The branch, master has been updated via e84f8bdff58 samba-tool: Optionally hide disabled/expired accounts in "group listmembers" via 7dad13cc86f samba-tool: Optionally hide disabled/expired accounts in "user list" via ac621a06412 doc/samba-tool: describe command parameters for "user list" command via 97089ab7bce doc/samba-tool: describe command parameters for "group listmembers" command from 4c6c71e1378 libcli/smb: allow unexpected padding in SMB2 IOCTL responses
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit e84f8bdff584ae2d020e42bbd8b15444f097acd2 Author: Björn Baumbach <b...@sernet.de> Date: Wed Dec 23 15:51:12 2020 +0100 samba-tool: Optionally hide disabled/expired accounts in "group listmembers" --hide-expired Do not list expired group members --hide-disabled Do not list disabled group members Signed-off-by: Björn Baumbach <b...@sernet.de> Reviewed-by: Volker Lendecke <v...@samba.org> Autobuild-User(master): Volker Lendecke <v...@samba.org> Autobuild-Date(master): Fri Jan 15 16:34:11 UTC 2021 on sn-devel-184 commit 7dad13cc86fa603d1ae9c2b00c26686a5f652dc2 Author: Björn Baumbach <b...@sernet.de> Date: Wed Dec 23 13:00:34 2020 +0100 samba-tool: Optionally hide disabled/expired accounts in "user list" --hide-expired Do not list expired user accounts --hide-disabled Do not list disabled user accounts Signed-off-by: Björn Baumbach <b...@sernet.de> Reviewed-by: Volker Lendecke <v...@samba.org> commit ac621a06412df0bc2ad7c09a985d32af74270323 Author: Björn Baumbach <b...@sernet.de> Date: Wed Dec 23 16:39:55 2020 +0100 doc/samba-tool: describe command parameters for "user list" command Signed-off-by: Björn Baumbach <b...@sernet.de> Reviewed-by: Volker Lendecke <v...@samba.org> commit 97089ab7bced3f5450db4f92627235d53f82ba1d Author: Björn Baumbach <b...@sernet.de> Date: Wed Dec 23 16:48:31 2020 +0100 doc/samba-tool: describe command parameters for "group listmembers" command Signed-off-by: Björn Baumbach <b...@sernet.de> Reviewed-by: Volker Lendecke <v...@samba.org> ----------------------------------------------------------------------- Summary of changes: docs-xml/manpages/samba-tool.8.xml | 50 +++++++++++++++ python/samba/netcmd/group.py | 29 ++++++++- python/samba/netcmd/user.py | 30 ++++++++- python/samba/samdb.py | 15 +++++ python/samba/tests/samba_tool/group.py | 109 +++++++++++++++++++++++++++++++++ python/samba/tests/samba_tool/user.py | 70 +++++++++++++++++++++ 6 files changed, 298 insertions(+), 5 deletions(-) Changeset truncated at 500 lines: diff --git a/docs-xml/manpages/samba-tool.8.xml b/docs-xml/manpages/samba-tool.8.xml index a7e8a7c9d1a..820e278198d 100644 --- a/docs-xml/manpages/samba-tool.8.xml +++ b/docs-xml/manpages/samba-tool.8.xml @@ -935,6 +935,28 @@ <refsect3> <title>group listmembers <replaceable>groupname</replaceable> [options]</title> <para>List all members of the specified AD group.</para> + <para>By default the sAMAccountNames are listed. If no sAMAccountName + is available, the CN will be used instead.</para> + <variablelist> + <varlistentry> + <term>--full-dn</term> + <listitem><para> + List the distinguished names instead of the sAMAccountNames. + </para></listitem> + </varlistentry> + <varlistentry> + <term>--hide-expired</term> + <listitem><para> + Do not list expired group members. + </para></listitem> + </varlistentry> + <varlistentry> + <term>--hide-disabled</term> + <listitem><para> + Do not list disabled group members. + </para></listitem> + </varlistentry> + </variablelist> </refsect3> <refsect3> @@ -1332,6 +1354,34 @@ <refsect3> <title>user list</title> <para>List all users.</para> + <para>By default the user's sAMAccountNames are listed.</para> + <variablelist> + <varlistentry> + <term>--full-dn</term> + <listitem><para> + List user's distinguished names instead of the sAMAccountNames. + </para></listitem> + </varlistentry> + <varlistentry> + <term>-b BASE_DN|--base-dn=BASE_DN</term> + <listitem><para> + Specify base DN to use. Only users under the specified base DN will be + listed. + </para></listitem> + </varlistentry> + <varlistentry> + <term>--hide-expired</term> + <listitem><para> + Do not list expired user accounts. + </para></listitem> + </varlistentry> + <varlistentry> + <term>--hide-disabled</term> + <listitem><para> + Do not list disabled user accounts. + </para></listitem> + </varlistentry> + </variablelist> </refsect3> <refsect3> diff --git a/python/samba/netcmd/group.py b/python/samba/netcmd/group.py index b5c86d33019..a958db2c42c 100644 --- a/python/samba/netcmd/group.py +++ b/python/samba/netcmd/group.py @@ -33,6 +33,7 @@ from samba.dsdb import ( GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP, GTYPE_DISTRIBUTION_GLOBAL_GROUP, GTYPE_DISTRIBUTION_UNIVERSAL_GROUP, + UF_ACCOUNTDISABLE, ) from collections import defaultdict from subprocess import check_call, CalledProcessError @@ -488,6 +489,14 @@ samba-tool group listmembers \"Domain Users\" -H ldap://samba.samdom.example.com takes_options = [ Option("-H", "--URL", help="LDB URL for database or target server", type=str, metavar="URL", dest="H"), + Option("--hide-expired", + help="Do not list expired group members", + default=False, + action='store_true'), + Option("--hide-disabled", + default=False, + action='store_true', + help="Do not list disabled group members"), Option("--full-dn", dest="full_dn", default=False, action='store_true', @@ -508,6 +517,8 @@ samba-tool group listmembers \"Domain Users\" -H ldap://samba.samdom.example.com sambaopts=None, versionopts=None, H=None, + hide_expired=False, + hide_disabled=False, full_dn=False): lp = sambaopts.get_loadparm() creds = credopts.get_credentials(lp, fallback_machine=True) @@ -530,10 +541,22 @@ samba-tool group listmembers \"Domain Users\" -H ldap://samba.samdom.example.com (group_dom_sid, rid) = group_sid.split() group_sid_dn = "<SID=%s>" % (group_sid) - search_filter = ("(|(primaryGroupID=%s)(memberOf=%s))" % - (rid, group_sid_dn)) + filter_expires = "" + if hide_expired is True: + current_nttime = samdb.get_nttime() + filter_expires = \ + "(|(accountExpires=0)(accountExpires>=%u))" % (current_nttime) + + filter_disabled = "" + if hide_disabled is True: + filter_disabled = "(!(userAccountControl:%s:=%u))" % ( + ldb.OID_COMPARATOR_AND, UF_ACCOUNTDISABLE) + + filter = "(&(|(primaryGroupID=%s)(memberOf=%s))%s%s)" % ( + rid, group_sid_dn, filter_disabled, filter_expires) + res = samdb.search(samdb.domain_dn(), scope=ldb.SCOPE_SUBTREE, - expression=(search_filter), + expression=filter, attrs=["samAccountName", "cn"]) if (len(res) == 0): diff --git a/python/samba/netcmd/user.py b/python/samba/netcmd/user.py index 7e8204462d1..bbfa7e989dd 100644 --- a/python/samba/netcmd/user.py +++ b/python/samba/netcmd/user.py @@ -466,6 +466,14 @@ class cmd_user_list(Command): takes_options = [ Option("-H", "--URL", help="LDB URL for database or target server", type=str, metavar="URL", dest="H"), + Option("--hide-expired", + help="Do not list expired user accounts", + default=False, + action='store_true'), + Option("--hide-disabled", + default=False, + action='store_true', + help="Do not list disabled user accounts"), Option("-b", "--base-dn", help="Specify base DN to use", type=str), @@ -486,6 +494,8 @@ class cmd_user_list(Command): credopts=None, versionopts=None, H=None, + hide_expired=False, + hide_disabled=False, base_dn=None, full_dn=False): lp = sambaopts.get_loadparm() @@ -498,10 +508,26 @@ class cmd_user_list(Command): if base_dn: search_dn = samdb.normalize_dn_in_domain(base_dn) + filter_expires = "" + if hide_expired is True: + current_nttime = samdb.get_nttime() + filter_expires = "(|(accountExpires=0)(accountExpires>=%u))" % ( + current_nttime) + + filter_disabled = "" + if hide_disabled is True: + filter_disabled = "(!(userAccountControl:%s:=%u))" % ( + ldb.OID_COMPARATOR_AND, dsdb.UF_ACCOUNTDISABLE) + + filter = "(&(objectClass=user)(userAccountControl:%s:=%u)%s%s)" % ( + ldb.OID_COMPARATOR_AND, + dsdb.UF_NORMAL_ACCOUNT, + filter_disabled, + filter_expires) + res = samdb.search(search_dn, scope=ldb.SCOPE_SUBTREE, - expression=("(&(objectClass=user)(userAccountControl:%s:=%u))" - % (ldb.OID_COMPARATOR_AND, dsdb.UF_NORMAL_ACCOUNT)), + expression=filter, attrs=["samaccountname"]) if (len(res) == 0): return diff --git a/python/samba/samdb.py b/python/samba/samdb.py index a0a7dbf1c50..f95709ab7c8 100644 --- a/python/samba/samdb.py +++ b/python/samba/samdb.py @@ -984,6 +984,21 @@ accountExpires: %u """Get the NTDS objectGUID""" return dsdb._samdb_ntds_objectGUID(self) + def get_timestr(self): + """Get the current time as generalized time string""" + res = self.search(base="", + scope=ldb.SCOPE_BASE, + attrs=["currentTime"]) + return str(res[0]["currentTime"][0]) + + def get_time(self): + """Get the current time as UNIX time""" + return ldb.string_to_time(self.get_timestr()) + + def get_nttime(self): + """Get the current time as NT time""" + return samba.unix2nttime(self.get_time()) + def server_site_name(self): """Get the server site name""" return dsdb._samdb_server_site_name(self) diff --git a/python/samba/tests/samba_tool/group.py b/python/samba/tests/samba_tool/group.py index 3d714f206f3..2542411d74a 100644 --- a/python/samba/tests/samba_tool/group.py +++ b/python/samba/tests/samba_tool/group.py @@ -239,6 +239,79 @@ class GroupCmdTestCase(SambaToolCmdTest): name = str(groupobj.get("samAccountName", idx=0)) found = self.assertMatch(out, name, "group '%s' not found" % name) + def test_listmembers_hide_expired(self): + expire_username = "expireUser" + expire_user = self._random_user({"name": expire_username}) + self._create_user(expire_user) + + (result, out, err) = self.runsubcmd( + "group", + "listmembers", + "Domain Users", + "--hide-expired", + "-H", + "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + self.assertCmdSuccess(result, out, err, "Error running listmembers") + self.assertTrue(expire_username in out, + "user '%s' not found" % expire_username) + + # user will be expired one second ago + self.samdb.setexpiry( + "(sAMAccountname=%s)" % expire_username, + -1, + False) + + (result, out, err) = self.runsubcmd( + "group", + "listmembers", + "Domain Users", + "--hide-expired", + "-H", + "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + self.assertCmdSuccess(result, out, err, "Error running listmembers") + self.assertFalse(expire_username in out, + "user '%s' not found" % expire_username) + + self.samdb.deleteuser(expire_username) + + def test_listmembers_hide_disabled(self): + disable_username = "disableUser" + disable_user = self._random_user({"name": disable_username}) + self._create_user(disable_user) + + (result, out, err) = self.runsubcmd( + "group", + "listmembers", + "Domain Users", + "--hide-disabled", + "-H", + "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + self.assertCmdSuccess(result, out, err, "Error running listmembers") + self.assertTrue(disable_username in out, + "user '%s' not found" % disable_username) + + self.samdb.disable_account("(sAMAccountname=%s)" % disable_username) + + (result, out, err) = self.runsubcmd( + "group", + "listmembers", + "Domain Users", + "--hide-disabled", + "-H", + "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + self.assertCmdSuccess(result, out, err, "Error running listmembers") + self.assertFalse(disable_username in out, + "user '%s' not found" % disable_username) + + self.samdb.deleteuser(disable_username) def test_listmembers_full_dn(self): (result, out, err) = self.runsubcmd("group", "listmembers", "Domain Users", @@ -502,3 +575,39 @@ template """ total_groups = len(grouplist) self.assertTrue("Total groups: {0}".format(total_groups) in out, "Total groups not reported correctly") + + def _random_user(self, base={}): + ''' + create a user with random attribute values, you can specify + base attributes + ''' + user = { + "name": self.randomName(), + "password": self.random_password(16), + "surname": self.randomName(), + "given-name": self.randomName(), + "job-title": self.randomName(), + "department": self.randomName(), + "company": self.randomName(), + "description": self.randomName(count=100), + "createUserFn": self._create_user, + } + user.update(base) + return user + + def _create_user(self, user): + return self.runsubcmd( + "user", + "add", + user["name"], + user["password"], + "--surname=%s" % user["surname"], + "--given-name=%s" % user["given-name"], + "--job-title=%s" % user["job-title"], + "--department=%s" % user["department"], + "--description=%s" % user["description"], + "--company=%s" % user["company"], + "-H", + "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) diff --git a/python/samba/tests/samba_tool/user.py b/python/samba/tests/samba_tool/user.py index 07eb09b24d5..3d3ea0681f8 100644 --- a/python/samba/tests/samba_tool/user.py +++ b/python/samba/tests/samba_tool/user.py @@ -433,6 +433,76 @@ class UserCmdTestCase(SambaToolCmdTest): found = self.assertMatch(out, name, "user '%s' not found" % name) + def test_list_hide_expired(self): + expire_username = "expireUser" + expire_user = self._randomUser({"name": expire_username}) + self._create_user(expire_user) + + (result, out, err) = self.runsubcmd( + "user", + "list", + "--hide-expired", + "-H", + "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + self.assertCmdSuccess(result, out, err, "Error running list") + self.assertTrue(expire_username in out, + "user '%s' not found" % expire_username) + + # user will be expired one second ago + self.samdb.setexpiry( + "(sAMAccountname=%s)" % expire_username, + -1, + False) + + (result, out, err) = self.runsubcmd( + "user", + "list", + "--hide-expired", + "-H", + "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + self.assertCmdSuccess(result, out, err, "Error running list") + self.assertFalse(expire_username in out, + "user '%s' found" % expire_username) + + self.samdb.deleteuser(expire_username) + + def test_list_hide_disabled(self): + disable_username = "disableUser" + disable_user = self._randomUser({"name": disable_username}) + self._create_user(disable_user) + + (result, out, err) = self.runsubcmd( + "user", + "list", + "--hide-disabled", + "-H", + "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + self.assertCmdSuccess(result, out, err, "Error running list") + self.assertTrue(disable_username in out, + "user '%s' not found" % disable_username) + + self.samdb.disable_account("(sAMAccountname=%s)" % disable_username) + + (result, out, err) = self.runsubcmd( + "user", + "list", + "--hide-disabled", + "-H", + "ldap://%s" % os.environ["DC_SERVER"], + "-U%s%%%s" % (os.environ["DC_USERNAME"], + os.environ["DC_PASSWORD"])) + self.assertCmdSuccess(result, out, err, "Error running list") + self.assertFalse(disable_username in out, + "user '%s' found" % disable_username) + + self.samdb.deleteuser(disable_username) + def test_show(self): for user in self.users: (result, out, err) = self.runsubcmd( -- Samba Shared Repository