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