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 *****************************************************************/
22 unsigned char *Buffer
;
28 const struct ustring
*in
,
29 const struct ustring
*key
,
35 IN PVOID ContextHandle
,
36 OUT LPBYTE SessionKey
);
38 /* FUNCTIONS *****************************************************************/
42 ScmOpenServiceKey(LPWSTR lpServiceName
,
46 HKEY hServicesKey
= NULL
;
51 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
52 L
"System\\CurrentControlSet\\Services",
56 if (dwError
!= ERROR_SUCCESS
)
59 dwError
= RegOpenKeyExW(hServicesKey
,
65 RegCloseKey(hServicesKey
);
72 ScmCreateServiceKey(LPCWSTR lpServiceName
,
76 HKEY hServicesKey
= NULL
;
82 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
83 L
"System\\CurrentControlSet\\Services",
85 KEY_READ
| KEY_CREATE_SUB_KEY
,
87 if (dwError
!= ERROR_SUCCESS
)
90 dwError
= RegCreateKeyExW(hServicesKey
,
94 REG_OPTION_NON_VOLATILE
,
100 if ((dwError
== ERROR_SUCCESS
) &&
101 (dwDisposition
== REG_OPENED_EXISTING_KEY
))
105 dwError
= ERROR_SERVICE_EXISTS
;
109 RegCloseKey(hServicesKey
);
117 ScmWriteDependencies(HKEY hServiceKey
,
118 LPCWSTR lpDependencies
,
119 DWORD dwDependenciesLength
)
121 DWORD dwError
= ERROR_SUCCESS
;
122 SIZE_T cchGroupLength
= 0;
123 SIZE_T cchServiceLength
= 0;
126 LPWSTR lpServiceDeps
;
130 if (*lpDependencies
== 0)
132 RegDeleteValueW(hServiceKey
,
134 RegDeleteValueW(hServiceKey
,
139 lpGroupDeps
= HeapAlloc(GetProcessHeap(),
141 (dwDependenciesLength
+ 2) * sizeof(WCHAR
));
142 if (lpGroupDeps
== NULL
)
143 return ERROR_NOT_ENOUGH_MEMORY
;
145 lpSrc
= lpDependencies
;
149 cchLength
= wcslen(lpSrc
) + 1;
150 if (*lpSrc
== SC_GROUP_IDENTIFIERW
)
154 cchGroupLength
+= cchLength
;
155 wcscpy(lpDst
, lpSrc
);
156 lpDst
= lpDst
+ cchLength
;
159 lpSrc
= lpSrc
+ cchLength
;
165 lpSrc
= lpDependencies
;
166 lpServiceDeps
= lpDst
;
169 cchLength
= wcslen(lpSrc
) + 1;
170 if (*lpSrc
!= SC_GROUP_IDENTIFIERW
)
172 cchServiceLength
+= cchLength
;
173 wcscpy(lpDst
, lpSrc
);
174 lpDst
= lpDst
+ cchLength
;
177 lpSrc
= lpSrc
+ cchLength
;
182 if (cchGroupLength
> 1)
184 dwError
= RegSetValueExW(hServiceKey
,
189 (DWORD
)(cchGroupLength
* sizeof(WCHAR
)));
193 RegDeleteValueW(hServiceKey
,
197 if (dwError
== ERROR_SUCCESS
)
199 if (cchServiceLength
> 1)
201 dwError
= RegSetValueExW(hServiceKey
,
205 (LPBYTE
)lpServiceDeps
,
206 (DWORD
)(cchServiceLength
* sizeof(WCHAR
)));
210 RegDeleteValueW(hServiceKey
,
215 HeapFree(GetProcessHeap(), 0, lpGroupDeps
);
223 ScmMarkServiceForDelete(PSERVICE pService
)
225 HKEY hServiceKey
= NULL
;
229 DPRINT("ScmMarkServiceForDelete() called\n");
231 dwError
= ScmOpenServiceKey(pService
->lpServiceName
,
234 if (dwError
!= ERROR_SUCCESS
)
237 dwError
= RegSetValueExW(hServiceKey
,
244 RegCloseKey(hServiceKey
);
251 ScmIsDeleteFlagSet(HKEY hServiceKey
)
256 DWORD dwSize
= sizeof(DWORD
);
258 dwError
= RegQueryValueExW(hServiceKey
,
265 return (dwError
== ERROR_SUCCESS
);
270 ScmReadString(HKEY hServiceKey
,
278 LPWSTR expanded
= NULL
;
282 dwError
= RegQueryValueExW(hServiceKey
,
288 if (dwError
!= ERROR_SUCCESS
)
291 ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwSize
);
293 return ERROR_NOT_ENOUGH_MEMORY
;
295 dwError
= RegQueryValueExW(hServiceKey
,
301 if (dwError
!= ERROR_SUCCESS
)
303 HeapFree(GetProcessHeap(), 0, ptr
);
307 if (dwType
== REG_EXPAND_SZ
)
309 /* Expand the value... */
310 dwSize
= ExpandEnvironmentStringsW(ptr
, NULL
, 0);
313 expanded
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwSize
* sizeof(WCHAR
));
316 if (dwSize
== ExpandEnvironmentStringsW(ptr
, expanded
, dwSize
))
319 dwError
= ERROR_SUCCESS
;
323 dwError
= GetLastError();
324 HeapFree(GetProcessHeap(), 0, expanded
);
329 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
334 dwError
= GetLastError();
337 HeapFree(GetProcessHeap(), 0, ptr
);
349 ScmReadDependencies(HKEY hServiceKey
,
350 LPWSTR
*lpDependencies
,
351 DWORD
*lpdwDependenciesLength
)
353 LPWSTR lpGroups
= NULL
;
354 LPWSTR lpServices
= NULL
;
355 SIZE_T cchGroupsLength
= 0;
356 SIZE_T cchServicesLength
= 0;
360 SIZE_T cchTotalLength
;
362 *lpDependencies
= NULL
;
363 *lpdwDependenciesLength
= 0;
365 /* Read the dependency values */
366 ScmReadString(hServiceKey
,
370 ScmReadString(hServiceKey
,
374 /* Leave, if there are no dependencies */
375 if (lpGroups
== NULL
&& lpServices
== NULL
)
376 return ERROR_SUCCESS
;
378 /* Determine the total buffer size for the dependencies */
385 DPRINT(" %S\n", lpSrc
);
387 cchLength
= wcslen(lpSrc
) + 1;
388 cchGroupsLength
+= cchLength
+ 1;
390 lpSrc
= lpSrc
+ cchLength
;
396 DPRINT("Services:\n");
400 DPRINT(" %S\n", lpSrc
);
402 cchLength
= wcslen(lpSrc
) + 1;
403 cchServicesLength
+= cchLength
;
405 lpSrc
= lpSrc
+ cchLength
;
409 cchTotalLength
= cchGroupsLength
+ cchServicesLength
+ 1;
410 DPRINT("cchTotalLength: %lu\n", cchTotalLength
);
412 /* Allocate the common buffer for the dependencies */
413 *lpDependencies
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, cchTotalLength
* sizeof(WCHAR
));
414 if (*lpDependencies
== NULL
)
417 HeapFree(GetProcessHeap(), 0, lpGroups
);
420 HeapFree(GetProcessHeap(), 0, lpServices
);
422 return ERROR_NOT_ENOUGH_MEMORY
;
425 /* Return the allocated buffer length in characters */
426 *lpdwDependenciesLength
= (DWORD
)cchTotalLength
;
428 /* Copy the service dependencies into the common buffer */
429 lpDest
= *lpDependencies
;
434 cchServicesLength
* sizeof(WCHAR
));
436 lpDest
= lpDest
+ cchServicesLength
;
439 /* Copy the group dependencies into the common buffer */
445 cchLength
= wcslen(lpSrc
) + 1;
447 *lpDest
= SC_GROUP_IDENTIFIERW
;
450 wcscpy(lpDest
, lpSrc
);
452 lpDest
= lpDest
+ cchLength
;
453 lpSrc
= lpSrc
+ cchLength
;
457 /* Free the temporary buffers */
459 HeapFree(GetProcessHeap(), 0, lpGroups
);
462 HeapFree(GetProcessHeap(), 0, lpServices
);
464 return ERROR_SUCCESS
;
469 ScmSetServicePassword(
470 IN PCWSTR pszServiceName
,
471 IN PCWSTR pszPassword
)
473 OBJECT_ATTRIBUTES ObjectAttributes
;
474 LSA_HANDLE PolicyHandle
= NULL
;
475 UNICODE_STRING ServiceName
= {0, 0, NULL
};
476 UNICODE_STRING Password
;
478 DWORD dwError
= ERROR_SUCCESS
;
479 SIZE_T ServiceNameLength
;
481 RtlZeroMemory(&ObjectAttributes
, sizeof(OBJECT_ATTRIBUTES
));
483 ServiceNameLength
= wcslen(pszServiceName
);
484 if (ServiceNameLength
> (UNICODE_STRING_MAX_CHARS
- 4))
486 return ERROR_INVALID_PARAMETER
;
489 Status
= LsaOpenPolicy(NULL
,
491 POLICY_CREATE_SECRET
,
493 if (!NT_SUCCESS(Status
))
494 return RtlNtStatusToDosError(Status
);
496 ServiceName
.Length
= ((USHORT
)ServiceNameLength
+ 4) * sizeof(WCHAR
);
497 ServiceName
.MaximumLength
= ServiceName
.Length
+ sizeof(WCHAR
);
498 ServiceName
.Buffer
= HeapAlloc(GetProcessHeap(),
500 ServiceName
.MaximumLength
);
501 if (ServiceName
.Buffer
== NULL
)
502 return ERROR_NOT_ENOUGH_MEMORY
;
504 wcscpy(ServiceName
.Buffer
, L
"_SC_");
505 wcscat(ServiceName
.Buffer
, pszServiceName
);
507 RtlInitUnicodeString(&Password
, pszPassword
);
509 Status
= LsaStorePrivateData(PolicyHandle
,
511 pszPassword
? &Password
: NULL
);
512 if (!NT_SUCCESS(Status
))
514 dwError
= RtlNtStatusToDosError(Status
);
519 if (ServiceName
.Buffer
!= NULL
)
520 HeapFree(GetProcessHeap(), 0, ServiceName
.Buffer
);
522 if (PolicyHandle
!= NULL
)
523 LsaClose(PolicyHandle
);
530 ScmWriteSecurityDescriptor(
531 _In_ HKEY hServiceKey
,
532 _In_ PSECURITY_DESCRIPTOR pSecurityDescriptor
)
534 HKEY hSecurityKey
= NULL
;
538 DPRINT("ScmWriteSecurityDescriptor(%p %p)\n", hServiceKey
, pSecurityDescriptor
);
540 dwError
= RegCreateKeyExW(hServiceKey
,
544 REG_OPTION_NON_VOLATILE
,
549 if (dwError
!= ERROR_SUCCESS
)
552 dwError
= RegSetValueExW(hSecurityKey
,
556 (LPBYTE
)pSecurityDescriptor
,
557 RtlLengthSecurityDescriptor(pSecurityDescriptor
));
559 RegCloseKey(hSecurityKey
);
566 ScmReadSecurityDescriptor(
567 _In_ HKEY hServiceKey
,
568 _Out_ PSECURITY_DESCRIPTOR
*ppSecurityDescriptor
)
570 PSECURITY_DESCRIPTOR pRelativeSD
= NULL
;
571 HKEY hSecurityKey
= NULL
;
572 DWORD dwBufferLength
= 0;
576 DPRINT("ScmReadSecurityDescriptor(%p %p)\n", hServiceKey
, ppSecurityDescriptor
);
578 *ppSecurityDescriptor
= NULL
;
580 dwError
= RegOpenKeyExW(hServiceKey
,
585 if (dwError
!= ERROR_SUCCESS
)
587 DPRINT("RegOpenKeyExW() failed (Error %lu)\n", dwError
);
589 /* Do not fail if the Security key does not exist */
590 if (dwError
== ERROR_FILE_NOT_FOUND
)
591 dwError
= ERROR_SUCCESS
;
595 dwError
= RegQueryValueExW(hSecurityKey
,
601 if (dwError
!= ERROR_SUCCESS
)
603 DPRINT("RegQueryValueExW() failed (Error %lu)\n", dwError
);
605 /* Do not fail if the Security value does not exist */
606 if (dwError
== ERROR_FILE_NOT_FOUND
)
607 dwError
= ERROR_SUCCESS
;
611 DPRINT("dwBufferLength: %lu\n", dwBufferLength
);
612 pRelativeSD
= RtlAllocateHeap(RtlGetProcessHeap(),
615 if (pRelativeSD
== NULL
)
617 return ERROR_OUTOFMEMORY
;
620 DPRINT("pRelativeSD: %lu\n", pRelativeSD
);
621 dwError
= RegQueryValueExW(hSecurityKey
,
627 if (dwError
!= ERROR_SUCCESS
)
632 *ppSecurityDescriptor
= pRelativeSD
;
635 if (dwError
!= ERROR_SUCCESS
&& pRelativeSD
!= NULL
)
636 RtlFreeHeap(RtlGetProcessHeap(), 0, pRelativeSD
);
638 if (hSecurityKey
!= NULL
)
639 RegCloseKey(hSecurityKey
);
648 _In_ PCWSTR pszSubKey
)
650 DWORD dwMaxSubkeyLen
, dwMaxValueLen
;
651 DWORD dwMaxLen
, dwSize
;
652 PWSTR pszName
= NULL
;
656 dwError
= RegOpenKeyExW(hKey
, pszSubKey
, 0, KEY_READ
, &hSubKey
);
657 if (dwError
!= ERROR_SUCCESS
)
660 /* Get maximum length of key and value names */
661 dwError
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
662 &dwMaxSubkeyLen
, NULL
, NULL
, &dwMaxValueLen
, NULL
, NULL
, NULL
);
663 if (dwError
!= ERROR_SUCCESS
)
668 dwMaxLen
= max(dwMaxSubkeyLen
, dwMaxValueLen
);
670 /* Allocate the name buffer */
671 pszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxLen
* sizeof(WCHAR
));
674 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
678 /* Recursively delete all the subkeys */
682 if (RegEnumKeyExW(hSubKey
, 0, pszName
, &dwSize
,
683 NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
688 dwError
= ScmDeleteRegKey(hSubKey
, pszName
);
689 if (dwError
!= ERROR_SUCCESS
)
695 HeapFree(GetProcessHeap(), 0, pszName
);
697 RegCloseKey(hSubKey
);
699 /* Finally delete the key */
700 if (dwError
== ERROR_SUCCESS
)
701 dwError
= RegDeleteKeyW(hKey
, pszSubKey
);
709 _In_ PVOID ContextHandle
,
710 _In_ PBYTE pPassword
,
711 _In_ DWORD dwPasswordSize
,
712 _Out_ PWSTR
*pClearTextPassword
)
714 struct ustring inData
, keyData
, outData
;
719 /* Get the session key */
720 Status
= SystemFunction028(ContextHandle
,
722 if (!NT_SUCCESS(Status
))
724 DPRINT1("SystemFunction028 failed (Status 0x%08lx)\n", Status
);
725 return RtlNtStatusToDosError(Status
);
728 inData
.Length
= dwPasswordSize
;
729 inData
.MaximumLength
= inData
.Length
;
730 inData
.Buffer
= pPassword
;
732 keyData
.Length
= sizeof(SessionKey
);
733 keyData
.MaximumLength
= keyData
.Length
;
734 keyData
.Buffer
= SessionKey
;
737 outData
.MaximumLength
= 0;
738 outData
.Buffer
= NULL
;
740 /* Get the required buffer size */
741 Status
= SystemFunction005(&inData
,
744 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
746 DPRINT1("SystemFunction005 failed (Status 0x%08lx)\n", Status
);
747 return RtlNtStatusToDosError(Status
);
750 /* Allocate a buffer for the clear text password */
751 pBuffer
= HeapAlloc(GetProcessHeap(), 0, outData
.Length
);
753 return ERROR_OUTOFMEMORY
;
755 outData
.MaximumLength
= outData
.Length
;
756 outData
.Buffer
= (unsigned char *)pBuffer
;
758 /* Decrypt the password */
759 Status
= SystemFunction005(&inData
,
762 if (!NT_SUCCESS(Status
))
764 DPRINT1("SystemFunction005 failed (Status 0x%08lx)\n", Status
);
765 HeapFree(GetProcessHeap(), 0, pBuffer
);
766 return RtlNtStatusToDosError(Status
);
769 *pClearTextPassword
= pBuffer
;
771 return ERROR_SUCCESS
;