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