def check_permissions(perms, file_name_pattern): """ Verify that a given file has a given numeric permission. :param int perms: best given in octal form, e.g. 0o755 :param str file_name_pattern: can be a glob :raises: :py:class:`RuntimeError` if file has wrong permissions """ for file_name in iglob(file_name_pattern): actual_perms = S_IMODE(os.stat(file_name).st_mode) if perms != actual_perms: raise RuntimeError( f'file {file_name} has permissions {oct(actual_perms)} ' f'(should be {oct(perms)})!') LOG.debug('checked permissions %s of file %s', oct(perms), file_name)
def authorized_keys_permissions_ok(self) -> bool: """ Indicates whether ~/.ssh/authorized_keys exists, is owned by the user, and is only writable by the user. """ # pylint: disable=R0911 if not self.ssh_dir_permissions_ok: return False auth_keys = self.home + "/.ssh/authorized_keys" if not exists(auth_keys): log.debug("User %s does not have ~/.ssh/authorized_keys: %s", self.name, auth_keys) return False try: auth_keys_stat = stat(auth_keys) except OSError as e: log.error("Unable to stat %s: %s", auth_keys, e) return False if auth_keys_stat.st_uid != self.uid: log.warning( "User %s does not own ~/.ssh/authorized_keys file %s: user " "uid %d, owner uid %d", self.name, auth_keys, self.uid, auth_keys_stat.st_uid) return False if not S_ISREG(auth_keys_stat.st_mode): log.warning("User %s ~/.ssh/authorized_keys file %s is not a file", self.name, auth_keys) return False mode_bits = S_IMODE(auth_keys_stat.st_mode) if mode_bits & 0o020: log.warning( "User %s ~/.ssh/authorized_keys file %s is group-writable", self.name, auth_keys) return False if mode_bits & 0o002: log.warning( "User %s ~/.ssh/authorized_keys file %s is other-writable", self.name, auth_keys) return False return True
def ssh_dir_permissions_ok(self) -> bool: """ Indicates whether ~/.ssh exists, is a directory owned by the user, and is only writable by the user. """ # pylint: disable=R0911 home = self.home if not home: log.debug("User %s does not have a home directory set", self.name) return False ssh_dir = home + "/.ssh" if not exists(ssh_dir): log.debug("User %s does not have ~/.ssh directory: %s", self.name, ssh_dir) return False try: ssh_stat = stat(ssh_dir) except OSError as e: log.error("Unable to stat %s: %s", ssh_dir, e) return False if ssh_stat.st_uid != self.uid: log.warning( "User %s does not own ~/.ssh directory %s: user uid %d, " "owner uid %d", self.name, ssh_dir, self.uid, ssh_stat.st_uid) return False if not S_ISDIR(ssh_stat.st_mode): log.warning("User %s ~/.ssh direcotry %s is not a directory", self.name, ssh_dir) return False mode_bits = S_IMODE(ssh_stat.st_mode) if mode_bits & 0o020: log.warning("User %s ~/.ssh directory %s is group-writable", self.name, ssh_dir) return False if mode_bits & 0o002: log.warning("User %s ~/.ssh directory %s is other-writable", self.name, ssh_dir) return False return True
def copystat(src, dst): """Copy stat bits from src to dst This should be used when shutil.copystat would be used on directories on win32 because win32 does not support utime() for directories. According to the official docs written by Microsoft, it returns ENOACCES if the supplied filename is a directory. Looks like a trainee implemented the function. """ if sys.platform == 'win32' and S_ISDIR(os.stat(dst)[ST_MODE]): if os.name == 'nt': st = os.stat(src) mode = S_IMODE(st[ST_MODE]) if hasattr(os, 'chmod'): os.chmod(dst, mode) # KEEP THIS ONE! else: shutil.copystat(src, dst)
def test_rotation_permissions(tmp_path, permissions, set_umask): def file_permission_opener(file, flags): return os.open(file, flags, permissions) logger.add(tmp_path / "file.log", rotation=0, opener=file_permission_opener) logger.debug("Message") files = list(tmp_path.iterdir()) assert len(files) == 2 for filepath in files: stat_result = os.stat(str(filepath)) expected = 0o666 if os.name == "nt" else permissions assert S_IMODE(stat_result.st_mode) == expected
def make_executable(path): """ Modified version of conda/gateways/disk/permissions.py:make_executable at be8c08c083f4d5e05b06bd2689d2cd0d410c2ffe. Modifications included: * changed lstat -> os.lstat * changed chmod -> os.chmod * changed log.trace -> log.info (log.trace not supported) """ if isfile(path): mode = os.lstat(path).st_mode log.info('chmod +x %s', path) os.chmod(path, S_IMODE(mode) | S_IXUSR | S_IXGRP | S_IXOTH) else: log.error("Cannot make path '%s' executable", path)
def get_tmpdir_path(self, create_path=False): """Return the absolute path to secrets descriptions tmp directory""" tmpdir = self.get_environment_path() / "tmp" if create_path: tmpdir_mode = 0o700 try: os.makedirs(tmpdir, tmpdir_mode) self.logger.info("[+] created tmpdir %s", tmpdir) except FileExistsError: mode = os.stat(tmpdir).st_mode current_mode = S_IMODE(mode) if current_mode != tmpdir_mode: os.chmod(tmpdir, tmpdir_mode) self.logger.info("[+] changed mode on %s from %s to %s", oct(current_mode), oct(tmpdir_mode), tmpdir) return tmpdir
def checkpermissions(ddir, umode): uid = os.getuid() gid = os.getgid() try: stat = os.stat(ddir) except OSError: return if stat[ST_UID] != uid: try: os.chown(ddir, uid, gid) except: pass if S_IMODE(stat[ST_MODE]) != umode: try: os.chmod(ddir, umode) except: handle_exception() pass
def _file_needs_update(self, file_config): if not path.exists(file_config.get_dest()): return True if self._calculate_md5(file_config.get_src()) != self._calculate_md5( file_config.get_dest()): return True dest_stat = stat(file_config.get_dest()) if S_IMODE(dest_stat.st_mode) != self._convert_mode_to_int( file_config.get_mode()): return True dest_grp = getgrgid(dest_stat.st_gid) if dest_grp.gr_name != file_config.get_group(): return True dest_owner = getpwuid(dest_stat.st_uid) if dest_owner.pw_name != file_config.get_owner(): return True return False
def write_to_zipapp( archive: zipfile.ZipFile, arcname: str, data: bytes, date_time: Tuple[int, int, int, int, int, int], compression: int, stat: Optional[os.stat_result] = None, ) -> None: """Write a file or a bytestring to a ZipFile as a separate entry and update contents_hash as a side effect.""" zinfo = zipfile.ZipInfo(arcname, date_time=date_time) zinfo.compress_type = compression if stat: zinfo.external_attr = (S_IMODE(stat.st_mode) | S_IFMT(stat.st_mode)) << 16 archive.writestr(zinfo, data)
def get_authinfo_password(machine, login, port=None, prefix=None, srcpath=None): if not prefix: prefix = '' if not srcpath: srcpath = '~/.authinfo.gpg' srcfile = path.expanduser(srcpath) fstat = stat(srcfile) uid = getuid() if not fstat.st_uid == uid: print("Warning: {0} is not owned by current process's user (uid={1})". format(srcfile, uid), file=stderr) expected_mode = 0o600 if not S_IMODE(fstat.st_mode) == expected_mode: print('Warning: {0} should have mode {1}'.format( srcfile, oct(expected_mode)[2:]), file=stderr) authinfo = subprocess.check_output( ['gpg', '-q', '--no-tty', '-d', srcfile], universal_newlines=True) if port: p = re.compile( r'^machine\s*{0}\s*login\s*{1}\s*password\s*(\S*)\s*port\s*{2}\s*$' .format(re.escape(machine), re.escape(login), re.escape(port)), re.M) res = p.search(authinfo) if res: return prefix + res.group(1) p = re.compile( r'^machine\s*{0}\s*login\s*{1}\s*password\s*(\S*)\s*$'.format( re.escape(machine), re.escape(login)), re.M) res = p.search(authinfo) return prefix + res.group(1) if res else None
def __fetch_info(self): # lstat() does not follow sym links. try: info = os.lstat(self.__abs_path) is_symlink = True if S_ISLNK(info.st_mode) != 0 else False if Platform.isWindows: is_symlink = jaraco.windows.filesystem.is_reparse_point( self.__abs_path) dst_info = info if is_symlink: dst_info = os.stat(self.__abs_path) if info is not None: self.__dict.update({ 'exists': os.path.exists(self.__abs_path), 'size': info.st_size, 'r_size': 0, 'gid': info.st_gid, 'uid': info.st_uid, 'posix_perms': S_IMODE(info.st_mode), 'dir': S_ISDIR(dst_info.st_mode), 'create_date': info.st_ctime, 'mod_date': info.st_mtime, 'sym_link': is_symlink }) # if its a directory - collecting the size makes no sense, and in fact confuses the markup of checked/partially # modified scans - because changes to the posix perms can modify it? at least unit tests show that - anyway, we've # got no present use for directories with a size attribute. if self.is_dir: self.__dict.update({'size': 0}) else: # if its Mac, it might have the r_size and others if Platform.isMac and hasattr(info, 'r_size'): self.__dict.update({'r_size': info.r_size}) else: self.setDefaults() except OSError, err: # lookup on fs failed, fill in a blank directory logger.warn( "stat() on path '{0}' failed, using empty/blank defaults, error: {1}" .format(self.__abs_path, err)) self.setDefaults()
def copyfile(src, dst): try: f1 = open(src, "rb") if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) f2 = open(dst, "w+b") while True: buf = f1.read(16*1024) if not buf: break f2.write(buf) st = os.stat(src) mode = S_IMODE(st.st_mode) os.chmod(dst, mode) os.utime(dst, (st.st_atime, st.st_mtime)) except: print "copy", src, "to", dst, "failed!" return -1 return 0
def run (self): _install.run(self) # Rewrite with constants if needed for f in self.get_outputs(): # If is package __init__.py file holding some constants if os.path.basename(f) == '__init__.py': script = open(f, encoding='utf-8') content = script.read() script.close() const_begin = content.find('### CONSTANTS BEGIN ###') const_end = content.find('### CONSTANTS END ###') # If needs constants if (const_begin != -1) and (const_end != -1): log.info("Setting constants of %s" % f) at = os.stat(f) # Store attributes if self.install_data: replace_me = os.path.join(self.install_data,'share/qtarot') elif self.prefix: replace_me = os.path.join(self.prefix,'share/qtarot') if self.root == None: consts = [['DATA_DIR', replace_me.replace(os.sep,'/')]] elif self.root[-1] == '/': consts = [['DATA_DIR', replace_me.replace(self.root[:-2],'')]] else: consts = [['DATA_DIR', replace_me.replace(self.root,'')]] script = open(f, 'w', encoding='utf-8') script.write(content[:const_begin] + \ "### CONSTANTS BEGIN ###") for const in consts: script.write("\n{} = '{}'".format(const[0], const[1])) script.write("\n" + content[const_end:]) script.close() # Restore attributes os.utime(f, (at[ST_ATIME], at[ST_MTIME])) os.chmod(f, S_IMODE(at[ST_MODE]))
def fpopen(*args, **kwargs): ''' Shortcut for fopen with extra uid, gid, and mode options. Supported optional Keyword Arguments: mode Explicit mode to set. Mode is anything os.chmod would accept as input for mode. Works only on unix/unix-like systems. uid The uid to set, if not set, or it is None or -1 no changes are made. Same applies if the path is already owned by this uid. Must be int. Works only on unix/unix-like systems. gid The gid to set, if not set, or it is None or -1 no changes are made. Same applies if the path is already owned by this gid. Must be int. Works only on unix/unix-like systems. ''' # Remove uid, gid and mode from kwargs if present uid = kwargs.pop('uid', -1) # -1 means no change to current uid gid = kwargs.pop('gid', -1) # -1 means no change to current gid mode = kwargs.pop('mode', None) with fopen(*args, **kwargs) as f_handle: path = args[0] d_stat = os.stat(path) if hasattr(os, 'chown'): # if uid and gid are both -1 then go ahead with # no changes at all if (d_stat.st_uid != uid or d_stat.st_gid != gid) and \ [i for i in (uid, gid) if i != -1]: os.chown(path, uid, gid) if mode is not None: mode_part = S_IMODE(d_stat.st_mode) if mode_part != mode: os.chmod(path, (d_stat.st_mode ^ mode_part) | mode) yield f_handle
def take_action(self, parsed_args): self.LOG.debug('returning environment path') e = SecretsEnvironment(environment=self.app.options.environment) if parsed_args.tmpdir: tmpdir = e.tmpdir_path() tmpdir_mode = 0o700 try: os.makedirs(tmpdir, tmpdir_mode) self.LOG.info('created tmpdir {}'.format(tmpdir)) except FileExistsError: mode = os.stat(tmpdir).st_mode current_mode = S_IMODE(mode) if current_mode != tmpdir_mode: os.chmod(tmpdir, tmpdir_mode) self.LOG.info('changed mode on {} from {} to {}'.format( tmpdir, oct(current_mode), oct(tmpdir_mode))) finally: self._print(tmpdir, parsed_args.json) else: self._print(e.environment_path(), parsed_args.json)
def copy_file(src, dst, preserve_mode=1, preserve_times=1, update=0, link=None, verbose=1, dry_run=0): from distutils.dep_util import newer from stat import ST_ATIME, ST_MTIME, ST_MODE, S_IMODE if not os.path.isfile(src): raise DistutilsFileError("can't copy '%s': doesn't exist or not a regular file" % src) if os.path.isdir(dst): dir = dst dst = os.path.join(dst, os.path.basename(src)) else: dir = os.path.dirname(dst) if update and not newer(src, dst): if verbose >= 1: log.debug('not copying %s (output up-to-date)', src) return (dst, 0) try: action = _copy_action[link] except KeyError: raise ValueError("invalid value '%s' for 'link' argument" % link) if verbose >= 1: if os.path.basename(dst) == os.path.basename(src): log.info('%s %s -> %s', action, src, dir) else: log.info('%s %s -> %s', action, src, dst) if dry_run: return (dst, 1) if link == 'hard': if not (os.path.exists(dst) and os.path.samefile(src, dst)): os.link(src, dst) elif link == 'sym': if not (os.path.exists(dst) and os.path.samefile(src, dst)): os.symlink(src, dst) else: _copy_file_contents(src, dst) if preserve_mode or preserve_times: st = os.stat(src) if preserve_times: os.utime(dst, (st[ST_ATIME], st[ST_MTIME])) if preserve_mode: os.chmod(dst, S_IMODE(st[ST_MODE])) return (dst, 1)
def copyfile(src, dst): f1 = None f2 = None status = 0 try: f1 = open(src, "rb") if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) f2 = open(dst, "w+b") while True: buf = f1.read(16 * 1024) if not buf: break f2.write(buf) except (IOError, OSError) as err: print("[Directories] Error %d: Copying file '%s' to '%s'! (%s)" % (err.errno, src, dst, err.strerror)) status = -1 if f1 is not None: f1.close() if f2 is not None: f2.close() try: st = os.stat(src) try: os.chmod(dst, S_IMODE(st.st_mode)) except (IOError, OSError) as err: print( "[Directories] Error %d: Setting modes from '%s' to '%s'! (%s)" % (err.errno, src, dst, err.strerror)) try: os.utime(dst, (st.st_atime, st.st_mtime)) except (IOError, OSError) as err: print( "[Directories] Error %d: Setting times from '%s' to '%s'! (%s)" % (err.errno, src, dst, err.strerror)) except (IOError, OSError) as err: print( "[Directories] Error %d: Obtaining stats from '%s' to '%s'! (%s)" % (err.errno, src, dst, err.strerror)) return status
def checkpermissions(ddir, umode): """ see if ddir has umode permission and if not set them. """ try: uid = os.getuid() gid = os.getgid() except AttributeError: return try: stat = os.stat(ddir) except OSError: return if stat[ST_UID] != uid: try: os.chown(ddir, uid, gid) except: pass if S_IMODE(stat[ST_MODE]) != umode: try: os.chmod(ddir, umode) except: handle_exception()
def add_file(self, fname, stats): """ Appends file(s) added to report """ if not self.enabled: return cfile = self.files.newChild(None, "file", None) cfile.setNsProp(None, "fname", fname) cchild = cfile.newChild(None, "uid", str(stats[ST_UID])) cchild = cfile.newChild(None, "gid", str(stats[ST_GID])) cfile.newChild(None, "mode", str(oct(S_IMODE(stats[ST_MODE])))) cchild = cfile.newChild(None, "ctime", strftime('%a %b %d %H:%M:%S %Y', localtime(stats[ST_CTIME]))) cchild.setNsProp(None, "tstamp", str(stats[ST_CTIME])) cchild = cfile.newChild(None, "atime", strftime('%a %b %d %H:%M:%S %Y', localtime(stats[ST_ATIME]))) cchild.setNsProp(None, "tstamp", str(stats[ST_ATIME])) cchild = cfile.newChild(None, "mtime", strftime('%a %b %d %H:%M:%S %Y', localtime(stats[ST_MTIME]))) cchild.setNsProp(None, "tstamp", str(stats[ST_MTIME]))
def get_ftype_and_perm(mode): """ Returns a tuple of whether the file is: file(regular file)/dir/slink /char. spec/block spec/pipe/socket and the permission bits of the file. If it does not match any of the cases below (it will return "unknown" twice)""" if S_ISREG(mode): return "file", S_IMODE(mode) if S_ISDIR(mode): return "dir", S_IMODE(mode) if S_ISLNK(mode): return "slink", S_IMODE(mode) if S_ISCHR(mode): return "character special", S_IMODE(mode) if S_ISBLK(mode): return "block special", S_IMODE(mode) if S_ISFIFO(mode): return "pipe", S_IMODE(mode) if S_ISSOCK(mode): return "socket", S_IMODE(mode) return "unknown", "unknown"
def copytree(src, dst, symlinks=False): names = os.listdir(src) if os.path.isdir(dst): dst = os.path.join(dst, os.path.basename(src)) if not os.path.isdir(dst): os.mkdir(dst) else: os.makedirs(dst) for name in names: srcname = os.path.join(src, name) dstname = os.path.join(dst, name) try: if symlinks and os.path.islink(srcname): linkto = os.readlink(srcname) os.symlink(linkto, dstname) elif os.path.isdir(srcname): copytree(srcname, dstname, symlinks) else: copyfile(srcname, dstname) except (IOError, OSError) as err: print("[Directories] Error %d: Copying tree '%s' to '%s'! (%s)" % (err.errno, srcname, dstname, err.strerror)) try: st = os.stat(src) try: os.chmod(dst, S_IMODE(st.st_mode)) except (IOError, OSError) as err: print( "[Directories] Error %d: Setting modes from '%s' to '%s'! (%s)" % (err.errno, src, dst, err.strerror)) try: os.utime(dst, (st.st_atime, st.st_mtime)) except (IOError, OSError) as err: print( "[Directories] Error %d: Setting times from '%s' to '%s'! (%s)" % (err.errno, src, dst, err.strerror)) except (IOError, OSError) as err: print( "[Directories] Error %d: Obtaining stats from '%s' to '%s'! (%s)" % (err.errno, src, dst, err.strerror))
def copyTree(src, dst, symlinks=False): names = listdir(src) if isdir(dst): dst = pathjoin(dst, basename(src)) if not isdir(dst): mkdir(dst) else: makedirs(dst) for name in names: srcName = pathjoin(src, name) dstName = pathjoin(dst, name) try: if symlinks and islink(srcName): linkTo = readlink(srcName) symlink(linkTo, dstName) elif isdir(srcName): copytree(srcName, dstName, symlinks) else: copyfile(srcName, dstName) except (IOError, OSError) as err: print("[Directories] Error %d: Copying tree '%s' to '%s'! (%s)" % (err.errno, srcName, dstName, err.strerror)) try: status = stat(src) try: chmod(dst, S_IMODE(status.st_mode)) except (IOError, OSError) as err: print( "[Directories] Error %d: Setting modes from '%s' to '%s'! (%s)" % (err.errno, src, dst, err.strerror)) try: utime(dst, (status.st_atime, status.st_mtime)) except (IOError, OSError) as err: print( "[Directories] Error %d: Setting times from '%s' to '%s'! (%s)" % (err.errno, src, dst, err.strerror)) except (IOError, OSError) as err: print( "[Directories] Error %d: Obtaining stats from '%s' to '%s'! (%s)" % (err.errno, src, dst, err.strerror))
def take_action(self, parsed_args): self.LOG.debug('[*] returning environment path') environment = self.app.options.environment e = psec.secrets.SecretsEnvironment(environment) if parsed_args.tmpdir: tmpdir = e.tmpdir_path() tmpdir_mode = 0o700 try: os.makedirs(tmpdir, tmpdir_mode) self.LOG.info(f"[+] created tmpdir {tmpdir}") except FileExistsError: mode = os.stat(tmpdir).st_mode current_mode = S_IMODE(mode) if current_mode != tmpdir_mode: os.chmod(tmpdir, tmpdir_mode) self.LOG.info( f"[+] changed mode on {tmpdir} " f"from {oct(current_mode)} to {oct(tmpdir_mode)}") finally: self._print(tmpdir, parsed_args.json) else: base_path = e.environment_path() subdir = parsed_args.subdir full_path = base_path if subdir is None \ else os.path.join(base_path, *subdir) if not os.path.exists(full_path) and parsed_args.create: mode = 0o700 os.makedirs(full_path, mode) if self.app_args.verbose_level > 1: self.LOG.info(f"[+] created {full_path}") if parsed_args.exists: # Just check existance and return result exists = os.path.exists(full_path) if self.app_args.verbose_level > 1: status = "exists" if exists else "does not exist" self.LOG.info( f"[+] environment path '{full_path}' {status}") return 0 if exists else 1 else: self._print(full_path, parsed_args.json)
def zips_to_dirs(zipfiles, output_base_dir=None, quiet=True): """ Converts zip files into directories. If output_base_dir is provided, the source files are not destroyed. Otherwise, this happens in-place. The directory names match the zip filenames exactly, as do the file permissions and times. """ if isinstance(zipfiles, basestring): zipfiles = glob.glob(zipfiles) for zipfile in zipfiles: statinfo = os.stat(zipfile) if output_base_dir: outdir = posixpath.join(output_base_dir, posixpath.basename(zipfile)) else: outdir = zipfile + '.tmp' flags = '-oq' if quiet else '-o' # Error 1 means no files were unzipped (empty zip file) - that's ok. _zip_exec(['unzip', flags, zipfile, '-d', outdir], ok=(0, 1)) if not output_base_dir: os.remove(zipfile) os.rename(outdir, zipfile) os.chmod(zipfile, S_IMODE(statinfo.st_mode) | 0111) # turn on x bits os.utime(zipfile, (statinfo.st_atime, statinfo.st_mtime))
def dirs_to_zips(dirs, quiet=True): """ Converts directories into zip files in-place. The zip filename matches the directory name exactly, as do the file permissions and times. 'dirs' can be an iterable of strings, or a single string with wildcards.""" if isinstance(dirs, basestring): dirs = glob.glob(dirs) for dir in dirs: dir = dir.rstrip('/') statinfo = os.stat(dir) if not S_ISDIR(statinfo.st_mode): raise Exception('%s is not a directory' % dir) outfile = os.path.abspath('%s.tmp' % dir) flags = '-Rmq' if quiet else '-Rm' if _zip_exec(['zip', flags, outfile, '*'], cwd=dir, ok=(0, 12)) == 12: # Error 12 means no input files (empty dir). # We'll just create an empty zipfile directly instead. open(outfile, 'wb').write('PK\5\6' + '\0' * 18) os.rmdir(dir) os.rename(outfile, dir) os.chmod(dir, S_IMODE(statinfo.st_mode) ^ 0111) # turn off execute bits os.utime(dir, (statinfo.st_atime, statinfo.st_mtime))
def _check_reset_group_other_writable(filename: str, mode: int) -> None: """ ShadowDatabase._check_reset_group_other_writable( filename: str, mode: int) -> None If filename is writable by group or other, log this information and reset those bits. """ group_writable = (mode & 0o020 != 0) other_writable = (mode & 0o002 != 0) who = [] if group_writable: who.append("group") if other_writable: who.append("other") if not who: return log.warning("%s is writable by %s; resetting these bits.", filename, " and ".join(who)) chmod(filename, S_IMODE(mode) & 0o755)
def __get_or_create_dir(parent: str, name: str, mode: int = 0o700) -> str: from stat import S_ISDIR, S_IMODE path = os.path.join(parent, name) path = os.path.abspath(path) create = True try: stat = os.stat(path) if not S_ISDIR(stat.st_mode): raise Exception('Not a directory: ' + repr(path)) elif S_IMODE(stat.st_mode) != mode: os.chmod(path=path, mode=mode) else: create = False except FileNotFoundError: pass if create: os.makedirs(path, 0o700, True) return path
def update_prefix(path, new_prefix, placeholder=PREFIX_PLACEHOLDER, mode=FileMode.text): if on_win and mode == FileMode.text: # force all prefix replacements to forward slashes to simplify need to escape backslashes # replace with unix-style path separators new_prefix = new_prefix.replace('\\', '/') path = realpath(path) with open(path, 'rb') as fi: original_data = data = fi.read() data = replace_prefix(mode, data, placeholder, new_prefix) if not on_win: data = replace_long_shebang(mode, data) if data == original_data: return st = lstat(path) with exp_backoff_fn(open, path, 'wb') as fo: fo.write(data) chmod(path, S_IMODE(st.st_mode))
def test_permissions_warnings(self): """Make sure letsencrypt-auto properly warns about permissions problems.""" # This test assumes that only the parent of the directory containing # letsencrypt-auto (usually /tmp) may have permissions letsencrypt-auto # considers insecure. with temp_paths() as (le_auto_path, venv_dir): le_auto_path = abspath(le_auto_path) le_auto_dir = dirname(le_auto_path) le_auto_dir_parent = dirname(le_auto_dir) install_le_auto(self.NEW_LE_AUTO, le_auto_path) run_letsencrypt_auto = partial( run_le_auto, le_auto_path, venv_dir, le_auto_args_str='--install-only --no-self-upgrade', PIP_FIND_LINKS=join(tests_dir(), 'fake-letsencrypt', 'dist')) # Run letsencrypt-auto once with current permissions to avoid # potential problems when the script tries to write to temporary # directories. run_letsencrypt_auto() le_auto_dir_mode = stat(le_auto_dir).st_mode le_auto_dir_parent_mode = S_IMODE(stat(le_auto_dir_parent).st_mode) try: # Make letsencrypt-auto happy with the current permissions chmod(le_auto_dir, S_IRUSR | S_IXUSR) sudo_chmod(le_auto_dir_parent, 0o755) self._test_permissions_warnings_about_path( le_auto_path, run_letsencrypt_auto) self._test_permissions_warnings_about_path( le_auto_dir, run_letsencrypt_auto) finally: chmod(le_auto_dir, le_auto_dir_mode) sudo_chmod(le_auto_dir_parent, le_auto_dir_parent_mode)