/*++ Copyright (c) Microsoft Corporation. All rights reserved. Module Name: rmisc.c Abstract: This module contains the server-side misc configuration manager routines. PNP_GetVersion PNP_GetVersionInternal PNP_GetGlobalState PNP_SetActiveService PNP_QueryArbitratorFreeData PNP_QueryArbitratorFreeSize PNP_InitDetection PNP_RunDetection PNP_Connect PNP_Disconnect PNP_GetBlockedDriverInfo The following routines are used by the RPC server stubs to allocate and free memory. MIDL_user_allocate MIDL_user_free Author: Paula Tomlinson (paulat) 6-28-1995 Environment: User-mode only. Revision History: 28-June-1995 paulat Creation and initial implementation. --*/ // // includes // #include "precomp.h" #pragma hdrstop #include "umpnpi.h" #include "umpnpdat.h" // // global data // extern DWORD CurrentServiceState; // current state of the PlugPlay service - DO NOT MODIFY CONFIGRET PNP_GetVersion( IN handle_t hBinding, IN OUT WORD * pVersion ) /*++ Routine Description: This is the RPC server entry point, it returns the version number for the server-side component. Arguments: hBinding Not used. Return Value: Return the version number, with the major version in the high byte and the minor version number in the low byte. --*/ { CONFIGRET Status = CR_SUCCESS; UNREFERENCED_PARAMETER(hBinding); try { *pVersion = (WORD)PNP_VERSION; } except(EXCEPTION_EXECUTE_HANDLER) { Status = CR_FAILURE; } return Status; } // PNP_GetVersion CONFIGRET PNP_GetVersionInternal( IN handle_t hBinding, IN OUT WORD * pwVersion ) /*++ Routine Description: This is the RPC server entry point, it returns the internal version number for the server-side component. Arguments: hBinding Not used. pwVersion Receives the internal cfgmgr32 version number, returns the internal server version number, with the major version in the high byte and the minor version number in the low byte. Return Value: Return CR_SUCCESS if the function succeeds, otherwise it returns one of the CR_* errors. --*/ { CONFIGRET Status = CR_SUCCESS; UNREFERENCED_PARAMETER(hBinding); try { *pwVersion = (WORD)PNP_VERSION_INTERNAL; } except(EXCEPTION_EXECUTE_HANDLER) { Status = CR_FAILURE; } return Status; } // PNP_GetVersionInternal CONFIGRET PNP_GetGlobalState( IN handle_t hBinding, OUT PULONG pulState, IN ULONG ulFlags ) /*++ Routine Description: This is the RPC server entry point, it returns the Global State of the Configuration Manager. Arguments: hBinding Not used. pulState Returns the current global state. ulFlags Not used, must be zero. Return Value: Return CR_SUCCESS if the function succeeds, otherwise it returns one of the CR_* errors. --*/ { CONFIGRET Status = CR_SUCCESS; UNREFERENCED_PARAMETER(hBinding); try { // // validate parameters // if (INVALID_FLAGS(ulFlags, 0)) { Status = CR_INVALID_FLAG; goto Clean0; } // // The following CM global state flags are always set. // *pulState = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE; // // If the service is shutting down, specify the corresponding CM global // state flag. // if ((CurrentServiceState == SERVICE_STOP_PENDING) || (CurrentServiceState == SERVICE_STOPPED)) { *pulState |= CM_GLOBAL_STATE_SHUTTING_DOWN; } Clean0: NOTHING; } except(EXCEPTION_EXECUTE_HANDLER) { Status = CR_FAILURE; } return Status; } // PNP_GetGlobalState CONFIGRET PNP_SetActiveService( IN handle_t hBinding, IN LPCWSTR pszService, IN ULONG ulFlags ) /*++ Routine Description: This routine is currently not an rpc routine, it is called directly and privately by the service controller. Arguments: hBinding RPC binding handle, not used. pszService Specifies the service name. ulFlags Either PNP_SERVICE_STARTED or PNP_SERVICE_STOPPED. Return Value: Return CR_SUCCESS if the function succeeds, otherwise it returns one of the CR_* errors. --*/ { CONFIGRET Status = CR_SUCCESS; ULONG ulSize = 0; LPWSTR pDeviceList = NULL, pszDevice = NULL; HKEY hKey = NULL, hControlKey = NULL; WCHAR RegStr[MAX_PATH]; UNREFERENCED_PARAMETER(hBinding); try { // // validate parameters // if (pszService == NULL) { Status = CR_INVALID_POINTER; goto Clean0; } if ((ulFlags != PNP_SERVICE_STOPPED) && (ulFlags != PNP_SERVICE_STARTED)) { Status = CR_INVALID_FLAG; goto Clean0; } // // not handling stops right now, everything beyond here assumes // the service is starting (or at least it attempted to start) // if (ulFlags == PNP_SERVICE_STOPPED) { Status = CR_SUCCESS; goto Clean0; } // // retreive the list of devices that this service is controlling // Status = PNP_GetDeviceListSize(NULL, pszService, &ulSize, CM_GETIDLIST_FILTER_SERVICE); if (Status != CR_SUCCESS) { goto Clean0; } pDeviceList = HeapAlloc(ghPnPHeap, 0, ulSize * sizeof(WCHAR)); if (pDeviceList == NULL) { Status = CR_OUT_OF_MEMORY; goto Clean0; } Status = PNP_GetDeviceList(NULL, pszService, pDeviceList, &ulSize, CM_GETIDLIST_FILTER_SERVICE); if (Status != CR_SUCCESS) { goto Clean0; } // // set the ActiveService value for each device // for (pszDevice = pDeviceList; *pszDevice; pszDevice += lstrlen(pszDevice) + 1) { if (FAILED(StringCchPrintf( RegStr, SIZECHARS(RegStr), L"%s\\%s", pszRegPathEnum, pszDevice))) { continue; } // // open the device instance key // if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegStr, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) { // // open/create the volatile Control key // if (RegCreateKeyEx(hKey, pszRegKeyDeviceControl, 0, NULL, REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hControlKey, NULL) == ERROR_SUCCESS) { RegSetValueEx(hControlKey, pszRegValueActiveService, 0, REG_SZ, (LPBYTE)pszService, (lstrlen(pszService) + 1) * sizeof(WCHAR)); // // set the statusflag to DN_STARTED // SetDeviceStatus(pszDevice, DN_STARTED, 0); RegCloseKey(hControlKey); hControlKey = NULL; } RegCloseKey(hKey); hKey = NULL; } } Clean0: NOTHING; } except(EXCEPTION_EXECUTE_HANDLER) { Status = CR_FAILURE; } if (pDeviceList != NULL) { HeapFree(ghPnPHeap, 0, pDeviceList); } if (hKey != NULL) { RegCloseKey(hKey); } return Status; } // PNP_SetActiveService //-------------------------------------------------------------------- // Stub server side CM routines - not implemented yet //-------------------------------------------------------------------- CONFIGRET PNP_QueryArbitratorFreeData( IN handle_t hBinding, OUT LPBYTE pData, IN ULONG ulDataLen, IN LPCWSTR pszDeviceID, IN RESOURCEID ResourceID, IN ULONG ulFlags ) { UNREFERENCED_PARAMETER(hBinding); UNREFERENCED_PARAMETER(pData); UNREFERENCED_PARAMETER(ulDataLen); UNREFERENCED_PARAMETER(pszDeviceID); UNREFERENCED_PARAMETER(ResourceID); UNREFERENCED_PARAMETER(ulFlags); return CR_CALL_NOT_IMPLEMENTED; } // PNP_QueryArbitratorFreeData CONFIGRET PNP_QueryArbitratorFreeSize( IN handle_t hBinding, OUT PULONG pulSize, IN LPCWSTR pszDeviceID, IN RESOURCEID ResourceID, IN ULONG ulFlags ) { CONFIGRET Status; UNREFERENCED_PARAMETER(hBinding); UNREFERENCED_PARAMETER(pszDeviceID); UNREFERENCED_PARAMETER(ResourceID); UNREFERENCED_PARAMETER(ulFlags); try { if (ARGUMENT_PRESENT(pulSize)) { *pulSize = 0; } Status = CR_CALL_NOT_IMPLEMENTED; } except(EXCEPTION_EXECUTE_HANDLER) { Status = CR_FAILURE; } return Status; } // PNP_QueryArbitratorFreeSize //--------------------------------------------------------------------------- // Debugging interface - initiate detection through private debug interface //--------------------------------------------------------------------------- CONFIGRET PNP_InitDetection( handle_t hBinding ) /*++ Routine Description: This routine is a private debugging interface to initiate device detection. Arguments: hBinding - RPC binding handle. Return Value: Currently returns CR_CALL_NOT_IMPLEMENTED. Notes: Previously, this routine would kick off the InitializePnPManager thread on checked builds only. Presumably, this dates way back to a time when this routine actually sought out non-configured devices and initiated installation on them (as is currently done at the start of the ThreadProc_DeviceInstall thread procedure routine). Since InitializePnPManager no longer does this, so this behavior has been removed altogether. It is currently never valid to perform initialization more than once, however this routine may be used to implement detection of non-configured devices. --*/ { // // Verify client "execute" access // if (!VerifyClientAccess(hBinding, PLUGPLAY_EXECUTE)) { return CR_ACCESS_DENIED; } // // Verify client privilege // if (!VerifyClientPrivilege(hBinding, SE_LOAD_DRIVER_PRIVILEGE, L"Plug and Play Action (not implemeted)")) { return CR_ACCESS_DENIED; } return CR_CALL_NOT_IMPLEMENTED; } // PNP_InitDetection CONFIGRET PNP_RunDetection( IN handle_t hBinding, IN ULONG ulFlags ) { UNREFERENCED_PARAMETER(ulFlags); // // Verify client "execute" access // if (!VerifyClientAccess(hBinding, PLUGPLAY_EXECUTE)) { return CR_ACCESS_DENIED; } // // Verify client privilege // if (!VerifyClientPrivilege(hBinding, SE_LOAD_DRIVER_PRIVILEGE, L"Plug and Play Action (not implemeted)")) { return CR_ACCESS_DENIED; } return CR_CALL_NOT_IMPLEMENTED; } // PNP_RunDetection CONFIGRET PNP_Connect( IN PNP_HANDLE UNCServerName ) { // // Note that although this routine is listed in the PNP RPC interface, it // uses automatic binding, and does not reference any implicit binding handle // (which is how the interface has come to be defined). As such, it is not // callable through the existing PNP RPC interface. // UNREFERENCED_PARAMETER(UNCServerName); return CR_CALL_NOT_IMPLEMENTED; } // PNP_Connect CONFIGRET PNP_Disconnect( IN PNP_HANDLE UNCServerName ) { // // Note that although this routine is listed in the PNP RPC interface, it // uses automatic binding, and does not reference any implicit binding handle // (which is how the interface has come to be defined). As such, it is not // callable through the existing PNP RPC interface. // UNREFERENCED_PARAMETER(UNCServerName); return CR_CALL_NOT_IMPLEMENTED; } // PNP_Disconnect CONFIGRET PNP_GetBlockedDriverInfo( IN handle_t hBinding, OUT LPBYTE Buffer, OUT PULONG pulTransferLen, IN OUT PULONG pulLength, IN ULONG ulFlags ) /*++ Routine Description: This is the RPC server entry point for the CMP_GetBlockedDriverInfo routine. Arguments: hBinding - RPC binding handle, not used. Buffer - Supplies the address of the buffer that receives the list. Can be NULL when simply retrieving data size. pulTransferLen - Used by stubs, indicates how much data (in bytes) to copy back into user buffer. pulLength - Parameter passed in by caller, on entry it contains the size (in bytes) of the buffer, on exit it contains either the number of bytes transferred to the caller's buffer (if a transfer occured) or else the size of buffer required to hold the list. ulFlags Not used, must be zero. Return Value: Return CR_SUCCESS if the function succeeds, otherwise it returns one of the CR_* errors. --*/ { CONFIGRET Status = CR_SUCCESS; NTSTATUS ntStatus; PLUGPLAY_CONTROL_BLOCKED_DRIVER_DATA controlData; UNREFERENCED_PARAMETER(hBinding); try { // // Validate parameters // if ((!ARGUMENT_PRESENT(pulTransferLen)) || (!ARGUMENT_PRESENT(pulLength))) { Status = CR_INVALID_POINTER; goto Clean0; } if ((!ARGUMENT_PRESENT(Buffer)) && (*pulLength != 0)) { Status = CR_INVALID_POINTER; goto Clean0; } if (INVALID_FLAGS(ulFlags, 0)) { Status = CR_INVALID_FLAG; goto Clean0; } // // We should never have both arguments pointing to the same memory... // ASSERT(pulTransferLen != pulLength); // // ...but if we do, fail the call. // if (pulTransferLen == pulLength) { Status = CR_INVALID_POINTER; goto Clean0; } // // Retrieve the blocked driver list via kernel-mode. // memset(&controlData, 0, sizeof(PLUGPLAY_CONTROL_BLOCKED_DRIVER_DATA)); controlData.Buffer = Buffer; controlData.BufferLength = *pulLength; controlData.Flags = ulFlags; ntStatus = NtPlugPlayControl(PlugPlayControlGetBlockedDriverList, &controlData, sizeof(controlData)); if (NT_SUCCESS(ntStatus)) { *pulTransferLen = *pulLength; // Transfer everything back *pulLength = controlData.BufferLength; // Length of valid data } else if (ntStatus == STATUS_BUFFER_TOO_SMALL) { *pulTransferLen = 0; // Nothing to transfer *pulLength = controlData.BufferLength; Status = CR_BUFFER_SMALL; } else { *pulLength = *pulTransferLen = 0; // Nothing to transfer Status = MapNtStatusToCmError(ntStatus); } Clean0: NOTHING; } except(EXCEPTION_EXECUTE_HANDLER) { Status = CR_FAILURE; } return Status; } // PNP_GetBlockedDriverInfo void __RPC_FAR * __RPC_USER MIDL_user_allocate( size_t cBytes ) { return HeapAlloc(ghPnPHeap, 0, cBytes); } // MIDL_user_allocate void __RPC_USER MIDL_user_free( void __RPC_FAR * pBuffer ) { HeapFree(ghPnPHeap, 0, pBuffer); } // MIDL_user_free