示例#1
0
    def configFromCommandSpec(cls, spec, user = None, default = None, extra_settings = None, disable_console_log = False):
        """
        A command specification (typically specified with the --config=<file_or_dir> command
        line option) is used to create a configuration object.   The target may be either a file
        or a directory.  If it is a file, then the file itself will be the only configuration
        read.  If it is a directory, then a search is made for any top-level files which end in
        .conf or .yaml, and those will be combined according to lexicographic order.

        If the configuration path is a relative path, then it is relative to either the root
        directory, or the home directory of the given user.  This allows a user-specific
        configuration to automatically take effect if desired.
        """

        frombase = '/'

        if user:
            frombase = lookup_user(user).pw_dir

        trypath = os.path.join(frombase, spec)

        debug("TRY CONFIG PATH: {0}".format(trypath))

        if not os.path.exists(trypath):
            return cls(default = default)
        else:
            os.environ[ENV_CONFIG_DIR] = os.path.dirname(trypath)

        if os.path.isdir(trypath):
            return cls(*[os.path.join(trypath, f) for f in sorted(os.listdir(trypath))
                         if f.endswith('.yaml') or f.endswith('.conf')],
                       default = default, uid = user, extra_settings = extra_settings, disable_console_log = disable_console_log)


        return cls(trypath, default = default, uid = user, extra_settings = extra_settings, disable_console_log = disable_console_log)
示例#2
0
    def _try_to_enable(self):
        service = self.service
        if self._orig_executable:
            try:
                service.exec_args[0] = executable_path(
                    self._orig_executable, service.environment.expanded())
            except FileNotFoundError:
                if service.optional:
                    service.enabled = False
                    self.loginfo(
                        "optional service {0} disabled since '{1}' is not present"
                        .format(self.name, self._orig_executable))
                    return
                elif service.ignore_failures:
                    service.enabled = False
                    self.logwarn(
                        "(ignored) service {0} executable '{1}' is not present"
                        .format(self.name, self._orig_executable))
                    return
                raise ChNotFoundError("executable '{0}' not found".format(
                    service.exec_args[0]))

        # Now we know this service is truly enabled, we need to assure its credentials
        # are correct.

        senv = service.environment

        if senv and senv.uid is not None and not self._pwrec:
            self._pwrec = lookup_user(senv.uid, senv.gid)

        service.enabled = True
示例#3
0
    def configFromCommandSpec(cls, spec, user = None, default = None, extra_settings = None, disable_console_log = False):
        """
        A command specification (typically specified with the --config=<file_or_dir> command
        line option) is used to create a configuration object.   The target may be either a file
        or a directory.  If it is a file, then the file itself will be the only configuration
        read.  If it is a directory, then a search is made for any top-level files which end in
        .conf or .yaml, and those will be combined according to lexicographic order.

        If the configuration path is a relative path, then it is relative to either the root
        directory, or the home directory of the given user.  This allows a user-specific
        configuration to automatically take effect if desired.
        """

        frombase = '/'

        if user:
            frombase = lookup_user(user).pw_dir

        trypath = os.path.join(frombase, spec)

        debug("TRY CONFIG PATH: {0}".format(trypath))

        if not os.path.exists(trypath):
            return cls(default = default)
        else:
            os.environ[ENV_CONFIG_DIR] = os.path.dirname(trypath)

        if os.path.isdir(trypath):
            return cls(*[os.path.join(trypath, f) for f in sorted(os.listdir(trypath))
                         if f.endswith('.yaml') or f.endswith('.conf')],
                       default = default, uid = user, extra_settings = extra_settings, disable_console_log = disable_console_log)


        return cls(trypath, default = default, uid = user, extra_settings = extra_settings, disable_console_log = disable_console_log)
示例#4
0
    def _try_to_enable(self):
        service = self.service
        if self._orig_executable:
            try:
                service.exec_args[0] = executable_path(self._orig_executable, service.environment.expanded())
            except FileNotFoundError:
                if service.optional:
                    service.enabled = False
                    self.loginfo("optional service {0} disabled since '{1}' is not present".format(self.name, self._orig_executable))
                    return
                elif service.ignore_failures:
                    service.enabled = False
                    self.logwarn("(ignored) service {0} executable '{1}' is not present".format(self.name, self._orig_executable))
                    return
                raise ChNotFoundError("executable '{0}' not found".format(service.exec_args[0]))

        # Now we know this service is truly enabled, we need to assure its credentials
        # are correct.

        senv = service.environment

        if senv and senv.uid is not None and not self._pwrec:
            self._pwrec = lookup_user(senv.uid, senv.gid)

        service.enabled = True
示例#5
0
    def _backtick_expand(self, cmd):
        """
        Performs rudimentary backtick expansion after all other environment variables have been
        expanded.   Because these are cached, the user should not expect results to differ
        for different environment contexts, nor should the environment itself be relied upon.
        """

        # Accepts either a string or match object
        if not isinstance(cmd, str):
            cmd = cmd.group(1)

        if not self._cls_backtick:
            return "`" + cmd + "`"

        key = '{0}:{1}:{2}'.format(self.uid, self.gid, cmd)

        result = self._cls_btcache.get(key)

        if result is None:
            if self.uid:
                try:
                    pwrec = lookup_user(self.uid, self.gid)
                except ChNotFoundError as ex:
                    ex.annotate(
                        '(required for backtick expansion `{0}`)'.format(cmd))
                    raise ex
            else:
                pwrec = None

            def _proc_setup():
                if pwrec:
                    os.setgid(pwrec.pw_gid)
                    os.setuid(pwrec.pw_uid)

            try:
                result = subprocess.check_output(cmd,
                                                 shell=True,
                                                 stderr=subprocess.STDOUT,
                                                 preexec_fn=_proc_setup)
                result = result.decode()
            except Exception as ex:
                error(ex, "Backtick expansion returned error: " + str(ex))
                result = ""

            result = result.strip().replace("\n", " ")
            if self._cls_use_btcache:
                self._cls_btcache[key] = result

        return result
示例#6
0
文件: env.py 项目: CivilPol/chaperone
    def _backtick_expand(self, cmd):
        """
        Performs rudimentary backtick expansion after all other environment variables have been
        expanded.   Because these are cached, the user should not expect results to differ
        for different environment contexts, nor should the environment itself be relied upon.
        """

        # Accepts either a string or match object
        if not isinstance(cmd, str):
            cmd = cmd.group(1)

        if not self._cls_backtick:
            return "`" + cmd + "`"

        key = '{0}:{1}:{2}'.format(self.uid, self.gid, cmd)

        result = self._cls_btcache.get(key)

        if result is None:
            if self.uid:
                try:
                    pwrec = lookup_user(self.uid, self.gid)
                except ChNotFoundError as ex:
                    ex.annotate('(required for backtick expansion `{0}`)'.format(cmd))
                    raise ex
            else:
                pwrec = None

            def _proc_setup():
                if pwrec:
                    os.setgid(pwrec.pw_gid)
                    os.setuid(pwrec.pw_uid)

            try:
                result = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT,
                                                 preexec_fn=_proc_setup)
                result = result.decode()
            except Exception as ex:
                error(ex, "Backtick expansion returned error: " + str(ex))
                result = ""

            result = result.strip().replace("\n", " ")
            if self._cls_use_btcache:
                self._cls_btcache[key] = result

        return result
示例#7
0
文件: env.py 项目: CivilPol/chaperone
    def __init__(self, from_env = os.environ, config = None, uid = None, gid = None, resolve_xid = True):
        """
        Create a new environment.  An environment may have a user associated with it.  If so,
        then it will be pre-populated with the user's HOME, USER and LOGNAME so that expansions
        can reference these.
        
        Note that if resolve_xid is False, then credentials if they do not exist, but leave the uid/gid the same.  
        This means that certain features, like HOME variables, will not be properly set, leading to possible
        interactions between the optional components and their actual specification.  However, this is better
        than having optional components trigger errors because uninstalled software did not create uid's
        needed for operation.  The onus is on the service itself (in cproc) to assure that checking
        is performed.

        Note also that environments which use backtick expansions will *still* fail, because the backticks
        must occur within the context of the specified user, and it would be a security violation to
        allow a default.
        """
        super().__init__()

        #print("\n--ENV INIT", config, uid, from_env, from_env and getattr(from_env, 'uid', None))

        userenv = dict()

        # Inherit user from passed-in environment
        self._shadow = getattr(from_env, '_shadow', None)
        shadow = None           # we don't bother to recreate this in any complex fashion unless we need to

        if uid is None:
            self.uid = getattr(from_env, 'uid', self.uid)
            self.gid = getattr(from_env, 'gid', self.gid)
        else:
            pwrec = None
            try:
                pwrec = lookup_user(uid, gid)
            except ChNotFoundError:
                if resolve_xid:
                    raise
                self.uid = uid
                self.gid = gid

            if pwrec:
                self.uid = pwrec.pw_uid
                self.gid = pwrec.pw_gid
                userenv['HOME'] = pwrec.pw_dir
                userenv['USER'] = userenv['LOGNAME'] = pwrec.pw_name

        if not config:
            if from_env:
                self.update(from_env)
            self.update(userenv)
        else:
            inherit = config.get('env_inherit') or ['*']
            if inherit and from_env:
                self.update({k:v for k,v in from_env.items() if any([fnmatch(k,pat) for pat in inherit])})
            self.update(userenv)

            add = config.get('env_set')
            unset = config.get('env_unset')

            if add or unset:
                self._shadow = shadow = (getattr(self, '_shadow') or _DICT_CONST).copy()

            if add:
                for k,v in add.items():
                    if from_env and k in from_env:
                        shadow[k] = from_env # we keep track of the environment where the predecessor originated
                    self[k] = v
            if unset:
                patmatch = lambda p: any([fnmatch(p,pat) for pat in unset])
                for delkey in [k for k in self.keys() if patmatch(k)]:
                    del self[delkey]
                for delkey in [k for k in shadow.keys() if patmatch(k)]:
                    del shadow[delkey]
示例#8
0
    def __init__(self,
                 from_env=os.environ,
                 config=None,
                 uid=None,
                 gid=None,
                 resolve_xid=True):
        """
        Create a new environment.  An environment may have a user associated with it.  If so,
        then it will be pre-populated with the user's HOME, USER and LOGNAME so that expansions
        can reference these.
        
        Note that if resolve_xid is False, then credentials if they do not exist, but leave the uid/gid the same.  
        This means that certain features, like HOME variables, will not be properly set, leading to possible
        interactions between the optional components and their actual specification.  However, this is better
        than having optional components trigger errors because uninstalled software did not create uid's
        needed for operation.  The onus is on the service itself (in cproc) to assure that checking
        is performed.

        Note also that environments which use backtick expansions will *still* fail, because the backticks
        must occur within the context of the specified user, and it would be a security violation to
        allow a default.
        """
        super().__init__()

        #print("\n--ENV INIT", config, uid, from_env, from_env and getattr(from_env, 'uid', None))

        userenv = dict()

        # Inherit user from passed-in environment
        self._shadow = getattr(from_env, '_shadow', None)
        shadow = None  # we don't bother to recreate this in any complex fashion unless we need to

        if uid is None:
            self.uid = getattr(from_env, 'uid', self.uid)
            self.gid = getattr(from_env, 'gid', self.gid)
        else:
            pwrec = None
            try:
                pwrec = lookup_user(uid, gid)
            except ChNotFoundError:
                if resolve_xid:
                    raise
                self.uid = uid
                self.gid = gid

            if pwrec:
                self.uid = pwrec.pw_uid
                self.gid = pwrec.pw_gid
                userenv['HOME'] = pwrec.pw_dir
                userenv['USER'] = userenv['LOGNAME'] = pwrec.pw_name

        if not config:
            if from_env:
                self.update(from_env)
            self.update(userenv)
        else:
            inherit = config.get('env_inherit') or ['*']
            if inherit and from_env:
                self.update({
                    k: v
                    for k, v in from_env.items()
                    if any([fnmatch(k, pat) for pat in inherit])
                })
            self.update(userenv)

            add = config.get('env_set')
            unset = config.get('env_unset')

            if add or unset:
                self._shadow = shadow = (getattr(self, '_shadow')
                                         or _DICT_CONST).copy()

            if add:
                for k, v in add.items():
                    if from_env and k in from_env:
                        shadow[
                            k] = from_env  # we keep track of the environment where the predecessor originated
                    self[k] = v
            if unset:
                patmatch = lambda p: any([fnmatch(p, pat) for pat in unset])
                for delkey in [k for k in self.keys() if patmatch(k)]:
                    del self[delkey]
                for delkey in [k for k in shadow.keys() if patmatch(k)]:
                    del shadow[delkey]