Create this branch to work on loading of different Kernel-Debugger DLL providers...
[reactos.git] / 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
2899 #ifndef NDEBUG
2900 DWORD i;
2901
2902 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
2903 DPRINT(" argc: %lu\n", argc);
2904 if (argv != NULL)
2905 {
2906 for (i = 0; i < argc; i++)
2907 {
2908 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
2909 }
2910 }
2911 #endif
2912
2913 if (ScmShutdown)
2914 return ERROR_SHUTDOWN_IN_PROGRESS;
2915
2916 hSvc = ScmGetServiceFromHandle(hService);
2917 if (hSvc == NULL)
2918 {
2919 DPRINT1("Invalid service handle!\n");
2920 return ERROR_INVALID_HANDLE;
2921 }
2922
2923 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2924 SERVICE_START))
2925 {
2926 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2927 return ERROR_ACCESS_DENIED;
2928 }
2929
2930 lpService = hSvc->ServiceEntry;
2931 if (lpService == NULL)
2932 {
2933 DPRINT("lpService == NULL!\n");
2934 return ERROR_INVALID_HANDLE;
2935 }
2936
2937 if (lpService->dwStartType == SERVICE_DISABLED)
2938 return ERROR_SERVICE_DISABLED;
2939
2940 if (lpService->bDeleted)
2941 return ERROR_SERVICE_MARKED_FOR_DELETE;
2942
2943 /* Start the service */
2944 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
2945
2946 return dwError;
2947 }
2948
2949
2950 /* Function 20 */
2951 DWORD RGetServiceDisplayNameW(
2952 SC_RPC_HANDLE hSCManager,
2953 LPCWSTR lpServiceName,
2954 LPWSTR lpDisplayName,
2955 DWORD *lpcchBuffer)
2956 {
2957 // PMANAGER_HANDLE hManager;
2958 PSERVICE lpService;
2959 DWORD dwLength;
2960 DWORD dwError;
2961
2962 DPRINT("RGetServiceDisplayNameW() called\n");
2963 DPRINT("hSCManager = %p\n", hSCManager);
2964 DPRINT("lpServiceName: %S\n", lpServiceName);
2965 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2966 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2967
2968 // hManager = (PMANAGER_HANDLE)hSCManager;
2969 // if (hManager->Handle.Tag != MANAGER_TAG)
2970 // {
2971 // DPRINT("Invalid manager handle!\n");
2972 // return ERROR_INVALID_HANDLE;
2973 // }
2974
2975 /* Get service database entry */
2976 lpService = ScmGetServiceEntryByName(lpServiceName);
2977 if (lpService == NULL)
2978 {
2979 DPRINT("Could not find a service!\n");
2980
2981 /* If the service could not be found and lpcchBuffer is less than 2, windows
2982 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2983 if (*lpcchBuffer < 2)
2984 {
2985 *lpcchBuffer = 2;
2986 if (lpDisplayName != NULL)
2987 {
2988 *lpDisplayName = 0;
2989 }
2990 }
2991
2992 return ERROR_SERVICE_DOES_NOT_EXIST;
2993 }
2994
2995 if (!lpService->lpDisplayName)
2996 {
2997 dwLength = (DWORD)wcslen(lpService->lpServiceName);
2998
2999 if (lpDisplayName != NULL &&
3000 *lpcchBuffer > dwLength)
3001 {
3002 wcscpy(lpDisplayName, lpService->lpServiceName);
3003 }
3004 }
3005 else
3006 {
3007 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
3008
3009 if (lpDisplayName != NULL &&
3010 *lpcchBuffer > dwLength)
3011 {
3012 wcscpy(lpDisplayName, lpService->lpDisplayName);
3013 }
3014 }
3015
3016 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3017
3018 *lpcchBuffer = dwLength;
3019
3020 return dwError;
3021 }
3022
3023
3024 /* Function 21 */
3025 DWORD RGetServiceKeyNameW(
3026 SC_RPC_HANDLE hSCManager,
3027 LPCWSTR lpDisplayName,
3028 LPWSTR lpServiceName,
3029 DWORD *lpcchBuffer)
3030 {
3031 // PMANAGER_HANDLE hManager;
3032 PSERVICE lpService;
3033 DWORD dwLength;
3034 DWORD dwError;
3035
3036 DPRINT("RGetServiceKeyNameW() called\n");
3037 DPRINT("hSCManager = %p\n", hSCManager);
3038 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3039 DPRINT("lpServiceName: %p\n", lpServiceName);
3040 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3041
3042 // hManager = (PMANAGER_HANDLE)hSCManager;
3043 // if (hManager->Handle.Tag != MANAGER_TAG)
3044 // {
3045 // DPRINT("Invalid manager handle!\n");
3046 // return ERROR_INVALID_HANDLE;
3047 // }
3048
3049 /* Get service database entry */
3050 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3051 if (lpService == NULL)
3052 {
3053 DPRINT("Could not find a service!\n");
3054
3055 /* If the service could not be found and lpcchBuffer is less than 2, windows
3056 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3057 if (*lpcchBuffer < 2)
3058 {
3059 *lpcchBuffer = 2;
3060 if (lpServiceName != NULL)
3061 {
3062 *lpServiceName = 0;
3063 }
3064 }
3065
3066 return ERROR_SERVICE_DOES_NOT_EXIST;
3067 }
3068
3069 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3070
3071 if (lpServiceName != NULL &&
3072 *lpcchBuffer > dwLength)
3073 {
3074 wcscpy(lpServiceName, lpService->lpServiceName);
3075 *lpcchBuffer = dwLength;
3076 return ERROR_SUCCESS;
3077 }
3078
3079 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3080
3081 *lpcchBuffer = dwLength;
3082
3083 return dwError;
3084 }
3085
3086
3087 /* Function 22 */
3088 DWORD RI_ScSetServiceBitsA(
3089 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3090 DWORD dwServiceBits,
3091 int bSetBitsOn,
3092 int bUpdateImmediately,
3093 char *lpString)
3094 {
3095 UNIMPLEMENTED;
3096 return ERROR_CALL_NOT_IMPLEMENTED;
3097 }
3098
3099
3100 /* Function 23 */
3101 DWORD RChangeServiceConfigA(
3102 SC_RPC_HANDLE hService,
3103 DWORD dwServiceType,
3104 DWORD dwStartType,
3105 DWORD dwErrorControl,
3106 LPSTR lpBinaryPathName,
3107 LPSTR lpLoadOrderGroup,
3108 LPDWORD lpdwTagId,
3109 LPBYTE lpDependencies,
3110 DWORD dwDependSize,
3111 LPSTR lpServiceStartName,
3112 LPBYTE lpPassword,
3113 DWORD dwPwSize,
3114 LPSTR lpDisplayName)
3115 {
3116 DWORD dwError = ERROR_SUCCESS;
3117 PSERVICE_HANDLE hSvc;
3118 PSERVICE lpService = NULL;
3119 HKEY hServiceKey = NULL;
3120 LPWSTR lpDisplayNameW = NULL;
3121 LPWSTR lpBinaryPathNameW = NULL;
3122 LPWSTR lpCanonicalImagePathW = NULL;
3123 LPWSTR lpLoadOrderGroupW = NULL;
3124 LPWSTR lpDependenciesW = NULL;
3125
3126 DPRINT("RChangeServiceConfigA() called\n");
3127 DPRINT("dwServiceType = %lu\n", dwServiceType);
3128 DPRINT("dwStartType = %lu\n", dwStartType);
3129 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3130 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3131 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3132 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3133
3134 if (ScmShutdown)
3135 return ERROR_SHUTDOWN_IN_PROGRESS;
3136
3137 hSvc = ScmGetServiceFromHandle(hService);
3138 if (hSvc == NULL)
3139 {
3140 DPRINT1("Invalid service handle!\n");
3141 return ERROR_INVALID_HANDLE;
3142 }
3143
3144 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3145 SERVICE_CHANGE_CONFIG))
3146 {
3147 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3148 return ERROR_ACCESS_DENIED;
3149 }
3150
3151 lpService = hSvc->ServiceEntry;
3152 if (lpService == NULL)
3153 {
3154 DPRINT("lpService == NULL!\n");
3155 return ERROR_INVALID_HANDLE;
3156 }
3157
3158 /* Lock the service database exclusively */
3159 ScmLockDatabaseExclusive();
3160
3161 if (lpService->bDeleted)
3162 {
3163 DPRINT("The service has already been marked for delete!\n");
3164 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
3165 goto done;
3166 }
3167
3168 /* Open the service key */
3169 dwError = ScmOpenServiceKey(lpService->szServiceName,
3170 KEY_SET_VALUE,
3171 &hServiceKey);
3172 if (dwError != ERROR_SUCCESS)
3173 goto done;
3174
3175 /* Write service data to the registry */
3176
3177 if (lpDisplayName != NULL && *lpDisplayName != 0)
3178 {
3179 /* Set the display name */
3180 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3181 HEAP_ZERO_MEMORY,
3182 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3183 if (lpDisplayNameW == NULL)
3184 {
3185 dwError = ERROR_NOT_ENOUGH_MEMORY;
3186 goto done;
3187 }
3188
3189 MultiByteToWideChar(CP_ACP,
3190 0,
3191 lpDisplayName,
3192 -1,
3193 lpDisplayNameW,
3194 (int)(strlen(lpDisplayName) + 1));
3195
3196 RegSetValueExW(hServiceKey,
3197 L"DisplayName",
3198 0,
3199 REG_SZ,
3200 (LPBYTE)lpDisplayNameW,
3201 (DWORD)((wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR)));
3202
3203 /* Update lpService->lpDisplayName */
3204 if (lpService->lpDisplayName)
3205 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3206
3207 lpService->lpDisplayName = lpDisplayNameW;
3208 }
3209
3210 if (dwServiceType != SERVICE_NO_CHANGE)
3211 {
3212 /* Set the service type */
3213 dwError = RegSetValueExW(hServiceKey,
3214 L"Type",
3215 0,
3216 REG_DWORD,
3217 (LPBYTE)&dwServiceType,
3218 sizeof(DWORD));
3219 if (dwError != ERROR_SUCCESS)
3220 goto done;
3221
3222 lpService->Status.dwServiceType = dwServiceType;
3223 }
3224
3225 if (dwStartType != SERVICE_NO_CHANGE)
3226 {
3227 /* Set the start value */
3228 dwError = RegSetValueExW(hServiceKey,
3229 L"Start",
3230 0,
3231 REG_DWORD,
3232 (LPBYTE)&dwStartType,
3233 sizeof(DWORD));
3234 if (dwError != ERROR_SUCCESS)
3235 goto done;
3236
3237 lpService->dwStartType = dwStartType;
3238 }
3239
3240 if (dwErrorControl != SERVICE_NO_CHANGE)
3241 {
3242 /* Set the error control value */
3243 dwError = RegSetValueExW(hServiceKey,
3244 L"ErrorControl",
3245 0,
3246 REG_DWORD,
3247 (LPBYTE)&dwErrorControl,
3248 sizeof(DWORD));
3249 if (dwError != ERROR_SUCCESS)
3250 goto done;
3251
3252 lpService->dwErrorControl = dwErrorControl;
3253 }
3254
3255 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3256 {
3257 /* Set the image path */
3258 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
3259 HEAP_ZERO_MEMORY,
3260 (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
3261 if (lpBinaryPathNameW == NULL)
3262 {
3263 dwError = ERROR_NOT_ENOUGH_MEMORY;
3264 goto done;
3265 }
3266
3267 MultiByteToWideChar(CP_ACP,
3268 0,
3269 lpBinaryPathName,
3270 -1,
3271 lpBinaryPathNameW,
3272 (int)(strlen(lpBinaryPathName) + 1));
3273
3274 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
3275 {
3276 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
3277 lpBinaryPathNameW,
3278 &lpCanonicalImagePathW);
3279
3280 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3281
3282 if (dwError != ERROR_SUCCESS)
3283 goto done;
3284
3285 lpBinaryPathNameW = lpCanonicalImagePathW;
3286 }
3287
3288 dwError = RegSetValueExW(hServiceKey,
3289 L"ImagePath",
3290 0,
3291 REG_EXPAND_SZ,
3292 (LPBYTE)lpBinaryPathNameW,
3293 (DWORD)((wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR)));
3294
3295 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3296
3297 if (dwError != ERROR_SUCCESS)
3298 goto done;
3299 }
3300
3301 /* Set the group name */
3302 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3303 {
3304 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3305 HEAP_ZERO_MEMORY,
3306 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3307 if (lpLoadOrderGroupW == NULL)
3308 {
3309 dwError = ERROR_NOT_ENOUGH_MEMORY;
3310 goto done;
3311 }
3312
3313 MultiByteToWideChar(CP_ACP,
3314 0,
3315 lpLoadOrderGroup,
3316 -1,
3317 lpLoadOrderGroupW,
3318 (int)(strlen(lpLoadOrderGroup) + 1));
3319
3320 dwError = RegSetValueExW(hServiceKey,
3321 L"Group",
3322 0,
3323 REG_SZ,
3324 (LPBYTE)lpLoadOrderGroupW,
3325 (DWORD)((wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR)));
3326 if (dwError != ERROR_SUCCESS)
3327 {
3328 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3329 goto done;
3330 }
3331
3332 dwError = ScmSetServiceGroup(lpService,
3333 lpLoadOrderGroupW);
3334
3335 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3336
3337 if (dwError != ERROR_SUCCESS)
3338 goto done;
3339 }
3340
3341 if (lpdwTagId != NULL)
3342 {
3343 dwError = ScmAssignNewTag(lpService);
3344 if (dwError != ERROR_SUCCESS)
3345 goto done;
3346
3347 dwError = RegSetValueExW(hServiceKey,
3348 L"Tag",
3349 0,
3350 REG_DWORD,
3351 (LPBYTE)&lpService->dwTag,
3352 sizeof(DWORD));
3353 if (dwError != ERROR_SUCCESS)
3354 goto done;
3355
3356 *lpdwTagId = lpService->dwTag;
3357 }
3358
3359 /* Write dependencies */
3360 if (lpDependencies != NULL && *lpDependencies != 0)
3361 {
3362 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3363 HEAP_ZERO_MEMORY,
3364 (strlen((LPSTR)lpDependencies) + 1) * sizeof(WCHAR));
3365 if (lpDependenciesW == NULL)
3366 {
3367 dwError = ERROR_NOT_ENOUGH_MEMORY;
3368 goto done;
3369 }
3370
3371 MultiByteToWideChar(CP_ACP,
3372 0,
3373 (LPSTR)lpDependencies,
3374 dwDependSize,
3375 lpDependenciesW,
3376 (int)(strlen((LPSTR)lpDependencies) + 1));
3377
3378 dwError = ScmWriteDependencies(hServiceKey,
3379 (LPWSTR)lpDependenciesW,
3380 dwDependSize);
3381
3382 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3383 }
3384
3385 if (lpPassword != NULL)
3386 {
3387 /* FIXME: Decrypt and write password */
3388 }
3389
3390 done:
3391 /* Unlock the service database */
3392 ScmUnlockDatabase();
3393
3394 if (hServiceKey != NULL)
3395 RegCloseKey(hServiceKey);
3396
3397 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3398
3399 return dwError;
3400 }
3401
3402
3403 /* Function 24 */
3404 DWORD RCreateServiceA(
3405 SC_RPC_HANDLE hSCManager,
3406 LPSTR lpServiceName,
3407 LPSTR lpDisplayName,
3408 DWORD dwDesiredAccess,
3409 DWORD dwServiceType,
3410 DWORD dwStartType,
3411 DWORD dwErrorControl,
3412 LPSTR lpBinaryPathName,
3413 LPSTR lpLoadOrderGroup,
3414 LPDWORD lpdwTagId,
3415 LPBYTE lpDependencies,
3416 DWORD dwDependSize,
3417 LPSTR lpServiceStartName,
3418 LPBYTE lpPassword,
3419 DWORD dwPwSize,
3420 LPSC_RPC_HANDLE lpServiceHandle)
3421 {
3422 DWORD dwError = ERROR_SUCCESS;
3423 LPWSTR lpServiceNameW = NULL;
3424 LPWSTR lpDisplayNameW = NULL;
3425 LPWSTR lpBinaryPathNameW = NULL;
3426 LPWSTR lpLoadOrderGroupW = NULL;
3427 LPWSTR lpDependenciesW = NULL;
3428 LPWSTR lpServiceStartNameW = NULL;
3429 DWORD dwDependenciesLength = 0;
3430 SIZE_T cchLength;
3431 int len;
3432 LPCSTR lpStr;
3433
3434 if (lpServiceName)
3435 {
3436 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3437 lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3438 if (!lpServiceNameW)
3439 {
3440 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3441 goto cleanup;
3442 }
3443 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3444 }
3445
3446 if (lpDisplayName)
3447 {
3448 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3449 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3450 if (!lpDisplayNameW)
3451 {
3452 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3453 goto cleanup;
3454 }
3455 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3456 }
3457
3458 if (lpBinaryPathName)
3459 {
3460 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3461 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3462 if (!lpBinaryPathNameW)
3463 {
3464 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3465 goto cleanup;
3466 }
3467 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3468 }
3469
3470 if (lpLoadOrderGroup)
3471 {
3472 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3473 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3474 if (!lpLoadOrderGroupW)
3475 {
3476 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3477 goto cleanup;
3478 }
3479 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3480 }
3481
3482 if (lpDependencies)
3483 {
3484 lpStr = (LPCSTR)lpDependencies;
3485 while (*lpStr)
3486 {
3487 cchLength = strlen(lpStr) + 1;
3488 dwDependenciesLength += (DWORD)cchLength;
3489 lpStr = lpStr + cchLength;
3490 }
3491 dwDependenciesLength++;
3492
3493 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3494 if (!lpDependenciesW)
3495 {
3496 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3497 goto cleanup;
3498 }
3499 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3500 }
3501
3502 if (lpServiceStartName)
3503 {
3504 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3505 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3506 if (!lpServiceStartNameW)
3507 {
3508 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3509 goto cleanup;
3510 }
3511 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3512 }
3513
3514 dwError = RCreateServiceW(hSCManager,
3515 lpServiceNameW,
3516 lpDisplayNameW,
3517 dwDesiredAccess,
3518 dwServiceType,
3519 dwStartType,
3520 dwErrorControl,
3521 lpBinaryPathNameW,
3522 lpLoadOrderGroupW,
3523 lpdwTagId,
3524 (LPBYTE)lpDependenciesW,
3525 dwDependenciesLength,
3526 lpServiceStartNameW,
3527 lpPassword,
3528 dwPwSize,
3529 lpServiceHandle);
3530
3531 cleanup:
3532 if (lpServiceNameW !=NULL)
3533 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3534
3535 if (lpDisplayNameW != NULL)
3536 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3537
3538 if (lpBinaryPathNameW != NULL)
3539 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3540
3541 if (lpLoadOrderGroupW != NULL)
3542 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3543
3544 if (lpDependenciesW != NULL)
3545 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3546
3547 if (lpServiceStartNameW != NULL)
3548 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3549
3550 return dwError;
3551 }
3552
3553
3554 /* Function 25 */
3555 DWORD REnumDependentServicesA(
3556 SC_RPC_HANDLE hService,
3557 DWORD dwServiceState,
3558 LPBYTE lpServices,
3559 DWORD cbBufSize,
3560 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3561 LPBOUNDED_DWORD_256K lpServicesReturned)
3562 {
3563 DWORD dwError = ERROR_SUCCESS;
3564 DWORD dwServicesReturned = 0;
3565 DWORD dwServiceCount;
3566 HKEY hServicesKey = NULL;
3567 PSERVICE_HANDLE hSvc;
3568 PSERVICE lpService = NULL;
3569 PSERVICE *lpServicesArray = NULL;
3570 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3571 LPSTR lpStr;
3572
3573 *pcbBytesNeeded = 0;
3574 *lpServicesReturned = 0;
3575
3576 DPRINT("REnumDependentServicesA() called\n");
3577
3578 hSvc = ScmGetServiceFromHandle(hService);
3579 if (hSvc == NULL)
3580 {
3581 DPRINT1("Invalid service handle!\n");
3582 return ERROR_INVALID_HANDLE;
3583 }
3584
3585 lpService = hSvc->ServiceEntry;
3586
3587 /* Check access rights */
3588 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3589 SC_MANAGER_ENUMERATE_SERVICE))
3590 {
3591 DPRINT("Insufficient access rights! 0x%lx\n",
3592 hSvc->Handle.DesiredAccess);
3593 return ERROR_ACCESS_DENIED;
3594 }
3595
3596 /* Open the Services Reg key */
3597 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3598 L"System\\CurrentControlSet\\Services",
3599 0,
3600 KEY_READ,
3601 &hServicesKey);
3602
3603 if (dwError != ERROR_SUCCESS)
3604 return dwError;
3605
3606 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3607 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3608 are the same for both. Verified in WINXP. */
3609
3610 /* First determine the bytes needed and get the number of dependent services*/
3611 dwError = Int_EnumDependentServicesW(hServicesKey,
3612 lpService,
3613 dwServiceState,
3614 NULL,
3615 pcbBytesNeeded,
3616 &dwServicesReturned);
3617 if (dwError != ERROR_SUCCESS)
3618 goto Done;
3619
3620 /* If buffer size is less than the bytes needed or pointer is null*/
3621 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3622 {
3623 dwError = ERROR_MORE_DATA;
3624 goto Done;
3625 }
3626
3627 /* Allocate memory for array of service pointers */
3628 lpServicesArray = HeapAlloc(GetProcessHeap(),
3629 HEAP_ZERO_MEMORY,
3630 (dwServicesReturned + 1) * sizeof(PSERVICE));
3631 if (!lpServicesArray)
3632 {
3633 DPRINT("Could not allocate a buffer!!\n");
3634 dwError = ERROR_NOT_ENOUGH_MEMORY;
3635 goto Done;
3636 }
3637
3638 dwServicesReturned = 0;
3639 *pcbBytesNeeded = 0;
3640
3641 dwError = Int_EnumDependentServicesW(hServicesKey,
3642 lpService,
3643 dwServiceState,
3644 lpServicesArray,
3645 pcbBytesNeeded,
3646 &dwServicesReturned);
3647 if (dwError != ERROR_SUCCESS)
3648 {
3649 goto Done;
3650 }
3651
3652 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3653 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3654
3655 /* Copy EnumDepenedentService to Buffer */
3656 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3657 {
3658 lpService = lpServicesArray[dwServiceCount];
3659
3660 /* Copy the status info */
3661 memcpy(&lpServicesPtr->ServiceStatus,
3662 &lpService->Status,
3663 sizeof(SERVICE_STATUS));
3664
3665 /* Copy display name */
3666 WideCharToMultiByte(CP_ACP,
3667 0,
3668 lpService->lpDisplayName,
3669 -1,
3670 lpStr,
3671 (int)wcslen(lpService->lpDisplayName),
3672 0,
3673 0);
3674 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3675 lpStr += strlen(lpStr) + 1;
3676
3677 /* Copy service name */
3678 WideCharToMultiByte(CP_ACP,
3679 0,
3680 lpService->lpServiceName,
3681 -1,
3682 lpStr,
3683 (int)wcslen(lpService->lpServiceName),
3684 0,
3685 0);
3686 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3687 lpStr += strlen(lpStr) + 1;
3688
3689 lpServicesPtr++;
3690 }
3691
3692 *lpServicesReturned = dwServicesReturned;
3693
3694 Done:
3695 if (lpServicesArray)
3696 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3697
3698 RegCloseKey(hServicesKey);
3699
3700 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3701
3702 return dwError;
3703 }
3704
3705
3706 /* Function 26 */
3707 DWORD REnumServicesStatusA(
3708 SC_RPC_HANDLE hSCManager,
3709 DWORD dwServiceType,
3710 DWORD dwServiceState,
3711 LPBYTE lpBuffer,
3712 DWORD dwBufSize,
3713 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3714 LPBOUNDED_DWORD_256K lpServicesReturned,
3715 LPBOUNDED_DWORD_256K lpResumeHandle)
3716 {
3717 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3718 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW;
3719 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3720 LPWSTR lpStringPtrW;
3721 LPSTR lpStringPtrA;
3722 DWORD dwError;
3723 DWORD dwServiceCount;
3724
3725 DPRINT("REnumServicesStatusA() called\n");
3726
3727 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
3728 {
3729 return ERROR_INVALID_ADDRESS;
3730 }
3731
3732 if ((dwBufSize > 0) && (lpBuffer))
3733 {
3734 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3735 if (!lpStatusPtrW)
3736 {
3737 DPRINT("Failed to allocate buffer!\n");
3738 return ERROR_NOT_ENOUGH_MEMORY;
3739 }
3740 }
3741
3742 dwError = REnumServicesStatusW(hSCManager,
3743 dwServiceType,
3744 dwServiceState,
3745 (LPBYTE)lpStatusPtrW,
3746 dwBufSize,
3747 pcbBytesNeeded,
3748 lpServicesReturned,
3749 lpResumeHandle);
3750
3751 /* if no services were returned then we are Done */
3752 if (*lpServicesReturned == 0)
3753 goto Done;
3754
3755 lpStatusPtrIncrW = lpStatusPtrW;
3756 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3757 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3758 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3759 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3760 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3761
3762 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3763 {
3764 /* Copy the service name */
3765 WideCharToMultiByte(CP_ACP,
3766 0,
3767 lpStringPtrW,
3768 -1,
3769 lpStringPtrA,
3770 (int)wcslen(lpStringPtrW),
3771 0,
3772 0);
3773
3774 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3775 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3776 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3777
3778 /* Copy the display name */
3779 WideCharToMultiByte(CP_ACP,
3780 0,
3781 lpStringPtrW,
3782 -1,
3783 lpStringPtrA,
3784 (int)wcslen(lpStringPtrW),
3785 0,
3786 0);
3787
3788 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3789 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3790 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3791
3792 /* Copy the status information */
3793 memcpy(&lpStatusPtrA->ServiceStatus,
3794 &lpStatusPtrIncrW->ServiceStatus,
3795 sizeof(SERVICE_STATUS));
3796
3797 lpStatusPtrIncrW++;
3798 lpStatusPtrA++;
3799 }
3800
3801 Done:
3802 if (lpStatusPtrW)
3803 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3804
3805 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3806
3807 return dwError;
3808 }
3809
3810
3811 /* Function 27 */
3812 DWORD ROpenSCManagerA(
3813 LPSTR lpMachineName,
3814 LPSTR lpDatabaseName,
3815 DWORD dwDesiredAccess,
3816 LPSC_RPC_HANDLE lpScHandle)
3817 {
3818 UNICODE_STRING MachineName;
3819 UNICODE_STRING DatabaseName;
3820 DWORD dwError;
3821
3822 DPRINT("ROpenSCManagerA() called\n");
3823
3824 if (lpMachineName)
3825 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3826 lpMachineName);
3827
3828 if (lpDatabaseName)
3829 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3830 lpDatabaseName);
3831
3832 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
3833 lpDatabaseName ? DatabaseName.Buffer : NULL,
3834 dwDesiredAccess,
3835 lpScHandle);
3836
3837 if (lpMachineName)
3838 RtlFreeUnicodeString(&MachineName);
3839
3840 if (lpDatabaseName)
3841 RtlFreeUnicodeString(&DatabaseName);
3842
3843 return dwError;
3844 }
3845
3846
3847 /* Function 28 */
3848 DWORD ROpenServiceA(
3849 SC_RPC_HANDLE hSCManager,
3850 LPSTR lpServiceName,
3851 DWORD dwDesiredAccess,
3852 LPSC_RPC_HANDLE lpServiceHandle)
3853 {
3854 UNICODE_STRING ServiceName;
3855 DWORD dwError;
3856
3857 DPRINT("ROpenServiceA() called\n");
3858
3859 if (lpServiceName)
3860 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3861 lpServiceName);
3862
3863 dwError = ROpenServiceW(hSCManager,
3864 lpServiceName ? ServiceName.Buffer : NULL,
3865 dwDesiredAccess,
3866 lpServiceHandle);
3867
3868 if (lpServiceName)
3869 RtlFreeUnicodeString(&ServiceName);
3870
3871 return dwError;
3872 }
3873
3874
3875 /* Function 29 */
3876 DWORD RQueryServiceConfigA(
3877 SC_RPC_HANDLE hService,
3878 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3879 DWORD cbBufSize,
3880 LPBOUNDED_DWORD_8K pcbBytesNeeded)
3881 {
3882 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
3883 DWORD dwError = ERROR_SUCCESS;
3884 PSERVICE_HANDLE hSvc;
3885 PSERVICE lpService = NULL;
3886 HKEY hServiceKey = NULL;
3887 LPWSTR lpImagePath = NULL;
3888 LPWSTR lpServiceStartName = NULL;
3889 LPWSTR lpDependencies = NULL;
3890 DWORD dwDependenciesLength = 0;
3891 DWORD dwRequiredSize;
3892 CHAR lpEmptyString[]={0,0};
3893 LPSTR lpStr;
3894
3895 DPRINT("RQueryServiceConfigA() called\n");
3896
3897 if (ScmShutdown)
3898 return ERROR_SHUTDOWN_IN_PROGRESS;
3899
3900 hSvc = ScmGetServiceFromHandle(hService);
3901 if (hSvc == NULL)
3902 {
3903 DPRINT1("Invalid service handle!\n");
3904 return ERROR_INVALID_HANDLE;
3905 }
3906
3907 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3908 SERVICE_QUERY_CONFIG))
3909 {
3910 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3911 return ERROR_ACCESS_DENIED;
3912 }
3913
3914 lpService = hSvc->ServiceEntry;
3915 if (lpService == NULL)
3916 {
3917 DPRINT("lpService == NULL!\n");
3918 return ERROR_INVALID_HANDLE;
3919 }
3920
3921 /* Lock the service database shared */
3922 ScmLockDatabaseShared();
3923
3924 dwError = ScmOpenServiceKey(lpService->lpServiceName,
3925 KEY_READ,
3926 &hServiceKey);
3927 if (dwError != ERROR_SUCCESS)
3928 goto Done;
3929
3930 /* Read the image path */
3931 dwError = ScmReadString(hServiceKey,
3932 L"ImagePath",
3933 &lpImagePath);
3934 if (dwError != ERROR_SUCCESS)
3935 goto Done;
3936
3937 /* Read the service start name */
3938 ScmReadString(hServiceKey,
3939 L"ObjectName",
3940 &lpServiceStartName);
3941
3942 /* Read the dependencies */
3943 ScmReadDependencies(hServiceKey,
3944 &lpDependencies,
3945 &dwDependenciesLength);
3946
3947 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGA);
3948
3949 if (lpImagePath != NULL)
3950 dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
3951 else
3952 dwRequiredSize += 2;
3953
3954 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3955 dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
3956 else
3957 dwRequiredSize += 2;
3958
3959 /* Add Dependencies length */
3960 if (lpDependencies != NULL)
3961 dwRequiredSize += dwDependenciesLength;
3962 else
3963 dwRequiredSize += 2;
3964
3965 if (lpServiceStartName != NULL)
3966 dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
3967 else
3968 dwRequiredSize += 2;
3969
3970 if (lpService->lpDisplayName != NULL)
3971 dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
3972 else
3973 dwRequiredSize += 2;
3974
3975 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3976 {
3977 dwError = ERROR_INSUFFICIENT_BUFFER;
3978 }
3979 else
3980 {
3981 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
3982 lpServiceConfig->dwStartType = lpService->dwStartType;
3983 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
3984 lpServiceConfig->dwTagId = lpService->dwTag;
3985
3986 lpStr = (LPSTR)(lpServiceConfig + 1);
3987
3988 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
3989 Verified in WINXP */
3990
3991 if (lpImagePath)
3992 {
3993 WideCharToMultiByte(CP_ACP,
3994 0,
3995 lpImagePath,
3996 -1,
3997 lpStr,
3998 (int)(wcslen(lpImagePath) + 1),
3999 0,
4000 0);
4001 }
4002 else
4003 {
4004 strcpy(lpStr, lpEmptyString);
4005 }
4006
4007 lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4008 lpStr += (strlen((LPSTR)lpStr) + 1);
4009
4010 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4011 {
4012 WideCharToMultiByte(CP_ACP,
4013 0,
4014 lpService->lpGroup->lpGroupName,
4015 -1,
4016 lpStr,
4017 (int)(wcslen(lpService->lpGroup->lpGroupName) + 1),
4018 0,
4019 0);
4020 }
4021 else
4022 {
4023 strcpy(lpStr, lpEmptyString);
4024 }
4025
4026 lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4027 lpStr += (strlen(lpStr) + 1);
4028
4029 /* Append Dependencies */
4030 if (lpDependencies)
4031 {
4032 WideCharToMultiByte(CP_ACP,
4033 0,
4034 lpDependencies,
4035 dwDependenciesLength,
4036 lpStr,
4037 dwDependenciesLength,
4038 0,
4039 0);
4040 }
4041 else
4042 {
4043 strcpy(lpStr, lpEmptyString);
4044 }
4045
4046 lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4047 if (lpDependencies)
4048 lpStr += dwDependenciesLength;
4049 else
4050 lpStr += (strlen(lpStr) + 1);
4051
4052 if (lpServiceStartName)
4053 {
4054 WideCharToMultiByte(CP_ACP,
4055 0,
4056 lpServiceStartName,
4057 -1,
4058 lpStr,
4059 (int)(wcslen(lpServiceStartName) + 1),
4060 0,
4061 0);
4062 }
4063 else
4064 {
4065 strcpy(lpStr, lpEmptyString);
4066 }
4067
4068 lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4069 lpStr += (strlen(lpStr) + 1);
4070
4071 if (lpService->lpDisplayName)
4072 {
4073 WideCharToMultiByte(CP_ACP,
4074 0,
4075 lpService->lpDisplayName,
4076 -1,
4077 lpStr,
4078 (int)(wcslen(lpService->lpDisplayName) + 1),
4079 0,
4080 0);
4081 }
4082 else
4083 {
4084 strcpy(lpStr, lpEmptyString);
4085 }
4086
4087 lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4088 }
4089
4090 if (pcbBytesNeeded != NULL)
4091 *pcbBytesNeeded = dwRequiredSize;
4092
4093 Done:
4094 /* Unlock the service database */
4095 ScmUnlockDatabase();
4096
4097 if (lpImagePath != NULL)
4098 HeapFree(GetProcessHeap(), 0, lpImagePath);
4099
4100 if (lpServiceStartName != NULL)
4101 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4102
4103 if (lpDependencies != NULL)
4104 HeapFree(GetProcessHeap(), 0, lpDependencies);
4105
4106 if (hServiceKey != NULL)
4107 RegCloseKey(hServiceKey);
4108
4109 DPRINT("RQueryServiceConfigA() done\n");
4110
4111 return dwError;
4112 }
4113
4114
4115 /* Function 30 */
4116 DWORD RQueryServiceLockStatusA(
4117 SC_RPC_HANDLE hSCManager,
4118 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4119 DWORD cbBufSize,
4120 LPBOUNDED_DWORD_4K pcbBytesNeeded)
4121 {
4122 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSA)lpBuf;
4123 PMANAGER_HANDLE hMgr;
4124 DWORD dwRequiredSize;
4125
4126 if (!lpLockStatus || !pcbBytesNeeded)
4127 return ERROR_INVALID_PARAMETER;
4128
4129 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
4130 if (hMgr == NULL)
4131 {
4132 DPRINT1("Invalid service manager handle!\n");
4133 return ERROR_INVALID_HANDLE;
4134 }
4135
4136 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
4137 SC_MANAGER_QUERY_LOCK_STATUS))
4138 {
4139 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
4140 return ERROR_ACCESS_DENIED;
4141 }
4142
4143 /* FIXME: we need to compute instead the real length of the owner name */
4144 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR);
4145 *pcbBytesNeeded = dwRequiredSize;
4146
4147 if (cbBufSize < dwRequiredSize)
4148 return ERROR_INSUFFICIENT_BUFFER;
4149
4150 ScmQueryServiceLockStatusA(lpLockStatus);
4151
4152 return ERROR_SUCCESS;
4153 }
4154
4155
4156 /* Function 31 */
4157 DWORD RStartServiceA(
4158 SC_RPC_HANDLE hService,
4159 DWORD argc,
4160 LPSTRING_PTRSA argv)
4161 {
4162 DWORD dwError = ERROR_SUCCESS;
4163 PSERVICE_HANDLE hSvc;
4164 PSERVICE lpService = NULL;
4165 LPWSTR *lpVector = NULL;
4166 DWORD i;
4167 DWORD dwLength;
4168
4169 DPRINT("RStartServiceA() called\n");
4170
4171 if (ScmShutdown)
4172 return ERROR_SHUTDOWN_IN_PROGRESS;
4173
4174 hSvc = ScmGetServiceFromHandle(hService);
4175 if (hSvc == NULL)
4176 {
4177 DPRINT1("Invalid service handle!\n");
4178 return ERROR_INVALID_HANDLE;
4179 }
4180
4181 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4182 SERVICE_START))
4183 {
4184 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4185 return ERROR_ACCESS_DENIED;
4186 }
4187
4188 lpService = hSvc->ServiceEntry;
4189 if (lpService == NULL)
4190 {
4191 DPRINT("lpService == NULL!\n");
4192 return ERROR_INVALID_HANDLE;
4193 }
4194
4195 if (lpService->dwStartType == SERVICE_DISABLED)
4196 return ERROR_SERVICE_DISABLED;
4197
4198 if (lpService->bDeleted)
4199 return ERROR_SERVICE_MARKED_FOR_DELETE;
4200
4201 /* Build a Unicode argument vector */
4202 if (argc > 0)
4203 {
4204 lpVector = HeapAlloc(GetProcessHeap(),
4205 HEAP_ZERO_MEMORY,
4206 argc * sizeof(LPWSTR));
4207 if (lpVector == NULL)
4208 return ERROR_NOT_ENOUGH_MEMORY;
4209
4210 for (i = 0; i < argc; i++)
4211 {
4212 dwLength = MultiByteToWideChar(CP_ACP,
4213 0,
4214 ((LPSTR*)argv)[i],
4215 -1,
4216 NULL,
4217 0);
4218
4219 lpVector[i] = HeapAlloc(GetProcessHeap(),
4220 HEAP_ZERO_MEMORY,
4221 dwLength * sizeof(WCHAR));
4222 if (lpVector[i] == NULL)
4223 {
4224 dwError = ERROR_NOT_ENOUGH_MEMORY;
4225 goto done;
4226 }
4227
4228 MultiByteToWideChar(CP_ACP,
4229 0,
4230 ((LPSTR*)argv)[i],
4231 -1,
4232 lpVector[i],
4233 dwLength);
4234 }
4235 }
4236
4237 /* Start the service */
4238 dwError = ScmStartService(lpService, argc, lpVector);
4239
4240 done:
4241 /* Free the Unicode argument vector */
4242 if (lpVector != NULL)
4243 {
4244 for (i = 0; i < argc; i++)
4245 {
4246 if (lpVector[i] != NULL)
4247 HeapFree(GetProcessHeap(), 0, lpVector[i]);
4248 }
4249 HeapFree(GetProcessHeap(), 0, lpVector);
4250 }
4251
4252 return dwError;
4253 }
4254
4255
4256 /* Function 32 */
4257 DWORD RGetServiceDisplayNameA(
4258 SC_RPC_HANDLE hSCManager,
4259 LPCSTR lpServiceName,
4260 LPSTR lpDisplayName,
4261 LPBOUNDED_DWORD_4K lpcchBuffer)
4262 {
4263 // PMANAGER_HANDLE hManager;
4264 PSERVICE lpService = NULL;
4265 DWORD dwLength;
4266 DWORD dwError;
4267 LPWSTR lpServiceNameW;
4268
4269 DPRINT("RGetServiceDisplayNameA() called\n");
4270 DPRINT("hSCManager = %p\n", hSCManager);
4271 DPRINT("lpServiceName: %s\n", lpServiceName);
4272 DPRINT("lpDisplayName: %p\n", lpDisplayName);
4273 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4274
4275 // hManager = (PMANAGER_HANDLE)hSCManager;
4276 // if (hManager->Handle.Tag != MANAGER_TAG)
4277 // {
4278 // DPRINT("Invalid manager handle!\n");
4279 // return ERROR_INVALID_HANDLE;
4280 // }
4281
4282 if (lpServiceName != NULL)
4283 {
4284 dwLength = (DWORD)(strlen(lpServiceName) + 1);
4285 lpServiceNameW = HeapAlloc(GetProcessHeap(),
4286 HEAP_ZERO_MEMORY,
4287 dwLength * sizeof(WCHAR));
4288 if (!lpServiceNameW)
4289 return ERROR_NOT_ENOUGH_MEMORY;
4290
4291 MultiByteToWideChar(CP_ACP,
4292 0,
4293 lpServiceName,
4294 -1,
4295 lpServiceNameW,
4296 dwLength);
4297
4298 lpService = ScmGetServiceEntryByName(lpServiceNameW);
4299
4300 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4301 }
4302
4303 if (lpService == NULL)
4304 {
4305 DPRINT("Could not find a service!\n");
4306
4307 /* If the service could not be found and lpcchBuffer is 0, windows
4308 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4309 if (*lpcchBuffer == 0)
4310 {
4311 *lpcchBuffer = 1;
4312 if (lpDisplayName != NULL)
4313 {
4314 *lpDisplayName = 0;
4315 }
4316 }
4317 return ERROR_SERVICE_DOES_NOT_EXIST;
4318 }
4319
4320 if (!lpService->lpDisplayName)
4321 {
4322 dwLength = (DWORD)wcslen(lpService->lpServiceName);
4323 if (lpDisplayName != NULL &&
4324 *lpcchBuffer > dwLength)
4325 {
4326 WideCharToMultiByte(CP_ACP,
4327 0,
4328 lpService->lpServiceName,
4329 (int)wcslen(lpService->lpServiceName),
4330 lpDisplayName,
4331 dwLength + 1,
4332 NULL,
4333 NULL);
4334 return ERROR_SUCCESS;
4335 }
4336 }
4337 else
4338 {
4339 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
4340 if (lpDisplayName != NULL &&
4341 *lpcchBuffer > dwLength)
4342 {
4343 WideCharToMultiByte(CP_ACP,
4344 0,
4345 lpService->lpDisplayName,
4346 (int)wcslen(lpService->lpDisplayName),
4347 lpDisplayName,
4348 dwLength + 1,
4349 NULL,
4350 NULL);
4351 return ERROR_SUCCESS;
4352 }
4353 }
4354
4355 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4356
4357 *lpcchBuffer = dwLength * 2;
4358
4359 return dwError;
4360 }
4361
4362
4363 /* Function 33 */
4364 DWORD RGetServiceKeyNameA(
4365 SC_RPC_HANDLE hSCManager,
4366 LPCSTR lpDisplayName,
4367 LPSTR lpServiceName,
4368 LPBOUNDED_DWORD_4K lpcchBuffer)
4369 {
4370 PSERVICE lpService;
4371 DWORD dwLength;
4372 DWORD dwError;
4373 LPWSTR lpDisplayNameW;
4374
4375 DPRINT("RGetServiceKeyNameA() called\n");
4376 DPRINT("hSCManager = %p\n", hSCManager);
4377 DPRINT("lpDisplayName: %s\n", lpDisplayName);
4378 DPRINT("lpServiceName: %p\n", lpServiceName);
4379 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4380
4381 dwLength = (DWORD)(strlen(lpDisplayName) + 1);
4382 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4383 HEAP_ZERO_MEMORY,
4384 dwLength * sizeof(WCHAR));
4385 if (!lpDisplayNameW)
4386 return ERROR_NOT_ENOUGH_MEMORY;
4387
4388 MultiByteToWideChar(CP_ACP,
4389 0,
4390 lpDisplayName,
4391 -1,
4392 lpDisplayNameW,
4393 dwLength);
4394
4395 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4396
4397 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4398
4399 if (lpService == NULL)
4400 {
4401 DPRINT("Could not find the service!\n");
4402
4403 /* If the service could not be found and lpcchBuffer is 0,
4404 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4405 if (*lpcchBuffer == 0)
4406 {
4407 *lpcchBuffer = 1;
4408 if (lpServiceName != NULL)
4409 {
4410 *lpServiceName = 0;
4411 }
4412 }
4413
4414 return ERROR_SERVICE_DOES_NOT_EXIST;
4415 }
4416
4417 dwLength = (DWORD)wcslen(lpService->lpServiceName);
4418 if (lpServiceName != NULL &&
4419 *lpcchBuffer > dwLength)
4420 {
4421 WideCharToMultiByte(CP_ACP,
4422 0,
4423 lpService->lpServiceName,
4424 (int)wcslen(lpService->lpServiceName),
4425 lpServiceName,
4426 dwLength + 1,
4427 NULL,
4428 NULL);
4429 return ERROR_SUCCESS;
4430 }
4431
4432 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4433
4434 *lpcchBuffer = dwLength * 2;
4435
4436 return dwError;
4437 }
4438
4439
4440 /* Function 34 */
4441 DWORD RI_ScGetCurrentGroupStateW(
4442 SC_RPC_HANDLE hSCManager,
4443 LPWSTR lpLoadOrderGroup,
4444 LPDWORD lpState)
4445 {
4446 UNIMPLEMENTED;
4447 return ERROR_CALL_NOT_IMPLEMENTED;
4448 }
4449
4450
4451 /* Function 35 */
4452 DWORD REnumServiceGroupW(
4453 SC_RPC_HANDLE hSCManager,
4454 DWORD dwServiceType,
4455 DWORD dwServiceState,
4456 LPBYTE lpBuffer,
4457 DWORD cbBufSize,
4458 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4459 LPBOUNDED_DWORD_256K lpServicesReturned,
4460 LPBOUNDED_DWORD_256K lpResumeIndex,
4461 LPCWSTR pszGroupName)
4462 {
4463 PMANAGER_HANDLE hManager;
4464 PSERVICE lpService;
4465 DWORD dwError = ERROR_SUCCESS;
4466 PLIST_ENTRY ServiceEntry;
4467 PSERVICE CurrentService;
4468 DWORD dwState;
4469 DWORD dwRequiredSize;
4470 DWORD dwServiceCount;
4471 DWORD dwSize;
4472 DWORD dwLastResumeCount = 0;
4473 LPENUM_SERVICE_STATUSW lpStatusPtr;
4474 LPWSTR lpStringPtr;
4475
4476 DPRINT("REnumServiceGroupW() called\n");
4477
4478 if (ScmShutdown)
4479 return ERROR_SHUTDOWN_IN_PROGRESS;
4480
4481 hManager = ScmGetServiceManagerFromHandle(hSCManager);
4482 if (hManager == NULL)
4483 {
4484 DPRINT1("Invalid service manager handle!\n");
4485 return ERROR_INVALID_HANDLE;
4486 }
4487
4488 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
4489 {
4490 return ERROR_INVALID_ADDRESS;
4491 }
4492
4493 *pcbBytesNeeded = 0;
4494 *lpServicesReturned = 0;
4495
4496 if ((dwServiceType == 0) ||
4497 ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
4498 {
4499 DPRINT("Not a valid Service Type!\n");
4500 return ERROR_INVALID_PARAMETER;
4501 }
4502
4503 if ((dwServiceState == 0) ||
4504 ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
4505 {
4506 DPRINT("Not a valid Service State!\n");
4507 return ERROR_INVALID_PARAMETER;
4508 }
4509
4510 /* Check access rights */
4511 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4512 SC_MANAGER_ENUMERATE_SERVICE))
4513 {
4514 DPRINT("Insufficient access rights! 0x%lx\n",
4515 hManager->Handle.DesiredAccess);
4516 return ERROR_ACCESS_DENIED;
4517 }
4518
4519 if (lpResumeIndex)
4520 dwLastResumeCount = *lpResumeIndex;
4521
4522 /* Lock the service database shared */
4523 ScmLockDatabaseShared();
4524
4525 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4526 if (lpService == NULL)
4527 {
4528 dwError = ERROR_SUCCESS;
4529 goto Done;
4530 }
4531
4532 dwRequiredSize = 0;
4533 dwServiceCount = 0;
4534
4535 for (ServiceEntry = &lpService->ServiceListEntry;
4536 ServiceEntry != &ServiceListHead;
4537 ServiceEntry = ServiceEntry->Flink)
4538 {
4539 CurrentService = CONTAINING_RECORD(ServiceEntry,
4540 SERVICE,
4541 ServiceListEntry);
4542
4543 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4544 continue;
4545
4546 dwState = SERVICE_ACTIVE;
4547 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4548 dwState = SERVICE_INACTIVE;
4549
4550 if ((dwState & dwServiceState) == 0)
4551 continue;
4552
4553 if (pszGroupName)
4554 {
4555 if (*pszGroupName == 0)
4556 {
4557 if (CurrentService->lpGroup != NULL)
4558 continue;
4559 }
4560 else
4561 {
4562 if ((CurrentService->lpGroup == NULL) ||
4563 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4564 continue;
4565 }
4566 }
4567
4568 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4569 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4570 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4571
4572 if (dwRequiredSize + dwSize > cbBufSize)
4573 {
4574 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4575 break;
4576 }
4577
4578 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4579 dwRequiredSize += dwSize;
4580 dwServiceCount++;
4581 dwLastResumeCount = CurrentService->dwResumeCount;
4582 }
4583
4584 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4585 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4586
4587 for (;
4588 ServiceEntry != &ServiceListHead;
4589 ServiceEntry = ServiceEntry->Flink)
4590 {
4591 CurrentService = CONTAINING_RECORD(ServiceEntry,
4592 SERVICE,
4593 ServiceListEntry);
4594
4595 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4596 continue;
4597
4598 dwState = SERVICE_ACTIVE;
4599 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4600 dwState = SERVICE_INACTIVE;
4601
4602 if ((dwState & dwServiceState) == 0)
4603 continue;
4604
4605 if (pszGroupName)
4606 {
4607 if (*pszGroupName == 0)
4608 {
4609 if (CurrentService->lpGroup != NULL)
4610 continue;
4611 }
4612 else
4613 {
4614 if ((CurrentService->lpGroup == NULL) ||
4615 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4616 continue;
4617 }
4618 }
4619
4620 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
4621 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4622 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
4623
4624 dwError = ERROR_MORE_DATA;
4625 }
4626
4627 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4628
4629 if (lpResumeIndex)
4630 *lpResumeIndex = dwLastResumeCount;
4631
4632 *lpServicesReturned = dwServiceCount;
4633 *pcbBytesNeeded = dwRequiredSize;
4634
4635 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
4636 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
4637 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
4638
4639 dwRequiredSize = 0;
4640 for (ServiceEntry = &lpService->ServiceListEntry;
4641 ServiceEntry != &ServiceListHead;
4642 ServiceEntry = ServiceEntry->Flink)
4643 {
4644 CurrentService = CONTAINING_RECORD(ServiceEntry,
4645 SERVICE,
4646 ServiceListEntry);
4647
4648 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4649 continue;
4650
4651 dwState = SERVICE_ACTIVE;
4652 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4653 dwState = SERVICE_INACTIVE;
4654
4655 if ((dwState & dwServiceState) == 0)
4656 continue;
4657
4658 if (pszGroupName)
4659 {
4660 if (*pszGroupName == 0)
4661 {
4662 if (CurrentService->lpGroup != NULL)
4663 continue;
4664 }
4665 else
4666 {
4667 if ((CurrentService->lpGroup == NULL) ||
4668 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4669 continue;
4670 }
4671 }
4672
4673 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4674 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4675 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4676
4677 if (dwRequiredSize + dwSize > cbBufSize)
4678 break;
4679
4680 /* Copy the service name */
4681 wcscpy(lpStringPtr, CurrentService->lpServiceName);
4682 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4683 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
4684
4685 /* Copy the display name */
4686 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
4687 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4688 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
4689
4690 /* Copy the status information */
4691 memcpy(&lpStatusPtr->ServiceStatus,
4692 &CurrentService->Status,
4693 sizeof(SERVICE_STATUS));
4694
4695 lpStatusPtr++;
4696 dwRequiredSize += dwSize;
4697 }
4698
4699 if (dwError == ERROR_SUCCESS)
4700 {
4701 *pcbBytesNeeded = 0;
4702 if (lpResumeIndex) *lpResumeIndex = 0;
4703 }
4704
4705 Done:
4706 /* Unlock the service database */
4707 ScmUnlockDatabase();
4708
4709 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError);
4710
4711 return dwError;
4712 }
4713
4714
4715 //
4716 // WARNING: This function is untested
4717 //
4718 /* Function 36 */
4719 DWORD RChangeServiceConfig2A(
4720 SC_RPC_HANDLE hService,
4721 SC_RPC_CONFIG_INFOA Info)
4722 {
4723 SC_RPC_CONFIG_INFOW InfoW;
4724 DWORD dwRet, dwLength;
4725 PVOID ptr = NULL;
4726
4727 DPRINT("RChangeServiceConfig2A() called\n");
4728 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4729
4730 InfoW.dwInfoLevel = Info.dwInfoLevel;
4731
4732 if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4733 {
4734 LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
4735 //LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
4736
4737 //lpServiceDescriptonA = Info.psd;
4738
4739 ///if (lpServiceDescriptonA &&
4740 ///lpServiceDescriptonA->lpDescription)
4741 ///{
4742 dwLength = (DWORD)((strlen(Info.lpDescription) + 1) * sizeof(WCHAR));
4743
4744 lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
4745 HEAP_ZERO_MEMORY,
4746 dwLength + sizeof(SERVICE_DESCRIPTIONW));
4747 if (!lpServiceDescriptonW)
4748 {
4749 return ERROR_NOT_ENOUGH_MEMORY;
4750 }
4751
4752 lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
4753
4754 MultiByteToWideChar(CP_ACP,
4755 0,
4756 Info.lpDescription,
4757 -1,
4758 lpServiceDescriptonW->lpDescription,
4759 dwLength);
4760
4761 ptr = lpServiceDescriptonW;
4762 InfoW.psd = lpServiceDescriptonW;
4763 ///}
4764 }
4765 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4766 {
4767 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
4768 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
4769 DWORD dwRebootLen = 0;
4770 DWORD dwCommandLen = 0;
4771
4772 lpServiceFailureActionsA = Info.psfa;
4773
4774 if (lpServiceFailureActionsA)
4775 {
4776 if (lpServiceFailureActionsA->lpRebootMsg)
4777 {
4778 dwRebootLen = (DWORD)((strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR));
4779 }
4780 if (lpServiceFailureActionsA->lpCommand)
4781 {
4782 dwCommandLen = (DWORD)((strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR));
4783 }
4784 dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
4785
4786 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
4787 HEAP_ZERO_MEMORY,
4788 dwLength);
4789 if (!lpServiceFailureActionsW)
4790 {
4791 return ERROR_NOT_ENOUGH_MEMORY;
4792 }
4793
4794 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
4795 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
4796 CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
4797
4798 if (lpServiceFailureActionsA->lpRebootMsg)
4799 {
4800 MultiByteToWideChar(CP_ACP,
4801 0,
4802 lpServiceFailureActionsA->lpRebootMsg,
4803 -1,
4804 lpServiceFailureActionsW->lpRebootMsg,
4805 dwRebootLen);
4806 }
4807
4808 if (lpServiceFailureActionsA->lpCommand)
4809 {
4810 MultiByteToWideChar(CP_ACP,
4811 0,
4812 lpServiceFailureActionsA->lpCommand,
4813 -1,
4814 lpServiceFailureActionsW->lpCommand,
4815 dwCommandLen);
4816 }
4817
4818 ptr = lpServiceFailureActionsW;
4819 }
4820 }
4821
4822 dwRet = RChangeServiceConfig2W(hService, InfoW);
4823
4824 HeapFree(GetProcessHeap(), 0, ptr);
4825
4826 return dwRet;
4827 }
4828
4829
4830 static DWORD
4831 ScmSetFailureActions(PSERVICE_HANDLE hSvc,
4832 PSERVICE lpService,
4833 HKEY hServiceKey,
4834 LPSERVICE_FAILURE_ACTIONSW lpFailureActions)
4835 {
4836 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer = NULL;
4837 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer = NULL;
4838 BOOL bIsActionRebootSet = FALSE;
4839 DWORD dwDesiredAccess = SERVICE_CHANGE_CONFIG;
4840 DWORD dwRequiredSize = 0;
4841 DWORD dwType = 0;
4842 DWORD i = 0;
4843 DWORD dwError;
4844
4845 /* There is nothing to be done if we have no failure actions */
4846 if (lpFailureActions == NULL)
4847 return ERROR_SUCCESS;
4848
4849 /*
4850 * 1- Check whether or not we can set
4851 * failure actions for this service.
4852 */
4853
4854 /* Failure actions can only be set for Win32 services, not for drivers */
4855 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
4856 return ERROR_CANNOT_DETECT_DRIVER_FAILURE;
4857
4858 /*
4859 * If the service controller handles the SC_ACTION_RESTART action,
4860 * hService must have the SERVICE_START access right.
4861 *
4862 * If you specify SC_ACTION_REBOOT, the caller must have the
4863 * SE_SHUTDOWN_NAME privilege.
4864 */
4865 if (lpFailureActions->cActions > 0 &&
4866 lpFailureActions->lpsaActions != NULL)
4867 {
4868 for (i = 0; i < lpFailureActions->cActions; ++i)
4869 {
4870 if (lpFailureActions->lpsaActions[i].Type == SC_ACTION_RESTART)
4871 dwDesiredAccess |= SERVICE_START;
4872 else if (lpFailureActions->lpsaActions[i].Type == SC_ACTION_REBOOT)
4873 bIsActionRebootSet = TRUE;
4874 }
4875 }
4876
4877 /* Re-check the access rights */
4878 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4879 dwDesiredAccess))
4880 {
4881 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4882 return ERROR_ACCESS_DENIED;
4883 }
4884
4885 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
4886 if (bIsActionRebootSet)
4887 {
4888 }
4889
4890 /*
4891 * 2- Retrieve the original value of FailureActions.
4892 */
4893
4894 /* Query value length */
4895 dwError = RegQueryValueExW(hServiceKey,
4896 L"FailureActions",
4897 NULL,
4898 &dwType,
4899 NULL,
4900 &dwRequiredSize);
4901 if (dwError != ERROR_SUCCESS &&
4902 dwError != ERROR_MORE_DATA &&
4903 dwError != ERROR_FILE_NOT_FOUND)
4904 return dwError;
4905
4906 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
4907 : sizeof(SERVICE_FAILURE_ACTIONSW);
4908
4909 /* Initialize the read buffer */
4910 lpReadBuffer = HeapAlloc(GetProcessHeap(),
4911 HEAP_ZERO_MEMORY,
4912 dwRequiredSize);
4913 if (lpReadBuffer == NULL)
4914 return ERROR_NOT_ENOUGH_MEMORY;
4915
4916 /* Now we can fill the read buffer */
4917 if (dwError != ERROR_FILE_NOT_FOUND &&
4918 dwType == REG_BINARY)
4919 {
4920 dwError = RegQueryValueExW(hServiceKey,
4921 L"FailureActions",
4922 NULL,
4923 NULL,
4924 (LPBYTE)lpReadBuffer,
4925 &dwRequiredSize);
4926 if (dwError != ERROR_SUCCESS &&
4927 dwError != ERROR_FILE_NOT_FOUND)
4928 goto done;
4929
4930 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
4931 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
4932 }
4933 else
4934 {
4935 /*
4936 * The value of the error doesn't really matter, the only
4937 * important thing is that it must be != ERROR_SUCCESS.
4938 */
4939 dwError = ERROR_INVALID_DATA;
4940 }
4941
4942 if (dwError == ERROR_SUCCESS)
4943 {
4944 lpReadBuffer->cActions = min(lpReadBuffer->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
4945 lpReadBuffer->lpsaActions = (lpReadBuffer->cActions > 0 ? (LPSC_ACTION)(lpReadBuffer + 1) : NULL);
4946 }
4947 else
4948 {
4949 lpReadBuffer->dwResetPeriod = 0;
4950 lpReadBuffer->cActions = 0;
4951 lpReadBuffer->lpsaActions = NULL;
4952 }
4953
4954 lpReadBuffer->lpRebootMsg = NULL;
4955 lpReadBuffer->lpCommand = NULL;
4956
4957 /*
4958 * 3- Initialize the new value to set.
4959 */
4960
4961 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
4962
4963 if (lpFailureActions->lpsaActions == NULL)
4964 {
4965 /*
4966 * lpFailureActions->cActions is ignored.
4967 * Therefore we use the original values
4968 * of cActions and lpsaActions.
4969 */
4970 dwRequiredSize += lpReadBuffer->cActions * sizeof(SC_ACTION);
4971 }
4972 else
4973 {
4974 /*
4975 * The reset period and array of failure actions
4976 * are deleted if lpFailureActions->cActions == 0 .
4977 */
4978 dwRequiredSize += lpFailureActions->cActions * sizeof(SC_ACTION);
4979 }
4980
4981 lpWriteBuffer = HeapAlloc(GetProcessHeap(),
4982 HEAP_ZERO_MEMORY,
4983 dwRequiredSize);
4984 if (lpWriteBuffer == NULL)
4985 {
4986 dwError = ERROR_NOT_ENOUGH_MEMORY;
4987 goto done;
4988 }
4989
4990 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
4991 lpWriteBuffer->lpRebootMsg = NULL;
4992 lpWriteBuffer->lpCommand = NULL;
4993 lpWriteBuffer->lpsaActions = NULL;
4994
4995 /* Set the members */
4996 if (lpFailureActions->lpsaActions == NULL)
4997 {
4998 /*
4999 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5000 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5001 */
5002 lpWriteBuffer->dwResetPeriod = lpReadBuffer->dwResetPeriod;
5003 lpWriteBuffer->cActions = lpReadBuffer->cActions;
5004
5005 if (lpReadBuffer->lpsaActions != NULL)
5006 {
5007 memmove(lpWriteBuffer + 1,
5008 lpReadBuffer->lpsaActions,
5009 lpReadBuffer->cActions * sizeof(SC_ACTION));
5010 }
5011 }
5012 else
5013 {
5014 if (lpFailureActions->cActions > 0)
5015 {
5016 lpWriteBuffer->dwResetPeriod = lpFailureActions->dwResetPeriod;
5017 lpWriteBuffer->cActions = lpFailureActions->cActions;
5018
5019 memmove(lpWriteBuffer + 1,
5020 lpFailureActions->lpsaActions,
5021 lpFailureActions->cActions * sizeof(SC_ACTION));
5022 }
5023 else
5024 {
5025 /* The reset period and array of failure actions are deleted */
5026 lpWriteBuffer->dwResetPeriod = 0;
5027 lpWriteBuffer->cActions = 0;
5028 }
5029 }
5030
5031 /* Save the new failure actions into the registry */
5032 dwError = RegSetValueExW(hServiceKey,
5033 L"FailureActions",
5034 0,
5035 REG_BINARY,
5036 (LPBYTE)lpWriteBuffer,
5037 dwRequiredSize);
5038
5039 /* We modify the strings only in case of success.*/
5040 if (dwError == ERROR_SUCCESS)
5041 {
5042 /* Modify the Reboot Message value, if specified */
5043 if (lpFailureActions->lpRebootMsg != NULL)
5044 {
5045 /* If the Reboot Message is "" then we delete it */
5046 if (*lpFailureActions->lpRebootMsg == 0)
5047 {
5048 DPRINT("Delete Reboot Message value\n");
5049 RegDeleteValueW(hServiceKey, L"RebootMessage");
5050 }
5051 else
5052 {
5053 DPRINT("Setting Reboot Message value %S\n", lpFailureActions->lpRebootMsg);
5054 RegSetValueExW(hServiceKey,
5055 L"RebootMessage",
5056 0,
5057 REG_SZ,
5058 (LPBYTE)lpFailureActions->lpRebootMsg,
5059 (DWORD)((wcslen(lpFailureActions->lpRebootMsg) + 1) * sizeof(WCHAR)));
5060 }
5061 }
5062
5063 /* Modify the Failure Command value, if specified */
5064 if (lpFailureActions->lpCommand != NULL)
5065 {
5066 /* If the FailureCommand string is an empty string, delete the value */
5067 if (*lpFailureActions->lpCommand == 0)
5068 {
5069 DPRINT("Delete Failure Command value\n");
5070 RegDeleteValueW(hServiceKey, L"FailureCommand");
5071 }
5072 else
5073 {
5074 DPRINT("Setting Failure Command value %S\n", lpFailureActions->lpCommand);
5075 RegSetValueExW(hServiceKey,
5076 L"FailureCommand",
5077 0,
5078 REG_SZ,
5079 (LPBYTE)lpFailureActions->lpCommand,
5080 (DWORD)((wcslen(lpFailureActions->lpCommand) + 1) * sizeof(WCHAR)));
5081 }
5082 }
5083 }
5084
5085 done:
5086 if (lpWriteBuffer != NULL)
5087 HeapFree(GetProcessHeap(), 0, lpWriteBuffer);
5088
5089 if (lpReadBuffer != NULL)
5090 HeapFree(GetProcessHeap(), 0, lpReadBuffer);
5091
5092 return dwError;
5093 }
5094
5095
5096 /* Function 37 */
5097 DWORD RChangeServiceConfig2W(
5098 SC_RPC_HANDLE hService,
5099 SC_RPC_CONFIG_INFOW Info)
5100 {
5101 DWORD dwError = ERROR_SUCCESS;
5102 PSERVICE_HANDLE hSvc;
5103 PSERVICE lpService = NULL;
5104 HKEY hServiceKey = NULL;
5105
5106 DPRINT("RChangeServiceConfig2W() called\n");
5107 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
5108
5109 if (ScmShutdown)
5110 return ERROR_SHUTDOWN_IN_PROGRESS;
5111
5112 hSvc = ScmGetServiceFromHandle(hService);
5113 if (hSvc == NULL)
5114 {
5115 DPRINT1("Invalid service handle!\n");
5116 return ERROR_INVALID_HANDLE;
5117 }
5118
5119 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5120 SERVICE_CHANGE_CONFIG))
5121 {
5122 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5123 return ERROR_ACCESS_DENIED;
5124 }
5125
5126 lpService = hSvc->ServiceEntry;
5127 if (lpService == NULL)
5128 {
5129 DPRINT("lpService == NULL!\n");
5130 return ERROR_INVALID_HANDLE;
5131 }
5132
5133 /* Lock the service database exclusively */
5134 ScmLockDatabaseExclusive();
5135
5136 if (lpService->bDeleted)
5137 {
5138 DPRINT("The service has already been marked for delete!\n");
5139 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
5140 goto done;
5141 }
5142
5143 /* Open the service key */
5144 dwError = ScmOpenServiceKey(lpService->szServiceName,
5145 KEY_READ | KEY_SET_VALUE,
5146 &hServiceKey);
5147 if (dwError != ERROR_SUCCESS)
5148 goto done;
5149
5150 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5151 {
5152 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
5153
5154 /* Modify the service description, if specified */
5155 if (lpServiceDescription != NULL &&
5156 lpServiceDescription->lpDescription != NULL)
5157 {
5158 /* If the description is "" then we delete it */
5159 if (*lpServiceDescription->lpDescription == 0)
5160 {
5161 DPRINT("Delete service description\n");
5162 dwError = RegDeleteValueW(hServiceKey, L"Description");
5163
5164 if (dwError == ERROR_FILE_NOT_FOUND)
5165 dwError = ERROR_SUCCESS;
5166 }
5167 else
5168 {
5169 DPRINT("Setting service description value %S\n", lpServiceDescription->lpDescription);
5170 dwError = RegSetValueExW(hServiceKey,
5171 L"Description",
5172 0,
5173 REG_SZ,
5174 (LPBYTE)lpServiceDescription->lpDescription,
5175 (DWORD)((wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR)));
5176 }
5177 }
5178 else
5179 {
5180 dwError = ERROR_SUCCESS;
5181 }
5182 }
5183 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5184 {
5185 dwError = ScmSetFailureActions(hSvc,
5186 lpService,
5187 hServiceKey,
5188 (LPSERVICE_FAILURE_ACTIONSW)Info.psfa);
5189 }
5190
5191 done:
5192 if (hServiceKey != NULL)
5193 RegCloseKey(hServiceKey);
5194
5195 /* Unlock the service database */
5196 ScmUnlockDatabase();
5197
5198 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
5199
5200 return dwError;
5201 }
5202
5203
5204 /* Function 38 */
5205 DWORD RQueryServiceConfig2A(
5206 SC_RPC_HANDLE hService,
5207 DWORD dwInfoLevel,
5208 LPBYTE lpBuffer,
5209 DWORD cbBufSize,
5210 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5211 {
5212 DWORD dwError = ERROR_SUCCESS;
5213 PSERVICE_HANDLE hSvc;
5214 PSERVICE lpService = NULL;
5215 HKEY hServiceKey = NULL;
5216 DWORD dwRequiredSize = 0;
5217 DWORD dwType = 0;
5218 LPWSTR lpDescriptionW = NULL;
5219 LPWSTR lpRebootMessageW = NULL;
5220 LPWSTR lpFailureCommandW = NULL;
5221
5222 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5223 hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
5224
5225 if (!lpBuffer)
5226 return ERROR_INVALID_ADDRESS;
5227
5228 if (ScmShutdown)
5229 return ERROR_SHUTDOWN_IN_PROGRESS;
5230
5231 hSvc = ScmGetServiceFromHandle(hService);
5232 if (hSvc == NULL)
5233 {
5234 DPRINT1("Invalid service handle!\n");
5235 return ERROR_INVALID_HANDLE;
5236 }
5237
5238 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5239 SERVICE_QUERY_CONFIG))
5240 {
5241 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5242 return ERROR_ACCESS_DENIED;
5243 }
5244
5245 lpService = hSvc->ServiceEntry;
5246 if (lpService == NULL)
5247 {
5248 DPRINT("lpService == NULL!\n");
5249 return ERROR_INVALID_HANDLE;
5250 }
5251
5252 /* Lock the service database shared */
5253 ScmLockDatabaseShared();
5254
5255 dwError = ScmOpenServiceKey(lpService->lpServiceName,
5256 KEY_READ,
5257 &hServiceKey);
5258 if (dwError != ERROR_SUCCESS)
5259 goto done;
5260
5261 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5262 {
5263 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
5264 LPSTR lpStr;
5265
5266 dwError = ScmReadString(hServiceKey,
5267 L"Description",
5268 &lpDescriptionW);
5269 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5270 goto done;
5271
5272 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
5273 if (dwError == ERROR_SUCCESS)
5274 *pcbBytesNeeded += (DWORD)((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
5275
5276 if (cbBufSize < *pcbBytesNeeded)
5277 {
5278 dwError = ERROR_INSUFFICIENT_BUFFER;
5279 goto done;
5280 }
5281
5282 if (dwError == ERROR_SUCCESS)
5283 {
5284 lpStr = (LPSTR)(lpServiceDescription + 1);
5285
5286 WideCharToMultiByte(CP_ACP,
5287 0,
5288 lpDescriptionW,
5289 -1,
5290 lpStr,
5291 (int)wcslen(lpDescriptionW),
5292 NULL,
5293 NULL);
5294 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
5295 }
5296 else
5297 {
5298 lpServiceDescription->lpDescription = NULL;
5299 dwError = ERROR_SUCCESS;
5300 }
5301 }
5302 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5303 {
5304 LPSERVICE_FAILURE_ACTIONSA lpFailureActions = (LPSERVICE_FAILURE_ACTIONSA)lpBuffer;
5305 LPSTR lpStr = NULL;
5306
5307 /* Query value length */
5308 dwError = RegQueryValueExW(hServiceKey,
5309 L"FailureActions",
5310 NULL,
5311 &dwType,
5312 NULL,
5313 &dwRequiredSize);
5314 if (dwError != ERROR_SUCCESS &&
5315 dwError != ERROR_MORE_DATA &&
5316 dwError != ERROR_FILE_NOT_FOUND)
5317 goto done;
5318
5319 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSA), dwRequiredSize)
5320 : sizeof(SERVICE_FAILURE_ACTIONSA);
5321
5322 /* Get the strings */
5323 ScmReadString(hServiceKey,
5324 L"FailureCommand",
5325 &lpFailureCommandW);
5326
5327 ScmReadString(hServiceKey,
5328 L"RebootMessage",
5329 &lpRebootMessageW);
5330
5331 if (lpRebootMessageW)
5332 dwRequiredSize += (DWORD)((wcslen(lpRebootMessageW) + 1) * sizeof(WCHAR));
5333
5334 if (lpFailureCommandW)
5335 dwRequiredSize += (DWORD)((wcslen(lpFailureCommandW) + 1) * sizeof(WCHAR));
5336
5337 if (cbBufSize < dwRequiredSize)
5338 {
5339 *pcbBytesNeeded = dwRequiredSize;
5340 dwError = ERROR_INSUFFICIENT_BUFFER;
5341 goto done;
5342 }
5343
5344 /* Now we can fill the buffer */
5345 if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY)
5346 {
5347 dwError = RegQueryValueExW(hServiceKey,
5348 L"FailureActions",
5349 NULL,
5350 NULL,
5351 (LPBYTE)lpFailureActions,
5352 &dwRequiredSize);
5353 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5354 goto done;
5355
5356 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSA))
5357 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSA);
5358 }
5359 else
5360 {
5361 /*
5362 * The value of the error doesn't really matter, the only
5363 * important thing is that it must be != ERROR_SUCCESS .
5364 */
5365 dwError = ERROR_INVALID_DATA;
5366 }
5367
5368 if (dwError == ERROR_SUCCESS)
5369 {
5370 lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSA)) / sizeof(SC_ACTION));
5371
5372 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5373 lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSA) : NULL);
5374
5375 lpStr = (LPSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION));
5376 }
5377 else
5378 {
5379 lpFailureActions->dwResetPeriod = 0;
5380 lpFailureActions->cActions = 0;
5381 lpFailureActions->lpsaActions = NULL;
5382 lpStr = (LPSTR)(lpFailureActions + 1);
5383 }
5384
5385 lpFailureActions->lpRebootMsg = NULL;
5386 lpFailureActions->lpCommand = NULL;
5387
5388 if (lpRebootMessageW)
5389 {
5390 WideCharToMultiByte(CP_ACP,
5391 0,
5392 lpRebootMessageW,
5393 -1,
5394 lpStr,
5395 (int)wcslen(lpRebootMessageW),
5396 NULL,
5397 NULL);
5398 lpFailureActions->lpRebootMsg = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5399 lpStr += strlen(lpStr) + 1;
5400 }
5401
5402 if (lpFailureCommandW)
5403 {
5404 WideCharToMultiByte(CP_ACP,
5405 0,
5406 lpFailureCommandW,
5407 -1,
5408 lpStr,
5409 (int)wcslen(lpFailureCommandW),
5410 NULL,
5411 NULL);
5412 lpFailureActions->lpCommand = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5413 /* lpStr += strlen(lpStr) + 1; */
5414 }
5415
5416 dwError = ERROR_SUCCESS;
5417 }
5418
5419 done:
5420 /* Unlock the service database */
5421 ScmUnlockDatabase();
5422
5423 if (lpDescriptionW != NULL)
5424 HeapFree(GetProcessHeap(), 0, lpDescriptionW);
5425
5426 if (lpRebootMessageW != NULL)
5427 HeapFree(GetProcessHeap(), 0, lpRebootMessageW);
5428
5429 if (lpFailureCommandW != NULL)
5430 HeapFree(GetProcessHeap(), 0, lpFailureCommandW);
5431
5432 if (hServiceKey != NULL)
5433 RegCloseKey(hServiceKey);
5434
5435 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError);
5436
5437 return dwError;
5438 }
5439
5440
5441 /* Function 39 */
5442 DWORD RQueryServiceConfig2W(
5443 SC_RPC_HANDLE hService,
5444 DWORD dwInfoLevel,
5445 LPBYTE lpBuffer,
5446 DWORD cbBufSize,
5447 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5448 {
5449 DWORD dwError = ERROR_SUCCESS;
5450 PSERVICE_HANDLE hSvc;
5451 PSERVICE lpService = NULL;
5452 HKEY hServiceKey = NULL;
5453 DWORD dwRequiredSize = 0;
5454 DWORD dwType = 0;
5455 LPWSTR lpDescription = NULL;
5456 LPWSTR lpRebootMessage = NULL;
5457 LPWSTR lpFailureCommand = NULL;
5458
5459 DPRINT("RQueryServiceConfig2W() called\n");
5460
5461 if (!lpBuffer)
5462 return ERROR_INVALID_ADDRESS;
5463
5464 if (ScmShutdown)
5465 return ERROR_SHUTDOWN_IN_PROGRESS;
5466
5467 hSvc = ScmGetServiceFromHandle(hService);
5468 if (hSvc == NULL)
5469 {
5470 DPRINT1("Invalid service handle!\n");
5471 return ERROR_INVALID_HANDLE;
5472 }
5473
5474 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5475 SERVICE_QUERY_CONFIG))
5476 {
5477 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5478 return ERROR_ACCESS_DENIED;
5479 }
5480
5481 lpService = hSvc->ServiceEntry;
5482 if (lpService == NULL)
5483 {
5484 DPRINT("lpService == NULL!\n");
5485 return ERROR_INVALID_HANDLE;
5486 }
5487
5488 /* Lock the service database shared */
5489 ScmLockDatabaseShared();
5490
5491 dwError = ScmOpenServiceKey(lpService->lpServiceName,
5492 KEY_READ,
5493 &hServiceKey);
5494 if (dwError != ERROR_SUCCESS)
5495 goto done;
5496
5497 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5498 {
5499 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
5500 LPWSTR lpStr;
5501
5502 dwError = ScmReadString(hServiceKey,
5503 L"Description",
5504 &lpDescription);
5505 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5506 goto done;
5507
5508 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW);
5509 if (dwError == ERROR_SUCCESS)
5510 *pcbBytesNeeded += (DWORD)((wcslen(lpDescription) + 1) * sizeof(WCHAR));
5511
5512 if (cbBufSize < *pcbBytesNeeded)
5513 {
5514 dwError = ERROR_INSUFFICIENT_BUFFER;
5515 goto done;
5516 }
5517
5518 if (dwError == ERROR_SUCCESS)
5519 {
5520 lpStr = (LPWSTR)(lpServiceDescription + 1);
5521 wcscpy(lpStr, lpDescription);
5522 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
5523 }
5524 else
5525 {
5526 lpServiceDescription->lpDescription = NULL;
5527 dwError = ERROR_SUCCESS;
5528 }
5529 }
5530 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5531 {
5532 LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
5533 LPWSTR lpStr = NULL;
5534
5535 /* Query value length */
5536 dwError = RegQueryValueExW(hServiceKey,
5537 L"FailureActions",
5538 NULL,
5539 &dwType,
5540 NULL,
5541 &dwRequiredSize);
5542 if (dwError != ERROR_SUCCESS &&
5543 dwError != ERROR_MORE_DATA &&
5544 dwError != ERROR_FILE_NOT_FOUND)
5545 goto done;
5546
5547 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
5548 : sizeof(SERVICE_FAILURE_ACTIONSW);
5549
5550 /* Get the strings */
5551 ScmReadString(hServiceKey,
5552 L"FailureCommand",
5553 &lpFailureCommand);
5554
5555 ScmReadString(hServiceKey,
5556 L"RebootMessage",
5557 &lpRebootMessage);
5558
5559 if (lpRebootMessage)
5560 dwRequiredSize += (DWORD)((wcslen(lpRebootMessage) + 1) * sizeof(WCHAR));
5561
5562 if (lpFailureCommand)
5563 dwRequiredSize += (DWORD)((wcslen(lpFailureCommand) + 1) * sizeof(WCHAR));
5564
5565 if (cbBufSize < dwRequiredSize)
5566 {
5567 *pcbBytesNeeded = dwRequiredSize;
5568 dwError = ERROR_INSUFFICIENT_BUFFER;
5569 goto done;
5570 }
5571
5572 /* Now we can fill the buffer */
5573 if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY)
5574 {
5575 dwError = RegQueryValueExW(hServiceKey,
5576 L"FailureActions",
5577 NULL,
5578 NULL,
5579 (LPBYTE)lpFailureActions,
5580 &dwRequiredSize);
5581 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5582 goto done;
5583
5584 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
5585 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5586 }
5587 else
5588 {
5589 /*
5590 * The value of the error doesn't really matter, the only
5591 * important thing is that it must be != ERROR_SUCCESS .
5592 */
5593 dwError = ERROR_INVALID_DATA;
5594 }
5595
5596 if (dwError == ERROR_SUCCESS)
5597 {
5598 lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
5599
5600 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5601 lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSW) : NULL);
5602
5603 lpStr = (LPWSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION));
5604 }
5605 else
5606 {
5607 lpFailureActions->dwResetPeriod = 0;
5608 lpFailureActions->cActions = 0;
5609 lpFailureActions->lpsaActions = NULL;
5610 lpStr = (LPWSTR)(lpFailureActions + 1);
5611 }
5612
5613 lpFailureActions->lpRebootMsg = NULL;
5614 lpFailureActions->lpCommand = NULL;
5615
5616 if (lpRebootMessage)
5617 {
5618 wcscpy(lpStr, lpRebootMessage);
5619 lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5620 lpStr += wcslen(lpStr) + 1;
5621 }
5622
5623 if (lpFailureCommand)
5624 {
5625 wcscpy(lpStr, lpFailureCommand);
5626 lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5627 /* lpStr += wcslen(lpStr) + 1; */
5628 }
5629
5630 dwError = ERROR_SUCCESS;
5631 }
5632
5633 done:
5634 /* Unlock the service database */
5635 ScmUnlockDatabase();
5636
5637 if (lpDescription != NULL)
5638 HeapFree(GetProcessHeap(), 0, lpDescription);
5639
5640 if (lpRebootMessage != NULL)
5641 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
5642
5643 if (lpFailureCommand != NULL)
5644 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
5645
5646 if (hServiceKey != NULL)
5647 RegCloseKey(hServiceKey);
5648
5649 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
5650
5651 return dwError;
5652 }
5653
5654
5655 /* Function 40 */
5656 DWORD RQueryServiceStatusEx(
5657 SC_RPC_HANDLE hService,
5658 SC_STATUS_TYPE InfoLevel,
5659 LPBYTE lpBuffer,
5660 DWORD cbBufSize,
5661 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5662 {
5663 LPSERVICE_STATUS_PROCESS lpStatus;
5664 PSERVICE_HANDLE hSvc;
5665 PSERVICE lpService;
5666
5667 DPRINT("RQueryServiceStatusEx() called\n");
5668
5669 if (ScmShutdown)
5670 return ERROR_SHUTDOWN_IN_PROGRESS;
5671
5672 if (InfoLevel != SC_STATUS_PROCESS_INFO)
5673 return ERROR_INVALID_LEVEL;
5674
5675 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
5676
5677 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
5678 return ERROR_INSUFFICIENT_BUFFER;
5679
5680 hSvc = ScmGetServiceFromHandle(hService);
5681 if (hSvc == NULL)
5682 {
5683 DPRINT1("Invalid service handle!\n");
5684 return ERROR_INVALID_HANDLE;
5685 }
5686
5687 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5688 SERVICE_QUERY_STATUS))
5689 {
5690 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5691 return ERROR_ACCESS_DENIED;
5692 }
5693
5694 lpService = hSvc->ServiceEntry;
5695 if (lpService == NULL)
5696 {
5697 DPRINT("lpService == NULL!\n");
5698 return ERROR_INVALID_HANDLE;
5699 }
5700
5701 /* Lock the service database shared */
5702 ScmLockDatabaseShared();
5703
5704 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
5705
5706 /* Return service status information */
5707 RtlCopyMemory(lpStatus,
5708 &lpService->Status,
5709 sizeof(SERVICE_STATUS));
5710
5711 lpStatus->dwProcessId = (lpService->lpImage != NULL) ? lpService->lpImage->dwProcessId : 0; /* FIXME */
5712 lpStatus->dwServiceFlags = 0; /* FIXME */
5713
5714 /* Unlock the service database */
5715 ScmUnlockDatabase();
5716
5717 return ERROR_SUCCESS;
5718 }
5719
5720
5721 /* Function 41 */
5722 DWORD REnumServicesStatusExA(
5723 SC_RPC_HANDLE hSCManager,
5724 SC_ENUM_TYPE InfoLevel,
5725 DWORD dwServiceType,
5726 DWORD dwServiceState,
5727 LPBYTE lpBuffer,
5728 DWORD cbBufSize,
5729 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5730 LPBOUNDED_DWORD_256K lpServicesReturned,
5731 LPBOUNDED_DWORD_256K lpResumeIndex,
5732 LPCSTR pszGroupName)
5733 {
5734 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
5735 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW;
5736 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
5737 LPWSTR lpStringPtrW;
5738 LPSTR lpStringPtrA;
5739 LPWSTR pszGroupNameW = NULL;
5740 DWORD dwError;
5741 DWORD dwServiceCount;
5742
5743 DPRINT("REnumServicesStatusExA() called\n");
5744
5745 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
5746 {
5747 return ERROR_INVALID_ADDRESS;
5748 }
5749
5750 if (pszGroupName)
5751 {
5752 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
5753 if (!pszGroupNameW)
5754 {
5755 DPRINT("Failed to allocate buffer!\n");
5756 return ERROR_NOT_ENOUGH_MEMORY;
5757 }
5758
5759 MultiByteToWideChar(CP_ACP,
5760 0,
5761 pszGroupName,
5762 -1,
5763 pszGroupNameW,
5764 (int)(strlen(pszGroupName) + 1));
5765 }
5766
5767 if ((cbBufSize > 0) && (lpBuffer))
5768 {
5769 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
5770 if (!lpStatusPtrW)
5771 {
5772 DPRINT("Failed to allocate buffer!\n");
5773 return ERROR_NOT_ENOUGH_MEMORY;
5774 }
5775 }
5776
5777 dwError = REnumServicesStatusExW(hSCManager,
5778 InfoLevel,
5779 dwServiceType,
5780 dwServiceState,
5781 (LPBYTE)lpStatusPtrW,
5782 cbBufSize,
5783 pcbBytesNeeded,
5784 lpServicesReturned,
5785 lpResumeIndex,
5786 pszGroupNameW);
5787
5788 /* if no services were returned then we are Done */
5789 if (*lpServicesReturned == 0)
5790 goto Done;
5791
5792 lpStatusPtrIncrW = lpStatusPtrW;
5793 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
5794 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
5795 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
5796 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
5797 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
5798
5799 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
5800 {
5801 /* Copy the service name */
5802 WideCharToMultiByte(CP_ACP,
5803 0,
5804 lpStringPtrW,
5805 -1,
5806 lpStringPtrA,
5807 (int)wcslen(lpStringPtrW),
5808 0,
5809 0);
5810
5811 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5812 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5813 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5814
5815 /* Copy the display name */
5816 WideCharToMultiByte(CP_ACP,
5817 0,
5818 lpStringPtrW,
5819 -1,
5820 lpStringPtrA,
5821 (int)wcslen(lpStringPtrW),
5822 0,
5823 0);
5824
5825 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5826 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5827 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5828
5829 /* Copy the status information */
5830 memcpy(&lpStatusPtrA->ServiceStatusProcess,
5831 &lpStatusPtrIncrW->ServiceStatusProcess,
5832 sizeof(SERVICE_STATUS));
5833
5834 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrIncrW->ServiceStatusProcess.dwProcessId; /* FIXME */
5835 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5836
5837 lpStatusPtrIncrW++;
5838 lpStatusPtrA++;
5839 }
5840
5841 Done:
5842 if (pszGroupNameW)
5843 HeapFree(GetProcessHeap(), 0, pszGroupNameW);
5844
5845 if (lpStatusPtrW)
5846 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
5847
5848 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
5849
5850 return dwError;
5851 }
5852
5853
5854 /* Function 42 */
5855 DWORD REnumServicesStatusExW(
5856 SC_RPC_HANDLE hSCManager,
5857 SC_ENUM_TYPE InfoLevel,
5858 DWORD dwServiceType,
5859 DWORD dwServiceState,
5860 LPBYTE lpBuffer,
5861 DWORD cbBufSize,
5862 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5863 LPBOUNDED_DWORD_256K lpServicesReturned,
5864 LPBOUNDED_DWORD_256K lpResumeIndex,
5865 LPCWSTR pszGroupName)
5866 {
5867 PMANAGER_HANDLE hManager;
5868 PSERVICE lpService;
5869 DWORD dwError = ERROR_SUCCESS;
5870 PLIST_ENTRY ServiceEntry;
5871 PSERVICE CurrentService;
5872 DWORD dwState;
5873 DWORD dwRequiredSize;
5874 DWORD dwServiceCount;
5875 DWORD dwSize;
5876 DWORD dwLastResumeCount = 0;
5877 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
5878 LPWSTR lpStringPtr;
5879
5880 DPRINT("REnumServicesStatusExW() called\n");
5881
5882 if (ScmShutdown)
5883 return ERROR_SHUTDOWN_IN_PROGRESS;
5884
5885 if (InfoLevel != SC_ENUM_PROCESS_INFO)
5886 return ERROR_INVALID_LEVEL;
5887
5888 hManager = ScmGetServiceManagerFromHandle(hSCManager);
5889 if (hManager == NULL)
5890 {
5891 DPRINT1("Invalid service manager handle!\n");
5892 return ERROR_INVALID_HANDLE;
5893 }
5894
5895 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
5896 {
5897 return ERROR_INVALID_ADDRESS;
5898 }
5899
5900 *pcbBytesNeeded = 0;
5901 *lpServicesReturned = 0;
5902
5903 if ((dwServiceType == 0) ||
5904 ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
5905 {
5906 DPRINT("Not a valid Service Type!\n");
5907 return ERROR_INVALID_PARAMETER;
5908 }
5909
5910 if ((dwServiceState == 0) ||
5911 ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
5912 {
5913 DPRINT("Not a valid Service State!\n");
5914 return ERROR_INVALID_PARAMETER;
5915 }
5916
5917 /* Check access rights */
5918 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
5919 SC_MANAGER_ENUMERATE_SERVICE))
5920 {
5921 DPRINT("Insufficient access rights! 0x%lx\n",
5922 hManager->Handle.DesiredAccess);
5923 return ERROR_ACCESS_DENIED;
5924 }
5925
5926 if (lpResumeIndex)
5927 dwLastResumeCount = *lpResumeIndex;
5928
5929 /* Lock the service database shared */
5930 ScmLockDatabaseShared();
5931
5932 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
5933 if (lpService == NULL)
5934 {
5935 dwError = ERROR_SUCCESS;
5936 goto Done;
5937 }
5938
5939 dwRequiredSize = 0;
5940 dwServiceCount = 0;
5941
5942 for (ServiceEntry = &lpService->ServiceListEntry;
5943 ServiceEntry != &ServiceListHead;
5944 ServiceEntry = ServiceEntry->Flink)
5945 {
5946 CurrentService = CONTAINING_RECORD(ServiceEntry,
5947 SERVICE,
5948 ServiceListEntry);
5949
5950 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5951 continue;
5952
5953 dwState = SERVICE_ACTIVE;
5954 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5955 dwState = SERVICE_INACTIVE;
5956
5957 if ((dwState & dwServiceState) == 0)
5958 continue;
5959
5960 if (pszGroupName)
5961 {
5962 if (*pszGroupName == 0)
5963 {
5964 if (CurrentService->lpGroup != NULL)
5965 continue;
5966 }
5967 else
5968 {
5969 if ((CurrentService->lpGroup == NULL) ||
5970 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
5971 continue;
5972 }
5973 }
5974
5975 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5976 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5977 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5978
5979 if (dwRequiredSize + dwSize <= cbBufSize)
5980 {
5981 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
5982 dwRequiredSize += dwSize;
5983 dwServiceCount++;
5984 dwLastResumeCount = CurrentService->dwResumeCount;
5985 }
5986 else
5987 {
5988 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
5989 break;
5990 }
5991
5992 }
5993
5994 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
5995 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
5996
5997 for (;
5998 ServiceEntry != &ServiceListHead;
5999 ServiceEntry = ServiceEntry->Flink)
6000 {
6001 CurrentService = CONTAINING_RECORD(ServiceEntry,
6002 SERVICE,
6003 ServiceListEntry);
6004
6005 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6006 continue;
6007
6008 dwState = SERVICE_ACTIVE;
6009 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6010 dwState = SERVICE_INACTIVE;
6011
6012 if ((dwState & dwServiceState) == 0)
6013 continue;
6014
6015 if (pszGroupName)
6016 {
6017 if (*pszGroupName == 0)
6018 {
6019 if (CurrentService->lpGroup != NULL)
6020 continue;
6021 }
6022 else
6023 {
6024 if ((CurrentService->lpGroup == NULL) ||
6025 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6026 continue;
6027 }
6028 }
6029
6030 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6031 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6032 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
6033
6034 dwError = ERROR_MORE_DATA;
6035 }
6036
6037 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
6038
6039 if (lpResumeIndex)
6040 *lpResumeIndex = dwLastResumeCount;
6041
6042 *lpServicesReturned = dwServiceCount;
6043 *pcbBytesNeeded = dwRequiredSize;
6044
6045 /* If there was no services that matched */
6046 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
6047 {
6048 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
6049 goto Done;
6050 }
6051
6052 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
6053 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
6054 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
6055
6056 dwRequiredSize = 0;
6057 for (ServiceEntry = &lpService->ServiceListEntry;
6058 ServiceEntry != &ServiceListHead;
6059 ServiceEntry = ServiceEntry->Flink)
6060 {
6061 CurrentService = CONTAINING_RECORD(ServiceEntry,
6062 SERVICE,
6063 ServiceListEntry);
6064
6065 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6066 continue;
6067
6068 dwState = SERVICE_ACTIVE;
6069 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6070 dwState = SERVICE_INACTIVE;
6071
6072 if ((dwState & dwServiceState) == 0)
6073 continue;
6074
6075 if (pszGroupName)
6076 {
6077 if (*pszGroupName == 0)
6078 {
6079 if (CurrentService->lpGroup != NULL)
6080 continue;
6081 }
6082 else
6083 {
6084 if ((CurrentService->lpGroup == NULL) ||
6085 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6086 continue;
6087 }
6088 }
6089
6090 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6091 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6092 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
6093
6094 if (dwRequiredSize + dwSize <= cbBufSize)
6095 {
6096 /* Copy the service name */
6097 wcscpy(lpStringPtr,
6098 CurrentService->lpServiceName);
6099 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
6100 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
6101
6102 /* Copy the display name */
6103 wcscpy(lpStringPtr,
6104 CurrentService->lpDisplayName);
6105 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
6106 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
6107
6108 /* Copy the status information */
6109 memcpy(&lpStatusPtr->ServiceStatusProcess,
6110 &CurrentService->Status,
6111 sizeof(SERVICE_STATUS));
6112 lpStatusPtr->ServiceStatusProcess.dwProcessId =
6113 (CurrentService->lpImage != NULL) ? CurrentService->lpImage->dwProcessId : 0; /* FIXME */
6114 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
6115
6116 lpStatusPtr++;
6117 dwRequiredSize += dwSize;
6118 }
6119 else
6120 {
6121 break;
6122 }
6123 }
6124
6125 if (dwError == 0)
6126 {
6127 *pcbBytesNeeded = 0;
6128 if (lpResumeIndex)
6129 *lpResumeIndex = 0;
6130 }
6131
6132 Done:
6133 /* Unlock the service database */
6134 ScmUnlockDatabase();
6135
6136 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
6137
6138 return dwError;
6139 }
6140
6141
6142 /* Function 43 */
6143 DWORD RSendTSMessage(
6144 handle_t BindingHandle) /* FIXME */
6145 {
6146 UNIMPLEMENTED;
6147 return ERROR_CALL_NOT_IMPLEMENTED;
6148 }
6149
6150
6151 /* Function 44 */
6152 DWORD RCreateServiceWOW64A(
6153 handle_t BindingHandle,
6154 LPSTR lpServiceName,
6155 LPSTR lpDisplayName,
6156 DWORD dwDesiredAccess,
6157 DWORD dwServiceType,
6158 DWORD dwStartType,
6159 DWORD dwErrorControl,
6160 LPSTR lpBinaryPathName,
6161 LPSTR lpLoadOrderGroup,
6162 LPDWORD lpdwTagId,
6163 LPBYTE lpDependencies,
6164 DWORD dwDependSize,
6165 LPSTR lpServiceStartName,
6166 LPBYTE lpPassword,
6167 DWORD dwPwSize,
6168 LPSC_RPC_HANDLE lpServiceHandle)
6169 {
6170 UNIMPLEMENTED;
6171 return ERROR_CALL_NOT_IMPLEMENTED;
6172 }
6173
6174
6175 /* Function 45 */
6176 DWORD RCreateServiceWOW64W(
6177 handle_t BindingHandle,
6178 LPWSTR lpServiceName,
6179 LPWSTR lpDisplayName,
6180 DWORD dwDesiredAccess,
6181 DWORD dwServiceType,
6182 DWORD dwStartType,
6183 DWORD dwErrorControl,
6184 LPWSTR lpBinaryPathName,
6185 LPWSTR lpLoadOrderGroup,
6186 LPDWORD lpdwTagId,
6187 LPBYTE lpDependencies,
6188 DWORD dwDependSize,
6189 LPWSTR lpServiceStartName,
6190 LPBYTE lpPassword,
6191 DWORD dwPwSize,
6192 LPSC_RPC_HANDLE lpServiceHandle)
6193 {
6194 UNIMPLEMENTED;
6195 return ERROR_CALL_NOT_IMPLEMENTED;
6196 }
6197
6198
6199 /* Function 46 */
6200 DWORD RQueryServiceTagInfo(
6201 handle_t BindingHandle) /* FIXME */
6202 {
6203 UNIMPLEMENTED;
6204 return ERROR_CALL_NOT_IMPLEMENTED;
6205 }
6206
6207
6208 /* Function 47 */
6209 DWORD RNotifyServiceStatusChange(
6210 SC_RPC_HANDLE hService,
6211 SC_RPC_NOTIFY_PARAMS NotifyParams,
6212 GUID *pClientProcessGuid,
6213 GUID *pSCMProcessGuid,
6214 PBOOL pfCreateRemoteQueue,
6215 LPSC_NOTIFY_RPC_HANDLE phNotify)
6216 {
6217 UNIMPLEMENTED;
6218 return ERROR_CALL_NOT_IMPLEMENTED;
6219 }
6220
6221
6222 /* Function 48 */
6223 DWORD RGetNotifyResults(
6224 SC_NOTIFY_RPC_HANDLE hNotify,
6225 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
6226 {
6227 UNIMPLEMENTED;
6228 return ERROR_CALL_NOT_IMPLEMENTED;
6229 }
6230
6231
6232 /* Function 49 */
6233 DWORD RCloseNotifyHandle(
6234 LPSC_NOTIFY_RPC_HANDLE phNotify,
6235 PBOOL pfApcFired)
6236 {
6237 UNIMPLEMENTED;
6238 return ERROR_CALL_NOT_IMPLEMENTED;
6239 }
6240
6241
6242 /* Function 50 */
6243 DWORD RControlServiceExA(
6244 SC_RPC_HANDLE hService,
6245 DWORD dwControl,
6246 DWORD dwInfoLevel)
6247 {
6248 UNIMPLEMENTED;
6249 return ERROR_CALL_NOT_IMPLEMENTED;
6250 }
6251
6252
6253 /* Function 51 */
6254 DWORD RControlServiceExW(
6255 SC_RPC_HANDLE hService,
6256 DWORD dwControl,
6257 DWORD dwInfoLevel)
6258 {
6259 UNIMPLEMENTED;
6260 return ERROR_CALL_NOT_IMPLEMENTED;
6261 }
6262
6263
6264 /* Function 52 */
6265 DWORD RSendPnPMessage(
6266 handle_t BindingHandle) /* FIXME */
6267 {
6268 UNIMPLEMENTED;
6269 return ERROR_CALL_NOT_IMPLEMENTED;
6270 }
6271
6272
6273 /* Function 53 */
6274 DWORD RValidatePnPService(
6275 handle_t BindingHandle) /* FIXME */
6276 {
6277 UNIMPLEMENTED;
6278 return ERROR_CALL_NOT_IMPLEMENTED;
6279 }
6280
6281
6282 /* Function 54 */
6283 DWORD ROpenServiceStatusHandle(
6284 handle_t BindingHandle) /* FIXME */
6285 {
6286 UNIMPLEMENTED;
6287 return ERROR_CALL_NOT_IMPLEMENTED;
6288 }
6289
6290
6291 /* Function 55 */
6292 DWORD RFunction55(
6293 handle_t BindingHandle) /* FIXME */
6294 {
6295 UNIMPLEMENTED;
6296 return ERROR_CALL_NOT_IMPLEMENTED;
6297 }
6298
6299
6300 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
6301 {
6302 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
6303 }
6304
6305
6306 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
6307 {
6308 HeapFree(GetProcessHeap(), 0, ptr);
6309 }
6310
6311
6312 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
6313 {
6314 /* Close the handle */
6315 RCloseServiceHandle(&hSCObject);
6316 }
6317
6318
6319 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
6320 {
6321 /* Unlock the database */
6322 RUnlockServiceDatabase(&Lock);
6323 }
6324
6325
6326 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
6327 {
6328 }
6329
6330 /* EOF */