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