[SERVICES] Use safe-string routines in some places, and do not hardcode buffer lengths.
[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
101 /* FUNCTIONS ***************************************************************/
102
103 VOID
104 ScmStartRpcServer(VOID)
105 {
106 RPC_STATUS Status;
107
108 DPRINT("ScmStartRpcServer() called\n");
109
110 Status = RpcServerUseProtseqEpW(L"ncacn_np",
111 10,
112 L"\\pipe\\ntsvcs",
113 NULL);
114 if (Status != RPC_S_OK)
115 {
116 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
117 return;
118 }
119
120 Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
121 NULL,
122 NULL);
123 if (Status != RPC_S_OK)
124 {
125 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
126 return;
127 }
128
129 Status = RpcServerListen(1, 20, TRUE);
130 if (Status != RPC_S_OK)
131 {
132 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
133 return;
134 }
135
136 DPRINT("ScmStartRpcServer() done\n");
137 }
138
139
140 static DWORD
141 ScmCreateManagerHandle(LPWSTR lpDatabaseName,
142 SC_HANDLE *Handle)
143 {
144 PMANAGER_HANDLE Ptr;
145
146 if (lpDatabaseName == NULL)
147 lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
148
149 if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
150 {
151 DPRINT("Database %S, does not exist\n", lpDatabaseName);
152 return ERROR_DATABASE_DOES_NOT_EXIST;
153 }
154 else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
155 {
156 DPRINT("Invalid Database name %S.\n", lpDatabaseName);
157 return ERROR_INVALID_NAME;
158 }
159
160 Ptr = HeapAlloc(GetProcessHeap(),
161 HEAP_ZERO_MEMORY,
162 FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1]));
163 if (Ptr == NULL)
164 return ERROR_NOT_ENOUGH_MEMORY;
165
166 Ptr->Handle.Tag = MANAGER_TAG;
167
168 wcscpy(Ptr->DatabaseName, lpDatabaseName);
169
170 *Handle = (SC_HANDLE)Ptr;
171
172 return ERROR_SUCCESS;
173 }
174
175
176 static DWORD
177 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
178 SC_HANDLE *Handle)
179 {
180 PSERVICE_HANDLE Ptr;
181
182 Ptr = HeapAlloc(GetProcessHeap(),
183 HEAP_ZERO_MEMORY,
184 sizeof(SERVICE_HANDLE));
185 if (Ptr == NULL)
186 return ERROR_NOT_ENOUGH_MEMORY;
187
188 Ptr->Handle.Tag = SERVICE_TAG;
189
190 Ptr->ServiceEntry = lpServiceEntry;
191
192 *Handle = (SC_HANDLE)Ptr;
193
194 return ERROR_SUCCESS;
195 }
196
197
198 static PMANAGER_HANDLE
199 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle)
200 {
201 PMANAGER_HANDLE pManager = NULL;
202
203 _SEH2_TRY
204 {
205 if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG)
206 pManager = (PMANAGER_HANDLE)Handle;
207 }
208 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
209 {
210 DPRINT1("Exception: Invalid Service Manager handle!\n");
211 }
212 _SEH2_END;
213
214 return pManager;
215 }
216
217
218 static PSERVICE_HANDLE
219 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle)
220 {
221 PSERVICE_HANDLE pService = NULL;
222
223 _SEH2_TRY
224 {
225 if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG)
226 pService = (PSERVICE_HANDLE)Handle;
227 }
228 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
229 {
230 DPRINT1("Exception: Invalid Service handle!\n");
231 }
232 _SEH2_END;
233
234 return pService;
235 }
236
237
238 static DWORD
239 ScmCheckAccess(SC_HANDLE Handle,
240 DWORD dwDesiredAccess)
241 {
242 PMANAGER_HANDLE hMgr;
243
244 hMgr = (PMANAGER_HANDLE)Handle;
245 if (hMgr->Handle.Tag == MANAGER_TAG)
246 {
247 RtlMapGenericMask(&dwDesiredAccess,
248 &ScmManagerMapping);
249
250 hMgr->Handle.DesiredAccess = dwDesiredAccess;
251
252 return ERROR_SUCCESS;
253 }
254 else if (hMgr->Handle.Tag == SERVICE_TAG)
255 {
256 RtlMapGenericMask(&dwDesiredAccess,
257 &ScmServiceMapping);
258
259 hMgr->Handle.DesiredAccess = dwDesiredAccess;
260
261 return ERROR_SUCCESS;
262 }
263
264 return ERROR_INVALID_HANDLE;
265 }
266
267
268 DWORD
269 ScmAssignNewTag(PSERVICE lpService)
270 {
271 HKEY hKey = NULL;
272 DWORD dwError;
273 DWORD dwGroupTagCount = 0;
274 PDWORD pdwGroupTags = NULL;
275 DWORD dwFreeTag = 0;
276 DWORD dwTagUsedBase = 1;
277 BOOLEAN TagUsed[TAG_ARRAY_SIZE];
278 INT nTagOffset;
279 DWORD i;
280 DWORD cbDataSize;
281 PLIST_ENTRY ServiceEntry;
282 PSERVICE CurrentService;
283
284 ASSERT(lpService != NULL);
285 ASSERT(lpService->lpGroup != NULL);
286
287 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
288 L"System\\CurrentControlSet\\Control\\GroupOrderList",
289 0,
290 KEY_READ,
291 &hKey);
292
293 if (dwError != ERROR_SUCCESS)
294 goto findFreeTag;
295
296 /* query value length */
297 cbDataSize = 0;
298 dwError = RegQueryValueExW(hKey,
299 lpService->lpGroup->szGroupName,
300 NULL,
301 NULL,
302 NULL,
303 &cbDataSize);
304
305 if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA)
306 goto findFreeTag;
307
308 pdwGroupTags = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDataSize);
309 if (!pdwGroupTags)
310 {
311 dwError = ERROR_NOT_ENOUGH_MEMORY;
312 goto cleanup;
313 }
314
315 dwError = RegQueryValueExW(hKey,
316 lpService->lpGroup->szGroupName,
317 NULL,
318 NULL,
319 (LPBYTE)pdwGroupTags,
320 &cbDataSize);
321
322 if (dwError != ERROR_SUCCESS)
323 goto findFreeTag;
324
325 if (cbDataSize < sizeof(pdwGroupTags[0]))
326 goto findFreeTag;
327
328 dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1);
329
330 findFreeTag:
331 do
332 {
333 /* mark all tags as unused */
334 for (i = 0; i < TAG_ARRAY_SIZE; i++)
335 TagUsed[i] = FALSE;
336
337 /* mark tags in GroupOrderList as used */
338 for (i = 1; i <= dwGroupTagCount; i++)
339 {
340 nTagOffset = pdwGroupTags[i] - dwTagUsedBase;
341 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
342 TagUsed[nTagOffset] = TRUE;
343 }
344
345 /* mark tags in service list as used */
346 ServiceEntry = lpService->ServiceListEntry.Flink;
347 while (ServiceEntry != &lpService->ServiceListEntry)
348 {
349 ASSERT(ServiceEntry != NULL);
350 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
351 if (CurrentService->lpGroup == lpService->lpGroup)
352 {
353 nTagOffset = CurrentService->dwTag - dwTagUsedBase;
354 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
355 TagUsed[nTagOffset] = TRUE;
356 }
357
358 ServiceEntry = ServiceEntry->Flink;
359 }
360
361 /* find unused tag, if any */
362 for (i = 0; i < TAG_ARRAY_SIZE; i++)
363 {
364 if (!TagUsed[i])
365 {
366 dwFreeTag = dwTagUsedBase + i;
367 break;
368 }
369 }
370
371 dwTagUsedBase += TAG_ARRAY_SIZE;
372 } while (!dwFreeTag);
373
374 cleanup:
375 if (pdwGroupTags)
376 HeapFree(GetProcessHeap(), 0, pdwGroupTags);
377
378 if (hKey)
379 RegCloseKey(hKey);
380
381 if (dwFreeTag)
382 {
383 lpService->dwTag = dwFreeTag;
384 DPRINT("Assigning new tag %lu to service %S in group %S\n",
385 lpService->dwTag, lpService->lpServiceName, lpService->lpGroup->szGroupName);
386 dwError = ERROR_SUCCESS;
387 }
388 else
389 {
390 DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
391 lpService->lpServiceName, dwError);
392 }
393
394 return dwError;
395 }
396
397
398 /* Create a path suitable for the bootloader out of the full path */
399 DWORD
400 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
401 {
402 SIZE_T ServiceNameLen, ExpandedLen;
403 DWORD BufferSize;
404 WCHAR Dest;
405 WCHAR *Expanded;
406 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
407 OBJECT_ATTRIBUTES ObjectAttributes;
408 NTSTATUS Status;
409 HANDLE SymbolicLinkHandle;
410
411 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
412
413 if (!RelativeName)
414 return ERROR_INVALID_PARAMETER;
415
416 *RelativeName = NULL;
417
418 ServiceNameLen = wcslen(CanonName);
419
420 /* First check, if it's already good */
421 if (ServiceNameLen > 12 &&
422 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
423 {
424 *RelativeName = HeapAlloc(GetProcessHeap(),
425 HEAP_ZERO_MEMORY,
426 (ServiceNameLen + 1) * sizeof(WCHAR));
427 if (*RelativeName == NULL)
428 {
429 DPRINT("Error allocating memory for boot driver name!\n");
430 return ERROR_NOT_ENOUGH_MEMORY;
431 }
432
433 /* Copy it */
434 wcscpy(*RelativeName, CanonName);
435
436 DPRINT("Bootdriver name %S\n", *RelativeName);
437 return ERROR_SUCCESS;
438 }
439
440 /* If it has %SystemRoot% prefix, substitute it to \System*/
441 if (ServiceNameLen > 13 &&
442 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
443 {
444 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
445 *RelativeName = HeapAlloc(GetProcessHeap(),
446 HEAP_ZERO_MEMORY,
447 ServiceNameLen * sizeof(WCHAR));
448
449 if (*RelativeName == NULL)
450 {
451 DPRINT("Error allocating memory for boot driver name!\n");
452 return ERROR_NOT_ENOUGH_MEMORY;
453 }
454
455 /* Copy it */
456 wcscpy(*RelativeName, L"\\SystemRoot\\");
457 wcscat(*RelativeName, CanonName + 13);
458
459 DPRINT("Bootdriver name %S\n", *RelativeName);
460 return ERROR_SUCCESS;
461 }
462
463 /* Get buffer size needed for expanding env strings */
464 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
465
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 DesiredAccess = SERVICE_PAUSE_CONTINUE;
1116 break;
1117
1118 case SERVICE_CONTROL_INTERROGATE:
1119 DesiredAccess = SERVICE_INTERROGATE;
1120 break;
1121
1122 default:
1123 if (dwControl >= 128 && dwControl <= 255)
1124 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
1125 else
1126 return ERROR_INVALID_PARAMETER;
1127 break;
1128 }
1129
1130 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1131 DesiredAccess))
1132 return ERROR_ACCESS_DENIED;
1133
1134 /* Return the current service status information */
1135 RtlCopyMemory(lpServiceStatus,
1136 &lpService->Status,
1137 sizeof(SERVICE_STATUS));
1138
1139 if (dwControl == SERVICE_CONTROL_STOP)
1140 {
1141 /* Check if the service has dependencies running as windows
1142 doesn't stop a service that does */
1143
1144 /* Open the Services Reg key */
1145 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1146 L"System\\CurrentControlSet\\Services",
1147 0,
1148 KEY_READ,
1149 &hServicesKey);
1150 if (dwError != ERROR_SUCCESS)
1151 {
1152 DPRINT("Failed to open services key\n");
1153 return dwError;
1154 }
1155
1156 /* Call the internal function with NULL, just to get bytes we need */
1157 Int_EnumDependentServicesW(hServicesKey,
1158 lpService,
1159 SERVICE_ACTIVE,
1160 NULL,
1161 &pcbBytesNeeded,
1162 &dwServicesReturned);
1163
1164 RegCloseKey(hServicesKey);
1165
1166 /* If pcbBytesNeeded is not zero then there are services running that
1167 are dependent on this service */
1168 if (pcbBytesNeeded != 0)
1169 {
1170 DPRINT("Service has running dependencies. Failed to stop service.\n");
1171 return ERROR_DEPENDENT_SERVICES_RUNNING;
1172 }
1173 }
1174
1175 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1176 {
1177 /* Send control code to the driver */
1178 dwError = ScmControlDriver(lpService,
1179 dwControl,
1180 lpServiceStatus);
1181 }
1182 else
1183 {
1184 dwControlsAccepted = lpService->Status.dwControlsAccepted;
1185 dwCurrentState = lpService->Status.dwCurrentState;
1186
1187 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1188 if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
1189 return ERROR_SERVICE_NOT_ACTIVE;
1190
1191 /* Check the current state before sending a control request */
1192 switch (dwCurrentState)
1193 {
1194 case SERVICE_STOP_PENDING:
1195 case SERVICE_STOPPED:
1196 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1197
1198 case SERVICE_START_PENDING:
1199 switch (dwControl)
1200 {
1201 case SERVICE_CONTROL_STOP:
1202 break;
1203
1204 case SERVICE_CONTROL_INTERROGATE:
1205 RtlCopyMemory(lpServiceStatus,
1206 &lpService->Status,
1207 sizeof(SERVICE_STATUS));
1208 return ERROR_SUCCESS;
1209
1210 default:
1211 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1212 }
1213 break;
1214 }
1215
1216 /* Check if the control code is acceptable to the service */
1217 switch (dwControl)
1218 {
1219 case SERVICE_CONTROL_STOP:
1220 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
1221 return ERROR_INVALID_SERVICE_CONTROL;
1222 break;
1223
1224 case SERVICE_CONTROL_PAUSE:
1225 case SERVICE_CONTROL_CONTINUE:
1226 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1227 return ERROR_INVALID_SERVICE_CONTROL;
1228 break;
1229 }
1230
1231 /* Send control code to the service */
1232 dwError = ScmControlService(lpService->lpImage->hControlPipe,
1233 lpService->lpServiceName,
1234 (SERVICE_STATUS_HANDLE)lpService,
1235 dwControl);
1236
1237 /* Return service status information */
1238 RtlCopyMemory(lpServiceStatus,
1239 &lpService->Status,
1240 sizeof(SERVICE_STATUS));
1241 }
1242
1243 if (dwError == ERROR_SUCCESS)
1244 {
1245 if (dwControl == SERVICE_CONTROL_STOP ||
1246 dwControl == SERVICE_CONTROL_PAUSE ||
1247 dwControl == SERVICE_CONTROL_CONTINUE)
1248 {
1249 /* Log a successful send control */
1250
1251 switch (dwControl)
1252 {
1253 case SERVICE_CONTROL_STOP:
1254 uID = IDS_SERVICE_STOP;
1255 break;
1256
1257 case SERVICE_CONTROL_PAUSE:
1258 uID = IDS_SERVICE_PAUSE;
1259 break;
1260
1261 case SERVICE_CONTROL_CONTINUE:
1262 uID = IDS_SERVICE_RESUME;
1263 break;
1264 }
1265 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1266
1267 lpLogStrings[0] = lpService->lpDisplayName;
1268 lpLogStrings[1] = szLogBuffer;
1269
1270 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
1271 EVENTLOG_INFORMATION_TYPE,
1272 2,
1273 lpLogStrings);
1274 }
1275 }
1276
1277 return dwError;
1278 }
1279
1280
1281 /* Function 2 */
1282 DWORD
1283 WINAPI
1284 RDeleteService(
1285 SC_RPC_HANDLE hService)
1286 {
1287 PSERVICE_HANDLE hSvc;
1288 PSERVICE lpService;
1289 DWORD dwError;
1290
1291 DPRINT("RDeleteService() called\n");
1292
1293 if (ScmShutdown)
1294 return ERROR_SHUTDOWN_IN_PROGRESS;
1295
1296 hSvc = ScmGetServiceFromHandle(hService);
1297 if (hSvc == NULL)
1298 {
1299 DPRINT1("Invalid service handle!\n");
1300 return ERROR_INVALID_HANDLE;
1301 }
1302
1303 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1304 DELETE))
1305 return ERROR_ACCESS_DENIED;
1306
1307 lpService = hSvc->ServiceEntry;
1308 if (lpService == NULL)
1309 {
1310 DPRINT("lpService == NULL!\n");
1311 return ERROR_INVALID_HANDLE;
1312 }
1313
1314 /* Lock the service database exclusively */
1315 ScmLockDatabaseExclusive();
1316
1317 if (lpService->bDeleted)
1318 {
1319 DPRINT("The service has already been marked for delete!\n");
1320 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1321 goto Done;
1322 }
1323
1324 /* Mark service for delete */
1325 lpService->bDeleted = TRUE;
1326
1327 dwError = ScmMarkServiceForDelete(lpService);
1328
1329 Done:
1330 /* Unlock the service database */
1331 ScmUnlockDatabase();
1332
1333 DPRINT("RDeleteService() done\n");
1334
1335 return dwError;
1336 }
1337
1338
1339 /* Function 3 */
1340 DWORD
1341 WINAPI
1342 RLockServiceDatabase(
1343 SC_RPC_HANDLE hSCManager,
1344 LPSC_RPC_LOCK lpLock)
1345 {
1346 PMANAGER_HANDLE hMgr;
1347
1348 DPRINT("RLockServiceDatabase() called\n");
1349
1350 *lpLock = NULL;
1351
1352 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
1353 if (hMgr == NULL)
1354 {
1355 DPRINT1("Invalid service manager handle!\n");
1356 return ERROR_INVALID_HANDLE;
1357 }
1358
1359 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
1360 SC_MANAGER_LOCK))
1361 return ERROR_ACCESS_DENIED;
1362
1363 return ScmAcquireServiceStartLock(FALSE, lpLock);
1364 }
1365
1366
1367 /* Function 4 */
1368 DWORD
1369 WINAPI
1370 RQueryServiceObjectSecurity(
1371 SC_RPC_HANDLE hService,
1372 SECURITY_INFORMATION dwSecurityInformation,
1373 LPBYTE lpSecurityDescriptor,
1374 DWORD cbBufSize,
1375 LPBOUNDED_DWORD_256K pcbBytesNeeded)
1376 {
1377 PSERVICE_HANDLE hSvc;
1378 PSERVICE lpService;
1379 ULONG DesiredAccess = 0;
1380 NTSTATUS Status;
1381 DWORD dwBytesNeeded;
1382 DWORD dwError;
1383
1384 DPRINT("RQueryServiceObjectSecurity() called\n");
1385
1386 hSvc = ScmGetServiceFromHandle(hService);
1387 if (hSvc == NULL)
1388 {
1389 DPRINT1("Invalid service handle!\n");
1390 return ERROR_INVALID_HANDLE;
1391 }
1392
1393 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1394 GROUP_SECURITY_INFORMATION |
1395 OWNER_SECURITY_INFORMATION))
1396 DesiredAccess |= READ_CONTROL;
1397
1398 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1399 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1400
1401 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1402 DesiredAccess))
1403 {
1404 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1405 return ERROR_ACCESS_DENIED;
1406 }
1407
1408 lpService = hSvc->ServiceEntry;
1409 if (lpService == NULL)
1410 {
1411 DPRINT("lpService == NULL!\n");
1412 return ERROR_INVALID_HANDLE;
1413 }
1414
1415 /* Lock the service database */
1416 ScmLockDatabaseShared();
1417
1418 /* Retrieve the security descriptor */
1419 Status = RtlQuerySecurityObject(lpService->pSecurityDescriptor,
1420 dwSecurityInformation,
1421 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1422 cbBufSize,
1423 &dwBytesNeeded);
1424
1425 /* Unlock the service database */
1426 ScmUnlockDatabase();
1427
1428 if (NT_SUCCESS(Status))
1429 {
1430 *pcbBytesNeeded = dwBytesNeeded;
1431 dwError = STATUS_SUCCESS;
1432 }
1433 else if (Status == STATUS_BUFFER_TOO_SMALL)
1434 {
1435 *pcbBytesNeeded = dwBytesNeeded;
1436 dwError = ERROR_INSUFFICIENT_BUFFER;
1437 }
1438 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
1439 {
1440 dwError = ERROR_GEN_FAILURE;
1441 }
1442 else
1443 {
1444 dwError = RtlNtStatusToDosError(Status);
1445 }
1446
1447 return dwError;
1448 }
1449
1450
1451 /* Function 5 */
1452 DWORD
1453 WINAPI
1454 RSetServiceObjectSecurity(
1455 SC_RPC_HANDLE hService,
1456 DWORD dwSecurityInformation,
1457 LPBYTE lpSecurityDescriptor,
1458 DWORD dwSecurityDescriptorSize)
1459 {
1460 PSERVICE_HANDLE hSvc;
1461 PSERVICE lpService;
1462 ACCESS_MASK DesiredAccess = 0;
1463 HANDLE hToken = NULL;
1464 HKEY hServiceKey = NULL;
1465 BOOL bDatabaseLocked = FALSE;
1466 NTSTATUS Status;
1467 DWORD dwError;
1468
1469 DPRINT("RSetServiceObjectSecurity() called\n");
1470
1471 hSvc = ScmGetServiceFromHandle(hService);
1472 if (hSvc == NULL)
1473 {
1474 DPRINT1("Invalid service handle!\n");
1475 return ERROR_INVALID_HANDLE;
1476 }
1477
1478 if (dwSecurityInformation == 0 ||
1479 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1480 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
1481 return ERROR_INVALID_PARAMETER;
1482
1483 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1484 return ERROR_INVALID_PARAMETER;
1485
1486 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1487 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1488
1489 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1490 DesiredAccess |= WRITE_DAC;
1491
1492 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1493 DesiredAccess |= WRITE_OWNER;
1494
1495 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1496 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1497 return ERROR_INVALID_PARAMETER;
1498
1499 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1500 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1501 return ERROR_INVALID_PARAMETER;
1502
1503 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1504 DesiredAccess))
1505 {
1506 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1507 return ERROR_ACCESS_DENIED;
1508 }
1509
1510 lpService = hSvc->ServiceEntry;
1511 if (lpService == NULL)
1512 {
1513 DPRINT1("lpService == NULL!\n");
1514 return ERROR_INVALID_HANDLE;
1515 }
1516
1517 if (lpService->bDeleted)
1518 return ERROR_SERVICE_MARKED_FOR_DELETE;
1519
1520 #if 0
1521 RpcImpersonateClient(NULL);
1522
1523 Status = NtOpenThreadToken(NtCurrentThread(),
1524 8,
1525 TRUE,
1526 &hToken);
1527 if (!NT_SUCCESS(Status))
1528 return RtlNtStatusToDosError(Status);
1529
1530 RpcRevertToSelf();
1531 #endif
1532
1533 /* Build the new security descriptor */
1534 Status = RtlSetSecurityObject(dwSecurityInformation,
1535 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1536 &lpService->pSecurityDescriptor,
1537 &ScmServiceMapping,
1538 hToken);
1539 if (!NT_SUCCESS(Status))
1540 {
1541 dwError = RtlNtStatusToDosError(Status);
1542 goto Done;
1543 }
1544
1545 /* Lock the service database exclusive */
1546 ScmLockDatabaseExclusive();
1547 bDatabaseLocked = TRUE;
1548
1549 /* Open the service key */
1550 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1551 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
1552 &hServiceKey);
1553 if (dwError != ERROR_SUCCESS)
1554 goto Done;
1555
1556 /* Store the new security descriptor */
1557 dwError = ScmWriteSecurityDescriptor(hServiceKey,
1558 lpService->pSecurityDescriptor);
1559
1560 RegFlushKey(hServiceKey);
1561
1562 Done:
1563 if (hServiceKey != NULL)
1564 RegCloseKey(hServiceKey);
1565
1566 /* Unlock service database */
1567 if (bDatabaseLocked == TRUE)
1568 ScmUnlockDatabase();
1569
1570 if (hToken != NULL)
1571 NtClose(hToken);
1572
1573 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1574
1575 return dwError;
1576 }
1577
1578
1579 /* Function 6 */
1580 DWORD
1581 WINAPI
1582 RQueryServiceStatus(
1583 SC_RPC_HANDLE hService,
1584 LPSERVICE_STATUS lpServiceStatus)
1585 {
1586 PSERVICE_HANDLE hSvc;
1587 PSERVICE lpService;
1588
1589 DPRINT("RQueryServiceStatus() called\n");
1590
1591 if (ScmShutdown)
1592 return ERROR_SHUTDOWN_IN_PROGRESS;
1593
1594 hSvc = ScmGetServiceFromHandle(hService);
1595 if (hSvc == NULL)
1596 {
1597 DPRINT1("Invalid service handle!\n");
1598 return ERROR_INVALID_HANDLE;
1599 }
1600
1601 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1602 SERVICE_QUERY_STATUS))
1603 {
1604 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1605 return ERROR_ACCESS_DENIED;
1606 }
1607
1608 lpService = hSvc->ServiceEntry;
1609 if (lpService == NULL)
1610 {
1611 DPRINT("lpService == NULL!\n");
1612 return ERROR_INVALID_HANDLE;
1613 }
1614
1615 /* Lock the service database shared */
1616 ScmLockDatabaseShared();
1617
1618 /* Return service status information */
1619 RtlCopyMemory(lpServiceStatus,
1620 &lpService->Status,
1621 sizeof(SERVICE_STATUS));
1622
1623 /* Unlock the service database */
1624 ScmUnlockDatabase();
1625
1626 return ERROR_SUCCESS;
1627 }
1628
1629
1630 static BOOL
1631 ScmIsValidServiceState(DWORD dwCurrentState)
1632 {
1633 switch (dwCurrentState)
1634 {
1635 case SERVICE_STOPPED:
1636 case SERVICE_START_PENDING:
1637 case SERVICE_STOP_PENDING:
1638 case SERVICE_RUNNING:
1639 case SERVICE_CONTINUE_PENDING:
1640 case SERVICE_PAUSE_PENDING:
1641 case SERVICE_PAUSED:
1642 return TRUE;
1643
1644 default:
1645 return FALSE;
1646 }
1647 }
1648
1649
1650 /* Function 7 */
1651 DWORD
1652 WINAPI
1653 RSetServiceStatus(
1654 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1655 LPSERVICE_STATUS lpServiceStatus)
1656 {
1657 PSERVICE lpService;
1658 DWORD dwPreviousState;
1659 DWORD dwPreviousType;
1660 LPCWSTR lpLogStrings[2];
1661 WCHAR szLogBuffer[80];
1662 UINT uID;
1663
1664 DPRINT("RSetServiceStatus() called\n");
1665 DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1666 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
1667 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1668 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1669 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1670 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1671 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1672 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1673
1674 if (hServiceStatus == 0)
1675 {
1676 DPRINT("hServiceStatus == NULL!\n");
1677 return ERROR_INVALID_HANDLE;
1678 }
1679
1680 lpService = (PSERVICE)hServiceStatus;
1681
1682 /* Check current state */
1683 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1684 {
1685 DPRINT("Invalid service state!\n");
1686 return ERROR_INVALID_DATA;
1687 }
1688
1689 /* Check service type */
1690 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1691 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1692 {
1693 DPRINT("Invalid service type!\n");
1694 return ERROR_INVALID_DATA;
1695 }
1696
1697 /* Check accepted controls */
1698 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1699 {
1700 DPRINT("Invalid controls accepted!\n");
1701 return ERROR_INVALID_DATA;
1702 }
1703
1704 /* Set the wait hint and check point only if the service is in a pending state,
1705 otherwise they should be 0 */
1706 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1707 lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
1708 lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
1709 {
1710 lpServiceStatus->dwWaitHint = 0;
1711 lpServiceStatus->dwCheckPoint = 0;
1712 }
1713
1714 /* Lock the service database exclusively */
1715 ScmLockDatabaseExclusive();
1716
1717 /* Save the current service state */
1718 dwPreviousState = lpService->Status.dwCurrentState;
1719
1720 /* Save the current service type */
1721 dwPreviousType = lpService->Status.dwServiceType;
1722
1723 /* Update the service status */
1724 RtlCopyMemory(&lpService->Status,
1725 lpServiceStatus,
1726 sizeof(SERVICE_STATUS));
1727
1728 /* Restore the previous service type */
1729 lpService->Status.dwServiceType = dwPreviousType;
1730
1731 /* Handle a stopped service */
1732 if ((lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1733 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED))
1734 {
1735 /* Decrement the image run counter */
1736 lpService->lpImage->dwImageRunCount--;
1737
1738 /* If we just stopped the last running service... */
1739 if (lpService->lpImage->dwImageRunCount == 0)
1740 {
1741 /* Stop the dispatcher thread */
1742 ScmControlService(lpService->lpImage->hControlPipe,
1743 L"",
1744 (SERVICE_STATUS_HANDLE)lpService,
1745 SERVICE_CONTROL_STOP);
1746
1747 /* Remove the service image */
1748 ScmRemoveServiceImage(lpService->lpImage);
1749 lpService->lpImage = NULL;
1750 }
1751 }
1752
1753 /* Unlock the service database */
1754 ScmUnlockDatabase();
1755
1756 if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
1757 (dwPreviousState != SERVICE_STOPPED) &&
1758 (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS))
1759 {
1760 /* Log a failed service stop */
1761 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer),
1762 L"%lu", lpServiceStatus->dwWin32ExitCode);
1763 lpLogStrings[0] = lpService->lpDisplayName;
1764 lpLogStrings[1] = szLogBuffer;
1765
1766 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED,
1767 EVENTLOG_ERROR_TYPE,
1768 2,
1769 lpLogStrings);
1770 }
1771 else if (lpServiceStatus->dwCurrentState != dwPreviousState &&
1772 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1773 lpServiceStatus->dwCurrentState == SERVICE_RUNNING ||
1774 lpServiceStatus->dwCurrentState == SERVICE_PAUSED))
1775 {
1776 /* Log a successful service status change */
1777 switch(lpServiceStatus->dwCurrentState)
1778 {
1779 case SERVICE_STOPPED:
1780 uID = IDS_SERVICE_STOPPED;
1781 break;
1782
1783 case SERVICE_RUNNING:
1784 uID = IDS_SERVICE_RUNNING;
1785 break;
1786
1787 case SERVICE_PAUSED:
1788 uID = IDS_SERVICE_PAUSED;
1789 break;
1790 }
1791
1792 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1793 lpLogStrings[0] = lpService->lpDisplayName;
1794 lpLogStrings[1] = szLogBuffer;
1795
1796 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS,
1797 EVENTLOG_INFORMATION_TYPE,
1798 2,
1799 lpLogStrings);
1800 }
1801
1802 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1803 DPRINT("RSetServiceStatus() done\n");
1804
1805 return ERROR_SUCCESS;
1806 }
1807
1808
1809 /* Function 8 */
1810 DWORD
1811 WINAPI
1812 RUnlockServiceDatabase(
1813 LPSC_RPC_LOCK Lock)
1814 {
1815 DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1816 return ScmReleaseServiceStartLock(Lock);
1817 }
1818
1819
1820 /* Function 9 */
1821 DWORD
1822 WINAPI
1823 RNotifyBootConfigStatus(
1824 SVCCTL_HANDLEW lpMachineName,
1825 DWORD BootAcceptable)
1826 {
1827 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1828 return ERROR_SUCCESS;
1829
1830 // UNIMPLEMENTED;
1831 // return ERROR_CALL_NOT_IMPLEMENTED;
1832 }
1833
1834
1835 /* Function 10 */
1836 DWORD
1837 WINAPI
1838 RI_ScSetServiceBitsW(
1839 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1840 DWORD dwServiceBits,
1841 int bSetBitsOn,
1842 int bUpdateImmediately,
1843 wchar_t *lpString)
1844 {
1845 UNIMPLEMENTED;
1846 return ERROR_CALL_NOT_IMPLEMENTED;
1847 }
1848
1849
1850 /* Function 11 */
1851 DWORD
1852 WINAPI
1853 RChangeServiceConfigW(
1854 SC_RPC_HANDLE hService,
1855 DWORD dwServiceType,
1856 DWORD dwStartType,
1857 DWORD dwErrorControl,
1858 LPWSTR lpBinaryPathName,
1859 LPWSTR lpLoadOrderGroup,
1860 LPDWORD lpdwTagId,
1861 LPBYTE lpDependencies,
1862 DWORD dwDependSize,
1863 LPWSTR lpServiceStartName,
1864 LPBYTE lpPassword,
1865 DWORD dwPwSize,
1866 LPWSTR lpDisplayName)
1867 {
1868 DWORD dwError = ERROR_SUCCESS;
1869 PSERVICE_HANDLE hSvc;
1870 PSERVICE lpService = NULL;
1871 HKEY hServiceKey = NULL;
1872 LPWSTR lpDisplayNameW = NULL;
1873 LPWSTR lpImagePathW = NULL;
1874
1875 DPRINT("RChangeServiceConfigW() called\n");
1876 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
1877 DPRINT("dwStartType = %lu\n", dwStartType);
1878 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1879 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1880 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1881 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1882
1883 if (ScmShutdown)
1884 return ERROR_SHUTDOWN_IN_PROGRESS;
1885
1886 hSvc = ScmGetServiceFromHandle(hService);
1887 if (hSvc == NULL)
1888 {
1889 DPRINT1("Invalid service handle!\n");
1890 return ERROR_INVALID_HANDLE;
1891 }
1892
1893 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1894 SERVICE_CHANGE_CONFIG))
1895 {
1896 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1897 return ERROR_ACCESS_DENIED;
1898 }
1899
1900 /* Check for invalid service type value */
1901 if ((dwServiceType != SERVICE_NO_CHANGE) &&
1902 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
1903 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
1904 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
1905 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
1906 return ERROR_INVALID_PARAMETER;
1907
1908 /* Check for invalid start type value */
1909 if ((dwStartType != SERVICE_NO_CHANGE) &&
1910 (dwStartType != SERVICE_BOOT_START) &&
1911 (dwStartType != SERVICE_SYSTEM_START) &&
1912 (dwStartType != SERVICE_AUTO_START) &&
1913 (dwStartType != SERVICE_DEMAND_START) &&
1914 (dwStartType != SERVICE_DISABLED))
1915 return ERROR_INVALID_PARAMETER;
1916
1917 /* Only drivers can be boot start or system start services */
1918 if ((dwStartType == SERVICE_BOOT_START) ||
1919 (dwStartType == SERVICE_SYSTEM_START))
1920 {
1921 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
1922 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
1923 return ERROR_INVALID_PARAMETER;
1924 }
1925
1926 /* Check for invalid error control value */
1927 if ((dwErrorControl != SERVICE_NO_CHANGE) &&
1928 (dwErrorControl != SERVICE_ERROR_IGNORE) &&
1929 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
1930 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
1931 (dwErrorControl != SERVICE_ERROR_CRITICAL))
1932 return ERROR_INVALID_PARAMETER;
1933
1934 lpService = hSvc->ServiceEntry;
1935 if (lpService == NULL)
1936 {
1937 DPRINT("lpService == NULL!\n");
1938 return ERROR_INVALID_HANDLE;
1939 }
1940
1941 /* Lock the service database exclusively */
1942 ScmLockDatabaseExclusive();
1943
1944 if (lpService->bDeleted)
1945 {
1946 DPRINT("The service has already been marked for delete!\n");
1947 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1948 goto done;
1949 }
1950
1951 /* Open the service key */
1952 dwError = ScmOpenServiceKey(lpService->szServiceName,
1953 KEY_SET_VALUE,
1954 &hServiceKey);
1955 if (dwError != ERROR_SUCCESS)
1956 goto done;
1957
1958 /* Write service data to the registry */
1959 /* Set the display name */
1960 if (lpDisplayName != NULL && *lpDisplayName != 0)
1961 {
1962 RegSetValueExW(hServiceKey,
1963 L"DisplayName",
1964 0,
1965 REG_SZ,
1966 (LPBYTE)lpDisplayName,
1967 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
1968
1969 /* Update the display name */
1970 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
1971 HEAP_ZERO_MEMORY,
1972 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1973 if (lpDisplayNameW == NULL)
1974 {
1975 dwError = ERROR_NOT_ENOUGH_MEMORY;
1976 goto done;
1977 }
1978
1979 wcscpy(lpDisplayNameW, lpDisplayName);
1980 if (lpService->lpDisplayName != lpService->lpServiceName)
1981 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1982
1983 lpService->lpDisplayName = lpDisplayNameW;
1984 }
1985
1986 if (dwServiceType != SERVICE_NO_CHANGE)
1987 {
1988 /* Set the service type */
1989 dwError = RegSetValueExW(hServiceKey,
1990 L"Type",
1991 0,
1992 REG_DWORD,
1993 (LPBYTE)&dwServiceType,
1994 sizeof(DWORD));
1995 if (dwError != ERROR_SUCCESS)
1996 goto done;
1997
1998 lpService->Status.dwServiceType = dwServiceType;
1999 }
2000
2001 if (dwStartType != SERVICE_NO_CHANGE)
2002 {
2003 /* Set the start value */
2004 dwError = RegSetValueExW(hServiceKey,
2005 L"Start",
2006 0,
2007 REG_DWORD,
2008 (LPBYTE)&dwStartType,
2009 sizeof(DWORD));
2010 if (dwError != ERROR_SUCCESS)
2011 goto done;
2012
2013 lpService->dwStartType = dwStartType;
2014 }
2015
2016 if (dwErrorControl != SERVICE_NO_CHANGE)
2017 {
2018 /* Set the error control value */
2019 dwError = RegSetValueExW(hServiceKey,
2020 L"ErrorControl",
2021 0,
2022 REG_DWORD,
2023 (LPBYTE)&dwErrorControl,
2024 sizeof(DWORD));
2025 if (dwError != ERROR_SUCCESS)
2026 goto done;
2027
2028 lpService->dwErrorControl = dwErrorControl;
2029 }
2030
2031 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2032 {
2033 /* Set the image path */
2034 lpImagePathW = lpBinaryPathName;
2035
2036 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
2037 {
2038 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
2039 lpBinaryPathName,
2040 &lpImagePathW);
2041
2042 if (dwError != ERROR_SUCCESS)
2043 goto done;
2044 }
2045
2046 dwError = RegSetValueExW(hServiceKey,
2047 L"ImagePath",
2048 0,
2049 REG_EXPAND_SZ,
2050 (LPBYTE)lpImagePathW,
2051 (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
2052
2053 if (lpImagePathW != lpBinaryPathName)
2054 HeapFree(GetProcessHeap(), 0, lpImagePathW);
2055
2056 if (dwError != ERROR_SUCCESS)
2057 goto done;
2058 }
2059
2060 /* Set the group name */
2061 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2062 {
2063 dwError = RegSetValueExW(hServiceKey,
2064 L"Group",
2065 0,
2066 REG_SZ,
2067 (LPBYTE)lpLoadOrderGroup,
2068 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2069 if (dwError != ERROR_SUCCESS)
2070 goto done;
2071
2072 dwError = ScmSetServiceGroup(lpService,
2073 lpLoadOrderGroup);
2074 if (dwError != ERROR_SUCCESS)
2075 goto done;
2076 }
2077
2078 /* Set the tag */
2079 if (lpdwTagId != NULL)
2080 {
2081 dwError = ScmAssignNewTag(lpService);
2082 if (dwError != ERROR_SUCCESS)
2083 goto done;
2084
2085 dwError = RegSetValueExW(hServiceKey,
2086 L"Tag",
2087 0,
2088 REG_DWORD,
2089 (LPBYTE)&lpService->dwTag,
2090 sizeof(DWORD));
2091 if (dwError != ERROR_SUCCESS)
2092 goto done;
2093
2094 *lpdwTagId = lpService->dwTag;
2095 }
2096
2097 /* Write dependencies */
2098 if (lpDependencies != NULL && *lpDependencies != 0)
2099 {
2100 dwError = ScmWriteDependencies(hServiceKey,
2101 (LPWSTR)lpDependencies,
2102 dwDependSize);
2103 if (dwError != ERROR_SUCCESS)
2104 goto done;
2105 }
2106
2107 if (lpPassword != NULL)
2108 {
2109 if (wcslen((LPWSTR)lpPassword) != 0)
2110 {
2111 /* FIXME: Decrypt the password */
2112
2113 /* Write the password */
2114 dwError = ScmSetServicePassword(lpService->szServiceName,
2115 (LPCWSTR)lpPassword);
2116 if (dwError != ERROR_SUCCESS)
2117 goto done;
2118 }
2119 else
2120 {
2121 /* Delete the password */
2122 dwError = ScmSetServicePassword(lpService->szServiceName,
2123 NULL);
2124 if (dwError == ERROR_FILE_NOT_FOUND)
2125 dwError = ERROR_SUCCESS;
2126
2127 if (dwError != ERROR_SUCCESS)
2128 goto done;
2129 }
2130 }
2131
2132 done:
2133 if (hServiceKey != NULL)
2134 RegCloseKey(hServiceKey);
2135
2136 /* Unlock the service database */
2137 ScmUnlockDatabase();
2138
2139 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
2140
2141 return dwError;
2142 }
2143
2144
2145 /* Function 12 */
2146 DWORD
2147 WINAPI
2148 RCreateServiceW(
2149 SC_RPC_HANDLE hSCManager,
2150 LPCWSTR lpServiceName,
2151 LPCWSTR lpDisplayName,
2152 DWORD dwDesiredAccess,
2153 DWORD dwServiceType,
2154 DWORD dwStartType,
2155 DWORD dwErrorControl,
2156 LPCWSTR lpBinaryPathName,
2157 LPCWSTR lpLoadOrderGroup,
2158 LPDWORD lpdwTagId,
2159 LPBYTE lpDependencies,
2160 DWORD dwDependSize,
2161 LPCWSTR lpServiceStartName,
2162 LPBYTE lpPassword,
2163 DWORD dwPwSize,
2164 LPSC_RPC_HANDLE lpServiceHandle)
2165 {
2166 PMANAGER_HANDLE hManager;
2167 DWORD dwError = ERROR_SUCCESS;
2168 PSERVICE lpService = NULL;
2169 SC_HANDLE hServiceHandle = NULL;
2170 LPWSTR lpImagePath = NULL;
2171 HKEY hServiceKey = NULL;
2172 LPWSTR lpObjectName;
2173
2174 DPRINT("RCreateServiceW() called\n");
2175 DPRINT("lpServiceName = %S\n", lpServiceName);
2176 DPRINT("lpDisplayName = %S\n", lpDisplayName);
2177 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2178 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2179 DPRINT("dwStartType = %lu\n", dwStartType);
2180 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2181 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2182 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2183 DPRINT("lpdwTagId = %p\n", lpdwTagId);
2184
2185 if (ScmShutdown)
2186 return ERROR_SHUTDOWN_IN_PROGRESS;
2187
2188 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2189 if (hManager == NULL)
2190 {
2191 DPRINT1("Invalid service manager handle!\n");
2192 return ERROR_INVALID_HANDLE;
2193 }
2194
2195 /* Check access rights */
2196 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2197 SC_MANAGER_CREATE_SERVICE))
2198 {
2199 DPRINT("Insufficient access rights! 0x%lx\n",
2200 hManager->Handle.DesiredAccess);
2201 return ERROR_ACCESS_DENIED;
2202 }
2203
2204 if (wcslen(lpServiceName) == 0)
2205 {
2206 return ERROR_INVALID_NAME;
2207 }
2208
2209 if (wcslen(lpBinaryPathName) == 0)
2210 {
2211 return ERROR_INVALID_PARAMETER;
2212 }
2213
2214 /* Check for invalid service type value */
2215 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2216 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2217 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2218 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
2219 return ERROR_INVALID_PARAMETER;
2220
2221 /* Check for invalid start type value */
2222 if ((dwStartType != SERVICE_BOOT_START) &&
2223 (dwStartType != SERVICE_SYSTEM_START) &&
2224 (dwStartType != SERVICE_AUTO_START) &&
2225 (dwStartType != SERVICE_DEMAND_START) &&
2226 (dwStartType != SERVICE_DISABLED))
2227 return ERROR_INVALID_PARAMETER;
2228
2229 /* Only drivers can be boot start or system start services */
2230 if ((dwStartType == SERVICE_BOOT_START) ||
2231 (dwStartType == SERVICE_SYSTEM_START))
2232 {
2233 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2234 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2235 return ERROR_INVALID_PARAMETER;
2236 }
2237
2238 /* Check for invalid error control value */
2239 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2240 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2241 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2242 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2243 return ERROR_INVALID_PARAMETER;
2244
2245 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2246 (lpServiceStartName))
2247 {
2248 /* We allow LocalSystem to run interactive. */
2249 if (wcsicmp(lpServiceStartName, L"LocalSystem"))
2250 {
2251 return ERROR_INVALID_PARAMETER;
2252 }
2253 }
2254
2255 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2256 {
2257 return ERROR_INVALID_PARAMETER;
2258 }
2259
2260 /* Lock the service database exclusively */
2261 ScmLockDatabaseExclusive();
2262
2263 lpService = ScmGetServiceEntryByName(lpServiceName);
2264 if (lpService)
2265 {
2266 /* Unlock the service database */
2267 ScmUnlockDatabase();
2268
2269 /* Check if it is marked for deletion */
2270 if (lpService->bDeleted)
2271 return ERROR_SERVICE_MARKED_FOR_DELETE;
2272
2273 /* Return Error exist */
2274 return ERROR_SERVICE_EXISTS;
2275 }
2276
2277 if (lpDisplayName != NULL &&
2278 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2279 {
2280 /* Unlock the service database */
2281 ScmUnlockDatabase();
2282
2283 return ERROR_DUPLICATE_SERVICE_NAME;
2284 }
2285
2286 if (dwServiceType & SERVICE_DRIVER)
2287 {
2288 dwError = ScmCanonDriverImagePath(dwStartType,
2289 lpBinaryPathName,
2290 &lpImagePath);
2291 if (dwError != ERROR_SUCCESS)
2292 goto done;
2293 }
2294 else
2295 {
2296 if (dwStartType == SERVICE_BOOT_START ||
2297 dwStartType == SERVICE_SYSTEM_START)
2298 {
2299 /* Unlock the service database */
2300 ScmUnlockDatabase();
2301
2302 return ERROR_INVALID_PARAMETER;
2303 }
2304 }
2305
2306 /* Allocate a new service entry */
2307 dwError = ScmCreateNewServiceRecord(lpServiceName,
2308 &lpService,
2309 dwServiceType,
2310 dwStartType);
2311 if (dwError != ERROR_SUCCESS)
2312 goto done;
2313
2314 /* Fill the new service entry */
2315 lpService->dwErrorControl = dwErrorControl;
2316
2317 /* Fill the display name */
2318 if (lpDisplayName != NULL &&
2319 *lpDisplayName != 0 &&
2320 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2321 {
2322 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2323 HEAP_ZERO_MEMORY,
2324 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2325 if (lpService->lpDisplayName == NULL)
2326 {
2327 dwError = ERROR_NOT_ENOUGH_MEMORY;
2328 goto done;
2329 }
2330 wcscpy(lpService->lpDisplayName, lpDisplayName);
2331 }
2332
2333 /* Assign the service to a group */
2334 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2335 {
2336 dwError = ScmSetServiceGroup(lpService,
2337 lpLoadOrderGroup);
2338 if (dwError != ERROR_SUCCESS)
2339 goto done;
2340 }
2341
2342 /* Assign a new tag */
2343 if (lpdwTagId != NULL)
2344 {
2345 dwError = ScmAssignNewTag(lpService);
2346 if (dwError != ERROR_SUCCESS)
2347 goto done;
2348 }
2349
2350 /* Assign the default security descriptor */
2351 if (dwServiceType & SERVICE_WIN32)
2352 {
2353 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
2354 if (dwError != ERROR_SUCCESS)
2355 goto done;
2356 }
2357
2358 /* Write service data to the registry */
2359 /* Create the service key */
2360 dwError = ScmCreateServiceKey(lpServiceName,
2361 KEY_WRITE,
2362 &hServiceKey);
2363 if (dwError != ERROR_SUCCESS)
2364 goto done;
2365
2366 /* Set the display name */
2367 if (lpDisplayName != NULL && *lpDisplayName != 0)
2368 {
2369 RegSetValueExW(hServiceKey,
2370 L"DisplayName",
2371 0,
2372 REG_SZ,
2373 (LPBYTE)lpDisplayName,
2374 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2375 }
2376
2377 /* Set the service type */
2378 dwError = RegSetValueExW(hServiceKey,
2379 L"Type",
2380 0,
2381 REG_DWORD,
2382 (LPBYTE)&dwServiceType,
2383 sizeof(DWORD));
2384 if (dwError != ERROR_SUCCESS)
2385 goto done;
2386
2387 /* Set the start value */
2388 dwError = RegSetValueExW(hServiceKey,
2389 L"Start",
2390 0,
2391 REG_DWORD,
2392 (LPBYTE)&dwStartType,
2393 sizeof(DWORD));
2394 if (dwError != ERROR_SUCCESS)
2395 goto done;
2396
2397 /* Set the error control value */
2398 dwError = RegSetValueExW(hServiceKey,
2399 L"ErrorControl",
2400 0,
2401 REG_DWORD,
2402 (LPBYTE)&dwErrorControl,
2403 sizeof(DWORD));
2404 if (dwError != ERROR_SUCCESS)
2405 goto done;
2406
2407 /* Set the image path */
2408 if (dwServiceType & SERVICE_WIN32)
2409 {
2410 dwError = RegSetValueExW(hServiceKey,
2411 L"ImagePath",
2412 0,
2413 REG_EXPAND_SZ,
2414 (LPBYTE)lpBinaryPathName,
2415 (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2416 if (dwError != ERROR_SUCCESS)
2417 goto done;
2418 }
2419 else if (dwServiceType & SERVICE_DRIVER)
2420 {
2421 dwError = RegSetValueExW(hServiceKey,
2422 L"ImagePath",
2423 0,
2424 REG_EXPAND_SZ,
2425 (LPBYTE)lpImagePath,
2426 (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2427 if (dwError != ERROR_SUCCESS)
2428 goto done;
2429 }
2430
2431 /* Set the group name */
2432 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2433 {
2434 dwError = RegSetValueExW(hServiceKey,
2435 L"Group",
2436 0,
2437 REG_SZ,
2438 (LPBYTE)lpLoadOrderGroup,
2439 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2440 if (dwError != ERROR_SUCCESS)
2441 goto done;
2442 }
2443
2444 /* Set the service tag */
2445 if (lpdwTagId != NULL)
2446 {
2447 dwError = RegSetValueExW(hServiceKey,
2448 L"Tag",
2449 0,
2450 REG_DWORD,
2451 (LPBYTE)&lpService->dwTag,
2452 sizeof(DWORD));
2453 if (dwError != ERROR_SUCCESS)
2454 goto done;
2455 }
2456
2457 /* Write dependencies */
2458 if (lpDependencies != NULL && *lpDependencies != 0)
2459 {
2460 dwError = ScmWriteDependencies(hServiceKey,
2461 (LPCWSTR)lpDependencies,
2462 dwDependSize);
2463 if (dwError != ERROR_SUCCESS)
2464 goto done;
2465 }
2466
2467 /* Start name and password are only used by Win32 services */
2468 if (dwServiceType & SERVICE_WIN32)
2469 {
2470 /* Write service start name */
2471 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2472 dwError = RegSetValueExW(hServiceKey,
2473 L"ObjectName",
2474 0,
2475 REG_SZ,
2476 (LPBYTE)lpObjectName,
2477 (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2478 if (dwError != ERROR_SUCCESS)
2479 goto done;
2480
2481 if (lpPassword != NULL && wcslen((LPWSTR)lpPassword) != 0)
2482 {
2483 /* FIXME: Decrypt the password */
2484
2485 /* Write the password */
2486 dwError = ScmSetServicePassword(lpServiceName,
2487 (LPCWSTR)lpPassword);
2488 if (dwError != ERROR_SUCCESS)
2489 goto done;
2490 }
2491
2492 DPRINT1("\n");
2493 /* Write the security descriptor */
2494 dwError = ScmWriteSecurityDescriptor(hServiceKey,
2495 lpService->pSecurityDescriptor);
2496 if (dwError != ERROR_SUCCESS)
2497 goto done;
2498 }
2499
2500 dwError = ScmCreateServiceHandle(lpService,
2501 &hServiceHandle);
2502 if (dwError != ERROR_SUCCESS)
2503 goto done;
2504
2505 dwError = ScmCheckAccess(hServiceHandle,
2506 dwDesiredAccess);
2507 if (dwError != ERROR_SUCCESS)
2508 goto done;
2509
2510 lpService->dwRefCount = 1;
2511 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2512
2513 done:
2514 /* Unlock the service database */
2515 ScmUnlockDatabase();
2516
2517 if (hServiceKey != NULL)
2518 RegCloseKey(hServiceKey);
2519
2520 if (dwError == ERROR_SUCCESS)
2521 {
2522 DPRINT("hService %p\n", hServiceHandle);
2523 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2524
2525 if (lpdwTagId != NULL)
2526 *lpdwTagId = lpService->dwTag;
2527 }
2528 else
2529 {
2530 if (lpService != NULL &&
2531 lpService->lpServiceName != NULL)
2532 {
2533 /* Release the display name buffer */
2534 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2535 }
2536
2537 if (hServiceHandle)
2538 {
2539 /* Remove the service handle */
2540 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2541 }
2542
2543 if (lpService != NULL)
2544 {
2545 /* FIXME: remove the service entry */
2546 }
2547 }
2548
2549 if (lpImagePath != NULL)
2550 HeapFree(GetProcessHeap(), 0, lpImagePath);
2551
2552 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2553
2554 return dwError;
2555 }
2556
2557
2558 /* Function 13 */
2559 DWORD
2560 WINAPI
2561 REnumDependentServicesW(
2562 SC_RPC_HANDLE hService,
2563 DWORD dwServiceState,
2564 LPBYTE lpServices,
2565 DWORD cbBufSize,
2566 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2567 LPBOUNDED_DWORD_256K lpServicesReturned)
2568 {
2569 DWORD dwError = ERROR_SUCCESS;
2570 DWORD dwServicesReturned = 0;
2571 DWORD dwServiceCount;
2572 HKEY hServicesKey = NULL;
2573 PSERVICE_HANDLE hSvc;
2574 PSERVICE lpService = NULL;
2575 PSERVICE *lpServicesArray = NULL;
2576 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2577 LPWSTR lpStr;
2578
2579 *pcbBytesNeeded = 0;
2580 *lpServicesReturned = 0;
2581
2582 DPRINT("REnumDependentServicesW() called\n");
2583
2584 hSvc = ScmGetServiceFromHandle(hService);
2585 if (hSvc == NULL)
2586 {
2587 DPRINT1("Invalid service handle!\n");
2588 return ERROR_INVALID_HANDLE;
2589 }
2590
2591 lpService = hSvc->ServiceEntry;
2592
2593 /* Check access rights */
2594 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2595 SC_MANAGER_ENUMERATE_SERVICE))
2596 {
2597 DPRINT("Insufficient access rights! 0x%lx\n",
2598 hSvc->Handle.DesiredAccess);
2599 return ERROR_ACCESS_DENIED;
2600 }
2601
2602 /* Open the Services Reg key */
2603 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2604 L"System\\CurrentControlSet\\Services",
2605 0,
2606 KEY_READ,
2607 &hServicesKey);
2608 if (dwError != ERROR_SUCCESS)
2609 return dwError;
2610
2611 /* First determine the bytes needed and get the number of dependent services */
2612 dwError = Int_EnumDependentServicesW(hServicesKey,
2613 lpService,
2614 dwServiceState,
2615 NULL,
2616 pcbBytesNeeded,
2617 &dwServicesReturned);
2618 if (dwError != ERROR_SUCCESS)
2619 goto Done;
2620
2621 /* If buffer size is less than the bytes needed or pointer is null */
2622 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2623 {
2624 dwError = ERROR_MORE_DATA;
2625 goto Done;
2626 }
2627
2628 /* Allocate memory for array of service pointers */
2629 lpServicesArray = HeapAlloc(GetProcessHeap(),
2630 HEAP_ZERO_MEMORY,
2631 (dwServicesReturned + 1) * sizeof(PSERVICE));
2632 if (!lpServicesArray)
2633 {
2634 DPRINT1("Could not allocate a buffer!!\n");
2635 dwError = ERROR_NOT_ENOUGH_MEMORY;
2636 goto Done;
2637 }
2638
2639 dwServicesReturned = 0;
2640 *pcbBytesNeeded = 0;
2641
2642 dwError = Int_EnumDependentServicesW(hServicesKey,
2643 lpService,
2644 dwServiceState,
2645 lpServicesArray,
2646 pcbBytesNeeded,
2647 &dwServicesReturned);
2648 if (dwError != ERROR_SUCCESS)
2649 {
2650 goto Done;
2651 }
2652
2653 lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2654 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2655
2656 /* Copy EnumDepenedentService to Buffer */
2657 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2658 {
2659 lpService = lpServicesArray[dwServiceCount];
2660
2661 /* Copy status info */
2662 memcpy(&lpServicesPtr->ServiceStatus,
2663 &lpService->Status,
2664 sizeof(SERVICE_STATUS));
2665
2666 /* Copy display name */
2667 wcscpy(lpStr, lpService->lpDisplayName);
2668 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2669 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2670
2671 /* Copy service name */
2672 wcscpy(lpStr, lpService->lpServiceName);
2673 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2674 lpStr += (wcslen(lpService->lpServiceName) + 1);
2675
2676 lpServicesPtr++;
2677 }
2678
2679 *lpServicesReturned = dwServicesReturned;
2680
2681 Done:
2682 if (lpServicesArray != NULL)
2683 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2684
2685 RegCloseKey(hServicesKey);
2686
2687 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2688
2689 return dwError;
2690 }
2691
2692
2693 /* Function 14 */
2694 DWORD
2695 WINAPI
2696 REnumServicesStatusW(
2697 SC_RPC_HANDLE hSCManager,
2698 DWORD dwServiceType,
2699 DWORD dwServiceState,
2700 LPBYTE lpBuffer,
2701 DWORD dwBufSize,
2702 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2703 LPBOUNDED_DWORD_256K lpServicesReturned,
2704 LPBOUNDED_DWORD_256K lpResumeHandle)
2705 {
2706 /* Enumerate all the services, not regarding of their group */
2707 return REnumServiceGroupW(hSCManager,
2708 dwServiceType,
2709 dwServiceState,
2710 lpBuffer,
2711 dwBufSize,
2712 pcbBytesNeeded,
2713 lpServicesReturned,
2714 lpResumeHandle,
2715 NULL);
2716 }
2717
2718
2719 /* Function 15 */
2720 DWORD
2721 WINAPI
2722 ROpenSCManagerW(
2723 LPWSTR lpMachineName,
2724 LPWSTR lpDatabaseName,
2725 DWORD dwDesiredAccess,
2726 LPSC_RPC_HANDLE lpScHandle)
2727 {
2728 DWORD dwError;
2729 SC_HANDLE hHandle;
2730
2731 DPRINT("ROpenSCManagerW() called\n");
2732 DPRINT("lpMachineName = %p\n", lpMachineName);
2733 DPRINT("lpMachineName: %S\n", lpMachineName);
2734 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2735 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2736 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2737
2738 if (ScmShutdown)
2739 return ERROR_SHUTDOWN_IN_PROGRESS;
2740
2741 if (!lpScHandle)
2742 return ERROR_INVALID_PARAMETER;
2743
2744 dwError = ScmCreateManagerHandle(lpDatabaseName,
2745 &hHandle);
2746 if (dwError != ERROR_SUCCESS)
2747 {
2748 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2749 return dwError;
2750 }
2751
2752 /* Check the desired access */
2753 dwError = ScmCheckAccess(hHandle,
2754 dwDesiredAccess | SC_MANAGER_CONNECT);
2755 if (dwError != ERROR_SUCCESS)
2756 {
2757 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2758 HeapFree(GetProcessHeap(), 0, hHandle);
2759 return dwError;
2760 }
2761
2762 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2763 DPRINT("*hScm = %p\n", *lpScHandle);
2764
2765 DPRINT("ROpenSCManagerW() done\n");
2766
2767 return ERROR_SUCCESS;
2768 }
2769
2770
2771 /* Function 16 */
2772 DWORD
2773 WINAPI
2774 ROpenServiceW(
2775 SC_RPC_HANDLE hSCManager,
2776 LPWSTR lpServiceName,
2777 DWORD dwDesiredAccess,
2778 LPSC_RPC_HANDLE lpServiceHandle)
2779 {
2780 PSERVICE lpService;
2781 PMANAGER_HANDLE hManager;
2782 SC_HANDLE hHandle;
2783 DWORD dwError = ERROR_SUCCESS;
2784
2785 DPRINT("ROpenServiceW() called\n");
2786 DPRINT("hSCManager = %p\n", hSCManager);
2787 DPRINT("lpServiceName = %p\n", lpServiceName);
2788 DPRINT("lpServiceName: %S\n", lpServiceName);
2789 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2790
2791 if (ScmShutdown)
2792 return ERROR_SHUTDOWN_IN_PROGRESS;
2793
2794 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2795 if (hManager == NULL)
2796 {
2797 DPRINT1("Invalid service manager handle!\n");
2798 return ERROR_INVALID_HANDLE;
2799 }
2800
2801 if (!lpServiceHandle)
2802 return ERROR_INVALID_PARAMETER;
2803
2804 if (!lpServiceName)
2805 return ERROR_INVALID_ADDRESS;
2806
2807 /* Lock the service database exclusive */
2808 ScmLockDatabaseExclusive();
2809
2810 /* Get service database entry */
2811 lpService = ScmGetServiceEntryByName(lpServiceName);
2812 if (lpService == NULL)
2813 {
2814 DPRINT("Could not find a service!\n");
2815 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2816 goto Done;
2817 }
2818
2819 /* Create a service handle */
2820 dwError = ScmCreateServiceHandle(lpService,
2821 &hHandle);
2822 if (dwError != ERROR_SUCCESS)
2823 {
2824 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2825 goto Done;
2826 }
2827
2828 /* Check the desired access */
2829 dwError = ScmCheckAccess(hHandle,
2830 dwDesiredAccess);
2831 if (dwError != ERROR_SUCCESS)
2832 {
2833 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2834 HeapFree(GetProcessHeap(), 0, hHandle);
2835 goto Done;
2836 }
2837
2838 lpService->dwRefCount++;
2839 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2840
2841 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2842 DPRINT("*hService = %p\n", *lpServiceHandle);
2843
2844 Done:
2845 /* Unlock the service database */
2846 ScmUnlockDatabase();
2847
2848 DPRINT("ROpenServiceW() done\n");
2849
2850 return dwError;
2851 }
2852
2853
2854 /* Function 17 */
2855 DWORD
2856 WINAPI
2857 RQueryServiceConfigW(
2858 SC_RPC_HANDLE hService,
2859 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2860 DWORD cbBufSize,
2861 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2862 {
2863 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2864 DWORD dwError = ERROR_SUCCESS;
2865 PSERVICE_HANDLE hSvc;
2866 PSERVICE lpService = NULL;
2867 HKEY hServiceKey = NULL;
2868 LPWSTR lpImagePath = NULL;
2869 LPWSTR lpServiceStartName = NULL;
2870 LPWSTR lpDependencies = NULL;
2871 DWORD dwDependenciesLength = 0;
2872 DWORD dwRequiredSize;
2873 WCHAR lpEmptyString[] = {0,0};
2874 LPWSTR lpStr;
2875
2876 DPRINT("RQueryServiceConfigW() called\n");
2877
2878 if (ScmShutdown)
2879 return ERROR_SHUTDOWN_IN_PROGRESS;
2880
2881 hSvc = ScmGetServiceFromHandle(hService);
2882 if (hSvc == NULL)
2883 {
2884 DPRINT1("Invalid service handle!\n");
2885 return ERROR_INVALID_HANDLE;
2886 }
2887
2888 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2889 SERVICE_QUERY_CONFIG))
2890 {
2891 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2892 return ERROR_ACCESS_DENIED;
2893 }
2894
2895 lpService = hSvc->ServiceEntry;
2896 if (lpService == NULL)
2897 {
2898 DPRINT("lpService == NULL!\n");
2899 return ERROR_INVALID_HANDLE;
2900 }
2901
2902 /* Lock the service database shared */
2903 ScmLockDatabaseShared();
2904
2905 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2906 KEY_READ,
2907 &hServiceKey);
2908 if (dwError != ERROR_SUCCESS)
2909 goto Done;
2910
2911 /* Read the image path */
2912 dwError = ScmReadString(hServiceKey,
2913 L"ImagePath",
2914 &lpImagePath);
2915 if (dwError != ERROR_SUCCESS)
2916 goto Done;
2917
2918 /* Read the service start name */
2919 ScmReadString(hServiceKey,
2920 L"ObjectName",
2921 &lpServiceStartName);
2922
2923 /* Read the dependencies */
2924 ScmReadDependencies(hServiceKey,
2925 &lpDependencies,
2926 &dwDependenciesLength);
2927
2928 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2929
2930 if (lpImagePath != NULL)
2931 dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2932 else
2933 dwRequiredSize += 2 * sizeof(WCHAR);
2934
2935 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2936 dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2937 else
2938 dwRequiredSize += 2 * sizeof(WCHAR);
2939
2940 if (lpDependencies != NULL)
2941 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2942 else
2943 dwRequiredSize += 2 * sizeof(WCHAR);
2944
2945 if (lpServiceStartName != NULL)
2946 dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2947 else
2948 dwRequiredSize += 2 * sizeof(WCHAR);
2949
2950 if (lpService->lpDisplayName != NULL)
2951 dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2952 else
2953 dwRequiredSize += 2 * sizeof(WCHAR);
2954
2955 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2956 {
2957 dwError = ERROR_INSUFFICIENT_BUFFER;
2958 }
2959 else
2960 {
2961 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
2962 lpServiceConfig->dwStartType = lpService->dwStartType;
2963 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
2964 lpServiceConfig->dwTagId = lpService->dwTag;
2965
2966 lpStr = (LPWSTR)(lpServiceConfig + 1);
2967
2968 /* Append the image path */
2969 if (lpImagePath != NULL)
2970 {
2971 wcscpy(lpStr, lpImagePath);
2972 }
2973 else
2974 {
2975 wcscpy(lpStr, lpEmptyString);
2976 }
2977
2978 lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2979 lpStr += (wcslen(lpStr) + 1);
2980
2981 /* Append the group name */
2982 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2983 {
2984 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2985 }
2986 else
2987 {
2988 wcscpy(lpStr, lpEmptyString);
2989 }
2990
2991 lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2992 lpStr += (wcslen(lpStr) + 1);
2993
2994 /* Append Dependencies */
2995 if (lpDependencies != NULL)
2996 {
2997 memcpy(lpStr,
2998 lpDependencies,
2999 dwDependenciesLength * sizeof(WCHAR));
3000 }
3001 else
3002 {
3003 wcscpy(lpStr, lpEmptyString);
3004 }
3005
3006 lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3007 if (lpDependencies != NULL)
3008 lpStr += dwDependenciesLength;
3009 else
3010 lpStr += (wcslen(lpStr) + 1);
3011
3012 /* Append the service start name */
3013 if (lpServiceStartName != NULL)
3014 {
3015 wcscpy(lpStr, lpServiceStartName);
3016 }
3017 else
3018 {
3019 wcscpy(lpStr, lpEmptyString);
3020 }
3021
3022 lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3023 lpStr += (wcslen(lpStr) + 1);
3024
3025 /* Append the display name */
3026 if (lpService->lpDisplayName != NULL)
3027 {
3028 wcscpy(lpStr, lpService->lpDisplayName);
3029 }
3030 else
3031 {
3032 wcscpy(lpStr, lpEmptyString);
3033 }
3034
3035 lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3036 }
3037
3038 if (pcbBytesNeeded != NULL)
3039 *pcbBytesNeeded = dwRequiredSize;
3040
3041 Done:
3042 /* Unlock the service database */
3043 ScmUnlockDatabase();
3044
3045 if (lpImagePath != NULL)
3046 HeapFree(GetProcessHeap(), 0, lpImagePath);
3047
3048 if (lpServiceStartName != NULL)
3049 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3050
3051 if (lpDependencies != NULL)
3052 HeapFree(GetProcessHeap(), 0, lpDependencies);
3053
3054 if (hServiceKey != NULL)
3055 RegCloseKey(hServiceKey);
3056
3057 DPRINT("RQueryServiceConfigW() done\n");
3058
3059 return dwError;
3060 }
3061
3062
3063 /* Function 18 */
3064 DWORD
3065 WINAPI
3066 RQueryServiceLockStatusW(
3067 SC_RPC_HANDLE hSCManager,
3068 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3069 DWORD cbBufSize,
3070 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3071 {
3072 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf;
3073 PMANAGER_HANDLE hMgr;
3074 DWORD dwRequiredSize;
3075
3076 if (!lpLockStatus || !pcbBytesNeeded)
3077 return ERROR_INVALID_PARAMETER;
3078
3079 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
3080 if (hMgr == NULL)
3081 {
3082 DPRINT1("Invalid service manager handle!\n");
3083 return ERROR_INVALID_HANDLE;
3084 }
3085
3086 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
3087 SC_MANAGER_QUERY_LOCK_STATUS))
3088 {
3089 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
3090 return ERROR_ACCESS_DENIED;
3091 }
3092
3093 /* FIXME: we need to compute instead the real length of the owner name */
3094 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
3095 *pcbBytesNeeded = dwRequiredSize;
3096
3097 if (cbBufSize < dwRequiredSize)
3098 return ERROR_INSUFFICIENT_BUFFER;
3099
3100 ScmQueryServiceLockStatusW(lpLockStatus);
3101
3102 return ERROR_SUCCESS;
3103 }
3104
3105
3106 /* Function 19 */
3107 DWORD
3108 WINAPI
3109 RStartServiceW(
3110 SC_RPC_HANDLE hService,
3111 DWORD argc,
3112 LPSTRING_PTRSW argv)
3113 {
3114 DWORD dwError = ERROR_SUCCESS;
3115 PSERVICE_HANDLE hSvc;
3116 PSERVICE lpService = NULL;
3117
3118 #ifndef NDEBUG
3119 DWORD i;
3120
3121 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3122 DPRINT(" argc: %lu\n", argc);
3123 if (argv != NULL)
3124 {
3125 for (i = 0; i < argc; i++)
3126 {
3127 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
3128 }
3129 }
3130 #endif
3131
3132 if (ScmShutdown)
3133 return ERROR_SHUTDOWN_IN_PROGRESS;
3134
3135 hSvc = ScmGetServiceFromHandle(hService);
3136 if (hSvc == NULL)
3137 {
3138 DPRINT1("Invalid service handle!\n");
3139 return ERROR_INVALID_HANDLE;
3140 }
3141
3142 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3143 SERVICE_START))
3144 {
3145 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3146 return ERROR_ACCESS_DENIED;
3147 }
3148
3149 lpService = hSvc->ServiceEntry;
3150 if (lpService == NULL)
3151 {
3152 DPRINT("lpService == NULL!\n");
3153 return ERROR_INVALID_HANDLE;
3154 }
3155
3156 if (lpService->dwStartType == SERVICE_DISABLED)
3157 return ERROR_SERVICE_DISABLED;
3158
3159 if (lpService->bDeleted)
3160 return ERROR_SERVICE_MARKED_FOR_DELETE;
3161
3162 /* Start the service */
3163 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3164
3165 return dwError;
3166 }
3167
3168
3169 /* Function 20 */
3170 DWORD
3171 WINAPI
3172 RGetServiceDisplayNameW(
3173 SC_RPC_HANDLE hSCManager,
3174 LPCWSTR lpServiceName,
3175 LPWSTR lpDisplayName,
3176 DWORD *lpcchBuffer)
3177 {
3178 // PMANAGER_HANDLE hManager;
3179 PSERVICE lpService;
3180 DWORD dwLength;
3181 DWORD dwError;
3182
3183 DPRINT("RGetServiceDisplayNameW() called\n");
3184 DPRINT("hSCManager = %p\n", hSCManager);
3185 DPRINT("lpServiceName: %S\n", lpServiceName);
3186 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3187 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3188
3189 // hManager = (PMANAGER_HANDLE)hSCManager;
3190 // if (hManager->Handle.Tag != MANAGER_TAG)
3191 // {
3192 // DPRINT("Invalid manager handle!\n");
3193 // return ERROR_INVALID_HANDLE;
3194 // }
3195
3196 /* Get service database entry */
3197 lpService = ScmGetServiceEntryByName(lpServiceName);
3198 if (lpService == NULL)
3199 {
3200 DPRINT("Could not find a service!\n");
3201
3202 /* If the service could not be found and lpcchBuffer is less than 2, windows
3203 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3204 if (*lpcchBuffer < 2)
3205 {
3206 *lpcchBuffer = 2;
3207 if (lpDisplayName != NULL)
3208 {
3209 *lpDisplayName = 0;
3210 }
3211 }
3212
3213 return ERROR_SERVICE_DOES_NOT_EXIST;
3214 }
3215
3216 if (!lpService->lpDisplayName)
3217 {
3218 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3219
3220 if (lpDisplayName != NULL &&
3221 *lpcchBuffer > dwLength)
3222 {
3223 wcscpy(lpDisplayName, lpService->lpServiceName);
3224 }
3225 }
3226 else
3227 {
3228 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
3229
3230 if (lpDisplayName != NULL &&
3231 *lpcchBuffer > dwLength)
3232 {
3233 wcscpy(lpDisplayName, lpService->lpDisplayName);
3234 }
3235 }
3236
3237 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3238
3239 *lpcchBuffer = dwLength;
3240
3241 return dwError;
3242 }
3243
3244
3245 /* Function 21 */
3246 DWORD
3247 WINAPI
3248 RGetServiceKeyNameW(
3249 SC_RPC_HANDLE hSCManager,
3250 LPCWSTR lpDisplayName,
3251 LPWSTR lpServiceName,
3252 DWORD *lpcchBuffer)
3253 {
3254 // PMANAGER_HANDLE hManager;
3255 PSERVICE lpService;
3256 DWORD dwLength;
3257 DWORD dwError;
3258
3259 DPRINT("RGetServiceKeyNameW() called\n");
3260 DPRINT("hSCManager = %p\n", hSCManager);
3261 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3262 DPRINT("lpServiceName: %p\n", lpServiceName);
3263 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3264
3265 // hManager = (PMANAGER_HANDLE)hSCManager;
3266 // if (hManager->Handle.Tag != MANAGER_TAG)
3267 // {
3268 // DPRINT("Invalid manager handle!\n");
3269 // return ERROR_INVALID_HANDLE;
3270 // }
3271
3272 /* Get service database entry */
3273 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3274 if (lpService == NULL)
3275 {
3276 DPRINT("Could not find a service!\n");
3277
3278 /* If the service could not be found and lpcchBuffer is less than 2, windows
3279 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3280 if (*lpcchBuffer < 2)
3281 {
3282 *lpcchBuffer = 2;
3283 if (lpServiceName != NULL)
3284 {
3285 *lpServiceName = 0;
3286 }
3287 }
3288
3289 return ERROR_SERVICE_DOES_NOT_EXIST;
3290 }
3291
3292 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3293
3294 if (lpServiceName != NULL &&
3295 *lpcchBuffer > dwLength)
3296 {
3297 wcscpy(lpServiceName, lpService->lpServiceName);
3298 *lpcchBuffer = dwLength;
3299 return ERROR_SUCCESS;
3300 }
3301
3302 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3303
3304 *lpcchBuffer = dwLength;
3305
3306 return dwError;
3307 }
3308
3309
3310 /* Function 22 */
3311 DWORD
3312 WINAPI
3313 RI_ScSetServiceBitsA(
3314 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3315 DWORD dwServiceBits,
3316 int bSetBitsOn,
3317 int bUpdateImmediately,
3318 char *lpString)
3319 {
3320 UNIMPLEMENTED;
3321 return ERROR_CALL_NOT_IMPLEMENTED;
3322 }
3323
3324
3325 /* Function 23 */
3326 DWORD
3327 WINAPI
3328 RChangeServiceConfigA(
3329 SC_RPC_HANDLE hService,
3330 DWORD dwServiceType,
3331 DWORD dwStartType,
3332 DWORD dwErrorControl,
3333 LPSTR lpBinaryPathName,
3334 LPSTR lpLoadOrderGroup,
3335 LPDWORD lpdwTagId,
3336 LPBYTE lpDependencies,
3337 DWORD dwDependSize,
3338 LPSTR lpServiceStartName,
3339 LPBYTE lpPassword,
3340 DWORD dwPwSize,
3341 LPSTR lpDisplayName)
3342 {
3343 DWORD dwError = ERROR_SUCCESS;
3344 PSERVICE_HANDLE hSvc;
3345 PSERVICE lpService = NULL;
3346 HKEY hServiceKey = NULL;
3347 LPWSTR lpDisplayNameW = NULL;
3348 LPWSTR lpBinaryPathNameW = NULL;
3349 LPWSTR lpCanonicalImagePathW = NULL;
3350 LPWSTR lpLoadOrderGroupW = NULL;
3351 LPWSTR lpDependenciesW = NULL;
3352
3353 DPRINT("RChangeServiceConfigA() called\n");
3354 DPRINT("dwServiceType = %lu\n", dwServiceType);
3355 DPRINT("dwStartType = %lu\n", dwStartType);
3356 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3357 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3358 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3359 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3360
3361 if (ScmShutdown)
3362 return ERROR_SHUTDOWN_IN_PROGRESS;
3363
3364 hSvc = ScmGetServiceFromHandle(hService);
3365 if (hSvc == NULL)
3366 {
3367 DPRINT1("Invalid service handle!\n");</