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