reactos/dll/win32/advapi32/service/scm.c
Eric Kohl f5346cbc1b [ADVAPI32][IDL][SERVICES] Implement I_ScValidatePnPService
This is actually a Vista+ function, but we need it enable umpnpmgr.dll to notify services of device events. Up until WinXP it was possible to make direct calls to the service manager by umpnpmgr.dll because umpnpmgr.dll was loaded into the service manager process. From Vista onwards umpnpmgr.dll is run as a separate service host process. And since ReactOS always ran umpnpmgr.dll as a separate process, we have to use the Vista RPC functions to notify services.
2023-12-31 15:33:19 +01:00

3215 lines
87 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: lib/advapi32/service/scm.c
* PURPOSE: Service control manager functions
* PROGRAMMER: Emanuele Aliberti
* Eric Kohl
* Pierre Schweitzer
*/
/* INCLUDES ******************************************************************/
#include <advapi32.h>
WINE_DEFAULT_DEBUG_CHANNEL(advapi);
NTSTATUS
WINAPI
SystemFunction004(
const struct ustring *in,
const struct ustring *key,
struct ustring *out);
NTSTATUS
WINAPI
SystemFunction028(
IN PVOID ContextHandle,
OUT LPBYTE SessionKey);
/* FUNCTIONS *****************************************************************/
handle_t __RPC_USER
SVCCTL_HANDLEA_bind(SVCCTL_HANDLEA szMachineName)
{
handle_t hBinding = NULL;
RPC_CSTR pszStringBinding;
RPC_STATUS status;
TRACE("SVCCTL_HANDLEA_bind(%s)\n",
debugstr_a(szMachineName));
status = RpcStringBindingComposeA(NULL,
(RPC_CSTR)"ncacn_np",
(RPC_CSTR)szMachineName,
(RPC_CSTR)"\\pipe\\ntsvcs",
NULL,
&pszStringBinding);
if (status != RPC_S_OK)
{
ERR("RpcStringBindingCompose returned 0x%x\n", status);
return NULL;
}
/* Set the binding handle that will be used to bind to the server. */
status = RpcBindingFromStringBindingA(pszStringBinding,
&hBinding);
if (status != RPC_S_OK)
{
ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
}
status = RpcStringFreeA(&pszStringBinding);
if (status != RPC_S_OK)
{
ERR("RpcStringFree returned 0x%x\n", status);
}
return hBinding;
}
void __RPC_USER
SVCCTL_HANDLEA_unbind(SVCCTL_HANDLEA szMachineName,
handle_t hBinding)
{
RPC_STATUS status;
TRACE("SVCCTL_HANDLEA_unbind(%s %p)\n",
debugstr_a(szMachineName), hBinding);
status = RpcBindingFree(&hBinding);
if (status != RPC_S_OK)
{
ERR("RpcBindingFree returned 0x%x\n", status);
}
}
handle_t __RPC_USER
SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW szMachineName)
{
handle_t hBinding = NULL;
RPC_WSTR pszStringBinding;
RPC_STATUS status;
TRACE("SVCCTL_HANDLEW_bind(%s)\n",
debugstr_w(szMachineName));
status = RpcStringBindingComposeW(NULL,
L"ncacn_np",
szMachineName,
L"\\pipe\\ntsvcs",
NULL,
&pszStringBinding);
if (status != RPC_S_OK)
{
ERR("RpcStringBindingCompose returned 0x%x\n", status);
return NULL;
}
/* Set the binding handle that will be used to bind to the server. */
status = RpcBindingFromStringBindingW(pszStringBinding,
&hBinding);
if (status != RPC_S_OK)
{
ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
}
status = RpcStringFreeW(&pszStringBinding);
if (status != RPC_S_OK)
{
ERR("RpcStringFree returned 0x%x\n", status);
}
return hBinding;
}
void __RPC_USER
SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW szMachineName,
handle_t hBinding)
{
RPC_STATUS status;
TRACE("SVCCTL_HANDLEW_unbind(%s %p)\n",
debugstr_w(szMachineName), hBinding);
status = RpcBindingFree(&hBinding);
if (status != RPC_S_OK)
{
ERR("RpcBindingFree returned 0x%x\n", status);
}
}
DWORD
ScmRpcStatusToWinError(RPC_STATUS Status)
{
TRACE("ScmRpcStatusToWinError(%lx)\n",
Status);
switch (Status)
{
case STATUS_ACCESS_VIOLATION:
case RPC_S_INVALID_BINDING:
case RPC_X_SS_IN_NULL_CONTEXT:
return ERROR_INVALID_HANDLE;
case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
case RPC_X_BYTE_COUNT_TOO_SMALL:
return ERROR_INVALID_PARAMETER;
case RPC_X_NULL_REF_POINTER:
return ERROR_INVALID_ADDRESS;
default:
return (DWORD)Status;
}
}
static
DWORD
ScmEncryptPassword(
_In_ PVOID ContextHandle,
_In_ PCWSTR pClearTextPassword,
_Out_ PBYTE *pEncryptedPassword,
_Out_ PDWORD pEncryptedPasswordSize)
{
struct ustring inData, keyData, outData;
BYTE SessionKey[16];
PBYTE pBuffer;
NTSTATUS Status;
/* Get the session key */
Status = SystemFunction028(ContextHandle,
SessionKey);
if (!NT_SUCCESS(Status))
{
ERR("SystemFunction028 failed (Status 0x%08lx)\n", Status);
return RtlNtStatusToDosError(Status);
}
inData.Length = (wcslen(pClearTextPassword) + 1) * sizeof(WCHAR);
inData.MaximumLength = inData.Length;
inData.Buffer = (unsigned char *)pClearTextPassword;
keyData.Length = sizeof(SessionKey);
keyData.MaximumLength = keyData.Length;
keyData.Buffer = SessionKey;
outData.Length = 0;
outData.MaximumLength = 0;
outData.Buffer = NULL;
/* Get the required buffer size */
Status = SystemFunction004(&inData,
&keyData,
&outData);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
ERR("SystemFunction004 failed (Status 0x%08lx)\n", Status);
return RtlNtStatusToDosError(Status);
}
/* Allocate a buffer for the encrypted password */
pBuffer = HeapAlloc(GetProcessHeap(), 0, outData.Length);
if (pBuffer == NULL)
return ERROR_OUTOFMEMORY;
outData.MaximumLength = outData.Length;
outData.Buffer = pBuffer;
/* Encrypt the password */
Status = SystemFunction004(&inData,
&keyData,
&outData);
if (!NT_SUCCESS(Status))
{
ERR("SystemFunction004 failed (Status 0x%08lx)\n", Status);
HeapFree(GetProcessHeap(), 0, pBuffer);
return RtlNtStatusToDosError(Status);
}
*pEncryptedPassword = outData.Buffer;
*pEncryptedPasswordSize = outData.Length;
return ERROR_SUCCESS;
}
/**********************************************************************
* ChangeServiceConfig2A
*
* @implemented
*/
BOOL WINAPI
ChangeServiceConfig2A(SC_HANDLE hService,
DWORD dwInfoLevel,
LPVOID lpInfo)
{
SC_RPC_CONFIG_INFOA Info;
DWORD dwError;
TRACE("ChangeServiceConfig2A(%p %lu %p)\n",
hService, dwInfoLevel, lpInfo);
if (lpInfo == NULL) return TRUE;
/* Fill relevant field of the Info structure */
Info.dwInfoLevel = dwInfoLevel;
switch (dwInfoLevel)
{
case SERVICE_CONFIG_DESCRIPTION:
Info.psd = lpInfo;
break;
case SERVICE_CONFIG_FAILURE_ACTIONS:
Info.psfa = lpInfo;
break;
default:
WARN("Unknown info level 0x%lx\n", dwInfoLevel);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
RpcTryExcept
{
dwError = RChangeServiceConfig2A((SC_RPC_HANDLE)hService,
Info);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RChangeServiceConfig2A() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* ChangeServiceConfig2W
*
* @implemented
*/
BOOL WINAPI
ChangeServiceConfig2W(SC_HANDLE hService,
DWORD dwInfoLevel,
LPVOID lpInfo)
{
SC_RPC_CONFIG_INFOW Info;
DWORD dwError;
TRACE("ChangeServiceConfig2W(%p %lu %p)\n",
hService, dwInfoLevel, lpInfo);
if (lpInfo == NULL) return TRUE;
/* Fill relevant field of the Info structure */
Info.dwInfoLevel = dwInfoLevel;
switch (dwInfoLevel)
{
case SERVICE_CONFIG_DESCRIPTION:
Info.psd = lpInfo;
break;
case SERVICE_CONFIG_FAILURE_ACTIONS:
Info.psfa = lpInfo;
break;
default:
WARN("Unknown info level 0x%lx\n", dwInfoLevel);
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
RpcTryExcept
{
dwError = RChangeServiceConfig2W((SC_RPC_HANDLE)hService,
Info);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RChangeServiceConfig2W() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* ChangeServiceConfigA
*
* @implemented
*/
BOOL WINAPI
ChangeServiceConfigA(SC_HANDLE hService,
DWORD dwServiceType,
DWORD dwStartType,
DWORD dwErrorControl,
LPCSTR lpBinaryPathName,
LPCSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCSTR lpDependencies,
LPCSTR lpServiceStartName,
LPCSTR lpPassword,
LPCSTR lpDisplayName)
{
DWORD dwError;
DWORD dwDependenciesLength = 0;
SIZE_T cchLength;
LPCSTR lpStr;
DWORD dwPasswordSize = 0;
LPWSTR lpPasswordW = NULL;
LPBYTE lpEncryptedPassword = NULL;
TRACE("ChangeServiceConfigA(%p %lu %lu %lu %s %s %p %s %s %s %s)\n",
hService, dwServiceType, dwStartType, dwErrorControl, debugstr_a(lpBinaryPathName),
debugstr_a(lpLoadOrderGroup), lpdwTagId, debugstr_a(lpDependencies),
debugstr_a(lpServiceStartName), debugstr_a(lpPassword), debugstr_a(lpDisplayName));
/* Calculate the Dependencies length*/
if (lpDependencies != NULL)
{
lpStr = lpDependencies;
while (*lpStr)
{
cchLength = strlen(lpStr) + 1;
dwDependenciesLength += (DWORD)cchLength;
lpStr = lpStr + cchLength;
}
dwDependenciesLength++;
}
if (lpPassword != NULL)
{
/* Convert the password to unicode */
lpPasswordW = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
(strlen(lpPassword) + 1) * sizeof(WCHAR));
if (lpPasswordW == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
MultiByteToWideChar(CP_ACP,
0,
lpPassword,
-1,
lpPasswordW,
(int)(strlen(lpPassword) + 1));
/* Encrypt the unicode password */
dwError = ScmEncryptPassword(hService,
lpPasswordW,
&lpEncryptedPassword,
&dwPasswordSize);
if (dwError != ERROR_SUCCESS)
goto done;
}
RpcTryExcept
{
dwError = RChangeServiceConfigA((SC_RPC_HANDLE)hService,
dwServiceType,
dwStartType,
dwErrorControl,
(LPSTR)lpBinaryPathName,
(LPSTR)lpLoadOrderGroup,
lpdwTagId,
(LPBYTE)lpDependencies,
dwDependenciesLength,
(LPSTR)lpServiceStartName,
lpEncryptedPassword,
dwPasswordSize,
(LPSTR)lpDisplayName);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
done:
if (lpPasswordW != NULL)
{
/* Wipe and release the password buffers */
SecureZeroMemory(lpPasswordW, (wcslen(lpPasswordW) + 1) * sizeof(WCHAR));
HeapFree(GetProcessHeap(), 0, lpPasswordW);
if (lpEncryptedPassword != NULL)
{
SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
}
}
if (dwError != ERROR_SUCCESS)
{
TRACE("RChangeServiceConfigA() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* ChangeServiceConfigW
*
* @implemented
*/
BOOL WINAPI
ChangeServiceConfigW(SC_HANDLE hService,
DWORD dwServiceType,
DWORD dwStartType,
DWORD dwErrorControl,
LPCWSTR lpBinaryPathName,
LPCWSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCWSTR lpDependencies,
LPCWSTR lpServiceStartName,
LPCWSTR lpPassword,
LPCWSTR lpDisplayName)
{
DWORD dwError;
DWORD dwDependenciesLength = 0;
SIZE_T cchLength;
LPCWSTR lpStr;
DWORD dwPasswordSize = 0;
LPBYTE lpEncryptedPassword = NULL;
TRACE("ChangeServiceConfigW(%p %lu %lu %lu %s %s %p %s %s %s %s)\n",
hService, dwServiceType, dwStartType, dwErrorControl, debugstr_w(lpBinaryPathName),
debugstr_w(lpLoadOrderGroup), lpdwTagId, debugstr_w(lpDependencies),
debugstr_w(lpServiceStartName), debugstr_w(lpPassword), debugstr_w(lpDisplayName));
/* Calculate the Dependencies length*/
if (lpDependencies != NULL)
{
lpStr = lpDependencies;
while (*lpStr)
{
cchLength = wcslen(lpStr) + 1;
dwDependenciesLength += (DWORD)cchLength;
lpStr = lpStr + cchLength;
}
dwDependenciesLength++;
dwDependenciesLength *= sizeof(WCHAR);
}
if (lpPassword != NULL)
{
dwError = ScmEncryptPassword(hService,
lpPassword,
&lpEncryptedPassword,
&dwPasswordSize);
if (dwError != ERROR_SUCCESS)
{
ERR("ScmEncryptPassword failed (Error %lu)\n", dwError);
goto done;
}
}
RpcTryExcept
{
dwError = RChangeServiceConfigW((SC_RPC_HANDLE)hService,
dwServiceType,
dwStartType,
dwErrorControl,
(LPWSTR)lpBinaryPathName,
(LPWSTR)lpLoadOrderGroup,
lpdwTagId,
(LPBYTE)lpDependencies,
dwDependenciesLength,
(LPWSTR)lpServiceStartName,
lpEncryptedPassword,
dwPasswordSize,
(LPWSTR)lpDisplayName);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
done:
if (lpEncryptedPassword != NULL)
{
/* Wipe and release the password buffer */
SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
}
if (dwError != ERROR_SUCCESS)
{
TRACE("RChangeServiceConfigW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* CloseServiceHandle
*
* @implemented
*/
BOOL WINAPI
CloseServiceHandle(SC_HANDLE hSCObject)
{
DWORD dwError;
TRACE("CloseServiceHandle(%p)\n",
hSCObject);
if (!hSCObject)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
RpcTryExcept
{
dwError = RCloseServiceHandle((LPSC_RPC_HANDLE)&hSCObject);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError)
{
TRACE("RCloseServiceHandle() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
TRACE("CloseServiceHandle() done\n");
return TRUE;
}
/**********************************************************************
* ControlService
*
* @implemented
*/
BOOL WINAPI
ControlService(SC_HANDLE hService,
DWORD dwControl,
LPSERVICE_STATUS lpServiceStatus)
{
DWORD dwError;
TRACE("ControlService(%p %lu %p)\n",
hService, dwControl, lpServiceStatus);
RpcTryExcept
{
dwError = RControlService((SC_RPC_HANDLE)hService,
dwControl,
lpServiceStatus);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RControlService() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
TRACE("ControlService() done\n");
return TRUE;
}
/**********************************************************************
* ControlServiceEx
*
* @unimplemented
*/
BOOL WINAPI
ControlServiceEx(IN SC_HANDLE hService,
IN DWORD dwControl,
IN DWORD dwInfoLevel,
IN OUT PVOID pControlParams)
{
FIXME("ControlServiceEx(%p %lu %lu %p)\n",
hService, dwControl, dwInfoLevel, pControlParams);
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return FALSE;
}
/**********************************************************************
* CreateServiceA
*
* @implemented
*/
SC_HANDLE WINAPI
CreateServiceA(SC_HANDLE hSCManager,
LPCSTR lpServiceName,
LPCSTR lpDisplayName,
DWORD dwDesiredAccess,
DWORD dwServiceType,
DWORD dwStartType,
DWORD dwErrorControl,
LPCSTR lpBinaryPathName,
LPCSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCSTR lpDependencies,
LPCSTR lpServiceStartName,
LPCSTR lpPassword)
{
SC_HANDLE hService = NULL;
DWORD dwDependenciesLength = 0;
DWORD dwError;
SIZE_T cchLength;
LPCSTR lpStr;
DWORD dwPasswordSize = 0;
LPWSTR lpPasswordW = NULL;
LPBYTE lpEncryptedPassword = NULL;
TRACE("CreateServiceA(%p %s %s %lx %lu %lu %lu %s %s %p %s %s %s)\n",
hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName),
dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup), lpdwTagId,
debugstr_a(lpDependencies), debugstr_a(lpServiceStartName), debugstr_a(lpPassword));
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
/* Calculate the Dependencies length */
if (lpDependencies != NULL)
{
lpStr = lpDependencies;
while (*lpStr)
{
cchLength = strlen(lpStr) + 1;
dwDependenciesLength += (DWORD)cchLength;
lpStr = lpStr + cchLength;
}
dwDependenciesLength++;
}
if (lpPassword != NULL)
{
/* Convert the password to unicode */
lpPasswordW = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
(strlen(lpPassword) + 1) * sizeof(WCHAR));
if (lpPasswordW == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
MultiByteToWideChar(CP_ACP,
0,
lpPassword,
-1,
lpPasswordW,
(int)(strlen(lpPassword) + 1));
/* Encrypt the password */
dwError = ScmEncryptPassword(hSCManager,
lpPasswordW,
&lpEncryptedPassword,
&dwPasswordSize);
if (dwError != ERROR_SUCCESS)
goto done;
}
RpcTryExcept
{
dwError = RCreateServiceA((SC_RPC_HANDLE)hSCManager,
(LPSTR)lpServiceName,
(LPSTR)lpDisplayName,
dwDesiredAccess,
dwServiceType,
dwStartType,
dwErrorControl,
(LPSTR)lpBinaryPathName,
(LPSTR)lpLoadOrderGroup,
lpdwTagId,
(LPBYTE)lpDependencies,
dwDependenciesLength,
(LPSTR)lpServiceStartName,
lpEncryptedPassword,
dwPasswordSize,
(SC_RPC_HANDLE *)&hService);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
done:
if (lpPasswordW != NULL)
{
/* Wipe and release the password buffers */
SecureZeroMemory(lpPasswordW, (wcslen(lpPasswordW) + 1) * sizeof(WCHAR));
HeapFree(GetProcessHeap(), 0, lpPasswordW);
if (lpEncryptedPassword != NULL)
{
SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
}
}
SetLastError(dwError);
if (dwError != ERROR_SUCCESS)
{
TRACE("RCreateServiceA() failed (Error %lu)\n", dwError);
return NULL;
}
return hService;
}
/**********************************************************************
* CreateServiceW
*
* @implemented
*/
SC_HANDLE WINAPI
CreateServiceW(SC_HANDLE hSCManager,
LPCWSTR lpServiceName,
LPCWSTR lpDisplayName,
DWORD dwDesiredAccess,
DWORD dwServiceType,
DWORD dwStartType,
DWORD dwErrorControl,
LPCWSTR lpBinaryPathName,
LPCWSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCWSTR lpDependencies,
LPCWSTR lpServiceStartName,
LPCWSTR lpPassword)
{
SC_HANDLE hService = NULL;
DWORD dwDependenciesLength = 0;
DWORD dwError;
SIZE_T cchLength;
LPCWSTR lpStr;
DWORD dwPasswordSize = 0;
LPBYTE lpEncryptedPassword = NULL;
TRACE("CreateServiceW(%p %s %s %lx %lu %lu %lu %s %s %p %s %s %s)\n",
hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName),
dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup), lpdwTagId,
debugstr_w(lpDependencies), debugstr_w(lpServiceStartName), debugstr_w(lpPassword));
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
/* Calculate the Dependencies length */
if (lpDependencies != NULL)
{
lpStr = lpDependencies;
while (*lpStr)
{
cchLength = wcslen(lpStr) + 1;
dwDependenciesLength += (DWORD)cchLength;
lpStr = lpStr + cchLength;
}
dwDependenciesLength++;
dwDependenciesLength *= sizeof(WCHAR);
}
if (lpPassword != NULL)
{
/* Encrypt the password */
dwError = ScmEncryptPassword(hSCManager,
lpPassword,
&lpEncryptedPassword,
&dwPasswordSize);
if (dwError != ERROR_SUCCESS)
goto done;
}
RpcTryExcept
{
dwError = RCreateServiceW((SC_RPC_HANDLE)hSCManager,
lpServiceName,
lpDisplayName,
dwDesiredAccess,
dwServiceType,
dwStartType,
dwErrorControl,
lpBinaryPathName,
lpLoadOrderGroup,
lpdwTagId,
(LPBYTE)lpDependencies,
dwDependenciesLength,
lpServiceStartName,
lpEncryptedPassword,
dwPasswordSize,
(SC_RPC_HANDLE *)&hService);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
done:
if (lpEncryptedPassword != NULL)
{
/* Wipe and release the password buffers */
SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
}
SetLastError(dwError);
if (dwError != ERROR_SUCCESS)
{
TRACE("RCreateServiceW() failed (Error %lu)\n", dwError);
return NULL;
}
return hService;
}
/**********************************************************************
* DeleteService
*
* @implemented
*/
BOOL WINAPI
DeleteService(SC_HANDLE hService)
{
DWORD dwError;
TRACE("DeleteService(%p)\n",
hService);
RpcTryExcept
{
dwError = RDeleteService((SC_RPC_HANDLE)hService);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RDeleteService() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* EnumDependentServicesA
*
* @implemented
*/
BOOL WINAPI
EnumDependentServicesA(SC_HANDLE hService,
DWORD dwServiceState,
LPENUM_SERVICE_STATUSA lpServices,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned)
{
ENUM_SERVICE_STATUSA ServiceStatus;
LPENUM_SERVICE_STATUSA lpStatusPtr;
DWORD dwBufferSize;
DWORD dwError;
DWORD dwCount;
TRACE("EnumDependentServicesA(%p %lu %p %lu %p %p)\n",
hService, dwServiceState, lpServices, cbBufSize,
pcbBytesNeeded, lpServicesReturned);
if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSA))
{
lpStatusPtr = &ServiceStatus;
dwBufferSize = sizeof(ENUM_SERVICE_STATUSA);
}
else
{
lpStatusPtr = lpServices;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
dwError = REnumDependentServicesA((SC_RPC_HANDLE)hService,
dwServiceState,
(LPBYTE)lpStatusPtr,
dwBufferSize,
pcbBytesNeeded,
lpServicesReturned);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
{
for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
{
if (lpStatusPtr->lpServiceName)
lpStatusPtr->lpServiceName =
(LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
if (lpStatusPtr->lpDisplayName)
lpStatusPtr->lpDisplayName =
(LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
lpStatusPtr++;
}
}
if (dwError != ERROR_SUCCESS)
{
TRACE("REnumDependentServicesA() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
TRACE("EnumDependentServicesA() done\n");
return TRUE;
}
/**********************************************************************
* EnumDependentServicesW
*
* @implemented
*/
BOOL WINAPI
EnumDependentServicesW(SC_HANDLE hService,
DWORD dwServiceState,
LPENUM_SERVICE_STATUSW lpServices,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned)
{
ENUM_SERVICE_STATUSW ServiceStatus;
LPENUM_SERVICE_STATUSW lpStatusPtr;
DWORD dwBufferSize;
DWORD dwError;
DWORD dwCount;
TRACE("EnumDependentServicesW(%p %lu %p %lu %p %p)\n",
hService, dwServiceState, lpServices, cbBufSize,
pcbBytesNeeded, lpServicesReturned);
if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
{
lpStatusPtr = &ServiceStatus;
dwBufferSize = sizeof(ENUM_SERVICE_STATUSW);
}
else
{
lpStatusPtr = lpServices;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
dwError = REnumDependentServicesW((SC_RPC_HANDLE)hService,
dwServiceState,
(LPBYTE)lpStatusPtr,
dwBufferSize,
pcbBytesNeeded,
lpServicesReturned);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
{
for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
{
if (lpStatusPtr->lpServiceName)
lpStatusPtr->lpServiceName =
(LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
if (lpStatusPtr->lpDisplayName)
lpStatusPtr->lpDisplayName =
(LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
lpStatusPtr++;
}
}
if (dwError != ERROR_SUCCESS)
{
TRACE("REnumDependentServicesW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
TRACE("EnumDependentServicesW() done\n");
return TRUE;
}
/**********************************************************************
* EnumServiceGroupW
*
* @implemented
*/
BOOL WINAPI
EnumServiceGroupW(SC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
LPENUM_SERVICE_STATUSW lpServices,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned,
LPDWORD lpResumeHandle,
LPCWSTR lpGroup)
{
ENUM_SERVICE_STATUSW ServiceStatus;
LPENUM_SERVICE_STATUSW lpStatusPtr;
DWORD dwBufferSize;
DWORD dwError;
DWORD dwCount;
TRACE("EnumServiceGroupW(%p %lu %lu %p %lu %p %p %p %s)\n",
hSCManager, dwServiceType, dwServiceState, lpServices,
cbBufSize, pcbBytesNeeded, lpServicesReturned,
lpResumeHandle, debugstr_w(lpGroup));
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
{
SetLastError(ERROR_INVALID_ADDRESS);
return FALSE;
}
if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
{
lpStatusPtr = &ServiceStatus;
dwBufferSize = sizeof(ENUM_SERVICE_STATUSW);
}
else
{
lpStatusPtr = lpServices;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
if (lpGroup == NULL)
{
dwError = REnumServicesStatusW((SC_RPC_HANDLE)hSCManager,
dwServiceType,
dwServiceState,
(LPBYTE)lpStatusPtr,
dwBufferSize,
pcbBytesNeeded,
lpServicesReturned,
lpResumeHandle);
}
else
{
dwError = REnumServiceGroupW((SC_RPC_HANDLE)hSCManager,
dwServiceType,
dwServiceState,
(LPBYTE)lpStatusPtr,
dwBufferSize,
pcbBytesNeeded,
lpServicesReturned,
lpResumeHandle,
lpGroup);
}
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
{
for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
{
if (lpStatusPtr->lpServiceName)
lpStatusPtr->lpServiceName =
(LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
if (lpStatusPtr->lpDisplayName)
lpStatusPtr->lpDisplayName =
(LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
lpStatusPtr++;
}
}
if (dwError != ERROR_SUCCESS)
{
TRACE("REnumServiceGroupW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
TRACE("EnumServiceGroupW() done\n");
return TRUE;
}
/**********************************************************************
* EnumServicesStatusA
*
* @implemented
*/
BOOL WINAPI
EnumServicesStatusA(SC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
LPENUM_SERVICE_STATUSA lpServices,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned,
LPDWORD lpResumeHandle)
{
ENUM_SERVICE_STATUSA ServiceStatus;
LPENUM_SERVICE_STATUSA lpStatusPtr;
DWORD dwBufferSize;
DWORD dwError;
DWORD dwCount;
TRACE("EnumServicesStatusA(%p %lu %lu %p %lu %p %p %p)\n",
hSCManager, dwServiceType, dwServiceState, lpServices,
cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
{
SetLastError(ERROR_INVALID_ADDRESS);
return FALSE;
}
if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSA))
{
lpStatusPtr = &ServiceStatus;
dwBufferSize = sizeof(ENUM_SERVICE_STATUSA);
}
else
{
lpStatusPtr = lpServices;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
dwError = REnumServicesStatusA((SC_RPC_HANDLE)hSCManager,
dwServiceType,
dwServiceState,
(LPBYTE)lpStatusPtr,
dwBufferSize,
pcbBytesNeeded,
lpServicesReturned,
lpResumeHandle);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
{
for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
{
if (lpStatusPtr->lpServiceName)
lpStatusPtr->lpServiceName =
(LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
if (lpStatusPtr->lpDisplayName)
lpStatusPtr->lpDisplayName =
(LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
lpStatusPtr++;
}
}
if (dwError != ERROR_SUCCESS)
{
TRACE("REnumServicesStatusA() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
TRACE("EnumServicesStatusA() done\n");
return TRUE;
}
/**********************************************************************
* EnumServicesStatusW
*
* @implemented
*/
BOOL WINAPI
EnumServicesStatusW(SC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
LPENUM_SERVICE_STATUSW lpServices,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned,
LPDWORD lpResumeHandle)
{
ENUM_SERVICE_STATUSW ServiceStatus;
LPENUM_SERVICE_STATUSW lpStatusPtr;
DWORD dwBufferSize;
DWORD dwError;
DWORD dwCount;
TRACE("EnumServicesStatusW(%p %lu %lu %p %lu %p %p %p)\n",
hSCManager, dwServiceType, dwServiceState, lpServices,
cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
{
SetLastError(ERROR_INVALID_ADDRESS);
return FALSE;
}
if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
{
lpStatusPtr = &ServiceStatus;
dwBufferSize = sizeof(ENUM_SERVICE_STATUSW);
}
else
{
lpStatusPtr = lpServices;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
dwError = REnumServicesStatusW((SC_RPC_HANDLE)hSCManager,
dwServiceType,
dwServiceState,
(LPBYTE)lpStatusPtr,
dwBufferSize,
pcbBytesNeeded,
lpServicesReturned,
lpResumeHandle);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
{
for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
{
if (lpStatusPtr->lpServiceName)
lpStatusPtr->lpServiceName =
(LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
if (lpStatusPtr->lpDisplayName)
lpStatusPtr->lpDisplayName =
(LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
lpStatusPtr++;
}
}
if (dwError != ERROR_SUCCESS)
{
TRACE("REnumServicesStatusW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
TRACE("EnumServicesStatusW() done\n");
return TRUE;
}
/**********************************************************************
* EnumServicesStatusExA
*
* @implemented
*/
BOOL WINAPI
EnumServicesStatusExA(SC_HANDLE hSCManager,
SC_ENUM_TYPE InfoLevel,
DWORD dwServiceType,
DWORD dwServiceState,
LPBYTE lpServices,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned,
LPDWORD lpResumeHandle,
LPCSTR pszGroupName)
{
ENUM_SERVICE_STATUS_PROCESSA ServiceStatus;
LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtr;
DWORD dwBufferSize;
DWORD dwError;
DWORD dwCount;
TRACE("EnumServicesStatusExA(%p %lu %lu %p %lu %p %p %p %s)\n",
hSCManager, dwServiceType, dwServiceState, lpServices,
cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle,
debugstr_a(pszGroupName));
if (InfoLevel != SC_ENUM_PROCESS_INFO)
{
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
{
SetLastError(ERROR_INVALID_ADDRESS);
return FALSE;
}
if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUS_PROCESSA))
{
lpStatusPtr = &ServiceStatus;
dwBufferSize = sizeof(ENUM_SERVICE_STATUS_PROCESSA);
}
else
{
lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSA)lpServices;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
dwError = REnumServicesStatusExA((SC_RPC_HANDLE)hSCManager,
InfoLevel,
dwServiceType,
dwServiceState,
(LPBYTE)lpStatusPtr,
dwBufferSize,
pcbBytesNeeded,
lpServicesReturned,
lpResumeHandle,
(LPSTR)pszGroupName);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
{
if (InfoLevel == SC_ENUM_PROCESS_INFO)
{
for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
{
if (lpStatusPtr->lpServiceName)
lpStatusPtr->lpServiceName =
(LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
if (lpStatusPtr->lpDisplayName)
lpStatusPtr->lpDisplayName =
(LPSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
lpStatusPtr++;
}
}
}
if (dwError != ERROR_SUCCESS)
{
TRACE("REnumServicesStatusExA() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
TRACE("EnumServicesStatusExA() done\n");
return TRUE;
}
/**********************************************************************
* EnumServicesStatusExW
*
* @implemented
*/
BOOL WINAPI
EnumServicesStatusExW(SC_HANDLE hSCManager,
SC_ENUM_TYPE InfoLevel,
DWORD dwServiceType,
DWORD dwServiceState,
LPBYTE lpServices,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned,
LPDWORD lpResumeHandle,
LPCWSTR pszGroupName)
{
ENUM_SERVICE_STATUS_PROCESSW ServiceStatus;
LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
DWORD dwBufferSize;
DWORD dwError;
DWORD dwCount;
TRACE("EnumServicesStatusExW(%p %lu %lu %p %lu %p %p %p %s)\n",
hSCManager, dwServiceType, dwServiceState, lpServices,
cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle,
debugstr_w(pszGroupName));
if (InfoLevel != SC_ENUM_PROCESS_INFO)
{
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
{
SetLastError(ERROR_INVALID_ADDRESS);
return FALSE;
}
if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUS_PROCESSW))
{
lpStatusPtr = &ServiceStatus;
dwBufferSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW);
}
else
{
lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpServices;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
dwError = REnumServicesStatusExW((SC_RPC_HANDLE)hSCManager,
InfoLevel,
dwServiceType,
dwServiceState,
(LPBYTE)lpStatusPtr,
dwBufferSize,
pcbBytesNeeded,
lpServicesReturned,
lpResumeHandle,
(LPWSTR)pszGroupName);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError == ERROR_SUCCESS || dwError == ERROR_MORE_DATA)
{
if (InfoLevel == SC_ENUM_PROCESS_INFO)
{
for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
{
if (lpStatusPtr->lpServiceName)
lpStatusPtr->lpServiceName =
(LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
if (lpStatusPtr->lpDisplayName)
lpStatusPtr->lpDisplayName =
(LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
lpStatusPtr++;
}
}
}
if (dwError != ERROR_SUCCESS)
{
TRACE("REnumServicesStatusExW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
TRACE("EnumServicesStatusExW() done\n");
return TRUE;
}
/**********************************************************************
* GetServiceDisplayNameA
*
* @implemented
*/
BOOL WINAPI
GetServiceDisplayNameA(SC_HANDLE hSCManager,
LPCSTR lpServiceName,
LPSTR lpDisplayName,
LPDWORD lpcchBuffer)
{
DWORD dwError;
LPSTR lpNameBuffer;
CHAR szEmptyName[] = "";
TRACE("GetServiceDisplayNameA(%p %s %p %p)\n",
hSCManager, debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!lpDisplayName || *lpcchBuffer < sizeof(CHAR))
{
lpNameBuffer = szEmptyName;
*lpcchBuffer = sizeof(CHAR);
}
else
{
lpNameBuffer = lpDisplayName;
}
RpcTryExcept
{
dwError = RGetServiceDisplayNameA((SC_RPC_HANDLE)hSCManager,
lpServiceName,
lpNameBuffer,
lpcchBuffer);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RGetServiceDisplayNameA() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* GetServiceDisplayNameW
*
* @implemented
*/
BOOL WINAPI
GetServiceDisplayNameW(SC_HANDLE hSCManager,
LPCWSTR lpServiceName,
LPWSTR lpDisplayName,
LPDWORD lpcchBuffer)
{
DWORD dwError;
LPWSTR lpNameBuffer;
WCHAR szEmptyName[] = L"";
TRACE("GetServiceDisplayNameW(%p %s %p %p)\n",
hSCManager, debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
/*
* NOTE: A size of 1 character would be enough, but tests show that
* Windows returns 2 characters instead, certainly due to a WCHAR/bytes
* mismatch in their code.
*/
if (!lpDisplayName || *lpcchBuffer < sizeof(WCHAR))
{
lpNameBuffer = szEmptyName;
*lpcchBuffer = sizeof(WCHAR);
}
else
{
lpNameBuffer = lpDisplayName;
}
RpcTryExcept
{
dwError = RGetServiceDisplayNameW((SC_RPC_HANDLE)hSCManager,
lpServiceName,
lpNameBuffer,
lpcchBuffer);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RGetServiceDisplayNameW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* GetServiceKeyNameA
*
* @implemented
*/
BOOL WINAPI
GetServiceKeyNameA(SC_HANDLE hSCManager,
LPCSTR lpDisplayName,
LPSTR lpServiceName,
LPDWORD lpcchBuffer)
{
DWORD dwError;
LPSTR lpNameBuffer;
CHAR szEmptyName[] = "";
TRACE("GetServiceKeyNameA(%p %s %p %p)\n",
hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (!lpServiceName || *lpcchBuffer < sizeof(CHAR))
{
lpNameBuffer = szEmptyName;
*lpcchBuffer = sizeof(CHAR);
}
else
{
lpNameBuffer = lpServiceName;
}
RpcTryExcept
{
dwError = RGetServiceKeyNameA((SC_RPC_HANDLE)hSCManager,
lpDisplayName,
lpNameBuffer,
lpcchBuffer);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
/* HACK: because of a problem with rpcrt4, rpcserver is hacked to return 6 for ERROR_SERVICE_DOES_NOT_EXIST */
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RGetServiceKeyNameA() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* GetServiceKeyNameW
*
* @implemented
*/
BOOL WINAPI
GetServiceKeyNameW(SC_HANDLE hSCManager,
LPCWSTR lpDisplayName,
LPWSTR lpServiceName,
LPDWORD lpcchBuffer)
{
DWORD dwError;
LPWSTR lpNameBuffer;
WCHAR szEmptyName[] = L"";
TRACE("GetServiceKeyNameW(%p %s %p %p)\n",
hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
/*
* NOTE: A size of 1 character would be enough, but tests show that
* Windows returns 2 characters instead, certainly due to a WCHAR/bytes
* mismatch in their code.
*/
if (!lpServiceName || *lpcchBuffer < sizeof(WCHAR))
{
lpNameBuffer = szEmptyName;
*lpcchBuffer = sizeof(WCHAR);
}
else
{
lpNameBuffer = lpServiceName;
}
RpcTryExcept
{
dwError = RGetServiceKeyNameW((SC_RPC_HANDLE)hSCManager,
lpDisplayName,
lpNameBuffer,
lpcchBuffer);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RGetServiceKeyNameW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* I_ScGetCurrentGroupStateW
*
* @implemented
*/
DWORD WINAPI
I_ScGetCurrentGroupStateW(SC_HANDLE hSCManager,
LPWSTR pszGroupName,
LPDWORD pdwGroupState)
{
DWORD dwError;
TRACE("I_ScGetCurrentGroupStateW(%p %s %p)\n",
hSCManager, debugstr_w(pszGroupName), pdwGroupState);
RpcTryExcept
{
dwError = RI_ScGetCurrentGroupStateW((SC_RPC_HANDLE)hSCManager,
pszGroupName,
pdwGroupState);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept
if (dwError != ERROR_SUCCESS)
{
TRACE("RI_ScGetCurrentGroupStateW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
}
return dwError;
}
/**********************************************************************
* I_ScValidatePnpService
*
* Undocumented
*
* @implemented
*/
DWORD
WINAPI
I_ScValidatePnpService(
_In_ LPCWSTR pszMachineName,
_In_ LPCWSTR pszServiceName,
_Out_ SERVICE_STATUS_HANDLE *phServiceStatus)
{
SC_RPC_HANDLE hSCManager = NULL;
SERVICE_STATUS_HANDLE hServiceStatus = NULL;
DWORD dwError;
TRACE("I_ScValidatePnpService(%S %S %p)\n",
pszMachineName, pszServiceName, phServiceStatus);
hSCManager = OpenSCManagerW(pszMachineName,
SERVICES_ACTIVE_DATABASEW,
SC_MANAGER_CONNECT);
if (hSCManager == NULL)
{
dwError = GetLastError();
goto done;
}
RpcTryExcept
{
dwError = RI_ScValidatePnPService(hSCManager,
(LPWSTR)pszServiceName,
(RPC_SERVICE_STATUS_HANDLE *)&hServiceStatus);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept
*phServiceStatus = hServiceStatus;
done:
if (hSCManager != NULL)
CloseServiceHandle(hSCManager);
return dwError;
}
/**********************************************************************
* LockServiceDatabase
*
* @implemented
*/
SC_LOCK WINAPI
LockServiceDatabase(SC_HANDLE hSCManager)
{
SC_LOCK hLock;
DWORD dwError;
TRACE("LockServiceDatabase(%p)\n",
hSCManager);
RpcTryExcept
{
dwError = RLockServiceDatabase((SC_RPC_HANDLE)hSCManager,
(SC_RPC_LOCK *)&hLock);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RLockServiceDatabase() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return NULL;
}
TRACE("hLock = %p\n", hLock);
return hLock;
}
static VOID
WaitForSCManager(VOID)
{
HANDLE hEvent;
TRACE("WaitForSCManager()\n");
/* Try to open the existing event */
hEvent = OpenEventW(SYNCHRONIZE, FALSE, SCM_START_EVENT);
if (hEvent == NULL)
{
if (GetLastError() != ERROR_FILE_NOT_FOUND)
return;
/* Try to create a new event */
hEvent = CreateEventW(NULL, TRUE, FALSE, SCM_START_EVENT);
if (hEvent == NULL)
return;
}
/* Wait for 3 minutes */
WaitForSingleObject(hEvent, 180000);
CloseHandle(hEvent);
TRACE("ScmWaitForSCManager() done\n");
}
/**********************************************************************
* OpenSCManagerA
*
* @implemented
*/
SC_HANDLE WINAPI
OpenSCManagerA(LPCSTR lpMachineName,
LPCSTR lpDatabaseName,
DWORD dwDesiredAccess)
{
SC_HANDLE hScm = NULL;
DWORD dwError;
TRACE("OpenSCManagerA(%s %s %lx)\n",
debugstr_a(lpMachineName), debugstr_a(lpDatabaseName), dwDesiredAccess);
WaitForSCManager();
RpcTryExcept
{
dwError = ROpenSCManagerA((LPSTR)lpMachineName,
(LPSTR)lpDatabaseName,
dwDesiredAccess,
(SC_RPC_HANDLE *)&hScm);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
SetLastError(dwError);
if (dwError != ERROR_SUCCESS)
{
TRACE("ROpenSCManagerA() failed (Error %lu)\n", dwError);
return NULL;
}
TRACE("hScm = %p\n", hScm);
return hScm;
}
/**********************************************************************
* OpenSCManagerW
*
* @implemented
*/
SC_HANDLE WINAPI
OpenSCManagerW(LPCWSTR lpMachineName,
LPCWSTR lpDatabaseName,
DWORD dwDesiredAccess)
{
SC_HANDLE hScm = NULL;
DWORD dwError;
TRACE("OpenSCManagerW(%s %s %lx)\n",
debugstr_w(lpMachineName), debugstr_w(lpDatabaseName), dwDesiredAccess);
WaitForSCManager();
RpcTryExcept
{
dwError = ROpenSCManagerW((LPWSTR)lpMachineName,
(LPWSTR)lpDatabaseName,
dwDesiredAccess,
(SC_RPC_HANDLE *)&hScm);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
SetLastError(dwError);
if (dwError != ERROR_SUCCESS)
{
TRACE("ROpenSCManagerW() failed (Error %lu)\n", dwError);
return NULL;
}
TRACE("hScm = %p\n", hScm);
return hScm;
}
/**********************************************************************
* OpenServiceA
*
* @implemented
*/
SC_HANDLE WINAPI
OpenServiceA(SC_HANDLE hSCManager,
LPCSTR lpServiceName,
DWORD dwDesiredAccess)
{
SC_HANDLE hService = NULL;
DWORD dwError;
TRACE("OpenServiceA(%p %s %lx)\n",
hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
RpcTryExcept
{
dwError = ROpenServiceA((SC_RPC_HANDLE)hSCManager,
(LPSTR)lpServiceName,
dwDesiredAccess,
(SC_RPC_HANDLE *)&hService);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
SetLastError(dwError);
if (dwError != ERROR_SUCCESS)
{
TRACE("ROpenServiceA() failed (Error %lu)\n", dwError);
return NULL;
}
TRACE("hService = %p\n", hService);
return hService;
}
/**********************************************************************
* OpenServiceW
*
* @implemented
*/
SC_HANDLE WINAPI
OpenServiceW(SC_HANDLE hSCManager,
LPCWSTR lpServiceName,
DWORD dwDesiredAccess)
{
SC_HANDLE hService = NULL;
DWORD dwError;
TRACE("OpenServiceW(%p %s %lx)\n",
hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
if (!hSCManager)
{
SetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
RpcTryExcept
{
dwError = ROpenServiceW((SC_RPC_HANDLE)hSCManager,
(LPWSTR)lpServiceName,
dwDesiredAccess,
(SC_RPC_HANDLE *)&hService);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
SetLastError(dwError);
if (dwError != ERROR_SUCCESS)
{
TRACE("ROpenServiceW() failed (Error %lu)\n", dwError);
return NULL;
}
TRACE("hService = %p\n", hService);
return hService;
}
/**********************************************************************
* QueryServiceConfigA
*
* @implemented
*/
BOOL WINAPI
QueryServiceConfigA(SC_HANDLE hService,
LPQUERY_SERVICE_CONFIGA lpServiceConfig,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded)
{
QUERY_SERVICE_CONFIGA ServiceConfig;
LPQUERY_SERVICE_CONFIGA lpConfigPtr;
DWORD dwBufferSize;
DWORD dwError;
TRACE("QueryServiceConfigA(%p %p %lu %p)\n",
hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
if (lpServiceConfig == NULL ||
cbBufSize < sizeof(QUERY_SERVICE_CONFIGA))
{
lpConfigPtr = &ServiceConfig;
dwBufferSize = sizeof(QUERY_SERVICE_CONFIGA);
}
else
{
lpConfigPtr = lpServiceConfig;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
dwError = RQueryServiceConfigA((SC_RPC_HANDLE)hService,
(LPBYTE)lpConfigPtr,
dwBufferSize,
pcbBytesNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RQueryServiceConfigA() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
/* Adjust the pointers */
if (lpConfigPtr->lpBinaryPathName)
lpConfigPtr->lpBinaryPathName =
(LPSTR)((ULONG_PTR)lpConfigPtr +
(ULONG_PTR)lpConfigPtr->lpBinaryPathName);
if (lpConfigPtr->lpLoadOrderGroup)
lpConfigPtr->lpLoadOrderGroup =
(LPSTR)((ULONG_PTR)lpConfigPtr +
(ULONG_PTR)lpConfigPtr->lpLoadOrderGroup);
if (lpConfigPtr->lpDependencies)
lpConfigPtr->lpDependencies =
(LPSTR)((ULONG_PTR)lpConfigPtr +
(ULONG_PTR)lpConfigPtr->lpDependencies);
if (lpConfigPtr->lpServiceStartName)
lpConfigPtr->lpServiceStartName =
(LPSTR)((ULONG_PTR)lpConfigPtr +
(ULONG_PTR)lpConfigPtr->lpServiceStartName);
if (lpConfigPtr->lpDisplayName)
lpConfigPtr->lpDisplayName =
(LPSTR)((ULONG_PTR)lpConfigPtr +
(ULONG_PTR)lpConfigPtr->lpDisplayName);
TRACE("QueryServiceConfigA() done\n");
return TRUE;
}
/**********************************************************************
* QueryServiceConfigW
*
* @implemented
*/
BOOL WINAPI
QueryServiceConfigW(SC_HANDLE hService,
LPQUERY_SERVICE_CONFIGW lpServiceConfig,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded)
{
QUERY_SERVICE_CONFIGW ServiceConfig;
LPQUERY_SERVICE_CONFIGW lpConfigPtr;
DWORD dwBufferSize;
DWORD dwError;
TRACE("QueryServiceConfigW(%p %p %lu %p)\n",
hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
if (lpServiceConfig == NULL ||
cbBufSize < sizeof(QUERY_SERVICE_CONFIGW))
{
lpConfigPtr = &ServiceConfig;
dwBufferSize = sizeof(QUERY_SERVICE_CONFIGW);
}
else
{
lpConfigPtr = lpServiceConfig;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
dwError = RQueryServiceConfigW((SC_RPC_HANDLE)hService,
(LPBYTE)lpConfigPtr,
dwBufferSize,
pcbBytesNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RQueryServiceConfigW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
/* Adjust the pointers */
if (lpConfigPtr->lpBinaryPathName)
lpConfigPtr->lpBinaryPathName =
(LPWSTR)((ULONG_PTR)lpConfigPtr +
(ULONG_PTR)lpConfigPtr->lpBinaryPathName);
if (lpConfigPtr->lpLoadOrderGroup)
lpConfigPtr->lpLoadOrderGroup =
(LPWSTR)((ULONG_PTR)lpConfigPtr +
(ULONG_PTR)lpConfigPtr->lpLoadOrderGroup);
if (lpConfigPtr->lpDependencies)
lpConfigPtr->lpDependencies =
(LPWSTR)((ULONG_PTR)lpConfigPtr +
(ULONG_PTR)lpConfigPtr->lpDependencies);
if (lpConfigPtr->lpServiceStartName)
lpConfigPtr->lpServiceStartName =
(LPWSTR)((ULONG_PTR)lpConfigPtr +
(ULONG_PTR)lpConfigPtr->lpServiceStartName);
if (lpConfigPtr->lpDisplayName)
lpConfigPtr->lpDisplayName =
(LPWSTR)((ULONG_PTR)lpConfigPtr +
(ULONG_PTR)lpConfigPtr->lpDisplayName);
TRACE("QueryServiceConfigW() done\n");
return TRUE;
}
/**********************************************************************
* QueryServiceConfig2A
*
* @implemented
*/
BOOL WINAPI
QueryServiceConfig2A(SC_HANDLE hService,
DWORD dwInfoLevel,
LPBYTE lpBuffer,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded)
{
SERVICE_DESCRIPTIONA ServiceDescription;
SERVICE_FAILURE_ACTIONSA ServiceFailureActions;
LPBYTE lpTempBuffer;
BOOL bUseTempBuffer = FALSE;
DWORD dwBufferSize;
DWORD dwError;
TRACE("QueryServiceConfig2A(%p %lu %p %lu %p)\n",
hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
lpTempBuffer = lpBuffer;
dwBufferSize = cbBufSize;
switch (dwInfoLevel)
{
case SERVICE_CONFIG_DESCRIPTION:
if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_DESCRIPTIONA)))
{
lpTempBuffer = (LPBYTE)&ServiceDescription;
dwBufferSize = sizeof(SERVICE_DESCRIPTIONA);
bUseTempBuffer = TRUE;
}
break;
case SERVICE_CONFIG_FAILURE_ACTIONS:
if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_FAILURE_ACTIONSA)))
{
lpTempBuffer = (LPBYTE)&ServiceFailureActions;
dwBufferSize = sizeof(SERVICE_FAILURE_ACTIONSA);
bUseTempBuffer = TRUE;
}
break;
default:
WARN("Unknown info level 0x%lx\n", dwInfoLevel);
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
RpcTryExcept
{
dwError = RQueryServiceConfig2A((SC_RPC_HANDLE)hService,
dwInfoLevel,
lpTempBuffer,
dwBufferSize,
pcbBytesNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RQueryServiceConfig2A() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
if (bUseTempBuffer != FALSE)
{
TRACE("RQueryServiceConfig2A() returns ERROR_INSUFFICIENT_BUFFER\n");
*pcbBytesNeeded = dwBufferSize;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
switch (dwInfoLevel)
{
case SERVICE_CONFIG_DESCRIPTION:
{
LPSERVICE_DESCRIPTIONA lpPtr = (LPSERVICE_DESCRIPTIONA)lpTempBuffer;
if (lpPtr->lpDescription != NULL)
lpPtr->lpDescription =
(LPSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpDescription);
}
break;
case SERVICE_CONFIG_FAILURE_ACTIONS:
{
LPSERVICE_FAILURE_ACTIONSA lpPtr = (LPSERVICE_FAILURE_ACTIONSA)lpTempBuffer;
if (lpPtr->lpRebootMsg != NULL)
lpPtr->lpRebootMsg =
(LPSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpRebootMsg);
if (lpPtr->lpCommand != NULL)
lpPtr->lpCommand =
(LPSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpCommand);
if (lpPtr->lpsaActions != NULL)
lpPtr->lpsaActions =
(LPSC_ACTION)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpsaActions);
}
break;
}
TRACE("QueryServiceConfig2A() done\n");
return TRUE;
}
/**********************************************************************
* QueryServiceConfig2W
*
* @implemented
*/
BOOL WINAPI
QueryServiceConfig2W(SC_HANDLE hService,
DWORD dwInfoLevel,
LPBYTE lpBuffer,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded)
{
SERVICE_DESCRIPTIONW ServiceDescription;
SERVICE_FAILURE_ACTIONSW ServiceFailureActions;
LPBYTE lpTempBuffer;
BOOL bUseTempBuffer = FALSE;
DWORD dwBufferSize;
DWORD dwError;
TRACE("QueryServiceConfig2W(%p %lu %p %lu %p)\n",
hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
lpTempBuffer = lpBuffer;
dwBufferSize = cbBufSize;
switch (dwInfoLevel)
{
case SERVICE_CONFIG_DESCRIPTION:
if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_DESCRIPTIONW)))
{
lpTempBuffer = (LPBYTE)&ServiceDescription;
dwBufferSize = sizeof(SERVICE_DESCRIPTIONW);
bUseTempBuffer = TRUE;
}
break;
case SERVICE_CONFIG_FAILURE_ACTIONS:
if ((lpBuffer == NULL) || (cbBufSize < sizeof(SERVICE_FAILURE_ACTIONSW)))
{
lpTempBuffer = (LPBYTE)&ServiceFailureActions;
dwBufferSize = sizeof(SERVICE_FAILURE_ACTIONSW);
bUseTempBuffer = TRUE;
}
break;
default:
WARN("Unknown info level 0x%lx\n", dwInfoLevel);
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
RpcTryExcept
{
dwError = RQueryServiceConfig2W((SC_RPC_HANDLE)hService,
dwInfoLevel,
lpTempBuffer,
dwBufferSize,
pcbBytesNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RQueryServiceConfig2W() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
if (bUseTempBuffer != FALSE)
{
TRACE("RQueryServiceConfig2W() returns ERROR_INSUFFICIENT_BUFFER\n");
*pcbBytesNeeded = dwBufferSize;
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
switch (dwInfoLevel)
{
case SERVICE_CONFIG_DESCRIPTION:
{
LPSERVICE_DESCRIPTIONW lpPtr = (LPSERVICE_DESCRIPTIONW)lpTempBuffer;
if (lpPtr->lpDescription != NULL)
lpPtr->lpDescription =
(LPWSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpDescription);
}
break;
case SERVICE_CONFIG_FAILURE_ACTIONS:
{
LPSERVICE_FAILURE_ACTIONSW lpPtr = (LPSERVICE_FAILURE_ACTIONSW)lpTempBuffer;
if (lpPtr->lpRebootMsg != NULL)
lpPtr->lpRebootMsg =
(LPWSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpRebootMsg);
if (lpPtr->lpCommand != NULL)
lpPtr->lpCommand =
(LPWSTR)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpCommand);
if (lpPtr->lpsaActions != NULL)
lpPtr->lpsaActions =
(LPSC_ACTION)((ULONG_PTR)lpPtr + (ULONG_PTR)lpPtr->lpsaActions);
}
break;
}
TRACE("QueryServiceConfig2W() done\n");
return TRUE;
}
/**********************************************************************
* QueryServiceLockStatusA
*
* @implemented
*/
BOOL WINAPI
QueryServiceLockStatusA(SC_HANDLE hSCManager,
LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded)
{
QUERY_SERVICE_LOCK_STATUSA LockStatus;
LPQUERY_SERVICE_LOCK_STATUSA lpStatusPtr;
DWORD dwBufferSize;
DWORD dwError;
TRACE("QueryServiceLockStatusA(%p %p %lu %p)\n",
hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
if (lpLockStatus == NULL || cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSA))
{
lpStatusPtr = &LockStatus;
dwBufferSize = sizeof(QUERY_SERVICE_LOCK_STATUSA);
}
else
{
lpStatusPtr = lpLockStatus;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
dwError = RQueryServiceLockStatusA((SC_RPC_HANDLE)hSCManager,
(LPBYTE)lpStatusPtr,
dwBufferSize,
pcbBytesNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RQueryServiceLockStatusA() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
if (lpStatusPtr->lpLockOwner != NULL)
{
lpStatusPtr->lpLockOwner =
(LPSTR)((ULONG_PTR)lpStatusPtr + (ULONG_PTR)lpStatusPtr->lpLockOwner);
}
TRACE("QueryServiceLockStatusA() done\n");
return TRUE;
}
/**********************************************************************
* QueryServiceLockStatusW
*
* @implemented
*/
BOOL WINAPI
QueryServiceLockStatusW(SC_HANDLE hSCManager,
LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded)
{
QUERY_SERVICE_LOCK_STATUSW LockStatus;
LPQUERY_SERVICE_LOCK_STATUSW lpStatusPtr;
DWORD dwBufferSize;
DWORD dwError;
TRACE("QueryServiceLockStatusW(%p %p %lu %p)\n",
hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
if (lpLockStatus == NULL || cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSW))
{
lpStatusPtr = &LockStatus;
dwBufferSize = sizeof(QUERY_SERVICE_LOCK_STATUSW);
}
else
{
lpStatusPtr = lpLockStatus;
dwBufferSize = cbBufSize;
}
RpcTryExcept
{
dwError = RQueryServiceLockStatusW((SC_RPC_HANDLE)hSCManager,
(LPBYTE)lpStatusPtr,
dwBufferSize,
pcbBytesNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RQueryServiceLockStatusW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
if (lpStatusPtr->lpLockOwner != NULL)
{
lpStatusPtr->lpLockOwner =
(LPWSTR)((ULONG_PTR)lpStatusPtr + (ULONG_PTR)lpStatusPtr->lpLockOwner);
}
TRACE("QueryServiceLockStatusW() done\n");
return TRUE;
}
/**********************************************************************
* QueryServiceObjectSecurity
*
* @implemented
*/
BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService,
SECURITY_INFORMATION dwSecurityInformation,
PSECURITY_DESCRIPTOR lpSecurityDescriptor,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded)
{
DWORD dwError;
TRACE("QueryServiceObjectSecurity(%p %lu %p)\n",
hService, dwSecurityInformation, lpSecurityDescriptor);
RpcTryExcept
{
dwError = RQueryServiceObjectSecurity((SC_RPC_HANDLE)hService,
dwSecurityInformation,
(LPBYTE)lpSecurityDescriptor,
cbBufSize,
pcbBytesNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("QueryServiceObjectSecurity() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* SetServiceObjectSecurity
*
* @implemented
*/
BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService,
SECURITY_INFORMATION dwSecurityInformation,
PSECURITY_DESCRIPTOR lpSecurityDescriptor)
{
PSECURITY_DESCRIPTOR SelfRelativeSD = NULL;
ULONG Length;
NTSTATUS Status;
DWORD dwError;
TRACE("SetServiceObjectSecurity(%p %lu %p)\n",
hService, dwSecurityInformation, lpSecurityDescriptor);
Length = 0;
Status = RtlMakeSelfRelativeSD(lpSecurityDescriptor,
SelfRelativeSD,
&Length);
if (Status != STATUS_BUFFER_TOO_SMALL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
SelfRelativeSD = HeapAlloc(GetProcessHeap(), 0, Length);
if (SelfRelativeSD == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
Status = RtlMakeSelfRelativeSD(lpSecurityDescriptor,
SelfRelativeSD,
&Length);
if (!NT_SUCCESS(Status))
{
HeapFree(GetProcessHeap(), 0, SelfRelativeSD);
SetLastError(RtlNtStatusToDosError(Status));
return FALSE;
}
RpcTryExcept
{
dwError = RSetServiceObjectSecurity((SC_RPC_HANDLE)hService,
dwSecurityInformation,
(LPBYTE)SelfRelativeSD,
Length);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
HeapFree(GetProcessHeap(), 0, SelfRelativeSD);
if (dwError != ERROR_SUCCESS)
{
TRACE("RServiceObjectSecurity() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* QueryServiceStatus
*
* @implemented
*/
BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService,
LPSERVICE_STATUS lpServiceStatus)
{
DWORD dwError;
TRACE("QueryServiceStatus(%p %p)\n",
hService, lpServiceStatus);
if (!hService)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
RpcTryExcept
{
dwError = RQueryServiceStatus((SC_RPC_HANDLE)hService,
lpServiceStatus);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RQueryServiceStatus() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* QueryServiceStatusEx
*
* @implemented
*/
BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService,
SC_STATUS_TYPE InfoLevel,
LPBYTE lpBuffer,
DWORD cbBufSize,
LPDWORD pcbBytesNeeded)
{
DWORD dwError;
TRACE("QueryServiceStatusEx(%p %lu %p %lu %p)\n",
hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
if (InfoLevel != SC_STATUS_PROCESS_INFO)
{
SetLastError(ERROR_INVALID_LEVEL);
return FALSE;
}
if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
{
*pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
RpcTryExcept
{
dwError = RQueryServiceStatusEx((SC_RPC_HANDLE)hService,
InfoLevel,
lpBuffer,
cbBufSize,
pcbBytesNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("RQueryServiceStatusEx() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* StartServiceA
*
* @implemented
*/
BOOL WINAPI
StartServiceA(SC_HANDLE hService,
DWORD dwNumServiceArgs,
LPCSTR *lpServiceArgVectors)
{
DWORD dwError;
TRACE("StartServiceA(%p %lu %p)\n",
hService, dwNumServiceArgs, lpServiceArgVectors);
RpcTryExcept
{
dwError = RStartServiceA((SC_RPC_HANDLE)hService,
dwNumServiceArgs,
(LPSTRING_PTRSA)lpServiceArgVectors);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
ERR("RStartServiceA() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* StartServiceW
*
* @implemented
*/
BOOL WINAPI
StartServiceW(SC_HANDLE hService,
DWORD dwNumServiceArgs,
LPCWSTR *lpServiceArgVectors)
{
DWORD dwError;
TRACE("StartServiceW(%p %lu %p)\n",
hService, dwNumServiceArgs, lpServiceArgVectors);
RpcTryExcept
{
dwError = RStartServiceW((SC_RPC_HANDLE)hService,
dwNumServiceArgs,
(LPSTRING_PTRSW)lpServiceArgVectors);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
ERR("RStartServiceW() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* UnlockServiceDatabase
*
* @implemented
*/
BOOL WINAPI
UnlockServiceDatabase(SC_LOCK ScLock)
{
DWORD dwError;
TRACE("UnlockServiceDatabase(%x)\n",
ScLock);
RpcTryExcept
{
dwError = RUnlockServiceDatabase((LPSC_RPC_LOCK)&ScLock);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError == ERROR_INVALID_HANDLE)
dwError = ERROR_INVALID_SERVICE_LOCK;
if (dwError != ERROR_SUCCESS)
{
TRACE("RUnlockServiceDatabase() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
/**********************************************************************
* NotifyBootConfigStatus
*
* @implemented
*/
BOOL WINAPI
NotifyBootConfigStatus(BOOL BootAcceptable)
{
DWORD dwError;
TRACE("NotifyBootConfigStatus(%u)\n",
BootAcceptable);
RpcTryExcept
{
dwError = RNotifyBootConfigStatus(NULL,
BootAcceptable);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
if (dwError != ERROR_SUCCESS)
{
TRACE("NotifyBootConfigStatus() failed (Error %lu)\n", dwError);
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
DWORD
I_ScQueryServiceTagInfo(PVOID Unused,
TAG_INFO_LEVEL dwInfoLevel,
PTAG_INFO_NAME_FROM_TAG InOutParams)
{
SC_HANDLE hScm;
DWORD dwError;
PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams;
PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutParams;
LPWSTR lpszName;
/* We only support one class */
if (dwInfoLevel != TagInfoLevelNameFromTag)
{
return ERROR_RETRY;
}
/* Validate input structure */
if (InOutParams->InParams.dwPid == 0 || InOutParams->InParams.dwTag == 0)
{
return ERROR_INVALID_PARAMETER;
}
/* Validate output structure */
if (InOutParams->OutParams.pszName != NULL)
{
return ERROR_INVALID_PARAMETER;
}
/* Open service manager */
hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if (hScm == NULL)
{
return GetLastError();
}
/* Setup call parameters */
InParams = &InOutParams->InParams;
OutParams = NULL;
/* Call SCM to query tag information */
RpcTryExcept
{
dwError = RI_ScQueryServiceTagInfo(hScm, TagInfoLevelNameFromTag, &InParams, &OutParams);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
}
RpcEndExcept;
/* Quit if not a success */
if (dwError != ERROR_SUCCESS)
{
goto Cleanup;
}
/* OutParams must be set now and we must have a name */
if (OutParams == NULL ||
OutParams->pszName == NULL)
{
dwError = ERROR_INVALID_DATA;
goto Cleanup;
}
/* Copy back what SCM returned */
lpszName = LocalAlloc(LPTR,
sizeof(WCHAR) * wcslen(OutParams->pszName) + sizeof(UNICODE_NULL));
if (lpszName == NULL)
{
dwError = GetLastError();
goto Cleanup;
}
wcscpy(lpszName, OutParams->pszName);
InOutParams->OutParams.pszName = lpszName;
InOutParams->OutParams.TagType = OutParams->TagType;
Cleanup:
CloseServiceHandle(hScm);
/* Free memory allocated by SCM */
if (OutParams != NULL)
{
if (OutParams->pszName != NULL)
{
midl_user_free(OutParams->pszName);
}
midl_user_free(OutParams);
}
return dwError;
}
/**********************************************************************
* I_QueryTagInformation
*
* @implemented
*/
DWORD WINAPI
I_QueryTagInformation(PVOID Unused,
TAG_INFO_LEVEL dwInfoLevel,
PTAG_INFO_NAME_FROM_TAG InOutParams)
{
/*
* We only support one information class and it
* needs parameters
*/
if (dwInfoLevel != TagInfoLevelNameFromTag ||
InOutParams == NULL)
{
return ERROR_INVALID_PARAMETER;
}
/* Validate input structure */
if (InOutParams->InParams.dwPid == 0 || InOutParams->InParams.dwTag == 0)
{
return ERROR_INVALID_PARAMETER;
}
/* Validate output structure */
if (InOutParams->OutParams.pszName != NULL)
{
return ERROR_INVALID_PARAMETER;
}
/* Call internal function for the RPC call */
return I_ScQueryServiceTagInfo(Unused, TagInfoLevelNameFromTag, InOutParams);
}
/* EOF */