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