[PATCH V8] add a method to fix search permissions

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> V6 -> V7 do not fix path search permission for others. also fix read permission for file. ShaoHe Feng (1): add a method to fix search permissions src/kimchi/utils.py | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) -- 1.8.4.2

From: ShaoHe Feng <shaohef@linux.vnet.ibm.com> If the user of path is the same user of "qemu-kvm", then set the fix the permission directly. Or just use setfacl to set the path search permission just for "qemu-kvm" user. We do not fix the permission for others. Usage: check_path_permission("/tmp/need/to/fix/path", username) fix_path_permission("/tmp/need/to/fix/path", username) test: $ mkdir -p a/b/c $ echo "test" > a/b/c/f $ sudo chmod a-xr -R a/b/c/f $ sudo PYTHONPATH=./src python -c ' from kimchi.utils import * path = "a/b/c/f" print check_path_permission(path, "qemu") ' $ sudo PYTHONPATH=./src python -c ' from kimchi.utils import * path = "a/b/c/f" print fix_path_permission(path, "qemu") ' $ cat a/b/c/f Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> Signed-off-by: Aline Manera <alinefm@linux.vnet.ibm.com> Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/utils.py | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py index 0e66214..39a6cf6 100644 --- a/src/kimchi/utils.py +++ b/src/kimchi/utils.py @@ -22,7 +22,11 @@ # import cherrypy +import grp import os +import pwd +import re +import stat import subprocess import urllib2 @@ -179,3 +183,148 @@ def patch_find_nfs_target(nfs_server): target['type'] = 'nfs' target['host_name'] = nfs_server return targets + + +def name_uid(user): + return pwd.getpwnam(user).pw_uid + + +def get_group_ids(user): + gids = [g.gr_gid for g in grp.getgrall() if user in g.gr_mem] + gid = pwd.getpwnam(user).pw_gid + gids.append(grp.getgrgid(gid).gr_gid) + return gids + + +def get_groups(user): + gids = get_group_ids(user) + return [grp.getgrgid(gid).gr_name for gid in gids] + + +def run_setfacl_set_attr(path, attr="x", user="qemu"): + set_user = ["setfacl", "--modify", "user:%s:%s" % (user, attr), path] + out, error, ret = run_command(set_user) + return ret == 0 + + +def run_getfacl(path, attr="x", user="qemu", groups=[]): + attr = "".join(map(lambda x, y: x if y else ".", ["r", "w", "x"], + [b in attr for b in ["r", "w", "x"]])) + cmd = ["getfacl", path] + out, error, ret = run_command(cmd) + if out and ret == 0: + res = re.findall("user:%s:%s" % (user, attr), out) + if res: + return True + res = re.findall("(?<=group:)(.*)(?=:%s)" % attr, + out) if groups else [] + return list(set(res) & set(groups)) != [] + return False + + +def set_x_on_path(path, who="other"): + S_IXWHO = ((stat.S_IXUSR if who == "user" else None) or + (stat.S_IXGRP if who == "group" else None) or + (stat.S_IXOTH if who == "other" else None)) + + if S_IXWHO is None: + return False + mode = os.stat(path).st_mode | S_IXWHO + os.chmod(path, mode) + ret = os.stat(path).st_mode == mode + if not ret: + kimchi_log.debug("faild to set +x attribute on %s", path) + return ret + + +def set_r_on_path(path, who="other"): + S_IXWHO = ((stat.S_IRUSR if who == "user" else None) or + (stat.S_IRGRP if who == "group" else None) or + (stat.S_IROTH if who == "other" else None)) + + if S_IXWHO is None: + return False + mode = os.stat(path).st_mode | S_IXWHO + os.chmod(path, mode) + ret = os.stat(path).st_mode == mode + if not ret: + kimchi_log.debug("faild to set +x attribute on %s", path) + return ret + + +def get_x_on_path(path, uid, gids=[]): + try: + st = os.stat(path) + mode = st.st_mode + return ((uid == st.st_uid and mode & stat.S_IXUSR == stat.S_IXUSR) or + (st.st_gid in gids and mode & stat.S_IXGRP == stat.S_IXGRP) or + mode & stat.S_IXOTH == stat.S_IXOTH) + except OSError as e: + kimchi_log.error("faild to get x attribute on %s as user id: %s. %s", + path, uid, e.message) + return False + + +def get_r_on_path(path, uid, gids=[]): + try: + st = os.stat(path) + mode = st.st_mode + return ((uid == st.st_uid and mode & stat.S_IRUSR == stat.S_IRUSR) or + (st.st_gid in gids and mode & stat.S_IRGRP == stat.S_IRGRP) or + mode & stat.S_IROTH == stat.S_IROTH) + except OSError as e: + kimchi_log.error("faild to get r attribute on %s as user id: %s. %s", + path, uid, e.message) + return False + + +def check_path_permission(path, user='qemu', groups=[]): + f = path if os.path.isfile(path) else None + groups = groups if groups else get_groups(user) + gids = [grp.getgrnam(group).gr_gid for group in groups] if groups else [] + uid = name_uid(user) + path = os.path.abspath(path) + path = os.path.dirname(path) if f else path + paths = path.split("/") + paths = paths[1:] + path = "/" + for p in paths: + path = os.path.join(path, p) + if not (get_x_on_path(path, uid, gids) or + run_getfacl(path, 'x', user, groups)): + return False + + return (f is not None and + (get_r_on_path(f, uid, gids) or + run_getfacl(f, 'r', user, groups)) or + False) + + +def fix_path_permission(path, user='qemu', groups=[]): + f = path if os.path.isfile(path) else None + groups = groups if groups else get_groups(user) + gids = [grp.getgrnam(group).gr_gid for group in groups] if groups else [] + uid = name_uid(user) + path = os.path.abspath(path) + path = os.path.dirname(path) if f else path + paths = path.split("/") + paths = paths[1:] + path = "/" + for p in paths: + path = os.path.join(path, p) + st = os.stat(path) + who = 'user' if st.st_uid == uid else None + if not (get_x_on_path(path, uid, gids) or + run_getfacl(path, 'x', user, groups) or + set_x_on_path(path, who) or + run_setfacl_set_attr(path, 'x', user)): + return False + + st = os.stat(f) + who = 'user' if st.st_uid == uid else None + return (f is not None and + (get_r_on_path(f, uid, gids) or + run_getfacl(f, 'r', user, groups) or + set_r_on_path(f, who) or + run_setfacl_set_attr(f, 'r', user)) or + False) -- 1.8.4.2

On 01/28/2014 12:37 PM, shaohef@linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef@linux.vnet.ibm.com>
If the user of path is the same user of "qemu-kvm", then set the fix the permission directly.
Or just use setfacl to set the path search permission just for "qemu-kvm" user.
We do not fix the permission for others.
Usage: check_path_permission("/tmp/need/to/fix/path", username) fix_path_permission("/tmp/need/to/fix/path", username)
test: $ mkdir -p a/b/c $ echo "test" > a/b/c/f $ sudo chmod a-xr -R a/b/c/f
$ sudo PYTHONPATH=./src python -c ' from kimchi.utils import * path = "a/b/c/f" print check_path_permission(path, "qemu") '
$ sudo PYTHONPATH=./src python -c ' from kimchi.utils import * path = "a/b/c/f" print fix_path_permission(path, "qemu") '
$ cat a/b/c/f
Signed-off-by: ShaoHe Feng <shaohef@linux.vnet.ibm.com> Signed-off-by: Aline Manera <alinefm@linux.vnet.ibm.com> Signed-off-by: Royce Lv <lvroyce@linux.vnet.ibm.com> --- src/kimchi/utils.py | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+)
diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py index 0e66214..39a6cf6 100644 --- a/src/kimchi/utils.py +++ b/src/kimchi/utils.py @@ -22,7 +22,11 @@ #
import cherrypy +import grp import os +import pwd +import re +import stat import subprocess import urllib2
@@ -179,3 +183,148 @@ def patch_find_nfs_target(nfs_server): target['type'] = 'nfs' target['host_name'] = nfs_server return targets + + +def name_uid(user): + return pwd.getpwnam(user).pw_uid + + +def get_group_ids(user): + gids = [g.gr_gid for g in grp.getgrall() if user in g.gr_mem] + gid = pwd.getpwnam(user).pw_gid + gids.append(grp.getgrgid(gid).gr_gid) + return gids + + +def get_groups(user): + gids = get_group_ids(user) + return [grp.getgrgid(gid).gr_name for gid in gids] + + +def run_setfacl_set_attr(path, attr="x", user="qemu"): + set_user = ["setfacl", "--modify", "user:%s:%s" % (user, attr), path] + out, error, ret = run_command(set_user) + return ret == 0 + + +def run_getfacl(path, attr="x", user="qemu", groups=[]): + attr = "".join(map(lambda x, y: x if y else ".", ["r", "w", "x"], + [b in attr for b in ["r", "w", "x"]])) + cmd = ["getfacl", path] + out, error, ret = run_command(cmd) + if out and ret == 0: + res = re.findall("user:%s:%s" % (user, attr), out) + if res: + return True + res = re.findall("(?<=group:)(.*)(?=:%s)" % attr, + out) if groups else [] + return list(set(res) & set(groups)) != [] + return False + +
+def set_x_on_path(path, who="other"): + S_IXWHO = ((stat.S_IXUSR if who == "user" else None) or + (stat.S_IXGRP if who == "group" else None) or + (stat.S_IXOTH if who == "other" else None)) + + if S_IXWHO is None: + return False + mode = os.stat(path).st_mode | S_IXWHO + os.chmod(path, mode) + ret = os.stat(path).st_mode == mode + if not ret: + kimchi_log.debug("faild to set +x attribute on %s", path) + return ret +
I think we don't need it. The ISO image will be only read.
+ +def set_r_on_path(path, who="other"): + S_IXWHO = ((stat.S_IRUSR if who == "user" else None) or + (stat.S_IRGRP if who == "group" else None) or + (stat.S_IROTH if who == "other" else None)) + + if S_IXWHO is None: + return False + mode = os.stat(path).st_mode | S_IXWHO + os.chmod(path, mode) + ret = os.stat(path).st_mode == mode + if not ret: + kimchi_log.debug("faild to set +x attribute on %s", path) + return ret + + +def get_x_on_path(path, uid, gids=[]): + try: + st = os.stat(path) + mode = st.st_mode + return ((uid == st.st_uid and mode & stat.S_IXUSR == stat.S_IXUSR) or + (st.st_gid in gids and mode & stat.S_IXGRP == stat.S_IXGRP) or + mode & stat.S_IXOTH == stat.S_IXOTH) + except OSError as e: + kimchi_log.error("faild to get x attribute on %s as user id: %s. %s", + path, uid, e.message) + return False + + +def get_r_on_path(path, uid, gids=[]): + try: + st = os.stat(path) + mode = st.st_mode + return ((uid == st.st_uid and mode & stat.S_IRUSR == stat.S_IRUSR) or + (st.st_gid in gids and mode & stat.S_IRGRP == stat.S_IRGRP) or + mode & stat.S_IROTH == stat.S_IROTH) + except OSError as e: + kimchi_log.error("faild to get r attribute on %s as user id: %s. %s", + path, uid, e.message) + return False + + +def check_path_permission(path, user='qemu', groups=[]): + f = path if os.path.isfile(path) else None + groups = groups if groups else get_groups(user) + gids = [grp.getgrnam(group).gr_gid for group in groups] if groups else [] + uid = name_uid(user) + path = os.path.abspath(path) + path = os.path.dirname(path) if f else path + paths = path.split("/") + paths = paths[1:] + path = "/"
+ for p in paths: + path = os.path.join(path, p) + if not (get_x_on_path(path, uid, gids) or + run_getfacl(path, 'x', user, groups)): + return False +
I don't think we need to check x permission
+ return (f is not None and + (get_r_on_path(f, uid, gids) or + run_getfacl(f, 'r', user, groups)) or + False) + + +def fix_path_permission(path, user='qemu', groups=[]): + f = path if os.path.isfile(path) else None + groups = groups if groups else get_groups(user) + gids = [grp.getgrnam(group).gr_gid for group in groups] if groups else [] + uid = name_uid(user) + path = os.path.abspath(path) + path = os.path.dirname(path) if f else path + paths = path.split("/") + paths = paths[1:] + path = "/" + for p in paths: + path = os.path.join(path, p) + st = os.stat(path) + who = 'user' if st.st_uid == uid else None + if not (get_x_on_path(path, uid, gids) or + run_getfacl(path, 'x', user, groups) or + set_x_on_path(path, who) or + run_setfacl_set_attr(path, 'x', user)): + return False + + st = os.stat(f) + who = 'user' if st.st_uid == uid else None + return (f is not None and + (get_r_on_path(f, uid, gids) or + run_getfacl(f, 'r', user, groups) or + set_r_on_path(f, who) or + run_setfacl_set_attr(f, 'r', user)) or + False)
participants (2)
-
Aline Manera
-
shaohef@linux.vnet.ibm.com