mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-31 10:05:31 +00:00
Run QEMU guests as an unprivileged user
* configure.in: Add --with-qemu-user and --with-qemu-group args * libvirt.spec.in: use 'qemu' for user/group for Fedora >= 12 * qemud/libvirtd_qemu.arg, qemud/test_libvirtd_qemu.aug, src/qemu.conf: Add 'user' and 'group' args for configuration * src/Makefile.am: Create %localstatedir/cache/libvirt/qemu * src/qemu_conf.c, src/qemu_conf.h: Load user/group from config * src/qemu_driver.c: Change user ID/group ID when launching QEMU guests. Change user/group ownership on disks/usb/pci devs. Put memory dumps in %localstatedir/cache/libvirt/qemu * src/util.c, src/util.h: Add convenient APIs for converting username/groupname to user ID / group ID
This commit is contained in:
parent
d4ad29be2a
commit
0714b2ba4c
17
configure.in
17
configure.in
@ -1437,6 +1437,19 @@ AM_CONDITIONAL([WITH_NODE_DEVICES], [test "$with_nodedev" = "yes"])
|
||||
|
||||
AM_CONDITIONAL([WITH_LINUX], [test `uname -s` = "Linux"])
|
||||
|
||||
|
||||
AC_ARG_WITH([qemu-user],
|
||||
[ --with-qemu-user username to run QEMU system instance as],
|
||||
[QEMU_USER=${withval}],
|
||||
[QEMU_USER=root])
|
||||
AC_ARG_WITH([qemu-group],
|
||||
[ --with-qemu-group groupname to run QEMU system instance as],
|
||||
[QEMU_GROUP=${withval}],
|
||||
[QEMU_GROUP=root])
|
||||
AC_DEFINE_UNQUOTED([QEMU_USER], ["$QEMU_USER"], [QEMU user account])
|
||||
AC_DEFINE_UNQUOTED([QEMU_GROUP], ["$QEMU_GROUP"], [QEMU group account])
|
||||
|
||||
|
||||
# Only COPYING.LIB is under version control, yet COPYING
|
||||
# is included as part of the distribution tarball.
|
||||
# Copy one to the other, but only if this is a srcdir-build.
|
||||
@ -1578,3 +1591,7 @@ AC_MSG_NOTICE([ Debug: $enable_debug])
|
||||
AC_MSG_NOTICE([ Warnings: $enable_compile_warnings])
|
||||
AC_MSG_NOTICE([ Readline: $lv_use_readline])
|
||||
AC_MSG_NOTICE([])
|
||||
AC_MSG_NOTICE([Privileges])
|
||||
AC_MSG_NOTICE([])
|
||||
AC_MSG_NOTICE([ QEMU: $QEMU_USER:$QEMU_GROUP])
|
||||
AC_MSG_NOTICE([])
|
@ -46,6 +46,14 @@
|
||||
%define with_capng 0%{!?_without_capng:1}
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} >= 12
|
||||
%define qemu_user qemu
|
||||
%define qemu_group qemu
|
||||
%else
|
||||
%define qemu_user root
|
||||
%define qemu_group root
|
||||
%endif
|
||||
|
||||
#
|
||||
# If building on RHEL switch on the specific support
|
||||
#
|
||||
@ -309,6 +317,8 @@ of recent versions of Linux (and other OSes).
|
||||
%{?_without_storage_iscsi} \
|
||||
%{?_without_storage_disk} \
|
||||
%{?_without_numactl} \
|
||||
--with-qemu-user=%{qemu_user} \
|
||||
--with-qemu-group=%{qemu_group} \
|
||||
--with-init-script=redhat \
|
||||
--with-remote-pid-file=%{_localstatedir}/run/libvirtd.pid
|
||||
make %{?_smp_mflags}
|
||||
@ -445,8 +455,9 @@ fi
|
||||
%dir %attr(0700, root, root) %{_localstatedir}/cache/libvirt/
|
||||
|
||||
%if %{with_qemu}
|
||||
%dir %{_localstatedir}/run/libvirt/qemu/
|
||||
%dir %attr(0700, root, root) %{_localstatedir}/lib/libvirt/qemu/
|
||||
%dir %attr(0700, %{qemu_user}, %{qemu_group}) %{_localstatedir}/run/libvirt/qemu/
|
||||
%dir %attr(0700, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/
|
||||
%dir %attr(0700, %{qemu_user}, %{qemu_group}) %{_localstatedir}/cache/libvirt/qemu/
|
||||
%endif
|
||||
%if %{with_lxc}
|
||||
%dir %{_localstatedir}/run/libvirt/lxc/
|
||||
|
@ -29,6 +29,8 @@ module Libvirtd_qemu =
|
||||
| str_entry "vnc_password"
|
||||
| bool_entry "vnc_sasl"
|
||||
| str_entry "vnc_sasl_dir"
|
||||
| str_entry "user"
|
||||
| str_entry "group"
|
||||
|
||||
(* Each enty in the config is one of the following three ... *)
|
||||
let entry = vnc_entry
|
||||
|
@ -79,6 +79,10 @@ vnc_sasl = 1
|
||||
# point to the directory, and create a qemu.conf in that location
|
||||
#
|
||||
vnc_sasl_dir = \"/some/directory/sasl2\"
|
||||
|
||||
user = \"root\"
|
||||
|
||||
group = \"root\"
|
||||
"
|
||||
|
||||
test Libvirtd_qemu.lns get conf =
|
||||
@ -161,3 +165,7 @@ vnc_sasl_dir = \"/some/directory/sasl2\"
|
||||
{ "#comment" = "point to the directory, and create a qemu.conf in that location" }
|
||||
{ "#comment" = "" }
|
||||
{ "vnc_sasl_dir" = "/some/directory/sasl2" }
|
||||
{ "#comment" = "" }
|
||||
{ "user"= "root" }
|
||||
{ "#comment" = "" }
|
||||
{ "group" = "root" }
|
@ -684,6 +684,7 @@ install-exec-local:
|
||||
if WITH_QEMU
|
||||
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/qemu"
|
||||
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/run/libvirt/qemu"
|
||||
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/cache/libvirt/qemu"
|
||||
endif
|
||||
if WITH_LXC
|
||||
$(MKDIR_P) "$(DESTDIR)$(localstatedir)/lib/libvirt/lxc"
|
||||
|
@ -378,6 +378,8 @@ virRun;
|
||||
virSkipSpaces;
|
||||
virKillProcess;
|
||||
virGetUserDirectory;
|
||||
virGetUserID;
|
||||
virGetGroupID;
|
||||
|
||||
|
||||
# uuid.h
|
||||
|
@ -88,3 +88,10 @@
|
||||
# to 'none' instead
|
||||
#
|
||||
# security_driver = "selinux"
|
||||
|
||||
|
||||
# The user ID for QEMU processes run by the system instance
|
||||
#user = "root"
|
||||
|
||||
# The group ID for QEMU processes run by the system instance
|
||||
#group = "root"
|
||||
|
@ -92,6 +92,8 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
|
||||
const char *filename) {
|
||||
virConfPtr conf;
|
||||
virConfValuePtr p;
|
||||
char *user;
|
||||
char *group;
|
||||
|
||||
/* Setup 2 critical defaults */
|
||||
if (!(driver->vncListen = strdup("127.0.0.1"))) {
|
||||
@ -186,6 +188,36 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
|
||||
}
|
||||
}
|
||||
|
||||
p = virConfGetValue (conf, "user");
|
||||
CHECK_TYPE ("user", VIR_CONF_STRING);
|
||||
if (!(user = strdup(p && p->str ? p->str : QEMU_USER))) {
|
||||
virReportOOMError(NULL);
|
||||
virConfFree(conf);
|
||||
return -1;
|
||||
}
|
||||
if (virGetUserID(NULL, user, &driver->user) < 0) {
|
||||
VIR_FREE(user);
|
||||
virConfFree(conf);
|
||||
return -1;
|
||||
}
|
||||
VIR_FREE(user);
|
||||
|
||||
p = virConfGetValue (conf, "group");
|
||||
CHECK_TYPE ("group", VIR_CONF_STRING);
|
||||
if (!(group = strdup(p && p->str ? p->str : QEMU_GROUP))) {
|
||||
virReportOOMError(NULL);
|
||||
virConfFree(conf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if (virGetGroupID(NULL, group, &driver->group) < 0) {
|
||||
VIR_FREE(group);
|
||||
virConfFree(conf);
|
||||
return -1;
|
||||
}
|
||||
VIR_FREE(group);
|
||||
|
||||
virConfFree (conf);
|
||||
return 0;
|
||||
}
|
||||
|
@ -66,6 +66,9 @@ struct qemud_driver {
|
||||
|
||||
int privileged;
|
||||
|
||||
uid_t user;
|
||||
gid_t group;
|
||||
|
||||
unsigned int qemuVersion;
|
||||
int nextvmid;
|
||||
|
||||
|
@ -71,12 +71,11 @@
|
||||
#define VIR_FROM_THIS VIR_FROM_QEMU
|
||||
|
||||
/* For storing short-lived temporary files. */
|
||||
#define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt"
|
||||
#define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt/qemu"
|
||||
|
||||
#define QEMU_CMD_PROMPT "\n(qemu) "
|
||||
#define QEMU_PASSWD_PROMPT "Password: "
|
||||
|
||||
|
||||
static int qemudShutdown(void);
|
||||
|
||||
static void qemuDriverLock(struct qemud_driver *driver)
|
||||
@ -1367,6 +1366,205 @@ static int qemudDomainSetSecurityLabel(virConnectPtr conn, struct qemud_driver *
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __linux__
|
||||
static int qemuDomainSetHostdevUSBOwnership(virConnectPtr conn,
|
||||
virDomainHostdevDefPtr def,
|
||||
uid_t uid, gid_t gid)
|
||||
{
|
||||
char *usbpath = NULL;
|
||||
|
||||
/* XXX what todo for USB devs assigned based on product/vendor ? Doom :-( */
|
||||
if (!def->source.subsys.u.usb.bus ||
|
||||
!def->source.subsys.u.usb.device)
|
||||
return 0;
|
||||
|
||||
if (virAsprintf(&usbpath, "/dev/bus/usb/%03d/%03d",
|
||||
def->source.subsys.u.usb.bus,
|
||||
def->source.subsys.u.usb.device) < 0) {
|
||||
virReportOOMError(conn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
VIR_DEBUG("Setting ownership on %s to %d:%d", usbpath, uid, gid);
|
||||
if (chown(usbpath, uid, gid) < 0) {
|
||||
virReportSystemError(conn, errno, _("cannot set ownership on %s"), usbpath);
|
||||
VIR_FREE(usbpath);
|
||||
return -1;
|
||||
}
|
||||
VIR_FREE(usbpath);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qemuDomainSetHostdevPCIOwnership(virConnectPtr conn,
|
||||
virDomainHostdevDefPtr def,
|
||||
uid_t uid, gid_t gid)
|
||||
{
|
||||
char *pcidir = NULL;
|
||||
char *file = NULL;
|
||||
DIR *dir = NULL;
|
||||
int ret = -1;
|
||||
struct dirent *ent;
|
||||
|
||||
if (virAsprintf(&pcidir, "/sys/bus/pci/devices/%04x:%02x:%02x.%x",
|
||||
def->source.subsys.u.pci.domain,
|
||||
def->source.subsys.u.pci.bus,
|
||||
def->source.subsys.u.pci.slot,
|
||||
def->source.subsys.u.pci.function) < 0) {
|
||||
virReportOOMError(conn);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(dir = opendir(pcidir))) {
|
||||
virReportSystemError(conn, errno,
|
||||
_("cannot open %s"), pcidir);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
/* QEMU device assignment requires:
|
||||
* $PCIDIR/config, $PCIDIR/resource, $PCIDIR/resourceNNN, $PCIDIR/rom
|
||||
*/
|
||||
if (STREQ(ent->d_name, "config") ||
|
||||
STRPREFIX(ent->d_name, "resource") ||
|
||||
STREQ(ent->d_name, "rom")) {
|
||||
if (virAsprintf(&file, "%s/%s", pcidir, ent->d_name) < 0) {
|
||||
virReportOOMError(conn);
|
||||
goto cleanup;
|
||||
}
|
||||
VIR_DEBUG("Setting ownership on %s to %d:%d", file, uid, gid);
|
||||
if (chown(file, uid, gid) < 0) {
|
||||
virReportSystemError(conn, errno, _("cannot set ownership on %s"), file);
|
||||
goto cleanup;
|
||||
}
|
||||
VIR_FREE(file);
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
if (dir)
|
||||
closedir(dir);
|
||||
VIR_FREE(file);
|
||||
VIR_FREE(pcidir);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int qemuDomainSetHostdevOwnership(virConnectPtr conn,
|
||||
virDomainHostdevDefPtr def,
|
||||
uid_t uid, gid_t gid)
|
||||
{
|
||||
if (def->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS)
|
||||
return 0;
|
||||
|
||||
#ifdef __linux__
|
||||
switch (def->source.subsys.type) {
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
|
||||
return qemuDomainSetHostdevUSBOwnership(conn, def, uid, gid);
|
||||
|
||||
case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
|
||||
return qemuDomainSetHostdevPCIOwnership(conn, def, uid, gid);
|
||||
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
qemudReportError(conn, NULL, NULL, "%s",
|
||||
_("unable to set host device ownership on this platform"));
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static int qemuDomainSetDiskOwnership(virConnectPtr conn,
|
||||
virDomainDiskDefPtr def,
|
||||
uid_t uid, gid_t gid)
|
||||
{
|
||||
|
||||
if (!def->src)
|
||||
return 0;
|
||||
|
||||
VIR_DEBUG("Setting ownership on %s to %d:%d", def->src, uid, gid);
|
||||
if (chown(def->src, uid, gid) < 0) {
|
||||
virReportSystemError(conn, errno, _("cannot set ownership on %s"),
|
||||
def->src);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qemuDomainSetDeviceOwnership(virConnectPtr conn,
|
||||
struct qemud_driver *driver,
|
||||
virDomainDeviceDefPtr def,
|
||||
int restore)
|
||||
{
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
if (!driver->privileged)
|
||||
return 0;
|
||||
|
||||
/* short circuit case of root:root */
|
||||
if (!driver->user && !driver->group)
|
||||
return 0;
|
||||
|
||||
uid = restore ? 0 : driver->user;
|
||||
gid = restore ? 0 : driver->group;
|
||||
|
||||
switch (def->type) {
|
||||
case VIR_DOMAIN_DEVICE_DISK:
|
||||
if (restore &&
|
||||
(def->data.disk->readonly || def->data.disk->shared))
|
||||
return 0;
|
||||
|
||||
return qemuDomainSetDiskOwnership(conn, def->data.disk, uid, gid);
|
||||
|
||||
case VIR_DOMAIN_DEVICE_HOSTDEV:
|
||||
return qemuDomainSetHostdevOwnership(conn, def->data.hostdev, uid, gid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qemuDomainSetAllDeviceOwnership(virConnectPtr conn,
|
||||
struct qemud_driver *driver,
|
||||
virDomainDefPtr def,
|
||||
int restore)
|
||||
{
|
||||
int i;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
if (!driver->privileged)
|
||||
return 0;
|
||||
|
||||
/* short circuit case of root:root */
|
||||
if (!driver->user && !driver->group)
|
||||
return 0;
|
||||
|
||||
uid = restore ? 0 : driver->user;
|
||||
gid = restore ? 0 : driver->group;
|
||||
|
||||
for (i = 0 ; i < def->ndisks ; i++) {
|
||||
if (restore &&
|
||||
(def->disks[i]->readonly || def->disks[i]->shared))
|
||||
continue;
|
||||
|
||||
if (qemuDomainSetDiskOwnership(conn, def->disks[i], uid, gid) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0 ; i < def->nhostdevs ; i++) {
|
||||
if (qemuDomainSetHostdevOwnership(conn, def->hostdevs[i], uid, gid) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
|
||||
const char *name);
|
||||
|
||||
@ -1377,14 +1575,39 @@ struct gemudHookData {
|
||||
};
|
||||
|
||||
static int qemudSecurityHook(void *data) {
|
||||
struct gemudHookData *h = (struct gemudHookData *) data;
|
||||
struct gemudHookData *h = (struct gemudHookData *) data;
|
||||
|
||||
if (qemudDomainSetSecurityLabel(h->conn, h->driver, h->vm) < 0) {
|
||||
qemudReportError(h->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||
_("Failed to set security label"));
|
||||
if (qemudDomainSetSecurityLabel(h->conn, h->driver, h->vm) < 0) {
|
||||
qemudReportError(h->conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||
_("Failed to set security label"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (h->driver->privileged) {
|
||||
DEBUG("Dropping privileges of VM to %d:%d", h->driver->user, h->driver->group);
|
||||
|
||||
if (qemuDomainSetAllDeviceOwnership(h->conn, h->driver, h->vm->def, 0) < 0)
|
||||
return -1;
|
||||
|
||||
if (h->driver->group) {
|
||||
if (setregid(h->driver->group, h->driver->group) < 0) {
|
||||
virReportSystemError(NULL, errno,
|
||||
_("cannot change to '%d' group"),
|
||||
h->driver->group);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
if (h->driver->user) {
|
||||
if (setreuid(h->driver->user, h->driver->user) < 0) {
|
||||
virReportSystemError(NULL, errno,
|
||||
_("cannot change to '%d' user"),
|
||||
h->driver->user);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1662,6 +1885,10 @@ static void qemudShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||
VIR_FREE(vm->def->seclabel.imagelabel);
|
||||
}
|
||||
|
||||
if (qemuDomainSetAllDeviceOwnership(conn, driver, vm->def, 1) < 0)
|
||||
VIR_WARN("Failed to restore all device ownership for %s",
|
||||
vm->def->name);
|
||||
|
||||
if (qemudRemoveDomainStatus(conn, driver, vm) < 0) {
|
||||
VIR_WARN(_("Failed to remove domain status for %s"),
|
||||
vm->def->name);
|
||||
@ -4329,12 +4556,20 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
|
||||
case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
|
||||
if (driver->securityDriver)
|
||||
driver->securityDriver->domainSetSecurityImageLabel(dom->conn, vm, dev->data.disk);
|
||||
|
||||
if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 0) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = qemudDomainChangeEjectableMedia(dom->conn, vm, dev);
|
||||
break;
|
||||
|
||||
case VIR_DOMAIN_DISK_DEVICE_DISK:
|
||||
if (driver->securityDriver)
|
||||
driver->securityDriver->domainSetSecurityImageLabel(dom->conn, vm, dev->data.disk);
|
||||
|
||||
if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 0) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
|
||||
ret = qemudDomainAttachUsbMassstorageDevice(dom->conn, vm, dev);
|
||||
} else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
|
||||
@ -4357,6 +4592,9 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
|
||||
} else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV &&
|
||||
dev->data.hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
|
||||
dev->data.hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB) {
|
||||
if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 0) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = qemudDomainAttachHostDevice(dom->conn, vm, dev);
|
||||
} else {
|
||||
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
||||
@ -4369,8 +4607,11 @@ static int qemudDomainAttachDevice(virDomainPtr dom,
|
||||
ret = -1;
|
||||
|
||||
cleanup:
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0)
|
||||
VIR_WARN0("Fail to restore disk device ownership");
|
||||
virDomainDeviceDefFree(dev);
|
||||
}
|
||||
if (vm)
|
||||
virDomainObjUnlock(vm);
|
||||
qemuDriverUnlock(driver);
|
||||
@ -4498,6 +4739,8 @@ static int qemudDomainDetachDevice(virDomainPtr dom,
|
||||
ret = qemudDomainDetachPciDiskDevice(dom->conn, vm, dev);
|
||||
if (driver->securityDriver)
|
||||
driver->securityDriver->domainRestoreSecurityImageLabel(dom->conn, dev->data.disk);
|
||||
if (qemuDomainSetDeviceOwnership(dom->conn, driver, dev, 1) < 0)
|
||||
VIR_WARN0("Fail to restore disk device ownership");
|
||||
}
|
||||
else
|
||||
qemudReportError(dom->conn, dom, NULL, VIR_ERR_NO_SUPPORT,
|
||||
|
75
src/util.c
75
src/util.c
@ -55,6 +55,7 @@
|
||||
#include <netdb.h>
|
||||
#ifdef HAVE_GETPWUID_R
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#endif
|
||||
#if HAVE_CAPNG
|
||||
#include <cap-ng.h>
|
||||
@ -1862,4 +1863,78 @@ char *virGetUserDirectory(virConnectPtr conn,
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int virGetUserID(virConnectPtr conn,
|
||||
const char *name,
|
||||
uid_t *uid)
|
||||
{
|
||||
char *strbuf;
|
||||
struct passwd pwbuf;
|
||||
struct passwd *pw = NULL;
|
||||
size_t strbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
|
||||
|
||||
if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
|
||||
virReportOOMError(conn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* From the manpage (terrifying but true):
|
||||
*
|
||||
* ERRORS
|
||||
* 0 or ENOENT or ESRCH or EBADF or EPERM or ...
|
||||
* The given name or uid was not found.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
*uid = pw->pw_uid;
|
||||
|
||||
VIR_FREE(strbuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int virGetGroupID(virConnectPtr conn,
|
||||
const char *name,
|
||||
gid_t *gid)
|
||||
{
|
||||
char *strbuf;
|
||||
struct group grbuf;
|
||||
struct group *gr = NULL;
|
||||
size_t strbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
|
||||
|
||||
if (VIR_ALLOC_N(strbuf, strbuflen) < 0) {
|
||||
virReportOOMError(conn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* From the manpage (terrifying but true):
|
||||
*
|
||||
* ERRORS
|
||||
* 0 or ENOENT or ESRCH or EBADF or EPERM or ...
|
||||
* The given name or uid was not found.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
*gid = gr->gr_gid;
|
||||
|
||||
VIR_FREE(strbuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -217,6 +217,12 @@ int virKillProcess(pid_t pid, int sig);
|
||||
#ifdef HAVE_GETPWUID_R
|
||||
char *virGetUserDirectory(virConnectPtr conn,
|
||||
uid_t uid);
|
||||
int virGetUserID(virConnectPtr conn,
|
||||
const char *name,
|
||||
uid_t *uid);
|
||||
int virGetGroupID(virConnectPtr conn,
|
||||
const char *name,
|
||||
gid_t *gid);
|
||||
#endif
|
||||
|
||||
int virRandomInitialize(unsigned int seed);
|
||||
|
Loading…
Reference in New Issue
Block a user