Example #1
0
    def __init__(self, cfgFile, drop=False):
        Environment.noargs = True
        Environment.config = cfgFile
        self.env = Environment.getInstance()
        acl_file = os.path.join(self.env.config.getBaseDir(), "agent.acl")
        self.acl_file = acl_file

        # Drop an existing agent.acl file
        if drop:
            if os.path.exists(self.acl_file):

                # Create a unique nackup name for the  existing acl file
                backup_name = "agent.acl._back_" + time.strftime("%d.%m.%Y")
                new_name = backup_name
                cnt = 1
                while os.path.exists(os.path.join(self.env.config.getBaseDir(), new_name)):
                    new_name = backup_name + "_" + str(cnt)
                    cnt += 1

                # Now try to rename the existing agent.acl file
                try:
                    os.rename(acl_file, os.path.join(self.env.config.getBaseDir(), new_name))
                except Exception as e:
                    print e
                    print(_("\n... maybe you are not allowed to access the acls file! (%s)") % acl_file)
                    print
                    sys.exit(1)
            else:
                print(_("\n... no old acl-file found, nothing dropped!"))
                print
                sys.exit(1)

        # Try to load the ACLResolver class.
        try:
            self.resolver = ACLResolver()
        except IOError as e:
            print e
            print
            print(_("... maybe you are not allowed to access the acls file! (%s)") % acl_file)
            print
            sys.exit(1)
        except ValueError as e:
            print e
            print(_("... the file seems to be corrupt!"))
            print
            print(_("You could try the --drop-all-permissions to create a new and clean acl-file! (%s)") % acl_file)
            print
            sys.exit(1)

        self.ldap_base = self.resolver.base

        # Tell the resolver to ignore acls for us (temporarily)
        self.resolver.admins.append('tmp_admin')

        # Build reverse scope map
        self.rev_acl_scope_map = dict((v, k) for k, v in
                self.acl_scope_map.iteritems())
Example #2
0
class ACLAdmin(object):
    """
    This class privides all necessary action for the 'acl-admin' script.

    All script actions will be forwarded to exported gosa commands.
    """

    acl_scope_map = {
        'one': ACL.ONE,
        'sub': ACL.SUB,
        'psub': ACL.PSUB,
        'reset': ACL.RESET,
        }

    def __init__(self, cfgFile, drop=False):
        Environment.noargs = True
        Environment.config = cfgFile
        self.env = Environment.getInstance()
        acl_file = os.path.join(self.env.config.getBaseDir(), "agent.acl")
        self.acl_file = acl_file

        # Drop an existing agent.acl file
        if drop:
            if os.path.exists(self.acl_file):

                # Create a unique nackup name for the  existing acl file
                backup_name = "agent.acl._back_" + time.strftime("%d.%m.%Y")
                new_name = backup_name
                cnt = 1
                while os.path.exists(os.path.join(self.env.config.getBaseDir(), new_name)):
                    new_name = backup_name + "_" + str(cnt)
                    cnt += 1

                # Now try to rename the existing agent.acl file
                try:
                    os.rename(acl_file, os.path.join(self.env.config.getBaseDir(), new_name))
                except Exception as e:
                    print e
                    print(_("\n... maybe you are not allowed to access the acls file! (%s)") % acl_file)
                    print
                    sys.exit(1)
            else:
                print(_("\n... no old acl-file found, nothing dropped!"))
                print
                sys.exit(1)

        # Try to load the ACLResolver class.
        try:
            self.resolver = ACLResolver()
        except IOError as e:
            print e
            print
            print(_("... maybe you are not allowed to access the acls file! (%s)") % acl_file)
            print
            sys.exit(1)
        except ValueError as e:
            print e
            print(_("... the file seems to be corrupt!"))
            print
            print(_("You could try the --drop-all-permissions to create a new and clean acl-file! (%s)") % acl_file)
            print
            sys.exit(1)

        self.ldap_base = self.resolver.base

        # Tell the resolver to ignore acls for us (temporarily)
        self.resolver.admins.append('tmp_admin')

        # Build reverse scope map
        self.rev_acl_scope_map = dict((v, k) for k, v in
                self.acl_scope_map.iteritems())

    def idToScopeStr(self, sid):
        """
        Helper method which converts a given scope value from int to string.

        =========== =============
        key         description
        =========== =============
        sid         The corresponding scope value
        =========== =============

        """
        if sid in self.rev_acl_scope_map:
            return(self.rev_acl_scope_map[sid])
        else:
            return(_("unknown"))

    def strToScopeId(self, sid):
        """
        Helper method which converts a given scope value from string to int.

        =========== =============
        key         description
        =========== =============
        sid         The corresponding scope value
        =========== =============

        """
        if sid in self.acl_scope_map:
            return(self.acl_scope_map[sid])
        else:
            return(None)

    def printReportHeader(self, string):
        """
        Helper method which prints a header for reports.

        =========== =============
        key         description
        =========== =============
        string      The report caption.
        =========== =============

        """
        print
        print("-" * len(string))
        print(string)
        print("-" * len(string))

    def para_missing(self, name):
        """
        Helper method that shows a warning about a missing required parameter!

        =========== =============
        key         description
        =========== =============
        name        The name of the parameter that was missing.
        =========== =============

        """
        print
        print(_("<%s> parameter is missing!") % name)
        desc = self.get_para_help(name)
        if len(desc):
            print " %s" % desc
        print

    def para_invalid(self, name):
        """
        Helper method which prints out a warning method that a parameter
        was passend in an invalid format.

        =========== =============
        key         description
        =========== =============
        name        The name of the parameter we want to print the invalid message for.
        =========== =============
        """

        print
        print(_("<%s> parameter is invalid!") % name)
        desc = self.get_para_help(name)
        if len(desc):
            print " %s" % desc
        print

    def get_para_help(self, para):
        """
        This method holds a description for all parameters that can be passed to this script.
        Due to the fact that we need the descriptions in several functions, i've put them
         into a single function.

        =========== =============
        key         description
        =========== =============
        para        The name of the parameter we want to get the description for.
        =========== =============
        """

        help_msgs = {
                "base": _("The base parameter specifies the position acls are active for. For example: dc=example,dc=de"),
                "scope": _("The scope value specifies how the acl role influences sub-directories"
                    "\n Possible scope values are:"
                    "\n  one   - For acls that are active only for the current base"
                    "\n          this can be revoked using the 'reset' scope!"
                    "\n  sub   - For acls that are active only for the complete subtree"
                    "\n          this can be revoked using the 'reset' scope!"
                    "\n  psub  - For acls that are active only for the complete subtree"
                    "\n          this can NOT be revoked using the 'reset' scope!"
                    "\n  reset - Revokes previously defined acls, except for those with scope 'psub'"),
                "priority": _("An integer value to prioritize an acl-rule. (Lower values mean higher priority)"
                    "\n  highest priority: -100"
                    "\n  lowest priority: -100"),
                "members": _("The names of the users/clients the acl-rule should be valid for. "
                    "\n  A comma separated list:"
                    "\n   e.g.: hubert,peter,klaus"),
                "acl-definition": _("The <acl-defintion> parameter specifies what actions can be performed on a given topic."
                    "\n"
                    "\n Syntax {<topic>:<acls>:<option1>: ... :<option N>,}"
                    "\n"
                    "\n Command examples:"
                    "\n   A single definition without options:"
                    "\n       org.gosa.*:rwcdm"
                    "\n"
                    "\n   A single definition with options:"
                    "\n       org.gosa.*:rwcdm:uid=user_*:tag=event"
                    "\n"
                    "\n   A multi action defintion"
                    "\n       org.gosa.events:rwcdm,org.gosa.factory:rw,org.gosa.something:rw"
                    "\n"
                    "\n <topic> "
                    "\n ========"
                    "\n The topic defines the target-action this acl includes"
                    "\n Topics can contain placeholder to be more flexible when it come to resolving acls."
                    "\n You can use `#` and `*` where `#` matches for one level and `*` for multiple topic levels."
                    "\n  e.g.: "
                    "\n   org.gosa.*        for all topics included in org.gosa"
                    "\n   org.gosa.#.help   allows to call help methods for modules under org.gosa"
                    "\n"
                    "\n <acls>"
                    "\n ======"
                    "\n The acl parameter defines which operations can be executed on a given topic."
                    "\n  e.g.:"
                    "\n   rwcd    -> allows to read, write, create and delete"
                    "\n"
                    "\n  Possible values are:"
                    "\n    r - Read             w - Write           m - Move"
                    "\n    c - Create           d - Delete          s - Search - or beeing found"
                    "\n    x - Execute          e - Receive event"
                    "\n"
                    "\n <options>"
                    "\n ========="
                    "\n Options are additional checks, please read the GOsa documentation for details."
                    "\n The format is:  key:value;key:value;..."
                    "\n  e.g. (Do not forget to use quotes!)"
                    "\n   'uid:peter;eventType:start;'"),
                "id": _("ID parameters have to be of type int!"),
                "rolename": _("The name of the acl role you want to set"),
                "acl-update-action": _("You can specify the upate-action for the acl."
                    "\n  Possible values are:"
                    "\n    * set-scope      Update the scope of an acl-rule"
                    "\n    * set-members    Set a new list of members for an acl-rule"
                    "\n    * set-priority   Set another priority level for the acl-rule"
                    "\n    * set-action     Set a new action for the acl"
                    "\n    * set-role       Let the acl-rule point to a role"),
                "roleacl-update-action": _("You can specify the upate-action for the role-acl."
                    "\n  Possible values are:"
                    "\n    * set-scope      Update the scope of an acl-rule"
                    "\n    * set-priority   Set another priority level for the acl-rule"
                    "\n    * set-action     Set a new action for the acl"
                    "\n    * set-role       Let the acl-rule point to a role"),
                "acl-add-action": _("You can either create acl-rule that contain direkt permissions settings"
                    " or you can use previously defined roles"
                    "\n  Possible values are:"
                    "\n    * with-actions   To directly specify the topic, acls and options this defintions includes"
                    "\n    * with-role      To use a rolename instead of defining actions directly")}

        # Return the help message, if it exists.
        if para in help_msgs:
            return(help_msgs[para])
        else:
            return(_("no help for %s ...") % para)

    def get_value_from_args(self, name, args):
        """
        This method extracts a parameter out of a given argument-list.

        (Due to the fact that we need parameter values in several functions, i've put them
         into a single function)

        =========== =============
        key         description
        =========== =============
        para        The name of the parameter we want to get the value for.
        args        The arguments-list we want to extract from.
        =========== =============
        """

        # Validate given id-parameters
        if name in ["id"]:
            if len(args):
                try:
                    if int(args[0]) < -100 or int(args[0]) > 100:
                        self.para_invalid(name)
                        sys.exit(1)
                except KeyError:
                    self.para_invalid(name)
                    sys.exit(1)
                aid = int(args[0])
                del(args[0])
                return(aid)
            else:
                self.para_missing(name)
                sys.exit(1)

        # Validate the base value
        elif name == "base":
            if len(args):
                base = args[0]
                del(args[0])
                return(base)
            else:
                self.para_missing('base')
                sys.exit(1)

        # Validate the scope value
        elif name == "scope":
            if len(args):
                if args[0] not in self.acl_scope_map:
                    self.para_invalid('scope')
                    sys.exit(1)
                else:
                    scope = args[0]
                    del(args[0])
                    return(scope)
            else:
                self.para_missing('scope')
                sys.exit(1)

        # Check for priority
        elif name == "priority":
            if len(args):
                try:
                    if int(args[0]) < -100 or int(args[0]) > 100:
                        self.para_invalid('priority')
                        sys.exit(1)
                except Exception:
                    self.para_invalid('priority')
                    sys.exit(1)

                prio = int(args[0])
                del(args[0])
                return(prio)
            else:
                self.para_missing('priority')
                sys.exit(1)

        # Check topic
        elif name == "topic":
            if len(args):
                topic = args[0]
                del(args[0])
                return(topic)
            else:
                self.para_missing(name)
                sys.exit(1)

        # Check topic
        elif name == "acl-definition":
            if len(args):
                defs = args[0].split(",")

                # Parse each definition
                actions = []
                for defintion in defs:
                    entries = defintion.split(":")
                    if len(entries) < 2:
                        self.para_missing(name)
                        sys.exit(1)
                    else:
                        action = {}
                        action['topic'] = entries[0]
                        action['acls'] = entries[1]
                        action['options'] = {}
                        for opt in entries[2::]:
                            opt_entries = opt.split("=")
                            if len(opt_entries) != 2:
                                self.para_missing(name)
                                sys.exit(1)
                            else:
                                on, ov = opt_entries
                                action['options'][on] = ov
                        actions.append(action)
                del(args[0])
                return(actions)
            else:
                self.para_missing(name)
                sys.exit(1)

        # Check members
        elif name == "members":
            if len(args):
                members = args[0]
                del(args[0])

                # Validate the found member valus
                members = members.split(",")
                m_list = []
                for member in members:
                    member = member.strip()
                    if not re.match("^[a-zA-Z][a-zA-Z0-9\.-]*$", member):
                        self.para_invalid(name)
                        sys.exit(1)
                    m_list.append(member)
                return(m_list)
            else:
                self.para_missing(name)
                sys.exit(1)

        # Check acls
        elif name == "acls":
            if len(args):
                acls = args[0]
                del(args[0])
                return(acls)
            else:
                self.para_missing(name)
                sys.exit(1)

        # Check rolename
        elif name == "rolename":
            if len(args):
                rolename = args[0]
                del(args[0])
                return(rolename)
            else:
                self.para_missing(name)
                sys.exit(1)

        # Check for options
        elif name == "options":
            if len(args):
                options = args[0]
                if not re.match(r"^([a-z0-9]*:[^:;]*;)*$", options):
                    self.para_invalid('options')
                    sys.exit(1)

                opts = {}
                for item in options.split(";"):
                    if len(item):
                        tmp = item.split(":")
                        opts[tmp[0]] = tmp[1]

                del(args[0])
                return(opts)
            return({})

        # Check for acl-update-actions
        elif name == "acl-update-action":
            if len(args):
                action = args[0]
                if action not in ["set-scope", "set-members", "set-priority", "set-action", "set-role"]:
                    self.para_invalid(name)
                    sys.exit(1)

                del(args[0])
                return(action)
            else:
                self.para_missing(name)
                sys.exit(1)

        # Check for roleacl-update-actions
        elif name == "roleacl-update-action":
            if len(args):
                action = args[0]
                if action not in ["set-scope", "set-priority", "set-action", "set-role"]:
                    self.para_invalid(name)
                    sys.exit(1)

                del(args[0])
                return(action)
            else:
                self.para_missing(name)
                sys.exit(1)

        # Check for acl-add-actions
        elif name == "acl-add-action":
            if len(args):
                action = args[0]
                if action not in ["with-actions", "with-role"]:
                    self.para_invalid(name)
                    sys.exit(1)

                del(args[0])
                return(action)
            else:
                self.para_missing(name)
                sys.exit(1)

        else:
            raise(Exception("Unknown parameter to extract: %s" % (name,)))

    @helpDecorator(_("Updates an acl entry"), _("update acl [set-scope|set-members|set-priority|set-action|set-role] <ID> [parameters]"))
    def update_acl(self, args):
        """
        This method updates an existing ACL-rule

        (It can be accessed via parameter 'update acl')

        =========== =============
        key         description
        =========== =============
        args        The arguments-list we use as information basis
        =========== =============
        """

        action_type = self.get_value_from_args("acl-update-action", args)
        aid = self.get_value_from_args("id", args)

        try:
            if "set-scope" == action_type:
                scope = self.get_value_from_args("scope", args)
                self.resolver.updateACL('tmp_admin', aid, scope=scope)
                self.resolver.save_to_file()

            if "set-members" == action_type:
                members = self.get_value_from_args("members", args)
                self.resolver.updateACL('tmp_admin', aid, members=members)
                self.resolver.save_to_file()

            if "set-priority" == action_type:
                priority = self.get_value_from_args("priority", args)
                self.resolver.updateACL('tmp_admin', aid, priority=priority)
                self.resolver.save_to_file()

            if "set-action" == action_type:
                scope = self.get_value_from_args("scope", args)
                actions = self.get_value_from_args("acl-definition", args)
                self.resolver.updateACL('tmp_admin', aid, actions=actions, scope=scope)
                self.resolver.save_to_file()

            if "set-role" == action_type:
                rolename = self.get_value_from_args("rolename", args)
                self.resolver.updateACL('tmp_admin', aid, rolename=rolename)
                self.resolver.save_to_file()

        except ACLException as e:
            print e

    @helpDecorator(_("Removes an acl entry"), _("remove acl <ID>"))
    def remove_acl(self, args):
        """
        This method removes an ACL-rule entry by ID.

        (It can be accessed via parameter 'remove acl')

        =========== =============
        key         description
        =========== =============
        args        The arguments-list we use as information basis
        =========== =============
        """
        rid = self.get_value_from_args("id", args)
        try:
            self.resolver.removeACL('tmp_admin', rid)
            self.resolver.save_to_file()
        except ACLException as e:
            print e

    @helpDecorator(_("Adds a new acl entry"), _("add acl [with-role|with-actions] <base> <priority> <members> [rolename|<scope> <topic> <acls> [options]]"))
    def add_acl(self, args):
        """
        This method creates a new ACL rule

        (It can be accessed via parameter 'add acl')

        =========== =============
        key         description
        =========== =============
        args        The arguments-list we use as information basis
        =========== =============
        """

        try:
            action_type = self.get_value_from_args("acl-add-action", args)
            actions = rolename = scope = members = None
            base = self.get_value_from_args("base", args)
            priority = self.get_value_from_args("priority", args)
            members = self.get_value_from_args("members", args)

            # Do we create an acl with direct actions or do we use a role.
            if action_type == "with-actions":
                scope = self.get_value_from_args("scope", args)
                actions = self.get_value_from_args("acl-definition", args)
                self.resolver.addACL('tmp_admin', base, priority, members, actions=actions, scope=scope)
            else:
                rolename = self.get_value_from_args("rolename", args)
                self.resolver.addACL('tmp_admin', base, priority, members, rolename=rolename)

            self.resolver.save_to_file()
        except ACLException as e:
            print e

    @helpDecorator(_("Adds a new acl entry to an existing role"), _("add roleacl [with-role|with-actions] <rolename> <priority> [rolename|<scope> <topic> <acls> [options]]"))
    def add_roleacl(self, args):
        """
        This method creates a new ACLRole entry for a given role.

        (It can be accessed via parameter 'add roleacl')

        =========== =============
        key         description
        =========== =============
        args        The arguments-list we use as information basis
        =========== =============
        """

        try:
            action_type = self.get_value_from_args("acl-add-action", args)
            actions = rolename = scope = members = None
            rolename = self.get_value_from_args("rolename", args)
            priority = self.get_value_from_args("priority", args)

            # Do we create an acl with direct actions or do we use a role.
            if action_type == "with-actions":
                scope = self.get_value_from_args("scope", args)
                actions = self.get_value_from_args("acl-definition", args)
                self.resolver.addACLToRole('tmp_admin', rolename, priority, actions=actions, scope=scope)
            else:
                use_role = self.get_value_from_args("rolename", args)
                self.resolver.addACLToRole('tmp_admin', rolename, priority, use_role=use_role)

            self.resolver.save_to_file()
        except ACLException as e:
            print e

    @helpDecorator(_("Adds a new role"), _("add role <rolename>"))
    def add_role(self, args):
        """
        This method creates a new ACL ROLE

        (It can be accessed via parameter 'add role')

        =========== =============
        key         description
        =========== =============
        args        The arguments-list we use as information basis
        =========== =============
        """

        rolename = self.get_value_from_args("rolename", args)
        try:
            self.resolver.addACLRole('tmp_admin', rolename)
            self.resolver.save_to_file()
        except ACLException as e:
            print e

    @helpDecorator(_("Removes an acl entry from a role"), _("remove roleacl <ID>"))
    def remove_roleacl(self, args):
        """
        This method removes an ACL from an ROLE

        =========== =============
        key         description
        =========== =============
        args        The arguments-list we use as information basis
        =========== =============
        """

        aid = self.get_value_from_args("id", args)
        try:
            self.resolver.removeRoleACL('tmp_admin', aid)
            self.resolver.save_to_file()
        except ACLException as e:
            print e

    @helpDecorator(_("Removes a role"), _("remove role <rolename>"))
    def remove_role(self, args):
        """
        This method removes an ACLRole

        =========== =============
        key         description
        =========== =============
        args        The arguments-list we use as information basis
        =========== =============
        """

        rolename = self.get_value_from_args("rolename", args)
        try:
            self.resolver.removeRole('tmp_admin', rolename)
            self.resolver.save_to_file()
        except ACLException as e:
            print e

    @helpDecorator(_("Updates an acl entry of a role"), _("update roleacl [set-scope|set-priority|set-action|set-role] <ID> [parameters]"))
    def update_roleacl(self, args):
        """
        This method updates an existing ACL ROLE entry.

        (It can be accessed via parameter 'update roleacl')

        =========== =============
        key         description
        =========== =============
        args        The arguments-list we use as information basis
        =========== =============
        """

        action_type = self.get_value_from_args("roleacl-update-action", args)
        aid = self.get_value_from_args("id", args)

        try:
            if "set-scope" == action_type:
                scope = self.get_value_from_args("scope", args)
                self.resolver.updateACLRole('tmp_admin', aid, scope=scope)
                self.resolver.save_to_file()

            if "set-priority" == action_type:
                priority = self.get_value_from_args("priority", args)
                self.resolver.updateACLRole('tmp_admin', aid, priority=priority)
                self.resolver.save_to_file()

            if "set-action" == action_type:
                scope = self.get_value_from_args("scope", args)
                actions = self.get_value_from_args("acl-definition", args)
                self.resolver.updateACLRole('tmp_admin', aid, actions=actions, scope=scope)
                self.resolver.save_to_file()

            if "set-role" == action_type:
                rolename = self.get_value_from_args("rolename", args)
                self.resolver.updateACLRole('tmp_admin', aid, use_role=rolename)
                self.resolver.save_to_file()
        except ACLException as e:
            print e

    @helpDecorator(_("List all defined acls"))
    def list_acls(self, args):
        """
        This method lists all defined acls.

        (It can be accessed via parameter 'list acls')

        =========== =============
        key         description
        =========== =============
        args        The arguments-list we use as information basis
        =========== =============
        """

        self.printReportHeader(_("Listing of active GOsa-ng acls"))
        allSets = self.resolver.list_acls()
        if not len(allSets):
            print(_("   ... none"))
        for aclset in allSets:
            for acl in aclset:
                print("ID: %i \tSCOPE(%s)\tPRIORITY: %s \t BASE (%s)" % (acl.id, self.idToScopeStr(acl.scope), acl.priority, aclset.base))
                print("       \tMEMBER: %s" % (", ".join(acl.members)))
                if acl.uses_role:
                    print(_("\trefers to role: %s") % acl.role)
                else:
                    cnt = 1
                    print("     \tACTIONS:")
                    for action in acl.actions:
                        print("        - %s. %s (%s)  %s" % (cnt, action['topic'], action['acls'], action['options']))
                        cnt += 1

    @helpDecorator(_("List all defined roles"))
    def list_roles(self, args):
        """
        This method lists all defined acl roles.

        (It can be accessed via parameter 'list acls')

        =========== =============
        key         description
        =========== =============
        args        The arguments-list we use as information basis
        =========== =============
        """
        self.printReportHeader(_("Listing of active GOsa-ng roles"))
        allRoles = self.resolver.list_roles()
        if not len(allRoles):
            print("   ... none")
        for aclrole in allRoles:
            print("  Entries for role: %s" % aclrole)
            for acl in allRoles[aclrole]:
                print("ID: %i \tROLENAME: %s \t SCOPE (%s) \t PRIORITY (%s)" % (acl.id, allRoles[aclrole].name, self.idToScopeStr(acl.scope), str(acl.priority)))
                if acl.uses_role:
                    print(_("\trefers to role: %s") % acl.role)
                else:
                    cnt = 1
                    print("     \tACTIONS:")
                    for action in acl.actions:
                        print("        - %s. %s (%s)  %s" % (cnt, action['topic'], action['acls'], action['options']))
                        cnt += 1