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, ¶ms_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