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