#+
# Copyright 2011 iXsystems, Inc.
# All rights reserved
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted providing that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
#####################################################################
from freenasUI.common.acl import *
#
# getfacl POSIX flags
#
GETFACL_POSIX_FLAGS_DEFALT = 0x0001
GETFACL_POSIX_FLAGS_SYMLINK_ACL = 0x0002
SETFACL_POSIX_FLAGS_NO_COMMENTS = 0x0004
#
# setfacl POSIX flags
#
SETFACL_POSIX_FLAGS_SET_DEFAULTS = 0x0001
SETFACL_POSIX_FLAGS_APPLY_DEFAULT = 0x0002
SETFACL_POSIX_FLAGS_SYMLINK_OP = 0x0004
SETFACL_POSIX_FLAGS_DELETE_DEFAULTS = 0x0008
SETFACL_POSIX_FLAGS_MODIFY = 0x0010
SETFACL_POSIX_FLAGS_NO_RECALCULATE = 0x0020
SETFACL_POSIX_FLAGS_REMOVE_ENTRY = 0x0040
class POSIX_ACL_Exception(Base_ACL_Exception):
pass
class POSIX_pipe(Base_ACL_pipe):
pass
class POSIX_getfacl(Base_ACL_getfacl):
def _build_args(self, path, flags):
syslog(LOG_DEBUG, "POSIX_getfacl._build_args: enter")
syslog(LOG_DEBUG, "POSIX_getfacl._build_args: path = %s, flags = 0x%08x" %
(path, flags))
args = ""
if flags & GETFACL_POSIX_FLAGS_DEFALT:
args += "-d "
if flags & GETFACL_POSIX_FLAGS_SYMLINK_ACL:
args += "-h "
if flags & SETFACL_POSIX_FLAGS_NO_COMMENTS:
args += "-q "
syslog(LOG_DEBUG, "POSIX_getfacl._build_args: enter")
return args
class POSIX_setfacl(Base_ACL_setfacl):
def _build_args(self, path, entry, flags, pos):
syslog(LOG_DEBUG, "POSIX_setfacl._build_args: enter")
syslog(LOG_DEBUG, "POSIX_setfacl._build_args: path = %s, entry = %s, flags = 0x%08x, pos = %d" %
(path, entry, flags, pos))
args = ""
if flags & SETFACL_POSIX_FLAGS_SET_DEFAULTS:
args += "-b "
if flags & SETFACL_POSIX_FLAGS_APPLY_DEFAULT:
args += "-d "
if flags & SETFACL_POSIX_FLAGS_SYMLINK_OP:
args += "-h "
if flags & SETFACL_POSIX_FLAGS_DELETE_DEFAULTS:
args += "-k "
if flags & SETFACL_POSIX_FLAGS_MODIFY:
args += "-m "
if flags & SETFACL_POSIX_FLAGS_NO_RECALCULATE:
args += "-n "
if flags & SETFACL_POSIX_FLAGS_REMOVE_ENTRY:
args += "-x %d" % pos
syslog(LOG_DEBUG, "POSIX_setfacl._build_args: enter")
return args
class POSIX_ACL_Entry(Base_ACL_Entry):
def __init__(self):
syslog(LOG_DEBUG, "POSIX_ACL_Entry.__init__: enter")
#
# ACL tag
#
self.tag = None
#
# ACL qualifier
#
self.qualifier = None
#
# Access Permissions
#
self.read = False
self.write = False
self.execute = False
syslog(LOG_DEBUG, "POSIX_ACL_Entry.__init__: leave")
def __set_access_permission(self, permission, value):
syslog(LOG_DEBUG, "POSIX_ACL_Entry.__set_access_permission: enter")
syslog(LOG_DEBUG, "POSIX_ACL_Entry.__set_access_permission: permission = %s, value = %s" %
(permission, value))
if permission == 'r':
self.read = value
elif permission == 'w':
self.write = value
elif permission == 'x':
self.execute = value
syslog(LOG_DEBUG, "POSIX_ACL_Entry.__set_access_permission: enter")
def set_access_permissions(self, permissions):
syslog(LOG_DEBUG, "POSIX_ACL_Entry.set_access_permissions: enter")
syslog(LOG_DEBUG, "POSIX_ACL_Entry.set_access_permissions: permissions = %s" % permissions)
flag = True
for p in permissions:
if p == '+':
flag = True
continue
elif p == '-':
flag = False
continue
self.__set_access_permission(p, flag)
syslog(LOG_DEBUG, "POSIX_ACL_Entry.set_access_permissions: leave")
def set_access_permission(self, permission):
syslog(LOG_DEBUG, "POSIX_ACL_Entry.set_access_permission: enter")
syslog(LOG_DEBUG, "POSIX_ACL_Entry.set_access_permission: permission = %s" % permission)
self.__set_access_permission(permission, True)
syslog(LOG_DEBUG, "POSIX_ACL_Entry.set_access_permission: leave")
def clear_access_permissions(self):
syslog(LOG_DEBUG, "POSIX_ACL_Entry.clear_access_permissions: enter")
self.read = False
self.write = False
self.execute = False
syslog(LOG_DEBUG, "POSIX_ACL_Entry.clear_access_permissions: leave")
def clear_access_permission(self, permission):
syslog(LOG_DEBUG, "POSIX_ACL_Entry.clear_access_permission: enter")
syslog(LOG_DEBUG, "POSIX_ACL_Entry.clear_access_permission: permission = %s" % permission)
self.__set_access_permission(permission, False)
syslog(LOG_DEBUG, "POSIX_ACL_Entry.clear_access_permission: leave")
def get_access_permissions(self):
str = ""
str = str + ('r' if self.read else '-')
str = str + ('w' if self.write else '-')
str = str + ('x' if self.execute else '-')
return str
def __str__(self):
str = self.tag
str += ":"
if self.qualifier:
str += self.qualifier
str += ":"
str += self.get_access_permissions()
return str
class POSIX_ACL(Base_ACL):
def _load(self):
syslog(LOG_DEBUG, "POSIX_ACL._load: enter")
for line in POSIX_getfacl(self.path):
syslog(LOG_DEBUG, "POSIX_ACL._load: line = %s" % line)
if line.startswith("#"):
comment_parts = line.split('#')[1:]
for c in comment_parts:
c = c.strip()
parts = c.split(":")
if parts[0] == 'file':
self.file = parts[1]
elif parts[0] == 'owner':
self.owner = parts[1]
elif parts[0] == 'group':
self.group = parts[1]
else:
line = line.strip()
parts = line.split(':')
entry = POSIX_ACL_Entry()
entry.tag = parts[0]
if parts[1]:
entry.qualifier = parts[1]
for a in parts[2]:
if a != '-':
entry.set_access_permission(a)
self.entries.append(entry)
syslog(LOG_DEBUG, "POSIX_ACL._load: enter")
def update(self, tag, qualifier, permissions):
syslog(LOG_DEBUG, "POSIX_ACL.update: enter")
syslog(LOG_DEBUG, "POSIX_ACL.update: tag = %s, qualifier = %s, permissions = %s," %
(tag, (qualifier if qualifier else ""), (permissions if permissions else "")))
for entry in self.entries:
if entry.tag == tag and entry.qualifier == qualifier:
if permissions:
entry.set_access_permissions(permissions)
self.dirty = True
break
if self.dirty:
POSIX_setfacl(self.path, entry, SETFACL_POSIX_FLAGS_MODIFY)
self._refresh()
syslog(LOG_DEBUG, "POSIX_ACL.update: leave")
def add(self, tag, qualifier = None, permissions = None):
syslog(LOG_DEBUG, "POSIX_ACL.add: enter")
syslog(LOG_DEBUG, "POSIX_ACL.add: tag = %s, qualifier = %s, permissions = %s, " %
(tag, qualifier if qualifier else "", permissions if permissions else ""))
entry = POSIX_ACL_Entry()
entry.tag = tag
if qualifier:
entry.qualifier = qualifier
if permissions:
entry.set_access_permissions(permissions)
self.entries.append(entry)
self.dirty = True
POSIX_setfacl(self.path, entry, SETFACL_POSIX_FLAGS_MODIFY)
self._refresh()
syslog(LOG_DEBUG, "POSIX_ACL.add: leave")
def get(self, tag = None, qualifier = None):
syslog(LOG_DEBUG, "POSIX_ACL.get: enter")
syslog(LOG_DEBUG, "POSIX_ACL.get: tag = %s, qualifier = %s" %
((tag if tag else ""), (qualifier if qualifier else "")))
entries = []
for entry in self.entries:
if tag and entry.tag == tag:
if qualifier == None or qualifier == entry.qualifier:
entries.append(entry)
elif not tag:
entries.append(entry)
syslog(LOG_DEBUG, "POSIX_ACL.get: leave")
return entries
def remove(self, tag, qualifier = None, pos = None):
syslog(LOG_DEBUG, "POSIX_ACL.remove: enter")
syslog(LOG_DEBUG, "POSIX_ACL.remove: tag = %s, qualifier = %s, pos = %s" %
((tag if tag else ""), (qualifier if qualifier else ""), (str(pos) if pos else "None")))
n = 0
entries = []
entry = None
for entry in self.entries:
if entry.tag == tag and entry.qualifier == qualifier and pos == pos:
POSIX_setfacl(self.path, entry, SETFACL_POSIX_FLAGS_REMOVE_ENTRY, n)
self.dirty = True
n += 1
if pos == -1 and entry:
POSIX_setfacl(self.path, entry, SETFACL_POSIX_FLAGS_REMOVE_ENTRY, (n - 1) if n > 0 else n)
self.dirty = True
self._refresh()
syslog(LOG_DEBUG, "POSIX_ACL.remove: leave")
def reset(self):
syslog(LOG_DEBUG, "POSIX_ACL.reset: enter")
POSIX_setfacl(self.path, None, SETFACL_POSIX_FLAGS_SET_DEFAULTS)
self._refresh()
syslog(LOG_DEBUG, "POSIX_ACL.reset: leave")
def chmod(self, mode):
syslog(LOG_DEBUG, "POSIX_ACL.chmod: enter")
syslog(LOG_DEBUG, "POSIX_ACL.chmod: mode = %s" % mode)
length = len(mode)
if length == 4:
mode = mode[1:]
pos = 0
acl = ['user', 'group', 'other']
mask = None
for c in mode:
n = int(c)
tag = acl[pos]
permissions = ""
permissions = ((permissions + "+r") if (n & 4) else (permissions + "-r"))
permissions = ((permissions + "+w") if (n & 2) else (permissions + "-w"))
permissions = ((permissions + "+x") if (n & 1) else (permissions + "-x"))
if permissions:
self.update(tag, None, permissions)
if tag == 'group':
mask = permissions
pos += 1
if mask:
self.update('mask', None, mask)
syslog(LOG_DEBUG, "POSIX_ACL.chmod: leave")
class POSIX_ACL_Hierarchy(Base_ACL_Hierarchy):
def _set_windows_file_defaults(self, acl):
pass
def _set_windows_directory_defaults(self, acl):
pass
def _set_unix_file_defaults(self, acl):
syslog(LOG_DEBUG, "POSIX_ACL_Hierarchy._set_unix_file_defaults: enter")
syslog(LOG_DEBUG, "POSIX_ACL_Hierarchy._set_unix_file_defaults: acl = %s" % acl)
acl.reset()
acl.chmod('644')
syslog(LOG_DEBUG, "POSIX_ACL_Hierarchy._set_unix_file_defaults: leave")
def _set_unix_directory_defaults(self, acl):
syslog(LOG_DEBUG, "POSIX_ACL_Hierarchy._set_unix_directory_defaults: enter")
syslog(LOG_DEBUG, "POSIX_ACL_Hierarchy._set_unix_directory_defaults: acl = %s" % acl)
acl.reset()
acl.chmod('755')
syslog(LOG_DEBUG, "POSIX_ACL_Hierarchy._set_unix_directory_defaults: leave")
def new_ACL(self, path):
syslog(LOG_DEBUG, "POSIX_ACL_Hierarchy.new_ACL: enter")
syslog(LOG_DEBUG, "POSIX_ACL_Hierarchy.new_ACL: leave")
return POSIX_ACL(path)