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