mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1167 lines
28 KiB
1167 lines
28 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
misc.c
|
|
|
|
Abstract:
|
|
|
|
This module contains miscellaneous Configuration Manager API routines.
|
|
|
|
Author:
|
|
|
|
Paula Tomlinson (paulat) 6-20-1995
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
|
|
Revision History:
|
|
|
|
20-Jun-1995 paulat
|
|
|
|
Creation and initial implementation.
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// includes
|
|
//
|
|
#include "precomp.h"
|
|
#include "setupapi.h"
|
|
#include "spapip.h"
|
|
#include "pnpipc.h"
|
|
|
|
|
|
//
|
|
// Prototype for private utility routine in util.c
|
|
//
|
|
PVOID
|
|
GetLocalBindingHandle(
|
|
VOID
|
|
);
|
|
|
|
|
|
//
|
|
// global data
|
|
//
|
|
extern PVOID hLocalStringTable; // NOT MODIFIED BY THESE PROCEDURES
|
|
extern WCHAR LocalMachineName[]; // NOT MODIFIED BY THESE PROCEDURES
|
|
|
|
#define NUM_LOGON_RETRIES 30
|
|
|
|
WCHAR pszProcessCmdLine[] = TEXT("setup.exe -plugplay");
|
|
|
|
|
|
|
|
|
|
WORD
|
|
CM_Get_Version_Ex(
|
|
IN HMACHINE hMachine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the version number of the Configuration Manager APIs.
|
|
|
|
Arguments:
|
|
|
|
hBinding
|
|
|
|
Return value:
|
|
|
|
The function returns the major revision number in the high byte and the
|
|
minor revision number in the low byte. For example, version 4.0 of
|
|
Configuration Manager returns 0x0400.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
WORD wVersion = (WORD)CFGMGR32_VERSION;
|
|
handle_t hBinding = NULL;
|
|
|
|
//
|
|
// setup rpc binding handle
|
|
//
|
|
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return wVersion = 0;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
//
|
|
// call rpc service entry point
|
|
//
|
|
Status = PNP_GetVersion(
|
|
hBinding, // rpc machine name
|
|
&wVersion); // server size version
|
|
}
|
|
RpcExcept (1) {
|
|
PnPTrace(
|
|
TEXT("PNP_GetVersion caused an exception (%d)\n"),
|
|
RpcExceptionCode());
|
|
|
|
SetLastError(RpcExceptionCode());
|
|
wVersion = 0;
|
|
}
|
|
RpcEndExcept
|
|
|
|
return wVersion;
|
|
|
|
} // CM_Get_Version_Ex
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Connect_MachineW(
|
|
IN PCWSTR UNCServerName,
|
|
OUT PHMACHINE phMachine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine connects to the machine specified and returns a handle that
|
|
is then passed to future calls to the Ex versions of the CM routines.
|
|
This allows callers to get device information on remote machines.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return value:
|
|
|
|
If the function succeeds, it returns CR_SUCCESS, otherwise it returns one
|
|
of the CR_* error codes.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
WORD wVersion = 0;
|
|
PPNP_MACHINE pMachine = NULL;
|
|
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (phMachine == NULL) {
|
|
Status = CR_INVALID_POINTER;
|
|
goto Clean0;
|
|
}
|
|
|
|
*phMachine = NULL;
|
|
|
|
//
|
|
// if machine name specified, check for UNC format
|
|
//
|
|
if ((UNCServerName != NULL) && (*UNCServerName != '\0')) {
|
|
|
|
if (lstrlen(UNCServerName) < 3 ||
|
|
UNCServerName[0] != '\\' ||
|
|
UNCServerName[1] != '\\') {
|
|
|
|
Status = CR_INVALID_MACHINENAME;
|
|
goto Clean0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// allocate memory for the machine structure and initialize it
|
|
//
|
|
pMachine = (PPNP_MACHINE)malloc(sizeof(PNP_MACHINE));
|
|
|
|
if (pMachine == NULL) {
|
|
Status = CR_OUT_OF_MEMORY;
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
if ((UNCServerName == NULL) || (*UNCServerName == '\0') ||
|
|
(lstrcmpi(UNCServerName, LocalMachineName) == 0)) {
|
|
|
|
//----------------------------------------------------------
|
|
// If no machine name was passed in or the machine name
|
|
// matches the local name, use local machine info rather
|
|
// than creating a new binding.
|
|
//----------------------------------------------------------
|
|
|
|
PnPGetGlobalHandles(NULL,
|
|
&pMachine->hStringTable,
|
|
&pMachine->hBindingHandle);
|
|
|
|
lstrcpy(pMachine->szMachineName, LocalMachineName);
|
|
}
|
|
|
|
else {
|
|
|
|
//-------------------------------------------------------------
|
|
// A remote machine name was specified so explicitly force a
|
|
// new binding for this machine.
|
|
//-------------------------------------------------------------
|
|
|
|
pMachine->hBindingHandle =
|
|
(PVOID)PNP_HANDLE_bind((PNP_HANDLE)UNCServerName);
|
|
|
|
if (pMachine->hBindingHandle == NULL) {
|
|
|
|
if (GetLastError() == ERROR_NOT_ENOUGH_MEMORY) {
|
|
Status = CR_OUT_OF_MEMORY;
|
|
} else if (GetLastError() == ERROR_INVALID_COMPUTERNAME) {
|
|
Status = CR_INVALID_MACHINENAME;
|
|
} else {
|
|
Status = CR_FAILURE;
|
|
}
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// initialize a string table for use with this connection to
|
|
// the remote machine
|
|
//
|
|
pMachine->hStringTable = StringTableInitialize();
|
|
|
|
if (pMachine->hStringTable == NULL) {
|
|
Status = CR_OUT_OF_MEMORY;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Add a priming string (see dll entrypt in main.c for details)
|
|
//
|
|
StringTableAddString(pMachine->hStringTable,
|
|
PRIMING_STRING,
|
|
STRTAB_CASE_SENSITIVE);
|
|
|
|
//
|
|
// save the machine name
|
|
//
|
|
lstrcpy(pMachine->szMachineName, UNCServerName);
|
|
}
|
|
|
|
|
|
//
|
|
// test the binding by calling the simplest RPC call (good way
|
|
// for the caller to know whether the service is actually
|
|
// running)
|
|
//
|
|
RpcTryExcept {
|
|
//
|
|
// call rpc service entry point
|
|
//
|
|
Status = PNP_GetVersion(pMachine->hBindingHandle,
|
|
&wVersion);
|
|
}
|
|
RpcExcept (1) {
|
|
PnPTrace(
|
|
TEXT("PNP_GetVersion caused an exception (%d)\n"),
|
|
RpcExceptionCode());
|
|
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
|
|
if (Status == CR_SUCCESS) {
|
|
*phMachine = (HMACHINE)pMachine;
|
|
}
|
|
|
|
|
|
Clean0:
|
|
;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (Status != CR_SUCCESS && pMachine != NULL) {
|
|
free(pMachine);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Connect_MachineW
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Disconnect_Machine(
|
|
IN HMACHINE hMachine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine disconnects from a machine that was previously connected to
|
|
with the CM_Connect_Machine call.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return value:
|
|
|
|
If the function succeeds, it returns CR_SUCCESS, otherwise it returns one
|
|
of the CR_* error codes.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PPNP_MACHINE pMachine = NULL;
|
|
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (hMachine == NULL) {
|
|
Status = CR_INVALID_POINTER;
|
|
goto Clean0;
|
|
}
|
|
|
|
pMachine = (PPNP_MACHINE)hMachine;
|
|
|
|
//
|
|
// only free the machine info if it's not the local machine
|
|
//
|
|
if (pMachine->hStringTable != hLocalStringTable) {
|
|
//
|
|
// free the rpc binding for this remote machine
|
|
//
|
|
PNP_HANDLE_unbind((PNP_HANDLE)pMachine->szMachineName,
|
|
(handle_t)pMachine->hBindingHandle);
|
|
|
|
//
|
|
// release the string table
|
|
//
|
|
StringTableDestroy(pMachine->hStringTable);
|
|
}
|
|
|
|
//
|
|
// free the memory for the PNP_MACHINE struct
|
|
//
|
|
free(pMachine);
|
|
|
|
|
|
Clean0:
|
|
;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Disconnect_Machine
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Get_Global_State_Ex(
|
|
OUT PULONG pulState,
|
|
IN ULONG ulFlags,
|
|
IN HMACHINE hMachine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine retrieves the global state of the configuration manager.
|
|
|
|
Parameters:
|
|
|
|
pulState Supplies the address of the variable that receives the
|
|
Configuration Manager’s state. May be a combination of the
|
|
following values:
|
|
|
|
Configuration Manager Global State Flags:
|
|
CM_GLOBAL_STATE_CAN_DO_UI
|
|
Can UI be initiated? [TBD: On NT, this may relate to
|
|
whether anyone is logged in]
|
|
CM_GLOBAL_STATE_SERVICES_AVAILABLE
|
|
Are the CM APIs available? (on Windows NT this is always set)
|
|
CM_GLOBAL_STATE_SHUTTING_DOWN
|
|
The Configuration Manager is shutting down.
|
|
[TBD: Does this only happen at shutdown/restart time?]
|
|
CM_GLOBAL_STATE_DETECTION_PENDING
|
|
The Configuration Manager is about to initiate some
|
|
sort of detection.
|
|
|
|
Windows 95 also defines the following additional flag:
|
|
CM_GLOBAL_STATE_ON_BIG_STACK
|
|
[TBD: What should this be defaulted to for NT?]
|
|
|
|
ulFlags [TBD: What flags apply here?]
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is a CR error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
handle_t hBinding = NULL;
|
|
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (pulState == NULL) {
|
|
Status = CR_INVALID_POINTER;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, 0)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// setup rpc binding handle (don't need string table handle)
|
|
//
|
|
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
//
|
|
// call rpc service entry point
|
|
//
|
|
Status = PNP_GetGlobalState(
|
|
hBinding, // rpc binding handle
|
|
pulState, // returns global state
|
|
ulFlags); // not used
|
|
}
|
|
RpcExcept (1) {
|
|
PnPTrace(
|
|
TEXT("PNP_GetGlobalState caused an exception (%d)\n"),
|
|
RpcExceptionCode());
|
|
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
|
|
Clean0:
|
|
;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Get_Global_State
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Run_Detection_Ex(
|
|
IN ULONG ulFlags,
|
|
IN HMACHINE hMachine
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine loads and executes a detection module.
|
|
|
|
Parameters:
|
|
|
|
ulFlags Specifies the reason for the detection. Can be one of the
|
|
following values:
|
|
|
|
Detection Flags:
|
|
CM_DETECT_NEW_PROFILE - Run detection for a new hardware
|
|
profile.
|
|
CM_DETECT_CRASHED - Previously attempted detection crashed.
|
|
|
|
(Windows 95 defines the following two unused flags as well:
|
|
CM_DETECT_HWPROF_FIRST_BOOT and CM_DETECT_RUN.)
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is CR_INVALID_FLAG.
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
handle_t hBinding = NULL;
|
|
|
|
|
|
try {
|
|
//
|
|
// validate permission
|
|
//
|
|
if (!IsUserAdmin()) {
|
|
Status = CR_ACCESS_DENIED;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (INVALID_FLAGS(ulFlags, CM_DETECT_BITS)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// setup rpc binding handle (don't need string table handle)
|
|
//
|
|
if (!PnPGetGlobalHandles(hMachine, NULL, &hBinding)) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
RpcTryExcept {
|
|
//
|
|
// call rpc service entry point
|
|
//
|
|
Status = PNP_RunDetection(
|
|
hBinding,
|
|
ulFlags); // not used
|
|
}
|
|
RpcExcept (1) {
|
|
PnPTrace(
|
|
TEXT("PNP_RunDetection caused an exception (%d)\n"),
|
|
RpcExceptionCode());
|
|
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
|
|
Clean0:
|
|
;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Run_Detect_Ex
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Query_Arbitrator_Free_Data_Ex(
|
|
OUT PVOID pData,
|
|
IN ULONG DataLen,
|
|
IN DEVINST dnDevInst,
|
|
IN RESOURCEID ResourceID,
|
|
IN ULONG ulFlags,
|
|
IN HMACHINE hMachine
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns information about available resources of a
|
|
particular type. If the given size is not large enough, this API
|
|
truncates the data and returns CR_BUFFER_SMALL. To determine the
|
|
buffer size needed to receive all the available resource information,
|
|
use the CM_Query_Arbitrator_Free_Size API.
|
|
|
|
Parameters:
|
|
|
|
pData Supplies the address of the buffer that receives information
|
|
on the available resources for the resource type specified
|
|
by ResourceID.
|
|
|
|
DataLen Supplies the size, in bytes, of the data buffer.
|
|
|
|
dnDevNode Supplies the handle of the device instance associated with
|
|
the arbitrator. This is only meaningful for local
|
|
arbitrators--for global arbitrators, specify the root device
|
|
instance or NULL. On Windows NT, this parameter must
|
|
specify either the Root device instance or NULL.
|
|
|
|
ResourceID Supplies the type of the resource. Can be one of the ResType
|
|
values listed in Section 2.1.2.1.. (This API returns
|
|
CR_INVALID_RESOURCEID if this value is ResType_All or
|
|
ResType_None.)
|
|
|
|
ulFlags Must be zero.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_BUFFER_SMALL,
|
|
CR_FAILURE,
|
|
CR_INVALID_DEVNODE,
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_POINTER, or
|
|
CR_INVALID_RESOURCEID.
|
|
(Windows 95 may also return CR_NO_ARBITRATOR.)
|
|
|
|
--*/
|
|
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
LPWSTR pDeviceID = NULL;
|
|
PVOID hStringTable = NULL;
|
|
handle_t hBinding = NULL;
|
|
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (dnDevInst == 0) {
|
|
Status = CR_INVALID_DEVINST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (pData == NULL || DataLen == 0) {
|
|
Status = CR_INVALID_POINTER;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, CM_QUERY_ARBITRATOR_BITS)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (ResourceID > ResType_MAX && ResourceID != ResType_ClassSpecific) {
|
|
Status = CR_INVALID_RESOURCEID;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// setup rpc binding handle (don't need string table handle)
|
|
//
|
|
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// retrieve the device instance ID string associated with the devinst
|
|
//
|
|
pDeviceID = StringTableStringFromId(hStringTable, dnDevInst);
|
|
if (pDeviceID == NULL || INVALID_DEVINST(pDeviceID)) {
|
|
Status = CR_INVALID_DEVINST;
|
|
goto Clean0;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
//
|
|
// call rpc service entry point
|
|
//
|
|
Status = PNP_QueryArbitratorFreeData(
|
|
hBinding,
|
|
pData,
|
|
DataLen,
|
|
pDeviceID,
|
|
ResourceID,
|
|
ulFlags); // not used
|
|
}
|
|
RpcExcept (1) {
|
|
PnPTrace(
|
|
TEXT("PNP_QueryArbitratorFreeData caused an exception (%d)\n"),
|
|
RpcExceptionCode());
|
|
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
|
|
Clean0:
|
|
;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Query_Arbitrator_Free_Data_Ex
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CM_Query_Arbitrator_Free_Size_Ex(
|
|
OUT PULONG pulSize,
|
|
IN DEVINST dnDevInst,
|
|
IN RESOURCEID ResourceID,
|
|
IN ULONG ulFlags,
|
|
IN HMACHINE hMachine
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
This routine retrieves the size of the available resource information
|
|
that would be returned in a call to the CM_Query_Arbitrator_Free_Data
|
|
API.
|
|
|
|
Parameters:
|
|
|
|
pulSize Supplies the address of the variable that receives the size,
|
|
in bytes, that is required to hold the available resource
|
|
information.
|
|
|
|
dnDevNode Supplies the handle of the device instance associated with
|
|
the arbitrator. This is only meaningful for local
|
|
arbitrators--for global arbitrators, specify the root
|
|
device instance or NULL. On Windows NT, this parameter
|
|
must specify either the Root device instance or NULL.
|
|
|
|
ResourceID Supplies the type of the resource. Can be one of the
|
|
ResType values listed in Section 2.1.2.1.. (This API returns
|
|
CR_INVALID_RESOURCEID if this value is ResType_All or
|
|
ResType_None.)
|
|
|
|
ulFlags Must be zero.
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is CR_SUCCESS.
|
|
If the function fails, the return value is one of the following:
|
|
CR_FAILURE,
|
|
CR_INVALID_DEVNODE,
|
|
CR_INVALID_FLAG,
|
|
CR_INVALID_POINTER, or
|
|
CR_INVALID_RESOURCEID.
|
|
(Windows 95 may also return CR_NO_ARBITRATOR.)
|
|
|
|
--*/
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
LPWSTR pDeviceID = NULL;
|
|
PVOID hStringTable = NULL;
|
|
handle_t hBinding = NULL;
|
|
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (dnDevInst == 0) {
|
|
Status = CR_INVALID_DEVINST;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (pulSize == NULL) {
|
|
Status = CR_INVALID_POINTER;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (INVALID_FLAGS(ulFlags, CM_QUERY_ARBITRATOR_BITS)) {
|
|
Status = CR_INVALID_FLAG;
|
|
goto Clean0;
|
|
}
|
|
|
|
if (ResourceID > ResType_MAX && ResourceID != ResType_ClassSpecific) {
|
|
Status = CR_INVALID_RESOURCEID;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// setup rpc binding handle (don't need string table handle)
|
|
//
|
|
if (!PnPGetGlobalHandles(hMachine, &hStringTable, &hBinding)) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// retrieve the device instance ID string associated with the devinst
|
|
//
|
|
pDeviceID = StringTableStringFromId(hStringTable, dnDevInst);
|
|
if (pDeviceID == NULL || INVALID_DEVINST(pDeviceID)) {
|
|
Status = CR_INVALID_DEVINST;
|
|
goto Clean0;
|
|
}
|
|
|
|
RpcTryExcept {
|
|
//
|
|
// call rpc service entry point
|
|
//
|
|
Status = PNP_QueryArbitratorFreeSize(
|
|
hBinding,
|
|
pulSize,
|
|
pDeviceID,
|
|
ResourceID,
|
|
ulFlags); // not used
|
|
}
|
|
RpcExcept (1) {
|
|
PnPTrace(
|
|
TEXT("PNP_QueryArbitratorFreeSize caused an exception (%d)\n"),
|
|
RpcExceptionCode());
|
|
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
|
|
Clean0:
|
|
;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Query_Arbitrator_Free_Size_Ex
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
// Private CM routines
|
|
//-------------------------------------------------------------------
|
|
|
|
CONFIGRET
|
|
CMP_Report_LogOn(
|
|
IN ULONG ulPrivateID
|
|
)
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
handle_t hBinding = NULL;
|
|
BOOL bAdmin = FALSE;
|
|
STARTUPINFO StartupInfo;
|
|
PROCESS_INFORMATION ProcessInfo;
|
|
HANDLE hEvent = NULL, hPipe = NULL;
|
|
DWORD Retries = 0;
|
|
|
|
|
|
try {
|
|
|
|
ProcessInfo.hThread = NULL;
|
|
ProcessInfo.hProcess = NULL;
|
|
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (ulPrivateID != 0x07020420) {
|
|
Status = CR_INVALID_DATA;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// this is always to the local server, by definition
|
|
//
|
|
if (!PnPGetGlobalHandles(NULL, NULL, &hBinding)) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// determine from the userinit process, whether the user
|
|
// logged onto an account that is part of Administrators
|
|
// local group
|
|
//
|
|
bAdmin = IsUserAdmin();
|
|
|
|
//
|
|
// create an event that will be signaled by the hidden process
|
|
// after it creates the pipe
|
|
//
|
|
hEvent = CreateEvent(NULL,
|
|
FALSE, // auto-reset
|
|
FALSE, // not owned initially
|
|
PNP_CREATE_PIPE_EVENT);
|
|
|
|
if (hEvent == NULL) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Start setup.exe, it will run in the context of the
|
|
// currently logged on user and respond to requests
|
|
//
|
|
StartupInfo.cb = sizeof(STARTUPINFO);
|
|
StartupInfo.lpReserved = NULL;
|
|
StartupInfo.lpDesktop = NULL;
|
|
StartupInfo.lpTitle = NULL;
|
|
StartupInfo.dwX = StartupInfo.dwY = 0;
|
|
StartupInfo.dwXSize = StartupInfo.dwYSize = 0;
|
|
StartupInfo.dwFlags = 0;
|
|
StartupInfo.wShowWindow = SW_SHOW;
|
|
StartupInfo.cbReserved2 = 0;
|
|
StartupInfo.lpReserved2 = NULL;
|
|
|
|
if (!CreateProcess(NULL,
|
|
pszProcessCmdLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
DETACHED_PROCESS,
|
|
NULL,
|
|
NULL,
|
|
&StartupInfo,
|
|
&ProcessInfo)) {
|
|
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
CloseHandle(ProcessInfo.hThread);
|
|
|
|
//
|
|
// wait for event to be signaled - which means the process has
|
|
// created the named pipe and is about to start listening on it
|
|
// (wait up to three minutes)
|
|
//
|
|
if (WaitForSingleObject(hEvent, 180000) != WAIT_OBJECT_0) {
|
|
//
|
|
// didn't get the event (most likely it either timed out
|
|
// or the event was abandoned).
|
|
//
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
for (Retries = 0; Retries < NUM_LOGON_RETRIES; Retries++) {
|
|
|
|
RpcTryExcept {
|
|
//
|
|
// call rpc service entry point
|
|
//
|
|
Status = PNP_ReportLogOn(
|
|
hBinding, // rpc binding handle
|
|
bAdmin); // Is Admin?
|
|
}
|
|
RpcExcept (1) {
|
|
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
|
|
if (Status == CR_NO_CM_SERVICES ||
|
|
Status == CR_REMOTE_COMM_FAILURE) {
|
|
|
|
#if DBG
|
|
PnPTrace(TEXT("PlugPlay services not avaible (%d), retrying...\n"), Status);
|
|
#endif
|
|
|
|
Sleep(5000); // wait and then retry
|
|
continue;
|
|
|
|
} else {
|
|
|
|
goto Clean0; // success or other non-rpc error
|
|
}
|
|
}
|
|
|
|
|
|
Clean0:
|
|
;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
if (hEvent != NULL) {
|
|
CloseHandle(hEvent);
|
|
}
|
|
|
|
if (Status != CR_SUCCESS) {
|
|
//
|
|
// try getting setup.exe process to exit on it's own by
|
|
// opening and closing the pipe
|
|
//
|
|
if (WaitNamedPipe(PNP_NEW_HW_PIPE, PNP_PIPE_TIMEOUT)) {
|
|
|
|
if ((hPipe = CreateFile(PNP_NEW_HW_PIPE,
|
|
GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL)) != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hPipe);
|
|
}
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CMP_Report_LogOn
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
CMP_Init_Detection(
|
|
IN ULONG ulPrivateID
|
|
)
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
handle_t hBinding = NULL;
|
|
|
|
|
|
try {
|
|
//
|
|
// validate parameters
|
|
//
|
|
if (ulPrivateID != 0x07020420) {
|
|
Status = CR_INVALID_DATA;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// this is always to the local server, by definition
|
|
//
|
|
if (!PnPGetGlobalHandles(NULL, NULL, &hBinding)) {
|
|
Status = CR_FAILURE;
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
RpcTryExcept {
|
|
//
|
|
// call rpc service entry point
|
|
//
|
|
Status = PNP_InitDetection(
|
|
hBinding); // rpc binding handle
|
|
}
|
|
RpcExcept (1) {
|
|
PnPTrace(
|
|
TEXT("PNP_InitDetection caused an exception (%d)\n"),
|
|
RpcExceptionCode());
|
|
Status = MapRpcExceptionToCR(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept
|
|
|
|
|
|
Clean0:
|
|
;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = CR_FAILURE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CMP_Init_Detection
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
// Local Stubs
|
|
//-------------------------------------------------------------------
|
|
|
|
|
|
WORD
|
|
CM_Get_Version(
|
|
VOID
|
|
)
|
|
{
|
|
return CM_Get_Version_Ex(NULL);
|
|
}
|
|
|
|
|
|
CONFIGRET
|
|
CM_Get_Global_State(
|
|
OUT PULONG pulState,
|
|
IN ULONG ulFlags
|
|
)
|
|
{
|
|
return CM_Get_Global_State_Ex(pulState, ulFlags, NULL);
|
|
}
|
|
|
|
|
|
CONFIGRET
|
|
CM_Query_Arbitrator_Free_Data(
|
|
OUT PVOID pData,
|
|
IN ULONG DataLen,
|
|
IN DEVINST dnDevInst,
|
|
IN RESOURCEID ResourceID,
|
|
IN ULONG ulFlags
|
|
)
|
|
{
|
|
return CM_Query_Arbitrator_Free_Data_Ex(pData, DataLen, dnDevInst,
|
|
ResourceID, ulFlags, NULL);
|
|
}
|
|
|
|
|
|
CONFIGRET
|
|
CM_Query_Arbitrator_Free_Size(
|
|
OUT PULONG pulSize,
|
|
IN DEVINST dnDevInst,
|
|
IN RESOURCEID ResourceID,
|
|
IN ULONG ulFlags
|
|
)
|
|
{
|
|
return CM_Query_Arbitrator_Free_Size_Ex(pulSize, dnDevInst, ResourceID,
|
|
ulFlags, NULL);
|
|
}
|
|
|
|
|
|
CONFIGRET
|
|
CM_Run_Detection(
|
|
IN ULONG ulFlags
|
|
)
|
|
{
|
|
return CM_Run_Detection_Ex(ulFlags, NULL);
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
// ANSI Stubs
|
|
//-------------------------------------------------------------------
|
|
|
|
|
|
CONFIGRET
|
|
CM_Connect_MachineA(
|
|
IN PCSTR UNCServerName,
|
|
OUT PHMACHINE phMachine
|
|
)
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
PWSTR pUniName = NULL;
|
|
|
|
if (UNCServerName == NULL ||
|
|
*UNCServerName == 0x0) {
|
|
//
|
|
// no explicit name specified, so assume local machine and
|
|
// nothing to translate
|
|
//
|
|
Status = CM_Connect_MachineW(pUniName,
|
|
phMachine);
|
|
|
|
} else if (CaptureAndConvertAnsiArg(UNCServerName, &pUniName) == NO_ERROR) {
|
|
|
|
Status = CM_Connect_MachineW(pUniName,
|
|
phMachine);
|
|
free(pUniName);
|
|
|
|
} else {
|
|
Status = CR_INVALID_DATA;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // CM_Connect_MachineA
|
|
|
|
|
|
|