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