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