wbclient: Check with nss_wrapper_enabled().
[Samba.git] / python / samba / provision / sambadns.py
blob13e03aba5a588256f5198bf30895c725ac6dfe4c
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 self.data = soa
136 class SRVRecord(dnsp.DnssrvRpcRecord):
138 def __init__(self, target, port, priority=0, weight=100, serial=1, ttl=900,
139 rank=dnsp.DNS_RANK_ZONE):
140 super(SRVRecord, self).__init__()
141 self.wType = dnsp.DNS_TYPE_SRV
142 self.rank = rank
143 self.dwSerial = serial
144 self.dwTtlSeconds = ttl
145 srv = dnsp.srv()
146 srv.nameTarget = target
147 srv.wPort = port
148 srv.wPriority = priority
149 srv.wWeight = weight
150 self.data = srv
153 class TXTRecord(dnsp.DnssrvRpcRecord):
155 def __init__(self, slist, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE):
156 super(TXTRecord, self).__init__()
157 self.wType = dnsp.DNS_TYPE_TXT
158 self.rank = rank
159 self.dwSerial = serial
160 self.dwTtlSeconds = ttl
161 stringlist = dnsp.string_list()
162 stringlist.count = len(slist)
163 stringlist.str = slist
164 self.data = stringlist
167 class TypeProperty(dnsp.DnsProperty):
169 def __init__(self, zone_type=dnsp.DNS_ZONE_TYPE_PRIMARY):
170 super(TypeProperty, self).__init__()
171 self.wDataLength = 1
172 self.version = 1
173 self.id = dnsp.DSPROPERTY_ZONE_TYPE
174 self.data = zone_type
177 class AllowUpdateProperty(dnsp.DnsProperty):
179 def __init__(self, allow_update=dnsp.DNS_ZONE_UPDATE_SECURE):
180 super(AllowUpdateProperty, self).__init__()
181 self.wDataLength = 1
182 self.version = 1
183 self.id = dnsp.DSPROPERTY_ZONE_ALLOW_UPDATE
184 self.data = allow_update
187 class SecureTimeProperty(dnsp.DnsProperty):
189 def __init__(self, secure_time=0):
190 super(SecureTimeProperty, self).__init__()
191 self.wDataLength = 1
192 self.version = 1
193 self.id = dnsp.DSPROPERTY_ZONE_SECURE_TIME
194 self.data = secure_time
197 class NorefreshIntervalProperty(dnsp.DnsProperty):
199 def __init__(self, norefresh_interval=0):
200 super(NorefreshIntervalProperty, self).__init__()
201 self.wDataLength = 1
202 self.version = 1
203 self.id = dnsp.DSPROPERTY_ZONE_NOREFRESH_INTERVAL
204 self.data = norefresh_interval
207 class RefreshIntervalProperty(dnsp.DnsProperty):
209 def __init__(self, refresh_interval=0):
210 super(RefreshIntervalProperty, self).__init__()
211 self.wDataLength = 1
212 self.version = 1
213 self.id = dnsp.DSPROPERTY_ZONE_REFRESH_INTERVAL
214 self.data = refresh_interval
217 class AgingStateProperty(dnsp.DnsProperty):
219 def __init__(self, aging_enabled=0):
220 super(AgingStateProperty, self).__init__()
221 self.wDataLength = 1
222 self.version = 1
223 self.id = dnsp.DSPROPERTY_ZONE_AGING_STATE
224 self.data = aging_enabled
227 class AgingEnabledTimeProperty(dnsp.DnsProperty):
229 def __init__(self, next_cycle_hours=0):
230 super(AgingEnabledTimeProperty, self).__init__()
231 self.wDataLength = 1
232 self.version = 1;
233 self.id = dnsp.DSPROPERTY_ZONE_AGING_ENABLED_TIME
234 self.data = next_cycle_hours
237 def setup_dns_partitions(samdb, domainsid, domaindn, forestdn, configdn,
238 serverdn, fill_level):
239 domainzone_dn = "DC=DomainDnsZones,%s" % domaindn
240 forestzone_dn = "DC=ForestDnsZones,%s" % forestdn
241 descriptor = get_dns_partition_descriptor(domainsid)
243 setup_add_ldif(samdb, setup_path("provision_dnszones_partitions.ldif"), {
244 "ZONE_DN": domainzone_dn,
245 "SECDESC" : b64encode(descriptor)
247 if fill_level != FILL_SUBDOMAIN:
248 setup_add_ldif(samdb, setup_path("provision_dnszones_partitions.ldif"), {
249 "ZONE_DN": forestzone_dn,
250 "SECDESC" : b64encode(descriptor)
253 domainzone_guid = get_domainguid(samdb, domainzone_dn)
254 forestzone_guid = get_domainguid(samdb, forestzone_dn)
256 domainzone_guid = str(uuid.uuid4())
257 forestzone_guid = str(uuid.uuid4())
259 domainzone_dns = ldb.Dn(samdb, domainzone_dn).canonical_ex_str().strip()
260 forestzone_dns = ldb.Dn(samdb, forestzone_dn).canonical_ex_str().strip()
262 protected1_desc = get_domain_delete_protected1_descriptor(domainsid)
263 protected2_desc = get_domain_delete_protected2_descriptor(domainsid)
264 setup_add_ldif(samdb, setup_path("provision_dnszones_add.ldif"), {
265 "ZONE_DN": domainzone_dn,
266 "ZONE_GUID": domainzone_guid,
267 "ZONE_DNS": domainzone_dns,
268 "CONFIGDN": configdn,
269 "SERVERDN": serverdn,
270 "LOSTANDFOUND_DESCRIPTOR": b64encode(protected2_desc),
271 "INFRASTRUCTURE_DESCRIPTOR": b64encode(protected1_desc),
273 setup_modify_ldif(samdb, setup_path("provision_dnszones_modify.ldif"), {
274 "CONFIGDN": configdn,
275 "SERVERDN": serverdn,
276 "ZONE_DN": domainzone_dn,
279 if fill_level != FILL_SUBDOMAIN:
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
804 del partfile[domaindn]
806 # Link dns partitions and metadata
807 domainzonedn = "DC=DOMAINDNSZONES,%s" % names.domaindn.upper()
808 forestzonedn = "DC=FORESTDNSZONES,%s" % names.rootdn.upper()
809 domainzone_file = partfile[domainzonedn]
810 forestzone_file = partfile[forestzonedn]
811 metadata_file = "metadata.tdb"
812 try:
813 os.link(os.path.join(samldb_dir, metadata_file),
814 os.path.join(dns_samldb_dir, metadata_file))
815 os.link(os.path.join(private_dir, domainzone_file),
816 os.path.join(dns_dir, domainzone_file))
817 os.link(os.path.join(private_dir, forestzone_file),
818 os.path.join(dns_dir, forestzone_file))
819 except OSError:
820 logger.error(
821 "Failed to setup database for BIND, AD based DNS cannot be used")
822 raise
823 del partfile[domainzonedn]
824 del partfile[forestzonedn]
826 # Copy root, config, schema partitions (and any other if any)
827 # Since samdb is open in the current process, copy them in a child process
828 try:
829 tdb_copy(os.path.join(private_dir, "sam.ldb"),
830 os.path.join(dns_dir, "sam.ldb"))
831 for nc in partfile:
832 pfile = partfile[nc]
833 tdb_copy(os.path.join(private_dir, pfile),
834 os.path.join(dns_dir, pfile))
835 except:
836 logger.error(
837 "Failed to setup database for BIND, AD based DNS cannot be used")
838 raise
840 # Give bind read/write permissions dns partitions
841 if paths.bind_gid is not None:
842 try:
843 os.chown(samldb_dir, -1, paths.bind_gid)
844 os.chmod(samldb_dir, 0750)
846 for dirname, dirs, files in os.walk(dns_dir):
847 for d in dirs:
848 dpath = os.path.join(dirname, d)
849 os.chown(dpath, -1, paths.bind_gid)
850 os.chmod(dpath, 0770)
851 for f in files:
852 if f.endswith('.ldb') or f.endswith('.tdb'):
853 fpath = os.path.join(dirname, f)
854 os.chown(fpath, -1, paths.bind_gid)
855 os.chmod(fpath, 0660)
856 except OSError:
857 if not os.environ.has_key('SAMBA_SELFTEST'):
858 logger.error(
859 "Failed to set permissions to sam.ldb* files, fix manually")
860 else:
861 if not os.environ.has_key('SAMBA_SELFTEST'):
862 logger.warning("""Unable to find group id for BIND,
863 set permissions to sam.ldb* files manually""")
866 def create_dns_update_list(lp, logger, paths):
867 """Write out a dns_update_list file"""
868 # note that we use no variable substitution on this file
869 # the substitution is done at runtime by samba_dnsupdate, samba_spnupdate
870 setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
871 setup_file(setup_path("spn_update_list"), paths.spn_update_list, None)
874 def create_named_conf(paths, realm, dnsdomain, dns_backend, logger):
875 """Write out a file containing zone statements suitable for inclusion in a
876 named.conf file (including GSS-TSIG configuration).
878 :param paths: all paths
879 :param realm: Realm name
880 :param dnsdomain: DNS Domain name
881 :param dns_backend: DNS backend type
882 :param keytab_name: File name of DNS keytab file
883 :param logger: Logger object
886 # TODO: This really should have been done as a top level import.
887 # It is done here to avoid a depencency loop. That is, we move
888 # ProvisioningError to another file, and have all the provision
889 # scripts import it from there.
891 from samba.provision import ProvisioningError
893 if dns_backend == "BIND9_FLATFILE":
894 setup_file(setup_path("named.conf"), paths.namedconf, {
895 "DNSDOMAIN": dnsdomain,
896 "REALM": realm,
897 "ZONE_FILE": paths.dns,
898 "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
899 "NAMED_CONF": paths.namedconf,
900 "NAMED_CONF_UPDATE": paths.namedconf_update
903 setup_file(setup_path("named.conf.update"), paths.namedconf_update)
905 elif dns_backend == "BIND9_DLZ":
906 bind_info = subprocess.Popen(['named -V'], shell=True,
907 stdout=subprocess.PIPE,
908 stderr=subprocess.STDOUT,
909 cwd='.').communicate()[0]
910 bind98 = '#'
911 bind99 = '#'
912 if bind_info.upper().find('BIND 9.8') != -1:
913 bind98 = ''
914 elif bind_info.upper().find('BIND 9.9') != -1:
915 bind99 = ''
916 elif bind_info.upper().find('BIND 9.7') != -1:
917 raise ProvisioningError("DLZ option incompatible with BIND 9.7.")
918 else:
919 logger.warning("BIND version unknown, please modify %s manually." % paths.namedconf)
920 setup_file(setup_path("named.conf.dlz"), paths.namedconf, {
921 "NAMED_CONF": paths.namedconf,
922 "MODULESDIR" : samba.param.modules_dir(),
923 "BIND98" : bind98,
924 "BIND99" : bind99
928 def create_named_txt(path, realm, dnsdomain, dnsname, private_dir,
929 keytab_name):
930 """Write out a file containing zone statements suitable for inclusion in a
931 named.conf file (including GSS-TSIG configuration).
933 :param path: Path of the new named.conf file.
934 :param realm: Realm name
935 :param dnsdomain: DNS Domain name
936 :param private_dir: Path to private directory
937 :param keytab_name: File name of DNS keytab file
939 setup_file(setup_path("named.txt"), path, {
940 "DNSDOMAIN": dnsdomain,
941 "DNSNAME" : dnsname,
942 "REALM": realm,
943 "DNS_KEYTAB": keytab_name,
944 "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
945 "PRIVATE_DIR": private_dir
949 def is_valid_dns_backend(dns_backend):
950 return dns_backend in ("BIND9_FLATFILE", "BIND9_DLZ", "SAMBA_INTERNAL", "NONE")
953 def is_valid_os_level(os_level):
954 return DS_DOMAIN_FUNCTION_2000 <= os_level <= DS_DOMAIN_FUNCTION_2008_R2
957 def create_dns_legacy(samdb, domainsid, forestdn, dnsadmins_sid):
958 # Set up MicrosoftDNS container
959 add_dns_container(samdb, forestdn, "CN=System", domainsid, dnsadmins_sid)
960 # Add root servers
961 add_rootservers(samdb, forestdn, "CN=System")
964 def fill_dns_data_legacy(samdb, domainsid, forestdn, dnsdomain, site, hostname,
965 hostip, hostip6, dnsadmins_sid):
966 # Add domain record
967 add_domain_record(samdb, forestdn, "CN=System", dnsdomain, domainsid,
968 dnsadmins_sid)
970 # Add DNS records for a DC in domain
971 add_dc_domain_records(samdb, forestdn, "CN=System", site, dnsdomain,
972 hostname, hostip, hostip6)
975 def create_dns_partitions(samdb, domainsid, names, domaindn, forestdn,
976 dnsadmins_sid, fill_level):
977 # Set up additional partitions (DomainDnsZones, ForstDnsZones)
978 setup_dns_partitions(samdb, domainsid, domaindn, forestdn,
979 names.configdn, names.serverdn, fill_level)
981 # Set up MicrosoftDNS containers
982 add_dns_container(samdb, domaindn, "DC=DomainDnsZones", domainsid,
983 dnsadmins_sid)
984 if fill_level != FILL_SUBDOMAIN:
985 add_dns_container(samdb, forestdn, "DC=ForestDnsZones", domainsid,
986 dnsadmins_sid, forest=True)
989 def fill_dns_data_partitions(samdb, domainsid, site, domaindn, forestdn,
990 dnsdomain, dnsforest, hostname, hostip, hostip6,
991 domainguid, ntdsguid, dnsadmins_sid, autofill=True,
992 fill_level=FILL_FULL):
993 """Fill data in various AD partitions
995 :param samdb: LDB object connected to sam.ldb file
996 :param domainsid: Domain SID (as dom_sid object)
997 :param site: Site name to create hostnames in
998 :param domaindn: DN of the domain
999 :param forestdn: DN of the forest
1000 :param dnsdomain: DNS name of the domain
1001 :param dnsforest: DNS name of the forest
1002 :param hostname: Host name of this DC
1003 :param hostip: IPv4 addresses
1004 :param hostip6: IPv6 addresses
1005 :param domainguid: Domain GUID
1006 :param ntdsguid: NTDS GUID
1007 :param dnsadmins_sid: SID for DnsAdmins group
1008 :param autofill: Create DNS records (using fixed template)
1011 ##### Set up DC=DomainDnsZones,<DOMAINDN>
1012 # Add rootserver records
1013 add_rootservers(samdb, domaindn, "DC=DomainDnsZones")
1015 # Add domain record
1016 add_domain_record(samdb, domaindn, "DC=DomainDnsZones", dnsdomain,
1017 domainsid, dnsadmins_sid)
1019 # Add DNS records for a DC in domain
1020 if autofill:
1021 add_dc_domain_records(samdb, domaindn, "DC=DomainDnsZones", site,
1022 dnsdomain, hostname, hostip, hostip6)
1024 if fill_level != FILL_SUBDOMAIN:
1025 ##### Set up DC=ForestDnsZones,<FORESTDN>
1026 # Add _msdcs record
1027 add_msdcs_record(samdb, forestdn, "DC=ForestDnsZones", dnsforest)
1029 # Add DNS records for a DC in forest
1030 if autofill:
1031 add_dc_msdcs_records(samdb, forestdn, "DC=ForestDnsZones", site,
1032 dnsforest, hostname, hostip, hostip6,
1033 domainguid, ntdsguid)
1036 def setup_ad_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
1037 dns_backend, os_level, site, dnspass=None, hostip=None, hostip6=None,
1038 targetdir=None, fill_level=FILL_FULL):
1039 """Provision DNS information (assuming GC role)
1041 :param samdb: LDB object connected to sam.ldb file
1042 :param secretsdb: LDB object connected to secrets.ldb file
1043 :param domainsid: Domain SID (as dom_sid object)
1044 :param names: Names shortcut
1045 :param paths: Paths shortcut
1046 :param lp: Loadparm object
1047 :param logger: Logger object
1048 :param dns_backend: Type of DNS backend
1049 :param os_level: Functional level (treated as os level)
1050 :param site: Site to create hostnames in
1051 :param dnspass: Password for bind's DNS account
1052 :param hostip: IPv4 address
1053 :param hostip6: IPv6 address
1054 :param targetdir: Target directory for creating DNS-related files for BIND9
1057 if not is_valid_dns_backend(dns_backend):
1058 raise Exception("Invalid dns backend: %r" % dns_backend)
1060 if not is_valid_os_level(os_level):
1061 raise Exception("Invalid os level: %r" % os_level)
1063 if dns_backend == "NONE":
1064 logger.info("No DNS backend set, not configuring DNS")
1065 return
1067 # Add dns accounts (DnsAdmins, DnsUpdateProxy) in domain
1068 logger.info("Adding DNS accounts")
1069 add_dns_accounts(samdb, names.domaindn)
1071 # If dns_backend is BIND9_FLATFILE
1072 # Populate only CN=MicrosoftDNS,CN=System,<DOMAINDN>
1074 # If dns_backend is SAMBA_INTERNAL or BIND9_DLZ
1075 # Populate DNS partitions
1077 # If os_level < 2003 (DS_DOMAIN_FUNCTION_2000)
1078 # All dns records are in CN=MicrosoftDNS,CN=System,<DOMAINDN>
1080 # If os_level >= 2003 (DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008,
1081 # DS_DOMAIN_FUNCTION_2008_R2)
1082 # Root server records are in CN=MicrosoftDNS,CN=System,<DOMAINDN>
1083 # Domain records are in CN=MicrosoftDNS,CN=System,<DOMAINDN>
1084 # Domain records are in CN=MicrosoftDNS,DC=DomainDnsZones,<DOMAINDN>
1085 # Forest records are in CN=MicrosoftDNS,DC=ForestDnsZones,<FORESTDN>
1086 domaindn = names.domaindn
1087 forestdn = samdb.get_root_basedn().get_linearized()
1089 dnsdomain = names.dnsdomain.lower()
1090 dnsforest = dnsdomain
1092 hostname = names.netbiosname.lower()
1094 dnsadmins_sid = get_dnsadmins_sid(samdb, domaindn)
1095 domainguid = get_domainguid(samdb, domaindn)
1097 # Create CN=System
1098 logger.info("Creating CN=MicrosoftDNS,CN=System,%s" % domaindn)
1099 create_dns_legacy(samdb, domainsid, domaindn, dnsadmins_sid)
1101 if os_level == DS_DOMAIN_FUNCTION_2000:
1102 # Populating legacy dns
1103 logger.info("Populating CN=MicrosoftDNS,CN=System,%s" % domaindn)
1104 fill_dns_data_legacy(samdb, domainsid, domaindn, dnsdomain, site,
1105 hostname, hostip, hostip6, dnsadmins_sid)
1107 elif dns_backend in ("SAMBA_INTERNAL", "BIND9_DLZ") and \
1108 os_level >= DS_DOMAIN_FUNCTION_2003:
1110 # Create DNS partitions
1111 logger.info("Creating DomainDnsZones and ForestDnsZones partitions")
1112 create_dns_partitions(samdb, domainsid, names, domaindn, forestdn,
1113 dnsadmins_sid, fill_level)
1115 # Populating dns partitions
1116 logger.info("Populating DomainDnsZones and ForestDnsZones partitions")
1117 fill_dns_data_partitions(samdb, domainsid, site, domaindn, forestdn,
1118 dnsdomain, dnsforest, hostname, hostip, hostip6,
1119 domainguid, names.ntdsguid, dnsadmins_sid,
1120 fill_level=fill_level)
1122 if dns_backend.startswith("BIND9_"):
1123 setup_bind9_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
1124 dns_backend, os_level, site=site, dnspass=dnspass, hostip=hostip,
1125 hostip6=hostip6, targetdir=targetdir)
1128 def setup_bind9_dns(samdb, secretsdb, domainsid, names, paths, lp, logger,
1129 dns_backend, os_level, site=None, dnspass=None, hostip=None,
1130 hostip6=None, targetdir=None, key_version_number=None):
1131 """Provision DNS information (assuming BIND9 backend in DC role)
1133 :param samdb: LDB object connected to sam.ldb file
1134 :param secretsdb: LDB object connected to secrets.ldb file
1135 :param domainsid: Domain SID (as dom_sid object)
1136 :param names: Names shortcut
1137 :param paths: Paths shortcut
1138 :param lp: Loadparm object
1139 :param logger: Logger object
1140 :param dns_backend: Type of DNS backend
1141 :param os_level: Functional level (treated as os level)
1142 :param site: Site to create hostnames in
1143 :param dnspass: Password for bind's DNS account
1144 :param hostip: IPv4 address
1145 :param hostip6: IPv6 address
1146 :param targetdir: Target directory for creating DNS-related files for BIND9
1149 if (not is_valid_dns_backend(dns_backend) or
1150 not dns_backend.startswith("BIND9_")):
1151 raise Exception("Invalid dns backend: %r" % dns_backend)
1153 if not is_valid_os_level(os_level):
1154 raise Exception("Invalid os level: %r" % os_level)
1156 domaindn = names.domaindn
1158 domainguid = get_domainguid(samdb, domaindn)
1160 secretsdb_setup_dns(secretsdb, names,
1161 paths.private_dir, realm=names.realm,
1162 dnsdomain=names.dnsdomain,
1163 dns_keytab_path=paths.dns_keytab, dnspass=dnspass,
1164 key_version_number=key_version_number)
1166 create_dns_dir(logger, paths)
1168 if dns_backend == "BIND9_FLATFILE":
1169 create_zone_file(lp, logger, paths, targetdir, site=site,
1170 dnsdomain=names.dnsdomain, hostip=hostip,
1171 hostip6=hostip6, hostname=names.hostname,
1172 realm=names.realm, domainguid=domainguid,
1173 ntdsguid=names.ntdsguid)
1175 if dns_backend == "BIND9_DLZ" and os_level >= DS_DOMAIN_FUNCTION_2003:
1176 create_samdb_copy(samdb, logger, paths, names, domainsid, domainguid)
1178 create_named_conf(paths, realm=names.realm,
1179 dnsdomain=names.dnsdomain, dns_backend=dns_backend,
1180 logger=logger)
1182 create_named_txt(paths.namedtxt,
1183 realm=names.realm, dnsdomain=names.dnsdomain,
1184 dnsname = "%s.%s" % (names.hostname, names.dnsdomain),
1185 private_dir=paths.private_dir,
1186 keytab_name=paths.dns_keytab)
1187 logger.info("See %s for an example configuration include file for BIND",
1188 paths.namedconf)
1189 logger.info("and %s for further documentation required for secure DNS "
1190 "updates", paths.namedtxt)