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 *****************************************************************/
24 /* GLOBALS *******************************************************************/
26 LIST_ENTRY ImageListHead
;
27 LIST_ENTRY ServiceListHead
;
29 static RTL_RESOURCE DatabaseLock
;
30 static DWORD ResumeCount
= 1;
31 static DWORD NoInteractiveServices
= 0;
33 /* The critical section synchronizes service control requests */
34 static CRITICAL_SECTION ControlServiceCriticalSection
;
35 static DWORD PipeTimeout
= 30000; /* 30 Seconds */
38 /* FUNCTIONS *****************************************************************/
41 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
43 WCHAR szControlPipeName
[MAX_PATH
+ 1];
44 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
45 DWORD ServiceCurrent
= 0;
50 /* Get the service number */
51 /* TODO: Create registry entry with correct write access */
52 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
53 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
59 if (dwError
!= ERROR_SUCCESS
)
61 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
65 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
67 dwKeySize
= sizeof(DWORD
);
68 dwError
= RegQueryValueExW(hServiceCurrentKey
,
69 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
71 if (dwError
!= ERROR_SUCCESS
)
73 RegCloseKey(hServiceCurrentKey
);
74 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
81 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
83 RegCloseKey(hServiceCurrentKey
);
85 if (dwError
!= ERROR_SUCCESS
)
87 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
91 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
92 StringCchPrintfW(szControlPipeName
, ARRAYSIZE(szControlPipeName
),
93 L
"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent
);
95 DPRINT("PipeName: %S\n", szControlPipeName
);
97 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
98 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
99 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
105 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
106 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
108 DPRINT1("Failed to create control pipe!\n");
109 return GetLastError();
112 return ERROR_SUCCESS
;
116 static PSERVICE_IMAGE
117 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
119 PLIST_ENTRY ImageEntry
;
120 PSERVICE_IMAGE CurrentImage
;
122 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
124 ImageEntry
= ImageListHead
.Flink
;
125 while (ImageEntry
!= &ImageListHead
)
127 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
130 if (_wcsicmp(CurrentImage
->pszImagePath
, lpImagePath
) == 0)
132 DPRINT("Found image: '%S'\n", CurrentImage
->pszImagePath
);
136 ImageEntry
= ImageEntry
->Flink
;
139 DPRINT("Couldn't find a matching image\n");
148 ScmIsSameServiceAccount(
149 _In_ PCWSTR pszAccountName1
,
150 _In_ PCWSTR pszAccountName2
)
152 if (pszAccountName1
== NULL
&& pszAccountName2
== NULL
)
155 if (pszAccountName1
== NULL
&& pszAccountName2
&& wcscmp(pszAccountName2
, L
"LocalSystem") == 0)
158 if (pszAccountName2
== NULL
&& pszAccountName1
&& wcscmp(pszAccountName1
, L
"LocalSystem") == 0)
161 if (pszAccountName1
&& pszAccountName2
&& wcscmp(pszAccountName1
, pszAccountName2
) == 0)
170 ScmIsLocalSystemAccount(
171 _In_ PCWSTR pszAccountName
)
173 if (pszAccountName
== NULL
||
174 wcscmp(pszAccountName
, L
"LocalSystem") == 0)
184 IN PSERVICE pService
,
185 IN PSERVICE_IMAGE pImage
)
187 DWORD dwError
= ERROR_SUCCESS
;
188 PROFILEINFOW ProfileInfo
;
189 PWSTR pszUserName
= NULL
;
190 PWSTR pszDomainName
= NULL
;
191 PWSTR pszPassword
= NULL
;
194 DPRINT("ScmLogonService(%p %p)\n", pService
, pImage
);
195 DPRINT("Service %S\n", pService
->lpServiceName
);
197 if (ScmIsLocalSystemAccount(pImage
->pszAccountName
))
198 return ERROR_SUCCESS
;
200 /* Get the user and domain names */
201 ptr
= wcschr(pImage
->pszAccountName
, L
'\\');
205 pszUserName
= ptr
+ 1;
206 pszDomainName
= pImage
->pszAccountName
;
210 // ERROR_INVALID_SERVICE_ACCOUNT
211 pszUserName
= pImage
->pszAccountName
;
212 pszDomainName
= NULL
;
215 /* Build the service 'password' */
216 pszPassword
= HeapAlloc(GetProcessHeap(),
218 (wcslen(pService
->lpServiceName
) + 5) * sizeof(WCHAR
));
219 if (pszPassword
== NULL
)
221 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
225 wcscpy(pszPassword
, L
"_SC_");
226 wcscat(pszPassword
, pService
->lpServiceName
);
228 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName
, pszUserName
, pszPassword
);
230 /* Do the service logon */
231 if (!LogonUserW(pszUserName
,
234 LOGON32_LOGON_SERVICE
,
235 LOGON32_PROVIDER_DEFAULT
,
238 dwError
= GetLastError();
239 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError
);
241 /* Normalize the returned error */
242 dwError
= ERROR_SERVICE_LOGON_FAILED
;
246 /* Load the user profile; the per-user environment variables are thus correctly initialized */
247 ZeroMemory(&ProfileInfo
, sizeof(ProfileInfo
));
248 ProfileInfo
.dwSize
= sizeof(ProfileInfo
);
249 ProfileInfo
.dwFlags
= PI_NOUI
;
250 ProfileInfo
.lpUserName
= pszUserName
;
251 // ProfileInfo.lpProfilePath = NULL;
252 // ProfileInfo.lpDefaultPath = NULL;
253 // ProfileInfo.lpServerName = NULL;
254 // ProfileInfo.lpPolicyPath = NULL;
255 // ProfileInfo.hProfile = NULL;
257 if (!LoadUserProfileW(pImage
->hToken
, &ProfileInfo
))
259 dwError
= GetLastError();
260 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError
);
264 pImage
->hProfile
= ProfileInfo
.hProfile
;
267 if (pszPassword
!= NULL
)
268 HeapFree(GetProcessHeap(), 0, pszPassword
);
278 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
280 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
281 UNICODE_STRING ImagePath
;
282 UNICODE_STRING ObjectName
;
283 PSERVICE_IMAGE pServiceImage
= NULL
;
285 DWORD dwError
= ERROR_SUCCESS
;
289 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
291 RtlInitUnicodeString(&ImagePath
, NULL
);
292 RtlInitUnicodeString(&ObjectName
, NULL
);
294 /* Get service data */
295 RtlZeroMemory(&QueryTable
,
298 QueryTable
[0].Name
= L
"ImagePath";
299 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
300 QueryTable
[0].EntryContext
= &ImagePath
;
301 QueryTable
[1].Name
= L
"ObjectName";
302 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
303 QueryTable
[1].EntryContext
= &ObjectName
;
305 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
306 pService
->lpServiceName
,
310 if (!NT_SUCCESS(Status
))
312 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
313 return RtlNtStatusToDosError(Status
);
316 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
317 DPRINT("ObjectName: '%wZ'\n", &ObjectName
);
319 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
320 if (pServiceImage
== NULL
)
322 dwRecordSize
= sizeof(SERVICE_IMAGE
) +
323 ImagePath
.Length
+ sizeof(WCHAR
) +
324 ((ObjectName
.Length
!= 0) ? (ObjectName
.Length
+ sizeof(WCHAR
)) : 0);
326 /* Create a new service image */
327 pServiceImage
= HeapAlloc(GetProcessHeap(),
330 if (pServiceImage
== NULL
)
332 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
336 pServiceImage
->dwImageRunCount
= 1;
337 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
338 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
340 pString
= (PWSTR
)((INT_PTR
)pServiceImage
+ sizeof(SERVICE_IMAGE
));
342 /* Set the image path */
343 pServiceImage
->pszImagePath
= pString
;
344 wcscpy(pServiceImage
->pszImagePath
,
347 /* Set the account name */
348 if (ObjectName
.Length
> 0)
350 pString
= pString
+ wcslen(pString
) + 1;
352 pServiceImage
->pszAccountName
= pString
;
353 wcscpy(pServiceImage
->pszAccountName
,
358 dwError
= ScmLogonService(pService
, pServiceImage
);
359 if (dwError
!= ERROR_SUCCESS
)
361 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError
);
363 /* Release the service image */
364 HeapFree(GetProcessHeap(), 0, pServiceImage
);
369 /* Create the control pipe */
370 dwError
= ScmCreateNewControlPipe(pServiceImage
);
371 if (dwError
!= ERROR_SUCCESS
)
373 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError
);
375 /* Unload the user profile */
376 if (pServiceImage
->hProfile
!= NULL
)
377 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
379 /* Close the logon token */
380 if (pServiceImage
->hToken
!= NULL
)
381 CloseHandle(pServiceImage
->hToken
);
383 /* Release the service image */
384 HeapFree(GetProcessHeap(), 0, pServiceImage
);
389 /* FIXME: Add more initialization code here */
392 /* Append service record */
393 InsertTailList(&ImageListHead
,
394 &pServiceImage
->ImageListEntry
);
398 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
400 /* Fail if services in an image use different accounts */
401 if (!ScmIsSameServiceAccount(pServiceImage
->pszAccountName
, ObjectName
.Buffer
))
403 dwError
= ERROR_DIFFERENT_SERVICE_ACCOUNT
;
407 /* Increment the run counter */
408 pServiceImage
->dwImageRunCount
++;
411 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage
->pszImagePath
);
412 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage
->pszAccountName
);
413 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
415 /* Link the service image to the service */
416 pService
->lpImage
= pServiceImage
;
419 RtlFreeUnicodeString(&ObjectName
);
420 RtlFreeUnicodeString(&ImagePath
);
422 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
429 ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage
)
431 DPRINT1("ScmRemoveServiceImage() called\n");
433 /* FIXME: Terminate the process */
435 /* Remove the service image from the list */
436 RemoveEntryList(&pServiceImage
->ImageListEntry
);
438 /* Close the process handle */
439 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
440 CloseHandle(pServiceImage
->hProcess
);
442 /* Close the control pipe */
443 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
444 CloseHandle(pServiceImage
->hControlPipe
);
446 /* Unload the user profile */
447 if (pServiceImage
->hProfile
!= NULL
)
448 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
450 /* Close the logon token */
451 if (pServiceImage
->hToken
!= NULL
)
452 CloseHandle(pServiceImage
->hToken
);
454 /* Release the service image */
455 HeapFree(GetProcessHeap(), 0, pServiceImage
);
460 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
462 PLIST_ENTRY ServiceEntry
;
463 PSERVICE CurrentService
;
465 DPRINT("ScmGetServiceEntryByName() called\n");
467 ServiceEntry
= ServiceListHead
.Flink
;
468 while (ServiceEntry
!= &ServiceListHead
)
470 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
473 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
475 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
476 return CurrentService
;
479 ServiceEntry
= ServiceEntry
->Flink
;
482 DPRINT("Couldn't find a matching service\n");
489 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
491 PLIST_ENTRY ServiceEntry
;
492 PSERVICE CurrentService
;
494 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
496 ServiceEntry
= ServiceListHead
.Flink
;
497 while (ServiceEntry
!= &ServiceListHead
)
499 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
502 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
504 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
505 return CurrentService
;
508 ServiceEntry
= ServiceEntry
->Flink
;
511 DPRINT("Couldn't find a matching service\n");
518 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
520 PLIST_ENTRY ServiceEntry
;
521 PSERVICE CurrentService
;
523 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
525 ServiceEntry
= ServiceListHead
.Flink
;
526 while (ServiceEntry
!= &ServiceListHead
)
528 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
531 if (CurrentService
->dwResumeCount
> dwResumeCount
)
533 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
534 return CurrentService
;
537 ServiceEntry
= ServiceEntry
->Flink
;
540 DPRINT("Couldn't find a matching service\n");
547 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
548 PSERVICE
*lpServiceRecord
,
552 PSERVICE lpService
= NULL
;
554 DPRINT("Service: '%S'\n", lpServiceName
);
556 /* Allocate service entry */
557 lpService
= HeapAlloc(GetProcessHeap(),
559 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
560 if (lpService
== NULL
)
561 return ERROR_NOT_ENOUGH_MEMORY
;
563 *lpServiceRecord
= lpService
;
565 /* Copy service name */
566 wcscpy(lpService
->szServiceName
, lpServiceName
);
567 lpService
->lpServiceName
= lpService
->szServiceName
;
568 lpService
->lpDisplayName
= lpService
->lpServiceName
;
570 /* Set the start type */
571 lpService
->dwStartType
= dwStartType
;
573 /* Set the resume count */
574 lpService
->dwResumeCount
= ResumeCount
++;
576 /* Append service record */
577 InsertTailList(&ServiceListHead
,
578 &lpService
->ServiceListEntry
);
580 /* Initialize the service status */
581 lpService
->Status
.dwServiceType
= dwServiceType
;
582 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
583 lpService
->Status
.dwControlsAccepted
= 0;
584 lpService
->Status
.dwWin32ExitCode
=
585 (dwStartType
== SERVICE_DISABLED
) ? ERROR_SERVICE_DISABLED
: ERROR_SERVICE_NEVER_STARTED
;
586 lpService
->Status
.dwServiceSpecificExitCode
= 0;
587 lpService
->Status
.dwCheckPoint
= 0;
588 lpService
->Status
.dwWaitHint
=
589 (dwServiceType
& SERVICE_DRIVER
) ? 0 : 2000; /* 2 seconds */
591 return ERROR_SUCCESS
;
596 ScmDeleteServiceRecord(PSERVICE lpService
)
598 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
600 /* Delete the display name */
601 if (lpService
->lpDisplayName
!= NULL
&&
602 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
603 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
605 /* Dereference the service image */
606 if (lpService
->lpImage
)
608 lpService
->lpImage
->dwImageRunCount
--;
610 if (lpService
->lpImage
->dwImageRunCount
== 0)
612 ScmRemoveServiceImage(lpService
->lpImage
);
613 lpService
->lpImage
= NULL
;
617 /* Decrement the group reference counter */
618 ScmSetServiceGroup(lpService
, NULL
);
620 /* Release the SecurityDescriptor */
621 if (lpService
->pSecurityDescriptor
!= NULL
)
622 HeapFree(GetProcessHeap(), 0, lpService
->pSecurityDescriptor
);
624 /* Remove the Service from the List */
625 RemoveEntryList(&lpService
->ServiceListEntry
);
627 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
629 /* Delete the service record */
630 HeapFree(GetProcessHeap(), 0, lpService
);
637 CreateServiceListEntry(LPCWSTR lpServiceName
,
640 PSERVICE lpService
= NULL
;
641 LPWSTR lpDisplayName
= NULL
;
642 LPWSTR lpGroup
= NULL
;
647 DWORD dwErrorControl
;
650 DPRINT("Service: '%S'\n", lpServiceName
);
651 if (*lpServiceName
== L
'{')
652 return ERROR_SUCCESS
;
654 dwSize
= sizeof(DWORD
);
655 dwError
= RegQueryValueExW(hServiceKey
,
659 (LPBYTE
)&dwServiceType
,
661 if (dwError
!= ERROR_SUCCESS
)
662 return ERROR_SUCCESS
;
664 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
665 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
666 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
667 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
668 return ERROR_SUCCESS
;
670 DPRINT("Service type: %lx\n", dwServiceType
);
672 dwSize
= sizeof(DWORD
);
673 dwError
= RegQueryValueExW(hServiceKey
,
677 (LPBYTE
)&dwStartType
,
679 if (dwError
!= ERROR_SUCCESS
)
680 return ERROR_SUCCESS
;
682 DPRINT("Start type: %lx\n", dwStartType
);
684 dwSize
= sizeof(DWORD
);
685 dwError
= RegQueryValueExW(hServiceKey
,
689 (LPBYTE
)&dwErrorControl
,
691 if (dwError
!= ERROR_SUCCESS
)
692 return ERROR_SUCCESS
;
694 DPRINT("Error control: %lx\n", dwErrorControl
);
696 dwError
= RegQueryValueExW(hServiceKey
,
702 if (dwError
!= ERROR_SUCCESS
)
705 DPRINT("Tag: %lx\n", dwTagId
);
707 dwError
= ScmReadString(hServiceKey
,
710 if (dwError
!= ERROR_SUCCESS
)
713 DPRINT("Group: %S\n", lpGroup
);
715 dwError
= ScmReadString(hServiceKey
,
718 if (dwError
!= ERROR_SUCCESS
)
719 lpDisplayName
= NULL
;
721 DPRINT("Display name: %S\n", lpDisplayName
);
723 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
727 if (dwError
!= ERROR_SUCCESS
)
730 lpService
->dwErrorControl
= dwErrorControl
;
731 lpService
->dwTag
= dwTagId
;
735 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
736 if (dwError
!= ERROR_SUCCESS
)
740 if (lpDisplayName
!= NULL
)
742 lpService
->lpDisplayName
= lpDisplayName
;
743 lpDisplayName
= NULL
;
746 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
747 if (lpService
->lpGroup
!= NULL
)
749 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
751 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
752 lpService
->dwStartType
,
753 lpService
->Status
.dwServiceType
,
755 lpService
->dwErrorControl
);
757 if (ScmIsDeleteFlagSet(hServiceKey
))
758 lpService
->bDeleted
= TRUE
;
760 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
762 dwError
= ScmReadSecurityDescriptor(hServiceKey
,
763 &lpService
->pSecurityDescriptor
);
764 if (dwError
!= ERROR_SUCCESS
)
767 /* Assing the default security descriptor if the security descriptor cannot be read */
768 if (lpService
->pSecurityDescriptor
== NULL
)
770 DPRINT("No security descriptor found! Assign default security descriptor!\n");
771 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
772 if (dwError
!= ERROR_SUCCESS
)
775 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
776 lpService
->pSecurityDescriptor
);
777 if (dwError
!= ERROR_SUCCESS
)
784 HeapFree(GetProcessHeap(), 0, lpGroup
);
786 if (lpDisplayName
!= NULL
)
787 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
789 if (lpService
!= NULL
)
791 ASSERT(lpService
->lpImage
== NULL
);
799 ScmDeleteMarkedServices(VOID
)
801 PLIST_ENTRY ServiceEntry
;
802 PSERVICE CurrentService
;
806 ServiceEntry
= ServiceListHead
.Flink
;
807 while (ServiceEntry
!= &ServiceListHead
)
809 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
811 ServiceEntry
= ServiceEntry
->Flink
;
813 if (CurrentService
->bDeleted
!= FALSE
)
815 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
816 L
"System\\CurrentControlSet\\Services",
820 if (dwError
== ERROR_SUCCESS
)
822 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
823 RegCloseKey(hServicesKey
);
824 if (dwError
== ERROR_SUCCESS
)
826 RemoveEntryList(&CurrentService
->ServiceListEntry
);
827 HeapFree(GetProcessHeap(), 0, CurrentService
);
831 if (dwError
!= ERROR_SUCCESS
)
832 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
840 ScmGetNoInteractiveServicesValue(VOID
)
846 lError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
847 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
851 if (lError
== ERROR_SUCCESS
)
853 dwKeySize
= sizeof(NoInteractiveServices
);
854 lError
= RegQueryValueExW(hKey
,
855 L
"NoInteractiveServices",
858 (LPBYTE
)&NoInteractiveServices
,
866 ScmCreateServiceDatabase(VOID
)
868 WCHAR szSubKey
[MAX_PATH
];
872 DWORD dwSubKeyLength
;
873 FILETIME ftLastChanged
;
876 DPRINT("ScmCreateServiceDatabase() called\n");
878 /* Retrieve the NoInteractiveServies value */
879 ScmGetNoInteractiveServicesValue();
881 /* Create the service group list */
882 dwError
= ScmCreateGroupList();
883 if (dwError
!= ERROR_SUCCESS
)
886 /* Initialize image and service lists */
887 InitializeListHead(&ImageListHead
);
888 InitializeListHead(&ServiceListHead
);
890 /* Initialize the database lock */
891 RtlInitializeResource(&DatabaseLock
);
893 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
894 L
"System\\CurrentControlSet\\Services",
898 if (dwError
!= ERROR_SUCCESS
)
904 dwSubKeyLength
= MAX_PATH
;
905 dwError
= RegEnumKeyExW(hServicesKey
,
913 if (dwError
== ERROR_SUCCESS
&&
916 DPRINT("SubKeyName: '%S'\n", szSubKey
);
918 dwError
= RegOpenKeyExW(hServicesKey
,
923 if (dwError
== ERROR_SUCCESS
)
925 dwError
= CreateServiceListEntry(szSubKey
,
928 RegCloseKey(hServiceKey
);
932 if (dwError
!= ERROR_SUCCESS
)
938 RegCloseKey(hServicesKey
);
940 /* Wait for the LSA server */
943 /* Delete services that are marked for delete */
944 ScmDeleteMarkedServices();
946 DPRINT("ScmCreateServiceDatabase() done\n");
948 return ERROR_SUCCESS
;
953 ScmShutdownServiceDatabase(VOID
)
955 DPRINT("ScmShutdownServiceDatabase() called\n");
957 ScmDeleteMarkedServices();
958 RtlDeleteResource(&DatabaseLock
);
960 DPRINT("ScmShutdownServiceDatabase() done\n");
965 ScmCheckDriver(PSERVICE Service
)
967 OBJECT_ATTRIBUTES ObjectAttributes
;
968 UNICODE_STRING DirName
;
971 POBJECT_DIRECTORY_INFORMATION DirInfo
;
976 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
978 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
980 RtlInitUnicodeString(&DirName
, L
"\\Driver");
982 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
984 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
985 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
988 InitializeObjectAttributes(&ObjectAttributes
,
994 Status
= NtOpenDirectoryObject(&DirHandle
,
995 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
997 if (!NT_SUCCESS(Status
))
1002 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
1003 2 * MAX_PATH
* sizeof(WCHAR
);
1004 DirInfo
= HeapAlloc(GetProcessHeap(),
1011 Status
= NtQueryDirectoryObject(DirHandle
,
1018 if (Status
== STATUS_NO_MORE_ENTRIES
)
1020 /* FIXME: Add current service to 'failed service' list */
1021 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
1025 if (!NT_SUCCESS(Status
))
1028 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
1030 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
1032 DPRINT("Found: '%S' '%wZ'\n",
1033 Service
->lpServiceName
, &DirInfo
->Name
);
1035 /* Mark service as 'running' */
1036 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1037 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1038 Service
->Status
.dwWin32ExitCode
= ERROR_SUCCESS
;
1039 Service
->Status
.dwServiceSpecificExitCode
= 0;
1040 Service
->Status
.dwCheckPoint
= 0;
1041 Service
->Status
.dwWaitHint
= 0;
1043 /* Mark the service group as 'running' */
1044 if (Service
->lpGroup
!= NULL
)
1046 Service
->lpGroup
->ServicesRunning
= TRUE
;
1053 HeapFree(GetProcessHeap(),
1058 return STATUS_SUCCESS
;
1063 ScmGetBootAndSystemDriverState(VOID
)
1065 PLIST_ENTRY ServiceEntry
;
1066 PSERVICE CurrentService
;
1068 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1070 ServiceEntry
= ServiceListHead
.Flink
;
1071 while (ServiceEntry
!= &ServiceListHead
)
1073 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1075 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
1076 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
1079 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
1081 ScmCheckDriver(CurrentService
);
1084 ServiceEntry
= ServiceEntry
->Flink
;
1087 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1092 ScmControlService(HANDLE hControlPipe
,
1094 SERVICE_STATUS_HANDLE hServiceStatus
,
1097 PSCM_CONTROL_PACKET ControlPacket
;
1098 SCM_REPLY_PACKET ReplyPacket
;
1100 DWORD dwWriteCount
= 0;
1101 DWORD dwReadCount
= 0;
1104 DWORD dwError
= ERROR_SUCCESS
;
1106 OVERLAPPED Overlapped
= {0};
1108 DPRINT("ScmControlService() called\n");
1110 /* Acquire the service control critical section, to synchronize requests */
1111 EnterCriticalSection(&ControlServiceCriticalSection
);
1113 /* Calculate the total length of the start command line */
1114 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1115 PacketSize
+= (DWORD
)((wcslen(pServiceName
) + 1) * sizeof(WCHAR
));
1117 ControlPacket
= HeapAlloc(GetProcessHeap(),
1120 if (ControlPacket
== NULL
)
1122 LeaveCriticalSection(&ControlServiceCriticalSection
);
1123 return ERROR_NOT_ENOUGH_MEMORY
;
1126 ControlPacket
->dwSize
= PacketSize
;
1127 ControlPacket
->dwControl
= dwControl
;
1128 ControlPacket
->hServiceStatus
= hServiceStatus
;
1130 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1132 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1133 wcscpy(Ptr
, pServiceName
);
1135 ControlPacket
->dwArgumentsCount
= 0;
1136 ControlPacket
->dwArgumentsOffset
= 0;
1138 bResult
= WriteFile(hControlPipe
,
1143 if (bResult
== FALSE
)
1145 DPRINT("WriteFile() returned FALSE\n");
1147 dwError
= GetLastError();
1148 if (dwError
== ERROR_IO_PENDING
)
1150 DPRINT("dwError: ERROR_IO_PENDING\n");
1152 dwError
= WaitForSingleObject(hControlPipe
,
1154 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1156 if (dwError
== WAIT_TIMEOUT
)
1158 bResult
= CancelIo(hControlPipe
);
1159 if (bResult
== FALSE
)
1161 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1164 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1167 else if (dwError
== WAIT_OBJECT_0
)
1169 bResult
= GetOverlappedResult(hControlPipe
,
1173 if (bResult
== FALSE
)
1175 dwError
= GetLastError();
1176 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1184 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1189 /* Read the reply */
1190 Overlapped
.hEvent
= (HANDLE
) NULL
;
1192 bResult
= ReadFile(hControlPipe
,
1194 sizeof(SCM_REPLY_PACKET
),
1197 if (bResult
== FALSE
)
1199 DPRINT("ReadFile() returned FALSE\n");
1201 dwError
= GetLastError();
1202 if (dwError
== ERROR_IO_PENDING
)
1204 DPRINT("dwError: ERROR_IO_PENDING\n");
1206 dwError
= WaitForSingleObject(hControlPipe
,
1208 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1210 if (dwError
== WAIT_TIMEOUT
)
1212 bResult
= CancelIo(hControlPipe
);
1213 if (bResult
== FALSE
)
1215 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1218 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1221 else if (dwError
== WAIT_OBJECT_0
)
1223 bResult
= GetOverlappedResult(hControlPipe
,
1227 if (bResult
== FALSE
)
1229 dwError
= GetLastError();
1230 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1238 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1244 /* Release the control packet */
1245 HeapFree(GetProcessHeap(),
1249 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1251 dwError
= ReplyPacket
.dwError
;
1254 LeaveCriticalSection(&ControlServiceCriticalSection
);
1256 DPRINT("ScmControlService() done\n");
1263 ScmSendStartCommand(PSERVICE Service
,
1267 DWORD dwError
= ERROR_SUCCESS
;
1268 PSCM_CONTROL_PACKET ControlPacket
;
1269 SCM_REPLY_PACKET ReplyPacket
;
1276 DWORD dwWriteCount
= 0;
1277 DWORD dwReadCount
= 0;
1278 OVERLAPPED Overlapped
= {0};
1280 DPRINT("ScmSendStartCommand() called\n");
1282 /* Calculate the total length of the start command line */
1283 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1284 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1287 * Calculate the required packet size for the start argument vector 'argv',
1288 * composed of the list of pointer offsets, followed by UNICODE strings.
1289 * The strings are stored continuously after the vector of offsets, with
1290 * the offsets being relative to the beginning of the vector, as in the
1291 * following layout (with N == argc):
1292 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1294 if (argc
> 0 && argv
!= NULL
)
1296 PacketSize
= ALIGN_UP(PacketSize
, PWSTR
);
1297 PacketSize
+= (argc
* sizeof(PWSTR
));
1299 DPRINT("Argc: %lu\n", argc
);
1300 for (i
= 0; i
< argc
; i
++)
1302 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1303 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
));
1307 /* Allocate a control packet */
1308 ControlPacket
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, PacketSize
);
1309 if (ControlPacket
== NULL
)
1310 return ERROR_NOT_ENOUGH_MEMORY
;
1312 ControlPacket
->dwSize
= PacketSize
;
1313 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1314 ? SERVICE_CONTROL_START_OWN
1315 : SERVICE_CONTROL_START_SHARE
;
1316 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1318 /* Copy the start command line */
1319 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1320 Ptr
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1321 wcscpy(Ptr
, Service
->lpServiceName
);
1323 ControlPacket
->dwArgumentsCount
= 0;
1324 ControlPacket
->dwArgumentsOffset
= 0;
1326 /* Copy the argument vector */
1327 if (argc
> 0 && argv
!= NULL
)
1329 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1330 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1331 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1333 ControlPacket
->dwArgumentsCount
= argc
;
1334 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1336 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1337 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1339 for (i
= 0; i
< argc
; i
++)
1341 wcscpy(pArgPtr
, argv
[i
]);
1342 pOffPtr
[i
] = (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1343 DPRINT("offset[%lu]: %p\n", i
, pOffPtr
[i
]);
1344 pArgPtr
+= wcslen(argv
[i
]) + 1;
1348 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1353 if (bResult
== FALSE
)
1355 DPRINT("WriteFile() returned FALSE\n");
1357 dwError
= GetLastError();
1358 if (dwError
== ERROR_IO_PENDING
)
1360 DPRINT("dwError: ERROR_IO_PENDING\n");
1362 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1364 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1366 if (dwError
== WAIT_TIMEOUT
)
1368 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1369 if (bResult
== FALSE
)
1371 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1374 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1377 else if (dwError
== WAIT_OBJECT_0
)
1379 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1383 if (bResult
== FALSE
)
1385 dwError
= GetLastError();
1386 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1394 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1399 /* Read the reply */
1400 Overlapped
.hEvent
= (HANDLE
) NULL
;
1402 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1404 sizeof(SCM_REPLY_PACKET
),
1407 if (bResult
== FALSE
)
1409 DPRINT("ReadFile() returned FALSE\n");
1411 dwError
= GetLastError();
1412 if (dwError
== ERROR_IO_PENDING
)
1414 DPRINT("dwError: ERROR_IO_PENDING\n");
1416 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1418 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1420 if (dwError
== WAIT_TIMEOUT
)
1422 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1423 if (bResult
== FALSE
)
1425 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1428 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1431 else if (dwError
== WAIT_OBJECT_0
)
1433 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1437 if (bResult
== FALSE
)
1439 dwError
= GetLastError();
1440 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1448 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1454 /* Release the control packet */
1455 HeapFree(GetProcessHeap(),
1459 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1461 dwError
= ReplyPacket
.dwError
;
1464 DPRINT("ScmSendStartCommand() done\n");
1471 ScmWaitForServiceConnect(PSERVICE Service
)
1474 DWORD dwProcessId
= 0;
1475 DWORD dwError
= ERROR_SUCCESS
;
1477 OVERLAPPED Overlapped
= {0};
1479 LPCWSTR lpLogStrings
[3];
1480 WCHAR szBuffer1
[20];
1481 WCHAR szBuffer2
[20];
1484 DPRINT("ScmWaitForServiceConnect()\n");
1486 Overlapped
.hEvent
= (HANDLE
)NULL
;
1488 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1490 if (bResult
== FALSE
)
1492 DPRINT("ConnectNamedPipe() returned FALSE\n");
1494 dwError
= GetLastError();
1495 if (dwError
== ERROR_IO_PENDING
)
1497 DPRINT("dwError: ERROR_IO_PENDING\n");
1499 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1501 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1503 if (dwError
== WAIT_TIMEOUT
)
1505 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1507 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1508 if (bResult
== FALSE
)
1510 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1514 _ultow(PipeTimeout
, szBuffer1
, 10);
1515 lpLogStrings
[0] = Service
->lpDisplayName
;
1516 lpLogStrings
[1] = szBuffer1
;
1518 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1519 EVENTLOG_ERROR_TYPE
,
1523 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1525 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1527 else if (dwError
== WAIT_OBJECT_0
)
1529 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1533 if (bResult
== FALSE
)
1535 dwError
= GetLastError();
1536 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1542 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1544 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1549 DPRINT("Control pipe connected!\n");
1551 Overlapped
.hEvent
= (HANDLE
) NULL
;
1553 /* Read the process id from pipe */
1554 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1555 (LPVOID
)&dwProcessId
,
1559 if (bResult
== FALSE
)
1561 DPRINT("ReadFile() returned FALSE\n");
1563 dwError
= GetLastError();
1564 if (dwError
== ERROR_IO_PENDING
)
1566 DPRINT("dwError: ERROR_IO_PENDING\n");
1568 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1570 if (dwError
== WAIT_TIMEOUT
)
1572 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1574 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1575 if (bResult
== FALSE
)
1577 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1581 _ultow(PipeTimeout
, szBuffer1
, 10);
1582 lpLogStrings
[0] = szBuffer1
;
1584 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1585 EVENTLOG_ERROR_TYPE
,
1589 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1591 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1593 else if (dwError
== WAIT_OBJECT_0
)
1595 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1597 DPRINT("Process Id: %lu\n", dwProcessId
);
1599 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1603 if (bResult
== FALSE
)
1605 dwError
= GetLastError();
1606 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1613 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1618 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1623 if (dwProcessId
!= Service
->lpImage
->dwProcessId
)
1626 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1627 _ultow(dwProcessId
, szBuffer2
, 10);
1629 lpLogStrings
[0] = Service
->lpDisplayName
;
1630 lpLogStrings
[1] = szBuffer1
;
1631 lpLogStrings
[2] = szBuffer2
;
1633 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1634 EVENTLOG_WARNING_TYPE
,
1639 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1642 DPRINT("ScmWaitForServiceConnect() done\n");
1644 return ERROR_SUCCESS
;
1649 ScmStartUserModeService(PSERVICE Service
,
1653 PROCESS_INFORMATION ProcessInformation
;
1654 STARTUPINFOW StartupInfo
;
1655 LPVOID lpEnvironment
;
1657 DWORD dwError
= ERROR_SUCCESS
;
1659 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1661 /* If the image is already running ... */
1662 if (Service
->lpImage
->dwImageRunCount
> 1)
1664 /* ... just send a start command */
1665 return ScmSendStartCommand(Service
, argc
, argv
);
1668 /* Otherwise start its process */
1669 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1670 StartupInfo
.cb
= sizeof(StartupInfo
);
1671 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1673 /* Use the interactive desktop if the service is interactive */
1674 if ((NoInteractiveServices
== 0) &&
1675 (Service
->Status
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
))
1677 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
1680 if (Service
->lpImage
->hToken
)
1682 /* User token: Run the service under the user account */
1684 if (!CreateEnvironmentBlock(&lpEnvironment
, Service
->lpImage
->hToken
, FALSE
))
1686 /* We failed, run the service with the current environment */
1687 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1688 GetLastError(), Service
->lpServiceName
);
1689 lpEnvironment
= NULL
;
1692 /* Impersonate the new user */
1693 Result
= ImpersonateLoggedOnUser(Service
->lpImage
->hToken
);
1696 /* Launch the process in the user's logon session */
1697 Result
= CreateProcessAsUserW(Service
->lpImage
->hToken
,
1699 Service
->lpImage
->pszImagePath
,
1703 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1707 &ProcessInformation
);
1709 dwError
= GetLastError();
1711 /* Revert the impersonation */
1716 dwError
= GetLastError();
1717 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError
);
1722 /* No user token: Run the service under the LocalSystem account */
1724 if (!CreateEnvironmentBlock(&lpEnvironment
, NULL
, TRUE
))
1726 /* We failed, run the service with the current environment */
1727 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1728 GetLastError(), Service
->lpServiceName
);
1729 lpEnvironment
= NULL
;
1732 Result
= CreateProcessW(NULL
,
1733 Service
->lpImage
->pszImagePath
,
1737 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1741 &ProcessInformation
);
1743 dwError
= GetLastError();
1747 DestroyEnvironmentBlock(lpEnvironment
);
1751 DPRINT1("Starting '%S' failed with error %d\n",
1752 Service
->lpServiceName
, dwError
);
1756 DPRINT("Process Id: %lu Handle %p\n",
1757 ProcessInformation
.dwProcessId
,
1758 ProcessInformation
.hProcess
);
1759 DPRINT("Thread Id: %lu Handle %p\n",
1760 ProcessInformation
.dwThreadId
,
1761 ProcessInformation
.hThread
);
1763 /* Get the process handle and ID */
1764 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1765 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1767 /* Resume the main thread and close its handle */
1768 ResumeThread(ProcessInformation
.hThread
);
1769 CloseHandle(ProcessInformation
.hThread
);
1771 /* Connect control pipe */
1772 dwError
= ScmWaitForServiceConnect(Service
);
1773 if (dwError
!= ERROR_SUCCESS
)
1775 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1776 Service
->lpImage
->dwProcessId
= 0;
1780 /* Send the start command */
1781 return ScmSendStartCommand(Service
, argc
, argv
);
1786 ScmLoadService(PSERVICE Service
,
1790 PSERVICE_GROUP Group
= Service
->lpGroup
;
1791 DWORD dwError
= ERROR_SUCCESS
;
1792 LPCWSTR lpLogStrings
[2];
1793 WCHAR szLogBuffer
[80];
1795 DPRINT("ScmLoadService() called\n");
1796 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1798 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1800 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1801 return ERROR_SERVICE_ALREADY_RUNNING
;
1804 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1806 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1808 /* Start the driver */
1809 dwError
= ScmStartDriver(Service
);
1811 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1813 /* Start user-mode service */
1814 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1815 if (dwError
== ERROR_SUCCESS
)
1817 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1818 if (dwError
== ERROR_SUCCESS
)
1820 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1821 Service
->Status
.dwControlsAccepted
= 0;
1825 Service
->lpImage
->dwImageRunCount
--;
1826 if (Service
->lpImage
->dwImageRunCount
== 0)
1828 ScmRemoveServiceImage(Service
->lpImage
);
1829 Service
->lpImage
= NULL
;
1835 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
1837 if (dwError
== ERROR_SUCCESS
)
1841 Group
->ServicesRunning
= TRUE
;
1844 /* Log a successful service start */
1845 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
1846 lpLogStrings
[0] = Service
->lpDisplayName
;
1847 lpLogStrings
[1] = szLogBuffer
;
1849 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1850 EVENTLOG_INFORMATION_TYPE
,
1856 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1858 /* Log a failed service start */
1859 StringCchPrintfW(szLogBuffer
, ARRAYSIZE(szLogBuffer
),
1861 lpLogStrings
[0] = Service
->lpServiceName
;
1862 lpLogStrings
[1] = szLogBuffer
;
1863 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
1864 EVENTLOG_ERROR_TYPE
,
1870 switch (Service
->dwErrorControl
)
1872 case SERVICE_ERROR_SEVERE
:
1873 if (IsLastKnownGood
== FALSE
)
1875 /* FIXME: Boot last known good configuration */
1879 case SERVICE_ERROR_CRITICAL
:
1880 if (IsLastKnownGood
== FALSE
)
1882 /* FIXME: Boot last known good configuration */
1898 ScmStartService(PSERVICE Service
,
1902 DWORD dwError
= ERROR_SUCCESS
;
1903 SC_RPC_LOCK Lock
= NULL
;
1905 DPRINT("ScmStartService() called\n");
1906 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1908 /* Acquire the service control critical section, to synchronize starts */
1909 EnterCriticalSection(&ControlServiceCriticalSection
);
1912 * Acquire the user service start lock while the service is starting, if
1913 * needed (i.e. if we are not starting it during the initialization phase).
1914 * If we don't success, bail out.
1918 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
1919 if (dwError
!= ERROR_SUCCESS
) goto done
;
1922 /* Really start the service */
1923 dwError
= ScmLoadService(Service
, argc
, argv
);
1925 /* Release the service start lock, if needed, and the critical section */
1926 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
1929 LeaveCriticalSection(&ControlServiceCriticalSection
);
1931 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1938 ScmAutoStartServices(VOID
)
1941 PLIST_ENTRY GroupEntry
;
1942 PLIST_ENTRY ServiceEntry
;
1943 PSERVICE_GROUP CurrentGroup
;
1944 PSERVICE CurrentService
;
1945 WCHAR szSafeBootServicePath
[MAX_PATH
];
1946 DWORD SafeBootEnabled
;
1952 * This function MUST be called ONLY at initialization time.
1953 * Therefore, no need to acquire the user service start lock.
1955 ASSERT(ScmInitialize
);
1957 /* Retrieve the SafeBoot parameter */
1958 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1959 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
1963 if (dwError
== ERROR_SUCCESS
)
1965 dwKeySize
= sizeof(SafeBootEnabled
);
1966 dwError
= RegQueryValueExW(hKey
,
1970 (LPBYTE
)&SafeBootEnabled
,
1975 /* Default to Normal boot if the value doesn't exist */
1976 if (dwError
!= ERROR_SUCCESS
)
1977 SafeBootEnabled
= 0;
1979 /* Acquire the service control critical section, to synchronize starts */
1980 EnterCriticalSection(&ControlServiceCriticalSection
);
1982 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1983 ServiceEntry
= ServiceListHead
.Flink
;
1984 while (ServiceEntry
!= &ServiceListHead
)
1986 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1988 /* Build the safe boot path */
1989 StringCchCopyW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
1990 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1992 switch (SafeBootEnabled
)
1994 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1997 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2002 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2007 if (SafeBootEnabled
!= 0)
2009 /* If key does not exist then do not assume safe mode */
2010 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2011 szSafeBootServicePath
,
2015 if (dwError
== ERROR_SUCCESS
)
2019 /* Finish Safe Boot path off */
2020 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2021 CurrentService
->lpServiceName
);
2023 /* Check that the key is in the Safe Boot path */
2024 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2025 szSafeBootServicePath
,
2029 if (dwError
!= ERROR_SUCCESS
)
2031 /* Mark service as visited so it is not auto-started */
2032 CurrentService
->ServiceVisited
= TRUE
;
2036 /* Must be auto-started in safe mode - mark as unvisited */
2038 CurrentService
->ServiceVisited
= FALSE
;
2043 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2044 CurrentService
->ServiceVisited
= FALSE
;
2048 ServiceEntry
= ServiceEntry
->Flink
;
2051 /* Start all services which are members of an existing group */
2052 GroupEntry
= GroupListHead
.Flink
;
2053 while (GroupEntry
!= &GroupListHead
)
2055 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
2057 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
2059 /* Start all services witch have a valid tag */
2060 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
2062 ServiceEntry
= ServiceListHead
.Flink
;
2063 while (ServiceEntry
!= &ServiceListHead
)
2065 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2067 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2068 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2069 (CurrentService
->ServiceVisited
== FALSE
) &&
2070 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
2072 CurrentService
->ServiceVisited
= TRUE
;
2073 ScmLoadService(CurrentService
, 0, NULL
);
2076 ServiceEntry
= ServiceEntry
->Flink
;
2080 /* Start all services which have an invalid tag or which do not have a tag */
2081 ServiceEntry
= ServiceListHead
.Flink
;
2082 while (ServiceEntry
!= &ServiceListHead
)
2084 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2086 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2087 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2088 (CurrentService
->ServiceVisited
== FALSE
))
2090 CurrentService
->ServiceVisited
= TRUE
;
2091 ScmLoadService(CurrentService
, 0, NULL
);
2094 ServiceEntry
= ServiceEntry
->Flink
;
2097 GroupEntry
= GroupEntry
->Flink
;
2100 /* Start all services which are members of any non-existing group */
2101 ServiceEntry
= ServiceListHead
.Flink
;
2102 while (ServiceEntry
!= &ServiceListHead
)
2104 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2106 if ((CurrentService
->lpGroup
!= NULL
) &&
2107 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2108 (CurrentService
->ServiceVisited
== FALSE
))
2110 CurrentService
->ServiceVisited
= TRUE
;
2111 ScmLoadService(CurrentService
, 0, NULL
);
2114 ServiceEntry
= ServiceEntry
->Flink
;
2117 /* Start all services which are not a member of any group */
2118 ServiceEntry
= ServiceListHead
.Flink
;
2119 while (ServiceEntry
!= &ServiceListHead
)
2121 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2123 if ((CurrentService
->lpGroup
== NULL
) &&
2124 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2125 (CurrentService
->ServiceVisited
== FALSE
))
2127 CurrentService
->ServiceVisited
= TRUE
;
2128 ScmLoadService(CurrentService
, 0, NULL
);
2131 ServiceEntry
= ServiceEntry
->Flink
;
2134 /* Clear 'ServiceVisited' flag again */
2135 ServiceEntry
= ServiceListHead
.Flink
;
2136 while (ServiceEntry
!= &ServiceListHead
)
2138 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2139 CurrentService
->ServiceVisited
= FALSE
;
2140 ServiceEntry
= ServiceEntry
->Flink
;
2143 /* Release the critical section */
2144 LeaveCriticalSection(&ControlServiceCriticalSection
);
2149 ScmAutoShutdownServices(VOID
)
2151 PLIST_ENTRY ServiceEntry
;
2152 PSERVICE CurrentService
;
2154 DPRINT("ScmAutoShutdownServices() called\n");
2156 /* Lock the service database exclusively */
2157 ScmLockDatabaseExclusive();
2159 ServiceEntry
= ServiceListHead
.Flink
;
2160 while (ServiceEntry
!= &ServiceListHead
)
2162 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2164 if ((CurrentService
->Status
.dwControlsAccepted
& SERVICE_ACCEPT_SHUTDOWN
) &&
2165 (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2166 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
))
2168 /* Send the shutdown notification */
2169 DPRINT("Shutdown service: %S\n", CurrentService
->lpServiceName
);
2170 ScmControlService(CurrentService
->lpImage
->hControlPipe
,
2171 CurrentService
->lpServiceName
,
2172 (SERVICE_STATUS_HANDLE
)CurrentService
,
2173 SERVICE_CONTROL_SHUTDOWN
);
2176 ServiceEntry
= ServiceEntry
->Flink
;
2179 /* Unlock the service database */
2180 ScmUnlockDatabase();
2182 DPRINT("ScmAutoShutdownServices() done\n");
2187 ScmLockDatabaseExclusive(VOID
)
2189 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2194 ScmLockDatabaseShared(VOID
)
2196 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2201 ScmUnlockDatabase(VOID
)
2203 RtlReleaseResource(&DatabaseLock
);
2208 ScmInitNamedPipeCriticalSection(VOID
)
2214 InitializeCriticalSection(&ControlServiceCriticalSection
);
2216 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2217 L
"SYSTEM\\CurrentControlSet\\Control",
2221 if (dwError
== ERROR_SUCCESS
)
2223 dwKeySize
= sizeof(PipeTimeout
);
2224 RegQueryValueExW(hKey
,
2225 L
"ServicesPipeTimeout",
2228 (LPBYTE
)&PipeTimeout
,
2236 ScmDeleteNamedPipeCriticalSection(VOID
)
2238 DeleteCriticalSection(&ControlServiceCriticalSection
);