/* INCLUDES ****************************************************************/
#include "services.h"
-#include "svcctl_s.h"
+
+#include <winnls.h>
#define NDEBUG
#include <debug.h>
SERVICE_STOP | \
SERVICE_START)
+#define TAG_ARRAY_SIZE 32
/* VARIABLES ***************************************************************/
if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
{
- DPRINT("Database %S, does not exist\n",lpDatabaseName);
+ DPRINT("Database %S, does not exist\n", lpDatabaseName);
return ERROR_DATABASE_DOES_NOT_EXIST;
}
else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
{
- DPRINT("Invalid Database name %S.\n",lpDatabaseName);
+ DPRINT("Invalid Database name %S.\n", lpDatabaseName);
return ERROR_INVALID_NAME;
}
- Ptr = (MANAGER_HANDLE*) HeapAlloc(GetProcessHeap(),
+ Ptr = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
- sizeof(MANAGER_HANDLE) + (wcslen(lpDatabaseName) + 1) * sizeof(WCHAR));
+ FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1]));
if (Ptr == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
{
PSERVICE_HANDLE Ptr;
- Ptr = (SERVICE_HANDLE*) HeapAlloc(GetProcessHeap(),
+ Ptr = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(SERVICE_HANDLE));
if (Ptr == NULL)
DWORD
ScmAssignNewTag(PSERVICE lpService)
{
- /* FIXME */
- DPRINT("Assigning new tag to service %S\n", lpService->lpServiceName);
- lpService->dwTag = 0;
- return ERROR_SUCCESS;
-}
+ HKEY hKey = NULL;
+ DWORD dwError;
+ DWORD dwGroupTagCount = 0;
+ PDWORD pdwGroupTags = NULL;
+ DWORD dwFreeTag = 0;
+ DWORD dwTagUsedBase = 1;
+ BOOLEAN TagUsed[TAG_ARRAY_SIZE];
+ INT nTagOffset;
+ DWORD i;
+ DWORD cbDataSize;
+ PLIST_ENTRY ServiceEntry;
+ PSERVICE CurrentService;
+ ASSERT(lpService != NULL);
+ ASSERT(lpService->lpGroup != NULL);
-/* Internal recursive function */
-/* Need to search for every dependency on every service */
-static DWORD
-Int_EnumDependentServicesW(HKEY hServicesKey,
- PSERVICE lpService,
- DWORD dwServiceState,
- PSERVICE *lpServices,
- LPDWORD pcbBytesNeeded,
- LPDWORD lpServicesReturned)
-{
- DWORD dwError = ERROR_SUCCESS;
- WCHAR szNameBuf[MAX_PATH];
- WCHAR szValueBuf[MAX_PATH];
- WCHAR *lpszNameBuf = szNameBuf;
- WCHAR *lpszValueBuf = szValueBuf;
- DWORD dwSize;
- DWORD dwNumSubKeys;
- DWORD dwIteration;
- PSERVICE lpCurrentService;
- HKEY hServiceEnumKey;
- DWORD dwCurrentServiceState = SERVICE_ACTIVE;
- DWORD dwDependServiceStrPtr = 0;
- DWORD dwRequiredSize = 0;
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"System\\CurrentControlSet\\Control\\GroupOrderList",
+ 0,
+ KEY_READ,
+ &hKey);
- /* Get the number of service keys */
- dwError = RegQueryInfoKeyW(hServicesKey,
- NULL,
- NULL,
- NULL,
- &dwNumSubKeys,
- NULL,
- NULL,
- NULL,
+ if (dwError != ERROR_SUCCESS)
+ goto findFreeTag;
+
+ /* query value length */
+ cbDataSize = 0;
+ dwError = RegQueryValueExW(hKey,
+ lpService->lpGroup->szGroupName,
NULL,
NULL,
NULL,
- NULL);
- if (dwError != ERROR_SUCCESS)
+ &cbDataSize);
+
+ if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA)
+ goto findFreeTag;
+
+ pdwGroupTags = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDataSize);
+ if (!pdwGroupTags)
{
- DPRINT("ERROR! Unable to get number of services keys.\n");
- return dwError;
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto cleanup;
}
- /* Iterate the service keys to see if another service depends on the this service */
- for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
- {
- dwSize = MAX_PATH;
- dwError = RegEnumKeyExW(hServicesKey,
- dwIteration,
- lpszNameBuf,
- &dwSize,
- NULL,
- NULL,
- NULL,
- NULL);
- if (dwError != ERROR_SUCCESS)
- return dwError;
+ dwError = RegQueryValueExW(hKey,
+ lpService->lpGroup->szGroupName,
+ NULL,
+ NULL,
+ (LPBYTE)pdwGroupTags,
+ &cbDataSize);
- /* Open the Service key */
- dwError = RegOpenKeyExW(hServicesKey,
- lpszNameBuf,
- 0,
- KEY_READ,
- &hServiceEnumKey);
- if (dwError != ERROR_SUCCESS)
- return dwError;
+ if (dwError != ERROR_SUCCESS)
+ goto findFreeTag;
- dwSize = MAX_PATH;
+ if (cbDataSize < sizeof(pdwGroupTags[0]))
+ goto findFreeTag;
- /* Check for the DependOnService Value */
- dwError = RegQueryValueExW(hServiceEnumKey,
- L"DependOnService",
- NULL,
- NULL,
- (LPBYTE)lpszValueBuf,
- &dwSize);
+ dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1);
- /* FIXME: Handle load order. */
+findFreeTag:
+ do
+ {
+ /* mark all tags as unused */
+ for (i = 0; i < TAG_ARRAY_SIZE; i++)
+ TagUsed[i] = FALSE;
- /* If the service found has a DependOnService value */
- if (dwError == ERROR_SUCCESS)
+ /* mark tags in GroupOrderList as used */
+ for (i = 1; i <= dwGroupTagCount; i++)
{
- dwDependServiceStrPtr = 0;
+ nTagOffset = pdwGroupTags[i] - dwTagUsedBase;
+ if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
+ TagUsed[nTagOffset] = TRUE;
+ }
- /* Can be more than one Dependencies in the DependOnService string */
- while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
+ /* mark tags in service list as used */
+ ServiceEntry = lpService->ServiceListEntry.Flink;
+ while (ServiceEntry != &lpService->ServiceListEntry)
+ {
+ ASSERT(ServiceEntry != NULL);
+ CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
+ if (CurrentService->lpGroup == lpService->lpGroup)
{
- if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
- {
- /* Get the current enumed service pointer */
- lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
-
- /* Check for valid Service */
- if (!lpCurrentService)
- {
- /* This should never happen! */
- DPRINT("This should not happen at this point, report to Developer\n");
- return ERROR_NOT_FOUND;
- }
-
- /* Determine state the service is in */
- if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
- dwCurrentServiceState = SERVICE_INACTIVE;
-
- /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
- if ((dwCurrentServiceState == dwServiceState) ||
- (dwServiceState == SERVICE_STATE_ALL))
- {
- /* Calculate the required size */
- dwRequiredSize += sizeof(SERVICE_STATUS);
- dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
- dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
-
- /* Add the size for service name and display name pointers */
- dwRequiredSize += (2 * sizeof(PVOID));
-
- /* increase the BytesNeeded size */
- *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
+ nTagOffset = CurrentService->dwTag - dwTagUsedBase;
+ if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE)
+ TagUsed[nTagOffset] = TRUE;
+ }
- /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
- comes first */
+ ServiceEntry = ServiceEntry->Flink;
+ }
- /* Recursive call to check for its dependencies */
- Int_EnumDependentServicesW(hServicesKey,
- lpCurrentService,
- dwServiceState,
- lpServices,
- pcbBytesNeeded,
- lpServicesReturned);
+ /* find unused tag, if any */
+ for (i = 0; i < TAG_ARRAY_SIZE; i++)
+ {
+ if (!TagUsed[i])
+ {
+ dwFreeTag = dwTagUsedBase + i;
+ break;
+ }
+ }
- /* If the lpServices is valid set the service pointer */
- if (lpServices)
- lpServices[*lpServicesReturned] = lpCurrentService;
+ dwTagUsedBase += TAG_ARRAY_SIZE;
+ } while (!dwFreeTag);
- *lpServicesReturned = *lpServicesReturned + 1;
- }
- }
+cleanup:
+ if (pdwGroupTags)
+ HeapFree(GetProcessHeap(), 0, pdwGroupTags);
- dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
- }
- }
- else if (*pcbBytesNeeded)
- {
- dwError = ERROR_SUCCESS;
- }
+ if (hKey)
+ RegCloseKey(hKey);
- RegCloseKey(hServiceEnumKey);
+ if (dwFreeTag)
+ {
+ lpService->dwTag = dwFreeTag;
+ DPRINT("Assigning new tag %lu to service %S in group %S\n",
+ lpService->dwTag, lpService->lpServiceName, lpService->lpGroup->szGroupName);
+ dwError = ERROR_SUCCESS;
+ }
+ else
+ {
+ DPRINT1("Failed to assign new tag to service %S, error=%lu\n",
+ lpService->lpServiceName, dwError);
}
return dwError;
}
-/* Function 0 */
-DWORD RCloseServiceHandle(
- LPSC_RPC_HANDLE hSCObject)
+/* Create a path suitable for the bootloader out of the full path */
+DWORD
+ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
{
- PMANAGER_HANDLE hManager;
- PSERVICE_HANDLE hService;
- PSERVICE lpService;
- HKEY hServicesKey;
- DWORD dwError;
- DWORD pcbBytesNeeded = 0;
- DWORD dwServicesReturned = 0;
+ SIZE_T ServiceNameLen, ExpandedLen;
+ DWORD BufferSize;
+ WCHAR Dest;
+ WCHAR *Expanded;
+ UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ HANDLE SymbolicLinkHandle;
- DPRINT("RCloseServiceHandle() called\n");
+ DPRINT("ScmConvertToBootPathName %S\n", CanonName);
- DPRINT("hSCObject = %p\n", *hSCObject);
+ if (!RelativeName)
+ return ERROR_INVALID_PARAMETER;
- if (*hSCObject == 0)
- return ERROR_INVALID_HANDLE;
+ *RelativeName = NULL;
- hManager = ScmGetServiceManagerFromHandle(*hSCObject);
- hService = ScmGetServiceFromHandle(*hSCObject);
+ ServiceNameLen = wcslen(CanonName);
- if (hManager != NULL)
+ /* First check, if it's already good */
+ if (ServiceNameLen > 12 &&
+ !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
{
- DPRINT("Found manager handle\n");
-
- /* FIXME: add handle cleanup code */
-
- HeapFree(GetProcessHeap(), 0, hManager);
- hManager = NULL;
+ *RelativeName = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (ServiceNameLen + 1) * sizeof(WCHAR));
+ if (*RelativeName == NULL)
+ {
+ DPRINT("Error allocating memory for boot driver name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
- *hSCObject = NULL;
+ /* Copy it */
+ wcscpy(*RelativeName, CanonName);
- DPRINT("RCloseServiceHandle() done\n");
+ DPRINT("Bootdriver name %S\n", *RelativeName);
return ERROR_SUCCESS;
}
- else if (hService != NULL)
+
+ /* If it has %SystemRoot% prefix, substitute it to \System*/
+ if (ServiceNameLen > 13 &&
+ !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
{
- DPRINT("Found service handle\n");
+ /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
+ *RelativeName = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ ServiceNameLen * sizeof(WCHAR));
- /* Lock the service database exlusively */
- ScmLockDatabaseExclusive();
+ if (*RelativeName == NULL)
+ {
+ DPRINT("Error allocating memory for boot driver name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
- /* Get the pointer to the service record */
- lpService = hService->ServiceEntry;
+ /* Copy it */
+ wcscpy(*RelativeName, L"\\SystemRoot\\");
+ wcscat(*RelativeName, CanonName + 13);
- /* FIXME: add handle cleanup code */
+ DPRINT("Bootdriver name %S\n", *RelativeName);
+ return ERROR_SUCCESS;
+ }
- /* Free the handle */
- HeapFree(GetProcessHeap(), 0, hService);
- hService = NULL;
+ /* Get buffer size needed for expanding env strings */
+ BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
- ASSERT(lpService->dwRefCount > 0);
+ if (BufferSize <= 1)
+ {
+ DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
+ return ERROR_INVALID_ENVIRONMENT;
+ }
- lpService->dwRefCount--;
- DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
- lpService->dwRefCount);
+ /* Allocate memory, since the size is known now */
+ Expanded = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (BufferSize + 1) * sizeof(WCHAR));
+ if (!Expanded)
+ {
+ DPRINT("Error allocating memory for boot driver name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
- if (lpService->dwRefCount == 0)
- {
- /* If this service has been marked for deletion */
- if (lpService->bDeleted)
- {
- /* Open the Services Reg key */
- dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
- L"System\\CurrentControlSet\\Services",
- 0,
- KEY_SET_VALUE | KEY_READ,
- &hServicesKey);
- if (dwError != ERROR_SUCCESS)
- {
- DPRINT("Failed to open services key\n");
- ScmUnlockDatabase();
- return dwError;
- }
+ /* Expand it */
+ if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
+ BufferSize)
+ {
+ DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
+ HeapFree(GetProcessHeap(), 0, Expanded);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
- /* Call the internal function with NULL, just to get bytes we need */
- Int_EnumDependentServicesW(hServicesKey,
- lpService,
- SERVICE_ACTIVE,
- NULL,
- &pcbBytesNeeded,
- &dwServicesReturned);
+ /* Convert to NT-style path */
+ if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
+ {
+ DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
+ return ERROR_INVALID_ENVIRONMENT;
+ }
- /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service*/
- if (pcbBytesNeeded)
+ DPRINT("Converted to NT-style %wZ\n", &NtPathName);
+
+ /* No need to keep the dos-path anymore */
+ HeapFree(GetProcessHeap(), 0, Expanded);
+
+ /* Copy it to the allocated place */
+ Expanded = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ NtPathName.Length + sizeof(UNICODE_NULL));
+ if (!Expanded)
+ {
+ DPRINT("Error allocating memory for boot driver name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ ExpandedLen = NtPathName.Length / sizeof(WCHAR);
+ wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
+ Expanded[ExpandedLen] = UNICODE_NULL;
+
+ if (ServiceNameLen > ExpandedLen &&
+ !_wcsnicmp(Expanded, CanonName, ExpandedLen))
+ {
+ /* Only \SystemRoot\ is missing */
+ *RelativeName = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
+ if (*RelativeName == NULL)
+ {
+ DPRINT("Error allocating memory for boot driver name!\n");
+ HeapFree(GetProcessHeap(), 0, Expanded);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ wcscpy(*RelativeName, L"\\SystemRoot\\");
+ wcscat(*RelativeName, CanonName + ExpandedLen);
+
+ RtlFreeUnicodeString(&NtPathName);
+ return ERROR_SUCCESS;
+ }
+
+ /* The most complex case starts here */
+ RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
+ InitializeObjectAttributes(&ObjectAttributes,
+ &SystemRoot,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ /* Open this symlink */
+ Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
+
+ if (NT_SUCCESS(Status))
+ {
+ LinkTarget.Length = 0;
+ LinkTarget.MaximumLength = 0;
+
+ DPRINT("Opened symbolic link object\n");
+
+ Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
+ if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ /* Check if required buffer size is sane */
+ if (BufferSize > 0xFFFD)
+ {
+ DPRINT("Too large buffer required\n");
+
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ HeapFree(GetProcessHeap(), 0, Expanded);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Alloc the string */
+ LinkTarget.Length = (USHORT)BufferSize;
+ LinkTarget.MaximumLength = LinkTarget.Length + sizeof(UNICODE_NULL);
+ LinkTarget.Buffer = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ LinkTarget.MaximumLength);
+ if (!LinkTarget.Buffer)
+ {
+ DPRINT("Unable to alloc buffer\n");
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ HeapFree(GetProcessHeap(), 0, Expanded);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Do a real query now */
+ Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
+ if (NT_SUCCESS(Status))
+ {
+ DPRINT("LinkTarget: %wZ\n", &LinkTarget);
+
+ ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
+ if ((ServiceNameLen > ExpandedLen) &&
+ !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
{
- DPRINT("Deletion failed due to running dependencies.\n");
- RegCloseKey(hServicesKey);
- ScmUnlockDatabase();
- return ERROR_SUCCESS;
- }
+ *RelativeName = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
- /* There are no references and no runnning dependencies,
- it is now safe to delete the service */
+ if (*RelativeName == NULL)
+ {
+ DPRINT("Unable to alloc buffer\n");
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ HeapFree(GetProcessHeap(), 0, Expanded);
+ RtlFreeUnicodeString(&NtPathName);
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
- /* Delete the Service Key */
- dwError = RegDeleteKeyW(hServicesKey,
- lpService->lpServiceName);
+ /* Copy it over, substituting the first part
+ with SystemRoot */
+ wcscpy(*RelativeName, L"\\SystemRoot\\");
+ wcscat(*RelativeName, CanonName+ExpandedLen+1);
- RegCloseKey(hServicesKey);
+ /* Cleanup */
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ HeapFree(GetProcessHeap(), 0, Expanded);
+ RtlFreeUnicodeString(&NtPathName);
- if (dwError != ERROR_SUCCESS)
+ /* Return success */
+ return ERROR_SUCCESS;
+ }
+ else
{
- DPRINT("Failed to Delete the Service Registry key\n");
- ScmUnlockDatabase();
- return dwError;
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ HeapFree(GetProcessHeap(), 0, Expanded);
+ RtlFreeUnicodeString(&NtPathName);
+ return ERROR_INVALID_PARAMETER;
}
-
- /* Delete the Service */
- ScmDeleteServiceRecord(lpService);
+ }
+ else
+ {
+ DPRINT("Error, Status = %08X\n", Status);
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ HeapFree(GetProcessHeap(), 0, Expanded);
+ RtlFreeUnicodeString(&NtPathName);
+ return ERROR_INVALID_PARAMETER;
}
}
+ else
+ {
+ DPRINT("Error, Status = %08X\n", Status);
+ if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
+ HeapFree(GetProcessHeap(), 0, Expanded);
+ RtlFreeUnicodeString(&NtPathName);
+ return ERROR_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ /* Failure */
+ DPRINT("Error, Status = %08X\n", Status);
+ HeapFree(GetProcessHeap(), 0, Expanded);
+ return ERROR_INVALID_PARAMETER;
+ }
+}
- ScmUnlockDatabase();
- *hSCObject = NULL;
+DWORD
+ScmCanonDriverImagePath(DWORD dwStartType,
+ const wchar_t *lpServiceName,
+ wchar_t **lpCanonName)
+{
+ DWORD Result;
+ SIZE_T ServiceNameLen;
+ UNICODE_STRING NtServiceName;
+ WCHAR *RelativeName;
+ const WCHAR *SourceName = lpServiceName;
- DPRINT("RCloseServiceHandle() done\n");
- return ERROR_SUCCESS;
+ /* Calculate the length of the service's name */
+ ServiceNameLen = wcslen(lpServiceName);
+
+ /* 12 is wcslen(L"\\SystemRoot\\") */
+ if (ServiceNameLen > 12 &&
+ !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
+ {
+ /* SystemRoot prefix is already included */
+ *lpCanonName = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (ServiceNameLen + 1) * sizeof(WCHAR));
+
+ if (*lpCanonName == NULL)
+ {
+ DPRINT("Error allocating memory for canonized service name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* If it's a boot-time driver, it must be systemroot relative */
+ if (dwStartType == SERVICE_BOOT_START)
+ SourceName += 12;
+
+ /* Copy it */
+ wcscpy(*lpCanonName, SourceName);
+
+ DPRINT("Canonicalized name %S\n", *lpCanonName);
+ return NO_ERROR;
}
- DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
+ /* Check if it has %SystemRoot% (len=13) */
+ if (ServiceNameLen > 13 &&
+ !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13))
+ {
+ /* Substitute %SystemRoot% with \\SystemRoot\\ */
+ *lpCanonName = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (ServiceNameLen + 1) * sizeof(WCHAR));
- return ERROR_INVALID_HANDLE;
-}
+ if (*lpCanonName == NULL)
+ {
+ DPRINT("Error allocating memory for canonized service name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ /* If it's a boot-time driver, it must be systemroot relative */
+ if (dwStartType == SERVICE_BOOT_START)
+ wcscpy(*lpCanonName, L"\\SystemRoot\\");
-/* Function 1 */
-DWORD RControlService(
- SC_RPC_HANDLE hService,
- DWORD dwControl,
- LPSERVICE_STATUS lpServiceStatus)
-{
- PSERVICE_HANDLE hSvc;
- PSERVICE lpService;
- ACCESS_MASK DesiredAccess;
- DWORD dwError = ERROR_SUCCESS;
- DWORD pcbBytesNeeded = 0;
- DWORD dwServicesReturned = 0;
- DWORD dwControlsAccepted;
- DWORD dwCurrentState;
- HKEY hServicesKey = NULL;
+ wcscat(*lpCanonName, lpServiceName + 13);
- DPRINT("RControlService() called\n");
+ DPRINT("Canonicalized name %S\n", *lpCanonName);
+ return NO_ERROR;
+ }
- if (ScmShutdown)
- return ERROR_SHUTDOWN_IN_PROGRESS;
+ /* Check if it's a relative path name */
+ if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
+ {
+ *lpCanonName = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (ServiceNameLen + 1) * sizeof(WCHAR));
- /* Check the service handle */
- hSvc = ScmGetServiceFromHandle(hService);
- if (hSvc == NULL)
+ if (*lpCanonName == NULL)
+ {
+ DPRINT("Error allocating memory for canonized service name!\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ /* Just copy it over without changing */
+ wcscpy(*lpCanonName, lpServiceName);
+
+ return NO_ERROR;
+ }
+
+ /* It seems to be a DOS path, convert it */
+ if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
{
- DPRINT1("Invalid service handle!\n");
- return ERROR_INVALID_HANDLE;
+ DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
+ return ERROR_INVALID_PARAMETER;
}
+ *lpCanonName = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ NtServiceName.Length + sizeof(WCHAR));
- /* Check the service entry point */
- lpService = hSvc->ServiceEntry;
- if (lpService == NULL)
+ if (*lpCanonName == NULL)
{
- DPRINT1("lpService == NULL!\n");
- return ERROR_INVALID_HANDLE;
+ DPRINT("Error allocating memory for canonized service name!\n");
+ RtlFreeUnicodeString(&NtServiceName);
+ return ERROR_NOT_ENOUGH_MEMORY;
}
- /* Check access rights */
- switch (dwControl)
+ /* Copy the string */
+ wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
+
+ /* The unicode string is not needed anymore */
+ RtlFreeUnicodeString(&NtServiceName);
+
+ if (dwStartType != SERVICE_BOOT_START)
{
- case SERVICE_CONTROL_STOP:
- DesiredAccess = SERVICE_STOP;
- break;
+ DPRINT("Canonicalized name %S\n", *lpCanonName);
+ return NO_ERROR;
+ }
- case SERVICE_CONTROL_PAUSE:
- case SERVICE_CONTROL_CONTINUE:
- DesiredAccess = SERVICE_PAUSE_CONTINUE;
- break;
+ /* The service is boot-started, so must be relative */
+ Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
+ if (Result)
+ {
+ /* There is a problem, free name and return */
+ HeapFree(GetProcessHeap(), 0, *lpCanonName);
+ DPRINT("Error converting named!\n");
+ return Result;
+ }
- case SERVICE_INTERROGATE:
- DesiredAccess = SERVICE_INTERROGATE;
- break;
+ ASSERT(RelativeName);
- default:
- if (dwControl >= 128 && dwControl <= 255)
- DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
- else
- DesiredAccess = SERVICE_QUERY_CONFIG |
- SERVICE_CHANGE_CONFIG |
- SERVICE_QUERY_STATUS |
- SERVICE_START |
- SERVICE_PAUSE_CONTINUE;
- break;
+ /* Copy that string */
+ wcscpy(*lpCanonName, RelativeName + 12);
+
+ /* Free the allocated buffer */
+ HeapFree(GetProcessHeap(), 0, RelativeName);
+
+ DPRINT("Canonicalized name %S\n", *lpCanonName);
+
+ /* Success */
+ return NO_ERROR;
+}
+
+
+/* Internal recursive function */
+/* Need to search for every dependency on every service */
+static DWORD
+Int_EnumDependentServicesW(HKEY hServicesKey,
+ PSERVICE lpService,
+ DWORD dwServiceState,
+ PSERVICE *lpServices,
+ LPDWORD pcbBytesNeeded,
+ LPDWORD lpServicesReturned)
+{
+ DWORD dwError = ERROR_SUCCESS;
+ WCHAR szNameBuf[MAX_PATH];
+ WCHAR szValueBuf[MAX_PATH];
+ WCHAR *lpszNameBuf = szNameBuf;
+ WCHAR *lpszValueBuf = szValueBuf;
+ DWORD dwSize;
+ DWORD dwNumSubKeys;
+ DWORD dwIteration;
+ PSERVICE lpCurrentService;
+ HKEY hServiceEnumKey;
+ DWORD dwCurrentServiceState = SERVICE_ACTIVE;
+ DWORD dwDependServiceStrPtr = 0;
+ DWORD dwRequiredSize = 0;
+
+ /* Get the number of service keys */
+ dwError = RegQueryInfoKeyW(hServicesKey,
+ NULL,
+ NULL,
+ NULL,
+ &dwNumSubKeys,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT("ERROR! Unable to get number of services keys.\n");
+ return dwError;
}
- if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
- DesiredAccess))
- return ERROR_ACCESS_DENIED;
-
- if (dwControl == SERVICE_CONTROL_STOP)
+ /* Iterate the service keys to see if another service depends on the this service */
+ for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
{
- /* Check if the service has dependencies running as windows
- doesn't stop a service that does */
+ dwSize = MAX_PATH;
+ dwError = RegEnumKeyExW(hServicesKey,
+ dwIteration,
+ lpszNameBuf,
+ &dwSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (dwError != ERROR_SUCCESS)
+ return dwError;
- /* Open the Services Reg key */
- dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
- L"System\\CurrentControlSet\\Services",
+ /* Open the Service key */
+ dwError = RegOpenKeyExW(hServicesKey,
+ lpszNameBuf,
0,
KEY_READ,
- &hServicesKey);
+ &hServiceEnumKey);
if (dwError != ERROR_SUCCESS)
- {
- DPRINT("Failed to open services key\n");
return dwError;
- }
- /* Call the internal function with NULL, just to get bytes we need */
- Int_EnumDependentServicesW(hServicesKey,
- lpService,
- SERVICE_ACTIVE,
+ dwSize = MAX_PATH;
+
+ /* Check for the DependOnService Value */
+ dwError = RegQueryValueExW(hServiceEnumKey,
+ L"DependOnService",
NULL,
- &pcbBytesNeeded,
- &dwServicesReturned);
+ NULL,
+ (LPBYTE)lpszValueBuf,
+ &dwSize);
- RegCloseKey(hServicesKey);
+ /* FIXME: Handle load order. */
- /* If pcbBytesNeeded is not zero then there are services running that
- are dependent on this service */
- if (pcbBytesNeeded != 0)
+ /* If the service found has a DependOnService value */
+ if (dwError == ERROR_SUCCESS)
{
- DPRINT("Service has running dependencies. Failed to stop service.\n");
- return ERROR_DEPENDENT_SERVICES_RUNNING;
- }
- }
+ dwDependServiceStrPtr = 0;
- if (lpService->Status.dwServiceType & SERVICE_DRIVER)
- {
- /* Send control code to the driver */
- dwError = ScmControlDriver(lpService,
- dwControl,
- lpServiceStatus);
- }
- else
- {
- dwControlsAccepted = lpService->Status.dwControlsAccepted;
- dwCurrentState = lpService->Status.dwCurrentState;
+ /* Can be more than one Dependencies in the DependOnService string */
+ while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
+ {
+ if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
+ {
+ /* Get the current enumed service pointer */
+ lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
- /* Check the current state before sending a control request */
- switch (dwCurrentState)
- {
- case SERVICE_STOP_PENDING:
- case SERVICE_STOPPED:
- return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
+ /* Check for valid Service */
+ if (!lpCurrentService)
+ {
+ /* This should never happen! */
+ DPRINT("This should not happen at this point, report to Developer\n");
+ return ERROR_NOT_FOUND;
+ }
- case SERVICE_START_PENDING:
- switch (dwControl)
- {
- case SERVICE_CONTROL_STOP:
- break;
+ /* Determine state the service is in */
+ if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+ dwCurrentServiceState = SERVICE_INACTIVE;
- case SERVICE_CONTROL_INTERROGATE:
- RtlCopyMemory(lpServiceStatus,
- &lpService->Status,
- sizeof(SERVICE_STATUS));
- return ERROR_SUCCESS;
+ /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
+ if ((dwCurrentServiceState == dwServiceState) ||
+ (dwServiceState == SERVICE_STATE_ALL))
+ {
+ /* Calculate the required size */
+ dwRequiredSize += sizeof(SERVICE_STATUS);
+ dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
+ dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
- default:
- return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
+ /* Add the size for service name and display name pointers */
+ dwRequiredSize += (2 * sizeof(PVOID));
+
+ /* increase the BytesNeeded size */
+ *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
+
+ /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
+ comes first */
+
+ /* Recursive call to check for its dependencies */
+ Int_EnumDependentServicesW(hServicesKey,
+ lpCurrentService,
+ dwServiceState,
+ lpServices,
+ pcbBytesNeeded,
+ lpServicesReturned);
+
+ /* If the lpServices is valid set the service pointer */
+ if (lpServices)
+ lpServices[*lpServicesReturned] = lpCurrentService;
+
+ *lpServicesReturned = *lpServicesReturned + 1;
+ }
}
- break;
- }
- /* Check if the control code is acceptable to the service */
- switch (dwControl)
+ dwDependServiceStrPtr += (DWORD)(wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
+ }
+ }
+ else if (*pcbBytesNeeded)
{
- case SERVICE_CONTROL_STOP:
- if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
- return ERROR_INVALID_SERVICE_CONTROL;
- break;
-
- case SERVICE_CONTROL_PAUSE:
- case SERVICE_CONTROL_CONTINUE:
- if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
- return ERROR_INVALID_SERVICE_CONTROL;
- break;
+ dwError = ERROR_SUCCESS;
}
- /* Send control code to the service */
- dwError = ScmControlService(lpService,
- dwControl);
-
- /* Return service status information */
- RtlCopyMemory(lpServiceStatus,
- &lpService->Status,
- sizeof(SERVICE_STATUS));
+ RegCloseKey(hServiceEnumKey);
}
- if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
- dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
-
return dwError;
}
-/* Function 2 */
-DWORD RDeleteService(
- SC_RPC_HANDLE hService)
+/* Function 0 */
+DWORD RCloseServiceHandle(
+ LPSC_RPC_HANDLE hSCObject)
{
- PSERVICE_HANDLE hSvc;
+ PMANAGER_HANDLE hManager;
+ PSERVICE_HANDLE hService;
PSERVICE lpService;
+ HKEY hServicesKey;
DWORD dwError;
+ DWORD pcbBytesNeeded = 0;
+ DWORD dwServicesReturned = 0;
- DPRINT("RDeleteService() called\n");
+ DPRINT("RCloseServiceHandle() called\n");
- if (ScmShutdown)
- return ERROR_SHUTDOWN_IN_PROGRESS;
+ DPRINT("hSCObject = %p\n", *hSCObject);
- hSvc = ScmGetServiceFromHandle(hService);
- if (hSvc == NULL)
- {
- DPRINT1("Invalid service handle!\n");
+ if (*hSCObject == 0)
return ERROR_INVALID_HANDLE;
- }
- if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
- DELETE))
- return ERROR_ACCESS_DENIED;
+ hManager = ScmGetServiceManagerFromHandle(*hSCObject);
+ hService = ScmGetServiceFromHandle(*hSCObject);
- lpService = hSvc->ServiceEntry;
- if (lpService == NULL)
+ if (hManager != NULL)
{
- DPRINT("lpService == NULL!\n");
- return ERROR_INVALID_HANDLE;
- }
+ DPRINT("Found manager handle\n");
- /* Lock the service database exclusively */
- ScmLockDatabaseExclusive();
+ /* FIXME: add handle cleanup code */
- if (lpService->bDeleted)
- {
- DPRINT("The service has already been marked for delete!\n");
- dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
- goto Done;
+ HeapFree(GetProcessHeap(), 0, hManager);
+ hManager = NULL;
+
+ *hSCObject = NULL;
+
+ DPRINT("RCloseServiceHandle() done\n");
+ return ERROR_SUCCESS;
}
+ else if (hService != NULL)
+ {
+ DPRINT("Found service handle\n");
- /* Mark service for delete */
- lpService->bDeleted = TRUE;
+ /* Lock the service database exlusively */
+ ScmLockDatabaseExclusive();
+
+ /* Get the pointer to the service record */
+ lpService = hService->ServiceEntry;
+
+ /* FIXME: add handle cleanup code */
+
+ /* Free the handle */
+ HeapFree(GetProcessHeap(), 0, hService);
+ hService = NULL;
+
+ ASSERT(lpService->dwRefCount > 0);
+
+ lpService->dwRefCount--;
+ DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
+ lpService->dwRefCount);
+
+ if (lpService->dwRefCount == 0)
+ {
+ /* If this service has been marked for deletion */
+ if (lpService->bDeleted)
+ {
+ /* Open the Services Reg key */
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"System\\CurrentControlSet\\Services",
+ 0,
+ KEY_SET_VALUE | KEY_READ,
+ &hServicesKey);
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT("Failed to open services key\n");
+ ScmUnlockDatabase();
+ return dwError;
+ }
+
+ /* Call the internal function with NULL, just to get bytes we need */
+ Int_EnumDependentServicesW(hServicesKey,
+ lpService,
+ SERVICE_ACTIVE,
+ NULL,
+ &pcbBytesNeeded,
+ &dwServicesReturned);
- dwError = ScmMarkServiceForDelete(lpService);
+ /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
+ if (pcbBytesNeeded)
+ {
+ DPRINT("Deletion failed due to running dependencies.\n");
+ RegCloseKey(hServicesKey);
+ ScmUnlockDatabase();
+ return ERROR_SUCCESS;
+ }
-Done:;
- /* Unlock the service database */
- ScmUnlockDatabase();
+ /* There are no references and no runnning dependencies,
+ it is now safe to delete the service */
- DPRINT("RDeleteService() done\n");
+ /* Delete the Service Key */
+ dwError = RegDeleteKeyW(hServicesKey,
+ lpService->lpServiceName);
- return dwError;
-}
+ RegCloseKey(hServicesKey);
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT("Failed to Delete the Service Registry key\n");
+ ScmUnlockDatabase();
+ return dwError;
+ }
-/* Function 3 */
-DWORD RLockServiceDatabase(
- SC_RPC_HANDLE hSCManager,
- LPSC_RPC_LOCK lpLock)
-{
- PMANAGER_HANDLE hMgr;
+ /* Delete the Service */
+ ScmDeleteServiceRecord(lpService);
+ }
+ }
- DPRINT("RLockServiceDatabase() called\n");
+ ScmUnlockDatabase();
- *lpLock = 0;
+ *hSCObject = NULL;
- hMgr = ScmGetServiceManagerFromHandle(hSCManager);
- if (hMgr == NULL)
- {
- DPRINT1("Invalid service manager handle!\n");
- return ERROR_INVALID_HANDLE;
+ DPRINT("RCloseServiceHandle() done\n");
+ return ERROR_SUCCESS;
}
- if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
- SC_MANAGER_LOCK))
- return ERROR_ACCESS_DENIED;
-
-// return ScmLockDatabase(0, hMgr->0xC, hLock);
-
- /* FIXME: Lock the database */
- *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */
+ DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
- return ERROR_SUCCESS;
+ return ERROR_INVALID_HANDLE;
}
-/* Function 4 */
-DWORD RQueryServiceObjectSecurity(
+/* Function 1 */
+DWORD RControlService(
SC_RPC_HANDLE hService,
- SECURITY_INFORMATION dwSecurityInformation,
- LPBYTE lpSecurityDescriptor,
- DWORD cbBufSize,
- LPBOUNDED_DWORD_256K pcbBytesNeeded)
+ DWORD dwControl,
+ LPSERVICE_STATUS lpServiceStatus)
{
PSERVICE_HANDLE hSvc;
PSERVICE lpService;
- ULONG DesiredAccess = 0;
- NTSTATUS Status;
- DWORD dwBytesNeeded;
- DWORD dwError;
-
+ ACCESS_MASK DesiredAccess;
+ DWORD dwError = ERROR_SUCCESS;
+ DWORD pcbBytesNeeded = 0;
+ DWORD dwServicesReturned = 0;
+ DWORD dwControlsAccepted;
+ DWORD dwCurrentState;
+ HKEY hServicesKey = NULL;
- SECURITY_DESCRIPTOR ObjectDescriptor;
+ DPRINT("RControlService() called\n");
- DPRINT("RQueryServiceObjectSecurity() called\n");
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
+ /* Check the service handle */
hSvc = ScmGetServiceFromHandle(hService);
if (hSvc == NULL)
{
return ERROR_INVALID_HANDLE;
}
- if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
- GROUP_SECURITY_INFORMATION |
- OWNER_SECURITY_INFORMATION))
- DesiredAccess |= READ_CONTROL;
-
- if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
- DesiredAccess |= ACCESS_SYSTEM_SECURITY;
-
- if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
- DesiredAccess))
- {
- DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
- return ERROR_ACCESS_DENIED;
- }
-
+ /* Check the service entry point */
lpService = hSvc->ServiceEntry;
if (lpService == NULL)
{
- DPRINT("lpService == NULL!\n");
+ DPRINT1("lpService == NULL!\n");
return ERROR_INVALID_HANDLE;
}
- /* FIXME: Lock the service list */
-
- /* hack */
- Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
-
- Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */,
- dwSecurityInformation,
- (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
- cbBufSize,
- &dwBytesNeeded);
-
- /* FIXME: Unlock the service list */
-
- if (NT_SUCCESS(Status))
- {
- *pcbBytesNeeded = dwBytesNeeded;
- dwError = STATUS_SUCCESS;
- }
- else if (Status == STATUS_BUFFER_TOO_SMALL)
- {
- *pcbBytesNeeded = dwBytesNeeded;
- dwError = ERROR_INSUFFICIENT_BUFFER;
- }
- else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
- {
- dwError = ERROR_GEN_FAILURE;
- }
- else
+ /* Check access rights */
+ switch (dwControl)
{
- dwError = RtlNtStatusToDosError(Status);
- }
-
- return dwError;
-}
-
+ case SERVICE_CONTROL_STOP:
+ DesiredAccess = SERVICE_STOP;
+ break;
-/* Function 5 */
-DWORD RSetServiceObjectSecurity(
- SC_RPC_HANDLE hService,
- DWORD dwSecurityInformation,
- LPBYTE lpSecurityDescriptor,
- DWORD dwSecuityDescriptorSize)
-{
- PSERVICE_HANDLE hSvc;
- PSERVICE lpService;
- ULONG DesiredAccess = 0;
- /* HANDLE hToken = NULL; */
- HKEY hServiceKey;
- /* NTSTATUS Status; */
- DWORD dwError;
+ case SERVICE_CONTROL_PAUSE:
+ case SERVICE_CONTROL_CONTINUE:
+ DesiredAccess = SERVICE_PAUSE_CONTINUE;
+ break;
- DPRINT("RSetServiceObjectSecurity() called\n");
+ case SERVICE_CONTROL_INTERROGATE:
+ DesiredAccess = SERVICE_INTERROGATE;
+ break;
- hSvc = ScmGetServiceFromHandle(hService);
- if (hSvc == NULL)
- {
- DPRINT1("Invalid service handle!\n");
- return ERROR_INVALID_HANDLE;
+ default:
+ if (dwControl >= 128 && dwControl <= 255)
+ DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
+ else
+ return ERROR_INVALID_PARAMETER;
+ break;
}
- if (dwSecurityInformation == 0 ||
- dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
- | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
- return ERROR_INVALID_PARAMETER;
-
- if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
- return ERROR_INVALID_PARAMETER;
-
- if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
- DesiredAccess |= ACCESS_SYSTEM_SECURITY;
-
- if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
- DesiredAccess |= WRITE_DAC;
-
- if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
- DesiredAccess |= WRITE_OWNER;
-
- if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
- (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
- return ERROR_INVALID_PARAMETER;
-
- if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
- (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
- return ERROR_INVALID_PARAMETER;
-
if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
DesiredAccess))
- {
- DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
return ERROR_ACCESS_DENIED;
- }
- lpService = hSvc->ServiceEntry;
- if (lpService == NULL)
- {
- DPRINT("lpService == NULL!\n");
- return ERROR_INVALID_HANDLE;
- }
-
- if (lpService->bDeleted)
- return ERROR_SERVICE_MARKED_FOR_DELETE;
+ /* Return the current service status information */
+ RtlCopyMemory(lpServiceStatus,
+ &lpService->Status,
+ sizeof(SERVICE_STATUS));
-#if 0
- RpcImpersonateClient(NULL);
+ if (dwControl == SERVICE_CONTROL_STOP)
+ {
+ /* Check if the service has dependencies running as windows
+ doesn't stop a service that does */
- Status = NtOpenThreadToken(NtCurrentThread(),
- 8,
- TRUE,
- &hToken);
- if (!NT_SUCCESS(Status))
- return RtlNtStatusToDosError(Status);
+ /* Open the Services Reg key */
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"System\\CurrentControlSet\\Services",
+ 0,
+ KEY_READ,
+ &hServicesKey);
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT("Failed to open services key\n");
+ return dwError;
+ }
- RpcRevertToSelf();
+ /* Call the internal function with NULL, just to get bytes we need */
+ Int_EnumDependentServicesW(hServicesKey,
+ lpService,
+ SERVICE_ACTIVE,
+ NULL,
+ &pcbBytesNeeded,
+ &dwServicesReturned);
- /* FIXME: Lock service database */
+ RegCloseKey(hServicesKey);
- Status = RtlSetSecurityObject(dwSecurityInformation,
- (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
- &lpService->lpSecurityDescriptor,
- &ScmServiceMapping,
- hToken);
- if (!NT_SUCCESS(Status))
+ /* If pcbBytesNeeded is not zero then there are services running that
+ are dependent on this service */
+ if (pcbBytesNeeded != 0)
+ {
+ DPRINT("Service has running dependencies. Failed to stop service.\n");
+ return ERROR_DEPENDENT_SERVICES_RUNNING;
+ }
+ }
+
+ if (lpService->Status.dwServiceType & SERVICE_DRIVER)
{
- dwError = RtlNtStatusToDosError(Status);
- goto Done;
+ /* Send control code to the driver */
+ dwError = ScmControlDriver(lpService,
+ dwControl,
+ lpServiceStatus);
}
-#endif
+ else
+ {
+ dwControlsAccepted = lpService->Status.dwControlsAccepted;
+ dwCurrentState = lpService->Status.dwCurrentState;
- dwError = ScmOpenServiceKey(lpService->lpServiceName,
- READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
- &hServiceKey);
- if (dwError != ERROR_SUCCESS)
- goto Done;
+ /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
+ if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
+ return ERROR_SERVICE_NOT_ACTIVE;
- UNIMPLEMENTED;
- dwError = ERROR_SUCCESS;
-// dwError = ScmWriteSecurityDescriptor(hServiceKey,
-// lpService->lpSecurityDescriptor);
+ /* Check the current state before sending a control request */
+ switch (dwCurrentState)
+ {
+ case SERVICE_STOP_PENDING:
+ case SERVICE_STOPPED:
+ return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
- RegFlushKey(hServiceKey);
- RegCloseKey(hServiceKey);
+ case SERVICE_START_PENDING:
+ switch (dwControl)
+ {
+ case SERVICE_CONTROL_STOP:
+ break;
-Done:
+ case SERVICE_CONTROL_INTERROGATE:
+ RtlCopyMemory(lpServiceStatus,
+ &lpService->Status,
+ sizeof(SERVICE_STATUS));
+ return ERROR_SUCCESS;
-#if 0
- if (hToken != NULL)
- NtClose(hToken);
-#endif
+ default:
+ return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
+ }
+ break;
+ }
- /* FIXME: Unlock service database */
+ /* Check if the control code is acceptable to the service */
+ switch (dwControl)
+ {
+ case SERVICE_CONTROL_STOP:
+ if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
+ return ERROR_INVALID_SERVICE_CONTROL;
+ break;
- DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
+ case SERVICE_CONTROL_PAUSE:
+ case SERVICE_CONTROL_CONTINUE:
+ if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
+ return ERROR_INVALID_SERVICE_CONTROL;
+ break;
+ }
+
+ /* Send control code to the service */
+ dwError = ScmControlService(lpService,
+ dwControl);
+
+ /* Return service status information */
+ RtlCopyMemory(lpServiceStatus,
+ &lpService->Status,
+ sizeof(SERVICE_STATUS));
+ }
return dwError;
}
-/* Function 6 */
-DWORD RQueryServiceStatus(
- SC_RPC_HANDLE hService,
- LPSERVICE_STATUS lpServiceStatus)
+/* Function 2 */
+DWORD RDeleteService(
+ SC_RPC_HANDLE hService)
{
PSERVICE_HANDLE hSvc;
PSERVICE lpService;
+ DWORD dwError;
- DPRINT("RQueryServiceStatus() called\n");
+ DPRINT("RDeleteService() called\n");
if (ScmShutdown)
return ERROR_SHUTDOWN_IN_PROGRESS;
}
if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
- SERVICE_QUERY_STATUS))
- {
- DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+ DELETE))
return ERROR_ACCESS_DENIED;
- }
lpService = hSvc->ServiceEntry;
if (lpService == NULL)
return ERROR_INVALID_HANDLE;
}
- /* Lock the srevice database shared */
- ScmLockDatabaseShared();
+ /* Lock the service database exclusively */
+ ScmLockDatabaseExclusive();
- /* Return service status information */
- RtlCopyMemory(lpServiceStatus,
- &lpService->Status,
- sizeof(SERVICE_STATUS));
+ if (lpService->bDeleted)
+ {
+ DPRINT("The service has already been marked for delete!\n");
+ dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
+ goto Done;
+ }
+ /* Mark service for delete */
+ lpService->bDeleted = TRUE;
+
+ dwError = ScmMarkServiceForDelete(lpService);
+
+Done:
/* Unlock the service database */
ScmUnlockDatabase();
- return ERROR_SUCCESS;
+ DPRINT("RDeleteService() done\n");
+
+ return dwError;
}
-static BOOL
-ScmIsValidServiceState(DWORD dwCurrentState)
+/* Function 3 */
+DWORD RLockServiceDatabase(
+ SC_RPC_HANDLE hSCManager,
+ LPSC_RPC_LOCK lpLock)
{
- switch (dwCurrentState)
- {
- case SERVICE_STOPPED:
- case SERVICE_START_PENDING:
- case SERVICE_STOP_PENDING:
- case SERVICE_RUNNING:
- case SERVICE_CONTINUE_PENDING:
- case SERVICE_PAUSE_PENDING:
- case SERVICE_PAUSED:
- return TRUE;
+ PMANAGER_HANDLE hMgr;
- default:
- return FALSE;
+ DPRINT("RLockServiceDatabase() called\n");
+
+ *lpLock = NULL;
+
+ hMgr = ScmGetServiceManagerFromHandle(hSCManager);
+ if (hMgr == NULL)
+ {
+ DPRINT1("Invalid service manager handle!\n");
+ return ERROR_INVALID_HANDLE;
}
+
+ if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
+ SC_MANAGER_LOCK))
+ return ERROR_ACCESS_DENIED;
+
+ return ScmAcquireServiceStartLock(FALSE, lpLock);
}
-/* Function 7 */
-DWORD RSetServiceStatus(
- RPC_SERVICE_STATUS_HANDLE hServiceStatus,
- LPSERVICE_STATUS lpServiceStatus)
+/* Function 4 */
+DWORD RQueryServiceObjectSecurity(
+ SC_RPC_HANDLE hService,
+ SECURITY_INFORMATION dwSecurityInformation,
+ LPBYTE lpSecurityDescriptor,
+ DWORD cbBufSize,
+ LPBOUNDED_DWORD_256K pcbBytesNeeded)
{
+ PSERVICE_HANDLE hSvc;
PSERVICE lpService;
+ ULONG DesiredAccess = 0;
+ NTSTATUS Status;
+ DWORD dwBytesNeeded;
+ DWORD dwError;
- DPRINT("RSetServiceStatus() called\n");
- DPRINT("hServiceStatus = %p\n", hServiceStatus);
- DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
- DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
- DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
- DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
- DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
- DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
- DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
- if (hServiceStatus == 0)
- {
- DPRINT("hServiceStatus == NULL!\n");
- return ERROR_INVALID_HANDLE;
- }
+ SECURITY_DESCRIPTOR ObjectDescriptor;
- lpService = (PSERVICE)hServiceStatus;
- if (lpService == NULL)
+ DPRINT("RQueryServiceObjectSecurity() called\n");
+
+ hSvc = ScmGetServiceFromHandle(hService);
+ if (hSvc == NULL)
{
- DPRINT("lpService == NULL!\n");
+ DPRINT1("Invalid service handle!\n");
return ERROR_INVALID_HANDLE;
}
- /* Check current state */
- if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
- {
- DPRINT("Invalid service state!\n");
- return ERROR_INVALID_DATA;
- }
+ if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ OWNER_SECURITY_INFORMATION))
+ DesiredAccess |= READ_CONTROL;
- /* Check service type */
- if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
- (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
+ if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
+ DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+
+ if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+ DesiredAccess))
{
- DPRINT("Invalid service type!\n");
- return ERROR_INVALID_DATA;
+ DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
}
- /* Check accepted controls */
- if (lpServiceStatus->dwControlsAccepted & ~0xFF)
+ lpService = hSvc->ServiceEntry;
+ if (lpService == NULL)
{
- DPRINT("Invalid controls accepted!\n");
- return ERROR_INVALID_DATA;
+ DPRINT("lpService == NULL!\n");
+ return ERROR_INVALID_HANDLE;
}
- /* Lock the service database exclusively */
- ScmLockDatabaseExclusive();
-
- RtlCopyMemory(&lpService->Status,
- lpServiceStatus,
- sizeof(SERVICE_STATUS));
-
- /* Unlock the service database */
- ScmUnlockDatabase();
-
- DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
- DPRINT("RSetServiceStatus() done\n");
-
- return ERROR_SUCCESS;
-}
-
+ /* Lock the service database */
+ ScmLockDatabaseShared();
-/* Function 8 */
-DWORD RUnlockServiceDatabase(
- LPSC_RPC_LOCK Lock)
-{
- UNIMPLEMENTED;
- return ERROR_SUCCESS;
-}
+ /* hack */
+ Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
-/* Function 9 */
-DWORD RNotifyBootConfigStatus(
- SVCCTL_HANDLEW lpMachineName,
- DWORD BootAcceptable)
-{
- DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
- return ERROR_SUCCESS;
+ Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */,
+ dwSecurityInformation,
+ (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
+ cbBufSize,
+ &dwBytesNeeded);
-// UNIMPLEMENTED;
-// return ERROR_CALL_NOT_IMPLEMENTED;
-}
+ /* Unlock the service database */
+ ScmUnlockDatabase();
+ if (NT_SUCCESS(Status))
+ {
+ *pcbBytesNeeded = dwBytesNeeded;
+ dwError = STATUS_SUCCESS;
+ }
+ else if (Status == STATUS_BUFFER_TOO_SMALL)
+ {
+ *pcbBytesNeeded = dwBytesNeeded;
+ dwError = ERROR_INSUFFICIENT_BUFFER;
+ }
+ else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
+ {
+ dwError = ERROR_GEN_FAILURE;
+ }
+ else
+ {
+ dwError = RtlNtStatusToDosError(Status);
+ }
-/* Function 10 */
-DWORD RI_ScSetServiceBitsW(
- RPC_SERVICE_STATUS_HANDLE hServiceStatus,
- DWORD dwServiceBits,
- int bSetBitsOn,
- int bUpdateImmediately,
- wchar_t *lpString)
-{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ return dwError;
}
-/* Function 11 */
-DWORD RChangeServiceConfigW(
+/* Function 5 */
+DWORD RSetServiceObjectSecurity(
SC_RPC_HANDLE hService,
- DWORD dwServiceType,
- DWORD dwStartType,
- DWORD dwErrorControl,
- LPWSTR lpBinaryPathName,
- LPWSTR lpLoadOrderGroup,
- LPDWORD lpdwTagId,
- LPBYTE lpDependencies,
- DWORD dwDependSize,
- LPWSTR lpServiceStartName,
- LPBYTE lpPassword,
- DWORD dwPwSize,
- LPWSTR lpDisplayName)
+ DWORD dwSecurityInformation,
+ LPBYTE lpSecurityDescriptor,
+ DWORD dwSecuityDescriptorSize)
{
- DWORD dwError = ERROR_SUCCESS;
PSERVICE_HANDLE hSvc;
- PSERVICE lpService = NULL;
- HKEY hServiceKey = NULL;
- LPWSTR lpDisplayNameW = NULL;
-
- DPRINT("RChangeServiceConfigW() called\n");
- DPRINT("dwServiceType = %lu\n", dwServiceType);
- DPRINT("dwStartType = %lu\n", dwStartType);
- DPRINT("dwErrorControl = %lu\n", dwErrorControl);
- DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
- DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
- DPRINT("lpDisplayName = %S\n", lpDisplayName);
+ PSERVICE lpService;
+ ULONG DesiredAccess = 0;
+ /* HANDLE hToken = NULL; */
+ HKEY hServiceKey;
+ /* NTSTATUS Status; */
+ DWORD dwError;
- if (ScmShutdown)
- return ERROR_SHUTDOWN_IN_PROGRESS;
+ DPRINT("RSetServiceObjectSecurity() called\n");
hSvc = ScmGetServiceFromHandle(hService);
if (hSvc == NULL)
return ERROR_INVALID_HANDLE;
}
+ if (dwSecurityInformation == 0 ||
+ dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
+ | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
+ return ERROR_INVALID_PARAMETER;
+
+ if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
+ return ERROR_INVALID_PARAMETER;
+
+ if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
+ DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+
+ if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
+ DesiredAccess |= WRITE_DAC;
+
+ if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
+ DesiredAccess |= WRITE_OWNER;
+
+ if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
+ (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
+ return ERROR_INVALID_PARAMETER;
+
+ if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
+ (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
+ return ERROR_INVALID_PARAMETER;
+
if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
- SERVICE_CHANGE_CONFIG))
+ DesiredAccess))
{
DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
return ERROR_ACCESS_DENIED;
return ERROR_INVALID_HANDLE;
}
- /* Lock the service database exclusively */
- ScmLockDatabaseExclusive();
-
if (lpService->bDeleted)
- {
- DPRINT("The service has already been marked for delete!\n");
- dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
- goto done;
- }
-
- /* Open the service key */
- dwError = ScmOpenServiceKey(lpService->szServiceName,
- KEY_SET_VALUE,
- &hServiceKey);
- if (dwError != ERROR_SUCCESS)
- goto done;
+ return ERROR_SERVICE_MARKED_FOR_DELETE;
- /* Write service data to the registry */
- /* Set the display name */
- if (lpDisplayName != NULL && *lpDisplayName != 0)
- {
- RegSetValueExW(hServiceKey,
- L"DisplayName",
- 0,
- REG_SZ,
- (LPBYTE)lpDisplayName,
- (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
+#if 0
+ RpcImpersonateClient(NULL);
- /* Update the display name */
- lpDisplayNameW = (LPWSTR)HeapAlloc(GetProcessHeap(),
- 0,
- (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
- if (lpDisplayNameW == NULL)
- {
- dwError = ERROR_NOT_ENOUGH_MEMORY;
- goto done;
- }
+ Status = NtOpenThreadToken(NtCurrentThread(),
+ 8,
+ TRUE,
+ &hToken);
+ if (!NT_SUCCESS(Status))
+ return RtlNtStatusToDosError(Status);
- if (lpService->lpDisplayName != lpService->lpServiceName)
- HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
+ RpcRevertToSelf();
+#endif
- lpService->lpDisplayName = lpDisplayNameW;
- }
+ /* Lock the service database exclusive */
+ ScmLockDatabaseExclusive();
- if (dwServiceType != SERVICE_NO_CHANGE)
+#if 0
+ Status = RtlSetSecurityObject(dwSecurityInformation,
+ (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
+ &lpService->lpSecurityDescriptor,
+ &ScmServiceMapping,
+ hToken);
+ if (!NT_SUCCESS(Status))
{
- /* Set the service type */
- dwError = RegSetValueExW(hServiceKey,
- L"Type",
- 0,
- REG_DWORD,
- (LPBYTE)&dwServiceType,
- sizeof(DWORD));
- if (dwError != ERROR_SUCCESS)
- goto done;
-
- lpService->Status.dwServiceType = dwServiceType;
+ dwError = RtlNtStatusToDosError(Status);
+ goto Done;
}
+#endif
- if (dwStartType != SERVICE_NO_CHANGE)
- {
- /* Set the start value */
- dwError = RegSetValueExW(hServiceKey,
- L"Start",
- 0,
- REG_DWORD,
- (LPBYTE)&dwStartType,
- sizeof(DWORD));
- if (dwError != ERROR_SUCCESS)
- goto done;
+ dwError = ScmOpenServiceKey(lpService->lpServiceName,
+ READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
+ &hServiceKey);
+ if (dwError != ERROR_SUCCESS)
+ goto Done;
- lpService->dwStartType = dwStartType;
- }
+ UNIMPLEMENTED;
+ dwError = ERROR_SUCCESS;
+// dwError = ScmWriteSecurityDescriptor(hServiceKey,
+// lpService->lpSecurityDescriptor);
- if (dwErrorControl != SERVICE_NO_CHANGE)
- {
- /* Set the error control value */
- dwError = RegSetValueExW(hServiceKey,
- L"ErrorControl",
- 0,
- REG_DWORD,
- (LPBYTE)&dwErrorControl,
- sizeof(DWORD));
- if (dwError != ERROR_SUCCESS)
- goto done;
+ RegFlushKey(hServiceKey);
+ RegCloseKey(hServiceKey);
- lpService->dwErrorControl = dwErrorControl;
- }
+Done:
#if 0
- /* FIXME: set the new ImagePath value */
-
- /* Set the image path */
- if (dwServiceType & SERVICE_WIN32)
- {
- if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
- {
- dwError = RegSetValueExW(hServiceKey,
- L"ImagePath",
- 0,
- REG_EXPAND_SZ,
- (LPBYTE)lpBinaryPathName,
- (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
- if (dwError != ERROR_SUCCESS)
- goto done;
- }
- }
- else if (dwServiceType & SERVICE_DRIVER)
- {
- if (lpImagePath != NULL && *lpImagePath != 0)
- {
- dwError = RegSetValueExW(hServiceKey,
- L"ImagePath",
- 0,
- REG_EXPAND_SZ,
- (LPBYTE)lpImagePath,
- (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
- if (dwError != ERROR_SUCCESS)
- goto done;
- }
- }
+ if (hToken != NULL)
+ NtClose(hToken);
#endif
- /* Set the group name */
- if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
- {
- dwError = RegSetValueExW(hServiceKey,
- L"Group",
- 0,
- REG_SZ,
- (LPBYTE)lpLoadOrderGroup,
- (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
- if (dwError != ERROR_SUCCESS)
- goto done;
+ /* Unlock service database */
+ ScmUnlockDatabase();
- dwError = ScmSetServiceGroup(lpService,
- lpLoadOrderGroup);
- if (dwError != ERROR_SUCCESS)
- goto done;
- }
+ DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
- if (lpdwTagId != NULL)
- {
- dwError = ScmAssignNewTag(lpService);
- if (dwError != ERROR_SUCCESS)
- goto done;
+ return dwError;
+}
+
+
+/* Function 6 */
+DWORD RQueryServiceStatus(
+ SC_RPC_HANDLE hService,
+ LPSERVICE_STATUS lpServiceStatus)
+{
+ PSERVICE_HANDLE hSvc;
+ PSERVICE lpService;
+
+ DPRINT("RQueryServiceStatus() called\n");
- dwError = RegSetValueExW(hServiceKey,
- L"Tag",
- 0,
- REG_DWORD,
- (LPBYTE)&lpService->dwTag,
- sizeof(DWORD));
- if (dwError != ERROR_SUCCESS)
- goto done;
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
- *lpdwTagId = lpService->dwTag;
+ hSvc = ScmGetServiceFromHandle(hService);
+ if (hSvc == NULL)
+ {
+ DPRINT1("Invalid service handle!\n");
+ return ERROR_INVALID_HANDLE;
}
- /* Write dependencies */
- if (lpDependencies != NULL && *lpDependencies != 0)
+ if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+ SERVICE_QUERY_STATUS))
{
- dwError = ScmWriteDependencies(hServiceKey,
- (LPWSTR)lpDependencies,
- dwDependSize);
- if (dwError != ERROR_SUCCESS)
- goto done;
+ DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
}
- if (lpPassword != NULL)
+ lpService = hSvc->ServiceEntry;
+ if (lpService == NULL)
{
- /* FIXME: Write password */
+ DPRINT("lpService == NULL!\n");
+ return ERROR_INVALID_HANDLE;
}
-done:
- if (hServiceKey != NULL)
- RegCloseKey(hServiceKey);
+ /* Lock the service database shared */
+ ScmLockDatabaseShared();
+
+ /* Return service status information */
+ RtlCopyMemory(lpServiceStatus,
+ &lpService->Status,
+ sizeof(SERVICE_STATUS));
/* Unlock the service database */
ScmUnlockDatabase();
- DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
-
- return dwError;
+ return ERROR_SUCCESS;
}
-/* Create a path suitable for the bootloader out of the full path */
-DWORD
-ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
+static BOOL
+ScmIsValidServiceState(DWORD dwCurrentState)
{
- DWORD ServiceNameLen, BufferSize, ExpandedLen;
- WCHAR Dest;
- WCHAR *Expanded;
- UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
- OBJECT_ATTRIBUTES ObjectAttributes;
- NTSTATUS Status;
- HANDLE SymbolicLinkHandle;
-
- DPRINT("ScmConvertToBootPathName %S\n", CanonName);
-
- ServiceNameLen = wcslen(CanonName);
-
- /* First check, if it's already good */
- if (ServiceNameLen > 12 &&
- !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
+ switch (dwCurrentState)
{
- *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
- if (*RelativeName == NULL)
- {
- DPRINT("Error allocating memory for boot driver name!\n");
- return ERROR_NOT_ENOUGH_MEMORY;
- }
-
- /* Copy it */
- wcscpy(*RelativeName, CanonName);
+ case SERVICE_STOPPED:
+ case SERVICE_START_PENDING:
+ case SERVICE_STOP_PENDING:
+ case SERVICE_RUNNING:
+ case SERVICE_CONTINUE_PENDING:
+ case SERVICE_PAUSE_PENDING:
+ case SERVICE_PAUSED:
+ return TRUE;
- DPRINT("Bootdriver name %S\n", *RelativeName);
- return ERROR_SUCCESS;
+ default:
+ return FALSE;
}
+}
- /* If it has %SystemRoot% prefix, substitute it to \System*/
- if (ServiceNameLen > 13 &&
- !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
- {
- /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
- *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
- if (*RelativeName == NULL)
- {
- DPRINT("Error allocating memory for boot driver name!\n");
- return ERROR_NOT_ENOUGH_MEMORY;
- }
+/* Function 7 */
+DWORD RSetServiceStatus(
+ RPC_SERVICE_STATUS_HANDLE hServiceStatus,
+ LPSERVICE_STATUS lpServiceStatus)
+{
+ PSERVICE lpService;
+ DWORD dwPreviousState;
+ DWORD dwPreviousType;
+ LPCWSTR lpErrorStrings[2];
+ WCHAR szErrorBuffer[32];
- /* Copy it */
- wcscpy(*RelativeName, L"\\SystemRoot\\");
- wcscat(*RelativeName, CanonName + 13);
+ DPRINT("RSetServiceStatus() called\n");
+ DPRINT("hServiceStatus = %lu\n", hServiceStatus);
+ DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
+ DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
+ DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
+ DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
+ DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
+ DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
+ DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
- DPRINT("Bootdriver name %S\n", *RelativeName);
- return ERROR_SUCCESS;
+ if (hServiceStatus == 0)
+ {
+ DPRINT("hServiceStatus == NULL!\n");
+ return ERROR_INVALID_HANDLE;
}
- /* Get buffer size needed for expanding env strings */
- BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
+ lpService = (PSERVICE)hServiceStatus;
- if (BufferSize <= 1)
+ /* Check current state */
+ if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
{
- DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
- return ERROR_INVALID_ENVIRONMENT;
+ DPRINT("Invalid service state!\n");
+ return ERROR_INVALID_DATA;
}
- /* Allocate memory, since the size is known now */
- Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
- if (!Expanded)
+ /* Check service type */
+ if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
+ (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
{
- DPRINT("Error allocating memory for boot driver name!\n");
- return ERROR_NOT_ENOUGH_MEMORY;
+ DPRINT("Invalid service type!\n");
+ return ERROR_INVALID_DATA;
}
- /* Expand it */
- if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
- BufferSize)
+ /* Check accepted controls */
+ if (lpServiceStatus->dwControlsAccepted & ~0xFF)
{
- DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
- LocalFree(Expanded);
- return ERROR_NOT_ENOUGH_MEMORY;
+ DPRINT("Invalid controls accepted!\n");
+ return ERROR_INVALID_DATA;
}
- /* Convert to NY-style path */
- if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
+ /* Set the wait hint and check point only if the service is in a pending state,
+ otherwise they should be 0 */
+ if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
+ lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
+ lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
{
- DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
- return ERROR_INVALID_ENVIRONMENT;
+ lpServiceStatus->dwWaitHint = 0;
+ lpServiceStatus->dwCheckPoint = 0;
}
- DPRINT("Converted to NT-style %wZ\n", &NtPathName);
+ /* Lock the service database exclusively */
+ ScmLockDatabaseExclusive();
- /* No need to keep the dos-path anymore */
- LocalFree(Expanded);
+ /* Save the current service state */
+ dwPreviousState = lpService->Status.dwCurrentState;
- /* Copy it to the allocated place */
- Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
- if (!Expanded)
- {
- DPRINT("Error allocating memory for boot driver name!\n");
- return ERROR_NOT_ENOUGH_MEMORY;
- }
+ /* Save the current service type */
+ dwPreviousType = lpService->Status.dwServiceType;
- ExpandedLen = NtPathName.Length / sizeof(WCHAR);
- wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
- Expanded[ExpandedLen] = 0;
+ /* Update the service status */
+ RtlCopyMemory(&lpService->Status,
+ lpServiceStatus,
+ sizeof(SERVICE_STATUS));
- if (ServiceNameLen > ExpandedLen &&
- !_wcsnicmp(Expanded, CanonName, ExpandedLen))
+ /* Restore the previous service type */
+ lpService->Status.dwServiceType = dwPreviousType;
+
+ /* Unlock the service database */
+ ScmUnlockDatabase();
+
+ /* Log a failed service stop */
+ if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
+ (dwPreviousState != SERVICE_STOPPED))
{
- /* Only \SystemRoot\ is missing */
- *RelativeName = LocalAlloc(LMEM_ZEROINIT,
- (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
- if (*RelativeName == NULL)
+ if (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS)
{
- DPRINT("Error allocating memory for boot driver name!\n");
- LocalFree(Expanded);
- return ERROR_NOT_ENOUGH_MEMORY;
- }
-
- wcscpy(*RelativeName, L"\\SystemRoot\\");
- wcscat(*RelativeName, CanonName + ExpandedLen);
+ swprintf(szErrorBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode);
+ lpErrorStrings[0] = lpService->lpDisplayName;
+ lpErrorStrings[1] = szErrorBuffer;
- RtlFreeUnicodeString(&NtPathName);
- return ERROR_SUCCESS;
+ ScmLogError(EVENT_SERVICE_EXIT_FAILED,
+ 2,
+ lpErrorStrings);
+ }
}
- /* The most complex case starts here */
- RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
- InitializeObjectAttributes(&ObjectAttributes,
- &SystemRoot,
- OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
+ DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
+ DPRINT("RSetServiceStatus() done\n");
- /* Open this symlink */
- Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
+ return ERROR_SUCCESS;
+}
- if (NT_SUCCESS(Status))
- {
- LinkTarget.Length = 0;
- LinkTarget.MaximumLength = 0;
- DPRINT("Opened symbolic link object\n");
+/* Function 8 */
+DWORD RUnlockServiceDatabase(
+ LPSC_RPC_LOCK Lock)
+{
+ DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
+ return ScmReleaseServiceStartLock(Lock);
+}
- Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
- if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
- {
- /* Check if required buffer size is sane */
- if (BufferSize > 0xFFFD)
- {
- DPRINT("Too large buffer required\n");
- *RelativeName = 0;
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- LocalFree(Expanded);
- return ERROR_NOT_ENOUGH_MEMORY;
- }
+/* Function 9 */
+DWORD RNotifyBootConfigStatus(
+ SVCCTL_HANDLEW lpMachineName,
+ DWORD BootAcceptable)
+{
+ DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
+ return ERROR_SUCCESS;
- /* Alloc the string */
- LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
- if (!LinkTarget.Buffer)
- {
- DPRINT("Unable to alloc buffer\n");
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- LocalFree(Expanded);
- return ERROR_NOT_ENOUGH_MEMORY;
- }
+// UNIMPLEMENTED;
+// return ERROR_CALL_NOT_IMPLEMENTED;
+}
- /* Do a real query now */
- LinkTarget.Length = (USHORT)BufferSize;
- LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
- Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
- if (NT_SUCCESS(Status))
- {
- DPRINT("LinkTarget: %wZ\n", &LinkTarget);
+/* Function 10 */
+DWORD RI_ScSetServiceBitsW(
+ RPC_SERVICE_STATUS_HANDLE hServiceStatus,
+ DWORD dwServiceBits,
+ int bSetBitsOn,
+ int bUpdateImmediately,
+ wchar_t *lpString)
+{
+ UNIMPLEMENTED;
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
- ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
- if ((ServiceNameLen > ExpandedLen) &&
- !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
- {
- *RelativeName = LocalAlloc(LMEM_ZEROINIT,
- (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
- if (*RelativeName == NULL)
- {
- DPRINT("Unable to alloc buffer\n");
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- LocalFree(Expanded);
- RtlFreeUnicodeString(&NtPathName);
- return ERROR_NOT_ENOUGH_MEMORY;
- }
+/* Function 11 */
+DWORD RChangeServiceConfigW(
+ SC_RPC_HANDLE hService,
+ DWORD dwServiceType,
+ DWORD dwStartType,
+ DWORD dwErrorControl,
+ LPWSTR lpBinaryPathName,
+ LPWSTR lpLoadOrderGroup,
+ LPDWORD lpdwTagId,
+ LPBYTE lpDependencies,
+ DWORD dwDependSize,
+ LPWSTR lpServiceStartName,
+ LPBYTE lpPassword,
+ DWORD dwPwSize,
+ LPWSTR lpDisplayName)
+{
+ DWORD dwError = ERROR_SUCCESS;
+ PSERVICE_HANDLE hSvc;
+ PSERVICE lpService = NULL;
+ HKEY hServiceKey = NULL;
+ LPWSTR lpDisplayNameW = NULL;
+ LPWSTR lpImagePathW = NULL;
+
+ DPRINT("RChangeServiceConfigW() called\n");
+ DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
+ DPRINT("dwStartType = %lu\n", dwStartType);
+ DPRINT("dwErrorControl = %lu\n", dwErrorControl);
+ DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
+ DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
+ DPRINT("lpDisplayName = %S\n", lpDisplayName);
- /* Copy it over, substituting the first part
- with SystemRoot */
- wcscpy(*RelativeName, L"\\SystemRoot\\");
- wcscat(*RelativeName, CanonName+ExpandedLen+1);
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
- /* Cleanup */
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- LocalFree(Expanded);
- RtlFreeUnicodeString(&NtPathName);
+ hSvc = ScmGetServiceFromHandle(hService);
+ if (hSvc == NULL)
+ {
+ DPRINT1("Invalid service handle!\n");
+ return ERROR_INVALID_HANDLE;
+ }
- /* Return success */
- return ERROR_SUCCESS;
- }
- else
- {
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- LocalFree(Expanded);
- RtlFreeUnicodeString(&NtPathName);
- return ERROR_INVALID_PARAMETER;
- }
- }
- else
- {
- DPRINT("Error, Status = %08X\n", Status);
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- LocalFree(Expanded);
- RtlFreeUnicodeString(&NtPathName);
- return ERROR_INVALID_PARAMETER;
- }
- }
- else
- {
- DPRINT("Error, Status = %08X\n", Status);
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- LocalFree(Expanded);
- RtlFreeUnicodeString(&NtPathName);
- return ERROR_INVALID_PARAMETER;
- }
+ if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+ SERVICE_CHANGE_CONFIG))
+ {
+ DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
}
- else
+
+ lpService = hSvc->ServiceEntry;
+ if (lpService == NULL)
{
- DPRINT("Error, Status = %08X\n", Status);
- LocalFree(Expanded);
- return ERROR_INVALID_PARAMETER;
+ DPRINT("lpService == NULL!\n");
+ return ERROR_INVALID_HANDLE;
}
- /* Failure */
- *RelativeName = NULL;
- return ERROR_INVALID_PARAMETER;
-}
+ /* Lock the service database exclusively */
+ ScmLockDatabaseExclusive();
-DWORD
-ScmCanonDriverImagePath(DWORD dwStartType,
- const wchar_t *lpServiceName,
- wchar_t **lpCanonName)
-{
- DWORD ServiceNameLen, Result;
- UNICODE_STRING NtServiceName;
- WCHAR *RelativeName;
- const WCHAR *SourceName = lpServiceName;
+ if (lpService->bDeleted)
+ {
+ DPRINT("The service has already been marked for delete!\n");
+ dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
+ goto done;
+ }
- /* Calculate the length of the service's name */
- ServiceNameLen = wcslen(lpServiceName);
+ /* Open the service key */
+ dwError = ScmOpenServiceKey(lpService->szServiceName,
+ KEY_SET_VALUE,
+ &hServiceKey);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
- /* 12 is wcslen(L"\\SystemRoot\\") */
- if (ServiceNameLen > 12 &&
- !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
+ /* Write service data to the registry */
+ /* Set the display name */
+ if (lpDisplayName != NULL && *lpDisplayName != 0)
{
- /* SystemRoot prefix is already included */
-
- *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
+ RegSetValueExW(hServiceKey,
+ L"DisplayName",
+ 0,
+ REG_SZ,
+ (LPBYTE)lpDisplayName,
+ (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
- if (*lpCanonName == NULL)
+ /* Update the display name */
+ lpDisplayNameW = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
+ if (lpDisplayNameW == NULL)
{
- DPRINT("Error allocating memory for canonized service name!\n");
- return ERROR_NOT_ENOUGH_MEMORY;
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
}
- /* If it's a boot-time driver, it must be systemroot relative */
- if (dwStartType == SERVICE_BOOT_START)
- SourceName += 12;
-
- /* Copy it */
- wcscpy(*lpCanonName, SourceName);
+ if (lpService->lpDisplayName != lpService->lpServiceName)
+ HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
- DPRINT("Canonicalized name %S\n", *lpCanonName);
- return NO_ERROR;
+ lpService->lpDisplayName = lpDisplayNameW;
}
- /* Check if it has %SystemRoot% (len=13) */
- if (ServiceNameLen > 13 &&
- !_wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
+ if (dwServiceType != SERVICE_NO_CHANGE)
{
- /* Substitute %SystemRoot% with \\SystemRoot\\ */
- *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
+ /* Set the service type */
+ dwError = RegSetValueExW(hServiceKey,
+ L"Type",
+ 0,
+ REG_DWORD,
+ (LPBYTE)&dwServiceType,
+ sizeof(DWORD));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
- if (*lpCanonName == NULL)
- {
- DPRINT("Error allocating memory for canonized service name!\n");
- return ERROR_NOT_ENOUGH_MEMORY;
- }
+ lpService->Status.dwServiceType = dwServiceType;
+ }
- /* If it's a boot-time driver, it must be systemroot relative */
- if (dwStartType == SERVICE_BOOT_START)
- wcscpy(*lpCanonName, L"\\SystemRoot\\");
+ if (dwStartType != SERVICE_NO_CHANGE)
+ {
+ /* Set the start value */
+ dwError = RegSetValueExW(hServiceKey,
+ L"Start",
+ 0,
+ REG_DWORD,
+ (LPBYTE)&dwStartType,
+ sizeof(DWORD));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
- wcscat(*lpCanonName, lpServiceName + 13);
+ lpService->dwStartType = dwStartType;
+ }
- DPRINT("Canonicalized name %S\n", *lpCanonName);
- return NO_ERROR;
+ if (dwErrorControl != SERVICE_NO_CHANGE)
+ {
+ /* Set the error control value */
+ dwError = RegSetValueExW(hServiceKey,
+ L"ErrorControl",
+ 0,
+ REG_DWORD,
+ (LPBYTE)&dwErrorControl,
+ sizeof(DWORD));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ lpService->dwErrorControl = dwErrorControl;
}
- /* Check if it's a relative path name */
- if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
+ if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
{
- *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
+ /* Set the image path */
+ lpImagePathW = lpBinaryPathName;
- if (*lpCanonName == NULL)
+ if (lpService->Status.dwServiceType & SERVICE_DRIVER)
{
- DPRINT("Error allocating memory for canonized service name!\n");
- return ERROR_NOT_ENOUGH_MEMORY;
+ dwError = ScmCanonDriverImagePath(lpService->dwStartType,
+ lpBinaryPathName,
+ &lpImagePathW);
+
+ if (dwError != ERROR_SUCCESS)
+ goto done;
}
- /* Just copy it over without changing */
- wcscpy(*lpCanonName, lpServiceName);
+ dwError = RegSetValueExW(hServiceKey,
+ L"ImagePath",
+ 0,
+ REG_EXPAND_SZ,
+ (LPBYTE)lpImagePathW,
+ (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
- return NO_ERROR;
- }
+ if (lpImagePathW != lpBinaryPathName)
+ HeapFree(GetProcessHeap(), 0, lpImagePathW);
- /* It seems to be a DOS path, convert it */
- if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
- {
- DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
- return ERROR_INVALID_PARAMETER;
+ if (dwError != ERROR_SUCCESS)
+ goto done;
}
- *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
-
- if (*lpCanonName == NULL)
+ /* Set the group name */
+ if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
{
- DPRINT("Error allocating memory for canonized service name!\n");
- RtlFreeUnicodeString(&NtServiceName);
- return ERROR_NOT_ENOUGH_MEMORY;
+ dwError = RegSetValueExW(hServiceKey,
+ L"Group",
+ 0,
+ REG_SZ,
+ (LPBYTE)lpLoadOrderGroup,
+ (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ dwError = ScmSetServiceGroup(lpService,
+ lpLoadOrderGroup);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
}
- /* Copy the string */
- wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
+ if (lpdwTagId != NULL)
+ {
+ dwError = ScmAssignNewTag(lpService);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
- /* The unicode string is not needed anymore */
- RtlFreeUnicodeString(&NtServiceName);
+ dwError = RegSetValueExW(hServiceKey,
+ L"Tag",
+ 0,
+ REG_DWORD,
+ (LPBYTE)&lpService->dwTag,
+ sizeof(DWORD));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
- if (dwStartType != SERVICE_BOOT_START)
- {
- DPRINT("Canonicalized name %S\n", *lpCanonName);
- return NO_ERROR;
+ *lpdwTagId = lpService->dwTag;
}
- /* The service is boot-started, so must be relative */
- Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
- if (Result)
+ /* Write dependencies */
+ if (lpDependencies != NULL && *lpDependencies != 0)
{
- /* There is a problem, free name and return */
- LocalFree(*lpCanonName);
- DPRINT("Error converting named!\n");
- return Result;
+ dwError = ScmWriteDependencies(hServiceKey,
+ (LPWSTR)lpDependencies,
+ dwDependSize);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
}
- ASSERT(RelativeName);
+ if (lpPassword != NULL)
+ {
+ /* FIXME: Decrypt and write password */
+ }
- /* Copy that string */
- wcscpy(*lpCanonName, RelativeName + 12);
+done:
+ if (hServiceKey != NULL)
+ RegCloseKey(hServiceKey);
- /* Free the allocated buffer */
- LocalFree(RelativeName);
+ /* Unlock the service database */
+ ScmUnlockDatabase();
- DPRINT("Canonicalized name %S\n", *lpCanonName);
+ DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
- /* Success */
- return NO_ERROR;
+ return dwError;
}
DPRINT("lpServiceName = %S\n", lpServiceName);
DPRINT("lpDisplayName = %S\n", lpDisplayName);
DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
- DPRINT("dwServiceType = %lu\n", dwServiceType);
+ DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
DPRINT("dwStartType = %lu\n", dwStartType);
DPRINT("dwErrorControl = %lu\n", dwErrorControl);
DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
+ DPRINT("lpdwTagId = %p\n", lpdwTagId);
if (ScmShutdown)
return ERROR_SHUTDOWN_IN_PROGRESS;
return ERROR_INVALID_PARAMETER;
}
- if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
- (lpServiceStartName))
- {
+ /* Check for invalid service type value */
+ if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
+ (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
+ ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
+ ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
+ return ERROR_INVALID_PARAMETER;
+
+ /* Check for invalid start type value */
+ if ((dwStartType != SERVICE_BOOT_START) &&
+ (dwStartType != SERVICE_SYSTEM_START) &&
+ (dwStartType != SERVICE_AUTO_START) &&
+ (dwStartType != SERVICE_DEMAND_START) &&
+ (dwStartType != SERVICE_DISABLED))
return ERROR_INVALID_PARAMETER;
+
+ /* Only drivers can be boot start or system start services */
+ if ((dwStartType == SERVICE_BOOT_START) ||
+ (dwStartType == SERVICE_SYSTEM_START))
+ {
+ if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
+ (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
+ return ERROR_INVALID_PARAMETER;
}
- if ((dwServiceType > SERVICE_WIN32_SHARE_PROCESS) &&
- (dwServiceType != (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
- (dwServiceType != (SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)))
+ /* Check for invalid error control value */
+ if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
+ (dwErrorControl != SERVICE_ERROR_NORMAL) &&
+ (dwErrorControl != SERVICE_ERROR_SEVERE) &&
+ (dwErrorControl != SERVICE_ERROR_CRITICAL))
+ return ERROR_INVALID_PARAMETER;
+
+ if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
+ (lpServiceStartName))
{
return ERROR_INVALID_PARAMETER;
}
- if (dwStartType > SERVICE_DISABLED)
+ if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
{
return ERROR_INVALID_PARAMETER;
}
/* Unlock the service database */
ScmUnlockDatabase();
- /* check if it is marked for deletion */
+ /* Check if it is marked for deletion */
if (lpService->bDeleted)
return ERROR_SERVICE_MARKED_FOR_DELETE;
+
/* Return Error exist */
return ERROR_SERVICE_EXISTS;
}
*lpDisplayName != 0 &&
_wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
{
- lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
+ lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
(wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
if (lpService->lpDisplayName == NULL)
{
0,
REG_SZ,
(LPBYTE)lpDisplayName,
- (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
+ (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
}
/* Set the service type */
0,
REG_EXPAND_SZ,
(LPBYTE)lpBinaryPathName,
- (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
+ (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
if (dwError != ERROR_SUCCESS)
goto done;
}
0,
REG_EXPAND_SZ,
(LPBYTE)lpImagePath,
- (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
+ (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
if (dwError != ERROR_SUCCESS)
goto done;
}
0,
REG_SZ,
(LPBYTE)lpLoadOrderGroup,
- (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
+ (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
if (dwError != ERROR_SUCCESS)
goto done;
}
if (lpDependencies != NULL && *lpDependencies != 0)
{
dwError = ScmWriteDependencies(hServiceKey,
- (LPWSTR)lpDependencies,
+ (LPCWSTR)lpDependencies,
dwDependSize);
if (dwError != ERROR_SUCCESS)
goto done;
0,
REG_SZ,
(LPBYTE)lpObjectName,
- (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
+ (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
if (dwError != ERROR_SUCCESS)
goto done;
}
if (lpPassword != NULL)
{
- /* FIXME: Write password */
+ /* FIXME: Decrypt and write password */
}
dwError = ScmCreateServiceHandle(lpService,
lpService->dwRefCount = 1;
DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
-done:;
+done:
/* Unlock the service database */
ScmUnlockDatabase();
}
else
{
- /* Release the display name buffer */
- if (lpService->lpServiceName != NULL)
+ if (lpService != NULL &&
+ lpService->lpServiceName != NULL)
+ {
+ /* Release the display name buffer */
HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
+ }
if (hServiceHandle)
{
return ERROR_INVALID_HANDLE;
}
- lpService = hSvc->ServiceEntry;
-
- /* Check access rights */
- if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
- SC_MANAGER_ENUMERATE_SERVICE))
- {
- DPRINT("Insufficient access rights! 0x%lx\n",
- hSvc->Handle.DesiredAccess);
- return ERROR_ACCESS_DENIED;
- }
-
- /* Open the Services Reg key */
- dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
- L"System\\CurrentControlSet\\Services",
- 0,
- KEY_READ,
- &hServicesKey);
- if (dwError != ERROR_SUCCESS)
- return dwError;
-
- /* First determine the bytes needed and get the number of dependent services */
- dwError = Int_EnumDependentServicesW(hServicesKey,
- lpService,
- dwServiceState,
- NULL,
- pcbBytesNeeded,
- &dwServicesReturned);
- if (dwError != ERROR_SUCCESS)
- goto Done;
-
- /* If buffer size is less than the bytes needed or pointer is null */
- if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
- {
- dwError = ERROR_MORE_DATA;
- goto Done;
- }
-
- /* Allocate memory for array of service pointers */
- lpServicesArray = HeapAlloc(GetProcessHeap(),
- 0,
- (dwServicesReturned + 1) * sizeof(PSERVICE));
- if (!lpServicesArray)
- {
- DPRINT("Could not allocate a buffer!!\n");
- dwError = ERROR_NOT_ENOUGH_MEMORY;
- goto Done;
- }
-
- dwServicesReturned = 0;
- *pcbBytesNeeded = 0;
-
- dwError = Int_EnumDependentServicesW(hServicesKey,
- lpService,
- dwServiceState,
- lpServicesArray,
- pcbBytesNeeded,
- &dwServicesReturned);
- if (dwError != ERROR_SUCCESS)
- {
- goto Done;
- }
-
- lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
- lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
-
- /* Copy EnumDepenedentService to Buffer */
- for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
- {
- lpService = lpServicesArray[dwServiceCount];
-
- /* Copy status info */
- memcpy(&lpServicesPtr->ServiceStatus,
- &lpService->Status,
- sizeof(SERVICE_STATUS));
-
- /* Copy display name */
- wcscpy(lpStr, lpService->lpDisplayName);
- lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
- lpStr += (wcslen(lpService->lpDisplayName) + 1);
-
- /* Copy service name */
- wcscpy(lpStr, lpService->lpServiceName);
- lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
- lpStr += (wcslen(lpService->lpServiceName) + 1);
-
- lpServicesPtr ++;
- }
-
- *lpServicesReturned = dwServicesReturned;
-
-Done:
- if (lpServicesArray != NULL)
- HeapFree(GetProcessHeap(), 0, lpServicesArray);
-
- RegCloseKey(hServicesKey);
-
- DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
-
- return dwError;
-}
-
-
-/* Function 14 */
-DWORD REnumServicesStatusW(
- SC_RPC_HANDLE hSCManager,
- DWORD dwServiceType,
- DWORD dwServiceState,
- LPBYTE lpBuffer,
- DWORD dwBufSize,
- LPBOUNDED_DWORD_256K pcbBytesNeeded,
- LPBOUNDED_DWORD_256K lpServicesReturned,
- LPBOUNDED_DWORD_256K lpResumeHandle)
-{
- PMANAGER_HANDLE hManager;
- PSERVICE lpService;
- DWORD dwError = ERROR_SUCCESS;
- PLIST_ENTRY ServiceEntry;
- PSERVICE CurrentService;
- DWORD dwState;
- DWORD dwRequiredSize;
- DWORD dwServiceCount;
- DWORD dwSize;
- DWORD dwLastResumeCount = 0;
- LPENUM_SERVICE_STATUSW lpStatusPtr;
- LPWSTR lpStringPtr;
-
- DPRINT("REnumServicesStatusW() called\n");
-
- if (ScmShutdown)
- return ERROR_SHUTDOWN_IN_PROGRESS;
-
- hManager = ScmGetServiceManagerFromHandle(hSCManager);
- if (hManager == NULL)
- {
- DPRINT1("Invalid service manager handle!\n");
- return ERROR_INVALID_HANDLE;
- }
-
-
- *pcbBytesNeeded = 0;
- *lpServicesReturned = 0;
-
- if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
- {
- DPRINT("Not a valid Service Type!\n");
- return ERROR_INVALID_PARAMETER;
- }
-
- if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
- {
- DPRINT("Not a valid Service State!\n");
- return ERROR_INVALID_PARAMETER;
- }
-
- /* Check access rights */
- if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
- SC_MANAGER_ENUMERATE_SERVICE))
- {
- DPRINT("Insufficient access rights! 0x%lx\n",
- hManager->Handle.DesiredAccess);
- return ERROR_ACCESS_DENIED;
- }
-
- if (lpResumeHandle)
- dwLastResumeCount = *lpResumeHandle;
-
- /* Lock the service database shared */
- ScmLockDatabaseShared();
-
- lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
- if (lpService == NULL)
- {
- dwError = ERROR_SUCCESS;
- goto Done;
- }
-
- dwRequiredSize = 0;
- dwServiceCount = 0;
-
- for (ServiceEntry = &lpService->ServiceListEntry;
- ServiceEntry != &ServiceListHead;
- ServiceEntry = ServiceEntry->Flink)
- {
- CurrentService = CONTAINING_RECORD(ServiceEntry,
- SERVICE,
- ServiceListEntry);
-
- if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
- continue;
-
- dwState = SERVICE_ACTIVE;
- if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
- dwState = SERVICE_INACTIVE;
-
- if ((dwState & dwServiceState) == 0)
- continue;
-
- dwSize = sizeof(ENUM_SERVICE_STATUSW) +
- ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
- ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
-
- if (dwRequiredSize + dwSize > dwBufSize)
- {
- DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
- break;
- }
-
- DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
- dwRequiredSize += dwSize;
- dwServiceCount++;
- dwLastResumeCount = CurrentService->dwResumeCount;
- }
-
- DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
- DPRINT("dwServiceCount: %lu\n", dwServiceCount);
+ lpService = hSvc->ServiceEntry;
- for (;
- ServiceEntry != &ServiceListHead;
- ServiceEntry = ServiceEntry->Flink)
+ /* Check access rights */
+ if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+ SC_MANAGER_ENUMERATE_SERVICE))
{
- CurrentService = CONTAINING_RECORD(ServiceEntry,
- SERVICE,
- ServiceListEntry);
-
- if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
- continue;
-
- dwState = SERVICE_ACTIVE;
- if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
- dwState = SERVICE_INACTIVE;
+ DPRINT("Insufficient access rights! 0x%lx\n",
+ hSvc->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
- if ((dwState & dwServiceState) == 0)
- continue;
+ /* Open the Services Reg key */
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"System\\CurrentControlSet\\Services",
+ 0,
+ KEY_READ,
+ &hServicesKey);
+ if (dwError != ERROR_SUCCESS)
+ return dwError;
- dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
- ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
- ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
+ /* First determine the bytes needed and get the number of dependent services */
+ dwError = Int_EnumDependentServicesW(hServicesKey,
+ lpService,
+ dwServiceState,
+ NULL,
+ pcbBytesNeeded,
+ &dwServicesReturned);
+ if (dwError != ERROR_SUCCESS)
+ goto Done;
+ /* If buffer size is less than the bytes needed or pointer is null */
+ if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
+ {
dwError = ERROR_MORE_DATA;
+ goto Done;
}
- DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
-
- if (lpResumeHandle)
- *lpResumeHandle = dwLastResumeCount;
-
- *lpServicesReturned = dwServiceCount;
- *pcbBytesNeeded = dwRequiredSize;
+ /* Allocate memory for array of service pointers */
+ lpServicesArray = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (dwServicesReturned + 1) * sizeof(PSERVICE));
+ if (!lpServicesArray)
+ {
+ DPRINT1("Could not allocate a buffer!!\n");
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto Done;
+ }
- lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
- lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
- dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
+ dwServicesReturned = 0;
+ *pcbBytesNeeded = 0;
- dwRequiredSize = 0;
- for (ServiceEntry = &lpService->ServiceListEntry;
- ServiceEntry != &ServiceListHead;
- ServiceEntry = ServiceEntry->Flink)
+ dwError = Int_EnumDependentServicesW(hServicesKey,
+ lpService,
+ dwServiceState,
+ lpServicesArray,
+ pcbBytesNeeded,
+ &dwServicesReturned);
+ if (dwError != ERROR_SUCCESS)
{
- CurrentService = CONTAINING_RECORD(ServiceEntry,
- SERVICE,
- ServiceListEntry);
+ goto Done;
+ }
- if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
- continue;
+ lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
+ lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
- dwState = SERVICE_ACTIVE;
- if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
- dwState = SERVICE_INACTIVE;
+ /* Copy EnumDepenedentService to Buffer */
+ for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
+ {
+ lpService = lpServicesArray[dwServiceCount];
- if ((dwState & dwServiceState) == 0)
- continue;
+ /* Copy status info */
+ memcpy(&lpServicesPtr->ServiceStatus,
+ &lpService->Status,
+ sizeof(SERVICE_STATUS));
- dwSize = sizeof(ENUM_SERVICE_STATUSW) +
- ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
- ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
+ /* Copy display name */
+ wcscpy(lpStr, lpService->lpDisplayName);
+ lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
+ lpStr += (wcslen(lpService->lpDisplayName) + 1);
- if (dwRequiredSize + dwSize > dwBufSize)
- break;
+ /* Copy service name */
+ wcscpy(lpStr, lpService->lpServiceName);
+ lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
+ lpStr += (wcslen(lpService->lpServiceName) + 1);
- /* Copy the service name */
- wcscpy(lpStringPtr, CurrentService->lpServiceName);
- lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
- lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
+ lpServicesPtr++;
+ }
- /* Copy the display name */
- wcscpy(lpStringPtr, CurrentService->lpDisplayName);
- lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
- lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
+ *lpServicesReturned = dwServicesReturned;
- /* Copy the status information */
- memcpy(&lpStatusPtr->ServiceStatus,
- &CurrentService->Status,
- sizeof(SERVICE_STATUS));
+Done:
+ if (lpServicesArray != NULL)
+ HeapFree(GetProcessHeap(), 0, lpServicesArray);
- lpStatusPtr++;
- dwRequiredSize += dwSize;
- }
+ RegCloseKey(hServicesKey);
- if (dwError == 0)
- {
- *pcbBytesNeeded = 0;
- if (lpResumeHandle) *lpResumeHandle = 0;
- }
+ DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
-Done:;
- /* Unlock the service database */
- ScmUnlockDatabase();
+ return dwError;
+}
- DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
- return dwError;
+/* Function 14 */
+DWORD REnumServicesStatusW(
+ SC_RPC_HANDLE hSCManager,
+ DWORD dwServiceType,
+ DWORD dwServiceState,
+ LPBYTE lpBuffer,
+ DWORD dwBufSize,
+ LPBOUNDED_DWORD_256K pcbBytesNeeded,
+ LPBOUNDED_DWORD_256K lpServicesReturned,
+ LPBOUNDED_DWORD_256K lpResumeHandle)
+{
+ /* Enumerate all the services, not regarding of their group */
+ return REnumServiceGroupW(hSCManager,
+ dwServiceType,
+ dwServiceState,
+ lpBuffer,
+ dwBufSize,
+ pcbBytesNeeded,
+ lpServicesReturned,
+ lpResumeHandle,
+ NULL);
}
*lpServiceHandle = (SC_RPC_HANDLE)hHandle;
DPRINT("*hService = %p\n", *lpServiceHandle);
-Done:;
+Done:
/* Unlock the service database */
ScmUnlockDatabase();
LPWSTR lpDependencies = NULL;
DWORD dwDependenciesLength = 0;
DWORD dwRequiredSize;
- LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
WCHAR lpEmptyString[] = {0,0};
LPWSTR lpStr;
dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
if (lpImagePath != NULL)
- dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
+ dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
else
dwRequiredSize += 2 * sizeof(WCHAR);
- if (lpService->lpGroup != NULL)
- dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
+ if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
+ dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
else
dwRequiredSize += 2 * sizeof(WCHAR);
dwRequiredSize += 2 * sizeof(WCHAR);
if (lpServiceStartName != NULL)
- dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
+ dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
else
dwRequiredSize += 2 * sizeof(WCHAR);
if (lpService->lpDisplayName != NULL)
- dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
+ dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
else
dwRequiredSize += 2 * sizeof(WCHAR);
}
else
{
- lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
- lpConfig->dwServiceType = lpService->Status.dwServiceType;
- lpConfig->dwStartType = lpService->dwStartType;
- lpConfig->dwErrorControl = lpService->dwErrorControl;
- lpConfig->dwTagId = lpService->dwTag;
+ lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
+ lpServiceConfig->dwStartType = lpService->dwStartType;
+ lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
+ lpServiceConfig->dwTagId = lpService->dwTag;
- lpStr = (LPWSTR)(lpConfig + 1);
+ lpStr = (LPWSTR)(lpServiceConfig + 1);
/* Append the image path */
if (lpImagePath != NULL)
wcscpy(lpStr, lpEmptyString);
}
- lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
lpStr += (wcslen(lpStr) + 1);
/* Append the group name */
- if (lpService->lpGroup != NULL)
+ if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
{
wcscpy(lpStr, lpService->lpGroup->lpGroupName);
}
wcscpy(lpStr, lpEmptyString);
}
- lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
lpStr += (wcslen(lpStr) + 1);
/* Append Dependencies */
wcscpy(lpStr, lpEmptyString);
}
- lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
if (lpDependencies != NULL)
- lpStr += dwDependenciesLength * sizeof(WCHAR);
+ lpStr += dwDependenciesLength;
else
lpStr += (wcslen(lpStr) + 1);
wcscpy(lpStr, lpEmptyString);
}
- lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
lpStr += (wcslen(lpStr) + 1);
/* Append the display name */
wcscpy(lpStr, lpEmptyString);
}
- lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
}
if (pcbBytesNeeded != NULL)
*pcbBytesNeeded = dwRequiredSize;
-Done:;
+Done:
/* Unlock the service database */
ScmUnlockDatabase();
/* Function 18 */
DWORD RQueryServiceLockStatusW(
SC_RPC_HANDLE hSCManager,
- LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
+ LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
DWORD cbBufSize,
LPBOUNDED_DWORD_4K pcbBytesNeeded)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf;
+ PMANAGER_HANDLE hMgr;
+ DWORD dwRequiredSize;
+
+ if (!lpLockStatus || !pcbBytesNeeded)
+ return ERROR_INVALID_PARAMETER;
+
+ hMgr = ScmGetServiceManagerFromHandle(hSCManager);
+ if (hMgr == NULL)
+ {
+ DPRINT1("Invalid service manager handle!\n");
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
+ SC_MANAGER_QUERY_LOCK_STATUS))
+ {
+ DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ /* FIXME: we need to compute instead the real length of the owner name */
+ dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
+ *pcbBytesNeeded = dwRequiredSize;
+
+ if (cbBufSize < dwRequiredSize)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ ScmQueryServiceLockStatusW(lpLockStatus);
+
+ return ERROR_SUCCESS;
}
PSERVICE_HANDLE hSvc;
PSERVICE lpService = NULL;
- DPRINT("RStartServiceW() called\n");
+#ifndef NDEBUG
+ DWORD i;
+
+ DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
+ DPRINT(" argc: %lu\n", argc);
+ if (argv != NULL)
+ {
+ for (i = 0; i < argc; i++)
+ {
+ DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
+ }
+ }
+#endif
if (ScmShutdown)
return ERROR_SHUTDOWN_IN_PROGRESS;
if (lpService->bDeleted)
return ERROR_SERVICE_MARKED_FOR_DELETE;
- if (argv) {
- UNIMPLEMENTED;
- argv = NULL;
- }
-
/* Start the service */
- dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
+ dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
return dwError;
}
*lpcchBuffer = 2;
if (lpDisplayName != NULL)
{
- *lpDisplayName = '\0';
+ *lpDisplayName = 0;
}
}
if (!lpService->lpDisplayName)
{
- dwLength = wcslen(lpService->lpServiceName);
+ dwLength = (DWORD)wcslen(lpService->lpServiceName);
if (lpDisplayName != NULL &&
*lpcchBuffer > dwLength)
}
else
{
- dwLength = wcslen(lpService->lpDisplayName);
+ dwLength = (DWORD)wcslen(lpService->lpDisplayName);
if (lpDisplayName != NULL &&
*lpcchBuffer > dwLength)
*lpcchBuffer = 2;
if (lpServiceName != NULL)
{
- *lpServiceName = '\0';
+ *lpServiceName = 0;
}
}
return ERROR_SERVICE_DOES_NOT_EXIST;
}
- dwLength = wcslen(lpService->lpServiceName);
+ dwLength = (DWORD)wcslen(lpService->lpServiceName);
if (lpServiceName != NULL &&
*lpcchBuffer > dwLength)
LPSTR lpBinaryPathName,
LPSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
- LPSTR lpDependencies,
+ LPBYTE lpDependencies,
DWORD dwDependSize,
LPSTR lpServiceStartName,
LPBYTE lpPassword,
PSERVICE lpService = NULL;
HKEY hServiceKey = NULL;
LPWSTR lpDisplayNameW = NULL;
- // LPWSTR lpBinaryPathNameW = NULL;
+ LPWSTR lpBinaryPathNameW = NULL;
+ LPWSTR lpCanonicalImagePathW = NULL;
LPWSTR lpLoadOrderGroupW = NULL;
LPWSTR lpDependenciesW = NULL;
- // LPWSTR lpPasswordW = NULL;
DPRINT("RChangeServiceConfigA() called\n");
DPRINT("dwServiceType = %lu\n", dwServiceType);
{
/* Set the display name */
lpDisplayNameW = HeapAlloc(GetProcessHeap(),
- 0,
+ HEAP_ZERO_MEMORY,
(strlen(lpDisplayName) + 1) * sizeof(WCHAR));
if (lpDisplayNameW == NULL)
{
lpDisplayName,
-1,
lpDisplayNameW,
- strlen(lpDisplayName) + 1);
+ (int)(strlen(lpDisplayName) + 1));
RegSetValueExW(hServiceKey,
L"DisplayName",
0,
REG_SZ,
(LPBYTE)lpDisplayNameW,
- (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
+ (DWORD)((wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR)));
/* Update lpService->lpDisplayName */
if (lpService->lpDisplayName)
lpService->dwErrorControl = dwErrorControl;
}
-#if 0
- /* FIXME: set the new ImagePath value */
-
- /* Set the image path */
- if (dwServiceType & SERVICE_WIN32)
+ if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
{
- if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
+ /* Set the image path */
+ lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
+ if (lpBinaryPathNameW == NULL)
{
- lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
- MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, strlen(lpBinaryPathName)+1);
- dwError = RegSetValueExW(hServiceKey,
- L"ImagePath",
- 0,
- REG_EXPAND_SZ,
- (LPBYTE)lpBinaryPathNameW,
- (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
- if (dwError != ERROR_SUCCESS)
- goto done;
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
}
- }
- else if (dwServiceType & SERVICE_DRIVER)
- {
- if (lpImagePath != NULL && *lpImagePath != 0)
+
+ MultiByteToWideChar(CP_ACP,
+ 0,
+ lpBinaryPathName,
+ -1,
+ lpBinaryPathNameW,
+ (int)(strlen(lpBinaryPathName) + 1));
+
+ if (lpService->Status.dwServiceType & SERVICE_DRIVER)
{
- dwError = RegSetValueExW(hServiceKey,
- L"ImagePath",
- 0,
- REG_EXPAND_SZ,
- (LPBYTE)lpImagePath,
- (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
+ dwError = ScmCanonDriverImagePath(lpService->dwStartType,
+ lpBinaryPathNameW,
+ &lpCanonicalImagePathW);
+
+ HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
+
if (dwError != ERROR_SUCCESS)
goto done;
+
+ lpBinaryPathNameW = lpCanonicalImagePathW;
}
+
+ dwError = RegSetValueExW(hServiceKey,
+ L"ImagePath",
+ 0,
+ REG_EXPAND_SZ,
+ (LPBYTE)lpBinaryPathNameW,
+ (DWORD)((wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR)));
+
+ HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
+
+ if (dwError != ERROR_SUCCESS)
+ goto done;
}
-#endif
/* Set the group name */
if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
{
lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
- 0,
+ HEAP_ZERO_MEMORY,
(strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
if (lpLoadOrderGroupW == NULL)
{
lpLoadOrderGroup,
-1,
lpLoadOrderGroupW,
- strlen(lpLoadOrderGroup) + 1);
+ (int)(strlen(lpLoadOrderGroup) + 1));
dwError = RegSetValueExW(hServiceKey,
L"Group",
0,
REG_SZ,
(LPBYTE)lpLoadOrderGroupW,
- (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
+ (DWORD)((wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR)));
if (dwError != ERROR_SUCCESS)
{
HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
if (lpDependencies != NULL && *lpDependencies != 0)
{
lpDependenciesW = HeapAlloc(GetProcessHeap(),
- 0,
- (strlen(lpDependencies) + 1) * sizeof(WCHAR));
+ HEAP_ZERO_MEMORY,
+ (strlen((LPSTR)lpDependencies) + 1) * sizeof(WCHAR));
if (lpDependenciesW == NULL)
{
dwError = ERROR_NOT_ENOUGH_MEMORY;
MultiByteToWideChar(CP_ACP,
0,
- lpDependencies,
+ (LPSTR)lpDependencies,
dwDependSize,
lpDependenciesW,
- strlen(lpDependencies) + 1);
+ (int)(strlen((LPSTR)lpDependencies) + 1));
dwError = ScmWriteDependencies(hServiceKey,
(LPWSTR)lpDependenciesW,
if (lpPassword != NULL)
{
- /* FIXME: Write password */
+ /* FIXME: Decrypt and write password */
}
done:
LPWSTR lpDependenciesW = NULL;
LPWSTR lpServiceStartNameW = NULL;
DWORD dwDependenciesLength = 0;
- DWORD dwLength;
+ SIZE_T cchLength;
int len;
- LPSTR lpStr;
+ LPCSTR lpStr;
if (lpServiceName)
{
len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
- lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
if (!lpServiceNameW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
if (lpDisplayName)
{
len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
- lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
if (!lpDisplayNameW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
if (lpBinaryPathName)
{
len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
- lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
if (!lpBinaryPathNameW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
if (lpLoadOrderGroup)
{
len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
- lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
if (!lpLoadOrderGroupW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
if (lpDependencies)
{
- lpStr = (LPSTR)lpDependencies;
+ lpStr = (LPCSTR)lpDependencies;
while (*lpStr)
{
- dwLength = strlen(lpStr) + 1;
- dwDependenciesLength += dwLength;
- lpStr = lpStr + dwLength;
+ cchLength = strlen(lpStr) + 1;
+ dwDependenciesLength += (DWORD)cchLength;
+ lpStr = lpStr + cchLength;
}
dwDependenciesLength++;
- lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR));
+ lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
if (!lpDependenciesW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto cleanup;
}
- MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
+ MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
}
if (lpServiceStartName)
{
len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
- lpServiceStartNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+ lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
if (!lpServiceStartNameW)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
/* Allocate memory for array of service pointers */
lpServicesArray = HeapAlloc(GetProcessHeap(),
- 0,
+ HEAP_ZERO_MEMORY,
(dwServicesReturned + 1) * sizeof(PSERVICE));
if (!lpServicesArray)
{
lpService->lpDisplayName,
-1,
lpStr,
- wcslen(lpService->lpDisplayName),
+ (int)wcslen(lpService->lpDisplayName),
0,
0);
lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
lpService->lpServiceName,
-1,
lpStr,
- wcslen(lpService->lpServiceName),
+ (int)wcslen(lpService->lpServiceName),
0,
0);
lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
lpStr += strlen(lpStr) + 1;
- lpServicesPtr ++;
+ lpServicesPtr++;
}
*lpServicesReturned = dwServicesReturned;
LPBOUNDED_DWORD_256K lpResumeHandle)
{
LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
+ LPENUM_SERVICE_STATUSW lpStatusPtrIncrW;
LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
LPWSTR lpStringPtrW;
LPSTR lpStringPtrA;
DPRINT("REnumServicesStatusA() called\n");
+ if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
+ {
+ return ERROR_INVALID_ADDRESS;
+ }
+
if ((dwBufSize > 0) && (lpBuffer))
{
lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
if (*lpServicesReturned == 0)
goto Done;
+ lpStatusPtrIncrW = lpStatusPtrW;
lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
*lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
lpStringPtrW,
-1,
lpStringPtrA,
- wcslen(lpStringPtrW),
+ (int)wcslen(lpStringPtrW),
0,
0);
lpStringPtrW,
-1,
lpStringPtrA,
- wcslen(lpStringPtrW),
+ (int)wcslen(lpStringPtrW),
0,
0);
/* Copy the status information */
memcpy(&lpStatusPtrA->ServiceStatus,
- &lpStatusPtrW->ServiceStatus,
+ &lpStatusPtrIncrW->ServiceStatus,
sizeof(SERVICE_STATUS));
+ lpStatusPtrIncrW++;
lpStatusPtrA++;
}
-Done:;
+Done:
if (lpStatusPtrW)
HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
LPWSTR lpDependencies = NULL;
DWORD dwDependenciesLength = 0;
DWORD dwRequiredSize;
- LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
CHAR lpEmptyString[]={0,0};
LPSTR lpStr;
&lpDependencies,
&dwDependenciesLength);
- dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
+ dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGA);
if (lpImagePath != NULL)
- dwRequiredSize += wcslen(lpImagePath) + 1;
+ dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
else
dwRequiredSize += 2;
if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
- dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
+ dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
else
dwRequiredSize += 2;
dwRequiredSize += 2;
if (lpServiceStartName != NULL)
- dwRequiredSize += wcslen(lpServiceStartName) + 1;
+ dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
else
dwRequiredSize += 2;
if (lpService->lpDisplayName != NULL)
- dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
+ dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
else
dwRequiredSize += 2;
}
else
{
- lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
- lpConfig->dwServiceType = lpService->Status.dwServiceType;
- lpConfig->dwStartType = lpService->dwStartType;
- lpConfig->dwErrorControl = lpService->dwErrorControl;
- lpConfig->dwTagId = lpService->dwTag;
+ lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
+ lpServiceConfig->dwStartType = lpService->dwStartType;
+ lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
+ lpServiceConfig->dwTagId = lpService->dwTag;
lpStr = (LPSTR)(lpServiceConfig + 1);
/* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
- Verified in WINXP*/
+ Verified in WINXP */
if (lpImagePath)
{
lpImagePath,
-1,
lpStr,
- wcslen(lpImagePath) + 1,
+ (int)(wcslen(lpImagePath) + 1),
0,
0);
}
strcpy(lpStr, lpEmptyString);
}
- lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
lpStr += (strlen((LPSTR)lpStr) + 1);
if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
lpService->lpGroup->lpGroupName,
-1,
lpStr,
- wcslen(lpService->lpGroup->lpGroupName) + 1,
+ (int)(wcslen(lpService->lpGroup->lpGroupName) + 1),
0,
0);
}
strcpy(lpStr, lpEmptyString);
}
- lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
lpStr += (strlen(lpStr) + 1);
/* Append Dependencies */
strcpy(lpStr, lpEmptyString);
}
- lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
if (lpDependencies)
lpStr += dwDependenciesLength;
else
lpServiceStartName,
-1,
lpStr,
- wcslen(lpServiceStartName) + 1,
+ (int)(wcslen(lpServiceStartName) + 1),
0,
0);
}
strcpy(lpStr, lpEmptyString);
}
- lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
lpStr += (strlen(lpStr) + 1);
if (lpService->lpDisplayName)
lpService->lpDisplayName,
-1,
lpStr,
- wcslen(lpService->lpDisplayName) + 1,
+ (int)(wcslen(lpService->lpDisplayName) + 1),
0,
0);
}
strcpy(lpStr, lpEmptyString);
}
- lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+ lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
}
if (pcbBytesNeeded != NULL)
*pcbBytesNeeded = dwRequiredSize;
-Done:;
+Done:
/* Unlock the service database */
ScmUnlockDatabase();
/* Function 30 */
DWORD RQueryServiceLockStatusA(
SC_RPC_HANDLE hSCManager,
- LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
+ LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
DWORD cbBufSize,
LPBOUNDED_DWORD_4K pcbBytesNeeded)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSA)lpBuf;
+ PMANAGER_HANDLE hMgr;
+ DWORD dwRequiredSize;
+
+ if (!lpLockStatus || !pcbBytesNeeded)
+ return ERROR_INVALID_PARAMETER;
+
+ hMgr = ScmGetServiceManagerFromHandle(hSCManager);
+ if (hMgr == NULL)
+ {
+ DPRINT1("Invalid service manager handle!\n");
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
+ SC_MANAGER_QUERY_LOCK_STATUS))
+ {
+ DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ /* FIXME: we need to compute instead the real length of the owner name */
+ dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR);
+ *pcbBytesNeeded = dwRequiredSize;
+
+ if (cbBufSize < dwRequiredSize)
+ return ERROR_INSUFFICIENT_BUFFER;
+
+ ScmQueryServiceLockStatusA(lpLockStatus);
+
+ return ERROR_SUCCESS;
}
DWORD dwError = ERROR_SUCCESS;
PSERVICE_HANDLE hSvc;
PSERVICE lpService = NULL;
+ LPWSTR *lpVector = NULL;
+ DWORD i;
+ DWORD dwLength;
DPRINT("RStartServiceA() called\n");
if (lpService->bDeleted)
return ERROR_SERVICE_MARKED_FOR_DELETE;
- /* FIXME: Convert argument vector to Unicode */
+ /* Build a Unicode argument vector */
+ if (argc > 0)
+ {
+ lpVector = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ argc * sizeof(LPWSTR));
+ if (lpVector == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ for (i = 0; i < argc; i++)
+ {
+ dwLength = MultiByteToWideChar(CP_ACP,
+ 0,
+ ((LPSTR*)argv)[i],
+ -1,
+ NULL,
+ 0);
+
+ lpVector[i] = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ dwLength * sizeof(WCHAR));
+ if (lpVector[i] == NULL)
+ {
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ MultiByteToWideChar(CP_ACP,
+ 0,
+ ((LPSTR*)argv)[i],
+ -1,
+ lpVector[i],
+ dwLength);
+ }
+ }
/* Start the service */
- dwError = ScmStartService(lpService, 0, NULL);
+ dwError = ScmStartService(lpService, argc, lpVector);
- /* FIXME: Free argument vector */
+done:
+ /* Free the Unicode argument vector */
+ if (lpVector != NULL)
+ {
+ for (i = 0; i < argc; i++)
+ {
+ if (lpVector[i] != NULL)
+ HeapFree(GetProcessHeap(), 0, lpVector[i]);
+ }
+ HeapFree(GetProcessHeap(), 0, lpVector);
+ }
return dwError;
}
if (lpServiceName != NULL)
{
- dwLength = strlen(lpServiceName) + 1;
+ dwLength = (DWORD)(strlen(lpServiceName) + 1);
lpServiceNameW = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwLength * sizeof(WCHAR));
*lpcchBuffer = 1;
if (lpDisplayName != NULL)
{
- *lpDisplayName = '\0';
+ *lpDisplayName = 0;
}
}
return ERROR_SERVICE_DOES_NOT_EXIST;
if (!lpService->lpDisplayName)
{
- dwLength = wcslen(lpService->lpServiceName);
+ dwLength = (DWORD)wcslen(lpService->lpServiceName);
if (lpDisplayName != NULL &&
*lpcchBuffer > dwLength)
{
WideCharToMultiByte(CP_ACP,
0,
lpService->lpServiceName,
- wcslen(lpService->lpServiceName),
+ (int)wcslen(lpService->lpServiceName),
lpDisplayName,
dwLength + 1,
NULL,
}
else
{
- dwLength = wcslen(lpService->lpDisplayName);
+ dwLength = (DWORD)wcslen(lpService->lpDisplayName);
if (lpDisplayName != NULL &&
*lpcchBuffer > dwLength)
{
WideCharToMultiByte(CP_ACP,
0,
lpService->lpDisplayName,
- wcslen(lpService->lpDisplayName),
+ (int)wcslen(lpService->lpDisplayName),
lpDisplayName,
dwLength + 1,
NULL,
DPRINT("lpServiceName: %p\n", lpServiceName);
DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
- dwLength = strlen(lpDisplayName) + 1;
+ dwLength = (DWORD)(strlen(lpDisplayName) + 1);
lpDisplayNameW = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwLength * sizeof(WCHAR));
*lpcchBuffer = 1;
if (lpServiceName != NULL)
{
- *lpServiceName = '\0';
+ *lpServiceName = 0;
}
}
return ERROR_SERVICE_DOES_NOT_EXIST;
}
- dwLength = wcslen(lpService->lpServiceName);
+ dwLength = (DWORD)wcslen(lpService->lpServiceName);
if (lpServiceName != NULL &&
*lpcchBuffer > dwLength)
{
WideCharToMultiByte(CP_ACP,
0,
lpService->lpServiceName,
- wcslen(lpService->lpServiceName),
+ (int)wcslen(lpService->lpServiceName),
lpServiceName,
dwLength + 1,
NULL,
LPBOUNDED_DWORD_256K lpResumeIndex,
LPCWSTR pszGroupName)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ PMANAGER_HANDLE hManager;
+ PSERVICE lpService;
+ DWORD dwError = ERROR_SUCCESS;
+ PLIST_ENTRY ServiceEntry;
+ PSERVICE CurrentService;
+ DWORD dwState;
+ DWORD dwRequiredSize;
+ DWORD dwServiceCount;
+ DWORD dwSize;
+ DWORD dwLastResumeCount = 0;
+ LPENUM_SERVICE_STATUSW lpStatusPtr;
+ LPWSTR lpStringPtr;
+
+ DPRINT("REnumServiceGroupW() called\n");
+
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
+
+ hManager = ScmGetServiceManagerFromHandle(hSCManager);
+ if (hManager == NULL)
+ {
+ DPRINT1("Invalid service manager handle!\n");
+ return ERROR_INVALID_HANDLE;
+ }
+
+ if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
+ {
+ return ERROR_INVALID_ADDRESS;
+ }
+
+ *pcbBytesNeeded = 0;
+ *lpServicesReturned = 0;
+
+ if ((dwServiceType == 0) ||
+ ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
+ {
+ DPRINT("Not a valid Service Type!\n");
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if ((dwServiceState == 0) ||
+ ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
+ {
+ DPRINT("Not a valid Service State!\n");
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Check access rights */
+ if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
+ SC_MANAGER_ENUMERATE_SERVICE))
+ {
+ DPRINT("Insufficient access rights! 0x%lx\n",
+ hManager->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ if (lpResumeIndex)
+ dwLastResumeCount = *lpResumeIndex;
+
+ /* Lock the service database shared */
+ ScmLockDatabaseShared();
+
+ lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
+ if (lpService == NULL)
+ {
+ dwError = ERROR_SUCCESS;
+ goto Done;
+ }
+
+ dwRequiredSize = 0;
+ dwServiceCount = 0;
+
+ for (ServiceEntry = &lpService->ServiceListEntry;
+ ServiceEntry != &ServiceListHead;
+ ServiceEntry = ServiceEntry->Flink)
+ {
+ CurrentService = CONTAINING_RECORD(ServiceEntry,
+ SERVICE,
+ ServiceListEntry);
+
+ if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
+ continue;
+
+ dwState = SERVICE_ACTIVE;
+ if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+ dwState = SERVICE_INACTIVE;
+
+ if ((dwState & dwServiceState) == 0)
+ continue;
+
+ if (pszGroupName)
+ {
+ if (*pszGroupName == 0)
+ {
+ if (CurrentService->lpGroup != NULL)
+ continue;
+ }
+ else
+ {
+ if ((CurrentService->lpGroup == NULL) ||
+ _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
+ continue;
+ }
+ }
+
+ dwSize = sizeof(ENUM_SERVICE_STATUSW) +
+ (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
+ (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
+
+ if (dwRequiredSize + dwSize > cbBufSize)
+ {
+ DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
+ break;
+ }
+
+ DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
+ dwRequiredSize += dwSize;
+ dwServiceCount++;
+ dwLastResumeCount = CurrentService->dwResumeCount;
+ }
+
+ DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
+ DPRINT("dwServiceCount: %lu\n", dwServiceCount);
+
+ for (;
+ ServiceEntry != &ServiceListHead;
+ ServiceEntry = ServiceEntry->Flink)
+ {
+ CurrentService = CONTAINING_RECORD(ServiceEntry,
+ SERVICE,
+ ServiceListEntry);
+
+ if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
+ continue;
+
+ dwState = SERVICE_ACTIVE;
+ if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+ dwState = SERVICE_INACTIVE;
+
+ if ((dwState & dwServiceState) == 0)
+ continue;
+
+ if (pszGroupName)
+ {
+ if (*pszGroupName == 0)
+ {
+ if (CurrentService->lpGroup != NULL)
+ continue;
+ }
+ else
+ {
+ if ((CurrentService->lpGroup == NULL) ||
+ _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
+ continue;
+ }
+ }
+
+ dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
+ (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
+ (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
+
+ dwError = ERROR_MORE_DATA;
+ }
+
+ DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
+
+ if (lpResumeIndex)
+ *lpResumeIndex = dwLastResumeCount;
+
+ *lpServicesReturned = dwServiceCount;
+ *pcbBytesNeeded = dwRequiredSize;
+
+ lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
+ lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
+ dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
+
+ dwRequiredSize = 0;
+ for (ServiceEntry = &lpService->ServiceListEntry;
+ ServiceEntry != &ServiceListHead;
+ ServiceEntry = ServiceEntry->Flink)
+ {
+ CurrentService = CONTAINING_RECORD(ServiceEntry,
+ SERVICE,
+ ServiceListEntry);
+
+ if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
+ continue;
+
+ dwState = SERVICE_ACTIVE;
+ if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+ dwState = SERVICE_INACTIVE;
+
+ if ((dwState & dwServiceState) == 0)
+ continue;
+
+ if (pszGroupName)
+ {
+ if (*pszGroupName == 0)
+ {
+ if (CurrentService->lpGroup != NULL)
+ continue;
+ }
+ else
+ {
+ if ((CurrentService->lpGroup == NULL) ||
+ _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
+ continue;
+ }
+ }
+
+ dwSize = sizeof(ENUM_SERVICE_STATUSW) +
+ (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
+ (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
+
+ if (dwRequiredSize + dwSize > cbBufSize)
+ break;
+
+ /* Copy the service name */
+ wcscpy(lpStringPtr, CurrentService->lpServiceName);
+ lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
+ lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
+
+ /* Copy the display name */
+ wcscpy(lpStringPtr, CurrentService->lpDisplayName);
+ lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
+ lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
+
+ /* Copy the status information */
+ memcpy(&lpStatusPtr->ServiceStatus,
+ &CurrentService->Status,
+ sizeof(SERVICE_STATUS));
+
+ lpStatusPtr++;
+ dwRequiredSize += dwSize;
+ }
+
+ if (dwError == ERROR_SUCCESS)
+ {
+ *pcbBytesNeeded = 0;
+ if (lpResumeIndex) *lpResumeIndex = 0;
+ }
+
+Done:
+ /* Unlock the service database */
+ ScmUnlockDatabase();
+
+ DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError);
+
+ return dwError;
}
-//
-// WARNING: This function is untested
-//
/* Function 36 */
DWORD RChangeServiceConfig2A(
SC_RPC_HANDLE hService,
if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
{
- LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
- LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
+ LPSERVICE_DESCRIPTIONW lpServiceDescriptionW;
+ //LPSERVICE_DESCRIPTIONA lpServiceDescriptionA;
- lpServiceDescriptonA = Info.psd;
+ //lpServiceDescriptionA = Info.psd;
- ///if (lpServiceDescriptonA &&
- ///lpServiceDescriptonA->lpDescription)
+ ///if (lpServiceDescriptionA &&
+ ///lpServiceDescriptionA->lpDescription)
///{
- dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR);
+ dwLength = (DWORD)((strlen(Info.lpDescription) + 1) * sizeof(WCHAR));
- lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
- 0,
- dwLength + sizeof(SERVICE_DESCRIPTIONW));
- if (!lpServiceDescriptonW)
+ lpServiceDescriptionW = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ dwLength + sizeof(SERVICE_DESCRIPTIONW));
+ if (!lpServiceDescriptionW)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
- lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
+ lpServiceDescriptionW->lpDescription = (LPWSTR)(lpServiceDescriptionW + 1);
MultiByteToWideChar(CP_ACP,
0,
Info.lpDescription,
-1,
- lpServiceDescriptonW->lpDescription,
+ lpServiceDescriptionW->lpDescription,
dwLength);
- ptr = lpServiceDescriptonW;
- InfoW.psd = lpServiceDescriptonW;
+ ptr = lpServiceDescriptionW;
+ InfoW.psd = lpServiceDescriptionW;
///}
}
else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
{
LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
- DWORD dwRebootLen = 0;
+ DWORD dwRebootLen = 0;
DWORD dwCommandLen = 0;
+ DWORD dwActionArrayLen = 0;
+ LPWSTR lpStr = NULL;
lpServiceFailureActionsA = Info.psfa;
if (lpServiceFailureActionsA)
{
+ /*
+ * The following code is inspired by the
+ * SERVICE_CONFIG_FAILURE_ACTIONS case of
+ * the RQueryServiceConfig2W function.
+ */
+
+ /* Retrieve the needed length for the two data strings */
if (lpServiceFailureActionsA->lpRebootMsg)
{
- dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
+ dwRebootLen = (DWORD)((strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR));
}
if (lpServiceFailureActionsA->lpCommand)
{
- dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
+ dwCommandLen = (DWORD)((strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR));
}
- dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
+ /*
+ * Retrieve the size of the lpsaActions array if needed.
+ * We will copy the lpsaActions array only if there is at
+ * least one action AND that the original array is valid.
+ */
+ if (lpServiceFailureActionsA->cActions > 0 && lpServiceFailureActionsA->lpsaActions)
+ {
+ dwActionArrayLen = lpServiceFailureActionsA->cActions * sizeof(SC_ACTION);
+ }
+
+ /* Compute the total length for the UNICODE structure, including data */
+ dwLength = sizeof(SERVICE_FAILURE_ACTIONSW) +
+ dwActionArrayLen + dwRebootLen + dwCommandLen;
+
+ /* Allocate the structure */
lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
- 0,
+ HEAP_ZERO_MEMORY,
dwLength);
if (!lpServiceFailureActionsW)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
- lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
+ /* Copy the members */
lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
- CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
+ lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
- if (lpServiceFailureActionsA->lpRebootMsg)
+ /* Copy the lpsaActions array if needed */
+ if (dwActionArrayLen > 0)
+ {
+ /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */
+ lpServiceFailureActionsW->lpsaActions = (LPSC_ACTION)((ULONG_PTR)(lpServiceFailureActionsW + 1));
+
+ /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */
+ RtlCopyMemory(lpServiceFailureActionsW->lpsaActions,
+ lpServiceFailureActionsA->lpsaActions,
+ dwActionArrayLen);
+ }
+ else
+ {
+ /* No lpsaActions array */
+ lpServiceFailureActionsW->lpsaActions = NULL;
+ }
+ /* The data strings are stored just after the lpsaActions array */
+ lpStr = (LPWSTR)((ULONG_PTR)(lpServiceFailureActionsW + 1) + dwActionArrayLen);
+
+ /*
+ * Convert the data strings to UNICODE
+ */
+
+ lpServiceFailureActionsW->lpRebootMsg = NULL;
+ lpServiceFailureActionsW->lpCommand = NULL;
+
+ if (dwRebootLen)
{
+ /* lpRebootMsg points just after the lpsaActions array */
+ lpServiceFailureActionsW->lpRebootMsg = lpStr;
+
MultiByteToWideChar(CP_ACP,
0,
lpServiceFailureActionsA->lpRebootMsg,
-1,
lpServiceFailureActionsW->lpRebootMsg,
dwRebootLen);
+
+ lpStr += dwRebootLen / sizeof(WCHAR);
}
- if (lpServiceFailureActionsA->lpCommand)
+ if (dwCommandLen)
{
+ /* lpRebootMsg points just after the lpRebootMsg data string */
+ lpServiceFailureActionsW->lpCommand = lpStr;
+
MultiByteToWideChar(CP_ACP,
0,
lpServiceFailureActionsA->lpCommand,
dwCommandLen);
}
+ /* Set the pointers */
ptr = lpServiceFailureActionsW;
+ InfoW.psfa = lpServiceFailureActionsW;
}
}
}
+static DWORD
+ScmSetFailureActions(PSERVICE_HANDLE hSvc,
+ PSERVICE lpService,
+ HKEY hServiceKey,
+ LPSERVICE_FAILURE_ACTIONSW lpFailureActions)
+{
+ LPSERVICE_FAILURE_ACTIONSW lpReadBuffer = NULL;
+ LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer = NULL;
+ BOOL bIsActionRebootSet = FALSE;
+ DWORD dwDesiredAccess = SERVICE_CHANGE_CONFIG;
+ DWORD dwRequiredSize = 0;
+ DWORD dwType = 0;
+ DWORD i = 0;
+ DWORD dwError;
+
+ /* There is nothing to be done if we have no failure actions */
+ if (lpFailureActions == NULL)
+ return ERROR_SUCCESS;
+
+ /*
+ * 1- Check whether or not we can set
+ * failure actions for this service.
+ */
+
+ /* Failure actions can only be set for Win32 services, not for drivers */
+ if (lpService->Status.dwServiceType & SERVICE_DRIVER)
+ return ERROR_CANNOT_DETECT_DRIVER_FAILURE;
+
+ /*
+ * If the service controller handles the SC_ACTION_RESTART action,
+ * hService must have the SERVICE_START access right.
+ *
+ * If you specify SC_ACTION_REBOOT, the caller must have the
+ * SE_SHUTDOWN_NAME privilege.
+ */
+ if (lpFailureActions->cActions > 0 &&
+ lpFailureActions->lpsaActions != NULL)
+ {
+ for (i = 0; i < lpFailureActions->cActions; ++i)
+ {
+ if (lpFailureActions->lpsaActions[i].Type == SC_ACTION_RESTART)
+ dwDesiredAccess |= SERVICE_START;
+ else if (lpFailureActions->lpsaActions[i].Type == SC_ACTION_REBOOT)
+ bIsActionRebootSet = TRUE;
+ }
+ }
+
+ /* Re-check the access rights */
+ if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+ dwDesiredAccess))
+ {
+ DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
+ if (bIsActionRebootSet)
+ {
+ }
+
+ /*
+ * 2- Retrieve the original value of FailureActions.
+ */
+
+ /* Query value length */
+ dwError = RegQueryValueExW(hServiceKey,
+ L"FailureActions",
+ NULL,
+ &dwType,
+ NULL,
+ &dwRequiredSize);
+ if (dwError != ERROR_SUCCESS &&
+ dwError != ERROR_MORE_DATA &&
+ dwError != ERROR_FILE_NOT_FOUND)
+ return dwError;
+
+ dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
+ : sizeof(SERVICE_FAILURE_ACTIONSW);
+
+ /* Initialize the read buffer */
+ lpReadBuffer = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ dwRequiredSize);
+ if (lpReadBuffer == NULL)
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ /* Now we can fill the read buffer */
+ if (dwError != ERROR_FILE_NOT_FOUND &&
+ dwType == REG_BINARY)
+ {
+ dwError = RegQueryValueExW(hServiceKey,
+ L"FailureActions",
+ NULL,
+ NULL,
+ (LPBYTE)lpReadBuffer,
+ &dwRequiredSize);
+ if (dwError != ERROR_SUCCESS &&
+ dwError != ERROR_FILE_NOT_FOUND)
+ goto done;
+
+ if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
+ dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
+ }
+ else
+ {
+ /*
+ * The value of the error doesn't really matter, the only
+ * important thing is that it must be != ERROR_SUCCESS.
+ */
+ dwError = ERROR_INVALID_DATA;
+ }
+
+ if (dwError == ERROR_SUCCESS)
+ {
+ lpReadBuffer->cActions = min(lpReadBuffer->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
+ lpReadBuffer->lpsaActions = (lpReadBuffer->cActions > 0 ? (LPSC_ACTION)(lpReadBuffer + 1) : NULL);
+ }
+ else
+ {
+ lpReadBuffer->dwResetPeriod = 0;
+ lpReadBuffer->cActions = 0;
+ lpReadBuffer->lpsaActions = NULL;
+ }
+
+ lpReadBuffer->lpRebootMsg = NULL;
+ lpReadBuffer->lpCommand = NULL;
+
+ /*
+ * 3- Initialize the new value to set.
+ */
+
+ dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
+
+ if (lpFailureActions->lpsaActions == NULL)
+ {
+ /*
+ * lpFailureActions->cActions is ignored.
+ * Therefore we use the original values
+ * of cActions and lpsaActions.
+ */
+ dwRequiredSize += lpReadBuffer->cActions * sizeof(SC_ACTION);
+ }
+ else
+ {
+ /*
+ * The reset period and array of failure actions
+ * are deleted if lpFailureActions->cActions == 0 .
+ */
+ dwRequiredSize += lpFailureActions->cActions * sizeof(SC_ACTION);
+ }
+
+ lpWriteBuffer = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ dwRequiredSize);
+ if (lpWriteBuffer == NULL)
+ {
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ /* Clean the pointers as they have no meaning when the structure is stored in the registry */
+ lpWriteBuffer->lpRebootMsg = NULL;
+ lpWriteBuffer->lpCommand = NULL;
+ lpWriteBuffer->lpsaActions = NULL;
+
+ /* Set the members */
+ if (lpFailureActions->lpsaActions == NULL)
+ {
+ /*
+ * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored.
+ * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions.
+ */
+ lpWriteBuffer->dwResetPeriod = lpReadBuffer->dwResetPeriod;
+ lpWriteBuffer->cActions = lpReadBuffer->cActions;
+
+ if (lpReadBuffer->lpsaActions != NULL)
+ {
+ memmove(lpWriteBuffer + 1,
+ lpReadBuffer->lpsaActions,
+ lpReadBuffer->cActions * sizeof(SC_ACTION));
+ }
+ }
+ else
+ {
+ if (lpFailureActions->cActions > 0)
+ {
+ lpWriteBuffer->dwResetPeriod = lpFailureActions->dwResetPeriod;
+ lpWriteBuffer->cActions = lpFailureActions->cActions;
+
+ memmove(lpWriteBuffer + 1,
+ lpFailureActions->lpsaActions,
+ lpFailureActions->cActions * sizeof(SC_ACTION));
+ }
+ else
+ {
+ /* The reset period and array of failure actions are deleted */
+ lpWriteBuffer->dwResetPeriod = 0;
+ lpWriteBuffer->cActions = 0;
+ }
+ }
+
+ /* Save the new failure actions into the registry */
+ dwError = RegSetValueExW(hServiceKey,
+ L"FailureActions",
+ 0,
+ REG_BINARY,
+ (LPBYTE)lpWriteBuffer,
+ dwRequiredSize);
+
+ /* We modify the strings only in case of success.*/
+ if (dwError == ERROR_SUCCESS)
+ {
+ /* Modify the Reboot Message value, if specified */
+ if (lpFailureActions->lpRebootMsg != NULL)
+ {
+ /* If the Reboot Message is "" then we delete it */
+ if (*lpFailureActions->lpRebootMsg == 0)
+ {
+ DPRINT("Delete Reboot Message value\n");
+ RegDeleteValueW(hServiceKey, L"RebootMessage");
+ }
+ else
+ {
+ DPRINT("Setting Reboot Message value %S\n", lpFailureActions->lpRebootMsg);
+ RegSetValueExW(hServiceKey,
+ L"RebootMessage",
+ 0,
+ REG_SZ,
+ (LPBYTE)lpFailureActions->lpRebootMsg,
+ (DWORD)((wcslen(lpFailureActions->lpRebootMsg) + 1) * sizeof(WCHAR)));
+ }
+ }
+
+ /* Modify the Failure Command value, if specified */
+ if (lpFailureActions->lpCommand != NULL)
+ {
+ /* If the FailureCommand string is an empty string, delete the value */
+ if (*lpFailureActions->lpCommand == 0)
+ {
+ DPRINT("Delete Failure Command value\n");
+ RegDeleteValueW(hServiceKey, L"FailureCommand");
+ }
+ else
+ {
+ DPRINT("Setting Failure Command value %S\n", lpFailureActions->lpCommand);
+ RegSetValueExW(hServiceKey,
+ L"FailureCommand",
+ 0,
+ REG_SZ,
+ (LPBYTE)lpFailureActions->lpCommand,
+ (DWORD)((wcslen(lpFailureActions->lpCommand) + 1) * sizeof(WCHAR)));
+ }
+ }
+ }
+
+done:
+ if (lpWriteBuffer != NULL)
+ HeapFree(GetProcessHeap(), 0, lpWriteBuffer);
+
+ if (lpReadBuffer != NULL)
+ HeapFree(GetProcessHeap(), 0, lpReadBuffer);
+
+ return dwError;
+}
+
+
/* Function 37 */
DWORD RChangeServiceConfig2W(
SC_RPC_HANDLE hService,
/* Open the service key */
dwError = ScmOpenServiceKey(lpService->szServiceName,
- KEY_SET_VALUE,
+ KEY_READ | KEY_SET_VALUE,
&hServiceKey);
if (dwError != ERROR_SUCCESS)
goto done;
if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
{
- LPSERVICE_DESCRIPTIONW lpServiceDescription;
-
- lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
- lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpServiceDescription + sizeof(LPSERVICE_DESCRIPTIONW));
+ LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
+ /* Modify the service description, if specified */
if (lpServiceDescription != NULL &&
lpServiceDescription->lpDescription != NULL)
{
- DPRINT("Setting value %S\n", lpServiceDescription->lpDescription);
- dwError = RegSetValueExW(hServiceKey,
- L"Description",
- 0,
- REG_SZ,
- (LPBYTE)lpServiceDescription->lpDescription,
- (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
- if (dwError != ERROR_SUCCESS)
- goto done;
+ /* If the description is "" then we delete it */
+ if (*lpServiceDescription->lpDescription == 0)
+ {
+ DPRINT("Delete service description\n");
+ dwError = RegDeleteValueW(hServiceKey, L"Description");
+
+ if (dwError == ERROR_FILE_NOT_FOUND)
+ dwError = ERROR_SUCCESS;
+ }
+ else
+ {
+ DPRINT("Setting service description value %S\n", lpServiceDescription->lpDescription);
+ dwError = RegSetValueExW(hServiceKey,
+ L"Description",
+ 0,
+ REG_SZ,
+ (LPBYTE)lpServiceDescription->lpDescription,
+ (DWORD)((wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR)));
+ }
+ }
+ else
+ {
+ dwError = ERROR_SUCCESS;
}
}
else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
{
- UNIMPLEMENTED;
- dwError = ERROR_CALL_NOT_IMPLEMENTED;
- goto done;
+ dwError = ScmSetFailureActions(hSvc,
+ lpService,
+ hServiceKey,
+ (LPSERVICE_FAILURE_ACTIONSW)Info.psfa);
}
done:
- /* Unlock the service database */
- ScmUnlockDatabase();
-
if (hServiceKey != NULL)
RegCloseKey(hServiceKey);
+ /* Unlock the service database */
+ ScmUnlockDatabase();
+
DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
return dwError;
PSERVICE_HANDLE hSvc;
PSERVICE lpService = NULL;
HKEY hServiceKey = NULL;
+ DWORD dwRequiredSize = 0;
+ DWORD dwType = 0;
LPWSTR lpDescriptionW = NULL;
- LPSTR lpDescription = NULL;
+ LPWSTR lpRebootMessageW = NULL;
+ LPWSTR lpFailureCommandW = NULL;
DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
*pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
if (dwError == ERROR_SUCCESS)
- *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
+ *pcbBytesNeeded += (DWORD)((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
if (cbBufSize < *pcbBytesNeeded)
{
lpDescriptionW,
-1,
lpStr,
- wcslen(lpDescriptionW),
+ (int)wcslen(lpDescriptionW),
NULL,
NULL);
lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
{
lpServiceDescription->lpDescription = NULL;
dwError = ERROR_SUCCESS;
- goto done;
}
}
- else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
+ else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
{
- UNIMPLEMENTED;
- dwError = ERROR_CALL_NOT_IMPLEMENTED;
- goto done;
+ LPSERVICE_FAILURE_ACTIONSA lpFailureActions = (LPSERVICE_FAILURE_ACTIONSA)lpBuffer;
+ LPSTR lpStr = NULL;
+
+ /* Query value length */
+ dwError = RegQueryValueExW(hServiceKey,
+ L"FailureActions",
+ NULL,
+ &dwType,
+ NULL,
+ &dwRequiredSize);
+ if (dwError != ERROR_SUCCESS &&
+ dwError != ERROR_MORE_DATA &&
+ dwError != ERROR_FILE_NOT_FOUND)
+ goto done;
+
+ dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSA), dwRequiredSize)
+ : sizeof(SERVICE_FAILURE_ACTIONSA);
+
+ /* Get the strings */
+ ScmReadString(hServiceKey,
+ L"FailureCommand",
+ &lpFailureCommandW);
+
+ ScmReadString(hServiceKey,
+ L"RebootMessage",
+ &lpRebootMessageW);
+
+ if (lpRebootMessageW)
+ dwRequiredSize += (DWORD)((wcslen(lpRebootMessageW) + 1) * sizeof(WCHAR));
+
+ if (lpFailureCommandW)
+ dwRequiredSize += (DWORD)((wcslen(lpFailureCommandW) + 1) * sizeof(WCHAR));
+
+ if (cbBufSize < dwRequiredSize)
+ {
+ *pcbBytesNeeded = dwRequiredSize;
+ dwError = ERROR_INSUFFICIENT_BUFFER;
+ goto done;
+ }
+
+ /* Now we can fill the buffer */
+ if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY)
+ {
+ dwError = RegQueryValueExW(hServiceKey,
+ L"FailureActions",
+ NULL,
+ NULL,
+ (LPBYTE)lpFailureActions,
+ &dwRequiredSize);
+ if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
+ goto done;
+
+ if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSA))
+ dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSA);
+ }
+ else
+ {
+ /*
+ * The value of the error doesn't really matter, the only
+ * important thing is that it must be != ERROR_SUCCESS .
+ */
+ dwError = ERROR_INVALID_DATA;
+ }
+
+ if (dwError == ERROR_SUCCESS)
+ {
+ lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSA)) / sizeof(SC_ACTION));
+
+ /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
+ lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSA) : NULL);
+
+ lpStr = (LPSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION));
+ }
+ else
+ {
+ lpFailureActions->dwResetPeriod = 0;
+ lpFailureActions->cActions = 0;
+ lpFailureActions->lpsaActions = NULL;
+ lpStr = (LPSTR)(lpFailureActions + 1);
+ }
+
+ lpFailureActions->lpRebootMsg = NULL;
+ lpFailureActions->lpCommand = NULL;
+
+ if (lpRebootMessageW)
+ {
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ lpRebootMessageW,
+ -1,
+ lpStr,
+ (int)wcslen(lpRebootMessageW),
+ NULL,
+ NULL);
+ lpFailureActions->lpRebootMsg = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
+ lpStr += strlen(lpStr) + 1;
+ }
+
+ if (lpFailureCommandW)
+ {
+ WideCharToMultiByte(CP_ACP,
+ 0,
+ lpFailureCommandW,
+ -1,
+ lpStr,
+ (int)wcslen(lpFailureCommandW),
+ NULL,
+ NULL);
+ lpFailureActions->lpCommand = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
+ /* lpStr += strlen(lpStr) + 1; */
+ }
+
+ dwError = ERROR_SUCCESS;
}
done:
/* Unlock the service database */
ScmUnlockDatabase();
- if (lpDescription != NULL)
- HeapFree(GetProcessHeap(), 0, lpDescription);
+ if (lpDescriptionW != NULL)
+ HeapFree(GetProcessHeap(), 0, lpDescriptionW);
+
+ if (lpRebootMessageW != NULL)
+ HeapFree(GetProcessHeap(), 0, lpRebootMessageW);
+
+ if (lpFailureCommandW != NULL)
+ HeapFree(GetProcessHeap(), 0, lpFailureCommandW);
if (hServiceKey != NULL)
RegCloseKey(hServiceKey);
- DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
+ DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError);
return dwError;
}
PSERVICE_HANDLE hSvc;
PSERVICE lpService = NULL;
HKEY hServiceKey = NULL;
- DWORD dwRequiredSize;
+ DWORD dwRequiredSize = 0;
+ DWORD dwType = 0;
LPWSTR lpDescription = NULL;
- LPWSTR lpFailureCommand = NULL;
LPWSTR lpRebootMessage = NULL;
+ LPWSTR lpFailureCommand = NULL;
DPRINT("RQueryServiceConfig2W() called\n");
*pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW);
if (dwError == ERROR_SUCCESS)
- *pcbBytesNeeded += ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
+ *pcbBytesNeeded += (DWORD)((wcslen(lpDescription) + 1) * sizeof(WCHAR));
if (cbBufSize < *pcbBytesNeeded)
{
}
else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
{
- LPWSTR lpStr;
LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
+ LPWSTR lpStr = NULL;
- UNIMPLEMENTED;
-
- dwError = ScmReadString(hServiceKey,
- L"FailureCommand",
- &lpFailureCommand);
+ /* Query value length */
+ dwError = RegQueryValueExW(hServiceKey,
+ L"FailureActions",
+ NULL,
+ &dwType,
+ NULL,
+ &dwRequiredSize);
+ if (dwError != ERROR_SUCCESS &&
+ dwError != ERROR_MORE_DATA &&
+ dwError != ERROR_FILE_NOT_FOUND)
+ goto done;
- dwError = ScmReadString(hServiceKey,
- L"RebootMessage",
- &lpRebootMessage);
+ dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
+ : sizeof(SERVICE_FAILURE_ACTIONSW);
- dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
+ /* Get the strings */
+ ScmReadString(hServiceKey,
+ L"FailureCommand",
+ &lpFailureCommand);
- if (lpFailureCommand)
- dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR);
+ ScmReadString(hServiceKey,
+ L"RebootMessage",
+ &lpRebootMessage);
if (lpRebootMessage)
- dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR);
+ dwRequiredSize += (DWORD)((wcslen(lpRebootMessage) + 1) * sizeof(WCHAR));
+
+ if (lpFailureCommand)
+ dwRequiredSize += (DWORD)((wcslen(lpFailureCommand) + 1) * sizeof(WCHAR));
if (cbBufSize < dwRequiredSize)
{
goto done;
}
- lpFailureActions->cActions = 0;
- lpFailureActions->dwResetPeriod = 0;
- lpFailureActions->lpCommand = NULL;
+ /* Now we can fill the buffer */
+ if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY)
+ {
+ dwError = RegQueryValueExW(hServiceKey,
+ L"FailureActions",
+ NULL,
+ NULL,
+ (LPBYTE)lpFailureActions,
+ &dwRequiredSize);
+ if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
+ goto done;
+
+ if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW))
+ dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
+ }
+ else
+ {
+ /*
+ * The value of the error doesn't really matter, the only
+ * important thing is that it must be != ERROR_SUCCESS .
+ */
+ dwError = ERROR_INVALID_DATA;
+ }
+
+ if (dwError == ERROR_SUCCESS)
+ {
+ lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION));
+
+ /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */
+ lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSW) : NULL);
+
+ lpStr = (LPWSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION));
+ }
+ else
+ {
+ lpFailureActions->dwResetPeriod = 0;
+ lpFailureActions->cActions = 0;
+ lpFailureActions->lpsaActions = NULL;
+ lpStr = (LPWSTR)(lpFailureActions + 1);
+ }
+
lpFailureActions->lpRebootMsg = NULL;
- lpFailureActions->lpsaActions = NULL;
+ lpFailureActions->lpCommand = NULL;
- lpStr = (LPWSTR)(lpFailureActions + 1);
if (lpRebootMessage)
{
wcscpy(lpStr, lpRebootMessage);
- lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage);
- lpStr += wcslen(lpRebootMessage) + 1;
+ lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
+ lpStr += wcslen(lpStr) + 1;
}
if (lpFailureCommand)
{
wcscpy(lpStr, lpFailureCommand);
- lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand);
- lpStr += wcslen(lpRebootMessage) + 1;
+ lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions);
+ /* lpStr += wcslen(lpStr) + 1; */
}
- dwError = STATUS_SUCCESS;
- goto done;
+
+ dwError = ERROR_SUCCESS;
}
done:
LPCSTR pszGroupName)
{
LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
+ LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW;
LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
LPWSTR lpStringPtrW;
LPSTR lpStringPtrA;
DPRINT("REnumServicesStatusExA() called\n");
+ if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
+ {
+ return ERROR_INVALID_ADDRESS;
+ }
+
if (pszGroupName)
{
pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
pszGroupName,
-1,
pszGroupNameW,
- strlen(pszGroupName) + 1);
+ (int)(strlen(pszGroupName) + 1));
}
if ((cbBufSize > 0) && (lpBuffer))
if (*lpServicesReturned == 0)
goto Done;
+ lpStatusPtrIncrW = lpStatusPtrW;
lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
*lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
lpStringPtrW,
-1,
lpStringPtrA,
- wcslen(lpStringPtrW),
+ (int)wcslen(lpStringPtrW),
0,
0);
lpStringPtrW,
-1,
lpStringPtrA,
- wcslen(lpStringPtrW),
+ (int)wcslen(lpStringPtrW),
0,
0);
/* Copy the status information */
memcpy(&lpStatusPtrA->ServiceStatusProcess,
- &lpStatusPtrW->ServiceStatusProcess,
+ &lpStatusPtrIncrW->ServiceStatusProcess,
sizeof(SERVICE_STATUS));
- lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
+ lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrIncrW->ServiceStatusProcess.dwProcessId; /* FIXME */
lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
+
+ lpStatusPtrIncrW++;
lpStatusPtrA++;
}
-Done:;
+Done:
if (pszGroupNameW)
HeapFree(GetProcessHeap(), 0, pszGroupNameW);
return ERROR_INVALID_HANDLE;
}
+ if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
+ {
+ return ERROR_INVALID_ADDRESS;
+ }
+
*pcbBytesNeeded = 0;
*lpServicesReturned = 0;
- if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
+ if ((dwServiceType == 0) ||
+ ((dwServiceType & ~SERVICE_TYPE_ALL) != 0))
{
DPRINT("Not a valid Service Type!\n");
return ERROR_INVALID_PARAMETER;
}
- if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
+ if ((dwServiceState == 0) ||
+ ((dwServiceState & ~SERVICE_STATE_ALL) != 0))
{
DPRINT("Not a valid Service State!\n");
return ERROR_INVALID_PARAMETER;
else
{
if ((CurrentService->lpGroup == NULL) ||
- _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
+ _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
continue;
}
}
dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
- ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
- ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
+ (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
+ (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
if (dwRequiredSize + dwSize <= cbBufSize)
{
else
{
if ((CurrentService->lpGroup == NULL) ||
- _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
+ _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
continue;
}
}
dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
- ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
- ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
+ (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
+ (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
dwError = ERROR_MORE_DATA;
}
else
{
if ((CurrentService->lpGroup == NULL) ||
- _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
+ _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0)
continue;
}
}
dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
- ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
- ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
+ (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
+ (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
if (dwRequiredSize + dwSize <= cbBufSize)
{
*lpResumeIndex = 0;
}
-Done:;
+Done:
/* Unlock the service database */
ScmUnlockDatabase();
void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
{
+ /* Close the handle */
+ RCloseServiceHandle(&hSCObject);
}
void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
{
+ /* Unlock the database */
+ RUnlockServiceDatabase(&Lock);
}