#include "services.h"
+#include <winnls.h>
+
#define NDEBUG
#include <debug.h>
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;
}
}
DWORD dwControlsAccepted;
DWORD dwCurrentState;
HKEY hServicesKey = NULL;
+ LPCWSTR lpLogStrings[2];
+ WCHAR szLogBuffer[80];
+ UINT uID;
DPRINT("RControlService() called\n");
sizeof(SERVICE_STATUS));
}
+ if (dwError == ERROR_SUCCESS)
+ {
+ if (dwControl == SERVICE_CONTROL_STOP ||
+ dwControl == SERVICE_CONTROL_PAUSE ||
+ dwControl == SERVICE_CONTROL_CONTINUE)
+ {
+ /* Log a sucessful 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, 80);
+
+ lpLogStrings[0] = lpService->lpDisplayName;
+ lpLogStrings[1] = szLogBuffer;
+
+ ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
+ EVENTLOG_INFORMATION_TYPE,
+ 2,
+ lpLogStrings);
+ }
+ }
+
return dwError;
}
{
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;
+
/* 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 */
+ swprintf(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;
+
+ case SERVICE_RUNNING:
+ uID = IDS_SERVICE_RUNNING;
+ break;
- ScmLogError(EVENT_SERVICE_EXIT_FAILED,
- 2,
- lpErrorStrings);
+ case SERVICE_PAUSED:
+ uID = IDS_SERVICE_PAUSED;
+ break;
}
+
+ LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, 80);
+ 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);
LPWSTR lpImagePathW = 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);
goto done;
}
+ wcscpy(lpDisplayNameW, lpDisplayName);
if (lpService->lpDisplayName != lpService->lpServiceName)
HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
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);
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 && wcslen((LPWSTR)lpPassword) != 0)
+ {
+ /* FIXME: Decrypt the password */
+
+ /* Write the password */
+ dwError = ScmSetServicePassword(lpServiceName,
+ (LPCWSTR)lpPassword);
+ if (dwError != ERROR_SUCCESS)
+ goto done;
+ }
}
dwError = ScmCreateServiceHandle(lpService,
DWORD dwError = ERROR_SUCCESS;
PSERVICE_HANDLE hSvc;
PSERVICE lpService = NULL;
- SC_RPC_LOCK Lock = NULL;
#ifndef NDEBUG
DWORD i;
if (lpService->bDeleted)
return ERROR_SERVICE_MARKED_FOR_DELETE;
- /* Acquire the service start lock until the service has been started */
- dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
- if (dwError != ERROR_SUCCESS)
- return dwError;
-
/* Start the service */
dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
- /* Release the service start lock */
- ScmReleaseServiceStartLock(&Lock);
-
return dwError;
}
DWORD dwError = ERROR_SUCCESS;
PSERVICE_HANDLE hSvc;
PSERVICE lpService = NULL;
- SC_RPC_LOCK Lock = NULL;
LPWSTR *lpVector = NULL;
DWORD i;
DWORD dwLength;
}
}
- /* Acquire the service start lock until the service has been started */
- dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
- if (dwError != ERROR_SUCCESS)
- goto done;
-
/* Start the service */
dwError = ScmStartService(lpService, argc, lpVector);
- /* Release the service start lock */
- ScmReleaseServiceStartLock(&Lock);
-
done:
/* Free the Unicode argument vector */
if (lpVector != NULL)
}
-//
-// 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)
- ///{
- 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;
}
}
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;
}
}