blob: 1d05e0c148d6f3e1ef46f5e2a3d47afe38d90300 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_UPDATER_TAG_H_
#define CHROME_UPDATER_TAG_H_
#include <cstdint>
#include <optional>
#include <ostream>
#include <string>
#include <string_view>
#include <vector>
#include "base/files/file_path.h"
namespace updater::tagging {
namespace internal {
// Advances the iterator by |distance| and makes sure that it remains valid,
// else returns |end|.
std::vector<uint8_t>::const_iterator AdvanceIt(
std::vector<uint8_t>::const_iterator it,
size_t distance,
std::vector<uint8_t>::const_iterator end);
// Checks that the range [it, it + size) is found within the binary. |size| must
// be > 0.
bool CheckRange(std::vector<uint8_t>::const_iterator it,
size_t size,
std::vector<uint8_t>::const_iterator end);
} // namespace internal
// Represents application requirements for admin.
enum class NeedsAdmin {
// The application will install per user.
kNo = 0,
// The application will install machine-wide.
kYes,
// The application will install machine-wide if permissions allow, else will
// install per-user.
kPrefers,
};
// This struct contains the attributes for a given app parsed from a part of the
// metainstaller tag. It contains minimal policy and is intended to be a
// near-direct mapping from tag to memory. See TagArgs, which stores a list of
// these.
//
// An empty string in std::string members indicates that the given attribute did
// not appear in the tag for this app.
struct AppArgs {
// |app_id| must not be empty and will be made lowercase.
explicit AppArgs(std::string_view app_id);
~AppArgs();
AppArgs(const AppArgs&);
AppArgs& operator=(const AppArgs&);
AppArgs(AppArgs&&);
AppArgs& operator=(AppArgs&&);
// An ASCII-encoded lowercase string. Must not be empty.
std::string app_id;
std::string app_name;
std::string ap;
std::string encoded_installer_data;
std::string install_data_index;
std::string experiment_labels;
std::string untrusted_data;
std::optional<NeedsAdmin> needs_admin;
};
std::ostream& operator<<(std::ostream&, const NeedsAdmin&);
// This struct contains the "runtime mode" parsed from the metainstaller tag.
struct RuntimeModeArgs {
std::optional<NeedsAdmin> needs_admin;
};
// This struct contains the attributes parsed from a metainstaller tag. An empty
// string in std::string members indicates that the given attribute did not
// appear in the tag.
struct TagArgs {
// Must be kept in sync with the enum in
// `google_update\google_update_idl.idl`. Do not include `BrowserType::kMax`
// in the IDL file. Do not move or remove existing elements.
enum class BrowserType {
kUnknown = 0,
kDefault = 1,
kInternetExplorer = 2,
kFirefox = 3,
kChrome = 4,
// Add new browsers above this.
kMax
};
TagArgs();
~TagArgs();
TagArgs(const TagArgs&);
TagArgs& operator=(const TagArgs&);
TagArgs(TagArgs&&);
TagArgs& operator=(TagArgs&&);
std::string bundle_name;
std::string installation_id;
std::string brand_code;
std::string client_id;
std::string experiment_labels;
std::string referral_id;
std::string language;
std::optional<BrowserType> browser_type;
std::optional<bool> flighting = false;
std::optional<bool> usage_stats_enable;
// List of apps to install.
std::vector<AppArgs> apps;
// This member is present if the "runtime mode" was provided on the command
// line.
std::optional<RuntimeModeArgs> runtime_mode;
// The original tag string.
std::string tag_string;
// Vector of name/value attributes from the tag.
std::vector<std::pair<std::string, std::string>> attributes;
};
std::ostream& operator<<(std::ostream&, const TagArgs::BrowserType&);
// List of possible error states that the parser can encounter.
enum class ErrorCode {
// Parsing succeeded.
kSuccess,
// The attribute's name is unrecognized as an arg parameter.
kUnrecognizedName,
// The tag contains disallowed characters.
// See |kDisallowedCharsInExtraArgs|.
kTagIsInvalid,
// All attributes require a value.
kAttributeMustHaveValue,
// An app attribute was specified before an app id was specified.
kApp_AppIdNotSpecified,
// The app's experiment label cannot be whitespace.
kApp_ExperimentLabelsCannotBeWhitespace,
// The specified app id is not a valid.
// It must be ASCII-encoded and 512 bytes or less.
kApp_AppIdIsNotValid,
// The app name cannot be whitespace.
kApp_AppNameCannotBeWhitespace,
// The needsadmin value must be "yes", "no", or "prefers".
kApp_NeedsAdminValueIsInvalid,
// No app matches provided app id. Installer data can only be added to an app
// that has been previously specified in the TagArgs.
kAppInstallerData_AppIdNotFound,
// Cannot specify installer data before specifying at least one app id.
kAppInstallerData_InstallerDataCannotBeSpecifiedBeforeAppId,
// The bundle name cannot be whitespace.
kGlobal_BundleNameCannotBeWhitespace,
// The updater experiment label cannot be whitespace.
kGlobal_ExperimentLabelsCannotBeWhitespace,
// The browser type specified is invalid. It must be an integer matching the
// TagArgs::BrowserType enum.
kGlobal_BrowserTypeIsInvalid,
// The flighting value could not be parsed as a boolean.
kGlobal_FlightingValueIsNotABoolean,
// The usage stats value must be 0 or 1.
// Note: A value of 2 is considered the same as not specifying the usage
// stats.
kGlobal_UsageStatsValueIsInvalid,
// The runtime value must be "true", "persist", or "false". The values
// "persist" and "false" are only for backward compatibility in case someone
// uses it as an oversight, and are treated the same as "true".
kGlobal_RuntimeModeValueIsInvalid,
// The needsadmin value must be "yes", "no", or "prefers".
kRuntimeMode_NeedsAdminValueIsInvalid,
};
std::ostream& operator<<(std::ostream&, const ErrorCode&);
// The metainstaller tag contains the metadata used to configure the updater as
// a metainstaller. This usually comes from a 3rd party source, either as
// command-line arguments or embedded in the metainstaller image after it is
// signed.
//
// The metainstaller is generic. It gets bound to a specific application by
// using this configuration.
//
// This function parses |tag| and |app_installer_data_args| into |args|.
//
// |tag| is a querystring-encoded ordered list of key-value pairs. All values
// are unescaped from url-encoding. The following keys are valid and affect the
// global parameters and have the following constraints on the value:
// - bundlename Must not contain only whitespace.
// - iid Can be any string.
// - brand Can be any string.
// - client Can be any string.
// - omahaexperiments Must not contain only whitespace.
// - referral Can be any string.
// - browser Must be a positive integer greater than 0 and less than
// TagArgs::BrowserType::kMax.
// - lang Can be any string.
// - flighting Must be "true" or "false".
// - usagestats Must be "0", "1", or "2".
//
// The following keys specify app-specific attributes. "appid" must be specified
// before any other app attribute to specify the "current" app. Other app
// attributes will then affect the parameters of the most recently specified app
// ID. For example, if the tag is
// "appid=App1&brand=BrandForApp1&appid=App2&ap=ApForApp2&iid=GlobalInstallId",
// the resulting tag will look like:
// TagArgs {
// iid = GlobalInstallId
// apps = [
// AppArgs {
// appid = App1
// brand = BrandForApp1
// }
// AppArgs {
// appid = App2
// ap = ApForApp2
// }
// ]
// }
// These attributes has the following constraints on the value:
// - appid Can be any ASCII string. Case-insensitive.
// - ap Can be any string.
// - experiments Must not contain only whitespace.
// - appname Must not contain only whitespace.
// - needsadmin Must be "yes", "no", or "prefers".
// - installdataindex Can by any string.
// - untrusteddata Can be any string.
//
// |app_installer_data_args| is also a querystring-encoded ordered list of
// key-value pairs. Unlike in the |tag|, the values are no unescaped. The
// following keys are valid and affect the app installer data parameters and
// have the following constraints on the value:
// - appid Must be a valid app id specified in |tag|.
// - installerdata Can be any string. Must be specified after appid.
//
// Note: This method assumes all attribute names are ASCII.
ErrorCode Parse(std::string_view tag,
std::optional<std::string_view> app_installer_data_args,
TagArgs& args);
std::string ReadTag(std::vector<uint8_t>::const_iterator begin,
std::vector<uint8_t>::const_iterator end);
std::vector<uint8_t> GetTagFromTagString(const std::string& tag_string);
// Utilities for reading and writing tags to Windows PE and MSI files.
//
//
// The tag specification is as follows:
// - The tag area begins with a magic signature 'Gact2.0Omaha'.
// - The next 2 bytes are the tag string length in big endian.
// - Then comes the tag string in the format "key1=value1&key2=value2".
// - The key is alphanumeric, the value allows special characters such as '*'.
//
// A sample layout:
// +-------------------------------------+
// ~ .............................. ~
// | .............................. |
// | Other parts of the file |
// +-------------------------------------+
// | Start of the certificate |
// ~ .............................. ~
// ~ .............................. ~
// | Magic signature 'Gact2.0Omaha' | Tag starts
// | Tag length (2 bytes in big-endian)) |
// | tag string |
// +-------------------------------------+
//
// A real example (an MSI file tagged with 'brand=CDCD&key2=Test'):
// +-----------------------------------------------------------------+
// | G a c t 2 . 0 O m a h a 0x0 0x14 b r |
// | a n d = C D C D & k e y 2 = T e |
// | s t |
// +-----------------------------------------------------------------+
// Extracts a tag from `filename`.
std::string BinaryReadTagString(const base::FilePath& file);
std::optional<tagging::TagArgs> BinaryReadTag(const base::FilePath& file);
// Tags `file` with `tag_string` and writes the result to `file` by default, or
// to `out_file` if `out_file` is provided.
bool BinaryWriteTag(const base::FilePath& in_file,
const std::string& tag_string,
int padded_length,
base::FilePath out_file);
} // namespace updater::tagging
#endif // CHROME_UPDATER_TAG_H_