[SERVICES]
[reactos.git] / reactos / base / system / services / rpcserver.c
1 /*
2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/rpcserver.c
5 * PURPOSE: RPC server interface for the advapi32 calls
6 * COPYRIGHT: Copyright 2005-2006 Eric Kohl
7 * Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include "services.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 /* GLOBALS *****************************************************************/
19
20 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
21 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
22
23 typedef struct _SCMGR_HANDLE
24 {
25 DWORD Tag;
26 DWORD DesiredAccess;
27 } SCMGR_HANDLE;
28
29
30 typedef struct _MANAGER_HANDLE
31 {
32 SCMGR_HANDLE Handle;
33 WCHAR DatabaseName[1];
34 } MANAGER_HANDLE, *PMANAGER_HANDLE;
35
36
37 typedef struct _SERVICE_HANDLE
38 {
39 SCMGR_HANDLE Handle;
40 PSERVICE ServiceEntry;
41 } SERVICE_HANDLE, *PSERVICE_HANDLE;
42
43
44 #define SC_MANAGER_READ \
45 (STANDARD_RIGHTS_READ | \
46 SC_MANAGER_QUERY_LOCK_STATUS | \
47 SC_MANAGER_ENUMERATE_SERVICE)
48
49 #define SC_MANAGER_WRITE \
50 (STANDARD_RIGHTS_WRITE | \
51 SC_MANAGER_MODIFY_BOOT_CONFIG | \
52 SC_MANAGER_CREATE_SERVICE)
53
54 #define SC_MANAGER_EXECUTE \
55 (STANDARD_RIGHTS_EXECUTE | \
56 SC_MANAGER_LOCK | \
57 SC_MANAGER_ENUMERATE_SERVICE | \
58 SC_MANAGER_CONNECT | \
59 SC_MANAGER_CREATE_SERVICE)
60
61
62 #define SERVICE_READ \
63 (STANDARD_RIGHTS_READ | \
64 SERVICE_INTERROGATE | \
65 SERVICE_ENUMERATE_DEPENDENTS | \
66 SERVICE_QUERY_STATUS | \
67 SERVICE_QUERY_CONFIG)
68
69 #define SERVICE_WRITE \
70 (STANDARD_RIGHTS_WRITE | \
71 SERVICE_CHANGE_CONFIG)
72
73 #define SERVICE_EXECUTE \
74 (STANDARD_RIGHTS_EXECUTE | \
75 SERVICE_USER_DEFINED_CONTROL | \
76 SERVICE_PAUSE_CONTINUE | \
77 SERVICE_STOP | \
78 SERVICE_START)
79
80 #define TAG_ARRAY_SIZE 32
81
82 /* VARIABLES ***************************************************************/
83
84 static GENERIC_MAPPING
85 ScmManagerMapping = {SC_MANAGER_READ,
86 SC_MANAGER_WRITE,
87 SC_MANAGER_EXECUTE,
88 SC_MANAGER_ALL_ACCESS};
89
90 static GENERIC_MAPPING
91 ScmServiceMapping = {SERVICE_READ,
92 SERVICE_WRITE,
93 SERVICE_EXECUTE,
94 SERVICE_ALL_ACCESS};
95
96
97 /* FUNCTIONS ***************************************************************/
98
99 VOID
100 ScmStartRpcServer(VOID)
101 {
102 RPC_STATUS Status;
103
104 DPRINT("ScmStartRpcServer() called\n");
105
106 Status = RpcServerUseProtseqEpW(L"ncacn_np",
107 10,
108 L"\\pipe\\ntsvcs",
109 NULL);
110 if (Status != RPC_S_OK)
111 {
112 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
113 return;
114 }
115
116 Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
117 NULL,
118 NULL);
119 if (Status != RPC_S_OK)
120 {
121 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
122 return;
123 }
124
125 Status = RpcServerListen(1, 20, TRUE);
126 if (Status != RPC_S_OK)
127 {
128 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
129 return;
130 }
131
132 DPRINT("ScmStartRpcServer() done\n");
133 }
134
135
136 static DWORD
137 ScmCreateManagerHandle(LPWSTR lpDatabaseName,
138 SC_HANDLE *Handle)
139 {
140 PMANAGER_HANDLE Ptr;
141
142 if (lpDatabaseName == NULL)
143 lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
144
145 if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
146 {
147 DPRINT("Database %S, does not exist\n", lpDatabaseName);
148 return ERROR_DATABASE_DOES_NOT_EXIST;
149 }
150 else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
151 {
152 DPRINT("Invalid Database name %S.\n", lpDatabaseName);
153 return ERROR_INVALID_NAME;
154 }
155
156 Ptr = HeapAlloc(GetProcessHeap(),
157 HEAP_ZERO_MEMORY,
158 FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1]));
159 if (Ptr == NULL)
160 return ERROR_NOT_ENOUGH_MEMORY;
161
162 Ptr->Handle.Tag = MANAGER_TAG;
163
164 wcscpy(Ptr->DatabaseName, lpDatabaseName);
165
166 *Handle = (SC_HANDLE)Ptr;
167
168 return ERROR_SUCCESS;
169 }
170
171
172 static DWORD
173 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
174 SC_HANDLE *Handle)
175 {
176 PSERVICE_HANDLE Ptr;
177
178 Ptr = HeapAlloc(GetProcessHeap(),
179 HEAP_ZERO_MEMORY,
180 sizeof(SERVICE_HANDLE));
181 if (Ptr == NULL)
182 return ERROR_NOT_ENOUGH_MEMORY;
183
184 Ptr->Handle.Tag = SERVICE_TAG;
185
186 Ptr->ServiceEntry = lpServiceEntry;
187
188 *Handle = (SC_HANDLE)Ptr;
189
190 return ERROR_SUCCESS;
191 }
192
193
194 static PMANAGER_HANDLE
195 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle)
196 {
197 PMANAGER_HANDLE pManager = NULL;
198
199 _SEH2_TRY
200 {
201 if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG)
202 pManager = (PMANAGER_HANDLE)Handle;
203 }
204 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
205 {
206 DPRINT1("Exception: Invalid Service Manager handle!\n");
207 }
208 _SEH2_END;
209
210 return pManager;
211 }
212
213
214 static PSERVICE_HANDLE
215 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle)
216 {
217 PSERVICE_HANDLE pService = NULL;
218
219 _SEH2_TRY
220 {
221 if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG)
222 pService = (PSERVICE_HANDLE)Handle;
223 }
224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
225 {
226 DPRINT1("Exception: Invalid Service handle!\n");
227 }
228 _SEH2_END;
229
230 return pService;
231 }
232
233
234 static DWORD
235 ScmCheckAccess(SC_HANDLE Handle,
236 DWORD dwDesiredAccess)
237 {
238 PMANAGER_HANDLE hMgr;
239
240 hMgr = (PMANAGER_HANDLE)Handle;
241 if (hMgr->Handle.Tag == MANAGER_TAG)
242 {
243 RtlMapGenericMask(&dwDesiredAccess,
244 &ScmManagerMapping);
245
246 hMgr->Handle.DesiredAccess = dwDesiredAccess;
247
248 return ERROR_SUCCESS;
249 }
250 else if (hMgr->Handle.Tag == SERVICE_TAG)
251 {
252 RtlMapGenericMask(&dwDesiredAccess,
253 &ScmServiceMapping);
254
255 hMgr->Handle.DesiredAccess = dwDesiredAccess;
256
257 return ERROR_SUCCESS;
258 }
259
260 return ERROR_INVALID_HANDLE;
261 }
262
263
264 DWORD
265 ScmAssignNewTag(PSERVICE lpService)
266 {
267 HKEY hKey = NULL;
268 DWORD dwError;
269 DWORD dwGroupTagCount = 0;
270 PDWORD pdwGroupTags = NULL;
271 DWORD dwFreeTag = 0;
272 DWORD dwTagUsedBase = 1;
273 BOOLEAN TagUsed[TAG_ARRAY_SIZE];
274 DWORD dwTagOffset;
275 DWORD i;
276 DWORD cbDataSize;
277 PLIST_ENTRY ServiceEntry;
278 PSERVICE CurrentService;
279
280 ASSERT(lpService != NULL);
281 ASSERT(lpService->lpGroup != NULL);
282
283 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
284 L"System\\CurrentControlSet\\Control\\GroupOrderList",
285 0,
286 KEY_READ,
287 &hKey);
288
289 if (dwError != ERROR_SUCCESS)
290 goto findFreeTag;
291
292 /* query value length */
293 cbDataSize = 0;
294 dwError = RegQueryValueExW(hKey,
295 lpService->lpGroup->szGroupName,
296 NULL,
297 NULL,
298 NULL,
299 &cbDataSize);
300
301 if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA)
302 goto findFreeTag;
303
304 pdwGroupTags = HeapAlloc(GetProcessHeap(), 0, cbDataSize);
305 if (!pdwGroupTags)
306 {
307 dwError = ERROR_NOT_ENOUGH_MEMORY;
308 goto cleanup;
309 }
310
311 dwError = RegQueryValueExW(hKey,
312 lpService->lpGroup->szGroupName,
313 NULL,
314 NULL,
315 (LPBYTE)pdwGroupTags,
316 &cbDataSize);
317
318 if (dwError != ERROR_SUCCESS)
319 goto findFreeTag;
320
321 if (cbDataSize < sizeof(pdwGroupTags[0]))
322 goto findFreeTag;
323
324 dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1);
325
326 findFreeTag:
327 do
328 {
329 /* mark all tags as unused */
330 for (i = 0; i < TAG_ARRAY_SIZE; i++)
331 TagUsed[i] = FALSE;
332
333 /* mark tags in GroupOrderList as used */
334 for (i = 1; i <= dwGroupTagCount; i++)
335 {
336 dwTagOffset = pdwGroupTags[i] - dwTagUsedBase;
337 if (dwTagOffset >= 0 && dwTagOffset < TAG_ARRAY_SIZE)
338 TagUsed[dwTagOffset] = TRUE;
339 }
340
341 /* mark tags in service list as used */
342 ServiceEntry = lpService->ServiceListEntry.Flink;
343 while (ServiceEntry != &lpService->ServiceListEntry)
344 {
345 ASSERT(ServiceEntry != NULL);
346 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
347 if (CurrentService->lpGroup == lpService->lpGroup)
348 {
349 dwTagOffset = CurrentService->dwTag - dwTagUsedBase;
350 if (dwTagOffset >= 0 && dwTagOffset < TAG_ARRAY_SIZE)
351 TagUsed[dwTagOffset] = TRUE;
352 }
353
354 ServiceEntry = ServiceEntry->Flink;
355 }
356
357 /* find unused tag, if any */
358 for (i = 0; i < TAG_ARRAY_SIZE; i++)
359 {
360 if (!TagUsed[i])
361 {
362 dwFreeTag = dwTagUsedBase + i;
363 break;
364 }
365 }
366
367 dwTagUsedBase += TAG_ARRAY_SIZE;
368 }
369 while (!dwFreeTag);
370
371 cleanup:
372 if (pdwGroupTags)
373 HeapFree(GetProcessHeap(), 0, pdwGroupTags);
374
375 if (hKey)
376 RegCloseKey(hKey);
377
378 if (dwFreeTag)
379 {
380 lpService->dwTag = dwFreeTag;
381 DPRINT("Assigning new tag %lu to service %S in group %S\n",
382 lpService->dwTag, lpService->lpServiceName, lpService->lpGroup->szGroupName);
383 dwError = ERROR_SUCCESS;
384 }
385 else
386 {
387 DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
388 lpService->lpServiceName, dwError);
389 }
390
391 return dwError;
392 }
393
394
395 /* Create a path suitable for the bootloader out of the full path */
396 DWORD
397 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
398 {
399 DWORD ServiceNameLen, BufferSize, ExpandedLen;
400 WCHAR Dest;
401 WCHAR *Expanded;
402 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
403 OBJECT_ATTRIBUTES ObjectAttributes;
404 NTSTATUS Status;
405 HANDLE SymbolicLinkHandle;
406
407 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
408
409 ServiceNameLen = wcslen(CanonName);
410
411 /* First check, if it's already good */
412 if (ServiceNameLen > 12 &&
413 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
414 {
415 *RelativeName = HeapAlloc(GetProcessHeap(),
416 HEAP_ZERO_MEMORY,
417 (ServiceNameLen + 1) * sizeof(WCHAR));
418 if (*RelativeName == NULL)
419 {
420 DPRINT("Error allocating memory for boot driver name!\n");
421 return ERROR_NOT_ENOUGH_MEMORY;
422 }
423
424 /* Copy it */
425 wcscpy(*RelativeName, CanonName);
426
427 DPRINT("Bootdriver name %S\n", *RelativeName);
428 return ERROR_SUCCESS;
429 }
430
431 /* If it has %SystemRoot% prefix, substitute it to \System*/
432 if (ServiceNameLen > 13 &&
433 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
434 {
435 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
436 *RelativeName = HeapAlloc(GetProcessHeap(),
437 HEAP_ZERO_MEMORY,
438 ServiceNameLen * sizeof(WCHAR));
439
440 if (*RelativeName == NULL)
441 {
442 DPRINT("Error allocating memory for boot driver name!\n");
443 return ERROR_NOT_ENOUGH_MEMORY;
444 }
445
446 /* Copy it */
447 wcscpy(*RelativeName, L"\\SystemRoot\\");
448 wcscat(*RelativeName, CanonName + 13);
449
450 DPRINT("Bootdriver name %S\n", *RelativeName);
451 return ERROR_SUCCESS;
452 }
453
454 /* Get buffer size needed for expanding env strings */
455 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
456
457 if (BufferSize <= 1)
458 {
459 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
460 return ERROR_INVALID_ENVIRONMENT;
461 }
462
463 /* Allocate memory, since the size is known now */
464 Expanded = HeapAlloc(GetProcessHeap(),
465 HEAP_ZERO_MEMORY,
466 (BufferSize + 1) * sizeof(WCHAR));
467 if (!Expanded)
468 {
469 DPRINT("Error allocating memory for boot driver name!\n");
470 return ERROR_NOT_ENOUGH_MEMORY;
471 }
472
473 /* Expand it */
474 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
475 BufferSize)
476 {
477 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
478 HeapFree(GetProcessHeap(), 0, Expanded);
479 return ERROR_NOT_ENOUGH_MEMORY;
480 }
481
482 /* Convert to NY-style path */
483 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
484 {
485 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
486 return ERROR_INVALID_ENVIRONMENT;
487 }
488
489 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
490
491 /* No need to keep the dos-path anymore */
492 HeapFree(GetProcessHeap(), 0, Expanded);
493
494 /* Copy it to the allocated place */
495 Expanded = HeapAlloc(GetProcessHeap(),
496 HEAP_ZERO_MEMORY,
497 NtPathName.Length + sizeof(UNICODE_NULL));
498 if (!Expanded)
499 {
500 DPRINT("Error allocating memory for boot driver name!\n");
501 return ERROR_NOT_ENOUGH_MEMORY;
502 }
503
504 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
505 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
506 Expanded[ExpandedLen] = UNICODE_NULL;
507
508 if (ServiceNameLen > ExpandedLen &&
509 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
510 {
511 /* Only \SystemRoot\ is missing */
512 *RelativeName = HeapAlloc(GetProcessHeap(),
513 HEAP_ZERO_MEMORY,
514 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
515 if (*RelativeName == NULL)
516 {
517 DPRINT("Error allocating memory for boot driver name!\n");
518 HeapFree(GetProcessHeap(), 0, Expanded);
519 return ERROR_NOT_ENOUGH_MEMORY;
520 }
521
522 wcscpy(*RelativeName, L"\\SystemRoot\\");
523 wcscat(*RelativeName, CanonName + ExpandedLen);
524
525 RtlFreeUnicodeString(&NtPathName);
526 return ERROR_SUCCESS;
527 }
528
529 /* The most complex case starts here */
530 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
531 InitializeObjectAttributes(&ObjectAttributes,
532 &SystemRoot,
533 OBJ_CASE_INSENSITIVE,
534 NULL,
535 NULL);
536
537 /* Open this symlink */
538 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
539
540 if (NT_SUCCESS(Status))
541 {
542 LinkTarget.Length = 0;
543 LinkTarget.MaximumLength = 0;
544
545 DPRINT("Opened symbolic link object\n");
546
547 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
548 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
549 {
550 /* Check if required buffer size is sane */
551 if (BufferSize > 0xFFFD)
552 {
553 DPRINT("Too large buffer required\n");
554 *RelativeName = 0;
555
556 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
557 HeapFree(GetProcessHeap(), 0, Expanded);
558 return ERROR_NOT_ENOUGH_MEMORY;
559 }
560
561 /* Alloc the string */
562 LinkTarget.Length = (USHORT)BufferSize;
563 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(UNICODE_NULL);
564 LinkTarget.Buffer = HeapAlloc(GetProcessHeap(),
565 HEAP_ZERO_MEMORY,
566 LinkTarget.MaximumLength);
567 if (!LinkTarget.Buffer)
568 {
569 DPRINT("Unable to alloc buffer\n");
570 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
571 HeapFree(GetProcessHeap(), 0, Expanded);
572 return ERROR_NOT_ENOUGH_MEMORY;
573 }
574
575 /* Do a real query now */
576 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
577 if (NT_SUCCESS(Status))
578 {
579 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
580
581 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
582 if ((ServiceNameLen > ExpandedLen) &&
583 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
584 {
585 *RelativeName = HeapAlloc(GetProcessHeap(),
586 HEAP_ZERO_MEMORY,
587 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
588
589 if (*RelativeName == NULL)
590 {
591 DPRINT("Unable to alloc buffer\n");
592 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
593 HeapFree(GetProcessHeap(), 0, Expanded);
594 RtlFreeUnicodeString(&NtPathName);
595 return ERROR_NOT_ENOUGH_MEMORY;
596 }
597
598 /* Copy it over, substituting the first part
599 with SystemRoot */
600 wcscpy(*RelativeName, L"\\SystemRoot\\");
601 wcscat(*RelativeName, CanonName+ExpandedLen+1);
602
603 /* Cleanup */
604 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
605 HeapFree(GetProcessHeap(), 0, Expanded);
606 RtlFreeUnicodeString(&NtPathName);
607
608 /* Return success */
609 return ERROR_SUCCESS;
610 }
611 else
612 {
613 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
614 HeapFree(GetProcessHeap(), 0, Expanded);
615 RtlFreeUnicodeString(&NtPathName);
616 return ERROR_INVALID_PARAMETER;
617 }
618 }
619 else
620 {
621 DPRINT("Error, Status = %08X\n", Status);
622 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
623 HeapFree(GetProcessHeap(), 0, Expanded);
624 RtlFreeUnicodeString(&NtPathName);
625 return ERROR_INVALID_PARAMETER;
626 }
627 }
628 else
629 {
630 DPRINT("Error, Status = %08X\n", Status);
631 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
632 HeapFree(GetProcessHeap(), 0, Expanded);
633 RtlFreeUnicodeString(&NtPathName);
634 return ERROR_INVALID_PARAMETER;
635 }
636 }
637 else
638 {
639 DPRINT("Error, Status = %08X\n", Status);
640 HeapFree(GetProcessHeap(), 0, Expanded);
641 return ERROR_INVALID_PARAMETER;
642 }
643
644 /* Failure */
645 *RelativeName = NULL;
646 return ERROR_INVALID_PARAMETER;
647 }
648
649
650 DWORD
651 ScmCanonDriverImagePath(DWORD dwStartType,
652 const wchar_t *lpServiceName,
653 wchar_t **lpCanonName)
654 {
655 DWORD ServiceNameLen, Result;
656 UNICODE_STRING NtServiceName;
657 WCHAR *RelativeName;
658 const WCHAR *SourceName = lpServiceName;
659
660 /* Calculate the length of the service's name */
661 ServiceNameLen = wcslen(lpServiceName);
662
663 /* 12 is wcslen(L"\\SystemRoot\\") */
664 if (ServiceNameLen > 12 &&
665 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
666 {
667 /* SystemRoot prefix is already included */
668 *lpCanonName = HeapAlloc(GetProcessHeap(),
669 HEAP_ZERO_MEMORY,
670 (ServiceNameLen + 1) * sizeof(WCHAR));
671
672 if (*lpCanonName == NULL)
673 {
674 DPRINT("Error allocating memory for canonized service name!\n");
675 return ERROR_NOT_ENOUGH_MEMORY;
676 }
677
678 /* If it's a boot-time driver, it must be systemroot relative */
679 if (dwStartType == SERVICE_BOOT_START)
680 SourceName += 12;
681
682 /* Copy it */
683 wcscpy(*lpCanonName, SourceName);
684
685 DPRINT("Canonicalized name %S\n", *lpCanonName);
686 return NO_ERROR;
687 }
688
689 /* Check if it has %SystemRoot% (len=13) */
690 if (ServiceNameLen > 13 &&
691 !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13))
692 {
693 /* Substitute %SystemRoot% with \\SystemRoot\\ */
694 *lpCanonName = HeapAlloc(GetProcessHeap(),
695 HEAP_ZERO_MEMORY,
696 (ServiceNameLen + 1) * sizeof(WCHAR));
697
698 if (*lpCanonName == NULL)
699 {
700 DPRINT("Error allocating memory for canonized service name!\n");
701 return ERROR_NOT_ENOUGH_MEMORY;
702 }
703
704 /* If it's a boot-time driver, it must be systemroot relative */
705 if (dwStartType == SERVICE_BOOT_START)
706 wcscpy(*lpCanonName, L"\\SystemRoot\\");
707
708 wcscat(*lpCanonName, lpServiceName + 13);
709
710 DPRINT("Canonicalized name %S\n", *lpCanonName);
711 return NO_ERROR;
712 }
713
714 /* Check if it's a relative path name */
715 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
716 {
717 *lpCanonName = HeapAlloc(GetProcessHeap(),
718 HEAP_ZERO_MEMORY,
719 (ServiceNameLen + 1) * sizeof(WCHAR));
720
721 if (*lpCanonName == NULL)
722 {
723 DPRINT("Error allocating memory for canonized service name!\n");
724 return ERROR_NOT_ENOUGH_MEMORY;
725 }
726
727 /* Just copy it over without changing */
728 wcscpy(*lpCanonName, lpServiceName);
729
730 return NO_ERROR;
731 }
732
733 /* It seems to be a DOS path, convert it */
734 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
735 {
736 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
737 return ERROR_INVALID_PARAMETER;
738 }
739
740 *lpCanonName = HeapAlloc(GetProcessHeap(),
741 HEAP_ZERO_MEMORY,
742 NtServiceName.Length + sizeof(WCHAR));
743
744 if (*lpCanonName == NULL)
745 {
746 DPRINT("Error allocating memory for canonized service name!\n");
747 RtlFreeUnicodeString(&NtServiceName);
748 return ERROR_NOT_ENOUGH_MEMORY;
749 }
750
751 /* Copy the string */
752 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
753
754 /* The unicode string is not needed anymore */
755 RtlFreeUnicodeString(&NtServiceName);
756
757 if (dwStartType != SERVICE_BOOT_START)
758 {
759 DPRINT("Canonicalized name %S\n", *lpCanonName);
760 return NO_ERROR;
761 }
762
763 /* The service is boot-started, so must be relative */
764 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
765 if (Result)
766 {
767 /* There is a problem, free name and return */
768 HeapFree(GetProcessHeap(), 0, *lpCanonName);
769 DPRINT("Error converting named!\n");
770 return Result;
771 }
772
773 ASSERT(RelativeName);
774
775 /* Copy that string */
776 wcscpy(*lpCanonName, RelativeName + 12);
777
778 /* Free the allocated buffer */
779 HeapFree(GetProcessHeap(), 0, RelativeName);
780
781 DPRINT("Canonicalized name %S\n", *lpCanonName);
782
783 /* Success */
784 return NO_ERROR;
785 }
786
787
788 /* Internal recursive function */
789 /* Need to search for every dependency on every service */
790 static DWORD
791 Int_EnumDependentServicesW(HKEY hServicesKey,
792 PSERVICE lpService,
793 DWORD dwServiceState,
794 PSERVICE *lpServices,
795 LPDWORD pcbBytesNeeded,
796 LPDWORD lpServicesReturned)
797 {
798 DWORD dwError = ERROR_SUCCESS;
799 WCHAR szNameBuf[MAX_PATH];
800 WCHAR szValueBuf[MAX_PATH];
801 WCHAR *lpszNameBuf = szNameBuf;
802 WCHAR *lpszValueBuf = szValueBuf;
803 DWORD dwSize;
804 DWORD dwNumSubKeys;
805 DWORD dwIteration;
806 PSERVICE lpCurrentService;
807 HKEY hServiceEnumKey;
808 DWORD dwCurrentServiceState = SERVICE_ACTIVE;
809 DWORD dwDependServiceStrPtr = 0;
810 DWORD dwRequiredSize = 0;
811
812 /* Get the number of service keys */
813 dwError = RegQueryInfoKeyW(hServicesKey,
814 NULL,
815 NULL,
816 NULL,
817 &dwNumSubKeys,
818 NULL,
819 NULL,
820 NULL,
821 NULL,
822 NULL,
823 NULL,
824 NULL);
825 if (dwError != ERROR_SUCCESS)
826 {
827 DPRINT("ERROR! Unable to get number of services keys.\n");
828 return dwError;
829 }
830
831 /* Iterate the service keys to see if another service depends on the this service */
832 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
833 {
834 dwSize = MAX_PATH;
835 dwError = RegEnumKeyExW(hServicesKey,
836 dwIteration,
837 lpszNameBuf,
838 &dwSize,
839 NULL,
840 NULL,
841 NULL,
842 NULL);
843 if (dwError != ERROR_SUCCESS)
844 return dwError;
845
846 /* Open the Service key */
847 dwError = RegOpenKeyExW(hServicesKey,
848 lpszNameBuf,
849 0,
850 KEY_READ,
851 &hServiceEnumKey);
852 if (dwError != ERROR_SUCCESS)
853 return dwError;
854
855 dwSize = MAX_PATH;
856
857 /* Check for the DependOnService Value */
858 dwError = RegQueryValueExW(hServiceEnumKey,
859 L"DependOnService",
860 NULL,
861 NULL,
862 (LPBYTE)lpszValueBuf,
863 &dwSize);
864
865 /* FIXME: Handle load order. */
866
867 /* If the service found has a DependOnService value */
868 if (dwError == ERROR_SUCCESS)
869 {
870 dwDependServiceStrPtr = 0;
871
872 /* Can be more than one Dependencies in the DependOnService string */
873 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
874 {
875 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
876 {
877 /* Get the current enumed service pointer */
878 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
879
880 /* Check for valid Service */
881 if (!lpCurrentService)
882 {
883 /* This should never happen! */
884 DPRINT("This should not happen at this point, report to Developer\n");
885 return ERROR_NOT_FOUND;
886 }
887
888 /* Determine state the service is in */
889 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
890 dwCurrentServiceState = SERVICE_INACTIVE;
891
892 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
893 if ((dwCurrentServiceState == dwServiceState) ||
894 (dwServiceState == SERVICE_STATE_ALL))
895 {
896 /* Calculate the required size */
897 dwRequiredSize += sizeof(SERVICE_STATUS);
898 dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
899 dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
900
901 /* Add the size for service name and display name pointers */
902 dwRequiredSize += (2 * sizeof(PVOID));
903
904 /* increase the BytesNeeded size */
905 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
906
907 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
908 comes first */
909
910 /* Recursive call to check for its dependencies */
911 Int_EnumDependentServicesW(hServicesKey,
912 lpCurrentService,
913 dwServiceState,
914 lpServices,
915 pcbBytesNeeded,
916 lpServicesReturned);
917
918 /* If the lpServices is valid set the service pointer */
919 if (lpServices)
920 lpServices[*lpServicesReturned] = lpCurrentService;
921
922 *lpServicesReturned = *lpServicesReturned + 1;
923 }
924 }
925
926 dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
927 }
928 }
929 else if (*pcbBytesNeeded)
930 {
931 dwError = ERROR_SUCCESS;
932 }
933
934 RegCloseKey(hServiceEnumKey);
935 }
936
937 return dwError;
938 }
939
940
941 /* Function 0 */
942 DWORD RCloseServiceHandle(
943 LPSC_RPC_HANDLE hSCObject)
944 {
945 PMANAGER_HANDLE hManager;
946 PSERVICE_HANDLE hService;
947 PSERVICE lpService;
948 HKEY hServicesKey;
949 DWORD dwError;
950 DWORD pcbBytesNeeded = 0;
951 DWORD dwServicesReturned = 0;
952
953 DPRINT("RCloseServiceHandle() called\n");
954
955 DPRINT("hSCObject = %p\n", *hSCObject);
956
957 if (*hSCObject == 0)
958 return ERROR_INVALID_HANDLE;
959
960 hManager = ScmGetServiceManagerFromHandle(*hSCObject);
961 hService = ScmGetServiceFromHandle(*hSCObject);
962
963 if (hManager != NULL)
964 {
965 DPRINT("Found manager handle\n");
966
967 /* FIXME: add handle cleanup code */
968
969 HeapFree(GetProcessHeap(), 0, hManager);
970 hManager = NULL;
971
972 *hSCObject = NULL;
973
974 DPRINT("RCloseServiceHandle() done\n");
975 return ERROR_SUCCESS;
976 }
977 else if (hService != NULL)
978 {
979 DPRINT("Found service handle\n");
980
981 /* Lock the service database exlusively */
982 ScmLockDatabaseExclusive();
983
984 /* Get the pointer to the service record */
985 lpService = hService->ServiceEntry;
986
987 /* FIXME: add handle cleanup code */
988
989 /* Free the handle */
990 HeapFree(GetProcessHeap(), 0, hService);
991 hService = NULL;
992
993 ASSERT(lpService->dwRefCount > 0);
994
995 lpService->dwRefCount--;
996 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
997 lpService->dwRefCount);
998
999 if (lpService->dwRefCount == 0)
1000 {
1001 /* If this service has been marked for deletion */
1002 if (lpService->bDeleted)
1003 {
1004 /* Open the Services Reg key */
1005 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1006 L"System\\CurrentControlSet\\Services",
1007 0,
1008 KEY_SET_VALUE | KEY_READ,
1009 &hServicesKey);
1010 if (dwError != ERROR_SUCCESS)
1011 {
1012 DPRINT("Failed to open services key\n");
1013 ScmUnlockDatabase();
1014 return dwError;
1015 }
1016
1017 /* Call the internal function with NULL, just to get bytes we need */
1018 Int_EnumDependentServicesW(hServicesKey,
1019 lpService,
1020 SERVICE_ACTIVE,
1021 NULL,
1022 &pcbBytesNeeded,
1023 &dwServicesReturned);
1024
1025 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
1026 if (pcbBytesNeeded)
1027 {
1028 DPRINT("Deletion failed due to running dependencies.\n");
1029 RegCloseKey(hServicesKey);
1030 ScmUnlockDatabase();
1031 return ERROR_SUCCESS;
1032 }
1033
1034 /* There are no references and no runnning dependencies,
1035 it is now safe to delete the service */
1036
1037 /* Delete the Service Key */
1038 dwError = RegDeleteKeyW(hServicesKey,
1039 lpService->lpServiceName);
1040
1041 RegCloseKey(hServicesKey);
1042
1043 if (dwError != ERROR_SUCCESS)
1044 {
1045 DPRINT("Failed to Delete the Service Registry key\n");
1046 ScmUnlockDatabase();
1047 return dwError;
1048 }
1049
1050 /* Delete the Service */
1051 ScmDeleteServiceRecord(lpService);
1052 }
1053 }
1054
1055 ScmUnlockDatabase();
1056
1057 *hSCObject = NULL;
1058
1059 DPRINT("RCloseServiceHandle() done\n");
1060 return ERROR_SUCCESS;
1061 }
1062
1063 DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
1064
1065 return ERROR_INVALID_HANDLE;
1066 }
1067
1068
1069 /* Function 1 */
1070 DWORD RControlService(
1071 SC_RPC_HANDLE hService,
1072 DWORD dwControl,
1073 LPSERVICE_STATUS lpServiceStatus)
1074 {
1075 PSERVICE_HANDLE hSvc;
1076 PSERVICE lpService;
1077 ACCESS_MASK DesiredAccess;
1078 DWORD dwError = ERROR_SUCCESS;
1079 DWORD pcbBytesNeeded = 0;
1080 DWORD dwServicesReturned = 0;
1081 DWORD dwControlsAccepted;
1082 DWORD dwCurrentState;
1083 HKEY hServicesKey = NULL;
1084
1085 DPRINT("RControlService() called\n");
1086
1087 if (ScmShutdown)
1088 return ERROR_SHUTDOWN_IN_PROGRESS;
1089
1090 /* Check the service handle */
1091 hSvc = ScmGetServiceFromHandle(hService);
1092 if (hSvc == NULL)
1093 {
1094 DPRINT1("Invalid service handle!\n");
1095 return ERROR_INVALID_HANDLE;
1096 }
1097
1098 /* Check the service entry point */
1099 lpService = hSvc->ServiceEntry;
1100 if (lpService == NULL)
1101 {
1102 DPRINT1("lpService == NULL!\n");
1103 return ERROR_INVALID_HANDLE;
1104 }
1105
1106 /* Check access rights */
1107 switch (dwControl)
1108 {
1109 case SERVICE_CONTROL_STOP:
1110 DesiredAccess = SERVICE_STOP;
1111 break;
1112
1113 case SERVICE_CONTROL_PAUSE:
1114 case SERVICE_CONTROL_CONTINUE:
1115 DesiredAccess = SERVICE_PAUSE_CONTINUE;
1116 break;
1117
1118 case SERVICE_INTERROGATE:
1119 DesiredAccess = SERVICE_INTERROGATE;
1120 break;
1121
1122 default:
1123 if (dwControl >= 128 && dwControl <= 255)
1124 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
1125 else
1126 return ERROR_INVALID_PARAMETER;
1127 break;
1128 }
1129
1130 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1131 DesiredAccess))
1132 return ERROR_ACCESS_DENIED;
1133
1134 /* Return the current service status information */
1135 RtlCopyMemory(lpServiceStatus,
1136 &lpService->Status,
1137 sizeof(SERVICE_STATUS));
1138
1139 if (dwControl == SERVICE_CONTROL_STOP)
1140 {
1141 /* Check if the service has dependencies running as windows
1142 doesn't stop a service that does */
1143
1144 /* Open the Services Reg key */
1145 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1146 L"System\\CurrentControlSet\\Services",
1147 0,
1148 KEY_READ,
1149 &hServicesKey);
1150 if (dwError != ERROR_SUCCESS)
1151 {
1152 DPRINT("Failed to open services key\n");
1153 return dwError;
1154 }
1155
1156 /* Call the internal function with NULL, just to get bytes we need */
1157 Int_EnumDependentServicesW(hServicesKey,
1158 lpService,
1159 SERVICE_ACTIVE,
1160 NULL,
1161 &pcbBytesNeeded,
1162 &dwServicesReturned);
1163
1164 RegCloseKey(hServicesKey);
1165
1166 /* If pcbBytesNeeded is not zero then there are services running that
1167 are dependent on this service */
1168 if (pcbBytesNeeded != 0)
1169 {
1170 DPRINT("Service has running dependencies. Failed to stop service.\n");
1171 return ERROR_DEPENDENT_SERVICES_RUNNING;
1172 }
1173 }
1174
1175 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1176 {
1177 /* Send control code to the driver */
1178 dwError = ScmControlDriver(lpService,
1179 dwControl,
1180 lpServiceStatus);
1181 }
1182 else
1183 {
1184 dwControlsAccepted = lpService->Status.dwControlsAccepted;
1185 dwCurrentState = lpService->Status.dwCurrentState;
1186
1187 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1188 if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
1189 return ERROR_SERVICE_NOT_ACTIVE;
1190
1191 /* Check the current state before sending a control request */
1192 switch (dwCurrentState)
1193 {
1194 case SERVICE_STOP_PENDING:
1195 case SERVICE_STOPPED:
1196 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1197
1198 case SERVICE_START_PENDING:
1199 switch (dwControl)
1200 {
1201 case SERVICE_CONTROL_STOP:
1202 break;
1203
1204 case SERVICE_CONTROL_INTERROGATE:
1205 RtlCopyMemory(lpServiceStatus,
1206 &lpService->Status,
1207 sizeof(SERVICE_STATUS));
1208 return ERROR_SUCCESS;
1209
1210 default:
1211 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1212 }
1213 break;
1214 }
1215
1216 /* Check if the control code is acceptable to the service */
1217 switch (dwControl)
1218 {
1219 case SERVICE_CONTROL_STOP:
1220 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
1221 return ERROR_INVALID_SERVICE_CONTROL;
1222 break;
1223
1224 case SERVICE_CONTROL_PAUSE:
1225 case SERVICE_CONTROL_CONTINUE:
1226 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1227 return ERROR_INVALID_SERVICE_CONTROL;
1228 break;
1229 }
1230
1231 /* Send control code to the service */
1232 dwError = ScmControlService(lpService,
1233 dwControl);
1234
1235 /* Return service status information */
1236 RtlCopyMemory(lpServiceStatus,
1237 &lpService->Status,
1238 sizeof(SERVICE_STATUS));
1239 }
1240
1241 if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
1242 dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
1243
1244 return dwError;
1245 }
1246
1247
1248 /* Function 2 */
1249 DWORD RDeleteService(
1250 SC_RPC_HANDLE hService)
1251 {
1252 PSERVICE_HANDLE hSvc;
1253 PSERVICE lpService;
1254 DWORD dwError;
1255
1256 DPRINT("RDeleteService() called\n");
1257
1258 if (ScmShutdown)
1259 return ERROR_SHUTDOWN_IN_PROGRESS;
1260
1261 hSvc = ScmGetServiceFromHandle(hService);
1262 if (hSvc == NULL)
1263 {
1264 DPRINT1("Invalid service handle!\n");
1265 return ERROR_INVALID_HANDLE;
1266 }
1267
1268 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1269 DELETE))
1270 return ERROR_ACCESS_DENIED;
1271
1272 lpService = hSvc->ServiceEntry;
1273 if (lpService == NULL)
1274 {
1275 DPRINT("lpService == NULL!\n");
1276 return ERROR_INVALID_HANDLE;
1277 }
1278
1279 /* Lock the service database exclusively */
1280 ScmLockDatabaseExclusive();
1281
1282 if (lpService->bDeleted)
1283 {
1284 DPRINT("The service has already been marked for delete!\n");
1285 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1286 goto Done;
1287 }
1288
1289 /* Mark service for delete */
1290 lpService->bDeleted = TRUE;
1291
1292 dwError = ScmMarkServiceForDelete(lpService);
1293
1294 Done:;
1295 /* Unlock the service database */
1296 ScmUnlockDatabase();
1297
1298 DPRINT("RDeleteService() done\n");
1299
1300 return dwError;
1301 }
1302
1303
1304 /* Function 3 */
1305 DWORD RLockServiceDatabase(
1306 SC_RPC_HANDLE hSCManager,
1307 LPSC_RPC_LOCK lpLock)
1308 {
1309 PMANAGER_HANDLE hMgr;
1310
1311 DPRINT("RLockServiceDatabase() called\n");
1312
1313 *lpLock = 0;
1314
1315 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
1316 if (hMgr == NULL)
1317 {
1318 DPRINT1("Invalid service manager handle!\n");
1319 return ERROR_INVALID_HANDLE;
1320 }
1321
1322 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
1323 SC_MANAGER_LOCK))
1324 return ERROR_ACCESS_DENIED;
1325
1326 // return ScmLockDatabase(0, hMgr->0xC, hLock);
1327
1328 /* FIXME: Lock the database */
1329 *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */
1330
1331 return ERROR_SUCCESS;
1332 }
1333
1334
1335 /* Function 4 */
1336 DWORD RQueryServiceObjectSecurity(
1337 SC_RPC_HANDLE hService,
1338 SECURITY_INFORMATION dwSecurityInformation,
1339 LPBYTE lpSecurityDescriptor,
1340 DWORD cbBufSize,
1341 LPBOUNDED_DWORD_256K pcbBytesNeeded)
1342 {
1343 PSERVICE_HANDLE hSvc;
1344 PSERVICE lpService;
1345 ULONG DesiredAccess = 0;
1346 NTSTATUS Status;
1347 DWORD dwBytesNeeded;
1348 DWORD dwError;
1349
1350
1351 SECURITY_DESCRIPTOR ObjectDescriptor;
1352
1353 DPRINT("RQueryServiceObjectSecurity() called\n");
1354
1355 hSvc = ScmGetServiceFromHandle(hService);
1356 if (hSvc == NULL)
1357 {
1358 DPRINT1("Invalid service handle!\n");
1359 return ERROR_INVALID_HANDLE;
1360 }
1361
1362 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1363 GROUP_SECURITY_INFORMATION |
1364 OWNER_SECURITY_INFORMATION))
1365 DesiredAccess |= READ_CONTROL;
1366
1367 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1368 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1369
1370 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1371 DesiredAccess))
1372 {
1373 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1374 return ERROR_ACCESS_DENIED;
1375 }
1376
1377 lpService = hSvc->ServiceEntry;
1378 if (lpService == NULL)
1379 {
1380 DPRINT("lpService == NULL!\n");
1381 return ERROR_INVALID_HANDLE;
1382 }
1383
1384 /* Lock the service database */
1385 ScmLockDatabaseShared();
1386
1387
1388 /* hack */
1389 Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
1390
1391 Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */,
1392 dwSecurityInformation,
1393 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1394 cbBufSize,
1395 &dwBytesNeeded);
1396
1397 /* Unlock the service database */
1398 ScmUnlockDatabase();
1399
1400 if (NT_SUCCESS(Status))
1401 {
1402 *pcbBytesNeeded = dwBytesNeeded;
1403 dwError = STATUS_SUCCESS;
1404 }
1405 else if (Status == STATUS_BUFFER_TOO_SMALL)
1406 {
1407 *pcbBytesNeeded = dwBytesNeeded;
1408 dwError = ERROR_INSUFFICIENT_BUFFER;
1409 }
1410 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
1411 {
1412 dwError = ERROR_GEN_FAILURE;
1413 }
1414 else
1415 {
1416 dwError = RtlNtStatusToDosError(Status);
1417 }
1418
1419 return dwError;
1420 }
1421
1422
1423 /* Function 5 */
1424 DWORD RSetServiceObjectSecurity(
1425 SC_RPC_HANDLE hService,
1426 DWORD dwSecurityInformation,
1427 LPBYTE lpSecurityDescriptor,
1428 DWORD dwSecuityDescriptorSize)
1429 {
1430 PSERVICE_HANDLE hSvc;
1431 PSERVICE lpService;
1432 ULONG DesiredAccess = 0;
1433 /* HANDLE hToken = NULL; */
1434 HKEY hServiceKey;
1435 /* NTSTATUS Status; */
1436 DWORD dwError;
1437
1438 DPRINT("RSetServiceObjectSecurity() called\n");
1439
1440 hSvc = ScmGetServiceFromHandle(hService);
1441 if (hSvc == NULL)
1442 {
1443 DPRINT1("Invalid service handle!\n");
1444 return ERROR_INVALID_HANDLE;
1445 }
1446
1447 if (dwSecurityInformation == 0 ||
1448 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1449 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
1450 return ERROR_INVALID_PARAMETER;
1451
1452 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1453 return ERROR_INVALID_PARAMETER;
1454
1455 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1456 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1457
1458 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1459 DesiredAccess |= WRITE_DAC;
1460
1461 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1462 DesiredAccess |= WRITE_OWNER;
1463
1464 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1465 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1466 return ERROR_INVALID_PARAMETER;
1467
1468 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1469 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1470 return ERROR_INVALID_PARAMETER;
1471
1472 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1473 DesiredAccess))
1474 {
1475 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1476 return ERROR_ACCESS_DENIED;
1477 }
1478
1479 lpService = hSvc->ServiceEntry;
1480 if (lpService == NULL)
1481 {
1482 DPRINT("lpService == NULL!\n");
1483 return ERROR_INVALID_HANDLE;
1484 }
1485
1486 if (lpService->bDeleted)
1487 return ERROR_SERVICE_MARKED_FOR_DELETE;
1488
1489 #if 0
1490 RpcImpersonateClient(NULL);
1491
1492 Status = NtOpenThreadToken(NtCurrentThread(),
1493 8,
1494 TRUE,
1495 &hToken);
1496 if (!NT_SUCCESS(Status))
1497 return RtlNtStatusToDosError(Status);
1498
1499 RpcRevertToSelf();
1500 #endif
1501
1502 /* Lock the service database exclusive */
1503 ScmLockDatabaseExclusive();
1504
1505 #if 0
1506 Status = RtlSetSecurityObject(dwSecurityInformation,
1507 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1508 &lpService->lpSecurityDescriptor,
1509 &ScmServiceMapping,
1510 hToken);
1511 if (!NT_SUCCESS(Status))
1512 {
1513 dwError = RtlNtStatusToDosError(Status);
1514 goto Done;
1515 }
1516 #endif
1517
1518 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1519 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
1520 &hServiceKey);
1521 if (dwError != ERROR_SUCCESS)
1522 goto Done;
1523
1524 UNIMPLEMENTED;
1525 dwError = ERROR_SUCCESS;
1526 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
1527 // lpService->lpSecurityDescriptor);
1528
1529 RegFlushKey(hServiceKey);
1530 RegCloseKey(hServiceKey);
1531
1532 Done:
1533
1534 #if 0
1535 if (hToken != NULL)
1536 NtClose(hToken);
1537 #endif
1538
1539 /* Unlock service database */
1540 ScmUnlockDatabase();
1541
1542 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1543
1544 return dwError;
1545 }
1546
1547
1548 /* Function 6 */
1549 DWORD RQueryServiceStatus(
1550 SC_RPC_HANDLE hService,
1551 LPSERVICE_STATUS lpServiceStatus)
1552 {
1553 PSERVICE_HANDLE hSvc;
1554 PSERVICE lpService;
1555
1556 DPRINT("RQueryServiceStatus() called\n");
1557
1558 if (ScmShutdown)
1559 return ERROR_SHUTDOWN_IN_PROGRESS;
1560
1561 hSvc = ScmGetServiceFromHandle(hService);
1562 if (hSvc == NULL)
1563 {
1564 DPRINT1("Invalid service handle!\n");
1565 return ERROR_INVALID_HANDLE;
1566 }
1567
1568 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1569 SERVICE_QUERY_STATUS))
1570 {
1571 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1572 return ERROR_ACCESS_DENIED;
1573 }
1574
1575 lpService = hSvc->ServiceEntry;
1576 if (lpService == NULL)
1577 {
1578 DPRINT("lpService == NULL!\n");
1579 return ERROR_INVALID_HANDLE;
1580 }
1581
1582 /* Lock the service database shared */
1583 ScmLockDatabaseShared();
1584
1585 /* Return service status information */
1586 RtlCopyMemory(lpServiceStatus,
1587 &lpService->Status,
1588 sizeof(SERVICE_STATUS));
1589
1590 /* Unlock the service database */
1591 ScmUnlockDatabase();
1592
1593 return ERROR_SUCCESS;
1594 }
1595
1596
1597 static BOOL
1598 ScmIsValidServiceState(DWORD dwCurrentState)
1599 {
1600 switch (dwCurrentState)
1601 {
1602 case SERVICE_STOPPED:
1603 case SERVICE_START_PENDING:
1604 case SERVICE_STOP_PENDING:
1605 case SERVICE_RUNNING:
1606 case SERVICE_CONTINUE_PENDING:
1607 case SERVICE_PAUSE_PENDING:
1608 case SERVICE_PAUSED:
1609 return TRUE;
1610
1611 default:
1612 return FALSE;
1613 }
1614 }
1615
1616
1617 /* Function 7 */
1618 DWORD RSetServiceStatus(
1619 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1620 LPSERVICE_STATUS lpServiceStatus)
1621 {
1622 PSERVICE lpService;
1623
1624 DPRINT("RSetServiceStatus() called\n");
1625 DPRINT("hServiceStatus = %p\n", hServiceStatus);
1626 DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
1627 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1628 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1629 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1630 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1631 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1632 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1633
1634 if (hServiceStatus == 0)
1635 {
1636 DPRINT("hServiceStatus == NULL!\n");
1637 return ERROR_INVALID_HANDLE;
1638 }
1639
1640 lpService = (PSERVICE)hServiceStatus;
1641 if (lpService == NULL)
1642 {
1643 DPRINT("lpService == NULL!\n");
1644 return ERROR_INVALID_HANDLE;
1645 }
1646
1647 /* Check current state */
1648 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1649 {
1650 DPRINT("Invalid service state!\n");
1651 return ERROR_INVALID_DATA;
1652 }
1653
1654 /* Check service type */
1655 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1656 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1657 {
1658 DPRINT("Invalid service type!\n");
1659 return ERROR_INVALID_DATA;
1660 }
1661
1662 /* Check accepted controls */
1663 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1664 {
1665 DPRINT("Invalid controls accepted!\n");
1666 return ERROR_INVALID_DATA;
1667 }
1668
1669 /* Lock the service database exclusively */
1670 ScmLockDatabaseExclusive();
1671
1672 RtlCopyMemory(&lpService->Status,
1673 lpServiceStatus,
1674 sizeof(SERVICE_STATUS));
1675
1676 /* Unlock the service database */
1677 ScmUnlockDatabase();
1678
1679 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1680 DPRINT("RSetServiceStatus() done\n");
1681
1682 return ERROR_SUCCESS;
1683 }
1684
1685
1686 /* Function 8 */
1687 DWORD RUnlockServiceDatabase(
1688 LPSC_RPC_LOCK Lock)
1689 {
1690 UNIMPLEMENTED;
1691 return ERROR_SUCCESS;
1692 }
1693
1694
1695 /* Function 9 */
1696 DWORD RNotifyBootConfigStatus(
1697 SVCCTL_HANDLEW lpMachineName,
1698 DWORD BootAcceptable)
1699 {
1700 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1701 return ERROR_SUCCESS;
1702
1703 // UNIMPLEMENTED;
1704 // return ERROR_CALL_NOT_IMPLEMENTED;
1705 }
1706
1707
1708 /* Function 10 */
1709 DWORD RI_ScSetServiceBitsW(
1710 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1711 DWORD dwServiceBits,
1712 int bSetBitsOn,
1713 int bUpdateImmediately,
1714 wchar_t *lpString)
1715 {
1716 UNIMPLEMENTED;
1717 return ERROR_CALL_NOT_IMPLEMENTED;
1718 }
1719
1720
1721 /* Function 11 */
1722 DWORD RChangeServiceConfigW(
1723 SC_RPC_HANDLE hService,
1724 DWORD dwServiceType,
1725 DWORD dwStartType,
1726 DWORD dwErrorControl,
1727 LPWSTR lpBinaryPathName,
1728 LPWSTR lpLoadOrderGroup,
1729 LPDWORD lpdwTagId,
1730 LPBYTE lpDependencies,
1731 DWORD dwDependSize,
1732 LPWSTR lpServiceStartName,
1733 LPBYTE lpPassword,
1734 DWORD dwPwSize,
1735 LPWSTR lpDisplayName)
1736 {
1737 DWORD dwError = ERROR_SUCCESS;
1738 PSERVICE_HANDLE hSvc;
1739 PSERVICE lpService = NULL;
1740 HKEY hServiceKey = NULL;
1741 LPWSTR lpDisplayNameW = NULL;
1742 LPWSTR lpImagePathW = NULL;
1743
1744 DPRINT("RChangeServiceConfigW() called\n");
1745 DPRINT("dwServiceType = %lu\n", dwServiceType);
1746 DPRINT("dwStartType = %lu\n", dwStartType);
1747 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1748 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1749 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1750 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1751
1752 if (ScmShutdown)
1753 return ERROR_SHUTDOWN_IN_PROGRESS;
1754
1755 hSvc = ScmGetServiceFromHandle(hService);
1756 if (hSvc == NULL)
1757 {
1758 DPRINT1("Invalid service handle!\n");
1759 return ERROR_INVALID_HANDLE;
1760 }
1761
1762 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1763 SERVICE_CHANGE_CONFIG))
1764 {
1765 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1766 return ERROR_ACCESS_DENIED;
1767 }
1768
1769 lpService = hSvc->ServiceEntry;
1770 if (lpService == NULL)
1771 {
1772 DPRINT("lpService == NULL!\n");
1773 return ERROR_INVALID_HANDLE;
1774 }
1775
1776 /* Lock the service database exclusively */
1777 ScmLockDatabaseExclusive();
1778
1779 if (lpService->bDeleted)
1780 {
1781 DPRINT("The service has already been marked for delete!\n");
1782 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1783 goto done;
1784 }
1785
1786 /* Open the service key */
1787 dwError = ScmOpenServiceKey(lpService->szServiceName,
1788 KEY_SET_VALUE,
1789 &hServiceKey);
1790 if (dwError != ERROR_SUCCESS)
1791 goto done;
1792
1793 /* Write service data to the registry */
1794 /* Set the display name */
1795 if (lpDisplayName != NULL && *lpDisplayName != 0)
1796 {
1797 RegSetValueExW(hServiceKey,
1798 L"DisplayName",
1799 0,
1800 REG_SZ,
1801 (LPBYTE)lpDisplayName,
1802 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1803
1804 /* Update the display name */
1805 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
1806 0,
1807 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1808 if (lpDisplayNameW == NULL)
1809 {
1810 dwError = ERROR_NOT_ENOUGH_MEMORY;
1811 goto done;
1812 }
1813
1814 if (lpService->lpDisplayName != lpService->lpServiceName)
1815 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1816
1817 lpService->lpDisplayName = lpDisplayNameW;
1818 }
1819
1820 if (dwServiceType != SERVICE_NO_CHANGE)
1821 {
1822 /* Set the service type */
1823 dwError = RegSetValueExW(hServiceKey,
1824 L"Type",
1825 0,
1826 REG_DWORD,
1827 (LPBYTE)&dwServiceType,
1828 sizeof(DWORD));
1829 if (dwError != ERROR_SUCCESS)
1830 goto done;
1831
1832 lpService->Status.dwServiceType = dwServiceType;
1833 }
1834
1835 if (dwStartType != SERVICE_NO_CHANGE)
1836 {
1837 /* Set the start value */
1838 dwError = RegSetValueExW(hServiceKey,
1839 L"Start",
1840 0,
1841 REG_DWORD,
1842 (LPBYTE)&dwStartType,
1843 sizeof(DWORD));
1844 if (dwError != ERROR_SUCCESS)
1845 goto done;
1846
1847 lpService->dwStartType = dwStartType;
1848 }
1849
1850 if (dwErrorControl != SERVICE_NO_CHANGE)
1851 {
1852 /* Set the error control value */
1853 dwError = RegSetValueExW(hServiceKey,
1854 L"ErrorControl",
1855 0,
1856 REG_DWORD,
1857 (LPBYTE)&dwErrorControl,
1858 sizeof(DWORD));
1859 if (dwError != ERROR_SUCCESS)
1860 goto done;
1861
1862 lpService->dwErrorControl = dwErrorControl;
1863 }
1864
1865 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
1866 {
1867 /* Set the image path */
1868 lpImagePathW = lpBinaryPathName;
1869
1870 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1871 {
1872 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
1873 lpBinaryPathName,
1874 &lpImagePathW);
1875
1876 if (dwError != ERROR_SUCCESS)
1877 goto done;
1878 }
1879
1880 dwError = RegSetValueExW(hServiceKey,
1881 L"ImagePath",
1882 0,
1883 REG_EXPAND_SZ,
1884 (LPBYTE)lpImagePathW,
1885 (wcslen(lpImagePathW) + 1) * sizeof(WCHAR));
1886
1887 if (lpImagePathW != lpBinaryPathName)
1888 HeapFree(GetProcessHeap(), 0, lpImagePathW);
1889
1890 if (dwError != ERROR_SUCCESS)
1891 goto done;
1892 }
1893
1894 /* Set the group name */
1895 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1896 {
1897 dwError = RegSetValueExW(hServiceKey,
1898 L"Group",
1899 0,
1900 REG_SZ,
1901 (LPBYTE)lpLoadOrderGroup,
1902 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1903 if (dwError != ERROR_SUCCESS)
1904 goto done;
1905
1906 dwError = ScmSetServiceGroup(lpService,
1907 lpLoadOrderGroup);
1908 if (dwError != ERROR_SUCCESS)
1909 goto done;
1910 }
1911
1912 if (lpdwTagId != NULL)
1913 {
1914 dwError = ScmAssignNewTag(lpService);
1915 if (dwError != ERROR_SUCCESS)
1916 goto done;
1917
1918 dwError = RegSetValueExW(hServiceKey,
1919 L"Tag",
1920 0,
1921 REG_DWORD,
1922 (LPBYTE)&lpService->dwTag,
1923 sizeof(DWORD));
1924 if (dwError != ERROR_SUCCESS)
1925 goto done;
1926
1927 *lpdwTagId = lpService->dwTag;
1928 }
1929
1930 /* Write dependencies */
1931 if (lpDependencies != NULL && *lpDependencies != 0)
1932 {
1933 dwError = ScmWriteDependencies(hServiceKey,
1934 (LPWSTR)lpDependencies,
1935 dwDependSize);
1936 if (dwError != ERROR_SUCCESS)
1937 goto done;
1938 }
1939
1940 if (lpPassword != NULL)
1941 {
1942 /* FIXME: Write password */
1943 }
1944
1945 done:
1946 if (hServiceKey != NULL)
1947 RegCloseKey(hServiceKey);
1948
1949 /* Unlock the service database */
1950 ScmUnlockDatabase();
1951
1952 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1953
1954 return dwError;
1955 }
1956
1957
1958 /* Function 12 */
1959 DWORD RCreateServiceW(
1960 SC_RPC_HANDLE hSCManager,
1961 LPCWSTR lpServiceName,
1962 LPCWSTR lpDisplayName,
1963 DWORD dwDesiredAccess,
1964 DWORD dwServiceType,
1965 DWORD dwStartType,
1966 DWORD dwErrorControl,
1967 LPCWSTR lpBinaryPathName,
1968 LPCWSTR lpLoadOrderGroup,
1969 LPDWORD lpdwTagId,
1970 LPBYTE lpDependencies,
1971 DWORD dwDependSize,
1972 LPCWSTR lpServiceStartName,
1973 LPBYTE lpPassword,
1974 DWORD dwPwSize,
1975 LPSC_RPC_HANDLE lpServiceHandle)
1976 {
1977 PMANAGER_HANDLE hManager;
1978 DWORD dwError = ERROR_SUCCESS;
1979 PSERVICE lpService = NULL;
1980 SC_HANDLE hServiceHandle = NULL;
1981 LPWSTR lpImagePath = NULL;
1982 HKEY hServiceKey = NULL;
1983 LPWSTR lpObjectName;
1984
1985 DPRINT("RCreateServiceW() called\n");
1986 DPRINT("lpServiceName = %S\n", lpServiceName);
1987 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1988 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
1989 DPRINT("dwServiceType = %lu\n", dwServiceType);
1990 DPRINT("dwStartType = %lu\n", dwStartType);
1991 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1992 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1993 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1994 DPRINT("lpdwTagId = %p\n", lpdwTagId);
1995
1996 if (ScmShutdown)
1997 return ERROR_SHUTDOWN_IN_PROGRESS;
1998
1999 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2000 if (hManager == NULL)
2001 {
2002 DPRINT1("Invalid service manager handle!\n");
2003 return ERROR_INVALID_HANDLE;
2004 }
2005
2006 /* Check access rights */
2007 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2008 SC_MANAGER_CREATE_SERVICE))
2009 {
2010 DPRINT("Insufficient access rights! 0x%lx\n",
2011 hManager->Handle.DesiredAccess);
2012 return ERROR_ACCESS_DENIED;
2013 }
2014
2015 if (wcslen(lpServiceName) == 0)
2016 {
2017 return ERROR_INVALID_NAME;
2018 }
2019
2020 if (wcslen(lpBinaryPathName) == 0)
2021 {
2022 return ERROR_INVALID_PARAMETER;
2023 }
2024
2025 /* Check for invalid service type value */
2026 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2027 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2028 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2029 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
2030 return ERROR_INVALID_PARAMETER;
2031
2032 /* Check for invalid start type value */
2033 if ((dwStartType != SERVICE_BOOT_START) &&
2034 (dwStartType != SERVICE_SYSTEM_START) &&
2035 (dwStartType != SERVICE_AUTO_START) &&
2036 (dwStartType != SERVICE_DEMAND_START) &&
2037 (dwStartType != SERVICE_DISABLED))
2038 return ERROR_INVALID_PARAMETER;
2039
2040 /* Only drivers can be boot start or system start services */
2041 if ((dwStartType == SERVICE_BOOT_START) ||
2042 (dwStartType == SERVICE_SYSTEM_START))
2043 {
2044 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2045 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2046 return ERROR_INVALID_PARAMETER;
2047 }
2048
2049 /* Check for invalid error control value */
2050 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2051 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2052 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2053 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2054 return ERROR_INVALID_PARAMETER;
2055
2056 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2057 (lpServiceStartName))
2058 {
2059 return ERROR_INVALID_PARAMETER;
2060 }
2061
2062 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2063 {
2064 return ERROR_INVALID_PARAMETER;
2065 }
2066
2067 /* Lock the service database exclusively */
2068 ScmLockDatabaseExclusive();
2069
2070 lpService = ScmGetServiceEntryByName(lpServiceName);
2071 if (lpService)
2072 {
2073 /* Unlock the service database */
2074 ScmUnlockDatabase();
2075
2076 /* Check if it is marked for deletion */
2077 if (lpService->bDeleted)
2078 return ERROR_SERVICE_MARKED_FOR_DELETE;
2079
2080 /* Return Error exist */
2081 return ERROR_SERVICE_EXISTS;
2082 }
2083
2084 if (lpDisplayName != NULL &&
2085 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2086 {
2087 /* Unlock the service database */
2088 ScmUnlockDatabase();
2089
2090 return ERROR_DUPLICATE_SERVICE_NAME;
2091 }
2092
2093 if (dwServiceType & SERVICE_DRIVER)
2094 {
2095 dwError = ScmCanonDriverImagePath(dwStartType,
2096 lpBinaryPathName,
2097 &lpImagePath);
2098 if (dwError != ERROR_SUCCESS)
2099 goto done;
2100 }
2101 else
2102 {
2103 if (dwStartType == SERVICE_BOOT_START ||
2104 dwStartType == SERVICE_SYSTEM_START)
2105 {
2106 /* Unlock the service database */
2107 ScmUnlockDatabase();
2108
2109 return ERROR_INVALID_PARAMETER;
2110 }
2111 }
2112
2113 /* Allocate a new service entry */
2114 dwError = ScmCreateNewServiceRecord(lpServiceName,
2115 &lpService);
2116 if (dwError != ERROR_SUCCESS)
2117 goto done;
2118
2119 /* Fill the new service entry */
2120 lpService->Status.dwServiceType = dwServiceType;
2121 lpService->dwStartType = dwStartType;
2122 lpService->dwErrorControl = dwErrorControl;
2123
2124 /* Fill the display name */
2125 if (lpDisplayName != NULL &&
2126 *lpDisplayName != 0 &&
2127 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2128 {
2129 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(), 0,
2130 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2131 if (lpService->lpDisplayName == NULL)
2132 {
2133 dwError = ERROR_NOT_ENOUGH_MEMORY;
2134 goto done;
2135 }
2136 wcscpy(lpService->lpDisplayName, lpDisplayName);
2137 }
2138
2139 /* Assign the service to a group */
2140 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2141 {
2142 dwError = ScmSetServiceGroup(lpService,
2143 lpLoadOrderGroup);
2144 if (dwError != ERROR_SUCCESS)
2145 goto done;
2146 }
2147
2148 /* Assign a new tag */
2149 if (lpdwTagId != NULL)
2150 {
2151 dwError = ScmAssignNewTag(lpService);
2152 if (dwError != ERROR_SUCCESS)
2153 goto done;
2154 }
2155
2156 /* Write service data to the registry */
2157 /* Create the service key */
2158 dwError = ScmCreateServiceKey(lpServiceName,
2159 KEY_WRITE,
2160 &hServiceKey);
2161 if (dwError != ERROR_SUCCESS)
2162 goto done;
2163
2164 /* Set the display name */
2165 if (lpDisplayName != NULL && *lpDisplayName != 0)
2166 {
2167 RegSetValueExW(hServiceKey,
2168 L"DisplayName",
2169 0,
2170 REG_SZ,
2171 (LPBYTE)lpDisplayName,
2172 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2173 }
2174
2175 /* Set the service type */
2176 dwError = RegSetValueExW(hServiceKey,
2177 L"Type",
2178 0,
2179 REG_DWORD,
2180 (LPBYTE)&dwServiceType,
2181 sizeof(DWORD));
2182 if (dwError != ERROR_SUCCESS)
2183 goto done;
2184
2185 /* Set the start value */
2186 dwError = RegSetValueExW(hServiceKey,
2187 L"Start",
2188 0,
2189 REG_DWORD,
2190 (LPBYTE)&dwStartType,
2191 sizeof(DWORD));
2192 if (dwError != ERROR_SUCCESS)
2193 goto done;
2194
2195 /* Set the error control value */
2196 dwError = RegSetValueExW(hServiceKey,
2197 L"ErrorControl",
2198 0,
2199 REG_DWORD,
2200 (LPBYTE)&dwErrorControl,
2201 sizeof(DWORD));
2202 if (dwError != ERROR_SUCCESS)
2203 goto done;
2204
2205 /* Set the image path */
2206 if (dwServiceType & SERVICE_WIN32)
2207 {
2208 dwError = RegSetValueExW(hServiceKey,
2209 L"ImagePath",
2210 0,
2211 REG_EXPAND_SZ,
2212 (LPBYTE)lpBinaryPathName,
2213 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
2214 if (dwError != ERROR_SUCCESS)
2215 goto done;
2216 }
2217 else if (dwServiceType & SERVICE_DRIVER)
2218 {
2219 dwError = RegSetValueExW(hServiceKey,
2220 L"ImagePath",
2221 0,
2222 REG_EXPAND_SZ,
2223 (LPBYTE)lpImagePath,
2224 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2225 if (dwError != ERROR_SUCCESS)
2226 goto done;
2227 }
2228
2229 /* Set the group name */
2230 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2231 {
2232 dwError = RegSetValueExW(hServiceKey,
2233 L"Group",
2234 0,
2235 REG_SZ,
2236 (LPBYTE)lpLoadOrderGroup,
2237 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
2238 if (dwError != ERROR_SUCCESS)
2239 goto done;
2240 }
2241
2242 if (lpdwTagId != NULL)
2243 {
2244 dwError = RegSetValueExW(hServiceKey,
2245 L"Tag",
2246 0,
2247 REG_DWORD,
2248 (LPBYTE)&lpService->dwTag,
2249 sizeof(DWORD));
2250 if (dwError != ERROR_SUCCESS)
2251 goto done;
2252 }
2253
2254 /* Write dependencies */
2255 if (lpDependencies != NULL && *lpDependencies != 0)
2256 {
2257 dwError = ScmWriteDependencies(hServiceKey,
2258 (LPCWSTR)lpDependencies,
2259 dwDependSize);
2260 if (dwError != ERROR_SUCCESS)
2261 goto done;
2262 }
2263
2264 /* Write service start name */
2265 if (dwServiceType & SERVICE_WIN32)
2266 {
2267 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2268 dwError = RegSetValueExW(hServiceKey,
2269 L"ObjectName",
2270 0,
2271 REG_SZ,
2272 (LPBYTE)lpObjectName,
2273 (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
2274 if (dwError != ERROR_SUCCESS)
2275 goto done;
2276 }
2277
2278 if (lpPassword != NULL)
2279 {
2280 /* FIXME: Write password */
2281 }
2282
2283 dwError = ScmCreateServiceHandle(lpService,
2284 &hServiceHandle);
2285 if (dwError != ERROR_SUCCESS)
2286 goto done;
2287
2288 dwError = ScmCheckAccess(hServiceHandle,
2289 dwDesiredAccess);
2290 if (dwError != ERROR_SUCCESS)
2291 goto done;
2292
2293 lpService->dwRefCount = 1;
2294 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2295
2296 done:;
2297 /* Unlock the service database */
2298 ScmUnlockDatabase();
2299
2300 if (hServiceKey != NULL)
2301 RegCloseKey(hServiceKey);
2302
2303 if (dwError == ERROR_SUCCESS)
2304 {
2305 DPRINT("hService %p\n", hServiceHandle);
2306 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2307
2308 if (lpdwTagId != NULL)
2309 *lpdwTagId = lpService->dwTag;
2310 }
2311 else
2312 {
2313 if (lpService != NULL &&
2314 lpService->lpServiceName != NULL)
2315 {
2316 /* Release the display name buffer */
2317 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2318 }
2319
2320 if (hServiceHandle)
2321 {
2322 /* Remove the service handle */
2323 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2324 }
2325
2326 if (lpService != NULL)
2327 {
2328 /* FIXME: remove the service entry */
2329 }
2330 }
2331
2332 if (lpImagePath != NULL)
2333 HeapFree(GetProcessHeap(), 0, lpImagePath);
2334
2335 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2336
2337 return dwError;
2338 }
2339
2340
2341 /* Function 13 */
2342 DWORD REnumDependentServicesW(
2343 SC_RPC_HANDLE hService,
2344 DWORD dwServiceState,
2345 LPBYTE lpServices,
2346 DWORD cbBufSize,
2347 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2348 LPBOUNDED_DWORD_256K lpServicesReturned)
2349 {
2350 DWORD dwError = ERROR_SUCCESS;
2351 DWORD dwServicesReturned = 0;
2352 DWORD dwServiceCount;
2353 HKEY hServicesKey = NULL;
2354 PSERVICE_HANDLE hSvc;
2355 PSERVICE lpService = NULL;
2356 PSERVICE *lpServicesArray = NULL;
2357 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2358 LPWSTR lpStr;
2359
2360 *pcbBytesNeeded = 0;
2361 *lpServicesReturned = 0;
2362
2363 DPRINT("REnumDependentServicesW() called\n");
2364
2365 hSvc = ScmGetServiceFromHandle(hService);
2366 if (hSvc == NULL)
2367 {
2368 DPRINT1("Invalid service handle!\n");
2369 return ERROR_INVALID_HANDLE;
2370 }
2371
2372 lpService = hSvc->ServiceEntry;
2373
2374 /* Check access rights */
2375 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2376 SC_MANAGER_ENUMERATE_SERVICE))
2377 {
2378 DPRINT("Insufficient access rights! 0x%lx\n",
2379 hSvc->Handle.DesiredAccess);
2380 return ERROR_ACCESS_DENIED;
2381 }
2382
2383 /* Open the Services Reg key */
2384 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2385 L"System\\CurrentControlSet\\Services",
2386 0,
2387 KEY_READ,
2388 &hServicesKey);
2389 if (dwError != ERROR_SUCCESS)
2390 return dwError;
2391
2392 /* First determine the bytes needed and get the number of dependent services */
2393 dwError = Int_EnumDependentServicesW(hServicesKey,
2394 lpService,
2395 dwServiceState,
2396 NULL,
2397 pcbBytesNeeded,
2398 &dwServicesReturned);
2399 if (dwError != ERROR_SUCCESS)
2400 goto Done;
2401
2402 /* If buffer size is less than the bytes needed or pointer is null */
2403 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2404 {
2405 dwError = ERROR_MORE_DATA;
2406 goto Done;
2407 }
2408
2409 /* Allocate memory for array of service pointers */
2410 lpServicesArray = HeapAlloc(GetProcessHeap(),
2411 0,
2412 (dwServicesReturned + 1) * sizeof(PSERVICE));
2413 if (!lpServicesArray)
2414 {
2415 DPRINT1("Could not allocate a buffer!!\n");
2416 dwError = ERROR_NOT_ENOUGH_MEMORY;
2417 goto Done;
2418 }
2419
2420 dwServicesReturned = 0;
2421 *pcbBytesNeeded = 0;
2422
2423 dwError = Int_EnumDependentServicesW(hServicesKey,
2424 lpService,
2425 dwServiceState,
2426 lpServicesArray,
2427 pcbBytesNeeded,
2428 &dwServicesReturned);
2429 if (dwError != ERROR_SUCCESS)
2430 {
2431 goto Done;
2432 }
2433
2434 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
2435 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2436
2437 /* Copy EnumDepenedentService to Buffer */
2438 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2439 {
2440 lpService = lpServicesArray[dwServiceCount];
2441
2442 /* Copy status info */
2443 memcpy(&lpServicesPtr->ServiceStatus,
2444 &lpService->Status,
2445 sizeof(SERVICE_STATUS));
2446
2447 /* Copy display name */
2448 wcscpy(lpStr, lpService->lpDisplayName);
2449 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2450 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2451
2452 /* Copy service name */
2453 wcscpy(lpStr, lpService->lpServiceName);
2454 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2455 lpStr += (wcslen(lpService->lpServiceName) + 1);
2456
2457 lpServicesPtr ++;
2458 }
2459
2460 *lpServicesReturned = dwServicesReturned;
2461
2462 Done:
2463 if (lpServicesArray != NULL)
2464 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2465
2466 RegCloseKey(hServicesKey);
2467
2468 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2469
2470 return dwError;
2471 }
2472
2473
2474 /* Function 14 */
2475 DWORD REnumServicesStatusW(
2476 SC_RPC_HANDLE hSCManager,
2477 DWORD dwServiceType,
2478 DWORD dwServiceState,
2479 LPBYTE lpBuffer,
2480 DWORD dwBufSize,
2481 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2482 LPBOUNDED_DWORD_256K lpServicesReturned,
2483 LPBOUNDED_DWORD_256K lpResumeHandle)
2484 {
2485 PMANAGER_HANDLE hManager;
2486 PSERVICE lpService;
2487 DWORD dwError = ERROR_SUCCESS;
2488 PLIST_ENTRY ServiceEntry;
2489 PSERVICE CurrentService;
2490 DWORD dwState;
2491 DWORD dwRequiredSize;
2492 DWORD dwServiceCount;
2493 DWORD dwSize;
2494 DWORD dwLastResumeCount = 0;
2495 LPENUM_SERVICE_STATUSW lpStatusPtr;
2496 LPWSTR lpStringPtr;
2497
2498 DPRINT("REnumServicesStatusW() called\n");
2499
2500 if (ScmShutdown)
2501 return ERROR_SHUTDOWN_IN_PROGRESS;
2502
2503 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2504 if (hManager == NULL)
2505 {
2506 DPRINT1("Invalid service manager handle!\n");
2507 return ERROR_INVALID_HANDLE;
2508 }
2509
2510
2511 *pcbBytesNeeded = 0;
2512 *lpServicesReturned = 0;
2513
2514 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
2515 {
2516 DPRINT("Not a valid Service Type!\n");
2517 return ERROR_INVALID_PARAMETER;
2518 }
2519
2520 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
2521 {
2522 DPRINT("Not a valid Service State!\n");
2523 return ERROR_INVALID_PARAMETER;
2524 }
2525
2526 /* Check access rights */
2527 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2528 SC_MANAGER_ENUMERATE_SERVICE))
2529 {
2530 DPRINT("Insufficient access rights! 0x%lx\n",
2531 hManager->Handle.DesiredAccess);
2532 return ERROR_ACCESS_DENIED;
2533 }
2534
2535 if (lpResumeHandle)
2536 dwLastResumeCount = *lpResumeHandle;
2537
2538 /* Lock the service database shared */
2539 ScmLockDatabaseShared();
2540
2541 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2542 if (lpService == NULL)
2543 {
2544 dwError = ERROR_SUCCESS;
2545 goto Done;
2546 }
2547
2548 dwRequiredSize = 0;
2549 dwServiceCount = 0;
2550
2551 for (ServiceEntry = &lpService->ServiceListEntry;
2552 ServiceEntry != &ServiceListHead;
2553 ServiceEntry = ServiceEntry->Flink)
2554 {
2555 CurrentService = CONTAINING_RECORD(ServiceEntry,
2556 SERVICE,
2557 ServiceListEntry);
2558
2559 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2560 continue;
2561
2562 dwState = SERVICE_ACTIVE;
2563 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2564 dwState = SERVICE_INACTIVE;
2565
2566 if ((dwState & dwServiceState) == 0)
2567 continue;
2568
2569 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2570 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2571 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2572
2573 if (dwRequiredSize + dwSize > dwBufSize)
2574 {
2575 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2576 break;
2577 }
2578
2579 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2580 dwRequiredSize += dwSize;
2581 dwServiceCount++;
2582 dwLastResumeCount = CurrentService->dwResumeCount;
2583 }
2584
2585 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2586 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2587
2588 for (;
2589 ServiceEntry != &ServiceListHead;
2590 ServiceEntry = ServiceEntry->Flink)
2591 {
2592 CurrentService = CONTAINING_RECORD(ServiceEntry,
2593 SERVICE,
2594 ServiceListEntry);
2595
2596 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2597 continue;
2598
2599 dwState = SERVICE_ACTIVE;
2600 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2601 dwState = SERVICE_INACTIVE;
2602
2603 if ((dwState & dwServiceState) == 0)
2604 continue;
2605
2606 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2607 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2608 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2609
2610 dwError = ERROR_MORE_DATA;
2611 }
2612
2613 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2614
2615 if (lpResumeHandle)
2616 *lpResumeHandle = dwLastResumeCount;
2617
2618 *lpServicesReturned = dwServiceCount;
2619 *pcbBytesNeeded = dwRequiredSize;
2620
2621 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2622 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2623 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2624
2625 dwRequiredSize = 0;
2626 for (ServiceEntry = &lpService->ServiceListEntry;
2627 ServiceEntry != &ServiceListHead;
2628 ServiceEntry = ServiceEntry->Flink)
2629 {
2630 CurrentService = CONTAINING_RECORD(ServiceEntry,
2631 SERVICE,
2632 ServiceListEntry);
2633
2634 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2635 continue;
2636
2637 dwState = SERVICE_ACTIVE;
2638 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2639 dwState = SERVICE_INACTIVE;
2640
2641 if ((dwState & dwServiceState) == 0)
2642 continue;
2643
2644 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2645 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2646 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2647
2648 if (dwRequiredSize + dwSize > dwBufSize)
2649 break;
2650
2651 /* Copy the service name */
2652 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2653 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2654 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2655
2656 /* Copy the display name */
2657 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2658 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2659 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2660
2661 /* Copy the status information */
2662 memcpy(&lpStatusPtr->ServiceStatus,
2663 &CurrentService->Status,
2664 sizeof(SERVICE_STATUS));
2665
2666 lpStatusPtr++;
2667 dwRequiredSize += dwSize;
2668 }
2669
2670 if (dwError == 0)
2671 {
2672 *pcbBytesNeeded = 0;
2673 if (lpResumeHandle) *lpResumeHandle = 0;
2674 }
2675
2676 Done:;
2677 /* Unlock the service database */
2678 ScmUnlockDatabase();
2679
2680 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2681
2682 return dwError;
2683 }
2684
2685
2686 /* Function 15 */
2687 DWORD ROpenSCManagerW(
2688 LPWSTR lpMachineName,
2689 LPWSTR lpDatabaseName,
2690 DWORD dwDesiredAccess,
2691 LPSC_RPC_HANDLE lpScHandle)
2692 {
2693 DWORD dwError;
2694 SC_HANDLE hHandle;
2695
2696 DPRINT("ROpenSCManagerW() called\n");
2697 DPRINT("lpMachineName = %p\n", lpMachineName);
2698 DPRINT("lpMachineName: %S\n", lpMachineName);
2699 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2700 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2701 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2702
2703 if (ScmShutdown)
2704 return ERROR_SHUTDOWN_IN_PROGRESS;
2705
2706 if (!lpScHandle)
2707 return ERROR_INVALID_PARAMETER;
2708
2709 dwError = ScmCreateManagerHandle(lpDatabaseName,
2710 &hHandle);
2711 if (dwError != ERROR_SUCCESS)
2712 {
2713 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2714 return dwError;
2715 }
2716
2717 /* Check the desired access */
2718 dwError = ScmCheckAccess(hHandle,
2719 dwDesiredAccess | SC_MANAGER_CONNECT);
2720 if (dwError != ERROR_SUCCESS)
2721 {
2722 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2723 HeapFree(GetProcessHeap(), 0, hHandle);
2724 return dwError;
2725 }
2726
2727 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2728 DPRINT("*hScm = %p\n", *lpScHandle);
2729
2730 DPRINT("ROpenSCManagerW() done\n");
2731
2732 return ERROR_SUCCESS;
2733 }
2734
2735
2736 /* Function 16 */
2737 DWORD ROpenServiceW(
2738 SC_RPC_HANDLE hSCManager,
2739 LPWSTR lpServiceName,
2740 DWORD dwDesiredAccess,
2741 LPSC_RPC_HANDLE lpServiceHandle)
2742 {
2743 PSERVICE lpService;
2744 PMANAGER_HANDLE hManager;
2745 SC_HANDLE hHandle;
2746 DWORD dwError = ERROR_SUCCESS;
2747
2748 DPRINT("ROpenServiceW() called\n");
2749 DPRINT("hSCManager = %p\n", hSCManager);
2750 DPRINT("lpServiceName = %p\n", lpServiceName);
2751 DPRINT("lpServiceName: %S\n", lpServiceName);
2752 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2753
2754 if (ScmShutdown)
2755 return ERROR_SHUTDOWN_IN_PROGRESS;
2756
2757 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2758 if (hManager == NULL)
2759 {
2760 DPRINT1("Invalid service manager handle!\n");
2761 return ERROR_INVALID_HANDLE;
2762 }
2763
2764 if (!lpServiceHandle)
2765 return ERROR_INVALID_PARAMETER;
2766
2767 if (!lpServiceName)
2768 return ERROR_INVALID_ADDRESS;
2769
2770 /* Lock the service database exclusive */
2771 ScmLockDatabaseExclusive();
2772
2773 /* Get service database entry */
2774 lpService = ScmGetServiceEntryByName(lpServiceName);
2775 if (lpService == NULL)
2776 {
2777 DPRINT("Could not find a service!\n");
2778 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2779 goto Done;
2780 }
2781
2782 /* Create a service handle */
2783 dwError = ScmCreateServiceHandle(lpService,
2784 &hHandle);
2785 if (dwError != ERROR_SUCCESS)
2786 {
2787 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2788 goto Done;
2789 }
2790
2791 /* Check the desired access */
2792 dwError = ScmCheckAccess(hHandle,
2793 dwDesiredAccess);
2794 if (dwError != ERROR_SUCCESS)
2795 {
2796 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2797 HeapFree(GetProcessHeap(), 0, hHandle);
2798 goto Done;
2799 }
2800
2801 lpService->dwRefCount++;
2802 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2803
2804 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2805 DPRINT("*hService = %p\n", *lpServiceHandle);
2806
2807 Done:;
2808 /* Unlock the service database */
2809 ScmUnlockDatabase();
2810
2811 DPRINT("ROpenServiceW() done\n");
2812
2813 return dwError;
2814 }
2815
2816
2817 /* Function 17 */
2818 DWORD RQueryServiceConfigW(
2819 SC_RPC_HANDLE hService,
2820 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2821 DWORD cbBufSize,
2822 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2823 {
2824 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2825 DWORD dwError = ERROR_SUCCESS;
2826 PSERVICE_HANDLE hSvc;
2827 PSERVICE lpService = NULL;
2828 HKEY hServiceKey = NULL;
2829 LPWSTR lpImagePath = NULL;
2830 LPWSTR lpServiceStartName = NULL;
2831 LPWSTR lpDependencies = NULL;
2832 DWORD dwDependenciesLength = 0;
2833 DWORD dwRequiredSize;
2834 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2835 WCHAR lpEmptyString[] = {0,0};
2836 LPWSTR lpStr;
2837
2838 DPRINT("RQueryServiceConfigW() called\n");
2839
2840 if (ScmShutdown)
2841 return ERROR_SHUTDOWN_IN_PROGRESS;
2842
2843 hSvc = ScmGetServiceFromHandle(hService);
2844 if (hSvc == NULL)
2845 {
2846 DPRINT1("Invalid service handle!\n");
2847 return ERROR_INVALID_HANDLE;
2848 }
2849
2850 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2851 SERVICE_QUERY_CONFIG))
2852 {
2853 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2854 return ERROR_ACCESS_DENIED;
2855 }
2856
2857 lpService = hSvc->ServiceEntry;
2858 if (lpService == NULL)
2859 {
2860 DPRINT("lpService == NULL!\n");
2861 return ERROR_INVALID_HANDLE;
2862 }
2863
2864 /* Lock the service database shared */
2865 ScmLockDatabaseShared();
2866
2867 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2868 KEY_READ,
2869 &hServiceKey);
2870 if (dwError != ERROR_SUCCESS)
2871 goto Done;
2872
2873 /* Read the image path */
2874 dwError = ScmReadString(hServiceKey,
2875 L"ImagePath",
2876 &lpImagePath);
2877 if (dwError != ERROR_SUCCESS)
2878 goto Done;
2879
2880 /* Read the service start name */
2881 ScmReadString(hServiceKey,
2882 L"ObjectName",
2883 &lpServiceStartName);
2884
2885 /* Read the dependencies */
2886 ScmReadDependencies(hServiceKey,
2887 &lpDependencies,
2888 &dwDependenciesLength);
2889
2890 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2891
2892 if (lpImagePath != NULL)
2893 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2894 else
2895 dwRequiredSize += 2 * sizeof(WCHAR);
2896
2897 if (lpService->lpGroup != NULL)
2898 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2899 else
2900 dwRequiredSize += 2 * sizeof(WCHAR);
2901
2902 if (lpDependencies != NULL)
2903 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2904 else
2905 dwRequiredSize += 2 * sizeof(WCHAR);
2906
2907 if (lpServiceStartName != NULL)
2908 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2909 else
2910 dwRequiredSize += 2 * sizeof(WCHAR);
2911
2912 if (lpService->lpDisplayName != NULL)
2913 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2914 else
2915 dwRequiredSize += 2 * sizeof(WCHAR);
2916
2917 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2918 {
2919 dwError = ERROR_INSUFFICIENT_BUFFER;
2920 }
2921 else
2922 {
2923 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2924 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2925 lpConfig->dwStartType = lpService->dwStartType;
2926 lpConfig->dwErrorControl = lpService->dwErrorControl;
2927 lpConfig->dwTagId = lpService->dwTag;
2928
2929 lpStr = (LPWSTR)(lpConfig + 1);
2930
2931 /* Append the image path */
2932 if (lpImagePath != NULL)
2933 {
2934 wcscpy(lpStr, lpImagePath);
2935 }
2936 else
2937 {
2938 wcscpy(lpStr, lpEmptyString);
2939 }
2940
2941 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2942 lpStr += (wcslen(lpStr) + 1);
2943
2944 /* Append the group name */
2945 if (lpService->lpGroup != NULL)
2946 {
2947 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2948 }
2949 else
2950 {
2951 wcscpy(lpStr, lpEmptyString);
2952 }
2953
2954 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2955 lpStr += (wcslen(lpStr) + 1);
2956
2957 /* Append Dependencies */
2958 if (lpDependencies != NULL)
2959 {
2960 memcpy(lpStr,
2961 lpDependencies,
2962 dwDependenciesLength * sizeof(WCHAR));
2963 }
2964 else
2965 {
2966 wcscpy(lpStr, lpEmptyString);
2967 }
2968
2969 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2970 if (lpDependencies != NULL)
2971 lpStr += dwDependenciesLength * sizeof(WCHAR);
2972 else
2973 lpStr += (wcslen(lpStr) + 1);
2974
2975 /* Append the service start name */
2976 if (lpServiceStartName != NULL)
2977 {
2978 wcscpy(lpStr, lpServiceStartName);
2979 }
2980 else
2981 {
2982 wcscpy(lpStr, lpEmptyString);
2983 }
2984
2985 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2986 lpStr += (wcslen(lpStr) + 1);
2987
2988 /* Append the display name */
2989 if (lpService->lpDisplayName != NULL)
2990 {
2991 wcscpy(lpStr, lpService->lpDisplayName);
2992 }
2993 else
2994 {
2995 wcscpy(lpStr, lpEmptyString);
2996 }
2997
2998 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2999 }
3000
3001 if (pcbBytesNeeded != NULL)
3002 *pcbBytesNeeded = dwRequiredSize;
3003
3004 Done:;
3005 /* Unlock the service database */
3006 ScmUnlockDatabase();
3007
3008 if (lpImagePath != NULL)
3009 HeapFree(GetProcessHeap(), 0, lpImagePath);
3010
3011 if (lpServiceStartName != NULL)
3012 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3013
3014 if (lpDependencies != NULL)
3015 HeapFree(GetProcessHeap(), 0, lpDependencies);
3016
3017 if (hServiceKey != NULL)
3018 RegCloseKey(hServiceKey);
3019
3020 DPRINT("RQueryServiceConfigW() done\n");
3021
3022 return dwError;
3023 }
3024
3025
3026 /* Function 18 */
3027 DWORD RQueryServiceLockStatusW(
3028 SC_RPC_HANDLE hSCManager,
3029 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3030 DWORD cbBufSize,
3031 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3032 {
3033 UNIMPLEMENTED;
3034 return ERROR_CALL_NOT_IMPLEMENTED;
3035 }
3036
3037
3038 /* Function 19 */
3039 DWORD RStartServiceW(
3040 SC_RPC_HANDLE hService,
3041 DWORD argc,
3042 LPSTRING_PTRSW argv)
3043 {
3044 DWORD dwError = ERROR_SUCCESS;
3045 PSERVICE_HANDLE hSvc;
3046 PSERVICE lpService = NULL;
3047 DWORD i;
3048
3049 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3050 DPRINT(" argc: %lu\n", argc);
3051 if (argv != NULL)
3052 {
3053 for (i = 0; i < argc; i++)
3054 {
3055 DPRINT(" argv[%lu]: %S\n", i, argv[i]);
3056 }
3057 }
3058
3059 if (ScmShutdown)
3060 return ERROR_SHUTDOWN_IN_PROGRESS;
3061
3062 hSvc = ScmGetServiceFromHandle(hService);
3063 if (hSvc == NULL)
3064 {
3065 DPRINT1("Invalid service handle!\n");
3066 return ERROR_INVALID_HANDLE;
3067 }
3068
3069 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3070 SERVICE_START))
3071 {
3072 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3073 return ERROR_ACCESS_DENIED;
3074 }
3075
3076 lpService = hSvc->ServiceEntry;
3077 if (lpService == NULL)
3078 {
3079 DPRINT("lpService == NULL!\n");
3080 return ERROR_INVALID_HANDLE;
3081 }
3082
3083 if (lpService->dwStartType == SERVICE_DISABLED)
3084 return ERROR_SERVICE_DISABLED;
3085
3086 if (lpService->bDeleted)
3087 return ERROR_SERVICE_MARKED_FOR_DELETE;
3088
3089 /* Start the service */
3090 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3091
3092 return dwError;
3093 }
3094
3095
3096 /* Function 20 */
3097 DWORD RGetServiceDisplayNameW(
3098 SC_RPC_HANDLE hSCManager,
3099 LPCWSTR lpServiceName,
3100 LPWSTR lpDisplayName,
3101 DWORD *lpcchBuffer)
3102 {
3103 // PMANAGER_HANDLE hManager;
3104 PSERVICE lpService;
3105 DWORD dwLength;
3106 DWORD dwError;
3107
3108 DPRINT("RGetServiceDisplayNameW() called\n");
3109 DPRINT("hSCManager = %p\n", hSCManager);
3110 DPRINT("lpServiceName: %S\n", lpServiceName);
3111 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3112 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3113
3114 // hManager = (PMANAGER_HANDLE)hSCManager;
3115 // if (hManager->Handle.Tag != MANAGER_TAG)
3116 // {
3117 // DPRINT("Invalid manager handle!\n");
3118 // return ERROR_INVALID_HANDLE;
3119 // }
3120
3121 /* Get service database entry */
3122 lpService = ScmGetServiceEntryByName(lpServiceName);
3123 if (lpService == NULL)
3124 {
3125 DPRINT("Could not find a service!\n");
3126
3127 /* If the service could not be found and lpcchBuffer is less than 2, windows
3128 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3129 if (*lpcchBuffer < 2)
3130 {
3131 *lpcchBuffer = 2;
3132 if (lpDisplayName != NULL)
3133 {
3134 *lpDisplayName = '\0';
3135 }
3136 }
3137
3138 return ERROR_SERVICE_DOES_NOT_EXIST;
3139 }
3140
3141 if (!lpService->lpDisplayName)
3142 {
3143 dwLength = wcslen(lpService->lpServiceName);
3144
3145 if (lpDisplayName != NULL &&
3146 *lpcchBuffer > dwLength)
3147 {
3148 wcscpy(lpDisplayName, lpService->lpServiceName);
3149 }
3150 }
3151 else
3152 {
3153 dwLength = wcslen(lpService->lpDisplayName);
3154
3155 if (lpDisplayName != NULL &&
3156 *lpcchBuffer > dwLength)
3157 {
3158 wcscpy(lpDisplayName, lpService->lpDisplayName);
3159 }
3160 }
3161
3162 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3163
3164 *lpcchBuffer = dwLength;
3165
3166 return dwError;
3167 }
3168
3169
3170 /* Function 21 */
3171 DWORD RGetServiceKeyNameW(
3172 SC_RPC_HANDLE hSCManager,
3173 LPCWSTR lpDisplayName,
3174 LPWSTR lpServiceName,
3175 DWORD *lpcchBuffer)
3176 {
3177 // PMANAGER_HANDLE hManager;
3178 PSERVICE lpService;
3179 DWORD dwLength;
3180 DWORD dwError;
3181
3182 DPRINT("RGetServiceKeyNameW() called\n");
3183 DPRINT("hSCManager = %p\n", hSCManager);
3184 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3185 DPRINT("lpServiceName: %p\n", lpServiceName);
3186 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3187
3188 // hManager = (PMANAGER_HANDLE)hSCManager;
3189 // if (hManager->Handle.Tag != MANAGER_TAG)
3190 // {
3191 // DPRINT("Invalid manager handle!\n");
3192 // return ERROR_INVALID_HANDLE;
3193 // }
3194
3195 /* Get service database entry */
3196 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3197 if (lpService == NULL)
3198 {
3199 DPRINT("Could not find a service!\n");
3200
3201 /* If the service could not be found and lpcchBuffer is less than 2, windows
3202 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3203 if (*lpcchBuffer < 2)
3204 {
3205 *lpcchBuffer = 2;
3206 if (lpServiceName != NULL)
3207 {
3208 *lpServiceName = '\0';
3209 }
3210 }
3211
3212 return ERROR_SERVICE_DOES_NOT_EXIST;
3213 }
3214
3215 dwLength = wcslen(lpService->lpServiceName);
3216
3217 if (lpServiceName != NULL &&
3218 *lpcchBuffer > dwLength)
3219 {
3220 wcscpy(lpServiceName, lpService->lpServiceName);
3221 *lpcchBuffer = dwLength;
3222 return ERROR_SUCCESS;
3223 }
3224
3225 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3226
3227 *lpcchBuffer = dwLength;
3228
3229 return dwError;
3230 }
3231
3232
3233 /* Function 22 */
3234 DWORD RI_ScSetServiceBitsA(
3235 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3236 DWORD dwServiceBits,
3237 int bSetBitsOn,
3238 int bUpdateImmediately,
3239 char *lpString)
3240 {
3241 UNIMPLEMENTED;
3242 return ERROR_CALL_NOT_IMPLEMENTED;
3243 }
3244
3245
3246 /* Function 23 */
3247 DWORD RChangeServiceConfigA(
3248 SC_RPC_HANDLE hService,
3249 DWORD dwServiceType,
3250 DWORD dwStartType,
3251 DWORD dwErrorControl,
3252 LPSTR lpBinaryPathName,
3253 LPSTR lpLoadOrderGroup,
3254 LPDWORD lpdwTagId,
3255 LPSTR lpDependencies,
3256 DWORD dwDependSize,
3257 LPSTR lpServiceStartName,
3258 LPBYTE lpPassword,
3259 DWORD dwPwSize,
3260 LPSTR lpDisplayName)
3261 {
3262 DWORD dwError = ERROR_SUCCESS;
3263 PSERVICE_HANDLE hSvc;
3264 PSERVICE lpService = NULL;
3265 HKEY hServiceKey = NULL;
3266 LPWSTR lpDisplayNameW = NULL;
3267 LPWSTR lpBinaryPathNameW = NULL;
3268 LPWSTR lpCanonicalImagePathW = NULL;
3269 LPWSTR lpLoadOrderGroupW = NULL;