samba-tool trust: support discovery via netr_GetDcName
[samba.git] / python / samba / netcmd / domain.py
index 85ce236298a918d715d3a5af0a275c00680654e9..becbc498b9e8d752f03fd32b2891c86302c0f5a7 100644 (file)
@@ -99,6 +99,9 @@ from samba.provision.common import (
     FILL_DRS
 )
 
+from samba.netcmd.pso import cmd_domain_passwordsettings_pso
+from samba.netcmd.domain_backup import cmd_domain_backup
+
 string_version_to_constant = {
     "2008_R2" : DS_DOMAIN_FUNCTION_2008_R2,
     "2012": DS_DOMAIN_FUNCTION_2012,
@@ -106,8 +109,38 @@ string_version_to_constant = {
 }
 
 common_provision_join_options = [
+    Option("--machinepass", type="string", metavar="PASSWORD",
+           help="choose machine password (otherwise random)"),
+    Option("--plaintext-secrets", action="store_true",
+           help="Store secret/sensitive values as plain text on disk" +
+           "(default is to encrypt secret/ensitive values)"),
+    Option("--backend-store", type="choice", metavar="BACKENDSTORE",
+           choices=["tdb", "mdb"],
+           help="Specify the database backend to be used "
+           "(default is %s)" % get_default_backend_store()),
     Option("--targetdir", metavar="DIR",
-           help="Set target directory (where to store provision)", type=str)
+           help="Set target directory (where to store provision)", type=str),
+    Option("-q", "--quiet", help="Be quiet", action="store_true"),
+]
+
+common_join_options = [
+    Option("--server", help="DC to join", type=str),
+    Option("--site", help="site to join", type=str),
+    Option("--domain-critical-only",
+           help="only replicate critical domain objects",
+           action="store_true"),
+    Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
+           choices=["SAMBA_INTERNAL", "BIND9_DLZ", "NONE"],
+           help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
+           "BIND9_DLZ uses samba4 AD to store zone information, "
+           "NONE skips the DNS setup entirely (this DC will not be a DNS server)",
+           default="SAMBA_INTERNAL"),
+    Option("-v", "--verbose", help="Be verbose", action="store_true")
+]
+
+common_ntvfs_options = [
+        Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
+               action="store_true")
 ]
 
 def get_testparm_var(testparm, smbconf, varname):
@@ -215,8 +248,6 @@ class cmd_domain_provision(Command):
                 help="choose admin password (otherwise random)"),
          Option("--krbtgtpass", type="string", metavar="PASSWORD",
                 help="choose krbtgt password (otherwise random)"),
-         Option("--machinepass", type="string", metavar="PASSWORD",
-                help="choose machine password (otherwise random)"),
          Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
                 choices=["SAMBA_INTERNAL", "BIND9_FLATFILE", "BIND9_DLZ", "NONE"],
                 help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
@@ -232,7 +263,6 @@ class cmd_domain_provision(Command):
                 help="choose 'nobody' user"),
          Option("--users", type="string", metavar="GROUPNAME",
                 help="choose 'users' group"),
-         Option("--quiet", help="Be quiet", action="store_true"),
          Option("--blank", action="store_true",
                 help="do not add users or groups, just the structure"),
          Option("--server-role", type="choice", metavar="ROLE",
@@ -252,13 +282,6 @@ class cmd_domain_provision(Command):
          Option("--partitions-only",
                 help="Configure Samba's partitions, but do not modify them (ie, join a BDC)", action="store_true"),
          Option("--use-rfc2307", action="store_true", help="Use AD to store posix attributes (default = no)"),
-         Option("--plaintext-secrets", action="store_true",
-                help="Store secret/sensitive values as plain text on disk" +
-                     "(default is to encrypt secret/ensitive values)"),
-         Option("--backend-store", type="choice", metavar="BACKENDSTORE",
-                choices=["tdb", "mdb"],
-                help="Specify the database backend to be used "
-                     "(default is %s)" % get_default_backend_store()),
         ]
 
     openldap_options = [
@@ -280,7 +303,6 @@ class cmd_domain_provision(Command):
         ]
 
     ntvfs_options = [
-        Option("--use-ntvfs", action="store_true", help="Use NTVFS for the fileserver (default = no)"),
         Option("--use-xattrs", type="choice", choices=["yes","no","auto"],
                metavar="[yes|no|auto]",
                help="Define if we should use the native fs capabilities or a tdb file for "
@@ -295,7 +317,8 @@ class cmd_domain_provision(Command):
         takes_options.extend(openldap_options)
 
     if samba.is_ntvfs_fileserver_built():
-         takes_options.extend(ntvfs_options)
+        takes_options.extend(common_ntvfs_options)
+        takes_options.extend(ntvfs_options)
 
     takes_args = []
 
@@ -568,32 +591,13 @@ class cmd_domain_dcpromo(Command):
         "credopts": options.CredentialsOptions,
     }
 
-    takes_options = [
-        Option("--server", help="DC to join", type=str),
-        Option("--site", help="site to join", type=str),
-        Option("--domain-critical-only",
-               help="only replicate critical domain objects",
-               action="store_true"),
-        Option("--machinepass", type=str, metavar="PASSWORD",
-               help="choose machine password (otherwise random)"),
-        Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
-               choices=["SAMBA_INTERNAL", "BIND9_DLZ", "NONE"],
-               help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
-                   "BIND9_DLZ uses samba4 AD to store zone information, "
-                   "NONE skips the DNS setup entirely (this DC will not be a DNS server)",
-               default="SAMBA_INTERNAL"),
-        Option("--quiet", help="Be quiet", action="store_true"),
-        Option("--verbose", help="Be verbose", action="store_true")
-        ]
+    takes_options = []
+    takes_options.extend(common_join_options)
 
     takes_options.extend(common_provision_join_options)
 
-    ntvfs_options = [
-         Option("--use-ntvfs", action="store_true", help="Use NTVFS for the fileserver (default = no)"),
-    ]
-
     if samba.is_ntvfs_fileserver_built():
-         takes_options.extend(ntvfs_options)
+         takes_options.extend(common_ntvfs_options)
 
 
     takes_args = ["domain", "role?"]
@@ -602,7 +606,8 @@ class cmd_domain_dcpromo(Command):
             versionopts=None, server=None, site=None, targetdir=None,
             domain_critical_only=False, parent_domain=None, machinepass=None,
             use_ntvfs=False, dns_backend=None,
-            quiet=False, verbose=False):
+            quiet=False, verbose=False, plaintext_secrets=False,
+            backend_store=None):
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp)
         net = Net(creds, lp, server=credopts.ipaddress)
@@ -626,13 +631,15 @@ class cmd_domain_dcpromo(Command):
                     domain_critical_only=domain_critical_only,
                     machinepass=machinepass, use_ntvfs=use_ntvfs,
                     dns_backend=dns_backend,
-                    promote_existing=True)
+                    promote_existing=True, plaintext_secrets=plaintext_secrets,
+                    backend_store=backend_store)
         elif role == "RODC":
             join_RODC(logger=logger, server=server, creds=creds, lp=lp, domain=domain,
                       site=site, netbios_name=netbios_name, targetdir=targetdir,
                       domain_critical_only=domain_critical_only,
                       machinepass=machinepass, use_ntvfs=use_ntvfs, dns_backend=dns_backend,
-                      promote_existing=True)
+                      promote_existing=True, plaintext_secrets=plaintext_secrets,
+                      backend_store=backend_store)
         else:
             raise CommandError("Invalid role '%s' (possible values: DC, RODC)" % role)
 
@@ -649,33 +656,16 @@ class cmd_domain_join(Command):
     }
 
     takes_options = [
-        Option("--server", help="DC to join", type=str),
-        Option("--site", help="site to join", type=str),
         Option("--parent-domain", help="parent domain to create subdomain under", type=str),
-        Option("--domain-critical-only",
-               help="only replicate critical domain objects",
-               action="store_true"),
-        Option("--machinepass", type=str, metavar="PASSWORD",
-               help="choose machine password (otherwise random)"),
         Option("--adminpass", type="string", metavar="PASSWORD",
                help="choose adminstrator password when joining as a subdomain (otherwise random)"),
-        Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
-               choices=["SAMBA_INTERNAL", "BIND9_DLZ", "NONE"],
-               help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
-                   "BIND9_DLZ uses samba4 AD to store zone information, "
-                   "NONE skips the DNS setup entirely (this DC will not be a DNS server)",
-               default="SAMBA_INTERNAL"),
-        Option("--plaintext-secrets", action="store_true",
-               help="Store secret/sensitive values as plain text on disk" +
-                    "(default is to encrypt secret/ensitive values)"),
-        Option("--quiet", help="Be quiet", action="store_true"),
-        Option("--verbose", help="Be verbose", action="store_true")
        ]
 
     ntvfs_options = [
         Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
                action="store_true")
     ]
+    takes_options.extend(common_join_options)
     takes_options.extend(common_provision_join_options)
 
     if samba.is_ntvfs_fileserver_built():
@@ -687,7 +677,9 @@ class cmd_domain_join(Command):
             versionopts=None, server=None, site=None, targetdir=None,
             domain_critical_only=False, parent_domain=None, machinepass=None,
             use_ntvfs=False, dns_backend=None, adminpass=None,
-            quiet=False, verbose=False, plaintext_secrets=False):
+            quiet=False, verbose=False,
+            plaintext_secrets=False,
+            backend_store=None):
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp)
         net = Net(creds, lp, server=credopts.ipaddress)
@@ -720,14 +712,16 @@ class cmd_domain_join(Command):
                     domain_critical_only=domain_critical_only,
                     machinepass=machinepass, use_ntvfs=use_ntvfs,
                     dns_backend=dns_backend,
-                    plaintext_secrets=plaintext_secrets)
+                    plaintext_secrets=plaintext_secrets,
+                    backend_store=backend_store)
         elif role == "RODC":
             join_RODC(logger=logger, server=server, creds=creds, lp=lp, domain=domain,
                       site=site, netbios_name=netbios_name, targetdir=targetdir,
                       domain_critical_only=domain_critical_only,
                       machinepass=machinepass, use_ntvfs=use_ntvfs,
                       dns_backend=dns_backend,
-                      plaintext_secrets=plaintext_secrets)
+                      plaintext_secrets=plaintext_secrets,
+                      backend_store=backend_store)
         elif role == "SUBDOMAIN":
             if not adminpass:
                 logger.info("Administrator password will be set randomly!")
@@ -741,7 +735,8 @@ class cmd_domain_join(Command):
                            targetdir=targetdir, machinepass=machinepass,
                            use_ntvfs=use_ntvfs, dns_backend=dns_backend,
                            adminpass=adminpass,
-                           plaintext_secrets=plaintext_secrets)
+                           plaintext_secrets=plaintext_secrets,
+                           backend_store=backend_store)
         else:
             raise CommandError("Invalid role '%s' (possible values: MEMBER, DC, RODC, SUBDOMAIN)" % role)
 
@@ -757,8 +752,8 @@ class cmd_domain_demote(Command):
                metavar="URL", dest="H"),
         Option("--remove-other-dead-server", help="Dead DC (name or NTDS GUID) "
                "to remove ALL references to (rather than this DC)", type=str),
-        Option("--quiet", help="Be quiet", action="store_true"),
-        Option("--verbose", help="Be verbose", action="store_true"),
+        Option("-q", "--quiet", help="Be quiet", action="store_true"),
+        Option("-v", "--verbose", help="Be verbose", action="store_true"),
         ]
 
     takes_optiongroups = {
@@ -804,7 +799,7 @@ class cmd_domain_demote(Command):
                 raise CommandError("Unable to search for servers")
 
             if (len(res) == 1):
-                raise CommandError("You are the latest server in the domain")
+                raise CommandError("You are the last server in the domain")
 
             server = None
             for e in res:
@@ -826,7 +821,10 @@ class cmd_domain_demote(Command):
                             controls=["search_options:1:2"])
 
         if len(res) != 0:
-            raise CommandError("Current DC is still the owner of %d role(s), use the role command to transfer roles to another DC" % len(res))
+            raise CommandError("Current DC is still the owner of %d role(s), "
+                               "use the role command to transfer roles to "
+                               "another DC" %
+                               len(res))
 
         self.errf.write("Using %s as partner server for the demotion\n" %
                         server)
@@ -1017,9 +1015,13 @@ class cmd_domain_demote(Command):
             remote_samdb.modify(msg)
             remote_samdb.rename(newdn, dc_dn)
             if werr == werror.WERR_DS_DRA_NO_REPLICA:
-                raise CommandError("The DC %s is not present on (already removed from) the remote server: " % server_dsa_dn, e)
+                raise CommandError("The DC %s is not present on (already "
+                                   "removed from) the remote server: %s" %
+                                   (server_dsa_dn, e3))
             else:
-                raise CommandError("Error while sending a removeDsServer of %s: " % server_dsa_dn, e)
+                raise CommandError("Error while sending a removeDsServer "
+                                   "of %s: %s" %
+                                   (server_dsa_dn, e3))
 
         remove_dc.remove_sysvol_references(remote_samdb, logger, dc_name)
 
@@ -1034,6 +1036,10 @@ class cmd_domain_demote(Command):
             except ldb.LdbError as l:
                 pass
 
+        # get dns host name for target server to demote, remove dns references
+        remove_dc.remove_dns_references(remote_samdb, logger, samdb.host_dns_name(),
+                                        ignore_no_name=True)
+
         self.errf.write("Demote successful\n")
 
 
@@ -1051,7 +1057,7 @@ class cmd_domain_level(Command):
     takes_options = [
         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
                metavar="URL", dest="H"),
-        Option("--quiet", help="Be quiet", action="store_true"),
+        Option("-q", "--quiet", help="Be quiet", action="store_true"), # unused
         Option("--forest-level", type="choice", choices=["2003", "2008", "2008_R2", "2012", "2012_R2"],
             help="The forest function level (2003 | 2008 | 2008_R2 | 2012 | 2012_R2)"),
         Option("--domain-level", type="choice", choices=["2003", "2008", "2008_R2", "2012", "2012_R2"],
@@ -1358,7 +1364,7 @@ class cmd_domain_passwordsettings_set(Command):
     takes_options = [
         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
                metavar="URL", dest="H"),
-        Option("--quiet", help="Be quiet", action="store_true"),
+        Option("-q", "--quiet", help="Be quiet", action="store_true"), # unused
         Option("--complexity", type="choice", choices=["on","off","default"],
           help="The password complexity (on | off | default). Default is 'on'"),
         Option("--store-plaintext", type="choice", choices=["on","off","default"],
@@ -1525,7 +1531,7 @@ class cmd_domain_passwordsettings_set(Command):
               ldb.FLAG_MOD_REPLACE, "lockOutObservationWindow")
             msgs.append("Duration to reset account lockout after changed!")
 
-        if max_pwd_age > 0 and min_pwd_age >= max_pwd_age:
+        if max_pwd_age and max_pwd_age > 0 and min_pwd_age >= max_pwd_age:
             raise CommandError("Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age))
 
         if len(m) == 0:
@@ -1538,6 +1544,7 @@ class cmd_domain_passwordsettings(SuperCommand):
     """Manage password policy settings."""
 
     subcommands = {}
+    subcommands["pso"] = cmd_domain_passwordsettings_pso()
     subcommands["show"] = cmd_domain_passwordsettings_show()
     subcommands["set"] = cmd_domain_passwordsettings_set()
 
@@ -1562,8 +1569,8 @@ class cmd_domain_classicupgrade(Command):
                   help="Path to samba classic DC testparm utility from the previous installation.  This allows the default paths of the previous installation to be followed"),
         Option("--targetdir", type="string", metavar="DIR",
                   help="Path prefix where the new Samba 4.0 AD domain should be initialised"),
-        Option("--quiet", help="Be quiet", action="store_true"),
-        Option("--verbose", help="Be verbose", action="store_true"),
+        Option("-q", "--quiet", help="Be quiet", action="store_true"),
+        Option("-v", "--verbose", help="Be verbose", action="store_true"),
         Option("--dns-backend", type="choice", metavar="NAMESERVER-BACKEND",
                choices=["SAMBA_INTERNAL", "BIND9_FLATFILE", "BIND9_DLZ", "NONE"],
                help="The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
@@ -1574,8 +1581,6 @@ class cmd_domain_classicupgrade(Command):
     ]
 
     ntvfs_options = [
-        Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
-               action="store_true"),
         Option("--use-xattrs", type="choice", choices=["yes","no","auto"],
                metavar="[yes|no|auto]",
                help="Define if we should use the native fs capabilities or a tdb file for "
@@ -1584,6 +1589,7 @@ class cmd_domain_classicupgrade(Command):
                default="auto")
     ]
     if samba.is_ntvfs_fileserver_built():
+        takes_options.extend(common_ntvfs_options)
         takes_options.extend(ntvfs_options)
 
     takes_args = ["smbconf"]
@@ -1716,7 +1722,7 @@ class DomainTrustCommand(Command):
         if runtime is None:
             return False
 
-        err32 = self._uint32(runtime[0])
+        err32 = self._uint32(runtime.args[0])
         if err32 == val:
             return True
 
@@ -1724,24 +1730,24 @@ class DomainTrustCommand(Command):
 
     class LocalRuntimeError(CommandError):
         def __init__(exception_self, self, runtime, message):
-            err32 = self._uint32(runtime[0])
-            errstr = runtime[1]
+            err32 = self._uint32(runtime.args[0])
+            errstr = runtime.args[1]
             msg = "LOCAL_DC[%s]: %s - ERROR(0x%08X) - %s" % (
                   self.local_server, message, err32, errstr)
             CommandError.__init__(exception_self, msg)
 
     class RemoteRuntimeError(CommandError):
         def __init__(exception_self, self, runtime, message):
-            err32 = self._uint32(runtime[0])
-            errstr = runtime[1]
+            err32 = self._uint32(runtime.args[0])
+            errstr = runtime.args[1]
             msg = "REMOTE_DC[%s]: %s - ERROR(0x%08X) - %s" % (
                   self.remote_server, message, err32, errstr)
             CommandError.__init__(exception_self, msg)
 
     class LocalLdbError(CommandError):
         def __init__(exception_self, self, ldb_error, message):
-            errval = ldb_error[0]
-            errstr = ldb_error[1]
+            errval = ldb_error.args[0]
+            errstr = ldb_error.args[1]
             msg = "LOCAL_DC[%s]: %s - ERROR(%d) - %s" % (
                   self.local_server, message, errval, errstr)
             CommandError.__init__(exception_self, msg)
@@ -1870,6 +1876,15 @@ class DomainTrustCommand(Command):
 
         return (policy, info)
 
+    def get_netlogon_dc_unc(self, conn, server, domain):
+        try:
+            info = conn.netr_DsRGetDCNameEx2(server,
+                                             None, 0, None, None, None,
+                                             netlogon.DS_RETURN_DNS_NAME)
+            return info.dc_unc
+        except RuntimeError:
+            return conn.netr_GetDcName(server, domain)
+
     def get_netlogon_dc_info(self, conn, server):
         info = conn.netr_DsRGetDCNameEx2(server,
                                          None, 0, None, None, None,
@@ -2043,8 +2058,7 @@ class DomainTrustCommand(Command):
         self.outf.write("Namespaces[%d]%s:\n" % (
                         len(fti.entries), tln_string))
 
-        for i in xrange(0, len(fti.entries)):
-            e = fti.entries[i]
+        for i, e in enumerate(fti.entries):
 
             flags = e.flags
             collision_string = ""
@@ -2504,7 +2518,8 @@ class cmd_domain_trust_create(DomainTrustCommand):
                 raise self.RemoteRuntimeError(self, error, "failed to connect netlogon server")
 
             try:
-                remote_netlogon_info = self.get_netlogon_dc_info(remote_netlogon, remote_server)
+                remote_netlogon_dc_unc = self.get_netlogon_dc_unc(remote_netlogon,
+                                                                  remote_server, domain)
             except RuntimeError as error:
                 raise self.RemoteRuntimeError(self, error, "failed to get netlogon dc info")
 
@@ -2654,9 +2669,9 @@ class cmd_domain_trust_create(DomainTrustCommand):
                         # this triggers netr_GetForestTrustInformation to our domain.
                         # and lsaRSetForestTrustInformation() remotely, but new top level
                         # names are disabled by default.
-                        remote_forest_info = remote_netlogon.netr_DsRGetForestTrustInformation(remote_netlogon_info.dc_unc,
-                                                                      local_lsa_info.dns_domain.string,
-                                                                      netlogon.DS_GFTI_UPDATE_TDO)
+                        remote_forest_info = remote_netlogon.netr_DsRGetForestTrustInformation(remote_netlogon_dc_unc,
+                                                                                               local_lsa_info.dns_domain.string,
+                                                                                               netlogon.DS_GFTI_UPDATE_TDO)
                     except RuntimeError as error:
                         raise self.RemoteRuntimeError(self, error, "netr_DsRGetForestTrustInformation() failed")
 
@@ -2707,10 +2722,10 @@ class cmd_domain_trust_create(DomainTrustCommand):
                 if remote_trust_info.trust_direction & lsa.LSA_TRUST_DIRECTION_OUTBOUND:
                     self.outf.write("Validating incoming trust...\n")
                     try:
-                        remote_trust_verify = remote_netlogon.netr_LogonControl2Ex(remote_netlogon_info.dc_unc,
-                                                                      netlogon.NETLOGON_CONTROL_TC_VERIFY,
-                                                                      2,
-                                                                      local_lsa_info.dns_domain.string)
+                        remote_trust_verify = remote_netlogon.netr_LogonControl2Ex(remote_netlogon_dc_unc,
+                                                                                   netlogon.NETLOGON_CONTROL_TC_VERIFY,
+                                                                                   2,
+                                                                                   local_lsa_info.dns_domain.string)
                     except RuntimeError as error:
                         raise self.RemoteRuntimeError(self, error, "NETLOGON_CONTROL_TC_VERIFY failed")
 
@@ -3434,22 +3449,17 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
             update_spn_vals.extend(stored_spn_vals)
 
             for upn in add_upn:
-                idx = None
-                for i in xrange(0, len(update_upn_vals)):
-                    v = update_upn_vals[i]
-                    if v.lower() != upn.lower():
-                        continue
-                    idx = i
-                    break
-                if idx is not None:
-                    raise CommandError("Entry already present for value[%s] specified for --add-upn-suffix" % upn)
+                for i, v in enumerate(update_upn_vals):
+                    if v.lower() == upn.lower():
+                        raise CommandError("Entry already present for "
+                                           "value[%s] specified for "
+                                           "--add-upn-suffix" % upn)
                 update_upn_vals.append(upn)
                 replace_upn = True
 
             for upn in delete_upn:
                 idx = None
-                for i in xrange(0, len(update_upn_vals)):
-                    v = update_upn_vals[i]
+                for i, v in enumerate(update_upn_vals):
                     if v.lower() != upn.lower():
                         continue
                     idx = i
@@ -3461,22 +3471,17 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
                 replace_upn = True
 
             for spn in add_spn:
-                idx = None
-                for i in xrange(0, len(update_spn_vals)):
-                    v = update_spn_vals[i]
-                    if v.lower() != spn.lower():
-                        continue
-                    idx = i
-                    break
-                if idx is not None:
-                    raise CommandError("Entry already present for value[%s] specified for --add-spn-suffix" % spn)
+                for i, v in enumerate(update_spn_vals):
+                    if v.lower() == spn.lower():
+                        raise CommandError("Entry already present for "
+                                           "value[%s] specified for "
+                                           "--add-spn-suffix" % spn)
                 update_spn_vals.append(spn)
                 replace_spn = True
 
             for spn in delete_spn:
                 idx = None
-                for i in xrange(0, len(update_spn_vals)):
-                    v = update_spn_vals[i]
+                for i, v in enumerate(update_spn_vals):
                     if v.lower() != spn.lower():
                         continue
                     idx = i
@@ -3627,16 +3632,14 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
         update_forest_info.entries = entries
 
         if enable_all:
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME:
                     continue
                 if update_forest_info.entries[i].flags == 0:
                     continue
                 update_forest_info.entries[i].time = 0
                 update_forest_info.entries[i].flags &= ~lsa.LSA_TLN_DISABLED_MASK
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
                     continue
                 if update_forest_info.entries[i].flags == 0:
@@ -3647,8 +3650,7 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
 
         for tln in enable_tln:
             idx = None
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME:
                     continue
                 if r.forest_trust_data.string.lower() != tln.lower():
@@ -3664,8 +3666,7 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
 
         for tln in disable_tln:
             idx = None
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME:
                     continue
                 if r.forest_trust_data.string.lower() != tln.lower():
@@ -3682,8 +3683,7 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
 
         for tln_ex in add_tln_ex:
             idx = None
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
                     continue
                 if r.forest_trust_data.string.lower() != tln_ex.lower():
@@ -3695,8 +3695,7 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
 
             tln_dot = ".%s" % tln_ex.lower()
             idx = None
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME:
                     continue
                 r_dot = ".%s" % r.forest_trust_data.string.lower()
@@ -3724,8 +3723,7 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
 
         for tln_ex in delete_tln_ex:
             idx = None
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_TOP_LEVEL_NAME_EX:
                     continue
                 if r.forest_trust_data.string.lower() != tln_ex.lower():
@@ -3743,8 +3741,7 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
 
         for nb in enable_nb:
             idx = None
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
                     continue
                 if r.forest_trust_data.netbios_domain_name.string.upper() != nb.upper():
@@ -3760,8 +3757,7 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
 
         for nb in disable_nb:
             idx = None
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
                     continue
                 if r.forest_trust_data.netbios_domain_name.string.upper() != nb.upper():
@@ -3778,8 +3774,7 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
 
         for sid in enable_sid:
             idx = None
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
                     continue
                 if r.forest_trust_data.domain_sid != sid:
@@ -3795,8 +3790,7 @@ class cmd_domain_trust_namespaces(DomainTrustCommand):
 
         for sid in disable_sid:
             idx = None
-            for i in xrange(0, len(update_forest_info.entries)):
-                r = update_forest_info.entries[i]
+            for i, r in enumerate(update_forest_info.entries):
                 if r.type != lsa.LSA_FOREST_TRUST_DOMAIN_INFO:
                     continue
                 if r.forest_trust_data.domain_sid != sid:
@@ -3937,15 +3931,6 @@ class ldif_schema_update:
         self.dn = None
         self.ldif = ""
 
-    def _ldap_schemaUpdateNow(self, samdb):
-        ldif = """
-dn:
-changetype: modify
-add: schemaUpdateNow
-schemaUpdateNow: 1
-"""
-        samdb.modify_ldif(ldif)
-
     def can_ignore_failure(self, error):
         """Checks if we can safely ignore failure to apply an LDIF update"""
         (num, errstr) = error.args
@@ -3974,7 +3959,7 @@ schemaUpdateNow: 1
                     # Otherwise the OID-to-attribute mapping in
                     # _apply_updates_in_file() won't work, because it
                     # can't lookup the new OID in the schema
-                    self._ldap_schemaUpdateNow(samdb)
+                    samdb.set_schema_update_now()
 
                     samdb.modify_ldif(self.ldif, controls=['relax:0'])
                 else:
@@ -4006,8 +3991,8 @@ class cmd_domain_schema_upgrade(Command):
     takes_options = [
         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
                metavar="URL", dest="H"),
-        Option("--quiet", help="Be quiet", action="store_true"),
-        Option("--verbose", help="Be verbose", action="store_true"),
+        Option("-q", "--quiet", help="Be quiet", action="store_true"), #unused
+        Option("-v", "--verbose", help="Be verbose", action="store_true"),
         Option("--schema", type="choice", metavar="SCHEMA",
                choices=["2012", "2012_R2"],
                help="The schema file to upgrade to. Default is (Windows) 2012_R2.",
@@ -4256,8 +4241,8 @@ class cmd_domain_functional_prep(Command):
     takes_options = [
         Option("-H", "--URL", help="LDB URL for database or target server", type=str,
                metavar="URL", dest="H"),
-        Option("--quiet", help="Be quiet", action="store_true"),
-        Option("--verbose", help="Be verbose", action="store_true"),
+        Option("-q", "--quiet", help="Be quiet", action="store_true"),
+        Option("-v", "--verbose", help="Be verbose", action="store_true"),
         Option("--function-level", type="choice", metavar="FUNCTION_LEVEL",
                choices=["2008_R2", "2012", "2012_R2"],
                help="The schema file to upgrade to. Default is (Windows) 2012_R2.",
@@ -4367,3 +4352,4 @@ class cmd_domain(SuperCommand):
     subcommands["tombstones"] = cmd_domain_tombstones()
     subcommands["schemaupgrade"] = cmd_domain_schema_upgrade()
     subcommands["functionalprep"] = cmd_domain_functional_prep()
+    subcommands["backup"] = cmd_domain_backup()