/*++ Copyright (c) 1992 Microsoft Corporation Module Name: scwrap.c Abstract: These are the Service Controller API RPC client wrapper routines. These are the entry points that are exported by the dll. ControlService EnumServicesStatusW EnumServicesStatusA EnumServicesStatusExW EnumServicesStatusExA EnumServiceGroupW OpenServiceW CloseServiceHandle OpenSCManagerW QueryServiceStatus QueryServiceStatusEx StartServiceW SetServiceStatus I_ScSetServiceBitsW I_ScSetServiceBitsA I_ScGetCurrentGroupStateW I_ScSendTSMessage SetServiceBits OpenSCManagerA OpenServiceA StartServiceA QueryServiceObjectSecurity SetServiceObjectSecurity ScConvertOffsetsW ScConvertOffsetsA ScConvertOffsetsExW ScConvertOffsetsExA ScConvertOffsets64 ChangeServiceConfigA ChangeServiceConfigW ChangeServiceConfig2A ChangeServiceConfig2W CreateServiceA CreateServiceW DeleteService EnumDependentServicesA EnumDependentServicesW GetServiceDisplayNameA GetServiceDisplayNameW GetServiceKeyNameA GetServiceKeyNameW LockServiceDatabase QueryServiceConfigA QueryServiceConfigW QueryServiceConfig2A QueryServiceConfig2W QueryServiceLockStatusA QueryServiceLockStatusW UnlockServiceDatabase NotifyBootConfigStatus Author: Dan Lafferty (danl) 03-Feb-1992 Environment: User Mode - Win32 Revision History: 07-May-1998 jschwart Added QueryServiceStatusEx and EnumServicesStatusEx 11-Oct-1996 AnirudhS Added ChangeServiceConfig2 and QueryServiceConfig2. 14-Feb-1996 AnirudhS Added EnumServiceGroupW. 22-Sep-1995 AnirudhS ScWaitForStart: Fixed race condition - OpenEvent needs to be tried a second time after CreateEvent. 15-Aug-1995 AnirudhS Added I_ScGetCurrentGroupStateW. 05-Nov-1992 Danl Added display name changes (CreateService, ChangeServiceConfig) and new api (GetServiceDisplayName, GetServiceKeyName). 13-Oct-1992 Danl Allow 0 length buffers to be passed into EnumServicesStatus and EnumDependentServices. 04-Aug-1992 Danl Allow 0 length buffers to be passed into QueryServiceConfig and QueryServiceLockStatus. 28-May-1992 JohnRo RAID 9829: winsvc.h and related file cleanup. 14-Apr-1992 JohnRo Enable Lock and Unlock APIs. 03-Feb-1992 Danl Created --*/ // // INCLUDES // extern "C" { #include // DbgPrint prototype #include // DbgPrint prototype #include // needed when we include windows.h } #include // DataTypes and runtime APIs #include // NO_ERROR #include // generated by the MIDL compiler #include // for lmserver.h #include // MS-internal functions #include // MS-internal functions #include // I_RpcExceptionFilter #include // needed by strarray.h #include // SCC_LOG #include // ScEncryptPassword #include // ScConvertToUnicode #include // ScWStrArraySize #include // for lmserver.h #include // SV_TYPE_WORKSTATION ... #include // ScCreateStartEventSD #include // 32/64-bit interop structures // // DEFINES // #define SC_START_TIMEOUT 180000 // 3 minute timeout #define RESERVED_BITS (SV_TYPE_WORKSTATION | \ SV_TYPE_SERVER | \ SV_TYPE_DOMAIN_CTRL | \ SV_TYPE_DOMAIN_BAKCTRL | \ SV_TYPE_TIME_SOURCE | \ SV_TYPE_AFP | \ SV_TYPE_DOMAIN_MEMBER | \ SV_TYPE_PRINTQ_SERVER | \ SV_TYPE_DIALIN_SERVER | \ SV_TYPE_XENIX_SERVER | \ SV_TYPE_SERVER_UNIX | \ SV_TYPE_NT | \ SV_TYPE_WFW | \ SV_TYPE_POTENTIAL_BROWSER | \ SV_TYPE_BACKUP_BROWSER | \ SV_TYPE_MASTER_BROWSER | \ SV_TYPE_DOMAIN_MASTER | \ SV_TYPE_LOCAL_LIST_ONLY | \ SV_TYPE_DOMAIN_ENUM) // // LOCAL FUNCTIONS // VOID ScConvertOffsetsW( LPENUM_SERVICE_STATUSW lpServices, DWORD NumStructs ); VOID ScConvertOffsetsA( LPENUM_SERVICE_STATUSA lpServices, DWORD NumStructs ); VOID ScConvertOffsetsExW( LPENUM_SERVICE_STATUS_PROCESSW lpServices, DWORD NumStructs ); VOID ScConvertOffsetsExA( LPENUM_SERVICE_STATUS_PROCESSA lpServices, DWORD NumStructs ); #ifdef _WIN64 // // API numbers for ScConvertOffsets64 // typedef enum { SC_API_ENUM_W = 0, SC_API_ENUM_A, SC_API_ENUM_GROUP, SC_API_ENUM_DEPEND_W, SC_API_ENUM_DEPEND_A, SC_API_ENUM_PROCESS_W, SC_API_ENUM_PROCESS_A, SC_API_QUERY_DESCRIPTION_W, SC_API_QUERY_DESCRIPTION_A, SC_API_QUERY_FAILURE_ACTIONS_W, SC_API_QUERY_FAILURE_ACTIONS_A, SC_API_MAX } SC_API_NUMBER; BOOL ScConvertOffsets64( SC_API_NUMBER scApi, SC_HANDLE hSCManager, DWORD dwServiceType, DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned, LPDWORD lpResumeIndex, LPVOID pszGroupName, LPDWORD lpdwError ); #endif // _WIN64 DWORD ScMapRpcError( IN DWORD RpcError, IN DWORD BadContextError ); DWORD ScWaitForStart( VOID ); // // Globals // extern "C" { void SccInit( DWORD dwReason ) { return; } } BOOL WINAPI ControlService( IN SC_HANDLE hService, IN DWORD dwControl, OUT LPSERVICE_STATUS lpServiceStatus ) /*++ Routine Description: This is the DLL entrypoint for Control Service Arguments: Return Value: --*/ { DWORD status; RpcTryExcept { status = RControlService ( (SC_RPC_HANDLE)hService, dwControl, lpServiceStatus); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI EnumServicesStatusW( IN SC_HANDLE hSCManager, IN DWORD dwServiceType, IN DWORD dwServiceState, OUT LPENUM_SERVICE_STATUSW lpServices, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded, OUT LPDWORD lpServicesReturned, IN OUT LPDWORD lpResumeIndex ) /*++ Routine Description: This is the DLL entrypoint for EnumServicesStatusW Arguments: Return Value: Note: --*/ { return EnumServiceGroupW( hSCManager, dwServiceType, dwServiceState, lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeIndex, NULL); } BOOL WINAPI EnumServicesStatusExW( IN SC_HANDLE hSCManager, IN SC_ENUM_TYPE InfoLevel, IN DWORD dwServiceType, IN DWORD dwServiceState, OUT LPBYTE lpServices, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded, OUT LPDWORD lpServicesReturned, IN OUT LPDWORD lpResumeIndex, IN LPCWSTR pszGroupName ) /*++ Routine Description: This is the DLL entrypoint for EnumServicesStatusExW Arguments: Return Value: Note: --*/ { DWORD status; LPENUM_SERVICE_STATUS_PROCESSW pEnumBuf; ENUM_SERVICE_STATUS_PROCESSW enumBuf; DWORD tempBufSize; #ifdef _WIN64 DWORD dwOldResumeIndex = 0; if (lpResumeIndex != NULL) { dwOldResumeIndex = *lpResumeIndex; } #endif // _WIN64 // // Make sure we were passed a valid InfoLevel // if (InfoLevel != SC_ENUM_PROCESS_INFO) { SetLastError(ERROR_INVALID_LEVEL); return FALSE; } tempBufSize = cbBufSize; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // if (cbBufSize < sizeof(ENUM_SERVICE_STATUS_PROCESSW) || (lpServices == NULL)) { pEnumBuf = &enumBuf; tempBufSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW); } else { pEnumBuf = (LPENUM_SERVICE_STATUS_PROCESSW)lpServices; } RpcTryExcept { status = REnumServicesStatusExW ( hSCManager, InfoLevel, dwServiceType, dwServiceState, (LPBYTE)pEnumBuf, tempBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeIndex, pszGroupName); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept // // If data is returned, convert Offsets in the Enum buffer to pointers. // if ((status == NO_ERROR) || (status == ERROR_MORE_DATA)) { if ((*lpServicesReturned) > 0) { #ifdef _WIN64 DWORD dwError; if (!ScConvertOffsets64(SC_API_ENUM_PROCESS_W, hSCManager, dwServiceType, dwServiceState, (LPBYTE) lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, &dwOldResumeIndex, (LPVOID) pszGroupName, &dwError)) { status = dwError; if (lpResumeIndex != NULL) { *lpResumeIndex = dwOldResumeIndex; } } #else // ndef _WIN64 ScConvertOffsetsExW((LPENUM_SERVICE_STATUS_PROCESSW) lpServices, *lpServicesReturned); #endif // _WIN64 } #ifdef _WIN64 // // The byte count returned is the size needed to hold all of // the 32-bit structures rather than the 64-bit ones. Assume // a buffer full of fixed-length structures (i.e., no variable- // length data) and scale from 32- to 64-bit sizes to get the // minimum guaranteed size for all the 64-bit structures. // *pcbBytesNeeded = *pcbBytesNeeded * sizeof(ENUM_SERVICE_STATUS_PROCESSW) / sizeof(ENUM_SERVICE_STATUS_PROCESS_WOW64); #endif // _WIN64 } if (status != NO_ERROR) { SetLastError(status); return FALSE; } return TRUE; } BOOL WINAPI EnumServiceGroupW( IN SC_HANDLE hSCManager, IN DWORD dwServiceType, IN DWORD dwServiceState, OUT LPENUM_SERVICE_STATUSW lpServices, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded, OUT LPDWORD lpServicesReturned, IN OUT LPDWORD lpResumeIndex, IN LPCWSTR pszGroupName ) /*++ Routine Description: This is the DLL entrypoint for EnumServiceGroupW Arguments: Return Value: Note: --*/ { DWORD status; LPENUM_SERVICE_STATUSW pEnumBuf; ENUM_SERVICE_STATUSW enumBuf; DWORD tempBufSize; #ifdef _WIN64 DWORD dwOldResumeIndex = 0; if (lpResumeIndex != NULL) { dwOldResumeIndex = *lpResumeIndex; } #endif // _WIN64 tempBufSize = cbBufSize; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // if (cbBufSize < sizeof(ENUM_SERVICE_STATUSW) || (lpServices == NULL)) { pEnumBuf = &enumBuf; tempBufSize = sizeof(ENUM_SERVICE_STATUSW); } else { pEnumBuf = lpServices; } RpcTryExcept { if (pszGroupName == NULL) { // // Call the downlevel API, so that the call will work on targeted // machines running Windows NT 3.51 or earlier // status = REnumServicesStatusW ( (SC_RPC_HANDLE)hSCManager, dwServiceType, dwServiceState, (LPBYTE)pEnumBuf, tempBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeIndex); } else { status = REnumServiceGroupW ( (SC_RPC_HANDLE)hSCManager, dwServiceType, dwServiceState, (LPBYTE)pEnumBuf, tempBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeIndex, pszGroupName); } } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept // // If data is returned, convert Offsets in the Enum buffer to pointers. // if ((status == NO_ERROR) || (status == ERROR_MORE_DATA)) { if ((*lpServicesReturned) > 0) { #ifdef _WIN64 DWORD dwError; if (!ScConvertOffsets64(pszGroupName ? SC_API_ENUM_GROUP : SC_API_ENUM_W, hSCManager, dwServiceType, dwServiceState, (LPBYTE) lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, &dwOldResumeIndex, (LPVOID) pszGroupName, &dwError)) { status = dwError; if (lpResumeIndex != NULL) { *lpResumeIndex = dwOldResumeIndex; } } #else // ndef _WIN64 ScConvertOffsetsW(lpServices, *lpServicesReturned); #endif // _WIN64 } #ifdef _WIN64 // // The byte count returned is the size needed to hold all of // the 32-bit structures rather than the 64-bit ones. Assume // a buffer full of fixed-length structures (i.e., no variable- // length data) and scale from 32- to 64-bit sizes to get the // minimum guaranteed size for all the 64-bit structures. // *pcbBytesNeeded = *pcbBytesNeeded * sizeof(ENUM_SERVICE_STATUSW) / sizeof(ENUM_SERVICE_STATUS_WOW64); #endif // _WIN64 } if (status != NO_ERROR) { SetLastError(status); return(FALSE); } return(TRUE); } SC_HANDLE WINAPI OpenServiceW( IN SC_HANDLE hSCManager, IN LPCWSTR lpServiceName, IN DWORD dwDesiredAccess ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD status; SC_RPC_HANDLE hService=NULL; RpcTryExcept { status = ROpenServiceW ( (SC_RPC_HANDLE)hSCManager, (LPWSTR) lpServiceName, dwDesiredAccess, &hService); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(NULL); } return (SC_HANDLE)hService; } BOOL WINAPI CloseServiceHandle( IN SC_HANDLE hSCObject ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD status; RpcTryExcept { status = RCloseServiceHandle((LPSC_RPC_HANDLE)&hSCObject); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } SC_HANDLE WINAPI OpenSCManagerW( IN LPCWSTR lpMachineName, IN LPCWSTR lpDatabaseName OPTIONAL, IN DWORD dwDesiredAccess ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD status; SC_RPC_HANDLE ScHandle=NULL; // // Check to see if the local Service Controller is started yet. // If not, then wait for it to start (or timeout). // status = ScWaitForStart(); if (status != NO_ERROR) { SetLastError(status); return(NULL); } RpcTryExcept { status = ROpenSCManagerW ( (LPWSTR) lpMachineName, (LPWSTR) lpDatabaseName, dwDesiredAccess, &ScHandle); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(NULL); } return (SC_HANDLE)ScHandle; } BOOL WINAPI QueryServiceStatus( IN SC_HANDLE hService, OUT LPSERVICE_STATUS lpServiceStatus ) /*++ Routine Description: This is the DLL entrypoint for QueryServiceStatus. Arguments: Return Value: --*/ { DWORD status; RpcTryExcept { status = RQueryServiceStatus ( (SC_RPC_HANDLE)hService, lpServiceStatus); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI QueryServiceStatusEx( IN SC_HANDLE hService, IN SC_STATUS_TYPE InfoLevel, OUT LPBYTE lpBuffer, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded ) /*++ Routine Description: This is the DLL entrypoint for QueryServiceStatusEx. Arguments: Return Value: Note: --*/ { DWORD status; switch (InfoLevel) { case SC_STATUS_PROCESS_INFO: if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS)) { // // The buffer is too small -- since the structure is a fixed // size, we can handle this error on the client side // *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS); SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } RpcTryExcept { status = RQueryServiceStatusEx ( (SC_RPC_HANDLE)hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR) { SetLastError(status); return FALSE; } return TRUE; } BOOL WINAPI StartServiceW( IN SC_HANDLE hService, IN DWORD dwNumServiceArgs, IN LPCWSTR *lpServiceArgVectors ) /*++ Routine Description: This is the DLL entrypoint for StartServiceW Arguments: servername - Points to a string containing the name of the computer that is to execute the API function. service- Points to a string containing the name of the service that is to be started. argc - Indicates the number or argument vectors in argv. argv - A pointer to an array of pointers to strings. These are command line arguments that are to be passed to the service. bufptr - This is the address where a pointer to the service's information buffer (SERVICE_INFO_2) is to be placed. Return Value: --*/ { DWORD status; RpcTryExcept { status = RStartServiceW ( (SC_RPC_HANDLE)hService, dwNumServiceArgs, (LPSTRING_PTRSW)lpServiceArgVectors); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI SetServiceStatus( IN SERVICE_STATUS_HANDLE hServiceStatus, IN LPSERVICE_STATUS lpServiceStatus ) /*++ Routine Description: This is the DLL entrypoint for SetServiceStatus. It is called from a service when that service changes its state or receives a control. The status is maintained by the service controller. Arguments: hServiceStatus - This is a handle that was obtained from calling the RegisterControlHandler function. lpServiceStatus - This is a pointer to a service status structure. Return Value: --*/ { DWORD status; // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { status = RSetServiceStatus ( (SC_HANDLE)hServiceStatus, lpServiceStatus); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED) { // // Service is stopping -- close the handle we opened // in StartServiceCtrlDispatcher when the service started // CloseServiceHandle((SC_HANDLE)hServiceStatus); } return(TRUE); } BOOL I_ScSetServiceBitsA( IN SERVICE_STATUS_HANDLE hServiceStatus, IN DWORD dwServiceBits, IN BOOL bSetBitsOn, IN BOOL bUpdateImmediately, IN LPSTR pszTransportName ) /*++ Routine Description: This is an internal routine that sets the Server Announcement bits in the service controller. Arguments: hServiceStatus - dwServiceBits - Return Value: Note: --*/ { DWORD status; DWORD setBitsOnFlag=0; DWORD updateImmediatelyFlag=0; if(bSetBitsOn) { setBitsOnFlag = 1; } if(bUpdateImmediately) { updateImmediatelyFlag = 1; } // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { status = RI_ScSetServiceBitsA ( (SC_HANDLE)hServiceStatus, dwServiceBits, setBitsOnFlag, updateImmediatelyFlag, pszTransportName); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } BOOL I_ScSetServiceBitsW( IN SERVICE_STATUS_HANDLE hServiceStatus, IN DWORD dwServiceBits, IN BOOL bSetBitsOn, IN BOOL bUpdateImmediately, IN LPWSTR pszTransportName ) /*++ Routine Description: This is an internal routine that sets the Server Announcement bits in the service controller. Arguments: hServiceStatus - dwServiceBits - Return Value: Note: --*/ { DWORD status; DWORD setBitsOnFlag=0; DWORD updateImmediatelyFlag=0; if(bSetBitsOn) { setBitsOnFlag = 1; } if(bUpdateImmediately) { updateImmediatelyFlag = 1; } // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { status = RI_ScSetServiceBitsW ( (SC_HANDLE)hServiceStatus, dwServiceBits, setBitsOnFlag, updateImmediatelyFlag, pszTransportName); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } DWORD I_ScGetCurrentGroupStateW( IN SC_HANDLE hSCManager, IN LPWSTR pszGroupName, OUT LPDWORD pdwCurrentState ) /*++ Routine Description: This is obsolete but some (MS) apps still statically link to it. --*/ { return ERROR_NOT_SUPPORTED; } extern "C" { DWORD I_ScSendTSMessage( DWORD OpCode, DWORD dwEvent, DWORD cbData, LPBYTE lpData ) /*++ Routine Description: Private entrypoint for Terminal Server to tell the SCM to send console switch notification to services that are interested. --*/ { DWORD status; SC_HANDLE hSCManager; hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hSCManager == NULL) { return GetLastError(); } // // Do the RPC call with an exception handler since RPC will raise an // exception if anything fails. It is up to us to figure out what // to do once the exception is raised. // RpcTryExcept { status = RI_ScSendTSMessage(hSCManager, OpCode, dwEvent, cbData, lpData); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept CloseServiceHandle(hSCManager); return status; } } // extern "C" BOOL SetServiceBits( IN SERVICE_STATUS_HANDLE hServiceStatus, IN DWORD dwServiceBits, IN BOOL bSetBitsOn, IN BOOL bUpdateImmediately ) /*++ Routine Description: This is an internal routine that sets the Server Announcement bits in the service controller. Arguments: hServiceStatus - dwServiceBits - Return Value: Note: --*/ { if (dwServiceBits & RESERVED_BITS) { SetLastError(ERROR_INVALID_DATA); return(FALSE); } return(I_ScSetServiceBitsW( hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately, (LPWSTR)NULL)); } SC_HANDLE WINAPI OpenSCManagerA( IN LPCSTR lpMachineName, IN LPCSTR lpDatabaseName OPTIONAL, IN DWORD dwDesiredAccess ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD status; SC_RPC_HANDLE ScHandle=NULL; // // Check to see if the local Service Controller is started yet. // If not, then wait for it to start (or timeout). // status = ScWaitForStart(); if (status != NO_ERROR) { SetLastError(status); return(NULL); }; RpcTryExcept { status = ROpenSCManagerA ( (LPSTR) lpMachineName, (LPSTR) lpDatabaseName, dwDesiredAccess, &ScHandle); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(NULL); } return (SC_HANDLE)ScHandle; } SC_HANDLE WINAPI OpenServiceA( IN SC_HANDLE hSCManager, IN LPCSTR lpServiceName, IN DWORD dwDesiredAccess ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD status; SC_RPC_HANDLE hService=NULL; RpcTryExcept { status = ROpenServiceA ( (SC_RPC_HANDLE)hSCManager, (LPSTR) lpServiceName, dwDesiredAccess, &hService); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(NULL); } return (SC_HANDLE)hService; } BOOL WINAPI StartServiceA( IN SC_HANDLE hService, IN DWORD dwNumServiceArgs, IN LPCSTR *lpServiceArgVectors ) /*++ Routine Description: Arguments: servername - Points to a string containing the name of the computer that is to execute the API function. service- Points to a string containing the name of the service that is to be started. argc - Indicates the number or argument vectors in argv. argv - A pointer to an array of pointers to strings. These are command line arguments that are to be passed to the service. bufptr - This is the address where a pointer to the service's information buffer (SERVICE_INFO_2) is to be placed. Return Value: --*/ { DWORD status; RpcTryExcept { status = RStartServiceA ( (SC_RPC_HANDLE)hService, dwNumServiceArgs, (LPSTRING_PTRSA)lpServiceArgVectors); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI EnumServicesStatusA( IN SC_HANDLE hSCManager, IN DWORD dwServiceType, IN DWORD dwServiceState, OUT LPENUM_SERVICE_STATUSA lpServices, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded, OUT LPDWORD lpServicesReturned, IN OUT LPDWORD lpResumeIndex ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD status; LPENUM_SERVICE_STATUSA pEnumBuf; ENUM_SERVICE_STATUSA enumBuf; DWORD tempBufSize; #ifdef _WIN64 DWORD dwOldResumeIndex = 0; if (lpResumeIndex != NULL) { dwOldResumeIndex = *lpResumeIndex; } #endif // _WIN64 tempBufSize = cbBufSize; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // if (cbBufSize < sizeof(ENUM_SERVICE_STATUSA) || (lpServices == NULL)) { pEnumBuf = &enumBuf; tempBufSize = sizeof(ENUM_SERVICE_STATUSA); } else { pEnumBuf = lpServices; } RpcTryExcept { status = REnumServicesStatusA ( (SC_RPC_HANDLE)hSCManager, dwServiceType, dwServiceState, (LPBYTE)pEnumBuf, tempBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeIndex); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept // // If data is returned, convert Offsets in the Enum buffer to pointers. // if ((status == NO_ERROR) || (status == ERROR_MORE_DATA)) { if ((*lpServicesReturned) > 0) { #ifdef _WIN64 DWORD dwError; if (!ScConvertOffsets64(SC_API_ENUM_A, hSCManager, dwServiceType, dwServiceState, (LPBYTE) lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, &dwOldResumeIndex, NULL, &dwError)) { status = dwError; if (lpResumeIndex != NULL) { *lpResumeIndex = dwOldResumeIndex; } } #else // ndef _WIN64 ScConvertOffsetsA(lpServices, *lpServicesReturned); #endif // _WIN64 } #ifdef _WIN64 // // The byte count returned is the size needed to hold all of // the 32-bit structures rather than the 64-bit ones. Assume // a buffer full of fixed-length structures (i.e., no variable- // length data) and scale from 32- to 64-bit sizes to get the // minimum guaranteed size for all the 64-bit structures. // *pcbBytesNeeded = *pcbBytesNeeded * sizeof(ENUM_SERVICE_STATUSA) / sizeof(ENUM_SERVICE_STATUS_WOW64); #endif // _WIN64 } if (status != NO_ERROR) { SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI EnumServicesStatusExA( IN SC_HANDLE hSCManager, IN SC_ENUM_TYPE InfoLevel, IN DWORD dwServiceType, IN DWORD dwServiceState, OUT LPBYTE lpServices, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded, OUT LPDWORD lpServicesReturned, IN OUT LPDWORD lpResumeIndex, IN LPCTSTR pszGroupName ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD status; LPENUM_SERVICE_STATUS_PROCESSA pEnumBuf; ENUM_SERVICE_STATUS_PROCESSA enumBuf; DWORD tempBufSize; #ifdef _WIN64 DWORD dwOldResumeIndex = 0; if (lpResumeIndex != NULL) { dwOldResumeIndex = *lpResumeIndex; } #endif // _WIN64 // // Make sure we were passed a valid InfoLevel // if (InfoLevel != SC_ENUM_PROCESS_INFO) { SetLastError(ERROR_INVALID_LEVEL); return FALSE; } tempBufSize = cbBufSize; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // if (cbBufSize < sizeof(ENUM_SERVICE_STATUS_PROCESSA) || (lpServices == NULL)) { pEnumBuf = &enumBuf; tempBufSize = sizeof(ENUM_SERVICE_STATUS_PROCESSA); } else { pEnumBuf = (LPENUM_SERVICE_STATUS_PROCESSA) lpServices; } RpcTryExcept { status = REnumServicesStatusExA ( (SC_RPC_HANDLE)hSCManager, InfoLevel, dwServiceType, dwServiceState, (LPBYTE)pEnumBuf, tempBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeIndex, pszGroupName); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept // // If data is returned, convert Offsets in the Enum buffer to pointers. // if ((status == NO_ERROR) || (status == ERROR_MORE_DATA)) { if ((*lpServicesReturned) > 0) { #ifdef _WIN64 DWORD dwError; if (!ScConvertOffsets64(SC_API_ENUM_PROCESS_A, hSCManager, dwServiceType, dwServiceState, (LPBYTE) lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, &dwOldResumeIndex, (LPVOID) pszGroupName, &dwError)) { status = dwError; if (lpResumeIndex != NULL) { *lpResumeIndex = dwOldResumeIndex; } } #else // ndef _WIN64 ScConvertOffsetsExA((LPENUM_SERVICE_STATUS_PROCESSA) lpServices, *lpServicesReturned); #endif // _WIN64 } #ifdef _WIN64 // // The byte count returned is the size needed to hold all of // the 32-bit structures rather than the 64-bit ones. Assume // a buffer full of fixed-length structures (i.e., no variable- // length data) and scale from 32- to 64-bit sizes to get the // minimum guaranteed size for all the 64-bit structures. // *pcbBytesNeeded = *pcbBytesNeeded * sizeof(ENUM_SERVICE_STATUS_PROCESSA) / sizeof(ENUM_SERVICE_STATUS_PROCESS_WOW64); #endif // _WIN64 } if (status != NO_ERROR) { SetLastError(status); return FALSE; } return TRUE; } BOOL WINAPI QueryServiceObjectSecurity( IN SC_HANDLE hService, IN SECURITY_INFORMATION dwSecurityInformation, OUT PSECURITY_DESCRIPTOR lpSecurityDescriptor, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded ) /*++ Routine Description: This is the DLL entrypoint for the QueryServiceObjectSecurity API. This function returns to the caller requested security information currently assigned to an object. Based on the caller's access rights this procedure will return a security descriptor containing any or all of the object's owner ID, group ID, discretionary ACL or system ACL. To read the owner ID, group ID, or the discretionary ACL the caller must be granted READ_CONTROL access to the object. To read the system ACL the caller must be granted ACCESS_SYSTEM_SECURITY access. Arguments: hService - Supplies a handle to an existing service object. dwSecurityInformation - Supplies a value describing which pieces of security information are being queried. lpSecurityInformation - Supplies the output buffer from the user which security descriptor information will be written to on return. cbBufSize - Supplies the size of lpSecurityInformation buffer. pcbBytesNeeded - Returns the number of bytes needed of the lpSecurityInformation buffer to get all the requested information. Return Value: NO_ERROR - The operation was successful. ERROR_INVALID_HANDLE - The specified handle was invalid. ERROR_ACCESS_DENIED - The specified handle was not opened for either READ_CONTROL or ACCESS_SYSTEM_SECURITY access. ERROR_INVALID_PARAMETER - The dwSecurityInformation parameter is invalid. ERROR_INSUFFICIENT_BUFFER - The specified output buffer is smaller than the required size returned in pcbBytesNeeded. None of the security descriptor is returned. --*/ { DWORD status; RpcTryExcept { status = RQueryServiceObjectSecurity( (SC_RPC_HANDLE) hService, (DWORD) dwSecurityInformation, (LPBYTE) lpSecurityDescriptor, cbBufSize, pcbBytesNeeded ); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI SetServiceObjectSecurity( IN SC_HANDLE hService, IN SECURITY_INFORMATION dwSecurityInformation, IN PSECURITY_DESCRIPTOR lpSecurityDescriptor ) /*++ Routine Description: This is the DLL entrypoint for the SetServiceObjectSecurity API. This function takes a well-formed Security Descriptor provided by the caller and assigns specified portions of it to an existing service object. Based on the flags set in the SecurityInformation parameter and the caller's access rights, this procedure will replace any or all of the security information associated with an object. This is the only function available to users and applications for changing security information, including the owner ID, group ID, and the discretionary and system ACLs of an object. The caller must have WRITE_OWNER access to the object to change the owner or primary group of the object. The caller must have WRITE_DAC access to the object to change the discretionary ACL. The caller must have ACCESS_SYSTEM_SECURITY access to an object to assign a system ACL to the object. Parameters: hService - Supplies a handle to an existing service object. dwSecurityInformation - Supplies a value describing which pieces of security information are being set. lpSecurityInformation - Supplies a pointer to a well-formed security descriptor. Return Values: NO_ERROR - The operation was successful. ERROR_INVALID_HANDLE - The specified handle was invalid. ERROR_ACCESS_DENIED - The specified handle was not opened for either WRITE_OWNER, WRITE_DAC, or ACCESS_SYSTEM_SECURITY access. ERROR_INVALID_PARAMETER - The lpSecurityDescriptor or dwSecurityInformation parameter is invalid. ERROR_NOT_ENOUGH_MEMORY - Not enough memory to complete the API call. --*/ { DWORD status; NTSTATUS ntstatus; DWORD UserSdSize = 0; PSECURITY_DESCRIPTOR SelfRelativeSd; // // Find out the length of the user supplied security descriptor // ntstatus = RtlMakeSelfRelativeSD( lpSecurityDescriptor, NULL, &UserSdSize ); if (ntstatus != STATUS_BUFFER_TOO_SMALL) { // // lpSecurityDescriptor is invalid // SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); } SelfRelativeSd = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_ZEROINIT, (UINT) UserSdSize); if (SelfRelativeSd == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(FALSE); } // // Make a self-relative security descriptor for the RPC call // ntstatus = RtlMakeSelfRelativeSD( lpSecurityDescriptor, SelfRelativeSd, &UserSdSize ); if (! NT_SUCCESS(ntstatus)) { LocalFree(SelfRelativeSd); SetLastError(RtlNtStatusToDosError(ntstatus)); return(FALSE); } // // Call the server // RpcTryExcept { status = RSetServiceObjectSecurity( (SC_RPC_HANDLE) hService, (DWORD) dwSecurityInformation, (LPBYTE) SelfRelativeSd, UserSdSize ); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept (void) LocalFree(SelfRelativeSd); if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } VOID ScConvertOffsetsW( LPENUM_SERVICE_STATUSW lpServices, DWORD NumStructs ) /*++ Routine Description: Arguments: Return Value: --*/ { LPBYTE pBuffer; DWORD i; pBuffer = (LPBYTE)lpServices; for (i=0; idwDisplayNameOffset; dwCurrentVarData = cbBufSize - dwOffset - dwTotalVarData; // // Is there room to expand the current record to 64-bit pointers? // if (dwSize64 + dwStrucSize64 + dwCurrentVarData > cbBufSize) { // // Nope. // break; } // // Update the total number of variable-length data bytes // in the post-conversion buffer // dwTotalVarData += dwCurrentVarData; dwSize64 += dwStrucSize64 + dwCurrentVarData; } // // Set up the pointer to the last soon-to-be-converted structure. // Cast to INT to sign-extend the offset to 64 bits (required // when (dwCount64 == 0) or else the sum gets bizarre). // lpIter = lpServices + (INT) (dwStrucSizeWOW * (dwCount64 - 1)); lpConverted = lpServices + (INT) (dwStrucSize64 * (dwCount64 - 1)); for ( ; lpIter >= lpServices; lpIter -= dwStrucSizeWOW, lpConverted -= dwStrucSize64) { LPENUM_SERVICE_STATUSW lpEnum = (LPENUM_SERVICE_STATUSW) lpConverted; LPENUM_SERVICE_STATUS_WOW64 lpEnumWOW = (LPENUM_SERVICE_STATUS_WOW64) lpIter; // // Copy fields individually in reverse order in case there's overlap // RtlMoveMemory(&lpEnum->ServiceStatus, &lpEnumWOW->ServiceStatus, dwStatusSize); // // Do the offset-to-pointer conversion. Can do straight addition // since we didn't move the variable length data. // lpEnum->lpDisplayName = (LPWSTR) (lpServices + lpEnumWOW->dwDisplayNameOffset); lpEnum->lpServiceName = (LPWSTR) (lpServices + lpEnumWOW->dwServiceNameOffset); } ASSERT(lpIter < lpServices && lpConverted < lpServices); if (*lpServicesReturned != dwCount64) { // // Not enough room to fit all the records returned. Update // all the OUT parameters. Add on the size of the overwritten // records' variable-length data first. // *pcbBytesNeeded += (cbBufSize - dwTotalVarData - *lpServicesReturned * dwStrucSizeWOW); // // And now do the fixed-length data. Use the 32-bit structures // and the caller will multiply it up to 64-bit lengths. // *pcbBytesNeeded += (*lpServicesReturned - dwCount64) * dwStrucSizeWOW; // // Update the count of services returned // *lpServicesReturned = dwCount64; if (scApi == SC_API_ENUM_DEPEND_W || scApi == SC_API_ENUM_DEPEND_A) { *lpdwError = ERROR_MORE_DATA; return FALSE; } // // And now things get ugly. We need to update the resume index // since we removed some services from the buffer. However, // there's no easy way to get the resume index of a particular // service from the server side. So we have to build up an // enum buffer that's just small enough to hold only the records // we're going to return and enum again just to get the RI. // LPBYTE lpTemp; DWORD status; DWORD dwTempBytes; DWORD dwTempCount; DWORD dwTempSize = dwCount64 * dwStrucSizeWOW + dwTotalVarData; lpTemp = (LPBYTE) LocalAlloc(LMEM_FIXED, dwTempSize); if (lpTemp == NULL) { *lpdwError = ERROR_NOT_ENOUGH_MEMORY; return FALSE; } RpcTryExcept { switch (scApi) { case SC_API_ENUM_W: status = REnumServicesStatusW ( (SC_RPC_HANDLE) hSCManager, dwServiceType, dwServiceState, (LPBYTE) lpTemp, dwTempSize, &dwTempBytes, &dwTempCount, lpResumeIndex); break; case SC_API_ENUM_A: status = REnumServicesStatusA ( (SC_RPC_HANDLE) hSCManager, dwServiceType, dwServiceState, (LPBYTE) lpTemp, dwTempSize, &dwTempBytes, &dwTempCount, lpResumeIndex); break; case SC_API_ENUM_GROUP: status = REnumServiceGroupW ( (SC_RPC_HANDLE) hSCManager, dwServiceType, dwServiceState, (LPBYTE) lpTemp, dwTempSize, &dwTempBytes, &dwTempCount, lpResumeIndex, (LPCWSTR) pszGroupName); break; case SC_API_ENUM_PROCESS_W: status = REnumServicesStatusExW ( hSCManager, SC_ENUM_PROCESS_INFO, dwServiceType, dwServiceState, (LPBYTE) lpTemp, dwTempSize, &dwTempBytes, &dwTempCount, lpResumeIndex, (LPCWSTR) pszGroupName); break; case SC_API_ENUM_PROCESS_A: status = REnumServicesStatusExA ( hSCManager, SC_ENUM_PROCESS_INFO, dwServiceType, dwServiceState, (LPBYTE) lpTemp, dwTempSize, &dwTempBytes, &dwTempCount, lpResumeIndex, (LPCSTR) pszGroupName); break; default: ASSERT(FALSE && "Unsupported API in ScConvertOffsets64 enum path"); status = ERROR_NOT_SUPPORTED; } } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept LocalFree(lpTemp); // // We had to overwrite at least one structure so we need // to return some form of error, even if it's ERROR_MORE_DATA. // *lpdwError = status; return FALSE; } return TRUE; break; } case SC_API_QUERY_DESCRIPTION_W: case SC_API_QUERY_DESCRIPTION_A: { DWORD dwBytesNeeded = *pcbBytesNeeded; DWORD dwSizeDiff = sizeof(SERVICE_DESCRIPTIONW) - sizeof(SERVICE_DESCRIPTION_WOW64); LPSERVICE_DESCRIPTION_WOW64 psdWOW = (LPSERVICE_DESCRIPTION_WOW64) lpServices; LPSERVICE_DESCRIPTIONW psd = (LPSERVICE_DESCRIPTIONW) lpServices; // // *pcbBytesNeeded is filled in on success or "buffer too small" // failure, so update it with the 64-bit size. // *pcbBytesNeeded += dwSizeDiff; if (*pcbBytesNeeded > cbBufSize) { return FALSE; } // // We have room -- move the variable-length data // RtlMoveMemory(psd + 1, psdWOW + 1, dwBytesNeeded - sizeof(SERVICE_DESCRIPTION_WOW64)); // // Resize the offset from 4 to 8 bytes. // if (psdWOW->dwDescriptionOffset == 0) { psd->lpDescription = NULL; } else { psd->lpDescription = (LPWSTR) UlongToPtr(psdWOW->dwDescriptionOffset + dwSizeDiff); } return TRUE; } case SC_API_QUERY_FAILURE_ACTIONS_W: case SC_API_QUERY_FAILURE_ACTIONS_A: { DWORD dwBytesNeeded = *pcbBytesNeeded; DWORD dwSizeDiff = sizeof(SERVICE_FAILURE_ACTIONSW) - sizeof(SERVICE_FAILURE_ACTIONS_WOW64); LPSERVICE_FAILURE_ACTIONS_WOW64 psfaWOW = (LPSERVICE_FAILURE_ACTIONS_WOW64) lpServices; LPSERVICE_FAILURE_ACTIONSW psfa = (LPSERVICE_FAILURE_ACTIONSW) lpServices; // // *pcbBytesNeeded is filled in on success or "buffer too small" // failure, so update it with the 64-bit size. // *pcbBytesNeeded += dwSizeDiff; if (*pcbBytesNeeded > cbBufSize) { return FALSE; } // // We have room -- move the variable-length data // RtlMoveMemory(psfa + 1, psfaWOW + 1, dwBytesNeeded - sizeof(SERVICE_FAILURE_ACTIONS_WOW64)); // // Resize the offsets from 4 to 8 bytes. Do this in reverse field order // to avoid trampling over any still-to-be-converted offsets. // if (psfaWOW->dwsaActionsOffset == 0) { psfa->lpsaActions = NULL; } else { psfa->lpsaActions = (SC_ACTION *) UlongToPtr(psfaWOW->dwsaActionsOffset + dwSizeDiff); } psfa->cActions = psfaWOW->cActions; if (psfaWOW->dwCommandOffset == 0) { psfa->lpCommand = NULL; } else { psfa->lpCommand = (LPWSTR) UlongToPtr(psfaWOW->dwCommandOffset + dwSizeDiff); } if (psfaWOW->dwRebootMsgOffset == 0) { psfa->lpRebootMsg = NULL; } else { psfa->lpRebootMsg = (LPWSTR) UlongToPtr(psfaWOW->dwRebootMsgOffset + dwSizeDiff); } psfa->dwResetPeriod = psfaWOW->dwResetPeriod; return TRUE; } default: ASSERT(FALSE && "Unsupported API passed to ScConvertOffsets64"); *lpdwError = ERROR_NOT_SUPPORTED; return FALSE; } } #endif // _WIN64 BOOL WINAPI ChangeServiceConfigA( IN SC_HANDLE hService, IN DWORD dwServiceType, IN DWORD dwStartType, IN DWORD dwErrorControl, IN LPCSTR lpBinaryPathName, IN LPCSTR lpLoadOrderGroup, OUT LPDWORD lpdwTagId, IN LPCSTR lpDependencies, IN LPCSTR lpServiceStartName, IN LPCSTR lpPassword, IN LPCSTR lpDisplayName ) /*++ Routine Description: This is the DLL entry point for the ChangeServiceConfig function. ChangeServiceConfig changes the service configuration kept in the Service Control Manager database. This configuration information was first set in the database via the CreateService API, and can be queried (exept for the password parameter) using the QueryServiceConfig API. Arguments: hService - Handle obtained from a previous OpenService call. dwServiceType - Value to indicate the type of service this is. dwStartType - Value to specify when to start the service. dwErrorControl - Value to specify the severity of the error if this service fails to start during boot so that the appropriate action can be taken. lpBinaryPathName - Fully-qualified path name to the service binary file. lpLoadOrderGroup - Name of the load ordering group which this service is a member of. Groups of services are started based on the group order list specified in the registry at HKEY_LOCAL_SYSTEM\Control\Service_Group_Order. lpdwTagId - On output this pointer receives a unique tag identification number within the group. If this parameter is specified (non-NULL) but lpLoadOrderGroup is not specified, ERROR_INVALID_PARAMETER will be returned. lpDependencies - NULL-separated names of services which must be running before this service can run. An empty string means that this service has no dependencies. lpServiceStartName - If service type is SERVICE_WIN32, this name is the account name in the form of "DomainName\Username" which the service process will be logged on as when it runs. If service type is SERVICE_DRIVER, this name must be the NT driver object name (e.g. \FileSystem\LanManRedirector or \Driver\Xns) which the I/O system uses to load the device driver. lpPassword - Password to the account name specified by lpServiceStartName if service type is SERVICE_WIN32. This password will be changed periodically by the Service Control Manager so that it will not expire. If service type is SERVICE_DRIVER, this parameter is ignored. lpDisplayName - This is the internationalized name that is used for display purposes only. Return Value: Note: --*/ { DWORD status; LPWSTR lpPasswordW; LPBYTE EncryptedPassword = NULL; DWORD PasswordSize = 0; LPSTR Ptr; LPWSTR DependBuffer = NULL; DWORD DependSize = 0; RpcTryExcept { // // Create a unicode version of lpPassword, and then encrypt it. // if (ARGUMENT_PRESENT(lpPassword)) { if (! ScConvertToUnicode(&lpPasswordW, lpPassword)) { SCC_LOG0(ERROR,"ChangeServiceConfigA: convert password to Unicode failed\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(FALSE); } status = ScEncryptPassword( (SC_RPC_HANDLE)hService, lpPasswordW, &EncryptedPassword, &PasswordSize ); (void) LocalFree(lpPasswordW); if (status != NO_ERROR) { SCC_LOG0(ERROR,"ChangeServiceConfigA: ScEncryptPassword failed\n"); SetLastError(status); return(FALSE); } } if (ARGUMENT_PRESENT(lpDependencies)) { DependSize = ScAStrArraySize((LPSTR) lpDependencies) / sizeof(CHAR) * sizeof(WCHAR); if ((DependBuffer = (LPWSTR)LocalAlloc( LMEM_ZEROINIT, (UINT) DependSize)) == NULL) { SCC_LOG1(ERROR, "ChangeServiceConfigA: LocalAlloc of DependBuffer failed " FORMAT_DWORD "\n", GetLastError()); status = ERROR_NOT_ENOUGH_MEMORY; } if (DependSize > sizeof(WCHAR)) { // // There is at least one dependency entry. // Ptr = (LPSTR) lpDependencies; // // Convert each dependency into Unicode, and append it to the // DependBuffer. // while (*Ptr != 0) { LPWSTR ConvertedDependency = NULL; if (! ScConvertToUnicode(&ConvertedDependency, Ptr)) { SCC_LOG0(ERROR, "ChangeServiceConfigA: convert dependency to Unicode failed\n"); status = ERROR_NOT_ENOUGH_MEMORY; goto CleanExit; } ScAddWStrToWStrArray(DependBuffer, ConvertedDependency); (void) LocalFree(ConvertedDependency); Ptr = ScNextAStrArrayEntry(Ptr); } } } status = RChangeServiceConfigA( (SC_RPC_HANDLE)hService, dwServiceType, dwStartType, dwErrorControl, (LPSTR) lpBinaryPathName, (LPSTR) lpLoadOrderGroup, lpdwTagId, (LPBYTE) DependBuffer, DependSize, (LPSTR) lpServiceStartName, EncryptedPassword, PasswordSize, (LPSTR)lpDisplayName); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept CleanExit: if (EncryptedPassword != NULL) { (void) LocalFree(EncryptedPassword); } if (DependBuffer != NULL) { (void) LocalFree(DependBuffer); } if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI ChangeServiceConfigW( IN SC_HANDLE hService, IN DWORD dwServiceType, IN DWORD dwStartType, IN DWORD dwErrorControl, IN LPCWSTR lpBinaryPathName, IN LPCWSTR lpLoadOrderGroup, OUT LPDWORD lpdwTagId, IN LPCWSTR lpDependencies, IN LPCWSTR lpServiceStartName, IN LPCWSTR lpPassword, IN LPCWSTR lpDisplayName ) /*++ Routine Description: see ChangeServiceConfigA Arguments: Return Value: Note: --*/ { DWORD status; LPBYTE EncryptedPassword = NULL; DWORD PasswordSize = 0; DWORD DependSize = 0; RpcTryExcept { // // Create a unicode version of lpPassword, and then encrypt it. // if (ARGUMENT_PRESENT(lpPassword)) { status = ScEncryptPassword( (SC_RPC_HANDLE)hService, (LPWSTR) lpPassword, &EncryptedPassword, &PasswordSize ); if (status != NO_ERROR) { SCC_LOG0(ERROR,"ChangeServiceConfigW: ScEncryptPassword failed\n"); SetLastError(status); return(FALSE); } } if (ARGUMENT_PRESENT(lpDependencies)) { DependSize = ScWStrArraySize((LPWSTR) lpDependencies); } status = RChangeServiceConfigW( (SC_RPC_HANDLE)hService, dwServiceType, dwStartType, dwErrorControl, (LPWSTR) lpBinaryPathName, (LPWSTR) lpLoadOrderGroup, lpdwTagId, (LPBYTE) lpDependencies, DependSize, (LPWSTR) lpServiceStartName, EncryptedPassword, PasswordSize, (LPWSTR)lpDisplayName); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (EncryptedPassword != NULL) { (void) LocalFree(EncryptedPassword); } if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI ChangeServiceConfig2A( IN SC_HANDLE hService, IN DWORD dwInfoLevel, IN LPVOID lpInfo ) /*++ Routine Description: Arguments: Return Value: Note: --*/ { DWORD status; // Transform the parameters into a union that RPC likes SC_RPC_CONFIG_INFOA RpcInfo = { dwInfoLevel, (LPSERVICE_DESCRIPTIONA) lpInfo }; RpcTryExcept { status = RChangeServiceConfig2A( (SC_RPC_HANDLE) hService, RpcInfo ); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status == RPC_S_INVALID_TAG) { status = ERROR_INVALID_LEVEL; } if (status != NO_ERROR) { SetLastError(status); return FALSE; } return TRUE; } BOOL WINAPI ChangeServiceConfig2W( IN SC_HANDLE hService, IN DWORD dwInfoLevel, IN LPVOID lpInfo ) /*++ Routine Description: Arguments: Return Value: Note: --*/ { DWORD status; // Transform the parameters into a union that RPC likes SC_RPC_CONFIG_INFOW RpcInfo = { dwInfoLevel, (LPSERVICE_DESCRIPTIONW) lpInfo }; RpcTryExcept { status = RChangeServiceConfig2W( (SC_RPC_HANDLE) hService, RpcInfo ); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status == RPC_S_INVALID_TAG) { status = ERROR_INVALID_LEVEL; } if (status != NO_ERROR) { SetLastError(status); return FALSE; } return TRUE; } SC_HANDLE WINAPI CreateServiceA( IN SC_HANDLE hSCManager, IN LPCSTR lpServiceName, IN LPCSTR lpDisplayName, IN DWORD dwDesiredAccess, IN DWORD dwServiceType, IN DWORD dwStartType, IN DWORD dwErrorControl, IN LPCSTR lpBinaryPathName, IN LPCSTR lpLoadOrderGroup, OUT LPDWORD lpdwTagId, IN LPCSTR lpDependencies, IN LPCSTR lpServiceStartName, IN LPCSTR lpPassword ) /*++ Routine Description: This function is the DLL entry point for the ansi version of CreateService. On the server side, this function will create a service object and add it to the Service Control Manager database. Arguments: hSCManager - Handle obtained from a previous OpenSCManager call. lpServiceName - Name of the service to install. lpDisplayName - This is the internationalized name that is used for display purposes only. dwDesiredAccess - Access types desired to access the service. dwServiceType - Value to indicate the type of service this is. dwStartType - Value to specify when to start the service. dwErrorControl - Value to specify the severity of the error if this service fails to start during boot so that the appropriate action can be taken. lpBinaryPathName - Fully-qualified path name to the service binary file. lpLoadOrderGroup - Name of the load ordering group which this service is a member of. Groups of services are started based on the group order list specified in the registry at HKEY_LOCAL_SYSTEM\Control\Service_Group_Order. lpdwTagId - On output this pointer receives a unique tag identification number within the group. If this parameter is specified (non-NULL) but lpLoadOrderGroup is not specified, ERROR_INVALID_PARAMETER will be returned. lpDependencies - Space-separated names of services which must be running before this service can run. An empty string means that this service has no dependencies. lpServiceStartName - If service type is SERVICE_WIN32, this name is the account name in the form of "DomainName\Username" which the service process will be logged on as when it runs. If service type is SERVICE_DRIVER, this name must be the NT driver object name (e.g. \FileSystem\LanManRedirector or \Driver\Xns) which the I/O system uses to load the device driver. lpPassword - Password to the account name specified by lpServiceStartName if service type is SERVICE_WIN32. This password will be changed periodically by the Service Control Manager so that it will not expire. If service type is SERVICE_DRIVER, this parameter is ignored. Return Value: Note: --*/ { DWORD status; SC_RPC_HANDLE hService=NULL; LPWSTR lpPasswordW; LPBYTE EncryptedPassword = NULL; DWORD PasswordSize = 0; LPSTR Ptr; LPWSTR DependBuffer = NULL; DWORD DependSize = 0; RpcTryExcept { // // Create a unicode version of lpPassword, and then encrypt it. // if (ARGUMENT_PRESENT(lpPassword)) { if (! ScConvertToUnicode(&lpPasswordW, lpPassword)) { SCC_LOG0(ERROR,"CreateServiceA: convert password to Unicode failed\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return(NULL); } status = ScEncryptPassword( (SC_RPC_HANDLE)hSCManager, lpPasswordW, &EncryptedPassword, &PasswordSize ); (void) LocalFree(lpPasswordW); if (status != NO_ERROR) { SCC_LOG0(ERROR,"CreateServiceA: ScEncryptPassword failed\n"); SetLastError(status); return(NULL); } } if (ARGUMENT_PRESENT(lpDependencies)) { DependSize = ScAStrArraySize((LPSTR) lpDependencies) / sizeof(CHAR) * sizeof(WCHAR); if ((DependBuffer = (LPWSTR)LocalAlloc( LMEM_ZEROINIT, (UINT) DependSize)) == NULL) { SCC_LOG1(ERROR, "CreateServiceA: LocalAlloc of DependBuffer failed " FORMAT_DWORD "\n", GetLastError()); status = ERROR_NOT_ENOUGH_MEMORY; goto CleanExit; } if (DependSize > sizeof(WCHAR)) { // // There is at least one dependency entry. // Ptr = (LPSTR) lpDependencies; // // Convert each dependency into Unicode, and append it to the // DependBuffer. // while (*Ptr != 0) { LPWSTR ConvertedDependency = NULL; if (! ScConvertToUnicode(&ConvertedDependency, Ptr)) { SCC_LOG0(ERROR, "CreateServiceA: convert dependency to Unicode failed\n"); status = ERROR_NOT_ENOUGH_MEMORY; goto CleanExit; } ScAddWStrToWStrArray(DependBuffer, ConvertedDependency); (void) LocalFree(ConvertedDependency); Ptr = ScNextAStrArrayEntry(Ptr); } } } status = RCreateServiceA ( (SC_RPC_HANDLE)hSCManager, (LPSTR) lpServiceName, (LPSTR) lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, (LPSTR) lpBinaryPathName, (LPSTR) lpLoadOrderGroup, lpdwTagId, (LPBYTE) DependBuffer, DependSize, (LPSTR) lpServiceStartName, EncryptedPassword, PasswordSize, &hService); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept CleanExit: if (DependBuffer != NULL) { (void) LocalFree(DependBuffer); } if (EncryptedPassword != NULL) { (void) LocalFree(EncryptedPassword); } if (status != NO_ERROR){ SetLastError(status); return(NULL); } return (SC_HANDLE)hService; } SC_HANDLE WINAPI CreateServiceW( IN SC_HANDLE hSCManager, IN LPCWSTR lpServiceName, IN LPCWSTR lpDisplayName, IN DWORD dwDesiredAccess, IN DWORD dwServiceType, IN DWORD dwStartType, IN DWORD dwErrorControl, IN LPCWSTR lpBinaryPathName, IN LPCWSTR lpLoadOrderGroup, OUT LPDWORD lpdwTagId, IN LPCWSTR lpDependencies, IN LPCWSTR lpServiceStartName, IN LPCWSTR lpPassword ) /*++ Routine Description: see CreateServiceA Arguments: Return Value: Note: --*/ { DWORD status; SC_RPC_HANDLE hService = NULL; LPBYTE EncryptedPassword = NULL; DWORD PasswordSize = 0; DWORD DependSize = 0; RpcTryExcept { if (ARGUMENT_PRESENT(lpPassword)) { status = ScEncryptPassword( (SC_RPC_HANDLE)hSCManager, (LPWSTR) lpPassword, &EncryptedPassword, &PasswordSize ); if (status != NO_ERROR) { SCC_LOG0(ERROR,"CreateServiceW: ScEncryptPassword failed\n"); SetLastError(status); return NULL; } } if (ARGUMENT_PRESENT(lpDependencies)) { DependSize = ScWStrArraySize((LPWSTR) lpDependencies); } status = RCreateServiceW ( (SC_RPC_HANDLE)hSCManager, (LPWSTR) lpServiceName, (LPWSTR) lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl, (LPWSTR) lpBinaryPathName, (LPWSTR) lpLoadOrderGroup, lpdwTagId, (LPBYTE) lpDependencies, DependSize, (LPWSTR) lpServiceStartName, EncryptedPassword, PasswordSize, &hService); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (EncryptedPassword != NULL) { LocalFree(EncryptedPassword); } if (status != NO_ERROR){ SetLastError(status); return NULL; } return (SC_HANDLE)hService; } BOOL WINAPI DeleteService( IN SC_HANDLE hService ) /*++ Routine Description: This is the DLL entry point for the DeleteService function. DeleteService removes the service from the Service Control Manager's database. Arguments: hService - Handle obtained from a previous CreateService or OpenService call. Return Value: Note: --*/ { DWORD status; SCC_LOG1(TRACE, "---------DeleteService called (%ws)\n", GetCommandLineW()); RpcTryExcept { status = RDeleteService ((SC_RPC_HANDLE)hService); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SCC_LOG2(TRACE, "---------DeleteService FAILED, %ld (%ws)\n", status, GetCommandLineW()); SetLastError(status); return(FALSE); } SCC_LOG1(TRACE, "---------DeleteService SUCCESS (%ws)\n", GetCommandLineW()); return TRUE; } BOOL WINAPI EnumDependentServicesA( IN SC_HANDLE hService, IN DWORD dwServiceState, OUT LPENUM_SERVICE_STATUSA lpServices, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded, OUT LPDWORD lpServicesReturned ) /*++ Routine Description: This function lists the services which depend on the specified service to be running before they can run. The returned services entries are ordered in the reverse order of start dependencies with group order taken into account. Services can be stopped in the proper order based on the order of entries written to the output buffer. Arguments: hService - Handle obtained from a previous OpenService call. dwServiceState - Value to select the services to enumerate based on the running state. lpServices - A pointer to a buffer to receive an array of service entries; each entry is the ENUM_SERVICE_STATUS information structure. The services returned in the buffer is ordered by the reverse dependency order. cbBufSize - Size of the buffer in bytes pointed to by lpServices. pcbBytesNeeded - A pointer to a variable to receive the number of bytes needed to fit the remaining service entries. lpServicesReturned - A pointer to a variable to receive the number of service entries returned. Return Value: TRUE - if all Services are successfully written into the supplied output buffer. FALSE - If an error has occured - Use GetLastError to determine the cause of the failure. --*/ { DWORD status; LPENUM_SERVICE_STATUSA pEnumBuf; ENUM_SERVICE_STATUSA enumBuf; DWORD tempBufSize; tempBufSize = cbBufSize; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // if (cbBufSize < sizeof(ENUM_SERVICE_STATUSA) || (lpServices == NULL)) { pEnumBuf = &enumBuf; tempBufSize = sizeof(ENUM_SERVICE_STATUSA); } else { pEnumBuf = lpServices; } RpcTryExcept { status = REnumDependentServicesA( (SC_RPC_HANDLE)hService, dwServiceState, (LPBYTE)pEnumBuf, tempBufSize, pcbBytesNeeded, lpServicesReturned); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept // // If data is returned, convert Offsets in the Enum buffer to pointers. // if ((status == NO_ERROR) || (status == ERROR_MORE_DATA)) { if ((*lpServicesReturned) > 0) { #ifdef _WIN64 DWORD dwError; if (!ScConvertOffsets64(SC_API_ENUM_DEPEND_A, NULL, // no hSCManager 0, // no service type 0, // no service state (LPBYTE) lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, NULL, // no old resume index NULL, // no group name &dwError)) { status = dwError; } } // // Scale required size up to the minimum size guaranteed to // succeed with 64-bit structures. // *pcbBytesNeeded = *pcbBytesNeeded * sizeof(ENUM_SERVICE_STATUSA) / sizeof(ENUM_SERVICE_STATUS_WOW64); #else // ndef _WIN64 ScConvertOffsetsA(lpServices, *lpServicesReturned); } #endif // _WIN64 } if (status != NO_ERROR) { SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI EnumDependentServicesW( IN SC_HANDLE hService, IN DWORD dwServiceState, OUT LPENUM_SERVICE_STATUSW lpServices, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded, OUT LPDWORD lpServicesReturned ) /*++ Routine Description: This function lists the services which depend on the specified service to be running before they can run. The returned services entries are ordered in the reverse order of start dependencies with group order taken into account. Services can be stopped in the proper order based on the order of entries written to the output buffer. Arguments: hService - Handle obtained from a previous OpenService call. dwServiceState - Value to select the services to enumerate based on the running state. lpServices - A pointer to a buffer to receive an array of service entries; each entry is the ENUM_SERVICE_STATUS information structure. The services returned in the buffer is ordered by the reverse dependency order. cbBufSize - Size of the buffer in bytes pointed to by lpServices. pcbBytesNeeded - A pointer to a variable to receive the number of bytes needed to fit the remaining service entries. lpServicesReturned - A pointer to a variable to receive the number of service entries returned. Return Value: TRUE - if all Services are successfully written into the supplied output buffer. FALSE - If an error has occured - Use GetLastError to determine the cause of the failure. --*/ { DWORD status; LPENUM_SERVICE_STATUSW pEnumBuf; ENUM_SERVICE_STATUSW enumBuf; DWORD tempBufSize; tempBufSize = cbBufSize; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // if (cbBufSize < sizeof(ENUM_SERVICE_STATUSW) || (lpServices == NULL)) { pEnumBuf = &enumBuf; tempBufSize = sizeof(ENUM_SERVICE_STATUSW); } else { pEnumBuf = lpServices; } RpcTryExcept { status = REnumDependentServicesW( (SC_RPC_HANDLE)hService, dwServiceState, (LPBYTE)pEnumBuf, tempBufSize, pcbBytesNeeded, lpServicesReturned); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept // // If data is returned, convert Offsets in the Enum buffer to pointers. // if ((status == NO_ERROR) || (status == ERROR_MORE_DATA)) { if ((*lpServicesReturned) > 0) { #ifdef _WIN64 DWORD dwError; if (!ScConvertOffsets64(SC_API_ENUM_DEPEND_W, NULL, // no hSCManager 0, // no service type 0, // no service state (LPBYTE) lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned, NULL, // no old resume index NULL, // no group name &dwError)) { status = dwError; } } // // Scale required size up to the minimum size guaranteed to // succeed with 64-bit structures. // *pcbBytesNeeded = *pcbBytesNeeded * sizeof(ENUM_SERVICE_STATUSA) / sizeof(ENUM_SERVICE_STATUS_WOW64); #else // ndef _WIN64 ScConvertOffsetsW(lpServices, *lpServicesReturned); } #endif // _WIN64 } if (status != NO_ERROR) { SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName, LPSTR lpDisplayName, LPDWORD lpcchBuffer ) /*++ Routine Description: This function returns the display name for a service that is identified by its key name (ServiceName). Arguments: hSCManager - This is the handle to the Service Controller Manager that is expected to return the display name. lpServiceName - This is the ServiceName (which is actually a key name) that identifies the service. lpDisplayName - This is a pointer to a buffer that is to receive the DisplayName string. lpcchBuffer - This is a pointer to the size (in characters) of the buffer that is to receive the DisplayName string. If the buffer is not large enough to receive the entire string, then the required buffer size is returned in this location. (NOTE: Ansi Characters, including DBCS, are assumed to be 8 bits). Return Value: --*/ { DWORD status; LPSTR bufPtr; CHAR tempString[] = ""; // // Create a dummy buffer that is at least the size of a CHAR. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // RpcTryExcept { if ((*lpcchBuffer < sizeof(CHAR)) || (lpDisplayName == NULL)){ bufPtr = tempString; *lpcchBuffer = sizeof(CHAR); } else { bufPtr = (LPSTR)lpDisplayName; } status = RGetServiceDisplayNameA( (SC_RPC_HANDLE)hSCManager, (LPSTR)lpServiceName, bufPtr, lpcchBuffer); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR) { SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName, LPWSTR lpDisplayName, LPDWORD lpcchBuffer ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD status; LPWSTR bufPtr; WCHAR tempString[]=L""; // // Create a dummy buffer that is at least the size of a WCHAR. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // RpcTryExcept { if ((*lpcchBuffer < sizeof(WCHAR)) || (lpDisplayName == NULL)) { bufPtr = tempString; *lpcchBuffer = sizeof(WCHAR); } else { bufPtr = (LPWSTR)lpDisplayName; } status = RGetServiceDisplayNameW( (SC_RPC_HANDLE)hSCManager, (LPWSTR)lpServiceName, bufPtr, lpcchBuffer); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR) { SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName, LPSTR lpServiceName, LPDWORD lpcchBuffer ) /*++ Routine Description: Arguments: hSCManager - This is the handle to the Service Controller Manager that is expected to return the service name (key name). lpServiceName - This is the Service Display Name that identifies the service. lpServiceName - This is a pointer to a buffer that is to receive the Service Key Name string. lpcchBuffer - This is a pointer to the size of the buffer that is to receive the Service Key Name string. If the buffer is not large enough to receive the entire string, then the required buffer size is returned in this location. Return Value: --*/ { DWORD status; LPSTR bufPtr; CHAR tempString[]=""; // // Create a dummy buffer that is at least the size of a CHAR. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // RpcTryExcept { if ((*lpcchBuffer < sizeof(CHAR)) || (lpServiceName == NULL)) { bufPtr = tempString; *lpcchBuffer = sizeof(CHAR); } else { bufPtr = (LPSTR)lpServiceName; } status = RGetServiceKeyNameA( (SC_RPC_HANDLE)hSCManager, (LPSTR)lpDisplayName, bufPtr, lpcchBuffer); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR) { SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName, LPWSTR lpServiceName, LPDWORD lpcchBuffer ) /*++ Routine Description: Arguments: Return Value: --*/ { DWORD status = NO_ERROR; LPWSTR bufPtr; WCHAR tempString[]=L""; // // Create a dummy buffer that is at least the size of a WCHAR. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // RpcTryExcept { if ((*lpcchBuffer < sizeof(WCHAR)) || (lpServiceName == NULL)) { bufPtr = tempString; *lpcchBuffer = sizeof(WCHAR); } else { bufPtr = (LPWSTR)lpServiceName; } status = RGetServiceKeyNameW( (SC_RPC_HANDLE)hSCManager, (LPWSTR)lpDisplayName, bufPtr, lpcchBuffer); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR) { SetLastError(status); return(FALSE); } return(TRUE); } SC_LOCK WINAPI LockServiceDatabase( IN SC_HANDLE hSCManager ) /*++ Routine Description: This is the DLL entry point for the LockServiceDatabase function. This function acquires a lock on the database that was opened from a previous OpenSCManager call. There can only be one lock outstanding on a database for a given time. Arguments: hSCManager - Handle obtained from a previous OpenSCManager call which specifies the database to lock. Return Value: --*/ { DWORD status; SC_RPC_LOCK lock = NULL; RpcTryExcept { status = RLockServiceDatabase( (SC_RPC_HANDLE)hSCManager, &lock); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(NULL); } return((SC_LOCK)lock); } BOOL WINAPI QueryServiceConfigA( IN SC_HANDLE hService, OUT LPQUERY_SERVICE_CONFIGA lpServiceConfig, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded ) /*++ Routine Description: This is the DLL entry point for the QueryServiceConfig function. QueryServiceConfig obtains the service configuration information stored in the Service Control Manager database. This configuration information was first set in the database via the CreateService API, and may have been updated via the ChangeServiceConfig API. Arguments: hService - Handle obtained from a previous CreateService or OpenService call. lpServiceConfig - A pointer to a buffer to receive a QUERY_SERVICE_CONFIG information structure. cbBufSize - Size of the buffer in bytes pointed to by lpServiceConfig. pcbBytesNeeded - A pointer to a variable to receive the number of bytes needed to fit the entire QUERY_SERVICE_CONFIG information structure. Return Value: Note: --*/ { DWORD status; LPSTR pDepend; LPQUERY_SERVICE_CONFIGA pConfigBuf; QUERY_SERVICE_CONFIGA configBuf; DWORD tempBufSize; tempBufSize = cbBufSize; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // if (cbBufSize < sizeof(QUERY_SERVICE_CONFIGA)) { pConfigBuf = &configBuf; tempBufSize = sizeof(QUERY_SERVICE_CONFIGA); } else { pConfigBuf = lpServiceConfig; } RpcTryExcept { status = RQueryServiceConfigA( (SC_RPC_HANDLE)hService, pConfigBuf, tempBufSize, pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR) { #ifdef _WIN64 // // pcbBytesNeeded isn't filled in if the byte count is too // small (returned when the buffer size is large enough to // hold the 32-bit structure but too small to hold the // 64-bit structure. Get the necessary (32-bit) size. // if (status == RPC_X_BYTE_COUNT_TOO_SMALL) { RpcTryExcept { status = RQueryServiceConfigA( (SC_RPC_HANDLE)hService, pConfigBuf, sizeof(QUERY_SERVICE_CONFIGA), pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept } // // Since the ACF file specifies byte_count for this API, we're // responsible for managing the count of bytes needed by the // caller. For 64-bit clients calling 32-bit servers, the // returned buffer size is too small because of differing // pointer sizes. Add on the minimum number of bytes that // will guarantee enough space in the buffer for the next // call. // if (status == ERROR_INSUFFICIENT_BUFFER) { // // 5 embedded pointers in the structure and max // space required for alignment. // *pcbBytesNeeded += 5 * (sizeof(PVOID) - sizeof(ULONG) + sizeof(PVOID)); } #endif // _WIN64 SetLastError(status); return(FALSE); } else { // // Replace the '/' separator characters by NULLs. We used // separator characters in the double NULL terminated set of // strings so that RPC could treat it as a single string. // if ((pDepend = lpServiceConfig->lpDependencies) != NULL) { while (*pDepend != '\0') { if (*pDepend == '/') { *pDepend = '\0'; } pDepend++; } } } return(TRUE); } BOOL WINAPI QueryServiceConfigW( IN SC_HANDLE hService, OUT LPQUERY_SERVICE_CONFIGW lpServiceConfig, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded ) /*++ Routine Description: see QueryServiceConfigA Arguments: Return Value: Note: --*/ { DWORD status; LPWSTR pDepend; LPQUERY_SERVICE_CONFIGW pConfigBuf; QUERY_SERVICE_CONFIGW configBuf; DWORD tempBufSize; tempBufSize = cbBufSize; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // if (cbBufSize < sizeof(QUERY_SERVICE_CONFIGW)) { pConfigBuf = &configBuf; tempBufSize = sizeof(QUERY_SERVICE_CONFIGW); } else { pConfigBuf = lpServiceConfig; } RpcTryExcept { status = RQueryServiceConfigW( (SC_RPC_HANDLE)hService, pConfigBuf, tempBufSize, pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR) { #ifdef _WIN64 // // pcbBytesNeeded isn't filled in if the byte count is too // small (returned when the buffer size is large enough to // hold the 32-bit structure but too small to hold the // 64-bit structure. Get the necessary (32-bit) size. // if (status == RPC_X_BYTE_COUNT_TOO_SMALL) { RpcTryExcept { status = RQueryServiceConfigW( (SC_RPC_HANDLE)hService, pConfigBuf, sizeof(QUERY_SERVICE_CONFIGW), pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept } // // Since the ACF file specifies byte_count for this API, we're // responsible for managing the count of bytes needed by the // caller. For 64-bit clients calling 32-bit servers, the // returned buffer size is too small because of differing // pointer sizes. Add on the minimum number of bytes that // will guarantee enough space in the buffer for the next // call. // if (status == ERROR_INSUFFICIENT_BUFFER) { // // 5 embedded pointers in the structure and max // space required for alignment. // *pcbBytesNeeded += 5 * (sizeof(PVOID) - sizeof(ULONG) + sizeof(PVOID)); } #endif // _WIN64 SetLastError(status); return(FALSE); } else { // // Replace the '/' separator characters by NULLs. We used // separator characters in the double NULL terminated set of // strings so that RPC could treat it as a single string. // if ((pDepend = lpServiceConfig->lpDependencies) != NULL) { while (*pDepend != L'\0') { if (*pDepend == L'/') { *pDepend = L'\0'; } pDepend++; } } } return(TRUE); } BOOL WINAPI QueryServiceConfig2A( IN SC_HANDLE hService, IN DWORD dwInfoLevel, OUT LPBYTE lpBuffer, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded ) /*++ Routine Description: Arguments: Return Value: Note: --*/ { DWORD status; LPBYTE lpTempBuffer; SERVICE_DESCRIPTIONA sdDescription; SERVICE_FAILURE_ACTIONSA sfaActions; DWORD tempBufSize; BOOL fDummyBuffer = FALSE; tempBufSize = cbBufSize; lpTempBuffer = lpBuffer; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, put the correct size in the BytesNeeded parameter, and // fail the call. // switch(dwInfoLevel) { case SERVICE_CONFIG_DESCRIPTION: if (cbBufSize < sizeof(SERVICE_DESCRIPTION_WOW64)) { lpTempBuffer = (LPBYTE) &sdDescription; tempBufSize = sizeof(SERVICE_DESCRIPTION_WOW64); fDummyBuffer = TRUE; } break; case SERVICE_CONFIG_FAILURE_ACTIONS: if (cbBufSize < sizeof(SERVICE_FAILURE_ACTIONS_WOW64)) { lpTempBuffer = (LPBYTE) &sfaActions; tempBufSize = sizeof(SERVICE_FAILURE_ACTIONS_WOW64); fDummyBuffer = TRUE; } break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } RpcTryExcept { status = RQueryServiceConfig2A( (SC_RPC_HANDLE) hService, dwInfoLevel, lpTempBuffer, tempBufSize, pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept #ifdef _WIN64 // // 64-bit needs more space than the 32-bit-oriented structure // coming from the server. Make sure we have it. Do this // even if fDummyBuffer is TRUE since ScConvertOffsets64 will // update *pcbBytesNeeded appropriately. // if (status == NO_ERROR || status == ERROR_INSUFFICIENT_BUFFER) { if (!ScConvertOffsets64(dwInfoLevel == SERVICE_CONFIG_DESCRIPTION ? SC_API_QUERY_DESCRIPTION_A : SC_API_QUERY_FAILURE_ACTIONS_A, NULL, 0, 0, lpTempBuffer, tempBufSize, pcbBytesNeeded, NULL, NULL, NULL, NULL)) { status = ERROR_INSUFFICIENT_BUFFER; } } #endif // _WIN64 if (status != NO_ERROR) { SetLastError(status); return FALSE; } // // Catch the case where the RPC call succeeded even though we used // a dummy buffer (e.g., SERVICE_FAILURE_ACTIONS on a service with // no command line or reboot message). Note that the server side // of this API fills in pcbBytesNeeded even on success // if (fDummyBuffer) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } // // Convert offsets to pointers in the returned structure // switch (dwInfoLevel) { case SERVICE_CONFIG_DESCRIPTION: { LPSERVICE_DESCRIPTIONA psd = (LPSERVICE_DESCRIPTIONA) lpBuffer; if (psd->lpDescription != NULL) { psd->lpDescription = (LPSTR) (lpBuffer + (DWORD)(ULONG_PTR)psd->lpDescription); } } break; case SERVICE_CONFIG_FAILURE_ACTIONS: { LPSERVICE_FAILURE_ACTIONSA psfa = (LPSERVICE_FAILURE_ACTIONSA) lpBuffer; if (psfa->lpRebootMsg != NULL) { psfa->lpRebootMsg = (LPSTR) (lpBuffer + (DWORD)(ULONG_PTR)psfa->lpRebootMsg); } if (psfa->lpCommand != NULL) { psfa->lpCommand = (LPSTR) (lpBuffer + (DWORD)(ULONG_PTR)psfa->lpCommand); } if (psfa->lpsaActions != NULL) { psfa->lpsaActions = (SC_ACTION *) (lpBuffer + (DWORD)(ULONG_PTR)psfa->lpsaActions); } } break; } return TRUE; } BOOL WINAPI QueryServiceConfig2W( IN SC_HANDLE hService, IN DWORD dwInfoLevel, OUT LPBYTE lpBuffer, IN DWORD cbBufSize, OUT LPDWORD pcbBytesNeeded ) /*++ Routine Description: Arguments: Return Value: Note: --*/ { DWORD status; LPBYTE lpTempBuffer; SERVICE_DESCRIPTIONW sdDescription; SERVICE_FAILURE_ACTIONSW sfaActions; DWORD tempBufSize; BOOL fDummyBuffer = FALSE; tempBufSize = cbBufSize; lpTempBuffer = lpBuffer; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, put the correct size in the BytesNeeded parameter, and // fail the call. // switch(dwInfoLevel) { case SERVICE_CONFIG_DESCRIPTION: if (cbBufSize < sizeof(SERVICE_DESCRIPTIONW)) { lpTempBuffer = (LPBYTE) &sdDescription; tempBufSize = sizeof(SERVICE_DESCRIPTIONW); fDummyBuffer = TRUE; } break; case SERVICE_CONFIG_FAILURE_ACTIONS: if (cbBufSize < sizeof(SERVICE_FAILURE_ACTIONSW)) { lpTempBuffer = (LPBYTE) &sfaActions; tempBufSize = sizeof(SERVICE_FAILURE_ACTIONSW); fDummyBuffer = TRUE; } break; default: SetLastError(ERROR_INVALID_LEVEL); return FALSE; } RpcTryExcept { status = RQueryServiceConfig2W( (SC_RPC_HANDLE) hService, dwInfoLevel, lpTempBuffer, tempBufSize, pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept #ifdef _WIN64 // // 64-bit needs more space than the 32-bit-oriented structure // coming from the server. Make sure we have it. Do this // even if fDummyBuffer is TRUE since ScConvertOffsets64 will // update *pcbBytesNeeded appropriately. // if (status == NO_ERROR || status == ERROR_INSUFFICIENT_BUFFER) { if (!ScConvertOffsets64(dwInfoLevel == SERVICE_CONFIG_DESCRIPTION ? SC_API_QUERY_DESCRIPTION_W : SC_API_QUERY_FAILURE_ACTIONS_W, NULL, 0, 0, lpTempBuffer, tempBufSize, pcbBytesNeeded, NULL, NULL, NULL, NULL)) { status = ERROR_INSUFFICIENT_BUFFER; } } #endif // _WIN64 if (status != NO_ERROR) { SetLastError(status); return FALSE; } // // Catch the case where the RPC call succeeded even though we used // a dummy buffer (e.g., SERVICE_FAILURE_ACTIONS on a service with // no command line or reboot message). Note that the server side // of this API fills in pcbBytesNeeded even on success // if (fDummyBuffer) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } // // Convert offsets to pointers in the returned structure // switch (dwInfoLevel) { case SERVICE_CONFIG_DESCRIPTION: { LPSERVICE_DESCRIPTIONW psd = (LPSERVICE_DESCRIPTIONW) lpBuffer; if (psd->lpDescription != NULL) { psd->lpDescription = (LPWSTR) (lpBuffer + (DWORD)(ULONG_PTR) psd->lpDescription); } } break; case SERVICE_CONFIG_FAILURE_ACTIONS: { LPSERVICE_FAILURE_ACTIONSW psfa = (LPSERVICE_FAILURE_ACTIONSW) lpBuffer; if (psfa->lpRebootMsg != NULL) { psfa->lpRebootMsg = (LPWSTR) (lpBuffer + (DWORD)(ULONG_PTR) psfa->lpRebootMsg); } if (psfa->lpCommand != NULL) { psfa->lpCommand = (LPWSTR) (lpBuffer + (DWORD)(ULONG_PTR) psfa->lpCommand); } if (psfa->lpsaActions != NULL) { psfa->lpsaActions = (SC_ACTION *) (lpBuffer + (DWORD)(ULONG_PTR) psfa->lpsaActions); } } break; } return TRUE; } BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager, LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus, DWORD cbBufSize, LPDWORD pcbBytesNeeded ) /*++ Routine Description: This is the DLL entry point for the QueryServiceLockStatus function. This function returns lock status information on a Service Control Manager database. Arguments: hSCManager - Handled obtained from a previous call to OpenSCManager call. lpLockStatus - A pointer to a buffer to receive a QUERY_SERVICE_LOCK_STATUS information structure. Return Value: Note: --*/ { DWORD status; LPQUERY_SERVICE_LOCK_STATUSA pStatusBuf; QUERY_SERVICE_LOCK_STATUSA statusBuf; DWORD tempBufSize; tempBufSize = cbBufSize; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // if (cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSA)) { pStatusBuf = &statusBuf; tempBufSize = sizeof(QUERY_SERVICE_LOCK_STATUSA); } else { pStatusBuf = lpLockStatus; } RpcTryExcept { status = RQueryServiceLockStatusA( (SC_RPC_HANDLE)hSCManager, pStatusBuf, tempBufSize, pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR) { #ifdef _WIN64 // // pcbBytesNeeded isn't filled in if the byte count is too // small (returned when the buffer size is large enough to // hold the 32-bit structure but too small to hold the // 64-bit structure. Get the necessary (32-bit) size. // if (status == RPC_X_BYTE_COUNT_TOO_SMALL) { RpcTryExcept { status = RQueryServiceLockStatusA( (SC_RPC_HANDLE)hSCManager, pStatusBuf, sizeof(QUERY_SERVICE_LOCK_STATUSA), pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept } // // Since the ACF file specifies byte_count for this API, we're // responsible for managing the count of bytes needed by the // caller. For 64-bit clients calling 32-bit servers, the // returned buffer size is too small because of differing // pointer sizes. Add on the minimum number of bytes that // will guarantee enough space in the buffer for the next // call. // if (status == ERROR_INSUFFICIENT_BUFFER) { // // 1 embedded pointer in the structure and max // space required for alignment. // *pcbBytesNeeded += (sizeof(PVOID) - sizeof(ULONG) + sizeof(PVOID)); } else if (status == RPC_X_BYTE_COUNT_TOO_SMALL) { // // We get here if we called a 32-bit server where the lock // was unowned and we used a buffer size smaller than // sizeof(QUERY_SERVICE_LOCK_STATUSA). // *pcbBytesNeeded = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(WCHAR); status = ERROR_INSUFFICIENT_BUFFER; } #endif // _WIN64 SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager, LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus, DWORD cbBufSize, LPDWORD pcbBytesNeeded ) /*++ Routine Description: see QueryServiceLockStatusA Arguments: Return Value: Note: --*/ { DWORD status; LPQUERY_SERVICE_LOCK_STATUSW pStatusBuf; QUERY_SERVICE_LOCK_STATUSW statusBuf; DWORD tempBufSize; tempBufSize = cbBufSize; // // Create a dummy buffer that is at least the size of the structure. // This way RPC should at least send the request to the server side. // The server should recognize that the buffer is to small for any // strings, and put the correct size in the BytesNeeded parameter, // and fail the call. // if (cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSW)) { pStatusBuf = &statusBuf; tempBufSize = sizeof(QUERY_SERVICE_LOCK_STATUSW); } else { pStatusBuf = lpLockStatus; } RpcTryExcept { status = RQueryServiceLockStatusW( (SC_RPC_HANDLE)hSCManager, pStatusBuf, tempBufSize, pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR) { #ifdef _WIN64 // // pcbBytesNeeded isn't filled in if the byte count is too // small (returned when the buffer size is large enough to // hold the 32-bit structure but too small to hold the // 64-bit structure. Get the necessary (32-bit) size. // if (status == RPC_X_BYTE_COUNT_TOO_SMALL) { RpcTryExcept { status = RQueryServiceLockStatusW( (SC_RPC_HANDLE)hSCManager, pStatusBuf, sizeof(QUERY_SERVICE_LOCK_STATUSW), pcbBytesNeeded); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept } // // Since the ACF file specifies byte_count for this API, we're // responsible for managing the count of bytes needed by the // caller. For 64-bit clients calling 32-bit servers, the // returned buffer size is too small because of differing // pointer sizes. Add on the minimum number of bytes that // will guarantee enough space in the buffer for the next // call. // if (status == ERROR_INSUFFICIENT_BUFFER) { // // 1 embedded pointer in the structure and max // space required for alignment. // *pcbBytesNeeded += (sizeof(PVOID) - sizeof(ULONG) + sizeof(PVOID)); } else if (status == RPC_X_BYTE_COUNT_TOO_SMALL) { // // We get here if we called a 32-bit server where the lock // was unowned and we used a buffer size smaller than // sizeof(QUERY_SERVICE_LOCK_STATUSW). // *pcbBytesNeeded = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR); status = ERROR_INSUFFICIENT_BUFFER; } #endif // _WIN64 SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI UnlockServiceDatabase( IN SC_LOCK ScLock ) /*++ Routine Description: This is the DLL entry point for the UnlockServiceDatabase function. This function releases a lock on a Service Control Manager database. Arguments: ScLock - Lock obtained from a previous LockServiceDatabase call. Return Value: --*/ { DWORD status; UNREFERENCED_PARAMETER(ScLock); RpcTryExcept { status = RUnlockServiceDatabase((LPSC_RPC_LOCK)&ScLock); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_SERVICE_LOCK); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } BOOL WINAPI NotifyBootConfigStatus( IN BOOL BootAcceptable ) /*++ Routine Description: If we are not currently booted with Last Known Good, this function will revert to Last Known Good if the boot is not acceptable. Or it will save the boot configuration that we last booted from as the Last Known Good. This is the configuration that we will fall back to if a future boot fails. Arguments: BootAcceptable - This indicates whether or not the boot was acceptable. Return Value: TRUE - This is only returned if the boot is acceptable, and we successfully replaced Last Known Good with the current boot configuration. FALSE - This is returned if an error occured when attempting to replace Last Known Good or if the system is currently booted from Last Known Good. --*/ { DWORD status; RpcTryExcept { status = RNotifyBootConfigStatus( NULL, // A Local Call Only. (DWORD)BootAcceptable); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE); } RpcEndExcept if (status != NO_ERROR){ SetLastError(status); return(FALSE); } return(TRUE); } DWORD ScWaitForStart( VOID ) /*++ Routine Description: This routine waits until the SC_INTERNAL_START_EVENT is set or until a timeout occurs. Then it returns. Arguments: none Return Value: none --*/ { DWORD status; HANDLE ScStartEvent = NULL; // // Try opening the event first because it will work most of the // time. // ScStartEvent = OpenEventW( SYNCHRONIZE, FALSE, SC_INTERNAL_START_EVENT ); if (ScStartEvent == NULL) { status = GetLastError(); if (status == ERROR_FILE_NOT_FOUND) { // // Only if we can't find the event do we attempt to create // it here. // SCC_LOG0(ERROR, "ScWaitForStart: Event does not exist -- attempting to create it\n"); // // Create the event that the OpenSCManager will use to wait on the // service controller with. // SECURITY_ATTRIBUTES SecurityAttributes; PSECURITY_DESCRIPTOR SecurityDescriptor=NULL; status = ScCreateStartEventSD(&SecurityDescriptor); if (status != NO_ERROR) { SCC_LOG0(ERROR,"ScGetStartEvent: Couldn't allocate for SecurityDesc\n"); return status; } SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); SecurityAttributes.bInheritHandle = FALSE; SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor; ScStartEvent = CreateEventW( &SecurityAttributes, TRUE, // Must be manually reset FALSE, // The event is initially not signalled SC_INTERNAL_START_EVENT ); status = GetLastError(); // must do this before LocalFree LocalFree(SecurityDescriptor); if (ScStartEvent == NULL) { // // Failed to create StartEvent. // // If we failed to create it because someone else created // it between our calls to OpenEvent and CreateEvent, try // to open it once more. // if (status == ERROR_ALREADY_EXISTS) { ScStartEvent = OpenEventW( SYNCHRONIZE, FALSE, SC_INTERNAL_START_EVENT ); if (ScStartEvent == NULL) { status = GetLastError(); SCC_LOG1(ERROR,"ScWaitForStart: OpenEvent (StartEvent) failed " FORMAT_DWORD " on second attempt\n", status); return status; } } else { SCC_LOG1(ERROR,"ScWaitForStart: CreateEvent (StartEvent) Failed " FORMAT_DWORD "\n", status); return status; } } } else { // // Could not open the event for some unknown reason. Give up. // SCC_LOG1(ERROR,"ScWaitForStart: OpenEvent (StartEvent) Failed " FORMAT_DWORD "\n", status); return status; } } SCC_LOG0(TRACE,"Beginning wait for ScStartEvent\n"); status = WaitForSingleObject(ScStartEvent, SC_START_TIMEOUT); CloseHandle(ScStartEvent); if (status == WAIT_TIMEOUT) { SCC_LOG0(ERROR,"ScWaitForStart: TIMEOUT waiting for StartEvent\n"); return ERROR_TIMEOUT; } return NO_ERROR; } DWORD ScMapRpcError( IN DWORD RpcError, IN DWORD BadContextError ) /*++ Routine Description: This routine maps the RPC error into a more meaningful error for the caller. Arguments: RpcError - Supplies the exception error raised by RPC BadContextError - Supplies the error code to return whenever an error which indicates invalid context is received. In some cases, this value is ERROR_INVALID_HANDLE; in others, it is ERROR_INVALID_SERVICE_LOCK. Return Value: Returns the mapped error. --*/ { switch (RpcError) { case RPC_S_INVALID_BINDING: case RPC_X_SS_IN_NULL_CONTEXT: case RPC_X_SS_CONTEXT_DAMAGED: case RPC_X_SS_HANDLES_MISMATCH: case ERROR_INVALID_HANDLE: return BadContextError; case RPC_X_NULL_REF_POINTER: case EXCEPTION_ACCESS_VIOLATION: return ERROR_INVALID_ADDRESS; case RPC_S_INVALID_TAG: return ERROR_INVALID_LEVEL; case RPC_S_PROCNUM_OUT_OF_RANGE: return ERROR_CALL_NOT_IMPLEMENTED; default: return RpcError; } }