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