]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
lib/file: Clean up POSIX File_GetSafeTempDir() in fileTempPosix.c
authorOliver Kurth <okurth@vmware.com>
Mon, 26 Feb 2018 20:29:07 +0000 (12:29 -0800)
committerOliver Kurth <okurth@vmware.com>
Mon, 26 Feb 2018 20:29:07 +0000 (12:29 -0800)
Make things clearer.

open-vm-tools/lib/file/fileTempPosix.c

index adce56be9842a4641bed29fdf2b8837eb1e6b0f3..d035ae8904a8f99f041dc9b1286cb5bfb0920f5f 100644 (file)
  *
  * FileTryDir --
  *
- *     Check to see if the given directory is actually a directory
+ *      Check to see if the specified directory is actually a directory
  *      and is writable by us.
  *
  * Results:
- *     The expanded directory name on success, NULL on failure.
+ *     !NULL  The expanded directory name (must be freed)
+ *      NULL  Failure
  *
  * Side effects:
- *     The result is allocated.
+ *      None
  *
  *----------------------------------------------------------------------
  */
@@ -98,15 +99,16 @@ FileTryDir(const char *dirName)  // IN: Is this a writable directory?
  *
  * FileGetTmpDir --
  *
- *     Determine the best temporary directory. Unsafe since the
- *     returned directory is generally going to be 0777, thus all sorts
- *     of denial of service or symlink attacks are possible.
+ *      Determine the best temporary directory. Unsafe since the returned
+ *      directory is generally going to be 0777, thus all sorts of denial
+ *      of service or symlink attacks are possible.
  *
  * Results:
- *     NULL if error (reported to the user).
+ *     !NULL  The temp directory name (must be freed)
+ *      NULL  Failure (reported to the user).
  *
  * Side effects:
- *     The result is allocated.
+ *      None
  *
  *----------------------------------------------------------------------
  */
@@ -178,12 +180,12 @@ FileGetTmpDir(Bool useConf)  // IN: Use the config file?
  *
  * FileGetUserName --
  *
- *      Retrieve the name associated with a user ID. Thread-safe
+ *      Retrieve the name associated with the specified UID. Thread-safe
  *      version. --hpreg
  *
  * Results:
- *      The allocated name on success
- *      NULL on failure
+ *     !NULL  The user name (must be freed)
+ *      NULL  Failure
  *
  * Side effects:
  *      None
@@ -195,10 +197,10 @@ static char *
 FileGetUserName(uid_t uid)  // IN:
 {
    char *memPool;
-   char *userName;
+   long memPoolSize;
    struct passwd pw;
    struct passwd *pw_p;
-   long memPoolSize;
+   char *userName = NULL;
 
 #if defined(__APPLE__)
    memPoolSize = _PASSWORD_LEN;
@@ -212,28 +214,56 @@ FileGetUserName(uid_t uid)  // IN:
    }
 #endif
 
-   memPool = malloc(memPoolSize);
-   if (memPool == NULL) {
-      Warning("%s: Not enough memory.\n", __FUNCTION__);
-
-      return NULL;
-   }
+   memPool = Util_SafeMalloc(memPoolSize);
 
    if ((Posix_Getpwuid_r(uid, &pw, memPool, memPoolSize, &pw_p) != 0) ||
        pw_p == NULL) {
-      Posix_Free(memPool);
-      Warning("%s: Unable to retrieve the username associated with "
-              "user ID %u.\n", __FUNCTION__, uid);
-
-      return NULL;
+      Warning("%s: Unable to retrieve the user name associated with UID %u.\n",
+             __FUNCTION__, uid);
+   } else {
+      userName = Util_SafeStrdup(pw_p->pw_name);
    }
 
-   userName = strdup(pw_p->pw_name);
    Posix_Free(memPool);
+
+   return userName;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * FileGetUserIdentifier --
+ *
+ *      Attempt to obtain an user identification string.
+ *
+ * Results:
+ *     A dynamically allocated string containing the user identifier.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static char *
+FileGetUserIdentifier(uid_t uid,    // IN:
+                      Bool addPid)  // IN:
+{
+   char *userName = FileGetUserName(uid);
+
    if (userName == NULL) {
-      Warning("%s: Not enough memory.\n", __FUNCTION__);
+      Warning("%s: Failed to get user name, using UID.\n", __FUNCTION__);
 
-      return NULL;
+      /* Fallback on just using the uid as the user name. */
+      userName = Str_SafeAsprintf(NULL, "uid_%u", uid);
+   }
+
+   if (addPid) {
+      char *pidToo = Str_SafeAsprintf(NULL, "%s_%u", userName, getpid());
+
+      Posix_Free(userName);
+      userName = pidToo;
    }
 
    return userName;
@@ -245,13 +275,13 @@ FileGetUserName(uid_t uid)  // IN:
  *
  * FileAcceptableSafeTmpDir --
  *
- *      Determines if the specified path is acceptable as the safe
- *      temp directory.  The directory must either be creatable
- *      with the appropriate permissions and userId or it must
- *      already exist with those settings.
+ *      Determines if the specified path is acceptable as a safe temp
+ *      directory. The directory must either be creatable with the appropriate
+ *      permissions and UID or it must already exist with those settings.
  *
  * Results:
- *      TRUE if path is acceptible, FALSE otherwise
+ *      TRUE   Path is acceptible
+ *      FALSE  Otherwise
  *
  * Side effects:
  *      Directory may be created
@@ -260,14 +290,15 @@ FileGetUserName(uid_t uid)  // IN:
  */
 
 static Bool
-FileAcceptableSafeTmpDir(const char *dirname,  // IN:
-                         int userId)           // IN:
+FileAcceptableSafeTmpDir(const char *dirName,  // IN:
+                         uid_t uid)            // IN:
 {
-   Bool result;
+   Bool acceptable;
    static const mode_t mode = 0700;
 
-   result = (Posix_Mkdir(dirname, mode) == 0);
-   if (!result) {
+   acceptable = (Posix_Mkdir(dirName, mode) == 0);
+
+   if (!acceptable) {
       int error = errno;
 
       if (EEXIST == error) {
@@ -282,23 +313,23 @@ FileAcceptableSafeTmpDir(const char *dirname,  // IN:
           * effective user with permissions 'mode'.
           */
 
-         if (Posix_Lstat(dirname, &st) == 0) {
+         if (Posix_Lstat(dirName, &st) == 0) {
             /*
-             * Our directory inherited S_ISGID if its parent had it. So it
-             * is important to ignore that bit, and it is safe to do so
-             * because that bit does not affect the owner's permissions.
+             * Our directory inherited S_ISGID if its parent had it. So it is
+             * important to ignore that bit, and it is safe to do so because
+             * that bit does not affect the owner's permissions.
              */
 
             if (S_ISDIR(st.st_mode) &&
-                (st.st_uid == userId) &&
+                (st.st_uid == uid) &&
                 ((st.st_mode & 05777) == mode)) {
-               result = TRUE;
+               acceptable = TRUE;
             }
          }
       }
    }
 
-   return result;
+   return acceptable;
 }
 
 
@@ -307,13 +338,13 @@ FileAcceptableSafeTmpDir(const char *dirname,  // IN:
  *
  * FileFindExistingSafeTmpDir --
  *
- *      Searches the directory baseTmpDir to see if any subdirectories
- *      are suitable to use as the safe temp directory.  The safe temp
- *      directory must have the correct permissions and userId.
+ *      Searches baseTmpDir to see if any subdirectories are suitable to use
+ *      as a safe temp directory. The safe temp directory must have the correct
+ *      permissions and UID.
  *
  * Results:
- *      Path to discovered safe temp directory (must be freed).
- *      NULL returned if no suitable directory is found.
+ *     !NULL  Path to discovered safe temp directory (must be freed)
+ *      NULL  No suitable directory was found
  *
  * Side effects:
  *      None
@@ -322,9 +353,9 @@ FileAcceptableSafeTmpDir(const char *dirname,  // IN:
  */
 
 static char *
-FileFindExistingSafeTmpDir(uid_t userId,            // IN:
+FileFindExistingSafeTmpDir(const char *baseTmpDir,  // IN:
                            const char *userName,    // IN:
-                           const char *baseTmpDir)  // IN:
+                           uid_t uid)               // IN:
 {
    int i;
    int numFiles;
@@ -333,9 +364,9 @@ FileFindExistingSafeTmpDir(uid_t userId,            // IN:
    char **fileList = NULL;
 
    /*
-    * We always use the pattern PRODUCT-USER-xxxx when creating
-    * alternative safe temp directories, so check for ones with
-    * those names and the appropriate permissions.
+    * We always use the pattern PRODUCT-USER-xxxx when creating alternative
+    * safe temp directories, so check for ones with those names and the
+    * appropriate permissions.
     */
 
    pattern = Unicode_Format("%s-%s-", PRODUCT_GENERIC_NAME_LOWER, userName);
@@ -356,7 +387,7 @@ FileFindExistingSafeTmpDir(uid_t userId,            // IN:
           char *path = Unicode_Join(baseTmpDir, DIRSEPS, fileList[i], NULL);
 
           if (File_IsDirectory(path) &&
-              FileAcceptableSafeTmpDir(path, userId)) {
+              FileAcceptableSafeTmpDir(path, uid)) {
              tmpDir = path;
              break;
           }
@@ -378,11 +409,11 @@ FileFindExistingSafeTmpDir(uid_t userId,            // IN:
  * FileCreateSafeTmpDir --
  *
  *      Creates a new directory within baseTmpDir with the correct permissions
- *      and userId to ensure it is safe from symlink attacks.
+ *      and UID to ensure it is safe from symlink attacks.
  *
  * Results:
- *      Path to created safe temp directory (must be freed).
- *      NULL returned if no suitable directory could be created.
+ *     !NULL  Path to created safe temp directory (must be freed)
+ *      NULL  No suitable directory was found
  *
  * Side effects:
  *      Directory may be created.
@@ -391,13 +422,13 @@ FileFindExistingSafeTmpDir(uid_t userId,            // IN:
  */
 
 static char *
-FileCreateSafeTmpDir(uid_t userId,            // IN:
+FileCreateSafeTmpDir(const char *baseTmpDir,  // IN:
                      const char *userName,    // IN:
-                     const char *baseTmpDir)  // IN:
+                     uid_t uid)               // IN:
 {
-   static const int MAX_DIR_ITERS = 250;
    int curDirIter = 0;
    char *tmpDir = NULL;
+   static const int MAX_DIR_ITERS = 250;
 
    while (TRUE) {
       /*
@@ -405,16 +436,11 @@ FileCreateSafeTmpDir(uid_t userId,            // IN:
        * an unused name than if we had simply tried suffixes in numeric order.
        */
 
-      tmpDir = Str_Asprintf(NULL, "%s%s%s-%s-%u", baseTmpDir, DIRSEPS,
-                            PRODUCT_GENERIC_NAME_LOWER, userName,
-                            FileSimpleRandom());
+      tmpDir = Str_SafeAsprintf(NULL, "%s%s%s-%s-%u", baseTmpDir, DIRSEPS,
+                                PRODUCT_GENERIC_NAME_LOWER, userName,
+                                FileSimpleRandom());
 
-      if (tmpDir == NULL) {
-         Warning("%s: Out of memory error.\n", __FUNCTION__);
-         break;
-      }
-
-      if (FileAcceptableSafeTmpDir(tmpDir, userId)) {
+      if (FileAcceptableSafeTmpDir(tmpDir, uid)) {
          break;
       }
 
@@ -428,7 +454,6 @@ FileCreateSafeTmpDir(uid_t userId,            // IN:
       }
 
       Posix_Free(tmpDir);
-      tmpDir = NULL;
    }
 
    return tmpDir;
@@ -442,17 +467,19 @@ FileCreateSafeTmpDir(uid_t userId,            // IN:
  * FileGetSafeTmpDir --
  *
  *      Return a safe temporary directory (i.e. a temporary directory which
- *      is not prone to symlink attacks, because it is only writable by the
- *      current effective user).
+ *      is not prone to symlink attacks, because it is only writable with the
+ *      current set of credentials (EUID).
  *
- *      Guaranteed to return the same directory, based on the randomTemp
- *      boolean argument, every time it is called during the lifetime of
- *      the current process, for the current effective user ID. (Barring
- *      the user manually deleting or renaming the directory.)
+ *      Guaranteed to return the same directory every time it is called during
+ *      the lifetime of the current process, for the current effective UID.
+ *      (Barring the user manually deleting or renaming the directory.)
+ *
+ *      Optionally, add the PID to the user identifier for the cases where
+ *      the EUID may change during the lifetime of the calling process.
  *
  * Results:
- *      The allocated directory path on success.
- *      NULL on failure.
+ *     !NULL  Path to safe temp directory (must be freed)
+ *      NULL  No suitable directory was found
  *
  * Side effects:
  *      None.
@@ -461,8 +488,8 @@ FileCreateSafeTmpDir(uid_t userId,            // IN:
  */
 
 static char *
-FileGetSafeTmpDir(Bool useConf,     // IN:
-                  Bool randomTemp)  // IN:
+FileGetSafeTmpDir(Bool useConf,  // IN: Use configuration variables?
+                  Bool addPid)   // IN: Add PID to userName?
 {
    char *tmpDir = NULL;
 
@@ -471,14 +498,12 @@ FileGetSafeTmpDir(Bool useConf,     // IN:
 #else
    static Atomic_Ptr lckStorage;
    static char *safeDir;
-   static char *safeRandomDir;
+   static char *safePidDir;
+   MXUserExclLock *lck;
    char *testSafeDir;
-   char *baseTmpDir = NULL;
    char *userName = NULL;
-   uid_t userId;
-   MXUserExclLock *lck;
-
-   userId = geteuid();
+   char *baseTmpDir = NULL;
+   uid_t euid = geteuid();
 
    /* Get and take lock for our safe dir. */
    lck = MXUser_CreateSingletonExclLock(&lckStorage, "getSafeTmpDirLock",
@@ -487,12 +512,13 @@ FileGetSafeTmpDir(Bool useConf,     // IN:
    MXUser_AcquireExclLock(lck);
 
    /*
-    * Based on the randomTemp boolean argument, check if we've created a
+    * Based on the addPid boolean argument, check if we've created a
     * temporary dir already and if it is still usable.
     */
 
-   testSafeDir = randomTemp ? safeRandomDir : safeDir;
-   if (testSafeDir && FileAcceptableSafeTmpDir(testSafeDir, userId)) {
+   testSafeDir = addPid ? safePidDir : safeDir;
+
+   if ((testSafeDir != NULL) && FileAcceptableSafeTmpDir(testSafeDir, euid)) {
       tmpDir = Util_SafeStrdup(testSafeDir);
       goto exit;
    }
@@ -501,71 +527,31 @@ FileGetSafeTmpDir(Bool useConf,     // IN:
    baseTmpDir = FileGetTmpDir(useConf);
 
    if (baseTmpDir == NULL) {
-      Warning("%s: FileGetTmpDir failed.\n", __FUNCTION__);
       goto exit;
    }
 
-   userName = FileGetUserName(userId);
+   userName = FileGetUserIdentifier(euid, addPid);
 
-   if (userName == NULL) {
-      Warning("%s: FileGetUserName failed, using numeric ID "
-              "as username instead.\n", __FUNCTION__);
-
-      /* Fallback on just using the userId as the username. */
-      userName = Str_Asprintf(NULL, "uid_%d", userId);
+   tmpDir = Str_SafeAsprintf(NULL, "%s%s%s-%s", baseTmpDir, DIRSEPS,
+                             PRODUCT_GENERIC_NAME_LOWER, userName);
 
-      if (userName == NULL) {
-         Warning("%s: Str_Asprintf error.\n", __FUNCTION__);
-         goto exit;
-      }
-   }
-
-   if (randomTemp) {
+   if (addPid || !FileAcceptableSafeTmpDir(tmpDir, euid)) {
       /*
-       * Suffix the userName with the PID for the cases where the
-       * EUID may toggle during the lifetime of the process.
-       */
-
-      char *userNameAndPid;
-      pid_t pid = getpid();
-
-      userNameAndPid = Str_Asprintf(NULL, "%s_%d", userName, pid);
-
-      if (userNameAndPid == NULL) {
-         Warning("%s: Str_Asprintf error.\n", __FUNCTION__);
-         goto exit;
-      }
-
-      Posix_Free(userName);
-      userName = userNameAndPid;
-   }
-
-   tmpDir = Str_Asprintf(NULL, "%s%s%s-%s", baseTmpDir, DIRSEPS,
-                         PRODUCT_GENERIC_NAME_LOWER, userName);
-
-   if (tmpDir == NULL) {
-      Warning("%s: Out of memory error.\n", __FUNCTION__);
-      goto exit;
-   }
-
-   if (randomTemp || !FileAcceptableSafeTmpDir(tmpDir, userId)) {
-      /*
-       * Either we want a truely random temp directory or we didn't get
-       * our first choice for the safe temp directory.
-       * Search through the unsafe tmp directory to see if there is
-       * an acceptable one to use.
+       * Either we want a truely random temp directory or we didn't get our
+       * first choice for the safe temp directory. Search through the unsafe
+       * tmp directory to see if there is an acceptable one to use.
        */
 
       Posix_Free(tmpDir);
 
-      tmpDir = FileFindExistingSafeTmpDir(userId, userName, baseTmpDir);
+      tmpDir = FileFindExistingSafeTmpDir(baseTmpDir, userName, euid);
 
       if (tmpDir == NULL) {
          /*
           * We didn't find any usable directories, so try to create one now.
           */
 
-         tmpDir = FileCreateSafeTmpDir(userId, userName, baseTmpDir);
+         tmpDir = FileCreateSafeTmpDir(baseTmpDir, userName, euid);
       }
    }
 
@@ -576,16 +562,18 @@ FileGetSafeTmpDir(Bool useConf,     // IN:
        */
 
       testSafeDir = Util_SafeStrdup(tmpDir);
-      if (randomTemp) {
-         Posix_Free(safeRandomDir);
-         safeRandomDir = testSafeDir;
+
+      if (addPid) {
+         Posix_Free(safePidDir);
+         safePidDir = testSafeDir;
       } else {
          Posix_Free(safeDir);
          safeDir = testSafeDir;
       }
    }
 
-  exit:
+exit:
+
    MXUser_ReleaseExclLock(lck);
    Posix_Free(baseTmpDir);
    Posix_Free(userName);
@@ -601,17 +589,16 @@ FileGetSafeTmpDir(Bool useConf,     // IN:
  * File_GetSafeTmpDir --
  *
  *      Return a safe temporary directory (i.e. a temporary directory which
- *      is not prone to symlink attacks, because it is only writable by the
- *      current effective user).
+ *      is not prone to symlink attacks, because it is only writable with the
+ *      current set of credentials (EUID).
  *
- *      Guaranteed to return the same directory every time it is
- *      called during the lifetime of the current process, for the
- *      current effective user ID. (Barring the user manually deleting
- *      or renaming the directory.)
+ *      Guaranteed to return the same directory every time it is called during
+ *      the lifetime of the current process, for the current effective UID.
+ *      (Barring the user manually deleting or renaming the directory.)
  *
  * Results:
- *      The allocated directory path on success.
- *      NULL on failure.
+ *     !NULL  Path to safe temp directory (must be freed)
+ *      NULL  No suitable directory was found
  *
  * Side effects:
  *      None.
@@ -622,7 +609,7 @@ FileGetSafeTmpDir(Bool useConf,     // IN:
 char *
 File_GetSafeTmpDir(Bool useConf)  // IN:
 {
-   return  FileGetSafeTmpDir(useConf, FALSE);
+   return FileGetSafeTmpDir(useConf, FALSE);
 }
 
 
@@ -632,17 +619,16 @@ File_GetSafeTmpDir(Bool useConf)  // IN:
  * File_GetSafeRandomTmpDir --
  *
  *      Return a safe, random temporary directory (i.e. a temporary directory
- *      which is not prone to symlink attacks, because it is only writable
- *      by the current effective user).
+ *      is not prone to symlink attacks, because it is only writable with the
+ *      current set of credentials (EUID).
  *
- *      Guaranteed to return the same directory every time it is
- *      called during the lifetime of the current process, for the
- *      current effective user ID. (Barring the user manually deleting
- *      or renaming the directory.)
+ *      Guaranteed to return the same directory every time it is called during
+ *      the lifetime of the current process, for the current effective UID.
+ *      (Barring the user manually deleting or renaming the directory.)
  *
  * Results:
- *      The allocated directory path on success.
- *      NULL on failure.
+ *     !NULL  Path to safe temp directory (must be freed).
+ *      NULL  No suitable directory was found.
  *
  * Side effects:
  *      None.