From d596c6dc9b64ca0c910a87127de72ed2ef47b692 Mon Sep 17 00:00:00 2001 From: Laine Stump Date: Thu, 23 Dec 2010 01:44:02 -0500 Subject: [PATCH] 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/libvirt_private.syms | 1 + src/util/util.c | 64 ++++++++++++++++++++++++++++++++++++++++ src/util/util.h | 2 ++ 4 files changed, 68 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 90fe145bbf..85db01f5e3 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/libvirt_private.syms b/src/libvirt_private.syms index 05c4af8ab7..a959ad92ed 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -859,6 +859,7 @@ virRun; virRunWithHook; virSetCloseExec; virSetNonBlock; +virSetUIDGID; virSkipSpaces; virStrToDouble; virStrToLong_i; diff --git a/src/util/util.c b/src/util/util.c index 7d3377b504..d6fa81b4af 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -2811,6 +2811,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 * @@ -2849,6 +2904,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 ef4fc1349d..989962f33f 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -93,6 +93,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; -- GitLab