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