From aedcf6a52748d0858aab7d1b3e0253592e963706 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bj=C3=B6rn=20Baumbach?= Date: Tue, 17 Dec 2019 16:26:23 +0100 Subject: [PATCH] samba-tool group addmembers: add --member-dn option MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The --member-dn option allows to specify an object by it's DN. This is required to select a specific object if there are more than one with the same name. Multiple contacts can exist with the same name in different OUs. Signed-off-by: Björn Baumbach Reviewed-by: Ralph Boehme --- python/samba/netcmd/group.py | 16 +++++++--- python/samba/samdb.py | 59 ++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 30 deletions(-) diff --git a/python/samba/netcmd/group.py b/python/samba/netcmd/group.py index 6a8da402c47..4bf417cc878 100644 --- a/python/samba/netcmd/group.py +++ b/python/samba/netcmd/group.py @@ -218,7 +218,7 @@ sudo samba-tool group addmembers supergroup User2 Example2 shows how to add a single user account, User2, to the supergroup AD group. It uses the sudo command to run as root when issuing the command. """ - synopsis = "%prog [options]" + synopsis = "%prog (]|--member-dn=) [options]" takes_optiongroups = { "sambaopts": options.SambaOptions, @@ -229,6 +229,10 @@ Example2 shows how to add a single user account, User2, to the supergroup AD gro takes_options = [ Option("-H", "--URL", help="LDB URL for database or target server", type=str, metavar="URL", dest="H"), + Option("--member-dn", + help=("DN of the new group member to be added.\n" + "The --object-types option will be ignored."), + type=str), Option("--object-types", help=("Comma separated list of object types.\n" "The types are used to filter the search for the " @@ -240,15 +244,16 @@ Example2 shows how to add a single user account, User2, to the supergroup AD gro type=str), ] - takes_args = ["groupname", "listofmembers"] + takes_args = ["groupname", "listofmembers?"] def run(self, groupname, - listofmembers, + listofmembers=None, credopts=None, sambaopts=None, versionopts=None, H=None, + member_dn=None, object_types="user,group,computer"): lp = sambaopts.get_loadparm() @@ -257,7 +262,10 @@ Example2 shows how to add a single user account, User2, to the supergroup AD gro try: samdb = SamDB(url=H, session_info=system_session(), credentials=creds, lp=lp) - groupmembers = listofmembers.split(',') + if member_dn is not None: + groupmembers = [ member_dn ] + else: + groupmembers = listofmembers.split(',') group_member_types = object_types.split(',') samdb.add_remove_group_members(groupname, groupmembers, add_members_operation=True, diff --git a/python/samba/samdb.py b/python/samba/samdb.py index af3a7ddf96a..d0320c1d2cc 100644 --- a/python/samba/samdb.py +++ b/python/samba/samdb.py @@ -334,35 +334,42 @@ changetype: modify """ % (str(targetgroup[0].dn)) for member in members: - filter = self.group_member_filter(member, member_types) - foreign_msg = None + targetmember_dn = None + try: membersid = security.dom_sid(member) + targetmember_dn = "" % str(membersid) except TypeError as e: - membersid = None - - if membersid is not None: - filter = '(objectSid=%s)' % str(membersid) - dn_str = "" % str(membersid) - foreign_msg = ldb.Message() - foreign_msg.dn = ldb.Dn(self, dn_str) - - targetmember = self.search(base=self.domain_dn(), - scope=ldb.SCOPE_SUBTREE, - expression="%s" % filter, - attrs=[]) - - if len(targetmember) > 1: - memberlist_str = "" - for msg in targetmember: - memberlist_str += "%s\n" % msg.get("dn") - raise Exception('Found multiple results for "%s":\n%s' % - (member, memberlist_str)) - if len(targetmember) == 0 and foreign_msg is not None: - targetmember = [foreign_msg] - if len(targetmember) != 1: - raise Exception('Unable to find "%s". Operation cancelled.' % member) - targetmember_dn = targetmember[0].dn.extended_str(1) + pass + + if targetmember_dn is None: + try: + member_dn = ldb.Dn(self, member) + if member_dn.get_linearized() == member_dn.extended_str(1): + full_member_dn = self.normalize_dn_in_domain(member_dn) + else: + full_member_dn = member_dn + targetmember_dn = full_member_dn.extended_str(1) + except ValueError as e: + pass + + if targetmember_dn is None: + filter = self.group_member_filter(member, member_types) + targetmember = self.search(base=self.domain_dn(), + scope=ldb.SCOPE_SUBTREE, + expression=filter, + attrs=[]) + + if len(targetmember) > 1: + targetmemberlist_str = "" + for msg in targetmember: + targetmemberlist_str += "%s\n" % msg.get("dn") + raise Exception('Found multiple results for "%s":\n%s' % + (member, targetmemberlist_str)) + if len(targetmember) != 1: + raise Exception('Unable to find "%s". Operation cancelled.' % member) + targetmember_dn = targetmember[0].dn.extended_str(1) + if add_members_operation is True and (targetgroup[0].get('member') is None or get_bytes(targetmember_dn) not in [str(x) for x in targetgroup[0]['member']]): modified = True addtargettogroup += """add: member -- 2.34.1