def symlink_atomically(srcpath, dstpath, force=False, preserve_context=True): """Create a symlink, optionally replacing dstpath atomically, optionally setting or preserving SELinux context.""" dstdname = os.path.dirname(dstpath) dstbname = os.path.basename(dstpath) run_restorecon = False ctx = None if preserve_context and selinux.is_selinux_enabled() <= 0: preserve_context = False else: try: ret, ctx = selinux.lgetfilecon(dstpath) if ret < 0: raise RuntimeError("getfilecon(%r) failed" % dstpath) except OSError as e: if e.errno == errno.ENOENT: run_restorecon = True else: raise if not force: os.symlink(srcpath, dstpath) if preserve_context: selinux.restorecon(dstpath) else: dsttmp = None for attempt in range(tempfile.TMP_MAX): _dsttmp = tempfile.mktemp( prefix=dstbname + os.extsep, dir=dstdname) try: os.symlink(srcpath, _dsttmp) except OSError as e: if e.errno == errno.EEXIST: # try again continue raise else: dsttmp = _dsttmp break if dsttmp is None: raise IOError( errno.EEXIST, "No suitable temporary symlink could be created.") if preserve_context and not run_restorecon: selinux.lsetfilecon(dsttmp, ctx) try: os.rename(dsttmp, dstpath) except: # clean up os.remove(dsttmp) raise if run_restorecon: selinux.restorecon(dstpath)
def restoreSecurityContext_api(path, recursive=False): """ restorecon() wrapper. path - can be a single string or a list returns True if successful or False if there was a problem """ try: logger = TCSLogger.TCSLogger.getInstance(6) except TCSLogger.SingletonException: logger = TCSLogger.TCSLogger.getInstance() if type(path).__name__ == 'str': if os.path.exists(path): contextCurrent = "" notes = "" rpath = os.path.realpath(path) if rpath != path: notes = "(%s)" % rpath myerror = None try: contextCurrent = selinux.getfilecon(rpath)[1] except: pass try: # unfortunately not all RH5 boxes have 'restorecon' as part of the python bindings. Since we never # do this recursively, we'll explicitly do the matchpathcon/lsetfilecon ourselves. mode = os.stat(rpath)[stat.ST_MODE] status, contextRestore = selinux.matchpathcon(rpath, mode) if status == 0: # On the advice of our inhouse SELinux experts, we are intentially disregarding a potential 'user' mismatch # We know that especially for daemon processes in targetted mode we could be either user_u or system_u # depending on how the daemon started. if contextRestore.split(':')[1:] != contextCurrent.split( ':')[1:]: selinux.lsetfilecon(rpath, contextRestore) if notes: msg = """OS Lockdown reset context of '%s' (actually '%s') to '%s'""" % ( path, notes, contextRestore) else: msg = """OS Lockdown reset context of '%s' to '%s'""" % ( path, contextRestore) logger.info(MODULE_NAME, msg) else: myerror = "Unable to get default context for '%s'" % path except OSError, err: myerror = err if myerror != None: logger.error(MODULE_NAME, str(myerror)) return False else: msg = """OS Lockdown trying to restore context of '%s' which does not exist.""" % ( path) logger.warn(MODULE_NAME, msg)
def set_context_if_different(self, path, context, changed): if not HAVE_SELINUX or not self.selinux_enabled(): return changed cur_context = self.selinux_context(path) new_context = list(cur_context) # Iterate over the current context instead of the # argument context, which may have selevel. (is_nfs, nfs_context) = self.is_nfs_path(path) if is_nfs: new_context = nfs_context else: for i in range(len(cur_context)): if len(context) > i: if context[i] is not None and context[i] != cur_context[i]: new_context[i] = context[i] if context[i] is None: new_context[i] = cur_context[i] if cur_context != new_context: try: if self.check_mode: return True rc = selinux.lsetfilecon(self._to_filesystem_str(path), str(':'.join(new_context))) except OSError: self.fail_json(path=path, msg='invalid selinux context', new_context=new_context, cur_context=cur_context, input_was=context) if rc != 0: self.fail_json(path=path, msg='set selinux context failed') changed = True return changed
def _set_secontext(self, entry, path=None): """ set the SELinux context of the file on disk according to the config""" if not HAS_SELINUX: return True if path is None: path = entry.get("name") context = entry.get("secontext") if not context: # no context listed return True if context == '__default__': try: selinux.restorecon(path) rv = True except OSError: err = sys.exc_info()[1] self.logger.error("POSIX: Failed to restore SELinux context " "for %s: %s" % (path, err)) rv = False else: try: rv = selinux.lsetfilecon(path, context) == 0 except OSError: err = sys.exc_info()[1] self.logger.error("POSIX: Failed to restore SELinux context " "for %s: %s" % (path, err)) rv = False return rv
def set_file_context(path, context, root=None): """ Set the SELinux file context of a file. Arguments: path filename string context context string Keyword Arguments: root an optional chroot string Return Value: True if successful, False if not. """ if root is None: root = '/' full_path = os.path.normpath("%s/%s" % (root, path)) if context is None or not os.access(full_path, os.F_OK): return False try: rc = (selinux.lsetfilecon(full_path, context) == 0) except OSError as e: log.info("failed to set SELinux context for %s: %s", full_path, e) rc = False return rc
def _set_secontext(self, entry, path=None): # pylint: disable=R0911 """ set the SELinux context of the file on disk according to the config""" if not HAS_SELINUX: return True if path is None: path = entry.get("name") context = entry.get("secontext") if not context: # no context listed return True secontext = selinux.lgetfilecon(path)[1].split(":")[2] if secontext in Bcfg2.Options.setup.secontext_ignore: return True try: if context == '__default__': selinux.restorecon(path) return True else: return selinux.lsetfilecon(path, context) == 0 except OSError: err = sys.exc_info()[1] if err.errno == errno.EOPNOTSUPP: # Operation not supported if context != '__default__': self.logger.debug("POSIX: Failed to set SELinux context " "for %s: %s" % (path, err)) return False return True err = sys.exc_info()[1] self.logger.error("POSIX: Failed to set or restore SELinux " "context for %s: %s" % (path, err)) return False
def set_context_if_different(self, path, context, changed): if not HAVE_SELINUX or not self.selinux_enabled(): return changed cur_context = self.selinux_context(path) new_context = list(cur_context) # Iterate over the current context instead of the # argument context, which may have selevel. for i in range(len(cur_context)): if len(context) > i: if context[i] is not None and context[i] != cur_context[i]: new_context[i] = context[i] if context[i] is None: new_context[i] = cur_context[i] if cur_context != new_context: try: if self.check_mode: return True rc = selinux.lsetfilecon(self._to_filesystem_str(path), str(':'.join(new_context))) except OSError: self.fail_json(path=path, msg='invalid selinux context', new_context=new_context, cur_context=cur_context, input_was=context) if rc != 0: self.fail_json(path=path, msg='set selinux context failed') changed = True return changed
def setFileContext(fn, con, instroot = '/'): full_path = os.path.normpath("%s/%s" % (instroot, fn)) rc = False if con is not None and os.access(full_path, os.F_OK): try: rc = (selinux.lsetfilecon(full_path, con) == 0) except OSError as e: log.info("failed to set SELinux context for %s: %s" % (full_path, e)) return rc
def chcon(self, context): # If dir returns whether to recusively set context try: try: selinux.lsetfilecon(self.path, context) LOG.info('Setting selinux context of %s to %s', self.path, context) return True except OSError as e: if self.is_dir and e.errno == 95: # Operation not supported, assume NFS mount and skip LOG.info('Setting selinux context not supported for %s', self.path) return False else: raise except Exception: LOG.exception('Could not set selinux context of %s to %s:', self.path, context) raise
def _chown_chmod_chcon(self, temp_file_path, dest_path, file_info, strict_ownership=1): if file_info['filetype'] != 'symlink': uid = file_info.get('uid') if uid is None: if 'username' in file_info: # determine uid try: user_record = pwd.getpwnam(file_info['username']) uid = user_record[2] except Exception: e = sys.exc_info()[1] #Check if username is an int try: uid = int(file_info['username']) except ValueError: raise_with_tb( cfg_exceptions.UserNotFound( file_info['username']), sys.exc_info()[2]) else: #default to root (3.2 sats) uid = 0 gid = file_info.get('gid') if gid is None: if 'groupname' in file_info: # determine gid try: group_record = grp.getgrnam(file_info['groupname']) gid = group_record[2] except Exception: e = sys.exc_info()[1] try: gid = int(file_info['groupname']) except ValueError: raise_with_tb( cfg_exceptions.GroupNotFound( file_info['groupname']), sys.exc_info()[2]) else: #default to root (3.2 sats) gid = 0 try: if file_info['filetype'] != 'symlink': os.chown(temp_file_path, uid, gid) mode = '600' if 'filemode' in file_info: if file_info['filemode'] is "": mode = '000' else: mode = file_info['filemode'] mode = int(str(mode), 8) os.chmod(temp_file_path, mode) if 'selinux_ctx' in file_info: sectx = file_info.get('selinux_ctx') if sectx is not None and sectx is not "": log_debug(1, "selinux context: " + sectx) try: if lsetfilecon(temp_file_path, sectx) < 0: raise Exception( "failed to set selinux context on %s" % dest_path) except OSError: e = sys.exc_info()[1] raise_with_tb( Exception( "failed to set selinux context on %s" % dest_path, e), sys.exc_info()[2]) except OSError: e = sys.exc_info()[1] if e.errno == errno.EPERM and not strict_ownership: sys.stderr.write( "cannonical file ownership and permissions lost on %s\n" % dest_path) else: raise
def set_selinux_context(path, context): """ Sets selinux context, returns False on error and None if selinux is not available """ if context == get_selinux_context(path): return True else: return not bool(selinux.lsetfilecon(path, ':'.join(context)))
def lsetfilecon(path, context): selinux.lsetfilecon(path, context)
def _chown_chmod_chcon(self, temp_file_path, dest_path, file_info, strict_ownership=1): if file_info['filetype'] != 'symlink': uid = file_info.get('uid') if uid is None: if 'username' in file_info: # determine uid try: user_record = pwd.getpwnam(file_info['username']) uid = user_record[2] except Exception: e = sys.exc_info()[1] #Check if username is an int try: uid = int(file_info['username']) except ValueError: raise_with_tb(cfg_exceptions.UserNotFound(file_info['username']), sys.exc_info()[2]) else: #default to root (3.2 sats) uid = 0 gid = file_info.get('gid') if gid is None: if 'groupname' in file_info: # determine gid try: group_record = grp.getgrnam(file_info['groupname']) gid = group_record[2] except Exception: e = sys.exc_info()[1] try: gid = int(file_info['groupname']) except ValueError: raise_with_tb(cfg_exceptions.GroupNotFound(file_info['groupname']), sys.exc_info()[2]) else: #default to root (3.2 sats) gid = 0 try: if file_info['filetype'] != 'symlink': os.chown(temp_file_path, uid, gid) mode = '600' if 'filemode' in file_info: if file_info['filemode'] is "": mode='000' else: mode = file_info['filemode'] mode = int(str(mode), 8) os.chmod(temp_file_path, mode) if 'selinux_ctx' in file_info: sectx = file_info.get('selinux_ctx') if sectx is not None and sectx is not "": log_debug(1, "selinux context: " + sectx); try: if lsetfilecon(temp_file_path, sectx) < 0: raise Exception("failed to set selinux context on %s" % dest_path) except OSError: e = sys.exc_info()[1] raise_with_tb(Exception("failed to set selinux context on %s" % dest_path, e), sys.exc_info()[2]) except OSError: e = sys.exc_info()[1] if e.errno == errno.EPERM and not strict_ownership: sys.stderr.write("cannonical file ownership and permissions lost on %s\n" % dest_path) else: raise
os.symlink(srcpath, _dsttmp) except OSError, e: if e.errno == errno.EEXIST: # try again continue raise else: dsttmp = _dsttmp break if dsttmp is None: raise IOError(errno.EEXIST, "No suitable temporary symlink could be created.") if preserve_context and not run_restorecon: selinux.lsetfilecon(dsttmp, ctx) try: os.rename(dsttmp, dstpath) except: # clean up os.remove(dsttmp) raise if run_restorecon: selinux.restorecon(dstpath) def overwrite_safely(path, content, preserve_mode=True, preserve_context=True): """Safely overwrite a file by creating a temporary file in the same directory, writing it, moving it over the original file, eventually
def trySetfilecon(src, dest): try: selinux.lsetfilecon(dest, selinux.lgetfilecon(src)[1]) except OSError: log.error("Could not set selinux context on file %s" % dest)
mode = '600' if file_info.has_key('filemode'): if file_info['filemode'] is "": mode='000' else: mode = file_info['filemode'] mode = string.atoi(str(mode), 8) os.chmod(temp_file_path, mode) if file_info.has_key('selinux_ctx'): sectx = file_info.get('selinux_ctx') if sectx is not None and sectx is not "": log_debug(1, "selinux context: " + sectx); try: if lsetfilecon(temp_file_path, sectx) < 0: raise Exception("failed to set selinux context on %s" % dest_path) except OSError, e: raise Exception("failed to set selinux context on %s" % dest_path, e), None, sys.exc_info()[2] except OSError, e: if e.errno == errno.EPERM and not strict_ownership: sys.stderr.write("cannonical file ownership and permissions lost on %s\n" % dest_path) else: raise def _normalize_path_to_root(self, path): if self.transaction_root: path = utils.normalize_path(self.transaction_root + os.sep + path)
def lsetfilecon(filename, context): if __enabled < 0: return if not context: return 0 return selinux.lsetfilecon(filename, context)
mode = '600' if file_info.has_key('filemode'): if file_info['filemode'] is "": mode = '000' else: mode = file_info['filemode'] mode = string.atoi(str(mode), 8) os.chmod(temp_file_path, mode) if file_info.has_key('selinux_ctx'): sectx = file_info.get('selinux_ctx') if sectx is not None and sectx is not "": log_debug(1, "selinux context: " + sectx) try: if lsetfilecon(temp_file_path, sectx) < 0: raise Exception( "failed to set selinux context on %s" % dest_path) except OSError, e: raise Exception( "failed to set selinux context on %s" % dest_path, e), None, sys.exc_info()[2] except OSError, e: if e.errno == errno.EPERM and not strict_ownership: sys.stderr.write( "cannonical file ownership and permissions lost on %s\n" % dest_path) else: raise
def trySetfilecon(src, dest): try: selinux.lsetfilecon(dest, selinux.lgetfilecon(src)[1]) except: log.error("Could not set selinux context on file %s" % dest)