c101a9f3ee9e457903ca82e9ea0e3eaf99039db9
[reactos.git] / reactos / base / system / services / config.c
1 /*
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
7 *
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "services.h"
13 #include <ntsecapi.h>
14
15 #define NDEBUG
16 #include <debug.h>
17
18
19 /* FUNCTIONS *****************************************************************/
20
21
22 DWORD
23 ScmOpenServiceKey(LPWSTR lpServiceName,
24 REGSAM samDesired,
25 PHKEY phKey)
26 {
27 HKEY hServicesKey = NULL;
28 DWORD dwError;
29
30 *phKey = NULL;
31
32 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
33 L"System\\CurrentControlSet\\Services",
34 0,
35 KEY_READ,
36 &hServicesKey);
37 if (dwError != ERROR_SUCCESS)
38 return dwError;
39
40 dwError = RegOpenKeyExW(hServicesKey,
41 lpServiceName,
42 0,
43 samDesired,
44 phKey);
45
46 RegCloseKey(hServicesKey);
47
48 return dwError;
49 }
50
51
52 DWORD
53 ScmCreateServiceKey(LPCWSTR lpServiceName,
54 REGSAM samDesired,
55 PHKEY phKey)
56 {
57 HKEY hServicesKey = NULL;
58 DWORD dwDisposition;
59 DWORD dwError;
60
61 *phKey = NULL;
62
63 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
64 L"System\\CurrentControlSet\\Services",
65 0,
66 KEY_READ | KEY_CREATE_SUB_KEY,
67 &hServicesKey);
68 if (dwError != ERROR_SUCCESS)
69 return dwError;
70
71 dwError = RegCreateKeyExW(hServicesKey,
72 lpServiceName,
73 0,
74 NULL,
75 REG_OPTION_NON_VOLATILE,
76 samDesired,
77 NULL,
78 phKey,
79 &dwDisposition);
80 #if 0
81 if ((dwError == ERROR_SUCCESS) &&
82 (dwDisposition == REG_OPENED_EXISTING_KEY))
83 {
84 RegCloseKey(*phKey);
85 *phKey = NULL;
86 dwError = ERROR_SERVICE_EXISTS;
87 }
88 #endif
89
90 RegCloseKey(hServicesKey);
91
92 return dwError;
93 }
94
95
96
97 DWORD
98 ScmWriteDependencies(HKEY hServiceKey,
99 LPCWSTR lpDependencies,
100 DWORD dwDependenciesLength)
101 {
102 DWORD dwError = ERROR_SUCCESS;
103 SIZE_T cchGroupLength = 0;
104 SIZE_T cchServiceLength = 0;
105 SIZE_T cchLength;
106 LPWSTR lpGroupDeps;
107 LPWSTR lpServiceDeps;
108 LPCWSTR lpSrc;
109 LPWSTR lpDst;
110
111 if (*lpDependencies == 0)
112 {
113 RegDeleteValueW(hServiceKey,
114 L"DependOnService");
115 RegDeleteValueW(hServiceKey,
116 L"DependOnGroup");
117 }
118 else
119 {
120 lpGroupDeps = HeapAlloc(GetProcessHeap(),
121 HEAP_ZERO_MEMORY,
122 (dwDependenciesLength + 2) * sizeof(WCHAR));
123 if (lpGroupDeps == NULL)
124 return ERROR_NOT_ENOUGH_MEMORY;
125
126 lpSrc = lpDependencies;
127 lpDst = lpGroupDeps;
128 while (*lpSrc != 0)
129 {
130 cchLength = wcslen(lpSrc) + 1;
131 if (*lpSrc == SC_GROUP_IDENTIFIERW)
132 {
133 lpSrc++;
134 cchLength--;
135 cchGroupLength += cchLength;
136 wcscpy(lpDst, lpSrc);
137 lpDst = lpDst + cchLength;
138 }
139
140 lpSrc = lpSrc + cchLength;
141 }
142 *lpDst = 0;
143 lpDst++;
144 cchGroupLength++;
145
146 lpSrc = lpDependencies;
147 lpServiceDeps = lpDst;
148 while (*lpSrc != 0)
149 {
150 cchLength = wcslen(lpSrc) + 1;
151 if (*lpSrc != SC_GROUP_IDENTIFIERW)
152 {
153 cchServiceLength += cchLength;
154 wcscpy(lpDst, lpSrc);
155 lpDst = lpDst + cchLength;
156 }
157
158 lpSrc = lpSrc + cchLength;
159 }
160 *lpDst = 0;
161 cchServiceLength++;
162
163 if (cchGroupLength > 1)
164 {
165 dwError = RegSetValueExW(hServiceKey,
166 L"DependOnGroup",
167 0,
168 REG_MULTI_SZ,
169 (LPBYTE)lpGroupDeps,
170 (DWORD)(cchGroupLength * sizeof(WCHAR)));
171 }
172 else
173 {
174 RegDeleteValueW(hServiceKey,
175 L"DependOnGroup");
176 }
177
178 if (dwError == ERROR_SUCCESS)
179 {
180 if (cchServiceLength > 1)
181 {
182 dwError = RegSetValueExW(hServiceKey,
183 L"DependOnService",
184 0,
185 REG_MULTI_SZ,
186 (LPBYTE)lpServiceDeps,
187 (DWORD)(cchServiceLength * sizeof(WCHAR)));
188 }
189 else
190 {
191 RegDeleteValueW(hServiceKey,
192 L"DependOnService");
193 }
194 }
195
196 HeapFree(GetProcessHeap(), 0, lpGroupDeps);
197 }
198
199 return dwError;
200 }
201
202
203 DWORD
204 ScmMarkServiceForDelete(PSERVICE pService)
205 {
206 HKEY hServiceKey = NULL;
207 DWORD dwValue = 1;
208 DWORD dwError;
209
210 DPRINT("ScmMarkServiceForDelete() called\n");
211
212 dwError = ScmOpenServiceKey(pService->lpServiceName,
213 KEY_WRITE,
214 &hServiceKey);
215 if (dwError != ERROR_SUCCESS)
216 return dwError;
217
218 dwError = RegSetValueExW(hServiceKey,
219 L"DeleteFlag",
220 0,
221 REG_DWORD,
222 (LPBYTE)&dwValue,
223 sizeof(DWORD));
224
225 RegCloseKey(hServiceKey);
226
227 return dwError;
228 }
229
230
231 BOOL
232 ScmIsDeleteFlagSet(HKEY hServiceKey)
233 {
234 DWORD dwError;
235 DWORD dwType;
236 DWORD dwFlag;
237 DWORD dwSize = sizeof(DWORD);
238
239 dwError = RegQueryValueExW(hServiceKey,
240 L"DeleteFlag",
241 0,
242 &dwType,
243 (LPBYTE)&dwFlag,
244 &dwSize);
245
246 return (dwError == ERROR_SUCCESS);
247 }
248
249
250 DWORD
251 ScmReadString(HKEY hServiceKey,
252 LPCWSTR lpValueName,
253 LPWSTR *lpValue)
254 {
255 DWORD dwError = 0;
256 DWORD dwSize = 0;
257 DWORD dwType = 0;
258 LPWSTR ptr = NULL;
259 LPWSTR expanded = NULL;
260
261 *lpValue = NULL;
262
263 dwError = RegQueryValueExW(hServiceKey,
264 lpValueName,
265 0,
266 &dwType,
267 NULL,
268 &dwSize);
269 if (dwError != ERROR_SUCCESS)
270 return dwError;
271
272 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
273 if (ptr == NULL)
274 return ERROR_NOT_ENOUGH_MEMORY;
275
276 dwError = RegQueryValueExW(hServiceKey,
277 lpValueName,
278 0,
279 &dwType,
280 (LPBYTE)ptr,
281 &dwSize);
282 if (dwError != ERROR_SUCCESS)
283 {
284 HeapFree(GetProcessHeap(), 0, ptr);
285 return dwError;
286 }
287
288 if (dwType == REG_EXPAND_SZ)
289 {
290 /* Expand the value... */
291 dwSize = ExpandEnvironmentStringsW(ptr, NULL, 0);
292 if (dwSize > 0)
293 {
294 expanded = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize * sizeof(WCHAR));
295 if (expanded)
296 {
297 if (dwSize == ExpandEnvironmentStringsW(ptr, expanded, dwSize))
298 {
299 *lpValue = expanded;
300 dwError = ERROR_SUCCESS;
301 }
302 else
303 {
304 dwError = GetLastError();
305 HeapFree(GetProcessHeap(), 0, expanded);
306 }
307 }
308 else
309 {
310 dwError = ERROR_NOT_ENOUGH_MEMORY;
311 }
312 }
313 else
314 {
315 dwError = GetLastError();
316 }
317
318 HeapFree(GetProcessHeap(), 0, ptr);
319 }
320 else
321 {
322 *lpValue = ptr;
323 }
324
325 return dwError;
326 }
327
328
329 DWORD
330 ScmReadDependencies(HKEY hServiceKey,
331 LPWSTR *lpDependencies,
332 DWORD *lpdwDependenciesLength)
333 {
334 LPWSTR lpGroups = NULL;
335 LPWSTR lpServices = NULL;
336 SIZE_T cchGroupsLength = 0;
337 SIZE_T cchServicesLength = 0;
338 LPWSTR lpSrc;
339 LPWSTR lpDest;
340 SIZE_T cchLength;
341 SIZE_T cchTotalLength;
342
343 *lpDependencies = NULL;
344 *lpdwDependenciesLength = 0;
345
346 /* Read the dependency values */
347 ScmReadString(hServiceKey,
348 L"DependOnGroup",
349 &lpGroups);
350
351 ScmReadString(hServiceKey,
352 L"DependOnService",
353 &lpServices);
354
355 /* Leave, if there are no dependencies */
356 if (lpGroups == NULL && lpServices == NULL)
357 return ERROR_SUCCESS;
358
359 /* Determine the total buffer size for the dependencies */
360 if (lpGroups)
361 {
362 DPRINT("Groups:\n");
363 lpSrc = lpGroups;
364 while (*lpSrc != 0)
365 {
366 DPRINT(" %S\n", lpSrc);
367
368 cchLength = wcslen(lpSrc) + 1;
369 cchGroupsLength += cchLength + 1;
370
371 lpSrc = lpSrc + cchLength;
372 }
373 }
374
375 if (lpServices)
376 {
377 DPRINT("Services:\n");
378 lpSrc = lpServices;
379 while (*lpSrc != 0)
380 {
381 DPRINT(" %S\n", lpSrc);
382
383 cchLength = wcslen(lpSrc) + 1;
384 cchServicesLength += cchLength;
385
386 lpSrc = lpSrc + cchLength;
387 }
388 }
389
390 cchTotalLength = cchGroupsLength + cchServicesLength + 1;
391 DPRINT("cchTotalLength: %lu\n", cchTotalLength);
392
393 /* Allocate the common buffer for the dependencies */
394 *lpDependencies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cchTotalLength * sizeof(WCHAR));
395 if (*lpDependencies == NULL)
396 {
397 if (lpGroups)
398 HeapFree(GetProcessHeap(), 0, lpGroups);
399
400 if (lpServices)
401 HeapFree(GetProcessHeap(), 0, lpServices);
402
403 return ERROR_NOT_ENOUGH_MEMORY;
404 }
405
406 /* Return the allocated buffer length in characters */
407 *lpdwDependenciesLength = (DWORD)cchTotalLength;
408
409 /* Copy the service dependencies into the common buffer */
410 lpDest = *lpDependencies;
411 if (lpServices)
412 {
413 memcpy(lpDest,
414 lpServices,
415 cchServicesLength * sizeof(WCHAR));
416
417 lpDest = lpDest + cchServicesLength;
418 }
419
420 /* Copy the group dependencies into the common buffer */
421 if (lpGroups)
422 {
423 lpSrc = lpGroups;
424 while (*lpSrc != 0)
425 {
426 cchLength = wcslen(lpSrc) + 1;
427
428 *lpDest = SC_GROUP_IDENTIFIERW;
429 lpDest++;
430
431 wcscpy(lpDest, lpSrc);
432
433 lpDest = lpDest + cchLength;
434 lpSrc = lpSrc + cchLength;
435 }
436 }
437
438 /* Free the temporary buffers */
439 if (lpGroups)
440 HeapFree(GetProcessHeap(), 0, lpGroups);
441
442 if (lpServices)
443 HeapFree(GetProcessHeap(), 0, lpServices);
444
445 return ERROR_SUCCESS;
446 }
447
448
449 DWORD
450 ScmSetServicePassword(
451 IN PCWSTR pszServiceName,
452 IN PCWSTR pszPassword)
453 {
454 OBJECT_ATTRIBUTES ObjectAttributes;
455 LSA_HANDLE PolicyHandle = NULL;
456 UNICODE_STRING ServiceName = {0, 0, NULL};
457 UNICODE_STRING Password;
458 NTSTATUS Status;
459 DWORD dwError = ERROR_SUCCESS;
460
461 RtlZeroMemory(&ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));
462
463 Status = LsaOpenPolicy(NULL,
464 &ObjectAttributes,
465 POLICY_CREATE_SECRET,
466 &PolicyHandle);
467 if (!NT_SUCCESS(Status))
468 return RtlNtStatusToDosError(Status);
469
470 ServiceName.Length = (wcslen(pszServiceName) + 4) * sizeof(WCHAR);
471 ServiceName.MaximumLength = ServiceName.Length + sizeof(WCHAR);
472 ServiceName.Buffer = HeapAlloc(GetProcessHeap(),
473 HEAP_ZERO_MEMORY,
474 ServiceName.MaximumLength);
475 if (ServiceName.Buffer == NULL)
476 return ERROR_NOT_ENOUGH_MEMORY;
477
478 wcscpy(ServiceName.Buffer, L"_SC_");
479 wcscat(ServiceName.Buffer, pszServiceName);
480
481 RtlInitUnicodeString(&Password, pszPassword);
482
483 Status = LsaStorePrivateData(PolicyHandle,
484 &ServiceName,
485 pszPassword ? &Password : NULL);
486 if (!NT_SUCCESS(Status))
487 {
488 dwError = RtlNtStatusToDosError(Status);
489 goto done;
490 }
491
492 done:
493 if (ServiceName.Buffer != NULL)
494 HeapFree(GetProcessHeap(), 0, ServiceName.Buffer);
495
496 if (PolicyHandle != NULL)
497 LsaClose(PolicyHandle);
498
499 return dwError;
500 }
501
502
503 DWORD
504 ScmWriteSecurityDescriptor(
505 _In_ HKEY hServiceKey,
506 _In_ PSECURITY_DESCRIPTOR pSecurityDescriptor)
507 {
508 HKEY hSecurityKey = NULL;
509 DWORD dwDisposition;
510 DWORD dwError;
511
512 DPRINT("ScmWriteSecurityDescriptor(%p %p)\n", hServiceKey, pSecurityDescriptor);
513
514 dwError = RegCreateKeyExW(hServiceKey,
515 L"Security",
516 0,
517 NULL,
518 REG_OPTION_NON_VOLATILE,
519 KEY_SET_VALUE,
520 NULL,
521 &hSecurityKey,
522 &dwDisposition);
523 if (dwError != ERROR_SUCCESS)
524 return dwError;
525
526 dwError = RegSetValueExW(hSecurityKey,
527 L"Security",
528 0,
529 REG_BINARY,
530 (LPBYTE)pSecurityDescriptor,
531 RtlLengthSecurityDescriptor(pSecurityDescriptor));
532
533 RegCloseKey(hSecurityKey);
534
535 return dwError;
536 }
537
538
539 DWORD
540 ScmReadSecurityDescriptor(
541 _In_ HKEY hServiceKey,
542 _Out_ PSECURITY_DESCRIPTOR *ppSecurityDescriptor)
543 {
544 PSECURITY_DESCRIPTOR pRelativeSD = NULL;
545 HKEY hSecurityKey = NULL;
546 DWORD dwBufferLength = 0;
547 DWORD dwType;
548 DWORD dwError;
549
550 DPRINT("ScmReadSecurityDescriptor(%p %p)\n", hServiceKey, ppSecurityDescriptor);
551
552 *ppSecurityDescriptor = NULL;
553
554 dwError = RegOpenKeyExW(hServiceKey,
555 L"Security",
556 0,
557 KEY_QUERY_VALUE,
558 &hSecurityKey);
559 if (dwError != ERROR_SUCCESS)
560 {
561 DPRINT("RegOpenKeyExW() failed (Error %lu)\n", dwError);
562
563 /* Do not fail if the Security key does not exist */
564 if (dwError == ERROR_FILE_NOT_FOUND)
565 dwError = ERROR_SUCCESS;
566 goto done;
567 }
568
569 dwError = RegQueryValueExW(hSecurityKey,
570 L"Security",
571 0,
572 &dwType,
573 NULL,
574 &dwBufferLength);
575 if (dwError != ERROR_SUCCESS)
576 {
577 DPRINT("RegQueryValueExW() failed (Error %lu)\n", dwError);
578
579 /* Do not fail if the Security value does not exist */
580 if (dwError == ERROR_FILE_NOT_FOUND)
581 dwError = ERROR_SUCCESS;
582 goto done;
583 }
584
585 DPRINT("dwBufferLength: %lu\n", dwBufferLength);
586 pRelativeSD = RtlAllocateHeap(RtlGetProcessHeap(),
587 HEAP_ZERO_MEMORY,
588 dwBufferLength);
589 if (pRelativeSD == NULL)
590 {
591 return ERROR_OUTOFMEMORY;
592 }
593
594 DPRINT("pRelativeSD: %lu\n", pRelativeSD);
595 dwError = RegQueryValueExW(hSecurityKey,
596 L"Security",
597 0,
598 &dwType,
599 (LPBYTE)pRelativeSD,
600 &dwBufferLength);
601 if (dwError != ERROR_SUCCESS)
602 {
603 goto done;
604 }
605
606 *ppSecurityDescriptor = pRelativeSD;
607
608 done:
609 if (dwError != ERROR_SUCCESS && pRelativeSD != NULL)
610 RtlFreeHeap(RtlGetProcessHeap(), 0, pRelativeSD);
611
612 if (hSecurityKey != NULL)
613 RegCloseKey(hSecurityKey);
614
615 return dwError;
616 }
617
618
619 DWORD
620 ScmDeleteRegKey(
621 _In_ HKEY hKey,
622 _In_ PCWSTR pszSubKey)
623 {
624 DWORD dwMaxSubkeyLen, dwMaxValueLen;
625 DWORD dwMaxLen, dwSize;
626 PWSTR pszName = NULL;
627 HKEY hSubKey;
628 DWORD dwError;
629
630 dwError = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_READ, &hSubKey);
631 if (dwError != ERROR_SUCCESS)
632 return dwError;
633
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)
638 goto done;
639
640 dwMaxSubkeyLen++;
641 dwMaxValueLen++;
642 dwMaxLen = max(dwMaxSubkeyLen, dwMaxValueLen);
643
644 /* Allocate the name buffer */
645 pszName = HeapAlloc(GetProcessHeap(), 0, dwMaxLen * sizeof(WCHAR));
646 if (pszName == NULL)
647 {
648 dwError = ERROR_NOT_ENOUGH_MEMORY;
649 goto done;
650 }
651
652 /* Recursively delete all the subkeys */
653 while (TRUE)
654 {
655 dwSize = dwMaxLen;
656 if (RegEnumKeyExW(hSubKey, 0, pszName, &dwSize,
657 NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
658 {
659 break;
660 }
661
662 dwError = ScmDeleteServiceKey(hSubKey, pszName);
663 if (dwError != ERROR_SUCCESS)
664 goto done;
665 }
666
667 done:
668 if (pszName != NULL)
669 HeapFree(GetProcessHeap(), 0, pszName);
670
671 RegCloseKey(hSubKey);
672
673 /* Finally delete the key */
674 if (dwError == ERROR_SUCCESS)
675 dwError = RegDeleteKeyW(hKey, pszSubKey);
676
677 return dwError;
678 }
679
680 /* EOF */