]> xenbits.xensource.com Git - libvirt.git/commitdiff
util: improve user lookup helper
authorEric Blake <eblake@redhat.com>
Tue, 9 Jul 2013 23:57:48 +0000 (17:57 -0600)
committerEric Blake <eblake@redhat.com>
Thu, 11 Jul 2013 21:12:56 +0000 (15:12 -0600)
A future patch needs to look up pw_gid; but it is wasteful
to crawl through getpwuid_r twice for two separate pieces
of information, and annoying to copy that much boilerplate
code for doing the crawl.  The current internal-only
virGetUserEnt is also a rather awkward interface; it's easier
to just design it to let callers request multiple pieces of
data as needed from one traversal.

And while at it, I noticed that virGetXDGDirectory could deref
NULL if the getpwuid_r lookup fails.

* src/util/virutil.c (virGetUserEnt): Alter signature.
(virGetUserDirectory, virGetXDGDirectory, virGetUserName): Adjust
callers.

Signed-off-by: Eric Blake <eblake@redhat.com>
src/util/virutil.c

index 8f38fb114f78eb61de6ba98d36be667d19660314..d7e61db37f1b6c4f45cbf778a00a41ffae296b86 100644 (file)
@@ -647,28 +647,30 @@ cleanup:
 }
 
 #ifdef HAVE_GETPWUID_R
-enum {
-    VIR_USER_ENT_DIRECTORY,
-    VIR_USER_ENT_NAME,
-};
-
-static char *virGetUserEnt(uid_t uid,
-                           int field)
+/* Look up fields from the user database for the given user.  On
+ * error, set errno, report the error, and return -1.  */
+static int
+virGetUserEnt(uid_t uid, char **name, gid_t *group, char **dir)
 {
     char *strbuf;
-    char *ret;
     struct passwd pwbuf;
     struct passwd *pw = NULL;
     long val = sysconf(_SC_GETPW_R_SIZE_MAX);
     size_t strbuflen = val;
     int rc;
+    int ret = -1;
+
+    if (name)
+        *name = NULL;
+    if (dir)
+        *dir = NULL;
 
     /* sysconf is a hint; if it fails, fall back to a reasonable size */
     if (val < 0)
         strbuflen = 1024;
 
     if (VIR_ALLOC_N(strbuf, strbuflen) < 0)
-        return NULL;
+        return -1;
 
     /*
      * From the manpage (terrifying but true):
@@ -679,19 +681,27 @@ static char *virGetUserEnt(uid_t uid,
      */
     while ((rc = getpwuid_r(uid, &pwbuf, strbuf, strbuflen, &pw)) == ERANGE) {
         if (VIR_RESIZE_N(strbuf, strbuflen, strbuflen, strbuflen) < 0)
-            VIR_FREE(strbuf);
-            return NULL;
+            goto cleanup;
     }
     if (rc != 0 || pw == NULL) {
         virReportSystemError(rc,
                              _("Failed to find user record for uid '%u'"),
                              (unsigned int) uid);
-        VIR_FREE(strbuf);
-        return NULL;
+        goto cleanup;
+    }
+
+    if (name && VIR_STRDUP(*name, pw->pw_name) < 0)
+        goto cleanup;
+    if (group)
+        *group = pw->pw_gid;
+    if (dir && VIR_STRDUP(*dir, pw->pw_dir) < 0) {
+        if (name)
+            VIR_FREE(*name);
+        goto cleanup;
     }
 
-    ignore_value(VIR_STRDUP(ret, field == VIR_USER_ENT_DIRECTORY ?
-                            pw->pw_dir : pw->pw_name));
+    ret = 0;
+cleanup:
     VIR_FREE(strbuf);
     return ret;
 }
@@ -741,7 +751,9 @@ static char *virGetGroupEnt(gid_t gid)
 
 char *virGetUserDirectory(void)
 {
-    return virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY);
+    char *ret;
+    virGetUserEnt(geteuid(), NULL, NULL, &ret);
+    return ret;
 }
 
 static char *virGetXDGDirectory(const char *xdgenvname, const char *xdgdefdir)
@@ -753,8 +765,9 @@ static char *virGetXDGDirectory(const char *xdgenvname, const char *xdgdefdir)
     if (path && path[0]) {
         ignore_value(virAsprintf(&ret, "%s/libvirt", path));
     } else {
-        home = virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY);
-        ignore_value(virAsprintf(&ret, "%s/%s/libvirt", home, xdgdefdir));
+        home = virGetUserDirectory();
+        if (home)
+            ignore_value(virAsprintf(&ret, "%s/%s/libvirt", home, xdgdefdir));
     }
 
     VIR_FREE(home);
@@ -787,7 +800,9 @@ char *virGetUserRuntimeDirectory(void)
 
 char *virGetUserName(uid_t uid)
 {
-    return virGetUserEnt(uid, VIR_USER_ENT_NAME);
+    char *ret;
+    virGetUserEnt(uid, &ret, NULL, NULL);
+    return ret;
 }
 
 char *virGetGroupName(gid_t gid)