[IPCONFIG] Implement the /flushdns option and most of the /displaydns option
[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
44 BOOL
45 ScmIsSecurityService(
46 _In_ PSERVICE_IMAGE pServiceImage)
47 {
48 return (wcsstr(pServiceImage->pszImagePath, L"\\system32\\lsass.exe") != NULL);
49 }
50
51
52 static DWORD
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
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
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->dwTag == 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
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
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
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 the 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
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))
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
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
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
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
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
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
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->dwTag = ServiceTag;
761
762 return ERROR_SUCCESS;
763 }
764
765
766 DWORD
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
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
856 static DWORD
857 CreateServiceListEntry(LPCWSTR lpServiceName,
858 HKEY hServiceKey)
859 {
860 PSERVICE lpService = NULL;
861 LPWSTR lpDisplayName = NULL;
862 LPWSTR lpGroup = NULL;
863 DWORD dwSize;
864 DWORD dwError;
865 DWORD dwServiceType;
866 DWORD dwStartType;
867 DWORD dwErrorControl;
868 DWORD dwTagId;
869
870 DPRINT("Service: '%S'\n", lpServiceName);
871 if (*lpServiceName == L'{')
872 return ERROR_SUCCESS;
873
874 dwSize = sizeof(DWORD);
875 dwError = RegQueryValueExW(hServiceKey,
876 L"Type",
877 NULL,
878 NULL,
879 (LPBYTE)&dwServiceType,
880 &dwSize);
881 if (dwError != ERROR_SUCCESS)
882 return ERROR_SUCCESS;
883
884 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
885 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) &&
886 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
887 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
888 return ERROR_SUCCESS;
889
890 DPRINT("Service type: %lx\n", dwServiceType);
891
892 dwSize = sizeof(DWORD);
893 dwError = RegQueryValueExW(hServiceKey,
894 L"Start",
895 NULL,
896 NULL,
897 (LPBYTE)&dwStartType,
898 &dwSize);
899 if (dwError != ERROR_SUCCESS)
900 return ERROR_SUCCESS;
901
902 DPRINT("Start type: %lx\n", dwStartType);
903
904 dwSize = sizeof(DWORD);
905 dwError = RegQueryValueExW(hServiceKey,
906 L"ErrorControl",
907 NULL,
908 NULL,
909 (LPBYTE)&dwErrorControl,
910 &dwSize);
911 if (dwError != ERROR_SUCCESS)
912 return ERROR_SUCCESS;
913
914 DPRINT("Error control: %lx\n", dwErrorControl);
915
916 dwError = RegQueryValueExW(hServiceKey,
917 L"Tag",
918 NULL,
919 NULL,
920 (LPBYTE)&dwTagId,
921 &dwSize);
922 if (dwError != ERROR_SUCCESS)
923 dwTagId = 0;
924
925 DPRINT("Tag: %lx\n", dwTagId);
926
927 dwError = ScmReadString(hServiceKey,
928 L"Group",
929 &lpGroup);
930 if (dwError != ERROR_SUCCESS)
931 lpGroup = NULL;
932
933 DPRINT("Group: %S\n", lpGroup);
934
935 dwError = ScmReadString(hServiceKey,
936 L"DisplayName",
937 &lpDisplayName);
938 if (dwError != ERROR_SUCCESS)
939 lpDisplayName = NULL;
940
941 DPRINT("Display name: %S\n", lpDisplayName);
942
943 dwError = ScmCreateNewServiceRecord(lpServiceName,
944 &lpService,
945 dwServiceType,
946 dwStartType);
947 if (dwError != ERROR_SUCCESS)
948 goto done;
949
950 lpService->dwErrorControl = dwErrorControl;
951 lpService->dwTag = dwTagId;
952
953 if (lpGroup != NULL)
954 {
955 dwError = ScmSetServiceGroup(lpService, lpGroup);
956 if (dwError != ERROR_SUCCESS)
957 goto done;
958 }
959
960 if (lpDisplayName != NULL)
961 {
962 lpService->lpDisplayName = lpDisplayName;
963 lpDisplayName = NULL;
964 }
965
966 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
967 if (lpService->lpGroup != NULL)
968 {
969 DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName);
970 }
971 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
972 lpService->dwStartType,
973 lpService->Status.dwServiceType,
974 lpService->dwTag,
975 lpService->dwErrorControl);
976
977 if (ScmIsDeleteFlagSet(hServiceKey))
978 lpService->bDeleted = TRUE;
979 else
980 ScmGenerateServiceTag(lpService);
981
982 if (lpService->Status.dwServiceType & SERVICE_WIN32)
983 {
984 dwError = ScmReadSecurityDescriptor(hServiceKey,
985 &lpService->pSecurityDescriptor);
986 if (dwError != ERROR_SUCCESS)
987 goto done;
988
989 /* Assing the default security descriptor if the security descriptor cannot be read */
990 if (lpService->pSecurityDescriptor == NULL)
991 {
992 DPRINT("No security descriptor found! Assign default security descriptor!\n");
993 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
994 if (dwError != ERROR_SUCCESS)
995 goto done;
996
997 dwError = ScmWriteSecurityDescriptor(hServiceKey,
998 lpService->pSecurityDescriptor);
999 if (dwError != ERROR_SUCCESS)
1000 goto done;
1001 }
1002 }
1003
1004 done:
1005 if (lpGroup != NULL)
1006 HeapFree(GetProcessHeap(), 0, lpGroup);
1007
1008 if (lpDisplayName != NULL)
1009 HeapFree(GetProcessHeap(), 0, lpDisplayName);
1010
1011 if (lpService != NULL)
1012 {
1013 ASSERT(lpService->lpImage == NULL);
1014 }
1015
1016 return dwError;
1017 }
1018
1019
1020 VOID
1021 ScmDeleteMarkedServices(VOID)
1022 {
1023 PLIST_ENTRY ServiceEntry;
1024 PSERVICE CurrentService;
1025 HKEY hServicesKey;
1026 DWORD dwError;
1027
1028 ServiceEntry = ServiceListHead.Flink;
1029 while (ServiceEntry != &ServiceListHead)
1030 {
1031 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1032
1033 ServiceEntry = ServiceEntry->Flink;
1034
1035 if (CurrentService->bDeleted != FALSE)
1036 {
1037 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1038 L"System\\CurrentControlSet\\Services",
1039 0,
1040 DELETE,
1041 &hServicesKey);
1042 if (dwError == ERROR_SUCCESS)
1043 {
1044 dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName);
1045 RegCloseKey(hServicesKey);
1046 if (dwError == ERROR_SUCCESS)
1047 {
1048 RemoveEntryList(&CurrentService->ServiceListEntry);
1049 HeapFree(GetProcessHeap(), 0, CurrentService);
1050 }
1051 }
1052
1053 if (dwError != ERROR_SUCCESS)
1054 DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName);
1055 }
1056 }
1057 }
1058
1059
1060 static
1061 VOID
1062 ScmGetNoInteractiveServicesValue(VOID)
1063 {
1064 HKEY hKey;
1065 DWORD dwKeySize;
1066 LONG lError;
1067
1068 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1069 L"SYSTEM\\CurrentControlSet\\Control\\Windows",
1070 0,
1071 KEY_READ,
1072 &hKey);
1073 if (lError == ERROR_SUCCESS)
1074 {
1075 dwKeySize = sizeof(NoInteractiveServices);
1076 lError = RegQueryValueExW(hKey,
1077 L"NoInteractiveServices",
1078 0,
1079 NULL,
1080 (LPBYTE)&NoInteractiveServices,
1081 &dwKeySize);
1082 RegCloseKey(hKey);
1083 }
1084 }
1085
1086
1087 DWORD
1088 ScmCreateServiceDatabase(VOID)
1089 {
1090 WCHAR szSubKey[MAX_PATH];
1091 HKEY hServicesKey;
1092 HKEY hServiceKey;
1093 DWORD dwSubKey;
1094 DWORD dwSubKeyLength;
1095 FILETIME ftLastChanged;
1096 DWORD dwError;
1097
1098 DPRINT("ScmCreateServiceDatabase() called\n");
1099
1100 /* Retrieve the NoInteractiveServies value */
1101 ScmGetNoInteractiveServicesValue();
1102
1103 /* Create the service group list */
1104 dwError = ScmCreateGroupList();
1105 if (dwError != ERROR_SUCCESS)
1106 return dwError;
1107
1108 /* Initialize image and service lists */
1109 InitializeListHead(&ImageListHead);
1110 InitializeListHead(&ServiceListHead);
1111
1112 /* Initialize the database lock */
1113 RtlInitializeResource(&DatabaseLock);
1114
1115 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1116 L"System\\CurrentControlSet\\Services",
1117 0,
1118 KEY_READ,
1119 &hServicesKey);
1120 if (dwError != ERROR_SUCCESS)
1121 return dwError;
1122
1123 dwSubKey = 0;
1124 for (;;)
1125 {
1126 dwSubKeyLength = MAX_PATH;
1127 dwError = RegEnumKeyExW(hServicesKey,
1128 dwSubKey,
1129 szSubKey,
1130 &dwSubKeyLength,
1131 NULL,
1132 NULL,
1133 NULL,
1134 &ftLastChanged);
1135 if (dwError == ERROR_SUCCESS &&
1136 szSubKey[0] != L'{')
1137 {
1138 DPRINT("SubKeyName: '%S'\n", szSubKey);
1139
1140 dwError = RegOpenKeyExW(hServicesKey,
1141 szSubKey,
1142 0,
1143 KEY_READ,
1144 &hServiceKey);
1145 if (dwError == ERROR_SUCCESS)
1146 {
1147 dwError = CreateServiceListEntry(szSubKey,
1148 hServiceKey);
1149
1150 RegCloseKey(hServiceKey);
1151 }
1152 }
1153
1154 if (dwError != ERROR_SUCCESS)
1155 break;
1156
1157 dwSubKey++;
1158 }
1159
1160 RegCloseKey(hServicesKey);
1161
1162 /* Wait for the LSA server */
1163 ScmWaitForLsa();
1164
1165 /* Delete services that are marked for delete */
1166 ScmDeleteMarkedServices();
1167
1168 DPRINT("ScmCreateServiceDatabase() done\n");
1169
1170 return ERROR_SUCCESS;
1171 }
1172
1173
1174 VOID
1175 ScmShutdownServiceDatabase(VOID)
1176 {
1177 DPRINT("ScmShutdownServiceDatabase() called\n");
1178
1179 ScmDeleteMarkedServices();
1180 RtlDeleteResource(&DatabaseLock);
1181
1182 DPRINT("ScmShutdownServiceDatabase() done\n");
1183 }
1184
1185
1186 static NTSTATUS
1187 ScmCheckDriver(PSERVICE Service)
1188 {
1189 OBJECT_ATTRIBUTES ObjectAttributes;
1190 UNICODE_STRING DirName;
1191 HANDLE DirHandle;
1192 NTSTATUS Status;
1193 POBJECT_DIRECTORY_INFORMATION DirInfo;
1194 ULONG BufferLength;
1195 ULONG DataLength;
1196 ULONG Index;
1197
1198 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
1199
1200 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
1201 {
1202 RtlInitUnicodeString(&DirName, L"\\Driver");
1203 }
1204 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
1205 {
1206 ASSERT(Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER);
1207 RtlInitUnicodeString(&DirName, L"\\FileSystem");
1208 }
1209
1210 InitializeObjectAttributes(&ObjectAttributes,
1211 &DirName,
1212 0,
1213 NULL,
1214 NULL);
1215
1216 Status = NtOpenDirectoryObject(&DirHandle,
1217 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
1218 &ObjectAttributes);
1219 if (!NT_SUCCESS(Status))
1220 {
1221 return Status;
1222 }
1223
1224 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
1225 2 * MAX_PATH * sizeof(WCHAR);
1226 DirInfo = HeapAlloc(GetProcessHeap(),
1227 HEAP_ZERO_MEMORY,
1228 BufferLength);
1229
1230 Index = 0;
1231 while (TRUE)
1232 {
1233 Status = NtQueryDirectoryObject(DirHandle,
1234 DirInfo,
1235 BufferLength,
1236 TRUE,
1237 FALSE,
1238 &Index,
1239 &DataLength);
1240 if (Status == STATUS_NO_MORE_ENTRIES)
1241 {
1242 /* FIXME: Add current service to 'failed service' list */
1243 DPRINT("Service '%S' failed\n", Service->lpServiceName);
1244 break;
1245 }
1246
1247 if (!NT_SUCCESS(Status))
1248 break;
1249
1250 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
1251
1252 if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
1253 {
1254 DPRINT("Found: '%S' '%wZ'\n",
1255 Service->lpServiceName, &DirInfo->Name);
1256
1257 /* Mark service as 'running' */
1258 Service->Status.dwCurrentState = SERVICE_RUNNING;
1259 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
1260 Service->Status.dwWin32ExitCode = ERROR_SUCCESS;
1261 Service->Status.dwServiceSpecificExitCode = 0;
1262 Service->Status.dwCheckPoint = 0;
1263 Service->Status.dwWaitHint = 0;
1264
1265 /* Mark the service group as 'running' */
1266 if (Service->lpGroup != NULL)
1267 {
1268 Service->lpGroup->ServicesRunning = TRUE;
1269 }
1270
1271 break;
1272 }
1273 }
1274
1275 HeapFree(GetProcessHeap(),
1276 0,
1277 DirInfo);
1278 NtClose(DirHandle);
1279
1280 return STATUS_SUCCESS;
1281 }
1282
1283
1284 VOID
1285 ScmGetBootAndSystemDriverState(VOID)
1286 {
1287 PLIST_ENTRY ServiceEntry;
1288 PSERVICE CurrentService;
1289
1290 DPRINT("ScmGetBootAndSystemDriverState() called\n");
1291
1292 ServiceEntry = ServiceListHead.Flink;
1293 while (ServiceEntry != &ServiceListHead)
1294 {
1295 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1296
1297 if (CurrentService->dwStartType == SERVICE_BOOT_START ||
1298 CurrentService->dwStartType == SERVICE_SYSTEM_START)
1299 {
1300 /* Check driver */
1301 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
1302
1303 ScmCheckDriver(CurrentService);
1304 }
1305
1306 ServiceEntry = ServiceEntry->Flink;
1307 }
1308
1309 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1310 }
1311
1312
1313 DWORD
1314 ScmControlService(HANDLE hControlPipe,
1315 PWSTR pServiceName,
1316 SERVICE_STATUS_HANDLE hServiceStatus,
1317 DWORD dwControl)
1318 {
1319 PSCM_CONTROL_PACKET ControlPacket;
1320 SCM_REPLY_PACKET ReplyPacket;
1321
1322 DWORD dwWriteCount = 0;
1323 DWORD dwReadCount = 0;
1324 DWORD PacketSize;
1325 PWSTR Ptr;
1326 DWORD dwError = ERROR_SUCCESS;
1327 BOOL bResult;
1328 OVERLAPPED Overlapped = {0};
1329
1330 DPRINT("ScmControlService() called\n");
1331
1332 /* Acquire the service control critical section, to synchronize requests */
1333 EnterCriticalSection(&ControlServiceCriticalSection);
1334
1335 /* Calculate the total length of the start command line */
1336 PacketSize = sizeof(SCM_CONTROL_PACKET);
1337 PacketSize += (DWORD)((wcslen(pServiceName) + 1) * sizeof(WCHAR));
1338
1339 ControlPacket = HeapAlloc(GetProcessHeap(),
1340 HEAP_ZERO_MEMORY,
1341 PacketSize);
1342 if (ControlPacket == NULL)
1343 {
1344 LeaveCriticalSection(&ControlServiceCriticalSection);
1345 return ERROR_NOT_ENOUGH_MEMORY;
1346 }
1347
1348 ControlPacket->dwSize = PacketSize;
1349 ControlPacket->dwControl = dwControl;
1350 ControlPacket->hServiceStatus = hServiceStatus;
1351
1352 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
1353
1354 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
1355 wcscpy(Ptr, pServiceName);
1356
1357 ControlPacket->dwArgumentsCount = 0;
1358 ControlPacket->dwArgumentsOffset = 0;
1359
1360 bResult = WriteFile(hControlPipe,
1361 ControlPacket,
1362 PacketSize,
1363 &dwWriteCount,
1364 &Overlapped);
1365 if (bResult == FALSE)
1366 {
1367 DPRINT("WriteFile() returned FALSE\n");
1368
1369 dwError = GetLastError();
1370 if (dwError == ERROR_IO_PENDING)
1371 {
1372 DPRINT("dwError: ERROR_IO_PENDING\n");
1373
1374 dwError = WaitForSingleObject(hControlPipe,
1375 PipeTimeout);
1376 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1377
1378 if (dwError == WAIT_TIMEOUT)
1379 {
1380 bResult = CancelIo(hControlPipe);
1381 if (bResult == FALSE)
1382 {
1383 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1384 }
1385
1386 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1387 goto Done;
1388 }
1389 else if (dwError == WAIT_OBJECT_0)
1390 {
1391 bResult = GetOverlappedResult(hControlPipe,
1392 &Overlapped,
1393 &dwWriteCount,
1394 TRUE);
1395 if (bResult == FALSE)
1396 {
1397 dwError = GetLastError();
1398 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1399
1400 goto Done;
1401 }
1402 }
1403 }
1404 else
1405 {
1406 DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
1407 goto Done;
1408 }
1409 }
1410
1411 /* Read the reply */
1412 Overlapped.hEvent = (HANDLE) NULL;
1413
1414 bResult = ReadFile(hControlPipe,
1415 &ReplyPacket,
1416 sizeof(SCM_REPLY_PACKET),
1417 &dwReadCount,
1418 &Overlapped);
1419 if (bResult == FALSE)
1420 {
1421 DPRINT("ReadFile() returned FALSE\n");
1422
1423 dwError = GetLastError();
1424 if (dwError == ERROR_IO_PENDING)
1425 {
1426 DPRINT("dwError: ERROR_IO_PENDING\n");
1427
1428 dwError = WaitForSingleObject(hControlPipe,
1429 PipeTimeout);
1430 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1431
1432 if (dwError == WAIT_TIMEOUT)
1433 {
1434 bResult = CancelIo(hControlPipe);
1435 if (bResult == FALSE)
1436 {
1437 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1438 }
1439
1440 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1441 goto Done;
1442 }
1443 else if (dwError == WAIT_OBJECT_0)
1444 {
1445 bResult = GetOverlappedResult(hControlPipe,
1446 &Overlapped,
1447 &dwReadCount,
1448 TRUE);
1449 if (bResult == FALSE)
1450 {
1451 dwError = GetLastError();
1452 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1453
1454 goto Done;
1455 }
1456 }
1457 }
1458 else
1459 {
1460 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1461 goto Done;
1462 }
1463 }
1464
1465 Done:
1466 /* Release the control packet */
1467 HeapFree(GetProcessHeap(),
1468 0,
1469 ControlPacket);
1470
1471 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
1472 {
1473 dwError = ReplyPacket.dwError;
1474 }
1475
1476 LeaveCriticalSection(&ControlServiceCriticalSection);
1477
1478 DPRINT("ScmControlService() done\n");
1479
1480 return dwError;
1481 }
1482
1483
1484 static DWORD
1485 ScmSendStartCommand(PSERVICE Service,
1486 DWORD argc,
1487 LPWSTR* argv)
1488 {
1489 DWORD dwError = ERROR_SUCCESS;
1490 PSCM_CONTROL_PACKET ControlPacket;
1491 SCM_REPLY_PACKET ReplyPacket;
1492 DWORD PacketSize;
1493 DWORD i;
1494 PWSTR Ptr;
1495 PWSTR *pOffPtr;
1496 PWSTR pArgPtr;
1497 BOOL bResult;
1498 DWORD dwWriteCount = 0;
1499 DWORD dwReadCount = 0;
1500 OVERLAPPED Overlapped = {0};
1501
1502 DPRINT("ScmSendStartCommand() called\n");
1503
1504 /* Calculate the total length of the start command line */
1505 PacketSize = sizeof(SCM_CONTROL_PACKET);
1506 PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
1507
1508 /*
1509 * Calculate the required packet size for the start argument vector 'argv',
1510 * composed of the list of pointer offsets, followed by UNICODE strings.
1511 * The strings are stored continuously after the vector of offsets, with
1512 * the offsets being relative to the beginning of the vector, as in the
1513 * following layout (with N == argc):
1514 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] .
1515 */
1516 if (argc > 0 && argv != NULL)
1517 {
1518 PacketSize = ALIGN_UP(PacketSize, PWSTR);
1519 PacketSize += (argc * sizeof(PWSTR));
1520
1521 DPRINT("Argc: %lu\n", argc);
1522 for (i = 0; i < argc; i++)
1523 {
1524 DPRINT("Argv[%lu]: %S\n", i, argv[i]);
1525 PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR));
1526 }
1527 }
1528
1529 /* Allocate a control packet */
1530 ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PacketSize);
1531 if (ControlPacket == NULL)
1532 return ERROR_NOT_ENOUGH_MEMORY;
1533
1534 ControlPacket->dwSize = PacketSize;
1535 ControlPacket->dwControl = (Service->Status.dwServiceType & SERVICE_WIN32_OWN_PROCESS)
1536 ? SERVICE_CONTROL_START_OWN
1537 : SERVICE_CONTROL_START_SHARE;
1538 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
1539 ControlPacket->dwServiceTag = Service->dwTag;
1540
1541 /* Copy the start command line */
1542 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
1543 Ptr = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset);
1544 wcscpy(Ptr, Service->lpServiceName);
1545
1546 ControlPacket->dwArgumentsCount = 0;
1547 ControlPacket->dwArgumentsOffset = 0;
1548
1549 /* Copy the argument vector */
1550 if (argc > 0 && argv != NULL)
1551 {
1552 Ptr += wcslen(Service->lpServiceName) + 1;
1553 pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR);
1554 pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
1555
1556 ControlPacket->dwArgumentsCount = argc;
1557 ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
1558
1559 DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount);
1560 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset);
1561
1562 for (i = 0; i < argc; i++)
1563 {
1564 wcscpy(pArgPtr, argv[i]);
1565 pOffPtr[i] = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
1566 DPRINT("offset[%lu]: %p\n", i, pOffPtr[i]);
1567 pArgPtr += wcslen(argv[i]) + 1;
1568 }
1569 }
1570
1571 bResult = WriteFile(Service->lpImage->hControlPipe,
1572 ControlPacket,
1573 PacketSize,
1574 &dwWriteCount,
1575 &Overlapped);
1576 if (bResult == FALSE)
1577 {
1578 DPRINT("WriteFile() returned FALSE\n");
1579
1580 dwError = GetLastError();
1581 if (dwError == ERROR_IO_PENDING)
1582 {
1583 DPRINT("dwError: ERROR_IO_PENDING\n");
1584
1585 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1586 PipeTimeout);
1587 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1588
1589 if (dwError == WAIT_TIMEOUT)
1590 {
1591 bResult = CancelIo(Service->lpImage->hControlPipe);
1592 if (bResult == FALSE)
1593 {
1594 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1595 }
1596
1597 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1598 goto Done;
1599 }
1600 else if (dwError == WAIT_OBJECT_0)
1601 {
1602 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1603 &Overlapped,
1604 &dwWriteCount,
1605 TRUE);
1606 if (bResult == FALSE)
1607 {
1608 dwError = GetLastError();
1609 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1610
1611 goto Done;
1612 }
1613 }
1614 }
1615 else
1616 {
1617 DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
1618 goto Done;
1619 }
1620 }
1621
1622 /* Read the reply */
1623 Overlapped.hEvent = (HANDLE) NULL;
1624
1625 bResult = ReadFile(Service->lpImage->hControlPipe,
1626 &ReplyPacket,
1627 sizeof(SCM_REPLY_PACKET),
1628 &dwReadCount,
1629 &Overlapped);
1630 if (bResult == FALSE)
1631 {
1632 DPRINT("ReadFile() returned FALSE\n");
1633
1634 dwError = GetLastError();
1635 if (dwError == ERROR_IO_PENDING)
1636 {
1637 DPRINT("dwError: ERROR_IO_PENDING\n");
1638
1639 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1640 PipeTimeout);
1641 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1642
1643 if (dwError == WAIT_TIMEOUT)
1644 {
1645 bResult = CancelIo(Service->lpImage->hControlPipe);
1646 if (bResult == FALSE)
1647 {
1648 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1649 }
1650
1651 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
1652 goto Done;
1653 }
1654 else if (dwError == WAIT_OBJECT_0)
1655 {
1656 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1657 &Overlapped,
1658 &dwReadCount,
1659 TRUE);
1660 if (bResult == FALSE)
1661 {
1662 dwError = GetLastError();
1663 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1664
1665 goto Done;
1666 }
1667 }
1668 }
1669 else
1670 {
1671 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1672 goto Done;
1673 }
1674 }
1675
1676 Done:
1677 /* Release the control packet */
1678 HeapFree(GetProcessHeap(),
1679 0,
1680 ControlPacket);
1681
1682 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
1683 {
1684 dwError = ReplyPacket.dwError;
1685 }
1686
1687 DPRINT("ScmSendStartCommand() done\n");
1688
1689 return dwError;
1690 }
1691
1692
1693 static DWORD
1694 ScmWaitForServiceConnect(PSERVICE Service)
1695 {
1696 DWORD dwRead = 0;
1697 DWORD dwProcessId = 0;
1698 DWORD dwError = ERROR_SUCCESS;
1699 BOOL bResult;
1700 OVERLAPPED Overlapped = {0};
1701 #if 0
1702 LPCWSTR lpLogStrings[3];
1703 WCHAR szBuffer1[20];
1704 WCHAR szBuffer2[20];
1705 #endif
1706
1707 DPRINT("ScmWaitForServiceConnect()\n");
1708
1709 Overlapped.hEvent = (HANDLE)NULL;
1710
1711 bResult = ConnectNamedPipe(Service->lpImage->hControlPipe,
1712 &Overlapped);
1713 if (bResult == FALSE)
1714 {
1715 DPRINT("ConnectNamedPipe() returned FALSE\n");
1716
1717 dwError = GetLastError();
1718 if (dwError == ERROR_IO_PENDING)
1719 {
1720 DPRINT("dwError: ERROR_IO_PENDING\n");
1721
1722 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1723 PipeTimeout);
1724 DPRINT("WaitForSingleObject() returned %lu\n", dwError);
1725
1726 if (dwError == WAIT_TIMEOUT)
1727 {
1728 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1729
1730 bResult = CancelIo(Service->lpImage->hControlPipe);
1731 if (bResult == FALSE)
1732 {
1733 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1734 }
1735
1736 #if 0
1737 _ultow(PipeTimeout, szBuffer1, 10);
1738 lpLogStrings[0] = Service->lpDisplayName;
1739 lpLogStrings[1] = szBuffer1;
1740
1741 ScmLogEvent(EVENT_CONNECTION_TIMEOUT,
1742 EVENTLOG_ERROR_TYPE,
1743 2,
1744 lpLogStrings);
1745 #endif
1746 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service->lpDisplayName);
1747
1748 return ERROR_SERVICE_REQUEST_TIMEOUT;
1749 }
1750 else if (dwError == WAIT_OBJECT_0)
1751 {
1752 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1753 &Overlapped,
1754 &dwRead,
1755 TRUE);
1756 if (bResult == FALSE)
1757 {
1758 dwError = GetLastError();
1759 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError);
1760
1761 return dwError;
1762 }
1763 }
1764 }
1765 else if (dwError != ERROR_PIPE_CONNECTED)
1766 {
1767 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError);
1768 return dwError;
1769 }
1770 }
1771
1772 DPRINT("Control pipe connected!\n");
1773
1774 Overlapped.hEvent = (HANDLE) NULL;
1775
1776 /* Read the process id from pipe */
1777 bResult = ReadFile(Service->lpImage->hControlPipe,
1778 (LPVOID)&dwProcessId,
1779 sizeof(DWORD),
1780 &dwRead,
1781 &Overlapped);
1782 if (bResult == FALSE)
1783 {
1784 DPRINT("ReadFile() returned FALSE\n");
1785
1786 dwError = GetLastError();
1787 if (dwError == ERROR_IO_PENDING)
1788 {
1789 DPRINT("dwError: ERROR_IO_PENDING\n");
1790
1791 dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
1792 PipeTimeout);
1793 if (dwError == WAIT_TIMEOUT)
1794 {
1795 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1796
1797 bResult = CancelIo(Service->lpImage->hControlPipe);
1798 if (bResult == FALSE)
1799 {
1800 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1801 }
1802
1803 #if 0
1804 _ultow(PipeTimeout, szBuffer1, 10);
1805 lpLogStrings[0] = szBuffer1;
1806
1807 ScmLogEvent(EVENT_READFILE_TIMEOUT,
1808 EVENTLOG_ERROR_TYPE,
1809 1,
1810 lpLogStrings);
1811 #endif
1812 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service->lpDisplayName);
1813
1814 return ERROR_SERVICE_REQUEST_TIMEOUT;
1815 }
1816 else if (dwError == WAIT_OBJECT_0)
1817 {
1818 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1819
1820 DPRINT("Process Id: %lu\n", dwProcessId);
1821
1822 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
1823 &Overlapped,
1824 &dwRead,
1825 TRUE);
1826 if (bResult == FALSE)
1827 {
1828 dwError = GetLastError();
1829 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
1830
1831 return dwError;
1832 }
1833 }
1834 else
1835 {
1836 DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
1837 }
1838 }
1839 else
1840 {
1841 DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
1842 return dwError;
1843 }
1844 }
1845
1846 if ((ScmIsSecurityService(Service->lpImage) == FALSE)&&
1847 (dwProcessId != Service->lpImage->dwProcessId))
1848 {
1849 #if 0
1850 _ultow(Service->lpImage->dwProcessId, szBuffer1, 10);
1851 _ultow(dwProcessId, szBuffer2, 10);
1852
1853 lpLogStrings[0] = Service->lpDisplayName;
1854 lpLogStrings[1] = szBuffer1;
1855 lpLogStrings[2] = szBuffer2;
1856
1857 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED,
1858 EVENTLOG_WARNING_TYPE,
1859 3,
1860 lpLogStrings);
1861 #endif
1862
1863 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service->lpDisplayName);
1864 }
1865
1866 DPRINT("ScmWaitForServiceConnect() done\n");
1867
1868 return ERROR_SUCCESS;
1869 }
1870
1871
1872 static DWORD
1873 ScmStartUserModeService(PSERVICE Service,
1874 DWORD argc,
1875 LPWSTR* argv)
1876 {
1877 PROCESS_INFORMATION ProcessInformation;
1878 STARTUPINFOW StartupInfo;
1879 LPVOID lpEnvironment;
1880 BOOL Result;
1881 DWORD dwError = ERROR_SUCCESS;
1882
1883 DPRINT("ScmStartUserModeService(%p)\n", Service);
1884
1885 /* If the image is already running ... */
1886 if (Service->lpImage->dwImageRunCount > 1)
1887 {
1888 /* ... just send a start command */
1889 return ScmSendStartCommand(Service, argc, argv);
1890 }
1891
1892 /* Otherwise start its process */
1893 ZeroMemory(&StartupInfo, sizeof(StartupInfo));
1894 StartupInfo.cb = sizeof(StartupInfo);
1895 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
1896
1897 if (Service->lpImage->hToken)
1898 {
1899 /* User token: Run the service under the user account */
1900
1901 if (!CreateEnvironmentBlock(&lpEnvironment, Service->lpImage->hToken, FALSE))
1902 {
1903 /* We failed, run the service with the current environment */
1904 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1905 GetLastError(), Service->lpServiceName);
1906 lpEnvironment = NULL;
1907 }
1908
1909 /* Impersonate the new user */
1910 Result = ImpersonateLoggedOnUser(Service->lpImage->hToken);
1911 if (Result)
1912 {
1913 /* Launch the process in the user's logon session */
1914 Result = CreateProcessAsUserW(Service->lpImage->hToken,
1915 NULL,
1916 Service->lpImage->pszImagePath,
1917 NULL,
1918 NULL,
1919 FALSE,
1920 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED,
1921 lpEnvironment,
1922 NULL,
1923 &StartupInfo,
1924 &ProcessInformation);
1925 if (!Result)
1926 dwError = GetLastError();
1927
1928 /* Revert the impersonation */
1929 RevertToSelf();
1930 }
1931 else
1932 {
1933 dwError = GetLastError();
1934 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError);
1935 }
1936 }
1937 else
1938 {
1939 /* No user token: Run the service under the LocalSystem account */
1940
1941 if (!CreateEnvironmentBlock(&lpEnvironment, NULL, TRUE))
1942 {
1943 /* We failed, run the service with the current environment */
1944 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n",
1945 GetLastError(), Service->lpServiceName);
1946 lpEnvironment = NULL;
1947 }
1948
1949 /* Use the interactive desktop if the service is interactive */
1950 if ((NoInteractiveServices == 0) &&
1951 (Service->Status.dwServiceType & SERVICE_INTERACTIVE_PROCESS))
1952 {
1953 StartupInfo.dwFlags |= STARTF_INHERITDESKTOP;
1954 StartupInfo.lpDesktop = L"WinSta0\\Default";
1955 }
1956
1957 if (!ScmIsSecurityService(Service->lpImage))
1958 {
1959 Result = CreateProcessW(NULL,
1960 Service->lpImage->pszImagePath,
1961 NULL,
1962 NULL,
1963 FALSE,
1964 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED,
1965 lpEnvironment,
1966 NULL,
1967 &StartupInfo,
1968 &ProcessInformation);
1969 if (!Result)
1970 dwError = GetLastError();
1971 }
1972 else
1973 {
1974 Result = TRUE;
1975 dwError = ERROR_SUCCESS;
1976 }
1977 }
1978
1979 if (lpEnvironment)
1980 DestroyEnvironmentBlock(lpEnvironment);
1981
1982 if (!Result)
1983 {
1984 DPRINT1("Starting '%S' failed with error %d\n",
1985 Service->lpServiceName, dwError);
1986 return dwError;
1987 }
1988
1989 DPRINT("Process Id: %lu Handle %p\n",
1990 ProcessInformation.dwProcessId,
1991 ProcessInformation.hProcess);
1992 DPRINT("Thread Id: %lu Handle %p\n",
1993 ProcessInformation.dwThreadId,
1994 ProcessInformation.hThread);
1995
1996 /* Get the process handle and ID */
1997 Service->lpImage->hProcess = ProcessInformation.hProcess;
1998 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
1999
2000 /* Resume the main thread and close its handle */
2001 ResumeThread(ProcessInformation.hThread);
2002 CloseHandle(ProcessInformation.hThread);
2003
2004 /* Connect control pipe */
2005 dwError = ScmWaitForServiceConnect(Service);
2006 if (dwError != ERROR_SUCCESS)
2007 {
2008 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
2009 Service->lpImage->dwProcessId = 0;
2010 return dwError;
2011 }
2012
2013 /* Send the start command */
2014 return ScmSendStartCommand(Service, argc, argv);
2015 }
2016
2017
2018 static DWORD
2019 ScmLoadService(PSERVICE Service,
2020 DWORD argc,
2021 LPWSTR* argv)
2022 {
2023 PSERVICE_GROUP Group = Service->lpGroup;
2024 DWORD dwError = ERROR_SUCCESS;
2025 LPCWSTR lpLogStrings[2];
2026 WCHAR szLogBuffer[80];
2027
2028 DPRINT("ScmLoadService() called\n");
2029 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
2030
2031 if (Service->Status.dwCurrentState != SERVICE_STOPPED)
2032 {
2033 DPRINT("Service %S is already running!\n", Service->lpServiceName);
2034 return ERROR_SERVICE_ALREADY_RUNNING;
2035 }
2036
2037 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
2038
2039 if (Service->Status.dwServiceType & SERVICE_DRIVER)
2040 {
2041 /* Start the driver */
2042 dwError = ScmStartDriver(Service);
2043 }
2044 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
2045 {
2046 /* Start user-mode service */
2047 dwError = ScmCreateOrReferenceServiceImage(Service);
2048 if (dwError == ERROR_SUCCESS)
2049 {
2050 dwError = ScmStartUserModeService(Service, argc, argv);
2051 if (dwError == ERROR_SUCCESS)
2052 {
2053 Service->Status.dwCurrentState = SERVICE_START_PENDING;
2054 Service->Status.dwControlsAccepted = 0;
2055 }
2056 else
2057 {
2058 Service->lpImage->dwImageRunCount--;
2059 if (Service->lpImage->dwImageRunCount == 0)
2060 {
2061 ScmRemoveServiceImage(Service->lpImage);
2062 Service->lpImage = NULL;
2063 }
2064 }
2065 }
2066 }
2067
2068 DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
2069
2070 if (dwError == ERROR_SUCCESS)
2071 {
2072 if (Group != NULL)
2073 {
2074 Group->ServicesRunning = TRUE;
2075 }
2076
2077 /* Log a successful service start */
2078 LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_START, szLogBuffer, 80);
2079 lpLogStrings[0] = Service->lpDisplayName;
2080 lpLogStrings[1] = szLogBuffer;
2081
2082 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
2083 EVENTLOG_INFORMATION_TYPE,
2084 2,
2085 lpLogStrings);
2086 }
2087 else
2088 {
2089 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
2090 {
2091 /* Log a failed service start */
2092 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer),
2093 L"%lu", dwError);
2094 lpLogStrings[0] = Service->lpServiceName;
2095 lpLogStrings[1] = szLogBuffer;
2096 ScmLogEvent(EVENT_SERVICE_START_FAILED,
2097 EVENTLOG_ERROR_TYPE,
2098 2,
2099 lpLogStrings);
2100 }
2101
2102 #if 0
2103 switch (Service->dwErrorControl)
2104 {
2105 case SERVICE_ERROR_SEVERE:
2106 if (IsLastKnownGood == FALSE)
2107 {
2108 /* FIXME: Boot last known good configuration */
2109 }
2110 break;
2111
2112 case SERVICE_ERROR_CRITICAL:
2113 if (IsLastKnownGood == FALSE)
2114 {
2115 /* FIXME: Boot last known good configuration */
2116 }
2117 else
2118 {
2119 /* FIXME: BSOD! */
2120 }
2121 break;
2122 }
2123 #endif
2124 }
2125
2126 return dwError;
2127 }
2128
2129
2130 DWORD
2131 ScmStartService(PSERVICE Service,
2132 DWORD argc,
2133 LPWSTR* argv)
2134 {
2135 DWORD dwError = ERROR_SUCCESS;
2136 SC_RPC_LOCK Lock = NULL;
2137
2138 DPRINT("ScmStartService() called\n");
2139 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
2140
2141 /* Acquire the service control critical section, to synchronize starts */
2142 EnterCriticalSection(&ControlServiceCriticalSection);
2143
2144 /*
2145 * Acquire the user service start lock while the service is starting, if
2146 * needed (i.e. if we are not starting it during the initialization phase).
2147 * If we don't success, bail out.
2148 */
2149 if (!ScmInitialize)
2150 {
2151 dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
2152 if (dwError != ERROR_SUCCESS) goto done;
2153 }
2154
2155 /* Really start the service */
2156 dwError = ScmLoadService(Service, argc, argv);
2157
2158 /* Release the service start lock, if needed, and the critical section */
2159 if (Lock) ScmReleaseServiceStartLock(&Lock);
2160
2161 done:
2162 LeaveCriticalSection(&ControlServiceCriticalSection);
2163
2164 DPRINT("ScmStartService() done (Error %lu)\n", dwError);
2165
2166 return dwError;
2167 }
2168
2169
2170 VOID
2171 ScmAutoStartServices(VOID)
2172 {
2173 DWORD dwError;
2174 PLIST_ENTRY GroupEntry;
2175 PLIST_ENTRY ServiceEntry;
2176 PSERVICE_GROUP CurrentGroup;
2177 PSERVICE CurrentService;
2178 WCHAR szSafeBootServicePath[MAX_PATH];
2179 DWORD SafeBootEnabled;
2180 HKEY hKey;
2181 DWORD dwKeySize;
2182 ULONG i;
2183
2184 /*
2185 * This function MUST be called ONLY at initialization time.
2186 * Therefore, no need to acquire the user service start lock.
2187 */
2188 ASSERT(ScmInitialize);
2189
2190 /* Retrieve the SafeBoot parameter */
2191 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2192 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
2193 0,
2194 KEY_READ,
2195 &hKey);
2196 if (dwError == ERROR_SUCCESS)
2197 {
2198 dwKeySize = sizeof(SafeBootEnabled);
2199 dwError = RegQueryValueExW(hKey,
2200 L"OptionValue",
2201 0,
2202 NULL,
2203 (LPBYTE)&SafeBootEnabled,
2204 &dwKeySize);
2205 RegCloseKey(hKey);
2206 }
2207
2208 /* Default to Normal boot if the value doesn't exist */
2209 if (dwError != ERROR_SUCCESS)
2210 SafeBootEnabled = 0;
2211
2212 /* Acquire the service control critical section, to synchronize starts */
2213 EnterCriticalSection(&ControlServiceCriticalSection);
2214
2215 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
2216 ServiceEntry = ServiceListHead.Flink;
2217 while (ServiceEntry != &ServiceListHead)
2218 {
2219 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2220
2221 /* Build the safe boot path */
2222 StringCchCopyW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath),
2223 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
2224
2225 switch (SafeBootEnabled)
2226 {
2227 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
2228 case 1:
2229 case 3:
2230 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath),
2231 L"\\Minimal\\");
2232 break;
2233
2234 case 2:
2235 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath),
2236 L"\\Network\\");
2237 break;
2238 }
2239
2240 if (SafeBootEnabled != 0)
2241 {
2242 /* If key does not exist then do not assume safe mode */
2243 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2244 szSafeBootServicePath,
2245 0,
2246 KEY_READ,
2247 &hKey);
2248 if (dwError == ERROR_SUCCESS)
2249 {
2250 RegCloseKey(hKey);
2251
2252 /* Finish Safe Boot path off */
2253 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath),
2254 CurrentService->lpServiceName);
2255
2256 /* Check that the key is in the Safe Boot path */
2257 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2258 szSafeBootServicePath,
2259 0,
2260 KEY_READ,
2261 &hKey);
2262 if (dwError != ERROR_SUCCESS)
2263 {
2264 /* Mark service as visited so it is not auto-started */
2265 CurrentService->ServiceVisited = TRUE;
2266 }
2267 else
2268 {
2269 /* Must be auto-started in safe mode - mark as unvisited */
2270 RegCloseKey(hKey);
2271 CurrentService->ServiceVisited = FALSE;
2272 }
2273 }
2274 else
2275 {
2276 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
2277 CurrentService->ServiceVisited = FALSE;
2278 }
2279 }
2280
2281 ServiceEntry = ServiceEntry->Flink;
2282 }
2283
2284 /* Start all services which are members of an existing group */
2285 GroupEntry = GroupListHead.Flink;
2286 while (GroupEntry != &GroupListHead)
2287 {
2288 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
2289
2290 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
2291
2292 /* Start all services witch have a valid tag */
2293 for (i = 0; i < CurrentGroup->TagCount; i++)
2294 {
2295 ServiceEntry = ServiceListHead.Flink;
2296 while (ServiceEntry != &ServiceListHead)
2297 {
2298 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2299
2300 if ((CurrentService->lpGroup == CurrentGroup) &&
2301 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2302 (CurrentService->ServiceVisited == FALSE) &&
2303 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
2304 {
2305 CurrentService->ServiceVisited = TRUE;
2306 ScmLoadService(CurrentService, 0, NULL);
2307 }
2308
2309 ServiceEntry = ServiceEntry->Flink;
2310 }
2311 }
2312
2313 /* Start all services which have an invalid tag or which do not have a tag */
2314 ServiceEntry = ServiceListHead.Flink;
2315 while (ServiceEntry != &ServiceListHead)
2316 {
2317 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2318
2319 if ((CurrentService->lpGroup == CurrentGroup) &&
2320 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2321 (CurrentService->ServiceVisited == FALSE))
2322 {
2323 CurrentService->ServiceVisited = TRUE;
2324 ScmLoadService(CurrentService, 0, NULL);
2325 }
2326
2327 ServiceEntry = ServiceEntry->Flink;
2328 }
2329
2330 GroupEntry = GroupEntry->Flink;
2331 }
2332
2333 /* Start all services which are members of any non-existing group */
2334 ServiceEntry = ServiceListHead.Flink;
2335 while (ServiceEntry != &ServiceListHead)
2336 {
2337 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2338
2339 if ((CurrentService->lpGroup != NULL) &&
2340 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2341 (CurrentService->ServiceVisited == FALSE))
2342 {
2343 CurrentService->ServiceVisited = TRUE;
2344 ScmLoadService(CurrentService, 0, NULL);
2345 }
2346
2347 ServiceEntry = ServiceEntry->Flink;
2348 }
2349
2350 /* Start all services which are not a member of any group */
2351 ServiceEntry = ServiceListHead.Flink;
2352 while (ServiceEntry != &ServiceListHead)
2353 {
2354 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2355
2356 if ((CurrentService->lpGroup == NULL) &&
2357 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
2358 (CurrentService->ServiceVisited == FALSE))
2359 {
2360 CurrentService->ServiceVisited = TRUE;
2361 ScmLoadService(CurrentService, 0, NULL);
2362 }
2363
2364 ServiceEntry = ServiceEntry->Flink;
2365 }
2366
2367 /* Clear 'ServiceVisited' flag again */
2368 ServiceEntry = ServiceListHead.Flink;
2369 while (ServiceEntry != &ServiceListHead)
2370 {
2371 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2372 CurrentService->ServiceVisited = FALSE;
2373 ServiceEntry = ServiceEntry->Flink;
2374 }
2375
2376 /* Release the critical section */
2377 LeaveCriticalSection(&ControlServiceCriticalSection);
2378 }
2379
2380
2381 VOID
2382 ScmAutoShutdownServices(VOID)
2383 {
2384 PLIST_ENTRY ServiceEntry;
2385 PSERVICE CurrentService;
2386
2387 DPRINT("ScmAutoShutdownServices() called\n");
2388
2389 /* Lock the service database exclusively */
2390 ScmLockDatabaseExclusive();
2391
2392 ServiceEntry = ServiceListHead.Flink;
2393 while (ServiceEntry != &ServiceListHead)
2394 {
2395 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
2396
2397 if ((CurrentService->Status.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) &&
2398 (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
2399 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING))
2400 {
2401 /* Send the shutdown notification */
2402 DPRINT("Shutdown service: %S\n", CurrentService->lpServiceName);
2403 ScmControlService(CurrentService->lpImage->hControlPipe,
2404 CurrentService->lpServiceName,
2405 (SERVICE_STATUS_HANDLE)CurrentService,
2406 SERVICE_CONTROL_SHUTDOWN);
2407 }
2408
2409 ServiceEntry = ServiceEntry->Flink;
2410 }
2411
2412 /* Unlock the service database */
2413 ScmUnlockDatabase();
2414
2415 DPRINT("ScmAutoShutdownServices() done\n");
2416 }
2417
2418
2419 BOOL
2420 ScmLockDatabaseExclusive(VOID)
2421 {
2422 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE);
2423 }
2424
2425
2426 BOOL
2427 ScmLockDatabaseShared(VOID)
2428 {
2429 return RtlAcquireResourceShared(&DatabaseLock, TRUE);
2430 }
2431
2432
2433 VOID
2434 ScmUnlockDatabase(VOID)
2435 {
2436 RtlReleaseResource(&DatabaseLock);
2437 }
2438
2439
2440 VOID
2441 ScmInitNamedPipeCriticalSection(VOID)
2442 {
2443 HKEY hKey;
2444 DWORD dwKeySize;
2445 DWORD dwError;
2446
2447 InitializeCriticalSection(&ControlServiceCriticalSection);
2448
2449 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2450 L"SYSTEM\\CurrentControlSet\\Control",
2451 0,
2452 KEY_READ,
2453 &hKey);
2454 if (dwError == ERROR_SUCCESS)
2455 {
2456 dwKeySize = sizeof(PipeTimeout);
2457 RegQueryValueExW(hKey,
2458 L"ServicesPipeTimeout",
2459 0,
2460 NULL,
2461 (LPBYTE)&PipeTimeout,
2462 &dwKeySize);
2463 RegCloseKey(hKey);
2464 }
2465 }
2466
2467
2468 VOID
2469 ScmDeleteNamedPipeCriticalSection(VOID)
2470 {
2471 DeleteCriticalSection(&ControlServiceCriticalSection);
2472 }
2473
2474 /* EOF */