[libvirt] [PATCH 1/7] util: improve user lookup helper

Eric Blake eblake at redhat.com
Tue Jul 23 15:03:54 UTC 2013


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 at redhat.com>
(cherry picked from commit c1983ba4e3902308054e961fcae75cece73ef4ba)

Conflicts:
	src/util/virutil.c - oom reporting/strdup changes not backported
---
 src/util/util.c | 60 ++++++++++++++++++++++++++++++++++-----------------------
 1 file changed, 36 insertions(+), 24 deletions(-)

diff --git a/src/util/util.c b/src/util/util.c
index 8315515..dd4e4ea 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -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)
-- 
1.8.3.1




More information about the libvir-list mailing list