Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendatabase.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Service Control Manager 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: base/system/services/database.c 00005 * PURPOSE: Database control interface 00006 * COPYRIGHT: Copyright 2002-2006 Eric Kohl 00007 * Copyright 2006 Hervé Poussineau <hpoussin@reactos.org> 00008 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org> 00009 * Gregor Brunmar <gregor.brunmar@home.se> 00010 * 00011 */ 00012 00013 /* INCLUDES *****************************************************************/ 00014 00015 #include "services.h" 00016 00017 #define NDEBUG 00018 #include <debug.h> 00019 00020 /* 00021 * Uncomment the line below to start services 00022 * using the SERVICE_START_PENDING state 00023 */ 00024 // #define USE_SERVICE_START_PENDING 00025 00026 /* 00027 * Uncomment the line below to use asynchronous IO operations 00028 * on the service control pipes. 00029 */ 00030 // #define USE_ASYNCHRONOUS_IO 00031 00032 00033 /* GLOBALS *******************************************************************/ 00034 00035 LIST_ENTRY ImageListHead; 00036 LIST_ENTRY ServiceListHead; 00037 00038 static RTL_RESOURCE DatabaseLock; 00039 static DWORD dwResumeCount = 1; 00040 00041 static CRITICAL_SECTION ControlServiceCriticalSection; 00042 static DWORD dwPipeTimeout = 30000; /* 30 Seconds */ 00043 00044 00045 /* FUNCTIONS *****************************************************************/ 00046 00047 static DWORD 00048 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage) 00049 { 00050 WCHAR szControlPipeName[MAX_PATH + 1]; 00051 HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE; 00052 DWORD ServiceCurrent = 0; 00053 DWORD KeyDisposition; 00054 DWORD dwKeySize; 00055 DWORD dwError; 00056 00057 /* Get the service number */ 00058 /* TODO: Create registry entry with correct write access */ 00059 dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE, 00060 L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL, 00061 REG_OPTION_VOLATILE, 00062 KEY_WRITE | KEY_READ, 00063 NULL, 00064 &hServiceCurrentKey, 00065 &KeyDisposition); 00066 if (dwError != ERROR_SUCCESS) 00067 { 00068 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError); 00069 return dwError; 00070 } 00071 00072 if (KeyDisposition == REG_OPENED_EXISTING_KEY) 00073 { 00074 dwKeySize = sizeof(DWORD); 00075 dwError = RegQueryValueExW(hServiceCurrentKey, 00076 L"", 0, NULL, (BYTE*)&ServiceCurrent, &dwKeySize); 00077 00078 if (dwError != ERROR_SUCCESS) 00079 { 00080 RegCloseKey(hServiceCurrentKey); 00081 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError); 00082 return dwError; 00083 } 00084 00085 ServiceCurrent++; 00086 } 00087 00088 dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent)); 00089 00090 RegCloseKey(hServiceCurrentKey); 00091 00092 if (dwError != ERROR_SUCCESS) 00093 { 00094 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError); 00095 return dwError; 00096 } 00097 00098 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */ 00099 swprintf(szControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent); 00100 00101 DPRINT("PipeName: %S\n", szControlPipeName); 00102 00103 pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName, 00104 #ifdef USE_ASYNCHRONOUS_IO 00105 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 00106 #else 00107 PIPE_ACCESS_DUPLEX, 00108 #endif 00109 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 00110 100, 00111 8000, 00112 4, 00113 dwPipeTimeout, 00114 NULL); 00115 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName); 00116 if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE) 00117 { 00118 DPRINT1("Failed to create control pipe!\n"); 00119 return GetLastError(); 00120 } 00121 00122 return ERROR_SUCCESS; 00123 } 00124 00125 00126 static PSERVICE_IMAGE 00127 ScmGetServiceImageByImagePath(LPWSTR lpImagePath) 00128 { 00129 PLIST_ENTRY ImageEntry; 00130 PSERVICE_IMAGE CurrentImage; 00131 00132 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath); 00133 00134 ImageEntry = ImageListHead.Flink; 00135 while (ImageEntry != &ImageListHead) 00136 { 00137 CurrentImage = CONTAINING_RECORD(ImageEntry, 00138 SERVICE_IMAGE, 00139 ImageListEntry); 00140 if (_wcsicmp(CurrentImage->szImagePath, lpImagePath) == 0) 00141 { 00142 DPRINT("Found image: '%S'\n", CurrentImage->szImagePath); 00143 return CurrentImage; 00144 } 00145 00146 ImageEntry = ImageEntry->Flink; 00147 } 00148 00149 DPRINT("Couldn't find a matching image\n"); 00150 00151 return NULL; 00152 00153 } 00154 00155 00156 static DWORD 00157 ScmCreateOrReferenceServiceImage(PSERVICE pService) 00158 { 00159 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 00160 UNICODE_STRING ImagePath; 00161 PSERVICE_IMAGE pServiceImage = NULL; 00162 NTSTATUS Status; 00163 DWORD dwError = ERROR_SUCCESS; 00164 00165 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService); 00166 00167 RtlInitUnicodeString(&ImagePath, NULL); 00168 00169 /* Get service data */ 00170 RtlZeroMemory(&QueryTable, 00171 sizeof(QueryTable)); 00172 00173 QueryTable[0].Name = L"ImagePath"; 00174 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; 00175 QueryTable[0].EntryContext = &ImagePath; 00176 00177 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, 00178 pService->lpServiceName, 00179 QueryTable, 00180 NULL, 00181 NULL); 00182 if (!NT_SUCCESS(Status)) 00183 { 00184 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); 00185 return RtlNtStatusToDosError(Status); 00186 } 00187 00188 DPRINT("ImagePath: '%wZ'\n", &ImagePath); 00189 00190 pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer); 00191 if (pServiceImage == NULL) 00192 { 00193 /* Create a new service image */ 00194 pServiceImage = HeapAlloc(GetProcessHeap(), 00195 HEAP_ZERO_MEMORY, 00196 FIELD_OFFSET(SERVICE_IMAGE, szImagePath[ImagePath.Length / sizeof(WCHAR) + 1])); 00197 if (pServiceImage == NULL) 00198 { 00199 dwError = ERROR_NOT_ENOUGH_MEMORY; 00200 goto done; 00201 } 00202 00203 pServiceImage->dwImageRunCount = 1; 00204 pServiceImage->hControlPipe = INVALID_HANDLE_VALUE; 00205 00206 /* Set the image path */ 00207 wcscpy(pServiceImage->szImagePath, 00208 ImagePath.Buffer); 00209 00210 RtlFreeUnicodeString(&ImagePath); 00211 00212 /* Create the control pipe */ 00213 dwError = ScmCreateNewControlPipe(pServiceImage); 00214 if (dwError != ERROR_SUCCESS) 00215 { 00216 HeapFree(GetProcessHeap(), 0, pServiceImage); 00217 goto done; 00218 } 00219 00220 /* FIXME: Add more initialization code here */ 00221 00222 00223 /* Append service record */ 00224 InsertTailList(&ImageListHead, 00225 &pServiceImage->ImageListEntry); 00226 } 00227 else 00228 { 00229 /* Increment the run counter */ 00230 pServiceImage->dwImageRunCount++; 00231 } 00232 00233 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount); 00234 00235 /* Link the service image to the service */ 00236 pService->lpImage = pServiceImage; 00237 00238 done:; 00239 RtlFreeUnicodeString(&ImagePath); 00240 00241 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError); 00242 00243 return dwError; 00244 } 00245 00246 00247 static VOID 00248 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage) 00249 { 00250 DPRINT1("ScmDereferenceServiceImage() called\n"); 00251 00252 pServiceImage->dwImageRunCount--; 00253 00254 if (pServiceImage->dwImageRunCount == 0) 00255 { 00256 DPRINT1("dwImageRunCount == 0\n"); 00257 00258 /* FIXME: Terminate the process */ 00259 00260 /* Remove the service image from the list */ 00261 RemoveEntryList(&pServiceImage->ImageListEntry); 00262 00263 /* Close the control pipe */ 00264 if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE) 00265 CloseHandle(pServiceImage->hControlPipe); 00266 00267 /* Release the service image */ 00268 HeapFree(GetProcessHeap(), 0, pServiceImage); 00269 } 00270 } 00271 00272 00273 PSERVICE 00274 ScmGetServiceEntryByName(LPCWSTR lpServiceName) 00275 { 00276 PLIST_ENTRY ServiceEntry; 00277 PSERVICE CurrentService; 00278 00279 DPRINT("ScmGetServiceEntryByName() called\n"); 00280 00281 ServiceEntry = ServiceListHead.Flink; 00282 while (ServiceEntry != &ServiceListHead) 00283 { 00284 CurrentService = CONTAINING_RECORD(ServiceEntry, 00285 SERVICE, 00286 ServiceListEntry); 00287 if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0) 00288 { 00289 DPRINT("Found service: '%S'\n", CurrentService->lpServiceName); 00290 return CurrentService; 00291 } 00292 00293 ServiceEntry = ServiceEntry->Flink; 00294 } 00295 00296 DPRINT("Couldn't find a matching service\n"); 00297 00298 return NULL; 00299 } 00300 00301 00302 PSERVICE 00303 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName) 00304 { 00305 PLIST_ENTRY ServiceEntry; 00306 PSERVICE CurrentService; 00307 00308 DPRINT("ScmGetServiceEntryByDisplayName() called\n"); 00309 00310 ServiceEntry = ServiceListHead.Flink; 00311 while (ServiceEntry != &ServiceListHead) 00312 { 00313 CurrentService = CONTAINING_RECORD(ServiceEntry, 00314 SERVICE, 00315 ServiceListEntry); 00316 if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0) 00317 { 00318 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName); 00319 return CurrentService; 00320 } 00321 00322 ServiceEntry = ServiceEntry->Flink; 00323 } 00324 00325 DPRINT("Couldn't find a matching service\n"); 00326 00327 return NULL; 00328 } 00329 00330 00331 PSERVICE 00332 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount) 00333 { 00334 PLIST_ENTRY ServiceEntry; 00335 PSERVICE CurrentService; 00336 00337 DPRINT("ScmGetServiceEntryByResumeCount() called\n"); 00338 00339 ServiceEntry = ServiceListHead.Flink; 00340 while (ServiceEntry != &ServiceListHead) 00341 { 00342 CurrentService = CONTAINING_RECORD(ServiceEntry, 00343 SERVICE, 00344 ServiceListEntry); 00345 if (CurrentService->dwResumeCount > dwResumeCount) 00346 { 00347 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName); 00348 return CurrentService; 00349 } 00350 00351 ServiceEntry = ServiceEntry->Flink; 00352 } 00353 00354 DPRINT("Couldn't find a matching service\n"); 00355 00356 return NULL; 00357 } 00358 00359 00360 DWORD 00361 ScmCreateNewServiceRecord(LPCWSTR lpServiceName, 00362 PSERVICE *lpServiceRecord) 00363 { 00364 PSERVICE lpService = NULL; 00365 00366 DPRINT("Service: '%S'\n", lpServiceName); 00367 00368 /* Allocate service entry */ 00369 lpService = HeapAlloc(GetProcessHeap(), 00370 HEAP_ZERO_MEMORY, 00371 FIELD_OFFSET(SERVICE, szServiceName[wcslen(lpServiceName) + 1])); 00372 if (lpService == NULL) 00373 return ERROR_NOT_ENOUGH_MEMORY; 00374 00375 *lpServiceRecord = lpService; 00376 00377 /* Copy service name */ 00378 wcscpy(lpService->szServiceName, lpServiceName); 00379 lpService->lpServiceName = lpService->szServiceName; 00380 lpService->lpDisplayName = lpService->lpServiceName; 00381 00382 /* Set the resume count */ 00383 lpService->dwResumeCount = dwResumeCount++; 00384 00385 /* Append service record */ 00386 InsertTailList(&ServiceListHead, 00387 &lpService->ServiceListEntry); 00388 00389 /* Initialize the service status */ 00390 lpService->Status.dwCurrentState = SERVICE_STOPPED; 00391 lpService->Status.dwControlsAccepted = 0; 00392 lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED; 00393 lpService->Status.dwServiceSpecificExitCode = 0; 00394 lpService->Status.dwCheckPoint = 0; 00395 lpService->Status.dwWaitHint = 2000; /* 2 seconds */ 00396 00397 return ERROR_SUCCESS; 00398 } 00399 00400 00401 VOID 00402 ScmDeleteServiceRecord(PSERVICE lpService) 00403 { 00404 DPRINT("Deleting Service %S\n", lpService->lpServiceName); 00405 00406 /* Delete the display name */ 00407 if (lpService->lpDisplayName != NULL && 00408 lpService->lpDisplayName != lpService->lpServiceName) 00409 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName); 00410 00411 /* Dereference the service image */ 00412 if (lpService->lpImage) 00413 ScmDereferenceServiceImage(lpService->lpImage); 00414 00415 /* Decrement the group reference counter */ 00416 if (lpService->lpGroup) 00417 lpService->lpGroup->dwRefCount--; 00418 00419 /* FIXME: SecurityDescriptor */ 00420 00421 00422 /* Remove the Service from the List */ 00423 RemoveEntryList(&lpService->ServiceListEntry); 00424 00425 DPRINT("Deleted Service %S\n", lpService->lpServiceName); 00426 00427 /* Delete the service record */ 00428 HeapFree(GetProcessHeap(), 0, lpService); 00429 00430 DPRINT("Done\n"); 00431 } 00432 00433 00434 static DWORD 00435 CreateServiceListEntry(LPCWSTR lpServiceName, 00436 HKEY hServiceKey) 00437 { 00438 PSERVICE lpService = NULL; 00439 LPWSTR lpDisplayName = NULL; 00440 LPWSTR lpGroup = NULL; 00441 DWORD dwSize; 00442 DWORD dwError; 00443 DWORD dwServiceType; 00444 DWORD dwStartType; 00445 DWORD dwErrorControl; 00446 DWORD dwTagId; 00447 00448 DPRINT("Service: '%S'\n", lpServiceName); 00449 if (*lpServiceName == L'{') 00450 return ERROR_SUCCESS; 00451 00452 dwSize = sizeof(DWORD); 00453 dwError = RegQueryValueExW(hServiceKey, 00454 L"Type", 00455 NULL, 00456 NULL, 00457 (LPBYTE)&dwServiceType, 00458 &dwSize); 00459 if (dwError != ERROR_SUCCESS) 00460 return ERROR_SUCCESS; 00461 00462 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) && 00463 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) && 00464 (dwServiceType != SERVICE_KERNEL_DRIVER) && 00465 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)) 00466 return ERROR_SUCCESS; 00467 00468 DPRINT("Service type: %lx\n", dwServiceType); 00469 00470 dwSize = sizeof(DWORD); 00471 dwError = RegQueryValueExW(hServiceKey, 00472 L"Start", 00473 NULL, 00474 NULL, 00475 (LPBYTE)&dwStartType, 00476 &dwSize); 00477 if (dwError != ERROR_SUCCESS) 00478 return ERROR_SUCCESS; 00479 00480 DPRINT("Start type: %lx\n", dwStartType); 00481 00482 dwSize = sizeof(DWORD); 00483 dwError = RegQueryValueExW(hServiceKey, 00484 L"ErrorControl", 00485 NULL, 00486 NULL, 00487 (LPBYTE)&dwErrorControl, 00488 &dwSize); 00489 if (dwError != ERROR_SUCCESS) 00490 return ERROR_SUCCESS; 00491 00492 DPRINT("Error control: %lx\n", dwErrorControl); 00493 00494 dwError = RegQueryValueExW(hServiceKey, 00495 L"Tag", 00496 NULL, 00497 NULL, 00498 (LPBYTE)&dwTagId, 00499 &dwSize); 00500 if (dwError != ERROR_SUCCESS) 00501 dwTagId = 0; 00502 00503 DPRINT("Tag: %lx\n", dwTagId); 00504 00505 dwError = ScmReadString(hServiceKey, 00506 L"Group", 00507 &lpGroup); 00508 if (dwError != ERROR_SUCCESS) 00509 lpGroup = NULL; 00510 00511 DPRINT("Group: %S\n", lpGroup); 00512 00513 dwError = ScmReadString(hServiceKey, 00514 L"DisplayName", 00515 &lpDisplayName); 00516 if (dwError != ERROR_SUCCESS) 00517 lpDisplayName = NULL; 00518 00519 DPRINT("Display name: %S\n", lpDisplayName); 00520 00521 dwError = ScmCreateNewServiceRecord(lpServiceName, 00522 &lpService); 00523 if (dwError != ERROR_SUCCESS) 00524 goto done; 00525 00526 lpService->Status.dwServiceType = dwServiceType; 00527 lpService->dwStartType = dwStartType; 00528 lpService->dwErrorControl = dwErrorControl; 00529 lpService->dwTag = dwTagId; 00530 00531 if (lpGroup != NULL) 00532 { 00533 dwError = ScmSetServiceGroup(lpService, lpGroup); 00534 if (dwError != ERROR_SUCCESS) 00535 goto done; 00536 } 00537 00538 if (lpDisplayName != NULL) 00539 { 00540 lpService->lpDisplayName = lpDisplayName; 00541 lpDisplayName = NULL; 00542 } 00543 00544 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName); 00545 if (lpService->lpGroup != NULL) 00546 { 00547 DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName); 00548 } 00549 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n", 00550 lpService->dwStartType, 00551 lpService->Status.dwServiceType, 00552 lpService->dwTag, 00553 lpService->dwErrorControl); 00554 00555 if (ScmIsDeleteFlagSet(hServiceKey)) 00556 lpService->bDeleted = TRUE; 00557 00558 done:; 00559 if (lpGroup != NULL) 00560 HeapFree(GetProcessHeap(), 0, lpGroup); 00561 00562 if (lpDisplayName != NULL) 00563 HeapFree(GetProcessHeap(), 0, lpDisplayName); 00564 00565 if (lpService != NULL) 00566 { 00567 if (lpService->lpImage != NULL) 00568 ScmDereferenceServiceImage(lpService->lpImage); 00569 } 00570 00571 return dwError; 00572 } 00573 00574 00575 DWORD 00576 ScmDeleteRegKey(HKEY hKey, LPCWSTR lpszSubKey) 00577 { 00578 DWORD dwRet, dwMaxSubkeyLen = 0, dwSize; 00579 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf; 00580 HKEY hSubKey = 0; 00581 00582 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey); 00583 if (!dwRet) 00584 { 00585 /* Find the maximum subkey length so that we can allocate a buffer */ 00586 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, 00587 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL); 00588 if (!dwRet) 00589 { 00590 dwMaxSubkeyLen++; 00591 if (dwMaxSubkeyLen > sizeof(szNameBuf) / sizeof(WCHAR)) 00592 { 00593 /* Name too big: alloc a buffer for it */ 00594 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen * sizeof(WCHAR)); 00595 } 00596 00597 if (!lpszName) 00598 dwRet = ERROR_NOT_ENOUGH_MEMORY; 00599 else 00600 { 00601 while (dwRet == ERROR_SUCCESS) 00602 { 00603 dwSize = dwMaxSubkeyLen; 00604 dwRet = RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL); 00605 if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA) 00606 dwRet = ScmDeleteRegKey(hSubKey, lpszName); 00607 } 00608 if (dwRet == ERROR_NO_MORE_ITEMS) 00609 dwRet = ERROR_SUCCESS; 00610 00611 if (lpszName != szNameBuf) 00612 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */ 00613 } 00614 } 00615 00616 RegCloseKey(hSubKey); 00617 if (!dwRet) 00618 dwRet = RegDeleteKeyW(hKey, lpszSubKey); 00619 } 00620 return dwRet; 00621 } 00622 00623 00624 VOID 00625 ScmDeleteMarkedServices(VOID) 00626 { 00627 PLIST_ENTRY ServiceEntry; 00628 PSERVICE CurrentService; 00629 HKEY hServicesKey; 00630 DWORD dwError; 00631 00632 ServiceEntry = ServiceListHead.Flink; 00633 while (ServiceEntry != &ServiceListHead) 00634 { 00635 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 00636 00637 ServiceEntry = ServiceEntry->Flink; 00638 00639 if (CurrentService->bDeleted == TRUE) 00640 { 00641 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 00642 L"System\\CurrentControlSet\\Services", 00643 0, 00644 DELETE, 00645 &hServicesKey); 00646 if (dwError == ERROR_SUCCESS) 00647 { 00648 dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName); 00649 RegCloseKey(hServicesKey); 00650 if (dwError == ERROR_SUCCESS) 00651 { 00652 RemoveEntryList(&CurrentService->ServiceListEntry); 00653 HeapFree(GetProcessHeap(), 0, CurrentService); 00654 } 00655 } 00656 00657 if (dwError != ERROR_SUCCESS) 00658 DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName); 00659 } 00660 } 00661 } 00662 00663 00664 VOID 00665 WaitForLSA(VOID) 00666 { 00667 HANDLE hEvent; 00668 DWORD dwError; 00669 00670 DPRINT("WaitForLSA() called\n"); 00671 00672 hEvent = CreateEventW(NULL, 00673 TRUE, 00674 FALSE, 00675 L"LSA_RPC_SERVER_ACTIVE"); 00676 if (hEvent == NULL) 00677 { 00678 dwError = GetLastError(); 00679 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError); 00680 00681 if (dwError == ERROR_ALREADY_EXISTS) 00682 { 00683 hEvent = OpenEventW(SYNCHRONIZE, 00684 FALSE, 00685 L"LSA_RPC_SERVER_ACTIVE"); 00686 if (hEvent != NULL) 00687 { 00688 DPRINT1("Could not open the notification event!\n"); 00689 return; 00690 } 00691 } 00692 } 00693 00694 DPRINT("Wait for LSA!\n"); 00695 WaitForSingleObject(hEvent, INFINITE); 00696 DPRINT("LSA is available!\n"); 00697 00698 CloseHandle(hEvent); 00699 00700 DPRINT("WaitForLSA() done\n"); 00701 } 00702 00703 00704 DWORD 00705 ScmCreateServiceDatabase(VOID) 00706 { 00707 WCHAR szSubKey[MAX_PATH]; 00708 HKEY hServicesKey; 00709 HKEY hServiceKey; 00710 DWORD dwSubKey; 00711 DWORD dwSubKeyLength; 00712 FILETIME ftLastChanged; 00713 DWORD dwError; 00714 00715 DPRINT("ScmCreateServiceDatabase() called\n"); 00716 00717 dwError = ScmCreateGroupList(); 00718 if (dwError != ERROR_SUCCESS) 00719 return dwError; 00720 00721 /* Initialize basic variables */ 00722 InitializeListHead(&ImageListHead); 00723 InitializeListHead(&ServiceListHead); 00724 00725 /* Initialize the database lock */ 00726 RtlInitializeResource(&DatabaseLock); 00727 00728 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 00729 L"System\\CurrentControlSet\\Services", 00730 0, 00731 KEY_READ, 00732 &hServicesKey); 00733 if (dwError != ERROR_SUCCESS) 00734 return dwError; 00735 00736 dwSubKey = 0; 00737 for (;;) 00738 { 00739 dwSubKeyLength = MAX_PATH; 00740 dwError = RegEnumKeyExW(hServicesKey, 00741 dwSubKey, 00742 szSubKey, 00743 &dwSubKeyLength, 00744 NULL, 00745 NULL, 00746 NULL, 00747 &ftLastChanged); 00748 if (dwError == ERROR_SUCCESS && 00749 szSubKey[0] != L'{') 00750 { 00751 DPRINT("SubKeyName: '%S'\n", szSubKey); 00752 00753 dwError = RegOpenKeyExW(hServicesKey, 00754 szSubKey, 00755 0, 00756 KEY_READ, 00757 &hServiceKey); 00758 if (dwError == ERROR_SUCCESS) 00759 { 00760 dwError = CreateServiceListEntry(szSubKey, 00761 hServiceKey); 00762 00763 RegCloseKey(hServiceKey); 00764 } 00765 } 00766 00767 if (dwError != ERROR_SUCCESS) 00768 break; 00769 00770 dwSubKey++; 00771 } 00772 00773 RegCloseKey(hServicesKey); 00774 00775 /* Wait for LSA */ 00776 WaitForLSA(); 00777 00778 /* Delete services that are marked for delete */ 00779 ScmDeleteMarkedServices(); 00780 00781 DPRINT("ScmCreateServiceDatabase() done\n"); 00782 00783 return ERROR_SUCCESS; 00784 } 00785 00786 00787 VOID 00788 ScmShutdownServiceDatabase(VOID) 00789 { 00790 DPRINT("ScmShutdownServiceDatabase() called\n"); 00791 00792 ScmDeleteMarkedServices(); 00793 RtlDeleteResource(&DatabaseLock); 00794 00795 DPRINT("ScmShutdownServiceDatabase() done\n"); 00796 } 00797 00798 00799 static NTSTATUS 00800 ScmCheckDriver(PSERVICE Service) 00801 { 00802 OBJECT_ATTRIBUTES ObjectAttributes; 00803 UNICODE_STRING DirName; 00804 HANDLE DirHandle; 00805 NTSTATUS Status; 00806 POBJECT_DIRECTORY_INFORMATION DirInfo; 00807 ULONG BufferLength; 00808 ULONG DataLength; 00809 ULONG Index; 00810 00811 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName); 00812 00813 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER) 00814 { 00815 RtlInitUnicodeString(&DirName, 00816 L"\\Driver"); 00817 } 00818 else 00819 { 00820 RtlInitUnicodeString(&DirName, 00821 L"\\FileSystem"); 00822 } 00823 00824 InitializeObjectAttributes(&ObjectAttributes, 00825 &DirName, 00826 0, 00827 NULL, 00828 NULL); 00829 00830 Status = NtOpenDirectoryObject(&DirHandle, 00831 DIRECTORY_QUERY | DIRECTORY_TRAVERSE, 00832 &ObjectAttributes); 00833 if (!NT_SUCCESS(Status)) 00834 { 00835 return Status; 00836 } 00837 00838 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) + 00839 2 * MAX_PATH * sizeof(WCHAR); 00840 DirInfo = HeapAlloc(GetProcessHeap(), 00841 HEAP_ZERO_MEMORY, 00842 BufferLength); 00843 00844 Index = 0; 00845 while (TRUE) 00846 { 00847 Status = NtQueryDirectoryObject(DirHandle, 00848 DirInfo, 00849 BufferLength, 00850 TRUE, 00851 FALSE, 00852 &Index, 00853 &DataLength); 00854 if (Status == STATUS_NO_MORE_ENTRIES) 00855 { 00856 /* FIXME: Add current service to 'failed service' list */ 00857 DPRINT("Service '%S' failed\n", Service->lpServiceName); 00858 break; 00859 } 00860 00861 if (!NT_SUCCESS(Status)) 00862 break; 00863 00864 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name); 00865 00866 if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0) 00867 { 00868 DPRINT("Found: '%S' '%wZ'\n", 00869 Service->lpServiceName, &DirInfo->Name); 00870 00871 /* Mark service as 'running' */ 00872 Service->Status.dwCurrentState = SERVICE_RUNNING; 00873 00874 /* Mark the service group as 'running' */ 00875 if (Service->lpGroup != NULL) 00876 { 00877 Service->lpGroup->ServicesRunning = TRUE; 00878 } 00879 00880 break; 00881 } 00882 } 00883 00884 HeapFree(GetProcessHeap(), 00885 0, 00886 DirInfo); 00887 NtClose(DirHandle); 00888 00889 return STATUS_SUCCESS; 00890 } 00891 00892 00893 VOID 00894 ScmGetBootAndSystemDriverState(VOID) 00895 { 00896 PLIST_ENTRY ServiceEntry; 00897 PSERVICE CurrentService; 00898 00899 DPRINT("ScmGetBootAndSystemDriverState() called\n"); 00900 00901 ServiceEntry = ServiceListHead.Flink; 00902 while (ServiceEntry != &ServiceListHead) 00903 { 00904 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 00905 00906 if (CurrentService->dwStartType == SERVICE_BOOT_START || 00907 CurrentService->dwStartType == SERVICE_SYSTEM_START) 00908 { 00909 /* Check driver */ 00910 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName); 00911 00912 ScmCheckDriver(CurrentService); 00913 } 00914 00915 ServiceEntry = ServiceEntry->Flink; 00916 } 00917 00918 DPRINT("ScmGetBootAndSystemDriverState() done\n"); 00919 } 00920 00921 00922 DWORD 00923 ScmControlService(PSERVICE Service, 00924 DWORD dwControl) 00925 { 00926 PSCM_CONTROL_PACKET ControlPacket; 00927 SCM_REPLY_PACKET ReplyPacket; 00928 00929 DWORD dwWriteCount = 0; 00930 DWORD dwReadCount = 0; 00931 DWORD PacketSize; 00932 PWSTR Ptr; 00933 DWORD dwError = ERROR_SUCCESS; 00934 BOOL bResult; 00935 #ifdef USE_ASYNCHRONOUS_IO 00936 OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; 00937 #endif 00938 00939 DPRINT("ScmControlService() called\n"); 00940 00941 EnterCriticalSection(&ControlServiceCriticalSection); 00942 00943 /* Calculate the total length of the start command line */ 00944 PacketSize = sizeof(SCM_CONTROL_PACKET); 00945 PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR); 00946 00947 ControlPacket = HeapAlloc(GetProcessHeap(), 00948 HEAP_ZERO_MEMORY, 00949 PacketSize); 00950 if (ControlPacket == NULL) 00951 { 00952 LeaveCriticalSection(&ControlServiceCriticalSection); 00953 return ERROR_NOT_ENOUGH_MEMORY; 00954 } 00955 00956 ControlPacket->dwSize = PacketSize; 00957 ControlPacket->dwControl = dwControl; 00958 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service; 00959 00960 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); 00961 00962 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); 00963 wcscpy(Ptr, Service->lpServiceName); 00964 00965 ControlPacket->dwArgumentsCount = 0; 00966 ControlPacket->dwArgumentsOffset = 0; 00967 00968 #ifdef USE_ASYNCHRONOUS_IO 00969 bResult = WriteFile(Service->lpImage->hControlPipe, 00970 ControlPacket, 00971 PacketSize, 00972 &dwWriteCount, 00973 &Overlapped); 00974 if (bResult == FALSE) 00975 { 00976 DPRINT1("WriteFile() returned FALSE\n"); 00977 00978 dwError = GetLastError(); 00979 if (dwError == ERROR_IO_PENDING) 00980 { 00981 DPRINT1("dwError: ERROR_IO_PENDING\n"); 00982 00983 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 00984 dwPipeTimeout); 00985 DPRINT1("WaitForSingleObject() returned %lu\n", dwError); 00986 00987 if (dwError == WAIT_TIMEOUT) 00988 { 00989 bResult = CancelIo(Service->lpImage->hControlPipe); 00990 if (bResult == FALSE) 00991 { 00992 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 00993 } 00994 00995 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 00996 goto Done; 00997 } 00998 else if (dwError == ERROR_SUCCESS) 00999 { 01000 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 01001 &Overlapped, 01002 &dwWriteCount, 01003 TRUE); 01004 if (bResult == FALSE) 01005 { 01006 dwError = GetLastError(); 01007 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 01008 01009 goto Done; 01010 } 01011 } 01012 } 01013 else 01014 { 01015 DPRINT1("WriteFile() failed (Error %lu)\n", dwError); 01016 goto Done; 01017 } 01018 } 01019 01020 /* Read the reply */ 01021 Overlapped.hEvent = (HANDLE) NULL; 01022 01023 bResult = ReadFile(Service->lpImage->hControlPipe, 01024 &ReplyPacket, 01025 sizeof(SCM_REPLY_PACKET), 01026 &dwReadCount, 01027 &Overlapped); 01028 if (bResult == FALSE) 01029 { 01030 DPRINT1("ReadFile() returned FALSE\n"); 01031 01032 dwError = GetLastError(); 01033 if (dwError == ERROR_IO_PENDING) 01034 { 01035 DPRINT1("dwError: ERROR_IO_PENDING\n"); 01036 01037 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 01038 dwPipeTimeout); 01039 DPRINT1("WaitForSingleObject() returned %lu\n", dwError); 01040 01041 if (dwError == WAIT_TIMEOUT) 01042 { 01043 bResult = CancelIo(Service->lpImage->hControlPipe); 01044 if (bResult == FALSE) 01045 { 01046 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 01047 } 01048 01049 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 01050 goto Done; 01051 } 01052 else if (dwError == ERROR_SUCCESS) 01053 { 01054 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 01055 &Overlapped, 01056 &dwReadCount, 01057 TRUE); 01058 if (bResult == FALSE) 01059 { 01060 dwError = GetLastError(); 01061 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 01062 01063 goto Done; 01064 } 01065 } 01066 } 01067 else 01068 { 01069 DPRINT1("ReadFile() failed (Error %lu)\n", dwError); 01070 goto Done; 01071 } 01072 } 01073 01074 #else 01075 /* Send the control packet */ 01076 bResult = WriteFile(Service->lpImage->hControlPipe, 01077 ControlPacket, 01078 PacketSize, 01079 &dwWriteCount, 01080 NULL); 01081 if (bResult == FALSE) 01082 { 01083 dwError = GetLastError(); 01084 DPRINT("WriteFile() failed (Error %lu)\n", dwError); 01085 01086 if ((dwError == ERROR_GEN_FAILURE) && 01087 (dwControl == SERVICE_CONTROL_STOP)) 01088 { 01089 /* Service is already terminated */ 01090 Service->Status.dwCurrentState = SERVICE_STOPPED; 01091 Service->Status.dwControlsAccepted = 0; 01092 Service->Status.dwWin32ExitCode = ERROR_SERVICE_NOT_ACTIVE; 01093 dwError = ERROR_SUCCESS; 01094 } 01095 goto Done; 01096 } 01097 01098 /* Read the reply */ 01099 bResult = ReadFile(Service->lpImage->hControlPipe, 01100 &ReplyPacket, 01101 sizeof(SCM_REPLY_PACKET), 01102 &dwReadCount, 01103 NULL); 01104 if (bResult == FALSE) 01105 { 01106 dwError = GetLastError(); 01107 DPRINT("ReadFile() failed (Error %lu)\n", dwError); 01108 } 01109 #endif 01110 01111 Done: 01112 /* Release the contol packet */ 01113 HeapFree(GetProcessHeap(), 01114 0, 01115 ControlPacket); 01116 01117 if (dwReadCount == sizeof(SCM_REPLY_PACKET)) 01118 { 01119 dwError = ReplyPacket.dwError; 01120 } 01121 01122 if (dwError == ERROR_SUCCESS && 01123 dwControl == SERVICE_CONTROL_STOP) 01124 { 01125 ScmDereferenceServiceImage(Service->lpImage); 01126 } 01127 01128 LeaveCriticalSection(&ControlServiceCriticalSection); 01129 01130 DPRINT("ScmControlService() done\n"); 01131 01132 return dwError; 01133 } 01134 01135 01136 static DWORD 01137 ScmSendStartCommand(PSERVICE Service, 01138 DWORD argc, 01139 LPWSTR *argv) 01140 { 01141 PSCM_CONTROL_PACKET ControlPacket; 01142 SCM_REPLY_PACKET ReplyPacket; 01143 DWORD PacketSize; 01144 PWSTR Ptr; 01145 DWORD dwWriteCount = 0; 01146 DWORD dwReadCount = 0; 01147 DWORD dwError = ERROR_SUCCESS; 01148 DWORD i; 01149 PWSTR *pOffPtr; 01150 PWSTR pArgPtr; 01151 BOOL bResult; 01152 #ifdef USE_ASYNCHRONOUS_IO 01153 OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; 01154 #endif 01155 01156 DPRINT("ScmSendStartCommand() called\n"); 01157 01158 /* Calculate the total length of the start command line */ 01159 PacketSize = sizeof(SCM_CONTROL_PACKET); 01160 PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR); 01161 01162 /* Calculate the required packet size for the start arguments */ 01163 if (argc > 0 && argv != NULL) 01164 { 01165 PacketSize = ALIGN_UP(PacketSize, LPWSTR); 01166 01167 DPRINT("Argc: %lu\n", argc); 01168 for (i = 0; i < argc; i++) 01169 { 01170 DPRINT("Argv[%lu]: %S\n", i, argv[i]); 01171 PacketSize += (wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR); 01172 } 01173 } 01174 01175 /* Allocate a control packet */ 01176 ControlPacket = HeapAlloc(GetProcessHeap(), 01177 HEAP_ZERO_MEMORY, 01178 PacketSize); 01179 if (ControlPacket == NULL) 01180 return ERROR_NOT_ENOUGH_MEMORY; 01181 01182 ControlPacket->dwSize = PacketSize; 01183 ControlPacket->dwControl = SERVICE_CONTROL_START; 01184 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service; 01185 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); 01186 01187 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); 01188 wcscpy(Ptr, Service->lpServiceName); 01189 01190 ControlPacket->dwArgumentsCount = 0; 01191 ControlPacket->dwArgumentsOffset = 0; 01192 01193 /* Copy argument list */ 01194 if (argc > 0 && argv != NULL) 01195 { 01196 Ptr += wcslen(Service->lpServiceName) + 1; 01197 pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR); 01198 pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR)); 01199 01200 ControlPacket->dwArgumentsCount = argc; 01201 ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket); 01202 01203 DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount); 01204 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset); 01205 01206 for (i = 0; i < argc; i++) 01207 { 01208 wcscpy(pArgPtr, argv[i]); 01209 *pOffPtr = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr); 01210 DPRINT("offset: %p\n", *pOffPtr); 01211 01212 pArgPtr += wcslen(argv[i]) + 1; 01213 pOffPtr++; 01214 } 01215 } 01216 01217 #ifdef USE_ASYNCHRONOUS_IO 01218 bResult = WriteFile(Service->lpImage->hControlPipe, 01219 ControlPacket, 01220 PacketSize, 01221 &dwWriteCount, 01222 &Overlapped); 01223 if (bResult == FALSE) 01224 { 01225 DPRINT1("WriteFile() returned FALSE\n"); 01226 01227 dwError = GetLastError(); 01228 if (dwError == ERROR_IO_PENDING) 01229 { 01230 DPRINT1("dwError: ERROR_IO_PENDING\n"); 01231 01232 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 01233 dwPipeTimeout); 01234 DPRINT1("WaitForSingleObject() returned %lu\n", dwError); 01235 01236 if (dwError == WAIT_TIMEOUT) 01237 { 01238 bResult = CancelIo(Service->lpImage->hControlPipe); 01239 if (bResult == FALSE) 01240 { 01241 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 01242 } 01243 01244 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 01245 goto Done; 01246 } 01247 else if (dwError == ERROR_SUCCESS) 01248 { 01249 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 01250 &Overlapped, 01251 &dwWriteCount, 01252 TRUE); 01253 if (bResult == FALSE) 01254 { 01255 dwError = GetLastError(); 01256 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 01257 01258 goto Done; 01259 } 01260 } 01261 } 01262 else 01263 { 01264 DPRINT1("WriteFile() failed (Error %lu)\n", dwError); 01265 goto Done; 01266 } 01267 } 01268 01269 /* Read the reply */ 01270 Overlapped.hEvent = (HANDLE) NULL; 01271 01272 bResult = ReadFile(Service->lpImage->hControlPipe, 01273 &ReplyPacket, 01274 sizeof(SCM_REPLY_PACKET), 01275 &dwReadCount, 01276 &Overlapped); 01277 if (bResult == FALSE) 01278 { 01279 DPRINT1("ReadFile() returned FALSE\n"); 01280 01281 dwError = GetLastError(); 01282 if (dwError == ERROR_IO_PENDING) 01283 { 01284 DPRINT1("dwError: ERROR_IO_PENDING\n"); 01285 01286 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 01287 dwPipeTimeout); 01288 DPRINT1("WaitForSingleObject() returned %lu\n", dwError); 01289 01290 if (dwError == WAIT_TIMEOUT) 01291 { 01292 bResult = CancelIo(Service->lpImage->hControlPipe); 01293 if (bResult == FALSE) 01294 { 01295 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 01296 } 01297 01298 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 01299 goto Done; 01300 } 01301 else if (dwError == ERROR_SUCCESS) 01302 { 01303 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 01304 &Overlapped, 01305 &dwReadCount, 01306 TRUE); 01307 if (bResult == FALSE) 01308 { 01309 dwError = GetLastError(); 01310 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 01311 01312 goto Done; 01313 } 01314 } 01315 } 01316 else 01317 { 01318 DPRINT1("ReadFile() failed (Error %lu)\n", dwError); 01319 goto Done; 01320 } 01321 } 01322 01323 #else 01324 /* Send the start command */ 01325 bResult = WriteFile(Service->lpImage->hControlPipe, 01326 ControlPacket, 01327 PacketSize, 01328 &dwWriteCount, 01329 NULL); 01330 if (bResult == FALSE) 01331 { 01332 dwError = GetLastError(); 01333 DPRINT("WriteFile() failed (Error %lu)\n", dwError); 01334 goto Done; 01335 } 01336 01337 /* Read the reply */ 01338 bResult = ReadFile(Service->lpImage->hControlPipe, 01339 &ReplyPacket, 01340 sizeof(SCM_REPLY_PACKET), 01341 &dwReadCount, 01342 NULL); 01343 if (bResult == FALSE) 01344 { 01345 dwError = GetLastError(); 01346 DPRINT("ReadFile() failed (Error %lu)\n", dwError); 01347 } 01348 #endif 01349 01350 Done: 01351 /* Release the contol packet */ 01352 HeapFree(GetProcessHeap(), 01353 0, 01354 ControlPacket); 01355 01356 if (dwReadCount == sizeof(SCM_REPLY_PACKET)) 01357 { 01358 dwError = ReplyPacket.dwError; 01359 } 01360 01361 DPRINT("ScmSendStartCommand() done\n"); 01362 01363 return dwError; 01364 } 01365 01366 01367 static DWORD 01368 ScmWaitForServiceConnect(PSERVICE Service) 01369 { 01370 DWORD dwRead = 0; 01371 DWORD dwProcessId = 0; 01372 DWORD dwError = ERROR_SUCCESS; 01373 BOOL bResult; 01374 #ifdef USE_ASYNCHRONOUS_IO 01375 OVERLAPPED Overlapped = {0, 0, 0, 0, 0}; 01376 #endif 01377 01378 DPRINT("ScmWaitForServiceConnect()\n"); 01379 01380 #ifdef USE_ASYNCHRONOUS_IO 01381 Overlapped.hEvent = (HANDLE)NULL; 01382 01383 bResult = ConnectNamedPipe(Service->lpImage->hControlPipe, 01384 &Overlapped); 01385 if (bResult == FALSE) 01386 { 01387 DPRINT("ConnectNamedPipe() returned FALSE\n"); 01388 01389 dwError = GetLastError(); 01390 if (dwError == ERROR_IO_PENDING) 01391 { 01392 DPRINT("dwError: ERROR_IO_PENDING\n"); 01393 01394 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 01395 dwPipeTimeout); 01396 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 01397 01398 if (dwError == WAIT_TIMEOUT) 01399 { 01400 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n"); 01401 01402 bResult = CancelIo(Service->lpImage->hControlPipe); 01403 if (bResult == FALSE) 01404 { 01405 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 01406 } 01407 01408 return ERROR_SERVICE_REQUEST_TIMEOUT; 01409 } 01410 else if (dwError == WAIT_OBJECT_0) 01411 { 01412 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 01413 &Overlapped, 01414 &dwRead, 01415 TRUE); 01416 if (bResult == FALSE) 01417 { 01418 dwError = GetLastError(); 01419 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError); 01420 01421 return dwError; 01422 } 01423 } 01424 } 01425 else if (dwError != ERROR_PIPE_CONNECTED) 01426 { 01427 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError); 01428 return dwError; 01429 } 01430 } 01431 01432 DPRINT("Control pipe connected!\n"); 01433 01434 Overlapped.hEvent = (HANDLE) NULL; 01435 01436 /* Read the process id from pipe */ 01437 bResult = ReadFile(Service->lpImage->hControlPipe, 01438 (LPVOID)&dwProcessId, 01439 sizeof(DWORD), 01440 &dwRead, 01441 &Overlapped); 01442 if (bResult == FALSE) 01443 { 01444 DPRINT("ReadFile() returned FALSE\n"); 01445 01446 dwError = GetLastError(); 01447 if (dwError == ERROR_IO_PENDING) 01448 { 01449 DPRINT("dwError: ERROR_IO_PENDING\n"); 01450 01451 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 01452 dwPipeTimeout); 01453 if (dwError == WAIT_TIMEOUT) 01454 { 01455 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n"); 01456 01457 bResult = CancelIo(Service->lpImage->hControlPipe); 01458 if (bResult == FALSE) 01459 { 01460 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 01461 } 01462 01463 return ERROR_SERVICE_REQUEST_TIMEOUT; 01464 } 01465 else if (dwError == ERROR_SUCCESS) 01466 { 01467 DPRINT("WaitForSingleObject() returned ERROR_SUCCESS\n"); 01468 01469 DPRINT("Process Id: %lu\n", dwProcessId); 01470 01471 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 01472 &Overlapped, 01473 &dwRead, 01474 TRUE); 01475 if (bResult == FALSE) 01476 { 01477 dwError = GetLastError(); 01478 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 01479 01480 return dwError; 01481 } 01482 } 01483 else 01484 { 01485 DPRINT1("WaitForSingleObject() returned %lu\n", dwError); 01486 } 01487 } 01488 else 01489 { 01490 DPRINT1("ReadFile() failed (Error %lu)\n", dwError); 01491 return dwError; 01492 } 01493 } 01494 01495 DPRINT1("ScmWaitForServiceConnect() done\n"); 01496 01497 return ERROR_SUCCESS; 01498 #else 01499 01500 /* Connect control pipe */ 01501 if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ? 01502 TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED) 01503 { 01504 DPRINT("Control pipe connected!\n"); 01505 01506 /* Read SERVICE_STATUS_HANDLE from pipe */ 01507 bResult = ReadFile(Service->lpImage->hControlPipe, 01508 (LPVOID)&dwProcessId, 01509 sizeof(DWORD), 01510 &dwRead, 01511 NULL); 01512 if (bResult == FALSE) 01513 { 01514 dwError = GetLastError(); 01515 DPRINT1("Reading the service control pipe failed (Error %lu)\n", 01516 dwError); 01517 } 01518 else 01519 { 01520 dwError = ERROR_SUCCESS; 01521 DPRINT("Read control pipe successfully\n"); 01522 } 01523 } 01524 else 01525 { 01526 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); 01527 } 01528 01529 return dwError; 01530 #endif 01531 } 01532 01533 01534 static DWORD 01535 ScmStartUserModeService(PSERVICE Service, 01536 DWORD argc, 01537 LPWSTR *argv) 01538 { 01539 PROCESS_INFORMATION ProcessInformation; 01540 STARTUPINFOW StartupInfo; 01541 BOOL Result; 01542 DWORD dwError = ERROR_SUCCESS; 01543 01544 DPRINT("ScmStartUserModeService(%p)\n", Service); 01545 01546 /* If the image is already running ... */ 01547 if (Service->lpImage->dwImageRunCount > 1) 01548 { 01549 /* ... just send a start command */ 01550 return ScmSendStartCommand(Service, argc, argv); 01551 } 01552 01553 StartupInfo.cb = sizeof(StartupInfo); 01554 StartupInfo.lpReserved = NULL; 01555 StartupInfo.lpDesktop = NULL; 01556 StartupInfo.lpTitle = NULL; 01557 StartupInfo.dwFlags = 0; 01558 StartupInfo.cbReserved2 = 0; 01559 StartupInfo.lpReserved2 = 0; 01560 01561 Result = CreateProcessW(NULL, 01562 Service->lpImage->szImagePath, 01563 NULL, 01564 NULL, 01565 FALSE, 01566 DETACHED_PROCESS | CREATE_SUSPENDED, 01567 NULL, 01568 NULL, 01569 &StartupInfo, 01570 &ProcessInformation); 01571 if (!Result) 01572 { 01573 dwError = GetLastError(); 01574 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName); 01575 return dwError; 01576 } 01577 01578 DPRINT("Process Id: %lu Handle %p\n", 01579 ProcessInformation.dwProcessId, 01580 ProcessInformation.hProcess); 01581 DPRINT("Thread Id: %lu Handle %p\n", 01582 ProcessInformation.dwThreadId, 01583 ProcessInformation.hThread); 01584 01585 /* Get process handle and id */ 01586 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId; 01587 01588 /* Resume Thread */ 01589 ResumeThread(ProcessInformation.hThread); 01590 01591 /* Connect control pipe */ 01592 dwError = ScmWaitForServiceConnect(Service); 01593 if (dwError == ERROR_SUCCESS) 01594 { 01595 /* Send start command */ 01596 dwError = ScmSendStartCommand(Service, 01597 argc, 01598 argv); 01599 } 01600 else 01601 { 01602 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); 01603 Service->lpImage->dwProcessId = 0; 01604 } 01605 01606 /* Close thread and process handle */ 01607 CloseHandle(ProcessInformation.hThread); 01608 CloseHandle(ProcessInformation.hProcess); 01609 01610 return dwError; 01611 } 01612 01613 01614 DWORD 01615 ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv) 01616 { 01617 PSERVICE_GROUP Group = Service->lpGroup; 01618 DWORD dwError = ERROR_SUCCESS; 01619 LPCWSTR ErrorLogStrings[2]; 01620 WCHAR szErrorBuffer[32]; 01621 01622 DPRINT("ScmStartService() called\n"); 01623 01624 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName); 01625 01626 EnterCriticalSection(&ControlServiceCriticalSection); 01627 01628 if (Service->Status.dwCurrentState != SERVICE_STOPPED) 01629 { 01630 DPRINT("Service %S is already running!\n", Service->lpServiceName); 01631 LeaveCriticalSection(&ControlServiceCriticalSection); 01632 return ERROR_SERVICE_ALREADY_RUNNING; 01633 } 01634 01635 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType); 01636 01637 if (Service->Status.dwServiceType & SERVICE_DRIVER) 01638 { 01639 /* Load driver */ 01640 dwError = ScmLoadDriver(Service); 01641 if (dwError == ERROR_SUCCESS) 01642 { 01643 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; 01644 Service->Status.dwCurrentState = SERVICE_RUNNING; 01645 } 01646 } 01647 else 01648 { 01649 /* Start user-mode service */ 01650 dwError = ScmCreateOrReferenceServiceImage(Service); 01651 if (dwError == ERROR_SUCCESS) 01652 { 01653 dwError = ScmStartUserModeService(Service, argc, argv); 01654 if (dwError == ERROR_SUCCESS) 01655 { 01656 #ifdef USE_SERVICE_START_PENDING 01657 Service->Status.dwCurrentState = SERVICE_START_PENDING; 01658 #else 01659 Service->Status.dwCurrentState = SERVICE_RUNNING; 01660 #endif 01661 } 01662 else 01663 { 01664 ScmDereferenceServiceImage(Service->lpImage); 01665 Service->lpImage = NULL; 01666 } 01667 } 01668 } 01669 01670 LeaveCriticalSection(&ControlServiceCriticalSection); 01671 01672 DPRINT("ScmStartService() done (Error %lu)\n", dwError); 01673 01674 if (dwError == ERROR_SUCCESS) 01675 { 01676 if (Group != NULL) 01677 { 01678 Group->ServicesRunning = TRUE; 01679 } 01680 } 01681 else 01682 { 01683 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE) 01684 { 01685 /* Log a failed service start */ 01686 swprintf(szErrorBuffer, L"%lu", dwError); 01687 ErrorLogStrings[0] = Service->lpServiceName; 01688 ErrorLogStrings[1] = szErrorBuffer; 01689 ScmLogError(EVENT_SERVICE_START_FAILED, 01690 2, 01691 ErrorLogStrings); 01692 } 01693 01694 #if 0 01695 switch (Service->dwErrorControl) 01696 { 01697 case SERVICE_ERROR_SEVERE: 01698 if (IsLastKnownGood == FALSE) 01699 { 01700 /* FIXME: Boot last known good configuration */ 01701 } 01702 break; 01703 01704 case SERVICE_ERROR_CRITICAL: 01705 if (IsLastKnownGood == FALSE) 01706 { 01707 /* FIXME: Boot last known good configuration */ 01708 } 01709 else 01710 { 01711 /* FIXME: BSOD! */ 01712 } 01713 break; 01714 } 01715 #endif 01716 } 01717 01718 return dwError; 01719 } 01720 01721 01722 VOID 01723 ScmAutoStartServices(VOID) 01724 { 01725 PLIST_ENTRY GroupEntry; 01726 PLIST_ENTRY ServiceEntry; 01727 PSERVICE_GROUP CurrentGroup; 01728 PSERVICE CurrentService; 01729 WCHAR szSafeBootServicePath[MAX_PATH]; 01730 DWORD dwError; 01731 HKEY hKey; 01732 ULONG i; 01733 01734 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */ 01735 ServiceEntry = ServiceListHead.Flink; 01736 while (ServiceEntry != &ServiceListHead) 01737 { 01738 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 01739 01740 /* Build the safe boot path */ 01741 wcscpy(szSafeBootServicePath, 01742 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot"); 01743 01744 switch (GetSystemMetrics(SM_CLEANBOOT)) 01745 { 01746 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */ 01747 case 1: 01748 case 3: 01749 wcscat(szSafeBootServicePath, L"\\Minimal\\"); 01750 break; 01751 01752 case 2: 01753 wcscat(szSafeBootServicePath, L"\\Network\\"); 01754 break; 01755 } 01756 01757 if (GetSystemMetrics(SM_CLEANBOOT)) 01758 { 01759 /* If key does not exist then do not assume safe mode */ 01760 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 01761 szSafeBootServicePath, 01762 0, 01763 KEY_READ, 01764 &hKey); 01765 if (dwError == ERROR_SUCCESS) 01766 { 01767 RegCloseKey(hKey); 01768 01769 /* Finish Safe Boot path off */ 01770 wcsncat(szSafeBootServicePath, 01771 CurrentService->lpServiceName, 01772 MAX_PATH - wcslen(szSafeBootServicePath)); 01773 01774 /* Check that the key is in the Safe Boot path */ 01775 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 01776 szSafeBootServicePath, 01777 0, 01778 KEY_READ, 01779 &hKey); 01780 if (dwError != ERROR_SUCCESS) 01781 { 01782 /* Mark service as visited so it is not auto-started */ 01783 CurrentService->ServiceVisited = TRUE; 01784 } 01785 else 01786 { 01787 /* Must be auto-started in safe mode - mark as unvisited */ 01788 RegCloseKey(hKey); 01789 CurrentService->ServiceVisited = FALSE; 01790 } 01791 } 01792 else 01793 { 01794 DPRINT1("WARNING: Could not open the associated Safe Boot key!"); 01795 CurrentService->ServiceVisited = FALSE; 01796 } 01797 } 01798 01799 ServiceEntry = ServiceEntry->Flink; 01800 } 01801 01802 /* Start all services which are members of an existing group */ 01803 GroupEntry = GroupListHead.Flink; 01804 while (GroupEntry != &GroupListHead) 01805 { 01806 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry); 01807 01808 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName); 01809 01810 /* Start all services witch have a valid tag */ 01811 for (i = 0; i < CurrentGroup->TagCount; i++) 01812 { 01813 ServiceEntry = ServiceListHead.Flink; 01814 while (ServiceEntry != &ServiceListHead) 01815 { 01816 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 01817 01818 if ((CurrentService->lpGroup == CurrentGroup) && 01819 (CurrentService->dwStartType == SERVICE_AUTO_START) && 01820 (CurrentService->ServiceVisited == FALSE) && 01821 (CurrentService->dwTag == CurrentGroup->TagArray[i])) 01822 { 01823 CurrentService->ServiceVisited = TRUE; 01824 ScmStartService(CurrentService, 0, NULL); 01825 } 01826 01827 ServiceEntry = ServiceEntry->Flink; 01828 } 01829 } 01830 01831 /* Start all services which have an invalid tag or which do not have a tag */ 01832 ServiceEntry = ServiceListHead.Flink; 01833 while (ServiceEntry != &ServiceListHead) 01834 { 01835 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 01836 01837 if ((CurrentService->lpGroup == CurrentGroup) && 01838 (CurrentService->dwStartType == SERVICE_AUTO_START) && 01839 (CurrentService->ServiceVisited == FALSE)) 01840 { 01841 CurrentService->ServiceVisited = TRUE; 01842 ScmStartService(CurrentService, 0, NULL); 01843 } 01844 01845 ServiceEntry = ServiceEntry->Flink; 01846 } 01847 01848 GroupEntry = GroupEntry->Flink; 01849 } 01850 01851 /* Start all services which are members of any non-existing group */ 01852 ServiceEntry = ServiceListHead.Flink; 01853 while (ServiceEntry != &ServiceListHead) 01854 { 01855 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 01856 01857 if ((CurrentService->lpGroup != NULL) && 01858 (CurrentService->dwStartType == SERVICE_AUTO_START) && 01859 (CurrentService->ServiceVisited == FALSE)) 01860 { 01861 CurrentService->ServiceVisited = TRUE; 01862 ScmStartService(CurrentService, 0, NULL); 01863 } 01864 01865 ServiceEntry = ServiceEntry->Flink; 01866 } 01867 01868 /* Start all services which are not a member of any group */ 01869 ServiceEntry = ServiceListHead.Flink; 01870 while (ServiceEntry != &ServiceListHead) 01871 { 01872 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 01873 01874 if ((CurrentService->lpGroup == NULL) && 01875 (CurrentService->dwStartType == SERVICE_AUTO_START) && 01876 (CurrentService->ServiceVisited == FALSE)) 01877 { 01878 CurrentService->ServiceVisited = TRUE; 01879 ScmStartService(CurrentService, 0, NULL); 01880 } 01881 01882 ServiceEntry = ServiceEntry->Flink; 01883 } 01884 01885 /* Clear 'ServiceVisited' flag again */ 01886 ServiceEntry = ServiceListHead.Flink; 01887 while (ServiceEntry != &ServiceListHead) 01888 { 01889 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 01890 CurrentService->ServiceVisited = FALSE; 01891 ServiceEntry = ServiceEntry->Flink; 01892 } 01893 } 01894 01895 01896 VOID 01897 ScmAutoShutdownServices(VOID) 01898 { 01899 PLIST_ENTRY ServiceEntry; 01900 PSERVICE CurrentService; 01901 01902 DPRINT("ScmAutoShutdownServices() called\n"); 01903 01904 /* Lock the service database exclusively */ 01905 ScmLockDatabaseExclusive(); 01906 01907 ServiceEntry = ServiceListHead.Flink; 01908 while (ServiceEntry != &ServiceListHead) 01909 { 01910 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 01911 01912 if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING || 01913 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING) 01914 { 01915 /* shutdown service */ 01916 DPRINT("Shutdown service: %S\n", CurrentService->szServiceName); 01917 ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN); 01918 } 01919 01920 ServiceEntry = ServiceEntry->Flink; 01921 } 01922 01923 /* Unlock the service database */ 01924 ScmUnlockDatabase(); 01925 01926 DPRINT("ScmAutoShutdownServices() done\n"); 01927 } 01928 01929 01930 BOOL 01931 ScmLockDatabaseExclusive(VOID) 01932 { 01933 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE); 01934 } 01935 01936 01937 BOOL 01938 ScmLockDatabaseShared(VOID) 01939 { 01940 return RtlAcquireResourceShared(&DatabaseLock, TRUE); 01941 } 01942 01943 01944 VOID 01945 ScmUnlockDatabase(VOID) 01946 { 01947 RtlReleaseResource(&DatabaseLock); 01948 } 01949 01950 01951 VOID 01952 ScmInitNamedPipeCriticalSection(VOID) 01953 { 01954 HKEY hKey; 01955 DWORD dwKeySize; 01956 DWORD dwError; 01957 01958 InitializeCriticalSection(&ControlServiceCriticalSection); 01959 01960 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 01961 L"SYSTEM\\CurrentControlSet\\Control", 01962 0, 01963 KEY_READ, 01964 &hKey); 01965 if (dwError == ERROR_SUCCESS) 01966 { 01967 dwKeySize = sizeof(DWORD); 01968 RegQueryValueExW(hKey, 01969 L"ServicesPipeTimeout", 01970 0, 01971 NULL, 01972 (LPBYTE)&dwPipeTimeout, 01973 &dwKeySize); 01974 01975 RegCloseKey(hKey); 01976 } 01977 } 01978 01979 01980 VOID 01981 ScmDeleteNamedPipeCriticalSection(VOID) 01982 { 01983 DeleteCriticalSection(&ControlServiceCriticalSection); 01984 } 01985 01986 /* EOF */ Generated on Thu May 24 2012 04:19:00 for ReactOS by
1.7.6.1
|