scripting: Make tdb_copy use the python subprocess module
[Samba/gbeck.git] / source4 / scripting / python / samba / provision / sambadns.py
blob21675113d6ba1050f75444760ba3c194d0cdf218
1 # Unix SMB/CIFS implementation.
2 # backend code for provisioning DNS for a Samba4 server
4 # Copyright (C) Kai Blin <kai@samba.org> 2011
5 # Copyright (C) Amitay Isaacs <amitay@gmail.com> 2011
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.
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.
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/>.
21 """DNS-related provisioning"""
23 import os
24 import uuid
25 import shutil
26 import time
27 import ldb
28 from base64 import b64encode
29 import samba
30 import subprocess
31 from samba.ndr import ndr_pack, ndr_unpack
32 from samba import setup_file
33 from samba.dcerpc import dnsp, misc, security
34 from samba.dsdb import (
35 DS_DOMAIN_FUNCTION_2000,
36 DS_DOMAIN_FUNCTION_2003,
37 DS_DOMAIN_FUNCTION_2008_R2
39 from samba.provision.descriptor import (
40 get_domain_descriptor,
41 get_domain_delete_protected1_descriptor,
42 get_domain_delete_protected2_descriptor,
43 get_dns_partition_descriptor,
44 get_dns_forest_microsoft_dns_descriptor,
45 get_dns_domain_microsoft_dns_descriptor
47 from samba.provision.common import (
48 setup_path,
49 setup_add_ldif,
50 setup_modify_ldif,
51 setup_ldb
55 def get_domainguid(samdb, domaindn):
56 res = samdb.search(base=domaindn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"])
57 domainguid = str(ndr_unpack(misc.GUID, res[0]["objectGUID"][0]))
58 return domainguid
61 def get_dnsadmins_sid(samdb, domaindn):
62 res = samdb.search(base="CN=DnsAdmins,CN=Users,%s" % domaindn, scope=ldb.SCOPE_BASE,
63 attrs=["objectSid"])
64 dnsadmins_sid = ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
65 return dnsadmins_sid
68 class ARecord(dnsp.DnssrvRpcRecord):
70 def __init__(self, ip_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
71 super(ARecord, self).__init__()
72 self.wType = dnsp.DNS_TYPE_A
73 self.rank = rank
74 self.dwSerial = serial
75 self.dwTtlSeconds = ttl
76 self.data = ip_addr
79 class AAAARecord(dnsp.DnssrvRpcRecord):
81 def __init__(self, ip6_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
82 super(AAAARecord, self).__init__()
83 self.wType = dnsp.DNS_TYPE_AAAA
84 self.rank = rank
85 self.dwSerial = serial
86 self.dwTtlSeconds = ttl
87 self.data = ip6_addr
90 class CNameRecord(dnsp.DnssrvRpcRecord):
92 def __init__(self, cname, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
93 super(CNameRecord, self).__init__()
94 self.wType = dnsp.DNS_TYPE_CNAME
95 self.rank = rank
96 self.dwSerial = serial
97 self.dwTtlSeconds = ttl
98 self.data = cname
101 class NSRecord(dnsp.DnssrvRpcRecord):
103 def __init__(self, dns_server, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
104 super(NSRecord, self).__init__()
105 self.wType = dnsp.DNS_TYPE_NS
106 self.rank = rank
107 self.dwSerial = serial
108 self.dwTtlSeconds = ttl
109 self.data = dns_server
112 class SOARecord(dnsp.DnssrvRpcRecord):
114 def __init__(self, mname, rname, serial=1, refresh=900, retry=600,
115 expire=86400, minimum=3600, ttl=3600, rank=dnsp.DNS_RANK_ZONE):
116 super(SOARecord, self).__init__()
117 self.wType = dnsp.DNS_TYPE_SOA
118 self.rank = rank
119 self.dwSerial = serial
120 self.dwTtlSeconds = ttl
121 soa = dnsp.soa()
122 soa.serial = serial
123 soa.refresh = refresh
124 soa.retry = retry
125 soa.expire = expire
126 soa.mname = mname
127 soa.rname = rname
128 self.data = soa
131 class SRVRecord(dnsp.DnssrvRpcRecord):
133 def __init__(self, target, port, priority=0, weight=100, serial=1, ttl=900,
134 rank=dnsp.DNS_RANK_ZONE):
135 super(SRVRecord, self).__init__()
136 self.wType = dnsp.DNS_TYPE_SRV
137 self.rank = rank
138 self.dwSerial = serial
139 self.dwTtlSeconds = ttl
140 srv = dnsp.srv()
141 srv.nameTarget = target
142 srv.wPort = port
143 srv.wPriority = priority
144 srv.wWeight = weight
145 self.data = srv
148 class TXTRecord(dnsp.DnssrvRpcRecord):
150 def __init__(self, slist, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
151 super(TXTRecord, self).__init__()
152 self.wType = dnsp.DNS_TYPE_TXT
153 self.rank = rank
154 self.dwSerial = serial
155 self.dwTtlSeconds = ttl
156 stringlist = dnsp.string_list()
157 stringlist.count = len(slist)
158 stringlist.str = slist
159 self.data = stringlist
162 class TypeProperty(dnsp.DnsProperty):
164 def __init__(self, zone_type=dnsp.DNS_ZONE_TYPE_PRIMARY):
165 super(TypeProperty, self).__init__()
166 self.wDataLength = 1
167 self.version = 1
168 self.id = dnsp.DSPROPERTY_ZONE_TYPE
169 self.data = zone_type
172 class AllowUpdateProperty(dnsp.DnsProperty):
174 def __init__(self, allow_update=dnsp.DNS_ZONE_UPDATE_SECURE):
175 super(AllowUpdateProperty, self).__init__()
176 self.wDataLength = 1
177 self.version = 1
178 self.id = dnsp.DSPROPERTY_ZONE_ALLOW_UPDATE
179 self.data = allow_update
182 class SecureTimeProperty(dnsp.DnsProperty):
184 def __init__(self, secure_time=0):
185 super(SecureTimeProperty, self).__init__()
186 self.wDataLength = 1
187 self.version = 1
188 self.id = dnsp.DSPROPERTY_ZONE_SECURE_TIME
189 self.data = secure_time
192 class NorefreshIntervalProperty(dnsp.DnsProperty):
194 def __init__(self, norefresh_interval=0):
195 super(NorefreshIntervalProperty, self).__init__()
196 self.wDataLength = 1
197 self.version = 1
198 self.id = dnsp.DSPROPERTY_ZONE_NOREFRESH_INTERVAL
199 self.data = norefresh_interval
202 class RefreshIntervalProperty(dnsp.DnsProperty):
204 def __init__(self, refresh_interval=0):
205 super(RefreshIntervalProperty, self).__init__()
206 self.wDataLength = 1
207 self.version = 1
208 self.id = dnsp.DSPROPERTY_ZONE_REFRESH_INTERVAL
209 self.data = refresh_interval
212 class AgingStateProperty(dnsp.DnsProperty):
214 def __init__(self, aging_enabled=0):
215 super(AgingStateProperty, self).__init__()
216 self.wDataLength = 1
217 self.version = 1
218 self.id = dnsp.DSPROPERTY_ZONE_AGING_STATE
219 self.data = aging_enabled
222 class AgingEnabledTimeProperty(dnsp.DnsProperty):
224 def __init__(self, next_cycle_hours=0):
225 super(AgingEnabledTimeProperty, self).__init__()
226 self.wDataLength = 1
227 self.version = 1;
228 self.id = dnsp.DSPROPERTY_ZONE_AGING_ENABLED_TIME
229 self.data = next_cycle_hours
232 def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn,
233 serverdn):
234 domainzone_dn = "DC=DomainDnsZones,%s" % domaindn
235 forestzone_dn = "DC=ForestDnsZones,%s" % forestdn
236 descriptor = get_dns_partition_descriptor(domainsid)
237 setup_add_ldif(samdb, setup_path("provision_dnszones_partitions.ldif"), {
238 "DOMAINZONE_DN": domainzone_dn,
239 "FORESTZONE_DN": forestzone_dn,
240 "SECDESC" : b64encode(descriptor)
243 domainzone_guid = get_domainguid(samdb, domainzone_dn)
244 forestzone_guid = get_domainguid(samdb, forestzone_dn)
246 domainzone_guid = str(uuid.uuid4())
247 forestzone_guid = str(uuid.uuid4())
249 domainzone_dns = ldb.Dn(samdb, domainzone_dn).canonical_ex_str().strip()
250 forestzone_dns = ldb.Dn(samdb, forestzone_dn).canonical_ex_str().strip()
252 protected1_desc = get_domain_delete_protected1_descriptor(domainsid)
253 protected2_desc = get_domain_delete_protected2_descriptor(domainsid)
254 setup_add_ldif(samdb, setup_path("provision_dnszones_add.ldif"), {
255 "DOMAINZONE_DN": domainzone_dn,
256 "FORESTZONE_DN": forestzone_dn,
257 "DOMAINZONE_GUID": domainzone_guid,
258 "FORESTZONE_GUID": forestzone_guid,
259 "DOMAINZONE_DNS": domainzone_dns,
260 "FORESTZONE_DNS": forestzone_dns,
261 "CONFIGDN": configdn,
262 "SERVERDN": serverdn,
263 "LOSTANDFOUND_DESCRIPTOR": b64encode(protected2_desc),
264 "INFRASTRUCTURE_DESCRIPTOR": b64encode(protected1_desc),
267 setup_modify_ldif(samdb, setup_path("provision_dnszones_modify.ldif"), {
268 "CONFIGDN": configdn,
269 "SERVERDN": serverdn,
270 "DOMAINZONE_DN": domainzone_dn,
271 "FORESTZONE_DN": forestzone_dn,
275 def add_dns_accounts(samdb, domaindn):
276 setup_add_ldif(samdb, setup_path("provision_dns_accounts_add.ldif"), {
277 "DOMAINDN": domaindn,
281 def add_dns_container(samdb, domaindn, prefix, domain_sid, dnsadmins_sid, forest=False):
282 name_map = {'DnsAdmins': str(dnsadmins_sid)}
283 if forest is True:
284 sd_val = get_dns_forest_microsoft_dns_descriptor(domain_sid,
285 name_map=name_map)
286 else:
287 sd_val = get_dns_domain_microsoft_dns_descriptor(domain_sid,
288 name_map=name_map)
289 # CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
290 msg = ldb.Message(ldb.Dn(samdb, "CN=MicrosoftDNS,%s,%s" % (prefix, domaindn)))
291 msg["objectClass"] = ["top", "container"]
292 msg["nTSecurityDescriptor"] = ldb.MessageElement(sd_val, ldb.FLAG_MOD_ADD,
293 "nTSecurityDescriptor")
294 samdb.add(msg)
297 def add_rootservers(samdb, domaindn, prefix):
298 rootservers = {}
299 rootservers["a.root-servers.net"] = "198.41.0.4"
300 rootservers["b.root-servers.net"] = "192.228.79.201"
301 rootservers["c.root-servers.net"] = "192.33.4.12"
302 rootservers["d.root-servers.net"] = "128.8.10.90"
303 rootservers["e.root-servers.net"] = "192.203.230.10"
304 rootservers["f.root-servers.net"] = "192.5.5.241"
305 rootservers["g.root-servers.net"] = "192.112.36.4"
306 rootservers["h.root-servers.net"] = "128.63.2.53"
307 rootservers["i.root-servers.net"] = "192.36.148.17"
308 rootservers["j.root-servers.net"] = "192.58.128.30"
309 rootservers["k.root-servers.net"] = "193.0.14.129"
310 rootservers["l.root-servers.net"] = "199.7.83.42"
311 rootservers["m.root-servers.net"] = "202.12.27.33"
313 rootservers_v6 = {}
314 rootservers_v6["a.root-servers.net"] = "2001:503:ba3e::2:30"
315 rootservers_v6["f.root-servers.net"] = "2001:500:2f::f"
316 rootservers_v6["h.root-servers.net"] = "2001:500:1::803f:235"
317 rootservers_v6["j.root-servers.net"] = "2001:503:c27::2:30"
318 rootservers_v6["k.root-servers.net"] = "2001:7fd::1"
319 rootservers_v6["m.root-servers.net"] = "2001:dc3::35"
321 container_dn = "DC=RootDNSServers,CN=MicrosoftDNS,%s,%s" % (prefix, domaindn)
323 # Add DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
324 msg = ldb.Message(ldb.Dn(samdb, container_dn))
325 props = []
326 props.append(ndr_pack(TypeProperty(zone_type=dnsp.DNS_ZONE_TYPE_CACHE)))
327 props.append(ndr_pack(AllowUpdateProperty(allow_update=dnsp.DNS_ZONE_UPDATE_OFF)))
328 props.append(ndr_pack(SecureTimeProperty()))
329 props.append(ndr_pack(NorefreshIntervalProperty()))
330 props.append(ndr_pack(RefreshIntervalProperty()))
331 props.append(ndr_pack(AgingStateProperty()))
332 props.append(ndr_pack(AgingEnabledTimeProperty()))
333 msg["objectClass"] = ["top", "dnsZone"]
334 msg["cn"] = ldb.MessageElement("Zone", ldb.FLAG_MOD_ADD, "cn")
335 msg["dNSProperty"] = ldb.MessageElement(props, ldb.FLAG_MOD_ADD, "dNSProperty")
336 samdb.add(msg)
338 # Add DC=@,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
339 record = []
340 for rserver in rootservers:
341 record.append(ndr_pack(NSRecord(rserver, serial=0, ttl=0, rank=dnsp.DNS_RANK_ROOT_HINT)))
343 msg = ldb.Message(ldb.Dn(samdb, "DC=@,%s" % container_dn))
344 msg["objectClass"] = ["top", "dnsNode"]
345 msg["dnsRecord"] = ldb.MessageElement(record, ldb.FLAG_MOD_ADD, "dnsRecord")
346 samdb.add(msg)
348 # Add DC=<rootserver>,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
349 for rserver in rootservers:
350 record = [ndr_pack(ARecord(rootservers[rserver], serial=0, ttl=0, rank=dnsp.DNS_RANK_ROOT_HINT))]
351 # Add AAAA record as well (How does W2K* add IPv6 records?)
352 #if rserver in rootservers_v6:
353 # record.append(ndr_pack(AAAARecord(rootservers_v6[rserver], serial=0, ttl=0)))
354 msg = ldb.Message(ldb.Dn(samdb, "DC=%s,%s" % (rserver, container_dn)))
355 msg["objectClass"] = ["top", "dnsNode"]
356 msg["dnsRecord"] = ldb.MessageElement(record, ldb.FLAG_MOD_ADD, "dnsRecord")
357 samdb.add(msg)
359 def add_at_record(samdb, container_dn, prefix, hostname, dnsdomain, hostip, hostip6):
361 fqdn_hostname = "%s.%s" % (hostname, dnsdomain)
363 at_records = []
365 # SOA record
366 at_soa_record = SOARecord(fqdn_hostname, "hostmaster.%s" % dnsdomain)
367 at_records.append(ndr_pack(at_soa_record))
369 # NS record
370 at_ns_record = NSRecord(fqdn_hostname)
371 at_records.append(ndr_pack(at_ns_record))
373 if hostip is not None:
374 # A record
375 at_a_record = ARecord(hostip)
376 at_records.append(ndr_pack(at_a_record))
378 if hostip6 is not None:
379 # AAAA record
380 at_aaaa_record = AAAARecord(hostip6)
381 at_records.append(ndr_pack(at_aaaa_record))
383 msg = ldb.Message(ldb.Dn(samdb, "DC=@,%s" % container_dn))
384 msg["objectClass"] = ["top", "dnsNode"]
385 msg["dnsRecord"] = ldb.MessageElement(at_records, ldb.FLAG_MOD_ADD, "dnsRecord")
386 samdb.add(msg)
389 def add_srv_record(samdb, container_dn, prefix, host, port):
390 srv_record = SRVRecord(host, port)
391 msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
392 msg["objectClass"] = ["top", "dnsNode"]
393 msg["dnsRecord"] = ldb.MessageElement(ndr_pack(srv_record), ldb.FLAG_MOD_ADD, "dnsRecord")
394 samdb.add(msg)
397 def add_ns_record(samdb, container_dn, prefix, host):
398 ns_record = NSRecord(host)
399 msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
400 msg["objectClass"] = ["top", "dnsNode"]
401 msg["dnsRecord"] = ldb.MessageElement(ndr_pack(ns_record), ldb.FLAG_MOD_ADD, "dnsRecord")
402 samdb.add(msg)
405 def add_ns_glue_record(samdb, container_dn, prefix, host):
406 ns_record = NSRecord(host, rank=dnsp.DNS_RANK_NS_GLUE)
407 msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
408 msg["objectClass"] = ["top", "dnsNode"]
409 msg["dnsRecord"] = ldb.MessageElement(ndr_pack(ns_record), ldb.FLAG_MOD_ADD, "dnsRecord")
410 samdb.add(msg)
413 def add_cname_record(samdb, container_dn, prefix, host):
414 cname_record = CNameRecord(host)
415 msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
416 msg["objectClass"] = ["top", "dnsNode"]
417 msg["dnsRecord"] = ldb.MessageElement(ndr_pack(cname_record), ldb.FLAG_MOD_ADD, "dnsRecord")
418 samdb.add(msg)
421 def add_host_record(samdb, container_dn, prefix, hostip, hostip6):
422 host_records = []
423 if hostip:
424 a_record = ARecord(hostip)
425 host_records.append(ndr_pack(a_record))
426 if hostip6:
427 aaaa_record = AAAARecord(hostip6)
428 host_records.append(ndr_pack(aaaa_record))
429 if host_records:
430 msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
431 msg["objectClass"] = ["top", "dnsNode"]
432 msg["dnsRecord"] = ldb.MessageElement(host_records, ldb.FLAG_MOD_ADD, "dnsRecord")
433 samdb.add(msg)
436 def add_domain_record(samdb, domaindn, prefix, dnsdomain, domainsid, dnsadmins_sid):
437 # DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
438 sddl = "O:SYG:BAD:AI" \
439 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
440 "(A;;CC;;;AU)" \
441 "(A;;RPLCLORC;;;WD)" \
442 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
443 "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
444 "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)" \
445 "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
446 "(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
447 "(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
448 "(A;CIID;LC;;;RU)" \
449 "(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
450 "S:AI" % dnsadmins_sid
451 sec = security.descriptor.from_sddl(sddl, domainsid)
452 props = []
453 props.append(ndr_pack(TypeProperty()))
454 props.append(ndr_pack(AllowUpdateProperty()))
455 props.append(ndr_pack(SecureTimeProperty()))
456 props.append(ndr_pack(NorefreshIntervalProperty(norefresh_interval=168)))
457 props.append(ndr_pack(RefreshIntervalProperty(refresh_interval=168)))
458 props.append(ndr_pack(AgingStateProperty()))
459 props.append(ndr_pack(AgingEnabledTimeProperty()))
460 msg = ldb.Message(ldb.Dn(samdb, "DC=%s,CN=MicrosoftDNS,%s,%s" % (dnsdomain, prefix, domaindn)))
461 msg["objectClass"] = ["top", "dnsZone"]
462 msg["ntSecurityDescriptor"] = ldb.MessageElement(ndr_pack(sec), ldb.FLAG_MOD_ADD,
463 "nTSecurityDescriptor")
464 msg["dNSProperty"] = ldb.MessageElement(props, ldb.FLAG_MOD_ADD, "dNSProperty")
465 samdb.add(msg)
468 def add_msdcs_record(samdb, forestdn, prefix, dnsforest):
469 # DC=_msdcs.<DNSFOREST>,CN=MicrosoftDNS,<PREFIX>,<FORESTDN>
470 msg = ldb.Message(ldb.Dn(samdb, "DC=_msdcs.%s,CN=MicrosoftDNS,%s,%s" %
471 (dnsforest, prefix, forestdn)))
472 msg["objectClass"] = ["top", "dnsZone"]
473 samdb.add(msg)
476 def add_dc_domain_records(samdb, domaindn, prefix, site, dnsdomain, hostname,
477 hostip, hostip6):
479 fqdn_hostname = "%s.%s" % (hostname, dnsdomain)
481 # Set up domain container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
482 domain_container_dn = ldb.Dn(samdb, "DC=%s,CN=MicrosoftDNS,%s,%s" %
483 (dnsdomain, prefix, domaindn))
485 # DC=@ record
486 add_at_record(samdb, domain_container_dn, "DC=@", hostname, dnsdomain,
487 hostip, hostip6)
489 # DC=<HOSTNAME> record
490 add_host_record(samdb, domain_container_dn, "DC=%s" % hostname, hostip,
491 hostip6)
493 # DC=_kerberos._tcp record
494 add_srv_record(samdb, domain_container_dn, "DC=_kerberos._tcp",
495 fqdn_hostname, 88)
497 # DC=_kerberos._tcp.<SITENAME>._sites record
498 add_srv_record(samdb, domain_container_dn, "DC=_kerberos._tcp.%s._sites" %
499 site, fqdn_hostname, 88)
501 # DC=_kerberos._udp record
502 add_srv_record(samdb, domain_container_dn, "DC=_kerberos._udp",
503 fqdn_hostname, 88)
505 # DC=_kpasswd._tcp record
506 add_srv_record(samdb, domain_container_dn, "DC=_kpasswd._tcp",
507 fqdn_hostname, 464)
509 # DC=_kpasswd._udp record
510 add_srv_record(samdb, domain_container_dn, "DC=_kpasswd._udp",
511 fqdn_hostname, 464)
513 # DC=_ldap._tcp record
514 add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp", fqdn_hostname,
515 389)
517 # DC=_ldap._tcp.<SITENAME>._sites record
518 add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.%s._sites" %
519 site, fqdn_hostname, 389)
521 # FIXME: The number of SRV records depend on the various roles this DC has.
522 # _gc and _msdcs records are added if the we are the forest dc and not subdomain dc
524 # Assumption: current DC is GC and add all the entries
526 # DC=_gc._tcp record
527 add_srv_record(samdb, domain_container_dn, "DC=_gc._tcp", fqdn_hostname,
528 3268)
530 # DC=_gc._tcp.<SITENAME>,_sites record
531 add_srv_record(samdb, domain_container_dn, "DC=_gc._tcp.%s._sites" % site,
532 fqdn_hostname, 3268)
534 # DC=_msdcs record
535 add_ns_glue_record(samdb, domain_container_dn, "DC=_msdcs", fqdn_hostname)
537 # FIXME: Following entries are added only if DomainDnsZones and ForestDnsZones partitions
538 # are created
540 # Assumption: Additional entries won't hurt on os_level = 2000
542 # DC=_ldap._tcp.<SITENAME>._sites.DomainDnsZones
543 add_srv_record(samdb, domain_container_dn,
544 "DC=_ldap._tcp.%s._sites.DomainDnsZones" % site, fqdn_hostname,
545 389)
547 # DC=_ldap._tcp.<SITENAME>._sites.ForestDnsZones
548 add_srv_record(samdb, domain_container_dn,
549 "DC=_ldap._tcp.%s._sites.ForestDnsZones" % site, fqdn_hostname,
550 389)
552 # DC=_ldap._tcp.DomainDnsZones
553 add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.DomainDnsZones",
554 fqdn_hostname, 389)
556 # DC=_ldap._tcp.ForestDnsZones
557 add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.ForestDnsZones",
558 fqdn_hostname, 389)
560 # DC=DomainDnsZones
561 add_host_record(samdb, domain_container_dn, "DC=DomainDnsZones", hostip,
562 hostip6)
564 # DC=ForestDnsZones
565 add_host_record(samdb, domain_container_dn, "DC=ForestDnsZones", hostip,
566 hostip6)
569 def add_dc_msdcs_records(samdb, forestdn, prefix, site, dnsforest, hostname,
570 hostip, hostip6, domainguid, ntdsguid):
572 fqdn_hostname = "%s.%s" % (hostname, dnsforest)
574 # Set up forest container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
575 forest_container_dn = ldb.Dn(samdb, "DC=_msdcs.%s,CN=MicrosoftDNS,%s,%s" %
576 (dnsforest, prefix, forestdn))
578 # DC=@ record
579 add_at_record(samdb, forest_container_dn, "DC=@", hostname, dnsforest,
580 None, None)
582 # DC=_kerberos._tcp.dc record
583 add_srv_record(samdb, forest_container_dn, "DC=_kerberos._tcp.dc",
584 fqdn_hostname, 88)
586 # DC=_kerberos._tcp.<SITENAME>._sites.dc record
587 add_srv_record(samdb, forest_container_dn,
588 "DC=_kerberos._tcp.%s._sites.dc" % site, fqdn_hostname, 88)
590 # DC=_ldap._tcp.dc record
591 add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.dc",
592 fqdn_hostname, 389)
594 # DC=_ldap._tcp.<SITENAME>._sites.dc record
595 add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.%s._sites.dc" %
596 site, fqdn_hostname, 389)
598 # DC=_ldap._tcp.<SITENAME>._sites.gc record
599 add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.%s._sites.gc" %
600 site, fqdn_hostname, 3268)
602 # DC=_ldap._tcp.gc record
603 add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.gc",
604 fqdn_hostname, 3268)
606 # DC=_ldap._tcp.pdc record
607 add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.pdc",
608 fqdn_hostname, 389)
610 # DC=gc record
611 add_host_record(samdb, forest_container_dn, "DC=gc", hostip, hostip6)
613 # DC=_ldap._tcp.<DOMAINGUID>.domains record
614 add_srv_record(samdb, forest_container_dn,
615 "DC=_ldap._tcp.%s.domains" % domainguid, fqdn_hostname, 389)
617 # DC=<NTDSGUID>
618 add_cname_record(samdb, forest_container_dn, "DC=%s" % ntdsguid,
619 fqdn_hostname)
622 def secretsdb_setup_dns(secretsdb, names, private_dir, realm,
623 dnsdomain, dns_keytab_path, dnspass):
624 """Add DNS specific bits to a secrets database.
626 :param secretsdb: Ldb Handle to the secrets database
627 :param names: Names shortcut
628 :param machinepass: Machine password
630 try:
631 os.unlink(os.path.join(private_dir, dns_keytab_path))
632 except OSError:
633 pass
635 setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
636 "REALM": realm,
637 "DNSDOMAIN": dnsdomain,
638 "DNS_KEYTAB": dns_keytab_path,
639 "DNSPASS_B64": b64encode(dnspass),
640 "HOSTNAME": names.hostname,
641 "DNSNAME" : '%s.%s' % (
642 names.netbiosname.lower(), names.dnsdomain.lower())
646 def create_dns_dir(logger, paths):
647 """Write out a DNS zone file, from the info in the current database.
649 :param logger: Logger object
650 :param paths: paths object
652 dns_dir = os.path.dirname(paths.dns)
654 try:
655 shutil.rmtree(dns_dir, True)
656 except OSError:
657 pass
659 os.mkdir(dns_dir, 0770)
661 if paths.bind_gid is not None:
662 try:
663 os.chown(dns_dir, -1, paths.bind_gid)
664 # chmod needed to cope with umask
665 os.chmod(dns_dir, 0770)
666 except OSError:
667 if not os.environ.has_key('SAMBA_SELFTEST'):
668 logger.error("Failed to chown %s to bind gid %u" % (
669 dns_dir, paths.bind_gid))
672 def create_zone_file(lp, logger, paths, targetdir, dnsdomain,
673 hostip, hostip6, hostname, realm, domainguid,
674 ntdsguid, site):
675 """Write out a DNS zone file, from the info in the current database.
677 :param paths: paths object
678 :param dnsdomain: DNS Domain name
679 :param domaindn: DN of the Domain
680 :param hostip: Local IPv4 IP
681 :param hostip6: Local IPv6 IP
682 :param hostname: Local hostname
683 :param realm: Realm name
684 :param domainguid: GUID of the domain.
685 :param ntdsguid: GUID of the hosts nTDSDSA record.
687 assert isinstance(domainguid, str)
689 if hostip6 is not None:
690 hostip6_base_line = " IN AAAA " + hostip6
691 hostip6_host_line = hostname + " IN AAAA " + hostip6
692 gc_msdcs_ip6_line = "gc._msdcs IN AAAA " + hostip6
693 else:
694 hostip6_base_line = ""
695 hostip6_host_line = ""
696 gc_msdcs_ip6_line = ""
698 if hostip is not None:
699 hostip_base_line = " IN A " + hostip
700 hostip_host_line = hostname + " IN A " + hostip
701 gc_msdcs_ip_line = "gc._msdcs IN A " + hostip
702 else:
703 hostip_base_line = ""
704 hostip_host_line = ""
705 gc_msdcs_ip_line = ""
707 # we need to freeze the zone while we update the contents
708 if targetdir is None:
709 rndc = ' '.join(lp.get("rndc command"))
710 os.system(rndc + " freeze " + lp.get("realm"))
712 setup_file(setup_path("provision.zone"), paths.dns, {
713 "HOSTNAME": hostname,
714 "DNSDOMAIN": dnsdomain,
715 "REALM": realm,
716 "HOSTIP_BASE_LINE": hostip_base_line,
717 "HOSTIP_HOST_LINE": hostip_host_line,
718 "DOMAINGUID": domainguid,
719 "DATESTRING": time.strftime("%Y%m%d%H"),
720 "DEFAULTSITE": site,
721 "NTDSGUID": ntdsguid,
722 "HOSTIP6_BASE_LINE": hostip6_base_line,
723 "HOSTIP6_HOST_LINE": hostip6_host_line,
724 "GC_MSDCS_IP_LINE": gc_msdcs_ip_line,
725 "GC_MSDCS_IP6_LINE": gc_msdcs_ip6_line,
728 if paths.bind_gid is not None:
729 try:
730 os.chown(paths.dns, -1, paths.bind_gid)
731 # chmod needed to cope with umask
732 os.chmod(paths.dns, 0664)
733 except OSError:
734 if not os.environ.has_key('SAMBA_SELFTEST'):
735 logger.error("Failed to chown %s to bind gid %u" % (
736 paths.dns, paths.bind_gid))
738 if targetdir is None:
739 os.system(rndc + " unfreeze " + lp.get("realm"))
742 def tdb_copy(file1, file2):
743 """Copy tdb file using tdbbackup utility and rename it
745 # Find the location of tdbbackup tool
746 dirs = ["bin", samba.param.bin_dir()] + os.getenv('PATH').split(os.pathsep)
747 for d in dirs:
748 toolpath = os.path.join(d, "tdbbackup")
749 if os.path.exists(toolpath):
750 break
752 tdbbackup_cmd = [toolpath, "-s", ".copy.tdb", file1]
753 status = subprocess.call(tdbbackup_cmd, close_fds=True, shell=False)
755 if status == 0:
756 os.rename("%s.copy.tdb" % file1, file2)
757 else:
758 raise Exception("Error copying %s" % file1)
761 def create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid):
762 """Create a copy of samdb and give write permissions to named for dns partitions
764 private_dir = paths.private_dir
765 samldb_dir = os.path.join(private_dir, "sam.ldb.d")
766 dns_dir = os.path.dirname(paths.dns)
767 dns_samldb_dir = os.path.join(dns_dir, "sam.ldb.d")
769 # Find the partitions and corresponding filenames
770 partfile = {}
771 res = samdb.search(base="@PARTITION", scope=ldb.SCOPE_BASE, attrs=["partition"])
772 for tmp in res[0]["partition"]:
773 (nc, fname) = tmp.split(':')
774 partfile[nc.upper()] = fname
776 # Create empty domain partition
777 domaindn = names.domaindn.upper()
778 domainpart_file = os.path.join(dns_dir, partfile[domaindn])
779 try:
780 os.mkdir(dns_samldb_dir)
781 file(domainpart_file, 'w').close()
783 # Fill the basedn and @OPTION records in domain partition
784 dom_ldb = samba.Ldb(domainpart_file)
785 domainguid_line = "objectGUID: %s\n-" % domainguid
786 descr = b64encode(get_domain_descriptor(domainsid))
787 setup_add_ldif(dom_ldb, setup_path("provision_basedn.ldif"), {
788 "DOMAINDN" : names.domaindn,
789 "DOMAINGUID" : domainguid_line,
790 "DOMAINSID" : str(domainsid),
791 "DESCRIPTOR" : descr})
792 setup_add_ldif(dom_ldb,
793 setup_path("provision_basedn_options.ldif"), None)
794 except:
795 logger.error(
796 "Failed to setup database for BIND, AD based DNS cannot be used")
797 raise
798 del partfile[domaindn]
800 # Link dns partitions and metadata
801 domainzonedn = "DC=DOMAINDNSZONES,%s" % names.domaindn.upper()
802 forestzonedn = "DC=FORESTDNSZONES,%s" % names.rootdn.upper()
803 domainzone_file = partfile[domainzonedn]
804 forestzone_file = partfile[forestzonedn]
805 metadata_file = "metadata.tdb"
806 try:
807 os.link(os.path.join(samldb_dir, metadata_file),
808 os.path.join(dns_samldb_dir, metadata_file))
809 os.link(os.path.join(private_dir, domainzone_file),
810 os.path.join(dns_dir, domainzone_file))
811 os.link(os.path.join(private_dir, forestzone_file),
812 os.path.join(dns_dir, forestzone_file))
813 except OSError:
814 logger.error(
815 "Failed to setup database for BIND, AD based DNS cannot be used")
816 raise
817 del partfile[domainzonedn]
818 del partfile[forestzonedn]
820 # Copy root, config, schema partitions (and any other if any)
821 # Since samdb is open in the current process, copy them in a child process
822 try:
823 tdb_copy(os.path.join(private_dir, "sam.ldb"),
824 os.path.join(dns_dir, "sam.ldb"))
825 for nc in partfile:
826 pfile = partfile[nc]
827 tdb_copy(os.path.join(private_dir, pfile),
828 os.path.join(dns_dir, pfile))
829 except:
830 logger.error(
831 "Failed to setup database for BIND, AD based DNS cannot be used")
832 raise
834 # Give bind read/write permissions dns partitions
835 if paths.bind_gid is not None:
836 try:
837 os.chown(samldb_dir, -1, paths.bind_gid)
838 os.chmod(samldb_dir, 0750)
840 for dirname, dirs, files in os.walk(dns_dir):
841 for d in dirs:
842 dpath = os.path.join(dirname, d)
843 os.chown(dpath, -1, paths.bind_gid)
844 os.chmod(dpath, 0770)
845 for f in files:
846 if f.endswith('.ldb') or f.endswith('.tdb'):
847 fpath = os.path.join(dirname, f)
848 os.chown(fpath, -1, paths.bind_gid)
849 os.chmod(fpath, 0660)
850 except OSError:
851 if not os.environ.has_key('SAMBA_SELFTEST'):
852 logger.error(
853 "Failed to set permissions to sam.ldb* files, fix manually")
854 else:
855 if not os.environ.has_key('SAMBA_SELFTEST'):
856 logger.warning("""Unable to find group id for BIND,
857 set permissions to sam.ldb* files manually""")
860 def create_dns_update_list(lp, logger, paths):
861 """Write out a dns_update_list file"""
862 # note that we use no variable substitution on this file
863 # the substitution is done at runtime by samba_dnsupdate, samba_spnupdate
864 setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
865 setup_file(setup_path("spn_update_list"), paths.spn_update_list, None)
868 def create_named_conf(paths, realm, dnsdomain, dns_backend):
869 """Write out a file containing zone statements suitable for inclusion in a
870 named.conf file (including GSS-TSIG configuration).
872 :param paths: all paths
873 :param realm: Realm name
874 :param dnsdomain: DNS Domain name
875 :param dns_backend: DNS backend type
876 :param keytab_name: File name of DNS keytab file
879 if dns_backend == "BIND9_FLATFILE":
880 setup_file(setup_path("named.conf"), paths.namedconf, {
881 "DNSDOMAIN": dnsdomain,
882 "REALM": realm,
883 "ZONE_FILE": paths.dns,
884 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
885 "NAMED_CONF": paths.namedconf,
886 "NAMED_CONF_UPDATE": paths.namedconf_update
889 setup_file(setup_path("named.conf.update"), paths.namedconf_update)
891 elif dns_backend == "BIND9_DLZ":
892 setup_file(setup_path("named.conf.dlz"), paths.namedconf, {
893 "NAMED_CONF": paths.namedconf,
894 "MODULESDIR" : samba.param.modules_dir(),
898 def create_named_txt(path, realm, dnsdomain, dnsname, private_dir,
899 keytab_name):
900 """Write out a file containing zone statements suitable for inclusion in a
901 named.conf file (including GSS-TSIG configuration).
903 :param path: Path of the new named.conf file.
904 :param realm: Realm name
905 :param dnsdomain: DNS Domain name
906 :param private_dir: Path to private directory
907 :param keytab_name: File name of DNS keytab file
909 setup_file(setup_path("named.txt"), path, {
910 "DNSDOMAIN": dnsdomain,
911 "DNSNAME" : dnsname,
912 "REALM": realm,
913 "DNS_KEYTAB": keytab_name,
914 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
915 "PRIVATE_DIR": private_dir
919 def is_valid_dns_backend(dns_backend):
920 return dns_backend in ("BIND9_FLATFILE", "BIND9_DLZ", "SAMBA_INTERNAL", "NONE")
923 def is_valid_os_level(os_level):
924 return DS_DOMAIN_FUNCTION_2000 <= os_level <= DS_DOMAIN_FUNCTION_2008_R2
927 def create_dns_legacy(samdb, domainsid, forestdn, dnsadmins_sid):
928 # Set up MicrosoftDNS container
929 add_dns_container(samdb, forestdn, "CN=System", domainsid, dnsadmins_sid)
930 # Add root servers
931 add_rootservers(samdb, forestdn, "CN=System")
934 def fill_dns_data_legacy(samdb, domainsid, forestdn, dnsdomain, site, hostname,
935 hostip, hostip6, dnsadmins_sid):
936 # Add domain record
937 add_domain_record(samdb, forestdn, "CN=System", dnsdomain, domainsid,
938 dnsadmins_sid)
940 # Add DNS records for a DC in domain
941 add_dc_domain_records(samdb, forestdn, "CN=System", site, dnsdomain,
942 hostname, hostip, hostip6)
945 def create_dns_partitions(samdb, domainsid, names, domaindn, forestdn,
946 dnsadmins_sid):
947 # Set up additional partitions (DomainDnsZones, ForstDnsZones)
948 setup_dns_partitions(samdb, domainsid, domaindn, forestdn,
949 names.configdn, names.serverdn)
951 # Set up MicrosoftDNS containers
952 add_dns_container(samdb, domaindn, "DC=DomainDnsZones", domainsid,
953 dnsadmins_sid)
954 add_dns_container(samdb, forestdn, "DC=ForestDnsZones", domainsid,
955 dnsadmins_sid, forest=True)
958 def fill_dns_data_partitions(samdb, domainsid, site, domaindn, forestdn,
959 dnsdomain, dnsforest, hostname, hostip, hostip6,
960 domainguid, ntdsguid, dnsadmins_sid, autofill=True):
961 """Fill data in various AD partitions
963 :param samdb: LDB object connected to sam.ldb file
964 :param domainsid: Domain SID (as dom_sid object)
965 :param site: Site name to create hostnames in
966 :param domaindn: DN of the domain
967 :param forestdn: DN of the forest
968 :param dnsdomain: DNS name of the domain
969 :param dnsforest: DNS name of the forest
970 :param hostname: Host name of this DC
971 :param hostip: IPv4 addresses
972 :param hostip6: IPv6 addresses
973 :param domainguid: Domain GUID
974 :param ntdsguid: NTDS GUID
975 :param dnsadmins_sid: SID for DnsAdmins group
976 :param autofill: Create DNS records (using fixed template)
979 ##### Set up DC=DomainDnsZones,<DOMAINDN>
980 # Add rootserver records
981 add_rootservers(samdb, domaindn, "DC=DomainDnsZones")
983 # Add domain record
984 add_domain_record(samdb, domaindn, "DC=DomainDnsZones", dnsdomain,
985 domainsid, dnsadmins_sid)
987 # Add DNS records for a DC in domain
988 if autofill:
989 add_dc_domain_records(samdb, domaindn, "DC=DomainDnsZones", site,
990 dnsdomain, hostname, hostip, hostip6)
992 ##### Set up DC=ForestDnsZones,<DOMAINDN>
993 # Add _msdcs record
994 add_msdcs_record(samdb, forestdn, "DC=ForestDnsZones", dnsforest)
996 # Add DNS records for a DC in forest
997 if autofill:
998 add_dc_msdcs_records(samdb, forestdn, "DC=ForestDnsZones", site,
999 dnsforest, hostname, hostip, hostip6,
1000 domainguid, ntdsguid)
1003 def setup_ad_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
1004 dns_backend, os_level, site, dnspass=None, hostip=None, hostip6=None,
1005 targetdir=None):
1006 """Provision DNS information (assuming GC role)
1008 :param samdb: LDB object connected to sam.ldb file
1009 :param secretsdb: LDB object connected to secrets.ldb file
1010 :param domainsid: Domain SID (as dom_sid object)
1011 :param names: Names shortcut
1012 :param paths: Paths shortcut
1013 :param lp: Loadparm object
1014 :param logger: Logger object
1015 :param dns_backend: Type of DNS backend
1016 :param os_level: Functional level (treated as os level)
1017 :param site: Site to create hostnames in
1018 :param dnspass: Password for bind's DNS account
1019 :param hostip: IPv4 address
1020 :param hostip6: IPv6 address
1021 :param targetdir: Target directory for creating DNS-related files for BIND9
1024 if not is_valid_dns_backend(dns_backend):
1025 raise Exception("Invalid dns backend: %r" % dns_backend)
1027 if not is_valid_os_level(os_level):
1028 raise Exception("Invalid os level: %r" % os_level)
1030 if dns_backend == "NONE":
1031 logger.info("No DNS backend set, not configuring DNS")
1032 return
1034 # Add dns accounts (DnsAdmins, DnsUpdateProxy) in domain
1035 logger.info("Adding DNS accounts")
1036 add_dns_accounts(samdb, names.domaindn)
1038 # If dns_backend is BIND9_FLATFILE
1039 # Populate only CN=MicrosoftDNS,CN=System,<FORESTDN>
1041 # If dns_backend is SAMBA_INTERNAL or BIND9_DLZ
1042 # Populate DNS partitions
1044 # If os_level < 2003 (DS_DOMAIN_FUNCTION_2000)
1045 # All dns records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
1047 # If os_level >= 2003 (DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008,
1048 # DS_DOMAIN_FUNCTION_2008_R2)
1049 # Root server records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
1050 # Domain records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
1051 # Domain records are in CN=MicrosoftDNS,DC=DomainDnsZones,<DOMAINDN>
1052 # Forest records are in CN=MicrosoftDNS,DC=ForestDnsZones,<FORESTDN>
1053 domaindn = names.domaindn
1054 forestdn = samdb.get_root_basedn().get_linearized()
1056 dnsdomain = names.dnsdomain.lower()
1057 dnsforest = dnsdomain
1059 hostname = names.netbiosname.lower()
1061 dnsadmins_sid = get_dnsadmins_sid(samdb, domaindn)
1062 domainguid = get_domainguid(samdb, domaindn)
1064 # Create CN=System
1065 logger.info("Creating CN=MicrosoftDNS,CN=System,%s" % forestdn)
1066 create_dns_legacy(samdb, domainsid, forestdn, dnsadmins_sid)
1068 if os_level == DS_DOMAIN_FUNCTION_2000:
1069 # Populating legacy dns
1070 logger.info("Populating CN=MicrosoftDNS,CN=System,%s" % forestdn)
1071 fill_dns_data_legacy(samdb, domainsid, forestdn, dnsdomain, site,
1072 hostname, hostip, hostip6, dnsadmins_sid)
1074 elif dns_backend in ("SAMBA_INTERNAL", "BIND9_DLZ") and \
1075 os_level >= DS_DOMAIN_FUNCTION_2003:
1077 # Create DNS partitions
1078 logger.info("Creating DomainDnsZones and ForestDnsZones partitions")
1079 create_dns_partitions(samdb, domainsid, names, domaindn, forestdn,
1080 dnsadmins_sid)
1082 # Populating dns partitions
1083 logger.info("Populating DomainDnsZones and ForestDnsZones partitions")
1084 fill_dns_data_partitions(samdb, domainsid, site, domaindn, forestdn,
1085 dnsdomain, dnsforest, hostname, hostip, hostip6,
1086 domainguid, names.ntdsguid, dnsadmins_sid)
1088 if dns_backend.startswith("BIND9_"):
1089 setup_bind9_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
1090 dns_backend, os_level, site=site, dnspass=dnspass, hostip=hostip,
1091 hostip6=hostip6, targetdir=targetdir)
1094 def setup_bind9_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
1095 dns_backend, os_level, site=None, dnspass=None, hostip=None,
1096 hostip6=None, targetdir=None):
1097 """Provision DNS information (assuming BIND9 backend in DC role)
1099 :param samdb: LDB object connected to sam.ldb file
1100 :param secretsdb: LDB object connected to secrets.ldb file
1101 :param domainsid: Domain SID (as dom_sid object)
1102 :param names: Names shortcut
1103 :param paths: Paths shortcut
1104 :param lp: Loadparm object
1105 :param logger: Logger object
1106 :param dns_backend: Type of DNS backend
1107 :param os_level: Functional level (treated as os level)
1108 :param site: Site to create hostnames in
1109 :param dnspass: Password for bind's DNS account
1110 :param hostip: IPv4 address
1111 :param hostip6: IPv6 address
1112 :param targetdir: Target directory for creating DNS-related files for BIND9
1115 if (not is_valid_dns_backend(dns_backend) or
1116 not dns_backend.startswith("BIND9_")):
1117 raise Exception("Invalid dns backend: %r" % dns_backend)
1119 if not is_valid_os_level(os_level):
1120 raise Exception("Invalid os level: %r" % os_level)
1122 domaindn = names.domaindn
1124 domainguid = get_domainguid(samdb, domaindn)
1126 secretsdb_setup_dns(secretsdb, names,
1127 paths.private_dir, realm=names.realm,
1128 dnsdomain=names.dnsdomain,
1129 dns_keytab_path=paths.dns_keytab, dnspass=dnspass)
1131 create_dns_dir(logger, paths)
1133 if dns_backend == "BIND9_FLATFILE":
1134 create_zone_file(lp, logger, paths, targetdir, site=site,
1135 dnsdomain=names.dnsdomain, hostip=hostip,
1136 hostip6=hostip6, hostname=names.hostname,
1137 realm=names.realm, domainguid=domainguid,
1138 ntdsguid=names.ntdsguid)
1140 if dns_backend == "BIND9_DLZ" and os_level >= DS_DOMAIN_FUNCTION_2003:
1141 create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid)
1143 create_named_conf(paths, realm=names.realm,
1144 dnsdomain=names.dnsdomain, dns_backend=dns_backend)
1146 create_named_txt(paths.namedtxt,
1147 realm=names.realm, dnsdomain=names.dnsdomain,
1148 dnsname = "%s.%s" % (names.hostname, names.dnsdomain),
1149 private_dir=paths.private_dir,
1150 keytab_name=paths.dns_keytab)
1151 logger.info("See %s for an example configuration include file for BIND",
1152 paths.namedconf)
1153 logger.info("and %s for further documentation required for secure DNS "
1154 "updates", paths.namedtxt)