/*! * @file service.c * @brief Definitions for service management functions */ #include "extapi.h" #include "service.h" #ifdef _WIN32 #include <Sddl.h> /*! @brief The possible list of operations to perform on a service */ typedef enum _ServiceOperation { ServOpStart = 1, ServOpPause = 2, ServOpResume = 3, ServOpStop = 4, ServOpRestart = 5 } ServiceOperation; HMODULE hAdvapi32 = NULL; /*! @brief Typedef for the OpenSCManagerA function. */ typedef SC_HANDLE(WINAPI * POPENSCMANAGERA)(LPCSTR lpMachineName, LPCSTR lpDatabaseName, DWORD dwDesiredAccess); static POPENSCMANAGERA pOpenSCManagerA = NULL; /*! @brief Typedef for the CloseServiceHandle function. */ typedef BOOL(WINAPI * PCLOSESERVICEHANDLE)(SC_HANDLE hSCObject); static PCLOSESERVICEHANDLE pCloseServiceHandle = NULL; /*! @brief Typedef for the StartServiceA function. */ typedef BOOL (WINAPI * PSTARTSERVICEA)(SC_HANDLE hService, DWORD dwNumServiceArgs, LPCTSTR *lpServiceArgVectors); static PSTARTSERVICEA pStartServiceA = NULL; /*! @brief Typedef for the ControlService function. */ typedef BOOL (WINAPI * PCONTROLSERVICE)(SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus); static PCONTROLSERVICE pControlService = NULL; /*! @brief Typedef for the QueryServiceStatus function. */ typedef BOOL (WINAPI * PQUERYSERVICESTATUS)(SC_HANDLE hService, LPSERVICE_STATUS lpServiceStatus); static PQUERYSERVICESTATUS pQueryServiceStatus = NULL; /*! @brief Typedef for the EnumServicesStatusExA function. */ typedef BOOL(WINAPI * PENUMSERVICESSTATUSEXA)( SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType, DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName ); static PENUMSERVICESSTATUSEXA pEnumServicesStatusExA = NULL; /*! @brief Typedef for the OpenServiceA function. */ typedef SC_HANDLE(WINAPI * POPENSERVICEA)(SC_HANDLE hSCManager, LPCSTR lpServiceName, DWORD dwDesiredAcces); static POPENSERVICEA pOpenServiceA = NULL; /*! @brief Typedef for the QueryServiceObjectSecurity function. */ typedef BOOL(WINAPI * PQUERYSERVICEOBJECTSECURITY)( SC_HANDLE hService, SECURITY_INFORMATION dwSecurityInformation, PSECURITY_DESCRIPTOR lpSecurityDescriptor, DWORD cbBufSize, LPDWORD pcbBytesNeeded ); static PQUERYSERVICEOBJECTSECURITY pQueryServiceObjectSecurity = NULL; /*! @brief Typedef for the QueryServiceConfigA function. */ typedef BOOL(WINAPI * PQUERYSERVICECONFIGA)( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA lpServiceConfig, DWORD dbBufSize, LPDWORD pcbBytesNeeded ); static PQUERYSERVICECONFIGA pQueryServiceConfigA = NULL; /*! @brief Typedef for the ConvertSecurityDescriptorToStringSecurityDescriptorA function. */ typedef BOOL(WINAPI * PCSDTSSDA)( PSECURITY_DESCRIPTOR SecurityDescriptor, DWORD RequestedStringSDRevision, SECURITY_INFORMATION SecurityInformation, LPCSTR *StringSecurityDescriptor, PULONG StringSecurityDescriptorLen ); static PCSDTSSDA pCSDTSSDA = NULL; VOID add_enumerated_service(Packet *pResponse, LPCSTR cpName, LPCSTR cpDisplayName, DWORD dwProcessId, DWORD dwStatus, BOOL bInteractive); DWORD query_service(LPCSTR cpServiceName, Packet *pResponse); DWORD get_service_config(SC_HANDLE scService, Packet *pResponse); DWORD get_service_status(SC_HANDLE scService, Packet *pResponse); DWORD get_service_dacl(SC_HANDLE scService, Packet *pResponse); #endif DWORD execute_service_task(LPCSTR lpServiceName, ServiceOperation eServiceOp, Packet *response); DWORD enumerate_services(Packet *response); /*! * @brief Initialise the service part of the extended api. */ VOID initialise_service() { do { dprintf("[EXTAPI SERVICE] Loading advapi32.dll"); if ((hAdvapi32 = LoadLibraryA("advapi32.dll")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to load advapi32.dll"); break; } dprintf("[EXTAPI SERVICE] Searching for OpenSCManagerA"); if ((pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(hAdvapi32, "OpenSCManagerA")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate OpenSCManagerA in advapi32.dll"); } dprintf("[EXTAPI SERVICE] Searching for CloseServiceHandle"); if ((pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(hAdvapi32, "CloseServiceHandle")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate CloseServiceHandle in advapi32.dll. Continuing anyway."); } dprintf("[EXTAPI SERVICE] Searching for EnumServicesStatusExA"); if ((pEnumServicesStatusExA = (PENUMSERVICESSTATUSEXA)GetProcAddress(hAdvapi32, "EnumServicesStatusExA")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate EnumServicesStatusExA in advapi32.dll."); } dprintf("[EXTAPI SERVICE] Searching for CloseServiceHandle"); if ((pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(hAdvapi32, "CloseServiceHandle")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate CloseServiceHandle in advapi32.dll. Continuing anyway."); } dprintf("[EXTAPI SERVICE] Searching for OpenServiceA"); if ((pOpenServiceA = (POPENSERVICEA)GetProcAddress(hAdvapi32, "OpenServiceA")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate OpenServiceA in advapi32.dll."); } dprintf("[EXTAPI SERVICE] Searching for QueryServiceConfigA"); if ((pQueryServiceConfigA = (PQUERYSERVICECONFIGA)GetProcAddress(hAdvapi32, "QueryServiceConfigA")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate QueryServiceConfigA in advapi32.dll."); } dprintf("[EXTAPI SERVICE] Searching for QueryServiceObjectSecurity"); if ((pQueryServiceObjectSecurity = (PQUERYSERVICEOBJECTSECURITY)GetProcAddress(hAdvapi32, "QueryServiceObjectSecurity")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate QueryServiceObjectSecurity in advapi32.dll."); } dprintf("[EXTAPI SERVICE] Searching for ConvertSecurityDescriptorToStringSecurityDescriptorA"); if ((pCSDTSSDA = (PCSDTSSDA)GetProcAddress(hAdvapi32, "ConvertSecurityDescriptorToStringSecurityDescriptorA")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate ConvertSecurityDescriptorToStringSecurityDescriptorA in advapi32.dll."); } dprintf("[EXTAPI SERVICE] Searching for StartServiceA"); if ((pStartServiceA = (PSTARTSERVICEA)GetProcAddress(hAdvapi32, "StartServiceA")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate StartServiceA in advapi32.dll."); } dprintf("[EXTAPI SERVICE] Searching for ControlService"); if ((pControlService = (PCONTROLSERVICE)GetProcAddress(hAdvapi32, "ControlService")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate ControlService in advapi32.dll."); } dprintf("[EXTAPI SERVICE] Searching for QueryServiceStatus"); if ((pQueryServiceStatus = (PQUERYSERVICESTATUS)GetProcAddress(hAdvapi32, "QueryServiceStatus")) == NULL) { dprintf("[EXTAPI SERVICE] Unable to locate QueryServiceStatus in advapi32.dll."); } } while (0); } /*! * @brief Handle the request for service control. * @param remote Pointer to the \c Remote making the request. * @param packet Pointer to the request \c Packet. * @returns Indication of sucess or failure. */ DWORD request_service_control(Remote *remote, Packet *packet) { LPSTR lpServiceName = NULL; ServiceOperation eServiceOp = 0; DWORD dwResult = ERROR_SUCCESS; Packet * response = packet_create_response(packet); do { if (!response) { dprintf("[EXTAPI SERVICE] Unable to create response packet"); dwResult = ERROR_OUTOFMEMORY; break; } lpServiceName = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_SERVICE_CTRL_NAME); if (!lpServiceName) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service name parameter", ERROR_INVALID_PARAMETER); } eServiceOp = (ServiceOperation)packet_get_tlv_value_uint(packet, TLV_TYPE_EXT_SERVICE_CTRL_OP); if (eServiceOp == 0) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service operation parameter", ERROR_INVALID_PARAMETER); } dprintf("[EXTAPI SERVICE] Executing service control task"); dwResult = execute_service_task(lpServiceName, eServiceOp, response); } while (0); dprintf("[EXTAPI SERVICE] Transmitting response back to caller."); if (response) { packet_transmit_response(dwResult, remote, response); } return dwResult; } /*! * @brief Handle the request for service enumeration. * @param remote Pointer to the \c Remote making the request. * @param packet Pointer to the request \c Packet. * @returns Indication of sucess or failure. */ DWORD request_service_enum(Remote *remote, Packet *packet) { DWORD dwResult = ERROR_SUCCESS; Packet * response = packet_create_response(packet); do { if (!response) { dprintf("[EXTAPI SERVICE] Unable to create response packet"); dwResult = ERROR_OUTOFMEMORY; break; } dprintf("[EXTAPI SERVICE] Beginning service enumeration"); dwResult = enumerate_services(response); } while (0); dprintf("[EXTAPI SERVICE] Transmitting response back to caller."); if (response) { packet_transmit_response(dwResult, remote, response); } return dwResult; } /*! * @brief Handle the request for a service query. * @param remote Pointer to the \c Remote making the request. * @param packet Pointer to the request \c Packet. * @remark The \c packet must contain the name of the service to query. * @returns Indication of sucess or failure. * @retval ERROR_SUCCESS Query succeeded. * @retval ERROR_OUTOFMEMORY Memory allocation failed. * @retval ERROR_BAD_ARGUMENTS Service name was missing from \c packet. */ DWORD request_service_query(Remote *remote, Packet *packet) { LPSTR lpServiceName = NULL; DWORD dwResult = ERROR_SUCCESS; Packet * response = packet_create_response(packet); do { if (!response) { dprintf("[EXTAPI SERVICE] Unable to create response packet"); dwResult = ERROR_OUTOFMEMORY; break; } lpServiceName = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_SERVICE_ENUM_NAME); if (!lpServiceName) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service name parameter", ERROR_INVALID_PARAMETER); } dprintf("[EXTAPI SERVICE] Beginning service enumeration"); dwResult = query_service(lpServiceName, response); } while (0); dprintf("[EXTAPI SERVICE] Transmitting response back to caller."); if (response) { packet_transmit_response(dwResult, remote, response); } return dwResult; } /*! * @brief Perform the request for a service query. * @param cpServiceName Name of the serivce to perform the query on. * @param pRacket Pointer to the response \c Packet. * @returns Indication of sucess or failure. * @retval ERROR_SUCCESS Query succeeded. */ DWORD query_service(LPCSTR cpServiceName, Packet *pResponse) { #ifdef _WIN32 // currently we only support Windoze DWORD dwResult = ERROR_SUCCESS; SC_HANDLE scManager = NULL; SC_HANDLE scService = NULL; do { if (hAdvapi32 == NULL || pOpenSCManagerA == NULL || pCloseServiceHandle == NULL || pOpenServiceA == NULL) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to query services, required functions not found", ERROR_INVALID_PARAMETER); } dprintf("[EXTAPI SERVICE] Opening the Service Control manager"); if ((scManager = pOpenSCManagerA(NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL) { BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to open the service control manager"); } dprintf("[EXTAPI SERVICE] Opening the Service: %s", cpServiceName); if ((scService = pOpenServiceA(scManager, cpServiceName, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL) { dwResult = GetLastError(); dprintf("[EXTAPI SERVICE] Unable to open the service: %s (%u)", cpServiceName, dwResult); break; } get_service_config(scService, pResponse); get_service_status(scService, pResponse); get_service_dacl(scService, pResponse); } while (0); if (scService && pCloseServiceHandle) { pCloseServiceHandle(scService); } if (scManager && pCloseServiceHandle) { pCloseServiceHandle(scManager); } return dwResult; #else return ERROR_NOT_SUPPORTED; #endif } /*! * @brief Perform the service enumeration. * @param pRacket Pointer to the response \c Packet. * @returns Indication of sucess or failure. * @retval ERROR_SUCCESS Query succeeded. */ DWORD enumerate_services(Packet *pResponse) { #ifdef _WIN32 // currently we only support Windoze DWORD dwResult = ERROR_SUCCESS; SC_HANDLE scManager = NULL; ENUM_SERVICE_STATUS_PROCESSA* pSsInfo = NULL; DWORD dwBytesNeeded = 0; DWORD dwServicesReturned = 0; DWORD dwResumeHandle = 0; DWORD dwServiceIndex = 0; BOOL bResult; do { if (hAdvapi32 == NULL || pOpenSCManagerA == NULL || pCloseServiceHandle == NULL || pEnumServicesStatusExA == NULL) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to enumerate services, required functions not found", ERROR_INVALID_PARAMETER); } // TODO: add support for other machine names so that this instance can query other machines on the network. dprintf("[EXTAPI SERVICE] Opening the Service Control manager"); if ((scManager = pOpenSCManagerA(NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL) { BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to open the service control manager"); } bResult = pEnumServicesStatusExA(scManager, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &dwBytesNeeded, &dwServicesReturned, &dwResumeHandle, NULL); if (!bResult && dwBytesNeeded) { pSsInfo = (ENUM_SERVICE_STATUS_PROCESSA*)malloc(dwBytesNeeded); if (!pSsInfo) { BREAK_ON_ERROR("[EXTAPI SERVICE] Out of memory"); } bResult = pEnumServicesStatusExA(scManager, SC_ENUM_PROCESS_INFO, SERVICE_WIN32, SERVICE_STATE_ALL, (LPBYTE)pSsInfo, dwBytesNeeded, &dwBytesNeeded, &dwServicesReturned, &dwResumeHandle, NULL); } if (!bResult) { BREAK_ON_ERROR("[EXTAPI SERVICE] Failed to enumerate services"); } dprintf("[EXTAPI SERVICE] %s with %u entries returned", (bResult ? "succeeded" : "failed"), dwServicesReturned); for (dwServiceIndex = 0; dwServiceIndex < dwServicesReturned; ++dwServiceIndex) { add_enumerated_service(pResponse, pSsInfo[dwServiceIndex].lpServiceName, pSsInfo[dwServiceIndex].lpDisplayName, pSsInfo[dwServiceIndex].ServiceStatusProcess.dwProcessId, pSsInfo[dwServiceIndex].ServiceStatusProcess.dwCurrentState, pSsInfo[dwServiceIndex].ServiceStatusProcess.dwServiceType & SERVICE_INTERACTIVE_PROCESS); } } while (0); if (pSsInfo) { free(pSsInfo); } if (scManager && pCloseServiceHandle) { pCloseServiceHandle(scManager); } return dwResult; #else return ERROR_NOT_SUPPORTED; #endif } /*! * @brief Perform the task/operation on a service. * @param cpServiceName Name of the serivce to perform the query on. * @param eServiceOp The operationg to perform on the service. * @param pRacket Pointer to the response \c Packet. * @returns Indication of sucess or failure. * @retval ERROR_SUCCESS Operation succeeded. */ DWORD execute_service_task(LPCSTR cpServiceName, ServiceOperation eServiceOp, Packet *pResponse) { #ifdef _WIN32 // currently we only support Windoze DWORD dwResult = ERROR_SUCCESS; DWORD dwOpenFlags = SC_MANAGER_CONNECT | GENERIC_READ | SERVICE_QUERY_STATUS; DWORD dwControlFlag = 0; DWORD dwTargetStatus = 0; SC_HANDLE scManager = NULL; SC_HANDLE scService = NULL; SERVICE_STATUS serviceStatus; do { if (hAdvapi32 == NULL || pOpenSCManagerA == NULL || pStartServiceA == NULL || pCloseServiceHandle == NULL || pQueryServiceStatus == NULL || pOpenServiceA == NULL) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to query services, required functions not found", ERROR_INVALID_PARAMETER); } dprintf("[EXTAPI SERVICE] Opening the Service Control manager"); if ((scManager = pOpenSCManagerA(NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL) { BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to open the service control manager"); } switch (eServiceOp) { case ServOpStart: dwOpenFlags |= SERVICE_START; break; case ServOpStop: dwOpenFlags |= SERVICE_STOP; break; case ServOpPause: case ServOpResume: dwOpenFlags |= SERVICE_PAUSE_CONTINUE; break; case ServOpRestart: dwOpenFlags |= SERVICE_START | SERVICE_STOP; } dprintf("[EXTAPI SERVICE] Opening the Service: %s", cpServiceName); if ((scService = pOpenServiceA(scManager, cpServiceName, dwOpenFlags)) == NULL) { dwResult = GetLastError(); dprintf("[EXTAPI SERVICE] Unable to open the service: %s (%u)", cpServiceName, dwResult); break; } // let's get a clue as to what the service status is before we move on if (!pQueryServiceStatus(scService, &serviceStatus)) { dwResult = GetLastError(); dprintf("[EXTAPI SERVICE] Unable to query the service status: %s (%u)", cpServiceName, dwResult); break; } dwResult = ERROR_SUCCESS; if (eServiceOp == ServOpStart) { // we can't try to start the service if it isn't stopped if (serviceStatus.dwCurrentState == SERVICE_STOPPED) { if (!pStartServiceA(scService, 0, NULL)) { dwResult = GetLastError(); dprintf("[EXTAPI SERVICE] Unable to start the service: %s (%u)", cpServiceName, dwResult); break; } } else if(serviceStatus.dwCurrentState != SERVICE_RUNNING) { dprintf("[EXTAPI SERVICE] Unable to start the service in its current state: %s %x", cpServiceName, serviceStatus.dwCurrentState); dwResult = ERROR_INVALID_OPERATION; break; } } else { switch (eServiceOp) { case ServOpRestart: case ServOpStop: dwControlFlag = SERVICE_CONTROL_STOP; dwTargetStatus = SERVICE_STOPPED; break; case ServOpPause: dwControlFlag = SERVICE_CONTROL_PAUSE; dwTargetStatus = SERVICE_PAUSED; break; case ServOpResume: dwControlFlag = SERVICE_CONTROL_CONTINUE; dwTargetStatus = SERVICE_RUNNING; break; } dwResult = ERROR_SUCCESS; if (serviceStatus.dwCurrentState == dwTargetStatus) { dprintf("[EXTAPI SERVICE] Service already in target state: %u on %s (%u)", eServiceOp, cpServiceName, dwResult); } else if (!pControlService(scService, dwControlFlag, &serviceStatus)) { dwResult = GetLastError(); dprintf("[EXTAPI SERVICE] Unable to control the service: %u on %s (%u)", eServiceOp, cpServiceName, dwResult); break; } if (eServiceOp == ServOpRestart) { // At this point the service should either be stopped already or it will be stopping. // We have to wait until the service has stopped before we attempt to restart. do { Sleep(500); pQueryServiceStatus(scService, &serviceStatus); } while (serviceStatus.dwCurrentState != SERVICE_STOPPED); // next we try to kick it off again if (!pStartServiceA(scService, 0, NULL)) { dwResult = GetLastError(); dprintf("[EXTAPI SERVICE] Unable to start the service: %s (%u)", cpServiceName, dwResult); } } } } while (0); if (scService && pCloseServiceHandle) { pCloseServiceHandle(scService); } if (scManager && pCloseServiceHandle) { pCloseServiceHandle(scManager); } return dwResult; #else return ERROR_NOT_SUPPORTED; #endif } #ifdef _WIN32 /*! * @brief Add an enumeration result to the given response packet. * @param pRacket Pointer to the response \c Packet. * @param cpName Name of the service. * @param cpDisplayName Display name of the service. * @param dwProcessId ID of the service process. * @param dwStatus Status of the service (running, paused, etc). * @param bInteractive Indicates if the service can interact with the desktop. */ VOID add_enumerated_service(Packet *pResponse, LPCSTR cpName, LPCSTR cpDisplayName, DWORD dwProcessId, DWORD dwStatus, BOOL bInteractive) { Packet* pGroup = packet_create_group(); packet_add_tlv_string(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_NAME, cpName); packet_add_tlv_string(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_DISPLAYNAME, cpDisplayName); packet_add_tlv_uint(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_PID, dwProcessId); packet_add_tlv_uint(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_STATUS, dwStatus); packet_add_tlv_bool(pGroup, TLV_TYPE_EXT_SERVICE_ENUM_INTERACTIVE, bInteractive); packet_add_group(pResponse, TLV_TYPE_EXT_SERVICE_ENUM_GROUP, pGroup); } /*! * @brief Query the configuration of the given service. * @details On successful query the results of the query are added to the response. * @param scService Service handle referencing the service to query. * @param pResponse Pointer to the response \c Packet to add the result to. * @returns Indication of success or failure. * @retval ERROR_SUCCESS The service configuration query succeeded. */ DWORD get_service_config(SC_HANDLE scService, Packet *pResponse) { DWORD dwResult = ERROR_SUCCESS; LPQUERY_SERVICE_CONFIGA lpServiceConfig = NULL; DWORD cbBytesNeeded = 0; do { if (pQueryServiceConfigA == NULL) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to enumerate services, required functions not found", ERROR_INVALID_PARAMETER); } if (pQueryServiceConfigA(scService, NULL, 0, &cbBytesNeeded)) { BREAK_ON_ERROR("[EXTAPI SERVICE] This query should have failed"); } if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { BREAK_ON_ERROR("[EXTAPI SERVICE] Unexpected error from QueryServiceConfigA"); } if ((lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)malloc(cbBytesNeeded)) == NULL) { BREAK_ON_ERROR("[EXTAPI SERVICE] Out of memory"); } if (!pQueryServiceConfigA(scService, lpServiceConfig, cbBytesNeeded, &cbBytesNeeded)) { BREAK_ON_ERROR("[EXTAPI SERVICE] QueryServiceConfigA failed"); } dprintf("[EXTAPI SERVICE] Start type: %u", lpServiceConfig->dwStartType); packet_add_tlv_uint(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STARTTYPE, lpServiceConfig->dwStartType); packet_add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_DISPLAYNAME, lpServiceConfig->lpDisplayName); packet_add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STARTNAME, lpServiceConfig->lpServiceStartName); packet_add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_PATH, lpServiceConfig->lpBinaryPathName); packet_add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP, lpServiceConfig->lpLoadOrderGroup ? lpServiceConfig->lpLoadOrderGroup : ""); packet_add_tlv_bool(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE, lpServiceConfig->dwServiceType & SERVICE_INTERACTIVE_PROCESS); } while (0); if (lpServiceConfig) { free(lpServiceConfig); } return dwResult; } /*! * @brief Query the status of a given service handle. * @details On successful querying the status is added to the response. * @param scService Service handle referencing the service to query. * @param pResponse Pointer to the response \c Packet to add the result to. * @returns Indication of success or failure. * @retval ERROR_SUCCESS The service status query succeeded. */ DWORD get_service_status(SC_HANDLE scService, Packet *pResponse) { DWORD dwResult = ERROR_SUCCESS; SERVICE_STATUS serviceStatus; do { if (pQueryServiceStatus == NULL) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to query service status, required functions not found", ERROR_INVALID_PARAMETER); } // let's get a clue as to what the service status is before we move on if (!pQueryServiceStatus(scService, &serviceStatus)) { dwResult = GetLastError(); dprintf("[EXTAPI SERVICE] Unable to query the service status: %u", dwResult); break; } packet_add_tlv_uint(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STATUS, serviceStatus.dwCurrentState); } while (0); return dwResult; } /*! * @brief Get the DACL of the specified service. * @details On successful query the DACL string is added to the response. * @param scService Service handle referencing the service to query. * @param pResponse Pointer to the response \c Packet to add the result to. * @returns Indication of success or failure. * @retval ERROR_SUCCESS The service configuration query succeeded. */ DWORD get_service_dacl(SC_HANDLE scService, Packet *pResponse) { DWORD dwResult = ERROR_SUCCESS; DWORD dwBytesNeeded = 0; PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; LPSTR lpDaclString; do { if (pQueryServiceObjectSecurity == NULL || pCSDTSSDA == NULL) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to get service dacl, required functions not found", ERROR_INVALID_PARAMETER); } if (pQueryServiceObjectSecurity(scService, DACL_SECURITY_INFORMATION, (PSECURITY_DESCRIPTOR)&pSecurityDescriptor, 0, &dwBytesNeeded)) { BREAK_ON_ERROR("[EXTAPI SERVICE] Call should have failed"); } if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { BREAK_ON_ERROR("[EXTAPI SERVICE] Unexpected error getting security"); } if ((pSecurityDescriptor = (PSECURITY_DESCRIPTOR)malloc(dwBytesNeeded)) == NULL) { BREAK_WITH_ERROR("[EXTAPI SERVICE] Out of memory", ERROR_OUTOFMEMORY); } if (!pQueryServiceObjectSecurity(scService, DACL_SECURITY_INFORMATION, pSecurityDescriptor, dwBytesNeeded, &dwBytesNeeded)) { BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to query security information for DACL_SECURITY_INFORMATION"); } if (!pCSDTSSDA(pSecurityDescriptor, SDDL_REVISION_1, DACL_SECURITY_INFORMATION, &lpDaclString, NULL)) { BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to get DACL string"); } packet_add_tlv_string(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_DACL, lpDaclString); } while (0); if (lpDaclString) { LocalFree(lpDaclString); } if (pSecurityDescriptor) { free(pSecurityDescriptor); } return dwResult; } #endif