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