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
)
151 PLIST_ENTRY ServiceEntry
;
152 PSERVICE CurrentService
;
153 PSERVICE_IMAGE CurrentImage
;
154 PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutBuffer
= NULL
;
157 /* Lock the database */
158 ScmLockDatabaseExclusive();
160 /* Find the matching service */
161 ServiceEntry
= ServiceListHead
.Flink
;
162 while (ServiceEntry
!= &ServiceListHead
)
164 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
168 /* We must match the tag */
169 if (CurrentService
->dwTag
== InParams
->dwTag
&&
170 CurrentService
->lpImage
!= NULL
)
172 CurrentImage
= CurrentService
->lpImage
;
173 /* And matching the PID */
174 if (CurrentImage
->hProcess
== (HANDLE
)InParams
->dwPid
)
180 ServiceEntry
= ServiceEntry
->Flink
;
184 if (ServiceEntry
== &ServiceListHead
)
186 dwError
= ERROR_RETRY
;
190 /* Allocate the output buffer */
191 OutBuffer
= MIDL_user_allocate(sizeof(TAG_INFO_NAME_FROM_TAG_OUT_PARAMS
));
192 if (OutBuffer
== NULL
)
194 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
198 /* And the buffer for the name */
199 OutBuffer
->pszName
= MIDL_user_allocate(wcslen(CurrentService
->lpServiceName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
200 if (OutBuffer
->pszName
== NULL
)
202 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
206 /* Fill in output data */
207 wcscpy(OutBuffer
->pszName
, CurrentService
->lpServiceName
);
208 OutBuffer
->TagType
= TagTypeService
;
211 *OutParams
= OutBuffer
;
212 dwError
= ERROR_SUCCESS
;
216 /* Unlock database */
219 /* If failure, free allocated memory */
220 if (dwError
!= ERROR_SUCCESS
)
222 MIDL_user_free(OutBuffer
);
225 /* Return error/success */
232 ScmIsSameServiceAccount(
233 _In_ PCWSTR pszAccountName1
,
234 _In_ PCWSTR pszAccountName2
)
236 if (pszAccountName1
== NULL
&&
237 pszAccountName2
== NULL
)
240 if (pszAccountName1
== NULL
&&
241 pszAccountName2
!= NULL
&&
242 _wcsicmp(pszAccountName2
, L
"LocalSystem") == 0)
245 if (pszAccountName1
!= NULL
&&
246 pszAccountName2
== NULL
&&
247 _wcsicmp(pszAccountName1
, L
"LocalSystem") == 0)
250 if (pszAccountName1
!= NULL
&&
251 pszAccountName2
!= NULL
&&
252 _wcsicmp(pszAccountName1
, pszAccountName2
) == 0)
261 ScmIsLocalSystemAccount(
262 _In_ PCWSTR pszAccountName
)
264 if (pszAccountName
== NULL
||
265 _wcsicmp(pszAccountName
, L
"LocalSystem") == 0)
275 IN PSERVICE pService
,
276 IN PSERVICE_IMAGE pImage
)
278 DWORD dwError
= ERROR_SUCCESS
;
279 PROFILEINFOW ProfileInfo
;
280 PWSTR pszUserName
= NULL
;
281 PWSTR pszDomainName
= NULL
;
282 PWSTR pszPassword
= NULL
;
285 DPRINT("ScmLogonService(%p %p)\n", pService
, pImage
);
286 DPRINT("Service %S\n", pService
->lpServiceName
);
288 if (ScmIsLocalSystemAccount(pImage
->pszAccountName
))
289 return ERROR_SUCCESS
;
291 /* Get the user and domain names */
292 ptr
= wcschr(pImage
->pszAccountName
, L
'\\');
296 pszUserName
= ptr
+ 1;
297 pszDomainName
= pImage
->pszAccountName
;
301 // ERROR_INVALID_SERVICE_ACCOUNT
302 pszUserName
= pImage
->pszAccountName
;
303 pszDomainName
= NULL
;
306 /* Build the service 'password' */
307 pszPassword
= HeapAlloc(GetProcessHeap(),
309 (wcslen(pService
->lpServiceName
) + 5) * sizeof(WCHAR
));
310 if (pszPassword
== NULL
)
312 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
316 wcscpy(pszPassword
, L
"_SC_");
317 wcscat(pszPassword
, pService
->lpServiceName
);
319 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName
, pszUserName
, pszPassword
);
321 /* Do the service logon */
322 if (!LogonUserW(pszUserName
,
325 LOGON32_LOGON_SERVICE
,
326 LOGON32_PROVIDER_DEFAULT
,
329 dwError
= GetLastError();
330 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError
);
332 /* Normalize the returned error */
333 dwError
= ERROR_SERVICE_LOGON_FAILED
;
337 /* Load the user profile; the per-user environment variables are thus correctly initialized */
338 ZeroMemory(&ProfileInfo
, sizeof(ProfileInfo
));
339 ProfileInfo
.dwSize
= sizeof(ProfileInfo
);
340 ProfileInfo
.dwFlags
= PI_NOUI
;
341 ProfileInfo
.lpUserName
= pszUserName
;
342 // ProfileInfo.lpProfilePath = NULL;
343 // ProfileInfo.lpDefaultPath = NULL;
344 // ProfileInfo.lpServerName = NULL;
345 // ProfileInfo.lpPolicyPath = NULL;
346 // ProfileInfo.hProfile = NULL;
348 if (!LoadUserProfileW(pImage
->hToken
, &ProfileInfo
))
350 dwError
= GetLastError();
351 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError
);
355 pImage
->hProfile
= ProfileInfo
.hProfile
;
358 if (pszPassword
!= NULL
)
359 HeapFree(GetProcessHeap(), 0, pszPassword
);
369 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
371 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
372 UNICODE_STRING ImagePath
;
373 UNICODE_STRING ObjectName
;
374 PSERVICE_IMAGE pServiceImage
= NULL
;
376 DWORD dwError
= ERROR_SUCCESS
;
380 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
382 RtlInitUnicodeString(&ImagePath
, NULL
);
383 RtlInitUnicodeString(&ObjectName
, NULL
);
385 /* Get service data */
386 RtlZeroMemory(&QueryTable
,
389 QueryTable
[0].Name
= L
"ImagePath";
390 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
391 QueryTable
[0].EntryContext
= &ImagePath
;
392 QueryTable
[1].Name
= L
"ObjectName";
393 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
394 QueryTable
[1].EntryContext
= &ObjectName
;
396 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
397 pService
->lpServiceName
,
401 if (!NT_SUCCESS(Status
))
403 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
404 return RtlNtStatusToDosError(Status
);
407 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
408 DPRINT("ObjectName: '%wZ'\n", &ObjectName
);
410 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
411 if (pServiceImage
== NULL
)
413 dwRecordSize
= sizeof(SERVICE_IMAGE
) +
414 ImagePath
.Length
+ sizeof(WCHAR
) +
415 ((ObjectName
.Length
!= 0) ? (ObjectName
.Length
+ sizeof(WCHAR
)) : 0);
417 /* Create a new service image */
418 pServiceImage
= HeapAlloc(GetProcessHeap(),
421 if (pServiceImage
== NULL
)
423 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
427 pServiceImage
->dwImageRunCount
= 1;
428 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
429 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
431 pString
= (PWSTR
)((INT_PTR
)pServiceImage
+ sizeof(SERVICE_IMAGE
));
433 /* Set the image path */
434 pServiceImage
->pszImagePath
= pString
;
435 wcscpy(pServiceImage
->pszImagePath
,
438 /* Set the account name */
439 if (ObjectName
.Length
> 0)
441 pString
= pString
+ wcslen(pString
) + 1;
443 pServiceImage
->pszAccountName
= pString
;
444 wcscpy(pServiceImage
->pszAccountName
,
449 dwError
= ScmLogonService(pService
, pServiceImage
);
450 if (dwError
!= ERROR_SUCCESS
)
452 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError
);
454 /* Release the service image */
455 HeapFree(GetProcessHeap(), 0, pServiceImage
);
460 /* Create the control pipe */
461 dwError
= ScmCreateNewControlPipe(pServiceImage
);
462 if (dwError
!= ERROR_SUCCESS
)
464 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError
);
466 /* Unload the user profile */
467 if (pServiceImage
->hProfile
!= NULL
)
468 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
470 /* Close the logon token */
471 if (pServiceImage
->hToken
!= NULL
)
472 CloseHandle(pServiceImage
->hToken
);
474 /* Release the service image */
475 HeapFree(GetProcessHeap(), 0, pServiceImage
);
480 /* FIXME: Add more initialization code here */
483 /* Append service record */
484 InsertTailList(&ImageListHead
,
485 &pServiceImage
->ImageListEntry
);
489 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
491 /* Fail if services in an image use different accounts */
492 if (!ScmIsSameServiceAccount(pServiceImage
->pszAccountName
, ObjectName
.Buffer
))
494 dwError
= ERROR_DIFFERENT_SERVICE_ACCOUNT
;
498 /* Increment the run counter */
499 pServiceImage
->dwImageRunCount
++;
502 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage
->pszImagePath
);
503 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage
->pszAccountName
);
504 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
506 /* Link the service image to the service */
507 pService
->lpImage
= pServiceImage
;
510 RtlFreeUnicodeString(&ObjectName
);
511 RtlFreeUnicodeString(&ImagePath
);
513 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
520 ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage
)
522 DPRINT1("ScmRemoveServiceImage() called\n");
524 /* FIXME: Terminate the process */
526 /* Remove the service image from the list */
527 RemoveEntryList(&pServiceImage
->ImageListEntry
);
529 /* Close the process handle */
530 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
531 CloseHandle(pServiceImage
->hProcess
);
533 /* Close the control pipe */
534 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
535 CloseHandle(pServiceImage
->hControlPipe
);
537 /* Unload the user profile */
538 if (pServiceImage
->hProfile
!= NULL
)
539 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
541 /* Close the logon token */
542 if (pServiceImage
->hToken
!= NULL
)
543 CloseHandle(pServiceImage
->hToken
);
545 /* Release the service image */
546 HeapFree(GetProcessHeap(), 0, pServiceImage
);
551 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
553 PLIST_ENTRY ServiceEntry
;
554 PSERVICE CurrentService
;
556 DPRINT("ScmGetServiceEntryByName() called\n");
558 ServiceEntry
= ServiceListHead
.Flink
;
559 while (ServiceEntry
!= &ServiceListHead
)
561 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
564 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
566 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
567 return CurrentService
;
570 ServiceEntry
= ServiceEntry
->Flink
;
573 DPRINT("Couldn't find a matching service\n");
580 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
582 PLIST_ENTRY ServiceEntry
;
583 PSERVICE CurrentService
;
585 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
587 ServiceEntry
= ServiceListHead
.Flink
;
588 while (ServiceEntry
!= &ServiceListHead
)
590 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
593 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
595 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
596 return CurrentService
;
599 ServiceEntry
= ServiceEntry
->Flink
;
602 DPRINT("Couldn't find a matching service\n");
609 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
611 PLIST_ENTRY ServiceEntry
;
612 PSERVICE CurrentService
;
614 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
616 ServiceEntry
= ServiceListHead
.Flink
;
617 while (ServiceEntry
!= &ServiceListHead
)
619 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
622 if (CurrentService
->dwResumeCount
> dwResumeCount
)
624 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
625 return CurrentService
;
628 ServiceEntry
= ServiceEntry
->Flink
;
631 DPRINT("Couldn't find a matching service\n");
638 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
639 PSERVICE
*lpServiceRecord
,
643 PSERVICE lpService
= NULL
;
645 DPRINT("Service: '%S'\n", lpServiceName
);
647 /* Allocate service entry */
648 lpService
= HeapAlloc(GetProcessHeap(),
650 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
651 if (lpService
== NULL
)
652 return ERROR_NOT_ENOUGH_MEMORY
;
654 *lpServiceRecord
= lpService
;
656 /* Copy service name */
657 wcscpy(lpService
->szServiceName
, lpServiceName
);
658 lpService
->lpServiceName
= lpService
->szServiceName
;
659 lpService
->lpDisplayName
= lpService
->lpServiceName
;
661 /* Set the start type */
662 lpService
->dwStartType
= dwStartType
;
664 /* Set the resume count */
665 lpService
->dwResumeCount
= ResumeCount
++;
667 /* Append service record */
668 InsertTailList(&ServiceListHead
,
669 &lpService
->ServiceListEntry
);
671 /* Initialize the service status */
672 lpService
->Status
.dwServiceType
= dwServiceType
;
673 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
674 lpService
->Status
.dwControlsAccepted
= 0;
675 lpService
->Status
.dwWin32ExitCode
=
676 (dwStartType
== SERVICE_DISABLED
) ? ERROR_SERVICE_DISABLED
: ERROR_SERVICE_NEVER_STARTED
;
677 lpService
->Status
.dwServiceSpecificExitCode
= 0;
678 lpService
->Status
.dwCheckPoint
= 0;
679 lpService
->Status
.dwWaitHint
=
680 (dwServiceType
& SERVICE_DRIVER
) ? 0 : 2000; /* 2 seconds */
682 return ERROR_SUCCESS
;
687 ScmDeleteServiceRecord(PSERVICE lpService
)
689 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
691 /* Delete the display name */
692 if (lpService
->lpDisplayName
!= NULL
&&
693 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
694 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
696 /* Dereference the service image */
697 if (lpService
->lpImage
)
699 lpService
->lpImage
->dwImageRunCount
--;
701 if (lpService
->lpImage
->dwImageRunCount
== 0)
703 ScmRemoveServiceImage(lpService
->lpImage
);
704 lpService
->lpImage
= NULL
;
708 /* Decrement the group reference counter */
709 ScmSetServiceGroup(lpService
, NULL
);
711 /* Release the SecurityDescriptor */
712 if (lpService
->pSecurityDescriptor
!= NULL
)
713 HeapFree(GetProcessHeap(), 0, lpService
->pSecurityDescriptor
);
715 /* Remove the Service from the List */
716 RemoveEntryList(&lpService
->ServiceListEntry
);
718 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
720 /* Delete the service record */
721 HeapFree(GetProcessHeap(), 0, lpService
);
728 CreateServiceListEntry(LPCWSTR lpServiceName
,
731 PSERVICE lpService
= NULL
;
732 LPWSTR lpDisplayName
= NULL
;
733 LPWSTR lpGroup
= NULL
;
738 DWORD dwErrorControl
;
741 DPRINT("Service: '%S'\n", lpServiceName
);
742 if (*lpServiceName
== L
'{')
743 return ERROR_SUCCESS
;
745 dwSize
= sizeof(DWORD
);
746 dwError
= RegQueryValueExW(hServiceKey
,
750 (LPBYTE
)&dwServiceType
,
752 if (dwError
!= ERROR_SUCCESS
)
753 return ERROR_SUCCESS
;
755 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
756 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
757 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
758 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
759 return ERROR_SUCCESS
;
761 DPRINT("Service type: %lx\n", dwServiceType
);
763 dwSize
= sizeof(DWORD
);
764 dwError
= RegQueryValueExW(hServiceKey
,
768 (LPBYTE
)&dwStartType
,
770 if (dwError
!= ERROR_SUCCESS
)
771 return ERROR_SUCCESS
;
773 DPRINT("Start type: %lx\n", dwStartType
);
775 dwSize
= sizeof(DWORD
);
776 dwError
= RegQueryValueExW(hServiceKey
,
780 (LPBYTE
)&dwErrorControl
,
782 if (dwError
!= ERROR_SUCCESS
)
783 return ERROR_SUCCESS
;
785 DPRINT("Error control: %lx\n", dwErrorControl
);
787 dwError
= RegQueryValueExW(hServiceKey
,
793 if (dwError
!= ERROR_SUCCESS
)
796 DPRINT("Tag: %lx\n", dwTagId
);
798 dwError
= ScmReadString(hServiceKey
,
801 if (dwError
!= ERROR_SUCCESS
)
804 DPRINT("Group: %S\n", lpGroup
);
806 dwError
= ScmReadString(hServiceKey
,
809 if (dwError
!= ERROR_SUCCESS
)
810 lpDisplayName
= NULL
;
812 DPRINT("Display name: %S\n", lpDisplayName
);
814 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
818 if (dwError
!= ERROR_SUCCESS
)
821 lpService
->dwErrorControl
= dwErrorControl
;
822 lpService
->dwTag
= dwTagId
;
826 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
827 if (dwError
!= ERROR_SUCCESS
)
831 if (lpDisplayName
!= NULL
)
833 lpService
->lpDisplayName
= lpDisplayName
;
834 lpDisplayName
= NULL
;
837 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
838 if (lpService
->lpGroup
!= NULL
)
840 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
842 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
843 lpService
->dwStartType
,
844 lpService
->Status
.dwServiceType
,
846 lpService
->dwErrorControl
);
848 if (ScmIsDeleteFlagSet(hServiceKey
))
849 lpService
->bDeleted
= TRUE
;
851 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
853 dwError
= ScmReadSecurityDescriptor(hServiceKey
,
854 &lpService
->pSecurityDescriptor
);
855 if (dwError
!= ERROR_SUCCESS
)
858 /* Assing the default security descriptor if the security descriptor cannot be read */
859 if (lpService
->pSecurityDescriptor
== NULL
)
861 DPRINT("No security descriptor found! Assign default security descriptor!\n");
862 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
863 if (dwError
!= ERROR_SUCCESS
)
866 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
867 lpService
->pSecurityDescriptor
);
868 if (dwError
!= ERROR_SUCCESS
)
875 HeapFree(GetProcessHeap(), 0, lpGroup
);
877 if (lpDisplayName
!= NULL
)
878 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
880 if (lpService
!= NULL
)
882 ASSERT(lpService
->lpImage
== NULL
);
890 ScmDeleteMarkedServices(VOID
)
892 PLIST_ENTRY ServiceEntry
;
893 PSERVICE CurrentService
;
897 ServiceEntry
= ServiceListHead
.Flink
;
898 while (ServiceEntry
!= &ServiceListHead
)
900 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
902 ServiceEntry
= ServiceEntry
->Flink
;
904 if (CurrentService
->bDeleted
!= FALSE
)
906 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
907 L
"System\\CurrentControlSet\\Services",
911 if (dwError
== ERROR_SUCCESS
)
913 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
914 RegCloseKey(hServicesKey
);
915 if (dwError
== ERROR_SUCCESS
)
917 RemoveEntryList(&CurrentService
->ServiceListEntry
);
918 HeapFree(GetProcessHeap(), 0, CurrentService
);
922 if (dwError
!= ERROR_SUCCESS
)
923 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
931 ScmGetNoInteractiveServicesValue(VOID
)
937 lError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
938 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
942 if (lError
== ERROR_SUCCESS
)
944 dwKeySize
= sizeof(NoInteractiveServices
);
945 lError
= RegQueryValueExW(hKey
,
946 L
"NoInteractiveServices",
949 (LPBYTE
)&NoInteractiveServices
,
957 ScmCreateServiceDatabase(VOID
)
959 WCHAR szSubKey
[MAX_PATH
];
963 DWORD dwSubKeyLength
;
964 FILETIME ftLastChanged
;
967 DPRINT("ScmCreateServiceDatabase() called\n");
969 /* Retrieve the NoInteractiveServies value */
970 ScmGetNoInteractiveServicesValue();
972 /* Create the service group list */
973 dwError
= ScmCreateGroupList();
974 if (dwError
!= ERROR_SUCCESS
)
977 /* Initialize image and service lists */
978 InitializeListHead(&ImageListHead
);
979 InitializeListHead(&ServiceListHead
);
981 /* Initialize the database lock */
982 RtlInitializeResource(&DatabaseLock
);
984 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
985 L
"System\\CurrentControlSet\\Services",
989 if (dwError
!= ERROR_SUCCESS
)
995 dwSubKeyLength
= MAX_PATH
;
996 dwError
= RegEnumKeyExW(hServicesKey
,
1004 if (dwError
== ERROR_SUCCESS
&&
1005 szSubKey
[0] != L
'{')
1007 DPRINT("SubKeyName: '%S'\n", szSubKey
);
1009 dwError
= RegOpenKeyExW(hServicesKey
,
1014 if (dwError
== ERROR_SUCCESS
)
1016 dwError
= CreateServiceListEntry(szSubKey
,
1019 RegCloseKey(hServiceKey
);
1023 if (dwError
!= ERROR_SUCCESS
)
1029 RegCloseKey(hServicesKey
);
1031 /* Wait for the LSA server */
1034 /* Delete services that are marked for delete */
1035 ScmDeleteMarkedServices();
1037 DPRINT("ScmCreateServiceDatabase() done\n");
1039 return ERROR_SUCCESS
;
1044 ScmShutdownServiceDatabase(VOID
)
1046 DPRINT("ScmShutdownServiceDatabase() called\n");
1048 ScmDeleteMarkedServices();
1049 RtlDeleteResource(&DatabaseLock
);
1051 DPRINT("ScmShutdownServiceDatabase() done\n");
1056 ScmCheckDriver(PSERVICE Service
)
1058 OBJECT_ATTRIBUTES ObjectAttributes
;
1059 UNICODE_STRING DirName
;
1062 POBJECT_DIRECTORY_INFORMATION DirInfo
;
1067 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
1069 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
1071 RtlInitUnicodeString(&DirName
, L
"\\Driver");
1073 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
1075 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
1076 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
1079 InitializeObjectAttributes(&ObjectAttributes
,
1085 Status
= NtOpenDirectoryObject(&DirHandle
,
1086 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1088 if (!NT_SUCCESS(Status
))
1093 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
1094 2 * MAX_PATH
* sizeof(WCHAR
);
1095 DirInfo
= HeapAlloc(GetProcessHeap(),
1102 Status
= NtQueryDirectoryObject(DirHandle
,
1109 if (Status
== STATUS_NO_MORE_ENTRIES
)
1111 /* FIXME: Add current service to 'failed service' list */
1112 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
1116 if (!NT_SUCCESS(Status
))
1119 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
1121 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
1123 DPRINT("Found: '%S' '%wZ'\n",
1124 Service
->lpServiceName
, &DirInfo
->Name
);
1126 /* Mark service as 'running' */
1127 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1128 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1129 Service
->Status
.dwWin32ExitCode
= ERROR_SUCCESS
;
1130 Service
->Status
.dwServiceSpecificExitCode
= 0;
1131 Service
->Status
.dwCheckPoint
= 0;
1132 Service
->Status
.dwWaitHint
= 0;
1134 /* Mark the service group as 'running' */
1135 if (Service
->lpGroup
!= NULL
)
1137 Service
->lpGroup
->ServicesRunning
= TRUE
;
1144 HeapFree(GetProcessHeap(),
1149 return STATUS_SUCCESS
;
1154 ScmGetBootAndSystemDriverState(VOID
)
1156 PLIST_ENTRY ServiceEntry
;
1157 PSERVICE CurrentService
;
1159 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1161 ServiceEntry
= ServiceListHead
.Flink
;
1162 while (ServiceEntry
!= &ServiceListHead
)
1164 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1166 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
1167 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
1170 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
1172 ScmCheckDriver(CurrentService
);
1175 ServiceEntry
= ServiceEntry
->Flink
;
1178 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1183 ScmControlService(HANDLE hControlPipe
,
1185 SERVICE_STATUS_HANDLE hServiceStatus
,
1188 PSCM_CONTROL_PACKET ControlPacket
;
1189 SCM_REPLY_PACKET ReplyPacket
;
1191 DWORD dwWriteCount
= 0;
1192 DWORD dwReadCount
= 0;
1195 DWORD dwError
= ERROR_SUCCESS
;
1197 OVERLAPPED Overlapped
= {0};
1199 DPRINT("ScmControlService() called\n");
1201 /* Acquire the service control critical section, to synchronize requests */
1202 EnterCriticalSection(&ControlServiceCriticalSection
);
1204 /* Calculate the total length of the start command line */
1205 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1206 PacketSize
+= (DWORD
)((wcslen(pServiceName
) + 1) * sizeof(WCHAR
));
1208 ControlPacket
= HeapAlloc(GetProcessHeap(),
1211 if (ControlPacket
== NULL
)
1213 LeaveCriticalSection(&ControlServiceCriticalSection
);
1214 return ERROR_NOT_ENOUGH_MEMORY
;
1217 ControlPacket
->dwSize
= PacketSize
;
1218 ControlPacket
->dwControl
= dwControl
;
1219 ControlPacket
->hServiceStatus
= hServiceStatus
;
1221 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1223 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1224 wcscpy(Ptr
, pServiceName
);
1226 ControlPacket
->dwArgumentsCount
= 0;
1227 ControlPacket
->dwArgumentsOffset
= 0;
1229 bResult
= WriteFile(hControlPipe
,
1234 if (bResult
== FALSE
)
1236 DPRINT("WriteFile() returned FALSE\n");
1238 dwError
= GetLastError();
1239 if (dwError
== ERROR_IO_PENDING
)
1241 DPRINT("dwError: ERROR_IO_PENDING\n");
1243 dwError
= WaitForSingleObject(hControlPipe
,
1245 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1247 if (dwError
== WAIT_TIMEOUT
)
1249 bResult
= CancelIo(hControlPipe
);
1250 if (bResult
== FALSE
)
1252 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1255 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1258 else if (dwError
== WAIT_OBJECT_0
)
1260 bResult
= GetOverlappedResult(hControlPipe
,
1264 if (bResult
== FALSE
)
1266 dwError
= GetLastError();
1267 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1275 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1280 /* Read the reply */
1281 Overlapped
.hEvent
= (HANDLE
) NULL
;
1283 bResult
= ReadFile(hControlPipe
,
1285 sizeof(SCM_REPLY_PACKET
),
1288 if (bResult
== FALSE
)
1290 DPRINT("ReadFile() returned FALSE\n");
1292 dwError
= GetLastError();
1293 if (dwError
== ERROR_IO_PENDING
)
1295 DPRINT("dwError: ERROR_IO_PENDING\n");
1297 dwError
= WaitForSingleObject(hControlPipe
,
1299 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1301 if (dwError
== WAIT_TIMEOUT
)
1303 bResult
= CancelIo(hControlPipe
);
1304 if (bResult
== FALSE
)
1306 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1309 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1312 else if (dwError
== WAIT_OBJECT_0
)
1314 bResult
= GetOverlappedResult(hControlPipe
,
1318 if (bResult
== FALSE
)
1320 dwError
= GetLastError();
1321 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1329 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1335 /* Release the control packet */
1336 HeapFree(GetProcessHeap(),
1340 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1342 dwError
= ReplyPacket
.dwError
;
1345 LeaveCriticalSection(&ControlServiceCriticalSection
);
1347 DPRINT("ScmControlService() done\n");
1354 ScmSendStartCommand(PSERVICE Service
,
1358 DWORD dwError
= ERROR_SUCCESS
;
1359 PSCM_CONTROL_PACKET ControlPacket
;
1360 SCM_REPLY_PACKET ReplyPacket
;
1367 DWORD dwWriteCount
= 0;
1368 DWORD dwReadCount
= 0;
1369 OVERLAPPED Overlapped
= {0};
1371 DPRINT("ScmSendStartCommand() called\n");
1373 /* Calculate the total length of the start command line */
1374 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1375 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1378 * Calculate the required packet size for the start argument vector 'argv',
1379 * composed of the list of pointer offsets, followed by UNICODE strings.
1380 * The strings are stored continuously after the vector of offsets, with
1381 * the offsets being relative to the beginning of the vector, as in the
1382 * following layout (with N == argc):
1383 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1385 if (argc
> 0 && argv
!= NULL
)
1387 PacketSize
= ALIGN_UP(PacketSize
, PWSTR
);
1388 PacketSize
+= (argc
* sizeof(PWSTR
));
1390 DPRINT("Argc: %lu\n", argc
);
1391 for (i
= 0; i
< argc
; i
++)
1393 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1394 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
));
1398 /* Allocate a control packet */
1399 ControlPacket
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, PacketSize
);
1400 if (ControlPacket
== NULL
)
1401 return ERROR_NOT_ENOUGH_MEMORY
;
1403 ControlPacket
->dwSize
= PacketSize
;
1404 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1405 ? SERVICE_CONTROL_START_OWN
1406 : SERVICE_CONTROL_START_SHARE
;
1407 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1409 /* Copy the start command line */
1410 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1411 Ptr
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1412 wcscpy(Ptr
, Service
->lpServiceName
);
1414 ControlPacket
->dwArgumentsCount
= 0;
1415 ControlPacket
->dwArgumentsOffset
= 0;
1417 /* Copy the argument vector */
1418 if (argc
> 0 && argv
!= NULL
)
1420 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1421 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1422 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1424 ControlPacket
->dwArgumentsCount
= argc
;
1425 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1427 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1428 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1430 for (i
= 0; i
< argc
; i
++)
1432 wcscpy(pArgPtr
, argv
[i
]);
1433 pOffPtr
[i
] = (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1434 DPRINT("offset[%lu]: %p\n", i
, pOffPtr
[i
]);
1435 pArgPtr
+= wcslen(argv
[i
]) + 1;
1439 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1444 if (bResult
== FALSE
)
1446 DPRINT("WriteFile() returned FALSE\n");
1448 dwError
= GetLastError();
1449 if (dwError
== ERROR_IO_PENDING
)
1451 DPRINT("dwError: ERROR_IO_PENDING\n");
1453 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1455 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1457 if (dwError
== WAIT_TIMEOUT
)
1459 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1460 if (bResult
== FALSE
)
1462 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1465 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1468 else if (dwError
== WAIT_OBJECT_0
)
1470 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1474 if (bResult
== FALSE
)
1476 dwError
= GetLastError();
1477 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1485 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1490 /* Read the reply */
1491 Overlapped
.hEvent
= (HANDLE
) NULL
;
1493 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1495 sizeof(SCM_REPLY_PACKET
),
1498 if (bResult
== FALSE
)
1500 DPRINT("ReadFile() returned FALSE\n");
1502 dwError
= GetLastError();
1503 if (dwError
== ERROR_IO_PENDING
)
1505 DPRINT("dwError: ERROR_IO_PENDING\n");
1507 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1509 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1511 if (dwError
== WAIT_TIMEOUT
)
1513 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1514 if (bResult
== FALSE
)
1516 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1519 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1522 else if (dwError
== WAIT_OBJECT_0
)
1524 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1528 if (bResult
== FALSE
)
1530 dwError
= GetLastError();
1531 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1539 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1545 /* Release the control packet */
1546 HeapFree(GetProcessHeap(),
1550 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1552 dwError
= ReplyPacket
.dwError
;
1555 DPRINT("ScmSendStartCommand() done\n");
1562 ScmWaitForServiceConnect(PSERVICE Service
)
1565 DWORD dwProcessId
= 0;
1566 DWORD dwError
= ERROR_SUCCESS
;
1568 OVERLAPPED Overlapped
= {0};
1570 LPCWSTR lpLogStrings
[3];
1571 WCHAR szBuffer1
[20];
1572 WCHAR szBuffer2
[20];
1575 DPRINT("ScmWaitForServiceConnect()\n");
1577 Overlapped
.hEvent
= (HANDLE
)NULL
;
1579 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1581 if (bResult
== FALSE
)
1583 DPRINT("ConnectNamedPipe() returned FALSE\n");
1585 dwError
= GetLastError();
1586 if (dwError
== ERROR_IO_PENDING
)
1588 DPRINT("dwError: ERROR_IO_PENDING\n");
1590 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1592 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1594 if (dwError
== WAIT_TIMEOUT
)
1596 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1598 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1599 if (bResult
== FALSE
)
1601 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1605 _ultow(PipeTimeout
, szBuffer1
, 10);
1606 lpLogStrings
[0] = Service
->lpDisplayName
;
1607 lpLogStrings
[1] = szBuffer1
;
1609 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1610 EVENTLOG_ERROR_TYPE
,
1614 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1616 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1618 else if (dwError
== WAIT_OBJECT_0
)
1620 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1624 if (bResult
== FALSE
)
1626 dwError
= GetLastError();
1627 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1633 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1635 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1640 DPRINT("Control pipe connected!\n");
1642 Overlapped
.hEvent
= (HANDLE
) NULL
;
1644 /* Read the process id from pipe */
1645 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1646 (LPVOID
)&dwProcessId
,
1650 if (bResult
== FALSE
)
1652 DPRINT("ReadFile() returned FALSE\n");
1654 dwError
= GetLastError();
1655 if (dwError
== ERROR_IO_PENDING
)
1657 DPRINT("dwError: ERROR_IO_PENDING\n");
1659 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1661 if (dwError
== WAIT_TIMEOUT
)
1663 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1665 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1666 if (bResult
== FALSE
)
1668 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1672 _ultow(PipeTimeout
, szBuffer1
, 10);
1673 lpLogStrings
[0] = szBuffer1
;
1675 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1676 EVENTLOG_ERROR_TYPE
,
1680 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1682 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1684 else if (dwError
== WAIT_OBJECT_0
)
1686 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1688 DPRINT("Process Id: %lu\n", dwProcessId
);
1690 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1694 if (bResult
== FALSE
)
1696 dwError
= GetLastError();
1697 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1704 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1709 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1714 if (dwProcessId
!= Service
->lpImage
->dwProcessId
)
1717 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1718 _ultow(dwProcessId
, szBuffer2
, 10);
1720 lpLogStrings
[0] = Service
->lpDisplayName
;
1721 lpLogStrings
[1] = szBuffer1
;
1722 lpLogStrings
[2] = szBuffer2
;
1724 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1725 EVENTLOG_WARNING_TYPE
,
1730 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1733 DPRINT("ScmWaitForServiceConnect() done\n");
1735 return ERROR_SUCCESS
;
1740 ScmStartUserModeService(PSERVICE Service
,
1744 PROCESS_INFORMATION ProcessInformation
;
1745 STARTUPINFOW StartupInfo
;
1746 LPVOID lpEnvironment
;
1748 DWORD dwError
= ERROR_SUCCESS
;
1750 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1752 /* If the image is already running ... */
1753 if (Service
->lpImage
->dwImageRunCount
> 1)
1755 /* ... just send a start command */
1756 return ScmSendStartCommand(Service
, argc
, argv
);
1759 /* Otherwise start its process */
1760 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1761 StartupInfo
.cb
= sizeof(StartupInfo
);
1762 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1764 if (Service
->lpImage
->hToken
)
1766 /* User token: Run the service under the user account */
1768 if (!CreateEnvironmentBlock(&lpEnvironment
, Service
->lpImage
->hToken
, FALSE
))
1770 /* We failed, run the service with the current environment */
1771 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1772 GetLastError(), Service
->lpServiceName
);
1773 lpEnvironment
= NULL
;
1776 /* Impersonate the new user */
1777 Result
= ImpersonateLoggedOnUser(Service
->lpImage
->hToken
);
1780 /* Launch the process in the user's logon session */
1781 Result
= CreateProcessAsUserW(Service
->lpImage
->hToken
,
1783 Service
->lpImage
->pszImagePath
,
1787 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1791 &ProcessInformation
);
1793 dwError
= GetLastError();
1795 /* Revert the impersonation */
1800 dwError
= GetLastError();
1801 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError
);
1806 /* No user token: Run the service under the LocalSystem account */
1808 if (!CreateEnvironmentBlock(&lpEnvironment
, NULL
, TRUE
))
1810 /* We failed, run the service with the current environment */
1811 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1812 GetLastError(), Service
->lpServiceName
);
1813 lpEnvironment
= NULL
;
1816 /* Use the interactive desktop if the service is interactive */
1817 if ((NoInteractiveServices
== 0) &&
1818 (Service
->Status
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
))
1820 StartupInfo
.dwFlags
|= STARTF_INHERITDESKTOP
;
1821 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
1824 Result
= CreateProcessW(NULL
,
1825 Service
->lpImage
->pszImagePath
,
1829 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1833 &ProcessInformation
);
1835 dwError
= GetLastError();
1839 DestroyEnvironmentBlock(lpEnvironment
);
1843 DPRINT1("Starting '%S' failed with error %d\n",
1844 Service
->lpServiceName
, dwError
);
1848 DPRINT("Process Id: %lu Handle %p\n",
1849 ProcessInformation
.dwProcessId
,
1850 ProcessInformation
.hProcess
);
1851 DPRINT("Thread Id: %lu Handle %p\n",
1852 ProcessInformation
.dwThreadId
,
1853 ProcessInformation
.hThread
);
1855 /* Get the process handle and ID */
1856 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1857 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1859 /* Resume the main thread and close its handle */
1860 ResumeThread(ProcessInformation
.hThread
);
1861 CloseHandle(ProcessInformation
.hThread
);
1863 /* Connect control pipe */
1864 dwError
= ScmWaitForServiceConnect(Service
);
1865 if (dwError
!= ERROR_SUCCESS
)
1867 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1868 Service
->lpImage
->dwProcessId
= 0;
1872 /* Send the start command */
1873 return ScmSendStartCommand(Service
, argc
, argv
);
1878 ScmLoadService(PSERVICE Service
,
1882 PSERVICE_GROUP Group
= Service
->lpGroup
;
1883 DWORD dwError
= ERROR_SUCCESS
;
1884 LPCWSTR lpLogStrings
[2];
1885 WCHAR szLogBuffer
[80];
1887 DPRINT("ScmLoadService() called\n");
1888 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1890 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1892 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1893 return ERROR_SERVICE_ALREADY_RUNNING
;
1896 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1898 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1900 /* Start the driver */
1901 dwError
= ScmStartDriver(Service
);
1903 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1905 /* Start user-mode service */
1906 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1907 if (dwError
== ERROR_SUCCESS
)
1909 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1910 if (dwError
== ERROR_SUCCESS
)
1912 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1913 Service
->Status
.dwControlsAccepted
= 0;
1917 Service
->lpImage
->dwImageRunCount
--;
1918 if (Service
->lpImage
->dwImageRunCount
== 0)
1920 ScmRemoveServiceImage(Service
->lpImage
);
1921 Service
->lpImage
= NULL
;
1927 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
1929 if (dwError
== ERROR_SUCCESS
)
1933 Group
->ServicesRunning
= TRUE
;
1936 /* Log a successful service start */
1937 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
1938 lpLogStrings
[0] = Service
->lpDisplayName
;
1939 lpLogStrings
[1] = szLogBuffer
;
1941 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1942 EVENTLOG_INFORMATION_TYPE
,
1948 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1950 /* Log a failed service start */
1951 StringCchPrintfW(szLogBuffer
, ARRAYSIZE(szLogBuffer
),
1953 lpLogStrings
[0] = Service
->lpServiceName
;
1954 lpLogStrings
[1] = szLogBuffer
;
1955 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
1956 EVENTLOG_ERROR_TYPE
,
1962 switch (Service
->dwErrorControl
)
1964 case SERVICE_ERROR_SEVERE
:
1965 if (IsLastKnownGood
== FALSE
)
1967 /* FIXME: Boot last known good configuration */
1971 case SERVICE_ERROR_CRITICAL
:
1972 if (IsLastKnownGood
== FALSE
)
1974 /* FIXME: Boot last known good configuration */
1990 ScmStartService(PSERVICE Service
,
1994 DWORD dwError
= ERROR_SUCCESS
;
1995 SC_RPC_LOCK Lock
= NULL
;
1997 DPRINT("ScmStartService() called\n");
1998 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
2000 /* Acquire the service control critical section, to synchronize starts */
2001 EnterCriticalSection(&ControlServiceCriticalSection
);
2004 * Acquire the user service start lock while the service is starting, if
2005 * needed (i.e. if we are not starting it during the initialization phase).
2006 * If we don't success, bail out.
2010 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
2011 if (dwError
!= ERROR_SUCCESS
) goto done
;
2014 /* Really start the service */
2015 dwError
= ScmLoadService(Service
, argc
, argv
);
2017 /* Release the service start lock, if needed, and the critical section */
2018 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
2021 LeaveCriticalSection(&ControlServiceCriticalSection
);
2023 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
2030 ScmAutoStartServices(VOID
)
2033 PLIST_ENTRY GroupEntry
;
2034 PLIST_ENTRY ServiceEntry
;
2035 PSERVICE_GROUP CurrentGroup
;
2036 PSERVICE CurrentService
;
2037 WCHAR szSafeBootServicePath
[MAX_PATH
];
2038 DWORD SafeBootEnabled
;
2044 * This function MUST be called ONLY at initialization time.
2045 * Therefore, no need to acquire the user service start lock.
2047 ASSERT(ScmInitialize
);
2049 /* Retrieve the SafeBoot parameter */
2050 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2051 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
2055 if (dwError
== ERROR_SUCCESS
)
2057 dwKeySize
= sizeof(SafeBootEnabled
);
2058 dwError
= RegQueryValueExW(hKey
,
2062 (LPBYTE
)&SafeBootEnabled
,
2067 /* Default to Normal boot if the value doesn't exist */
2068 if (dwError
!= ERROR_SUCCESS
)
2069 SafeBootEnabled
= 0;
2071 /* Acquire the service control critical section, to synchronize starts */
2072 EnterCriticalSection(&ControlServiceCriticalSection
);
2074 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
2075 ServiceEntry
= ServiceListHead
.Flink
;
2076 while (ServiceEntry
!= &ServiceListHead
)
2078 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2080 /* Build the safe boot path */
2081 StringCchCopyW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2082 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
2084 switch (SafeBootEnabled
)
2086 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
2089 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2094 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2099 if (SafeBootEnabled
!= 0)
2101 /* If key does not exist then do not assume safe mode */
2102 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2103 szSafeBootServicePath
,
2107 if (dwError
== ERROR_SUCCESS
)
2111 /* Finish Safe Boot path off */
2112 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2113 CurrentService
->lpServiceName
);
2115 /* Check that the key is in the Safe Boot path */
2116 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2117 szSafeBootServicePath
,
2121 if (dwError
!= ERROR_SUCCESS
)
2123 /* Mark service as visited so it is not auto-started */
2124 CurrentService
->ServiceVisited
= TRUE
;
2128 /* Must be auto-started in safe mode - mark as unvisited */
2130 CurrentService
->ServiceVisited
= FALSE
;
2135 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2136 CurrentService
->ServiceVisited
= FALSE
;
2140 ServiceEntry
= ServiceEntry
->Flink
;
2143 /* Start all services which are members of an existing group */
2144 GroupEntry
= GroupListHead
.Flink
;
2145 while (GroupEntry
!= &GroupListHead
)
2147 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
2149 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
2151 /* Start all services witch have a valid tag */
2152 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
2154 ServiceEntry
= ServiceListHead
.Flink
;
2155 while (ServiceEntry
!= &ServiceListHead
)
2157 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2159 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2160 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2161 (CurrentService
->ServiceVisited
== FALSE
) &&
2162 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
2164 CurrentService
->ServiceVisited
= TRUE
;
2165 ScmLoadService(CurrentService
, 0, NULL
);
2168 ServiceEntry
= ServiceEntry
->Flink
;
2172 /* Start all services which have an invalid tag or which do not have a tag */
2173 ServiceEntry
= ServiceListHead
.Flink
;
2174 while (ServiceEntry
!= &ServiceListHead
)
2176 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2178 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2179 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2180 (CurrentService
->ServiceVisited
== FALSE
))
2182 CurrentService
->ServiceVisited
= TRUE
;
2183 ScmLoadService(CurrentService
, 0, NULL
);
2186 ServiceEntry
= ServiceEntry
->Flink
;
2189 GroupEntry
= GroupEntry
->Flink
;
2192 /* Start all services which are members of any non-existing group */
2193 ServiceEntry
= ServiceListHead
.Flink
;
2194 while (ServiceEntry
!= &ServiceListHead
)
2196 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2198 if ((CurrentService
->lpGroup
!= NULL
) &&
2199 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2200 (CurrentService
->ServiceVisited
== FALSE
))
2202 CurrentService
->ServiceVisited
= TRUE
;
2203 ScmLoadService(CurrentService
, 0, NULL
);
2206 ServiceEntry
= ServiceEntry
->Flink
;
2209 /* Start all services which are not a member of any group */
2210 ServiceEntry
= ServiceListHead
.Flink
;
2211 while (ServiceEntry
!= &ServiceListHead
)
2213 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2215 if ((CurrentService
->lpGroup
== NULL
) &&
2216 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2217 (CurrentService
->ServiceVisited
== FALSE
))
2219 CurrentService
->ServiceVisited
= TRUE
;
2220 ScmLoadService(CurrentService
, 0, NULL
);
2223 ServiceEntry
= ServiceEntry
->Flink
;
2226 /* Clear 'ServiceVisited' flag again */
2227 ServiceEntry
= ServiceListHead
.Flink
;
2228 while (ServiceEntry
!= &ServiceListHead
)
2230 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2231 CurrentService
->ServiceVisited
= FALSE
;
2232 ServiceEntry
= ServiceEntry
->Flink
;
2235 /* Release the critical section */
2236 LeaveCriticalSection(&ControlServiceCriticalSection
);
2241 ScmAutoShutdownServices(VOID
)
2243 PLIST_ENTRY ServiceEntry
;
2244 PSERVICE CurrentService
;
2246 DPRINT("ScmAutoShutdownServices() called\n");
2248 /* Lock the service database exclusively */
2249 ScmLockDatabaseExclusive();
2251 ServiceEntry
= ServiceListHead
.Flink
;
2252 while (ServiceEntry
!= &ServiceListHead
)
2254 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2256 if ((CurrentService
->Status
.dwControlsAccepted
& SERVICE_ACCEPT_SHUTDOWN
) &&
2257 (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2258 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
))
2260 /* Send the shutdown notification */
2261 DPRINT("Shutdown service: %S\n", CurrentService
->lpServiceName
);
2262 ScmControlService(CurrentService
->lpImage
->hControlPipe
,
2263 CurrentService
->lpServiceName
,
2264 (SERVICE_STATUS_HANDLE
)CurrentService
,
2265 SERVICE_CONTROL_SHUTDOWN
);
2268 ServiceEntry
= ServiceEntry
->Flink
;
2271 /* Unlock the service database */
2272 ScmUnlockDatabase();
2274 DPRINT("ScmAutoShutdownServices() done\n");
2279 ScmLockDatabaseExclusive(VOID
)
2281 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2286 ScmLockDatabaseShared(VOID
)
2288 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2293 ScmUnlockDatabase(VOID
)
2295 RtlReleaseResource(&DatabaseLock
);
2300 ScmInitNamedPipeCriticalSection(VOID
)
2306 InitializeCriticalSection(&ControlServiceCriticalSection
);
2308 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2309 L
"SYSTEM\\CurrentControlSet\\Control",
2313 if (dwError
== ERROR_SUCCESS
)
2315 dwKeySize
= sizeof(PipeTimeout
);
2316 RegQueryValueExW(hKey
,
2317 L
"ServicesPipeTimeout",
2320 (LPBYTE
)&PipeTimeout
,
2328 ScmDeleteNamedPipeCriticalSection(VOID
)
2330 DeleteCriticalSection(&ControlServiceCriticalSection
);