From 6554cfa87e01bc606cb6ff9566e7e96808d02e91 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bj=C3=B6rn=20Baumbach?= Date: Tue, 11 Jun 2019 15:11:20 +0200 Subject: [PATCH] samba-tool: add ntacl changedomsid command MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This tool is meant to locally change all entries in acl_xattr when the machine's SID has accidentially changed or the data set has been copied to another box either via backup/restore or rsync. Signed-off-by: Björn Baumbach Reviewed-by: Stefan Metzmacher --- python/samba/netcmd/ntacl.py | 164 +++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/python/samba/netcmd/ntacl.py b/python/samba/netcmd/ntacl.py index e366ee72554..4cc7737ae77 100644 --- a/python/samba/netcmd/ntacl.py +++ b/python/samba/netcmd/ntacl.py @@ -25,6 +25,7 @@ from samba.ndr import ndr_unpack, ndr_print from samba.samdb import SamDB from samba.samba3 import param as s3param, passdb, smbd from samba import provision +import os from samba.auth import ( system_session, @@ -195,6 +196,168 @@ class cmd_ntacl_get(Command): self.outf.write(ndr_print(acl)) +class cmd_ntacl_changedomsid(Command): + """Change the domain SID for ACLs""" + synopsis = "%prog [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + } + + takes_options = [ + Option( + "--service", + help="Name of the smb.conf service to use", + type="string"), + Option( + "--use-ntvfs", + help=("Set the ACLs directly to the TDB or xattr for use with the " + "ntvfs file server"), + action="store_true"), + Option( + "--use-s3fs", + help=("Set the ACLs for use with the default s3fs file server via " + "the VFS layer"), + action="store_true"), + Option( + "--eadb-file", + help="Name of the tdb file where attributes are stored", + type="string"), + Option( + "--xattr-backend", + type="choice", + help="xattr backend type (native fs or tdb)", + choices=["native", "tdb"]), + Option( + "-r", + "--recursive", + help="Set the ACLs for directories and their contents recursively", + action="store_true"), + Option( + "--follow-symlinks", + help="Follow symlinks", + action="store_true"), + Option( + "-v", + "--verbose", + help="Be verbose", + action="store_true"), + ] + + takes_args = ["old_domain_sid", "new_domain_sid", "file"] + + def run(self, + old_domain_sid_str, + new_domain_sid_str, + file, + use_ntvfs=False, + use_s3fs=False, + service=None, + xattr_backend=None, + eadb_file=None, + sambaopts=None, + recursive=False, + follow_symlinks=False, + verbose=False): + logger = self.get_logger() + lp = sambaopts.get_loadparm() + domain_sid = get_local_domain_sid(lp) + + if not use_ntvfs and not use_s3fs: + use_ntvfs = "smb" in lp.get("server services") + elif use_s3fs: + use_ntvfs = False + + if not use_ntvfs and not service: + raise CommandError( + "Must provide a share name with --service=") + + try: + old_domain_sid = security.dom_sid(old_domain_sid_str) + except Exception as e: + raise CommandError("Could not parse old sid %s: %s" % + (old_domain_sid_str, e)) + + try: + new_domain_sid = security.dom_sid(new_domain_sid_str) + except Exception as e: + raise CommandError("Could not parse old sid %s: %s" % + (new_domain_sid_str, e)) + + def changedom_sids(file): + if verbose: + self.outf.write("file: %s\n" % file) + + try: + acl = getntacl(lp, + file, + xattr_backend, + eadb_file, + direct_db_access=use_ntvfs, + service=service, + session_info=system_session_unix()) + except Exception as e: + raise CommandError("Could not get acl for %s: %s" % (file, e)) + + orig_sddl = acl.as_sddl(domain_sid) + if verbose: + self.outf.write("before:\n%s\n" % orig_sddl) + + def replace_domain_sid(sid): + (dom, rid) = sid.split() + if dom == old_domain_sid: + return security.dom_sid("%s-%i" % (new_domain_sid, rid)) + return sid + + acl.owner_sid = replace_domain_sid(acl.owner_sid) + acl.group_sid = replace_domain_sid(acl.group_sid) + + if acl.sacl: + for ace in acl.sacl.aces: + ace.trustee = replace_domain_sid(ace.trustee) + if acl.dacl: + for ace in acl.dacl.aces: + ace.trustee = replace_domain_sid(ace.trustee) + + new_sddl = acl.as_sddl(domain_sid) + if verbose: + self.outf.write("after:\n%s\n" % new_sddl) + + if orig_sddl == new_sddl: + if verbose: + self.outf.write("nothing to do\n") + return True + + try: + setntacl(lp, + file, + acl, + new_domain_sid, + xattr_backend, + eadb_file, + use_ntvfs=use_ntvfs, + service=service, + session_info=system_session_unix()) + except Exception as e: + raise CommandError("Could not set acl for %s: %s" % (file, e)) + + def recursive_changedom_sids(file): + for root, dirs, files in os.walk(file, followlinks=follow_symlinks): + for f in files: + changedom_sids(os.path.join(root, f)) + + for d in dirs: + changedom_sids(os.path.join(root, d)) + + changedom_sids(file) + if recursive and os.path.isdir(file): + recursive_changedom_sids(file) + + if use_ntvfs: + logger.warning("Please note that POSIX permissions have NOT been " + "changed, only the stored NT ACL.") + + class cmd_ntacl_sysvolreset(Command): """Reset sysvol ACLs to defaults (including correct ACLs on GPOs).""" synopsis = "%prog [options]" @@ -299,6 +462,7 @@ class cmd_ntacl(SuperCommand): subcommands = {} subcommands["set"] = cmd_ntacl_set() subcommands["get"] = cmd_ntacl_get() + subcommands["changedomsid"] = cmd_ntacl_changedomsid() subcommands["sysvolreset"] = cmd_ntacl_sysvolreset() subcommands["sysvolcheck"] = cmd_ntacl_sysvolcheck() subcommands["getdosinfo"] = cmd_dosinfo_get() -- 2.47.3