]> git.ipfire.org Git - thirdparty/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>
Mon, 22 Jul 2013 21:37:42 +0000 (15:37 -0600)
https://bugzilla.redhat.com/show_bug.cgi?id=964358

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>
(cherry picked from commit c1983ba4e3902308054e961fcae75cece73ef4ba)

Conflicts:
src/util/virutil.c - oom reporting/strdup changes not backported

src/util/util.c

index 8315515293d23e347ecec11e2fcc379df087cec2..dd4e4eafb2fb3709de0637945c7d4d55855196bc 100644 (file)
@@ -2290,21 +2290,23 @@ check_and_return:
 }
 
 #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)
@@ -2312,7 +2314,7 @@ static char *virGetUserEnt(uid_t uid,
 
     if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
         virReportOOMError();
-        return NULL;
+        return -1;
     }
 
     /*
@@ -2325,28 +2327,33 @@ 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) {
             virReportOOMError();
-            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 (field == VIR_USER_ENT_DIRECTORY)
-        ret = strdup(pw->pw_dir);
-    else
-        ret = strdup(pw->pw_name);
+    if (name && !(*name = strdup(pw->pw_name)))
+        goto no_memory;
+    if (group)
+        *group = pw->pw_gid;
+    if (dir && !(*dir = strdup(pw->pw_dir))) {
+        if (name)
+            VIR_FREE(*name);
+        goto no_memory;
+    }
 
+    ret = 0;
+cleanup:
     VIR_FREE(strbuf);
-    if (!ret)
-        virReportOOMError();
-
     return ret;
+no_memory:
+    virReportOOMError();
+    goto cleanup;
 }
 
 static char *virGetGroupEnt(gid_t gid)
@@ -2401,20 +2408,23 @@ 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)
 {
     const char *path = getenv(xdgenvname);
     char *ret = NULL;
-    char *home = virGetUserEnt(geteuid(), VIR_USER_ENT_DIRECTORY);
+    char *home = virGetUserDirectory();
 
     if (path && path[0]) {
         if (virAsprintf(&ret, "%s/libvirt", path) < 0)
             goto no_memory;
     } else {
-        if (virAsprintf(&ret, "%s/%s/libvirt", home, xdgdefdir) < 0)
+        if (home &&
+            virAsprintf(&ret, "%s/%s/libvirt", home, xdgdefdir) < 0)
             goto no_memory;
     }
 
@@ -2456,7 +2466,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)