1083 lines
30 KiB
C
1083 lines
30 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1995-2001 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
util.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains general utility routines used by cfgmgr32 code.
|
|||
|
|
|||
|
INVALID_DEVINST
|
|||
|
CopyFixedUpDeviceId
|
|||
|
PnPUnicodeToMultiByte
|
|||
|
PnPMultiByteToUnicode
|
|||
|
PnPRetrieveMachineName
|
|||
|
PnPGetVersion
|
|||
|
PnPGetGlobalHandles
|
|||
|
EnablePnPPrivileges
|
|||
|
IsRemoteServiceRunning
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Paula Tomlinson (paulat) 6-22-1995
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User mode only.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
22-Jun-1995 paulat
|
|||
|
|
|||
|
Creation and initial implementation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// includes
|
|||
|
//
|
|||
|
#include "precomp.h"
|
|||
|
#include "cfgi.h"
|
|||
|
#include "setupapi.h"
|
|||
|
#include "spapip.h"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Private prototypes
|
|||
|
//
|
|||
|
BOOL
|
|||
|
EnablePnPPrivileges(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// global data
|
|||
|
//
|
|||
|
extern PVOID hLocalStringTable; // MODIFIED by PnPGetGlobalHandles
|
|||
|
extern PVOID hLocalBindingHandle; // MODIFIED by PnPGetGlobalHandles
|
|||
|
extern WORD LocalServerVersion; // MODIFIED by PnPGetVersion
|
|||
|
extern WCHAR LocalMachineNameNetBIOS[]; // NOT MODIFIED BY THIS FILE
|
|||
|
extern CRITICAL_SECTION BindingCriticalSection; // NOT MODIFIED IN THIS FILE
|
|||
|
extern CRITICAL_SECTION StringTableCriticalSection; // NOT MODIFIED IN THIS FILE
|
|||
|
|
|||
|
LUID gLuidLoadDriverPrivilege;
|
|||
|
LUID gLuidUndockPrivilege;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
INVALID_DEVINST(
|
|||
|
PWSTR pDeviceID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine attempts a simple check whether the pDeviceID string
|
|||
|
returned from StringTableStringFromID is valid or not. It does
|
|||
|
this simply by dereferencing the pointer and comparing the first
|
|||
|
character in the string against the range of characters for a valid
|
|||
|
device id. If the string is valid but it's not an existing device id
|
|||
|
then this error will be caught later.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pDeviceID Supplies a pointer to the string to be validated.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
If it's invalid it returns TRUE, otherwise it returns FALSE.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
BOOL Status = FALSE;
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
if ((!ARGUMENT_PRESENT(pDeviceID)) ||
|
|||
|
(*pDeviceID <= TEXT(' ')) ||
|
|||
|
(*pDeviceID > (TCHAR)0x7F) ||
|
|||
|
(*pDeviceID == TEXT(','))) {
|
|||
|
Status = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
Status = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
} // INVALID_DEVINST
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
CopyFixedUpDeviceId(
|
|||
|
OUT LPTSTR DestinationString,
|
|||
|
IN LPCTSTR SourceString,
|
|||
|
IN DWORD SourceStringLen
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine copies a device id, fixing it up as it does the copy.
|
|||
|
'Fixing up' means that the string is made upper-case, and that the
|
|||
|
following character ranges are turned into underscores (_):
|
|||
|
|
|||
|
c <= 0x20 (' ')
|
|||
|
c > 0x7F
|
|||
|
c == 0x2C (',')
|
|||
|
|
|||
|
(NOTE: This algorithm is also implemented in the Config Manager APIs,
|
|||
|
and must be kept in sync with that routine. To maintain device identifier
|
|||
|
compatibility, these routines must work the same as Win95.)
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DestinationString - Supplies a pointer to the destination string buffer
|
|||
|
where the fixed-up device id is to be copied. This buffer must
|
|||
|
be large enough to hold a copy of the source string (including
|
|||
|
terminating NULL).
|
|||
|
|
|||
|
SourceString - Supplies a pointer to the (null-terminated) source
|
|||
|
string to be fixed up.
|
|||
|
|
|||
|
SourceStringLen - Supplies the length, in characters, of the source
|
|||
|
string (not including terminating NULL).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PTCHAR p;
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
CopyMemory(DestinationString,
|
|||
|
SourceString,
|
|||
|
((SourceStringLen + 1) * sizeof(TCHAR)));
|
|||
|
|
|||
|
CharUpperBuff(DestinationString, SourceStringLen);
|
|||
|
|
|||
|
for(p = DestinationString; *p; p++) {
|
|||
|
|
|||
|
if((*p <= TEXT(' ')) ||
|
|||
|
(*p > (TCHAR)0x7F) ||
|
|||
|
(*p == TEXT(','))) {
|
|||
|
*p = TEXT('_');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
NOTHING;
|
|||
|
}
|
|||
|
|
|||
|
} // CopyFixedUpDeviceId
|
|||
|
|
|||
|
|
|||
|
|
|||
|
CONFIGRET
|
|||
|
PnPUnicodeToMultiByte(
|
|||
|
IN PWSTR UnicodeString,
|
|||
|
IN ULONG UnicodeStringLen,
|
|||
|
OUT PSTR AnsiString OPTIONAL,
|
|||
|
IN OUT PULONG AnsiStringLen
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Convert a string from unicode to ansi.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
UnicodeString - Supplies string to be converted.
|
|||
|
|
|||
|
UnicodeStringLen - Specifies the size, in bytes, of the string to be
|
|||
|
converted.
|
|||
|
|
|||
|
AnsiString - Optionally, supplies a buffer to receive the ANSI
|
|||
|
string.
|
|||
|
|
|||
|
AnsiStringLen - Supplies the address of a variable that contains the
|
|||
|
size, in bytes, of the buffer pointed to by AnsiString.
|
|||
|
This API replaces the initial size with the number of
|
|||
|
bytes of data copied to the buffer. If the variable is
|
|||
|
initially zero, the API replaces it with the buffer size
|
|||
|
needed to receive all the registry data. In this case,
|
|||
|
the AnsiString parameter is ignored.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns a CONFIGRET code.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
CONFIGRET Status = CR_SUCCESS;
|
|||
|
NTSTATUS ntStatus;
|
|||
|
ULONG ulAnsiStringLen = 0;
|
|||
|
|
|||
|
try {
|
|||
|
//
|
|||
|
// Validate parameters
|
|||
|
//
|
|||
|
if ((!ARGUMENT_PRESENT(AnsiStringLen)) ||
|
|||
|
(!ARGUMENT_PRESENT(AnsiString)) && (*AnsiStringLen != 0)) {
|
|||
|
Status = CR_INVALID_POINTER;
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Determine the size required for the ANSI string representation.
|
|||
|
//
|
|||
|
ntStatus = RtlUnicodeToMultiByteSize(&ulAnsiStringLen,
|
|||
|
UnicodeString,
|
|||
|
UnicodeStringLen);
|
|||
|
if (!NT_SUCCESS(ntStatus)) {
|
|||
|
Status = CR_FAILURE;
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
if ((!ARGUMENT_PRESENT(AnsiString)) ||
|
|||
|
(*AnsiStringLen < ulAnsiStringLen)) {
|
|||
|
*AnsiStringLen = ulAnsiStringLen;
|
|||
|
Status = CR_BUFFER_SMALL;
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Perform the conversion.
|
|||
|
//
|
|||
|
ntStatus = RtlUnicodeToMultiByteN(AnsiString,
|
|||
|
*AnsiStringLen,
|
|||
|
&ulAnsiStringLen,
|
|||
|
UnicodeString,
|
|||
|
UnicodeStringLen);
|
|||
|
|
|||
|
ASSERT(NT_SUCCESS(ntStatus));
|
|||
|
ASSERT(ulAnsiStringLen <= *AnsiStringLen);
|
|||
|
|
|||
|
if (!NT_SUCCESS(ntStatus)) {
|
|||
|
Status = CR_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
*AnsiStringLen = ulAnsiStringLen;
|
|||
|
|
|||
|
Clean0:
|
|||
|
NOTHING;
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
Status = CR_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
} // PnPUnicodeToMultiByte
|
|||
|
|
|||
|
|
|||
|
|
|||
|
CONFIGRET
|
|||
|
PnPMultiByteToUnicode(
|
|||
|
IN PSTR AnsiString,
|
|||
|
IN ULONG AnsiStringLen,
|
|||
|
OUT PWSTR UnicodeString OPTIONAL,
|
|||
|
IN OUT PULONG UnicodeStringLen
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Convert a string from ansi to unicode.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
AnsiString - Supplies string to be converted.
|
|||
|
|
|||
|
AnsiStringLen - Specifies the size, in bytes, of the string to be
|
|||
|
converted.
|
|||
|
|
|||
|
UnicodeString - Optionally, supplies a buffer to receive the Unicode
|
|||
|
string.
|
|||
|
|
|||
|
UnicodeStringLen - Supplies the address of a variable that contains the
|
|||
|
size, in bytes, of the buffer pointed to by UnicodeString.
|
|||
|
This API replaces the initial size with the number of
|
|||
|
bytes of data copied to the buffer. If the variable is
|
|||
|
initially zero, the API replaces it with the buffer size
|
|||
|
needed to receive all the registry data. In this case,
|
|||
|
the UnicodeString parameter is ignored.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Returns a CONFIGRET code.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
CONFIGRET Status = CR_SUCCESS;
|
|||
|
NTSTATUS ntStatus;
|
|||
|
ULONG ulUnicodeStringLen = 0;
|
|||
|
|
|||
|
try {
|
|||
|
//
|
|||
|
// Validate parameters
|
|||
|
//
|
|||
|
if ((!ARGUMENT_PRESENT(UnicodeStringLen)) ||
|
|||
|
(!ARGUMENT_PRESENT(UnicodeString)) && (*UnicodeStringLen != 0)) {
|
|||
|
Status = CR_INVALID_POINTER;
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Determine the size required for the ANSI string representation.
|
|||
|
//
|
|||
|
ntStatus = RtlMultiByteToUnicodeSize(&ulUnicodeStringLen,
|
|||
|
AnsiString,
|
|||
|
AnsiStringLen);
|
|||
|
if (!NT_SUCCESS(ntStatus)) {
|
|||
|
Status = CR_FAILURE;
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
if ((!ARGUMENT_PRESENT(UnicodeString)) ||
|
|||
|
(*UnicodeStringLen < ulUnicodeStringLen)) {
|
|||
|
*UnicodeStringLen = ulUnicodeStringLen;
|
|||
|
Status = CR_BUFFER_SMALL;
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Perform the conversion.
|
|||
|
//
|
|||
|
ntStatus = RtlMultiByteToUnicodeN(UnicodeString,
|
|||
|
*UnicodeStringLen,
|
|||
|
&ulUnicodeStringLen,
|
|||
|
AnsiString,
|
|||
|
AnsiStringLen);
|
|||
|
|
|||
|
ASSERT(NT_SUCCESS(ntStatus));
|
|||
|
ASSERT(ulUnicodeStringLen <= *UnicodeStringLen);
|
|||
|
|
|||
|
if (!NT_SUCCESS(ntStatus)) {
|
|||
|
Status = CR_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
*UnicodeStringLen = ulUnicodeStringLen;
|
|||
|
|
|||
|
Clean0:
|
|||
|
NOTHING;
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
Status = CR_FAILURE;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
} // PnPMultiByteToUnicode
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
PnPRetrieveMachineName(
|
|||
|
IN HMACHINE hMachine,
|
|||
|
OUT LPWSTR pszMachineName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Optimized version of PnPConnect, only returns the machine name
|
|||
|
associated with this connection.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hMachine Information about this connection
|
|||
|
|
|||
|
pszMachineName Returns machine name specified when CM_Connect_Machine
|
|||
|
was called.
|
|||
|
|
|||
|
** This buffer must be at least (MAX_PATH + 3)
|
|||
|
characters long. **
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return TRUE if the function succeeds and FALSE if it fails.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL Status = TRUE;
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
if (hMachine == NULL) {
|
|||
|
//
|
|||
|
// local machine scenario
|
|||
|
//
|
|||
|
// use the global local machine name string that was filled
|
|||
|
// when the DLL initialized.
|
|||
|
//
|
|||
|
lstrcpy(pszMachineName, LocalMachineNameNetBIOS);
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// remote machine scenario
|
|||
|
//
|
|||
|
// validate the machine handle.
|
|||
|
//
|
|||
|
if (((PPNP_MACHINE)hMachine)->ulSignature != (ULONG)MACHINE_HANDLE_SIGNATURE) {
|
|||
|
Status = FALSE;
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// use information within the hMachine handle to fill in the
|
|||
|
// machine name. The hMachine info was set on a previous call
|
|||
|
// to CM_Connect_Machine.
|
|||
|
//
|
|||
|
lstrcpy(pszMachineName, ((PPNP_MACHINE)hMachine)->szMachineName);
|
|||
|
}
|
|||
|
|
|||
|
Clean0:
|
|||
|
NOTHING;
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
Status = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
} // PnPRetrieveMachineName
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
PnPGetVersion(
|
|||
|
IN HMACHINE hMachine,
|
|||
|
IN WORD * pwVersion
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine returns the internal server version for the specified machine
|
|||
|
connection, as returned by the RPC server interface routine
|
|||
|
PNP_GetVersionInternal. If the PNP_GetVersionInternal interface does not
|
|||
|
exist on the specified machine, this routine returns the version as reported
|
|||
|
by PNP_GetVersion.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hMachine - Information about this connection
|
|||
|
|
|||
|
pwVersion - Receives the internal server version.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Return TRUE if the function succeeds and FALSE if it fails.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
The version reported by PNP_GetVersion is defined to be constant, at 0x0400.
|
|||
|
The version returned by PNP_GetVersionInternal may change with each release
|
|||
|
of the product, starting with 0x0501 for Windows NT 5.1.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL Status = TRUE;
|
|||
|
handle_t hBinding = NULL;
|
|||
|
CONFIGRET crStatus;
|
|||
|
WORD wVersionInternal;
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
if (pwVersion == NULL) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
if (hMachine == NULL) {
|
|||
|
//
|
|||
|
// local machine scenario
|
|||
|
//
|
|||
|
if (LocalServerVersion != 0) {
|
|||
|
//
|
|||
|
// local server version has already been retrieved.
|
|||
|
//
|
|||
|
*pwVersion = LocalServerVersion;
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// retrieve binding handle for the local machine.
|
|||
|
//
|
|||
|
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(hBinding);
|
|||
|
|
|||
|
//
|
|||
|
// initialize the version supplied to the internal client
|
|||
|
// version, in case the server wants to adjust the response
|
|||
|
// based on the client version.
|
|||
|
//
|
|||
|
wVersionInternal = (WORD)CFGMGR32_VERSION_INTERNAL;
|
|||
|
|
|||
|
RpcTryExcept {
|
|||
|
//
|
|||
|
// call rpc service entry point
|
|||
|
//
|
|||
|
crStatus = PNP_GetVersionInternal(
|
|||
|
hBinding, // rpc binding
|
|||
|
&wVersionInternal); // internal server version
|
|||
|
}
|
|||
|
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_WARNINGS,
|
|||
|
"PNP_GetVersionInternal caused an exception (%d)\n",
|
|||
|
RpcExceptionCode()));
|
|||
|
|
|||
|
crStatus = MapRpcExceptionToCR(RpcExceptionCode());
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
if (crStatus == CR_SUCCESS) {
|
|||
|
//
|
|||
|
// PNP_GetVersionInternal exists on NT 5.1 and later.
|
|||
|
//
|
|||
|
ASSERT(wVersionInternal >= (WORD)0x0501);
|
|||
|
|
|||
|
//
|
|||
|
// initialize the global local server version.
|
|||
|
//
|
|||
|
LocalServerVersion = *pwVersion = wVersionInternal;
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// we successfully retrieved a local binding handle, but
|
|||
|
// PNP_GetVersionInternal failed for some reason other than
|
|||
|
// the server not being available.
|
|||
|
//
|
|||
|
ASSERT(0);
|
|||
|
|
|||
|
//
|
|||
|
// although we know this version of the client should match
|
|||
|
// a version of the server where PNP_GetVersionInternal is
|
|||
|
// available, it's technically possible (though unsupported)
|
|||
|
// that this client is communicating with a downlevel server
|
|||
|
// on the local machine, so we'll have to resort to calling
|
|||
|
// PNP_GetVersion.
|
|||
|
//
|
|||
|
RpcTryExcept {
|
|||
|
//
|
|||
|
// call rpc service entry point
|
|||
|
//
|
|||
|
crStatus = PNP_GetVersion(
|
|||
|
hBinding, // rpc binding
|
|||
|
&wVersionInternal); // server version
|
|||
|
}
|
|||
|
RpcExcept (I_RpcExceptionFilter(RpcExceptionCode())) {
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_WARNINGS,
|
|||
|
"PNP_GetVersion caused an exception (%d)\n",
|
|||
|
RpcExceptionCode()));
|
|||
|
|
|||
|
crStatus = MapRpcExceptionToCR(RpcExceptionCode());
|
|||
|
}
|
|||
|
RpcEndExcept
|
|||
|
|
|||
|
if (crStatus == CR_SUCCESS) {
|
|||
|
//
|
|||
|
// PNP_GetVersion should always return 0x0400 on all servers.
|
|||
|
//
|
|||
|
ASSERT(wVersionInternal == (WORD)0x0400);
|
|||
|
|
|||
|
//
|
|||
|
// initialize the global local server version.
|
|||
|
//
|
|||
|
LocalServerVersion = *pwVersion = wVersionInternal;
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// nothing more we can do here but fail.
|
|||
|
//
|
|||
|
ASSERT(0);
|
|||
|
Status = FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// remote machine scenario
|
|||
|
//
|
|||
|
// validate the machine handle.
|
|||
|
//
|
|||
|
if (((PPNP_MACHINE)hMachine)->ulSignature != (ULONG)MACHINE_HANDLE_SIGNATURE) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// use information within the hMachine handle to fill in the
|
|||
|
// version. The hMachine info was set on a previous call to
|
|||
|
// CM_Connect_Machine.
|
|||
|
//
|
|||
|
*pwVersion = ((PPNP_MACHINE)hMachine)->wVersion;
|
|||
|
}
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
Status = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
} // PnPGetVersion
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
PnPGetGlobalHandles(
|
|||
|
IN HMACHINE hMachine,
|
|||
|
OUT PVOID *phStringTable, OPTIONAL
|
|||
|
OUT PVOID *phBindingHandle OPTIONAL
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine retrieves a handle to the string table and/or the rpc binding
|
|||
|
handle for the specified server machine connection.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
hMachine - Specifies a server machine connection handle, as returned
|
|||
|
by CM_Connect_Machine.
|
|||
|
|
|||
|
phStringTable - Optionally, specifies an address to receive a handle to
|
|||
|
the string table for the specified server machine
|
|||
|
connection.
|
|||
|
|
|||
|
phBindingHandle - Optionally, specifies an address to receive the RPC
|
|||
|
binding handle for the specifies server machine
|
|||
|
connection.
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
Returns TRUE if successful, FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL bStatus = TRUE;
|
|||
|
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
EnablePnPPrivileges();
|
|||
|
|
|||
|
if (phStringTable != NULL) {
|
|||
|
|
|||
|
if (hMachine == NULL) {
|
|||
|
|
|||
|
//------------------------------------------------------
|
|||
|
// Retrieve String Table Handle for the local machine
|
|||
|
//-------------------------------------------------------
|
|||
|
|
|||
|
EnterCriticalSection(&StringTableCriticalSection);
|
|||
|
|
|||
|
if (hLocalStringTable != NULL) {
|
|||
|
//
|
|||
|
// local string table has already been created
|
|||
|
//
|
|||
|
*phStringTable = hLocalStringTable;
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// first time, initialize the local string table
|
|||
|
//
|
|||
|
|
|||
|
hLocalStringTable = pSetupStringTableInitialize();
|
|||
|
|
|||
|
if (hLocalStringTable == NULL) {
|
|||
|
bStatus = FALSE;
|
|||
|
*phStringTable = NULL;
|
|||
|
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_ERRORS,
|
|||
|
"CFGMGR32: failed to initialize local string table\n"));
|
|||
|
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// No matter how the string table is implemented, I never
|
|||
|
// want to have a string id of zero - this would generate
|
|||
|
// an invalid devinst. So, add a small priming string just
|
|||
|
// to be safe.
|
|||
|
//
|
|||
|
pSetupStringTableAddString(hLocalStringTable,
|
|||
|
PRIMING_STRING,
|
|||
|
STRTAB_CASE_SENSITIVE);
|
|||
|
|
|||
|
*phStringTable = hLocalStringTable;
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection(&StringTableCriticalSection);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//-------------------------------------------------------
|
|||
|
// Retrieve String Table Handle for the remote machine
|
|||
|
//-------------------------------------------------------
|
|||
|
|
|||
|
//
|
|||
|
// validate the machine handle.
|
|||
|
//
|
|||
|
if (((PPNP_MACHINE)hMachine)->ulSignature != (ULONG)MACHINE_HANDLE_SIGNATURE) {
|
|||
|
bStatus = FALSE;
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// use information within the hMachine handle to set the string
|
|||
|
// table handle. The hMachine info was set on a previous call
|
|||
|
// to CM_Connect_Machine.
|
|||
|
//
|
|||
|
*phStringTable = ((PPNP_MACHINE)hMachine)->hStringTable;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
if (phBindingHandle != NULL) {
|
|||
|
|
|||
|
if (hMachine == NULL) {
|
|||
|
|
|||
|
//-------------------------------------------------------
|
|||
|
// Retrieve Binding Handle for the local machine
|
|||
|
//-------------------------------------------------------
|
|||
|
|
|||
|
EnterCriticalSection(&BindingCriticalSection);
|
|||
|
|
|||
|
if (hLocalBindingHandle != NULL) {
|
|||
|
//
|
|||
|
// local binding handle has already been set
|
|||
|
//
|
|||
|
*phBindingHandle = hLocalBindingHandle;
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// first time, explicitly force binding to local machine
|
|||
|
//
|
|||
|
pnp_handle = PNP_HANDLE_bind(NULL); // set rpc global
|
|||
|
|
|||
|
if (pnp_handle == NULL) {
|
|||
|
bStatus = FALSE;
|
|||
|
*phBindingHandle = NULL;
|
|||
|
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_ERRORS,
|
|||
|
"CFGMGR32: failed to initialize local binding handle\n"));
|
|||
|
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
*phBindingHandle = hLocalBindingHandle = (PVOID)pnp_handle;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
LeaveCriticalSection(&BindingCriticalSection);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//-------------------------------------------------------
|
|||
|
// Retrieve Binding Handle for the remote machine
|
|||
|
//-------------------------------------------------------
|
|||
|
|
|||
|
//
|
|||
|
// validate the machine handle.
|
|||
|
//
|
|||
|
if (((PPNP_MACHINE)hMachine)->ulSignature != (ULONG)MACHINE_HANDLE_SIGNATURE) {
|
|||
|
bStatus = FALSE;
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// use information within the hMachine handle to set the
|
|||
|
// binding handle. The hMachine info was set on a previous call
|
|||
|
// to CM_Connect_Machine.
|
|||
|
//
|
|||
|
*phBindingHandle = ((PPNP_MACHINE)hMachine)->hBindingHandle;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Clean0:
|
|||
|
NOTHING;
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
bStatus = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return bStatus;
|
|||
|
|
|||
|
} // PnpGetGlobalHandles
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
EnablePnPPrivileges(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine attempts to enable the SE_LOAD_DRIVER_NAME and SE_UNDOCK_NAME
|
|||
|
privileges in either the thread token or the calling thread (if
|
|||
|
impersonating), or thread's process token if no thread token exists.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
Returns TRUE if successful, FALSE otherwise.
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
Note that this routine can return successfully even if either the
|
|||
|
SE_LOAD_DRIVER_NAME or SE_UNDOCK_NAME (or both) privileges were not
|
|||
|
successfully enabled in the appropriate token.
|
|||
|
|
|||
|
If sucessful, to determine whether the function adjusted all of the
|
|||
|
specified privileges, call GetLastError to determine the last error set by
|
|||
|
AdjustTokenPrivileges, which returns one of the following values when the
|
|||
|
function succeeds:
|
|||
|
|
|||
|
ERROR_SUCCESS - The function adjusted all specified privileges.
|
|||
|
|
|||
|
ERROR_NOT_ALL_ASSIGNED - The token does not have one or more of the
|
|||
|
privileges enabled.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HANDLE hToken;
|
|||
|
PTOKEN_PRIVILEGES lpTokenPrivs;
|
|||
|
BOOL bSuccess;
|
|||
|
|
|||
|
if (gLuidLoadDriverPrivilege.LowPart == 0 &&
|
|||
|
gLuidLoadDriverPrivilege.HighPart == 0) {
|
|||
|
|
|||
|
bSuccess = LookupPrivilegeValue( NULL,
|
|||
|
SE_LOAD_DRIVER_NAME,
|
|||
|
&gLuidLoadDriverPrivilege);
|
|||
|
|
|||
|
if (!bSuccess) {
|
|||
|
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_ERRORS,
|
|||
|
"CFGMGR32: LookupPrivilegeValue failed, error = %d\n",
|
|||
|
GetLastError()));
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (gLuidUndockPrivilege.LowPart == 0 && gLuidUndockPrivilege.HighPart == 0) {
|
|||
|
bSuccess = LookupPrivilegeValue( NULL,
|
|||
|
SE_UNDOCK_NAME,
|
|||
|
&gLuidUndockPrivilege);
|
|||
|
if (!bSuccess) {
|
|||
|
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_ERRORS,
|
|||
|
"CFGMGR32: LookupPrivilegeValue failed, error = %d\n",
|
|||
|
GetLastError()));
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ADJUST_PRIVILEGES, TRUE, &hToken)) {
|
|||
|
|
|||
|
if (GetLastError() == ERROR_NO_TOKEN) {
|
|||
|
|
|||
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_ERRORS,
|
|||
|
"CFGMGR32: OpenProcessToken returned %d\n",
|
|||
|
GetLastError()));
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
} else {
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_ERRORS,
|
|||
|
"CFGMGR32: OpenThreadToken returned %d\n",
|
|||
|
GetLastError()));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
lpTokenPrivs = pSetupMalloc(sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES));
|
|||
|
|
|||
|
if (lpTokenPrivs == NULL) {
|
|||
|
|
|||
|
CloseHandle(hToken);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
lpTokenPrivs->PrivilegeCount = 2;
|
|||
|
|
|||
|
lpTokenPrivs->Privileges[0].Luid = gLuidLoadDriverPrivilege;
|
|||
|
lpTokenPrivs->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|||
|
|
|||
|
lpTokenPrivs->Privileges[1].Luid = gLuidUndockPrivilege;
|
|||
|
lpTokenPrivs->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
|
|||
|
|
|||
|
bSuccess = AdjustTokenPrivileges( hToken,
|
|||
|
FALSE, // DisableAllPrivileges
|
|||
|
lpTokenPrivs,
|
|||
|
0,
|
|||
|
(PTOKEN_PRIVILEGES) NULL,
|
|||
|
(PDWORD) NULL);
|
|||
|
if (!bSuccess) {
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_ERRORS,
|
|||
|
"CFGMGR32: AdjustTokenPrivileges failed: %u\n",
|
|||
|
GetLastError()));
|
|||
|
}
|
|||
|
|
|||
|
pSetupFree(lpTokenPrivs);
|
|||
|
|
|||
|
CloseHandle(hToken);
|
|||
|
|
|||
|
return bSuccess;
|
|||
|
|
|||
|
} // EnablePnPPrivileges
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
IsRemoteServiceRunning(
|
|||
|
IN LPCWSTR UNCServerName,
|
|||
|
IN LPCWSTR ServiceName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine connects to the active service database of the Service Control
|
|||
|
Manager (SCM) on the machine specified and returns whether or not the
|
|||
|
specified service is running.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
UNCServerName - Specifies the name of the remote machine.
|
|||
|
|
|||
|
ServiceName - Specifies the name of the service whose status is to be
|
|||
|
queried.
|
|||
|
|
|||
|
Return value:
|
|||
|
|
|||
|
Returns TRUE if the specified service is installed on the remote machine and
|
|||
|
is currently in the SERVICE_RUNNING state, FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
BOOL Status = FALSE;
|
|||
|
SC_HANDLE hSCManager = NULL, hService = NULL;
|
|||
|
SERVICE_STATUS ServiceStatus;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Open the Service Control Manager
|
|||
|
//
|
|||
|
hSCManager = OpenSCManager(
|
|||
|
UNCServerName, // computer name
|
|||
|
SERVICES_ACTIVE_DATABASE, // SCM database name
|
|||
|
SC_MANAGER_CONNECT // access type
|
|||
|
);
|
|||
|
|
|||
|
if (hSCManager == NULL) {
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_WARNINGS,
|
|||
|
"CFGMGR32: OpenSCManager failed, error = %d\n",
|
|||
|
GetLastError()));
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Open the service
|
|||
|
//
|
|||
|
hService = OpenService(
|
|||
|
hSCManager, // handle to SCM database
|
|||
|
ServiceName, // service name
|
|||
|
SERVICE_QUERY_STATUS // access type
|
|||
|
);
|
|||
|
|
|||
|
if (hService == NULL) {
|
|||
|
Status = FALSE;
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_WARNINGS,
|
|||
|
"CFGMGR32: OpenService failed, error = %d\n",
|
|||
|
GetLastError()));
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Query the service status
|
|||
|
//
|
|||
|
if (!QueryServiceStatus(hService,
|
|||
|
&ServiceStatus)) {
|
|||
|
Status = FALSE;
|
|||
|
KdPrintEx((DPFLTR_PNPMGR_ID,
|
|||
|
DBGF_WARNINGS,
|
|||
|
"CFGMGR32: QueryServiceStatus failed, error = %d\n",
|
|||
|
GetLastError()));
|
|||
|
goto Clean0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check if the service is running.
|
|||
|
//
|
|||
|
if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) {
|
|||
|
Status = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
Clean0:
|
|||
|
|
|||
|
if (hService) {
|
|||
|
CloseServiceHandle(hService);
|
|||
|
}
|
|||
|
|
|||
|
if (hSCManager) {
|
|||
|
CloseServiceHandle(hSCManager);
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
|
|||
|
} // IsRemoteServiceRunning
|
|||
|
|
|||
|
|