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 * Uncomment the line below to use asynchronous IO operations
24 * on the service control pipes.
26 #define USE_ASYNCHRONOUS_IO
29 /* GLOBALS *******************************************************************/
31 LIST_ENTRY ImageListHead
;
32 LIST_ENTRY ServiceListHead
;
34 static RTL_RESOURCE DatabaseLock
;
35 static DWORD ResumeCount
= 1;
37 /* The critical section synchronizes service control requests */
38 static CRITICAL_SECTION ControlServiceCriticalSection
;
39 static DWORD PipeTimeout
= 30000; /* 30 Seconds */
42 /* FUNCTIONS *****************************************************************/
45 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
47 WCHAR szControlPipeName
[MAX_PATH
+ 1];
48 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
49 DWORD ServiceCurrent
= 0;
54 /* Get the service number */
55 /* TODO: Create registry entry with correct write access */
56 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
57 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
63 if (dwError
!= ERROR_SUCCESS
)
65 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
69 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
71 dwKeySize
= sizeof(DWORD
);
72 dwError
= RegQueryValueExW(hServiceCurrentKey
,
73 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
75 if (dwError
!= ERROR_SUCCESS
)
77 RegCloseKey(hServiceCurrentKey
);
78 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
85 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
87 RegCloseKey(hServiceCurrentKey
);
89 if (dwError
!= ERROR_SUCCESS
)
91 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
95 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
96 swprintf(szControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent
);
98 DPRINT("PipeName: %S\n", szControlPipeName
);
100 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
101 #ifdef USE_ASYNCHRONOUS_IO
102 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
106 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
112 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
113 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
115 DPRINT1("Failed to create control pipe!\n");
116 return GetLastError();
119 return ERROR_SUCCESS
;
123 static PSERVICE_IMAGE
124 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
126 PLIST_ENTRY ImageEntry
;
127 PSERVICE_IMAGE CurrentImage
;
129 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
131 ImageEntry
= ImageListHead
.Flink
;
132 while (ImageEntry
!= &ImageListHead
)
134 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
137 if (_wcsicmp(CurrentImage
->pszImagePath
, lpImagePath
) == 0)
139 DPRINT("Found image: '%S'\n", CurrentImage
->pszImagePath
);
143 ImageEntry
= ImageEntry
->Flink
;
146 DPRINT("Couldn't find a matching image\n");
155 ScmIsSameServiceAccount(
156 _In_ PCWSTR pszAccountName1
,
157 _In_ PCWSTR pszAccountName2
)
159 if (pszAccountName1
== NULL
&& pszAccountName2
== NULL
)
162 if (pszAccountName1
== NULL
&& pszAccountName2
&& wcscmp(pszAccountName2
, L
"LocalSystem") == 0)
165 if (pszAccountName2
== NULL
&& pszAccountName1
&& wcscmp(pszAccountName1
, L
"LocalSystem") == 0)
168 if (pszAccountName1
&& pszAccountName2
&& wcscmp(pszAccountName1
, pszAccountName2
) == 0)
177 ScmIsLocalSystemAccount(
178 _In_ PCWSTR pszAccountName
)
180 if (pszAccountName
== NULL
||
181 wcscmp(pszAccountName
, L
"LocalSystem") == 0)
191 IN PSERVICE pService
,
192 IN PSERVICE_IMAGE pImage
)
194 PWSTR pUserName
= NULL
;
195 PWSTR pDomainName
= NULL
;
197 DWORD dwError
= ERROR_SUCCESS
;
199 DPRINT("ScmLogonService()\n");
201 DPRINT("Service %S\n", pService
->lpServiceName
);
203 if (ScmIsLocalSystemAccount(pImage
->pszAccountName
))
204 return ERROR_SUCCESS
;
206 ptr
= wcschr(pImage
->pszAccountName
, L
'\\');
212 pDomainName
= pImage
->pszAccountName
;
216 pUserName
= pImage
->pszAccountName
;
220 if (pDomainName
== NULL
|| wcscmp(pDomainName
, L
".") == 0)
222 // pDomainName = computer name
225 DPRINT("Domain: %S User: %S\n", pDomainName
, pUserName
);
229 if (!LogonUserW(pUserName
,
231 L
"", // lpszPassword,
232 LOGON32_LOGON_SERVICE
,
233 LOGON32_PROVIDER_DEFAULT
,
236 dwError
= GetLastError();
237 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError
);
249 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
251 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
252 UNICODE_STRING ImagePath
;
253 UNICODE_STRING ObjectName
;
254 PSERVICE_IMAGE pServiceImage
= NULL
;
256 DWORD dwError
= ERROR_SUCCESS
;
260 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
262 RtlInitUnicodeString(&ImagePath
, NULL
);
263 RtlInitUnicodeString(&ObjectName
, NULL
);
265 /* Get service data */
266 RtlZeroMemory(&QueryTable
,
269 QueryTable
[0].Name
= L
"ImagePath";
270 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
271 QueryTable
[0].EntryContext
= &ImagePath
;
272 QueryTable
[1].Name
= L
"ObjectName";
273 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
274 QueryTable
[1].EntryContext
= &ObjectName
;
276 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
277 pService
->lpServiceName
,
281 if (!NT_SUCCESS(Status
))
283 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
284 return RtlNtStatusToDosError(Status
);
287 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
288 DPRINT("ObjectName: '%wZ'\n", &ObjectName
);
290 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
291 if (pServiceImage
== NULL
)
293 dwRecordSize
= sizeof(SERVICE_IMAGE
) +
294 ImagePath
.Length
+ sizeof(WCHAR
) +
295 ((ObjectName
.Length
!= 0) ? (ObjectName
.Length
+ sizeof(WCHAR
)) : 0);
297 /* Create a new service image */
298 pServiceImage
= HeapAlloc(GetProcessHeap(),
301 if (pServiceImage
== NULL
)
303 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
307 pServiceImage
->dwImageRunCount
= 1;
308 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
309 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
311 pString
= (PWSTR
)((INT_PTR
)pServiceImage
+ sizeof(SERVICE_IMAGE
));
313 /* Set the image path */
314 pServiceImage
->pszImagePath
= pString
;
315 wcscpy(pServiceImage
->pszImagePath
,
318 /* Set the account name */
319 if (ObjectName
.Length
> 0)
321 pString
= pString
+ wcslen(pString
) + 1;
323 pServiceImage
->pszAccountName
= pString
;
324 wcscpy(pServiceImage
->pszAccountName
,
329 dwError
= ScmLogonService(pService
, pServiceImage
);
330 if (dwError
!= ERROR_SUCCESS
)
332 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError
);
334 /* Release the service image */
335 HeapFree(GetProcessHeap(), 0, pServiceImage
);
340 /* Create the control pipe */
341 dwError
= ScmCreateNewControlPipe(pServiceImage
);
342 if (dwError
!= ERROR_SUCCESS
)
344 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError
);
346 /* Close the logon token */
347 if (pServiceImage
->hToken
!= NULL
)
348 CloseHandle(pServiceImage
->hToken
);
350 /* Release the service image */
351 HeapFree(GetProcessHeap(), 0, pServiceImage
);
356 /* FIXME: Add more initialization code here */
359 /* Append service record */
360 InsertTailList(&ImageListHead
,
361 &pServiceImage
->ImageListEntry
);
365 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
367 /* Fail if services in an image use different accounts */
368 if (!ScmIsSameServiceAccount(pServiceImage
->pszAccountName
, ObjectName
.Buffer
))
370 dwError
= ERROR_DIFFERENT_SERVICE_ACCOUNT
;
374 /* Increment the run counter */
375 pServiceImage
->dwImageRunCount
++;
378 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage
->pszImagePath
);
379 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage
->pszAccountName
);
380 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
382 /* Link the service image to the service */
383 pService
->lpImage
= pServiceImage
;
386 RtlFreeUnicodeString(&ObjectName
);
387 RtlFreeUnicodeString(&ImagePath
);
389 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
396 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage
)
398 DPRINT1("ScmDereferenceServiceImage() called\n");
400 pServiceImage
->dwImageRunCount
--;
402 if (pServiceImage
->dwImageRunCount
== 0)
404 DPRINT1("dwImageRunCount == 0\n");
406 /* FIXME: Terminate the process */
408 /* Remove the service image from the list */
409 RemoveEntryList(&pServiceImage
->ImageListEntry
);
411 /* Close the process handle */
412 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
413 CloseHandle(pServiceImage
->hProcess
);
415 /* Close the control pipe */
416 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
417 CloseHandle(pServiceImage
->hControlPipe
);
419 /* Close the logon token */
420 if (pServiceImage
->hToken
!= NULL
)
421 CloseHandle(pServiceImage
->hToken
);
423 /* Release the service image */
424 HeapFree(GetProcessHeap(), 0, pServiceImage
);
430 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
432 PLIST_ENTRY ServiceEntry
;
433 PSERVICE CurrentService
;
435 DPRINT("ScmGetServiceEntryByName() called\n");
437 ServiceEntry
= ServiceListHead
.Flink
;
438 while (ServiceEntry
!= &ServiceListHead
)
440 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
443 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
445 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
446 return CurrentService
;
449 ServiceEntry
= ServiceEntry
->Flink
;
452 DPRINT("Couldn't find a matching service\n");
459 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
461 PLIST_ENTRY ServiceEntry
;
462 PSERVICE CurrentService
;
464 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
466 ServiceEntry
= ServiceListHead
.Flink
;
467 while (ServiceEntry
!= &ServiceListHead
)
469 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
472 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
474 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
475 return CurrentService
;
478 ServiceEntry
= ServiceEntry
->Flink
;
481 DPRINT("Couldn't find a matching service\n");
488 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
490 PLIST_ENTRY ServiceEntry
;
491 PSERVICE CurrentService
;
493 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
495 ServiceEntry
= ServiceListHead
.Flink
;
496 while (ServiceEntry
!= &ServiceListHead
)
498 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
501 if (CurrentService
->dwResumeCount
> dwResumeCount
)
503 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
504 return CurrentService
;
507 ServiceEntry
= ServiceEntry
->Flink
;
510 DPRINT("Couldn't find a matching service\n");
517 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
518 PSERVICE
* lpServiceRecord
)
520 PSERVICE lpService
= NULL
;
522 DPRINT("Service: '%S'\n", lpServiceName
);
524 /* Allocate service entry */
525 lpService
= HeapAlloc(GetProcessHeap(),
527 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
528 if (lpService
== NULL
)
529 return ERROR_NOT_ENOUGH_MEMORY
;
531 *lpServiceRecord
= lpService
;
533 /* Copy service name */
534 wcscpy(lpService
->szServiceName
, lpServiceName
);
535 lpService
->lpServiceName
= lpService
->szServiceName
;
536 lpService
->lpDisplayName
= lpService
->lpServiceName
;
538 /* Set the resume count */
539 lpService
->dwResumeCount
= ResumeCount
++;
541 /* Append service record */
542 InsertTailList(&ServiceListHead
,
543 &lpService
->ServiceListEntry
);
545 /* Initialize the service status */
546 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
547 lpService
->Status
.dwControlsAccepted
= 0;
548 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
549 lpService
->Status
.dwServiceSpecificExitCode
= 0;
550 lpService
->Status
.dwCheckPoint
= 0;
551 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
553 return ERROR_SUCCESS
;
558 ScmDeleteServiceRecord(PSERVICE lpService
)
560 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
562 /* Delete the display name */
563 if (lpService
->lpDisplayName
!= NULL
&&
564 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
565 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
567 /* Dereference the service image */
568 if (lpService
->lpImage
)
569 ScmDereferenceServiceImage(lpService
->lpImage
);
571 /* Decrement the group reference counter */
572 ScmSetServiceGroup(lpService
, NULL
);
574 /* Release the SecurityDescriptor */
575 if (lpService
->pSecurityDescriptor
!= NULL
)
576 HeapFree(GetProcessHeap(), 0, lpService
->pSecurityDescriptor
);
578 /* Remove the Service from the List */
579 RemoveEntryList(&lpService
->ServiceListEntry
);
581 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
583 /* Delete the service record */
584 HeapFree(GetProcessHeap(), 0, lpService
);
591 CreateServiceListEntry(LPCWSTR lpServiceName
,
594 PSERVICE lpService
= NULL
;
595 LPWSTR lpDisplayName
= NULL
;
596 LPWSTR lpGroup
= NULL
;
601 DWORD dwErrorControl
;
604 DPRINT("Service: '%S'\n", lpServiceName
);
605 if (*lpServiceName
== L
'{')
606 return ERROR_SUCCESS
;
608 dwSize
= sizeof(DWORD
);
609 dwError
= RegQueryValueExW(hServiceKey
,
613 (LPBYTE
)&dwServiceType
,
615 if (dwError
!= ERROR_SUCCESS
)
616 return ERROR_SUCCESS
;
618 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
619 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
620 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
621 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
622 return ERROR_SUCCESS
;
624 DPRINT("Service type: %lx\n", dwServiceType
);
626 dwSize
= sizeof(DWORD
);
627 dwError
= RegQueryValueExW(hServiceKey
,
631 (LPBYTE
)&dwStartType
,
633 if (dwError
!= ERROR_SUCCESS
)
634 return ERROR_SUCCESS
;
636 DPRINT("Start type: %lx\n", dwStartType
);
638 dwSize
= sizeof(DWORD
);
639 dwError
= RegQueryValueExW(hServiceKey
,
643 (LPBYTE
)&dwErrorControl
,
645 if (dwError
!= ERROR_SUCCESS
)
646 return ERROR_SUCCESS
;
648 DPRINT("Error control: %lx\n", dwErrorControl
);
650 dwError
= RegQueryValueExW(hServiceKey
,
656 if (dwError
!= ERROR_SUCCESS
)
659 DPRINT("Tag: %lx\n", dwTagId
);
661 dwError
= ScmReadString(hServiceKey
,
664 if (dwError
!= ERROR_SUCCESS
)
667 DPRINT("Group: %S\n", lpGroup
);
669 dwError
= ScmReadString(hServiceKey
,
672 if (dwError
!= ERROR_SUCCESS
)
673 lpDisplayName
= NULL
;
675 DPRINT("Display name: %S\n", lpDisplayName
);
677 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
679 if (dwError
!= ERROR_SUCCESS
)
682 lpService
->Status
.dwServiceType
= dwServiceType
;
683 lpService
->dwStartType
= dwStartType
;
684 lpService
->dwErrorControl
= dwErrorControl
;
685 lpService
->dwTag
= dwTagId
;
689 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
690 if (dwError
!= ERROR_SUCCESS
)
694 if (lpDisplayName
!= NULL
)
696 lpService
->lpDisplayName
= lpDisplayName
;
697 lpDisplayName
= NULL
;
700 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
701 if (lpService
->lpGroup
!= NULL
)
703 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
705 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
706 lpService
->dwStartType
,
707 lpService
->Status
.dwServiceType
,
709 lpService
->dwErrorControl
);
711 if (ScmIsDeleteFlagSet(hServiceKey
))
712 lpService
->bDeleted
= TRUE
;
714 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
716 dwError
= ScmReadSecurityDescriptor(hServiceKey
,
717 &lpService
->pSecurityDescriptor
);
718 if (dwError
!= ERROR_SUCCESS
)
721 /* Assing the default security descriptor if the security descriptor cannot be read */
722 if (lpService
->pSecurityDescriptor
== NULL
)
724 DPRINT("No security descriptor found! Assign default security descriptor!\n");
725 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
726 if (dwError
!= ERROR_SUCCESS
)
729 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
730 lpService
->pSecurityDescriptor
);
731 if (dwError
!= ERROR_SUCCESS
)
738 HeapFree(GetProcessHeap(), 0, lpGroup
);
740 if (lpDisplayName
!= NULL
)
741 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
743 if (lpService
!= NULL
)
745 ASSERT(lpService
->lpImage
== NULL
);
753 ScmDeleteMarkedServices(VOID
)
755 PLIST_ENTRY ServiceEntry
;
756 PSERVICE CurrentService
;
760 ServiceEntry
= ServiceListHead
.Flink
;
761 while (ServiceEntry
!= &ServiceListHead
)
763 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
765 ServiceEntry
= ServiceEntry
->Flink
;
767 if (CurrentService
->bDeleted
== TRUE
)
769 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
770 L
"System\\CurrentControlSet\\Services",
774 if (dwError
== ERROR_SUCCESS
)
776 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
777 RegCloseKey(hServicesKey
);
778 if (dwError
== ERROR_SUCCESS
)
780 RemoveEntryList(&CurrentService
->ServiceListEntry
);
781 HeapFree(GetProcessHeap(), 0, CurrentService
);
785 if (dwError
!= ERROR_SUCCESS
)
786 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
793 ScmCreateServiceDatabase(VOID
)
795 WCHAR szSubKey
[MAX_PATH
];
799 DWORD dwSubKeyLength
;
800 FILETIME ftLastChanged
;
803 DPRINT("ScmCreateServiceDatabase() called\n");
805 dwError
= ScmCreateGroupList();
806 if (dwError
!= ERROR_SUCCESS
)
809 /* Initialize basic variables */
810 InitializeListHead(&ImageListHead
);
811 InitializeListHead(&ServiceListHead
);
813 /* Initialize the database lock */
814 RtlInitializeResource(&DatabaseLock
);
816 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
817 L
"System\\CurrentControlSet\\Services",
821 if (dwError
!= ERROR_SUCCESS
)
827 dwSubKeyLength
= MAX_PATH
;
828 dwError
= RegEnumKeyExW(hServicesKey
,
836 if (dwError
== ERROR_SUCCESS
&&
839 DPRINT("SubKeyName: '%S'\n", szSubKey
);
841 dwError
= RegOpenKeyExW(hServicesKey
,
846 if (dwError
== ERROR_SUCCESS
)
848 dwError
= CreateServiceListEntry(szSubKey
,
851 RegCloseKey(hServiceKey
);
855 if (dwError
!= ERROR_SUCCESS
)
861 RegCloseKey(hServicesKey
);
863 /* Wait for the LSA server */
866 /* Delete services that are marked for delete */
867 ScmDeleteMarkedServices();
869 DPRINT("ScmCreateServiceDatabase() done\n");
871 return ERROR_SUCCESS
;
876 ScmShutdownServiceDatabase(VOID
)
878 DPRINT("ScmShutdownServiceDatabase() called\n");
880 ScmDeleteMarkedServices();
881 RtlDeleteResource(&DatabaseLock
);
883 DPRINT("ScmShutdownServiceDatabase() done\n");
888 ScmCheckDriver(PSERVICE Service
)
890 OBJECT_ATTRIBUTES ObjectAttributes
;
891 UNICODE_STRING DirName
;
894 POBJECT_DIRECTORY_INFORMATION DirInfo
;
899 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
901 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
903 RtlInitUnicodeString(&DirName
, L
"\\Driver");
905 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
907 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
908 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
911 InitializeObjectAttributes(&ObjectAttributes
,
917 Status
= NtOpenDirectoryObject(&DirHandle
,
918 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
920 if (!NT_SUCCESS(Status
))
925 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
926 2 * MAX_PATH
* sizeof(WCHAR
);
927 DirInfo
= HeapAlloc(GetProcessHeap(),
934 Status
= NtQueryDirectoryObject(DirHandle
,
941 if (Status
== STATUS_NO_MORE_ENTRIES
)
943 /* FIXME: Add current service to 'failed service' list */
944 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
948 if (!NT_SUCCESS(Status
))
951 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
953 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
955 DPRINT("Found: '%S' '%wZ'\n",
956 Service
->lpServiceName
, &DirInfo
->Name
);
958 /* Mark service as 'running' */
959 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
961 /* Mark the service group as 'running' */
962 if (Service
->lpGroup
!= NULL
)
964 Service
->lpGroup
->ServicesRunning
= TRUE
;
971 HeapFree(GetProcessHeap(),
976 return STATUS_SUCCESS
;
981 ScmGetBootAndSystemDriverState(VOID
)
983 PLIST_ENTRY ServiceEntry
;
984 PSERVICE CurrentService
;
986 DPRINT("ScmGetBootAndSystemDriverState() called\n");
988 ServiceEntry
= ServiceListHead
.Flink
;
989 while (ServiceEntry
!= &ServiceListHead
)
991 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
993 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
994 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
997 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
999 ScmCheckDriver(CurrentService
);
1002 ServiceEntry
= ServiceEntry
->Flink
;
1005 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1010 ScmControlService(PSERVICE Service
,
1013 PSCM_CONTROL_PACKET ControlPacket
;
1014 SCM_REPLY_PACKET ReplyPacket
;
1016 DWORD dwWriteCount
= 0;
1017 DWORD dwReadCount
= 0;
1020 DWORD dwError
= ERROR_SUCCESS
;
1022 #ifdef USE_ASYNCHRONOUS_IO
1023 OVERLAPPED Overlapped
= {0};
1026 DPRINT("ScmControlService() called\n");
1028 /* Acquire the service control critical section, to synchronize requests */
1029 EnterCriticalSection(&ControlServiceCriticalSection
);
1031 /* Calculate the total length of the start command line */
1032 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1033 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1035 ControlPacket
= HeapAlloc(GetProcessHeap(),
1038 if (ControlPacket
== NULL
)
1040 LeaveCriticalSection(&ControlServiceCriticalSection
);
1041 return ERROR_NOT_ENOUGH_MEMORY
;
1044 ControlPacket
->dwSize
= PacketSize
;
1045 ControlPacket
->dwControl
= dwControl
;
1046 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1048 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1050 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1051 wcscpy(Ptr
, Service
->lpServiceName
);
1053 ControlPacket
->dwArgumentsCount
= 0;
1054 ControlPacket
->dwArgumentsOffset
= 0;
1056 #ifdef USE_ASYNCHRONOUS_IO
1057 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1062 if (bResult
== FALSE
)
1064 DPRINT("WriteFile() returned FALSE\n");
1066 dwError
= GetLastError();
1067 if (dwError
== ERROR_IO_PENDING
)
1069 DPRINT("dwError: ERROR_IO_PENDING\n");
1071 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1073 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1075 if (dwError
== WAIT_TIMEOUT
)
1077 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1078 if (bResult
== FALSE
)
1080 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1083 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1086 else if (dwError
== WAIT_OBJECT_0
)
1088 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1092 if (bResult
== FALSE
)
1094 dwError
= GetLastError();
1095 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1103 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1108 /* Read the reply */
1109 Overlapped
.hEvent
= (HANDLE
) NULL
;
1111 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1113 sizeof(SCM_REPLY_PACKET
),
1116 if (bResult
== FALSE
)
1118 DPRINT("ReadFile() returned FALSE\n");
1120 dwError
= GetLastError();
1121 if (dwError
== ERROR_IO_PENDING
)
1123 DPRINT("dwError: ERROR_IO_PENDING\n");
1125 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1127 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1129 if (dwError
== WAIT_TIMEOUT
)
1131 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1132 if (bResult
== FALSE
)
1134 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1137 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1140 else if (dwError
== WAIT_OBJECT_0
)
1142 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1146 if (bResult
== FALSE
)
1148 dwError
= GetLastError();
1149 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1157 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1163 /* Send the control packet */
1164 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1169 if (bResult
== FALSE
)
1171 dwError
= GetLastError();
1172 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1174 if ((dwError
== ERROR_GEN_FAILURE
) &&
1175 (dwControl
== SERVICE_CONTROL_STOP
))
1177 /* Service is already terminated */
1178 Service
->Status
.dwCurrentState
= SERVICE_STOPPED
;
1179 Service
->Status
.dwControlsAccepted
= 0;
1180 Service
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NOT_ACTIVE
;
1181 dwError
= ERROR_SUCCESS
;
1186 /* Read the reply */
1187 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1189 sizeof(SCM_REPLY_PACKET
),
1192 if (bResult
== FALSE
)
1194 dwError
= GetLastError();
1195 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1200 /* Release the control packet */
1201 HeapFree(GetProcessHeap(),
1205 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1207 dwError
= ReplyPacket
.dwError
;
1210 if (dwError
== ERROR_SUCCESS
&&
1211 dwControl
== SERVICE_CONTROL_STOP
)
1213 ScmDereferenceServiceImage(Service
->lpImage
);
1214 Service
->lpImage
= NULL
;
1217 LeaveCriticalSection(&ControlServiceCriticalSection
);
1219 DPRINT("ScmControlService() done\n");
1226 ScmSendStartCommand(PSERVICE Service
,
1230 DWORD dwError
= ERROR_SUCCESS
;
1231 PSCM_CONTROL_PACKET ControlPacket
;
1232 SCM_REPLY_PACKET ReplyPacket
;
1239 DWORD dwWriteCount
= 0;
1240 DWORD dwReadCount
= 0;
1241 #ifdef USE_ASYNCHRONOUS_IO
1242 OVERLAPPED Overlapped
= {0};
1245 DPRINT("ScmSendStartCommand() called\n");
1247 /* Calculate the total length of the start command line */
1248 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1249 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1252 * Calculate the required packet size for the start argument vector 'argv',
1253 * composed of the list of pointer offsets, followed by UNICODE strings.
1254 * The strings are stored continuously after the vector of offsets, with
1255 * the offsets being relative to the beginning of the vector, as in the
1256 * following layout (with N == argc):
1257 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1259 if (argc
> 0 && argv
!= NULL
)
1261 PacketSize
= ALIGN_UP(PacketSize
, PWSTR
);
1262 PacketSize
+= (argc
* sizeof(PWSTR
));
1264 DPRINT("Argc: %lu\n", argc
);
1265 for (i
= 0; i
< argc
; i
++)
1267 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1268 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
));
1272 /* Allocate a control packet */
1273 ControlPacket
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, PacketSize
);
1274 if (ControlPacket
== NULL
)
1275 return ERROR_NOT_ENOUGH_MEMORY
;
1277 ControlPacket
->dwSize
= PacketSize
;
1278 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1279 ? SERVICE_CONTROL_START_OWN
1280 : SERVICE_CONTROL_START_SHARE
;
1281 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1283 /* Copy the start command line */
1284 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1285 Ptr
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1286 wcscpy(Ptr
, Service
->lpServiceName
);
1288 ControlPacket
->dwArgumentsCount
= 0;
1289 ControlPacket
->dwArgumentsOffset
= 0;
1291 /* Copy the argument vector */
1292 if (argc
> 0 && argv
!= NULL
)
1294 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1295 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1296 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1298 ControlPacket
->dwArgumentsCount
= argc
;
1299 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1301 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1302 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1304 for (i
= 0; i
< argc
; i
++)
1306 wcscpy(pArgPtr
, argv
[i
]);
1307 pOffPtr
[i
] = (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1308 DPRINT("offset[%lu]: %p\n", i
, pOffPtr
[i
]);
1309 pArgPtr
+= wcslen(argv
[i
]) + 1;
1313 #ifdef USE_ASYNCHRONOUS_IO
1314 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1319 if (bResult
== FALSE
)
1321 DPRINT("WriteFile() returned FALSE\n");
1323 dwError
= GetLastError();
1324 if (dwError
== ERROR_IO_PENDING
)
1326 DPRINT("dwError: ERROR_IO_PENDING\n");
1328 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1330 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1332 if (dwError
== WAIT_TIMEOUT
)
1334 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1335 if (bResult
== FALSE
)
1337 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1340 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1343 else if (dwError
== WAIT_OBJECT_0
)
1345 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1349 if (bResult
== FALSE
)
1351 dwError
= GetLastError();
1352 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1360 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1365 /* Read the reply */
1366 Overlapped
.hEvent
= (HANDLE
) NULL
;
1368 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1370 sizeof(SCM_REPLY_PACKET
),
1373 if (bResult
== FALSE
)
1375 DPRINT("ReadFile() returned FALSE\n");
1377 dwError
= GetLastError();
1378 if (dwError
== ERROR_IO_PENDING
)
1380 DPRINT("dwError: ERROR_IO_PENDING\n");
1382 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1384 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1386 if (dwError
== WAIT_TIMEOUT
)
1388 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1389 if (bResult
== FALSE
)
1391 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1394 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1397 else if (dwError
== WAIT_OBJECT_0
)
1399 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1403 if (bResult
== FALSE
)
1405 dwError
= GetLastError();
1406 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1414 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1420 /* Send the start command */
1421 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1426 if (bResult
== FALSE
)
1428 dwError
= GetLastError();
1429 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1433 /* Read the reply */
1434 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1436 sizeof(SCM_REPLY_PACKET
),
1439 if (bResult
== FALSE
)
1441 dwError
= GetLastError();
1442 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1447 /* Release the control packet */
1448 HeapFree(GetProcessHeap(),
1452 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1454 dwError
= ReplyPacket
.dwError
;
1457 DPRINT("ScmSendStartCommand() done\n");
1464 ScmWaitForServiceConnect(PSERVICE Service
)
1467 DWORD dwProcessId
= 0;
1468 DWORD dwError
= ERROR_SUCCESS
;
1470 #ifdef USE_ASYNCHRONOUS_IO
1471 OVERLAPPED Overlapped
= {0};
1474 LPCWSTR lpLogStrings
[3];
1475 WCHAR szBuffer1
[20];
1476 WCHAR szBuffer2
[20];
1479 DPRINT("ScmWaitForServiceConnect()\n");
1481 #ifdef USE_ASYNCHRONOUS_IO
1482 Overlapped
.hEvent
= (HANDLE
)NULL
;
1484 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1486 if (bResult
== FALSE
)
1488 DPRINT("ConnectNamedPipe() returned FALSE\n");
1490 dwError
= GetLastError();
1491 if (dwError
== ERROR_IO_PENDING
)
1493 DPRINT("dwError: ERROR_IO_PENDING\n");
1495 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1497 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1499 if (dwError
== WAIT_TIMEOUT
)
1501 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1503 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1504 if (bResult
== FALSE
)
1506 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1510 _ultow(PipeTimeout
, szBuffer1
, 10);
1511 lpLogStrings
[0] = Service
->lpDisplayName
;
1512 lpLogStrings
[1] = szBuffer1
;
1514 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1515 EVENTLOG_ERROR_TYPE
,
1519 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1521 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1523 else if (dwError
== WAIT_OBJECT_0
)
1525 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1529 if (bResult
== FALSE
)
1531 dwError
= GetLastError();
1532 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1538 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1540 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1545 DPRINT("Control pipe connected!\n");
1547 Overlapped
.hEvent
= (HANDLE
) NULL
;
1549 /* Read the process id from pipe */
1550 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1551 (LPVOID
)&dwProcessId
,
1555 if (bResult
== FALSE
)
1557 DPRINT("ReadFile() returned FALSE\n");
1559 dwError
= GetLastError();
1560 if (dwError
== ERROR_IO_PENDING
)
1562 DPRINT("dwError: ERROR_IO_PENDING\n");
1564 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1566 if (dwError
== WAIT_TIMEOUT
)
1568 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1570 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1571 if (bResult
== FALSE
)
1573 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1577 _ultow(PipeTimeout
, szBuffer1
, 10);
1578 lpLogStrings
[0] = szBuffer1
;
1580 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1581 EVENTLOG_ERROR_TYPE
,
1585 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1587 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1589 else if (dwError
== WAIT_OBJECT_0
)
1591 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1593 DPRINT("Process Id: %lu\n", dwProcessId
);
1595 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1599 if (bResult
== FALSE
)
1601 dwError
= GetLastError();
1602 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1609 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1614 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1619 if (dwProcessId
!= Service
->lpImage
->dwProcessId
)
1622 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1623 _ultow(dwProcessId
, szBuffer2
, 10);
1625 lpLogStrings
[0] = Service
->lpDisplayName
;
1626 lpLogStrings
[1] = szBuffer1
;
1627 lpLogStrings
[2] = szBuffer2
;
1629 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1630 EVENTLOG_WARNING_TYPE
,
1635 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1638 DPRINT("ScmWaitForServiceConnect() done\n");
1640 return ERROR_SUCCESS
;
1643 /* Connect control pipe */
1644 if (ConnectNamedPipe(Service
->lpImage
->hControlPipe
, NULL
) ?
1645 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
1647 DPRINT("Control pipe connected!\n");
1649 /* Read SERVICE_STATUS_HANDLE from pipe */
1650 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1651 (LPVOID
)&dwProcessId
,
1655 if (bResult
== FALSE
)
1657 dwError
= GetLastError();
1658 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1663 dwError
= ERROR_SUCCESS
;
1664 DPRINT("Read control pipe successfully\n");
1669 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1678 ScmStartUserModeService(PSERVICE Service
,
1682 PROCESS_INFORMATION ProcessInformation
;
1683 STARTUPINFOW StartupInfo
;
1684 LPVOID lpEnvironment
;
1686 DWORD dwError
= ERROR_SUCCESS
;
1688 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1690 /* If the image is already running ... */
1691 if (Service
->lpImage
->dwImageRunCount
> 1)
1693 /* ... just send a start command */
1694 return ScmSendStartCommand(Service
, argc
, argv
);
1697 /* Otherwise start its process */
1698 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1699 StartupInfo
.cb
= sizeof(StartupInfo
);
1700 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1702 /* Use the interactive desktop if the service is interactive */
1703 // TODO: We should also check the value "NoInteractiveServices ":
1704 // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683502(v=vs.85).aspx
1705 // for more details.
1706 if (Service
->Status
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
)
1707 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
1709 if (Service
->lpImage
->hToken
)
1711 /* User token: Run the service under the user account */
1713 if (!CreateEnvironmentBlock(&lpEnvironment
, Service
->lpImage
->hToken
, FALSE
))
1715 /* We failed, run the service with the current environment */
1716 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1717 GetLastError(), Service
->lpServiceName
);
1718 lpEnvironment
= NULL
;
1721 /* Impersonate the new user */
1722 Result
= ImpersonateLoggedOnUser(Service
->lpImage
->hToken
);
1725 /* Launch the process in the user's logon session */
1726 Result
= CreateProcessAsUserW(Service
->lpImage
->hToken
,
1728 Service
->lpImage
->pszImagePath
,
1732 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1736 &ProcessInformation
);
1738 dwError
= GetLastError();
1740 /* Revert the impersonation */
1745 dwError
= GetLastError();
1746 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError
);
1751 /* No user token: Run the service under the LocalSystem account */
1753 if (!CreateEnvironmentBlock(&lpEnvironment
, NULL
, TRUE
))
1755 /* We failed, run the service with the current environment */
1756 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1757 GetLastError(), Service
->lpServiceName
);
1758 lpEnvironment
= NULL
;
1761 Result
= CreateProcessW(NULL
,
1762 Service
->lpImage
->pszImagePath
,
1766 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1770 &ProcessInformation
);
1772 dwError
= GetLastError();
1776 DestroyEnvironmentBlock(lpEnvironment
);
1780 DPRINT1("Starting '%S' failed with error %d\n",
1781 Service
->lpServiceName
, dwError
);
1785 DPRINT("Process Id: %lu Handle %p\n",
1786 ProcessInformation
.dwProcessId
,
1787 ProcessInformation
.hProcess
);
1788 DPRINT("Thread Id: %lu Handle %p\n",
1789 ProcessInformation
.dwThreadId
,
1790 ProcessInformation
.hThread
);
1792 /* Get the process handle and ID */
1793 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1794 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1796 /* Resume the main thread and close its handle */
1797 ResumeThread(ProcessInformation
.hThread
);
1798 CloseHandle(ProcessInformation
.hThread
);
1800 /* Connect control pipe */
1801 dwError
= ScmWaitForServiceConnect(Service
);
1802 if (dwError
!= ERROR_SUCCESS
)
1804 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1805 Service
->lpImage
->dwProcessId
= 0;
1809 /* Send the start command */
1810 return ScmSendStartCommand(Service
, argc
, argv
);
1815 ScmLoadService(PSERVICE Service
,
1819 PSERVICE_GROUP Group
= Service
->lpGroup
;
1820 DWORD dwError
= ERROR_SUCCESS
;
1821 LPCWSTR lpLogStrings
[2];
1822 WCHAR szLogBuffer
[80];
1824 DPRINT("ScmLoadService() called\n");
1825 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1827 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1829 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1830 return ERROR_SERVICE_ALREADY_RUNNING
;
1833 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1835 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1838 dwError
= ScmLoadDriver(Service
);
1839 if (dwError
== ERROR_SUCCESS
)
1841 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1842 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1845 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1847 /* Start user-mode service */
1848 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1849 if (dwError
== ERROR_SUCCESS
)
1851 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1852 if (dwError
== ERROR_SUCCESS
)
1854 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1855 Service
->Status
.dwControlsAccepted
= 0;
1859 ScmDereferenceServiceImage(Service
->lpImage
);
1860 Service
->lpImage
= NULL
;
1865 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
1867 if (dwError
== ERROR_SUCCESS
)
1871 Group
->ServicesRunning
= TRUE
;
1874 /* Log a successful service start */
1875 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
1876 lpLogStrings
[0] = Service
->lpDisplayName
;
1877 lpLogStrings
[1] = szLogBuffer
;
1879 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1880 EVENTLOG_INFORMATION_TYPE
,
1886 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1888 /* Log a failed service start */
1889 swprintf(szLogBuffer
, L
"%lu", dwError
);
1890 lpLogStrings
[0] = Service
->lpServiceName
;
1891 lpLogStrings
[1] = szLogBuffer
;
1892 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
1893 EVENTLOG_ERROR_TYPE
,
1899 switch (Service
->dwErrorControl
)
1901 case SERVICE_ERROR_SEVERE
:
1902 if (IsLastKnownGood
== FALSE
)
1904 /* FIXME: Boot last known good configuration */
1908 case SERVICE_ERROR_CRITICAL
:
1909 if (IsLastKnownGood
== FALSE
)
1911 /* FIXME: Boot last known good configuration */
1927 ScmStartService(PSERVICE Service
,
1931 DWORD dwError
= ERROR_SUCCESS
;
1932 SC_RPC_LOCK Lock
= NULL
;
1934 DPRINT("ScmStartService() called\n");
1935 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1937 /* Acquire the service control critical section, to synchronize starts */
1938 EnterCriticalSection(&ControlServiceCriticalSection
);
1941 * Acquire the user service start lock while the service is starting, if
1942 * needed (i.e. if we are not starting it during the initialization phase).
1943 * If we don't success, bail out.
1947 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
1948 if (dwError
!= ERROR_SUCCESS
) goto done
;
1951 /* Really start the service */
1952 dwError
= ScmLoadService(Service
, argc
, argv
);
1954 /* Release the service start lock, if needed, and the critical section */
1955 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
1958 LeaveCriticalSection(&ControlServiceCriticalSection
);
1960 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1967 ScmAutoStartServices(VOID
)
1970 PLIST_ENTRY GroupEntry
;
1971 PLIST_ENTRY ServiceEntry
;
1972 PSERVICE_GROUP CurrentGroup
;
1973 PSERVICE CurrentService
;
1974 WCHAR szSafeBootServicePath
[MAX_PATH
];
1975 DWORD SafeBootEnabled
;
1981 * This function MUST be called ONLY at initialization time.
1982 * Therefore, no need to acquire the user service start lock.
1984 ASSERT(ScmInitialize
);
1987 * Retrieve the SafeBoot parameter.
1989 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1990 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
1994 if (dwError
== ERROR_SUCCESS
)
1996 dwKeySize
= sizeof(SafeBootEnabled
);
1997 dwError
= RegQueryValueExW(hKey
,
2001 (LPBYTE
)&SafeBootEnabled
,
2006 /* Default to Normal boot if the value doesn't exist */
2007 if (dwError
!= ERROR_SUCCESS
)
2008 SafeBootEnabled
= 0;
2010 /* Acquire the service control critical section, to synchronize starts */
2011 EnterCriticalSection(&ControlServiceCriticalSection
);
2013 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
2014 ServiceEntry
= ServiceListHead
.Flink
;
2015 while (ServiceEntry
!= &ServiceListHead
)
2017 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2019 /* Build the safe boot path */
2020 wcscpy(szSafeBootServicePath
,
2021 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
2023 switch (SafeBootEnabled
)
2025 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
2028 wcscat(szSafeBootServicePath
, L
"\\Minimal\\");
2032 wcscat(szSafeBootServicePath
, L
"\\Network\\");
2036 if (SafeBootEnabled
!= 0)
2038 /* If key does not exist then do not assume safe mode */
2039 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2040 szSafeBootServicePath
,
2044 if (dwError
== ERROR_SUCCESS
)
2048 /* Finish Safe Boot path off */
2049 wcsncat(szSafeBootServicePath
,
2050 CurrentService
->lpServiceName
,
2051 MAX_PATH
- wcslen(szSafeBootServicePath
));
2053 /* Check that the key is in the Safe Boot path */
2054 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2055 szSafeBootServicePath
,
2059 if (dwError
!= ERROR_SUCCESS
)
2061 /* Mark service as visited so it is not auto-started */
2062 CurrentService
->ServiceVisited
= TRUE
;
2066 /* Must be auto-started in safe mode - mark as unvisited */
2068 CurrentService
->ServiceVisited
= FALSE
;
2073 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2074 CurrentService
->ServiceVisited
= FALSE
;
2078 ServiceEntry
= ServiceEntry
->Flink
;
2081 /* Start all services which are members of an existing group */
2082 GroupEntry
= GroupListHead
.Flink
;
2083 while (GroupEntry
!= &GroupListHead
)
2085 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
2087 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
2089 /* Start all services witch have a valid tag */
2090 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
2092 ServiceEntry
= ServiceListHead
.Flink
;
2093 while (ServiceEntry
!= &ServiceListHead
)
2095 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2097 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2098 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2099 (CurrentService
->ServiceVisited
== FALSE
) &&
2100 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
2102 CurrentService
->ServiceVisited
= TRUE
;
2103 ScmLoadService(CurrentService
, 0, NULL
);
2106 ServiceEntry
= ServiceEntry
->Flink
;
2110 /* Start all services which have an invalid tag or which do not have a tag */
2111 ServiceEntry
= ServiceListHead
.Flink
;
2112 while (ServiceEntry
!= &ServiceListHead
)
2114 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2116 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2117 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2118 (CurrentService
->ServiceVisited
== FALSE
))
2120 CurrentService
->ServiceVisited
= TRUE
;
2121 ScmLoadService(CurrentService
, 0, NULL
);
2124 ServiceEntry
= ServiceEntry
->Flink
;
2127 GroupEntry
= GroupEntry
->Flink
;
2130 /* Start all services which are members of any non-existing group */
2131 ServiceEntry
= ServiceListHead
.Flink
;
2132 while (ServiceEntry
!= &ServiceListHead
)
2134 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2136 if ((CurrentService
->lpGroup
!= NULL
) &&
2137 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2138 (CurrentService
->ServiceVisited
== FALSE
))
2140 CurrentService
->ServiceVisited
= TRUE
;
2141 ScmLoadService(CurrentService
, 0, NULL
);
2144 ServiceEntry
= ServiceEntry
->Flink
;
2147 /* Start all services which are not a member of any group */
2148 ServiceEntry
= ServiceListHead
.Flink
;
2149 while (ServiceEntry
!= &ServiceListHead
)
2151 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2153 if ((CurrentService
->lpGroup
== NULL
) &&
2154 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2155 (CurrentService
->ServiceVisited
== FALSE
))
2157 CurrentService
->ServiceVisited
= TRUE
;
2158 ScmLoadService(CurrentService
, 0, NULL
);
2161 ServiceEntry
= ServiceEntry
->Flink
;
2164 /* Clear 'ServiceVisited' flag again */
2165 ServiceEntry
= ServiceListHead
.Flink
;
2166 while (ServiceEntry
!= &ServiceListHead
)
2168 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2169 CurrentService
->ServiceVisited
= FALSE
;
2170 ServiceEntry
= ServiceEntry
->Flink
;
2173 /* Release the critical section */
2174 LeaveCriticalSection(&ControlServiceCriticalSection
);
2179 ScmAutoShutdownServices(VOID
)
2181 PLIST_ENTRY ServiceEntry
;
2182 PSERVICE CurrentService
;
2184 DPRINT("ScmAutoShutdownServices() called\n");
2186 /* Lock the service database exclusively */
2187 ScmLockDatabaseExclusive();
2189 ServiceEntry
= ServiceListHead
.Flink
;
2190 while (ServiceEntry
!= &ServiceListHead
)
2192 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2194 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2195 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
2197 /* shutdown service */
2198 DPRINT("Shutdown service: %S\n", CurrentService
->szServiceName
);
2199 ScmControlService(CurrentService
, SERVICE_CONTROL_SHUTDOWN
);
2202 ServiceEntry
= ServiceEntry
->Flink
;
2205 /* Unlock the service database */
2206 ScmUnlockDatabase();
2208 DPRINT("ScmAutoShutdownServices() done\n");
2213 ScmLockDatabaseExclusive(VOID
)
2215 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2220 ScmLockDatabaseShared(VOID
)
2222 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2227 ScmUnlockDatabase(VOID
)
2229 RtlReleaseResource(&DatabaseLock
);
2234 ScmInitNamedPipeCriticalSection(VOID
)
2240 InitializeCriticalSection(&ControlServiceCriticalSection
);
2242 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2243 L
"SYSTEM\\CurrentControlSet\\Control",
2247 if (dwError
== ERROR_SUCCESS
)
2249 dwKeySize
= sizeof(PipeTimeout
);
2250 RegQueryValueExW(hKey
,
2251 L
"ServicesPipeTimeout",
2254 (LPBYTE
)&PipeTimeout
,
2262 ScmDeleteNamedPipeCriticalSection(VOID
)
2264 DeleteCriticalSection(&ControlServiceCriticalSection
);