replace: Fix bug 11455
[Samba.git] / python / samba / provision / sambadns.py
blobb5639324b45e4af63ea0b4e53ae60b8ee1bba5df
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 subprocess
30 import samba
31 from samba.tdb_util import tdb_copy
32 from samba.ndr import ndr_pack, ndr_unpack
33 from samba import setup_file
34 from samba.dcerpc import dnsp, misc, security
35 from samba.dsdb import (
36 DS_DOMAIN_FUNCTION_2000,
37 DS_DOMAIN_FUNCTION_2003,
38 DS_DOMAIN_FUNCTION_2008_R2
40 from samba.descriptor import (
41 get_domain_descriptor,
42 get_domain_delete_protected1_descriptor,
43 get_domain_delete_protected2_descriptor,
44 get_dns_partition_descriptor,
45 get_dns_forest_microsoft_dns_descriptor,
46 get_dns_domain_microsoft_dns_descriptor
48 from samba.provision.common import (
49 setup_path,
50 setup_add_ldif,
51 setup_modify_ldif,
52 setup_ldb,
53 FILL_FULL,
54 FILL_SUBDOMAIN,
55 FILL_NT4SYNC,
56 FILL_DRS,
60 def get_domainguid(samdb, domaindn):
61 res = samdb.search(base=domaindn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"])
62 domainguid = str(ndr_unpack(misc.GUID, res[0]["objectGUID"][0]))
63 return domainguid
66 def get_dnsadmins_sid(samdb, domaindn):
67 res = samdb.search(base="CN=DnsAdmins,CN=Users,%s" % domaindn, scope=ldb.SCOPE_BASE,
68 attrs=["objectSid"])
69 dnsadmins_sid = ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
70 return dnsadmins_sid
73 class ARecord(dnsp.DnssrvRpcRecord):
75 def __init__(self, ip_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
76 super(ARecord, self).__init__()
77 self.wType = dnsp.DNS_TYPE_A
78 self.rank = rank
79 self.dwSerial = serial
80 self.dwTtlSeconds = ttl
81 self.data = ip_addr
84 class AAAARecord(dnsp.DnssrvRpcRecord):
86 def __init__(self, ip6_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
87 super(AAAARecord, self).__init__()
88 self.wType = dnsp.DNS_TYPE_AAAA
89 self.rank = rank
90 self.dwSerial = serial
91 self.dwTtlSeconds = ttl
92 self.data = ip6_addr
95 class CNameRecord(dnsp.DnssrvRpcRecord):
97 def __init__(self, cname, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
98 super(CNameRecord, self).__init__()
99 self.wType = dnsp.DNS_TYPE_CNAME
100 self.rank = rank
101 self.dwSerial = serial
102 self.dwTtlSeconds = ttl
103 self.data = cname
106 class NSRecord(dnsp.DnssrvRpcRecord):
108 def __init__(self, dns_server, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
109 super(NSRecord, self).__init__()
110 self.wType = dnsp.DNS_TYPE_NS
111 self.rank = rank
112 self.dwSerial = serial
113 self.dwTtlSeconds = ttl
114 self.data = dns_server
117 class SOARecord(dnsp.DnssrvRpcRecord):
119 def __init__(self, mname, rname, serial=1, refresh=900, retry=600,
120 expire=86400, minimum=3600, ttl=3600, rank=dnsp.DNS_RANK_ZONE):
121 super(SOARecord, self).__init__()
122 self.wType = dnsp.DNS_TYPE_SOA
123 self.rank = rank
124 self.dwSerial = serial
125 self.dwTtlSeconds = ttl
126 soa = dnsp.soa()
127 soa.serial = serial
128 soa.refresh = refresh
129 soa.retry = retry
130 soa.expire = expire
131 soa.mname = mname
132 soa.rname = rname
133 soa.minimum = minimum
134 self.data = soa
137 class SRVRecord(dnsp.DnssrvRpcRecord):
139 def __init__(self, target, port, priority=0, weight=100, serial=1, ttl=900,
140 rank=dnsp.DNS_RANK_ZONE):
141 super(SRVRecord, self).__init__()
142 self.wType = dnsp.DNS_TYPE_SRV
143 self.rank = rank
144 self.dwSerial = serial
145 self.dwTtlSeconds = ttl
146 srv = dnsp.srv()
147 srv.nameTarget = target
148 srv.wPort = port
149 srv.wPriority = priority
150 srv.wWeight = weight
151 self.data = srv
154 class TXTRecord(dnsp.DnssrvRpcRecord):
156 def __init__(self, slist, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
157 super(TXTRecord, self).__init__()
158 self.wType = dnsp.DNS_TYPE_TXT
159 self.rank = rank
160 self.dwSerial = serial
161 self.dwTtlSeconds = ttl
162 stringlist = dnsp.string_list()
163 stringlist.count = len(slist)
164 stringlist.str = slist
165 self.data = stringlist
168 class TypeProperty(dnsp.DnsProperty):
170 def __init__(self, zone_type=dnsp.DNS_ZONE_TYPE_PRIMARY):
171 super(TypeProperty, self).__init__()
172 self.wDataLength = 1
173 self.version = 1
174 self.id = dnsp.DSPROPERTY_ZONE_TYPE
175 self.data = zone_type
178 class AllowUpdateProperty(dnsp.DnsProperty):
180 def __init__(self, allow_update=dnsp.DNS_ZONE_UPDATE_SECURE):
181 super(AllowUpdateProperty, self).__init__()
182 self.wDataLength = 1
183 self.version = 1
184 self.id = dnsp.DSPROPERTY_ZONE_ALLOW_UPDATE
185 self.data = allow_update
188 class SecureTimeProperty(dnsp.DnsProperty):
190 def __init__(self, secure_time=0):
191 super(SecureTimeProperty, self).__init__()
192 self.wDataLength = 1
193 self.version = 1
194 self.id = dnsp.DSPROPERTY_ZONE_SECURE_TIME
195 self.data = secure_time
198 class NorefreshIntervalProperty(dnsp.DnsProperty):
200 def __init__(self, norefresh_interval=0):
201 super(NorefreshIntervalProperty, self).__init__()
202 self.wDataLength = 1
203 self.version = 1
204 self.id = dnsp.DSPROPERTY_ZONE_NOREFRESH_INTERVAL
205 self.data = norefresh_interval
208 class RefreshIntervalProperty(dnsp.DnsProperty):
210 def __init__(self, refresh_interval=0):
211 super(RefreshIntervalProperty, self).__init__()
212 self.wDataLength = 1
213 self.version = 1
214 self.id = dnsp.DSPROPERTY_ZONE_REFRESH_INTERVAL
215 self.data = refresh_interval
218 class AgingStateProperty(dnsp.DnsProperty):
220 def __init__(self, aging_enabled=0):
221 super(AgingStateProperty, self).__init__()
222 self.wDataLength = 1
223 self.version = 1
224 self.id = dnsp.DSPROPERTY_ZONE_AGING_STATE
225 self.data = aging_enabled
228 class AgingEnabledTimeProperty(dnsp.DnsProperty):
230 def __init__(self, next_cycle_hours=0):
231 super(AgingEnabledTimeProperty, self).__init__()
232 self.wDataLength = 1
233 self.version = 1;
234 self.id = dnsp.DSPROPERTY_ZONE_AGING_ENABLED_TIME
235 self.data = next_cycle_hours
238 def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn,
239 serverdn, fill_level):
240 domainzone_dn = "DC=DomainDnsZones,%s" % domaindn
241 forestzone_dn = "DC=ForestDnsZones,%s" % forestdn
242 descriptor = get_dns_partition_descriptor(domainsid)
244 setup_add_ldif(samdb, setup_path("provision_dnszones_partitions.ldif"), {
245 "ZONE_DN": domainzone_dn,
246 "SECDESC" : b64encode(descriptor)
248 if fill_level != FILL_SUBDOMAIN:
249 setup_add_ldif(samdb, setup_path("provision_dnszones_partitions.ldif"), {
250 "ZONE_DN": forestzone_dn,
251 "SECDESC" : b64encode(descriptor)
254 domainzone_guid = get_domainguid(samdb, domainzone_dn)
255 domainzone_guid = str(uuid.uuid4())
256 domainzone_dns = ldb.Dn(samdb, domainzone_dn).canonical_ex_str().strip()
258 protected1_desc = get_domain_delete_protected1_descriptor(domainsid)
259 protected2_desc = get_domain_delete_protected2_descriptor(domainsid)
260 setup_add_ldif(samdb, setup_path("provision_dnszones_add.ldif"), {
261 "ZONE_DN": domainzone_dn,
262 "ZONE_GUID": domainzone_guid,
263 "ZONE_DNS": domainzone_dns,
264 "CONFIGDN": configdn,
265 "SERVERDN": serverdn,
266 "LOSTANDFOUND_DESCRIPTOR": b64encode(protected2_desc),
267 "INFRASTRUCTURE_DESCRIPTOR": b64encode(protected1_desc),
269 setup_modify_ldif(samdb, setup_path("provision_dnszones_modify.ldif"), {
270 "CONFIGDN": configdn,
271 "SERVERDN": serverdn,
272 "ZONE_DN": domainzone_dn,
275 if fill_level != FILL_SUBDOMAIN:
276 forestzone_guid = get_domainguid(samdb, forestzone_dn)
277 forestzone_guid = str(uuid.uuid4())
278 forestzone_dns = ldb.Dn(samdb, forestzone_dn).canonical_ex_str().strip()
280 setup_add_ldif(samdb, setup_path("provision_dnszones_add.ldif"), {
281 "ZONE_DN": forestzone_dn,
282 "ZONE_GUID": forestzone_guid,
283 "ZONE_DNS": forestzone_dns,
284 "CONFIGDN": configdn,
285 "SERVERDN": serverdn,
286 "LOSTANDFOUND_DESCRIPTOR": b64encode(protected2_desc),
287 "INFRASTRUCTURE_DESCRIPTOR": b64encode(protected1_desc),
289 setup_modify_ldif(samdb, setup_path("provision_dnszones_modify.ldif"), {
290 "CONFIGDN": configdn,
291 "SERVERDN": serverdn,
292 "ZONE_DN": forestzone_dn,
296 def add_dns_accounts(samdb, domaindn):
297 setup_add_ldif(samdb, setup_path("provision_dns_accounts_add.ldif"), {
298 "DOMAINDN": domaindn,
302 def add_dns_container(samdb, domaindn, prefix, domain_sid, dnsadmins_sid, forest=False):
303 name_map = {'DnsAdmins': str(dnsadmins_sid)}
304 if forest is True:
305 sd_val = get_dns_forest_microsoft_dns_descriptor(domain_sid,
306 name_map=name_map)
307 else:
308 sd_val = get_dns_domain_microsoft_dns_descriptor(domain_sid,
309 name_map=name_map)
310 # CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
311 msg = ldb.Message(ldb.Dn(samdb, "CN=MicrosoftDNS,%s,%s" % (prefix, domaindn)))
312 msg["objectClass"] = ["top", "container"]
313 msg["nTSecurityDescriptor"] = ldb.MessageElement(sd_val, ldb.FLAG_MOD_ADD,
314 "nTSecurityDescriptor")
315 samdb.add(msg)
318 def add_rootservers(samdb, domaindn, prefix):
319 rootservers = {}
320 rootservers["a.root-servers.net"] = "198.41.0.4"
321 rootservers["b.root-servers.net"] = "192.228.79.201"
322 rootservers["c.root-servers.net"] = "192.33.4.12"
323 rootservers["d.root-servers.net"] = "128.8.10.90"
324 rootservers["e.root-servers.net"] = "192.203.230.10"
325 rootservers["f.root-servers.net"] = "192.5.5.241"
326 rootservers["g.root-servers.net"] = "192.112.36.4"
327 rootservers["h.root-servers.net"] = "128.63.2.53"
328 rootservers["i.root-servers.net"] = "192.36.148.17"
329 rootservers["j.root-servers.net"] = "192.58.128.30"
330 rootservers["k.root-servers.net"] = "193.0.14.129"
331 rootservers["l.root-servers.net"] = "199.7.83.42"
332 rootservers["m.root-servers.net"] = "202.12.27.33"
334 rootservers_v6 = {}
335 rootservers_v6["a.root-servers.net"] = "2001:503:ba3e::2:30"
336 rootservers_v6["f.root-servers.net"] = "2001:500:2f::f"
337 rootservers_v6["h.root-servers.net"] = "2001:500:1::803f:235"
338 rootservers_v6["j.root-servers.net"] = "2001:503:c27::2:30"
339 rootservers_v6["k.root-servers.net"] = "2001:7fd::1"
340 rootservers_v6["m.root-servers.net"] = "2001:dc3::35"
342 container_dn = "DC=RootDNSServers,CN=MicrosoftDNS,%s,%s" % (prefix, domaindn)
344 # Add DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
345 msg = ldb.Message(ldb.Dn(samdb, container_dn))
346 props = []
347 props.append(ndr_pack(TypeProperty(zone_type=dnsp.DNS_ZONE_TYPE_CACHE)))
348 props.append(ndr_pack(AllowUpdateProperty(allow_update=dnsp.DNS_ZONE_UPDATE_OFF)))
349 props.append(ndr_pack(SecureTimeProperty()))
350 props.append(ndr_pack(NorefreshIntervalProperty()))
351 props.append(ndr_pack(RefreshIntervalProperty()))
352 props.append(ndr_pack(AgingStateProperty()))
353 props.append(ndr_pack(AgingEnabledTimeProperty()))
354 msg["objectClass"] = ["top", "dnsZone"]
355 msg["cn"] = ldb.MessageElement("Zone", ldb.FLAG_MOD_ADD, "cn")
356 msg["dNSProperty"] = ldb.MessageElement(props, ldb.FLAG_MOD_ADD, "dNSProperty")
357 samdb.add(msg)
359 # Add DC=@,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
360 record = []
361 for rserver in rootservers:
362 record.append(ndr_pack(NSRecord(rserver, serial=0, ttl=0, rank=dnsp.DNS_RANK_ROOT_HINT)))
364 msg = ldb.Message(ldb.Dn(samdb, "DC=@,%s" % container_dn))
365 msg["objectClass"] = ["top", "dnsNode"]
366 msg["dnsRecord"] = ldb.MessageElement(record, ldb.FLAG_MOD_ADD, "dnsRecord")
367 samdb.add(msg)
369 # Add DC=<rootserver>,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
370 for rserver in rootservers:
371 record = [ndr_pack(ARecord(rootservers[rserver], serial=0, ttl=0, rank=dnsp.DNS_RANK_ROOT_HINT))]
372 # Add AAAA record as well (How does W2K* add IPv6 records?)
373 #if rserver in rootservers_v6:
374 # record.append(ndr_pack(AAAARecord(rootservers_v6[rserver], serial=0, ttl=0)))
375 msg = ldb.Message(ldb.Dn(samdb, "DC=%s,%s" % (rserver, container_dn)))
376 msg["objectClass"] = ["top", "dnsNode"]
377 msg["dnsRecord"] = ldb.MessageElement(record, ldb.FLAG_MOD_ADD, "dnsRecord")
378 samdb.add(msg)
380 def add_at_record(samdb, container_dn, prefix, hostname, dnsdomain, hostip, hostip6):
382 fqdn_hostname = "%s.%s" % (hostname, dnsdomain)
384 at_records = []
386 # SOA record
387 at_soa_record = SOARecord(fqdn_hostname, "hostmaster.%s" % dnsdomain)
388 at_records.append(ndr_pack(at_soa_record))
390 # NS record
391 at_ns_record = NSRecord(fqdn_hostname)
392 at_records.append(ndr_pack(at_ns_record))
394 if hostip is not None:
395 # A record
396 at_a_record = ARecord(hostip)
397 at_records.append(ndr_pack(at_a_record))
399 if hostip6 is not None:
400 # AAAA record
401 at_aaaa_record = AAAARecord(hostip6)
402 at_records.append(ndr_pack(at_aaaa_record))
404 msg = ldb.Message(ldb.Dn(samdb, "DC=@,%s" % container_dn))
405 msg["objectClass"] = ["top", "dnsNode"]
406 msg["dnsRecord"] = ldb.MessageElement(at_records, ldb.FLAG_MOD_ADD, "dnsRecord")
407 samdb.add(msg)
410 def add_srv_record(samdb, container_dn, prefix, host, port):
411 srv_record = SRVRecord(host, port)
412 msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
413 msg["objectClass"] = ["top", "dnsNode"]
414 msg["dnsRecord"] = ldb.MessageElement(ndr_pack(srv_record), ldb.FLAG_MOD_ADD, "dnsRecord")
415 samdb.add(msg)
418 def add_ns_record(samdb, container_dn, prefix, host):
419 ns_record = NSRecord(host)
420 msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
421 msg["objectClass"] = ["top", "dnsNode"]
422 msg["dnsRecord"] = ldb.MessageElement(ndr_pack(ns_record), ldb.FLAG_MOD_ADD, "dnsRecord")
423 samdb.add(msg)
426 def add_ns_glue_record(samdb, container_dn, prefix, host):
427 ns_record = NSRecord(host, rank=dnsp.DNS_RANK_NS_GLUE)
428 msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
429 msg["objectClass"] = ["top", "dnsNode"]
430 msg["dnsRecord"] = ldb.MessageElement(ndr_pack(ns_record), ldb.FLAG_MOD_ADD, "dnsRecord")
431 samdb.add(msg)
434 def add_cname_record(samdb, container_dn, prefix, host):
435 cname_record = CNameRecord(host)
436 msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
437 msg["objectClass"] = ["top", "dnsNode"]
438 msg["dnsRecord"] = ldb.MessageElement(ndr_pack(cname_record), ldb.FLAG_MOD_ADD, "dnsRecord")
439 samdb.add(msg)
442 def add_host_record(samdb, container_dn, prefix, hostip, hostip6):
443 host_records = []
444 if hostip:
445 a_record = ARecord(hostip)
446 host_records.append(ndr_pack(a_record))
447 if hostip6:
448 aaaa_record = AAAARecord(hostip6)
449 host_records.append(ndr_pack(aaaa_record))
450 if host_records:
451 msg = ldb.Message(ldb.Dn(samdb, "%s,%s" % (prefix, container_dn)))
452 msg["objectClass"] = ["top", "dnsNode"]
453 msg["dnsRecord"] = ldb.MessageElement(host_records, ldb.FLAG_MOD_ADD, "dnsRecord")
454 samdb.add(msg)
457 def add_domain_record(samdb, domaindn, prefix, dnsdomain, domainsid, dnsadmins_sid):
458 # DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
459 sddl = "O:SYG:BAD:AI" \
460 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
461 "(A;;CC;;;AU)" \
462 "(A;;RPLCLORC;;;WD)" \
463 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
464 "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
465 "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)" \
466 "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
467 "(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
468 "(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
469 "(A;CIID;LC;;;RU)" \
470 "(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
471 "S:AI" % dnsadmins_sid
472 sec = security.descriptor.from_sddl(sddl, domainsid)
473 props = []
474 props.append(ndr_pack(TypeProperty()))
475 props.append(ndr_pack(AllowUpdateProperty()))
476 props.append(ndr_pack(SecureTimeProperty()))
477 props.append(ndr_pack(NorefreshIntervalProperty(norefresh_interval=168)))
478 props.append(ndr_pack(RefreshIntervalProperty(refresh_interval=168)))
479 props.append(ndr_pack(AgingStateProperty()))
480 props.append(ndr_pack(AgingEnabledTimeProperty()))
481 msg = ldb.Message(ldb.Dn(samdb, "DC=%s,CN=MicrosoftDNS,%s,%s" % (dnsdomain, prefix, domaindn)))
482 msg["objectClass"] = ["top", "dnsZone"]
483 msg["ntSecurityDescriptor"] = ldb.MessageElement(ndr_pack(sec), ldb.FLAG_MOD_ADD,
484 "nTSecurityDescriptor")
485 msg["dNSProperty"] = ldb.MessageElement(props, ldb.FLAG_MOD_ADD, "dNSProperty")
486 samdb.add(msg)
489 def add_msdcs_record(samdb, forestdn, prefix, dnsforest):
490 # DC=_msdcs.<DNSFOREST>,CN=MicrosoftDNS,<PREFIX>,<FORESTDN>
491 msg = ldb.Message(ldb.Dn(samdb, "DC=_msdcs.%s,CN=MicrosoftDNS,%s,%s" %
492 (dnsforest, prefix, forestdn)))
493 msg["objectClass"] = ["top", "dnsZone"]
494 samdb.add(msg)
497 def add_dc_domain_records(samdb, domaindn, prefix, site, dnsdomain, hostname,
498 hostip, hostip6):
500 fqdn_hostname = "%s.%s" % (hostname, dnsdomain)
502 # Set up domain container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
503 domain_container_dn = ldb.Dn(samdb, "DC=%s,CN=MicrosoftDNS,%s,%s" %
504 (dnsdomain, prefix, domaindn))
506 # DC=@ record
507 add_at_record(samdb, domain_container_dn, "DC=@", hostname, dnsdomain,
508 hostip, hostip6)
510 # DC=<HOSTNAME> record
511 add_host_record(samdb, domain_container_dn, "DC=%s" % hostname, hostip,
512 hostip6)
514 # DC=_kerberos._tcp record
515 add_srv_record(samdb, domain_container_dn, "DC=_kerberos._tcp",
516 fqdn_hostname, 88)
518 # DC=_kerberos._tcp.<SITENAME>._sites record
519 add_srv_record(samdb, domain_container_dn, "DC=_kerberos._tcp.%s._sites" %
520 site, fqdn_hostname, 88)
522 # DC=_kerberos._udp record
523 add_srv_record(samdb, domain_container_dn, "DC=_kerberos._udp",
524 fqdn_hostname, 88)
526 # DC=_kpasswd._tcp record
527 add_srv_record(samdb, domain_container_dn, "DC=_kpasswd._tcp",
528 fqdn_hostname, 464)
530 # DC=_kpasswd._udp record
531 add_srv_record(samdb, domain_container_dn, "DC=_kpasswd._udp",
532 fqdn_hostname, 464)
534 # DC=_ldap._tcp record
535 add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp", fqdn_hostname,
536 389)
538 # DC=_ldap._tcp.<SITENAME>._sites record
539 add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.%s._sites" %
540 site, fqdn_hostname, 389)
542 # FIXME: The number of SRV records depend on the various roles this DC has.
543 # _gc and _msdcs records are added if the we are the forest dc and not subdomain dc
545 # Assumption: current DC is GC and add all the entries
547 # DC=_gc._tcp record
548 add_srv_record(samdb, domain_container_dn, "DC=_gc._tcp", fqdn_hostname,
549 3268)
551 # DC=_gc._tcp.<SITENAME>,_sites record
552 add_srv_record(samdb, domain_container_dn, "DC=_gc._tcp.%s._sites" % site,
553 fqdn_hostname, 3268)
555 # DC=_msdcs record
556 add_ns_glue_record(samdb, domain_container_dn, "DC=_msdcs", fqdn_hostname)
558 # FIXME: Following entries are added only if DomainDnsZones and ForestDnsZones partitions
559 # are created
561 # Assumption: Additional entries won't hurt on os_level = 2000
563 # DC=_ldap._tcp.<SITENAME>._sites.DomainDnsZones
564 add_srv_record(samdb, domain_container_dn,
565 "DC=_ldap._tcp.%s._sites.DomainDnsZones" % site, fqdn_hostname,
566 389)
568 # DC=_ldap._tcp.<SITENAME>._sites.ForestDnsZones
569 add_srv_record(samdb, domain_container_dn,
570 "DC=_ldap._tcp.%s._sites.ForestDnsZones" % site, fqdn_hostname,
571 389)
573 # DC=_ldap._tcp.DomainDnsZones
574 add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.DomainDnsZones",
575 fqdn_hostname, 389)
577 # DC=_ldap._tcp.ForestDnsZones
578 add_srv_record(samdb, domain_container_dn, "DC=_ldap._tcp.ForestDnsZones",
579 fqdn_hostname, 389)
581 # DC=DomainDnsZones
582 add_host_record(samdb, domain_container_dn, "DC=DomainDnsZones", hostip,
583 hostip6)
585 # DC=ForestDnsZones
586 add_host_record(samdb, domain_container_dn, "DC=ForestDnsZones", hostip,
587 hostip6)
590 def add_dc_msdcs_records(samdb, forestdn, prefix, site, dnsforest, hostname,
591 hostip, hostip6, domainguid, ntdsguid):
593 fqdn_hostname = "%s.%s" % (hostname, dnsforest)
595 # Set up forest container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
596 forest_container_dn = ldb.Dn(samdb, "DC=_msdcs.%s,CN=MicrosoftDNS,%s,%s" %
597 (dnsforest, prefix, forestdn))
599 # DC=@ record
600 add_at_record(samdb, forest_container_dn, "DC=@", hostname, dnsforest,
601 None, None)
603 # DC=_kerberos._tcp.dc record
604 add_srv_record(samdb, forest_container_dn, "DC=_kerberos._tcp.dc",
605 fqdn_hostname, 88)
607 # DC=_kerberos._tcp.<SITENAME>._sites.dc record
608 add_srv_record(samdb, forest_container_dn,
609 "DC=_kerberos._tcp.%s._sites.dc" % site, fqdn_hostname, 88)
611 # DC=_ldap._tcp.dc record
612 add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.dc",
613 fqdn_hostname, 389)
615 # DC=_ldap._tcp.<SITENAME>._sites.dc record
616 add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.%s._sites.dc" %
617 site, fqdn_hostname, 389)
619 # DC=_ldap._tcp.<SITENAME>._sites.gc record
620 add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.%s._sites.gc" %
621 site, fqdn_hostname, 3268)
623 # DC=_ldap._tcp.gc record
624 add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.gc",
625 fqdn_hostname, 3268)
627 # DC=_ldap._tcp.pdc record
628 add_srv_record(samdb, forest_container_dn, "DC=_ldap._tcp.pdc",
629 fqdn_hostname, 389)
631 # DC=gc record
632 add_host_record(samdb, forest_container_dn, "DC=gc", hostip, hostip6)
634 # DC=_ldap._tcp.<DOMAINGUID>.domains record
635 add_srv_record(samdb, forest_container_dn,
636 "DC=_ldap._tcp.%s.domains" % domainguid, fqdn_hostname, 389)
638 # DC=<NTDSGUID>
639 add_cname_record(samdb, forest_container_dn, "DC=%s" % ntdsguid,
640 fqdn_hostname)
643 def secretsdb_setup_dns(secretsdb, names, private_dir, realm,
644 dnsdomain, dns_keytab_path, dnspass, key_version_number):
645 """Add DNS specific bits to a secrets database.
647 :param secretsdb: Ldb Handle to the secrets database
648 :param names: Names shortcut
649 :param machinepass: Machine password
651 try:
652 os.unlink(os.path.join(private_dir, dns_keytab_path))
653 except OSError:
654 pass
656 if key_version_number is None:
657 key_version_number = 1
659 setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
660 "REALM": realm,
661 "DNSDOMAIN": dnsdomain,
662 "DNS_KEYTAB": dns_keytab_path,
663 "DNSPASS_B64": b64encode(dnspass),
664 "KEY_VERSION_NUMBER": str(key_version_number),
665 "HOSTNAME": names.hostname,
666 "DNSNAME" : '%s.%s' % (
667 names.netbiosname.lower(), names.dnsdomain.lower())
671 def create_dns_dir(logger, paths):
672 """Write out a DNS zone file, from the info in the current database.
674 :param logger: Logger object
675 :param paths: paths object
677 dns_dir = os.path.dirname(paths.dns)
679 try:
680 shutil.rmtree(dns_dir, True)
681 except OSError:
682 pass
684 os.mkdir(dns_dir, 0770)
686 if paths.bind_gid is not None:
687 try:
688 os.chown(dns_dir, -1, paths.bind_gid)
689 # chmod needed to cope with umask
690 os.chmod(dns_dir, 0770)
691 except OSError:
692 if not os.environ.has_key('SAMBA_SELFTEST'):
693 logger.error("Failed to chown %s to bind gid %u" % (
694 dns_dir, paths.bind_gid))
697 def create_zone_file(lp, logger, paths, targetdir, dnsdomain,
698 hostip, hostip6, hostname, realm, domainguid,
699 ntdsguid, site):
700 """Write out a DNS zone file, from the info in the current database.
702 :param paths: paths object
703 :param dnsdomain: DNS Domain name
704 :param domaindn: DN of the Domain
705 :param hostip: Local IPv4 IP
706 :param hostip6: Local IPv6 IP
707 :param hostname: Local hostname
708 :param realm: Realm name
709 :param domainguid: GUID of the domain.
710 :param ntdsguid: GUID of the hosts nTDSDSA record.
712 assert isinstance(domainguid, str)
714 if hostip6 is not None:
715 hostip6_base_line = " IN AAAA " + hostip6
716 hostip6_host_line = hostname + " IN AAAA " + hostip6
717 gc_msdcs_ip6_line = "gc._msdcs IN AAAA " + hostip6
718 else:
719 hostip6_base_line = ""
720 hostip6_host_line = ""
721 gc_msdcs_ip6_line = ""
723 if hostip is not None:
724 hostip_base_line = " IN A " + hostip
725 hostip_host_line = hostname + " IN A " + hostip
726 gc_msdcs_ip_line = "gc._msdcs IN A " + hostip
727 else:
728 hostip_base_line = ""
729 hostip_host_line = ""
730 gc_msdcs_ip_line = ""
732 # we need to freeze the zone while we update the contents
733 if targetdir is None:
734 rndc = ' '.join(lp.get("rndc command"))
735 os.system(rndc + " freeze " + lp.get("realm"))
737 setup_file(setup_path("provision.zone"), paths.dns, {
738 "HOSTNAME": hostname,
739 "DNSDOMAIN": dnsdomain,
740 "REALM": realm,
741 "HOSTIP_BASE_LINE": hostip_base_line,
742 "HOSTIP_HOST_LINE": hostip_host_line,
743 "DOMAINGUID": domainguid,
744 "DATESTRING": time.strftime("%Y%m%d%H"),
745 "DEFAULTSITE": site,
746 "NTDSGUID": ntdsguid,
747 "HOSTIP6_BASE_LINE": hostip6_base_line,
748 "HOSTIP6_HOST_LINE": hostip6_host_line,
749 "GC_MSDCS_IP_LINE": gc_msdcs_ip_line,
750 "GC_MSDCS_IP6_LINE": gc_msdcs_ip6_line,
753 if paths.bind_gid is not None:
754 try:
755 os.chown(paths.dns, -1, paths.bind_gid)
756 # chmod needed to cope with umask
757 os.chmod(paths.dns, 0664)
758 except OSError:
759 if not os.environ.has_key('SAMBA_SELFTEST'):
760 logger.error("Failed to chown %s to bind gid %u" % (
761 paths.dns, paths.bind_gid))
763 if targetdir is None:
764 os.system(rndc + " unfreeze " + lp.get("realm"))
767 def create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid):
768 """Create a copy of samdb and give write permissions to named for dns partitions
770 private_dir = paths.private_dir
771 samldb_dir = os.path.join(private_dir, "sam.ldb.d")
772 dns_dir = os.path.dirname(paths.dns)
773 dns_samldb_dir = os.path.join(dns_dir, "sam.ldb.d")
775 # Find the partitions and corresponding filenames
776 partfile = {}
777 res = samdb.search(base="@PARTITION", scope=ldb.SCOPE_BASE, attrs=["partition"])
778 for tmp in res[0]["partition"]:
779 (nc, fname) = tmp.split(':')
780 partfile[nc.upper()] = fname
782 # Create empty domain partition
783 domaindn = names.domaindn.upper()
784 domainpart_file = os.path.join(dns_dir, partfile[domaindn])
785 try:
786 os.mkdir(dns_samldb_dir)
787 file(domainpart_file, 'w').close()
789 # Fill the basedn and @OPTION records in domain partition
790 dom_ldb = samba.Ldb(domainpart_file)
791 domainguid_line = "objectGUID: %s\n-" % domainguid
792 descr = b64encode(get_domain_descriptor(domainsid))
793 setup_add_ldif(dom_ldb, setup_path("provision_basedn.ldif"), {
794 "DOMAINDN" : names.domaindn,
795 "DOMAINGUID" : domainguid_line,
796 "DOMAINSID" : str(domainsid),
797 "DESCRIPTOR" : descr})
798 setup_add_ldif(dom_ldb,
799 setup_path("provision_basedn_options.ldif"), None)
800 except:
801 logger.error(
802 "Failed to setup database for BIND, AD based DNS cannot be used")
803 raise
805 # This line is critical to the security of the whole scheme.
806 # We assume there is no secret data in the (to be left out of
807 # date and essentially read-only) config, schema and metadata partitions.
809 # Only the stub of the domain partition is created above.
811 # That way, things like the krbtgt key do not leak.
812 del partfile[domaindn]
814 # Link dns partitions and metadata
815 domainzonedn = "DC=DOMAINDNSZONES,%s" % names.domaindn.upper()
816 forestzonedn = "DC=FORESTDNSZONES,%s" % names.rootdn.upper()
818 domainzone_file = partfile[domainzonedn]
819 forestzone_file = partfile.get(forestzonedn)
821 metadata_file = "metadata.tdb"
822 try:
823 os.link(os.path.join(samldb_dir, metadata_file),
824 os.path.join(dns_samldb_dir, metadata_file))
825 os.link(os.path.join(private_dir, domainzone_file),
826 os.path.join(dns_dir, domainzone_file))
827 if forestzone_file:
828 os.link(os.path.join(private_dir, forestzone_file),
829 os.path.join(dns_dir, forestzone_file))
830 except OSError:
831 logger.error(
832 "Failed to setup database for BIND, AD based DNS cannot be used")
833 raise
834 del partfile[domainzonedn]
835 if forestzone_file:
836 del partfile[forestzonedn]
838 # Copy root, config, schema partitions (and any other if any)
839 # Since samdb is open in the current process, copy them in a child process
840 try:
841 tdb_copy(os.path.join(private_dir, "sam.ldb"),
842 os.path.join(dns_dir, "sam.ldb"))
843 for nc in partfile:
844 pfile = partfile[nc]
845 tdb_copy(os.path.join(private_dir, pfile),
846 os.path.join(dns_dir, pfile))
847 except:
848 logger.error(
849 "Failed to setup database for BIND, AD based DNS cannot be used")
850 raise
852 # Give bind read/write permissions dns partitions
853 if paths.bind_gid is not None:
854 try:
855 os.chown(samldb_dir, -1, paths.bind_gid)
856 os.chmod(samldb_dir, 0750)
858 for dirname, dirs, files in os.walk(dns_dir):
859 for d in dirs:
860 dpath = os.path.join(dirname, d)
861 os.chown(dpath, -1, paths.bind_gid)
862 os.chmod(dpath, 0770)
863 for f in files:
864 if f.endswith('.ldb') or f.endswith('.tdb'):
865 fpath = os.path.join(dirname, f)
866 os.chown(fpath, -1, paths.bind_gid)
867 os.chmod(fpath, 0660)
868 except OSError:
869 if not os.environ.has_key('SAMBA_SELFTEST'):
870 logger.error(
871 "Failed to set permissions to sam.ldb* files, fix manually")
872 else:
873 if not os.environ.has_key('SAMBA_SELFTEST'):
874 logger.warning("""Unable to find group id for BIND,
875 set permissions to sam.ldb* files manually""")
878 def create_dns_update_list(lp, logger, paths):
879 """Write out a dns_update_list file"""
880 # note that we use no variable substitution on this file
881 # the substitution is done at runtime by samba_dnsupdate, samba_spnupdate
882 setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
883 setup_file(setup_path("spn_update_list"), paths.spn_update_list, None)
886 def create_named_conf(paths, realm, dnsdomain, dns_backend, logger):
887 """Write out a file containing zone statements suitable for inclusion in a
888 named.conf file (including GSS-TSIG configuration).
890 :param paths: all paths
891 :param realm: Realm name
892 :param dnsdomain: DNS Domain name
893 :param dns_backend: DNS backend type
894 :param keytab_name: File name of DNS keytab file
895 :param logger: Logger object
898 # TODO: This really should have been done as a top level import.
899 # It is done here to avoid a depencency loop. That is, we move
900 # ProvisioningError to another file, and have all the provision
901 # scripts import it from there.
903 from samba.provision import ProvisioningError
905 if dns_backend == "BIND9_FLATFILE":
906 setup_file(setup_path("named.conf"), paths.namedconf, {
907 "DNSDOMAIN": dnsdomain,
908 "REALM": realm,
909 "ZONE_FILE": paths.dns,
910 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
911 "NAMED_CONF": paths.namedconf,
912 "NAMED_CONF_UPDATE": paths.namedconf_update
915 setup_file(setup_path("named.conf.update"), paths.namedconf_update)
917 elif dns_backend == "BIND9_DLZ":
918 bind_info = subprocess.Popen(['named -V'], shell=True,
919 stdout=subprocess.PIPE,
920 stderr=subprocess.STDOUT,
921 cwd='.').communicate()[0]
922 bind9_8 = '#'
923 bind9_9 = '#'
924 bind9_10 = '#'
925 if bind_info.upper().find('BIND 9.8') != -1:
926 bind9_8 = ''
927 elif bind_info.upper().find('BIND 9.9') != -1:
928 bind9_9 = ''
929 elif bind_info.upper().find('BIND 9.10') != -1:
930 bind9_10 = ''
931 elif bind_info.upper().find('BIND 9.7') != -1:
932 raise ProvisioningError("DLZ option incompatible with BIND 9.7.")
933 else:
934 logger.warning("BIND version unknown, please modify %s manually." % paths.namedconf)
935 setup_file(setup_path("named.conf.dlz"), paths.namedconf, {
936 "NAMED_CONF": paths.namedconf,
937 "MODULESDIR" : samba.param.modules_dir(),
938 "BIND9_8" : bind9_8,
939 "BIND9_9" : bind9_9,
940 "BIND9_10" : bind9_10
944 def create_named_txt(path, realm, dnsdomain, dnsname, private_dir,
945 keytab_name):
946 """Write out a file containing zone statements suitable for inclusion in a
947 named.conf file (including GSS-TSIG configuration).
949 :param path: Path of the new named.conf file.
950 :param realm: Realm name
951 :param dnsdomain: DNS Domain name
952 :param private_dir: Path to private directory
953 :param keytab_name: File name of DNS keytab file
955 setup_file(setup_path("named.txt"), path, {
956 "DNSDOMAIN": dnsdomain,
957 "DNSNAME" : dnsname,
958 "REALM": realm,
959 "DNS_KEYTAB": keytab_name,
960 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
961 "PRIVATE_DIR": private_dir
965 def is_valid_dns_backend(dns_backend):
966 return dns_backend in ("BIND9_FLATFILE", "BIND9_DLZ", "SAMBA_INTERNAL", "NONE")
969 def is_valid_os_level(os_level):
970 return DS_DOMAIN_FUNCTION_2000 <= os_level <= DS_DOMAIN_FUNCTION_2008_R2
973 def create_dns_legacy(samdb, domainsid, forestdn, dnsadmins_sid):
974 # Set up MicrosoftDNS container
975 add_dns_container(samdb, forestdn, "CN=System", domainsid, dnsadmins_sid)
976 # Add root servers
977 add_rootservers(samdb, forestdn, "CN=System")
980 def fill_dns_data_legacy(samdb, domainsid, forestdn, dnsdomain, site, hostname,
981 hostip, hostip6, dnsadmins_sid):
982 # Add domain record
983 add_domain_record(samdb, forestdn, "CN=System", dnsdomain, domainsid,
984 dnsadmins_sid)
986 # Add DNS records for a DC in domain
987 add_dc_domain_records(samdb, forestdn, "CN=System", site, dnsdomain,
988 hostname, hostip, hostip6)
991 def create_dns_partitions(samdb, domainsid, names, domaindn, forestdn,
992 dnsadmins_sid, fill_level):
993 # Set up additional partitions (DomainDnsZones, ForstDnsZones)
994 setup_dns_partitions(samdb, domainsid, domaindn, forestdn,
995 names.configdn, names.serverdn, fill_level)
997 # Set up MicrosoftDNS containers
998 add_dns_container(samdb, domaindn, "DC=DomainDnsZones", domainsid,
999 dnsadmins_sid)
1000 if fill_level != FILL_SUBDOMAIN:
1001 add_dns_container(samdb, forestdn, "DC=ForestDnsZones", domainsid,
1002 dnsadmins_sid, forest=True)
1005 def fill_dns_data_partitions(samdb, domainsid, site, domaindn, forestdn,
1006 dnsdomain, dnsforest, hostname, hostip, hostip6,
1007 domainguid, ntdsguid, dnsadmins_sid, autofill=True,
1008 fill_level=FILL_FULL):
1009 """Fill data in various AD partitions
1011 :param samdb: LDB object connected to sam.ldb file
1012 :param domainsid: Domain SID (as dom_sid object)
1013 :param site: Site name to create hostnames in
1014 :param domaindn: DN of the domain
1015 :param forestdn: DN of the forest
1016 :param dnsdomain: DNS name of the domain
1017 :param dnsforest: DNS name of the forest
1018 :param hostname: Host name of this DC
1019 :param hostip: IPv4 addresses
1020 :param hostip6: IPv6 addresses
1021 :param domainguid: Domain GUID
1022 :param ntdsguid: NTDS GUID
1023 :param dnsadmins_sid: SID for DnsAdmins group
1024 :param autofill: Create DNS records (using fixed template)
1027 ##### Set up DC=DomainDnsZones,<DOMAINDN>
1028 # Add rootserver records
1029 add_rootservers(samdb, domaindn, "DC=DomainDnsZones")
1031 # Add domain record
1032 add_domain_record(samdb, domaindn, "DC=DomainDnsZones", dnsdomain,
1033 domainsid, dnsadmins_sid)
1035 # Add DNS records for a DC in domain
1036 if autofill:
1037 add_dc_domain_records(samdb, domaindn, "DC=DomainDnsZones", site,
1038 dnsdomain, hostname, hostip, hostip6)
1040 if fill_level != FILL_SUBDOMAIN:
1041 ##### Set up DC=ForestDnsZones,<FORESTDN>
1042 # Add _msdcs record
1043 add_msdcs_record(samdb, forestdn, "DC=ForestDnsZones", dnsforest)
1045 # Add DNS records for a DC in forest
1046 if autofill:
1047 add_dc_msdcs_records(samdb, forestdn, "DC=ForestDnsZones", site,
1048 dnsforest, hostname, hostip, hostip6,
1049 domainguid, ntdsguid)
1052 def setup_ad_dns(samdb, secretsdb, names, paths, lp, logger,
1053 dns_backend, os_level, dnspass=None, hostip=None, hostip6=None,
1054 targetdir=None, fill_level=FILL_FULL):
1055 """Provision DNS information (assuming GC role)
1057 :param samdb: LDB object connected to sam.ldb file
1058 :param secretsdb: LDB object connected to secrets.ldb file
1059 :param names: Names shortcut
1060 :param paths: Paths shortcut
1061 :param lp: Loadparm object
1062 :param logger: Logger object
1063 :param dns_backend: Type of DNS backend
1064 :param os_level: Functional level (treated as os level)
1065 :param dnspass: Password for bind's DNS account
1066 :param hostip: IPv4 address
1067 :param hostip6: IPv6 address
1068 :param targetdir: Target directory for creating DNS-related files for BIND9
1071 if not is_valid_dns_backend(dns_backend):
1072 raise Exception("Invalid dns backend: %r" % dns_backend)
1074 if not is_valid_os_level(os_level):
1075 raise Exception("Invalid os level: %r" % os_level)
1077 if dns_backend == "NONE":
1078 logger.info("No DNS backend set, not configuring DNS")
1079 return
1081 # Add dns accounts (DnsAdmins, DnsUpdateProxy) in domain
1082 logger.info("Adding DNS accounts")
1083 add_dns_accounts(samdb, names.domaindn)
1085 # If dns_backend is BIND9_FLATFILE
1086 # Populate only CN=MicrosoftDNS,CN=System,<DOMAINDN>
1088 # If dns_backend is SAMBA_INTERNAL or BIND9_DLZ
1089 # Populate DNS partitions
1091 # If os_level < 2003 (DS_DOMAIN_FUNCTION_2000)
1092 # All dns records are in CN=MicrosoftDNS,CN=System,<DOMAINDN>
1094 # If os_level >= 2003 (DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008,
1095 # DS_DOMAIN_FUNCTION_2008_R2)
1096 # Root server records are in CN=MicrosoftDNS,CN=System,<DOMAINDN>
1097 # Domain records are in CN=MicrosoftDNS,CN=System,<DOMAINDN>
1098 # Domain records are in CN=MicrosoftDNS,DC=DomainDnsZones,<DOMAINDN>
1099 # Forest records are in CN=MicrosoftDNS,DC=ForestDnsZones,<FORESTDN>
1100 domaindn = names.domaindn
1101 forestdn = samdb.get_root_basedn().get_linearized()
1103 dnsdomain = names.dnsdomain.lower()
1104 dnsforest = dnsdomain
1106 site = names.sitename
1108 hostname = names.netbiosname.lower()
1110 dnsadmins_sid = get_dnsadmins_sid(samdb, domaindn)
1111 domainguid = get_domainguid(samdb, domaindn)
1113 # Create CN=System
1114 logger.info("Creating CN=MicrosoftDNS,CN=System,%s" % domaindn)
1115 create_dns_legacy(samdb, names.domainsid, domaindn, dnsadmins_sid)
1117 if os_level == DS_DOMAIN_FUNCTION_2000:
1118 # Populating legacy dns
1119 logger.info("Populating CN=MicrosoftDNS,CN=System,%s" % domaindn)
1120 fill_dns_data_legacy(samdb, names.domainsid, domaindn, dnsdomain, site,
1121 hostname, hostip, hostip6, dnsadmins_sid)
1123 elif dns_backend in ("SAMBA_INTERNAL", "BIND9_DLZ") and \
1124 os_level >= DS_DOMAIN_FUNCTION_2003:
1126 # Create DNS partitions
1127 logger.info("Creating DomainDnsZones and ForestDnsZones partitions")
1128 create_dns_partitions(samdb, names.domainsid, names, domaindn, forestdn,
1129 dnsadmins_sid, fill_level)
1131 # Populating dns partitions
1132 logger.info("Populating DomainDnsZones and ForestDnsZones partitions")
1133 fill_dns_data_partitions(samdb, names.domainsid, site, domaindn, forestdn,
1134 dnsdomain, dnsforest, hostname, hostip, hostip6,
1135 domainguid, names.ntdsguid, dnsadmins_sid,
1136 fill_level=fill_level)
1138 if dns_backend.startswith("BIND9_"):
1139 setup_bind9_dns(samdb, secretsdb, names, paths, lp, logger,
1140 dns_backend, os_level, site=site, dnspass=dnspass, hostip=hostip,
1141 hostip6=hostip6, targetdir=targetdir)
1144 def setup_bind9_dns(samdb, secretsdb, names, paths, lp, logger,
1145 dns_backend, os_level, site=None, dnspass=None, hostip=None,
1146 hostip6=None, targetdir=None, key_version_number=None):
1147 """Provision DNS information (assuming BIND9 backend in DC role)
1149 :param samdb: LDB object connected to sam.ldb file
1150 :param secretsdb: LDB object connected to secrets.ldb file
1151 :param names: Names shortcut
1152 :param paths: Paths shortcut
1153 :param lp: Loadparm object
1154 :param logger: Logger object
1155 :param dns_backend: Type of DNS backend
1156 :param os_level: Functional level (treated as os level)
1157 :param site: Site to create hostnames in
1158 :param dnspass: Password for bind's DNS account
1159 :param hostip: IPv4 address
1160 :param hostip6: IPv6 address
1161 :param targetdir: Target directory for creating DNS-related files for BIND9
1164 if (not is_valid_dns_backend(dns_backend) or
1165 not dns_backend.startswith("BIND9_")):
1166 raise Exception("Invalid dns backend: %r" % dns_backend)
1168 if not is_valid_os_level(os_level):
1169 raise Exception("Invalid os level: %r" % os_level)
1171 domaindn = names.domaindn
1173 domainguid = get_domainguid(samdb, domaindn)
1175 secretsdb_setup_dns(secretsdb, names,
1176 paths.private_dir, realm=names.realm,
1177 dnsdomain=names.dnsdomain,
1178 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
1179 key_version_number=key_version_number)
1181 create_dns_dir(logger, paths)
1183 if dns_backend == "BIND9_FLATFILE":
1184 create_zone_file(lp, logger, paths, targetdir, site=site,
1185 dnsdomain=names.dnsdomain, hostip=hostip,
1186 hostip6=hostip6, hostname=names.hostname,
1187 realm=names.realm, domainguid=domainguid,
1188 ntdsguid=names.ntdsguid)
1190 if dns_backend == "BIND9_DLZ" and os_level >= DS_DOMAIN_FUNCTION_2003:
1191 create_samdb_copy(samdb, logger, paths, names, names.domainsid, domainguid)
1193 create_named_conf(paths, realm=names.realm,
1194 dnsdomain=names.dnsdomain, dns_backend=dns_backend,
1195 logger=logger)
1197 create_named_txt(paths.namedtxt,
1198 realm=names.realm, dnsdomain=names.dnsdomain,
1199 dnsname = "%s.%s" % (names.hostname, names.dnsdomain),
1200 private_dir=paths.private_dir,
1201 keytab_name=paths.dns_keytab)
1202 logger.info("See %s for an example configuration include file for BIND",
1203 paths.namedconf)
1204 logger.info("and %s for further documentation required for secure DNS "
1205 "updates", paths.namedtxt)