Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775/* * PROJECT: ReactOS Service Control Manager * LICENSE: GPL - See COPYING in the top level directory * FILE: base/system/services/config.c * PURPOSE: Service configuration interface * COPYRIGHT: Copyright 2005 Eric Kohl * */
/* INCLUDES *****************************************************************/
#include "services.h"#include <ntsecapi.h>
#define NDEBUG#include <debug.h>
struct ustring{ DWORD Length; DWORD MaximumLength; unsigned char *Buffer;};
NTSTATUSWINAPISystemFunction005( const struct ustring *in, const struct ustring *key, struct ustring *out);
NTSTATUSWINAPISystemFunction028( IN PVOID ContextHandle, OUT LPBYTE SessionKey);
/* FUNCTIONS *****************************************************************/
DWORDScmOpenServiceKey(LPWSTR lpServiceName, REGSAM samDesired, PHKEY phKey){ HKEY hServicesKey = NULL; DWORD dwError;
*phKey = NULL;
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services", 0, KEY_READ, &hServicesKey); if (dwError != ERROR_SUCCESS) return dwError;
dwError = RegOpenKeyExW(hServicesKey, lpServiceName, 0, samDesired, phKey);
RegCloseKey(hServicesKey);
return dwError;}
DWORDScmCreateServiceKey(LPCWSTR lpServiceName, REGSAM samDesired, PHKEY phKey){ HKEY hServicesKey = NULL; DWORD dwDisposition; DWORD dwError;
*phKey = NULL;
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Services", 0, KEY_READ | KEY_CREATE_SUB_KEY, &hServicesKey); if (dwError != ERROR_SUCCESS) return dwError;
dwError = RegCreateKeyExW(hServicesKey, lpServiceName, 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, phKey, &dwDisposition);#if 0 if ((dwError == ERROR_SUCCESS) && (dwDisposition == REG_OPENED_EXISTING_KEY)) { RegCloseKey(*phKey); *phKey = NULL; dwError = ERROR_SERVICE_EXISTS; }#endif
RegCloseKey(hServicesKey);
return dwError;}
DWORDScmWriteDependencies(HKEY hServiceKey, LPCWSTR lpDependencies, DWORD dwDependenciesLength){ DWORD dwError = ERROR_SUCCESS; SIZE_T cchGroupLength = 0; SIZE_T cchServiceLength = 0; SIZE_T cchLength; LPWSTR lpGroupDeps; LPWSTR lpServiceDeps; LPCWSTR lpSrc; LPWSTR lpDst;
if (*lpDependencies == 0) { RegDeleteValueW(hServiceKey, L"DependOnService"); RegDeleteValueW(hServiceKey, L"DependOnGroup"); } else { lpGroupDeps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (dwDependenciesLength + 2) * sizeof(WCHAR)); if (lpGroupDeps == NULL) return ERROR_NOT_ENOUGH_MEMORY;
lpSrc = lpDependencies; lpDst = lpGroupDeps; while (*lpSrc != 0) { cchLength = wcslen(lpSrc) + 1; if (*lpSrc == SC_GROUP_IDENTIFIERW) { lpSrc++; cchLength--; cchGroupLength += cchLength; wcscpy(lpDst, lpSrc); lpDst = lpDst + cchLength; }
lpSrc = lpSrc + cchLength; } *lpDst = 0; lpDst++; cchGroupLength++;
lpSrc = lpDependencies; lpServiceDeps = lpDst; while (*lpSrc != 0) { cchLength = wcslen(lpSrc) + 1; if (*lpSrc != SC_GROUP_IDENTIFIERW) { cchServiceLength += cchLength; wcscpy(lpDst, lpSrc); lpDst = lpDst + cchLength; }
lpSrc = lpSrc + cchLength; } *lpDst = 0; cchServiceLength++;
if (cchGroupLength > 1) { dwError = RegSetValueExW(hServiceKey, L"DependOnGroup", 0, REG_MULTI_SZ, (LPBYTE)lpGroupDeps, (DWORD)(cchGroupLength * sizeof(WCHAR))); } else { RegDeleteValueW(hServiceKey, L"DependOnGroup"); }
if (dwError == ERROR_SUCCESS) { if (cchServiceLength > 1) { dwError = RegSetValueExW(hServiceKey, L"DependOnService", 0, REG_MULTI_SZ, (LPBYTE)lpServiceDeps, (DWORD)(cchServiceLength * sizeof(WCHAR))); } else { RegDeleteValueW(hServiceKey, L"DependOnService"); } }
HeapFree(GetProcessHeap(), 0, lpGroupDeps); }
return dwError;}
DWORDScmMarkServiceForDelete(PSERVICE pService){ HKEY hServiceKey = NULL; DWORD dwValue = 1; DWORD dwError;
DPRINT("ScmMarkServiceForDelete() called\n");
dwError = ScmOpenServiceKey(pService->lpServiceName, KEY_WRITE, &hServiceKey); if (dwError != ERROR_SUCCESS) return dwError;
dwError = RegSetValueExW(hServiceKey, L"DeleteFlag", 0, REG_DWORD, (LPBYTE)&dwValue, sizeof(DWORD));
RegCloseKey(hServiceKey);
return dwError;}
BOOLScmIsDeleteFlagSet(HKEY hServiceKey){ DWORD dwError; DWORD dwType; DWORD dwFlag; DWORD dwSize = sizeof(DWORD);
dwError = RegQueryValueExW(hServiceKey, L"DeleteFlag", 0, &dwType, (LPBYTE)&dwFlag, &dwSize);
return (dwError == ERROR_SUCCESS);}
DWORDScmReadString(HKEY hServiceKey, LPCWSTR lpValueName, LPWSTR *lpValue){ DWORD dwError = 0; DWORD dwSize = 0; DWORD dwType = 0; LPWSTR ptr = NULL; LPWSTR expanded = NULL;
*lpValue = NULL;
dwError = RegQueryValueExW(hServiceKey, lpValueName, 0, &dwType, NULL, &dwSize); if (dwError != ERROR_SUCCESS) return dwError;
ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize); if (ptr == NULL) return ERROR_NOT_ENOUGH_MEMORY;
dwError = RegQueryValueExW(hServiceKey, lpValueName, 0, &dwType, (LPBYTE)ptr, &dwSize); if (dwError != ERROR_SUCCESS) { HeapFree(GetProcessHeap(), 0, ptr); return dwError; }
if (dwType == REG_EXPAND_SZ) { /* Expand the value... */ dwSize = ExpandEnvironmentStringsW(ptr, NULL, 0); if (dwSize > 0) { expanded = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize * sizeof(WCHAR)); if (expanded) { if (dwSize == ExpandEnvironmentStringsW(ptr, expanded, dwSize)) { *lpValue = expanded; dwError = ERROR_SUCCESS; } else { dwError = GetLastError(); HeapFree(GetProcessHeap(), 0, expanded); } } else { dwError = ERROR_NOT_ENOUGH_MEMORY; } } else { dwError = GetLastError(); }
HeapFree(GetProcessHeap(), 0, ptr); } else { *lpValue = ptr; }
return dwError;}
DWORDScmReadDependencies(HKEY hServiceKey, LPWSTR *lpDependencies, DWORD *lpdwDependenciesLength){ LPWSTR lpGroups = NULL; LPWSTR lpServices = NULL; SIZE_T cchGroupsLength = 0; SIZE_T cchServicesLength = 0; LPWSTR lpSrc; LPWSTR lpDest; SIZE_T cchLength; SIZE_T cchTotalLength;
*lpDependencies = NULL; *lpdwDependenciesLength = 0;
/* Read the dependency values */ ScmReadString(hServiceKey, L"DependOnGroup", &lpGroups);
ScmReadString(hServiceKey, L"DependOnService", &lpServices);
/* Leave, if there are no dependencies */ if (lpGroups == NULL && lpServices == NULL) return ERROR_SUCCESS;
/* Determine the total buffer size for the dependencies */ if (lpGroups) { DPRINT("Groups:\n"); lpSrc = lpGroups; while (*lpSrc != 0) { DPRINT(" %S\n", lpSrc);
cchLength = wcslen(lpSrc) + 1; cchGroupsLength += cchLength + 1;
lpSrc = lpSrc + cchLength; } }
if (lpServices) { DPRINT("Services:\n"); lpSrc = lpServices; while (*lpSrc != 0) { DPRINT(" %S\n", lpSrc);
cchLength = wcslen(lpSrc) + 1; cchServicesLength += cchLength;
lpSrc = lpSrc + cchLength; } }
cchTotalLength = cchGroupsLength + cchServicesLength + 1; DPRINT("cchTotalLength: %lu\n", cchTotalLength);
/* Allocate the common buffer for the dependencies */ *lpDependencies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cchTotalLength * sizeof(WCHAR)); if (*lpDependencies == NULL) { if (lpGroups) HeapFree(GetProcessHeap(), 0, lpGroups);
if (lpServices) HeapFree(GetProcessHeap(), 0, lpServices);
return ERROR_NOT_ENOUGH_MEMORY; }
/* Return the allocated buffer length in characters */ *lpdwDependenciesLength = (DWORD)cchTotalLength;
/* Copy the service dependencies into the common buffer */ lpDest = *lpDependencies; if (lpServices) { memcpy(lpDest, lpServices, cchServicesLength * sizeof(WCHAR));
lpDest = lpDest + cchServicesLength; }
/* Copy the group dependencies into the common buffer */ if (lpGroups) { lpSrc = lpGroups; while (*lpSrc != 0) { cchLength = wcslen(lpSrc) + 1;
*lpDest = SC_GROUP_IDENTIFIERW; lpDest++;
wcscpy(lpDest, lpSrc);
lpDest = lpDest + cchLength; lpSrc = lpSrc + cchLength; } }
/* Free the temporary buffers */ if (lpGroups) HeapFree(GetProcessHeap(), 0, lpGroups);
if (lpServices) HeapFree(GetProcessHeap(), 0, lpServices);
return ERROR_SUCCESS;}
DWORDScmSetServicePassword( IN PCWSTR pszServiceName, IN PCWSTR pszPassword){ OBJECT_ATTRIBUTES ObjectAttributes; LSA_HANDLE PolicyHandle = NULL; UNICODE_STRING ServiceName = {0, 0, NULL}; UNICODE_STRING Password; NTSTATUS Status; DWORD dwError = ERROR_SUCCESS; SIZE_T ServiceNameLength;
RtlZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
ServiceNameLength = wcslen(pszServiceName); if (ServiceNameLength > (UNICODE_STRING_MAX_CHARS - 4)) { return ERROR_INVALID_PARAMETER; }
Status = LsaOpenPolicy(NULL, &ObjectAttributes, POLICY_CREATE_SECRET, &PolicyHandle); if (!NT_SUCCESS(Status)) return RtlNtStatusToDosError(Status);
ServiceName.Length = ((USHORT)ServiceNameLength + 4) * sizeof(WCHAR); ServiceName.MaximumLength = ServiceName.Length + sizeof(WCHAR); ServiceName.Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ServiceName.MaximumLength); if (ServiceName.Buffer == NULL) return ERROR_NOT_ENOUGH_MEMORY;
wcscpy(ServiceName.Buffer, L"_SC_"); wcscat(ServiceName.Buffer, pszServiceName);
RtlInitUnicodeString(&Password, pszPassword);
Status = LsaStorePrivateData(PolicyHandle, &ServiceName, pszPassword ? &Password : NULL); if (!NT_SUCCESS(Status)) { dwError = RtlNtStatusToDosError(Status); goto done; }
done: if (ServiceName.Buffer != NULL) HeapFree(GetProcessHeap(), 0, ServiceName.Buffer);
if (PolicyHandle != NULL) LsaClose(PolicyHandle);
return dwError;}
DWORDScmWriteSecurityDescriptor( _In_ HKEY hServiceKey, _In_ PSECURITY_DESCRIPTOR pSecurityDescriptor){ HKEY hSecurityKey = NULL; DWORD dwDisposition; DWORD dwError;
DPRINT("ScmWriteSecurityDescriptor(%p %p)\n", hServiceKey, pSecurityDescriptor);
dwError = RegCreateKeyExW(hServiceKey, L"Security", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hSecurityKey, &dwDisposition); if (dwError != ERROR_SUCCESS) return dwError;
dwError = RegSetValueExW(hSecurityKey, L"Security", 0, REG_BINARY, (LPBYTE)pSecurityDescriptor, RtlLengthSecurityDescriptor(pSecurityDescriptor));
RegCloseKey(hSecurityKey);
return dwError;}
DWORDScmReadSecurityDescriptor( _In_ HKEY hServiceKey, _Out_ PSECURITY_DESCRIPTOR *ppSecurityDescriptor){ PSECURITY_DESCRIPTOR pRelativeSD = NULL; HKEY hSecurityKey = NULL; DWORD dwBufferLength = 0; DWORD dwType; DWORD dwError;
DPRINT("ScmReadSecurityDescriptor(%p %p)\n", hServiceKey, ppSecurityDescriptor);
*ppSecurityDescriptor = NULL;
dwError = RegOpenKeyExW(hServiceKey, L"Security", 0, KEY_QUERY_VALUE, &hSecurityKey); if (dwError != ERROR_SUCCESS) { DPRINT("RegOpenKeyExW() failed (Error %lu)\n", dwError);
/* Do not fail if the Security key does not exist */ if (dwError == ERROR_FILE_NOT_FOUND) dwError = ERROR_SUCCESS; goto done; }
dwError = RegQueryValueExW(hSecurityKey, L"Security", 0, &dwType, NULL, &dwBufferLength); if (dwError != ERROR_SUCCESS) { DPRINT("RegQueryValueExW() failed (Error %lu)\n", dwError);
/* Do not fail if the Security value does not exist */ if (dwError == ERROR_FILE_NOT_FOUND) dwError = ERROR_SUCCESS; goto done; }
DPRINT("dwBufferLength: %lu\n", dwBufferLength); pRelativeSD = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, dwBufferLength); if (pRelativeSD == NULL) { return ERROR_OUTOFMEMORY; }
DPRINT("pRelativeSD: %lu\n", pRelativeSD); dwError = RegQueryValueExW(hSecurityKey, L"Security", 0, &dwType, (LPBYTE)pRelativeSD, &dwBufferLength); if (dwError != ERROR_SUCCESS) { goto done; }
*ppSecurityDescriptor = pRelativeSD;
done: if (dwError != ERROR_SUCCESS && pRelativeSD != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, pRelativeSD);
if (hSecurityKey != NULL) RegCloseKey(hSecurityKey);
return dwError;}
DWORDScmDeleteRegKey( _In_ HKEY hKey, _In_ PCWSTR pszSubKey){ DWORD dwMaxSubkeyLen, dwMaxValueLen; DWORD dwMaxLen, dwSize; PWSTR pszName = NULL; HKEY hSubKey; DWORD dwError;
dwError = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_READ, &hSubKey); if (dwError != ERROR_SUCCESS) return dwError;
/* Get maximum length of key and value names */ dwError = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL, &dwMaxSubkeyLen, NULL, NULL, &dwMaxValueLen, NULL, NULL, NULL); if (dwError != ERROR_SUCCESS) goto done;
dwMaxSubkeyLen++; dwMaxValueLen++; dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
/* Allocate the name buffer */ pszName = HeapAlloc(GetProcessHeap(), 0, dwMaxLen * sizeof(WCHAR)); if (pszName == NULL) { dwError = ERROR_NOT_ENOUGH_MEMORY; goto done; }
/* Recursively delete all the subkeys */ while (TRUE) { dwSize = dwMaxLen; if (RegEnumKeyExW(hSubKey, 0, pszName, &dwSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) { break; }
dwError = ScmDeleteRegKey(hSubKey, pszName); if (dwError != ERROR_SUCCESS) goto done; }
done: if (pszName != NULL) HeapFree(GetProcessHeap(), 0, pszName);
RegCloseKey(hSubKey);
/* Finally delete the key */ if (dwError == ERROR_SUCCESS) dwError = RegDeleteKeyW(hKey, pszSubKey);
return dwError;}
DWORDScmDecryptPassword( _In_ PVOID ContextHandle, _In_ PBYTE pPassword, _In_ DWORD dwPasswordSize, _Out_ PWSTR *pClearTextPassword){ struct ustring inData, keyData, outData; BYTE SessionKey[16]; PWSTR pBuffer; NTSTATUS Status;
/* Get the session key */ Status = SystemFunction028(ContextHandle, SessionKey); if (!NT_SUCCESS(Status)) { DPRINT1("SystemFunction028 failed (Status 0x%08lx)\n", Status); return RtlNtStatusToDosError(Status); }
inData.Length = dwPasswordSize; inData.MaximumLength = inData.Length; inData.Buffer = pPassword;
keyData.Length = sizeof(SessionKey); keyData.MaximumLength = keyData.Length; keyData.Buffer = SessionKey;
outData.Length = 0; outData.MaximumLength = 0; outData.Buffer = NULL;
/* Get the required buffer size */ Status = SystemFunction005(&inData, &keyData, &outData); if (Status != STATUS_BUFFER_TOO_SMALL) { DPRINT1("SystemFunction005 failed (Status 0x%08lx)\n", Status); return RtlNtStatusToDosError(Status); }
/* Allocate a buffer for the clear text password */ pBuffer = HeapAlloc(GetProcessHeap(), 0, outData.Length); if (pBuffer == NULL) return ERROR_OUTOFMEMORY;
outData.MaximumLength = outData.Length; outData.Buffer = (unsigned char *)pBuffer;
/* Decrypt the password */ Status = SystemFunction005(&inData, &keyData, &outData); if (!NT_SUCCESS(Status)) { DPRINT1("SystemFunction005 failed (Status 0x%08lx)\n", Status); HeapFree(GetProcessHeap(), 0, pBuffer); return RtlNtStatusToDosError(Status); }
*pClearTextPassword = pBuffer;
return ERROR_SUCCESS;}
/* EOF */