From 80d204cc94f3514dc46387534eb9f8e4d72719ff Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Sat, 7 Oct 2023 13:56:41 +0200 Subject: Preserve setuid bits cleared by chown. --- perm_offset.py | 20 ++++++++++++++++---- 1 file 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" -- cgit v1.2.3