[libvirt] [PATCHv3 1/3] util: improve user lookup helper

Eric Blake eblake at redhat.com
Thu Jul 11 21:11:28 UTC 2013


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>
---

v3: fold in the changes proposed on-list.

I've gone ahead and pushed this, and the rest of the series, now.

Next, I'm working on backporting to at least v1.0.5-maint and
v0.10.2-maint, since those are active Fedora releases.

 src/util/virutil.c | 53 ++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 34 insertions(+), 19 deletions(-)

diff --git a/src/util/virutil.c b/src/util/virutil.c
index 8f38fb1..d7e61db 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -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)
-- 
1.8.1.4




More information about the libvir-list mailing list