ReactOS  0.4.15-dev-1384-g878186b
install.c
Go to the documentation of this file.
1 /*
2  * ReactOS kernel
3  * Copyright (C) 2005 ReactOS Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 /*
20  * COPYRIGHT: See COPYING in the top level directory
21  * PROJECT: ReactOS kernel
22  * FILE: base/services/umpnpmgr/install.c
23  * PURPOSE: Device installer
24  * PROGRAMMER: Eric Kohl (eric.kohl@reactos.org)
25  * HervĂ© Poussineau (hpoussin@reactos.org)
26  * Colin Finck (colin@reactos.org)
27  */
28 
29 /* INCLUDES *****************************************************************/
30 
31 #include "precomp.h"
32 
33 #define NDEBUG
34 #include <debug.h>
35 
36 
37 /* GLOBALS ******************************************************************/
38 
42 
43 /* Device-install event list */
47 
48 
49 /* FUNCTIONS *****************************************************************/
50 
51 static BOOL
53 {
54  BOOL DeviceInstalled = FALSE;
56  DWORD Value;
60  PROCESS_INFORMATION ProcessInfo;
61  STARTUPINFOW StartupInfo;
62  UUID RandomUuid;
63  HKEY DeviceKey;
64 
65  /* The following lengths are constant (see below), they cannot overflow */
66  WCHAR CommandLine[116];
67  WCHAR InstallEventName[73];
68  WCHAR PipeName[74];
69  WCHAR UuidString[39];
70 
71  DPRINT("InstallDevice(%S, %d)\n", DeviceInstance, ShowWizard);
72 
73  ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
74 
77  0,
79  &DeviceKey) == ERROR_SUCCESS)
80  {
81  if (RegQueryValueExW(DeviceKey,
82  L"Class",
83  NULL,
84  NULL,
85  NULL,
86  NULL) == ERROR_SUCCESS)
87  {
88  DPRINT("No need to install: %S\n", DeviceInstance);
89  RegCloseKey(DeviceKey);
90  return TRUE;
91  }
92 
93  BytesWritten = sizeof(DWORD);
94  if (RegQueryValueExW(DeviceKey,
95  L"ConfigFlags",
96  NULL,
97  NULL,
98  (PBYTE)&Value,
100  {
102  {
103  DPRINT("No need to install: %S\n", DeviceInstance);
104  RegCloseKey(DeviceKey);
105  return TRUE;
106  }
107  }
108 
109  RegCloseKey(DeviceKey);
110  }
111 
112  DPRINT1("Installing: %S\n", DeviceInstance);
113 
114  /* Create a random UUID for the named pipe & event*/
115  UuidCreate(&RandomUuid);
116  swprintf(UuidString, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
117  RandomUuid.Data1, RandomUuid.Data2, RandomUuid.Data3,
118  RandomUuid.Data4[0], RandomUuid.Data4[1], RandomUuid.Data4[2],
119  RandomUuid.Data4[3], RandomUuid.Data4[4], RandomUuid.Data4[5],
120  RandomUuid.Data4[6], RandomUuid.Data4[7]);
121 
122  /* Create the event */
123  wcscpy(InstallEventName, L"Global\\PNP_Device_Install_Event_0.");
124  wcscat(InstallEventName, UuidString);
125  hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName);
126  if (!hInstallEvent)
127  {
128  DPRINT1("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError());
129  goto cleanup;
130  }
131 
132  /* Create the named pipe */
133  wcscpy(PipeName, L"\\\\.\\pipe\\PNP_Device_Install_Pipe_0.");
134  wcscat(PipeName, UuidString);
135  hPipe = CreateNamedPipeW(PipeName, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 512, 512, 0, NULL);
136  if (hPipe == INVALID_HANDLE_VALUE)
137  {
138  DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
139  goto cleanup;
140  }
141 
142  /* Launch rundll32 to call ClientSideInstallW */
143  wcscpy(CommandLine, L"rundll32.exe newdev.dll,ClientSideInstall ");
144  wcscat(CommandLine, PipeName);
145 
146  ZeroMemory(&StartupInfo, sizeof(StartupInfo));
147  StartupInfo.cb = sizeof(StartupInfo);
148 
149  if (hUserToken)
150  {
151  /* newdev has to run under the environment of the current user */
153  {
154  DPRINT1("CreateEnvironmentBlock failed with error %d\n", GetLastError());
155  goto cleanup;
156  }
157 
158  if (!CreateProcessAsUserW(hUserToken, NULL, CommandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, Environment, NULL, &StartupInfo, &ProcessInfo))
159  {
160  DPRINT1("CreateProcessAsUserW failed with error %u\n", GetLastError());
161  goto cleanup;
162  }
163  }
164  else
165  {
166  /* FIXME: This is probably not correct, I guess newdev should never be run with SYSTEM privileges.
167 
168  Still, we currently do that in 2nd stage setup and probably Console mode as well, so allow it here.
169  (ShowWizard is only set to FALSE for these two modes) */
170  ASSERT(!ShowWizard);
171 
172  if (!CreateProcessW(NULL, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo))
173  {
174  DPRINT1("CreateProcessW failed with error %u\n", GetLastError());
175  goto cleanup;
176  }
177  }
178 
179  /* Wait for the function to connect to our pipe */
180  if (!ConnectNamedPipe(hPipe, NULL))
181  {
183  {
184  DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
185  goto cleanup;
186  }
187  }
188 
189  /* Pass the data. The following output is partly compatible to Windows XP SP2 (researched using a modified newdev.dll to log this stuff) */
190  Value = sizeof(InstallEventName);
191  WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
192  WriteFile(hPipe, InstallEventName, Value, &BytesWritten, NULL);
193 
194  /* I couldn't figure out what the following value means under WinXP. It's usually 0 in my tests, but was also 5 once.
195  Therefore the following line is entirely ReactOS-specific. We use the value here to pass the ShowWizard variable. */
196  WriteFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesWritten, NULL);
197 
198  Value = (wcslen(DeviceInstance) + 1) * sizeof(WCHAR);
199  WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
201 
202  /* Wait for newdev.dll to finish processing */
203  WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
204 
205  /* If the event got signalled, this is success */
206  DeviceInstalled = WaitForSingleObject(hInstallEvent, 0) == WAIT_OBJECT_0;
207 
208 cleanup:
209  if (hInstallEvent)
211 
212  if (hPipe != INVALID_HANDLE_VALUE)
213  CloseHandle(hPipe);
214 
215  if (Environment)
217 
218  if (ProcessInfo.hProcess)
219  CloseHandle(ProcessInfo.hProcess);
220 
221  if (ProcessInfo.hThread)
222  CloseHandle(ProcessInfo.hThread);
223 
224  if (!DeviceInstalled)
225  {
226  DPRINT1("InstallDevice failed for DeviceInstance '%ws'\n", DeviceInstance);
227  }
228 
229  return DeviceInstalled;
230 }
231 
232 
233 static LONG
235  IN HKEY hKey,
236  IN LPCWSTR pszKey,
237  OUT LPWSTR* pValue)
238 {
239  LONG rc;
240  DWORD dwType;
241  DWORD cbData = 0;
242  LPWSTR Value;
243 
244  if (!pValue)
246 
247  *pValue = NULL;
248  rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
249  if (rc != ERROR_SUCCESS)
250  return rc;
251  if (dwType != REG_SZ)
252  return ERROR_FILE_NOT_FOUND;
253  Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
254  if (!Value)
256  rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
257  if (rc != ERROR_SUCCESS)
258  {
260  return rc;
261  }
262  /* NULL-terminate the string */
263  Value[cbData / sizeof(WCHAR)] = '\0';
264 
265  *pValue = Value;
266  return ERROR_SUCCESS;
267 }
268 
269 
270 BOOL
272 {
273  HKEY hKey = NULL;
274  DWORD regType, active, size;
275  LONG rc;
276  BOOL ret = FALSE;
277 
278  rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, KEY_QUERY_VALUE, &hKey);
279  if (rc != ERROR_SUCCESS)
280  goto cleanup;
281 
282  size = sizeof(DWORD);
283  rc = RegQueryValueExW(hKey, L"SystemSetupInProgress", NULL, &regType, (LPBYTE)&active, &size);
284  if (rc != ERROR_SUCCESS)
285  goto cleanup;
286  if (regType != REG_DWORD || size != sizeof(DWORD))
287  goto cleanup;
288 
289  ret = (active != 0);
290 
291 cleanup:
292  if (hKey != NULL)
293  RegCloseKey(hKey);
294 
295  DPRINT("System setup in progress? %S\n", ret ? L"YES" : L"NO");
296 
297  return ret;
298 }
299 
300 
301 static BOOL
303 {
304  HKEY ControlKey = NULL;
305  LPWSTR SystemStartOptions = NULL;
306  LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
307  BOOL ConsoleBoot = FALSE;
308  LONG rc;
309 
310  rc = RegOpenKeyExW(
312  L"SYSTEM\\CurrentControlSet\\Control",
313  0,
315  &ControlKey);
316 
317  rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
318  if (rc != ERROR_SUCCESS)
319  goto cleanup;
320 
321  /* Check for CONSOLE switch in SystemStartOptions */
322  CurrentOption = SystemStartOptions;
323  while (CurrentOption)
324  {
325  NextOption = wcschr(CurrentOption, L' ');
326  if (NextOption)
327  *NextOption = L'\0';
328  if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
329  {
330  DPRINT("Found %S. Switching to console boot\n", CurrentOption);
331  ConsoleBoot = TRUE;
332  goto cleanup;
333  }
334  CurrentOption = NextOption ? NextOption + 1 : NULL;
335  }
336 
337 cleanup:
338  if (ControlKey != NULL)
339  RegCloseKey(ControlKey);
340  HeapFree(GetProcessHeap(), 0, SystemStartOptions);
341  return ConsoleBoot;
342 }
343 
344 
346 BOOL
348 {
349  /* Display the newdev.dll wizard UI only if it's allowed */
351 }
352 
353 
354 /* Loop to install all queued devices installations */
355 DWORD
356 WINAPI
358 {
359  PLIST_ENTRY ListEntry;
361  BOOL showWizard;
362 
364 
366 
367  showWizard = !SetupIsActive() && !IsConsoleBoot();
368 
369  while (TRUE)
370  {
371  /* Dequeue the next oldest device-install event */
373  ListEntry = (IsListEmpty(&DeviceInstallListHead)
376 
377  if (ListEntry == NULL)
378  {
381  }
382  else
383  {
385  Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry);
386  InstallDevice(Params->DeviceIds, showWizard && !IsUISuppressionAllowed());
388  }
389  }
390 
391  return 0;
392 }
static HANDLE DWORD
Definition: install.c:28
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesWritten
Definition: wdfiotarget.h:949
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
DWORD size
Definition: install.c:3631
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
const uint16_t * PCWSTR
Definition: typedefs.h:57
PVOID PVOID PWCHAR PVOID Environment
Definition: env.c:45
#define IN
Definition: typedefs.h:39
#define CloseHandle
Definition: compat.h:598
#define ERROR_SUCCESS
Definition: deptool.c:10
_In_ WDFIOTARGET _In_ PWDF_REQUEST_COMPLETION_PARAMS Params
Definition: wdfrequest.h:306
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define CREATE_UNICODE_ENVIRONMENT
Definition: winbase.h:186
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
HANDLE hInstallEvent
Definition: install.c:40
PWCHAR pValue
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:590
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1044
#define ZeroMemory
Definition: winbase.h:1648
LIST_ENTRY DeviceInstallListHead
Definition: install.c:45
static BOOL InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
Definition: install.c:52
BOOL WINAPI CreateEnvironmentBlock(OUT LPVOID *lpEnvironment, IN HANDLE hToken, IN BOOL bInherit)
Definition: environment.c:505
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
FORCEINLINE BOOL IsUISuppressionAllowed(VOID)
Definition: install.c:347
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:651
static BOOL IsConsoleBoot(VOID)
Definition: install.c:302
static LONG ReadRegSzKey(IN HKEY hKey, IN LPCWSTR pszKey, OUT LPWSTR *pValue)
Definition: install.c:234
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
unsigned char * LPBYTE
Definition: typedefs.h:53
#define FALSE
Definition: types.h:117
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
#define PIPE_TYPE_BYTE
Definition: winbase.h:167
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
void DPRINT(...)
Definition: polytest.cpp:61
HANDLE hNoPendingInstalls
Definition: install.c:41
#define ERROR_FILE_NOT_FOUND
Definition: disk.h:79
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation)
Definition: proc.c:4595
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:406
HANDLE hUserToken
Definition: install.c:39
#define WAIT_OBJECT_0
Definition: winbase.h:387
GLsizeiptr size
Definition: glext.h:5919
#define GetProcessHeap()
Definition: compat.h:595
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
DWORD cb
Definition: winbase.h:830
_CONST_RETURN wchar_t *__cdecl wcschr(_In_z_ const wchar_t *_Str, wchar_t _Ch)
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4116
#define ASSERT(a)
Definition: mode.c:45
BOOL SetupIsActive(VOID)
Definition: install.c:271
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define swprintf(buf, format,...)
Definition: sprintf.c:56
#define WINAPI
Definition: msvc.h:6
unsigned long DWORD
Definition: ntddk_ex.h:95
#define PIPE_ACCESS_OUTBOUND
Definition: winbase.h:166
HKEY hEnumKey
Definition: umpnpmgr.c:44
BOOL WINAPI DECLSPEC_HOTPATCH ReleaseMutex(IN HANDLE hMutex)
Definition: synch.c:618
int ret
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
static const WCHAR L[]
Definition: oid.c:1250
BOOL WINAPI DestroyEnvironmentBlock(IN LPVOID lpEnvironment)
Definition: environment.c:727
#define ERROR_PIPE_CONNECTED
Definition: winerror.h:352
BOOL g_IsUISuppressed
Definition: umpnpmgr.c:46
LPVOID lpParameter
Definition: kernel32.h:241
_In_ PNDIS_STRING DeviceInstance
Definition: ndis.h:5202
Definition: typedefs.h:119
HANDLE hDeviceInstallListNotEmpty
Definition: install.c:46
BOOL WINAPI DECLSPEC_HOTPATCH CreateProcessAsUserW(_In_opt_ HANDLE hToken, _In_opt_ LPCWSTR lpApplicationName, _Inout_opt_ LPWSTR lpCommandLine, _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, _In_ BOOL bInheritHandles, _In_ DWORD dwCreationFlags, _In_opt_ LPVOID lpEnvironment, _In_opt_ LPCWSTR lpCurrentDirectory, _In_ LPSTARTUPINFOW lpStartupInfo, _Out_ LPPROCESS_INFORMATION lpProcessInformation)
Definition: logon.c:281
RPC_STATUS WINAPI UuidCreate(UUID *Uuid)
Definition: rpcrt4_main.c:303
FxAutoRegKey hKey
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
#define FORCEINLINE
Definition: wdftypes.h:67
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
#define NULL
Definition: types.h:112
BOOL WINAPI DECLSPEC_HOTPATCH ResetEvent(IN HANDLE hEvent)
Definition: synch.c:714
#define DPRINT1
Definition: precomp.h:8
BOOL GetSuppressNewUIValue(VOID)
Definition: umpnpmgr.c:330
#define OUT
Definition: typedefs.h:40
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3366
char * cleanup(char *str)
Definition: wpickclick.c:99
WCHAR * LPWSTR
Definition: xmlstorage.h:184
HANDLE WINAPI CreateNamedPipeW(LPCWSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances, DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
Definition: npipe.c:246
HANDLE hDeviceInstallListMutex
Definition: install.c:44
#define INFINITE
Definition: serial.h:102
#define REG_DWORD
Definition: sdbapi.c:596
DWORD WINAPI DeviceInstallThread(LPVOID lpParameter)
Definition: install.c:357
BOOL WINAPI ConnectNamedPipe(IN HANDLE hNamedPipe, IN LPOVERLAPPED lpOverlapped)
Definition: npipe.c:701
BYTE * PBYTE
Definition: pedump.c:66
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define HeapFree(x, y, z)
Definition: compat.h:594
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define CONFIGFLAG_FAILEDINSTALL
Definition: regstr.h:396
static char * NextOption(const char *const ostr)
Definition: getopt.c:31
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define REG_SZ
Definition: layer.c:22