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