Use the service contol pipe to send a start command in order to start a service thread.

svn path=/trunk/; revision=13350
This commit is contained in:
Eric Kohl 2005-01-28 13:28:56 +00:00
parent 91337fece1
commit 9f44705b10
3 changed files with 353 additions and 148 deletions

View file

@ -0,0 +1,24 @@
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: include/services/services.h
* PURPOSE: Private interface between SERVICES.EXE and ADVAPI32.DLL
* PROGRAMMER: Eric Kohl
*/
#ifndef __SERVICES_SERVICES_H__
#define __SERVICES_SERVICES_H__
#define SCM_START_COMMAND 1
typedef struct _SCM_START_PACKET
{
ULONG Command;
ULONG Size;
WCHAR Arguments[1];
} SCM_START_PACKET, *PSCM_START_PACKET;
#endif /* __SERVICES_SERVICES_H__ */
/* EOF */

View file

@ -13,6 +13,8 @@
/* INCLUDES ******************************************************************/
#include "advapi32.h"
#include <services/services.h>
#define NDEBUG
#include <debug.h>
@ -23,9 +25,15 @@ typedef struct _ACTIVE_SERVICE
{
DWORD ThreadId;
UNICODE_STRING ServiceName;
LPSERVICE_MAIN_FUNCTIONW MainFunction;
union
{
LPSERVICE_MAIN_FUNCTIONA lpFuncA;
LPSERVICE_MAIN_FUNCTIONW lpFuncW;
} Main;
LPHANDLER_FUNCTION HandlerFunction;
SERVICE_STATUS ServiceStatus;
BOOL bUnicode;
LPWSTR Arguments;
} ACTIVE_SERVICE, *PACTIVE_SERVICE;
@ -33,7 +41,6 @@ typedef struct _ACTIVE_SERVICE
static DWORD dwActiveServiceCount = 0;
static PACTIVE_SERVICE lpActiveServices = NULL;
/* static PHANDLE ActiveServicesThreadHandles; */ /* uncomment when in use */
/* FUNCTIONS *****************************************************************/
@ -80,15 +87,53 @@ static DWORD WINAPI
ScServiceMainStub(LPVOID Context)
{
PACTIVE_SERVICE lpService;
DWORD dwArgCount = 0;
DWORD dwLength = 0;
lpService = (PACTIVE_SERVICE)Context;
DPRINT("ScServiceMainStub() called\n");
/* FIXME: Send argc and argv (from command line) as arguments */
/* Count arguments */
while (lpService->Arguments[dwLength])
{
dwLength += wcslen(&lpService->Arguments[dwLength]) + 1;
dwArgCount++;
}
/* Build the argument vector and call the main service routine */
if (lpService->bUnicode)
{
LPWSTR *lpArgVector;
LPWSTR Ptr;
(lpService->MainFunction)(0, NULL);
lpArgVector = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
(dwArgCount + 1) * sizeof(LPWSTR));
if (lpArgVector == NULL)
return ERROR_OUTOFMEMORY;
dwArgCount = 0;
Ptr = lpService->Arguments;
while (*Ptr)
{
lpArgVector[dwArgCount] = Ptr;
dwArgCount++;
Ptr += (wcslen(Ptr) + 1);
}
lpArgVector[dwArgCount] = NULL;
(lpService->Main.lpFuncW)(dwArgCount, lpArgVector);
HeapFree(GetProcessHeap(),
0,
lpArgVector);
}
else
{
(lpService->Main.lpFuncA)(0, NULL);
}
return ERROR_SUCCESS;
}
@ -141,17 +186,29 @@ ScConnectControlPipe(HANDLE *hPipe)
}
static BOOL
ScServiceDispatcher(HANDLE hPipe,
PUCHAR lpBuffer,
DWORD dwBufferSize)
static DWORD
ScStartService(PSCM_START_PACKET StartPacket)
{
PACTIVE_SERVICE lpService;
HANDLE ThreadHandle;
DPRINT("ScDispatcherLoop() called\n");
DPRINT("Size: %lu\n", StartPacket->Size);
DPRINT("Service: %S\n", &StartPacket->Arguments[0]);
lpService = &lpActiveServices[0];
lpService = ScLookupServiceByServiceName(&StartPacket->Arguments[0]);
if (lpService == NULL)
return ERROR_SERVICE_DOES_NOT_EXIST;
lpService->Arguments = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
StartPacket->Size);
if (lpService->Arguments == NULL)
return ERROR_OUTOFMEMORY;
memcpy(lpService->Arguments,
StartPacket->Arguments,
StartPacket->Size * sizeof(WCHAR));
ThreadHandle = CreateThread(NULL,
0,
@ -160,21 +217,63 @@ ScServiceDispatcher(HANDLE hPipe,
CREATE_SUSPENDED,
&lpService->ThreadId);
if (ThreadHandle == NULL)
return FALSE;
return ERROR_SERVICE_NO_THREAD;
ResumeThread(ThreadHandle);
CloseHandle(ThreadHandle);
#if 0
return ERROR_SUCCESS;
}
static BOOL
ScServiceDispatcher(HANDLE hPipe,
PUCHAR lpBuffer,
DWORD dwBufferSize)
{
LPDWORD Buffer;
DWORD Count;
BOOL bResult;
DPRINT("ScDispatcherLoop() called\n");
Buffer = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
1024);
if (Buffer == NULL)
return FALSE;
while (TRUE)
{
/* Read command from the control pipe */
bResult = ReadFile(hPipe,
Buffer,
1024,
&Count,
NULL);
if (bResult == FALSE)
{
DPRINT1("Pipe read failed\n");
return FALSE;
}
/* Execute command */
switch (Buffer[0])
{
case SCM_START_COMMAND:
DPRINT("Start command\n");
ScStartService((PSCM_START_PACKET)Buffer);
break;
default:
DPRINT1("Unknown command %lu", Buffer[0]);
break;
}
}
#endif
HeapFree(GetProcessHeap(),
0,
Buffer);
return TRUE;
}
@ -324,7 +423,8 @@ StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
{
RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
lpServiceStartTable[i].lpServiceName);
lpActiveServices[i].MainFunction = (LPSERVICE_MAIN_FUNCTIONW)lpServiceStartTable[i].lpServiceProc;
lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc;
lpActiveServices[i].bUnicode = FALSE;
}
dwError = ScConnectControlPipe(&hPipe);
@ -400,7 +500,8 @@ StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
{
RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
lpServiceStartTable[i].lpServiceName);
lpActiveServices[i].MainFunction = lpServiceStartTable[i].lpServiceProc;
lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc;
lpActiveServices[i].bUnicode = TRUE;
}
dwError = ScConnectControlPipe(&hPipe);

View file

@ -32,6 +32,7 @@
#include <windows.h>
#include <tchar.h>
#include <services/services.h>
#include "services.h"
#define NDEBUG
@ -521,8 +522,72 @@ ScmGetBootAndSystemDriverState(VOID)
static NTSTATUS
ScmStartService(PSERVICE Service,
PSERVICE_GROUP Group)
ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
{
PSCM_START_PACKET StartPacket;
DWORD TotalLength;
#if 0
DWORD Length;
#endif
PWSTR Ptr;
DWORD Count;
DPRINT("ScmSendStartCommand() called\n");
/* Calculate the total length of the start command line */
TotalLength = wcslen(Service->ServiceName.Buffer) + 1;
#if 0
if (Arguments != NULL)
{
Ptr = Arguments;
while (*Ptr)
{
Length = wcslen(Ptr) + 1;
TotalLength += Length;
Ptr += Length;
}
}
#endif
TotalLength++;
/* Allocate start command packet */
StartPacket = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
if (StartPacket == NULL)
return STATUS_INSUFFICIENT_RESOURCES;
StartPacket->Command = SCM_START_COMMAND;
StartPacket->Size = TotalLength;
Ptr = &StartPacket->Arguments[0];
wcscpy(Ptr, Service->ServiceName.Buffer);
Ptr += (wcslen(Service->ServiceName.Buffer) + 1);
/* FIXME: Copy argument list */
*Ptr = 0;
/* Send the start command */
WriteFile(Service->ControlPipeHandle,
StartPacket,
sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
&Count,
NULL);
/* FIXME: Read the reply */
HeapFree(GetProcessHeap(),
0,
StartPacket);
DPRINT("ScmSendStartCommand() done\n");
return STATUS_SUCCESS;
}
static NTSTATUS
ScmStartUserModeService(PSERVICE Service)
{
RTL_QUERY_REGISTRY_TABLE QueryTable[3];
PROCESS_INFORMATION ProcessInformation;
@ -532,6 +597,149 @@ ScmStartService(PSERVICE Service,
BOOL Result;
NTSTATUS Status;
RtlInitUnicodeString(&ImagePath, NULL);
/* Get service data */
RtlZeroMemory(&QueryTable,
sizeof(QueryTable));
QueryTable[0].Name = L"Type";
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[0].EntryContext = &Type;
QueryTable[1].Name = L"ImagePath";
QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[1].EntryContext = &ImagePath;
Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
Service->ServiceName.Buffer,
QueryTable,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
return Status;
}
DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
DPRINT("Type: %lx\n", Type);
/* Create '\\.\pipe\net\NtControlPipe' instance */
Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
100,
8000,
4,
30000,
NULL);
DPRINT("CreateNamedPipeW() done\n");
if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
{
DPRINT1("Failed to create control pipe!\n");
return STATUS_UNSUCCESSFUL;
}
StartupInfo.cb = sizeof(StartupInfo);
StartupInfo.lpReserved = NULL;
StartupInfo.lpDesktop = NULL;
StartupInfo.lpTitle = NULL;
StartupInfo.dwFlags = 0;
StartupInfo.cbReserved2 = 0;
StartupInfo.lpReserved2 = 0;
Result = CreateProcessW(ImagePath.Buffer,
NULL,
NULL,
NULL,
FALSE,
DETACHED_PROCESS | CREATE_SUSPENDED,
NULL,
NULL,
&StartupInfo,
&ProcessInformation);
RtlFreeUnicodeString(&ImagePath);
if (!Result)
{
/* Close control pipe */
CloseHandle(Service->ControlPipeHandle);
Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
DPRINT1("Starting '%S' failed!\n", Service->ServiceName.Buffer);
return STATUS_UNSUCCESSFUL;
}
DPRINT("Process Id: %lu Handle %lx\n",
ProcessInformation.dwProcessId,
ProcessInformation.hProcess);
DPRINT("Thread Id: %lu Handle %lx\n",
ProcessInformation.dwThreadId,
ProcessInformation.hThread);
/* Get process and thread ids */
Service->ProcessId = ProcessInformation.dwProcessId;
Service->ThreadId = ProcessInformation.dwThreadId;
/* Resume Thread */
ResumeThread(ProcessInformation.hThread);
/* Connect control pipe */
if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
{
DWORD dwProcessId = 0;
DWORD dwRead = 0;
DPRINT("Control pipe connected!\n");
/* Read thread id from pipe */
if (!ReadFile(Service->ControlPipeHandle,
(LPVOID)&dwProcessId,
sizeof(DWORD),
&dwRead,
NULL))
{
DPRINT1("Reading the service control pipe failed (Error %lu)\n",
GetLastError());
Status = STATUS_UNSUCCESSFUL;
}
else
{
DPRINT("Received process id %lu\n", dwProcessId);
/* FIXME: Send start command */
Status = STATUS_SUCCESS;
}
}
else
{
DPRINT("Connecting control pipe failed!\n");
/* Close control pipe */
CloseHandle(Service->ControlPipeHandle);
Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
Service->ProcessId = 0;
Service->ThreadId = 0;
Status = STATUS_UNSUCCESSFUL;
}
ScmSendStartCommand(Service, NULL);
/* Close process and thread handle */
CloseHandle(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hProcess);
return Status;
}
static NTSTATUS
ScmStartService(PSERVICE Service,
PSERVICE_GROUP Group)
{
NTSTATUS Status;
DPRINT("ScmStartService() called\n");
Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
@ -547,138 +755,10 @@ ScmStartService(PSERVICE Service,
}
else
{
RtlInitUnicodeString(&ImagePath, NULL);
/* Get service data */
RtlZeroMemory(&QueryTable,
sizeof(QueryTable));
QueryTable[0].Name = L"Type";
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[0].EntryContext = &Type;
QueryTable[1].Name = L"ImagePath";
QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[1].EntryContext = &ImagePath;
Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
Service->ServiceName.Buffer,
QueryTable,
NULL,
NULL);
if (NT_SUCCESS(Status))
{
DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
DPRINT("Type: %lx\n", Type);
/* FIXME: create '\\.\pipe\net\NtControlPipe' instance */
Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
100,
8000,
4,
30000,
NULL);
DPRINT("CreateNamedPipeW() done\n");
if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
{
DPRINT1("Failed to create control pipe!\n");
Status = STATUS_UNSUCCESSFUL;
goto Done;
}
StartupInfo.cb = sizeof(StartupInfo);
StartupInfo.lpReserved = NULL;
StartupInfo.lpDesktop = NULL;
StartupInfo.lpTitle = NULL;
StartupInfo.dwFlags = 0;
StartupInfo.cbReserved2 = 0;
StartupInfo.lpReserved2 = 0;
Result = CreateProcessW(ImagePath.Buffer,
NULL,
NULL,
NULL,
FALSE,
DETACHED_PROCESS | CREATE_SUSPENDED,
NULL,
NULL,
&StartupInfo,
&ProcessInformation);
RtlFreeUnicodeString(&ImagePath);
if (!Result)
{
/* Close control pipe */
CloseHandle(Service->ControlPipeHandle);
Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
DPRINT1("Starting '%S' failed!\n", Service->ServiceName.Buffer);
Status = STATUS_UNSUCCESSFUL;
}
else
{
DPRINT("Process Id: %lu Handle %lx\n",
ProcessInformation.dwProcessId,
ProcessInformation.hProcess);
DPRINT("Thread Id: %lu Handle %lx\n",
ProcessInformation.dwThreadId,
ProcessInformation.hThread);
/* Get process and thread ids */
Service->ProcessId = ProcessInformation.dwProcessId;
Service->ThreadId = ProcessInformation.dwThreadId;
/* Resume Thread */
ResumeThread(ProcessInformation.hThread);
/* Connect control pipe */
if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
{
DWORD dwProcessId = 0;
DWORD dwRead = 0;
DPRINT("Control pipe connected!\n");
/* FIXME: Read thread id from pipe */
if (!ReadFile(Service->ControlPipeHandle,
(LPVOID)&dwProcessId,
sizeof(DWORD),
&dwRead,
NULL))
{
DPRINT1("Reading the service control pipe failed (Error %lu)\n", GetLastError());
}
else
{
DPRINT("Received process id %lu\n", dwProcessId);
/* FIXME: Send start command */
Status = STATUS_SUCCESS;
}
}
else
{
DPRINT("Connecting control pipe failed!\n");
/* Close control pipe */
CloseHandle(Service->ControlPipeHandle);
Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
Service->ProcessId = 0;
Service->ThreadId = 0;
Status = STATUS_UNSUCCESSFUL;
}
/* Close process and thread handle */
CloseHandle(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hProcess);
}
}
/* Start user-mode service */
Status = ScmStartUserModeService(Service);
}
Done:
DPRINT("ScmStartService() done (Status %lx)\n", Status);
if (NT_SUCCESS(Status))