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;
35 /* The critical section synchronizes service control requests */
36 static CRITICAL_SECTION ControlServiceCriticalSection
;
37 static DWORD PipeTimeout
= 30000; /* 30 Seconds */
40 /* FUNCTIONS *****************************************************************/
43 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
45 WCHAR szControlPipeName
[MAX_PATH
+ 1];
46 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
47 DWORD ServiceCurrent
= 0;
52 /* Get the service number */
53 /* TODO: Create registry entry with correct write access */
54 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
55 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
61 if (dwError
!= ERROR_SUCCESS
)
63 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
67 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
69 dwKeySize
= sizeof(DWORD
);
70 dwError
= RegQueryValueExW(hServiceCurrentKey
,
71 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
73 if (dwError
!= ERROR_SUCCESS
)
75 RegCloseKey(hServiceCurrentKey
);
76 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
83 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
85 RegCloseKey(hServiceCurrentKey
);
87 if (dwError
!= ERROR_SUCCESS
)
89 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
93 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
94 StringCchPrintfW(szControlPipeName
, ARRAYSIZE(szControlPipeName
),
95 L
"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent
);
97 DPRINT("PipeName: %S\n", szControlPipeName
);
99 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
100 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
101 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
107 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
108 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
110 DPRINT1("Failed to create control pipe!\n");
111 return GetLastError();
114 return ERROR_SUCCESS
;
118 static PSERVICE_IMAGE
119 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
121 PLIST_ENTRY ImageEntry
;
122 PSERVICE_IMAGE CurrentImage
;
124 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
126 ImageEntry
= ImageListHead
.Flink
;
127 while (ImageEntry
!= &ImageListHead
)
129 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
132 if (_wcsicmp(CurrentImage
->pszImagePath
, lpImagePath
) == 0)
134 DPRINT("Found image: '%S'\n", CurrentImage
->pszImagePath
);
138 ImageEntry
= ImageEntry
->Flink
;
141 DPRINT("Couldn't find a matching image\n");
150 ScmIsSameServiceAccount(
151 _In_ PCWSTR pszAccountName1
,
152 _In_ PCWSTR pszAccountName2
)
154 if (pszAccountName1
== NULL
&& pszAccountName2
== NULL
)
157 if (pszAccountName1
== NULL
&& pszAccountName2
&& wcscmp(pszAccountName2
, L
"LocalSystem") == 0)
160 if (pszAccountName2
== NULL
&& pszAccountName1
&& wcscmp(pszAccountName1
, L
"LocalSystem") == 0)
163 if (pszAccountName1
&& pszAccountName2
&& wcscmp(pszAccountName1
, pszAccountName2
) == 0)
172 ScmIsLocalSystemAccount(
173 _In_ PCWSTR pszAccountName
)
175 if (pszAccountName
== NULL
||
176 wcscmp(pszAccountName
, L
"LocalSystem") == 0)
186 IN PSERVICE pService
,
187 IN PSERVICE_IMAGE pImage
)
189 DWORD dwError
= ERROR_SUCCESS
;
190 PROFILEINFOW ProfileInfo
;
191 PWSTR pszUserName
= NULL
;
192 PWSTR pszDomainName
= NULL
;
193 PWSTR pszPassword
= NULL
;
196 DPRINT("ScmLogonService(%p %p)\n", pService
, pImage
);
197 DPRINT("Service %S\n", pService
->lpServiceName
);
199 if (ScmIsLocalSystemAccount(pImage
->pszAccountName
))
200 return ERROR_SUCCESS
;
202 /* Get the user and domain names */
203 ptr
= wcschr(pImage
->pszAccountName
, L
'\\');
207 pszUserName
= ptr
+ 1;
208 pszDomainName
= pImage
->pszAccountName
;
212 // ERROR_INVALID_SERVICE_ACCOUNT
213 pszUserName
= pImage
->pszAccountName
;
214 pszDomainName
= NULL
;
217 /* Build the service 'password' */
218 pszPassword
= HeapAlloc(GetProcessHeap(),
220 (wcslen(pService
->lpServiceName
) + 5) * sizeof(WCHAR
));
221 if (pszPassword
== NULL
)
223 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
227 wcscpy(pszPassword
, L
"_SC_");
228 wcscat(pszPassword
, pService
->lpServiceName
);
230 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName
, pszUserName
, pszPassword
);
232 /* Do the service logon */
233 if (!LogonUserW(pszUserName
,
236 LOGON32_LOGON_SERVICE
,
237 LOGON32_PROVIDER_DEFAULT
,
240 dwError
= GetLastError();
241 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError
);
243 /* Normalize the returned error */
244 dwError
= ERROR_SERVICE_LOGON_FAILED
;
248 /* Load the user profile; the per-user environment variables are thus correctly initialized */
249 ZeroMemory(&ProfileInfo
, sizeof(ProfileInfo
));
250 ProfileInfo
.dwSize
= sizeof(ProfileInfo
);
251 ProfileInfo
.dwFlags
= PI_NOUI
;
252 ProfileInfo
.lpUserName
= pszUserName
;
253 // ProfileInfo.lpProfilePath = NULL;
254 // ProfileInfo.lpDefaultPath = NULL;
255 // ProfileInfo.lpServerName = NULL;
256 // ProfileInfo.lpPolicyPath = NULL;
257 // ProfileInfo.hProfile = NULL;
259 if (!LoadUserProfileW(pImage
->hToken
, &ProfileInfo
))
261 dwError
= GetLastError();
262 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError
);
266 pImage
->hProfile
= ProfileInfo
.hProfile
;
269 if (pszPassword
!= NULL
)
270 HeapFree(GetProcessHeap(), 0, pszPassword
);
280 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
282 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
283 UNICODE_STRING ImagePath
;
284 UNICODE_STRING ObjectName
;
285 PSERVICE_IMAGE pServiceImage
= NULL
;
287 DWORD dwError
= ERROR_SUCCESS
;
291 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
293 RtlInitUnicodeString(&ImagePath
, NULL
);
294 RtlInitUnicodeString(&ObjectName
, NULL
);
296 /* Get service data */
297 RtlZeroMemory(&QueryTable
,
300 QueryTable
[0].Name
= L
"ImagePath";
301 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
302 QueryTable
[0].EntryContext
= &ImagePath
;
303 QueryTable
[1].Name
= L
"ObjectName";
304 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
305 QueryTable
[1].EntryContext
= &ObjectName
;
307 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
308 pService
->lpServiceName
,
312 if (!NT_SUCCESS(Status
))
314 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
315 return RtlNtStatusToDosError(Status
);
318 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
319 DPRINT("ObjectName: '%wZ'\n", &ObjectName
);
321 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
322 if (pServiceImage
== NULL
)
324 dwRecordSize
= sizeof(SERVICE_IMAGE
) +
325 ImagePath
.Length
+ sizeof(WCHAR
) +
326 ((ObjectName
.Length
!= 0) ? (ObjectName
.Length
+ sizeof(WCHAR
)) : 0);
328 /* Create a new service image */
329 pServiceImage
= HeapAlloc(GetProcessHeap(),
332 if (pServiceImage
== NULL
)
334 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
338 pServiceImage
->dwImageRunCount
= 1;
339 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
340 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
342 pString
= (PWSTR
)((INT_PTR
)pServiceImage
+ sizeof(SERVICE_IMAGE
));
344 /* Set the image path */
345 pServiceImage
->pszImagePath
= pString
;
346 wcscpy(pServiceImage
->pszImagePath
,
349 /* Set the account name */
350 if (ObjectName
.Length
> 0)
352 pString
= pString
+ wcslen(pString
) + 1;
354 pServiceImage
->pszAccountName
= pString
;
355 wcscpy(pServiceImage
->pszAccountName
,
360 dwError
= ScmLogonService(pService
, pServiceImage
);
361 if (dwError
!= ERROR_SUCCESS
)
363 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError
);
365 /* Release the service image */
366 HeapFree(GetProcessHeap(), 0, pServiceImage
);
371 /* Create the control pipe */
372 dwError
= ScmCreateNewControlPipe(pServiceImage
);
373 if (dwError
!= ERROR_SUCCESS
)
375 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError
);
377 /* Unload the user profile */
378 if (pServiceImage
->hProfile
!= NULL
)
379 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
381 /* Close the logon token */
382 if (pServiceImage
->hToken
!= NULL
)
383 CloseHandle(pServiceImage
->hToken
);
385 /* Release the service image */
386 HeapFree(GetProcessHeap(), 0, pServiceImage
);
391 /* FIXME: Add more initialization code here */
394 /* Append service record */
395 InsertTailList(&ImageListHead
,
396 &pServiceImage
->ImageListEntry
);
400 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
402 /* Fail if services in an image use different accounts */
403 if (!ScmIsSameServiceAccount(pServiceImage
->pszAccountName
, ObjectName
.Buffer
))
405 dwError
= ERROR_DIFFERENT_SERVICE_ACCOUNT
;
409 /* Increment the run counter */
410 pServiceImage
->dwImageRunCount
++;
413 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage
->pszImagePath
);
414 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage
->pszAccountName
);
415 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
417 /* Link the service image to the service */
418 pService
->lpImage
= pServiceImage
;
421 RtlFreeUnicodeString(&ObjectName
);
422 RtlFreeUnicodeString(&ImagePath
);
424 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
431 ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage
)
433 DPRINT1("ScmRemoveServiceImage() called\n");
435 /* FIXME: Terminate the process */
437 /* Remove the service image from the list */
438 RemoveEntryList(&pServiceImage
->ImageListEntry
);
440 /* Close the process handle */
441 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
442 CloseHandle(pServiceImage
->hProcess
);
444 /* Close the control pipe */
445 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
446 CloseHandle(pServiceImage
->hControlPipe
);
448 /* Unload the user profile */
449 if (pServiceImage
->hProfile
!= NULL
)
450 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
452 /* Close the logon token */
453 if (pServiceImage
->hToken
!= NULL
)
454 CloseHandle(pServiceImage
->hToken
);
456 /* Release the service image */
457 HeapFree(GetProcessHeap(), 0, pServiceImage
);
462 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
464 PLIST_ENTRY ServiceEntry
;
465 PSERVICE CurrentService
;
467 DPRINT("ScmGetServiceEntryByName() called\n");
469 ServiceEntry
= ServiceListHead
.Flink
;
470 while (ServiceEntry
!= &ServiceListHead
)
472 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
475 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
477 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
478 return CurrentService
;
481 ServiceEntry
= ServiceEntry
->Flink
;
484 DPRINT("Couldn't find a matching service\n");
491 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
493 PLIST_ENTRY ServiceEntry
;
494 PSERVICE CurrentService
;
496 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
498 ServiceEntry
= ServiceListHead
.Flink
;
499 while (ServiceEntry
!= &ServiceListHead
)
501 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
504 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
506 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
507 return CurrentService
;
510 ServiceEntry
= ServiceEntry
->Flink
;
513 DPRINT("Couldn't find a matching service\n");
520 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
522 PLIST_ENTRY ServiceEntry
;
523 PSERVICE CurrentService
;
525 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
527 ServiceEntry
= ServiceListHead
.Flink
;
528 while (ServiceEntry
!= &ServiceListHead
)
530 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
533 if (CurrentService
->dwResumeCount
> dwResumeCount
)
535 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
536 return CurrentService
;
539 ServiceEntry
= ServiceEntry
->Flink
;
542 DPRINT("Couldn't find a matching service\n");
549 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
550 PSERVICE
*lpServiceRecord
,
554 PSERVICE lpService
= NULL
;
556 DPRINT("Service: '%S'\n", lpServiceName
);
558 /* Allocate service entry */
559 lpService
= HeapAlloc(GetProcessHeap(),
561 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
562 if (lpService
== NULL
)
563 return ERROR_NOT_ENOUGH_MEMORY
;
565 *lpServiceRecord
= lpService
;
567 /* Copy service name */
568 wcscpy(lpService
->szServiceName
, lpServiceName
);
569 lpService
->lpServiceName
= lpService
->szServiceName
;
570 lpService
->lpDisplayName
= lpService
->lpServiceName
;
572 /* Set the start type */
573 lpService
->dwStartType
= dwStartType
;
575 /* Set the resume count */
576 lpService
->dwResumeCount
= ResumeCount
++;
578 /* Append service record */
579 InsertTailList(&ServiceListHead
,
580 &lpService
->ServiceListEntry
);
582 /* Initialize the service status */
583 lpService
->Status
.dwServiceType
= dwServiceType
;
584 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
585 lpService
->Status
.dwControlsAccepted
= 0;
586 lpService
->Status
.dwWin32ExitCode
=
587 (dwStartType
== SERVICE_DISABLED
) ? ERROR_SERVICE_DISABLED
: ERROR_SERVICE_NEVER_STARTED
;
588 lpService
->Status
.dwServiceSpecificExitCode
= 0;
589 lpService
->Status
.dwCheckPoint
= 0;
590 lpService
->Status
.dwWaitHint
=
591 (dwServiceType
& SERVICE_DRIVER
) ? 0 : 2000; /* 2 seconds */
593 return ERROR_SUCCESS
;
598 ScmDeleteServiceRecord(PSERVICE lpService
)
600 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
602 /* Delete the display name */
603 if (lpService
->lpDisplayName
!= NULL
&&
604 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
605 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
607 /* Dereference the service image */
608 if (lpService
->lpImage
)
610 lpService
->lpImage
->dwImageRunCount
--;
612 if (lpService
->lpImage
->dwImageRunCount
== 0)
614 ScmRemoveServiceImage(lpService
->lpImage
);
615 lpService
->lpImage
= NULL
;
619 /* Decrement the group reference counter */
620 ScmSetServiceGroup(lpService
, NULL
);
622 /* Release the SecurityDescriptor */
623 if (lpService
->pSecurityDescriptor
!= NULL
)
624 HeapFree(GetProcessHeap(), 0, lpService
->pSecurityDescriptor
);
626 /* Remove the Service from the List */
627 RemoveEntryList(&lpService
->ServiceListEntry
);
629 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
631 /* Delete the service record */
632 HeapFree(GetProcessHeap(), 0, lpService
);
639 CreateServiceListEntry(LPCWSTR lpServiceName
,
642 PSERVICE lpService
= NULL
;
643 LPWSTR lpDisplayName
= NULL
;
644 LPWSTR lpGroup
= NULL
;
649 DWORD dwErrorControl
;
652 DPRINT("Service: '%S'\n", lpServiceName
);
653 if (*lpServiceName
== L
'{')
654 return ERROR_SUCCESS
;
656 dwSize
= sizeof(DWORD
);
657 dwError
= RegQueryValueExW(hServiceKey
,
661 (LPBYTE
)&dwServiceType
,
663 if (dwError
!= ERROR_SUCCESS
)
664 return ERROR_SUCCESS
;
666 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
667 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
668 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
669 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
670 return ERROR_SUCCESS
;
672 DPRINT("Service type: %lx\n", dwServiceType
);
674 dwSize
= sizeof(DWORD
);
675 dwError
= RegQueryValueExW(hServiceKey
,
679 (LPBYTE
)&dwStartType
,
681 if (dwError
!= ERROR_SUCCESS
)
682 return ERROR_SUCCESS
;
684 DPRINT("Start type: %lx\n", dwStartType
);
686 dwSize
= sizeof(DWORD
);
687 dwError
= RegQueryValueExW(hServiceKey
,
691 (LPBYTE
)&dwErrorControl
,
693 if (dwError
!= ERROR_SUCCESS
)
694 return ERROR_SUCCESS
;
696 DPRINT("Error control: %lx\n", dwErrorControl
);
698 dwError
= RegQueryValueExW(hServiceKey
,
704 if (dwError
!= ERROR_SUCCESS
)
707 DPRINT("Tag: %lx\n", dwTagId
);
709 dwError
= ScmReadString(hServiceKey
,
712 if (dwError
!= ERROR_SUCCESS
)
715 DPRINT("Group: %S\n", lpGroup
);
717 dwError
= ScmReadString(hServiceKey
,
720 if (dwError
!= ERROR_SUCCESS
)
721 lpDisplayName
= NULL
;
723 DPRINT("Display name: %S\n", lpDisplayName
);
725 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
729 if (dwError
!= ERROR_SUCCESS
)
732 lpService
->dwErrorControl
= dwErrorControl
;
733 lpService
->dwTag
= dwTagId
;
737 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
738 if (dwError
!= ERROR_SUCCESS
)
742 if (lpDisplayName
!= NULL
)
744 lpService
->lpDisplayName
= lpDisplayName
;
745 lpDisplayName
= NULL
;
748 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
749 if (lpService
->lpGroup
!= NULL
)
751 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
753 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
754 lpService
->dwStartType
,
755 lpService
->Status
.dwServiceType
,
757 lpService
->dwErrorControl
);
759 if (ScmIsDeleteFlagSet(hServiceKey
))
760 lpService
->bDeleted
= TRUE
;
762 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
764 dwError
= ScmReadSecurityDescriptor(hServiceKey
,
765 &lpService
->pSecurityDescriptor
);
766 if (dwError
!= ERROR_SUCCESS
)
769 /* Assing the default security descriptor if the security descriptor cannot be read */
770 if (lpService
->pSecurityDescriptor
== NULL
)
772 DPRINT("No security descriptor found! Assign default security descriptor!\n");
773 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
774 if (dwError
!= ERROR_SUCCESS
)
777 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
778 lpService
->pSecurityDescriptor
);
779 if (dwError
!= ERROR_SUCCESS
)
786 HeapFree(GetProcessHeap(), 0, lpGroup
);
788 if (lpDisplayName
!= NULL
)
789 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
791 if (lpService
!= NULL
)
793 ASSERT(lpService
->lpImage
== NULL
);
801 ScmDeleteMarkedServices(VOID
)
803 PLIST_ENTRY ServiceEntry
;
804 PSERVICE CurrentService
;
808 ServiceEntry
= ServiceListHead
.Flink
;
809 while (ServiceEntry
!= &ServiceListHead
)
811 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
813 ServiceEntry
= ServiceEntry
->Flink
;
815 if (CurrentService
->bDeleted
!= FALSE
)
817 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
818 L
"System\\CurrentControlSet\\Services",
822 if (dwError
== ERROR_SUCCESS
)
824 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
825 RegCloseKey(hServicesKey
);
826 if (dwError
== ERROR_SUCCESS
)
828 RemoveEntryList(&CurrentService
->ServiceListEntry
);
829 HeapFree(GetProcessHeap(), 0, CurrentService
);
833 if (dwError
!= ERROR_SUCCESS
)
834 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
842 ScmGetNoInteractiveServicesValue(VOID
)
848 lError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
849 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
853 if (lError
== ERROR_SUCCESS
)
855 dwKeySize
= sizeof(NoInteractiveServices
);
856 lError
= RegQueryValueExW(hKey
,
857 L
"NoInteractiveServices",
860 (LPBYTE
)&NoInteractiveServices
,
868 ScmCreateServiceDatabase(VOID
)
870 WCHAR szSubKey
[MAX_PATH
];
874 DWORD dwSubKeyLength
;
875 FILETIME ftLastChanged
;
878 DPRINT("ScmCreateServiceDatabase() called\n");
880 /* Retrieve the NoInteractiveServies value */
881 ScmGetNoInteractiveServicesValue();
883 /* Create the service group list */
884 dwError
= ScmCreateGroupList();
885 if (dwError
!= ERROR_SUCCESS
)
888 /* Initialize image and service lists */
889 InitializeListHead(&ImageListHead
);
890 InitializeListHead(&ServiceListHead
);
892 /* Initialize the database lock */
893 RtlInitializeResource(&DatabaseLock
);
895 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
896 L
"System\\CurrentControlSet\\Services",
900 if (dwError
!= ERROR_SUCCESS
)
906 dwSubKeyLength
= MAX_PATH
;
907 dwError
= RegEnumKeyExW(hServicesKey
,
915 if (dwError
== ERROR_SUCCESS
&&
918 DPRINT("SubKeyName: '%S'\n", szSubKey
);
920 dwError
= RegOpenKeyExW(hServicesKey
,
925 if (dwError
== ERROR_SUCCESS
)
927 dwError
= CreateServiceListEntry(szSubKey
,
930 RegCloseKey(hServiceKey
);
934 if (dwError
!= ERROR_SUCCESS
)
940 RegCloseKey(hServicesKey
);
942 /* Wait for the LSA server */
945 /* Delete services that are marked for delete */
946 ScmDeleteMarkedServices();
948 DPRINT("ScmCreateServiceDatabase() done\n");
950 return ERROR_SUCCESS
;
955 ScmShutdownServiceDatabase(VOID
)
957 DPRINT("ScmShutdownServiceDatabase() called\n");
959 ScmDeleteMarkedServices();
960 RtlDeleteResource(&DatabaseLock
);
962 DPRINT("ScmShutdownServiceDatabase() done\n");
967 ScmCheckDriver(PSERVICE Service
)
969 OBJECT_ATTRIBUTES ObjectAttributes
;
970 UNICODE_STRING DirName
;
973 POBJECT_DIRECTORY_INFORMATION DirInfo
;
978 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
980 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
982 RtlInitUnicodeString(&DirName
, L
"\\Driver");
984 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
986 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
987 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
990 InitializeObjectAttributes(&ObjectAttributes
,
996 Status
= NtOpenDirectoryObject(&DirHandle
,
997 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
999 if (!NT_SUCCESS(Status
))
1004 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
1005 2 * MAX_PATH
* sizeof(WCHAR
);
1006 DirInfo
= HeapAlloc(GetProcessHeap(),
1013 Status
= NtQueryDirectoryObject(DirHandle
,
1020 if (Status
== STATUS_NO_MORE_ENTRIES
)
1022 /* FIXME: Add current service to 'failed service' list */
1023 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
1027 if (!NT_SUCCESS(Status
))
1030 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
1032 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
1034 DPRINT("Found: '%S' '%wZ'\n",
1035 Service
->lpServiceName
, &DirInfo
->Name
);
1037 /* Mark service as 'running' */
1038 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1039 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1040 Service
->Status
.dwWin32ExitCode
= ERROR_SUCCESS
;
1041 Service
->Status
.dwServiceSpecificExitCode
= 0;
1042 Service
->Status
.dwCheckPoint
= 0;
1043 Service
->Status
.dwWaitHint
= 0;
1045 /* Mark the service group as 'running' */
1046 if (Service
->lpGroup
!= NULL
)
1048 Service
->lpGroup
->ServicesRunning
= TRUE
;
1055 HeapFree(GetProcessHeap(),
1060 return STATUS_SUCCESS
;
1065 ScmGetBootAndSystemDriverState(VOID
)
1067 PLIST_ENTRY ServiceEntry
;
1068 PSERVICE CurrentService
;
1070 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1072 ServiceEntry
= ServiceListHead
.Flink
;
1073 while (ServiceEntry
!= &ServiceListHead
)
1075 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1077 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
1078 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
1081 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
1083 ScmCheckDriver(CurrentService
);
1086 ServiceEntry
= ServiceEntry
->Flink
;
1089 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1094 ScmControlService(HANDLE hControlPipe
,
1096 SERVICE_STATUS_HANDLE hServiceStatus
,
1099 PSCM_CONTROL_PACKET ControlPacket
;
1100 SCM_REPLY_PACKET ReplyPacket
;
1102 DWORD dwWriteCount
= 0;
1103 DWORD dwReadCount
= 0;
1106 DWORD dwError
= ERROR_SUCCESS
;
1108 OVERLAPPED Overlapped
= {0};
1110 DPRINT("ScmControlService() called\n");
1112 /* Acquire the service control critical section, to synchronize requests */
1113 EnterCriticalSection(&ControlServiceCriticalSection
);
1115 /* Calculate the total length of the start command line */
1116 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1117 PacketSize
+= (DWORD
)((wcslen(pServiceName
) + 1) * sizeof(WCHAR
));
1119 ControlPacket
= HeapAlloc(GetProcessHeap(),
1122 if (ControlPacket
== NULL
)
1124 LeaveCriticalSection(&ControlServiceCriticalSection
);
1125 return ERROR_NOT_ENOUGH_MEMORY
;
1128 ControlPacket
->dwSize
= PacketSize
;
1129 ControlPacket
->dwControl
= dwControl
;
1130 ControlPacket
->hServiceStatus
= hServiceStatus
;
1132 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1134 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1135 wcscpy(Ptr
, pServiceName
);
1137 ControlPacket
->dwArgumentsCount
= 0;
1138 ControlPacket
->dwArgumentsOffset
= 0;
1140 bResult
= WriteFile(hControlPipe
,
1145 if (bResult
== FALSE
)
1147 DPRINT("WriteFile() returned FALSE\n");
1149 dwError
= GetLastError();
1150 if (dwError
== ERROR_IO_PENDING
)
1152 DPRINT("dwError: ERROR_IO_PENDING\n");
1154 dwError
= WaitForSingleObject(hControlPipe
,
1156 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1158 if (dwError
== WAIT_TIMEOUT
)
1160 bResult
= CancelIo(hControlPipe
);
1161 if (bResult
== FALSE
)
1163 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1166 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1169 else if (dwError
== WAIT_OBJECT_0
)
1171 bResult
= GetOverlappedResult(hControlPipe
,
1175 if (bResult
== FALSE
)
1177 dwError
= GetLastError();
1178 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1186 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1191 /* Read the reply */
1192 Overlapped
.hEvent
= (HANDLE
) NULL
;
1194 bResult
= ReadFile(hControlPipe
,
1196 sizeof(SCM_REPLY_PACKET
),
1199 if (bResult
== FALSE
)
1201 DPRINT("ReadFile() returned FALSE\n");
1203 dwError
= GetLastError();
1204 if (dwError
== ERROR_IO_PENDING
)
1206 DPRINT("dwError: ERROR_IO_PENDING\n");
1208 dwError
= WaitForSingleObject(hControlPipe
,
1210 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1212 if (dwError
== WAIT_TIMEOUT
)
1214 bResult
= CancelIo(hControlPipe
);
1215 if (bResult
== FALSE
)
1217 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1220 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1223 else if (dwError
== WAIT_OBJECT_0
)
1225 bResult
= GetOverlappedResult(hControlPipe
,
1229 if (bResult
== FALSE
)
1231 dwError
= GetLastError();
1232 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1240 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1246 /* Release the control packet */
1247 HeapFree(GetProcessHeap(),
1251 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1253 dwError
= ReplyPacket
.dwError
;
1256 LeaveCriticalSection(&ControlServiceCriticalSection
);
1258 DPRINT("ScmControlService() done\n");
1265 ScmSendStartCommand(PSERVICE Service
,
1269 DWORD dwError
= ERROR_SUCCESS
;
1270 PSCM_CONTROL_PACKET ControlPacket
;
1271 SCM_REPLY_PACKET ReplyPacket
;
1278 DWORD dwWriteCount
= 0;
1279 DWORD dwReadCount
= 0;
1280 OVERLAPPED Overlapped
= {0};
1282 DPRINT("ScmSendStartCommand() called\n");
1284 /* Calculate the total length of the start command line */
1285 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1286 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1289 * Calculate the required packet size for the start argument vector 'argv',
1290 * composed of the list of pointer offsets, followed by UNICODE strings.
1291 * The strings are stored continuously after the vector of offsets, with
1292 * the offsets being relative to the beginning of the vector, as in the
1293 * following layout (with N == argc):
1294 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1296 if (argc
> 0 && argv
!= NULL
)
1298 PacketSize
= ALIGN_UP(PacketSize
, PWSTR
);
1299 PacketSize
+= (argc
* sizeof(PWSTR
));
1301 DPRINT("Argc: %lu\n", argc
);
1302 for (i
= 0; i
< argc
; i
++)
1304 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1305 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
));
1309 /* Allocate a control packet */
1310 ControlPacket
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, PacketSize
);
1311 if (ControlPacket
== NULL
)
1312 return ERROR_NOT_ENOUGH_MEMORY
;
1314 ControlPacket
->dwSize
= PacketSize
;
1315 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1316 ? SERVICE_CONTROL_START_OWN
1317 : SERVICE_CONTROL_START_SHARE
;
1318 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1320 /* Copy the start command line */
1321 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1322 Ptr
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1323 wcscpy(Ptr
, Service
->lpServiceName
);
1325 ControlPacket
->dwArgumentsCount
= 0;
1326 ControlPacket
->dwArgumentsOffset
= 0;
1328 /* Copy the argument vector */
1329 if (argc
> 0 && argv
!= NULL
)
1331 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1332 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1333 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1335 ControlPacket
->dwArgumentsCount
= argc
;
1336 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1338 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1339 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1341 for (i
= 0; i
< argc
; i
++)
1343 wcscpy(pArgPtr
, argv
[i
]);
1344 pOffPtr
[i
] = (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1345 DPRINT("offset[%lu]: %p\n", i
, pOffPtr
[i
]);
1346 pArgPtr
+= wcslen(argv
[i
]) + 1;
1350 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1355 if (bResult
== FALSE
)
1357 DPRINT("WriteFile() returned FALSE\n");
1359 dwError
= GetLastError();
1360 if (dwError
== ERROR_IO_PENDING
)
1362 DPRINT("dwError: ERROR_IO_PENDING\n");
1364 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1366 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1368 if (dwError
== WAIT_TIMEOUT
)
1370 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1371 if (bResult
== FALSE
)
1373 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1376 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1379 else if (dwError
== WAIT_OBJECT_0
)
1381 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1385 if (bResult
== FALSE
)
1387 dwError
= GetLastError();
1388 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1396 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1401 /* Read the reply */
1402 Overlapped
.hEvent
= (HANDLE
) NULL
;
1404 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1406 sizeof(SCM_REPLY_PACKET
),
1409 if (bResult
== FALSE
)
1411 DPRINT("ReadFile() returned FALSE\n");
1413 dwError
= GetLastError();
1414 if (dwError
== ERROR_IO_PENDING
)
1416 DPRINT("dwError: ERROR_IO_PENDING\n");
1418 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1420 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1422 if (dwError
== WAIT_TIMEOUT
)
1424 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1425 if (bResult
== FALSE
)
1427 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1430 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1433 else if (dwError
== WAIT_OBJECT_0
)
1435 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1439 if (bResult
== FALSE
)
1441 dwError
= GetLastError();
1442 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1450 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1456 /* Release the control packet */
1457 HeapFree(GetProcessHeap(),
1461 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1463 dwError
= ReplyPacket
.dwError
;
1466 DPRINT("ScmSendStartCommand() done\n");
1473 ScmWaitForServiceConnect(PSERVICE Service
)
1476 DWORD dwProcessId
= 0;
1477 DWORD dwError
= ERROR_SUCCESS
;
1479 OVERLAPPED Overlapped
= {0};
1481 LPCWSTR lpLogStrings
[3];
1482 WCHAR szBuffer1
[20];
1483 WCHAR szBuffer2
[20];
1486 DPRINT("ScmWaitForServiceConnect()\n");
1488 Overlapped
.hEvent
= (HANDLE
)NULL
;
1490 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1492 if (bResult
== FALSE
)
1494 DPRINT("ConnectNamedPipe() returned FALSE\n");
1496 dwError
= GetLastError();
1497 if (dwError
== ERROR_IO_PENDING
)
1499 DPRINT("dwError: ERROR_IO_PENDING\n");
1501 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1503 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1505 if (dwError
== WAIT_TIMEOUT
)
1507 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1509 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1510 if (bResult
== FALSE
)
1512 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1516 _ultow(PipeTimeout
, szBuffer1
, 10);
1517 lpLogStrings
[0] = Service
->lpDisplayName
;
1518 lpLogStrings
[1] = szBuffer1
;
1520 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1521 EVENTLOG_ERROR_TYPE
,
1525 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1527 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1529 else if (dwError
== WAIT_OBJECT_0
)
1531 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1535 if (bResult
== FALSE
)
1537 dwError
= GetLastError();
1538 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1544 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1546 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1551 DPRINT("Control pipe connected!\n");
1553 Overlapped
.hEvent
= (HANDLE
) NULL
;
1555 /* Read the process id from pipe */
1556 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1557 (LPVOID
)&dwProcessId
,
1561 if (bResult
== FALSE
)
1563 DPRINT("ReadFile() returned FALSE\n");
1565 dwError
= GetLastError();
1566 if (dwError
== ERROR_IO_PENDING
)
1568 DPRINT("dwError: ERROR_IO_PENDING\n");
1570 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1572 if (dwError
== WAIT_TIMEOUT
)
1574 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1576 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1577 if (bResult
== FALSE
)
1579 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1583 _ultow(PipeTimeout
, szBuffer1
, 10);
1584 lpLogStrings
[0] = szBuffer1
;
1586 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1587 EVENTLOG_ERROR_TYPE
,
1591 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1593 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1595 else if (dwError
== WAIT_OBJECT_0
)
1597 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1599 DPRINT("Process Id: %lu\n", dwProcessId
);
1601 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1605 if (bResult
== FALSE
)
1607 dwError
= GetLastError();
1608 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1615 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1620 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1625 if (dwProcessId
!= Service
->lpImage
->dwProcessId
)
1628 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1629 _ultow(dwProcessId
, szBuffer2
, 10);
1631 lpLogStrings
[0] = Service
->lpDisplayName
;
1632 lpLogStrings
[1] = szBuffer1
;
1633 lpLogStrings
[2] = szBuffer2
;
1635 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1636 EVENTLOG_WARNING_TYPE
,
1641 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1644 DPRINT("ScmWaitForServiceConnect() done\n");
1646 return ERROR_SUCCESS
;
1651 ScmStartUserModeService(PSERVICE Service
,
1655 PROCESS_INFORMATION ProcessInformation
;
1656 STARTUPINFOW StartupInfo
;
1657 LPVOID lpEnvironment
;
1659 DWORD dwError
= ERROR_SUCCESS
;
1661 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1663 /* If the image is already running ... */
1664 if (Service
->lpImage
->dwImageRunCount
> 1)
1666 /* ... just send a start command */
1667 return ScmSendStartCommand(Service
, argc
, argv
);
1670 /* Otherwise start its process */
1671 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1672 StartupInfo
.cb
= sizeof(StartupInfo
);
1673 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1675 /* Use the interactive desktop if the service is interactive */
1676 if ((NoInteractiveServices
== 0) &&
1677 (Service
->Status
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
))
1679 StartupInfo
.dwFlags
|= STARTF_INHERITDESKTOP
;
1680 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
1683 if (Service
->lpImage
->hToken
)
1685 /* User token: Run the service under the user account */
1687 if (!CreateEnvironmentBlock(&lpEnvironment
, Service
->lpImage
->hToken
, FALSE
))
1689 /* We failed, run the service with the current environment */
1690 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1691 GetLastError(), Service
->lpServiceName
);
1692 lpEnvironment
= NULL
;
1695 /* Impersonate the new user */
1696 Result
= ImpersonateLoggedOnUser(Service
->lpImage
->hToken
);
1699 /* Launch the process in the user's logon session */
1700 Result
= CreateProcessAsUserW(Service
->lpImage
->hToken
,
1702 Service
->lpImage
->pszImagePath
,
1706 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1710 &ProcessInformation
);
1712 dwError
= GetLastError();
1714 /* Revert the impersonation */
1719 dwError
= GetLastError();
1720 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError
);
1725 /* No user token: Run the service under the LocalSystem account */
1727 if (!CreateEnvironmentBlock(&lpEnvironment
, NULL
, TRUE
))
1729 /* We failed, run the service with the current environment */
1730 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1731 GetLastError(), Service
->lpServiceName
);
1732 lpEnvironment
= NULL
;
1735 Result
= CreateProcessW(NULL
,
1736 Service
->lpImage
->pszImagePath
,
1740 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1744 &ProcessInformation
);
1746 dwError
= GetLastError();
1750 DestroyEnvironmentBlock(lpEnvironment
);
1754 DPRINT1("Starting '%S' failed with error %d\n",
1755 Service
->lpServiceName
, dwError
);
1759 DPRINT("Process Id: %lu Handle %p\n",
1760 ProcessInformation
.dwProcessId
,
1761 ProcessInformation
.hProcess
);
1762 DPRINT("Thread Id: %lu Handle %p\n",
1763 ProcessInformation
.dwThreadId
,
1764 ProcessInformation
.hThread
);
1766 /* Get the process handle and ID */
1767 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1768 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1770 /* Resume the main thread and close its handle */
1771 ResumeThread(ProcessInformation
.hThread
);
1772 CloseHandle(ProcessInformation
.hThread
);
1774 /* Connect control pipe */
1775 dwError
= ScmWaitForServiceConnect(Service
);
1776 if (dwError
!= ERROR_SUCCESS
)
1778 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1779 Service
->lpImage
->dwProcessId
= 0;
1783 /* Send the start command */
1784 return ScmSendStartCommand(Service
, argc
, argv
);
1789 ScmLoadService(PSERVICE Service
,
1793 PSERVICE_GROUP Group
= Service
->lpGroup
;
1794 DWORD dwError
= ERROR_SUCCESS
;
1795 LPCWSTR lpLogStrings
[2];
1796 WCHAR szLogBuffer
[80];
1798 DPRINT("ScmLoadService() called\n");
1799 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1801 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1803 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1804 return ERROR_SERVICE_ALREADY_RUNNING
;
1807 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1809 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1811 /* Start the driver */
1812 dwError
= ScmStartDriver(Service
);
1814 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1816 /* Start user-mode service */
1817 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1818 if (dwError
== ERROR_SUCCESS
)
1820 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1821 if (dwError
== ERROR_SUCCESS
)
1823 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1824 Service
->Status
.dwControlsAccepted
= 0;
1828 Service
->lpImage
->dwImageRunCount
--;
1829 if (Service
->lpImage
->dwImageRunCount
== 0)
1831 ScmRemoveServiceImage(Service
->lpImage
);
1832 Service
->lpImage
= NULL
;
1838 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
1840 if (dwError
== ERROR_SUCCESS
)
1844 Group
->ServicesRunning
= TRUE
;
1847 /* Log a successful service start */
1848 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
1849 lpLogStrings
[0] = Service
->lpDisplayName
;
1850 lpLogStrings
[1] = szLogBuffer
;
1852 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1853 EVENTLOG_INFORMATION_TYPE
,
1859 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1861 /* Log a failed service start */
1862 StringCchPrintfW(szLogBuffer
, ARRAYSIZE(szLogBuffer
),
1864 lpLogStrings
[0] = Service
->lpServiceName
;
1865 lpLogStrings
[1] = szLogBuffer
;
1866 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
1867 EVENTLOG_ERROR_TYPE
,
1873 switch (Service
->dwErrorControl
)
1875 case SERVICE_ERROR_SEVERE
:
1876 if (IsLastKnownGood
== FALSE
)
1878 /* FIXME: Boot last known good configuration */
1882 case SERVICE_ERROR_CRITICAL
:
1883 if (IsLastKnownGood
== FALSE
)
1885 /* FIXME: Boot last known good configuration */
1901 ScmStartService(PSERVICE Service
,
1905 DWORD dwError
= ERROR_SUCCESS
;
1906 SC_RPC_LOCK Lock
= NULL
;
1908 DPRINT("ScmStartService() called\n");
1909 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1911 /* Acquire the service control critical section, to synchronize starts */
1912 EnterCriticalSection(&ControlServiceCriticalSection
);
1915 * Acquire the user service start lock while the service is starting, if
1916 * needed (i.e. if we are not starting it during the initialization phase).
1917 * If we don't success, bail out.
1921 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
1922 if (dwError
!= ERROR_SUCCESS
) goto done
;
1925 /* Really start the service */
1926 dwError
= ScmLoadService(Service
, argc
, argv
);
1928 /* Release the service start lock, if needed, and the critical section */
1929 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
1932 LeaveCriticalSection(&ControlServiceCriticalSection
);
1934 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1941 ScmAutoStartServices(VOID
)
1944 PLIST_ENTRY GroupEntry
;
1945 PLIST_ENTRY ServiceEntry
;
1946 PSERVICE_GROUP CurrentGroup
;
1947 PSERVICE CurrentService
;
1948 WCHAR szSafeBootServicePath
[MAX_PATH
];
1949 DWORD SafeBootEnabled
;
1955 * This function MUST be called ONLY at initialization time.
1956 * Therefore, no need to acquire the user service start lock.
1958 ASSERT(ScmInitialize
);
1960 /* Retrieve the SafeBoot parameter */
1961 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1962 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
1966 if (dwError
== ERROR_SUCCESS
)
1968 dwKeySize
= sizeof(SafeBootEnabled
);
1969 dwError
= RegQueryValueExW(hKey
,
1973 (LPBYTE
)&SafeBootEnabled
,
1978 /* Default to Normal boot if the value doesn't exist */
1979 if (dwError
!= ERROR_SUCCESS
)
1980 SafeBootEnabled
= 0;
1982 /* Acquire the service control critical section, to synchronize starts */
1983 EnterCriticalSection(&ControlServiceCriticalSection
);
1985 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1986 ServiceEntry
= ServiceListHead
.Flink
;
1987 while (ServiceEntry
!= &ServiceListHead
)
1989 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1991 /* Build the safe boot path */
1992 StringCchCopyW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
1993 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1995 switch (SafeBootEnabled
)
1997 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
2000 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2005 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2010 if (SafeBootEnabled
!= 0)
2012 /* If key does not exist then do not assume safe mode */
2013 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2014 szSafeBootServicePath
,
2018 if (dwError
== ERROR_SUCCESS
)
2022 /* Finish Safe Boot path off */
2023 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2024 CurrentService
->lpServiceName
);
2026 /* Check that the key is in the Safe Boot path */
2027 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2028 szSafeBootServicePath
,
2032 if (dwError
!= ERROR_SUCCESS
)
2034 /* Mark service as visited so it is not auto-started */
2035 CurrentService
->ServiceVisited
= TRUE
;
2039 /* Must be auto-started in safe mode - mark as unvisited */
2041 CurrentService
->ServiceVisited
= FALSE
;
2046 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2047 CurrentService
->ServiceVisited
= FALSE
;
2051 ServiceEntry
= ServiceEntry
->Flink
;
2054 /* Start all services which are members of an existing group */
2055 GroupEntry
= GroupListHead
.Flink
;
2056 while (GroupEntry
!= &GroupListHead
)
2058 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
2060 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
2062 /* Start all services witch have a valid tag */
2063 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
2065 ServiceEntry
= ServiceListHead
.Flink
;
2066 while (ServiceEntry
!= &ServiceListHead
)
2068 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2070 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2071 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2072 (CurrentService
->ServiceVisited
== FALSE
) &&
2073 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
2075 CurrentService
->ServiceVisited
= TRUE
;
2076 ScmLoadService(CurrentService
, 0, NULL
);
2079 ServiceEntry
= ServiceEntry
->Flink
;
2083 /* Start all services which have an invalid tag or which do not have a tag */
2084 ServiceEntry
= ServiceListHead
.Flink
;
2085 while (ServiceEntry
!= &ServiceListHead
)
2087 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2089 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2090 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2091 (CurrentService
->ServiceVisited
== FALSE
))
2093 CurrentService
->ServiceVisited
= TRUE
;
2094 ScmLoadService(CurrentService
, 0, NULL
);
2097 ServiceEntry
= ServiceEntry
->Flink
;
2100 GroupEntry
= GroupEntry
->Flink
;
2103 /* Start all services which are members of any non-existing group */
2104 ServiceEntry
= ServiceListHead
.Flink
;
2105 while (ServiceEntry
!= &ServiceListHead
)
2107 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2109 if ((CurrentService
->lpGroup
!= NULL
) &&
2110 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2111 (CurrentService
->ServiceVisited
== FALSE
))
2113 CurrentService
->ServiceVisited
= TRUE
;
2114 ScmLoadService(CurrentService
, 0, NULL
);
2117 ServiceEntry
= ServiceEntry
->Flink
;
2120 /* Start all services which are not a member of any group */
2121 ServiceEntry
= ServiceListHead
.Flink
;
2122 while (ServiceEntry
!= &ServiceListHead
)
2124 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2126 if ((CurrentService
->lpGroup
== NULL
) &&
2127 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2128 (CurrentService
->ServiceVisited
== FALSE
))
2130 CurrentService
->ServiceVisited
= TRUE
;
2131 ScmLoadService(CurrentService
, 0, NULL
);
2134 ServiceEntry
= ServiceEntry
->Flink
;
2137 /* Clear 'ServiceVisited' flag again */
2138 ServiceEntry
= ServiceListHead
.Flink
;
2139 while (ServiceEntry
!= &ServiceListHead
)
2141 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2142 CurrentService
->ServiceVisited
= FALSE
;
2143 ServiceEntry
= ServiceEntry
->Flink
;
2146 /* Release the critical section */
2147 LeaveCriticalSection(&ControlServiceCriticalSection
);
2152 ScmAutoShutdownServices(VOID
)
2154 PLIST_ENTRY ServiceEntry
;
2155 PSERVICE CurrentService
;
2157 DPRINT("ScmAutoShutdownServices() called\n");
2159 /* Lock the service database exclusively */
2160 ScmLockDatabaseExclusive();
2162 ServiceEntry
= ServiceListHead
.Flink
;
2163 while (ServiceEntry
!= &ServiceListHead
)
2165 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2167 if ((CurrentService
->Status
.dwControlsAccepted
& SERVICE_ACCEPT_SHUTDOWN
) &&
2168 (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2169 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
))
2171 /* Send the shutdown notification */
2172 DPRINT("Shutdown service: %S\n", CurrentService
->lpServiceName
);
2173 ScmControlService(CurrentService
->lpImage
->hControlPipe
,
2174 CurrentService
->lpServiceName
,
2175 (SERVICE_STATUS_HANDLE
)CurrentService
,
2176 SERVICE_CONTROL_SHUTDOWN
);
2179 ServiceEntry
= ServiceEntry
->Flink
;
2182 /* Unlock the service database */
2183 ScmUnlockDatabase();
2185 DPRINT("ScmAutoShutdownServices() done\n");
2190 ScmLockDatabaseExclusive(VOID
)
2192 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2197 ScmLockDatabaseShared(VOID
)
2199 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2204 ScmUnlockDatabase(VOID
)
2206 RtlReleaseResource(&DatabaseLock
);
2211 ScmInitNamedPipeCriticalSection(VOID
)
2217 InitializeCriticalSection(&ControlServiceCriticalSection
);
2219 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2220 L
"SYSTEM\\CurrentControlSet\\Control",
2224 if (dwError
== ERROR_SUCCESS
)
2226 dwKeySize
= sizeof(PipeTimeout
);
2227 RegQueryValueExW(hKey
,
2228 L
"ServicesPipeTimeout",
2231 (LPBYTE
)&PipeTimeout
,
2239 ScmDeleteNamedPipeCriticalSection(VOID
)
2241 DeleteCriticalSection(&ControlServiceCriticalSection
);