mirror of
https://github.com/reactos/reactos.git
synced 2024-11-03 13:25:57 +00:00
1215 lines
33 KiB
C
1215 lines
33 KiB
C
/*
|
|
* PROJECT: ReactOS advapi32
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: dll/win32/advapi32/service/sctrl.c
|
|
* PURPOSE: Service control manager functions
|
|
* COPYRIGHT: Copyright 1999 Emanuele Aliberti
|
|
* Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
|
|
* Gregor Brunmar <gregor.brunmar@home.se>
|
|
*/
|
|
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <advapi32.h>
|
|
WINE_DEFAULT_DEBUG_CHANNEL(advapi);
|
|
|
|
|
|
/* TYPES *********************************************************************/
|
|
|
|
typedef struct _SERVICE_THREAD_PARAMSA
|
|
{
|
|
LPSERVICE_MAIN_FUNCTIONA lpServiceMain;
|
|
DWORD dwArgCount;
|
|
LPSTR *lpArgVector;
|
|
DWORD dwServiceTag;
|
|
} SERVICE_THREAD_PARAMSA, *PSERVICE_THREAD_PARAMSA;
|
|
|
|
|
|
typedef struct _SERVICE_THREAD_PARAMSW
|
|
{
|
|
LPSERVICE_MAIN_FUNCTIONW lpServiceMain;
|
|
DWORD dwArgCount;
|
|
LPWSTR *lpArgVector;
|
|
DWORD dwServiceTag;
|
|
} SERVICE_THREAD_PARAMSW, *PSERVICE_THREAD_PARAMSW;
|
|
|
|
|
|
typedef struct _ACTIVE_SERVICE
|
|
{
|
|
SERVICE_STATUS_HANDLE hServiceStatus;
|
|
UNICODE_STRING ServiceName;
|
|
union
|
|
{
|
|
LPSERVICE_MAIN_FUNCTIONA A;
|
|
LPSERVICE_MAIN_FUNCTIONW W;
|
|
} ServiceMain;
|
|
LPHANDLER_FUNCTION HandlerFunction;
|
|
LPHANDLER_FUNCTION_EX HandlerFunctionEx;
|
|
LPVOID HandlerContext;
|
|
BOOL bUnicode;
|
|
BOOL bOwnProcess;
|
|
DWORD dwServiceTag;
|
|
} ACTIVE_SERVICE, *PACTIVE_SERVICE;
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
static DWORD dwActiveServiceCount = 0;
|
|
static PACTIVE_SERVICE lpActiveServices = NULL;
|
|
static handle_t hStatusBinding = NULL;
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
handle_t __RPC_USER
|
|
RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus)
|
|
{
|
|
return hStatusBinding;
|
|
}
|
|
|
|
|
|
void __RPC_USER
|
|
RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus,
|
|
handle_t hBinding)
|
|
{
|
|
}
|
|
|
|
|
|
static RPC_STATUS
|
|
ScCreateStatusBinding(VOID)
|
|
{
|
|
LPWSTR pszStringBinding;
|
|
RPC_STATUS status;
|
|
|
|
TRACE("ScCreateStatusBinding()\n");
|
|
|
|
status = RpcStringBindingComposeW(NULL,
|
|
L"ncacn_np",
|
|
NULL,
|
|
L"\\pipe\\ntsvcs",
|
|
NULL,
|
|
&pszStringBinding);
|
|
if (status != RPC_S_OK)
|
|
{
|
|
ERR("RpcStringBindingCompose returned 0x%x\n", status);
|
|
return status;
|
|
}
|
|
|
|
/* Set the binding handle that will be used to bind to the server. */
|
|
status = RpcBindingFromStringBindingW(pszStringBinding,
|
|
&hStatusBinding);
|
|
if (status != RPC_S_OK)
|
|
{
|
|
ERR("RpcBindingFromStringBinding returned 0x%x\n", status);
|
|
}
|
|
|
|
status = RpcStringFreeW(&pszStringBinding);
|
|
if (status != RPC_S_OK)
|
|
{
|
|
ERR("RpcStringFree returned 0x%x\n", status);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
static RPC_STATUS
|
|
ScDestroyStatusBinding(VOID)
|
|
{
|
|
RPC_STATUS status;
|
|
|
|
TRACE("ScDestroyStatusBinding()\n");
|
|
|
|
if (hStatusBinding == NULL)
|
|
return RPC_S_OK;
|
|
|
|
status = RpcBindingFree(&hStatusBinding);
|
|
if (status != RPC_S_OK)
|
|
{
|
|
ERR("RpcBindingFree returned 0x%x\n", status);
|
|
}
|
|
else
|
|
{
|
|
hStatusBinding = NULL;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
static PACTIVE_SERVICE
|
|
ScLookupServiceByServiceName(LPCWSTR lpServiceName)
|
|
{
|
|
DWORD i;
|
|
|
|
TRACE("ScLookupServiceByServiceName(%S)\n",
|
|
lpServiceName);
|
|
|
|
if (lpActiveServices[0].bOwnProcess)
|
|
return &lpActiveServices[0];
|
|
|
|
for (i = 0; i < dwActiveServiceCount; i++)
|
|
{
|
|
TRACE("Checking %S\n", lpActiveServices[i].ServiceName.Buffer);
|
|
if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
|
|
{
|
|
TRACE("Found!\n");
|
|
return &lpActiveServices[i];
|
|
}
|
|
}
|
|
|
|
TRACE("No service found!\n");
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static DWORD WINAPI
|
|
ScServiceMainStubA(LPVOID Context)
|
|
{
|
|
PTEB Teb;
|
|
PSERVICE_THREAD_PARAMSA ThreadParams = Context;
|
|
|
|
TRACE("ScServiceMainStubA(%p)\n", Context);
|
|
|
|
/* Set service tag */
|
|
Teb = NtCurrentTeb();
|
|
Teb->SubProcessTag = UlongToPtr(ThreadParams->dwServiceTag);
|
|
|
|
/* Call the main service routine and free the arguments vector */
|
|
(ThreadParams->lpServiceMain)(ThreadParams->dwArgCount,
|
|
ThreadParams->lpArgVector);
|
|
|
|
/* Reset service tag */
|
|
Teb->SubProcessTag = 0;
|
|
|
|
if (ThreadParams->lpArgVector != NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector);
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, ThreadParams);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
static DWORD WINAPI
|
|
ScServiceMainStubW(LPVOID Context)
|
|
{
|
|
PTEB Teb;
|
|
PSERVICE_THREAD_PARAMSW ThreadParams = Context;
|
|
|
|
TRACE("ScServiceMainStubW(%p)\n", Context);
|
|
|
|
/* Set service tag */
|
|
Teb = NtCurrentTeb();
|
|
Teb->SubProcessTag = UlongToPtr(ThreadParams->dwServiceTag);
|
|
|
|
/* Call the main service routine and free the arguments vector */
|
|
(ThreadParams->lpServiceMain)(ThreadParams->dwArgCount,
|
|
ThreadParams->lpArgVector);
|
|
|
|
/* Reset service tag */
|
|
Teb->SubProcessTag = 0;
|
|
|
|
if (ThreadParams->lpArgVector != NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector);
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, ThreadParams);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
static DWORD
|
|
ScConnectControlPipe(HANDLE *hPipe)
|
|
{
|
|
DWORD dwBytesWritten;
|
|
DWORD dwState;
|
|
DWORD dwServiceCurrent = 0;
|
|
NTSTATUS Status;
|
|
WCHAR NtControlPipeName[MAX_PATH + 1];
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
DWORD dwProcessId;
|
|
|
|
TRACE("ScConnectControlPipe(%p)\n",
|
|
hPipe);
|
|
|
|
/* Get the service number and create the named pipe */
|
|
RtlZeroMemory(&QueryTable,
|
|
sizeof(QueryTable));
|
|
|
|
QueryTable[0].Name = L"";
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
|
|
QueryTable[0].EntryContext = &dwServiceCurrent;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
|
|
L"ServiceCurrent",
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
|
|
return RtlNtStatusToDosError(Status);
|
|
}
|
|
|
|
swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent);
|
|
|
|
if (!WaitNamedPipeW(NtControlPipeName, 30000))
|
|
{
|
|
ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError());
|
|
return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
|
|
}
|
|
|
|
*hPipe = CreateFileW(NtControlPipeName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (*hPipe == INVALID_HANDLE_VALUE)
|
|
{
|
|
ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName, GetLastError());
|
|
return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
|
|
}
|
|
|
|
dwState = PIPE_READMODE_MESSAGE;
|
|
if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
|
|
{
|
|
CloseHandle(*hPipe);
|
|
*hPipe = INVALID_HANDLE_VALUE;
|
|
return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
|
|
}
|
|
|
|
/* Pass the ProcessId to the SCM */
|
|
dwProcessId = GetCurrentProcessId();
|
|
WriteFile(*hPipe,
|
|
&dwProcessId,
|
|
sizeof(dwProcessId),
|
|
&dwBytesWritten,
|
|
NULL);
|
|
|
|
TRACE("Sent Process ID %lu\n", dwProcessId);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
* Ansi/Unicode argument layout of the vector passed to a service at startup,
|
|
* depending on the different versions of Windows considered:
|
|
*
|
|
* - XP/2003:
|
|
* [argv array of pointers][parameter 1][parameter 2]...[service name]
|
|
*
|
|
* - Vista:
|
|
* [argv array of pointers][align to 8 bytes]
|
|
* [parameter 1][parameter 2]...[service name]
|
|
*
|
|
* - Win7/8:
|
|
* [argv array of pointers][service name]
|
|
* [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]...
|
|
*
|
|
* Space for parameters and service name is always enough to store
|
|
* both the Ansi and the Unicode versions including NULL terminator.
|
|
*/
|
|
|
|
static DWORD
|
|
ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket,
|
|
LPDWORD lpArgCount,
|
|
LPWSTR **lpArgVector)
|
|
{
|
|
PWSTR *lpVector;
|
|
PWSTR pszServiceName;
|
|
DWORD cbServiceName;
|
|
DWORD cbArguments;
|
|
DWORD cbTotal;
|
|
DWORD i;
|
|
|
|
if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
*lpArgCount = 0;
|
|
*lpArgVector = NULL;
|
|
|
|
/* Retrieve and count the start command line (NULL-terminated) */
|
|
pszServiceName = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset);
|
|
cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
|
|
|
/*
|
|
* The total size of the argument vector is equal to the entry for
|
|
* the service name, plus the size of the original argument vector.
|
|
*/
|
|
cbTotal = sizeof(PWSTR) + cbServiceName;
|
|
if (ControlPacket->dwArgumentsCount > 0)
|
|
cbArguments = ControlPacket->dwSize - ControlPacket->dwArgumentsOffset;
|
|
else
|
|
cbArguments = 0;
|
|
cbTotal += cbArguments;
|
|
|
|
/* Allocate the new argument vector */
|
|
lpVector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbTotal);
|
|
if (lpVector == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
/*
|
|
* The first argument is reserved for the service name, which
|
|
* will be appended to the end of the argument string list.
|
|
*/
|
|
|
|
/* Copy the remaining arguments */
|
|
if (ControlPacket->dwArgumentsCount > 0)
|
|
{
|
|
memcpy(&lpVector[1],
|
|
(PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwArgumentsOffset),
|
|
cbArguments);
|
|
|
|
for (i = 0; i < ControlPacket->dwArgumentsCount; i++)
|
|
{
|
|
lpVector[i + 1] = (PWSTR)((ULONG_PTR)&lpVector[1] + (ULONG_PTR)lpVector[i + 1]);
|
|
TRACE("Unicode lpVector[%lu] = '%ls'\n", i + 1, lpVector[i + 1]);
|
|
}
|
|
}
|
|
|
|
/* Now copy the service name */
|
|
lpVector[0] = (PWSTR)((ULONG_PTR)&lpVector[1] + cbArguments);
|
|
memcpy(lpVector[0], pszServiceName, cbServiceName);
|
|
TRACE("Unicode lpVector[%lu] = '%ls'\n", 0, lpVector[0]);
|
|
|
|
*lpArgCount = ControlPacket->dwArgumentsCount + 1;
|
|
*lpArgVector = lpVector;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
static DWORD
|
|
ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket,
|
|
LPDWORD lpArgCount,
|
|
LPSTR **lpArgVector)
|
|
{
|
|
DWORD dwError;
|
|
NTSTATUS Status;
|
|
DWORD ArgCount, i;
|
|
PWSTR *lpVectorW;
|
|
PSTR *lpVectorA;
|
|
UNICODE_STRING UnicodeString;
|
|
ANSI_STRING AnsiString;
|
|
|
|
if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
*lpArgCount = 0;
|
|
*lpArgVector = NULL;
|
|
|
|
/* Build the UNICODE arguments vector */
|
|
dwError = ScBuildUnicodeArgsVector(ControlPacket, &ArgCount, &lpVectorW);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return dwError;
|
|
|
|
/* Convert the vector to ANSI in place */
|
|
lpVectorA = (PSTR*)lpVectorW;
|
|
for (i = 0; i < ArgCount; i++)
|
|
{
|
|
RtlInitUnicodeString(&UnicodeString, lpVectorW[i]);
|
|
RtlInitEmptyAnsiString(&AnsiString, lpVectorA[i], UnicodeString.MaximumLength);
|
|
Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Failed to convert to ANSI; free the allocated vector and return */
|
|
dwError = RtlNtStatusToDosError(Status);
|
|
HeapFree(GetProcessHeap(), 0, lpVectorW);
|
|
return dwError;
|
|
}
|
|
|
|
/* NULL-terminate the string */
|
|
AnsiString.Buffer[AnsiString.Length / sizeof(CHAR)] = ANSI_NULL;
|
|
|
|
TRACE("Ansi lpVector[%lu] = '%s'\n", i, lpVectorA[i]);
|
|
}
|
|
|
|
*lpArgCount = ArgCount;
|
|
*lpArgVector = lpVectorA;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
static DWORD
|
|
ScStartService(PACTIVE_SERVICE lpService,
|
|
PSCM_CONTROL_PACKET ControlPacket)
|
|
{
|
|
HANDLE ThreadHandle;
|
|
DWORD ThreadId;
|
|
DWORD dwError;
|
|
PSERVICE_THREAD_PARAMSA ThreadParamsA;
|
|
PSERVICE_THREAD_PARAMSW ThreadParamsW;
|
|
|
|
TRACE("ScStartService(%p %p)\n",
|
|
lpService, ControlPacket);
|
|
|
|
if (lpService == NULL || ControlPacket == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
TRACE("Size: %lu\n", ControlPacket->dwSize);
|
|
TRACE("Service: %S\n", (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset));
|
|
|
|
/* Set the service status handle */
|
|
lpService->hServiceStatus = ControlPacket->hServiceStatus;
|
|
/* Set the service tag */
|
|
lpService->dwServiceTag = ControlPacket->dwServiceTag;
|
|
|
|
/* Build the arguments vector */
|
|
if (lpService->bUnicode != FALSE)
|
|
{
|
|
ThreadParamsW = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsW));
|
|
if (ThreadParamsW == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
dwError = ScBuildUnicodeArgsVector(ControlPacket,
|
|
&ThreadParamsW->dwArgCount,
|
|
&ThreadParamsW->lpArgVector);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, ThreadParamsW);
|
|
return dwError;
|
|
}
|
|
ThreadParamsW->lpServiceMain = lpService->ServiceMain.W;
|
|
ThreadParamsW->dwServiceTag = ControlPacket->dwServiceTag;
|
|
ThreadHandle = CreateThread(NULL,
|
|
0,
|
|
ScServiceMainStubW,
|
|
ThreadParamsW,
|
|
0,
|
|
&ThreadId);
|
|
if (ThreadHandle == NULL)
|
|
{
|
|
if (ThreadParamsW->lpArgVector != NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, ThreadParamsW->lpArgVector);
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, ThreadParamsW);
|
|
|
|
return ERROR_SERVICE_NO_THREAD;
|
|
}
|
|
|
|
CloseHandle(ThreadHandle);
|
|
}
|
|
else
|
|
{
|
|
ThreadParamsA = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsA));
|
|
if (ThreadParamsA == NULL)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
dwError = ScBuildAnsiArgsVector(ControlPacket,
|
|
&ThreadParamsA->dwArgCount,
|
|
&ThreadParamsA->lpArgVector);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, ThreadParamsA);
|
|
return dwError;
|
|
}
|
|
ThreadParamsA->lpServiceMain = lpService->ServiceMain.A;
|
|
ThreadParamsA->dwServiceTag = ControlPacket->dwServiceTag;
|
|
ThreadHandle = CreateThread(NULL,
|
|
0,
|
|
ScServiceMainStubA,
|
|
ThreadParamsA,
|
|
0,
|
|
&ThreadId);
|
|
if (ThreadHandle == NULL)
|
|
{
|
|
if (ThreadParamsA->lpArgVector != NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, ThreadParamsA->lpArgVector);
|
|
}
|
|
HeapFree(GetProcessHeap(), 0, ThreadParamsA);
|
|
|
|
return ERROR_SERVICE_NO_THREAD;
|
|
}
|
|
|
|
CloseHandle(ThreadHandle);
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
static DWORD
|
|
ScControlService(PACTIVE_SERVICE lpService,
|
|
PSCM_CONTROL_PACKET ControlPacket)
|
|
{
|
|
DWORD dwError = ERROR_SUCCESS;
|
|
|
|
TRACE("ScControlService(%p %p)\n",
|
|
lpService, ControlPacket);
|
|
|
|
if (lpService == NULL || ControlPacket == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
TRACE("Size: %lu\n", ControlPacket->dwSize);
|
|
TRACE("Service: %S\n", (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset));
|
|
|
|
/* Set service tag */
|
|
NtCurrentTeb()->SubProcessTag = UlongToPtr(lpService->dwServiceTag);
|
|
|
|
if (lpService->HandlerFunction)
|
|
{
|
|
_SEH2_TRY
|
|
{
|
|
(lpService->HandlerFunction)(ControlPacket->dwControl);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwError = ERROR_EXCEPTION_IN_SERVICE;
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
else if (lpService->HandlerFunctionEx)
|
|
{
|
|
_SEH2_TRY
|
|
{
|
|
/* FIXME: Send correct 2nd and 3rd parameters */
|
|
(lpService->HandlerFunctionEx)(ControlPacket->dwControl,
|
|
0, NULL,
|
|
lpService->HandlerContext);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwError = ERROR_EXCEPTION_IN_SERVICE;
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
else
|
|
{
|
|
dwError = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
|
|
}
|
|
|
|
/* Reset service tag */
|
|
NtCurrentTeb()->SubProcessTag = 0;
|
|
|
|
TRACE("ScControlService() done (Error %lu)\n", dwError);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
static BOOL
|
|
ScServiceDispatcher(HANDLE hPipe,
|
|
PSCM_CONTROL_PACKET ControlPacket,
|
|
DWORD dwBufferSize)
|
|
{
|
|
DWORD Count;
|
|
BOOL bResult;
|
|
BOOL bRunning = TRUE;
|
|
LPWSTR lpServiceName;
|
|
PACTIVE_SERVICE lpService;
|
|
SCM_REPLY_PACKET ReplyPacket;
|
|
DWORD dwError;
|
|
|
|
TRACE("ScServiceDispatcher(%p %p %lu)\n",
|
|
hPipe, ControlPacket, dwBufferSize);
|
|
|
|
if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET))
|
|
return FALSE;
|
|
|
|
while (bRunning)
|
|
{
|
|
/* Read command from the control pipe */
|
|
bResult = ReadFile(hPipe,
|
|
ControlPacket,
|
|
dwBufferSize,
|
|
&Count,
|
|
NULL);
|
|
if (bResult == FALSE)
|
|
{
|
|
ERR("Pipe read failed (Error: %lu)\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
|
|
TRACE("Service: %S\n", lpServiceName);
|
|
|
|
if ((ControlPacket->dwControl == SERVICE_CONTROL_STOP) &&
|
|
(lpServiceName[0] == UNICODE_NULL))
|
|
{
|
|
TRACE("Stop dispatcher thread\n");
|
|
bRunning = FALSE;
|
|
dwError = ERROR_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
|
|
lpActiveServices[0].bOwnProcess = TRUE;
|
|
|
|
lpService = ScLookupServiceByServiceName(lpServiceName);
|
|
if (lpService != NULL)
|
|
{
|
|
/* Execute command */
|
|
switch (ControlPacket->dwControl)
|
|
{
|
|
case SERVICE_CONTROL_START_SHARE:
|
|
case SERVICE_CONTROL_START_OWN:
|
|
TRACE("Start command - received SERVICE_CONTROL_START\n");
|
|
dwError = ScStartService(lpService, ControlPacket);
|
|
break;
|
|
|
|
case SERVICE_CONTROL_STOP:
|
|
TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
|
|
dwError = ScControlService(lpService, ControlPacket);
|
|
break;
|
|
|
|
default:
|
|
TRACE("Command %lu received", ControlPacket->dwControl);
|
|
dwError = ScControlService(lpService, ControlPacket);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwError = ERROR_SERVICE_NOT_IN_EXE;
|
|
}
|
|
}
|
|
|
|
ReplyPacket.dwError = dwError;
|
|
|
|
/* Send the reply packet */
|
|
bResult = WriteFile(hPipe,
|
|
&ReplyPacket,
|
|
sizeof(ReplyPacket),
|
|
&Count,
|
|
NULL);
|
|
if (bResult == FALSE)
|
|
{
|
|
ERR("Pipe write failed (Error: %lu)\n", GetLastError());
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* RegisterServiceCtrlHandlerA
|
|
*
|
|
* @implemented
|
|
*/
|
|
SERVICE_STATUS_HANDLE WINAPI
|
|
RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
|
|
LPHANDLER_FUNCTION lpHandlerProc)
|
|
{
|
|
ANSI_STRING ServiceNameA;
|
|
UNICODE_STRING ServiceNameU;
|
|
SERVICE_STATUS_HANDLE hServiceStatus;
|
|
|
|
TRACE("RegisterServiceCtrlHandlerA(%s %p)\n",
|
|
debugstr_a(lpServiceName), lpHandlerProc);
|
|
|
|
RtlInitAnsiString(&ServiceNameA, lpServiceName);
|
|
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
hServiceStatus = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
|
|
lpHandlerProc);
|
|
|
|
RtlFreeUnicodeString(&ServiceNameU);
|
|
|
|
return hServiceStatus;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* RegisterServiceCtrlHandlerW
|
|
*
|
|
* @implemented
|
|
*/
|
|
SERVICE_STATUS_HANDLE WINAPI
|
|
RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
|
|
LPHANDLER_FUNCTION lpHandlerProc)
|
|
{
|
|
PACTIVE_SERVICE Service;
|
|
|
|
TRACE("RegisterServiceCtrlHandlerW(%s %p)\n",
|
|
debugstr_w(lpServiceName), lpHandlerProc);
|
|
|
|
Service = ScLookupServiceByServiceName(lpServiceName);
|
|
if (Service == NULL)
|
|
{
|
|
SetLastError(ERROR_SERVICE_NOT_IN_EXE);
|
|
return NULL;
|
|
}
|
|
|
|
if (!lpHandlerProc)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
Service->HandlerFunction = lpHandlerProc;
|
|
Service->HandlerFunctionEx = NULL;
|
|
|
|
TRACE("RegisterServiceCtrlHandler returning %p\n", Service->hServiceStatus);
|
|
|
|
return Service->hServiceStatus;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* RegisterServiceCtrlHandlerExA
|
|
*
|
|
* @implemented
|
|
*/
|
|
SERVICE_STATUS_HANDLE WINAPI
|
|
RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
|
|
LPHANDLER_FUNCTION_EX lpHandlerProc,
|
|
LPVOID lpContext)
|
|
{
|
|
ANSI_STRING ServiceNameA;
|
|
UNICODE_STRING ServiceNameU;
|
|
SERVICE_STATUS_HANDLE hServiceStatus;
|
|
|
|
TRACE("RegisterServiceCtrlHandlerExA(%s %p %p)\n",
|
|
debugstr_a(lpServiceName), lpHandlerProc, lpContext);
|
|
|
|
RtlInitAnsiString(&ServiceNameA, lpServiceName);
|
|
if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NULL;
|
|
}
|
|
|
|
hServiceStatus = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
|
|
lpHandlerProc,
|
|
lpContext);
|
|
|
|
RtlFreeUnicodeString(&ServiceNameU);
|
|
|
|
return hServiceStatus;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* RegisterServiceCtrlHandlerExW
|
|
*
|
|
* @implemented
|
|
*/
|
|
SERVICE_STATUS_HANDLE WINAPI
|
|
RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
|
|
LPHANDLER_FUNCTION_EX lpHandlerProc,
|
|
LPVOID lpContext)
|
|
{
|
|
PACTIVE_SERVICE Service;
|
|
|
|
TRACE("RegisterServiceCtrlHandlerExW(%s %p %p)\n",
|
|
debugstr_w(lpServiceName), lpHandlerProc, lpContext);
|
|
|
|
Service = ScLookupServiceByServiceName(lpServiceName);
|
|
if (Service == NULL)
|
|
{
|
|
SetLastError(ERROR_SERVICE_NOT_IN_EXE);
|
|
return NULL;
|
|
}
|
|
|
|
if (!lpHandlerProc)
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NULL;
|
|
}
|
|
|
|
Service->HandlerFunction = NULL;
|
|
Service->HandlerFunctionEx = lpHandlerProc;
|
|
Service->HandlerContext = lpContext;
|
|
|
|
TRACE("RegisterServiceCtrlHandlerEx returning %p\n", Service->hServiceStatus);
|
|
|
|
return Service->hServiceStatus;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* I_ScIsSecurityProcess
|
|
*
|
|
* Undocumented
|
|
*
|
|
* @unimplemented
|
|
*/
|
|
VOID
|
|
WINAPI
|
|
I_ScIsSecurityProcess(VOID)
|
|
{
|
|
FIXME("I_ScIsSecurityProcess()\n");
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* I_ScPnPGetServiceName
|
|
*
|
|
* Undocumented
|
|
*
|
|
* @implemented
|
|
*/
|
|
DWORD
|
|
WINAPI
|
|
I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus,
|
|
OUT LPWSTR lpServiceName,
|
|
IN DWORD cchServiceName)
|
|
{
|
|
DWORD i;
|
|
|
|
TRACE("I_ScPnPGetServiceName(%lu %p %lu)\n",
|
|
hServiceStatus, lpServiceName, cchServiceName);
|
|
|
|
for (i = 0; i < dwActiveServiceCount; i++)
|
|
{
|
|
if (lpActiveServices[i].hServiceStatus == hServiceStatus)
|
|
{
|
|
wcscpy(lpServiceName, lpActiveServices[i].ServiceName.Buffer);
|
|
return ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return ERROR_SERVICE_NOT_IN_EXE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* I_ScSetServiceBitsA
|
|
*
|
|
* Undocumented
|
|
*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,
|
|
DWORD dwServiceBits,
|
|
BOOL bSetBitsOn,
|
|
BOOL bUpdateImmediately,
|
|
LPSTR lpString)
|
|
{
|
|
BOOL bResult;
|
|
|
|
TRACE("I_ScSetServiceBitsA(%lu %lx %u %u %s)\n",
|
|
hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately,
|
|
debugstr_a(lpString));
|
|
|
|
RpcTryExcept
|
|
{
|
|
bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
|
|
dwServiceBits,
|
|
bSetBitsOn,
|
|
bUpdateImmediately,
|
|
lpString);
|
|
}
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
|
|
bResult = FALSE;
|
|
}
|
|
RpcEndExcept;
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* I_ScSetServiceBitsW
|
|
*
|
|
* Undocumented
|
|
*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,
|
|
DWORD dwServiceBits,
|
|
BOOL bSetBitsOn,
|
|
BOOL bUpdateImmediately,
|
|
LPWSTR lpString)
|
|
{
|
|
BOOL bResult;
|
|
|
|
TRACE("I_ScSetServiceBitsW(%lu %lx %u %u %s)\n",
|
|
hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately,
|
|
debugstr_w(lpString));
|
|
|
|
RpcTryExcept
|
|
{
|
|
bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
|
|
dwServiceBits,
|
|
bSetBitsOn,
|
|
bUpdateImmediately,
|
|
lpString);
|
|
}
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
|
|
bResult = FALSE;
|
|
}
|
|
RpcEndExcept;
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* SetServiceBits
|
|
*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
|
|
DWORD dwServiceBits,
|
|
BOOL bSetBitsOn,
|
|
BOOL bUpdateImmediately)
|
|
{
|
|
TRACE("SetServiceBits(%lu %lx %u %u)\n",
|
|
hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately);
|
|
|
|
return I_ScSetServiceBitsW(hServiceStatus,
|
|
dwServiceBits,
|
|
bSetBitsOn,
|
|
bUpdateImmediately,
|
|
NULL);
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* SetServiceStatus
|
|
*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
|
|
LPSERVICE_STATUS lpServiceStatus)
|
|
{
|
|
DWORD dwError;
|
|
|
|
TRACE("SetServiceStatus(%lu %p)\n",
|
|
hServiceStatus, lpServiceStatus);
|
|
|
|
RpcTryExcept
|
|
{
|
|
dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
|
|
lpServiceStatus);
|
|
}
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
dwError = ScmRpcStatusToWinError(RpcExceptionCode());
|
|
}
|
|
RpcEndExcept;
|
|
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
ERR("RSetServiceStatus() failed (Error %lu)\n", dwError);
|
|
SetLastError(dwError);
|
|
return FALSE;
|
|
}
|
|
|
|
TRACE("SetServiceStatus() done\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* StartServiceCtrlDispatcherA
|
|
*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
|
|
{
|
|
ULONG i;
|
|
HANDLE hPipe;
|
|
DWORD dwError;
|
|
PSCM_CONTROL_PACKET ControlPacket;
|
|
DWORD dwBufSize;
|
|
BOOL bRet = TRUE;
|
|
|
|
TRACE("StartServiceCtrlDispatcherA(%p)\n",
|
|
lpServiceStartTable);
|
|
|
|
i = 0;
|
|
while (lpServiceStartTable[i].lpServiceProc != NULL)
|
|
{
|
|
i++;
|
|
}
|
|
|
|
dwActiveServiceCount = i;
|
|
|
|
/* Allocate the service table */
|
|
lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
|
|
if (lpActiveServices == NULL)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Copy service names and start procedure */
|
|
for (i = 0; i < dwActiveServiceCount; i++)
|
|
{
|
|
RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
|
|
lpServiceStartTable[i].lpServiceName);
|
|
lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc;
|
|
lpActiveServices[i].hServiceStatus = NULL;
|
|
lpActiveServices[i].bUnicode = FALSE;
|
|
lpActiveServices[i].bOwnProcess = FALSE;
|
|
}
|
|
|
|
/* Connect to the SCM */
|
|
dwError = ScConnectControlPipe(&hPipe);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
bRet = FALSE;
|
|
goto done;
|
|
}
|
|
|
|
dwBufSize = sizeof(SCM_CONTROL_PACKET) +
|
|
(MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
|
|
|
|
ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwBufSize);
|
|
if (ControlPacket == NULL)
|
|
{
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
bRet = FALSE;
|
|
goto done;
|
|
}
|
|
|
|
ScCreateStatusBinding();
|
|
|
|
/* Call the dispatcher loop */
|
|
ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
|
|
|
|
|
|
ScDestroyStatusBinding();
|
|
|
|
/* Close the connection */
|
|
CloseHandle(hPipe);
|
|
|
|
/* Free the control packet */
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
|
|
|
|
done:
|
|
/* Free the service table */
|
|
for (i = 0; i < dwActiveServiceCount; i++)
|
|
{
|
|
RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
|
|
}
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
|
|
lpActiveServices = NULL;
|
|
dwActiveServiceCount = 0;
|
|
|
|
if (!bRet)
|
|
SetLastError(dwError);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* StartServiceCtrlDispatcherW
|
|
*
|
|
* @implemented
|
|
*/
|
|
BOOL WINAPI
|
|
StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
|
|
{
|
|
ULONG i;
|
|
HANDLE hPipe;
|
|
DWORD dwError;
|
|
PSCM_CONTROL_PACKET ControlPacket;
|
|
DWORD dwBufSize;
|
|
BOOL bRet = TRUE;
|
|
|
|
TRACE("StartServiceCtrlDispatcherW(%p)\n",
|
|
lpServiceStartTable);
|
|
|
|
i = 0;
|
|
while (lpServiceStartTable[i].lpServiceProc != NULL)
|
|
{
|
|
i++;
|
|
}
|
|
|
|
dwActiveServiceCount = i;
|
|
|
|
/* Allocate the service table */
|
|
lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
|
|
if (lpActiveServices == NULL)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Copy service names and start procedure */
|
|
for (i = 0; i < dwActiveServiceCount; i++)
|
|
{
|
|
RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
|
|
lpServiceStartTable[i].lpServiceName);
|
|
lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc;
|
|
lpActiveServices[i].hServiceStatus = NULL;
|
|
lpActiveServices[i].bUnicode = TRUE;
|
|
lpActiveServices[i].bOwnProcess = FALSE;
|
|
}
|
|
|
|
/* Connect to the SCM */
|
|
dwError = ScConnectControlPipe(&hPipe);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
bRet = FALSE;
|
|
goto done;
|
|
}
|
|
|
|
dwBufSize = sizeof(SCM_CONTROL_PACKET) +
|
|
(MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
|
|
|
|
ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwBufSize);
|
|
if (ControlPacket == NULL)
|
|
{
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
bRet = FALSE;
|
|
goto done;
|
|
}
|
|
|
|
ScCreateStatusBinding();
|
|
|
|
/* Call the dispatcher loop */
|
|
ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
|
|
|
|
ScDestroyStatusBinding();
|
|
|
|
/* Close the connection */
|
|
CloseHandle(hPipe);
|
|
|
|
/* Free the control packet */
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
|
|
|
|
done:
|
|
/* Free the service table */
|
|
for (i = 0; i < dwActiveServiceCount; i++)
|
|
{
|
|
RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
|
|
}
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
|
|
lpActiveServices = NULL;
|
|
dwActiveServiceCount = 0;
|
|
|
|
if (!bRet)
|
|
SetLastError(dwError);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/* EOF */
|