a4718aa15f2bc00d9cb3e51f5fedb3a2714913fd
[reactos.git] / base / system / services / rpcserver.c
1 /*
2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/rpcserver.c
5 * PURPOSE: RPC server interface for the advapi32 calls
6 * COPYRIGHT: Copyright 2005-2006 Eric Kohl
7 * Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include "services.h"
14
15 #include <winnls.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20 /* GLOBALS *****************************************************************/
21
22 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
23 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
24 #define INVALID_TAG 0xAABBCCDD
25
26 typedef struct _SCMGR_HANDLE
27 {
28 DWORD Tag;
29 DWORD DesiredAccess;
30 } SCMGR_HANDLE;
31
32
33 typedef struct _MANAGER_HANDLE
34 {
35 SCMGR_HANDLE Handle;
36 WCHAR DatabaseName[1];
37 } MANAGER_HANDLE, *PMANAGER_HANDLE;
38
39
40 typedef struct _SERVICE_HANDLE
41 {
42 SCMGR_HANDLE Handle;
43 PSERVICE ServiceEntry;
44 } SERVICE_HANDLE, *PSERVICE_HANDLE;
45
46
47 #define SC_MANAGER_READ \
48 (STANDARD_RIGHTS_READ | \
49 SC_MANAGER_QUERY_LOCK_STATUS | \
50 SC_MANAGER_ENUMERATE_SERVICE)
51
52 #define SC_MANAGER_WRITE \
53 (STANDARD_RIGHTS_WRITE | \
54 SC_MANAGER_MODIFY_BOOT_CONFIG | \
55 SC_MANAGER_CREATE_SERVICE)
56
57 #define SC_MANAGER_EXECUTE \
58 (STANDARD_RIGHTS_EXECUTE | \
59 SC_MANAGER_LOCK | \
60 SC_MANAGER_ENUMERATE_SERVICE | \
61 SC_MANAGER_CONNECT | \
62 SC_MANAGER_CREATE_SERVICE)
63
64
65 #define SERVICE_READ \
66 (STANDARD_RIGHTS_READ | \
67 SERVICE_INTERROGATE | \
68 SERVICE_ENUMERATE_DEPENDENTS | \
69 SERVICE_QUERY_STATUS | \
70 SERVICE_QUERY_CONFIG)
71
72 #define SERVICE_WRITE \
73 (STANDARD_RIGHTS_WRITE | \
74 SERVICE_CHANGE_CONFIG)
75
76 #define SERVICE_EXECUTE \
77 (STANDARD_RIGHTS_EXECUTE | \
78 SERVICE_USER_DEFINED_CONTROL | \
79 SERVICE_PAUSE_CONTINUE | \
80 SERVICE_STOP | \
81 SERVICE_START)
82
83 #define TAG_ARRAY_SIZE 32
84
85 /* VARIABLES ***************************************************************/
86
87 static GENERIC_MAPPING
88 ScmManagerMapping = {SC_MANAGER_READ,
89 SC_MANAGER_WRITE,
90 SC_MANAGER_EXECUTE,
91 SC_MANAGER_ALL_ACCESS};
92
93 static GENERIC_MAPPING
94 ScmServiceMapping = {SERVICE_READ,
95 SERVICE_WRITE,
96 SERVICE_EXECUTE,
97 SERVICE_ALL_ACCESS};
98
99
100 /* FUNCTIONS ***************************************************************/
101
102 VOID
103 ScmStartRpcServer(VOID)
104 {
105 RPC_STATUS Status;
106
107 DPRINT("ScmStartRpcServer() called\n");
108
109 Status = RpcServerUseProtseqEpW(L"ncacn_np",
110 10,
111 L"\\pipe\\ntsvcs",
112 NULL);
113 if (Status != RPC_S_OK)
114 {
115 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
116 return;
117 }
118
119 Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
120 NULL,
121 NULL);
122 if (Status != RPC_S_OK)
123 {
124 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
125 return;
126 }
127
128 Status = RpcServerListen(1, 20, TRUE);
129 if (Status != RPC_S_OK)
130 {
131 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
132 return;
133 }
134
135 DPRINT("ScmStartRpcServer() done\n");
136 }
137
138
139 static DWORD
140 ScmCreateManagerHandle(LPWSTR lpDatabaseName,
141 SC_HANDLE *Handle)
142 {
143 PMANAGER_HANDLE Ptr;
144
145 if (lpDatabaseName == NULL)
146 lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
147
148 if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
149 {
150 DPRINT("Database %S, does not exist\n", lpDatabaseName);
151 return ERROR_DATABASE_DOES_NOT_EXIST;
152 }
153 else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
154 {
155 DPRINT("Invalid Database name %S.\n", lpDatabaseName);
156 return ERROR_INVALID_NAME;
157 }
158
159 Ptr = HeapAlloc(GetProcessHeap(),
160 HEAP_ZERO_MEMORY,
161 FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1]));
162 if (Ptr == NULL)
163 return ERROR_NOT_ENOUGH_MEMORY;
164
165 Ptr->Handle.Tag = MANAGER_TAG;
166
167 wcscpy(Ptr->DatabaseName, lpDatabaseName);
168
169 *Handle = (SC_HANDLE)Ptr;
170
171 return ERROR_SUCCESS;
172 }
173
174
175 static DWORD
176 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
177 SC_HANDLE *Handle)
178 {
179 PSERVICE_HANDLE Ptr;
180
181 Ptr = HeapAlloc(GetProcessHeap(),
182 HEAP_ZERO_MEMORY,
183 sizeof(SERVICE_HANDLE));
184 if (Ptr == NULL)
185 return ERROR_NOT_ENOUGH_MEMORY;
186
187 Ptr->Handle.Tag = SERVICE_TAG;
188
189 Ptr->ServiceEntry = lpServiceEntry;
190
191 *Handle = (SC_HANDLE)Ptr;
192
193 return ERROR_SUCCESS;
194 }
195
196
197 static PMANAGER_HANDLE
198 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle)
199 {
200 PMANAGER_HANDLE pManager = NULL;
201
202 _SEH2_TRY
203 {
204 if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG)
205 pManager = (PMANAGER_HANDLE)Handle;
206 }
207 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
208 {
209 DPRINT1("Exception: Invalid Service Manager handle!\n");
210 }
211 _SEH2_END;
212
213 return pManager;
214 }
215
216
217 static PSERVICE_HANDLE
218 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle)
219 {
220 PSERVICE_HANDLE pService = NULL;
221
222 _SEH2_TRY
223 {
224 if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG)
225 pService = (PSERVICE_HANDLE)Handle;
226 }
227 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
228 {
229 DPRINT1("Exception: Invalid Service handle!\n");
230 }
231 _SEH2_END;
232
233 return pService;
234 }
235
236
237 static DWORD
238 ScmCheckAccess(SC_HANDLE Handle,
239 DWORD dwDesiredAccess)
240 {
241 PMANAGER_HANDLE hMgr;
242
243 hMgr = (PMANAGER_HANDLE)Handle;
244 if (hMgr->Handle.Tag == MANAGER_TAG)
245 {
246 RtlMapGenericMask(&dwDesiredAccess,
247 &ScmManagerMapping);
248
249 hMgr->Handle.DesiredAccess = dwDesiredAccess;
250
251 return ERROR_SUCCESS;
252 }
253 else if (hMgr->Handle.Tag == SERVICE_TAG)
254 {
255 RtlMapGenericMask(&dwDesiredAccess,
256 &ScmServiceMapping);
257
258 hMgr->Handle.DesiredAccess = dwDesiredAccess;
259
260 return ERROR_SUCCESS;
261 }
262
263 return ERROR_INVALID_HANDLE;
264 }
265
266
267 DWORD
268 ScmAssignNewTag(PSERVICE lpService)
269 {
270 HKEY hKey = NULL;
271 DWORD dwError;
272 DWORD dwGroupTagCount = 0;
273 PDWORD pdwGroupTags = NULL;
274 DWORD dwFreeTag = 0;
275 DWORD dwTagUsedBase = 1;
276 BOOLEAN TagUsed[TAG_ARRAY_SIZE];
277 INT nTagOffset;
278 DWORD i;
279 DWORD cbDataSize;
280 PLIST_ENTRY ServiceEntry;
281 PSERVICE CurrentService;
282
283 ASSERT(lpService != NULL);
284 ASSERT(lpService->lpGroup != NULL);
285
286 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
287 L"System\\CurrentControlSet\\Control\\GroupOrderList",
288 0,
289 KEY_READ,
290 &hKey);
291
292 if (dwError != ERROR_SUCCESS)
293 goto findFreeTag;
294
295 /* query value length */
296 cbDataSize = 0;
297 dwError = RegQueryValueExW(hKey,
298 lpService->lpGroup->szGroupName,
299 NULL,
300 NULL,
301 NULL,
302 &cbDataSize);
303
304 if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA)
305 goto findFreeTag;
306
307 pdwGroupTags = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDataSize);
308 if (!pdwGroupTags)
309 {
310 dwError = ERROR_NOT_ENOUGH_MEMORY;
311 goto cleanup;
312 }
313
314 dwError = RegQueryValueExW(hKey,
315 lpService->lpGroup->szGroupName,
316 NULL,
317 NULL,
318 (LPBYTE)pdwGroupTags,
319 &cbDataSize);
320
321 if (dwError != ERROR_SUCCESS)
322 goto findFreeTag;
323
324 if (cbDataSize < sizeof(pdwGroupTags[0]))
325 goto findFreeTag;
326
327 dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1);
328
329 findFreeTag:
330 do
331 {
332 /* mark all tags as unused */
333 for (i = 0; i < TAG_ARRAY_SIZE; i++)
334 TagUsed[i] = FALSE;
335
336 /* mark tags in GroupOrderList as used */
337 for (i = 1; i <= dwGroupTagCount; i++)
338 {
339 nTagOffset = pdwGroupTags[i] - dwTagUsedBase;
340 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
341 TagUsed[nTagOffset] = TRUE;
342 }
343
344 /* mark tags in service list as used */
345 ServiceEntry = lpService->ServiceListEntry.Flink;
346 while (ServiceEntry != &lpService->ServiceListEntry)
347 {
348 ASSERT(ServiceEntry != NULL);
349 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
350 if (CurrentService->lpGroup == lpService->lpGroup)
351 {
352 nTagOffset = CurrentService->dwTag - dwTagUsedBase;
353 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
354 TagUsed[nTagOffset] = TRUE;
355 }
356
357 ServiceEntry = ServiceEntry->Flink;
358 }
359
360 /* find unused tag, if any */
361 for (i = 0; i < TAG_ARRAY_SIZE; i++)
362 {
363 if (!TagUsed[i])
364 {
365 dwFreeTag = dwTagUsedBase + i;
366 break;
367 }
368 }
369
370 dwTagUsedBase += TAG_ARRAY_SIZE;
371 } while (!dwFreeTag);
372
373 cleanup:
374 if (pdwGroupTags)
375 HeapFree(GetProcessHeap(), 0, pdwGroupTags);
376
377 if (hKey)
378 RegCloseKey(hKey);
379
380 if (dwFreeTag)
381 {
382 lpService->dwTag = dwFreeTag;
383 DPRINT("Assigning new tag %lu to service %S in group %S\n",
384 lpService->dwTag, lpService->lpServiceName, lpService->lpGroup->szGroupName);
385 dwError = ERROR_SUCCESS;
386 }
387 else
388 {
389 DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
390 lpService->lpServiceName, dwError);
391 }
392
393 return dwError;
394 }
395
396
397 /* Create a path suitable for the bootloader out of the full path */
398 DWORD
399 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
400 {
401 SIZE_T ServiceNameLen, ExpandedLen;
402 DWORD BufferSize;
403 WCHAR Dest;
404 WCHAR *Expanded;
405 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
406 OBJECT_ATTRIBUTES ObjectAttributes;
407 NTSTATUS Status;
408 HANDLE SymbolicLinkHandle;
409
410 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
411
412 if (!RelativeName)
413 return ERROR_INVALID_PARAMETER;
414
415 *RelativeName = NULL;
416
417 ServiceNameLen = wcslen(CanonName);
418
419 /* First check, if it's already good */
420 if (ServiceNameLen > 12 &&
421 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
422 {
423 *RelativeName = HeapAlloc(GetProcessHeap(),
424 HEAP_ZERO_MEMORY,
425 (ServiceNameLen + 1) * sizeof(WCHAR));
426 if (*RelativeName == NULL)
427 {
428 DPRINT("Error allocating memory for boot driver name!\n");
429 return ERROR_NOT_ENOUGH_MEMORY;
430 }
431
432 /* Copy it */
433 wcscpy(*RelativeName, CanonName);
434
435 DPRINT("Bootdriver name %S\n", *RelativeName);
436 return ERROR_SUCCESS;
437 }
438
439 /* If it has %SystemRoot% prefix, substitute it to \System*/
440 if (ServiceNameLen > 13 &&
441 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
442 {
443 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
444 *RelativeName = HeapAlloc(GetProcessHeap(),
445 HEAP_ZERO_MEMORY,
446 ServiceNameLen * sizeof(WCHAR));
447
448 if (*RelativeName == NULL)
449 {
450 DPRINT("Error allocating memory for boot driver name!\n");
451 return ERROR_NOT_ENOUGH_MEMORY;
452 }
453
454 /* Copy it */
455 wcscpy(*RelativeName, L"\\SystemRoot\\");
456 wcscat(*RelativeName, CanonName + 13);
457
458 DPRINT("Bootdriver name %S\n", *RelativeName);
459 return ERROR_SUCCESS;
460 }
461
462 /* Get buffer size needed for expanding env strings */
463 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
464
465 if (BufferSize <= 1)
466 {
467 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
468 return ERROR_INVALID_ENVIRONMENT;
469 }
470
471 /* Allocate memory, since the size is known now */
472 Expanded = HeapAlloc(GetProcessHeap(),
473 HEAP_ZERO_MEMORY,
474 (BufferSize + 1) * sizeof(WCHAR));
475 if (!Expanded)
476 {
477 DPRINT("Error allocating memory for boot driver name!\n");
478 return ERROR_NOT_ENOUGH_MEMORY;
479 }
480
481 /* Expand it */
482 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
483 BufferSize)
484 {
485 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
486 HeapFree(GetProcessHeap(), 0, Expanded);
487 return ERROR_NOT_ENOUGH_MEMORY;
488 }
489
490 /* Convert to NT-style path */
491 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
492 {
493 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
494 return ERROR_INVALID_ENVIRONMENT;
495 }
496
497 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
498
499 /* No need to keep the dos-path anymore */
500 HeapFree(GetProcessHeap(), 0, Expanded);
501
502 /* Copy it to the allocated place */
503 Expanded = HeapAlloc(GetProcessHeap(),
504 HEAP_ZERO_MEMORY,
505 NtPathName.Length + sizeof(UNICODE_NULL));
506 if (!Expanded)
507 {
508 DPRINT("Error allocating memory for boot driver name!\n");
509 RtlFreeUnicodeString(&NtPathName);
510 return ERROR_NOT_ENOUGH_MEMORY;
511 }
512
513 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
514 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
515 Expanded[ExpandedLen] = UNICODE_NULL;
516 RtlFreeUnicodeString(&NtPathName);
517
518 if (ServiceNameLen > ExpandedLen &&
519 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
520 {
521 HeapFree(GetProcessHeap(), 0, Expanded);
522
523 /* Only \SystemRoot\ is missing */
524 *RelativeName = HeapAlloc(GetProcessHeap(),
525 HEAP_ZERO_MEMORY,
526 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
527 if (*RelativeName == NULL)
528 {
529 DPRINT("Error allocating memory for boot driver name!\n");
530 return ERROR_NOT_ENOUGH_MEMORY;
531 }
532
533 wcscpy(*RelativeName, L"\\SystemRoot\\");
534 wcscat(*RelativeName, CanonName + ExpandedLen);
535
536 return ERROR_SUCCESS;
537 }
538
539 /* No longer need this */
540 HeapFree(GetProcessHeap(), 0, Expanded);
541
542 /* The most complex case starts here */
543 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
544 InitializeObjectAttributes(&ObjectAttributes,
545 &SystemRoot,
546 OBJ_CASE_INSENSITIVE,
547 NULL,
548 NULL);
549
550 /* Open this symlink */
551 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
552 if (NT_SUCCESS(Status))
553 {
554 DPRINT("Opened symbolic link object\n");
555
556 RtlInitEmptyUnicodeString(&LinkTarget, NULL, 0);
557 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
558 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
559 {
560 /* Check if required buffer size is sane */
561 if (BufferSize > UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL))
562 {
563 DPRINT("Too large buffer required\n");
564
565 NtClose(SymbolicLinkHandle);
566 return ERROR_NOT_ENOUGH_MEMORY;
567 }
568
569 /* Alloc the string */
570 LinkTarget.Length = (USHORT)BufferSize;
571 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(UNICODE_NULL);
572 LinkTarget.Buffer = HeapAlloc(GetProcessHeap(),
573 HEAP_ZERO_MEMORY,
574 LinkTarget.MaximumLength);
575 if (!LinkTarget.Buffer)
576 {
577 DPRINT("Unable to alloc buffer\n");
578 NtClose(SymbolicLinkHandle);
579 return ERROR_NOT_ENOUGH_MEMORY;
580 }
581
582 /* Do a real query now */
583 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
584 NtClose(SymbolicLinkHandle);
585 if (NT_SUCCESS(Status))
586 {
587 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
588
589 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
590 if ((ServiceNameLen > ExpandedLen) &&
591 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
592 {
593 *RelativeName = HeapAlloc(GetProcessHeap(),
594 HEAP_ZERO_MEMORY,
595 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
596
597 if (*RelativeName == NULL)
598 {
599 DPRINT("Unable to alloc buffer\n");
600 return ERROR_NOT_ENOUGH_MEMORY;
601 }
602
603 /* Copy it over, substituting the first part
604 with SystemRoot */
605 wcscpy(*RelativeName, L"\\SystemRoot\\");
606 wcscat(*RelativeName, CanonName+ExpandedLen+1);
607
608 /* Return success */
609 return ERROR_SUCCESS;
610 }
611 else
612 {
613 return ERROR_INVALID_PARAMETER;
614 }
615 }
616 else
617 {
618 DPRINT("Error, Status = %08X\n", Status);
619 return ERROR_INVALID_PARAMETER;
620 }
621 }
622 else
623 {
624 DPRINT("Error, Status = %08X\n", Status);
625 NtClose(SymbolicLinkHandle);
626 return ERROR_INVALID_PARAMETER;
627 }
628 }
629 else
630 {
631 /* Failure */
632 DPRINT("Error, Status = %08X\n", Status);
633 return ERROR_INVALID_PARAMETER;
634 }
635 }
636
637
638 DWORD
639 ScmCanonDriverImagePath(DWORD dwStartType,
640 const wchar_t *lpServiceName,
641 wchar_t **lpCanonName)
642 {
643 DWORD Result;
644 SIZE_T ServiceNameLen;
645 UNICODE_STRING NtServiceName;
646 WCHAR *RelativeName;
647 const WCHAR *SourceName = lpServiceName;
648
649 /* Calculate the length of the service's name */
650 ServiceNameLen = wcslen(lpServiceName);
651
652 /* 12 is wcslen(L"\\SystemRoot\\") */
653 if (ServiceNameLen > 12 &&
654 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
655 {
656 /* SystemRoot prefix is already included */
657 *lpCanonName = HeapAlloc(GetProcessHeap(),
658 HEAP_ZERO_MEMORY,
659 (ServiceNameLen + 1) * sizeof(WCHAR));
660
661 if (*lpCanonName == NULL)
662 {
663 DPRINT("Error allocating memory for canonized service name!\n");
664 return ERROR_NOT_ENOUGH_MEMORY;
665 }
666
667 /* If it's a boot-time driver, it must be systemroot relative */
668 if (dwStartType == SERVICE_BOOT_START)
669 SourceName += 12;
670
671 /* Copy it */
672 wcscpy(*lpCanonName, SourceName);
673
674 DPRINT("Canonicalized name %S\n", *lpCanonName);
675 return NO_ERROR;
676 }
677
678 /* Check if it has %SystemRoot% (len=13) */
679 if (ServiceNameLen > 13 &&
680 !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13))
681 {
682 /* Substitute %SystemRoot% with \\SystemRoot\\ */
683 *lpCanonName = HeapAlloc(GetProcessHeap(),
684 HEAP_ZERO_MEMORY,
685 (ServiceNameLen + 1) * sizeof(WCHAR));
686
687 if (*lpCanonName == NULL)
688 {
689 DPRINT("Error allocating memory for canonized service name!\n");
690 return ERROR_NOT_ENOUGH_MEMORY;
691 }
692
693 /* If it's a boot-time driver, it must be systemroot relative */
694 if (dwStartType == SERVICE_BOOT_START)
695 wcscpy(*lpCanonName, L"\\SystemRoot\\");
696
697 wcscat(*lpCanonName, lpServiceName + 13);
698
699 DPRINT("Canonicalized name %S\n", *lpCanonName);
700 return NO_ERROR;
701 }
702
703 /* Check if it's a relative path name */
704 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
705 {
706 *lpCanonName = HeapAlloc(GetProcessHeap(),
707 HEAP_ZERO_MEMORY,
708 (ServiceNameLen + 1) * sizeof(WCHAR));
709
710 if (*lpCanonName == NULL)
711 {
712 DPRINT("Error allocating memory for canonized service name!\n");
713 return ERROR_NOT_ENOUGH_MEMORY;
714 }
715
716 /* Just copy it over without changing */
717 wcscpy(*lpCanonName, lpServiceName);
718
719 return NO_ERROR;
720 }
721
722 /* It seems to be a DOS path, convert it */
723 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
724 {
725 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
726 return ERROR_INVALID_PARAMETER;
727 }
728
729 *lpCanonName = HeapAlloc(GetProcessHeap(),
730 HEAP_ZERO_MEMORY,
731 NtServiceName.Length + sizeof(WCHAR));
732
733 if (*lpCanonName == NULL)
734 {
735 DPRINT("Error allocating memory for canonized service name!\n");
736 RtlFreeUnicodeString(&NtServiceName);
737 return ERROR_NOT_ENOUGH_MEMORY;
738 }
739
740 /* Copy the string */
741 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
742
743 /* The unicode string is not needed anymore */
744 RtlFreeUnicodeString(&NtServiceName);
745
746 if (dwStartType != SERVICE_BOOT_START)
747 {
748 DPRINT("Canonicalized name %S\n", *lpCanonName);
749 return NO_ERROR;
750 }
751
752 /* The service is boot-started, so must be relative */
753 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
754 if (Result)
755 {
756 /* There is a problem, free name and return */
757 HeapFree(GetProcessHeap(), 0, *lpCanonName);
758 DPRINT("Error converting named!\n");
759 return Result;
760 }
761
762 ASSERT(RelativeName);
763
764 /* Copy that string */
765 wcscpy(*lpCanonName, RelativeName + 12);
766
767 /* Free the allocated buffer */
768 HeapFree(GetProcessHeap(), 0, RelativeName);
769
770 DPRINT("Canonicalized name %S\n", *lpCanonName);
771
772 /* Success */
773 return NO_ERROR;
774 }
775
776
777 /* Internal recursive function */
778 /* Need to search for every dependency on every service */
779 static DWORD
780 Int_EnumDependentServicesW(HKEY hServicesKey,
781 PSERVICE lpService,
782 DWORD dwServiceState,
783 PSERVICE *lpServices,
784 LPDWORD pcbBytesNeeded,
785 LPDWORD lpServicesReturned)
786 {
787 DWORD dwError = ERROR_SUCCESS;
788 WCHAR szNameBuf[MAX_PATH];
789 WCHAR szValueBuf[MAX_PATH];
790 WCHAR *lpszNameBuf = szNameBuf;
791 WCHAR *lpszValueBuf = szValueBuf;
792 DWORD dwSize;
793 DWORD dwNumSubKeys;
794 DWORD dwIteration;
795 PSERVICE lpCurrentService;
796 HKEY hServiceEnumKey;
797 DWORD dwCurrentServiceState = SERVICE_ACTIVE;
798 DWORD dwDependServiceStrPtr = 0;
799 DWORD dwRequiredSize = 0;
800
801 /* Get the number of service keys */
802 dwError = RegQueryInfoKeyW(hServicesKey,
803 NULL,
804 NULL,
805 NULL,
806 &dwNumSubKeys,
807 NULL,
808 NULL,
809 NULL,
810 NULL,
811 NULL,
812 NULL,
813 NULL);
814 if (dwError != ERROR_SUCCESS)
815 {
816 DPRINT("ERROR! Unable to get number of services keys.\n");
817 return dwError;
818 }
819
820 /* Iterate the service keys to see if another service depends on the this service */
821 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
822 {
823 dwSize = MAX_PATH;
824 dwError = RegEnumKeyExW(hServicesKey,
825 dwIteration,
826 lpszNameBuf,
827 &dwSize,
828 NULL,
829 NULL,
830 NULL,
831 NULL);
832 if (dwError != ERROR_SUCCESS)
833 return dwError;
834
835 /* Open the Service key */
836 dwError = RegOpenKeyExW(hServicesKey,
837 lpszNameBuf,
838 0,
839 KEY_READ,
840 &hServiceEnumKey);
841 if (dwError != ERROR_SUCCESS)
842 return dwError;
843
844 dwSize = MAX_PATH * sizeof(WCHAR);
845
846 /* Check for the DependOnService Value */
847 dwError = RegQueryValueExW(hServiceEnumKey,
848 L"DependOnService",
849 NULL,
850 NULL,
851 (LPBYTE)lpszValueBuf,
852 &dwSize);
853
854 /* FIXME: Handle load order. */
855
856 /* If the service found has a DependOnService value */
857 if (dwError == ERROR_SUCCESS)
858 {
859 dwDependServiceStrPtr = 0;
860
861 /* Can be more than one Dependencies in the DependOnService string */
862 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
863 {
864 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
865 {
866 /* Get the current enumed service pointer */
867 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
868
869 /* Check for valid Service */
870 if (!lpCurrentService)
871 {
872 /* This should never happen! */
873 DPRINT("This should not happen at this point, report to Developer\n");
874 return ERROR_NOT_FOUND;
875 }
876
877 /* Determine state the service is in */
878 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
879 dwCurrentServiceState = SERVICE_INACTIVE;
880
881 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
882 if ((dwCurrentServiceState == dwServiceState) ||
883 (dwServiceState == SERVICE_STATE_ALL))
884 {
885 /* Calculate the required size */
886 dwRequiredSize += sizeof(SERVICE_STATUS);
887 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
888 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
889
890 /* Add the size for service name and display name pointers */
891 dwRequiredSize += (2 * sizeof(PVOID));
892
893 /* increase the BytesNeeded size */
894 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
895
896 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
897 comes first */
898
899 /* Recursive call to check for its dependencies */
900 Int_EnumDependentServicesW(hServicesKey,
901 lpCurrentService,
902 dwServiceState,
903 lpServices,
904 pcbBytesNeeded,
905 lpServicesReturned);
906
907 /* If the lpServices is valid set the service pointer */
908 if (lpServices)
909 lpServices[*lpServicesReturned] = lpCurrentService;
910
911 *lpServicesReturned = *lpServicesReturned + 1;
912 }
913 }
914
915 dwDependServiceStrPtr += (DWORD)(wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
916 }
917 }
918 else if (*pcbBytesNeeded)
919 {
920 dwError = ERROR_SUCCESS;
921 }
922
923 RegCloseKey(hServiceEnumKey);
924 }
925
926 return dwError;
927 }
928
929
930 /* Function 0 */
931 DWORD
932 WINAPI
933 RCloseServiceHandle(
934 LPSC_RPC_HANDLE hSCObject)
935 {
936 PMANAGER_HANDLE hManager;
937 PSERVICE_HANDLE hService;
938 PSERVICE lpService;
939 HKEY hServicesKey;
940 DWORD dwError;
941 DWORD pcbBytesNeeded = 0;
942 DWORD dwServicesReturned = 0;
943
944 DPRINT("RCloseServiceHandle() called\n");
945
946 DPRINT("hSCObject = %p\n", *hSCObject);
947
948 if (*hSCObject == 0)
949 return ERROR_INVALID_HANDLE;
950
951 hManager = ScmGetServiceManagerFromHandle(*hSCObject);
952 hService = ScmGetServiceFromHandle(*hSCObject);
953
954 if (hManager != NULL)
955 {
956 DPRINT("Found manager handle\n");
957
958 /* Make sure we don't access stale memory if someone tries to use this handle again. */
959 hManager->Handle.Tag = INVALID_TAG;
960
961 HeapFree(GetProcessHeap(), 0, hManager);
962 hManager = NULL;
963
964 *hSCObject = NULL;
965
966 DPRINT("RCloseServiceHandle() done\n");
967 return ERROR_SUCCESS;
968 }
969 else if (hService != NULL)
970 {
971 DPRINT("Found service handle\n");
972
973 /* Lock the service database exclusively */
974 ScmLockDatabaseExclusive();
975
976 /* Get the pointer to the service record */
977 lpService = hService->ServiceEntry;
978
979 /* Make sure we don't access stale memory if someone tries to use this handle again. */
980 hService->Handle.Tag = INVALID_TAG;
981
982 /* Free the handle */
983 HeapFree(GetProcessHeap(), 0, hService);
984 hService = NULL;
985
986 ASSERT(lpService->dwRefCount > 0);
987
988 lpService->dwRefCount--;
989 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
990 lpService->dwRefCount);
991
992 if (lpService->dwRefCount == 0)
993 {
994 /* If this service has been marked for deletion */
995 if (lpService->bDeleted &&
996 lpService->Status.dwCurrentState == SERVICE_STOPPED)
997 {
998 /* Open the Services Reg key */
999 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1000 L"System\\CurrentControlSet\\Services",
1001 0,
1002 KEY_SET_VALUE | KEY_READ,
1003 &hServicesKey);
1004 if (dwError != ERROR_SUCCESS)
1005 {
1006 DPRINT("Failed to open services key\n");
1007 ScmUnlockDatabase();
1008 return dwError;
1009 }
1010
1011 /* Call the internal function with NULL, just to get bytes we need */
1012 Int_EnumDependentServicesW(hServicesKey,
1013 lpService,
1014 SERVICE_ACTIVE,
1015 NULL,
1016 &pcbBytesNeeded,
1017 &dwServicesReturned);
1018
1019 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
1020 if (pcbBytesNeeded)
1021 {
1022 DPRINT("Deletion failed due to running dependencies.\n");
1023 RegCloseKey(hServicesKey);
1024 ScmUnlockDatabase();
1025 return ERROR_SUCCESS;
1026 }
1027
1028 /* There are no references and no running dependencies,
1029 it is now safe to delete the service */
1030
1031 /* Delete the Service Key */
1032 dwError = ScmDeleteRegKey(hServicesKey,
1033 lpService->lpServiceName);
1034
1035 RegCloseKey(hServicesKey);
1036
1037 if (dwError != ERROR_SUCCESS)
1038 {
1039 DPRINT("Failed to Delete the Service Registry key\n");
1040 ScmUnlockDatabase();
1041 return dwError;
1042 }
1043
1044 /* Delete the Service */
1045 ScmDeleteServiceRecord(lpService);
1046 }
1047 }
1048
1049 ScmUnlockDatabase();
1050
1051 *hSCObject = NULL;
1052
1053 DPRINT("RCloseServiceHandle() done\n");
1054 return ERROR_SUCCESS;
1055 }
1056
1057 DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
1058
1059 return ERROR_INVALID_HANDLE;
1060 }
1061
1062
1063 /* Function 1 */
1064 DWORD
1065 WINAPI
1066 RControlService(
1067 SC_RPC_HANDLE hService,
1068 DWORD dwControl,
1069 LPSERVICE_STATUS lpServiceStatus)
1070 {
1071 PSERVICE_HANDLE hSvc;
1072 PSERVICE lpService;
1073 ACCESS_MASK DesiredAccess;
1074 DWORD dwError = ERROR_SUCCESS;
1075 DWORD pcbBytesNeeded = 0;
1076 DWORD dwServicesReturned = 0;
1077 DWORD dwControlsAccepted;
1078 DWORD dwCurrentState;
1079 HKEY hServicesKey = NULL;
1080 LPCWSTR lpLogStrings[2];
1081 WCHAR szLogBuffer[80];
1082 UINT uID;
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_CONTROL_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)
1241 {
1242 if (dwControl == SERVICE_CONTROL_STOP ||
1243 dwControl == SERVICE_CONTROL_PAUSE ||
1244 dwControl == SERVICE_CONTROL_CONTINUE)
1245 {
1246 /* Log a successful send control */
1247
1248 switch (dwControl)
1249 {
1250 case SERVICE_CONTROL_STOP:
1251 uID = IDS_SERVICE_STOP;
1252 break;
1253
1254 case SERVICE_CONTROL_PAUSE:
1255 uID = IDS_SERVICE_PAUSE;
1256 break;
1257
1258 case SERVICE_CONTROL_CONTINUE:
1259 uID = IDS_SERVICE_RESUME;
1260 break;
1261 }
1262 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, 80);
1263
1264 lpLogStrings[0] = lpService->lpDisplayName;
1265 lpLogStrings[1] = szLogBuffer;
1266
1267 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
1268 EVENTLOG_INFORMATION_TYPE,
1269 2,
1270 lpLogStrings);
1271 }
1272 }
1273
1274 return dwError;
1275 }
1276
1277
1278 /* Function 2 */
1279 DWORD
1280 WINAPI
1281 RDeleteService(
1282 SC_RPC_HANDLE hService)
1283 {
1284 PSERVICE_HANDLE hSvc;
1285 PSERVICE lpService;
1286 DWORD dwError;
1287
1288 DPRINT("RDeleteService() called\n");
1289
1290 if (ScmShutdown)
1291 return ERROR_SHUTDOWN_IN_PROGRESS;
1292
1293 hSvc = ScmGetServiceFromHandle(hService);
1294 if (hSvc == NULL)
1295 {
1296 DPRINT1("Invalid service handle!\n");
1297 return ERROR_INVALID_HANDLE;
1298 }
1299
1300 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1301 DELETE))
1302 return ERROR_ACCESS_DENIED;
1303
1304 lpService = hSvc->ServiceEntry;
1305 if (lpService == NULL)
1306 {
1307 DPRINT("lpService == NULL!\n");
1308 return ERROR_INVALID_HANDLE;
1309 }
1310
1311 /* Lock the service database exclusively */
1312 ScmLockDatabaseExclusive();
1313
1314 if (lpService->bDeleted)
1315 {
1316 DPRINT("The service has already been marked for delete!\n");
1317 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1318 goto Done;
1319 }
1320
1321 /* Mark service for delete */
1322 lpService->bDeleted = TRUE;
1323
1324 dwError = ScmMarkServiceForDelete(lpService);
1325
1326 Done:
1327 /* Unlock the service database */
1328 ScmUnlockDatabase();
1329
1330 DPRINT("RDeleteService() done\n");
1331
1332 return dwError;
1333 }
1334
1335
1336 /* Function 3 */
1337 DWORD
1338 WINAPI
1339 RLockServiceDatabase(
1340 SC_RPC_HANDLE hSCManager,
1341 LPSC_RPC_LOCK lpLock)
1342 {
1343 PMANAGER_HANDLE hMgr;
1344
1345 DPRINT("RLockServiceDatabase() called\n");
1346
1347 *lpLock = NULL;
1348
1349 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
1350 if (hMgr == NULL)
1351 {
1352 DPRINT1("Invalid service manager handle!\n");
1353 return ERROR_INVALID_HANDLE;
1354 }
1355
1356 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
1357 SC_MANAGER_LOCK))
1358 return ERROR_ACCESS_DENIED;
1359
1360 return ScmAcquireServiceStartLock(FALSE, lpLock);
1361 }
1362
1363
1364 /* Function 4 */
1365 DWORD
1366 WINAPI
1367 RQueryServiceObjectSecurity(
1368 SC_RPC_HANDLE hService,
1369 SECURITY_INFORMATION dwSecurityInformation,
1370 LPBYTE lpSecurityDescriptor,
1371 DWORD cbBufSize,
1372 LPBOUNDED_DWORD_256K pcbBytesNeeded)
1373 {
1374 PSERVICE_HANDLE hSvc;
1375 PSERVICE lpService;
1376 ULONG DesiredAccess = 0;
1377 NTSTATUS Status;
1378 DWORD dwBytesNeeded;
1379 DWORD dwError;
1380
1381 DPRINT("RQueryServiceObjectSecurity() called\n");
1382
1383 hSvc = ScmGetServiceFromHandle(hService);
1384 if (hSvc == NULL)
1385 {
1386 DPRINT1("Invalid service handle!\n");
1387 return ERROR_INVALID_HANDLE;
1388 }
1389
1390 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1391 GROUP_SECURITY_INFORMATION |
1392 OWNER_SECURITY_INFORMATION))
1393 DesiredAccess |= READ_CONTROL;
1394
1395 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1396 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1397
1398 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1399 DesiredAccess))
1400 {
1401 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1402 return ERROR_ACCESS_DENIED;
1403 }
1404
1405 lpService = hSvc->ServiceEntry;
1406 if (lpService == NULL)
1407 {
1408 DPRINT("lpService == NULL!\n");
1409 return ERROR_INVALID_HANDLE;
1410 }
1411
1412 /* Lock the service database */
1413 ScmLockDatabaseShared();
1414
1415 /* Retrieve the security descriptor */
1416 Status = RtlQuerySecurityObject(lpService->pSecurityDescriptor,
1417 dwSecurityInformation,
1418 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1419 cbBufSize,
1420 &dwBytesNeeded);
1421
1422 /* Unlock the service database */
1423 ScmUnlockDatabase();
1424
1425 if (NT_SUCCESS(Status))
1426 {
1427 *pcbBytesNeeded = dwBytesNeeded;
1428 dwError = STATUS_SUCCESS;
1429 }
1430 else if (Status == STATUS_BUFFER_TOO_SMALL)
1431 {
1432 *pcbBytesNeeded = dwBytesNeeded;
1433 dwError = ERROR_INSUFFICIENT_BUFFER;
1434 }
1435 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
1436 {
1437 dwError = ERROR_GEN_FAILURE;
1438 }
1439 else
1440 {
1441 dwError = RtlNtStatusToDosError(Status);
1442 }
1443
1444 return dwError;
1445 }
1446
1447
1448 /* Function 5 */
1449 DWORD
1450 WINAPI
1451 RSetServiceObjectSecurity(
1452 SC_RPC_HANDLE hService,
1453 DWORD dwSecurityInformation,
1454 LPBYTE lpSecurityDescriptor,
1455 DWORD dwSecurityDescriptorSize)
1456 {
1457 PSERVICE_HANDLE hSvc;
1458 PSERVICE lpService;
1459 ACCESS_MASK DesiredAccess = 0;
1460 HANDLE hToken = NULL;
1461 HKEY hServiceKey = NULL;
1462 BOOL bDatabaseLocked = FALSE;
1463 NTSTATUS Status;
1464 DWORD dwError;
1465
1466 DPRINT("RSetServiceObjectSecurity() called\n");
1467
1468 hSvc = ScmGetServiceFromHandle(hService);
1469 if (hSvc == NULL)
1470 {
1471 DPRINT1("Invalid service handle!\n");
1472 return ERROR_INVALID_HANDLE;
1473 }
1474
1475 if (dwSecurityInformation == 0 ||
1476 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1477 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
1478 return ERROR_INVALID_PARAMETER;
1479
1480 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1481 return ERROR_INVALID_PARAMETER;
1482
1483 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1484 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1485
1486 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1487 DesiredAccess |= WRITE_DAC;
1488
1489 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1490 DesiredAccess |= WRITE_OWNER;
1491
1492 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1493 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1494 return ERROR_INVALID_PARAMETER;
1495
1496 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1497 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1498 return ERROR_INVALID_PARAMETER;
1499
1500 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1501 DesiredAccess))
1502 {
1503 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1504 return ERROR_ACCESS_DENIED;
1505 }
1506
1507 lpService = hSvc->ServiceEntry;
1508 if (lpService == NULL)
1509 {
1510 DPRINT1("lpService == NULL!\n");
1511 return ERROR_INVALID_HANDLE;
1512 }
1513
1514 if (lpService->bDeleted)
1515 return ERROR_SERVICE_MARKED_FOR_DELETE;
1516
1517 #if 0
1518 RpcImpersonateClient(NULL);
1519
1520 Status = NtOpenThreadToken(NtCurrentThread(),
1521 8,
1522 TRUE,
1523 &hToken);
1524 if (!NT_SUCCESS(Status))
1525 return RtlNtStatusToDosError(Status);
1526
1527 RpcRevertToSelf();
1528 #endif
1529
1530 /* Build the new security descriptor */
1531 Status = RtlSetSecurityObject(dwSecurityInformation,
1532 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1533 &lpService->pSecurityDescriptor,
1534 &ScmServiceMapping,
1535 hToken);
1536 if (!NT_SUCCESS(Status))
1537 {
1538 dwError = RtlNtStatusToDosError(Status);
1539 goto Done;
1540 }
1541
1542 /* Lock the service database exclusive */
1543 ScmLockDatabaseExclusive();
1544 bDatabaseLocked = TRUE;
1545
1546 /* Open the service key */
1547 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1548 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
1549 &hServiceKey);
1550 if (dwError != ERROR_SUCCESS)
1551 goto Done;
1552
1553 /* Store the new security descriptor */
1554 dwError = ScmWriteSecurityDescriptor(hServiceKey,
1555 lpService->pSecurityDescriptor);
1556
1557 RegFlushKey(hServiceKey);
1558
1559 Done:
1560 if (hServiceKey != NULL)
1561 RegCloseKey(hServiceKey);
1562
1563 /* Unlock service database */
1564 if (bDatabaseLocked == TRUE)
1565 ScmUnlockDatabase();
1566
1567 if (hToken != NULL)
1568 NtClose(hToken);
1569
1570 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1571
1572 return dwError;
1573 }
1574
1575
1576 /* Function 6 */
1577 DWORD
1578 WINAPI
1579 RQueryServiceStatus(
1580 SC_RPC_HANDLE hService,
1581 LPSERVICE_STATUS lpServiceStatus)
1582 {
1583 PSERVICE_HANDLE hSvc;
1584 PSERVICE lpService;
1585
1586 DPRINT("RQueryServiceStatus() called\n");
1587
1588 if (ScmShutdown)
1589 return ERROR_SHUTDOWN_IN_PROGRESS;
1590
1591 hSvc = ScmGetServiceFromHandle(hService);
1592 if (hSvc == NULL)
1593 {
1594 DPRINT1("Invalid service handle!\n");
1595 return ERROR_INVALID_HANDLE;
1596 }
1597
1598 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1599 SERVICE_QUERY_STATUS))
1600 {
1601 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1602 return ERROR_ACCESS_DENIED;
1603 }
1604
1605 lpService = hSvc->ServiceEntry;
1606 if (lpService == NULL)
1607 {
1608 DPRINT("lpService == NULL!\n");
1609 return ERROR_INVALID_HANDLE;
1610 }
1611
1612 /* Lock the service database shared */
1613 ScmLockDatabaseShared();
1614
1615 /* Return service status information */
1616 RtlCopyMemory(lpServiceStatus,
1617 &lpService->Status,
1618 sizeof(SERVICE_STATUS));
1619
1620 /* Unlock the service database */
1621 ScmUnlockDatabase();
1622
1623 return ERROR_SUCCESS;
1624 }
1625
1626
1627 static BOOL
1628 ScmIsValidServiceState(DWORD dwCurrentState)
1629 {
1630 switch (dwCurrentState)
1631 {
1632 case SERVICE_STOPPED:
1633 case SERVICE_START_PENDING:
1634 case SERVICE_STOP_PENDING:
1635 case SERVICE_RUNNING:
1636 case SERVICE_CONTINUE_PENDING:
1637 case SERVICE_PAUSE_PENDING:
1638 case SERVICE_PAUSED:
1639 return TRUE;
1640
1641 default:
1642 return FALSE;
1643 }
1644 }
1645
1646
1647 /* Function 7 */
1648 DWORD
1649 WINAPI
1650 RSetServiceStatus(
1651 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1652 LPSERVICE_STATUS lpServiceStatus)
1653 {
1654 PSERVICE lpService;
1655 DWORD dwPreviousState;
1656 DWORD dwPreviousType;
1657 LPCWSTR lpLogStrings[2];
1658 WCHAR szLogBuffer[80];
1659 UINT uID;
1660
1661 DPRINT("RSetServiceStatus() called\n");
1662 DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1663 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
1664 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1665 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1666 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1667 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1668 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1669 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1670
1671 if (hServiceStatus == 0)
1672 {
1673 DPRINT("hServiceStatus == NULL!\n");
1674 return ERROR_INVALID_HANDLE;
1675 }
1676
1677 lpService = (PSERVICE)hServiceStatus;
1678
1679 /* Check current state */
1680 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1681 {
1682 DPRINT("Invalid service state!\n");
1683 return ERROR_INVALID_DATA;
1684 }
1685
1686 /* Check service type */
1687 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1688 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1689 {
1690 DPRINT("Invalid service type!\n");
1691 return ERROR_INVALID_DATA;
1692 }
1693
1694 /* Check accepted controls */
1695 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1696 {
1697 DPRINT("Invalid controls accepted!\n");
1698 return ERROR_INVALID_DATA;
1699 }
1700
1701 /* Set the wait hint and check point only if the service is in a pending state,
1702 otherwise they should be 0 */
1703 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1704 lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
1705 lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
1706 {
1707 lpServiceStatus->dwWaitHint = 0;
1708 lpServiceStatus->dwCheckPoint = 0;
1709 }
1710
1711 /* Lock the service database exclusively */
1712 ScmLockDatabaseExclusive();
1713
1714 /* Save the current service state */
1715 dwPreviousState = lpService->Status.dwCurrentState;
1716
1717 /* Save the current service type */
1718 dwPreviousType = lpService->Status.dwServiceType;
1719
1720 /* Update the service status */
1721 RtlCopyMemory(&lpService->Status,
1722 lpServiceStatus,
1723 sizeof(SERVICE_STATUS));
1724
1725 /* Restore the previous service type */
1726 lpService->Status.dwServiceType = dwPreviousType;
1727
1728 /* Unlock the service database */
1729 ScmUnlockDatabase();
1730
1731 if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
1732 (dwPreviousState != SERVICE_STOPPED) &&
1733 (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS))
1734 {
1735 /* Log a failed service stop */
1736 swprintf(szLogBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode);
1737 lpLogStrings[0] = lpService->lpDisplayName;
1738 lpLogStrings[1] = szLogBuffer;
1739
1740 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED,
1741 EVENTLOG_ERROR_TYPE,
1742 2,
1743 lpLogStrings);
1744 }
1745 else if (lpServiceStatus->dwCurrentState != dwPreviousState &&
1746 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1747 lpServiceStatus->dwCurrentState == SERVICE_RUNNING ||
1748 lpServiceStatus->dwCurrentState == SERVICE_PAUSED))
1749 {
1750 /* Log a successful service status change */
1751 switch(lpServiceStatus->dwCurrentState)
1752 {
1753 case SERVICE_STOPPED:
1754 uID = IDS_SERVICE_STOPPED;
1755 break;
1756
1757 case SERVICE_RUNNING:
1758 uID = IDS_SERVICE_RUNNING;
1759 break;
1760
1761 case SERVICE_PAUSED:
1762 uID = IDS_SERVICE_PAUSED;
1763 break;
1764 }
1765
1766 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, 80);
1767 lpLogStrings[0] = lpService->lpDisplayName;
1768 lpLogStrings[1] = szLogBuffer;
1769
1770 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS,
1771 EVENTLOG_INFORMATION_TYPE,
1772 2,
1773 lpLogStrings);
1774 }
1775
1776 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1777 DPRINT("RSetServiceStatus() done\n");
1778
1779 return ERROR_SUCCESS;
1780 }
1781
1782
1783 /* Function 8 */
1784 DWORD
1785 WINAPI
1786 RUnlockServiceDatabase(
1787 LPSC_RPC_LOCK Lock)
1788 {
1789 DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1790 return ScmReleaseServiceStartLock(Lock);
1791 }
1792
1793
1794 /* Function 9 */
1795 DWORD
1796 WINAPI
1797 RNotifyBootConfigStatus(
1798 SVCCTL_HANDLEW lpMachineName,
1799 DWORD BootAcceptable)
1800 {
1801 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1802 return ERROR_SUCCESS;
1803
1804 // UNIMPLEMENTED;
1805 // return ERROR_CALL_NOT_IMPLEMENTED;
1806 }
1807
1808
1809 /* Function 10 */
1810 DWORD
1811 WINAPI
1812 RI_ScSetServiceBitsW(
1813 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1814 DWORD dwServiceBits,
1815 int bSetBitsOn,
1816 int bUpdateImmediately,
1817 wchar_t *lpString)
1818 {
1819 UNIMPLEMENTED;
1820 return ERROR_CALL_NOT_IMPLEMENTED;
1821 }
1822
1823
1824 /* Function 11 */
1825 DWORD
1826 WINAPI
1827 RChangeServiceConfigW(
1828 SC_RPC_HANDLE hService,
1829 DWORD dwServiceType,
1830 DWORD dwStartType,
1831 DWORD dwErrorControl,
1832 LPWSTR lpBinaryPathName,
1833 LPWSTR lpLoadOrderGroup,
1834 LPDWORD lpdwTagId,
1835 LPBYTE lpDependencies,
1836 DWORD dwDependSize,
1837 LPWSTR lpServiceStartName,
1838 LPBYTE lpPassword,
1839 DWORD dwPwSize,
1840 LPWSTR lpDisplayName)
1841 {
1842 DWORD dwError = ERROR_SUCCESS;
1843 PSERVICE_HANDLE hSvc;
1844 PSERVICE lpService = NULL;
1845 HKEY hServiceKey = NULL;
1846 LPWSTR lpDisplayNameW = NULL;
1847 LPWSTR lpImagePathW = NULL;
1848
1849 DPRINT("RChangeServiceConfigW() called\n");
1850 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
1851 DPRINT("dwStartType = %lu\n", dwStartType);
1852 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1853 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1854 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1855 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1856
1857 if (ScmShutdown)
1858 return ERROR_SHUTDOWN_IN_PROGRESS;
1859
1860 hSvc = ScmGetServiceFromHandle(hService);
1861 if (hSvc == NULL)
1862 {
1863 DPRINT1("Invalid service handle!\n");
1864 return ERROR_INVALID_HANDLE;
1865 }
1866
1867 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1868 SERVICE_CHANGE_CONFIG))
1869 {
1870 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1871 return ERROR_ACCESS_DENIED;
1872 }
1873
1874 /* Check for invalid service type value */
1875 if ((dwServiceType != SERVICE_NO_CHANGE) &&
1876 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
1877 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
1878 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
1879 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
1880 return ERROR_INVALID_PARAMETER;
1881
1882 /* Check for invalid start type value */
1883 if ((dwStartType != SERVICE_NO_CHANGE) &&
1884 (dwStartType != SERVICE_BOOT_START) &&
1885 (dwStartType != SERVICE_SYSTEM_START) &&
1886 (dwStartType != SERVICE_AUTO_START) &&
1887 (dwStartType != SERVICE_DEMAND_START) &&
1888 (dwStartType != SERVICE_DISABLED))
1889 return ERROR_INVALID_PARAMETER;
1890
1891 /* Only drivers can be boot start or system start services */
1892 if ((dwStartType == SERVICE_BOOT_START) ||
1893 (dwStartType == SERVICE_SYSTEM_START))
1894 {
1895 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
1896 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
1897 return ERROR_INVALID_PARAMETER;
1898 }
1899
1900 /* Check for invalid error control value */
1901 if ((dwErrorControl != SERVICE_NO_CHANGE) &&
1902 (dwErrorControl != SERVICE_ERROR_IGNORE) &&
1903 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
1904 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
1905 (dwErrorControl != SERVICE_ERROR_CRITICAL))
1906 return ERROR_INVALID_PARAMETER;
1907
1908 lpService = hSvc->ServiceEntry;
1909 if (lpService == NULL)
1910 {
1911 DPRINT("lpService == NULL!\n");
1912 return ERROR_INVALID_HANDLE;
1913 }
1914
1915 /* Lock the service database exclusively */
1916 ScmLockDatabaseExclusive();
1917
1918 if (lpService->bDeleted)
1919 {
1920 DPRINT("The service has already been marked for delete!\n");
1921 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1922 goto done;
1923 }
1924
1925 /* Open the service key */
1926 dwError = ScmOpenServiceKey(lpService->szServiceName,
1927 KEY_SET_VALUE,
1928 &hServiceKey);
1929 if (dwError != ERROR_SUCCESS)
1930 goto done;
1931
1932 /* Write service data to the registry */
1933 /* Set the display name */
1934 if (lpDisplayName != NULL && *lpDisplayName != 0)
1935 {
1936 RegSetValueExW(hServiceKey,
1937 L"DisplayName",
1938 0,
1939 REG_SZ,
1940 (LPBYTE)lpDisplayName,
1941 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
1942
1943 /* Update the display name */
1944 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
1945 HEAP_ZERO_MEMORY,
1946 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1947 if (lpDisplayNameW == NULL)
1948 {
1949 dwError = ERROR_NOT_ENOUGH_MEMORY;
1950 goto done;
1951 }
1952
1953 wcscpy(lpDisplayNameW, lpDisplayName);
1954 if (lpService->lpDisplayName != lpService->lpServiceName)
1955 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1956
1957 lpService->lpDisplayName = lpDisplayNameW;
1958 }
1959
1960 if (dwServiceType != SERVICE_NO_CHANGE)
1961 {
1962 /* Set the service type */
1963 dwError = RegSetValueExW(hServiceKey,
1964 L"Type",
1965 0,
1966 REG_DWORD,
1967 (LPBYTE)&dwServiceType,
1968 sizeof(DWORD));
1969 if (dwError != ERROR_SUCCESS)
1970 goto done;
1971
1972 lpService->Status.dwServiceType = dwServiceType;
1973 }
1974
1975 if (dwStartType != SERVICE_NO_CHANGE)
1976 {
1977 /* Set the start value */
1978 dwError = RegSetValueExW(hServiceKey,
1979 L"Start",
1980 0,
1981 REG_DWORD,
1982 (LPBYTE)&dwStartType,
1983 sizeof(DWORD));
1984 if (dwError != ERROR_SUCCESS)
1985 goto done;
1986
1987 lpService->dwStartType = dwStartType;
1988 }
1989
1990 if (dwErrorControl != SERVICE_NO_CHANGE)
1991 {
1992 /* Set the error control value */
1993 dwError = RegSetValueExW(hServiceKey,
1994 L"ErrorControl",
1995 0,
1996 REG_DWORD,
1997 (LPBYTE)&dwErrorControl,
1998 sizeof(DWORD));
1999 if (dwError != ERROR_SUCCESS)
2000 goto done;
2001
2002 lpService->dwErrorControl = dwErrorControl;
2003 }
2004
2005 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2006 {
2007 /* Set the image path */
2008 lpImagePathW = lpBinaryPathName;
2009
2010 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
2011 {
2012 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
2013 lpBinaryPathName,
2014 &lpImagePathW);
2015
2016 if (dwError != ERROR_SUCCESS)
2017 goto done;
2018 }
2019
2020 dwError = RegSetValueExW(hServiceKey,
2021 L"ImagePath",
2022 0,
2023 REG_EXPAND_SZ,
2024 (LPBYTE)lpImagePathW,
2025 (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
2026
2027 if (lpImagePathW != lpBinaryPathName)
2028 HeapFree(GetProcessHeap(), 0, lpImagePathW);
2029
2030 if (dwError != ERROR_SUCCESS)
2031 goto done;
2032 }
2033
2034 /* Set the group name */
2035 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2036 {
2037 dwError = RegSetValueExW(hServiceKey,
2038 L"Group",
2039 0,
2040 REG_SZ,
2041 (LPBYTE)lpLoadOrderGroup,
2042 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2043 if (dwError != ERROR_SUCCESS)
2044 goto done;
2045
2046 dwError = ScmSetServiceGroup(lpService,
2047 lpLoadOrderGroup);
2048 if (dwError != ERROR_SUCCESS)
2049 goto done;
2050 }
2051
2052 /* Set the tag */
2053 if (lpdwTagId != NULL)
2054 {
2055 dwError = ScmAssignNewTag(lpService);
2056 if (dwError != ERROR_SUCCESS)
2057 goto done;
2058
2059 dwError = RegSetValueExW(hServiceKey,
2060 L"Tag",
2061 0,
2062 REG_DWORD,
2063 (LPBYTE)&lpService->dwTag,
2064 sizeof(DWORD));
2065 if (dwError != ERROR_SUCCESS)
2066 goto done;
2067
2068 *lpdwTagId = lpService->dwTag;
2069 }
2070
2071 /* Write dependencies */
2072 if (lpDependencies != NULL && *lpDependencies != 0)
2073 {
2074 dwError = ScmWriteDependencies(hServiceKey,
2075 (LPWSTR)lpDependencies,
2076 dwDependSize);
2077 if (dwError != ERROR_SUCCESS)
2078 goto done;
2079 }
2080
2081 if (lpPassword != NULL)
2082 {
2083 if (wcslen((LPWSTR)lpPassword) != 0)
2084 {
2085 /* FIXME: Decrypt the password */
2086
2087 /* Write the password */
2088 dwError = ScmSetServicePassword(lpService->szServiceName,
2089 (LPCWSTR)lpPassword);
2090 if (dwError != ERROR_SUCCESS)
2091 goto done;
2092 }
2093 else
2094 {
2095 /* Delete the password */
2096 dwError = ScmSetServicePassword(lpService->szServiceName,
2097 NULL);
2098 if (dwError == ERROR_FILE_NOT_FOUND)
2099 dwError = ERROR_SUCCESS;
2100
2101 if (dwError != ERROR_SUCCESS)
2102 goto done;
2103 }
2104 }
2105
2106 done:
2107 if (hServiceKey != NULL)
2108 RegCloseKey(hServiceKey);
2109
2110 /* Unlock the service database */
2111 ScmUnlockDatabase();
2112
2113 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
2114
2115 return dwError;
2116 }
2117
2118
2119 /* Function 12 */
2120 DWORD
2121 WINAPI
2122 RCreateServiceW(
2123 SC_RPC_HANDLE hSCManager,
2124 LPCWSTR lpServiceName,
2125 LPCWSTR lpDisplayName,
2126 DWORD dwDesiredAccess,
2127 DWORD dwServiceType,
2128 DWORD dwStartType,
2129 DWORD dwErrorControl,
2130 LPCWSTR lpBinaryPathName,
2131 LPCWSTR lpLoadOrderGroup,
2132 LPDWORD lpdwTagId,
2133 LPBYTE lpDependencies,
2134 DWORD dwDependSize,
2135 LPCWSTR lpServiceStartName,
2136 LPBYTE lpPassword,
2137 DWORD dwPwSize,
2138 LPSC_RPC_HANDLE lpServiceHandle)
2139 {
2140 PMANAGER_HANDLE hManager;
2141 DWORD dwError = ERROR_SUCCESS;
2142 PSERVICE lpService = NULL;
2143 SC_HANDLE hServiceHandle = NULL;
2144 LPWSTR lpImagePath = NULL;
2145 HKEY hServiceKey = NULL;
2146 LPWSTR lpObjectName;
2147
2148 DPRINT("RCreateServiceW() called\n");
2149 DPRINT("lpServiceName = %S\n", lpServiceName);
2150 DPRINT("lpDisplayName = %S\n", lpDisplayName);
2151 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2152 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2153 DPRINT("dwStartType = %lu\n", dwStartType);
2154 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2155 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2156 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2157 DPRINT("lpdwTagId = %p\n", lpdwTagId);
2158
2159 if (ScmShutdown)
2160 return ERROR_SHUTDOWN_IN_PROGRESS;
2161
2162 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2163 if (hManager == NULL)
2164 {
2165 DPRINT1("Invalid service manager handle!\n");
2166 return ERROR_INVALID_HANDLE;
2167 }
2168
2169 /* Check access rights */
2170 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2171 SC_MANAGER_CREATE_SERVICE))
2172 {
2173 DPRINT("Insufficient access rights! 0x%lx\n",
2174 hManager->Handle.DesiredAccess);
2175 return ERROR_ACCESS_DENIED;
2176 }
2177
2178 if (wcslen(lpServiceName) == 0)
2179 {
2180 return ERROR_INVALID_NAME;
2181 }
2182
2183 if (wcslen(lpBinaryPathName) == 0)
2184 {
2185 return ERROR_INVALID_PARAMETER;
2186 }
2187
2188 /* Check for invalid service type value */
2189 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2190 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2191 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2192 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
2193 return ERROR_INVALID_PARAMETER;
2194
2195 /* Check for invalid start type value */
2196 if ((dwStartType != SERVICE_BOOT_START) &&
2197 (dwStartType != SERVICE_SYSTEM_START) &&
2198 (dwStartType != SERVICE_AUTO_START) &&
2199 (dwStartType != SERVICE_DEMAND_START) &&
2200 (dwStartType != SERVICE_DISABLED))
2201 return ERROR_INVALID_PARAMETER;
2202
2203 /* Only drivers can be boot start or system start services */
2204 if ((dwStartType == SERVICE_BOOT_START) ||
2205 (dwStartType == SERVICE_SYSTEM_START))
2206 {
2207 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2208 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2209 return ERROR_INVALID_PARAMETER;
2210 }
2211
2212 /* Check for invalid error control value */
2213 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2214 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2215 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2216 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2217 return ERROR_INVALID_PARAMETER;
2218
2219 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2220 (lpServiceStartName))
2221 {
2222 /* We allow LocalSystem to run interactive. */
2223 if (wcsicmp(lpServiceStartName, L"LocalSystem"))
2224 {
2225 return ERROR_INVALID_PARAMETER;
2226 }
2227 }
2228
2229 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2230 {
2231 return ERROR_INVALID_PARAMETER;
2232 }
2233
2234 /* Lock the service database exclusively */
2235 ScmLockDatabaseExclusive();
2236
2237 lpService = ScmGetServiceEntryByName(lpServiceName);
2238 if (lpService)
2239 {
2240 /* Unlock the service database */
2241 ScmUnlockDatabase();
2242
2243 /* Check if it is marked for deletion */
2244 if (lpService->bDeleted)
2245 return ERROR_SERVICE_MARKED_FOR_DELETE;
2246
2247 /* Return Error exist */
2248 return ERROR_SERVICE_EXISTS;
2249 }
2250
2251 if (lpDisplayName != NULL &&
2252 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2253 {
2254 /* Unlock the service database */
2255 ScmUnlockDatabase();
2256
2257 return ERROR_DUPLICATE_SERVICE_NAME;
2258 }
2259
2260 if (dwServiceType & SERVICE_DRIVER)
2261 {
2262 dwError = ScmCanonDriverImagePath(dwStartType,
2263 lpBinaryPathName,
2264 &lpImagePath);
2265 if (dwError != ERROR_SUCCESS)
2266 goto done;
2267 }
2268 else
2269 {
2270 if (dwStartType == SERVICE_BOOT_START ||
2271 dwStartType == SERVICE_SYSTEM_START)
2272 {
2273 /* Unlock the service database */
2274 ScmUnlockDatabase();
2275
2276 return ERROR_INVALID_PARAMETER;
2277 }
2278 }
2279
2280 /* Allocate a new service entry */
2281 dwError = ScmCreateNewServiceRecord(lpServiceName,
2282 &lpService,
2283 dwServiceType,
2284 dwStartType);
2285 if (dwError != ERROR_SUCCESS)
2286 goto done;
2287
2288 /* Fill the new service entry */
2289 lpService->dwErrorControl = dwErrorControl;
2290
2291 /* Fill the display name */
2292 if (lpDisplayName != NULL &&
2293 *lpDisplayName != 0 &&
2294 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2295 {
2296 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2297 HEAP_ZERO_MEMORY,
2298 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2299 if (lpService->lpDisplayName == NULL)
2300 {
2301 dwError = ERROR_NOT_ENOUGH_MEMORY;
2302 goto done;
2303 }
2304 wcscpy(lpService->lpDisplayName, lpDisplayName);
2305 }
2306
2307 /* Assign the service to a group */
2308 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2309 {
2310 dwError = ScmSetServiceGroup(lpService,
2311 lpLoadOrderGroup);
2312 if (dwError != ERROR_SUCCESS)
2313 goto done;
2314 }
2315
2316 /* Assign a new tag */
2317 if (lpdwTagId != NULL)
2318 {
2319 dwError = ScmAssignNewTag(lpService);
2320 if (dwError != ERROR_SUCCESS)
2321 goto done;
2322 }
2323
2324 /* Assign the default security descriptor */
2325 if (dwServiceType & SERVICE_WIN32)
2326 {
2327 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
2328 if (dwError != ERROR_SUCCESS)
2329 goto done;
2330 }
2331
2332 /* Write service data to the registry */
2333 /* Create the service key */
2334 dwError = ScmCreateServiceKey(lpServiceName,
2335 KEY_WRITE,
2336 &hServiceKey);
2337 if (dwError != ERROR_SUCCESS)
2338 goto done;
2339
2340 /* Set the display name */
2341 if (lpDisplayName != NULL && *lpDisplayName != 0)
2342 {
2343 RegSetValueExW(hServiceKey,
2344 L"DisplayName",
2345 0,
2346 REG_SZ,
2347 (LPBYTE)lpDisplayName,
2348 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2349 }
2350
2351 /* Set the service type */
2352 dwError = RegSetValueExW(hServiceKey,
2353 L"Type",
2354 0,
2355 REG_DWORD,
2356 (LPBYTE)&dwServiceType,
2357 sizeof(DWORD));
2358 if (dwError != ERROR_SUCCESS)
2359 goto done;
2360
2361 /* Set the start value */
2362 dwError = RegSetValueExW(hServiceKey,
2363 L"Start",
2364 0,
2365 REG_DWORD,
2366 (LPBYTE)&dwStartType,
2367 sizeof(DWORD));
2368 if (dwError != ERROR_SUCCESS)
2369 goto done;
2370
2371 /* Set the error control value */
2372 dwError = RegSetValueExW(hServiceKey,
2373 L"ErrorControl",
2374 0,
2375 REG_DWORD,
2376 (LPBYTE)&dwErrorControl,
2377 sizeof(DWORD));
2378 if (dwError != ERROR_SUCCESS)
2379 goto done;
2380
2381 /* Set the image path */
2382 if (dwServiceType & SERVICE_WIN32)
2383 {
2384 dwError = RegSetValueExW(hServiceKey,
2385 L"ImagePath",
2386 0,
2387 REG_EXPAND_SZ,
2388 (LPBYTE)lpBinaryPathName,
2389 (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2390 if (dwError != ERROR_SUCCESS)
2391 goto done;
2392 }
2393 else if (dwServiceType & SERVICE_DRIVER)
2394 {
2395 dwError = RegSetValueExW(hServiceKey,
2396 L"ImagePath",
2397 0,
2398 REG_EXPAND_SZ,
2399 (LPBYTE)lpImagePath,
2400 (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2401 if (dwError != ERROR_SUCCESS)
2402 goto done;
2403 }
2404
2405 /* Set the group name */
2406 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2407 {
2408 dwError = RegSetValueExW(hServiceKey,
2409 L"Group",
2410 0,
2411 REG_SZ,
2412 (LPBYTE)lpLoadOrderGroup,
2413 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2414 if (dwError != ERROR_SUCCESS)
2415 goto done;
2416 }
2417
2418 /* Set the service tag */
2419 if (lpdwTagId != NULL)
2420 {
2421 dwError = RegSetValueExW(hServiceKey,
2422 L"Tag",
2423 0,
2424 REG_DWORD,
2425 (LPBYTE)&lpService->dwTag,
2426 sizeof(DWORD));
2427 if (dwError != ERROR_SUCCESS)
2428 goto done;
2429 }
2430
2431 /* Write dependencies */
2432 if (lpDependencies != NULL && *lpDependencies != 0)
2433 {
2434 dwError = ScmWriteDependencies(hServiceKey,
2435 (LPCWSTR)lpDependencies,
2436 dwDependSize);
2437 if (dwError != ERROR_SUCCESS)
2438 goto done;
2439 }
2440
2441 /* Start name and password are only used by Win32 services */
2442 if (dwServiceType & SERVICE_WIN32)
2443 {
2444 /* Write service start name */
2445 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2446 dwError = RegSetValueExW(hServiceKey,
2447 L"ObjectName",
2448 0,
2449 REG_SZ,
2450 (LPBYTE)lpObjectName,
2451 (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2452 if (dwError != ERROR_SUCCESS)
2453 goto done;
2454
2455 if (lpPassword != NULL && wcslen((LPWSTR)lpPassword) != 0)
2456 {
2457 /* FIXME: Decrypt the password */
2458
2459 /* Write the password */
2460 dwError = ScmSetServicePassword(lpServiceName,
2461 (LPCWSTR)lpPassword);
2462 if (dwError != ERROR_SUCCESS)
2463 goto done;
2464 }
2465
2466 DPRINT1("\n");
2467 /* Write the security descriptor */
2468 dwError = ScmWriteSecurityDescriptor(hServiceKey,
2469 lpService->pSecurityDescriptor);
2470 if (dwError != ERROR_SUCCESS)
2471 goto done;
2472 }
2473
2474 dwError = ScmCreateServiceHandle(lpService,
2475 &hServiceHandle);
2476 if (dwError != ERROR_SUCCESS)
2477 goto done;
2478
2479 dwError = ScmCheckAccess(hServiceHandle,
2480 dwDesiredAccess);
2481 if (dwError != ERROR_SUCCESS)
2482 goto done;
2483
2484 lpService->dwRefCount = 1;
2485 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2486
2487 done:
2488 /* Unlock the service database */
2489 ScmUnlockDatabase();
2490
2491 if (hServiceKey != NULL)
2492 RegCloseKey(hServiceKey);
2493
2494 if (dwError == ERROR_SUCCESS)
2495 {
2496 DPRINT("hService %p\n", hServiceHandle);
2497 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2498
2499 if (lpdwTagId != NULL)
2500 *lpdwTagId = lpService->dwTag;
2501 }
2502 else
2503 {
2504 if (lpService != NULL &&
2505 lpService->lpServiceName != NULL)
2506 {
2507 /* Release the display name buffer */
2508 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2509 }
2510
2511 if (hServiceHandle)
2512 {
2513 /* Remove the service handle */
2514 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2515 }
2516
2517 if (lpService != NULL)
2518 {
2519 /* FIXME: remove the service entry */
2520 }
2521 }
2522
2523 if (lpImagePath != NULL)
2524 HeapFree(GetProcessHeap(), 0, lpImagePath);
2525
2526 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2527
2528 return dwError;
2529 }
2530
2531
2532 /* Function 13 */
2533 DWORD
2534 WINAPI
2535 REnumDependentServicesW(
2536 SC_RPC_HANDLE hService,
2537 DWORD dwServiceState,
2538 LPBYTE lpServices,
2539 DWORD cbBufSize,
2540 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2541 LPBOUNDED_DWORD_256K lpServicesReturned)
2542 {
2543 DWORD dwError = ERROR_SUCCESS;
2544 DWORD dwServicesReturned = 0;
2545 DWORD dwServiceCount;
2546 HKEY hServicesKey = NULL;
2547 PSERVICE_HANDLE hSvc;
2548 PSERVICE lpService = NULL;
2549 PSERVICE *lpServicesArray = NULL;
2550 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2551 LPWSTR lpStr;
2552
2553 *pcbBytesNeeded = 0;
2554 *lpServicesReturned = 0;
2555
2556 DPRINT("REnumDependentServicesW() called\n");
2557
2558 hSvc = ScmGetServiceFromHandle(hService);
2559 if (hSvc == NULL)
2560 {
2561 DPRINT1("Invalid service handle!\n");
2562 return ERROR_INVALID_HANDLE;
2563 }
2564
2565 lpService = hSvc->ServiceEntry;
2566
2567 /* Check access rights */
2568 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2569 SC_MANAGER_ENUMERATE_SERVICE))
2570 {
2571 DPRINT("Insufficient access rights! 0x%lx\n",
2572 hSvc->Handle.DesiredAccess);
2573 return ERROR_ACCESS_DENIED;
2574 }
2575
2576 /* Open the Services Reg key */
2577 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2578 L"System\\CurrentControlSet\\Services",
2579 0,
2580 KEY_READ,
2581 &hServicesKey);
2582 if (dwError != ERROR_SUCCESS)
2583 return dwError;
2584
2585 /* First determine the bytes needed and get the number of dependent services */
2586 dwError = Int_EnumDependentServicesW(hServicesKey,
2587 lpService,
2588 dwServiceState,
2589 NULL,
2590 pcbBytesNeeded,
2591 &dwServicesReturned);
2592 if (dwError != ERROR_SUCCESS)
2593 goto Done;
2594
2595 /* If buffer size is less than the bytes needed or pointer is null */
2596 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2597 {
2598 dwError = ERROR_MORE_DATA;
2599 goto Done;
2600 }
2601
2602 /* Allocate memory for array of service pointers */
2603 lpServicesArray = HeapAlloc(GetProcessHeap(),
2604 HEAP_ZERO_MEMORY,
2605 (dwServicesReturned + 1) * sizeof(PSERVICE));
2606 if (!lpServicesArray)
2607 {
2608 DPRINT1("Could not allocate a buffer!!\n");
2609 dwError = ERROR_NOT_ENOUGH_MEMORY;
2610 goto Done;
2611 }
2612
2613 dwServicesReturned = 0;
2614 *pcbBytesNeeded = 0;
2615
2616 dwError = Int_EnumDependentServicesW(hServicesKey,
2617 lpService,
2618 dwServiceState,
2619 lpServicesArray,
2620 pcbBytesNeeded,
2621 &dwServicesReturned);
2622 if (dwError != ERROR_SUCCESS)
2623 {
2624 goto Done;
2625 }
2626
2627 lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2628 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2629
2630 /* Copy EnumDepenedentService to Buffer */
2631 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2632 {
2633 lpService = lpServicesArray[dwServiceCount];
2634
2635 /* Copy status info */
2636 memcpy(&lpServicesPtr->ServiceStatus,
2637 &lpService->Status,
2638 sizeof(SERVICE_STATUS));
2639
2640 /* Copy display name */
2641 wcscpy(lpStr, lpService->lpDisplayName);
2642 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2643 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2644
2645 /* Copy service name */
2646 wcscpy(lpStr, lpService->lpServiceName);
2647 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2648 lpStr += (wcslen(lpService->lpServiceName) + 1);
2649
2650 lpServicesPtr++;
2651 }
2652
2653 *lpServicesReturned = dwServicesReturned;
2654
2655 Done:
2656 if (lpServicesArray != NULL)
2657 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2658
2659 RegCloseKey(hServicesKey);
2660
2661 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2662
2663 return dwError;
2664 }
2665
2666
2667 /* Function 14 */
2668 DWORD
2669 WINAPI
2670 REnumServicesStatusW(
2671 SC_RPC_HANDLE hSCManager,
2672 DWORD dwServiceType,
2673 DWORD dwServiceState,
2674 LPBYTE lpBuffer,
2675 DWORD dwBufSize,
2676 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2677 LPBOUNDED_DWORD_256K lpServicesReturned,
2678 LPBOUNDED_DWORD_256K lpResumeHandle)
2679 {
2680 /* Enumerate all the services, not regarding of their group */
2681 return REnumServiceGroupW(hSCManager,
2682 dwServiceType,
2683 dwServiceState,
2684 lpBuffer,
2685 dwBufSize,
2686 pcbBytesNeeded,
2687 lpServicesReturned,
2688 lpResumeHandle,
2689 NULL);
2690 }
2691
2692
2693 /* Function 15 */
2694 DWORD
2695 WINAPI
2696 ROpenSCManagerW(
2697 LPWSTR lpMachineName,
2698 LPWSTR lpDatabaseName,
2699 DWORD dwDesiredAccess,
2700 LPSC_RPC_HANDLE lpScHandle)
2701 {
2702 DWORD dwError;
2703 SC_HANDLE hHandle;
2704
2705 DPRINT("ROpenSCManagerW() called\n");
2706 DPRINT("lpMachineName = %p\n", lpMachineName);
2707 DPRINT("lpMachineName: %S\n", lpMachineName);
2708 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2709 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2710 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2711
2712 if (ScmShutdown)
2713 return ERROR_SHUTDOWN_IN_PROGRESS;
2714
2715 if (!lpScHandle)
2716 return ERROR_INVALID_PARAMETER;
2717
2718 dwError = ScmCreateManagerHandle(lpDatabaseName,
2719 &hHandle);
2720 if (dwError != ERROR_SUCCESS)
2721 {
2722 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2723 return dwError;
2724 }
2725
2726 /* Check the desired access */
2727 dwError = ScmCheckAccess(hHandle,
2728 dwDesiredAccess | SC_MANAGER_CONNECT);
2729 if (dwError != ERROR_SUCCESS)
2730 {
2731 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2732 HeapFree(GetProcessHeap(), 0, hHandle);
2733 return dwError;
2734 }
2735
2736 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2737 DPRINT("*hScm = %p\n", *lpScHandle);
2738
2739 DPRINT("ROpenSCManagerW() done\n");
2740
2741 return ERROR_SUCCESS;
2742 }
2743
2744
2745 /* Function 16 */
2746 DWORD
2747 WINAPI
2748 ROpenServiceW(
2749 SC_RPC_HANDLE hSCManager,
2750 LPWSTR lpServiceName,
2751 DWORD dwDesiredAccess,
2752 LPSC_RPC_HANDLE lpServiceHandle)
2753 {
2754 PSERVICE lpService;
2755 PMANAGER_HANDLE hManager;
2756 SC_HANDLE hHandle;
2757 DWORD dwError = ERROR_SUCCESS;
2758
2759 DPRINT("ROpenServiceW() called\n");
2760 DPRINT("hSCManager = %p\n", hSCManager);
2761 DPRINT("lpServiceName = %p\n", lpServiceName);
2762 DPRINT("lpServiceName: %S\n", lpServiceName);
2763 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2764
2765 if (ScmShutdown)
2766 return ERROR_SHUTDOWN_IN_PROGRESS;
2767
2768 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2769 if (hManager == NULL)
2770 {
2771 DPRINT1("Invalid service manager handle!\n");
2772 return ERROR_INVALID_HANDLE;
2773 }
2774
2775 if (!lpServiceHandle)
2776 return ERROR_INVALID_PARAMETER;
2777
2778 if (!lpServiceName)
2779 return ERROR_INVALID_ADDRESS;
2780
2781 /* Lock the service database exclusive */
2782 ScmLockDatabaseExclusive();
2783
2784 /* Get service database entry */
2785 lpService = ScmGetServiceEntryByName(lpServiceName);
2786 if (lpService == NULL)
2787 {
2788 DPRINT("Could not find a service!\n");
2789 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2790 goto Done;
2791 }
2792
2793 /* Create a service handle */
2794 dwError = ScmCreateServiceHandle(lpService,
2795 &hHandle);
2796 if (dwError != ERROR_SUCCESS)
2797 {
2798 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2799 goto Done;
2800 }
2801
2802 /* Check the desired access */
2803 dwError = ScmCheckAccess(hHandle,
2804 dwDesiredAccess);
2805 if (dwError != ERROR_SUCCESS)
2806 {
2807 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2808 HeapFree(GetProcessHeap(), 0, hHandle);
2809 goto Done;
2810 }
2811
2812 lpService->dwRefCount++;
2813 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2814
2815 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2816 DPRINT("*hService = %p\n", *lpServiceHandle);
2817
2818 Done:
2819 /* Unlock the service database */
2820 ScmUnlockDatabase();
2821
2822 DPRINT("ROpenServiceW() done\n");
2823
2824 return dwError;
2825 }
2826
2827
2828 /* Function 17 */
2829 DWORD
2830 WINAPI
2831 RQueryServiceConfigW(
2832 SC_RPC_HANDLE hService,
2833 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2834 DWORD cbBufSize,
2835 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2836 {
2837 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2838 DWORD dwError = ERROR_SUCCESS;
2839 PSERVICE_HANDLE hSvc;
2840 PSERVICE lpService = NULL;
2841 HKEY hServiceKey = NULL;
2842 LPWSTR lpImagePath = NULL;
2843 LPWSTR lpServiceStartName = NULL;
2844 LPWSTR lpDependencies = NULL;
2845 DWORD dwDependenciesLength = 0;
2846 DWORD dwRequiredSize;
2847 WCHAR lpEmptyString[] = {0,0};
2848 LPWSTR lpStr;
2849
2850 DPRINT("RQueryServiceConfigW() called\n");
2851
2852 if (ScmShutdown)
2853 return ERROR_SHUTDOWN_IN_PROGRESS;
2854
2855 hSvc = ScmGetServiceFromHandle(hService);
2856 if (hSvc == NULL)
2857 {
2858 DPRINT1("Invalid service handle!\n");
2859 return ERROR_INVALID_HANDLE;
2860 }
2861
2862 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2863 SERVICE_QUERY_CONFIG))
2864 {
2865 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2866 return ERROR_ACCESS_DENIED;
2867 }
2868
2869 lpService = hSvc->ServiceEntry;
2870 if (lpService == NULL)
2871 {
2872 DPRINT("lpService == NULL!\n");
2873 return ERROR_INVALID_HANDLE;
2874 }
2875
2876 /* Lock the service database shared */
2877 ScmLockDatabaseShared();
2878
2879 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2880 KEY_READ,
2881 &hServiceKey);
2882 if (dwError != ERROR_SUCCESS)
2883 goto Done;
2884
2885 /* Read the image path */
2886 dwError = ScmReadString(hServiceKey,
2887 L"ImagePath",
2888 &lpImagePath);
2889 if (dwError != ERROR_SUCCESS)
2890 goto Done;
2891
2892 /* Read the service start name */
2893 ScmReadString(hServiceKey,
2894 L"ObjectName",
2895 &lpServiceStartName);
2896
2897 /* Read the dependencies */
2898 ScmReadDependencies(hServiceKey,
2899 &lpDependencies,
2900 &dwDependenciesLength);
2901
2902 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2903
2904 if (lpImagePath != NULL)
2905 dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2906 else
2907 dwRequiredSize += 2 * sizeof(WCHAR);
2908
2909 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2910 dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2911 else
2912 dwRequiredSize += 2 * sizeof(WCHAR);
2913
2914 if (lpDependencies != NULL)
2915 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2916 else
2917 dwRequiredSize += 2 * sizeof(WCHAR);
2918
2919 if (lpServiceStartName != NULL)
2920 dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2921 else
2922 dwRequiredSize += 2 * sizeof(WCHAR);
2923
2924 if (lpService->lpDisplayName != NULL)
2925 dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2926 else
2927 dwRequiredSize += 2 * sizeof(WCHAR);
2928
2929 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2930 {
2931 dwError = ERROR_INSUFFICIENT_BUFFER;
2932 }
2933 else
2934 {
2935 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
2936 lpServiceConfig->dwStartType = lpService->dwStartType;
2937 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
2938 lpServiceConfig->dwTagId = lpService->dwTag;
2939
2940 lpStr = (LPWSTR)(lpServiceConfig + 1);
2941
2942 /* Append the image path */
2943 if (lpImagePath != NULL)
2944 {
2945 wcscpy(lpStr, lpImagePath);
2946 }
2947 else
2948 {
2949 wcscpy(lpStr, lpEmptyString);
2950 }
2951
2952 lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2953 lpStr += (wcslen(lpStr) + 1);
2954
2955 /* Append the group name */
2956 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2957 {
2958 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2959 }
2960 else
2961 {
2962 wcscpy(lpStr, lpEmptyString);
2963 }
2964
2965 lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2966 lpStr += (wcslen(lpStr) + 1);
2967
2968 /* Append Dependencies */
2969 if (lpDependencies != NULL)
2970 {
2971 memcpy(lpStr,
2972 lpDependencies,
2973 dwDependenciesLength * sizeof(WCHAR));
2974 }
2975 else
2976 {
2977 wcscpy(lpStr, lpEmptyString);
2978 }
2979
2980 lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2981 if (lpDependencies != NULL)
2982 lpStr += dwDependenciesLength;
2983 else
2984 lpStr += (wcslen(lpStr) + 1);
2985
2986 /* Append the service start name */
2987 if (lpServiceStartName != NULL)
2988 {
2989 wcscpy(lpStr, lpServiceStartName);
2990 }
2991 else
2992 {
2993 wcscpy(lpStr, lpEmptyString);
2994 }
2995
2996 lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2997 lpStr += (wcslen(lpStr) + 1);
2998
2999 /* Append the display name */
3000 if (lpService->lpDisplayName != NULL)
3001 {
3002 wcscpy(lpStr, lpService->lpDisplayName);
3003 }
3004 else
3005 {
3006 wcscpy(lpStr, lpEmptyString);
3007 }
3008
3009 lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3010 }
3011
3012 if (pcbBytesNeeded != NULL)
3013 *pcbBytesNeeded = dwRequiredSize;
3014
3015 Done:
3016 /* Unlock the service database */
3017 ScmUnlockDatabase();
3018
3019 if (lpImagePath != NULL)
3020 HeapFree(GetProcessHeap(), 0, lpImagePath);
3021
3022 if (lpServiceStartName != NULL)
3023 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3024
3025 if (lpDependencies != NULL)
3026 HeapFree(GetProcessHeap(), 0, lpDependencies);
3027
3028 if (hServiceKey != NULL)
3029 RegCloseKey(hServiceKey);
3030
3031 DPRINT("RQueryServiceConfigW() done\n");
3032
3033 return dwError;
3034 }
3035
3036
3037 /* Function 18 */
3038 DWORD
3039 WINAPI
3040 RQueryServiceLockStatusW(
3041 SC_RPC_HANDLE hSCManager,
3042 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3043 DWORD cbBufSize,
3044 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3045 {
3046 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf;
3047 PMANAGER_HANDLE hMgr;
3048 DWORD dwRequiredSize;
3049
3050 if (!lpLockStatus || !pcbBytesNeeded)
3051 return ERROR_INVALID_PARAMETER;
3052
3053 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
3054 if (hMgr == NULL)
3055 {
3056 DPRINT1("Invalid service manager handle!\n");
3057 return ERROR_INVALID_HANDLE;
3058 }
3059
3060 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
3061 SC_MANAGER_QUERY_LOCK_STATUS))
3062 {
3063 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
3064 return ERROR_ACCESS_DENIED;
3065 }
3066
3067 /* FIXME: we need to compute instead the real length of the owner name */
3068 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
3069 *pcbBytesNeeded = dwRequiredSize;
3070
3071 if (cbBufSize < dwRequiredSize)
3072 return ERROR_INSUFFICIENT_BUFFER;
3073
3074 ScmQueryServiceLockStatusW(lpLockStatus);
3075
3076 return ERROR_SUCCESS;
3077 }
3078
3079
3080 /* Function 19 */
3081 DWORD
3082 WINAPI
3083 RStartServiceW(
3084 SC_RPC_HANDLE hService,
3085 DWORD argc,
3086 LPSTRING_PTRSW argv)
3087 {
3088 DWORD dwError = ERROR_SUCCESS;
3089 PSERVICE_HANDLE hSvc;
3090 PSERVICE lpService = NULL;
3091
3092 #ifndef NDEBUG
3093 DWORD i;
3094
3095 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3096 DPRINT(" argc: %lu\n", argc);
3097 if (argv != NULL)
3098 {
3099 for (i = 0; i < argc; i++)
3100 {
3101 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
3102 }
3103 }
3104 #endif
3105
3106 if (ScmShutdown)
3107 return ERROR_SHUTDOWN_IN_PROGRESS;
3108
3109 hSvc = ScmGetServiceFromHandle(hService);
3110 if (hSvc == NULL)
3111 {
3112 DPRINT1("Invalid service handle!\n");
3113 return ERROR_INVALID_HANDLE;
3114 }
3115
3116 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3117 SERVICE_START))
3118 {
3119 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3120 return ERROR_ACCESS_DENIED;
3121 }
3122
3123 lpService = hSvc->ServiceEntry;
3124 if (lpService == NULL)
3125 {
3126 DPRINT("lpService == NULL!\n");
3127 return ERROR_INVALID_HANDLE;
3128 }
3129
3130 if (lpService->dwStartType == SERVICE_DISABLED)
3131 return ERROR_SERVICE_DISABLED;
3132
3133 if (lpService->bDeleted)
3134 return ERROR_SERVICE_MARKED_FOR_DELETE;
3135
3136 /* Start the service */
3137 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3138
3139 return dwError;
3140 }
3141
3142
3143 /* Function 20 */
3144 DWORD
3145 WINAPI
3146 RGetServiceDisplayNameW(
3147 SC_RPC_HANDLE hSCManager,
3148 LPCWSTR lpServiceName,
3149 LPWSTR lpDisplayName,
3150 DWORD *lpcchBuffer)
3151 {
3152 // PMANAGER_HANDLE hManager;
3153 PSERVICE lpService;
3154 DWORD dwLength;
3155 DWORD dwError;
3156
3157 DPRINT("RGetServiceDisplayNameW() called\n");
3158 DPRINT("hSCManager = %p\n", hSCManager);
3159 DPRINT("lpServiceName: %S\n", lpServiceName);
3160 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3161 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3162
3163 // hManager = (PMANAGER_HANDLE)hSCManager;
3164 // if (hManager->Handle.Tag != MANAGER_TAG)
3165 // {
3166 // DPRINT("Invalid manager handle!\n");
3167 // return ERROR_INVALID_HANDLE;
3168 // }
3169
3170 /* Get service database entry */
3171 lpService = ScmGetServiceEntryByName(lpServiceName);
3172 if (lpService == NULL)
3173 {
3174 DPRINT("Could not find a service!\n");
3175
3176 /* If the service could not be found and lpcchBuffer is less than 2, windows
3177 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3178 if (*lpcchBuffer < 2)
3179 {
3180 *lpcchBuffer = 2;
3181 if (lpDisplayName != NULL)
3182 {
3183 *lpDisplayName = 0;
3184 }
3185 }
3186
3187 return ERROR_SERVICE_DOES_NOT_EXIST;
3188 }
3189
3190 if (!lpService->lpDisplayName)
3191 {
3192 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3193
3194 if (lpDisplayName != NULL &&
3195 *lpcchBuffer > dwLength)
3196 {
3197 wcscpy(lpDisplayName, lpService->lpServiceName);
3198 }
3199 }
3200 else
3201 {
3202 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
3203
3204 if (lpDisplayName != NULL &&
3205 *lpcchBuffer > dwLength)
3206 {
3207 wcscpy(lpDisplayName, lpService->lpDisplayName);
3208 }
3209 }
3210
3211 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3212
3213 *lpcchBuffer = dwLength;
3214
3215 return dwError;
3216 }
3217
3218
3219 /* Function 21 */
3220 DWORD
3221 WINAPI
3222 RGetServiceKeyNameW(
3223 SC_RPC_HANDLE hSCManager,
3224 LPCWSTR lpDisplayName,
3225 LPWSTR lpServiceName,
3226 DWORD *lpcchBuffer)
3227 {
3228 // PMANAGER_HANDLE hManager;
3229 PSERVICE lpService;
3230 DWORD dwLength;
3231 DWORD dwError;
3232
3233 DPRINT("RGetServiceKeyNameW() called\n");
3234 DPRINT("hSCManager = %p\n", hSCManager);
3235 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3236 DPRINT("lpServiceName: %p\n", lpServiceName);
3237 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3238
3239 // hManager = (PMANAGER_HANDLE)hSCManager;
3240 // if (hManager->Handle.Tag != MANAGER_TAG)
3241 // {
3242 // DPRINT("Invalid manager handle!\n");
3243 // return ERROR_INVALID_HANDLE;
3244 // }
3245
3246 /* Get service database entry */
3247 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3248 if (lpService == NULL)
3249 {
3250 DPRINT("Could not find a service!\n");
3251
3252 /* If the service could not be found and lpcchBuffer is less than 2, windows
3253 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3254 if (*lpcchBuffer < 2)
3255 {
3256 *lpcchBuffer = 2;
3257 if (lpServiceName != NULL)
3258 {
3259 *lpServiceName = 0;
3260 }
3261 }
3262
3263 return ERROR_SERVICE_DOES_NOT_EXIST;
3264 }
3265
3266 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3267
3268 if (lpServiceName != NULL &&
3269 *lpcchBuffer > dwLength)
3270 {
3271 wcscpy(lpServiceName, lpService->lpServiceName);
3272 *lpcchBuffer = dwLength;
3273 return ERROR_SUCCESS;
3274 }
3275
3276 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3277
3278 *lpcchBuffer = dwLength;
3279
3280 return dwError;
3281 }
3282
3283
3284 /* Function 22 */
3285 DWORD
3286 WINAPI
3287 RI_ScSetServiceBitsA(
3288 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3289 DWORD dwServiceBits,
3290 int bSetBitsOn,
3291 int bUpdateImmediately,
3292 char *lpString)
3293 {
3294 UNIMPLEMENTED;
3295 return ERROR_CALL_NOT_IMPLEMENTED;
3296 }
3297
3298
3299 /* Function 23 */
3300 DWORD
3301 WINAPI
3302 RChangeServiceConfigA(
3303 SC_RPC_HANDLE hService,
3304 DWORD dwServiceType,
3305 DWORD dwStartType,
3306 DWORD dwErrorControl,
3307 LPSTR lpBinaryPathName,
3308 LPSTR lpLoadOrderGroup,
3309 LPDWORD lpdwTagId,
3310 LPBYTE lpDependencies,
3311 DWORD dwDependSize,
3312 LPSTR lpServiceStartName,
3313 LPBYTE lpPassword,
3314 DWORD dwPwSize,
3315 LPSTR lpDisplayName)
3316 {
3317 DWORD dwError = ERROR_SUCCESS;
3318 PSERVICE_HANDLE hSvc;
3319 PSERVICE lpService = NULL;
3320 HKEY hServiceKey = NULL;
3321 LPWSTR lpDisplayNameW = NULL;
3322 LPWSTR lpBinaryPathNameW = NULL;
3323 LPWSTR lpCanonicalImagePathW = NULL;
3324 LPWSTR lpLoadOrderGroupW = NULL;
3325 LPWSTR lpDependenciesW = NULL;
3326
3327 DPRINT("RChangeServiceConfigA() called\n");
3328 DPRINT("dwServiceType = %lu\n", dwServiceType);
3329 DPRINT("dwStartType = %lu\n", dwStartType);
3330 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3331 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3332 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3333 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3334
3335 if (ScmShutdown)
3336 return ERROR_SHUTDOWN_IN_PROGRESS;
3337
3338 hSvc = ScmGetServiceFromHandle(hService);
3339 if (hSvc == NULL)
3340 {
3341 DPRINT1("Invalid service handle!\n");
3342 return ERROR_INVALID_HANDLE;
3343 }
3344
3345 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3346 SERVICE_CHANGE_CONFIG))
3347 {
3348 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3349 return ERROR_ACCESS_DENIED;
3350 }
3351
3352 lpService = hSvc->ServiceEntry;
3353 if (lpService == NULL)
3354 {
3355 DPRINT("lpService == NULL!\n");
3356 return ERROR_INVALID_HANDLE;
3357 }
3358
3359 /* Lock the service database exclusively */
3360 ScmLockDatabaseExclusive();
3361
3362 if (lpService->bDeleted)
3363 {
3364 DPRINT("The service has already been marked for delete!\n");
3365 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
3366 goto done;
3367 }
3368
3369 /* Open the service key */
3370 dwError = ScmOpenServiceKey(lpService->szServiceName,
3371 KEY_SET_VALUE,
3372 &hServiceKey);
3373 if (dwError != ERROR_SUCCESS)
3374 goto done;
3375
3376 /* Write service data to the registry */
3377
3378 if (lpDisplayName != NULL && *lpDisplayName != 0)
3379 {
3380 /* Set the display name */
3381 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3382 HEAP_ZERO_MEMORY,
3383 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3384 if (lpDisplayNameW == NULL)
3385 {
3386 dwError = ERROR_NOT_ENOUGH_MEMORY;
3387 goto done;
3388 }
3389
3390 MultiByteToWideChar(CP_ACP,
3391 0,
3392 lpDisplayName,
3393 -1,
3394 lpDisplayNameW,
3395 (int)(strlen(lpDisplayName) + 1));
3396
3397 RegSetValueExW(hServiceKey,
3398 L"DisplayName",
3399 0,
3400 REG_SZ,
3401 (LPBYTE)lpDisplayNameW,
3402 (DWORD)((wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR)));
3403
3404 /* Update lpService->lpDisplayName */
3405 if (lpService->lpDisplayName)
3406 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3407
3408 lpService->lpDisplayName = lpDisplayNameW;
3409 }
3410
3411 if (dwServiceType != SERVICE_NO_CHANGE)
3412 {
3413 /* Set the service type */
3414 dwError = RegSetValueExW(hServiceKey,
3415 L"Type",
3416 0,
3417 REG_DWORD,
3418 (LPBYTE)&dwServiceType,
3419 sizeof(DWORD));
3420 if (dwError != ERROR_SUCCESS)
3421 goto done;
3422
3423 lpService->Status.dwServiceType = dwServiceType;
3424 }
3425
3426 if (dwStartType != SERVICE_NO_CHANGE)
3427 {
3428 /* Set the start value */
3429 dwError = RegSetValueExW(hServiceKey,
3430 L"Start",
3431 0,
3432 REG_DWORD,
3433 (LPBYTE)&dwStartType,
3434 sizeof(DWORD));
3435 if (dwError != ERROR_SUCCESS)
3436 goto done;
3437
3438 lpService->dwStartType = dwStartType;
3439 }
3440
3441 if (dwErrorControl != SERVICE_NO_CHANGE)
3442 {
3443 /* Set the error control value */
3444 dwError = RegSetValueExW(hServiceKey,
3445 L"ErrorControl",
3446 0,
3447 REG_DWORD,
3448 (LPBYTE)&dwErrorControl,
3449 sizeof(DWORD));
3450 if (dwError != ERROR_SUCCESS)
3451 goto done;
3452
3453 lpService->dwErrorControl = dwErrorControl;
3454 }
3455
3456 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3457 {
3458 /* Set the image path */
3459 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
3460 HEAP_ZERO_MEMORY,
3461 (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
3462 if (lpBinaryPathNameW == NULL)
3463 {
3464 dwError = ERROR_NOT_ENOUGH_MEMORY;
3465 goto done;
3466 }
3467
3468 MultiByteToWideChar(CP_ACP,
3469 0,
3470 lpBinaryPathName,
3471 -1,
3472 lpBinaryPathNameW,
3473 (int)(strlen(lpBinaryPathName) + 1));
3474
3475 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
3476 {
3477 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
3478 lpBinaryPathNameW,
3479 &lpCanonicalImagePathW);
3480
3481 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3482
3483 if (dwError != ERROR_SUCCESS)
3484 goto done;
3485
3486 lpBinaryPathNameW = lpCanonicalImagePathW;
3487 }
3488
3489 dwError = RegSetValueExW(hServiceKey,
3490 L"ImagePath",
3491 0,
3492 REG_EXPAND_SZ,
3493 (LPBYTE)lpBinaryPathNameW,
3494 (DWORD)((wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR)));
3495
3496 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3497
3498 if (dwError != ERROR_SUCCESS)
3499 goto done;
3500 }
3501
3502 /* Set the group name */
3503 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3504 {
3505 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3506 HEAP_ZERO_MEMORY,
3507 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3508 if (lpLoadOrderGroupW == NULL)
3509 {
3510 dwError = ERROR_NOT_ENOUGH_MEMORY;
3511 goto done;
3512 }
3513
3514 MultiByteToWideChar(CP_ACP,
3515 0,
3516 lpLoadOrderGroup,
3517 -1,
3518 lpLoadOrderGroupW,
3519 (int)(strlen(lpLoadOrderGroup) + 1));
3520
3521 dwError = RegSetValueExW(hServiceKey,
3522 L"Group",
3523 0,
3524 REG_SZ,
3525 (LPBYTE)lpLoadOrderGroupW,
3526 (DWORD)((wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR)));
3527 if (dwError != ERROR_SUCCESS)
3528 {
3529 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3530 goto done;
3531 }
3532
3533 dwError = ScmSetServiceGroup(lpService,
3534 lpLoadOrderGroupW);
3535
3536 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3537
3538 if (dwError != ERROR_SUCCESS)
3539 goto done;
3540 }
3541
3542 if (lpdwTagId != NULL)
3543 {
3544 dwError = ScmAssignNewTag(lpService);
3545 if (dwError != ERROR_SUCCESS)
3546 goto done;
3547
3548 dwError = RegSetValueExW(hServiceKey,
3549 L"Tag",
3550 0,
3551 REG_DWORD,
3552 (LPBYTE)&lpService->dwTag,
3553 sizeof(DWORD));
3554 if (dwError != ERROR_SUCCESS)
3555 goto done;
3556
3557 *lpdwTagId = lpService->dwTag;
3558 }
3559
3560 /* Write dependencies */
3561 if (lpDependencies != NULL && *lpDependencies != 0)
3562 {
3563 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3564 HEAP_ZERO_MEMORY,
3565 (strlen((LPSTR)lpDependencies) + 1) * sizeof(WCHAR));
3566 if (lpDependenciesW == NULL)
3567 {
3568 dwError = ERROR_NOT_ENOUGH_MEMORY;
3569 goto done;
3570 }
3571
3572 MultiByteToWideChar(CP_ACP,
3573 0,
3574 (LPSTR)lpDependencies,
3575 dwDependSize,
3576 lpDependenciesW,
3577 (int)(strlen((LPSTR)lpDependencies) + 1));
3578
3579 dwError = ScmWriteDependencies(hServiceKey,
3580 (LPWSTR)lpDependenciesW,
3581 dwDependSize);
3582
3583 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3584
3585 if (dwError != ERROR_SUCCESS)
3586 goto done;
3587 }
3588
3589 if (lpPassword != NULL)
3590 {
3591 if (wcslen((LPWSTR)lpPassword) != 0)
3592 {
3593 /* FIXME: Decrypt the password */
3594
3595 /* Write the password */
3596 dwError = ScmSetServicePassword(lpService->szServiceName,
3597 (LPCWSTR)lpPassword);
3598 if (dwError != ERROR_SUCCESS)
3599 goto done;
3600 }
3601 else
3602 {
3603 /* Delete the password */
3604 dwError = ScmSetServicePassword(lpService->szServiceName,
3605 NULL);
3606 if (dwError == ERROR_FILE_NOT_FOUND)
3607 dwError = ERROR_SUCCESS;
3608
3609 if (dwError != ERROR_SUCCESS)
3610 goto done;
3611 }
3612 }
3613
3614 done:
3615 /* Unlock the service database */
3616 ScmUnlockDatabase();
3617
3618 if (hServiceKey != NULL)
3619 RegCloseKey(hServiceKey);
3620
3621 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3622
3623 return dwError;
3624 }
3625
3626
3627 /* Function 24 */
3628 DWORD
3629 WINAPI
3630 RCreateServiceA(
3631 SC_RPC_HANDLE hSCManager,
3632 LPSTR lpServiceName,
3633 LPSTR lpDisplayName,
3634 DWORD dwDesiredAccess,
3635 DWORD dwServiceType,
3636 DWORD dwStartType,
3637 DWORD dwErrorControl,
3638 LPSTR lpBinaryPathName,
3639 LPSTR lpLoadOrderGroup,
3640 LPDWORD lpdwTagId,
3641 LPBYTE lpDependencies,
3642 DWORD dwDependSize,
3643 LPSTR lpServiceStartName,
3644 LPBYTE lpPassword,
3645 DWORD dwPwSize,
3646 LPSC_RPC_HANDLE lpServiceHandle)
3647 {
3648 DWORD dwError = ERROR_SUCCESS;
3649 LPWSTR lpServiceNameW = NULL;
3650 LPWSTR lpDisplayNameW = NULL;
3651 LPWSTR lpBinaryPathNameW = NULL;
3652 LPWSTR lpLoadOrderGroupW = NULL;
3653 LPWSTR lpDependenciesW = NULL;
3654 LPWSTR lpServiceStartNameW = NULL;
3655 DWORD dwDependenciesLength = 0;
3656 SIZE_T cchLength;
3657 int len;
3658 LPCSTR lpStr;
3659
3660 if (lpServiceName)
3661 {
3662 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3663 lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3664 if (!lpServiceNameW)
3665 {
3666 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3667 goto cleanup;
3668 }
3669 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3670 }
3671
3672 if (lpDisplayName)
3673 {
3674 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3675 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3676 if (!lpDisplayNameW)
3677 {
3678 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3679 goto cleanup;
3680 }
3681 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3682 }
3683
3684 if (lpBinaryPathName)
3685 {
3686 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3687 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3688 if (!lpBinaryPathNameW)
3689 {
3690 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3691 goto cleanup;
3692 }
3693 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3694 }
3695
3696 if (lpLoadOrderGroup)
3697 {
3698 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3699 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3700 if (!lpLoadOrderGroupW)
3701 {
3702 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3703 goto cleanup;
3704 }
3705 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3706 }
3707
3708 if (lpDependencies)
3709 {
3710 lpStr = (LPCSTR)lpDependencies;
3711 while (*lpStr)
3712 {
3713 cchLength = strlen(lpStr) + 1;
3714 dwDependenciesLength += (DWORD)cchLength;
3715 lpStr = lpStr + cchLength;
3716 }
3717 dwDependenciesLength++;
3718
3719 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3720 if (!lpDependenciesW)
3721 {
3722 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3723 goto cleanup;
3724 }
3725 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3726 }
3727
3728 if (lpServiceStartName)
3729 {
3730 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3731 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3732 if (!lpServiceStartNameW)
3733 {
3734 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3735 goto cleanup;
3736 }
3737 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3738 }
3739
3740 dwError = RCreateServiceW(hSCManager,
3741 lpServiceNameW,
3742 lpDisplayNameW,
3743 dwDesiredAccess,
3744 dwServiceType,
3745 dwStartType,
3746 dwErrorControl,
3747 lpBinaryPathNameW,
3748 lpLoadOrderGroupW,
3749 lpdwTagId,
3750 (LPBYTE)lpDependenciesW,
3751 dwDependenciesLength,
3752 lpServiceStartNameW,
3753 lpPassword,
3754 dwPwSize,
3755 lpServiceHandle);
3756
3757 cleanup:
3758 if (lpServiceNameW !=NULL)
3759 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3760
3761 if (lpDisplayNameW != NULL)
3762 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3763
3764 if (lpBinaryPathNameW != NULL)
3765 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3766
3767 if (lpLoadOrderGroupW != NULL)
3768 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3769
3770 if (lpDependenciesW != NULL)
3771 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3772
3773 if (lpServiceStartNameW != NULL)
3774 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3775
3776 return dwError;
3777 }
3778
3779
3780 /* Function 25 */
3781 DWORD
3782 WINAPI
3783 REnumDependentServicesA(
3784 SC_RPC_HANDLE hService,
3785 DWORD dwServiceState,
3786 LPBYTE lpServices,
3787 DWORD cbBufSize,
3788 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3789 LPBOUNDED_DWORD_256K lpServicesReturned)
3790 {
3791 DWORD dwError = ERROR_SUCCESS;
3792 DWORD dwServicesReturned = 0;
3793 DWORD dwServiceCount;
3794 HKEY hServicesKey = NULL;
3795 PSERVICE_HANDLE hSvc;
3796 PSERVICE lpService = NULL;
3797 PSERVICE *lpServicesArray = NULL;
3798 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3799 LPSTR lpStr;
3800
3801 *pcbBytesNeeded = 0;
3802 *lpServicesReturned = 0;
3803
3804 DPRINT("REnumDependentServicesA() called\n");
3805
3806 hSvc = ScmGetServiceFromHandle(hService);
3807 if (hSvc == NULL)
3808 {
3809 DPRINT1("Invalid service handle!\n");
3810 return ERROR_INVALID_HANDLE;
3811 }
3812
3813 lpService = hSvc->ServiceEntry;
3814
3815 /* Check access rights */
3816 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3817 SC_MANAGER_ENUMERATE_SERVICE))
3818 {
3819 DPRINT("Insufficient access rights! 0x%lx\n",
3820 hSvc->Handle.DesiredAccess);
3821 return ERROR_ACCESS_DENIED;
3822 }
3823
3824 /* Open the Services Reg key */
3825 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3826 L"System\\CurrentControlSet\\Services",
3827 0,
3828 KEY_READ,
3829 &hServicesKey);
3830
3831 if (dwError != ERROR_SUCCESS)
3832 return dwError;
3833
3834 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3835 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3836 are the same for both. Verified in WINXP. */
3837
3838 /* First determine the bytes needed and get the number of dependent services*/
3839 dwError = Int_EnumDependentServicesW(hServicesKey,
3840 lpService,
3841 dwServiceState,
3842 NULL,
3843 pcbBytesNeeded,
3844 &dwServicesReturned);
3845 if (dwError != ERROR_SUCCESS)
3846 goto Done;
3847
3848 /* If buffer size is less than the bytes needed or pointer is null*/
3849 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3850 {
3851 dwError = ERROR_MORE_DATA;
3852 goto Done;
3853 }
3854
3855 /* Allocate memory for array of service pointers */
3856 lpServicesArray = HeapAlloc(GetProcessHeap(),
3857 HEAP_ZERO_MEMORY,
3858 (dwServicesReturned + 1) * sizeof(PSERVICE));
3859 if (!lpServicesArray)
3860 {
3861 DPRINT("Could not allocate a buffer!!\n");
3862 dwError = ERROR_NOT_ENOUGH_MEMORY;
3863 goto Done;
3864 }
3865
3866 dwServicesReturned = 0;
3867 *pcbBytesNeeded = 0;
3868
3869 dwError = Int_EnumDependentServicesW(hServicesKey,
3870 lpService,
3871 dwServiceState,
3872 lpServicesArray,
3873 pcbBytesNeeded,
3874 &dwServicesReturned);
3875 if (dwError != ERROR_SUCCESS)
3876 {
3877 goto Done;
3878 }
3879
3880 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3881 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3882
3883 /* Copy EnumDepenedentService to Buffer */
3884 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3885 {
3886 lpService = lpServicesArray[dwServiceCount];
3887
3888 /* Copy the status info */
3889 memcpy(&lpServicesPtr->ServiceStatus,
3890 &lpService->Status,
3891 sizeof(SERVICE_STATUS));
3892
3893 /* Copy display name */
3894 WideCharToMultiByte(CP_ACP,
3895 0,
3896 lpService->lpDisplayName,
3897 -1,
3898 lpStr,
3899 (int)wcslen(lpService->lpDisplayName),
3900 0,
3901 0);
3902 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3903 lpStr += strlen(lpStr) + 1;
3904
3905 /* Copy service name */
3906 WideCharToMultiByte(CP_ACP,
3907 0,
3908 lpService->lpServiceName,
3909 -1,