Something went wrong. Try again.
Reactos
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425/* * PROJECT: ReactOS Service Control Manager * LICENSE: GPL - See COPYING in the top level directory * FILE: base/system/services/database.c * PURPOSE: Database control interface * COPYRIGHT: Copyright 2002-2006 Eric Kohl * Copyright 2006 Hervé Poussineau <hpoussin@reactos.org> * Copyright 2007 Ged Murphy <gedmurphy@reactos.org> * Gregor Brunmar <gregor.brunmar@home.se> * */
/* INCLUDES *****************************************************************/
#include "services.h"
#include <winbase_undoc.h>#include <userenv.h>#include <strsafe.h>
#define NDEBUG#include <debug.h>
/* GLOBALS *******************************************************************/
LIST_ENTRY ImageListHead;LIST_ENTRY ServiceListHead;
static RTL_RESOURCE DatabaseLock;static DWORD ResumeCount = 1;static DWORD NoInteractiveServices = 0;static DWORD ServiceTag = 0;
/* The critical section synchronizes service control requests */static CRITICAL_SECTION ControlServiceCriticalSection;static DWORD PipeTimeout = 30000; /* 30 Seconds */
/* FUNCTIONS *****************************************************************/
staticBOOLScmIsSecurityService( _In_ PSERVICE_IMAGE pServiceImage){ return (wcsstr(pServiceImage->pszImagePath, L"\\system32\\lsass.exe") != NULL);}
static DWORDScmCreateNewControlPipe( _In_ PSERVICE_IMAGE pServiceImage, _In_ BOOL bSecurityServiceProcess){ WCHAR szControlPipeName[MAX_PATH + 1]; SECURITY_ATTRIBUTES SecurityAttributes; HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE; DWORD dwServiceCurrent = 1; DWORD dwKeyDisposition; DWORD dwKeySize; DWORD dwError;
/* Get the service number */ if (bSecurityServiceProcess == FALSE) { /* TODO: Create registry entry with correct write access */ dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL, REG_OPTION_VOLATILE, KEY_WRITE | KEY_READ, NULL, &hServiceCurrentKey, &dwKeyDisposition); if (dwError != ERROR_SUCCESS) { DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError); return dwError; }
if (dwKeyDisposition == REG_OPENED_EXISTING_KEY) { dwKeySize = sizeof(DWORD); dwError = RegQueryValueExW(hServiceCurrentKey, L"", 0, NULL, (BYTE*)&dwServiceCurrent, &dwKeySize); if (dwError != ERROR_SUCCESS) { RegCloseKey(hServiceCurrentKey); DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError); return dwError; }
dwServiceCurrent++; }
dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&dwServiceCurrent, sizeof(dwServiceCurrent));
RegCloseKey(hServiceCurrentKey);
if (dwError != ERROR_SUCCESS) { DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError); return dwError; } } else { dwServiceCurrent = 0; }
/* Create '\\.\pipe\net\NtControlPipeXXX' instance */ StringCchPrintfW(szControlPipeName, ARRAYSIZE(szControlPipeName), L"\\\\.\\pipe\\net\\NtControlPipe%lu", dwServiceCurrent);
DPRINT("PipeName: %S\n", szControlPipeName);
SecurityAttributes.nLength = sizeof(SecurityAttributes); SecurityAttributes.lpSecurityDescriptor = pPipeSD; SecurityAttributes.bInheritHandle = FALSE;
pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 100, 8000, 4, PipeTimeout, &SecurityAttributes); DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName); if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE) { DPRINT1("Failed to create control pipe\n"); return GetLastError(); }
return ERROR_SUCCESS;}
static PSERVICE_IMAGEScmGetServiceImageByImagePath(LPWSTR lpImagePath){ PLIST_ENTRY ImageEntry; PSERVICE_IMAGE CurrentImage;
DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath);
ImageEntry = ImageListHead.Flink; while (ImageEntry != &ImageListHead) { CurrentImage = CONTAINING_RECORD(ImageEntry, SERVICE_IMAGE, ImageListEntry); if (_wcsicmp(CurrentImage->pszImagePath, lpImagePath) == 0) { DPRINT("Found image: '%S'\n", CurrentImage->pszImagePath); return CurrentImage; }
ImageEntry = ImageEntry->Flink; }
DPRINT("Couldn't find a matching image\n");
return NULL;
}
DWORDScmGetServiceNameFromTag(IN PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams, OUT PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS *OutParams){ PLIST_ENTRY ServiceEntry; PSERVICE CurrentService; PSERVICE_IMAGE CurrentImage; PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutBuffer = NULL; DWORD dwError;
/* Lock the database */ ScmLockDatabaseExclusive();
/* Find the matching service */ ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
/* We must match the tag */ if (CurrentService->dwServiceTag == InParams->dwTag && CurrentService->lpImage != NULL) { CurrentImage = CurrentService->lpImage; /* And matching the PID */ if (CurrentImage->dwProcessId == InParams->dwPid) { break; } }
ServiceEntry = ServiceEntry->Flink; }
/* No match! */ if (ServiceEntry == &ServiceListHead) { dwError = ERROR_RETRY; goto Cleanup; }
/* Allocate the output buffer */ OutBuffer = MIDL_user_allocate(sizeof(TAG_INFO_NAME_FROM_TAG_OUT_PARAMS)); if (OutBuffer == NULL) { dwError = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
/* And the buffer for the name */ OutBuffer->pszName = MIDL_user_allocate(wcslen(CurrentService->lpServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL)); if (OutBuffer->pszName == NULL) { dwError = ERROR_NOT_ENOUGH_MEMORY; goto Cleanup; }
/* Fill in output data */ wcscpy(OutBuffer->pszName, CurrentService->lpServiceName); OutBuffer->TagType = TagTypeService;
/* And return */ *OutParams = OutBuffer; dwError = ERROR_SUCCESS;
Cleanup:
/* Unlock database */ ScmUnlockDatabase();
/* If failure, free allocated memory */ if (dwError != ERROR_SUCCESS) { if (OutBuffer != NULL) { MIDL_user_free(OutBuffer); } }
/* Return error/success */ return dwError;}
staticBOOLScmIsSameServiceAccount( _In_ PCWSTR pszAccountName1, _In_ PCWSTR pszAccountName2){ if (pszAccountName1 == NULL && pszAccountName2 == NULL) return TRUE;
if (pszAccountName1 == NULL && pszAccountName2 != NULL && _wcsicmp(pszAccountName2, L"LocalSystem") == 0) return TRUE;
if (pszAccountName1 != NULL && pszAccountName2 == NULL && _wcsicmp(pszAccountName1, L"LocalSystem") == 0) return TRUE;
if (pszAccountName1 != NULL && pszAccountName2 != NULL && _wcsicmp(pszAccountName1, pszAccountName2) == 0) return TRUE;
return FALSE;}
staticBOOLScmIsLocalSystemAccount( _In_ PCWSTR pszAccountName){ if (pszAccountName == NULL || _wcsicmp(pszAccountName, L"LocalSystem") == 0) return TRUE;
return FALSE;}
staticBOOLScmEnableBackupRestorePrivileges( _In_ HANDLE hToken, _In_ BOOL bEnable){ PTOKEN_PRIVILEGES pTokenPrivileges = NULL; DWORD dwSize; BOOL bRet = FALSE;
DPRINT("ScmEnableBackupRestorePrivileges(%p %d)\n", hToken, bEnable);
dwSize = sizeof(TOKEN_PRIVILEGES) + 2 * sizeof(LUID_AND_ATTRIBUTES); pTokenPrivileges = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize); if (pTokenPrivileges == NULL) { DPRINT1("Failed to allocate privilege buffer\n"); goto done; }
pTokenPrivileges->PrivilegeCount = 2; pTokenPrivileges->Privileges[0].Luid.LowPart = SE_BACKUP_PRIVILEGE; pTokenPrivileges->Privileges[0].Luid.HighPart = 0; pTokenPrivileges->Privileges[0].Attributes = (bEnable ? SE_PRIVILEGE_ENABLED : 0); pTokenPrivileges->Privileges[1].Luid.LowPart = SE_RESTORE_PRIVILEGE; pTokenPrivileges->Privileges[1].Luid.HighPart = 0; pTokenPrivileges->Privileges[1].Attributes = (bEnable ? SE_PRIVILEGE_ENABLED : 0);
bRet = AdjustTokenPrivileges(hToken, FALSE, pTokenPrivileges, 0, NULL, NULL); if (!bRet) { DPRINT1("AdjustTokenPrivileges() failed with error %lu\n", GetLastError()); } else if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) { DPRINT1("AdjustTokenPrivileges() succeeded, but with not all privileges assigned\n"); bRet = FALSE; }
done: if (pTokenPrivileges != NULL) HeapFree(GetProcessHeap(), 0, pTokenPrivileges);
return bRet;}
staticDWORDScmLogonService( IN PSERVICE pService, IN PSERVICE_IMAGE pImage){ PROFILEINFOW ProfileInfo; PWSTR pszUserName = NULL; PWSTR pszDomainName = NULL; PWSTR pszPassword = NULL; PWSTR ptr; DWORD dwError = ERROR_SUCCESS;
DPRINT("ScmLogonService(%p %p)\n", pService, pImage); DPRINT("Service %S\n", pService->lpServiceName);
if (ScmIsLocalSystemAccount(pImage->pszAccountName) || ScmLiveSetup || ScmSetupInProgress) return ERROR_SUCCESS;
/* Get the user and domain names */ ptr = wcschr(pImage->pszAccountName, L'\\'); if (ptr != NULL) { *ptr = L'\0'; pszUserName = ptr + 1; pszDomainName = pImage->pszAccountName; } else { // ERROR_INVALID_SERVICE_ACCOUNT pszUserName = pImage->pszAccountName; pszDomainName = NULL; }
/* Build the service 'password' */ pszPassword = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pService->lpServiceName) + 5) * sizeof(WCHAR)); if (pszPassword == NULL) { dwError = ERROR_NOT_ENOUGH_MEMORY; goto done; }
wcscpy(pszPassword, L"_SC_"); wcscat(pszPassword, pService->lpServiceName);
DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName, pszUserName, pszPassword);
/* Do the service logon */ if (!LogonUserW(pszUserName, pszDomainName, pszPassword, LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT, &pImage->hToken)) { dwError = GetLastError(); DPRINT1("LogonUserW() failed (Error %lu)\n", dwError);
/* Normalize the returned error */ dwError = ERROR_SERVICE_LOGON_FAILED; goto done; }
/* Load the user profile; the per-user environment variables are thus correctly initialized */ ZeroMemory(&ProfileInfo, sizeof(ProfileInfo)); ProfileInfo.dwSize = sizeof(ProfileInfo); ProfileInfo.dwFlags = PI_NOUI; ProfileInfo.lpUserName = pszUserName; // ProfileInfo.lpProfilePath = NULL; // ProfileInfo.lpDefaultPath = NULL; // ProfileInfo.lpServerName = NULL; // ProfileInfo.lpPolicyPath = NULL; // ProfileInfo.hProfile = NULL;
ScmEnableBackupRestorePrivileges(pImage->hToken, TRUE); if (!LoadUserProfileW(pImage->hToken, &ProfileInfo)) dwError = GetLastError(); ScmEnableBackupRestorePrivileges(pImage->hToken, FALSE);
if (dwError != ERROR_SUCCESS) { DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError); goto done; }
pImage->hProfile = ProfileInfo.hProfile;
done: if (pszPassword != NULL) HeapFree(GetProcessHeap(), 0, pszPassword);
if (ptr != NULL) *ptr = L'\\';
return dwError;}
static DWORDScmCreateOrReferenceServiceImage(PSERVICE pService){ RTL_QUERY_REGISTRY_TABLE QueryTable[3]; UNICODE_STRING ImagePath; UNICODE_STRING ObjectName; PSERVICE_IMAGE pServiceImage = NULL; NTSTATUS Status; DWORD dwError = ERROR_SUCCESS; DWORD dwRecordSize; LPWSTR pString; BOOL bSecurityService;
DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService);
RtlInitUnicodeString(&ImagePath, NULL); RtlInitUnicodeString(&ObjectName, NULL);
/* Get service data */ RtlZeroMemory(&QueryTable, sizeof(QueryTable));
QueryTable[0].Name = L"ImagePath"; QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; QueryTable[0].EntryContext = &ImagePath; QueryTable[1].Name = L"ObjectName"; QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; QueryTable[1].EntryContext = &ObjectName;
Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, pService->lpServiceName, QueryTable, NULL, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); return RtlNtStatusToDosError(Status); }
DPRINT("ImagePath: '%wZ'\n", &ImagePath); DPRINT("ObjectName: '%wZ'\n", &ObjectName);
pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer); if (pServiceImage == NULL) { dwRecordSize = sizeof(SERVICE_IMAGE) + ImagePath.Length + sizeof(WCHAR) + ((ObjectName.Length != 0) ? (ObjectName.Length + sizeof(WCHAR)) : 0);
/* Create a new service image */ pServiceImage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwRecordSize); if (pServiceImage == NULL) { dwError = ERROR_NOT_ENOUGH_MEMORY; goto done; }
pServiceImage->dwImageRunCount = 1; pServiceImage->hControlPipe = INVALID_HANDLE_VALUE; pServiceImage->hProcess = INVALID_HANDLE_VALUE;
pString = (PWSTR)((INT_PTR)pServiceImage + sizeof(SERVICE_IMAGE));
/* Set the image path */ pServiceImage->pszImagePath = pString; wcscpy(pServiceImage->pszImagePath, ImagePath.Buffer);
/* Set the account name */ if (ObjectName.Length > 0) { pString = pString + wcslen(pString) + 1;
pServiceImage->pszAccountName = pString; wcscpy(pServiceImage->pszAccountName, ObjectName.Buffer); }
/* Service logon */ dwError = ScmLogonService(pService, pServiceImage); if (dwError != ERROR_SUCCESS) { DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError);
/* Release the service image */ HeapFree(GetProcessHeap(), 0, pServiceImage);
goto done; }
bSecurityService = ScmIsSecurityService(pServiceImage);
/* Create the control pipe */ dwError = ScmCreateNewControlPipe(pServiceImage, bSecurityService); if (dwError != ERROR_SUCCESS) { DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError);
/* Unload the user profile */ if (pServiceImage->hProfile != NULL) { ScmEnableBackupRestorePrivileges(pServiceImage->hToken, TRUE); UnloadUserProfile(pServiceImage->hToken, pServiceImage->hProfile); ScmEnableBackupRestorePrivileges(pServiceImage->hToken, FALSE); }
/* Close the logon token */ if (pServiceImage->hToken != NULL) CloseHandle(pServiceImage->hToken);
/* Release the service image */ HeapFree(GetProcessHeap(), 0, pServiceImage);
goto done; }
if (bSecurityService) { SetSecurityServicesEvent(); }
/* FIXME: Add more initialization code here */
/* Append service record */ InsertTailList(&ImageListHead, &pServiceImage->ImageListEntry); } else {// if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0)
/* Fail if services in an image use different accounts */ if (!ScmIsSameServiceAccount(pServiceImage->pszAccountName, ObjectName.Buffer)) { dwError = ERROR_DIFFERENT_SERVICE_ACCOUNT; goto done; }
/* Increment the run counter */ pServiceImage->dwImageRunCount++; }
DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage->pszImagePath); DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage->pszAccountName); DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount);
/* Link the service image to the service */ pService->lpImage = pServiceImage;
done: RtlFreeUnicodeString(&ObjectName); RtlFreeUnicodeString(&ImagePath);
DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError);
return dwError;}
VOIDScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage){ DPRINT1("ScmRemoveServiceImage() called\n");
/* FIXME: Terminate the process */
/* Remove the service image from the list */ RemoveEntryList(&pServiceImage->ImageListEntry);
/* Close the process handle */ if (pServiceImage->hProcess != INVALID_HANDLE_VALUE) CloseHandle(pServiceImage->hProcess);
/* Close the control pipe */ if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE) CloseHandle(pServiceImage->hControlPipe);
/* Unload the user profile */ if (pServiceImage->hProfile != NULL) { ScmEnableBackupRestorePrivileges(pServiceImage->hToken, TRUE); UnloadUserProfile(pServiceImage->hToken, pServiceImage->hProfile); ScmEnableBackupRestorePrivileges(pServiceImage->hToken, FALSE); }
/* Close the logon token */ if (pServiceImage->hToken != NULL) CloseHandle(pServiceImage->hToken);
/* Release the service image */ HeapFree(GetProcessHeap(), 0, pServiceImage);}
PSERVICEScmGetServiceEntryByName(LPCWSTR lpServiceName){ PLIST_ENTRY ServiceEntry; PSERVICE CurrentService;
DPRINT("ScmGetServiceEntryByName() called\n");
ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0) { DPRINT("Found service: '%S'\n", CurrentService->lpServiceName); return CurrentService; }
ServiceEntry = ServiceEntry->Flink; }
DPRINT("Couldn't find a matching service\n");
return NULL;}
PSERVICEScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName){ PLIST_ENTRY ServiceEntry; PSERVICE CurrentService;
DPRINT("ScmGetServiceEntryByDisplayName() called\n");
ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0) { DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName); return CurrentService; }
ServiceEntry = ServiceEntry->Flink; }
DPRINT("Couldn't find a matching service\n");
return NULL;}
PSERVICEScmGetServiceEntryByResumeCount(DWORD dwResumeCount){ PLIST_ENTRY ServiceEntry; PSERVICE CurrentService;
DPRINT("ScmGetServiceEntryByResumeCount() called\n");
ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); if (CurrentService->dwResumeCount > dwResumeCount) { DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName); return CurrentService; }
ServiceEntry = ServiceEntry->Flink; }
DPRINT("Couldn't find a matching service\n");
return NULL;}
DWORDScmGenerateServiceTag(PSERVICE lpServiceRecord){ /* Check for an overflow */ if (ServiceTag == -1) { return ERROR_INVALID_DATA; }
/* This is only valid for Win32 services */ if (!(lpServiceRecord->Status.dwServiceType & SERVICE_WIN32)) { return ERROR_INVALID_PARAMETER; }
/* Increment the tag counter and set it */ ServiceTag = ServiceTag % 0xFFFFFFFF + 1; lpServiceRecord->dwServiceTag = ServiceTag;
return ERROR_SUCCESS;}
DWORDScmCreateNewServiceRecord(LPCWSTR lpServiceName, PSERVICE *lpServiceRecord, DWORD dwServiceType, DWORD dwStartType){ PSERVICE lpService = NULL;
DPRINT("Service: '%S'\n", lpServiceName);
/* Allocate service entry */ lpService = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(SERVICE, szServiceName[wcslen(lpServiceName) + 1])); if (lpService == NULL) return ERROR_NOT_ENOUGH_MEMORY;
*lpServiceRecord = lpService;
/* Copy service name */ wcscpy(lpService->szServiceName, lpServiceName); lpService->lpServiceName = lpService->szServiceName; lpService->lpDisplayName = lpService->lpServiceName;
/* Set the start type */ lpService->dwStartType = dwStartType;
/* Set the resume count */ lpService->dwResumeCount = ResumeCount++;
/* Append service record */ InsertTailList(&ServiceListHead, &lpService->ServiceListEntry);
/* Initialize the service status */ lpService->Status.dwServiceType = dwServiceType; lpService->Status.dwCurrentState = SERVICE_STOPPED; lpService->Status.dwControlsAccepted = 0; lpService->Status.dwWin32ExitCode = (dwStartType == SERVICE_DISABLED) ? ERROR_SERVICE_DISABLED : ERROR_SERVICE_NEVER_STARTED; lpService->Status.dwServiceSpecificExitCode = 0; lpService->Status.dwCheckPoint = 0; lpService->Status.dwWaitHint = (dwServiceType & SERVICE_DRIVER) ? 0 : 2000; /* 2 seconds */
return ERROR_SUCCESS;}
VOIDScmDeleteServiceRecord(PSERVICE lpService){ DPRINT("Deleting Service %S\n", lpService->lpServiceName);
/* Delete the display name */ if (lpService->lpDisplayName != NULL && lpService->lpDisplayName != lpService->lpServiceName) HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
/* Dereference the service image */ if (lpService->lpImage) { lpService->lpImage->dwImageRunCount--;
if (lpService->lpImage->dwImageRunCount == 0) { ScmRemoveServiceImage(lpService->lpImage); lpService->lpImage = NULL; } }
/* Decrement the group reference counter */ ScmSetServiceGroup(lpService, NULL);
/* Release the SecurityDescriptor */ if (lpService->pSecurityDescriptor != NULL) HeapFree(GetProcessHeap(), 0, lpService->pSecurityDescriptor);
/* Remove the Service from the List */ RemoveEntryList(&lpService->ServiceListEntry);
DPRINT("Deleted Service %S\n", lpService->lpServiceName);
/* Delete the service record */ HeapFree(GetProcessHeap(), 0, lpService);
DPRINT("Done\n");}
DWORDInt_EnumDependentServicesW(HKEY hServicesKey, PSERVICE lpService, DWORD dwServiceState, PSERVICE *lpServices, LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned);
DWORD ScmDeleteService(PSERVICE lpService){ DWORD dwError; DWORD pcbBytesNeeded = 0; DWORD dwServicesReturned = 0; HKEY hServicesKey;
ASSERT(lpService->RefCount == 0);
/* Open the Services Reg key */ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services", 0, KEY_SET_VALUE | KEY_READ, &hServicesKey); if (dwError != ERROR_SUCCESS) { DPRINT1("Failed to open services key\n"); return dwError; }
/* Call the function with NULL, just to get bytes we need */ Int_EnumDependentServicesW(hServicesKey, lpService, SERVICE_ACTIVE, NULL, &pcbBytesNeeded, &dwServicesReturned);
/* If pcbBytesNeeded returned a value then there are services running that are dependent on this service */ if (pcbBytesNeeded) { DPRINT1("Deletion failed due to running dependencies\n"); RegCloseKey(hServicesKey); return ERROR_DEPENDENT_SERVICES_RUNNING; }
/* There are no references and no running dependencies, it is now safe to delete the service */
/* Delete the Service Key */ dwError = ScmDeleteRegKey(hServicesKey, lpService->lpServiceName);
RegCloseKey(hServicesKey);
if (dwError != ERROR_SUCCESS) { DPRINT1("Failed to delete the Service Registry key\n"); return dwError; }
/* Delete the Service */ ScmDeleteServiceRecord(lpService);
return ERROR_SUCCESS;}
/* * This function allows the caller to be sure that the service won't be freed unexpectedly. * In order to be sure that lpService will be valid until the reference is added * the caller needs to hold the database lock. * A running service will keep a reference for the whole time it is not SERVICE_STOPPED. * A service handle will also keep a reference to a service. Keeping a reference is * really needed so that ScmControlService can be called without keeping the database locked. * This means that eventually the correct order of operations to send a control message to * a service looks like: lock, reference, unlock, send control, lock, dereference, unlock. */DWORDScmReferenceService(PSERVICE lpService){ return InterlockedIncrement(&lpService->RefCount);}
/* This function must be called with the database lock held exclusively as it can end up deleting the service */DWORDScmDereferenceService(PSERVICE lpService){ DWORD ref;
ASSERT(lpService->RefCount > 0);
ref = InterlockedDecrement(&lpService->RefCount);
if (ref == 0 && lpService->bDeleted && lpService->Status.dwCurrentState == SERVICE_STOPPED) { ScmDeleteService(lpService); } return ref;}
static DWORDCreateServiceListEntry(LPCWSTR lpServiceName, HKEY hServiceKey){ PSERVICE lpService = NULL; LPWSTR lpDisplayName = NULL; LPWSTR lpGroup = NULL; DWORD dwSize; DWORD dwError; DWORD dwServiceType; DWORD dwStartType; DWORD dwErrorControl; DWORD dwTagId;
DPRINT("Service: '%S'\n", lpServiceName); if (*lpServiceName == L'{') return ERROR_SUCCESS;
dwSize = sizeof(DWORD); dwError = RegQueryValueExW(hServiceKey, L"Type", NULL, NULL, (LPBYTE)&dwServiceType, &dwSize); if (dwError != ERROR_SUCCESS) return ERROR_SUCCESS;
if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) && ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) && (dwServiceType != SERVICE_KERNEL_DRIVER) && (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)) return ERROR_SUCCESS;
DPRINT("Service type: %lx\n", dwServiceType);
dwSize = sizeof(DWORD); dwError = RegQueryValueExW(hServiceKey, L"Start", NULL, NULL, (LPBYTE)&dwStartType, &dwSize); if (dwError != ERROR_SUCCESS) return ERROR_SUCCESS;
DPRINT("Start type: %lx\n", dwStartType);
dwSize = sizeof(DWORD); dwError = RegQueryValueExW(hServiceKey, L"ErrorControl", NULL, NULL, (LPBYTE)&dwErrorControl, &dwSize); if (dwError != ERROR_SUCCESS) return ERROR_SUCCESS;
DPRINT("Error control: %lx\n", dwErrorControl);
dwError = RegQueryValueExW(hServiceKey, L"Tag", NULL, NULL, (LPBYTE)&dwTagId, &dwSize); if (dwError != ERROR_SUCCESS) dwTagId = 0;
DPRINT("Tag: %lx\n", dwTagId);
dwError = ScmReadString(hServiceKey, L"Group", &lpGroup); if (dwError != ERROR_SUCCESS) lpGroup = NULL;
DPRINT("Group: %S\n", lpGroup);
dwError = ScmReadString(hServiceKey, L"DisplayName", &lpDisplayName); if (dwError != ERROR_SUCCESS) lpDisplayName = NULL;
DPRINT("Display name: %S\n", lpDisplayName);
dwError = ScmCreateNewServiceRecord(lpServiceName, &lpService, dwServiceType, dwStartType); if (dwError != ERROR_SUCCESS) goto done;
lpService->dwErrorControl = dwErrorControl; lpService->dwTag = dwTagId;
if (lpGroup != NULL) { dwError = ScmSetServiceGroup(lpService, lpGroup); if (dwError != ERROR_SUCCESS) goto done; }
if (lpDisplayName != NULL) { lpService->lpDisplayName = lpDisplayName; lpDisplayName = NULL; }
DPRINT("ServiceName: '%S'\n", lpService->lpServiceName); if (lpService->lpGroup != NULL) { DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName); } DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n", lpService->dwStartType, lpService->Status.dwServiceType, lpService->dwTag, lpService->dwErrorControl);
if (ScmIsDeleteFlagSet(hServiceKey)) lpService->bDeleted = TRUE; else ScmGenerateServiceTag(lpService);
if (lpService->Status.dwServiceType & SERVICE_WIN32) { dwError = ScmReadSecurityDescriptor(hServiceKey, &lpService->pSecurityDescriptor); if (dwError != ERROR_SUCCESS) goto done;
/* Assing the default security descriptor if the security descriptor cannot be read */ if (lpService->pSecurityDescriptor == NULL) { DPRINT("No security descriptor found! Assign default security descriptor\n"); dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor); if (dwError != ERROR_SUCCESS) goto done;
dwError = ScmWriteSecurityDescriptor(hServiceKey, lpService->pSecurityDescriptor); if (dwError != ERROR_SUCCESS) goto done; } }
done: if (lpGroup != NULL) HeapFree(GetProcessHeap(), 0, lpGroup);
if (lpDisplayName != NULL) HeapFree(GetProcessHeap(), 0, lpDisplayName);
if (lpService != NULL) { ASSERT(lpService->lpImage == NULL); }
return dwError;}
VOIDScmDeleteMarkedServices(VOID){ PLIST_ENTRY ServiceEntry; PSERVICE CurrentService; HKEY hServicesKey; DWORD dwError;
ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
ServiceEntry = ServiceEntry->Flink;
if (CurrentService->bDeleted != FALSE) { dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services", 0, DELETE, &hServicesKey); if (dwError == ERROR_SUCCESS) { dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName); RegCloseKey(hServicesKey); if (dwError == ERROR_SUCCESS) { RemoveEntryList(&CurrentService->ServiceListEntry); HeapFree(GetProcessHeap(), 0, CurrentService); } }
if (dwError != ERROR_SUCCESS) DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName); } }}
staticVOIDScmGetNoInteractiveServicesValue(VOID){ HKEY hKey; DWORD dwKeySize; LONG lError;
lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\Windows", 0, KEY_READ, &hKey); if (lError == ERROR_SUCCESS) { dwKeySize = sizeof(NoInteractiveServices); lError = RegQueryValueExW(hKey, L"NoInteractiveServices", 0, NULL, (LPBYTE)&NoInteractiveServices, &dwKeySize); RegCloseKey(hKey); }}
DWORDScmCreateServiceDatabase(VOID){ WCHAR szSubKey[MAX_PATH]; HKEY hServicesKey; HKEY hServiceKey; DWORD dwSubKey; DWORD dwSubKeyLength; FILETIME ftLastChanged; DWORD dwError;
DPRINT("ScmCreateServiceDatabase() called\n");
/* Retrieve the NoInteractiveServies value */ ScmGetNoInteractiveServicesValue();
/* Create the service group list */ dwError = ScmCreateGroupList(); if (dwError != ERROR_SUCCESS) return dwError;
/* Initialize image and service lists */ InitializeListHead(&ImageListHead); InitializeListHead(&ServiceListHead);
/* Initialize the database lock */ RtlInitializeResource(&DatabaseLock);
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services", 0, KEY_READ, &hServicesKey); if (dwError != ERROR_SUCCESS) return dwError;
dwSubKey = 0; for (;;) { dwSubKeyLength = MAX_PATH; dwError = RegEnumKeyExW(hServicesKey, dwSubKey, szSubKey, &dwSubKeyLength, NULL, NULL, NULL, &ftLastChanged); if (dwError == ERROR_SUCCESS && szSubKey[0] != L'{') { DPRINT("SubKeyName: '%S'\n", szSubKey);
dwError = RegOpenKeyExW(hServicesKey, szSubKey, 0, KEY_READ, &hServiceKey); if (dwError == ERROR_SUCCESS) { dwError = CreateServiceListEntry(szSubKey, hServiceKey);
RegCloseKey(hServiceKey); } }
if (dwError != ERROR_SUCCESS) break;
dwSubKey++; }
RegCloseKey(hServicesKey);
/* Wait for the LSA server */ ScmWaitForLsa();
/* Delete services that are marked for delete */ ScmDeleteMarkedServices();
DPRINT("ScmCreateServiceDatabase() done\n");
return ERROR_SUCCESS;}
VOIDScmShutdownServiceDatabase(VOID){ DPRINT("ScmShutdownServiceDatabase() called\n");
ScmDeleteMarkedServices(); RtlDeleteResource(&DatabaseLock);
DPRINT("ScmShutdownServiceDatabase() done\n");}
static NTSTATUSScmCheckDriver(PSERVICE Service){ OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING DirName; HANDLE DirHandle; NTSTATUS Status; POBJECT_DIRECTORY_INFORMATION DirInfo; ULONG BufferLength; ULONG DataLength; ULONG Index;
DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER) { RtlInitUnicodeString(&DirName, L"\\Driver"); } else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER) { ASSERT(Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER); RtlInitUnicodeString(&DirName, L"\\FileSystem"); }
InitializeObjectAttributes(&ObjectAttributes, &DirName, 0, NULL, NULL);
Status = NtOpenDirectoryObject(&DirHandle, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, &ObjectAttributes); if (!NT_SUCCESS(Status)) { return Status; }
BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) + 2 * MAX_PATH * sizeof(WCHAR); DirInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, BufferLength);
Index = 0; while (TRUE) { Status = NtQueryDirectoryObject(DirHandle, DirInfo, BufferLength, TRUE, FALSE, &Index, &DataLength); if (Status == STATUS_NO_MORE_ENTRIES) { /* FIXME: Add current service to 'failed service' list */ DPRINT("Service '%S' failed\n", Service->lpServiceName); break; }
if (!NT_SUCCESS(Status)) break;
DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0) { DPRINT("Found: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
/* Mark service as 'running' */ Service->Status.dwCurrentState = SERVICE_RUNNING; Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; Service->Status.dwWin32ExitCode = ERROR_SUCCESS; Service->Status.dwServiceSpecificExitCode = 0; Service->Status.dwCheckPoint = 0; Service->Status.dwWaitHint = 0;
/* Mark the service group as 'running' */ if (Service->lpGroup != NULL) { Service->lpGroup->ServicesRunning = TRUE; }
break; } }
HeapFree(GetProcessHeap(), 0, DirInfo); NtClose(DirHandle);
return STATUS_SUCCESS;}
VOIDScmGetBootAndSystemDriverState(VOID){ PLIST_ENTRY ServiceEntry; PSERVICE CurrentService;
DPRINT("ScmGetBootAndSystemDriverState() called\n");
ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
if (CurrentService->dwStartType == SERVICE_BOOT_START || CurrentService->dwStartType == SERVICE_SYSTEM_START) { /* Check driver */ DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
ScmCheckDriver(CurrentService); }
ServiceEntry = ServiceEntry->Flink; }
DPRINT("ScmGetBootAndSystemDriverState() done\n");}
/* * ScmSendControlPacket must never be called with the database lock being held. * The service passed must always be referenced instead. */DWORDScmSendControlPacket( _In_ HANDLE hControlPipe, _In_ PCWSTR pServiceName, _In_ DWORD dwControl, _In_ DWORD dwControlPacketSize, _In_ PVOID pControlPacket){ DWORD dwError = ERROR_SUCCESS; BOOL bResult; SCM_REPLY_PACKET ReplyPacket; DWORD dwReadCount = 0; OVERLAPPED Overlapped = {0};
DPRINT("ScmSendControlPacket(%p, %lu, %p) called\n", hControlPipe, dwControlPacketSize, pControlPacket);
/* Acquire the service control critical section, to synchronize requests */ EnterCriticalSection(&ControlServiceCriticalSection);
bResult = TransactNamedPipe(hControlPipe, pControlPacket, dwControlPacketSize, &ReplyPacket, sizeof(ReplyPacket), &dwReadCount, &Overlapped); if (!bResult) { /* Fail for any error other than pending IO */ dwError = GetLastError(); if (dwError != ERROR_IO_PENDING) { DPRINT1("TransactNamedPipe(%S, %d) failed (Error %lu)\n", pServiceName, dwControl, dwError); goto Done; }
DPRINT("TransactNamedPipe(%S, %d) returned ERROR_IO_PENDING\n", pServiceName, dwControl);
dwError = WaitForSingleObject(hControlPipe, PipeTimeout); DPRINT("WaitForSingleObject(%S, %d) returned %lu\n", pServiceName, dwControl, dwError);
if (dwError == WAIT_TIMEOUT) { DPRINT1("WaitForSingleObject(%S, %d) timed out\n", pServiceName, dwControl); bResult = CancelIo(hControlPipe); if (!bResult) DPRINT1("CancelIo(%S, %d) failed (Error %lu)\n", pServiceName, dwControl, GetLastError());
dwError = ERROR_SERVICE_REQUEST_TIMEOUT; } else if (dwError == WAIT_OBJECT_0) { bResult = GetOverlappedResult(hControlPipe, &Overlapped, &dwReadCount, TRUE); if (!bResult) { dwError = GetLastError(); DPRINT1("GetOverlappedResult(%S, %d) failed (Error %lu)\n", pServiceName, dwControl, dwError); } } }
Done: /* Release the service control critical section */ LeaveCriticalSection(&ControlServiceCriticalSection);
if (dwReadCount == sizeof(ReplyPacket)) dwError = ReplyPacket.dwError;
return dwError;}
DWORDScmControlServiceEx( _In_ HANDLE hControlPipe, _In_ PCWSTR pServiceName, _In_ DWORD dwControl, _In_ SERVICE_STATUS_HANDLE hServiceStatus, _In_opt_ DWORD dwServiceTag, _In_opt_ DWORD argc, _In_reads_opt_(argc) const PCWSTR* argv){ DWORD dwError = ERROR_SUCCESS; PSCM_CONTROL_PACKET ControlPacket; DWORD PacketSize; DWORD i; PWSTR Ptr;
DPRINT("ScmControlServiceEx(%S, %d) called\n", pServiceName, dwControl);
/* Calculate the total size of the control packet: * initial structure, the start command line, and the argument vector */ PacketSize = sizeof(SCM_CONTROL_PACKET); PacketSize += (DWORD)((wcslen(pServiceName) + 1) * sizeof(WCHAR));
/* * Calculate the required packet size for the start argument vector 'argv', * composed of the pointer offsets list, followed by UNICODE strings. * The strings are stored successively after the offsets vector, with * the offsets being relative to the beginning of the vector, as in the * following layout (with N == argc): * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] . */ if (argc > 0 && argv != NULL) { PacketSize = ALIGN_UP(PacketSize, PWSTR); PacketSize += (argc * sizeof(PWSTR));
DPRINT("Argc: %lu\n", argc); for (i = 0; i < argc; i++) { DPRINT("Argv[%lu]: %S\n", i, argv[i]); PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR)); } }
/* Allocate the control packet */ ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PacketSize); if (!ControlPacket) return ERROR_NOT_ENOUGH_MEMORY;
ControlPacket->dwSize = PacketSize; ControlPacket->dwControl = dwControl; ControlPacket->hServiceStatus = hServiceStatus; ControlPacket->dwServiceTag = dwServiceTag;
/* Copy the start command line */ ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); Ptr = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset); wcscpy(Ptr, pServiceName);
ControlPacket->dwArgumentsCount = 0; ControlPacket->dwArgumentsOffset = 0;
/* Copy the argument vector */ if (argc > 0 && argv != NULL) { PWSTR *pOffPtr, pArgPtr;
Ptr += wcslen(pServiceName) + 1; pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR); pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
ControlPacket->dwArgumentsCount = argc; ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount); DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset);
for (i = 0; i < argc; i++) { wcscpy(pArgPtr, argv[i]); pOffPtr[i] = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr); DPRINT("offset[%lu]: %p\n", i, pOffPtr[i]); pArgPtr += wcslen(argv[i]) + 1; } }
dwError = ScmSendControlPacket(hControlPipe, pServiceName, dwControl, PacketSize, ControlPacket);
/* Free the control packet */ HeapFree(GetProcessHeap(), 0, ControlPacket);
DPRINT("ScmControlServiceEx(%S, %d) done (Error %lu)\n", pServiceName, dwControl, dwError); return dwError;}
DWORDScmControlService( _In_ HANDLE hControlPipe, _In_ PCWSTR pServiceName, _In_ DWORD dwControl, _In_ SERVICE_STATUS_HANDLE hServiceStatus){ DWORD dwError = ERROR_SUCCESS; PSCM_CONTROL_PACKET ControlPacket; DWORD PacketSize; PWSTR Ptr;
DPRINT("ScmControlService(%S, %d) called\n", pServiceName, dwControl);
/* Calculate the total size of the control packet: * initial structure, the start command line, and the argument vector */ PacketSize = sizeof(SCM_CONTROL_PACKET); PacketSize += (DWORD)((wcslen(pServiceName) + 1) * sizeof(WCHAR));
/* Allocate the control packet */ ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PacketSize); if (!ControlPacket) return ERROR_NOT_ENOUGH_MEMORY;
ControlPacket->dwSize = PacketSize; ControlPacket->dwControl = dwControl; ControlPacket->hServiceStatus = hServiceStatus;
/* Copy the service name */ ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); Ptr = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset); wcscpy(Ptr, pServiceName);
/* Send the control packet */ dwError = ScmSendControlPacket(hControlPipe, pServiceName, dwControl, PacketSize, ControlPacket);
/* Free the control packet */ HeapFree(GetProcessHeap(), 0, ControlPacket);
DPRINT("ScmControlService(%S, %d) done (Error %lu)\n", pServiceName, dwControl, dwError); return dwError;}
static DWORDScmWaitForServiceConnect(PSERVICE Service){ DWORD dwRead = 0; DWORD dwProcessId = 0; DWORD dwError = ERROR_SUCCESS; BOOL bResult; OVERLAPPED Overlapped = {0};#if 0 LPCWSTR lpLogStrings[3]; WCHAR szBuffer1[20]; WCHAR szBuffer2[20];#endif
DPRINT("ScmWaitForServiceConnect()\n");
bResult = ConnectNamedPipe(Service->lpImage->hControlPipe, &Overlapped); if (bResult == FALSE) { DPRINT("ConnectNamedPipe() returned FALSE\n");
dwError = GetLastError(); if (dwError == ERROR_IO_PENDING) { DPRINT("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe, PipeTimeout); DPRINT("WaitForSingleObject() returned %lu\n", dwError);
if (dwError == WAIT_TIMEOUT) { DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
bResult = CancelIo(Service->lpImage->hControlPipe); if (bResult == FALSE) { DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); }
#if 0 _ultow(PipeTimeout, szBuffer1, 10); lpLogStrings[0] = Service->lpDisplayName; lpLogStrings[1] = szBuffer1;
ScmLogEvent(EVENT_CONNECTION_TIMEOUT, EVENTLOG_ERROR_TYPE, 2, lpLogStrings);#endif DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service->lpDisplayName);
return ERROR_SERVICE_REQUEST_TIMEOUT; } else if (dwError == WAIT_OBJECT_0) { bResult = GetOverlappedResult(Service->lpImage->hControlPipe, &Overlapped, &dwRead, TRUE); if (bResult == FALSE) { dwError = GetLastError(); DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError);
return dwError; } } } else if (dwError != ERROR_PIPE_CONNECTED) { DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError); return dwError; } }
DPRINT("Control pipe connected\n");
Overlapped.hEvent = NULL;
/* Read the process id from pipe */ bResult = ReadFile(Service->lpImage->hControlPipe, (LPVOID)&dwProcessId, sizeof(DWORD), &dwRead, &Overlapped); if (bResult == FALSE) { DPRINT("ReadFile() returned FALSE\n");
dwError = GetLastError(); if (dwError == ERROR_IO_PENDING) { DPRINT("dwError: ERROR_IO_PENDING\n");
dwError = WaitForSingleObject(Service->lpImage->hControlPipe, PipeTimeout); if (dwError == WAIT_TIMEOUT) { DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
bResult = CancelIo(Service->lpImage->hControlPipe); if (bResult == FALSE) { DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); }
#if 0 _ultow(PipeTimeout, szBuffer1, 10); lpLogStrings[0] = szBuffer1;
ScmLogEvent(EVENT_READFILE_TIMEOUT, EVENTLOG_ERROR_TYPE, 1, lpLogStrings);#endif DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service->lpDisplayName);
return ERROR_SERVICE_REQUEST_TIMEOUT; } else if (dwError == WAIT_OBJECT_0) { DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
DPRINT("Process Id: %lu\n", dwProcessId);
bResult = GetOverlappedResult(Service->lpImage->hControlPipe, &Overlapped, &dwRead, TRUE); if (bResult == FALSE) { dwError = GetLastError(); DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
return dwError; } } else { DPRINT1("WaitForSingleObject() returned %lu\n", dwError); } } else { DPRINT1("ReadFile() failed (Error %lu)\n", dwError); return dwError; } }
if ((ScmIsSecurityService(Service->lpImage) == FALSE)&& (dwProcessId != Service->lpImage->dwProcessId)) {#if 0 _ultow(Service->lpImage->dwProcessId, szBuffer1, 10); _ultow(dwProcessId, szBuffer2, 10);
lpLogStrings[0] = Service->lpDisplayName; lpLogStrings[1] = szBuffer1; lpLogStrings[2] = szBuffer2;
ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED, EVENTLOG_WARNING_TYPE, 3, lpLogStrings);#endif
DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service->lpDisplayName); }
DPRINT("ScmWaitForServiceConnect() done\n");
return ERROR_SUCCESS;}
static DWORDScmStartUserModeService(PSERVICE Service, DWORD argc, const PCWSTR* argv){ PROCESS_INFORMATION ProcessInformation; STARTUPINFOW StartupInfo; LPVOID lpEnvironment; BOOL Result; DWORD dwError = ERROR_SUCCESS;
DPRINT("ScmStartUserModeService(%p)\n", Service);
/* If the image is already running, just send a start command */ if (Service->lpImage->dwImageRunCount > 1) goto Quit;
/* Otherwise start its process */ ZeroMemory(&StartupInfo, sizeof(StartupInfo)); StartupInfo.cb = sizeof(StartupInfo); ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
if (Service->lpImage->hToken) { /* User token: Run the service under the user account */
if (!CreateEnvironmentBlock(&lpEnvironment, Service->lpImage->hToken, FALSE)) { /* We failed, run the service with the current environment */ DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with current environment\n", GetLastError(), Service->lpServiceName); lpEnvironment = NULL; }
/* Impersonate the new user */ Result = ImpersonateLoggedOnUser(Service->lpImage->hToken); if (Result) { /* Launch the process in the user's logon session */ Result = CreateProcessAsUserW(Service->lpImage->hToken, NULL, Service->lpImage->pszImagePath, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, lpEnvironment, NULL, &StartupInfo, &ProcessInformation); if (!Result) dwError = GetLastError();
/* Revert the impersonation */ RevertToSelf(); } else { dwError = GetLastError(); DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError); } } else { /* No user token: Run the service under the LocalSystem account */
if (!CreateEnvironmentBlock(&lpEnvironment, NULL, TRUE)) { /* We failed, run the service with the current environment */ DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with current environment\n", GetLastError(), Service->lpServiceName); lpEnvironment = NULL; }
/* Use the interactive desktop if the service is interactive */ if ((NoInteractiveServices == 0) && (Service->Status.dwServiceType & SERVICE_INTERACTIVE_PROCESS)) { StartupInfo.dwFlags |= STARTF_INHERITDESKTOP; StartupInfo.lpDesktop = L"WinSta0\\Default"; }
if (!ScmIsSecurityService(Service->lpImage)) { Result = CreateProcessW(NULL, Service->lpImage->pszImagePath, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, lpEnvironment, NULL, &StartupInfo, &ProcessInformation); if (!Result) dwError = GetLastError(); } else { Result = TRUE; dwError = ERROR_SUCCESS; } }
if (lpEnvironment) DestroyEnvironmentBlock(lpEnvironment);
if (!Result) { DPRINT1("Starting '%S' failed with error %d\n", Service->lpServiceName, dwError); return dwError; }
DPRINT("Process Id: %lu Handle %p\n", ProcessInformation.dwProcessId, ProcessInformation.hProcess); DPRINT("Thread Id: %lu Handle %p\n", ProcessInformation.dwThreadId, ProcessInformation.hThread);
/* Get the process handle and ID */ Service->lpImage->hProcess = ProcessInformation.hProcess; Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
/* Resume the main thread and close its handle */ ResumeThread(ProcessInformation.hThread); CloseHandle(ProcessInformation.hThread);
/* Connect control pipe */ dwError = ScmWaitForServiceConnect(Service); if (dwError != ERROR_SUCCESS) { DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); Service->lpImage->dwProcessId = 0; return dwError; }
Quit: /* Send the start command and return */ return ScmControlServiceEx(Service->lpImage->hControlPipe, Service->lpServiceName, (Service->Status.dwServiceType & SERVICE_WIN32_OWN_PROCESS) ? SERVICE_CONTROL_START_OWN : SERVICE_CONTROL_START_SHARE, (SERVICE_STATUS_HANDLE)Service, Service->dwServiceTag, argc, argv);}
static DWORDScmLoadService(PSERVICE Service, DWORD argc, const PCWSTR* argv){ PSERVICE_GROUP Group = Service->lpGroup; DWORD dwError = ERROR_SUCCESS; LPCWSTR lpLogStrings[2]; WCHAR szLogBuffer[80];
DPRINT("ScmLoadService() called\n"); DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
if (Service->Status.dwCurrentState != SERVICE_STOPPED) { DPRINT("Service %S is already running\n", Service->lpServiceName); return ERROR_SERVICE_ALREADY_RUNNING; }
DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
if (Service->Status.dwServiceType & SERVICE_DRIVER) { /* Start the driver */ dwError = ScmStartDriver(Service); } else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS)) { /* Start user-mode service */ dwError = ScmCreateOrReferenceServiceImage(Service); if (dwError == ERROR_SUCCESS) { dwError = ScmStartUserModeService(Service, argc, argv); if (dwError == ERROR_SUCCESS) { Service->Status.dwCurrentState = SERVICE_START_PENDING; Service->Status.dwControlsAccepted = 0; ScmReferenceService(Service); } else { Service->lpImage->dwImageRunCount--; if (Service->lpImage->dwImageRunCount == 0) { ScmRemoveServiceImage(Service->lpImage); Service->lpImage = NULL; } } } }
DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
if (dwError == ERROR_SUCCESS) { if (Group != NULL) { Group->ServicesRunning = TRUE; }
/* Log a successful service start */ LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_START, szLogBuffer, 80); lpLogStrings[0] = Service->lpDisplayName; lpLogStrings[1] = szLogBuffer;
ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS, EVENTLOG_INFORMATION_TYPE, 2, lpLogStrings); } else { if (Service->dwErrorControl != SERVICE_ERROR_IGNORE) { /* Log a failed service start */ StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer), L"%lu", dwError); lpLogStrings[0] = Service->lpServiceName; lpLogStrings[1] = szLogBuffer; ScmLogEvent(EVENT_SERVICE_START_FAILED, EVENTLOG_ERROR_TYPE, 2, lpLogStrings); }
#if 0 switch (Service->dwErrorControl) { case SERVICE_ERROR_SEVERE: if (IsLastKnownGood == FALSE) { /* FIXME: Boot last known good configuration */ } break;
case SERVICE_ERROR_CRITICAL: if (IsLastKnownGood == FALSE) { /* FIXME: Boot last known good configuration */ } else { /* FIXME: BSOD! */ } break; }#endif }
return dwError;}
DWORDScmStartService(PSERVICE Service, DWORD argc, const PCWSTR* argv){ DWORD dwError = ERROR_SUCCESS; SC_RPC_LOCK Lock = NULL;
DPRINT("ScmStartService() called\n"); DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
/* Acquire the service control critical section, to synchronize starts */ EnterCriticalSection(&ControlServiceCriticalSection);
/* * Acquire the user service start lock while the service is starting, if * needed (i.e. if we are not starting it during the initialization phase). * If we don't success, bail out. */ if (!ScmInitialize) { dwError = ScmAcquireServiceStartLock(TRUE, &Lock); if (dwError != ERROR_SUCCESS) goto done; }
/* Really start the service */ dwError = ScmLoadService(Service, argc, argv);
/* Release the service start lock, if needed, and the critical section */ if (Lock) ScmReleaseServiceStartLock(&Lock);
done: LeaveCriticalSection(&ControlServiceCriticalSection);
DPRINT("ScmStartService() done (Error %lu)\n", dwError);
return dwError;}
VOIDScmAutoStartServices(VOID){ DWORD dwError; PLIST_ENTRY GroupEntry; PLIST_ENTRY ServiceEntry; PSERVICE_GROUP CurrentGroup; PSERVICE CurrentService; WCHAR szSafeBootServicePath[MAX_PATH]; DWORD SafeBootEnabled; HKEY hKey; DWORD dwKeySize; ULONG i;
/* * This function MUST be called ONLY at initialization time. * Therefore, no need to acquire the user service start lock. */ ASSERT(ScmInitialize);
/* Retrieve the SafeBoot parameter */ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option", 0, KEY_READ, &hKey); if (dwError == ERROR_SUCCESS) { dwKeySize = sizeof(SafeBootEnabled); dwError = RegQueryValueExW(hKey, L"OptionValue", 0, NULL, (LPBYTE)&SafeBootEnabled, &dwKeySize); RegCloseKey(hKey); }
/* Default to Normal boot if the value doesn't exist */ if (dwError != ERROR_SUCCESS) SafeBootEnabled = 0;
/* Acquire the service control critical section, to synchronize starts */ EnterCriticalSection(&ControlServiceCriticalSection);
/* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */ ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
/* Build the safe boot path */ StringCchCopyW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
switch (SafeBootEnabled) { /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */ case 1: case 3: StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), L"\\Minimal\\"); break;
case 2: StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), L"\\Network\\"); break; }
if (SafeBootEnabled != 0) { /* If key does not exist then do not assume safe mode */ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szSafeBootServicePath, 0, KEY_READ, &hKey); if (dwError == ERROR_SUCCESS) { RegCloseKey(hKey);
/* Finish Safe Boot path off */ StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), CurrentService->lpServiceName);
/* Check that the key is in the Safe Boot path */ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szSafeBootServicePath, 0, KEY_READ, &hKey); if (dwError != ERROR_SUCCESS) { /* Mark service as visited so it is not auto-started */ CurrentService->ServiceVisited = TRUE; } else { /* Must be auto-started in safe mode - mark as unvisited */ RegCloseKey(hKey); CurrentService->ServiceVisited = FALSE; } } else { DPRINT1("WARNING: Could not open the associated Safe Boot key\n"); CurrentService->ServiceVisited = FALSE; } }
ServiceEntry = ServiceEntry->Flink; }
/* Start all services which are members of an existing group */ GroupEntry = GroupListHead.Flink; while (GroupEntry != &GroupListHead) { CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
/* Start all services witch have a valid tag */ for (i = 0; i < CurrentGroup->TagCount; i++) { ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
if ((CurrentService->lpGroup == CurrentGroup) && (CurrentService->dwStartType == SERVICE_AUTO_START) && (CurrentService->ServiceVisited == FALSE) && (CurrentService->dwTag == CurrentGroup->TagArray[i])) { CurrentService->ServiceVisited = TRUE; ScmLoadService(CurrentService, 0, NULL); }
ServiceEntry = ServiceEntry->Flink; } }
/* Start all services which have an invalid tag or which do not have a tag */ ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
if ((CurrentService->lpGroup == CurrentGroup) && (CurrentService->dwStartType == SERVICE_AUTO_START) && (CurrentService->ServiceVisited == FALSE)) { CurrentService->ServiceVisited = TRUE; ScmLoadService(CurrentService, 0, NULL); }
ServiceEntry = ServiceEntry->Flink; }
GroupEntry = GroupEntry->Flink; }
/* Start all services which are members of any non-existing group */ ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
if ((CurrentService->lpGroup != NULL) && (CurrentService->dwStartType == SERVICE_AUTO_START) && (CurrentService->ServiceVisited == FALSE)) { CurrentService->ServiceVisited = TRUE; ScmLoadService(CurrentService, 0, NULL); }
ServiceEntry = ServiceEntry->Flink; }
/* Start all services which are not a member of any group */ ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
if ((CurrentService->lpGroup == NULL) && (CurrentService->dwStartType == SERVICE_AUTO_START) && (CurrentService->ServiceVisited == FALSE)) { CurrentService->ServiceVisited = TRUE; ScmLoadService(CurrentService, 0, NULL); }
ServiceEntry = ServiceEntry->Flink; }
/* Clear 'ServiceVisited' flag again */ ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); CurrentService->ServiceVisited = FALSE; ServiceEntry = ServiceEntry->Flink; }
/* Release the critical section */ LeaveCriticalSection(&ControlServiceCriticalSection);}
VOIDScmAutoShutdownServices(VOID){ PLIST_ENTRY ServiceEntry; PSERVICE CurrentService;
DPRINT("ScmAutoShutdownServices() called\n");
/* Lock the service database exclusively */ ScmLockDatabaseExclusive();
ServiceEntry = ServiceListHead.Flink; while (ServiceEntry != &ServiceListHead) { CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
if ((CurrentService->Status.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) && (CurrentService->Status.dwCurrentState == SERVICE_RUNNING || CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)) { /* Send the shutdown notification */ DPRINT("Shutdown service: %S\n", CurrentService->lpServiceName); ScmControlService(CurrentService->lpImage->hControlPipe, CurrentService->lpServiceName, SERVICE_CONTROL_SHUTDOWN, (SERVICE_STATUS_HANDLE)CurrentService); }
ServiceEntry = ServiceEntry->Flink; }
/* Unlock the service database */ ScmUnlockDatabase();
DPRINT("ScmAutoShutdownServices() done\n");}
BOOLScmLockDatabaseExclusive(VOID){ return RtlAcquireResourceExclusive(&DatabaseLock, TRUE);}
BOOLScmLockDatabaseShared(VOID){ return RtlAcquireResourceShared(&DatabaseLock, TRUE);}
VOIDScmUnlockDatabase(VOID){ RtlReleaseResource(&DatabaseLock);}
VOIDScmInitNamedPipeCriticalSection(VOID){ HKEY hKey; DWORD dwKeySize; DWORD dwError;
InitializeCriticalSection(&ControlServiceCriticalSection);
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control", 0, KEY_READ, &hKey); if (dwError == ERROR_SUCCESS) { dwKeySize = sizeof(PipeTimeout); RegQueryValueExW(hKey, L"ServicesPipeTimeout", 0, NULL, (LPBYTE)&PipeTimeout, &dwKeySize); RegCloseKey(hKey); }}
VOIDScmDeleteNamedPipeCriticalSection(VOID){ DeleteCriticalSection(&ControlServiceCriticalSection);}
/* EOF */