[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 == 0) ||
2515 ((dwServiceType & ~(SERVICE_DRIVER | SERVICE_WIN32)) != 0))
2516 {
2517 DPRINT("Not a valid Service Type!\n");
2518 return ERROR_INVALID_PARAMETER;
2519 }
2520
2521 if ((dwServiceState != SERVICE_ACTIVE) &&
2522 (dwServiceState != SERVICE_INACTIVE) &&
2523 (dwServiceState != SERVICE_STATE_ALL))
2524 {
2525 DPRINT("Not a valid Service State!\n");
2526 return ERROR_INVALID_PARAMETER;
2527 }
2528
2529 /* Check access rights */
2530 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2531 SC_MANAGER_ENUMERATE_SERVICE))
2532 {
2533 DPRINT("Insufficient access rights! 0x%lx\n",
2534 hManager->Handle.DesiredAccess);
2535 return ERROR_ACCESS_DENIED;
2536 }
2537
2538 if (lpResumeHandle)
2539 dwLastResumeCount = *lpResumeHandle;
2540
2541 /* Lock the service database shared */
2542 ScmLockDatabaseShared();
2543
2544 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2545 if (lpService == NULL)
2546 {
2547 dwError = ERROR_SUCCESS;
2548 goto Done;
2549 }
2550
2551 dwRequiredSize = 0;
2552 dwServiceCount = 0;
2553
2554 for (ServiceEntry = &lpService->ServiceListEntry;
2555 ServiceEntry != &ServiceListHead;
2556 ServiceEntry = ServiceEntry->Flink)
2557 {
2558 CurrentService = CONTAINING_RECORD(ServiceEntry,
2559 SERVICE,
2560 ServiceListEntry);
2561
2562 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2563 continue;
2564
2565 dwState = SERVICE_ACTIVE;
2566 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2567 dwState = SERVICE_INACTIVE;
2568
2569 if ((dwState & dwServiceState) == 0)
2570 continue;
2571
2572 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2573 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2574 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2575
2576 if (dwRequiredSize + dwSize > dwBufSize)
2577 {
2578 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2579 break;
2580 }
2581
2582 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2583 dwRequiredSize += dwSize;
2584 dwServiceCount++;
2585 dwLastResumeCount = CurrentService->dwResumeCount;
2586 }
2587
2588 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2589 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2590
2591 for (;
2592 ServiceEntry != &ServiceListHead;
2593 ServiceEntry = ServiceEntry->Flink)
2594 {
2595 CurrentService = CONTAINING_RECORD(ServiceEntry,
2596 SERVICE,
2597 ServiceListEntry);
2598
2599 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2600 continue;
2601
2602 dwState = SERVICE_ACTIVE;
2603 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2604 dwState = SERVICE_INACTIVE;
2605
2606 if ((dwState & dwServiceState) == 0)
2607 continue;
2608
2609 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2610 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2611 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2612
2613 dwError = ERROR_MORE_DATA;
2614 }
2615
2616 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2617
2618 if (lpResumeHandle)
2619 *lpResumeHandle = dwLastResumeCount;
2620
2621 *lpServicesReturned = dwServiceCount;
2622 *pcbBytesNeeded = dwRequiredSize;
2623
2624 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2625 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2626 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2627
2628 dwRequiredSize = 0;
2629 for (ServiceEntry = &lpService->ServiceListEntry;
2630 ServiceEntry != &ServiceListHead;
2631 ServiceEntry = ServiceEntry->Flink)
2632 {
2633 CurrentService = CONTAINING_RECORD(ServiceEntry,
2634 SERVICE,
2635 ServiceListEntry);
2636
2637 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2638 continue;
2639
2640 dwState = SERVICE_ACTIVE;
2641 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2642 dwState = SERVICE_INACTIVE;
2643
2644 if ((dwState & dwServiceState) == 0)
2645 continue;
2646
2647 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2648 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2649 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2650
2651 if (dwRequiredSize + dwSize > dwBufSize)
2652 break;
2653
2654 /* Copy the service name */
2655 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2656 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2657 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2658
2659 /* Copy the display name */
2660 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2661 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2662 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2663
2664 /* Copy the status information */
2665 memcpy(&lpStatusPtr->ServiceStatus,
2666 &CurrentService->Status,
2667 sizeof(SERVICE_STATUS));
2668
2669 lpStatusPtr++;
2670 dwRequiredSize += dwSize;
2671 }
2672
2673 if (dwError == ERROR_SUCCESS)
2674 {
2675 *pcbBytesNeeded = 0;
2676 if (lpResumeHandle) *lpResumeHandle = 0;
2677 }
2678
2679 Done:;
2680 /* Unlock the service database */
2681 ScmUnlockDatabase();
2682
2683 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2684
2685 return dwError;
2686 }
2687
2688
2689 /* Function 15 */
2690 DWORD ROpenSCManagerW(
2691 LPWSTR lpMachineName,
2692 LPWSTR lpDatabaseName,
2693 DWORD dwDesiredAccess,
2694 LPSC_RPC_HANDLE lpScHandle)
2695 {
2696 DWORD dwError;
2697 SC_HANDLE hHandle;
2698
2699 DPRINT("ROpenSCManagerW() called\n");
2700 DPRINT("lpMachineName = %p\n", lpMachineName);
2701 DPRINT("lpMachineName: %S\n", lpMachineName);
2702 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2703 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2704 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2705
2706 if (ScmShutdown)
2707 return ERROR_SHUTDOWN_IN_PROGRESS;
2708
2709 if (!lpScHandle)
2710 return ERROR_INVALID_PARAMETER;
2711
2712 dwError = ScmCreateManagerHandle(lpDatabaseName,
2713 &hHandle);
2714 if (dwError != ERROR_SUCCESS)
2715 {
2716 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2717 return dwError;
2718 }
2719
2720 /* Check the desired access */
2721 dwError = ScmCheckAccess(hHandle,
2722 dwDesiredAccess | SC_MANAGER_CONNECT);
2723 if (dwError != ERROR_SUCCESS)
2724 {
2725 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2726 HeapFree(GetProcessHeap(), 0, hHandle);
2727 return dwError;
2728 }
2729
2730 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2731 DPRINT("*hScm = %p\n", *lpScHandle);
2732
2733 DPRINT("ROpenSCManagerW() done\n");
2734
2735 return ERROR_SUCCESS;
2736 }
2737
2738
2739 /* Function 16 */
2740 DWORD ROpenServiceW(
2741 SC_RPC_HANDLE hSCManager,
2742 LPWSTR lpServiceName,
2743 DWORD dwDesiredAccess,
2744 LPSC_RPC_HANDLE lpServiceHandle)
2745 {
2746 PSERVICE lpService;
2747 PMANAGER_HANDLE hManager;
2748 SC_HANDLE hHandle;
2749 DWORD dwError = ERROR_SUCCESS;
2750
2751 DPRINT("ROpenServiceW() called\n");
2752 DPRINT("hSCManager = %p\n", hSCManager);
2753 DPRINT("lpServiceName = %p\n", lpServiceName);
2754 DPRINT("lpServiceName: %S\n", lpServiceName);
2755 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2756
2757 if (ScmShutdown)
2758 return ERROR_SHUTDOWN_IN_PROGRESS;
2759
2760 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2761 if (hManager == NULL)
2762 {
2763 DPRINT1("Invalid service manager handle!\n");
2764 return ERROR_INVALID_HANDLE;
2765 }
2766
2767 if (!lpServiceHandle)
2768 return ERROR_INVALID_PARAMETER;
2769
2770 if (!lpServiceName)
2771 return ERROR_INVALID_ADDRESS;
2772
2773 /* Lock the service database exclusive */
2774 ScmLockDatabaseExclusive();
2775
2776 /* Get service database entry */
2777 lpService = ScmGetServiceEntryByName(lpServiceName);
2778 if (lpService == NULL)
2779 {
2780 DPRINT("Could not find a service!\n");
2781 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2782 goto Done;
2783 }
2784
2785 /* Create a service handle */
2786 dwError = ScmCreateServiceHandle(lpService,
2787 &hHandle);
2788 if (dwError != ERROR_SUCCESS)
2789 {
2790 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2791 goto Done;
2792 }
2793
2794 /* Check the desired access */
2795 dwError = ScmCheckAccess(hHandle,
2796 dwDesiredAccess);
2797 if (dwError != ERROR_SUCCESS)
2798 {
2799 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2800 HeapFree(GetProcessHeap(), 0, hHandle);
2801 goto Done;
2802 }
2803
2804 lpService->dwRefCount++;
2805 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2806
2807 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2808 DPRINT("*hService = %p\n", *lpServiceHandle);
2809
2810 Done:;
2811 /* Unlock the service database */
2812 ScmUnlockDatabase();
2813
2814 DPRINT("ROpenServiceW() done\n");
2815
2816 return dwError;
2817 }
2818
2819
2820 /* Function 17 */
2821 DWORD RQueryServiceConfigW(
2822 SC_RPC_HANDLE hService,
2823 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2824 DWORD cbBufSize,
2825 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2826 {
2827 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2828 DWORD dwError = ERROR_SUCCESS;
2829 PSERVICE_HANDLE hSvc;
2830 PSERVICE lpService = NULL;
2831 HKEY hServiceKey = NULL;
2832 LPWSTR lpImagePath = NULL;
2833 LPWSTR lpServiceStartName = NULL;
2834 LPWSTR lpDependencies = NULL;
2835 DWORD dwDependenciesLength = 0;
2836 DWORD dwRequiredSize;
2837 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2838 WCHAR lpEmptyString[] = {0,0};
2839 LPWSTR lpStr;
2840
2841 DPRINT("RQueryServiceConfigW() called\n");
2842
2843 if (ScmShutdown)
2844 return ERROR_SHUTDOWN_IN_PROGRESS;
2845
2846 hSvc = ScmGetServiceFromHandle(hService);
2847 if (hSvc == NULL)
2848 {
2849 DPRINT1("Invalid service handle!\n");
2850 return ERROR_INVALID_HANDLE;
2851 }
2852
2853 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2854 SERVICE_QUERY_CONFIG))
2855 {
2856 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2857 return ERROR_ACCESS_DENIED;
2858 }
2859
2860 lpService = hSvc->ServiceEntry;
2861 if (lpService == NULL)
2862 {
2863 DPRINT("lpService == NULL!\n");
2864 return ERROR_INVALID_HANDLE;
2865 }
2866
2867 /* Lock the service database shared */
2868 ScmLockDatabaseShared();
2869
2870 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2871 KEY_READ,
2872 &hServiceKey);
2873 if (dwError != ERROR_SUCCESS)
2874 goto Done;
2875
2876 /* Read the image path */
2877 dwError = ScmReadString(hServiceKey,
2878 L"ImagePath",
2879 &lpImagePath);
2880 if (dwError != ERROR_SUCCESS)
2881 goto Done;
2882
2883 /* Read the service start name */
2884 ScmReadString(hServiceKey,
2885 L"ObjectName",
2886 &lpServiceStartName);
2887
2888 /* Read the dependencies */
2889 ScmReadDependencies(hServiceKey,
2890 &lpDependencies,
2891 &dwDependenciesLength);
2892
2893 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2894
2895 if (lpImagePath != NULL)
2896 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2897 else
2898 dwRequiredSize += 2 * sizeof(WCHAR);
2899
2900 if (lpService->lpGroup != NULL)
2901 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2902 else
2903 dwRequiredSize += 2 * sizeof(WCHAR);
2904
2905 if (lpDependencies != NULL)
2906 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2907 else
2908 dwRequiredSize += 2 * sizeof(WCHAR);
2909
2910 if (lpServiceStartName != NULL)
2911 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2912 else
2913 dwRequiredSize += 2 * sizeof(WCHAR);
2914
2915 if (lpService->lpDisplayName != NULL)
2916 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2917 else
2918 dwRequiredSize += 2 * sizeof(WCHAR);
2919
2920 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2921 {
2922 dwError = ERROR_INSUFFICIENT_BUFFER;
2923 }
2924 else
2925 {
2926 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2927 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2928 lpConfig->dwStartType = lpService->dwStartType;
2929 lpConfig->dwErrorControl = lpService->dwErrorControl;
2930 lpConfig->dwTagId = lpService->dwTag;
2931
2932 lpStr = (LPWSTR)(lpConfig + 1);
2933
2934 /* Append the image path */
2935 if (lpImagePath != NULL)
2936 {
2937 wcscpy(lpStr, lpImagePath);
2938 }
2939 else
2940 {
2941 wcscpy(lpStr, lpEmptyString);
2942 }
2943
2944 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2945 lpStr += (wcslen(lpStr) + 1);
2946
2947 /* Append the group name */
2948 if (lpService->lpGroup != NULL)
2949 {
2950 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2951 }
2952 else
2953 {
2954 wcscpy(lpStr, lpEmptyString);
2955 }
2956
2957 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2958 lpStr += (wcslen(lpStr) + 1);
2959
2960 /* Append Dependencies */
2961 if (lpDependencies != NULL)
2962 {
2963 memcpy(lpStr,
2964 lpDependencies,
2965 dwDependenciesLength * sizeof(WCHAR));
2966 }
2967 else
2968 {
2969 wcscpy(lpStr, lpEmptyString);
2970 }
2971
2972 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2973 if (lpDependencies != NULL)
2974 lpStr += dwDependenciesLength * sizeof(WCHAR);
2975 else
2976 lpStr += (wcslen(lpStr) + 1);
2977
2978 /* Append the service start name */
2979 if (lpServiceStartName != NULL)
2980 {
2981 wcscpy(lpStr, lpServiceStartName);
2982 }
2983 else
2984 {
2985 wcscpy(lpStr, lpEmptyString);
2986 }
2987
2988 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2989 lpStr += (wcslen(lpStr) + 1);
2990
2991 /* Append the display name */
2992 if (lpService->lpDisplayName != NULL)
2993 {
2994 wcscpy(lpStr, lpService->lpDisplayName);
2995 }
2996 else
2997 {
2998 wcscpy(lpStr, lpEmptyString);
2999 }
3000
3001 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3002 }
3003
3004 if (pcbBytesNeeded != NULL)
3005 *pcbBytesNeeded = dwRequiredSize;
3006
3007 Done:;
3008 /* Unlock the service database */
3009 ScmUnlockDatabase();
3010
3011 if (lpImagePath != NULL)
3012 HeapFree(GetProcessHeap(), 0, lpImagePath);
3013
3014 if (lpServiceStartName != NULL)
3015 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3016
3017 if (lpDependencies != NULL)
3018 HeapFree(GetProcessHeap(), 0, lpDependencies);
3019
3020 if (hServiceKey != NULL)
3021 RegCloseKey(hServiceKey);
3022
3023 DPRINT("RQueryServiceConfigW() done\n");
3024
3025 return dwError;
3026 }
3027
3028
3029 /* Function 18 */
3030 DWORD RQueryServiceLockStatusW(
3031 SC_RPC_HANDLE hSCManager,
3032 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3033 DWORD cbBufSize,
3034 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3035 {
3036 UNIMPLEMENTED;
3037 return ERROR_CALL_NOT_IMPLEMENTED;
3038 }
3039
3040
3041 /* Function 19 */
3042 DWORD RStartServiceW(
3043 SC_RPC_HANDLE hService,
3044 DWORD argc,
3045 LPSTRING_PTRSW argv)
3046 {
3047 DWORD dwError = ERROR_SUCCESS;
3048 PSERVICE_HANDLE hSvc;
3049 PSERVICE lpService = NULL;
3050 DWORD i;
3051
3052 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3053 DPRINT(" argc: %lu\n", argc);
3054 if (argv != NULL)
3055 {
3056 for (i = 0; i < argc; i++)
3057 {
3058 DPRINT(" argv[%lu]: %S\n", i, argv[i]);
3059 }
3060 }
3061
3062 if (ScmShutdown)
3063 return ERROR_SHUTDOWN_IN_PROGRESS;
3064
3065 hSvc = ScmGetServiceFromHandle(hService);
3066 if (hSvc == NULL)
3067 {
3068 DPRINT1("Invalid service handle!\n");
3069 return ERROR_INVALID_HANDLE;
3070 }
3071
3072 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3073 SERVICE_START))
3074 {
3075 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3076 return ERROR_ACCESS_DENIED;
3077 }
3078
3079 lpService = hSvc->ServiceEntry;
3080 if (lpService == NULL)
3081 {
3082 DPRINT("lpService == NULL!\n");
3083 return ERROR_INVALID_HANDLE;
3084 }
3085
3086 if (lpService->dwStartType == SERVICE_DISABLED)
3087 return ERROR_SERVICE_DISABLED;
3088
3089 if (lpService->bDeleted)
3090 return ERROR_SERVICE_MARKED_FOR_DELETE;
3091
3092 /* Start the service */
3093 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3094
3095 return dwError;
3096 }
3097
3098
3099 /* Function 20 */
3100 DWORD RGetServiceDisplayNameW(
3101 SC_RPC_HANDLE hSCManager,
3102 LPCWSTR lpServiceName,
3103 LPWSTR lpDisplayName,
3104 DWORD *lpcchBuffer)
3105 {
3106 // PMANAGER_HANDLE hManager;
3107 PSERVICE lpService;
3108 DWORD dwLength;
3109 DWORD dwError;
3110
3111 DPRINT("RGetServiceDisplayNameW() called\n");
3112 DPRINT("hSCManager = %p\n", hSCManager);
3113 DPRINT("lpServiceName: %S\n", lpServiceName);
3114 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3115 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3116
3117 // hManager = (PMANAGER_HANDLE)hSCManager;
3118 // if (hManager->Handle.Tag != MANAGER_TAG)
3119 // {
3120 // DPRINT("Invalid manager handle!\n");
3121 // return ERROR_INVALID_HANDLE;
3122 // }
3123
3124 /* Get service database entry */
3125 lpService = ScmGetServiceEntryByName(lpServiceName);
3126 if (lpService == NULL)
3127 {
3128 DPRINT("Could not find a service!\n");
3129
3130 /* If the service could not be found and lpcchBuffer is less than 2, windows
3131 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3132 if (*lpcchBuffer < 2)
3133 {
3134 *lpcchBuffer = 2;
3135 if (lpDisplayName != NULL)
3136 {
3137 *lpDisplayName = '\0';
3138 }
3139 }
3140
3141 return ERROR_SERVICE_DOES_NOT_EXIST;
3142 }
3143
3144 if (!lpService->lpDisplayName)
3145 {
3146 dwLength = wcslen(lpService->lpServiceName);
3147
3148 if (lpDisplayName != NULL &&
3149 *lpcchBuffer > dwLength)
3150 {
3151 wcscpy(lpDisplayName, lpService->lpServiceName);
3152 }
3153 }
3154 else
3155 {
3156 dwLength = wcslen(lpService->lpDisplayName);
3157
3158 if (lpDisplayName != NULL &&
3159 *lpcchBuffer > dwLength)
3160 {
3161 wcscpy(lpDisplayName, lpService->lpDisplayName);
3162 }
3163 }
3164
3165 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3166
3167 *lpcchBuffer = dwLength;
3168
3169 return dwError;
3170 }
3171
3172
3173 /* Function 21 */
3174 DWORD RGetServiceKeyNameW(
3175 SC_RPC_HANDLE hSCManager,
3176 LPCWSTR lpDisplayName,
3177 LPWSTR lpServiceName,
3178 DWORD *lpcchBuffer)
3179 {
3180 // PMANAGER_HANDLE hManager;
3181 PSERVICE lpService;
3182 DWORD dwLength;
3183 DWORD dwError;
3184
3185 DPRINT("RGetServiceKeyNameW() called\n");
3186 DPRINT("hSCManager = %p\n", hSCManager);
3187 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3188 DPRINT("lpServiceName: %p\n", lpServiceName);
3189 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3190
3191 // hManager = (PMANAGER_HANDLE)hSCManager;
3192 // if (hManager->Handle.Tag != MANAGER_TAG)
3193 // {
3194 // DPRINT("Invalid manager handle!\n");
3195 // return ERROR_INVALID_HANDLE;
3196 // }
3197
3198 /* Get service database entry */
3199 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3200 if (lpService == NULL)
3201 {
3202 DPRINT("Could not find a service!\n");
3203
3204 /* If the service could not be found and lpcchBuffer is less than 2, windows
3205 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3206 if (*lpcchBuffer < 2)
3207 {
3208 *lpcchBuffer = 2;
3209 if (lpServiceName != NULL)
3210 {
3211 *lpServiceName = '\0';
3212 }
3213 }
3214
3215 return ERROR_SERVICE_DOES_NOT_EXIST;
3216 }
3217
3218 dwLength = wcslen(lpService->lpServiceName);
3219
3220 if (lpServiceName != NULL &&
3221 *lpcchBuffer > dwLength)
3222 {
3223 wcscpy(lpServiceName, lpService->lpServiceName);
3224 *lpcchBuffer = dwLength;
3225 return ERROR_SUCCESS;
3226 }
3227
3228 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3229
3230 *lpcchBuffer = dwLength;
3231
3232 return dwError;
3233 }
3234
3235
3236 /* Function 22 */
3237 DWORD RI_ScSetServiceBitsA(
3238 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3239 DWORD dwServiceBits,
3240 int bSetBitsOn,
3241 int bUpdateImmediately,
3242 char *lpString)
3243 {
3244 UNIMPLEMENTED;
3245 return ERROR_CALL_NOT_IMPLEMENTED;
3246 }
3247
3248
3249 /* Function 23 */
3250 DWORD RChangeServiceConfigA(
3251 SC_RPC_HANDLE hService,
3252 DWORD dwServiceType,
3253 DWORD dwStartType,
3254 DWORD dwErrorControl,
3255 LPSTR lpBinaryPathName,
3256 LPSTR lpLoadOrderGroup,
3257 LPDWORD lpdwTagId,
3258 LPSTR lpDependencies,
3259 DWORD dwDependSize,
3260 LPSTR lpServiceStartName,
3261 LPBYTE lpPassword,
3262 DWORD dwPwSize,
3263 LPSTR lpDisplayName)
3264 {
3265 DWORD dwError = ERROR_SUCCESS;
3266 PSERVICE_HANDLE hSvc;
3267 PSERVICE lpService = NULL;
3268 HKEY hServiceKey = NULL;
3269 LPWSTR lpDisplayNameW = NULL;
3270 LPWSTR lpBinaryPathNameW = NULL;
3271 LPWSTR lpCanonicalImagePathW = NULL;
3272 LPWSTR lpLoadOrderGroupW = NULL;
3273 LPWSTR lpDependenciesW = NULL;
3274 // LPWSTR lpPasswordW = NULL;
3275
3276 DPRINT("RChangeServiceConfigA() called\n");
3277 DPRINT("dwServiceType = %lu\n", dwServiceType);
3278 DPRINT("dwStartType = %lu\n", dwStartType);
3279 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3280 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3281 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3282 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3283
3284 if (ScmShutdown)
3285 return ERROR_SHUTDOWN_IN_PROGRESS;
3286
3287 hSvc = ScmGetServiceFromHandle(hService);
3288 if (hSvc == NULL)
3289 {
3290 DPRINT1("Invalid service handle!\n");
3291 return ERROR_INVALID_HANDLE;
3292 }
3293
3294 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3295 SERVICE_CHANGE_CONFIG))
3296 {
3297 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3298 return ERROR_ACCESS_DENIED;
3299 }
3300
3301 lpService = hSvc->ServiceEntry;
3302 if (lpService == NULL)
3303 {
3304 DPRINT("lpService == NULL!\n");
3305 return ERROR_INVALID_HANDLE;
3306 }
3307
3308 /* Lock the service database exclusively */
3309 ScmLockDatabaseExclusive();
3310
3311 if (lpService->bDeleted)
3312 {
3313 DPRINT("The service has already been marked for delete!\n");
3314 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
3315 goto done;
3316 }
3317
3318 /* Open the service key */
3319 dwError = ScmOpenServiceKey(lpService->szServiceName,
3320 KEY_SET_VALUE,
3321 &hServiceKey);
3322 if (dwError != ERROR_SUCCESS)
3323 goto done;
3324
3325 /* Write service data to the registry */
3326
3327 if (lpDisplayName != NULL && *lpDisplayName != 0)
3328 {
3329 /* Set the display name */
3330 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3331 0,
3332 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3333 if (lpDisplayNameW == NULL)
3334 {
3335 dwError = ERROR_NOT_ENOUGH_MEMORY;
3336 goto done;
3337 }
3338
3339 MultiByteToWideChar(CP_ACP,
3340 0,
3341 lpDisplayName,
3342 -1,
3343 lpDisplayNameW,
3344 strlen(lpDisplayName) + 1);
3345
3346 RegSetValueExW(hServiceKey,
3347 L"DisplayName",
3348 0,
3349 REG_SZ,
3350 (LPBYTE)lpDisplayNameW,
3351 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
3352
3353 /* Update lpService->lpDisplayName */
3354 if (lpService->lpDisplayName)
3355 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3356
3357 lpService->lpDisplayName = lpDisplayNameW;
3358 }
3359
3360 if (dwServiceType != SERVICE_NO_CHANGE)
3361 {
3362 /* Set the service type */
3363 dwError = RegSetValueExW(hServiceKey,
3364 L"Type",
3365 0,
3366 REG_DWORD,
3367 (LPBYTE)&dwServiceType,
3368 sizeof(DWORD));
3369 if (dwError != ERROR_SUCCESS)
3370 goto done;
3371
3372 lpService->Status.dwServiceType = dwServiceType;
3373 }
3374
3375 if (dwStartType != SERVICE_NO_CHANGE)
3376 {
3377 /* Set the start value */
3378 dwError = RegSetValueExW(hServiceKey,
3379 L"Start",
3380 0,
3381 REG_DWORD,
3382 (LPBYTE)&dwStartType,
3383 sizeof(DWORD));
3384 if (dwError != ERROR_SUCCESS)
3385 goto done;
3386
3387 lpService->dwStartType = dwStartType;
3388 }
3389
3390 if (dwErrorControl != SERVICE_NO_CHANGE)
3391 {
3392 /* Set the error control value */
3393 dwError = RegSetValueExW(hServiceKey,
3394 L"ErrorControl",
3395 0,
3396 REG_DWORD,
3397 (LPBYTE)&dwErrorControl,
3398 sizeof(DWORD));
3399 if (dwError != ERROR_SUCCESS)
3400 goto done;
3401
3402 lpService->dwErrorControl = dwErrorControl;
3403 }
3404
3405 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3406 {
3407 /* Set the image path */
3408 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
3409 0,
3410 (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
3411 if (lpBinaryPathNameW == NULL)
3412 {
3413 dwError = ERROR_NOT_ENOUGH_MEMORY;
3414 goto done;
3415 }
3416
3417 MultiByteToWideChar(CP_ACP,
3418 0,
3419 lpBinaryPathName,
3420 -1,
3421 lpBinaryPathNameW,
3422 strlen(lpBinaryPathName) + 1);
3423
3424 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
3425 {
3426 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
3427 lpBinaryPathNameW,
3428 &lpCanonicalImagePathW);
3429
3430 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3431
3432 if (dwError != ERROR_SUCCESS)
3433 goto done;
3434
3435 lpBinaryPathNameW = lpCanonicalImagePathW;
3436 }
3437
3438 dwError = RegSetValueExW(hServiceKey,
3439 L"ImagePath",
3440 0,
3441 REG_EXPAND_SZ,
3442 (LPBYTE)lpBinaryPathNameW,
3443 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
3444
3445 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3446
3447 if (dwError != ERROR_SUCCESS)
3448 goto done;
3449 }
3450
3451 /* Set the group name */
3452 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3453 {
3454 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3455 0,
3456 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3457 if (lpLoadOrderGroupW == NULL)
3458 {
3459 dwError = ERROR_NOT_ENOUGH_MEMORY;
3460 goto done;
3461 }
3462
3463 MultiByteToWideChar(CP_ACP,
3464 0,
3465 lpLoadOrderGroup,
3466 -1,
3467 lpLoadOrderGroupW,
3468 strlen(lpLoadOrderGroup) + 1);
3469
3470 dwError = RegSetValueExW(hServiceKey,
3471 L"Group",
3472 0,
3473 REG_SZ,
3474 (LPBYTE)lpLoadOrderGroupW,
3475 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
3476 if (dwError != ERROR_SUCCESS)
3477 {
3478 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3479 goto done;
3480 }
3481
3482 dwError = ScmSetServiceGroup(lpService,
3483 lpLoadOrderGroupW);
3484
3485 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3486
3487 if (dwError != ERROR_SUCCESS)
3488 goto done;
3489 }
3490
3491 if (lpdwTagId != NULL)
3492 {
3493 dwError = ScmAssignNewTag(lpService);
3494 if (dwError != ERROR_SUCCESS)
3495 goto done;
3496
3497 dwError = RegSetValueExW(hServiceKey,
3498 L"Tag",
3499 0,
3500 REG_DWORD,
3501 (LPBYTE)&lpService->dwTag,
3502 sizeof(DWORD));
3503 if (dwError != ERROR_SUCCESS)
3504 goto done;
3505
3506 *lpdwTagId = lpService->dwTag;
3507 }
3508
3509 /* Write dependencies */
3510 if (lpDependencies != NULL && *lpDependencies != 0)
3511 {
3512 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3513 0,
3514 (strlen(lpDependencies) + 1) * sizeof(WCHAR));
3515 if (lpDependenciesW == NULL)
3516 {
3517 dwError = ERROR_NOT_ENOUGH_MEMORY;
3518 goto done;
3519 }
3520
3521 MultiByteToWideChar(CP_ACP,
3522 0,
3523 lpDependencies,
3524 dwDependSize,
3525 lpDependenciesW,
3526 strlen(lpDependencies) + 1);
3527
3528 dwError = ScmWriteDependencies(hServiceKey,
3529 (LPWSTR)lpDependenciesW,
3530 dwDependSize);
3531
3532 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3533 }
3534
3535 if (lpPassword != NULL)
3536 {
3537 /* FIXME: Write password */
3538 }
3539
3540 done:
3541 /* Unlock the service database */
3542 ScmUnlockDatabase();
3543
3544 if (hServiceKey != NULL)
3545 RegCloseKey(hServiceKey);
3546
3547 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3548
3549 return dwError;
3550 }
3551
3552
3553 /* Function 24 */
3554 DWORD RCreateServiceA(
3555 SC_RPC_HANDLE hSCManager,
3556 LPSTR lpServiceName,
3557 LPSTR lpDisplayName,
3558 DWORD dwDesiredAccess,
3559 DWORD dwServiceType,
3560 DWORD dwStartType,
3561 DWORD dwErrorControl,
3562 LPSTR lpBinaryPathName,
3563 LPSTR lpLoadOrderGroup,
3564 LPDWORD lpdwTagId,
3565 LPBYTE lpDependencies,
3566 DWORD dwDependSize,
3567 LPSTR lpServiceStartName,
3568 LPBYTE lpPassword,
3569 DWORD dwPwSize,
3570 LPSC_RPC_HANDLE lpServiceHandle)
3571 {
3572 DWORD dwError = ERROR_SUCCESS;
3573 LPWSTR lpServiceNameW = NULL;
3574 LPWSTR lpDisplayNameW = NULL;
3575 LPWSTR lpBinaryPathNameW = NULL;
3576 LPWSTR lpLoadOrderGroupW = NULL;
3577 LPWSTR lpDependenciesW = NULL;
3578 LPWSTR lpServiceStartNameW = NULL;
3579 DWORD dwDependenciesLength = 0;
3580 DWORD dwLength;
3581 int len;
3582 LPCSTR lpStr;
3583
3584 if (lpServiceName)
3585 {
3586 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3587 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3588 if (!lpServiceNameW)
3589 {
3590 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3591 goto cleanup;
3592 }
3593 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3594 }
3595
3596 if (lpDisplayName)
3597 {
3598 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3599 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3600 if (!lpDisplayNameW)
3601 {
3602 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3603 goto cleanup;
3604 }
3605 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3606 }
3607
3608 if (lpBinaryPathName)
3609 {
3610 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3611 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3612 if (!lpBinaryPathNameW)
3613 {
3614 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3615 goto cleanup;
3616 }
3617 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3618 }
3619
3620 if (lpLoadOrderGroup)
3621 {
3622 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3623 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3624 if (!lpLoadOrderGroupW)
3625 {
3626 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3627 goto cleanup;
3628 }
3629 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3630 }
3631
3632 if (lpDependencies)
3633 {
3634 lpStr = (LPCSTR)lpDependencies;
3635 while (*lpStr)
3636 {
3637 dwLength = strlen(lpStr) + 1;
3638 dwDependenciesLength += dwLength;
3639 lpStr = lpStr + dwLength;
3640 }
3641 dwDependenciesLength++;
3642
3643 lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR));
3644 if (!lpDependenciesW)
3645 {
3646 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3647 goto cleanup;
3648 }
3649 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3650 }
3651
3652 if (lpServiceStartName)
3653 {
3654 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3655 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3656 if (!lpServiceStartNameW)
3657 {
3658 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3659 goto cleanup;
3660 }
3661 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3662 }
3663
3664 dwError = RCreateServiceW(hSCManager,
3665 lpServiceNameW,
3666 lpDisplayNameW,
3667 dwDesiredAccess,
3668 dwServiceType,
3669 dwStartType,
3670 dwErrorControl,
3671 lpBinaryPathNameW,
3672 lpLoadOrderGroupW,
3673 lpdwTagId,
3674 (LPBYTE)lpDependenciesW,
3675 dwDependenciesLength,
3676 lpServiceStartNameW,
3677 lpPassword,
3678 dwPwSize,
3679 lpServiceHandle);
3680
3681 cleanup:
3682 if (lpServiceNameW !=NULL)
3683 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3684
3685 if (lpDisplayNameW != NULL)
3686 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3687
3688 if (lpBinaryPathNameW != NULL)
3689 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3690
3691 if (lpLoadOrderGroupW != NULL)
3692 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3693
3694 if (lpDependenciesW != NULL)
3695 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3696
3697 if (lpServiceStartNameW != NULL)
3698 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3699
3700 return dwError;
3701 }
3702
3703
3704 /* Function 25 */
3705 DWORD REnumDependentServicesA(
3706 SC_RPC_HANDLE hService,
3707 DWORD dwServiceState,
3708 LPBYTE lpServices,
3709 DWORD cbBufSize,
3710 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3711 LPBOUNDED_DWORD_256K lpServicesReturned)
3712 {
3713 DWORD dwError = ERROR_SUCCESS;
3714 DWORD dwServicesReturned = 0;
3715 DWORD dwServiceCount;
3716 HKEY hServicesKey = NULL;
3717 PSERVICE_HANDLE hSvc;
3718 PSERVICE lpService = NULL;
3719 PSERVICE *lpServicesArray = NULL;
3720 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3721 LPSTR lpStr;
3722
3723 *pcbBytesNeeded = 0;
3724 *lpServicesReturned = 0;
3725
3726 DPRINT("REnumDependentServicesA() called\n");
3727
3728 hSvc = ScmGetServiceFromHandle(hService);
3729 if (hSvc == NULL)
3730 {
3731 DPRINT1("Invalid service handle!\n");
3732 return ERROR_INVALID_HANDLE;
3733 }
3734
3735 lpService = hSvc->ServiceEntry;
3736
3737 /* Check access rights */
3738 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3739 SC_MANAGER_ENUMERATE_SERVICE))
3740 {
3741 DPRINT("Insufficient access rights! 0x%lx\n",
3742 hSvc->Handle.DesiredAccess);
3743 return ERROR_ACCESS_DENIED;
3744 }
3745
3746 /* Open the Services Reg key */
3747 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3748 L"System\\CurrentControlSet\\Services",
3749 0,
3750 KEY_READ,
3751 &hServicesKey);
3752
3753 if (dwError != ERROR_SUCCESS)
3754 return dwError;
3755
3756 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3757 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3758 are the same for both. Verified in WINXP. */
3759
3760 /* First determine the bytes needed and get the number of dependent services*/
3761 dwError = Int_EnumDependentServicesW(hServicesKey,
3762 lpService,
3763 dwServiceState,
3764 NULL,
3765 pcbBytesNeeded,
3766 &dwServicesReturned);
3767 if (dwError != ERROR_SUCCESS)
3768 goto Done;
3769
3770 /* If buffer size is less than the bytes needed or pointer is null*/
3771 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3772 {
3773 dwError = ERROR_MORE_DATA;
3774 goto Done;
3775 }
3776
3777 /* Allocate memory for array of service pointers */
3778 lpServicesArray = HeapAlloc(GetProcessHeap(),
3779 0,
3780 (dwServicesReturned + 1) * sizeof(PSERVICE));
3781 if (!lpServicesArray)
3782 {
3783 DPRINT("Could not allocate a buffer!!\n");
3784 dwError = ERROR_NOT_ENOUGH_MEMORY;
3785 goto Done;
3786 }
3787
3788 dwServicesReturned = 0;
3789 *pcbBytesNeeded = 0;
3790
3791 dwError = Int_EnumDependentServicesW(hServicesKey,
3792 lpService,
3793 dwServiceState,
3794 lpServicesArray,
3795 pcbBytesNeeded,
3796 &dwServicesReturned);
3797 if (dwError != ERROR_SUCCESS)
3798 {
3799 goto Done;
3800 }
3801
3802 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3803 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3804
3805 /* Copy EnumDepenedentService to Buffer */
3806 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3807 {
3808 lpService = lpServicesArray[dwServiceCount];
3809
3810 /* Copy the status info */
3811 memcpy(&lpServicesPtr->ServiceStatus,
3812 &lpService->Status,
3813 sizeof(SERVICE_STATUS));
3814
3815 /* Copy display name */
3816 WideCharToMultiByte(CP_ACP,
3817 0,
3818 lpService->lpDisplayName,
3819 -1,
3820 lpStr,
3821 wcslen(lpService->lpDisplayName),
3822 0,
3823 0);
3824 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3825 lpStr += strlen(lpStr) + 1;
3826
3827 /* Copy service name */
3828 WideCharToMultiByte(CP_ACP,
3829 0,
3830 lpService->lpServiceName,
3831 -1,
3832 lpStr,
3833 wcslen(lpService->lpServiceName),
3834 0,
3835 0);
3836 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3837 lpStr += strlen(lpStr) + 1;
3838
3839 lpServicesPtr ++;
3840 }
3841
3842 *lpServicesReturned = dwServicesReturned;
3843
3844 Done:
3845 if (lpServicesArray)
3846 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3847
3848 RegCloseKey(hServicesKey);
3849
3850 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3851
3852 return dwError;
3853 }
3854
3855
3856 /* Function 26 */
3857 DWORD REnumServicesStatusA(
3858 SC_RPC_HANDLE hSCManager,
3859 DWORD dwServiceType,
3860 DWORD dwServiceState,
3861 LPBYTE lpBuffer,
3862 DWORD dwBufSize,
3863 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3864 LPBOUNDED_DWORD_256K lpServicesReturned,
3865 LPBOUNDED_DWORD_256K lpResumeHandle)
3866 {
3867 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3868 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3869 LPWSTR lpStringPtrW;
3870 LPSTR lpStringPtrA;
3871 DWORD dwError;
3872 DWORD dwServiceCount;
3873
3874 DPRINT("REnumServicesStatusA() called\n");
3875
3876 if ((dwBufSize > 0) && (lpBuffer))
3877 {
3878 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3879 if (!lpStatusPtrW)
3880 {
3881 DPRINT("Failed to allocate buffer!\n");
3882 return ERROR_NOT_ENOUGH_MEMORY;
3883 }
3884 }
3885
3886 dwError = REnumServicesStatusW(hSCManager,
3887 dwServiceType,
3888 dwServiceState,
3889 (LPBYTE)lpStatusPtrW,
3890 dwBufSize,
3891 pcbBytesNeeded,
3892 lpServicesReturned,
3893 lpResumeHandle);
3894
3895 /* if no services were returned then we are Done */
3896 if (*lpServicesReturned == 0)
3897 goto Done;
3898
3899 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3900 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3901 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3902 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3903 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3904
3905 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3906 {
3907 /* Copy the service name */
3908 WideCharToMultiByte(CP_ACP,
3909 0,
3910 lpStringPtrW,
3911 -1,
3912 lpStringPtrA,
3913 wcslen(lpStringPtrW),
3914 0,
3915 0);
3916
3917 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3918 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3919 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3920
3921 /* Copy the display name */
3922 WideCharToMultiByte(CP_ACP,
3923 0,
3924 lpStringPtrW,
3925 -1,
3926 lpStringPtrA,
3927 wcslen(lpStringPtrW),
3928 0,
3929 0);
3930
3931 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3932 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3933 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3934
3935 /* Copy the status information */
3936 memcpy(&lpStatusPtrA->ServiceStatus,
3937 &lpStatusPtrW->ServiceStatus,
3938 sizeof(SERVICE_STATUS));
3939
3940 lpStatusPtrA++;
3941 }
3942
3943 Done:;
3944 if (lpStatusPtrW)
3945 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3946
3947 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3948
3949 return dwError;
3950 }
3951
3952
3953 /* Function 27 */
3954 DWORD ROpenSCManagerA(
3955 LPSTR lpMachineName,
3956 LPSTR lpDatabaseName,
3957 DWORD dwDesiredAccess,
3958 LPSC_RPC_HANDLE lpScHandle)
3959 {
3960 UNICODE_STRING MachineName;
3961 UNICODE_STRING DatabaseName;
3962 DWORD dwError;
3963
3964 DPRINT("ROpenSCManagerA() called\n");
3965
3966 if (lpMachineName)
3967 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3968 lpMachineName);
3969
3970 if (lpDatabaseName)
3971 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3972 lpDatabaseName);
3973
3974 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
3975 lpDatabaseName ? DatabaseName.Buffer : NULL,
3976 dwDesiredAccess,
3977 lpScHandle);
3978
3979 if (lpMachineName)
3980 RtlFreeUnicodeString(&MachineName);
3981
3982 if (lpDatabaseName)
3983 RtlFreeUnicodeString(&DatabaseName);
3984
3985 return dwError;
3986 }
3987
3988
3989 /* Function 28 */
3990 DWORD ROpenServiceA(
3991 SC_RPC_HANDLE hSCManager,
3992 LPSTR lpServiceName,
3993 DWORD dwDesiredAccess,
3994 LPSC_RPC_HANDLE lpServiceHandle)
3995 {
3996 UNICODE_STRING ServiceName;
3997 DWORD dwError;
3998
3999 DPRINT("ROpenServiceA() called\n");
4000
4001 if (lpServiceName)
4002 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
4003 lpServiceName);
4004
4005 dwError = ROpenServiceW(hSCManager,
4006 lpServiceName ? ServiceName.Buffer : NULL,
4007 dwDesiredAccess,
4008 lpServiceHandle);
4009
4010 if (lpServiceName)
4011 RtlFreeUnicodeString(&ServiceName);
4012
4013 return dwError;
4014 }
4015
4016
4017 /* Function 29 */
4018 DWORD RQueryServiceConfigA(
4019 SC_RPC_HANDLE hService,
4020 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4021 DWORD cbBufSize,
4022 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4023 {
4024 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
4025 DWORD dwError = ERROR_SUCCESS;
4026 PSERVICE_HANDLE hSvc;
4027 PSERVICE lpService = NULL;
4028 HKEY hServiceKey = NULL;
4029 LPWSTR lpImagePath = NULL;
4030 LPWSTR lpServiceStartName = NULL;
4031 LPWSTR lpDependencies = NULL;
4032 DWORD dwDependenciesLength = 0;
4033 DWORD dwRequiredSize;
4034 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
4035 CHAR lpEmptyString[]={0,0};
4036 LPSTR lpStr;
4037
4038 DPRINT("RQueryServiceConfigA() called\n");
4039
4040 if (ScmShutdown)
4041 return ERROR_SHUTDOWN_IN_PROGRESS;
4042
4043 hSvc = ScmGetServiceFromHandle(hService);
4044 if (hSvc == NULL)
4045 {
4046 DPRINT1("Invalid service handle!\n");
4047 return ERROR_INVALID_HANDLE;
4048 }
4049
4050 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4051 SERVICE_QUERY_CONFIG))
4052 {
4053 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4054 return ERROR_ACCESS_DENIED;
4055 }
4056
4057 lpService = hSvc->ServiceEntry;
4058 if (lpService == NULL)
4059 {
4060 DPRINT("lpService == NULL!\n");
4061 return ERROR_INVALID_HANDLE;
4062 }
4063
4064 /* Lock the service database shared */
4065 ScmLockDatabaseShared();
4066
4067 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4068 KEY_READ,
4069 &hServiceKey);
4070 if (dwError != ERROR_SUCCESS)
4071 goto Done;
4072
4073 /* Read the image path */
4074 dwError = ScmReadString(hServiceKey,
4075 L"ImagePath",
4076 &lpImagePath);
4077 if (dwError != ERROR_SUCCESS)
4078 goto Done;
4079
4080 /* Read the service start name */
4081 ScmReadString(hServiceKey,
4082 L"ObjectName",
4083 &lpServiceStartName);
4084
4085 /* Read the dependencies */
4086 ScmReadDependencies(hServiceKey,
4087 &lpDependencies,
4088 &dwDependenciesLength);
4089
4090 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
4091
4092 if (lpImagePath != NULL)
4093 dwRequiredSize += wcslen(lpImagePath) + 1;
4094 else
4095 dwRequiredSize += 2;
4096
4097 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
4098 dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
4099 else
4100 dwRequiredSize += 2;
4101
4102 /* Add Dependencies length */
4103 if (lpDependencies != NULL)
4104 dwRequiredSize += dwDependenciesLength;
4105 else
4106 dwRequiredSize += 2;
4107
4108 if (lpServiceStartName != NULL)
4109 dwRequiredSize += wcslen(lpServiceStartName) + 1;
4110 else
4111 dwRequiredSize += 2;
4112
4113 if (lpService->lpDisplayName != NULL)
4114 dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
4115 else
4116 dwRequiredSize += 2;
4117
4118 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
4119 {
4120 dwError = ERROR_INSUFFICIENT_BUFFER;
4121 }
4122 else
4123 {
4124 lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
4125 lpConfig->dwServiceType = lpService->Status.dwServiceType;
4126 lpConfig->dwStartType = lpService->dwStartType;
4127 lpConfig->dwErrorControl = lpService->dwErrorControl;
4128 lpConfig->dwTagId = lpService->dwTag;
4129
4130 lpStr = (LPSTR)(lpServiceConfig + 1);
4131
4132 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4133 Verified in WINXP*/
4134
4135 if (lpImagePath)
4136 {
4137 WideCharToMultiByte(CP_ACP,
4138 0,
4139 lpImagePath,
4140 -1,
4141 lpStr,
4142 wcslen(lpImagePath) + 1,
4143 0,
4144 0);
4145 }
4146 else
4147 {
4148 strcpy(lpStr, lpEmptyString);
4149 }
4150
4151 lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4152 lpStr += (strlen((LPSTR)lpStr) + 1);
4153
4154 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4155 {
4156 WideCharToMultiByte(CP_ACP,
4157 0,
4158 lpService->lpGroup->lpGroupName,
4159 -1,
4160 lpStr,
4161 wcslen(lpService->lpGroup->lpGroupName) + 1,
4162 0,
4163 0);
4164 }
4165 else
4166 {
4167 strcpy(lpStr, lpEmptyString);
4168 }
4169
4170 lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4171 lpStr += (strlen(lpStr) + 1);
4172
4173 /* Append Dependencies */
4174 if (lpDependencies)
4175 {
4176 WideCharToMultiByte(CP_ACP,
4177 0,
4178 lpDependencies,
4179 dwDependenciesLength,
4180 lpStr,
4181 dwDependenciesLength,
4182 0,
4183 0);
4184 }
4185 else
4186 {
4187 strcpy(lpStr, lpEmptyString);
4188 }
4189
4190 lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4191 if (lpDependencies)
4192 lpStr += dwDependenciesLength;
4193 else
4194 lpStr += (strlen(lpStr) + 1);
4195
4196 if (lpServiceStartName)
4197 {
4198 WideCharToMultiByte(CP_ACP,
4199 0,
4200 lpServiceStartName,
4201 -1,
4202 lpStr,
4203 wcslen(lpServiceStartName) + 1,
4204 0,
4205 0);
4206 }
4207 else
4208 {
4209 strcpy(lpStr, lpEmptyString);
4210 }
4211
4212 lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4213 lpStr += (strlen(lpStr) + 1);
4214
4215 if (lpService->lpDisplayName)
4216 {
4217 WideCharToMultiByte(CP_ACP,
4218 0,
4219 lpService->lpDisplayName,
4220 -1,
4221 lpStr,
4222 wcslen(lpService->lpDisplayName) + 1,
4223 0,
4224 0);
4225 }
4226 else
4227 {
4228 strcpy(lpStr, lpEmptyString);
4229 }
4230
4231 lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4232 }
4233
4234 if (pcbBytesNeeded != NULL)
4235 *pcbBytesNeeded = dwRequiredSize;
4236
4237 Done:;
4238 /* Unlock the service database */
4239 ScmUnlockDatabase();
4240
4241 if (lpImagePath != NULL)
4242 HeapFree(GetProcessHeap(), 0, lpImagePath);
4243
4244 if (lpServiceStartName != NULL)
4245 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4246
4247 if (lpDependencies != NULL)
4248 HeapFree(GetProcessHeap(), 0, lpDependencies);
4249
4250 if (hServiceKey != NULL)
4251 RegCloseKey(hServiceKey);
4252
4253 DPRINT("RQueryServiceConfigA() done\n");
4254
4255 return dwError;
4256 }
4257
4258
4259 /* Function 30 */
4260 DWORD RQueryServiceLockStatusA(
4261 SC_RPC_HANDLE hSCManager,
4262 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4263 DWORD cbBufSize,
4264 LPBOUNDED_DWORD_4K pcbBytesNeeded)
4265 {
4266 UNIMPLEMENTED;
4267 return ERROR_CALL_NOT_IMPLEMENTED;
4268 }
4269
4270
4271 /* Function 31 */
4272 DWORD RStartServiceA(
4273 SC_RPC_HANDLE hService,
4274 DWORD argc,
4275 LPSTRING_PTRSA argv)
4276 {
4277 DWORD dwError = ERROR_SUCCESS;
4278 PSERVICE_HANDLE hSvc;
4279 PSERVICE lpService = NULL;
4280 LPWSTR *lpVector = NULL;
4281 DWORD i;
4282 DWORD dwLength;
4283
4284 DPRINT("RStartServiceA() called\n");
4285
4286 if (ScmShutdown)
4287 return ERROR_SHUTDOWN_IN_PROGRESS;
4288
4289 hSvc = ScmGetServiceFromHandle(hService);
4290 if (hSvc == NULL)
4291 {
4292 DPRINT1("Invalid service handle!\n");
4293 return ERROR_INVALID_HANDLE;
4294 }
4295
4296 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4297 SERVICE_START))
4298 {
4299 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4300 return ERROR_ACCESS_DENIED;
4301 }
4302
4303 lpService = hSvc->ServiceEntry;
4304 if (lpService == NULL)
4305 {
4306 DPRINT("lpService == NULL!\n");
4307 return ERROR_INVALID_HANDLE;
4308 }
4309
4310 if (lpService->dwStartType == SERVICE_DISABLED)
4311 return ERROR_SERVICE_DISABLED;
4312
4313 if (lpService->bDeleted)
4314 return ERROR_SERVICE_MARKED_FOR_DELETE;
4315
4316 /* Build a Unicode argument vector */
4317 if (argc > 0)
4318 {
4319 lpVector = HeapAlloc(GetProcessHeap(),
4320 HEAP_ZERO_MEMORY,
4321 argc * sizeof(LPWSTR));
4322 if (lpVector == NULL)
4323 return ERROR_NOT_ENOUGH_MEMORY;
4324
4325 for (i = 0; i < argc; i++)
4326 {
4327 dwLength = MultiByteToWideChar(CP_ACP,
4328 0,
4329 ((LPSTR*)argv)[i],
4330 -1,
4331 NULL,
4332 0);
4333
4334 lpVector[i] = HeapAlloc(GetProcessHeap(),
4335 HEAP_ZERO_MEMORY,
4336 dwLength * sizeof(WCHAR));
4337 if (lpVector[i] == NULL)
4338 {
4339 dwError = ERROR_NOT_ENOUGH_MEMORY;
4340 goto done;
4341 }
4342
4343 MultiByteToWideChar(CP_ACP,
4344 0,
4345 ((LPSTR*)argv)[i],
4346 -1,
4347 lpVector[i],
4348 dwLength);
4349 }
4350 }
4351
4352 /* Start the service */
4353 dwError = ScmStartService(lpService, argc, lpVector);
4354
4355 done:
4356 /* Free the Unicode argument vector */
4357 if (lpVector != NULL)
4358 {
4359 for (i = 0; i < argc; i++)
4360 {
4361 if (lpVector[i] != NULL)
4362 HeapFree(GetProcessHeap(), 0, lpVector[i]);
4363 }
4364 HeapFree(GetProcessHeap(), 0, lpVector);
4365 }
4366
4367 return dwError;
4368 }
4369
4370
4371 /* Function 32 */
4372 DWORD RGetServiceDisplayNameA(
4373 SC_RPC_HANDLE hSCManager,
4374 LPCSTR lpServiceName,
4375 LPSTR lpDisplayName,
4376 LPBOUNDED_DWORD_4K lpcchBuffer)
4377 {
4378 // PMANAGER_HANDLE hManager;
4379 PSERVICE lpService = NULL;
4380 DWORD dwLength;
4381 DWORD dwError;
4382 LPWSTR lpServiceNameW;
4383
4384 DPRINT("RGetServiceDisplayNameA() called\n");
4385 DPRINT("hSCManager = %p\n", hSCManager);
4386 DPRINT("lpServiceName: %s\n", lpServiceName);
4387 DPRINT("lpDisplayName: %p\n", lpDisplayName);
4388 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4389
4390 // hManager = (PMANAGER_HANDLE)hSCManager;
4391 // if (hManager->Handle.Tag != MANAGER_TAG)
4392 // {
4393 // DPRINT("Invalid manager handle!\n");
4394 // return ERROR_INVALID_HANDLE;
4395 // }
4396
4397 if (lpServiceName != NULL)
4398 {
4399 dwLength = strlen(lpServiceName) + 1;
4400 lpServiceNameW = HeapAlloc(GetProcessHeap(),
4401 HEAP_ZERO_MEMORY,
4402 dwLength * sizeof(WCHAR));
4403 if (!lpServiceNameW)
4404 return ERROR_NOT_ENOUGH_MEMORY;
4405
4406 MultiByteToWideChar(CP_ACP,
4407 0,
4408 lpServiceName,
4409 -1,
4410 lpServiceNameW,
4411 dwLength);
4412
4413 lpService = ScmGetServiceEntryByName(lpServiceNameW);
4414
4415 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4416 }
4417
4418 if (lpService == NULL)
4419 {
4420 DPRINT("Could not find a service!\n");
4421
4422 /* If the service could not be found and lpcchBuffer is 0, windows
4423 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4424 if (*lpcchBuffer == 0)
4425 {
4426 *lpcchBuffer = 1;
4427 if (lpDisplayName != NULL)
4428 {
4429 *lpDisplayName = '\0';
4430 }
4431 }
4432 return ERROR_SERVICE_DOES_NOT_EXIST;
4433 }
4434
4435 if (!lpService->lpDisplayName)
4436 {
4437 dwLength = wcslen(lpService->lpServiceName);
4438 if (lpDisplayName != NULL &&
4439 *lpcchBuffer > dwLength)
4440 {
4441 WideCharToMultiByte(CP_ACP,
4442 0,
4443 lpService->lpServiceName,
4444 wcslen(lpService->lpServiceName),
4445 lpDisplayName,
4446 dwLength + 1,
4447 NULL,
4448 NULL);
4449 return ERROR_SUCCESS;
4450 }
4451 }
4452 else
4453 {
4454 dwLength = wcslen(lpService->lpDisplayName);
4455 if (lpDisplayName != NULL &&
4456 *lpcchBuffer > dwLength)
4457 {
4458 WideCharToMultiByte(CP_ACP,
4459 0,
4460 lpService->lpDisplayName,
4461 wcslen(lpService->lpDisplayName),
4462 lpDisplayName,
4463 dwLength + 1,
4464 NULL,
4465 NULL);
4466 return ERROR_SUCCESS;
4467 }
4468 }
4469
4470 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4471
4472 *lpcchBuffer = dwLength * 2;
4473
4474 return dwError;
4475 }
4476
4477
4478 /* Function 33 */
4479 DWORD RGetServiceKeyNameA(
4480 SC_RPC_HANDLE hSCManager,
4481 LPCSTR lpDisplayName,
4482 LPSTR lpServiceName,
4483 LPBOUNDED_DWORD_4K lpcchBuffer)
4484 {
4485 PSERVICE lpService;
4486 DWORD dwLength;
4487 DWORD dwError;
4488 LPWSTR lpDisplayNameW;
4489
4490 DPRINT("RGetServiceKeyNameA() called\n");
4491 DPRINT("hSCManager = %p\n", hSCManager);
4492 DPRINT("lpDisplayName: %s\n", lpDisplayName);
4493 DPRINT("lpServiceName: %p\n", lpServiceName);
4494 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4495
4496 dwLength = strlen(lpDisplayName) + 1;
4497 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4498 HEAP_ZERO_MEMORY,
4499 dwLength * sizeof(WCHAR));
4500 if (!lpDisplayNameW)
4501 return ERROR_NOT_ENOUGH_MEMORY;
4502
4503 MultiByteToWideChar(CP_ACP,
4504 0,
4505 lpDisplayName,
4506 -1,
4507 lpDisplayNameW,
4508 dwLength);
4509
4510 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4511
4512 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4513
4514 if (lpService == NULL)
4515 {
4516 DPRINT("Could not find the service!\n");
4517
4518 /* If the service could not be found and lpcchBuffer is 0,
4519 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4520 if (*lpcchBuffer == 0)
4521 {
4522 *lpcchBuffer = 1;
4523 if (lpServiceName != NULL)
4524 {
4525 *lpServiceName = '\0';
4526 }
4527 }
4528
4529 return ERROR_SERVICE_DOES_NOT_EXIST;
4530 }
4531
4532 dwLength = wcslen(lpService->lpServiceName);
4533 if (lpServiceName != NULL &&
4534 *lpcchBuffer > dwLength)
4535 {
4536 WideCharToMultiByte(CP_ACP,
4537 0,
4538 lpService->lpServiceName,
4539 wcslen(lpService->lpServiceName),
4540 lpServiceName,
4541 dwLength + 1,
4542 NULL,
4543 NULL);
4544 return ERROR_SUCCESS;
4545 }
4546
4547 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4548
4549 *lpcchBuffer = dwLength * 2;
4550
4551 return dwError;
4552 }
4553
4554
4555 /* Function 34 */
4556 DWORD RI_ScGetCurrentGroupStateW(
4557 SC_RPC_HANDLE hSCManager,
4558 LPWSTR lpLoadOrderGroup,
4559 LPDWORD lpState)
4560 {
4561 UNIMPLEMENTED;
4562 return ERROR_CALL_NOT_IMPLEMENTED;
4563 }
4564
4565
4566 /* Function 35 */
4567 DWORD REnumServiceGroupW(
4568 SC_RPC_HANDLE hSCManager,
4569 DWORD dwServiceType,
4570 DWORD dwServiceState,
4571 LPBYTE lpBuffer,
4572 DWORD cbBufSize,
4573 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4574 LPBOUNDED_DWORD_256K lpServicesReturned,
4575 LPBOUNDED_DWORD_256K lpResumeIndex,
4576 LPCWSTR pszGroupName)
4577 {
4578 UNIMPLEMENTED;
4579 return ERROR_CALL_NOT_IMPLEMENTED;
4580 }
4581
4582
4583 //
4584 // WARNING: This function is untested
4585 //
4586 /* Function 36 */
4587 DWORD RChangeServiceConfig2A(
4588 SC_RPC_HANDLE hService,
4589 SC_RPC_CONFIG_INFOA Info)
4590 {
4591 SC_RPC_CONFIG_INFOW InfoW;
4592 DWORD dwRet, dwLength;
4593 PVOID ptr = NULL;
4594
4595 DPRINT("RChangeServiceConfig2A() called\n");
4596 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4597
4598 InfoW.dwInfoLevel = Info.dwInfoLevel;
4599
4600 if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4601 {
4602 LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
4603 //LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
4604
4605 //lpServiceDescriptonA = Info.psd;
4606
4607 ///if (lpServiceDescriptonA &&
4608 ///lpServiceDescriptonA->lpDescription)
4609 ///{
4610 dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR);
4611
4612 lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
4613 0,
4614 dwLength + sizeof(SERVICE_DESCRIPTIONW));
4615 if (!lpServiceDescriptonW)
4616 {
4617 return ERROR_NOT_ENOUGH_MEMORY;
4618 }
4619
4620 lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
4621
4622 MultiByteToWideChar(CP_ACP,
4623 0,
4624 Info.lpDescription,
4625 -1,
4626 lpServiceDescriptonW->lpDescription,
4627 dwLength);
4628
4629 ptr = lpServiceDescriptonW;
4630 InfoW.psd = lpServiceDescriptonW;
4631 ///}
4632 }
4633 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4634 {
4635 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
4636 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
4637 DWORD dwRebootLen = 0;
4638 DWORD dwCommandLen = 0;
4639
4640 lpServiceFailureActionsA = Info.psfa;
4641
4642 if (lpServiceFailureActionsA)
4643 {
4644 if (lpServiceFailureActionsA->lpRebootMsg)
4645 {
4646 dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
4647 }
4648 if (lpServiceFailureActionsA->lpCommand)
4649 {
4650 dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
4651 }
4652 dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
4653
4654 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
4655 0,
4656 dwLength);
4657 if (!lpServiceFailureActionsW)
4658 {
4659 return ERROR_NOT_ENOUGH_MEMORY;
4660 }
4661
4662 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
4663 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
4664 CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
4665
4666 if (lpServiceFailureActionsA->lpRebootMsg)
4667 {
4668 MultiByteToWideChar(CP_ACP,
4669 0,
4670 lpServiceFailureActionsA->lpRebootMsg,
4671 -1,
4672 lpServiceFailureActionsW->lpRebootMsg,
4673 dwRebootLen);
4674 }
4675
4676 if (lpServiceFailureActionsA->lpCommand)
4677 {
4678 MultiByteToWideChar(CP_ACP,
4679 0,
4680 lpServiceFailureActionsA->lpCommand,
4681 -1,
4682 lpServiceFailureActionsW->lpCommand,
4683 dwCommandLen);
4684 }
4685
4686 ptr = lpServiceFailureActionsW;
4687 }
4688 }
4689
4690 dwRet = RChangeServiceConfig2W(hService, InfoW);
4691
4692 HeapFree(GetProcessHeap(), 0, ptr);
4693
4694 return dwRet;
4695 }
4696
4697
4698 /* Function 37 */
4699 DWORD RChangeServiceConfig2W(
4700 SC_RPC_HANDLE hService,
4701 SC_RPC_CONFIG_INFOW Info)
4702 {
4703 DWORD dwError = ERROR_SUCCESS;
4704 PSERVICE_HANDLE hSvc;
4705 PSERVICE lpService = NULL;
4706 HKEY hServiceKey = NULL;
4707
4708 DPRINT("RChangeServiceConfig2W() called\n");
4709 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4710
4711 if (ScmShutdown)
4712 return ERROR_SHUTDOWN_IN_PROGRESS;
4713
4714 hSvc = ScmGetServiceFromHandle(hService);
4715 if (hSvc == NULL)
4716 {
4717 DPRINT1("Invalid service handle!\n");
4718 return ERROR_INVALID_HANDLE;
4719 }
4720
4721 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4722 SERVICE_CHANGE_CONFIG))
4723 {
4724 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4725 return ERROR_ACCESS_DENIED;
4726 }
4727
4728 lpService = hSvc->ServiceEntry;
4729 if (lpService == NULL)
4730 {
4731 DPRINT("lpService == NULL!\n");
4732 return ERROR_INVALID_HANDLE;
4733 }
4734
4735 /* Lock the service database exclusively */
4736 ScmLockDatabaseExclusive();
4737
4738 if (lpService->bDeleted)
4739 {
4740 DPRINT("The service has already been marked for delete!\n");
4741 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
4742 goto done;
4743 }
4744
4745 /* Open the service key */
4746 dwError = ScmOpenServiceKey(lpService->szServiceName,
4747 KEY_SET_VALUE,
4748 &hServiceKey);
4749 if (dwError != ERROR_SUCCESS)
4750 goto done;
4751
4752 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4753 {
4754 LPSERVICE_DESCRIPTIONW lpServiceDescription;
4755
4756 lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
4757 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpServiceDescription + sizeof(LPSERVICE_DESCRIPTIONW));
4758
4759 if (lpServiceDescription != NULL &&
4760 lpServiceDescription->lpDescription != NULL)
4761 {
4762 DPRINT("Setting value %S\n", lpServiceDescription->lpDescription);
4763 dwError = RegSetValueExW(hServiceKey,
4764 L"Description",
4765 0,
4766 REG_SZ,
4767 (LPBYTE)lpServiceDescription->lpDescription,
4768 (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
4769 if (dwError != ERROR_SUCCESS)
4770 goto done;
4771 }
4772 }
4773 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4774 {
4775 UNIMPLEMENTED;
4776 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4777 goto done;
4778 }
4779
4780 done:
4781 /* Unlock the service database */
4782 ScmUnlockDatabase();
4783
4784 if (hServiceKey != NULL)
4785 RegCloseKey(hServiceKey);
4786
4787 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
4788
4789 return dwError;
4790 }
4791
4792
4793 /* Function 38 */
4794 DWORD RQueryServiceConfig2A(
4795 SC_RPC_HANDLE hService,
4796 DWORD dwInfoLevel,
4797 LPBYTE lpBuffer,
4798 DWORD cbBufSize,
4799 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4800 {
4801 DWORD dwError = ERROR_SUCCESS;
4802 PSERVICE_HANDLE hSvc;
4803 PSERVICE lpService = NULL;
4804 HKEY hServiceKey = NULL;
4805 LPWSTR lpDescriptionW = NULL;
4806
4807 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
4808 hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
4809
4810 if (!lpBuffer)
4811 return ERROR_INVALID_ADDRESS;
4812
4813 if (ScmShutdown)
4814 return ERROR_SHUTDOWN_IN_PROGRESS;
4815
4816 hSvc = ScmGetServiceFromHandle(hService);
4817 if (hSvc == NULL)
4818 {
4819 DPRINT1("Invalid service handle!\n");
4820 return ERROR_INVALID_HANDLE;
4821 }
4822
4823 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4824 SERVICE_QUERY_CONFIG))
4825 {
4826 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4827 return ERROR_ACCESS_DENIED;
4828 }
4829
4830 lpService = hSvc->ServiceEntry;
4831 if (lpService == NULL)
4832 {
4833 DPRINT("lpService == NULL!\n");
4834 return ERROR_INVALID_HANDLE;
4835 }
4836
4837 /* Lock the service database shared */
4838 ScmLockDatabaseShared();
4839
4840 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4841 KEY_READ,
4842 &hServiceKey);
4843 if (dwError != ERROR_SUCCESS)
4844 goto done;
4845
4846 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4847 {
4848 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
4849 LPSTR lpStr;
4850
4851 dwError = ScmReadString(hServiceKey,
4852 L"Description",
4853 &lpDescriptionW);
4854 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
4855 goto done;
4856
4857 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
4858 if (dwError == ERROR_SUCCESS)
4859 *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
4860
4861 if (cbBufSize < *pcbBytesNeeded)
4862 {
4863 dwError = ERROR_INSUFFICIENT_BUFFER;
4864 goto done;
4865 }
4866
4867 if (dwError == ERROR_SUCCESS)
4868 {
4869 lpStr = (LPSTR)(lpServiceDescription + 1);
4870
4871 WideCharToMultiByte(CP_ACP,
4872 0,
4873 lpDescriptionW,
4874 -1,
4875 lpStr,
4876 wcslen(lpDescriptionW),
4877 NULL,
4878 NULL);
4879 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4880 }
4881 else
4882 {
4883 lpServiceDescription->lpDescription = NULL;
4884 dwError = ERROR_SUCCESS;
4885 goto done;
4886 }
4887 }
4888 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4889 {
4890 UNIMPLEMENTED;
4891 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4892 goto done;
4893 }
4894
4895 done:
4896 /* Unlock the service database */
4897 ScmUnlockDatabase();
4898
4899 if (lpDescriptionW != NULL)
4900 HeapFree(GetProcessHeap(), 0, lpDescriptionW);
4901
4902 if (hServiceKey != NULL)
4903 RegCloseKey(hServiceKey);
4904
4905 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4906
4907 return dwError;
4908 }
4909
4910
4911 /* Function 39 */
4912 DWORD RQueryServiceConfig2W(
4913 SC_RPC_HANDLE hService,
4914 DWORD dwInfoLevel,
4915 LPBYTE lpBuffer,
4916 DWORD cbBufSize,
4917 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4918 {
4919 DWORD dwError = ERROR_SUCCESS;
4920 PSERVICE_HANDLE hSvc;
4921 PSERVICE lpService = NULL;
4922 HKEY hServiceKey = NULL;
4923 DWORD dwRequiredSize;
4924 LPWSTR lpDescription = NULL;
4925 LPWSTR lpFailureCommand = NULL;
4926 LPWSTR lpRebootMessage = NULL;
4927
4928 DPRINT("RQueryServiceConfig2W() called\n");
4929
4930 if (!lpBuffer)
4931 return ERROR_INVALID_ADDRESS;
4932
4933 if (ScmShutdown)
4934 return ERROR_SHUTDOWN_IN_PROGRESS;
4935
4936 hSvc = ScmGetServiceFromHandle(hService);
4937 if (hSvc == NULL)
4938 {
4939 DPRINT1("Invalid service handle!\n");
4940 return ERROR_INVALID_HANDLE;
4941 }
4942
4943 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4944 SERVICE_QUERY_CONFIG))
4945 {
4946 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4947 return ERROR_ACCESS_DENIED;
4948 }
4949
4950 lpService = hSvc->ServiceEntry;
4951 if (lpService == NULL)
4952 {
4953 DPRINT("lpService == NULL!\n");
4954 return ERROR_INVALID_HANDLE;
4955 }
4956
4957 /* Lock the service database shared */
4958 ScmLockDatabaseShared();
4959
4960 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4961 KEY_READ,
4962 &hServiceKey);
4963 if (dwError != ERROR_SUCCESS)
4964 goto done;
4965
4966 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4967 {
4968 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
4969 LPWSTR lpStr;
4970
4971 dwError = ScmReadString(hServiceKey,
4972 L"Description",
4973 &lpDescription);
4974 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
4975 goto done;
4976
4977 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW);
4978 if (dwError == ERROR_SUCCESS)
4979 *pcbBytesNeeded += ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
4980
4981 if (cbBufSize < *pcbBytesNeeded)
4982 {
4983 dwError = ERROR_INSUFFICIENT_BUFFER;
4984 goto done;
4985 }
4986
4987 if (dwError == ERROR_SUCCESS)
4988 {
4989 lpStr = (LPWSTR)(lpServiceDescription + 1);
4990 wcscpy(lpStr, lpDescription);
4991 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4992 }
4993 else
4994 {
4995 lpServiceDescription->lpDescription = NULL;
4996 dwError = ERROR_SUCCESS;
4997 }
4998 }
4999 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5000 {
5001 LPWSTR lpStr;
5002 LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
5003
5004 UNIMPLEMENTED;
5005
5006 dwError = ScmReadString(hServiceKey,
5007 L"FailureCommand",
5008 &lpFailureCommand);
5009
5010 dwError = ScmReadString(hServiceKey,
5011 L"RebootMessage",
5012 &lpRebootMessage);
5013
5014 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5015
5016 if (lpFailureCommand)
5017 dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR);
5018
5019 if (lpRebootMessage)
5020 dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR);
5021
5022 if (cbBufSize < dwRequiredSize)
5023 {
5024 *pcbBytesNeeded = dwRequiredSize;
5025 dwError = ERROR_INSUFFICIENT_BUFFER;
5026 goto done;
5027 }
5028
5029 lpFailureActions->cActions = 0;
5030 lpFailureActions->dwResetPeriod = 0;
5031 lpFailureActions->lpCommand = NULL;
5032 lpFailureActions->lpRebootMsg = NULL;
5033 lpFailureActions->lpsaActions = NULL;
5034
5035 lpStr = (LPWSTR)(lpFailureActions + 1);
5036 if (lpRebootMessage)
5037 {
5038 wcscpy(lpStr, lpRebootMessage);
5039 lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage);
5040 lpStr += wcslen(lpRebootMessage) + 1;
5041 }
5042
5043 if (lpFailureCommand)
5044 {
5045 wcscpy(lpStr, lpFailureCommand);
5046 lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand);
5047 lpStr += wcslen(lpRebootMessage) + 1;
5048 }
5049 dwError = STATUS_SUCCESS;
5050 goto done;
5051 }
5052
5053 done:
5054 /* Unlock the service database */
5055 ScmUnlockDatabase();
5056
5057 if (lpDescription != NULL)
5058 HeapFree(GetProcessHeap(), 0, lpDescription);
5059
5060 if (lpRebootMessage != NULL)
5061 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
5062
5063 if (lpFailureCommand != NULL)
5064 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
5065
5066 if (hServiceKey != NULL)
5067 RegCloseKey(hServiceKey);
5068
5069 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
5070
5071 return dwError;
5072 }
5073
5074
5075 /* Function 40 */
5076 DWORD RQueryServiceStatusEx(
5077 SC_RPC_HANDLE hService,
5078 SC_STATUS_TYPE InfoLevel,
5079 LPBYTE lpBuffer,
5080 DWORD cbBufSize,
5081 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5082 {
5083 LPSERVICE_STATUS_PROCESS lpStatus;
5084 PSERVICE_HANDLE hSvc;
5085 PSERVICE lpService;
5086
5087 DPRINT("RQueryServiceStatusEx() called\n");
5088
5089 if (ScmShutdown)
5090 return ERROR_SHUTDOWN_IN_PROGRESS;
5091
5092 if (InfoLevel != SC_STATUS_PROCESS_INFO)
5093 return ERROR_INVALID_LEVEL;
5094
5095 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
5096
5097 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
5098 return ERROR_INSUFFICIENT_BUFFER;
5099
5100 hSvc = ScmGetServiceFromHandle(hService);
5101 if (hSvc == NULL)
5102 {
5103 DPRINT1("Invalid service handle!\n");
5104 return ERROR_INVALID_HANDLE;
5105 }
5106
5107 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5108 SERVICE_QUERY_STATUS))
5109 {
5110 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5111 return ERROR_ACCESS_DENIED;
5112 }
5113
5114 lpService = hSvc->ServiceEntry;
5115 if (lpService == NULL)
5116 {
5117 DPRINT("lpService == NULL!\n");
5118 return ERROR_INVALID_HANDLE;
5119 }
5120
5121 /* Lock the service database shared */
5122 ScmLockDatabaseShared();
5123
5124 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
5125
5126 /* Return service status information */
5127 RtlCopyMemory(lpStatus,
5128 &lpService->Status,
5129 sizeof(SERVICE_STATUS));
5130
5131 lpStatus->dwProcessId = (lpService->lpImage != NULL) ? lpService->lpImage->dwProcessId : 0; /* FIXME */
5132 lpStatus->dwServiceFlags = 0; /* FIXME */
5133
5134 /* Unlock the service database */
5135 ScmUnlockDatabase();
5136
5137 return ERROR_SUCCESS;
5138 }
5139
5140
5141 /* Function 41 */
5142 DWORD REnumServicesStatusExA(
5143 SC_RPC_HANDLE hSCManager,
5144 SC_ENUM_TYPE InfoLevel,
5145 DWORD dwServiceType,
5146 DWORD dwServiceState,
5147 LPBYTE lpBuffer,
5148 DWORD cbBufSize,
5149 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5150 LPBOUNDED_DWORD_256K lpServicesReturned,
5151 LPBOUNDED_DWORD_256K lpResumeIndex,
5152 LPCSTR pszGroupName)
5153 {
5154 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
5155 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
5156 LPWSTR lpStringPtrW;
5157 LPSTR lpStringPtrA;
5158 LPWSTR pszGroupNameW = NULL;
5159 DWORD dwError;
5160 DWORD dwServiceCount;
5161
5162 DPRINT("REnumServicesStatusExA() called\n");
5163
5164 if (pszGroupName)
5165 {
5166 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
5167 if (!pszGroupNameW)
5168 {
5169 DPRINT("Failed to allocate buffer!\n");
5170 return ERROR_NOT_ENOUGH_MEMORY;
5171 }
5172
5173 MultiByteToWideChar(CP_ACP,
5174 0,
5175 pszGroupName,
5176 -1,
5177 pszGroupNameW,
5178 strlen(pszGroupName) + 1);
5179 }
5180
5181 if ((cbBufSize > 0) && (lpBuffer))
5182 {
5183 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
5184 if (!lpStatusPtrW)
5185 {
5186 DPRINT("Failed to allocate buffer!\n");
5187 return ERROR_NOT_ENOUGH_MEMORY;
5188 }
5189 }
5190
5191 dwError = REnumServicesStatusExW(hSCManager,
5192 InfoLevel,
5193 dwServiceType,
5194 dwServiceState,
5195 (LPBYTE)lpStatusPtrW,
5196 cbBufSize,
5197 pcbBytesNeeded,
5198 lpServicesReturned,
5199 lpResumeIndex,
5200 pszGroupNameW);
5201
5202 /* if no services were returned then we are Done */
5203 if (*lpServicesReturned == 0)
5204 goto Done;
5205
5206 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
5207 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
5208 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
5209 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
5210 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
5211
5212 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
5213 {
5214 /* Copy the service name */
5215 WideCharToMultiByte(CP_ACP,
5216 0,
5217 lpStringPtrW,
5218 -1,
5219 lpStringPtrA,
5220 wcslen(lpStringPtrW),
5221 0,
5222 0);
5223
5224 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5225 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5226 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5227
5228 /* Copy the display name */
5229 WideCharToMultiByte(CP_ACP,
5230 0,
5231 lpStringPtrW,
5232 -1,
5233 lpStringPtrA,
5234 wcslen(lpStringPtrW),
5235 0,
5236 0);
5237
5238 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5239 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5240 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5241
5242 /* Copy the status information */
5243 memcpy(&lpStatusPtrA->ServiceStatusProcess,
5244 &lpStatusPtrW->ServiceStatusProcess,
5245 sizeof(SERVICE_STATUS));
5246
5247 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
5248 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5249 lpStatusPtrA++;
5250 }
5251
5252 Done:;
5253 if (pszGroupNameW)
5254 HeapFree(GetProcessHeap(), 0, pszGroupNameW);
5255
5256 if (lpStatusPtrW)
5257 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
5258
5259 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
5260
5261 return dwError;
5262 }
5263
5264
5265 /* Function 42 */
5266 DWORD REnumServicesStatusExW(
5267 SC_RPC_HANDLE hSCManager,
5268 SC_ENUM_TYPE InfoLevel,
5269 DWORD dwServiceType,
5270 DWORD dwServiceState,
5271 LPBYTE lpBuffer,
5272 DWORD cbBufSize,
5273 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5274 LPBOUNDED_DWORD_256K lpServicesReturned,
5275 LPBOUNDED_DWORD_256K lpResumeIndex,
5276 LPCWSTR pszGroupName)
5277 {
5278 PMANAGER_HANDLE hManager;
5279 PSERVICE lpService;
5280 DWORD dwError = ERROR_SUCCESS;
5281 PLIST_ENTRY ServiceEntry;
5282 PSERVICE CurrentService;
5283 DWORD dwState;
5284 DWORD dwRequiredSize;
5285 DWORD dwServiceCount;
5286 DWORD dwSize;
5287 DWORD dwLastResumeCount = 0;
5288 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
5289 LPWSTR lpStringPtr;
5290
5291 DPRINT("REnumServicesStatusExW() called\n");
5292
5293 if (ScmShutdown)
5294 return ERROR_SHUTDOWN_IN_PROGRESS;
5295
5296 if (InfoLevel != SC_ENUM_PROCESS_INFO)
5297 return ERROR_INVALID_LEVEL;
5298
5299 hManager = ScmGetServiceManagerFromHandle(hSCManager);
5300 if (hManager == NULL)
5301 {
5302 DPRINT1("Invalid service manager handle!\n");
5303 return ERROR_INVALID_HANDLE;
5304 }
5305
5306 *pcbBytesNeeded = 0;
5307 *lpServicesReturned = 0;
5308
5309 if ((dwServiceType == 0) ||
5310 ((dwServiceType & ~(SERVICE_DRIVER | SERVICE_WIN32)) != 0))
5311 {
5312 DPRINT("Not a valid Service Type!\n");
5313 return ERROR_INVALID_PARAMETER;
5314 }
5315
5316 if ((dwServiceState != SERVICE_ACTIVE) &&
5317 (dwServiceState != SERVICE_INACTIVE) &&
5318 (dwServiceState != SERVICE_STATE_ALL))
5319 {
5320 DPRINT("Not a valid Service State!\n");
5321 return ERROR_INVALID_PARAMETER;
5322 }
5323
5324 /* Check access rights */
5325 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
5326 SC_MANAGER_ENUMERATE_SERVICE))
5327 {
5328 DPRINT("Insufficient access rights! 0x%lx\n",
5329 hManager->Handle.DesiredAccess);
5330 return ERROR_ACCESS_DENIED;
5331 }
5332
5333 if (lpResumeIndex)
5334 dwLastResumeCount = *lpResumeIndex;
5335
5336 /* Lock the service database shared */
5337 ScmLockDatabaseShared();
5338
5339 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
5340 if (lpService == NULL)
5341 {
5342 dwError = ERROR_SUCCESS;
5343 goto Done;
5344 }
5345
5346 dwRequiredSize = 0;
5347 dwServiceCount = 0;
5348
5349 for (ServiceEntry = &lpService->ServiceListEntry;
5350 ServiceEntry != &ServiceListHead;
5351 ServiceEntry = ServiceEntry->Flink)
5352 {
5353 CurrentService = CONTAINING_RECORD(ServiceEntry,
5354 SERVICE,
5355 ServiceListEntry);
5356
5357 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5358 continue;
5359
5360 dwState = SERVICE_ACTIVE;
5361 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5362 dwState = SERVICE_INACTIVE;
5363
5364 if ((dwState & dwServiceState) == 0)
5365 continue;
5366
5367 if (pszGroupName)
5368 {
5369 if (*pszGroupName == 0)
5370 {
5371 if (CurrentService->lpGroup != NULL)
5372 continue;
5373 }
5374 else
5375 {
5376 if ((CurrentService->lpGroup == NULL) ||
5377 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5378 continue;
5379 }
5380 }
5381
5382 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5383 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5384 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5385
5386 if (dwRequiredSize + dwSize <= cbBufSize)
5387 {
5388 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
5389 dwRequiredSize += dwSize;
5390 dwServiceCount++;
5391 dwLastResumeCount = CurrentService->dwResumeCount;
5392 }
5393 else
5394 {
5395 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
5396 break;
5397 }
5398
5399 }
5400
5401 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
5402 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
5403
5404 for (;
5405 ServiceEntry != &ServiceListHead;
5406 ServiceEntry = ServiceEntry->Flink)
5407 {
5408 CurrentService = CONTAINING_RECORD(ServiceEntry,
5409 SERVICE,
5410 ServiceListEntry);
5411
5412 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5413 continue;
5414
5415 dwState = SERVICE_ACTIVE;
5416 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5417 dwState = SERVICE_INACTIVE;
5418
5419 if ((dwState & dwServiceState) == 0)
5420 continue;
5421
5422 if (pszGroupName)
5423 {
5424 if (*pszGroupName == 0)
5425 {
5426 if (CurrentService->lpGroup != NULL)
5427 continue;
5428 }
5429 else
5430 {
5431 if ((CurrentService->lpGroup == NULL) ||
5432 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5433 continue;
5434 }
5435 }
5436
5437 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5438 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5439 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
5440
5441 dwError = ERROR_MORE_DATA;
5442 }
5443
5444 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
5445
5446 if (lpResumeIndex)
5447 *lpResumeIndex = dwLastResumeCount;
5448
5449 *lpServicesReturned = dwServiceCount;
5450 *pcbBytesNeeded = dwRequiredSize;
5451
5452 /* If there was no services that matched */
5453 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
5454 {
5455 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
5456 goto Done;
5457 }
5458
5459 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
5460 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
5461 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
5462
5463 dwRequiredSize = 0;
5464 for (ServiceEntry = &lpService->ServiceListEntry;
5465 ServiceEntry != &ServiceListHead;
5466 ServiceEntry = ServiceEntry->Flink)
5467 {
5468 CurrentService = CONTAINING_RECORD(ServiceEntry,
5469 SERVICE,
5470 ServiceListEntry);
5471
5472 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5473 continue;
5474
5475 dwState = SERVICE_ACTIVE;
5476 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5477 dwState = SERVICE_INACTIVE;
5478
5479 if ((dwState & dwServiceState) == 0)
5480 continue;
5481
5482 if (pszGroupName)
5483 {
5484 if (*pszGroupName == 0)
5485 {
5486 if (CurrentService->lpGroup != NULL)
5487 continue;
5488 }
5489 else
5490 {
5491 if ((CurrentService->lpGroup == NULL) ||
5492 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5493 continue;
5494 }
5495 }
5496
5497 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5498 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5499 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5500
5501 if (dwRequiredSize + dwSize <= cbBufSize)
5502 {
5503 /* Copy the service name */
5504 wcscpy(lpStringPtr,
5505 CurrentService->lpServiceName);
5506 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5507 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
5508
5509 /* Copy the display name */
5510 wcscpy(lpStringPtr,
5511 CurrentService->lpDisplayName);
5512 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5513 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
5514
5515 /* Copy the status information */
5516 memcpy(&lpStatusPtr->ServiceStatusProcess,
5517 &CurrentService->Status,
5518 sizeof(SERVICE_STATUS));
5519 lpStatusPtr->ServiceStatusProcess.dwProcessId =
5520 (CurrentService->lpImage != NULL) ? CurrentService->lpImage->dwProcessId : 0; /* FIXME */
5521 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5522
5523 lpStatusPtr++;
5524 dwRequiredSize += dwSize;
5525 }
5526 else
5527 {
5528 break;
5529 }
5530 }
5531
5532 if (dwError == 0)
5533 {
5534 *pcbBytesNeeded = 0;
5535 if (lpResumeIndex)
5536 *lpResumeIndex = 0;
5537 }
5538
5539 Done:;
5540 /* Unlock the service database */
5541 ScmUnlockDatabase();
5542
5543 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
5544
5545 return dwError;
5546 }
5547
5548
5549 /* Function 43 */
5550 DWORD RSendTSMessage(
5551 handle_t BindingHandle) /* FIXME */
5552 {
5553 UNIMPLEMENTED;
5554 return ERROR_CALL_NOT_IMPLEMENTED;
5555 }
5556
5557
5558 /* Function 44 */
5559 DWORD RCreateServiceWOW64A(
5560 handle_t BindingHandle,
5561 LPSTR lpServiceName,
5562 LPSTR lpDisplayName,
5563 DWORD dwDesiredAccess,
5564 DWORD dwServiceType,
5565 DWORD dwStartType,
5566 DWORD dwErrorControl,
5567 LPSTR lpBinaryPathName,
5568 LPSTR lpLoadOrderGroup,
5569 LPDWORD lpdwTagId,
5570 LPBYTE lpDependencies,
5571 DWORD dwDependSize,
5572 LPSTR lpServiceStartName,
5573 LPBYTE lpPassword,
5574 DWORD dwPwSize,
5575 LPSC_RPC_HANDLE lpServiceHandle)
5576 {
5577 UNIMPLEMENTED;
5578 return ERROR_CALL_NOT_IMPLEMENTED;
5579 }
5580
5581
5582 /* Function 45 */
5583 DWORD RCreateServiceWOW64W(
5584 handle_t BindingHandle,
5585 LPWSTR lpServiceName,
5586 LPWSTR lpDisplayName,
5587 DWORD dwDesiredAccess,
5588 DWORD dwServiceType,
5589 DWORD dwStartType,
5590 DWORD dwErrorControl,
5591 LPWSTR lpBinaryPathName,
5592 LPWSTR lpLoadOrderGroup,
5593 LPDWORD lpdwTagId,
5594 LPBYTE lpDependencies,
5595 DWORD dwDependSize,
5596 LPWSTR lpServiceStartName,
5597 LPBYTE lpPassword,
5598 DWORD dwPwSize,
5599 LPSC_RPC_HANDLE lpServiceHandle)
5600 {
5601 UNIMPLEMENTED;
5602 return ERROR_CALL_NOT_IMPLEMENTED;
5603 }
5604
5605
5606 /* Function 46 */
5607 DWORD RQueryServiceTagInfo(
5608 handle_t BindingHandle) /* FIXME */
5609 {
5610 UNIMPLEMENTED;
5611 return ERROR_CALL_NOT_IMPLEMENTED;
5612 }
5613
5614
5615 /* Function 47 */
5616 DWORD RNotifyServiceStatusChange(
5617 SC_RPC_HANDLE hService,
5618 SC_RPC_NOTIFY_PARAMS NotifyParams,
5619 GUID *pClientProcessGuid,
5620 GUID *pSCMProcessGuid,
5621 PBOOL pfCreateRemoteQueue,
5622 LPSC_NOTIFY_RPC_HANDLE phNotify)
5623 {
5624 UNIMPLEMENTED;
5625 return ERROR_CALL_NOT_IMPLEMENTED;
5626 }
5627
5628
5629 /* Function 48 */
5630 DWORD RGetNotifyResults(
5631 SC_NOTIFY_RPC_HANDLE hNotify,
5632 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
5633 {
5634 UNIMPLEMENTED;
5635 return ERROR_CALL_NOT_IMPLEMENTED;
5636 }
5637
5638
5639 /* Function 49 */
5640 DWORD RCloseNotifyHandle(
5641 LPSC_NOTIFY_RPC_HANDLE phNotify,
5642 PBOOL pfApcFired)
5643 {
5644 UNIMPLEMENTED;
5645 return ERROR_CALL_NOT_IMPLEMENTED;
5646 }
5647
5648
5649 /* Function 50 */
5650 DWORD RControlServiceExA(
5651 SC_RPC_HANDLE hService,
5652 DWORD dwControl,
5653 DWORD dwInfoLevel)
5654 {
5655 UNIMPLEMENTED;
5656 return ERROR_CALL_NOT_IMPLEMENTED;
5657 }
5658
5659
5660 /* Function 51 */
5661 DWORD RControlServiceExW(
5662 SC_RPC_HANDLE hService,
5663 DWORD dwControl,
5664 DWORD dwInfoLevel)
5665 {
5666 UNIMPLEMENTED;
5667 return ERROR_CALL_NOT_IMPLEMENTED;
5668 }
5669
5670
5671 /* Function 52 */
5672 DWORD RSendPnPMessage(
5673 handle_t BindingHandle) /* FIXME */
5674 {
5675 UNIMPLEMENTED;
5676 return ERROR_CALL_NOT_IMPLEMENTED;
5677 }
5678
5679
5680 /* Function 53 */
5681 DWORD RValidatePnPService(
5682 handle_t BindingHandle) /* FIXME */
5683 {
5684 UNIMPLEMENTED;
5685 return ERROR_CALL_NOT_IMPLEMENTED;
5686 }
5687
5688
5689 /* Function 54 */
5690 DWORD ROpenServiceStatusHandle(
5691 handle_t BindingHandle) /* FIXME */
5692 {
5693 UNIMPLEMENTED;
5694 return ERROR_CALL_NOT_IMPLEMENTED;
5695 }
5696
5697
5698 /* Function 55 */
5699 DWORD RFunction55(
5700 handle_t BindingHandle) /* FIXME */
5701 {
5702 UNIMPLEMENTED;
5703 return ERROR_CALL_NOT_IMPLEMENTED;
5704 }
5705
5706
5707 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
5708 {
5709 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
5710 }
5711
5712
5713 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
5714 {
5715 HeapFree(GetProcessHeap(), 0, ptr);
5716 }
5717
5718
5719 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
5720 {
5721 }
5722
5723
5724 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
5725 {
5726 }
5727
5728
5729 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
5730 {
5731 }
5732
5733 /* EOF */