[UMPNPMGR] Split the monolithic monster: service, rpc and installer.

This commit is contained in:
Eric Kohl 2019-05-30 11:48:29 +02:00
parent e71a94da20
commit fe3ae24369
5 changed files with 4220 additions and 4087 deletions

View file

@ -4,6 +4,8 @@ add_rpc_files(server ${REACTOS_SOURCE_DIR}/sdk/include/reactos/idl/pnp.idl)
spec2def(umpnpmgr.dll umpnpmgr.spec ADD_IMPORTLIB)
add_library(umpnpmgr MODULE
install.c
rpcserver.c
umpnpmgr.c
umpnpmgr.rc
${CMAKE_CURRENT_BINARY_DIR}/pnp_s.c

View file

@ -0,0 +1,377 @@
/*
* ReactOS kernel
* Copyright (C) 2005 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: base/services/umpnpmgr/install.c
* PURPOSE: Device installer
* PROGRAMMER: Eric Kohl (eric.kohl@reactos.org)
* Hervé Poussineau (hpoussin@reactos.org)
* Colin Finck (colin@reactos.org)
*/
/* INCLUDES *****************************************************************/
#include "precomp.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ******************************************************************/
HANDLE hUserToken = NULL;
HANDLE hInstallEvent = NULL;
HANDLE hNoPendingInstalls = NULL;
SLIST_HEADER DeviceInstallListHead;
HANDLE hDeviceInstallListNotEmpty;
/* FUNCTIONS *****************************************************************/
static BOOL
InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
{
BOOL DeviceInstalled = FALSE;
DWORD BytesWritten;
DWORD Value;
HANDLE hInstallEvent;
HANDLE hPipe = INVALID_HANDLE_VALUE;
LPVOID Environment = NULL;
PROCESS_INFORMATION ProcessInfo;
STARTUPINFOW StartupInfo;
UUID RandomUuid;
HKEY DeviceKey;
/* 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));
if (RegOpenKeyExW(hEnumKey,
DeviceInstance,
0,
KEY_QUERY_VALUE,
&DeviceKey) == ERROR_SUCCESS)
{
if (RegQueryValueExW(DeviceKey,
L"Class",
NULL,
NULL,
NULL,
NULL) == ERROR_SUCCESS)
{
DPRINT("No need to install: %S\n", DeviceInstance);
RegCloseKey(DeviceKey);
return TRUE;
}
BytesWritten = sizeof(DWORD);
if (RegQueryValueExW(DeviceKey,
L"ConfigFlags",
NULL,
NULL,
(PBYTE)&Value,
&BytesWritten) == ERROR_SUCCESS)
{
if (Value & CONFIGFLAG_FAILEDINSTALL)
{
DPRINT("No need to install: %S\n", DeviceInstance);
RegCloseKey(DeviceKey);
return TRUE;
}
}
RegCloseKey(DeviceKey);
}
DPRINT1("Installing: %S\n", DeviceInstance);
/* Create a random UUID for the named pipe & event*/
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 event */
wcscpy(InstallEventName, L"Global\\PNP_Device_Install_Event_0.");
wcscat(InstallEventName, UuidString);
hInstallEvent = CreateEventW(NULL, TRUE, FALSE, InstallEventName);
if (!hInstallEvent)
{
DPRINT1("CreateEventW('%ls') failed with error %lu\n", InstallEventName, GetLastError());
goto cleanup;
}
/* 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;
}
/* 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))
{
if (GetLastError() != ERROR_PIPE_CONNECTED)
{
DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
goto cleanup;
}
}
/* Pass the data. The following output is partly compatible to Windows XP SP2 (researched using a modified newdev.dll to log this stuff) */
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);
/* If the event got signalled, this is success */
DeviceInstalled = WaitForSingleObject(hInstallEvent, 0) == WAIT_OBJECT_0;
cleanup:
if (hInstallEvent)
CloseHandle(hInstallEvent);
if (hPipe != INVALID_HANDLE_VALUE)
CloseHandle(hPipe);
if (Environment)
DestroyEnvironmentBlock(Environment);
if (ProcessInfo.hProcess)
CloseHandle(ProcessInfo.hProcess);
if (ProcessInfo.hThread)
CloseHandle(ProcessInfo.hThread);
if (!DeviceInstalled)
{
DPRINT1("InstallDevice failed for DeviceInstance '%ws'\n", DeviceInstance);
}
return DeviceInstalled;
}
static LONG
ReadRegSzKey(
IN HKEY hKey,
IN LPCWSTR pszKey,
OUT LPWSTR* pValue)
{
LONG rc;
DWORD dwType;
DWORD cbData = 0;
LPWSTR Value;
if (!pValue)
return ERROR_INVALID_PARAMETER;
*pValue = NULL;
rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
if (rc != ERROR_SUCCESS)
return rc;
if (dwType != REG_SZ)
return ERROR_FILE_NOT_FOUND;
Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
if (!Value)
return ERROR_NOT_ENOUGH_MEMORY;
rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
if (rc != ERROR_SUCCESS)
{
HeapFree(GetProcessHeap(), 0, Value);
return rc;
}
/* NULL-terminate the string */
Value[cbData / sizeof(WCHAR)] = '\0';
*pValue = Value;
return ERROR_SUCCESS;
}
BOOL
SetupIsActive(VOID)
{
HKEY hKey = NULL;
DWORD regType, active, size;
LONG rc;
BOOL ret = FALSE;
rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\Setup", 0, KEY_QUERY_VALUE, &hKey);
if (rc != ERROR_SUCCESS)
goto cleanup;
size = sizeof(DWORD);
rc = RegQueryValueExW(hKey, L"SystemSetupInProgress", NULL, &regType, (LPBYTE)&active, &size);
if (rc != ERROR_SUCCESS)
goto cleanup;
if (regType != REG_DWORD || size != sizeof(DWORD))
goto cleanup;
ret = (active != 0);
cleanup:
if (hKey != NULL)
RegCloseKey(hKey);
DPRINT("System setup in progress? %S\n", ret ? L"YES" : L"NO");
return ret;
}
static BOOL
IsConsoleBoot(VOID)
{
HKEY ControlKey = NULL;
LPWSTR SystemStartOptions = NULL;
LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
BOOL ConsoleBoot = FALSE;
LONG rc;
rc = RegOpenKeyExW(
HKEY_LOCAL_MACHINE,
L"SYSTEM\\CurrentControlSet\\Control",
0,
KEY_QUERY_VALUE,
&ControlKey);
rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
if (rc != ERROR_SUCCESS)
goto cleanup;
/* Check for CONSOLE switch in SystemStartOptions */
CurrentOption = SystemStartOptions;
while (CurrentOption)
{
NextOption = wcschr(CurrentOption, L' ');
if (NextOption)
*NextOption = L'\0';
if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
{
DPRINT("Found %S. Switching to console boot\n", CurrentOption);
ConsoleBoot = TRUE;
goto cleanup;
}
CurrentOption = NextOption ? NextOption + 1 : NULL;
}
cleanup:
if (ControlKey != NULL)
RegCloseKey(ControlKey);
HeapFree(GetProcessHeap(), 0, SystemStartOptions);
return ConsoleBoot;
}
/* Loop to install all queued devices installations */
DWORD
WINAPI
DeviceInstallThread(LPVOID lpParameter)
{
PSLIST_ENTRY ListEntry;
DeviceInstallParams* Params;
BOOL showWizard;
UNREFERENCED_PARAMETER(lpParameter);
WaitForSingleObject(hInstallEvent, INFINITE);
showWizard = !SetupIsActive() && !IsConsoleBoot();
while (TRUE)
{
ListEntry = InterlockedPopEntrySList(&DeviceInstallListHead);
if (ListEntry == NULL)
{
SetEvent(hNoPendingInstalls);
WaitForSingleObject(hDeviceInstallListNotEmpty, INFINITE);
}
else
{
ResetEvent(hNoPendingInstalls);
Params = CONTAINING_RECORD(ListEntry, DeviceInstallParams, ListEntry);
InstallDevice(Params->DeviceIds, showWizard);
HeapFree(GetProcessHeap(), 0, Params);
}
}
return 0;
}

View file

@ -0,0 +1,75 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: base/services/umpnpmgr/install.c
* PURPOSE: Device installer
* PROGRAMMER: Eric Kohl (eric.kohl@reactos.org)
* Hervé Poussineau (hpoussin@reactos.org)
* Colin Finck (colin@reactos.org)
*/
#ifndef _UMPNPMGR_PCH_
#define _UMPNPMGR_PCH_
#define WIN32_NO_STATUS
#define _INC_WINDOWS
#define COM_NO_WINDOWS_H
#include <stdarg.h>
#include <windef.h>
#include <winbase.h>
#include <winreg.h>
#include <winsvc.h>
#include <winuser.h>
#include <dbt.h>
#include <stdio.h>
#include <cmfuncs.h>
#include <rtlfuncs.h>
#include <setypes.h>
#include <umpnpmgr/sysguid.h>
#include <cfgmgr32.h>
#include <regstr.h>
#include <userenv.h>
#include <shlwapi.h>
#include <pnp_s.h>
typedef struct
{
SLIST_ENTRY ListEntry;
WCHAR DeviceIds[1];
} DeviceInstallParams;
/* install.c */
extern HANDLE hUserToken;
extern HANDLE hInstallEvent;
extern HANDLE hNoPendingInstalls;
extern SLIST_HEADER DeviceInstallListHead;
extern HANDLE hDeviceInstallListNotEmpty;
BOOL
SetupIsActive(VOID);
DWORD
WINAPI
DeviceInstallThread(
LPVOID lpParameter);
/* rpcserver.c */
DWORD
WINAPI
RpcServerThread(
LPVOID lpParameter);
/* umpnpmgr.c */
extern HKEY hEnumKey;
extern HKEY hClassKey;
#endif /* _UMPNPMGR_PCH_ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff