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