0ffa838aa1b0b8cdebd7abb1b33a7b8e9dc5200a
[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
1099 /* Check the service entry point */
1100 lpService = hSvc->ServiceEntry;
1101 if (lpService == NULL)
1102 {
1103 DPRINT1("lpService == NULL!\n");
1104 return ERROR_INVALID_HANDLE;
1105 }
1106
1107 /* Check access rights */
1108 switch (dwControl)
1109 {
1110 case SERVICE_CONTROL_STOP:
1111 DesiredAccess = SERVICE_STOP;
1112 break;
1113
1114 case SERVICE_CONTROL_PAUSE:
1115 case SERVICE_CONTROL_CONTINUE:
1116 DesiredAccess = SERVICE_PAUSE_CONTINUE;
1117 break;
1118
1119 case SERVICE_INTERROGATE:
1120 DesiredAccess = SERVICE_INTERROGATE;
1121 break;
1122
1123 default:
1124 if (dwControl >= 128 && dwControl <= 255)
1125 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
1126 else
1127 return ERROR_INVALID_PARAMETER;
1128 break;
1129 }
1130
1131 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1132 DesiredAccess))
1133 return ERROR_ACCESS_DENIED;
1134
1135 if (dwControl == SERVICE_CONTROL_STOP)
1136 {
1137 /* Check if the service has dependencies running as windows
1138 doesn't stop a service that does */
1139
1140 /* Open the Services Reg key */
1141 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1142 L"System\\CurrentControlSet\\Services",
1143 0,
1144 KEY_READ,
1145 &hServicesKey);
1146 if (dwError != ERROR_SUCCESS)
1147 {
1148 DPRINT("Failed to open services key\n");
1149 return dwError;
1150 }
1151
1152 /* Call the internal function with NULL, just to get bytes we need */
1153 Int_EnumDependentServicesW(hServicesKey,
1154 lpService,
1155 SERVICE_ACTIVE,
1156 NULL,
1157 &pcbBytesNeeded,
1158 &dwServicesReturned);
1159
1160 RegCloseKey(hServicesKey);
1161
1162 /* If pcbBytesNeeded is not zero then there are services running that
1163 are dependent on this service */
1164 if (pcbBytesNeeded != 0)
1165 {
1166 DPRINT("Service has running dependencies. Failed to stop service.\n");
1167 return ERROR_DEPENDENT_SERVICES_RUNNING;
1168 }
1169 }
1170
1171 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1172 {
1173 /* Send control code to the driver */
1174 dwError = ScmControlDriver(lpService,
1175 dwControl,
1176 lpServiceStatus);
1177 }
1178 else
1179 {
1180 dwControlsAccepted = lpService->Status.dwControlsAccepted;
1181 dwCurrentState = lpService->Status.dwCurrentState;
1182
1183 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1184 if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
1185 return ERROR_SERVICE_NOT_ACTIVE;
1186
1187 /* Check the current state before sending a control request */
1188 switch (dwCurrentState)
1189 {
1190 case SERVICE_STOP_PENDING:
1191 case SERVICE_STOPPED:
1192 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1193
1194 case SERVICE_START_PENDING:
1195 switch (dwControl)
1196 {
1197 case SERVICE_CONTROL_STOP:
1198 break;
1199
1200 case SERVICE_CONTROL_INTERROGATE:
1201 RtlCopyMemory(lpServiceStatus,
1202 &lpService->Status,
1203 sizeof(SERVICE_STATUS));
1204 return ERROR_SUCCESS;
1205
1206 default:
1207 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1208 }
1209 break;
1210 }
1211
1212 /* Check if the control code is acceptable to the service */
1213 switch (dwControl)
1214 {
1215 case SERVICE_CONTROL_STOP:
1216 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
1217 return ERROR_INVALID_SERVICE_CONTROL;
1218 break;
1219
1220 case SERVICE_CONTROL_PAUSE:
1221 case SERVICE_CONTROL_CONTINUE:
1222 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1223 return ERROR_INVALID_SERVICE_CONTROL;
1224 break;
1225 }
1226
1227 /* Send control code to the service */
1228 dwError = ScmControlService(lpService,
1229 dwControl);
1230
1231 /* Return service status information */
1232 RtlCopyMemory(lpServiceStatus,
1233 &lpService->Status,
1234 sizeof(SERVICE_STATUS));
1235 }
1236
1237 if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
1238 dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
1239
1240 return dwError;
1241 }
1242
1243
1244 /* Function 2 */
1245 DWORD RDeleteService(
1246 SC_RPC_HANDLE hService)
1247 {
1248 PSERVICE_HANDLE hSvc;
1249 PSERVICE lpService;
1250 DWORD dwError;
1251
1252 DPRINT("RDeleteService() called\n");
1253
1254 if (ScmShutdown)
1255 return ERROR_SHUTDOWN_IN_PROGRESS;
1256
1257 hSvc = ScmGetServiceFromHandle(hService);
1258 if (hSvc == NULL)
1259 {
1260 DPRINT1("Invalid service handle!\n");
1261 return ERROR_INVALID_HANDLE;
1262 }
1263
1264 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1265 DELETE))
1266 return ERROR_ACCESS_DENIED;
1267
1268 lpService = hSvc->ServiceEntry;
1269 if (lpService == NULL)
1270 {
1271 DPRINT("lpService == NULL!\n");
1272 return ERROR_INVALID_HANDLE;
1273 }
1274
1275 /* Lock the service database exclusively */
1276 ScmLockDatabaseExclusive();
1277
1278 if (lpService->bDeleted)
1279 {
1280 DPRINT("The service has already been marked for delete!\n");
1281 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1282 goto Done;
1283 }
1284
1285 /* Mark service for delete */
1286 lpService->bDeleted = TRUE;
1287
1288 dwError = ScmMarkServiceForDelete(lpService);
1289
1290 Done:;
1291 /* Unlock the service database */
1292 ScmUnlockDatabase();
1293
1294 DPRINT("RDeleteService() done\n");
1295
1296 return dwError;
1297 }
1298
1299
1300 /* Function 3 */
1301 DWORD RLockServiceDatabase(
1302 SC_RPC_HANDLE hSCManager,
1303 LPSC_RPC_LOCK lpLock)
1304 {
1305 PMANAGER_HANDLE hMgr;
1306
1307 DPRINT("RLockServiceDatabase() called\n");
1308
1309 *lpLock = 0;
1310
1311 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
1312 if (hMgr == NULL)
1313 {
1314 DPRINT1("Invalid service manager handle!\n");
1315 return ERROR_INVALID_HANDLE;
1316 }
1317
1318 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
1319 SC_MANAGER_LOCK))
1320 return ERROR_ACCESS_DENIED;
1321
1322 // return ScmLockDatabase(0, hMgr->0xC, hLock);
1323
1324 /* FIXME: Lock the database */
1325 *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */
1326
1327 return ERROR_SUCCESS;
1328 }
1329
1330
1331 /* Function 4 */
1332 DWORD RQueryServiceObjectSecurity(
1333 SC_RPC_HANDLE hService,
1334 SECURITY_INFORMATION dwSecurityInformation,
1335 LPBYTE lpSecurityDescriptor,
1336 DWORD cbBufSize,
1337 LPBOUNDED_DWORD_256K pcbBytesNeeded)
1338 {
1339 PSERVICE_HANDLE hSvc;
1340 PSERVICE lpService;
1341 ULONG DesiredAccess = 0;
1342 NTSTATUS Status;
1343 DWORD dwBytesNeeded;
1344 DWORD dwError;
1345
1346
1347 SECURITY_DESCRIPTOR ObjectDescriptor;
1348
1349 DPRINT("RQueryServiceObjectSecurity() called\n");
1350
1351 hSvc = ScmGetServiceFromHandle(hService);
1352 if (hSvc == NULL)
1353 {
1354 DPRINT1("Invalid service handle!\n");
1355 return ERROR_INVALID_HANDLE;
1356 }
1357
1358 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1359 GROUP_SECURITY_INFORMATION |
1360 OWNER_SECURITY_INFORMATION))
1361 DesiredAccess |= READ_CONTROL;
1362
1363 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1364 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1365
1366 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1367 DesiredAccess))
1368 {
1369 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1370 return ERROR_ACCESS_DENIED;
1371 }
1372
1373 lpService = hSvc->ServiceEntry;
1374 if (lpService == NULL)
1375 {
1376 DPRINT("lpService == NULL!\n");
1377 return ERROR_INVALID_HANDLE;
1378 }
1379
1380 /* Lock the service database */
1381 ScmLockDatabaseShared();
1382
1383
1384 /* hack */
1385 Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
1386
1387 Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */,
1388 dwSecurityInformation,
1389 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1390 cbBufSize,
1391 &dwBytesNeeded);
1392
1393 /* Unlock the service database */
1394 ScmUnlockDatabase();
1395
1396 if (NT_SUCCESS(Status))
1397 {
1398 *pcbBytesNeeded = dwBytesNeeded;
1399 dwError = STATUS_SUCCESS;
1400 }
1401 else if (Status == STATUS_BUFFER_TOO_SMALL)
1402 {
1403 *pcbBytesNeeded = dwBytesNeeded;
1404 dwError = ERROR_INSUFFICIENT_BUFFER;
1405 }
1406 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
1407 {
1408 dwError = ERROR_GEN_FAILURE;
1409 }
1410 else
1411 {
1412 dwError = RtlNtStatusToDosError(Status);
1413 }
1414
1415 return dwError;
1416 }
1417
1418
1419 /* Function 5 */
1420 DWORD RSetServiceObjectSecurity(
1421 SC_RPC_HANDLE hService,
1422 DWORD dwSecurityInformation,
1423 LPBYTE lpSecurityDescriptor,
1424 DWORD dwSecuityDescriptorSize)
1425 {
1426 PSERVICE_HANDLE hSvc;
1427 PSERVICE lpService;
1428 ULONG DesiredAccess = 0;
1429 /* HANDLE hToken = NULL; */
1430 HKEY hServiceKey;
1431 /* NTSTATUS Status; */
1432 DWORD dwError;
1433
1434 DPRINT("RSetServiceObjectSecurity() called\n");
1435
1436 hSvc = ScmGetServiceFromHandle(hService);
1437 if (hSvc == NULL)
1438 {
1439 DPRINT1("Invalid service handle!\n");
1440 return ERROR_INVALID_HANDLE;
1441 }
1442
1443 if (dwSecurityInformation == 0 ||
1444 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1445 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
1446 return ERROR_INVALID_PARAMETER;
1447
1448 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1449 return ERROR_INVALID_PARAMETER;
1450
1451 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1452 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1453
1454 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1455 DesiredAccess |= WRITE_DAC;
1456
1457 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1458 DesiredAccess |= WRITE_OWNER;
1459
1460 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1461 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1462 return ERROR_INVALID_PARAMETER;
1463
1464 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1465 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1466 return ERROR_INVALID_PARAMETER;
1467
1468 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1469 DesiredAccess))
1470 {
1471 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1472 return ERROR_ACCESS_DENIED;
1473 }
1474
1475 lpService = hSvc->ServiceEntry;
1476 if (lpService == NULL)
1477 {
1478 DPRINT("lpService == NULL!\n");
1479 return ERROR_INVALID_HANDLE;
1480 }
1481
1482 if (lpService->bDeleted)
1483 return ERROR_SERVICE_MARKED_FOR_DELETE;
1484
1485 #if 0
1486 RpcImpersonateClient(NULL);
1487
1488 Status = NtOpenThreadToken(NtCurrentThread(),
1489 8,
1490 TRUE,
1491 &hToken);
1492 if (!NT_SUCCESS(Status))
1493 return RtlNtStatusToDosError(Status);
1494
1495 RpcRevertToSelf();
1496 #endif
1497
1498 /* Lock the service database exclusive */
1499 ScmLockDatabaseExclusive();
1500
1501 #if 0
1502 Status = RtlSetSecurityObject(dwSecurityInformation,
1503 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1504 &lpService->lpSecurityDescriptor,
1505 &ScmServiceMapping,
1506 hToken);
1507 if (!NT_SUCCESS(Status))
1508 {
1509 dwError = RtlNtStatusToDosError(Status);
1510 goto Done;
1511 }
1512 #endif
1513
1514 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1515 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
1516 &hServiceKey);
1517 if (dwError != ERROR_SUCCESS)
1518 goto Done;
1519
1520 UNIMPLEMENTED;
1521 dwError = ERROR_SUCCESS;
1522 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
1523 // lpService->lpSecurityDescriptor);
1524
1525 RegFlushKey(hServiceKey);
1526 RegCloseKey(hServiceKey);
1527
1528 Done:
1529
1530 #if 0
1531 if (hToken != NULL)
1532 NtClose(hToken);
1533 #endif
1534
1535 /* Unlock service database */
1536 ScmUnlockDatabase();
1537
1538 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1539
1540 return dwError;
1541 }
1542
1543
1544 /* Function 6 */
1545 DWORD RQueryServiceStatus(
1546 SC_RPC_HANDLE hService,
1547 LPSERVICE_STATUS lpServiceStatus)
1548 {
1549 PSERVICE_HANDLE hSvc;
1550 PSERVICE lpService;
1551
1552 DPRINT("RQueryServiceStatus() called\n");
1553
1554 if (ScmShutdown)
1555 return ERROR_SHUTDOWN_IN_PROGRESS;
1556
1557 hSvc = ScmGetServiceFromHandle(hService);
1558 if (hSvc == NULL)
1559 {
1560 DPRINT1("Invalid service handle!\n");
1561 return ERROR_INVALID_HANDLE;
1562 }
1563
1564 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1565 SERVICE_QUERY_STATUS))
1566 {
1567 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1568 return ERROR_ACCESS_DENIED;
1569 }
1570
1571 lpService = hSvc->ServiceEntry;
1572 if (lpService == NULL)
1573 {
1574 DPRINT("lpService == NULL!\n");
1575 return ERROR_INVALID_HANDLE;
1576 }
1577
1578 /* Lock the service database shared */
1579 ScmLockDatabaseShared();
1580
1581 /* Return service status information */
1582 RtlCopyMemory(lpServiceStatus,
1583 &lpService->Status,
1584 sizeof(SERVICE_STATUS));
1585
1586 /* Unlock the service database */
1587 ScmUnlockDatabase();
1588
1589 return ERROR_SUCCESS;
1590 }
1591
1592
1593 static BOOL
1594 ScmIsValidServiceState(DWORD dwCurrentState)
1595 {
1596 switch (dwCurrentState)
1597 {
1598 case SERVICE_STOPPED:
1599 case SERVICE_START_PENDING:
1600 case SERVICE_STOP_PENDING:
1601 case SERVICE_RUNNING:
1602 case SERVICE_CONTINUE_PENDING:
1603 case SERVICE_PAUSE_PENDING:
1604 case SERVICE_PAUSED:
1605 return TRUE;
1606
1607 default:
1608 return FALSE;
1609 }
1610 }
1611
1612
1613 /* Function 7 */
1614 DWORD RSetServiceStatus(
1615 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1616 LPSERVICE_STATUS lpServiceStatus)
1617 {
1618 PSERVICE lpService;
1619
1620 DPRINT("RSetServiceStatus() called\n");
1621 DPRINT("hServiceStatus = %p\n", hServiceStatus);
1622 DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
1623 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1624 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1625 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1626 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1627 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1628 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1629
1630 if (hServiceStatus == 0)
1631 {
1632 DPRINT("hServiceStatus == NULL!\n");
1633 return ERROR_INVALID_HANDLE;
1634 }
1635
1636 lpService = (PSERVICE)hServiceStatus;
1637 if (lpService == NULL)
1638 {
1639 DPRINT("lpService == NULL!\n");
1640 return ERROR_INVALID_HANDLE;
1641 }
1642
1643 /* Check current state */
1644 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1645 {
1646 DPRINT("Invalid service state!\n");
1647 return ERROR_INVALID_DATA;
1648 }
1649
1650 /* Check service type */
1651 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1652 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1653 {
1654 DPRINT("Invalid service type!\n");
1655 return ERROR_INVALID_DATA;
1656 }
1657
1658 /* Check accepted controls */
1659 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1660 {
1661 DPRINT("Invalid controls accepted!\n");
1662 return ERROR_INVALID_DATA;
1663 }
1664
1665 /* Lock the service database exclusively */
1666 ScmLockDatabaseExclusive();
1667
1668 RtlCopyMemory(&lpService->Status,
1669 lpServiceStatus,
1670 sizeof(SERVICE_STATUS));
1671
1672 /* Unlock the service database */
1673 ScmUnlockDatabase();
1674
1675 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1676 DPRINT("RSetServiceStatus() done\n");
1677
1678 return ERROR_SUCCESS;
1679 }
1680
1681
1682 /* Function 8 */
1683 DWORD RUnlockServiceDatabase(
1684 LPSC_RPC_LOCK Lock)
1685 {
1686 UNIMPLEMENTED;
1687 return ERROR_SUCCESS;
1688 }
1689
1690
1691 /* Function 9 */
1692 DWORD RNotifyBootConfigStatus(
1693 SVCCTL_HANDLEW lpMachineName,
1694 DWORD BootAcceptable)
1695 {
1696 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1697 return ERROR_SUCCESS;
1698
1699 // UNIMPLEMENTED;
1700 // return ERROR_CALL_NOT_IMPLEMENTED;
1701 }
1702
1703
1704 /* Function 10 */
1705 DWORD RI_ScSetServiceBitsW(
1706 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1707 DWORD dwServiceBits,
1708 int bSetBitsOn,
1709 int bUpdateImmediately,
1710 wchar_t *lpString)
1711 {
1712 UNIMPLEMENTED;
1713 return ERROR_CALL_NOT_IMPLEMENTED;
1714 }
1715
1716
1717 /* Function 11 */
1718 DWORD RChangeServiceConfigW(
1719 SC_RPC_HANDLE hService,
1720 DWORD dwServiceType,
1721 DWORD dwStartType,
1722 DWORD dwErrorControl,
1723 LPWSTR lpBinaryPathName,
1724 LPWSTR lpLoadOrderGroup,
1725 LPDWORD lpdwTagId,
1726 LPBYTE lpDependencies,
1727 DWORD dwDependSize,
1728 LPWSTR lpServiceStartName,
1729 LPBYTE lpPassword,
1730 DWORD dwPwSize,
1731 LPWSTR lpDisplayName)
1732 {
1733 DWORD dwError = ERROR_SUCCESS;
1734 PSERVICE_HANDLE hSvc;
1735 PSERVICE lpService = NULL;
1736 HKEY hServiceKey = NULL;
1737 LPWSTR lpDisplayNameW = NULL;
1738 LPWSTR lpImagePathW = NULL;
1739
1740 DPRINT("RChangeServiceConfigW() called\n");
1741 DPRINT("dwServiceType = %lu\n", dwServiceType);
1742 DPRINT("dwStartType = %lu\n", dwStartType);
1743 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1744 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1745 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1746 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1747
1748 if (ScmShutdown)
1749 return ERROR_SHUTDOWN_IN_PROGRESS;
1750
1751 hSvc = ScmGetServiceFromHandle(hService);
1752 if (hSvc == NULL)
1753 {
1754 DPRINT1("Invalid service handle!\n");
1755 return ERROR_INVALID_HANDLE;
1756 }
1757
1758 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1759 SERVICE_CHANGE_CONFIG))
1760 {
1761 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1762 return ERROR_ACCESS_DENIED;
1763 }
1764
1765 lpService = hSvc->ServiceEntry;
1766 if (lpService == NULL)
1767 {
1768 DPRINT("lpService == NULL!\n");
1769 return ERROR_INVALID_HANDLE;
1770 }
1771
1772 /* Lock the service database exclusively */
1773 ScmLockDatabaseExclusive();
1774
1775 if (lpService->bDeleted)
1776 {
1777 DPRINT("The service has already been marked for delete!\n");
1778 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1779 goto done;
1780 }
1781
1782 /* Open the service key */
1783 dwError = ScmOpenServiceKey(lpService->szServiceName,
1784 KEY_SET_VALUE,
1785 &hServiceKey);
1786 if (dwError != ERROR_SUCCESS)
1787 goto done;
1788
1789 /* Write service data to the registry */
1790 /* Set the display name */
1791 if (lpDisplayName != NULL && *lpDisplayName != 0)
1792 {
1793 RegSetValueExW(hServiceKey,
1794 L"DisplayName",
1795 0,
1796 REG_SZ,
1797 (LPBYTE)lpDisplayName,
1798 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1799
1800 /* Update the display name */
1801 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
1802 0,
1803 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1804 if (lpDisplayNameW == NULL)
1805 {
1806 dwError = ERROR_NOT_ENOUGH_MEMORY;
1807 goto done;
1808 }
1809
1810 if (lpService->lpDisplayName != lpService->lpServiceName)
1811 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1812
1813 lpService->lpDisplayName = lpDisplayNameW;
1814 }
1815
1816 if (dwServiceType != SERVICE_NO_CHANGE)
1817 {
1818 /* Set the service type */
1819 dwError = RegSetValueExW(hServiceKey,
1820 L"Type",
1821 0,
1822 REG_DWORD,
1823 (LPBYTE)&dwServiceType,
1824 sizeof(DWORD));
1825 if (dwError != ERROR_SUCCESS)
1826 goto done;
1827
1828 lpService->Status.dwServiceType = dwServiceType;
1829 }
1830
1831 if (dwStartType != SERVICE_NO_CHANGE)
1832 {
1833 /* Set the start value */
1834 dwError = RegSetValueExW(hServiceKey,
1835 L"Start",
1836 0,
1837 REG_DWORD,
1838 (LPBYTE)&dwStartType,
1839 sizeof(DWORD));
1840 if (dwError != ERROR_SUCCESS)
1841 goto done;
1842
1843 lpService->dwStartType = dwStartType;
1844 }
1845
1846 if (dwErrorControl != SERVICE_NO_CHANGE)
1847 {
1848 /* Set the error control value */
1849 dwError = RegSetValueExW(hServiceKey,
1850 L"ErrorControl",
1851 0,
1852 REG_DWORD,
1853 (LPBYTE)&dwErrorControl,
1854 sizeof(DWORD));
1855 if (dwError != ERROR_SUCCESS)
1856 goto done;
1857
1858 lpService->dwErrorControl = dwErrorControl;
1859 }
1860
1861 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
1862 {
1863 /* Set the image path */
1864 lpImagePathW = lpBinaryPathName;
1865
1866 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1867 {
1868 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
1869 lpBinaryPathName,
1870 &lpImagePathW);
1871
1872 if (dwError != ERROR_SUCCESS)
1873 goto done;
1874 }
1875
1876 dwError = RegSetValueExW(hServiceKey,
1877 L"ImagePath",
1878 0,
1879 REG_EXPAND_SZ,
1880 (LPBYTE)lpImagePathW,
1881 (wcslen(lpImagePathW) + 1) * sizeof(WCHAR));
1882
1883 if (lpImagePathW != lpBinaryPathName)
1884 HeapFree(GetProcessHeap(), 0, lpImagePathW);
1885
1886 if (dwError != ERROR_SUCCESS)
1887 goto done;
1888 }
1889
1890 /* Set the group name */
1891 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1892 {
1893 dwError = RegSetValueExW(hServiceKey,
1894 L"Group",
1895 0,
1896 REG_SZ,
1897 (LPBYTE)lpLoadOrderGroup,
1898 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1899 if (dwError != ERROR_SUCCESS)
1900 goto done;
1901
1902 dwError = ScmSetServiceGroup(lpService,
1903 lpLoadOrderGroup);
1904 if (dwError != ERROR_SUCCESS)
1905 goto done;
1906 }
1907
1908 if (lpdwTagId != NULL)
1909 {
1910 dwError = ScmAssignNewTag(lpService);
1911 if (dwError != ERROR_SUCCESS)
1912 goto done;
1913
1914 dwError = RegSetValueExW(hServiceKey,
1915 L"Tag",
1916 0,
1917 REG_DWORD,
1918 (LPBYTE)&lpService->dwTag,
1919 sizeof(DWORD));
1920 if (dwError != ERROR_SUCCESS)
1921 goto done;
1922
1923 *lpdwTagId = lpService->dwTag;
1924 }
1925
1926 /* Write dependencies */
1927 if (lpDependencies != NULL && *lpDependencies != 0)
1928 {
1929 dwError = ScmWriteDependencies(hServiceKey,
1930 (LPWSTR)lpDependencies,
1931 dwDependSize);
1932 if (dwError != ERROR_SUCCESS)
1933 goto done;
1934 }
1935
1936 if (lpPassword != NULL)
1937 {
1938 /* FIXME: Write password */
1939 }
1940
1941 done:
1942 if (hServiceKey != NULL)
1943 RegCloseKey(hServiceKey);
1944
1945 /* Unlock the service database */
1946 ScmUnlockDatabase();
1947
1948 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1949
1950 return dwError;
1951 }
1952
1953
1954 /* Function 12 */
1955 DWORD RCreateServiceW(
1956 SC_RPC_HANDLE hSCManager,
1957 LPCWSTR lpServiceName,
1958 LPCWSTR lpDisplayName,
1959 DWORD dwDesiredAccess,
1960 DWORD dwServiceType,
1961 DWORD dwStartType,
1962 DWORD dwErrorControl,
1963 LPCWSTR lpBinaryPathName,
1964 LPCWSTR lpLoadOrderGroup,
1965 LPDWORD lpdwTagId,
1966 LPBYTE lpDependencies,
1967 DWORD dwDependSize,
1968 LPCWSTR lpServiceStartName,
1969 LPBYTE lpPassword,
1970 DWORD dwPwSize,
1971 LPSC_RPC_HANDLE lpServiceHandle)
1972 {
1973 PMANAGER_HANDLE hManager;
1974 DWORD dwError = ERROR_SUCCESS;
1975 PSERVICE lpService = NULL;
1976 SC_HANDLE hServiceHandle = NULL;
1977 LPWSTR lpImagePath = NULL;
1978 HKEY hServiceKey = NULL;
1979 LPWSTR lpObjectName;
1980
1981 DPRINT("RCreateServiceW() called\n");
1982 DPRINT("lpServiceName = %S\n", lpServiceName);
1983 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1984 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
1985 DPRINT("dwServiceType = %lu\n", dwServiceType);
1986 DPRINT("dwStartType = %lu\n", dwStartType);
1987 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1988 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1989 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1990 DPRINT("lpdwTagId = %p\n", lpdwTagId);
1991
1992 if (ScmShutdown)
1993 return ERROR_SHUTDOWN_IN_PROGRESS;
1994
1995 hManager = ScmGetServiceManagerFromHandle(hSCManager);
1996 if (hManager == NULL)
1997 {
1998 DPRINT1("Invalid service manager handle!\n");
1999 return ERROR_INVALID_HANDLE;
2000 }
2001
2002 /* Check access rights */
2003 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2004 SC_MANAGER_CREATE_SERVICE))
2005 {
2006 DPRINT("Insufficient access rights! 0x%lx\n",
2007 hManager->Handle.DesiredAccess);
2008 return ERROR_ACCESS_DENIED;
2009 }
2010
2011 if (wcslen(lpServiceName) == 0)
2012 {
2013 return ERROR_INVALID_NAME;
2014 }
2015
2016 if (wcslen(lpBinaryPathName) == 0)
2017 {
2018 return ERROR_INVALID_PARAMETER;
2019 }
2020
2021 /* Check for invalid service type value */
2022 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2023 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2024 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2025 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
2026 return ERROR_INVALID_PARAMETER;
2027
2028 /* Check for invalid start type value */
2029 if ((dwStartType != SERVICE_BOOT_START) &&
2030 (dwStartType != SERVICE_SYSTEM_START) &&
2031 (dwStartType != SERVICE_AUTO_START) &&
2032 (dwStartType != SERVICE_DEMAND_START) &&
2033 (dwStartType != SERVICE_DISABLED))
2034 return ERROR_INVALID_PARAMETER;
2035
2036 /* Only drivers can be boot start or system start services */
2037 if ((dwStartType == SERVICE_BOOT_START) ||
2038 (dwStartType == SERVICE_SYSTEM_START))
2039 {
2040 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2041 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2042 return ERROR_INVALID_PARAMETER;
2043 }
2044
2045 /* Check for invalid error control value */
2046 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2047 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2048 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2049 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2050 return ERROR_INVALID_PARAMETER;
2051
2052 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2053 (lpServiceStartName))
2054 {
2055 return ERROR_INVALID_PARAMETER;
2056 }
2057
2058 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2059 {
2060 return ERROR_INVALID_PARAMETER;
2061 }
2062
2063 /* Lock the service database exclusively */
2064 ScmLockDatabaseExclusive();
2065
2066 lpService = ScmGetServiceEntryByName(lpServiceName);
2067 if (lpService)
2068 {
2069 /* Unlock the service database */
2070 ScmUnlockDatabase();
2071
2072 /* Check if it is marked for deletion */
2073 if (lpService->bDeleted)
2074 return ERROR_SERVICE_MARKED_FOR_DELETE;
2075
2076 /* Return Error exist */
2077 return ERROR_SERVICE_EXISTS;
2078 }
2079
2080 if (lpDisplayName != NULL &&
2081 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2082 {
2083 /* Unlock the service database */
2084 ScmUnlockDatabase();
2085
2086 return ERROR_DUPLICATE_SERVICE_NAME;
2087 }
2088
2089 if (dwServiceType & SERVICE_DRIVER)
2090 {
2091 dwError = ScmCanonDriverImagePath(dwStartType,
2092 lpBinaryPathName,
2093 &lpImagePath);
2094 if (dwError != ERROR_SUCCESS)
2095 goto done;
2096 }
2097 else
2098 {
2099 if (dwStartType == SERVICE_BOOT_START ||
2100 dwStartType == SERVICE_SYSTEM_START)
2101 {
2102 /* Unlock the service database */
2103 ScmUnlockDatabase();
2104
2105 return ERROR_INVALID_PARAMETER;
2106 }
2107 }
2108
2109 /* Allocate a new service entry */
2110 dwError = ScmCreateNewServiceRecord(lpServiceName,
2111 &lpService);
2112 if (dwError != ERROR_SUCCESS)
2113 goto done;
2114
2115 /* Fill the new service entry */
2116 lpService->Status.dwServiceType = dwServiceType;
2117 lpService->dwStartType = dwStartType;
2118 lpService->dwErrorControl = dwErrorControl;
2119
2120 /* Fill the display name */
2121 if (lpDisplayName != NULL &&
2122 *lpDisplayName != 0 &&
2123 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2124 {
2125 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(), 0,
2126 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2127 if (lpService->lpDisplayName == NULL)
2128 {
2129 dwError = ERROR_NOT_ENOUGH_MEMORY;
2130 goto done;
2131 }
2132 wcscpy(lpService->lpDisplayName, lpDisplayName);
2133 }
2134
2135 /* Assign the service to a group */
2136 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2137 {
2138 dwError = ScmSetServiceGroup(lpService,
2139 lpLoadOrderGroup);
2140 if (dwError != ERROR_SUCCESS)
2141 goto done;
2142 }
2143
2144 /* Assign a new tag */
2145 if (lpdwTagId != NULL)
2146 {
2147 dwError = ScmAssignNewTag(lpService);
2148 if (dwError != ERROR_SUCCESS)
2149 goto done;
2150 }
2151
2152 /* Write service data to the registry */
2153 /* Create the service key */
2154 dwError = ScmCreateServiceKey(lpServiceName,
2155 KEY_WRITE,
2156 &hServiceKey);
2157 if (dwError != ERROR_SUCCESS)
2158 goto done;
2159
2160 /* Set the display name */
2161 if (lpDisplayName != NULL && *lpDisplayName != 0)
2162 {
2163 RegSetValueExW(hServiceKey,
2164 L"DisplayName",
2165 0,
2166 REG_SZ,
2167 (LPBYTE)lpDisplayName,
2168 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2169 }
2170
2171 /* Set the service type */
2172 dwError = RegSetValueExW(hServiceKey,
2173 L"Type",
2174 0,
2175 REG_DWORD,
2176 (LPBYTE)&dwServiceType,
2177 sizeof(DWORD));
2178 if (dwError != ERROR_SUCCESS)
2179 goto done;
2180
2181 /* Set the start value */
2182 dwError = RegSetValueExW(hServiceKey,
2183 L"Start",
2184 0,
2185 REG_DWORD,
2186 (LPBYTE)&dwStartType,
2187 sizeof(DWORD));
2188 if (dwError != ERROR_SUCCESS)
2189 goto done;
2190
2191 /* Set the error control value */
2192 dwError = RegSetValueExW(hServiceKey,
2193 L"ErrorControl",
2194 0,
2195 REG_DWORD,
2196 (LPBYTE)&dwErrorControl,
2197 sizeof(DWORD));
2198 if (dwError != ERROR_SUCCESS)
2199 goto done;
2200
2201 /* Set the image path */
2202 if (dwServiceType & SERVICE_WIN32)
2203 {
2204 dwError = RegSetValueExW(hServiceKey,
2205 L"ImagePath",
2206 0,
2207 REG_EXPAND_SZ,
2208 (LPBYTE)lpBinaryPathName,
2209 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
2210 if (dwError != ERROR_SUCCESS)
2211 goto done;
2212 }
2213 else if (dwServiceType & SERVICE_DRIVER)
2214 {
2215 dwError = RegSetValueExW(hServiceKey,
2216 L"ImagePath",
2217 0,
2218 REG_EXPAND_SZ,
2219 (LPBYTE)lpImagePath,
2220 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2221 if (dwError != ERROR_SUCCESS)
2222 goto done;
2223 }
2224
2225 /* Set the group name */
2226 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2227 {
2228 dwError = RegSetValueExW(hServiceKey,
2229 L"Group",
2230 0,
2231 REG_SZ,
2232 (LPBYTE)lpLoadOrderGroup,
2233 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
2234 if (dwError != ERROR_SUCCESS)
2235 goto done;
2236 }
2237
2238 if (lpdwTagId != NULL)
2239 {
2240 dwError = RegSetValueExW(hServiceKey,
2241 L"Tag",
2242 0,
2243 REG_DWORD,
2244 (LPBYTE)&lpService->dwTag,
2245 sizeof(DWORD));
2246 if (dwError != ERROR_SUCCESS)
2247 goto done;
2248 }
2249
2250 /* Write dependencies */
2251 if (lpDependencies != NULL && *lpDependencies != 0)
2252 {
2253 dwError = ScmWriteDependencies(hServiceKey,
2254 (LPCWSTR)lpDependencies,
2255 dwDependSize);
2256 if (dwError != ERROR_SUCCESS)
2257 goto done;
2258 }
2259
2260 /* Write service start name */
2261 if (dwServiceType & SERVICE_WIN32)
2262 {
2263 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2264 dwError = RegSetValueExW(hServiceKey,
2265 L"ObjectName",
2266 0,
2267 REG_SZ,
2268 (LPBYTE)lpObjectName,
2269 (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
2270 if (dwError != ERROR_SUCCESS)
2271 goto done;
2272 }
2273
2274 if (lpPassword != NULL)
2275 {
2276 /* FIXME: Write password */
2277 }
2278
2279 dwError = ScmCreateServiceHandle(lpService,
2280 &hServiceHandle);
2281 if (dwError != ERROR_SUCCESS)
2282 goto done;
2283
2284 dwError = ScmCheckAccess(hServiceHandle,
2285 dwDesiredAccess);
2286 if (dwError != ERROR_SUCCESS)
2287 goto done;
2288
2289 lpService->dwRefCount = 1;
2290 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2291
2292 done:;
2293 /* Unlock the service database */
2294 ScmUnlockDatabase();
2295
2296 if (hServiceKey != NULL)
2297 RegCloseKey(hServiceKey);
2298
2299 if (dwError == ERROR_SUCCESS)
2300 {
2301 DPRINT("hService %p\n", hServiceHandle);
2302 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2303
2304 if (lpdwTagId != NULL)
2305 *lpdwTagId = lpService->dwTag;
2306 }
2307 else
2308 {
2309 if (lpService != NULL &&
2310 lpService->lpServiceName != NULL)
2311 {
2312 /* Release the display name buffer */
2313 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2314 }
2315
2316 if (hServiceHandle)
2317 {
2318 /* Remove the service handle */
2319 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2320 }
2321
2322 if (lpService != NULL)
2323 {
2324 /* FIXME: remove the service entry */
2325 }
2326 }
2327
2328 if (lpImagePath != NULL)
2329 HeapFree(GetProcessHeap(), 0, lpImagePath);
2330
2331 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2332
2333 return dwError;
2334 }
2335
2336
2337 /* Function 13 */
2338 DWORD REnumDependentServicesW(
2339 SC_RPC_HANDLE hService,
2340 DWORD dwServiceState,
2341 LPBYTE lpServices,
2342 DWORD cbBufSize,
2343 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2344 LPBOUNDED_DWORD_256K lpServicesReturned)
2345 {
2346 DWORD dwError = ERROR_SUCCESS;
2347 DWORD dwServicesReturned = 0;
2348 DWORD dwServiceCount;
2349 HKEY hServicesKey = NULL;
2350 PSERVICE_HANDLE hSvc;
2351 PSERVICE lpService = NULL;
2352 PSERVICE *lpServicesArray = NULL;
2353 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2354 LPWSTR lpStr;
2355
2356 *pcbBytesNeeded = 0;
2357 *lpServicesReturned = 0;
2358
2359 DPRINT("REnumDependentServicesW() called\n");
2360
2361 hSvc = ScmGetServiceFromHandle(hService);
2362 if (hSvc == NULL)
2363 {
2364 DPRINT1("Invalid service handle!\n");
2365 return ERROR_INVALID_HANDLE;
2366 }
2367
2368 lpService = hSvc->ServiceEntry;
2369
2370 /* Check access rights */
2371 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2372 SC_MANAGER_ENUMERATE_SERVICE))
2373 {
2374 DPRINT("Insufficient access rights! 0x%lx\n",
2375 hSvc->Handle.DesiredAccess);
2376 return ERROR_ACCESS_DENIED;
2377 }
2378
2379 /* Open the Services Reg key */
2380 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2381 L"System\\CurrentControlSet\\Services",
2382 0,
2383 KEY_READ,
2384 &hServicesKey);
2385 if (dwError != ERROR_SUCCESS)
2386 return dwError;
2387
2388 /* First determine the bytes needed and get the number of dependent services */
2389 dwError = Int_EnumDependentServicesW(hServicesKey,
2390 lpService,
2391 dwServiceState,
2392 NULL,
2393 pcbBytesNeeded,
2394 &dwServicesReturned);
2395 if (dwError != ERROR_SUCCESS)
2396 goto Done;
2397
2398 /* If buffer size is less than the bytes needed or pointer is null */
2399 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2400 {
2401 dwError = ERROR_MORE_DATA;
2402 goto Done;
2403 }
2404
2405 /* Allocate memory for array of service pointers */
2406 lpServicesArray = HeapAlloc(GetProcessHeap(),
2407 0,
2408 (dwServicesReturned + 1) * sizeof(PSERVICE));
2409 if (!lpServicesArray)
2410 {
2411 DPRINT1("Could not allocate a buffer!!\n");
2412 dwError = ERROR_NOT_ENOUGH_MEMORY;
2413 goto Done;
2414 }
2415
2416 dwServicesReturned = 0;
2417 *pcbBytesNeeded = 0;
2418
2419 dwError = Int_EnumDependentServicesW(hServicesKey,
2420 lpService,
2421 dwServiceState,
2422 lpServicesArray,
2423 pcbBytesNeeded,
2424 &dwServicesReturned);
2425 if (dwError != ERROR_SUCCESS)
2426 {
2427 goto Done;
2428 }
2429
2430 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
2431 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2432
2433 /* Copy EnumDepenedentService to Buffer */
2434 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2435 {
2436 lpService = lpServicesArray[dwServiceCount];
2437
2438 /* Copy status info */
2439 memcpy(&lpServicesPtr->ServiceStatus,
2440 &lpService->Status,
2441 sizeof(SERVICE_STATUS));
2442
2443 /* Copy display name */
2444 wcscpy(lpStr, lpService->lpDisplayName);
2445 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2446 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2447
2448 /* Copy service name */
2449 wcscpy(lpStr, lpService->lpServiceName);
2450 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2451 lpStr += (wcslen(lpService->lpServiceName) + 1);
2452
2453 lpServicesPtr ++;
2454 }
2455
2456 *lpServicesReturned = dwServicesReturned;
2457
2458 Done:
2459 if (lpServicesArray != NULL)
2460 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2461
2462 RegCloseKey(hServicesKey);
2463
2464 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2465
2466 return dwError;
2467 }
2468
2469
2470 /* Function 14 */
2471 DWORD REnumServicesStatusW(
2472 SC_RPC_HANDLE hSCManager,
2473 DWORD dwServiceType,
2474 DWORD dwServiceState,
2475 LPBYTE lpBuffer,
2476 DWORD dwBufSize,
2477 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2478 LPBOUNDED_DWORD_256K lpServicesReturned,
2479 LPBOUNDED_DWORD_256K lpResumeHandle)
2480 {
2481 PMANAGER_HANDLE hManager;
2482 PSERVICE lpService;
2483 DWORD dwError = ERROR_SUCCESS;
2484 PLIST_ENTRY ServiceEntry;
2485 PSERVICE CurrentService;
2486 DWORD dwState;
2487 DWORD dwRequiredSize;
2488 DWORD dwServiceCount;
2489 DWORD dwSize;
2490 DWORD dwLastResumeCount = 0;
2491 LPENUM_SERVICE_STATUSW lpStatusPtr;
2492 LPWSTR lpStringPtr;
2493
2494 DPRINT("REnumServicesStatusW() called\n");
2495
2496 if (ScmShutdown)
2497 return ERROR_SHUTDOWN_IN_PROGRESS;
2498
2499 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2500 if (hManager == NULL)
2501 {
2502 DPRINT1("Invalid service manager handle!\n");
2503 return ERROR_INVALID_HANDLE;
2504 }
2505
2506
2507 *pcbBytesNeeded = 0;
2508 *lpServicesReturned = 0;
2509
2510 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
2511 {
2512 DPRINT("Not a valid Service Type!\n");
2513 return ERROR_INVALID_PARAMETER;
2514 }
2515
2516 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
2517 {
2518 DPRINT("Not a valid Service State!\n");
2519 return ERROR_INVALID_PARAMETER;
2520 }
2521
2522 /* Check access rights */
2523 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2524 SC_MANAGER_ENUMERATE_SERVICE))
2525 {
2526 DPRINT("Insufficient access rights! 0x%lx\n",
2527 hManager->Handle.DesiredAccess);
2528 return ERROR_ACCESS_DENIED;
2529 }
2530
2531 if (lpResumeHandle)
2532 dwLastResumeCount = *lpResumeHandle;
2533
2534 /* Lock the service database shared */
2535 ScmLockDatabaseShared();
2536
2537 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2538 if (lpService == NULL)
2539 {
2540 dwError = ERROR_SUCCESS;
2541 goto Done;
2542 }
2543
2544 dwRequiredSize = 0;
2545 dwServiceCount = 0;
2546
2547 for (ServiceEntry = &lpService->ServiceListEntry;
2548 ServiceEntry != &ServiceListHead;
2549 ServiceEntry = ServiceEntry->Flink)
2550 {
2551 CurrentService = CONTAINING_RECORD(ServiceEntry,
2552 SERVICE,
2553 ServiceListEntry);
2554
2555 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2556 continue;
2557
2558 dwState = SERVICE_ACTIVE;
2559 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2560 dwState = SERVICE_INACTIVE;
2561
2562 if ((dwState & dwServiceState) == 0)
2563 continue;
2564
2565 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2566 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2567 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2568
2569 if (dwRequiredSize + dwSize > dwBufSize)
2570 {
2571 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2572 break;
2573 }
2574
2575 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2576 dwRequiredSize += dwSize;
2577 dwServiceCount++;
2578 dwLastResumeCount = CurrentService->dwResumeCount;
2579 }
2580
2581 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2582 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2583
2584 for (;
2585 ServiceEntry != &ServiceListHead;
2586 ServiceEntry = ServiceEntry->Flink)
2587 {
2588 CurrentService = CONTAINING_RECORD(ServiceEntry,
2589 SERVICE,
2590 ServiceListEntry);
2591
2592 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2593 continue;
2594
2595 dwState = SERVICE_ACTIVE;
2596 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2597 dwState = SERVICE_INACTIVE;
2598
2599 if ((dwState & dwServiceState) == 0)
2600 continue;
2601
2602 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2603 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2604 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2605
2606 dwError = ERROR_MORE_DATA;
2607 }
2608
2609 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2610
2611 if (lpResumeHandle)
2612 *lpResumeHandle = dwLastResumeCount;
2613
2614 *lpServicesReturned = dwServiceCount;
2615 *pcbBytesNeeded = dwRequiredSize;
2616
2617 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2618 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2619 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2620
2621 dwRequiredSize = 0;
2622 for (ServiceEntry = &lpService->ServiceListEntry;
2623 ServiceEntry != &ServiceListHead;
2624 ServiceEntry = ServiceEntry->Flink)
2625 {
2626 CurrentService = CONTAINING_RECORD(ServiceEntry,
2627 SERVICE,
2628 ServiceListEntry);
2629
2630 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2631 continue;
2632
2633 dwState = SERVICE_ACTIVE;
2634 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2635 dwState = SERVICE_INACTIVE;
2636
2637 if ((dwState & dwServiceState) == 0)
2638 continue;
2639
2640 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2641 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2642 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2643
2644 if (dwRequiredSize + dwSize > dwBufSize)
2645 break;
2646
2647 /* Copy the service name */
2648 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2649 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2650 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2651
2652 /* Copy the display name */
2653 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2654 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2655 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2656
2657 /* Copy the status information */
2658 memcpy(&lpStatusPtr->ServiceStatus,
2659 &CurrentService->Status,
2660 sizeof(SERVICE_STATUS));
2661
2662 lpStatusPtr++;
2663 dwRequiredSize += dwSize;
2664 }
2665
2666 if (dwError == 0)
2667 {
2668 *pcbBytesNeeded = 0;
2669 if (lpResumeHandle) *lpResumeHandle = 0;
2670 }
2671
2672 Done:;
2673 /* Unlock the service database */
2674 ScmUnlockDatabase();
2675
2676 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2677
2678 return dwError;
2679 }
2680
2681
2682 /* Function 15 */
2683 DWORD ROpenSCManagerW(
2684 LPWSTR lpMachineName,
2685 LPWSTR lpDatabaseName,
2686 DWORD dwDesiredAccess,
2687 LPSC_RPC_HANDLE lpScHandle)
2688 {
2689 DWORD dwError;
2690 SC_HANDLE hHandle;
2691
2692 DPRINT("ROpenSCManagerW() called\n");
2693 DPRINT("lpMachineName = %p\n", lpMachineName);
2694 DPRINT("lpMachineName: %S\n", lpMachineName);
2695 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2696 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2697 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2698
2699 if (ScmShutdown)
2700 return ERROR_SHUTDOWN_IN_PROGRESS;
2701
2702 if (!lpScHandle)
2703 return ERROR_INVALID_PARAMETER;
2704
2705 dwError = ScmCreateManagerHandle(lpDatabaseName,
2706 &hHandle);
2707 if (dwError != ERROR_SUCCESS)
2708 {
2709 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2710 return dwError;
2711 }
2712
2713 /* Check the desired access */
2714 dwError = ScmCheckAccess(hHandle,
2715 dwDesiredAccess | SC_MANAGER_CONNECT);
2716 if (dwError != ERROR_SUCCESS)
2717 {
2718 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2719 HeapFree(GetProcessHeap(), 0, hHandle);
2720 return dwError;
2721 }
2722
2723 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2724 DPRINT("*hScm = %p\n", *lpScHandle);
2725
2726 DPRINT("ROpenSCManagerW() done\n");
2727
2728 return ERROR_SUCCESS;
2729 }
2730
2731
2732 /* Function 16 */
2733 DWORD ROpenServiceW(
2734 SC_RPC_HANDLE hSCManager,
2735 LPWSTR lpServiceName,
2736 DWORD dwDesiredAccess,
2737 LPSC_RPC_HANDLE lpServiceHandle)
2738 {
2739 PSERVICE lpService;
2740 PMANAGER_HANDLE hManager;
2741 SC_HANDLE hHandle;
2742 DWORD dwError = ERROR_SUCCESS;
2743
2744 DPRINT("ROpenServiceW() called\n");
2745 DPRINT("hSCManager = %p\n", hSCManager);
2746 DPRINT("lpServiceName = %p\n", lpServiceName);
2747 DPRINT("lpServiceName: %S\n", lpServiceName);
2748 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2749
2750 if (ScmShutdown)
2751 return ERROR_SHUTDOWN_IN_PROGRESS;
2752
2753 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2754 if (hManager == NULL)
2755 {
2756 DPRINT1("Invalid service manager handle!\n");
2757 return ERROR_INVALID_HANDLE;
2758 }
2759
2760 if (!lpServiceHandle)
2761 return ERROR_INVALID_PARAMETER;
2762
2763 if (!lpServiceName)
2764 return ERROR_INVALID_ADDRESS;
2765
2766 /* Lock the service database exclusive */
2767 ScmLockDatabaseExclusive();
2768
2769 /* Get service database entry */
2770 lpService = ScmGetServiceEntryByName(lpServiceName);
2771 if (lpService == NULL)
2772 {
2773 DPRINT("Could not find a service!\n");
2774 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2775 goto Done;
2776 }
2777
2778 /* Create a service handle */
2779 dwError = ScmCreateServiceHandle(lpService,
2780 &hHandle);
2781 if (dwError != ERROR_SUCCESS)
2782 {
2783 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2784 goto Done;
2785 }
2786
2787 /* Check the desired access */
2788 dwError = ScmCheckAccess(hHandle,
2789 dwDesiredAccess);
2790 if (dwError != ERROR_SUCCESS)
2791 {
2792 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2793 HeapFree(GetProcessHeap(), 0, hHandle);
2794 goto Done;
2795 }
2796
2797 lpService->dwRefCount++;
2798 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2799
2800 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2801 DPRINT("*hService = %p\n", *lpServiceHandle);
2802
2803 Done:;
2804 /* Unlock the service database */
2805 ScmUnlockDatabase();
2806
2807 DPRINT("ROpenServiceW() done\n");
2808
2809 return dwError;
2810 }
2811
2812
2813 /* Function 17 */
2814 DWORD RQueryServiceConfigW(
2815 SC_RPC_HANDLE hService,
2816 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2817 DWORD cbBufSize,
2818 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2819 {
2820 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2821 DWORD dwError = ERROR_SUCCESS;
2822 PSERVICE_HANDLE hSvc;
2823 PSERVICE lpService = NULL;
2824 HKEY hServiceKey = NULL;
2825 LPWSTR lpImagePath = NULL;
2826 LPWSTR lpServiceStartName = NULL;
2827 LPWSTR lpDependencies = NULL;
2828 DWORD dwDependenciesLength = 0;
2829 DWORD dwRequiredSize;
2830 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2831 WCHAR lpEmptyString[] = {0,0};
2832 LPWSTR lpStr;
2833
2834 DPRINT("RQueryServiceConfigW() called\n");
2835
2836 if (ScmShutdown)
2837 return ERROR_SHUTDOWN_IN_PROGRESS;
2838
2839 hSvc = ScmGetServiceFromHandle(hService);
2840 if (hSvc == NULL)
2841 {
2842 DPRINT1("Invalid service handle!\n");
2843 return ERROR_INVALID_HANDLE;
2844 }
2845
2846 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2847 SERVICE_QUERY_CONFIG))
2848 {
2849 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2850 return ERROR_ACCESS_DENIED;
2851 }
2852
2853 lpService = hSvc->ServiceEntry;
2854 if (lpService == NULL)
2855 {
2856 DPRINT("lpService == NULL!\n");
2857 return ERROR_INVALID_HANDLE;
2858 }
2859
2860 /* Lock the service database shared */
2861 ScmLockDatabaseShared();
2862
2863 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2864 KEY_READ,
2865 &hServiceKey);
2866 if (dwError != ERROR_SUCCESS)
2867 goto Done;
2868
2869 /* Read the image path */
2870 dwError = ScmReadString(hServiceKey,
2871 L"ImagePath",
2872 &lpImagePath);
2873 if (dwError != ERROR_SUCCESS)
2874 goto Done;
2875
2876 /* Read the service start name */
2877 ScmReadString(hServiceKey,
2878 L"ObjectName",
2879 &lpServiceStartName);
2880
2881 /* Read the dependencies */
2882 ScmReadDependencies(hServiceKey,
2883 &lpDependencies,
2884 &dwDependenciesLength);
2885
2886 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2887
2888 if (lpImagePath != NULL)
2889 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2890 else
2891 dwRequiredSize += 2 * sizeof(WCHAR);
2892
2893 if (lpService->lpGroup != NULL)
2894 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2895 else
2896 dwRequiredSize += 2 * sizeof(WCHAR);
2897
2898 if (lpDependencies != NULL)
2899 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2900 else
2901 dwRequiredSize += 2 * sizeof(WCHAR);
2902
2903 if (lpServiceStartName != NULL)
2904 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2905 else
2906 dwRequiredSize += 2 * sizeof(WCHAR);
2907
2908 if (lpService->lpDisplayName != NULL)
2909 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2910 else
2911 dwRequiredSize += 2 * sizeof(WCHAR);
2912
2913 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2914 {
2915 dwError = ERROR_INSUFFICIENT_BUFFER;
2916 }
2917 else
2918 {
2919 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2920 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2921 lpConfig->dwStartType = lpService->dwStartType;
2922 lpConfig->dwErrorControl = lpService->dwErrorControl;
2923 lpConfig->dwTagId = lpService->dwTag;
2924
2925 lpStr = (LPWSTR)(lpConfig + 1);
2926
2927 /* Append the image path */
2928 if (lpImagePath != NULL)
2929 {
2930 wcscpy(lpStr, lpImagePath);
2931 }
2932 else
2933 {
2934 wcscpy(lpStr, lpEmptyString);
2935 }
2936
2937 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2938 lpStr += (wcslen(lpStr) + 1);
2939
2940 /* Append the group name */
2941 if (lpService->lpGroup != NULL)
2942 {
2943 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2944 }
2945 else
2946 {
2947 wcscpy(lpStr, lpEmptyString);
2948 }
2949
2950 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2951 lpStr += (wcslen(lpStr) + 1);
2952
2953 /* Append Dependencies */
2954 if (lpDependencies != NULL)
2955 {
2956 memcpy(lpStr,
2957 lpDependencies,
2958 dwDependenciesLength * sizeof(WCHAR));
2959 }
2960 else
2961 {
2962 wcscpy(lpStr, lpEmptyString);
2963 }
2964
2965 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2966 if (lpDependencies != NULL)
2967 lpStr += dwDependenciesLength * sizeof(WCHAR);
2968 else
2969 lpStr += (wcslen(lpStr) + 1);
2970
2971 /* Append the service start name */
2972 if (lpServiceStartName != NULL)
2973 {
2974 wcscpy(lpStr, lpServiceStartName);
2975 }
2976 else
2977 {
2978 wcscpy(lpStr, lpEmptyString);
2979 }
2980
2981 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2982 lpStr += (wcslen(lpStr) + 1);
2983
2984 /* Append the display name */
2985 if (lpService->lpDisplayName != NULL)
2986 {
2987 wcscpy(lpStr, lpService->lpDisplayName);
2988 }
2989 else
2990 {
2991 wcscpy(lpStr, lpEmptyString);
2992 }
2993
2994 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2995 }
2996
2997 if (pcbBytesNeeded != NULL)
2998 *pcbBytesNeeded = dwRequiredSize;
2999
3000 Done:;
3001 /* Unlock the service database */
3002 ScmUnlockDatabase();
3003
3004 if (lpImagePath != NULL)
3005 HeapFree(GetProcessHeap(), 0, lpImagePath);
3006
3007 if (lpServiceStartName != NULL)
3008 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3009
3010 if (lpDependencies != NULL)
3011 HeapFree(GetProcessHeap(), 0, lpDependencies);
3012
3013 if (hServiceKey != NULL)
3014 RegCloseKey(hServiceKey);
3015
3016 DPRINT("RQueryServiceConfigW() done\n");
3017
3018 return dwError;
3019 }
3020
3021
3022 /* Function 18 */
3023 DWORD RQueryServiceLockStatusW(
3024 SC_RPC_HANDLE hSCManager,
3025 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3026 DWORD cbBufSize,
3027 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3028 {
3029 UNIMPLEMENTED;
3030 return ERROR_CALL_NOT_IMPLEMENTED;
3031 }
3032
3033
3034 /* Function 19 */
3035 DWORD RStartServiceW(
3036 SC_RPC_HANDLE hService,
3037 DWORD argc,
3038 LPSTRING_PTRSW argv)
3039 {
3040 DWORD dwError = ERROR_SUCCESS;
3041 PSERVICE_HANDLE hSvc;
3042 PSERVICE lpService = NULL;
3043 DWORD i;
3044
3045 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3046 DPRINT(" argc: %lu\n", argc);
3047 if (argv != NULL)
3048 {
3049 for (i = 0; i < argc; i++)
3050 {
3051 DPRINT(" argv[%lu]: %S\n", i, argv[i]);
3052 }
3053 }
3054
3055 if (ScmShutdown)
3056 return ERROR_SHUTDOWN_IN_PROGRESS;
3057
3058 hSvc = ScmGetServiceFromHandle(hService);
3059 if (hSvc == NULL)
3060 {
3061 DPRINT1("Invalid service handle!\n");
3062 return ERROR_INVALID_HANDLE;
3063 }
3064
3065 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3066 SERVICE_START))
3067 {
3068 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3069 return ERROR_ACCESS_DENIED;
3070 }
3071
3072 lpService = hSvc->ServiceEntry;
3073 if (lpService == NULL)
3074 {
3075 DPRINT("lpService == NULL!\n");
3076 return ERROR_INVALID_HANDLE;
3077 }
3078
3079 if (lpService->dwStartType == SERVICE_DISABLED)
3080 return ERROR_SERVICE_DISABLED;
3081
3082 if (lpService->bDeleted)
3083 return ERROR_SERVICE_MARKED_FOR_DELETE;
3084
3085 /* Start the service */
3086 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3087
3088 return dwError;
3089 }
3090
3091
3092 /* Function 20 */
3093 DWORD RGetServiceDisplayNameW(
3094 SC_RPC_HANDLE hSCManager,
3095 LPCWSTR lpServiceName,
3096 LPWSTR lpDisplayName,
3097 DWORD *lpcchBuffer)
3098 {
3099 // PMANAGER_HANDLE hManager;
3100 PSERVICE lpService;
3101 DWORD dwLength;
3102 DWORD dwError;
3103
3104 DPRINT("RGetServiceDisplayNameW() called\n");
3105 DPRINT("hSCManager = %p\n", hSCManager);
3106 DPRINT("lpServiceName: %S\n", lpServiceName);
3107 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3108 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3109
3110 // hManager = (PMANAGER_HANDLE)hSCManager;
3111 // if (hManager->Handle.Tag != MANAGER_TAG)
3112 // {
3113 // DPRINT("Invalid manager handle!\n");
3114 // return ERROR_INVALID_HANDLE;
3115 // }
3116
3117 /* Get service database entry */
3118 lpService = ScmGetServiceEntryByName(lpServiceName);
3119 if (lpService == NULL)
3120 {
3121 DPRINT("Could not find a service!\n");
3122
3123 /* If the service could not be found and lpcchBuffer is less than 2, windows
3124 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3125 if (*lpcchBuffer < 2)
3126 {
3127 *lpcchBuffer = 2;
3128 if (lpDisplayName != NULL)
3129 {
3130 *lpDisplayName = '\0';
3131 }
3132 }
3133
3134 return ERROR_SERVICE_DOES_NOT_EXIST;
3135 }
3136
3137 if (!lpService->lpDisplayName)
3138 {
3139 dwLength = wcslen(lpService->lpServiceName);
3140
3141 if (lpDisplayName != NULL &&
3142 *lpcchBuffer > dwLength)
3143 {
3144 wcscpy(lpDisplayName, lpService->lpServiceName);
3145 }
3146 }
3147 else
3148 {
3149 dwLength = wcslen(lpService->lpDisplayName);
3150
3151 if (lpDisplayName != NULL &&
3152 *lpcchBuffer > dwLength)
3153 {
3154 wcscpy(lpDisplayName, lpService->lpDisplayName);
3155 }
3156 }
3157
3158 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3159
3160 *lpcchBuffer = dwLength;
3161
3162 return dwError;
3163 }
3164
3165
3166 /* Function 21 */
3167 DWORD RGetServiceKeyNameW(
3168 SC_RPC_HANDLE hSCManager,
3169 LPCWSTR lpDisplayName,
3170 LPWSTR lpServiceName,
3171 DWORD *lpcchBuffer)
3172 {
3173 // PMANAGER_HANDLE hManager;
3174 PSERVICE lpService;
3175 DWORD dwLength;
3176 DWORD dwError;
3177
3178 DPRINT("RGetServiceKeyNameW() called\n");
3179 DPRINT("hSCManager = %p\n", hSCManager);
3180 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3181 DPRINT("lpServiceName: %p\n", lpServiceName);
3182 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3183
3184 // hManager = (PMANAGER_HANDLE)hSCManager;
3185 // if (hManager->Handle.Tag != MANAGER_TAG)
3186 // {
3187 // DPRINT("Invalid manager handle!\n");
3188 // return ERROR_INVALID_HANDLE;
3189 // }
3190
3191 /* Get service database entry */
3192 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3193 if (lpService == NULL)
3194 {
3195 DPRINT("Could not find a service!\n");
3196
3197 /* If the service could not be found and lpcchBuffer is less than 2, windows
3198 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3199 if (*lpcchBuffer < 2)
3200 {
3201 *lpcchBuffer = 2;
3202 if (lpServiceName != NULL)
3203 {
3204 *lpServiceName = '\0';
3205 }
3206 }
3207
3208 return ERROR_SERVICE_DOES_NOT_EXIST;
3209 }
3210
3211 dwLength = wcslen(lpService->lpServiceName);
3212
3213 if (lpServiceName != NULL &&
3214 *lpcchBuffer > dwLength)
3215 {
3216 wcscpy(lpServiceName, lpService->lpServiceName);
3217 *lpcchBuffer = dwLength;
3218 return ERROR_SUCCESS;
3219 }
3220
3221 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3222
3223 *lpcchBuffer = dwLength;
3224
3225 return dwError;
3226 }
3227
3228
3229 /* Function 22 */
3230 DWORD RI_ScSetServiceBitsA(
3231 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3232 DWORD dwServiceBits,
3233 int bSetBitsOn,
3234 int bUpdateImmediately,
3235 char *lpString)
3236 {
3237 UNIMPLEMENTED;
3238 return ERROR_CALL_NOT_IMPLEMENTED;
3239 }
3240
3241
3242 /* Function 23 */
3243 DWORD RChangeServiceConfigA(
3244 SC_RPC_HANDLE hService,
3245 DWORD dwServiceType,
3246 DWORD dwStartType,
3247 DWORD dwErrorControl,
3248 LPSTR lpBinaryPathName,
3249 LPSTR lpLoadOrderGroup,
3250 LPDWORD lpdwTagId,
3251 LPSTR lpDependencies,
3252 DWORD dwDependSize,
3253 LPSTR lpServiceStartName,
3254 LPBYTE lpPassword,
3255 DWORD dwPwSize,
3256 LPSTR lpDisplayName)
3257 {
3258 DWORD dwError = ERROR_SUCCESS;
3259 PSERVICE_HANDLE hSvc;
3260 PSERVICE lpService = NULL;
3261 HKEY hServiceKey = NULL;
3262 LPWSTR lpDisplayNameW = NULL;
3263 LPWSTR lpBinaryPathNameW = NULL;
3264 LPWSTR lpCanonicalImagePathW = NULL;
3265 LPWSTR lpLoadOrderGroupW = NULL;
3266 LPWSTR lpDependenciesW = NULL;
3267 // LPWSTR lpPasswordW = NULL;
3268
3269 DPRINT("RChangeServiceConfigA() called\n");
3270 DPRINT("dwServiceType = %lu\n", dwServiceType);
3271 DPRINT("dwStartType = %lu\n", dwStartType);
3272 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3273 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3274 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3275 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3276
3277 if (ScmShutdown)
3278 return ERROR_SHUTDOWN_IN_PROGRESS;
3279
3280 hSvc = ScmGetServiceFromHandle(hService);
3281 if (hSvc == NULL)
3282 {
3283 DPRINT1("Invalid service handle!\n");
3284 return ERROR_INVALID_HANDLE;
3285 }
3286
3287 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3288 SERVICE_CHANGE_CONFIG))
3289 {
3290 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3291 return ERROR_ACCESS_DENIED;
3292 }
3293
3294 lpService = hSvc->ServiceEntry;
3295 if (lpService == NULL)
3296 {
3297 DPRINT("lpService == NULL!\n");
3298 return ERROR_INVALID_HANDLE;
3299 }
3300
3301 /* Lock the service database exclusively */
3302 ScmLockDatabaseExclusive();
3303
3304 if (lpService->bDeleted)
3305 {
3306 DPRINT("The service has already been marked for delete!\n");
3307 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
3308 goto done;
3309 }
3310
3311 /* Open the service key */
3312 dwError = ScmOpenServiceKey(lpService->szServiceName,
3313 KEY_SET_VALUE,
3314 &hServiceKey);
3315 if (dwError != ERROR_SUCCESS)
3316 goto done;
3317
3318 /* Write service data to the registry */
3319
3320 if (lpDisplayName != NULL && *lpDisplayName != 0)
3321 {
3322 /* Set the display name */
3323 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3324 0,
3325 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3326 if (lpDisplayNameW == NULL)
3327 {
3328 dwError = ERROR_NOT_ENOUGH_MEMORY;
3329 goto done;
3330 }
3331
3332 MultiByteToWideChar(CP_ACP,
3333 0,
3334 lpDisplayName,
3335 -1,
3336 lpDisplayNameW,
3337 strlen(lpDisplayName) + 1);
3338
3339 RegSetValueExW(hServiceKey,
3340 L"DisplayName",
3341 0,
3342 REG_SZ,
3343 (LPBYTE)lpDisplayNameW,
3344 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
3345
3346 /* Update lpService->lpDisplayName */
3347 if (lpService->lpDisplayName)
3348 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3349
3350 lpService->lpDisplayName = lpDisplayNameW;
3351 }
3352
3353 if (dwServiceType != SERVICE_NO_CHANGE)
3354 {
3355 /* Set the service type */
3356 dwError = RegSetValueExW(hServiceKey,
3357 L"Type",
3358 0,
3359 REG_DWORD,
3360 (LPBYTE)&dwServiceType,
3361 sizeof(DWORD));
3362 if (dwError != ERROR_SUCCESS)
3363 goto done;
3364
3365 lpService->Status.dwServiceType = dwServiceType;
3366 }
3367
3368 if (dwStartType != SERVICE_NO_CHANGE)
3369 {
3370 /* Set the start value */
3371 dwError = RegSetValueExW(hServiceKey,
3372 L"Start",
3373 0,
3374 REG_DWORD,
3375 (LPBYTE)&dwStartType,
3376 sizeof(DWORD));
3377 if (dwError != ERROR_SUCCESS)
3378 goto done;
3379
3380 lpService->dwStartType = dwStartType;
3381 }
3382
3383 if (dwErrorControl != SERVICE_NO_CHANGE)
3384 {
3385 /* Set the error control value */
3386 dwError = RegSetValueExW(hServiceKey,
3387 L"ErrorControl",
3388 0,
3389 REG_DWORD,
3390 (LPBYTE)&dwErrorControl,
3391 sizeof(DWORD));
3392 if (dwError != ERROR_SUCCESS)
3393 goto done;
3394
3395 lpService->dwErrorControl = dwErrorControl;
3396 }
3397
3398 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3399 {
3400 /* Set the image path */
3401 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
3402 0,
3403 (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
3404 if (lpBinaryPathNameW == NULL)
3405 {
3406 dwError = ERROR_NOT_ENOUGH_MEMORY;
3407 goto done;
3408 }
3409
3410 MultiByteToWideChar(CP_ACP,
3411 0,
3412 lpBinaryPathName,
3413 -1,
3414 lpBinaryPathNameW,
3415 strlen(lpBinaryPathName) + 1);
3416
3417 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
3418 {
3419 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
3420 lpBinaryPathNameW,
3421 &lpCanonicalImagePathW);
3422
3423 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3424
3425 if (dwError != ERROR_SUCCESS)
3426 goto done;
3427
3428 lpBinaryPathNameW = lpCanonicalImagePathW;
3429 }
3430
3431 dwError = RegSetValueExW(hServiceKey,
3432 L"ImagePath",
3433 0,
3434 REG_EXPAND_SZ,
3435 (LPBYTE)lpBinaryPathNameW,
3436 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
3437
3438 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3439
3440 if (dwError != ERROR_SUCCESS)
3441 goto done;
3442 }
3443
3444 /* Set the group name */
3445 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3446 {
3447 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3448 0,
3449 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3450 if (lpLoadOrderGroupW == NULL)
3451 {
3452 dwError = ERROR_NOT_ENOUGH_MEMORY;
3453 goto done;
3454 }
3455
3456 MultiByteToWideChar(CP_ACP,
3457 0,
3458 lpLoadOrderGroup,
3459 -1,
3460 lpLoadOrderGroupW,
3461 strlen(lpLoadOrderGroup) + 1);
3462
3463 dwError = RegSetValueExW(hServiceKey,
3464 L"Group",
3465 0,
3466 REG_SZ,
3467 (LPBYTE)lpLoadOrderGroupW,
3468 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
3469 if (dwError != ERROR_SUCCESS)
3470 {
3471 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3472 goto done;
3473 }
3474
3475 dwError = ScmSetServiceGroup(lpService,
3476 lpLoadOrderGroupW);
3477
3478 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3479
3480 if (dwError != ERROR_SUCCESS)
3481 goto done;
3482 }
3483
3484 if (lpdwTagId != NULL)
3485 {
3486 dwError = ScmAssignNewTag(lpService);
3487 if (dwError != ERROR_SUCCESS)
3488 goto done;
3489
3490 dwError = RegSetValueExW(hServiceKey,
3491 L"Tag",
3492 0,
3493 REG_DWORD,
3494 (LPBYTE)&lpService->dwTag,
3495 sizeof(DWORD));
3496 if (dwError != ERROR_SUCCESS)
3497 goto done;
3498
3499 *lpdwTagId = lpService->dwTag;
3500 }
3501
3502 /* Write dependencies */
3503 if (lpDependencies != NULL && *lpDependencies != 0)
3504 {
3505 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3506 0,
3507 (strlen(lpDependencies) + 1) * sizeof(WCHAR));
3508 if (lpDependenciesW == NULL)
3509 {
3510 dwError = ERROR_NOT_ENOUGH_MEMORY;
3511 goto done;
3512 }
3513
3514 MultiByteToWideChar(CP_ACP,
3515 0,
3516 lpDependencies,
3517 dwDependSize,
3518 lpDependenciesW,
3519 strlen(lpDependencies) + 1);
3520
3521 dwError = ScmWriteDependencies(hServiceKey,
3522 (LPWSTR)lpDependenciesW,
3523 dwDependSize);
3524
3525 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3526 }
3527
3528 if (lpPassword != NULL)
3529 {
3530 /* FIXME: Write password */
3531 }
3532
3533 done:
3534 /* Unlock the service database */
3535 ScmUnlockDatabase();
3536
3537 if (hServiceKey != NULL)
3538 RegCloseKey(hServiceKey);
3539
3540 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3541
3542 return dwError;
3543 }
3544
3545
3546 /* Function 24 */
3547 DWORD RCreateServiceA(
3548 SC_RPC_HANDLE hSCManager,
3549 LPSTR lpServiceName,
3550 LPSTR lpDisplayName,
3551 DWORD dwDesiredAccess,
3552 DWORD dwServiceType,
3553 DWORD dwStartType,
3554 DWORD dwErrorControl,
3555 LPSTR lpBinaryPathName,
3556 LPSTR lpLoadOrderGroup,
3557 LPDWORD lpdwTagId,
3558 LPBYTE lpDependencies,
3559 DWORD dwDependSize,
3560 LPSTR lpServiceStartName,
3561 LPBYTE lpPassword,
3562 DWORD dwPwSize,
3563 LPSC_RPC_HANDLE lpServiceHandle)
3564 {
3565 DWORD dwError = ERROR_SUCCESS;
3566 LPWSTR lpServiceNameW = NULL;
3567 LPWSTR lpDisplayNameW = NULL;
3568 LPWSTR lpBinaryPathNameW = NULL;
3569 LPWSTR lpLoadOrderGroupW = NULL;
3570 LPWSTR lpDependenciesW = NULL;
3571 LPWSTR lpServiceStartNameW = NULL;
3572 DWORD dwDependenciesLength = 0;
3573 DWORD dwLength;
3574 int len;
3575 LPCSTR lpStr;
3576
3577 if (lpServiceName)
3578 {
3579 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3580 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3581 if (!lpServiceNameW)
3582 {
3583 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3584 goto cleanup;
3585 }
3586 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3587 }
3588
3589 if (lpDisplayName)
3590 {
3591 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3592 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3593 if (!lpDisplayNameW)
3594 {
3595 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3596 goto cleanup;
3597 }
3598 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3599 }
3600
3601 if (lpBinaryPathName)
3602 {
3603 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3604 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3605 if (!lpBinaryPathNameW)
3606 {
3607 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3608 goto cleanup;
3609 }
3610 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3611 }
3612
3613 if (lpLoadOrderGroup)
3614 {
3615 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3616 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3617 if (!lpLoadOrderGroupW)
3618 {
3619 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3620 goto cleanup;
3621 }
3622 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3623 }
3624
3625 if (lpDependencies)
3626 {
3627 lpStr = (LPCSTR)lpDependencies;
3628 while (*lpStr)
3629 {
3630 dwLength = strlen(lpStr) + 1;
3631 dwDependenciesLength += dwLength;
3632 lpStr = lpStr + dwLength;
3633 }
3634 dwDependenciesLength++;
3635
3636 lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR));
3637 if (!lpDependenciesW)
3638 {
3639 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3640 goto cleanup;
3641 }
3642 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3643 }
3644
3645 if (lpServiceStartName)
3646 {
3647 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3648 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3649 if (!lpServiceStartNameW)
3650 {
3651 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3652 goto cleanup;
3653 }
3654 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3655 }
3656
3657 dwError = RCreateServiceW(hSCManager,
3658 lpServiceNameW,
3659 lpDisplayNameW,
3660 dwDesiredAccess,
3661 dwServiceType,
3662 dwStartType,
3663 dwErrorControl,
3664 lpBinaryPathNameW,
3665 lpLoadOrderGroupW,
3666 lpdwTagId,
3667 (LPBYTE)lpDependenciesW,
3668 dwDependenciesLength,
3669 lpServiceStartNameW,
3670 lpPassword,
3671 dwPwSize,
3672 lpServiceHandle);
3673
3674 cleanup:
3675 if (lpServiceNameW !=NULL)
3676 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3677
3678 if (lpDisplayNameW != NULL)
3679 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3680
3681 if (lpBinaryPathNameW != NULL)
3682 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3683
3684 if (lpLoadOrderGroupW != NULL)
3685 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3686
3687 if (lpDependenciesW != NULL)
3688 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3689
3690 if (lpServiceStartNameW != NULL)
3691 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3692
3693 return dwError;
3694 }
3695
3696
3697 /* Function 25 */
3698 DWORD REnumDependentServicesA(
3699 SC_RPC_HANDLE hService,
3700 DWORD dwServiceState,
3701 LPBYTE lpServices,
3702 DWORD cbBufSize,
3703 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3704 LPBOUNDED_DWORD_256K lpServicesReturned)
3705 {
3706 DWORD dwError = ERROR_SUCCESS;
3707 DWORD dwServicesReturned = 0;
3708 DWORD dwServiceCount;
3709 HKEY hServicesKey = NULL;
3710 PSERVICE_HANDLE hSvc;
3711 PSERVICE lpService = NULL;
3712 PSERVICE *lpServicesArray = NULL;
3713 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3714 LPSTR lpStr;
3715
3716 *pcbBytesNeeded = 0;
3717 *lpServicesReturned = 0;
3718
3719 DPRINT("REnumDependentServicesA() called\n");
3720
3721 hSvc = ScmGetServiceFromHandle(hService);
3722 if (hSvc == NULL)
3723 {
3724 DPRINT1("Invalid service handle!\n");
3725 return ERROR_INVALID_HANDLE;
3726 }
3727
3728 lpService = hSvc->ServiceEntry;
3729
3730 /* Check access rights */
3731 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3732 SC_MANAGER_ENUMERATE_SERVICE))
3733 {
3734 DPRINT("Insufficient access rights! 0x%lx\n",
3735 hSvc->Handle.DesiredAccess);
3736 return ERROR_ACCESS_DENIED;
3737 }
3738
3739 /* Open the Services Reg key */
3740 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3741 L"System\\CurrentControlSet\\Services",
3742 0,
3743 KEY_READ,
3744 &hServicesKey);
3745
3746 if (dwError != ERROR_SUCCESS)
3747 return dwError;
3748
3749 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3750 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3751 are the same for both. Verified in WINXP. */
3752
3753 /* First determine the bytes needed and get the number of dependent services*/
3754 dwError = Int_EnumDependentServicesW(hServicesKey,
3755 lpService,
3756 dwServiceState,
3757 NULL,
3758 pcbBytesNeeded,
3759 &dwServicesReturned);
3760 if (dwError != ERROR_SUCCESS)
3761 goto Done;
3762
3763 /* If buffer size is less than the bytes needed or pointer is null*/
3764 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3765 {
3766 dwError = ERROR_MORE_DATA;
3767 goto Done;
3768 }
3769
3770 /* Allocate memory for array of service pointers */
3771 lpServicesArray = HeapAlloc(GetProcessHeap(),
3772 0,
3773 (dwServicesReturned + 1) * sizeof(PSERVICE));
3774 if (!lpServicesArray)
3775 {
3776 DPRINT("Could not allocate a buffer!!\n");
3777 dwError = ERROR_NOT_ENOUGH_MEMORY;
3778 goto Done;
3779 }
3780
3781 dwServicesReturned = 0;
3782 *pcbBytesNeeded = 0;
3783
3784 dwError = Int_EnumDependentServicesW(hServicesKey,
3785 lpService,
3786 dwServiceState,
3787 lpServicesArray,
3788 pcbBytesNeeded,
3789 &dwServicesReturned);
3790 if (dwError != ERROR_SUCCESS)
3791 {
3792 goto Done;
3793 }
3794
3795 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3796 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3797
3798 /* Copy EnumDepenedentService to Buffer */
3799 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3800 {
3801 lpService = lpServicesArray[dwServiceCount];
3802
3803 /* Copy the status info */
3804 memcpy(&lpServicesPtr->ServiceStatus,
3805 &lpService->Status,
3806 sizeof(SERVICE_STATUS));
3807
3808 /* Copy display name */
3809 WideCharToMultiByte(CP_ACP,
3810 0,
3811 lpService->lpDisplayName,
3812 -1,
3813 lpStr,
3814 wcslen(lpService->lpDisplayName),
3815 0,
3816 0);
3817 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3818 lpStr += strlen(lpStr) + 1;
3819
3820 /* Copy service name */
3821 WideCharToMultiByte(CP_ACP,
3822 0,
3823 lpService->lpServiceName,
3824 -1,
3825 lpStr,
3826 wcslen(lpService->lpServiceName),
3827 0,
3828 0);
3829 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3830 lpStr += strlen(lpStr) + 1;
3831
3832 lpServicesPtr ++;
3833 }
3834
3835 *lpServicesReturned = dwServicesReturned;
3836
3837 Done:
3838 if (lpServicesArray)
3839 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3840
3841 RegCloseKey(hServicesKey);
3842
3843 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3844
3845 return dwError;
3846 }
3847
3848
3849 /* Function 26 */
3850 DWORD REnumServicesStatusA(
3851 SC_RPC_HANDLE hSCManager,
3852 DWORD dwServiceType,
3853 DWORD dwServiceState,
3854 LPBYTE lpBuffer,
3855 DWORD dwBufSize,
3856 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3857 LPBOUNDED_DWORD_256K lpServicesReturned,
3858 LPBOUNDED_DWORD_256K lpResumeHandle)
3859 {
3860 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3861 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3862 LPWSTR lpStringPtrW;
3863 LPSTR lpStringPtrA;
3864 DWORD dwError;
3865 DWORD dwServiceCount;
3866
3867 DPRINT("REnumServicesStatusA() called\n");
3868
3869 if ((dwBufSize > 0) && (lpBuffer))
3870 {
3871 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3872 if (!lpStatusPtrW)
3873 {
3874 DPRINT("Failed to allocate buffer!\n");
3875 return ERROR_NOT_ENOUGH_MEMORY;
3876 }
3877 }
3878
3879 dwError = REnumServicesStatusW(hSCManager,
3880 dwServiceType,
3881 dwServiceState,
3882 (LPBYTE)lpStatusPtrW,
3883 dwBufSize,
3884 pcbBytesNeeded,
3885 lpServicesReturned,
3886 lpResumeHandle);
3887
3888 /* if no services were returned then we are Done */
3889 if (*lpServicesReturned == 0)
3890 goto Done;
3891
3892 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3893 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3894 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3895 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3896 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3897
3898 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3899 {
3900 /* Copy the service name */
3901 WideCharToMultiByte(CP_ACP,
3902 0,
3903 lpStringPtrW,
3904 -1,
3905 lpStringPtrA,
3906 wcslen(lpStringPtrW),
3907 0,
3908 0);
3909
3910 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3911 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3912 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3913
3914 /* Copy the display name */
3915 WideCharToMultiByte(CP_ACP,
3916 0,
3917 lpStringPtrW,
3918 -1,
3919 lpStringPtrA,
3920 wcslen(lpStringPtrW),
3921 0,
3922 0);
3923
3924 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3925 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3926 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3927
3928 /* Copy the status information */
3929 memcpy(&lpStatusPtrA->ServiceStatus,
3930 &lpStatusPtrW->ServiceStatus,
3931 sizeof(SERVICE_STATUS));
3932
3933 lpStatusPtrA++;
3934 }
3935
3936 Done:;
3937 if (lpStatusPtrW)
3938 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3939
3940 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3941
3942 return dwError;
3943 }
3944
3945
3946 /* Function 27 */
3947 DWORD ROpenSCManagerA(
3948 LPSTR lpMachineName,
3949 LPSTR lpDatabaseName,
3950 DWORD dwDesiredAccess,
3951 LPSC_RPC_HANDLE lpScHandle)
3952 {
3953 UNICODE_STRING MachineName;
3954 UNICODE_STRING DatabaseName;
3955 DWORD dwError;
3956
3957 DPRINT("ROpenSCManagerA() called\n");
3958
3959 if (lpMachineName)
3960 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3961 lpMachineName);
3962
3963 if (lpDatabaseName)
3964 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3965 lpDatabaseName);
3966
3967 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
3968 lpDatabaseName ? DatabaseName.Buffer : NULL,
3969 dwDesiredAccess,
3970 lpScHandle);
3971
3972 if (lpMachineName)
3973 RtlFreeUnicodeString(&MachineName);
3974
3975 if (lpDatabaseName)
3976 RtlFreeUnicodeString(&DatabaseName);
3977
3978 return dwError;
3979 }
3980
3981
3982 /* Function 28 */
3983 DWORD ROpenServiceA(
3984 SC_RPC_HANDLE hSCManager,
3985 LPSTR lpServiceName,
3986 DWORD dwDesiredAccess,
3987 LPSC_RPC_HANDLE lpServiceHandle)
3988 {
3989 UNICODE_STRING ServiceName;
3990 DWORD dwError;
3991
3992 DPRINT("ROpenServiceA() called\n");
3993
3994 if (lpServiceName)
3995 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3996 lpServiceName);
3997
3998 dwError = ROpenServiceW(hSCManager,
3999 lpServiceName ? ServiceName.Buffer : NULL,
4000 dwDesiredAccess,
4001 lpServiceHandle);
4002
4003 if (lpServiceName)
4004 RtlFreeUnicodeString(&ServiceName);
4005
4006 return dwError;
4007 }
4008
4009
4010 /* Function 29 */
4011 DWORD RQueryServiceConfigA(
4012 SC_RPC_HANDLE hService,
4013 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
4014 DWORD cbBufSize,
4015 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4016 {
4017 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
4018 DWORD dwError = ERROR_SUCCESS;
4019 PSERVICE_HANDLE hSvc;
4020 PSERVICE lpService = NULL;
4021 HKEY hServiceKey = NULL;
4022 LPWSTR lpImagePath = NULL;
4023 LPWSTR lpServiceStartName = NULL;
4024 LPWSTR lpDependencies = NULL;
4025 DWORD dwDependenciesLength = 0;
4026 DWORD dwRequiredSize;
4027 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
4028 CHAR lpEmptyString[]={0,0};
4029 LPSTR lpStr;
4030
4031 DPRINT("RQueryServiceConfigA() called\n");
4032
4033 if (ScmShutdown)
4034 return ERROR_SHUTDOWN_IN_PROGRESS;
4035
4036 hSvc = ScmGetServiceFromHandle(hService);
4037 if (hSvc == NULL)
4038 {
4039 DPRINT1("Invalid service handle!\n");
4040 return ERROR_INVALID_HANDLE;
4041 }
4042
4043 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4044 SERVICE_QUERY_CONFIG))
4045 {
4046 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4047 return ERROR_ACCESS_DENIED;
4048 }
4049
4050 lpService = hSvc->ServiceEntry;
4051 if (lpService == NULL)
4052 {
4053 DPRINT("lpService == NULL!\n");
4054 return ERROR_INVALID_HANDLE;
4055 }
4056
4057 /* Lock the service database shared */
4058 ScmLockDatabaseShared();
4059
4060 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4061 KEY_READ,
4062 &hServiceKey);
4063 if (dwError != ERROR_SUCCESS)
4064 goto Done;
4065
4066 /* Read the image path */
4067 dwError = ScmReadString(hServiceKey,
4068 L"ImagePath",
4069 &lpImagePath);
4070 if (dwError != ERROR_SUCCESS)
4071 goto Done;
4072
4073 /* Read the service start name */
4074 ScmReadString(hServiceKey,
4075 L"ObjectName",
4076 &lpServiceStartName);
4077
4078 /* Read the dependencies */
4079 ScmReadDependencies(hServiceKey,
4080 &lpDependencies,
4081 &dwDependenciesLength);
4082
4083 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
4084
4085 if (lpImagePath != NULL)
4086 dwRequiredSize += wcslen(lpImagePath) + 1;
4087 else
4088 dwRequiredSize += 2;
4089
4090 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
4091 dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
4092 else
4093 dwRequiredSize += 2;
4094
4095 /* Add Dependencies length */
4096 if (lpDependencies != NULL)
4097 dwRequiredSize += dwDependenciesLength;
4098 else
4099 dwRequiredSize += 2;
4100
4101 if (lpServiceStartName != NULL)
4102 dwRequiredSize += wcslen(lpServiceStartName) + 1;
4103 else
4104 dwRequiredSize += 2;
4105
4106 if (lpService->lpDisplayName != NULL)
4107 dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
4108 else
4109 dwRequiredSize += 2;
4110
4111 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
4112 {
4113 dwError = ERROR_INSUFFICIENT_BUFFER;
4114 }
4115 else
4116 {
4117 lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
4118 lpConfig->dwServiceType = lpService->Status.dwServiceType;
4119 lpConfig->dwStartType = lpService->dwStartType;
4120 lpConfig->dwErrorControl = lpService->dwErrorControl;
4121 lpConfig->dwTagId = lpService->dwTag;
4122
4123 lpStr = (LPSTR)(lpServiceConfig + 1);
4124
4125 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4126 Verified in WINXP*/
4127
4128 if (lpImagePath)
4129 {
4130 WideCharToMultiByte(CP_ACP,
4131 0,
4132 lpImagePath,
4133 -1,
4134 lpStr,
4135 wcslen(lpImagePath) + 1,
4136 0,
4137 0);
4138 }
4139 else
4140 {
4141 strcpy(lpStr, lpEmptyString);
4142 }
4143
4144 lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4145 lpStr += (strlen((LPSTR)lpStr) + 1);
4146
4147 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4148 {
4149 WideCharToMultiByte(CP_ACP,
4150 0,
4151 lpService->lpGroup->lpGroupName,
4152 -1,
4153 lpStr,
4154 wcslen(lpService->lpGroup->lpGroupName) + 1,
4155 0,
4156 0);
4157 }
4158 else
4159 {
4160 strcpy(lpStr, lpEmptyString);
4161 }
4162
4163 lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4164 lpStr += (strlen(lpStr) + 1);
4165
4166 /* Append Dependencies */
4167 if (lpDependencies)
4168 {
4169 WideCharToMultiByte(CP_ACP,
4170 0,
4171 lpDependencies,
4172 dwDependenciesLength,
4173 lpStr,
4174 dwDependenciesLength,
4175 0,
4176 0);
4177 }
4178 else
4179 {
4180 strcpy(lpStr, lpEmptyString);
4181 }
4182
4183 lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4184 if (lpDependencies)
4185 lpStr += dwDependenciesLength;
4186 else
4187 lpStr += (strlen(lpStr) + 1);
4188
4189 if (lpServiceStartName)
4190 {
4191 WideCharToMultiByte(CP_ACP,
4192 0,
4193 lpServiceStartName,
4194 -1,
4195 lpStr,
4196 wcslen(lpServiceStartName) + 1,
4197 0,
4198 0);
4199 }
4200 else
4201 {
4202 strcpy(lpStr, lpEmptyString);
4203 }
4204
4205 lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4206 lpStr += (strlen(lpStr) + 1);
4207
4208 if (lpService->lpDisplayName)
4209 {
4210 WideCharToMultiByte(CP_ACP,
4211 0,
4212 lpService->lpDisplayName,
4213 -1,
4214 lpStr,
4215 wcslen(lpService->lpDisplayName) + 1,
4216 0,
4217 0);
4218 }
4219 else
4220 {
4221 strcpy(lpStr, lpEmptyString);
4222 }
4223
4224 lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4225 }
4226
4227 if (pcbBytesNeeded != NULL)
4228 *pcbBytesNeeded = dwRequiredSize;
4229
4230 Done:;
4231 /* Unlock the service database */
4232 ScmUnlockDatabase();
4233
4234 if (lpImagePath != NULL)
4235 HeapFree(GetProcessHeap(), 0, lpImagePath);
4236
4237 if (lpServiceStartName != NULL)
4238 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4239
4240 if (lpDependencies != NULL)
4241 HeapFree(GetProcessHeap(), 0, lpDependencies);
4242
4243 if (hServiceKey != NULL)
4244 RegCloseKey(hServiceKey);
4245
4246 DPRINT("RQueryServiceConfigA() done\n");
4247
4248 return dwError;
4249 }
4250
4251
4252 /* Function 30 */
4253 DWORD RQueryServiceLockStatusA(
4254 SC_RPC_HANDLE hSCManager,
4255 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4256 DWORD cbBufSize,
4257 LPBOUNDED_DWORD_4K pcbBytesNeeded)
4258 {
4259 UNIMPLEMENTED;
4260 return ERROR_CALL_NOT_IMPLEMENTED;
4261 }
4262
4263
4264 /* Function 31 */
4265 DWORD RStartServiceA(
4266 SC_RPC_HANDLE hService,
4267 DWORD argc,
4268 LPSTRING_PTRSA argv)
4269 {
4270 DWORD dwError = ERROR_SUCCESS;
4271 PSERVICE_HANDLE hSvc;
4272 PSERVICE lpService = NULL;
4273 LPWSTR *lpVector = NULL;
4274 DWORD i;
4275 DWORD dwLength;
4276
4277 DPRINT("RStartServiceA() called\n");
4278
4279 if (ScmShutdown)
4280 return ERROR_SHUTDOWN_IN_PROGRESS;
4281
4282 hSvc = ScmGetServiceFromHandle(hService);
4283 if (hSvc == NULL)
4284 {
4285 DPRINT1("Invalid service handle!\n");
4286 return ERROR_INVALID_HANDLE;
4287 }
4288
4289 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4290 SERVICE_START))
4291 {
4292 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4293 return ERROR_ACCESS_DENIED;
4294 }
4295
4296 lpService = hSvc->ServiceEntry;
4297 if (lpService == NULL)
4298 {
4299 DPRINT("lpService == NULL!\n");
4300 return ERROR_INVALID_HANDLE;
4301 }
4302
4303 if (lpService->dwStartType == SERVICE_DISABLED)
4304 return ERROR_SERVICE_DISABLED;
4305
4306 if (lpService->bDeleted)
4307 return ERROR_SERVICE_MARKED_FOR_DELETE;
4308
4309 /* Build a Unicode argument vector */
4310 if (argc > 0)
4311 {
4312 lpVector = HeapAlloc(GetProcessHeap(),
4313 HEAP_ZERO_MEMORY,
4314 argc * sizeof(LPWSTR));
4315 if (lpVector == NULL)
4316 return ERROR_NOT_ENOUGH_MEMORY;
4317
4318 for (i = 0; i < argc; i++)
4319 {
4320 dwLength = MultiByteToWideChar(CP_ACP,
4321 0,
4322 ((LPSTR*)argv)[i],
4323 -1,
4324 NULL,
4325 0);
4326
4327 lpVector[i] = HeapAlloc(GetProcessHeap(),
4328 HEAP_ZERO_MEMORY,
4329 dwLength * sizeof(WCHAR));
4330 if (lpVector[i] == NULL)
4331 {
4332 dwError = ERROR_NOT_ENOUGH_MEMORY;
4333 goto done;
4334 }
4335
4336 MultiByteToWideChar(CP_ACP,
4337 0,
4338 ((LPSTR*)argv)[i],
4339 -1,
4340 lpVector[i],
4341 dwLength);
4342 }
4343 }
4344
4345 /* Start the service */
4346 dwError = ScmStartService(lpService, argc, lpVector);
4347
4348 done:
4349 /* Free the Unicode argument vector */
4350 if (lpVector != NULL)
4351 {
4352 for (i = 0; i < argc; i++)
4353 {
4354 if (lpVector[i] != NULL)
4355 HeapFree(GetProcessHeap(), 0, lpVector[i]);
4356 }
4357 HeapFree(GetProcessHeap(), 0, lpVector);
4358 }
4359
4360 return dwError;
4361 }
4362
4363
4364 /* Function 32 */
4365 DWORD RGetServiceDisplayNameA(
4366 SC_RPC_HANDLE hSCManager,
4367 LPCSTR lpServiceName,
4368 LPSTR lpDisplayName,
4369 LPBOUNDED_DWORD_4K lpcchBuffer)
4370 {
4371 // PMANAGER_HANDLE hManager;
4372 PSERVICE lpService = NULL;
4373 DWORD dwLength;
4374 DWORD dwError;
4375 LPWSTR lpServiceNameW;
4376
4377 DPRINT("RGetServiceDisplayNameA() called\n");
4378 DPRINT("hSCManager = %p\n", hSCManager);
4379 DPRINT("lpServiceName: %s\n", lpServiceName);
4380 DPRINT("lpDisplayName: %p\n", lpDisplayName);
4381 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4382
4383 // hManager = (PMANAGER_HANDLE)hSCManager;
4384 // if (hManager->Handle.Tag != MANAGER_TAG)
4385 // {
4386 // DPRINT("Invalid manager handle!\n");
4387 // return ERROR_INVALID_HANDLE;
4388 // }
4389
4390 if (lpServiceName != NULL)
4391 {
4392 dwLength = strlen(lpServiceName) + 1;
4393 lpServiceNameW = HeapAlloc(GetProcessHeap(),
4394 HEAP_ZERO_MEMORY,
4395 dwLength * sizeof(WCHAR));
4396 if (!lpServiceNameW)
4397 return ERROR_NOT_ENOUGH_MEMORY;
4398
4399 MultiByteToWideChar(CP_ACP,
4400 0,
4401 lpServiceName,
4402 -1,
4403 lpServiceNameW,
4404 dwLength);
4405
4406 lpService = ScmGetServiceEntryByName(lpServiceNameW);
4407
4408 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4409 }
4410
4411 if (lpService == NULL)
4412 {
4413 DPRINT("Could not find a service!\n");
4414
4415 /* If the service could not be found and lpcchBuffer is 0, windows
4416 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4417 if (*lpcchBuffer == 0)
4418 {
4419 *lpcchBuffer = 1;
4420 if (lpDisplayName != NULL)
4421 {
4422 *lpDisplayName = '\0';
4423 }
4424 }
4425 return ERROR_SERVICE_DOES_NOT_EXIST;
4426 }
4427
4428 if (!lpService->lpDisplayName)
4429 {
4430 dwLength = wcslen(lpService->lpServiceName);
4431 if (lpDisplayName != NULL &&
4432 *lpcchBuffer > dwLength)
4433 {
4434 WideCharToMultiByte(CP_ACP,
4435 0,
4436 lpService->lpServiceName,
4437 wcslen(lpService->lpServiceName),
4438 lpDisplayName,
4439 dwLength + 1,
4440 NULL,
4441 NULL);
4442 return ERROR_SUCCESS;
4443 }
4444 }
4445 else
4446 {
4447 dwLength = wcslen(lpService->lpDisplayName);
4448 if (lpDisplayName != NULL &&
4449 *lpcchBuffer > dwLength)
4450 {
4451 WideCharToMultiByte(CP_ACP,
4452 0,
4453 lpService->lpDisplayName,
4454 wcslen(lpService->lpDisplayName),
4455 lpDisplayName,
4456 dwLength + 1,
4457 NULL,
4458 NULL);
4459 return ERROR_SUCCESS;
4460 }
4461 }
4462
4463 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4464
4465 *lpcchBuffer = dwLength * 2;
4466
4467 return dwError;
4468 }
4469
4470
4471 /* Function 33 */
4472 DWORD RGetServiceKeyNameA(
4473 SC_RPC_HANDLE hSCManager,
4474 LPCSTR lpDisplayName,
4475 LPSTR lpServiceName,
4476 LPBOUNDED_DWORD_4K lpcchBuffer)
4477 {
4478 PSERVICE lpService;
4479 DWORD dwLength;
4480 DWORD dwError;
4481 LPWSTR lpDisplayNameW;
4482
4483 DPRINT("RGetServiceKeyNameA() called\n");
4484 DPRINT("hSCManager = %p\n", hSCManager);
4485 DPRINT("lpDisplayName: %s\n", lpDisplayName);
4486 DPRINT("lpServiceName: %p\n", lpServiceName);
4487 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4488
4489 dwLength = strlen(lpDisplayName) + 1;
4490 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4491 HEAP_ZERO_MEMORY,
4492 dwLength * sizeof(WCHAR));
4493 if (!lpDisplayNameW)
4494 return ERROR_NOT_ENOUGH_MEMORY;
4495
4496 MultiByteToWideChar(CP_ACP,
4497 0,
4498 lpDisplayName,
4499 -1,
4500 lpDisplayNameW,
4501 dwLength);
4502
4503 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4504
4505 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4506
4507 if (lpService == NULL)
4508 {
4509 DPRINT("Could not find the service!\n");
4510
4511 /* If the service could not be found and lpcchBuffer is 0,
4512 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4513 if (*lpcchBuffer == 0)
4514 {
4515 *lpcchBuffer = 1;
4516 if (lpServiceName != NULL)
4517 {
4518 *lpServiceName = '\0';
4519 }
4520 }
4521
4522 return ERROR_SERVICE_DOES_NOT_EXIST;
4523 }
4524
4525 dwLength = wcslen(lpService->lpServiceName);
4526 if (lpServiceName != NULL &&
4527 *lpcchBuffer > dwLength)
4528 {
4529 WideCharToMultiByte(CP_ACP,
4530 0,
4531 lpService->lpServiceName,
4532 wcslen(lpService->lpServiceName),
4533 lpServiceName,
4534 dwLength + 1,
4535 NULL,
4536 NULL);
4537 return ERROR_SUCCESS;
4538 }
4539
4540 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4541
4542 *lpcchBuffer = dwLength * 2;
4543
4544 return dwError;
4545 }
4546
4547
4548 /* Function 34 */
4549 DWORD RI_ScGetCurrentGroupStateW(
4550 SC_RPC_HANDLE hSCManager,
4551 LPWSTR lpLoadOrderGroup,
4552 LPDWORD lpState)
4553 {
4554 UNIMPLEMENTED;
4555 return ERROR_CALL_NOT_IMPLEMENTED;
4556 }
4557
4558
4559 /* Function 35 */
4560 DWORD REnumServiceGroupW(
4561 SC_RPC_HANDLE hSCManager,
4562 DWORD dwServiceType,
4563 DWORD dwServiceState,
4564 LPBYTE lpBuffer,
4565 DWORD cbBufSize,
4566 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4567 LPBOUNDED_DWORD_256K lpServicesReturned,
4568 LPBOUNDED_DWORD_256K lpResumeIndex,
4569 LPCWSTR pszGroupName)
4570 {
4571 UNIMPLEMENTED;
4572 return ERROR_CALL_NOT_IMPLEMENTED;
4573 }
4574
4575
4576 //
4577 // WARNING: This function is untested
4578 //
4579 /* Function 36 */
4580 DWORD RChangeServiceConfig2A(
4581 SC_RPC_HANDLE hService,
4582 SC_RPC_CONFIG_INFOA Info)
4583 {
4584 SC_RPC_CONFIG_INFOW InfoW;
4585 DWORD dwRet, dwLength;
4586 PVOID ptr = NULL;
4587
4588 DPRINT("RChangeServiceConfig2A() called\n");
4589 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4590
4591 InfoW.dwInfoLevel = Info.dwInfoLevel;
4592
4593 if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4594 {
4595 LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
4596 //LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
4597
4598 //lpServiceDescriptonA = Info.psd;
4599
4600 ///if (lpServiceDescriptonA &&
4601 ///lpServiceDescriptonA->lpDescription)
4602 ///{
4603 dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR);
4604
4605 lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
4606 0,
4607 dwLength + sizeof(SERVICE_DESCRIPTIONW));
4608 if (!lpServiceDescriptonW)
4609 {
4610 return ERROR_NOT_ENOUGH_MEMORY;
4611 }
4612
4613 lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
4614
4615 MultiByteToWideChar(CP_ACP,
4616 0,
4617 Info.lpDescription,
4618 -1,
4619 lpServiceDescriptonW->lpDescription,
4620 dwLength);
4621
4622 ptr = lpServiceDescriptonW;
4623 InfoW.psd = lpServiceDescriptonW;
4624 ///}
4625 }
4626 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4627 {
4628 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
4629 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
4630 DWORD dwRebootLen = 0;
4631 DWORD dwCommandLen = 0;
4632
4633 lpServiceFailureActionsA = Info.psfa;
4634
4635 if (lpServiceFailureActionsA)
4636 {
4637 if (lpServiceFailureActionsA->lpRebootMsg)
4638 {
4639 dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
4640 }
4641 if (lpServiceFailureActionsA->lpCommand)
4642 {
4643 dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
4644 }
4645 dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
4646
4647 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
4648 0,
4649 dwLength);
4650 if (!lpServiceFailureActionsW)
4651 {
4652 return ERROR_NOT_ENOUGH_MEMORY;
4653 }
4654
4655 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
4656 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
4657 CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
4658
4659 if (lpServiceFailureActionsA->lpRebootMsg)
4660 {
4661 MultiByteToWideChar(CP_ACP,
4662 0,
4663 lpServiceFailureActionsA->lpRebootMsg,
4664 -1,
4665 lpServiceFailureActionsW->lpRebootMsg,
4666 dwRebootLen);
4667 }
4668
4669 if (lpServiceFailureActionsA->lpCommand)
4670 {
4671 MultiByteToWideChar(CP_ACP,
4672 0,
4673 lpServiceFailureActionsA->lpCommand,
4674 -1,
4675 lpServiceFailureActionsW->lpCommand,
4676 dwCommandLen);
4677 }
4678
4679 ptr = lpServiceFailureActionsW;
4680 }
4681 }
4682
4683 dwRet = RChangeServiceConfig2W(hService, InfoW);
4684
4685 HeapFree(GetProcessHeap(), 0, ptr);
4686
4687 return dwRet;
4688 }
4689
4690
4691 /* Function 37 */
4692 DWORD RChangeServiceConfig2W(
4693 SC_RPC_HANDLE hService,
4694 SC_RPC_CONFIG_INFOW Info)
4695 {
4696 DWORD dwError = ERROR_SUCCESS;
4697 PSERVICE_HANDLE hSvc;
4698 PSERVICE lpService = NULL;
4699 HKEY hServiceKey = NULL;
4700
4701 DPRINT("RChangeServiceConfig2W() called\n");
4702 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4703
4704 if (ScmShutdown)
4705 return ERROR_SHUTDOWN_IN_PROGRESS;
4706
4707 hSvc = ScmGetServiceFromHandle(hService);
4708 if (hSvc == NULL)
4709 {
4710 DPRINT1("Invalid service handle!\n");
4711 return ERROR_INVALID_HANDLE;
4712 }
4713
4714 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4715 SERVICE_CHANGE_CONFIG))
4716 {
4717 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4718 return ERROR_ACCESS_DENIED;
4719 }
4720
4721 lpService = hSvc->ServiceEntry;
4722 if (lpService == NULL)
4723 {
4724 DPRINT("lpService == NULL!\n");
4725 return ERROR_INVALID_HANDLE;
4726 }
4727
4728 /* Lock the service database exclusively */
4729 ScmLockDatabaseExclusive();
4730
4731 if (lpService->bDeleted)
4732 {
4733 DPRINT("The service has already been marked for delete!\n");
4734 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
4735 goto done;
4736 }
4737
4738 /* Open the service key */
4739 dwError = ScmOpenServiceKey(lpService->szServiceName,
4740 KEY_SET_VALUE,
4741 &hServiceKey);
4742 if (dwError != ERROR_SUCCESS)
4743 goto done;
4744
4745 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4746 {
4747 LPSERVICE_DESCRIPTIONW lpServiceDescription;
4748
4749 lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
4750 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpServiceDescription + sizeof(LPSERVICE_DESCRIPTIONW));
4751
4752 if (lpServiceDescription != NULL &&
4753 lpServiceDescription->lpDescription != NULL)
4754 {
4755 DPRINT("Setting value %S\n", lpServiceDescription->lpDescription);
4756 dwError = RegSetValueExW(hServiceKey,
4757 L"Description",
4758 0,
4759 REG_SZ,
4760 (LPBYTE)lpServiceDescription->lpDescription,
4761 (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
4762 if (dwError != ERROR_SUCCESS)
4763 goto done;
4764 }
4765 }
4766 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4767 {
4768 UNIMPLEMENTED;
4769 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4770 goto done;
4771 }
4772
4773 done:
4774 /* Unlock the service database */
4775 ScmUnlockDatabase();
4776
4777 if (hServiceKey != NULL)
4778 RegCloseKey(hServiceKey);
4779
4780 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
4781
4782 return dwError;
4783 }
4784
4785
4786 /* Function 38 */
4787 DWORD RQueryServiceConfig2A(
4788 SC_RPC_HANDLE hService,
4789 DWORD dwInfoLevel,
4790 LPBYTE lpBuffer,
4791 DWORD cbBufSize,
4792 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4793 {
4794 DWORD dwError = ERROR_SUCCESS;
4795 PSERVICE_HANDLE hSvc;
4796 PSERVICE lpService = NULL;
4797 HKEY hServiceKey = NULL;
4798 LPWSTR lpDescriptionW = NULL;
4799 LPSTR lpDescription = NULL;
4800
4801 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
4802 hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
4803
4804 if (!lpBuffer)
4805 return ERROR_INVALID_ADDRESS;
4806
4807 if (ScmShutdown)
4808 return ERROR_SHUTDOWN_IN_PROGRESS;
4809
4810 hSvc = ScmGetServiceFromHandle(hService);
4811 if (hSvc == NULL)
4812 {
4813 DPRINT1("Invalid service handle!\n");
4814 return ERROR_INVALID_HANDLE;
4815 }
4816
4817 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4818 SERVICE_QUERY_CONFIG))
4819 {
4820 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4821 return ERROR_ACCESS_DENIED;
4822 }
4823
4824 lpService = hSvc->ServiceEntry;
4825 if (lpService == NULL)
4826 {
4827 DPRINT("lpService == NULL!\n");
4828 return ERROR_INVALID_HANDLE;
4829 }
4830
4831 /* Lock the service database shared */
4832 ScmLockDatabaseShared();
4833
4834 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4835 KEY_READ,
4836 &hServiceKey);
4837 if (dwError != ERROR_SUCCESS)
4838 goto done;
4839
4840 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4841 {
4842 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
4843 LPSTR lpStr;
4844
4845 dwError = ScmReadString(hServiceKey,
4846 L"Description",
4847 &lpDescriptionW);
4848 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
4849 goto done;
4850
4851 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
4852 if (dwError == ERROR_SUCCESS)
4853 *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
4854
4855 if (cbBufSize < *pcbBytesNeeded)
4856 {
4857 dwError = ERROR_INSUFFICIENT_BUFFER;
4858 goto done;
4859 }
4860
4861 if (dwError == ERROR_SUCCESS)
4862 {
4863 lpStr = (LPSTR)(lpServiceDescription + 1);
4864
4865 WideCharToMultiByte(CP_ACP,
4866 0,
4867 lpDescriptionW,
4868 -1,
4869 lpStr,
4870 wcslen(lpDescriptionW),
4871 NULL,
4872 NULL);
4873 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4874 }
4875 else
4876 {
4877 lpServiceDescription->lpDescription = NULL;
4878 dwError = ERROR_SUCCESS;
4879 goto done;
4880 }
4881 }
4882 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4883 {
4884 UNIMPLEMENTED;
4885 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4886 goto done;
4887 }
4888
4889 done:
4890 /* Unlock the service database */
4891 ScmUnlockDatabase();
4892
4893 if (lpDescription != NULL)
4894 HeapFree(GetProcessHeap(), 0, lpDescription);
4895
4896 if (hServiceKey != NULL)
4897 RegCloseKey(hServiceKey);
4898
4899 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4900
4901 return dwError;
4902 }
4903
4904
4905 /* Function 39 */
4906 DWORD RQueryServiceConfig2W(
4907 SC_RPC_HANDLE hService,
4908 DWORD dwInfoLevel,
4909 LPBYTE lpBuffer,
4910 DWORD cbBufSize,
4911 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4912 {
4913 DWORD dwError = ERROR_SUCCESS;
4914 PSERVICE_HANDLE hSvc;
4915 PSERVICE lpService = NULL;
4916 HKEY hServiceKey = NULL;
4917 DWORD dwRequiredSize;
4918 LPWSTR lpDescription = NULL;
4919 LPWSTR lpFailureCommand = NULL;
4920 LPWSTR lpRebootMessage = NULL;
4921
4922 DPRINT("RQueryServiceConfig2W() called\n");
4923
4924 if (!lpBuffer)
4925 return ERROR_INVALID_ADDRESS;
4926
4927 if (ScmShutdown)
4928 return ERROR_SHUTDOWN_IN_PROGRESS;
4929
4930 hSvc = ScmGetServiceFromHandle(hService);
4931 if (hSvc == NULL)
4932 {
4933 DPRINT1("Invalid service handle!\n");
4934 return ERROR_INVALID_HANDLE;
4935 }
4936
4937 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4938 SERVICE_QUERY_CONFIG))
4939 {
4940 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4941 return ERROR_ACCESS_DENIED;
4942 }
4943
4944 lpService = hSvc->ServiceEntry;
4945 if (lpService == NULL)
4946 {
4947 DPRINT("lpService == NULL!\n");
4948 return ERROR_INVALID_HANDLE;
4949 }
4950
4951 /* Lock the service database shared */
4952 ScmLockDatabaseShared();
4953
4954 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4955 KEY_READ,
4956 &hServiceKey);
4957 if (dwError != ERROR_SUCCESS)
4958 goto done;
4959
4960 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4961 {
4962 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
4963 LPWSTR lpStr;
4964
4965 dwError = ScmReadString(hServiceKey,
4966 L"Description",
4967 &lpDescription);
4968 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
4969 goto done;
4970
4971 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW);
4972 if (dwError == ERROR_SUCCESS)
4973 *pcbBytesNeeded += ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
4974
4975 if (cbBufSize < *pcbBytesNeeded)
4976 {
4977 dwError = ERROR_INSUFFICIENT_BUFFER;
4978 goto done;
4979 }
4980
4981 if (dwError == ERROR_SUCCESS)
4982 {
4983 lpStr = (LPWSTR)(lpServiceDescription + 1);
4984 wcscpy(lpStr, lpDescription);
4985 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4986 }
4987 else
4988 {
4989 lpServiceDescription->lpDescription = NULL;
4990 dwError = ERROR_SUCCESS;
4991 }
4992 }
4993 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4994 {
4995 LPWSTR lpStr;
4996 LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
4997
4998 UNIMPLEMENTED;
4999
5000 dwError = ScmReadString(hServiceKey,
5001 L"FailureCommand",
5002 &lpFailureCommand);
5003
5004 dwError = ScmReadString(hServiceKey,
5005 L"RebootMessage",
5006 &lpRebootMessage);
5007
5008 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5009
5010 if (lpFailureCommand)
5011 dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR);
5012
5013 if (lpRebootMessage)
5014 dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR);
5015
5016 if (cbBufSize < dwRequiredSize)
5017 {
5018 *pcbBytesNeeded = dwRequiredSize;
5019 dwError = ERROR_INSUFFICIENT_BUFFER;
5020 goto done;
5021 }
5022
5023 lpFailureActions->cActions = 0;
5024 lpFailureActions->dwResetPeriod = 0;
5025 lpFailureActions->lpCommand = NULL;
5026 lpFailureActions->lpRebootMsg = NULL;
5027 lpFailureActions->lpsaActions = NULL;
5028
5029 lpStr = (LPWSTR)(lpFailureActions + 1);
5030 if (lpRebootMessage)
5031 {
5032 wcscpy(lpStr, lpRebootMessage);
5033 lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage);
5034 lpStr += wcslen(lpRebootMessage) + 1;
5035 }
5036
5037 if (lpFailureCommand)
5038 {
5039 wcscpy(lpStr, lpFailureCommand);
5040 lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand);
5041 lpStr += wcslen(lpRebootMessage) + 1;
5042 }
5043 dwError = STATUS_SUCCESS;
5044 goto done;
5045 }
5046
5047 done:
5048 /* Unlock the service database */
5049 ScmUnlockDatabase();
5050
5051 if (lpDescription != NULL)
5052 HeapFree(GetProcessHeap(), 0, lpDescription);
5053
5054 if (lpRebootMessage != NULL)
5055 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
5056
5057 if (lpFailureCommand != NULL)
5058 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
5059
5060 if (hServiceKey != NULL)
5061 RegCloseKey(hServiceKey);
5062
5063 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
5064
5065 return dwError;
5066 }
5067
5068
5069 /* Function 40 */
5070 DWORD RQueryServiceStatusEx(
5071 SC_RPC_HANDLE hService,
5072 SC_STATUS_TYPE InfoLevel,
5073 LPBYTE lpBuffer,
5074 DWORD cbBufSize,
5075 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5076 {
5077 LPSERVICE_STATUS_PROCESS lpStatus;
5078 PSERVICE_HANDLE hSvc;
5079 PSERVICE lpService;
5080
5081 DPRINT("RQueryServiceStatusEx() called\n");
5082
5083 if (ScmShutdown)
5084 return ERROR_SHUTDOWN_IN_PROGRESS;
5085
5086 if (InfoLevel != SC_STATUS_PROCESS_INFO)
5087 return ERROR_INVALID_LEVEL;
5088
5089 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
5090
5091 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
5092 return ERROR_INSUFFICIENT_BUFFER;
5093
5094 hSvc = ScmGetServiceFromHandle(hService);
5095 if (hSvc == NULL)
5096 {
5097 DPRINT1("Invalid service handle!\n");
5098 return ERROR_INVALID_HANDLE;
5099 }
5100
5101 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5102 SERVICE_QUERY_STATUS))
5103 {
5104 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5105 return ERROR_ACCESS_DENIED;
5106 }
5107
5108 lpService = hSvc->ServiceEntry;
5109 if (lpService == NULL)
5110 {
5111 DPRINT("lpService == NULL!\n");
5112 return ERROR_INVALID_HANDLE;
5113 }
5114
5115 /* Lock the service database shared */
5116 ScmLockDatabaseShared();
5117
5118 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
5119
5120 /* Return service status information */
5121 RtlCopyMemory(lpStatus,
5122 &lpService->Status,
5123 sizeof(SERVICE_STATUS));
5124
5125 lpStatus->dwProcessId = (lpService->lpImage != NULL) ? lpService->lpImage->dwProcessId : 0; /* FIXME */
5126 lpStatus->dwServiceFlags = 0; /* FIXME */
5127
5128 /* Unlock the service database */
5129 ScmUnlockDatabase();
5130
5131 return ERROR_SUCCESS;
5132 }
5133
5134
5135 /* Function 41 */
5136 DWORD REnumServicesStatusExA(
5137 SC_RPC_HANDLE hSCManager,
5138 SC_ENUM_TYPE InfoLevel,
5139 DWORD dwServiceType,
5140 DWORD dwServiceState,
5141 LPBYTE lpBuffer,
5142 DWORD cbBufSize,
5143 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5144 LPBOUNDED_DWORD_256K lpServicesReturned,
5145 LPBOUNDED_DWORD_256K lpResumeIndex,
5146 LPCSTR pszGroupName)
5147 {
5148 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
5149 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
5150 LPWSTR lpStringPtrW;
5151 LPSTR lpStringPtrA;
5152 LPWSTR pszGroupNameW = NULL;
5153 DWORD dwError;
5154 DWORD dwServiceCount;
5155
5156 DPRINT("REnumServicesStatusExA() called\n");
5157
5158 if (pszGroupName)
5159 {
5160 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
5161 if (!pszGroupNameW)
5162 {
5163 DPRINT("Failed to allocate buffer!\n");
5164 return ERROR_NOT_ENOUGH_MEMORY;
5165 }
5166
5167 MultiByteToWideChar(CP_ACP,
5168 0,
5169 pszGroupName,
5170 -1,
5171 pszGroupNameW,
5172 strlen(pszGroupName) + 1);
5173 }
5174
5175 if ((cbBufSize > 0) && (lpBuffer))
5176 {
5177 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
5178 if (!lpStatusPtrW)
5179 {
5180 DPRINT("Failed to allocate buffer!\n");
5181 return ERROR_NOT_ENOUGH_MEMORY;
5182 }
5183 }
5184
5185 dwError = REnumServicesStatusExW(hSCManager,
5186 InfoLevel,
5187 dwServiceType,
5188 dwServiceState,
5189 (LPBYTE)lpStatusPtrW,
5190 cbBufSize,
5191 pcbBytesNeeded,
5192 lpServicesReturned,
5193 lpResumeIndex,
5194 pszGroupNameW);
5195
5196 /* if no services were returned then we are Done */
5197 if (*lpServicesReturned == 0)
5198 goto Done;
5199
5200 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
5201 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
5202 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
5203 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
5204 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
5205
5206 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
5207 {
5208 /* Copy the service name */
5209 WideCharToMultiByte(CP_ACP,
5210 0,
5211 lpStringPtrW,
5212 -1,
5213 lpStringPtrA,
5214 wcslen(lpStringPtrW),
5215 0,
5216 0);
5217
5218 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5219 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5220 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5221
5222 /* Copy the display name */
5223 WideCharToMultiByte(CP_ACP,
5224 0,
5225 lpStringPtrW,
5226 -1,
5227 lpStringPtrA,
5228 wcslen(lpStringPtrW),
5229 0,
5230 0);
5231
5232 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5233 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5234 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5235
5236 /* Copy the status information */
5237 memcpy(&lpStatusPtrA->ServiceStatusProcess,
5238 &lpStatusPtrW->ServiceStatusProcess,
5239 sizeof(SERVICE_STATUS));
5240
5241 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
5242 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5243 lpStatusPtrA++;
5244 }
5245
5246 Done:;
5247 if (pszGroupNameW)
5248 HeapFree(GetProcessHeap(), 0, pszGroupNameW);
5249
5250 if (lpStatusPtrW)
5251 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
5252
5253 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
5254
5255 return dwError;
5256 }
5257
5258
5259 /* Function 42 */
5260 DWORD REnumServicesStatusExW(
5261 SC_RPC_HANDLE hSCManager,
5262 SC_ENUM_TYPE InfoLevel,
5263 DWORD dwServiceType,
5264 DWORD dwServiceState,
5265 LPBYTE lpBuffer,
5266 DWORD cbBufSize,
5267 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5268 LPBOUNDED_DWORD_256K lpServicesReturned,
5269 LPBOUNDED_DWORD_256K lpResumeIndex,
5270 LPCWSTR pszGroupName)
5271 {
5272 PMANAGER_HANDLE hManager;
5273 PSERVICE lpService;
5274 DWORD dwError = ERROR_SUCCESS;
5275 PLIST_ENTRY ServiceEntry;
5276 PSERVICE CurrentService;
5277 DWORD dwState;
5278 DWORD dwRequiredSize;
5279 DWORD dwServiceCount;
5280 DWORD dwSize;
5281 DWORD dwLastResumeCount = 0;
5282 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
5283 LPWSTR lpStringPtr;
5284
5285 DPRINT("REnumServicesStatusExW() called\n");
5286
5287 if (ScmShutdown)
5288 return ERROR_SHUTDOWN_IN_PROGRESS;
5289
5290 if (InfoLevel != SC_ENUM_PROCESS_INFO)
5291 return ERROR_INVALID_LEVEL;
5292
5293 hManager = ScmGetServiceManagerFromHandle(hSCManager);
5294 if (hManager == NULL)
5295 {
5296 DPRINT1("Invalid service manager handle!\n");
5297 return ERROR_INVALID_HANDLE;
5298 }
5299
5300 *pcbBytesNeeded = 0;
5301 *lpServicesReturned = 0;
5302
5303 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
5304 {
5305 DPRINT("Not a valid Service Type!\n");
5306 return ERROR_INVALID_PARAMETER;
5307 }
5308
5309 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
5310 {
5311 DPRINT("Not a valid Service State!\n");
5312 return ERROR_INVALID_PARAMETER;
5313 }
5314
5315 /* Check access rights */
5316 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
5317 SC_MANAGER_ENUMERATE_SERVICE))
5318 {
5319 DPRINT("Insufficient access rights! 0x%lx\n",
5320 hManager->Handle.DesiredAccess);
5321 return ERROR_ACCESS_DENIED;
5322 }
5323
5324 if (lpResumeIndex)
5325 dwLastResumeCount = *lpResumeIndex;
5326
5327 /* Lock the service database shared */
5328 ScmLockDatabaseShared();
5329
5330 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
5331 if (lpService == NULL)
5332 {
5333 dwError = ERROR_SUCCESS;
5334 goto Done;
5335 }
5336
5337 dwRequiredSize = 0;
5338 dwServiceCount = 0;
5339
5340 for (ServiceEntry = &lpService->ServiceListEntry;
5341 ServiceEntry != &ServiceListHead;
5342 ServiceEntry = ServiceEntry->Flink)
5343 {
5344 CurrentService = CONTAINING_RECORD(ServiceEntry,
5345 SERVICE,
5346 ServiceListEntry);
5347
5348 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5349 continue;
5350
5351 dwState = SERVICE_ACTIVE;
5352 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5353 dwState = SERVICE_INACTIVE;
5354
5355 if ((dwState & dwServiceState) == 0)
5356 continue;
5357
5358 if (pszGroupName)
5359 {
5360 if (*pszGroupName == 0)
5361 {
5362 if (CurrentService->lpGroup != NULL)
5363 continue;
5364 }
5365 else
5366 {
5367 if ((CurrentService->lpGroup == NULL) ||
5368 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5369 continue;
5370 }
5371 }
5372
5373 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5374 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5375 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5376
5377 if (dwRequiredSize + dwSize <= cbBufSize)
5378 {
5379 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
5380 dwRequiredSize += dwSize;
5381 dwServiceCount++;
5382 dwLastResumeCount = CurrentService->dwResumeCount;
5383 }
5384 else
5385 {
5386 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
5387 break;
5388 }
5389
5390 }
5391
5392 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
5393 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
5394
5395 for (;
5396 ServiceEntry != &ServiceListHead;
5397 ServiceEntry = ServiceEntry->Flink)
5398 {
5399 CurrentService = CONTAINING_RECORD(ServiceEntry,
5400 SERVICE,
5401 ServiceListEntry);
5402
5403 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5404 continue;
5405
5406 dwState = SERVICE_ACTIVE;
5407 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5408 dwState = SERVICE_INACTIVE;
5409
5410 if ((dwState & dwServiceState) == 0)
5411 continue;
5412
5413 if (pszGroupName)
5414 {
5415 if (*pszGroupName == 0)
5416 {
5417 if (CurrentService->lpGroup != NULL)
5418 continue;
5419 }
5420 else
5421 {
5422 if ((CurrentService->lpGroup == NULL) ||
5423 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5424 continue;
5425 }
5426 }
5427
5428 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5429 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5430 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
5431
5432 dwError = ERROR_MORE_DATA;
5433 }
5434
5435 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
5436
5437 if (lpResumeIndex)
5438 *lpResumeIndex = dwLastResumeCount;
5439
5440 *lpServicesReturned = dwServiceCount;
5441 *pcbBytesNeeded = dwRequiredSize;
5442
5443 /* If there was no services that matched */
5444 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
5445 {
5446 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
5447 goto Done;
5448 }
5449
5450 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
5451 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
5452 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
5453
5454 dwRequiredSize = 0;
5455 for (ServiceEntry = &lpService->ServiceListEntry;
5456 ServiceEntry != &ServiceListHead;
5457 ServiceEntry = ServiceEntry->Flink)
5458 {
5459 CurrentService = CONTAINING_RECORD(ServiceEntry,
5460 SERVICE,
5461 ServiceListEntry);
5462
5463 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5464 continue;
5465
5466 dwState = SERVICE_ACTIVE;
5467 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5468 dwState = SERVICE_INACTIVE;
5469
5470 if ((dwState & dwServiceState) == 0)
5471 continue;
5472
5473 if (pszGroupName)
5474 {
5475 if (*pszGroupName == 0)
5476 {
5477 if (CurrentService->lpGroup != NULL)
5478 continue;
5479 }
5480 else
5481 {
5482 if ((CurrentService->lpGroup == NULL) ||
5483 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5484 continue;
5485 }
5486 }
5487
5488 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5489 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5490 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5491
5492 if (dwRequiredSize + dwSize <= cbBufSize)
5493 {
5494 /* Copy the service name */
5495 wcscpy(lpStringPtr,
5496 CurrentService->lpServiceName);
5497 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5498 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
5499
5500 /* Copy the display name */
5501 wcscpy(lpStringPtr,
5502 CurrentService->lpDisplayName);
5503 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5504 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
5505
5506 /* Copy the status information */
5507 memcpy(&lpStatusPtr->ServiceStatusProcess,
5508 &CurrentService->Status,
5509 sizeof(SERVICE_STATUS));
5510 lpStatusPtr->ServiceStatusProcess.dwProcessId =
5511 (CurrentService->lpImage != NULL) ? CurrentService->lpImage->dwProcessId : 0; /* FIXME */
5512 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5513
5514 lpStatusPtr++;
5515 dwRequiredSize += dwSize;
5516 }
5517 else
5518 {
5519 break;
5520 }
5521 }
5522
5523 if (dwError == 0)
5524 {
5525 *pcbBytesNeeded = 0;
5526 if (lpResumeIndex)
5527 *lpResumeIndex = 0;
5528 }
5529
5530 Done:;
5531 /* Unlock the service database */
5532 ScmUnlockDatabase();
5533
5534 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
5535
5536 return dwError;
5537 }
5538
5539
5540 /* Function 43 */
5541 DWORD RSendTSMessage(
5542 handle_t BindingHandle) /* FIXME */
5543 {
5544 UNIMPLEMENTED;
5545 return ERROR_CALL_NOT_IMPLEMENTED;
5546 }
5547
5548
5549 /* Function 44 */
5550 DWORD RCreateServiceWOW64A(
5551 handle_t BindingHandle,
5552 LPSTR lpServiceName,
5553 LPSTR lpDisplayName,
5554 DWORD dwDesiredAccess,
5555 DWORD dwServiceType,
5556 DWORD dwStartType,
5557 DWORD dwErrorControl,
5558 LPSTR lpBinaryPathName,
5559 LPSTR lpLoadOrderGroup,
5560 LPDWORD lpdwTagId,
5561 LPBYTE lpDependencies,
5562 DWORD dwDependSize,
5563 LPSTR lpServiceStartName,
5564 LPBYTE lpPassword,
5565 DWORD dwPwSize,
5566 LPSC_RPC_HANDLE lpServiceHandle)
5567 {
5568 UNIMPLEMENTED;
5569 return ERROR_CALL_NOT_IMPLEMENTED;
5570 }
5571
5572
5573 /* Function 45 */
5574 DWORD RCreateServiceWOW64W(
5575 handle_t BindingHandle,
5576 LPWSTR lpServiceName,
5577 LPWSTR lpDisplayName,
5578 DWORD dwDesiredAccess,
5579 DWORD dwServiceType,
5580 DWORD dwStartType,
5581 DWORD dwErrorControl,
5582 LPWSTR lpBinaryPathName,
5583 LPWSTR lpLoadOrderGroup,
5584 LPDWORD lpdwTagId,
5585 LPBYTE lpDependencies,
5586 DWORD dwDependSize,
5587 LPWSTR lpServiceStartName,
5588 LPBYTE lpPassword,
5589 DWORD dwPwSize,
5590 LPSC_RPC_HANDLE lpServiceHandle)
5591 {
5592 UNIMPLEMENTED;
5593 return ERROR_CALL_NOT_IMPLEMENTED;
5594 }
5595
5596
5597 /* Function 46 */
5598 DWORD RQueryServiceTagInfo(
5599 handle_t BindingHandle) /* FIXME */
5600 {
5601 UNIMPLEMENTED;
5602 return ERROR_CALL_NOT_IMPLEMENTED;
5603 }
5604
5605
5606 /* Function 47 */
5607 DWORD RNotifyServiceStatusChange(
5608 SC_RPC_HANDLE hService,
5609 SC_RPC_NOTIFY_PARAMS NotifyParams,
5610 GUID *pClientProcessGuid,
5611 GUID *pSCMProcessGuid,
5612 PBOOL pfCreateRemoteQueue,
5613 LPSC_NOTIFY_RPC_HANDLE phNotify)
5614 {
5615 UNIMPLEMENTED;
5616 return ERROR_CALL_NOT_IMPLEMENTED;
5617 }
5618
5619
5620 /* Function 48 */
5621 DWORD RGetNotifyResults(
5622 SC_NOTIFY_RPC_HANDLE hNotify,
5623 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
5624 {
5625 UNIMPLEMENTED;
5626 return ERROR_CALL_NOT_IMPLEMENTED;
5627 }
5628
5629
5630 /* Function 49 */
5631 DWORD RCloseNotifyHandle(
5632 LPSC_NOTIFY_RPC_HANDLE phNotify,
5633 PBOOL pfApcFired)
5634 {
5635 UNIMPLEMENTED;
5636 return ERROR_CALL_NOT_IMPLEMENTED;
5637 }
5638
5639
5640 /* Function 50 */
5641 DWORD RControlServiceExA(
5642 SC_RPC_HANDLE hService,
5643 DWORD dwControl,
5644 DWORD dwInfoLevel)
5645 {
5646 UNIMPLEMENTED;
5647 return ERROR_CALL_NOT_IMPLEMENTED;
5648 }
5649
5650
5651 /* Function 51 */
5652 DWORD RControlServiceExW(
5653 SC_RPC_HANDLE hService,
5654 DWORD dwControl,
5655 DWORD dwInfoLevel)
5656 {
5657 UNIMPLEMENTED;
5658 return ERROR_CALL_NOT_IMPLEMENTED;
5659 }
5660
5661
5662 /* Function 52 */
5663 DWORD RSendPnPMessage(
5664 handle_t BindingHandle) /* FIXME */
5665 {
5666 UNIMPLEMENTED;
5667 return ERROR_CALL_NOT_IMPLEMENTED;
5668 }
5669
5670
5671 /* Function 53 */
5672 DWORD RValidatePnPService(
5673 handle_t BindingHandle) /* FIXME */
5674 {
5675 UNIMPLEMENTED;
5676 return ERROR_CALL_NOT_IMPLEMENTED;
5677 }
5678
5679
5680 /* Function 54 */
5681 DWORD ROpenServiceStatusHandle(
5682 handle_t BindingHandle) /* FIXME */
5683 {
5684 UNIMPLEMENTED;
5685 return ERROR_CALL_NOT_IMPLEMENTED;
5686 }
5687
5688
5689 /* Function 55 */
5690 DWORD RFunction55(
5691 handle_t BindingHandle) /* FIXME */
5692 {
5693 UNIMPLEMENTED;
5694 return ERROR_CALL_NOT_IMPLEMENTED;
5695 }
5696
5697
5698 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
5699 {
5700 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
5701 }
5702
5703
5704 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
5705 {
5706 HeapFree(GetProcessHeap(), 0, ptr);
5707 }
5708
5709
5710 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
5711 {
5712 }
5713
5714
5715 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
5716 {
5717 }
5718
5719
5720 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
5721 {
5722 }
5723
5724 /* EOF */