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