3301 lines
78 KiB
C
3301 lines
78 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
scwrap.c
|
||
|
||
Abstract:
|
||
|
||
These are the Service Controller API RPC client wrapper routines.
|
||
These are the entry points that are exported by the dll.
|
||
ControlService
|
||
EnumServicesStatusW
|
||
EnumServicesStatusA
|
||
EnumServiceGroupW
|
||
OpenServiceW
|
||
CloseServiceHandle
|
||
OpenSCManagerW
|
||
QueryServiceStatus
|
||
StartServiceW
|
||
SetServiceStatus
|
||
I_ScSetServiceBitsW
|
||
I_ScSetServiceBitsA
|
||
I_ScGetCurrentGroupStateW
|
||
SetServiceBits
|
||
|
||
OpenSCManagerA
|
||
OpenServiceA
|
||
StartServiceA
|
||
EnumServicesStatusA
|
||
|
||
QueryServiceObjectSecurity
|
||
SetServiceObjectSecurity
|
||
ScConvertOffsetsW
|
||
ScConvertOffsetsA
|
||
|
||
ChangeServiceConfigA
|
||
ChangeServiceConfigW
|
||
CreateServiceA
|
||
CreateServiceW
|
||
DeleteService
|
||
EnumDependentServicesA
|
||
EnumDependentServicesW
|
||
GetServiceDisplayNameA
|
||
GetServiceDisplayNameW
|
||
GetServiceKeyNameA
|
||
GetServiceKeyNameW
|
||
LockServiceDatabase
|
||
QueryServiceConfigA
|
||
QueryServiceConfigW
|
||
QueryServiceLockStatusA
|
||
QueryServiceLockStatusW
|
||
UnlockServiceDatabase
|
||
NotifyBootConfigStatus
|
||
|
||
Author:
|
||
|
||
Dan Lafferty (danl) 03-Feb-1992
|
||
|
||
Environment:
|
||
|
||
User Mode - Win32
|
||
|
||
Revision History:
|
||
|
||
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
|
||
//
|
||
|
||
#include <string.h> // needed by strarray.h
|
||
|
||
#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 complier
|
||
#include <lmcons.h> // for lmserver.h
|
||
#include <srvann.h> // MS-internal functions
|
||
#include <winsvcp.h> // MS-internal functions
|
||
|
||
#include <scdebug.h> // SCC_LOG
|
||
#include <scwrap.h> // GENERIC_INFO_CONTAINER
|
||
#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
|
||
|
||
//
|
||
// 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
|
||
);
|
||
|
||
DWORD
|
||
ScMapRpcError(
|
||
IN DWORD RpcError,
|
||
IN DWORD BadContextError
|
||
);
|
||
|
||
VOID
|
||
ScWaitForStart(
|
||
VOID
|
||
);
|
||
|
||
//
|
||
// Globals
|
||
//
|
||
#ifdef SC_DEBUG
|
||
DWORD SvcctrlDebugLevel = DEBUG_ALL;
|
||
#else
|
||
DWORD SvcctrlDebugLevel = DEBUG_ERROR;
|
||
#endif
|
||
|
||
|
||
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(1) {
|
||
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
|
||
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;
|
||
|
||
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(1) {
|
||
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){
|
||
|
||
ScConvertOffsetsW(lpServices, *lpServicesReturned);
|
||
}
|
||
}
|
||
|
||
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(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
SetLastError(status);
|
||
return(NULL);
|
||
}
|
||
|
||
return(hService);
|
||
}
|
||
|
||
BOOL
|
||
WINAPI
|
||
CloseServiceHandle(
|
||
IN SC_HANDLE hSCObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD status;
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
status = RCloseServiceHandle((LPSC_RPC_HANDLE)&hSCObject);
|
||
}
|
||
RpcExcept(1) {
|
||
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).
|
||
//
|
||
|
||
ScWaitForStart();
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
status = ROpenSCManagerW (
|
||
(LPWSTR) lpMachineName,
|
||
(LPWSTR) lpDatabaseName,
|
||
dwDesiredAccess,
|
||
&ScHandle);
|
||
}
|
||
RpcExcept(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
SetLastError(status);
|
||
return(NULL);
|
||
}
|
||
|
||
return(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(1) {
|
||
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(1) {
|
||
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 (
|
||
(DWORD)hServiceStatus,
|
||
lpServiceStatus);
|
||
}
|
||
RpcExcept(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
SetLastError(status);
|
||
return(FALSE);
|
||
}
|
||
|
||
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 (
|
||
(RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
|
||
dwServiceBits,
|
||
setBitsOnFlag,
|
||
updateImmediatelyFlag,
|
||
pszTransportName);
|
||
}
|
||
RpcExcept(1) {
|
||
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 (
|
||
(RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
|
||
dwServiceBits,
|
||
setBitsOnFlag,
|
||
updateImmediatelyFlag,
|
||
pszTransportName);
|
||
}
|
||
RpcExcept(1) {
|
||
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 an internal routine that checks the startup status of a
|
||
specified service group. It is used by the LSA to speed up logon,
|
||
by proceeding with logon after the transports have been started,
|
||
rather than waiting for the workstation service to start.
|
||
|
||
Arguments:
|
||
|
||
hSCManager - Handle to the service controller
|
||
|
||
pszGroupName - Name of the group whose state is to be determined.
|
||
|
||
pdwCurrentState - One of the following is returned here:
|
||
GROUP_START_FAIL - all service(s) in the group failed to start,
|
||
or there are no services in the group.
|
||
GROUP_NOT_STARTED - there are some services in the group that
|
||
have neither started nor failed to start.
|
||
GROUP_ONE_STARTED - there is at least one service in the group,
|
||
and all services in the group have started.
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR - The operation was completely successful.
|
||
|
||
ERROR_SERVICE_DOES_NOT_EXIST - The group named does not exist.
|
||
|
||
ERROR_SHUTDOWN_IN_PROGRESS - Service controller is shutting down.
|
||
|
||
ERROR_INVALID_HANDLE - hSCManager is invalid.
|
||
|
||
Other RPC errors.
|
||
|
||
--*/
|
||
{
|
||
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 = RI_ScGetCurrentGroupStateW (
|
||
(SC_RPC_HANDLE) hSCManager,
|
||
pszGroupName,
|
||
pdwCurrentState);
|
||
}
|
||
RpcExcept(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR) {
|
||
SetLastError(status);
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
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).
|
||
//
|
||
|
||
ScWaitForStart();
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
status = ROpenSCManagerA (
|
||
(LPSTR) lpMachineName,
|
||
(LPSTR) lpDatabaseName,
|
||
dwDesiredAccess,
|
||
&ScHandle);
|
||
}
|
||
RpcExcept(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
SetLastError(status);
|
||
return(NULL);
|
||
}
|
||
|
||
return(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(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
SetLastError(status);
|
||
return(NULL);
|
||
}
|
||
|
||
return(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(1) {
|
||
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;
|
||
|
||
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(1) {
|
||
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){
|
||
|
||
ScConvertOffsetsA(lpServices, *lpServicesReturned);
|
||
}
|
||
}
|
||
|
||
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(1) {
|
||
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(1) {
|
||
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)(lpServices[i].lpServiceName));
|
||
lpServices[i].lpDisplayName = (LPWSTR)(pBuffer +
|
||
(DWORD)(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)(lpServices[i].lpServiceName));
|
||
lpServices[i].lpDisplayName = (LPSTR)(pBuffer +
|
||
(DWORD)(lpServices[i].lpDisplayName));
|
||
}
|
||
}
|
||
|
||
|
||
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 CreateServcie 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(1) {
|
||
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(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (EncryptedPassword != NULL) {
|
||
(void) LocalFree(EncryptedPassword);
|
||
}
|
||
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(1) {
|
||
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(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(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (EncryptedPassword != NULL) {
|
||
(void) LocalFree(EncryptedPassword);
|
||
}
|
||
|
||
if (status != NO_ERROR){
|
||
SetLastError(status);
|
||
return(NULL);
|
||
}
|
||
|
||
return(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;
|
||
|
||
|
||
RpcTryExcept {
|
||
|
||
status = RDeleteService ((SC_RPC_HANDLE)hService);
|
||
|
||
}
|
||
RpcExcept(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
SetLastError(status);
|
||
return(FALSE);
|
||
}
|
||
|
||
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(1) {
|
||
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){
|
||
|
||
ScConvertOffsetsA(lpServices, *lpServicesReturned);
|
||
}
|
||
}
|
||
|
||
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(1) {
|
||
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){
|
||
|
||
ScConvertOffsetsW(lpServices, *lpServicesReturned);
|
||
}
|
||
}
|
||
|
||
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(1) {
|
||
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(1) {
|
||
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(1) {
|
||
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(1) {
|
||
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(1) {
|
||
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(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
SetLastError(status);
|
||
return(FALSE);
|
||
}
|
||
else {
|
||
//
|
||
// Replace the '/' seperator characters by NULLs. We used
|
||
// seperator 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(1) {
|
||
status = RpcExceptionCode();
|
||
if (status == EXCEPTION_ACCESS_VIOLATION) {
|
||
status = ERROR_INVALID_ADDRESS;
|
||
}
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
SetLastError(status);
|
||
return(FALSE);
|
||
}
|
||
else {
|
||
//
|
||
// Replace the '/' seperator characters by NULLs. We used
|
||
// seperator 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
|
||
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(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
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(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
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(1) {
|
||
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(1) {
|
||
status = ScMapRpcError(RpcExceptionCode(), ERROR_INVALID_HANDLE);
|
||
}
|
||
RpcEndExcept
|
||
|
||
if (status != NO_ERROR){
|
||
SetLastError(status);
|
||
return(FALSE);
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
VOID
|
||
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.
|
||
//
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
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) {
|
||
SCC_LOG1(ERROR,"ScWaitForStart: OpenEvent (StartEvent) failed "
|
||
FORMAT_DWORD " on second attempt\n", GetLastError());
|
||
return;
|
||
}
|
||
}
|
||
else {
|
||
SCC_LOG1(ERROR,"ScWaitForStart: CreateEvent (StartEvent) Failed "
|
||
FORMAT_DWORD "\n", status);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
//
|
||
// Could not open the event for some unknown reason. Give up.
|
||
//
|
||
SCC_LOG1(ERROR,"ScWaitForStart: OpenEvent (StartEvent) Failed "
|
||
FORMAT_DWORD "\n", status);
|
||
return;
|
||
}
|
||
}
|
||
|
||
SCC_LOG0(TRACE,"Beginning wait for ScStartEvent\n");
|
||
status = WaitForSingleObject(ScStartEvent, SC_START_TIMEOUT);
|
||
if (status == WAIT_TIMEOUT) {
|
||
SCC_LOG0(ERROR,"ScWaitForStart: TIMEOUT waiting for StartEvent\n");
|
||
}
|
||
|
||
CloseHandle(ScStartEvent);
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
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:
|
||
return ERROR_INVALID_PARAMETER;
|
||
|
||
case EXCEPTION_ACCESS_VIOLATION:
|
||
return ERROR_INVALID_ADDRESS;
|
||
|
||
default:
|
||
return RpcError;
|
||
}
|
||
|
||
}
|
||
|