#include "services.h"
+#include <winnls.h>
+#include <strsafe.h>
+
#define NDEBUG
#include <debug.h>
#define MANAGER_TAG 0x72674D68 /* 'hMgr' */
#define SERVICE_TAG 0x63765368 /* 'hSvc' */
+#define INVALID_TAG 0xAABBCCDD
typedef struct _SCMGR_HANDLE
{
SERVICE_EXECUTE,
SERVICE_ALL_ACCESS};
+DWORD g_dwServiceBits = 0;
/* FUNCTIONS ***************************************************************/
/* Get buffer size needed for expanding env strings */
BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
-
if (BufferSize <= 1)
{
DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
if (!Expanded)
{
DPRINT("Error allocating memory for boot driver name!\n");
+ RtlFreeUnicodeString(&NtPathName);
return ERROR_NOT_ENOUGH_MEMORY;
}
ExpandedLen = NtPathName.Length / sizeof(WCHAR);
wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
Expanded[ExpandedLen] = UNICODE_NULL;
+ RtlFreeUnicodeString(&NtPathName);
if (ServiceNameLen > ExpandedLen &&
!_wcsnicmp(Expanded, CanonName, ExpandedLen))
{
+ HeapFree(GetProcessHeap(), 0, Expanded);
+
/* Only \SystemRoot\ is missing */
*RelativeName = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
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;
}
+ /* No longer need this */
+ HeapFree(GetProcessHeap(), 0, Expanded);
+
/* The most complex case starts here */
RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
InitializeObjectAttributes(&ObjectAttributes,
/* 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");
+ RtlInitEmptyUnicodeString(&LinkTarget, NULL, 0);
Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
{
/* Check if required buffer size is sane */
- if (BufferSize > 0xFFFD)
+ if (BufferSize > UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL))
{
DPRINT("Too large buffer required\n");
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- HeapFree(GetProcessHeap(), 0, Expanded);
+ NtClose(SymbolicLinkHandle);
return ERROR_NOT_ENOUGH_MEMORY;
}
if (!LinkTarget.Buffer)
{
DPRINT("Unable to alloc buffer\n");
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- HeapFree(GetProcessHeap(), 0, Expanded);
+ NtClose(SymbolicLinkHandle);
return ERROR_NOT_ENOUGH_MEMORY;
}
/* Do a real query now */
Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
+ NtClose(SymbolicLinkHandle);
if (NT_SUCCESS(Status))
{
DPRINT("LinkTarget: %wZ\n", &LinkTarget);
if (*RelativeName == NULL)
{
DPRINT("Unable to alloc buffer\n");
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- HeapFree(GetProcessHeap(), 0, Expanded);
- RtlFreeUnicodeString(&NtPathName);
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy(*RelativeName, L"\\SystemRoot\\");
wcscat(*RelativeName, CanonName+ExpandedLen+1);
- /* Cleanup */
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- HeapFree(GetProcessHeap(), 0, Expanded);
- RtlFreeUnicodeString(&NtPathName);
-
/* Return success */
return ERROR_SUCCESS;
}
else
{
- 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
{
DPRINT("Error, Status = %08X\n", Status);
- if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
- HeapFree(GetProcessHeap(), 0, Expanded);
- RtlFreeUnicodeString(&NtPathName);
+ NtClose(SymbolicLinkHandle);
return ERROR_INVALID_PARAMETER;
}
}
{
/* Failure */
DPRINT("Error, Status = %08X\n", Status);
- HeapFree(GetProcessHeap(), 0, Expanded);
return ERROR_INVALID_PARAMETER;
}
}
if (dwError != ERROR_SUCCESS)
return dwError;
- dwSize = MAX_PATH;
+ dwSize = MAX_PATH * sizeof(WCHAR);
/* Check for the DependOnService Value */
dwError = RegQueryValueExW(hServiceEnumKey,
/* Function 0 */
-DWORD RCloseServiceHandle(
+DWORD
+WINAPI
+RCloseServiceHandle(
LPSC_RPC_HANDLE hSCObject)
{
PMANAGER_HANDLE hManager;
{
DPRINT("Found manager handle\n");
- /* FIXME: add handle cleanup code */
+ /* Make sure we don't access stale memory if someone tries to use this handle again. */
+ hManager->Handle.Tag = INVALID_TAG;
HeapFree(GetProcessHeap(), 0, hManager);
hManager = NULL;
{
DPRINT("Found service handle\n");
- /* Lock the service database exlusively */
+ /* Lock the service database exclusively */
ScmLockDatabaseExclusive();
/* Get the pointer to the service record */
lpService = hService->ServiceEntry;
- /* FIXME: add handle cleanup code */
+ /* Make sure we don't access stale memory if someone tries to use this handle again. */
+ hService->Handle.Tag = INVALID_TAG;
/* Free the handle */
HeapFree(GetProcessHeap(), 0, hService);
if (lpService->dwRefCount == 0)
{
/* If this service has been marked for deletion */
- if (lpService->bDeleted)
+ if (lpService->bDeleted &&
+ lpService->Status.dwCurrentState == SERVICE_STOPPED)
{
/* Open the Services Reg key */
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
&pcbBytesNeeded,
&dwServicesReturned);
- /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
+ /* 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");
return ERROR_SUCCESS;
}
- /* There are no references and no runnning dependencies,
+ /* There are no references and no running dependencies,
it is now safe to delete the service */
/* Delete the Service Key */
- dwError = RegDeleteKeyW(hServicesKey,
- lpService->lpServiceName);
+ dwError = ScmDeleteRegKey(hServicesKey,
+ lpService->lpServiceName);
RegCloseKey(hServicesKey);
/* Function 1 */
-DWORD RControlService(
+DWORD
+WINAPI
+RControlService(
SC_RPC_HANDLE hService,
DWORD dwControl,
LPSERVICE_STATUS lpServiceStatus)
DWORD dwControlsAccepted;
DWORD dwCurrentState;
HKEY hServicesKey = NULL;
+ LPCWSTR lpLogStrings[2];
+ WCHAR szLogBuffer[80];
+ UINT uID;
DPRINT("RControlService() called\n");
case SERVICE_CONTROL_PAUSE:
case SERVICE_CONTROL_CONTINUE:
+ case SERVICE_CONTROL_PARAMCHANGE:
+ case SERVICE_CONTROL_NETBINDADD:
+ case SERVICE_CONTROL_NETBINDREMOVE:
+ case SERVICE_CONTROL_NETBINDENABLE:
+ case SERVICE_CONTROL_NETBINDDISABLE:
DesiredAccess = SERVICE_PAUSE_CONTINUE;
break;
if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
return ERROR_INVALID_SERVICE_CONTROL;
break;
+
+ case SERVICE_CONTROL_PARAMCHANGE:
+ if ((dwControlsAccepted & SERVICE_ACCEPT_PARAMCHANGE) == 0)
+ return ERROR_INVALID_SERVICE_CONTROL;
+ break;
+
+ case SERVICE_CONTROL_NETBINDADD:
+ case SERVICE_CONTROL_NETBINDREMOVE:
+ case SERVICE_CONTROL_NETBINDENABLE:
+ case SERVICE_CONTROL_NETBINDDISABLE:
+ if ((dwControlsAccepted & SERVICE_ACCEPT_NETBINDCHANGE) == 0)
+ return ERROR_INVALID_SERVICE_CONTROL;
+ break;
}
/* Send control code to the service */
- dwError = ScmControlService(lpService,
+ dwError = ScmControlService(lpService->lpImage->hControlPipe,
+ lpService->lpServiceName,
+ (SERVICE_STATUS_HANDLE)lpService,
dwControl);
/* Return service status information */
sizeof(SERVICE_STATUS));
}
+ if (dwError == ERROR_SUCCESS)
+ {
+ if (dwControl == SERVICE_CONTROL_STOP ||
+ dwControl == SERVICE_CONTROL_PAUSE ||
+ dwControl == SERVICE_CONTROL_CONTINUE)
+ {
+ /* Log a successful send control */
+
+ switch (dwControl)
+ {
+ case SERVICE_CONTROL_STOP:
+ uID = IDS_SERVICE_STOP;
+ break;
+
+ case SERVICE_CONTROL_PAUSE:
+ uID = IDS_SERVICE_PAUSE;
+ break;
+
+ case SERVICE_CONTROL_CONTINUE:
+ uID = IDS_SERVICE_RESUME;
+ break;
+ }
+ LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
+
+ lpLogStrings[0] = lpService->lpDisplayName;
+ lpLogStrings[1] = szLogBuffer;
+
+ ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
+ EVENTLOG_INFORMATION_TYPE,
+ 2,
+ lpLogStrings);
+ }
+ }
+
return dwError;
}
/* Function 2 */
-DWORD RDeleteService(
+DWORD
+WINAPI
+RDeleteService(
SC_RPC_HANDLE hService)
{
PSERVICE_HANDLE hSvc;
/* Function 3 */
-DWORD RLockServiceDatabase(
+DWORD
+WINAPI
+RLockServiceDatabase(
SC_RPC_HANDLE hSCManager,
LPSC_RPC_LOCK lpLock)
{
/* Function 4 */
-DWORD RQueryServiceObjectSecurity(
+DWORD
+WINAPI
+RQueryServiceObjectSecurity(
SC_RPC_HANDLE hService,
SECURITY_INFORMATION dwSecurityInformation,
LPBYTE lpSecurityDescriptor,
DWORD dwBytesNeeded;
DWORD dwError;
-
- SECURITY_DESCRIPTOR ObjectDescriptor;
-
DPRINT("RQueryServiceObjectSecurity() called\n");
hSvc = ScmGetServiceFromHandle(hService);
/* Lock the service database */
ScmLockDatabaseShared();
-
- /* hack */
- Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
-
- Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */,
+ /* Retrieve the security descriptor */
+ Status = RtlQuerySecurityObject(lpService->pSecurityDescriptor,
dwSecurityInformation,
(PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
cbBufSize,
/* Function 5 */
-DWORD RSetServiceObjectSecurity(
+DWORD
+WINAPI
+RSetServiceObjectSecurity(
SC_RPC_HANDLE hService,
DWORD dwSecurityInformation,
LPBYTE lpSecurityDescriptor,
- DWORD dwSecuityDescriptorSize)
+ DWORD dwSecurityDescriptorSize)
{
PSERVICE_HANDLE hSvc;
PSERVICE lpService;
- ULONG DesiredAccess = 0;
- /* HANDLE hToken = NULL; */
- HKEY hServiceKey;
- /* NTSTATUS Status; */
+ ACCESS_MASK DesiredAccess = 0;
+ HANDLE hToken = NULL;
+ HKEY hServiceKey = NULL;
+ BOOL bDatabaseLocked = FALSE;
+ NTSTATUS Status;
DWORD dwError;
DPRINT("RSetServiceObjectSecurity() called\n");
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 & 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);
+ DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
return ERROR_ACCESS_DENIED;
}
lpService = hSvc->ServiceEntry;
if (lpService == NULL)
{
- DPRINT("lpService == NULL!\n");
+ DPRINT1("lpService == NULL!\n");
return ERROR_INVALID_HANDLE;
}
RpcRevertToSelf();
#endif
- /* Lock the service database exclusive */
- ScmLockDatabaseExclusive();
-
-#if 0
+ /* Build the new security descriptor */
Status = RtlSetSecurityObject(dwSecurityInformation,
(PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
- &lpService->lpSecurityDescriptor,
+ &lpService->pSecurityDescriptor,
&ScmServiceMapping,
hToken);
if (!NT_SUCCESS(Status))
dwError = RtlNtStatusToDosError(Status);
goto Done;
}
-#endif
+ /* Lock the service database exclusive */
+ ScmLockDatabaseExclusive();
+ bDatabaseLocked = TRUE;
+
+ /* Open the service key */
dwError = ScmOpenServiceKey(lpService->lpServiceName,
READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
&hServiceKey);
if (dwError != ERROR_SUCCESS)
goto Done;
- UNIMPLEMENTED;
- dwError = ERROR_SUCCESS;
-// dwError = ScmWriteSecurityDescriptor(hServiceKey,
-// lpService->lpSecurityDescriptor);
+ /* Store the new security descriptor */
+ dwError = ScmWriteSecurityDescriptor(hServiceKey,
+ lpService->pSecurityDescriptor);
RegFlushKey(hServiceKey);
- RegCloseKey(hServiceKey);
Done:
+ if (hServiceKey != NULL)
+ RegCloseKey(hServiceKey);
+
+ /* Unlock service database */
+ if (bDatabaseLocked == TRUE)
+ ScmUnlockDatabase();
-#if 0
if (hToken != NULL)
NtClose(hToken);
-#endif
-
- /* Unlock service database */
- ScmUnlockDatabase();
DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
/* Function 6 */
-DWORD RQueryServiceStatus(
+DWORD
+WINAPI
+RQueryServiceStatus(
SC_RPC_HANDLE hService,
LPSERVICE_STATUS lpServiceStatus)
{
/* Function 7 */
-DWORD RSetServiceStatus(
+DWORD
+WINAPI
+RSetServiceStatus(
RPC_SERVICE_STATUS_HANDLE hServiceStatus,
LPSERVICE_STATUS lpServiceStatus)
{
PSERVICE lpService;
DWORD dwPreviousState;
- LPCWSTR lpErrorStrings[2];
- WCHAR szErrorBuffer[32];
+ DWORD dwPreviousType;
+ LPCWSTR lpLogStrings[2];
+ WCHAR szLogBuffer[80];
+ UINT uID;
DPRINT("RSetServiceStatus() called\n");
DPRINT("hServiceStatus = %lu\n", hServiceStatus);
- DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
+ 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);
return ERROR_INVALID_DATA;
}
+ /* 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)
+ {
+ lpServiceStatus->dwWaitHint = 0;
+ lpServiceStatus->dwCheckPoint = 0;
+ }
+
/* Lock the service database exclusively */
ScmLockDatabaseExclusive();
/* Save the current service state */
dwPreviousState = lpService->Status.dwCurrentState;
+ /* Save the current service type */
+ dwPreviousType = lpService->Status.dwServiceType;
+
+ /* Update the service status */
RtlCopyMemory(&lpService->Status,
lpServiceStatus,
sizeof(SERVICE_STATUS));
+ /* Restore the previous service type */
+ lpService->Status.dwServiceType = dwPreviousType;
+
+ /* Dereference a stopped service */
+ if ((lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
+ (lpServiceStatus->dwCurrentState == SERVICE_STOPPED))
+ {
+ /* Decrement the image run counter */
+ lpService->lpImage->dwImageRunCount--;
+
+ /* If we just stopped the last running service... */
+ if (lpService->lpImage->dwImageRunCount == 0)
+ {
+ /* Stop the dispatcher thread */
+ ScmControlService(lpService->lpImage->hControlPipe,
+ L"",
+ (SERVICE_STATUS_HANDLE)lpService,
+ SERVICE_CONTROL_STOP);
+
+ /* Remove the service image */
+ ScmRemoveServiceImage(lpService->lpImage);
+ lpService->lpImage = NULL;
+ }
+ }
+
/* Unlock the service database */
ScmUnlockDatabase();
- /* Log a failed service stop */
if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
- (dwPreviousState != SERVICE_STOPPED))
- {
- if (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS)
+ (dwPreviousState != SERVICE_STOPPED) &&
+ (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS))
+ {
+ /* Log a failed service stop */
+ StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer),
+ L"%lu", lpServiceStatus->dwWin32ExitCode);
+ lpLogStrings[0] = lpService->lpDisplayName;
+ lpLogStrings[1] = szLogBuffer;
+
+ ScmLogEvent(EVENT_SERVICE_EXIT_FAILED,
+ EVENTLOG_ERROR_TYPE,
+ 2,
+ lpLogStrings);
+ }
+ else if (lpServiceStatus->dwCurrentState != dwPreviousState &&
+ (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
+ lpServiceStatus->dwCurrentState == SERVICE_RUNNING ||
+ lpServiceStatus->dwCurrentState == SERVICE_PAUSED))
+ {
+ /* Log a successful service status change */
+ switch(lpServiceStatus->dwCurrentState)
{
- swprintf(szErrorBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode);
- lpErrorStrings[0] = lpService->lpDisplayName;
- lpErrorStrings[1] = szErrorBuffer;
+ case SERVICE_STOPPED:
+ uID = IDS_SERVICE_STOPPED;
+ break;
- ScmLogError(EVENT_SERVICE_EXIT_FAILED,
- 2,
- lpErrorStrings);
+ case SERVICE_RUNNING:
+ uID = IDS_SERVICE_RUNNING;
+ break;
+
+ case SERVICE_PAUSED:
+ uID = IDS_SERVICE_PAUSED;
+ break;
}
+
+ LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
+ lpLogStrings[0] = lpService->lpDisplayName;
+ lpLogStrings[1] = szLogBuffer;
+
+ ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS,
+ EVENTLOG_INFORMATION_TYPE,
+ 2,
+ lpLogStrings);
}
DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
/* Function 8 */
-DWORD RUnlockServiceDatabase(
+DWORD
+WINAPI
+RUnlockServiceDatabase(
LPSC_RPC_LOCK Lock)
{
DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
/* Function 9 */
-DWORD RNotifyBootConfigStatus(
+DWORD
+WINAPI
+RNotifyBootConfigStatus(
SVCCTL_HANDLEW lpMachineName,
DWORD BootAcceptable)
{
/* Function 10 */
-DWORD RI_ScSetServiceBitsW(
+DWORD
+WINAPI
+RI_ScSetServiceBitsW(
RPC_SERVICE_STATUS_HANDLE hServiceStatus,
DWORD dwServiceBits,
int bSetBitsOn,
int bUpdateImmediately,
wchar_t *lpString)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ PSERVICE pService;
+
+ DPRINT("RI_ScSetServiceBitsW(%p %lx %d %d %S)\n",
+ hServiceStatus, dwServiceBits, bSetBitsOn,
+ bUpdateImmediately, lpString);
+
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
+
+ if (lpString != NULL)
+ return ERROR_INVALID_PARAMETER;
+
+ if (hServiceStatus == 0)
+ {
+ DPRINT("hServiceStatus == NULL!\n");
+ return ERROR_INVALID_HANDLE;
+ }
+
+ // FIXME: Validate the status handle
+ pService = (PSERVICE)hServiceStatus;
+
+ if (bSetBitsOn)
+ {
+ DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
+ DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
+ pService->dwServiceBits |= dwServiceBits;
+ g_dwServiceBits |= dwServiceBits;
+ DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
+ DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
+ }
+ else
+ {
+ DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
+ DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
+ pService->dwServiceBits &= ~dwServiceBits;
+ g_dwServiceBits &= ~dwServiceBits;
+ DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
+ DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
+ }
+
+ return ERROR_SUCCESS;
}
/* Function 11 */
-DWORD RChangeServiceConfigW(
+DWORD
+WINAPI
+RChangeServiceConfigW(
SC_RPC_HANDLE hService,
DWORD dwServiceType,
DWORD dwStartType,
HKEY hServiceKey = NULL;
LPWSTR lpDisplayNameW = NULL;
LPWSTR lpImagePathW = NULL;
+ LPWSTR lpClearTextPassword = NULL;
DPRINT("RChangeServiceConfigW() called\n");
- 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("lpServiceStartName = %S\n", lpServiceStartName);
+ DPRINT("lpPassword = %p\n", lpPassword);
+ DPRINT("dwPwSite = %lu\n", dwPwSize);
DPRINT("lpDisplayName = %S\n", lpDisplayName);
if (ScmShutdown)
return ERROR_ACCESS_DENIED;
}
+ /* Check for invalid service type value */
+ if ((dwServiceType != SERVICE_NO_CHANGE) &&
+ (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_NO_CHANGE) &&
+ (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;
+ }
+
+ /* Check for invalid error control value */
+ if ((dwErrorControl != SERVICE_NO_CHANGE) &&
+ (dwErrorControl != SERVICE_ERROR_IGNORE) &&
+ (dwErrorControl != SERVICE_ERROR_NORMAL) &&
+ (dwErrorControl != SERVICE_ERROR_SEVERE) &&
+ (dwErrorControl != SERVICE_ERROR_CRITICAL))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
+
lpService = hSvc->ServiceEntry;
if (lpService == NULL)
{
goto done;
/* Write service data to the registry */
+
/* Set the display name */
if (lpDisplayName != NULL && *lpDisplayName != 0)
{
goto done;
}
+ wcscpy(lpDisplayNameW, lpDisplayName);
if (lpService->lpDisplayName != lpService->lpServiceName)
HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
goto done;
}
+ /* Set the tag */
if (lpdwTagId != NULL)
{
dwError = ScmAssignNewTag(lpService);
goto done;
}
- if (lpPassword != NULL)
+ /* Start name and password are only used by Win32 services */
+ if (lpService->Status.dwServiceType & SERVICE_WIN32)
{
- /* FIXME: Decrypt and write password */
+ /* Write service start name */
+ if (lpServiceStartName != NULL && *lpServiceStartName != 0)
+ {
+ dwError = RegSetValueExW(hServiceKey,
+ L"ObjectName",
+ 0,
+ REG_SZ,
+ (LPBYTE)lpServiceStartName,
+ (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR)));
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+ }
+
+ if (lpPassword != NULL)
+ {
+ if (*(LPWSTR)lpPassword != 0)
+ {
+ /* Decrypt the password */
+ dwError = ScmDecryptPassword(lpPassword,
+ dwPwSize,
+ &lpClearTextPassword);
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT1("ScmDecryptPassword failed (Error %lu)\n", dwError);
+ goto done;
+ }
+ DPRINT1("Clear text password: %S\n", lpClearTextPassword);
+
+ /* Write the password */
+ dwError = ScmSetServicePassword(lpService->szServiceName,
+ lpClearTextPassword);
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
+ goto done;
+ }
+ }
+ else
+ {
+ /* Delete the password */
+ dwError = ScmSetServicePassword(lpService->szServiceName,
+ NULL);
+ if (dwError == ERROR_FILE_NOT_FOUND)
+ dwError = ERROR_SUCCESS;
+
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError);
+ goto done;
+ }
+ }
+ }
}
done:
+ if (lpClearTextPassword != NULL)
+ {
+ /* Wipe and release the password buffer */
+ ZeroMemory(lpClearTextPassword,
+ (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
+ HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
+ }
+
if (hServiceKey != NULL)
RegCloseKey(hServiceKey);
/* Function 12 */
-DWORD RCreateServiceW(
+DWORD
+WINAPI
+RCreateServiceW(
SC_RPC_HANDLE hSCManager,
LPCWSTR lpServiceName,
LPCWSTR lpDisplayName,
PSERVICE lpService = NULL;
SC_HANDLE hServiceHandle = NULL;
LPWSTR lpImagePath = NULL;
+ LPWSTR lpClearTextPassword = NULL;
HKEY hServiceKey = NULL;
LPWSTR lpObjectName;
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);
return ERROR_ACCESS_DENIED;
}
- if (wcslen(lpServiceName) == 0)
- {
+ if (*lpServiceName == 0)
return ERROR_INVALID_NAME;
- }
- if (wcslen(lpBinaryPathName) == 0)
- {
+ if (*lpBinaryPathName == 0)
return ERROR_INVALID_PARAMETER;
- }
/* 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;
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
/* Check for invalid start type value */
if ((dwStartType != SERVICE_BOOT_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) ||
{
if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
(dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
+ {
return ERROR_INVALID_PARAMETER;
+ }
}
/* Check for invalid error control value */
(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;
+ /* We allow LocalSystem to run interactive. */
+ if (wcsicmp(lpServiceStartName, L"LocalSystem"))
+ {
+ return ERROR_INVALID_PARAMETER;
+ }
}
if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
if (lpService->bDeleted)
return ERROR_SERVICE_MARKED_FOR_DELETE;
- /* Return Error exist */
+ /* Return service-exists error */
return ERROR_SERVICE_EXISTS;
}
/* Allocate a new service entry */
dwError = ScmCreateNewServiceRecord(lpServiceName,
- &lpService);
+ &lpService,
+ dwServiceType,
+ dwStartType);
if (dwError != ERROR_SUCCESS)
goto done;
/* Fill the new service entry */
- lpService->Status.dwServiceType = dwServiceType;
- lpService->dwStartType = dwStartType;
lpService->dwErrorControl = dwErrorControl;
/* Fill the display name */
goto done;
}
+ /* Assign the default security descriptor */
+ if (dwServiceType & SERVICE_WIN32)
+ {
+ dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+ }
+
/* Write service data to the registry */
/* Create the service key */
dwError = ScmCreateServiceKey(lpServiceName,
goto done;
}
+ /* Set the service tag */
if (lpdwTagId != NULL)
{
dwError = RegSetValueExW(hServiceKey,
goto done;
}
- /* Write service start name */
+ /* Start name and password are only used by Win32 services */
if (dwServiceType & SERVICE_WIN32)
{
+ /* Write service start name */
lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
dwError = RegSetValueExW(hServiceKey,
L"ObjectName",
(DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
if (dwError != ERROR_SUCCESS)
goto done;
- }
- if (lpPassword != NULL)
- {
- /* FIXME: Decrypt and write password */
+ if (lpPassword != NULL && *(LPWSTR)lpPassword != 0)
+ {
+ /* Decrypt the password */
+ dwError = ScmDecryptPassword(lpPassword,
+ dwPwSize,
+ &lpClearTextPassword);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+
+ /* Write the password */
+ dwError = ScmSetServicePassword(lpServiceName,
+ lpClearTextPassword);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+ }
+
+ /* Write the security descriptor */
+ dwError = ScmWriteSecurityDescriptor(hServiceKey,
+ lpService->pSecurityDescriptor);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
}
dwError = ScmCreateServiceHandle(lpService,
if (hServiceKey != NULL)
RegCloseKey(hServiceKey);
+ if (lpClearTextPassword != NULL)
+ {
+ /* Wipe and release the password buffer */
+ ZeroMemory(lpClearTextPassword,
+ (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR));
+ HeapFree(GetProcessHeap(), 0, lpClearTextPassword);
+ }
+
if (dwError == ERROR_SUCCESS)
{
DPRINT("hService %p\n", hServiceHandle);
/* Function 13 */
-DWORD REnumDependentServicesW(
+DWORD
+WINAPI
+REnumDependentServicesW(
SC_RPC_HANDLE hService,
DWORD dwServiceState,
LPBYTE lpServices,
/* Function 14 */
-DWORD REnumServicesStatusW(
+DWORD
+WINAPI
+REnumServicesStatusW(
SC_RPC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
/* Function 15 */
-DWORD ROpenSCManagerW(
+DWORD
+WINAPI
+ROpenSCManagerW(
LPWSTR lpMachineName,
LPWSTR lpDatabaseName,
DWORD dwDesiredAccess,
/* Function 16 */
-DWORD ROpenServiceW(
+DWORD
+WINAPI
+ROpenServiceW(
SC_RPC_HANDLE hSCManager,
LPWSTR lpServiceName,
DWORD dwDesiredAccess,
/* Function 17 */
-DWORD RQueryServiceConfigW(
+DWORD
+WINAPI
+RQueryServiceConfigW(
SC_RPC_HANDLE hService,
LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
DWORD cbBufSize,
LPWSTR lpDependencies = NULL;
DWORD dwDependenciesLength = 0;
DWORD dwRequiredSize;
- WCHAR lpEmptyString[] = {0,0};
LPWSTR lpStr;
DPRINT("RQueryServiceConfigW() called\n");
}
else
{
- wcscpy(lpStr, lpEmptyString);
+ *lpStr = 0;
}
lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
}
else
{
- wcscpy(lpStr, lpEmptyString);
+ *lpStr = 0;
}
lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
}
else
{
- wcscpy(lpStr, lpEmptyString);
+ *lpStr = 0;
}
lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
}
else
{
- wcscpy(lpStr, lpEmptyString);
+ *lpStr = 0;
}
lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
}
else
{
- wcscpy(lpStr, lpEmptyString);
+ *lpStr = 0;
}
lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
/* Function 18 */
-DWORD RQueryServiceLockStatusW(
+DWORD
+WINAPI
+RQueryServiceLockStatusW(
SC_RPC_HANDLE hSCManager,
LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
DWORD cbBufSize,
/* Function 19 */
-DWORD RStartServiceW(
+DWORD
+WINAPI
+RStartServiceW(
SC_RPC_HANDLE hService,
DWORD argc,
LPSTRING_PTRSW argv)
/* Function 20 */
-DWORD RGetServiceDisplayNameW(
+DWORD
+WINAPI
+RGetServiceDisplayNameW(
SC_RPC_HANDLE hSCManager,
LPCWSTR lpServiceName,
LPWSTR lpDisplayName,
/* If the service could not be found and lpcchBuffer is less than 2, windows
puts null in lpDisplayName and puts 2 in lpcchBuffer */
- if (*lpcchBuffer < 2)
+ if (*lpcchBuffer < sizeof(WCHAR))
{
- *lpcchBuffer = 2;
+ *lpcchBuffer = sizeof(WCHAR);
if (lpDisplayName != NULL)
{
*lpDisplayName = 0;
/* Function 21 */
-DWORD RGetServiceKeyNameW(
+DWORD
+WINAPI
+RGetServiceKeyNameW(
SC_RPC_HANDLE hSCManager,
LPCWSTR lpDisplayName,
LPWSTR lpServiceName,
/* If the service could not be found and lpcchBuffer is less than 2, windows
puts null in lpDisplayName and puts 2 in lpcchBuffer */
- if (*lpcchBuffer < 2)
+ if (*lpcchBuffer < sizeof(WCHAR))
{
- *lpcchBuffer = 2;
+ *lpcchBuffer = sizeof(WCHAR);
if (lpServiceName != NULL)
{
*lpServiceName = 0;
/* Function 22 */
-DWORD RI_ScSetServiceBitsA(
+DWORD
+WINAPI
+RI_ScSetServiceBitsA(
RPC_SERVICE_STATUS_HANDLE hServiceStatus,
DWORD dwServiceBits,
int bSetBitsOn,
int bUpdateImmediately,
char *lpString)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ if (ScmShutdown)
+ return ERROR_SHUTDOWN_IN_PROGRESS;
+
+ if (lpString != NULL)
+ return ERROR_INVALID_PARAMETER;
+
+ return RI_ScSetServiceBitsW(hServiceStatus,
+ dwServiceBits,
+ bSetBitsOn,
+ bUpdateImmediately,
+ NULL);
}
/* Function 23 */
-DWORD RChangeServiceConfigA(
+DWORD
+WINAPI
+RChangeServiceConfigA(
SC_RPC_HANDLE hService,
DWORD dwServiceType,
DWORD dwStartType,
LPSTR lpDisplayName)
{
DWORD dwError = ERROR_SUCCESS;
- PSERVICE_HANDLE hSvc;
- PSERVICE lpService = NULL;
- HKEY hServiceKey = NULL;
- LPWSTR lpDisplayNameW = NULL;
LPWSTR lpBinaryPathNameW = NULL;
- LPWSTR lpCanonicalImagePathW = NULL;
LPWSTR lpLoadOrderGroupW = NULL;
LPWSTR lpDependenciesW = NULL;
+ LPWSTR lpServiceStartNameW = NULL;
+ LPWSTR lpDisplayNameW = NULL;
+ DWORD dwDependenciesLength = 0;
+ SIZE_T cchLength;
+ int len;
+ LPCSTR lpStr;
- DPRINT("RChangeServiceConfigA() 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);
-
- if (ScmShutdown)
- return ERROR_SHUTDOWN_IN_PROGRESS;
-
- hSvc = ScmGetServiceFromHandle(hService);
- if (hSvc == NULL)
- {
- DPRINT1("Invalid service handle!\n");
- return ERROR_INVALID_HANDLE;
- }
-
- if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
- SERVICE_CHANGE_CONFIG))
- {
- 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;
- }
-
- /* 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;
-
- /* Write service data to the registry */
-
- if (lpDisplayName != NULL && *lpDisplayName != 0)
+ if (lpBinaryPathName)
{
- /* Set the display name */
- lpDisplayNameW = HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
- if (lpDisplayNameW == NULL)
+ len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
+ lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
+ if (!lpBinaryPathNameW)
{
- dwError = ERROR_NOT_ENOUGH_MEMORY;
- goto done;
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
}
-
- MultiByteToWideChar(CP_ACP,
- 0,
- lpDisplayName,
- -1,
- lpDisplayNameW,
- (int)(strlen(lpDisplayName) + 1));
-
- RegSetValueExW(hServiceKey,
- L"DisplayName",
- 0,
- REG_SZ,
- (LPBYTE)lpDisplayNameW,
- (DWORD)((wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR)));
-
- /* Update lpService->lpDisplayName */
- if (lpService->lpDisplayName)
- HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
-
- lpService->lpDisplayName = lpDisplayNameW;
- }
-
- if (dwServiceType != SERVICE_NO_CHANGE)
- {
- /* 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;
- }
-
- 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;
-
- lpService->dwStartType = dwStartType;
- }
-
- 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;
+ MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
}
- if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
+ if (lpLoadOrderGroup)
{
- /* Set the image path */
- lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
- if (lpBinaryPathNameW == NULL)
- {
- dwError = ERROR_NOT_ENOUGH_MEMORY;
- goto done;
- }
-
- MultiByteToWideChar(CP_ACP,
- 0,
- lpBinaryPathName,
- -1,
- lpBinaryPathNameW,
- (int)(strlen(lpBinaryPathName) + 1));
-
- if (lpService->Status.dwServiceType & SERVICE_DRIVER)
+ len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
+ lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
+ if (!lpLoadOrderGroupW)
{
- dwError = ScmCanonDriverImagePath(lpService->dwStartType,
- lpBinaryPathNameW,
- &lpCanonicalImagePathW);
-
- HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
-
- if (dwError != ERROR_SUCCESS)
- goto done;
-
- lpBinaryPathNameW = lpCanonicalImagePathW;
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
}
-
- 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;
+ MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
}
- /* Set the group name */
- if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
+ if (lpDependencies)
{
- lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
- if (lpLoadOrderGroupW == NULL)
+ lpStr = (LPCSTR)lpDependencies;
+ while (*lpStr)
{
- dwError = ERROR_NOT_ENOUGH_MEMORY;
- goto done;
+ cchLength = strlen(lpStr) + 1;
+ dwDependenciesLength += (DWORD)cchLength;
+ lpStr = lpStr + cchLength;
}
+ dwDependenciesLength++;
- MultiByteToWideChar(CP_ACP,
- 0,
- lpLoadOrderGroup,
- -1,
- lpLoadOrderGroupW,
- (int)(strlen(lpLoadOrderGroup) + 1));
-
- dwError = RegSetValueExW(hServiceKey,
- L"Group",
- 0,
- REG_SZ,
- (LPBYTE)lpLoadOrderGroupW,
- (DWORD)((wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR)));
- if (dwError != ERROR_SUCCESS)
+ lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
+ if (!lpDependenciesW)
{
- HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
- goto done;
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
}
-
- dwError = ScmSetServiceGroup(lpService,
- lpLoadOrderGroupW);
-
- HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
-
- if (dwError != ERROR_SUCCESS)
- goto done;
+ MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
}
- if (lpdwTagId != NULL)
+ if (lpServiceStartName)
{
- dwError = ScmAssignNewTag(lpService);
- if (dwError != ERROR_SUCCESS)
- goto done;
-
- dwError = RegSetValueExW(hServiceKey,
- L"Tag",
- 0,
- REG_DWORD,
- (LPBYTE)&lpService->dwTag,
- sizeof(DWORD));
- if (dwError != ERROR_SUCCESS)
- goto done;
-
- *lpdwTagId = lpService->dwTag;
+ len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
+ lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
+ if (!lpServiceStartNameW)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
+ }
+ MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
}
- /* Write dependencies */
- if (lpDependencies != NULL && *lpDependencies != 0)
+ if (lpDisplayName)
{
- lpDependenciesW = HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- (strlen((LPSTR)lpDependencies) + 1) * sizeof(WCHAR));
- if (lpDependenciesW == NULL)
+ len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
+ lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
+ if (!lpDisplayNameW)
{
- dwError = ERROR_NOT_ENOUGH_MEMORY;
- goto done;
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto cleanup;
}
+ MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
+ }
- MultiByteToWideChar(CP_ACP,
- 0,
- (LPSTR)lpDependencies,
- dwDependSize,
- lpDependenciesW,
- (int)(strlen((LPSTR)lpDependencies) + 1));
-
- dwError = ScmWriteDependencies(hServiceKey,
- (LPWSTR)lpDependenciesW,
- dwDependSize);
+ dwError = RChangeServiceConfigW(hService,
+ dwServiceType,
+ dwStartType,
+ dwErrorControl,
+ lpBinaryPathNameW,
+ lpLoadOrderGroupW,
+ lpdwTagId,
+ (LPBYTE)lpDependenciesW,
+ dwDependenciesLength,
+ lpServiceStartNameW,
+ lpPassword,
+ dwPwSize,
+ lpDisplayNameW);
- HeapFree(GetProcessHeap(), 0, lpDependenciesW);
- }
+cleanup:
+ if (lpBinaryPathNameW != NULL)
+ HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
- if (lpPassword != NULL)
- {
- /* FIXME: Decrypt and write password */
- }
+ if (lpLoadOrderGroupW != NULL)
+ HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
-done:
- /* Unlock the service database */
- ScmUnlockDatabase();
+ if (lpDependenciesW != NULL)
+ HeapFree(GetProcessHeap(), 0, lpDependenciesW);
- if (hServiceKey != NULL)
- RegCloseKey(hServiceKey);
+ if (lpServiceStartNameW != NULL)
+ HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
- DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
+ if (lpDisplayNameW != NULL)
+ HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
return dwError;
}
/* Function 24 */
-DWORD RCreateServiceA(
+DWORD
+WINAPI
+RCreateServiceA(
SC_RPC_HANDLE hSCManager,
LPSTR lpServiceName,
LPSTR lpDisplayName,
/* Function 25 */
-DWORD REnumDependentServicesA(
+DWORD
+WINAPI
+REnumDependentServicesA(
SC_RPC_HANDLE hService,
DWORD dwServiceState,
LPBYTE lpServices,
/* Function 26 */
-DWORD REnumServicesStatusA(
+DWORD
+WINAPI
+REnumServicesStatusA(
SC_RPC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
/* Function 27 */
-DWORD ROpenSCManagerA(
+DWORD
+WINAPI
+ROpenSCManagerA(
LPSTR lpMachineName,
LPSTR lpDatabaseName,
DWORD dwDesiredAccess,
/* Function 28 */
-DWORD ROpenServiceA(
+DWORD
+WINAPI
+ROpenServiceA(
SC_RPC_HANDLE hSCManager,
LPSTR lpServiceName,
DWORD dwDesiredAccess,
/* Function 29 */
-DWORD RQueryServiceConfigA(
+DWORD
+WINAPI
+RQueryServiceConfigA(
SC_RPC_HANDLE hService,
LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
DWORD cbBufSize,
LPWSTR lpDependencies = NULL;
DWORD dwDependenciesLength = 0;
DWORD dwRequiredSize;
- CHAR lpEmptyString[]={0,0};
LPSTR lpStr;
DPRINT("RQueryServiceConfigA() called\n");
if (lpImagePath != NULL)
dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1);
else
- dwRequiredSize += 2;
+ dwRequiredSize += 2 * sizeof(CHAR);
if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1);
else
- dwRequiredSize += 2;
+ dwRequiredSize += 2 * sizeof(CHAR);
/* Add Dependencies length */
if (lpDependencies != NULL)
dwRequiredSize += dwDependenciesLength;
else
- dwRequiredSize += 2;
+ dwRequiredSize += 2 * sizeof(CHAR);
if (lpServiceStartName != NULL)
dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1);
else
- dwRequiredSize += 2;
+ dwRequiredSize += 2 * sizeof(CHAR);
if (lpService->lpDisplayName != NULL)
dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1);
else
- dwRequiredSize += 2;
+ dwRequiredSize += 2 * sizeof(CHAR);
if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
{
}
else
{
- strcpy(lpStr, lpEmptyString);
+ *lpStr = 0;
}
lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
}
else
{
- strcpy(lpStr, lpEmptyString);
+ *lpStr = 0;
}
lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
}
else
{
- strcpy(lpStr, lpEmptyString);
+ *lpStr = 0;
}
lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
}
else
{
- strcpy(lpStr, lpEmptyString);
+ *lpStr = 0;
}
lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
}
else
{
- strcpy(lpStr, lpEmptyString);
+ *lpStr = 0;
}
lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
/* Function 30 */
-DWORD RQueryServiceLockStatusA(
+DWORD
+WINAPI
+RQueryServiceLockStatusA(
SC_RPC_HANDLE hSCManager,
LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
DWORD cbBufSize,
/* Function 31 */
-DWORD RStartServiceA(
+DWORD
+WINAPI
+RStartServiceA(
SC_RPC_HANDLE hService,
DWORD argc,
LPSTRING_PTRSA argv)
/* Function 32 */
-DWORD RGetServiceDisplayNameA(
+DWORD
+WINAPI
+RGetServiceDisplayNameA(
SC_RPC_HANDLE hSCManager,
LPCSTR lpServiceName,
LPSTR lpDisplayName,
puts null in lpDisplayName and puts 1 in lpcchBuffer */
if (*lpcchBuffer == 0)
{
- *lpcchBuffer = 1;
+ *lpcchBuffer = sizeof(CHAR);
if (lpDisplayName != NULL)
{
*lpDisplayName = 0;
/* Function 33 */
-DWORD RGetServiceKeyNameA(
+DWORD
+WINAPI
+RGetServiceKeyNameA(
SC_RPC_HANDLE hSCManager,
LPCSTR lpDisplayName,
LPSTR lpServiceName,
put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
if (*lpcchBuffer == 0)
{
- *lpcchBuffer = 1;
+ *lpcchBuffer = sizeof(CHAR);
if (lpServiceName != NULL)
{
*lpServiceName = 0;
/* Function 34 */
-DWORD RI_ScGetCurrentGroupStateW(
+DWORD
+WINAPI
+RI_ScGetCurrentGroupStateW(
SC_RPC_HANDLE hSCManager,
LPWSTR lpLoadOrderGroup,
LPDWORD lpState)
{
- UNIMPLEMENTED;
- return ERROR_CALL_NOT_IMPLEMENTED;
+ PMANAGER_HANDLE hManager;
+ PSERVICE_GROUP pServiceGroup;
+ DWORD dwError = ERROR_SUCCESS;
+
+ DPRINT("RI_ScGetCurrentGroupStateW() 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;
+ }
+
+ /* Check for SC_MANAGER_ENUMERATE_SERVICE access right */
+ if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
+ SC_MANAGER_ENUMERATE_SERVICE))
+ {
+ DPRINT("Insufficient access rights! 0x%lx\n",
+ hManager->Handle.DesiredAccess);
+ return ERROR_ACCESS_DENIED;
+ }
+
+ /* Lock the service database shared */
+ ScmLockDatabaseShared();
+
+ /* Get the group list entry */
+ pServiceGroup = ScmGetServiceGroupByName(lpLoadOrderGroup);
+ if (pServiceGroup == NULL)
+ {
+ dwError = ERROR_SERVICE_DOES_NOT_EXIST;
+ goto done;
+ }
+
+ /* FIXME: Return the group state */
+ *lpState = 0;
+
+done:
+ /* Unlock the service database */
+ ScmUnlockDatabase();
+
+ DPRINT("RI_ScGetCurrentGroupStateW() done (Error %lu)\n", dwError);
+
+ return dwError;
}
/* Function 35 */
-DWORD REnumServiceGroupW(
+DWORD
+WINAPI
+REnumServiceGroupW(
SC_RPC_HANDLE hSCManager,
DWORD dwServiceType,
DWORD dwServiceState,
}
-//
-// WARNING: This function is untested
-//
/* Function 36 */
-DWORD RChangeServiceConfig2A(
+DWORD
+WINAPI
+RChangeServiceConfig2A(
SC_RPC_HANDLE hService,
SC_RPC_CONFIG_INFOA Info)
{
- SC_RPC_CONFIG_INFOW InfoW;
+ SC_RPC_CONFIG_INFOW InfoW = { 0 };
DWORD dwRet, dwLength;
PVOID ptr = NULL;
DPRINT("RChangeServiceConfig2A() called\n");
DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
+ if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
+ (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+ {
+ return ERROR_INVALID_LEVEL;
+ }
+
InfoW.dwInfoLevel = Info.dwInfoLevel;
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)
- ///{
- dwLength = (DWORD)((strlen(Info.lpDescription) + 1) * sizeof(WCHAR));
+ if (lpServiceDescriptionA &&
+ lpServiceDescriptionA->lpDescription)
+ {
+ dwLength = (DWORD)((strlen(lpServiceDescriptionA->lpDescription) + 1) * sizeof(WCHAR));
- lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- 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,
+ lpServiceDescriptionA->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 = (DWORD)((strlen(lpServiceFailureActionsA->lpRebootMsg) + 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(),
HEAP_ZERO_MEMORY,
dwLength);
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,
+ScmSetFailureActions(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 */
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.
+ * 1- Retrieve the original value of FailureActions.
*/
/* Query value length */
NULL,
&dwType,
NULL,
- &dwRequiredSize);
+ &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);
lpReadBuffer->lpCommand = NULL;
/*
- * 3- Initialize the new value to set.
+ * 2- Initialize the new value to set.
*/
dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
/* Function 37 */
-DWORD RChangeServiceConfig2W(
+DWORD
+WINAPI
+RChangeServiceConfig2W(
SC_RPC_HANDLE hService,
SC_RPC_CONFIG_INFOW Info)
{
PSERVICE_HANDLE hSvc;
PSERVICE lpService = NULL;
HKEY hServiceKey = NULL;
+ ACCESS_MASK RequiredAccess = SERVICE_CHANGE_CONFIG;
DPRINT("RChangeServiceConfig2W() called\n");
DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
if (ScmShutdown)
return ERROR_SHUTDOWN_IN_PROGRESS;
+ if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
+ (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+ {
+ return ERROR_INVALID_LEVEL;
+ }
+
hSvc = ScmGetServiceFromHandle(hService);
if (hSvc == NULL)
{
- DPRINT1("Invalid service handle!\n");
+ DPRINT("Invalid service handle!\n");
return ERROR_INVALID_HANDLE;
}
+ if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
+ RequiredAccess |= SERVICE_START;
+
+ /* Check the access rights */
if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
- SERVICE_CHANGE_CONFIG))
+ RequiredAccess))
{
DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
return ERROR_ACCESS_DENIED;
}
+ if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
+ {
+ /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */
+
+ }
+
lpService = hSvc->ServiceEntry;
if (lpService == NULL)
{
return ERROR_INVALID_HANDLE;
}
+ /* Failure actions can only be set for Win32 services, not for drivers */
+ if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
+ {
+ if (lpService->Status.dwServiceType & SERVICE_DRIVER)
+ return ERROR_CANNOT_DETECT_DRIVER_FAILURE;
+ }
+
/* Lock the service database exclusively */
ScmLockDatabaseExclusive();
}
else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
{
- dwError = ScmSetFailureActions(hSvc,
- lpService,
- hServiceKey,
+ dwError = ScmSetFailureActions(hServiceKey,
(LPSERVICE_FAILURE_ACTIONSW)Info.psfa);
}
/* Function 38 */
-DWORD RQueryServiceConfig2A(
+DWORD
+WINAPI
+RQueryServiceConfig2A(
SC_RPC_HANDLE hService,
DWORD dwInfoLevel,
LPBYTE lpBuffer,
if (ScmShutdown)
return ERROR_SHUTDOWN_IN_PROGRESS;
+ if ((dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
+ (dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+ {
+ return ERROR_INVALID_LEVEL;
+ }
+
hSvc = ScmGetServiceFromHandle(hService);
if (hSvc == NULL)
{
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);
/* Function 39 */
-DWORD RQueryServiceConfig2W(
+DWORD
+WINAPI
+RQueryServiceConfig2W(
SC_RPC_HANDLE hService,
DWORD dwInfoLevel,
LPBYTE lpBuffer,
if (ScmShutdown)
return ERROR_SHUTDOWN_IN_PROGRESS;
+ if ((dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) ||
+ (dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS))
+ {
+ return ERROR_INVALID_LEVEL;
+ }
+
hSvc = ScmGetServiceFromHandle(hService);
if (hSvc == NULL)
{
if (dwError != ERROR_SUCCESS &&
dwError != ERROR_MORE_DATA &&
dwError != ERROR_FILE_NOT_FOUND)
+ {
goto done;
+ }
dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize)
: sizeof(SERVICE_FAILURE_ACTIONSW);
/* Function 40 */
-DWORD RQueryServiceStatusEx(
+DWORD
+WINAPI
+RQueryServiceStatusEx(
SC_RPC_HANDLE hService,
SC_STATUS_TYPE InfoLevel,
LPBYTE lpBuffer,
&lpService->Status,
sizeof(SERVICE_STATUS));
- lpStatus->dwProcessId = (lpService->lpImage != NULL) ? lpService->lpImage->dwProcessId : 0; /* FIXME */
- lpStatus->dwServiceFlags = 0; /* FIXME */
+ /* Copy the service process ID */
+ if ((lpService->Status.dwCurrentState == SERVICE_STOPPED) || (lpService->lpImage == NULL))
+ lpStatus->dwProcessId = 0;
+ else
+ lpStatus->dwProcessId = lpService->lpImage->dwProcessId;
+
+ lpStatus->dwServiceFlags = 0; /* FIXME */
/* Unlock the service database */
ScmUnlockDatabase();
/* Function 41 */
-DWORD REnumServicesStatusExA(
+DWORD
+WINAPI
+REnumServicesStatusExA(
SC_RPC_HANDLE hSCManager,
SC_ENUM_TYPE InfoLevel,
DWORD dwServiceType,
if (!pszGroupNameW)
{
DPRINT("Failed to allocate buffer!\n");
- return ERROR_NOT_ENOUGH_MEMORY;
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto Done;
}
MultiByteToWideChar(CP_ACP,
if (!lpStatusPtrW)
{
DPRINT("Failed to allocate buffer!\n");
- return ERROR_NOT_ENOUGH_MEMORY;
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto Done;
}
}
&lpStatusPtrIncrW->ServiceStatusProcess,
sizeof(SERVICE_STATUS));
- lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrIncrW->ServiceStatusProcess.dwProcessId; /* FIXME */
+ /* Copy the service process ID */
+ lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrIncrW->ServiceStatusProcess.dwProcessId;
+
lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
lpStatusPtrIncrW++;
/* Function 42 */
-DWORD REnumServicesStatusExW(
+DWORD
+WINAPI
+REnumServicesStatusExW(
SC_RPC_HANDLE hSCManager,
SC_ENUM_TYPE InfoLevel,
DWORD dwServiceType,
memcpy(&lpStatusPtr->ServiceStatusProcess,
&CurrentService->Status,
sizeof(SERVICE_STATUS));
- lpStatusPtr->ServiceStatusProcess.dwProcessId =
- (CurrentService->lpImage != NULL) ? CurrentService->lpImage->dwProcessId : 0; /* FIXME */
+
+ /* Copy the service process ID */
+ if ((CurrentService->Status.dwCurrentState == SERVICE_STOPPED) || (CurrentService->lpImage == NULL))
+ lpStatusPtr->ServiceStatusProcess.dwProcessId = 0;
+ else
+ lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->lpImage->dwProcessId;
+
lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
lpStatusPtr++;
/* Function 43 */
-DWORD RSendTSMessage(
+DWORD
+WINAPI
+RSendTSMessage(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;
/* Function 44 */
-DWORD RCreateServiceWOW64A(
+DWORD
+WINAPI
+RCreateServiceWOW64A(
handle_t BindingHandle,
LPSTR lpServiceName,
LPSTR lpDisplayName,
/* Function 45 */
-DWORD RCreateServiceWOW64W(
+DWORD
+WINAPI
+RCreateServiceWOW64W(
handle_t BindingHandle,
LPWSTR lpServiceName,
LPWSTR lpDisplayName,
/* Function 46 */
-DWORD RQueryServiceTagInfo(
+DWORD
+WINAPI
+RQueryServiceTagInfo(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;
/* Function 47 */
-DWORD RNotifyServiceStatusChange(
+DWORD
+WINAPI
+RNotifyServiceStatusChange(
SC_RPC_HANDLE hService,
SC_RPC_NOTIFY_PARAMS NotifyParams,
GUID *pClientProcessGuid,
/* Function 48 */
-DWORD RGetNotifyResults(
+DWORD
+WINAPI
+RGetNotifyResults(
SC_NOTIFY_RPC_HANDLE hNotify,
PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
{
/* Function 49 */
-DWORD RCloseNotifyHandle(
+DWORD
+WINAPI
+RCloseNotifyHandle(
LPSC_NOTIFY_RPC_HANDLE phNotify,
PBOOL pfApcFired)
{
/* Function 50 */
-DWORD RControlServiceExA(
+DWORD
+WINAPI
+RControlServiceExA(
SC_RPC_HANDLE hService,
DWORD dwControl,
DWORD dwInfoLevel)
/* Function 51 */
-DWORD RControlServiceExW(
+DWORD
+WINAPI
+RControlServiceExW(
SC_RPC_HANDLE hService,
DWORD dwControl,
DWORD dwInfoLevel)
/* Function 52 */
-DWORD RSendPnPMessage(
+DWORD
+WINAPI
+RSendPnPMessage(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;
/* Function 53 */
-DWORD RValidatePnPService(
+DWORD
+WINAPI
+RValidatePnPService(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;
/* Function 54 */
-DWORD ROpenServiceStatusHandle(
+DWORD
+WINAPI
+ROpenServiceStatusHandle(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;
/* Function 55 */
-DWORD RFunction55(
+DWORD
+WINAPI
+RFunction55(
handle_t BindingHandle) /* FIXME */
{
UNIMPLEMENTED;