]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Special-case profile loading for StartProgram
authorOliver Kurth <okurth@vmware.com>
Tue, 29 Jan 2019 22:03:18 +0000 (14:03 -0800)
committerOliver Kurth <okurth@vmware.com>
Tue, 29 Jan 2019 22:03:18 +0000 (14:03 -0800)
Keep the user's profile loaded for the life of the
program, to avoid races where its unloaded too quickly.

open-vm-tools/services/plugins/vix/vixTools.c

index e52737867a6f7197b2806d33d1f035c6ce0824e8..b4280ffd466882101530380949aa65293b7288e5 100644 (file)
@@ -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
+