2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/database.c
5 * PURPOSE: Database control interface
6 * COPYRIGHT: Copyright 2002-2006 Eric Kohl
7 * Copyright 2006 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
9 * Gregor Brunmar <gregor.brunmar@home.se>
13 /* INCLUDES *****************************************************************/
20 #include <reactos/undocuser.h>
26 /* GLOBALS *******************************************************************/
28 LIST_ENTRY ImageListHead
;
29 LIST_ENTRY ServiceListHead
;
31 static RTL_RESOURCE DatabaseLock
;
32 static DWORD ResumeCount
= 1;
33 static DWORD NoInteractiveServices
= 0;
35 /* The critical section synchronizes service control requests */
36 static CRITICAL_SECTION ControlServiceCriticalSection
;
37 static DWORD PipeTimeout
= 30000; /* 30 Seconds */
40 /* FUNCTIONS *****************************************************************/
43 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
45 WCHAR szControlPipeName
[MAX_PATH
+ 1];
46 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
47 DWORD ServiceCurrent
= 0;
52 /* Get the service number */
53 /* TODO: Create registry entry with correct write access */
54 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
55 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
61 if (dwError
!= ERROR_SUCCESS
)
63 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
67 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
69 dwKeySize
= sizeof(DWORD
);
70 dwError
= RegQueryValueExW(hServiceCurrentKey
,
71 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
73 if (dwError
!= ERROR_SUCCESS
)
75 RegCloseKey(hServiceCurrentKey
);
76 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
83 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
85 RegCloseKey(hServiceCurrentKey
);
87 if (dwError
!= ERROR_SUCCESS
)
89 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
93 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
94 StringCchPrintfW(szControlPipeName
, ARRAYSIZE(szControlPipeName
),
95 L
"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent
);
97 DPRINT("PipeName: %S\n", szControlPipeName
);
99 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
100 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
101 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
107 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
108 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
110 DPRINT1("Failed to create control pipe!\n");
111 return GetLastError();
114 return ERROR_SUCCESS
;
118 static PSERVICE_IMAGE
119 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
121 PLIST_ENTRY ImageEntry
;
122 PSERVICE_IMAGE CurrentImage
;
124 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
126 ImageEntry
= ImageListHead
.Flink
;
127 while (ImageEntry
!= &ImageListHead
)
129 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
132 if (_wcsicmp(CurrentImage
->pszImagePath
, lpImagePath
) == 0)
134 DPRINT("Found image: '%S'\n", CurrentImage
->pszImagePath
);
138 ImageEntry
= ImageEntry
->Flink
;
141 DPRINT("Couldn't find a matching image\n");
149 ScmGetServiceNameFromTag(PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams
, PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS
*OutParams
)
152 return ERROR_CALL_NOT_IMPLEMENTED
;
158 ScmIsSameServiceAccount(
159 _In_ PCWSTR pszAccountName1
,
160 _In_ PCWSTR pszAccountName2
)
162 if (pszAccountName1
== NULL
&&
163 pszAccountName2
== NULL
)
166 if (pszAccountName1
== NULL
&&
167 pszAccountName2
!= NULL
&&
168 _wcsicmp(pszAccountName2
, L
"LocalSystem") == 0)
171 if (pszAccountName1
!= NULL
&&
172 pszAccountName2
== NULL
&&
173 _wcsicmp(pszAccountName1
, L
"LocalSystem") == 0)
176 if (pszAccountName1
!= NULL
&&
177 pszAccountName2
!= NULL
&&
178 _wcsicmp(pszAccountName1
, pszAccountName2
) == 0)
187 ScmIsLocalSystemAccount(
188 _In_ PCWSTR pszAccountName
)
190 if (pszAccountName
== NULL
||
191 _wcsicmp(pszAccountName
, L
"LocalSystem") == 0)
201 IN PSERVICE pService
,
202 IN PSERVICE_IMAGE pImage
)
204 DWORD dwError
= ERROR_SUCCESS
;
205 PROFILEINFOW ProfileInfo
;
206 PWSTR pszUserName
= NULL
;
207 PWSTR pszDomainName
= NULL
;
208 PWSTR pszPassword
= NULL
;
211 DPRINT("ScmLogonService(%p %p)\n", pService
, pImage
);
212 DPRINT("Service %S\n", pService
->lpServiceName
);
214 if (ScmIsLocalSystemAccount(pImage
->pszAccountName
))
215 return ERROR_SUCCESS
;
217 /* Get the user and domain names */
218 ptr
= wcschr(pImage
->pszAccountName
, L
'\\');
222 pszUserName
= ptr
+ 1;
223 pszDomainName
= pImage
->pszAccountName
;
227 // ERROR_INVALID_SERVICE_ACCOUNT
228 pszUserName
= pImage
->pszAccountName
;
229 pszDomainName
= NULL
;
232 /* Build the service 'password' */
233 pszPassword
= HeapAlloc(GetProcessHeap(),
235 (wcslen(pService
->lpServiceName
) + 5) * sizeof(WCHAR
));
236 if (pszPassword
== NULL
)
238 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
242 wcscpy(pszPassword
, L
"_SC_");
243 wcscat(pszPassword
, pService
->lpServiceName
);
245 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName
, pszUserName
, pszPassword
);
247 /* Do the service logon */
248 if (!LogonUserW(pszUserName
,
251 LOGON32_LOGON_SERVICE
,
252 LOGON32_PROVIDER_DEFAULT
,
255 dwError
= GetLastError();
256 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError
);
258 /* Normalize the returned error */
259 dwError
= ERROR_SERVICE_LOGON_FAILED
;
263 /* Load the user profile; the per-user environment variables are thus correctly initialized */
264 ZeroMemory(&ProfileInfo
, sizeof(ProfileInfo
));
265 ProfileInfo
.dwSize
= sizeof(ProfileInfo
);
266 ProfileInfo
.dwFlags
= PI_NOUI
;
267 ProfileInfo
.lpUserName
= pszUserName
;
268 // ProfileInfo.lpProfilePath = NULL;
269 // ProfileInfo.lpDefaultPath = NULL;
270 // ProfileInfo.lpServerName = NULL;
271 // ProfileInfo.lpPolicyPath = NULL;
272 // ProfileInfo.hProfile = NULL;
274 if (!LoadUserProfileW(pImage
->hToken
, &ProfileInfo
))
276 dwError
= GetLastError();
277 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError
);
281 pImage
->hProfile
= ProfileInfo
.hProfile
;
284 if (pszPassword
!= NULL
)
285 HeapFree(GetProcessHeap(), 0, pszPassword
);
295 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
297 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
298 UNICODE_STRING ImagePath
;
299 UNICODE_STRING ObjectName
;
300 PSERVICE_IMAGE pServiceImage
= NULL
;
302 DWORD dwError
= ERROR_SUCCESS
;
306 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
308 RtlInitUnicodeString(&ImagePath
, NULL
);
309 RtlInitUnicodeString(&ObjectName
, NULL
);
311 /* Get service data */
312 RtlZeroMemory(&QueryTable
,
315 QueryTable
[0].Name
= L
"ImagePath";
316 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
317 QueryTable
[0].EntryContext
= &ImagePath
;
318 QueryTable
[1].Name
= L
"ObjectName";
319 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
320 QueryTable
[1].EntryContext
= &ObjectName
;
322 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
323 pService
->lpServiceName
,
327 if (!NT_SUCCESS(Status
))
329 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
330 return RtlNtStatusToDosError(Status
);
333 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
334 DPRINT("ObjectName: '%wZ'\n", &ObjectName
);
336 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
337 if (pServiceImage
== NULL
)
339 dwRecordSize
= sizeof(SERVICE_IMAGE
) +
340 ImagePath
.Length
+ sizeof(WCHAR
) +
341 ((ObjectName
.Length
!= 0) ? (ObjectName
.Length
+ sizeof(WCHAR
)) : 0);
343 /* Create a new service image */
344 pServiceImage
= HeapAlloc(GetProcessHeap(),
347 if (pServiceImage
== NULL
)
349 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
353 pServiceImage
->dwImageRunCount
= 1;
354 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
355 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
357 pString
= (PWSTR
)((INT_PTR
)pServiceImage
+ sizeof(SERVICE_IMAGE
));
359 /* Set the image path */
360 pServiceImage
->pszImagePath
= pString
;
361 wcscpy(pServiceImage
->pszImagePath
,
364 /* Set the account name */
365 if (ObjectName
.Length
> 0)
367 pString
= pString
+ wcslen(pString
) + 1;
369 pServiceImage
->pszAccountName
= pString
;
370 wcscpy(pServiceImage
->pszAccountName
,
375 dwError
= ScmLogonService(pService
, pServiceImage
);
376 if (dwError
!= ERROR_SUCCESS
)
378 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError
);
380 /* Release the service image */
381 HeapFree(GetProcessHeap(), 0, pServiceImage
);
386 /* Create the control pipe */
387 dwError
= ScmCreateNewControlPipe(pServiceImage
);
388 if (dwError
!= ERROR_SUCCESS
)
390 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError
);
392 /* Unload the user profile */
393 if (pServiceImage
->hProfile
!= NULL
)
394 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
396 /* Close the logon token */
397 if (pServiceImage
->hToken
!= NULL
)
398 CloseHandle(pServiceImage
->hToken
);
400 /* Release the service image */
401 HeapFree(GetProcessHeap(), 0, pServiceImage
);
406 /* FIXME: Add more initialization code here */
409 /* Append service record */
410 InsertTailList(&ImageListHead
,
411 &pServiceImage
->ImageListEntry
);
415 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
417 /* Fail if services in an image use different accounts */
418 if (!ScmIsSameServiceAccount(pServiceImage
->pszAccountName
, ObjectName
.Buffer
))
420 dwError
= ERROR_DIFFERENT_SERVICE_ACCOUNT
;
424 /* Increment the run counter */
425 pServiceImage
->dwImageRunCount
++;
428 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage
->pszImagePath
);
429 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage
->pszAccountName
);
430 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
432 /* Link the service image to the service */
433 pService
->lpImage
= pServiceImage
;
436 RtlFreeUnicodeString(&ObjectName
);
437 RtlFreeUnicodeString(&ImagePath
);
439 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
446 ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage
)
448 DPRINT1("ScmRemoveServiceImage() called\n");
450 /* FIXME: Terminate the process */
452 /* Remove the service image from the list */
453 RemoveEntryList(&pServiceImage
->ImageListEntry
);
455 /* Close the process handle */
456 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
457 CloseHandle(pServiceImage
->hProcess
);
459 /* Close the control pipe */
460 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
461 CloseHandle(pServiceImage
->hControlPipe
);
463 /* Unload the user profile */
464 if (pServiceImage
->hProfile
!= NULL
)
465 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
467 /* Close the logon token */
468 if (pServiceImage
->hToken
!= NULL
)
469 CloseHandle(pServiceImage
->hToken
);
471 /* Release the service image */
472 HeapFree(GetProcessHeap(), 0, pServiceImage
);
477 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
479 PLIST_ENTRY ServiceEntry
;
480 PSERVICE CurrentService
;
482 DPRINT("ScmGetServiceEntryByName() called\n");
484 ServiceEntry
= ServiceListHead
.Flink
;
485 while (ServiceEntry
!= &ServiceListHead
)
487 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
490 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
492 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
493 return CurrentService
;
496 ServiceEntry
= ServiceEntry
->Flink
;
499 DPRINT("Couldn't find a matching service\n");
506 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
508 PLIST_ENTRY ServiceEntry
;
509 PSERVICE CurrentService
;
511 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
513 ServiceEntry
= ServiceListHead
.Flink
;
514 while (ServiceEntry
!= &ServiceListHead
)
516 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
519 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
521 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
522 return CurrentService
;
525 ServiceEntry
= ServiceEntry
->Flink
;
528 DPRINT("Couldn't find a matching service\n");
535 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
537 PLIST_ENTRY ServiceEntry
;
538 PSERVICE CurrentService
;
540 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
542 ServiceEntry
= ServiceListHead
.Flink
;
543 while (ServiceEntry
!= &ServiceListHead
)
545 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
548 if (CurrentService
->dwResumeCount
> dwResumeCount
)
550 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
551 return CurrentService
;
554 ServiceEntry
= ServiceEntry
->Flink
;
557 DPRINT("Couldn't find a matching service\n");
564 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
565 PSERVICE
*lpServiceRecord
,
569 PSERVICE lpService
= NULL
;
571 DPRINT("Service: '%S'\n", lpServiceName
);
573 /* Allocate service entry */
574 lpService
= HeapAlloc(GetProcessHeap(),
576 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
577 if (lpService
== NULL
)
578 return ERROR_NOT_ENOUGH_MEMORY
;
580 *lpServiceRecord
= lpService
;
582 /* Copy service name */
583 wcscpy(lpService
->szServiceName
, lpServiceName
);
584 lpService
->lpServiceName
= lpService
->szServiceName
;
585 lpService
->lpDisplayName
= lpService
->lpServiceName
;
587 /* Set the start type */
588 lpService
->dwStartType
= dwStartType
;
590 /* Set the resume count */
591 lpService
->dwResumeCount
= ResumeCount
++;
593 /* Append service record */
594 InsertTailList(&ServiceListHead
,
595 &lpService
->ServiceListEntry
);
597 /* Initialize the service status */
598 lpService
->Status
.dwServiceType
= dwServiceType
;
599 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
600 lpService
->Status
.dwControlsAccepted
= 0;
601 lpService
->Status
.dwWin32ExitCode
=
602 (dwStartType
== SERVICE_DISABLED
) ? ERROR_SERVICE_DISABLED
: ERROR_SERVICE_NEVER_STARTED
;
603 lpService
->Status
.dwServiceSpecificExitCode
= 0;
604 lpService
->Status
.dwCheckPoint
= 0;
605 lpService
->Status
.dwWaitHint
=
606 (dwServiceType
& SERVICE_DRIVER
) ? 0 : 2000; /* 2 seconds */
608 return ERROR_SUCCESS
;
613 ScmDeleteServiceRecord(PSERVICE lpService
)
615 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
617 /* Delete the display name */
618 if (lpService
->lpDisplayName
!= NULL
&&
619 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
620 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
622 /* Dereference the service image */
623 if (lpService
->lpImage
)
625 lpService
->lpImage
->dwImageRunCount
--;
627 if (lpService
->lpImage
->dwImageRunCount
== 0)
629 ScmRemoveServiceImage(lpService
->lpImage
);
630 lpService
->lpImage
= NULL
;
634 /* Decrement the group reference counter */
635 ScmSetServiceGroup(lpService
, NULL
);
637 /* Release the SecurityDescriptor */
638 if (lpService
->pSecurityDescriptor
!= NULL
)
639 HeapFree(GetProcessHeap(), 0, lpService
->pSecurityDescriptor
);
641 /* Remove the Service from the List */
642 RemoveEntryList(&lpService
->ServiceListEntry
);
644 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
646 /* Delete the service record */
647 HeapFree(GetProcessHeap(), 0, lpService
);
654 CreateServiceListEntry(LPCWSTR lpServiceName
,
657 PSERVICE lpService
= NULL
;
658 LPWSTR lpDisplayName
= NULL
;
659 LPWSTR lpGroup
= NULL
;
664 DWORD dwErrorControl
;
667 DPRINT("Service: '%S'\n", lpServiceName
);
668 if (*lpServiceName
== L
'{')
669 return ERROR_SUCCESS
;
671 dwSize
= sizeof(DWORD
);
672 dwError
= RegQueryValueExW(hServiceKey
,
676 (LPBYTE
)&dwServiceType
,
678 if (dwError
!= ERROR_SUCCESS
)
679 return ERROR_SUCCESS
;
681 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
682 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
683 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
684 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
685 return ERROR_SUCCESS
;
687 DPRINT("Service type: %lx\n", dwServiceType
);
689 dwSize
= sizeof(DWORD
);
690 dwError
= RegQueryValueExW(hServiceKey
,
694 (LPBYTE
)&dwStartType
,
696 if (dwError
!= ERROR_SUCCESS
)
697 return ERROR_SUCCESS
;
699 DPRINT("Start type: %lx\n", dwStartType
);
701 dwSize
= sizeof(DWORD
);
702 dwError
= RegQueryValueExW(hServiceKey
,
706 (LPBYTE
)&dwErrorControl
,
708 if (dwError
!= ERROR_SUCCESS
)
709 return ERROR_SUCCESS
;
711 DPRINT("Error control: %lx\n", dwErrorControl
);
713 dwError
= RegQueryValueExW(hServiceKey
,
719 if (dwError
!= ERROR_SUCCESS
)
722 DPRINT("Tag: %lx\n", dwTagId
);
724 dwError
= ScmReadString(hServiceKey
,
727 if (dwError
!= ERROR_SUCCESS
)
730 DPRINT("Group: %S\n", lpGroup
);
732 dwError
= ScmReadString(hServiceKey
,
735 if (dwError
!= ERROR_SUCCESS
)
736 lpDisplayName
= NULL
;
738 DPRINT("Display name: %S\n", lpDisplayName
);
740 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
744 if (dwError
!= ERROR_SUCCESS
)
747 lpService
->dwErrorControl
= dwErrorControl
;
748 lpService
->dwTag
= dwTagId
;
752 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
753 if (dwError
!= ERROR_SUCCESS
)
757 if (lpDisplayName
!= NULL
)
759 lpService
->lpDisplayName
= lpDisplayName
;
760 lpDisplayName
= NULL
;
763 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
764 if (lpService
->lpGroup
!= NULL
)
766 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
768 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
769 lpService
->dwStartType
,
770 lpService
->Status
.dwServiceType
,
772 lpService
->dwErrorControl
);
774 if (ScmIsDeleteFlagSet(hServiceKey
))
775 lpService
->bDeleted
= TRUE
;
777 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
779 dwError
= ScmReadSecurityDescriptor(hServiceKey
,
780 &lpService
->pSecurityDescriptor
);
781 if (dwError
!= ERROR_SUCCESS
)
784 /* Assing the default security descriptor if the security descriptor cannot be read */
785 if (lpService
->pSecurityDescriptor
== NULL
)
787 DPRINT("No security descriptor found! Assign default security descriptor!\n");
788 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
789 if (dwError
!= ERROR_SUCCESS
)
792 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
793 lpService
->pSecurityDescriptor
);
794 if (dwError
!= ERROR_SUCCESS
)
801 HeapFree(GetProcessHeap(), 0, lpGroup
);
803 if (lpDisplayName
!= NULL
)
804 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
806 if (lpService
!= NULL
)
808 ASSERT(lpService
->lpImage
== NULL
);
816 ScmDeleteMarkedServices(VOID
)
818 PLIST_ENTRY ServiceEntry
;
819 PSERVICE CurrentService
;
823 ServiceEntry
= ServiceListHead
.Flink
;
824 while (ServiceEntry
!= &ServiceListHead
)
826 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
828 ServiceEntry
= ServiceEntry
->Flink
;
830 if (CurrentService
->bDeleted
!= FALSE
)
832 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
833 L
"System\\CurrentControlSet\\Services",
837 if (dwError
== ERROR_SUCCESS
)
839 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
840 RegCloseKey(hServicesKey
);
841 if (dwError
== ERROR_SUCCESS
)
843 RemoveEntryList(&CurrentService
->ServiceListEntry
);
844 HeapFree(GetProcessHeap(), 0, CurrentService
);
848 if (dwError
!= ERROR_SUCCESS
)
849 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
857 ScmGetNoInteractiveServicesValue(VOID
)
863 lError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
864 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
868 if (lError
== ERROR_SUCCESS
)
870 dwKeySize
= sizeof(NoInteractiveServices
);
871 lError
= RegQueryValueExW(hKey
,
872 L
"NoInteractiveServices",
875 (LPBYTE
)&NoInteractiveServices
,
883 ScmCreateServiceDatabase(VOID
)
885 WCHAR szSubKey
[MAX_PATH
];
889 DWORD dwSubKeyLength
;
890 FILETIME ftLastChanged
;
893 DPRINT("ScmCreateServiceDatabase() called\n");
895 /* Retrieve the NoInteractiveServies value */
896 ScmGetNoInteractiveServicesValue();
898 /* Create the service group list */
899 dwError
= ScmCreateGroupList();
900 if (dwError
!= ERROR_SUCCESS
)
903 /* Initialize image and service lists */
904 InitializeListHead(&ImageListHead
);
905 InitializeListHead(&ServiceListHead
);
907 /* Initialize the database lock */
908 RtlInitializeResource(&DatabaseLock
);
910 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
911 L
"System\\CurrentControlSet\\Services",
915 if (dwError
!= ERROR_SUCCESS
)
921 dwSubKeyLength
= MAX_PATH
;
922 dwError
= RegEnumKeyExW(hServicesKey
,
930 if (dwError
== ERROR_SUCCESS
&&
933 DPRINT("SubKeyName: '%S'\n", szSubKey
);
935 dwError
= RegOpenKeyExW(hServicesKey
,
940 if (dwError
== ERROR_SUCCESS
)
942 dwError
= CreateServiceListEntry(szSubKey
,
945 RegCloseKey(hServiceKey
);
949 if (dwError
!= ERROR_SUCCESS
)
955 RegCloseKey(hServicesKey
);
957 /* Wait for the LSA server */
960 /* Delete services that are marked for delete */
961 ScmDeleteMarkedServices();
963 DPRINT("ScmCreateServiceDatabase() done\n");
965 return ERROR_SUCCESS
;
970 ScmShutdownServiceDatabase(VOID
)
972 DPRINT("ScmShutdownServiceDatabase() called\n");
974 ScmDeleteMarkedServices();
975 RtlDeleteResource(&DatabaseLock
);
977 DPRINT("ScmShutdownServiceDatabase() done\n");
982 ScmCheckDriver(PSERVICE Service
)
984 OBJECT_ATTRIBUTES ObjectAttributes
;
985 UNICODE_STRING DirName
;
988 POBJECT_DIRECTORY_INFORMATION DirInfo
;
993 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
995 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
997 RtlInitUnicodeString(&DirName
, L
"\\Driver");
999 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
1001 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
1002 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
1005 InitializeObjectAttributes(&ObjectAttributes
,
1011 Status
= NtOpenDirectoryObject(&DirHandle
,
1012 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1014 if (!NT_SUCCESS(Status
))
1019 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
1020 2 * MAX_PATH
* sizeof(WCHAR
);
1021 DirInfo
= HeapAlloc(GetProcessHeap(),
1028 Status
= NtQueryDirectoryObject(DirHandle
,
1035 if (Status
== STATUS_NO_MORE_ENTRIES
)
1037 /* FIXME: Add current service to 'failed service' list */
1038 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
1042 if (!NT_SUCCESS(Status
))
1045 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
1047 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
1049 DPRINT("Found: '%S' '%wZ'\n",
1050 Service
->lpServiceName
, &DirInfo
->Name
);
1052 /* Mark service as 'running' */
1053 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1054 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1055 Service
->Status
.dwWin32ExitCode
= ERROR_SUCCESS
;
1056 Service
->Status
.dwServiceSpecificExitCode
= 0;
1057 Service
->Status
.dwCheckPoint
= 0;
1058 Service
->Status
.dwWaitHint
= 0;
1060 /* Mark the service group as 'running' */
1061 if (Service
->lpGroup
!= NULL
)
1063 Service
->lpGroup
->ServicesRunning
= TRUE
;
1070 HeapFree(GetProcessHeap(),
1075 return STATUS_SUCCESS
;
1080 ScmGetBootAndSystemDriverState(VOID
)
1082 PLIST_ENTRY ServiceEntry
;
1083 PSERVICE CurrentService
;
1085 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1087 ServiceEntry
= ServiceListHead
.Flink
;
1088 while (ServiceEntry
!= &ServiceListHead
)
1090 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1092 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
1093 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
1096 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
1098 ScmCheckDriver(CurrentService
);
1101 ServiceEntry
= ServiceEntry
->Flink
;
1104 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1109 ScmControlService(HANDLE hControlPipe
,
1111 SERVICE_STATUS_HANDLE hServiceStatus
,
1114 PSCM_CONTROL_PACKET ControlPacket
;
1115 SCM_REPLY_PACKET ReplyPacket
;
1117 DWORD dwWriteCount
= 0;
1118 DWORD dwReadCount
= 0;
1121 DWORD dwError
= ERROR_SUCCESS
;
1123 OVERLAPPED Overlapped
= {0};
1125 DPRINT("ScmControlService() called\n");
1127 /* Acquire the service control critical section, to synchronize requests */
1128 EnterCriticalSection(&ControlServiceCriticalSection
);
1130 /* Calculate the total length of the start command line */
1131 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1132 PacketSize
+= (DWORD
)((wcslen(pServiceName
) + 1) * sizeof(WCHAR
));
1134 ControlPacket
= HeapAlloc(GetProcessHeap(),
1137 if (ControlPacket
== NULL
)
1139 LeaveCriticalSection(&ControlServiceCriticalSection
);
1140 return ERROR_NOT_ENOUGH_MEMORY
;
1143 ControlPacket
->dwSize
= PacketSize
;
1144 ControlPacket
->dwControl
= dwControl
;
1145 ControlPacket
->hServiceStatus
= hServiceStatus
;
1147 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1149 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1150 wcscpy(Ptr
, pServiceName
);
1152 ControlPacket
->dwArgumentsCount
= 0;
1153 ControlPacket
->dwArgumentsOffset
= 0;
1155 bResult
= WriteFile(hControlPipe
,
1160 if (bResult
== FALSE
)
1162 DPRINT("WriteFile() returned FALSE\n");
1164 dwError
= GetLastError();
1165 if (dwError
== ERROR_IO_PENDING
)
1167 DPRINT("dwError: ERROR_IO_PENDING\n");
1169 dwError
= WaitForSingleObject(hControlPipe
,
1171 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1173 if (dwError
== WAIT_TIMEOUT
)
1175 bResult
= CancelIo(hControlPipe
);
1176 if (bResult
== FALSE
)
1178 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1181 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1184 else if (dwError
== WAIT_OBJECT_0
)
1186 bResult
= GetOverlappedResult(hControlPipe
,
1190 if (bResult
== FALSE
)
1192 dwError
= GetLastError();
1193 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1201 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1206 /* Read the reply */
1207 Overlapped
.hEvent
= (HANDLE
) NULL
;
1209 bResult
= ReadFile(hControlPipe
,
1211 sizeof(SCM_REPLY_PACKET
),
1214 if (bResult
== FALSE
)
1216 DPRINT("ReadFile() returned FALSE\n");
1218 dwError
= GetLastError();
1219 if (dwError
== ERROR_IO_PENDING
)
1221 DPRINT("dwError: ERROR_IO_PENDING\n");
1223 dwError
= WaitForSingleObject(hControlPipe
,
1225 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1227 if (dwError
== WAIT_TIMEOUT
)
1229 bResult
= CancelIo(hControlPipe
);
1230 if (bResult
== FALSE
)
1232 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1235 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1238 else if (dwError
== WAIT_OBJECT_0
)
1240 bResult
= GetOverlappedResult(hControlPipe
,
1244 if (bResult
== FALSE
)
1246 dwError
= GetLastError();
1247 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1255 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1261 /* Release the control packet */
1262 HeapFree(GetProcessHeap(),
1266 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1268 dwError
= ReplyPacket
.dwError
;
1271 LeaveCriticalSection(&ControlServiceCriticalSection
);
1273 DPRINT("ScmControlService() done\n");
1280 ScmSendStartCommand(PSERVICE Service
,
1284 DWORD dwError
= ERROR_SUCCESS
;
1285 PSCM_CONTROL_PACKET ControlPacket
;
1286 SCM_REPLY_PACKET ReplyPacket
;
1293 DWORD dwWriteCount
= 0;
1294 DWORD dwReadCount
= 0;
1295 OVERLAPPED Overlapped
= {0};
1297 DPRINT("ScmSendStartCommand() called\n");
1299 /* Calculate the total length of the start command line */
1300 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1301 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1304 * Calculate the required packet size for the start argument vector 'argv',
1305 * composed of the list of pointer offsets, followed by UNICODE strings.
1306 * The strings are stored continuously after the vector of offsets, with
1307 * the offsets being relative to the beginning of the vector, as in the
1308 * following layout (with N == argc):
1309 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1311 if (argc
> 0 && argv
!= NULL
)
1313 PacketSize
= ALIGN_UP(PacketSize
, PWSTR
);
1314 PacketSize
+= (argc
* sizeof(PWSTR
));
1316 DPRINT("Argc: %lu\n", argc
);
1317 for (i
= 0; i
< argc
; i
++)
1319 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1320 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
));
1324 /* Allocate a control packet */
1325 ControlPacket
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, PacketSize
);
1326 if (ControlPacket
== NULL
)
1327 return ERROR_NOT_ENOUGH_MEMORY
;
1329 ControlPacket
->dwSize
= PacketSize
;
1330 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1331 ? SERVICE_CONTROL_START_OWN
1332 : SERVICE_CONTROL_START_SHARE
;
1333 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1335 /* Copy the start command line */
1336 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1337 Ptr
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1338 wcscpy(Ptr
, Service
->lpServiceName
);
1340 ControlPacket
->dwArgumentsCount
= 0;
1341 ControlPacket
->dwArgumentsOffset
= 0;
1343 /* Copy the argument vector */
1344 if (argc
> 0 && argv
!= NULL
)
1346 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1347 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1348 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1350 ControlPacket
->dwArgumentsCount
= argc
;
1351 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1353 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1354 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1356 for (i
= 0; i
< argc
; i
++)
1358 wcscpy(pArgPtr
, argv
[i
]);
1359 pOffPtr
[i
] = (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1360 DPRINT("offset[%lu]: %p\n", i
, pOffPtr
[i
]);
1361 pArgPtr
+= wcslen(argv
[i
]) + 1;
1365 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1370 if (bResult
== FALSE
)
1372 DPRINT("WriteFile() returned FALSE\n");
1374 dwError
= GetLastError();
1375 if (dwError
== ERROR_IO_PENDING
)
1377 DPRINT("dwError: ERROR_IO_PENDING\n");
1379 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1381 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1383 if (dwError
== WAIT_TIMEOUT
)
1385 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1386 if (bResult
== FALSE
)
1388 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1391 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1394 else if (dwError
== WAIT_OBJECT_0
)
1396 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1400 if (bResult
== FALSE
)
1402 dwError
= GetLastError();
1403 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1411 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1416 /* Read the reply */
1417 Overlapped
.hEvent
= (HANDLE
) NULL
;
1419 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1421 sizeof(SCM_REPLY_PACKET
),
1424 if (bResult
== FALSE
)
1426 DPRINT("ReadFile() returned FALSE\n");
1428 dwError
= GetLastError();
1429 if (dwError
== ERROR_IO_PENDING
)
1431 DPRINT("dwError: ERROR_IO_PENDING\n");
1433 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1435 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1437 if (dwError
== WAIT_TIMEOUT
)
1439 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1440 if (bResult
== FALSE
)
1442 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1445 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1448 else if (dwError
== WAIT_OBJECT_0
)
1450 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1454 if (bResult
== FALSE
)
1456 dwError
= GetLastError();
1457 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1465 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1471 /* Release the control packet */
1472 HeapFree(GetProcessHeap(),
1476 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1478 dwError
= ReplyPacket
.dwError
;
1481 DPRINT("ScmSendStartCommand() done\n");
1488 ScmWaitForServiceConnect(PSERVICE Service
)
1491 DWORD dwProcessId
= 0;
1492 DWORD dwError
= ERROR_SUCCESS
;
1494 OVERLAPPED Overlapped
= {0};
1496 LPCWSTR lpLogStrings
[3];
1497 WCHAR szBuffer1
[20];
1498 WCHAR szBuffer2
[20];
1501 DPRINT("ScmWaitForServiceConnect()\n");
1503 Overlapped
.hEvent
= (HANDLE
)NULL
;
1505 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1507 if (bResult
== FALSE
)
1509 DPRINT("ConnectNamedPipe() returned FALSE\n");
1511 dwError
= GetLastError();
1512 if (dwError
== ERROR_IO_PENDING
)
1514 DPRINT("dwError: ERROR_IO_PENDING\n");
1516 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1518 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1520 if (dwError
== WAIT_TIMEOUT
)
1522 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1524 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1525 if (bResult
== FALSE
)
1527 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1531 _ultow(PipeTimeout
, szBuffer1
, 10);
1532 lpLogStrings
[0] = Service
->lpDisplayName
;
1533 lpLogStrings
[1] = szBuffer1
;
1535 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1536 EVENTLOG_ERROR_TYPE
,
1540 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1542 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1544 else if (dwError
== WAIT_OBJECT_0
)
1546 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1550 if (bResult
== FALSE
)
1552 dwError
= GetLastError();
1553 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1559 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1561 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1566 DPRINT("Control pipe connected!\n");
1568 Overlapped
.hEvent
= (HANDLE
) NULL
;
1570 /* Read the process id from pipe */
1571 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1572 (LPVOID
)&dwProcessId
,
1576 if (bResult
== FALSE
)
1578 DPRINT("ReadFile() returned FALSE\n");
1580 dwError
= GetLastError();
1581 if (dwError
== ERROR_IO_PENDING
)
1583 DPRINT("dwError: ERROR_IO_PENDING\n");
1585 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1587 if (dwError
== WAIT_TIMEOUT
)
1589 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1591 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1592 if (bResult
== FALSE
)
1594 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1598 _ultow(PipeTimeout
, szBuffer1
, 10);
1599 lpLogStrings
[0] = szBuffer1
;
1601 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1602 EVENTLOG_ERROR_TYPE
,
1606 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1608 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1610 else if (dwError
== WAIT_OBJECT_0
)
1612 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1614 DPRINT("Process Id: %lu\n", dwProcessId
);
1616 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1620 if (bResult
== FALSE
)
1622 dwError
= GetLastError();
1623 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1630 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1635 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1640 if (dwProcessId
!= Service
->lpImage
->dwProcessId
)
1643 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1644 _ultow(dwProcessId
, szBuffer2
, 10);
1646 lpLogStrings
[0] = Service
->lpDisplayName
;
1647 lpLogStrings
[1] = szBuffer1
;
1648 lpLogStrings
[2] = szBuffer2
;
1650 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1651 EVENTLOG_WARNING_TYPE
,
1656 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1659 DPRINT("ScmWaitForServiceConnect() done\n");
1661 return ERROR_SUCCESS
;
1666 ScmStartUserModeService(PSERVICE Service
,
1670 PROCESS_INFORMATION ProcessInformation
;
1671 STARTUPINFOW StartupInfo
;
1672 LPVOID lpEnvironment
;
1674 DWORD dwError
= ERROR_SUCCESS
;
1676 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1678 /* If the image is already running ... */
1679 if (Service
->lpImage
->dwImageRunCount
> 1)
1681 /* ... just send a start command */
1682 return ScmSendStartCommand(Service
, argc
, argv
);
1685 /* Otherwise start its process */
1686 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1687 StartupInfo
.cb
= sizeof(StartupInfo
);
1688 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1690 if (Service
->lpImage
->hToken
)
1692 /* User token: Run the service under the user account */
1694 if (!CreateEnvironmentBlock(&lpEnvironment
, Service
->lpImage
->hToken
, FALSE
))
1696 /* We failed, run the service with the current environment */
1697 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1698 GetLastError(), Service
->lpServiceName
);
1699 lpEnvironment
= NULL
;
1702 /* Impersonate the new user */
1703 Result
= ImpersonateLoggedOnUser(Service
->lpImage
->hToken
);
1706 /* Launch the process in the user's logon session */
1707 Result
= CreateProcessAsUserW(Service
->lpImage
->hToken
,
1709 Service
->lpImage
->pszImagePath
,
1713 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1717 &ProcessInformation
);
1719 dwError
= GetLastError();
1721 /* Revert the impersonation */
1726 dwError
= GetLastError();
1727 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError
);
1732 /* No user token: Run the service under the LocalSystem account */
1734 if (!CreateEnvironmentBlock(&lpEnvironment
, NULL
, TRUE
))
1736 /* We failed, run the service with the current environment */
1737 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1738 GetLastError(), Service
->lpServiceName
);
1739 lpEnvironment
= NULL
;
1742 /* Use the interactive desktop if the service is interactive */
1743 if ((NoInteractiveServices
== 0) &&
1744 (Service
->Status
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
))
1746 StartupInfo
.dwFlags
|= STARTF_INHERITDESKTOP
;
1747 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
1750 Result
= CreateProcessW(NULL
,
1751 Service
->lpImage
->pszImagePath
,
1755 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1759 &ProcessInformation
);
1761 dwError
= GetLastError();
1765 DestroyEnvironmentBlock(lpEnvironment
);
1769 DPRINT1("Starting '%S' failed with error %d\n",
1770 Service
->lpServiceName
, dwError
);
1774 DPRINT("Process Id: %lu Handle %p\n",
1775 ProcessInformation
.dwProcessId
,
1776 ProcessInformation
.hProcess
);
1777 DPRINT("Thread Id: %lu Handle %p\n",
1778 ProcessInformation
.dwThreadId
,
1779 ProcessInformation
.hThread
);
1781 /* Get the process handle and ID */
1782 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1783 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1785 /* Resume the main thread and close its handle */
1786 ResumeThread(ProcessInformation
.hThread
);
1787 CloseHandle(ProcessInformation
.hThread
);
1789 /* Connect control pipe */
1790 dwError
= ScmWaitForServiceConnect(Service
);
1791 if (dwError
!= ERROR_SUCCESS
)
1793 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1794 Service
->lpImage
->dwProcessId
= 0;
1798 /* Send the start command */
1799 return ScmSendStartCommand(Service
, argc
, argv
);
1804 ScmLoadService(PSERVICE Service
,
1808 PSERVICE_GROUP Group
= Service
->lpGroup
;
1809 DWORD dwError
= ERROR_SUCCESS
;
1810 LPCWSTR lpLogStrings
[2];
1811 WCHAR szLogBuffer
[80];
1813 DPRINT("ScmLoadService() called\n");
1814 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1816 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1818 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1819 return ERROR_SERVICE_ALREADY_RUNNING
;
1822 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1824 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1826 /* Start the driver */
1827 dwError
= ScmStartDriver(Service
);
1829 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1831 /* Start user-mode service */
1832 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1833 if (dwError
== ERROR_SUCCESS
)
1835 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1836 if (dwError
== ERROR_SUCCESS
)
1838 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1839 Service
->Status
.dwControlsAccepted
= 0;
1843 Service
->lpImage
->dwImageRunCount
--;
1844 if (Service
->lpImage
->dwImageRunCount
== 0)
1846 ScmRemoveServiceImage(Service
->lpImage
);
1847 Service
->lpImage
= NULL
;
1853 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
1855 if (dwError
== ERROR_SUCCESS
)
1859 Group
->ServicesRunning
= TRUE
;
1862 /* Log a successful service start */
1863 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
1864 lpLogStrings
[0] = Service
->lpDisplayName
;
1865 lpLogStrings
[1] = szLogBuffer
;
1867 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1868 EVENTLOG_INFORMATION_TYPE
,
1874 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1876 /* Log a failed service start */
1877 StringCchPrintfW(szLogBuffer
, ARRAYSIZE(szLogBuffer
),
1879 lpLogStrings
[0] = Service
->lpServiceName
;
1880 lpLogStrings
[1] = szLogBuffer
;
1881 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
1882 EVENTLOG_ERROR_TYPE
,
1888 switch (Service
->dwErrorControl
)
1890 case SERVICE_ERROR_SEVERE
:
1891 if (IsLastKnownGood
== FALSE
)
1893 /* FIXME: Boot last known good configuration */
1897 case SERVICE_ERROR_CRITICAL
:
1898 if (IsLastKnownGood
== FALSE
)
1900 /* FIXME: Boot last known good configuration */
1916 ScmStartService(PSERVICE Service
,
1920 DWORD dwError
= ERROR_SUCCESS
;
1921 SC_RPC_LOCK Lock
= NULL
;
1923 DPRINT("ScmStartService() called\n");
1924 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1926 /* Acquire the service control critical section, to synchronize starts */
1927 EnterCriticalSection(&ControlServiceCriticalSection
);
1930 * Acquire the user service start lock while the service is starting, if
1931 * needed (i.e. if we are not starting it during the initialization phase).
1932 * If we don't success, bail out.
1936 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
1937 if (dwError
!= ERROR_SUCCESS
) goto done
;
1940 /* Really start the service */
1941 dwError
= ScmLoadService(Service
, argc
, argv
);
1943 /* Release the service start lock, if needed, and the critical section */
1944 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
1947 LeaveCriticalSection(&ControlServiceCriticalSection
);
1949 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1956 ScmAutoStartServices(VOID
)
1959 PLIST_ENTRY GroupEntry
;
1960 PLIST_ENTRY ServiceEntry
;
1961 PSERVICE_GROUP CurrentGroup
;
1962 PSERVICE CurrentService
;
1963 WCHAR szSafeBootServicePath
[MAX_PATH
];
1964 DWORD SafeBootEnabled
;
1970 * This function MUST be called ONLY at initialization time.
1971 * Therefore, no need to acquire the user service start lock.
1973 ASSERT(ScmInitialize
);
1975 /* Retrieve the SafeBoot parameter */
1976 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1977 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
1981 if (dwError
== ERROR_SUCCESS
)
1983 dwKeySize
= sizeof(SafeBootEnabled
);
1984 dwError
= RegQueryValueExW(hKey
,
1988 (LPBYTE
)&SafeBootEnabled
,
1993 /* Default to Normal boot if the value doesn't exist */
1994 if (dwError
!= ERROR_SUCCESS
)
1995 SafeBootEnabled
= 0;
1997 /* Acquire the service control critical section, to synchronize starts */
1998 EnterCriticalSection(&ControlServiceCriticalSection
);
2000 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
2001 ServiceEntry
= ServiceListHead
.Flink
;
2002 while (ServiceEntry
!= &ServiceListHead
)
2004 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2006 /* Build the safe boot path */
2007 StringCchCopyW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2008 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
2010 switch (SafeBootEnabled
)
2012 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
2015 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2020 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2025 if (SafeBootEnabled
!= 0)
2027 /* If key does not exist then do not assume safe mode */
2028 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2029 szSafeBootServicePath
,
2033 if (dwError
== ERROR_SUCCESS
)
2037 /* Finish Safe Boot path off */
2038 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2039 CurrentService
->lpServiceName
);
2041 /* Check that the key is in the Safe Boot path */
2042 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2043 szSafeBootServicePath
,
2047 if (dwError
!= ERROR_SUCCESS
)
2049 /* Mark service as visited so it is not auto-started */
2050 CurrentService
->ServiceVisited
= TRUE
;
2054 /* Must be auto-started in safe mode - mark as unvisited */
2056 CurrentService
->ServiceVisited
= FALSE
;
2061 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2062 CurrentService
->ServiceVisited
= FALSE
;
2066 ServiceEntry
= ServiceEntry
->Flink
;
2069 /* Start all services which are members of an existing group */
2070 GroupEntry
= GroupListHead
.Flink
;
2071 while (GroupEntry
!= &GroupListHead
)
2073 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
2075 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
2077 /* Start all services witch have a valid tag */
2078 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
2080 ServiceEntry
= ServiceListHead
.Flink
;
2081 while (ServiceEntry
!= &ServiceListHead
)
2083 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2085 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2086 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2087 (CurrentService
->ServiceVisited
== FALSE
) &&
2088 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
2090 CurrentService
->ServiceVisited
= TRUE
;
2091 ScmLoadService(CurrentService
, 0, NULL
);
2094 ServiceEntry
= ServiceEntry
->Flink
;
2098 /* Start all services which have an invalid tag or which do not have a tag */
2099 ServiceEntry
= ServiceListHead
.Flink
;
2100 while (ServiceEntry
!= &ServiceListHead
)
2102 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2104 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2105 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2106 (CurrentService
->ServiceVisited
== FALSE
))
2108 CurrentService
->ServiceVisited
= TRUE
;
2109 ScmLoadService(CurrentService
, 0, NULL
);
2112 ServiceEntry
= ServiceEntry
->Flink
;
2115 GroupEntry
= GroupEntry
->Flink
;
2118 /* Start all services which are members of any non-existing group */
2119 ServiceEntry
= ServiceListHead
.Flink
;
2120 while (ServiceEntry
!= &ServiceListHead
)
2122 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2124 if ((CurrentService
->lpGroup
!= NULL
) &&
2125 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2126 (CurrentService
->ServiceVisited
== FALSE
))
2128 CurrentService
->ServiceVisited
= TRUE
;
2129 ScmLoadService(CurrentService
, 0, NULL
);
2132 ServiceEntry
= ServiceEntry
->Flink
;
2135 /* Start all services which are not a member of any group */
2136 ServiceEntry
= ServiceListHead
.Flink
;
2137 while (ServiceEntry
!= &ServiceListHead
)
2139 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2141 if ((CurrentService
->lpGroup
== NULL
) &&
2142 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2143 (CurrentService
->ServiceVisited
== FALSE
))
2145 CurrentService
->ServiceVisited
= TRUE
;
2146 ScmLoadService(CurrentService
, 0, NULL
);
2149 ServiceEntry
= ServiceEntry
->Flink
;
2152 /* Clear 'ServiceVisited' flag again */
2153 ServiceEntry
= ServiceListHead
.Flink
;
2154 while (ServiceEntry
!= &ServiceListHead
)
2156 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2157 CurrentService
->ServiceVisited
= FALSE
;
2158 ServiceEntry
= ServiceEntry
->Flink
;
2161 /* Release the critical section */
2162 LeaveCriticalSection(&ControlServiceCriticalSection
);
2167 ScmAutoShutdownServices(VOID
)
2169 PLIST_ENTRY ServiceEntry
;
2170 PSERVICE CurrentService
;
2172 DPRINT("ScmAutoShutdownServices() called\n");
2174 /* Lock the service database exclusively */
2175 ScmLockDatabaseExclusive();
2177 ServiceEntry
= ServiceListHead
.Flink
;
2178 while (ServiceEntry
!= &ServiceListHead
)
2180 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2182 if ((CurrentService
->Status
.dwControlsAccepted
& SERVICE_ACCEPT_SHUTDOWN
) &&
2183 (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2184 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
))
2186 /* Send the shutdown notification */
2187 DPRINT("Shutdown service: %S\n", CurrentService
->lpServiceName
);
2188 ScmControlService(CurrentService
->lpImage
->hControlPipe
,
2189 CurrentService
->lpServiceName
,
2190 (SERVICE_STATUS_HANDLE
)CurrentService
,
2191 SERVICE_CONTROL_SHUTDOWN
);
2194 ServiceEntry
= ServiceEntry
->Flink
;
2197 /* Unlock the service database */
2198 ScmUnlockDatabase();
2200 DPRINT("ScmAutoShutdownServices() done\n");
2205 ScmLockDatabaseExclusive(VOID
)
2207 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2212 ScmLockDatabaseShared(VOID
)
2214 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2219 ScmUnlockDatabase(VOID
)
2221 RtlReleaseResource(&DatabaseLock
);
2226 ScmInitNamedPipeCriticalSection(VOID
)
2232 InitializeCriticalSection(&ControlServiceCriticalSection
);
2234 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2235 L
"SYSTEM\\CurrentControlSet\\Control",
2239 if (dwError
== ERROR_SUCCESS
)
2241 dwKeySize
= sizeof(PipeTimeout
);
2242 RegQueryValueExW(hKey
,
2243 L
"ServicesPipeTimeout",
2246 (LPBYTE
)&PipeTimeout
,
2254 ScmDeleteNamedPipeCriticalSection(VOID
)
2256 DeleteCriticalSection(&ControlServiceCriticalSection
);