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