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;
34 static DWORD ServiceTag
= 0;
36 /* The critical section synchronizes service control requests */
37 static CRITICAL_SECTION ControlServiceCriticalSection
;
38 static DWORD PipeTimeout
= 30000; /* 30 Seconds */
41 /* FUNCTIONS *****************************************************************/
46 _In_ PSERVICE_IMAGE pServiceImage
)
48 return (wcsstr(pServiceImage
->pszImagePath
, L
"\\system32\\lsass.exe") != NULL
);
53 ScmCreateNewControlPipe(
54 _In_ PSERVICE_IMAGE pServiceImage
,
55 _In_ BOOL bSecurityServiceProcess
)
57 WCHAR szControlPipeName
[MAX_PATH
+ 1];
58 SECURITY_ATTRIBUTES SecurityAttributes
;
59 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
60 DWORD dwServiceCurrent
= 1;
61 DWORD dwKeyDisposition
;
65 /* Get the service number */
66 if (bSecurityServiceProcess
== FALSE
)
68 /* TODO: Create registry entry with correct write access */
69 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
70 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent",
78 if (dwError
!= ERROR_SUCCESS
)
80 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
84 if (dwKeyDisposition
== REG_OPENED_EXISTING_KEY
)
86 dwKeySize
= sizeof(DWORD
);
87 dwError
= RegQueryValueExW(hServiceCurrentKey
,
91 (BYTE
*)&dwServiceCurrent
,
93 if (dwError
!= ERROR_SUCCESS
)
95 RegCloseKey(hServiceCurrentKey
);
96 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
103 dwError
= RegSetValueExW(hServiceCurrentKey
,
107 (BYTE
*)&dwServiceCurrent
,
108 sizeof(dwServiceCurrent
));
110 RegCloseKey(hServiceCurrentKey
);
112 if (dwError
!= ERROR_SUCCESS
)
114 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
120 dwServiceCurrent
= 0;
123 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
124 StringCchPrintfW(szControlPipeName
, ARRAYSIZE(szControlPipeName
),
125 L
"\\\\.\\pipe\\net\\NtControlPipe%lu", dwServiceCurrent
);
127 DPRINT("PipeName: %S\n", szControlPipeName
);
129 SecurityAttributes
.nLength
= sizeof(SecurityAttributes
);
130 SecurityAttributes
.lpSecurityDescriptor
= pPipeSD
;
131 SecurityAttributes
.bInheritHandle
= FALSE
;
133 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
134 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
135 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
140 &SecurityAttributes
);
141 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
142 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
144 DPRINT1("Failed to create control pipe!\n");
145 return GetLastError();
148 return ERROR_SUCCESS
;
152 static PSERVICE_IMAGE
153 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
155 PLIST_ENTRY ImageEntry
;
156 PSERVICE_IMAGE CurrentImage
;
158 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
160 ImageEntry
= ImageListHead
.Flink
;
161 while (ImageEntry
!= &ImageListHead
)
163 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
166 if (_wcsicmp(CurrentImage
->pszImagePath
, lpImagePath
) == 0)
168 DPRINT("Found image: '%S'\n", CurrentImage
->pszImagePath
);
172 ImageEntry
= ImageEntry
->Flink
;
175 DPRINT("Couldn't find a matching image\n");
183 ScmGetServiceNameFromTag(IN PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams
,
184 OUT PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS
*OutParams
)
186 PLIST_ENTRY ServiceEntry
;
187 PSERVICE CurrentService
;
188 PSERVICE_IMAGE CurrentImage
;
189 PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutBuffer
= NULL
;
192 /* Lock the database */
193 ScmLockDatabaseExclusive();
195 /* Find the matching service */
196 ServiceEntry
= ServiceListHead
.Flink
;
197 while (ServiceEntry
!= &ServiceListHead
)
199 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
203 /* We must match the tag */
204 if (CurrentService
->dwTag
== InParams
->dwTag
&&
205 CurrentService
->lpImage
!= NULL
)
207 CurrentImage
= CurrentService
->lpImage
;
208 /* And matching the PID */
209 if (CurrentImage
->dwProcessId
== InParams
->dwPid
)
215 ServiceEntry
= ServiceEntry
->Flink
;
219 if (ServiceEntry
== &ServiceListHead
)
221 dwError
= ERROR_RETRY
;
225 /* Allocate the output buffer */
226 OutBuffer
= MIDL_user_allocate(sizeof(TAG_INFO_NAME_FROM_TAG_OUT_PARAMS
));
227 if (OutBuffer
== NULL
)
229 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
233 /* And the buffer for the name */
234 OutBuffer
->pszName
= MIDL_user_allocate(wcslen(CurrentService
->lpServiceName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
235 if (OutBuffer
->pszName
== NULL
)
237 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
241 /* Fill in output data */
242 wcscpy(OutBuffer
->pszName
, CurrentService
->lpServiceName
);
243 OutBuffer
->TagType
= TagTypeService
;
246 *OutParams
= OutBuffer
;
247 dwError
= ERROR_SUCCESS
;
251 /* Unlock database */
254 /* If failure, free allocated memory */
255 if (dwError
!= ERROR_SUCCESS
)
257 if (OutBuffer
!= NULL
)
259 MIDL_user_free(OutBuffer
);
263 /* Return error/success */
270 ScmIsSameServiceAccount(
271 _In_ PCWSTR pszAccountName1
,
272 _In_ PCWSTR pszAccountName2
)
274 if (pszAccountName1
== NULL
&&
275 pszAccountName2
== NULL
)
278 if (pszAccountName1
== NULL
&&
279 pszAccountName2
!= NULL
&&
280 _wcsicmp(pszAccountName2
, L
"LocalSystem") == 0)
283 if (pszAccountName1
!= NULL
&&
284 pszAccountName2
== NULL
&&
285 _wcsicmp(pszAccountName1
, L
"LocalSystem") == 0)
288 if (pszAccountName1
!= NULL
&&
289 pszAccountName2
!= NULL
&&
290 _wcsicmp(pszAccountName1
, pszAccountName2
) == 0)
299 ScmIsLocalSystemAccount(
300 _In_ PCWSTR pszAccountName
)
302 if (pszAccountName
== NULL
||
303 _wcsicmp(pszAccountName
, L
"LocalSystem") == 0)
312 ScmEnableBackupRestorePrivileges(
316 PTOKEN_PRIVILEGES pTokenPrivileges
= NULL
;
320 DPRINT("ScmEnableBackupRestorePrivileges(%p %d)\n", hToken
, bEnable
);
322 dwSize
= sizeof(TOKEN_PRIVILEGES
) + 2 * sizeof(LUID_AND_ATTRIBUTES
);
323 pTokenPrivileges
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwSize
);
324 if (pTokenPrivileges
== NULL
)
326 DPRINT1("Failed to allocate the privilege buffer!\n");
330 pTokenPrivileges
->PrivilegeCount
= 2;
331 pTokenPrivileges
->Privileges
[0].Luid
.LowPart
= SE_BACKUP_PRIVILEGE
;
332 pTokenPrivileges
->Privileges
[0].Luid
.HighPart
= 0;
333 pTokenPrivileges
->Privileges
[0].Attributes
= (bEnable
? SE_PRIVILEGE_ENABLED
: 0);
334 pTokenPrivileges
->Privileges
[1].Luid
.LowPart
= SE_RESTORE_PRIVILEGE
;
335 pTokenPrivileges
->Privileges
[1].Luid
.HighPart
= 0;
336 pTokenPrivileges
->Privileges
[1].Attributes
= (bEnable
? SE_PRIVILEGE_ENABLED
: 0);
338 bRet
= AdjustTokenPrivileges(hToken
, FALSE
, pTokenPrivileges
, 0, NULL
, NULL
);
341 DPRINT1("AdjustTokenPrivileges() failed with error %lu\n", GetLastError());
343 else if (GetLastError() == ERROR_NOT_ALL_ASSIGNED
)
345 DPRINT1("AdjustTokenPrivileges() succeeded, but with not all privileges assigned\n");
350 if (pTokenPrivileges
!= NULL
)
351 HeapFree(GetProcessHeap(), 0, pTokenPrivileges
);
360 IN PSERVICE pService
,
361 IN PSERVICE_IMAGE pImage
)
363 PROFILEINFOW ProfileInfo
;
364 PWSTR pszUserName
= NULL
;
365 PWSTR pszDomainName
= NULL
;
366 PWSTR pszPassword
= NULL
;
368 DWORD dwError
= ERROR_SUCCESS
;
370 DPRINT("ScmLogonService(%p %p)\n", pService
, pImage
);
371 DPRINT("Service %S\n", pService
->lpServiceName
);
373 if (ScmIsLocalSystemAccount(pImage
->pszAccountName
) || ScmLiveSetup
)
374 return ERROR_SUCCESS
;
376 /* Get the user and domain names */
377 ptr
= wcschr(pImage
->pszAccountName
, L
'\\');
381 pszUserName
= ptr
+ 1;
382 pszDomainName
= pImage
->pszAccountName
;
386 // ERROR_INVALID_SERVICE_ACCOUNT
387 pszUserName
= pImage
->pszAccountName
;
388 pszDomainName
= NULL
;
391 /* Build the service 'password' */
392 pszPassword
= HeapAlloc(GetProcessHeap(),
394 (wcslen(pService
->lpServiceName
) + 5) * sizeof(WCHAR
));
395 if (pszPassword
== NULL
)
397 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
401 wcscpy(pszPassword
, L
"_SC_");
402 wcscat(pszPassword
, pService
->lpServiceName
);
404 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName
, pszUserName
, pszPassword
);
406 /* Do the service logon */
407 if (!LogonUserW(pszUserName
,
410 LOGON32_LOGON_SERVICE
,
411 LOGON32_PROVIDER_DEFAULT
,
414 dwError
= GetLastError();
415 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError
);
417 /* Normalize the returned error */
418 dwError
= ERROR_SERVICE_LOGON_FAILED
;
422 /* Load the user profile; the per-user environment variables are thus correctly initialized */
423 ZeroMemory(&ProfileInfo
, sizeof(ProfileInfo
));
424 ProfileInfo
.dwSize
= sizeof(ProfileInfo
);
425 ProfileInfo
.dwFlags
= PI_NOUI
;
426 ProfileInfo
.lpUserName
= pszUserName
;
427 // ProfileInfo.lpProfilePath = NULL;
428 // ProfileInfo.lpDefaultPath = NULL;
429 // ProfileInfo.lpServerName = NULL;
430 // ProfileInfo.lpPolicyPath = NULL;
431 // ProfileInfo.hProfile = NULL;
433 ScmEnableBackupRestorePrivileges(pImage
->hToken
, TRUE
);
434 if (!LoadUserProfileW(pImage
->hToken
, &ProfileInfo
))
435 dwError
= GetLastError();
436 ScmEnableBackupRestorePrivileges(pImage
->hToken
, FALSE
);
438 if (dwError
!= ERROR_SUCCESS
)
440 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError
);
444 pImage
->hProfile
= ProfileInfo
.hProfile
;
447 if (pszPassword
!= NULL
)
448 HeapFree(GetProcessHeap(), 0, pszPassword
);
458 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
460 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
461 UNICODE_STRING ImagePath
;
462 UNICODE_STRING ObjectName
;
463 PSERVICE_IMAGE pServiceImage
= NULL
;
465 DWORD dwError
= ERROR_SUCCESS
;
468 BOOL bSecurityService
;
470 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
472 RtlInitUnicodeString(&ImagePath
, NULL
);
473 RtlInitUnicodeString(&ObjectName
, NULL
);
475 /* Get service data */
476 RtlZeroMemory(&QueryTable
,
479 QueryTable
[0].Name
= L
"ImagePath";
480 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
481 QueryTable
[0].EntryContext
= &ImagePath
;
482 QueryTable
[1].Name
= L
"ObjectName";
483 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
484 QueryTable
[1].EntryContext
= &ObjectName
;
486 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
487 pService
->lpServiceName
,
491 if (!NT_SUCCESS(Status
))
493 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
494 return RtlNtStatusToDosError(Status
);
497 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
498 DPRINT("ObjectName: '%wZ'\n", &ObjectName
);
500 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
501 if (pServiceImage
== NULL
)
503 dwRecordSize
= sizeof(SERVICE_IMAGE
) +
504 ImagePath
.Length
+ sizeof(WCHAR
) +
505 ((ObjectName
.Length
!= 0) ? (ObjectName
.Length
+ sizeof(WCHAR
)) : 0);
507 /* Create a new service image */
508 pServiceImage
= HeapAlloc(GetProcessHeap(),
511 if (pServiceImage
== NULL
)
513 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
517 pServiceImage
->dwImageRunCount
= 1;
518 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
519 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
521 pString
= (PWSTR
)((INT_PTR
)pServiceImage
+ sizeof(SERVICE_IMAGE
));
523 /* Set the image path */
524 pServiceImage
->pszImagePath
= pString
;
525 wcscpy(pServiceImage
->pszImagePath
,
528 /* Set the account name */
529 if (ObjectName
.Length
> 0)
531 pString
= pString
+ wcslen(pString
) + 1;
533 pServiceImage
->pszAccountName
= pString
;
534 wcscpy(pServiceImage
->pszAccountName
,
539 dwError
= ScmLogonService(pService
, pServiceImage
);
540 if (dwError
!= ERROR_SUCCESS
)
542 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError
);
544 /* Release the service image */
545 HeapFree(GetProcessHeap(), 0, pServiceImage
);
550 bSecurityService
= ScmIsSecurityService(pServiceImage
);
552 /* Create the control pipe */
553 dwError
= ScmCreateNewControlPipe(pServiceImage
,
555 if (dwError
!= ERROR_SUCCESS
)
557 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError
);
559 /* Unload the user profile */
560 if (pServiceImage
->hProfile
!= NULL
)
562 ScmEnableBackupRestorePrivileges(pServiceImage
->hToken
, TRUE
);
563 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
564 ScmEnableBackupRestorePrivileges(pServiceImage
->hToken
, FALSE
);
567 /* Close the logon token */
568 if (pServiceImage
->hToken
!= NULL
)
569 CloseHandle(pServiceImage
->hToken
);
571 /* Release the service image */
572 HeapFree(GetProcessHeap(), 0, pServiceImage
);
577 if (bSecurityService
)
579 SetSecurityServicesEvent();
582 /* FIXME: Add more initialization code here */
585 /* Append service record */
586 InsertTailList(&ImageListHead
,
587 &pServiceImage
->ImageListEntry
);
591 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
593 /* Fail if services in an image use different accounts */
594 if (!ScmIsSameServiceAccount(pServiceImage
->pszAccountName
, ObjectName
.Buffer
))
596 dwError
= ERROR_DIFFERENT_SERVICE_ACCOUNT
;
600 /* Increment the run counter */
601 pServiceImage
->dwImageRunCount
++;
604 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage
->pszImagePath
);
605 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage
->pszAccountName
);
606 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
608 /* Link the service image to the service */
609 pService
->lpImage
= pServiceImage
;
612 RtlFreeUnicodeString(&ObjectName
);
613 RtlFreeUnicodeString(&ImagePath
);
615 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
622 ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage
)
624 DPRINT1("ScmRemoveServiceImage() called\n");
626 /* FIXME: Terminate the process */
628 /* Remove the service image from the list */
629 RemoveEntryList(&pServiceImage
->ImageListEntry
);
631 /* Close the process handle */
632 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
633 CloseHandle(pServiceImage
->hProcess
);
635 /* Close the control pipe */
636 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
637 CloseHandle(pServiceImage
->hControlPipe
);
639 /* Unload the user profile */
640 if (pServiceImage
->hProfile
!= NULL
)
642 ScmEnableBackupRestorePrivileges(pServiceImage
->hToken
, TRUE
);
643 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
644 ScmEnableBackupRestorePrivileges(pServiceImage
->hToken
, FALSE
);
647 /* Close the logon token */
648 if (pServiceImage
->hToken
!= NULL
)
649 CloseHandle(pServiceImage
->hToken
);
651 /* Release the service image */
652 HeapFree(GetProcessHeap(), 0, pServiceImage
);
657 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
659 PLIST_ENTRY ServiceEntry
;
660 PSERVICE CurrentService
;
662 DPRINT("ScmGetServiceEntryByName() called\n");
664 ServiceEntry
= ServiceListHead
.Flink
;
665 while (ServiceEntry
!= &ServiceListHead
)
667 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
670 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
672 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
673 return CurrentService
;
676 ServiceEntry
= ServiceEntry
->Flink
;
679 DPRINT("Couldn't find a matching service\n");
686 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
688 PLIST_ENTRY ServiceEntry
;
689 PSERVICE CurrentService
;
691 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
693 ServiceEntry
= ServiceListHead
.Flink
;
694 while (ServiceEntry
!= &ServiceListHead
)
696 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
699 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
701 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
702 return CurrentService
;
705 ServiceEntry
= ServiceEntry
->Flink
;
708 DPRINT("Couldn't find a matching service\n");
715 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
717 PLIST_ENTRY ServiceEntry
;
718 PSERVICE CurrentService
;
720 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
722 ServiceEntry
= ServiceListHead
.Flink
;
723 while (ServiceEntry
!= &ServiceListHead
)
725 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
728 if (CurrentService
->dwResumeCount
> dwResumeCount
)
730 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
731 return CurrentService
;
734 ServiceEntry
= ServiceEntry
->Flink
;
737 DPRINT("Couldn't find a matching service\n");
744 ScmGenerateServiceTag(PSERVICE lpServiceRecord
)
746 /* Check for an overflow */
747 if (ServiceTag
== -1)
749 return ERROR_INVALID_DATA
;
752 /* This is only valid for Win32 services */
753 if (!(lpServiceRecord
->Status
.dwServiceType
& SERVICE_WIN32
))
755 return ERROR_INVALID_PARAMETER
;
758 /* Increment the tag counter and set it */
759 ServiceTag
= ServiceTag
% 0xFFFFFFFF + 1;
760 lpServiceRecord
->dwTag
= ServiceTag
;
762 return ERROR_SUCCESS
;
767 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
768 PSERVICE
*lpServiceRecord
,
772 PSERVICE lpService
= NULL
;
774 DPRINT("Service: '%S'\n", lpServiceName
);
776 /* Allocate service entry */
777 lpService
= HeapAlloc(GetProcessHeap(),
779 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
780 if (lpService
== NULL
)
781 return ERROR_NOT_ENOUGH_MEMORY
;
783 *lpServiceRecord
= lpService
;
785 /* Copy service name */
786 wcscpy(lpService
->szServiceName
, lpServiceName
);
787 lpService
->lpServiceName
= lpService
->szServiceName
;
788 lpService
->lpDisplayName
= lpService
->lpServiceName
;
790 /* Set the start type */
791 lpService
->dwStartType
= dwStartType
;
793 /* Set the resume count */
794 lpService
->dwResumeCount
= ResumeCount
++;
796 /* Append service record */
797 InsertTailList(&ServiceListHead
,
798 &lpService
->ServiceListEntry
);
800 /* Initialize the service status */
801 lpService
->Status
.dwServiceType
= dwServiceType
;
802 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
803 lpService
->Status
.dwControlsAccepted
= 0;
804 lpService
->Status
.dwWin32ExitCode
=
805 (dwStartType
== SERVICE_DISABLED
) ? ERROR_SERVICE_DISABLED
: ERROR_SERVICE_NEVER_STARTED
;
806 lpService
->Status
.dwServiceSpecificExitCode
= 0;
807 lpService
->Status
.dwCheckPoint
= 0;
808 lpService
->Status
.dwWaitHint
=
809 (dwServiceType
& SERVICE_DRIVER
) ? 0 : 2000; /* 2 seconds */
811 return ERROR_SUCCESS
;
816 ScmDeleteServiceRecord(PSERVICE lpService
)
818 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
820 /* Delete the display name */
821 if (lpService
->lpDisplayName
!= NULL
&&
822 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
823 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
825 /* Dereference the service image */
826 if (lpService
->lpImage
)
828 lpService
->lpImage
->dwImageRunCount
--;
830 if (lpService
->lpImage
->dwImageRunCount
== 0)
832 ScmRemoveServiceImage(lpService
->lpImage
);
833 lpService
->lpImage
= NULL
;
837 /* Decrement the group reference counter */
838 ScmSetServiceGroup(lpService
, NULL
);
840 /* Release the SecurityDescriptor */
841 if (lpService
->pSecurityDescriptor
!= NULL
)
842 HeapFree(GetProcessHeap(), 0, lpService
->pSecurityDescriptor
);
844 /* Remove the Service from the List */
845 RemoveEntryList(&lpService
->ServiceListEntry
);
847 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
849 /* Delete the service record */
850 HeapFree(GetProcessHeap(), 0, lpService
);
857 CreateServiceListEntry(LPCWSTR lpServiceName
,
860 PSERVICE lpService
= NULL
;
861 LPWSTR lpDisplayName
= NULL
;
862 LPWSTR lpGroup
= NULL
;
867 DWORD dwErrorControl
;
870 DPRINT("Service: '%S'\n", lpServiceName
);
871 if (*lpServiceName
== L
'{')
872 return ERROR_SUCCESS
;
874 dwSize
= sizeof(DWORD
);
875 dwError
= RegQueryValueExW(hServiceKey
,
879 (LPBYTE
)&dwServiceType
,
881 if (dwError
!= ERROR_SUCCESS
)
882 return ERROR_SUCCESS
;
884 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
885 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
886 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
887 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
888 return ERROR_SUCCESS
;
890 DPRINT("Service type: %lx\n", dwServiceType
);
892 dwSize
= sizeof(DWORD
);
893 dwError
= RegQueryValueExW(hServiceKey
,
897 (LPBYTE
)&dwStartType
,
899 if (dwError
!= ERROR_SUCCESS
)
900 return ERROR_SUCCESS
;
902 DPRINT("Start type: %lx\n", dwStartType
);
904 dwSize
= sizeof(DWORD
);
905 dwError
= RegQueryValueExW(hServiceKey
,
909 (LPBYTE
)&dwErrorControl
,
911 if (dwError
!= ERROR_SUCCESS
)
912 return ERROR_SUCCESS
;
914 DPRINT("Error control: %lx\n", dwErrorControl
);
916 dwError
= RegQueryValueExW(hServiceKey
,
922 if (dwError
!= ERROR_SUCCESS
)
925 DPRINT("Tag: %lx\n", dwTagId
);
927 dwError
= ScmReadString(hServiceKey
,
930 if (dwError
!= ERROR_SUCCESS
)
933 DPRINT("Group: %S\n", lpGroup
);
935 dwError
= ScmReadString(hServiceKey
,
938 if (dwError
!= ERROR_SUCCESS
)
939 lpDisplayName
= NULL
;
941 DPRINT("Display name: %S\n", lpDisplayName
);
943 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
947 if (dwError
!= ERROR_SUCCESS
)
950 lpService
->dwErrorControl
= dwErrorControl
;
951 lpService
->dwTag
= dwTagId
;
955 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
956 if (dwError
!= ERROR_SUCCESS
)
960 if (lpDisplayName
!= NULL
)
962 lpService
->lpDisplayName
= lpDisplayName
;
963 lpDisplayName
= NULL
;
966 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
967 if (lpService
->lpGroup
!= NULL
)
969 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
971 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
972 lpService
->dwStartType
,
973 lpService
->Status
.dwServiceType
,
975 lpService
->dwErrorControl
);
977 if (ScmIsDeleteFlagSet(hServiceKey
))
978 lpService
->bDeleted
= TRUE
;
980 ScmGenerateServiceTag(lpService
);
982 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
984 dwError
= ScmReadSecurityDescriptor(hServiceKey
,
985 &lpService
->pSecurityDescriptor
);
986 if (dwError
!= ERROR_SUCCESS
)
989 /* Assing the default security descriptor if the security descriptor cannot be read */
990 if (lpService
->pSecurityDescriptor
== NULL
)
992 DPRINT("No security descriptor found! Assign default security descriptor!\n");
993 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
994 if (dwError
!= ERROR_SUCCESS
)
997 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
998 lpService
->pSecurityDescriptor
);
999 if (dwError
!= ERROR_SUCCESS
)
1005 if (lpGroup
!= NULL
)
1006 HeapFree(GetProcessHeap(), 0, lpGroup
);
1008 if (lpDisplayName
!= NULL
)
1009 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
1011 if (lpService
!= NULL
)
1013 ASSERT(lpService
->lpImage
== NULL
);
1021 ScmDeleteMarkedServices(VOID
)
1023 PLIST_ENTRY ServiceEntry
;
1024 PSERVICE CurrentService
;
1028 ServiceEntry
= ServiceListHead
.Flink
;
1029 while (ServiceEntry
!= &ServiceListHead
)
1031 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1033 ServiceEntry
= ServiceEntry
->Flink
;
1035 if (CurrentService
->bDeleted
!= FALSE
)
1037 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1038 L
"System\\CurrentControlSet\\Services",
1042 if (dwError
== ERROR_SUCCESS
)
1044 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
1045 RegCloseKey(hServicesKey
);
1046 if (dwError
== ERROR_SUCCESS
)
1048 RemoveEntryList(&CurrentService
->ServiceListEntry
);
1049 HeapFree(GetProcessHeap(), 0, CurrentService
);
1053 if (dwError
!= ERROR_SUCCESS
)
1054 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
1062 ScmGetNoInteractiveServicesValue(VOID
)
1068 lError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1069 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
1073 if (lError
== ERROR_SUCCESS
)
1075 dwKeySize
= sizeof(NoInteractiveServices
);
1076 lError
= RegQueryValueExW(hKey
,
1077 L
"NoInteractiveServices",
1080 (LPBYTE
)&NoInteractiveServices
,
1088 ScmCreateServiceDatabase(VOID
)
1090 WCHAR szSubKey
[MAX_PATH
];
1094 DWORD dwSubKeyLength
;
1095 FILETIME ftLastChanged
;
1098 DPRINT("ScmCreateServiceDatabase() called\n");
1100 /* Retrieve the NoInteractiveServies value */
1101 ScmGetNoInteractiveServicesValue();
1103 /* Create the service group list */
1104 dwError
= ScmCreateGroupList();
1105 if (dwError
!= ERROR_SUCCESS
)
1108 /* Initialize image and service lists */
1109 InitializeListHead(&ImageListHead
);
1110 InitializeListHead(&ServiceListHead
);
1112 /* Initialize the database lock */
1113 RtlInitializeResource(&DatabaseLock
);
1115 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1116 L
"System\\CurrentControlSet\\Services",
1120 if (dwError
!= ERROR_SUCCESS
)
1126 dwSubKeyLength
= MAX_PATH
;
1127 dwError
= RegEnumKeyExW(hServicesKey
,
1135 if (dwError
== ERROR_SUCCESS
&&
1136 szSubKey
[0] != L
'{')
1138 DPRINT("SubKeyName: '%S'\n", szSubKey
);
1140 dwError
= RegOpenKeyExW(hServicesKey
,
1145 if (dwError
== ERROR_SUCCESS
)
1147 dwError
= CreateServiceListEntry(szSubKey
,
1150 RegCloseKey(hServiceKey
);
1154 if (dwError
!= ERROR_SUCCESS
)
1160 RegCloseKey(hServicesKey
);
1162 /* Wait for the LSA server */
1165 /* Delete services that are marked for delete */
1166 ScmDeleteMarkedServices();
1168 DPRINT("ScmCreateServiceDatabase() done\n");
1170 return ERROR_SUCCESS
;
1175 ScmShutdownServiceDatabase(VOID
)
1177 DPRINT("ScmShutdownServiceDatabase() called\n");
1179 ScmDeleteMarkedServices();
1180 RtlDeleteResource(&DatabaseLock
);
1182 DPRINT("ScmShutdownServiceDatabase() done\n");
1187 ScmCheckDriver(PSERVICE Service
)
1189 OBJECT_ATTRIBUTES ObjectAttributes
;
1190 UNICODE_STRING DirName
;
1193 POBJECT_DIRECTORY_INFORMATION DirInfo
;
1198 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
1200 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
1202 RtlInitUnicodeString(&DirName
, L
"\\Driver");
1204 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
1206 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
1207 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
1210 InitializeObjectAttributes(&ObjectAttributes
,
1216 Status
= NtOpenDirectoryObject(&DirHandle
,
1217 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1219 if (!NT_SUCCESS(Status
))
1224 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
1225 2 * MAX_PATH
* sizeof(WCHAR
);
1226 DirInfo
= HeapAlloc(GetProcessHeap(),
1233 Status
= NtQueryDirectoryObject(DirHandle
,
1240 if (Status
== STATUS_NO_MORE_ENTRIES
)
1242 /* FIXME: Add current service to 'failed service' list */
1243 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
1247 if (!NT_SUCCESS(Status
))
1250 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
1252 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
1254 DPRINT("Found: '%S' '%wZ'\n",
1255 Service
->lpServiceName
, &DirInfo
->Name
);
1257 /* Mark service as 'running' */
1258 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1259 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1260 Service
->Status
.dwWin32ExitCode
= ERROR_SUCCESS
;
1261 Service
->Status
.dwServiceSpecificExitCode
= 0;
1262 Service
->Status
.dwCheckPoint
= 0;
1263 Service
->Status
.dwWaitHint
= 0;
1265 /* Mark the service group as 'running' */
1266 if (Service
->lpGroup
!= NULL
)
1268 Service
->lpGroup
->ServicesRunning
= TRUE
;
1275 HeapFree(GetProcessHeap(),
1280 return STATUS_SUCCESS
;
1285 ScmGetBootAndSystemDriverState(VOID
)
1287 PLIST_ENTRY ServiceEntry
;
1288 PSERVICE CurrentService
;
1290 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1292 ServiceEntry
= ServiceListHead
.Flink
;
1293 while (ServiceEntry
!= &ServiceListHead
)
1295 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1297 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
1298 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
1301 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
1303 ScmCheckDriver(CurrentService
);
1306 ServiceEntry
= ServiceEntry
->Flink
;
1309 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1314 ScmControlService(HANDLE hControlPipe
,
1316 SERVICE_STATUS_HANDLE hServiceStatus
,
1319 PSCM_CONTROL_PACKET ControlPacket
;
1320 SCM_REPLY_PACKET ReplyPacket
;
1322 DWORD dwWriteCount
= 0;
1323 DWORD dwReadCount
= 0;
1326 DWORD dwError
= ERROR_SUCCESS
;
1328 OVERLAPPED Overlapped
= {0};
1330 DPRINT("ScmControlService() called\n");
1332 /* Acquire the service control critical section, to synchronize requests */
1333 EnterCriticalSection(&ControlServiceCriticalSection
);
1335 /* Calculate the total length of the start command line */
1336 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1337 PacketSize
+= (DWORD
)((wcslen(pServiceName
) + 1) * sizeof(WCHAR
));
1339 ControlPacket
= HeapAlloc(GetProcessHeap(),
1342 if (ControlPacket
== NULL
)
1344 LeaveCriticalSection(&ControlServiceCriticalSection
);
1345 return ERROR_NOT_ENOUGH_MEMORY
;
1348 ControlPacket
->dwSize
= PacketSize
;
1349 ControlPacket
->dwControl
= dwControl
;
1350 ControlPacket
->hServiceStatus
= hServiceStatus
;
1352 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1354 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1355 wcscpy(Ptr
, pServiceName
);
1357 ControlPacket
->dwArgumentsCount
= 0;
1358 ControlPacket
->dwArgumentsOffset
= 0;
1360 bResult
= WriteFile(hControlPipe
,
1365 if (bResult
== FALSE
)
1367 DPRINT("WriteFile() returned FALSE\n");
1369 dwError
= GetLastError();
1370 if (dwError
== ERROR_IO_PENDING
)
1372 DPRINT("dwError: ERROR_IO_PENDING\n");
1374 dwError
= WaitForSingleObject(hControlPipe
,
1376 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1378 if (dwError
== WAIT_TIMEOUT
)
1380 bResult
= CancelIo(hControlPipe
);
1381 if (bResult
== FALSE
)
1383 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1386 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1389 else if (dwError
== WAIT_OBJECT_0
)
1391 bResult
= GetOverlappedResult(hControlPipe
,
1395 if (bResult
== FALSE
)
1397 dwError
= GetLastError();
1398 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1406 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1411 /* Read the reply */
1412 Overlapped
.hEvent
= (HANDLE
) NULL
;
1414 bResult
= ReadFile(hControlPipe
,
1416 sizeof(SCM_REPLY_PACKET
),
1419 if (bResult
== FALSE
)
1421 DPRINT("ReadFile() returned FALSE\n");
1423 dwError
= GetLastError();
1424 if (dwError
== ERROR_IO_PENDING
)
1426 DPRINT("dwError: ERROR_IO_PENDING\n");
1428 dwError
= WaitForSingleObject(hControlPipe
,
1430 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1432 if (dwError
== WAIT_TIMEOUT
)
1434 bResult
= CancelIo(hControlPipe
);
1435 if (bResult
== FALSE
)
1437 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1440 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1443 else if (dwError
== WAIT_OBJECT_0
)
1445 bResult
= GetOverlappedResult(hControlPipe
,
1449 if (bResult
== FALSE
)
1451 dwError
= GetLastError();
1452 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1460 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1466 /* Release the control packet */
1467 HeapFree(GetProcessHeap(),
1471 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1473 dwError
= ReplyPacket
.dwError
;
1476 LeaveCriticalSection(&ControlServiceCriticalSection
);
1478 DPRINT("ScmControlService() done\n");
1485 ScmSendStartCommand(PSERVICE Service
,
1489 DWORD dwError
= ERROR_SUCCESS
;
1490 PSCM_CONTROL_PACKET ControlPacket
;
1491 SCM_REPLY_PACKET ReplyPacket
;
1498 DWORD dwWriteCount
= 0;
1499 DWORD dwReadCount
= 0;
1500 OVERLAPPED Overlapped
= {0};
1502 DPRINT("ScmSendStartCommand() called\n");
1504 /* Calculate the total length of the start command line */
1505 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1506 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1509 * Calculate the required packet size for the start argument vector 'argv',
1510 * composed of the list of pointer offsets, followed by UNICODE strings.
1511 * The strings are stored continuously after the vector of offsets, with
1512 * the offsets being relative to the beginning of the vector, as in the
1513 * following layout (with N == argc):
1514 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1516 if (argc
> 0 && argv
!= NULL
)
1518 PacketSize
= ALIGN_UP(PacketSize
, PWSTR
);
1519 PacketSize
+= (argc
* sizeof(PWSTR
));
1521 DPRINT("Argc: %lu\n", argc
);
1522 for (i
= 0; i
< argc
; i
++)
1524 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1525 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
));
1529 /* Allocate a control packet */
1530 ControlPacket
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, PacketSize
);
1531 if (ControlPacket
== NULL
)
1532 return ERROR_NOT_ENOUGH_MEMORY
;
1534 ControlPacket
->dwSize
= PacketSize
;
1535 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1536 ? SERVICE_CONTROL_START_OWN
1537 : SERVICE_CONTROL_START_SHARE
;
1538 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1539 ControlPacket
->dwServiceTag
= Service
->dwTag
;
1541 /* Copy the start command line */
1542 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1543 Ptr
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1544 wcscpy(Ptr
, Service
->lpServiceName
);
1546 ControlPacket
->dwArgumentsCount
= 0;
1547 ControlPacket
->dwArgumentsOffset
= 0;
1549 /* Copy the argument vector */
1550 if (argc
> 0 && argv
!= NULL
)
1552 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1553 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1554 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1556 ControlPacket
->dwArgumentsCount
= argc
;
1557 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1559 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1560 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1562 for (i
= 0; i
< argc
; i
++)
1564 wcscpy(pArgPtr
, argv
[i
]);
1565 pOffPtr
[i
] = (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1566 DPRINT("offset[%lu]: %p\n", i
, pOffPtr
[i
]);
1567 pArgPtr
+= wcslen(argv
[i
]) + 1;
1571 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1576 if (bResult
== FALSE
)
1578 DPRINT("WriteFile() 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 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1589 if (dwError
== WAIT_TIMEOUT
)
1591 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1592 if (bResult
== FALSE
)
1594 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1597 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1600 else if (dwError
== WAIT_OBJECT_0
)
1602 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1606 if (bResult
== FALSE
)
1608 dwError
= GetLastError();
1609 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1617 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1622 /* Read the reply */
1623 Overlapped
.hEvent
= (HANDLE
) NULL
;
1625 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1627 sizeof(SCM_REPLY_PACKET
),
1630 if (bResult
== FALSE
)
1632 DPRINT("ReadFile() returned FALSE\n");
1634 dwError
= GetLastError();
1635 if (dwError
== ERROR_IO_PENDING
)
1637 DPRINT("dwError: ERROR_IO_PENDING\n");
1639 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1641 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1643 if (dwError
== WAIT_TIMEOUT
)
1645 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1646 if (bResult
== FALSE
)
1648 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1651 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1654 else if (dwError
== WAIT_OBJECT_0
)
1656 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1660 if (bResult
== FALSE
)
1662 dwError
= GetLastError();
1663 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1671 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1677 /* Release the control packet */
1678 HeapFree(GetProcessHeap(),
1682 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1684 dwError
= ReplyPacket
.dwError
;
1687 DPRINT("ScmSendStartCommand() done\n");
1694 ScmWaitForServiceConnect(PSERVICE Service
)
1697 DWORD dwProcessId
= 0;
1698 DWORD dwError
= ERROR_SUCCESS
;
1700 OVERLAPPED Overlapped
= {0};
1702 LPCWSTR lpLogStrings
[3];
1703 WCHAR szBuffer1
[20];
1704 WCHAR szBuffer2
[20];
1707 DPRINT("ScmWaitForServiceConnect()\n");
1709 Overlapped
.hEvent
= (HANDLE
)NULL
;
1711 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1713 if (bResult
== FALSE
)
1715 DPRINT("ConnectNamedPipe() returned FALSE\n");
1717 dwError
= GetLastError();
1718 if (dwError
== ERROR_IO_PENDING
)
1720 DPRINT("dwError: ERROR_IO_PENDING\n");
1722 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1724 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1726 if (dwError
== WAIT_TIMEOUT
)
1728 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1730 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1731 if (bResult
== FALSE
)
1733 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1737 _ultow(PipeTimeout
, szBuffer1
, 10);
1738 lpLogStrings
[0] = Service
->lpDisplayName
;
1739 lpLogStrings
[1] = szBuffer1
;
1741 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1742 EVENTLOG_ERROR_TYPE
,
1746 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1748 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1750 else if (dwError
== WAIT_OBJECT_0
)
1752 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1756 if (bResult
== FALSE
)
1758 dwError
= GetLastError();
1759 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1765 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1767 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1772 DPRINT("Control pipe connected!\n");
1774 Overlapped
.hEvent
= (HANDLE
) NULL
;
1776 /* Read the process id from pipe */
1777 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1778 (LPVOID
)&dwProcessId
,
1782 if (bResult
== FALSE
)
1784 DPRINT("ReadFile() returned FALSE\n");
1786 dwError
= GetLastError();
1787 if (dwError
== ERROR_IO_PENDING
)
1789 DPRINT("dwError: ERROR_IO_PENDING\n");
1791 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1793 if (dwError
== WAIT_TIMEOUT
)
1795 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1797 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1798 if (bResult
== FALSE
)
1800 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1804 _ultow(PipeTimeout
, szBuffer1
, 10);
1805 lpLogStrings
[0] = szBuffer1
;
1807 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1808 EVENTLOG_ERROR_TYPE
,
1812 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1814 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1816 else if (dwError
== WAIT_OBJECT_0
)
1818 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1820 DPRINT("Process Id: %lu\n", dwProcessId
);
1822 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1826 if (bResult
== FALSE
)
1828 dwError
= GetLastError();
1829 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1836 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1841 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1846 if ((ScmIsSecurityService(Service
->lpImage
) == FALSE
)&&
1847 (dwProcessId
!= Service
->lpImage
->dwProcessId
))
1850 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1851 _ultow(dwProcessId
, szBuffer2
, 10);
1853 lpLogStrings
[0] = Service
->lpDisplayName
;
1854 lpLogStrings
[1] = szBuffer1
;
1855 lpLogStrings
[2] = szBuffer2
;
1857 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1858 EVENTLOG_WARNING_TYPE
,
1863 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1866 DPRINT("ScmWaitForServiceConnect() done\n");
1868 return ERROR_SUCCESS
;
1873 ScmStartUserModeService(PSERVICE Service
,
1877 PROCESS_INFORMATION ProcessInformation
;
1878 STARTUPINFOW StartupInfo
;
1879 LPVOID lpEnvironment
;
1881 DWORD dwError
= ERROR_SUCCESS
;
1883 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1885 /* If the image is already running ... */
1886 if (Service
->lpImage
->dwImageRunCount
> 1)
1888 /* ... just send a start command */
1889 return ScmSendStartCommand(Service
, argc
, argv
);
1892 /* Otherwise start its process */
1893 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1894 StartupInfo
.cb
= sizeof(StartupInfo
);
1895 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1897 if (Service
->lpImage
->hToken
)
1899 /* User token: Run the service under the user account */
1901 if (!CreateEnvironmentBlock(&lpEnvironment
, Service
->lpImage
->hToken
, FALSE
))
1903 /* We failed, run the service with the current environment */
1904 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1905 GetLastError(), Service
->lpServiceName
);
1906 lpEnvironment
= NULL
;
1909 /* Impersonate the new user */
1910 Result
= ImpersonateLoggedOnUser(Service
->lpImage
->hToken
);
1913 /* Launch the process in the user's logon session */
1914 Result
= CreateProcessAsUserW(Service
->lpImage
->hToken
,
1916 Service
->lpImage
->pszImagePath
,
1920 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1924 &ProcessInformation
);
1926 dwError
= GetLastError();
1928 /* Revert the impersonation */
1933 dwError
= GetLastError();
1934 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError
);
1939 /* No user token: Run the service under the LocalSystem account */
1941 if (!CreateEnvironmentBlock(&lpEnvironment
, NULL
, TRUE
))
1943 /* We failed, run the service with the current environment */
1944 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1945 GetLastError(), Service
->lpServiceName
);
1946 lpEnvironment
= NULL
;
1949 /* Use the interactive desktop if the service is interactive */
1950 if ((NoInteractiveServices
== 0) &&
1951 (Service
->Status
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
))
1953 StartupInfo
.dwFlags
|= STARTF_INHERITDESKTOP
;
1954 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
1957 if (!ScmIsSecurityService(Service
->lpImage
))
1959 Result
= CreateProcessW(NULL
,
1960 Service
->lpImage
->pszImagePath
,
1964 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1968 &ProcessInformation
);
1970 dwError
= GetLastError();
1975 dwError
= ERROR_SUCCESS
;
1980 DestroyEnvironmentBlock(lpEnvironment
);
1984 DPRINT1("Starting '%S' failed with error %d\n",
1985 Service
->lpServiceName
, dwError
);
1989 DPRINT("Process Id: %lu Handle %p\n",
1990 ProcessInformation
.dwProcessId
,
1991 ProcessInformation
.hProcess
);
1992 DPRINT("Thread Id: %lu Handle %p\n",
1993 ProcessInformation
.dwThreadId
,
1994 ProcessInformation
.hThread
);
1996 /* Get the process handle and ID */
1997 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1998 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
2000 /* Resume the main thread and close its handle */
2001 ResumeThread(ProcessInformation
.hThread
);
2002 CloseHandle(ProcessInformation
.hThread
);
2004 /* Connect control pipe */
2005 dwError
= ScmWaitForServiceConnect(Service
);
2006 if (dwError
!= ERROR_SUCCESS
)
2008 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
2009 Service
->lpImage
->dwProcessId
= 0;
2013 /* Send the start command */
2014 return ScmSendStartCommand(Service
, argc
, argv
);
2019 ScmLoadService(PSERVICE Service
,
2023 PSERVICE_GROUP Group
= Service
->lpGroup
;
2024 DWORD dwError
= ERROR_SUCCESS
;
2025 LPCWSTR lpLogStrings
[2];
2026 WCHAR szLogBuffer
[80];
2028 DPRINT("ScmLoadService() called\n");
2029 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
2031 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
2033 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
2034 return ERROR_SERVICE_ALREADY_RUNNING
;
2037 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
2039 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
2041 /* Start the driver */
2042 dwError
= ScmStartDriver(Service
);
2044 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
2046 /* Start user-mode service */
2047 dwError
= ScmCreateOrReferenceServiceImage(Service
);
2048 if (dwError
== ERROR_SUCCESS
)
2050 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
2051 if (dwError
== ERROR_SUCCESS
)
2053 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
2054 Service
->Status
.dwControlsAccepted
= 0;
2058 Service
->lpImage
->dwImageRunCount
--;
2059 if (Service
->lpImage
->dwImageRunCount
== 0)
2061 ScmRemoveServiceImage(Service
->lpImage
);
2062 Service
->lpImage
= NULL
;
2068 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
2070 if (dwError
== ERROR_SUCCESS
)
2074 Group
->ServicesRunning
= TRUE
;
2077 /* Log a successful service start */
2078 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
2079 lpLogStrings
[0] = Service
->lpDisplayName
;
2080 lpLogStrings
[1] = szLogBuffer
;
2082 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
2083 EVENTLOG_INFORMATION_TYPE
,
2089 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
2091 /* Log a failed service start */
2092 StringCchPrintfW(szLogBuffer
, ARRAYSIZE(szLogBuffer
),
2094 lpLogStrings
[0] = Service
->lpServiceName
;
2095 lpLogStrings
[1] = szLogBuffer
;
2096 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
2097 EVENTLOG_ERROR_TYPE
,
2103 switch (Service
->dwErrorControl
)
2105 case SERVICE_ERROR_SEVERE
:
2106 if (IsLastKnownGood
== FALSE
)
2108 /* FIXME: Boot last known good configuration */
2112 case SERVICE_ERROR_CRITICAL
:
2113 if (IsLastKnownGood
== FALSE
)
2115 /* FIXME: Boot last known good configuration */
2131 ScmStartService(PSERVICE Service
,
2135 DWORD dwError
= ERROR_SUCCESS
;
2136 SC_RPC_LOCK Lock
= NULL
;
2138 DPRINT("ScmStartService() called\n");
2139 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
2141 /* Acquire the service control critical section, to synchronize starts */
2142 EnterCriticalSection(&ControlServiceCriticalSection
);
2145 * Acquire the user service start lock while the service is starting, if
2146 * needed (i.e. if we are not starting it during the initialization phase).
2147 * If we don't success, bail out.
2151 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
2152 if (dwError
!= ERROR_SUCCESS
) goto done
;
2155 /* Really start the service */
2156 dwError
= ScmLoadService(Service
, argc
, argv
);
2158 /* Release the service start lock, if needed, and the critical section */
2159 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
2162 LeaveCriticalSection(&ControlServiceCriticalSection
);
2164 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
2171 ScmAutoStartServices(VOID
)
2174 PLIST_ENTRY GroupEntry
;
2175 PLIST_ENTRY ServiceEntry
;
2176 PSERVICE_GROUP CurrentGroup
;
2177 PSERVICE CurrentService
;
2178 WCHAR szSafeBootServicePath
[MAX_PATH
];
2179 DWORD SafeBootEnabled
;
2185 * This function MUST be called ONLY at initialization time.
2186 * Therefore, no need to acquire the user service start lock.
2188 ASSERT(ScmInitialize
);
2190 /* Retrieve the SafeBoot parameter */
2191 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2192 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
2196 if (dwError
== ERROR_SUCCESS
)
2198 dwKeySize
= sizeof(SafeBootEnabled
);
2199 dwError
= RegQueryValueExW(hKey
,
2203 (LPBYTE
)&SafeBootEnabled
,
2208 /* Default to Normal boot if the value doesn't exist */
2209 if (dwError
!= ERROR_SUCCESS
)
2210 SafeBootEnabled
= 0;
2212 /* Acquire the service control critical section, to synchronize starts */
2213 EnterCriticalSection(&ControlServiceCriticalSection
);
2215 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
2216 ServiceEntry
= ServiceListHead
.Flink
;
2217 while (ServiceEntry
!= &ServiceListHead
)
2219 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2221 /* Build the safe boot path */
2222 StringCchCopyW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2223 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
2225 switch (SafeBootEnabled
)
2227 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
2230 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2235 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2240 if (SafeBootEnabled
!= 0)
2242 /* If key does not exist then do not assume safe mode */
2243 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2244 szSafeBootServicePath
,
2248 if (dwError
== ERROR_SUCCESS
)
2252 /* Finish Safe Boot path off */
2253 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2254 CurrentService
->lpServiceName
);
2256 /* Check that the key is in the Safe Boot path */
2257 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2258 szSafeBootServicePath
,
2262 if (dwError
!= ERROR_SUCCESS
)
2264 /* Mark service as visited so it is not auto-started */
2265 CurrentService
->ServiceVisited
= TRUE
;
2269 /* Must be auto-started in safe mode - mark as unvisited */
2271 CurrentService
->ServiceVisited
= FALSE
;
2276 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2277 CurrentService
->ServiceVisited
= FALSE
;
2281 ServiceEntry
= ServiceEntry
->Flink
;
2284 /* Start all services which are members of an existing group */
2285 GroupEntry
= GroupListHead
.Flink
;
2286 while (GroupEntry
!= &GroupListHead
)
2288 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
2290 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
2292 /* Start all services witch have a valid tag */
2293 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
2295 ServiceEntry
= ServiceListHead
.Flink
;
2296 while (ServiceEntry
!= &ServiceListHead
)
2298 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2300 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2301 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2302 (CurrentService
->ServiceVisited
== FALSE
) &&
2303 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
2305 CurrentService
->ServiceVisited
= TRUE
;
2306 ScmLoadService(CurrentService
, 0, NULL
);
2309 ServiceEntry
= ServiceEntry
->Flink
;
2313 /* Start all services which have an invalid tag or which do not have a tag */
2314 ServiceEntry
= ServiceListHead
.Flink
;
2315 while (ServiceEntry
!= &ServiceListHead
)
2317 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2319 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2320 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2321 (CurrentService
->ServiceVisited
== FALSE
))
2323 CurrentService
->ServiceVisited
= TRUE
;
2324 ScmLoadService(CurrentService
, 0, NULL
);
2327 ServiceEntry
= ServiceEntry
->Flink
;
2330 GroupEntry
= GroupEntry
->Flink
;
2333 /* Start all services which are members of any non-existing group */
2334 ServiceEntry
= ServiceListHead
.Flink
;
2335 while (ServiceEntry
!= &ServiceListHead
)
2337 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2339 if ((CurrentService
->lpGroup
!= NULL
) &&
2340 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2341 (CurrentService
->ServiceVisited
== FALSE
))
2343 CurrentService
->ServiceVisited
= TRUE
;
2344 ScmLoadService(CurrentService
, 0, NULL
);
2347 ServiceEntry
= ServiceEntry
->Flink
;
2350 /* Start all services which are not a member of any group */
2351 ServiceEntry
= ServiceListHead
.Flink
;
2352 while (ServiceEntry
!= &ServiceListHead
)
2354 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2356 if ((CurrentService
->lpGroup
== NULL
) &&
2357 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2358 (CurrentService
->ServiceVisited
== FALSE
))
2360 CurrentService
->ServiceVisited
= TRUE
;
2361 ScmLoadService(CurrentService
, 0, NULL
);
2364 ServiceEntry
= ServiceEntry
->Flink
;
2367 /* Clear 'ServiceVisited' flag again */
2368 ServiceEntry
= ServiceListHead
.Flink
;
2369 while (ServiceEntry
!= &ServiceListHead
)
2371 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2372 CurrentService
->ServiceVisited
= FALSE
;
2373 ServiceEntry
= ServiceEntry
->Flink
;
2376 /* Release the critical section */
2377 LeaveCriticalSection(&ControlServiceCriticalSection
);
2382 ScmAutoShutdownServices(VOID
)
2384 PLIST_ENTRY ServiceEntry
;
2385 PSERVICE CurrentService
;
2387 DPRINT("ScmAutoShutdownServices() called\n");
2389 /* Lock the service database exclusively */
2390 ScmLockDatabaseExclusive();
2392 ServiceEntry
= ServiceListHead
.Flink
;
2393 while (ServiceEntry
!= &ServiceListHead
)
2395 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2397 if ((CurrentService
->Status
.dwControlsAccepted
& SERVICE_ACCEPT_SHUTDOWN
) &&
2398 (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2399 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
))
2401 /* Send the shutdown notification */
2402 DPRINT("Shutdown service: %S\n", CurrentService
->lpServiceName
);
2403 ScmControlService(CurrentService
->lpImage
->hControlPipe
,
2404 CurrentService
->lpServiceName
,
2405 (SERVICE_STATUS_HANDLE
)CurrentService
,
2406 SERVICE_CONTROL_SHUTDOWN
);
2409 ServiceEntry
= ServiceEntry
->Flink
;
2412 /* Unlock the service database */
2413 ScmUnlockDatabase();
2415 DPRINT("ScmAutoShutdownServices() done\n");
2420 ScmLockDatabaseExclusive(VOID
)
2422 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2427 ScmLockDatabaseShared(VOID
)
2429 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2434 ScmUnlockDatabase(VOID
)
2436 RtlReleaseResource(&DatabaseLock
);
2441 ScmInitNamedPipeCriticalSection(VOID
)
2447 InitializeCriticalSection(&ControlServiceCriticalSection
);
2449 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2450 L
"SYSTEM\\CurrentControlSet\\Control",
2454 if (dwError
== ERROR_SUCCESS
)
2456 dwKeySize
= sizeof(PipeTimeout
);
2457 RegQueryValueExW(hKey
,
2458 L
"ServicesPipeTimeout",
2461 (LPBYTE
)&PipeTimeout
,
2469 ScmDeleteNamedPipeCriticalSection(VOID
)
2471 DeleteCriticalSection(&ControlServiceCriticalSection
);