[SERVICES] Do not try to start lsass.exe as a service.
[reactos.git] / base / system / services / database.c
1 /*
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>
10 *
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include "services.h"
16
17 #include <userenv.h>
18 #include <strsafe.h>
19
20 #include <reactos/undocuser.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25
26 /* GLOBALS *******************************************************************/
27
28 LIST_ENTRY ImageListHead;
29 LIST_ENTRY ServiceListHead;
30
31 static RTL_RESOURCE DatabaseLock;
32 static DWORD ResumeCount = 1;
33 static DWORD NoInteractiveServices = 0;
34 static DWORD ServiceTag = 0;
35
36 /* The critical section synchronizes service control requests */
37 static CRITICAL_SECTION ControlServiceCriticalSection;
38 static DWORD PipeTimeout = 30000; /* 30 Seconds */
39
40
41 /* FUNCTIONS *****************************************************************/
42
43 static DWORD
44 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage)
45 {
46 WCHAR szControlPipeName[MAX_PATH + 1];
47 HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE;
48 DWORD ServiceCurrent = 0;
49 DWORD KeyDisposition;
50 DWORD dwKeySize;
51 DWORD dwError;
52
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,
57 REG_OPTION_VOLATILE,
58 KEY_WRITE | KEY_READ,
59 NULL,
60 &hServiceCurrentKey,
61 &KeyDisposition);
62 if (dwError != ERROR_SUCCESS)
63 {
64 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError);
65 return dwError;
66 }
67
68 if (KeyDisposition == REG_OPENED_EXISTING_KEY)
69 {
70 dwKeySize = sizeof(DWORD);
71 dwError = RegQueryValueExW(hServiceCurrentKey,
72 L"", 0, NULL, (BYTE*)&ServiceCurrent, &dwKeySize);
73
74 if (dwError != ERROR_SUCCESS)
75 {
76 RegCloseKey(hServiceCurrentKey);
77 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError);
78 return dwError;
79 }
80
81 ServiceCurrent++;
82 }
83
84 dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent));
85
86 RegCloseKey(hServiceCurrentKey);
87
88 if (dwError != ERROR_SUCCESS)
89 {
90 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError);
91 return dwError;
92 }
93
94 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
95 StringCchPrintfW(szControlPipeName, ARRAYSIZE(szControlPipeName),
96 L"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent);
97
98 DPRINT("PipeName: %S\n", szControlPipeName);
99
100 pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName,
101 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
102 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
103 100,
104 8000,
105 4,
106 PipeTimeout,
107 NULL);
108 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName);
109 if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE)
110 {
111 DPRINT1("Failed to create control pipe!\n");
112 return GetLastError();
113 }
114
115 return ERROR_SUCCESS;
116 }
117
118
119 static PSERVICE_IMAGE
120 ScmGetServiceImageByImagePath(LPWSTR lpImagePath)
121 {
122 PLIST_ENTRY ImageEntry;
123 PSERVICE_IMAGE CurrentImage;
124
125 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath);
126
127 ImageEntry = ImageListHead.Flink;
128 while (ImageEntry != &ImageListHead)
129 {
130 CurrentImage = CONTAINING_RECORD(ImageEntry,
131 SERVICE_IMAGE,
132 ImageListEntry);
133 if (_wcsicmp(CurrentImage->pszImagePath, lpImagePath) == 0)
134 {
135 DPRINT("Found image: '%S'\n", CurrentImage->pszImagePath);
136 return CurrentImage;
137 }
138
139 ImageEntry = ImageEntry->Flink;
140 }
141
142 DPRINT("Couldn't find a matching image\n");
143
144 return NULL;
145
146 }
147
148
149 DWORD
150 ScmGetServiceNameFromTag(IN PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams,
151 OUT PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS *OutParams)
152 {
153 PLIST_ENTRY ServiceEntry;
154 PSERVICE CurrentService;
155 PSERVICE_IMAGE CurrentImage;
156 PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutBuffer = NULL;
157 DWORD dwError;
158
159 /* Lock the database */
160 ScmLockDatabaseExclusive();
161
162 /* Find the matching service */
163 ServiceEntry = ServiceListHead.Flink;
164 while (ServiceEntry != &ServiceListHead)
165 {
166 CurrentService = CONTAINING_RECORD(ServiceEntry,
167 SERVICE,
168 ServiceListEntry);
169
170 /* We must match the tag */
171 if (CurrentService->dwTag == InParams->dwTag &&
172 CurrentService->lpImage != NULL)
173 {
174 CurrentImage = CurrentService->lpImage;
175 /* And matching the PID */
176 if (CurrentImage->dwProcessId == InParams->dwPid)
177 {
178 break;
179 }
180 }
181
182 ServiceEntry = ServiceEntry->Flink;
183 }
184
185 /* No match! */
186 if (ServiceEntry == &ServiceListHead)
187 {
188 dwError = ERROR_RETRY;
189 goto Cleanup;
190 }
191
192 /* Allocate the output buffer */
193 OutBuffer = MIDL_user_allocate(sizeof(TAG_INFO_NAME_FROM_TAG_OUT_PARAMS));
194 if (OutBuffer == NULL)
195 {
196 dwError = ERROR_NOT_ENOUGH_MEMORY;
197 goto Cleanup;
198 }
199
200 /* And the buffer for the name */
201 OutBuffer->pszName = MIDL_user_allocate(wcslen(CurrentService->lpServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL));
202 if (OutBuffer->pszName == NULL)
203 {
204 dwError = ERROR_NOT_ENOUGH_MEMORY;
205 goto Cleanup;
206 }
207
208 /* Fill in output data */
209 wcscpy(OutBuffer->pszName, CurrentService->lpServiceName);
210 OutBuffer->TagType = TagTypeService;
211
212 /* And return */
213 *OutParams = OutBuffer;
214 dwError = ERROR_SUCCESS;
215
216 Cleanup:
217
218 /* Unlock database */
219 ScmUnlockDatabase();
220
221 /* If failure, free allocated memory */
222 if (dwError != ERROR_SUCCESS)
223 {
224 if (OutBuffer != NULL)
225 {
226 MIDL_user_free(OutBuffer);
227 }
228 }
229
230 /* Return error/success */
231 return dwError;
232 }
233
234
235 static
236 BOOL
237 ScmIsSameServiceAccount(
238 _In_ PCWSTR pszAccountName1,
239 _In_ PCWSTR pszAccountName2)
240 {
241 if (pszAccountName1 == NULL &&
242 pszAccountName2 == NULL)
243 return TRUE;
244
245 if (pszAccountName1 == NULL &&
246 pszAccountName2 != NULL &&
247 _wcsicmp(pszAccountName2, L"LocalSystem") == 0)
248 return TRUE;
249
250 if (pszAccountName1 != NULL &&
251 pszAccountName2 == NULL &&
252 _wcsicmp(pszAccountName1, L"LocalSystem") == 0)
253 return TRUE;
254
255 if (pszAccountName1 != NULL &&
256 pszAccountName2 != NULL &&
257 _wcsicmp(pszAccountName1, pszAccountName2) == 0)
258 return TRUE;
259
260 return FALSE;
261 }
262
263
264 static
265 BOOL
266 ScmIsLocalSystemAccount(
267 _In_ PCWSTR pszAccountName)
268 {
269 if (pszAccountName == NULL ||
270 _wcsicmp(pszAccountName, L"LocalSystem") == 0)
271 return TRUE;
272
273 return FALSE;
274 }
275
276
277 static
278 DWORD
279 ScmLogonService(
280 IN PSERVICE pService,
281 IN PSERVICE_IMAGE pImage)
282 {
283 DWORD dwError = ERROR_SUCCESS;
284 PROFILEINFOW ProfileInfo;
285 PWSTR pszUserName = NULL;
286 PWSTR pszDomainName = NULL;
287 PWSTR pszPassword = NULL;
288 PWSTR ptr;
289
290 DPRINT("ScmLogonService(%p %p)\n", pService, pImage);
291 DPRINT("Service %S\n", pService->lpServiceName);
292
293 if (ScmIsLocalSystemAccount(pImage->pszAccountName))
294 return ERROR_SUCCESS;
295
296 /* Get the user and domain names */
297 ptr = wcschr(pImage->pszAccountName, L'\\');
298 if (ptr != NULL)
299 {
300 *ptr = L'\0';
301 pszUserName = ptr + 1;
302 pszDomainName = pImage->pszAccountName;
303 }
304 else
305 {
306 // ERROR_INVALID_SERVICE_ACCOUNT
307 pszUserName = pImage->pszAccountName;
308 pszDomainName = NULL;
309 }
310
311 /* Build the service 'password' */
312 pszPassword = HeapAlloc(GetProcessHeap(),
313 HEAP_ZERO_MEMORY,
314 (wcslen(pService->lpServiceName) + 5) * sizeof(WCHAR));
315 if (pszPassword == NULL)
316 {
317 dwError = ERROR_NOT_ENOUGH_MEMORY;
318 goto done;
319 }
320
321 wcscpy(pszPassword, L"_SC_");
322 wcscat(pszPassword, pService->lpServiceName);
323
324 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName, pszUserName, pszPassword);
325
326 /* Do the service logon */
327 if (!LogonUserW(pszUserName,
328 pszDomainName,
329 pszPassword,
330 LOGON32_LOGON_SERVICE,
331 LOGON32_PROVIDER_DEFAULT,
332 &pImage->hToken))
333 {
334 dwError = GetLastError();
335 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError);
336
337 /* Normalize the returned error */
338 dwError = ERROR_SERVICE_LOGON_FAILED;
339 goto done;
340 }
341
342 /* Load the user profile; the per-user environment variables are thus correctly initialized */
343 ZeroMemory(&ProfileInfo, sizeof(ProfileInfo));
344 ProfileInfo.dwSize = sizeof(ProfileInfo);
345 ProfileInfo.dwFlags = PI_NOUI;
346 ProfileInfo.lpUserName = pszUserName;
347 // ProfileInfo.lpProfilePath = NULL;
348 // ProfileInfo.lpDefaultPath = NULL;
349 // ProfileInfo.lpServerName = NULL;
350 // ProfileInfo.lpPolicyPath = NULL;
351 // ProfileInfo.hProfile = NULL;
352
353 if (!LoadUserProfileW(pImage->hToken, &ProfileInfo))
354 {
355 dwError = GetLastError();
356 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError);
357 goto done;
358 }
359
360 pImage->hProfile = ProfileInfo.hProfile;
361
362 done:
363 if (pszPassword != NULL)
364 HeapFree(GetProcessHeap(), 0, pszPassword);
365
366 if (ptr != NULL)
367 *ptr = L'\\';
368
369 return dwError;
370 }
371
372
373 static DWORD
374 ScmCreateOrReferenceServiceImage(PSERVICE pService)
375 {
376 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
377 UNICODE_STRING ImagePath;
378 UNICODE_STRING ObjectName;
379 PSERVICE_IMAGE pServiceImage = NULL;
380 NTSTATUS Status;
381 DWORD dwError = ERROR_SUCCESS;
382 DWORD dwRecordSize;
383 LPWSTR pString;
384
385 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService);
386
387 RtlInitUnicodeString(&ImagePath, NULL);
388 RtlInitUnicodeString(&ObjectName, NULL);
389
390 /* Get service data */
391 RtlZeroMemory(&QueryTable,
392 sizeof(QueryTable));
393
394 QueryTable[0].Name = L"ImagePath";
395 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
396 QueryTable[0].EntryContext = &ImagePath;
397 QueryTable[1].Name = L"ObjectName";
398 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
399 QueryTable[1].EntryContext = &ObjectName;
400
401 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
402 pService->lpServiceName,
403 QueryTable,
404 NULL,
405 NULL);
406 if (!NT_SUCCESS(Status))
407 {
408 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
409 return RtlNtStatusToDosError(Status);
410 }
411
412 DPRINT("ImagePath: '%wZ'\n", &ImagePath);
413 DPRINT("ObjectName: '%wZ'\n", &ObjectName);
414
415 pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer);
416 if (pServiceImage == NULL)
417 {
418 dwRecordSize = sizeof(SERVICE_IMAGE) +
419 ImagePath.Length + sizeof(WCHAR) +
420 ((ObjectName.Length != 0) ? (ObjectName.Length + sizeof(WCHAR)) : 0);
421
422 /* Create a new service image */
423 pServiceImage = HeapAlloc(GetProcessHeap(),
424 HEAP_ZERO_MEMORY,
425 dwRecordSize);
426 if (pServiceImage == NULL)
427 {
428 dwError = ERROR_NOT_ENOUGH_MEMORY;
429 goto done;
430 }
431
432 pServiceImage->dwImageRunCount = 1;
433 pServiceImage->hControlPipe = INVALID_HANDLE_VALUE;
434 pServiceImage->hProcess = INVALID_HANDLE_VALUE;
435
436 pString = (PWSTR)((INT_PTR)pServiceImage + sizeof(SERVICE_IMAGE));
437
438 /* Set the image path */
439 pServiceImage->pszImagePath = pString;
440 wcscpy(pServiceImage->pszImagePath,
441 ImagePath.Buffer);
442
443 /* Set the account name */
444 if (ObjectName.Length > 0)
445 {
446 pString = pString + wcslen(pString) + 1;
447
448 pServiceImage->pszAccountName = pString;
449 wcscpy(pServiceImage->pszAccountName,
450 ObjectName.Buffer);
451 }
452
453 /* Service logon */
454 dwError = ScmLogonService(pService, pServiceImage);
455 if (dwError != ERROR_SUCCESS)
456 {
457 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError);
458
459 /* Release the service image */
460 HeapFree(GetProcessHeap(), 0, pServiceImage);
461
462 goto done;
463 }
464
465 /* Create the control pipe */
466 dwError = ScmCreateNewControlPipe(pServiceImage);
467 if (dwError != ERROR_SUCCESS)
468 {
469 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError);
470
471 /* Unload the user profile */
472 if (pServiceImage->hProfile != NULL)
473 UnloadUserProfile(pServiceImage->hToken, pServiceImage->hProfile);
474
475 /* Close the logon token */
476 if (pServiceImage->hToken != NULL)
477 CloseHandle(pServiceImage->hToken);
478
479 /* Release the service image */
480 HeapFree(GetProcessHeap(), 0, pServiceImage);
481
482 goto done;
483 }
484
485 /* FIXME: Add more initialization code here */
486
487
488 /* Append service record */
489 InsertTailList(&ImageListHead,
490 &pServiceImage->ImageListEntry);
491 }
492 else
493 {
494 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
495
496 /* Fail if services in an image use different accounts */
497 if (!ScmIsSameServiceAccount(pServiceImage->pszAccountName, ObjectName.Buffer))
498 {
499 dwError = ERROR_DIFFERENT_SERVICE_ACCOUNT;
500 goto done;
501 }
502
503 /* Increment the run counter */
504 pServiceImage->dwImageRunCount++;
505 }
506
507 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage->pszImagePath);
508 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage->pszAccountName);
509 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount);
510
511 /* Link the service image to the service */
512 pService->lpImage = pServiceImage;
513
514 done:
515 RtlFreeUnicodeString(&ObjectName);
516 RtlFreeUnicodeString(&ImagePath);
517
518 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError);
519
520 return dwError;
521 }
522
523
524 VOID
525 ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage)
526 {
527 DPRINT1("ScmRemoveServiceImage() called\n");
528
529 /* FIXME: Terminate the process */
530
531 /* Remove the service image from the list */
532 RemoveEntryList(&pServiceImage->ImageListEntry);
533
534 /* Close the process handle */
535 if (pServiceImage->hProcess != INVALID_HANDLE_VALUE)
536 CloseHandle(pServiceImage->hProcess);
537
538 /* Close the control pipe */
539 if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE)
540 CloseHandle(pServiceImage->hControlPipe);
541
542 /* Unload the user profile */
543 if (pServiceImage->hProfile != NULL)
544 UnloadUserProfile(pServiceImage->hToken, pServiceImage->hProfile);
545
546 /* Close the logon token */
547 if (pServiceImage->hToken != NULL)
548 CloseHandle(pServiceImage->hToken);
549
550 /* Release the service image */
551 HeapFree(GetProcessHeap(), 0, pServiceImage);
552 }
553
554
555 PSERVICE
556 ScmGetServiceEntryByName(LPCWSTR lpServiceName)
557 {
558 PLIST_ENTRY ServiceEntry;
559 PSERVICE CurrentService;
560
561 DPRINT("ScmGetServiceEntryByName() called\n");
562
563 ServiceEntry = ServiceListHead.Flink;
564 while (ServiceEntry != &ServiceListHead)
565 {
566 CurrentService = CONTAINING_RECORD(ServiceEntry,
567 SERVICE,
568 ServiceListEntry);
569 if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0)
570 {
571 DPRINT("Found service: '%S'\n", CurrentService->lpServiceName);
572 return CurrentService;
573 }
574
575 ServiceEntry = ServiceEntry->Flink;
576 }
577
578 DPRINT("Couldn't find a matching service\n");
579
580 return NULL;
581 }
582
583
584 PSERVICE
585 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName)
586 {
587 PLIST_ENTRY ServiceEntry;
588 PSERVICE CurrentService;
589
590 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
591
592 ServiceEntry = ServiceListHead.Flink;
593 while (ServiceEntry != &ServiceListHead)
594 {
595 CurrentService = CONTAINING_RECORD(ServiceEntry,
596 SERVICE,
597 ServiceListEntry);
598 if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0)
599 {
600 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
601 return CurrentService;
602 }
603
604 ServiceEntry = ServiceEntry->Flink;
605 }
606
607 DPRINT("Couldn't find a matching service\n");
608
609 return NULL;
610 }
611
612
613 PSERVICE
614 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
615 {
616 PLIST_ENTRY ServiceEntry;
617 PSERVICE CurrentService;
618
619 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
620
621 ServiceEntry = ServiceListHead.Flink;
622 while (ServiceEntry != &ServiceListHead)
623 {
624 CurrentService = CONTAINING_RECORD(ServiceEntry,
625 SERVICE,
626 ServiceListEntry);
627 if (CurrentService->dwResumeCount > dwResumeCount)
628 {
629 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
630 return CurrentService;
631 }
632
633 ServiceEntry = ServiceEntry->Flink;
634 }
635
636 DPRINT("Couldn't find a matching service\n");
637
638 return NULL;
639 }
640
641
642 DWORD
643 ScmGenerateServiceTag(PSERVICE lpServiceRecord)
644 {
645 /* Check for an overflow */
646 if (ServiceTag == -1)
647 {
648 return ERROR_INVALID_DATA;
649 }
650
651 /* This is only valid for Win32 services */
652 if (!(lpServiceRecord->Status.dwServiceType & SERVICE_WIN32))
653 {
654 return ERROR_INVALID_PARAMETER;
655 }
656
657 /* Increment the tag counter and set it */
658 ServiceTag = ServiceTag % 0xFFFFFFFF + 1;
659 lpServiceRecord->dwTag = ServiceTag;
660
661 return ERROR_SUCCESS;
662 }
663
664
665 DWORD
666 ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
667 PSERVICE *lpServiceRecord,
668 DWORD dwServiceType,
669 DWORD dwStartType)
670 {
671 PSERVICE lpService = NULL;
672
673 DPRINT("Service: '%S'\n", lpServiceName);
674
675 /* Allocate service entry */
676 lpService = HeapAlloc(GetProcessHeap(),
677 HEAP_ZERO_MEMORY,
678 FIELD_OFFSET(SERVICE, szServiceName[wcslen(lpServiceName) + 1]));
679 if (lpService == NULL)
680 return ERROR_NOT_ENOUGH_MEMORY;
681
682 *lpServiceRecord = lpService;
683
684 /* Copy service name */
685 wcscpy(lpService->szServiceName, lpServiceName);
686 lpService->lpServiceName = lpService->szServiceName;
687 lpService->lpDisplayName = lpService->lpServiceName;
688
689 /* Set the start type */
690 lpService->dwStartType = dwStartType;
691
692 /* Set the resume count */
693 lpService->dwResumeCount = ResumeCount++;
694
695 /* Append service record */
696 InsertTailList(&ServiceListHead,
697 &lpService->ServiceListEntry);
698
699 /* Initialize the service status */
700 lpService->Status.dwServiceType = dwServiceType;
701 lpService->Status.dwCurrentState = SERVICE_STOPPED;
702 lpService->Status.dwControlsAccepted = 0;
703 lpService->Status.dwWin32ExitCode =
704 (dwStartType == SERVICE_DISABLED) ? ERROR_SERVICE_DISABLED : ERROR_SERVICE_NEVER_STARTED;
705 lpService->Status.dwServiceSpecificExitCode = 0;
706 lpService->Status.dwCheckPoint = 0;
707 lpService->Status.dwWaitHint =
708 (dwServiceType & SERVICE_DRIVER) ? 0 : 2000; /* 2 seconds */
709
710 return ERROR_SUCCESS;
711 }
712
713
714 VOID
715 ScmDeleteServiceRecord(PSERVICE lpService)
716 {
717 DPRINT("Deleting Service %S\n", lpService->lpServiceName);
718
719 /* Delete the display name */
720 if (lpService->lpDisplayName != NULL &&
721 lpService->lpDisplayName != lpService->lpServiceName)
722 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
723
724 /* Dereference the service image */
725 if (lpService->lpImage)
726 {
727 lpService->lpImage->dwImageRunCount--;
728
729 if (lpService->lpImage->dwImageRunCount == 0)
730 {
731 ScmRemoveServiceImage(lpService->lpImage);
732 lpService->lpImage = NULL;
733 }
734 }
735
736 /* Decrement the group reference counter */
737 ScmSetServiceGroup(lpService, NULL);
738
739 /* Release the SecurityDescriptor */
740 if (lpService->pSecurityDescriptor != NULL)
741 HeapFree(GetProcessHeap(), 0, lpService->pSecurityDescriptor);
742
743 /* Remove the Service from the List */
744 RemoveEntryList(&lpService->ServiceListEntry);
745
746 DPRINT("Deleted Service %S\n", lpService->lpServiceName);
747
748 /* Delete the service record */
749 HeapFree(GetProcessHeap(), 0, lpService);
750
751 DPRINT("Done\n");
752 }
753
754
755 static DWORD
756 CreateServiceListEntry(LPCWSTR lpServiceName,
757 HKEY hServiceKey)
758 {
759 PSERVICE lpService = NULL;
760 LPWSTR lpDisplayName = NULL;
761 LPWSTR lpGroup = NULL;
762 DWORD dwSize;
763 DWORD dwError;
764 DWORD dwServiceType;
765 DWORD dwStartType;
766 DWORD dwErrorControl;
767 DWORD dwTagId;
768
769 DPRINT("Service: '%S'\n", lpServiceName);
770 if (*lpServiceName == L'{')
771 return ERROR_SUCCESS;
772
773 dwSize = sizeof(DWORD);
774 dwError = RegQueryValueExW(hServiceKey,
775 L"Type",
776 NULL,
777 NULL,
778 (LPBYTE)&dwServiceType,
779 &dwSize);
780 if (dwError != ERROR_SUCCESS)
781 return ERROR_SUCCESS;
782
783 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
784 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) &&
785 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
786 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
787 return ERROR_SUCCESS;
788
789 DPRINT("Service type: %lx\n", dwServiceType);
790
791 dwSize = sizeof(DWORD);
792 dwError = RegQueryValueExW(hServiceKey,
793 L"Start",
794 NULL,
795 NULL,
796 (LPBYTE)&dwStartType,
797 &dwSize);
798 if (dwError != ERROR_SUCCESS)
799 return ERROR_SUCCESS;
800
801 DPRINT("Start type: %lx\n", dwStartType);
802
803 dwSize = sizeof(DWORD);
804 dwError = RegQueryValueExW(hServiceKey,
805 L"ErrorControl",
806 NULL,
807 NULL,
808 (LPBYTE)&dwErrorControl,
809 &dwSize);
810 if (dwError != ERROR_SUCCESS)
811 return ERROR_SUCCESS;
812
813 DPRINT("Error control: %lx\n", dwErrorControl);
814
815 dwError = RegQueryValueExW(hServiceKey,
816 L"Tag",
817 NULL,
818 NULL,
819 (LPBYTE)&dwTagId,
820 &dwSize);
821 if (dwError != ERROR_SUCCESS)
822 dwTagId = 0;
823
824 DPRINT("Tag: %lx\n", dwTagId);
825
826 dwError = ScmReadString(hServiceKey,
827 L"Group",
828 &lpGroup);
829 if (dwError != ERROR_SUCCESS)
830 lpGroup = NULL;
831
832 DPRINT("Group: %S\n", lpGroup);
833
834 dwError = ScmReadString(hServiceKey,
835 L"DisplayName",
836 &lpDisplayName);
837 if (dwError != ERROR_SUCCESS)
838 lpDisplayName = NULL;
839
840 DPRINT("Display name: %S\n", lpDisplayName);
841
842 dwError = ScmCreateNewServiceRecord(lpServiceName,
843 &lpService,
844 dwServiceType,
845 dwStartType);
846 if (dwError != ERROR_SUCCESS)
847 goto done;
848
849 lpService->dwErrorControl = dwErrorControl;
850 lpService->dwTag = dwTagId;
851
852 if (lpGroup != NULL)
853 {
854 dwError = ScmSetServiceGroup(lpService, lpGroup);
855 if (dwError != ERROR_SUCCESS)
856 goto done;
857 }
858
859 if (lpDisplayName != NULL)
860 {
861 lpService->lpDisplayName = lpDisplayName;
862 lpDisplayName = NULL;
863 }
864
865 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
866 if (lpService->lpGroup != NULL)
867 {
868 DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName);
869 }
870 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
871 lpService->dwStartType,
872 lpService->Status.dwServiceType,
873 lpService->dwTag,
874 lpService->dwErrorControl);
875
876 if (ScmIsDeleteFlagSet(hServiceKey))
877 lpService->bDeleted = TRUE;
878 else
879 ScmGenerateServiceTag(lpService);
880
881 if (lpService->Status.dwServiceType & SERVICE_WIN32)
882 {
883 dwError = ScmReadSecurityDescriptor(hServiceKey,
884 &lpService->pSecurityDescriptor);
885 if (dwError != ERROR_SUCCESS)
886 goto done;
887
888 /* Assing the default security descriptor if the security descriptor cannot be read */
889 if (lpService->pSecurityDescriptor == NULL)
890 {
891 DPRINT("No security descriptor found! Assign default security descriptor!\n");
892 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
893 if (dwError != ERROR_SUCCESS)
894 goto done;
895
896 dwError = ScmWriteSecurityDescriptor(hServiceKey,
897 lpService->pSecurityDescriptor);
898 if (dwError != ERROR_SUCCESS)
899 goto done;
900 }
901 }
902
903 done:
904 if (lpGroup != NULL)
905 HeapFree(GetProcessHeap(), 0, lpGroup);
906
907 if (lpDisplayName != NULL)
908 HeapFree(GetProcessHeap(), 0, lpDisplayName);
909
910 if (lpService != NULL)
911 {
912 ASSERT(lpService->lpImage == NULL);
913 }
914
915 return dwError;
916 }
917
918
919 VOID
920 ScmDeleteMarkedServices(VOID)
921 {
922 PLIST_ENTRY ServiceEntry;
923 PSERVICE CurrentService;
924 HKEY hServicesKey;
925 DWORD dwError;
926
927 ServiceEntry = ServiceListHead.Flink;
928 while (ServiceEntry != &ServiceListHead)
929 {
930 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
931
932 ServiceEntry = ServiceEntry->Flink;
933
934 if (CurrentService->bDeleted != FALSE)
935 {
936 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
937 L"System\\CurrentControlSet\\Services",
938 0,
939 DELETE,
940 &hServicesKey);
941 if (dwError == ERROR_SUCCESS)
942 {
943 dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName);
944 RegCloseKey(hServicesKey);
945 if (dwError == ERROR_SUCCESS)
946 {
947 RemoveEntryList(&CurrentService->ServiceListEntry);
948 HeapFree(GetProcessHeap(), 0, CurrentService);
949 }
950 }
951
952 if (dwError != ERROR_SUCCESS)
953 DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName);
954 }
955 }
956 }
957
958
959 static
960 VOID
961 ScmGetNoInteractiveServicesValue(VOID)
962 {
963 HKEY hKey;
964 DWORD dwKeySize;
965 LONG lError;
966
967 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
968 L"SYSTEM\\CurrentControlSet\\Control\\Windows",
969 0,
970 KEY_READ,
971 &hKey);
972 if (lError == ERROR_SUCCESS)
973 {
974 dwKeySize = sizeof(NoInteractiveServices);
975 lError = RegQueryValueExW(hKey,
976 L"NoInteractiveServices",
977 0,
978 NULL,
979 (LPBYTE)&NoInteractiveServices,
980 &dwKeySize);
981 RegCloseKey(hKey);
982 }
983 }
984
985
986 DWORD
987 ScmCreateServiceDatabase(VOID)
988 {
989 WCHAR szSubKey[MAX_PATH];
990 HKEY hServicesKey;
991 HKEY hServiceKey;
992 DWORD dwSubKey;
993 DWORD dwSubKeyLength;
994 FILETIME ftLastChanged;
995 DWORD dwError;
996
997 DPRINT("ScmCreateServiceDatabase() called\n");
998
999 /* Retrieve the NoInteractiveServies value */
1000 ScmGetNoInteractiveServicesValue();
1001
1002 /* Create the service group list */
1003 dwError = ScmCreateGroupList();
1004 if (dwError != ERROR_SUCCESS)
1005 return dwError;
1006
1007 /* Initialize image and service lists */
1008 InitializeListHead(&ImageListHead);
1009 InitializeListHead(&ServiceListHead);
1010
1011 /* Initialize the database lock */
1012 RtlInitializeResource(&DatabaseLock);
1013
1014 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1015 L"System\\CurrentControlSet\\Services",
1016 0,
1017 KEY_READ,
1018 &hServicesKey);
1019 if (dwError != ERROR_SUCCESS)
1020 return dwError;
1021
1022 dwSubKey = 0;
1023 for (;;)
1024 {
1025 dwSubKeyLength = MAX_PATH;
1026 dwError = RegEnumKeyExW(hServicesKey,
1027 dwSubKey,
1028 szSubKey,
1029 &dwSubKeyLength,
1030 NULL,
1031 NULL,
1032 NULL,
1033 &ftLastChanged);
1034 if (dwError == ERROR_SUCCESS &&
1035 szSubKey[0] != L'{')
1036 {
1037 DPRINT("SubKeyName: '%S'\n", szSubKey);
1038
1039 dwError = RegOpenKeyExW(hServicesKey,
1040 szSubKey,
1041 0,
1042 KEY_READ,
1043 &hServiceKey);
1044 if (dwError == ERROR_SUCCESS)
1045 {
1046 dwError = CreateServiceListEntry(szSubKey,
1047 hServiceKey);
1048
1049 RegCloseKey(hServiceKey);
1050 }
1051 }
1052
1053 if (dwError != ERROR_SUCCESS)
1054 break;
1055
1056 dwSubKey++;
1057 }
1058
1059 RegCloseKey(hServicesKey);
1060
1061 /* Wait for the LSA server */
1062 ScmWaitForLsa();
1063
1064 /* Delete services that are marked for delete */
1065 ScmDeleteMarkedServices();
1066
1067 DPRINT("ScmCreateServiceDatabase() done\n");
1068
1069 return ERROR_SUCCESS;
1070 }
1071
1072
1073 VOID
1074 ScmShutdownServiceDatabase(VOID)
1075 {
1076 DPRINT("ScmShutdownServiceDatabase() called\n");
1077
1078 ScmDeleteMarkedServices();
1079 RtlDeleteResource(&DatabaseLock);
1080
1081 DPRINT("ScmShutdownServiceDatabase() done\n");
1082 }
1083
1084
1085 static NTSTATUS
1086 ScmCheckDriver(PSERVICE Service)
1087 {
1088 OBJECT_ATTRIBUTES ObjectAttributes;
1089 UNICODE_STRING DirName;
1090 HANDLE DirHandle;
1091 NTSTATUS Status;
1092 POBJECT_DIRECTORY_INFORMATION DirInfo;
1093 ULONG BufferLength;
1094 ULONG DataLength;
1095 ULONG Index;
1096
1097 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
1098
1099 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
1100 {
1101 RtlInitUnicodeString(&DirName, L"\\Driver");
1102 }
1103 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
1104 {
1105 ASSERT(Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER);
1106 RtlInitUnicodeString(&DirName, L"\\FileSystem");
1107 }
1108
1109 InitializeObjectAttributes(&ObjectAttributes,
1110 &DirName,
1111 0,
1112 NULL,
1113 NULL);
1114
1115 Status = NtOpenDirectoryObject(&DirHandle,
1116 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
1117 &ObjectAttributes);
1118 if (!NT_SUCCESS(Status))
1119 {
1120 return Status;
1121 }
1122
1123 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
1124 2 * MAX_PATH * sizeof(WCHAR);
1125 DirInfo = HeapAlloc(GetProcessHeap(),
1126 HEAP_ZERO_MEMORY,
1127 BufferLength);
1128
1129 Index = 0;
1130 while (TRUE)
1131 {
1132 Status = NtQueryDirectoryObject(DirHandle,
1133 DirInfo,
1134 BufferLength,
1135 TRUE,
1136 FALSE,
1137 &Index,
1138 &DataLength);
1139 if (Status == STATUS_NO_MORE_ENTRIES)
1140 {
1141 /* FIXME: Add current service to 'failed service' list */
1142 DPRINT("Service '%S' failed\n", Service->lpServiceName);
1143 break;
1144 }
1145
1146 if (!NT_SUCCESS(Status))
1147 break;
1148
1149 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
1150
1151 if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
1152 {
1153 DPRINT("Found: '%S' '%wZ'\n",
1154 Service->lpServiceName, &DirInfo->Name);
1155
1156 /* Mark service as 'running' */
1157 Service->Status.dwCurrentState = SERVICE_RUNNING;
1158 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
1159 Service->Status.dwWin32ExitCode = ERROR_SUCCESS;
1160 Service->Status.dwServiceSpecificExitCode = 0;
1161 Service->Status.dwCheckPoint = 0;
1162 Service->Status.dwWaitHint = 0;
1163
1164 /* Mark the service group as 'running' */
1165 if (Service->lpGroup != NULL)
1166 {
1167 Service->lpGroup->ServicesRunning = TRUE;
1168 }
1169
1170 break;
1171 }
1172 }
1173
1174 HeapFree(GetProcessHeap(),
1175 0,
1176 DirInfo);
1177 NtClose(DirHandle);
1178
1179 return STATUS_SUCCESS;
1180 }
1181
1182
1183 VOID
1184 ScmGetBootAndSystemDriverState(VOID)
1185 {
1186 PLIST_ENTRY ServiceEntry;
1187 PSERVICE CurrentService;
1188
1189 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1190
1191 ServiceEntry = ServiceListHead.Flink;
1192 while (ServiceEntry != &ServiceListHead)
1193 {
1194 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1195
1196 if (CurrentService->dwStartType == SERVICE_BOOT_START ||
1197 CurrentService->dwStartType == SERVICE_SYSTEM_START)
1198 {
1199 /* Check driver */
1200 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
1201
1202 ScmCheckDriver(CurrentService);
1203 }
1204
1205 ServiceEntry = ServiceEntry->Flink;
1206 }
1207
1208 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1209 }
1210
1211
1212 DWORD
1213 ScmControlService(HANDLE hControlPipe,
1214 PWSTR pServiceName,
1215 SERVICE_STATUS_HANDLE hServiceStatus,
1216 DWORD dwControl)
1217 {
1218 PSCM_CONTROL_PACKET ControlPacket;
1219 SCM_REPLY_PACKET ReplyPacket;
1220
1221 DWORD dwWriteCount = 0;
1222 DWORD dwReadCount = 0;
1223 DWORD PacketSize;
1224 PWSTR Ptr;
1225 DWORD dwError = ERROR_SUCCESS;
1226 BOOL bResult;
1227 OVERLAPPED Overlapped = {0};
1228
1229 DPRINT("ScmControlService() called\n");
1230
1231 /* Acquire the service control critical section, to synchronize requests */
1232 EnterCriticalSection(&ControlServiceCriticalSection);
1233
1234 /* Calculate the total length of the start command line */
1235 PacketSize = sizeof(SCM_CONTROL_PACKET);
1236 PacketSize += (DWORD)((wcslen(pServiceName) + 1) * sizeof(WCHAR));
1237
1238 ControlPacket = HeapAlloc(GetProcessHeap(),
1239 HEAP_ZERO_MEMORY,
1240 PacketSize);
1241 if (ControlPacket == NULL)
1242 {
1243 LeaveCriticalSection(&ControlServiceCriticalSection);
1244 return ERROR_NOT_ENOUGH_MEMORY;
1245 }
1246
1247 ControlPacket->dwSize = PacketSize;
1248 ControlPacket->dwControl = dwControl;
1249 ControlPacket->hServiceStatus = hServiceStatus;
1250
1251 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
1252
1253 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
1254 wcscpy(Ptr, pServiceName);
1255
1256 ControlPacket->dwArgumentsCount = 0;
1257 ControlPacket->dwArgumentsOffset = 0;
1258
1259 bResult = WriteFile(hControlPipe,
1260 ControlPacket,
1261 PacketSize,
1262 &dwWriteCount,
1263 &Overlapped);
1264 if (bResult == FALSE)
1265 {
1266 DPRINT("WriteFile() returned FALSE\n");
1267
1268 dwError = GetLastError();
1269 if (dwError == ERROR_IO_PENDING)
1270 {
1271 DPRINT("dwError: ERROR_IO_PENDING\n");
1272
1273 dwError = WaitForSingleObject(hControlPipe,
1274 PipeTimeout);
1275 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1276
1277 if (dwError == WAIT_TIMEOUT)
1278 {
1279 bResult = CancelIo(hControlPipe);
1280 if (bResult == FALSE)
1281 {
1282 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1283 }
1284
1285 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1286 goto Done;
1287 }
1288 else if (dwError == WAIT_OBJECT_0)
1289 {
1290 bResult = GetOverlappedResult(hControlPipe,
1291 &Overlapped,
1292 &dwWriteCount,
1293 TRUE);
1294 if (bResult == FALSE)
1295 {
1296 dwError = GetLastError();
1297 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1298
1299 goto Done;
1300 }
1301 }
1302 }
1303 else
1304 {
1305 DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
1306 goto Done;
1307 }
1308 }
1309
1310 /* Read the reply */
1311 Overlapped.hEvent = (HANDLE) NULL;
1312
1313 bResult = ReadFile(hControlPipe,
1314 &ReplyPacket,
1315 sizeof(SCM_REPLY_PACKET),
1316 &dwReadCount,
1317 &Overlapped);
1318 if (bResult == FALSE)
1319 {
1320 DPRINT("ReadFile() returned FALSE\n");
1321
1322 dwError = GetLastError();
1323 if (dwError == ERROR_IO_PENDING)
1324 {
1325 DPRINT("dwError: ERROR_IO_PENDING\n");
1326
1327 dwError = WaitForSingleObject(hControlPipe,
1328 PipeTimeout);
1329 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1330
1331 if (dwError == WAIT_TIMEOUT)
1332 {
1333 bResult = CancelIo(hControlPipe);
1334 if (bResult == FALSE)
1335 {
1336 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1337 }
1338
1339 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1340 goto Done;
1341 }
1342 else if (dwError == WAIT_OBJECT_0)
1343 {
1344 bResult = GetOverlappedResult(hControlPipe,
1345 &Overlapped,
1346 &dwReadCount,
1347 TRUE);
1348 if (bResult == FALSE)
1349 {
1350 dwError = GetLastError();
1351 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1352
1353 goto Done;
1354 }
1355 }
1356 }
1357 else
1358 {
1359 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1360 goto Done;
1361 }
1362 }
1363
1364 Done:
1365 /* Release the control packet */
1366 HeapFree(GetProcessHeap(),
1367 0,
1368 ControlPacket);
1369
1370 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
1371 {
1372 dwError = ReplyPacket.dwError;
1373 }
1374
1375 LeaveCriticalSection(&ControlServiceCriticalSection);
1376
1377 DPRINT("ScmControlService() done\n");
1378
1379 return dwError;
1380 }
1381
1382
1383 static DWORD
1384 ScmSendStartCommand(PSERVICE Service,
1385 DWORD argc,
1386 LPWSTR* argv)
1387 {
1388 DWORD dwError = ERROR_SUCCESS;
1389 PSCM_CONTROL_PACKET ControlPacket;
1390 SCM_REPLY_PACKET ReplyPacket;
1391 DWORD PacketSize;
1392 DWORD i;
1393 PWSTR Ptr;
1394 PWSTR *pOffPtr;
1395 PWSTR pArgPtr;
1396 BOOL bResult;
1397 DWORD dwWriteCount = 0;
1398 DWORD dwReadCount = 0;
1399 OVERLAPPED Overlapped = {0};
1400
1401 DPRINT("ScmSendStartCommand() called\n");
1402
1403 /* Calculate the total length of the start command line */
1404 PacketSize = sizeof(SCM_CONTROL_PACKET);
1405 PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
1406
1407 /*
1408 * Calculate the required packet size for the start argument vector 'argv',
1409 * composed of the list of pointer offsets, followed by UNICODE strings.
1410 * The strings are stored continuously after the vector of offsets, with
1411 * the offsets being relative to the beginning of the vector, as in the
1412 * following layout (with N == argc):
1413 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1414 */
1415 if (argc > 0 && argv != NULL)
1416 {
1417 PacketSize = ALIGN_UP(PacketSize, PWSTR);
1418 PacketSize += (argc * sizeof(PWSTR));
1419
1420 DPRINT("Argc: %lu\n", argc);
1421 for (i = 0; i < argc; i++)
1422 {
1423 DPRINT("Argv[%lu]: %S\n", i, argv[i]);
1424 PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR));
1425 }
1426 }
1427
1428 /* Allocate a control packet */
1429 ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PacketSize);
1430 if (ControlPacket == NULL)
1431 return ERROR_NOT_ENOUGH_MEMORY;
1432
1433 ControlPacket->dwSize = PacketSize;
1434 ControlPacket->dwControl = (Service->Status.dwServiceType & SERVICE_WIN32_OWN_PROCESS)
1435 ? SERVICE_CONTROL_START_OWN
1436 : SERVICE_CONTROL_START_SHARE;
1437 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
1438 ControlPacket->dwServiceTag = Service->dwTag;
1439
1440 /* Copy the start command line */
1441 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
1442 Ptr = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset);
1443 wcscpy(Ptr, Service->lpServiceName);
1444
1445 ControlPacket->dwArgumentsCount = 0;
1446 ControlPacket->dwArgumentsOffset = 0;
1447
1448 /* Copy the argument vector */
1449 if (argc > 0 && argv != NULL)
1450 {
1451 Ptr += wcslen(Service->lpServiceName) + 1;
1452 pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR);
1453 pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
1454
1455 ControlPacket->dwArgumentsCount = argc;
1456 ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
1457
1458 DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount);
1459 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset);
1460
1461 for (i = 0; i < argc; i++)
1462 {
1463 wcscpy(pArgPtr, argv[i]);
1464 pOffPtr[i] = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
1465 DPRINT("offset[%lu]: %p\n", i, pOffPtr[i]);
1466 pArgPtr += wcslen(argv[i]) + 1;
1467 }
1468 }
1469
1470 bResult = WriteFile(Service->lpImage->hControlPipe,
1471 ControlPacket,
1472 PacketSize,
1473 &dwWriteCount,
1474 &Overlapped);
1475 if (bResult == FALSE)
1476 {
1477 DPRINT("WriteFile() returned FALSE\n");
1478
1479 dwError = GetLastError();
1480 if (dwError == ERROR_IO_PENDING)
1481 {
1482 DPRINT("dwError: ERROR_IO_PENDING\n");
1483
1484 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1485 PipeTimeout);
1486 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1487
1488 if (dwError == WAIT_TIMEOUT)
1489 {
1490 bResult = CancelIo(Service->lpImage->hControlPipe);
1491 if (bResult == FALSE)
1492 {
1493 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1494 }
1495
1496 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1497 goto Done;
1498 }
1499 else if (dwError == WAIT_OBJECT_0)
1500 {
1501 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1502 &Overlapped,
1503 &dwWriteCount,
1504 TRUE);
1505 if (bResult == FALSE)
1506 {
1507 dwError = GetLastError();
1508 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1509
1510 goto Done;
1511 }
1512 }
1513 }
1514 else
1515 {
1516 DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
1517 goto Done;
1518 }
1519 }
1520
1521 /* Read the reply */
1522 Overlapped.hEvent = (HANDLE) NULL;
1523
1524 bResult = ReadFile(Service->lpImage->hControlPipe,
1525 &ReplyPacket,
1526 sizeof(SCM_REPLY_PACKET),
1527 &dwReadCount,
1528 &Overlapped);
1529 if (bResult == FALSE)
1530 {
1531 DPRINT("ReadFile() returned FALSE\n");
1532
1533 dwError = GetLastError();
1534 if (dwError == ERROR_IO_PENDING)
1535 {
1536 DPRINT("dwError: ERROR_IO_PENDING\n");
1537
1538 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1539 PipeTimeout);
1540 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1541
1542 if (dwError == WAIT_TIMEOUT)
1543 {
1544 bResult = CancelIo(Service->lpImage->hControlPipe);
1545 if (bResult == FALSE)
1546 {
1547 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1548 }
1549
1550 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1551 goto Done;
1552 }
1553 else if (dwError == WAIT_OBJECT_0)
1554 {
1555 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1556 &Overlapped,
1557 &dwReadCount,
1558 TRUE);
1559 if (bResult == FALSE)
1560 {
1561 dwError = GetLastError();
1562 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1563
1564 goto Done;
1565 }
1566 }
1567 }
1568 else
1569 {
1570 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1571 goto Done;
1572 }
1573 }
1574
1575 Done:
1576 /* Release the control packet */
1577 HeapFree(GetProcessHeap(),
1578 0,
1579 ControlPacket);
1580
1581 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
1582 {
1583 dwError = ReplyPacket.dwError;
1584 }
1585
1586 DPRINT("ScmSendStartCommand() done\n");
1587
1588 return dwError;
1589 }
1590
1591
1592 static DWORD
1593 ScmWaitForServiceConnect(PSERVICE Service)
1594 {
1595 DWORD dwRead = 0;
1596 DWORD dwProcessId = 0;
1597 DWORD dwError = ERROR_SUCCESS;
1598 BOOL bResult;
1599 OVERLAPPED Overlapped = {0};
1600 #if 0
1601 LPCWSTR lpLogStrings[3];
1602 WCHAR szBuffer1[20];
1603 WCHAR szBuffer2[20];
1604 #endif
1605
1606 DPRINT("ScmWaitForServiceConnect()\n");
1607
1608 Overlapped.hEvent = (HANDLE)NULL;
1609
1610 bResult = ConnectNamedPipe(Service->lpImage->hControlPipe,
1611 &Overlapped);
1612 if (bResult == FALSE)
1613 {
1614 DPRINT("ConnectNamedPipe() returned FALSE\n");
1615
1616 dwError = GetLastError();
1617 if (dwError == ERROR_IO_PENDING)
1618 {
1619 DPRINT("dwError: ERROR_IO_PENDING\n");
1620
1621 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1622 PipeTimeout);
1623 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1624
1625 if (dwError == WAIT_TIMEOUT)
1626 {
1627 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1628
1629 bResult = CancelIo(Service->lpImage->hControlPipe);
1630 if (bResult == FALSE)
1631 {
1632 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1633 }
1634
1635 #if 0
1636 _ultow(PipeTimeout, szBuffer1, 10);
1637 lpLogStrings[0] = Service->lpDisplayName;
1638 lpLogStrings[1] = szBuffer1;
1639
1640 ScmLogEvent(EVENT_CONNECTION_TIMEOUT,
1641 EVENTLOG_ERROR_TYPE,
1642 2,
1643 lpLogStrings);
1644 #endif
1645 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service->lpDisplayName);
1646
1647 return ERROR_SERVICE_REQUEST_TIMEOUT;
1648 }
1649 else if (dwError == WAIT_OBJECT_0)
1650 {
1651 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1652 &Overlapped,
1653 &dwRead,
1654 TRUE);
1655 if (bResult == FALSE)
1656 {
1657 dwError = GetLastError();
1658 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError);
1659
1660 return dwError;
1661 }
1662 }
1663 }
1664 else if (dwError != ERROR_PIPE_CONNECTED)
1665 {
1666 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError);
1667 return dwError;
1668 }
1669 }
1670
1671 DPRINT("Control pipe connected!\n");
1672
1673 Overlapped.hEvent = (HANDLE) NULL;
1674
1675 /* Read the process id from pipe */
1676 bResult = ReadFile(Service->lpImage->hControlPipe,
1677 (LPVOID)&dwProcessId,
1678 sizeof(DWORD),
1679 &dwRead,
1680 &Overlapped);
1681 if (bResult == FALSE)
1682 {
1683 DPRINT("ReadFile() returned FALSE\n");
1684
1685 dwError = GetLastError();
1686 if (dwError == ERROR_IO_PENDING)
1687 {
1688 DPRINT("dwError: ERROR_IO_PENDING\n");
1689
1690 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1691 PipeTimeout);
1692 if (dwError == WAIT_TIMEOUT)
1693 {
1694 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1695
1696 bResult = CancelIo(Service->lpImage->hControlPipe);
1697 if (bResult == FALSE)
1698 {
1699 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1700 }
1701
1702 #if 0
1703 _ultow(PipeTimeout, szBuffer1, 10);
1704 lpLogStrings[0] = szBuffer1;
1705
1706 ScmLogEvent(EVENT_READFILE_TIMEOUT,
1707 EVENTLOG_ERROR_TYPE,
1708 1,
1709 lpLogStrings);
1710 #endif
1711 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service->lpDisplayName);
1712
1713 return ERROR_SERVICE_REQUEST_TIMEOUT;
1714 }
1715 else if (dwError == WAIT_OBJECT_0)
1716 {
1717 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1718
1719 DPRINT("Process Id: %lu\n", dwProcessId);
1720
1721 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1722 &Overlapped,
1723 &dwRead,
1724 TRUE);
1725 if (bResult == FALSE)
1726 {
1727 dwError = GetLastError();
1728 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1729
1730 return dwError;
1731 }
1732 }
1733 else
1734 {
1735 DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
1736 }
1737 }
1738 else
1739 {
1740 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1741 return dwError;
1742 }
1743 }
1744
1745 if (dwProcessId != Service->lpImage->dwProcessId)
1746 {
1747 #if 0
1748 _ultow(Service->lpImage->dwProcessId, szBuffer1, 10);
1749 _ultow(dwProcessId, szBuffer2, 10);
1750
1751 lpLogStrings[0] = Service->lpDisplayName;
1752 lpLogStrings[1] = szBuffer1;
1753 lpLogStrings[2] = szBuffer2;
1754
1755 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED,
1756 EVENTLOG_WARNING_TYPE,
1757 3,
1758 lpLogStrings);
1759 #endif
1760
1761 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service->lpDisplayName);
1762 }
1763
1764 DPRINT("ScmWaitForServiceConnect() done\n");
1765
1766 return ERROR_SUCCESS;
1767 }
1768
1769
1770 static DWORD
1771 ScmStartUserModeService(PSERVICE Service,
1772 DWORD argc,
1773 LPWSTR* argv)
1774 {
1775 PROCESS_INFORMATION ProcessInformation;
1776 STARTUPINFOW StartupInfo;
1777 LPVOID lpEnvironment;
1778 BOOL Result;
1779 DWORD dwError = ERROR_SUCCESS;
1780
1781 DPRINT("ScmStartUserModeService(%p)\n", Service);
1782
1783 /* If the image is already running ... */
1784 if (Service->lpImage->dwImageRunCount > 1)
1785 {
1786 /* ... just send a start command */
1787 return ScmSendStartCommand(Service, argc, argv);
1788 }
1789
1790 /* Otherwise start its process */
1791 ZeroMemory(&StartupInfo, sizeof(StartupInfo));
1792 StartupInfo.cb = sizeof(StartupInfo);
1793 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
1794
1795 if (Service->lpImage->hToken)
1796 {
1797 /* User token: Run the service under the user account */
1798
1799 if (!CreateEnvironmentBlock(&lpEnvironment, Service->lpImage->hToken, FALSE))
1800 {
1801 /* We failed, run the service with the current environment */
1802 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1803 GetLastError(), Service->lpServiceName);
1804 lpEnvironment = NULL;
1805 }
1806
1807 /* Impersonate the new user */
1808 Result = ImpersonateLoggedOnUser(Service->lpImage->hToken);
1809 if (Result)
1810 {
1811 /* Launch the process in the user's logon session */
1812 Result = CreateProcessAsUserW(Service->lpImage->hToken,
1813 NULL,
1814 Service->lpImage->pszImagePath,
1815 NULL,
1816 NULL,
1817 FALSE,
1818 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED,
1819 lpEnvironment,
1820 NULL,
1821 &StartupInfo,
1822 &ProcessInformation);
1823 if (!Result)
1824 dwError = GetLastError();
1825
1826 /* Revert the impersonation */
1827 RevertToSelf();
1828 }
1829 else
1830 {
1831 dwError = GetLastError();
1832 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError);
1833 }
1834 }
1835 else
1836 {
1837 /* No user token: Run the service under the LocalSystem account */
1838
1839 if (!CreateEnvironmentBlock(&lpEnvironment, NULL, TRUE))
1840 {
1841 /* We failed, run the service with the current environment */
1842 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1843 GetLastError(), Service->lpServiceName);
1844 lpEnvironment = NULL;
1845 }
1846
1847 /* Use the interactive desktop if the service is interactive */
1848 if ((NoInteractiveServices == 0) &&
1849 (Service->Status.dwServiceType & SERVICE_INTERACTIVE_PROCESS))
1850 {
1851 StartupInfo.dwFlags |= STARTF_INHERITDESKTOP;
1852 StartupInfo.lpDesktop = L"WinSta0\\Default";
1853 }
1854
1855 if (wcsstr(Service->lpImage->pszImagePath, L"\\system32\\lsass.exe") == NULL)
1856 {
1857 Result = CreateProcessW(NULL,
1858 Service->lpImage->pszImagePath,
1859 NULL,
1860 NULL,
1861 FALSE,
1862 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED,
1863 lpEnvironment,
1864 NULL,
1865 &StartupInfo,
1866 &ProcessInformation);
1867 if (!Result)
1868 dwError = GetLastError();
1869 }
1870 else
1871 {
1872 Result = TRUE;
1873 dwError = ERROR_SUCCESS;
1874 }
1875 }
1876
1877 if (lpEnvironment)
1878 DestroyEnvironmentBlock(lpEnvironment);
1879
1880 if (!Result)
1881 {
1882 DPRINT1("Starting '%S' failed with error %d\n",
1883 Service->lpServiceName, dwError);
1884 return dwError;
1885 }
1886
1887 DPRINT("Process Id: %lu Handle %p\n",
1888 ProcessInformation.dwProcessId,
1889 ProcessInformation.hProcess);
1890 DPRINT("Thread Id: %lu Handle %p\n",
1891 ProcessInformation.dwThreadId,
1892 ProcessInformation.hThread);
1893
1894 /* Get the process handle and ID */
1895 Service->lpImage->hProcess = ProcessInformation.hProcess;
1896 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
1897
1898 /* Resume the main thread and close its handle */
1899 ResumeThread(ProcessInformation.hThread);
1900 CloseHandle(ProcessInformation.hThread);
1901
1902 /* Connect control pipe */
1903 dwError = ScmWaitForServiceConnect(Service);
1904 if (dwError != ERROR_SUCCESS)
1905 {
1906 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
1907 Service->lpImage->dwProcessId = 0;
1908 return dwError;
1909 }
1910
1911 /* Send the start command */
1912 return ScmSendStartCommand(Service, argc, argv);
1913 }
1914
1915
1916 static DWORD
1917 ScmLoadService(PSERVICE Service,
1918 DWORD argc,
1919 LPWSTR* argv)
1920 {
1921 PSERVICE_GROUP Group = Service->lpGroup;
1922 DWORD dwError = ERROR_SUCCESS;
1923 LPCWSTR lpLogStrings[2];
1924 WCHAR szLogBuffer[80];
1925
1926 DPRINT("ScmLoadService() called\n");
1927 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
1928
1929 if (Service->Status.dwCurrentState != SERVICE_STOPPED)
1930 {
1931 DPRINT("Service %S is already running!\n", Service->lpServiceName);
1932 return ERROR_SERVICE_ALREADY_RUNNING;
1933 }
1934
1935 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
1936
1937 if (Service->Status.dwServiceType & SERVICE_DRIVER)
1938 {
1939 /* Start the driver */
1940 dwError = ScmStartDriver(Service);
1941 }
1942 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1943 {
1944 /* Start user-mode service */
1945 dwError = ScmCreateOrReferenceServiceImage(Service);
1946 if (dwError == ERROR_SUCCESS)
1947 {
1948 dwError = ScmStartUserModeService(Service, argc, argv);
1949 if (dwError == ERROR_SUCCESS)
1950 {
1951 Service->Status.dwCurrentState = SERVICE_START_PENDING;
1952 Service->Status.dwControlsAccepted = 0;
1953 }
1954 else
1955 {
1956 Service->lpImage->dwImageRunCount--;
1957 if (Service->lpImage->dwImageRunCount == 0)
1958 {
1959 ScmRemoveServiceImage(Service->lpImage);
1960 Service->lpImage = NULL;
1961 }
1962 }
1963 }
1964 }
1965
1966 DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
1967
1968 if (dwError == ERROR_SUCCESS)
1969 {
1970 if (Group != NULL)
1971 {
1972 Group->ServicesRunning = TRUE;
1973 }
1974
1975 /* Log a successful service start */
1976 LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_START, szLogBuffer, 80);
1977 lpLogStrings[0] = Service->lpDisplayName;
1978 lpLogStrings[1] = szLogBuffer;
1979
1980 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
1981 EVENTLOG_INFORMATION_TYPE,
1982 2,
1983 lpLogStrings);
1984 }
1985 else
1986 {
1987 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
1988 {
1989 /* Log a failed service start */
1990 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer),
1991 L"%lu", dwError);
1992 lpLogStrings[0] = Service->lpServiceName;
1993 lpLogStrings[1] = szLogBuffer;
1994 ScmLogEvent(EVENT_SERVICE_START_FAILED,
1995 EVENTLOG_ERROR_TYPE,
1996 2,
1997 lpLogStrings);
1998 }
1999
2000 #if 0
2001 switch (Service->dwErrorControl)
2002 {
2003 case SERVICE_ERROR_SEVERE:
2004 if (IsLastKnownGood == FALSE)
2005 {
2006 /* FIXME: Boot last known good configuration */
2007 }
2008 break;
2009
2010 case SERVICE_ERROR_CRITICAL:
2011 if (IsLastKnownGood == FALSE)
2012 {
2013 /* FIXME: Boot last known good configuration */
2014 }
2015 else
2016 {
2017 /* FIXME: BSOD! */
2018 }
2019 break;
2020 }
2021 #endif
2022 }
2023
2024 return dwError;
2025 }
2026
2027
2028 DWORD
2029 ScmStartService(PSERVICE Service,
2030 DWORD argc,
2031 LPWSTR* argv)
2032 {
2033 DWORD dwError = ERROR_SUCCESS;
2034 SC_RPC_LOCK Lock = NULL;
2035
2036 DPRINT("ScmStartService() called\n");
2037 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
2038
2039 /* Acquire the service control critical section, to synchronize starts */
2040 EnterCriticalSection(&ControlServiceCriticalSection);
2041
2042 /*
2043 * Acquire the user service start lock while the service is starting, if
2044 * needed (i.e. if we are not starting it during the initialization phase).
2045 * If we don't success, bail out.
2046 */
2047 if (!ScmInitialize)
2048 {
2049 dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
2050 if (dwError != ERROR_SUCCESS) goto done;
2051 }
2052
2053 /* Really start the service */
2054 dwError = ScmLoadService(Service, argc, argv);
2055
2056 /* Release the service start lock, if needed, and the critical section */
2057 if (Lock) ScmReleaseServiceStartLock(&Lock);
2058
2059 done:
2060 LeaveCriticalSection(&ControlServiceCriticalSection);
2061
2062 DPRINT("ScmStartService() done (Error %lu)\n", dwError);
2063
2064 return dwError;
2065 }
2066
2067
2068 VOID
2069 ScmAutoStartServices(VOID)
2070 {
2071 DWORD dwError;
2072 PLIST_ENTRY GroupEntry;
2073 PLIST_ENTRY ServiceEntry;
2074 PSERVICE_GROUP CurrentGroup;
2075 PSERVICE CurrentService;
2076 WCHAR szSafeBootServicePath[MAX_PATH];
2077 DWORD SafeBootEnabled;
2078 HKEY hKey;
2079 DWORD dwKeySize;
2080 ULONG i;
2081
2082 /*
2083 * This function MUST be called ONLY at initialization time.
2084 * Therefore, no need to acquire the user service start lock.
2085 */
2086 ASSERT(ScmInitialize);
2087
2088 /* Retrieve the SafeBoot parameter */
2089 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2090 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
2091 0,
2092 KEY_READ,
2093 &hKey);
2094 if (dwError == ERROR_SUCCESS)
2095 {
2096 dwKeySize = sizeof(SafeBootEnabled);
2097 dwError = RegQueryValueExW(hKey,
2098 L"OptionValue",
2099 0,
2100 NULL,
2101 (LPBYTE)&SafeBootEnabled,
2102 &dwKeySize);
2103 RegCloseKey(hKey);
2104 }
2105
2106 /* Default to Normal boot if the value doesn't exist */
2107 if (dwError != ERROR_SUCCESS)
2108 SafeBootEnabled = 0;
2109
2110 /* Acquire the service control critical section, to synchronize starts */
2111 EnterCriticalSection(&ControlServiceCriticalSection);
2112
2113 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
2114 ServiceEntry = ServiceListHead.Flink;
2115 while (ServiceEntry != &ServiceListHead)
2116 {
2117 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2118
2119 /* Build the safe boot path */
2120 StringCchCopyW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath),
2121 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
2122
2123 switch (SafeBootEnabled)
2124 {
2125 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
2126 case 1:
2127 case 3:
2128 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath),
2129 L"\\Minimal\\");
2130 break;
2131
2132 case 2:
2133 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath),
2134 L"\\Network\\");
2135 break;
2136 }
2137
2138 if (SafeBootEnabled != 0)
2139 {
2140 /* If key does not exist then do not assume safe mode */
2141 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2142 szSafeBootServicePath,
2143 0,
2144 KEY_READ,
2145 &hKey);
2146 if (dwError == ERROR_SUCCESS)
2147 {
2148 RegCloseKey(hKey);
2149
2150 /* Finish Safe Boot path off */
2151 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath),
2152 CurrentService->lpServiceName);
2153
2154 /* Check that the key is in the Safe Boot path */
2155 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2156 szSafeBootServicePath,
2157 0,
2158 KEY_READ,
2159 &hKey);
2160 if (dwError != ERROR_SUCCESS)
2161 {
2162 /* Mark service as visited so it is not auto-started */
2163 CurrentService->ServiceVisited = TRUE;
2164 }
2165 else
2166 {
2167 /* Must be auto-started in safe mode - mark as unvisited */
2168 RegCloseKey(hKey);
2169 CurrentService->ServiceVisited = FALSE;
2170 }
2171 }
2172 else
2173 {
2174 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2175 CurrentService->ServiceVisited = FALSE;
2176 }
2177 }
2178
2179 ServiceEntry = ServiceEntry->Flink;
2180 }
2181
2182 /* Start all services which are members of an existing group */
2183 GroupEntry = GroupListHead.Flink;
2184 while (GroupEntry != &GroupListHead)
2185 {
2186 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
2187
2188 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
2189
2190 /* Start all services witch have a valid tag */
2191 for (i = 0; i < CurrentGroup->TagCount; i++)
2192 {
2193 ServiceEntry = ServiceListHead.Flink;
2194 while (ServiceEntry != &ServiceListHead)
2195 {
2196 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2197
2198 if ((CurrentService->lpGroup == CurrentGroup) &&
2199 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2200 (CurrentService->ServiceVisited == FALSE) &&
2201 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
2202 {
2203 CurrentService->ServiceVisited = TRUE;
2204 ScmLoadService(CurrentService, 0, NULL);
2205 }
2206
2207 ServiceEntry = ServiceEntry->Flink;
2208 }
2209 }
2210
2211 /* Start all services which have an invalid tag or which do not have a tag */
2212 ServiceEntry = ServiceListHead.Flink;
2213 while (ServiceEntry != &ServiceListHead)
2214 {
2215 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2216
2217 if ((CurrentService->lpGroup == CurrentGroup) &&
2218 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2219 (CurrentService->ServiceVisited == FALSE))
2220 {
2221 CurrentService->ServiceVisited = TRUE;
2222 ScmLoadService(CurrentService, 0, NULL);
2223 }
2224
2225 ServiceEntry = ServiceEntry->Flink;
2226 }
2227
2228 GroupEntry = GroupEntry->Flink;
2229 }
2230
2231 /* Start all services which are members of any non-existing group */
2232 ServiceEntry = ServiceListHead.Flink;
2233 while (ServiceEntry != &ServiceListHead)
2234 {
2235 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2236
2237 if ((CurrentService->lpGroup != NULL) &&
2238 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2239 (CurrentService->ServiceVisited == FALSE))
2240 {
2241 CurrentService->ServiceVisited = TRUE;
2242 ScmLoadService(CurrentService, 0, NULL);
2243 }
2244
2245 ServiceEntry = ServiceEntry->Flink;
2246 }
2247
2248 /* Start all services which are not a member of any group */
2249 ServiceEntry = ServiceListHead.Flink;
2250 while (ServiceEntry != &ServiceListHead)
2251 {
2252 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2253
2254 if ((CurrentService->lpGroup == NULL) &&
2255 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2256 (CurrentService->ServiceVisited == FALSE))
2257 {
2258 CurrentService->ServiceVisited = TRUE;
2259 ScmLoadService(CurrentService, 0, NULL);
2260 }
2261
2262 ServiceEntry = ServiceEntry->Flink;
2263 }
2264
2265 /* Clear 'ServiceVisited' flag again */
2266 ServiceEntry = ServiceListHead.Flink;
2267 while (ServiceEntry != &ServiceListHead)
2268 {
2269 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2270 CurrentService->ServiceVisited = FALSE;
2271 ServiceEntry = ServiceEntry->Flink;
2272 }
2273
2274 /* Release the critical section */
2275 LeaveCriticalSection(&ControlServiceCriticalSection);
2276 }
2277
2278
2279 VOID
2280 ScmAutoShutdownServices(VOID)
2281 {
2282 PLIST_ENTRY ServiceEntry;
2283 PSERVICE CurrentService;
2284
2285 DPRINT("ScmAutoShutdownServices() called\n");
2286
2287 /* Lock the service database exclusively */
2288 ScmLockDatabaseExclusive();
2289
2290 ServiceEntry = ServiceListHead.Flink;
2291 while (ServiceEntry != &ServiceListHead)
2292 {
2293 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2294
2295 if ((CurrentService->Status.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) &&
2296 (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
2297 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING))
2298 {
2299 /* Send the shutdown notification */
2300 DPRINT("Shutdown service: %S\n", CurrentService->lpServiceName);
2301 ScmControlService(CurrentService->lpImage->hControlPipe,
2302 CurrentService->lpServiceName,
2303 (SERVICE_STATUS_HANDLE)CurrentService,
2304 SERVICE_CONTROL_SHUTDOWN);
2305 }
2306
2307 ServiceEntry = ServiceEntry->Flink;
2308 }
2309
2310 /* Unlock the service database */
2311 ScmUnlockDatabase();
2312
2313 DPRINT("ScmAutoShutdownServices() done\n");
2314 }
2315
2316
2317 BOOL
2318 ScmLockDatabaseExclusive(VOID)
2319 {
2320 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE);
2321 }
2322
2323
2324 BOOL
2325 ScmLockDatabaseShared(VOID)
2326 {
2327 return RtlAcquireResourceShared(&DatabaseLock, TRUE);
2328 }
2329
2330
2331 VOID
2332 ScmUnlockDatabase(VOID)
2333 {
2334 RtlReleaseResource(&DatabaseLock);
2335 }
2336
2337
2338 VOID
2339 ScmInitNamedPipeCriticalSection(VOID)
2340 {
2341 HKEY hKey;
2342 DWORD dwKeySize;
2343 DWORD dwError;
2344
2345 InitializeCriticalSection(&ControlServiceCriticalSection);
2346
2347 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2348 L"SYSTEM\\CurrentControlSet\\Control",
2349 0,
2350 KEY_READ,
2351 &hKey);
2352 if (dwError == ERROR_SUCCESS)
2353 {
2354 dwKeySize = sizeof(PipeTimeout);
2355 RegQueryValueExW(hKey,
2356 L"ServicesPipeTimeout",
2357 0,
2358 NULL,
2359 (LPBYTE)&PipeTimeout,
2360 &dwKeySize);
2361 RegCloseKey(hKey);
2362 }
2363 }
2364
2365
2366 VOID
2367 ScmDeleteNamedPipeCriticalSection(VOID)
2368 {
2369 DeleteCriticalSection(&ControlServiceCriticalSection);
2370 }
2371
2372 /* EOF */