VirtualBox

Changeset 29289 in vbox for trunk/src/VBox/Runtime/r3


Ignore:
Timestamp:
May 10, 2010 9:38:30 AM (15 years ago)
Author:
vboxsync
Message:

IPRT: Added RTPROC_FLAGS_SERVICE for code path handling when used with a (Windows) service, added first support for session 0 isolation on Windows Vista+.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/win/process-win.cpp

    r29004 r29289  
    7070typedef FNCREATEPROCESSWITHLOGON *PFNCREATEPROCESSWITHLOGON;
    7171
     72typedef DWORD WINAPI FNWTSGETACTIVECONSOLESESSIONID();
     73typedef FNWTSGETACTIVECONSOLESESSIONID *PFNWTSGETACTIVECONSOLESESSIONID;
     74
     75typedef BOOL WINAPI FNWTSQUERYUSERTOKEN(ULONG, PHANDLE);
     76typedef FNWTSQUERYUSERTOKEN *PFNWTSQUERYUSERTOKEN;
     77
    7278
    7379/*******************************************************************************
     
    237243static int rtProcCreateAsUserHlp(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,
    238244                                 PRTUTF16 pwszzBlock, DWORD dwCreationFlags,
    239                                  STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo)
    240 {
    241     /** @todo On NT4 we need to enable the SeTcbPrivilege to act as part of the operating system. Otherwise
    242       *       we will get error 1314 (priviledge not held) as a response. */
    243 
    244     /*
    245      * The following rights are needed in order to use LogonUserW and
    246      * CreateProcessAsUserW, so the local policy has to be modified to:
    247      *  - SE_TCB_NAME = Act as part of the operating system
    248      *  - SE_ASSIGNPRIMARYTOKEN_NAME = Create/replace a token object
    249      *  - SE_INCREASE_QUOTA_NAME
    250      *
    251      * We may fail here with ERROR_PRIVILEGE_NOT_HELD.
    252      */
    253     int    rc;
    254     DWORD  dwErr  = NO_ERROR;
     245                                 STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo, uint32_t fFlags)
     246{
    255247    HANDLE hToken = INVALID_HANDLE_VALUE;
    256     BOOL   fRc    = LogonUserW(pwszUser,
    257                                NULL,      /* lpDomain */
    258                                pwszPassword,
    259                                LOGON32_LOGON_INTERACTIVE,
    260                                LOGON32_PROVIDER_DEFAULT,
    261                                &hToken);
     248    BOOL fRc = FALSE;
     249#ifndef IPRT_TARGET_NT4
     250    /*
     251     * Get the session ID.
     252     */
     253    DWORD dwSessionID = 0; /* On W2K the session ID is always 0 (does not have fast user switching). */
     254    RTLDRMOD hKernel32;
     255    int rc = RTLdrLoad("Kernel32.dll", &hKernel32);
     256    if (RT_SUCCESS(rc))
     257    {
     258        PFNWTSGETACTIVECONSOLESESSIONID pfnWTSGetActiveConsoleSessionId;
     259        rc = RTLdrGetSymbol(hKernel32, "WTSGetActiveConsoleSessionId", (void **)&pfnWTSGetActiveConsoleSessionId);
     260        if (RT_SUCCESS(rc))
     261        {
     262            /*
     263             * Console session means the session which the physical keyboard and mouse
     264             * is connected to. Due to FUS (fast user switching) starting with Windows XP
     265             * this can be a different session than 0.
     266             */
     267            dwSessionID = pfnWTSGetActiveConsoleSessionId(); /* Get active console session ID. */
     268        }
     269        RTLdrClose(hKernel32);
     270    }
     271
     272    if (fFlags & RTPROC_FLAGS_SERVICE)
     273    {
     274        /*
     275         * Get the current user token.
     276         */
     277        RTLDRMOD hWtsAPI32;
     278        rc = RTLdrLoad("Wtsapi32.dll", &hWtsAPI32);
     279        if (RT_SUCCESS(rc))
     280        {
     281            /* Note that WTSQueryUserToken() only is available on Windows XP and up! */
     282            PFNWTSQUERYUSERTOKEN pfnWTSQueryUserToken;
     283            rc = RTLdrGetSymbol(hWtsAPI32, "WTSQueryUserToken", (void **)&pfnWTSQueryUserToken);
     284            if (RT_SUCCESS(rc))
     285                fRc = pfnWTSQueryUserToken(dwSessionID, &hToken);
     286            RTLdrClose(hWtsAPI32);
     287        }
     288    }
     289#endif /* !IPRT_TARGET_NT4 */
     290
     291    DWORD dwErr = NO_ERROR;
     292    /*
     293     * If not run by a service, use the normal LogonUserW function in order
     294     * to run the child process with different credentials using the returned
     295     * primary token.
     296     */
     297    if (!(fFlags & RTPROC_FLAGS_SERVICE))
     298    { 
     299        /*
     300         * The following rights are needed in order to use LogonUserW and
     301         * CreateProcessAsUserW, so the local policy has to be modified to:
     302         *  - SE_TCB_NAME = Act as part of the operating system
     303         *  - SE_ASSIGNPRIMARYTOKEN_NAME = Create/replace a token object
     304         *  - SE_INCREASE_QUOTA_NAME
     305         *
     306         * We may fail here with ERROR_PRIVILEGE_NOT_HELD.
     307         */
     308        fRc = LogonUserW(pwszUser,
     309                          NULL,      /* lpDomain */
     310                          pwszPassword,
     311                          LOGON32_LOGON_INTERACTIVE,
     312                          LOGON32_PROVIDER_DEFAULT,
     313                          &hToken);
     314    }
     315
    262316    if (fRc)
    263317    {
    264         fRc = CreateProcessAsUserW(hToken,
    265                                    pwszExec,
    266                                    pwszCmdLine,
    267                                    NULL,         /* pProcessAttributes */
    268                                    NULL,         /* pThreadAttributes */
    269                                    TRUE,         /* fInheritHandles */
    270                                    dwCreationFlags,
    271                                    pwszzBlock,
    272                                    NULL,         /* pCurrentDirectory */
    273                                    pStartupInfo,
    274                                    pProcInfo);
    275         if (!fRc)
    276             dwErr = GetLastError();
     318#ifndef IPRT_TARGET_NT4
     319        HANDLE hDuplicatedToken = INVALID_HANDLE_VALUE;
     320        HANDLE hProcessToken = INVALID_HANDLE_VALUE;
     321
     322        /*
     323         * If used by a service, open this service process and adjust
     324         * privileges by enabling the SE_TCB_NAME right to act as part
     325         * of the operating system.
     326         */
     327        if (fFlags & RTPROC_FLAGS_SERVICE)
     328        {           
     329            TOKEN_PRIVILEGES privToken, privTokenOld;
     330            DWORD dwTokenSize;
     331       
     332            fRc = OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken);
     333            if (   fRc
     334                && LookupPrivilegeValue(NULL, SE_TCB_NAME, &privToken.Privileges[0].Luid))
     335            {
     336                privToken.PrivilegeCount = 1;
     337                privToken.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
     338                fRc = AdjustTokenPrivileges(hProcessToken, FALSE, &privToken, sizeof(privToken), &privTokenOld, &dwTokenSize);
     339                if (!fRc)
     340                    dwErr = GetLastError();
     341            }
     342        }
     343   
     344        if (   dwErr == ERROR_SUCCESS
     345            || dwErr == ERROR_NOT_ALL_ASSIGNED) /* The AdjustTokenPrivileges() did not succeed, but this isn't fatal. */
     346        {           
     347            fRc = DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDuplicatedToken);
     348#if 0
     349            /*
     350             * Assign the current session ID (> 0 on Windows Vista and up) to the primary token we just duplicated.
     351             ** @todo This does not work yet, needs more investigation! */
     352             */
     353            if (fRc)
     354            {
     355                fRc = SetTokenInformation(hDuplicatedToken, TokenSessionId, &dwSessionID, sizeof(DWORD));
     356                if (!fRc)
     357                    dwErr = GetLastError();
     358            }
     359            else
     360                dwErr = GetLastError();
     361#endif
     362        }
     363
     364#endif /* !IPRT_TARGET_NT4 */
     365
     366        /** @todo On NT4 we need to enable the SeTcbPrivilege to act as part of the operating system. Otherwise
     367          *       we will get error 1314 (priviledge not held) as a response. */
     368
     369        /* Hopefully having a valid token now! */
     370        if (   fRc
     371#ifdef IPRT_TARGET_NT4
     372            && hToken           != INVALID_HANDLE_VALUE
     373#else
     374            && hDuplicatedToken != INVALID_HANDLE_VALUE
     375#endif /* IPRT_TARGET_NT4 */
     376            )
     377        {   
     378            fRc = CreateProcessAsUserW(
     379#ifdef IPRT_TARGET_NT4
     380                                       hToken,
     381#else
     382                                       hDuplicatedToken,
     383#endif /* !IPRT_TARGET_NT4 */
     384                                       pwszExec,
     385                                       pwszCmdLine,
     386                                       NULL,         /* pProcessAttributes */
     387                                       NULL,         /* pThreadAttributes */
     388                                       TRUE,         /* fInheritHandles */
     389                                       dwCreationFlags,
     390                                       pwszzBlock,
     391                                       NULL,         /* pCurrentDirectory */
     392                                       pStartupInfo,
     393                                       pProcInfo);
     394            if (!fRc)
     395                dwErr = GetLastError();
     396#ifndef IPRT_TARGET_NT4
     397            CloseHandle(hDuplicatedToken);
     398#endif /* !IPRT_TARGET_NT4 */
     399        }
    277400        CloseHandle(hToken);
     401#ifndef IPRT_TARGET_NT4
     402        if (fFlags & RTPROC_FLAGS_SERVICE)
     403        {
     404            /** @todo Drop SE_TCB_NAME priviledge before closing the process handle! */
     405            if (hProcessToken != INVALID_HANDLE_VALUE)
     406                CloseHandle(hProcessToken);
     407        }
     408#endif /* !IPRT_TARGET_NT4 */
    278409    }
    279410    else
     
    317448        }
    318449    }
    319 #endif
     450#endif /* !IPRT_TARGET_NT4 */
    320451
    321452    if (dwErr != NO_ERROR)
     
    335466    AssertPtrReturn(pszExec, VERR_INVALID_POINTER);
    336467    AssertReturn(*pszExec, VERR_INVALID_PARAMETER);
    337     AssertReturn(!(fFlags & ~(RTPROC_FLAGS_DAEMONIZE_DEPRECATED | RTPROC_FLAGS_DETACHED)), VERR_INVALID_PARAMETER);
     468    AssertReturn(!(fFlags & ~(RTPROC_FLAGS_DAEMONIZE_DEPRECATED | RTPROC_FLAGS_DETACHED | RTPROC_FLAGS_SERVICE)), VERR_INVALID_PARAMETER);
    338469    AssertReturn(!(fFlags & RTPROC_FLAGS_DETACHED) || !phProcess, VERR_INVALID_PARAMETER);
    339470    AssertReturn(hEnv != NIL_RTENV, VERR_INVALID_PARAMETER);
     
    487618                            rc = rtProcCreateAsUserHlp(pwszUser, pwszPassword,
    488619                                                       pwszExec, pwszCmdLine, pwszzBlock, dwCreationFlags,
    489                                                        &StartupInfo, &ProcInfo);
     620                                                       &StartupInfo, &ProcInfo, fFlags);
    490621
    491622                            RTUtf16Free(pwszPassword);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette