s4-provision: Fix typo in 9b9fdeefb47f2657c9bb4c2f48318550da510209
[ira/wip.git] / source4 / scripting / python / samba / provision / sambadns.py
1 # Unix SMB/CIFS implementation.
2 # backend code for provisioning DNS for a Samba4 server
3 #
4 # Copyright (C) Kai Blin <kai@samba.org> 2011
5 # Copyright (C) Amitay Isaacs <amitay@gmail.com> 2011
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20
21 """DNS-related provisioning"""
22
23 import os
24 import uuid
25 import shutil
26 import time
27 import ldb
28 from base64 import b64encode
29 import samba
30 from samba.ndr import ndr_pack, ndr_unpack
31 from samba import read_and_sub_file, setup_file
32 from samba.dcerpc import dnsp, misc, security
33 from samba.dsdb import (
34     DS_DOMAIN_FUNCTION_2000,
35     DS_DOMAIN_FUNCTION_2003,
36     DS_DOMAIN_FUNCTION_2008,
37     DS_DOMAIN_FUNCTION_2008_R2
38     )
39 from base64 import b64encode
40 from samba.provision.descriptor import (
41     get_domain_descriptor,
42     get_dns_partition_descriptor
43     )
44 from samba.provision.common import (
45     setup_path,
46     setup_add_ldif,
47     setup_modify_ldif,
48     setup_ldb
49     )
50
51
52 def get_domainguid(samdb, domaindn):
53     res = samdb.search(base=domaindn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"])
54     domainguid =  str(ndr_unpack(misc.GUID, res[0]["objectGUID"][0]))
55     return domainguid
56
57 def get_dnsadmins_sid(samdb, domaindn):
58     res = samdb.search(base="CN=DnsAdmins,CN=Users,%s" % domaindn, scope=ldb.SCOPE_BASE,
59                        attrs=["objectSid"])
60     dnsadmins_sid = ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
61     return dnsadmins_sid
62
63 class ARecord(dnsp.DnssrvRpcRecord):
64     def __init__(self, ip_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
65         super(ARecord, self).__init__()
66         self.wType = dnsp.DNS_TYPE_A
67         self.rank = rank
68         self.dwSerial = serial
69         self.dwTtlSeconds = ttl
70         self.data = ip_addr
71
72 class AAAARecord(dnsp.DnssrvRpcRecord):
73     def __init__(self, ip6_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
74         super(AAAARecord, self).__init__()
75         self.wType = dnsp.DNS_TYPE_AAAA
76         self.rank = rank
77         self.dwSerial = serial
78         self.dwTtlSeconds = ttl
79         self.data = ip6_addr
80
81 class CNameRecord(dnsp.DnssrvRpcRecord):
82     def __init__(self, cname, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
83         super(CNameRecord, self).__init__()
84         self.wType = dnsp.DNS_TYPE_CNAME
85         self.rank = rank
86         self.dwSerial = serial
87         self.dwTtlSeconds = ttl
88         self.data = cname
89
90 class NSRecord(dnsp.DnssrvRpcRecord):
91     def __init__(self, dns_server, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
92         super(NSRecord, self).__init__()
93         self.wType = dnsp.DNS_TYPE_NS
94         self.rank = rank
95         self.dwSerial = serial
96         self.dwTtlSeconds = ttl
97         self.data = dns_server
98
99 class SOARecord(dnsp.DnssrvRpcRecord):
100     def __init__(self, mname, rname, serial=1, refresh=900, retry=600,
101                  expire=86400, minimum=3600, ttl=3600, rank=dnsp.DNS_RANK_ZONE):
102         super(SOARecord, self).__init__()
103         self.wType = dnsp.DNS_TYPE_SOA
104         self.rank = rank
105         self.dwSerial = serial
106         self.dwTtlSeconds = ttl
107         soa = dnsp.soa()
108         soa.serial = serial
109         soa.refresh = refresh
110         soa.retry = retry
111         soa.expire = expire
112         soa.mname = mname
113         soa.rname = rname
114         self.data = soa
115
116 class SRVRecord(dnsp.DnssrvRpcRecord):
117     def __init__(self, target, port, priority=0, weight=100, serial=1, ttl=900,
118                 rank=dnsp.DNS_RANK_ZONE):
119         super(SRVRecord, self).__init__()
120         self.wType = dnsp.DNS_TYPE_SRV
121         self.rank = rank
122         self.dwSerial = serial
123         self.dwTtlSeconds = ttl
124         srv = dnsp.srv()
125         srv.nameTarget = target
126         srv.wPort = port
127         srv.wPriority = priority
128         srv.wWeight = weight
129         self.data = srv
130
131 class TXTRecord(dnsp.DnssrvRpcRecord):
132     def __init__(self, txt, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
133         super(TXTRecord, self).__init__()
134         self.wType = dnsp.DNS_TYPE_TXT
135         self.rank = rank
136         self.dwSerial = serial
137         self.dwTtlSeconds = ttl
138         self.data = txt
139
140 class TypeProperty(dnsp.DnsProperty):
141     def __init__(self, zone_type=dnsp.DNS_ZONE_TYPE_PRIMARY):
142         super(TypeProperty, self).__init__()
143         self.wDataLength = 1
144         self.version = 1
145         self.id = dnsp.DSPROPERTY_ZONE_TYPE
146         self.data = zone_type
147
148 class AllowUpdateProperty(dnsp.DnsProperty):
149     def __init__(self, allow_update=dnsp.DNS_ZONE_UPDATE_SECURE):
150         super(AllowUpdateProperty, self).__init__()
151         self.wDataLength = 1
152         self.version = 1
153         self.id = dnsp.DSPROPERTY_ZONE_ALLOW_UPDATE
154         self.data = allow_update
155
156 class SecureTimeProperty(dnsp.DnsProperty):
157     def __init__(self, secure_time=0):
158         super(SecureTimeProperty, self).__init__()
159         self.wDataLength = 1
160         self.version = 1
161         self.id = dnsp.DSPROPERTY_ZONE_SECURE_TIME
162         self.data = secure_time
163
164 class NorefreshIntervalProperty(dnsp.DnsProperty):
165     def __init__(self, norefresh_interval=0):
166         super(NorefreshIntervalProperty, self).__init__()
167         self.wDataLength = 1
168         self.version = 1
169         self.id = dnsp.DSPROPERTY_ZONE_NOREFRESH_INTERVAL
170         self.data = norefresh_interval
171
172 class RefreshIntervalProperty(dnsp.DnsProperty):
173     def __init__(self, refresh_interval=0):
174         super(RefreshIntervalProperty, self).__init__()
175         self.wDataLength = 1
176         self.version = 1
177         self.id = dnsp.DSPROPERTY_ZONE_REFRESH_INTERVAL
178         self.data = refresh_interval
179
180 class AgingStateProperty(dnsp.DnsProperty):
181     def __init__(self, aging_enabled=0):
182         super(AgingStateProperty, self).__init__()
183         self.wDataLength = 1
184         self.version = 1
185         self.id = dnsp.DSPROPERTY_ZONE_AGING_STATE
186         self.data = aging_enabled
187
188 class AgingEnabledTimeProperty(dnsp.DnsProperty):
189     def __init__(self, next_cycle_hours=0):
190         super(AgingEnabledTimeProperty, self).__init__()
191         self.wDataLength = 1
192         self.version = 1;
193         self.id = dnsp.DSPROPERTY_ZONE_AGING_ENABLED_TIME
194         self.data = next_cycle_hours
195
196 def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn, serverdn):
197     domainzone_dn = "DC=DomainDnsZones,%s" % domaindn
198     forestzone_dn = "DC=ForestDnsZones,%s" % forestdn
199     descriptor = get_dns_partition_descriptor(domainsid)
200     setup_add_ldif(samdb, setup_path("provision_dnszones_partitions.ldif"), {
201         "DOMAINZONE_DN": domainzone_dn,
202         "FORESTZONE_DN": forestzone_dn,
203         "SECDESC"      : b64encode(descriptor)
204         })
205
206     domainzone_guid = get_domainguid(samdb, domainzone_dn)
207     forestzone_guid = get_domainguid(samdb, forestzone_dn)
208
209     domainzone_guid = str(uuid.uuid4())
210     forestzone_guid = str(uuid.uuid4())
211
212     domainzone_dns = ldb.Dn(samdb, domainzone_dn).canonical_ex_str().strip()
213     forestzone_dns = ldb.Dn(samdb, forestzone_dn).canonical_ex_str().strip()
214
215     setup_add_ldif(samdb, setup_path("provision_dnszones_add.ldif"), {
216         "DOMAINZONE_DN": domainzone_dn,
217         "FORESTZONE_DN": forestzone_dn,
218         "DOMAINZONE_GUID": domainzone_guid,
219         "FORESTZONE_GUID": forestzone_guid,
220         "DOMAINZONE_DNS": domainzone_dns,
221         "FORESTZONE_DNS": forestzone_dns,
222         "CONFIGDN": configdn,
223         "SERVERDN": serverdn,
224         })
225
226     setup_modify_ldif(samdb, setup_path("provision_dnszones_modify.ldif"), {
227         "CONFIGDN": configdn,
228         "SERVERDN": serverdn,
229         "DOMAINZONE_DN": domainzone_dn,
230         "FORESTZONE_DN": forestzone_dn,
231     })
232
233
234 def add_dns_accounts(samdb, domaindn):
235     setup_add_ldif(samdb, setup_path("provision_dns_accounts_add.ldif"), {
236         "DOMAINDN": domaindn,
237         })
238
239 def add_dns_container(samdb, domaindn, prefix, domainsid, dnsadmins_sid):
240     # CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
241     sddl = "O:SYG:SYD:AI" \
242     "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
243     "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)" \
244     "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
245     "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
246     "S:AI" % dnsadmins_sid
247     sec = security.descriptor.from_sddl(sddl, domainsid)
248     msg = ldb.Message(ldb.Dn(samdb, "CN=MicrosoftDNS,%s,%s" % (prefix, domaindn)))
249     msg["objectClass"] = ["top", "container"]
250     msg["nTSecurityDescriptor"] = ldb.MessageElement(ndr_pack(sec), ldb.FLAG_MOD_ADD,
251         "nTSecurityDescriptor")
252     samdb.add(msg)
253
254 def add_rootservers(samdb, domaindn, prefix):
255     rootservers = {}
256     rootservers["a.root-servers.net"] = "198.41.0.4"
257     rootservers["b.root-servers.net"] = "192.228.79.201"
258     rootservers["c.root-servers.net"] = "192.33.4.12"
259     rootservers["d.root-servers.net"] = "128.8.10.90"
260     rootservers["e.root-servers.net"] = "192.203.230.10"
261     rootservers["f.root-servers.net"] = "192.5.5.241"
262     rootservers["g.root-servers.net"] = "192.112.36.4"
263     rootservers["h.root-servers.net"] = "128.63.2.53"
264     rootservers["i.root-servers.net"] = "192.36.148.17"
265     rootservers["j.root-servers.net"] = "192.58.128.30"
266     rootservers["k.root-servers.net"] = "193.0.14.129"
267     rootservers["l.root-servers.net"] = "199.7.83.42"
268     rootservers["m.root-servers.net"] = "202.12.27.33"
269
270     rootservers_v6 = {}
271     rootservers_v6["a.root-servers.net"] = "2001:503:ba3e::2:30"
272     rootservers_v6["f.root-servers.net"] = "2001:500:2f::f"
273     rootservers_v6["h.root-servers.net"] = "2001:500:1::803f:235"
274     rootservers_v6["j.root-servers.net"] = "2001:503:c27::2:30"
275     rootservers_v6["k.root-servers.net"] = "2001:7fd::1"
276     rootservers_v6["m.root-servers.net"] = "2001:dc3::35"
277
278     container_dn = "DC=RootDNSServers,CN=MicrosoftDNS,%s,%s" % (prefix, domaindn)
279
280     # Add DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
281     msg = ldb.Message(ldb.Dn(samdb, container_dn))
282     props = []
283     props.append(ndr_pack(TypeProperty(zone_type=dnsp.DNS_ZONE_TYPE_CACHE)))
284     props.append(ndr_pack(AllowUpdateProperty(allow_update=dnsp.DNS_ZONE_UPDATE_OFF)))
285     props.append(ndr_pack(SecureTimeProperty()))
286     props.append(ndr_pack(NorefreshIntervalProperty()))
287     props.append(ndr_pack(RefreshIntervalProperty()))
288     props.append(ndr_pack(AgingStateProperty()))
289     props.append(ndr_pack(AgingEnabledTimeProperty()))
290     msg["objectClass"] = ["top", "dnsZone"]
291     msg["cn"] = ldb.MessageElement("Zone", ldb.FLAG_MOD_ADD, "cn")
292     msg["dNSProperty"] = ldb.MessageElement(props, ldb.FLAG_MOD_ADD, "dNSProperty")
293     samdb.add(msg)
294
295     # Add DC=@,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
296     record = []
297     for rserver in rootservers:
298         record.append(ndr_pack(NSRecord(rserver, serial=0, ttl=0, rank=dnsp.DNS_RANK_ROOT_HINT)))
299
300     msg = ldb.Message(ldb.Dn(samdb, "DC=@,%s" % container_dn))
301     msg["objectClass"] = ["top", "dnsNode"]
302     msg["dnsRecord"] = ldb.MessageElement(record, ldb.FLAG_MOD_ADD, "dnsRecord")
303     samdb.add(msg)
304
305     # Add DC=<rootserver>,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
306     for rserver in rootservers:
307         record = [ndr_pack(ARecord(rootservers[rserver], serial=0, ttl=0, rank=dnsp.DNS_RANK_ROOT_HINT))]
308         # Add AAAA record as well (How does W2K* add IPv6 records?)
309         #if rserver in rootservers_v6:
310         #    record.append(ndr_pack(AAAARecord(rootservers_v6[rserver], serial=0, ttl=0)))
311         msg = ldb.Message(ldb.Dn(samdb, "DC=%s,%s" % (rserver, container_dn)))
312         msg["objectClass"] = ["top", "dnsNode"]
313         msg["dnsRecord"] = ldb.MessageElement(record, ldb.FLAG_MOD_ADD, "dnsRecord")
314         samdb.add(msg)
315
316 def add_at_record(samdb, container_dn, prefix, hostname, dnsdomain, hostip, hostip6):
317
318     fqdn_hostname = "%s.%s" % (hostname, dnsdomain)
319
320     at_records = []
321
322     # SOA record
323     at_soa_record = SOARecord(fqdn_hostname, "hostmaster.%s" % dnsdomain)
324     at_records.append(ndr_pack(at_soa_record))
325
326     # NS record
327     at_ns_record = NSRecord(fqdn_hostname)
328     at_records.append(ndr_pack(at_ns_record))
329
330     if hostip is not None:
331         # A record
332         at_a_record = ARecord(hostip)
333         at_records.append(ndr_pack(at_a_record))
334
335     if hostip6 is not None:
336         # AAAA record
337         at_aaaa_record = AAAARecord(hostip6)
338         at_records.append(ndr_pack(at_aaaa_record))
339
340     msg = ldb.Message(ldb.Dn(samdb, "DC=@,%s" % container_dn))
341     msg["objectClass"] = ["top", "dnsNode"]
342     msg["dnsRecord"] = ldb.MessageElement(at_records, ldb.FLAG_MOD_ADD, "dnsRecord")
343     samdb.add(msg)
344
345 def add_srv_record(samdb, container_dn, prefix, host, port):
346     srv_record = SRVRecord(host, port)
347     msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
348     msg["objectClass"] = ["top", "dnsNode"]
349     msg["dnsRecord"] = ldb.MessageElement(ndr_pack(srv_record), ldb.FLAG_MOD_ADD, "dnsRecord")
350     samdb.add(msg)
351
352 def add_ns_record(samdb, container_dn, prefix, host):
353     ns_record = NSRecord(host)
354     msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
355     msg["objectClass"] = ["top", "dnsNode"]
356     msg["dnsRecord"] = ldb.MessageElement(ndr_pack(ns_record), ldb.FLAG_MOD_ADD, "dnsRecord")
357     samdb.add(msg)
358
359 def add_ns_glue_record(samdb, container_dn, prefix, host):
360     ns_record = NSRecord(host, rank=dnsp.DNS_RANK_NS_GLUE)
361     msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
362     msg["objectClass"] = ["top", "dnsNode"]
363     msg["dnsRecord"] = ldb.MessageElement(ndr_pack(ns_record), ldb.FLAG_MOD_ADD, "dnsRecord")
364     samdb.add(msg)
365
366 def add_cname_record(samdb, container_dn, prefix, host):
367     cname_record = CNameRecord(host)
368     msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
369     msg["objectClass"] = ["top", "dnsNode"]
370     msg["dnsRecord"] = ldb.MessageElement(ndr_pack(cname_record), ldb.FLAG_MOD_ADD, "dnsRecord")
371     samdb.add(msg)
372
373 def add_host_record(samdb, container_dn, prefix, hostip, hostip6):
374     host_records = []
375     if hostip:
376         a_record = ARecord(hostip)
377         host_records.append(ndr_pack(a_record))
378     if hostip6:
379         aaaa_record = AAAARecord(hostip6)
380         host_records.append(ndr_pack(aaaa_record))
381     if host_records:
382         msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
383         msg["objectClass"] = ["top", "dnsNode"]
384         msg["dnsRecord"] = ldb.MessageElement(host_records, ldb.FLAG_MOD_ADD, "dnsRecord")
385         samdb.add(msg)
386
387 def add_domain_record(samdb, domaindn, prefix, dnsdomain, domainsid, dnsadmins_sid):
388     # DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
389     sddl = "O:SYG:BAD:AI" \
390     "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
391     "(A;;CC;;;AU)" \
392     "(A;;RPLCLORC;;;WD)" \
393     "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
394     "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
395     "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)" \
396     "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
397     "(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
398     "(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
399     "(A;CIID;LC;;;RU)" \
400     "(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
401     "S:AI" % dnsadmins_sid
402     sec = security.descriptor.from_sddl(sddl, domainsid)
403     props = []
404     props.append(ndr_pack(TypeProperty()))
405     props.append(ndr_pack(AllowUpdateProperty()))
406     props.append(ndr_pack(SecureTimeProperty()))
407     props.append(ndr_pack(NorefreshIntervalProperty(norefresh_interval=168)))
408     props.append(ndr_pack(RefreshIntervalProperty(refresh_interval=168)))
409     props.append(ndr_pack(AgingStateProperty()))
410     props.append(ndr_pack(AgingEnabledTimeProperty()))
411     msg = ldb.Message(ldb.Dn(samdb, "DC=%s,CN=MicrosoftDNS,%s,%s" % (dnsdomain, prefix, domaindn)))
412     msg["objectClass"] = ["top", "dnsZone"]
413     msg["ntSecurityDescriptor"] = ldb.MessageElement(ndr_pack(sec), ldb.FLAG_MOD_ADD,
414         "nTSecurityDescriptor")
415     msg["dNSProperty"] = ldb.MessageElement(props, ldb.FLAG_MOD_ADD, "dNSProperty")
416     samdb.add(msg)
417
418 def add_msdcs_record(samdb, forestdn, prefix, dnsforest):
419     # DC=_msdcs.<DNSFOREST>,CN=MicrosoftDNS,<PREFIX>,<FORESTDN>
420     msg = ldb.Message(ldb.Dn(samdb, "DC=_msdcs.%s,CN=MicrosoftDNS,%s,%s" %
421                                     (dnsforest, prefix, forestdn)))
422     msg["objectClass"] = ["top", "dnsZone"]
423     samdb.add(msg)
424
425
426 def add_dc_domain_records(samdb, domaindn, prefix, site, dnsdomain, hostname, hostip, hostip6):
427
428     fqdn_hostname = "%s.%s" % (hostname, dnsdomain)
429
430     # Set up domain container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
431     domain_container_dn = ldb.Dn(samdb, "DC=%s,CN=MicrosoftDNS,%s,%s" %
432                                     (dnsdomain, prefix, domaindn))
433
434     # DC=@ record
435     add_at_record(samdb, domain_container_dn, "DC=@", hostname, dnsdomain, hostip, hostip6)
436
437     # DC=<HOSTNAME> record
438     add_host_record(samdb, domain_container_dn, "DC=%s" % hostname, hostip, hostip6)
439
440     # DC=_kerberos._tcp record
441     add_srv_record(samdb, domain_container_dn, "DC=_kerberos._tcp", fqdn_hostname, 88)
442
443     # DC=_kerberos._tcp.<SITENAME>._sites record
444     add_srv_record(samdb, domain_container_dn, "DC=_kerberos._tcp.%s._sites" % site,
445                     fqdn_hostname, 88)
446
447     # DC=_kerberos._udp record
448     add_srv_record(samdb, domain_container_dn, "DC=_kerberos._udp", fqdn_hostname, 88)
449
450     # DC=_kpasswd._tcp record
451     add_srv_record(samdb, domain_container_dn, "DC=_kpasswd._tcp", fqdn_hostname, 464)
452
453     # DC=_kpasswd._udp record
454     add_srv_record(samdb, domain_container_dn, "DC=_kpasswd._udp", fqdn_hostname, 464)
455
456     # DC=_ldap._tcp record
457     add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp", fqdn_hostname, 389)
458
459     # DC=_ldap._tcp.<SITENAME>._sites record
460     add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.%s._sites" % site,
461                     fqdn_hostname, 389)
462
463     # FIXME: The number of SRV records depend on the various roles this DC has.
464     #        _gc and _msdcs records are added if the we are the forest dc and not subdomain dc
465     #
466     # Assumption: current DC is GC and add all the entries
467
468     # DC=_gc._tcp record
469     add_srv_record(samdb, domain_container_dn, "DC=_gc._tcp", fqdn_hostname, 3268)
470
471     # DC=_gc._tcp.<SITENAME>,_sites record
472     add_srv_record(samdb, domain_container_dn, "DC=_gc._tcp.%s._sites" % site, fqdn_hostname, 3268)
473
474     # DC=_msdcs record
475     add_ns_glue_record(samdb, domain_container_dn, "DC=_msdcs", fqdn_hostname)
476
477     # FIXME: Following entries are added only if DomainDnsZones and ForestDnsZones partitions
478     #        are created
479     #
480     # Assumption: Additional entries won't hurt on os_level = 2000
481
482     # DC=_ldap._tcp.<SITENAME>._sites.DomainDnsZones
483     add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.%s._sites.DomainDnsZones" % site,
484                     fqdn_hostname, 389)
485
486     # DC=_ldap._tcp.<SITENAME>._sites.ForestDnsZones
487     add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.%s._sites.ForestDnsZones" % site,
488                     fqdn_hostname, 389)
489
490     # DC=_ldap._tcp.DomainDnsZones
491     add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.DomainDnsZones",
492                     fqdn_hostname, 389)
493
494     # DC=_ldap._tcp.ForestDnsZones
495     add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.ForestDnsZones",
496                     fqdn_hostname, 389)
497
498     # DC=DomainDnsZones
499     add_host_record(samdb, domain_container_dn, "DC=DomainDnsZones", hostip, hostip6)
500
501     # DC=ForestDnsZones
502     add_host_record(samdb, domain_container_dn, "DC=ForestDnsZones", hostip, hostip6)
503
504
505 def add_dc_msdcs_records(samdb, forestdn, prefix, site, dnsforest, hostname,
506                             hostip, hostip6, domainguid, ntdsguid):
507
508     fqdn_hostname = "%s.%s" % (hostname, dnsforest)
509
510     # Set up forest container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
511     forest_container_dn = ldb.Dn(samdb, "DC=_msdcs.%s,CN=MicrosoftDNS,%s,%s" %
512                                     (dnsforest, prefix, forestdn))
513
514     # DC=@ record
515     add_at_record(samdb, forest_container_dn, "DC=@", hostname, dnsforest, None, None)
516
517     # DC=_kerberos._tcp.dc record
518     add_srv_record(samdb, forest_container_dn, "DC=_kerberos._tcp.dc", fqdn_hostname, 88)
519
520     # DC=_kerberos._tcp.<SITENAME>._sites.dc record
521     add_srv_record(samdb, forest_container_dn, "DC=_kerberos._tcp.%s._sites.dc" % site,
522                     fqdn_hostname, 88)
523
524     # DC=_ldap._tcp.dc record
525     add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.dc", fqdn_hostname, 389)
526
527     # DC=_ldap._tcp.<SITENAME>._sites.dc record
528     add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.%s._sites.dc" % site,
529                     fqdn_hostname, 389)
530
531     # DC=_ldap._tcp.<SITENAME>._sites.gc record
532     add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.%s._sites.gc" % site,
533                     fqdn_hostname, 3268)
534
535     # DC=_ldap._tcp.gc record
536     add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.gc", fqdn_hostname, 3268)
537
538     # DC=_ldap._tcp.pdc record
539     add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.pdc", fqdn_hostname, 389)
540
541     # DC=gc record
542     add_host_record(samdb, forest_container_dn, "DC=gc", hostip, hostip6)
543
544     # DC=_ldap._tcp.<DOMAINGUID>.domains record
545     add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.%s.domains" % domainguid,
546                     fqdn_hostname, 389)
547
548     # DC=<NTDSGUID>
549     add_cname_record(samdb, forest_container_dn, "DC=%s" % ntdsguid, fqdn_hostname)
550
551
552 def secretsdb_setup_dns(secretsdb, names, private_dir, realm,
553                         dnsdomain, dns_keytab_path, dnspass):
554     """Add DNS specific bits to a secrets database.
555
556     :param secretsdb: Ldb Handle to the secrets database
557     :param names: Names shortcut
558     :param machinepass: Machine password
559     """
560     try:
561         os.unlink(os.path.join(private_dir, dns_keytab_path))
562     except OSError:
563         pass
564
565     setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
566             "REALM": realm,
567             "DNSDOMAIN": dnsdomain,
568             "DNS_KEYTAB": dns_keytab_path,
569             "DNSPASS_B64": b64encode(dnspass),
570             "HOSTNAME": names.hostname,
571             "DNSNAME" : '%s.%s' % (
572                 names.netbiosname.lower(), names.dnsdomain.lower())
573             })
574
575
576 def create_dns_dir(logger, paths):
577     """Write out a DNS zone file, from the info in the current database.
578
579     :param logger: Logger object
580     :param paths: paths object
581     """
582     dns_dir = os.path.dirname(paths.dns)
583
584     try:
585         shutil.rmtree(dns_dir, True)
586     except OSError:
587         pass
588
589     os.mkdir(dns_dir, 0770)
590
591     if paths.bind_gid is not None:
592         try:
593             os.chown(dns_dir, -1, paths.bind_gid)
594             # chmod needed to cope with umask
595             os.chmod(dns_dir, 0770)
596         except OSError:
597             if not os.environ.has_key('SAMBA_SELFTEST'):
598                 logger.error("Failed to chown %s to bind gid %u" % (
599                     dns_dir, paths.bind_gid))
600
601
602 def create_zone_file(lp, logger, paths, targetdir, dnsdomain,
603                      hostip, hostip6, hostname, realm, domainguid,
604                      ntdsguid, site):
605     """Write out a DNS zone file, from the info in the current database.
606
607     :param paths: paths object
608     :param dnsdomain: DNS Domain name
609     :param domaindn: DN of the Domain
610     :param hostip: Local IPv4 IP
611     :param hostip6: Local IPv6 IP
612     :param hostname: Local hostname
613     :param realm: Realm name
614     :param domainguid: GUID of the domain.
615     :param ntdsguid: GUID of the hosts nTDSDSA record.
616     """
617     assert isinstance(domainguid, str)
618
619     if hostip6 is not None:
620         hostip6_base_line = "            IN AAAA    " + hostip6
621         hostip6_host_line = hostname + "        IN AAAA    " + hostip6
622         gc_msdcs_ip6_line = "gc._msdcs               IN AAAA    " + hostip6
623     else:
624         hostip6_base_line = ""
625         hostip6_host_line = ""
626         gc_msdcs_ip6_line = ""
627
628     if hostip is not None:
629         hostip_base_line = "            IN A    " + hostip
630         hostip_host_line = hostname + "        IN A    " + hostip
631         gc_msdcs_ip_line = "gc._msdcs               IN A    " + hostip
632     else:
633         hostip_base_line = ""
634         hostip_host_line = ""
635         gc_msdcs_ip_line = ""
636
637     # we need to freeze the zone while we update the contents
638     if targetdir is None:
639         rndc = ' '.join(lp.get("rndc command"))
640         os.system(rndc + " freeze " + lp.get("realm"))
641
642     setup_file(setup_path("provision.zone"), paths.dns, {
643             "HOSTNAME": hostname,
644             "DNSDOMAIN": dnsdomain,
645             "REALM": realm,
646             "HOSTIP_BASE_LINE": hostip_base_line,
647             "HOSTIP_HOST_LINE": hostip_host_line,
648             "DOMAINGUID": domainguid,
649             "DATESTRING": time.strftime("%Y%m%d%H"),
650             "DEFAULTSITE": site,
651             "NTDSGUID": ntdsguid,
652             "HOSTIP6_BASE_LINE": hostip6_base_line,
653             "HOSTIP6_HOST_LINE": hostip6_host_line,
654             "GC_MSDCS_IP_LINE": gc_msdcs_ip_line,
655             "GC_MSDCS_IP6_LINE": gc_msdcs_ip6_line,
656         })
657
658     if paths.bind_gid is not None:
659         try:
660             os.chown(paths.dns, -1, paths.bind_gid)
661             # chmod needed to cope with umask
662             os.chmod(paths.dns, 0664)
663         except OSError:
664             if not os.environ.has_key('SAMBA_SELFTEST'):
665                 logger.error("Failed to chown %s to bind gid %u" % (
666                     paths.dns, paths.bind_gid))
667
668     if targetdir is None:
669         os.system(rndc + " unfreeze " + lp.get("realm"))
670
671 def tdb_copy(logger, file1, file2):
672     """Copy tdb file using tdbbackup utility and rename it
673     """
674     # Find the location of tdbbackup tool
675     dirs = ["bin", samba.param.bin_dir()] + os.getenv('PATH').split(os.pathsep)
676     for d in dirs:
677         toolpath = os.path.join(d, "tdbbackup")
678         if os.path.exists(toolpath):
679             break
680     status = os.system("%s -s '.dns' %s" % (toolpath, file1))
681     if status == 0:
682         os.rename("%s.dns" % file1, file2)
683     else:
684         raise Exception("Error copying %s" % file1)
685
686 def create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid):
687     """Create a copy of samdb and give write permissions to named for dns partitions
688     """
689     private_dir = paths.private_dir
690     samldb_dir = os.path.join(private_dir, "sam.ldb.d")
691     dns_dir = os.path.dirname(paths.dns)
692     dns_samldb_dir = os.path.join(dns_dir, "sam.ldb.d")
693
694     # Find the partitions and corresponding filenames
695     partfile = {}
696     res = samdb.search(base="@PARTITION", scope=ldb.SCOPE_BASE, attrs=["partition"])
697     for tmp in res[0]["partition"]:
698         (nc, fname) = tmp.split(':')
699         partfile[nc.upper()] = fname
700
701     # Create empty domain partition
702     domaindn = names.domaindn.upper()
703     domainpart_file = os.path.join(dns_dir, partfile[domaindn])
704     try:
705         os.mkdir(dns_samldb_dir)
706         file(domainpart_file, 'w').close()
707
708         # Fill the basedn and @OPTION records in domain partition
709         dom_ldb = samba.Ldb(domainpart_file)
710         domainguid_line = "objectGUID: %s\n-" % domainguid
711         descr = b64encode(get_domain_descriptor(domainsid))
712         setup_add_ldif(dom_ldb, setup_path("provision_basedn.ldif"), {
713             "DOMAINDN" : names.domaindn,
714             "DOMAINGUID" : domainguid_line,
715             "DOMAINSID" : str(domainsid),
716             "DESCRIPTOR" : descr})
717         setup_add_ldif(dom_ldb, setup_path("provision_basedn_options.ldif"), None)
718     except Exception:
719         logger.error("Failed to setup database for BIND, AD based DNS cannot be used")
720         raise
721     del partfile[domaindn]
722
723     # Link dns partitions and metadata
724     domainzonedn = "DC=DOMAINDNSZONES,%s" % names.domaindn.upper()
725     forestzonedn = "DC=FORESTDNSZONES,%s" % names.rootdn.upper()
726     domainzone_file = partfile[domainzonedn]
727     forestzone_file = partfile[forestzonedn]
728     metadata_file = "metadata.tdb"
729     try:
730         os.link(os.path.join(samldb_dir, metadata_file),
731             os.path.join(dns_samldb_dir, metadata_file))
732         os.link(os.path.join(private_dir, domainzone_file),
733             os.path.join(dns_dir, domainzone_file))
734         os.link(os.path.join(private_dir, forestzone_file),
735             os.path.join(dns_dir, forestzone_file))
736     except OSError:
737         logger.error("Failed to setup database for BIND, AD based DNS cannot be used")
738         raise
739     del partfile[domainzonedn]
740     del partfile[forestzonedn]
741
742     # Copy root, config, schema partitions (and any other if any)
743     # Since samdb is open in the current process, copy them in a child process
744     try:
745         tdb_copy(logger,
746                  os.path.join(private_dir, "sam.ldb"),
747                  os.path.join(dns_dir, "sam.ldb"))
748         for nc in partfile:
749             pfile = partfile[nc]
750             tdb_copy(logger,
751                      os.path.join(private_dir, pfile),
752                      os.path.join(dns_dir, pfile))
753     except Exception:
754         logger.error("Failed to setup database for BIND, AD based DNS cannot be used")
755         raise
756
757     # Give bind read/write permissions dns partitions
758     if paths.bind_gid is not None:
759         try:
760             os.chown(samldb_dir, -1, paths.bind_gid)
761             os.chmod(samldb_dir, 0750)
762
763             for dirname, dirs, files in os.walk(dns_dir):
764                 for d in dirs:
765                     dpath = os.path.join(dirname, d)
766                     os.chown(dpath, -1, paths.bind_gid)
767                     os.chmod(dpath, 0770)
768                 for f in files:
769                     if f.endswith('.ldb') or f.endswith('.tdb'):
770                         fpath = os.path.join(dirname, f)
771                         os.chown(fpath, -1, paths.bind_gid)
772                         os.chmod(fpath, 0660)
773         except OSError:
774             if not os.environ.has_key('SAMBA_SELFTEST'):
775                 logger.error("Failed to set permissions to sam.ldb* files, fix manually")
776     else:
777         if not os.environ.has_key('SAMBA_SELFTEST'):
778             logger.warning("""Unable to find group id for BIND,
779                 set permissions to sam.ldb* files manually""")
780
781
782 def create_dns_update_list(lp, logger, paths):
783     """Write out a dns_update_list file"""
784     # note that we use no variable substitution on this file
785     # the substitution is done at runtime by samba_dnsupdate, samba_spnupdate
786     setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
787     setup_file(setup_path("spn_update_list"), paths.spn_update_list, None)
788
789
790 def create_named_conf(paths, realm, dnsdomain, dns_backend):
791     """Write out a file containing zone statements suitable for inclusion in a
792     named.conf file (including GSS-TSIG configuration).
793
794     :param paths: all paths
795     :param realm: Realm name
796     :param dnsdomain: DNS Domain name
797     :param dns_backend: DNS backend type
798     :param keytab_name: File name of DNS keytab file
799     """
800
801     if dns_backend == "BIND9_FLATFILE":
802         setup_file(setup_path("named.conf"), paths.namedconf, {
803                     "DNSDOMAIN": dnsdomain,
804                     "REALM": realm,
805                     "ZONE_FILE": paths.dns,
806                     "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
807                     "NAMED_CONF": paths.namedconf,
808                     "NAMED_CONF_UPDATE": paths.namedconf_update
809                     })
810
811         setup_file(setup_path("named.conf.update"), paths.namedconf_update)
812
813     elif dns_backend == "BIND9_DLZ":
814         dlz_module_path = os.path.join(samba.param.modules_dir(),
815                                         "bind9/dlz_bind9.so")
816         setup_file(setup_path("named.conf.dlz"), paths.namedconf, {
817                     "NAMED_CONF": paths.namedconf,
818                     "BIND9_DLZ_MODULE": dlz_module_path,
819                     })
820
821
822 def create_named_txt(path, realm, dnsdomain, dnsname, private_dir,
823     keytab_name):
824     """Write out a file containing zone statements suitable for inclusion in a
825     named.conf file (including GSS-TSIG configuration).
826
827     :param path: Path of the new named.conf file.
828     :param realm: Realm name
829     :param dnsdomain: DNS Domain name
830     :param private_dir: Path to private directory
831     :param keytab_name: File name of DNS keytab file
832     """
833     setup_file(setup_path("named.txt"), path, {
834             "DNSDOMAIN": dnsdomain,
835             "DNSNAME" : dnsname,
836             "REALM": realm,
837             "DNS_KEYTAB": keytab_name,
838             "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
839             "PRIVATE_DIR": private_dir
840         })
841
842
843 def is_valid_dns_backend(dns_backend):
844     return dns_backend in ("BIND9_FLATFILE", "BIND9_DLZ", "SAMBA_INTERNAL", "NONE")
845
846
847 def is_valid_os_level(os_level):
848     return DS_DOMAIN_FUNCTION_2000 <= os_level <= DS_DOMAIN_FUNCTION_2008_R2
849
850
851 def create_dns_legacy(samdb, domainsid, forestdn, dnsadmins_sid):
852     # Set up MicrosoftDNS container
853     add_dns_container(samdb, forestdn, "CN=System", domainsid, dnsadmins_sid)
854     # Add root servers
855     add_rootservers(samdb, forestdn, "CN=System")
856
857
858 def fill_dns_data_legacy(samdb, domainsid, forestdn, dnsdomain, site, hostname,
859                          hostip, hostip6, dnsadmins_sid):
860     # Add domain record
861     add_domain_record(samdb, forestdn, "CN=System", dnsdomain, domainsid,
862                       dnsadmins_sid)
863
864     # Add DNS records for a DC in domain
865     add_dc_domain_records(samdb, forestdn, "CN=System", site, dnsdomain,
866                           hostname, hostip, hostip6)
867
868
869 def create_dns_partitions(samdb, domainsid, names, domaindn, forestdn,
870                           dnsadmins_sid):
871     # Set up additional partitions (DomainDnsZones, ForstDnsZones)
872     setup_dns_partitions(samdb, domainsid, domaindn, forestdn,
873                         names.configdn, names.serverdn)
874
875     # Set up MicrosoftDNS containers
876     add_dns_container(samdb, domaindn, "DC=DomainDnsZones", domainsid,
877                       dnsadmins_sid)
878     add_dns_container(samdb, forestdn, "DC=ForestDnsZones", domainsid,
879                       dnsadmins_sid)
880
881
882 def fill_dns_data_partitions(samdb, domainsid, site, domaindn, forestdn,
883                             dnsdomain, dnsforest, hostname, hostip, hostip6,
884                             domainguid, ntdsguid, dnsadmins_sid, autofill=True):
885     """Fill data in various AD partitions
886
887     :param samdb: LDB object connected to sam.ldb file
888     :param domainsid: Domain SID (as dom_sid object)
889     :param site: Site name to create hostnames in
890     :param domaindn: DN of the domain
891     :param forestdn: DN of the forest
892     :param dnsdomain: DNS name of the domain
893     :param dnsforest: DNS name of the forest
894     :param hostname: Host name of this DC
895     :param hostip: IPv4 addresses
896     :param hostip6: IPv6 addresses
897     :param domainguid: Domain GUID
898     :param ntdsguid: NTDS GUID
899     :param dnsadmins_sid: SID for DnsAdmins group
900     :param autofill: Create DNS records (using fixed template)
901     """
902
903     ##### Set up DC=DomainDnsZones,<DOMAINDN>
904     # Add rootserver records
905     add_rootservers(samdb, domaindn, "DC=DomainDnsZones")
906
907     # Add domain record
908     add_domain_record(samdb, domaindn, "DC=DomainDnsZones", dnsdomain,
909                       domainsid, dnsadmins_sid)
910
911     # Add DNS records for a DC in domain
912     if autofill:
913         add_dc_domain_records(samdb, domaindn, "DC=DomainDnsZones", site,
914                               dnsdomain, hostname, hostip, hostip6)
915
916     ##### Set up DC=ForestDnsZones,<DOMAINDN>
917     # Add _msdcs record
918     add_msdcs_record(samdb, forestdn, "DC=ForestDnsZones", dnsforest)
919
920     # Add DNS records for a DC in forest
921     if autofill:
922         add_dc_msdcs_records(samdb, forestdn, "DC=ForestDnsZones", site,
923                              dnsforest, hostname, hostip, hostip6,
924                              domainguid, ntdsguid)
925
926
927 def setup_ad_dns(samdb, secretsdb, domainsid, names, paths, lp, logger, dns_backend,
928                  os_level, site, dnspass=None, hostip=None, hostip6=None,
929                  targetdir=None):
930     """Provision DNS information (assuming GC role)
931
932     :param samdb: LDB object connected to sam.ldb file
933     :param secretsdb: LDB object connected to secrets.ldb file
934     :param domainsid: Domain SID (as dom_sid object)
935     :param names: Names shortcut
936     :param paths: Paths shortcut
937     :param lp: Loadparm object
938     :param logger: Logger object
939     :param dns_backend: Type of DNS backend
940     :param os_level: Functional level (treated as os level)
941     :param site: Site to create hostnames in
942     :param dnspass: Password for bind's DNS account
943     :param hostip: IPv4 address
944     :param hostip6: IPv6 address
945     :param targetdir: Target directory for creating DNS-related files for BIND9
946     """
947
948     if not is_valid_dns_backend(dns_backend):
949         raise Exception("Invalid dns backend: %r" % dns_backend)
950
951     if not is_valid_os_level(os_level):
952         raise Exception("Invalid os level: %r" % os_level)
953
954     if dns_backend is "NONE":
955         logger.info("No DNS backend set, not configuring DNS")
956         return
957
958     # Add dns accounts (DnsAdmins, DnsUpdateProxy) in domain
959     logger.info("Adding DNS accounts")
960     add_dns_accounts(samdb, names.domaindn)
961
962     # If dns_backend is BIND9_FLATFILE
963     #   Populate only CN=MicrosoftDNS,CN=System,<FORESTDN>
964     #
965     # If dns_backend is SAMBA_INTERNAL or BIND9_DLZ
966     #   Populate DNS partitions
967
968     # If os_level < 2003 (DS_DOMAIN_FUNCTION_2000)
969     #   All dns records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
970     #
971     # If os_level >= 2003 (DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008,
972     #                        DS_DOMAIN_FUNCTION_2008_R2)
973     #   Root server records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
974     #   Domain records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
975     #   Domain records are in CN=MicrosoftDNS,DC=DomainDnsZones,<DOMAINDN>
976     #   Forest records are in CN=MicrosoftDNS,DC=ForestDnsZones,<FORESTDN>
977     domaindn = names.domaindn
978     forestdn = samdb.get_root_basedn().get_linearized()
979
980     dnsdomain = names.dnsdomain.lower()
981     dnsforest = dnsdomain
982
983     hostname = names.netbiosname.lower()
984
985     dnsadmins_sid = get_dnsadmins_sid(samdb, domaindn)
986     domainguid = get_domainguid(samdb, domaindn)
987
988     # Create CN=System
989     logger.info("Creating CN=MicrosoftDNS,CN=System,%s" % forestdn)
990     create_dns_legacy(samdb, domainsid, forestdn, dnsadmins_sid)
991
992     if os_level == DS_DOMAIN_FUNCTION_2000:
993         # Populating legacy dns
994         logger.info("Populating CN=MicrosoftDNS,CN=System,%s" % forestdn)
995         fill_dns_data_legacy(samdb, domainsid, forestdn, dnsdomain, site,
996                              hostname, hostip, hostip6, dnsadmins_sid)
997
998     elif dns_backend in ("SAMBA_INTERNAL", "BIND9_DLZ") and \
999             os_level >= DS_DOMAIN_FUNCTION_2003:
1000
1001         # Create DNS partitions
1002         logger.info("Creating DomainDnsZones and ForestDnsZones partitions")
1003         create_dns_partitions(samdb, domainsid, names, domaindn, forestdn,
1004                               dnsadmins_sid)
1005
1006         # Populating dns partitions
1007         logger.info("Populating DomainDnsZones and ForestDnsZones partitions")
1008         fill_dns_data_partitions(samdb, domainsid, site, domaindn, forestdn,
1009                                 dnsdomain, dnsforest, hostname, hostip, hostip6,
1010                                 domainguid, names.ntdsguid, dnsadmins_sid)
1011
1012     if dns_backend.startswith("BIND9_"):
1013         secretsdb_setup_dns(secretsdb, names,
1014                             paths.private_dir, realm=names.realm,
1015                             dnsdomain=names.dnsdomain,
1016                             dns_keytab_path=paths.dns_keytab, dnspass=dnspass)
1017
1018         create_dns_dir(logger, paths)
1019
1020         if dns_backend == "BIND9_FLATFILE":
1021             create_zone_file(lp, logger, paths, targetdir, site=site,
1022                              dnsdomain=names.dnsdomain, hostip=hostip, hostip6=hostip6,
1023                              hostname=names.hostname, realm=names.realm,
1024                              domainguid=domainguid, ntdsguid=names.ntdsguid)
1025
1026         if dns_backend == "BIND9_DLZ" and os_level >= DS_DOMAIN_FUNCTION_2003:
1027             create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid)
1028
1029         create_named_conf(paths, realm=names.realm,
1030                           dnsdomain=names.dnsdomain, dns_backend=dns_backend)
1031
1032         create_named_txt(paths.namedtxt,
1033                          realm=names.realm, dnsdomain=names.dnsdomain,
1034                          dnsname = "%s.%s" % (names.hostname, names.dnsdomain),
1035                          private_dir=paths.private_dir,
1036                          keytab_name=paths.dns_keytab)
1037         logger.info("See %s for an example configuration include file for BIND", paths.namedconf)
1038         logger.info("and %s for further documentation required for secure DNS "
1039                     "updates", paths.namedtxt)