Author: cfinck
Date: Wed Apr 15 02:31:36 2009
New Revision: 40513
URL:
http://svn.reactos.org/svn/reactos?rev=40513&view=rev
Log:
- Use rundll32.exe and CreateProcessAsUserW to call ClientSideInstallW for installing new
devices and supply all required information over a named pipe.
The named pipe communication was monitored under Windows XP SP2, so that the protocol
under ReactOS is compatible (except for one data field, see code)
- Implement ClientSideInstallW in newdev.dll
- Give umpnpmgr the SE_ASSIGNPRIMARYTOKEN privilege to use CreateProcessAsUserW
- Open the token of the userinit process with TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE |
TOKEN_QUERY, we don't get TOKEN_ALL_ACCESS and used to fail here without noticing it
- Return CR_FAILURE in case of problems inside PNP_ReportLogOn
This stuff by the way fixes the "Browse" button in a "New hardware
device" dialog
See issue #4363 for more details.
Modified:
trunk/reactos/base/services/umpnpmgr/umpnpmgr.c
trunk/reactos/base/services/umpnpmgr/umpnpmgr.rbuild
trunk/reactos/dll/win32/newdev/newdev.c
Modified: trunk/reactos/base/services/umpnpmgr/umpnpmgr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/umpnpmgr/ump…
==============================================================================
--- trunk/reactos/base/services/umpnpmgr/umpnpmgr.c [iso-8859-1] (original)
+++ trunk/reactos/base/services/umpnpmgr/umpnpmgr.c [iso-8859-1] Wed Apr 15 02:31:36 2009
@@ -23,19 +23,23 @@
* PURPOSE: User-mode Plug and Play manager
* PROGRAMMER: Eric Kohl
* Hervé Poussineau (hpoussin(a)reactos.org)
+ * Colin Finck (colin(a)reactos.org)
*/
/* INCLUDES *****************************************************************/
//#define HAVE_SLIST_ENTRY_IMPLEMENTED
#define WIN32_NO_STATUS
#include <windows.h>
+#include <stdio.h>
#include <cmtypes.h>
#include <cmfuncs.h>
#include <rtlfuncs.h>
+#include <setypes.h>
#include <umpnpmgr/sysguid.h>
#include <wdmguid.h>
#include <cfgmgr32.h>
#include <regstr.h>
+#include <userenv.h>
#include <rpc.h>
#include <rpcdce.h>
@@ -222,6 +226,7 @@
BOOL Admin,
DWORD ProcessId)
{
+ DWORD ReturnValue = CR_FAILURE;
HANDLE hProcess;
UNREFERENCED_PARAMETER(hBinding);
@@ -233,28 +238,37 @@
SetEvent(hInstallEvent);
/* Get the users token */
- hProcess = OpenProcess(PROCESS_ALL_ACCESS,
- TRUE,
- ProcessId);
- if (hProcess != NULL)
- {
- if (hUserToken != NULL)
- {
- CloseHandle(hUserToken);
- hUserToken = NULL;
- }
-
- OpenProcessToken(hProcess,
- TOKEN_ALL_ACCESS,
- &hUserToken);
- CloseHandle(hProcess);
+ hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcessId);
+
+ if(!hProcess)
+ {
+ DPRINT1("OpenProcess failed with error %u\n", GetLastError());
+ goto cleanup;
+ }
+
+ if (hUserToken)
+ {
+ CloseHandle(hUserToken);
+ hUserToken = NULL;
+ }
+
+ if(!OpenProcessToken(hProcess, TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY,
&hUserToken))
+ {
+ DPRINT1("OpenProcessToken failed with error %u\n", GetLastError());
+ goto cleanup;
}
/* Trigger the installer thread */
/*if (hInstallEvent != NULL)
SetEvent(hInstallEvent);*/
- return CR_SUCCESS;
+ ReturnValue = CR_SUCCESS;
+
+cleanup:
+ if(hProcess)
+ CloseHandle(hProcess);
+
+ return ReturnValue;
}
@@ -1900,18 +1914,29 @@
}
-typedef BOOL (WINAPI *PDEV_INSTALL_W)(HWND, HINSTANCE, LPCWSTR, INT);
-
static BOOL
InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
{
PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
- HMODULE hNewDev = NULL;
- PDEV_INSTALL_W DevInstallW;
NTSTATUS Status;
BOOL DeviceInstalled = FALSE;
+ DWORD BytesWritten;
+ DWORD Value;
+ HANDLE hPipe = INVALID_HANDLE_VALUE;
+ LPVOID Environment = NULL;
+ PROCESS_INFORMATION ProcessInfo;
+ STARTUPINFOW StartupInfo;
+ UUID RandomUuid;
+
+ /* The following lengths are constant (see below), they cannot overflow */
+ WCHAR CommandLine[116];
+ WCHAR InstallEventName[73];
+ WCHAR PipeName[74];
+ WCHAR UuidString[39];
DPRINT("InstallDevice(%S, %d)\n", DeviceInstance, ShowWizard);
+
+ ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
DeviceInstance);
@@ -1934,34 +1959,109 @@
return TRUE;
}
- /* Install device */
- SetEnvironmentVariableW(L"USERPROFILE", L"."); /* FIXME: why is
it needed? */
-
- hNewDev = LoadLibraryW(L"newdev.dll");
- if (!hNewDev)
- {
- DPRINT1("Unable to load newdev.dll\n");
+ /* Create a random UUID for the named pipe */
+ UuidCreate(&RandomUuid);
+ swprintf(UuidString,
L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+ RandomUuid.Data1, RandomUuid.Data2, RandomUuid.Data3,
+ RandomUuid.Data4[0], RandomUuid.Data4[1], RandomUuid.Data4[2],
+ RandomUuid.Data4[3], RandomUuid.Data4[4], RandomUuid.Data4[5],
+ RandomUuid.Data4[6], RandomUuid.Data4[7]);
+
+ /* Create the named pipe */
+ wcscpy(PipeName, L"\\\\.\\pipe\\PNP_Device_Install_Pipe_0.");
+ wcscat(PipeName, UuidString);
+ hPipe = CreateNamedPipeW(PipeName, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 512, 512,
0, NULL);
+
+ if(hPipe == INVALID_HANDLE_VALUE)
+ {
+ DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
goto cleanup;
}
- DevInstallW = (PDEV_INSTALL_W)GetProcAddress(hNewDev,
(LPCSTR)"DevInstallW");
- if (!DevInstallW)
- {
- DPRINT1("'DevInstallW' not found in newdev.dll\n");
+ /* Launch rundll32 to call ClientSideInstallW */
+ wcscpy(CommandLine, L"rundll32.exe newdev.dll,ClientSideInstall ");
+ wcscat(CommandLine, PipeName);
+
+ ZeroMemory(&StartupInfo, sizeof(StartupInfo));
+ StartupInfo.cb = sizeof(StartupInfo);
+
+ if(hUserToken)
+ {
+ /* newdev has to run under the environment of the current user */
+ if(!CreateEnvironmentBlock(&Environment, hUserToken, FALSE))
+ {
+ DPRINT1("CreateEnvironmentBlock failed with error %d\n",
GetLastError());
+ goto cleanup;
+ }
+
+ if(!CreateProcessAsUserW(hUserToken, NULL, CommandLine, NULL, NULL, FALSE,
CREATE_UNICODE_ENVIRONMENT, Environment, NULL, &StartupInfo, &ProcessInfo))
+ {
+ DPRINT1("CreateProcessAsUserW failed with error %u\n",
GetLastError());
+ goto cleanup;
+ }
+ }
+ else
+ {
+ /* FIXME: This is probably not correct, I guess newdev should never be run with
SYSTEM privileges.
+
+ Still, we currently do that in 2nd stage setup and probably Console mode as
well, so allow it here.
+ (ShowWizard is only set to FALSE for these two modes) */
+ ASSERT(!ShowWizard);
+
+ if(!CreateProcessW(NULL, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL,
&StartupInfo, &ProcessInfo))
+ {
+ DPRINT1("CreateProcessW failed with error %u\n", GetLastError());
+ goto cleanup;
+ }
+ }
+
+ /* Wait for the function to connect to our pipe */
+ if(!ConnectNamedPipe(hPipe, NULL))
+ {
+ DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
goto cleanup;
}
- if (!DevInstallW(NULL, NULL, DeviceInstance, ShowWizard ? SW_SHOWNOACTIVATE :
SW_HIDE))
- {
- DPRINT1("DevInstallW('%S') failed\n", DeviceInstance);
+ /* Pass the data. The following output is partly compatible to Windows XP SP2
(researched using a modified newdev.dll to log this stuff) */
+ wcscpy(InstallEventName, L"Global\\PNP_Device_Install_Event_0.");
+ wcscat(InstallEventName, UuidString);
+
+ Value = sizeof(InstallEventName);
+ WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
+ WriteFile(hPipe, InstallEventName, Value, &BytesWritten, NULL);
+
+ /* I couldn't figure out what the following value means under WinXP. It's
usually 0 in my tests, but was also 5 once.
+ Therefore the following line is entirely ReactOS-specific. We use the value here
to pass the ShowWizard variable. */
+ WriteFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesWritten, NULL);
+
+ Value = (wcslen(DeviceInstance) + 1) * sizeof(WCHAR);
+ WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
+ WriteFile(hPipe, DeviceInstance, Value, &BytesWritten, NULL);
+
+ /* Wait for newdev.dll to finish processing */
+ WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
+
+ /* The following check for success is probably not compatible to Windows, but should
do its job */
+ if(!GetExitCodeProcess(ProcessInfo.hProcess, &Value))
+ {
+ DPRINT1("GetExitCodeProcess failed with error %u\n", GetLastError());
goto cleanup;
}
- DeviceInstalled = TRUE;
+ DeviceInstalled = Value;
cleanup:
- if (hNewDev != NULL)
- FreeLibrary(hNewDev);
+ if(hPipe != INVALID_HANDLE_VALUE)
+ CloseHandle(hPipe);
+
+ if(Environment)
+ DestroyEnvironmentBlock(Environment);
+
+ if(ProcessInfo.hProcess)
+ CloseHandle(ProcessInfo.hProcess);
+
+ if(ProcessInfo.hThread)
+ CloseHandle(ProcessInfo.hThread);
return DeviceInstalled;
}
@@ -2255,12 +2355,16 @@
int
wmain(int argc, WCHAR *argv[])
{
+ BOOLEAN OldValue;
DWORD dwError;
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
DPRINT("Umpnpmgr: main() started\n");
+
+ /* We need this privilege for using CreateProcessAsUserW */
+ RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &OldValue);
hInstallEvent = CreateEvent(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL);
if (hInstallEvent == NULL)
Modified: trunk/reactos/base/services/umpnpmgr/umpnpmgr.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/services/umpnpmgr/ump…
==============================================================================
--- trunk/reactos/base/services/umpnpmgr/umpnpmgr.rbuild [iso-8859-1] (original)
+++ trunk/reactos/base/services/umpnpmgr/umpnpmgr.rbuild [iso-8859-1] Wed Apr 15 02:31:36
2009
@@ -11,6 +11,7 @@
<library>rpcrt4</library>
<library>pseh</library>
<library>wdmguid</library>
+ <library>userenv</library>
<file>umpnpmgr.c</file>
<file>umpnpmgr.rc</file>
</module>
Modified: trunk/reactos/dll/win32/newdev/newdev.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/newdev/newdev.c?…
==============================================================================
--- trunk/reactos/dll/win32/newdev/newdev.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/newdev/newdev.c [iso-8859-1] Wed Apr 15 02:31:36 2009
@@ -3,6 +3,7 @@
*
* Copyright 2005-2006 Hervé Poussineau (hpoussin(a)reactos.org)
* 2005 Christoph von Wittich (Christoph(a)ActiveVB.de)
+ * 2009 Colin Finck (colin(a)reactos.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -803,7 +804,7 @@
}
/*
-* @unimplemented
+* @implemented
*/
BOOL WINAPI
ClientSideInstallW(
@@ -811,11 +812,75 @@
IN DWORD dwUnknownFlags,
IN LPWSTR lpNamedPipeName)
{
- /* NOTE: pNamedPipeName is in the format:
- *
"\\.\pipe\PNP_Device_Install_Pipe_0.{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
- */
- FIXME("Stub\n");
- return FALSE;
+ BOOL ReturnValue = FALSE;
+ BOOL ShowWizard;
+ DWORD BytesRead;
+ DWORD Value;
+ HANDLE hPipe = INVALID_HANDLE_VALUE;
+ PWSTR DeviceInstance = NULL;
+ PWSTR InstallEventName = NULL;
+
+ /* Open the pipe */
+ hPipe = CreateFileW(lpNamedPipeName, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if(hPipe == INVALID_HANDLE_VALUE)
+ {
+ ERR("CreateFileW failed with error %u\n", GetLastError());
+ goto cleanup;
+ }
+
+ /* Read the data. Some is just included for compatibility with Windows right now and
not yet used by ReactOS.
+ See umpnpmgr for more details. */
+ if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
+ {
+ ERR("ReadFile failed with error %u\n", GetLastError());
+ goto cleanup;
+ }
+
+ InstallEventName = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
+
+ if(!ReadFile(hPipe, InstallEventName, Value, &BytesRead, NULL))
+ {
+ ERR("ReadFile failed with error %u\n", GetLastError());
+ goto cleanup;
+ }
+
+ /* I couldn't figure out what the following value means under Windows XP.
+ Therefore I used it in umpnpmgr to pass the ShowWizard variable. */
+ if(!ReadFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesRead, NULL))
+ {
+ ERR("ReadFile failed with error %u\n", GetLastError());
+ goto cleanup;
+ }
+
+ /* Next one is again size in bytes of the following string */
+ if(!ReadFile(hPipe, &Value, sizeof(Value), &BytesRead, NULL))
+ {
+ ERR("ReadFile failed with error %u\n", GetLastError());
+ goto cleanup;
+ }
+
+ DeviceInstance = (PWSTR)HeapAlloc(GetProcessHeap(), 0, Value);
+
+ if(!ReadFile(hPipe, DeviceInstance, Value, &BytesRead, NULL))
+ {
+ ERR("ReadFile failed with error %u\n", GetLastError());
+ goto cleanup;
+ }
+
+ ReturnValue = DevInstallW(NULL, NULL, DeviceInstance, ShowWizard ? SW_SHOWNOACTIVATE
: SW_HIDE);
+
+cleanup:
+ if(hPipe != INVALID_HANDLE_VALUE)
+ CloseHandle(hPipe);
+
+ if(InstallEventName)
+ HeapFree(GetProcessHeap(), 0, InstallEventName);
+
+ if(DeviceInstance)
+ HeapFree(GetProcessHeap(), 0, DeviceInstance);
+
+ return ReturnValue;
}
BOOL WINAPI