[SERVICES][ADVAPI32] Fix the broken service stop sequence
[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
17 #define NDEBUG
18 #include <debug.h>
19
20 /* GLOBALS *****************************************************************/
21
22 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
23 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
24 #define INVALID_TAG 0xAABBCCDD
25
26 typedef struct _SCMGR_HANDLE
27 {
28 DWORD Tag;
29 DWORD DesiredAccess;
30 } SCMGR_HANDLE;
31
32
33 typedef struct _MANAGER_HANDLE
34 {
35 SCMGR_HANDLE Handle;
36 WCHAR DatabaseName[1];
37 } MANAGER_HANDLE, *PMANAGER_HANDLE;
38
39
40 typedef struct _SERVICE_HANDLE
41 {
42 SCMGR_HANDLE Handle;
43 PSERVICE ServiceEntry;
44 } SERVICE_HANDLE, *PSERVICE_HANDLE;
45
46
47 #define SC_MANAGER_READ \
48 (STANDARD_RIGHTS_READ | \
49 SC_MANAGER_QUERY_LOCK_STATUS | \
50 SC_MANAGER_ENUMERATE_SERVICE)
51
52 #define SC_MANAGER_WRITE \
53 (STANDARD_RIGHTS_WRITE | \
54 SC_MANAGER_MODIFY_BOOT_CONFIG | \
55 SC_MANAGER_CREATE_SERVICE)
56
57 #define SC_MANAGER_EXECUTE \
58 (STANDARD_RIGHTS_EXECUTE | \
59 SC_MANAGER_LOCK | \
60 SC_MANAGER_ENUMERATE_SERVICE | \
61 SC_MANAGER_CONNECT | \
62 SC_MANAGER_CREATE_SERVICE)
63
64
65 #define SERVICE_READ \
66 (STANDARD_RIGHTS_READ | \
67 SERVICE_INTERROGATE | \
68 SERVICE_ENUMERATE_DEPENDENTS | \
69 SERVICE_QUERY_STATUS | \
70 SERVICE_QUERY_CONFIG)
71
72 #define SERVICE_WRITE \
73 (STANDARD_RIGHTS_WRITE | \
74 SERVICE_CHANGE_CONFIG)
75
76 #define SERVICE_EXECUTE \
77 (STANDARD_RIGHTS_EXECUTE | \
78 SERVICE_USER_DEFINED_CONTROL | \
79 SERVICE_PAUSE_CONTINUE | \
80 SERVICE_STOP | \
81 SERVICE_START)
82
83 #define TAG_ARRAY_SIZE 32
84
85 /* VARIABLES ***************************************************************/
86
87 static GENERIC_MAPPING
88 ScmManagerMapping = {SC_MANAGER_READ,
89 SC_MANAGER_WRITE,
90 SC_MANAGER_EXECUTE,
91 SC_MANAGER_ALL_ACCESS};
92
93 static GENERIC_MAPPING
94 ScmServiceMapping = {SERVICE_READ,
95 SERVICE_WRITE,
96 SERVICE_EXECUTE,
97 SERVICE_ALL_ACCESS};
98
99
100 /* FUNCTIONS ***************************************************************/
101
102 VOID
103 ScmStartRpcServer(VOID)
104 {
105 RPC_STATUS Status;
106
107 DPRINT("ScmStartRpcServer() called\n");
108
109 Status = RpcServerUseProtseqEpW(L"ncacn_np",
110 10,
111 L"\\pipe\\ntsvcs",
112 NULL);
113 if (Status != RPC_S_OK)
114 {
115 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
116 return;
117 }
118
119 Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
120 NULL,
121 NULL);
122 if (Status != RPC_S_OK)
123 {
124 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
125 return;
126 }
127
128 Status = RpcServerListen(1, 20, TRUE);
129 if (Status != RPC_S_OK)
130 {
131 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
132 return;
133 }
134
135 DPRINT("ScmStartRpcServer() done\n");
136 }
137
138
139 static DWORD
140 ScmCreateManagerHandle(LPWSTR lpDatabaseName,
141 SC_HANDLE *Handle)
142 {
143 PMANAGER_HANDLE Ptr;
144
145 if (lpDatabaseName == NULL)
146 lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
147
148 if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
149 {
150 DPRINT("Database %S, does not exist\n", lpDatabaseName);
151 return ERROR_DATABASE_DOES_NOT_EXIST;
152 }
153 else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
154 {
155 DPRINT("Invalid Database name %S.\n", lpDatabaseName);
156 return ERROR_INVALID_NAME;
157 }
158
159 Ptr = HeapAlloc(GetProcessHeap(),
160 HEAP_ZERO_MEMORY,
161 FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1]));
162 if (Ptr == NULL)
163 return ERROR_NOT_ENOUGH_MEMORY;
164
165 Ptr->Handle.Tag = MANAGER_TAG;
166
167 wcscpy(Ptr->DatabaseName, lpDatabaseName);
168
169 *Handle = (SC_HANDLE)Ptr;
170
171 return ERROR_SUCCESS;
172 }
173
174
175 static DWORD
176 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
177 SC_HANDLE *Handle)
178 {
179 PSERVICE_HANDLE Ptr;
180
181 Ptr = HeapAlloc(GetProcessHeap(),
182 HEAP_ZERO_MEMORY,
183 sizeof(SERVICE_HANDLE));
184 if (Ptr == NULL)
185 return ERROR_NOT_ENOUGH_MEMORY;
186
187 Ptr->Handle.Tag = SERVICE_TAG;
188
189 Ptr->ServiceEntry = lpServiceEntry;
190
191 *Handle = (SC_HANDLE)Ptr;
192
193 return ERROR_SUCCESS;
194 }
195
196
197 static PMANAGER_HANDLE
198 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle)
199 {
200 PMANAGER_HANDLE pManager = NULL;
201
202 _SEH2_TRY
203 {
204 if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG)
205 pManager = (PMANAGER_HANDLE)Handle;
206 }
207 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
208 {
209 DPRINT1("Exception: Invalid Service Manager handle!\n");
210 }
211 _SEH2_END;
212
213 return pManager;
214 }
215
216
217 static PSERVICE_HANDLE
218 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle)
219 {
220 PSERVICE_HANDLE pService = NULL;
221
222 _SEH2_TRY
223 {
224 if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG)
225 pService = (PSERVICE_HANDLE)Handle;
226 }
227 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
228 {
229 DPRINT1("Exception: Invalid Service handle!\n");
230 }
231 _SEH2_END;
232
233 return pService;
234 }
235
236
237 static DWORD
238 ScmCheckAccess(SC_HANDLE Handle,
239 DWORD dwDesiredAccess)
240 {
241 PMANAGER_HANDLE hMgr;
242
243 hMgr = (PMANAGER_HANDLE)Handle;
244 if (hMgr->Handle.Tag == MANAGER_TAG)
245 {
246 RtlMapGenericMask(&dwDesiredAccess,
247 &ScmManagerMapping);
248
249 hMgr->Handle.DesiredAccess = dwDesiredAccess;
250
251 return ERROR_SUCCESS;
252 }
253 else if (hMgr->Handle.Tag == SERVICE_TAG)
254 {
255 RtlMapGenericMask(&dwDesiredAccess,
256 &ScmServiceMapping);
257
258 hMgr->Handle.DesiredAccess = dwDesiredAccess;
259
260 return ERROR_SUCCESS;
261 }
262
263 return ERROR_INVALID_HANDLE;
264 }
265
266
267 DWORD
268 ScmAssignNewTag(PSERVICE lpService)
269 {
270 HKEY hKey = NULL;
271 DWORD dwError;
272 DWORD dwGroupTagCount = 0;
273 PDWORD pdwGroupTags = NULL;
274 DWORD dwFreeTag = 0;
275 DWORD dwTagUsedBase = 1;
276 BOOLEAN TagUsed[TAG_ARRAY_SIZE];
277 INT nTagOffset;
278 DWORD i;
279 DWORD cbDataSize;
280 PLIST_ENTRY ServiceEntry;
281 PSERVICE CurrentService;
282
283 ASSERT(lpService != NULL);
284 ASSERT(lpService->lpGroup != NULL);
285
286 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
287 L"System\\CurrentControlSet\\Control\\GroupOrderList",
288 0,
289 KEY_READ,
290 &hKey);
291
292 if (dwError != ERROR_SUCCESS)
293 goto findFreeTag;
294
295 /* query value length */
296 cbDataSize = 0;
297 dwError = RegQueryValueExW(hKey,
298 lpService->lpGroup->szGroupName,
299 NULL,
300 NULL,
301 NULL,
302 &cbDataSize);
303
304 if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA)
305 goto findFreeTag;
306
307 pdwGroupTags = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDataSize);
308 if (!pdwGroupTags)
309 {
310 dwError = ERROR_NOT_ENOUGH_MEMORY;
311 goto cleanup;
312 }
313
314 dwError = RegQueryValueExW(hKey,
315 lpService->lpGroup->szGroupName,
316 NULL,
317 NULL,
318 (LPBYTE)pdwGroupTags,
319 &cbDataSize);
320
321 if (dwError != ERROR_SUCCESS)
322 goto findFreeTag;
323
324 if (cbDataSize < sizeof(pdwGroupTags[0]))
325 goto findFreeTag;
326
327 dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1);
328
329 findFreeTag:
330 do
331 {
332 /* mark all tags as unused */
333 for (i = 0; i < TAG_ARRAY_SIZE; i++)
334 TagUsed[i] = FALSE;
335
336 /* mark tags in GroupOrderList as used */
337 for (i = 1; i <= dwGroupTagCount; i++)
338 {
339 nTagOffset = pdwGroupTags[i] - dwTagUsedBase;
340 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
341 TagUsed[nTagOffset] = TRUE;
342 }
343
344 /* mark tags in service list as used */
345 ServiceEntry = lpService->ServiceListEntry.Flink;
346 while (ServiceEntry != &lpService->ServiceListEntry)
347 {
348 ASSERT(ServiceEntry != NULL);
349 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
350 if (CurrentService->lpGroup == lpService->lpGroup)
351 {
352 nTagOffset = CurrentService->dwTag - dwTagUsedBase;
353 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
354 TagUsed[nTagOffset] = TRUE;
355 }
356
357 ServiceEntry = ServiceEntry->Flink;
358 }
359
360 /* find unused tag, if any */
361 for (i = 0; i < TAG_ARRAY_SIZE; i++)
362 {
363 if (!TagUsed[i])
364 {
365 dwFreeTag = dwTagUsedBase + i;
366 break;
367 }
368 }
369
370 dwTagUsedBase += TAG_ARRAY_SIZE;
371 } while (!dwFreeTag);
372
373 cleanup:
374 if (pdwGroupTags)
375 HeapFree(GetProcessHeap(), 0, pdwGroupTags);
376
377 if (hKey)
378 RegCloseKey(hKey);
379
380 if (dwFreeTag)
381 {
382 lpService->dwTag = dwFreeTag;
383 DPRINT("Assigning new tag %lu to service %S in group %S\n",
384 lpService->dwTag, lpService->lpServiceName, lpService->lpGroup->szGroupName);
385 dwError = ERROR_SUCCESS;
386 }
387 else
388 {
389 DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
390 lpService->lpServiceName, dwError);
391 }
392
393 return dwError;
394 }
395
396
397 /* Create a path suitable for the bootloader out of the full path */
398 DWORD
399 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
400 {
401 SIZE_T ServiceNameLen, ExpandedLen;
402 DWORD BufferSize;
403 WCHAR Dest;
404 WCHAR *Expanded;
405 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
406 OBJECT_ATTRIBUTES ObjectAttributes;
407 NTSTATUS Status;
408 HANDLE SymbolicLinkHandle;
409
410 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
411
412 if (!RelativeName)
413 return ERROR_INVALID_PARAMETER;
414
415 *RelativeName = NULL;
416
417 ServiceNameLen = wcslen(CanonName);
418
419 /* First check, if it's already good */
420 if (ServiceNameLen > 12 &&
421 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
422 {
423 *RelativeName = HeapAlloc(GetProcessHeap(),
424 HEAP_ZERO_MEMORY,
425 (ServiceNameLen + 1) * sizeof(WCHAR));
426 if (*RelativeName == NULL)
427 {
428 DPRINT("Error allocating memory for boot driver name!\n");
429 return ERROR_NOT_ENOUGH_MEMORY;
430 }
431
432 /* Copy it */
433 wcscpy(*RelativeName, CanonName);
434
435 DPRINT("Bootdriver name %S\n", *RelativeName);
436 return ERROR_SUCCESS;
437 }
438
439 /* If it has %SystemRoot% prefix, substitute it to \System*/
440 if (ServiceNameLen > 13 &&
441 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
442 {
443 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
444 *RelativeName = HeapAlloc(GetProcessHeap(),
445 HEAP_ZERO_MEMORY,
446 ServiceNameLen * sizeof(WCHAR));
447
448 if (*RelativeName == NULL)
449 {
450 DPRINT("Error allocating memory for boot driver name!\n");
451 return ERROR_NOT_ENOUGH_MEMORY;
452 }
453
454 /* Copy it */
455 wcscpy(*RelativeName, L"\\SystemRoot\\");
456 wcscat(*RelativeName, CanonName + 13);
457
458 DPRINT("Bootdriver name %S\n", *RelativeName);
459 return ERROR_SUCCESS;
460 }
461
462 /* Get buffer size needed for expanding env strings */
463 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
464
465 if (BufferSize <= 1)
466 {
467 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
468 return ERROR_INVALID_ENVIRONMENT;
469 }
470
471 /* Allocate memory, since the size is known now */
472 Expanded = HeapAlloc(GetProcessHeap(),
473 HEAP_ZERO_MEMORY,
474 (BufferSize + 1) * sizeof(WCHAR));
475 if (!Expanded)
476 {
477 DPRINT("Error allocating memory for boot driver name!\n");
478 return ERROR_NOT_ENOUGH_MEMORY;
479 }
480
481 /* Expand it */
482 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
483 BufferSize)
484 {
485 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
486 HeapFree(GetProcessHeap(), 0, Expanded);
487 return ERROR_NOT_ENOUGH_MEMORY;
488 }
489
490 /* Convert to NT-style path */
491 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
492 {
493 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
494 return ERROR_INVALID_ENVIRONMENT;
495 }
496
497 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
498
499 /* No need to keep the dos-path anymore */
500 HeapFree(GetProcessHeap(), 0, Expanded);
501
502 /* Copy it to the allocated place */
503 Expanded = HeapAlloc(GetProcessHeap(),
504 HEAP_ZERO_MEMORY,
505 NtPathName.Length + sizeof(UNICODE_NULL));
506 if (!Expanded)
507 {
508 DPRINT("Error allocating memory for boot driver name!\n");
509 RtlFreeUnicodeString(&NtPathName);
510 return ERROR_NOT_ENOUGH_MEMORY;
511 }
512
513 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
514 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
515 Expanded[ExpandedLen] = UNICODE_NULL;
516 RtlFreeUnicodeString(&NtPathName);
517
518 if (ServiceNameLen > ExpandedLen &&
519 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
520 {
521 HeapFree(GetProcessHeap(), 0, Expanded);
522
523 /* Only \SystemRoot\ is missing */
524 *RelativeName = HeapAlloc(GetProcessHeap(),
525 HEAP_ZERO_MEMORY,
526 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
527 if (*RelativeName == NULL)
528 {
529 DPRINT("Error allocating memory for boot driver name!\n");
530 return ERROR_NOT_ENOUGH_MEMORY;
531 }
532
533 wcscpy(*RelativeName, L"\\SystemRoot\\");
534 wcscat(*RelativeName, CanonName + ExpandedLen);
535
536 return ERROR_SUCCESS;
537 }
538
539 /* No longer need this */
540 HeapFree(GetProcessHeap(), 0, Expanded);
541
542 /* The most complex case starts here */
543 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
544 InitializeObjectAttributes(&ObjectAttributes,
545 &SystemRoot,
546 OBJ_CASE_INSENSITIVE,
547 NULL,
548 NULL);
549
550 /* Open this symlink */
551 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
552 if (NT_SUCCESS(Status))
553 {
554 DPRINT("Opened symbolic link object\n");
555
556 RtlInitEmptyUnicodeString(&LinkTarget, NULL, 0);
557 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
558 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
559 {
560 /* Check if required buffer size is sane */
561 if (BufferSize > UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL))
562 {
563 DPRINT("Too large buffer required\n");
564
565 NtClose(SymbolicLinkHandle);
566 return ERROR_NOT_ENOUGH_MEMORY;
567 }
568
569 /* Alloc the string */
570 LinkTarget.Length = (USHORT)BufferSize;
571 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(UNICODE_NULL);
572 LinkTarget.Buffer = HeapAlloc(GetProcessHeap(),
573 HEAP_ZERO_MEMORY,
574 LinkTarget.MaximumLength);
575 if (!LinkTarget.Buffer)
576 {
577 DPRINT("Unable to alloc buffer\n");
578 NtClose(SymbolicLinkHandle);
579 return ERROR_NOT_ENOUGH_MEMORY;
580 }
581
582 /* Do a real query now */
583 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
584 NtClose(SymbolicLinkHandle);
585 if (NT_SUCCESS(Status))
586 {
587 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
588
589 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
590 if ((ServiceNameLen > ExpandedLen) &&
591 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
592 {
593 *RelativeName = HeapAlloc(GetProcessHeap(),
594 HEAP_ZERO_MEMORY,
595 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
596
597 if (*RelativeName == NULL)
598 {
599 DPRINT("Unable to alloc buffer\n");
600 return ERROR_NOT_ENOUGH_MEMORY;
601 }
602
603 /* Copy it over, substituting the first part
604 with SystemRoot */
605 wcscpy(*RelativeName, L"\\SystemRoot\\");
606 wcscat(*RelativeName, CanonName+ExpandedLen+1);
607
608 /* Return success */
609 return ERROR_SUCCESS;
610 }
611 else
612 {
613 return ERROR_INVALID_PARAMETER;
614 }
615 }
616 else
617 {
618 DPRINT("Error, Status = %08X\n", Status);
619 return ERROR_INVALID_PARAMETER;
620 }
621 }
622 else
623 {
624 DPRINT("Error, Status = %08X\n", Status);
625 NtClose(SymbolicLinkHandle);
626 return ERROR_INVALID_PARAMETER;
627 }
628 }
629 else
630 {
631 /* Failure */
632 DPRINT("Error, Status = %08X\n", Status);
633 return ERROR_INVALID_PARAMETER;
634 }
635 }
636
637
638 DWORD
639 ScmCanonDriverImagePath(DWORD dwStartType,
640 const wchar_t *lpServiceName,
641 wchar_t **lpCanonName)
642 {
643 DWORD Result;
644 SIZE_T ServiceNameLen;
645 UNICODE_STRING NtServiceName;
646 WCHAR *RelativeName;
647 const WCHAR *SourceName = lpServiceName;
648
649 /* Calculate the length of the service's name */
650 ServiceNameLen = wcslen(lpServiceName);
651
652 /* 12 is wcslen(L"\\SystemRoot\\") */
653 if (ServiceNameLen > 12 &&
654 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
655 {
656 /* SystemRoot prefix is already included */
657 *lpCanonName = HeapAlloc(GetProcessHeap(),
658 HEAP_ZERO_MEMORY,
659 (ServiceNameLen + 1) * sizeof(WCHAR));
660
661 if (*lpCanonName == NULL)
662 {
663 DPRINT("Error allocating memory for canonized service name!\n");
664 return ERROR_NOT_ENOUGH_MEMORY;
665 }
666
667 /* If it's a boot-time driver, it must be systemroot relative */
668 if (dwStartType == SERVICE_BOOT_START)
669 SourceName += 12;
670
671 /* Copy it */
672 wcscpy(*lpCanonName, SourceName);
673
674 DPRINT("Canonicalized name %S\n", *lpCanonName);
675 return NO_ERROR;
676 }
677
678 /* Check if it has %SystemRoot% (len=13) */
679 if (ServiceNameLen > 13 &&
680 !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13))
681 {
682 /* Substitute %SystemRoot% with \\SystemRoot\\ */
683 *lpCanonName = HeapAlloc(GetProcessHeap(),
684 HEAP_ZERO_MEMORY,
685 (ServiceNameLen + 1) * sizeof(WCHAR));
686
687 if (*lpCanonName == NULL)
688 {
689 DPRINT("Error allocating memory for canonized service name!\n");
690 return ERROR_NOT_ENOUGH_MEMORY;
691 }
692
693 /* If it's a boot-time driver, it must be systemroot relative */
694 if (dwStartType == SERVICE_BOOT_START)
695 wcscpy(*lpCanonName, L"\\SystemRoot\\");
696
697 wcscat(*lpCanonName, lpServiceName + 13);
698
699 DPRINT("Canonicalized name %S\n", *lpCanonName);
700 return NO_ERROR;
701 }
702
703 /* Check if it's a relative path name */
704 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
705 {
706 *lpCanonName = HeapAlloc(GetProcessHeap(),
707 HEAP_ZERO_MEMORY,
708 (ServiceNameLen + 1) * sizeof(WCHAR));
709
710 if (*lpCanonName == NULL)
711 {
712 DPRINT("Error allocating memory for canonized service name!\n");
713 return ERROR_NOT_ENOUGH_MEMORY;
714 }
715
716 /* Just copy it over without changing */
717 wcscpy(*lpCanonName, lpServiceName);
718
719 return NO_ERROR;
720 }
721
722 /* It seems to be a DOS path, convert it */
723 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
724 {
725 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
726 return ERROR_INVALID_PARAMETER;
727 }
728
729 *lpCanonName = HeapAlloc(GetProcessHeap(),
730 HEAP_ZERO_MEMORY,
731 NtServiceName.Length + sizeof(WCHAR));
732
733 if (*lpCanonName == NULL)
734 {
735 DPRINT("Error allocating memory for canonized service name!\n");
736 RtlFreeUnicodeString(&NtServiceName);
737 return ERROR_NOT_ENOUGH_MEMORY;
738 }
739
740 /* Copy the string */
741 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
742
743 /* The unicode string is not needed anymore */
744 RtlFreeUnicodeString(&NtServiceName);
745
746 if (dwStartType != SERVICE_BOOT_START)
747 {
748 DPRINT("Canonicalized name %S\n", *lpCanonName);
749 return NO_ERROR;
750 }
751
752 /* The service is boot-started, so must be relative */
753 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
754 if (Result)
755 {
756 /* There is a problem, free name and return */
757 HeapFree(GetProcessHeap(), 0, *lpCanonName);
758 DPRINT("Error converting named!\n");
759 return Result;
760 }
761
762 ASSERT(RelativeName);
763
764 /* Copy that string */
765 wcscpy(*lpCanonName, RelativeName + 12);
766
767 /* Free the allocated buffer */
768 HeapFree(GetProcessHeap(), 0, RelativeName);
769
770 DPRINT("Canonicalized name %S\n", *lpCanonName);
771
772 /* Success */
773 return NO_ERROR;
774 }
775
776
777 /* Internal recursive function */
778 /* Need to search for every dependency on every service */
779 static DWORD
780 Int_EnumDependentServicesW(HKEY hServicesKey,
781 PSERVICE lpService,
782 DWORD dwServiceState,
783 PSERVICE *lpServices,
784 LPDWORD pcbBytesNeeded,
785 LPDWORD lpServicesReturned)
786 {
787 DWORD dwError = ERROR_SUCCESS;
788 WCHAR szNameBuf[MAX_PATH];
789 WCHAR szValueBuf[MAX_PATH];
790 WCHAR *lpszNameBuf = szNameBuf;
791 WCHAR *lpszValueBuf = szValueBuf;
792 DWORD dwSize;
793 DWORD dwNumSubKeys;
794 DWORD dwIteration;
795 PSERVICE lpCurrentService;
796 HKEY hServiceEnumKey;
797 DWORD dwCurrentServiceState = SERVICE_ACTIVE;
798 DWORD dwDependServiceStrPtr = 0;
799 DWORD dwRequiredSize = 0;
800
801 /* Get the number of service keys */
802 dwError = RegQueryInfoKeyW(hServicesKey,
803 NULL,
804 NULL,
805 NULL,
806 &dwNumSubKeys,
807 NULL,
808 NULL,
809 NULL,
810 NULL,
811 NULL,
812 NULL,
813 NULL);
814 if (dwError != ERROR_SUCCESS)
815 {
816 DPRINT("ERROR! Unable to get number of services keys.\n");
817 return dwError;
818 }
819
820 /* Iterate the service keys to see if another service depends on the this service */
821 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
822 {
823 dwSize = MAX_PATH;
824 dwError = RegEnumKeyExW(hServicesKey,
825 dwIteration,
826 lpszNameBuf,
827 &dwSize,
828 NULL,
829 NULL,
830 NULL,
831 NULL);
832 if (dwError != ERROR_SUCCESS)
833 return dwError;
834
835 /* Open the Service key */
836 dwError = RegOpenKeyExW(hServicesKey,
837 lpszNameBuf,
838 0,
839 KEY_READ,
840 &hServiceEnumKey);
841 if (dwError != ERROR_SUCCESS)
842 return dwError;
843
844 dwSize = MAX_PATH * sizeof(WCHAR);
845
846 /* Check for the DependOnService Value */
847 dwError = RegQueryValueExW(hServiceEnumKey,
848 L"DependOnService",
849 NULL,
850 NULL,
851 (LPBYTE)lpszValueBuf,
852 &dwSize);
853
854 /* FIXME: Handle load order. */
855
856 /* If the service found has a DependOnService value */
857 if (dwError == ERROR_SUCCESS)
858 {
859 dwDependServiceStrPtr = 0;
860
861 /* Can be more than one Dependencies in the DependOnService string */
862 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
863 {
864 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
865 {
866 /* Get the current enumed service pointer */
867 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
868
869 /* Check for valid Service */
870 if (!lpCurrentService)
871 {
872 /* This should never happen! */
873 DPRINT("This should not happen at this point, report to Developer\n");
874 return ERROR_NOT_FOUND;
875 }
876
877 /* Determine state the service is in */
878 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
879 dwCurrentServiceState = SERVICE_INACTIVE;
880
881 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
882 if ((dwCurrentServiceState == dwServiceState) ||
883 (dwServiceState == SERVICE_STATE_ALL))
884 {
885 /* Calculate the required size */
886 dwRequiredSize += sizeof(SERVICE_STATUS);
887 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
888 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
889
890 /* Add the size for service name and display name pointers */
891 dwRequiredSize += (2 * sizeof(PVOID));
892
893 /* increase the BytesNeeded size */
894 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
895
896 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
897 comes first */
898
899 /* Recursive call to check for its dependencies */
900 Int_EnumDependentServicesW(hServicesKey,
901 lpCurrentService,
902 dwServiceState,
903 lpServices,
904 pcbBytesNeeded,
905 lpServicesReturned);
906
907 /* If the lpServices is valid set the service pointer */
908 if (lpServices)
909 lpServices[*lpServicesReturned] = lpCurrentService;
910
911 *lpServicesReturned = *lpServicesReturned + 1;
912 }
913 }
914
915 dwDependServiceStrPtr += (DWORD)(wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
916 }
917 }
918 else if (*pcbBytesNeeded)
919 {
920 dwError = ERROR_SUCCESS;
921 }
922
923 RegCloseKey(hServiceEnumKey);
924 }
925
926 return dwError;
927 }
928
929
930 /* Function 0 */
931 DWORD
932 WINAPI
933 RCloseServiceHandle(
934 LPSC_RPC_HANDLE hSCObject)
935 {
936 PMANAGER_HANDLE hManager;
937 PSERVICE_HANDLE hService;
938 PSERVICE lpService;
939 HKEY hServicesKey;
940 DWORD dwError;
941 DWORD pcbBytesNeeded = 0;
942 DWORD dwServicesReturned = 0;
943
944 DPRINT("RCloseServiceHandle() called\n");
945
946 DPRINT("hSCObject = %p\n", *hSCObject);
947
948 if (*hSCObject == 0)
949 return ERROR_INVALID_HANDLE;
950
951 hManager = ScmGetServiceManagerFromHandle(*hSCObject);
952 hService = ScmGetServiceFromHandle(*hSCObject);
953
954 if (hManager != NULL)
955 {
956 DPRINT("Found manager handle\n");
957
958 /* Make sure we don't access stale memory if someone tries to use this handle again. */
959 hManager->Handle.Tag = INVALID_TAG;
960
961 HeapFree(GetProcessHeap(), 0, hManager);
962 hManager = NULL;
963
964 *hSCObject = NULL;
965
966 DPRINT("RCloseServiceHandle() done\n");
967 return ERROR_SUCCESS;
968 }
969 else if (hService != NULL)
970 {
971 DPRINT("Found service handle\n");
972
973 /* Lock the service database exclusively */
974 ScmLockDatabaseExclusive();
975
976 /* Get the pointer to the service record */
977 lpService = hService->ServiceEntry;
978
979 /* Make sure we don't access stale memory if someone tries to use this handle again. */
980 hService->Handle.Tag = INVALID_TAG;
981
982 /* Free the handle */
983 HeapFree(GetProcessHeap(), 0, hService);
984 hService = NULL;
985
986 ASSERT(lpService->dwRefCount > 0);
987
988 lpService->dwRefCount--;
989 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
990 lpService->dwRefCount);
991
992 if (lpService->dwRefCount == 0)
993 {
994 /* If this service has been marked for deletion */
995 if (lpService->bDeleted &&
996 lpService->Status.dwCurrentState == SERVICE_STOPPED)
997 {
998 /* Open the Services Reg key */
999 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1000 L"System\\CurrentControlSet\\Services",
1001 0,
1002 KEY_SET_VALUE | KEY_READ,
1003 &hServicesKey);
1004 if (dwError != ERROR_SUCCESS)
1005 {
1006 DPRINT("Failed to open services key\n");
1007 ScmUnlockDatabase();
1008 return dwError;
1009 }
1010
1011 /* Call the internal function with NULL, just to get bytes we need */
1012 Int_EnumDependentServicesW(hServicesKey,
1013 lpService,
1014 SERVICE_ACTIVE,
1015 NULL,
1016 &pcbBytesNeeded,
1017 &dwServicesReturned);
1018
1019 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
1020 if (pcbBytesNeeded)
1021 {
1022 DPRINT("Deletion failed due to running dependencies.\n");
1023 RegCloseKey(hServicesKey);
1024 ScmUnlockDatabase();
1025 return ERROR_SUCCESS;
1026 }
1027
1028 /* There are no references and no running dependencies,
1029 it is now safe to delete the service */
1030
1031 /* Delete the Service Key */
1032 dwError = ScmDeleteRegKey(hServicesKey,
1033 lpService->lpServiceName);
1034
1035 RegCloseKey(hServicesKey);
1036
1037 if (dwError != ERROR_SUCCESS)
1038 {
1039 DPRINT("Failed to Delete the Service Registry key\n");
1040 ScmUnlockDatabase();
1041 return dwError;
1042 }
1043
1044 /* Delete the Service */
1045 ScmDeleteServiceRecord(lpService);
1046 }
1047 }
1048
1049 ScmUnlockDatabase();
1050
1051 *hSCObject = NULL;
1052
1053 DPRINT("RCloseServiceHandle() done\n");
1054 return ERROR_SUCCESS;
1055 }
1056
1057 DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
1058
1059 return ERROR_INVALID_HANDLE;
1060 }
1061
1062
1063 /* Function 1 */
1064 DWORD
1065 WINAPI
1066 RControlService(
1067 SC_RPC_HANDLE hService,
1068 DWORD dwControl,
1069 LPSERVICE_STATUS lpServiceStatus)
1070 {
1071 PSERVICE_HANDLE hSvc;
1072 PSERVICE lpService;
1073 ACCESS_MASK DesiredAccess;
1074 DWORD dwError = ERROR_SUCCESS;
1075 DWORD pcbBytesNeeded = 0;
1076 DWORD dwServicesReturned = 0;
1077 DWORD dwControlsAccepted;
1078 DWORD dwCurrentState;
1079 HKEY hServicesKey = NULL;
1080 LPCWSTR lpLogStrings[2];
1081 WCHAR szLogBuffer[80];
1082 UINT uID;
1083
1084 DPRINT("RControlService() called\n");
1085
1086 if (ScmShutdown)
1087 return ERROR_SHUTDOWN_IN_PROGRESS;
1088
1089 /* Check the service handle */
1090 hSvc = ScmGetServiceFromHandle(hService);
1091 if (hSvc == NULL)
1092 {
1093 DPRINT1("Invalid service handle!\n");
1094 return ERROR_INVALID_HANDLE;
1095 }
1096
1097 /* Check the service entry point */
1098 lpService = hSvc->ServiceEntry;
1099 if (lpService == NULL)
1100 {
1101 DPRINT1("lpService == NULL!\n");
1102 return ERROR_INVALID_HANDLE;
1103 }
1104
1105 /* Check access rights */
1106 switch (dwControl)
1107 {
1108 case SERVICE_CONTROL_STOP:
1109 DesiredAccess = SERVICE_STOP;
1110 break;
1111
1112 case SERVICE_CONTROL_PAUSE:
1113 case SERVICE_CONTROL_CONTINUE:
1114 DesiredAccess = SERVICE_PAUSE_CONTINUE;
1115 break;
1116
1117 case SERVICE_CONTROL_INTERROGATE:
1118 DesiredAccess = SERVICE_INTERROGATE;
1119 break;
1120
1121 default:
1122 if (dwControl >= 128 && dwControl <= 255)
1123 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
1124 else
1125 return ERROR_INVALID_PARAMETER;
1126 break;
1127 }
1128
1129 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1130 DesiredAccess))
1131 return ERROR_ACCESS_DENIED;
1132
1133 /* Return the current service status information */
1134 RtlCopyMemory(lpServiceStatus,
1135 &lpService->Status,
1136 sizeof(SERVICE_STATUS));
1137
1138 if (dwControl == SERVICE_CONTROL_STOP)
1139 {
1140 /* Check if the service has dependencies running as windows
1141 doesn't stop a service that does */
1142
1143 /* Open the Services Reg key */
1144 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1145 L"System\\CurrentControlSet\\Services",
1146 0,
1147 KEY_READ,
1148 &hServicesKey);
1149 if (dwError != ERROR_SUCCESS)
1150 {
1151 DPRINT("Failed to open services key\n");
1152 return dwError;
1153 }
1154
1155 /* Call the internal function with NULL, just to get bytes we need */
1156 Int_EnumDependentServicesW(hServicesKey,
1157 lpService,
1158 SERVICE_ACTIVE,
1159 NULL,
1160 &pcbBytesNeeded,
1161 &dwServicesReturned);
1162
1163 RegCloseKey(hServicesKey);
1164
1165 /* If pcbBytesNeeded is not zero then there are services running that
1166 are dependent on this service */
1167 if (pcbBytesNeeded != 0)
1168 {
1169 DPRINT("Service has running dependencies. Failed to stop service.\n");
1170 return ERROR_DEPENDENT_SERVICES_RUNNING;
1171 }
1172 }
1173
1174 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1175 {
1176 /* Send control code to the driver */
1177 dwError = ScmControlDriver(lpService,
1178 dwControl,
1179 lpServiceStatus);
1180 }
1181 else
1182 {
1183 dwControlsAccepted = lpService->Status.dwControlsAccepted;
1184 dwCurrentState = lpService->Status.dwCurrentState;
1185
1186 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1187 if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
1188 return ERROR_SERVICE_NOT_ACTIVE;
1189
1190 /* Check the current state before sending a control request */
1191 switch (dwCurrentState)
1192 {
1193 case SERVICE_STOP_PENDING:
1194 case SERVICE_STOPPED:
1195 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1196
1197 case SERVICE_START_PENDING:
1198 switch (dwControl)
1199 {
1200 case SERVICE_CONTROL_STOP:
1201 break;
1202
1203 case SERVICE_CONTROL_INTERROGATE:
1204 RtlCopyMemory(lpServiceStatus,
1205 &lpService->Status,
1206 sizeof(SERVICE_STATUS));
1207 return ERROR_SUCCESS;
1208
1209 default:
1210 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1211 }
1212 break;
1213 }
1214
1215 /* Check if the control code is acceptable to the service */
1216 switch (dwControl)
1217 {
1218 case SERVICE_CONTROL_STOP:
1219 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
1220 return ERROR_INVALID_SERVICE_CONTROL;
1221 break;
1222
1223 case SERVICE_CONTROL_PAUSE:
1224 case SERVICE_CONTROL_CONTINUE:
1225 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1226 return ERROR_INVALID_SERVICE_CONTROL;
1227 break;
1228 }
1229
1230 /* Send control code to the service */
1231 dwError = ScmControlService(lpService->lpImage->hControlPipe,
1232 lpService->lpServiceName,
1233 (SERVICE_STATUS_HANDLE)lpService,
1234 dwControl);
1235
1236 /* Return service status information */
1237 RtlCopyMemory(lpServiceStatus,
1238 &lpService->Status,
1239 sizeof(SERVICE_STATUS));
1240 }
1241
1242 if (dwError == ERROR_SUCCESS)
1243 {
1244 if (dwControl == SERVICE_CONTROL_STOP ||
1245 dwControl == SERVICE_CONTROL_PAUSE ||
1246 dwControl == SERVICE_CONTROL_CONTINUE)
1247 {
1248 /* Log a successful send control */
1249
1250 switch (dwControl)
1251 {
1252 case SERVICE_CONTROL_STOP:
1253 uID = IDS_SERVICE_STOP;
1254 break;
1255
1256 case SERVICE_CONTROL_PAUSE:
1257 uID = IDS_SERVICE_PAUSE;
1258 break;
1259
1260 case SERVICE_CONTROL_CONTINUE:
1261 uID = IDS_SERVICE_RESUME;
1262 break;
1263 }
1264 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, 80);
1265
1266 lpLogStrings[0] = lpService->lpDisplayName;
1267 lpLogStrings[1] = szLogBuffer;
1268
1269 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
1270 EVENTLOG_INFORMATION_TYPE,
1271 2,
1272 lpLogStrings);
1273 }
1274 }
1275
1276 return dwError;
1277 }
1278
1279
1280 /* Function 2 */
1281 DWORD
1282 WINAPI
1283 RDeleteService(
1284 SC_RPC_HANDLE hService)
1285 {
1286 PSERVICE_HANDLE hSvc;
1287 PSERVICE lpService;
1288 DWORD dwError;
1289
1290 DPRINT("RDeleteService() called\n");
1291
1292 if (ScmShutdown)
1293 return ERROR_SHUTDOWN_IN_PROGRESS;
1294
1295 hSvc = ScmGetServiceFromHandle(hService);
1296 if (hSvc == NULL)
1297 {
1298 DPRINT1("Invalid service handle!\n");
1299 return ERROR_INVALID_HANDLE;
1300 }
1301
1302 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1303 DELETE))
1304 return ERROR_ACCESS_DENIED;
1305
1306 lpService = hSvc->ServiceEntry;
1307 if (lpService == NULL)
1308 {
1309 DPRINT("lpService == NULL!\n");
1310 return ERROR_INVALID_HANDLE;
1311 }
1312
1313 /* Lock the service database exclusively */
1314 ScmLockDatabaseExclusive();
1315
1316 if (lpService->bDeleted)
1317 {
1318 DPRINT("The service has already been marked for delete!\n");
1319 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1320 goto Done;
1321 }
1322
1323 /* Mark service for delete */
1324 lpService->bDeleted = TRUE;
1325
1326 dwError = ScmMarkServiceForDelete(lpService);
1327
1328 Done:
1329 /* Unlock the service database */
1330 ScmUnlockDatabase();
1331
1332 DPRINT("RDeleteService() done\n");
1333
1334 return dwError;
1335 }
1336
1337
1338 /* Function 3 */
1339 DWORD
1340 WINAPI
1341 RLockServiceDatabase(
1342 SC_RPC_HANDLE hSCManager,
1343 LPSC_RPC_LOCK lpLock)
1344 {
1345 PMANAGER_HANDLE hMgr;
1346
1347 DPRINT("RLockServiceDatabase() called\n");
1348
1349 *lpLock = NULL;
1350
1351 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
1352 if (hMgr == NULL)
1353 {
1354 DPRINT1("Invalid service manager handle!\n");
1355 return ERROR_INVALID_HANDLE;
1356 }
1357
1358 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
1359 SC_MANAGER_LOCK))
1360 return ERROR_ACCESS_DENIED;
1361
1362 return ScmAcquireServiceStartLock(FALSE, lpLock);
1363 }
1364
1365
1366 /* Function 4 */
1367 DWORD
1368 WINAPI
1369 RQueryServiceObjectSecurity(
1370 SC_RPC_HANDLE hService,
1371 SECURITY_INFORMATION dwSecurityInformation,
1372 LPBYTE lpSecurityDescriptor,
1373 DWORD cbBufSize,
1374 LPBOUNDED_DWORD_256K pcbBytesNeeded)
1375 {
1376 PSERVICE_HANDLE hSvc;
1377 PSERVICE lpService;
1378 ULONG DesiredAccess = 0;
1379 NTSTATUS Status;
1380 DWORD dwBytesNeeded;
1381 DWORD dwError;
1382
1383 DPRINT("RQueryServiceObjectSecurity() called\n");
1384
1385 hSvc = ScmGetServiceFromHandle(hService);
1386 if (hSvc == NULL)
1387 {
1388 DPRINT1("Invalid service handle!\n");
1389 return ERROR_INVALID_HANDLE;
1390 }
1391
1392 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1393 GROUP_SECURITY_INFORMATION |
1394 OWNER_SECURITY_INFORMATION))
1395 DesiredAccess |= READ_CONTROL;
1396
1397 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1398 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1399
1400 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1401 DesiredAccess))
1402 {
1403 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1404 return ERROR_ACCESS_DENIED;
1405 }
1406
1407 lpService = hSvc->ServiceEntry;
1408 if (lpService == NULL)
1409 {
1410 DPRINT("lpService == NULL!\n");
1411 return ERROR_INVALID_HANDLE;
1412 }
1413
1414 /* Lock the service database */
1415 ScmLockDatabaseShared();
1416
1417 /* Retrieve the security descriptor */
1418 Status = RtlQuerySecurityObject(lpService->pSecurityDescriptor,
1419 dwSecurityInformation,
1420 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1421 cbBufSize,
1422 &dwBytesNeeded);
1423
1424 /* Unlock the service database */
1425 ScmUnlockDatabase();
1426
1427 if (NT_SUCCESS(Status))
1428 {
1429 *pcbBytesNeeded = dwBytesNeeded;
1430 dwError = STATUS_SUCCESS;
1431 }
1432 else if (Status == STATUS_BUFFER_TOO_SMALL)
1433 {
1434 *pcbBytesNeeded = dwBytesNeeded;
1435 dwError = ERROR_INSUFFICIENT_BUFFER;
1436 }
1437 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
1438 {
1439 dwError = ERROR_GEN_FAILURE;
1440 }
1441 else
1442 {
1443 dwError = RtlNtStatusToDosError(Status);
1444 }
1445
1446 return dwError;
1447 }
1448
1449
1450 /* Function 5 */
1451 DWORD
1452 WINAPI
1453 RSetServiceObjectSecurity(
1454 SC_RPC_HANDLE hService,
1455 DWORD dwSecurityInformation,
1456 LPBYTE lpSecurityDescriptor,
1457 DWORD dwSecurityDescriptorSize)
1458 {
1459 PSERVICE_HANDLE hSvc;
1460 PSERVICE lpService;
1461 ACCESS_MASK DesiredAccess = 0;
1462 HANDLE hToken = NULL;
1463 HKEY hServiceKey = NULL;
1464 BOOL bDatabaseLocked = FALSE;
1465 NTSTATUS Status;
1466 DWORD dwError;
1467
1468 DPRINT("RSetServiceObjectSecurity() called\n");
1469
1470 hSvc = ScmGetServiceFromHandle(hService);
1471 if (hSvc == NULL)
1472 {
1473 DPRINT1("Invalid service handle!\n");
1474 return ERROR_INVALID_HANDLE;
1475 }
1476
1477 if (dwSecurityInformation == 0 ||
1478 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1479 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
1480 return ERROR_INVALID_PARAMETER;
1481
1482 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1483 return ERROR_INVALID_PARAMETER;
1484
1485 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1486 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1487
1488 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1489 DesiredAccess |= WRITE_DAC;
1490
1491 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1492 DesiredAccess |= WRITE_OWNER;
1493
1494 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1495 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1496 return ERROR_INVALID_PARAMETER;
1497
1498 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1499 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1500 return ERROR_INVALID_PARAMETER;
1501
1502 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1503 DesiredAccess))
1504 {
1505 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1506 return ERROR_ACCESS_DENIED;
1507 }
1508
1509 lpService = hSvc->ServiceEntry;
1510 if (lpService == NULL)
1511 {
1512 DPRINT1("lpService == NULL!\n");
1513 return ERROR_INVALID_HANDLE;
1514 }
1515
1516 if (lpService->bDeleted)
1517 return ERROR_SERVICE_MARKED_FOR_DELETE;
1518
1519 #if 0
1520 RpcImpersonateClient(NULL);
1521
1522 Status = NtOpenThreadToken(NtCurrentThread(),
1523 8,
1524 TRUE,
1525 &hToken);
1526 if (!NT_SUCCESS(Status))
1527 return RtlNtStatusToDosError(Status);
1528
1529 RpcRevertToSelf();
1530 #endif
1531
1532 /* Build the new security descriptor */
1533 Status = RtlSetSecurityObject(dwSecurityInformation,
1534 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1535 &lpService->pSecurityDescriptor,
1536 &ScmServiceMapping,
1537 hToken);
1538 if (!NT_SUCCESS(Status))
1539 {
1540 dwError = RtlNtStatusToDosError(Status);
1541 goto Done;
1542 }
1543
1544 /* Lock the service database exclusive */
1545 ScmLockDatabaseExclusive();
1546 bDatabaseLocked = TRUE;
1547
1548 /* Open the service key */
1549 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1550 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
1551 &hServiceKey);
1552 if (dwError != ERROR_SUCCESS)
1553 goto Done;
1554
1555 /* Store the new security descriptor */
1556 dwError = ScmWriteSecurityDescriptor(hServiceKey,
1557 lpService->pSecurityDescriptor);
1558
1559 RegFlushKey(hServiceKey);
1560
1561 Done:
1562 if (hServiceKey != NULL)
1563 RegCloseKey(hServiceKey);
1564
1565 /* Unlock service database */
1566 if (bDatabaseLocked == TRUE)
1567 ScmUnlockDatabase();
1568
1569 if (hToken != NULL)
1570 NtClose(hToken);
1571
1572 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1573
1574 return dwError;
1575 }
1576
1577
1578 /* Function 6 */
1579 DWORD
1580 WINAPI
1581 RQueryServiceStatus(
1582 SC_RPC_HANDLE hService,
1583 LPSERVICE_STATUS lpServiceStatus)
1584 {
1585 PSERVICE_HANDLE hSvc;
1586 PSERVICE lpService;
1587
1588 DPRINT("RQueryServiceStatus() called\n");
1589
1590 if (ScmShutdown)
1591 return ERROR_SHUTDOWN_IN_PROGRESS;
1592
1593 hSvc = ScmGetServiceFromHandle(hService);
1594 if (hSvc == NULL)
1595 {
1596 DPRINT1("Invalid service handle!\n");
1597 return ERROR_INVALID_HANDLE;
1598 }
1599
1600 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1601 SERVICE_QUERY_STATUS))
1602 {
1603 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1604 return ERROR_ACCESS_DENIED;
1605 }
1606
1607 lpService = hSvc->ServiceEntry;
1608 if (lpService == NULL)
1609 {
1610 DPRINT("lpService == NULL!\n");
1611 return ERROR_INVALID_HANDLE;
1612 }
1613
1614 /* Lock the service database shared */
1615 ScmLockDatabaseShared();
1616
1617 /* Return service status information */
1618 RtlCopyMemory(lpServiceStatus,
1619 &lpService->Status,
1620 sizeof(SERVICE_STATUS));
1621
1622 /* Unlock the service database */
1623 ScmUnlockDatabase();
1624
1625 return ERROR_SUCCESS;
1626 }
1627
1628
1629 static BOOL
1630 ScmIsValidServiceState(DWORD dwCurrentState)
1631 {
1632 switch (dwCurrentState)
1633 {
1634 case SERVICE_STOPPED:
1635 case SERVICE_START_PENDING:
1636 case SERVICE_STOP_PENDING:
1637 case SERVICE_RUNNING:
1638 case SERVICE_CONTINUE_PENDING:
1639 case SERVICE_PAUSE_PENDING:
1640 case SERVICE_PAUSED:
1641 return TRUE;
1642
1643 default:
1644 return FALSE;
1645 }
1646 }
1647
1648
1649 /* Function 7 */
1650 DWORD
1651 WINAPI
1652 RSetServiceStatus(
1653 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1654 LPSERVICE_STATUS lpServiceStatus)
1655 {
1656 PSERVICE lpService;
1657 DWORD dwPreviousState;
1658 DWORD dwPreviousType;
1659 LPCWSTR lpLogStrings[2];
1660 WCHAR szLogBuffer[80];
1661 UINT uID;
1662
1663 DPRINT("RSetServiceStatus() called\n");
1664 DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1665 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
1666 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1667 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1668 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1669 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1670 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1671 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1672
1673 if (hServiceStatus == 0)
1674 {
1675 DPRINT("hServiceStatus == NULL!\n");
1676 return ERROR_INVALID_HANDLE;
1677 }
1678
1679 lpService = (PSERVICE)hServiceStatus;
1680
1681 /* Check current state */
1682 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1683 {
1684 DPRINT("Invalid service state!\n");
1685 return ERROR_INVALID_DATA;
1686 }
1687
1688 /* Check service type */
1689 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1690 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1691 {
1692 DPRINT("Invalid service type!\n");
1693 return ERROR_INVALID_DATA;
1694 }
1695
1696 /* Check accepted controls */
1697 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1698 {
1699 DPRINT("Invalid controls accepted!\n");
1700 return ERROR_INVALID_DATA;
1701 }
1702
1703 /* Set the wait hint and check point only if the service is in a pending state,
1704 otherwise they should be 0 */
1705 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1706 lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
1707 lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
1708 {
1709 lpServiceStatus->dwWaitHint = 0;
1710 lpServiceStatus->dwCheckPoint = 0;
1711 }
1712
1713 /* Lock the service database exclusively */
1714 ScmLockDatabaseExclusive();
1715
1716 /* Save the current service state */
1717 dwPreviousState = lpService->Status.dwCurrentState;
1718
1719 /* Save the current service type */
1720 dwPreviousType = lpService->Status.dwServiceType;
1721
1722 /* Update the service status */
1723 RtlCopyMemory(&lpService->Status,
1724 lpServiceStatus,
1725 sizeof(SERVICE_STATUS));
1726
1727 /* Restore the previous service type */
1728 lpService->Status.dwServiceType = dwPreviousType;
1729
1730 /* Handle a stopped service */
1731 if ((lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1732 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED))
1733 {
1734 /* Decrement the image run counter */
1735 lpService->lpImage->dwImageRunCount--;
1736
1737 /* If we just stopped the last running service... */
1738 if (lpService->lpImage->dwImageRunCount == 0)
1739 {
1740 /* Stop the dispatcher thread */
1741 ScmControlService(lpService->lpImage->hControlPipe,
1742 L"",
1743 (SERVICE_STATUS_HANDLE)lpService,
1744 SERVICE_CONTROL_STOP);
1745
1746 /* Remove the service image */
1747 ScmRemoveServiceImage(lpService->lpImage);
1748 lpService->lpImage = NULL;
1749 }
1750 }
1751
1752 /* Unlock the service database */
1753 ScmUnlockDatabase();
1754
1755 if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
1756 (dwPreviousState != SERVICE_STOPPED) &&
1757 (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS))
1758 {
1759 /* Log a failed service stop */
1760 swprintf(szLogBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode);
1761 lpLogStrings[0] = lpService->lpDisplayName;
1762 lpLogStrings[1] = szLogBuffer;
1763
1764 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED,
1765 EVENTLOG_ERROR_TYPE,
1766 2,
1767 lpLogStrings);
1768 }
1769 else if (lpServiceStatus->dwCurrentState != dwPreviousState &&
1770 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1771 lpServiceStatus->dwCurrentState == SERVICE_RUNNING ||
1772 lpServiceStatus->dwCurrentState == SERVICE_PAUSED))
1773 {
1774 /* Log a successful service status change */
1775 switch(lpServiceStatus->dwCurrentState)
1776 {
1777 case SERVICE_STOPPED:
1778 uID = IDS_SERVICE_STOPPED;
1779 break;
1780
1781 case SERVICE_RUNNING:
1782 uID = IDS_SERVICE_RUNNING;
1783 break;
1784
1785 case SERVICE_PAUSED:
1786 uID = IDS_SERVICE_PAUSED;
1787 break;
1788 }
1789
1790 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, 80);
1791 lpLogStrings[0] = lpService->lpDisplayName;
1792 lpLogStrings[1] = szLogBuffer;
1793
1794 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS,
1795 EVENTLOG_INFORMATION_TYPE,
1796 2,
1797 lpLogStrings);
1798 }
1799
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");
3368