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