File: win_util.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (477 lines) | stat: -rw-r--r-- 18,911 bytes parent folder | download | duplicates (5)
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
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
// Copyright 2019 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_UTIL_WIN_UTIL_H_
#define CHROME_UPDATER_UTIL_WIN_UTIL_H_

#include <windows.h>

#include <wrl/client.h>
#include <wrl/implements.h>

#include <algorithm>
#include <cstdint>
#include <optional>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "base/check.h"
#include "base/containers/span.h"
#include "base/debug/alias.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/functional/function_ref.h"
#include "base/hash/hash.h"
#include "base/logging.h"
#include "base/process/process_iterator.h"
#include "base/scoped_generic.h"
#include "base/time/time.h"
#include "base/types/expected.h"
#include "base/version.h"
#include "base/win/atl.h"
#include "base/win/scoped_handle.h"
#include "base/win/win_util.h"
#include "base/win/windows_types.h"
#include "chrome/updater/updater_scope.h"
#include "chrome/updater/updater_version.h"
#include "chrome/updater/win/scoped_handle.h"

namespace base {
class FilePath;
}

struct IidComparator {
  constexpr bool operator()(const IID& lhs, const IID& rhs) const {
    auto lhs_prefix = std::tie(lhs.Data1, lhs.Data2, lhs.Data3);
    auto rhs_prefix = std::tie(rhs.Data1, rhs.Data2, rhs.Data3);
    if (lhs_prefix < rhs_prefix) {
      return true;
    }
    if (lhs_prefix == rhs_prefix) {
      return std::ranges::lexicographical_compare(lhs.Data4, rhs.Data4);
    }
    return false;
  }
};

namespace updater {

// Converts a `guid` to a string with the format
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}.
[[nodiscard]] std::wstring StringFromGuid(const GUID& guid);

template <typename ValueT>
using HResultOr = base::expected<ValueT, HRESULT>;

class ScHandleTraits {
 public:
  using Handle = SC_HANDLE;

  ScHandleTraits() = delete;
  ScHandleTraits(const ScHandleTraits&) = delete;
  ScHandleTraits& operator=(const ScHandleTraits&) = delete;

  static bool CloseHandle(SC_HANDLE handle) {
    return ::CloseServiceHandle(handle) != FALSE;
  }

  static bool IsHandleValid(SC_HANDLE handle) { return handle != nullptr; }

  static SC_HANDLE NullHandle() { return nullptr; }
};

using ScopedScHandle =
    base::win::GenericScopedHandle<ScHandleTraits,
                                   base::win::DummyVerifierTraits>;

class ProcessFilterName : public base::ProcessFilter {
 public:
  explicit ProcessFilterName(const std::wstring& process_name);

  // Overrides for base::ProcessFilter.
  bool Includes(const base::ProcessEntry& entry) const override;

 private:
  // Case-insensive name of the program image to look for, not including the
  // path. The name is not localized, therefore the function must be used
  // to look up only processes whose names are known to be ASCII.
  std::wstring process_name_;
};

namespace internal {

template <typename... T>
using WrlRuntimeClass = Microsoft::WRL::RuntimeClass<
    Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>,
    T...>;

}  // namespace internal

// Implements `DynamicIIDs` for interface `Interface`, where `Interface` is the
// implemented interface. `iid_user` and `iid_system` are aliases for interface
// `Interface` for user and system installs respectively.
//
// Usage: derive your COM class that implements interface `Interface` from
// `DynamicIIDsImpl<Interface, iid_user, iid_system>`.
template <typename Interface, REFIID iid_user, REFIID iid_system>
class DynamicIIDsImpl : public internal::WrlRuntimeClass<Interface> {
 public:
  explicit DynamicIIDsImpl(UpdaterScope scope) : scope_(scope) {
    VLOG(3) << __func__ << ": Interface: " << typeid(Interface).name()
            << ": iid_user: " << StringFromGuid(iid_user)
            << ": iid_system: " << StringFromGuid(iid_system)
            << ": scope: " << scope;
  }

  IFACEMETHODIMP QueryInterface(REFIID riid, void** object) override {
    return internal::WrlRuntimeClass<Interface>::QueryInterface(
        riid == (IsSystemInstall(scope_) ? iid_system : iid_user)
            ? __uuidof(Interface)
            : riid,
        object);
  }

 protected:
  UpdaterScope scope() const { return scope_; }

 private:
  const UpdaterScope scope_;
};

// Macro that makes it easier to derive from `DynamicIIDsImpl`.
#define DYNAMICIIDSIMPL(interface)                      \
  DynamicIIDsImpl<interface, __uuidof(interface##User), \
                  __uuidof(interface##System)>

// Implements `DynamicIIDs` for multiple interfaces `Interface`, taking
// `iid_user` and `iid_system` as maps.
template <typename... Interface>
class DynamicIIDsMultImpl : public internal::WrlRuntimeClass<Interface...> {
 public:
  DynamicIIDsMultImpl(
      UpdaterScope scope,
      const base::flat_map<IID, IID, IidComparator>& user_iid_map,
      const base::flat_map<IID, IID, IidComparator>& system_iid_map)
      : iid_map_(IsSystemInstall(scope) ? system_iid_map : user_iid_map) {}

  IFACEMETHODIMP QueryInterface(REFIID riid, void** object) override {
    const auto find_iid = iid_map_.find(riid);
    return internal::WrlRuntimeClass<Interface...>::QueryInterface(
        find_iid != iid_map_.end() ? find_iid->second : riid, object);
  }

 private:
  const base::flat_map<IID, IID, IidComparator> iid_map_;
};

// Macros that makes it easier to call the `IDispatchImpl` constructor.
#define IID_MAP_ENTRY_USER(interface) \
  { __uuidof(interface##User), __uuidof(interface) }
#define IID_MAP_ENTRY_SYSTEM(interface) \
  { __uuidof(interface##System), __uuidof(interface) }
#define IID_MAPS_USERSYSTEM(interface) \
  {IID_MAP_ENTRY_USER(interface)}, {   \
    IID_MAP_ENTRY_SYSTEM(interface)    \
  }

// Returns the last error as an HRESULT or E_FAIL if last error is NO_ERROR.
// This is not a drop in replacement for the HRESULT_FROM_WIN32 macro.
// The macro maps a NO_ERROR to S_OK, whereas the HRESULTFromLastError maps a
// NO_ERROR to E_FAIL.
HRESULT HRESULTFromLastError();

struct NamedObjectAttributes {
  NamedObjectAttributes(const std::wstring& name, const CSecurityDesc& sd);
  NamedObjectAttributes(const NamedObjectAttributes& other) = delete;
  NamedObjectAttributes& operator=(const NamedObjectAttributes& other) = delete;
  ~NamedObjectAttributes();

  std::wstring name;

  // `CSecurityAttributes` has broken value semantics because it does not update
  // its `SECURITY_ATTRIBUTES` base to keep it in sync with the internal
  // `m_SecurityDescriptor` data member.
  CSecurityAttributes sa;
};

// For machine and local system, the prefix would be "Global\G{obj_name}".
// For user, the prefix would be "Global\G{user_sid}{obj_name}".
// For machine objects, returns a security attributes that gives permissions to
// both Admins and SYSTEM. This allows for cases where SYSTEM creates the named
// object first. The default DACL for SYSTEM will not allow Admins access.
NamedObjectAttributes GetNamedObjectAttributes(const wchar_t* base_name,
                                               UpdaterScope scope);

// Gets the security descriptor with the default DACL for the current process
// user. The owner is the current user, the group is the current primary group.
// Returns security attributes on success, nullopt on failure.
std::optional<CSecurityDesc> GetCurrentUserDefaultSecurityDescriptor();

// Get security descriptor containing a DACL that grants the ACCESS_MASK access
// to admins and system.
CSecurityDesc GetAdminDaclSecurityDescriptor(ACCESS_MASK accessmask);

// Returns the registry path `Software\{CompanyName}\Update\Clients\{app_id}`.
std::wstring GetAppClientsKey(const std::string& app_id);
std::wstring GetAppClientsKey(const std::wstring& app_id);

// Returns the registry path
// `Software\{CompanyName}\Update\ClientState\{app_id}`.
std::wstring GetAppClientStateKey(const std::string& app_id);
std::wstring GetAppClientStateKey(const std::wstring& app_id);

// Returns the registry path
// `Software\{CompanyName}\Update\ClientStateMedium\{app_id}`.
std::wstring GetAppClientStateMediumKey(const std::string& app_id);
std::wstring GetAppClientStateMediumKey(const std::wstring& app_id);

// Returns the registry path
// `Software\{CompanyName}\Update\ClientState\{app_id}\cohort`.
std::wstring GetAppCohortKey(const std::string& app_id);
std::wstring GetAppCohortKey(const std::wstring& app_id);

// Returns the registry path
// `Software\{CompanyName}\Update\Clients\{app_id}\Commands\{command_id}`.
std::wstring GetAppCommandKey(const std::wstring& app_id,
                              const std::wstring& command_id);

// Returns the registry value
// `{HKRoot}\Software\{CompanyName}\Update\ClientState\{app_id}\ap`.
std::string GetAppAPValue(UpdaterScope scope, const std::string& app_id);

// Returns the registry path for the Updater app id under the |Clients| subkey.
// The path does not include the registry root hive prefix.
std::wstring GetRegistryKeyClientsUpdater();

// Returns the registry path for the Updater app id under the |ClientState|
// subkey. The path does not include the registry root hive prefix.
std::wstring GetRegistryKeyClientStateUpdater();

// Set `name` in `root`\`key` to `value`.
bool SetRegistryKey(HKEY root,
                    const std::wstring& key,
                    const std::wstring& name,
                    const std::wstring& value);

// Deletes or sets the `eulaaccepted` value in the `Google\Update` key, based on
// whether `eula_accepted` is `true` or `false`. Returns `true` on success.
bool SetEulaAccepted(UpdaterScope scope, bool eula_accepted);

// Returns `true` if the token is an elevated administrator. If
// `token` is `NULL`, the current thread token is used.
HResultOr<bool> IsTokenAdmin(HANDLE token);

// Returns true if the user is running as an elevated
// administrator.
HResultOr<bool> IsUserAdmin();

// Returns `true` if the user is running as a
// non-elevated administrator.
HResultOr<bool> IsUserNonElevatedAdmin();

// Returns `true` if the COM caller is an admin.
HResultOr<bool> IsCOMCallerAdmin();

// Returns `true` if the UAC is enabled.
bool IsUACOn();

// Returns `true` if running at high integrity with UAC on.
bool IsElevatedWithUACOn();

// Returns a string representing the UAC settings and elevation state for the
// caller. The value can be used for logging purposes.
std::string GetUACState();

// Returns the versioned service name in the following format:
// "{ProductName}{InternalService/Service}{UpdaterVersion}".
// For instance: "ChromiumUpdaterInternalService92.0.0.1".
std::wstring GetServiceName(
    bool is_internal_service,
    const base::Version& version = base::Version(kUpdaterVersion));

// Returns `KEY_WOW64_32KEY | access`. All registry access under the Updater key
// should use `Wow6432(access)` as the `REGSAM`.
REGSAM Wow6432(REGSAM access);

// Starts a new process via ::ShellExecuteEx. `parameters` and `verb` can be
// empty strings. The function waits until the spawned process has completed.
// `verb` specifies the action to perform. For instance, the "runas" verb
// launches an application as administrator with an UAC prompt if UAC is enabled
// and the parent process is running at medium integrity.
// Returns the exit code of the process or HRESULT on failure. Returns 0 if the
// process was created successfully but the exit code is unknown.
HResultOr<DWORD> ShellExecuteAndWait(const base::FilePath& file_path,
                                     const std::wstring& parameters,
                                     const std::wstring& verb);

// Starts a new elevated process. `file_path` specifies the program to be run.
// `parameters` can be an empty string.
// The function waits until the spawned process has completed.
// Returns the exit code of the process or HRESULT on failure. Returns 0 if the
// process was created successfully but the exit code is unknown.
HResultOr<DWORD> RunElevated(const base::FilePath& file_path,
                             const std::wstring& parameters);

// Runs `cmd_line` de-elevated.The function does not wait for the spawned
// process.
HRESULT RunDeElevatedCmdLine(const std::wstring& cmd_line);

std::optional<base::FilePath> GetGoogleUpdateExePath(UpdaterScope scope);

// Causes the COM runtime not to handle exceptions. Failing to set this
// up is a critical error, since ignoring exceptions may lead to corrupted
// program state.
[[nodiscard]] HRESULT DisableCOMExceptionHandling();

// Builds a command line running `MSIExec` on the provided
// `msi_installer`,`arguments`, and `installer_data_file`, with added logging to
// a log file in the same directory as the MSI installer.
std::wstring BuildMsiCommandLine(
    const std::wstring& arguments,
    std::optional<base::FilePath> installer_data_file,
    const base::FilePath& msi_installer);

// Builds a command line running the provided `exe_installer`, `arguments`, and
// `installer_data_file`.
std::wstring BuildExeCommandLine(
    const std::wstring& arguments,
    std::optional<base::FilePath> installer_data_file,
    const base::FilePath& exe_installer);

// Returns `true` if the service specified is currently running or starting.
bool IsServiceRunning(const std::wstring& service_name);

// Returns the HKEY root corresponding to the UpdaterScope:
// * scope == UpdaterScope::kSystem == HKEY_LOCAL_MACHINE
// * scope == UpdaterScope::kUser == HKEY_CURRENT_USER
HKEY UpdaterScopeToHKeyRoot(UpdaterScope scope);

// Returns an OSVERSIONINFOEX for the current OS version.
std::optional<OSVERSIONINFOEX> GetOSVersion();

// Compares the current OS to the supplied version.  The value of `oper` should
// be one of the predicate values from `::VerSetConditionMask()`, for example,
// `VER_GREATER` or `VER_GREATER_EQUAL`. `os_version` is usually from a prior
// call to `::GetVersionEx` or `::RtlGetVersion`.
bool CompareOSVersions(const OSVERSIONINFOEX& os, BYTE oper);

// This function calls ::SetDefaultDllDirectories to restrict DLL loads to
// either full paths or %SYSTEM32%.
[[nodiscard]] bool EnableSecureDllLoading();

// Enables metadata protection in the heap manager. This allows for the process
// to be terminated immediately when a buffer overflow or illegal heap
// operations are detected. This call enables protection for the entire process
// and cannot be reversed.
bool EnableProcessHeapMetadataProtection();

// Creates a unique temporary directory. The directory is created under a secure
// location if the caller is admin.
std::optional<base::ScopedTempDir> CreateSecureTempDir();

// Signals the shutdown event that causes legacy GoogleUpdate processes to exit.
// Returns a closure that resets the shutdown event when it goes out of scope.
[[nodiscard]] base::ScopedClosureRunner SignalShutdownEvent(UpdaterScope scope);

// Returns `true` if the legacy GoogleUpdate shutdown event is signaled.
bool IsShutdownEventSignaled(UpdaterScope scope);

// Stops processes running under the provided `path`, by first waiting
// `wait_period`, and if the processes still have not exited, by terminating the
// processes.
void StopProcessesUnderPath(const base::FilePath& path,
                            base::TimeDelta wait_period);

// Returns `true` if the argument is a guid.
bool IsGuid(const std::wstring& s);

// Runs `callback` for each run value in the registry that matches `prefix`.
void ForEachRegistryRunValueWithPrefix(
    const std::wstring& prefix,
    base::FunctionRef<void(const std::wstring&)> callback);

// Deletes the registry value at `root\\path`, and returns `true` on success or
// if the path does not exist.
[[nodiscard]] bool DeleteRegValue(HKEY root,
                                  const std::wstring& path,
                                  const std::wstring& value);

// Runs `callback` for each system service that matches `service_name_prefix`
// and `display_name_prefix`. `display_name_prefix` can be empty, in which case,
// only `service_name_prefix` is used for the matching.
void ForEachServiceWithPrefix(
    const std::wstring& service_name_prefix,
    const std::wstring& display_name_prefix,
    base::FunctionRef<void(const std::wstring&)> callback);

// Deletes `service_name` system service and returns `true` on success.
[[nodiscard]] bool DeleteService(const std::wstring& service_name);

// Logs CLSID entries in HKLM and HKCU under both the 64-bit and 32-bit hives
// for the given CLSID.
void LogClsidEntries(REFCLSID clsid);

template <typename T, typename... TArgs>
Microsoft::WRL::ComPtr<T> MakeComObjectOrCrash(TArgs&&... args) {
  auto obj = Microsoft::WRL::Make<T>(std::forward<TArgs>(args)...);
  CHECK(obj);
  return obj;
}

template <typename T, typename I, typename... TArgs>
[[nodiscard]] HRESULT MakeAndInitializeComObject(I** obj, TArgs&&... args) {
  return Microsoft::WRL::MakeAndInitialize<T>(obj,
                                              std::forward<TArgs>(args)...);
}

template <typename T, typename I, typename... TArgs>
[[nodiscard]] HRESULT MakeAndInitializeComObject(Microsoft::WRL::ComPtr<I>& obj,
                                                 TArgs&&... args) {
  return MakeAndInitializeComObject<T>(static_cast<I**>(&obj),
                                       std::forward<TArgs>(args)...);
}

// Gets the contents under a given registry key.
std::optional<std::wstring> GetRegKeyContents(const std::wstring& reg_key);

// Returns the textual description of a system `error` as provided by the
// operating system. The function assumes that the locale value for the calling
// thread is set, otherwise, the function uses the user/system default LANGID,
// or it defaults to US English.
std::wstring GetTextForSystemError(int error);

// Retrieves the logged on user token for the active explorer process if one
// exists.
HResultOr<ScopedKernelHANDLE> GetLoggedOnUserToken();

// Returns true if running in Windows Audit mode, as documented at
// http://technet.microsoft.com/en-us/library/cc721913.aspx.
bool IsAuditMode();

// Writes the OEM install beginning timestamp in the registry.
bool SetOemInstallState();

// Removes the OEM install beginning timestamp from the registry.
bool ResetOemInstallState();

// Returns `true` if the OEM install time is present and it has been less than
// `kMinOemModeTime` since the OEM install.
bool IsOemInstalling();

// Stores the runtime enrollment token to the persistent storage.
bool StoreRunTimeEnrollmentToken(const std::string& enrollment_token);

// Returns `true` if the service exists and has not been marked for deletion.
[[nodiscard]] bool IsServicePresent(const std::wstring& service_name);

// Returns `true` if the service exists and is not deleted or disabled.
[[nodiscard]] bool IsServiceEnabled(const std::wstring& service_name);

}  // namespace updater

#endif  // CHROME_UPDATER_UTIL_WIN_UTIL_H_