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