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