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