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 *****************************************************************/
23 /* GLOBALS *******************************************************************/
25 LIST_ENTRY ImageListHead
;
26 LIST_ENTRY ServiceListHead
;
28 static RTL_RESOURCE DatabaseLock
;
29 static DWORD ResumeCount
= 1;
30 static DWORD NoInteractiveServices
= 0;
32 /* The critical section synchronizes service control requests */
33 static CRITICAL_SECTION ControlServiceCriticalSection
;
34 static DWORD PipeTimeout
= 30000; /* 30 Seconds */
37 /* FUNCTIONS *****************************************************************/
40 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
42 WCHAR szControlPipeName
[MAX_PATH
+ 1];
43 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
44 DWORD ServiceCurrent
= 0;
49 /* Get the service number */
50 /* TODO: Create registry entry with correct write access */
51 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
52 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
58 if (dwError
!= ERROR_SUCCESS
)
60 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
64 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
66 dwKeySize
= sizeof(DWORD
);
67 dwError
= RegQueryValueExW(hServiceCurrentKey
,
68 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
70 if (dwError
!= ERROR_SUCCESS
)
72 RegCloseKey(hServiceCurrentKey
);
73 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
80 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
82 RegCloseKey(hServiceCurrentKey
);
84 if (dwError
!= ERROR_SUCCESS
)
86 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
90 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
91 swprintf(szControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent
);
93 DPRINT("PipeName: %S\n", szControlPipeName
);
95 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
96 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
97 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
103 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
104 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
106 DPRINT1("Failed to create control pipe!\n");
107 return GetLastError();
110 return ERROR_SUCCESS
;
114 static PSERVICE_IMAGE
115 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
117 PLIST_ENTRY ImageEntry
;
118 PSERVICE_IMAGE CurrentImage
;
120 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
122 ImageEntry
= ImageListHead
.Flink
;
123 while (ImageEntry
!= &ImageListHead
)
125 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
128 if (_wcsicmp(CurrentImage
->pszImagePath
, lpImagePath
) == 0)
130 DPRINT("Found image: '%S'\n", CurrentImage
->pszImagePath
);
134 ImageEntry
= ImageEntry
->Flink
;
137 DPRINT("Couldn't find a matching image\n");
146 ScmIsSameServiceAccount(
147 _In_ PCWSTR pszAccountName1
,
148 _In_ PCWSTR pszAccountName2
)
150 if (pszAccountName1
== NULL
&& pszAccountName2
== NULL
)
153 if (pszAccountName1
== NULL
&& pszAccountName2
&& wcscmp(pszAccountName2
, L
"LocalSystem") == 0)
156 if (pszAccountName2
== NULL
&& pszAccountName1
&& wcscmp(pszAccountName1
, L
"LocalSystem") == 0)
159 if (pszAccountName1
&& pszAccountName2
&& wcscmp(pszAccountName1
, pszAccountName2
) == 0)
168 ScmIsLocalSystemAccount(
169 _In_ PCWSTR pszAccountName
)
171 if (pszAccountName
== NULL
||
172 wcscmp(pszAccountName
, L
"LocalSystem") == 0)
182 IN PSERVICE pService
,
183 IN PSERVICE_IMAGE pImage
)
186 PROFILEINFOW ProfileInfo
;
187 PWSTR pszUserName
= NULL
;
188 PWSTR pszDomainName
= NULL
;
189 PWSTR pszPassword
= NULL
;
191 DWORD dwError
= ERROR_SUCCESS
;
194 DPRINT("ScmLogonService(%p %p)\n", pService
, pImage
);
196 DPRINT("Service %S\n", pService
->lpServiceName
);
198 if (ScmIsLocalSystemAccount(pImage
->pszAccountName
))
199 return ERROR_SUCCESS
;
201 // FIXME: Always assume LocalSystem
202 return ERROR_SUCCESS
;
205 /* Get the user and domain names */
206 ptr
= wcschr(pImage
->pszAccountName
, L
'\\');
211 pszUserName
= ptr
+ 1;
212 pszDomainName
= pImage
->pszAccountName
;
216 pszUserName
= pImage
->pszAccountName
;
217 pszDomainName
= NULL
;
220 /* Build the service 'password' */
221 pszPassword
= HeapAlloc(GetProcessHeap(),
223 (wcslen(pService
->lpServiceName
) + 5) * sizeof(WCHAR
));
224 if (pszPassword
== NULL
)
226 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
230 wcscpy(pszPassword
, L
"_SC_");
231 wcscat(pszPassword
, pService
->lpServiceName
);
233 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName
, pszUserName
, pszPassword
);
236 if (!LogonUserW(pszUserName
,
239 LOGON32_LOGON_SERVICE
,
240 LOGON32_PROVIDER_DEFAULT
,
243 dwError
= GetLastError();
244 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError
);
248 // FIXME: Call LoadUserProfileW to be able to initialize a per-user
249 // environment block, with user-specific environment variables as
250 // %USERNAME%, %USERPROFILE%, and %ALLUSERSPROFILE% correctly initialized!!
252 /* Load the user profile, so that the per-user environment variables can be initialized */
253 ZeroMemory(&ProfileInfo
, sizeof(ProfileInfo
));
254 ProfileInfo
.dwSize
= sizeof(ProfileInfo
);
255 ProfileInfo
.dwFlags
= PI_NOUI
;
256 ProfileInfo
.lpUserName
= pszUserName
;
257 // ProfileInfo.lpProfilePath = NULL;
258 // ProfileInfo.lpDefaultPath = NULL;
259 // ProfileInfo.lpServerName = NULL;
260 // ProfileInfo.lpPolicyPath = NULL;
261 // ProfileInfo.hProfile = NULL;
263 if (!LoadUserProfileW(pImage
->hToken
, &ProfileInfo
))
265 dwError
= GetLastError();
266 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError
);
270 pImage
->hProfile
= ProfileInfo
.hProfile
;
273 if (pszPassword
!= NULL
)
274 HeapFree(GetProcessHeap(), 0, pszPassword
);
285 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
287 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
288 UNICODE_STRING ImagePath
;
289 UNICODE_STRING ObjectName
;
290 PSERVICE_IMAGE pServiceImage
= NULL
;
292 DWORD dwError
= ERROR_SUCCESS
;
296 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
298 RtlInitUnicodeString(&ImagePath
, NULL
);
299 RtlInitUnicodeString(&ObjectName
, NULL
);
301 /* Get service data */
302 RtlZeroMemory(&QueryTable
,
305 QueryTable
[0].Name
= L
"ImagePath";
306 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
307 QueryTable
[0].EntryContext
= &ImagePath
;
308 QueryTable
[1].Name
= L
"ObjectName";
309 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
310 QueryTable
[1].EntryContext
= &ObjectName
;
312 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
313 pService
->lpServiceName
,
317 if (!NT_SUCCESS(Status
))
319 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
320 return RtlNtStatusToDosError(Status
);
323 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
324 DPRINT("ObjectName: '%wZ'\n", &ObjectName
);
326 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
327 if (pServiceImage
== NULL
)
329 dwRecordSize
= sizeof(SERVICE_IMAGE
) +
330 ImagePath
.Length
+ sizeof(WCHAR
) +
331 ((ObjectName
.Length
!= 0) ? (ObjectName
.Length
+ sizeof(WCHAR
)) : 0);
333 /* Create a new service image */
334 pServiceImage
= HeapAlloc(GetProcessHeap(),
337 if (pServiceImage
== NULL
)
339 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
343 pServiceImage
->dwImageRunCount
= 1;
344 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
345 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
347 pString
= (PWSTR
)((INT_PTR
)pServiceImage
+ sizeof(SERVICE_IMAGE
));
349 /* Set the image path */
350 pServiceImage
->pszImagePath
= pString
;
351 wcscpy(pServiceImage
->pszImagePath
,
354 /* Set the account name */
355 if (ObjectName
.Length
> 0)
357 pString
= pString
+ wcslen(pString
) + 1;
359 pServiceImage
->pszAccountName
= pString
;
360 wcscpy(pServiceImage
->pszAccountName
,
365 dwError
= ScmLogonService(pService
, pServiceImage
);
366 if (dwError
!= ERROR_SUCCESS
)
368 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError
);
370 /* Release the service image */
371 HeapFree(GetProcessHeap(), 0, pServiceImage
);
376 /* Create the control pipe */
377 dwError
= ScmCreateNewControlPipe(pServiceImage
);
378 if (dwError
!= ERROR_SUCCESS
)
380 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError
);
382 /* Unload the user profile */
383 if (pServiceImage
->hProfile
!= NULL
)
384 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
386 /* Close the logon token */
387 if (pServiceImage
->hToken
!= NULL
)
388 CloseHandle(pServiceImage
->hToken
);
390 /* Release the service image */
391 HeapFree(GetProcessHeap(), 0, pServiceImage
);
396 /* FIXME: Add more initialization code here */
399 /* Append service record */
400 InsertTailList(&ImageListHead
,
401 &pServiceImage
->ImageListEntry
);
405 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
407 /* Fail if services in an image use different accounts */
408 if (!ScmIsSameServiceAccount(pServiceImage
->pszAccountName
, ObjectName
.Buffer
))
410 dwError
= ERROR_DIFFERENT_SERVICE_ACCOUNT
;
414 /* Increment the run counter */
415 pServiceImage
->dwImageRunCount
++;
418 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage
->pszImagePath
);
419 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage
->pszAccountName
);
420 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
422 /* Link the service image to the service */
423 pService
->lpImage
= pServiceImage
;
426 RtlFreeUnicodeString(&ObjectName
);
427 RtlFreeUnicodeString(&ImagePath
);
429 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
436 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage
)
438 DPRINT1("ScmDereferenceServiceImage() called\n");
440 pServiceImage
->dwImageRunCount
--;
442 if (pServiceImage
->dwImageRunCount
== 0)
444 DPRINT1("dwImageRunCount == 0\n");
446 /* FIXME: Terminate the process */
448 /* Remove the service image from the list */
449 RemoveEntryList(&pServiceImage
->ImageListEntry
);
451 /* Close the process handle */
452 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
453 CloseHandle(pServiceImage
->hProcess
);
455 /* Close the control pipe */
456 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
457 CloseHandle(pServiceImage
->hControlPipe
);
459 /* Unload the user profile */
460 if (pServiceImage
->hProfile
!= NULL
)
461 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
463 /* Close the logon token */
464 if (pServiceImage
->hToken
!= NULL
)
465 CloseHandle(pServiceImage
->hToken
);
467 /* Release the service image */
468 HeapFree(GetProcessHeap(), 0, pServiceImage
);
474 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
476 PLIST_ENTRY ServiceEntry
;
477 PSERVICE CurrentService
;
479 DPRINT("ScmGetServiceEntryByName() called\n");
481 ServiceEntry
= ServiceListHead
.Flink
;
482 while (ServiceEntry
!= &ServiceListHead
)
484 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
487 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
489 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
490 return CurrentService
;
493 ServiceEntry
= ServiceEntry
->Flink
;
496 DPRINT("Couldn't find a matching service\n");
503 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
505 PLIST_ENTRY ServiceEntry
;
506 PSERVICE CurrentService
;
508 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
510 ServiceEntry
= ServiceListHead
.Flink
;
511 while (ServiceEntry
!= &ServiceListHead
)
513 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
516 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
518 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
519 return CurrentService
;
522 ServiceEntry
= ServiceEntry
->Flink
;
525 DPRINT("Couldn't find a matching service\n");
532 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
534 PLIST_ENTRY ServiceEntry
;
535 PSERVICE CurrentService
;
537 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
539 ServiceEntry
= ServiceListHead
.Flink
;
540 while (ServiceEntry
!= &ServiceListHead
)
542 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
545 if (CurrentService
->dwResumeCount
> dwResumeCount
)
547 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
548 return CurrentService
;
551 ServiceEntry
= ServiceEntry
->Flink
;
554 DPRINT("Couldn't find a matching service\n");
561 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
562 PSERVICE
* lpServiceRecord
)
564 PSERVICE lpService
= NULL
;
566 DPRINT("Service: '%S'\n", lpServiceName
);
568 /* Allocate service entry */
569 lpService
= HeapAlloc(GetProcessHeap(),
571 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
572 if (lpService
== NULL
)
573 return ERROR_NOT_ENOUGH_MEMORY
;
575 *lpServiceRecord
= lpService
;
577 /* Copy service name */
578 wcscpy(lpService
->szServiceName
, lpServiceName
);
579 lpService
->lpServiceName
= lpService
->szServiceName
;
580 lpService
->lpDisplayName
= lpService
->lpServiceName
;
582 /* Set the resume count */
583 lpService
->dwResumeCount
= ResumeCount
++;
585 /* Append service record */
586 InsertTailList(&ServiceListHead
,
587 &lpService
->ServiceListEntry
);
589 /* Initialize the service status */
590 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
591 lpService
->Status
.dwControlsAccepted
= 0;
592 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
593 lpService
->Status
.dwServiceSpecificExitCode
= 0;
594 lpService
->Status
.dwCheckPoint
= 0;
595 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
597 return ERROR_SUCCESS
;
602 ScmDeleteServiceRecord(PSERVICE lpService
)
604 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
606 /* Delete the display name */
607 if (lpService
->lpDisplayName
!= NULL
&&
608 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
609 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
611 /* Dereference the service image */
612 if (lpService
->lpImage
)
613 ScmDereferenceServiceImage(lpService
->lpImage
);
615 /* Decrement the group reference counter */
616 ScmSetServiceGroup(lpService
, NULL
);
618 /* Release the SecurityDescriptor */
619 if (lpService
->pSecurityDescriptor
!= NULL
)
620 HeapFree(GetProcessHeap(), 0, lpService
->pSecurityDescriptor
);
622 /* Remove the Service from the List */
623 RemoveEntryList(&lpService
->ServiceListEntry
);
625 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
627 /* Delete the service record */
628 HeapFree(GetProcessHeap(), 0, lpService
);
635 CreateServiceListEntry(LPCWSTR lpServiceName
,
638 PSERVICE lpService
= NULL
;
639 LPWSTR lpDisplayName
= NULL
;
640 LPWSTR lpGroup
= NULL
;
645 DWORD dwErrorControl
;
648 DPRINT("Service: '%S'\n", lpServiceName
);
649 if (*lpServiceName
== L
'{')
650 return ERROR_SUCCESS
;
652 dwSize
= sizeof(DWORD
);
653 dwError
= RegQueryValueExW(hServiceKey
,
657 (LPBYTE
)&dwServiceType
,
659 if (dwError
!= ERROR_SUCCESS
)
660 return ERROR_SUCCESS
;
662 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
663 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
664 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
665 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
666 return ERROR_SUCCESS
;
668 DPRINT("Service type: %lx\n", dwServiceType
);
670 dwSize
= sizeof(DWORD
);
671 dwError
= RegQueryValueExW(hServiceKey
,
675 (LPBYTE
)&dwStartType
,
677 if (dwError
!= ERROR_SUCCESS
)
678 return ERROR_SUCCESS
;
680 DPRINT("Start type: %lx\n", dwStartType
);
682 dwSize
= sizeof(DWORD
);
683 dwError
= RegQueryValueExW(hServiceKey
,
687 (LPBYTE
)&dwErrorControl
,
689 if (dwError
!= ERROR_SUCCESS
)
690 return ERROR_SUCCESS
;
692 DPRINT("Error control: %lx\n", dwErrorControl
);
694 dwError
= RegQueryValueExW(hServiceKey
,
700 if (dwError
!= ERROR_SUCCESS
)
703 DPRINT("Tag: %lx\n", dwTagId
);
705 dwError
= ScmReadString(hServiceKey
,
708 if (dwError
!= ERROR_SUCCESS
)
711 DPRINT("Group: %S\n", lpGroup
);
713 dwError
= ScmReadString(hServiceKey
,
716 if (dwError
!= ERROR_SUCCESS
)
717 lpDisplayName
= NULL
;
719 DPRINT("Display name: %S\n", lpDisplayName
);
721 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
723 if (dwError
!= ERROR_SUCCESS
)
726 lpService
->Status
.dwServiceType
= dwServiceType
;
727 lpService
->dwStartType
= dwStartType
;
728 lpService
->dwErrorControl
= dwErrorControl
;
729 lpService
->dwTag
= dwTagId
;
733 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
734 if (dwError
!= ERROR_SUCCESS
)
738 if (lpDisplayName
!= NULL
)
740 lpService
->lpDisplayName
= lpDisplayName
;
741 lpDisplayName
= NULL
;
744 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
745 if (lpService
->lpGroup
!= NULL
)
747 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
749 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
750 lpService
->dwStartType
,
751 lpService
->Status
.dwServiceType
,
753 lpService
->dwErrorControl
);
755 if (ScmIsDeleteFlagSet(hServiceKey
))
756 lpService
->bDeleted
= TRUE
;
758 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
760 dwError
= ScmReadSecurityDescriptor(hServiceKey
,
761 &lpService
->pSecurityDescriptor
);
762 if (dwError
!= ERROR_SUCCESS
)
765 /* Assing the default security descriptor if the security descriptor cannot be read */
766 if (lpService
->pSecurityDescriptor
== NULL
)
768 DPRINT("No security descriptor found! Assign default security descriptor!\n");
769 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
770 if (dwError
!= ERROR_SUCCESS
)
773 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
774 lpService
->pSecurityDescriptor
);
775 if (dwError
!= ERROR_SUCCESS
)
782 HeapFree(GetProcessHeap(), 0, lpGroup
);
784 if (lpDisplayName
!= NULL
)
785 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
787 if (lpService
!= NULL
)
789 ASSERT(lpService
->lpImage
== NULL
);
797 ScmDeleteMarkedServices(VOID
)
799 PLIST_ENTRY ServiceEntry
;
800 PSERVICE CurrentService
;
804 ServiceEntry
= ServiceListHead
.Flink
;
805 while (ServiceEntry
!= &ServiceListHead
)
807 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
809 ServiceEntry
= ServiceEntry
->Flink
;
811 if (CurrentService
->bDeleted
!= FALSE
)
813 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
814 L
"System\\CurrentControlSet\\Services",
818 if (dwError
== ERROR_SUCCESS
)
820 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
821 RegCloseKey(hServicesKey
);
822 if (dwError
== ERROR_SUCCESS
)
824 RemoveEntryList(&CurrentService
->ServiceListEntry
);
825 HeapFree(GetProcessHeap(), 0, CurrentService
);
829 if (dwError
!= ERROR_SUCCESS
)
830 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
838 ScmGetNoInteractiveServicesValue(VOID
)
844 lError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
845 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
849 if (lError
== ERROR_SUCCESS
)
851 dwKeySize
= sizeof(NoInteractiveServices
);
852 lError
= RegQueryValueExW(hKey
,
853 L
"NoInteractiveServices",
856 (LPBYTE
)&NoInteractiveServices
,
864 ScmCreateServiceDatabase(VOID
)
866 WCHAR szSubKey
[MAX_PATH
];
870 DWORD dwSubKeyLength
;
871 FILETIME ftLastChanged
;
874 DPRINT("ScmCreateServiceDatabase() called\n");
876 /* Retrieve the NoInteractiveServies value */
877 ScmGetNoInteractiveServicesValue();
879 /* Create the service group list */
880 dwError
= ScmCreateGroupList();
881 if (dwError
!= ERROR_SUCCESS
)
884 /* Initialize image and service lists */
885 InitializeListHead(&ImageListHead
);
886 InitializeListHead(&ServiceListHead
);
888 /* Initialize the database lock */
889 RtlInitializeResource(&DatabaseLock
);
891 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
892 L
"System\\CurrentControlSet\\Services",
896 if (dwError
!= ERROR_SUCCESS
)
902 dwSubKeyLength
= MAX_PATH
;
903 dwError
= RegEnumKeyExW(hServicesKey
,
911 if (dwError
== ERROR_SUCCESS
&&
914 DPRINT("SubKeyName: '%S'\n", szSubKey
);
916 dwError
= RegOpenKeyExW(hServicesKey
,
921 if (dwError
== ERROR_SUCCESS
)
923 dwError
= CreateServiceListEntry(szSubKey
,
926 RegCloseKey(hServiceKey
);
930 if (dwError
!= ERROR_SUCCESS
)
936 RegCloseKey(hServicesKey
);
938 /* Wait for the LSA server */
941 /* Delete services that are marked for delete */
942 ScmDeleteMarkedServices();
944 DPRINT("ScmCreateServiceDatabase() done\n");
946 return ERROR_SUCCESS
;
951 ScmShutdownServiceDatabase(VOID
)
953 DPRINT("ScmShutdownServiceDatabase() called\n");
955 ScmDeleteMarkedServices();
956 RtlDeleteResource(&DatabaseLock
);
958 DPRINT("ScmShutdownServiceDatabase() done\n");
963 ScmCheckDriver(PSERVICE Service
)
965 OBJECT_ATTRIBUTES ObjectAttributes
;
966 UNICODE_STRING DirName
;
969 POBJECT_DIRECTORY_INFORMATION DirInfo
;
974 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
976 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
978 RtlInitUnicodeString(&DirName
, L
"\\Driver");
980 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
982 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
983 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
986 InitializeObjectAttributes(&ObjectAttributes
,
992 Status
= NtOpenDirectoryObject(&DirHandle
,
993 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
995 if (!NT_SUCCESS(Status
))
1000 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
1001 2 * MAX_PATH
* sizeof(WCHAR
);
1002 DirInfo
= HeapAlloc(GetProcessHeap(),
1009 Status
= NtQueryDirectoryObject(DirHandle
,
1016 if (Status
== STATUS_NO_MORE_ENTRIES
)
1018 /* FIXME: Add current service to 'failed service' list */
1019 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
1023 if (!NT_SUCCESS(Status
))
1026 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
1028 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
1030 DPRINT("Found: '%S' '%wZ'\n",
1031 Service
->lpServiceName
, &DirInfo
->Name
);
1033 /* Mark service as 'running' */
1034 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1036 /* Mark the service group as 'running' */
1037 if (Service
->lpGroup
!= NULL
)
1039 Service
->lpGroup
->ServicesRunning
= TRUE
;
1046 HeapFree(GetProcessHeap(),
1051 return STATUS_SUCCESS
;
1056 ScmGetBootAndSystemDriverState(VOID
)
1058 PLIST_ENTRY ServiceEntry
;
1059 PSERVICE CurrentService
;
1061 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1063 ServiceEntry
= ServiceListHead
.Flink
;
1064 while (ServiceEntry
!= &ServiceListHead
)
1066 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1068 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
1069 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
1072 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
1074 ScmCheckDriver(CurrentService
);
1077 ServiceEntry
= ServiceEntry
->Flink
;
1080 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1085 ScmControlService(PSERVICE Service
,
1088 PSCM_CONTROL_PACKET ControlPacket
;
1089 SCM_REPLY_PACKET ReplyPacket
;
1091 DWORD dwWriteCount
= 0;
1092 DWORD dwReadCount
= 0;
1095 DWORD dwError
= ERROR_SUCCESS
;
1097 OVERLAPPED Overlapped
= {0};
1099 DPRINT("ScmControlService() called\n");
1101 /* Acquire the service control critical section, to synchronize requests */
1102 EnterCriticalSection(&ControlServiceCriticalSection
);
1104 /* Calculate the total length of the start command line */
1105 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1106 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1108 ControlPacket
= HeapAlloc(GetProcessHeap(),
1111 if (ControlPacket
== NULL
)
1113 LeaveCriticalSection(&ControlServiceCriticalSection
);
1114 return ERROR_NOT_ENOUGH_MEMORY
;
1117 ControlPacket
->dwSize
= PacketSize
;
1118 ControlPacket
->dwControl
= dwControl
;
1119 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1121 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1123 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1124 wcscpy(Ptr
, Service
->lpServiceName
);
1126 ControlPacket
->dwArgumentsCount
= 0;
1127 ControlPacket
->dwArgumentsOffset
= 0;
1129 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1134 if (bResult
== FALSE
)
1136 DPRINT("WriteFile() returned FALSE\n");
1138 dwError
= GetLastError();
1139 if (dwError
== ERROR_IO_PENDING
)
1141 DPRINT("dwError: ERROR_IO_PENDING\n");
1143 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1145 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1147 if (dwError
== WAIT_TIMEOUT
)
1149 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1150 if (bResult
== FALSE
)
1152 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1155 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1158 else if (dwError
== WAIT_OBJECT_0
)
1160 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1164 if (bResult
== FALSE
)
1166 dwError
= GetLastError();
1167 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1175 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1180 /* Read the reply */
1181 Overlapped
.hEvent
= (HANDLE
) NULL
;
1183 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1185 sizeof(SCM_REPLY_PACKET
),
1188 if (bResult
== FALSE
)
1190 DPRINT("ReadFile() returned FALSE\n");
1192 dwError
= GetLastError();
1193 if (dwError
== ERROR_IO_PENDING
)
1195 DPRINT("dwError: ERROR_IO_PENDING\n");
1197 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1199 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1201 if (dwError
== WAIT_TIMEOUT
)
1203 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1204 if (bResult
== FALSE
)
1206 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1209 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1212 else if (dwError
== WAIT_OBJECT_0
)
1214 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1218 if (bResult
== FALSE
)
1220 dwError
= GetLastError();
1221 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1229 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1235 /* Release the control packet */
1236 HeapFree(GetProcessHeap(),
1240 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1242 dwError
= ReplyPacket
.dwError
;
1245 if (dwError
== ERROR_SUCCESS
&&
1246 dwControl
== SERVICE_CONTROL_STOP
)
1248 ScmDereferenceServiceImage(Service
->lpImage
);
1249 Service
->lpImage
= NULL
;
1252 LeaveCriticalSection(&ControlServiceCriticalSection
);
1254 DPRINT("ScmControlService() done\n");
1261 ScmSendStartCommand(PSERVICE Service
,
1265 DWORD dwError
= ERROR_SUCCESS
;
1266 PSCM_CONTROL_PACKET ControlPacket
;
1267 SCM_REPLY_PACKET ReplyPacket
;
1274 DWORD dwWriteCount
= 0;
1275 DWORD dwReadCount
= 0;
1276 OVERLAPPED Overlapped
= {0};
1278 DPRINT("ScmSendStartCommand() called\n");
1280 /* Calculate the total length of the start command line */
1281 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1282 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1285 * Calculate the required packet size for the start argument vector 'argv',
1286 * composed of the list of pointer offsets, followed by UNICODE strings.
1287 * The strings are stored continuously after the vector of offsets, with
1288 * the offsets being relative to the beginning of the vector, as in the
1289 * following layout (with N == argc):
1290 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1292 if (argc
> 0 && argv
!= NULL
)
1294 PacketSize
= ALIGN_UP(PacketSize
, PWSTR
);
1295 PacketSize
+= (argc
* sizeof(PWSTR
));
1297 DPRINT("Argc: %lu\n", argc
);
1298 for (i
= 0; i
< argc
; i
++)
1300 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1301 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
));
1305 /* Allocate a control packet */
1306 ControlPacket
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, PacketSize
);
1307 if (ControlPacket
== NULL
)
1308 return ERROR_NOT_ENOUGH_MEMORY
;
1310 ControlPacket
->dwSize
= PacketSize
;
1311 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1312 ? SERVICE_CONTROL_START_OWN
1313 : SERVICE_CONTROL_START_SHARE
;
1314 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1316 /* Copy the start command line */
1317 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1318 Ptr
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1319 wcscpy(Ptr
, Service
->lpServiceName
);
1321 ControlPacket
->dwArgumentsCount
= 0;
1322 ControlPacket
->dwArgumentsOffset
= 0;
1324 /* Copy the argument vector */
1325 if (argc
> 0 && argv
!= NULL
)
1327 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1328 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1329 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1331 ControlPacket
->dwArgumentsCount
= argc
;
1332 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1334 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1335 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1337 for (i
= 0; i
< argc
; i
++)
1339 wcscpy(pArgPtr
, argv
[i
]);
1340 pOffPtr
[i
] = (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1341 DPRINT("offset[%lu]: %p\n", i
, pOffPtr
[i
]);
1342 pArgPtr
+= wcslen(argv
[i
]) + 1;
1346 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1351 if (bResult
== FALSE
)
1353 DPRINT("WriteFile() returned FALSE\n");
1355 dwError
= GetLastError();
1356 if (dwError
== ERROR_IO_PENDING
)
1358 DPRINT("dwError: ERROR_IO_PENDING\n");
1360 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1362 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1364 if (dwError
== WAIT_TIMEOUT
)
1366 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1367 if (bResult
== FALSE
)
1369 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1372 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1375 else if (dwError
== WAIT_OBJECT_0
)
1377 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1381 if (bResult
== FALSE
)
1383 dwError
= GetLastError();
1384 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1392 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1397 /* Read the reply */
1398 Overlapped
.hEvent
= (HANDLE
) NULL
;
1400 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1402 sizeof(SCM_REPLY_PACKET
),
1405 if (bResult
== FALSE
)
1407 DPRINT("ReadFile() returned FALSE\n");
1409 dwError
= GetLastError();
1410 if (dwError
== ERROR_IO_PENDING
)
1412 DPRINT("dwError: ERROR_IO_PENDING\n");
1414 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1416 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1418 if (dwError
== WAIT_TIMEOUT
)
1420 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1421 if (bResult
== FALSE
)
1423 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1426 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1429 else if (dwError
== WAIT_OBJECT_0
)
1431 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1435 if (bResult
== FALSE
)
1437 dwError
= GetLastError();
1438 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1446 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1452 /* Release the control packet */
1453 HeapFree(GetProcessHeap(),
1457 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1459 dwError
= ReplyPacket
.dwError
;
1462 DPRINT("ScmSendStartCommand() done\n");
1469 ScmWaitForServiceConnect(PSERVICE Service
)
1472 DWORD dwProcessId
= 0;
1473 DWORD dwError
= ERROR_SUCCESS
;
1475 OVERLAPPED Overlapped
= {0};
1477 LPCWSTR lpLogStrings
[3];
1478 WCHAR szBuffer1
[20];
1479 WCHAR szBuffer2
[20];
1482 DPRINT("ScmWaitForServiceConnect()\n");
1484 Overlapped
.hEvent
= (HANDLE
)NULL
;
1486 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1488 if (bResult
== FALSE
)
1490 DPRINT("ConnectNamedPipe() returned FALSE\n");
1492 dwError
= GetLastError();
1493 if (dwError
== ERROR_IO_PENDING
)
1495 DPRINT("dwError: ERROR_IO_PENDING\n");
1497 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1499 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1501 if (dwError
== WAIT_TIMEOUT
)
1503 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1505 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1506 if (bResult
== FALSE
)
1508 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1512 _ultow(PipeTimeout
, szBuffer1
, 10);
1513 lpLogStrings
[0] = Service
->lpDisplayName
;
1514 lpLogStrings
[1] = szBuffer1
;
1516 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1517 EVENTLOG_ERROR_TYPE
,
1521 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1523 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1525 else if (dwError
== WAIT_OBJECT_0
)
1527 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1531 if (bResult
== FALSE
)
1533 dwError
= GetLastError();
1534 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1540 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1542 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1547 DPRINT("Control pipe connected!\n");
1549 Overlapped
.hEvent
= (HANDLE
) NULL
;
1551 /* Read the process id from pipe */
1552 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1553 (LPVOID
)&dwProcessId
,
1557 if (bResult
== FALSE
)
1559 DPRINT("ReadFile() returned FALSE\n");
1561 dwError
= GetLastError();
1562 if (dwError
== ERROR_IO_PENDING
)
1564 DPRINT("dwError: ERROR_IO_PENDING\n");
1566 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1568 if (dwError
== WAIT_TIMEOUT
)
1570 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1572 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1573 if (bResult
== FALSE
)
1575 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1579 _ultow(PipeTimeout
, szBuffer1
, 10);
1580 lpLogStrings
[0] = szBuffer1
;
1582 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1583 EVENTLOG_ERROR_TYPE
,
1587 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1589 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1591 else if (dwError
== WAIT_OBJECT_0
)
1593 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1595 DPRINT("Process Id: %lu\n", dwProcessId
);
1597 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1601 if (bResult
== FALSE
)
1603 dwError
= GetLastError();
1604 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1611 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1616 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1621 if (dwProcessId
!= Service
->lpImage
->dwProcessId
)
1624 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1625 _ultow(dwProcessId
, szBuffer2
, 10);
1627 lpLogStrings
[0] = Service
->lpDisplayName
;
1628 lpLogStrings
[1] = szBuffer1
;
1629 lpLogStrings
[2] = szBuffer2
;
1631 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1632 EVENTLOG_WARNING_TYPE
,
1637 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1640 DPRINT("ScmWaitForServiceConnect() done\n");
1642 return ERROR_SUCCESS
;
1647 ScmStartUserModeService(PSERVICE Service
,
1651 PROCESS_INFORMATION ProcessInformation
;
1652 STARTUPINFOW StartupInfo
;
1653 LPVOID lpEnvironment
;
1655 DWORD dwError
= ERROR_SUCCESS
;
1657 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1659 /* If the image is already running ... */
1660 if (Service
->lpImage
->dwImageRunCount
> 1)
1662 /* ... just send a start command */
1663 return ScmSendStartCommand(Service
, argc
, argv
);
1666 /* Otherwise start its process */
1667 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1668 StartupInfo
.cb
= sizeof(StartupInfo
);
1669 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1671 /* Use the interactive desktop if the service is interactive */
1672 if ((NoInteractiveServices
== 0) &&
1673 (Service
->Status
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
))
1674 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
1676 if (Service
->lpImage
->hToken
)
1678 /* User token: Run the service under the user account */
1680 if (!CreateEnvironmentBlock(&lpEnvironment
, Service
->lpImage
->hToken
, FALSE
))
1682 /* We failed, run the service with the current environment */
1683 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1684 GetLastError(), Service
->lpServiceName
);
1685 lpEnvironment
= NULL
;
1688 /* Impersonate the new user */
1689 Result
= ImpersonateLoggedOnUser(Service
->lpImage
->hToken
);
1692 /* Launch the process in the user's logon session */
1693 Result
= CreateProcessAsUserW(Service
->lpImage
->hToken
,
1695 Service
->lpImage
->pszImagePath
,
1699 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1703 &ProcessInformation
);
1705 dwError
= GetLastError();
1707 /* Revert the impersonation */
1712 dwError
= GetLastError();
1713 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError
);
1718 /* No user token: Run the service under the LocalSystem account */
1720 if (!CreateEnvironmentBlock(&lpEnvironment
, NULL
, TRUE
))
1722 /* We failed, run the service with the current environment */
1723 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1724 GetLastError(), Service
->lpServiceName
);
1725 lpEnvironment
= NULL
;
1728 Result
= CreateProcessW(NULL
,
1729 Service
->lpImage
->pszImagePath
,
1733 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1737 &ProcessInformation
);
1739 dwError
= GetLastError();
1743 DestroyEnvironmentBlock(lpEnvironment
);
1747 DPRINT1("Starting '%S' failed with error %d\n",
1748 Service
->lpServiceName
, dwError
);
1752 DPRINT("Process Id: %lu Handle %p\n",
1753 ProcessInformation
.dwProcessId
,
1754 ProcessInformation
.hProcess
);
1755 DPRINT("Thread Id: %lu Handle %p\n",
1756 ProcessInformation
.dwThreadId
,
1757 ProcessInformation
.hThread
);
1759 /* Get the process handle and ID */
1760 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1761 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1763 /* Resume the main thread and close its handle */
1764 ResumeThread(ProcessInformation
.hThread
);
1765 CloseHandle(ProcessInformation
.hThread
);
1767 /* Connect control pipe */
1768 dwError
= ScmWaitForServiceConnect(Service
);
1769 if (dwError
!= ERROR_SUCCESS
)
1771 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1772 Service
->lpImage
->dwProcessId
= 0;
1776 /* Send the start command */
1777 return ScmSendStartCommand(Service
, argc
, argv
);
1782 ScmLoadService(PSERVICE Service
,
1786 PSERVICE_GROUP Group
= Service
->lpGroup
;
1787 DWORD dwError
= ERROR_SUCCESS
;
1788 LPCWSTR lpLogStrings
[2];
1789 WCHAR szLogBuffer
[80];
1791 DPRINT("ScmLoadService() called\n");
1792 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1794 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1796 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1797 return ERROR_SERVICE_ALREADY_RUNNING
;
1800 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1802 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1805 dwError
= ScmLoadDriver(Service
);
1806 if (dwError
== ERROR_SUCCESS
)
1808 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1809 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1812 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1814 /* Start user-mode service */
1815 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1816 if (dwError
== ERROR_SUCCESS
)
1818 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1819 if (dwError
== ERROR_SUCCESS
)
1821 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1822 Service
->Status
.dwControlsAccepted
= 0;
1826 ScmDereferenceServiceImage(Service
->lpImage
);
1827 Service
->lpImage
= NULL
;
1832 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
1834 if (dwError
== ERROR_SUCCESS
)
1838 Group
->ServicesRunning
= TRUE
;
1841 /* Log a successful service start */
1842 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
1843 lpLogStrings
[0] = Service
->lpDisplayName
;
1844 lpLogStrings
[1] = szLogBuffer
;
1846 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1847 EVENTLOG_INFORMATION_TYPE
,
1853 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1855 /* Log a failed service start */
1856 swprintf(szLogBuffer
, L
"%lu", dwError
);
1857 lpLogStrings
[0] = Service
->lpServiceName
;
1858 lpLogStrings
[1] = szLogBuffer
;
1859 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
1860 EVENTLOG_ERROR_TYPE
,
1866 switch (Service
->dwErrorControl
)
1868 case SERVICE_ERROR_SEVERE
:
1869 if (IsLastKnownGood
== FALSE
)
1871 /* FIXME: Boot last known good configuration */
1875 case SERVICE_ERROR_CRITICAL
:
1876 if (IsLastKnownGood
== FALSE
)
1878 /* FIXME: Boot last known good configuration */
1894 ScmStartService(PSERVICE Service
,
1898 DWORD dwError
= ERROR_SUCCESS
;
1899 SC_RPC_LOCK Lock
= NULL
;
1901 DPRINT("ScmStartService() called\n");
1902 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1904 /* Acquire the service control critical section, to synchronize starts */
1905 EnterCriticalSection(&ControlServiceCriticalSection
);
1908 * Acquire the user service start lock while the service is starting, if
1909 * needed (i.e. if we are not starting it during the initialization phase).
1910 * If we don't success, bail out.
1914 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
1915 if (dwError
!= ERROR_SUCCESS
) goto done
;
1918 /* Really start the service */
1919 dwError
= ScmLoadService(Service
, argc
, argv
);
1921 /* Release the service start lock, if needed, and the critical section */
1922 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
1925 LeaveCriticalSection(&ControlServiceCriticalSection
);
1927 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1934 ScmAutoStartServices(VOID
)
1937 PLIST_ENTRY GroupEntry
;
1938 PLIST_ENTRY ServiceEntry
;
1939 PSERVICE_GROUP CurrentGroup
;
1940 PSERVICE CurrentService
;
1941 WCHAR szSafeBootServicePath
[MAX_PATH
];
1942 DWORD SafeBootEnabled
;
1948 * This function MUST be called ONLY at initialization time.
1949 * Therefore, no need to acquire the user service start lock.
1951 ASSERT(ScmInitialize
);
1953 /* Retrieve the SafeBoot parameter */
1954 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1955 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
1959 if (dwError
== ERROR_SUCCESS
)
1961 dwKeySize
= sizeof(SafeBootEnabled
);
1962 dwError
= RegQueryValueExW(hKey
,
1966 (LPBYTE
)&SafeBootEnabled
,
1971 /* Default to Normal boot if the value doesn't exist */
1972 if (dwError
!= ERROR_SUCCESS
)
1973 SafeBootEnabled
= 0;
1975 /* Acquire the service control critical section, to synchronize starts */
1976 EnterCriticalSection(&ControlServiceCriticalSection
);
1978 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1979 ServiceEntry
= ServiceListHead
.Flink
;
1980 while (ServiceEntry
!= &ServiceListHead
)
1982 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1984 /* Build the safe boot path */
1985 wcscpy(szSafeBootServicePath
,
1986 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1988 switch (SafeBootEnabled
)
1990 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1993 wcscat(szSafeBootServicePath
, L
"\\Minimal\\");
1997 wcscat(szSafeBootServicePath
, L
"\\Network\\");
2001 if (SafeBootEnabled
!= 0)
2003 /* If key does not exist then do not assume safe mode */
2004 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2005 szSafeBootServicePath
,
2009 if (dwError
== ERROR_SUCCESS
)
2013 /* Finish Safe Boot path off */
2014 wcsncat(szSafeBootServicePath
,
2015 CurrentService
->lpServiceName
,
2016 MAX_PATH
- wcslen(szSafeBootServicePath
));
2018 /* Check that the key is in the Safe Boot path */
2019 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2020 szSafeBootServicePath
,
2024 if (dwError
!= ERROR_SUCCESS
)
2026 /* Mark service as visited so it is not auto-started */
2027 CurrentService
->ServiceVisited
= TRUE
;
2031 /* Must be auto-started in safe mode - mark as unvisited */
2033 CurrentService
->ServiceVisited
= FALSE
;
2038 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2039 CurrentService
->ServiceVisited
= FALSE
;
2043 ServiceEntry
= ServiceEntry
->Flink
;
2046 /* Start all services which are members of an existing group */
2047 GroupEntry
= GroupListHead
.Flink
;
2048 while (GroupEntry
!= &GroupListHead
)
2050 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
2052 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
2054 /* Start all services witch have a valid tag */
2055 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
2057 ServiceEntry
= ServiceListHead
.Flink
;
2058 while (ServiceEntry
!= &ServiceListHead
)
2060 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2062 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2063 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2064 (CurrentService
->ServiceVisited
== FALSE
) &&
2065 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
2067 CurrentService
->ServiceVisited
= TRUE
;
2068 ScmLoadService(CurrentService
, 0, NULL
);
2071 ServiceEntry
= ServiceEntry
->Flink
;
2075 /* Start all services which have an invalid tag or which do not have a tag */
2076 ServiceEntry
= ServiceListHead
.Flink
;
2077 while (ServiceEntry
!= &ServiceListHead
)
2079 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2081 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2082 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2083 (CurrentService
->ServiceVisited
== FALSE
))
2085 CurrentService
->ServiceVisited
= TRUE
;
2086 ScmLoadService(CurrentService
, 0, NULL
);
2089 ServiceEntry
= ServiceEntry
->Flink
;
2092 GroupEntry
= GroupEntry
->Flink
;
2095 /* Start all services which are members of any non-existing group */
2096 ServiceEntry
= ServiceListHead
.Flink
;
2097 while (ServiceEntry
!= &ServiceListHead
)
2099 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2101 if ((CurrentService
->lpGroup
!= NULL
) &&
2102 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2103 (CurrentService
->ServiceVisited
== FALSE
))
2105 CurrentService
->ServiceVisited
= TRUE
;
2106 ScmLoadService(CurrentService
, 0, NULL
);
2109 ServiceEntry
= ServiceEntry
->Flink
;
2112 /* Start all services which are not a member of any group */
2113 ServiceEntry
= ServiceListHead
.Flink
;
2114 while (ServiceEntry
!= &ServiceListHead
)
2116 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2118 if ((CurrentService
->lpGroup
== NULL
) &&
2119 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2120 (CurrentService
->ServiceVisited
== FALSE
))
2122 CurrentService
->ServiceVisited
= TRUE
;
2123 ScmLoadService(CurrentService
, 0, NULL
);
2126 ServiceEntry
= ServiceEntry
->Flink
;
2129 /* Clear 'ServiceVisited' flag again */
2130 ServiceEntry
= ServiceListHead
.Flink
;
2131 while (ServiceEntry
!= &ServiceListHead
)
2133 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2134 CurrentService
->ServiceVisited
= FALSE
;
2135 ServiceEntry
= ServiceEntry
->Flink
;
2138 /* Release the critical section */
2139 LeaveCriticalSection(&ControlServiceCriticalSection
);
2144 ScmAutoShutdownServices(VOID
)
2146 PLIST_ENTRY ServiceEntry
;
2147 PSERVICE CurrentService
;
2149 DPRINT("ScmAutoShutdownServices() called\n");
2151 /* Lock the service database exclusively */
2152 ScmLockDatabaseExclusive();
2154 ServiceEntry
= ServiceListHead
.Flink
;
2155 while (ServiceEntry
!= &ServiceListHead
)
2157 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2159 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2160 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
2162 /* shutdown service */
2163 DPRINT("Shutdown service: %S\n", CurrentService
->szServiceName
);
2164 ScmControlService(CurrentService
, SERVICE_CONTROL_SHUTDOWN
);
2167 ServiceEntry
= ServiceEntry
->Flink
;
2170 /* Unlock the service database */
2171 ScmUnlockDatabase();
2173 DPRINT("ScmAutoShutdownServices() done\n");
2178 ScmLockDatabaseExclusive(VOID
)
2180 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2185 ScmLockDatabaseShared(VOID
)
2187 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2192 ScmUnlockDatabase(VOID
)
2194 RtlReleaseResource(&DatabaseLock
);
2199 ScmInitNamedPipeCriticalSection(VOID
)
2205 InitializeCriticalSection(&ControlServiceCriticalSection
);
2207 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2208 L
"SYSTEM\\CurrentControlSet\\Control",
2212 if (dwError
== ERROR_SUCCESS
)
2214 dwKeySize
= sizeof(PipeTimeout
);
2215 RegQueryValueExW(hKey
,
2216 L
"ServicesPipeTimeout",
2219 (LPBYTE
)&PipeTimeout
,
2227 ScmDeleteNamedPipeCriticalSection(VOID
)
2229 DeleteCriticalSection(&ControlServiceCriticalSection
);