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