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