[ROSTESTS]: advapi32_apitest: Add a test to extensively test services command-line...
[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 DWORD dwError = ERROR_SUCCESS;
1220 PSCM_CONTROL_PACKET ControlPacket;
1221 SCM_REPLY_PACKET ReplyPacket;
1222 DWORD PacketSize;
1223 DWORD i;
1224 PWSTR Ptr;
1225 PWSTR *pOffPtr;
1226 PWSTR pArgPtr;
1227 BOOL bResult;
1228 DWORD dwWriteCount = 0;
1229 DWORD dwReadCount = 0;
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 PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
1239
1240 /*
1241 * Calculate the required packet size for the start argument vector 'argv',
1242 * composed of the list of pointer offsets, followed by UNICODE strings.
1243 * The strings are stored continuously after the vector of offsets, with
1244 * the offsets being relative to the beginning of the vector, as in the
1245 * following layout (with N == argc):
1246 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1247 */
1248 if (argc > 0 && argv != NULL)
1249 {
1250 PacketSize = ALIGN_UP(PacketSize, PWSTR);
1251 PacketSize += (argc * sizeof(PWSTR));
1252
1253 DPRINT("Argc: %lu\n", argc);
1254 for (i = 0; i < argc; i++)
1255 {
1256 DPRINT("Argv[%lu]: %S\n", i, argv[i]);
1257 PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR));
1258 }
1259 }
1260
1261 /* Allocate a control packet */
1262 ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PacketSize);
1263 if (ControlPacket == NULL)
1264 return ERROR_NOT_ENOUGH_MEMORY;
1265
1266 ControlPacket->dwSize = PacketSize;
1267 ControlPacket->dwControl = (Service->Status.dwServiceType & SERVICE_WIN32_OWN_PROCESS)
1268 ? SERVICE_CONTROL_START_OWN
1269 : SERVICE_CONTROL_START_SHARE;
1270 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
1271
1272 /* Copy the start command line */
1273 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
1274 Ptr = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset);
1275 wcscpy(Ptr, Service->lpServiceName);
1276
1277 ControlPacket->dwArgumentsCount = 0;
1278 ControlPacket->dwArgumentsOffset = 0;
1279
1280 /* Copy the argument vector */
1281 if (argc > 0 && argv != NULL)
1282 {
1283 Ptr += wcslen(Service->lpServiceName) + 1;
1284 pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR);
1285 pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
1286
1287 ControlPacket->dwArgumentsCount = argc;
1288 ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
1289
1290 DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount);
1291 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset);
1292
1293 for (i = 0; i < argc; i++)
1294 {
1295 wcscpy(pArgPtr, argv[i]);
1296 pOffPtr[i] = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
1297 DPRINT("offset[%lu]: %p\n", i, pOffPtr[i]);
1298 pArgPtr += wcslen(argv[i]) + 1;
1299 }
1300 }
1301
1302 #ifdef USE_ASYNCHRONOUS_IO
1303 bResult = WriteFile(Service->lpImage->hControlPipe,
1304 ControlPacket,
1305 PacketSize,
1306 &dwWriteCount,
1307 &Overlapped);
1308 if (bResult == FALSE)
1309 {
1310 DPRINT("WriteFile() returned FALSE\n");
1311
1312 dwError = GetLastError();
1313 if (dwError == ERROR_IO_PENDING)
1314 {
1315 DPRINT("dwError: ERROR_IO_PENDING\n");
1316
1317 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1318 PipeTimeout);
1319 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1320
1321 if (dwError == WAIT_TIMEOUT)
1322 {
1323 bResult = CancelIo(Service->lpImage->hControlPipe);
1324 if (bResult == FALSE)
1325 {
1326 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1327 }
1328
1329 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1330 goto Done;
1331 }
1332 else if (dwError == WAIT_OBJECT_0)
1333 {
1334 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1335 &Overlapped,
1336 &dwWriteCount,
1337 TRUE);
1338 if (bResult == FALSE)
1339 {
1340 dwError = GetLastError();
1341 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1342
1343 goto Done;
1344 }
1345 }
1346 }
1347 else
1348 {
1349 DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
1350 goto Done;
1351 }
1352 }
1353
1354 /* Read the reply */
1355 Overlapped.hEvent = (HANDLE) NULL;
1356
1357 bResult = ReadFile(Service->lpImage->hControlPipe,
1358 &ReplyPacket,
1359 sizeof(SCM_REPLY_PACKET),
1360 &dwReadCount,
1361 &Overlapped);
1362 if (bResult == FALSE)
1363 {
1364 DPRINT("ReadFile() returned FALSE\n");
1365
1366 dwError = GetLastError();
1367 if (dwError == ERROR_IO_PENDING)
1368 {
1369 DPRINT("dwError: ERROR_IO_PENDING\n");
1370
1371 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1372 PipeTimeout);
1373 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1374
1375 if (dwError == WAIT_TIMEOUT)
1376 {
1377 bResult = CancelIo(Service->lpImage->hControlPipe);
1378 if (bResult == FALSE)
1379 {
1380 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1381 }
1382
1383 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1384 goto Done;
1385 }
1386 else if (dwError == WAIT_OBJECT_0)
1387 {
1388 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1389 &Overlapped,
1390 &dwReadCount,
1391 TRUE);
1392 if (bResult == FALSE)
1393 {
1394 dwError = GetLastError();
1395 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1396
1397 goto Done;
1398 }
1399 }
1400 }
1401 else
1402 {
1403 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1404 goto Done;
1405 }
1406 }
1407
1408 #else
1409 /* Send the start command */
1410 bResult = WriteFile(Service->lpImage->hControlPipe,
1411 ControlPacket,
1412 PacketSize,
1413 &dwWriteCount,
1414 NULL);
1415 if (bResult == FALSE)
1416 {
1417 dwError = GetLastError();
1418 DPRINT("WriteFile() failed (Error %lu)\n", dwError);
1419 goto Done;
1420 }
1421
1422 /* Read the reply */
1423 bResult = ReadFile(Service->lpImage->hControlPipe,
1424 &ReplyPacket,
1425 sizeof(SCM_REPLY_PACKET),
1426 &dwReadCount,
1427 NULL);
1428 if (bResult == FALSE)
1429 {
1430 dwError = GetLastError();
1431 DPRINT("ReadFile() failed (Error %lu)\n", dwError);
1432 }
1433 #endif
1434
1435 Done:
1436 /* Release the control packet */
1437 HeapFree(GetProcessHeap(),
1438 0,
1439 ControlPacket);
1440
1441 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
1442 {
1443 dwError = ReplyPacket.dwError;
1444 }
1445
1446 DPRINT("ScmSendStartCommand() done\n");
1447
1448 return dwError;
1449 }
1450
1451
1452 static DWORD
1453 ScmWaitForServiceConnect(PSERVICE Service)
1454 {
1455 DWORD dwRead = 0;
1456 DWORD dwProcessId = 0;
1457 DWORD dwError = ERROR_SUCCESS;
1458 BOOL bResult;
1459 #ifdef USE_ASYNCHRONOUS_IO
1460 OVERLAPPED Overlapped = {0};
1461 #endif
1462 #if 0
1463 LPCWSTR lpLogStrings[3];
1464 WCHAR szBuffer1[20];
1465 WCHAR szBuffer2[20];
1466 #endif
1467
1468 DPRINT("ScmWaitForServiceConnect()\n");
1469
1470 #ifdef USE_ASYNCHRONOUS_IO
1471 Overlapped.hEvent = (HANDLE)NULL;
1472
1473 bResult = ConnectNamedPipe(Service->lpImage->hControlPipe,
1474 &Overlapped);
1475 if (bResult == FALSE)
1476 {
1477 DPRINT("ConnectNamedPipe() returned FALSE\n");
1478
1479 dwError = GetLastError();
1480 if (dwError == ERROR_IO_PENDING)
1481 {
1482 DPRINT("dwError: ERROR_IO_PENDING\n");
1483
1484 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1485 PipeTimeout);
1486 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1487
1488 if (dwError == WAIT_TIMEOUT)
1489 {
1490 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1491
1492 bResult = CancelIo(Service->lpImage->hControlPipe);
1493 if (bResult == FALSE)
1494 {
1495 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1496 }
1497
1498 #if 0
1499 _ultow(PipeTimeout, szBuffer1, 10);
1500 lpLogStrings[0] = Service->lpDisplayName;
1501 lpLogStrings[1] = szBuffer1;
1502
1503 ScmLogEvent(EVENT_CONNECTION_TIMEOUT,
1504 EVENTLOG_ERROR_TYPE,
1505 2,
1506 lpLogStrings);
1507 #endif
1508 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service->lpDisplayName);
1509
1510 return ERROR_SERVICE_REQUEST_TIMEOUT;
1511 }
1512 else if (dwError == WAIT_OBJECT_0)
1513 {
1514 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1515 &Overlapped,
1516 &dwRead,
1517 TRUE);
1518 if (bResult == FALSE)
1519 {
1520 dwError = GetLastError();
1521 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError);
1522
1523 return dwError;
1524 }
1525 }
1526 }
1527 else if (dwError != ERROR_PIPE_CONNECTED)
1528 {
1529 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError);
1530 return dwError;
1531 }
1532 }
1533
1534 DPRINT("Control pipe connected!\n");
1535
1536 Overlapped.hEvent = (HANDLE) NULL;
1537
1538 /* Read the process id from pipe */
1539 bResult = ReadFile(Service->lpImage->hControlPipe,
1540 (LPVOID)&dwProcessId,
1541 sizeof(DWORD),
1542 &dwRead,
1543 &Overlapped);
1544 if (bResult == FALSE)
1545 {
1546 DPRINT("ReadFile() returned FALSE\n");
1547
1548 dwError = GetLastError();
1549 if (dwError == ERROR_IO_PENDING)
1550 {
1551 DPRINT("dwError: ERROR_IO_PENDING\n");
1552
1553 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1554 PipeTimeout);
1555 if (dwError == WAIT_TIMEOUT)
1556 {
1557 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1558
1559 bResult = CancelIo(Service->lpImage->hControlPipe);
1560 if (bResult == FALSE)
1561 {
1562 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1563 }
1564
1565 #if 0
1566 _ultow(PipeTimeout, szBuffer1, 10);
1567 lpLogStrings[0] = szBuffer1;
1568
1569 ScmLogEvent(EVENT_READFILE_TIMEOUT,
1570 EVENTLOG_ERROR_TYPE,
1571 1,
1572 lpLogStrings);
1573 #endif
1574 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service->lpDisplayName);
1575
1576 return ERROR_SERVICE_REQUEST_TIMEOUT;
1577 }
1578 else if (dwError == WAIT_OBJECT_0)
1579 {
1580 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1581
1582 DPRINT("Process Id: %lu\n", dwProcessId);
1583
1584 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1585 &Overlapped,
1586 &dwRead,
1587 TRUE);
1588 if (bResult == FALSE)
1589 {
1590 dwError = GetLastError();
1591 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1592
1593 return dwError;
1594 }
1595 }
1596 else
1597 {
1598 DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
1599 }
1600 }
1601 else
1602 {
1603 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1604 return dwError;
1605 }
1606 }
1607
1608 if (dwProcessId != Service->lpImage->dwProcessId)
1609 {
1610 #if 0
1611 _ultow(Service->lpImage->dwProcessId, szBuffer1, 10);
1612 _ultow(dwProcessId, szBuffer2, 10);
1613
1614 lpLogStrings[0] = Service->lpDisplayName;
1615 lpLogStrings[1] = szBuffer1;
1616 lpLogStrings[2] = szBuffer2;
1617
1618 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED,
1619 EVENTLOG_WARNING_TYPE,
1620 3,
1621 lpLogStrings);
1622 #endif
1623
1624 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service->lpDisplayName);
1625 }
1626
1627 DPRINT("ScmWaitForServiceConnect() done\n");
1628
1629 return ERROR_SUCCESS;
1630 #else
1631
1632 /* Connect control pipe */
1633 if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ?
1634 TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
1635 {
1636 DPRINT("Control pipe connected!\n");
1637
1638 /* Read SERVICE_STATUS_HANDLE from pipe */
1639 bResult = ReadFile(Service->lpImage->hControlPipe,
1640 (LPVOID)&dwProcessId,
1641 sizeof(DWORD),
1642 &dwRead,
1643 NULL);
1644 if (bResult == FALSE)
1645 {
1646 dwError = GetLastError();
1647 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1648 dwError);
1649 }
1650 else
1651 {
1652 dwError = ERROR_SUCCESS;
1653 DPRINT("Read control pipe successfully\n");
1654 }
1655 }
1656 else
1657 {
1658 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
1659 }
1660
1661 return dwError;
1662 #endif
1663 }
1664
1665
1666 static DWORD
1667 ScmStartUserModeService(PSERVICE Service,
1668 DWORD argc,
1669 LPWSTR* argv)
1670 {
1671 PROCESS_INFORMATION ProcessInformation;
1672 STARTUPINFOW StartupInfo;
1673 BOOL Result;
1674 DWORD dwError = ERROR_SUCCESS;
1675
1676 DPRINT("ScmStartUserModeService(%p)\n", Service);
1677
1678 /* If the image is already running ... */
1679 if (Service->lpImage->dwImageRunCount > 1)
1680 {
1681 /* ... just send a start command */
1682 return ScmSendStartCommand(Service, argc, argv);
1683 }
1684
1685 /* Otherwise start its process */
1686 ZeroMemory(&StartupInfo, sizeof(StartupInfo));
1687 StartupInfo.cb = sizeof(StartupInfo);
1688 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
1689
1690 Result = CreateProcessAsUserW(Service->lpImage->hToken,
1691 NULL,
1692 Service->lpImage->pszImagePath,
1693 NULL,
1694 NULL,
1695 FALSE,
1696 DETACHED_PROCESS | CREATE_SUSPENDED,
1697 NULL,
1698 NULL,
1699 &StartupInfo,
1700 &ProcessInformation);
1701 if (!Result)
1702 {
1703 dwError = GetLastError();
1704 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
1705 return dwError;
1706 }
1707
1708 DPRINT("Process Id: %lu Handle %p\n",
1709 ProcessInformation.dwProcessId,
1710 ProcessInformation.hProcess);
1711 DPRINT("Thread Id: %lu Handle %p\n",
1712 ProcessInformation.dwThreadId,
1713 ProcessInformation.hThread);
1714
1715 /* Get process handle and id */
1716 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
1717
1718 /* Resume Thread */
1719 ResumeThread(ProcessInformation.hThread);
1720
1721 /* Connect control pipe */
1722 dwError = ScmWaitForServiceConnect(Service);
1723 if (dwError == ERROR_SUCCESS)
1724 {
1725 /* Send start command */
1726 dwError = ScmSendStartCommand(Service, argc, argv);
1727 }
1728 else
1729 {
1730 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
1731 Service->lpImage->dwProcessId = 0;
1732 }
1733
1734 /* Close thread and process handle */
1735 CloseHandle(ProcessInformation.hThread);
1736 CloseHandle(ProcessInformation.hProcess);
1737
1738 return dwError;
1739 }
1740
1741
1742 static DWORD
1743 ScmLoadService(PSERVICE Service,
1744 DWORD argc,
1745 LPWSTR* argv)
1746 {
1747 PSERVICE_GROUP Group = Service->lpGroup;
1748 DWORD dwError = ERROR_SUCCESS;
1749 LPCWSTR lpLogStrings[2];
1750 WCHAR szLogBuffer[80];
1751
1752 DPRINT("ScmLoadService() called\n");
1753 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
1754
1755 if (Service->Status.dwCurrentState != SERVICE_STOPPED)
1756 {
1757 DPRINT("Service %S is already running!\n", Service->lpServiceName);
1758 return ERROR_SERVICE_ALREADY_RUNNING;
1759 }
1760
1761 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
1762
1763 if (Service->Status.dwServiceType & SERVICE_DRIVER)
1764 {
1765 /* Load driver */
1766 dwError = ScmLoadDriver(Service);
1767 if (dwError == ERROR_SUCCESS)
1768 {
1769 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
1770 Service->Status.dwCurrentState = SERVICE_RUNNING;
1771 }
1772 }
1773 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1774 {
1775 /* Start user-mode service */
1776 dwError = ScmCreateOrReferenceServiceImage(Service);
1777 if (dwError == ERROR_SUCCESS)
1778 {
1779 dwError = ScmStartUserModeService(Service, argc, argv);
1780 if (dwError == ERROR_SUCCESS)
1781 {
1782 #ifdef USE_SERVICE_START_PENDING
1783 Service->Status.dwCurrentState = SERVICE_START_PENDING;
1784 #else
1785 Service->Status.dwCurrentState = SERVICE_RUNNING;
1786 #endif
1787 }
1788 else
1789 {
1790 ScmDereferenceServiceImage(Service->lpImage);
1791 Service->lpImage = NULL;
1792 }
1793 }
1794 }
1795
1796 DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
1797
1798 if (dwError == ERROR_SUCCESS)
1799 {
1800 if (Group != NULL)
1801 {
1802 Group->ServicesRunning = TRUE;
1803 }
1804
1805 /* Log a successful service start */
1806 LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_START, szLogBuffer, 80);
1807 lpLogStrings[0] = Service->lpDisplayName;
1808 lpLogStrings[1] = szLogBuffer;
1809
1810 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
1811 EVENTLOG_INFORMATION_TYPE,
1812 2,
1813 lpLogStrings);
1814 }
1815 else
1816 {
1817 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
1818 {
1819 /* Log a failed service start */
1820 swprintf(szLogBuffer, L"%lu", dwError);
1821 lpLogStrings[0] = Service->lpServiceName;
1822 lpLogStrings[1] = szLogBuffer;
1823 ScmLogEvent(EVENT_SERVICE_START_FAILED,
1824 EVENTLOG_ERROR_TYPE,
1825 2,
1826 lpLogStrings);
1827 }
1828
1829 #if 0
1830 switch (Service->dwErrorControl)
1831 {
1832 case SERVICE_ERROR_SEVERE:
1833 if (IsLastKnownGood == FALSE)
1834 {
1835 /* FIXME: Boot last known good configuration */
1836 }
1837 break;
1838
1839 case SERVICE_ERROR_CRITICAL:
1840 if (IsLastKnownGood == FALSE)
1841 {
1842 /* FIXME: Boot last known good configuration */
1843 }
1844 else
1845 {
1846 /* FIXME: BSOD! */
1847 }
1848 break;
1849 }
1850 #endif
1851 }
1852
1853 return dwError;
1854 }
1855
1856
1857 DWORD
1858 ScmStartService(PSERVICE Service,
1859 DWORD argc,
1860 LPWSTR* argv)
1861 {
1862 DWORD dwError = ERROR_SUCCESS;
1863 SC_RPC_LOCK Lock = NULL;
1864
1865 DPRINT("ScmStartService() called\n");
1866 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
1867
1868 /* Acquire the service control critical section, to synchronize starts */
1869 EnterCriticalSection(&ControlServiceCriticalSection);
1870
1871 /*
1872 * Acquire the user service start lock while the service is starting, if
1873 * needed (i.e. if we are not starting it during the initialization phase).
1874 * If we don't success, bail out.
1875 */
1876 if (!ScmInitialize)
1877 {
1878 dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
1879 if (dwError != ERROR_SUCCESS) goto done;
1880 }
1881
1882 /* Really start the service */
1883 dwError = ScmLoadService(Service, argc, argv);
1884
1885 /* Release the service start lock, if needed, and the critical section */
1886 if (Lock) ScmReleaseServiceStartLock(&Lock);
1887
1888 done:
1889 LeaveCriticalSection(&ControlServiceCriticalSection);
1890
1891 DPRINT("ScmStartService() done (Error %lu)\n", dwError);
1892
1893 return dwError;
1894 }
1895
1896
1897 VOID
1898 ScmAutoStartServices(VOID)
1899 {
1900 DWORD dwError;
1901 PLIST_ENTRY GroupEntry;
1902 PLIST_ENTRY ServiceEntry;
1903 PSERVICE_GROUP CurrentGroup;
1904 PSERVICE CurrentService;
1905 WCHAR szSafeBootServicePath[MAX_PATH];
1906 DWORD SafeBootEnabled;
1907 HKEY hKey;
1908 DWORD dwKeySize;
1909 ULONG i;
1910
1911 /*
1912 * This function MUST be called ONLY at initialization time.
1913 * Therefore, no need to acquire the user service start lock.
1914 */
1915 ASSERT(ScmInitialize);
1916
1917 /*
1918 * Retrieve the SafeBoot parameter.
1919 */
1920 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1921 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
1922 0,
1923 KEY_READ,
1924 &hKey);
1925 if (dwError == ERROR_SUCCESS)
1926 {
1927 dwKeySize = sizeof(SafeBootEnabled);
1928 dwError = RegQueryValueExW(hKey,
1929 L"OptionValue",
1930 0,
1931 NULL,
1932 (LPBYTE)&SafeBootEnabled,
1933 &dwKeySize);
1934 RegCloseKey(hKey);
1935 }
1936
1937 /* Default to Normal boot if the value doesn't exist */
1938 if (dwError != ERROR_SUCCESS)
1939 SafeBootEnabled = 0;
1940
1941 /* Acquire the service control critical section, to synchronize starts */
1942 EnterCriticalSection(&ControlServiceCriticalSection);
1943
1944 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1945 ServiceEntry = ServiceListHead.Flink;
1946 while (ServiceEntry != &ServiceListHead)
1947 {
1948 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1949
1950 /* Build the safe boot path */
1951 wcscpy(szSafeBootServicePath,
1952 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1953
1954 switch (SafeBootEnabled)
1955 {
1956 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1957 case 1:
1958 case 3:
1959 wcscat(szSafeBootServicePath, L"\\Minimal\\");
1960 break;
1961
1962 case 2:
1963 wcscat(szSafeBootServicePath, L"\\Network\\");
1964 break;
1965 }
1966
1967 if (SafeBootEnabled != 0)
1968 {
1969 /* If key does not exist then do not assume safe mode */
1970 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1971 szSafeBootServicePath,
1972 0,
1973 KEY_READ,
1974 &hKey);
1975 if (dwError == ERROR_SUCCESS)
1976 {
1977 RegCloseKey(hKey);
1978
1979 /* Finish Safe Boot path off */
1980 wcsncat(szSafeBootServicePath,
1981 CurrentService->lpServiceName,
1982 MAX_PATH - wcslen(szSafeBootServicePath));
1983
1984 /* Check that the key is in the Safe Boot path */
1985 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1986 szSafeBootServicePath,
1987 0,
1988 KEY_READ,
1989 &hKey);
1990 if (dwError != ERROR_SUCCESS)
1991 {
1992 /* Mark service as visited so it is not auto-started */
1993 CurrentService->ServiceVisited = TRUE;
1994 }
1995 else
1996 {
1997 /* Must be auto-started in safe mode - mark as unvisited */
1998 RegCloseKey(hKey);
1999 CurrentService->ServiceVisited = FALSE;
2000 }
2001 }
2002 else
2003 {
2004 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2005 CurrentService->ServiceVisited = FALSE;
2006 }
2007 }
2008
2009 ServiceEntry = ServiceEntry->Flink;
2010 }
2011
2012 /* Start all services which are members of an existing group */
2013 GroupEntry = GroupListHead.Flink;
2014 while (GroupEntry != &GroupListHead)
2015 {
2016 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
2017
2018 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
2019
2020 /* Start all services witch have a valid tag */
2021 for (i = 0; i < CurrentGroup->TagCount; i++)
2022 {
2023 ServiceEntry = ServiceListHead.Flink;
2024 while (ServiceEntry != &ServiceListHead)
2025 {
2026 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2027
2028 if ((CurrentService->lpGroup == CurrentGroup) &&
2029 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2030 (CurrentService->ServiceVisited == FALSE) &&
2031 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
2032 {
2033 CurrentService->ServiceVisited = TRUE;
2034 ScmLoadService(CurrentService, 0, NULL);
2035 }
2036
2037 ServiceEntry = ServiceEntry->Flink;
2038 }
2039 }
2040
2041 /* Start all services which have an invalid tag or which do not have a tag */
2042 ServiceEntry = ServiceListHead.Flink;
2043 while (ServiceEntry != &ServiceListHead)
2044 {
2045 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2046
2047 if ((CurrentService->lpGroup == CurrentGroup) &&
2048 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2049 (CurrentService->ServiceVisited == FALSE))
2050 {
2051 CurrentService->ServiceVisited = TRUE;
2052 ScmLoadService(CurrentService, 0, NULL);
2053 }
2054
2055 ServiceEntry = ServiceEntry->Flink;
2056 }
2057
2058 GroupEntry = GroupEntry->Flink;
2059 }
2060
2061 /* Start all services which are members of any non-existing group */
2062 ServiceEntry = ServiceListHead.Flink;
2063 while (ServiceEntry != &ServiceListHead)
2064 {
2065 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2066
2067 if ((CurrentService->lpGroup != NULL) &&
2068 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2069 (CurrentService->ServiceVisited == FALSE))
2070 {
2071 CurrentService->ServiceVisited = TRUE;
2072 ScmLoadService(CurrentService, 0, NULL);
2073 }
2074
2075 ServiceEntry = ServiceEntry->Flink;
2076 }
2077
2078 /* Start all services which are not a member of any group */
2079 ServiceEntry = ServiceListHead.Flink;
2080 while (ServiceEntry != &ServiceListHead)
2081 {
2082 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2083
2084 if ((CurrentService->lpGroup == NULL) &&
2085 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2086 (CurrentService->ServiceVisited == FALSE))
2087 {
2088 CurrentService->ServiceVisited = TRUE;
2089 ScmLoadService(CurrentService, 0, NULL);
2090 }
2091
2092 ServiceEntry = ServiceEntry->Flink;
2093 }
2094
2095 /* Clear 'ServiceVisited' flag again */
2096 ServiceEntry = ServiceListHead.Flink;
2097 while (ServiceEntry != &ServiceListHead)
2098 {
2099 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2100 CurrentService->ServiceVisited = FALSE;
2101 ServiceEntry = ServiceEntry->Flink;
2102 }
2103
2104 /* Release the critical section */
2105 LeaveCriticalSection(&ControlServiceCriticalSection);
2106 }
2107
2108
2109 VOID
2110 ScmAutoShutdownServices(VOID)
2111 {
2112 PLIST_ENTRY ServiceEntry;
2113 PSERVICE CurrentService;
2114
2115 DPRINT("ScmAutoShutdownServices() called\n");
2116
2117 /* Lock the service database exclusively */
2118 ScmLockDatabaseExclusive();
2119
2120 ServiceEntry = ServiceListHead.Flink;
2121 while (ServiceEntry != &ServiceListHead)
2122 {
2123 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2124
2125 if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
2126 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
2127 {
2128 /* shutdown service */
2129 DPRINT("Shutdown service: %S\n", CurrentService->szServiceName);
2130 ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN);
2131 }
2132
2133 ServiceEntry = ServiceEntry->Flink;
2134 }
2135
2136 /* Unlock the service database */
2137 ScmUnlockDatabase();
2138
2139 DPRINT("ScmAutoShutdownServices() done\n");
2140 }
2141
2142
2143 BOOL
2144 ScmLockDatabaseExclusive(VOID)
2145 {
2146 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE);
2147 }
2148
2149
2150 BOOL
2151 ScmLockDatabaseShared(VOID)
2152 {
2153 return RtlAcquireResourceShared(&DatabaseLock, TRUE);
2154 }
2155
2156
2157 VOID
2158 ScmUnlockDatabase(VOID)
2159 {
2160 RtlReleaseResource(&DatabaseLock);
2161 }
2162
2163
2164 VOID
2165 ScmInitNamedPipeCriticalSection(VOID)
2166 {
2167 HKEY hKey;
2168 DWORD dwKeySize;
2169 DWORD dwError;
2170
2171 InitializeCriticalSection(&ControlServiceCriticalSection);
2172
2173 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2174 L"SYSTEM\\CurrentControlSet\\Control",
2175 0,
2176 KEY_READ,
2177 &hKey);
2178 if (dwError == ERROR_SUCCESS)
2179 {
2180 dwKeySize = sizeof(PipeTimeout);
2181 RegQueryValueExW(hKey,
2182 L"ServicesPipeTimeout",
2183 0,
2184 NULL,
2185 (LPBYTE)&PipeTimeout,
2186 &dwKeySize);
2187 RegCloseKey(hKey);
2188 }
2189 }
2190
2191
2192 VOID
2193 ScmDeleteNamedPipeCriticalSection(VOID)
2194 {
2195 DeleteCriticalSection(&ControlServiceCriticalSection);
2196 }
2197
2198 /* EOF */