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