diff options
author | Anton Khirnov <anton@khirnov.net> | 2023-10-07 13:56:41 +0200 |
---|---|---|
committer | Anton Khirnov <anton@khirnov.net> | 2023-10-07 19:09:04 +0200 |
commit | 80d204cc94f3514dc46387534eb9f8e4d72719ff (patch) | |
tree | d2a0b612dc3afcf13c5bf179a4dd7986c18fa614 | |
parent | 71f9452cca49bcd9da0ddda3047c2e18e58b9083 (diff) |
Preserve setuid bits cleared by chown.
-rwxr-xr-x | perm_offset.py | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/perm_offset.py b/perm_offset.py index 4e13eb3..3f23ab1 100755 --- a/perm_offset.py +++ b/perm_offset.py @@ -3,6 +3,7 @@ import argparse import logging import os +from stat import S_IMODE, S_ISLNK import sys def remap_file(fpath, src, dst, count, dry_run): @@ -15,10 +16,21 @@ def remap_file(fpath, src, dst, count, dry_run): if gid >= src and gid < src + count: gid += dst - src - logging.debug('chown(%s, %d->%d, %d->%d)' % (fpath, stat.st_uid, uid, - stat.st_gid, gid)) - if not dry_run: - os.chown(fpath, uid, gid, follow_symlinks = False) + mode = S_IMODE(stat.st_mode) + + logging.debug('chown(%s, mode=%o %d->%d, %d->%d)' % + (fpath, mode, stat.st_uid, uid, stat.st_gid, gid)) + if dry_run: + return + + if S_ISLNK(stat.st_mode) and not os.chown in os.supports_follow_symlinks: + return + os.chown(fpath, uid, gid, follow_symlinks = False) + + # chown may clear setuid bits, so make sure to preserve them + if S_ISLNK(stat.st_mode) and not os.chmod in os.supports_follow_symlinks: + return + os.chmod(fpath, mode, follow_symlinks = False) parser = argparse.ArgumentParser( description = "Remap UIDs/GIDs in a directory tree from one range to another" |