From: Oliver Kurth Date: Tue, 29 Jan 2019 22:03:18 +0000 (-0800) Subject: Special-case profile loading for StartProgram X-Git-Tag: stable-10.3.10~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=81835cd72369b5b75fc5b0bed761f3b75cb7146b;p=thirdparty%2Fopen-vm-tools.git Special-case profile loading for StartProgram Keep the user's profile loaded for the life of the program, to avoid races where its unloaded too quickly. --- diff --git a/open-vm-tools/services/plugins/vix/vixTools.c b/open-vm-tools/services/plugins/vix/vixTools.c index e52737867..b4280ffd4 100644 --- a/open-vm-tools/services/plugins/vix/vixTools.c +++ b/open-vm-tools/services/plugins/vix/vixTools.c @@ -293,10 +293,18 @@ typedef struct VixToolsRunProgramState { /* * State of a single asynch startProgram. + * + * On Windows, keep the user's token and profile HANDLEs around + * so the profile isn't unloaded until the program exits. */ typedef struct VixToolsStartProgramState { ProcMgr_AsyncProc *procState; +#if defined(_WIN32) && SUPPORT_VGAUTH + HANDLE hToken; + HANDLE hProfile; +#endif + void *eventQueue; } VixToolsStartProgramState; @@ -693,6 +701,10 @@ static Bool VixToolsCheckIfAuthenticationTypeEnabled(GKeyFile *confDictRef, VGAuthError TheVGAuthContext(VGAuthContext **ctx); +#ifdef _WIN32 +static void GuestAuthUnloadUserProfileAndToken(HANDLE hToken, HANDLE hProfile); +#endif + #endif @@ -1629,6 +1641,12 @@ VixToolsStartProgramImpl(const char *requestName, // IN Bool envBlockFromMalloc = TRUE; #endif GSource *timer; +#if defined(_WIN32) && SUPPORT_VGAUTH + HANDLE hToken = INVALID_HANDLE_VALUE; + HANDLE hProfile = INVALID_HANDLE_VALUE; + VGAuthError vgErr; + VGAuthContext *ctx; +#endif /* * Initialize this here so we can call free on its member variables in abort @@ -1788,6 +1806,43 @@ VixToolsStartProgramImpl(const char *requestName, // IN procArgs.envp = (char **)envVars; #endif +#if defined(_WIN32) && SUPPORT_VGAUTH + /* + * Special case profile handling for StartProgram. It should stay loaded + * until the program exits, so copy the profile and user handles for + * later cleanup, and clobber the profile handle so that it's not unloaded + * when the impersonation ends. + * + * Only do this when we've actually impersonated; its not + * needed when impersonation isn't done (eg vmusr or SYSTEM bypass). + */ + if (GuestAuthEnabled() && PROCESS_CREATOR_USER_TOKEN != userToken) { + vgErr = TheVGAuthContext(&ctx); + if (VGAUTH_FAILED(vgErr)) { + err = VixToolsTranslateVGAuthError(vgErr); + g_warning("%s: Couldn't get the vgauth context\n", __FUNCTION__); + goto abort; + } + + vgErr = VGAuth_UserHandleAccessToken(ctx, currentUserHandle, &hToken); + if (VGAUTH_FAILED(vgErr)) { + err = VixToolsTranslateVGAuthError(vgErr); + g_warning("%s: Failed to get user token\n", __FUNCTION__); + goto abort; + } + vgErr = VGAuth_UserHandleGetUserProfile(ctx, currentUserHandle, + &hProfile); + if (VGAUTH_FAILED(vgErr)) { + err = VixToolsTranslateVGAuthError(vgErr); + g_warning("%s: Failed to get user profile\n", __FUNCTION__); + CloseHandle(hToken); + goto abort; + } + } + asyncState->hToken = hToken; + asyncState->hProfile = hProfile; +#endif + asyncState->procState = ProcMgr_ExecAsync(fullCommandLine, &procArgs); #if defined(_WIN32) @@ -1808,6 +1863,25 @@ VixToolsStartProgramImpl(const char *requestName, // IN g_debug("%s: started '%s', pid %"FMT64"d\n", __FUNCTION__, fullCommandLine, *pid); +#if defined(_WIN32) && SUPPORT_VGAUTH + /* + * Clobber the profile handle before un-impersonation. + */ + if (GuestAuthEnabled() && PROCESS_CREATOR_USER_TOKEN != userToken) { + vgErr = VGAuth_UserHandleSetUserProfile(ctx, currentUserHandle, + INVALID_HANDLE_VALUE); + if (VGAUTH_FAILED(vgErr)) { + err = VixToolsTranslateVGAuthError(vgErr); + g_warning("%s: Failed to clobber user profile\n", __FUNCTION__); + // VGAuth_EndImpersonation will take care of profile, close hToken + CloseHandle(asyncState->hToken); + asyncState->hToken = INVALID_HANDLE_VALUE; + asyncState->hProfile = INVALID_HANDLE_VALUE; + goto abort; + } + } +#endif + /* * Start a periodic procedure to check the app periodically */ @@ -1823,6 +1897,7 @@ VixToolsStartProgramImpl(const char *requestName, // IN */ asyncState = NULL; + abort: free(tempCommandLine); free(fullCommandLine); @@ -2123,6 +2198,7 @@ done: * *----------------------------------------------------------------------------- */ + static void VixToolsUpdateStartedProgramList(VixToolsStartedProgramState *state) // IN { @@ -2147,6 +2223,9 @@ VixToolsUpdateStartedProgramList(VixToolsStartedProgramState *state) // I spList->endTime = state->endTime; spList->isRunning = FALSE; + g_debug("%s: started program '%s' has completed, exitCode %d\n", + __FUNCTION__, spList->fullCommandLine, spList->exitCode); + /* * Don't let the procState be free'd on Windows to * keep OS from reusing the pid. We need to free @@ -7882,6 +7961,9 @@ VixToolsImpersonateUserImplEx(char const *credentialTypeStr, // IN *userToken = PROCESS_CREATOR_USER_TOKEN; gImpersonatedUsername = Util_SafeStrdup(unobfuscatedUserName); + g_debug("%s: allowing interactive mode for user '%s'\n", + __FUNCTION__, gImpersonatedUsername); + goto abort; } else { /* @@ -8188,6 +8270,16 @@ VixToolsFreeStartProgramState(VixToolsStartProgramState *asyncState) // IN if (NULL == asyncState) { return; } +#if defined(_WIN32) && SUPPORT_VGAUTH + /* + * Unload the user profile if saved. + */ + if (asyncState->hProfile != INVALID_HANDLE_VALUE && + asyncState->hToken != INVALID_HANDLE_VALUE) { + GuestAuthUnloadUserProfileAndToken(asyncState->hToken, + asyncState->hProfile); + } +#endif free(asyncState); } // VixToolsFreeStartProgramState @@ -11825,4 +11917,41 @@ TheVGAuthContext(VGAuthContext **ctx) // OUT *ctx = vgaCtx; return vgaCode; } -#endif + + +#ifdef _WIN32 +/* + *----------------------------------------------------------------------------- + * + * GuestAuthUnloadUserProfileAndToken -- + * + * Unload user profile and close user token. + * + * Helper to handle StartProgram cleanup. + * + * Return value: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static void +GuestAuthUnloadUserProfileAndToken(HANDLE hToken, + HANDLE hProfile) +{ + if (GuestAuthEnabled()) { + g_debug("%s: special-case profile unload %p\n", __FUNCTION__, hProfile); + if (!UnloadUserProfile(hToken, hProfile)) { + g_warning("%s: UnloadUserProfile() failed %d\n", + __FUNCTION__, GetLastError()); + } + CloseHandle(hToken); + } +} +#endif // _WIN32 + +#endif // SUPPORT_VGAUTH +