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