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