efbe3d6a9829cb420106a041f1c7bf1b95b76535
[reactos.git] / reactos / subsys / system / services / database.c
1 /*
2 *
3 * service control manager
4 *
5 * ReactOS Operating System
6 *
7 * --------------------------------------------------------------------
8 *
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
22 * MA 02139, USA.
23 *
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #include "services.h"
29
30 #define NDEBUG
31 #include <debug.h>
32
33
34 /* TYPES *********************************************************************/
35
36 typedef struct _SERVICE_GROUP
37 {
38 LIST_ENTRY GroupListEntry;
39 UNICODE_STRING GroupName;
40
41 BOOLEAN ServicesRunning;
42 ULONG TagCount;
43 PULONG TagArray;
44
45 } SERVICE_GROUP, *PSERVICE_GROUP;
46
47
48 /* GLOBALS *******************************************************************/
49
50 LIST_ENTRY GroupListHead;
51 LIST_ENTRY ServiceListHead;
52
53 static RTL_RESOURCE DatabaseLock;
54 static DWORD dwResumeCount = 1;
55
56
57 /* FUNCTIONS *****************************************************************/
58
59 PSERVICE
60 ScmGetServiceEntryByName(LPWSTR lpServiceName)
61 {
62 PLIST_ENTRY ServiceEntry;
63 PSERVICE CurrentService;
64
65 DPRINT("ScmGetServiceEntryByName() called\n");
66
67 ServiceEntry = ServiceListHead.Flink;
68 while (ServiceEntry != &ServiceListHead)
69 {
70 CurrentService = CONTAINING_RECORD(ServiceEntry,
71 SERVICE,
72 ServiceListEntry);
73 if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0)
74 {
75 DPRINT("Found service: '%S'\n", CurrentService->lpServiceName);
76 return CurrentService;
77 }
78
79 ServiceEntry = ServiceEntry->Flink;
80 }
81
82 DPRINT("Couldn't find a matching service\n");
83
84 return NULL;
85 }
86
87
88 PSERVICE
89 ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName)
90 {
91 PLIST_ENTRY ServiceEntry;
92 PSERVICE CurrentService;
93
94 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
95
96 ServiceEntry = ServiceListHead.Flink;
97 while (ServiceEntry != &ServiceListHead)
98 {
99 CurrentService = CONTAINING_RECORD(ServiceEntry,
100 SERVICE,
101 ServiceListEntry);
102 if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0)
103 {
104 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
105 return CurrentService;
106 }
107
108 ServiceEntry = ServiceEntry->Flink;
109 }
110
111 DPRINT("Couldn't find a matching service\n");
112
113 return NULL;
114 }
115
116
117 PSERVICE
118 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
119 {
120 PLIST_ENTRY ServiceEntry;
121 PSERVICE CurrentService;
122
123 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
124
125 ServiceEntry = ServiceListHead.Flink;
126 while (ServiceEntry != &ServiceListHead)
127 {
128 CurrentService = CONTAINING_RECORD(ServiceEntry,
129 SERVICE,
130 ServiceListEntry);
131 if (CurrentService->dwResumeCount > dwResumeCount)
132 {
133 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
134 return CurrentService;
135 }
136
137 ServiceEntry = ServiceEntry->Flink;
138 }
139
140 DPRINT("Couldn't find a matching service\n");
141
142 return NULL;
143 }
144
145
146 static NTSTATUS STDCALL
147 CreateGroupOrderListRoutine(PWSTR ValueName,
148 ULONG ValueType,
149 PVOID ValueData,
150 ULONG ValueLength,
151 PVOID Context,
152 PVOID EntryContext)
153 {
154 PSERVICE_GROUP Group;
155
156 DPRINT("CreateGroupOrderListRoutine(%S, %x, %x, %x, %x, %x)\n",
157 ValueName, ValueType, ValueData, ValueLength, Context, EntryContext);
158
159 if (ValueType == REG_BINARY &&
160 ValueData != NULL &&
161 ValueLength >= sizeof(DWORD) &&
162 ValueLength >= (*(PULONG)ValueData + 1) * sizeof(DWORD))
163 {
164 Group = (PSERVICE_GROUP)Context;
165 Group->TagCount = ((PULONG)ValueData)[0];
166 if (Group->TagCount > 0)
167 {
168 if (ValueLength >= (Group->TagCount + 1) * sizeof(DWORD))
169 {
170 Group->TagArray = (PULONG)HeapAlloc(GetProcessHeap(),
171 HEAP_ZERO_MEMORY,
172 Group->TagCount * sizeof(DWORD));
173 if (Group->TagArray == NULL)
174 {
175 Group->TagCount = 0;
176 return STATUS_INSUFFICIENT_RESOURCES;
177 }
178
179 RtlCopyMemory(Group->TagArray,
180 (PULONG)ValueData + 1,
181 Group->TagCount * sizeof(DWORD));
182 }
183 else
184 {
185 Group->TagCount = 0;
186 return STATUS_UNSUCCESSFUL;
187 }
188 }
189 }
190
191 return STATUS_SUCCESS;
192 }
193
194
195 static NTSTATUS STDCALL
196 CreateGroupListRoutine(PWSTR ValueName,
197 ULONG ValueType,
198 PVOID ValueData,
199 ULONG ValueLength,
200 PVOID Context,
201 PVOID EntryContext)
202 {
203 PSERVICE_GROUP Group;
204 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
205 NTSTATUS Status;
206
207 if (ValueType == REG_SZ)
208 {
209 DPRINT("Data: '%S'\n", (PWCHAR)ValueData);
210
211 Group = (PSERVICE_GROUP)HeapAlloc(GetProcessHeap(),
212 HEAP_ZERO_MEMORY,
213 sizeof(SERVICE_GROUP));
214 if (Group == NULL)
215 {
216 return STATUS_INSUFFICIENT_RESOURCES;
217 }
218
219 if (!RtlCreateUnicodeString(&Group->GroupName,
220 (PWSTR)ValueData))
221 {
222 return STATUS_INSUFFICIENT_RESOURCES;
223 }
224
225 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
226 QueryTable[0].Name = (PWSTR)ValueData;
227 QueryTable[0].QueryRoutine = CreateGroupOrderListRoutine;
228
229 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
230 L"GroupOrderList",
231 QueryTable,
232 (PVOID)Group,
233 NULL);
234 DPRINT("%x %d %S\n", Status, Group->TagCount, (PWSTR)ValueData);
235
236 InsertTailList(&GroupListHead,
237 &Group->GroupListEntry);
238 }
239
240 return STATUS_SUCCESS;
241 }
242
243
244 DWORD
245 ScmCreateNewServiceRecord(LPWSTR lpServiceName,
246 PSERVICE *lpServiceRecord)
247 {
248 PSERVICE lpService = NULL;
249
250 DPRINT("Service: '%S'\n", lpServiceName);
251
252 /* Allocate service entry */
253 lpService = HeapAlloc(GetProcessHeap(),
254 HEAP_ZERO_MEMORY,
255 sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR)));
256 if (lpService == NULL)
257 return ERROR_NOT_ENOUGH_MEMORY;
258
259 *lpServiceRecord = lpService;
260
261 /* Copy service name */
262 wcscpy(lpService->szServiceName, lpServiceName);
263 lpService->lpServiceName = lpService->szServiceName;
264 lpService->lpDisplayName = lpService->lpServiceName;
265
266 /* Set the resume count */
267 lpService->dwResumeCount = dwResumeCount++;
268
269 /* Append service entry */
270 InsertTailList(&ServiceListHead,
271 &lpService->ServiceListEntry);
272
273 lpService->Status.dwCurrentState = SERVICE_STOPPED;
274 lpService->Status.dwControlsAccepted = 0;
275 lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
276 lpService->Status.dwServiceSpecificExitCode = 0;
277 lpService->Status.dwCheckPoint = 0;
278 lpService->Status.dwWaitHint = 2000; /* 2 seconds */
279
280 return ERROR_SUCCESS;
281 }
282
283
284 static DWORD
285 CreateServiceListEntry(LPWSTR lpServiceName,
286 HKEY hServiceKey)
287 {
288 PSERVICE lpService = NULL;
289 LPWSTR lpDisplayName = NULL;
290 LPWSTR lpGroup = NULL;
291 DWORD dwSize;
292 DWORD dwError;
293 DWORD dwServiceType;
294 DWORD dwStartType;
295 DWORD dwErrorControl;
296 DWORD dwTagId;
297
298 DPRINT("Service: '%S'\n", lpServiceName);
299 if (*lpServiceName == L'{')
300 return ERROR_SUCCESS;
301
302 dwSize = sizeof(DWORD);
303 dwError = RegQueryValueExW(hServiceKey,
304 L"Type",
305 NULL,
306 NULL,
307 (LPBYTE)&dwServiceType,
308 &dwSize);
309 if (dwError != ERROR_SUCCESS)
310 return ERROR_SUCCESS;
311
312 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
313 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) &&
314 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
315 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
316 return ERROR_SUCCESS;
317
318 DPRINT("Service type: %lx\n", dwServiceType);
319
320 dwSize = sizeof(DWORD);
321 dwError = RegQueryValueExW(hServiceKey,
322 L"Start",
323 NULL,
324 NULL,
325 (LPBYTE)&dwStartType,
326 &dwSize);
327 if (dwError != ERROR_SUCCESS)
328 return ERROR_SUCCESS;
329
330 DPRINT("Start type: %lx\n", dwStartType);
331
332 dwSize = sizeof(DWORD);
333 dwError = RegQueryValueExW(hServiceKey,
334 L"ErrorControl",
335 NULL,
336 NULL,
337 (LPBYTE)&dwErrorControl,
338 &dwSize);
339 if (dwError != ERROR_SUCCESS)
340 return ERROR_SUCCESS;
341
342 DPRINT("Error control: %lx\n", dwErrorControl);
343
344 dwError = RegQueryValueExW(hServiceKey,
345 L"Tag",
346 NULL,
347 NULL,
348 (LPBYTE)&dwTagId,
349 &dwSize);
350 if (dwError != ERROR_SUCCESS)
351 dwTagId = 0;
352
353 DPRINT("Tag: %lx\n", dwTagId);
354
355 dwError = ScmReadString(hServiceKey,
356 L"Group",
357 &lpGroup);
358 if (dwError != ERROR_SUCCESS)
359 lpGroup = NULL;
360
361 DPRINT("Group: %S\n", lpGroup);
362
363 dwError = ScmReadString(hServiceKey,
364 L"DisplayName",
365 &lpDisplayName);
366 if (dwError != ERROR_SUCCESS)
367 lpDisplayName = NULL;
368
369 DPRINT("Display name: %S\n", lpDisplayName);
370
371 dwError = ScmCreateNewServiceRecord(lpServiceName,
372 &lpService);
373 if (dwError != ERROR_SUCCESS)
374 goto done;
375
376 lpService->Status.dwServiceType = dwServiceType;
377 lpService->dwStartType = dwStartType;
378 lpService->dwErrorControl = dwErrorControl;
379 lpService->dwTag = dwTagId;
380
381 if (lpGroup != NULL)
382 {
383 lpService->lpServiceGroup = lpGroup;
384 lpGroup = NULL;
385 }
386
387 if (lpDisplayName != NULL)
388 {
389 lpService->lpDisplayName = lpDisplayName;
390 lpDisplayName = NULL;
391 }
392
393 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
394 DPRINT("Group: '%S'\n", lpService->lpServiceGroup);
395 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
396 lpService->dwStartType,
397 lpService->Status.dwServiceType,
398 lpService->dwTag,
399 lpService->dwErrorControl);
400
401 if (ScmIsDeleteFlagSet(hServiceKey))
402 lpService->bDeleted = TRUE;
403
404 done:;
405 if (lpGroup != NULL)
406 HeapFree(GetProcessHeap(), 0, lpGroup);
407
408 if (lpDisplayName != NULL)
409 HeapFree(GetProcessHeap(), 0, lpDisplayName);
410
411 return dwError;
412 }
413
414
415 DWORD
416 ScmReadGroupList(VOID)
417 {
418 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
419 NTSTATUS Status;
420
421 InitializeListHead(&GroupListHead);
422
423 /* Build group order list */
424 RtlZeroMemory(&QueryTable,
425 sizeof(QueryTable));
426
427 QueryTable[0].Name = L"List";
428 QueryTable[0].QueryRoutine = CreateGroupListRoutine;
429
430 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
431 L"ServiceGroupOrder",
432 QueryTable,
433 NULL,
434 NULL);
435
436 return RtlNtStatusToDosError(Status);
437 }
438
439
440 VOID
441 ScmDeleteMarkedServices(VOID)
442 {
443 PLIST_ENTRY ServiceEntry;
444 PSERVICE CurrentService;
445
446 ServiceEntry = ServiceListHead.Flink;
447 while (ServiceEntry != &ServiceListHead)
448 {
449 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
450
451 ServiceEntry = ServiceEntry->Flink;
452
453 if (CurrentService->bDeleted == TRUE)
454 {
455 DPRINT1("Delete service: %S\n", CurrentService->lpServiceName);
456
457 /* FIXME: Delete the registry keys */
458
459 /* FIXME: Delete the service record from the list */
460
461 }
462 }
463 }
464
465
466 DWORD
467 ScmCreateServiceDatabase(VOID)
468 {
469 WCHAR szSubKey[MAX_PATH];
470 HKEY hServicesKey;
471 HKEY hServiceKey;
472 DWORD dwSubKey;
473 DWORD dwSubKeyLength;
474 FILETIME ftLastChanged;
475 DWORD dwError;
476
477 DPRINT("ScmCreateServiceDatabase() called\n");
478
479 dwError = ScmReadGroupList();
480 if (dwError != ERROR_SUCCESS)
481 return dwError;
482
483 /* Initialize basic variables */
484 InitializeListHead(&ServiceListHead);
485
486 /* Initialize the database lock */
487 RtlInitializeResource(&DatabaseLock);
488
489 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
490 L"System\\CurrentControlSet\\Services",
491 0,
492 KEY_READ,
493 &hServicesKey);
494 if (dwError != ERROR_SUCCESS)
495 return dwError;
496
497 dwSubKey = 0;
498 for (;;)
499 {
500 dwSubKeyLength = MAX_PATH;
501 dwError = RegEnumKeyExW(hServicesKey,
502 dwSubKey,
503 szSubKey,
504 &dwSubKeyLength,
505 NULL,
506 NULL,
507 NULL,
508 &ftLastChanged);
509 if (dwError == ERROR_SUCCESS &&
510 szSubKey[0] != L'{')
511 {
512 DPRINT("SubKeyName: '%S'\n", szSubKey);
513
514 dwError = RegOpenKeyExW(hServicesKey,
515 szSubKey,
516 0,
517 KEY_READ,
518 &hServiceKey);
519 if (dwError == ERROR_SUCCESS)
520 {
521 dwError = CreateServiceListEntry(szSubKey,
522 hServiceKey);
523
524 RegCloseKey(hServiceKey);
525 }
526 }
527
528 if (dwError != ERROR_SUCCESS)
529 break;
530
531 dwSubKey++;
532 }
533
534 RegCloseKey(hServicesKey);
535
536 /* Delete services that are marked for delete */
537 ScmDeleteMarkedServices();
538
539 DPRINT("ScmCreateServiceDatabase() done\n");
540
541 return ERROR_SUCCESS;
542 }
543
544
545 static NTSTATUS
546 ScmCheckDriver(PSERVICE Service)
547 {
548 OBJECT_ATTRIBUTES ObjectAttributes;
549 UNICODE_STRING DirName;
550 HANDLE DirHandle;
551 NTSTATUS Status;
552 POBJECT_DIRECTORY_INFORMATION DirInfo;
553 ULONG BufferLength;
554 ULONG DataLength;
555 ULONG Index;
556 PLIST_ENTRY GroupEntry;
557 PSERVICE_GROUP CurrentGroup;
558
559 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
560
561 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
562 {
563 RtlInitUnicodeString(&DirName,
564 L"\\Driver");
565 }
566 else
567 {
568 RtlInitUnicodeString(&DirName,
569 L"\\FileSystem");
570 }
571
572 InitializeObjectAttributes(&ObjectAttributes,
573 &DirName,
574 0,
575 NULL,
576 NULL);
577
578 Status = NtOpenDirectoryObject(&DirHandle,
579 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
580 &ObjectAttributes);
581 if (!NT_SUCCESS(Status))
582 {
583 return Status;
584 }
585
586 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
587 2 * MAX_PATH * sizeof(WCHAR);
588 DirInfo = HeapAlloc(GetProcessHeap(),
589 HEAP_ZERO_MEMORY,
590 BufferLength);
591
592 Index = 0;
593 while (TRUE)
594 {
595 Status = NtQueryDirectoryObject(DirHandle,
596 DirInfo,
597 BufferLength,
598 TRUE,
599 FALSE,
600 &Index,
601 &DataLength);
602 if (Status == STATUS_NO_MORE_ENTRIES)
603 {
604 /* FIXME: Add current service to 'failed service' list */
605 DPRINT("Service '%S' failed\n", Service->lpServiceName);
606 break;
607 }
608
609 if (!NT_SUCCESS(Status))
610 break;
611
612 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->ObjectName);
613
614 if (_wcsicmp(Service->lpServiceName, DirInfo->ObjectName.Buffer) == 0)
615 {
616 DPRINT("Found: '%S' '%wZ'\n",
617 Service->lpServiceName, &DirInfo->ObjectName);
618
619 /* Mark service as 'running' */
620 Service->Status.dwCurrentState = SERVICE_RUNNING;
621
622 /* Find the driver's group and mark it as 'running' */
623 if (Service->lpServiceGroup != NULL)
624 {
625 GroupEntry = GroupListHead.Flink;
626 while (GroupEntry != &GroupListHead)
627 {
628 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
629
630 DPRINT("Checking group '%wZ'\n", &CurrentGroup->GroupName);
631 if (Service->lpServiceGroup != NULL &&
632 _wcsicmp(Service->lpServiceGroup, CurrentGroup->GroupName.Buffer) == 0)
633 {
634 CurrentGroup->ServicesRunning = TRUE;
635 }
636
637 GroupEntry = GroupEntry->Flink;
638 }
639 }
640 break;
641 }
642 }
643
644 HeapFree(GetProcessHeap(),
645 0,
646 DirInfo);
647 NtClose(DirHandle);
648
649 return STATUS_SUCCESS;
650 }
651
652
653 VOID
654 ScmGetBootAndSystemDriverState(VOID)
655 {
656 PLIST_ENTRY ServiceEntry;
657 PSERVICE CurrentService;
658
659 DPRINT("ScmGetBootAndSystemDriverState() called\n");
660
661 ServiceEntry = ServiceListHead.Flink;
662 while (ServiceEntry != &ServiceListHead)
663 {
664 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
665
666 if (CurrentService->dwStartType == SERVICE_BOOT_START ||
667 CurrentService->dwStartType == SERVICE_SYSTEM_START)
668 {
669 /* Check driver */
670 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
671
672 ScmCheckDriver(CurrentService);
673 }
674
675 ServiceEntry = ServiceEntry->Flink;
676 }
677
678 DPRINT("ScmGetBootAndSystemDriverState() done\n");
679 }
680
681
682 static NTSTATUS
683 ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
684 {
685 PSCM_START_PACKET StartPacket;
686 DWORD TotalLength;
687 #if 0
688 DWORD Length;
689 #endif
690 PWSTR Ptr;
691 DWORD Count;
692
693 DPRINT("ScmSendStartCommand() called\n");
694
695 /* Calculate the total length of the start command line */
696 TotalLength = wcslen(Service->lpServiceName) + 1;
697 #if 0
698 if (Arguments != NULL)
699 {
700 Ptr = Arguments;
701 while (*Ptr)
702 {
703 Length = wcslen(Ptr) + 1;
704 TotalLength += Length;
705 Ptr += Length;
706 }
707 }
708 #endif
709 TotalLength++;
710
711 /* Allocate start command packet */
712 StartPacket = HeapAlloc(GetProcessHeap(),
713 HEAP_ZERO_MEMORY,
714 sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
715 if (StartPacket == NULL)
716 return STATUS_INSUFFICIENT_RESOURCES;
717
718 StartPacket->Command = SCM_START_COMMAND;
719 StartPacket->Size = TotalLength;
720 Ptr = &StartPacket->Arguments[0];
721 wcscpy(Ptr, Service->lpServiceName);
722 Ptr += (wcslen(Service->lpServiceName) + 1);
723
724 /* FIXME: Copy argument list */
725
726 *Ptr = 0;
727
728 /* Send the start command */
729 WriteFile(Service->ControlPipeHandle,
730 StartPacket,
731 sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
732 &Count,
733 NULL);
734
735 /* FIXME: Read the reply */
736
737 HeapFree(GetProcessHeap(),
738 0,
739 StartPacket);
740
741 DPRINT("ScmSendStartCommand() done\n");
742
743 return STATUS_SUCCESS;
744 }
745
746
747 static NTSTATUS
748 ScmStartUserModeService(PSERVICE Service)
749 {
750 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
751 PROCESS_INFORMATION ProcessInformation;
752 STARTUPINFOW StartupInfo;
753 UNICODE_STRING ImagePath;
754 ULONG Type;
755 BOOL Result;
756 NTSTATUS Status;
757
758 RtlInitUnicodeString(&ImagePath, NULL);
759
760 /* Get service data */
761 RtlZeroMemory(&QueryTable,
762 sizeof(QueryTable));
763
764 QueryTable[0].Name = L"Type";
765 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
766 QueryTable[0].EntryContext = &Type;
767
768 QueryTable[1].Name = L"ImagePath";
769 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
770 QueryTable[1].EntryContext = &ImagePath;
771
772 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
773 Service->lpServiceName,
774 QueryTable,
775 NULL,
776 NULL);
777 if (!NT_SUCCESS(Status))
778 {
779 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
780 return Status;
781 }
782 DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
783 DPRINT("Type: %lx\n", Type);
784
785 /* Create '\\.\pipe\net\NtControlPipe' instance */
786 Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
787 PIPE_ACCESS_DUPLEX,
788 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
789 100,
790 8000,
791 4,
792 30000,
793 NULL);
794 DPRINT("CreateNamedPipeW() done\n");
795 if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
796 {
797 DPRINT1("Failed to create control pipe!\n");
798 return STATUS_UNSUCCESSFUL;
799 }
800
801 StartupInfo.cb = sizeof(StartupInfo);
802 StartupInfo.lpReserved = NULL;
803 StartupInfo.lpDesktop = NULL;
804 StartupInfo.lpTitle = NULL;
805 StartupInfo.dwFlags = 0;
806 StartupInfo.cbReserved2 = 0;
807 StartupInfo.lpReserved2 = 0;
808
809 Result = CreateProcessW(ImagePath.Buffer,
810 NULL,
811 NULL,
812 NULL,
813 FALSE,
814 DETACHED_PROCESS | CREATE_SUSPENDED,
815 NULL,
816 NULL,
817 &StartupInfo,
818 &ProcessInformation);
819 RtlFreeUnicodeString(&ImagePath);
820
821 if (!Result)
822 {
823 /* Close control pipe */
824 CloseHandle(Service->ControlPipeHandle);
825 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
826
827 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
828 return STATUS_UNSUCCESSFUL;
829 }
830
831 DPRINT("Process Id: %lu Handle %lx\n",
832 ProcessInformation.dwProcessId,
833 ProcessInformation.hProcess);
834 DPRINT("Thread Id: %lu Handle %lx\n",
835 ProcessInformation.dwThreadId,
836 ProcessInformation.hThread);
837
838 /* Get process and thread ids */
839 Service->ProcessId = ProcessInformation.dwProcessId;
840 Service->ThreadId = ProcessInformation.dwThreadId;
841
842 /* Resume Thread */
843 ResumeThread(ProcessInformation.hThread);
844
845 /* Connect control pipe */
846 if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
847 {
848 DWORD dwProcessId = 0;
849 DWORD dwRead = 0;
850
851 DPRINT("Control pipe connected!\n");
852
853 /* Read thread id from pipe */
854 if (!ReadFile(Service->ControlPipeHandle,
855 (LPVOID)&dwProcessId,
856 sizeof(DWORD),
857 &dwRead,
858 NULL))
859 {
860 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
861 GetLastError());
862 Status = STATUS_UNSUCCESSFUL;
863 }
864 else
865 {
866 DPRINT("Received process id %lu\n", dwProcessId);
867
868 /* FIXME: Send start command */
869
870 Status = STATUS_SUCCESS;
871 }
872 }
873 else
874 {
875 DPRINT("Connecting control pipe failed!\n");
876
877 /* Close control pipe */
878 CloseHandle(Service->ControlPipeHandle);
879 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
880 Service->ProcessId = 0;
881 Service->ThreadId = 0;
882 Status = STATUS_UNSUCCESSFUL;
883 }
884
885 ScmSendStartCommand(Service, NULL);
886
887 /* Close process and thread handle */
888 CloseHandle(ProcessInformation.hThread);
889 CloseHandle(ProcessInformation.hProcess);
890
891 return Status;
892 }
893
894
895 static NTSTATUS
896 ScmStartService(PSERVICE Service,
897 PSERVICE_GROUP Group)
898 {
899 NTSTATUS Status;
900
901 DPRINT("ScmStartService() called\n");
902
903 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
904 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
905
906 if (Service->Status.dwServiceType & SERVICE_DRIVER)
907 {
908 /* Load driver */
909 Status = ScmLoadDriver(Service);
910 if (Status == STATUS_SUCCESS)
911 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
912 }
913 else
914 {
915 /* Start user-mode service */
916 Status = ScmStartUserModeService(Service);
917 }
918
919 DPRINT("ScmStartService() done (Status %lx)\n", Status);
920
921 if (NT_SUCCESS(Status))
922 {
923 if (Group != NULL)
924 {
925 Group->ServicesRunning = TRUE;
926 }
927 Service->Status.dwCurrentState = SERVICE_RUNNING;
928 }
929 #if 0
930 else
931 {
932 switch (Service->ErrorControl)
933 {
934 case SERVICE_ERROR_NORMAL:
935 /* FIXME: Log error */
936 break;
937
938 case SERVICE_ERROR_SEVERE:
939 if (IsLastKnownGood == FALSE)
940 {
941 /* FIXME: Boot last known good configuration */
942 }
943 break;
944
945 case SERVICE_ERROR_CRITICAL:
946 if (IsLastKnownGood == FALSE)
947 {
948 /* FIXME: Boot last known good configuration */
949 }
950 else
951 {
952 /* FIXME: BSOD! */
953 }
954 break;
955 }
956 }
957 #endif
958
959 return Status;
960 }
961
962
963 VOID
964 ScmAutoStartServices(VOID)
965 {
966 PLIST_ENTRY GroupEntry;
967 PLIST_ENTRY ServiceEntry;
968 PSERVICE_GROUP CurrentGroup;
969 PSERVICE CurrentService;
970 ULONG i;
971
972 /* Clear 'ServiceVisited' flag */
973 ServiceEntry = ServiceListHead.Flink;
974 while (ServiceEntry != &ServiceListHead)
975 {
976 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
977 CurrentService->ServiceVisited = FALSE;
978 ServiceEntry = ServiceEntry->Flink;
979 }
980
981 /* Start all services which are members of an existing group */
982 GroupEntry = GroupListHead.Flink;
983 while (GroupEntry != &GroupListHead)
984 {
985 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
986
987 DPRINT("Group '%wZ'\n", &CurrentGroup->GroupName);
988
989 /* Start all services witch have a valid tag */
990 for (i = 0; i < CurrentGroup->TagCount; i++)
991 {
992 ServiceEntry = ServiceListHead.Flink;
993 while (ServiceEntry != &ServiceListHead)
994 {
995 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
996
997 if ((CurrentService->lpServiceGroup != NULL) &&
998 (_wcsicmp(CurrentGroup->GroupName.Buffer, CurrentService->lpServiceGroup) == 0) &&
999 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1000 (CurrentService->ServiceVisited == FALSE) &&
1001 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
1002 {
1003 CurrentService->ServiceVisited = TRUE;
1004 ScmStartService(CurrentService,
1005 CurrentGroup);
1006 }
1007
1008 ServiceEntry = ServiceEntry->Flink;
1009 }
1010 }
1011
1012 /* Start all services which have an invalid tag or which do not have a tag */
1013 ServiceEntry = ServiceListHead.Flink;
1014 while (ServiceEntry != &ServiceListHead)
1015 {
1016 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1017
1018 if ((CurrentService->lpServiceGroup != NULL) &&
1019 (_wcsicmp(CurrentGroup->GroupName.Buffer, CurrentService->lpServiceGroup) == 0) &&
1020 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1021 (CurrentService->ServiceVisited == FALSE))
1022 {
1023 CurrentService->ServiceVisited = TRUE;
1024 ScmStartService(CurrentService,
1025 CurrentGroup);
1026 }
1027
1028 ServiceEntry = ServiceEntry->Flink;
1029 }
1030
1031 GroupEntry = GroupEntry->Flink;
1032 }
1033
1034 /* Start all services which are members of any non-existing group */
1035 ServiceEntry = ServiceListHead.Flink;
1036 while (ServiceEntry != &ServiceListHead)
1037 {
1038 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1039
1040 if ((CurrentService->lpServiceGroup != NULL) &&
1041 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1042 (CurrentService->ServiceVisited == FALSE))
1043 {
1044 CurrentService->ServiceVisited = TRUE;
1045 ScmStartService(CurrentService,
1046 NULL);
1047 }
1048
1049 ServiceEntry = ServiceEntry->Flink;
1050 }
1051
1052 /* Start all services which are not a member of any group */
1053 ServiceEntry = ServiceListHead.Flink;
1054 while (ServiceEntry != &ServiceListHead)
1055 {
1056 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1057
1058 if ((CurrentService->lpServiceGroup == NULL) &&
1059 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1060 (CurrentService->ServiceVisited == FALSE))
1061 {
1062 CurrentService->ServiceVisited = TRUE;
1063 ScmStartService(CurrentService,
1064 NULL);
1065 }
1066
1067 ServiceEntry = ServiceEntry->Flink;
1068 }
1069
1070 /* Clear 'ServiceVisited' flag again */
1071 ServiceEntry = ServiceListHead.Flink;
1072 while (ServiceEntry != &ServiceListHead)
1073 {
1074 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1075 CurrentService->ServiceVisited = FALSE;
1076 ServiceEntry = ServiceEntry->Flink;
1077 }
1078 }
1079
1080 /* EOF */