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