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