<html>
<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<div class="moz-cite-prefix">On 12/24/2013 05:46 AM,
<a class="moz-txt-link-abbreviated" href="mailto:shaohef@linux.vnet.ibm.com">shaohef@linux.vnet.ibm.com</a> wrote:<br>
</div>
<blockquote
cite="mid:1387871191-9294-4-git-send-email-shaohef@linux.vnet.ibm.com"
type="cite">
<pre wrap="">From: ShaoHe Feng <a class="moz-txt-link-rfc2396E" href="mailto:shaohef@linux.vnet.ibm.com"><shaohef@linux.vnet.ibm.com></a>
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 <a class="moz-txt-link-rfc2396E" href="mailto:shaohef@linux.vnet.ibm.com"><shaohef@linux.vnet.ibm.com></a>
Signed-off-by: Royce Lv <a class="moz-txt-link-rfc2396E" href="mailto:lvroyce@linux.vnet.ibm.com"><lvroyce@linux.vnet.ibm.com></a>
---
src/kimchi/utils.py | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 115 insertions(+), 1 deletion(-)
diff --git a/src/kimchi/utils.py b/src/kimchi/utils.py
index bf2a760..e94aeb1 100644
--- a/src/kimchi/utils.py
+++ b/src/kimchi/utils.py
@@ -18,11 +18,15 @@
#
# 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 os
+import pwd
+import re
+import stat
+import subprocess
from cherrypy.lib.reprconf import Parser
@@ -33,6 +37,7 @@ from kimchi import config
kimchi_log = cherrypy.log.error_log
+
def is_digit(value):
if isinstance(value, int):
return True
@@ -130,3 +135,112 @@ class RollbackContext(object):
def prependDefer(self, func, *args, **kwargs):
self._finally.insert(0, (func, args, kwargs))
+
+
+def name_uid(user):
+ return pwd.getpwnam(user).pw_uid
+
+
+def run_command(cmd):
+ try:
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out, error = proc.communicate()
+
+ 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:</pre>
</blockquote>
<br>
From subprocess.Popen documentation a ValueError exception can also
be raised<br>
<br>
A <a class="reference internal"
href="http://docs.python.org/2/library/exceptions.html#exceptions.ValueError"
title="exceptions.ValueError"><tt class="xref py py-exc docutils
literal"><span class="pre">ValueError</span></tt></a> will be
raised if <a class="reference internal"
href="http://docs.python.org/2/library/subprocess.html#subprocess.Popen"
title="subprocess.Popen"><tt class="xref py py-class docutils
literal"><span class="pre">Popen</span></tt></a> is called with
invalid
arguments.<br>
<br>
<blockquote
cite="mid:1387871191-9294-4-git-send-email-shaohef@linux.vnet.ibm.com"
type="cite">
<pre wrap="">
+ kimchi_log.debug("Failed to run command %s", " ".join(cmd))
+ return (None, None, None)
+ if proc.returncode != 0:
+ kimchi_log.debug("Cmd '%s' failed, error code: %s", cmd, error)
+ return (out, error, proc.returncode)
+
+
+def run_setfacl_set_x(path, user="qemu", group=None):</pre>
</blockquote>
<br>
From my system I have:<br>
<br>
alinefm@alinefm:~/kimchi$ getfacl /home/alinefm/kimchi<br>
getfacl: Removing leading '/' from absolute path names<br>
# file: home/alinefm/kimchi<br>
# owner: alinefm<br>
# group: alinefm<br>
user::rwx<br>
group::r-x<br>
other::r-x<br>
<br>
So I think the default value for 'group' parameter should be '' (an
empty string)<br>
<br>
Otherwise we will set<br>
<br>
group:None:x<br>
<br>
<blockquote
cite="mid:1387871191-9294-4-git-send-email-shaohef@linux.vnet.ibm.com"
type="cite">
<pre wrap="">
+ set_user = ["setfacl", "--modify", "user:%s:x" % user, path]
+ set_group = ["setfacl", "--modify", "group:%s:x" % group, path]
+ out, error, ret = run_command(set_user)
+ if ret != 0 and group:
+ out, error, ret = run_command(set_group)
+ return ret == 0
+
+
+def run_getfacl(path, user="qemu", group=None):</pre>
</blockquote>
<br>
Same as I commented above about default value for 'group' parameter<br>
<br>
<blockquote
cite="mid:1387871191-9294-4-git-send-email-shaohef@linux.vnet.ibm.com"
type="cite">
<pre wrap="">
+ cmd = ["getfacl", path]
+ out, error, ret = run_command(cmd)
+ if out and ret == 0:
+ res = re.findall("user:%s:..x" % user, out)</pre>
</blockquote>
<br>
<blockquote
cite="mid:1387871191-9294-4-git-send-email-shaohef@linux.vnet.ibm.com"
type="cite">
<pre wrap="">
+ res = re.findall("group:%s:..x" % group,
+ out) if group and not res else res</pre>
</blockquote>
<br>
Please, do it in a common if statement (it is easier to ready)<br>
<br>
<blockquote
cite="mid:1387871191-9294-4-git-send-email-shaohef@linux.vnet.ibm.com"
type="cite">
<pre wrap="">
+ return res != []
+ 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):
+ try:
+ info = os.stat(path)
+ mode = info.st_mode
+ return ((uid == info.st_uid and mode & stat.S_IXUSR == stat.S_IXUSR) or
+ (uid == info.st_gid and mode & stat.S_IXGRP == stat.S_IXGRP) or
+ mode & stat.S_IXGRP == stat.S_IXOTH)
+ except OSError:
+ kimchi_log.debug("faild to get attribute on %s as user id: %s",
+ path, uid)
+ return False
+
+
+def check_path_permission(path, user='qemu', group=None):
+ return get_x_on_path(path,
+ name_uid(user)) or run_getfacl(path, user, group)
+
+
+def fix_path_permission(path, user='qemu'):
+ paths = []
+ while path:
+ paths.append(path)
+ if path == "/":
+ break
+ path = os.path.dirname(path)
+
+ paths.reverse()
+ for path in paths:
+ if not (check_path_permission(path) or
+ run_setfacl_set_x(path) or
+ set_x_on_path(path)):
+ return False</pre>
</blockquote>
<br>
We can do it in a single for <br>
<br>
# get all paths relates to 'path'<br>
paths = path.split("/")<br>
<br>
# remove /<br>
paths = paths[1:]<br>
<br>
path = "/"<br>
for p in paths:<br>
path = os.path.join(path, p)<br>
if not (check_path_permission(path) or<br>
run_setfacl_set_x(path) or<br>
set_x_on_path(path))<br>
return False
<br>
<br>
<blockquote
cite="mid:1387871191-9294-4-git-send-email-shaohef@linux.vnet.ibm.com"
type="cite">
<pre wrap="">
+ return True
+
+
+def check_path_acl_permission(path, user='qemu', group=None):
+ return run_getfacl(path, user, group)
+
+</pre>
</blockquote>
<br>
<blockquote
cite="mid:1387871191-9294-4-git-send-email-shaohef@linux.vnet.ibm.com"
type="cite">
<pre wrap="">
+def fix_path_acl_permission(path, user='qemu'):
+ paths = []
+ while path:
+ paths.append(path)
+ if path == "/":
+ break
+ path = os.path.dirname(path)
+
+ paths.reverse()
+ for path in paths:
+ if not (run_getfacl(path, user) or run_setfacl_set_x(path, user)):
+ kimchi_log.debug("faild to set on researchable permission on %s "
+ "for user: %s", path, user)
+ return False</pre>
</blockquote>
<br>
As I commented above, we can do it in a single for statement.<br>
<br>
<blockquote
cite="mid:1387871191-9294-4-git-send-email-shaohef@linux.vnet.ibm.com"
type="cite">
<pre wrap="">
+ return True
</pre>
</blockquote>
<br>
All functions related to file permission could be moved to
filepermission.py<br>
<br>
</body>
</html>