[SERVICES/ADVAPI32]
[reactos.git] / reactos / 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 #define NDEBUG
18 #include <debug.h>
19
20 /*
21 * Uncomment the line below to start services
22 * using the SERVICE_START_PENDING state
23 */
24 // #define USE_SERVICE_START_PENDING
25
26 /* GLOBALS *******************************************************************/
27
28 LIST_ENTRY ImageListHead;
29 LIST_ENTRY ServiceListHead;
30
31 static RTL_RESOURCE DatabaseLock;
32 static DWORD dwResumeCount = 1;
33
34 static CRITICAL_SECTION ControlServiceCriticalSection;
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%u", ServiceCurrent);
91
92 DPRINT("PipeName: %S\n", szControlPipeName);
93
94 pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName,
95 PIPE_ACCESS_DUPLEX,
96 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
97 100,
98 8000,
99 4,
100 30000,
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->szImagePath, lpImagePath) == 0)
128 {
129 DPRINT("Found image: '%S'\n", CurrentImage->szImagePath);
130 return CurrentImage;
131 }
132
133 ImageEntry = ImageEntry->Flink;
134 }
135
136 DPRINT1("Couldn't find a matching image\n");
137
138 return NULL;
139
140 }
141
142
143 static DWORD
144 ScmCreateOrReferenceServiceImage(PSERVICE pService)
145 {
146 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
147 UNICODE_STRING ImagePath;
148 PSERVICE_IMAGE pServiceImage = NULL;
149 NTSTATUS Status;
150 DWORD dwError = ERROR_SUCCESS;
151
152 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService);
153
154 RtlInitUnicodeString(&ImagePath, NULL);
155
156 /* Get service data */
157 RtlZeroMemory(&QueryTable,
158 sizeof(QueryTable));
159
160 QueryTable[0].Name = L"ImagePath";
161 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
162 QueryTable[0].EntryContext = &ImagePath;
163
164 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
165 pService->lpServiceName,
166 QueryTable,
167 NULL,
168 NULL);
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
172 return RtlNtStatusToDosError(Status);
173 }
174
175 DPRINT("ImagePath: '%wZ'\n", &ImagePath);
176
177 pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer);
178 if (pServiceImage == NULL)
179 {
180 /* Create a new service image */
181 pServiceImage = (PSERVICE_IMAGE)HeapAlloc(GetProcessHeap(),
182 HEAP_ZERO_MEMORY,
183 sizeof(SERVICE_IMAGE) + ((wcslen(ImagePath.Buffer) + 1) * sizeof(WCHAR)));
184 if (pServiceImage == NULL)
185 {
186 dwError = ERROR_NOT_ENOUGH_MEMORY;
187 goto done;
188 }
189
190 pServiceImage->dwImageRunCount = 1;
191 pServiceImage->hControlPipe = INVALID_HANDLE_VALUE;
192 pServiceImage->hProcess = INVALID_HANDLE_VALUE;
193
194 /* Set the image path */
195 wcscpy(pServiceImage->szImagePath,
196 ImagePath.Buffer);
197
198 RtlFreeUnicodeString(&ImagePath);
199
200 /* Create the control pipe */
201 dwError = ScmCreateNewControlPipe(pServiceImage);
202 if (dwError != ERROR_SUCCESS)
203 {
204 HeapFree(GetProcessHeap(), 0, pServiceImage);
205 goto done;
206 }
207
208 /* FIXME: Add more initialization code here */
209
210
211 /* Append service record */
212 InsertTailList(&ImageListHead,
213 &pServiceImage->ImageListEntry);
214 }
215 else
216 {
217 /* Increment the run counter */
218 pServiceImage->dwImageRunCount++;
219 }
220
221 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount);
222
223 /* Link the service image to the service */
224 pService->lpImage = pServiceImage;
225
226 done:;
227 RtlFreeUnicodeString(&ImagePath);
228
229 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError);
230
231 return dwError;
232 }
233
234
235 static VOID
236 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage)
237 {
238 DPRINT1("ScmDereferenceServiceImage() called\n");
239
240 pServiceImage->dwImageRunCount--;
241
242 if (pServiceImage->dwImageRunCount == 0)
243 {
244 DPRINT1("dwImageRunCount == 0\n");
245
246 /* FIXME: Terminate the process */
247
248 /* Remove the service image from the list */
249 RemoveEntryList(&pServiceImage->ImageListEntry);
250
251 /* Close the control pipe */
252 if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE)
253 CloseHandle(pServiceImage->hControlPipe);
254
255 /* Close the process handle */
256 if (pServiceImage->hProcess != INVALID_HANDLE_VALUE)
257 CloseHandle(pServiceImage->hProcess);
258
259 /* Release the service image */
260 HeapFree(GetProcessHeap(), 0, pServiceImage);
261 }
262 }
263
264
265 PSERVICE
266 ScmGetServiceEntryByName(LPCWSTR lpServiceName)
267 {
268 PLIST_ENTRY ServiceEntry;
269 PSERVICE CurrentService;
270
271 DPRINT("ScmGetServiceEntryByName() called\n");
272
273 ServiceEntry = ServiceListHead.Flink;
274 while (ServiceEntry != &ServiceListHead)
275 {
276 CurrentService = CONTAINING_RECORD(ServiceEntry,
277 SERVICE,
278 ServiceListEntry);
279 if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0)
280 {
281 DPRINT("Found service: '%S'\n", CurrentService->lpServiceName);
282 return CurrentService;
283 }
284
285 ServiceEntry = ServiceEntry->Flink;
286 }
287
288 DPRINT("Couldn't find a matching service\n");
289
290 return NULL;
291 }
292
293
294 PSERVICE
295 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName)
296 {
297 PLIST_ENTRY ServiceEntry;
298 PSERVICE CurrentService;
299
300 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
301
302 ServiceEntry = ServiceListHead.Flink;
303 while (ServiceEntry != &ServiceListHead)
304 {
305 CurrentService = CONTAINING_RECORD(ServiceEntry,
306 SERVICE,
307 ServiceListEntry);
308 if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0)
309 {
310 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
311 return CurrentService;
312 }
313
314 ServiceEntry = ServiceEntry->Flink;
315 }
316
317 DPRINT("Couldn't find a matching service\n");
318
319 return NULL;
320 }
321
322
323 PSERVICE
324 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
325 {
326 PLIST_ENTRY ServiceEntry;
327 PSERVICE CurrentService;
328
329 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
330
331 ServiceEntry = ServiceListHead.Flink;
332 while (ServiceEntry != &ServiceListHead)
333 {
334 CurrentService = CONTAINING_RECORD(ServiceEntry,
335 SERVICE,
336 ServiceListEntry);
337 if (CurrentService->dwResumeCount > dwResumeCount)
338 {
339 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
340 return CurrentService;
341 }
342
343 ServiceEntry = ServiceEntry->Flink;
344 }
345
346 DPRINT("Couldn't find a matching service\n");
347
348 return NULL;
349 }
350
351
352 DWORD
353 ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
354 PSERVICE *lpServiceRecord)
355 {
356 PSERVICE lpService = NULL;
357
358 DPRINT("Service: '%S'\n", lpServiceName);
359
360 /* Allocate service entry */
361 lpService = (SERVICE*)HeapAlloc(GetProcessHeap(),
362 HEAP_ZERO_MEMORY,
363 sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR)));
364 if (lpService == NULL)
365 return ERROR_NOT_ENOUGH_MEMORY;
366
367 *lpServiceRecord = lpService;
368
369 /* Copy service name */
370 wcscpy(lpService->szServiceName, lpServiceName);
371 lpService->lpServiceName = lpService->szServiceName;
372 lpService->lpDisplayName = lpService->lpServiceName;
373
374 /* Set the resume count */
375 lpService->dwResumeCount = dwResumeCount++;
376
377 /* Append service record */
378 InsertTailList(&ServiceListHead,
379 &lpService->ServiceListEntry);
380
381 /* Initialize the service status */
382 lpService->Status.dwCurrentState = SERVICE_STOPPED;
383 lpService->Status.dwControlsAccepted = 0;
384 lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
385 lpService->Status.dwServiceSpecificExitCode = 0;
386 lpService->Status.dwCheckPoint = 0;
387 lpService->Status.dwWaitHint = 2000; /* 2 seconds */
388
389 return ERROR_SUCCESS;
390 }
391
392
393 VOID
394 ScmDeleteServiceRecord(PSERVICE lpService)
395 {
396 DPRINT("Deleting Service %S\n", lpService->lpServiceName);
397
398 /* Delete the display name */
399 if (lpService->lpDisplayName != NULL &&
400 lpService->lpDisplayName != lpService->lpServiceName)
401 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
402
403 /* Dereference the service image */
404 if (lpService->lpImage)
405 ScmDereferenceServiceImage(lpService->lpImage);
406
407 /* Decrement the group reference counter */
408 if (lpService->lpGroup)
409 lpService->lpGroup->dwRefCount--;
410
411 /* FIXME: SecurityDescriptor */
412
413
414 /* Remove the Service from the List */
415 RemoveEntryList(&lpService->ServiceListEntry);
416
417 DPRINT("Deleted Service %S\n", lpService->lpServiceName);
418
419 /* Delete the service record */
420 HeapFree(GetProcessHeap(), 0, lpService);
421
422 DPRINT("Done\n");
423 }
424
425
426 static DWORD
427 CreateServiceListEntry(LPCWSTR lpServiceName,
428 HKEY hServiceKey)
429 {
430 PSERVICE lpService = NULL;
431 LPWSTR lpDisplayName = NULL;
432 LPWSTR lpGroup = NULL;
433 DWORD dwSize;
434 DWORD dwError;
435 DWORD dwServiceType;
436 DWORD dwStartType;
437 DWORD dwErrorControl;
438 DWORD dwTagId;
439
440 DPRINT("Service: '%S'\n", lpServiceName);
441 if (*lpServiceName == L'{')
442 return ERROR_SUCCESS;
443
444 dwSize = sizeof(DWORD);
445 dwError = RegQueryValueExW(hServiceKey,
446 L"Type",
447 NULL,
448 NULL,
449 (LPBYTE)&dwServiceType,
450 &dwSize);
451 if (dwError != ERROR_SUCCESS)
452 return ERROR_SUCCESS;
453
454 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
455 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) &&
456 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
457 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
458 return ERROR_SUCCESS;
459
460 DPRINT("Service type: %lx\n", dwServiceType);
461
462 dwSize = sizeof(DWORD);
463 dwError = RegQueryValueExW(hServiceKey,
464 L"Start",
465 NULL,
466 NULL,
467 (LPBYTE)&dwStartType,
468 &dwSize);
469 if (dwError != ERROR_SUCCESS)
470 return ERROR_SUCCESS;
471
472 DPRINT("Start type: %lx\n", dwStartType);
473
474 dwSize = sizeof(DWORD);
475 dwError = RegQueryValueExW(hServiceKey,
476 L"ErrorControl",
477 NULL,
478 NULL,
479 (LPBYTE)&dwErrorControl,
480 &dwSize);
481 if (dwError != ERROR_SUCCESS)
482 return ERROR_SUCCESS;
483
484 DPRINT("Error control: %lx\n", dwErrorControl);
485
486 dwError = RegQueryValueExW(hServiceKey,
487 L"Tag",
488 NULL,
489 NULL,
490 (LPBYTE)&dwTagId,
491 &dwSize);
492 if (dwError != ERROR_SUCCESS)
493 dwTagId = 0;
494
495 DPRINT("Tag: %lx\n", dwTagId);
496
497 dwError = ScmReadString(hServiceKey,
498 L"Group",
499 &lpGroup);
500 if (dwError != ERROR_SUCCESS)
501 lpGroup = NULL;
502
503 DPRINT("Group: %S\n", lpGroup);
504
505 dwError = ScmReadString(hServiceKey,
506 L"DisplayName",
507 &lpDisplayName);
508 if (dwError != ERROR_SUCCESS)
509 lpDisplayName = NULL;
510
511 DPRINT("Display name: %S\n", lpDisplayName);
512
513 dwError = ScmCreateNewServiceRecord(lpServiceName,
514 &lpService);
515 if (dwError != ERROR_SUCCESS)
516 goto done;
517
518 lpService->Status.dwServiceType = dwServiceType;
519 lpService->dwStartType = dwStartType;
520 lpService->dwErrorControl = dwErrorControl;
521 lpService->dwTag = dwTagId;
522
523 if (lpGroup != NULL)
524 {
525 dwError = ScmSetServiceGroup(lpService, lpGroup);
526 if (dwError != ERROR_SUCCESS)
527 goto done;
528 }
529
530 if (lpDisplayName != NULL)
531 {
532 lpService->lpDisplayName = lpDisplayName;
533 lpDisplayName = NULL;
534 }
535
536 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
537 if (lpService->lpGroup != NULL)
538 {
539 DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName);
540 }
541 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
542 lpService->dwStartType,
543 lpService->Status.dwServiceType,
544 lpService->dwTag,
545 lpService->dwErrorControl);
546
547 if (ScmIsDeleteFlagSet(hServiceKey))
548 lpService->bDeleted = TRUE;
549
550 done:;
551 if (lpGroup != NULL)
552 HeapFree(GetProcessHeap(), 0, lpGroup);
553
554 if (lpDisplayName != NULL)
555 HeapFree(GetProcessHeap(), 0, lpDisplayName);
556
557 if (lpService != NULL)
558 {
559 if (lpService->lpImage != NULL)
560 ScmDereferenceServiceImage(lpService->lpImage);
561 }
562
563 return dwError;
564 }
565
566
567 DWORD
568 ScmDeleteRegKey(HKEY hKey, LPCWSTR lpszSubKey)
569 {
570 DWORD dwRet, dwMaxSubkeyLen = 0, dwSize;
571 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
572 HKEY hSubKey = 0;
573
574 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
575 if (!dwRet)
576 {
577 /* Find the maximum subkey length so that we can allocate a buffer */
578 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
579 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
580 if (!dwRet)
581 {
582 dwMaxSubkeyLen++;
583 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
584 /* Name too big: alloc a buffer for it */
585 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
586
587 if(!lpszName)
588 dwRet = ERROR_NOT_ENOUGH_MEMORY;
589 else
590 {
591 while (dwRet == ERROR_SUCCESS)
592 {
593 dwSize = dwMaxSubkeyLen;
594 dwRet = RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL);
595 if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA)
596 dwRet = ScmDeleteRegKey(hSubKey, lpszName);
597 }
598 if (dwRet == ERROR_NO_MORE_ITEMS)
599 dwRet = ERROR_SUCCESS;
600
601 if (lpszName != szNameBuf)
602 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
603 }
604 }
605
606 RegCloseKey(hSubKey);
607 if (!dwRet)
608 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
609 }
610 return dwRet;
611 }
612
613
614 VOID
615 ScmDeleteMarkedServices(VOID)
616 {
617 PLIST_ENTRY ServiceEntry;
618 PSERVICE CurrentService;
619 HKEY hServicesKey;
620 DWORD dwError;
621
622 ServiceEntry = ServiceListHead.Flink;
623 while (ServiceEntry != &ServiceListHead)
624 {
625 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
626
627 ServiceEntry = ServiceEntry->Flink;
628
629 if (CurrentService->bDeleted == TRUE)
630 {
631 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
632 L"System\\CurrentControlSet\\Services",
633 0,
634 DELETE,
635 &hServicesKey);
636 if (dwError == ERROR_SUCCESS)
637 {
638 dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName);
639 RegCloseKey(hServicesKey);
640 if (dwError == ERROR_SUCCESS)
641 {
642 RemoveEntryList(&CurrentService->ServiceListEntry);
643 HeapFree(GetProcessHeap(), 0, CurrentService);
644 }
645 }
646
647 if (dwError != ERROR_SUCCESS)
648 DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName);
649 }
650 }
651 }
652
653
654 VOID
655 WaitForLSA(VOID)
656 {
657 HANDLE hEvent;
658 DWORD dwError;
659
660 DPRINT("WaitForLSA() called\n");
661
662 hEvent = CreateEventW(NULL,
663 TRUE,
664 FALSE,
665 L"LSA_RPC_SERVER_ACTIVE");
666 if (hEvent == NULL)
667 {
668 dwError = GetLastError();
669 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError);
670
671 if (dwError == ERROR_ALREADY_EXISTS)
672 {
673 hEvent = OpenEventW(SYNCHRONIZE,
674 FALSE,
675 L"LSA_RPC_SERVER_ACTIVE");
676 if (hEvent != NULL)
677 {
678 DPRINT1("Could not open the notification event!\n");
679 return;
680 }
681 }
682 }
683
684 DPRINT("Wait for LSA!\n");
685 WaitForSingleObject(hEvent, INFINITE);
686 DPRINT("LSA is available!\n");
687
688 CloseHandle(hEvent);
689
690 DPRINT("WaitForLSA() done\n");
691 }
692
693
694 DWORD
695 ScmCreateServiceDatabase(VOID)
696 {
697 WCHAR szSubKey[MAX_PATH];
698 HKEY hServicesKey;
699 HKEY hServiceKey;
700 DWORD dwSubKey;
701 DWORD dwSubKeyLength;
702 FILETIME ftLastChanged;
703 DWORD dwError;
704
705 DPRINT("ScmCreateServiceDatabase() called\n");
706
707 dwError = ScmCreateGroupList();
708 if (dwError != ERROR_SUCCESS)
709 return dwError;
710
711 /* Initialize basic variables */
712 InitializeListHead(&ImageListHead);
713 InitializeListHead(&ServiceListHead);
714
715 /* Initialize the database lock */
716 RtlInitializeResource(&DatabaseLock);
717
718 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
719 L"System\\CurrentControlSet\\Services",
720 0,
721 KEY_READ,
722 &hServicesKey);
723 if (dwError != ERROR_SUCCESS)
724 return dwError;
725
726 dwSubKey = 0;
727 for (;;)
728 {
729 dwSubKeyLength = MAX_PATH;
730 dwError = RegEnumKeyExW(hServicesKey,
731 dwSubKey,
732 szSubKey,
733 &dwSubKeyLength,
734 NULL,
735 NULL,
736 NULL,
737 &ftLastChanged);
738 if (dwError == ERROR_SUCCESS &&
739 szSubKey[0] != L'{')
740 {
741 DPRINT("SubKeyName: '%S'\n", szSubKey);
742
743 dwError = RegOpenKeyExW(hServicesKey,
744 szSubKey,
745 0,
746 KEY_READ,
747 &hServiceKey);
748 if (dwError == ERROR_SUCCESS)
749 {
750 dwError = CreateServiceListEntry(szSubKey,
751 hServiceKey);
752
753 RegCloseKey(hServiceKey);
754 }
755 }
756
757 if (dwError != ERROR_SUCCESS)
758 break;
759
760 dwSubKey++;
761 }
762
763 RegCloseKey(hServicesKey);
764
765 /* Wait for LSA */
766 WaitForLSA();
767
768 /* Delete services that are marked for delete */
769 ScmDeleteMarkedServices();
770
771 DPRINT("ScmCreateServiceDatabase() done\n");
772
773 return ERROR_SUCCESS;
774 }
775
776
777 VOID
778 ScmShutdownServiceDatabase(VOID)
779 {
780 DPRINT("ScmShutdownServiceDatabase() called\n");
781
782 ScmDeleteMarkedServices();
783 RtlDeleteResource(&DatabaseLock);
784
785 DPRINT("ScmShutdownServiceDatabase() done\n");
786 }
787
788
789 static NTSTATUS
790 ScmCheckDriver(PSERVICE Service)
791 {
792 OBJECT_ATTRIBUTES ObjectAttributes;
793 UNICODE_STRING DirName;
794 HANDLE DirHandle;
795 NTSTATUS Status;
796 POBJECT_DIRECTORY_INFORMATION DirInfo;
797 ULONG BufferLength;
798 ULONG DataLength;
799 ULONG Index;
800
801 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
802
803 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
804 {
805 RtlInitUnicodeString(&DirName,
806 L"\\Driver");
807 }
808 else
809 {
810 RtlInitUnicodeString(&DirName,
811 L"\\FileSystem");
812 }
813
814 InitializeObjectAttributes(&ObjectAttributes,
815 &DirName,
816 0,
817 NULL,
818 NULL);
819
820 Status = NtOpenDirectoryObject(&DirHandle,
821 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
822 &ObjectAttributes);
823 if (!NT_SUCCESS(Status))
824 {
825 return Status;
826 }
827
828 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
829 2 * MAX_PATH * sizeof(WCHAR);
830 DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(),
831 HEAP_ZERO_MEMORY,
832 BufferLength);
833
834 Index = 0;
835 while (TRUE)
836 {
837 Status = NtQueryDirectoryObject(DirHandle,
838 DirInfo,
839 BufferLength,
840 TRUE,
841 FALSE,
842 &Index,
843 &DataLength);
844 if (Status == STATUS_NO_MORE_ENTRIES)
845 {
846 /* FIXME: Add current service to 'failed service' list */
847 DPRINT("Service '%S' failed\n", Service->lpServiceName);
848 break;
849 }
850
851 if (!NT_SUCCESS(Status))
852 break;
853
854 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
855
856 if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
857 {
858 DPRINT("Found: '%S' '%wZ'\n",
859 Service->lpServiceName, &DirInfo->Name);
860
861 /* Mark service as 'running' */
862 Service->Status.dwCurrentState = SERVICE_RUNNING;
863
864 /* Mark the service group as 'running' */
865 if (Service->lpGroup != NULL)
866 {
867 Service->lpGroup->ServicesRunning = TRUE;
868 }
869
870 break;
871 }
872 }
873
874 HeapFree(GetProcessHeap(),
875 0,
876 DirInfo);
877 NtClose(DirHandle);
878
879 return STATUS_SUCCESS;
880 }
881
882
883 VOID
884 ScmGetBootAndSystemDriverState(VOID)
885 {
886 PLIST_ENTRY ServiceEntry;
887 PSERVICE CurrentService;
888
889 DPRINT("ScmGetBootAndSystemDriverState() called\n");
890
891 ServiceEntry = ServiceListHead.Flink;
892 while (ServiceEntry != &ServiceListHead)
893 {
894 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
895
896 if (CurrentService->dwStartType == SERVICE_BOOT_START ||
897 CurrentService->dwStartType == SERVICE_SYSTEM_START)
898 {
899 /* Check driver */
900 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
901
902 ScmCheckDriver(CurrentService);
903 }
904
905 ServiceEntry = ServiceEntry->Flink;
906 }
907
908 DPRINT("ScmGetBootAndSystemDriverState() done\n");
909 }
910
911
912 DWORD
913 ScmControlService(PSERVICE Service,
914 DWORD dwControl)
915 {
916 PSCM_CONTROL_PACKET ControlPacket;
917 SCM_REPLY_PACKET ReplyPacket;
918
919 DWORD dwWriteCount = 0;
920 DWORD dwReadCount = 0;
921 DWORD PacketSize;
922 PWSTR Ptr;
923 DWORD dwError = ERROR_SUCCESS;
924
925 DPRINT("ScmControlService() called\n");
926
927 EnterCriticalSection(&ControlServiceCriticalSection);
928
929 /* Calculate the total length of the start command line */
930 PacketSize = sizeof(SCM_CONTROL_PACKET);
931 PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR);
932
933 ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
934 HEAP_ZERO_MEMORY,
935 PacketSize);
936 if (ControlPacket == NULL)
937 {
938 LeaveCriticalSection(&ControlServiceCriticalSection);
939 return ERROR_NOT_ENOUGH_MEMORY;
940 }
941
942 ControlPacket->dwSize = PacketSize;
943 ControlPacket->dwControl = dwControl;
944 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
945
946 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
947
948 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
949 wcscpy(Ptr, Service->lpServiceName);
950
951 ControlPacket->dwArgumentsCount = 0;
952 ControlPacket->dwArgumentsOffset = 0;
953
954 /* Send the control packet */
955 WriteFile(Service->lpImage->hControlPipe,
956 ControlPacket,
957 PacketSize,
958 &dwWriteCount,
959 NULL);
960
961 /* Read the reply */
962 ReadFile(Service->lpImage->hControlPipe,
963 &ReplyPacket,
964 sizeof(SCM_REPLY_PACKET),
965 &dwReadCount,
966 NULL);
967
968 /* Release the contol packet */
969 HeapFree(GetProcessHeap(),
970 0,
971 ControlPacket);
972
973 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
974 {
975 dwError = ReplyPacket.dwError;
976 }
977
978 if (dwError == ERROR_SUCCESS &&
979 dwControl == SERVICE_CONTROL_STOP)
980 {
981 ScmDereferenceServiceImage(Service->lpImage);
982 }
983
984 LeaveCriticalSection(&ControlServiceCriticalSection);
985
986 DPRINT("ScmControlService() done\n");
987
988 return dwError;
989 }
990
991
992 static DWORD
993 ScmSendStartCommand(PSERVICE Service,
994 DWORD argc,
995 LPWSTR *argv)
996 {
997 PSCM_CONTROL_PACKET ControlPacket;
998 SCM_REPLY_PACKET ReplyPacket;
999 DWORD PacketSize;
1000 PWSTR Ptr;
1001 DWORD dwWriteCount = 0;
1002 DWORD dwReadCount = 0;
1003 DWORD dwError = ERROR_SUCCESS;
1004 DWORD i;
1005
1006 DPRINT("ScmSendStartCommand() called\n");
1007
1008 /* Calculate the total length of the start command line */
1009 PacketSize = sizeof(SCM_CONTROL_PACKET);
1010 PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR);
1011
1012 /* Calculate the required packet size for the start arguments */
1013 if (argc > 0 && argv != NULL)
1014 {
1015 PacketSize = ALIGN_UP(PacketSize, LPWSTR);
1016
1017 DPRINT("Argc: %lu\n", argc);
1018 for (i = 0; i < argc; i++)
1019 {
1020 DPRINT("Argv[%lu]: %S\n", i, argv[i]);
1021 PacketSize += (wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR);
1022 }
1023 }
1024
1025 /* Allocate a control packet */
1026 ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
1027 HEAP_ZERO_MEMORY,
1028 PacketSize);
1029 if (ControlPacket == NULL)
1030 return ERROR_NOT_ENOUGH_MEMORY;
1031
1032 ControlPacket->dwSize = PacketSize;
1033 ControlPacket->dwControl = SERVICE_CONTROL_START;
1034 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
1035 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
1036
1037 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
1038 wcscpy(Ptr, Service->lpServiceName);
1039
1040 ControlPacket->dwArgumentsCount = 0;
1041 ControlPacket->dwArgumentsOffset = 0;
1042
1043 /* Copy argument list */
1044 if (argc > 0 && argv != NULL)
1045 {
1046 // Ptr += wcslen(Service->lpServiceName) + 1;
1047 // Ptr = ALIGN_UP_POINTER(Ptr, LPWSTR);
1048
1049 // ControlPacket->dwArgumentsOffset = (DWORD)((INT_PTR)Ptr - (INT_PTR)ControlPacket);
1050
1051
1052 #if 0
1053 memcpy(Ptr, Arguments, ArgsLength);
1054 Ptr += ArgsLength;
1055 #endif
1056 }
1057
1058 /* Send the start command */
1059 WriteFile(Service->lpImage->hControlPipe,
1060 ControlPacket,
1061 PacketSize,
1062 &dwWriteCount,
1063 NULL);
1064
1065 /* Read the reply */
1066 ReadFile(Service->lpImage->hControlPipe,
1067 &ReplyPacket,
1068 sizeof(SCM_REPLY_PACKET),
1069 &dwReadCount,
1070 NULL);
1071
1072 /* Release the contol packet */
1073 HeapFree(GetProcessHeap(),
1074 0,
1075 ControlPacket);
1076
1077 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
1078 {
1079 dwError = ReplyPacket.dwError;
1080 }
1081
1082 DPRINT("ScmSendStartCommand() done\n");
1083
1084 return dwError;
1085 }
1086
1087
1088 static DWORD
1089 ScmStartUserModeService(PSERVICE Service,
1090 DWORD argc,
1091 LPWSTR *argv)
1092 {
1093 PROCESS_INFORMATION ProcessInformation;
1094 STARTUPINFOW StartupInfo;
1095 BOOL Result;
1096 DWORD dwError = ERROR_SUCCESS;
1097 DWORD dwProcessId;
1098
1099 DPRINT("ScmStartUserModeService(%p)\n", Service);
1100
1101 /* If the image is already running ... */
1102 if (Service->lpImage->dwImageRunCount > 1)
1103 {
1104 /* ... just send a start command */
1105 return ScmSendStartCommand(Service, argc, argv);
1106 }
1107
1108 StartupInfo.cb = sizeof(StartupInfo);
1109 StartupInfo.lpReserved = NULL;
1110 StartupInfo.lpDesktop = NULL;
1111 StartupInfo.lpTitle = NULL;
1112 StartupInfo.dwFlags = 0;
1113 StartupInfo.cbReserved2 = 0;
1114 StartupInfo.lpReserved2 = 0;
1115
1116 Result = CreateProcessW(NULL,
1117 Service->lpImage->szImagePath,
1118 NULL,
1119 NULL,
1120 FALSE,
1121 DETACHED_PROCESS | CREATE_SUSPENDED,
1122 NULL,
1123 NULL,
1124 &StartupInfo,
1125 &ProcessInformation);
1126 if (!Result)
1127 {
1128 dwError = GetLastError();
1129 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
1130 return dwError;
1131 }
1132
1133 DPRINT("Process Id: %lu Handle %lx\n",
1134 ProcessInformation.dwProcessId,
1135 ProcessInformation.hProcess);
1136 DPRINT("Thread Id: %lu Handle %lx\n",
1137 ProcessInformation.dwThreadId,
1138 ProcessInformation.hThread);
1139
1140 /* Get process handle and id */
1141 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
1142 Service->lpImage->hProcess = ProcessInformation.hProcess;
1143
1144 /* Resume Thread */
1145 ResumeThread(ProcessInformation.hThread);
1146
1147 /* Connect control pipe */
1148 if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ?
1149 TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
1150 {
1151 DWORD dwRead = 0;
1152
1153 DPRINT("Control pipe connected!\n");
1154
1155 /* Read SERVICE_STATUS_HANDLE from pipe */
1156 if (!ReadFile(Service->lpImage->hControlPipe,
1157 (LPVOID)&dwProcessId,
1158 sizeof(DWORD),
1159 &dwRead,
1160 NULL))
1161 {
1162 dwError = GetLastError();
1163 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1164 dwError);
1165 }
1166 else
1167 {
1168 DPRINT("Received service process ID %lu\n", dwProcessId);
1169
1170 /* Send start command */
1171 dwError = ScmSendStartCommand(Service, argc, argv);
1172 }
1173 }
1174 else
1175 {
1176 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
1177 }
1178
1179 /* Close thread handle */
1180 CloseHandle(ProcessInformation.hThread);
1181
1182 return dwError;
1183 }
1184
1185
1186 DWORD
1187 ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
1188 {
1189 PSERVICE_GROUP Group = Service->lpGroup;
1190 DWORD dwError = ERROR_SUCCESS;
1191 LPCWSTR ErrorLogStrings[2];
1192
1193 DPRINT("ScmStartService() called\n");
1194
1195 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
1196
1197 EnterCriticalSection(&ControlServiceCriticalSection);
1198
1199 if (Service->Status.dwCurrentState != SERVICE_STOPPED)
1200 {
1201 DPRINT("Service %S is already running!\n", Service->lpServiceName);
1202 LeaveCriticalSection(&ControlServiceCriticalSection);
1203 return ERROR_SERVICE_ALREADY_RUNNING;
1204 }
1205
1206 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
1207
1208 if (Service->Status.dwServiceType & SERVICE_DRIVER)
1209 {
1210 /* Load driver */
1211 dwError = ScmLoadDriver(Service);
1212 if (dwError == ERROR_SUCCESS)
1213 {
1214 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
1215 Service->Status.dwCurrentState = SERVICE_RUNNING;
1216 }
1217 }
1218 else
1219 {
1220 /* Start user-mode service */
1221 dwError = ScmCreateOrReferenceServiceImage(Service);
1222 if (dwError == ERROR_SUCCESS)
1223 {
1224 dwError = ScmStartUserModeService(Service, argc, argv);
1225 if (dwError == ERROR_SUCCESS)
1226 {
1227 #ifdef USE_SERVICE_START_PENDING
1228 Service->Status.dwCurrentState = SERVICE_START_PENDING;
1229 #else
1230 Service->Status.dwCurrentState = SERVICE_RUNNING;
1231 #endif
1232 }
1233 else
1234 {
1235 ScmDereferenceServiceImage(Service->lpImage);
1236 Service->lpImage = NULL;
1237 }
1238 }
1239 }
1240
1241 LeaveCriticalSection(&ControlServiceCriticalSection);
1242
1243 DPRINT("ScmStartService() done (Error %lu)\n", dwError);
1244
1245 if (dwError == ERROR_SUCCESS)
1246 {
1247 if (Group != NULL)
1248 {
1249 Group->ServicesRunning = TRUE;
1250 }
1251 }
1252 else
1253 {
1254 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
1255 {
1256 ErrorLogStrings[0] = Service->lpServiceName;
1257 ErrorLogStrings[1] = L"Test";
1258 ScmLogError(EVENT_SERVICE_START_FAILED,
1259 2,
1260 ErrorLogStrings);
1261 }
1262
1263 #if 0
1264 switch (Service->dwErrorControl)
1265 {
1266 case SERVICE_ERROR_SEVERE:
1267 if (IsLastKnownGood == FALSE)
1268 {
1269 /* FIXME: Boot last known good configuration */
1270 }
1271 break;
1272
1273 case SERVICE_ERROR_CRITICAL:
1274 if (IsLastKnownGood == FALSE)
1275 {
1276 /* FIXME: Boot last known good configuration */
1277 }
1278 else
1279 {
1280 /* FIXME: BSOD! */
1281 }
1282 break;
1283 }
1284 #endif
1285 }
1286
1287 return dwError;
1288 }
1289
1290
1291 VOID
1292 ScmAutoStartServices(VOID)
1293 {
1294 PLIST_ENTRY GroupEntry;
1295 PLIST_ENTRY ServiceEntry;
1296 PSERVICE_GROUP CurrentGroup;
1297 PSERVICE CurrentService;
1298 WCHAR szSafeBootServicePath[MAX_PATH];
1299 DWORD dwError;
1300 HKEY hKey;
1301 ULONG i;
1302
1303 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1304 ServiceEntry = ServiceListHead.Flink;
1305 while (ServiceEntry != &ServiceListHead)
1306 {
1307 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1308
1309 /* Build the safe boot path */
1310 wcscpy(szSafeBootServicePath,
1311 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1312
1313 switch (GetSystemMetrics(SM_CLEANBOOT))
1314 {
1315 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1316 case 1:
1317 case 3:
1318 wcscat(szSafeBootServicePath, L"\\Minimal\\");
1319 break;
1320
1321 case 2:
1322 wcscat(szSafeBootServicePath, L"\\Network\\");
1323 break;
1324 }
1325
1326 if (GetSystemMetrics(SM_CLEANBOOT))
1327 {
1328 /* If key does not exist then do not assume safe mode */
1329 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1330 szSafeBootServicePath,
1331 0,
1332 KEY_READ,
1333 &hKey);
1334 if (dwError == ERROR_SUCCESS)
1335 {
1336 RegCloseKey(hKey);
1337
1338 /* Finish Safe Boot path off */
1339 wcsncat(szSafeBootServicePath,
1340 CurrentService->lpServiceName,
1341 MAX_PATH - wcslen(szSafeBootServicePath));
1342
1343 /* Check that the key is in the Safe Boot path */
1344 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1345 szSafeBootServicePath,
1346 0,
1347 KEY_READ,
1348 &hKey);
1349 if (dwError != ERROR_SUCCESS)
1350 {
1351 /* Mark service as visited so it is not auto-started */
1352 CurrentService->ServiceVisited = TRUE;
1353 }
1354 else
1355 {
1356 /* Must be auto-started in safe mode - mark as unvisited */
1357 RegCloseKey(hKey);
1358 CurrentService->ServiceVisited = FALSE;
1359 }
1360 }
1361 else
1362 {
1363 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1364 CurrentService->ServiceVisited = FALSE;
1365 }
1366 }
1367
1368 ServiceEntry = ServiceEntry->Flink;
1369 }
1370
1371 /* Start all services which are members of an existing group */
1372 GroupEntry = GroupListHead.Flink;
1373 while (GroupEntry != &GroupListHead)
1374 {
1375 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
1376
1377 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
1378
1379 /* Start all services witch have a valid tag */
1380 for (i = 0; i < CurrentGroup->TagCount; i++)
1381 {
1382 ServiceEntry = ServiceListHead.Flink;
1383 while (ServiceEntry != &ServiceListHead)
1384 {
1385 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1386
1387 if ((CurrentService->lpGroup == CurrentGroup) &&
1388 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1389 (CurrentService->ServiceVisited == FALSE) &&
1390 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
1391 {
1392 CurrentService->ServiceVisited = TRUE;
1393 ScmStartService(CurrentService, 0, NULL);
1394 }
1395
1396 ServiceEntry = ServiceEntry->Flink;
1397 }
1398 }
1399
1400 /* Start all services which have an invalid tag or which do not have a tag */
1401 ServiceEntry = ServiceListHead.Flink;
1402 while (ServiceEntry != &ServiceListHead)
1403 {
1404 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1405
1406 if ((CurrentService->lpGroup == CurrentGroup) &&
1407 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1408 (CurrentService->ServiceVisited == FALSE))
1409 {
1410 CurrentService->ServiceVisited = TRUE;
1411 ScmStartService(CurrentService, 0, NULL);
1412 }
1413
1414 ServiceEntry = ServiceEntry->Flink;
1415 }
1416
1417 GroupEntry = GroupEntry->Flink;
1418 }
1419
1420 /* Start all services which are members of any non-existing group */
1421 ServiceEntry = ServiceListHead.Flink;
1422 while (ServiceEntry != &ServiceListHead)
1423 {
1424 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1425
1426 if ((CurrentService->lpGroup != NULL) &&
1427 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1428 (CurrentService->ServiceVisited == FALSE))
1429 {
1430 CurrentService->ServiceVisited = TRUE;
1431 ScmStartService(CurrentService, 0, NULL);
1432 }
1433
1434 ServiceEntry = ServiceEntry->Flink;
1435 }
1436
1437 /* Start all services which are not a member of any group */
1438 ServiceEntry = ServiceListHead.Flink;
1439 while (ServiceEntry != &ServiceListHead)
1440 {
1441 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1442
1443 if ((CurrentService->lpGroup == NULL) &&
1444 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1445 (CurrentService->ServiceVisited == FALSE))
1446 {
1447 CurrentService->ServiceVisited = TRUE;
1448 ScmStartService(CurrentService, 0, NULL);
1449 }
1450
1451 ServiceEntry = ServiceEntry->Flink;
1452 }
1453
1454 /* Clear 'ServiceVisited' flag again */
1455 ServiceEntry = ServiceListHead.Flink;
1456 while (ServiceEntry != &ServiceListHead)
1457 {
1458 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1459 CurrentService->ServiceVisited = FALSE;
1460 ServiceEntry = ServiceEntry->Flink;
1461 }
1462 }
1463
1464
1465 VOID
1466 ScmAutoShutdownServices(VOID)
1467 {
1468 PLIST_ENTRY ServiceEntry;
1469 PSERVICE CurrentService;
1470
1471 DPRINT("ScmAutoShutdownServices() called\n");
1472
1473 /* Lock the service database exclusively */
1474 ScmLockDatabaseExclusive();
1475
1476 ServiceEntry = ServiceListHead.Flink;
1477 while (ServiceEntry != &ServiceListHead)
1478 {
1479 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1480
1481 if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
1482 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
1483 {
1484 /* shutdown service */
1485 DPRINT("Shutdown service: %S\n", CurrentService->szServiceName);
1486 ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN);
1487 }
1488
1489 ServiceEntry = ServiceEntry->Flink;
1490 }
1491
1492 /* Unlock the service database */
1493 ScmUnlockDatabase();
1494
1495 DPRINT("ScmAutoShutdownServices() done\n");
1496 }
1497
1498
1499 BOOL
1500 ScmLockDatabaseExclusive(VOID)
1501 {
1502 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE);
1503 }
1504
1505
1506 BOOL
1507 ScmLockDatabaseShared(VOID)
1508 {
1509 return RtlAcquireResourceShared(&DatabaseLock, TRUE);
1510 }
1511
1512
1513 VOID
1514 ScmUnlockDatabase(VOID)
1515 {
1516 RtlReleaseResource(&DatabaseLock);
1517 }
1518
1519
1520 VOID
1521 ScmInitNamedPipeCriticalSection(VOID)
1522 {
1523 InitializeCriticalSection(&ControlServiceCriticalSection);
1524 }
1525
1526
1527 VOID
1528 ScmDeleteNamedPipeCriticalSection(VOID)
1529 {
1530 DeleteCriticalSection(&ControlServiceCriticalSection);
1531 }
1532
1533 /* EOF */