Package: libvirt / 0.8.3-5+squeeze5

security/0017-New-virSetUIDGID-utility-function.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
From: Laine Stump <laine@laine.org>
Date: Sun, 17 Mar 2013 13:32:59 +0100
Subject: New virSetUIDGID() utility function

virSetUIDGID() sets both the real and effective group and user of the
process, and additionally calls initgroups() to assure that the
process joins all the auxiliary groups that the given uid is a member
of.

---
 configure.ac    |    2 +-
 src/util/util.c |   64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/util.h |    2 ++
 3 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index cd48c1b..a075c58 100644
--- a/configure.ac
+++ b/configure.ac
@@ -93,7 +93,7 @@ AC_MSG_RESULT([$have_cpuid])
 
 
 dnl Availability of various common functions (non-fatal if missing).
-AC_CHECK_FUNCS_ONCE([cfmakeraw regexec sched_getaffinity getuid getgid \
+AC_CHECK_FUNCS_ONCE([cfmakeraw regexec sched_getaffinity getuid getgid initgroups \
  posix_fallocate mmap])
 
 dnl Availability of various not common threadsafe functions
diff --git a/src/util/util.c b/src/util/util.c
index 8f2a17e..08e6137 100644
--- a/src/util/util.c
+++ b/src/util/util.c
@@ -2748,6 +2748,61 @@ int virGetGroupID(const char *name,
     return 0;
 }
 
+
+/* Set the real and effective uid and gid to the given values, and call
+ * initgroups so that the process has all the assumed group membership of
+ * that uid. return 0 on success, -1 on failure.
+ */
+int
+virSetUIDGID(uid_t uid, gid_t gid)
+{
+    if (gid > 0) {
+        if (setregid(gid, gid) < 0) {
+            virReportSystemError(errno,
+                                 _("cannot change to '%d' group"), gid);
+            return -1;
+        }
+    }
+
+    if (uid > 0) {
+# ifdef HAVE_INITGROUPS
+        struct passwd pwd, *pwd_result;
+        char *buf = NULL;
+        size_t bufsize;
+
+        bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+        if (bufsize == -1)
+            bufsize = 16384;
+
+        if (VIR_ALLOC_N(buf, bufsize) < 0) {
+            virReportOOMError();
+            return -1;
+        }
+        getpwuid_r(uid, &pwd, buf, bufsize, &pwd_result);
+        if (!pwd_result) {
+            virReportSystemError(errno,
+                                 _("cannot getpwuid_r(%d)"), uid);
+            VIR_FREE(buf);
+            return -1;
+        }
+        if (initgroups(pwd.pw_name, pwd.pw_gid) < 0) {
+            virReportSystemError(errno,
+                                 _("cannot initgroups(\"%s\", %d)"),
+                                 pwd.pw_name, pwd.pw_gid);
+            VIR_FREE(buf);
+            return -1;
+        }
+        VIR_FREE(buf);
+# endif
+        if (setreuid(uid, uid) < 0) {
+            virReportSystemError(errno,
+                                 _("cannot change to uid to '%d'"), uid);
+            return -1;
+        }
+    }
+    return 0;
+}
+
 #else /* HAVE_GETPWUID_R */
 
 char *
@@ -2786,6 +2841,15 @@ int virGetGroupID(const char *name ATTRIBUTE_UNUSED,
 
     return 0;
 }
+
+int
+virSetUIDGID(uid_t uid ATTRIBUTE_UNUSED,
+             gid_t gid ATTRIBUTE_UNUSED)
+{
+    virUtilError(VIR_ERR_INTERNAL_ERROR,
+                 "%s", _("virSetUIDGID is not available"));
+    return -1;
+}
 #endif /* HAVE_GETPWUID_R */
 
 
diff --git a/src/util/util.h b/src/util/util.h
index 476eac4..f746cce 100644
--- a/src/util/util.h
+++ b/src/util/util.h
@@ -92,6 +92,8 @@ int virPipeReadUntilEOF(int outfd, int errfd,
                         char **outbuf, char **errbuf);
 int virFork(pid_t *pid);
 
+int virSetUIDGID(uid_t uid, gid_t gid);
+
 int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK;
 
 int virFileReadAll(const char *path, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK;