From: ShaoHe Feng <shaohef(a)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(a)linux.vnet.ibm.com>
Signed-off-by: Aline Manera <alinefm(a)linux.vnet.ibm.com>
Signed-off-by: Royce Lv <lvroyce(a)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