On 2014年01月09日 08:01, shaohef(a)linux.vnet.ibm.com wrote:
From: ShaoHe Feng <shaohef(a)linux.vnet.ibm.com>
First will use setfacl to set the path search permission for user or
group, if failed then set search permission for others on the path.
Usage:
check_path_permission("/tmp/need/to/fix/path", username)
fix_path_permission("/tmp/need/to/fix/path", username)
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>
---
Makefile.am | 1 +
src/kimchi/utils.py | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 122 insertions(+), 1 deletion(-)
diff --git a/Makefile.am b/Makefile.am
index 04ad696..1f80e5f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -46,6 +46,7 @@ PEP8_WHITELIST = \
src/kimchi/cachebust.py \
src/kimchi/config.py.in \
src/kimchi/control/*.py \
+ src/kimchi/utils.py \
src/kimchi/disks.py \
src/kimchi/distroloader.py \
src/kimchi/exception.py \
diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py
index af245c6..62a412d 100644
--- a/src/kimchi/utils.py
+++ b/src/kimchi/utils.py
@@ -18,11 +18,16 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
import cherrypy
+import grp
import os
+import pwd
+import re
+import stat
+import subprocess
import urllib2
@@ -34,6 +39,7 @@ from kimchi import config
kimchi_log = cherrypy.log.error_log
+
def is_digit(value):
if isinstance(value, int):
return True
@@ -96,3 +102,117 @@ def check_url_path(path):
return False
return True
+
+
+def run_command(cmd):
+ try:
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out, error = proc.communicate()
As this command will be used at multiple
cases, we may not want to wait
the execute result, do you think it's reasonable to add a timeout here?
+
+ kimchi_log.debug("Run command '%s'", " ".join(cmd))
+ if out or error:
+ kimchi_log.debug("out:\n %s\nerror:\n %s", out, error)
+ except OSError as e:
+ kimchi_log.error("Failed to run command %s. %s", "
".join(cmd),
+ e.message)
+ return (None, None, None)
I think according to
http://docs.python.org/3.3/library/subprocess.html#exceptions:
Multiple exceptions will be raised and just except OSError may leak others.
What about except all?
+ if proc.returncode != 0:
+ kimchi_log.debug("Cmd '%s' failed, error code: %s", cmd,
error)
+ return (out, error, proc.returncode)
+
+
+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_x(path, user="qemu"):
+ set_user = ["setfacl", "--modify", "user:%s:x" % user,
path]
+ out, error, ret = run_command(set_user)
+ return ret == 0
+
+
+def run_getfacl(path, user="qemu", groups=[]):
+ cmd = ["getfacl", path]
+ out, error, ret = run_command(cmd)
+ if out and ret == 0:
+ res = re.findall("user:%s:..x" % user, out)
+ if res:
+ return True
+ res = re.findall("(?<=group:)(.*)(?=:..x)",
+ 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)
+ 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 attribute on %s as user id: %s. %s",
+ path, uid, e.message)
+ return False
+
+
+def check_path_permission(path, user='qemu', groups=[]):
+ groups = groups if groups else get_groups(user)
+ gids = [grp.getgrnam(group).gr_gid for group in groups] if groups else []
+ path = os.path.abspath(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, name_uid(user), gids) or
+ run_getfacl(path, user, groups)):
+ return False
+ return True
+
+
+def fix_path_permission(path, user='qemu', groups=[]):
+ groups = groups if groups else get_groups(user)
+ gids = [grp.getgrnam(group).gr_gid for group in groups] if groups else []
+ path = os.path.abspath(path)
+ paths = path.split("/")
+ paths = paths[1:]
+ path = "/"
+ for p in paths:
+ path = os.path.join(path, p)
+ st = os.stat(path)
+ uid = name_uid(user)
+ who = 'user' if st.st_uid == uid else None
+ who = 'group' if not who and st.st_gid in gids else 'other'
+ if not (get_x_on_path(path, uid, gids) or
+ run_getfacl(path, user, groups) or
+ run_setfacl_set_x(path, user) or
+ set_x_on_path(path, who)):
+ return False
+ return True