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