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