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