43b953096bcf5f03b8553b46a0d6fb5cd09ed322
[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 case SERVICE_CONTROL_PARAMCHANGE:
1116 case SERVICE_CONTROL_NETBINDADD:
1117 case SERVICE_CONTROL_NETBINDREMOVE:
1118 case SERVICE_CONTROL_NETBINDENABLE:
1119 case SERVICE_CONTROL_NETBINDDISABLE:
1120 DesiredAccess = SERVICE_PAUSE_CONTINUE;
1121 break;
1122
1123 case SERVICE_CONTROL_INTERROGATE:
1124 DesiredAccess = SERVICE_INTERROGATE;
1125 break;
1126
1127 default:
1128 if (dwControl >= 128 && dwControl <= 255)
1129 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
1130 else
1131 return ERROR_INVALID_PARAMETER;
1132 break;
1133 }
1134
1135 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1136 DesiredAccess))
1137 return ERROR_ACCESS_DENIED;
1138
1139 /* Return the current service status information */
1140 RtlCopyMemory(lpServiceStatus,
1141 &lpService->Status,
1142 sizeof(SERVICE_STATUS));
1143
1144 if (dwControl == SERVICE_CONTROL_STOP)
1145 {
1146 /* Check if the service has dependencies running as windows
1147 doesn't stop a service that does */
1148
1149 /* Open the Services Reg key */
1150 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1151 L"System\\CurrentControlSet\\Services",
1152 0,
1153 KEY_READ,
1154 &hServicesKey);
1155 if (dwError != ERROR_SUCCESS)
1156 {
1157 DPRINT("Failed to open services key\n");
1158 return dwError;
1159 }
1160
1161 /* Call the internal function with NULL, just to get bytes we need */
1162 Int_EnumDependentServicesW(hServicesKey,
1163 lpService,
1164 SERVICE_ACTIVE,
1165 NULL,
1166 &pcbBytesNeeded,
1167 &dwServicesReturned);
1168
1169 RegCloseKey(hServicesKey);
1170
1171 /* If pcbBytesNeeded is not zero then there are services running that
1172 are dependent on this service */
1173 if (pcbBytesNeeded != 0)
1174 {
1175 DPRINT("Service has running dependencies. Failed to stop service.\n");
1176 return ERROR_DEPENDENT_SERVICES_RUNNING;
1177 }
1178 }
1179
1180 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1181 {
1182 /* Send control code to the driver */
1183 dwError = ScmControlDriver(lpService,
1184 dwControl,
1185 lpServiceStatus);
1186 }
1187 else
1188 {
1189 dwControlsAccepted = lpService->Status.dwControlsAccepted;
1190 dwCurrentState = lpService->Status.dwCurrentState;
1191
1192 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1193 if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
1194 return ERROR_SERVICE_NOT_ACTIVE;
1195
1196 /* Check the current state before sending a control request */
1197 switch (dwCurrentState)
1198 {
1199 case SERVICE_STOP_PENDING:
1200 case SERVICE_STOPPED:
1201 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1202
1203 case SERVICE_START_PENDING:
1204 switch (dwControl)
1205 {
1206 case SERVICE_CONTROL_STOP:
1207 break;
1208
1209 case SERVICE_CONTROL_INTERROGATE:
1210 RtlCopyMemory(lpServiceStatus,
1211 &lpService->Status,
1212 sizeof(SERVICE_STATUS));
1213 return ERROR_SUCCESS;
1214
1215 default:
1216 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1217 }
1218 break;
1219 }
1220
1221 /* Check if the control code is acceptable to the service */
1222 switch (dwControl)
1223 {
1224 case SERVICE_CONTROL_STOP:
1225 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
1226 return ERROR_INVALID_SERVICE_CONTROL;
1227 break;
1228
1229 case SERVICE_CONTROL_PAUSE:
1230 case SERVICE_CONTROL_CONTINUE:
1231 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1232 return ERROR_INVALID_SERVICE_CONTROL;
1233 break;
1234
1235 case SERVICE_CONTROL_PARAMCHANGE:
1236 if ((dwControlsAccepted & SERVICE_ACCEPT_PARAMCHANGE) == 0)
1237 return ERROR_INVALID_SERVICE_CONTROL;
1238 break;
1239
1240 case SERVICE_CONTROL_NETBINDADD:
1241 case SERVICE_CONTROL_NETBINDREMOVE:
1242 case SERVICE_CONTROL_NETBINDENABLE:
1243 case SERVICE_CONTROL_NETBINDDISABLE:
1244 if ((dwControlsAccepted & SERVICE_ACCEPT_NETBINDCHANGE) == 0)
1245 return ERROR_INVALID_SERVICE_CONTROL;
1246 break;
1247 }
1248
1249 /* Send control code to the service */
1250 dwError = ScmControlService(lpService->lpImage->hControlPipe,
1251 lpService->lpServiceName,
1252 (SERVICE_STATUS_HANDLE)lpService,
1253 dwControl);
1254
1255 /* Return service status information */
1256 RtlCopyMemory(lpServiceStatus,
1257 &lpService->Status,
1258 sizeof(SERVICE_STATUS));
1259 }
1260
1261 if (dwError == ERROR_SUCCESS)
1262 {
1263 if (dwControl == SERVICE_CONTROL_STOP ||
1264 dwControl == SERVICE_CONTROL_PAUSE ||
1265 dwControl == SERVICE_CONTROL_CONTINUE)
1266 {
1267 /* Log a successful send control */
1268
1269 switch (dwControl)
1270 {
1271 case SERVICE_CONTROL_STOP:
1272 uID = IDS_SERVICE_STOP;
1273 break;
1274
1275 case SERVICE_CONTROL_PAUSE:
1276 uID = IDS_SERVICE_PAUSE;
1277 break;
1278
1279 case SERVICE_CONTROL_CONTINUE:
1280 uID = IDS_SERVICE_RESUME;
1281 break;
1282 }
1283 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1284
1285 lpLogStrings[0] = lpService->lpDisplayName;
1286 lpLogStrings[1] = szLogBuffer;
1287
1288 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
1289 EVENTLOG_INFORMATION_TYPE,
1290 2,
1291 lpLogStrings);
1292 }
1293 }
1294
1295 return dwError;
1296 }
1297
1298
1299 /* Function 2 */
1300 DWORD
1301 WINAPI
1302 RDeleteService(
1303 SC_RPC_HANDLE hService)
1304 {
1305 PSERVICE_HANDLE hSvc;
1306 PSERVICE lpService;
1307 DWORD dwError;
1308
1309 DPRINT("RDeleteService() called\n");
1310
1311 if (ScmShutdown)
1312 return ERROR_SHUTDOWN_IN_PROGRESS;
1313
1314 hSvc = ScmGetServiceFromHandle(hService);
1315 if (hSvc == NULL)
1316 {
1317 DPRINT1("Invalid service handle!\n");
1318 return ERROR_INVALID_HANDLE;
1319 }
1320
1321 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1322 DELETE))
1323 return ERROR_ACCESS_DENIED;
1324
1325 lpService = hSvc->ServiceEntry;
1326 if (lpService == NULL)
1327 {
1328 DPRINT("lpService == NULL!\n");
1329 return ERROR_INVALID_HANDLE;
1330 }
1331
1332 /* Lock the service database exclusively */
1333 ScmLockDatabaseExclusive();
1334
1335 if (lpService->bDeleted)
1336 {
1337 DPRINT("The service has already been marked for delete!\n");
1338 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1339 goto Done;
1340 }
1341
1342 /* Mark service for delete */
1343 lpService->bDeleted = TRUE;
1344
1345 dwError = ScmMarkServiceForDelete(lpService);
1346
1347 Done:
1348 /* Unlock the service database */
1349 ScmUnlockDatabase();
1350
1351 DPRINT("RDeleteService() done\n");
1352
1353 return dwError;
1354 }
1355
1356
1357 /* Function 3 */
1358 DWORD
1359 WINAPI
1360 RLockServiceDatabase(
1361 SC_RPC_HANDLE hSCManager,
1362 LPSC_RPC_LOCK lpLock)
1363 {
1364 PMANAGER_HANDLE hMgr;
1365
1366 DPRINT("RLockServiceDatabase() called\n");
1367
1368 *lpLock = NULL;
1369
1370 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
1371 if (hMgr == NULL)
1372 {
1373 DPRINT1("Invalid service manager handle!\n");
1374 return ERROR_INVALID_HANDLE;
1375 }
1376
1377 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
1378 SC_MANAGER_LOCK))
1379 return ERROR_ACCESS_DENIED;
1380
1381 return ScmAcquireServiceStartLock(FALSE, lpLock);
1382 }
1383
1384
1385 /* Function 4 */
1386 DWORD
1387 WINAPI
1388 RQueryServiceObjectSecurity(
1389 SC_RPC_HANDLE hService,
1390 SECURITY_INFORMATION dwSecurityInformation,
1391 LPBYTE lpSecurityDescriptor,
1392 DWORD cbBufSize,
1393 LPBOUNDED_DWORD_256K pcbBytesNeeded)
1394 {
1395 PSERVICE_HANDLE hSvc;
1396 PSERVICE lpService;
1397 ULONG DesiredAccess = 0;
1398 NTSTATUS Status;
1399 DWORD dwBytesNeeded;
1400 DWORD dwError;
1401
1402 DPRINT("RQueryServiceObjectSecurity() called\n");
1403
1404 hSvc = ScmGetServiceFromHandle(hService);
1405 if (hSvc == NULL)
1406 {
1407 DPRINT1("Invalid service handle!\n");
1408 return ERROR_INVALID_HANDLE;
1409 }
1410
1411 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1412 GROUP_SECURITY_INFORMATION |
1413 OWNER_SECURITY_INFORMATION))
1414 DesiredAccess |= READ_CONTROL;
1415
1416 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1417 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1418
1419 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1420 DesiredAccess))
1421 {
1422 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1423 return ERROR_ACCESS_DENIED;
1424 }
1425
1426 lpService = hSvc->ServiceEntry;
1427 if (lpService == NULL)
1428 {
1429 DPRINT("lpService == NULL!\n");
1430 return ERROR_INVALID_HANDLE;
1431 }
1432
1433 /* Lock the service database */
1434 ScmLockDatabaseShared();
1435
1436 /* Retrieve the security descriptor */
1437 Status = RtlQuerySecurityObject(lpService->pSecurityDescriptor,
1438 dwSecurityInformation,
1439 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1440 cbBufSize,
1441 &dwBytesNeeded);
1442
1443 /* Unlock the service database */
1444 ScmUnlockDatabase();
1445
1446 if (NT_SUCCESS(Status))
1447 {
1448 *pcbBytesNeeded = dwBytesNeeded;
1449 dwError = STATUS_SUCCESS;
1450 }
1451 else if (Status == STATUS_BUFFER_TOO_SMALL)
1452 {
1453 *pcbBytesNeeded = dwBytesNeeded;
1454 dwError = ERROR_INSUFFICIENT_BUFFER;
1455 }
1456 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
1457 {
1458 dwError = ERROR_GEN_FAILURE;
1459 }
1460 else
1461 {
1462 dwError = RtlNtStatusToDosError(Status);
1463 }
1464
1465 return dwError;
1466 }
1467
1468
1469 /* Function 5 */
1470 DWORD
1471 WINAPI
1472 RSetServiceObjectSecurity(
1473 SC_RPC_HANDLE hService,
1474 DWORD dwSecurityInformation,
1475 LPBYTE lpSecurityDescriptor,
1476 DWORD dwSecurityDescriptorSize)
1477 {
1478 PSERVICE_HANDLE hSvc;
1479 PSERVICE lpService;
1480 ACCESS_MASK DesiredAccess = 0;
1481 HANDLE hToken = NULL;
1482 HKEY hServiceKey = NULL;
1483 BOOL bDatabaseLocked = FALSE;
1484 NTSTATUS Status;
1485 DWORD dwError;
1486
1487 DPRINT("RSetServiceObjectSecurity() called\n");
1488
1489 hSvc = ScmGetServiceFromHandle(hService);
1490 if (hSvc == NULL)
1491 {
1492 DPRINT1("Invalid service handle!\n");
1493 return ERROR_INVALID_HANDLE;
1494 }
1495
1496 if (dwSecurityInformation == 0 ||
1497 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1498 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
1499 return ERROR_INVALID_PARAMETER;
1500
1501 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1502 return ERROR_INVALID_PARAMETER;
1503
1504 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1505 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1506
1507 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1508 DesiredAccess |= WRITE_DAC;
1509
1510 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1511 DesiredAccess |= WRITE_OWNER;
1512
1513 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1514 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1515 return ERROR_INVALID_PARAMETER;
1516
1517 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1518 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1519 return ERROR_INVALID_PARAMETER;
1520
1521 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1522 DesiredAccess))
1523 {
1524 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1525 return ERROR_ACCESS_DENIED;
1526 }
1527
1528 lpService = hSvc->ServiceEntry;
1529 if (lpService == NULL)
1530 {
1531 DPRINT1("lpService == NULL!\n");
1532 return ERROR_INVALID_HANDLE;
1533 }
1534
1535 if (lpService->bDeleted)
1536 return ERROR_SERVICE_MARKED_FOR_DELETE;
1537
1538 #if 0
1539 RpcImpersonateClient(NULL);
1540
1541 Status = NtOpenThreadToken(NtCurrentThread(),
1542 8,
1543 TRUE,
1544 &hToken);
1545 if (!NT_SUCCESS(Status))
1546 return RtlNtStatusToDosError(Status);
1547
1548 RpcRevertToSelf();
1549 #endif
1550
1551 /* Build the new security descriptor */
1552 Status = RtlSetSecurityObject(dwSecurityInformation,
1553 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1554 &lpService->pSecurityDescriptor,
1555 &ScmServiceMapping,
1556 hToken);
1557 if (!NT_SUCCESS(Status))
1558 {
1559 dwError = RtlNtStatusToDosError(Status);
1560 goto Done;
1561 }
1562
1563 /* Lock the service database exclusive */
1564 ScmLockDatabaseExclusive();
1565 bDatabaseLocked = TRUE;
1566
1567 /* Open the service key */
1568 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1569 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
1570 &hServiceKey);
1571 if (dwError != ERROR_SUCCESS)
1572 goto Done;
1573
1574 /* Store the new security descriptor */
1575 dwError = ScmWriteSecurityDescriptor(hServiceKey,
1576 lpService->pSecurityDescriptor);
1577
1578 RegFlushKey(hServiceKey);
1579
1580 Done:
1581 if (hServiceKey != NULL)
1582 RegCloseKey(hServiceKey);
1583
1584 /* Unlock service database */
1585 if (bDatabaseLocked == TRUE)
1586 ScmUnlockDatabase();
1587
1588 if (hToken != NULL)
1589 NtClose(hToken);
1590
1591 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1592
1593 return dwError;
1594 }
1595
1596
1597 /* Function 6 */
1598 DWORD
1599 WINAPI
1600 RQueryServiceStatus(
1601 SC_RPC_HANDLE hService,
1602 LPSERVICE_STATUS lpServiceStatus)
1603 {
1604 PSERVICE_HANDLE hSvc;
1605 PSERVICE lpService;
1606
1607 DPRINT("RQueryServiceStatus() called\n");
1608
1609 if (ScmShutdown)
1610 return ERROR_SHUTDOWN_IN_PROGRESS;
1611
1612 hSvc = ScmGetServiceFromHandle(hService);
1613 if (hSvc == NULL)
1614 {
1615 DPRINT1("Invalid service handle!\n");
1616 return ERROR_INVALID_HANDLE;
1617 }
1618
1619 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1620 SERVICE_QUERY_STATUS))
1621 {
1622 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1623 return ERROR_ACCESS_DENIED;
1624 }
1625
1626 lpService = hSvc->ServiceEntry;
1627 if (lpService == NULL)
1628 {
1629 DPRINT("lpService == NULL!\n");
1630 return ERROR_INVALID_HANDLE;
1631 }
1632
1633 /* Lock the service database shared */
1634 ScmLockDatabaseShared();
1635
1636 /* Return service status information */
1637 RtlCopyMemory(lpServiceStatus,
1638 &lpService->Status,
1639 sizeof(SERVICE_STATUS));
1640
1641 /* Unlock the service database */
1642 ScmUnlockDatabase();
1643
1644 return ERROR_SUCCESS;
1645 }
1646
1647
1648 static BOOL
1649 ScmIsValidServiceState(DWORD dwCurrentState)
1650 {
1651 switch (dwCurrentState)
1652 {
1653 case SERVICE_STOPPED:
1654 case SERVICE_START_PENDING:
1655 case SERVICE_STOP_PENDING:
1656 case SERVICE_RUNNING:
1657 case SERVICE_CONTINUE_PENDING:
1658 case SERVICE_PAUSE_PENDING:
1659 case SERVICE_PAUSED:
1660 return TRUE;
1661
1662 default:
1663 return FALSE;
1664 }
1665 }
1666
1667
1668 /* Function 7 */
1669 DWORD
1670 WINAPI
1671 RSetServiceStatus(
1672 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1673 LPSERVICE_STATUS lpServiceStatus)
1674 {
1675 PSERVICE lpService;
1676 DWORD dwPreviousState;
1677 DWORD dwPreviousType;
1678 LPCWSTR lpLogStrings[2];
1679 WCHAR szLogBuffer[80];
1680 UINT uID;
1681
1682 DPRINT("RSetServiceStatus() called\n");
1683 DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1684 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
1685 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1686 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1687 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1688 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1689 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1690 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1691
1692 if (hServiceStatus == 0)
1693 {
1694 DPRINT("hServiceStatus == NULL!\n");
1695 return ERROR_INVALID_HANDLE;
1696 }
1697
1698 lpService = (PSERVICE)hServiceStatus;
1699
1700 /* Check current state */
1701 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1702 {
1703 DPRINT("Invalid service state!\n");
1704 return ERROR_INVALID_DATA;
1705 }
1706
1707 /* Check service type */
1708 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1709 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1710 {
1711 DPRINT("Invalid service type!\n");
1712 return ERROR_INVALID_DATA;
1713 }
1714
1715 /* Check accepted controls */
1716 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1717 {
1718 DPRINT("Invalid controls accepted!\n");
1719 return ERROR_INVALID_DATA;
1720 }
1721
1722 /* Set the wait hint and check point only if the service is in a pending state,
1723 otherwise they should be 0 */
1724 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1725 lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
1726 lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
1727 {
1728 lpServiceStatus->dwWaitHint = 0;
1729 lpServiceStatus->dwCheckPoint = 0;
1730 }
1731
1732 /* Lock the service database exclusively */
1733 ScmLockDatabaseExclusive();
1734
1735 /* Save the current service state */
1736 dwPreviousState = lpService->Status.dwCurrentState;
1737
1738 /* Save the current service type */
1739 dwPreviousType = lpService->Status.dwServiceType;
1740
1741 /* Update the service status */
1742 RtlCopyMemory(&lpService->Status,
1743 lpServiceStatus,
1744 sizeof(SERVICE_STATUS));
1745
1746 /* Restore the previous service type */
1747 lpService->Status.dwServiceType = dwPreviousType;
1748
1749 /* Dereference a stopped service */
1750 if ((lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1751 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED))
1752 {
1753 /* Decrement the image run counter */
1754 lpService->lpImage->dwImageRunCount--;
1755
1756 /* If we just stopped the last running service... */
1757 if (lpService->lpImage->dwImageRunCount == 0)
1758 {
1759 /* Stop the dispatcher thread */
1760 ScmControlService(lpService->lpImage->hControlPipe,
1761 L"",
1762 (SERVICE_STATUS_HANDLE)lpService,
1763 SERVICE_CONTROL_STOP);
1764
1765 /* Remove the service image */
1766 ScmRemoveServiceImage(lpService->lpImage);
1767 lpService->lpImage = NULL;
1768 }
1769 }
1770
1771 /* Unlock the service database */
1772 ScmUnlockDatabase();
1773
1774 if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
1775 (dwPreviousState != SERVICE_STOPPED) &&
1776 (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS))
1777 {
1778 /* Log a failed service stop */
1779 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer),
1780 L"%lu", lpServiceStatus->dwWin32ExitCode);
1781 lpLogStrings[0] = lpService->lpDisplayName;
1782 lpLogStrings[1] = szLogBuffer;
1783
1784 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED,
1785 EVENTLOG_ERROR_TYPE,
1786 2,
1787 lpLogStrings);
1788 }
1789 else if (lpServiceStatus->dwCurrentState != dwPreviousState &&
1790 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1791 lpServiceStatus->dwCurrentState == SERVICE_RUNNING ||
1792 lpServiceStatus->dwCurrentState == SERVICE_PAUSED))
1793 {
1794 /* Log a successful service status change */
1795 switch(lpServiceStatus->dwCurrentState)
1796 {
1797 case SERVICE_STOPPED:
1798 uID = IDS_SERVICE_STOPPED;
1799 break;
1800
1801 case SERVICE_RUNNING:
1802 uID = IDS_SERVICE_RUNNING;
1803 break;
1804
1805 case SERVICE_PAUSED:
1806 uID = IDS_SERVICE_PAUSED;
1807 break;
1808 }
1809
1810 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1811 lpLogStrings[0] = lpService->lpDisplayName;
1812 lpLogStrings[1] = szLogBuffer;
1813
1814 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS,
1815 EVENTLOG_INFORMATION_TYPE,
1816 2,
1817 lpLogStrings);
1818 }
1819
1820 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1821 DPRINT("RSetServiceStatus() done\n");
1822
1823 return ERROR_SUCCESS;
1824 }
1825
1826
1827 /* Function 8 */
1828 DWORD
1829 WINAPI
1830 RUnlockServiceDatabase(
1831 LPSC_RPC_LOCK Lock)
1832 {
1833 DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1834 return ScmReleaseServiceStartLock(Lock);
1835 }
1836
1837
1838 /* Function 9 */
1839 DWORD
1840 WINAPI
1841 RNotifyBootConfigStatus(
1842 SVCCTL_HANDLEW lpMachineName,
1843 DWORD BootAcceptable)
1844 {
1845 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1846 return ERROR_SUCCESS;
1847
1848 // UNIMPLEMENTED;
1849 // return ERROR_CALL_NOT_IMPLEMENTED;
1850 }
1851
1852
1853 /* Function 10 */
1854 DWORD
1855 WINAPI
1856 RI_ScSetServiceBitsW(
1857 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1858 DWORD dwServiceBits,
1859 int bSetBitsOn,
1860 int bUpdateImmediately,
1861 wchar_t *lpString)
1862 {
1863 UNIMPLEMENTED;
1864 return ERROR_CALL_NOT_IMPLEMENTED;
1865 }
1866
1867
1868 /* Function 11 */
1869 DWORD
1870 WINAPI
1871 RChangeServiceConfigW(
1872 SC_RPC_HANDLE hService,
1873 DWORD dwServiceType,
1874 DWORD dwStartType,
1875 DWORD dwErrorControl,
1876 LPWSTR lpBinaryPathName,
1877 LPWSTR lpLoadOrderGroup,
1878 LPDWORD lpdwTagId,
1879 LPBYTE lpDependencies,
1880 DWORD dwDependSize,
1881 LPWSTR lpServiceStartName,
1882 LPBYTE lpPassword,
1883 DWORD dwPwSize,
1884 LPWSTR lpDisplayName)
1885 {
1886 DWORD dwError = ERROR_SUCCESS;
1887 PSERVICE_HANDLE hSvc;
1888 PSERVICE lpService = NULL;
1889 HKEY hServiceKey = NULL;
1890 LPWSTR lpDisplayNameW = NULL;
1891 LPWSTR lpImagePathW = NULL;
1892
1893 DPRINT("RChangeServiceConfigW() called\n");
1894 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
1895 DPRINT("dwStartType = %lu\n", dwStartType);
1896 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1897 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1898 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1899 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1900
1901 if (ScmShutdown)
1902 return ERROR_SHUTDOWN_IN_PROGRESS;
1903
1904 hSvc = ScmGetServiceFromHandle(hService);
1905 if (hSvc == NULL)
1906 {
1907 DPRINT1("Invalid service handle!\n");
1908 return ERROR_INVALID_HANDLE;
1909 }
1910
1911 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1912 SERVICE_CHANGE_CONFIG))
1913 {
1914 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1915 return ERROR_ACCESS_DENIED;
1916 }
1917
1918 /* Check for invalid service type value */
1919 if ((dwServiceType != SERVICE_NO_CHANGE) &&
1920 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
1921 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
1922 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
1923 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
1924 return ERROR_INVALID_PARAMETER;
1925
1926 /* Check for invalid start type value */
1927 if ((dwStartType != SERVICE_NO_CHANGE) &&
1928 (dwStartType != SERVICE_BOOT_START) &&
1929 (dwStartType != SERVICE_SYSTEM_START) &&
1930 (dwStartType != SERVICE_AUTO_START) &&
1931 (dwStartType != SERVICE_DEMAND_START) &&
1932 (dwStartType != SERVICE_DISABLED))
1933 return ERROR_INVALID_PARAMETER;
1934
1935 /* Only drivers can be boot start or system start services */
1936 if ((dwStartType == SERVICE_BOOT_START) ||
1937 (dwStartType == SERVICE_SYSTEM_START))
1938 {
1939 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
1940 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
1941 return ERROR_INVALID_PARAMETER;
1942 }
1943
1944 /* Check for invalid error control value */
1945 if ((dwErrorControl != SERVICE_NO_CHANGE) &&
1946 (dwErrorControl != SERVICE_ERROR_IGNORE) &&
1947 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
1948 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
1949 (dwErrorControl != SERVICE_ERROR_CRITICAL))
1950 return ERROR_INVALID_PARAMETER;
1951
1952 lpService = hSvc->ServiceEntry;
1953 if (lpService == NULL)
1954 {
1955 DPRINT("lpService == NULL!\n");
1956 return ERROR_INVALID_HANDLE;
1957 }
1958
1959 /* Lock the service database exclusively */
1960 ScmLockDatabaseExclusive();
1961
1962 if (lpService->bDeleted)
1963 {
1964 DPRINT("The service has already been marked for delete!\n");
1965 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1966 goto done;
1967 }
1968
1969 /* Open the service key */
1970 dwError = ScmOpenServiceKey(lpService->szServiceName,
1971 KEY_SET_VALUE,
1972 &hServiceKey);
1973 if (dwError != ERROR_SUCCESS)
1974 goto done;
1975
1976 /* Write service data to the registry */
1977 /* Set the display name */
1978 if (lpDisplayName != NULL && *lpDisplayName != 0)
1979 {
1980 RegSetValueExW(hServiceKey,
1981 L"DisplayName",
1982 0,
1983 REG_SZ,
1984 (LPBYTE)lpDisplayName,
1985 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
1986
1987 /* Update the display name */
1988 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
1989 HEAP_ZERO_MEMORY,
1990 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1991 if (lpDisplayNameW == NULL)
1992 {
1993 dwError = ERROR_NOT_ENOUGH_MEMORY;
1994 goto done;
1995 }
1996
1997 wcscpy(lpDisplayNameW, lpDisplayName);
1998 if (lpService->lpDisplayName != lpService->lpServiceName)
1999 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2000
2001 lpService->lpDisplayName = lpDisplayNameW;
2002 }
2003
2004 if (dwServiceType != SERVICE_NO_CHANGE)
2005 {
2006 /* Set the service type */
2007 dwError = RegSetValueExW(hServiceKey,
2008 L"Type",
2009 0,
2010 REG_DWORD,
2011 (LPBYTE)&dwServiceType,
2012 sizeof(DWORD));
2013 if (dwError != ERROR_SUCCESS)
2014 goto done;
2015
2016 lpService->Status.dwServiceType = dwServiceType;
2017 }
2018
2019 if (dwStartType != SERVICE_NO_CHANGE)
2020 {
2021 /* Set the start value */
2022 dwError = RegSetValueExW(hServiceKey,
2023 L"Start",
2024 0,
2025 REG_DWORD,
2026 (LPBYTE)&dwStartType,
2027 sizeof(DWORD));
2028 if (dwError != ERROR_SUCCESS)
2029 goto done;
2030
2031 lpService->dwStartType = dwStartType;
2032 }
2033
2034 if (dwErrorControl != SERVICE_NO_CHANGE)
2035 {
2036 /* Set the error control value */
2037 dwError = RegSetValueExW(hServiceKey,
2038 L"ErrorControl",
2039 0,
2040 REG_DWORD,
2041 (LPBYTE)&dwErrorControl,
2042 sizeof(DWORD));
2043 if (dwError != ERROR_SUCCESS)
2044 goto done;
2045
2046 lpService->dwErrorControl = dwErrorControl;
2047 }
2048
2049 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2050 {
2051 /* Set the image path */
2052 lpImagePathW = lpBinaryPathName;
2053
2054 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
2055 {
2056 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
2057 lpBinaryPathName,
2058 &lpImagePathW);
2059
2060 if (dwError != ERROR_SUCCESS)
2061 goto done;
2062 }
2063
2064 dwError = RegSetValueExW(hServiceKey,
2065 L"ImagePath",
2066 0,
2067 REG_EXPAND_SZ,
2068 (LPBYTE)lpImagePathW,
2069 (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
2070
2071 if (lpImagePathW != lpBinaryPathName)
2072 HeapFree(GetProcessHeap(), 0, lpImagePathW);
2073
2074 if (dwError != ERROR_SUCCESS)
2075 goto done;
2076 }
2077
2078 /* Set the group name */
2079 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2080 {
2081 dwError = RegSetValueExW(hServiceKey,
2082 L"Group",
2083 0,
2084 REG_SZ,
2085 (LPBYTE)lpLoadOrderGroup,
2086 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2087 if (dwError != ERROR_SUCCESS)
2088 goto done;
2089
2090 dwError = ScmSetServiceGroup(lpService,
2091 lpLoadOrderGroup);
2092 if (dwError != ERROR_SUCCESS)
2093 goto done;
2094 }
2095
2096 /* Set the tag */
2097 if (lpdwTagId != NULL)
2098 {
2099 dwError = ScmAssignNewTag(lpService);
2100 if (dwError != ERROR_SUCCESS)
2101 goto done;
2102
2103 dwError = RegSetValueExW(hServiceKey,
2104 L"Tag",
2105 0,
2106 REG_DWORD,
2107 (LPBYTE)&lpService->dwTag,
2108 sizeof(DWORD));
2109 if (dwError != ERROR_SUCCESS)
2110 goto done;
2111
2112 *lpdwTagId = lpService->dwTag;
2113 }
2114
2115 /* Write dependencies */
2116 if (lpDependencies != NULL && *lpDependencies != 0)
2117 {
2118 dwError = ScmWriteDependencies(hServiceKey,
2119 (LPWSTR)lpDependencies,
2120 dwDependSize);
2121 if (dwError != ERROR_SUCCESS)
2122 goto done;
2123 }
2124
2125 if (lpPassword != NULL)
2126 {
2127 if (wcslen((LPWSTR)lpPassword) != 0)
2128 {
2129 /* FIXME: Decrypt the password */
2130
2131 /* Write the password */
2132 dwError = ScmSetServicePassword(lpService->szServiceName,
2133 (LPCWSTR)lpPassword);
2134 if (dwError != ERROR_SUCCESS)
2135 goto done;
2136 }
2137 else
2138 {
2139 /* Delete the password */
2140 dwError = ScmSetServicePassword(lpService->szServiceName,
2141 NULL);
2142 if (dwError == ERROR_FILE_NOT_FOUND)
2143 dwError = ERROR_SUCCESS;
2144
2145 if (dwError != ERROR_SUCCESS)
2146 goto done;
2147 }
2148 }
2149
2150 done:
2151 if (hServiceKey != NULL)
2152 RegCloseKey(hServiceKey);
2153
2154 /* Unlock the service database */
2155 ScmUnlockDatabase();
2156
2157 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
2158
2159 return dwError;
2160 }
2161
2162
2163 /* Function 12 */
2164 DWORD
2165 WINAPI
2166 RCreateServiceW(
2167 SC_RPC_HANDLE hSCManager,
2168 LPCWSTR lpServiceName,
2169 LPCWSTR lpDisplayName,
2170 DWORD dwDesiredAccess,
2171 DWORD dwServiceType,
2172 DWORD dwStartType,
2173 DWORD dwErrorControl,
2174 LPCWSTR lpBinaryPathName,
2175 LPCWSTR lpLoadOrderGroup,
2176 LPDWORD lpdwTagId,
2177 LPBYTE lpDependencies,
2178 DWORD dwDependSize,
2179 LPCWSTR lpServiceStartName,
2180 LPBYTE lpPassword,
2181 DWORD dwPwSize,
2182 LPSC_RPC_HANDLE lpServiceHandle)
2183 {
2184 PMANAGER_HANDLE hManager;
2185 DWORD dwError = ERROR_SUCCESS;
2186 PSERVICE lpService = NULL;
2187 SC_HANDLE hServiceHandle = NULL;
2188 LPWSTR lpImagePath = NULL;
2189 HKEY hServiceKey = NULL;
2190 LPWSTR lpObjectName;
2191
2192 DPRINT("RCreateServiceW() called\n");
2193 DPRINT("lpServiceName = %S\n", lpServiceName);
2194 DPRINT("lpDisplayName = %S\n", lpDisplayName);
2195 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2196 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2197 DPRINT("dwStartType = %lu\n", dwStartType);
2198 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2199 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2200 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2201 DPRINT("lpdwTagId = %p\n", lpdwTagId);
2202
2203 if (ScmShutdown)
2204 return ERROR_SHUTDOWN_IN_PROGRESS;
2205
2206 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2207 if (hManager == NULL)
2208 {
2209 DPRINT1("Invalid service manager handle!\n");
2210 return ERROR_INVALID_HANDLE;
2211 }
2212
2213 /* Check access rights */
2214 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2215 SC_MANAGER_CREATE_SERVICE))
2216 {
2217 DPRINT("Insufficient access rights! 0x%lx\n",
2218 hManager->Handle.DesiredAccess);
2219 return ERROR_ACCESS_DENIED;
2220 }
2221
2222 if (wcslen(lpServiceName) == 0)
2223 {
2224 return ERROR_INVALID_NAME;
2225 }
2226
2227 if (wcslen(lpBinaryPathName) == 0)
2228 {
2229 return ERROR_INVALID_PARAMETER;
2230 }
2231
2232 /* Check for invalid service type value */
2233 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2234 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2235 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2236 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
2237 return ERROR_INVALID_PARAMETER;
2238
2239 /* Check for invalid start type value */
2240 if ((dwStartType != SERVICE_BOOT_START) &&
2241 (dwStartType != SERVICE_SYSTEM_START) &&
2242 (dwStartType != SERVICE_AUTO_START) &&
2243 (dwStartType != SERVICE_DEMAND_START) &&
2244 (dwStartType != SERVICE_DISABLED))
2245 return ERROR_INVALID_PARAMETER;
2246
2247 /* Only drivers can be boot start or system start services */
2248 if ((dwStartType == SERVICE_BOOT_START) ||
2249 (dwStartType == SERVICE_SYSTEM_START))
2250 {
2251 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2252 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2253 return ERROR_INVALID_PARAMETER;
2254 }
2255
2256 /* Check for invalid error control value */
2257 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2258 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2259 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2260 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2261 return ERROR_INVALID_PARAMETER;
2262
2263 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2264 (lpServiceStartName))
2265 {
2266 /* We allow LocalSystem to run interactive. */
2267 if (wcsicmp(lpServiceStartName, L"LocalSystem"))
2268 {
2269 return ERROR_INVALID_PARAMETER;
2270 }
2271 }
2272
2273 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2274 {
2275 return ERROR_INVALID_PARAMETER;
2276 }
2277
2278 /* Lock the service database exclusively */
2279 ScmLockDatabaseExclusive();
2280
2281 lpService = ScmGetServiceEntryByName(lpServiceName);
2282 if (lpService)
2283 {
2284 /* Unlock the service database */
2285 ScmUnlockDatabase();
2286
2287 /* Check if it is marked for deletion */
2288 if (lpService->bDeleted)
2289 return ERROR_SERVICE_MARKED_FOR_DELETE;
2290
2291 /* Return Error exist */
2292 return ERROR_SERVICE_EXISTS;
2293 }
2294
2295 if (lpDisplayName != NULL &&
2296 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2297 {
2298 /* Unlock the service database */
2299 ScmUnlockDatabase();
2300
2301 return ERROR_DUPLICATE_SERVICE_NAME;
2302 }
2303
2304 if (dwServiceType & SERVICE_DRIVER)
2305 {
2306 dwError = ScmCanonDriverImagePath(dwStartType,
2307 lpBinaryPathName,
2308 &lpImagePath);
2309 if (dwError != ERROR_SUCCESS)
2310 goto done;
2311 }
2312 else
2313 {
2314 if (dwStartType == SERVICE_BOOT_START ||
2315 dwStartType == SERVICE_SYSTEM_START)
2316 {
2317 /* Unlock the service database */
2318 ScmUnlockDatabase();
2319
2320 return ERROR_INVALID_PARAMETER;
2321 }
2322 }
2323
2324 /* Allocate a new service entry */
2325 dwError = ScmCreateNewServiceRecord(lpServiceName,
2326 &lpService,
2327 dwServiceType,
2328 dwStartType);
2329 if (dwError != ERROR_SUCCESS)
2330 goto done;
2331
2332 /* Fill the new service entry */
2333 lpService->dwErrorControl = dwErrorControl;
2334
2335 /* Fill the display name */
2336 if (lpDisplayName != NULL &&
2337 *lpDisplayName != 0 &&
2338 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2339 {
2340 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2341 HEAP_ZERO_MEMORY,
2342 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2343 if (lpService->lpDisplayName == NULL)
2344 {
2345 dwError = ERROR_NOT_ENOUGH_MEMORY;
2346 goto done;
2347 }
2348 wcscpy(lpService->lpDisplayName, lpDisplayName);
2349 }
2350
2351 /* Assign the service to a group */
2352 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2353 {
2354 dwError = ScmSetServiceGroup(lpService,
2355 lpLoadOrderGroup);
2356 if (dwError != ERROR_SUCCESS)
2357 goto done;
2358 }
2359
2360 /* Assign a new tag */
2361 if (lpdwTagId != NULL)
2362 {
2363 dwError = ScmAssignNewTag(lpService);
2364 if (dwError != ERROR_SUCCESS)
2365 goto done;
2366 }
2367
2368 /* Assign the default security descriptor */
2369 if (dwServiceType & SERVICE_WIN32)
2370 {
2371 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
2372 if (dwError != ERROR_SUCCESS)
2373 goto done;
2374 }
2375
2376 /* Write service data to the registry */
2377 /* Create the service key */
2378 dwError = ScmCreateServiceKey(lpServiceName,
2379 KEY_WRITE,
2380 &hServiceKey);
2381 if (dwError != ERROR_SUCCESS)
2382 goto done;
2383
2384 /* Set the display name */
2385 if (lpDisplayName != NULL && *lpDisplayName != 0)
2386 {
2387 RegSetValueExW(hServiceKey,
2388 L"DisplayName",
2389 0,
2390 REG_SZ,
2391 (LPBYTE)lpDisplayName,
2392 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2393 }
2394
2395 /* Set the service type */
2396 dwError = RegSetValueExW(hServiceKey,
2397 L"Type",
2398 0,
2399 REG_DWORD,
2400 (LPBYTE)&dwServiceType,
2401 sizeof(DWORD));
2402 if (dwError != ERROR_SUCCESS)
2403 goto done;
2404
2405 /* Set the start value */
2406 dwError = RegSetValueExW(hServiceKey,
2407 L"Start",
2408 0,
2409 REG_DWORD,
2410 (LPBYTE)&dwStartType,
2411 sizeof(DWORD));
2412 if (dwError != ERROR_SUCCESS)
2413 goto done;
2414
2415 /* Set the error control value */
2416 dwError = RegSetValueExW(hServiceKey,
2417 L"ErrorControl",
2418 0,
2419 REG_DWORD,
2420 (LPBYTE)&dwErrorControl,
2421 sizeof(DWORD));
2422 if (dwError != ERROR_SUCCESS)
2423 goto done;
2424
2425 /* Set the image path */
2426 if (dwServiceType & SERVICE_WIN32)
2427 {
2428 dwError = RegSetValueExW(hServiceKey,
2429 L"ImagePath",
2430 0,
2431 REG_EXPAND_SZ,
2432 (LPBYTE)lpBinaryPathName,
2433 (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2434 if (dwError != ERROR_SUCCESS)
2435 goto done;
2436 }
2437 else if (dwServiceType & SERVICE_DRIVER)
2438 {
2439 dwError = RegSetValueExW(hServiceKey,
2440 L"ImagePath",
2441 0,
2442 REG_EXPAND_SZ,
2443 (LPBYTE)lpImagePath,
2444 (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2445 if (dwError != ERROR_SUCCESS)
2446 goto done;
2447 }
2448
2449 /* Set the group name */
2450 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2451 {
2452 dwError = RegSetValueExW(hServiceKey,
2453 L"Group",
2454 0,
2455 REG_SZ,
2456 (LPBYTE)lpLoadOrderGroup,
2457 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2458 if (dwError != ERROR_SUCCESS)
2459 goto done;
2460 }
2461
2462 /* Set the service tag */
2463 if (lpdwTagId != NULL)
2464 {
2465 dwError = RegSetValueExW(hServiceKey,
2466 L"Tag",
2467 0,
2468 REG_DWORD,
2469 (LPBYTE)&lpService->dwTag,
2470 sizeof(DWORD));
2471 if (dwError != ERROR_SUCCESS)
2472 goto done;
2473 }
2474
2475 /* Write dependencies */
2476 if (lpDependencies != NULL && *lpDependencies != 0)
2477 {
2478 dwError = ScmWriteDependencies(hServiceKey,
2479 (LPCWSTR)lpDependencies,
2480 dwDependSize);
2481 if (dwError != ERROR_SUCCESS)
2482 goto done;
2483 }
2484
2485 /* Start name and password are only used by Win32 services */
2486 if (dwServiceType & SERVICE_WIN32)
2487 {
2488 /* Write service start name */
2489 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2490 dwError = RegSetValueExW(hServiceKey,
2491 L"ObjectName",
2492 0,
2493 REG_SZ,
2494 (LPBYTE)lpObjectName,
2495 (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2496 if (dwError != ERROR_SUCCESS)
2497 goto done;
2498
2499 if (lpPassword != NULL && wcslen((LPWSTR)lpPassword) != 0)
2500 {
2501 /* FIXME: Decrypt the password */
2502
2503 /* Write the password */
2504 dwError = ScmSetServicePassword(lpServiceName,
2505 (LPCWSTR)lpPassword);
2506 if (dwError != ERROR_SUCCESS)
2507 goto done;
2508 }
2509
2510 DPRINT1("\n");
2511 /* Write the security descriptor */
2512 dwError = ScmWriteSecurityDescriptor(hServiceKey,
2513 lpService->pSecurityDescriptor);
2514 if (dwError != ERROR_SUCCESS)
2515 goto done;
2516 }
2517
2518 dwError = ScmCreateServiceHandle(lpService,
2519 &hServiceHandle);
2520 if (dwError != ERROR_SUCCESS)
2521 goto done;
2522
2523 dwError = ScmCheckAccess(hServiceHandle,
2524 dwDesiredAccess);
2525 if (dwError != ERROR_SUCCESS)
2526 goto done;
2527
2528 lpService->dwRefCount = 1;
2529 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2530
2531 done:
2532 /* Unlock the service database */
2533 ScmUnlockDatabase();
2534
2535 if (hServiceKey != NULL)
2536 RegCloseKey(hServiceKey);
2537
2538 if (dwError == ERROR_SUCCESS)
2539 {
2540 DPRINT("hService %p\n", hServiceHandle);
2541 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2542
2543 if (lpdwTagId != NULL)
2544 *lpdwTagId = lpService->dwTag;
2545 }
2546 else
2547 {
2548 if (lpService != NULL &&
2549 lpService->lpServiceName != NULL)
2550 {
2551 /* Release the display name buffer */
2552 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2553 }
2554
2555 if (hServiceHandle)
2556 {
2557 /* Remove the service handle */
2558 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2559 }
2560
2561 if (lpService != NULL)
2562 {
2563 /* FIXME: remove the service entry */
2564 }
2565 }
2566
2567 if (lpImagePath != NULL)
2568 HeapFree(GetProcessHeap(), 0, lpImagePath);
2569
2570 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2571
2572 return dwError;
2573 }
2574
2575
2576 /* Function 13 */
2577 DWORD
2578 WINAPI
2579 REnumDependentServicesW(
2580 SC_RPC_HANDLE hService,
2581 DWORD dwServiceState,
2582 LPBYTE lpServices,
2583 DWORD cbBufSize,
2584 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2585 LPBOUNDED_DWORD_256K lpServicesReturned)
2586 {
2587 DWORD dwError = ERROR_SUCCESS;
2588 DWORD dwServicesReturned = 0;
2589 DWORD dwServiceCount;
2590 HKEY hServicesKey = NULL;
2591 PSERVICE_HANDLE hSvc;
2592 PSERVICE lpService = NULL;
2593 PSERVICE *lpServicesArray = NULL;
2594 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2595 LPWSTR lpStr;
2596
2597 *pcbBytesNeeded = 0;
2598 *lpServicesReturned = 0;
2599
2600 DPRINT("REnumDependentServicesW() called\n");
2601
2602 hSvc = ScmGetServiceFromHandle(hService);
2603 if (hSvc == NULL)
2604 {
2605 DPRINT1("Invalid service handle!\n");
2606 return ERROR_INVALID_HANDLE;
2607 }
2608
2609 lpService = hSvc->ServiceEntry;
2610
2611 /* Check access rights */
2612 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2613 SC_MANAGER_ENUMERATE_SERVICE))
2614 {
2615 DPRINT("Insufficient access rights! 0x%lx\n",
2616 hSvc->Handle.DesiredAccess);
2617 return ERROR_ACCESS_DENIED;
2618 }
2619
2620 /* Open the Services Reg key */
2621 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2622 L"System\\CurrentControlSet\\Services",
2623 0,
2624 KEY_READ,
2625 &hServicesKey);
2626 if (dwError != ERROR_SUCCESS)
2627 return dwError;
2628
2629 /* First determine the bytes needed and get the number of dependent services */
2630 dwError = Int_EnumDependentServicesW(hServicesKey,
2631 lpService,
2632 dwServiceState,
2633 NULL,
2634 pcbBytesNeeded,
2635 &dwServicesReturned);
2636 if (dwError != ERROR_SUCCESS)
2637 goto Done;
2638
2639 /* If buffer size is less than the bytes needed or pointer is null */
2640 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2641 {
2642 dwError = ERROR_MORE_DATA;
2643 goto Done;
2644 }
2645
2646 /* Allocate memory for array of service pointers */
2647 lpServicesArray = HeapAlloc(GetProcessHeap(),
2648 HEAP_ZERO_MEMORY,
2649 (dwServicesReturned + 1) * sizeof(PSERVICE));
2650 if (!lpServicesArray)
2651 {
2652 DPRINT1("Could not allocate a buffer!!\n");
2653 dwError = ERROR_NOT_ENOUGH_MEMORY;
2654 goto Done;
2655 }
2656
2657 dwServicesReturned = 0;
2658 *pcbBytesNeeded = 0;
2659
2660 dwError = Int_EnumDependentServicesW(hServicesKey,
2661 lpService,
2662 dwServiceState,
2663 lpServicesArray,
2664 pcbBytesNeeded,
2665 &dwServicesReturned);
2666 if (dwError != ERROR_SUCCESS)
2667 {
2668 goto Done;
2669 }
2670
2671 lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2672 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2673
2674 /* Copy EnumDepenedentService to Buffer */
2675 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2676 {
2677 lpService = lpServicesArray[dwServiceCount];
2678
2679 /* Copy status info */
2680 memcpy(&lpServicesPtr->ServiceStatus,
2681 &lpService->Status,
2682 sizeof(SERVICE_STATUS));
2683
2684 /* Copy display name */
2685 wcscpy(lpStr, lpService->lpDisplayName);
2686 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2687 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2688
2689 /* Copy service name */
2690 wcscpy(lpStr, lpService->lpServiceName);
2691 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2692 lpStr += (wcslen(lpService->lpServiceName) + 1);
2693
2694 lpServicesPtr++;
2695 }
2696
2697 *lpServicesReturned = dwServicesReturned;
2698
2699 Done:
2700 if (lpServicesArray != NULL)
2701 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2702
2703 RegCloseKey(hServicesKey);
2704
2705 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2706
2707 return dwError;
2708 }
2709
2710
2711 /* Function 14 */
2712 DWORD
2713 WINAPI
2714 REnumServicesStatusW(
2715 SC_RPC_HANDLE hSCManager,
2716 DWORD dwServiceType,
2717 DWORD dwServiceState,
2718 LPBYTE lpBuffer,
2719 DWORD dwBufSize,
2720 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2721 LPBOUNDED_DWORD_256K lpServicesReturned,
2722 LPBOUNDED_DWORD_256K lpResumeHandle)
2723 {
2724 /* Enumerate all the services, not regarding of their group */
2725 return REnumServiceGroupW(hSCManager,
2726 dwServiceType,
2727 dwServiceState,
2728 lpBuffer,
2729 dwBufSize,
2730 pcbBytesNeeded,
2731 lpServicesReturned,
2732 lpResumeHandle,
2733 NULL);
2734 }
2735
2736
2737 /* Function 15 */
2738 DWORD
2739 WINAPI
2740 ROpenSCManagerW(
2741 LPWSTR lpMachineName,
2742 LPWSTR lpDatabaseName,
2743 DWORD dwDesiredAccess,
2744 LPSC_RPC_HANDLE lpScHandle)
2745 {
2746 DWORD dwError;
2747 SC_HANDLE hHandle;
2748
2749 DPRINT("ROpenSCManagerW() called\n");
2750 DPRINT("lpMachineName = %p\n", lpMachineName);
2751 DPRINT("lpMachineName: %S\n", lpMachineName);
2752 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2753 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2754 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2755
2756 if (ScmShutdown)
2757 return ERROR_SHUTDOWN_IN_PROGRESS;
2758
2759 if (!lpScHandle)
2760 return ERROR_INVALID_PARAMETER;
2761
2762 dwError = ScmCreateManagerHandle(lpDatabaseName,
2763 &hHandle);
2764 if (dwError != ERROR_SUCCESS)
2765 {
2766 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2767 return dwError;
2768 }
2769
2770 /* Check the desired access */
2771 dwError = ScmCheckAccess(hHandle,
2772 dwDesiredAccess | SC_MANAGER_CONNECT);
2773 if (dwError != ERROR_SUCCESS)
2774 {
2775 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2776 HeapFree(GetProcessHeap(), 0, hHandle);
2777 return dwError;
2778 }
2779
2780 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2781 DPRINT("*hScm = %p\n", *lpScHandle);
2782
2783 DPRINT("ROpenSCManagerW() done\n");
2784
2785 return ERROR_SUCCESS;
2786 }
2787
2788
2789 /* Function 16 */
2790 DWORD
2791 WINAPI
2792 ROpenServiceW(
2793 SC_RPC_HANDLE hSCManager,
2794 LPWSTR lpServiceName,
2795 DWORD dwDesiredAccess,
2796 LPSC_RPC_HANDLE lpServiceHandle)
2797 {
2798 PSERVICE lpService;
2799 PMANAGER_HANDLE hManager;
2800 SC_HANDLE hHandle;
2801 DWORD dwError = ERROR_SUCCESS;
2802
2803 DPRINT("ROpenServiceW() called\n");
2804 DPRINT("hSCManager = %p\n", hSCManager);
2805 DPRINT("lpServiceName = %p\n", lpServiceName);
2806 DPRINT("lpServiceName: %S\n", lpServiceName);
2807 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2808
2809 if (ScmShutdown)
2810 return ERROR_SHUTDOWN_IN_PROGRESS;
2811
2812 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2813 if (hManager == NULL)
2814 {
2815 DPRINT1("Invalid service manager handle!\n");
2816 return ERROR_INVALID_HANDLE;
2817 }
2818
2819 if (!lpServiceHandle)
2820 return ERROR_INVALID_PARAMETER;
2821
2822 if (!lpServiceName)
2823 return ERROR_INVALID_ADDRESS;
2824
2825 /* Lock the service database exclusive */
2826 ScmLockDatabaseExclusive();
2827
2828 /* Get service database entry */
2829 lpService = ScmGetServiceEntryByName(lpServiceName);
2830 if (lpService == NULL)
2831 {
2832 DPRINT("Could not find a service!\n");
2833 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2834 goto Done;
2835 }
2836
2837 /* Create a service handle */
2838 dwError = ScmCreateServiceHandle(lpService,
2839 &hHandle);
2840 if (dwError != ERROR_SUCCESS)
2841 {
2842 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2843 goto Done;
2844 }
2845
2846 /* Check the desired access */
2847 dwError = ScmCheckAccess(hHandle,
2848 dwDesiredAccess);
2849 if (dwError != ERROR_SUCCESS)
2850 {
2851 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2852 HeapFree(GetProcessHeap(), 0, hHandle);
2853 goto Done;
2854 }
2855
2856 lpService->dwRefCount++;
2857 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2858
2859 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2860 DPRINT("*hService = %p\n", *lpServiceHandle);
2861
2862 Done:
2863 /* Unlock the service database */
2864 ScmUnlockDatabase();
2865
2866 DPRINT("ROpenServiceW() done\n");
2867
2868 return dwError;
2869 }
2870
2871
2872 /* Function 17 */
2873 DWORD
2874 WINAPI
2875 RQueryServiceConfigW(
2876 SC_RPC_HANDLE hService,
2877 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2878 DWORD cbBufSize,
2879 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2880 {
2881 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2882 DWORD dwError = ERROR_SUCCESS;
2883 PSERVICE_HANDLE hSvc;
2884 PSERVICE lpService = NULL;
2885 HKEY hServiceKey = NULL;
2886 LPWSTR lpImagePath = NULL;
2887 LPWSTR lpServiceStartName = NULL;
2888 LPWSTR lpDependencies = NULL;
2889 DWORD dwDependenciesLength = 0;
2890 DWORD dwRequiredSize;
2891 WCHAR lpEmptyString[] = {0,0};
2892 LPWSTR lpStr;
2893
2894 DPRINT("RQueryServiceConfigW() called\n");
2895
2896 if (ScmShutdown)
2897 return ERROR_SHUTDOWN_IN_PROGRESS;
2898
2899 hSvc = ScmGetServiceFromHandle(hService);
2900 if (hSvc == NULL)
2901 {
2902 DPRINT1("Invalid service handle!\n");
2903 return ERROR_INVALID_HANDLE;
2904 }
2905
2906 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2907 SERVICE_QUERY_CONFIG))
2908 {
2909 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2910 return ERROR_ACCESS_DENIED;
2911 }
2912
2913 lpService = hSvc->ServiceEntry;
2914 if (lpService == NULL)
2915 {
2916 DPRINT("lpService == NULL!\n");
2917 return ERROR_INVALID_HANDLE;
2918 }
2919
2920 /* Lock the service database shared */
2921 ScmLockDatabaseShared();
2922
2923 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2924 KEY_READ,
2925 &hServiceKey);
2926 if (dwError != ERROR_SUCCESS)
2927 goto Done;
2928
2929 /* Read the image path */
2930 dwError = ScmReadString(hServiceKey,
2931 L"ImagePath",
2932 &lpImagePath);
2933 if (dwError != ERROR_SUCCESS)
2934 goto Done;
2935
2936 /* Read the service start name */
2937 ScmReadString(hServiceKey,
2938 L"ObjectName",
2939 &lpServiceStartName);
2940
2941 /* Read the dependencies */
2942 ScmReadDependencies(hServiceKey,
2943 &lpDependencies,
2944 &dwDependenciesLength);
2945
2946 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2947
2948 if (lpImagePath != NULL)
2949 dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2950 else
2951 dwRequiredSize += 2 * sizeof(WCHAR);
2952
2953 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2954 dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2955 else
2956 dwRequiredSize += 2 * sizeof(WCHAR);
2957
2958 if (lpDependencies != NULL)
2959 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2960 else
2961 dwRequiredSize += 2 * sizeof(WCHAR);
2962
2963 if (lpServiceStartName != NULL)
2964 dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2965 else
2966 dwRequiredSize += 2 * sizeof(WCHAR);
2967
2968 if (lpService->lpDisplayName != NULL)
2969 dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2970 else
2971 dwRequiredSize += 2 * sizeof(WCHAR);
2972
2973 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2974 {
2975 dwError = ERROR_INSUFFICIENT_BUFFER;
2976 }
2977 else
2978 {
2979 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
2980 lpServiceConfig->dwStartType = lpService->dwStartType;
2981 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
2982 lpServiceConfig->dwTagId = lpService->dwTag;
2983
2984 lpStr = (LPWSTR)(lpServiceConfig + 1);
2985
2986 /* Append the image path */
2987 if (lpImagePath != NULL)
2988 {
2989 wcscpy(lpStr, lpImagePath);
2990 }
2991 else
2992 {
2993 wcscpy(lpStr, lpEmptyString);
2994 }
2995
2996 lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2997 lpStr += (wcslen(lpStr) + 1);
2998
2999 /* Append the group name */
3000 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3001 {
3002 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
3003 }
3004 else
3005 {
3006 wcscpy(lpStr, lpEmptyString);
3007 }
3008
3009 lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3010 lpStr += (wcslen(lpStr) + 1);
3011
3012 /* Append Dependencies */
3013 if (lpDependencies != NULL)
3014 {
3015 memcpy(lpStr,
3016 lpDependencies,
3017 dwDependenciesLength * sizeof(WCHAR));
3018 }
3019 else
3020 {
3021 wcscpy(lpStr, lpEmptyString);
3022 }
3023
3024 lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3025 if (lpDependencies != NULL)
3026 lpStr += dwDependenciesLength;
3027 else
3028 lpStr += (wcslen(lpStr) + 1);
3029
3030 /* Append the service start name */
3031 if (lpServiceStartName != NULL)
3032 {
3033 wcscpy(lpStr, lpServiceStartName);
3034 }
3035 else
3036 {
3037 wcscpy(lpStr, lpEmptyString);
3038 }
3039
3040 lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3041 lpStr += (wcslen(lpStr) + 1);
3042
3043 /* Append the display name */
3044 if (lpService->lpDisplayName != NULL)
3045 {
3046 wcscpy(lpStr, lpService->lpDisplayName);
3047 }
3048 else
3049 {
3050 wcscpy(lpStr, lpEmptyString);
3051 }
3052
3053 lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3054 }
3055
3056 if (pcbBytesNeeded != NULL)
3057 *pcbBytesNeeded = dwRequiredSize;
3058
3059 Done:
3060 /* Unlock the service database */
3061 ScmUnlockDatabase();
3062
3063 if (lpImagePath != NULL)
3064 HeapFree(GetProcessHeap(), 0, lpImagePath);
3065
3066 if (lpServiceStartName != NULL)
3067 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3068
3069 if (lpDependencies != NULL)
3070 HeapFree(GetProcessHeap(), 0, lpDependencies);
3071
3072 if (hServiceKey != NULL)
3073 RegCloseKey(hServiceKey);
3074
3075 DPRINT("RQueryServiceConfigW() done\n");
3076
3077 return dwError;
3078 }
3079
3080
3081 /* Function 18 */
3082 DWORD
3083 WINAPI
3084 RQueryServiceLockStatusW(
3085 SC_RPC_HANDLE hSCManager,
3086 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3087 DWORD cbBufSize,
3088 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3089 {
3090 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf;
3091 PMANAGER_HANDLE hMgr;
3092 DWORD dwRequiredSize;
3093
3094 if (!lpLockStatus || !pcbBytesNeeded)
3095 return ERROR_INVALID_PARAMETER;
3096
3097 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
3098 if (hMgr == NULL)
3099 {
3100 DPRINT1("Invalid service manager handle!\n");
3101 return ERROR_INVALID_HANDLE;
3102 }
3103
3104 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
3105 SC_MANAGER_QUERY_LOCK_STATUS))
3106 {
3107 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
3108 return ERROR_ACCESS_DENIED;
3109 }
3110
3111 /* FIXME: we need to compute instead the real length of the owner name */
3112 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
3113 *pcbBytesNeeded = dwRequiredSize;
3114
3115 if (cbBufSize < dwRequiredSize)
3116 return ERROR_INSUFFICIENT_BUFFER;
3117
3118 ScmQueryServiceLockStatusW(lpLockStatus);
3119
3120 return ERROR_SUCCESS;
3121 }
3122
3123
3124 /* Function 19 */
3125 DWORD
3126 WINAPI
3127 RStartServiceW(
3128 SC_RPC_HANDLE hService,
3129 DWORD argc,
3130 LPSTRING_PTRSW argv)
3131 {
3132 DWORD dwError = ERROR_SUCCESS;
3133 PSERVICE_HANDLE hSvc;
3134 PSERVICE lpService = NULL;
3135
3136 #ifndef NDEBUG
3137 DWORD i;
3138
3139 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3140 DPRINT(" argc: %lu\n", argc);
3141 if (argv != NULL)
3142 {
3143 for (i = 0; i < argc; i++)
3144 {
3145 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
3146 }
3147 }
3148 #endif
3149
3150 if (ScmShutdown)
3151 return ERROR_SHUTDOWN_IN_PROGRESS;
3152
3153 hSvc = ScmGetServiceFromHandle(hService);
3154 if (hSvc == NULL)
3155 {
3156 DPRINT1("Invalid service handle!\n");
3157 return ERROR_INVALID_HANDLE;
3158 }
3159
3160 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3161 SERVICE_START))
3162 {
3163 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3164 return ERROR_ACCESS_DENIED;
3165 }
3166
3167 lpService = hSvc->ServiceEntry;
3168 if (lpService == NULL)
3169 {
3170 DPRINT("lpService == NULL!\n");
3171 return ERROR_INVALID_HANDLE;
3172 }
3173
3174 if (lpService->dwStartType == SERVICE_DISABLED)
3175 return ERROR_SERVICE_DISABLED;
3176
3177 if (lpService->bDeleted)
3178 return ERROR_SERVICE_MARKED_FOR_DELETE;
3179
3180 /* Start the service */
3181 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3182
3183 return dwError;
3184 }
3185
3186
3187 /* Function 20 */
3188 DWORD
3189 WINAPI
3190 RGetServiceDisplayNameW(
3191 SC_RPC_HANDLE hSCManager,
3192 LPCWSTR lpServiceName,
3193 LPWSTR lpDisplayName,
3194 DWORD *lpcchBuffer)
3195 {
3196 // PMANAGER_HANDLE hManager;
3197 PSERVICE lpService;
3198 DWORD dwLength;
3199 DWORD dwError;
3200
3201 DPRINT("RGetServiceDisplayNameW() called\n");
3202 DPRINT("hSCManager = %p\n", hSCManager);
3203 DPRINT("lpServiceName: %S\n", lpServiceName);
3204 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3205 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3206
3207 // hManager = (PMANAGER_HANDLE)hSCManager;
3208 // if (hManager->Handle.Tag != MANAGER_TAG)
3209 // {
3210 // DPRINT("Invalid manager handle!\n");
3211 // return ERROR_INVALID_HANDLE;
3212 // }
3213
3214 /* Get service database entry */
3215 lpService = ScmGetServiceEntryByName(lpServiceName);
3216 if (lpService == NULL)
3217 {
3218 DPRINT("Could not find a service!\n");
3219
3220 /* If the service could not be found and lpcchBuffer is less than 2, windows
3221 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3222 if (*lpcchBuffer < 2)
3223 {
3224 *lpcchBuffer = 2;
3225 if (lpDisplayName != NULL)
3226 {
3227 *lpDisplayName = 0;
3228 }
3229 }
3230
3231 return ERROR_SERVICE_DOES_NOT_EXIST;
3232 }
3233
3234 if (!lpService->lpDisplayName)
3235 {
3236 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3237
3238 if (lpDisplayName != NULL &&
3239 *lpcchBuffer > dwLength)
3240 {
3241 wcscpy(lpDisplayName, lpService->lpServiceName);
3242 }
3243 }
3244 else
3245 {
3246 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
3247
3248 if (lpDisplayName != NULL &&
3249 *lpcchBuffer > dwLength)
3250 {
3251 wcscpy(lpDisplayName, lpService->lpDisplayName);
3252 }
3253 }
3254
3255 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3256
3257 *lpcchBuffer = dwLength;
3258
3259 return dwError;
3260 }
3261
3262
3263 /* Function 21 */
3264 DWORD
3265 WINAPI
3266 RGetServiceKeyNameW(
3267 SC_RPC_HANDLE hSCManager,
3268 LPCWSTR lpDisplayName,
3269 LPWSTR lpServiceName,
3270 DWORD *lpcchBuffer)
3271 {
3272 // PMANAGER_HANDLE hManager;
3273 PSERVICE lpService;
3274 DWORD dwLength;
3275 DWORD dwError;
3276
3277 DPRINT("RGetServiceKeyNameW() called\n");
3278 DPRINT("hSCManager = %p\n", hSCManager);
3279 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3280 DPRINT("lpServiceName: %p\n", lpServiceName);
3281 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3282
3283 // hManager = (PMANAGER_HANDLE)hSCManager;
3284 // if (hManager->Handle.Tag != MANAGER_TAG)
3285 // {
3286 // DPRINT("Invalid manager handle!\n");
3287 // return ERROR_INVALID_HANDLE;
3288 // }
3289
3290 /* Get service database entry */
3291 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3292 if (lpService == NULL)
3293 {
3294 DPRINT("Could not find a service!\n");
3295
3296 /* If the service could not be found and lpcchBuffer is less than 2, windows
3297 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3298 if (*lpcchBuffer < 2)
3299 {
3300 *lpcchBuffer = 2;
3301 if (lpServiceName != NULL)
3302 {
3303 *lpServiceName = 0;
3304 }
3305 }
3306
3307 return ERROR_SERVICE_DOES_NOT_EXIST;
3308 }
3309
3310 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3311
3312 if (lpServiceName != NULL &&
3313 *lpcchBuffer > dwLength)
3314 {
3315 wcscpy(lpServiceName, lpService->lpServiceName);
3316 *lpcchBuffer = dwLength;
3317 return ERROR_SUCCESS;
3318 }
3319
3320 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3321
3322 *lpcchBuffer = dwLength;
3323
3324 return dwError;
3325 }
3326
3327
3328 /* Function 22 */
3329 DWORD
3330 WINAPI
3331 RI_ScSetServiceBitsA(
3332 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3333 DWORD dwServiceBits,
3334 int bSetBitsOn,
3335 int bUpdateImmediately,
3336 char *lpString)
3337 {
3338 UNIMPLEMENTED;
3339 return ERROR_CALL_NOT_IMPLEMENTED;
3340 }
3341
3342
3343 /* Function 23 */
3344 DWORD
3345 WINAPI
3346 RChangeServiceConfigA(
3347 SC_RPC_HANDLE hService,
3348 DWORD dwServiceType,
3349 DWORD dwStartType,
3350 DWORD dwErrorControl,
3351 LPSTR lpBinaryPathName,
3352 LPSTR lpLoadOrderGroup,
3353 LPDWORD lpdwTagId,
3354 LPBYTE lpDependencies,
3355 DWORD dwDependSize,
3356 LPSTR lpServiceStartName,
3357 LPBYTE lpPassword,
3358 DWORD dwPwSize,
3359 LPSTR lpDisplayName)
3360 {
3361 DWORD dwError = ERROR_SUCCESS;
3362 PSERVICE_HANDLE hSvc;
3363 PSERVICE lpService = NULL;
3364 HKEY hServiceKey = NULL;
3365 LPWSTR lpDisplayNameW = NULL;
3366 LPWSTR lpBinaryPathNameW = NULL;
3367 LPWSTR lpCanonicalImagePathW = NULL;
3368 LPWSTR lpLoadOrderGroupW = NULL;
3369 LPWSTR lpDependenciesW = NULL;
3370
3371 DPRINT("RChangeServiceConfigA() called\n");
3372 DPRINT("dwServiceType = %lu\n", dwServiceType);
3373 DPRINT("dwStartType = %lu\n", dwStartType);
3374 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3375 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3376 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3377 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3378
3379 if (ScmShutdown)
3380 return ERROR_SHUTDOWN_IN_PROGRESS;
3381
3382 hSvc = ScmGetServiceFromHandle(hService);
3383 if (hSvc == NULL)
3384 {
3385 DPRINT1("Invalid service handle!\n");
3386 return ERROR_INVALID_HANDLE;
3387 }
3388
3389 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3390 SERVICE_CHANGE_CONFIG))
3391 {
3392 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3393 return ERROR_ACCESS_DENIED;
3394 }
3395
3396 lpService = hSvc->ServiceEntry;
3397 if (lpService == NULL)
3398 {
3399 DPRINT("lpService == NULL!\n");
3400 return ERROR_INVALID_HANDLE;
3401 }
3402
3403 /* Lock the service database exclusively */
3404 ScmLockDatabaseExclusive();
3405
3406 if (lpService->bDeleted)
3407 {
3408 DPRINT("The service has already been marked for delete!\n");
3409 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
3410 goto done;
3411 }
3412
3413 /* Open the service key */
3414 dwError = ScmOpenServiceKey(lpService->szServiceName,
3415 KEY_SET_VALUE,
3416 &hServiceKey);
3417 if (dwError != ERROR_SUCCESS)
3418 goto done;
3419
3420 /* Write service data to the registry */
3421
3422 if (lpDisplayName != NULL && *lpDisplayName != 0)
3423 {
3424 /* Set the display name */
3425 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3426 HEAP_ZERO_MEMORY,
3427 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3428 if (lpDisplayNameW == NULL)
3429 {
3430 dwError = ERROR_NOT_ENOUGH_MEMORY;
3431 goto done;
3432 }
3433
3434 MultiByteToWideChar(CP_ACP,
3435 0,
3436 lpDisplayName,
3437 -1,
3438 lpDisplayNameW,
3439 (int)(strlen(lpDisplayName) + 1));
3440
3441 RegSetValueExW(hServiceKey,
3442 L"DisplayName",
3443 0,
3444 REG_SZ,
3445 (LPBYTE)lpDisplayNameW,
3446 (DWORD)((wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR)));
3447
3448 /* Update lpService->lpDisplayName */
3449 if (lpService->lpDisplayName)
3450 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3451
3452 lpService->lpDisplayName = lpDisplayNameW;
3453 }
3454
3455 if (dwServiceType != SERVICE_NO_CHANGE)
3456 {
3457 /* Set the service type */
3458 dwError = RegSetValueExW(hServiceKey,
3459 L"Type",
3460 0,
3461 REG_DWORD,
3462 (LPBYTE)&dwServiceType,
3463 sizeof(DWORD));
3464 if (dwError != ERROR_SUCCESS)
3465 goto done;
3466
3467 lpService->Status.dwServiceType = dwServiceType;
3468 }
3469
3470 if (dwStartType != SERVICE_NO_CHANGE)
3471 {
3472 /* Set the start value */
3473 dwError = RegSetValueExW(hServiceKey,
3474 L"Start",
3475 0,
3476 REG_DWORD,
3477 (LPBYTE)&dwStartType,
3478 sizeof(DWORD));
3479 if (dwError != ERROR_SUCCESS)
3480 goto done;
3481
3482 lpService->dwStartType = dwStartType;
3483 }
3484
3485 if (dwErrorControl != SERVICE_NO_CHANGE)
3486 {
3487 /* Set the error control value */
3488 dwError = RegSetValueExW(hServiceKey,
3489 L"ErrorControl",
3490 0,
3491 REG_DWORD,
3492 (LPBYTE)&dwErrorControl,
3493 sizeof(DWORD));
3494 if (dwError != ERROR_SUCCESS)
3495 goto done;
3496
3497 lpService->dwErrorControl = dwErrorControl;
3498 }
3499
3500 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3501 {
3502 /* Set the image path */
3503 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
3504 HEAP_ZERO_MEMORY,
3505 (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
3506 if (lpBinaryPathNameW == NULL)
3507 {
3508 dwError = ERROR_NOT_ENOUGH_MEMORY;
3509 goto done;
3510 }
3511
3512 MultiByteToWideChar(CP_ACP,
3513 0,
3514 lpBinaryPathName,
3515 -1,
3516 lpBinaryPathNameW,
3517 (int)(strlen(lpBinaryPathName) + 1));
3518
3519 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
3520 {
3521 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
3522 lpBinaryPathNameW,
3523 &lpCanonicalImagePathW);
3524
3525 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3526
3527 if (dwError != ERROR_SUCCESS)
3528 goto done;
3529
3530 lpBinaryPathNameW = lpCanonicalImagePathW;
3531 }
3532
3533 dwError = RegSetValueExW(hServiceKey,
3534 L"ImagePath",
3535 0,
3536 REG_EXPAND_SZ,
3537 (LPBYTE)lpBinaryPathNameW,
3538 (DWORD)((wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR)));
3539
3540 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3541
3542 if (dwError != ERROR_SUCCESS)
3543 goto done;
3544 }
3545
3546 /* Set the group name */
3547 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3548 {
3549 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3550 HEAP_ZERO_MEMORY,
3551 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3552 if (lpLoadOrderGroupW == NULL)
3553 {
3554 dwError = ERROR_NOT_ENOUGH_MEMORY;
3555 goto done;
3556 }
3557
3558 MultiByteToWideChar(CP_ACP,
3559 0,
3560 lpLoadOrderGroup,
3561 -1,
3562 lpLoadOrderGroupW,
3563 (int)(strlen(lpLoadOrderGroup) + 1));
3564
3565 dwError = RegSetValueExW(hServiceKey,
3566 L"Group",
3567 0,
3568 REG_SZ,
3569 (LPBYTE)lpLoadOrderGroupW,
3570 (DWORD)((wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR)));
3571 if (dwError != ERROR_SUCCESS)
3572 {
3573 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3574 goto done;
3575 }
3576
3577 dwError = ScmSetServiceGroup(lpService,
3578 lpLoadOrderGroupW);
3579
3580 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3581
3582 if (dwError != ERROR_SUCCESS)
3583 goto done;
3584 }
3585
3586 if (lpdwTagId != NULL)
3587 {
3588 dwError = ScmAssignNewTag(lpService);
3589 if (dwError != ERROR_SUCCESS)
3590 goto done;
3591
3592 dwError = RegSetValueExW(hServiceKey,
3593 L"Tag",
3594 0,
3595 REG_DWORD,
3596 (LPBYTE)&lpService->dwTag,
3597 sizeof(DWORD));
3598 if (dwError != ERROR_SUCCESS)
3599 goto done;
3600
3601 *lpdwTagId = lpService->dwTag;
3602 }
3603
3604 /* Write dependencies */
3605 if (lpDependencies != NULL && *lpDependencies != 0)
3606 {
3607 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3608 HEAP_ZERO_MEMORY,
3609 (strlen((LPSTR)lpDependencies) + 1) * sizeof(WCHAR));
3610 if (lpDependenciesW == NULL)
3611 {
3612 dwError = ERROR_NOT_ENOUGH_MEMORY;
3613 goto done;
3614 }
3615
3616 MultiByteToWideChar(CP_ACP,
3617 0,
3618 (LPSTR)lpDependencies,
3619 dwDependSize,
3620 lpDependenciesW,
3621 (int)(strlen((LPSTR)lpDependencies) + 1));
3622
3623 dwError = ScmWriteDependencies(hServiceKey,
3624 (LPWSTR)lpDependenciesW,
3625 dwDependSize);
3626
3627 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3628
3629 if (dwError != ERROR_SUCCESS)
3630 goto done;
3631 }
3632
3633 if (lpPassword != NULL)
3634 {
3635 if (wcslen((LPWSTR)lpPassword) != 0)
3636 {
3637 /* FIXME: Decrypt the password */
3638
3639 /* Write the password */
3640 dwError = ScmSetServicePassword(lpService->szServiceName,
3641 (LPCWSTR)lpPassword);
3642 if (dwError != ERROR_SUCCESS)
3643 goto done;
3644 }
3645 else
3646 {
3647 /* Delete the password */
3648 dwError = ScmSetServicePassword(lpService->szServiceName,
3649 NULL);
3650 if (dwError == ERROR_FILE_NOT_FOUND)
3651 dwError = ERROR_SUCCESS;
3652
3653 if (dwError != ERROR_SUCCESS)
3654 goto done;
3655 }
3656 }
3657
3658 done:
3659 /* Unlock the service database */
3660 ScmUnlockDatabase();
3661
3662 if (hServiceKey != NULL)
3663 RegCloseKey(hServiceKey);
3664
3665 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3666
3667 return dwError;
3668 }
3669
3670
3671 /* Function 24 */
3672 DWORD
3673 WINAPI
3674 RCreateServiceA(
3675 SC_RPC_HANDLE hSCManager,
3676 LPSTR lpServiceName,
3677 LPSTR lpDisplayName,
3678 DWORD dwDesiredAccess,
3679 DWORD dwServiceType,
3680 DWORD dwStartType,
3681 DWORD dwErrorControl,
3682 LPSTR lpBinaryPathName,
3683 LPSTR lpLoadOrderGroup,
3684 LPDWORD lpdwTagId,
3685 LPBYTE lpDependencies,
3686 DWORD dwDependSize,
3687 LPSTR lpServiceStartName,
3688 LPBYTE lpPassword,
3689 DWORD dwPwSize,
3690 LPSC_RPC_HANDLE lpServiceHandle)
3691 {
3692 DWORD dwError = ERROR_SUCCESS;
3693 LPWSTR lpServiceNameW = NULL;
3694 LPWSTR lpDisplayNameW = NULL;
3695 LPWSTR lpBinaryPathNameW = NULL;
3696 LPWSTR lpLoadOrderGroupW = NULL;
3697 LPWSTR lpDependenciesW = NULL;
3698 LPWSTR lpServiceStartNameW = NULL;
3699 DWORD dwDependenciesLength = 0;
3700 SIZE_T cchLength;
3701 int len;
3702 LPCSTR lpStr;
3703
3704 if (lpServiceName)
3705 {
3706 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3707 lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3708 if (!lpServiceNameW)
3709 {
3710 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3711 goto cleanup;
3712 }
3713 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3714 }
3715
3716 if (lpDisplayName)
3717 {
3718 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3719 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3720 if (!lpDisplayNameW)
3721 {
3722 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3723 goto cleanup;
3724 }
3725 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3726 }
3727
3728 if (lpBinaryPathName)
3729 {
3730 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3731 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3732 if (!lpBinaryPathNameW)
3733 {
3734 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3735 goto cleanup;
3736 }
3737 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3738 }
3739
3740 if (lpLoadOrderGroup)
3741 {
3742 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3743 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3744 if (!lpLoadOrderGroupW)
3745 {
3746 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3747 goto cleanup;
3748 }
3749 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3750 }
3751
3752 if (lpDependencies)
3753 {
3754 lpStr = (LPCSTR)lpDependencies;
3755 while (*lpStr)
3756 {
3757 cchLength = strlen(lpStr) + 1;
3758 dwDependenciesLength += (DWORD)cchLength;
3759 lpStr = lpStr + cchLength;
3760 }
3761 dwDependenciesLength++;
3762
3763 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3764 if (!lpDependenciesW)
3765 {
3766 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3767 goto cleanup;
3768 }
3769 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3770 }
3771
3772 if (lpServiceStartName)
3773 {
3774 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3775 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3776 if (!lpServiceStartNameW)
3777 {
3778 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3779 goto cleanup;
3780 }
3781 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3782 }
3783
3784 dwError = RCreateServiceW(hSCManager,
3785 lpServiceNameW,
3786 lpDisplayNameW,
3787 dwDesiredAccess,
3788 dwServiceType,
3789 dwStartType,
3790 dwErrorControl,
3791 lpBinaryPathNameW,
3792 lpLoadOrderGroupW,
3793 lpdwTagId,
3794 (LPBYTE)lpDependenciesW,
3795 dwDependenciesLength,
3796 lpServiceStartNameW,
3797 lpPassword,
3798 dwPwSize,
3799 lpServiceHandle);
3800
3801 cleanup:
3802 if (lpServiceNameW !=NULL)
3803 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3804
3805 if (lpDisplayNameW != NULL)
3806 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3807
3808 if (lpBinaryPathNameW != NULL)
3809 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3810
3811 if (lpLoadOrderGroupW != NULL)
3812 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3813
3814 if (lpDependenciesW != NULL)
3815 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3816
3817 if (lpServiceStartNameW != NULL)
3818 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3819
3820 return dwError;
3821 }
3822
3823
3824 /* Function 25 */
3825 DWORD
3826 WINAPI
3827 REnumDependentServicesA(
3828 SC_RPC_HANDLE hService,
3829 DWORD dwServiceState,
3830 LPBYTE lpServices,
3831 DWORD cbBufSize,
3832 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3833 LPBOUNDED_DWORD_256K lpServicesReturned)
3834 {
3835 DWORD dwError = ERROR_SUCCESS;
3836 DWORD dwServicesReturned = 0;
3837 DWORD dwServiceCount;
3838 HKEY hServicesKey = NULL;
3839 PSERVICE_HANDLE hSvc;
3840 PSERVICE lpService = NULL;
3841 PSERVICE *lpServicesArray = NULL;
3842 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3843 LPSTR lpStr;
3844
3845 *pcbBytesNeeded = 0;
3846 *lpServicesReturned = 0;
3847
3848 DPRINT("REnumDependentServicesA() called\n");
3849
3850 hSvc = ScmGetServiceFromHandle(hService);
3851 if (hSvc == NULL)
3852 {
3853 DPRINT1("Invalid service handle!\n");
3854 return ERROR_INVALID_HANDLE;
3855 }
3856
3857 lpService = hSvc->ServiceEntry;
3858
3859 /* Check access rights */
3860 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3861 SC_MANAGER_ENUMERATE_SERVICE))
3862 {
3863 DPRINT("Insufficient access rights! 0x%lx\n",
3864 hSvc->Handle.DesiredAccess);
3865 return ERROR_ACCESS_DENIED;
3866 }
3867
3868 /* Open the Services Reg key */
3869 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3870 L"System\\CurrentControlSet\\Services",
3871 0,
3872 KEY_READ,
3873 &hServicesKey);
3874
3875 if (dwError != ERROR_SUCCESS)
3876 return dwError;
3877
3878 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3879 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3880 are the same for both. Verified in WINXP. */
3881
3882 /* First determine the bytes needed and get the number of dependent services*/
3883 dwError = Int_EnumDependentServicesW(hServicesKey,
3884 lpService,
3885 dwServiceState,
3886 NULL,
3887 pcbBytesNeeded,
3888 &dwServicesReturned);
3889 if (dwError != ERROR_SUCCESS)
3890 goto Done;
3891
3892 /* If buffer size is less than the bytes needed or pointer is null*/
3893 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3894 {
3895 dwError = ERROR_MORE_DATA;
3896 goto Done;
3897 }
3898
3899 /* Allocate memory for array of service pointers */
3900 lpServicesArray = HeapAlloc(GetProcessHeap(),
3901 HEAP_ZERO_MEMORY,
3902 (dwServicesReturned + 1) * sizeof(PSERVICE));
3903 if (!lpServicesArray)
3904 {
3905 DPRINT("Could not allocate a buffer!!\n");
3906 dwError = ERROR_NOT_ENOUGH_MEMORY;
3907 goto Done;
3908 }
3909
3910 dwServicesReturned = 0;
3911 *pcbBytesNeeded = 0;
3912
3913 dwError = Int_EnumDependentServicesW(hServicesKey,
3914 lpService,
3915 dwServiceState,
3916 lpServicesArray,
3917 pcbBytesNeeded,
3918 &dwServicesReturned);
3919 if (dwError != ERROR_SUCCESS)
3920 {
3921 goto Done;
3922 }
3923
3924 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3925 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3926
3927 /* Copy EnumDepenedentService to Buffer */
3928 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3929 {
3930 lpService = lpServicesArray[dwServiceCount];
3931
3932 /* Copy the status info */
3933 memcpy(&lpServicesPtr->ServiceStatus,
3934 &lpService->Status,
3935 sizeof(SERVICE_STATUS));
3936
3937 /* Copy display name */
3938 WideCharToMultiByte(CP_ACP,
3939 0,
3940 lpService->lpDisplayName,
3941 -1,
3942 lpStr,
3943 (int)wcslen(lpService->lpDisplayName),
3944 0,
3945 0);
3946 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3947 lpStr += strlen(lpStr) + 1;
3948
3949 /* Copy service name */
3950 WideCharToMultiByte(CP_ACP,
3951 0,
3952 lpService->lpServiceName,
3953 -1,
3954 lpStr,
3955 (int)wcslen(lpService->lpServiceName),
3956 0,
3957 0);
3958 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3959 lpStr += strlen(lpStr) + 1;
3960
3961 lpServicesPtr++;
3962 }
3963
3964 *lpServicesReturned = dwServicesReturned;
3965
3966 Done:
3967 if (lpServicesArray)
3968 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3969
3970 RegCloseKey(hServicesKey);
3971
3972 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3973
3974 return dwError;
3975 }
3976
3977
3978 /* Function 26 */
3979 DWORD
3980 WINAPI
3981 REnumServicesStatusA(
3982 SC_RPC_HANDLE hSCManager,
3983 DWORD dwServiceType,
3984 DWORD dwServiceState,
3985 LPBYTE lpBuffer,
3986 DWORD dwBufSize,
3987 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3988 LPBOUNDED_DWORD_256K lpServicesReturned,
3989 LPBOUNDED_DWORD_256K lpResumeHandle)
3990 {
3991 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3992 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW;
3993 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3994 LPWSTR lpStringPtrW;
3995 LPSTR lpStringPtrA;
3996 DWORD dwError;
3997 DWORD dwServiceCount;
3998
3999 DPRINT("REnumServicesStatusA() called\n");
4000
4001 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
4002 {
4003 return ERROR_INVALID_ADDRESS;
4004 }
4005
4006 if ((dwBufSize > 0) && (lpBuffer))
4007 {
4008 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
4009 if (!lpStatusPtrW)
4010 {
4011 DPRINT("Failed to allocate buffer!\n");
4012 return ERROR_NOT_ENOUGH_MEMORY;
4013 }
4014 }
4015
4016 dwError = REnumServicesStatusW(hSCManager,
4017 dwServiceType,
4018 dwServiceState,
4019 (LPBYTE)lpStatusPtrW,
4020 dwBufSize,
4021 pcbBytesNeeded,
4022 lpServicesReturned,
4023 lpResumeHandle);
4024
4025 /* if no services were returned then we are Done */
4026 if (*lpServicesReturned == 0)
4027 goto Done;
4028
4029 lpStatusPtrIncrW = lpStatusPtrW;
4030 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
4031 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
4032 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
4033 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
4034 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
4035
4036 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
4037 {
4038 /* Copy the service name */
4039 WideCharToMultiByte(CP_ACP,
4040 0,
4041 lpStringPtrW,
4042 -1,
4043 lpStringPtrA,
4044 (int)wcslen(lpStringPtrW),
4045 0,
4046 0);
4047
4048 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
4049 lpStringPtrA += wcslen(lpStringPtrW) + 1;
4050 lpStringPtrW += wcslen(lpStringPtrW) + 1;
4051
4052 /* Copy the display name */
4053 WideCharToMultiByte(CP_ACP,
4054 0,
4055 lpStringPtrW,
4056 -1,
4057 lpStringPtrA,
4058 (int)wcslen(lpStringPtrW),
4059 0,
4060 0);
4061
4062 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
4063 lpStringPtrA += wcslen(lpStringPtrW) + 1;
4064 lpStringPtrW += wcslen(lpStringPtrW) + 1;
4065
4066 /* Copy the status information */
4067 memcpy(&lpStatusPtrA->ServiceStatus,
4068 &lpStatusPtrIncrW->ServiceStatus,
4069 sizeof(SERVICE_STATUS));
4070
4071 lpStatusPtrIncrW++;
4072 lpStatusPtrA++;
4073 }
4074
4075 Done:
4076 if (lpStatusPtrW)
4077 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
4078
4079 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
4080
4081 return dwError;
4082 }
4083
4084
4085 /* Function 27 */
4086 DWORD
4087 WINAPI
4088 ROpenSCManagerA(
4089 LPSTR lpMachineName,
4090 LPSTR lpDatabaseName,
4091 DWORD dwDesiredAccess,
4092 LPSC_RPC_HANDLE lpScHandle)
4093 {
4094 UNICODE_STRING MachineName;
4095 UNICODE_STRING DatabaseName;
4096 DWORD dwError;
4097
4098 DPRINT("ROpenSCManagerA() called\n");
4099
4100 if (lpMachineName)
4101 RtlCreateUnicodeStringFromAsciiz(&MachineName,
4102 lpMachineName);
4103
4104 if (lpDatabaseName)
4105 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
4106 lpDatabaseName);
4107
4108 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
4109 lpDatabaseName ? DatabaseName.Buffer : NULL,
4110 dwDesiredAccess,
4111 lpScHandle);
4112
4113 if (lpMachineName)
4114 RtlFreeUnicodeString(&MachineName);
4115
4116 if (lpDatabaseName)
4117 RtlFreeUnicodeString(&DatabaseName);
4118
4119 return dwError;
4120 }
4121
4122
4123 /* Function 28 */
4124 DWORD
4125 WINAPI
4126 ROpenServiceA(
4127 SC_RPC_HANDLE hSCManager,
4128 LPSTR lpServiceName,
4129 DWORD dwDesiredAccess,
4130 LPSC_RPC_HANDLE lpServiceHandle)
4131 {
4132 UNICODE_STRING ServiceName;
4133 DWORD dwError;
4134
4135 DPRINT("ROpenServiceA() called\n");
4136
4137 if (lpServiceName)
4138 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
4139 lpServiceName);
4140
4141 dwError = ROpenServiceW(hSCManager,
4142 lpServiceName ? ServiceName.Buffer : NULL,
4143 dwDesiredAccess,
4144 lpServiceHandle);
4145
4146 if (lpServiceName)
4147 RtlFreeUnicodeString(&ServiceName);
4148
4149 return dwError;
4150 }
4151
4152
4153 /* Function 29 */
4154 DWORD
4155 WINAPI
4156 RQueryServiceConfigA(
4157 SC_RPC_HANDLE hService,
4158 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4159 DWORD cbBufSize,
4160 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4161 {
4162 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
4163 DWORD dwError = ERROR_SUCCESS;
4164 PSERVICE_HANDLE hSvc;
4165 PSERVICE lpService = NULL;
4166 HKEY hServiceKey = NULL;
4167 LPWSTR lpImagePath = NULL;
4168 LPWSTR lpServiceStartName = NULL;
4169 LPWSTR lpDependencies = NULL;
4170 DWORD dwDependenciesLength = 0;
4171 DWORD dwRequiredSize;
4172 CHAR lpEmptyString[]={0,0};
4173 LPSTR lpStr;
4174
4175 DPRINT("RQueryServiceConfigA() called\n");
4176
4177 if (ScmShutdown)
4178 return ERROR_SHUTDOWN_IN_PROGRESS;
4179
4180 hSvc = ScmGetServiceFromHandle(hService);
4181 if (hSvc == NULL)
4182 {
4183 DPRINT1("Invalid service handle!\n");
4184 return ERROR_INVALID_HANDLE;
4185 }
4186
4187 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4188 SERVICE_QUERY_CONFIG))
4189 {
4190 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4191 return ERROR_ACCESS_DENIED;
4192 }
4193
4194 lpService = hSvc->ServiceEntry;
4195 if (lpService == NULL)
4196 {
4197 DPRINT("lpService == NULL!\n");
4198 return ERROR_INVALID_HANDLE;
4199 }
4200
4201 /* Lock the service database shared */
4202 ScmLockDatabaseShared();
4203
4204 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4205 KEY_READ,
4206 &hServiceKey);
4207 if (dwError != ERROR_SUCCESS)
4208 goto Done;
4209
4210 /* Read the image path */
4211 dwError = ScmReadString(hServiceKey,
4212 L"ImagePath",
4213 &lpImagePath);
4214 if (dwError != ERROR_SUCCESS)
4215 goto Done;
4216
4217 /* Read the service start name */
4218 ScmReadString(hServiceKey,
4219 L"ObjectName",
4220 &lpServiceStartName);
4221
4222 /* Read the dependencies */
4223 ScmReadDependencies(hServiceKey,
4224 &lpDependencies,
4225 &dwDependenciesLength);
4226
4227 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGA);
4228
4229 if (lpImagePath != NULL)
4230 dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
4231 else
4232 dwRequiredSize += 2;
4233
4234 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
4235 dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
4236 else
4237 dwRequiredSize += 2;
4238
4239 /* Add Dependencies length */
4240 if (lpDependencies != NULL)
4241 dwRequiredSize += dwDependenciesLength;
4242 else
4243 dwRequiredSize += 2;
4244
4245 if (lpServiceStartName != NULL)
4246 dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
4247 else
4248 dwRequiredSize += 2;
4249
4250 if (lpService->lpDisplayName != NULL)
4251 dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
4252 else
4253 dwRequiredSize += 2;
4254
4255 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
4256 {
4257 dwError = ERROR_INSUFFICIENT_BUFFER;
4258 }
4259 else
4260 {
4261 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
4262 lpServiceConfig->dwStartType = lpService->dwStartType;
4263 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
4264 lpServiceConfig->dwTagId = lpService->dwTag;
4265
4266 lpStr = (LPSTR)(lpServiceConfig + 1);
4267
4268 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4269 Verified in WINXP */
4270
4271 if (lpImagePath)
4272 {
4273 WideCharToMultiByte(CP_ACP,
4274 0,
4275 lpImagePath,
4276 -1,
4277 lpStr,
4278 (int)(wcslen(lpImagePath) + 1),
4279 0,
4280 0);
4281 }
4282 else
4283 {
4284 strcpy(lpStr, lpEmptyString);
4285 }
4286
4287 lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4288 lpStr += (strlen((LPSTR)lpStr) + 1);
4289
4290 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4291 {
4292 WideCharToMultiByte(CP_ACP,
4293 0,
4294 lpService->lpGroup->lpGroupName,
4295 -1,
4296 lpStr,
4297 (int)(wcslen(lpService->lpGroup->lpGroupName) + 1),
4298 0,
4299 0);
4300 }
4301 else
4302 {
4303 strcpy(lpStr, lpEmptyString);
4304 }
4305
4306 lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4307 lpStr += (strlen(lpStr) + 1);
4308
4309 /* Append Dependencies */
4310 if (lpDependencies)
4311 {
4312 WideCharToMultiByte(CP_ACP,
4313 0,
4314 lpDependencies,
4315 dwDependenciesLength,
4316 lpStr,
4317 dwDependenciesLength,
4318 0,
4319 0);
4320 }
4321 else
4322 {
4323 strcpy(lpStr, lpEmptyString);
4324 }
4325
4326 lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4327 if (lpDependencies)
4328 lpStr += dwDependenciesLength;
4329 else
4330 lpStr += (strlen(lpStr) + 1);
4331
4332 if (lpServiceStartName)
4333 {
4334 WideCharToMultiByte(CP_ACP,
4335 0,
4336 lpServiceStartName,
4337 -1,
4338 lpStr,
4339 (int)(wcslen(lpServiceStartName) + 1),
4340 0,
4341 0);
4342 }
4343 else
4344 {
4345 strcpy(lpStr, lpEmptyString);
4346 }
4347
4348 lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4349 lpStr += (strlen(lpStr) + 1);
4350
4351 if (lpService->lpDisplayName)
4352 {
4353 WideCharToMultiByte(CP_ACP,
4354 0,
4355 lpService->lpDisplayName,
4356 -1,
4357 lpStr,
4358 (int)(wcslen(lpService->lpDisplayName) + 1),
4359 0,
4360 0);
4361 }
4362 else
4363 {
4364 strcpy(lpStr, lpEmptyString);
4365 }
4366
4367 lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4368 }
4369
4370 if (pcbBytesNeeded != NULL)
4371 *pcbBytesNeeded = dwRequiredSize;
4372
4373 Done:
4374 /* Unlock the service database */
4375 ScmUnlockDatabase();
4376
4377 if (lpImagePath != NULL)
4378 HeapFree(GetProcessHeap(), 0, lpImagePath);
4379
4380 if (lpServiceStartName != NULL)
4381 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4382
4383 if (lpDependencies != NULL)
4384 HeapFree(GetProcessHeap(), 0, lpDependencies);
4385
4386 if (hServiceKey != NULL)
4387 RegCloseKey(hServiceKey);
4388
4389 DPRINT("RQueryServiceConfigA() done\n");
4390
4391 return dwError;
4392 }
4393
4394
4395 /* Function 30 */
4396 DWORD
4397 WINAPI
4398 RQueryServiceLockStatusA(
4399 SC_RPC_HANDLE hSCManager,
4400 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4401 DWORD cbBufSize,
4402 LPBOUNDED_DWORD_4K pcbBytesNeeded)
4403 {
4404 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSA)lpBuf;
4405 PMANAGER_HANDLE hMgr;
4406 DWORD dwRequiredSize;
4407
4408 if (!lpLockStatus || !pcbBytesNeeded)
4409 return ERROR_INVALID_PARAMETER;
4410
4411 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
4412 if (hMgr == NULL)
4413 {
4414 DPRINT1("Invalid service manager handle!\n");
4415 return ERROR_INVALID_HANDLE;
4416 }
4417
4418 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
4419 SC_MANAGER_QUERY_LOCK_STATUS))
4420 {
4421 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
4422 return ERROR_ACCESS_DENIED;
4423 }
4424
4425 /* FIXME: we need to compute instead the real length of the owner name */
4426 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR);
4427 *pcbBytesNeeded = dwRequiredSize;
4428
4429 if (cbBufSize < dwRequiredSize)
4430 return ERROR_INSUFFICIENT_BUFFER;
4431
4432 ScmQueryServiceLockStatusA(lpLockStatus);
4433
4434 return ERROR_SUCCESS;
4435 }
4436
4437
4438 /* Function 31 */
4439 DWORD
4440 WINAPI
4441 RStartServiceA(
4442 SC_RPC_HANDLE hService,
4443 DWORD argc,
4444 LPSTRING_PTRSA argv)
4445 {
4446 DWORD dwError = ERROR_SUCCESS;
4447 PSERVICE_HANDLE hSvc;
4448 PSERVICE lpService = NULL;
4449 LPWSTR *lpVector = NULL;
4450 DWORD i;
4451 DWORD dwLength;
4452
4453 DPRINT("RStartServiceA() called\n");
4454
4455 if (ScmShutdown)
4456 return ERROR_SHUTDOWN_IN_PROGRESS;
4457
4458 hSvc = ScmGetServiceFromHandle(hService);
4459 if (hSvc == NULL)
4460 {
4461 DPRINT1("Invalid service handle!\n");
4462 return ERROR_INVALID_HANDLE;
4463 }
4464
4465 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4466 SERVICE_START))
4467 {
4468 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4469 return ERROR_ACCESS_DENIED;
4470 }
4471
4472 lpService = hSvc->ServiceEntry;
4473 if (lpService == NULL)
4474 {
4475 DPRINT("lpService == NULL!\n");
4476 return ERROR_INVALID_HANDLE;
4477 }
4478
4479 if (lpService->dwStartType == SERVICE_DISABLED)
4480 return ERROR_SERVICE_DISABLED;
4481
4482 if (lpService->bDeleted)
4483 return ERROR_SERVICE_MARKED_FOR_DELETE;
4484
4485 /* Build a Unicode argument vector */
4486 if (argc > 0)
4487 {
4488 lpVector = HeapAlloc(GetProcessHeap(),
4489 HEAP_ZERO_MEMORY,
4490 argc * sizeof(LPWSTR));
4491 if (lpVector == NULL)
4492 return ERROR_NOT_ENOUGH_MEMORY;
4493
4494 for (i = 0; i < argc; i++)
4495 {
4496 dwLength = MultiByteToWideChar(CP_ACP,
4497 0,
4498 ((LPSTR*)argv)[i],
4499 -1,
4500 NULL,
4501 0);
4502
4503 lpVector[i] = HeapAlloc(GetProcessHeap(),
4504 HEAP_ZERO_MEMORY,
4505 dwLength * sizeof(WCHAR));
4506 if (lpVector[i] == NULL)
4507 {
4508 dwError = ERROR_NOT_ENOUGH_MEMORY;
4509 goto done;
4510 }
4511
4512 MultiByteToWideChar(CP_ACP,
4513 0,
4514 ((LPSTR*)argv)[i],
4515 -1,
4516 lpVector[i],
4517 dwLength);
4518 }
4519 }
4520
4521 /* Start the service */
4522 dwError = ScmStartService(lpService, argc, lpVector);
4523
4524 done:
4525 /* Free the Unicode argument vector */
4526 if (lpVector != NULL)
4527 {
4528 for (i = 0; i < argc; i++)
4529 {
4530 if (lpVector[i] != NULL)
4531 HeapFree(GetProcessHeap(), 0, lpVector[i]);
4532 }
4533 HeapFree(GetProcessHeap(), 0, lpVector);
4534 }
4535
4536 return dwError;
4537 }
4538
4539
4540 /* Function 32 */
4541 DWORD
4542 WINAPI
4543 RGetServiceDisplayNameA(
4544 SC_RPC_HANDLE hSCManager,
4545 LPCSTR lpServiceName,
4546 LPSTR lpDisplayName,
4547 LPBOUNDED_DWORD_4K lpcchBuffer)
4548 {
4549 // PMANAGER_HANDLE hManager;
4550 PSERVICE lpService = NULL;
4551 DWORD dwLength;
4552 DWORD dwError;
4553 LPWSTR lpServiceNameW;
4554
4555 DPRINT("RGetServiceDisplayNameA() called\n");
4556 DPRINT("hSCManager = %p\n", hSCManager);
4557 DPRINT("lpServiceName: %s\n", lpServiceName);
4558 DPRINT("lpDisplayName: %p\n", lpDisplayName);
4559 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4560
4561 // hManager = (PMANAGER_HANDLE)hSCManager;
4562 // if (hManager->Handle.Tag != MANAGER_TAG)
4563 // {
4564 // DPRINT("Invalid manager handle!\n");
4565 // return ERROR_INVALID_HANDLE;
4566 // }
4567
4568 if (lpServiceName != NULL)
4569 {
4570 dwLength = (DWORD)(strlen(lpServiceName) + 1);
4571 lpServiceNameW = HeapAlloc(GetProcessHeap(),
4572 HEAP_ZERO_MEMORY,
4573 dwLength * sizeof(WCHAR));
4574 if (!lpServiceNameW)
4575 return ERROR_NOT_ENOUGH_MEMORY;
4576
4577 MultiByteToWideChar(CP_ACP,
4578 0,
4579 lpServiceName,
4580 -1,
4581 lpServiceNameW,
4582 dwLength);
4583
4584 lpService = ScmGetServiceEntryByName(lpServiceNameW);
4585
4586 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4587 }
4588
4589 if (lpService == NULL)
4590 {
4591 DPRINT("Could not find a service!\n");
4592
4593 /* If the service could not be found and lpcchBuffer is 0, windows
4594 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4595 if (*lpcchBuffer == 0)
4596 {
4597 *lpcchBuffer = 1;
4598 if (lpDisplayName != NULL)
4599 {
4600 *lpDisplayName = 0;
4601 }
4602 }
4603 return ERROR_SERVICE_DOES_NOT_EXIST;
4604 }
4605
4606 if (!lpService->lpDisplayName)
4607 {
4608 dwLength = (DWORD)wcslen(lpService->lpServiceName);
4609 if (lpDisplayName != NULL &&
4610 *lpcchBuffer > dwLength)
4611 {
4612 WideCharToMultiByte(CP_ACP,
4613 0,
4614 lpService->lpServiceName,
4615 (int)wcslen(lpService->lpServiceName),
4616 lpDisplayName,
4617 dwLength + 1,
4618 NULL,
4619 NULL);
4620 return ERROR_SUCCESS;
4621 }
4622 }
4623 else
4624 {
4625 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
4626 if (lpDisplayName != NULL &&
4627 *lpcchBuffer > dwLength)
4628 {
4629 WideCharToMultiByte(CP_ACP,
4630 0,
4631 lpService->lpDisplayName,
4632 (int)wcslen(lpService->lpDisplayName),
4633 lpDisplayName,
4634 dwLength + 1,
4635 NULL,
4636 NULL);
4637 return ERROR_SUCCESS;
4638 }
4639 }
4640
4641 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4642
4643 *lpcchBuffer = dwLength * 2;
4644
4645 return dwError;
4646 }
4647
4648
4649 /* Function 33 */
4650 DWORD
4651 WINAPI
4652 RGetServiceKeyNameA(
4653 SC_RPC_HANDLE hSCManager,
4654 LPCSTR lpDisplayName,
4655 LPSTR lpServiceName,
4656 LPBOUNDED_DWORD_4K lpcchBuffer)
4657 {
4658 PSERVICE lpService;
4659 DWORD dwLength;
4660 DWORD dwError;
4661 LPWSTR lpDisplayNameW;
4662
4663 DPRINT("RGetServiceKeyNameA() called\n");
4664 DPRINT("hSCManager = %p\n", hSCManager);
4665 DPRINT("lpDisplayName: %s\n", lpDisplayName);
4666 DPRINT("lpServiceName: %p\n", lpServiceName);
4667 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4668
4669 dwLength = (DWORD)(strlen(lpDisplayName) + 1);
4670 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4671 HEAP_ZERO_MEMORY,
4672 dwLength * sizeof(WCHAR));
4673 if (!lpDisplayNameW)
4674 return ERROR_NOT_ENOUGH_MEMORY;
4675
4676 MultiByteToWideChar(CP_ACP,
4677 0,
4678 lpDisplayName,
4679 -1,
4680 lpDisplayNameW,
4681 dwLength);
4682
4683 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4684
4685 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4686
4687 if (lpService == NULL)
4688 {
4689 DPRINT("Could not find the service!\n");
4690
4691 /* If the service could not be found and lpcchBuffer is 0,
4692 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4693 if (*lpcchBuffer == 0)
4694 {
4695 *lpcchBuffer = 1;
4696 if (lpServiceName != NULL)
4697 {
4698 *lpServiceName = 0;
4699 }
4700 }
4701
4702 return ERROR_SERVICE_DOES_NOT_EXIST;
4703 }
4704
4705 dwLength = (DWORD)wcslen(lpService->lpServiceName);
4706 if (lpServiceName != NULL &&
4707 *lpcchBuffer > dwLength)
4708 {
4709 WideCharToMultiByte(CP_ACP,
4710 0,
4711 lpService->lpServiceName,
4712 (int)wcslen(lpService->lpServiceName),
4713 lpServiceName,
4714 dwLength + 1,
4715 NULL,
4716 NULL);
4717 return ERROR_SUCCESS;
4718 }
4719
4720 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4721
4722 *lpcchBuffer = dwLength * 2;
4723
4724 return dwError;
4725 }
4726
4727
4728 /* Function 34 */
4729 DWORD
4730 WINAPI
4731 RI_ScGetCurrentGroupStateW(
4732 SC_RPC_HANDLE hSCManager,
4733 LPWSTR lpLoadOrderGroup,
4734 LPDWORD lpState)
4735 {
4736 PMANAGER_HANDLE hManager;
4737 PSERVICE_GROUP pServiceGroup;
4738 DWORD dwError = ERROR_SUCCESS;
4739
4740 DPRINT("RI_ScGetCurrentGroupStateW() called\n");
4741
4742 if (ScmShutdown)
4743 return ERROR_SHUTDOWN_IN_PROGRESS;
4744
4745 hManager = ScmGetServiceManagerFromHandle(hSCManager);
4746 if (hManager == NULL)
4747 {
4748 DPRINT1("Invalid service manager handle!\n");
4749 return ERROR_INVALID_HANDLE;
4750 }
4751
4752 /* Check for SC_MANAGER_ENUMERATE_SERVICE access right */
4753 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4754 SC_MANAGER_ENUMERATE_SERVICE))
4755 {
4756 DPRINT("Insufficient access rights! 0x%lx\n",
4757 hManager->Handle.DesiredAccess);
4758 return ERROR_ACCESS_DENIED;
4759 }
4760
4761 /* Lock the service database shared */
4762 ScmLockDatabaseShared();
4763
4764 /* Get the group list entry */
4765 pServiceGroup = ScmGetServiceGroupByName(lpLoadOrderGroup);
4766 if (pServiceGroup == NULL)
4767 {
4768 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
4769 goto done;
4770 }
4771
4772 /* FIXME: Return the group state */
4773 *lpState = 0;
4774
4775 done:
4776 /* Unlock the service database */
4777 ScmUnlockDatabase();
4778
4779 DPRINT("RI_ScGetCurrentGroupStateW() done (Error %lu)\n", dwError);
4780
4781 return dwError;
4782 }
4783
4784
4785 /* Function 35 */
4786 DWORD
4787 WINAPI
4788 REnumServiceGroupW(
4789 SC_RPC_HANDLE hSCManager,
4790 DWORD dwServiceType,
4791 DWORD dwServiceState,
4792 LPBYTE lpBuffer,
4793 DWORD cbBufSize,
4794 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4795 LPBOUNDED_DWORD_256K lpServicesReturned,
4796 LPBOUNDED_DWORD_256K lpResumeIndex,
4797 LPCWSTR pszGroupName)
4798 {
4799 PMANAGER_HANDLE hManager;
4800 PSERVICE lpService;
4801 DWORD dwError = ERROR_SUCCESS;
4802 PLIST_ENTRY ServiceEntry;
4803 PSERVICE CurrentService;
4804 DWORD dwState;
4805 DWORD dwRequiredSize;
4806 DWORD dwServiceCount;
4807 DWORD dwSize;
4808 DWORD dwLastResumeCount = 0;
4809 LPENUM_SERVICE_STATUSW lpStatusPtr;
4810 LPWSTR lpStringPtr;
4811
4812 DPRINT("REnumServiceGroupW() called\n");
4813
4814 if (ScmShutdown)
4815 return ERROR_SHUTDOWN_IN_PROGRESS;
4816
4817 hManager = ScmGetServiceManagerFromHandle(hSCManager);
4818 if (hManager == NULL)
4819 {
4820 DPRINT1("Invalid service manager handle!\n");
4821 return ERROR_INVALID_HANDLE;
4822 }
4823
4824 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
4825 {
4826 return ERROR_INVALID_ADDRESS;
4827 }
4828
4829 *pcbBytesNeeded = 0;
4830 *lpServicesReturned = 0;
4831
4832 if ((dwServiceType == 0) ||
4833 ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
4834 {
4835 DPRINT("Not a valid Service Type!\n");
4836 return ERROR_INVALID_PARAMETER;
4837 }
4838
4839 if ((dwServiceState == 0) ||
4840 ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
4841 {
4842 DPRINT("Not a valid Service State!\n");
4843 return ERROR_INVALID_PARAMETER;
4844 }
4845
4846 /* Check access rights */
4847 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4848 SC_MANAGER_ENUMERATE_SERVICE))
4849 {
4850 DPRINT("Insufficient access rights! 0x%lx\n",
4851 hManager->Handle.DesiredAccess);
4852 return ERROR_ACCESS_DENIED;
4853 }
4854
4855 if (lpResumeIndex)
4856 dwLastResumeCount = *lpResumeIndex;
4857
4858 /* Lock the service database shared */
4859 ScmLockDatabaseShared();
4860
4861 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4862 if (lpService == NULL)
4863 {
4864 dwError = ERROR_SUCCESS;
4865 goto Done;
4866 }
4867
4868 dwRequiredSize = 0;
4869 dwServiceCount = 0;
4870
4871 for (ServiceEntry = &lpService->ServiceListEntry;
4872 ServiceEntry != &ServiceListHead;
4873 ServiceEntry = ServiceEntry->Flink)
4874 {
4875 CurrentService = CONTAINING_RECORD(ServiceEntry,
4876 SERVICE,
4877 ServiceListEntry);
4878
4879 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4880 continue;
4881
4882 dwState = SERVICE_ACTIVE;
4883 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4884 dwState = SERVICE_INACTIVE;
4885
4886 if ((dwState & dwServiceState) == 0)
4887 continue;
4888
4889 if (pszGroupName)
4890 {
4891 if (*pszGroupName == 0)
4892 {
4893 if (CurrentService->lpGroup != NULL)
4894 continue;
4895 }
4896 else
4897 {
4898 if ((CurrentService->lpGroup == NULL) ||
4899 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4900 continue;
4901 }
4902 }
4903
4904 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4905 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4906 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4907
4908 if (dwRequiredSize + dwSize > cbBufSize)
4909 {
4910 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4911 break;
4912 }
4913
4914 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4915 dwRequiredSize += dwSize;
4916 dwServiceCount++;
4917 dwLastResumeCount = CurrentService->dwResumeCount;
4918 }
4919
4920 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4921 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4922
4923 for (;
4924 ServiceEntry != &ServiceListHead;
4925 ServiceEntry = ServiceEntry->Flink)
4926 {
4927 CurrentService = CONTAINING_RECORD(ServiceEntry,
4928 SERVICE,
4929 ServiceListEntry);
4930
4931 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4932 continue;
4933
4934 dwState = SERVICE_ACTIVE;
4935 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4936 dwState = SERVICE_INACTIVE;
4937
4938 if ((dwState & dwServiceState) == 0)
4939 continue;
4940
4941 if (pszGroupName)
4942 {
4943 if (*pszGroupName == 0)
4944 {
4945 if (CurrentService->lpGroup != NULL)
4946 continue;
4947 }
4948 else
4949 {
4950 if ((CurrentService->lpGroup == NULL) ||
4951 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4952 continue;
4953 }
4954 }
4955
4956 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
4957 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4958 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
4959
4960 dwError = ERROR_MORE_DATA;
4961 }
4962
4963 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4964
4965 if (lpResumeIndex)
4966 *lpResumeIndex = dwLastResumeCount;
4967
4968 *lpServicesReturned = dwServiceCount;
4969 *pcbBytesNeeded = dwRequiredSize;
4970
4971 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
4972 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
4973 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
4974
4975 dwRequiredSize = 0;
4976 for (ServiceEntry = &lpService->ServiceListEntry;
4977 ServiceEntry != &ServiceListHead;
4978 ServiceEntry = ServiceEntry->Flink)
4979 {
4980 CurrentService = CONTAINING_RECORD(ServiceEntry,
4981 SERVICE,
4982 ServiceListEntry);
4983
4984 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4985 continue;
4986
4987 dwState = SERVICE_ACTIVE;
4988 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4989 dwState = SERVICE_INACTIVE;
4990
4991 if ((dwState & dwServiceState) == 0)
4992 continue;
4993
4994 if (pszGroupName)
4995 {
4996 if (*pszGroupName == 0)
4997 {
4998 if (CurrentService->lpGroup != NULL)
4999 continue;
5000 }
5001 else
5002 {
5003 if ((CurrentService->lpGroup == NULL) ||
5004 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
5005 continue;
5006 }
5007 }
5008
5009 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
5010 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5011 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5012
5013 if (dwRequiredSize + dwSize > cbBufSize)
5014 break;
5015
5016 /* Copy the service name */
5017 wcscpy(lpStringPtr, CurrentService->lpServiceName);
5018 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5019 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
5020
5021 /* Copy the display name */
5022 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
5023 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5024 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
5025
5026 /* Copy the status information */
5027 memcpy(&lpStatusPtr->ServiceStatus,
5028 &CurrentService->Status,
5029 sizeof(SERVICE_STATUS));
5030
5031 lpStatusPtr++;
5032 dwRequiredSize += dwSize;
5033 }
5034
5035 if (dwError == ERROR_SUCCESS)
5036 {
5037 *pcbBytesNeeded = 0;
5038 if (lpResumeIndex) *lpResumeIndex = 0;
5039 }
5040
5041 Done:
5042 /* Unlock the service database */
5043 ScmUnlockDatabase();
5044
5045 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError);
5046
5047 return dwError;
5048 }
5049
5050
5051 /* Function 36 */
5052 DWORD
5053 WINAPI
5054 RChangeServiceConfig2A(
5055 SC_RPC_HANDLE hService,
5056 SC_RPC_CONFIG_INFOA Info)
5057 {
5058 SC_RPC_CONFIG_INFOW InfoW;
5059 DWORD dwRet, dwLength;
5060 PVOID ptr = NULL;
5061
5062 DPRINT("RChangeServiceConfig2A() called\n");
5063 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
5064
5065 InfoW.dwInfoLevel = Info.dwInfoLevel;
5066
5067 if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5068 {
5069 LPSERVICE_DESCRIPTIONW lpServiceDescriptionW;
5070 LPSERVICE_DESCRIPTIONA lpServiceDescriptionA;
5071
5072 lpServiceDescriptionA = Info.psd;
5073
5074 if (lpServiceDescriptionA &&
5075 lpServiceDescriptionA->lpDescription)
5076 {
5077 dwLength = (DWORD)((strlen(lpServiceDescriptionA->lpDescription) + 1) * sizeof(WCHAR));
5078
5079 lpServiceDescriptionW = HeapAlloc(GetProcessHeap(),
5080 HEAP_ZERO_MEMORY,
5081 dwLength + sizeof(SERVICE_DESCRIPTIONW));
5082 if (!lpServiceDescriptionW)
5083 {
5084 return ERROR_NOT_ENOUGH_MEMORY;
5085 }
5086
5087 lpServiceDescriptionW->lpDescription = (LPWSTR)(lpServiceDescriptionW + 1);
5088
5089 MultiByteToWideChar(CP_ACP,
5090 0,
5091 lpServiceDescriptionA->lpDescription,
5092 -1,
5093 lpServiceDescriptionW->lpDescription,
5094 dwLength);
5095
5096 ptr = lpServiceDescriptionW;
5097 InfoW.psd = lpServiceDescriptionW;
5098 }
5099 }
5100 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5101 {
5102 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
5103 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
5104 DWORD dwRebootLen = 0;
5105 DWORD dwCommandLen = 0;
5106 DWORD dwActionArrayLen = 0;
5107 LPWSTR lpStr = NULL;
5108
5109 lpServiceFailureActionsA = Info.psfa;
5110
5111 if (lpServiceFailureActionsA)
5112 {
5113 /*
5114 * The following code is inspired by the
5115 * SERVICE_CONFIG_FAILURE_ACTIONS case of
5116 * the RQueryServiceConfig2W function.
5117 */
5118
5119 /* Retrieve the needed length for the two data strings */
5120 if (lpServiceFailureActionsA->lpRebootMsg)
5121 {
5122 dwRebootLen = (DWORD)((strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR));
5123 }
5124 if (lpServiceFailureActionsA->lpCommand)
5125 {
5126 dwCommandLen = (DWORD)((strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR));
5127 }
5128
5129 /*
5130 * Retrieve the size of the lpsaActions array if needed.
5131 * We will copy the lpsaActions array only if there is at
5132 * least one action AND that the original array is valid.
5133 */
5134 if (lpServiceFailureActionsA->cActions > 0 && lpServiceFailureActionsA->lpsaActions)
5135 {
5136 dwActionArrayLen = lpServiceFailureActionsA->cActions * sizeof(SC_ACTION);
5137 }
5138
5139 /* Compute the total length for the UNICODE structure, including data */
5140 dwLength = sizeof(SERVICE_FAILURE_ACTIONSW) +
5141 dwActionArrayLen + dwRebootLen + dwCommandLen;
5142
5143 /* Allocate the structure */
5144 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
5145 HEAP_ZERO_MEMORY,
5146 dwLength);
5147 if (!lpServiceFailureActionsW)
5148 {
5149 return ERROR_NOT_ENOUGH_MEMORY;
5150 }
5151
5152 /* Copy the members */
5153 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
5154 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
5155
5156 /* Copy the lpsaActions array if needed */
5157 if (dwActionArrayLen > 0)
5158 {
5159 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
5160 lpServiceFailureActionsW->lpsaActions = (LPSC_ACTION)((ULONG_PTR)(lpServiceFailureActionsW + 1));
5161
5162 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
5163 RtlCopyMemory(lpServiceFailureActionsW->lpsaActions,
5164 lpServiceFailureActionsA->lpsaActions,
5165 dwActionArrayLen);
5166 }
5167 else
5168 {
5169 /* No lpsaActions array */
5170 lpServiceFailureActionsW->lpsaActions = NULL;
5171 }
5172 /* The data strings are stored just after the lpsaActions array */
5173 lpStr = (LPWSTR)((ULONG_PTR)(lpServiceFailureActionsW + 1) + dwActionArrayLen);
5174
5175 /*
5176 * Convert the data strings to UNICODE
5177 */
5178
5179 lpServiceFailureActionsW->lpRebootMsg = NULL;
5180 lpServiceFailureActionsW->lpCommand = NULL;
5181
5182 if (dwRebootLen)
5183 {
5184 /* lpRebootMsg points just after the lpsaActions array */
5185 lpServiceFailureActionsW->lpRebootMsg = lpStr;
5186
5187 MultiByteToWideChar(CP_ACP,
5188 0,
5189 lpServiceFailureActionsA->lpRebootMsg,
5190 -1,
5191 lpServiceFailureActionsW->lpRebootMsg,
5192 dwRebootLen);
5193
5194 lpStr += dwRebootLen / sizeof(WCHAR);
5195 }
5196
5197 if (dwCommandLen)
5198 {
5199 /* lpRebootMsg points just after the lpRebootMsg data string */
5200 lpServiceFailureActionsW->lpCommand = lpStr;
5201
5202 MultiByteToWideChar(CP_ACP,
5203 0,
5204 lpServiceFailureActionsA->lpCommand,
5205 -1,
5206 lpServiceFailureActionsW->lpCommand,
5207 dwCommandLen);
5208 }
5209
5210 /* Set the pointers */
5211 ptr = lpServiceFailureActionsW;
5212 InfoW.psfa = lpServiceFailureActionsW;
5213 }
5214 }
5215
5216 dwRet = RChangeServiceConfig2W(hService, InfoW);
5217
5218 HeapFree(GetProcessHeap(), 0, ptr);
5219
5220 return dwRet;
5221 }
5222
5223
5224 static DWORD
5225 ScmSetFailureActions(HKEY hServiceKey,
5226 LPSERVICE_FAILURE_ACTIONSW lpFailureActions)
5227 {
5228 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer = NULL;
5229 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer = NULL;
5230 DWORD dwRequiredSize = 0;
5231 DWORD dwType = 0;
5232 DWORD dwError;
5233
5234 /* There is nothing to be done if we have no failure actions */
5235 if (lpFailureActions == NULL)
5236 return ERROR_SUCCESS;
5237
5238 /*
5239 * 1- Retrieve the original value of FailureActions.
5240 */
5241
5242 /* Query value length */
5243 dwError = RegQueryValueExW(hServiceKey,
5244 L"FailureActions",
5245 NULL,
5246 &dwType,
5247 NULL,
5248 &dwRequiredSize);
5249 if (dwError != ERROR_SUCCESS &&
5250 dwError != ERROR_MORE_DATA &&
5251 dwError != ERROR_FILE_NOT_FOUND)
5252 return dwError;
5253
5254 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
5255 : sizeof(SERVICE_FAILURE_ACTIONSW);
5256
5257 /* Initialize the read buffer */
5258 lpReadBuffer = HeapAlloc(GetProcessHeap(),
5259 HEAP_ZERO_MEMORY,
5260 dwRequiredSize);
5261 if (lpReadBuffer == NULL)
5262 return ERROR_NOT_ENOUGH_MEMORY;
5263
5264 /* Now we can fill the read buffer */
5265 if (dwError != ERROR_FILE_NOT_FOUND &&
5266 dwType == REG_BINARY)
5267 {
5268 dwError = RegQueryValueExW(hServiceKey,
5269 L"FailureActions",
5270 NULL,
5271 NULL,
5272 (LPBYTE)lpReadBuffer,
5273 &dwRequiredSize);
5274 if (dwError != ERROR_SUCCESS &&
5275 dwError != ERROR_FILE_NOT_FOUND)
5276 goto done;
5277
5278 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
5279 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5280 }
5281 else
5282 {
5283 /*
5284 * The value of the error doesn't really matter, the only
5285 * important thing is that it must be != ERROR_SUCCESS.
5286 */
5287 dwError = ERROR_INVALID_DATA;
5288 }
5289
5290 if (dwError == ERROR_SUCCESS)
5291 {
5292 lpReadBuffer->cActions = min(lpReadBuffer->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
5293 lpReadBuffer->lpsaActions = (lpReadBuffer->cActions > 0 ? (LPSC_ACTION)(lpReadBuffer + 1) : NULL);
5294 }
5295 else
5296 {
5297 lpReadBuffer->dwResetPeriod = 0;
5298 lpReadBuffer->cActions = 0;
5299 lpReadBuffer->lpsaActions = NULL;
5300 }
5301
5302 lpReadBuffer->lpRebootMsg = NULL;
5303 lpReadBuffer->lpCommand = NULL;
5304
5305 /*
5306 * 2- Initialize the new value to set.
5307 */
5308
5309 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5310
5311 if (lpFailureActions->lpsaActions == NULL)
5312 {
5313 /*
5314 * lpFailureActions->cActions is ignored.
5315 * Therefore we use the original values
5316 * of cActions and lpsaActions.
5317 */
5318 dwRequiredSize += lpReadBuffer->cActions * sizeof(SC_ACTION);
5319 }
5320 else
5321 {
5322 /*
5323 * The reset period and array of failure actions
5324 * are deleted if lpFailureActions->cActions == 0 .
5325 */
5326 dwRequiredSize += lpFailureActions->cActions * sizeof(SC_ACTION);
5327 }
5328
5329 lpWriteBuffer = HeapAlloc(GetProcessHeap(),
5330 HEAP_ZERO_MEMORY,
5331 dwRequiredSize);
5332 if (lpWriteBuffer == NULL)
5333 {
5334 dwError = ERROR_NOT_ENOUGH_MEMORY;
5335 goto done;
5336 }
5337
5338 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5339 lpWriteBuffer->lpRebootMsg = NULL;
5340 lpWriteBuffer->lpCommand = NULL;
5341 lpWriteBuffer->lpsaActions = NULL;
5342
5343 /* Set the members */
5344 if (lpFailureActions->lpsaActions == NULL)
5345 {
5346 /*
5347 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5348 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5349 */
5350 lpWriteBuffer->dwResetPeriod = lpReadBuffer->dwResetPeriod;
5351 lpWriteBuffer->cActions = lpReadBuffer->cActions;
5352
5353 if (lpReadBuffer->lpsaActions != NULL)
5354 {
5355 memmove(lpWriteBuffer + 1,
5356 lpReadBuffer->lpsaActions,
5357 lpReadBuffer->cActions * sizeof(SC_ACTION));
5358 }
5359 }
5360 else
5361 {
5362 if (lpFailureActions->cActions > 0)
5363 {
5364 lpWriteBuffer->dwResetPeriod = lpFailureActions->dwResetPeriod;
5365 lpWriteBuffer->cActions = lpFailureActions->cActions;
5366
5367 memmove(lpWriteBuffer + 1,
5368 lpFailureActions->lpsaActions,
5369 lpFailureActions->cActions * sizeof(SC_ACTION));
5370 }
5371 else
5372 {
5373 /* The reset period and array of failure actions are deleted */
5374 lpWriteBuffer->dwResetPeriod = 0;
5375 lpWriteBuffer->cActions = 0;
5376 }
5377 }
5378
5379 /* Save the new failure actions into the registry */
5380 dwError = RegSetValueExW(hServiceKey,
5381 L"FailureActions",
5382 0,
5383 REG_BINARY,
5384 (LPBYTE)lpWriteBuffer,
5385 dwRequiredSize);
5386
5387 /* We modify the strings only in case of success.*/
5388 if (dwError == ERROR_SUCCESS)
5389 {
5390 /* Modify the Reboot Message value, if specified */
5391 if (lpFailureActions->lpRebootMsg != NULL)
5392 {
5393 /* If the Reboot Message is "" then we delete it */
5394 if (*lpFailureActions->lpRebootMsg == 0)
5395 {
5396 DPRINT("Delete Reboot Message value\n");
5397 RegDeleteValueW(hServiceKey, L"RebootMessage");
5398 }
5399 else
5400 {
5401 DPRINT("Setting Reboot Message value %S\n", lpFailureActions->lpRebootMsg);
5402 RegSetValueExW(hServiceKey,
5403 L"RebootMessage",
5404 0,
5405 REG_SZ,
5406 (LPBYTE)lpFailureActions->lpRebootMsg,
5407 (DWORD)((wcslen(lpFailureActions->lpRebootMsg) + 1) * sizeof(WCHAR)));
5408 }
5409 }
5410
5411 /* Modify the Failure Command value, if specified */
5412 if (lpFailureActions->lpCommand != NULL)
5413 {
5414 /* If the FailureCommand string is an empty string, delete the value */
5415 if (*lpFailureActions->lpCommand == 0)
5416 {
5417 DPRINT("Delete Failure Command value\n");
5418 RegDeleteValueW(hServiceKey, L"FailureCommand");
5419 }
5420 else
5421 {
5422 DPRINT("Setting Failure Command value %S\n", lpFailureActions->lpCommand);
5423 RegSetValueExW(hServiceKey,
5424 L"FailureCommand",
5425 0,
5426 REG_SZ,
5427 (LPBYTE)lpFailureActions->lpCommand,
5428 (DWORD)((wcslen(lpFailureActions->lpCommand) + 1) * sizeof(WCHAR)));
5429 }
5430 }
5431 }
5432
5433 done:
5434 if (lpWriteBuffer != NULL)
5435 HeapFree(GetProcessHeap(), 0, lpWriteBuffer);
5436
5437 if (lpReadBuffer != NULL)
5438 HeapFree(GetProcessHeap(), 0, lpReadBuffer);
5439
5440 return dwError;
5441 }
5442
5443
5444 /* Function 37 */
5445 DWORD
5446 WINAPI
5447 RChangeServiceConfig2W(
5448 SC_RPC_HANDLE hService,
5449 SC_RPC_CONFIG_INFOW Info)
5450 {
5451 DWORD dwError = ERROR_SUCCESS;
5452 PSERVICE_HANDLE hSvc;
5453 PSERVICE lpService = NULL;
5454 HKEY hServiceKey = NULL;
5455 ACCESS_MASK RequiredAccess = SERVICE_CHANGE_CONFIG;
5456
5457 DPRINT("RChangeServiceConfig2W() called\n");
5458 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
5459
5460 if (ScmShutdown)
5461 return ERROR_SHUTDOWN_IN_PROGRESS;
5462
5463 hSvc = ScmGetServiceFromHandle(hService);
5464 if (hSvc == NULL)
5465 {
5466 DPRINT("Invalid service handle!\n");
5467 return ERROR_INVALID_HANDLE;
5468 }
5469
5470 if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5471 RequiredAccess |= SERVICE_START;
5472
5473 /* Check the access rights */
5474 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5475 RequiredAccess))
5476 {
5477 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5478 return ERROR_ACCESS_DENIED;
5479 }
5480
5481 if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5482 {
5483 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
5484
5485 }
5486
5487 lpService = hSvc->ServiceEntry;
5488 if (lpService == NULL)
5489 {
5490 DPRINT("lpService == NULL!\n");
5491 return ERROR_INVALID_HANDLE;
5492 }
5493
5494 /* Failure actions can only be set for Win32 services, not for drivers */
5495 if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5496 {
5497 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
5498 return ERROR_CANNOT_DETECT_DRIVER_FAILURE;
5499 }
5500
5501 /* Lock the service database exclusively */
5502 ScmLockDatabaseExclusive();
5503
5504 if (lpService->bDeleted)
5505 {
5506 DPRINT("The service has already been marked for delete!\n");
5507 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
5508 goto done;
5509 }
5510
5511 /* Open the service key */
5512 dwError = ScmOpenServiceKey(lpService->szServiceName,
5513 KEY_READ | KEY_SET_VALUE,
5514 &hServiceKey);
5515 if (dwError != ERROR_SUCCESS)
5516 goto done;
5517
5518 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5519 {
5520 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
5521
5522 /* Modify the service description, if specified */
5523 if (lpServiceDescription != NULL &&
5524 lpServiceDescription->lpDescription != NULL)
5525 {
5526 /* If the description is "" then we delete it */
5527 if (*lpServiceDescription->lpDescription == 0)
5528 {
5529 DPRINT("Delete service description\n");
5530 dwError = RegDeleteValueW(hServiceKey, L"Description");
5531
5532 if (dwError == ERROR_FILE_NOT_FOUND)
5533 dwError = ERROR_SUCCESS;
5534 }
5535 else
5536 {
5537 DPRINT("Setting service description value %S\n", lpServiceDescription->lpDescription);
5538 dwError = RegSetValueExW(hServiceKey,
5539 L"Description",
5540 0,
5541 REG_SZ,
5542 (LPBYTE)lpServiceDescription->lpDescription,
5543 (DWORD)((wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR)));
5544 }
5545 }
5546 else
5547 {
5548 dwError = ERROR_SUCCESS;
5549 }
5550 }
5551 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5552 {
5553 dwError = ScmSetFailureActions(hServiceKey,
5554 (LPSERVICE_FAILURE_ACTIONSW)Info.psfa);
5555 }
5556
5557 done:
5558 if (hServiceKey != NULL)
5559 RegCloseKey(hServiceKey);
5560
5561 /* Unlock the service database */
5562 ScmUnlockDatabase();
5563
5564 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
5565
5566 return dwError;
5567 }
5568
5569
5570 /* Function 38 */
5571 DWORD
5572 WINAPI
5573 RQueryServiceConfig2A(
5574 SC_RPC_HANDLE hService,
5575 DWORD dwInfoLevel,
5576 LPBYTE lpBuffer,
5577 DWORD cbBufSize,
5578 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5579 {
5580 DWORD dwError = ERROR_SUCCESS;
5581 PSERVICE_HANDLE hSvc;
5582 PSERVICE lpService = NULL;
5583 HKEY hServiceKey = NULL;
5584 DWORD dwRequiredSize = 0;
5585 DWORD dwType = 0;
5586 LPWSTR lpDescriptionW = NULL;
5587 LPWSTR lpRebootMessageW = NULL;
5588 LPWSTR lpFailureCommandW = NULL;
5589
5590 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5591 hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
5592
5593 if (!lpBuffer)
5594 return ERROR_INVALID_ADDRESS;
5595
5596 if (ScmShutdown)
5597 return ERROR_SHUTDOWN_IN_PROGRESS;
5598
5599 hSvc = ScmGetServiceFromHandle(hService);
5600 if (hSvc == NULL)
5601 {
5602 DPRINT1("Invalid service handle!\n");
5603 return ERROR_INVALID_HANDLE;
5604 }
5605
5606 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5607 SERVICE_QUERY_CONFIG))
5608 {
5609 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5610 return ERROR_ACCESS_DENIED;
5611 }
5612
5613 lpService = hSvc->ServiceEntry;
5614 if (lpService == NULL)
5615 {
5616 DPRINT("lpService == NULL!\n");
5617 return ERROR_INVALID_HANDLE;
5618 }
5619
5620 /* Lock the service database shared */
5621 ScmLockDatabaseShared();
5622
5623 dwError = ScmOpenServiceKey(lpService->lpServiceName,
5624 KEY_READ,
5625 &hServiceKey);
5626 if (dwError != ERROR_SUCCESS)
5627 goto done;
5628
5629 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5630 {
5631 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
5632 LPSTR lpStr;
5633
5634 dwError = ScmReadString(hServiceKey,
5635 L"Description",
5636 &lpDescriptionW);
5637 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5638 goto done;
5639
5640 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
5641 if (dwError == ERROR_SUCCESS)
5642 *pcbBytesNeeded += (DWORD)((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
5643
5644 if (cbBufSize < *pcbBytesNeeded)
5645 {
5646 dwError = ERROR_INSUFFICIENT_BUFFER;
5647 goto done;
5648 }
5649
5650 if (dwError == ERROR_SUCCESS)
5651 {
5652 lpStr = (LPSTR)(lpServiceDescription + 1);
5653
5654 WideCharToMultiByte(CP_ACP,
5655 0,
5656 lpDescriptionW,
5657 -1,
5658 lpStr,
5659 (int)wcslen(lpDescriptionW),
5660 NULL,
5661 NULL);
5662 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
5663 }
5664 else
5665 {
5666 lpServiceDescription->lpDescription = NULL;
5667 dwError = ERROR_SUCCESS;
5668 }
5669 }
5670 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5671 {
5672 LPSERVICE_FAILURE_ACTIONSA lpFailureActions = (LPSERVICE_FAILURE_ACTIONSA)lpBuffer;
5673 LPSTR lpStr = NULL;
5674
5675 /* Query value length */
5676 dwError = RegQueryValueExW(hServiceKey,
5677 L"FailureActions",
5678 NULL,
5679 &dwType,
5680 NULL,
5681 &dwRequiredSize);
5682 if (dwError != ERROR_SUCCESS &&
5683 dwError != ERROR_MORE_DATA &&
5684 dwError != ERROR_FILE_NOT_FOUND)
5685 goto done;
5686
5687 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSA), dwRequiredSize)
5688 : sizeof(SERVICE_FAILURE_ACTIONSA);
5689
5690 /* Get the strings */
5691 ScmReadString(hServiceKey,
5692 L"FailureCommand",
5693 &lpFailureCommandW);
5694
5695 ScmReadString(hServiceKey,
5696 L"RebootMessage",
5697 &lpRebootMessageW);
5698
5699 if (lpRebootMessageW)
5700 dwRequiredSize += (DWORD)((wcslen(lpRebootMessageW) + 1) * sizeof(WCHAR));
5701
5702 if (lpFailureCommandW)
5703 dwRequiredSize += (DWORD)((wcslen(lpFailureCommandW) + 1) * sizeof(WCHAR));
5704
5705 if (cbBufSize < dwRequiredSize)
5706 {
5707 *pcbBytesNeeded = dwRequiredSize;
5708 dwError = ERROR_INSUFFICIENT_BUFFER;
5709 goto done;
5710 }
5711
5712 /* Now we can fill the buffer */
5713 if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY)
5714 {
5715 dwError = RegQueryValueExW(hServiceKey,
5716 L"FailureActions",
5717 NULL,
5718 NULL,
5719 (LPBYTE)lpFailureActions,
5720 &dwRequiredSize);
5721 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5722 goto done;
5723
5724 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSA))
5725 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSA);
5726 }
5727 else
5728 {
5729 /*
5730 * The value of the error doesn't really matter, the only
5731 * important thing is that it must be != ERROR_SUCCESS .
5732 */
5733 dwError = ERROR_INVALID_DATA;
5734 }
5735
5736 if (dwError == ERROR_SUCCESS)
5737 {
5738 lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSA)) / sizeof(SC_ACTION));
5739
5740 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5741 lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSA) : NULL);
5742
5743 lpStr = (LPSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION));
5744 }
5745 else
5746 {
5747 lpFailureActions->dwResetPeriod = 0;
5748 lpFailureActions->cActions = 0;
5749 lpFailureActions->lpsaActions = NULL;
5750 lpStr = (LPSTR)(lpFailureActions + 1);
5751 }
5752
5753 lpFailureActions->lpRebootMsg = NULL;
5754 lpFailureActions->lpCommand = NULL;
5755
5756 if (lpRebootMessageW)
5757 {
5758 WideCharToMultiByte(CP_ACP,
5759 0,
5760 lpRebootMessageW,
5761 -1,
5762 lpStr,
5763 (int)wcslen(lpRebootMessageW),
5764 NULL,
5765 NULL);
5766 lpFailureActions->lpRebootMsg = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5767 lpStr += strlen(lpStr) + 1;
5768 }
5769
5770 if (lpFailureCommandW)
5771 {
5772 WideCharToMultiByte(CP_ACP,
5773 0,
5774 lpFailureCommandW,
5775 -1,
5776 lpStr,
5777 (int)wcslen(lpFailureCommandW),
5778 NULL,
5779 NULL);
5780 lpFailureActions->lpCommand = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5781 /* lpStr += strlen(lpStr) + 1; */
5782 }
5783
5784 dwError = ERROR_SUCCESS;
5785 }
5786
5787 done:
5788 /* Unlock the service database */
5789 ScmUnlockDatabase();
5790
5791 if (lpDescriptionW != NULL)
5792 HeapFree(GetProcessHeap(), 0, lpDescriptionW);
5793
5794 if (lpRebootMessageW != NULL)
5795 HeapFree(GetProcessHeap(), 0, lpRebootMessageW);
5796
5797 if (lpFailureCommandW != NULL)
5798 HeapFree(GetProcessHeap(), 0, lpFailureCommandW);
5799
5800 if (hServiceKey != NULL)
5801 RegCloseKey(hServiceKey);
5802
5803 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError);
5804
5805 return dwError;
5806 }
5807
5808
5809 /* Function 39 */
5810 DWORD
5811 WINAPI
5812 RQueryServiceConfig2W(
5813 SC_RPC_HANDLE hService,
5814 DWORD dwInfoLevel,
5815 LPBYTE lpBuffer,
5816 DWORD cbBufSize,
5817 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5818 {
5819 DWORD dwError = ERROR_SUCCESS;
5820 PSERVICE_HANDLE hSvc;
5821 PSERVICE lpService = NULL;
5822 HKEY hServiceKey = NULL;
5823 DWORD dwRequiredSize = 0;
5824 DWORD dwType = 0;
5825 LPWSTR lpDescription = NULL;
5826 LPWSTR lpRebootMessage = NULL;
5827 LPWSTR lpFailureCommand = NULL;
5828
5829 DPRINT("RQueryServiceConfig2W() called\n");
5830
5831 if (!lpBuffer)
5832 return ERROR_INVALID_ADDRESS;
5833
5834 if (ScmShutdown)
5835 return ERROR_SHUTDOWN_IN_PROGRESS;
5836
5837 hSvc = ScmGetServiceFromHandle(hService);
5838 if (hSvc == NULL)
5839 {
5840 DPRINT1("Invalid service handle!\n");
5841 return ERROR_INVALID_HANDLE;
5842 }
5843
5844 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5845 SERVICE_QUERY_CONFIG))
5846 {
5847 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5848 return ERROR_ACCESS_DENIED;
5849 }
5850
5851 lpService = hSvc->ServiceEntry;
5852 if (lpService == NULL)
5853 {
5854 DPRINT("lpService == NULL!\n");
5855 return ERROR_INVALID_HANDLE;
5856 }
5857
5858 /* Lock the service database shared */
5859 ScmLockDatabaseShared();
5860
5861 dwError = ScmOpenServiceKey(lpService->lpServiceName,
5862 KEY_READ,
5863 &hServiceKey);
5864 if (dwError != ERROR_SUCCESS)
5865 goto done;
5866
5867 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5868 {
5869 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
5870 LPWSTR lpStr;
5871
5872 dwError = ScmReadString(hServiceKey,
5873 L"Description",
5874 &lpDescription);
5875 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5876 goto done;
5877
5878 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW);
5879 if (dwError == ERROR_SUCCESS)
5880 *pcbBytesNeeded += (DWORD)((wcslen(lpDescription) + 1) * sizeof(WCHAR));
5881
5882 if (cbBufSize < *pcbBytesNeeded)
5883 {
5884 dwError = ERROR_INSUFFICIENT_BUFFER;
5885 goto done;
5886 }
5887
5888 if (dwError == ERROR_SUCCESS)
5889 {
5890 lpStr = (LPWSTR)(lpServiceDescription + 1);
5891 wcscpy(lpStr, lpDescription);
5892 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
5893 }
5894 else
5895 {
5896 lpServiceDescription->lpDescription = NULL;
5897 dwError = ERROR_SUCCESS;
5898 }
5899 }
5900 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5901 {
5902 LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
5903 LPWSTR lpStr = NULL;
5904
5905 /* Query value length */
5906 dwError = RegQueryValueExW(hServiceKey,
5907 L"FailureActions",
5908 NULL,
5909 &dwType,
5910 NULL,
5911 &dwRequiredSize);
5912 if (dwError != ERROR_SUCCESS &&
5913 dwError != ERROR_MORE_DATA &&
5914 dwError != ERROR_FILE_NOT_FOUND)
5915 goto done;
5916
5917 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
5918 : sizeof(SERVICE_FAILURE_ACTIONSW);
5919
5920 /* Get the strings */
5921 ScmReadString(hServiceKey,
5922 L"FailureCommand",
5923 &lpFailureCommand);
5924
5925 ScmReadString(hServiceKey,
5926 L"RebootMessage",
5927 &lpRebootMessage);
5928
5929 if (lpRebootMessage)
5930 dwRequiredSize += (DWORD)((wcslen(lpRebootMessage) + 1) * sizeof(WCHAR));
5931
5932 if (lpFailureCommand)
5933 dwRequiredSize += (DWORD)((wcslen(lpFailureCommand) + 1) * sizeof(WCHAR));
5934
5935 if (cbBufSize < dwRequiredSize)
5936 {
5937 *pcbBytesNeeded = dwRequiredSize;
5938 dwError = ERROR_INSUFFICIENT_BUFFER;
5939 goto done;
5940 }
5941
5942 /* Now we can fill the buffer */
5943 if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY)
5944 {
5945 dwError = RegQueryValueExW(hServiceKey,
5946 L"FailureActions",
5947 NULL,
5948 NULL,
5949 (LPBYTE)lpFailureActions,
5950 &dwRequiredSize);
5951 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5952 goto done;
5953
5954 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
5955 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5956 }
5957 else
5958 {
5959 /*
5960 * The value of the error doesn't really matter, the only
5961 * important thing is that it must be != ERROR_SUCCESS .
5962 */
5963 dwError = ERROR_INVALID_DATA;
5964 }
5965
5966 if (dwError == ERROR_SUCCESS)
5967 {
5968 lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
5969
5970 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5971 lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSW) : NULL);
5972
5973 lpStr = (LPWSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION));
5974 }
5975 else
5976 {
5977 lpFailureActions->dwResetPeriod = 0;
5978 lpFailureActions->cActions = 0;
5979 lpFailureActions->lpsaActions = NULL;
5980 lpStr = (LPWSTR)(lpFailureActions + 1);
5981 }
5982
5983 lpFailureActions->lpRebootMsg = NULL;
5984 lpFailureActions->lpCommand = NULL;
5985
5986 if (lpRebootMessage)
5987 {
5988 wcscpy(lpStr, lpRebootMessage);
5989 lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5990 lpStr += wcslen(lpStr) + 1;
5991 }
5992
5993 if (lpFailureCommand)
5994 {
5995 wcscpy(lpStr, lpFailureCommand);
5996 lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5997 /* lpStr += wcslen(lpStr) + 1; */
5998 }
5999
6000 dwError = ERROR_SUCCESS;
6001 }
6002
6003 done:
6004 /* Unlock the service database */
6005 ScmUnlockDatabase();
6006
6007 if (lpDescription != NULL)
6008 HeapFree(GetProcessHeap(), 0, lpDescription);
6009
6010 if (lpRebootMessage != NULL)
6011 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
6012
6013 if (lpFailureCommand != NULL)
6014 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
6015
6016 if (hServiceKey != NULL)
6017 RegCloseKey(hServiceKey);
6018
6019 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
6020
6021 return dwError;
6022 }
6023
6024
6025 /* Function 40 */
6026 DWORD
6027 WINAPI
6028 RQueryServiceStatusEx(
6029 SC_RPC_HANDLE hService,
6030 SC_STATUS_TYPE InfoLevel,
6031 LPBYTE lpBuffer,
6032 DWORD cbBufSize,
6033 LPBOUNDED_DWORD_8K pcbBytesNeeded)
6034 {
6035 LPSERVICE_STATUS_PROCESS lpStatus;
6036 PSERVICE_HANDLE hSvc;
6037 PSERVICE lpService;
6038
6039 DPRINT("RQueryServiceStatusEx() called\n");
6040
6041 if (ScmShutdown)
6042 return ERROR_SHUTDOWN_IN_PROGRESS;
6043
6044 if (InfoLevel != SC_STATUS_PROCESS_INFO)
6045 return ERROR_INVALID_LEVEL;
6046
6047 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
6048
6049 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
6050 return ERROR_INSUFFICIENT_BUFFER;
6051
6052 hSvc = ScmGetServiceFromHandle(hService);
6053 if (hSvc == NULL)
6054 {
6055 DPRINT1("Invalid service handle!\n");
6056 return ERROR_INVALID_HANDLE;
6057 }
6058
6059 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
6060 SERVICE_QUERY_STATUS))
6061 {
6062 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
6063 return ERROR_ACCESS_DENIED;
6064 }
6065
6066 lpService = hSvc->ServiceEntry;
6067 if (lpService == NULL)
6068 {
6069 DPRINT("lpService == NULL!\n");
6070 return ERROR_INVALID_HANDLE;
6071 }
6072
6073 /* Lock the service database shared */
6074 ScmLockDatabaseShared();
6075
6076 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
6077
6078 /* Return service status information */
6079 RtlCopyMemory(lpStatus,
6080 &lpService->Status,
6081 sizeof(SERVICE_STATUS));
6082
6083 /* Copy the service process ID */
6084 if ((lpService->Status.dwCurrentState == SERVICE_STOPPED) || (lpService->lpImage == NULL))
6085 lpStatus->dwProcessId = 0;
6086 else
6087 lpStatus->dwProcessId = lpService->lpImage->dwProcessId;
6088
6089 lpStatus->dwServiceFlags = 0; /* FIXME */
6090
6091 /* Unlock the service database */
6092 ScmUnlockDatabase();
6093
6094 return ERROR_SUCCESS;
6095 }
6096
6097
6098 /* Function 41 */
6099 DWORD
6100 WINAPI
6101 REnumServicesStatusExA(
6102 SC_RPC_HANDLE hSCManager,
6103 SC_ENUM_TYPE InfoLevel,
6104 DWORD dwServiceType,
6105 DWORD dwServiceState,
6106 LPBYTE lpBuffer,
6107 DWORD cbBufSize,
6108 LPBOUNDED_DWORD_256K pcbBytesNeeded,
6109 LPBOUNDED_DWORD_256K lpServicesReturned,
6110 LPBOUNDED_DWORD_256K lpResumeIndex,
6111 LPCSTR pszGroupName)
6112 {
6113 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
6114 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW;
6115 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
6116 LPWSTR lpStringPtrW;
6117 LPSTR lpStringPtrA;
6118 LPWSTR pszGroupNameW = NULL;
6119 DWORD dwError;
6120 DWORD dwServiceCount;
6121
6122 DPRINT("REnumServicesStatusExA() called\n");
6123
6124 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
6125 {
6126 return ERROR_INVALID_ADDRESS;
6127 }
6128
6129 if (pszGroupName)
6130 {
6131 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
6132 if (!pszGroupNameW)
6133 {
6134 DPRINT("Failed to allocate buffer!\n");
6135 dwError = ERROR_NOT_ENOUGH_MEMORY;
6136 goto Done;
6137 }
6138
6139 MultiByteToWideChar(CP_ACP,
6140 0,
6141 pszGroupName,
6142 -1,
6143 pszGroupNameW,
6144 (int)(strlen(pszGroupName) + 1));
6145 }
6146
6147 if ((cbBufSize > 0) && (lpBuffer))
6148 {
6149 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
6150 if (!lpStatusPtrW)
6151 {
6152 DPRINT("Failed to allocate buffer!\n");
6153 dwError = ERROR_NOT_ENOUGH_MEMORY;
6154 goto Done;
6155 }
6156 }
6157
6158 dwError = REnumServicesStatusExW(hSCManager,
6159 InfoLevel,
6160 dwServiceType,
6161 dwServiceState,
6162 (LPBYTE)lpStatusPtrW,
6163 cbBufSize,
6164 pcbBytesNeeded,
6165 lpServicesReturned,
6166 lpResumeIndex,
6167 pszGroupNameW);
6168
6169 /* if no services were returned then we are Done */
6170 if (*lpServicesReturned == 0)
6171 goto Done;
6172
6173 lpStatusPtrIncrW = lpStatusPtrW;
6174 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
6175 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
6176 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
6177 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
6178 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
6179
6180 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
6181 {
6182 /* Copy the service name */
6183 WideCharToMultiByte(CP_ACP,
6184 0,
6185 lpStringPtrW,
6186 -1,
6187 lpStringPtrA,
6188 (int)wcslen(lpStringPtrW),
6189 0,
6190 0);
6191
6192 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
6193 lpStringPtrA += wcslen(lpStringPtrW) + 1;
6194 lpStringPtrW += wcslen(lpStringPtrW) + 1;
6195
6196 /* Copy the display name */
6197 WideCharToMultiByte(CP_ACP,
6198 0,
6199 lpStringPtrW,
6200 -1,
6201 lpStringPtrA,
6202 (int)wcslen(lpStringPtrW),
6203 0,
6204 0);
6205
6206 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
6207 lpStringPtrA += wcslen(lpStringPtrW) + 1;
6208 lpStringPtrW += wcslen(lpStringPtrW) + 1;
6209
6210 /* Copy the status information */
6211 memcpy(&lpStatusPtrA->ServiceStatusProcess,
6212 &lpStatusPtrIncrW->ServiceStatusProcess,
6213 sizeof(SERVICE_STATUS));
6214
6215 /* Copy the service process ID */
6216 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrIncrW->ServiceStatusProcess.dwProcessId;
6217
6218 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
6219
6220 lpStatusPtrIncrW++;
6221 lpStatusPtrA++;
6222 }
6223
6224 Done:
6225 if (pszGroupNameW)
6226 HeapFree(GetProcessHeap(), 0, pszGroupNameW);
6227
6228 if (lpStatusPtrW)
6229 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
6230
6231 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
6232
6233 return dwError;
6234 }
6235
6236
6237 /* Function 42 */
6238 DWORD
6239 WINAPI
6240 REnumServicesStatusExW(
6241 SC_RPC_HANDLE hSCManager,
6242 SC_ENUM_TYPE InfoLevel,
6243 DWORD dwServiceType,
6244 DWORD dwServiceState,
6245 LPBYTE lpBuffer,
6246 DWORD cbBufSize,
6247 LPBOUNDED_DWORD_256K pcbBytesNeeded,
6248 LPBOUNDED_DWORD_256K lpServicesReturned,
6249 LPBOUNDED_DWORD_256K lpResumeIndex,
6250 LPCWSTR pszGroupName)
6251 {
6252 PMANAGER_HANDLE hManager;
6253 PSERVICE lpService;
6254 DWORD dwError = ERROR_SUCCESS;
6255 PLIST_ENTRY ServiceEntry;
6256 PSERVICE CurrentService;
6257 DWORD dwState;
6258 DWORD dwRequiredSize;
6259 DWORD dwServiceCount;
6260 DWORD dwSize;
6261 DWORD dwLastResumeCount = 0;
6262 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
6263 LPWSTR lpStringPtr;
6264
6265 DPRINT("REnumServicesStatusExW() called\n");
6266
6267 if (ScmShutdown)
6268 return ERROR_SHUTDOWN_IN_PROGRESS;
6269
6270 if (InfoLevel != SC_ENUM_PROCESS_INFO)
6271 return ERROR_INVALID_LEVEL;
6272
6273 hManager = ScmGetServiceManagerFromHandle(hSCManager);
6274 if (hManager == NULL)
6275 {
6276 DPRINT1("Invalid service manager handle!\n");
6277 return ERROR_INVALID_HANDLE;
6278 }
6279
6280 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
6281 {
6282 return ERROR_INVALID_ADDRESS;
6283 }
6284
6285 *pcbBytesNeeded = 0;
6286 *lpServicesReturned = 0;
6287
6288 if ((dwServiceType == 0) ||
6289 ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
6290 {
6291 DPRINT("Not a valid Service Type!\n");
6292 return ERROR_INVALID_PARAMETER;
6293 }
6294
6295 if ((dwServiceState == 0) ||
6296 ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
6297 {
6298 DPRINT("Not a valid Service State!\n");
6299 return ERROR_INVALID_PARAMETER;
6300 }
6301
6302 /* Check access rights */
6303 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
6304 SC_MANAGER_ENUMERATE_SERVICE))
6305 {
6306 DPRINT("Insufficient access rights! 0x%lx\n",
6307 hManager->Handle.DesiredAccess);
6308 return ERROR_ACCESS_DENIED;
6309 }
6310
6311 if (lpResumeIndex)
6312 dwLastResumeCount = *lpResumeIndex;
6313
6314 /* Lock the service database shared */
6315 ScmLockDatabaseShared();
6316
6317 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
6318 if (lpService == NULL)
6319 {
6320 dwError = ERROR_SUCCESS;
6321 goto Done;
6322 }
6323
6324 dwRequiredSize = 0;
6325 dwServiceCount = 0;
6326
6327 for (ServiceEntry = &lpService->ServiceListEntry;
6328 ServiceEntry != &ServiceListHead;
6329 ServiceEntry = ServiceEntry->Flink)
6330 {
6331 CurrentService = CONTAINING_RECORD(ServiceEntry,
6332 SERVICE,
6333 ServiceListEntry);
6334
6335 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6336 continue;
6337
6338 dwState = SERVICE_ACTIVE;
6339 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6340 dwState = SERVICE_INACTIVE;
6341
6342 if ((dwState & dwServiceState) == 0)
6343 continue;
6344
6345 if (pszGroupName)
6346 {
6347 if (*pszGroupName == 0)
6348 {
6349 if (CurrentService->lpGroup != NULL)
6350 continue;
6351 }
6352 else
6353 {
6354 if ((CurrentService->lpGroup == NULL) ||
6355 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6356 continue;
6357 }
6358 }
6359
6360 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6361 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6362 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
6363
6364 if (dwRequiredSize + dwSize <= cbBufSize)
6365 {
6366 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
6367 dwRequiredSize += dwSize;
6368 dwServiceCount++;
6369 dwLastResumeCount = CurrentService->dwResumeCount;
6370 }
6371 else
6372 {
6373 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
6374 break;
6375 }
6376
6377 }
6378
6379 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
6380 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
6381
6382 for (;
6383 ServiceEntry != &ServiceListHead;
6384 ServiceEntry = ServiceEntry->Flink)
6385 {
6386 CurrentService = CONTAINING_RECORD(ServiceEntry,
6387 SERVICE,
6388 ServiceListEntry);
6389
6390 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6391 continue;
6392
6393 dwState = SERVICE_ACTIVE;
6394 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6395 dwState = SERVICE_INACTIVE;
6396
6397 if ((dwState & dwServiceState) == 0)
6398 continue;
6399
6400 if (pszGroupName)
6401 {
6402 if (*pszGroupName == 0)
6403 {
6404 if (CurrentService->lpGroup != NULL)
6405 continue;
6406 }
6407 else
6408 {
6409 if ((CurrentService->lpGroup == NULL) ||
6410 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6411 continue;
6412 }
6413 }
6414
6415 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6416 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6417 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
6418
6419 dwError = ERROR_MORE_DATA;
6420 }
6421
6422 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
6423
6424 if (lpResumeIndex)
6425 *lpResumeIndex = dwLastResumeCount;
6426
6427 *lpServicesReturned = dwServiceCount;
6428 *pcbBytesNeeded = dwRequiredSize;
6429
6430 /* If there was no services that matched */
6431 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
6432 {
6433 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
6434 goto Done;
6435 }
6436
6437 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
6438 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
6439 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
6440
6441 dwRequiredSize = 0;
6442 for (ServiceEntry = &lpService->ServiceListEntry;
6443 ServiceEntry != &ServiceListHead;
6444 ServiceEntry = ServiceEntry->Flink)
6445 {
6446 CurrentService = CONTAINING_RECORD(ServiceEntry,
6447 SERVICE,
6448 ServiceListEntry);
6449
6450 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6451 continue;
6452
6453 dwState = SERVICE_ACTIVE;
6454 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6455 dwState = SERVICE_INACTIVE;
6456
6457 if ((dwState & dwServiceState) == 0)
6458 continue;
6459
6460 if (pszGroupName)
6461 {
6462 if (*pszGroupName == 0)
6463 {
6464 if (CurrentService->lpGroup != NULL)
6465 continue;
6466 }
6467 else
6468 {
6469 if ((CurrentService->lpGroup == NULL) ||
6470 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6471 continue;
6472 }
6473 }
6474
6475 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6476 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6477 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
6478
6479 if (dwRequiredSize + dwSize <= cbBufSize)
6480 {
6481 /* Copy the service name */
6482 wcscpy(lpStringPtr,
6483 CurrentService->lpServiceName);
6484 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
6485 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
6486
6487 /* Copy the display name */
6488 wcscpy(lpStringPtr,
6489 CurrentService->lpDisplayName);
6490 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
6491 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
6492
6493 /* Copy the status information */
6494 memcpy(&lpStatusPtr->ServiceStatusProcess,
6495 &CurrentService->Status,
6496 sizeof(SERVICE_STATUS));
6497
6498 /* Copy the service process ID */
6499 if ((CurrentService->Status.dwCurrentState == SERVICE_STOPPED) || (CurrentService->lpImage == NULL))
6500 lpStatusPtr->ServiceStatusProcess.dwProcessId = 0;
6501 else
6502 lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->lpImage->dwProcessId;
6503
6504 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
6505
6506 lpStatusPtr++;
6507 dwRequiredSize += dwSize;
6508 }
6509 else
6510 {
6511 break;
6512 }
6513 }
6514
6515 if (dwError == 0)
6516 {
6517 *pcbBytesNeeded = 0;
6518 if (lpResumeIndex)
6519 *lpResumeIndex = 0;
6520 }
6521
6522 Done:
6523 /* Unlock the service database */
6524 ScmUnlockDatabase();
6525
6526 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
6527
6528 return dwError;
6529 }
6530
6531
6532 /* Function 43 */
6533 DWORD
6534 WINAPI
6535 RSendTSMessage(
6536 handle_t BindingHandle) /* FIXME */
6537 {
6538 UNIMPLEMENTED;
6539 return ERROR_CALL_NOT_IMPLEMENTED;
6540 }
6541
6542
6543 /* Function 44 */
6544 DWORD
6545 WINAPI
6546 RCreateServiceWOW64A(
6547 handle_t BindingHandle,
6548 LPSTR lpServiceName,
6549 LPSTR lpDisplayName,
6550 DWORD dwDesiredAccess,
6551 DWORD dwServiceType,
6552 DWORD dwStartType,
6553 DWORD dwErrorControl,
6554 LPSTR lpBinaryPathName,
6555 LPSTR lpLoadOrderGroup,
6556 LPDWORD lpdwTagId,
6557 LPBYTE lpDependencies,
6558 DWORD dwDependSize,
6559 LPSTR lpServiceStartName,
6560 LPBYTE lpPassword,
6561 DWORD dwPwSize,
6562 LPSC_RPC_HANDLE lpServiceHandle)
6563 {
6564 UNIMPLEMENTED;
6565 return ERROR_CALL_NOT_IMPLEMENTED;
6566 }
6567
6568
6569 /* Function 45 */
6570 DWORD
6571 WINAPI
6572 RCreateServiceWOW64W(
6573 handle_t BindingHandle,
6574 LPWSTR lpServiceName,
6575 LPWSTR lpDisplayName,
6576 DWORD dwDesiredAccess,
6577 DWORD dwServiceType,
6578 DWORD dwStartType,
6579 DWORD dwErrorControl,
6580 LPWSTR lpBinaryPathName,
6581 LPWSTR lpLoadOrderGroup,
6582 LPDWORD lpdwTagId,
6583 LPBYTE lpDependencies,
6584 DWORD dwDependSize,
6585 LPWSTR lpServiceStartName,
6586 LPBYTE lpPassword,
6587 DWORD dwPwSize,
6588 LPSC_RPC_HANDLE lpServiceHandle)
6589 {
6590 UNIMPLEMENTED;
6591 return ERROR_CALL_NOT_IMPLEMENTED;
6592 }
6593
6594
6595 /* Function 46 */
6596 DWORD
6597 WINAPI
6598 RQueryServiceTagInfo(
6599 handle_t BindingHandle) /* FIXME */
6600 {
6601 UNIMPLEMENTED;
6602 return ERROR_CALL_NOT_IMPLEMENTED;
6603 }
6604
6605
6606 /* Function 47 */
6607 DWORD
6608 WINAPI
6609 RNotifyServiceStatusChange(
6610 SC_RPC_HANDLE hService,
6611 SC_RPC_NOTIFY_PARAMS NotifyParams,
6612 GUID *pClientProcessGuid,
6613 GUID *pSCMProcessGuid,
6614 PBOOL pfCreateRemoteQueue,
6615 LPSC_NOTIFY_RPC_HANDLE phNotify)
6616 {
6617 UNIMPLEMENTED;
6618 return ERROR_CALL_NOT_IMPLEMENTED;
6619 }
6620
6621
6622 /* Function 48 */
6623 DWORD
6624 WINAPI
6625 RGetNotifyResults(
6626 SC_NOTIFY_RPC_HANDLE hNotify,
6627 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
6628 {
6629 UNIMPLEMENTED;
6630 return ERROR_CALL_NOT_IMPLEMENTED;
6631 }
6632
6633
6634 /* Function 49 */
6635 DWORD
6636 WINAPI
6637 RCloseNotifyHandle(
6638 LPSC_NOTIFY_RPC_HANDLE phNotify,
6639 PBOOL pfApcFired)
6640 {
6641 UNIMPLEMENTED;
6642 return ERROR_CALL_NOT_IMPLEMENTED;
6643 }
6644
6645
6646 /* Function 50 */
6647 DWORD
6648 WINAPI
6649 RControlServiceExA(
6650 SC_RPC_HANDLE hService,
6651 DWORD dwControl,
6652 DWORD dwInfoLevel)
6653 {
6654 UNIMPLEMENTED;
6655 return ERROR_CALL_NOT_IMPLEMENTED;
6656 }
6657
6658
6659 /* Function 51 */
6660 DWORD
6661 WINAPI
6662 RControlServiceExW(
6663 SC_RPC_HANDLE hService,
6664 DWORD dwControl,
6665 DWORD dwInfoLevel)
6666 {
6667 UNIMPLEMENTED;
6668 return ERROR_CALL_NOT_IMPLEMENTED;
6669 }
6670
6671
6672 /* Function 52 */
6673 DWORD
6674 WINAPI
6675 RSendPnPMessage(
6676 handle_t BindingHandle) /* FIXME */
6677 {
6678 UNIMPLEMENTED;
6679 return ERROR_CALL_NOT_IMPLEMENTED;
6680 }
6681
6682
6683 /* Function 53 */
6684 DWORD
6685 WINAPI
6686 RValidatePnPService(
6687 handle_t BindingHandle) /* FIXME */
6688 {
6689 UNIMPLEMENTED;
6690 return ERROR_CALL_NOT_IMPLEMENTED;
6691 }
6692
6693
6694 /* Function 54 */
6695 DWORD
6696 WINAPI
6697 ROpenServiceStatusHandle(
6698 handle_t BindingHandle) /* FIXME */
6699 {
6700 UNIMPLEMENTED;
6701 return ERROR_CALL_NOT_IMPLEMENTED;
6702 }
6703
6704
6705 /* Function 55 */
6706 DWORD
6707 WINAPI
6708 RFunction55(
6709 handle_t BindingHandle) /* FIXME */
6710 {
6711 UNIMPLEMENTED;
6712 return ERROR_CALL_NOT_IMPLEMENTED;
6713 }
6714
6715
6716 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
6717 {
6718 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
6719 }
6720
6721
6722 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
6723 {
6724 HeapFree(GetProcessHeap(), 0, ptr);
6725 }
6726
6727
6728 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
6729 {
6730 /* Close the handle */
6731 RCloseServiceHandle(&hSCObject);
6732 }
6733
6734
6735 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
6736 {
6737 /* Unlock the database */
6738 RUnlockServiceDatabase(&Lock);
6739 }
6740
6741
6742 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
6743 {
6744 }
6745
6746 /* EOF */