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