- Timestamp:
- Sep 21, 2015 4:14:20 PM (9 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/process.h
r57835 r57843 200 200 /** Load user profile data when executing a process. 201 201 * 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. */ 204 203 #define RTPROC_FLAGS_PROFILE RT_BIT(4) 205 204 /** Create process without a console window. -
trunk/src/VBox/Runtime/r3/win/process-win.cpp
r57835 r57843 132 132 133 133 134 /********************************************************************************************************************************* 135 * Internal Functions * 136 *********************************************************************************************************************************/ 137 static int rtProcWinFindExe(uint32_t fFlags, RTENV hEnv, const char *pszExec, PRTUTF16 *ppwszExec); 134 138 135 139 … … 640 644 * Logs on a specified user and returns its primary token. 641 645 * 642 * @return int646 * @returns IPRT status code. 643 647 * @param pwszUser User name. 644 648 * @param pwszPassword Password. … … 750 754 751 755 752 753 756 /** 754 757 * Method \#2. 755 758 */ 756 static int rtProcWinCreateAsUser2(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,759 static int rtProcWinCreateAsUser2(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 *ppwszExec, PRTUTF16 pwszCmdLine, 757 760 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) 759 763 { 760 764 /* … … 784 788 * We may fail here with ERROR_PRIVILEGE_NOT_HELD. 785 789 */ 790 /** @todo r=bird: Both methods starts with rtProcWinUserLogon, so we could probably do that once in the parent function, right... */ 786 791 DWORD dwErr = NO_ERROR; 787 792 HANDLE hTokenLogon = INVALID_HANDLE_VALUE; … … 858 863 if (fFlags & RTPROC_FLAGS_PROFILE) 859 864 { 860 /* @todo r=bird: I'm not convinced that the unload function restores our original environment... */861 865 ProfileInfo.dwSize = sizeof(ProfileInfo); 862 866 ProfileInfo.lpUserName = pwszUser; … … 879 883 if (RT_SUCCESS(rc)) 880 884 { 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 } 904 912 RTEnvFreeUtf16Block(pwszzBlock); 905 913 } … … 953 961 * platforms (however, this works on W2K!). 954 962 */ 955 static int rtProcWinCreateAsUser1(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,963 static int rtProcWinCreateAsUser1(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 *ppwszExec, PRTUTF16 pwszCmdLine, 956 964 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) 958 967 { 959 968 if (!g_pfnCreateProcessWithLogonW) 960 969 return VERR_SYMBOL_NOT_FOUND; 961 970 962 RTENV hEnvToUse ;971 RTENV hEnvToUse = NIL_RTENV; 963 972 HANDLE hToken; 964 973 int rc = rtProcWinUserLogon(pwszUser, pwszPassword, NULL /* Domain */, &hToken); 965 974 if (RT_SUCCESS(rc)) 966 975 { 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); 968 1002 CloseHandle(hToken); 969 1003 } … … 974 1008 if (RT_SUCCESS(rc)) 975 1009 { 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)) 990 1012 { 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 } 996 1035 } 997 1036 RTEnvFreeUtf16Block(pwszzBlock); … … 1004 1043 1005 1044 1006 static int rtProcWinCreateAsUser(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszExec, PRTUTF16 pwszCmdLine,1045 static int rtProcWinCreateAsUser(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 *ppwszExec, PRTUTF16 pwszCmdLine, 1007 1046 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) 1009 1049 { 1010 1050 /* … … 1015 1055 if (!(fFlags & RTPROC_FLAGS_SERVICE)) 1016 1056 { 1017 int rc = rtProcWinCreateAsUser1(pwszUser, pwszPassword, p wszExec, pwszCmdLine,1018 hEnv, dwCreationFlags, pStartupInfo, pProcInfo, fFlags );1057 int rc = rtProcWinCreateAsUser1(pwszUser, pwszPassword, ppwszExec, pwszCmdLine, 1058 hEnv, dwCreationFlags, pStartupInfo, pProcInfo, fFlags, pszExec); 1019 1059 if (RT_SUCCESS(rc)) 1020 1060 return rc; 1021 1061 } 1022 return rtProcWinCreateAsUser2(pwszUser, pwszPassword, p wszExec, pwszCmdLine,1023 hEnv, dwCreationFlags, pStartupInfo, pProcInfo, fFlags );1062 return rtProcWinCreateAsUser2(pwszUser, pwszPassword, ppwszExec, pwszCmdLine, 1063 hEnv, dwCreationFlags, pStartupInfo, pProcInfo, fFlags, pszExec); 1024 1064 } 1025 1065 1026 1066 1027 1067 /** 1028 * RTPathTraverseList callback used by RTProcCreateEx to locate the executable. 1068 * RTPathTraverseList callback used by rtProcWinFindExe to locate the 1069 * executable. 1029 1070 */ 1030 1071 static DECLCALLBACK(int) rtPathFindExec(char const *pchPath, size_t cchPath, void *pvUser1, void *pvUser2) … … 1041 1082 1042 1083 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 */ 1096 static 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 */ 1146 static 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 1043 1208 RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags, 1044 1209 PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser, … … 1053 1218 AssertReturn(!(fFlags & RTPROC_FLAGS_DETACHED) || !phProcess, VERR_INVALID_PARAMETER); 1054 1219 AssertReturn(hEnv != NIL_RTENV, VERR_INVALID_PARAMETER); 1055 AssertReturn( !(fFlags & RTPROC_FLAGS_PROFILE) /* Profile flag isn't fully implemented in all cases: */1056 || pszAsUser1057 || (hEnv != RTENV_DEFAULT && !(fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD)), VERR_NOT_SUPPORTED);1058 1220 AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER); 1059 1221 AssertPtrNullReturn(pszAsUser, VERR_INVALID_POINTER); … … 1071 1233 rc = RTOnce(&g_rtProcWinResolveOnce, rtProcWinResolveOnce, NULL); 1072 1234 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 else1098 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;1104 1235 } 1105 1236 … … 1191 1322 1192 1323 /* 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; 1198 1327 if (RT_SUCCESS(rc)) 1199 rc = RTEnvQueryUtf16Block(hEnv, &pwszzBlock);1200 if (RT_SUCCESS(rc))1201 {1202 PRTUTF16 pwszCmdLine;1203 1328 rc = RTGetOptArgvToUtf16String(&pwszCmdLine, papszArgs, 1204 1329 !(fFlags & RTPROC_FLAGS_UNQUOTED_ARGS) 1205 1330 ? RTGETOPTARGV_CNV_QUOTE_MS_CRT : RTGETOPTARGV_CNV_UNQUOTED); 1331 if (RT_SUCCESS(rc)) 1332 { 1333 PRTUTF16 pwszExec; 1334 rc = RTStrToUtf16(pszExec, &pwszExec); 1206 1335 if (RT_SUCCESS(rc)) 1207 1336 { 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)) 1211 1355 { 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)) 1230 1360 { 1231 1361 if (CreateProcessW(pwszExec, … … 1242 1372 else 1243 1373 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; 1244 1413 } 1245 1414 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; 1287 1417 } 1288 RTUtf16Free(pwsz CmdLine);1289 } 1290 RT EnvFreeUtf16Block(pwszzBlock);1418 RTUtf16Free(pwszExec); 1419 } 1420 RTUtf16Free(pwszCmdLine); 1291 1421 } 1292 1422 -
trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp
r57358 r57843 54 54 * Global Variables * 55 55 *********************************************************************************************************************************/ 56 static char g_szExecName[RTPATH_MAX]; 56 static RTENV g_hEnvInitial = NIL_RTENV; 57 static char g_szExecName[RTPATH_MAX]; 57 58 58 59 … … 82 83 83 84 85 static 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 203 static 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 84 329 static int tstRTCreateProcEx5Child(int argc, char **argv) 85 330 { … … 410 655 int main(int argc, char **argv) 411 656 { 657 /* 658 * Deal with child processes first. 659 */ 412 660 if (argc == 2 && !strcmp(argv[1], "--testcase-child-1")) 413 661 return tstRTCreateProcEx1Child(); … … 420 668 if (argc == 2 && !strcmp(argv[1], "--testcase-child-5")) 421 669 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 */ 422 677 const char *pszAsUser = NULL; 423 678 const char *pszPassword = NULL; … … 436 691 RTTestBanner(hTest); 437 692 693 /* 694 * Init globals. 695 */ 438 696 if (!RTProcGetExecutablePath(g_szExecName, sizeof(g_szExecName))) 439 697 RTStrCopy(g_szExecName, sizeof(g_szExecName), argv[0]); 698 RTTESTI_CHECK_RC(RTEnvClone(&g_hEnvInitial, RTENV_DEFAULT), VINF_SUCCESS); 440 699 441 700 /* … … 448 707 if (pszAsUser) 449 708 tstRTCreateProcEx5(pszAsUser, pszPassword); 709 #ifdef RT_OS_WINDOWS 710 tstRTCreateProcEx6(pszAsUser, pszPassword); 711 #endif 712 450 713 /** @todo Cover files, ++ */ 714 715 RTEnvDestroy(g_hEnvInitial); 451 716 452 717 /*
Note:
See TracChangeset
for help on using the changeset viewer.