The branch, master has been updated
       via  c7d0e6f samba-tool/tests: Check that dns cleanup does not 
spuriously remove entries
       via  90e74fc samba-tool/dns: Clarify the cleanup subcommand
       via  97de384 tests/samba-tool: dns cleanup should work with a missing 
name
       via  d82687e remove_dc: Allow remove_dns_references to ignore missing 
server names
       via  178f868 samba-tool: add dns cleanup cmd
       via  c4bb546 tests/samba-tool: add tests for samba-tool group move 
command
       via  8466323 docs-xml:samba-tool.8: document "group move" command
       via  6a2a5e6 samba-tool group: implement the group move command
       via  37b5195 tests/samba-tool: add tests for user move command
       via  b6b2eb8 docs-xml:samba-tool.8: document "user move" command
       via  62a8eec samba-tool user: implement the user move command
       via  4c1101d samba-tool user: fix some typos
       via  87ddbb6 tests/samba-tool: add test for samba-tool user show command
       via  6fbfe84 docs-xml:samba-tool.8: document "user show" command
       via  dc0fa33 samba-tool: implement user show command to display a user 
AD object
       via  dbd29a0 docs-xml:samba-tool.8: document ou management commands
       via  e3882f8 tests/samba-tool: add tests for new ou management commands
       via  2e0f33d samba-tool: implement ou management commands
       via  f973667 selftest: Add tests for samdb.normalize_dn_in_domain()
       via  f202b0e python/samdb: Improve function comment on 
normalize_dn_in_domain()
       via  3f022b2 python/samdb: Allow samdb.normalize_dn_in_domain() to take 
an ldb.Dn()
       via  0a88be8 python/samdb: add method normalize_dn_in_domain(): get full 
dn of an relative dn
       via  cf338b8 pyldb: extend dn.is_child_of() test: dn is child of itself
      from  a3485c4 ctdb-tests: Set test timeout to an hour

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit c7d0e6f39b15e54264dff2a897256f6bf9736333
Author: Garming Sam <garm...@catalyst.net.nz>
Date:   Wed Jan 31 16:13:14 2018 +1300

    samba-tool/tests: Check that dns cleanup does not spuriously remove entries
    
    This might happen in the multi-record case.
    
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>
    
    Autobuild-User(master): Andrew Bartlett <abart...@samba.org>
    Autobuild-Date(master): Thu Feb  8 10:00:13 CET 2018 on sn-devel-144

commit 90e74fc15a8366c775d12a0817b63b6539f1cdd6
Author: Garming Sam <garm...@catalyst.net.nz>
Date:   Wed Jan 31 16:12:05 2018 +1300

    samba-tool/dns: Clarify the cleanup subcommand
    
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 97de384e9a9c44e51954c385a30b113921b4c285
Author: Garming Sam <garm...@catalyst.net.nz>
Date:   Wed Jan 31 11:53:40 2018 +1300

    tests/samba-tool: dns cleanup should work with a missing name
    
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit d82687e77fc8467fb7a2c845220dde1f90fd30bf
Author: Garming Sam <garm...@catalyst.net.nz>
Date:   Wed Jan 31 11:52:34 2018 +1300

    remove_dc: Allow remove_dns_references to ignore missing server names
    
    Signed-off-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 178f86848d15b0a1b59e8a4535649f264a0d12c4
Author: Joe Guo <j...@catalyst.net.nz>
Date:   Fri Jan 12 14:14:00 2018 +1300

    samba-tool: add dns cleanup cmd
    
    1. Add new command to cleanup dns records for a dns host name
    2. Add test to verify the command is working
    
    Signed-off-by: Joe Guo <j...@catalyst.net.nz>
    Reviewed-by: Garming Sam <garm...@catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit c4bb546b21b7ddce5b6f0d023b35c62c98a71d65
Author: Björn Baumbach <b...@sernet.de>
Date:   Wed Jan 24 17:00:35 2018 +0100

    tests/samba-tool: add tests for samba-tool group move command
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 8466323c1f1ca69981f0ade14937cf7737ee5549
Author: Björn Baumbach <b...@sernet.de>
Date:   Wed Jan 24 18:01:42 2018 +0100

    docs-xml:samba-tool.8: document "group move" command
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 6a2a5e61dc4f397de14320b685acc46de5cc0701
Author: Björn Baumbach <b...@sernet.de>
Date:   Mon Nov 27 21:00:07 2017 +0100

    samba-tool group: implement the group move command
    
    This new command allows to move a a group into an ou or container.
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 37b5195d1c747b5388cb2576cd370b5e2eb7d34a
Author: Björn Baumbach <b...@sernet.de>
Date:   Mon Dec 18 16:12:13 2017 +0100

    tests/samba-tool: add tests for user move command
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit b6b2eb8f881e081e80a2a0c1294dc2ec2beda859
Author: Björn Baumbach <b...@sernet.de>
Date:   Wed Jan 24 17:59:29 2018 +0100

    docs-xml:samba-tool.8: document "user move" command
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 62a8eecfbbb4b5fb9f37e454e444751ccf16f82f
Author: Björn Baumbach <b...@sernet.de>
Date:   Mon Nov 27 20:40:49 2017 +0100

    samba-tool user: implement the user move command
    
    This new command allows to move an user into an ou or container.
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 4c1101d0335aba4fcede42e84b5058adc854c54a
Author: Björn Baumbach <b...@sernet.de>
Date:   Fri Dec 8 12:08:18 2017 +0100

    samba-tool user: fix some typos
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 87ddbb67201bedaa8f042a2b5175d795eec2cb7e
Author: Björn Baumbach <b...@sernet.de>
Date:   Wed Nov 29 15:22:20 2017 +0100

    tests/samba-tool: add test for samba-tool user show command
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 6fbfe84c011adc6a426dbd92e779a8759ba80989
Author: Björn Baumbach <b...@sernet.de>
Date:   Thu Jan 25 10:49:33 2018 +0100

    docs-xml:samba-tool.8: document "user show" command
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit dc0fa33c6817ccbf1a90eea5ea1925d2953dd84d
Author: Björn Baumbach <b...@sernet.de>
Date:   Thu Jan 25 10:49:17 2018 +0100

    samba-tool: implement user show command to display a user AD object
    
    This command displays a user account and it's attributes in the
    Active Directory domain.
    The username specified on the command is the sAMAccountName.
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit dbd29a0194cebc6bd0d6fe163c82feedbb1b55e5
Author: Björn Baumbach <b...@sernet.de>
Date:   Wed Jan 24 18:58:11 2018 +0100

    docs-xml:samba-tool.8: document ou management commands
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit e3882f80e0940f16e7808f08b28f3a4803a4ea7b
Author: Björn Baumbach <b...@sernet.de>
Date:   Wed Nov 29 16:51:21 2017 +0100

    tests/samba-tool: add tests for new ou management commands
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 2e0f33d8420a4c4beecb28a85576e54a4694046c
Author: Björn Baumbach <b...@sernet.de>
Date:   Thu Nov 16 12:31:11 2017 +0100

    samba-tool: implement ou management commands
    
    Available subcommands:
      create       - Create an organizational unit.
      delete       - Delete an organizational unit.
      list         - List all organizational units
      listobjects  - List all objects in an organizational unit.
      move         - Move an organizational unit.
      rename       - Rename an organizational unit.
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit f973667face7f6f30723d2b7a1cfb86930b05629
Author: Andrew Bartlett <abart...@samba.org>
Date:   Thu Feb 8 16:46:42 2018 +1300

    selftest: Add tests for samdb.normalize_dn_in_domain()
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit f202b0ef24ded7e93b986033473bc5cf260be33d
Author: Andrew Bartlett <abart...@samba.org>
Date:   Thu Feb 8 16:46:29 2018 +1300

    python/samdb: Improve function comment on normalize_dn_in_domain()
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 3f022b2dd0e0c9a5f1dea35609730ac0ce1bec76
Author: Andrew Bartlett <abart...@samba.org>
Date:   Thu Feb 8 16:27:17 2018 +1300

    python/samdb: Allow samdb.normalize_dn_in_domain() to take an ldb.Dn()
    
    Signed-off-by: Andrew Bartlett <abart...@samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit 0a88be836b3b57e0b268d26350be419ef1aa4fdd
Author: Björn Baumbach <b...@sernet.de>
Date:   Wed Jan 24 17:06:50 2018 +0100

    python/samdb: add method normalize_dn_in_domain(): get full dn of an 
relative dn
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

commit cf338b8260f5b33df6718e4850eed326c636b7ab
Author: Björn Baumbach <b...@sernet.de>
Date:   Wed Dec 20 15:55:50 2017 +0100

    pyldb: extend dn.is_child_of() test: dn is child of itself
    
    Add this test so ensure that this (unclear) behaviour does
    not change silently.
    
    Signed-off-by: Björn Baumbach <b...@sernet.de>
    Reviewed-by: Douglas Bagnall <douglas.bagn...@catalyst.net.nz>

-----------------------------------------------------------------------

Summary of changes:
 docs-xml/manpages/samba-tool.8.xml      | 117 ++++++++++
 lib/ldb/tests/python/api.py             |   4 +
 python/samba/netcmd/dns.py              |  49 ++++
 python/samba/netcmd/group.py            |  79 +++++++
 python/samba/netcmd/main.py             |   1 +
 python/samba/netcmd/ou.py               | 395 ++++++++++++++++++++++++++++++++
 python/samba/netcmd/user.py             | 165 ++++++++++++-
 python/samba/remove_dc.py               |  14 +-
 python/samba/samdb.py                   |  18 ++
 python/samba/tests/dsdb.py              |  49 ++++
 python/samba/tests/samba_tool/dnscmd.py | 157 +++++++++++++
 python/samba/tests/samba_tool/group.py  |  32 +++
 python/samba/tests/samba_tool/ou.py     | 274 ++++++++++++++++++++++
 python/samba/tests/samba_tool/user.py   |  54 +++++
 source4/selftest/tests.py               |   1 +
 15 files changed, 1404 insertions(+), 5 deletions(-)
 create mode 100644 python/samba/netcmd/ou.py
 create mode 100644 python/samba/tests/samba_tool/ou.py


Changeset truncated at 500 lines:

diff --git a/docs-xml/manpages/samba-tool.8.xml 
b/docs-xml/manpages/samba-tool.8.xml
index 1349654..bcdad77 100644
--- a/docs-xml/manpages/samba-tool.8.xml
+++ b/docs-xml/manpages/samba-tool.8.xml
@@ -445,6 +445,17 @@
 </refsect3>
 
 <refsect3>
+       <title>group move <replaceable>groupname</replaceable> 
<replaceable>new_parent_dn</replaceable> [options]</title>
+       <para>This command moves a group into the specified organizational unit
+       or container.</para>
+       <para>The groupname specified on the command is the sAMAccountName.
+       </para>
+       <para>The name of the organizational unit or container can be
+       specified as a full DN or without the domainDN component.</para>
+       <para></para>
+</refsect3>
+
+<refsect3>
        <title>group removemembers <replaceable>groupname</replaceable> 
<replaceable>members</replaceable> [options]</title>
        <para>Remove members from the specified AD group.</para>
 </refsect3>
@@ -479,6 +490,88 @@
        <para>Reset sysvol ACLs to defaults (including correct ACLs on 
GPOs).</para>
 </refsect3>
 
+<refsect3>
+       <title>ou create <replaceable>ou_dn</replaceable> [options]</title>
+       <para>Create an organizational unit.</para>
+       <para>The name of the organizational unit can be specified as a full DN
+       or without the domainDN component.</para>
+
+       <variablelist>
+       <varlistentry>
+       <term>--description=DESCRIPTION</term>
+       <listitem><para>
+       Specify OU's description.
+       </para></listitem>
+       </varlistentry>
+       </variablelist>
+</refsect3>
+
+<refsect3>
+       <title>ou delete <replaceable>ou_dn</replaceable> [options]</title>
+       <para>Delete an organizational unit.</para>
+       <para>The name of the organizational unit can be specified as a full DN
+       or without the domainDN component.</para>
+
+       <variablelist>
+       <varlistentry>
+       <term>--force-subtree-delete</term>
+       <listitem><para>
+       Delete organizational unit and all children reclusively.
+       </para></listitem>
+       </varlistentry>
+       </variablelist>
+</refsect3>
+
+<refsect3>
+       <title>ou list [options]</title>
+       <para>List all organizational units.</para>
+       <variablelist>
+       <varlistentry>
+       <term>--full-dn</term>
+       <listitem><para>
+       Display DNs including the base DN.
+       </para></listitem>
+       </varlistentry>
+       </variablelist>
+</refsect3>
+
+<refsect3>
+       <title>ou listobjects <replaceable>ou_dn</replaceable> [options]</title>
+       <para>List all objects in an organizational unit.</para>
+       <para>The name of the organizational unit can be specified as a full DN
+       or without the domainDN component.</para>
+
+       <variablelist>
+       <varlistentry>
+       <term>--full-dn</term>
+       <listitem><para>
+       Display DNs including the base DN.
+       </para></listitem>
+       </varlistentry>
+
+       <varlistentry>
+       <term>-r|--recursive</term>
+       <listitem><para>
+       List objects recursively.
+       </para></listitem>
+       </varlistentry>
+       </variablelist>
+</refsect3>
+
+<refsect3>
+       <title>ou move <replaceable>old_ou_dn</replaceable> 
<replaceable>new_parent_dn</replaceable> [options]</title>
+       <para>Move an organizational unit.</para>
+       <para>The name of the organizational units can be specified as a full DN
+       or without the domainDN component.</para>
+</refsect3>
+
+<refsect3>
+       <title>ou rename <replaceable>old_ou_dn</replaceable> 
<replaceable>new_ou_dn</replaceable> [options]</title>
+       <para>Rename an organizational unit.</para>
+       <para>The name of the organizational units can be specified as a full DN
+       or without the domainDN component.</para>
+</refsect3>
+
 <refsect2>
        <title>rodc</title>
        <para>Manage Read-Only Domain Controller (RODC).</para>
@@ -572,6 +665,30 @@
 </refsect3>
 
 <refsect3>
+       <title>user show <replaceable>username</replaceable> [options]</title>
+       <para>Display a user AD object.</para>
+
+       <variablelist>
+       <varlistentry>
+       <term>--attributes=USER_ATTRS</term>
+       <listitem><para>
+       Comma separated list of attributes, which will be printed.
+       </para></listitem>
+       </varlistentry>
+       </variablelist>
+</refsect3>
+
+<refsect3>
+       <title>user move <replaceable>username</replaceable> 
<replaceable>new_parent_dn</replaceable> [options]</title>
+       <para>This command moves a user account into the specified
+       organizational unit or container.</para>
+       <para>The username specified on the command is the
+       sAMAccountName.</para>
+       <para>The name of the organizational unit or container can be
+       specified as a full DN or without the domainDN component.</para>
+</refsect3>
+
+<refsect3>
        <title>user password [options]</title>
        <para>Change password for an user account (the one provided in
        authentication).</para>
diff --git a/lib/ldb/tests/python/api.py b/lib/ldb/tests/python/api.py
index 409f446..85fe1bc 100755
--- a/lib/ldb/tests/python/api.py
+++ b/lib/ldb/tests/python/api.py
@@ -1512,9 +1512,11 @@ class DnTests(TestCase):
         dn3 = ldb.Dn(self.ldb, "cn=bar,dc=base")
         dn4 = ldb.Dn(self.ldb, "cn=baz,cn=bar,dc=base")
 
+        self.assertTrue(dn1.is_child_of(dn1))
         self.assertTrue(dn2.is_child_of(dn1))
         self.assertTrue(dn4.is_child_of(dn1))
         self.assertTrue(dn4.is_child_of(dn3))
+        self.assertTrue(dn4.is_child_of(dn4))
         self.assertFalse(dn3.is_child_of(dn2))
         self.assertFalse(dn1.is_child_of(dn4))
 
@@ -1530,9 +1532,11 @@ class DnTests(TestCase):
         dn3 = ldb.Dn(self.ldb, dn3_str)
         dn4 = ldb.Dn(self.ldb, dn4_str)
 
+        self.assertTrue(dn1.is_child_of(dn1_str))
         self.assertTrue(dn2.is_child_of(dn1_str))
         self.assertTrue(dn4.is_child_of(dn1_str))
         self.assertTrue(dn4.is_child_of(dn3_str))
+        self.assertTrue(dn4.is_child_of(dn4_str))
         self.assertFalse(dn3.is_child_of(dn2_str))
         self.assertFalse(dn1.is_child_of(dn4_str))
 
diff --git a/python/samba/netcmd/dns.py b/python/samba/netcmd/dns.py
index fd8db93..33f81ee 100644
--- a/python/samba/netcmd/dns.py
+++ b/python/samba/netcmd/dns.py
@@ -15,6 +15,7 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
+import logging
 
 import samba.getopt as options
 from samba import WERRORError
@@ -26,6 +27,10 @@ from socket import AF_INET
 from socket import AF_INET6
 import shlex
 
+from samba import remove_dc
+from samba.samdb import SamDB
+from samba.auth import system_session
+
 from samba.netcmd import (
     Command,
     CommandError,
@@ -1068,6 +1073,49 @@ class cmd_delete_record(Command):
         self.outf.write('Record deleted successfully\n')
 
 
+class cmd_cleanup_record(Command):
+    """Cleanup DNS records for a DNS host.
+
+    example:
+
+        samba-tool dns cleanup dc1 dc1.samdom.test.site -U USER%PASSWORD
+
+    NOTE: This command in many cases will only mark the `dNSTombstoned` attr
+    as `TRUE` on the DNS records. Querying will no longer return results but
+    there may still be some placeholder entries in the database.
+    """
+
+    synopsis = '%prog <server> <dnshostname>'
+
+    takes_args = ['server', 'dnshostname']
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    def run(self, server, dnshostname, sambaopts=None, credopts=None,
+            versionopts=None, verbose=False, quiet=False):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp)
+
+        logger = self.get_logger()
+        if verbose:
+            logger.setLevel(logging.DEBUG)
+        elif quiet:
+            logger.setLevel(logging.WARNING)
+        else:
+            logger.setLevel(logging.INFO)
+
+        samdb = SamDB(url="ldap://%s"; % server,
+                      session_info=system_session(),
+                      credentials=creds, lp=lp)
+
+        remove_dc.remove_dns_references(samdb, logger, dnshostname,
+                                        ignore_no_name=True)
+
+
 class cmd_dns(SuperCommand):
     """Domain Name Service (DNS) management."""
 
@@ -1082,3 +1130,4 @@ class cmd_dns(SuperCommand):
     subcommands['add'] = cmd_add_record()
     subcommands['update'] = cmd_update_record()
     subcommands['delete'] = cmd_delete_record()
+    subcommands['cleanup'] = cmd_cleanup_record()
diff --git a/python/samba/netcmd/group.py b/python/samba/netcmd/group.py
index b9d6add..782a1ef 100644
--- a/python/samba/netcmd/group.py
+++ b/python/samba/netcmd/group.py
@@ -421,6 +421,84 @@ samba-tool group listmembers \"Domain Users\" -H 
ldap://samba.samdom.example.com
         except Exception, e:
             raise CommandError('Failed to list members of "%s" group ' % 
groupname, e)
 
+class cmd_group_move(Command):
+    """Move a group to an organizational unit/container.
+
+    This command moves a group object into the specified organizational unit
+    or container.
+    The groupname specified on the command is the sAMAccountName.
+    The name of the organizational unit or container can be specified as a
+    full DN or without the domainDN component.
+
+    The command may be run from the root userid or another authorized userid.
+
+    The -H or --URL= option can be used to execute the command against a remote
+    server.
+
+    Example1:
+    samba-tool group move Group1 'OU=OrgUnit,DC=samdom.DC=example,DC=com' \
+        -H ldap://samba.samdom.example.com -U administrator
+
+    Example1 shows how to move a group Group1 into the 'OrgUnit' organizational
+    unit on a remote LDAP server.
+
+    The -H parameter is used to specify the remote target server.
+
+    Example2:
+    samba-tool group move Group1 CN=Users
+
+    Example2 shows how to move a group Group1 back into the CN=Users container
+    on the local server.
+    """
+
+    synopsis = "%prog <groupname> <new_parent_dn> [options]"
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    takes_args = [ "groupname", "new_parent_dn" ]
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "credopts": options.CredentialsOptions,
+        "versionopts": options.VersionOptions,
+        }
+
+    def run(self, groupname, new_parent_dn, credopts=None, sambaopts=None,
+            versionopts=None, H=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp, fallback_machine=True)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+        domain_dn = ldb.Dn(samdb, samdb.domain_dn())
+
+        filter = ("(&(sAMAccountName=%s)(objectClass=group))" %
+                  groupname)
+        try:
+            res = samdb.search(base=domain_dn,
+                               expression=filter,
+                               scope=ldb.SCOPE_SUBTREE)
+            group_dn = res[0].dn
+        except IndexError:
+            raise CommandError('Unable to find group "%s"' % (groupname))
+
+        try:
+            full_new_parent_dn = samdb.normalize_dn_in_domain(new_parent_dn)
+        except Exception, e:
+            raise CommandError('Invalid new_parent_dn "%s": %s' %
+                               (new_parent_dn, e.message))
+
+        full_new_group_dn = ldb.Dn(samdb, str(group_dn))
+        full_new_group_dn.remove_base_components(len(group_dn)-1)
+        full_new_group_dn.add_base(full_new_parent_dn)
+
+        try:
+            samdb.rename(group_dn, full_new_group_dn)
+        except Exception, e:
+            raise CommandError('Failed to move group "%s"' % groupname, e)
+        self.outf.write('Moved group "%s" into "%s"\n' %
+                        (groupname, full_new_parent_dn))
 
 class cmd_group(SuperCommand):
     """Group management."""
@@ -432,3 +510,4 @@ class cmd_group(SuperCommand):
     subcommands["removemembers"] = cmd_group_remove_members()
     subcommands["list"] = cmd_group_list()
     subcommands["listmembers"] = cmd_group_list_members()
+    subcommands["move"] = cmd_group_move()
diff --git a/python/samba/netcmd/main.py b/python/samba/netcmd/main.py
index 7f94f89..a9cf176 100644
--- a/python/samba/netcmd/main.py
+++ b/python/samba/netcmd/main.py
@@ -75,5 +75,6 @@ class cmd_sambatool(SuperCommand):
     subcommands["testparm"] = None
     subcommands["time"] = None
     subcommands["user"] = None
+    subcommands["ou"] = None
     subcommands["processes"] = None
     subcommands["visualize"] = None
diff --git a/python/samba/netcmd/ou.py b/python/samba/netcmd/ou.py
new file mode 100644
index 0000000..16b7f65
--- /dev/null
+++ b/python/samba/netcmd/ou.py
@@ -0,0 +1,395 @@
+# implement samba_tool ou commands
+#
+# Copyright Bjoern Baumbach <b...@sernet.de> 2018
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+import samba.getopt as options
+import ldb
+
+from samba.auth import system_session
+from samba.netcmd import (
+    Command,
+    CommandError,
+    Option,
+    SuperCommand,
+    )
+from samba.samdb import SamDB
+from samba import dsdb
+from operator import attrgetter
+
+class cmd_rename(Command):
+    """Rename an organizational unit.
+
+    The name of the organizational units can be specified as a full DN
+    or without the domainDN component.
+
+    Examples:
+    samba-tool ou rename 'OU=OrgUnit,DC=samdom,DC=example,DC=com' \
+        'OU=NewNameOfOrgUnit,DC=samdom,DC=example,DC=com'
+    samba-tool ou rename 'OU=OrgUnit' 'OU=NewNameOfOrgUnit'
+
+    The examples show how an administrator would rename an ou 'OrgUnit'
+    to 'NewNameOfOrgUnit'. The new DN would be
+    'OU=NewNameOfOrgUnit,DC=samdom,DC=example,DC=com'
+    """
+
+    synopsis = "%prog <old_ou_dn> <new_ou_dn> [options]"
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    takes_args = ["old_ou_dn", "new_ou_dn"]
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "credopts": options.CredentialsOptions,
+        "versionopts": options.VersionOptions,
+        }
+
+    def run(self, old_ou_dn, new_ou_dn, credopts=None, sambaopts=None,
+            versionopts=None, H=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp, fallback_machine=True)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+        domain_dn = ldb.Dn(samdb, samdb.domain_dn())
+
+        try:
+            full_old_ou_dn = samdb.normalize_dn_in_domain(old_ou_dn)
+        except Exception, e:
+            raise CommandError('Invalid old_ou_dn "%s": %s' %
+                               (old_ou_dn, e.message))
+        try:
+            full_new_ou_dn = samdb.normalize_dn_in_domain(new_ou_dn)
+        except Exception, e:
+            raise CommandError('Invalid new_ou_dn "%s": %s' %
+                               (new_ou_dn, e.message))
+
+        try:
+            res = samdb.search(base=full_old_ou_dn,
+                               expression="(objectclass=organizationalUnit)",
+                               scope=ldb.SCOPE_BASE, attrs=[])
+            if len(res) == 0:
+                self.outf.write('Unable to find ou "%s"\n' % old_ou_dn)
+                return
+
+            samdb.rename(full_old_ou_dn, full_new_ou_dn)
+        except Exception, e:
+            raise CommandError('Failed to rename ou "%s"' % full_old_ou_dn, e)
+        self.outf.write('Renamed ou "%s" to "%s"\n' % (full_old_ou_dn,
+                                                       full_new_ou_dn))
+
+class cmd_move(Command):
+    """Move an organizational unit.
+
+    The name of the organizational units can be specified as a full DN
+    or without the domainDN component.
+
+    Examples:
+    samba-tool ou move 'OU=OrgUnit,DC=samdom,DC=example,DC=com' \
+        'OU=NewParentOfOrgUnit,DC=samdom,DC=example,DC=com'
+    samba-tool ou rename 'OU=OrgUnit' 'OU=NewParentOfOrgUnit'
+
+    The examples show how an administrator would move an ou 'OrgUnit'
+    into the ou 'NewParentOfOrgUnit'. The ou 'OrgUnit' would become
+    a child of the 'NewParentOfOrgUnit' ou. The new DN would be
+    'OU=OrgUnit,OU=NewParentOfOrgUnit,DC=samdom,DC=example,DC=com'
+    """
+
+    synopsis = "%prog <old_ou_dn> <new_parent_dn> [options]"
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server",
+               type=str, metavar="URL", dest="H"),
+    ]
+
+    takes_args = ["old_ou_dn", "new_parent_dn"]
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "credopts": options.CredentialsOptions,
+        "versionopts": options.VersionOptions,
+        }
+
+    def run(self, old_ou_dn, new_parent_dn, credopts=None, sambaopts=None,
+            versionopts=None, H=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp, fallback_machine=True)
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+
+        domain_dn = ldb.Dn(samdb, samdb.domain_dn())
+        try:
+            full_old_ou_dn = samdb.normalize_dn_in_domain(old_ou_dn)
+        except Exception, e:
+            raise CommandError('Invalid old_ou_dn "%s": %s' %
+                               (old_ou_dn, e.message))
+        try:
+            full_new_parent_dn = samdb.normalize_dn_in_domain(new_parent_dn)


-- 
Samba Shared Repository

Reply via email to