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