s4-join: Import DNS zones in AD DC join
authorAndrew Bartlett <abartlet@samba.org>
Thu, 21 Jun 2012 13:46:21 +0000 (23:46 +1000)
committerAndrew Bartlett <abartlet@samba.org>
Sun, 24 Jun 2012 14:26:41 +0000 (00:26 +1000)
source4/dsdb/tests/python/acl.py
source4/scripting/python/samba/join.py
source4/scripting/python/samba/netcmd/domain.py

index bbd4343a2121704aefbc80fb87c311afd0dd53db..94bc504804ff45b6f7c666c7b31725accaad0f31 100755 (executable)
@@ -1627,6 +1627,7 @@ class AclSPNTests(AclTests):
 
     # same as for join_RODC, but do not set any SPNs
     def create_rodc(self, ctx):
 
     # same as for join_RODC, but do not set any SPNs
     def create_rodc(self, ctx):
+         ctx.nc_list = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ]
          ctx.krbtgt_dn = "CN=krbtgt_%s,CN=Users,%s" % (ctx.myname, ctx.base_dn)
 
          ctx.never_reveal_sid = [ "<SID=%s-%s>" % (ctx.domsid, security.DOMAIN_RID_RODC_DENY),
          ctx.krbtgt_dn = "CN=krbtgt_%s,CN=Users,%s" % (ctx.myname, ctx.base_dn)
 
          ctx.never_reveal_sid = [ "<SID=%s-%s>" % (ctx.domsid, security.DOMAIN_RID_RODC_DENY),
@@ -1656,6 +1657,7 @@ class AclSPNTests(AclTests):
          ctx.join_add_objects()
 
     def create_dc(self, ctx):
          ctx.join_add_objects()
 
     def create_dc(self, ctx):
+        ctx.nc_list = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ]
         ctx.userAccountControl = samba.dsdb.UF_SERVER_TRUST_ACCOUNT | samba.dsdb.UF_TRUSTED_FOR_DELEGATION
         ctx.secure_channel_type = misc.SEC_CHAN_BDC
         ctx.replica_flags = (drsuapi.DRSUAPI_DRS_WRIT_REP |
         ctx.userAccountControl = samba.dsdb.UF_SERVER_TRUST_ACCOUNT | samba.dsdb.UF_TRUSTED_FOR_DELEGATION
         ctx.secure_channel_type = misc.SEC_CHAN_BDC
         ctx.replica_flags = (drsuapi.DRSUAPI_DRS_WRIT_REP |
index a683ee6963e3d118ed3602364ab3fc3988294c98..b1901e0421c83d397988beff48916aeab637ffa0 100644 (file)
@@ -47,13 +47,20 @@ class dc_join(object):
 
     def __init__(ctx, server=None, creds=None, lp=None, site=None,
             netbios_name=None, targetdir=None, domain=None,
 
     def __init__(ctx, server=None, creds=None, lp=None, site=None,
             netbios_name=None, targetdir=None, domain=None,
-            machinepass=None, use_ntvfs=False):
+            machinepass=None, use_ntvfs=False, dns_backend=None):
         ctx.creds = creds
         ctx.lp = lp
         ctx.site = site
         ctx.netbios_name = netbios_name
         ctx.targetdir = targetdir
         ctx.use_ntvfs = use_ntvfs
         ctx.creds = creds
         ctx.lp = lp
         ctx.site = site
         ctx.netbios_name = netbios_name
         ctx.targetdir = targetdir
         ctx.use_ntvfs = use_ntvfs
+        if dns_backend is None:
+            ctx.dns_backend = "NONE"
+        else:
+            ctx.dns_backend = dns_backend
+
+        ctx.nc_list = []
+        ctx.full_nc_list = []
 
         ctx.creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
         ctx.net = Net(creds=ctx.creds, lp=ctx.lp)
 
         ctx.creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
         ctx.net = Net(creds=ctx.creds, lp=ctx.lp)
@@ -402,14 +409,14 @@ class dc_join(object):
 
         if ctx.RODC:
             rec["objectCategory"] = "CN=NTDS-DSA-RO,%s" % ctx.schema_dn
 
         if ctx.RODC:
             rec["objectCategory"] = "CN=NTDS-DSA-RO,%s" % ctx.schema_dn
-            rec["msDS-HasFullReplicaNCs"] = nc_list
+            rec["msDS-HasFullReplicaNCs"] = ctx.nc_list
             rec["options"] = "37"
             ctx.samdb.add(rec, ["rodc_join:1:1"])
         else:
             rec["objectCategory"] = "CN=NTDS-DSA,%s" % ctx.schema_dn
             rec["HasMasterNCs"]      = nc_list
             if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
             rec["options"] = "37"
             ctx.samdb.add(rec, ["rodc_join:1:1"])
         else:
             rec["objectCategory"] = "CN=NTDS-DSA,%s" % ctx.schema_dn
             rec["HasMasterNCs"]      = nc_list
             if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
-                rec["msDS-HasMasterNCs"] = nc_list
+                rec["msDS-HasMasterNCs"] = ctx.nc_list
             rec["options"] = "1"
             rec["invocationId"] = ndr_pack(ctx.invocation_id)
             ctx.DsAddEntry([rec])
             rec["options"] = "1"
             rec["invocationId"] = ndr_pack(ctx.invocation_id)
             ctx.DsAddEntry([rec])
@@ -555,7 +562,7 @@ class dc_join(object):
         rec2["objectCategory"] = "CN=NTDS-DSA,%s" % ctx.schema_dn
         rec2["HasMasterNCs"]      = nc_list
         if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
         rec2["objectCategory"] = "CN=NTDS-DSA,%s" % ctx.schema_dn
         rec2["HasMasterNCs"]      = nc_list
         if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
-            rec2["msDS-HasMasterNCs"] = nc_list
+            rec2["msDS-HasMasterNCs"] = ctx.nc_list
         rec2["options"] = "1"
         rec2["invocationId"] = ndr_pack(ctx.invocation_id)
 
         rec2["options"] = "1"
         rec2["invocationId"] = ndr_pack(ctx.invocation_id)
 
@@ -596,7 +603,7 @@ class dc_join(object):
                 hostname=ctx.myname, domainsid=ctx.domsid,
                 machinepass=ctx.acct_pass, serverrole="domain controller",
                 sitename=ctx.site, lp=ctx.lp, ntdsguid=ctx.ntds_guid,
                 hostname=ctx.myname, domainsid=ctx.domsid,
                 machinepass=ctx.acct_pass, serverrole="domain controller",
                 sitename=ctx.site, lp=ctx.lp, ntdsguid=ctx.ntds_guid,
-                use_ntvfs=ctx.use_ntvfs, dns_backend="NONE")
+                use_ntvfs=ctx.use_ntvfs, dns_backend=ctx.dns_backend)
         print "Provision OK for domain DN %s" % presult.domaindn
         ctx.local_samdb = presult.samdb
         ctx.lp          = presult.lp
         print "Provision OK for domain DN %s" % presult.domaindn
         ctx.local_samdb = presult.samdb
         ctx.lp          = presult.lp
@@ -687,6 +694,17 @@ class dc_join(object):
                 repl.replicate(ctx.base_dn, source_dsa_invocation_id,
                                destination_dsa_guid, rodc=ctx.RODC,
                                replica_flags=ctx.domain_replica_flags)
                 repl.replicate(ctx.base_dn, source_dsa_invocation_id,
                                destination_dsa_guid, rodc=ctx.RODC,
                                replica_flags=ctx.domain_replica_flags)
+
+            if 'DC=DomainDnsZones,%s' % ctx.base_dn in ctx.nc_list:
+                repl.replicate('DC=DomainDnsZones,%s' % ctx.base_dn, source_dsa_invocation_id,
+                               destination_dsa_guid, rodc=ctx.RODC,
+                               replica_flags=ctx.replica_flags)
+
+            if 'DC=ForestDnsZones,%s' % ctx.root_dn in ctx.nc_list:
+                repl.replicate('DC=ForestDnsZones,%s' % ctx.root_dn, source_dsa_invocation_id,
+                               destination_dsa_guid, rodc=ctx.RODC,
+                               replica_flags=ctx.replica_flags)
+
             if ctx.RODC:
                 repl.replicate(ctx.acct_dn, source_dsa_invocation_id,
                         destination_dsa_guid,
             if ctx.RODC:
                 repl.replicate(ctx.acct_dn, source_dsa_invocation_id,
                         destination_dsa_guid,
@@ -724,9 +742,8 @@ class dc_join(object):
         '''finalise the join, mark us synchronised and setup secrets db'''
 
         print "Sending DsReplicateUpdateRefs for all the partitions"
         '''finalise the join, mark us synchronised and setup secrets db'''
 
         print "Sending DsReplicateUpdateRefs for all the partitions"
-        ctx.send_DsReplicaUpdateRefs(ctx.schema_dn)
-        ctx.send_DsReplicaUpdateRefs(ctx.config_dn)
-        ctx.send_DsReplicaUpdateRefs(ctx.base_dn)
+        for nc in ctx.full_nc_list:
+            ctx.send_DsReplicaUpdateRefs(nc)
 
         print "Setting isSynchronized and dsServiceName"
         m = ldb.Message()
 
         print "Setting isSynchronized and dsServiceName"
         m = ldb.Message()
@@ -865,6 +882,20 @@ class dc_join(object):
 
 
     def do_join(ctx):
 
 
     def do_join(ctx):
+        ctx.nc_list = [ ctx.config_dn, ctx.schema_dn ]
+        ctx.full_nc_list = [ctx.base_dn, ctx.config_dn, ctx.schema_dn ]
+
+        if not ctx.subdomain:
+            ctx.nc_list += [ctx.base_dn]
+            if ctx.dns_backend != "NONE":
+                ctx.nc_list += ['DC=DomainDnsZones,%s' % ctx.base_dn]
+
+        if ctx.dns_backend != "NONE":
+            ctx.full_nc_list += ['DC=DomainDnsZones,%s' % ctx.base_dn]
+            ctx.full_nc_list += ['DC=ForestDnsZones,%s' % ctx.root_dn]
+            ctx.nc_list += ['DC=ForestDnsZones,%s' % ctx.root_dn]
+
+
         ctx.cleanup_old_join()
         try:
             ctx.join_add_objects()
         ctx.cleanup_old_join()
         try:
             ctx.join_add_objects()
@@ -883,11 +914,11 @@ class dc_join(object):
 
 def join_RODC(server=None, creds=None, lp=None, site=None, netbios_name=None,
               targetdir=None, domain=None, domain_critical_only=False,
 
 def join_RODC(server=None, creds=None, lp=None, site=None, netbios_name=None,
               targetdir=None, domain=None, domain_critical_only=False,
-              machinepass=None, use_ntvfs=False):
+              machinepass=None, use_ntvfs=False, dns_backend=None):
     """join as a RODC"""
 
     ctx = dc_join(server, creds, lp, site, netbios_name, targetdir, domain,
     """join as a RODC"""
 
     ctx = dc_join(server, creds, lp, site, netbios_name, targetdir, domain,
-                  machinepass, use_ntvfs)
+                  machinepass, use_ntvfs, dns_backend)
 
     lp.set("workgroup", ctx.domain_name)
     print("workgroup is %s" % ctx.domain_name)
 
     lp.set("workgroup", ctx.domain_name)
     print("workgroup is %s" % ctx.domain_name)
@@ -937,10 +968,10 @@ def join_RODC(server=None, creds=None, lp=None, site=None, netbios_name=None,
 
 def join_DC(server=None, creds=None, lp=None, site=None, netbios_name=None,
             targetdir=None, domain=None, domain_critical_only=False,
 
 def join_DC(server=None, creds=None, lp=None, site=None, netbios_name=None,
             targetdir=None, domain=None, domain_critical_only=False,
-            machinepass=None, use_ntvfs=False):
+            machinepass=None, use_ntvfs=False, dns_backend=None):
     """join as a DC"""
     ctx = dc_join(server, creds, lp, site, netbios_name, targetdir, domain,
     """join as a DC"""
     ctx = dc_join(server, creds, lp, site, netbios_name, targetdir, domain,
-                  machinepass, use_ntvfs)
+                  machinepass, use_ntvfs, dns_backend)
 
     lp.set("workgroup", ctx.domain_name)
     print("workgroup is %s" % ctx.domain_name)
 
     lp.set("workgroup", ctx.domain_name)
     print("workgroup is %s" % ctx.domain_name)
@@ -967,10 +998,10 @@ def join_DC(server=None, creds=None, lp=None, site=None, netbios_name=None,
 
 def join_subdomain(server=None, creds=None, lp=None, site=None, netbios_name=None,
                    targetdir=None, parent_domain=None, dnsdomain=None, netbios_domain=None,
 
 def join_subdomain(server=None, creds=None, lp=None, site=None, netbios_name=None,
                    targetdir=None, parent_domain=None, dnsdomain=None, netbios_domain=None,
-                   machinepass=None, use_ntvfs=False):
+                   machinepass=None, use_ntvfs=False, dns_backend=None):
     """join as a DC"""
     ctx = dc_join(server, creds, lp, site, netbios_name, targetdir, parent_domain,
     """join as a DC"""
     ctx = dc_join(server, creds, lp, site, netbios_name, targetdir, parent_domain,
-                  machinepass, use_ntvfs)
+                  machinepass, use_ntvfs, dns_backend)
     ctx.subdomain = True
     ctx.parent_domain_name = ctx.domain_name
     ctx.domain_name = netbios_domain
     ctx.subdomain = True
     ctx.parent_domain_name = ctx.domain_name
     ctx.domain_name = netbios_domain
index 8199c41aba7f2d063ed5beb62283ddbd00fffbe3..4e73a29140e7cf54840ec2740491e1f7163f439e 100644 (file)
@@ -148,15 +148,21 @@ class cmd_domain_join(Command):
         Option("--machinepass", type=str, metavar="PASSWORD",
                help="choose machine password (otherwise random)"),
         Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
         Option("--machinepass", type=str, metavar="PASSWORD",
                help="choose machine password (otherwise random)"),
         Option("--use-ntvfs", help="Use NTVFS for the fileserver (default = no)",
-               action="store_true")
-        ]
+               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, " \
+                   "BIND9_DLZ uses samba4 AD to store zone information (default), " \
+                   "NONE skips the DNS setup entirely (this DC will not be a DNS server)",
+               default="BIND9_DLZ")
+       ]
 
     takes_args = ["domain", "role?"]
 
     def run(self, domain, role=None, sambaopts=None, credopts=None,
             versionopts=None, server=None, site=None, targetdir=None,
             domain_critical_only=False, parent_domain=None, machinepass=None,
 
     takes_args = ["domain", "role?"]
 
     def run(self, domain, role=None, sambaopts=None, credopts=None,
             versionopts=None, server=None, site=None, targetdir=None,
             domain_critical_only=False, parent_domain=None, machinepass=None,
-            use_ntvfs=False):
+            use_ntvfs=False, dns_backend=None):
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp)
         net = Net(creds, lp, server=credopts.ipaddress)
         lp = sambaopts.get_loadparm()
         creds = credopts.get_credentials(lp)
         net = Net(creds, lp, server=credopts.ipaddress)
@@ -181,13 +187,13 @@ class cmd_domain_join(Command):
             join_DC(server=server, creds=creds, lp=lp, domain=domain,
                     site=site, netbios_name=netbios_name, targetdir=targetdir,
                     domain_critical_only=domain_critical_only,
             join_DC(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)
+                    machinepass=machinepass, use_ntvfs=use_ntvfs, dns_backend=dns_backend)
             return
         elif role == "RODC":
             join_RODC(server=server, creds=creds, lp=lp, domain=domain,
                       site=site, netbios_name=netbios_name, targetdir=targetdir,
                       domain_critical_only=domain_critical_only,
             return
         elif role == "RODC":
             join_RODC(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)
+                      machinepass=machinepass, use_ntvfs=use_ntvfs, dns_backend=dns_backend)
             return
         elif role == "SUBDOMAIN":
             netbios_domain = lp.get("workgroup")
             return
         elif role == "SUBDOMAIN":
             netbios_domain = lp.get("workgroup")
@@ -195,7 +201,7 @@ class cmd_domain_join(Command):
                 parent_domain = ".".join(domain.split(".")[1:])
             join_subdomain(server=server, creds=creds, lp=lp, dnsdomain=domain, parent_domain=parent_domain,
                            site=site, netbios_name=netbios_name, netbios_domain=netbios_domain, targetdir=targetdir,
                 parent_domain = ".".join(domain.split(".")[1:])
             join_subdomain(server=server, creds=creds, lp=lp, dnsdomain=domain, parent_domain=parent_domain,
                            site=site, netbios_name=netbios_name, netbios_domain=netbios_domain, targetdir=targetdir,
-                           machinepass=machinepass, use_ntvfs=use_ntvfs)
+                           machinepass=machinepass, use_ntvfs=use_ntvfs, dns_backend=dns_backend)
             return
         else:
             raise CommandError("Invalid role '%s' (possible values: MEMBER, DC, RODC, SUBDOMAIN)" % role)
             return
         else:
             raise CommandError("Invalid role '%s' (possible values: MEMBER, DC, RODC, SUBDOMAIN)" % role)