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