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