#include "services.h"
-#include <winuser.h>
+#include <userenv.h>
#define NDEBUG
#include <debug.h>
-/*
- * Uncomment the line below to start services
- * using the SERVICE_START_PENDING state.
- */
-#define USE_SERVICE_START_PENDING
-
-/*
- * Uncomment the line below to use asynchronous IO operations
- * on the service control pipes.
- */
-// #define USE_ASYNCHRONOUS_IO
-
/* GLOBALS *******************************************************************/
static RTL_RESOURCE DatabaseLock;
static DWORD ResumeCount = 1;
+static DWORD NoInteractiveServices = 0;
/* The critical section synchronizes service control requests */
static CRITICAL_SECTION ControlServiceCriticalSection;
DPRINT("PipeName: %S\n", szControlPipeName);
pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName,
-#ifdef USE_ASYNCHRONOUS_IO
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
-#else
- PIPE_ACCESS_DUPLEX,
-#endif
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
100,
8000,
CurrentImage = CONTAINING_RECORD(ImageEntry,
SERVICE_IMAGE,
ImageListEntry);
- if (_wcsicmp(CurrentImage->szImagePath, lpImagePath) == 0)
+ if (_wcsicmp(CurrentImage->pszImagePath, lpImagePath) == 0)
{
- DPRINT("Found image: '%S'\n", CurrentImage->szImagePath);
+ DPRINT("Found image: '%S'\n", CurrentImage->pszImagePath);
return CurrentImage;
}
}
+static
+BOOL
+ScmIsSameServiceAccount(
+ _In_ PCWSTR pszAccountName1,
+ _In_ PCWSTR pszAccountName2)
+{
+ if (pszAccountName1 == NULL && pszAccountName2 == NULL)
+ return TRUE;
+
+ if (pszAccountName1 == NULL && pszAccountName2 && wcscmp(pszAccountName2, L"LocalSystem") == 0)
+ return TRUE;
+
+ if (pszAccountName2 == NULL && pszAccountName1 && wcscmp(pszAccountName1, L"LocalSystem") == 0)
+ return TRUE;
+
+ if (pszAccountName1 && pszAccountName2 && wcscmp(pszAccountName1, pszAccountName2) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+static
+BOOL
+ScmIsLocalSystemAccount(
+ _In_ PCWSTR pszAccountName)
+{
+ if (pszAccountName == NULL ||
+ wcscmp(pszAccountName, L"LocalSystem") == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+static
+DWORD
+ScmLogonService(
+ IN PSERVICE pService,
+ IN PSERVICE_IMAGE pImage)
+{
+#if 0
+ PROFILEINFOW ProfileInfo;
+ PWSTR pszUserName = NULL;
+ PWSTR pszDomainName = NULL;
+ PWSTR pszPassword = NULL;
+ PWSTR ptr;
+ DWORD dwError = ERROR_SUCCESS;
+#endif
+
+ DPRINT("ScmLogonService(%p %p)\n", pService, pImage);
+
+ DPRINT("Service %S\n", pService->lpServiceName);
+
+ if (ScmIsLocalSystemAccount(pImage->pszAccountName))
+ return ERROR_SUCCESS;
+
+ // FIXME: Always assume LocalSystem
+ return ERROR_SUCCESS;
+
+#if 0
+ /* Get the user and domain names */
+ ptr = wcschr(pImage->pszAccountName, L'\\');
+ if (ptr != NULL)
+ {
+ *ptr = L'\0';
+
+ pszUserName = ptr + 1;
+ pszDomainName = pImage->pszAccountName;
+ }
+ else
+ {
+ pszUserName = pImage->pszAccountName;
+ pszDomainName = NULL;
+ }
+
+ /* Build the service 'password' */
+ pszPassword = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (wcslen(pService->lpServiceName) + 5) * sizeof(WCHAR));
+ if (pszPassword == NULL)
+ {
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ wcscpy(pszPassword, L"_SC_");
+ wcscat(pszPassword, pService->lpServiceName);
+
+ DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName, pszUserName, pszPassword);
+
+ /* Service logon */
+ if (!LogonUserW(pszUserName,
+ pszDomainName,
+ pszPassword,
+ LOGON32_LOGON_SERVICE,
+ LOGON32_PROVIDER_DEFAULT,
+ &pImage->hToken))
+ {
+ dwError = GetLastError();
+ DPRINT1("LogonUserW() failed (Error %lu)\n", dwError);
+ goto done;
+ }
+
+ // FIXME: Call LoadUserProfileW to be able to initialize a per-user
+ // environment block, with user-specific environment variables as
+ // %USERNAME%, %USERPROFILE%, and %ALLUSERSPROFILE% correctly initialized!!
+
+ /* Load the user profile, so that the per-user environment variables can be initialized */
+ ZeroMemory(&ProfileInfo, sizeof(ProfileInfo));
+ ProfileInfo.dwSize = sizeof(ProfileInfo);
+ ProfileInfo.dwFlags = PI_NOUI;
+ ProfileInfo.lpUserName = pszUserName;
+ // ProfileInfo.lpProfilePath = NULL;
+ // ProfileInfo.lpDefaultPath = NULL;
+ // ProfileInfo.lpServerName = NULL;
+ // ProfileInfo.lpPolicyPath = NULL;
+ // ProfileInfo.hProfile = NULL;
+
+ if (!LoadUserProfileW(pImage->hToken, &ProfileInfo))
+ {
+ dwError = GetLastError();
+ DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError);
+ goto done;
+ }
+
+ pImage->hProfile = ProfileInfo.hProfile;
+
+done:
+ if (pszPassword != NULL)
+ HeapFree(GetProcessHeap(), 0, pszPassword);
+
+ if (ptr != NULL)
+ *ptr = L'\\';
+
+ return dwError;
+#endif
+}
+
+
static DWORD
ScmCreateOrReferenceServiceImage(PSERVICE pService)
{
- RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ RTL_QUERY_REGISTRY_TABLE QueryTable[3];
UNICODE_STRING ImagePath;
+ UNICODE_STRING ObjectName;
PSERVICE_IMAGE pServiceImage = NULL;
NTSTATUS Status;
DWORD dwError = ERROR_SUCCESS;
+ DWORD dwRecordSize;
+ LPWSTR pString;
DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService);
RtlInitUnicodeString(&ImagePath, NULL);
+ RtlInitUnicodeString(&ObjectName, NULL);
/* Get service data */
RtlZeroMemory(&QueryTable,
QueryTable[0].Name = L"ImagePath";
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
QueryTable[0].EntryContext = &ImagePath;
+ QueryTable[1].Name = L"ObjectName";
+ QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ QueryTable[1].EntryContext = &ObjectName;
Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
pService->lpServiceName,
}
DPRINT("ImagePath: '%wZ'\n", &ImagePath);
+ DPRINT("ObjectName: '%wZ'\n", &ObjectName);
pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer);
if (pServiceImage == NULL)
{
+ dwRecordSize = sizeof(SERVICE_IMAGE) +
+ ImagePath.Length + sizeof(WCHAR) +
+ ((ObjectName.Length != 0) ? (ObjectName.Length + sizeof(WCHAR)) : 0);
+
/* Create a new service image */
pServiceImage = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
- FIELD_OFFSET(SERVICE_IMAGE, szImagePath[ImagePath.Length / sizeof(WCHAR) + 1]));
+ dwRecordSize);
if (pServiceImage == NULL)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
pServiceImage->dwImageRunCount = 1;
pServiceImage->hControlPipe = INVALID_HANDLE_VALUE;
+ pServiceImage->hProcess = INVALID_HANDLE_VALUE;
+
+ pString = (PWSTR)((INT_PTR)pServiceImage + sizeof(SERVICE_IMAGE));
/* Set the image path */
- wcscpy(pServiceImage->szImagePath,
+ pServiceImage->pszImagePath = pString;
+ wcscpy(pServiceImage->pszImagePath,
ImagePath.Buffer);
- RtlFreeUnicodeString(&ImagePath);
+ /* Set the account name */
+ if (ObjectName.Length > 0)
+ {
+ pString = pString + wcslen(pString) + 1;
+
+ pServiceImage->pszAccountName = pString;
+ wcscpy(pServiceImage->pszAccountName,
+ ObjectName.Buffer);
+ }
+
+ /* Service logon */
+ dwError = ScmLogonService(pService, pServiceImage);
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError);
+
+ /* Release the service image */
+ HeapFree(GetProcessHeap(), 0, pServiceImage);
+
+ goto done;
+ }
/* Create the control pipe */
dwError = ScmCreateNewControlPipe(pServiceImage);
if (dwError != ERROR_SUCCESS)
{
+ DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError);
+
+ /* Unload the user profile */
+ if (pServiceImage->hProfile != NULL)
+ UnloadUserProfile(pServiceImage->hToken, pServiceImage->hProfile);
+
+ /* Close the logon token */
+ if (pServiceImage->hToken != NULL)
+ CloseHandle(pServiceImage->hToken);
+
+ /* Release the service image */
HeapFree(GetProcessHeap(), 0, pServiceImage);
+
goto done;
}
}
else
{
+// if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
+
+ /* Fail if services in an image use different accounts */
+ if (!ScmIsSameServiceAccount(pServiceImage->pszAccountName, ObjectName.Buffer))
+ {
+ dwError = ERROR_DIFFERENT_SERVICE_ACCOUNT;
+ goto done;
+ }
+
/* Increment the run counter */
pServiceImage->dwImageRunCount++;
}
+ DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage->pszImagePath);
+ DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage->pszAccountName);
DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount);
/* Link the service image to the service */
pService->lpImage = pServiceImage;
-done:;
+done:
+ RtlFreeUnicodeString(&ObjectName);
RtlFreeUnicodeString(&ImagePath);
DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError);
/* Remove the service image from the list */
RemoveEntryList(&pServiceImage->ImageListEntry);
+ /* Close the process handle */
+ if (pServiceImage->hProcess != INVALID_HANDLE_VALUE)
+ CloseHandle(pServiceImage->hProcess);
+
/* Close the control pipe */
if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE)
CloseHandle(pServiceImage->hControlPipe);
+ /* Unload the user profile */
+ if (pServiceImage->hProfile != NULL)
+ UnloadUserProfile(pServiceImage->hToken, pServiceImage->hProfile);
+
+ /* Close the logon token */
+ if (pServiceImage->hToken != NULL)
+ CloseHandle(pServiceImage->hToken);
+
/* Release the service image */
HeapFree(GetProcessHeap(), 0, pServiceImage);
}
ScmDereferenceServiceImage(lpService->lpImage);
/* Decrement the group reference counter */
- if (lpService->lpGroup)
- lpService->lpGroup->dwRefCount--;
-
- /* FIXME: SecurityDescriptor */
+ ScmSetServiceGroup(lpService, NULL);
+ /* Release the SecurityDescriptor */
+ if (lpService->pSecurityDescriptor != NULL)
+ HeapFree(GetProcessHeap(), 0, lpService->pSecurityDescriptor);
/* Remove the Service from the List */
RemoveEntryList(&lpService->ServiceListEntry);
if (ScmIsDeleteFlagSet(hServiceKey))
lpService->bDeleted = TRUE;
-done:;
+ if (lpService->Status.dwServiceType & SERVICE_WIN32)
+ {
+ dwError = ScmReadSecurityDescriptor(hServiceKey,
+ &lpService->pSecurityDescriptor);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ /* Assing the default security descriptor if the security descriptor cannot be read */
+ if (lpService->pSecurityDescriptor == NULL)
+ {
+ DPRINT("No security descriptor found! Assign default security descriptor!\n");
+ dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ dwError = ScmWriteSecurityDescriptor(hServiceKey,
+ lpService->pSecurityDescriptor);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+ }
+ }
+
+done:
if (lpGroup != NULL)
HeapFree(GetProcessHeap(), 0, lpGroup);
if (lpService != NULL)
{
- if (lpService->lpImage != NULL)
- ScmDereferenceServiceImage(lpService->lpImage);
+ ASSERT(lpService->lpImage == NULL);
}
return dwError;
}
-DWORD
-ScmDeleteRegKey(HKEY hKey, LPCWSTR lpszSubKey)
-{
- DWORD dwRet, dwMaxSubkeyLen = 0, dwSize;
- WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
- HKEY hSubKey = 0;
-
- dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
- if (!dwRet)
- {
- /* Find the maximum subkey length so that we can allocate a buffer */
- dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
- &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
- if (!dwRet)
- {
- dwMaxSubkeyLen++;
- if (dwMaxSubkeyLen > sizeof(szNameBuf) / sizeof(WCHAR))
- {
- /* Name too big: alloc a buffer for it */
- lpszName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwMaxSubkeyLen * sizeof(WCHAR));
- }
-
- if (!lpszName)
- dwRet = ERROR_NOT_ENOUGH_MEMORY;
- else
- {
- while (dwRet == ERROR_SUCCESS)
- {
- dwSize = dwMaxSubkeyLen;
- dwRet = RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL);
- if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA)
- dwRet = ScmDeleteRegKey(hSubKey, lpszName);
- }
- if (dwRet == ERROR_NO_MORE_ITEMS)
- dwRet = ERROR_SUCCESS;
-
- if (lpszName != szNameBuf)
- HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
- }
- }
-
- RegCloseKey(hSubKey);
- if (!dwRet)
- dwRet = RegDeleteKeyW(hKey, lpszSubKey);
- }
- return dwRet;
-}
-
-
VOID
ScmDeleteMarkedServices(VOID)
{
ServiceEntry = ServiceEntry->Flink;
- if (CurrentService->bDeleted == TRUE)
+ if (CurrentService->bDeleted != FALSE)
{
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Services",
}
+static
+VOID
+ScmGetNoInteractiveServicesValue(VOID)
+{
+ HKEY hKey;
+ DWORD dwKeySize;
+ LONG lError;
+
+ lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\Windows",
+ 0,
+ KEY_READ,
+ &hKey);
+ if (lError == ERROR_SUCCESS)
+ {
+ dwKeySize = sizeof(NoInteractiveServices);
+ lError = RegQueryValueExW(hKey,
+ L"NoInteractiveServices",
+ 0,
+ NULL,
+ (LPBYTE)&NoInteractiveServices,
+ &dwKeySize);
+ RegCloseKey(hKey);
+ }
+}
+
+
DWORD
ScmCreateServiceDatabase(VOID)
{
DPRINT("ScmCreateServiceDatabase() called\n");
+ /* Retrieve the NoInteractiveServies value */
+ ScmGetNoInteractiveServicesValue();
+
+ /* Create the service group list */
dwError = ScmCreateGroupList();
if (dwError != ERROR_SUCCESS)
return dwError;
- /* Initialize basic variables */
+ /* Initialize image and service lists */
InitializeListHead(&ImageListHead);
InitializeListHead(&ServiceListHead);
PWSTR Ptr;
DWORD dwError = ERROR_SUCCESS;
BOOL bResult;
-#ifdef USE_ASYNCHRONOUS_IO
OVERLAPPED Overlapped = {0};
-#endif
DPRINT("ScmControlService() called\n");
ControlPacket->dwArgumentsCount = 0;
ControlPacket->dwArgumentsOffset = 0;
-#ifdef USE_ASYNCHRONOUS_IO
bResult = WriteFile(Service->lpImage->hControlPipe,
ControlPacket,
PacketSize,
&Overlapped);
if (bResult == FALSE)
{
- DPRINT1("WriteFile() returned FALSE\n");
+ DPRINT("WriteFile() returned FALSE\n");
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
- DPRINT1("dwError: ERROR_IO_PENDING\n");
+ DPRINT("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
PipeTimeout);
- DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+ DPRINT("WaitForSingleObject() returned %lu\n", dwError);
if (dwError == WAIT_TIMEOUT)
{
&Overlapped);
if (bResult == FALSE)
{
- DPRINT1("ReadFile() returned FALSE\n");
+ DPRINT("ReadFile() returned FALSE\n");
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
- DPRINT1("dwError: ERROR_IO_PENDING\n");
+ DPRINT("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
PipeTimeout);
- DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+ DPRINT("WaitForSingleObject() returned %lu\n", dwError);
if (dwError == WAIT_TIMEOUT)
{
}
}
-#else
- /* Send the control packet */
- bResult = WriteFile(Service->lpImage->hControlPipe,
- ControlPacket,
- PacketSize,
- &dwWriteCount,
- NULL);
- if (bResult == FALSE)
- {
- dwError = GetLastError();
- DPRINT("WriteFile() failed (Error %lu)\n", dwError);
-
- if ((dwError == ERROR_GEN_FAILURE) &&
- (dwControl == SERVICE_CONTROL_STOP))
- {
- /* Service is already terminated */
- Service->Status.dwCurrentState = SERVICE_STOPPED;
- Service->Status.dwControlsAccepted = 0;
- Service->Status.dwWin32ExitCode = ERROR_SERVICE_NOT_ACTIVE;
- dwError = ERROR_SUCCESS;
- }
- goto Done;
- }
-
- /* Read the reply */
- bResult = ReadFile(Service->lpImage->hControlPipe,
- &ReplyPacket,
- sizeof(SCM_REPLY_PACKET),
- &dwReadCount,
- NULL);
- if (bResult == FALSE)
- {
- dwError = GetLastError();
- DPRINT("ReadFile() failed (Error %lu)\n", dwError);
- }
-#endif
-
Done:
- /* Release the contol packet */
+ /* Release the control packet */
HeapFree(GetProcessHeap(),
0,
ControlPacket);
dwControl == SERVICE_CONTROL_STOP)
{
ScmDereferenceServiceImage(Service->lpImage);
+ Service->lpImage = NULL;
}
LeaveCriticalSection(&ControlServiceCriticalSection);
DWORD argc,
LPWSTR* argv)
{
+ DWORD dwError = ERROR_SUCCESS;
PSCM_CONTROL_PACKET ControlPacket;
SCM_REPLY_PACKET ReplyPacket;
DWORD PacketSize;
- PWSTR Ptr;
- DWORD dwWriteCount = 0;
- DWORD dwReadCount = 0;
- DWORD dwError = ERROR_SUCCESS;
DWORD i;
+ PWSTR Ptr;
PWSTR *pOffPtr;
PWSTR pArgPtr;
BOOL bResult;
-#ifdef USE_ASYNCHRONOUS_IO
+ DWORD dwWriteCount = 0;
+ DWORD dwReadCount = 0;
OVERLAPPED Overlapped = {0};
-#endif
DPRINT("ScmSendStartCommand() called\n");
/* Calculate the total length of the start command line */
- PacketSize = sizeof(SCM_CONTROL_PACKET) +
- (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
+ PacketSize = sizeof(SCM_CONTROL_PACKET);
+ PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
- /* Calculate the required packet size for the start arguments */
+ /*
+ * Calculate the required packet size for the start argument vector 'argv',
+ * composed of the list of pointer offsets, followed by UNICODE strings.
+ * The strings are stored continuously after the vector of offsets, with
+ * the offsets being relative to the beginning of the vector, as in the
+ * following layout (with N == argc):
+ * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
+ */
if (argc > 0 && argv != NULL)
{
- PacketSize = ALIGN_UP(PacketSize, LPWSTR);
+ PacketSize = ALIGN_UP(PacketSize, PWSTR);
+ PacketSize += (argc * sizeof(PWSTR));
DPRINT("Argc: %lu\n", argc);
for (i = 0; i < argc; i++)
{
DPRINT("Argv[%lu]: %S\n", i, argv[i]);
- PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR));
+ PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR));
}
}
/* Allocate a control packet */
- ControlPacket = HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- PacketSize);
+ ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PacketSize);
if (ControlPacket == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
? SERVICE_CONTROL_START_OWN
: SERVICE_CONTROL_START_SHARE;
ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
- ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
- Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
+ /* Copy the start command line */
+ ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
+ Ptr = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset);
wcscpy(Ptr, Service->lpServiceName);
- ControlPacket->dwArgumentsCount = 0;
+ ControlPacket->dwArgumentsCount = 0;
ControlPacket->dwArgumentsOffset = 0;
- /* Copy argument list */
+ /* Copy the argument vector */
if (argc > 0 && argv != NULL)
{
Ptr += wcslen(Service->lpServiceName) + 1;
pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR);
pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
- ControlPacket->dwArgumentsCount = argc;
+ ControlPacket->dwArgumentsCount = argc;
ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount);
for (i = 0; i < argc; i++)
{
- wcscpy(pArgPtr, argv[i]);
- *pOffPtr = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
- DPRINT("offset: %p\n", *pOffPtr);
-
- pArgPtr += wcslen(argv[i]) + 1;
- pOffPtr++;
+ wcscpy(pArgPtr, argv[i]);
+ pOffPtr[i] = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
+ DPRINT("offset[%lu]: %p\n", i, pOffPtr[i]);
+ pArgPtr += wcslen(argv[i]) + 1;
}
}
-#ifdef USE_ASYNCHRONOUS_IO
bResult = WriteFile(Service->lpImage->hControlPipe,
ControlPacket,
PacketSize,
&Overlapped);
if (bResult == FALSE)
{
- DPRINT1("WriteFile() returned FALSE\n");
+ DPRINT("WriteFile() returned FALSE\n");
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
- DPRINT1("dwError: ERROR_IO_PENDING\n");
+ DPRINT("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
PipeTimeout);
- DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+ DPRINT("WaitForSingleObject() returned %lu\n", dwError);
if (dwError == WAIT_TIMEOUT)
{
&Overlapped);
if (bResult == FALSE)
{
- DPRINT1("ReadFile() returned FALSE\n");
+ DPRINT("ReadFile() returned FALSE\n");
dwError = GetLastError();
if (dwError == ERROR_IO_PENDING)
{
- DPRINT1("dwError: ERROR_IO_PENDING\n");
+ DPRINT("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
PipeTimeout);
- DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+ DPRINT("WaitForSingleObject() returned %lu\n", dwError);
if (dwError == WAIT_TIMEOUT)
{
}
}
-#else
- /* Send the start command */
- bResult = WriteFile(Service->lpImage->hControlPipe,
- ControlPacket,
- PacketSize,
- &dwWriteCount,
- NULL);
- if (bResult == FALSE)
- {
- dwError = GetLastError();
- DPRINT("WriteFile() failed (Error %lu)\n", dwError);
- goto Done;
- }
-
- /* Read the reply */
- bResult = ReadFile(Service->lpImage->hControlPipe,
- &ReplyPacket,
- sizeof(SCM_REPLY_PACKET),
- &dwReadCount,
- NULL);
- if (bResult == FALSE)
- {
- dwError = GetLastError();
- DPRINT("ReadFile() failed (Error %lu)\n", dwError);
- }
-#endif
-
Done:
- /* Release the contol packet */
+ /* Release the control packet */
HeapFree(GetProcessHeap(),
0,
ControlPacket);
DWORD dwProcessId = 0;
DWORD dwError = ERROR_SUCCESS;
BOOL bResult;
-#ifdef USE_ASYNCHRONOUS_IO
OVERLAPPED Overlapped = {0};
+#if 0
+ LPCWSTR lpLogStrings[3];
+ WCHAR szBuffer1[20];
+ WCHAR szBuffer2[20];
#endif
DPRINT("ScmWaitForServiceConnect()\n");
-#ifdef USE_ASYNCHRONOUS_IO
Overlapped.hEvent = (HANDLE)NULL;
bResult = ConnectNamedPipe(Service->lpImage->hControlPipe,
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
}
+#if 0
+ _ultow(PipeTimeout, szBuffer1, 10);
+ lpLogStrings[0] = Service->lpDisplayName;
+ lpLogStrings[1] = szBuffer1;
+
+ ScmLogEvent(EVENT_CONNECTION_TIMEOUT,
+ EVENTLOG_ERROR_TYPE,
+ 2,
+ lpLogStrings);
+#endif
+ DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service->lpDisplayName);
+
return ERROR_SERVICE_REQUEST_TIMEOUT;
}
else if (dwError == WAIT_OBJECT_0)
DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
}
+#if 0
+ _ultow(PipeTimeout, szBuffer1, 10);
+ lpLogStrings[0] = szBuffer1;
+
+ ScmLogEvent(EVENT_READFILE_TIMEOUT,
+ EVENTLOG_ERROR_TYPE,
+ 1,
+ lpLogStrings);
+#endif
+ DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service->lpDisplayName);
+
return ERROR_SERVICE_REQUEST_TIMEOUT;
}
else if (dwError == WAIT_OBJECT_0)
}
}
- DPRINT1("ScmWaitForServiceConnect() done\n");
+ if (dwProcessId != Service->lpImage->dwProcessId)
+ {
+#if 0
+ _ultow(Service->lpImage->dwProcessId, szBuffer1, 10);
+ _ultow(dwProcessId, szBuffer2, 10);
- return ERROR_SUCCESS;
-#else
+ lpLogStrings[0] = Service->lpDisplayName;
+ lpLogStrings[1] = szBuffer1;
+ lpLogStrings[2] = szBuffer2;
- /* Connect control pipe */
- if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ?
- TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
- {
- DPRINT("Control pipe connected!\n");
-
- /* Read SERVICE_STATUS_HANDLE from pipe */
- bResult = ReadFile(Service->lpImage->hControlPipe,
- (LPVOID)&dwProcessId,
- sizeof(DWORD),
- &dwRead,
- NULL);
- if (bResult == FALSE)
- {
- dwError = GetLastError();
- DPRINT1("Reading the service control pipe failed (Error %lu)\n",
- dwError);
- }
- else
- {
- dwError = ERROR_SUCCESS;
- DPRINT("Read control pipe successfully\n");
- }
- }
- else
- {
- DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
+ ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED,
+ EVENTLOG_WARNING_TYPE,
+ 3,
+ lpLogStrings);
+#endif
+
+ DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service->lpDisplayName);
}
- return dwError;
-#endif
+ DPRINT("ScmWaitForServiceConnect() done\n");
+
+ return ERROR_SUCCESS;
}
{
PROCESS_INFORMATION ProcessInformation;
STARTUPINFOW StartupInfo;
+ LPVOID lpEnvironment;
BOOL Result;
DWORD dwError = ERROR_SUCCESS;
StartupInfo.cb = sizeof(StartupInfo);
ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
- Result = CreateProcessW(NULL,
- Service->lpImage->szImagePath,
- NULL,
- NULL,
- FALSE,
- DETACHED_PROCESS | CREATE_SUSPENDED,
- NULL,
- NULL,
- &StartupInfo,
- &ProcessInformation);
+ /* Use the interactive desktop if the service is interactive */
+ if ((NoInteractiveServices == 0) &&
+ (Service->Status.dwServiceType & SERVICE_INTERACTIVE_PROCESS))
+ StartupInfo.lpDesktop = L"WinSta0\\Default";
+
+ if (Service->lpImage->hToken)
+ {
+ /* User token: Run the service under the user account */
+
+ if (!CreateEnvironmentBlock(&lpEnvironment, Service->lpImage->hToken, FALSE))
+ {
+ /* We failed, run the service with the current environment */
+ DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
+ GetLastError(), Service->lpServiceName);
+ lpEnvironment = NULL;
+ }
+
+ /* Impersonate the new user */
+ Result = ImpersonateLoggedOnUser(Service->lpImage->hToken);
+ if (Result)
+ {
+ /* Launch the process in the user's logon session */
+ Result = CreateProcessAsUserW(Service->lpImage->hToken,
+ NULL,
+ Service->lpImage->pszImagePath,
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED,
+ lpEnvironment,
+ NULL,
+ &StartupInfo,
+ &ProcessInformation);
+ if (!Result)
+ dwError = GetLastError();
+
+ /* Revert the impersonation */
+ RevertToSelf();
+ }
+ else
+ {
+ dwError = GetLastError();
+ DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError);
+ }
+ }
+ else
+ {
+ /* No user token: Run the service under the LocalSystem account */
+
+ if (!CreateEnvironmentBlock(&lpEnvironment, NULL, TRUE))
+ {
+ /* We failed, run the service with the current environment */
+ DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
+ GetLastError(), Service->lpServiceName);
+ lpEnvironment = NULL;
+ }
+
+ Result = CreateProcessW(NULL,
+ Service->lpImage->pszImagePath,
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED,
+ lpEnvironment,
+ NULL,
+ &StartupInfo,
+ &ProcessInformation);
+ if (!Result)
+ dwError = GetLastError();
+ }
+
+ if (lpEnvironment)
+ DestroyEnvironmentBlock(lpEnvironment);
+
if (!Result)
{
- dwError = GetLastError();
- DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
+ DPRINT1("Starting '%S' failed with error %d\n",
+ Service->lpServiceName, dwError);
return dwError;
}
ProcessInformation.dwThreadId,
ProcessInformation.hThread);
- /* Get process handle and id */
+ /* Get the process handle and ID */
+ Service->lpImage->hProcess = ProcessInformation.hProcess;
Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
- /* Resume Thread */
+ /* Resume the main thread and close its handle */
ResumeThread(ProcessInformation.hThread);
+ CloseHandle(ProcessInformation.hThread);
/* Connect control pipe */
dwError = ScmWaitForServiceConnect(Service);
- if (dwError == ERROR_SUCCESS)
- {
- /* Send start command */
- dwError = ScmSendStartCommand(Service, argc, argv);
- }
- else
+ if (dwError != ERROR_SUCCESS)
{
DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
Service->lpImage->dwProcessId = 0;
+ return dwError;
}
- /* Close thread and process handle */
- CloseHandle(ProcessInformation.hThread);
- CloseHandle(ProcessInformation.hProcess);
-
- return dwError;
+ /* Send the start command */
+ return ScmSendStartCommand(Service, argc, argv);
}
{
PSERVICE_GROUP Group = Service->lpGroup;
DWORD dwError = ERROR_SUCCESS;
- LPCWSTR ErrorLogStrings[2];
- WCHAR szErrorBuffer[32];
+ LPCWSTR lpLogStrings[2];
+ WCHAR szLogBuffer[80];
DPRINT("ScmLoadService() called\n");
DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
dwError = ScmLoadDriver(Service);
if (dwError == ERROR_SUCCESS)
{
- Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
Service->Status.dwCurrentState = SERVICE_RUNNING;
+ Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
}
}
else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
dwError = ScmStartUserModeService(Service, argc, argv);
if (dwError == ERROR_SUCCESS)
{
-#ifdef USE_SERVICE_START_PENDING
Service->Status.dwCurrentState = SERVICE_START_PENDING;
-#else
- Service->Status.dwCurrentState = SERVICE_RUNNING;
-#endif
+ Service->Status.dwControlsAccepted = 0;
}
else
{
{
Group->ServicesRunning = TRUE;
}
+
+ /* Log a successful service start */
+ LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_START, szLogBuffer, 80);
+ lpLogStrings[0] = Service->lpDisplayName;
+ lpLogStrings[1] = szLogBuffer;
+
+ ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
+ EVENTLOG_INFORMATION_TYPE,
+ 2,
+ lpLogStrings);
}
else
{
if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
{
/* Log a failed service start */
- swprintf(szErrorBuffer, L"%lu", dwError);
- ErrorLogStrings[0] = Service->lpServiceName;
- ErrorLogStrings[1] = szErrorBuffer;
- ScmLogError(EVENT_SERVICE_START_FAILED,
+ swprintf(szLogBuffer, L"%lu", dwError);
+ lpLogStrings[0] = Service->lpServiceName;
+ lpLogStrings[1] = szLogBuffer;
+ ScmLogEvent(EVENT_SERVICE_START_FAILED,
+ EVENTLOG_ERROR_TYPE,
2,
- ErrorLogStrings);
+ lpLogStrings);
}
#if 0
VOID
ScmAutoStartServices(VOID)
{
- DWORD dwError = ERROR_SUCCESS;
+ DWORD dwError;
PLIST_ENTRY GroupEntry;
PLIST_ENTRY ServiceEntry;
PSERVICE_GROUP CurrentGroup;
PSERVICE CurrentService;
WCHAR szSafeBootServicePath[MAX_PATH];
+ DWORD SafeBootEnabled;
HKEY hKey;
+ DWORD dwKeySize;
ULONG i;
/*
*/
ASSERT(ScmInitialize);
+ /* Retrieve the SafeBoot parameter */
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
+ 0,
+ KEY_READ,
+ &hKey);
+ if (dwError == ERROR_SUCCESS)
+ {
+ dwKeySize = sizeof(SafeBootEnabled);
+ dwError = RegQueryValueExW(hKey,
+ L"OptionValue",
+ 0,
+ NULL,
+ (LPBYTE)&SafeBootEnabled,
+ &dwKeySize);
+ RegCloseKey(hKey);
+ }
+
+ /* Default to Normal boot if the value doesn't exist */
+ if (dwError != ERROR_SUCCESS)
+ SafeBootEnabled = 0;
+
/* Acquire the service control critical section, to synchronize starts */
EnterCriticalSection(&ControlServiceCriticalSection);
wcscpy(szSafeBootServicePath,
L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
- switch (GetSystemMetrics(SM_CLEANBOOT))
+ switch (SafeBootEnabled)
{
/* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
case 1:
break;
}
- if (GetSystemMetrics(SM_CLEANBOOT))
+ if (SafeBootEnabled != 0)
{
/* If key does not exist then do not assume safe mode */
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
&hKey);
if (dwError == ERROR_SUCCESS)
{
- dwKeySize = sizeof(DWORD);
+ dwKeySize = sizeof(PipeTimeout);
RegQueryValueExW(hKey,
L"ServicesPipeTimeout",
0,
NULL,
(LPBYTE)&PipeTimeout,
&dwKeySize);
-
RegCloseKey(hKey);
}
}