2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/config.c
5 * PURPOSE: Service configuration interface
6 * COPYRIGHT: Copyright 2005 Eric Kohl
10 /* INCLUDES *****************************************************************/
19 /* FUNCTIONS *****************************************************************/
23 ScmOpenServiceKey(LPWSTR lpServiceName
,
27 HKEY hServicesKey
= NULL
;
32 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
33 L
"System\\CurrentControlSet\\Services",
37 if (dwError
!= ERROR_SUCCESS
)
40 dwError
= RegOpenKeyExW(hServicesKey
,
46 RegCloseKey(hServicesKey
);
53 ScmCreateServiceKey(LPCWSTR lpServiceName
,
57 HKEY hServicesKey
= NULL
;
63 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
64 L
"System\\CurrentControlSet\\Services",
66 KEY_READ
| KEY_CREATE_SUB_KEY
,
68 if (dwError
!= ERROR_SUCCESS
)
71 dwError
= RegCreateKeyExW(hServicesKey
,
75 REG_OPTION_NON_VOLATILE
,
81 if ((dwError
== ERROR_SUCCESS
) &&
82 (dwDisposition
== REG_OPENED_EXISTING_KEY
))
86 dwError
= ERROR_SERVICE_EXISTS
;
90 RegCloseKey(hServicesKey
);
98 ScmWriteDependencies(HKEY hServiceKey
,
99 LPCWSTR lpDependencies
,
100 DWORD dwDependenciesLength
)
102 DWORD dwError
= ERROR_SUCCESS
;
103 SIZE_T cchGroupLength
= 0;
104 SIZE_T cchServiceLength
= 0;
107 LPWSTR lpServiceDeps
;
111 if (*lpDependencies
== 0)
113 RegDeleteValueW(hServiceKey
,
115 RegDeleteValueW(hServiceKey
,
120 lpGroupDeps
= HeapAlloc(GetProcessHeap(),
122 (dwDependenciesLength
+ 2) * sizeof(WCHAR
));
123 if (lpGroupDeps
== NULL
)
124 return ERROR_NOT_ENOUGH_MEMORY
;
126 lpSrc
= lpDependencies
;
130 cchLength
= wcslen(lpSrc
) + 1;
131 if (*lpSrc
== SC_GROUP_IDENTIFIERW
)
135 cchGroupLength
+= cchLength
;
136 wcscpy(lpDst
, lpSrc
);
137 lpDst
= lpDst
+ cchLength
;
140 lpSrc
= lpSrc
+ cchLength
;
146 lpSrc
= lpDependencies
;
147 lpServiceDeps
= lpDst
;
150 cchLength
= wcslen(lpSrc
) + 1;
151 if (*lpSrc
!= SC_GROUP_IDENTIFIERW
)
153 cchServiceLength
+= cchLength
;
154 wcscpy(lpDst
, lpSrc
);
155 lpDst
= lpDst
+ cchLength
;
158 lpSrc
= lpSrc
+ cchLength
;
163 if (cchGroupLength
> 1)
165 dwError
= RegSetValueExW(hServiceKey
,
170 (DWORD
)(cchGroupLength
* sizeof(WCHAR
)));
174 RegDeleteValueW(hServiceKey
,
178 if (dwError
== ERROR_SUCCESS
)
180 if (cchServiceLength
> 1)
182 dwError
= RegSetValueExW(hServiceKey
,
186 (LPBYTE
)lpServiceDeps
,
187 (DWORD
)(cchServiceLength
* sizeof(WCHAR
)));
191 RegDeleteValueW(hServiceKey
,
196 HeapFree(GetProcessHeap(), 0, lpGroupDeps
);
204 ScmMarkServiceForDelete(PSERVICE pService
)
206 HKEY hServiceKey
= NULL
;
210 DPRINT("ScmMarkServiceForDelete() called\n");
212 dwError
= ScmOpenServiceKey(pService
->lpServiceName
,
215 if (dwError
!= ERROR_SUCCESS
)
218 dwError
= RegSetValueExW(hServiceKey
,
225 RegCloseKey(hServiceKey
);
232 ScmIsDeleteFlagSet(HKEY hServiceKey
)
237 DWORD dwSize
= sizeof(DWORD
);
239 dwError
= RegQueryValueExW(hServiceKey
,
246 return (dwError
== ERROR_SUCCESS
);
251 ScmReadString(HKEY hServiceKey
,
259 LPWSTR expanded
= NULL
;
263 dwError
= RegQueryValueExW(hServiceKey
,
269 if (dwError
!= ERROR_SUCCESS
)
272 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwSize
);
274 return ERROR_NOT_ENOUGH_MEMORY
;
276 dwError
= RegQueryValueExW(hServiceKey
,
282 if (dwError
!= ERROR_SUCCESS
)
284 HeapFree(GetProcessHeap(), 0, ptr
);
288 if (dwType
== REG_EXPAND_SZ
)
290 /* Expand the value... */
291 dwSize
= ExpandEnvironmentStringsW(ptr
, NULL
, 0);
294 expanded
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwSize
* sizeof(WCHAR
));
297 if (dwSize
== ExpandEnvironmentStringsW(ptr
, expanded
, dwSize
))
300 dwError
= ERROR_SUCCESS
;
304 dwError
= GetLastError();
305 HeapFree(GetProcessHeap(), 0, expanded
);
310 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
315 dwError
= GetLastError();
318 HeapFree(GetProcessHeap(), 0, ptr
);
330 ScmReadDependencies(HKEY hServiceKey
,
331 LPWSTR
*lpDependencies
,
332 DWORD
*lpdwDependenciesLength
)
334 LPWSTR lpGroups
= NULL
;
335 LPWSTR lpServices
= NULL
;
336 SIZE_T cchGroupsLength
= 0;
337 SIZE_T cchServicesLength
= 0;
341 SIZE_T cchTotalLength
;
343 *lpDependencies
= NULL
;
344 *lpdwDependenciesLength
= 0;
346 /* Read the dependency values */
347 ScmReadString(hServiceKey
,
351 ScmReadString(hServiceKey
,
355 /* Leave, if there are no dependencies */
356 if (lpGroups
== NULL
&& lpServices
== NULL
)
357 return ERROR_SUCCESS
;
359 /* Determine the total buffer size for the dependencies */
366 DPRINT(" %S\n", lpSrc
);
368 cchLength
= wcslen(lpSrc
) + 1;
369 cchGroupsLength
+= cchLength
+ 1;
371 lpSrc
= lpSrc
+ cchLength
;
377 DPRINT("Services:\n");
381 DPRINT(" %S\n", lpSrc
);
383 cchLength
= wcslen(lpSrc
) + 1;
384 cchServicesLength
+= cchLength
;
386 lpSrc
= lpSrc
+ cchLength
;
390 cchTotalLength
= cchGroupsLength
+ cchServicesLength
+ 1;
391 DPRINT("cchTotalLength: %lu\n", cchTotalLength
);
393 /* Allocate the common buffer for the dependencies */
394 *lpDependencies
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cchTotalLength
* sizeof(WCHAR
));
395 if (*lpDependencies
== NULL
)
398 HeapFree(GetProcessHeap(), 0, lpGroups
);
401 HeapFree(GetProcessHeap(), 0, lpServices
);
403 return ERROR_NOT_ENOUGH_MEMORY
;
406 /* Return the allocated buffer length in characters */
407 *lpdwDependenciesLength
= (DWORD
)cchTotalLength
;
409 /* Copy the service dependencies into the common buffer */
410 lpDest
= *lpDependencies
;
415 cchServicesLength
* sizeof(WCHAR
));
417 lpDest
= lpDest
+ cchServicesLength
;
420 /* Copy the group dependencies into the common buffer */
426 cchLength
= wcslen(lpSrc
) + 1;
428 *lpDest
= SC_GROUP_IDENTIFIERW
;
431 wcscpy(lpDest
, lpSrc
);
433 lpDest
= lpDest
+ cchLength
;
434 lpSrc
= lpSrc
+ cchLength
;
438 /* Free the temporary buffers */
440 HeapFree(GetProcessHeap(), 0, lpGroups
);
443 HeapFree(GetProcessHeap(), 0, lpServices
);
445 return ERROR_SUCCESS
;
450 ScmSetServicePassword(
451 IN PCWSTR pszServiceName
,
452 IN PCWSTR pszPassword
)
454 OBJECT_ATTRIBUTES ObjectAttributes
;
455 LSA_HANDLE PolicyHandle
= NULL
;
456 UNICODE_STRING ServiceName
= {0, 0, NULL
};
457 UNICODE_STRING Password
;
459 DWORD dwError
= ERROR_SUCCESS
;
461 RtlZeroMemory(&ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
));
463 Status
= LsaOpenPolicy(NULL
,
465 POLICY_CREATE_SECRET
,
467 if (!NT_SUCCESS(Status
))
468 return RtlNtStatusToDosError(Status
);
470 ServiceName
.Length
= (wcslen(pszServiceName
) + 4) * sizeof(WCHAR
);
471 ServiceName
.MaximumLength
= ServiceName
.Length
+ sizeof(WCHAR
);
472 ServiceName
.Buffer
= HeapAlloc(GetProcessHeap(),
474 ServiceName
.MaximumLength
);
475 if (ServiceName
.Buffer
== NULL
)
476 return ERROR_NOT_ENOUGH_MEMORY
;
478 wcscpy(ServiceName
.Buffer
, L
"_SC_");
479 wcscat(ServiceName
.Buffer
, pszServiceName
);
481 RtlInitUnicodeString(&Password
, pszPassword
);
483 Status
= LsaStorePrivateData(PolicyHandle
,
485 pszPassword
? &Password
: NULL
);
486 if (!NT_SUCCESS(Status
))
488 dwError
= RtlNtStatusToDosError(Status
);
493 if (ServiceName
.Buffer
!= NULL
)
494 HeapFree(GetProcessHeap(), 0, ServiceName
.Buffer
);
496 if (PolicyHandle
!= NULL
)
497 LsaClose(PolicyHandle
);
504 ScmWriteSecurityDescriptor(
505 _In_ HKEY hServiceKey
,
506 _In_ PSECURITY_DESCRIPTOR pSecurityDescriptor
)
508 HKEY hSecurityKey
= NULL
;
512 DPRINT("ScmWriteSecurityDescriptor(%p %p)\n", hServiceKey
, pSecurityDescriptor
);
514 dwError
= RegCreateKeyExW(hServiceKey
,
518 REG_OPTION_NON_VOLATILE
,
523 if (dwError
!= ERROR_SUCCESS
)
526 dwError
= RegSetValueExW(hSecurityKey
,
530 (LPBYTE
)pSecurityDescriptor
,
531 RtlLengthSecurityDescriptor(pSecurityDescriptor
));
533 RegCloseKey(hSecurityKey
);
540 ScmReadSecurityDescriptor(
541 _In_ HKEY hServiceKey
,
542 _Out_ PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
)
544 PSECURITY_DESCRIPTOR pRelativeSD
= NULL
;
545 HKEY hSecurityKey
= NULL
;
546 DWORD dwBufferLength
= 0;
550 DPRINT("ScmReadSecurityDescriptor(%p %p)\n", hServiceKey
, ppSecurityDescriptor
);
552 *ppSecurityDescriptor
= NULL
;
554 dwError
= RegOpenKeyExW(hServiceKey
,
559 if (dwError
!= ERROR_SUCCESS
)
561 DPRINT("RegOpenKeyExW() failed (Error %lu)\n", dwError
);
563 /* Do not fail if the Security key does not exist */
564 if (dwError
== ERROR_FILE_NOT_FOUND
)
565 dwError
= ERROR_SUCCESS
;
569 dwError
= RegQueryValueExW(hSecurityKey
,
575 if (dwError
!= ERROR_SUCCESS
)
577 DPRINT("RegQueryValueExW() failed (Error %lu)\n", dwError
);
579 /* Do not fail if the Security value does not exist */
580 if (dwError
== ERROR_FILE_NOT_FOUND
)
581 dwError
= ERROR_SUCCESS
;
585 DPRINT("dwBufferLength: %lu\n", dwBufferLength
);
586 pRelativeSD
= RtlAllocateHeap(RtlGetProcessHeap(),
589 if (pRelativeSD
== NULL
)
591 return ERROR_OUTOFMEMORY
;
594 DPRINT("pRelativeSD: %lu\n", pRelativeSD
);
595 dwError
= RegQueryValueExW(hSecurityKey
,
601 if (dwError
!= ERROR_SUCCESS
)
606 *ppSecurityDescriptor
= pRelativeSD
;
609 if (dwError
!= ERROR_SUCCESS
&& pRelativeSD
!= NULL
)
610 RtlFreeHeap(RtlGetProcessHeap(), 0, pRelativeSD
);
612 if (hSecurityKey
!= NULL
)
613 RegCloseKey(hSecurityKey
);
622 _In_ PCWSTR pszSubKey
)
624 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
625 DWORD dwMaxLen
, dwSize
;
626 PWSTR pszName
= NULL
;
630 dwError
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_READ
, &hSubKey
);
631 if (dwError
!= ERROR_SUCCESS
)
634 /* Get maximum length of key and value names */
635 dwError
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
636 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
637 if (dwError
!= ERROR_SUCCESS
)
642 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
644 /* Allocate the name buffer */
645 pszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxLen
* sizeof(WCHAR
));
648 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
652 /* Recursively delete all the subkeys */
656 if (RegEnumKeyExW(hSubKey
, 0, pszName
, &dwSize
,
657 NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
662 dwError
= ScmDeleteServiceKey(hSubKey
, pszName
);
663 if (dwError
!= ERROR_SUCCESS
)
669 HeapFree(GetProcessHeap(), 0, pszName
);
671 RegCloseKey(hSubKey
);
673 /* Finally delete the key */
674 if (dwError
== ERROR_SUCCESS
)
675 dwError
= RegDeleteKeyW(hKey
, pszSubKey
);