From bf8a01689e345ec9c08a1348b5781c51b6016ef4 Mon Sep 17 00:00:00 2001
From: Ryota Ozaki <ozaki.ryota@gmail.com>
Date: Sun, 15 Mar 2009 02:30:02 +0900
Subject: [PATCH] storage: allow alphabetical names in owner/group of permissions

---
 configure.in       |    2 +-
 src/storage_conf.c |   50 ++++++++++++++++++++++++++++++++++++---------
 src/util.c         |   57 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/util.h         |    8 +++++++
 4 files changed, 105 insertions(+), 12 deletions(-)

diff --git a/configure.in b/configure.in
index 413d27c..0277d9a 100644
--- a/configure.in
+++ b/configure.in
@@ -75,7 +75,7 @@ dnl Availability of various common functions (non-fatal if missing).
 AC_CHECK_FUNCS([cfmakeraw regexec uname sched_getaffinity getuid getgid])
 
 dnl Availability of various not common threadsafe functions
-AC_CHECK_FUNCS([strerror_r strtok_r getmntent_r getgrnam_r getpwuid_r])
+AC_CHECK_FUNCS([strerror_r strtok_r getmntent_r getgrnam_r getpwuid_r getpwnam_r])
 
 dnl Availability of various common headers (non-fatal if missing).
 AC_CHECK_HEADERS([pwd.h paths.h regex.h sys/syslimits.h sys/utsname.h sys/wait.h winsock2.h sched.h termios.h sys/poll.h syslog.h])
diff --git a/src/storage_conf.c b/src/storage_conf.c
index 1c9a4e5..7d75b71 100644
--- a/src/storage_conf.c
+++ b/src/storage_conf.c
@@ -412,23 +412,53 @@ virStorageDefParsePerms(virConnectPtr conn,
     if (virXPathNode(conn, "./owner", ctxt) == NULL) {
         perms->uid = getuid();
     } else {
-        if (virXPathLong(conn, "number(./owner)", ctxt, &v) < 0) {
-            virStorageReportError(conn, VIR_ERR_XML_ERROR,
-                                  "%s", _("malformed owner element"));
-            goto error;
+        if (virXPathLong(conn, "number(./owner)", ctxt, &v) == 0) {
+            perms->uid = (int)v;
+        } else {
+            char *name;
+            int uid;
+
+            name = virXPathString(conn, "string(./owner)", ctxt);
+            if (!name) {
+                 virStorageReportError(conn, VIR_ERR_XML_ERROR,
+                                       "%s", _("malformed owner element"));
+                 goto error;
+            }
+
+            uid = virGetUIDByUsername(conn, name);
+            VIR_FREE(name);
+            if (uid < 0) {
+                 goto error;
+            }
+
+            perms->uid = uid;
         }
-        perms->uid = (int)v;
     }
 
     if (virXPathNode(conn, "./group", ctxt) == NULL) {
         perms->gid = getgid();
     } else {
-        if (virXPathLong(conn, "number(./group)", ctxt, &v) < 0) {
-            virStorageReportError(conn, VIR_ERR_XML_ERROR,
-                                  "%s", _("malformed group element"));
-            goto error;
+        if (virXPathLong(conn, "number(./group)", ctxt, &v) == 0) {
+            perms->gid = (int)v;
+        } else {
+            char *name;
+            int gid;
+
+            name = virXPathString(conn, "string(./group)", ctxt);
+            if (!name) {
+                 virStorageReportError(conn, VIR_ERR_XML_ERROR,
+                                       "%s", _("malformed group element"));
+                 goto error;
+            }
+
+            gid = virGetGIDByGroupname(conn, name);
+            VIR_FREE(name);
+            if (gid < 0) {
+                 goto error;
+            }
+
+            perms->gid = gid;
         }
-        perms->gid = (int)v;
     }
 
     /* NB, we're ignoring missing labels here - they'll simply inherit */
diff --git a/src/util.c b/src/util.c
index 9b74757..fbe329d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -50,9 +50,12 @@
 #include <paths.h>
 #endif
 #include <netdb.h>
-#ifdef HAVE_GETPWUID_R
+#if defined(HAVE_GETPWUID_R) || defined(HAVE_GETPWNAM_R)
 #include <pwd.h>
 #endif
+#ifdef HAVE_GETGRNAM_R
+#include <grp.h>
+#endif
 
 #include "virterror_internal.h"
 #include "logging.h"
@@ -1558,3 +1561,55 @@ char *virGetUserDirectory(virConnectPtr conn,
     return ret;
 }
 #endif
+
+
+#ifdef HAVE_GETPWNAM_R
+int virGetUIDByUsername(virConnectPtr conn, char *name)
+{
+    struct passwd pwbuf;
+    struct passwd *pw = NULL;
+    char *strbuf;
+    size_t strbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+
+    if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    if (getpwnam_r(name, &pwbuf, strbuf, strbuflen, &pw) != 0 || pw == NULL) {
+        virReportSystemError(conn, errno,
+                             _("Failed to find user record for name '%s'"),
+                             name);
+        VIR_FREE(strbuf);
+        return -1;
+    }
+    VIR_FREE(strbuf);
+    return pw->pw_uid;
+}
+#endif
+
+
+#ifdef HAVE_GETGRNAM_R
+int virGetGIDByGroupname(virConnectPtr conn, char *name)
+{
+    struct group grbuf;
+    struct group *gr = NULL;
+    char *strbuf;
+    size_t strbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
+
+    if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
+        virReportOOMError(conn);
+        return -1;
+    }
+
+    if (getgrnam_r(name, &grbuf, strbuf, strbuflen, &gr) != 0 || gr == NULL) {
+        virReportSystemError(conn, errno,
+                             _("Failed to find group record for name '%s'"),
+                             name);
+        VIR_FREE(strbuf);
+        return -1;
+    }
+    VIR_FREE(strbuf);
+    return gr->gr_gid;
+}
+#endif
diff --git a/src/util.h b/src/util.h
index 87cbf67..ffd3458 100644
--- a/src/util.h
+++ b/src/util.h
@@ -195,6 +195,14 @@ char *virGetUserDirectory(virConnectPtr conn,
                           uid_t uid);
 #endif
 
+#ifdef HAVE_GETPWNAM_R
+int virGetUIDByUsername(virConnectPtr conn, char *name);
+#endif
+
+#ifdef HAVE_GETGRNAM_R
+int virGetGIDByGroupname(virConnectPtr conn, char *name);
+#endif
+
 int virRandomInitialize(unsigned int seed);
 int virRandom(int max);
 
-- 
1.6.0.6

