# HG changeset patch # User Cole Robinson # Date 1253738317 14400 # Node ID 53cd275974ab35a790b4c4bf1424d0950d5b095e # Parent aff98f0152935ad7cd57e86c4172a6683e6306c5 VirtualDisk: Add methods for checking/changing path perms for username. Since libvirtd can now run qemu processes as non-root, the tools need to try to check directory permissions and make sure they are at least searchable by a specific username. This simply implements the functions to make that happen. diff -r aff98f015293 -r 53cd275974ab virtinst/VirtualDisk.py --- a/virtinst/VirtualDisk.py Mon Sep 21 15:52:04 2009 -0400 +++ b/virtinst/VirtualDisk.py Wed Sep 23 16:38:37 2009 -0400 @@ -19,9 +19,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. -import os, statvfs +import os, stat, pwd, statvfs import subprocess import logging +import re + import urlgrabber.progress as progress import libvirt @@ -69,6 +71,46 @@ return fmt +def _name_uid(user): + """ + Return UID for string username + """ + pwdinfo = pwd.getpwnam(user) + return pwdinfo[2] + +def _is_dir_searchable(uid, username, path): + """ + Check if passed directory is searchable by uid + """ + try: + statinfo = os.stat(path) + except OSError: + return False + + if uid == statinfo.st_uid: + flag = stat.S_IXUSR + elif uid == statinfo.st_gid: + flag = stat.S_IXGRP + else: + flag = stat.S_IXOTH + + if bool(statinfo.st_mode & flag): + return True + + # Check POSIX ACL (since that is what we use to 'fix' access) + cmd = ["getfacl", path] + proc = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, err = proc.communicate() + + if proc.returncode != 0: + logging.debug("Cmd '%s' failed: %s" % (cmd, err)) + return False + + return bool(re.search("user:%s:..x" % username, out)) + + class VirtualDisk(VirtualDevice): """ Builds a libvirt domain disk xml description @@ -156,6 +198,63 @@ return False + @staticmethod + def check_path_search_for_user(conn, path, username): + """ + Check if the passed user has search permissions for all the + directories in the disk path. + + @return: List of the directories the user cannot search, or empty list + @rtype : C{list} + """ + if _util.is_uri_remote(conn.getURI()): + return [] + + uid = _name_uid(username) + fixlist = [] + + dirname, base = os.path.split(path) + while base: + if not _is_dir_searchable(uid, username, dirname): + fixlist.append(dirname) + + dirname, base = os.path.split(dirname) + + return fixlist + + @staticmethod + def fix_path_search_for_user(conn, path, username): + """ + Try to fix any permission problems found by check_path_search_for_user + + @return: Return a dictionary of entries { broken path : error msg } + @rtype : C{dict} + """ + fixlist = VirtualDisk.check_path_search_for_user(conn, path, username) + if not fixlist: + return [] + + fixlist.reverse() + errdict = {} + + for dirname in fixlist: + try: + cmd = ["setfacl", "--modify", "user:%s:x" % username, dirname] + proc = subprocess.Popen(cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out, err = proc.communicate() + + logging.debug("Cmd '%s' output: \nout=%s, \nerr=%s" % + (cmd, out, err)) + if proc.returncode != 0: + raise ValueError(err) + except Exception, e: + errdict[dirname] = str(e) + + return errdict + + def __init__(self, path=None, size=None, transient=False, type=None, device=DEVICE_DISK, driverName=None, driverType=None, readOnly=False, sparse=True, conn=None, volObject=None, # HG changeset patch # User Cole Robinson # Date 1253741935 14400 # Node ID a523260ac56eb90e1eda067c2bbd5fc726bb0165 # Parent 53cd275974ab35a790b4c4bf1424d0950d5b095e VirtualDisk: Teach perms changing functions about a target directory. diff -r 53cd275974ab -r a523260ac56e virtinst/VirtualDisk.py --- a/virtinst/VirtualDisk.py Wed Sep 23 16:38:37 2009 -0400 +++ b/virtinst/VirtualDisk.py Wed Sep 23 17:38:55 2009 -0400 @@ -213,7 +213,12 @@ uid = _name_uid(username) fixlist = [] - dirname, base = os.path.split(path) + if os.path.isdir(path): + dirname = path + base = "-" + else: + dirname, base = os.path.split(path) + while base: if not _is_dir_searchable(uid, username, dirname): fixlist.append(dirname) diff -r 53cd275974ab virtinst/Installer.py --- a/virtinst/Installer.py Wed Sep 23 16:38:37 2009 -0400 +++ b/virtinst/Installer.py Wed Sep 23 17:32:14 2009 -0400 @@ -141,12 +141,20 @@ return XEN_SCRATCH if os.path.exists(LIBVIRT_SCRATCH): return LIBVIRT_SCRATCH - else: - scratch = os.path.expanduser("~/.virtinst/boot") - if not os.path.exists(scratch): - os.makedirs(scratch, 0750) - _util.selinux_restorecon(scratch) - return scratch + + scratch = os.path.expanduser("~/.virtinst/boot") + if not os.path.exists(scratch): + os.makedirs(scratch, 0751) + + if (self.conn and + not _util.is_uri_remote(self.conn.getURI()) and + _util.is_qemu_system(self.conn.getURI())): + # If we are using local qemu:///system, try to make sure the + # download location is searchable by the 'qemu' user + VirtualDisk.fix_path_search_for_user(self.conn, scratch, "qemu") + + _util.selinux_restorecon(scratch) + return scratch scratchdir = property(get_scratchdir) def get_cdrom(self):