e30697cd8aa243c418065713d373551738a5b25d
[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 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(), HEAP_ZERO_MEMORY, 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 DWORD
665 ScmCreateServiceDatabase(VOID)
666 {
667 WCHAR szSubKey[MAX_PATH];
668 HKEY hServicesKey;
669 HKEY hServiceKey;
670 DWORD dwSubKey;
671 DWORD dwSubKeyLength;
672 FILETIME ftLastChanged;
673 DWORD dwError;
674
675 DPRINT("ScmCreateServiceDatabase() called\n");
676
677 dwError = ScmCreateGroupList();
678 if (dwError != ERROR_SUCCESS)
679 return dwError;
680
681 /* Initialize basic variables */
682 InitializeListHead(&ImageListHead);
683 InitializeListHead(&ServiceListHead);
684
685 /* Initialize the database lock */
686 RtlInitializeResource(&DatabaseLock);
687
688 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
689 L"System\\CurrentControlSet\\Services",
690 0,
691 KEY_READ,
692 &hServicesKey);
693 if (dwError != ERROR_SUCCESS)
694 return dwError;
695
696 dwSubKey = 0;
697 for (;;)
698 {
699 dwSubKeyLength = MAX_PATH;
700 dwError = RegEnumKeyExW(hServicesKey,
701 dwSubKey,
702 szSubKey,
703 &dwSubKeyLength,
704 NULL,
705 NULL,
706 NULL,
707 &ftLastChanged);
708 if (dwError == ERROR_SUCCESS &&
709 szSubKey[0] != L'{')
710 {
711 DPRINT("SubKeyName: '%S'\n", szSubKey);
712
713 dwError = RegOpenKeyExW(hServicesKey,
714 szSubKey,
715 0,
716 KEY_READ,
717 &hServiceKey);
718 if (dwError == ERROR_SUCCESS)
719 {
720 dwError = CreateServiceListEntry(szSubKey,
721 hServiceKey);
722
723 RegCloseKey(hServiceKey);
724 }
725 }
726
727 if (dwError != ERROR_SUCCESS)
728 break;
729
730 dwSubKey++;
731 }
732
733 RegCloseKey(hServicesKey);
734
735 /* Wait for the LSA server */
736 ScmWaitForLsa();
737
738 /* Delete services that are marked for delete */
739 ScmDeleteMarkedServices();
740
741 DPRINT("ScmCreateServiceDatabase() done\n");
742
743 return ERROR_SUCCESS;
744 }
745
746
747 VOID
748 ScmShutdownServiceDatabase(VOID)
749 {
750 DPRINT("ScmShutdownServiceDatabase() called\n");
751
752 ScmDeleteMarkedServices();
753 RtlDeleteResource(&DatabaseLock);
754
755 DPRINT("ScmShutdownServiceDatabase() done\n");
756 }
757
758
759 static NTSTATUS
760 ScmCheckDriver(PSERVICE Service)
761 {
762 OBJECT_ATTRIBUTES ObjectAttributes;
763 UNICODE_STRING DirName;
764 HANDLE DirHandle;
765 NTSTATUS Status;
766 POBJECT_DIRECTORY_INFORMATION DirInfo;
767 ULONG BufferLength;
768 ULONG DataLength;
769 ULONG Index;
770
771 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
772
773 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
774 {
775 RtlInitUnicodeString(&DirName,
776 L"\\Driver");
777 }
778 else
779 {
780 RtlInitUnicodeString(&DirName,
781 L"\\FileSystem");
782 }
783
784 InitializeObjectAttributes(&ObjectAttributes,
785 &DirName,
786 0,
787 NULL,
788 NULL);
789
790 Status = NtOpenDirectoryObject(&DirHandle,
791 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
792 &ObjectAttributes);
793 if (!NT_SUCCESS(Status))
794 {
795 return Status;
796 }
797
798 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
799 2 * MAX_PATH * sizeof(WCHAR);
800 DirInfo = HeapAlloc(GetProcessHeap(),
801 HEAP_ZERO_MEMORY,
802 BufferLength);
803
804 Index = 0;
805 while (TRUE)
806 {
807 Status = NtQueryDirectoryObject(DirHandle,
808 DirInfo,
809 BufferLength,
810 TRUE,
811 FALSE,
812 &Index,
813 &DataLength);
814 if (Status == STATUS_NO_MORE_ENTRIES)
815 {
816 /* FIXME: Add current service to 'failed service' list */
817 DPRINT("Service '%S' failed\n", Service->lpServiceName);
818 break;
819 }
820
821 if (!NT_SUCCESS(Status))
822 break;
823
824 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
825
826 if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
827 {
828 DPRINT("Found: '%S' '%wZ'\n",
829 Service->lpServiceName, &DirInfo->Name);
830
831 /* Mark service as 'running' */
832 Service->Status.dwCurrentState = SERVICE_RUNNING;
833
834 /* Mark the service group as 'running' */
835 if (Service->lpGroup != NULL)
836 {
837 Service->lpGroup->ServicesRunning = TRUE;
838 }
839
840 break;
841 }
842 }
843
844 HeapFree(GetProcessHeap(),
845 0,
846 DirInfo);
847 NtClose(DirHandle);
848
849 return STATUS_SUCCESS;
850 }
851
852
853 VOID
854 ScmGetBootAndSystemDriverState(VOID)
855 {
856 PLIST_ENTRY ServiceEntry;
857 PSERVICE CurrentService;
858
859 DPRINT("ScmGetBootAndSystemDriverState() called\n");
860
861 ServiceEntry = ServiceListHead.Flink;
862 while (ServiceEntry != &ServiceListHead)
863 {
864 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
865
866 if (CurrentService->dwStartType == SERVICE_BOOT_START ||
867 CurrentService->dwStartType == SERVICE_SYSTEM_START)
868 {
869 /* Check driver */
870 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
871
872 ScmCheckDriver(CurrentService);
873 }
874
875 ServiceEntry = ServiceEntry->Flink;
876 }
877
878 DPRINT("ScmGetBootAndSystemDriverState() done\n");
879 }
880
881
882 DWORD
883 ScmControlService(PSERVICE Service,
884 DWORD dwControl)
885 {
886 PSCM_CONTROL_PACKET ControlPacket;
887 SCM_REPLY_PACKET ReplyPacket;
888
889 DWORD dwWriteCount = 0;
890 DWORD dwReadCount = 0;
891 DWORD PacketSize;
892 PWSTR Ptr;
893 DWORD dwError = ERROR_SUCCESS;
894 BOOL bResult;
895 #ifdef USE_ASYNCHRONOUS_IO
896 OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
897 #endif
898
899 DPRINT("ScmControlService() called\n");
900
901 EnterCriticalSection(&ControlServiceCriticalSection);
902
903 /* Calculate the total length of the start command line */
904 PacketSize = sizeof(SCM_CONTROL_PACKET);
905 PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
906
907 ControlPacket = HeapAlloc(GetProcessHeap(),
908 HEAP_ZERO_MEMORY,
909 PacketSize);
910 if (ControlPacket == NULL)
911 {
912 LeaveCriticalSection(&ControlServiceCriticalSection);
913 return ERROR_NOT_ENOUGH_MEMORY;
914 }
915
916 ControlPacket->dwSize = PacketSize;
917 ControlPacket->dwControl = dwControl;
918 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
919
920 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
921
922 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
923 wcscpy(Ptr, Service->lpServiceName);
924
925 ControlPacket->dwArgumentsCount = 0;
926 ControlPacket->dwArgumentsOffset = 0;
927
928 #ifdef USE_ASYNCHRONOUS_IO
929 bResult = WriteFile(Service->lpImage->hControlPipe,
930 ControlPacket,
931 PacketSize,
932 &dwWriteCount,
933 &Overlapped);
934 if (bResult == FALSE)
935 {
936 DPRINT1("WriteFile() returned FALSE\n");
937
938 dwError = GetLastError();
939 if (dwError == ERROR_IO_PENDING)
940 {
941 DPRINT1("dwError: ERROR_IO_PENDING\n");
942
943 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
944 dwPipeTimeout);
945 DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
946
947 if (dwError == WAIT_TIMEOUT)
948 {
949 bResult = CancelIo(Service->lpImage->hControlPipe);
950 if (bResult == FALSE)
951 {
952 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
953 }
954
955 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
956 goto Done;
957 }
958 else if (dwError == ERROR_SUCCESS)
959 {
960 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
961 &Overlapped,
962 &dwWriteCount,
963 TRUE);
964 if (bResult == FALSE)
965 {
966 dwError = GetLastError();
967 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
968
969 goto Done;
970 }
971 }
972 }
973 else
974 {
975 DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
976 goto Done;
977 }
978 }
979
980 /* Read the reply */
981 Overlapped.hEvent = (HANDLE) NULL;
982
983 bResult = ReadFile(Service->lpImage->hControlPipe,
984 &ReplyPacket,
985 sizeof(SCM_REPLY_PACKET),
986 &dwReadCount,
987 &Overlapped);
988 if (bResult == FALSE)
989 {
990 DPRINT1("ReadFile() returned FALSE\n");
991
992 dwError = GetLastError();
993 if (dwError == ERROR_IO_PENDING)
994 {
995 DPRINT1("dwError: ERROR_IO_PENDING\n");
996
997 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
998 dwPipeTimeout);
999 DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
1000
1001 if (dwError == WAIT_TIMEOUT)
1002 {
1003 bResult = CancelIo(Service->lpImage->hControlPipe);
1004 if (bResult == FALSE)
1005 {
1006 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1007 }
1008
1009 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1010 goto Done;
1011 }
1012 else if (dwError == ERROR_SUCCESS)
1013 {
1014 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1015 &Overlapped,
1016 &dwReadCount,
1017 TRUE);
1018 if (bResult == FALSE)
1019 {
1020 dwError = GetLastError();
1021 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1022
1023 goto Done;
1024 }
1025 }
1026 }
1027 else
1028 {
1029 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1030 goto Done;
1031 }
1032 }
1033
1034 #else
1035 /* Send the control packet */
1036 bResult = WriteFile(Service->lpImage->hControlPipe,
1037 ControlPacket,
1038 PacketSize,
1039 &dwWriteCount,
1040 NULL);
1041 if (bResult == FALSE)
1042 {
1043 dwError = GetLastError();
1044 DPRINT("WriteFile() failed (Error %lu)\n", dwError);
1045
1046 if ((dwError == ERROR_GEN_FAILURE) &&
1047 (dwControl == SERVICE_CONTROL_STOP))
1048 {
1049 /* Service is already terminated */
1050 Service->Status.dwCurrentState = SERVICE_STOPPED;
1051 Service->Status.dwControlsAccepted = 0;
1052 Service->Status.dwWin32ExitCode = ERROR_SERVICE_NOT_ACTIVE;
1053 dwError = ERROR_SUCCESS;
1054 }
1055 goto Done;
1056 }
1057
1058 /* Read the reply */
1059 bResult = ReadFile(Service->lpImage->hControlPipe,
1060 &ReplyPacket,
1061 sizeof(SCM_REPLY_PACKET),
1062 &dwReadCount,
1063 NULL);
1064 if (bResult == FALSE)
1065 {
1066 dwError = GetLastError();
1067 DPRINT("ReadFile() failed (Error %lu)\n", dwError);
1068 }
1069 #endif
1070
1071 Done:
1072 /* Release the contol packet */
1073 HeapFree(GetProcessHeap(),
1074 0,
1075 ControlPacket);
1076
1077 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
1078 {
1079 dwError = ReplyPacket.dwError;
1080 }
1081
1082 if (dwError == ERROR_SUCCESS &&
1083 dwControl == SERVICE_CONTROL_STOP)
1084 {
1085 ScmDereferenceServiceImage(Service->lpImage);
1086 }
1087
1088 LeaveCriticalSection(&ControlServiceCriticalSection);
1089
1090 DPRINT("ScmControlService() done\n");
1091
1092 return dwError;
1093 }
1094
1095
1096 static DWORD
1097 ScmSendStartCommand(PSERVICE Service,
1098 DWORD argc,
1099 LPWSTR *argv)
1100 {
1101 PSCM_CONTROL_PACKET ControlPacket;
1102 SCM_REPLY_PACKET ReplyPacket;
1103 DWORD PacketSize;
1104 PWSTR Ptr;
1105 DWORD dwWriteCount = 0;
1106 DWORD dwReadCount = 0;
1107 DWORD dwError = ERROR_SUCCESS;
1108 DWORD i;
1109 PWSTR *pOffPtr;
1110 PWSTR pArgPtr;
1111 BOOL bResult;
1112 #ifdef USE_ASYNCHRONOUS_IO
1113 OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
1114 #endif
1115
1116 DPRINT("ScmSendStartCommand() called\n");
1117
1118 /* Calculate the total length of the start command line */
1119 PacketSize = sizeof(SCM_CONTROL_PACKET) +
1120 (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
1121
1122 /* Calculate the required packet size for the start arguments */
1123 if (argc > 0 && argv != NULL)
1124 {
1125 PacketSize = ALIGN_UP(PacketSize, LPWSTR);
1126
1127 DPRINT("Argc: %lu\n", argc);
1128 for (i = 0; i < argc; i++)
1129 {
1130 DPRINT("Argv[%lu]: %S\n", i, argv[i]);
1131 PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR));
1132 }
1133 }
1134
1135 /* Allocate a control packet */
1136 ControlPacket = HeapAlloc(GetProcessHeap(),
1137 HEAP_ZERO_MEMORY,
1138 PacketSize);
1139 if (ControlPacket == NULL)
1140 return ERROR_NOT_ENOUGH_MEMORY;
1141
1142 ControlPacket->dwSize = PacketSize;
1143 ControlPacket->dwControl = (Service->Status.dwServiceType & SERVICE_WIN32_OWN_PROCESS)
1144 ? SERVICE_CONTROL_START_OWN
1145 : SERVICE_CONTROL_START_SHARE;
1146 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
1147 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
1148
1149 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
1150 wcscpy(Ptr, Service->lpServiceName);
1151
1152 ControlPacket->dwArgumentsCount = 0;
1153 ControlPacket->dwArgumentsOffset = 0;
1154
1155 /* Copy argument list */
1156 if (argc > 0 && argv != NULL)
1157 {
1158 Ptr += wcslen(Service->lpServiceName) + 1;
1159 pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR);
1160 pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
1161
1162 ControlPacket->dwArgumentsCount = argc;
1163 ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
1164
1165 DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount);
1166 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset);
1167
1168 for (i = 0; i < argc; i++)
1169 {
1170 wcscpy(pArgPtr, argv[i]);
1171 *pOffPtr = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
1172 DPRINT("offset: %p\n", *pOffPtr);
1173
1174 pArgPtr += wcslen(argv[i]) + 1;
1175 pOffPtr++;
1176 }
1177 }
1178
1179 #ifdef USE_ASYNCHRONOUS_IO
1180 bResult = WriteFile(Service->lpImage->hControlPipe,
1181 ControlPacket,
1182 PacketSize,
1183 &dwWriteCount,
1184 &Overlapped);
1185 if (bResult == FALSE)
1186 {
1187 DPRINT1("WriteFile() returned FALSE\n");
1188
1189 dwError = GetLastError();
1190 if (dwError == ERROR_IO_PENDING)
1191 {
1192 DPRINT1("dwError: ERROR_IO_PENDING\n");
1193
1194 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1195 dwPipeTimeout);
1196 DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
1197
1198 if (dwError == WAIT_TIMEOUT)
1199 {
1200 bResult = CancelIo(Service->lpImage->hControlPipe);
1201 if (bResult == FALSE)
1202 {
1203 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1204 }
1205
1206 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1207 goto Done;
1208 }
1209 else if (dwError == ERROR_SUCCESS)
1210 {
1211 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1212 &Overlapped,
1213 &dwWriteCount,
1214 TRUE);
1215 if (bResult == FALSE)
1216 {
1217 dwError = GetLastError();
1218 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1219
1220 goto Done;
1221 }
1222 }
1223 }
1224 else
1225 {
1226 DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
1227 goto Done;
1228 }
1229 }
1230
1231 /* Read the reply */
1232 Overlapped.hEvent = (HANDLE) NULL;
1233
1234 bResult = ReadFile(Service->lpImage->hControlPipe,
1235 &ReplyPacket,
1236 sizeof(SCM_REPLY_PACKET),
1237 &dwReadCount,
1238 &Overlapped);
1239 if (bResult == FALSE)
1240 {
1241 DPRINT1("ReadFile() returned FALSE\n");
1242
1243 dwError = GetLastError();
1244 if (dwError == ERROR_IO_PENDING)
1245 {
1246 DPRINT1("dwError: ERROR_IO_PENDING\n");
1247
1248 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1249 dwPipeTimeout);
1250 DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
1251
1252 if (dwError == WAIT_TIMEOUT)
1253 {
1254 bResult = CancelIo(Service->lpImage->hControlPipe);
1255 if (bResult == FALSE)
1256 {
1257 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1258 }
1259
1260 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1261 goto Done;
1262 }
1263 else if (dwError == ERROR_SUCCESS)
1264 {
1265 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1266 &Overlapped,
1267 &dwReadCount,
1268 TRUE);
1269 if (bResult == FALSE)
1270 {
1271 dwError = GetLastError();
1272 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1273
1274 goto Done;
1275 }
1276 }
1277 }
1278 else
1279 {
1280 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1281 goto Done;
1282 }
1283 }
1284
1285 #else
1286 /* Send the start command */
1287 bResult = WriteFile(Service->lpImage->hControlPipe,
1288 ControlPacket,
1289 PacketSize,
1290 &dwWriteCount,
1291 NULL);
1292 if (bResult == FALSE)
1293 {
1294 dwError = GetLastError();
1295 DPRINT("WriteFile() failed (Error %lu)\n", dwError);
1296 goto Done;
1297 }
1298
1299 /* Read the reply */
1300 bResult = ReadFile(Service->lpImage->hControlPipe,
1301 &ReplyPacket,
1302 sizeof(SCM_REPLY_PACKET),
1303 &dwReadCount,
1304 NULL);
1305 if (bResult == FALSE)
1306 {
1307 dwError = GetLastError();
1308 DPRINT("ReadFile() failed (Error %lu)\n", dwError);
1309 }
1310 #endif
1311
1312 Done:
1313 /* Release the contol packet */
1314 HeapFree(GetProcessHeap(),
1315 0,
1316 ControlPacket);
1317
1318 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
1319 {
1320 dwError = ReplyPacket.dwError;
1321 }
1322
1323 DPRINT("ScmSendStartCommand() done\n");
1324
1325 return dwError;
1326 }
1327
1328
1329 static DWORD
1330 ScmWaitForServiceConnect(PSERVICE Service)
1331 {
1332 DWORD dwRead = 0;
1333 DWORD dwProcessId = 0;
1334 DWORD dwError = ERROR_SUCCESS;
1335 BOOL bResult;
1336 #ifdef USE_ASYNCHRONOUS_IO
1337 OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
1338 #endif
1339
1340 DPRINT("ScmWaitForServiceConnect()\n");
1341
1342 #ifdef USE_ASYNCHRONOUS_IO
1343 Overlapped.hEvent = (HANDLE)NULL;
1344
1345 bResult = ConnectNamedPipe(Service->lpImage->hControlPipe,
1346 &Overlapped);
1347 if (bResult == FALSE)
1348 {
1349 DPRINT("ConnectNamedPipe() returned FALSE\n");
1350
1351 dwError = GetLastError();
1352 if (dwError == ERROR_IO_PENDING)
1353 {
1354 DPRINT("dwError: ERROR_IO_PENDING\n");
1355
1356 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1357 dwPipeTimeout);
1358 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1359
1360 if (dwError == WAIT_TIMEOUT)
1361 {
1362 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1363
1364 bResult = CancelIo(Service->lpImage->hControlPipe);
1365 if (bResult == FALSE)
1366 {
1367 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1368 }
1369
1370 return ERROR_SERVICE_REQUEST_TIMEOUT;
1371 }
1372 else if (dwError == WAIT_OBJECT_0)
1373 {
1374 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1375 &Overlapped,
1376 &dwRead,
1377 TRUE);
1378 if (bResult == FALSE)
1379 {
1380 dwError = GetLastError();
1381 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError);
1382
1383 return dwError;
1384 }
1385 }
1386 }
1387 else if (dwError != ERROR_PIPE_CONNECTED)
1388 {
1389 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError);
1390 return dwError;
1391 }
1392 }
1393
1394 DPRINT("Control pipe connected!\n");
1395
1396 Overlapped.hEvent = (HANDLE) NULL;
1397
1398 /* Read the process id from pipe */
1399 bResult = ReadFile(Service->lpImage->hControlPipe,
1400 (LPVOID)&dwProcessId,
1401 sizeof(DWORD),
1402 &dwRead,
1403 &Overlapped);
1404 if (bResult == FALSE)
1405 {
1406 DPRINT("ReadFile() returned FALSE\n");
1407
1408 dwError = GetLastError();
1409 if (dwError == ERROR_IO_PENDING)
1410 {
1411 DPRINT("dwError: ERROR_IO_PENDING\n");
1412
1413 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1414 dwPipeTimeout);
1415 if (dwError == WAIT_TIMEOUT)
1416 {
1417 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1418
1419 bResult = CancelIo(Service->lpImage->hControlPipe);
1420 if (bResult == FALSE)
1421 {
1422 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1423 }
1424
1425 return ERROR_SERVICE_REQUEST_TIMEOUT;
1426 }
1427 else if (dwError == ERROR_SUCCESS)
1428 {
1429 DPRINT("WaitForSingleObject() returned ERROR_SUCCESS\n");
1430
1431 DPRINT("Process Id: %lu\n", dwProcessId);
1432
1433 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1434 &Overlapped,
1435 &dwRead,
1436 TRUE);
1437 if (bResult == FALSE)
1438 {
1439 dwError = GetLastError();
1440 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1441
1442 return dwError;
1443 }
1444 }
1445 else
1446 {
1447 DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
1448 }
1449 }
1450 else
1451 {
1452 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1453 return dwError;
1454 }
1455 }
1456
1457 DPRINT1("ScmWaitForServiceConnect() done\n");
1458
1459 return ERROR_SUCCESS;
1460 #else
1461
1462 /* Connect control pipe */
1463 if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ?
1464 TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
1465 {
1466 DPRINT("Control pipe connected!\n");
1467
1468 /* Read SERVICE_STATUS_HANDLE from pipe */
1469 bResult = ReadFile(Service->lpImage->hControlPipe,
1470 (LPVOID)&dwProcessId,
1471 sizeof(DWORD),
1472 &dwRead,
1473 NULL);
1474 if (bResult == FALSE)
1475 {
1476 dwError = GetLastError();
1477 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1478 dwError);
1479 }
1480 else
1481 {
1482 dwError = ERROR_SUCCESS;
1483 DPRINT("Read control pipe successfully\n");
1484 }
1485 }
1486 else
1487 {
1488 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
1489 }
1490
1491 return dwError;
1492 #endif
1493 }
1494
1495
1496 static DWORD
1497 ScmStartUserModeService(PSERVICE Service,
1498 DWORD argc,
1499 LPWSTR *argv)
1500 {
1501 PROCESS_INFORMATION ProcessInformation;
1502 STARTUPINFOW StartupInfo;
1503 BOOL Result;
1504 DWORD dwError = ERROR_SUCCESS;
1505
1506 DPRINT("ScmStartUserModeService(%p)\n", Service);
1507
1508 /* If the image is already running ... */
1509 if (Service->lpImage->dwImageRunCount > 1)
1510 {
1511 /* ... just send a start command */
1512 return ScmSendStartCommand(Service, argc, argv);
1513 }
1514
1515 StartupInfo.cb = sizeof(StartupInfo);
1516 StartupInfo.lpReserved = NULL;
1517 StartupInfo.lpDesktop = NULL;
1518 StartupInfo.lpTitle = NULL;
1519 StartupInfo.dwFlags = 0;
1520 StartupInfo.cbReserved2 = 0;
1521 StartupInfo.lpReserved2 = 0;
1522
1523 Result = CreateProcessW(NULL,
1524 Service->lpImage->szImagePath,
1525 NULL,
1526 NULL,
1527 FALSE,
1528 DETACHED_PROCESS | CREATE_SUSPENDED,
1529 NULL,
1530 NULL,
1531 &StartupInfo,
1532 &ProcessInformation);
1533 if (!Result)
1534 {
1535 dwError = GetLastError();
1536 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
1537 return dwError;
1538 }
1539
1540 DPRINT("Process Id: %lu Handle %p\n",
1541 ProcessInformation.dwProcessId,
1542 ProcessInformation.hProcess);
1543 DPRINT("Thread Id: %lu Handle %p\n",
1544 ProcessInformation.dwThreadId,
1545 ProcessInformation.hThread);
1546
1547 /* Get process handle and id */
1548 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
1549
1550 /* Resume Thread */
1551 ResumeThread(ProcessInformation.hThread);
1552
1553 /* Connect control pipe */
1554 dwError = ScmWaitForServiceConnect(Service);
1555 if (dwError == ERROR_SUCCESS)
1556 {
1557 /* Send start command */
1558 dwError = ScmSendStartCommand(Service,
1559 argc,
1560 argv);
1561 }
1562 else
1563 {
1564 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
1565 Service->lpImage->dwProcessId = 0;
1566 }
1567
1568 /* Close thread and process handle */
1569 CloseHandle(ProcessInformation.hThread);
1570 CloseHandle(ProcessInformation.hProcess);
1571
1572 return dwError;
1573 }
1574
1575
1576 DWORD
1577 ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
1578 {
1579 PSERVICE_GROUP Group = Service->lpGroup;
1580 DWORD dwError = ERROR_SUCCESS;
1581 LPCWSTR ErrorLogStrings[2];
1582 WCHAR szErrorBuffer[32];
1583
1584 DPRINT("ScmStartService() called\n");
1585
1586 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
1587
1588 EnterCriticalSection(&ControlServiceCriticalSection);
1589
1590 if (Service->Status.dwCurrentState != SERVICE_STOPPED)
1591 {
1592 DPRINT("Service %S is already running!\n", Service->lpServiceName);
1593 LeaveCriticalSection(&ControlServiceCriticalSection);
1594 return ERROR_SERVICE_ALREADY_RUNNING;
1595 }
1596
1597 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
1598
1599 if (Service->Status.dwServiceType & SERVICE_DRIVER)
1600 {
1601 /* Load driver */
1602 dwError = ScmLoadDriver(Service);
1603 if (dwError == ERROR_SUCCESS)
1604 {
1605 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
1606 Service->Status.dwCurrentState = SERVICE_RUNNING;
1607 }
1608 }
1609 else
1610 {
1611 /* Start user-mode service */
1612 dwError = ScmCreateOrReferenceServiceImage(Service);
1613 if (dwError == ERROR_SUCCESS)
1614 {
1615 dwError = ScmStartUserModeService(Service, argc, argv);
1616 if (dwError == ERROR_SUCCESS)
1617 {
1618 #ifdef USE_SERVICE_START_PENDING
1619 Service->Status.dwCurrentState = SERVICE_START_PENDING;
1620 #else
1621 Service->Status.dwCurrentState = SERVICE_RUNNING;
1622 #endif
1623 }
1624 else
1625 {
1626 ScmDereferenceServiceImage(Service->lpImage);
1627 Service->lpImage = NULL;
1628 }
1629 }
1630 }
1631
1632 LeaveCriticalSection(&ControlServiceCriticalSection);
1633
1634 DPRINT("ScmStartService() done (Error %lu)\n", dwError);
1635
1636 if (dwError == ERROR_SUCCESS)
1637 {
1638 if (Group != NULL)
1639 {
1640 Group->ServicesRunning = TRUE;
1641 }
1642 }
1643 else
1644 {
1645 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
1646 {
1647 /* Log a failed service start */
1648 swprintf(szErrorBuffer, L"%lu", dwError);
1649 ErrorLogStrings[0] = Service->lpServiceName;
1650 ErrorLogStrings[1] = szErrorBuffer;
1651 ScmLogError(EVENT_SERVICE_START_FAILED,
1652 2,
1653 ErrorLogStrings);
1654 }
1655
1656 #if 0
1657 switch (Service->dwErrorControl)
1658 {
1659 case SERVICE_ERROR_SEVERE:
1660 if (IsLastKnownGood == FALSE)
1661 {
1662 /* FIXME: Boot last known good configuration */
1663 }
1664 break;
1665
1666 case SERVICE_ERROR_CRITICAL:
1667 if (IsLastKnownGood == FALSE)
1668 {
1669 /* FIXME: Boot last known good configuration */
1670 }
1671 else
1672 {
1673 /* FIXME: BSOD! */
1674 }
1675 break;
1676 }
1677 #endif
1678 }
1679
1680 return dwError;
1681 }
1682
1683
1684 VOID
1685 ScmAutoStartServices(VOID)
1686 {
1687 PLIST_ENTRY GroupEntry;
1688 PLIST_ENTRY ServiceEntry;
1689 PSERVICE_GROUP CurrentGroup;
1690 PSERVICE CurrentService;
1691 WCHAR szSafeBootServicePath[MAX_PATH];
1692 DWORD dwError;
1693 HKEY hKey;
1694 ULONG i;
1695
1696 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1697 ServiceEntry = ServiceListHead.Flink;
1698 while (ServiceEntry != &ServiceListHead)
1699 {
1700 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1701
1702 /* Build the safe boot path */
1703 wcscpy(szSafeBootServicePath,
1704 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1705
1706 switch (GetSystemMetrics(SM_CLEANBOOT))
1707 {
1708 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1709 case 1:
1710 case 3:
1711 wcscat(szSafeBootServicePath, L"\\Minimal\\");
1712 break;
1713
1714 case 2:
1715 wcscat(szSafeBootServicePath, L"\\Network\\");
1716 break;
1717 }
1718
1719 if (GetSystemMetrics(SM_CLEANBOOT))
1720 {
1721 /* If key does not exist then do not assume safe mode */
1722 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1723 szSafeBootServicePath,
1724 0,
1725 KEY_READ,
1726 &hKey);
1727 if (dwError == ERROR_SUCCESS)
1728 {
1729 RegCloseKey(hKey);
1730
1731 /* Finish Safe Boot path off */
1732 wcsncat(szSafeBootServicePath,
1733 CurrentService->lpServiceName,
1734 MAX_PATH - wcslen(szSafeBootServicePath));
1735
1736 /* Check that the key is in the Safe Boot path */
1737 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1738 szSafeBootServicePath,
1739 0,
1740 KEY_READ,
1741 &hKey);
1742 if (dwError != ERROR_SUCCESS)
1743 {
1744 /* Mark service as visited so it is not auto-started */
1745 CurrentService->ServiceVisited = TRUE;
1746 }
1747 else
1748 {
1749 /* Must be auto-started in safe mode - mark as unvisited */
1750 RegCloseKey(hKey);
1751 CurrentService->ServiceVisited = FALSE;
1752 }
1753 }
1754 else
1755 {
1756 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1757 CurrentService->ServiceVisited = FALSE;
1758 }
1759 }
1760
1761 ServiceEntry = ServiceEntry->Flink;
1762 }
1763
1764 /* Start all services which are members of an existing group */
1765 GroupEntry = GroupListHead.Flink;
1766 while (GroupEntry != &GroupListHead)
1767 {
1768 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
1769
1770 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
1771
1772 /* Start all services witch have a valid tag */
1773 for (i = 0; i < CurrentGroup->TagCount; i++)
1774 {
1775 ServiceEntry = ServiceListHead.Flink;
1776 while (ServiceEntry != &ServiceListHead)
1777 {
1778 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1779
1780 if ((CurrentService->lpGroup == CurrentGroup) &&
1781 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1782 (CurrentService->ServiceVisited == FALSE) &&
1783 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
1784 {
1785 CurrentService->ServiceVisited = TRUE;
1786 ScmStartService(CurrentService, 0, NULL);
1787 }
1788
1789 ServiceEntry = ServiceEntry->Flink;
1790 }
1791 }
1792
1793 /* Start all services which have an invalid tag or which do not have a tag */
1794 ServiceEntry = ServiceListHead.Flink;
1795 while (ServiceEntry != &ServiceListHead)
1796 {
1797 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1798
1799 if ((CurrentService->lpGroup == CurrentGroup) &&
1800 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1801 (CurrentService->ServiceVisited == FALSE))
1802 {
1803 CurrentService->ServiceVisited = TRUE;
1804 ScmStartService(CurrentService, 0, NULL);
1805 }
1806
1807 ServiceEntry = ServiceEntry->Flink;
1808 }
1809
1810 GroupEntry = GroupEntry->Flink;
1811 }
1812
1813 /* Start all services which are members of any non-existing group */
1814 ServiceEntry = ServiceListHead.Flink;
1815 while (ServiceEntry != &ServiceListHead)
1816 {
1817 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1818
1819 if ((CurrentService->lpGroup != NULL) &&
1820 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1821 (CurrentService->ServiceVisited == FALSE))
1822 {
1823 CurrentService->ServiceVisited = TRUE;
1824 ScmStartService(CurrentService, 0, NULL);
1825 }
1826
1827 ServiceEntry = ServiceEntry->Flink;
1828 }
1829
1830 /* Start all services which are not a member of any group */
1831 ServiceEntry = ServiceListHead.Flink;
1832 while (ServiceEntry != &ServiceListHead)
1833 {
1834 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1835
1836 if ((CurrentService->lpGroup == NULL) &&
1837 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1838 (CurrentService->ServiceVisited == FALSE))
1839 {
1840 CurrentService->ServiceVisited = TRUE;
1841 ScmStartService(CurrentService, 0, NULL);
1842 }
1843
1844 ServiceEntry = ServiceEntry->Flink;
1845 }
1846
1847 /* Clear 'ServiceVisited' flag again */
1848 ServiceEntry = ServiceListHead.Flink;
1849 while (ServiceEntry != &ServiceListHead)
1850 {
1851 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1852 CurrentService->ServiceVisited = FALSE;
1853 ServiceEntry = ServiceEntry->Flink;
1854 }
1855 }
1856
1857
1858 VOID
1859 ScmAutoShutdownServices(VOID)
1860 {
1861 PLIST_ENTRY ServiceEntry;
1862 PSERVICE CurrentService;
1863
1864 DPRINT("ScmAutoShutdownServices() called\n");
1865
1866 /* Lock the service database exclusively */
1867 ScmLockDatabaseExclusive();
1868
1869 ServiceEntry = ServiceListHead.Flink;
1870 while (ServiceEntry != &ServiceListHead)
1871 {
1872 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1873
1874 if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
1875 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
1876 {
1877 /* shutdown service */
1878 DPRINT("Shutdown service: %S\n", CurrentService->szServiceName);
1879 ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN);
1880 }
1881
1882 ServiceEntry = ServiceEntry->Flink;
1883 }
1884
1885 /* Unlock the service database */
1886 ScmUnlockDatabase();
1887
1888 DPRINT("ScmAutoShutdownServices() done\n");
1889 }
1890
1891
1892 BOOL
1893 ScmLockDatabaseExclusive(VOID)
1894 {
1895 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE);
1896 }
1897
1898
1899 BOOL
1900 ScmLockDatabaseShared(VOID)
1901 {
1902 return RtlAcquireResourceShared(&DatabaseLock, TRUE);
1903 }
1904
1905
1906 VOID
1907 ScmUnlockDatabase(VOID)
1908 {
1909 RtlReleaseResource(&DatabaseLock);
1910 }
1911
1912
1913 VOID
1914 ScmInitNamedPipeCriticalSection(VOID)
1915 {
1916 HKEY hKey;
1917 DWORD dwKeySize;
1918 DWORD dwError;
1919
1920 InitializeCriticalSection(&ControlServiceCriticalSection);
1921
1922 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1923 L"SYSTEM\\CurrentControlSet\\Control",
1924 0,
1925 KEY_READ,
1926 &hKey);
1927 if (dwError == ERROR_SUCCESS)
1928 {
1929 dwKeySize = sizeof(DWORD);
1930 RegQueryValueExW(hKey,
1931 L"ServicesPipeTimeout",
1932 0,
1933 NULL,
1934 (LPBYTE)&dwPipeTimeout,
1935 &dwKeySize);
1936
1937 RegCloseKey(hKey);
1938 }
1939 }
1940
1941
1942 VOID
1943 ScmDeleteNamedPipeCriticalSection(VOID)
1944 {
1945 DeleteCriticalSection(&ControlServiceCriticalSection);
1946 }
1947
1948 /* EOF */