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