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