xref: /aosp_15_r20/external/cronet/base/win/wmi.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2010 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/win/wmi.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <objbase.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <windows.h>
10*6777b538SAndroid Build Coastguard Worker 
11*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker #include <string_view>
14*6777b538SAndroid Build Coastguard Worker #include <utility>
15*6777b538SAndroid Build Coastguard Worker 
16*6777b538SAndroid Build Coastguard Worker #include "base/location.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/no_destructor.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_thread_priority.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_bstr.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_variant.h"
23*6777b538SAndroid Build Coastguard Worker 
24*6777b538SAndroid Build Coastguard Worker using Microsoft::WRL::ComPtr;
25*6777b538SAndroid Build Coastguard Worker 
26*6777b538SAndroid Build Coastguard Worker namespace base {
27*6777b538SAndroid Build Coastguard Worker namespace win {
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker const wchar_t kCimV2ServerName[] = L"ROOT\\CIMV2";
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker const wchar_t kSecurityCenter2ServerName[] = L"ROOT\\SecurityCenter2";
32*6777b538SAndroid Build Coastguard Worker 
33*6777b538SAndroid Build Coastguard Worker namespace {
34*6777b538SAndroid Build Coastguard Worker 
35*6777b538SAndroid Build Coastguard Worker constexpr wchar_t kSerialNumberQuery[] = L"SELECT SerialNumber FROM Win32_Bios";
36*6777b538SAndroid Build Coastguard Worker 
37*6777b538SAndroid Build Coastguard Worker // Instantiates `wmi_services` with a connection to `server_name` in WMI. Will
38*6777b538SAndroid Build Coastguard Worker // set a security blanket if `set_blanket` is true.
CreateLocalWmiConnection(bool set_blanket,const std::wstring & server_name,ComPtr<IWbemServices> * wmi_services)39*6777b538SAndroid Build Coastguard Worker std::optional<WmiError> CreateLocalWmiConnection(
40*6777b538SAndroid Build Coastguard Worker     bool set_blanket,
41*6777b538SAndroid Build Coastguard Worker     const std::wstring& server_name,
42*6777b538SAndroid Build Coastguard Worker     ComPtr<IWbemServices>* wmi_services) {
43*6777b538SAndroid Build Coastguard Worker   DCHECK(wmi_services);
44*6777b538SAndroid Build Coastguard Worker   ComPtr<IWbemLocator> wmi_locator;
45*6777b538SAndroid Build Coastguard Worker   HRESULT hr =
46*6777b538SAndroid Build Coastguard Worker       ::CoCreateInstance(CLSID_WbemLocator, nullptr, CLSCTX_INPROC_SERVER,
47*6777b538SAndroid Build Coastguard Worker                          IID_PPV_ARGS(&wmi_locator));
48*6777b538SAndroid Build Coastguard Worker   if (FAILED(hr))
49*6777b538SAndroid Build Coastguard Worker     return WmiError::kFailedToCreateInstance;
50*6777b538SAndroid Build Coastguard Worker 
51*6777b538SAndroid Build Coastguard Worker   ComPtr<IWbemServices> wmi_services_r;
52*6777b538SAndroid Build Coastguard Worker   hr = wmi_locator->ConnectServer(base::win::ScopedBstr(server_name).Get(),
53*6777b538SAndroid Build Coastguard Worker                                   nullptr, nullptr, nullptr, 0, nullptr,
54*6777b538SAndroid Build Coastguard Worker                                   nullptr, &wmi_services_r);
55*6777b538SAndroid Build Coastguard Worker   if (FAILED(hr))
56*6777b538SAndroid Build Coastguard Worker     return WmiError::kFailedToConnectToWMI;
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker   if (set_blanket) {
59*6777b538SAndroid Build Coastguard Worker     hr = ::CoSetProxyBlanket(wmi_services_r.Get(), RPC_C_AUTHN_WINNT,
60*6777b538SAndroid Build Coastguard Worker                              RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL,
61*6777b538SAndroid Build Coastguard Worker                              RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_NONE);
62*6777b538SAndroid Build Coastguard Worker     if (FAILED(hr))
63*6777b538SAndroid Build Coastguard Worker       return WmiError::kFailedToSetSecurityBlanket;
64*6777b538SAndroid Build Coastguard Worker   }
65*6777b538SAndroid Build Coastguard Worker 
66*6777b538SAndroid Build Coastguard Worker   *wmi_services = std::move(wmi_services_r);
67*6777b538SAndroid Build Coastguard Worker   return std::nullopt;
68*6777b538SAndroid Build Coastguard Worker }
69*6777b538SAndroid Build Coastguard Worker 
70*6777b538SAndroid Build Coastguard Worker // Runs `query` through `wmi_services` and sets the results' `enumerator`.
TryRunQuery(const std::wstring & query,const ComPtr<IWbemServices> & wmi_services,ComPtr<IEnumWbemClassObject> * enumerator)71*6777b538SAndroid Build Coastguard Worker bool TryRunQuery(const std::wstring& query,
72*6777b538SAndroid Build Coastguard Worker                  const ComPtr<IWbemServices>& wmi_services,
73*6777b538SAndroid Build Coastguard Worker                  ComPtr<IEnumWbemClassObject>* enumerator) {
74*6777b538SAndroid Build Coastguard Worker   DCHECK(enumerator);
75*6777b538SAndroid Build Coastguard Worker   base::win::ScopedBstr query_language(L"WQL");
76*6777b538SAndroid Build Coastguard Worker   base::win::ScopedBstr query_bstr(query);
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker   ComPtr<IEnumWbemClassObject> enumerator_r;
79*6777b538SAndroid Build Coastguard Worker   HRESULT hr = wmi_services->ExecQuery(
80*6777b538SAndroid Build Coastguard Worker       query_language.Get(), query_bstr.Get(),
81*6777b538SAndroid Build Coastguard Worker       WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, nullptr,
82*6777b538SAndroid Build Coastguard Worker       &enumerator_r);
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker   if (FAILED(hr))
85*6777b538SAndroid Build Coastguard Worker     return false;
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker   *enumerator = std::move(enumerator_r);
88*6777b538SAndroid Build Coastguard Worker   return true;
89*6777b538SAndroid Build Coastguard Worker }
90*6777b538SAndroid Build Coastguard Worker 
91*6777b538SAndroid Build Coastguard Worker }  // namespace
92*6777b538SAndroid Build Coastguard Worker 
RunWmiQuery(const std::wstring & server_name,const std::wstring & query,ComPtr<IEnumWbemClassObject> * enumerator)93*6777b538SAndroid Build Coastguard Worker std::optional<WmiError> RunWmiQuery(const std::wstring& server_name,
94*6777b538SAndroid Build Coastguard Worker                                     const std::wstring& query,
95*6777b538SAndroid Build Coastguard Worker                                     ComPtr<IEnumWbemClassObject>* enumerator) {
96*6777b538SAndroid Build Coastguard Worker   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
97*6777b538SAndroid Build Coastguard Worker 
98*6777b538SAndroid Build Coastguard Worker   DCHECK(enumerator);
99*6777b538SAndroid Build Coastguard Worker 
100*6777b538SAndroid Build Coastguard Worker   ComPtr<IWbemServices> wmi_services;
101*6777b538SAndroid Build Coastguard Worker   auto error = CreateLocalWmiConnection(/*set_blanket=*/true, server_name,
102*6777b538SAndroid Build Coastguard Worker                                         &wmi_services);
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker   if (error.has_value())
105*6777b538SAndroid Build Coastguard Worker     return error;
106*6777b538SAndroid Build Coastguard Worker 
107*6777b538SAndroid Build Coastguard Worker   if (!TryRunQuery(query, wmi_services, enumerator))
108*6777b538SAndroid Build Coastguard Worker     return WmiError::kFailedToExecWMIQuery;
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker   return std::nullopt;
111*6777b538SAndroid Build Coastguard Worker }
112*6777b538SAndroid Build Coastguard Worker 
CreateLocalWmiConnection(bool set_blanket,ComPtr<IWbemServices> * wmi_services)113*6777b538SAndroid Build Coastguard Worker bool CreateLocalWmiConnection(bool set_blanket,
114*6777b538SAndroid Build Coastguard Worker                               ComPtr<IWbemServices>* wmi_services) {
115*6777b538SAndroid Build Coastguard Worker   // Mitigate the issues caused by loading DLLs on a background thread
116*6777b538SAndroid Build Coastguard Worker   // (http://crbug/973868).
117*6777b538SAndroid Build Coastguard Worker   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
118*6777b538SAndroid Build Coastguard Worker 
119*6777b538SAndroid Build Coastguard Worker   auto error =
120*6777b538SAndroid Build Coastguard Worker       CreateLocalWmiConnection(set_blanket, kCimV2ServerName, wmi_services);
121*6777b538SAndroid Build Coastguard Worker   return !error.has_value();
122*6777b538SAndroid Build Coastguard Worker }
123*6777b538SAndroid Build Coastguard Worker 
CreateWmiConnection(bool set_blanket,const std::wstring & resource)124*6777b538SAndroid Build Coastguard Worker ComPtr<IWbemServices> CreateWmiConnection(bool set_blanket,
125*6777b538SAndroid Build Coastguard Worker                                           const std::wstring& resource) {
126*6777b538SAndroid Build Coastguard Worker   // Mitigate the issues caused by loading DLLs on a background thread
127*6777b538SAndroid Build Coastguard Worker   // (http://crbug/973868).
128*6777b538SAndroid Build Coastguard Worker   SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY();
129*6777b538SAndroid Build Coastguard Worker 
130*6777b538SAndroid Build Coastguard Worker   ComPtr<IWbemServices> wmi_services = nullptr;
131*6777b538SAndroid Build Coastguard Worker   auto error = CreateLocalWmiConnection(set_blanket, resource, &wmi_services);
132*6777b538SAndroid Build Coastguard Worker   if (error.has_value())
133*6777b538SAndroid Build Coastguard Worker     return nullptr;
134*6777b538SAndroid Build Coastguard Worker   return wmi_services;
135*6777b538SAndroid Build Coastguard Worker }
136*6777b538SAndroid Build Coastguard Worker 
CreateWmiClassMethodObject(IWbemServices * wmi_services,std::wstring_view class_name,std::wstring_view method_name,ComPtr<IWbemClassObject> * class_instance)137*6777b538SAndroid Build Coastguard Worker bool CreateWmiClassMethodObject(IWbemServices* wmi_services,
138*6777b538SAndroid Build Coastguard Worker                                 std::wstring_view class_name,
139*6777b538SAndroid Build Coastguard Worker                                 std::wstring_view method_name,
140*6777b538SAndroid Build Coastguard Worker                                 ComPtr<IWbemClassObject>* class_instance) {
141*6777b538SAndroid Build Coastguard Worker   // We attempt to instantiate a COM object that represents a WMI object plus
142*6777b538SAndroid Build Coastguard Worker   // a method rolled into one entity.
143*6777b538SAndroid Build Coastguard Worker   ScopedBstr b_class_name(class_name);
144*6777b538SAndroid Build Coastguard Worker   ScopedBstr b_method_name(method_name);
145*6777b538SAndroid Build Coastguard Worker   ComPtr<IWbemClassObject> class_object;
146*6777b538SAndroid Build Coastguard Worker   HRESULT hr;
147*6777b538SAndroid Build Coastguard Worker   hr = wmi_services->GetObject(b_class_name.Get(), 0, nullptr, &class_object,
148*6777b538SAndroid Build Coastguard Worker                                nullptr);
149*6777b538SAndroid Build Coastguard Worker   if (FAILED(hr))
150*6777b538SAndroid Build Coastguard Worker     return false;
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker   ComPtr<IWbemClassObject> params_def;
153*6777b538SAndroid Build Coastguard Worker   hr = class_object->GetMethod(b_method_name.Get(), 0, &params_def, nullptr);
154*6777b538SAndroid Build Coastguard Worker   if (FAILED(hr))
155*6777b538SAndroid Build Coastguard Worker     return false;
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker   if (!params_def.Get()) {
158*6777b538SAndroid Build Coastguard Worker     // You hit this special case if the WMI class is not a CIM class. MSDN
159*6777b538SAndroid Build Coastguard Worker     // sometimes tells you this. Welcome to WMI hell.
160*6777b538SAndroid Build Coastguard Worker     return false;
161*6777b538SAndroid Build Coastguard Worker   }
162*6777b538SAndroid Build Coastguard Worker 
163*6777b538SAndroid Build Coastguard Worker   hr = params_def->SpawnInstance(0, &(*class_instance));
164*6777b538SAndroid Build Coastguard Worker   return SUCCEEDED(hr);
165*6777b538SAndroid Build Coastguard Worker }
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker // The code in Launch() basically calls the Create Method of the Win32_Process
168*6777b538SAndroid Build Coastguard Worker // CIM class is documented here:
169*6777b538SAndroid Build Coastguard Worker // http://msdn2.microsoft.com/en-us/library/aa389388(VS.85).aspx
170*6777b538SAndroid Build Coastguard Worker // NOTE: The documentation for the Create method suggests that the ProcessId
171*6777b538SAndroid Build Coastguard Worker // parameter and return value are of type uint32_t, but when we call the method
172*6777b538SAndroid Build Coastguard Worker // the values in the returned out_params, are VT_I4, which is int32_t.
WmiLaunchProcess(const std::wstring & command_line,int * process_id)173*6777b538SAndroid Build Coastguard Worker bool WmiLaunchProcess(const std::wstring& command_line, int* process_id) {
174*6777b538SAndroid Build Coastguard Worker   ComPtr<IWbemServices> wmi_local;
175*6777b538SAndroid Build Coastguard Worker   if (!CreateLocalWmiConnection(true, &wmi_local))
176*6777b538SAndroid Build Coastguard Worker     return false;
177*6777b538SAndroid Build Coastguard Worker 
178*6777b538SAndroid Build Coastguard Worker   static constexpr wchar_t class_name[] = L"Win32_Process";
179*6777b538SAndroid Build Coastguard Worker   static constexpr wchar_t method_name[] = L"Create";
180*6777b538SAndroid Build Coastguard Worker   ComPtr<IWbemClassObject> process_create;
181*6777b538SAndroid Build Coastguard Worker   if (!CreateWmiClassMethodObject(wmi_local.Get(), class_name, method_name,
182*6777b538SAndroid Build Coastguard Worker                                   &process_create)) {
183*6777b538SAndroid Build Coastguard Worker     return false;
184*6777b538SAndroid Build Coastguard Worker   }
185*6777b538SAndroid Build Coastguard Worker 
186*6777b538SAndroid Build Coastguard Worker   ScopedVariant b_command_line(command_line.c_str());
187*6777b538SAndroid Build Coastguard Worker 
188*6777b538SAndroid Build Coastguard Worker   if (FAILED(process_create->Put(L"CommandLine", 0, b_command_line.AsInput(),
189*6777b538SAndroid Build Coastguard Worker                                  0))) {
190*6777b538SAndroid Build Coastguard Worker     return false;
191*6777b538SAndroid Build Coastguard Worker   }
192*6777b538SAndroid Build Coastguard Worker 
193*6777b538SAndroid Build Coastguard Worker   ComPtr<IWbemClassObject> out_params;
194*6777b538SAndroid Build Coastguard Worker   HRESULT hr = wmi_local->ExecMethod(
195*6777b538SAndroid Build Coastguard Worker       ScopedBstr(class_name).Get(), ScopedBstr(method_name).Get(), 0, nullptr,
196*6777b538SAndroid Build Coastguard Worker       process_create.Get(), &out_params, nullptr);
197*6777b538SAndroid Build Coastguard Worker   if (FAILED(hr))
198*6777b538SAndroid Build Coastguard Worker     return false;
199*6777b538SAndroid Build Coastguard Worker 
200*6777b538SAndroid Build Coastguard Worker   // We're only expecting int32_t or uint32_t values, so no need for
201*6777b538SAndroid Build Coastguard Worker   // ScopedVariant.
202*6777b538SAndroid Build Coastguard Worker   VARIANT ret_value = {{{VT_EMPTY}}};
203*6777b538SAndroid Build Coastguard Worker   hr = out_params->Get(L"ReturnValue", 0, &ret_value, nullptr, nullptr);
204*6777b538SAndroid Build Coastguard Worker   if (FAILED(hr) || V_I4(&ret_value) != 0)
205*6777b538SAndroid Build Coastguard Worker     return false;
206*6777b538SAndroid Build Coastguard Worker 
207*6777b538SAndroid Build Coastguard Worker   VARIANT pid = {{{VT_EMPTY}}};
208*6777b538SAndroid Build Coastguard Worker   hr = out_params->Get(L"ProcessId", 0, &pid, nullptr, nullptr);
209*6777b538SAndroid Build Coastguard Worker   if (FAILED(hr) || V_I4(&pid) == 0)
210*6777b538SAndroid Build Coastguard Worker     return false;
211*6777b538SAndroid Build Coastguard Worker 
212*6777b538SAndroid Build Coastguard Worker   if (process_id)
213*6777b538SAndroid Build Coastguard Worker     *process_id = V_I4(&pid);
214*6777b538SAndroid Build Coastguard Worker 
215*6777b538SAndroid Build Coastguard Worker   return true;
216*6777b538SAndroid Build Coastguard Worker }
217*6777b538SAndroid Build Coastguard Worker 
218*6777b538SAndroid Build Coastguard Worker // static
Get()219*6777b538SAndroid Build Coastguard Worker WmiComputerSystemInfo WmiComputerSystemInfo::Get() {
220*6777b538SAndroid Build Coastguard Worker   static const base::NoDestructor<WmiComputerSystemInfo> static_info([] {
221*6777b538SAndroid Build Coastguard Worker     WmiComputerSystemInfo info;
222*6777b538SAndroid Build Coastguard Worker     ComPtr<IEnumWbemClassObject> enumerator_bios;
223*6777b538SAndroid Build Coastguard Worker     auto error =
224*6777b538SAndroid Build Coastguard Worker         RunWmiQuery(kCimV2ServerName, kSerialNumberQuery, &enumerator_bios);
225*6777b538SAndroid Build Coastguard Worker     if (!error.has_value())
226*6777b538SAndroid Build Coastguard Worker       info.PopulateSerialNumber(enumerator_bios);
227*6777b538SAndroid Build Coastguard Worker     return info;
228*6777b538SAndroid Build Coastguard Worker   }());
229*6777b538SAndroid Build Coastguard Worker   return *static_info;
230*6777b538SAndroid Build Coastguard Worker }
231*6777b538SAndroid Build Coastguard Worker 
PopulateSerialNumber(const ComPtr<IEnumWbemClassObject> & enumerator_bios)232*6777b538SAndroid Build Coastguard Worker void WmiComputerSystemInfo::PopulateSerialNumber(
233*6777b538SAndroid Build Coastguard Worker     const ComPtr<IEnumWbemClassObject>& enumerator_bios) {
234*6777b538SAndroid Build Coastguard Worker   ComPtr<IWbemClassObject> class_obj;
235*6777b538SAndroid Build Coastguard Worker   ULONG items_returned = 0;
236*6777b538SAndroid Build Coastguard Worker   HRESULT hr =
237*6777b538SAndroid Build Coastguard Worker       enumerator_bios->Next(WBEM_INFINITE, 1, &class_obj, &items_returned);
238*6777b538SAndroid Build Coastguard Worker   if (FAILED(hr) || !items_returned)
239*6777b538SAndroid Build Coastguard Worker     return;
240*6777b538SAndroid Build Coastguard Worker 
241*6777b538SAndroid Build Coastguard Worker   ScopedVariant serial_number;
242*6777b538SAndroid Build Coastguard Worker   hr = class_obj->Get(L"SerialNumber", 0, serial_number.Receive(), nullptr,
243*6777b538SAndroid Build Coastguard Worker                       nullptr);
244*6777b538SAndroid Build Coastguard Worker   if (SUCCEEDED(hr) && serial_number.type() == VT_BSTR) {
245*6777b538SAndroid Build Coastguard Worker     serial_number_.assign(V_BSTR(serial_number.ptr()),
246*6777b538SAndroid Build Coastguard Worker                           ::SysStringLen(V_BSTR(serial_number.ptr())));
247*6777b538SAndroid Build Coastguard Worker   }
248*6777b538SAndroid Build Coastguard Worker }
249*6777b538SAndroid Build Coastguard Worker 
250*6777b538SAndroid Build Coastguard Worker }  // namespace win
251*6777b538SAndroid Build Coastguard Worker }  // namespace base
252