ReactOS  0.4.14-dev-358-gbef841c
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 
45 
46 
47 /* FUNCTIONS *****************************************************************/
48 
49 static BOOL
51 {
52  BOOL DeviceInstalled = FALSE;
54  DWORD Value;
58  PROCESS_INFORMATION ProcessInfo;
59  STARTUPINFOW StartupInfo;
60  UUID RandomUuid;
61  HKEY DeviceKey;
62 
63  /* The following lengths are constant (see below), they cannot overflow */
64  WCHAR CommandLine[116];
65  WCHAR InstallEventName[73];
66  WCHAR PipeName[74];
67  WCHAR UuidString[39];
68 
69  DPRINT("InstallDevice(%S, %d)\n", DeviceInstance, ShowWizard);
70 
71  ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
72 
75  0,
77  &DeviceKey) == ERROR_SUCCESS)
78  {
79  if (RegQueryValueExW(DeviceKey,
80  L"Class",
81  NULL,
82  NULL,
83  NULL,
84  NULL) == ERROR_SUCCESS)
85  {
86  DPRINT("No need to install: %S\n", DeviceInstance);
87  RegCloseKey(DeviceKey);
88  return TRUE;
89  }
90 
91  BytesWritten = sizeof(DWORD);
92  if (RegQueryValueExW(DeviceKey,
93  L"ConfigFlags",
94  NULL,
95  NULL,
96  (PBYTE)&Value,
98  {
100  {
101  DPRINT("No need to install: %S\n", DeviceInstance);
102  RegCloseKey(DeviceKey);
103  return TRUE;
104  }
105  }
106 
107  RegCloseKey(DeviceKey);
108  }
109 
110  DPRINT1("Installing: %S\n", DeviceInstance);
111 
112  /* Create a random UUID for the named pipe & event*/
113  UuidCreate(&RandomUuid);
114  swprintf(UuidString, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
115  RandomUuid.Data1, RandomUuid.Data2, RandomUuid.Data3,
116  RandomUuid.Data4[0], RandomUuid.Data4[1], RandomUuid.Data4[2],
117  RandomUuid.Data4[3], RandomUuid.Data4[4], RandomUuid.Data4[5],
118  RandomUuid.Data4[6], RandomUuid.Data4[7]);
119 
120  /* Create the event */
121  wcscpy(InstallEventName, L"Global\\PNP_Device_Install_Event_0.");
122  wcscat(InstallEventName, UuidString);
123  hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName);
124  if (!hInstallEvent)
125  {
126  DPRINT1("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError());
127  goto cleanup;
128  }
129 
130  /* Create the named pipe */
131  wcscpy(PipeName, L"\\\\.\\pipe\\PNP_Device_Install_Pipe_0.");
132  wcscat(PipeName, UuidString);
133  hPipe = CreateNamedPipeW(PipeName, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 512, 512, 0, NULL);
134  if (hPipe == INVALID_HANDLE_VALUE)
135  {
136  DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
137  goto cleanup;
138  }
139 
140  /* Launch rundll32 to call ClientSideInstallW */
141  wcscpy(CommandLine, L"rundll32.exe newdev.dll,ClientSideInstall ");
142  wcscat(CommandLine, PipeName);
143 
144  ZeroMemory(&StartupInfo, sizeof(StartupInfo));
145  StartupInfo.cb = sizeof(StartupInfo);
146 
147  if (hUserToken)
148  {
149  /* newdev has to run under the environment of the current user */
151  {
152  DPRINT1("CreateEnvironmentBlock failed with error %d\n", GetLastError());
153  goto cleanup;
154  }
155 
156  if (!CreateProcessAsUserW(hUserToken, NULL, CommandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, Environment, NULL, &StartupInfo, &ProcessInfo))
157  {
158  DPRINT1("CreateProcessAsUserW failed with error %u\n", GetLastError());
159  goto cleanup;
160  }
161  }
162  else
163  {
164  /* FIXME: This is probably not correct, I guess newdev should never be run with SYSTEM privileges.
165 
166  Still, we currently do that in 2nd stage setup and probably Console mode as well, so allow it here.
167  (ShowWizard is only set to FALSE for these two modes) */
168  ASSERT(!ShowWizard);
169 
170  if (!CreateProcessW(NULL, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo))
171  {
172  DPRINT1("CreateProcessW failed with error %u\n", GetLastError());
173  goto cleanup;
174  }
175  }
176 
177  /* Wait for the function to connect to our pipe */
178  if (!ConnectNamedPipe(hPipe, NULL))
179  {
181  {
182  DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
183  goto cleanup;
184  }
185  }
186 
187  /* Pass the data. The following output is partly compatible to Windows XP SP2 (researched using a modified newdev.dll to log this stuff) */
188  Value = sizeof(InstallEventName);
189  WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
190  WriteFile(hPipe, InstallEventName, Value, &BytesWritten, NULL);
191 
192  /* I couldn't figure out what the following value means under WinXP. It's usually 0 in my tests, but was also 5 once.
193  Therefore the following line is entirely ReactOS-specific. We use the value here to pass the ShowWizard variable. */
194  WriteFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesWritten, NULL);
195 
196  Value = (wcslen(DeviceInstance) + 1) * sizeof(WCHAR);
197  WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
199 
200  /* Wait for newdev.dll to finish processing */
201  WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
202 
203  /* If the event got signalled, this is success */
204  DeviceInstalled = WaitForSingleObject(hInstallEvent, 0) == WAIT_OBJECT_0;
205 
206 cleanup:
207  if (hInstallEvent)
209 
210  if (hPipe != INVALID_HANDLE_VALUE)
211  CloseHandle(hPipe);
212 
213  if (Environment)
215 
216  if (ProcessInfo.hProcess)
217  CloseHandle(ProcessInfo.hProcess);
218 
219  if (ProcessInfo.hThread)
220  CloseHandle(ProcessInfo.hThread);
221 
222  if (!DeviceInstalled)
223  {
224  DPRINT1("InstallDevice failed for DeviceInstance '%ws'\n", DeviceInstance);
225  }
226 
227  return DeviceInstalled;
228 }
229 
230 
231 static LONG
233  IN HKEY hKey,
234  IN LPCWSTR pszKey,
235  OUT LPWSTR* pValue)
236 {
237  LONG rc;
238  DWORD dwType;
239  DWORD cbData = 0;
240  LPWSTR Value;
241 
242  if (!pValue)
244 
245  *pValue = NULL;
246  rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
247  if (rc != ERROR_SUCCESS)
248  return rc;
249  if (dwType != REG_SZ)
250  return ERROR_FILE_NOT_FOUND;
251  Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
252  if (!Value)
254  rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
255  if (rc != ERROR_SUCCESS)
256  {
258  return rc;
259  }
260  /* NULL-terminate the string */
261  Value[cbData / sizeof(WCHAR)] = '\0';
262 
263  *pValue = Value;
264  return ERROR_SUCCESS;
265 }
266 
267 
268 BOOL
270 {
271  HKEY hKey = NULL;
272  DWORD regType, active, size;
273  LONG rc;
274  BOOL ret = FALSE;
275 
276  rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, KEY_QUERY_VALUE, &hKey);
277  if (rc != ERROR_SUCCESS)
278  goto cleanup;
279 
280  size = sizeof(DWORD);
281  rc = RegQueryValueExW(hKey, L"SystemSetupInProgress", NULL, &regType, (LPBYTE)&active, &size);
282  if (rc != ERROR_SUCCESS)
283  goto cleanup;
284  if (regType != REG_DWORD || size != sizeof(DWORD))
285  goto cleanup;
286 
287  ret = (active != 0);
288 
289 cleanup:
290  if (hKey != NULL)
291  RegCloseKey(hKey);
292 
293  DPRINT("System setup in progress? %S\n", ret ? L"YES" : L"NO");
294 
295  return ret;
296 }
297 
298 
299 static BOOL
301 {
302  HKEY ControlKey = NULL;
303  LPWSTR SystemStartOptions = NULL;
304  LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
305  BOOL ConsoleBoot = FALSE;
306  LONG rc;
307 
308  rc = RegOpenKeyExW(
310  L"SYSTEM\\CurrentControlSet\\Control",
311  0,
313  &ControlKey);
314 
315  rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
316  if (rc != ERROR_SUCCESS)
317  goto cleanup;
318 
319  /* Check for CONSOLE switch in SystemStartOptions */
320  CurrentOption = SystemStartOptions;
321  while (CurrentOption)
322  {
323  NextOption = wcschr(CurrentOption, L' ');
324  if (NextOption)
325  *NextOption = L'\0';
326  if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
327  {
328  DPRINT("Found %S. Switching to console boot\n", CurrentOption);
329  ConsoleBoot = TRUE;
330  goto cleanup;
331  }
332  CurrentOption = NextOption ? NextOption + 1 : NULL;
333  }
334 
335 cleanup:
336  if (ControlKey != NULL)
337  RegCloseKey(ControlKey);
338  HeapFree(GetProcessHeap(), 0, SystemStartOptions);
339  return ConsoleBoot;
340 }
341 
342 
344 BOOL
346 {
347  /* Display the newdev.dll wizard UI only if it's allowed */
349 }
350 
351 
352 /* Loop to install all queued devices installations */
353 DWORD
354 WINAPI
356 {
357  PSLIST_ENTRY ListEntry;
358  DeviceInstallParams* Params;
359  BOOL showWizard;
360 
362 
364 
365  showWizard = !SetupIsActive() && !IsConsoleBoot();
366 
367  while (TRUE)
368  {
370 
371  if (ListEntry == NULL)
372  {
375  }
376  else
377  {
379  Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry);
380  InstallDevice(Params->DeviceIds, showWizard && !IsUISuppressionAllowed());
381  HeapFree(GetProcessHeap(), 0, Params);
382  }
383  }
384 
385  return 0;
386 }
static HANDLE DWORD
Definition: install.c:28
_In_opt_ ULONG _Out_ PULONG Value
Definition: rtlfuncs.h:2343
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
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:55
PVOID PVOID PWCHAR PVOID Environment
Definition: env.c:45
#define IN
Definition: typedefs.h:38
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesWritten
Definition: fltkernel.h:1293
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:406
#define ERROR_SUCCESS
Definition: deptool.c:10
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
#define CREATE_UNICODE_ENVIRONMENT
Definition: winbase.h:186
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
HANDLE hInstallEvent
Definition: install.c:40
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define INVALID_HANDLE_VALUE
Definition: compat.h:399
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:733
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1642
static BOOL InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
Definition: install.c:50
BOOL WINAPI CreateEnvironmentBlock(OUT LPVOID *lpEnvironment, IN HANDLE hToken, IN BOOL bInherit)
Definition: environment.c:505
SLIST_HEADER DeviceInstallListHead
Definition: install.c:43
FORCEINLINE BOOL IsUISuppressionAllowed(VOID)
Definition: install.c:345
PSLIST_ENTRY WINAPI InterlockedPopEntrySList(PSLIST_HEADER ListHead)
Definition: interlocked.c:55
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:300
static LONG ReadRegSzKey(IN HKEY hKey, IN LPCWSTR pszKey, OUT LPWSTR *pValue)
Definition: install.c:232
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:52
unsigned int BOOL
Definition: ntddk_ex.h:94
long LONG
Definition: pedump.c:60
#define PIPE_TYPE_BYTE
Definition: winbase.h:167
smooth NULL
Definition: ftsmooth.c:416
#define FORCEINLINE
Definition: ntbasedef.h:221
WCHAR DeviceIds[1]
Definition: precomp.h:39
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:4593
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:403
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
DWORD cb
Definition: winbase.h:824
_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
BOOL SetupIsActive(VOID)
Definition: install.c:269
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define swprintf(buf, format,...)
Definition: sprintf.c:56
#define WINAPI
Definition: msvc.h:8
unsigned long DWORD
Definition: ntddk_ex.h:95
#define PSLIST_ENTRY
Definition: rtltypes.h:130
#define PIPE_ACCESS_OUTBOUND
Definition: winbase.h:166
HKEY hEnumKey
Definition: umpnpmgr.c:44
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
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
HANDLE hDeviceInstallListNotEmpty
Definition: install.c:44
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:306
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
BOOL WINAPI DECLSPEC_HOTPATCH ResetEvent(IN HANDLE hEvent)
Definition: synch.c:714
#define DPRINT1
Definition: precomp.h:8
BOOL GetSuppressNewUIValue(VOID)
Definition: umpnpmgr.c:325
#define OUT
Definition: typedefs.h:39
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
#define INFINITE
Definition: serial.h:102
#define REG_DWORD
Definition: sdbapi.c:596
DWORD WINAPI DeviceInstallThread(LPVOID lpParameter)
Definition: install.c:355
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:402
_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