[MSIEXEC] Sync with Wine Staging 2.16. CORE-13762
[reactos.git] / base / system / services / services.c
index 4163a3c..58a6256 100644 (file)
@@ -21,9 +21,6 @@ int WINAPI RegisterServicesProcess(DWORD ServicesProcessId);
 
 /* GLOBALS ******************************************************************/
 
-#define PIPE_BUFSIZE 1024
-#define PIPE_TIMEOUT 1000
-
 /* Defined in include/reactos/services/services.h */
 // #define SCM_START_EVENT             L"SvcctrlStartEvent_A3752DX"
 #define SCM_AUTOSTARTCOMPLETE_EVENT L"SC_AutoStartComplete"
@@ -53,7 +50,8 @@ PrintString(LPCSTR fmt, ...)
 
 
 VOID
-ScmLogError(DWORD dwEventId,
+ScmLogEvent(DWORD dwEventId,
+            WORD wType,
             WORD wStrings,
             LPCWSTR *lpStrings)
 {
@@ -68,10 +66,10 @@ ScmLogError(DWORD dwEventId,
     }
 
     if (!ReportEventW(hLog,
-                      EVENTLOG_ERROR_TYPE,
+                      wType,
                       0,
                       dwEventId,
-                      NULL, // Sid,
+                      NULL,
                       wStrings,
                       0,
                       lpStrings,
@@ -104,202 +102,198 @@ ScmWaitForLsa(VOID)
 }
 
 
-BOOL
-ScmNamedPipeHandleRequest(PVOID Request,
-                          DWORD RequestSize,
-                          PVOID Reply,
-                          LPDWORD ReplySize)
-{
-    DbgPrint("SCM READ: %p\n", Request);
-
-    *ReplySize = 0;
-    return FALSE;
-}
-
-
-DWORD WINAPI
-ScmNamedPipeThread(LPVOID Context)
+BOOL WINAPI
+ShutdownHandlerRoutine(DWORD dwCtrlType)
 {
-    CHAR chRequest[PIPE_BUFSIZE];
-    CHAR chReply[PIPE_BUFSIZE];
-    DWORD cbReplyBytes;
-    DWORD cbBytesRead;
-    DWORD cbWritten;
-    BOOL bSuccess;
-    HANDLE hPipe;
-
-    hPipe = (HANDLE)Context;
-
-    DPRINT("ScmNamedPipeThread(%p) - Accepting SCM commands through named pipe\n", hPipe);
+    DPRINT1("ShutdownHandlerRoutine() called\n");
 
-    for (;;)
+    if (dwCtrlType & (CTRL_SHUTDOWN_EVENT | CTRL_LOGOFF_EVENT))
     {
-        bSuccess = ReadFile(hPipe,
-                            &chRequest,
-                            PIPE_BUFSIZE,
-                            &cbBytesRead,
-                            NULL);
-        if (!bSuccess || cbBytesRead == 0)
-        {
-            break;
-        }
+        DPRINT1("Shutdown event received!\n");
+        ScmShutdown = TRUE;
 
-        if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes))
-        {
-            bSuccess = WriteFile(hPipe,
-                                 &chReply,
-                                 cbReplyBytes,
-                                 &cbWritten,
-                                 NULL);
-            if (!bSuccess || cbReplyBytes != cbWritten)
-            {
-                break;
-            }
-        }
-    }
+        ScmAutoShutdownServices();
+        ScmShutdownServiceDatabase();
 
-    DPRINT("ScmNamedPipeThread(%p) - Disconnecting named pipe connection\n", hPipe);
+        /* Set the shutdown event */
+        SetEvent(hScmShutdownEvent);
+    }
 
-    FlushFileBuffers(hPipe);
-    DisconnectNamedPipe(hPipe);
-    CloseHandle(hPipe);
+    return TRUE;
+}
 
-    DPRINT("ScmNamedPipeThread(%p) - Done.\n", hPipe);
 
-    return ERROR_SUCCESS;
-}
+/*** HACK CORE-12541: Special service accounts initialization HACK ************/
 
+#include <ndk/setypes.h>
+#include <sddl.h>
+#include <userenv.h>
+#include <strsafe.h>
 
+/* Inspired from userenv.dll's CreateUserProfileExW and LoadUserProfileW APIs */
+static
 BOOL
-ScmCreateNamedPipe(VOID)
+ScmLogAccountHack(IN LPCWSTR pszAccountName,
+                  IN LPCWSTR pszSid,
+                  OUT PHKEY phProfile)
 {
-    DWORD dwThreadId;
-    BOOL bConnected;
-    HANDLE hThread;
-    HANDLE hPipe;
-
-    DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n");
-
-    hPipe = CreateNamedPipeW(L"\\\\.\\pipe\\Ntsvcs",
-              PIPE_ACCESS_DUPLEX,
-              PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
-              PIPE_UNLIMITED_INSTANCES,
-              PIPE_BUFSIZE,
-              PIPE_BUFSIZE,
-              PIPE_TIMEOUT,
-              NULL);
-    if (hPipe == INVALID_HANDLE_VALUE)
+    BOOL Success = FALSE;
+    LONG Error;
+    NTSTATUS Status;
+    BOOLEAN WasPriv1Set = FALSE, WasPriv2Set = FALSE;
+    PSID pSid;
+    DWORD dwLength;
+    WCHAR szUserHivePath[MAX_PATH];
+
+    DPRINT1("ScmLogAccountsHack(%S, %S)\n", pszAccountName, pszSid);
+    if (!pszAccountName || !pszSid || !phProfile)
+        return ERROR_INVALID_PARAMETER;
+
+    /* Convert the SID string into a SID. NOTE: No RTL equivalent. */
+    if (!ConvertStringSidToSidW(pszSid, &pSid))
     {
-        DPRINT("CreateNamedPipe() failed (%lu)\n", GetLastError());
+        DPRINT1("ConvertStringSidToSidW() failed (error %lu)\n", GetLastError());
         return FALSE;
     }
 
-    DPRINT("CreateNamedPipe() - calling ConnectNamedPipe(%p)\n", hPipe);
-    bConnected = ConnectNamedPipe(hPipe,
-                                  NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
-    DPRINT("CreateNamedPipe() - ConnectNamedPipe() returned %d\n", bConnected);
+    /* Determine a suitable profile path */
+    dwLength = ARRAYSIZE(szUserHivePath);
+    if (!GetProfilesDirectoryW(szUserHivePath, &dwLength))
+    {
+        DPRINT1("GetProfilesDirectoryW() failed (error %lu)\n", GetLastError());
+        goto Quit;
+    }
+
+    /* Create user hive name */
+    StringCbCatW(szUserHivePath, sizeof(szUserHivePath), L"\\");
+    StringCbCatW(szUserHivePath, sizeof(szUserHivePath), pszAccountName);
+    StringCbCatW(szUserHivePath, sizeof(szUserHivePath), L"\\ntuser.dat");
+    DPRINT("szUserHivePath: %S\n", szUserHivePath);
 
-    if (bConnected)
+    /* Magic #1: Create the special user profile if needed */
+    if (GetFileAttributesW(szUserHivePath) == INVALID_FILE_ATTRIBUTES)
     {
-        DPRINT("Pipe connected\n");
-        hThread = CreateThread(NULL,
-                               0,
-                               ScmNamedPipeThread,
-                               (LPVOID)hPipe,
-                               0,
-                               &dwThreadId);
-        if (!hThread)
+        if (!CreateUserProfileW(pSid, pszAccountName))
         {
-            DPRINT("Could not create thread (%lu)\n", GetLastError());
-            DisconnectNamedPipe(hPipe);
-            CloseHandle(hPipe);
-            DPRINT("CreateNamedPipe() - returning FALSE\n");
-            return FALSE;
+            DPRINT1("CreateUserProfileW() failed (error %lu)\n", GetLastError());
+            goto Quit;
         }
+    }
 
-        CloseHandle(hThread);
+    /*
+     * Now Da Magiks #2: Manually mount the user profile registry hive
+     * aka. manually do what LoadUserProfile does!! But we don't require
+     * a security token!
+     */
+
+    /* Acquire restore privilege */
+    Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasPriv1Set);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE) failed (Error 0x%08lx)\n", Status);
+        goto Quit;
     }
-    else
+
+    /* Acquire backup privilege */
+    Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &WasPriv2Set);
+    if (!NT_SUCCESS(Status))
     {
-        DPRINT("Pipe not connected\n");
-        CloseHandle(hPipe);
-        DPRINT("CreateNamedPipe() - returning FALSE\n");
-        return FALSE;
+        DPRINT1("RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE) failed (Error 0x%08lx)\n", Status);
+        RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasPriv1Set, FALSE, &WasPriv1Set);
+        goto Quit;
     }
-    DPRINT("CreateNamedPipe() - returning TRUE\n");
-    return TRUE;
-}
 
+    /* Load user registry hive */
+    Error = RegLoadKeyW(HKEY_USERS, pszSid, szUserHivePath);
 
-DWORD WINAPI
-ScmNamedPipeListenerThread(LPVOID Context)
-{
-//    HANDLE hPipe;
-    DPRINT("ScmNamedPipeListenerThread(%p) - aka SCM.\n", Context);
+    /* Remove restore and backup privileges */
+    RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, WasPriv2Set, FALSE, &WasPriv2Set);
+    RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasPriv1Set, FALSE, &WasPriv1Set);
 
-//    hPipe = (HANDLE)Context;
-    for (;;)
+    /* HACK: Do not fail if the profile has already been loaded! */
+    if (Error == ERROR_SHARING_VIOLATION)
+        Error = ERROR_SUCCESS;
+
+    if (Error != ERROR_SUCCESS)
     {
-        DPRINT("SCM: Waiting for new connection on named pipe...\n");
-        /* Create named pipe */
-        if (!ScmCreateNamedPipe())
-        {
-            DPRINT1("\nSCM: Failed to create named pipe\n");
-            break;
-            //ExitThread(0);
-        }
-        DPRINT("\nSCM: named pipe session created.\n");
-        Sleep(10);
+        DPRINT1("RegLoadKeyW() failed (Error %ld)\n", Error);
+        goto Quit;
     }
-    DPRINT("\n\nWARNING: ScmNamedPipeListenerThread(%p) - Aborted.\n\n", Context);
-    return ERROR_SUCCESS;
-}
-
 
-BOOL
-StartScmNamedPipeThreadListener(VOID)
-{
-    DWORD dwThreadId;
-    HANDLE hThread;
-
-    hThread = CreateThread(NULL,
-                           0,
-                           ScmNamedPipeListenerThread,
-                           NULL, /*(LPVOID)hPipe,*/
-                           0,
-                           &dwThreadId);
-    if (!hThread)
+    /* Open future HKEY_CURRENT_USER */
+    Error = RegOpenKeyExW(HKEY_USERS,
+                          pszSid,
+                          0,
+                          MAXIMUM_ALLOWED,
+                          phProfile);
+    if (Error != ERROR_SUCCESS)
     {
-        DPRINT1("SERVICES: Could not create thread (Status %lx)\n", GetLastError());
-        return FALSE;
+        DPRINT1("RegOpenKeyExW() failed (Error %ld)\n", Error);
+        goto Quit;
     }
 
-    CloseHandle(hThread);
+    Success = TRUE;
 
-    return TRUE;
-}
+Quit:
+    LocalFree(pSid);
 
+    DPRINT1("ScmLogAccountsHack(%S) returned %s\n",
+            pszAccountName, Success ? "success" : "failure");
 
-BOOL WINAPI
-ShutdownHandlerRoutine(DWORD dwCtrlType)
+    return Success;
+}
+
+static struct
 {
-    DPRINT1("ShutdownHandlerRoutine() called\n");
+    LPCWSTR pszAccountName;
+    LPCWSTR pszSid;
+    HKEY    hProfile;
+} AccountHandles[] = {
+//  {L"LocalSystem"   , L"S-1-5-18", NULL},
+    {L"LocalService"  , L"S-1-5-19", NULL}, // L"NT AUTHORITY\\LocalService"
+    {L"NetworkService", L"S-1-5-20", NULL}, // L"NT AUTHORITY\\NetworkService"
+};
+
+static VOID
+ScmCleanupServiceAccountsHack(VOID)
+{
+    UINT i;
 
-    if (dwCtrlType & (CTRL_SHUTDOWN_EVENT | CTRL_LOGOFF_EVENT))
+    DPRINT1("ScmCleanupServiceAccountsHack()\n");
+
+    for (i = 0; i < ARRAYSIZE(AccountHandles); ++i)
     {
-        DPRINT1("Shutdown event received!\n");
-        ScmShutdown = TRUE;
+        if (AccountHandles[i].hProfile)
+        {
+            RegCloseKey(AccountHandles[i].hProfile);
+            AccountHandles[i].hProfile = NULL;
+        }
+    }
+}
 
-        ScmAutoShutdownServices();
-        ScmShutdownServiceDatabase();
+static BOOL
+ScmApplyServiceAccountsHack(VOID)
+{
+    UINT i;
 
-        /* Set the shutdwon event */
-        SetEvent(hScmShutdownEvent);
+    DPRINT1("ScmApplyServiceAccountsHack()\n");
+
+    for (i = 0; i < ARRAYSIZE(AccountHandles); ++i)
+    {
+        if (!ScmLogAccountHack( AccountHandles[i].pszAccountName,
+                                AccountHandles[i].pszSid,
+                               &AccountHandles[i].hProfile))
+        {
+            ScmCleanupServiceAccountsHack();
+            return FALSE;
+        }
     }
 
     return TRUE;
 }
 
+/*************************** END OF HACK CORE-12541 ***************************/
+
 
 int WINAPI
 wWinMain(HINSTANCE hInstance,
@@ -315,6 +309,9 @@ wWinMain(HINSTANCE hInstance,
 
     DPRINT("SERVICES: Service Control Manager\n");
 
+    /* Make us critical */
+    RtlSetProcessIsCritical(TRUE, NULL, TRUE);
+
     /* We are initializing ourselves */
     ScmInitialize = TRUE;
 
@@ -350,6 +347,8 @@ wWinMain(HINSTANCE hInstance,
 
 //    ScmInitThreadManager();
 
+    ScmInitializeSecurity();
+
     /* FIXME: more initialization */
 
     /* Read the control set values */
@@ -402,6 +401,15 @@ wWinMain(HINSTANCE hInstance,
     /* Register event handler (used for system shutdown) */
     SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE);
 
+    /*
+     * Set our shutdown parameters: we want to shutdown after the maintained
+     * services (that inherit the default shutdown level of 640).
+     */
+    SetProcessShutdownParameters(480, SHUTDOWN_NORETRY);
+
+    /*** HACK CORE-12541: Apply service accounts HACK ***/
+    ScmApplyServiceAccountsHack();
+
     /* Start auto-start services */
     ScmAutoStartServices();
 
@@ -421,9 +429,14 @@ wWinMain(HINSTANCE hInstance,
     /* Wait until the shutdown event gets signaled */
     WaitForSingleObject(hScmShutdownEvent, INFINITE);
 
+    /*** HACK CORE-12541: Cleanup service accounts HACK ***/
+    ScmCleanupServiceAccountsHack();
+
 done:
+    ScmShutdownSecurity();
+
     /* Delete our communication named pipe's critical section */
-    if (bCanDeleteNamedPipeCriticalSection == TRUE)
+    if (bCanDeleteNamedPipeCriticalSection != FALSE)
         ScmDeleteNamedPipeCriticalSection();
 
     /* Close the shutdown event */