[SERVICES]
[reactos.git] / reactos / base / system / services / rpcserver.c
index 4c877d2..118b760 100644 (file)
@@ -12,6 +12,8 @@
 
 #include "services.h"
 
+#include <winnls.h>
+
 #define NDEBUG
 #include <debug.h>
 
@@ -503,16 +505,20 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
     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,
@@ -520,17 +526,18 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
         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,
@@ -541,24 +548,20 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
 
     /* 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;
             }
 
@@ -571,13 +574,13 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
             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);
@@ -593,9 +596,6 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
                     if (*RelativeName == NULL)
                     {
                         DPRINT("Unable to alloc buffer\n");
-                        if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
-                        HeapFree(GetProcessHeap(), 0, Expanded);
-                        RtlFreeUnicodeString(&NtPathName);
                         return ERROR_NOT_ENOUGH_MEMORY;
                     }
 
@@ -604,37 +604,24 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
                     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;
         }
     }
@@ -642,7 +629,6 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
     {
         /* Failure */
         DPRINT("Error, Status = %08X\n", Status);
-        HeapFree(GetProcessHeap(), 0, Expanded);
         return ERROR_INVALID_PARAMETER;
     }
 }
@@ -1083,6 +1069,9 @@ DWORD RControlService(
     DWORD dwControlsAccepted;
     DWORD dwCurrentState;
     HKEY hServicesKey = NULL;
+    LPCWSTR lpLogStrings[2];
+    WCHAR szLogBuffer[80];
+    UINT uID;
 
     DPRINT("RControlService() called\n");
 
@@ -1240,6 +1229,40 @@ DWORD RControlService(
                       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;
 }
 
@@ -1615,12 +1638,14 @@ DWORD RSetServiceStatus(
 {
     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);
@@ -1658,33 +1683,79 @@ DWORD RSetServiceStatus(
         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);
@@ -1753,7 +1824,7 @@ DWORD RChangeServiceConfigW(
     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);
@@ -1822,6 +1893,7 @@ DWORD RChangeServiceConfigW(
             goto done;
         }
 
+        wcscpy(lpDisplayNameW, lpDisplayName);
         if (lpService->lpDisplayName != lpService->lpServiceName)
             HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
 
@@ -1997,7 +2069,7 @@ DWORD RCreateServiceW(
     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);
@@ -2251,6 +2323,7 @@ DWORD RCreateServiceW(
             goto done;
     }
 
+    /* Set the service tag */
     if (lpdwTagId != NULL)
     {
         dwError = RegSetValueExW(hServiceKey,
@@ -2273,9 +2346,10 @@ DWORD RCreateServiceW(
             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",
@@ -2285,11 +2359,17 @@ DWORD RCreateServiceW(
                                  (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,
@@ -2895,7 +2975,6 @@ DWORD RStartServiceW(
     DWORD dwError = ERROR_SUCCESS;
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService = NULL;
-    SC_RPC_LOCK Lock = NULL;
 
 #ifndef NDEBUG
     DWORD i;
@@ -2941,17 +3020,9 @@ DWORD RStartServiceW(
     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;
 }
 
@@ -4171,7 +4242,6 @@ DWORD RStartServiceA(
     DWORD dwError = ERROR_SUCCESS;
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService = NULL;
-    SC_RPC_LOCK Lock = NULL;
     LPWSTR *lpVector = NULL;
     DWORD i;
     DWORD dwLength;
@@ -4244,17 +4314,9 @@ DWORD RStartServiceA(
         }
     }
 
-    /* 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)
@@ -4730,9 +4792,6 @@ Done:
 }
 
 
-//
-// WARNING: This function is untested
-//
 /* Function 36 */
 DWORD RChangeServiceConfig2A(
     SC_RPC_HANDLE hService,
@@ -4749,48 +4808,57 @@ DWORD RChangeServiceConfig2A(
 
     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));
@@ -4799,8 +4867,22 @@ DWORD RChangeServiceConfig2A(
             {
                 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);
@@ -4809,22 +4891,56 @@ DWORD RChangeServiceConfig2A(
                 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,
@@ -4833,7 +4949,9 @@ DWORD RChangeServiceConfig2A(
                                     dwCommandLen);
             }
 
+            /* Set the pointers */
             ptr = lpServiceFailureActionsW;
+            InfoW.psfa = lpServiceFailureActionsW;
         }
     }
 
@@ -5771,7 +5889,8 @@ DWORD REnumServicesStatusExA(
         if (!pszGroupNameW)
         {
              DPRINT("Failed to allocate buffer!\n");
-             return ERROR_NOT_ENOUGH_MEMORY;
+             dwError = ERROR_NOT_ENOUGH_MEMORY;
+             goto Done;
         }
 
         MultiByteToWideChar(CP_ACP,
@@ -5788,7 +5907,8 @@ DWORD REnumServicesStatusExA(
         if (!lpStatusPtrW)
         {
             DPRINT("Failed to allocate buffer!\n");
-            return ERROR_NOT_ENOUGH_MEMORY;
+            dwError = ERROR_NOT_ENOUGH_MEMORY;
+            goto Done;
         }
     }