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