Partial merge of the condrv_restructure branch, including:
[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 DWORD dwPreviousType;
1621 LPCWSTR lpErrorStrings[2];
1622 WCHAR szErrorBuffer[32];
1623
1624 DPRINT("RSetServiceStatus() called\n");
1625 DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1626 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
1627 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1628 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1629 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1630 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1631 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1632 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1633
1634 if (hServiceStatus == 0)
1635 {
1636 DPRINT("hServiceStatus == NULL!\n");
1637 return ERROR_INVALID_HANDLE;
1638 }
1639
1640 lpService = (PSERVICE)hServiceStatus;
1641
1642 /* Check current state */
1643 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1644 {
1645 DPRINT("Invalid service state!\n");
1646 return ERROR_INVALID_DATA;
1647 }
1648
1649 /* Check service type */
1650 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1651 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1652 {
1653 DPRINT("Invalid service type!\n");
1654 return ERROR_INVALID_DATA;
1655 }
1656
1657 /* Check accepted controls */
1658 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1659 {
1660 DPRINT("Invalid controls accepted!\n");
1661 return ERROR_INVALID_DATA;
1662 }
1663
1664 /* Set the wait hint and check point only if the service is in a pending state,
1665 otherwise they should be 0 */
1666 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1667 lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
1668 lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
1669 {
1670 lpServiceStatus->dwWaitHint = 0;
1671 lpServiceStatus->dwCheckPoint = 0;
1672 }
1673
1674 /* Lock the service database exclusively */
1675 ScmLockDatabaseExclusive();
1676
1677 /* Save the current service state */
1678 dwPreviousState = lpService->Status.dwCurrentState;
1679
1680 /* Save the current service type */
1681 dwPreviousType = lpService->Status.dwServiceType;
1682
1683 /* Update the service status */
1684 RtlCopyMemory(&lpService->Status,
1685 lpServiceStatus,
1686 sizeof(SERVICE_STATUS));
1687
1688 /* Restore the previous service type */
1689 lpService->Status.dwServiceType = dwPreviousType;
1690
1691 /* Unlock the service database */
1692 ScmUnlockDatabase();
1693
1694 /* Log a failed service stop */
1695 if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
1696 (dwPreviousState != SERVICE_STOPPED))
1697 {
1698 if (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS)
1699 {
1700 swprintf(szErrorBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode);
1701 lpErrorStrings[0] = lpService->lpDisplayName;
1702 lpErrorStrings[1] = szErrorBuffer;
1703
1704 ScmLogError(EVENT_SERVICE_EXIT_FAILED,
1705 2,
1706 lpErrorStrings);
1707 }
1708 }
1709
1710 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1711 DPRINT("RSetServiceStatus() done\n");
1712
1713 return ERROR_SUCCESS;
1714 }
1715
1716
1717 /* Function 8 */
1718 DWORD RUnlockServiceDatabase(
1719 LPSC_RPC_LOCK Lock)
1720 {
1721 DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1722 return ScmReleaseServiceStartLock(Lock);
1723 }
1724
1725
1726 /* Function 9 */
1727 DWORD RNotifyBootConfigStatus(
1728 SVCCTL_HANDLEW lpMachineName,
1729 DWORD BootAcceptable)
1730 {
1731 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1732 return ERROR_SUCCESS;
1733
1734 // UNIMPLEMENTED;
1735 // return ERROR_CALL_NOT_IMPLEMENTED;
1736 }
1737
1738
1739 /* Function 10 */
1740 DWORD RI_ScSetServiceBitsW(
1741 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1742 DWORD dwServiceBits,
1743 int bSetBitsOn,
1744 int bUpdateImmediately,
1745 wchar_t *lpString)
1746 {
1747 UNIMPLEMENTED;
1748 return ERROR_CALL_NOT_IMPLEMENTED;
1749 }
1750
1751
1752 /* Function 11 */
1753 DWORD RChangeServiceConfigW(
1754 SC_RPC_HANDLE hService,
1755 DWORD dwServiceType,
1756 DWORD dwStartType,
1757 DWORD dwErrorControl,
1758 LPWSTR lpBinaryPathName,
1759 LPWSTR lpLoadOrderGroup,
1760 LPDWORD lpdwTagId,
1761 LPBYTE lpDependencies,
1762 DWORD dwDependSize,
1763 LPWSTR lpServiceStartName,
1764 LPBYTE lpPassword,
1765 DWORD dwPwSize,
1766 LPWSTR lpDisplayName)
1767 {
1768 DWORD dwError = ERROR_SUCCESS;
1769 PSERVICE_HANDLE hSvc;
1770 PSERVICE lpService = NULL;
1771 HKEY hServiceKey = NULL;
1772 LPWSTR lpDisplayNameW = NULL;
1773 LPWSTR lpImagePathW = NULL;
1774
1775 DPRINT("RChangeServiceConfigW() called\n");
1776 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
1777 DPRINT("dwStartType = %lu\n", dwStartType);
1778 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1779 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1780 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1781 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1782
1783 if (ScmShutdown)
1784 return ERROR_SHUTDOWN_IN_PROGRESS;
1785
1786 hSvc = ScmGetServiceFromHandle(hService);
1787 if (hSvc == NULL)
1788 {
1789 DPRINT1("Invalid service handle!\n");
1790 return ERROR_INVALID_HANDLE;
1791 }
1792
1793 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1794 SERVICE_CHANGE_CONFIG))
1795 {
1796 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1797 return ERROR_ACCESS_DENIED;
1798 }
1799
1800 lpService = hSvc->ServiceEntry;
1801 if (lpService == NULL)
1802 {
1803 DPRINT("lpService == NULL!\n");
1804 return ERROR_INVALID_HANDLE;
1805 }
1806
1807 /* Lock the service database exclusively */
1808 ScmLockDatabaseExclusive();
1809
1810 if (lpService->bDeleted)
1811 {
1812 DPRINT("The service has already been marked for delete!\n");
1813 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1814 goto done;
1815 }
1816
1817 /* Open the service key */
1818 dwError = ScmOpenServiceKey(lpService->szServiceName,
1819 KEY_SET_VALUE,
1820 &hServiceKey);
1821 if (dwError != ERROR_SUCCESS)
1822 goto done;
1823
1824 /* Write service data to the registry */
1825 /* Set the display name */
1826 if (lpDisplayName != NULL && *lpDisplayName != 0)
1827 {
1828 RegSetValueExW(hServiceKey,
1829 L"DisplayName",
1830 0,
1831 REG_SZ,
1832 (LPBYTE)lpDisplayName,
1833 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
1834
1835 /* Update the display name */
1836 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
1837 HEAP_ZERO_MEMORY,
1838 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1839 if (lpDisplayNameW == NULL)
1840 {
1841 dwError = ERROR_NOT_ENOUGH_MEMORY;
1842 goto done;
1843 }
1844
1845 if (lpService->lpDisplayName != lpService->lpServiceName)
1846 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1847
1848 lpService->lpDisplayName = lpDisplayNameW;
1849 }
1850
1851 if (dwServiceType != SERVICE_NO_CHANGE)
1852 {
1853 /* Set the service type */
1854 dwError = RegSetValueExW(hServiceKey,
1855 L"Type",
1856 0,
1857 REG_DWORD,
1858 (LPBYTE)&dwServiceType,
1859 sizeof(DWORD));
1860 if (dwError != ERROR_SUCCESS)
1861 goto done;
1862
1863 lpService->Status.dwServiceType = dwServiceType;
1864 }
1865
1866 if (dwStartType != SERVICE_NO_CHANGE)
1867 {
1868 /* Set the start value */
1869 dwError = RegSetValueExW(hServiceKey,
1870 L"Start",
1871 0,
1872 REG_DWORD,
1873 (LPBYTE)&dwStartType,
1874 sizeof(DWORD));
1875 if (dwError != ERROR_SUCCESS)
1876 goto done;
1877
1878 lpService->dwStartType = dwStartType;
1879 }
1880
1881 if (dwErrorControl != SERVICE_NO_CHANGE)
1882 {
1883 /* Set the error control value */
1884 dwError = RegSetValueExW(hServiceKey,
1885 L"ErrorControl",
1886 0,
1887 REG_DWORD,
1888 (LPBYTE)&dwErrorControl,
1889 sizeof(DWORD));
1890 if (dwError != ERROR_SUCCESS)
1891 goto done;
1892
1893 lpService->dwErrorControl = dwErrorControl;
1894 }
1895
1896 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
1897 {
1898 /* Set the image path */
1899 lpImagePathW = lpBinaryPathName;
1900
1901 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1902 {
1903 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
1904 lpBinaryPathName,
1905 &lpImagePathW);
1906
1907 if (dwError != ERROR_SUCCESS)
1908 goto done;
1909 }
1910
1911 dwError = RegSetValueExW(hServiceKey,
1912 L"ImagePath",
1913 0,
1914 REG_EXPAND_SZ,
1915 (LPBYTE)lpImagePathW,
1916 (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
1917
1918 if (lpImagePathW != lpBinaryPathName)
1919 HeapFree(GetProcessHeap(), 0, lpImagePathW);
1920
1921 if (dwError != ERROR_SUCCESS)
1922 goto done;
1923 }
1924
1925 /* Set the group name */
1926 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1927 {
1928 dwError = RegSetValueExW(hServiceKey,
1929 L"Group",
1930 0,
1931 REG_SZ,
1932 (LPBYTE)lpLoadOrderGroup,
1933 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
1934 if (dwError != ERROR_SUCCESS)
1935 goto done;
1936
1937 dwError = ScmSetServiceGroup(lpService,
1938 lpLoadOrderGroup);
1939 if (dwError != ERROR_SUCCESS)
1940 goto done;
1941 }
1942
1943 if (lpdwTagId != NULL)
1944 {
1945 dwError = ScmAssignNewTag(lpService);
1946 if (dwError != ERROR_SUCCESS)
1947 goto done;
1948
1949 dwError = RegSetValueExW(hServiceKey,
1950 L"Tag",
1951 0,
1952 REG_DWORD,
1953 (LPBYTE)&lpService->dwTag,
1954 sizeof(DWORD));
1955 if (dwError != ERROR_SUCCESS)
1956 goto done;
1957
1958 *lpdwTagId = lpService->dwTag;
1959 }
1960
1961 /* Write dependencies */
1962 if (lpDependencies != NULL && *lpDependencies != 0)
1963 {
1964 dwError = ScmWriteDependencies(hServiceKey,
1965 (LPWSTR)lpDependencies,
1966 dwDependSize);
1967 if (dwError != ERROR_SUCCESS)
1968 goto done;
1969 }
1970
1971 if (lpPassword != NULL)
1972 {
1973 /* FIXME: Decrypt and write password */
1974 }
1975
1976 done:
1977 if (hServiceKey != NULL)
1978 RegCloseKey(hServiceKey);
1979
1980 /* Unlock the service database */
1981 ScmUnlockDatabase();
1982
1983 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1984
1985 return dwError;
1986 }
1987
1988
1989 /* Function 12 */
1990 DWORD RCreateServiceW(
1991 SC_RPC_HANDLE hSCManager,
1992 LPCWSTR lpServiceName,
1993 LPCWSTR lpDisplayName,
1994 DWORD dwDesiredAccess,
1995 DWORD dwServiceType,
1996 DWORD dwStartType,
1997 DWORD dwErrorControl,
1998 LPCWSTR lpBinaryPathName,
1999 LPCWSTR lpLoadOrderGroup,
2000 LPDWORD lpdwTagId,
2001 LPBYTE lpDependencies,
2002 DWORD dwDependSize,
2003 LPCWSTR lpServiceStartName,
2004 LPBYTE lpPassword,
2005 DWORD dwPwSize,
2006 LPSC_RPC_HANDLE lpServiceHandle)
2007 {
2008 PMANAGER_HANDLE hManager;
2009 DWORD dwError = ERROR_SUCCESS;
2010 PSERVICE lpService = NULL;
2011 SC_HANDLE hServiceHandle = NULL;
2012 LPWSTR lpImagePath = NULL;
2013 HKEY hServiceKey = NULL;
2014 LPWSTR lpObjectName;
2015
2016 DPRINT("RCreateServiceW() called\n");
2017 DPRINT("lpServiceName = %S\n", lpServiceName);
2018 DPRINT("lpDisplayName = %S\n", lpDisplayName);
2019 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2020 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2021 DPRINT("dwStartType = %lu\n", dwStartType);
2022 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2023 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2024 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2025 DPRINT("lpdwTagId = %p\n", lpdwTagId);
2026
2027 if (ScmShutdown)
2028 return ERROR_SHUTDOWN_IN_PROGRESS;
2029
2030 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2031 if (hManager == NULL)
2032 {
2033 DPRINT1("Invalid service manager handle!\n");
2034 return ERROR_INVALID_HANDLE;
2035 }
2036
2037 /* Check access rights */
2038 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2039 SC_MANAGER_CREATE_SERVICE))
2040 {
2041 DPRINT("Insufficient access rights! 0x%lx\n",
2042 hManager->Handle.DesiredAccess);
2043 return ERROR_ACCESS_DENIED;
2044 }
2045
2046 if (wcslen(lpServiceName) == 0)
2047 {
2048 return ERROR_INVALID_NAME;
2049 }
2050
2051 if (wcslen(lpBinaryPathName) == 0)
2052 {
2053 return ERROR_INVALID_PARAMETER;
2054 }
2055
2056 /* Check for invalid service type value */
2057 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2058 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2059 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2060 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
2061 return ERROR_INVALID_PARAMETER;
2062
2063 /* Check for invalid start type value */
2064 if ((dwStartType != SERVICE_BOOT_START) &&
2065 (dwStartType != SERVICE_SYSTEM_START) &&
2066 (dwStartType != SERVICE_AUTO_START) &&
2067 (dwStartType != SERVICE_DEMAND_START) &&
2068 (dwStartType != SERVICE_DISABLED))
2069 return ERROR_INVALID_PARAMETER;
2070
2071 /* Only drivers can be boot start or system start services */
2072 if ((dwStartType == SERVICE_BOOT_START) ||
2073 (dwStartType == SERVICE_SYSTEM_START))
2074 {
2075 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2076 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2077 return ERROR_INVALID_PARAMETER;
2078 }
2079
2080 /* Check for invalid error control value */
2081 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2082 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2083 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2084 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2085 return ERROR_INVALID_PARAMETER;
2086
2087 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2088 (lpServiceStartName))
2089 {
2090 return ERROR_INVALID_PARAMETER;
2091 }
2092
2093 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2094 {
2095 return ERROR_INVALID_PARAMETER;
2096 }
2097
2098 /* Lock the service database exclusively */
2099 ScmLockDatabaseExclusive();
2100
2101 lpService = ScmGetServiceEntryByName(lpServiceName);
2102 if (lpService)
2103 {
2104 /* Unlock the service database */
2105 ScmUnlockDatabase();
2106
2107 /* Check if it is marked for deletion */
2108 if (lpService->bDeleted)
2109 return ERROR_SERVICE_MARKED_FOR_DELETE;
2110
2111 /* Return Error exist */
2112 return ERROR_SERVICE_EXISTS;
2113 }
2114
2115 if (lpDisplayName != NULL &&
2116 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2117 {
2118 /* Unlock the service database */
2119 ScmUnlockDatabase();
2120
2121 return ERROR_DUPLICATE_SERVICE_NAME;
2122 }
2123
2124 if (dwServiceType & SERVICE_DRIVER)
2125 {
2126 dwError = ScmCanonDriverImagePath(dwStartType,
2127 lpBinaryPathName,
2128 &lpImagePath);
2129 if (dwError != ERROR_SUCCESS)
2130 goto done;
2131 }
2132 else
2133 {
2134 if (dwStartType == SERVICE_BOOT_START ||
2135 dwStartType == SERVICE_SYSTEM_START)
2136 {
2137 /* Unlock the service database */
2138 ScmUnlockDatabase();
2139
2140 return ERROR_INVALID_PARAMETER;
2141 }
2142 }
2143
2144 /* Allocate a new service entry */
2145 dwError = ScmCreateNewServiceRecord(lpServiceName,
2146 &lpService);
2147 if (dwError != ERROR_SUCCESS)
2148 goto done;
2149
2150 /* Fill the new service entry */
2151 lpService->Status.dwServiceType = dwServiceType;
2152 lpService->dwStartType = dwStartType;
2153 lpService->dwErrorControl = dwErrorControl;
2154
2155 /* Fill the display name */
2156 if (lpDisplayName != NULL &&
2157 *lpDisplayName != 0 &&
2158 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2159 {
2160 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2161 HEAP_ZERO_MEMORY,
2162 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2163 if (lpService->lpDisplayName == NULL)
2164 {
2165 dwError = ERROR_NOT_ENOUGH_MEMORY;
2166 goto done;
2167 }
2168 wcscpy(lpService->lpDisplayName, lpDisplayName);
2169 }
2170
2171 /* Assign the service to a group */
2172 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2173 {
2174 dwError = ScmSetServiceGroup(lpService,
2175 lpLoadOrderGroup);
2176 if (dwError != ERROR_SUCCESS)
2177 goto done;
2178 }
2179
2180 /* Assign a new tag */
2181 if (lpdwTagId != NULL)
2182 {
2183 dwError = ScmAssignNewTag(lpService);
2184 if (dwError != ERROR_SUCCESS)
2185 goto done;
2186 }
2187
2188 /* Write service data to the registry */
2189 /* Create the service key */
2190 dwError = ScmCreateServiceKey(lpServiceName,
2191 KEY_WRITE,
2192 &hServiceKey);
2193 if (dwError != ERROR_SUCCESS)
2194 goto done;
2195
2196 /* Set the display name */
2197 if (lpDisplayName != NULL && *lpDisplayName != 0)
2198 {
2199 RegSetValueExW(hServiceKey,
2200 L"DisplayName",
2201 0,
2202 REG_SZ,
2203 (LPBYTE)lpDisplayName,
2204 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2205 }
2206
2207 /* Set the service type */
2208 dwError = RegSetValueExW(hServiceKey,
2209 L"Type",
2210 0,
2211 REG_DWORD,
2212 (LPBYTE)&dwServiceType,
2213 sizeof(DWORD));
2214 if (dwError != ERROR_SUCCESS)
2215 goto done;
2216
2217 /* Set the start value */
2218 dwError = RegSetValueExW(hServiceKey,
2219 L"Start",
2220 0,
2221 REG_DWORD,
2222 (LPBYTE)&dwStartType,
2223 sizeof(DWORD));
2224 if (dwError != ERROR_SUCCESS)
2225 goto done;
2226
2227 /* Set the error control value */
2228 dwError = RegSetValueExW(hServiceKey,
2229 L"ErrorControl",
2230 0,
2231 REG_DWORD,
2232 (LPBYTE)&dwErrorControl,
2233 sizeof(DWORD));
2234 if (dwError != ERROR_SUCCESS)
2235 goto done;
2236
2237 /* Set the image path */
2238 if (dwServiceType & SERVICE_WIN32)
2239 {
2240 dwError = RegSetValueExW(hServiceKey,
2241 L"ImagePath",
2242 0,
2243 REG_EXPAND_SZ,
2244 (LPBYTE)lpBinaryPathName,
2245 (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2246 if (dwError != ERROR_SUCCESS)
2247 goto done;
2248 }
2249 else if (dwServiceType & SERVICE_DRIVER)
2250 {
2251 dwError = RegSetValueExW(hServiceKey,
2252 L"ImagePath",
2253 0,
2254 REG_EXPAND_SZ,
2255 (LPBYTE)lpImagePath,
2256 (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2257 if (dwError != ERROR_SUCCESS)
2258 goto done;
2259 }
2260
2261 /* Set the group name */
2262 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2263 {
2264 dwError = RegSetValueExW(hServiceKey,
2265 L"Group",
2266 0,
2267 REG_SZ,
2268 (LPBYTE)lpLoadOrderGroup,
2269 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2270 if (dwError != ERROR_SUCCESS)
2271 goto done;
2272 }
2273
2274 if (lpdwTagId != NULL)
2275 {
2276 dwError = RegSetValueExW(hServiceKey,
2277 L"Tag",
2278 0,
2279 REG_DWORD,
2280 (LPBYTE)&lpService->dwTag,
2281 sizeof(DWORD));
2282 if (dwError != ERROR_SUCCESS)
2283 goto done;
2284 }
2285
2286 /* Write dependencies */
2287 if (lpDependencies != NULL && *lpDependencies != 0)
2288 {
2289 dwError = ScmWriteDependencies(hServiceKey,
2290 (LPCWSTR)lpDependencies,
2291 dwDependSize);
2292 if (dwError != ERROR_SUCCESS)
2293 goto done;
2294 }
2295
2296 /* Write service start name */
2297 if (dwServiceType & SERVICE_WIN32)
2298 {
2299 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2300 dwError = RegSetValueExW(hServiceKey,
2301 L"ObjectName",
2302 0,
2303 REG_SZ,
2304 (LPBYTE)lpObjectName,
2305 (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2306 if (dwError != ERROR_SUCCESS)
2307 goto done;
2308 }
2309
2310 if (lpPassword != NULL)
2311 {
2312 /* FIXME: Decrypt and write password */
2313 }
2314
2315 dwError = ScmCreateServiceHandle(lpService,
2316 &hServiceHandle);
2317 if (dwError != ERROR_SUCCESS)
2318 goto done;
2319
2320 dwError = ScmCheckAccess(hServiceHandle,
2321 dwDesiredAccess);
2322 if (dwError != ERROR_SUCCESS)
2323 goto done;
2324
2325 lpService->dwRefCount = 1;
2326 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2327
2328 done:
2329 /* Unlock the service database */
2330 ScmUnlockDatabase();
2331
2332 if (hServiceKey != NULL)
2333 RegCloseKey(hServiceKey);
2334
2335 if (dwError == ERROR_SUCCESS)
2336 {
2337 DPRINT("hService %p\n", hServiceHandle);
2338 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2339
2340 if (lpdwTagId != NULL)
2341 *lpdwTagId = lpService->dwTag;
2342 }
2343 else
2344 {
2345 if (lpService != NULL &&
2346 lpService->lpServiceName != NULL)
2347 {
2348 /* Release the display name buffer */
2349 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2350 }
2351
2352 if (hServiceHandle)
2353 {
2354 /* Remove the service handle */
2355 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2356 }
2357
2358 if (lpService != NULL)
2359 {
2360 /* FIXME: remove the service entry */
2361 }
2362 }
2363
2364 if (lpImagePath != NULL)
2365 HeapFree(GetProcessHeap(), 0, lpImagePath);
2366
2367 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2368
2369 return dwError;
2370 }
2371
2372
2373 /* Function 13 */
2374 DWORD REnumDependentServicesW(
2375 SC_RPC_HANDLE hService,
2376 DWORD dwServiceState,
2377 LPBYTE lpServices,
2378 DWORD cbBufSize,
2379 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2380 LPBOUNDED_DWORD_256K lpServicesReturned)
2381 {
2382 DWORD dwError = ERROR_SUCCESS;
2383 DWORD dwServicesReturned = 0;
2384 DWORD dwServiceCount;
2385 HKEY hServicesKey = NULL;
2386 PSERVICE_HANDLE hSvc;
2387 PSERVICE lpService = NULL;
2388 PSERVICE *lpServicesArray = NULL;
2389 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2390 LPWSTR lpStr;
2391
2392 *pcbBytesNeeded = 0;
2393 *lpServicesReturned = 0;
2394
2395 DPRINT("REnumDependentServicesW() called\n");
2396
2397 hSvc = ScmGetServiceFromHandle(hService);
2398 if (hSvc == NULL)
2399 {
2400 DPRINT1("Invalid service handle!\n");
2401 return ERROR_INVALID_HANDLE;
2402 }
2403
2404 lpService = hSvc->ServiceEntry;
2405
2406 /* Check access rights */
2407 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2408 SC_MANAGER_ENUMERATE_SERVICE))
2409 {
2410 DPRINT("Insufficient access rights! 0x%lx\n",
2411 hSvc->Handle.DesiredAccess);
2412 return ERROR_ACCESS_DENIED;
2413 }
2414
2415 /* Open the Services Reg key */
2416 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2417 L"System\\CurrentControlSet\\Services",
2418 0,
2419 KEY_READ,
2420 &hServicesKey);
2421 if (dwError != ERROR_SUCCESS)
2422 return dwError;
2423
2424 /* First determine the bytes needed and get the number of dependent services */
2425 dwError = Int_EnumDependentServicesW(hServicesKey,
2426 lpService,
2427 dwServiceState,
2428 NULL,
2429 pcbBytesNeeded,
2430 &dwServicesReturned);
2431 if (dwError != ERROR_SUCCESS)
2432 goto Done;
2433
2434 /* If buffer size is less than the bytes needed or pointer is null */
2435 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2436 {
2437 dwError = ERROR_MORE_DATA;
2438 goto Done;
2439 }
2440
2441 /* Allocate memory for array of service pointers */
2442 lpServicesArray = HeapAlloc(GetProcessHeap(),
2443 HEAP_ZERO_MEMORY,
2444 (dwServicesReturned + 1) * sizeof(PSERVICE));
2445 if (!lpServicesArray)
2446 {
2447 DPRINT1("Could not allocate a buffer!!\n");
2448 dwError = ERROR_NOT_ENOUGH_MEMORY;
2449 goto Done;
2450 }
2451
2452 dwServicesReturned = 0;
2453 *pcbBytesNeeded = 0;
2454
2455 dwError = Int_EnumDependentServicesW(hServicesKey,
2456 lpService,
2457 dwServiceState,
2458 lpServicesArray,
2459 pcbBytesNeeded,
2460 &dwServicesReturned);
2461 if (dwError != ERROR_SUCCESS)
2462 {
2463 goto Done;
2464 }
2465
2466 lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2467 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2468
2469 /* Copy EnumDepenedentService to Buffer */
2470 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2471 {
2472 lpService = lpServicesArray[dwServiceCount];
2473
2474 /* Copy status info */
2475 memcpy(&lpServicesPtr->ServiceStatus,
2476 &lpService->Status,
2477 sizeof(SERVICE_STATUS));
2478
2479 /* Copy display name */
2480 wcscpy(lpStr, lpService->lpDisplayName);
2481 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2482 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2483
2484 /* Copy service name */
2485 wcscpy(lpStr, lpService->lpServiceName);
2486 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2487 lpStr += (wcslen(lpService->lpServiceName) + 1);
2488
2489 lpServicesPtr++;
2490 }
2491
2492 *lpServicesReturned = dwServicesReturned;
2493
2494 Done:
2495 if (lpServicesArray != NULL)
2496 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2497
2498 RegCloseKey(hServicesKey);
2499
2500 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2501
2502 return dwError;
2503 }
2504
2505
2506 /* Function 14 */
2507 DWORD REnumServicesStatusW(
2508 SC_RPC_HANDLE hSCManager,
2509 DWORD dwServiceType,
2510 DWORD dwServiceState,
2511 LPBYTE lpBuffer,
2512 DWORD dwBufSize,
2513 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2514 LPBOUNDED_DWORD_256K lpServicesReturned,
2515 LPBOUNDED_DWORD_256K lpResumeHandle)
2516 {
2517 /* Enumerate all the services, not regarding of their group */
2518 return REnumServiceGroupW(hSCManager,
2519 dwServiceType,
2520 dwServiceState,
2521 lpBuffer,
2522 dwBufSize,
2523 pcbBytesNeeded,
2524 lpServicesReturned,
2525 lpResumeHandle,
2526 NULL);
2527 }
2528
2529
2530 /* Function 15 */
2531 DWORD ROpenSCManagerW(
2532 LPWSTR lpMachineName,
2533 LPWSTR lpDatabaseName,
2534 DWORD dwDesiredAccess,
2535 LPSC_RPC_HANDLE lpScHandle)
2536 {
2537 DWORD dwError;
2538 SC_HANDLE hHandle;
2539
2540 DPRINT("ROpenSCManagerW() called\n");
2541 DPRINT("lpMachineName = %p\n", lpMachineName);
2542 DPRINT("lpMachineName: %S\n", lpMachineName);
2543 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2544 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2545 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2546
2547 if (ScmShutdown)
2548 return ERROR_SHUTDOWN_IN_PROGRESS;
2549
2550 if (!lpScHandle)
2551 return ERROR_INVALID_PARAMETER;
2552
2553 dwError = ScmCreateManagerHandle(lpDatabaseName,
2554 &hHandle);
2555 if (dwError != ERROR_SUCCESS)
2556 {
2557 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2558 return dwError;
2559 }
2560
2561 /* Check the desired access */
2562 dwError = ScmCheckAccess(hHandle,
2563 dwDesiredAccess | SC_MANAGER_CONNECT);
2564 if (dwError != ERROR_SUCCESS)
2565 {
2566 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2567 HeapFree(GetProcessHeap(), 0, hHandle);
2568 return dwError;
2569 }
2570
2571 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2572 DPRINT("*hScm = %p\n", *lpScHandle);
2573
2574 DPRINT("ROpenSCManagerW() done\n");
2575
2576 return ERROR_SUCCESS;
2577 }
2578
2579
2580 /* Function 16 */
2581 DWORD ROpenServiceW(
2582 SC_RPC_HANDLE hSCManager,
2583 LPWSTR lpServiceName,
2584 DWORD dwDesiredAccess,
2585 LPSC_RPC_HANDLE lpServiceHandle)
2586 {
2587 PSERVICE lpService;
2588 PMANAGER_HANDLE hManager;
2589 SC_HANDLE hHandle;
2590 DWORD dwError = ERROR_SUCCESS;
2591
2592 DPRINT("ROpenServiceW() called\n");
2593 DPRINT("hSCManager = %p\n", hSCManager);
2594 DPRINT("lpServiceName = %p\n", lpServiceName);
2595 DPRINT("lpServiceName: %S\n", lpServiceName);
2596 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2597
2598 if (ScmShutdown)
2599 return ERROR_SHUTDOWN_IN_PROGRESS;
2600
2601 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2602 if (hManager == NULL)
2603 {
2604 DPRINT1("Invalid service manager handle!\n");
2605 return ERROR_INVALID_HANDLE;
2606 }
2607
2608 if (!lpServiceHandle)
2609 return ERROR_INVALID_PARAMETER;
2610
2611 if (!lpServiceName)
2612 return ERROR_INVALID_ADDRESS;
2613
2614 /* Lock the service database exclusive */
2615 ScmLockDatabaseExclusive();
2616
2617 /* Get service database entry */
2618 lpService = ScmGetServiceEntryByName(lpServiceName);
2619 if (lpService == NULL)
2620 {
2621 DPRINT("Could not find a service!\n");
2622 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2623 goto Done;
2624 }
2625
2626 /* Create a service handle */
2627 dwError = ScmCreateServiceHandle(lpService,
2628 &hHandle);
2629 if (dwError != ERROR_SUCCESS)
2630 {
2631 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2632 goto Done;
2633 }
2634
2635 /* Check the desired access */
2636 dwError = ScmCheckAccess(hHandle,
2637 dwDesiredAccess);
2638 if (dwError != ERROR_SUCCESS)
2639 {
2640 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2641 HeapFree(GetProcessHeap(), 0, hHandle);
2642 goto Done;
2643 }
2644
2645 lpService->dwRefCount++;
2646 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2647
2648 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2649 DPRINT("*hService = %p\n", *lpServiceHandle);
2650
2651 Done:
2652 /* Unlock the service database */
2653 ScmUnlockDatabase();
2654
2655 DPRINT("ROpenServiceW() done\n");
2656
2657 return dwError;
2658 }
2659
2660
2661 /* Function 17 */
2662 DWORD RQueryServiceConfigW(
2663 SC_RPC_HANDLE hService,
2664 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2665 DWORD cbBufSize,
2666 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2667 {
2668 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2669 DWORD dwError = ERROR_SUCCESS;
2670 PSERVICE_HANDLE hSvc;
2671 PSERVICE lpService = NULL;
2672 HKEY hServiceKey = NULL;
2673 LPWSTR lpImagePath = NULL;
2674 LPWSTR lpServiceStartName = NULL;
2675 LPWSTR lpDependencies = NULL;
2676 DWORD dwDependenciesLength = 0;
2677 DWORD dwRequiredSize;
2678 WCHAR lpEmptyString[] = {0,0};
2679 LPWSTR lpStr;
2680
2681 DPRINT("RQueryServiceConfigW() called\n");
2682
2683 if (ScmShutdown)
2684 return ERROR_SHUTDOWN_IN_PROGRESS;
2685
2686 hSvc = ScmGetServiceFromHandle(hService);
2687 if (hSvc == NULL)
2688 {
2689 DPRINT1("Invalid service handle!\n");
2690 return ERROR_INVALID_HANDLE;
2691 }
2692
2693 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2694 SERVICE_QUERY_CONFIG))
2695 {
2696 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2697 return ERROR_ACCESS_DENIED;
2698 }
2699
2700 lpService = hSvc->ServiceEntry;
2701 if (lpService == NULL)
2702 {
2703 DPRINT("lpService == NULL!\n");
2704 return ERROR_INVALID_HANDLE;
2705 }
2706
2707 /* Lock the service database shared */
2708 ScmLockDatabaseShared();
2709
2710 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2711 KEY_READ,
2712 &hServiceKey);
2713 if (dwError != ERROR_SUCCESS)
2714 goto Done;
2715
2716 /* Read the image path */
2717 dwError = ScmReadString(hServiceKey,
2718 L"ImagePath",
2719 &lpImagePath);
2720 if (dwError != ERROR_SUCCESS)
2721 goto Done;
2722
2723 /* Read the service start name */
2724 ScmReadString(hServiceKey,
2725 L"ObjectName",
2726 &lpServiceStartName);
2727
2728 /* Read the dependencies */
2729 ScmReadDependencies(hServiceKey,
2730 &lpDependencies,
2731 &dwDependenciesLength);
2732
2733 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2734
2735 if (lpImagePath != NULL)
2736 dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2737 else
2738 dwRequiredSize += 2 * sizeof(WCHAR);
2739
2740 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2741 dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2742 else
2743 dwRequiredSize += 2 * sizeof(WCHAR);
2744
2745 if (lpDependencies != NULL)
2746 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2747 else
2748 dwRequiredSize += 2 * sizeof(WCHAR);
2749
2750 if (lpServiceStartName != NULL)
2751 dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2752 else
2753 dwRequiredSize += 2 * sizeof(WCHAR);
2754
2755 if (lpService->lpDisplayName != NULL)
2756 dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2757 else
2758 dwRequiredSize += 2 * sizeof(WCHAR);
2759
2760 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2761 {
2762 dwError = ERROR_INSUFFICIENT_BUFFER;
2763 }
2764 else
2765 {
2766 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
2767 lpServiceConfig->dwStartType = lpService->dwStartType;
2768 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
2769 lpServiceConfig->dwTagId = lpService->dwTag;
2770
2771 lpStr = (LPWSTR)(lpServiceConfig + 1);
2772
2773 /* Append the image path */
2774 if (lpImagePath != NULL)
2775 {
2776 wcscpy(lpStr, lpImagePath);
2777 }
2778 else
2779 {
2780 wcscpy(lpStr, lpEmptyString);
2781 }
2782
2783 lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2784 lpStr += (wcslen(lpStr) + 1);
2785
2786 /* Append the group name */
2787 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2788 {
2789 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2790 }
2791 else
2792 {
2793 wcscpy(lpStr, lpEmptyString);
2794 }
2795
2796 lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2797 lpStr += (wcslen(lpStr) + 1);
2798
2799 /* Append Dependencies */
2800 if (lpDependencies != NULL)
2801 {
2802 memcpy(lpStr,
2803 lpDependencies,
2804 dwDependenciesLength * sizeof(WCHAR));
2805 }
2806 else
2807 {
2808 wcscpy(lpStr, lpEmptyString);
2809 }
2810
2811 lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2812 if (lpDependencies != NULL)
2813 lpStr += dwDependenciesLength;
2814 else
2815 lpStr += (wcslen(lpStr) + 1);
2816
2817 /* Append the service start name */
2818 if (lpServiceStartName != NULL)
2819 {
2820 wcscpy(lpStr, lpServiceStartName);
2821 }
2822 else
2823 {
2824 wcscpy(lpStr, lpEmptyString);
2825 }
2826
2827 lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2828 lpStr += (wcslen(lpStr) + 1);
2829
2830 /* Append the display name */
2831 if (lpService->lpDisplayName != NULL)
2832 {
2833 wcscpy(lpStr, lpService->lpDisplayName);
2834 }
2835 else
2836 {
2837 wcscpy(lpStr, lpEmptyString);
2838 }
2839
2840 lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2841 }
2842
2843 if (pcbBytesNeeded != NULL)
2844 *pcbBytesNeeded = dwRequiredSize;
2845
2846 Done:
2847 /* Unlock the service database */
2848 ScmUnlockDatabase();
2849
2850 if (lpImagePath != NULL)
2851 HeapFree(GetProcessHeap(), 0, lpImagePath);
2852
2853 if (lpServiceStartName != NULL)
2854 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2855
2856 if (lpDependencies != NULL)
2857 HeapFree(GetProcessHeap(), 0, lpDependencies);
2858
2859 if (hServiceKey != NULL)
2860 RegCloseKey(hServiceKey);
2861
2862 DPRINT("RQueryServiceConfigW() done\n");
2863
2864 return dwError;
2865 }
2866
2867
2868 /* Function 18 */
2869 DWORD RQueryServiceLockStatusW(
2870 SC_RPC_HANDLE hSCManager,
2871 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2872 DWORD cbBufSize,
2873 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2874 {
2875 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf;
2876 PMANAGER_HANDLE hMgr;
2877 DWORD dwRequiredSize;
2878
2879 if (!lpLockStatus || !pcbBytesNeeded)
2880 return ERROR_INVALID_PARAMETER;
2881
2882 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
2883 if (hMgr == NULL)
2884 {
2885 DPRINT1("Invalid service manager handle!\n");
2886 return ERROR_INVALID_HANDLE;
2887 }
2888
2889 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
2890 SC_MANAGER_QUERY_LOCK_STATUS))
2891 {
2892 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
2893 return ERROR_ACCESS_DENIED;
2894 }
2895
2896 /* FIXME: we need to compute instead the real length of the owner name */
2897 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
2898 *pcbBytesNeeded = dwRequiredSize;
2899
2900 if (cbBufSize < dwRequiredSize)
2901 return ERROR_INSUFFICIENT_BUFFER;
2902
2903 ScmQueryServiceLockStatusW(lpLockStatus);
2904
2905 return ERROR_SUCCESS;
2906 }
2907
2908
2909 /* Function 19 */
2910 DWORD RStartServiceW(
2911 SC_RPC_HANDLE hService,
2912 DWORD argc,
2913 LPSTRING_PTRSW argv)
2914 {
2915 DWORD dwError = ERROR_SUCCESS;
2916 PSERVICE_HANDLE hSvc;
2917 PSERVICE lpService = NULL;
2918
2919 #ifndef NDEBUG
2920 DWORD i;
2921
2922 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
2923 DPRINT(" argc: %lu\n", argc);
2924 if (argv != NULL)
2925 {
2926 for (i = 0; i < argc; i++)
2927 {
2928 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
2929 }
2930 }
2931 #endif
2932
2933 if (ScmShutdown)
2934 return ERROR_SHUTDOWN_IN_PROGRESS;
2935
2936 hSvc = ScmGetServiceFromHandle(hService);
2937 if (hSvc == NULL)
2938 {
2939 DPRINT1("Invalid service handle!\n");
2940 return ERROR_INVALID_HANDLE;
2941 }
2942
2943 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2944 SERVICE_START))
2945 {
2946 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2947 return ERROR_ACCESS_DENIED;
2948 }
2949
2950 lpService = hSvc->ServiceEntry;
2951 if (lpService == NULL)
2952 {
2953 DPRINT("lpService == NULL!\n");
2954 return ERROR_INVALID_HANDLE;
2955 }
2956
2957 if (lpService->dwStartType == SERVICE_DISABLED)
2958 return ERROR_SERVICE_DISABLED;
2959
2960 if (lpService->bDeleted)
2961 return ERROR_SERVICE_MARKED_FOR_DELETE;
2962
2963 /* Start the service */
2964 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
2965
2966 return dwError;
2967 }
2968
2969
2970 /* Function 20 */
2971 DWORD RGetServiceDisplayNameW(
2972 SC_RPC_HANDLE hSCManager,
2973 LPCWSTR lpServiceName,
2974 LPWSTR lpDisplayName,
2975 DWORD *lpcchBuffer)
2976 {
2977 // PMANAGER_HANDLE hManager;
2978 PSERVICE lpService;
2979 DWORD dwLength;
2980 DWORD dwError;
2981
2982 DPRINT("RGetServiceDisplayNameW() called\n");
2983 DPRINT("hSCManager = %p\n", hSCManager);
2984 DPRINT("lpServiceName: %S\n", lpServiceName);
2985 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2986 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2987
2988 // hManager = (PMANAGER_HANDLE)hSCManager;
2989 // if (hManager->Handle.Tag != MANAGER_TAG)
2990 // {
2991 // DPRINT("Invalid manager handle!\n");
2992 // return ERROR_INVALID_HANDLE;
2993 // }
2994
2995 /* Get service database entry */
2996 lpService = ScmGetServiceEntryByName(lpServiceName);
2997 if (lpService == NULL)
2998 {
2999 DPRINT("Could not find a service!\n");
3000
3001 /* If the service could not be found and lpcchBuffer is less than 2, windows
3002 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3003 if (*lpcchBuffer < 2)
3004 {
3005 *lpcchBuffer = 2;
3006 if (lpDisplayName != NULL)
3007 {
3008 *lpDisplayName = 0;
3009 }
3010 }
3011
3012 return ERROR_SERVICE_DOES_NOT_EXIST;
3013 }
3014
3015 if (!lpService->lpDisplayName)
3016 {
3017 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3018
3019 if (lpDisplayName != NULL &&
3020 *lpcchBuffer > dwLength)
3021 {
3022 wcscpy(lpDisplayName, lpService->lpServiceName);
3023 }
3024 }
3025 else
3026 {
3027 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
3028
3029 if (lpDisplayName != NULL &&
3030 *lpcchBuffer > dwLength)
3031 {
3032 wcscpy(lpDisplayName, lpService->lpDisplayName);
3033 }
3034 }
3035
3036 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3037
3038 *lpcchBuffer = dwLength;
3039
3040 return dwError;
3041 }
3042
3043
3044 /* Function 21 */
3045 DWORD RGetServiceKeyNameW(
3046 SC_RPC_HANDLE hSCManager,
3047 LPCWSTR lpDisplayName,
3048 LPWSTR lpServiceName,
3049 DWORD *lpcchBuffer)
3050 {
3051 // PMANAGER_HANDLE hManager;
3052 PSERVICE lpService;
3053 DWORD dwLength;
3054 DWORD dwError;
3055
3056 DPRINT("RGetServiceKeyNameW() called\n");
3057 DPRINT("hSCManager = %p\n", hSCManager);
3058 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3059 DPRINT("lpServiceName: %p\n", lpServiceName);
3060 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3061
3062 // hManager = (PMANAGER_HANDLE)hSCManager;
3063 // if (hManager->Handle.Tag != MANAGER_TAG)
3064 // {
3065 // DPRINT("Invalid manager handle!\n");
3066 // return ERROR_INVALID_HANDLE;
3067 // }
3068
3069 /* Get service database entry */
3070 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3071 if (lpService == NULL)
3072 {
3073 DPRINT("Could not find a service!\n");
3074
3075 /* If the service could not be found and lpcchBuffer is less than 2, windows
3076 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3077 if (*lpcchBuffer < 2)
3078 {
3079 *lpcchBuffer = 2;
3080 if (lpServiceName != NULL)
3081 {
3082 *lpServiceName = 0;
3083 }
3084 }
3085
3086 return ERROR_SERVICE_DOES_NOT_EXIST;
3087 }
3088
3089 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3090
3091 if (lpServiceName != NULL &&
3092 *lpcchBuffer > dwLength)
3093 {
3094 wcscpy(lpServiceName, lpService->lpServiceName);
3095 *lpcchBuffer = dwLength;
3096 return ERROR_SUCCESS;
3097 }
3098
3099 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3100
3101 *lpcchBuffer = dwLength;
3102
3103 return dwError;
3104 }
3105
3106
3107 /* Function 22 */
3108 DWORD RI_ScSetServiceBitsA(
3109 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3110 DWORD dwServiceBits,
3111 int bSetBitsOn,
3112 int bUpdateImmediately,
3113 char *lpString)
3114 {
3115 UNIMPLEMENTED;
3116 return ERROR_CALL_NOT_IMPLEMENTED;
3117 }
3118
3119
3120 /* Function 23 */
3121 DWORD RChangeServiceConfigA(
3122 SC_RPC_HANDLE hService,
3123 DWORD dwServiceType,
3124 DWORD dwStartType,
3125 DWORD dwErrorControl,
3126 LPSTR lpBinaryPathName,
3127 LPSTR lpLoadOrderGroup,
3128 LPDWORD lpdwTagId,
3129 LPBYTE lpDependencies,
3130 DWORD dwDependSize,
3131 LPSTR lpServiceStartName,
3132 LPBYTE lpPassword,
3133 DWORD dwPwSize,
3134 LPSTR lpDisplayName)
3135 {
3136 DWORD dwError = ERROR_SUCCESS;
3137 PSERVICE_HANDLE hSvc;
3138 PSERVICE lpService = NULL;
3139 HKEY hServiceKey = NULL;
3140 LPWSTR lpDisplayNameW = NULL;
3141 LPWSTR lpBinaryPathNameW = NULL;
3142 LPWSTR lpCanonicalImagePathW = NULL;
3143 LPWSTR lpLoadOrderGroupW = NULL;
3144 LPWSTR lpDependenciesW = NULL;
3145
3146 DPRINT("RChangeServiceConfigA() called\n");
3147 DPRINT("dwServiceType = %lu\n", dwServiceType);
3148 DPRINT("dwStartType = %lu\n", dwStartType);
3149 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3150 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3151 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3152 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3153
3154 if (ScmShutdown)
3155 return ERROR_SHUTDOWN_IN_PROGRESS;
3156
3157 hSvc = ScmGetServiceFromHandle(hService);
3158 if (hSvc == NULL)
3159 {
3160 DPRINT1("Invalid service handle!\n");
3161 return ERROR_INVALID_HANDLE;
3162 }
3163
3164 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3165 SERVICE_CHANGE_CONFIG))
3166 {
3167 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3168 return ERROR_ACCESS_DENIED;
3169 }
3170
3171 lpService = hSvc->ServiceEntry;
3172 if (lpService == NULL)
3173 {
3174 DPRINT("lpService == NULL!\n");
3175 return ERROR_INVALID_HANDLE;
3176 }
3177
3178 /* Lock the service database exclusively */
3179 ScmLockDatabaseExclusive();
3180
3181 if (lpService->bDeleted)
3182 {
3183 DPRINT("The service has already been marked for delete!\n");
3184 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
3185 goto done;
3186 }
3187
3188 /* Open the service key */
3189 dwError = ScmOpenServiceKey(lpService->szServiceName,
3190 KEY_SET_VALUE,
3191 &hServiceKey);
3192 if (dwError != ERROR_SUCCESS)
3193 goto done;
3194
3195 /* Write service data to the registry */
3196
3197 if (lpDisplayName != NULL && *lpDisplayName != 0)
3198 {
3199 /* Set the display name */
3200 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3201 HEAP_ZERO_MEMORY,
3202 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3203 if (lpDisplayNameW == NULL)
3204 {
3205 dwError = ERROR_NOT_ENOUGH_MEMORY;
3206 goto done;
3207 }
3208
3209 MultiByteToWideChar(CP_ACP,
3210 0,
3211 lpDisplayName,
3212 -1,
3213 lpDisplayNameW,
3214 (int)(strlen(lpDisplayName) + 1));
3215
3216 RegSetValueExW(hServiceKey,
3217 L"DisplayName",
3218 0,
3219 REG_SZ,
3220 (LPBYTE)lpDisplayNameW,
3221 (DWORD)((wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR)));
3222
3223 /* Update lpService->lpDisplayName */
3224 if (lpService->lpDisplayName)
3225 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3226
3227 lpService->lpDisplayName = lpDisplayNameW;
3228 }
3229
3230 if (dwServiceType != SERVICE_NO_CHANGE)
3231 {
3232 /* Set the service type */
3233 dwError = RegSetValueExW(hServiceKey,
3234 L"Type",
3235 0,
3236 REG_DWORD,
3237 (LPBYTE)&dwServiceType,
3238 sizeof(DWORD));
3239 if (dwError != ERROR_SUCCESS)
3240 goto done;
3241
3242 lpService->Status.dwServiceType = dwServiceType;
3243 }
3244
3245 if (dwStartType != SERVICE_NO_CHANGE)
3246 {
3247 /* Set the start value */
3248 dwError = RegSetValueExW(hServiceKey,
3249 L"Start",
3250 0,
3251 REG_DWORD,
3252 (LPBYTE)&dwStartType,
3253 sizeof(DWORD));
3254 if (dwError != ERROR_SUCCESS)
3255 goto done;
3256
3257 lpService->dwStartType = dwStartType;
3258 }
3259
3260 if (dwErrorControl != SERVICE_NO_CHANGE)
3261 {
3262 /* Set the error control value */
3263 dwError = RegSetValueExW(hServiceKey,
3264 L"ErrorControl",
3265 0,
3266 REG_DWORD,
3267 (LPBYTE)&dwErrorControl,
3268 sizeof(DWORD));
3269 if (dwError != ERROR_SUCCESS)
3270 goto done;
3271
3272 lpService->dwErrorControl = dwErrorControl;
3273 }
3274
3275 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3276 {
3277 /* Set the image path */
3278 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
3279 HEAP_ZERO_MEMORY,
3280 (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
3281 if (lpBinaryPathNameW == NULL)
3282 {
3283 dwError = ERROR_NOT_ENOUGH_MEMORY;
3284 goto done;
3285 }
3286
3287 MultiByteToWideChar(CP_ACP,
3288 0,
3289 lpBinaryPathName,
3290 -1,
3291 lpBinaryPathNameW,
3292 (int)(strlen(lpBinaryPathName) + 1));
3293
3294 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
3295 {
3296 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
3297 lpBinaryPathNameW,
3298 &lpCanonicalImagePathW);
3299
3300 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3301
3302 if (dwError != ERROR_SUCCESS)
3303 goto done;
3304
3305 lpBinaryPathNameW = lpCanonicalImagePathW;
3306 }
3307
3308 dwError = RegSetValueExW(hServiceKey,
3309 L"ImagePath",
3310 0,
3311 REG_EXPAND_SZ,
3312 (LPBYTE)lpBinaryPathNameW,
3313 (DWORD)((wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR)));
3314
3315 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3316
3317 if (dwError != ERROR_SUCCESS)
3318 goto done;
3319 }
3320
3321 /* Set the group name */
3322 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3323 {
3324 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3325 HEAP_ZERO_MEMORY,
3326 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3327 if (lpLoadOrderGroupW == NULL)
3328 {
3329 dwError = ERROR_NOT_ENOUGH_MEMORY;
3330 goto done;
3331 }
3332
3333 MultiByteToWideChar(CP_ACP,
3334 0,
3335 lpLoadOrderGroup,
3336 -1,
3337 lpLoadOrderGroupW,
3338 (int)(strlen(lpLoadOrderGroup) + 1));
3339
3340 dwError = RegSetValueExW(hServiceKey,
3341 L"Group",
3342 0,
3343 REG_SZ,
3344 (LPBYTE)lpLoadOrderGroupW,
3345 (DWORD)((wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR)));
3346 if (dwError != ERROR_SUCCESS)
3347 {
3348 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3349 goto done;
3350 }
3351
3352 dwError = ScmSetServiceGroup(lpService,
3353 lpLoadOrderGroupW);
3354
3355 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3356
3357 if (dwError != ERROR_SUCCESS)
3358 goto done;
3359 }
3360
3361 if (lpdwTagId != NULL)
3362 {
3363 dwError = ScmAssignNewTag(lpService);
3364 if (dwError != ERROR_SUCCESS)
3365 goto done;
3366
3367 dwError = RegSetValueExW(hServiceKey,
3368 L"Tag",
3369 0,
3370 REG_DWORD,
3371 (LPBYTE)&lpService->dwTag,
3372 sizeof(DWORD));
3373 if (dwError != ERROR_SUCCESS)
3374 goto done;
3375
3376 *lpdwTagId = lpService->dwTag;
3377 }
3378
3379 /* Write dependencies */
3380 if (lpDependencies != NULL && *lpDependencies != 0)
3381 {
3382 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3383 HEAP_ZERO_MEMORY,
3384 (strlen((LPSTR)lpDependencies) + 1) * sizeof(WCHAR));
3385 if (lpDependenciesW == NULL)
3386 {
3387 dwError = ERROR_NOT_ENOUGH_MEMORY;
3388 goto done;
3389 }
3390
3391 MultiByteToWideChar(CP_ACP,
3392 0,
3393 (LPSTR)lpDependencies,
3394 dwDependSize,
3395 lpDependenciesW,
3396 (int)(strlen((LPSTR)lpDependencies) + 1));
3397
3398 dwError = ScmWriteDependencies(hServiceKey,
3399 (LPWSTR)lpDependenciesW,
3400 dwDependSize);
3401
3402 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3403 }
3404
3405 if (lpPassword != NULL)
3406 {
3407 /* FIXME: Decrypt and write password */
3408 }
3409
3410 done:
3411 /* Unlock the service database */
3412 ScmUnlockDatabase();
3413
3414 if (hServiceKey != NULL)
3415 RegCloseKey(hServiceKey);
3416
3417 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3418
3419 return dwError;
3420 }
3421
3422
3423 /* Function 24 */
3424 DWORD RCreateServiceA(
3425 SC_RPC_HANDLE hSCManager,
3426 LPSTR lpServiceName,
3427 LPSTR lpDisplayName,
3428 DWORD dwDesiredAccess,
3429 DWORD dwServiceType,
3430 DWORD dwStartType,
3431 DWORD dwErrorControl,
3432 LPSTR lpBinaryPathName,
3433 LPSTR lpLoadOrderGroup,
3434 LPDWORD lpdwTagId,
3435 LPBYTE lpDependencies,
3436 DWORD dwDependSize,
3437 LPSTR lpServiceStartName,
3438 LPBYTE lpPassword,
3439 DWORD dwPwSize,
3440 LPSC_RPC_HANDLE lpServiceHandle)
3441 {
3442 DWORD dwError = ERROR_SUCCESS;
3443 LPWSTR lpServiceNameW = NULL;
3444 LPWSTR lpDisplayNameW = NULL;
3445 LPWSTR lpBinaryPathNameW = NULL;
3446 LPWSTR lpLoadOrderGroupW = NULL;
3447 LPWSTR lpDependenciesW = NULL;
3448 LPWSTR lpServiceStartNameW = NULL;
3449 DWORD dwDependenciesLength = 0;
3450 SIZE_T cchLength;
3451 int len;
3452 LPCSTR lpStr;
3453
3454 if (lpServiceName)
3455 {
3456 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3457 lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3458 if (!lpServiceNameW)
3459 {
3460 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3461 goto cleanup;
3462 }
3463 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3464 }
3465
3466 if (lpDisplayName)
3467 {
3468 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3469 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3470 if (!lpDisplayNameW)
3471 {
3472 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3473 goto cleanup;
3474 }
3475 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3476 }
3477
3478 if (lpBinaryPathName)
3479 {
3480 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3481 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3482 if (!lpBinaryPathNameW)
3483 {
3484 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3485 goto cleanup;
3486 }
3487 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3488 }
3489
3490 if (lpLoadOrderGroup)
3491 {
3492 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3493 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3494 if (!lpLoadOrderGroupW)
3495 {
3496 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3497 goto cleanup;
3498 }
3499 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3500 }
3501
3502 if (lpDependencies)
3503 {
3504 lpStr = (LPCSTR)lpDependencies;
3505 while (*lpStr)
3506 {
3507 cchLength = strlen(lpStr) + 1;
3508 dwDependenciesLength += (DWORD)cchLength;
3509 lpStr = lpStr + cchLength;
3510 }
3511 dwDependenciesLength++;
3512
3513 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3514 if (!lpDependenciesW)
3515 {
3516 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3517 goto cleanup;
3518 }
3519 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3520 }
3521
3522 if (lpServiceStartName)
3523 {
3524 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3525 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3526 if (!lpServiceStartNameW)
3527 {
3528 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3529 goto cleanup;
3530 }
3531 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3532 }
3533
3534 dwError = RCreateServiceW(hSCManager,
3535 lpServiceNameW,
3536 lpDisplayNameW,
3537 dwDesiredAccess,
3538 dwServiceType,
3539 dwStartType,
3540 dwErrorControl,
3541 lpBinaryPathNameW,
3542 lpLoadOrderGroupW,
3543 lpdwTagId,
3544 (LPBYTE)lpDependenciesW,
3545 dwDependenciesLength,
3546 lpServiceStartNameW,
3547 lpPassword,
3548 dwPwSize,
3549 lpServiceHandle);
3550
3551 cleanup:
3552 if (lpServiceNameW !=NULL)
3553 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3554
3555 if (lpDisplayNameW != NULL)
3556 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3557
3558 if (lpBinaryPathNameW != NULL)
3559 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3560
3561 if (lpLoadOrderGroupW != NULL)
3562 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3563
3564 if (lpDependenciesW != NULL)
3565 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3566
3567 if (lpServiceStartNameW != NULL)
3568 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3569
3570 return dwError;
3571 }
3572
3573
3574 /* Function 25 */
3575 DWORD REnumDependentServicesA(
3576 SC_RPC_HANDLE hService,
3577 DWORD dwServiceState,
3578 LPBYTE lpServices,
3579 DWORD cbBufSize,
3580 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3581 LPBOUNDED_DWORD_256K lpServicesReturned)
3582 {
3583 DWORD dwError = ERROR_SUCCESS;
3584 DWORD dwServicesReturned = 0;
3585 DWORD dwServiceCount;
3586 HKEY hServicesKey = NULL;
3587 PSERVICE_HANDLE hSvc;
3588 PSERVICE lpService = NULL;
3589 PSERVICE *lpServicesArray = NULL;
3590 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3591 LPSTR lpStr;
3592
3593 *pcbBytesNeeded = 0;
3594 *lpServicesReturned = 0;
3595
3596 DPRINT("REnumDependentServicesA() called\n");
3597
3598 hSvc = ScmGetServiceFromHandle(hService);
3599 if (hSvc == NULL)
3600 {
3601 DPRINT1("Invalid service handle!\n");
3602 return ERROR_INVALID_HANDLE;
3603 }
3604
3605 lpService = hSvc->ServiceEntry;
3606
3607 /* Check access rights */
3608 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3609 SC_MANAGER_ENUMERATE_SERVICE))
3610 {
3611 DPRINT("Insufficient access rights! 0x%lx\n",
3612 hSvc->Handle.DesiredAccess);
3613 return ERROR_ACCESS_DENIED;
3614 }
3615
3616 /* Open the Services Reg key */
3617 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3618 L"System\\CurrentControlSet\\Services",
3619 0,
3620 KEY_READ,
3621 &hServicesKey);
3622
3623 if (dwError != ERROR_SUCCESS)
3624 return dwError;
3625
3626 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3627 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3628 are the same for both. Verified in WINXP. */
3629
3630 /* First determine the bytes needed and get the number of dependent services*/
3631 dwError = Int_EnumDependentServicesW(hServicesKey,
3632 lpService,
3633 dwServiceState,
3634 NULL,
3635 pcbBytesNeeded,
3636 &dwServicesReturned);
3637 if (dwError != ERROR_SUCCESS)
3638 goto Done;
3639
3640 /* If buffer size is less than the bytes needed or pointer is null*/
3641 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3642 {
3643 dwError = ERROR_MORE_DATA;
3644 goto Done;
3645 }
3646
3647 /* Allocate memory for array of service pointers */
3648 lpServicesArray = HeapAlloc(GetProcessHeap(),
3649 HEAP_ZERO_MEMORY,
3650 (dwServicesReturned + 1) * sizeof(PSERVICE));
3651 if (!lpServicesArray)
3652 {
3653 DPRINT("Could not allocate a buffer!!\n");
3654 dwError = ERROR_NOT_ENOUGH_MEMORY;
3655 goto Done;
3656 }
3657
3658 dwServicesReturned = 0;
3659 *pcbBytesNeeded = 0;
3660
3661 dwError = Int_EnumDependentServicesW(hServicesKey,
3662 lpService,
3663 dwServiceState,
3664 lpServicesArray,
3665 pcbBytesNeeded,
3666 &dwServicesReturned);
3667 if (dwError != ERROR_SUCCESS)
3668 {
3669 goto Done;
3670 }
3671
3672 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3673 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3674
3675 /* Copy EnumDepenedentService to Buffer */
3676 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3677 {
3678 lpService = lpServicesArray[dwServiceCount];
3679
3680 /* Copy the status info */
3681 memcpy(&lpServicesPtr->ServiceStatus,
3682 &lpService->Status,
3683 sizeof(SERVICE_STATUS));
3684
3685 /* Copy display name */
3686 WideCharToMultiByte(CP_ACP,
3687 0,
3688 lpService->lpDisplayName,
3689 -1,
3690 lpStr,
3691 (int)wcslen(lpService->lpDisplayName),
3692 0,
3693 0);
3694 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3695 lpStr += strlen(lpStr) + 1;
3696
3697 /* Copy service name */
3698 WideCharToMultiByte(CP_ACP,
3699 0,
3700 lpService->lpServiceName,
3701 -1,
3702 lpStr,
3703 (int)wcslen(lpService->lpServiceName),
3704 0,
3705 0);
3706 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3707 lpStr += strlen(lpStr) + 1;
3708
3709 lpServicesPtr++;
3710 }
3711
3712 *lpServicesReturned = dwServicesReturned;
3713
3714 Done:
3715 if (lpServicesArray)
3716 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3717
3718 RegCloseKey(hServicesKey);
3719
3720 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3721
3722 return dwError;
3723 }
3724
3725
3726 /* Function 26 */
3727 DWORD REnumServicesStatusA(
3728 SC_RPC_HANDLE hSCManager,
3729 DWORD dwServiceType,
3730 DWORD dwServiceState,
3731 LPBYTE lpBuffer,
3732 DWORD dwBufSize,
3733 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3734 LPBOUNDED_DWORD_256K lpServicesReturned,
3735 LPBOUNDED_DWORD_256K lpResumeHandle)
3736 {
3737 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3738 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW;
3739 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3740 LPWSTR lpStringPtrW;
3741 LPSTR lpStringPtrA;
3742 DWORD dwError;
3743 DWORD dwServiceCount;
3744
3745 DPRINT("REnumServicesStatusA() called\n");
3746
3747 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
3748 {
3749 return ERROR_INVALID_ADDRESS;
3750 }
3751
3752 if ((dwBufSize > 0) && (lpBuffer))
3753 {
3754 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3755 if (!lpStatusPtrW)
3756 {
3757 DPRINT("Failed to allocate buffer!\n");
3758 return ERROR_NOT_ENOUGH_MEMORY;
3759 }
3760 }
3761
3762 dwError = REnumServicesStatusW(hSCManager,
3763 dwServiceType,
3764 dwServiceState,
3765 (LPBYTE)lpStatusPtrW,
3766 dwBufSize,
3767 pcbBytesNeeded,
3768 lpServicesReturned,
3769 lpResumeHandle);
3770
3771 /* if no services were returned then we are Done */
3772 if (*lpServicesReturned == 0)
3773 goto Done;
3774
3775 lpStatusPtrIncrW = lpStatusPtrW;
3776 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3777 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3778 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3779 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3780 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3781
3782 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3783 {
3784 /* Copy the service name */
3785 WideCharToMultiByte(CP_ACP,
3786 0,
3787 lpStringPtrW,
3788 -1,
3789 lpStringPtrA,
3790 (int)wcslen(lpStringPtrW),
3791 0,
3792 0);
3793
3794 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3795 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3796 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3797
3798 /* Copy the display name */
3799 WideCharToMultiByte(CP_ACP,
3800 0,
3801 lpStringPtrW,
3802 -1,
3803 lpStringPtrA,
3804 (int)wcslen(lpStringPtrW),
3805 0,
3806 0);
3807
3808 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3809 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3810 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3811
3812 /* Copy the status information */
3813 memcpy(&lpStatusPtrA->ServiceStatus,
3814 &lpStatusPtrIncrW->ServiceStatus,
3815 sizeof(SERVICE_STATUS));
3816
3817 lpStatusPtrIncrW++;
3818 lpStatusPtrA++;
3819 }
3820
3821 Done:
3822 if (lpStatusPtrW)
3823 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3824
3825 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3826
3827 return dwError;
3828 }
3829
3830
3831 /* Function 27 */
3832 DWORD ROpenSCManagerA(
3833 LPSTR lpMachineName,
3834 LPSTR lpDatabaseName,
3835 DWORD dwDesiredAccess,
3836 LPSC_RPC_HANDLE lpScHandle)
3837 {
3838 UNICODE_STRING MachineName;
3839 UNICODE_STRING DatabaseName;
3840 DWORD dwError;
3841
3842 DPRINT("ROpenSCManagerA() called\n");
3843
3844 if (lpMachineName)
3845 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3846 lpMachineName);
3847
3848 if (lpDatabaseName)
3849 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3850 lpDatabaseName);
3851
3852 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
3853 lpDatabaseName ? DatabaseName.Buffer : NULL,
3854 dwDesiredAccess,
3855 lpScHandle);
3856
3857 if (lpMachineName)
3858 RtlFreeUnicodeString(&MachineName);
3859
3860 if (lpDatabaseName)
3861 RtlFreeUnicodeString(&DatabaseName);
3862
3863 return dwError;
3864 }
3865
3866
3867 /* Function 28 */
3868 DWORD ROpenServiceA(
3869 SC_RPC_HANDLE hSCManager,
3870 LPSTR lpServiceName,
3871 DWORD dwDesiredAccess,
3872 LPSC_RPC_HANDLE lpServiceHandle)
3873 {
3874 UNICODE_STRING ServiceName;
3875 DWORD dwError;
3876
3877 DPRINT("ROpenServiceA() called\n");
3878
3879 if (lpServiceName)
3880 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3881 lpServiceName);
3882
3883 dwError = ROpenServiceW(hSCManager,
3884 lpServiceName ? ServiceName.Buffer : NULL,
3885 dwDesiredAccess,
3886 lpServiceHandle);
3887
3888 if (lpServiceName)
3889 RtlFreeUnicodeString(&ServiceName);
3890
3891 return dwError;
3892 }
3893
3894
3895 /* Function 29 */
3896 DWORD RQueryServiceConfigA(
3897 SC_RPC_HANDLE hService,
3898 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3899 DWORD cbBufSize,
3900 LPBOUNDED_DWORD_8K pcbBytesNeeded)
3901 {
3902 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
3903 DWORD dwError = ERROR_SUCCESS;
3904 PSERVICE_HANDLE hSvc;
3905 PSERVICE lpService = NULL;
3906 HKEY hServiceKey = NULL;
3907 LPWSTR lpImagePath = NULL;
3908 LPWSTR lpServiceStartName = NULL;
3909 LPWSTR lpDependencies = NULL;
3910 DWORD dwDependenciesLength = 0;
3911 DWORD dwRequiredSize;
3912 CHAR lpEmptyString[]={0,0};
3913 LPSTR lpStr;
3914
3915 DPRINT("RQueryServiceConfigA() called\n");
3916
3917 if (ScmShutdown)
3918 return ERROR_SHUTDOWN_IN_PROGRESS;
3919
3920 hSvc = ScmGetServiceFromHandle(hService);
3921 if (hSvc == NULL)
3922 {
3923 DPRINT1("Invalid service handle!\n");
3924 return ERROR_INVALID_HANDLE;
3925 }
3926
3927 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3928 SERVICE_QUERY_CONFIG))
3929 {
3930 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3931 return ERROR_ACCESS_DENIED;
3932 }
3933
3934 lpService = hSvc->ServiceEntry;
3935 if (lpService == NULL)
3936 {
3937 DPRINT("lpService == NULL!\n");
3938 return ERROR_INVALID_HANDLE;
3939 }
3940
3941 /* Lock the service database shared */
3942 ScmLockDatabaseShared();
3943
3944 dwError = ScmOpenServiceKey(lpService->lpServiceName,
3945 KEY_READ,
3946 &hServiceKey);
3947 if (dwError != ERROR_SUCCESS)
3948 goto Done;
3949
3950 /* Read the image path */
3951 dwError = ScmReadString(hServiceKey,
3952 L"ImagePath",
3953 &lpImagePath);
3954 if (dwError != ERROR_SUCCESS)
3955 goto Done;
3956
3957 /* Read the service start name */
3958 ScmReadString(hServiceKey,
3959 L"ObjectName",
3960 &lpServiceStartName);
3961
3962 /* Read the dependencies */
3963 ScmReadDependencies(hServiceKey,
3964 &lpDependencies,
3965 &dwDependenciesLength);
3966
3967 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGA);
3968
3969 if (lpImagePath != NULL)
3970 dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
3971 else
3972 dwRequiredSize += 2;
3973
3974 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3975 dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
3976 else
3977 dwRequiredSize += 2;
3978
3979 /* Add Dependencies length */
3980 if (lpDependencies != NULL)
3981 dwRequiredSize += dwDependenciesLength;
3982 else
3983 dwRequiredSize += 2;
3984
3985 if (lpServiceStartName != NULL)
3986 dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
3987 else
3988 dwRequiredSize += 2;
3989
3990 if (lpService->lpDisplayName != NULL)
3991 dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
3992 else
3993 dwRequiredSize += 2;
3994
3995 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3996 {
3997 dwError = ERROR_INSUFFICIENT_BUFFER;
3998 }
3999 else
4000 {
4001 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
4002 lpServiceConfig->dwStartType = lpService->dwStartType;
4003 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
4004 lpServiceConfig->dwTagId = lpService->dwTag;
4005
4006 lpStr = (LPSTR)(lpServiceConfig + 1);
4007
4008 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4009 Verified in WINXP */
4010
4011 if (lpImagePath)
4012 {
4013 WideCharToMultiByte(CP_ACP,
4014 0,
4015 lpImagePath,
4016 -1,
4017 lpStr,
4018 (int)(wcslen(lpImagePath) + 1),
4019 0,
4020 0);
4021 }
4022 else
4023 {
4024 strcpy(lpStr, lpEmptyString);
4025 }
4026
4027 lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4028 lpStr += (strlen((LPSTR)lpStr) + 1);
4029
4030 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4031 {
4032 WideCharToMultiByte(CP_ACP,
4033 0,
4034 lpService->lpGroup->lpGroupName,
4035 -1,
4036 lpStr,
4037 (int)(wcslen(lpService->lpGroup->lpGroupName) + 1),
4038 0,
4039 0);
4040 }
4041 else
4042 {
4043 strcpy(lpStr, lpEmptyString);
4044 }
4045
4046 lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4047 lpStr += (strlen(lpStr) + 1);
4048
4049 /* Append Dependencies */
4050 if (lpDependencies)
4051 {
4052 WideCharToMultiByte(CP_ACP,
4053 0,
4054 lpDependencies,
4055 dwDependenciesLength,
4056 lpStr,
4057 dwDependenciesLength,
4058 0,
4059 0);
4060 }
4061 else
4062 {
4063 strcpy(lpStr, lpEmptyString);
4064 }
4065
4066 lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4067 if (lpDependencies)
4068 lpStr += dwDependenciesLength;
4069 else
4070 lpStr += (strlen(lpStr) + 1);
4071
4072 if (lpServiceStartName)
4073 {
4074 WideCharToMultiByte(CP_ACP,
4075 0,
4076 lpServiceStartName,
4077 -1,
4078 lpStr,
4079 (int)(wcslen(lpServiceStartName) + 1),
4080 0,
4081 0);
4082 }
4083 else
4084 {
4085 strcpy(lpStr, lpEmptyString);
4086 }
4087
4088 lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4089 lpStr += (strlen(lpStr) + 1);
4090
4091 if (lpService->lpDisplayName)
4092 {
4093 WideCharToMultiByte(CP_ACP,
4094 0,
4095 lpService->lpDisplayName,
4096 -1,
4097 lpStr,
4098 (int)(wcslen(lpService->lpDisplayName) + 1),
4099 0,
4100 0);
4101 }
4102 else
4103 {
4104 strcpy(lpStr, lpEmptyString);
4105 }
4106
4107 lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
4108 }
4109
4110 if (pcbBytesNeeded != NULL)
4111 *pcbBytesNeeded = dwRequiredSize;
4112
4113 Done:
4114 /* Unlock the service database */
4115 ScmUnlockDatabase();
4116
4117 if (lpImagePath != NULL)
4118 HeapFree(GetProcessHeap(), 0, lpImagePath);
4119
4120 if (lpServiceStartName != NULL)
4121 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4122
4123 if (lpDependencies != NULL)
4124 HeapFree(GetProcessHeap(), 0, lpDependencies);
4125
4126 if (hServiceKey != NULL)
4127 RegCloseKey(hServiceKey);
4128
4129 DPRINT("RQueryServiceConfigA() done\n");
4130
4131 return dwError;
4132 }
4133
4134
4135 /* Function 30 */
4136 DWORD RQueryServiceLockStatusA(
4137 SC_RPC_HANDLE hSCManager,
4138 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4139 DWORD cbBufSize,
4140 LPBOUNDED_DWORD_4K pcbBytesNeeded)
4141 {
4142 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSA)lpBuf;
4143 PMANAGER_HANDLE hMgr;
4144 DWORD dwRequiredSize;
4145
4146 if (!lpLockStatus || !pcbBytesNeeded)
4147 return ERROR_INVALID_PARAMETER;
4148
4149 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
4150 if (hMgr == NULL)
4151 {
4152 DPRINT1("Invalid service manager handle!\n");
4153 return ERROR_INVALID_HANDLE;
4154 }
4155
4156 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
4157 SC_MANAGER_QUERY_LOCK_STATUS))
4158 {
4159 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
4160 return ERROR_ACCESS_DENIED;
4161 }
4162
4163 /* FIXME: we need to compute instead the real length of the owner name */
4164 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR);
4165 *pcbBytesNeeded = dwRequiredSize;
4166
4167 if (cbBufSize < dwRequiredSize)
4168 return ERROR_INSUFFICIENT_BUFFER;
4169
4170 ScmQueryServiceLockStatusA(lpLockStatus);
4171
4172 return ERROR_SUCCESS;
4173 }
4174
4175
4176 /* Function 31 */
4177 DWORD RStartServiceA(
4178 SC_RPC_HANDLE hService,
4179 DWORD argc,
4180 LPSTRING_PTRSA argv)
4181 {
4182 DWORD dwError = ERROR_SUCCESS;
4183 PSERVICE_HANDLE hSvc;
4184 PSERVICE lpService = NULL;
4185 LPWSTR *lpVector = NULL;
4186 DWORD i;
4187 DWORD dwLength;
4188
4189 DPRINT("RStartServiceA() called\n");
4190
4191 if (ScmShutdown)
4192 return ERROR_SHUTDOWN_IN_PROGRESS;
4193
4194 hSvc = ScmGetServiceFromHandle(hService);
4195 if (hSvc == NULL)
4196 {
4197 DPRINT1("Invalid service handle!\n");
4198 return ERROR_INVALID_HANDLE;
4199 }
4200
4201 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4202 SERVICE_START))
4203 {
4204 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4205 return ERROR_ACCESS_DENIED;
4206 }
4207
4208 lpService = hSvc->ServiceEntry;
4209 if (lpService == NULL)
4210 {
4211 DPRINT("lpService == NULL!\n");
4212 return ERROR_INVALID_HANDLE;
4213 }
4214
4215 if (lpService->dwStartType == SERVICE_DISABLED)
4216 return ERROR_SERVICE_DISABLED;
4217
4218 if (lpService->bDeleted)
4219 return ERROR_SERVICE_MARKED_FOR_DELETE;
4220
4221 /* Build a Unicode argument vector */
4222 if (argc > 0)
4223 {
4224 lpVector = HeapAlloc(GetProcessHeap(),
4225 HEAP_ZERO_MEMORY,
4226 argc * sizeof(LPWSTR));
4227 if (lpVector == NULL)
4228 return ERROR_NOT_ENOUGH_MEMORY;
4229
4230 for (i = 0; i < argc; i++)
4231 {
4232 dwLength = MultiByteToWideChar(CP_ACP,
4233 0,
4234 ((LPSTR*)argv)[i],
4235 -1,
4236 NULL,
4237 0);
4238
4239 lpVector[i] = HeapAlloc(GetProcessHeap(),
4240 HEAP_ZERO_MEMORY,
4241 dwLength * sizeof(WCHAR));
4242 if (lpVector[i] == NULL)
4243 {
4244 dwError = ERROR_NOT_ENOUGH_MEMORY;
4245 goto done;
4246 }
4247
4248 MultiByteToWideChar(CP_ACP,
4249 0,
4250 ((LPSTR*)argv)[i],
4251 -1,
4252 lpVector[i],
4253 dwLength);
4254 }
4255 }
4256
4257 /* Start the service */
4258 dwError = ScmStartService(lpService, argc, lpVector);
4259
4260 done:
4261 /* Free the Unicode argument vector */
4262 if (lpVector != NULL)
4263 {
4264 for (i = 0; i < argc; i++)
4265 {
4266 if (lpVector[i] != NULL)
4267 HeapFree(GetProcessHeap(), 0, lpVector[i]);
4268 }
4269 HeapFree(GetProcessHeap(), 0, lpVector);
4270 }
4271
4272 return dwError;
4273 }
4274
4275
4276 /* Function 32 */
4277 DWORD RGetServiceDisplayNameA(
4278 SC_RPC_HANDLE hSCManager,
4279 LPCSTR lpServiceName,
4280 LPSTR lpDisplayName,
4281 LPBOUNDED_DWORD_4K lpcchBuffer)
4282 {
4283 // PMANAGER_HANDLE hManager;
4284 PSERVICE lpService = NULL;
4285 DWORD dwLength;
4286 DWORD dwError;
4287 LPWSTR lpServiceNameW;
4288
4289 DPRINT("RGetServiceDisplayNameA() called\n");
4290 DPRINT("hSCManager = %p\n", hSCManager);
4291 DPRINT("lpServiceName: %s\n", lpServiceName);
4292 DPRINT("lpDisplayName: %p\n", lpDisplayName);
4293 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4294
4295 // hManager = (PMANAGER_HANDLE)hSCManager;
4296 // if (hManager->Handle.Tag != MANAGER_TAG)
4297 // {
4298 // DPRINT("Invalid manager handle!\n");
4299 // return ERROR_INVALID_HANDLE;
4300 // }
4301
4302 if (lpServiceName != NULL)
4303 {
4304 dwLength = (DWORD)(strlen(lpServiceName) + 1);
4305 lpServiceNameW = HeapAlloc(GetProcessHeap(),
4306 HEAP_ZERO_MEMORY,
4307 dwLength * sizeof(WCHAR));
4308 if (!lpServiceNameW)
4309 return ERROR_NOT_ENOUGH_MEMORY;
4310
4311 MultiByteToWideChar(CP_ACP,
4312 0,
4313 lpServiceName,
4314 -1,
4315 lpServiceNameW,
4316 dwLength);
4317
4318 lpService = ScmGetServiceEntryByName(lpServiceNameW);
4319
4320 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4321 }
4322
4323 if (lpService == NULL)
4324 {
4325 DPRINT("Could not find a service!\n");
4326
4327 /* If the service could not be found and lpcchBuffer is 0, windows
4328 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4329 if (*lpcchBuffer == 0)
4330 {
4331 *lpcchBuffer = 1;
4332 if (lpDisplayName != NULL)
4333 {
4334 *lpDisplayName = 0;
4335 }
4336 }
4337 return ERROR_SERVICE_DOES_NOT_EXIST;
4338 }
4339
4340 if (!lpService->lpDisplayName)
4341 {
4342 dwLength = (DWORD)wcslen(lpService->lpServiceName);
4343 if (lpDisplayName != NULL &&
4344 *lpcchBuffer > dwLength)
4345 {
4346 WideCharToMultiByte(CP_ACP,
4347 0,
4348 lpService->lpServiceName,
4349 (int)wcslen(lpService->lpServiceName),
4350 lpDisplayName,
4351 dwLength + 1,
4352 NULL,
4353 NULL);
4354 return ERROR_SUCCESS;
4355 }
4356 }
4357 else
4358 {
4359 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
4360 if (lpDisplayName != NULL &&
4361 *lpcchBuffer > dwLength)
4362 {
4363 WideCharToMultiByte(CP_ACP,
4364 0,
4365 lpService->lpDisplayName,
4366 (int)wcslen(lpService->lpDisplayName),
4367 lpDisplayName,
4368 dwLength + 1,
4369 NULL,
4370 NULL);
4371 return ERROR_SUCCESS;
4372 }
4373 }
4374
4375 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4376
4377 *lpcchBuffer = dwLength * 2;
4378
4379 return dwError;
4380 }
4381
4382
4383 /* Function 33 */
4384 DWORD RGetServiceKeyNameA(
4385 SC_RPC_HANDLE hSCManager,
4386 LPCSTR lpDisplayName,
4387 LPSTR lpServiceName,
4388 LPBOUNDED_DWORD_4K lpcchBuffer)
4389 {
4390 PSERVICE lpService;
4391 DWORD dwLength;
4392 DWORD dwError;
4393 LPWSTR lpDisplayNameW;
4394
4395 DPRINT("RGetServiceKeyNameA() called\n");
4396 DPRINT("hSCManager = %p\n", hSCManager);
4397 DPRINT("lpDisplayName: %s\n", lpDisplayName);
4398 DPRINT("lpServiceName: %p\n", lpServiceName);
4399 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4400
4401 dwLength = (DWORD)(strlen(lpDisplayName) + 1);
4402 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4403 HEAP_ZERO_MEMORY,
4404 dwLength * sizeof(WCHAR));
4405 if (!lpDisplayNameW)
4406 return ERROR_NOT_ENOUGH_MEMORY;
4407
4408 MultiByteToWideChar(CP_ACP,
4409 0,
4410 lpDisplayName,
4411 -1,
4412 lpDisplayNameW,
4413 dwLength);
4414
4415 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4416
4417 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4418
4419 if (lpService == NULL)
4420 {
4421 DPRINT("Could not find the service!\n");
4422
4423 /* If the service could not be found and lpcchBuffer is 0,
4424 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4425 if (*lpcchBuffer == 0)
4426 {
4427 *lpcchBuffer = 1;
4428 if (lpServiceName != NULL)
4429 {
4430 *lpServiceName = 0;
4431 }
4432 }
4433
4434 return ERROR_SERVICE_DOES_NOT_EXIST;
4435 }
4436
4437 dwLength = (DWORD)wcslen(lpService->lpServiceName);
4438 if (lpServiceName != NULL &&
4439 *lpcchBuffer > dwLength)
4440 {
4441 WideCharToMultiByte(CP_ACP,
4442 0,
4443 lpService->lpServiceName,
4444 (int)wcslen(lpService->lpServiceName),
4445 lpServiceName,
4446 dwLength + 1,
4447 NULL,
4448 NULL);
4449 return ERROR_SUCCESS;
4450 }
4451
4452 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4453
4454 *lpcchBuffer = dwLength * 2;
4455
4456 return dwError;
4457 }
4458
4459
4460 /* Function 34 */
4461 DWORD RI_ScGetCurrentGroupStateW(
4462 SC_RPC_HANDLE hSCManager,
4463 LPWSTR lpLoadOrderGroup,
4464 LPDWORD lpState)
4465 {
4466 UNIMPLEMENTED;
4467 return ERROR_CALL_NOT_IMPLEMENTED;
4468 }
4469
4470
4471 /* Function 35 */
4472 DWORD REnumServiceGroupW(
4473 SC_RPC_HANDLE hSCManager,
4474 DWORD dwServiceType,
4475 DWORD dwServiceState,
4476 LPBYTE lpBuffer,
4477 DWORD cbBufSize,
4478 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4479 LPBOUNDED_DWORD_256K lpServicesReturned,
4480 LPBOUNDED_DWORD_256K lpResumeIndex,
4481 LPCWSTR pszGroupName)
4482 {
4483 PMANAGER_HANDLE hManager;
4484 PSERVICE lpService;
4485 DWORD dwError = ERROR_SUCCESS;
4486 PLIST_ENTRY ServiceEntry;
4487 PSERVICE CurrentService;
4488 DWORD dwState;
4489 DWORD dwRequiredSize;
4490 DWORD dwServiceCount;
4491 DWORD dwSize;
4492 DWORD dwLastResumeCount = 0;
4493 LPENUM_SERVICE_STATUSW lpStatusPtr;
4494 LPWSTR lpStringPtr;
4495
4496 DPRINT("REnumServiceGroupW() called\n");
4497
4498 if (ScmShutdown)
4499 return ERROR_SHUTDOWN_IN_PROGRESS;
4500
4501 hManager = ScmGetServiceManagerFromHandle(hSCManager);
4502 if (hManager == NULL)
4503 {
4504 DPRINT1("Invalid service manager handle!\n");
4505 return ERROR_INVALID_HANDLE;
4506 }
4507
4508 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
4509 {
4510 return ERROR_INVALID_ADDRESS;
4511 }
4512
4513 *pcbBytesNeeded = 0;
4514 *lpServicesReturned = 0;
4515
4516 if ((dwServiceType == 0) ||
4517 ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
4518 {
4519 DPRINT("Not a valid Service Type!\n");
4520 return ERROR_INVALID_PARAMETER;
4521 }
4522
4523 if ((dwServiceState == 0) ||
4524 ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
4525 {
4526 DPRINT("Not a valid Service State!\n");
4527 return ERROR_INVALID_PARAMETER;
4528 }
4529
4530 /* Check access rights */
4531 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4532 SC_MANAGER_ENUMERATE_SERVICE))
4533 {
4534 DPRINT("Insufficient access rights! 0x%lx\n",
4535 hManager->Handle.DesiredAccess);
4536 return ERROR_ACCESS_DENIED;
4537 }
4538
4539 if (lpResumeIndex)
4540 dwLastResumeCount = *lpResumeIndex;
4541
4542 /* Lock the service database shared */
4543 ScmLockDatabaseShared();
4544
4545 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4546 if (lpService == NULL)
4547 {
4548 dwError = ERROR_SUCCESS;
4549 goto Done;
4550 }
4551
4552 dwRequiredSize = 0;
4553 dwServiceCount = 0;
4554
4555 for (ServiceEntry = &lpService->ServiceListEntry;
4556 ServiceEntry != &ServiceListHead;
4557 ServiceEntry = ServiceEntry->Flink)
4558 {
4559 CurrentService = CONTAINING_RECORD(ServiceEntry,
4560 SERVICE,
4561 ServiceListEntry);
4562
4563 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4564 continue;
4565
4566 dwState = SERVICE_ACTIVE;
4567 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4568 dwState = SERVICE_INACTIVE;
4569
4570 if ((dwState & dwServiceState) == 0)
4571 continue;
4572
4573 if (pszGroupName)
4574 {
4575 if (*pszGroupName == 0)
4576 {
4577 if (CurrentService->lpGroup != NULL)
4578 continue;
4579 }
4580 else
4581 {
4582 if ((CurrentService->lpGroup == NULL) ||
4583 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4584 continue;
4585 }
4586 }
4587
4588 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4589 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4590 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4591
4592 if (dwRequiredSize + dwSize > cbBufSize)
4593 {
4594 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4595 break;
4596 }
4597
4598 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4599 dwRequiredSize += dwSize;
4600 dwServiceCount++;
4601 dwLastResumeCount = CurrentService->dwResumeCount;
4602 }
4603
4604 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4605 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4606
4607 for (;
4608 ServiceEntry != &ServiceListHead;
4609 ServiceEntry = ServiceEntry->Flink)
4610 {
4611 CurrentService = CONTAINING_RECORD(ServiceEntry,
4612 SERVICE,
4613 ServiceListEntry);
4614
4615 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4616 continue;
4617
4618 dwState = SERVICE_ACTIVE;
4619 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4620 dwState = SERVICE_INACTIVE;
4621
4622 if ((dwState & dwServiceState) == 0)
4623 continue;
4624
4625 if (pszGroupName)
4626 {
4627 if (*pszGroupName == 0)
4628 {
4629 if (CurrentService->lpGroup != NULL)
4630 continue;
4631 }
4632 else
4633 {
4634 if ((CurrentService->lpGroup == NULL) ||
4635 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4636 continue;
4637 }
4638 }
4639
4640 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
4641 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4642 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
4643
4644 dwError = ERROR_MORE_DATA;
4645 }
4646
4647 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4648
4649 if (lpResumeIndex)
4650 *lpResumeIndex = dwLastResumeCount;
4651
4652 *lpServicesReturned = dwServiceCount;
4653 *pcbBytesNeeded = dwRequiredSize;
4654
4655 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
4656 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
4657 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
4658
4659 dwRequiredSize = 0;
4660 for (ServiceEntry = &lpService->ServiceListEntry;
4661 ServiceEntry != &ServiceListHead;
4662 ServiceEntry = ServiceEntry->Flink)
4663 {
4664 CurrentService = CONTAINING_RECORD(ServiceEntry,
4665 SERVICE,
4666 ServiceListEntry);
4667
4668 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4669 continue;
4670
4671 dwState = SERVICE_ACTIVE;
4672 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4673 dwState = SERVICE_INACTIVE;
4674
4675 if ((dwState & dwServiceState) == 0)
4676 continue;
4677
4678 if (pszGroupName)
4679 {
4680 if (*pszGroupName == 0)
4681 {
4682 if (CurrentService->lpGroup != NULL)
4683 continue;
4684 }
4685 else
4686 {
4687 if ((CurrentService->lpGroup == NULL) ||
4688 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
4689 continue;
4690 }
4691 }
4692
4693 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
4694 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4695 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4696
4697 if (dwRequiredSize + dwSize > cbBufSize)
4698 break;
4699
4700 /* Copy the service name */
4701 wcscpy(lpStringPtr, CurrentService->lpServiceName);
4702 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4703 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
4704
4705 /* Copy the display name */
4706 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
4707 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4708 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
4709
4710 /* Copy the status information */
4711 memcpy(&lpStatusPtr->ServiceStatus,
4712 &CurrentService->Status,
4713 sizeof(SERVICE_STATUS));
4714
4715 lpStatusPtr++;
4716 dwRequiredSize += dwSize;
4717 }
4718
4719 if (dwError == ERROR_SUCCESS)
4720 {
4721 *pcbBytesNeeded = 0;
4722 if (lpResumeIndex) *lpResumeIndex = 0;
4723 }
4724
4725 Done:
4726 /* Unlock the service database */
4727 ScmUnlockDatabase();
4728
4729 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError);
4730
4731 return dwError;
4732 }
4733
4734
4735 /* Function 36 */
4736 DWORD RChangeServiceConfig2A(
4737 SC_RPC_HANDLE hService,
4738 SC_RPC_CONFIG_INFOA Info)
4739 {
4740 SC_RPC_CONFIG_INFOW InfoW;
4741 DWORD dwRet, dwLength;
4742 PVOID ptr = NULL;
4743
4744 DPRINT("RChangeServiceConfig2A() called\n");
4745 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4746
4747 InfoW.dwInfoLevel = Info.dwInfoLevel;
4748
4749 if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4750 {
4751 LPSERVICE_DESCRIPTIONW lpServiceDescriptionW;
4752 //LPSERVICE_DESCRIPTIONA lpServiceDescriptionA;
4753
4754 //lpServiceDescriptionA = Info.psd;
4755
4756 ///if (lpServiceDescriptionA &&
4757 ///lpServiceDescriptionA->lpDescription)
4758 ///{
4759 dwLength = (DWORD)((strlen(Info.lpDescription) + 1) * sizeof(WCHAR));
4760
4761 lpServiceDescriptionW = HeapAlloc(GetProcessHeap(),
4762 HEAP_ZERO_MEMORY,
4763 dwLength + sizeof(SERVICE_DESCRIPTIONW));
4764 if (!lpServiceDescriptionW)
4765 {
4766 return ERROR_NOT_ENOUGH_MEMORY;
4767 }
4768
4769 lpServiceDescriptionW->lpDescription = (LPWSTR)(lpServiceDescriptionW + 1);
4770
4771 MultiByteToWideChar(CP_ACP,
4772 0,
4773 Info.lpDescription,
4774 -1,
4775 lpServiceDescriptionW->lpDescription,
4776 dwLength);
4777
4778 ptr = lpServiceDescriptionW;
4779 InfoW.psd = lpServiceDescriptionW;
4780 ///}
4781 }
4782 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4783 {
4784 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
4785 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
4786 DWORD dwRebootLen = 0;
4787 DWORD dwCommandLen = 0;
4788 DWORD dwActionArrayLen = 0;
4789 LPWSTR lpStr = NULL;
4790
4791 lpServiceFailureActionsA = Info.psfa;
4792
4793 if (lpServiceFailureActionsA)
4794 {
4795 /*
4796 * The following code is inspired by the
4797 * SERVICE_CONFIG_FAILURE_ACTIONS case of
4798 * the RQueryServiceConfig2W function.
4799 */
4800
4801 /* Retrieve the needed length for the two data strings */
4802 if (lpServiceFailureActionsA->lpRebootMsg)
4803 {
4804 dwRebootLen = (DWORD)((strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR));
4805 }
4806 if (lpServiceFailureActionsA->lpCommand)
4807 {
4808 dwCommandLen = (DWORD)((strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR));
4809 }
4810
4811 /*
4812 * Retrieve the size of the lpsaActions array if needed.
4813 * We will copy the lpsaActions array only if there is at
4814 * least one action AND that the original array is valid.
4815 */
4816 if (lpServiceFailureActionsA->cActions > 0 && lpServiceFailureActionsA->lpsaActions)
4817 {
4818 dwActionArrayLen = lpServiceFailureActionsA->cActions * sizeof(SC_ACTION);
4819 }
4820
4821 /* Compute the total length for the UNICODE structure, including data */
4822 dwLength = sizeof(SERVICE_FAILURE_ACTIONSW) +
4823 dwActionArrayLen + dwRebootLen + dwCommandLen;
4824
4825 /* Allocate the structure */
4826 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
4827 HEAP_ZERO_MEMORY,
4828 dwLength);
4829 if (!lpServiceFailureActionsW)
4830 {
4831 return ERROR_NOT_ENOUGH_MEMORY;
4832 }
4833
4834 /* Copy the members */
4835 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
4836 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
4837
4838 /* Copy the lpsaActions array if needed */
4839 if (dwActionArrayLen > 0)
4840 {
4841 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
4842 lpServiceFailureActionsW->lpsaActions = (LPSC_ACTION)((ULONG_PTR)(lpServiceFailureActionsW + 1));
4843
4844 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
4845 RtlCopyMemory(lpServiceFailureActionsW->lpsaActions,
4846 lpServiceFailureActionsA->lpsaActions,
4847 dwActionArrayLen);
4848 }
4849 else
4850 {
4851 /* No lpsaActions array */
4852 lpServiceFailureActionsW->lpsaActions = NULL;
4853 }
4854 /* The data strings are stored just after the lpsaActions array */
4855 lpStr = (LPWSTR)((ULONG_PTR)(lpServiceFailureActionsW + 1) + dwActionArrayLen);
4856
4857 /*
4858 * Convert the data strings to UNICODE
4859 */
4860
4861 lpServiceFailureActionsW->lpRebootMsg = NULL;
4862 lpServiceFailureActionsW->lpCommand = NULL;
4863
4864 if (dwRebootLen)
4865 {
4866 /* lpRebootMsg points just after the lpsaActions array */
4867 lpServiceFailureActionsW->lpRebootMsg = lpStr;
4868
4869 MultiByteToWideChar(CP_ACP,
4870 0,
4871 lpServiceFailureActionsA->lpRebootMsg,
4872 -1,
4873 lpServiceFailureActionsW->lpRebootMsg,
4874 dwRebootLen);
4875
4876 lpStr += dwRebootLen / sizeof(WCHAR);
4877 }
4878
4879 if (dwCommandLen)
4880 {
4881 /* lpRebootMsg points just after the lpRebootMsg data string */
4882 lpServiceFailureActionsW->lpCommand = lpStr;
4883
4884 MultiByteToWideChar(CP_ACP,
4885 0,
4886 lpServiceFailureActionsA->lpCommand,
4887 -1,
4888 lpServiceFailureActionsW->lpCommand,
4889 dwCommandLen);
4890 }
4891
4892 /* Set the pointers */
4893 ptr = lpServiceFailureActionsW;
4894 InfoW.psfa = lpServiceFailureActionsW;
4895 }
4896 }
4897
4898 dwRet = RChangeServiceConfig2W(hService, InfoW);
4899
4900 HeapFree(GetProcessHeap(), 0, ptr);
4901
4902 return dwRet;
4903 }
4904
4905
4906 static DWORD
4907 ScmSetFailureActions(PSERVICE_HANDLE hSvc,
4908 PSERVICE lpService,
4909 HKEY hServiceKey,
4910 LPSERVICE_FAILURE_ACTIONSW lpFailureActions)
4911 {
4912 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer = NULL;
4913 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer = NULL;
4914 BOOL bIsActionRebootSet = FALSE;
4915 DWORD dwDesiredAccess = SERVICE_CHANGE_CONFIG;
4916 DWORD dwRequiredSize = 0;
4917 DWORD dwType = 0;
4918 DWORD i = 0;
4919 DWORD dwError;
4920
4921 /* There is nothing to be done if we have no failure actions */
4922 if (lpFailureActions == NULL)
4923 return ERROR_SUCCESS;
4924
4925 /*
4926 * 1- Check whether or not we can set
4927 * failure actions for this service.
4928 */
4929
4930 /* Failure actions can only be set for Win32 services, not for drivers */
4931 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
4932 return ERROR_CANNOT_DETECT_DRIVER_FAILURE;
4933
4934 /*
4935 * If the service controller handles the SC_ACTION_RESTART action,
4936 * hService must have the SERVICE_START access right.
4937 *
4938 * If you specify SC_ACTION_REBOOT, the caller must have the
4939 * SE_SHUTDOWN_NAME privilege.
4940 */
4941 if (lpFailureActions->cActions > 0 &&
4942 lpFailureActions->lpsaActions != NULL)
4943 {
4944 for (i = 0; i < lpFailureActions->cActions; ++i)
4945 {
4946 if (lpFailureActions->lpsaActions[i].Type == SC_ACTION_RESTART)
4947 dwDesiredAccess |= SERVICE_START;
4948 else if (lpFailureActions->lpsaActions[i].Type == SC_ACTION_REBOOT)
4949 bIsActionRebootSet = TRUE;
4950 }
4951 }
4952
4953 /* Re-check the access rights */
4954 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4955 dwDesiredAccess))
4956 {
4957 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4958 return ERROR_ACCESS_DENIED;
4959 }
4960
4961 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
4962 if (bIsActionRebootSet)
4963 {
4964 }
4965
4966 /*
4967 * 2- Retrieve the original value of FailureActions.
4968 */
4969
4970 /* Query value length */
4971 dwError = RegQueryValueExW(hServiceKey,
4972 L"FailureActions",
4973 NULL,
4974 &dwType,
4975 NULL,
4976 &dwRequiredSize);
4977 if (dwError != ERROR_SUCCESS &&
4978 dwError != ERROR_MORE_DATA &&
4979 dwError != ERROR_FILE_NOT_FOUND)
4980 return dwError;
4981
4982 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
4983 : sizeof(SERVICE_FAILURE_ACTIONSW);
4984
4985 /* Initialize the read buffer */
4986 lpReadBuffer = HeapAlloc(GetProcessHeap(),
4987 HEAP_ZERO_MEMORY,
4988 dwRequiredSize);
4989 if (lpReadBuffer == NULL)
4990 return ERROR_NOT_ENOUGH_MEMORY;
4991
4992 /* Now we can fill the read buffer */
4993 if (dwError != ERROR_FILE_NOT_FOUND &&
4994 dwType == REG_BINARY)
4995 {
4996 dwError = RegQueryValueExW(hServiceKey,
4997 L"FailureActions",
4998 NULL,
4999 NULL,
5000 (LPBYTE)lpReadBuffer,
5001 &dwRequiredSize);
5002 if (dwError != ERROR_SUCCESS &&
5003 dwError != ERROR_FILE_NOT_FOUND)
5004 goto done;
5005
5006 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
5007 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5008 }
5009 else
5010 {
5011 /*
5012 * The value of the error doesn't really matter, the only
5013 * important thing is that it must be != ERROR_SUCCESS.
5014 */
5015 dwError = ERROR_INVALID_DATA;
5016 }
5017
5018 if (dwError == ERROR_SUCCESS)
5019 {
5020 lpReadBuffer->cActions = min(lpReadBuffer->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
5021 lpReadBuffer->lpsaActions = (lpReadBuffer->cActions > 0 ? (LPSC_ACTION)(lpReadBuffer + 1) : NULL);
5022 }
5023 else
5024 {
5025 lpReadBuffer->dwResetPeriod = 0;
5026 lpReadBuffer->cActions = 0;
5027 lpReadBuffer->lpsaActions = NULL;
5028 }
5029
5030 lpReadBuffer->lpRebootMsg = NULL;
5031 lpReadBuffer->lpCommand = NULL;
5032
5033 /*
5034 * 3- Initialize the new value to set.
5035 */
5036
5037 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5038
5039 if (lpFailureActions->lpsaActions == NULL)
5040 {
5041 /*
5042 * lpFailureActions->cActions is ignored.
5043 * Therefore we use the original values
5044 * of cActions and lpsaActions.
5045 */
5046 dwRequiredSize += lpReadBuffer->cActions * sizeof(SC_ACTION);
5047 }
5048 else
5049 {
5050 /*
5051 * The reset period and array of failure actions
5052 * are deleted if lpFailureActions->cActions == 0 .
5053 */
5054 dwRequiredSize += lpFailureActions->cActions * sizeof(SC_ACTION);
5055 }
5056
5057 lpWriteBuffer = HeapAlloc(GetProcessHeap(),
5058 HEAP_ZERO_MEMORY,
5059 dwRequiredSize);
5060 if (lpWriteBuffer == NULL)
5061 {
5062 dwError = ERROR_NOT_ENOUGH_MEMORY;
5063 goto done;
5064 }
5065
5066 /* Clean the pointers as they have no meaning when the structure is stored in the registry */
5067 lpWriteBuffer->lpRebootMsg = NULL;
5068 lpWriteBuffer->lpCommand = NULL;
5069 lpWriteBuffer->lpsaActions = NULL;
5070
5071 /* Set the members */
5072 if (lpFailureActions->lpsaActions == NULL)
5073 {
5074 /*
5075 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
5076 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
5077 */
5078 lpWriteBuffer->dwResetPeriod = lpReadBuffer->dwResetPeriod;
5079 lpWriteBuffer->cActions = lpReadBuffer->cActions;
5080
5081 if (lpReadBuffer->lpsaActions != NULL)
5082 {
5083 memmove(lpWriteBuffer + 1,
5084 lpReadBuffer->lpsaActions,
5085 lpReadBuffer->cActions * sizeof(SC_ACTION));
5086 }
5087 }
5088 else
5089 {
5090 if (lpFailureActions->cActions > 0)
5091 {
5092 lpWriteBuffer->dwResetPeriod = lpFailureActions->dwResetPeriod;
5093 lpWriteBuffer->cActions = lpFailureActions->cActions;
5094
5095 memmove(lpWriteBuffer + 1,
5096 lpFailureActions->lpsaActions,
5097 lpFailureActions->cActions * sizeof(SC_ACTION));
5098 }
5099 else
5100 {
5101 /* The reset period and array of failure actions are deleted */
5102 lpWriteBuffer->dwResetPeriod = 0;
5103 lpWriteBuffer->cActions = 0;
5104 }
5105 }
5106
5107 /* Save the new failure actions into the registry */
5108 dwError = RegSetValueExW(hServiceKey,
5109 L"FailureActions",
5110 0,
5111 REG_BINARY,
5112 (LPBYTE)lpWriteBuffer,
5113 dwRequiredSize);
5114
5115 /* We modify the strings only in case of success.*/
5116 if (dwError == ERROR_SUCCESS)
5117 {
5118 /* Modify the Reboot Message value, if specified */
5119 if (lpFailureActions->lpRebootMsg != NULL)
5120 {
5121 /* If the Reboot Message is "" then we delete it */
5122 if (*lpFailureActions->lpRebootMsg == 0)
5123 {
5124 DPRINT("Delete Reboot Message value\n");
5125 RegDeleteValueW(hServiceKey, L"RebootMessage");
5126 }
5127 else
5128 {
5129 DPRINT("Setting Reboot Message value %S\n", lpFailureActions->lpRebootMsg);
5130 RegSetValueExW(hServiceKey,
5131 L"RebootMessage",
5132 0,
5133 REG_SZ,
5134 (LPBYTE)lpFailureActions->lpRebootMsg,
5135 (DWORD)((wcslen(lpFailureActions->lpRebootMsg) + 1) * sizeof(WCHAR)));
5136 }
5137 }
5138
5139 /* Modify the Failure Command value, if specified */
5140 if (lpFailureActions->lpCommand != NULL)
5141 {
5142 /* If the FailureCommand string is an empty string, delete the value */
5143 if (*lpFailureActions->lpCommand == 0)
5144 {
5145 DPRINT("Delete Failure Command value\n");
5146 RegDeleteValueW(hServiceKey, L"FailureCommand");
5147 }
5148 else
5149 {
5150 DPRINT("Setting Failure Command value %S\n", lpFailureActions->lpCommand);
5151 RegSetValueExW(hServiceKey,
5152 L"FailureCommand",
5153 0,
5154 REG_SZ,
5155 (LPBYTE)lpFailureActions->lpCommand,
5156 (DWORD)((wcslen(lpFailureActions->lpCommand) + 1) * sizeof(WCHAR)));
5157 }
5158 }
5159 }
5160
5161 done:
5162 if (lpWriteBuffer != NULL)
5163 HeapFree(GetProcessHeap(), 0, lpWriteBuffer);
5164
5165 if (lpReadBuffer != NULL)
5166 HeapFree(GetProcessHeap(), 0, lpReadBuffer);
5167
5168 return dwError;
5169 }
5170
5171
5172 /* Function 37 */
5173 DWORD RChangeServiceConfig2W(
5174 SC_RPC_HANDLE hService,
5175 SC_RPC_CONFIG_INFOW Info)
5176 {
5177 DWORD dwError = ERROR_SUCCESS;
5178 PSERVICE_HANDLE hSvc;
5179 PSERVICE lpService = NULL;
5180 HKEY hServiceKey = NULL;
5181
5182 DPRINT("RChangeServiceConfig2W() called\n");
5183 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
5184
5185 if (ScmShutdown)
5186 return ERROR_SHUTDOWN_IN_PROGRESS;
5187
5188 hSvc = ScmGetServiceFromHandle(hService);
5189 if (hSvc == NULL)
5190 {
5191 DPRINT1("Invalid service handle!\n");
5192 return ERROR_INVALID_HANDLE;
5193 }
5194
5195 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5196 SERVICE_CHANGE_CONFIG))
5197 {
5198 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5199 return ERROR_ACCESS_DENIED;
5200 }
5201
5202 lpService = hSvc->ServiceEntry;
5203 if (lpService == NULL)
5204 {
5205 DPRINT("lpService == NULL!\n");
5206 return ERROR_INVALID_HANDLE;
5207 }
5208
5209 /* Lock the service database exclusively */
5210 ScmLockDatabaseExclusive();
5211
5212 if (lpService->bDeleted)
5213 {
5214 DPRINT("The service has already been marked for delete!\n");
5215 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
5216 goto done;
5217 }
5218
5219 /* Open the service key */
5220 dwError = ScmOpenServiceKey(lpService->szServiceName,
5221 KEY_READ | KEY_SET_VALUE,
5222 &hServiceKey);
5223 if (dwError != ERROR_SUCCESS)
5224 goto done;
5225
5226 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5227 {
5228 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
5229
5230 /* Modify the service description, if specified */
5231 if (lpServiceDescription != NULL &&
5232 lpServiceDescription->lpDescription != NULL)
5233 {
5234 /* If the description is "" then we delete it */
5235 if (*lpServiceDescription->lpDescription == 0)
5236 {
5237 DPRINT("Delete service description\n");
5238 dwError = RegDeleteValueW(hServiceKey, L"Description");
5239
5240 if (dwError == ERROR_FILE_NOT_FOUND)
5241 dwError = ERROR_SUCCESS;
5242 }
5243 else
5244 {
5245 DPRINT("Setting service description value %S\n", lpServiceDescription->lpDescription);
5246 dwError = RegSetValueExW(hServiceKey,
5247 L"Description",
5248 0,
5249 REG_SZ,
5250 (LPBYTE)lpServiceDescription->lpDescription,
5251 (DWORD)((wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR)));
5252 }
5253 }
5254 else
5255 {
5256 dwError = ERROR_SUCCESS;
5257 }
5258 }
5259 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5260 {
5261 dwError = ScmSetFailureActions(hSvc,
5262 lpService,
5263 hServiceKey,
5264 (LPSERVICE_FAILURE_ACTIONSW)Info.psfa);
5265 }
5266
5267 done:
5268 if (hServiceKey != NULL)
5269 RegCloseKey(hServiceKey);
5270
5271 /* Unlock the service database */
5272 ScmUnlockDatabase();
5273
5274 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
5275
5276 return dwError;
5277 }
5278
5279
5280 /* Function 38 */
5281 DWORD RQueryServiceConfig2A(
5282 SC_RPC_HANDLE hService,
5283 DWORD dwInfoLevel,
5284 LPBYTE lpBuffer,
5285 DWORD cbBufSize,
5286 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5287 {
5288 DWORD dwError = ERROR_SUCCESS;
5289 PSERVICE_HANDLE hSvc;
5290 PSERVICE lpService = NULL;
5291 HKEY hServiceKey = NULL;
5292 DWORD dwRequiredSize = 0;
5293 DWORD dwType = 0;
5294 LPWSTR lpDescriptionW = NULL;
5295 LPWSTR lpRebootMessageW = NULL;
5296 LPWSTR lpFailureCommandW = NULL;
5297
5298 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
5299 hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
5300
5301 if (!lpBuffer)
5302 return ERROR_INVALID_ADDRESS;
5303
5304 if (ScmShutdown)
5305 return ERROR_SHUTDOWN_IN_PROGRESS;
5306
5307 hSvc = ScmGetServiceFromHandle(hService);
5308 if (hSvc == NULL)
5309 {
5310 DPRINT1("Invalid service handle!\n");
5311 return ERROR_INVALID_HANDLE;
5312 }
5313
5314 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5315 SERVICE_QUERY_CONFIG))
5316 {
5317 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5318 return ERROR_ACCESS_DENIED;
5319 }
5320
5321 lpService = hSvc->ServiceEntry;
5322 if (lpService == NULL)
5323 {
5324 DPRINT("lpService == NULL!\n");
5325 return ERROR_INVALID_HANDLE;
5326 }
5327
5328 /* Lock the service database shared */
5329 ScmLockDatabaseShared();
5330
5331 dwError = ScmOpenServiceKey(lpService->lpServiceName,
5332 KEY_READ,
5333 &hServiceKey);
5334 if (dwError != ERROR_SUCCESS)
5335 goto done;
5336
5337 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5338 {
5339 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
5340 LPSTR lpStr;
5341
5342 dwError = ScmReadString(hServiceKey,
5343 L"Description",
5344 &lpDescriptionW);
5345 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5346 goto done;
5347
5348 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
5349 if (dwError == ERROR_SUCCESS)
5350 *pcbBytesNeeded += (DWORD)((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
5351
5352 if (cbBufSize < *pcbBytesNeeded)
5353 {
5354 dwError = ERROR_INSUFFICIENT_BUFFER;
5355 goto done;
5356 }
5357
5358 if (dwError == ERROR_SUCCESS)
5359 {
5360 lpStr = (LPSTR)(lpServiceDescription + 1);
5361
5362 WideCharToMultiByte(CP_ACP,
5363 0,
5364 lpDescriptionW,
5365 -1,
5366 lpStr,
5367 (int)wcslen(lpDescriptionW),
5368 NULL,
5369 NULL);
5370 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
5371 }
5372 else
5373 {
5374 lpServiceDescription->lpDescription = NULL;
5375 dwError = ERROR_SUCCESS;
5376 }
5377 }
5378 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5379 {
5380 LPSERVICE_FAILURE_ACTIONSA lpFailureActions = (LPSERVICE_FAILURE_ACTIONSA)lpBuffer;
5381 LPSTR lpStr = NULL;
5382
5383 /* Query value length */
5384 dwError = RegQueryValueExW(hServiceKey,
5385 L"FailureActions",
5386 NULL,
5387 &dwType,
5388 NULL,
5389 &dwRequiredSize);
5390 if (dwError != ERROR_SUCCESS &&
5391 dwError != ERROR_MORE_DATA &&
5392 dwError != ERROR_FILE_NOT_FOUND)
5393 goto done;
5394
5395 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSA), dwRequiredSize)
5396 : sizeof(SERVICE_FAILURE_ACTIONSA);
5397
5398 /* Get the strings */
5399 ScmReadString(hServiceKey,
5400 L"FailureCommand",
5401 &lpFailureCommandW);
5402
5403 ScmReadString(hServiceKey,
5404 L"RebootMessage",
5405 &lpRebootMessageW);
5406
5407 if (lpRebootMessageW)
5408 dwRequiredSize += (DWORD)((wcslen(lpRebootMessageW) + 1) * sizeof(WCHAR));
5409
5410 if (lpFailureCommandW)
5411 dwRequiredSize += (DWORD)((wcslen(lpFailureCommandW) + 1) * sizeof(WCHAR));
5412
5413 if (cbBufSize < dwRequiredSize)
5414 {
5415 *pcbBytesNeeded = dwRequiredSize;
5416 dwError = ERROR_INSUFFICIENT_BUFFER;
5417 goto done;
5418 }
5419
5420 /* Now we can fill the buffer */
5421 if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY)
5422 {
5423 dwError = RegQueryValueExW(hServiceKey,
5424 L"FailureActions",
5425 NULL,
5426 NULL,
5427 (LPBYTE)lpFailureActions,
5428 &dwRequiredSize);
5429 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5430 goto done;
5431
5432 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSA))
5433 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSA);
5434 }
5435 else
5436 {
5437 /*
5438 * The value of the error doesn't really matter, the only
5439 * important thing is that it must be != ERROR_SUCCESS .
5440 */
5441 dwError = ERROR_INVALID_DATA;
5442 }
5443
5444 if (dwError == ERROR_SUCCESS)
5445 {
5446 lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSA)) / sizeof(SC_ACTION));
5447
5448 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5449 lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSA) : NULL);
5450
5451 lpStr = (LPSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION));
5452 }
5453 else
5454 {
5455 lpFailureActions->dwResetPeriod = 0;
5456 lpFailureActions->cActions = 0;
5457 lpFailureActions->lpsaActions = NULL;
5458 lpStr = (LPSTR)(lpFailureActions + 1);
5459 }
5460
5461 lpFailureActions->lpRebootMsg = NULL;
5462 lpFailureActions->lpCommand = NULL;
5463
5464 if (lpRebootMessageW)
5465 {
5466 WideCharToMultiByte(CP_ACP,
5467 0,
5468 lpRebootMessageW,
5469 -1,
5470 lpStr,
5471 (int)wcslen(lpRebootMessageW),
5472 NULL,
5473 NULL);
5474 lpFailureActions->lpRebootMsg = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5475 lpStr += strlen(lpStr) + 1;
5476 }
5477
5478 if (lpFailureCommandW)
5479 {
5480 WideCharToMultiByte(CP_ACP,
5481 0,
5482 lpFailureCommandW,
5483 -1,
5484 lpStr,
5485 (int)wcslen(lpFailureCommandW),
5486 NULL,
5487 NULL);
5488 lpFailureActions->lpCommand = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5489 /* lpStr += strlen(lpStr) + 1; */
5490 }
5491
5492 dwError = ERROR_SUCCESS;
5493 }
5494
5495 done:
5496 /* Unlock the service database */
5497 ScmUnlockDatabase();
5498
5499 if (lpDescriptionW != NULL)
5500 HeapFree(GetProcessHeap(), 0, lpDescriptionW);
5501
5502 if (lpRebootMessageW != NULL)
5503 HeapFree(GetProcessHeap(), 0, lpRebootMessageW);
5504
5505 if (lpFailureCommandW != NULL)
5506 HeapFree(GetProcessHeap(), 0, lpFailureCommandW);
5507
5508 if (hServiceKey != NULL)
5509 RegCloseKey(hServiceKey);
5510
5511 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError);
5512
5513 return dwError;
5514 }
5515
5516
5517 /* Function 39 */
5518 DWORD RQueryServiceConfig2W(
5519 SC_RPC_HANDLE hService,
5520 DWORD dwInfoLevel,
5521 LPBYTE lpBuffer,
5522 DWORD cbBufSize,
5523 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5524 {
5525 DWORD dwError = ERROR_SUCCESS;
5526 PSERVICE_HANDLE hSvc;
5527 PSERVICE lpService = NULL;
5528 HKEY hServiceKey = NULL;
5529 DWORD dwRequiredSize = 0;
5530 DWORD dwType = 0;
5531 LPWSTR lpDescription = NULL;
5532 LPWSTR lpRebootMessage = NULL;
5533 LPWSTR lpFailureCommand = NULL;
5534
5535 DPRINT("RQueryServiceConfig2W() called\n");
5536
5537 if (!lpBuffer)
5538 return ERROR_INVALID_ADDRESS;
5539
5540 if (ScmShutdown)
5541 return ERROR_SHUTDOWN_IN_PROGRESS;
5542
5543 hSvc = ScmGetServiceFromHandle(hService);
5544 if (hSvc == NULL)
5545 {
5546 DPRINT1("Invalid service handle!\n");
5547 return ERROR_INVALID_HANDLE;
5548 }
5549
5550 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5551 SERVICE_QUERY_CONFIG))
5552 {
5553 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5554 return ERROR_ACCESS_DENIED;
5555 }
5556
5557 lpService = hSvc->ServiceEntry;
5558 if (lpService == NULL)
5559 {
5560 DPRINT("lpService == NULL!\n");
5561 return ERROR_INVALID_HANDLE;
5562 }
5563
5564 /* Lock the service database shared */
5565 ScmLockDatabaseShared();
5566
5567 dwError = ScmOpenServiceKey(lpService->lpServiceName,
5568 KEY_READ,
5569 &hServiceKey);
5570 if (dwError != ERROR_SUCCESS)
5571 goto done;
5572
5573 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
5574 {
5575 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
5576 LPWSTR lpStr;
5577
5578 dwError = ScmReadString(hServiceKey,
5579 L"Description",
5580 &lpDescription);
5581 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5582 goto done;
5583
5584 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW);
5585 if (dwError == ERROR_SUCCESS)
5586 *pcbBytesNeeded += (DWORD)((wcslen(lpDescription) + 1) * sizeof(WCHAR));
5587
5588 if (cbBufSize < *pcbBytesNeeded)
5589 {
5590 dwError = ERROR_INSUFFICIENT_BUFFER;
5591 goto done;
5592 }
5593
5594 if (dwError == ERROR_SUCCESS)
5595 {
5596 lpStr = (LPWSTR)(lpServiceDescription + 1);
5597 wcscpy(lpStr, lpDescription);
5598 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
5599 }
5600 else
5601 {
5602 lpServiceDescription->lpDescription = NULL;
5603 dwError = ERROR_SUCCESS;
5604 }
5605 }
5606 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
5607 {
5608 LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
5609 LPWSTR lpStr = NULL;
5610
5611 /* Query value length */
5612 dwError = RegQueryValueExW(hServiceKey,
5613 L"FailureActions",
5614 NULL,
5615 &dwType,
5616 NULL,
5617 &dwRequiredSize);
5618 if (dwError != ERROR_SUCCESS &&
5619 dwError != ERROR_MORE_DATA &&
5620 dwError != ERROR_FILE_NOT_FOUND)
5621 goto done;
5622
5623 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
5624 : sizeof(SERVICE_FAILURE_ACTIONSW);
5625
5626 /* Get the strings */
5627 ScmReadString(hServiceKey,
5628 L"FailureCommand",
5629 &lpFailureCommand);
5630
5631 ScmReadString(hServiceKey,
5632 L"RebootMessage",
5633 &lpRebootMessage);
5634
5635 if (lpRebootMessage)
5636 dwRequiredSize += (DWORD)((wcslen(lpRebootMessage) + 1) * sizeof(WCHAR));
5637
5638 if (lpFailureCommand)
5639 dwRequiredSize += (DWORD)((wcslen(lpFailureCommand) + 1) * sizeof(WCHAR));
5640
5641 if (cbBufSize < dwRequiredSize)
5642 {
5643 *pcbBytesNeeded = dwRequiredSize;
5644 dwError = ERROR_INSUFFICIENT_BUFFER;
5645 goto done;
5646 }
5647
5648 /* Now we can fill the buffer */
5649 if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY)
5650 {
5651 dwError = RegQueryValueExW(hServiceKey,
5652 L"FailureActions",
5653 NULL,
5654 NULL,
5655 (LPBYTE)lpFailureActions,
5656 &dwRequiredSize);
5657 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
5658 goto done;
5659
5660 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
5661 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
5662 }
5663 else
5664 {
5665 /*
5666 * The value of the error doesn't really matter, the only
5667 * important thing is that it must be != ERROR_SUCCESS .
5668 */
5669 dwError = ERROR_INVALID_DATA;
5670 }
5671
5672 if (dwError == ERROR_SUCCESS)
5673 {
5674 lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
5675
5676 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
5677 lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSW) : NULL);
5678
5679 lpStr = (LPWSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION));
5680 }
5681 else
5682 {
5683 lpFailureActions->dwResetPeriod = 0;
5684 lpFailureActions->cActions = 0;
5685 lpFailureActions->lpsaActions = NULL;
5686 lpStr = (LPWSTR)(lpFailureActions + 1);
5687 }
5688
5689 lpFailureActions->lpRebootMsg = NULL;
5690 lpFailureActions->lpCommand = NULL;
5691
5692 if (lpRebootMessage)
5693 {
5694 wcscpy(lpStr, lpRebootMessage);
5695 lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5696 lpStr += wcslen(lpStr) + 1;
5697 }
5698
5699 if (lpFailureCommand)
5700 {
5701 wcscpy(lpStr, lpFailureCommand);
5702 lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
5703 /* lpStr += wcslen(lpStr) + 1; */
5704 }
5705
5706 dwError = ERROR_SUCCESS;
5707 }
5708
5709 done:
5710 /* Unlock the service database */
5711 ScmUnlockDatabase();
5712
5713 if (lpDescription != NULL)
5714 HeapFree(GetProcessHeap(), 0, lpDescription);
5715
5716 if (lpRebootMessage != NULL)
5717 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
5718
5719 if (lpFailureCommand != NULL)
5720 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
5721
5722 if (hServiceKey != NULL)
5723 RegCloseKey(hServiceKey);
5724
5725 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
5726
5727 return dwError;
5728 }
5729
5730
5731 /* Function 40 */
5732 DWORD RQueryServiceStatusEx(
5733 SC_RPC_HANDLE hService,
5734 SC_STATUS_TYPE InfoLevel,
5735 LPBYTE lpBuffer,
5736 DWORD cbBufSize,
5737 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5738 {
5739 LPSERVICE_STATUS_PROCESS lpStatus;
5740 PSERVICE_HANDLE hSvc;
5741 PSERVICE lpService;
5742
5743 DPRINT("RQueryServiceStatusEx() called\n");
5744
5745 if (ScmShutdown)
5746 return ERROR_SHUTDOWN_IN_PROGRESS;
5747
5748 if (InfoLevel != SC_STATUS_PROCESS_INFO)
5749 return ERROR_INVALID_LEVEL;
5750
5751 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
5752
5753 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
5754 return ERROR_INSUFFICIENT_BUFFER;
5755
5756 hSvc = ScmGetServiceFromHandle(hService);
5757 if (hSvc == NULL)
5758 {
5759 DPRINT1("Invalid service handle!\n");
5760 return ERROR_INVALID_HANDLE;
5761 }
5762
5763 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5764 SERVICE_QUERY_STATUS))
5765 {
5766 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5767 return ERROR_ACCESS_DENIED;
5768 }
5769
5770 lpService = hSvc->ServiceEntry;
5771 if (lpService == NULL)
5772 {
5773 DPRINT("lpService == NULL!\n");
5774 return ERROR_INVALID_HANDLE;
5775 }
5776
5777 /* Lock the service database shared */
5778 ScmLockDatabaseShared();
5779
5780 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
5781
5782 /* Return service status information */
5783 RtlCopyMemory(lpStatus,
5784 &lpService->Status,
5785 sizeof(SERVICE_STATUS));
5786
5787 lpStatus->dwProcessId = (lpService->lpImage != NULL) ? lpService->lpImage->dwProcessId : 0; /* FIXME */
5788 lpStatus->dwServiceFlags = 0; /* FIXME */
5789
5790 /* Unlock the service database */
5791 ScmUnlockDatabase();
5792
5793 return ERROR_SUCCESS;
5794 }
5795
5796
5797 /* Function 41 */
5798 DWORD REnumServicesStatusExA(
5799 SC_RPC_HANDLE hSCManager,
5800 SC_ENUM_TYPE InfoLevel,
5801 DWORD dwServiceType,
5802 DWORD dwServiceState,
5803 LPBYTE lpBuffer,
5804 DWORD cbBufSize,
5805 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5806 LPBOUNDED_DWORD_256K lpServicesReturned,
5807 LPBOUNDED_DWORD_256K lpResumeIndex,
5808 LPCSTR pszGroupName)
5809 {
5810 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
5811 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW;
5812 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
5813 LPWSTR lpStringPtrW;
5814 LPSTR lpStringPtrA;
5815 LPWSTR pszGroupNameW = NULL;
5816 DWORD dwError;
5817 DWORD dwServiceCount;
5818
5819 DPRINT("REnumServicesStatusExA() called\n");
5820
5821 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
5822 {
5823 return ERROR_INVALID_ADDRESS;
5824 }
5825
5826 if (pszGroupName)
5827 {
5828 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
5829 if (!pszGroupNameW)
5830 {
5831 DPRINT("Failed to allocate buffer!\n");
5832 return ERROR_NOT_ENOUGH_MEMORY;
5833 }
5834
5835 MultiByteToWideChar(CP_ACP,
5836 0,
5837 pszGroupName,
5838 -1,
5839 pszGroupNameW,
5840 (int)(strlen(pszGroupName) + 1));
5841 }
5842
5843 if ((cbBufSize > 0) && (lpBuffer))
5844 {
5845 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
5846 if (!lpStatusPtrW)
5847 {
5848 DPRINT("Failed to allocate buffer!\n");
5849 return ERROR_NOT_ENOUGH_MEMORY;
5850 }
5851 }
5852
5853 dwError = REnumServicesStatusExW(hSCManager,
5854 InfoLevel,
5855 dwServiceType,
5856 dwServiceState,
5857 (LPBYTE)lpStatusPtrW,
5858 cbBufSize,
5859 pcbBytesNeeded,
5860 lpServicesReturned,
5861 lpResumeIndex,
5862 pszGroupNameW);
5863
5864 /* if no services were returned then we are Done */
5865 if (*lpServicesReturned == 0)
5866 goto Done;
5867
5868 lpStatusPtrIncrW = lpStatusPtrW;
5869 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
5870 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
5871 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
5872 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
5873 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
5874
5875 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
5876 {
5877 /* Copy the service name */
5878 WideCharToMultiByte(CP_ACP,
5879 0,
5880 lpStringPtrW,
5881 -1,
5882 lpStringPtrA,
5883 (int)wcslen(lpStringPtrW),
5884 0,
5885 0);
5886
5887 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5888 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5889 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5890
5891 /* Copy the display name */
5892 WideCharToMultiByte(CP_ACP,
5893 0,
5894 lpStringPtrW,
5895 -1,
5896 lpStringPtrA,
5897 (int)wcslen(lpStringPtrW),
5898 0,
5899 0);
5900
5901 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5902 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5903 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5904
5905 /* Copy the status information */
5906 memcpy(&lpStatusPtrA->ServiceStatusProcess,
5907 &lpStatusPtrIncrW->ServiceStatusProcess,
5908 sizeof(SERVICE_STATUS));
5909
5910 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrIncrW->ServiceStatusProcess.dwProcessId; /* FIXME */
5911 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5912
5913 lpStatusPtrIncrW++;
5914 lpStatusPtrA++;
5915 }
5916
5917 Done:
5918 if (pszGroupNameW)
5919 HeapFree(GetProcessHeap(), 0, pszGroupNameW);
5920
5921 if (lpStatusPtrW)
5922 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
5923
5924 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
5925
5926 return dwError;
5927 }
5928
5929
5930 /* Function 42 */
5931 DWORD REnumServicesStatusExW(
5932 SC_RPC_HANDLE hSCManager,
5933 SC_ENUM_TYPE InfoLevel,
5934 DWORD dwServiceType,
5935 DWORD dwServiceState,
5936 LPBYTE lpBuffer,
5937 DWORD cbBufSize,
5938 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5939 LPBOUNDED_DWORD_256K lpServicesReturned,
5940 LPBOUNDED_DWORD_256K lpResumeIndex,
5941 LPCWSTR pszGroupName)
5942 {
5943 PMANAGER_HANDLE hManager;
5944 PSERVICE lpService;
5945 DWORD dwError = ERROR_SUCCESS;
5946 PLIST_ENTRY ServiceEntry;
5947 PSERVICE CurrentService;
5948 DWORD dwState;
5949 DWORD dwRequiredSize;
5950 DWORD dwServiceCount;
5951 DWORD dwSize;
5952 DWORD dwLastResumeCount = 0;
5953 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
5954 LPWSTR lpStringPtr;
5955
5956 DPRINT("REnumServicesStatusExW() called\n");
5957
5958 if (ScmShutdown)
5959 return ERROR_SHUTDOWN_IN_PROGRESS;
5960
5961 if (InfoLevel != SC_ENUM_PROCESS_INFO)
5962 return ERROR_INVALID_LEVEL;
5963
5964 hManager = ScmGetServiceManagerFromHandle(hSCManager);
5965 if (hManager == NULL)
5966 {
5967 DPRINT1("Invalid service manager handle!\n");
5968 return ERROR_INVALID_HANDLE;
5969 }
5970
5971 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
5972 {
5973 return ERROR_INVALID_ADDRESS;
5974 }
5975
5976 *pcbBytesNeeded = 0;
5977 *lpServicesReturned = 0;
5978
5979 if ((dwServiceType == 0) ||
5980 ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
5981 {
5982 DPRINT("Not a valid Service Type!\n");
5983 return ERROR_INVALID_PARAMETER;
5984 }
5985
5986 if ((dwServiceState == 0) ||
5987 ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
5988 {
5989 DPRINT("Not a valid Service State!\n");
5990 return ERROR_INVALID_PARAMETER;
5991 }
5992
5993 /* Check access rights */
5994 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
5995 SC_MANAGER_ENUMERATE_SERVICE))
5996 {
5997 DPRINT("Insufficient access rights! 0x%lx\n",
5998 hManager->Handle.DesiredAccess);
5999 return ERROR_ACCESS_DENIED;
6000 }
6001
6002 if (lpResumeIndex)
6003 dwLastResumeCount = *lpResumeIndex;
6004
6005 /* Lock the service database shared */
6006 ScmLockDatabaseShared();
6007
6008 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
6009 if (lpService == NULL)
6010 {
6011 dwError = ERROR_SUCCESS;
6012 goto Done;
6013 }
6014
6015 dwRequiredSize = 0;
6016 dwServiceCount = 0;
6017
6018 for (ServiceEntry = &lpService->ServiceListEntry;
6019 ServiceEntry != &ServiceListHead;
6020 ServiceEntry = ServiceEntry->Flink)
6021 {
6022 CurrentService = CONTAINING_RECORD(ServiceEntry,
6023 SERVICE,
6024 ServiceListEntry);
6025
6026 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6027 continue;
6028
6029 dwState = SERVICE_ACTIVE;
6030 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6031 dwState = SERVICE_INACTIVE;
6032
6033 if ((dwState & dwServiceState) == 0)
6034 continue;
6035
6036 if (pszGroupName)
6037 {
6038 if (*pszGroupName == 0)
6039 {
6040 if (CurrentService->lpGroup != NULL)
6041 continue;
6042 }
6043 else
6044 {
6045 if ((CurrentService->lpGroup == NULL) ||
6046 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6047 continue;
6048 }
6049 }
6050
6051 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6052 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6053 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
6054
6055 if (dwRequiredSize + dwSize <= cbBufSize)
6056 {
6057 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
6058 dwRequiredSize += dwSize;
6059 dwServiceCount++;
6060 dwLastResumeCount = CurrentService->dwResumeCount;
6061 }
6062 else
6063 {
6064 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
6065 break;
6066 }
6067
6068 }
6069
6070 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
6071 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
6072
6073 for (;
6074 ServiceEntry != &ServiceListHead;
6075 ServiceEntry = ServiceEntry->Flink)
6076 {
6077 CurrentService = CONTAINING_RECORD(ServiceEntry,
6078 SERVICE,
6079 ServiceListEntry);
6080
6081 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6082 continue;
6083
6084 dwState = SERVICE_ACTIVE;
6085 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6086 dwState = SERVICE_INACTIVE;
6087
6088 if ((dwState & dwServiceState) == 0)
6089 continue;
6090
6091 if (pszGroupName)
6092 {
6093 if (*pszGroupName == 0)
6094 {
6095 if (CurrentService->lpGroup != NULL)
6096 continue;
6097 }
6098 else
6099 {
6100 if ((CurrentService->lpGroup == NULL) ||
6101 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6102 continue;
6103 }
6104 }
6105
6106 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6107 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6108 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
6109
6110 dwError = ERROR_MORE_DATA;
6111 }
6112
6113 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
6114
6115 if (lpResumeIndex)
6116 *lpResumeIndex = dwLastResumeCount;
6117
6118 *lpServicesReturned = dwServiceCount;
6119 *pcbBytesNeeded = dwRequiredSize;
6120
6121 /* If there was no services that matched */
6122 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
6123 {
6124 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
6125 goto Done;
6126 }
6127
6128 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
6129 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
6130 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
6131
6132 dwRequiredSize = 0;
6133 for (ServiceEntry = &lpService->ServiceListEntry;
6134 ServiceEntry != &ServiceListHead;
6135 ServiceEntry = ServiceEntry->Flink)
6136 {
6137 CurrentService = CONTAINING_RECORD(ServiceEntry,
6138 SERVICE,
6139 ServiceListEntry);
6140
6141 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
6142 continue;
6143
6144 dwState = SERVICE_ACTIVE;
6145 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
6146 dwState = SERVICE_INACTIVE;
6147
6148 if ((dwState & dwServiceState) == 0)
6149 continue;
6150
6151 if (pszGroupName)
6152 {
6153 if (*pszGroupName == 0)
6154 {
6155 if (CurrentService->lpGroup != NULL)
6156 continue;
6157 }
6158 else
6159 {
6160 if ((CurrentService->lpGroup == NULL) ||
6161 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
6162 continue;
6163 }
6164 }
6165
6166 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
6167 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
6168 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
6169
6170 if (dwRequiredSize + dwSize <= cbBufSize)
6171 {
6172 /* Copy the service name */
6173 wcscpy(lpStringPtr,
6174 CurrentService->lpServiceName);
6175 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
6176 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
6177
6178 /* Copy the display name */
6179 wcscpy(lpStringPtr,
6180 CurrentService->lpDisplayName);
6181 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
6182 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
6183
6184 /* Copy the status information */
6185 memcpy(&lpStatusPtr->ServiceStatusProcess,
6186 &CurrentService->Status,
6187 sizeof(SERVICE_STATUS));
6188 lpStatusPtr->ServiceStatusProcess.dwProcessId =
6189 (CurrentService->lpImage != NULL) ? CurrentService->lpImage->dwProcessId : 0; /* FIXME */
6190 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
6191
6192 lpStatusPtr++;
6193 dwRequiredSize += dwSize;
6194 }
6195 else
6196 {
6197 break;
6198 }
6199 }
6200
6201 if (dwError == 0)
6202 {
6203 *pcbBytesNeeded = 0;
6204 if (lpResumeIndex)
6205 *lpResumeIndex = 0;
6206 }
6207
6208 Done:
6209 /* Unlock the service database */
6210 ScmUnlockDatabase();
6211
6212 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
6213
6214 return dwError;
6215 }
6216
6217
6218 /* Function 43 */
6219 DWORD RSendTSMessage(
6220 handle_t BindingHandle) /* FIXME */
6221 {
6222 UNIMPLEMENTED;
6223 return ERROR_CALL_NOT_IMPLEMENTED;
6224 }
6225
6226
6227 /* Function 44 */
6228 DWORD RCreateServiceWOW64A(
6229 handle_t BindingHandle,
6230 LPSTR lpServiceName,
6231 LPSTR lpDisplayName,
6232 DWORD dwDesiredAccess,
6233 DWORD dwServiceType,
6234 DWORD dwStartType,
6235 DWORD dwErrorControl,
6236 LPSTR lpBinaryPathName,
6237 LPSTR lpLoadOrderGroup,
6238 LPDWORD lpdwTagId,
6239 LPBYTE lpDependencies,
6240 DWORD dwDependSize,
6241 LPSTR lpServiceStartName,
6242 LPBYTE lpPassword,
6243 DWORD dwPwSize,
6244 LPSC_RPC_HANDLE lpServiceHandle)
6245 {
6246 UNIMPLEMENTED;
6247 return ERROR_CALL_NOT_IMPLEMENTED;
6248 }
6249
6250
6251 /* Function 45 */
6252 DWORD RCreateServiceWOW64W(
6253 handle_t BindingHandle,
6254 LPWSTR lpServiceName,
6255 LPWSTR lpDisplayName,
6256 DWORD dwDesiredAccess,
6257 DWORD dwServiceType,
6258 DWORD dwStartType,
6259 DWORD dwErrorControl,
6260 LPWSTR lpBinaryPathName,
6261 LPWSTR lpLoadOrderGroup,
6262 LPDWORD lpdwTagId,
6263 LPBYTE lpDependencies,
6264 DWORD dwDependSize,
6265 LPWSTR lpServiceStartName,
6266 LPBYTE lpPassword,
6267 DWORD dwPwSize,
6268 LPSC_RPC_HANDLE lpServiceHandle)
6269 {
6270 UNIMPLEMENTED;
6271 return ERROR_CALL_NOT_IMPLEMENTED;
6272 }
6273
6274
6275 /* Function 46 */
6276 DWORD RQueryServiceTagInfo(
6277 handle_t BindingHandle) /* FIXME */
6278 {
6279 UNIMPLEMENTED;
6280 return ERROR_CALL_NOT_IMPLEMENTED;
6281 }
6282
6283
6284 /* Function 47 */
6285 DWORD RNotifyServiceStatusChange(
6286 SC_RPC_HANDLE hService,
6287 SC_RPC_NOTIFY_PARAMS NotifyParams,
6288 GUID *pClientProcessGuid,
6289 GUID *pSCMProcessGuid,
6290 PBOOL pfCreateRemoteQueue,
6291 LPSC_NOTIFY_RPC_HANDLE phNotify)
6292 {
6293 UNIMPLEMENTED;
6294 return ERROR_CALL_NOT_IMPLEMENTED;
6295 }
6296
6297
6298 /* Function 48 */
6299 DWORD RGetNotifyResults(
6300 SC_NOTIFY_RPC_HANDLE hNotify,
6301 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
6302 {
6303 UNIMPLEMENTED;
6304 return ERROR_CALL_NOT_IMPLEMENTED;
6305 }
6306
6307
6308 /* Function 49 */
6309 DWORD RCloseNotifyHandle(
6310 LPSC_NOTIFY_RPC_HANDLE phNotify,
6311 PBOOL pfApcFired)
6312 {
6313 UNIMPLEMENTED;
6314 return ERROR_CALL_NOT_IMPLEMENTED;
6315 }
6316
6317
6318 /* Function 50 */
6319 DWORD RControlServiceExA(
6320 SC_RPC_HANDLE hService,
6321 DWORD dwControl,
6322 DWORD dwInfoLevel)
6323 {
6324 UNIMPLEMENTED;
6325 return ERROR_CALL_NOT_IMPLEMENTED;
6326 }
6327
6328
6329 /* Function 51 */
6330 DWORD RControlServiceExW(
6331 SC_RPC_HANDLE hService,
6332 DWORD dwControl,
6333 DWORD dwInfoLevel)
6334 {
6335 UNIMPLEMENTED;
6336 return ERROR_CALL_NOT_IMPLEMENTED;
6337 }
6338
6339
6340 /* Function 52 */
6341 DWORD RSendPnPMessage(
6342 handle_t BindingHandle) /* FIXME */
6343 {
6344 UNIMPLEMENTED;
6345 return ERROR_CALL_NOT_IMPLEMENTED;
6346 }
6347
6348
6349 /* Function 53 */
6350 DWORD RValidatePnPService(
6351 handle_t BindingHandle) /* FIXME */
6352 {
6353 UNIMPLEMENTED;
6354 return ERROR_CALL_NOT_IMPLEMENTED;
6355 }
6356
6357
6358 /* Function 54 */
6359 DWORD ROpenServiceStatusHandle(
6360 handle_t BindingHandle) /* FIXME */
6361 {
6362 UNIMPLEMENTED;
6363 return ERROR_CALL_NOT_IMPLEMENTED;
6364 }
6365
6366
6367 /* Function 55 */
6368 DWORD RFunction55(
6369 handle_t BindingHandle) /* FIXME */
6370 {
6371 UNIMPLEMENTED;
6372 return ERROR_CALL_NOT_IMPLEMENTED;
6373 }
6374
6375
6376 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
6377 {
6378 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
6379 }
6380
6381
6382 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
6383 {
6384 HeapFree(GetProcessHeap(), 0, ptr);
6385 }
6386
6387
6388 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
6389 {
6390 /* Close the handle */
6391 RCloseServiceHandle(&hSCObject);
6392 }
6393
6394
6395 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
6396 {
6397 /* Unlock the database */
6398 RUnlockServiceDatabase(&Lock);
6399 }
6400
6401
6402 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
6403 {
6404 }
6405
6406 /* EOF */