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