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