mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 19:12:57 +00:00
- 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. svn path=/trunk/; revision=40513
This commit is contained in:
parent
2ef63b5190
commit
484b6902f1
3 changed files with 208 additions and 38 deletions
|
@ -23,19 +23,23 @@
|
||||||
* PURPOSE: User-mode Plug and Play manager
|
* PURPOSE: User-mode Plug and Play manager
|
||||||
* PROGRAMMER: Eric Kohl
|
* PROGRAMMER: Eric Kohl
|
||||||
* Hervé Poussineau (hpoussin@reactos.org)
|
* Hervé Poussineau (hpoussin@reactos.org)
|
||||||
|
* Colin Finck (colin@reactos.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES *****************************************************************/
|
||||||
//#define HAVE_SLIST_ENTRY_IMPLEMENTED
|
//#define HAVE_SLIST_ENTRY_IMPLEMENTED
|
||||||
#define WIN32_NO_STATUS
|
#define WIN32_NO_STATUS
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
#include <cmtypes.h>
|
#include <cmtypes.h>
|
||||||
#include <cmfuncs.h>
|
#include <cmfuncs.h>
|
||||||
#include <rtlfuncs.h>
|
#include <rtlfuncs.h>
|
||||||
|
#include <setypes.h>
|
||||||
#include <umpnpmgr/sysguid.h>
|
#include <umpnpmgr/sysguid.h>
|
||||||
#include <wdmguid.h>
|
#include <wdmguid.h>
|
||||||
#include <cfgmgr32.h>
|
#include <cfgmgr32.h>
|
||||||
#include <regstr.h>
|
#include <regstr.h>
|
||||||
|
#include <userenv.h>
|
||||||
|
|
||||||
#include <rpc.h>
|
#include <rpc.h>
|
||||||
#include <rpcdce.h>
|
#include <rpcdce.h>
|
||||||
|
@ -222,6 +226,7 @@ DWORD PNP_ReportLogOn(
|
||||||
BOOL Admin,
|
BOOL Admin,
|
||||||
DWORD ProcessId)
|
DWORD ProcessId)
|
||||||
{
|
{
|
||||||
|
DWORD ReturnValue = CR_FAILURE;
|
||||||
HANDLE hProcess;
|
HANDLE hProcess;
|
||||||
|
|
||||||
UNREFERENCED_PARAMETER(hBinding);
|
UNREFERENCED_PARAMETER(hBinding);
|
||||||
|
@ -233,28 +238,37 @@ DWORD PNP_ReportLogOn(
|
||||||
SetEvent(hInstallEvent);
|
SetEvent(hInstallEvent);
|
||||||
|
|
||||||
/* Get the users token */
|
/* Get the users token */
|
||||||
hProcess = OpenProcess(PROCESS_ALL_ACCESS,
|
hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcessId);
|
||||||
TRUE,
|
|
||||||
ProcessId);
|
|
||||||
if (hProcess != NULL)
|
|
||||||
{
|
|
||||||
if (hUserToken != NULL)
|
|
||||||
{
|
|
||||||
CloseHandle(hUserToken);
|
|
||||||
hUserToken = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenProcessToken(hProcess,
|
if(!hProcess)
|
||||||
TOKEN_ALL_ACCESS,
|
{
|
||||||
&hUserToken);
|
DPRINT1("OpenProcess failed with error %u\n", GetLastError());
|
||||||
CloseHandle(hProcess);
|
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 */
|
/* Trigger the installer thread */
|
||||||
/*if (hInstallEvent != NULL)
|
/*if (hInstallEvent != NULL)
|
||||||
SetEvent(hInstallEvent);*/
|
SetEvent(hInstallEvent);*/
|
||||||
|
|
||||||
return CR_SUCCESS;
|
ReturnValue = CR_SUCCESS;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if(hProcess)
|
||||||
|
CloseHandle(hProcess);
|
||||||
|
|
||||||
|
return ReturnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1900,19 +1914,30 @@ DWORD PNP_DeleteServiceDevices(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef BOOL (WINAPI *PDEV_INSTALL_W)(HWND, HINSTANCE, LPCWSTR, INT);
|
|
||||||
|
|
||||||
static BOOL
|
static BOOL
|
||||||
InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
|
InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
|
||||||
{
|
{
|
||||||
PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
|
PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
|
||||||
HMODULE hNewDev = NULL;
|
|
||||||
PDEV_INSTALL_W DevInstallW;
|
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
BOOL DeviceInstalled = FALSE;
|
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);
|
DPRINT("InstallDevice(%S, %d)\n", DeviceInstance, ShowWizard);
|
||||||
|
|
||||||
|
ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
|
||||||
|
|
||||||
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
|
||||||
DeviceInstance);
|
DeviceInstance);
|
||||||
PlugPlayData.Operation = 0; /* Get status */
|
PlugPlayData.Operation = 0; /* Get status */
|
||||||
|
@ -1934,34 +1959,109 @@ InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Install device */
|
/* Create a random UUID for the named pipe */
|
||||||
SetEnvironmentVariableW(L"USERPROFILE", L"."); /* FIXME: why is it needed? */
|
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]);
|
||||||
|
|
||||||
hNewDev = LoadLibraryW(L"newdev.dll");
|
/* Create the named pipe */
|
||||||
if (!hNewDev)
|
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("Unable to load newdev.dll\n");
|
DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
DevInstallW = (PDEV_INSTALL_W)GetProcAddress(hNewDev, (LPCSTR)"DevInstallW");
|
/* Launch rundll32 to call ClientSideInstallW */
|
||||||
if (!DevInstallW)
|
wcscpy(CommandLine, L"rundll32.exe newdev.dll,ClientSideInstall ");
|
||||||
|
wcscat(CommandLine, PipeName);
|
||||||
|
|
||||||
|
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
|
||||||
|
StartupInfo.cb = sizeof(StartupInfo);
|
||||||
|
|
||||||
|
if(hUserToken)
|
||||||
{
|
{
|
||||||
DPRINT1("'DevInstallW' not found in newdev.dll\n");
|
/* 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;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DevInstallW(NULL, NULL, DeviceInstance, ShowWizard ? SW_SHOWNOACTIVATE : SW_HIDE))
|
/* 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("DevInstallW('%S') failed\n", DeviceInstance);
|
DPRINT1("GetExitCodeProcess failed with error %u\n", GetLastError());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceInstalled = TRUE;
|
DeviceInstalled = Value;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (hNewDev != NULL)
|
if(hPipe != INVALID_HANDLE_VALUE)
|
||||||
FreeLibrary(hNewDev);
|
CloseHandle(hPipe);
|
||||||
|
|
||||||
|
if(Environment)
|
||||||
|
DestroyEnvironmentBlock(Environment);
|
||||||
|
|
||||||
|
if(ProcessInfo.hProcess)
|
||||||
|
CloseHandle(ProcessInfo.hProcess);
|
||||||
|
|
||||||
|
if(ProcessInfo.hThread)
|
||||||
|
CloseHandle(ProcessInfo.hThread);
|
||||||
|
|
||||||
return DeviceInstalled;
|
return DeviceInstalled;
|
||||||
}
|
}
|
||||||
|
@ -2255,6 +2355,7 @@ ServiceMain(DWORD argc, LPTSTR *argv)
|
||||||
int
|
int
|
||||||
wmain(int argc, WCHAR *argv[])
|
wmain(int argc, WCHAR *argv[])
|
||||||
{
|
{
|
||||||
|
BOOLEAN OldValue;
|
||||||
DWORD dwError;
|
DWORD dwError;
|
||||||
|
|
||||||
UNREFERENCED_PARAMETER(argc);
|
UNREFERENCED_PARAMETER(argc);
|
||||||
|
@ -2262,6 +2363,9 @@ wmain(int argc, WCHAR *argv[])
|
||||||
|
|
||||||
DPRINT("Umpnpmgr: main() started\n");
|
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);
|
hInstallEvent = CreateEvent(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL);
|
||||||
if (hInstallEvent == NULL)
|
if (hInstallEvent == NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
<library>rpcrt4</library>
|
<library>rpcrt4</library>
|
||||||
<library>pseh</library>
|
<library>pseh</library>
|
||||||
<library>wdmguid</library>
|
<library>wdmguid</library>
|
||||||
|
<library>userenv</library>
|
||||||
<file>umpnpmgr.c</file>
|
<file>umpnpmgr.c</file>
|
||||||
<file>umpnpmgr.rc</file>
|
<file>umpnpmgr.rc</file>
|
||||||
</module>
|
</module>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
|
* Copyright 2005-2006 Hervé Poussineau (hpoussin@reactos.org)
|
||||||
* 2005 Christoph von Wittich (Christoph@ActiveVB.de)
|
* 2005 Christoph von Wittich (Christoph@ActiveVB.de)
|
||||||
|
* 2009 Colin Finck (colin@reactos.org)
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -803,7 +804,7 @@ cleanup:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @unimplemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
ClientSideInstallW(
|
ClientSideInstallW(
|
||||||
|
@ -811,11 +812,75 @@ ClientSideInstallW(
|
||||||
IN DWORD dwUnknownFlags,
|
IN DWORD dwUnknownFlags,
|
||||||
IN LPWSTR lpNamedPipeName)
|
IN LPWSTR lpNamedPipeName)
|
||||||
{
|
{
|
||||||
/* NOTE: pNamedPipeName is in the format:
|
BOOL ReturnValue = FALSE;
|
||||||
* "\\.\pipe\PNP_Device_Install_Pipe_0.{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
|
BOOL ShowWizard;
|
||||||
*/
|
DWORD BytesRead;
|
||||||
FIXME("Stub\n");
|
DWORD Value;
|
||||||
return FALSE;
|
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
|
BOOL WINAPI
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue