]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
special case profile loading for StartProgram
authorOliver Kurth <okurth@vmware.com>
Tue, 18 Dec 2018 21:19:47 +0000 (13:19 -0800)
committerOliver Kurth <okurth@vmware.com>
Tue, 18 Dec 2018 21:19:47 +0000 (13:19 -0800)
For StartProgram, we need to be sure there's no race in the profile
unloading.  So keep it open through the life of the started program.

See related vgauth change.

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

index 56223368075d7f689ad0c26950ed5679202e880d..ec23f632307ad40dab4e8a6b33c9b0772f5b1b9a 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,42 @@ 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.
+    */
+   if (GuestAuthEnabled()) {
+      asyncState->hToken = INVALID_HANDLE_VALUE;
+      asyncState->hProfile = INVALID_HANDLE_VALUE;
+      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 +1862,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()) {
+      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__);
+         // EndImpersonate 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 +1896,7 @@ VixToolsStartProgramImpl(const char *requestName,            // IN
     */
    asyncState = NULL;
 
+
 abort:
    free(tempCommandLine);
    free(fullCommandLine);
@@ -2123,6 +2197,7 @@ done:
  *
  *-----------------------------------------------------------------------------
  */
+
 static void
 VixToolsUpdateStartedProgramList(VixToolsStartedProgramState *state)        // IN
 {
@@ -2147,6 +2222,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
@@ -8192,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
@@ -11854,4 +11942,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
+