File: tag.h

package info (click to toggle)
chromium 138.0.7204.157-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 6,071,864 kB
  • sloc: cpp: 34,936,859; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,967; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (356 lines) | stat: -rw-r--r-- 13,120 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
// 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 <utility>
#include <vector>

#include "base/files/file_path.h"
#include "base/types/expected.h"
#include "build/build_config.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 {
  auto operator<=>(const RuntimeModeArgs&) const = default;
  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;
  std::string enrollment_token;

  // 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,

  // The enrollment token must be a GUID.
  kGlobal_EnrollmentTokenValueIsInvalid,

  // No tag was found when attempting to extract one from a binary or other
  // potentially-tagged content.
  kTagNotFound,
};

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; usually 4 uppercase alphabetic chars.
// - 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".
// - runtime           Must be "true", "false".
// - etoken            Must be a GUID.
//
// 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&ap=ApApp1&brand=GBRN&appid=App2&ap=ApApp2&iid=GlobalInstallId",
// the resulting tag will look like:
//   TagArgs {
//     iid = GlobalInstallId
//     brand = GBRN
//     apps = [
//       AppArgs {
//         appid = App1
//         ap = ApApp1
//       }
//       AppArgs {
//         appid = App2
//         ap = ApApp2
//       }
//     ]
//   }
// These attributes have 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 escaped. 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);

// 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);

// ReadTag extracts the tag string from a region of binary data. This string
// does not include the magic signature or tag length itself. If no tag can
// be found, this returns the empty string.
std::string ReadTag(std::vector<uint8_t>::const_iterator begin,
                    std::vector<uint8_t>::const_iterator end);

// GetTagFromTagString creates binary tag data from a specified tag string by
// prefixing it with the signature and length.
std::vector<uint8_t> GetTagFromTagString(const std::string& tag_string);

// 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);

#if BUILDFLAG(IS_MAC)

// Reads the `com.apple.application-instance` extended attribute from the item
// at `path`, parsing it as a complete metainstaller tag, including the
// "Gact2.0Omaha" magic number prefix.
//
// If the file exists, has this specific extended attribute, this process can
// read that attribute, and this process can parse a complete metainstaller
// tag out of it, this returns the parsed `tagging::TagArgs`. If any of the
// prerequisites before tag content parsing fail, this returns the "no tag"
// error code. If tag parsing fails, this returns the error code from tag
// parsing.
base::expected<TagArgs, ErrorCode> ReadTagFromApplicationInstanceXattr(
    const base::FilePath& path);

// Overwrites the `com.apple.application-instance` extended attribute on the
// item at `path` with a formatted binary tag containing the provided string,
// prefixed with the "Gact2.0Omaha" signature and size, as described above.
// It does not check the validity of the string as a tag. Returns `true` on
// success, `false` on failure.
bool WriteTagStringToApplicationInstanceXattr(const base::FilePath& path,
                                              const std::string& tag_string);

#endif  // BUILDFLAG(IS_MAC)

}  // namespace updater::tagging

#endif  // CHROME_UPDATER_TAG_H_