windows-nt/Source/XPSP1/NT/base/screg/sc/client/scwrap.cxx
2020-09-26 16:20:57 +08:00

5251 lines
131 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}
}