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