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