From 15d5f5709efcafafc619ce686ac40963b622dcb4 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Mon, 12 Apr 2004 17:14:55 +0000 Subject: [PATCH] - Initial hacky implementation of some SCM calls needed by coLinux. svn path=/trunk/; revision=9110 --- reactos/include/services/scmprot.h | 115 ++++++ reactos/lib/advapi32/service/scm.c | 358 +++++++++++++++- reactos/subsys/system/services/database.c | 81 ++-- reactos/subsys/system/services/services.c | 478 +++++++++++++++++++++- reactos/subsys/system/services/services.h | 34 ++ 5 files changed, 984 insertions(+), 82 deletions(-) create mode 100644 reactos/include/services/scmprot.h diff --git a/reactos/include/services/scmprot.h b/reactos/include/services/scmprot.h new file mode 100644 index 00000000000..12d6f8a358a --- /dev/null +++ b/reactos/include/services/scmprot.h @@ -0,0 +1,115 @@ +/* + * Service Control Manager - Protocol Header + * + * Copyright (C) 2004 Filip Navara + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; see the file COPYING.LIB. If not, write + * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, + * MA 02139, USA. + * + * $Id: scmprot.h,v 1.1 2004/04/12 17:14:26 navaraf Exp $ + */ + +#ifndef _SCM_H +#define _SCM_H + +/* + * NOTE: + * This protocol isn't compatible with the Windows (R) one. Since + * Windows (R) XP (or 2000?) all the communcation goes through RPC. + * We don't have RPC implemented yet, so it can't be used yet :( + */ + +typedef struct +{ + ULONG Length; + WCHAR Buffer[256]; +} SCM_STRING; + +#define INIT_SCM_STRING(x, y) x.Length = wcslen(y) * sizeof(WCHAR), RtlCopyMemory(x.Buffer, y, x.Length + sizeof(UNICODE_NULL)) + +/* + * Global requests + */ + +#define SCM_OPENSERVICE 0x14 +#define SCM_CREATESERVICE 0x20 + +typedef struct _SCM_OPENSERVICE_REQUEST +{ + DWORD RequestCode; + SCM_STRING ServiceName; + DWORD dwDesiredAccess; +} SCM_OPENSERVICE_REQUEST, *PSCM_OPENSERVICE_REQUEST; + +typedef struct _SCM_OPENSERVICE_REPLY +{ + DWORD ReplyStatus; + WCHAR PipeName[128]; +} SCM_OPENSERVICE_REPLY, *PSCM_OPENSERVICE_REPLY; + +typedef struct _SCM_CREATESERVICE_REQUEST +{ + DWORD RequestCode; + SCM_STRING ServiceName; + SCM_STRING DisplayName; + DWORD dwDesiredAccess; + DWORD dwServiceType; + DWORD dwStartType; + DWORD dwErrorControl; + SCM_STRING BinaryPathName; + SCM_STRING LoadOrderGroup; + SCM_STRING Dependencies; + SCM_STRING ServiceStartName; + SCM_STRING Password; +} SCM_CREATESERVICE_REQUEST, *PSCM_CREATESERVICE_REQUEST; + +typedef struct _SCM_CREATESERVICE_REPLY +{ + DWORD ReplyStatus; + WCHAR PipeName[128]; +} SCM_CREATESERVICE_REPLY, *PSCM_CREATESERVICE_REPLY; + +typedef union _SCM_REQUEST +{ + DWORD RequestCode; + SCM_OPENSERVICE_REQUEST OpenService; + SCM_CREATESERVICE_REQUEST CreateService; +} SCM_REQUEST, *PSCM_REQUEST; + +typedef union _SCM_REPLY +{ + DWORD ReplyStatus; + SCM_OPENSERVICE_REPLY OpenService; + SCM_CREATESERVICE_REPLY CreateService; +} SCM_REPLY, *PSCM_REPLY; + +/* + * Per service requests + */ + +#define SCM_DELETESERVICE 0x10 +#define SCM_STARTSERVICE 0x11 + +typedef union _SCM_SERVICE_REQUEST +{ + DWORD RequestCode; +} SCM_SERVICE_REQUEST, *PSCM_SERVICE_REQUEST; + +typedef union _SCM_SERVICE_REPLY +{ + DWORD ReplyStatus; +} SCM_SERVICE_REPLY, *PSCM_SERVICE_REPLY; + +#endif diff --git a/reactos/lib/advapi32/service/scm.c b/reactos/lib/advapi32/service/scm.c index ae519b77c45..298b9f6e2e8 100644 --- a/reactos/lib/advapi32/service/scm.c +++ b/reactos/lib/advapi32/service/scm.c @@ -1,4 +1,4 @@ -/* $Id: scm.c,v 1.19 2003/08/07 04:03:22 royce Exp $ +/* $Id: scm.c,v 1.20 2004/04/12 17:14:54 navaraf Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries @@ -17,8 +17,9 @@ #include #include #include +#include -#define DBG +//#define DBG #include /* FUNCTIONS *****************************************************************/ @@ -82,14 +83,14 @@ BOOL STDCALL CloseServiceHandle(SC_HANDLE hSCObject) { - HANDLE hPipe; - DPRINT("CloseServiceHandle() - called.\n"); -// SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + DPRINT("CloseServiceHandle\n"); - if (!CloseHandle(hPipe)) { + if (!CloseHandle(hSCObject)) + { SetLastError(ERROR_INVALID_HANDLE); return FALSE; } + return TRUE; } @@ -132,8 +133,48 @@ CreateServiceA( LPCSTR lpServiceStartName, LPCSTR lpPassword) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; + UNICODE_STRING lpServiceNameW; + UNICODE_STRING lpDisplayNameW; + UNICODE_STRING lpBinaryPathNameW; + UNICODE_STRING lpLoadOrderGroupW; + UNICODE_STRING lpServiceStartNameW; + UNICODE_STRING lpPasswordW; + SC_HANDLE hService; + + RtlCreateUnicodeStringFromAsciiz(&lpServiceNameW, (LPSTR)lpServiceName); + RtlCreateUnicodeStringFromAsciiz(&lpDisplayNameW, (LPSTR)lpDisplayName); + RtlCreateUnicodeStringFromAsciiz(&lpBinaryPathNameW, (LPSTR)lpBinaryPathName); + RtlCreateUnicodeStringFromAsciiz(&lpLoadOrderGroupW, (LPSTR)lpLoadOrderGroup); + RtlCreateUnicodeStringFromAsciiz(&lpServiceStartNameW, (LPSTR)lpServiceStartName); + RtlCreateUnicodeStringFromAsciiz(&lpPasswordW, (LPSTR)lpPassword); + if (lpDependencies != NULL) + { + DPRINT1("Unimplemented case\n"); + } + + hService = CreateServiceW( + hSCManager, + lpServiceNameW.Buffer, + lpDisplayNameW.Buffer, + dwDesiredAccess, + dwServiceType, + dwStartType, + dwErrorControl, + lpBinaryPathNameW.Buffer, + lpLoadOrderGroupW.Buffer, + lpdwTagId, + NULL, + lpServiceStartNameW.Buffer, + lpPasswordW.Buffer); + + RtlFreeUnicodeString(&lpServiceNameW); + RtlFreeUnicodeString(&lpDisplayNameW); + RtlFreeUnicodeString(&lpBinaryPathNameW); + RtlFreeUnicodeString(&lpLoadOrderGroupW); + RtlFreeUnicodeString(&lpServiceStartNameW); + RtlFreeUnicodeString(&lpPasswordW); + + return hService; } @@ -159,8 +200,104 @@ CreateServiceW( LPCWSTR lpServiceStartName, LPCWSTR lpPassword) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; + SCM_CREATESERVICE_REQUEST Request; + SCM_CREATESERVICE_REPLY Reply; + BOOL fSuccess; + DWORD cbWritten, cbRead; + SC_HANDLE hService; + + DPRINT("CreateServiceW\n"); + + if (lpServiceName == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + Request.RequestCode = SCM_CREATESERVICE; + INIT_SCM_STRING(Request.ServiceName, lpServiceName); + INIT_SCM_STRING(Request.DisplayName, lpDisplayName); + Request.dwDesiredAccess = dwDesiredAccess; + Request.dwServiceType = dwServiceType; + Request.dwStartType = dwStartType; + Request.dwErrorControl = dwErrorControl; +#if 0 + INIT_SCM_STRING(Request.BinaryPathName, lpBinaryPathName); +#else + Request.BinaryPathName.Length = (wcslen(lpBinaryPathName) + 4) * sizeof(WCHAR); + swprintf(Request.BinaryPathName.Buffer, L"\\??\\%s", lpBinaryPathName); +#endif + INIT_SCM_STRING(Request.LoadOrderGroup, lpLoadOrderGroup); + INIT_SCM_STRING(Request.ServiceStartName, lpServiceStartName); + INIT_SCM_STRING(Request.Password, lpPassword); + if (lpDependencies != NULL) + { + DWORD Length; + for (Length = 0; + lpDependencies[Length++]; + Length += lstrlenW(&lpDependencies[Length]) + 1) + ; + Request.Dependencies.Length = Length; + } + else + { + Request.Dependencies.Length = 0; + } + RtlCopyMemory( + Request.Dependencies.Buffer, + lpDependencies, + Request.Dependencies.Length); + + fSuccess = WriteFile( + hSCManager, // pipe handle + &Request, // message + sizeof(Request), // message length + &cbWritten, // bytes written + NULL); // not overlapped + + if (!fSuccess || cbWritten != sizeof(Request)) + { + DPRINT("CreateServiceW - Failed to write to pipe.\n"); + return NULL; + } + + fSuccess = ReadFile( + hSCManager, // pipe handle + &Reply, // buffer to receive reply + sizeof(Reply), // size of buffer + &cbRead, // number of bytes read + NULL); // not overlapped + + if (!fSuccess && GetLastError() != ERROR_MORE_DATA) + { + DPRINT("CreateServiceW - Error\n"); + return NULL; + } + + if (Reply.ReplyStatus != NO_ERROR) + { + DPRINT("CreateServiceW - Error (%x)\n", Reply.ReplyStatus); + SetLastError(Reply.ReplyStatus); + return NULL; + } + + hService = CreateFileW( + Reply.PipeName, // pipe name + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + 0, // no sharing + NULL, // no security attributes + OPEN_EXISTING, // opens existing pipe + 0, // default attributes + NULL); // no template file + + if (hService == INVALID_HANDLE_VALUE) + { + /* FIXME: Set last error! */ + return NULL; + } + + DPRINT("CreateServiceW - Success - %x\n", hService); + return hService; } @@ -173,8 +310,51 @@ BOOL STDCALL DeleteService(SC_HANDLE hService) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return FALSE; + SCM_SERVICE_REQUEST Request; + SCM_SERVICE_REPLY Reply; + BOOL fSuccess; + DWORD cbWritten, cbRead; + + DPRINT("DeleteService\n"); + + Request.RequestCode = SCM_DELETESERVICE; + + fSuccess = WriteFile( + hService, // pipe handle + &Request, // message + sizeof(DWORD), // message length + &cbWritten, // bytes written + NULL); // not overlapped + + if (!fSuccess || cbWritten != sizeof(DWORD)) + { + DPRINT("Error: %x . %x\n", GetLastError(), hService); + /* FIXME: Set last error */ + return FALSE; + } + + fSuccess = ReadFile( + hService, // pipe handle + &Reply, // buffer to receive reply + sizeof(DWORD), // size of buffer + &cbRead, // number of bytes read + NULL); // not overlapped + + if (!fSuccess && GetLastError() != ERROR_MORE_DATA) + { + CHECKPOINT; + /* FIXME: Set last error */ + return FALSE; + } + + if (Reply.ReplyStatus != NO_ERROR) + { + CHECKPOINT; + SetLastError(Reply.ReplyStatus); + return FALSE; + } + + return TRUE; } @@ -634,22 +814,34 @@ SC_HANDLE STDCALL OpenSCManagerW(LPCWSTR lpMachineName, /********************************************************************** * OpenServiceA * - * @unimplemented + * @implemented */ -SC_HANDLE STDCALL -OpenServiceA(SC_HANDLE hSCManager, - LPCSTR lpServiceName, - DWORD dwDesiredAccess) +SC_HANDLE +STDCALL +OpenServiceA( + SC_HANDLE hSCManager, + LPCSTR lpServiceName, + DWORD dwDesiredAccess + ) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; + UNICODE_STRING lpServiceNameW; + SC_HANDLE hService; + + RtlCreateUnicodeStringFromAsciiz(&lpServiceNameW, (LPSTR)lpServiceName); + hService = OpenServiceW( + hSCManager, + lpServiceNameW.Buffer, + dwDesiredAccess); + RtlFreeUnicodeString(&lpServiceNameW); + + return hService; } /********************************************************************** * OpenServiceW * - * @unimplemented + * @implemented */ SC_HANDLE STDCALL @@ -659,8 +851,74 @@ OpenServiceW( DWORD dwDesiredAccess ) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; + SCM_OPENSERVICE_REQUEST Request; + SCM_OPENSERVICE_REPLY Reply; + BOOL fSuccess; + DWORD cbWritten, cbRead; + SC_HANDLE hService; + + DPRINT("OpenServiceW\n"); + + if (lpServiceName == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + Request.RequestCode = SCM_OPENSERVICE; + INIT_SCM_STRING(Request.ServiceName, lpServiceName); + Request.dwDesiredAccess = dwDesiredAccess; + + fSuccess = WriteFile( + hSCManager, // pipe handle + &Request, // message + sizeof(Request), // message length + &cbWritten, // bytes written + NULL); // not overlapped + + if (!fSuccess || cbWritten != sizeof(Request)) + { + DPRINT("OpenServiceW - Failed to write to pipe.\n"); + return NULL; + } + + fSuccess = ReadFile( + hSCManager, // pipe handle + &Reply, // buffer to receive reply + sizeof(Reply), // size of buffer + &cbRead, // number of bytes read + NULL); // not overlapped + + if (!fSuccess && GetLastError() != ERROR_MORE_DATA) + { + DPRINT("OpenServiceW - Failed to read from pipe\n"); + return NULL; + } + + if (Reply.ReplyStatus != NO_ERROR) + { + DPRINT("OpenServiceW - Error (%x)\n", Reply.ReplyStatus); + SetLastError(Reply.ReplyStatus); + return NULL; + } + + hService = CreateFileW( + Reply.PipeName, // pipe name + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + 0, // no sharing + NULL, // no security attributes + OPEN_EXISTING, // opens existing pipe + 0, // default attributes + NULL); // no template file + + if (hService == INVALID_HANDLE_VALUE) + { + DPRINT("OpenServiceW - Failed to connect to pipe\n"); + return NULL; + } + + DPRINT("OpenServiceW - Success - %x\n", hService); + return hService; } @@ -801,8 +1059,63 @@ StartServiceA( DWORD dwNumServiceArgs, LPCSTR *lpServiceArgVectors) { +#if 0 + DPRINT("StartServiceA\n"); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; +#else + SCM_SERVICE_REQUEST Request; + SCM_SERVICE_REPLY Reply; + BOOL fSuccess; + DWORD cbWritten, cbRead; + + DPRINT("StartServiceA\n"); + + if (dwNumServiceArgs != 0) + { + UNIMPLEMENTED; + } + + Request.RequestCode = SCM_STARTSERVICE; + + fSuccess = WriteFile( + hService, // pipe handle + &Request, // message + sizeof(DWORD), // message length + &cbWritten, // bytes written + NULL); // not overlapped + + if (!fSuccess || cbWritten != sizeof(DWORD)) + { + DPRINT("Error: %x . %x\n", GetLastError(), hService); + /* FIXME: Set last error */ + return FALSE; + } + + fSuccess = ReadFile( + hService, // pipe handle + &Reply, // buffer to receive reply + sizeof(DWORD), // size of buffer + &cbRead, // number of bytes read + NULL); // not overlapped + + if (!fSuccess && GetLastError() != ERROR_MORE_DATA) + { + CHECKPOINT; + /* FIXME: Set last error */ + return FALSE; + } + + if (Reply.ReplyStatus != NO_ERROR) + { + CHECKPOINT; + SetLastError(Reply.ReplyStatus); + return FALSE; + } + + CHECKPOINT; + return TRUE; +#endif } @@ -820,6 +1133,7 @@ StartServiceW( DWORD dwNumServiceArgs, LPCWSTR *lpServiceArgVectors) { + DPRINT("StartServiceW\n"); SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return FALSE; } diff --git a/reactos/subsys/system/services/database.c b/reactos/subsys/system/services/database.c index e3185364881..b0fd0bd18f7 100644 --- a/reactos/subsys/system/services/database.c +++ b/reactos/subsys/system/services/database.c @@ -1,4 +1,4 @@ -/* $Id: database.c,v 1.14 2004/04/11 16:10:05 jfilby Exp $ +/* $Id: database.c,v 1.15 2004/04/12 17:14:54 navaraf Exp $ * * service control manager * @@ -38,39 +38,6 @@ #include -/* TYPES *********************************************************************/ - -typedef struct _SERVICE_GROUP -{ - LIST_ENTRY GroupListEntry; - UNICODE_STRING GroupName; - - BOOLEAN ServicesRunning; - -} SERVICE_GROUP, *PSERVICE_GROUP; - - -typedef struct _SERVICE -{ - LIST_ENTRY ServiceListEntry; - UNICODE_STRING ServiceName; - UNICODE_STRING RegistryPath; - UNICODE_STRING ServiceGroup; - - ULONG Start; - ULONG Type; - ULONG ErrorControl; - ULONG Tag; - - BOOLEAN ServiceRunning; - BOOLEAN ServiceVisited; - - HANDLE ControlPipeHandle; - ULONG ProcessId; - ULONG ThreadId; -} SERVICE, *PSERVICE; - - /* GLOBALS *******************************************************************/ LIST_ENTRY GroupListHead; @@ -116,8 +83,8 @@ CreateGroupListRoutine(PWSTR ValueName, } -static NTSTATUS STDCALL -CreateServiceListEntry(PUNICODE_STRING ServiceName) +PSERVICE FASTCALL +ScmCreateServiceListEntry(PUNICODE_STRING ServiceName) { RTL_QUERY_REGISTRY_TABLE QueryTable[6]; PSERVICE Service = NULL; @@ -130,7 +97,7 @@ CreateServiceListEntry(PUNICODE_STRING ServiceName) sizeof(SERVICE)); if (Service == NULL) { - return(STATUS_INSUFFICIENT_RESOURCES); + return NULL; } /* Copy service name */ @@ -141,7 +108,7 @@ CreateServiceListEntry(PUNICODE_STRING ServiceName) if (Service->ServiceName.Buffer == NULL) { HeapFree(GetProcessHeap(), 0, Service); - return(STATUS_INSUFFICIENT_RESOURCES); + return NULL; } RtlCopyMemory(Service->ServiceName.Buffer, ServiceName->Buffer, @@ -156,7 +123,7 @@ CreateServiceListEntry(PUNICODE_STRING ServiceName) { HeapFree(GetProcessHeap(), 0, Service->ServiceName.Buffer); HeapFree(GetProcessHeap(), 0, Service); - return(STATUS_INSUFFICIENT_RESOURCES); + return NULL; } wcscpy(Service->RegistryPath.Buffer, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"); @@ -195,7 +162,7 @@ CreateServiceListEntry(PUNICODE_STRING ServiceName) RtlFreeUnicodeString(&Service->RegistryPath); RtlFreeUnicodeString(&Service->ServiceName); HeapFree(GetProcessHeap(), 0, Service); - return(Status); + return NULL; } DPRINT("ServiceName: '%wZ'\n", &Service->ServiceName); @@ -208,7 +175,7 @@ CreateServiceListEntry(PUNICODE_STRING ServiceName) InsertTailList(&ServiceListHead, &Service->ServiceListEntry); - return(STATUS_SUCCESS); + return Service; } @@ -293,7 +260,10 @@ ScmCreateServiceDataBase(VOID) SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = 0; DPRINT("KeyName: '%wZ'\n", &SubKeyName); - Status = CreateServiceListEntry(&SubKeyName); + if (ScmCreateServiceListEntry(&SubKeyName) == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } } } @@ -446,7 +416,7 @@ ScmGetBootAndSystemDriverState(VOID) } -static NTSTATUS +NTSTATUS FASTCALL ScmStartService(PSERVICE Service, PSERVICE_GROUP Group) { @@ -625,7 +595,7 @@ Done: } #endif - return(STATUS_SUCCESS); + return Status; //(STATUS_SUCCESS); } @@ -720,4 +690,27 @@ ScmAutoStartServices(VOID) } } +/* + * FIXME: Doesn't work!!! + */ +PSERVICE FASTCALL +ScmFindService(PUNICODE_STRING ServiceName) +{ + PSERVICE CurrentService; + PLIST_ENTRY ServiceEntry; + + ServiceEntry = ServiceListHead.Flink; + while (ServiceEntry != &ServiceListHead) + { + CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); + if (!RtlCompareUnicodeString(ServiceName, &CurrentService->ServiceName, TRUE)) + { + return CurrentService; + } + ServiceEntry = ServiceEntry->Flink; + } + + return NULL; +} + /* EOF */ diff --git a/reactos/subsys/system/services/services.c b/reactos/subsys/system/services/services.c index c0924500cdb..03a2771e04c 100644 --- a/reactos/subsys/system/services/services.c +++ b/reactos/subsys/system/services/services.c @@ -1,4 +1,4 @@ -/* $Id: services.c,v 1.16 2004/04/12 15:22:53 navaraf Exp $ +/* $Id: services.c,v 1.17 2004/04/12 17:14:55 navaraf Exp $ * * service control manager * @@ -33,8 +33,11 @@ #include #include #include +#undef CreateService +#undef OpenService #include "services.h" +#include #define NDEBUG #include @@ -43,8 +46,7 @@ /* GLOBALS ******************************************************************/ -#define PIPE_BUFSIZE 1024 -#define PIPE_TIMEOUT 1000 +#define PIPE_TIMEOUT 10000 /* FUNCTIONS *****************************************************************/ @@ -91,17 +93,461 @@ ScmCreateStartEvent(PHANDLE StartEvent) } +typedef struct _SERVICE_THREAD_DATA +{ + HANDLE hPipe; + PSERVICE pService; +} SERVICE_THREAD_DATA, *PSERVICE_THREAD_DATA; + + +VOID FASTCALL +ScmHandleDeleteServiceRequest( + PSERVICE_THREAD_DATA pServiceThreadData, + PSCM_SERVICE_REQUEST Request, + DWORD RequestSize, + PSCM_SERVICE_REPLY Reply, + LPDWORD ReplySize) +{ + Reply->ReplyStatus = RtlNtStatusToDosError( + ScmStartService(pServiceThreadData->pService, NULL)); + *ReplySize = sizeof(DWORD); +} + + +VOID FASTCALL +ScmHandleStartServiceRequest( + PSERVICE_THREAD_DATA pServiceThreadData, + PSCM_SERVICE_REQUEST Request, + DWORD RequestSize, + PSCM_SERVICE_REPLY Reply, + LPDWORD ReplySize) +{ + OBJECT_ATTRIBUTES ObjectAttributes; + NTSTATUS Status; + HANDLE KeyHandle; + + InitializeObjectAttributes( + &ObjectAttributes, + &pServiceThreadData->pService->RegistryPath, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = ZwOpenKey( + &KeyHandle, + KEY_READ, + &ObjectAttributes); + + if (NT_SUCCESS(Status)) + { + Status = ZwDeleteKey(KeyHandle); + if (NT_SUCCESS(Status)) + { + ZwClose(KeyHandle); + CHECKPOINT; + RemoveEntryList(&pServiceThreadData->pService->ServiceListEntry); + } + } + Reply->ReplyStatus = RtlNtStatusToDosError(Status); + *ReplySize = sizeof(DWORD); +} + + +DWORD +WINAPI +ScmNamedPipeServiceThread(LPVOID Context) +{ + SCM_SERVICE_REQUEST Request; + SCM_SERVICE_REPLY Reply; + DWORD cbBytesRead; + DWORD cbWritten, cbReplyBytes; + BOOL fSuccess; + PSERVICE_THREAD_DATA pServiceThreadData = Context; + + ConnectNamedPipe(pServiceThreadData->hPipe, NULL); + + for (;;) + { + fSuccess = ReadFile( + pServiceThreadData->hPipe, + &Request, + sizeof(Request), + &cbBytesRead, + NULL); + + if (!fSuccess || cbBytesRead == 0) + { + break; + } + + switch (Request.RequestCode) + { + case SCM_DELETESERVICE: + ScmHandleDeleteServiceRequest( + pServiceThreadData, + &Request, + cbBytesRead, + &Reply, + &cbReplyBytes); + break; + + case SCM_STARTSERVICE: + ScmHandleStartServiceRequest( + pServiceThreadData, + &Request, + cbBytesRead, + &Reply, + &cbReplyBytes); + break; + } + + fSuccess = WriteFile( + pServiceThreadData->hPipe, + &Reply, + cbReplyBytes, + &cbWritten, + NULL); + + if (!fSuccess || cbReplyBytes != cbWritten) + { + break; + } + } + + FlushFileBuffers(pServiceThreadData->hPipe); + DisconnectNamedPipe(pServiceThreadData->hPipe); + CloseHandle(pServiceThreadData->hPipe); + + return NO_ERROR; +} + + +VOID FASTCALL +ScmCreateServiceThread( + HANDLE hSCMPipe, + PSCM_OPENSERVICE_REPLY Reply, + LPDWORD ReplySize, + PSERVICE Service) +{ + HANDLE hPipe, hThread; + DWORD dwThreadId; + PSERVICE_THREAD_DATA ServiceThreadData; + + ServiceThreadData = HeapAlloc( + GetProcessHeap(), + 0, + sizeof(SERVICE_THREAD_DATA)); + + if (ServiceThreadData == NULL) + { + Reply->ReplyStatus = ERROR_NO_SYSTEM_RESOURCES; + CHECKPOINT; + return; + } + + swprintf(Reply->PipeName, L"\\\\.\\pipe\\SCM.%08X.%08X", hSCMPipe, Service); + + hPipe = CreateNamedPipeW( + Reply->PipeName, + PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + PIPE_UNLIMITED_INSTANCES, + sizeof(SCM_SERVICE_REQUEST), + sizeof(SCM_SERVICE_REPLY), + PIPE_TIMEOUT, + NULL); + + if (hPipe == INVALID_HANDLE_VALUE) + { + Reply->ReplyStatus = ERROR_NO_SYSTEM_RESOURCES; + CHECKPOINT; + return; + } + + ServiceThreadData->hPipe = hPipe; + ServiceThreadData->pService = Service; + + hThread = CreateThread( + NULL, + 0, + ScmNamedPipeServiceThread, + ServiceThreadData, + 0, + &dwThreadId); + + if (!hThread) + { + Reply->ReplyStatus = ERROR_NO_SYSTEM_RESOURCES; + CHECKPOINT; + CloseHandle(hPipe); + return; + } + + Reply->ReplyStatus = NO_ERROR; + *ReplySize = sizeof(SCM_OPENSERVICE_REPLY); +} + + +VOID FASTCALL +ScmHandleOpenServiceRequest( + HANDLE hPipe, + PSCM_REQUEST Request, + DWORD RequestSize, + PSCM_REPLY Reply, + LPDWORD ReplySize) +{ + PSERVICE Service; + UNICODE_STRING ServiceName; + + DPRINT("OpenService\n"); + + if (RequestSize != sizeof(SCM_OPENSERVICE_REQUEST)) + { + Reply->ReplyStatus = ERROR_INVALID_PARAMETER; + return; + } + + ServiceName.Length = Request->OpenService.ServiceName.Length; + ServiceName.Buffer = Request->OpenService.ServiceName.Buffer; + Service = ScmFindService(&ServiceName); + if (Service == NULL) + { + DPRINT("OpenService - Service not found\n"); + Reply->ReplyStatus = ERROR_SERVICE_DOES_NOT_EXIST; + return; + } + + DPRINT("OpenService - Service found\n"); + ScmCreateServiceThread( + hPipe, + &Reply->OpenService, + ReplySize, + Service); +} + + +VOID FASTCALL +ScmHandleCreateServiceRequest( + HANDLE hPipe, + PSCM_REQUEST Request, + DWORD RequestSize, + PSCM_REPLY Reply, + LPDWORD ReplySize) +{ + PSERVICE Service; + NTSTATUS Status; + UNICODE_STRING ServiceName; + + DPRINT("CreateService - %S\n", Request->CreateService.ServiceName.Buffer); + + if (RequestSize != sizeof(SCM_CREATESERVICE_REQUEST)) + { + Reply->ReplyStatus = ERROR_INVALID_PARAMETER; + return; + } + + Status = RtlCheckRegistryKey( + RTL_REGISTRY_SERVICES, + Request->CreateService.ServiceName.Buffer); + + if (NT_SUCCESS(Status)) + { + DPRINT("CreateService - Already exists\n"); + Reply->ReplyStatus = ERROR_SERVICE_EXISTS; + return; + } + + Status = RtlCreateRegistryKey( + RTL_REGISTRY_SERVICES, + Request->CreateService.ServiceName.Buffer); + + if (!NT_SUCCESS(Status)) + { + DPRINT("CreateService - Can't create key (%x)\n", Status); + Reply->ReplyStatus = Status; + return; + } + + Status = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + Request->CreateService.ServiceName.Buffer, + L"Type", + REG_DWORD, + &Request->CreateService.dwServiceType, + sizeof(DWORD)); + + if (!NT_SUCCESS(Status)) + { + DPRINT("CreateService - Error writing value\n"); + Reply->ReplyStatus = RtlNtStatusToDosError(Status); + return; + } + + Status = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + Request->CreateService.ServiceName.Buffer, + L"Start", + REG_DWORD, + &Request->CreateService.dwStartType, + sizeof(DWORD)); + + if (!NT_SUCCESS(Status)) + { + Reply->ReplyStatus = RtlNtStatusToDosError(Status); + return; + } + + Status = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + Request->CreateService.ServiceName.Buffer, + L"ErrorControl", + REG_DWORD, + &Request->CreateService.dwErrorControl, + sizeof(DWORD)); + + if (!NT_SUCCESS(Status)) + { + Reply->ReplyStatus = RtlNtStatusToDosError(Status); + return; + } + + if (Request->CreateService.BinaryPathName.Length) + { + Status = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + Request->CreateService.ServiceName.Buffer, + L"ImagePath", + REG_SZ, + Request->CreateService.BinaryPathName.Buffer, + Request->CreateService.BinaryPathName.Length + sizeof(UNICODE_NULL)); + + if (!NT_SUCCESS(Status)) + { + DPRINT("CreateService - Error writing value\n"); + Reply->ReplyStatus = RtlNtStatusToDosError(Status); + return; + } + } + + if (Request->CreateService.LoadOrderGroup.Length) + { + Status = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + Request->CreateService.ServiceName.Buffer, + L"Group", + REG_SZ, + Request->CreateService.LoadOrderGroup.Buffer, + Request->CreateService.LoadOrderGroup.Length + sizeof(UNICODE_NULL)); + + if (!NT_SUCCESS(Status)) + { + Reply->ReplyStatus = RtlNtStatusToDosError(Status); + return; + } + } + + if (Request->CreateService.Dependencies.Length) + { + Status = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + Request->CreateService.ServiceName.Buffer, + L"Dependencies", + REG_SZ, + Request->CreateService.Dependencies.Buffer, + Request->CreateService.Dependencies.Length + sizeof(UNICODE_NULL)); + + if (!NT_SUCCESS(Status)) + { + Reply->ReplyStatus = RtlNtStatusToDosError(Status); + return; + } + } + + if (Request->CreateService.DisplayName.Length) + { + Status = RtlWriteRegistryValue( + RTL_REGISTRY_SERVICES, + Request->CreateService.ServiceName.Buffer, + L"DisplayName", + REG_SZ, + Request->CreateService.DisplayName.Buffer, + Request->CreateService.DisplayName.Length + sizeof(UNICODE_NULL)); + + if (!NT_SUCCESS(Status)) + { + Reply->ReplyStatus = RtlNtStatusToDosError(Status); + return; + } + } + + if (Request->CreateService.ServiceStartName.Length || + Request->CreateService.Password.Length) + { + DPRINT1("Unimplemented case\n"); + } + + ServiceName.Length = Request->OpenService.ServiceName.Length; + ServiceName.Buffer = Request->OpenService.ServiceName.Buffer; + Service = ScmCreateServiceListEntry(&ServiceName); + if (Service == NULL) + { + DPRINT("CreateService - Error creating service list entry\n"); + Reply->ReplyStatus = ERROR_NOT_ENOUGH_MEMORY; + return; + } + + DPRINT("CreateService - Success\n"); + ScmCreateServiceThread( + hPipe, + &Reply->OpenService, + ReplySize, + Service); +} + + BOOL ScmNamedPipeHandleRequest( - PVOID Request, + HANDLE hPipe, + PSCM_REQUEST Request, DWORD RequestSize, - PVOID Reply, + PSCM_REPLY Reply, LPDWORD ReplySize) { - DbgPrint("SCM READ: %s\n", Request); + *ReplySize = sizeof(DWORD); + + if (RequestSize < sizeof(DWORD)) + { + Reply->ReplyStatus = ERROR_INVALID_PARAMETER; + return TRUE; + } - *ReplySize = 0; - return FALSE; + DPRINT("RequestCode: %x\n", Request->RequestCode); + + switch (Request->RequestCode) + { + case SCM_OPENSERVICE: + ScmHandleOpenServiceRequest( + hPipe, + Request, + RequestSize, + Reply, + ReplySize); + break; + + case SCM_CREATESERVICE: + ScmHandleCreateServiceRequest( + hPipe, + Request, + RequestSize, + Reply, + ReplySize); + break; + + default: + Reply->ReplyStatus = ERROR_INVALID_PARAMETER; + } + + return TRUE; } @@ -109,8 +555,8 @@ DWORD WINAPI ScmNamedPipeThread(LPVOID Context) { - CHAR chRequest[PIPE_BUFSIZE]; - CHAR chReply[PIPE_BUFSIZE]; + SCM_REQUEST Request; + SCM_REPLY Reply; DWORD cbReplyBytes; DWORD cbBytesRead; DWORD cbWritten; @@ -123,16 +569,16 @@ ScmNamedPipeThread(LPVOID Context) for (;;) { fSuccess = ReadFile(hPipe, - &chRequest, - PIPE_BUFSIZE, + &Request, + sizeof(Request), &cbBytesRead, NULL); if (!fSuccess || cbBytesRead == 0) { break; } - if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes)) { + if (ScmNamedPipeHandleRequest(hPipe, &Request, cbBytesRead, &Reply, &cbReplyBytes)) { fSuccess = WriteFile(hPipe, - &chReply, + &Reply, cbReplyBytes, &cbWritten, NULL); @@ -162,8 +608,8 @@ BOOL ScmCreateNamedPipe(VOID) PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - PIPE_BUFSIZE, - PIPE_BUFSIZE, + sizeof(SCM_REQUEST), + sizeof(SCM_REPLY), PIPE_TIMEOUT, NULL); if (hPipe == INVALID_HANDLE_VALUE) { diff --git a/reactos/subsys/system/services/services.h b/reactos/subsys/system/services/services.h index 443ac04e98e..d5177874eec 100644 --- a/reactos/subsys/system/services/services.h +++ b/reactos/subsys/system/services/services.h @@ -2,6 +2,34 @@ * services.h */ +typedef struct _SERVICE_GROUP +{ + LIST_ENTRY GroupListEntry; + UNICODE_STRING GroupName; + + BOOLEAN ServicesRunning; + +} SERVICE_GROUP, *PSERVICE_GROUP; + +typedef struct _SERVICE +{ + LIST_ENTRY ServiceListEntry; + UNICODE_STRING ServiceName; + UNICODE_STRING RegistryPath; + UNICODE_STRING ServiceGroup; + + ULONG Start; + ULONG Type; + ULONG ErrorControl; + ULONG Tag; + + BOOLEAN ServiceRunning; + BOOLEAN ServiceVisited; + + HANDLE ControlPipeHandle; + ULONG ProcessId; + ULONG ThreadId; +} SERVICE, *PSERVICE; /* services.c */ @@ -14,6 +42,12 @@ NTSTATUS ScmCreateServiceDataBase(VOID); VOID ScmGetBootAndSystemDriverState(VOID); VOID ScmAutoStartServices(VOID); +PSERVICE FASTCALL +ScmCreateServiceListEntry(PUNICODE_STRING ServiceName); +PSERVICE FASTCALL +ScmFindService(PUNICODE_STRING ServiceName); +NTSTATUS FASTCALL +ScmStartService(PSERVICE Service, PSERVICE_GROUP Group); /* EOF */ -- 2.17.1