Ejemplo n.º 1
0
    def _makedirs(self, entry, path=None):
        """ os.makedirs helpfully creates all parent directories for
        us, but it sets permissions according to umask, which is
        probably wrong.  we need to find out which directories were
        created and set permissions on those
        (http://trac.mcs.anl.gov/projects/bcfg2/ticket/1125 and
        http://trac.mcs.anl.gov/projects/bcfg2/ticket/1134) """
        created = []
        if path is None:
            path = entry.get("name")
        cur = path
        while cur and cur != '/':
            if not os.path.exists(cur):
                created.append(cur)
            cur = os.path.dirname(cur)
        rv = True
        try:
            os.makedirs(path)
        except OSError:
            err = sys.exc_info()[1]
            self.logger.error('POSIX: Failed to create directory %s: %s' %
                              (path, err))
            rv = False

        # set auto-created directories to mode 755, if you need
        # something else, you should specify it in your config
        tmpentry = copy.deepcopy(entry)
        tmpentry.set('mode', '0755')
        for acl in tmpentry.findall('ACL'):
            acl.set('perms',
                    oct_mode(self._norm_acl_perms(acl.get('perms')) |
                             ACL_MAP['x']))
        for cpath in created:
            rv &= self._set_perms(tmpentry, path=cpath)
        return rv
Ejemplo n.º 2
0
    def _generate_data(self, entry, metadata):
        """ Generate data for the given entry on the given client

        :param entry: The abstract entry to generate data for.  This
                      will not be modified
        :type entry: lxml.etree._Element
        :param metadata: The client metadata to generate data for
        :type metadata: Bcfg2.Server.Plugins.Metadata.ClientMetadata
        :returns: tuple of (string, generator) - the data for the
                  entry and the generator used to generate it (or
                  None, if data was created)
        """
        try:
            generator = self.best_matching(
                metadata, self.get_handlers(metadata, CfgGenerator))
        except PluginExecutionError:
            # if no creators or generators exist, _create_data()
            # raises an appropriate exception
            return (self._create_data(entry, metadata), None)

        if entry.get('mode').lower() == 'inherit':
            # use on-disk permissions
            self.logger.warning(
                "Cfg: %s: Use of mode='inherit' is deprecated" %
                entry.get("name"))
            fname = os.path.join(self.path, generator.name)
            entry.set('mode', oct_mode(stat.S_IMODE(os.stat(fname).st_mode)))
        try:
            return (generator.get_data(entry, metadata), generator)
        except:
            msg = "Cfg: Error rendering %s: %s" % (entry.get("name"),
                                                   sys.exc_info()[1])
            self.logger.error(msg)
            raise PluginExecutionError(msg)
Ejemplo n.º 3
0
    def _generate_data(self, entry, metadata):
        """ Generate data for the given entry on the given client

        :param entry: The abstract entry to generate data for.  This
                      will not be modified
        :type entry: lxml.etree._Element
        :param metadata: The client metadata to generate data for
        :type metadata: Bcfg2.Server.Plugins.Metadata.ClientMetadata
        :returns: string - the data for the entry
        """
        try:
            generator = self.best_matching(metadata,
                                           self.get_handlers(metadata,
                                                             CfgGenerator))
        except PluginExecutionError:
            # if no creators or generators exist, _create_data()
            # raises an appropriate exception
            return self._create_data(entry, metadata)

        if entry.get('mode').lower() == 'inherit':
            # use on-disk permissions
            self.logger.warning("Cfg: %s: Use of mode='inherit' is deprecated"
                                % entry.get("name"))
            fname = os.path.join(self.path, generator.name)
            entry.set('mode',
                      oct_mode(stat.S_IMODE(os.stat(fname).st_mode)))
        try:
            return generator.get_data(entry, metadata)
        except:
            msg = "Cfg: Error rendering %s: %s" % (entry.get("name"),
                                                   sys.exc_info()[1])
            self.logger.error(msg)
            raise PluginExecutionError(msg)
Ejemplo n.º 4
0
Archivo: base.py Proyecto: fennm/bcfg2
    def _gather_data(self, path):
        """ Get data on the existing state of <path> -- e.g., whether
        or not it exists, owner, group, permissions, etc. """
        try:
            ondisk = os.lstat(path)
        except OSError:
            self.logger.debug("POSIX: %s does not exist" % path)
            return (False, None, None, None, None, None)

        try:
            owner = str(ondisk[stat.ST_UID])
        except OSError:
            err = sys.exc_info()[1]
            self.logger.debug("POSIX: Could not get current owner of %s: %s" %
                              (path, err))
            owner = None
        except KeyError:
            self.logger.error('POSIX: User resolution failed for %s' % path)
            owner = None

        try:
            group = str(ondisk[stat.ST_GID])
        except (OSError, KeyError):
            err = sys.exc_info()[1]
            self.logger.debug("POSIX: Could not get current group of %s: %s" %
                              (path, err))
            group = None
        except KeyError:
            self.logger.error('POSIX: Group resolution failed for %s' % path)
            group = None

        try:
            mode = oct_mode(ondisk[stat.ST_MODE])[-4:]
        except (OSError, KeyError, TypeError):
            err = sys.exc_info()[1]
            self.logger.debug("POSIX: Could not get current permissions of "
                              "%s: %s" % (path, err))
            mode = None

        if HAS_SELINUX:
            try:
                secontext = selinux.lgetfilecon(path)[1].split(":")[2]
            except (OSError, KeyError):
                err = sys.exc_info()[1]
                self.logger.debug("POSIX: Could not get current SELinux "
                                  "context of %s: %s" % (path, err))
                secontext = None
        else:
            secontext = None

        if HAS_ACLS and not stat.S_ISLNK(ondisk[stat.ST_MODE]):
            acls = self._list_file_acls(path)
        else:
            acls = None
        return (ondisk, owner, group, mode, secontext, acls)
Ejemplo n.º 5
0
    def _gather_data(self, path):
        """ Get data on the existing state of <path> -- e.g., whether
        or not it exists, owner, group, permissions, etc. """
        try:
            ondisk = os.lstat(path)
        except OSError:
            self.logger.debug("POSIX: %s does not exist" % path)
            return (False, None, None, None, None, None)

        try:
            owner = str(ondisk[stat.ST_UID])
        except OSError:
            err = sys.exc_info()[1]
            self.logger.debug("POSIX: Could not get current owner of %s: %s" %
                              (path, err))
            owner = None
        except KeyError:
            self.logger.error('POSIX: User resolution failed for %s' % path)
            owner = None

        try:
            group = str(ondisk[stat.ST_GID])
        except (OSError, KeyError):
            err = sys.exc_info()[1]
            self.logger.debug("POSIX: Could not get current group of %s: %s" %
                              (path, err))
            group = None
        except KeyError:
            self.logger.error('POSIX: Group resolution failed for %s' % path)
            group = None

        try:
            mode = oct_mode(ondisk[stat.ST_MODE])[-4:]
        except (OSError, KeyError, TypeError):
            err = sys.exc_info()[1]
            self.logger.debug("POSIX: Could not get current permissions of "
                              "%s: %s" % (path, err))
            mode = None

        if HAS_SELINUX:
            try:
                secontext = selinux.lgetfilecon(path)[1].split(":")[2]
            except (OSError, KeyError):
                err = sys.exc_info()[1]
                self.logger.debug("POSIX: Could not get current SELinux "
                                  "context of %s: %s" % (path, err))
                secontext = None
        else:
            secontext = None

        if HAS_ACLS and not stat.S_ISLNK(ondisk[stat.ST_MODE]):
            acls = self._list_file_acls(path)
        else:
            acls = None
        return (ondisk, owner, group, mode, secontext, acls)
Ejemplo n.º 6
0
    def _makedirs(self, entry, path=None):
        """ os.makedirs helpfully creates all parent directories for
        us, but it sets permissions according to umask, which is
        probably wrong.  we need to find out which directories were
        created and set permissions on those
        (http://trac.mcs.anl.gov/projects/bcfg2/ticket/1125 and
        http://trac.mcs.anl.gov/projects/bcfg2/ticket/1134) """
        created = []
        if path is None:
            path = entry.get("name")
        cur = path
        while cur and cur != '/':
            if not os.path.exists(cur):
                created.append(cur)
            cur = os.path.dirname(cur)
        rv = True
        try:
            os.makedirs(path)
        except OSError:
            err = sys.exc_info()[1]
            self.logger.error('POSIX: Failed to create directory %s: %s' %
                              (path, err))
            rv = False

        # we need to make sure that we give +x to everyone who needs
        # it.  E.g., if the file that's been distributed is 0600, we
        # can't make the parent directories 0600 also; that'd be
        # pretty useless.  They need to be 0700.
        tmpentry = copy.deepcopy(entry)
        newmode = int(entry.get('mode'), 8)
        for i in range(0, 3):
            if newmode & (6 * pow(8, i)):
                newmode |= 1 * pow(8, i)
        tmpentry.set('mode', oct_mode(newmode))
        for acl in tmpentry.findall('ACL'):
            acl.set(
                'perms',
                oct_mode(
                    self._norm_acl_perms(acl.get('perms')) | ACL_MAP['x']))
        for cpath in created:
            rv &= self._set_perms(tmpentry, path=cpath)
        return rv
Ejemplo n.º 7
0
    def _makedirs(self, entry, path=None):
        """ os.makedirs helpfully creates all parent directories for
        us, but it sets permissions according to umask, which is
        probably wrong.  we need to find out which directories were
        created and set permissions on those
        (http://trac.mcs.anl.gov/projects/bcfg2/ticket/1125 and
        http://trac.mcs.anl.gov/projects/bcfg2/ticket/1134) """
        created = []
        if path is None:
            path = entry.get("name")
        cur = path
        while cur and cur != '/':
            if not os.path.exists(cur):
                created.append(cur)
            cur = os.path.dirname(cur)
        rv = True
        try:
            os.makedirs(path)
        except OSError:
            err = sys.exc_info()[1]
            self.logger.error('POSIX: Failed to create directory %s: %s' %
                              (path, err))
            rv = False

        # we need to make sure that we give +x to everyone who needs
        # it.  E.g., if the file that's been distributed is 0600, we
        # can't make the parent directories 0600 also; that'd be
        # pretty useless.  They need to be 0700.
        tmpentry = copy.deepcopy(entry)
        newmode = int(entry.get('mode'), 8)
        for i in range(0, 3):
            if newmode & (6 * pow(8, i)):
                newmode |= 1 * pow(8, i)
        tmpentry.set('mode', oct_mode(newmode))
        for acl in tmpentry.findall('ACL'):
            acl.set('perms',
                    oct_mode(self._norm_acl_perms(acl.get('perms')) |
                             ACL_MAP['x']))
        for cpath in created:
            rv &= self._set_perms(tmpentry, path=cpath)
        return rv
Ejemplo n.º 8
0
Archivo: base.py Proyecto: fennm/bcfg2
    def _set_perms(self, entry, path=None):
        """ set permissions on the given entry, or on the given path
        according to the given entry """
        if path is None:
            path = entry.get("name")

        rv = True
        if os.geteuid() == 0:
            if entry.get("owner") and entry.get("group"):
                try:
                    self.logger.debug("POSIX: Setting ownership of %s to %s:%s"
                                      % (path,
                                         self._norm_entry_uid(entry),
                                         self._norm_entry_gid(entry)))
                    os.chown(path, self._norm_entry_uid(entry),
                             self._norm_entry_gid(entry))
                except (OSError, KeyError):
                    self.logger.error('POSIX: Failed to change ownership of %s'
                                      % path)
                    rv = False
                    if sys.exc_info()[0] == KeyError:
                        os.chown(path, 0, 0)
        else:
            self.logger.debug("POSIX: Run as non-root, not setting ownership")

        if entry.get("mode"):
            wanted_mode = int(entry.get('mode'), 8)
            if entry.get('dev_type'):
                wanted_mode |= device_map[entry.get('dev_type')]
            try:
                self.logger.debug("POSIX: Setting mode on %s to %s" %
                                  (path, oct_mode(wanted_mode)))
                os.chmod(path, wanted_mode)
            except (OSError, KeyError):
                self.logger.error('POSIX: Failed to change mode on %s' %
                                  path)
                rv = False

        if entry.get('mtime'):
            try:
                os.utime(entry.get('name'), (int(entry.get('mtime')),
                                             int(entry.get('mtime'))))
            except OSError:
                self.logger.error("POSIX: Failed to set mtime of %s" % path)
                rv = False

        rv &= self._set_secontext(entry, path=path)
        rv &= self._set_acls(entry, path=path)
        return rv
Ejemplo n.º 9
0
    def _set_perms(self, entry, path=None):
        """ set permissions on the given entry, or on the given path
        according to the given entry """
        if path is None:
            path = entry.get("name")

        rv = True
        if os.geteuid() == 0:
            if entry.get("owner") and entry.get("group"):
                try:
                    self.logger.debug("POSIX: Setting ownership of %s to %s:%s"
                                      % (path,
                                         self._norm_entry_uid(entry),
                                         self._norm_entry_gid(entry)))
                    os.chown(path, self._norm_entry_uid(entry),
                             self._norm_entry_gid(entry))
                except (OSError, KeyError):
                    self.logger.error('POSIX: Failed to change ownership of %s'
                                      % path)
                    rv = False
                    if sys.exc_info()[0] == KeyError:
                        os.chown(path, 0, 0)
        else:
            self.logger.debug("POSIX: Run as non-root, not setting ownership")

        if entry.get("mode"):
            wanted_mode = int(entry.get('mode'), 8)
            if entry.get('dev_type'):
                wanted_mode |= device_map[entry.get('dev_type')]
            try:
                self.logger.debug("POSIX: Setting mode on %s to %s" %
                                  (path, oct_mode(wanted_mode)))
                os.chmod(path, wanted_mode)
            except (OSError, KeyError):
                self.logger.error('POSIX: Failed to change mode on %s' %
                                  path)
                rv = False

        if entry.get('mtime'):
            try:
                os.utime(entry.get('name'), (int(entry.get('mtime')),
                                             int(entry.get('mtime'))))
            except OSError:
                self.logger.error("POSIX: Failed to set mtime of %s" % path)
                rv = False

        rv &= self._set_secontext(entry, path=path)
        rv &= self._set_acls(entry, path=path)
        return rv
Ejemplo n.º 10
0
    def _makedirs(self, entry, path=None):
        """ os.makedirs helpfully creates all parent directories for
        us, but it sets permissions according to umask, which is
        probably wrong.  we need to find out which directories were
        created and try to set permissions on those
        (http://trac.mcs.anl.gov/projects/bcfg2/ticket/1125 and
        http://trac.mcs.anl.gov/projects/bcfg2/ticket/1134) """
        created = []
        if path is None:
            path = entry.get("name")
        cur = path
        while cur and cur != '/':
            if not os.path.exists(cur):
                created.append(cur)
            cur = os.path.dirname(cur)
        rv = True
        try:
            os.makedirs(path)
        except OSError:
            err = sys.exc_info()[1]
            self.logger.error('POSIX: Failed to create directory %s: %s' %
                              (path, err))
            rv = False

        # set auto-created directories to mode 755 and use best effort for
        # permissions.  If you need something else, you should specify it in
        # your config.
        tmpentry = copy.deepcopy(entry)
        tmpentry.set('mode', '0755')
        for acl in tmpentry.findall('ACL'):
            acl.set(
                'perms',
                oct_mode(
                    self._norm_acl_perms(acl.get('perms')) | ACL_MAP['x']))
        for cpath in created:
            self._set_perms(tmpentry, path=cpath)
        return rv
Ejemplo n.º 11
0
Archivo: base.py Proyecto: fennm/bcfg2
    def _verify_metadata(self, entry, path=None):  # pylint: disable=R0912
        """ generic method to verify mode, owner, group, secontext, acls,
        and mtime """
        # allow setting an alternate path for recursive permissions checking
        if path is None:
            path = entry.get('name')
        attrib = dict()
        ondisk, attrib['current_owner'], attrib['current_group'], \
            attrib['current_mode'], attrib['current_secontext'] = \
            self._gather_data(path)[0:5]

        if not ondisk:
            entry.set('current_exists', 'false')
            return False

        # we conditionally verify every bit of metadata only if it's
        # specified on the entry.  consequently, canVerify() and
        # fully_specified() are preconditions of _verify_metadata(),
        # since they will ensure that everything that needs to be
        # specified actually is.  this lets us gracefully handle
        # symlink and hardlink entries, which have SELinux contexts
        # but not other permissions, optional secontext and mtime
        # attrs, and so on.
        wanted_owner, wanted_group, wanted_mode, mtime = None, None, None, -1
        if entry.get('mtime', '-1') != '-1':
            mtime = str(ondisk[stat.ST_MTIME])
        if entry.get("owner"):
            wanted_owner = str(self._norm_entry_uid(entry))
        if entry.get("group"):
            wanted_group = str(self._norm_entry_gid(entry))
        if entry.get("mode"):
            while len(entry.get('mode', '')) < 4:
                entry.set('mode', '0' + entry.get('mode', ''))
            wanted_mode = int(entry.get('mode'), 8)

        errors = []
        if wanted_owner and attrib['current_owner'] != wanted_owner:
            errors.append("Owner for path %s is incorrect. "
                          "Current owner is %s but should be %s" %
                          (path, attrib['current_owner'], entry.get('owner')))

        if wanted_group and attrib['current_group'] != wanted_group:
            errors.append("Group for path %s is incorrect. "
                          "Current group is %s but should be %s" %
                          (path, attrib['current_group'], entry.get('group')))

        if (wanted_mode and
                oct_mode(int(attrib['current_mode'], 8)) !=
                oct_mode(wanted_mode)):
            errors.append("Permissions for path %s are incorrect. "
                          "Current permissions are %s but should be %s" %
                          (path, attrib['current_mode'], entry.get('mode')))

        if entry.get('mtime'):
            attrib['current_mtime'] = mtime
            if mtime != entry.get('mtime', '-1'):
                errors.append("mtime for path %s is incorrect. "
                              "Current mtime is %s but should be %s" %
                              (path, mtime, entry.get('mtime')))

        if HAS_SELINUX:
            wanted_secontext = None
            if entry.get("secontext") == "__default__":
                try:
                    wanted_secontext = \
                        selinux.matchpathcon(
                            path, ondisk[stat.ST_MODE])[1].split(":")[2]
                except OSError:
                    errors.append("%s has no default SELinux context" %
                                  entry.get("name"))
            elif entry.get("secontext"):
                wanted_secontext = entry.get("secontext").split(":")[2]
            if (wanted_secontext and
                    attrib['current_secontext'] != wanted_secontext):
                errors.append("SELinux context for path %s is incorrect. "
                              "Current context is %s but should be %s" %
                              (path, attrib['current_secontext'],
                               wanted_secontext))

        if errors:
            for error in errors:
                self.logger.debug("POSIX: " + error)
            entry.set('qtext', "\n".join([entry.get('qtext', '')] + errors))
        if path == entry.get("name"):
            for attr, val in attrib.items():
                if val is not None:
                    entry.set(attr, str(val))

        return self._verify_acls(entry, path=path) and len(errors) == 0
Ejemplo n.º 12
0
    def _verify_metadata(self, entry, path=None):  # pylint: disable=R0912
        """ generic method to verify mode, owner, group, secontext, acls,
        and mtime """
        # allow setting an alternate path for recursive permissions checking
        if path is None:
            path = entry.get('name')
        attrib = dict()
        ondisk, attrib['current_owner'], attrib['current_group'], \
            attrib['current_mode'], attrib['current_secontext'] = \
            self._gather_data(path)[0:5]

        if not ondisk:
            entry.set('current_exists', 'false')
            return False

        # we conditionally verify every bit of metadata only if it's
        # specified on the entry.  consequently, canVerify() and
        # fully_specified() are preconditions of _verify_metadata(),
        # since they will ensure that everything that needs to be
        # specified actually is.  this lets us gracefully handle
        # symlink and hardlink entries, which have SELinux contexts
        # but not other permissions, optional secontext and mtime
        # attrs, and so on.
        wanted_owner, wanted_group, wanted_mode, mtime = None, None, None, -1
        if entry.get('mtime', '-1') != '-1':
            mtime = str(ondisk[stat.ST_MTIME])
        if entry.get("owner"):
            wanted_owner = str(self._norm_entry_uid(entry))
        if entry.get("group"):
            wanted_group = str(self._norm_entry_gid(entry))
        if entry.get("mode"):
            while len(entry.get('mode', '')) < 4:
                entry.set('mode', '0' + entry.get('mode', ''))
            wanted_mode = int(entry.get('mode'), 8)

        errors = []
        if wanted_owner and attrib['current_owner'] != wanted_owner:
            errors.append("Owner for path %s is incorrect. "
                          "Current owner is %s but should be %s" %
                          (path, attrib['current_owner'], entry.get('owner')))

        if wanted_group and attrib['current_group'] != wanted_group:
            errors.append("Group for path %s is incorrect. "
                          "Current group is %s but should be %s" %
                          (path, attrib['current_group'], entry.get('group')))

        if (wanted_mode and
                oct_mode(int(attrib['current_mode'], 8)) !=
                oct_mode(wanted_mode)):
            errors.append("Permissions for path %s are incorrect. "
                          "Current permissions are %s but should be %s" %
                          (path, attrib['current_mode'], entry.get('mode')))

        if entry.get('mtime'):
            attrib['current_mtime'] = mtime
            if mtime != entry.get('mtime', '-1'):
                errors.append("mtime for path %s is incorrect. "
                              "Current mtime is %s but should be %s" %
                              (path, mtime, entry.get('mtime')))

        if HAS_SELINUX:
            wanted_secontext = None
            if entry.get("secontext") == "__default__":
                try:
                    wanted_secontext = \
                        selinux.matchpathcon(
                            path, ondisk[stat.ST_MODE])[1].split(":")[2]
                except OSError:
                    errors.append("%s has no default SELinux context" %
                                  entry.get("name"))
            else:
                wanted_secontext = entry.get("secontext")
            if (wanted_secontext and
                    attrib['current_secontext'] != wanted_secontext):
                errors.append("SELinux context for path %s is incorrect. "
                              "Current context is %s but should be %s" %
                              (path, attrib['current_secontext'],
                               wanted_secontext))

        if errors:
            for error in errors:
                self.logger.debug("POSIX: " + error)
            entry.set('qtext', "\n".join([entry.get('qtext', '')] + errors))
        if path == entry.get("name"):
            for attr, val in attrib.items():
                if val is not None:
                    entry.set(attr, str(val))

        return self._verify_acls(entry, path=path) and len(errors) == 0