2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/database.c
5 * PURPOSE: Database control interface
6 * COPYRIGHT: Copyright 2002-2006 Eric Kohl
7 * Copyright 2006 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
9 * Gregor Brunmar <gregor.brunmar@home.se>
13 /* INCLUDES *****************************************************************/
20 #include <reactos/undocuser.h>
26 /* GLOBALS *******************************************************************/
28 LIST_ENTRY ImageListHead
;
29 LIST_ENTRY ServiceListHead
;
31 static RTL_RESOURCE DatabaseLock
;
32 static DWORD ResumeCount
= 1;
33 static DWORD NoInteractiveServices
= 0;
34 static DWORD ServiceTag
= 0;
36 /* The critical section synchronizes service control requests */
37 static CRITICAL_SECTION ControlServiceCriticalSection
;
38 static DWORD PipeTimeout
= 30000; /* 30 Seconds */
41 /* FUNCTIONS *****************************************************************/
44 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
46 WCHAR szControlPipeName
[MAX_PATH
+ 1];
47 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
48 DWORD ServiceCurrent
= 0;
53 /* Get the service number */
54 /* TODO: Create registry entry with correct write access */
55 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
56 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
62 if (dwError
!= ERROR_SUCCESS
)
64 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
68 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
70 dwKeySize
= sizeof(DWORD
);
71 dwError
= RegQueryValueExW(hServiceCurrentKey
,
72 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
74 if (dwError
!= ERROR_SUCCESS
)
76 RegCloseKey(hServiceCurrentKey
);
77 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
84 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
86 RegCloseKey(hServiceCurrentKey
);
88 if (dwError
!= ERROR_SUCCESS
)
90 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
94 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
95 StringCchPrintfW(szControlPipeName
, ARRAYSIZE(szControlPipeName
),
96 L
"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent
);
98 DPRINT("PipeName: %S\n", szControlPipeName
);
100 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
101 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
102 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
108 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
109 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
111 DPRINT1("Failed to create control pipe!\n");
112 return GetLastError();
115 return ERROR_SUCCESS
;
119 static PSERVICE_IMAGE
120 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
122 PLIST_ENTRY ImageEntry
;
123 PSERVICE_IMAGE CurrentImage
;
125 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
127 ImageEntry
= ImageListHead
.Flink
;
128 while (ImageEntry
!= &ImageListHead
)
130 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
133 if (_wcsicmp(CurrentImage
->pszImagePath
, lpImagePath
) == 0)
135 DPRINT("Found image: '%S'\n", CurrentImage
->pszImagePath
);
139 ImageEntry
= ImageEntry
->Flink
;
142 DPRINT("Couldn't find a matching image\n");
150 ScmGetServiceNameFromTag(IN PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams
,
151 OUT PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS
*OutParams
)
153 PLIST_ENTRY ServiceEntry
;
154 PSERVICE CurrentService
;
155 PSERVICE_IMAGE CurrentImage
;
156 PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutBuffer
= NULL
;
159 /* Lock the database */
160 ScmLockDatabaseExclusive();
162 /* Find the matching service */
163 ServiceEntry
= ServiceListHead
.Flink
;
164 while (ServiceEntry
!= &ServiceListHead
)
166 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
170 /* We must match the tag */
171 if (CurrentService
->dwTag
== InParams
->dwTag
&&
172 CurrentService
->lpImage
!= NULL
)
174 CurrentImage
= CurrentService
->lpImage
;
175 /* And matching the PID */
176 if (CurrentImage
->dwProcessId
== InParams
->dwPid
)
182 ServiceEntry
= ServiceEntry
->Flink
;
186 if (ServiceEntry
== &ServiceListHead
)
188 dwError
= ERROR_RETRY
;
192 /* Allocate the output buffer */
193 OutBuffer
= MIDL_user_allocate(sizeof(TAG_INFO_NAME_FROM_TAG_OUT_PARAMS
));
194 if (OutBuffer
== NULL
)
196 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
200 /* And the buffer for the name */
201 OutBuffer
->pszName
= MIDL_user_allocate(wcslen(CurrentService
->lpServiceName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
202 if (OutBuffer
->pszName
== NULL
)
204 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
208 /* Fill in output data */
209 wcscpy(OutBuffer
->pszName
, CurrentService
->lpServiceName
);
210 OutBuffer
->TagType
= TagTypeService
;
213 *OutParams
= OutBuffer
;
214 dwError
= ERROR_SUCCESS
;
218 /* Unlock database */
221 /* If failure, free allocated memory */
222 if (dwError
!= ERROR_SUCCESS
)
224 if (OutBuffer
!= NULL
)
226 MIDL_user_free(OutBuffer
);
230 /* Return error/success */
237 ScmIsSameServiceAccount(
238 _In_ PCWSTR pszAccountName1
,
239 _In_ PCWSTR pszAccountName2
)
241 if (pszAccountName1
== NULL
&&
242 pszAccountName2
== NULL
)
245 if (pszAccountName1
== NULL
&&
246 pszAccountName2
!= NULL
&&
247 _wcsicmp(pszAccountName2
, L
"LocalSystem") == 0)
250 if (pszAccountName1
!= NULL
&&
251 pszAccountName2
== NULL
&&
252 _wcsicmp(pszAccountName1
, L
"LocalSystem") == 0)
255 if (pszAccountName1
!= NULL
&&
256 pszAccountName2
!= NULL
&&
257 _wcsicmp(pszAccountName1
, pszAccountName2
) == 0)
266 ScmIsLocalSystemAccount(
267 _In_ PCWSTR pszAccountName
)
269 if (pszAccountName
== NULL
||
270 _wcsicmp(pszAccountName
, L
"LocalSystem") == 0)
280 IN PSERVICE pService
,
281 IN PSERVICE_IMAGE pImage
)
283 DWORD dwError
= ERROR_SUCCESS
;
284 PROFILEINFOW ProfileInfo
;
285 PWSTR pszUserName
= NULL
;
286 PWSTR pszDomainName
= NULL
;
287 PWSTR pszPassword
= NULL
;
290 DPRINT("ScmLogonService(%p %p)\n", pService
, pImage
);
291 DPRINT("Service %S\n", pService
->lpServiceName
);
293 if (ScmIsLocalSystemAccount(pImage
->pszAccountName
))
294 return ERROR_SUCCESS
;
296 /* Get the user and domain names */
297 ptr
= wcschr(pImage
->pszAccountName
, L
'\\');
301 pszUserName
= ptr
+ 1;
302 pszDomainName
= pImage
->pszAccountName
;
306 // ERROR_INVALID_SERVICE_ACCOUNT
307 pszUserName
= pImage
->pszAccountName
;
308 pszDomainName
= NULL
;
311 /* Build the service 'password' */
312 pszPassword
= HeapAlloc(GetProcessHeap(),
314 (wcslen(pService
->lpServiceName
) + 5) * sizeof(WCHAR
));
315 if (pszPassword
== NULL
)
317 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
321 wcscpy(pszPassword
, L
"_SC_");
322 wcscat(pszPassword
, pService
->lpServiceName
);
324 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName
, pszUserName
, pszPassword
);
326 /* Do the service logon */
327 if (!LogonUserW(pszUserName
,
330 LOGON32_LOGON_SERVICE
,
331 LOGON32_PROVIDER_DEFAULT
,
334 dwError
= GetLastError();
335 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError
);
337 /* Normalize the returned error */
338 dwError
= ERROR_SERVICE_LOGON_FAILED
;
342 /* Load the user profile; the per-user environment variables are thus correctly initialized */
343 ZeroMemory(&ProfileInfo
, sizeof(ProfileInfo
));
344 ProfileInfo
.dwSize
= sizeof(ProfileInfo
);
345 ProfileInfo
.dwFlags
= PI_NOUI
;
346 ProfileInfo
.lpUserName
= pszUserName
;
347 // ProfileInfo.lpProfilePath = NULL;
348 // ProfileInfo.lpDefaultPath = NULL;
349 // ProfileInfo.lpServerName = NULL;
350 // ProfileInfo.lpPolicyPath = NULL;
351 // ProfileInfo.hProfile = NULL;
353 if (!LoadUserProfileW(pImage
->hToken
, &ProfileInfo
))
355 dwError
= GetLastError();
356 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError
);
360 pImage
->hProfile
= ProfileInfo
.hProfile
;
363 if (pszPassword
!= NULL
)
364 HeapFree(GetProcessHeap(), 0, pszPassword
);
374 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
376 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
377 UNICODE_STRING ImagePath
;
378 UNICODE_STRING ObjectName
;
379 PSERVICE_IMAGE pServiceImage
= NULL
;
381 DWORD dwError
= ERROR_SUCCESS
;
385 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
387 RtlInitUnicodeString(&ImagePath
, NULL
);
388 RtlInitUnicodeString(&ObjectName
, NULL
);
390 /* Get service data */
391 RtlZeroMemory(&QueryTable
,
394 QueryTable
[0].Name
= L
"ImagePath";
395 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
396 QueryTable
[0].EntryContext
= &ImagePath
;
397 QueryTable
[1].Name
= L
"ObjectName";
398 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
399 QueryTable
[1].EntryContext
= &ObjectName
;
401 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
402 pService
->lpServiceName
,
406 if (!NT_SUCCESS(Status
))
408 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
409 return RtlNtStatusToDosError(Status
);
412 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
413 DPRINT("ObjectName: '%wZ'\n", &ObjectName
);
415 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
416 if (pServiceImage
== NULL
)
418 dwRecordSize
= sizeof(SERVICE_IMAGE
) +
419 ImagePath
.Length
+ sizeof(WCHAR
) +
420 ((ObjectName
.Length
!= 0) ? (ObjectName
.Length
+ sizeof(WCHAR
)) : 0);
422 /* Create a new service image */
423 pServiceImage
= HeapAlloc(GetProcessHeap(),
426 if (pServiceImage
== NULL
)
428 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
432 pServiceImage
->dwImageRunCount
= 1;
433 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
434 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
436 pString
= (PWSTR
)((INT_PTR
)pServiceImage
+ sizeof(SERVICE_IMAGE
));
438 /* Set the image path */
439 pServiceImage
->pszImagePath
= pString
;
440 wcscpy(pServiceImage
->pszImagePath
,
443 /* Set the account name */
444 if (ObjectName
.Length
> 0)
446 pString
= pString
+ wcslen(pString
) + 1;
448 pServiceImage
->pszAccountName
= pString
;
449 wcscpy(pServiceImage
->pszAccountName
,
454 dwError
= ScmLogonService(pService
, pServiceImage
);
455 if (dwError
!= ERROR_SUCCESS
)
457 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError
);
459 /* Release the service image */
460 HeapFree(GetProcessHeap(), 0, pServiceImage
);
465 /* Create the control pipe */
466 dwError
= ScmCreateNewControlPipe(pServiceImage
);
467 if (dwError
!= ERROR_SUCCESS
)
469 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError
);
471 /* Unload the user profile */
472 if (pServiceImage
->hProfile
!= NULL
)
473 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
475 /* Close the logon token */
476 if (pServiceImage
->hToken
!= NULL
)
477 CloseHandle(pServiceImage
->hToken
);
479 /* Release the service image */
480 HeapFree(GetProcessHeap(), 0, pServiceImage
);
485 /* FIXME: Add more initialization code here */
488 /* Append service record */
489 InsertTailList(&ImageListHead
,
490 &pServiceImage
->ImageListEntry
);
494 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
496 /* Fail if services in an image use different accounts */
497 if (!ScmIsSameServiceAccount(pServiceImage
->pszAccountName
, ObjectName
.Buffer
))
499 dwError
= ERROR_DIFFERENT_SERVICE_ACCOUNT
;
503 /* Increment the run counter */
504 pServiceImage
->dwImageRunCount
++;
507 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage
->pszImagePath
);
508 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage
->pszAccountName
);
509 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
511 /* Link the service image to the service */
512 pService
->lpImage
= pServiceImage
;
515 RtlFreeUnicodeString(&ObjectName
);
516 RtlFreeUnicodeString(&ImagePath
);
518 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
525 ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage
)
527 DPRINT1("ScmRemoveServiceImage() called\n");
529 /* FIXME: Terminate the process */
531 /* Remove the service image from the list */
532 RemoveEntryList(&pServiceImage
->ImageListEntry
);
534 /* Close the process handle */
535 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
536 CloseHandle(pServiceImage
->hProcess
);
538 /* Close the control pipe */
539 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
540 CloseHandle(pServiceImage
->hControlPipe
);
542 /* Unload the user profile */
543 if (pServiceImage
->hProfile
!= NULL
)
544 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
546 /* Close the logon token */
547 if (pServiceImage
->hToken
!= NULL
)
548 CloseHandle(pServiceImage
->hToken
);
550 /* Release the service image */
551 HeapFree(GetProcessHeap(), 0, pServiceImage
);
556 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
558 PLIST_ENTRY ServiceEntry
;
559 PSERVICE CurrentService
;
561 DPRINT("ScmGetServiceEntryByName() called\n");
563 ServiceEntry
= ServiceListHead
.Flink
;
564 while (ServiceEntry
!= &ServiceListHead
)
566 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
569 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
571 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
572 return CurrentService
;
575 ServiceEntry
= ServiceEntry
->Flink
;
578 DPRINT("Couldn't find a matching service\n");
585 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
587 PLIST_ENTRY ServiceEntry
;
588 PSERVICE CurrentService
;
590 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
592 ServiceEntry
= ServiceListHead
.Flink
;
593 while (ServiceEntry
!= &ServiceListHead
)
595 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
598 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
600 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
601 return CurrentService
;
604 ServiceEntry
= ServiceEntry
->Flink
;
607 DPRINT("Couldn't find a matching service\n");
614 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
616 PLIST_ENTRY ServiceEntry
;
617 PSERVICE CurrentService
;
619 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
621 ServiceEntry
= ServiceListHead
.Flink
;
622 while (ServiceEntry
!= &ServiceListHead
)
624 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
627 if (CurrentService
->dwResumeCount
> dwResumeCount
)
629 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
630 return CurrentService
;
633 ServiceEntry
= ServiceEntry
->Flink
;
636 DPRINT("Couldn't find a matching service\n");
643 ScmGenerateServiceTag(PSERVICE lpServiceRecord
)
645 /* Check for an overflow */
646 if (ServiceTag
== -1)
648 return ERROR_INVALID_DATA
;
651 /* This is only valid for Win32 services */
652 if (!(lpServiceRecord
->Status
.dwServiceType
& SERVICE_WIN32
))
654 return ERROR_INVALID_PARAMETER
;
657 /* Increment the tag counter and set it */
658 ServiceTag
= ServiceTag
% 0xFFFFFFFF + 1;
659 lpServiceRecord
->dwTag
= ServiceTag
;
661 return ERROR_SUCCESS
;
666 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
667 PSERVICE
*lpServiceRecord
,
671 PSERVICE lpService
= NULL
;
673 DPRINT("Service: '%S'\n", lpServiceName
);
675 /* Allocate service entry */
676 lpService
= HeapAlloc(GetProcessHeap(),
678 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
679 if (lpService
== NULL
)
680 return ERROR_NOT_ENOUGH_MEMORY
;
682 *lpServiceRecord
= lpService
;
684 /* Copy service name */
685 wcscpy(lpService
->szServiceName
, lpServiceName
);
686 lpService
->lpServiceName
= lpService
->szServiceName
;
687 lpService
->lpDisplayName
= lpService
->lpServiceName
;
689 /* Set the start type */
690 lpService
->dwStartType
= dwStartType
;
692 /* Set the resume count */
693 lpService
->dwResumeCount
= ResumeCount
++;
695 /* Append service record */
696 InsertTailList(&ServiceListHead
,
697 &lpService
->ServiceListEntry
);
699 /* Initialize the service status */
700 lpService
->Status
.dwServiceType
= dwServiceType
;
701 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
702 lpService
->Status
.dwControlsAccepted
= 0;
703 lpService
->Status
.dwWin32ExitCode
=
704 (dwStartType
== SERVICE_DISABLED
) ? ERROR_SERVICE_DISABLED
: ERROR_SERVICE_NEVER_STARTED
;
705 lpService
->Status
.dwServiceSpecificExitCode
= 0;
706 lpService
->Status
.dwCheckPoint
= 0;
707 lpService
->Status
.dwWaitHint
=
708 (dwServiceType
& SERVICE_DRIVER
) ? 0 : 2000; /* 2 seconds */
710 return ERROR_SUCCESS
;
715 ScmDeleteServiceRecord(PSERVICE lpService
)
717 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
719 /* Delete the display name */
720 if (lpService
->lpDisplayName
!= NULL
&&
721 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
722 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
724 /* Dereference the service image */
725 if (lpService
->lpImage
)
727 lpService
->lpImage
->dwImageRunCount
--;
729 if (lpService
->lpImage
->dwImageRunCount
== 0)
731 ScmRemoveServiceImage(lpService
->lpImage
);
732 lpService
->lpImage
= NULL
;
736 /* Decrement the group reference counter */
737 ScmSetServiceGroup(lpService
, NULL
);
739 /* Release the SecurityDescriptor */
740 if (lpService
->pSecurityDescriptor
!= NULL
)
741 HeapFree(GetProcessHeap(), 0, lpService
->pSecurityDescriptor
);
743 /* Remove the Service from the List */
744 RemoveEntryList(&lpService
->ServiceListEntry
);
746 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
748 /* Delete the service record */
749 HeapFree(GetProcessHeap(), 0, lpService
);
756 CreateServiceListEntry(LPCWSTR lpServiceName
,
759 PSERVICE lpService
= NULL
;
760 LPWSTR lpDisplayName
= NULL
;
761 LPWSTR lpGroup
= NULL
;
766 DWORD dwErrorControl
;
769 DPRINT("Service: '%S'\n", lpServiceName
);
770 if (*lpServiceName
== L
'{')
771 return ERROR_SUCCESS
;
773 dwSize
= sizeof(DWORD
);
774 dwError
= RegQueryValueExW(hServiceKey
,
778 (LPBYTE
)&dwServiceType
,
780 if (dwError
!= ERROR_SUCCESS
)
781 return ERROR_SUCCESS
;
783 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
784 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
785 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
786 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
787 return ERROR_SUCCESS
;
789 DPRINT("Service type: %lx\n", dwServiceType
);
791 dwSize
= sizeof(DWORD
);
792 dwError
= RegQueryValueExW(hServiceKey
,
796 (LPBYTE
)&dwStartType
,
798 if (dwError
!= ERROR_SUCCESS
)
799 return ERROR_SUCCESS
;
801 DPRINT("Start type: %lx\n", dwStartType
);
803 dwSize
= sizeof(DWORD
);
804 dwError
= RegQueryValueExW(hServiceKey
,
808 (LPBYTE
)&dwErrorControl
,
810 if (dwError
!= ERROR_SUCCESS
)
811 return ERROR_SUCCESS
;
813 DPRINT("Error control: %lx\n", dwErrorControl
);
815 dwError
= RegQueryValueExW(hServiceKey
,
821 if (dwError
!= ERROR_SUCCESS
)
824 DPRINT("Tag: %lx\n", dwTagId
);
826 dwError
= ScmReadString(hServiceKey
,
829 if (dwError
!= ERROR_SUCCESS
)
832 DPRINT("Group: %S\n", lpGroup
);
834 dwError
= ScmReadString(hServiceKey
,
837 if (dwError
!= ERROR_SUCCESS
)
838 lpDisplayName
= NULL
;
840 DPRINT("Display name: %S\n", lpDisplayName
);
842 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
846 if (dwError
!= ERROR_SUCCESS
)
849 lpService
->dwErrorControl
= dwErrorControl
;
850 lpService
->dwTag
= dwTagId
;
854 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
855 if (dwError
!= ERROR_SUCCESS
)
859 if (lpDisplayName
!= NULL
)
861 lpService
->lpDisplayName
= lpDisplayName
;
862 lpDisplayName
= NULL
;
865 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
866 if (lpService
->lpGroup
!= NULL
)
868 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
870 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
871 lpService
->dwStartType
,
872 lpService
->Status
.dwServiceType
,
874 lpService
->dwErrorControl
);
876 if (ScmIsDeleteFlagSet(hServiceKey
))
877 lpService
->bDeleted
= TRUE
;
879 ScmGenerateServiceTag(lpService
);
881 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
883 dwError
= ScmReadSecurityDescriptor(hServiceKey
,
884 &lpService
->pSecurityDescriptor
);
885 if (dwError
!= ERROR_SUCCESS
)
888 /* Assing the default security descriptor if the security descriptor cannot be read */
889 if (lpService
->pSecurityDescriptor
== NULL
)
891 DPRINT("No security descriptor found! Assign default security descriptor!\n");
892 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
893 if (dwError
!= ERROR_SUCCESS
)
896 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
897 lpService
->pSecurityDescriptor
);
898 if (dwError
!= ERROR_SUCCESS
)
905 HeapFree(GetProcessHeap(), 0, lpGroup
);
907 if (lpDisplayName
!= NULL
)
908 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
910 if (lpService
!= NULL
)
912 ASSERT(lpService
->lpImage
== NULL
);
920 ScmDeleteMarkedServices(VOID
)
922 PLIST_ENTRY ServiceEntry
;
923 PSERVICE CurrentService
;
927 ServiceEntry
= ServiceListHead
.Flink
;
928 while (ServiceEntry
!= &ServiceListHead
)
930 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
932 ServiceEntry
= ServiceEntry
->Flink
;
934 if (CurrentService
->bDeleted
!= FALSE
)
936 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
937 L
"System\\CurrentControlSet\\Services",
941 if (dwError
== ERROR_SUCCESS
)
943 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
944 RegCloseKey(hServicesKey
);
945 if (dwError
== ERROR_SUCCESS
)
947 RemoveEntryList(&CurrentService
->ServiceListEntry
);
948 HeapFree(GetProcessHeap(), 0, CurrentService
);
952 if (dwError
!= ERROR_SUCCESS
)
953 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
961 ScmGetNoInteractiveServicesValue(VOID
)
967 lError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
968 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
972 if (lError
== ERROR_SUCCESS
)
974 dwKeySize
= sizeof(NoInteractiveServices
);
975 lError
= RegQueryValueExW(hKey
,
976 L
"NoInteractiveServices",
979 (LPBYTE
)&NoInteractiveServices
,
987 ScmCreateServiceDatabase(VOID
)
989 WCHAR szSubKey
[MAX_PATH
];
993 DWORD dwSubKeyLength
;
994 FILETIME ftLastChanged
;
997 DPRINT("ScmCreateServiceDatabase() called\n");
999 /* Retrieve the NoInteractiveServies value */
1000 ScmGetNoInteractiveServicesValue();
1002 /* Create the service group list */
1003 dwError
= ScmCreateGroupList();
1004 if (dwError
!= ERROR_SUCCESS
)
1007 /* Initialize image and service lists */
1008 InitializeListHead(&ImageListHead
);
1009 InitializeListHead(&ServiceListHead
);
1011 /* Initialize the database lock */
1012 RtlInitializeResource(&DatabaseLock
);
1014 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1015 L
"System\\CurrentControlSet\\Services",
1019 if (dwError
!= ERROR_SUCCESS
)
1025 dwSubKeyLength
= MAX_PATH
;
1026 dwError
= RegEnumKeyExW(hServicesKey
,
1034 if (dwError
== ERROR_SUCCESS
&&
1035 szSubKey
[0] != L
'{')
1037 DPRINT("SubKeyName: '%S'\n", szSubKey
);
1039 dwError
= RegOpenKeyExW(hServicesKey
,
1044 if (dwError
== ERROR_SUCCESS
)
1046 dwError
= CreateServiceListEntry(szSubKey
,
1049 RegCloseKey(hServiceKey
);
1053 if (dwError
!= ERROR_SUCCESS
)
1059 RegCloseKey(hServicesKey
);
1061 /* Wait for the LSA server */
1064 /* Delete services that are marked for delete */
1065 ScmDeleteMarkedServices();
1067 DPRINT("ScmCreateServiceDatabase() done\n");
1069 return ERROR_SUCCESS
;
1074 ScmShutdownServiceDatabase(VOID
)
1076 DPRINT("ScmShutdownServiceDatabase() called\n");
1078 ScmDeleteMarkedServices();
1079 RtlDeleteResource(&DatabaseLock
);
1081 DPRINT("ScmShutdownServiceDatabase() done\n");
1086 ScmCheckDriver(PSERVICE Service
)
1088 OBJECT_ATTRIBUTES ObjectAttributes
;
1089 UNICODE_STRING DirName
;
1092 POBJECT_DIRECTORY_INFORMATION DirInfo
;
1097 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
1099 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
1101 RtlInitUnicodeString(&DirName
, L
"\\Driver");
1103 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
1105 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
1106 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
1109 InitializeObjectAttributes(&ObjectAttributes
,
1115 Status
= NtOpenDirectoryObject(&DirHandle
,
1116 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1118 if (!NT_SUCCESS(Status
))
1123 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
1124 2 * MAX_PATH
* sizeof(WCHAR
);
1125 DirInfo
= HeapAlloc(GetProcessHeap(),
1132 Status
= NtQueryDirectoryObject(DirHandle
,
1139 if (Status
== STATUS_NO_MORE_ENTRIES
)
1141 /* FIXME: Add current service to 'failed service' list */
1142 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
1146 if (!NT_SUCCESS(Status
))
1149 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
1151 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
1153 DPRINT("Found: '%S' '%wZ'\n",
1154 Service
->lpServiceName
, &DirInfo
->Name
);
1156 /* Mark service as 'running' */
1157 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1158 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1159 Service
->Status
.dwWin32ExitCode
= ERROR_SUCCESS
;
1160 Service
->Status
.dwServiceSpecificExitCode
= 0;
1161 Service
->Status
.dwCheckPoint
= 0;
1162 Service
->Status
.dwWaitHint
= 0;
1164 /* Mark the service group as 'running' */
1165 if (Service
->lpGroup
!= NULL
)
1167 Service
->lpGroup
->ServicesRunning
= TRUE
;
1174 HeapFree(GetProcessHeap(),
1179 return STATUS_SUCCESS
;
1184 ScmGetBootAndSystemDriverState(VOID
)
1186 PLIST_ENTRY ServiceEntry
;
1187 PSERVICE CurrentService
;
1189 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1191 ServiceEntry
= ServiceListHead
.Flink
;
1192 while (ServiceEntry
!= &ServiceListHead
)
1194 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1196 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
1197 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
1200 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
1202 ScmCheckDriver(CurrentService
);
1205 ServiceEntry
= ServiceEntry
->Flink
;
1208 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1213 ScmControlService(HANDLE hControlPipe
,
1215 SERVICE_STATUS_HANDLE hServiceStatus
,
1218 PSCM_CONTROL_PACKET ControlPacket
;
1219 SCM_REPLY_PACKET ReplyPacket
;
1221 DWORD dwWriteCount
= 0;
1222 DWORD dwReadCount
= 0;
1225 DWORD dwError
= ERROR_SUCCESS
;
1227 OVERLAPPED Overlapped
= {0};
1229 DPRINT("ScmControlService() called\n");
1231 /* Acquire the service control critical section, to synchronize requests */
1232 EnterCriticalSection(&ControlServiceCriticalSection
);
1234 /* Calculate the total length of the start command line */
1235 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1236 PacketSize
+= (DWORD
)((wcslen(pServiceName
) + 1) * sizeof(WCHAR
));
1238 ControlPacket
= HeapAlloc(GetProcessHeap(),
1241 if (ControlPacket
== NULL
)
1243 LeaveCriticalSection(&ControlServiceCriticalSection
);
1244 return ERROR_NOT_ENOUGH_MEMORY
;
1247 ControlPacket
->dwSize
= PacketSize
;
1248 ControlPacket
->dwControl
= dwControl
;
1249 ControlPacket
->hServiceStatus
= hServiceStatus
;
1251 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1253 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1254 wcscpy(Ptr
, pServiceName
);
1256 ControlPacket
->dwArgumentsCount
= 0;
1257 ControlPacket
->dwArgumentsOffset
= 0;
1259 bResult
= WriteFile(hControlPipe
,
1264 if (bResult
== FALSE
)
1266 DPRINT("WriteFile() returned FALSE\n");
1268 dwError
= GetLastError();
1269 if (dwError
== ERROR_IO_PENDING
)
1271 DPRINT("dwError: ERROR_IO_PENDING\n");
1273 dwError
= WaitForSingleObject(hControlPipe
,
1275 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1277 if (dwError
== WAIT_TIMEOUT
)
1279 bResult
= CancelIo(hControlPipe
);
1280 if (bResult
== FALSE
)
1282 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1285 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1288 else if (dwError
== WAIT_OBJECT_0
)
1290 bResult
= GetOverlappedResult(hControlPipe
,
1294 if (bResult
== FALSE
)
1296 dwError
= GetLastError();
1297 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1305 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1310 /* Read the reply */
1311 Overlapped
.hEvent
= (HANDLE
) NULL
;
1313 bResult
= ReadFile(hControlPipe
,
1315 sizeof(SCM_REPLY_PACKET
),
1318 if (bResult
== FALSE
)
1320 DPRINT("ReadFile() returned FALSE\n");
1322 dwError
= GetLastError();
1323 if (dwError
== ERROR_IO_PENDING
)
1325 DPRINT("dwError: ERROR_IO_PENDING\n");
1327 dwError
= WaitForSingleObject(hControlPipe
,
1329 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1331 if (dwError
== WAIT_TIMEOUT
)
1333 bResult
= CancelIo(hControlPipe
);
1334 if (bResult
== FALSE
)
1336 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1339 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1342 else if (dwError
== WAIT_OBJECT_0
)
1344 bResult
= GetOverlappedResult(hControlPipe
,
1348 if (bResult
== FALSE
)
1350 dwError
= GetLastError();
1351 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1359 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1365 /* Release the control packet */
1366 HeapFree(GetProcessHeap(),
1370 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1372 dwError
= ReplyPacket
.dwError
;
1375 LeaveCriticalSection(&ControlServiceCriticalSection
);
1377 DPRINT("ScmControlService() done\n");
1384 ScmSendStartCommand(PSERVICE Service
,
1388 DWORD dwError
= ERROR_SUCCESS
;
1389 PSCM_CONTROL_PACKET ControlPacket
;
1390 SCM_REPLY_PACKET ReplyPacket
;
1397 DWORD dwWriteCount
= 0;
1398 DWORD dwReadCount
= 0;
1399 OVERLAPPED Overlapped
= {0};
1401 DPRINT("ScmSendStartCommand() called\n");
1403 /* Calculate the total length of the start command line */
1404 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1405 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1408 * Calculate the required packet size for the start argument vector 'argv',
1409 * composed of the list of pointer offsets, followed by UNICODE strings.
1410 * The strings are stored continuously after the vector of offsets, with
1411 * the offsets being relative to the beginning of the vector, as in the
1412 * following layout (with N == argc):
1413 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1415 if (argc
> 0 && argv
!= NULL
)
1417 PacketSize
= ALIGN_UP(PacketSize
, PWSTR
);
1418 PacketSize
+= (argc
* sizeof(PWSTR
));
1420 DPRINT("Argc: %lu\n", argc
);
1421 for (i
= 0; i
< argc
; i
++)
1423 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1424 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
));
1428 /* Allocate a control packet */
1429 ControlPacket
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, PacketSize
);
1430 if (ControlPacket
== NULL
)
1431 return ERROR_NOT_ENOUGH_MEMORY
;
1433 ControlPacket
->dwSize
= PacketSize
;
1434 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1435 ? SERVICE_CONTROL_START_OWN
1436 : SERVICE_CONTROL_START_SHARE
;
1437 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1438 ControlPacket
->dwServiceTag
= Service
->dwTag
;
1440 /* Copy the start command line */
1441 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1442 Ptr
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1443 wcscpy(Ptr
, Service
->lpServiceName
);
1445 ControlPacket
->dwArgumentsCount
= 0;
1446 ControlPacket
->dwArgumentsOffset
= 0;
1448 /* Copy the argument vector */
1449 if (argc
> 0 && argv
!= NULL
)
1451 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1452 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1453 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1455 ControlPacket
->dwArgumentsCount
= argc
;
1456 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1458 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1459 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1461 for (i
= 0; i
< argc
; i
++)
1463 wcscpy(pArgPtr
, argv
[i
]);
1464 pOffPtr
[i
] = (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1465 DPRINT("offset[%lu]: %p\n", i
, pOffPtr
[i
]);
1466 pArgPtr
+= wcslen(argv
[i
]) + 1;
1470 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1475 if (bResult
== FALSE
)
1477 DPRINT("WriteFile() returned FALSE\n");
1479 dwError
= GetLastError();
1480 if (dwError
== ERROR_IO_PENDING
)
1482 DPRINT("dwError: ERROR_IO_PENDING\n");
1484 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1486 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1488 if (dwError
== WAIT_TIMEOUT
)
1490 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1491 if (bResult
== FALSE
)
1493 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1496 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1499 else if (dwError
== WAIT_OBJECT_0
)
1501 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1505 if (bResult
== FALSE
)
1507 dwError
= GetLastError();
1508 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1516 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1521 /* Read the reply */
1522 Overlapped
.hEvent
= (HANDLE
) NULL
;
1524 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1526 sizeof(SCM_REPLY_PACKET
),
1529 if (bResult
== FALSE
)
1531 DPRINT("ReadFile() returned FALSE\n");
1533 dwError
= GetLastError();
1534 if (dwError
== ERROR_IO_PENDING
)
1536 DPRINT("dwError: ERROR_IO_PENDING\n");
1538 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1540 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1542 if (dwError
== WAIT_TIMEOUT
)
1544 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1545 if (bResult
== FALSE
)
1547 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1550 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1553 else if (dwError
== WAIT_OBJECT_0
)
1555 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1559 if (bResult
== FALSE
)
1561 dwError
= GetLastError();
1562 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1570 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1576 /* Release the control packet */
1577 HeapFree(GetProcessHeap(),
1581 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1583 dwError
= ReplyPacket
.dwError
;
1586 DPRINT("ScmSendStartCommand() done\n");
1593 ScmWaitForServiceConnect(PSERVICE Service
)
1596 DWORD dwProcessId
= 0;
1597 DWORD dwError
= ERROR_SUCCESS
;
1599 OVERLAPPED Overlapped
= {0};
1601 LPCWSTR lpLogStrings
[3];
1602 WCHAR szBuffer1
[20];
1603 WCHAR szBuffer2
[20];
1606 DPRINT("ScmWaitForServiceConnect()\n");
1608 Overlapped
.hEvent
= (HANDLE
)NULL
;
1610 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1612 if (bResult
== FALSE
)
1614 DPRINT("ConnectNamedPipe() returned FALSE\n");
1616 dwError
= GetLastError();
1617 if (dwError
== ERROR_IO_PENDING
)
1619 DPRINT("dwError: ERROR_IO_PENDING\n");
1621 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1623 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1625 if (dwError
== WAIT_TIMEOUT
)
1627 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1629 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1630 if (bResult
== FALSE
)
1632 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1636 _ultow(PipeTimeout
, szBuffer1
, 10);
1637 lpLogStrings
[0] = Service
->lpDisplayName
;
1638 lpLogStrings
[1] = szBuffer1
;
1640 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1641 EVENTLOG_ERROR_TYPE
,
1645 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1647 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1649 else if (dwError
== WAIT_OBJECT_0
)
1651 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1655 if (bResult
== FALSE
)
1657 dwError
= GetLastError();
1658 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1664 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1666 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1671 DPRINT("Control pipe connected!\n");
1673 Overlapped
.hEvent
= (HANDLE
) NULL
;
1675 /* Read the process id from pipe */
1676 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1677 (LPVOID
)&dwProcessId
,
1681 if (bResult
== FALSE
)
1683 DPRINT("ReadFile() returned FALSE\n");
1685 dwError
= GetLastError();
1686 if (dwError
== ERROR_IO_PENDING
)
1688 DPRINT("dwError: ERROR_IO_PENDING\n");
1690 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1692 if (dwError
== WAIT_TIMEOUT
)
1694 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1696 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1697 if (bResult
== FALSE
)
1699 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1703 _ultow(PipeTimeout
, szBuffer1
, 10);
1704 lpLogStrings
[0] = szBuffer1
;
1706 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1707 EVENTLOG_ERROR_TYPE
,
1711 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1713 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1715 else if (dwError
== WAIT_OBJECT_0
)
1717 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1719 DPRINT("Process Id: %lu\n", dwProcessId
);
1721 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1725 if (bResult
== FALSE
)
1727 dwError
= GetLastError();
1728 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1735 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1740 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1745 if (dwProcessId
!= Service
->lpImage
->dwProcessId
)
1748 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1749 _ultow(dwProcessId
, szBuffer2
, 10);
1751 lpLogStrings
[0] = Service
->lpDisplayName
;
1752 lpLogStrings
[1] = szBuffer1
;
1753 lpLogStrings
[2] = szBuffer2
;
1755 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1756 EVENTLOG_WARNING_TYPE
,
1761 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1764 DPRINT("ScmWaitForServiceConnect() done\n");
1766 return ERROR_SUCCESS
;
1771 ScmStartUserModeService(PSERVICE Service
,
1775 PROCESS_INFORMATION ProcessInformation
;
1776 STARTUPINFOW StartupInfo
;
1777 LPVOID lpEnvironment
;
1779 DWORD dwError
= ERROR_SUCCESS
;
1781 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1783 /* If the image is already running ... */
1784 if (Service
->lpImage
->dwImageRunCount
> 1)
1786 /* ... just send a start command */
1787 return ScmSendStartCommand(Service
, argc
, argv
);
1790 /* Otherwise start its process */
1791 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1792 StartupInfo
.cb
= sizeof(StartupInfo
);
1793 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1795 if (Service
->lpImage
->hToken
)
1797 /* User token: Run the service under the user account */
1799 if (!CreateEnvironmentBlock(&lpEnvironment
, Service
->lpImage
->hToken
, FALSE
))
1801 /* We failed, run the service with the current environment */
1802 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1803 GetLastError(), Service
->lpServiceName
);
1804 lpEnvironment
= NULL
;
1807 /* Impersonate the new user */
1808 Result
= ImpersonateLoggedOnUser(Service
->lpImage
->hToken
);
1811 /* Launch the process in the user's logon session */
1812 Result
= CreateProcessAsUserW(Service
->lpImage
->hToken
,
1814 Service
->lpImage
->pszImagePath
,
1818 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1822 &ProcessInformation
);
1824 dwError
= GetLastError();
1826 /* Revert the impersonation */
1831 dwError
= GetLastError();
1832 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError
);
1837 /* No user token: Run the service under the LocalSystem account */
1839 if (!CreateEnvironmentBlock(&lpEnvironment
, NULL
, TRUE
))
1841 /* We failed, run the service with the current environment */
1842 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1843 GetLastError(), Service
->lpServiceName
);
1844 lpEnvironment
= NULL
;
1847 /* Use the interactive desktop if the service is interactive */
1848 if ((NoInteractiveServices
== 0) &&
1849 (Service
->Status
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
))
1851 StartupInfo
.dwFlags
|= STARTF_INHERITDESKTOP
;
1852 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
1855 if (wcsstr(Service
->lpImage
->pszImagePath
, L
"\\system32\\lsass.exe") == NULL
)
1857 Result
= CreateProcessW(NULL
,
1858 Service
->lpImage
->pszImagePath
,
1862 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1866 &ProcessInformation
);
1868 dwError
= GetLastError();
1873 dwError
= ERROR_SUCCESS
;
1878 DestroyEnvironmentBlock(lpEnvironment
);
1882 DPRINT1("Starting '%S' failed with error %d\n",
1883 Service
->lpServiceName
, dwError
);
1887 DPRINT("Process Id: %lu Handle %p\n",
1888 ProcessInformation
.dwProcessId
,
1889 ProcessInformation
.hProcess
);
1890 DPRINT("Thread Id: %lu Handle %p\n",
1891 ProcessInformation
.dwThreadId
,
1892 ProcessInformation
.hThread
);
1894 /* Get the process handle and ID */
1895 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1896 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1898 /* Resume the main thread and close its handle */
1899 ResumeThread(ProcessInformation
.hThread
);
1900 CloseHandle(ProcessInformation
.hThread
);
1902 /* Connect control pipe */
1903 dwError
= ScmWaitForServiceConnect(Service
);
1904 if (dwError
!= ERROR_SUCCESS
)
1906 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1907 Service
->lpImage
->dwProcessId
= 0;
1911 /* Send the start command */
1912 return ScmSendStartCommand(Service
, argc
, argv
);
1917 ScmLoadService(PSERVICE Service
,
1921 PSERVICE_GROUP Group
= Service
->lpGroup
;
1922 DWORD dwError
= ERROR_SUCCESS
;
1923 LPCWSTR lpLogStrings
[2];
1924 WCHAR szLogBuffer
[80];
1926 DPRINT("ScmLoadService() called\n");
1927 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1929 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1931 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1932 return ERROR_SERVICE_ALREADY_RUNNING
;
1935 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1937 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1939 /* Start the driver */
1940 dwError
= ScmStartDriver(Service
);
1942 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1944 /* Start user-mode service */
1945 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1946 if (dwError
== ERROR_SUCCESS
)
1948 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1949 if (dwError
== ERROR_SUCCESS
)
1951 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1952 Service
->Status
.dwControlsAccepted
= 0;
1956 Service
->lpImage
->dwImageRunCount
--;
1957 if (Service
->lpImage
->dwImageRunCount
== 0)
1959 ScmRemoveServiceImage(Service
->lpImage
);
1960 Service
->lpImage
= NULL
;
1966 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
1968 if (dwError
== ERROR_SUCCESS
)
1972 Group
->ServicesRunning
= TRUE
;
1975 /* Log a successful service start */
1976 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
1977 lpLogStrings
[0] = Service
->lpDisplayName
;
1978 lpLogStrings
[1] = szLogBuffer
;
1980 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1981 EVENTLOG_INFORMATION_TYPE
,
1987 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1989 /* Log a failed service start */
1990 StringCchPrintfW(szLogBuffer
, ARRAYSIZE(szLogBuffer
),
1992 lpLogStrings
[0] = Service
->lpServiceName
;
1993 lpLogStrings
[1] = szLogBuffer
;
1994 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
1995 EVENTLOG_ERROR_TYPE
,
2001 switch (Service
->dwErrorControl
)
2003 case SERVICE_ERROR_SEVERE
:
2004 if (IsLastKnownGood
== FALSE
)
2006 /* FIXME: Boot last known good configuration */
2010 case SERVICE_ERROR_CRITICAL
:
2011 if (IsLastKnownGood
== FALSE
)
2013 /* FIXME: Boot last known good configuration */
2029 ScmStartService(PSERVICE Service
,
2033 DWORD dwError
= ERROR_SUCCESS
;
2034 SC_RPC_LOCK Lock
= NULL
;
2036 DPRINT("ScmStartService() called\n");
2037 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
2039 /* Acquire the service control critical section, to synchronize starts */
2040 EnterCriticalSection(&ControlServiceCriticalSection
);
2043 * Acquire the user service start lock while the service is starting, if
2044 * needed (i.e. if we are not starting it during the initialization phase).
2045 * If we don't success, bail out.
2049 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
2050 if (dwError
!= ERROR_SUCCESS
) goto done
;
2053 /* Really start the service */
2054 dwError
= ScmLoadService(Service
, argc
, argv
);
2056 /* Release the service start lock, if needed, and the critical section */
2057 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
2060 LeaveCriticalSection(&ControlServiceCriticalSection
);
2062 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
2069 ScmAutoStartServices(VOID
)
2072 PLIST_ENTRY GroupEntry
;
2073 PLIST_ENTRY ServiceEntry
;
2074 PSERVICE_GROUP CurrentGroup
;
2075 PSERVICE CurrentService
;
2076 WCHAR szSafeBootServicePath
[MAX_PATH
];
2077 DWORD SafeBootEnabled
;
2083 * This function MUST be called ONLY at initialization time.
2084 * Therefore, no need to acquire the user service start lock.
2086 ASSERT(ScmInitialize
);
2088 /* Retrieve the SafeBoot parameter */
2089 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2090 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
2094 if (dwError
== ERROR_SUCCESS
)
2096 dwKeySize
= sizeof(SafeBootEnabled
);
2097 dwError
= RegQueryValueExW(hKey
,
2101 (LPBYTE
)&SafeBootEnabled
,
2106 /* Default to Normal boot if the value doesn't exist */
2107 if (dwError
!= ERROR_SUCCESS
)
2108 SafeBootEnabled
= 0;
2110 /* Acquire the service control critical section, to synchronize starts */
2111 EnterCriticalSection(&ControlServiceCriticalSection
);
2113 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
2114 ServiceEntry
= ServiceListHead
.Flink
;
2115 while (ServiceEntry
!= &ServiceListHead
)
2117 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2119 /* Build the safe boot path */
2120 StringCchCopyW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2121 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
2123 switch (SafeBootEnabled
)
2125 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
2128 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2133 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2138 if (SafeBootEnabled
!= 0)
2140 /* If key does not exist then do not assume safe mode */
2141 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2142 szSafeBootServicePath
,
2146 if (dwError
== ERROR_SUCCESS
)
2150 /* Finish Safe Boot path off */
2151 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2152 CurrentService
->lpServiceName
);
2154 /* Check that the key is in the Safe Boot path */
2155 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2156 szSafeBootServicePath
,
2160 if (dwError
!= ERROR_SUCCESS
)
2162 /* Mark service as visited so it is not auto-started */
2163 CurrentService
->ServiceVisited
= TRUE
;
2167 /* Must be auto-started in safe mode - mark as unvisited */
2169 CurrentService
->ServiceVisited
= FALSE
;
2174 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2175 CurrentService
->ServiceVisited
= FALSE
;
2179 ServiceEntry
= ServiceEntry
->Flink
;
2182 /* Start all services which are members of an existing group */
2183 GroupEntry
= GroupListHead
.Flink
;
2184 while (GroupEntry
!= &GroupListHead
)
2186 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
2188 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
2190 /* Start all services witch have a valid tag */
2191 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
2193 ServiceEntry
= ServiceListHead
.Flink
;
2194 while (ServiceEntry
!= &ServiceListHead
)
2196 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2198 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2199 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2200 (CurrentService
->ServiceVisited
== FALSE
) &&
2201 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
2203 CurrentService
->ServiceVisited
= TRUE
;
2204 ScmLoadService(CurrentService
, 0, NULL
);
2207 ServiceEntry
= ServiceEntry
->Flink
;
2211 /* Start all services which have an invalid tag or which do not have a tag */
2212 ServiceEntry
= ServiceListHead
.Flink
;
2213 while (ServiceEntry
!= &ServiceListHead
)
2215 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2217 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2218 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2219 (CurrentService
->ServiceVisited
== FALSE
))
2221 CurrentService
->ServiceVisited
= TRUE
;
2222 ScmLoadService(CurrentService
, 0, NULL
);
2225 ServiceEntry
= ServiceEntry
->Flink
;
2228 GroupEntry
= GroupEntry
->Flink
;
2231 /* Start all services which are members of any non-existing group */
2232 ServiceEntry
= ServiceListHead
.Flink
;
2233 while (ServiceEntry
!= &ServiceListHead
)
2235 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2237 if ((CurrentService
->lpGroup
!= NULL
) &&
2238 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2239 (CurrentService
->ServiceVisited
== FALSE
))
2241 CurrentService
->ServiceVisited
= TRUE
;
2242 ScmLoadService(CurrentService
, 0, NULL
);
2245 ServiceEntry
= ServiceEntry
->Flink
;
2248 /* Start all services which are not a member of any group */
2249 ServiceEntry
= ServiceListHead
.Flink
;
2250 while (ServiceEntry
!= &ServiceListHead
)
2252 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2254 if ((CurrentService
->lpGroup
== NULL
) &&
2255 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2256 (CurrentService
->ServiceVisited
== FALSE
))
2258 CurrentService
->ServiceVisited
= TRUE
;
2259 ScmLoadService(CurrentService
, 0, NULL
);
2262 ServiceEntry
= ServiceEntry
->Flink
;
2265 /* Clear 'ServiceVisited' flag again */
2266 ServiceEntry
= ServiceListHead
.Flink
;
2267 while (ServiceEntry
!= &ServiceListHead
)
2269 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2270 CurrentService
->ServiceVisited
= FALSE
;
2271 ServiceEntry
= ServiceEntry
->Flink
;
2274 /* Release the critical section */
2275 LeaveCriticalSection(&ControlServiceCriticalSection
);
2280 ScmAutoShutdownServices(VOID
)
2282 PLIST_ENTRY ServiceEntry
;
2283 PSERVICE CurrentService
;
2285 DPRINT("ScmAutoShutdownServices() called\n");
2287 /* Lock the service database exclusively */
2288 ScmLockDatabaseExclusive();
2290 ServiceEntry
= ServiceListHead
.Flink
;
2291 while (ServiceEntry
!= &ServiceListHead
)
2293 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2295 if ((CurrentService
->Status
.dwControlsAccepted
& SERVICE_ACCEPT_SHUTDOWN
) &&
2296 (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2297 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
))
2299 /* Send the shutdown notification */
2300 DPRINT("Shutdown service: %S\n", CurrentService
->lpServiceName
);
2301 ScmControlService(CurrentService
->lpImage
->hControlPipe
,
2302 CurrentService
->lpServiceName
,
2303 (SERVICE_STATUS_HANDLE
)CurrentService
,
2304 SERVICE_CONTROL_SHUTDOWN
);
2307 ServiceEntry
= ServiceEntry
->Flink
;
2310 /* Unlock the service database */
2311 ScmUnlockDatabase();
2313 DPRINT("ScmAutoShutdownServices() done\n");
2318 ScmLockDatabaseExclusive(VOID
)
2320 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2325 ScmLockDatabaseShared(VOID
)
2327 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2332 ScmUnlockDatabase(VOID
)
2334 RtlReleaseResource(&DatabaseLock
);
2339 ScmInitNamedPipeCriticalSection(VOID
)
2345 InitializeCriticalSection(&ControlServiceCriticalSection
);
2347 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2348 L
"SYSTEM\\CurrentControlSet\\Control",
2352 if (dwError
== ERROR_SUCCESS
)
2354 dwKeySize
= sizeof(PipeTimeout
);
2355 RegQueryValueExW(hKey
,
2356 L
"ServicesPipeTimeout",
2359 (LPBYTE
)&PipeTimeout
,
2367 ScmDeleteNamedPipeCriticalSection(VOID
)
2369 DeleteCriticalSection(&ControlServiceCriticalSection
);