mirror of
https://github.com/reactos/reactos.git
synced 2024-08-18 09:28:36 +00:00
3163 lines
85 KiB
C
3163 lines
85 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;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* 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 */
|