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