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