VirtualBox

Changeset 57843 in vbox for trunk


Ignore:
Timestamp:
Sep 21, 2015 4:14:20 PM (9 years ago)
Author:
vboxsync
Message:

RTProcCreateEx/win: Implemented RTPROC_FLAGS_PROFILE and RTPROC_FLAGS_ENV_CHANGE_RECORD when pszUser is NULL, fixed the RTPROC_FLAGS_SEARCH_PATH behavior for those flags.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/process.h

    r57835 r57843  
    200200/** Load user profile data when executing a process.
    201201 * This redefines the meaning of RTENV_DEFAULT to the profile environment.
    202  * This bit is at the moment only supported on Windows using the RTProcCreateEx
    203  * with a user specified. */
     202 * This bit is at the moment only supported on Windows. */
    204203#define RTPROC_FLAGS_PROFILE                RT_BIT(4)
    205204/** Create process without a console window.
  • trunk/src/VBox/Runtime/r3/win/process-win.cpp

    r57835 r57843  
    132132
    133133
     134/*********************************************************************************************************************************
     135*   Internal Functions                                                                                                           *
     136*********************************************************************************************************************************/
     137static int rtProcWinFindExe(uint32_t fFlags, RTENV hEnv, const char *pszExec, PRTUTF16 *ppwszExec);
    134138
    135139
     
    640644 * Logs on a specified user and returns its primary token.
    641645 *
    642  * @return  int
     646 * @returns IPRT status code.
    643647 * @param   pwszUser            User name.
    644648 * @param   pwszPassword        Password.
     
    750754
    751755
    752 
    753756/**
    754757 * Method \#2.
    755758 */
    756 static int rtProcWinCreateAsUser2(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,
     759static int rtProcWinCreateAsUser2(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 *ppwszExec, PRTUTF16 pwszCmdLine,
    757760                                  RTENV hEnv, DWORD dwCreationFlags,
    758                                   STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo, uint32_t fFlags)
     761                                  STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo,
     762                                  uint32_t fFlags, const char *pszExec)
    759763{
    760764    /*
     
    784788     * We may fail here with ERROR_PRIVILEGE_NOT_HELD.
    785789     */
     790/** @todo r=bird: Both methods starts with rtProcWinUserLogon, so we could probably do that once in the parent function, right... */
    786791    DWORD   dwErr       = NO_ERROR;
    787792    HANDLE  hTokenLogon = INVALID_HANDLE_VALUE;
     
    858863                if (fFlags & RTPROC_FLAGS_PROFILE)
    859864                {
    860 /* @todo r=bird: I'm not convinced that the unload function restores our original environment... */
    861865                    ProfileInfo.dwSize     = sizeof(ProfileInfo);
    862866                    ProfileInfo.lpUserName = pwszUser;
     
    879883                        if (RT_SUCCESS(rc))
    880884                        {
    881                             /*
    882                              * Useful KB articles:
    883                              *      http://support.microsoft.com/kb/165194/
    884                              *      http://support.microsoft.com/kb/184802/
    885                              *      http://support.microsoft.com/kb/327618/
    886                              */
    887                             fRc = CreateProcessAsUserW(hTokenToUse,
    888                                                        pwszExec,
    889                                                        pwszCmdLine,
    890                                                        NULL,         /* pProcessAttributes */
    891                                                        NULL,         /* pThreadAttributes */
    892                                                        TRUE,         /* fInheritHandles */
    893                                                        dwCreationFlags,
    894                                                        /** @todo Warn about exceeding 8192 bytes
    895                                                         *        on XP and up. */
    896                                                        pwszzBlock,   /* lpEnvironment */
    897                                                        NULL,         /* pCurrentDirectory */
    898                                                        pStartupInfo,
    899                                                        pProcInfo);
    900                             if (fRc)
    901                                 dwErr = NO_ERROR;
    902                             else
    903                                 dwErr = GetLastError(); /* CreateProcessAsUserW() failed. */
     885                            rc = rtProcWinFindExe(fFlags, hEnv, pszExec, ppwszExec);
     886                            if (RT_SUCCESS(rc))
     887                            {
     888                                /*
     889                                 * Useful KB articles:
     890                                 *      http://support.microsoft.com/kb/165194/
     891                                 *      http://support.microsoft.com/kb/184802/
     892                                 *      http://support.microsoft.com/kb/327618/
     893                                 */
     894                                fRc = CreateProcessAsUserW(hTokenToUse,
     895                                                           *ppwszExec,
     896                                                           pwszCmdLine,
     897                                                           NULL,         /* pProcessAttributes */
     898                                                           NULL,         /* pThreadAttributes */
     899                                                           TRUE,         /* fInheritHandles */
     900                                                           dwCreationFlags,
     901                                                           /** @todo Warn about exceeding 8192 bytes
     902                                                            *        on XP and up. */
     903                                                           pwszzBlock,   /* lpEnvironment */
     904                                                           NULL,         /* pCurrentDirectory */
     905                                                           pStartupInfo,
     906                                                           pProcInfo);
     907                                if (fRc)
     908                                    dwErr = NO_ERROR;
     909                                else
     910                                    dwErr = GetLastError(); /* CreateProcessAsUserW() failed. */
     911                            }
    904912                            RTEnvFreeUtf16Block(pwszzBlock);
    905913                        }
     
    953961 * platforms (however, this works on W2K!).
    954962 */
    955 static int rtProcWinCreateAsUser1(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,
     963static int rtProcWinCreateAsUser1(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 *ppwszExec, PRTUTF16 pwszCmdLine,
    956964                                  RTENV hEnv, DWORD dwCreationFlags,
    957                                   STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo, uint32_t fFlags)
     965                                  STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo,
     966                                  uint32_t fFlags, const char *pszExec)
    958967{
    959968    if (!g_pfnCreateProcessWithLogonW)
    960969        return VERR_SYMBOL_NOT_FOUND;
    961970
    962     RTENV  hEnvToUse;
     971    RTENV  hEnvToUse = NIL_RTENV;
    963972    HANDLE hToken;
    964973    int rc = rtProcWinUserLogon(pwszUser, pwszPassword, NULL /* Domain */, &hToken);
    965974    if (RT_SUCCESS(rc))
    966975    {
    967         rc = rtProcWinCreateEnvFromToken(hToken, hEnv, fFlags, &hEnvToUse);
     976/** @todo r=bird: Why didn't we load the environment here?  The
     977 *       CreateEnvironmentBlock docs indicate that USERPROFILE isn't set
     978 *       unless we call LoadUserProfile first.  However, experiments here on W10
     979 *       shows it isn't really needed though. Weird. */
     980#if 0
     981        if (fFlags & RTPROC_FLAGS_PROFILE)
     982        {
     983            PROFILEINFOW ProfileInfo;
     984            RT_ZERO(ProfileInfo);
     985            ProfileInfo.dwSize     = sizeof(ProfileInfo);
     986            ProfileInfo.lpUserName = pwszUser;
     987            ProfileInfo.dwFlags    = PI_NOUI; /* Prevents the display of profile error messages. */
     988
     989            if (g_pfnLoadUserProfileW(hToken, &ProfileInfo))
     990            {
     991                rc = rtProcWinCreateEnvFromToken(hToken, hEnv, fFlags, &hEnvToUse);
     992
     993                if (!g_pfnUnloadUserProfile(hToken, ProfileInfo.hProfile))
     994                    AssertFailed();
     995            }
     996            else
     997                rc = RTErrConvertFromWin32(GetLastError());
     998        }
     999        else
     1000#endif
     1001            rc = rtProcWinCreateEnvFromToken(hToken, hEnv, fFlags, &hEnvToUse);
    9681002        CloseHandle(hToken);
    9691003    }
     
    9741008        if (RT_SUCCESS(rc))
    9751009        {
    976             BOOL fRc = g_pfnCreateProcessWithLogonW(pwszUser,
    977                                                     NULL,                       /* lpDomain*/
    978                                                     pwszPassword,
    979                                                     1 /*LOGON_WITH_PROFILE*/,   /* dwLogonFlags */
    980                                                     pwszExec,
    981                                                     pwszCmdLine,
    982                                                     dwCreationFlags,
    983                                                     pwszzBlock,
    984                                                     NULL,                       /* pCurrentDirectory */
    985                                                     pStartupInfo,
    986                                                     pProcInfo);
    987             if (fRc)
    988                 rc = VINF_SUCCESS;
    989             else
     1010            rc = rtProcWinFindExe(fFlags, hEnv, pszExec, ppwszExec);
     1011            if (RT_SUCCESS(rc))
    9901012            {
    991                 DWORD dwErr = GetLastError();
    992                 rc = rtProcWinMapErrorCodes(dwErr);
    993                 if (rc == VERR_UNRESOLVED_ERROR)
    994                     LogRelFunc(("g_pfnCreateProcessWithLogonW (%p) failed: dwErr=%u (%#x), rc=%Rrc\n",
    995                                 g_pfnCreateProcessWithLogonW, dwErr, dwErr, rc));
     1013                BOOL fRc = g_pfnCreateProcessWithLogonW(pwszUser,
     1014                                                        NULL,                       /* lpDomain*/
     1015                                                        pwszPassword,
     1016/** @todo r=bird: Not respecting the RTPROF_FLAGS_PROFILE flag here.  */
     1017                                                        1 /*LOGON_WITH_PROFILE*/,   /* dwLogonFlags */
     1018                                                        *ppwszExec,
     1019                                                        pwszCmdLine,
     1020                                                        dwCreationFlags,
     1021                                                        pwszzBlock,
     1022                                                        NULL,                       /* pCurrentDirectory */
     1023                                                        pStartupInfo,
     1024                                                        pProcInfo);
     1025                if (fRc)
     1026                    rc = VINF_SUCCESS;
     1027                else
     1028                {
     1029                    DWORD dwErr = GetLastError();
     1030                    rc = rtProcWinMapErrorCodes(dwErr);
     1031                    if (rc == VERR_UNRESOLVED_ERROR)
     1032                        LogRelFunc(("g_pfnCreateProcessWithLogonW (%p) failed: dwErr=%u (%#x), rc=%Rrc\n",
     1033                                    g_pfnCreateProcessWithLogonW, dwErr, dwErr, rc));
     1034                }
    9961035            }
    9971036            RTEnvFreeUtf16Block(pwszzBlock);
     
    10041043
    10051044
    1006 static int rtProcWinCreateAsUser(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,
     1045static int rtProcWinCreateAsUser(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 *ppwszExec, PRTUTF16 pwszCmdLine,
    10071046                                 RTENV hEnv, DWORD dwCreationFlags,
    1008                                  STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo, uint32_t fFlags)
     1047                                 STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo,
     1048                                 uint32_t fFlags, const char *pszExec)
    10091049{
    10101050    /*
     
    10151055    if (!(fFlags & RTPROC_FLAGS_SERVICE))
    10161056    {
    1017         int rc = rtProcWinCreateAsUser1(pwszUser, pwszPassword, pwszExec, pwszCmdLine,
    1018                                         hEnv, dwCreationFlags, pStartupInfo, pProcInfo, fFlags);
     1057        int rc = rtProcWinCreateAsUser1(pwszUser, pwszPassword, ppwszExec, pwszCmdLine,
     1058                                        hEnv, dwCreationFlags, pStartupInfo, pProcInfo, fFlags, pszExec);
    10191059        if (RT_SUCCESS(rc))
    10201060            return rc;
    10211061    }
    1022     return rtProcWinCreateAsUser2(pwszUser, pwszPassword, pwszExec, pwszCmdLine,
    1023                                   hEnv, dwCreationFlags, pStartupInfo, pProcInfo, fFlags);
     1062    return rtProcWinCreateAsUser2(pwszUser, pwszPassword, ppwszExec, pwszCmdLine,
     1063                                  hEnv, dwCreationFlags, pStartupInfo, pProcInfo, fFlags, pszExec);
    10241064}
    10251065
    10261066
    10271067/**
    1028  * RTPathTraverseList callback used by RTProcCreateEx to locate the executable.
     1068 * RTPathTraverseList callback used by rtProcWinFindExe to locate the
     1069 * executable.
    10291070 */
    10301071static DECLCALLBACK(int) rtPathFindExec(char const *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)
     
    10411082
    10421083
     1084/**
     1085 * Locate the executable file if necessary.
     1086 *
     1087 * @returns IPRT status code.
     1088 * @param   pszExec         The UTF-8 executable string passed in by the user.
     1089 * @param   fFlags          The process creation flags pass in by the user.
     1090 * @param   hEnv            The environment to get the path variabel from.
     1091 * @param   ppwszExec       Pointer to the variable pointing to the UTF-16
     1092 *                          converted string.  If we find something, the current
     1093 *                          pointer will be free (RTUtf16Free) and
     1094 *                          replaced by a new one.
     1095 */
     1096static int rtProcWinFindExe(uint32_t fFlags, RTENV hEnv, const char *pszExec, PRTUTF16 *ppwszExec)
     1097{
     1098    /*
     1099     * Return immediately if we're not asked to search, or if the file has a
     1100     * path already or if it actually exists in the current directory.
     1101     */
     1102    if (   !(fFlags & RTPROC_FLAGS_SEARCH_PATH)
     1103        || RTPathHavePath(pszExec)
     1104        || RTPathExists(pszExec) )
     1105        return VINF_SUCCESS;
     1106
     1107    /*
     1108     * Search the Path or PATH variable for the file.
     1109     */
     1110    char *pszPath;
     1111    if (RTEnvExistEx(hEnv, "PATH"))
     1112        pszPath = RTEnvDupEx(hEnv, "PATH");
     1113    else if (RTEnvExistEx(hEnv, "Path"))
     1114        pszPath = RTEnvDupEx(hEnv, "Path");
     1115    else
     1116        return VERR_FILE_NOT_FOUND;
     1117
     1118    char szRealExec[RTPATH_MAX];
     1119    int rc = RTPathTraverseList(pszPath, ';', rtPathFindExec, (void *)pszExec, &szRealExec[0]);
     1120    RTStrFree(pszPath);
     1121    if (RT_SUCCESS(rc))
     1122    {
     1123        /*
     1124         * Replace the executable string.
     1125         */
     1126        RTUtf16Free(*ppwszExec);
     1127        *ppwszExec = NULL;
     1128        rc = RTStrToUtf16(szRealExec, ppwszExec);
     1129    }
     1130    else if (rc == VERR_END_OF_STRING)
     1131        rc = VERR_FILE_NOT_FOUND;
     1132    return rc;
     1133}
     1134
     1135
     1136/**
     1137 * Creates the UTF-16 environment block and, if necessary, find the executable.
     1138 *
     1139 * @returns IPRT status code.
     1140 * @param   fFlags          The process creation flags pass in by the user.
     1141 * @param   hEnv            The environment handle passed by the user.
     1142 * @param   pszExec         See rtProcWinFindExe.
     1143 * @param   ppwszzBlock     Where RTEnvQueryUtf16Block returns the block.
     1144 * @param   ppwszExec       See rtProcWinFindExe.
     1145 */
     1146static int rtProcWinCreateEnvBlockAndFindExe(uint32_t fFlags, RTENV hEnv, const char *pszExec,
     1147                                             PRTUTF16 *ppwszzBlock, PRTUTF16 *ppwszExec)
     1148{
     1149    int rc;
     1150
     1151    /*
     1152     * In most cases, we just need to convert the incoming enviornment to a
     1153     * UTF-16 environment block.
     1154     */
     1155    RTENV hEnvToUse;
     1156    if (   !(fFlags & (RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_ENV_CHANGE_RECORD))
     1157        || (hEnv == RTENV_DEFAULT && !(fFlags & RTPROC_FLAGS_PROFILE))
     1158        || (hEnv != RTENV_DEFAULT && !(fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD)) )
     1159        hEnvToUse = hEnv;
     1160    else if (fFlags & RTPROC_FLAGS_PROFILE)
     1161    {
     1162        /*
     1163         * We need to get the profile environment for the current user.
     1164         */
     1165        Assert((fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD) || hEnv == RTENV_DEFAULT);
     1166        AssertReturn(g_pfnCreateEnvironmentBlock && g_pfnDestroyEnvironmentBlock, VERR_SYMBOL_NOT_FOUND);
     1167        AssertReturn(g_pfnLoadUserProfileW && g_pfnUnloadUserProfile, VERR_SYMBOL_NOT_FOUND);
     1168        HANDLE hToken;
     1169        if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE, &hToken))
     1170        {
     1171            rc = rtProcWinCreateEnvFromToken(hToken, hEnv, fFlags, &hEnvToUse);
     1172            CloseHandle(hToken);
     1173        }
     1174        else
     1175            rc = RTErrConvertFromWin32(GetLastError());
     1176    }
     1177    else
     1178    {
     1179        /*
     1180         * Apply hEnv as a change record on top of the default environment.
     1181         */
     1182        Assert(fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD);
     1183        rc = RTEnvClone(&hEnvToUse, RTENV_DEFAULT);
     1184        if (RT_SUCCESS(rc))
     1185        {
     1186            rc = RTEnvApplyChanges(hEnvToUse, hEnv);
     1187            if (RT_FAILURE(rc))
     1188                RTEnvDestroy(hEnvToUse);
     1189        }
     1190    }
     1191    if (RT_SUCCESS(rc))
     1192    {
     1193        /*
     1194         * Query the UTF-16 environment block and locate the executable (if needed).
     1195         */
     1196        rc = RTEnvQueryUtf16Block(hEnvToUse, ppwszzBlock);
     1197        if (RT_SUCCESS(rc))
     1198            rc = rtProcWinFindExe(fFlags, hEnvToUse, pszExec, ppwszExec);
     1199
     1200        if (hEnvToUse != hEnv)
     1201            RTEnvDestroy(hEnvToUse);
     1202    }
     1203
     1204    return rc;
     1205}
     1206
     1207
    10431208RTR3DECL(int)   RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
    10441209                               PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
     
    10531218    AssertReturn(!(fFlags & RTPROC_FLAGS_DETACHED) || !phProcess, VERR_INVALID_PARAMETER);
    10541219    AssertReturn(hEnv != NIL_RTENV, VERR_INVALID_PARAMETER);
    1055     AssertReturn(   !(fFlags & RTPROC_FLAGS_PROFILE) /* Profile flag isn't fully implemented in all cases: */
    1056                  || pszAsUser
    1057                  || (hEnv != RTENV_DEFAULT && !(fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD)), VERR_NOT_SUPPORTED);
    10581220    AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER);
    10591221    AssertPtrNullReturn(pszAsUser, VERR_INVALID_POINTER);
     
    10711233        rc = RTOnce(&g_rtProcWinResolveOnce, rtProcWinResolveOnce, NULL);
    10721234        AssertRCReturn(rc, rc);
    1073     }
    1074 
    1075     /*
    1076      * Resolve the executable name via the PATH if requested.
    1077      */
    1078     char szRealExec[RTPATH_MAX];
    1079     if (   (fFlags & RTPROC_FLAGS_SEARCH_PATH)
    1080         && !RTPathHavePath(pszExec)
    1081         && !RTPathExists(pszExec) )
    1082     {
    1083         /* search */
    1084 /** @todo RTPROC_FLAGS_PROFILE/win: Could be searching the wrong PATH/Path env var for executable. */
    1085         char *pszPath;
    1086         if (RTEnvExistEx(hEnv, "PATH"))
    1087             pszPath = RTEnvDupEx(hEnv, "PATH");
    1088         else if (RTEnvExistEx(hEnv, "Path"))
    1089             pszPath = RTEnvDupEx(hEnv, "Path");
    1090         else if (   !(fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD)
    1091                  || hEnv == RTENV_DEFAULT)
    1092             return VERR_FILE_NOT_FOUND;
    1093         else if (RTEnvExistEx(RTENV_DEFAULT, "PATH"))
    1094             pszPath = RTEnvDupEx(RTENV_DEFAULT, "PATH");
    1095         else if (RTEnvExistEx(RTENV_DEFAULT, "Path"))
    1096             pszPath = RTEnvDupEx(RTENV_DEFAULT, "Path");
    1097         else
    1098             return VERR_FILE_NOT_FOUND;
    1099         rc = RTPathTraverseList(pszPath, ';', rtPathFindExec, (void *)pszExec, &szRealExec[0]);
    1100         RTStrFree(pszPath);
    1101         if (RT_FAILURE(rc))
    1102             return rc == VERR_END_OF_STRING ? VERR_FILE_NOT_FOUND : rc;
    1103         pszExec = szRealExec;
    11041235    }
    11051236
     
    11911322
    11921323    /*
    1193      * Create the environment block, command line and convert the executable
    1194      * name.
    1195      */
    1196 /** @todo this environment creation isn't needed for the rtProcWinCreateAsUser case...  Also, we need to take the _PROFILE and _CHANGE_RECORD flags into account here */
    1197     PRTUTF16 pwszzBlock;
     1324     * Create the command line and convert the executable name.
     1325     */
     1326    PRTUTF16 pwszCmdLine;
    11981327    if (RT_SUCCESS(rc))
    1199         rc = RTEnvQueryUtf16Block(hEnv, &pwszzBlock);
    1200     if (RT_SUCCESS(rc))
    1201     {
    1202         PRTUTF16 pwszCmdLine;
    12031328        rc = RTGetOptArgvToUtf16String(&pwszCmdLine, papszArgs,
    12041329                                       !(fFlags & RTPROC_FLAGS_UNQUOTED_ARGS)
    12051330                                       ? RTGETOPTARGV_CNV_QUOTE_MS_CRT : RTGETOPTARGV_CNV_UNQUOTED);
     1331    if (RT_SUCCESS(rc))
     1332    {
     1333        PRTUTF16 pwszExec;
     1334        rc = RTStrToUtf16(pszExec, &pwszExec);
    12061335        if (RT_SUCCESS(rc))
    12071336        {
    1208             PRTUTF16 pwszExec;
    1209             rc = RTStrToUtf16(pszExec, &pwszExec);
    1210             if (RT_SUCCESS(rc))
     1337            /*
     1338             * Get going...
     1339             */
     1340            PROCESS_INFORMATION ProcInfo;
     1341            RT_ZERO(ProcInfo);
     1342            DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
     1343            if (fFlags & RTPROC_FLAGS_DETACHED)
     1344                dwCreationFlags |= DETACHED_PROCESS;
     1345            if (fFlags & RTPROC_FLAGS_NO_WINDOW)
     1346                dwCreationFlags |= CREATE_NO_WINDOW;
     1347
     1348            /*
     1349             * Only use the normal CreateProcess stuff if we have no user name
     1350             * and we are not running from a (Windows) service. Otherwise use
     1351             * the more advanced version in rtProcWinCreateAsUser().
     1352             */
     1353            if (   pszAsUser == NULL
     1354                && !(fFlags & RTPROC_FLAGS_SERVICE))
    12111355            {
    1212                 /*
    1213                  * Get going...
    1214                  */
    1215                 PROCESS_INFORMATION ProcInfo;
    1216                 RT_ZERO(ProcInfo);
    1217                 DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
    1218                 if (fFlags & RTPROC_FLAGS_DETACHED)
    1219                     dwCreationFlags |= DETACHED_PROCESS;
    1220                 if (fFlags & RTPROC_FLAGS_NO_WINDOW)
    1221                     dwCreationFlags |= CREATE_NO_WINDOW;
    1222 
    1223                 /*
    1224                  * Only use the normal CreateProcess stuff if we have no user name
    1225                  * and we are not running from a (Windows) service. Otherwise use
    1226                  * the more advanced version in rtProcWinCreateAsUser().
    1227                  */
    1228                 if (   pszAsUser == NULL
    1229                     && !(fFlags & RTPROC_FLAGS_SERVICE))
     1356                /* Create the environment block first. */
     1357                PRTUTF16 pwszzBlock;
     1358                rc = rtProcWinCreateEnvBlockAndFindExe(fFlags, hEnv, pszExec, &pwszzBlock, &pwszExec);
     1359                if (RT_SUCCESS(rc))
    12301360                {
    12311361                    if (CreateProcessW(pwszExec,
     
    12421372                    else
    12431373                        rc = RTErrConvertFromWin32(GetLastError());
     1374                    RTEnvFreeUtf16Block(pwszzBlock);
     1375                }
     1376            }
     1377            else
     1378            {
     1379                /*
     1380                 * Convert the additional parameters and use a helper
     1381                 * function to do the actual work.
     1382                 */
     1383                PRTUTF16 pwszUser;
     1384                rc = RTStrToUtf16(pszAsUser, &pwszUser);
     1385                if (RT_SUCCESS(rc))
     1386                {
     1387                    PRTUTF16 pwszPassword;
     1388                    rc = RTStrToUtf16(pszPassword ? pszPassword : "", &pwszPassword);
     1389                    if (RT_SUCCESS(rc))
     1390                    {
     1391                        rc = rtProcWinCreateAsUser(pwszUser, pwszPassword,
     1392                                                   &pwszExec, pwszCmdLine, hEnv, dwCreationFlags,
     1393                                                   &StartupInfo, &ProcInfo, fFlags, pszExec);
     1394
     1395                        if (pwszPassword && *pwszPassword)
     1396                            RTMemWipeThoroughly(pwszPassword, RTUtf16Len(pwszPassword), 5);
     1397                        RTUtf16Free(pwszPassword);
     1398                    }
     1399                    RTUtf16Free(pwszUser);
     1400                }
     1401            }
     1402            if (RT_SUCCESS(rc))
     1403            {
     1404                CloseHandle(ProcInfo.hThread);
     1405                if (phProcess)
     1406                {
     1407                    /*
     1408                     * Add the process to the child process list so
     1409                     * RTProcWait can reuse and close the process handle.
     1410                     */
     1411                    rtProcWinAddPid(ProcInfo.dwProcessId, ProcInfo.hProcess);
     1412                    *phProcess = ProcInfo.dwProcessId;
    12441413                }
    12451414                else
    1246                 {
    1247                     /*
    1248                      * Convert the additional parameters and use a helper
    1249                      * function to do the actual work.
    1250                      */
    1251                     PRTUTF16 pwszUser;
    1252                     rc = RTStrToUtf16(pszAsUser, &pwszUser);
    1253                     if (RT_SUCCESS(rc))
    1254                     {
    1255                         PRTUTF16 pwszPassword;
    1256                         rc = RTStrToUtf16(pszPassword ? pszPassword : "", &pwszPassword);
    1257                         if (RT_SUCCESS(rc))
    1258                         {
    1259                             rc = rtProcWinCreateAsUser(pwszUser, pwszPassword,
    1260                                                        pwszExec, pwszCmdLine, hEnv, dwCreationFlags,
    1261                                                        &StartupInfo, &ProcInfo, fFlags);
    1262 
    1263                             if (pwszPassword && *pwszPassword)
    1264                                 RTMemWipeThoroughly(pwszPassword, RTUtf16Len(pwszPassword), 5);
    1265                             RTUtf16Free(pwszPassword);
    1266                         }
    1267                         RTUtf16Free(pwszUser);
    1268                     }
    1269                 }
    1270                 if (RT_SUCCESS(rc))
    1271                 {
    1272                     CloseHandle(ProcInfo.hThread);
    1273                     if (phProcess)
    1274                     {
    1275                         /*
    1276                          * Add the process to the child process list so
    1277                          * RTProcWait can reuse and close the process handle.
    1278                          */
    1279                         rtProcWinAddPid(ProcInfo.dwProcessId, ProcInfo.hProcess);
    1280                         *phProcess = ProcInfo.dwProcessId;
    1281                     }
    1282                     else
    1283                         CloseHandle(ProcInfo.hProcess);
    1284                     rc = VINF_SUCCESS;
    1285                 }
    1286                 RTUtf16Free(pwszExec);
     1415                    CloseHandle(ProcInfo.hProcess);
     1416                rc = VINF_SUCCESS;
    12871417            }
    1288             RTUtf16Free(pwszCmdLine);
    1289         }
    1290         RTEnvFreeUtf16Block(pwszzBlock);
     1418            RTUtf16Free(pwszExec);
     1419        }
     1420        RTUtf16Free(pwszCmdLine);
    12911421    }
    12921422
  • trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp

    r57358 r57843  
    5454*   Global Variables                                                                                                             *
    5555*********************************************************************************************************************************/
    56 static char g_szExecName[RTPATH_MAX];
     56static RTENV g_hEnvInitial = NIL_RTENV;
     57static char  g_szExecName[RTPATH_MAX];
    5758
    5859
     
    8283
    8384
     85static int tstRTCreateProcEx6Child(int argc, char **argv)
     86{
     87    int rc = RTR3InitExeNoArguments(0);
     88    if (RT_FAILURE(rc))
     89        return RTMsgInitFailure(rc);
     90
     91    int cErrors = 0;
     92    char szValue[_1K];
     93
     94    /*
     95     * Check for the environment variable we've set in the parent process.
     96     */
     97    if (argc >= 3 && strcmp(argv[2], "inherit") == 0)
     98    {
     99        if (!RTEnvExistEx(RTENV_DEFAULT, "testcase-child-6"))
     100        {
     101            RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6' was not inherited from parent\n");
     102            cErrors++;
     103        }
     104    }
     105    else if (argc >= 3 && strstr(argv[2], "change-record") != NULL)
     106    {
     107        rc = RTEnvGetEx(RTENV_DEFAULT, "testcase-child-6", szValue, sizeof(szValue), NULL);
     108        if (RT_SUCCESS(rc) && strcmp(szValue, "changed"))
     109        {
     110            RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6'='%s', expected 'changed'.\n", szValue);
     111            cErrors++;
     112        }
     113        else if (RT_FAILURE(rc))
     114        {
     115            RTStrmPrintf(g_pStdErr, "child6: RTEnvGetEx(,'testcase-child-6',,) -> %Rrc\n", rc);
     116            cErrors++;
     117        }
     118    }
     119    else
     120    {
     121        if (RTEnvExistEx(RTENV_DEFAULT, "testcase-child-6"))
     122        {
     123            RTStrmPrintf(g_pStdErr, "child6: Env.var. 'testcase-child-6' was inherited from parent\n");
     124            cErrors++;
     125        }
     126    }
     127
     128    /*
     129     * Check the user name if present we didn't inherit from parent.
     130     */
     131    if (   argc >= 4
     132        && argv[3][0] != '\0'
     133        && strstr(argv[2], "noinherit") != NULL)
     134    {
     135        static struct
     136        {
     137            const char *pszVarNm;
     138            bool fReq;
     139        } const s_aVars[] =
     140        {
     141#ifdef RT_OS_WINDOWS
     142            { "USERNAME", true },
     143#else
     144            { "LOGNAME",  true },
     145            { "USER",    false },
     146#endif
     147        };
     148        for (unsigned i = 0; i < RT_ELEMENTS(s_aVars); i++)
     149        {
     150            rc = RTEnvGetEx(RTENV_DEFAULT, s_aVars[i].pszVarNm, szValue, sizeof(szValue), NULL);
     151            if (RT_SUCCESS(rc))
     152            {
     153                if (strcmp(szValue, argv[3]))
     154                {
     155                    RTStrmPrintf(g_pStdErr, "child6: env.var. '%s'='%s', expected '%s'\n",
     156                                 s_aVars[i].pszVarNm, szValue, argv[3]);
     157                    cErrors++;
     158                }
     159            }
     160            else if (rc != VERR_ENV_VAR_NOT_FOUND || s_aVars[i].fReq)
     161            {
     162                RTStrmPrintf(g_pStdErr, "child6: RTGetEnv('%s') -> %Rrc\n", s_aVars[i].pszVarNm, rc);
     163                cErrors++;
     164            }
     165        }
     166    }
     167
     168#if 0
     169    /* For manual testing. */
     170    if (strcmp(argv[2],"noinherit-change-record") == 0)
     171    {
     172        RTENV hEnv;
     173        rc = RTEnvClone(&hEnv, RTENV_DEFAULT);
     174        if (RT_SUCCESS(rc))
     175        {
     176            uint32_t cVars = RTEnvCountEx(hEnv);
     177            for (uint32_t i = 0; i < cVars; i++)
     178            {
     179                char szVarNm[_1K];
     180                char szValue[_16K];
     181                rc = RTEnvGetByIndexEx(hEnv, i, szVarNm, sizeof(szVarNm), szValue, sizeof(szValue));
     182                if (RT_SUCCESS(rc))
     183                    RTStrmPrintf(g_pStdErr, "child6: #%u: %s=%s\n", i, szVarNm, szValue);
     184                else
     185                {
     186                    RTStrmPrintf(g_pStdErr, "child6: #%u: %Rrc\n", rc);
     187                    cErrors++;
     188                }
     189            }
     190            RTEnvDestroy(hEnv);
     191        }
     192        else
     193        {
     194            RTStrmPrintf(g_pStdErr, "child6: RTEnvClone failed: %Rrc\n", rc);
     195            cErrors++;
     196        }
     197    }
     198#endif
     199
     200    return cErrors == 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     201}
     202
     203static void tstRTCreateProcEx6(const char *pszAsUser, const char *pszPassword)
     204{
     205    RTTestISub("Profile environment");
     206
     207    const char *apszArgs[5] =
     208    {
     209        g_szExecName,
     210        "--testcase-child-6",
     211        "inherit",
     212        pszAsUser,
     213        NULL
     214    };
     215
     216    RTTESTI_CHECK_RC_RETV(RTEnvSetEx(RTENV_DEFAULT, "testcase-child-6", "true"), VINF_SUCCESS);
     217
     218    /* Use the process environment first. */
     219    RTPROCESS hProc;
     220    RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/,
     221                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
     222    RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
     223    RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
     224
     225    if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
     226        RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
     227
     228    /* Use the process environment first with a little change. */
     229    apszArgs[2] = "change-record";
     230    RTENV hEnvChange;
     231    RTTESTI_CHECK_RC_RETV(RTEnvCreateChangeRecord(&hEnvChange), VINF_SUCCESS);
     232    RTTESTI_CHECK_RC_RETV(RTEnvSetEx(hEnvChange, "testcase-child-6", "changed"), VINF_SUCCESS);
     233    RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, hEnvChange, RTPROC_FLAGS_ENV_CHANGE_RECORD,
     234                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
     235    ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
     236    ProcStatus.iStatus   = -1;
     237    RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
     238
     239    if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
     240        RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
     241
     242
     243    /* Use profile environment this time. */
     244    apszArgs[2] = "noinherit";
     245    RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, RTPROC_FLAGS_PROFILE,
     246                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
     247    ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
     248    ProcStatus.iStatus   = -1;
     249    RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
     250
     251    if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
     252        RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
     253
     254    /* Use profile environment this time. */
     255    apszArgs[2] = "noinherit-change-record";
     256    RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, hEnvChange,
     257                                         RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_ENV_CHANGE_RECORD,
     258                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
     259    ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
     260    ProcStatus.iStatus   = -1;
     261    RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
     262
     263    if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
     264        RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
     265
     266
     267    RTTESTI_CHECK_RC(RTEnvDestroy(hEnvChange), VINF_SUCCESS);
     268
     269    /*
     270     * Restore the environment and check that the PROFILE flag didn't mess with
     271     * the process environment.  (Note! The bug may be elsewhere as well.)
     272     */
     273    RTTESTI_CHECK_RC(RTEnvUnsetEx(RTENV_DEFAULT, "testcase-child-6"), VINF_SUCCESS);
     274
     275    RTENV hEnvCur;
     276    RTTESTI_CHECK_RC_RETV(RTEnvClone(&hEnvCur, RTENV_DEFAULT), VINF_SUCCESS);
     277    uint32_t cCurrent = RTEnvCountEx(hEnvCur);
     278    uint32_t cInitial = RTEnvCountEx(g_hEnvInitial);
     279    RTTESTI_CHECK_MSG(cInitial == cInitial, ("cCurrent=%u cInitial=%u\n", cCurrent, cInitial));
     280    uint32_t    cVars1;
     281    RTENV       hEnv1,    hEnv2;
     282    const char *pszEnv1, *pszEnv2;
     283    if (cCurrent >= cInitial)
     284    {
     285        hEnv1   = hEnvCur;
     286        pszEnv1 = "current";
     287        cVars1  = cCurrent;
     288        hEnv2   = g_hEnvInitial;
     289        pszEnv2 = "initial";
     290    }
     291    else
     292    {
     293        hEnv2   = hEnvCur;
     294        pszEnv2 = "current";
     295        hEnv1   = g_hEnvInitial;
     296        pszEnv1 = "initial";
     297        cVars1  = cInitial;
     298    }
     299    for (uint32_t i = 0; i < cVars1; i++)
     300    {
     301        char szValue1[_16K];
     302        char szVarNm[_1K];
     303        int rc = RTEnvGetByIndexEx(hEnv1, i, szVarNm, sizeof(szVarNm), szValue1, sizeof(szValue1));
     304        if (RT_SUCCESS(rc))
     305        {
     306            char szValue2[_16K];
     307            rc = RTEnvGetEx(hEnv2, szVarNm, szValue2, sizeof(szValue2), NULL);
     308            if (RT_SUCCESS(rc))
     309            {
     310                if (strcmp(szValue1, szValue2) != 0)
     311                {
     312                    RTTestIFailed("Variable '%s' differs", szVarNm);
     313                    RTTestIFailureDetails("%s: '%s'\n"
     314                                          "%s: '%s'\n",
     315                                          pszEnv1, szValue1,
     316                                          pszEnv2, szValue2);
     317                }
     318            }
     319            else
     320                RTTestIFailed("RTEnvGetEx(%s,%s,,) failed: %Rrc", pszEnv2, szVarNm, rc);
     321
     322        }
     323        else
     324            RTTestIFailed("RTEnvGetByIndexEx(%s,%u,,,,) failed: %Rrc", pszEnv1, i, rc);
     325    }
     326}
     327
     328
    84329static int tstRTCreateProcEx5Child(int argc, char **argv)
    85330{
     
    410655int main(int argc, char **argv)
    411656{
     657    /*
     658     * Deal with child processes first.
     659     */
    412660    if (argc == 2 && !strcmp(argv[1], "--testcase-child-1"))
    413661        return tstRTCreateProcEx1Child();
     
    420668    if (argc == 2 && !strcmp(argv[1], "--testcase-child-5"))
    421669        return tstRTCreateProcEx5Child(argc, argv);
     670    if (argc >= 2 && !strcmp(argv[1], "--testcase-child-6"))
     671        return tstRTCreateProcEx6Child(argc, argv);
     672
     673
     674    /*
     675     * Main process.
     676     */
    422677    const char *pszAsUser   = NULL;
    423678    const char *pszPassword = NULL;
     
    436691    RTTestBanner(hTest);
    437692
     693    /*
     694     * Init globals.
     695     */
    438696    if (!RTProcGetExecutablePath(g_szExecName, sizeof(g_szExecName)))
    439697        RTStrCopy(g_szExecName, sizeof(g_szExecName), argv[0]);
     698    RTTESTI_CHECK_RC(RTEnvClone(&g_hEnvInitial, RTENV_DEFAULT), VINF_SUCCESS);
    440699
    441700    /*
     
    448707    if (pszAsUser)
    449708        tstRTCreateProcEx5(pszAsUser, pszPassword);
     709#ifdef RT_OS_WINDOWS
     710    tstRTCreateProcEx6(pszAsUser, pszPassword);
     711#endif
     712
    450713    /** @todo Cover files, ++ */
     714
     715    RTEnvDestroy(g_hEnvInitial);
    451716
    452717    /*
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