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 *****************************************************************/
44 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
46 WCHAR szControlPipeName
[MAX_PATH
+ 1];
47 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
48 DWORD ServiceCurrent
= 0;
53 /* Get the service number */
54 /* TODO: Create registry entry with correct write access */
55 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
56 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
62 if (dwError
!= ERROR_SUCCESS
)
64 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
68 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
70 dwKeySize
= sizeof(DWORD
);
71 dwError
= RegQueryValueExW(hServiceCurrentKey
,
72 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
74 if (dwError
!= ERROR_SUCCESS
)
76 RegCloseKey(hServiceCurrentKey
);
77 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
84 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
86 RegCloseKey(hServiceCurrentKey
);
88 if (dwError
!= ERROR_SUCCESS
)
90 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
94 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
95 StringCchPrintfW(szControlPipeName
, ARRAYSIZE(szControlPipeName
),
96 L
"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent
);
98 DPRINT("PipeName: %S\n", szControlPipeName
);
100 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
101 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
102 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
108 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
109 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
111 DPRINT1("Failed to create control pipe!\n");
112 return GetLastError();
115 return ERROR_SUCCESS
;
119 static PSERVICE_IMAGE
120 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
122 PLIST_ENTRY ImageEntry
;
123 PSERVICE_IMAGE CurrentImage
;
125 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
127 ImageEntry
= ImageListHead
.Flink
;
128 while (ImageEntry
!= &ImageListHead
)
130 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
133 if (_wcsicmp(CurrentImage
->pszImagePath
, lpImagePath
) == 0)
135 DPRINT("Found image: '%S'\n", CurrentImage
->pszImagePath
);
139 ImageEntry
= ImageEntry
->Flink
;
142 DPRINT("Couldn't find a matching image\n");
150 ScmGetServiceNameFromTag(PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams
, PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS
*OutParams
)
152 PLIST_ENTRY ServiceEntry
;
153 PSERVICE CurrentService
;
154 PSERVICE_IMAGE CurrentImage
;
155 PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutBuffer
= NULL
;
158 /* Lock the database */
159 ScmLockDatabaseExclusive();
161 /* Find the matching service */
162 ServiceEntry
= ServiceListHead
.Flink
;
163 while (ServiceEntry
!= &ServiceListHead
)
165 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
169 /* We must match the tag */
170 if (CurrentService
->dwTag
== InParams
->dwTag
&&
171 CurrentService
->lpImage
!= NULL
)
173 CurrentImage
= CurrentService
->lpImage
;
174 /* And matching the PID */
175 if (CurrentImage
->hProcess
== (HANDLE
)InParams
->dwPid
)
181 ServiceEntry
= ServiceEntry
->Flink
;
185 if (ServiceEntry
== &ServiceListHead
)
187 dwError
= ERROR_RETRY
;
191 /* Allocate the output buffer */
192 OutBuffer
= MIDL_user_allocate(sizeof(TAG_INFO_NAME_FROM_TAG_OUT_PARAMS
));
193 if (OutBuffer
== NULL
)
195 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
199 /* And the buffer for the name */
200 OutBuffer
->pszName
= MIDL_user_allocate(wcslen(CurrentService
->lpServiceName
) * sizeof(WCHAR
) + sizeof(UNICODE_NULL
));
201 if (OutBuffer
->pszName
== NULL
)
203 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
207 /* Fill in output data */
208 wcscpy(OutBuffer
->pszName
, CurrentService
->lpServiceName
);
209 OutBuffer
->TagType
= TagTypeService
;
212 *OutParams
= OutBuffer
;
213 dwError
= ERROR_SUCCESS
;
217 /* Unlock database */
220 /* If failure, free allocated memory */
221 if (dwError
!= ERROR_SUCCESS
)
223 MIDL_user_free(OutBuffer
);
226 /* Return error/success */
233 ScmIsSameServiceAccount(
234 _In_ PCWSTR pszAccountName1
,
235 _In_ PCWSTR pszAccountName2
)
237 if (pszAccountName1
== NULL
&&
238 pszAccountName2
== NULL
)
241 if (pszAccountName1
== NULL
&&
242 pszAccountName2
!= NULL
&&
243 _wcsicmp(pszAccountName2
, L
"LocalSystem") == 0)
246 if (pszAccountName1
!= NULL
&&
247 pszAccountName2
== NULL
&&
248 _wcsicmp(pszAccountName1
, L
"LocalSystem") == 0)
251 if (pszAccountName1
!= NULL
&&
252 pszAccountName2
!= NULL
&&
253 _wcsicmp(pszAccountName1
, pszAccountName2
) == 0)
262 ScmIsLocalSystemAccount(
263 _In_ PCWSTR pszAccountName
)
265 if (pszAccountName
== NULL
||
266 _wcsicmp(pszAccountName
, L
"LocalSystem") == 0)
276 IN PSERVICE pService
,
277 IN PSERVICE_IMAGE pImage
)
279 DWORD dwError
= ERROR_SUCCESS
;
280 PROFILEINFOW ProfileInfo
;
281 PWSTR pszUserName
= NULL
;
282 PWSTR pszDomainName
= NULL
;
283 PWSTR pszPassword
= NULL
;
286 DPRINT("ScmLogonService(%p %p)\n", pService
, pImage
);
287 DPRINT("Service %S\n", pService
->lpServiceName
);
289 if (ScmIsLocalSystemAccount(pImage
->pszAccountName
))
290 return ERROR_SUCCESS
;
292 /* Get the user and domain names */
293 ptr
= wcschr(pImage
->pszAccountName
, L
'\\');
297 pszUserName
= ptr
+ 1;
298 pszDomainName
= pImage
->pszAccountName
;
302 // ERROR_INVALID_SERVICE_ACCOUNT
303 pszUserName
= pImage
->pszAccountName
;
304 pszDomainName
= NULL
;
307 /* Build the service 'password' */
308 pszPassword
= HeapAlloc(GetProcessHeap(),
310 (wcslen(pService
->lpServiceName
) + 5) * sizeof(WCHAR
));
311 if (pszPassword
== NULL
)
313 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
317 wcscpy(pszPassword
, L
"_SC_");
318 wcscat(pszPassword
, pService
->lpServiceName
);
320 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName
, pszUserName
, pszPassword
);
322 /* Do the service logon */
323 if (!LogonUserW(pszUserName
,
326 LOGON32_LOGON_SERVICE
,
327 LOGON32_PROVIDER_DEFAULT
,
330 dwError
= GetLastError();
331 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError
);
333 /* Normalize the returned error */
334 dwError
= ERROR_SERVICE_LOGON_FAILED
;
338 /* Load the user profile; the per-user environment variables are thus correctly initialized */
339 ZeroMemory(&ProfileInfo
, sizeof(ProfileInfo
));
340 ProfileInfo
.dwSize
= sizeof(ProfileInfo
);
341 ProfileInfo
.dwFlags
= PI_NOUI
;
342 ProfileInfo
.lpUserName
= pszUserName
;
343 // ProfileInfo.lpProfilePath = NULL;
344 // ProfileInfo.lpDefaultPath = NULL;
345 // ProfileInfo.lpServerName = NULL;
346 // ProfileInfo.lpPolicyPath = NULL;
347 // ProfileInfo.hProfile = NULL;
349 if (!LoadUserProfileW(pImage
->hToken
, &ProfileInfo
))
351 dwError
= GetLastError();
352 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError
);
356 pImage
->hProfile
= ProfileInfo
.hProfile
;
359 if (pszPassword
!= NULL
)
360 HeapFree(GetProcessHeap(), 0, pszPassword
);
370 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
372 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
373 UNICODE_STRING ImagePath
;
374 UNICODE_STRING ObjectName
;
375 PSERVICE_IMAGE pServiceImage
= NULL
;
377 DWORD dwError
= ERROR_SUCCESS
;
381 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
383 RtlInitUnicodeString(&ImagePath
, NULL
);
384 RtlInitUnicodeString(&ObjectName
, NULL
);
386 /* Get service data */
387 RtlZeroMemory(&QueryTable
,
390 QueryTable
[0].Name
= L
"ImagePath";
391 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
392 QueryTable
[0].EntryContext
= &ImagePath
;
393 QueryTable
[1].Name
= L
"ObjectName";
394 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
395 QueryTable
[1].EntryContext
= &ObjectName
;
397 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
398 pService
->lpServiceName
,
402 if (!NT_SUCCESS(Status
))
404 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
405 return RtlNtStatusToDosError(Status
);
408 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
409 DPRINT("ObjectName: '%wZ'\n", &ObjectName
);
411 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
412 if (pServiceImage
== NULL
)
414 dwRecordSize
= sizeof(SERVICE_IMAGE
) +
415 ImagePath
.Length
+ sizeof(WCHAR
) +
416 ((ObjectName
.Length
!= 0) ? (ObjectName
.Length
+ sizeof(WCHAR
)) : 0);
418 /* Create a new service image */
419 pServiceImage
= HeapAlloc(GetProcessHeap(),
422 if (pServiceImage
== NULL
)
424 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
428 pServiceImage
->dwImageRunCount
= 1;
429 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
430 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
432 pString
= (PWSTR
)((INT_PTR
)pServiceImage
+ sizeof(SERVICE_IMAGE
));
434 /* Set the image path */
435 pServiceImage
->pszImagePath
= pString
;
436 wcscpy(pServiceImage
->pszImagePath
,
439 /* Set the account name */
440 if (ObjectName
.Length
> 0)
442 pString
= pString
+ wcslen(pString
) + 1;
444 pServiceImage
->pszAccountName
= pString
;
445 wcscpy(pServiceImage
->pszAccountName
,
450 dwError
= ScmLogonService(pService
, pServiceImage
);
451 if (dwError
!= ERROR_SUCCESS
)
453 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError
);
455 /* Release the service image */
456 HeapFree(GetProcessHeap(), 0, pServiceImage
);
461 /* Create the control pipe */
462 dwError
= ScmCreateNewControlPipe(pServiceImage
);
463 if (dwError
!= ERROR_SUCCESS
)
465 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError
);
467 /* Unload the user profile */
468 if (pServiceImage
->hProfile
!= NULL
)
469 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
471 /* Close the logon token */
472 if (pServiceImage
->hToken
!= NULL
)
473 CloseHandle(pServiceImage
->hToken
);
475 /* Release the service image */
476 HeapFree(GetProcessHeap(), 0, pServiceImage
);
481 /* FIXME: Add more initialization code here */
484 /* Append service record */
485 InsertTailList(&ImageListHead
,
486 &pServiceImage
->ImageListEntry
);
490 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
492 /* Fail if services in an image use different accounts */
493 if (!ScmIsSameServiceAccount(pServiceImage
->pszAccountName
, ObjectName
.Buffer
))
495 dwError
= ERROR_DIFFERENT_SERVICE_ACCOUNT
;
499 /* Increment the run counter */
500 pServiceImage
->dwImageRunCount
++;
503 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage
->pszImagePath
);
504 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage
->pszAccountName
);
505 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
507 /* Link the service image to the service */
508 pService
->lpImage
= pServiceImage
;
511 RtlFreeUnicodeString(&ObjectName
);
512 RtlFreeUnicodeString(&ImagePath
);
514 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
521 ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage
)
523 DPRINT1("ScmRemoveServiceImage() called\n");
525 /* FIXME: Terminate the process */
527 /* Remove the service image from the list */
528 RemoveEntryList(&pServiceImage
->ImageListEntry
);
530 /* Close the process handle */
531 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
532 CloseHandle(pServiceImage
->hProcess
);
534 /* Close the control pipe */
535 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
536 CloseHandle(pServiceImage
->hControlPipe
);
538 /* Unload the user profile */
539 if (pServiceImage
->hProfile
!= NULL
)
540 UnloadUserProfile(pServiceImage
->hToken
, pServiceImage
->hProfile
);
542 /* Close the logon token */
543 if (pServiceImage
->hToken
!= NULL
)
544 CloseHandle(pServiceImage
->hToken
);
546 /* Release the service image */
547 HeapFree(GetProcessHeap(), 0, pServiceImage
);
552 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
554 PLIST_ENTRY ServiceEntry
;
555 PSERVICE CurrentService
;
557 DPRINT("ScmGetServiceEntryByName() called\n");
559 ServiceEntry
= ServiceListHead
.Flink
;
560 while (ServiceEntry
!= &ServiceListHead
)
562 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
565 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
567 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
568 return CurrentService
;
571 ServiceEntry
= ServiceEntry
->Flink
;
574 DPRINT("Couldn't find a matching service\n");
581 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
583 PLIST_ENTRY ServiceEntry
;
584 PSERVICE CurrentService
;
586 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
588 ServiceEntry
= ServiceListHead
.Flink
;
589 while (ServiceEntry
!= &ServiceListHead
)
591 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
594 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
596 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
597 return CurrentService
;
600 ServiceEntry
= ServiceEntry
->Flink
;
603 DPRINT("Couldn't find a matching service\n");
610 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
612 PLIST_ENTRY ServiceEntry
;
613 PSERVICE CurrentService
;
615 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
617 ServiceEntry
= ServiceListHead
.Flink
;
618 while (ServiceEntry
!= &ServiceListHead
)
620 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
623 if (CurrentService
->dwResumeCount
> dwResumeCount
)
625 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
626 return CurrentService
;
629 ServiceEntry
= ServiceEntry
->Flink
;
632 DPRINT("Couldn't find a matching service\n");
639 ScmGenerateServiceTag(PSERVICE lpServiceRecord
)
641 /* Check for an overflow */
642 if (ServiceTag
== -1)
644 return ERROR_INVALID_DATA
;
647 /* This is only valid for Win32 services */
648 if (!(lpServiceRecord
->Status
.dwServiceType
& SERVICE_WIN32
))
650 return ERROR_INVALID_PARAMETER
;
653 /* Increment the tag counter and set it */
654 ServiceTag
= ServiceTag
% 0xFFFFFFFF + 1;
655 lpServiceRecord
->dwTag
= ServiceTag
;
657 return ERROR_SUCCESS
;
662 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
663 PSERVICE
*lpServiceRecord
,
667 PSERVICE lpService
= NULL
;
669 DPRINT("Service: '%S'\n", lpServiceName
);
671 /* Allocate service entry */
672 lpService
= HeapAlloc(GetProcessHeap(),
674 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
675 if (lpService
== NULL
)
676 return ERROR_NOT_ENOUGH_MEMORY
;
678 *lpServiceRecord
= lpService
;
680 /* Copy service name */
681 wcscpy(lpService
->szServiceName
, lpServiceName
);
682 lpService
->lpServiceName
= lpService
->szServiceName
;
683 lpService
->lpDisplayName
= lpService
->lpServiceName
;
685 /* Set the start type */
686 lpService
->dwStartType
= dwStartType
;
688 /* Set the resume count */
689 lpService
->dwResumeCount
= ResumeCount
++;
691 /* Append service record */
692 InsertTailList(&ServiceListHead
,
693 &lpService
->ServiceListEntry
);
695 /* Initialize the service status */
696 lpService
->Status
.dwServiceType
= dwServiceType
;
697 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
698 lpService
->Status
.dwControlsAccepted
= 0;
699 lpService
->Status
.dwWin32ExitCode
=
700 (dwStartType
== SERVICE_DISABLED
) ? ERROR_SERVICE_DISABLED
: ERROR_SERVICE_NEVER_STARTED
;
701 lpService
->Status
.dwServiceSpecificExitCode
= 0;
702 lpService
->Status
.dwCheckPoint
= 0;
703 lpService
->Status
.dwWaitHint
=
704 (dwServiceType
& SERVICE_DRIVER
) ? 0 : 2000; /* 2 seconds */
706 return ERROR_SUCCESS
;
711 ScmDeleteServiceRecord(PSERVICE lpService
)
713 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
715 /* Delete the display name */
716 if (lpService
->lpDisplayName
!= NULL
&&
717 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
718 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
720 /* Dereference the service image */
721 if (lpService
->lpImage
)
723 lpService
->lpImage
->dwImageRunCount
--;
725 if (lpService
->lpImage
->dwImageRunCount
== 0)
727 ScmRemoveServiceImage(lpService
->lpImage
);
728 lpService
->lpImage
= NULL
;
732 /* Decrement the group reference counter */
733 ScmSetServiceGroup(lpService
, NULL
);
735 /* Release the SecurityDescriptor */
736 if (lpService
->pSecurityDescriptor
!= NULL
)
737 HeapFree(GetProcessHeap(), 0, lpService
->pSecurityDescriptor
);
739 /* Remove the Service from the List */
740 RemoveEntryList(&lpService
->ServiceListEntry
);
742 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
744 /* Delete the service record */
745 HeapFree(GetProcessHeap(), 0, lpService
);
752 CreateServiceListEntry(LPCWSTR lpServiceName
,
755 PSERVICE lpService
= NULL
;
756 LPWSTR lpDisplayName
= NULL
;
757 LPWSTR lpGroup
= NULL
;
762 DWORD dwErrorControl
;
765 DPRINT("Service: '%S'\n", lpServiceName
);
766 if (*lpServiceName
== L
'{')
767 return ERROR_SUCCESS
;
769 dwSize
= sizeof(DWORD
);
770 dwError
= RegQueryValueExW(hServiceKey
,
774 (LPBYTE
)&dwServiceType
,
776 if (dwError
!= ERROR_SUCCESS
)
777 return ERROR_SUCCESS
;
779 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
780 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
781 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
782 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
783 return ERROR_SUCCESS
;
785 DPRINT("Service type: %lx\n", dwServiceType
);
787 dwSize
= sizeof(DWORD
);
788 dwError
= RegQueryValueExW(hServiceKey
,
792 (LPBYTE
)&dwStartType
,
794 if (dwError
!= ERROR_SUCCESS
)
795 return ERROR_SUCCESS
;
797 DPRINT("Start type: %lx\n", dwStartType
);
799 dwSize
= sizeof(DWORD
);
800 dwError
= RegQueryValueExW(hServiceKey
,
804 (LPBYTE
)&dwErrorControl
,
806 if (dwError
!= ERROR_SUCCESS
)
807 return ERROR_SUCCESS
;
809 DPRINT("Error control: %lx\n", dwErrorControl
);
811 dwError
= RegQueryValueExW(hServiceKey
,
817 if (dwError
!= ERROR_SUCCESS
)
820 DPRINT("Tag: %lx\n", dwTagId
);
822 dwError
= ScmReadString(hServiceKey
,
825 if (dwError
!= ERROR_SUCCESS
)
828 DPRINT("Group: %S\n", lpGroup
);
830 dwError
= ScmReadString(hServiceKey
,
833 if (dwError
!= ERROR_SUCCESS
)
834 lpDisplayName
= NULL
;
836 DPRINT("Display name: %S\n", lpDisplayName
);
838 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
842 if (dwError
!= ERROR_SUCCESS
)
845 lpService
->dwErrorControl
= dwErrorControl
;
846 lpService
->dwTag
= dwTagId
;
850 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
851 if (dwError
!= ERROR_SUCCESS
)
855 if (lpDisplayName
!= NULL
)
857 lpService
->lpDisplayName
= lpDisplayName
;
858 lpDisplayName
= NULL
;
861 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
862 if (lpService
->lpGroup
!= NULL
)
864 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
866 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
867 lpService
->dwStartType
,
868 lpService
->Status
.dwServiceType
,
870 lpService
->dwErrorControl
);
872 if (ScmIsDeleteFlagSet(hServiceKey
))
873 lpService
->bDeleted
= TRUE
;
875 ScmGenerateServiceTag(lpService
);
877 if (lpService
->Status
.dwServiceType
& SERVICE_WIN32
)
879 dwError
= ScmReadSecurityDescriptor(hServiceKey
,
880 &lpService
->pSecurityDescriptor
);
881 if (dwError
!= ERROR_SUCCESS
)
884 /* Assing the default security descriptor if the security descriptor cannot be read */
885 if (lpService
->pSecurityDescriptor
== NULL
)
887 DPRINT("No security descriptor found! Assign default security descriptor!\n");
888 dwError
= ScmCreateDefaultServiceSD(&lpService
->pSecurityDescriptor
);
889 if (dwError
!= ERROR_SUCCESS
)
892 dwError
= ScmWriteSecurityDescriptor(hServiceKey
,
893 lpService
->pSecurityDescriptor
);
894 if (dwError
!= ERROR_SUCCESS
)
901 HeapFree(GetProcessHeap(), 0, lpGroup
);
903 if (lpDisplayName
!= NULL
)
904 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
906 if (lpService
!= NULL
)
908 ASSERT(lpService
->lpImage
== NULL
);
916 ScmDeleteMarkedServices(VOID
)
918 PLIST_ENTRY ServiceEntry
;
919 PSERVICE CurrentService
;
923 ServiceEntry
= ServiceListHead
.Flink
;
924 while (ServiceEntry
!= &ServiceListHead
)
926 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
928 ServiceEntry
= ServiceEntry
->Flink
;
930 if (CurrentService
->bDeleted
!= FALSE
)
932 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
933 L
"System\\CurrentControlSet\\Services",
937 if (dwError
== ERROR_SUCCESS
)
939 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
940 RegCloseKey(hServicesKey
);
941 if (dwError
== ERROR_SUCCESS
)
943 RemoveEntryList(&CurrentService
->ServiceListEntry
);
944 HeapFree(GetProcessHeap(), 0, CurrentService
);
948 if (dwError
!= ERROR_SUCCESS
)
949 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
957 ScmGetNoInteractiveServicesValue(VOID
)
963 lError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
964 L
"SYSTEM\\CurrentControlSet\\Control\\Windows",
968 if (lError
== ERROR_SUCCESS
)
970 dwKeySize
= sizeof(NoInteractiveServices
);
971 lError
= RegQueryValueExW(hKey
,
972 L
"NoInteractiveServices",
975 (LPBYTE
)&NoInteractiveServices
,
983 ScmCreateServiceDatabase(VOID
)
985 WCHAR szSubKey
[MAX_PATH
];
989 DWORD dwSubKeyLength
;
990 FILETIME ftLastChanged
;
993 DPRINT("ScmCreateServiceDatabase() called\n");
995 /* Retrieve the NoInteractiveServies value */
996 ScmGetNoInteractiveServicesValue();
998 /* Create the service group list */
999 dwError
= ScmCreateGroupList();
1000 if (dwError
!= ERROR_SUCCESS
)
1003 /* Initialize image and service lists */
1004 InitializeListHead(&ImageListHead
);
1005 InitializeListHead(&ServiceListHead
);
1007 /* Initialize the database lock */
1008 RtlInitializeResource(&DatabaseLock
);
1010 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1011 L
"System\\CurrentControlSet\\Services",
1015 if (dwError
!= ERROR_SUCCESS
)
1021 dwSubKeyLength
= MAX_PATH
;
1022 dwError
= RegEnumKeyExW(hServicesKey
,
1030 if (dwError
== ERROR_SUCCESS
&&
1031 szSubKey
[0] != L
'{')
1033 DPRINT("SubKeyName: '%S'\n", szSubKey
);
1035 dwError
= RegOpenKeyExW(hServicesKey
,
1040 if (dwError
== ERROR_SUCCESS
)
1042 dwError
= CreateServiceListEntry(szSubKey
,
1045 RegCloseKey(hServiceKey
);
1049 if (dwError
!= ERROR_SUCCESS
)
1055 RegCloseKey(hServicesKey
);
1057 /* Wait for the LSA server */
1060 /* Delete services that are marked for delete */
1061 ScmDeleteMarkedServices();
1063 DPRINT("ScmCreateServiceDatabase() done\n");
1065 return ERROR_SUCCESS
;
1070 ScmShutdownServiceDatabase(VOID
)
1072 DPRINT("ScmShutdownServiceDatabase() called\n");
1074 ScmDeleteMarkedServices();
1075 RtlDeleteResource(&DatabaseLock
);
1077 DPRINT("ScmShutdownServiceDatabase() done\n");
1082 ScmCheckDriver(PSERVICE Service
)
1084 OBJECT_ATTRIBUTES ObjectAttributes
;
1085 UNICODE_STRING DirName
;
1088 POBJECT_DIRECTORY_INFORMATION DirInfo
;
1093 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
1095 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
1097 RtlInitUnicodeString(&DirName
, L
"\\Driver");
1099 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
1101 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
1102 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
1105 InitializeObjectAttributes(&ObjectAttributes
,
1111 Status
= NtOpenDirectoryObject(&DirHandle
,
1112 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
1114 if (!NT_SUCCESS(Status
))
1119 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
1120 2 * MAX_PATH
* sizeof(WCHAR
);
1121 DirInfo
= HeapAlloc(GetProcessHeap(),
1128 Status
= NtQueryDirectoryObject(DirHandle
,
1135 if (Status
== STATUS_NO_MORE_ENTRIES
)
1137 /* FIXME: Add current service to 'failed service' list */
1138 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
1142 if (!NT_SUCCESS(Status
))
1145 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
1147 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
1149 DPRINT("Found: '%S' '%wZ'\n",
1150 Service
->lpServiceName
, &DirInfo
->Name
);
1152 /* Mark service as 'running' */
1153 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1154 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1155 Service
->Status
.dwWin32ExitCode
= ERROR_SUCCESS
;
1156 Service
->Status
.dwServiceSpecificExitCode
= 0;
1157 Service
->Status
.dwCheckPoint
= 0;
1158 Service
->Status
.dwWaitHint
= 0;
1160 /* Mark the service group as 'running' */
1161 if (Service
->lpGroup
!= NULL
)
1163 Service
->lpGroup
->ServicesRunning
= TRUE
;
1170 HeapFree(GetProcessHeap(),
1175 return STATUS_SUCCESS
;
1180 ScmGetBootAndSystemDriverState(VOID
)
1182 PLIST_ENTRY ServiceEntry
;
1183 PSERVICE CurrentService
;
1185 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1187 ServiceEntry
= ServiceListHead
.Flink
;
1188 while (ServiceEntry
!= &ServiceListHead
)
1190 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1192 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
1193 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
1196 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
1198 ScmCheckDriver(CurrentService
);
1201 ServiceEntry
= ServiceEntry
->Flink
;
1204 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1209 ScmControlService(HANDLE hControlPipe
,
1211 SERVICE_STATUS_HANDLE hServiceStatus
,
1214 PSCM_CONTROL_PACKET ControlPacket
;
1215 SCM_REPLY_PACKET ReplyPacket
;
1217 DWORD dwWriteCount
= 0;
1218 DWORD dwReadCount
= 0;
1221 DWORD dwError
= ERROR_SUCCESS
;
1223 OVERLAPPED Overlapped
= {0};
1225 DPRINT("ScmControlService() called\n");
1227 /* Acquire the service control critical section, to synchronize requests */
1228 EnterCriticalSection(&ControlServiceCriticalSection
);
1230 /* Calculate the total length of the start command line */
1231 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1232 PacketSize
+= (DWORD
)((wcslen(pServiceName
) + 1) * sizeof(WCHAR
));
1234 ControlPacket
= HeapAlloc(GetProcessHeap(),
1237 if (ControlPacket
== NULL
)
1239 LeaveCriticalSection(&ControlServiceCriticalSection
);
1240 return ERROR_NOT_ENOUGH_MEMORY
;
1243 ControlPacket
->dwSize
= PacketSize
;
1244 ControlPacket
->dwControl
= dwControl
;
1245 ControlPacket
->hServiceStatus
= hServiceStatus
;
1247 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1249 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1250 wcscpy(Ptr
, pServiceName
);
1252 ControlPacket
->dwArgumentsCount
= 0;
1253 ControlPacket
->dwArgumentsOffset
= 0;
1255 bResult
= WriteFile(hControlPipe
,
1260 if (bResult
== FALSE
)
1262 DPRINT("WriteFile() returned FALSE\n");
1264 dwError
= GetLastError();
1265 if (dwError
== ERROR_IO_PENDING
)
1267 DPRINT("dwError: ERROR_IO_PENDING\n");
1269 dwError
= WaitForSingleObject(hControlPipe
,
1271 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1273 if (dwError
== WAIT_TIMEOUT
)
1275 bResult
= CancelIo(hControlPipe
);
1276 if (bResult
== FALSE
)
1278 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1281 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1284 else if (dwError
== WAIT_OBJECT_0
)
1286 bResult
= GetOverlappedResult(hControlPipe
,
1290 if (bResult
== FALSE
)
1292 dwError
= GetLastError();
1293 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1301 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1306 /* Read the reply */
1307 Overlapped
.hEvent
= (HANDLE
) NULL
;
1309 bResult
= ReadFile(hControlPipe
,
1311 sizeof(SCM_REPLY_PACKET
),
1314 if (bResult
== FALSE
)
1316 DPRINT("ReadFile() returned FALSE\n");
1318 dwError
= GetLastError();
1319 if (dwError
== ERROR_IO_PENDING
)
1321 DPRINT("dwError: ERROR_IO_PENDING\n");
1323 dwError
= WaitForSingleObject(hControlPipe
,
1325 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1327 if (dwError
== WAIT_TIMEOUT
)
1329 bResult
= CancelIo(hControlPipe
);
1330 if (bResult
== FALSE
)
1332 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1335 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1338 else if (dwError
== WAIT_OBJECT_0
)
1340 bResult
= GetOverlappedResult(hControlPipe
,
1344 if (bResult
== FALSE
)
1346 dwError
= GetLastError();
1347 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1355 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1361 /* Release the control packet */
1362 HeapFree(GetProcessHeap(),
1366 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1368 dwError
= ReplyPacket
.dwError
;
1371 LeaveCriticalSection(&ControlServiceCriticalSection
);
1373 DPRINT("ScmControlService() done\n");
1380 ScmSendStartCommand(PSERVICE Service
,
1384 DWORD dwError
= ERROR_SUCCESS
;
1385 PSCM_CONTROL_PACKET ControlPacket
;
1386 SCM_REPLY_PACKET ReplyPacket
;
1393 DWORD dwWriteCount
= 0;
1394 DWORD dwReadCount
= 0;
1395 OVERLAPPED Overlapped
= {0};
1397 DPRINT("ScmSendStartCommand() called\n");
1399 /* Calculate the total length of the start command line */
1400 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1401 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1404 * Calculate the required packet size for the start argument vector 'argv',
1405 * composed of the list of pointer offsets, followed by UNICODE strings.
1406 * The strings are stored continuously after the vector of offsets, with
1407 * the offsets being relative to the beginning of the vector, as in the
1408 * following layout (with N == argc):
1409 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1411 if (argc
> 0 && argv
!= NULL
)
1413 PacketSize
= ALIGN_UP(PacketSize
, PWSTR
);
1414 PacketSize
+= (argc
* sizeof(PWSTR
));
1416 DPRINT("Argc: %lu\n", argc
);
1417 for (i
= 0; i
< argc
; i
++)
1419 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1420 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
));
1424 /* Allocate a control packet */
1425 ControlPacket
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, PacketSize
);
1426 if (ControlPacket
== NULL
)
1427 return ERROR_NOT_ENOUGH_MEMORY
;
1429 ControlPacket
->dwSize
= PacketSize
;
1430 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1431 ? SERVICE_CONTROL_START_OWN
1432 : SERVICE_CONTROL_START_SHARE
;
1433 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1434 ControlPacket
->dwServiceTag
= Service
->dwTag
;
1436 /* Copy the start command line */
1437 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1438 Ptr
= (PWSTR
)((ULONG_PTR
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1439 wcscpy(Ptr
, Service
->lpServiceName
);
1441 ControlPacket
->dwArgumentsCount
= 0;
1442 ControlPacket
->dwArgumentsOffset
= 0;
1444 /* Copy the argument vector */
1445 if (argc
> 0 && argv
!= NULL
)
1447 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1448 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1449 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1451 ControlPacket
->dwArgumentsCount
= argc
;
1452 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1454 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1455 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1457 for (i
= 0; i
< argc
; i
++)
1459 wcscpy(pArgPtr
, argv
[i
]);
1460 pOffPtr
[i
] = (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1461 DPRINT("offset[%lu]: %p\n", i
, pOffPtr
[i
]);
1462 pArgPtr
+= wcslen(argv
[i
]) + 1;
1466 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1471 if (bResult
== FALSE
)
1473 DPRINT("WriteFile() returned FALSE\n");
1475 dwError
= GetLastError();
1476 if (dwError
== ERROR_IO_PENDING
)
1478 DPRINT("dwError: ERROR_IO_PENDING\n");
1480 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1482 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1484 if (dwError
== WAIT_TIMEOUT
)
1486 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1487 if (bResult
== FALSE
)
1489 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1492 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1495 else if (dwError
== WAIT_OBJECT_0
)
1497 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1501 if (bResult
== FALSE
)
1503 dwError
= GetLastError();
1504 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1512 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1517 /* Read the reply */
1518 Overlapped
.hEvent
= (HANDLE
) NULL
;
1520 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1522 sizeof(SCM_REPLY_PACKET
),
1525 if (bResult
== FALSE
)
1527 DPRINT("ReadFile() returned FALSE\n");
1529 dwError
= GetLastError();
1530 if (dwError
== ERROR_IO_PENDING
)
1532 DPRINT("dwError: ERROR_IO_PENDING\n");
1534 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1536 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1538 if (dwError
== WAIT_TIMEOUT
)
1540 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1541 if (bResult
== FALSE
)
1543 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1546 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1549 else if (dwError
== WAIT_OBJECT_0
)
1551 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1555 if (bResult
== FALSE
)
1557 dwError
= GetLastError();
1558 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1566 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1572 /* Release the control packet */
1573 HeapFree(GetProcessHeap(),
1577 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1579 dwError
= ReplyPacket
.dwError
;
1582 DPRINT("ScmSendStartCommand() done\n");
1589 ScmWaitForServiceConnect(PSERVICE Service
)
1592 DWORD dwProcessId
= 0;
1593 DWORD dwError
= ERROR_SUCCESS
;
1595 OVERLAPPED Overlapped
= {0};
1597 LPCWSTR lpLogStrings
[3];
1598 WCHAR szBuffer1
[20];
1599 WCHAR szBuffer2
[20];
1602 DPRINT("ScmWaitForServiceConnect()\n");
1604 Overlapped
.hEvent
= (HANDLE
)NULL
;
1606 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1608 if (bResult
== FALSE
)
1610 DPRINT("ConnectNamedPipe() returned FALSE\n");
1612 dwError
= GetLastError();
1613 if (dwError
== ERROR_IO_PENDING
)
1615 DPRINT("dwError: ERROR_IO_PENDING\n");
1617 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1619 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1621 if (dwError
== WAIT_TIMEOUT
)
1623 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1625 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1626 if (bResult
== FALSE
)
1628 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1632 _ultow(PipeTimeout
, szBuffer1
, 10);
1633 lpLogStrings
[0] = Service
->lpDisplayName
;
1634 lpLogStrings
[1] = szBuffer1
;
1636 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1637 EVENTLOG_ERROR_TYPE
,
1641 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1643 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1645 else if (dwError
== WAIT_OBJECT_0
)
1647 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1651 if (bResult
== FALSE
)
1653 dwError
= GetLastError();
1654 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1660 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1662 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1667 DPRINT("Control pipe connected!\n");
1669 Overlapped
.hEvent
= (HANDLE
) NULL
;
1671 /* Read the process id from pipe */
1672 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1673 (LPVOID
)&dwProcessId
,
1677 if (bResult
== FALSE
)
1679 DPRINT("ReadFile() returned FALSE\n");
1681 dwError
= GetLastError();
1682 if (dwError
== ERROR_IO_PENDING
)
1684 DPRINT("dwError: ERROR_IO_PENDING\n");
1686 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1688 if (dwError
== WAIT_TIMEOUT
)
1690 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1692 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1693 if (bResult
== FALSE
)
1695 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1699 _ultow(PipeTimeout
, szBuffer1
, 10);
1700 lpLogStrings
[0] = szBuffer1
;
1702 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1703 EVENTLOG_ERROR_TYPE
,
1707 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1709 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1711 else if (dwError
== WAIT_OBJECT_0
)
1713 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1715 DPRINT("Process Id: %lu\n", dwProcessId
);
1717 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1721 if (bResult
== FALSE
)
1723 dwError
= GetLastError();
1724 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1731 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1736 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1741 if (dwProcessId
!= Service
->lpImage
->dwProcessId
)
1744 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1745 _ultow(dwProcessId
, szBuffer2
, 10);
1747 lpLogStrings
[0] = Service
->lpDisplayName
;
1748 lpLogStrings
[1] = szBuffer1
;
1749 lpLogStrings
[2] = szBuffer2
;
1751 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1752 EVENTLOG_WARNING_TYPE
,
1757 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1760 DPRINT("ScmWaitForServiceConnect() done\n");
1762 return ERROR_SUCCESS
;
1767 ScmStartUserModeService(PSERVICE Service
,
1771 PROCESS_INFORMATION ProcessInformation
;
1772 STARTUPINFOW StartupInfo
;
1773 LPVOID lpEnvironment
;
1775 DWORD dwError
= ERROR_SUCCESS
;
1777 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1779 /* If the image is already running ... */
1780 if (Service
->lpImage
->dwImageRunCount
> 1)
1782 /* ... just send a start command */
1783 return ScmSendStartCommand(Service
, argc
, argv
);
1786 /* Otherwise start its process */
1787 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1788 StartupInfo
.cb
= sizeof(StartupInfo
);
1789 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1791 if (Service
->lpImage
->hToken
)
1793 /* User token: Run the service under the user account */
1795 if (!CreateEnvironmentBlock(&lpEnvironment
, Service
->lpImage
->hToken
, FALSE
))
1797 /* We failed, run the service with the current environment */
1798 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1799 GetLastError(), Service
->lpServiceName
);
1800 lpEnvironment
= NULL
;
1803 /* Impersonate the new user */
1804 Result
= ImpersonateLoggedOnUser(Service
->lpImage
->hToken
);
1807 /* Launch the process in the user's logon session */
1808 Result
= CreateProcessAsUserW(Service
->lpImage
->hToken
,
1810 Service
->lpImage
->pszImagePath
,
1814 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1818 &ProcessInformation
);
1820 dwError
= GetLastError();
1822 /* Revert the impersonation */
1827 dwError
= GetLastError();
1828 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError
);
1833 /* No user token: Run the service under the LocalSystem account */
1835 if (!CreateEnvironmentBlock(&lpEnvironment
, NULL
, TRUE
))
1837 /* We failed, run the service with the current environment */
1838 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1839 GetLastError(), Service
->lpServiceName
);
1840 lpEnvironment
= NULL
;
1843 /* Use the interactive desktop if the service is interactive */
1844 if ((NoInteractiveServices
== 0) &&
1845 (Service
->Status
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
))
1847 StartupInfo
.dwFlags
|= STARTF_INHERITDESKTOP
;
1848 StartupInfo
.lpDesktop
= L
"WinSta0\\Default";
1851 Result
= CreateProcessW(NULL
,
1852 Service
->lpImage
->pszImagePath
,
1856 CREATE_UNICODE_ENVIRONMENT
| DETACHED_PROCESS
| CREATE_SUSPENDED
,
1860 &ProcessInformation
);
1862 dwError
= GetLastError();
1866 DestroyEnvironmentBlock(lpEnvironment
);
1870 DPRINT1("Starting '%S' failed with error %d\n",
1871 Service
->lpServiceName
, dwError
);
1875 DPRINT("Process Id: %lu Handle %p\n",
1876 ProcessInformation
.dwProcessId
,
1877 ProcessInformation
.hProcess
);
1878 DPRINT("Thread Id: %lu Handle %p\n",
1879 ProcessInformation
.dwThreadId
,
1880 ProcessInformation
.hThread
);
1882 /* Get the process handle and ID */
1883 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1884 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1886 /* Resume the main thread and close its handle */
1887 ResumeThread(ProcessInformation
.hThread
);
1888 CloseHandle(ProcessInformation
.hThread
);
1890 /* Connect control pipe */
1891 dwError
= ScmWaitForServiceConnect(Service
);
1892 if (dwError
!= ERROR_SUCCESS
)
1894 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1895 Service
->lpImage
->dwProcessId
= 0;
1899 /* Send the start command */
1900 return ScmSendStartCommand(Service
, argc
, argv
);
1905 ScmLoadService(PSERVICE Service
,
1909 PSERVICE_GROUP Group
= Service
->lpGroup
;
1910 DWORD dwError
= ERROR_SUCCESS
;
1911 LPCWSTR lpLogStrings
[2];
1912 WCHAR szLogBuffer
[80];
1914 DPRINT("ScmLoadService() called\n");
1915 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1917 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1919 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1920 return ERROR_SERVICE_ALREADY_RUNNING
;
1923 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1925 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1927 /* Start the driver */
1928 dwError
= ScmStartDriver(Service
);
1930 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1932 /* Start user-mode service */
1933 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1934 if (dwError
== ERROR_SUCCESS
)
1936 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1937 if (dwError
== ERROR_SUCCESS
)
1939 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1940 Service
->Status
.dwControlsAccepted
= 0;
1944 Service
->lpImage
->dwImageRunCount
--;
1945 if (Service
->lpImage
->dwImageRunCount
== 0)
1947 ScmRemoveServiceImage(Service
->lpImage
);
1948 Service
->lpImage
= NULL
;
1954 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
1956 if (dwError
== ERROR_SUCCESS
)
1960 Group
->ServicesRunning
= TRUE
;
1963 /* Log a successful service start */
1964 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
1965 lpLogStrings
[0] = Service
->lpDisplayName
;
1966 lpLogStrings
[1] = szLogBuffer
;
1968 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1969 EVENTLOG_INFORMATION_TYPE
,
1975 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1977 /* Log a failed service start */
1978 StringCchPrintfW(szLogBuffer
, ARRAYSIZE(szLogBuffer
),
1980 lpLogStrings
[0] = Service
->lpServiceName
;
1981 lpLogStrings
[1] = szLogBuffer
;
1982 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
1983 EVENTLOG_ERROR_TYPE
,
1989 switch (Service
->dwErrorControl
)
1991 case SERVICE_ERROR_SEVERE
:
1992 if (IsLastKnownGood
== FALSE
)
1994 /* FIXME: Boot last known good configuration */
1998 case SERVICE_ERROR_CRITICAL
:
1999 if (IsLastKnownGood
== FALSE
)
2001 /* FIXME: Boot last known good configuration */
2017 ScmStartService(PSERVICE Service
,
2021 DWORD dwError
= ERROR_SUCCESS
;
2022 SC_RPC_LOCK Lock
= NULL
;
2024 DPRINT("ScmStartService() called\n");
2025 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
2027 /* Acquire the service control critical section, to synchronize starts */
2028 EnterCriticalSection(&ControlServiceCriticalSection
);
2031 * Acquire the user service start lock while the service is starting, if
2032 * needed (i.e. if we are not starting it during the initialization phase).
2033 * If we don't success, bail out.
2037 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
2038 if (dwError
!= ERROR_SUCCESS
) goto done
;
2041 /* Really start the service */
2042 dwError
= ScmLoadService(Service
, argc
, argv
);
2044 /* Release the service start lock, if needed, and the critical section */
2045 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
2048 LeaveCriticalSection(&ControlServiceCriticalSection
);
2050 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
2057 ScmAutoStartServices(VOID
)
2060 PLIST_ENTRY GroupEntry
;
2061 PLIST_ENTRY ServiceEntry
;
2062 PSERVICE_GROUP CurrentGroup
;
2063 PSERVICE CurrentService
;
2064 WCHAR szSafeBootServicePath
[MAX_PATH
];
2065 DWORD SafeBootEnabled
;
2071 * This function MUST be called ONLY at initialization time.
2072 * Therefore, no need to acquire the user service start lock.
2074 ASSERT(ScmInitialize
);
2076 /* Retrieve the SafeBoot parameter */
2077 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2078 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
2082 if (dwError
== ERROR_SUCCESS
)
2084 dwKeySize
= sizeof(SafeBootEnabled
);
2085 dwError
= RegQueryValueExW(hKey
,
2089 (LPBYTE
)&SafeBootEnabled
,
2094 /* Default to Normal boot if the value doesn't exist */
2095 if (dwError
!= ERROR_SUCCESS
)
2096 SafeBootEnabled
= 0;
2098 /* Acquire the service control critical section, to synchronize starts */
2099 EnterCriticalSection(&ControlServiceCriticalSection
);
2101 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
2102 ServiceEntry
= ServiceListHead
.Flink
;
2103 while (ServiceEntry
!= &ServiceListHead
)
2105 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2107 /* Build the safe boot path */
2108 StringCchCopyW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2109 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
2111 switch (SafeBootEnabled
)
2113 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
2116 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2121 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2126 if (SafeBootEnabled
!= 0)
2128 /* If key does not exist then do not assume safe mode */
2129 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2130 szSafeBootServicePath
,
2134 if (dwError
== ERROR_SUCCESS
)
2138 /* Finish Safe Boot path off */
2139 StringCchCatW(szSafeBootServicePath
, ARRAYSIZE(szSafeBootServicePath
),
2140 CurrentService
->lpServiceName
);
2142 /* Check that the key is in the Safe Boot path */
2143 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2144 szSafeBootServicePath
,
2148 if (dwError
!= ERROR_SUCCESS
)
2150 /* Mark service as visited so it is not auto-started */
2151 CurrentService
->ServiceVisited
= TRUE
;
2155 /* Must be auto-started in safe mode - mark as unvisited */
2157 CurrentService
->ServiceVisited
= FALSE
;
2162 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2163 CurrentService
->ServiceVisited
= FALSE
;
2167 ServiceEntry
= ServiceEntry
->Flink
;
2170 /* Start all services which are members of an existing group */
2171 GroupEntry
= GroupListHead
.Flink
;
2172 while (GroupEntry
!= &GroupListHead
)
2174 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
2176 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
2178 /* Start all services witch have a valid tag */
2179 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
2181 ServiceEntry
= ServiceListHead
.Flink
;
2182 while (ServiceEntry
!= &ServiceListHead
)
2184 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2186 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2187 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2188 (CurrentService
->ServiceVisited
== FALSE
) &&
2189 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
2191 CurrentService
->ServiceVisited
= TRUE
;
2192 ScmLoadService(CurrentService
, 0, NULL
);
2195 ServiceEntry
= ServiceEntry
->Flink
;
2199 /* Start all services which have an invalid tag or which do not have a tag */
2200 ServiceEntry
= ServiceListHead
.Flink
;
2201 while (ServiceEntry
!= &ServiceListHead
)
2203 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2205 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
2206 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2207 (CurrentService
->ServiceVisited
== FALSE
))
2209 CurrentService
->ServiceVisited
= TRUE
;
2210 ScmLoadService(CurrentService
, 0, NULL
);
2213 ServiceEntry
= ServiceEntry
->Flink
;
2216 GroupEntry
= GroupEntry
->Flink
;
2219 /* Start all services which are members of any non-existing group */
2220 ServiceEntry
= ServiceListHead
.Flink
;
2221 while (ServiceEntry
!= &ServiceListHead
)
2223 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2225 if ((CurrentService
->lpGroup
!= NULL
) &&
2226 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2227 (CurrentService
->ServiceVisited
== FALSE
))
2229 CurrentService
->ServiceVisited
= TRUE
;
2230 ScmLoadService(CurrentService
, 0, NULL
);
2233 ServiceEntry
= ServiceEntry
->Flink
;
2236 /* Start all services which are not a member of any group */
2237 ServiceEntry
= ServiceListHead
.Flink
;
2238 while (ServiceEntry
!= &ServiceListHead
)
2240 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2242 if ((CurrentService
->lpGroup
== NULL
) &&
2243 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
2244 (CurrentService
->ServiceVisited
== FALSE
))
2246 CurrentService
->ServiceVisited
= TRUE
;
2247 ScmLoadService(CurrentService
, 0, NULL
);
2250 ServiceEntry
= ServiceEntry
->Flink
;
2253 /* Clear 'ServiceVisited' flag again */
2254 ServiceEntry
= ServiceListHead
.Flink
;
2255 while (ServiceEntry
!= &ServiceListHead
)
2257 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2258 CurrentService
->ServiceVisited
= FALSE
;
2259 ServiceEntry
= ServiceEntry
->Flink
;
2262 /* Release the critical section */
2263 LeaveCriticalSection(&ControlServiceCriticalSection
);
2268 ScmAutoShutdownServices(VOID
)
2270 PLIST_ENTRY ServiceEntry
;
2271 PSERVICE CurrentService
;
2273 DPRINT("ScmAutoShutdownServices() called\n");
2275 /* Lock the service database exclusively */
2276 ScmLockDatabaseExclusive();
2278 ServiceEntry
= ServiceListHead
.Flink
;
2279 while (ServiceEntry
!= &ServiceListHead
)
2281 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2283 if ((CurrentService
->Status
.dwControlsAccepted
& SERVICE_ACCEPT_SHUTDOWN
) &&
2284 (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2285 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
))
2287 /* Send the shutdown notification */
2288 DPRINT("Shutdown service: %S\n", CurrentService
->lpServiceName
);
2289 ScmControlService(CurrentService
->lpImage
->hControlPipe
,
2290 CurrentService
->lpServiceName
,
2291 (SERVICE_STATUS_HANDLE
)CurrentService
,
2292 SERVICE_CONTROL_SHUTDOWN
);
2295 ServiceEntry
= ServiceEntry
->Flink
;
2298 /* Unlock the service database */
2299 ScmUnlockDatabase();
2301 DPRINT("ScmAutoShutdownServices() done\n");
2306 ScmLockDatabaseExclusive(VOID
)
2308 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2313 ScmLockDatabaseShared(VOID
)
2315 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2320 ScmUnlockDatabase(VOID
)
2322 RtlReleaseResource(&DatabaseLock
);
2327 ScmInitNamedPipeCriticalSection(VOID
)
2333 InitializeCriticalSection(&ControlServiceCriticalSection
);
2335 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2336 L
"SYSTEM\\CurrentControlSet\\Control",
2340 if (dwError
== ERROR_SUCCESS
)
2342 dwKeySize
= sizeof(PipeTimeout
);
2343 RegQueryValueExW(hKey
,
2344 L
"ServicesPipeTimeout",
2347 (LPBYTE
)&PipeTimeout
,
2355 ScmDeleteNamedPipeCriticalSection(VOID
)
2357 DeleteCriticalSection(&ControlServiceCriticalSection
);