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"""
28 from base64
import b64encode
30 from samba
.ndr
import ndr_pack
, ndr_unpack
31 from samba
import read_and_sub_file
, setup_file
32 from samba
.dcerpc
import dnsp
, misc
, security
33 from samba
.dsdb
import (
34 DS_DOMAIN_FUNCTION_2000
,
35 DS_DOMAIN_FUNCTION_2003
,
36 DS_DOMAIN_FUNCTION_2008
,
37 DS_DOMAIN_FUNCTION_2008_R2
39 from base64
import b64encode
40 from samba
.provision
.descriptor
import (
41 get_domain_descriptor
,
42 get_dns_partition_descriptor
44 from samba
.provision
.common
import (
52 def get_domainguid(samdb
, domaindn
):
53 res
= samdb
.search(base
=domaindn
, scope
=ldb
.SCOPE_BASE
, attrs
=["objectGUID"])
54 domainguid
= str(ndr_unpack(misc
.GUID
, res
[0]["objectGUID"][0]))
57 def get_dnsadmins_sid(samdb
, domaindn
):
58 res
= samdb
.search(base
="CN=DnsAdmins,CN=Users,%s" % domaindn
, scope
=ldb
.SCOPE_BASE
,
60 dnsadmins_sid
= ndr_unpack(security
.dom_sid
, res
[0]["objectSid"][0])
63 class ARecord(dnsp
.DnssrvRpcRecord
):
64 def __init__(self
, ip_addr
, serial
=1, ttl
=900, rank
=dnsp
.DNS_RANK_ZONE
):
65 super(ARecord
, self
).__init
__()
66 self
.wType
= dnsp
.DNS_TYPE_A
68 self
.dwSerial
= serial
69 self
.dwTtlSeconds
= ttl
72 class AAAARecord(dnsp
.DnssrvRpcRecord
):
73 def __init__(self
, ip6_addr
, serial
=1, ttl
=900, rank
=dnsp
.DNS_RANK_ZONE
):
74 super(AAAARecord
, self
).__init
__()
75 self
.wType
= dnsp
.DNS_TYPE_AAAA
77 self
.dwSerial
= serial
78 self
.dwTtlSeconds
= ttl
81 class CNameRecord(dnsp
.DnssrvRpcRecord
):
82 def __init__(self
, cname
, serial
=1, ttl
=900, rank
=dnsp
.DNS_RANK_ZONE
):
83 super(CNameRecord
, self
).__init
__()
84 self
.wType
= dnsp
.DNS_TYPE_CNAME
86 self
.dwSerial
= serial
87 self
.dwTtlSeconds
= ttl
90 class NSRecord(dnsp
.DnssrvRpcRecord
):
91 def __init__(self
, dns_server
, serial
=1, ttl
=900, rank
=dnsp
.DNS_RANK_ZONE
):
92 super(NSRecord
, self
).__init
__()
93 self
.wType
= dnsp
.DNS_TYPE_NS
95 self
.dwSerial
= serial
96 self
.dwTtlSeconds
= ttl
97 self
.data
= dns_server
99 class SOARecord(dnsp
.DnssrvRpcRecord
):
100 def __init__(self
, mname
, rname
, serial
=1, refresh
=900, retry
=600,
101 expire
=86400, minimum
=3600, ttl
=3600, rank
=dnsp
.DNS_RANK_ZONE
):
102 super(SOARecord
, self
).__init
__()
103 self
.wType
= dnsp
.DNS_TYPE_SOA
105 self
.dwSerial
= serial
106 self
.dwTtlSeconds
= ttl
109 soa
.refresh
= refresh
116 class SRVRecord(dnsp
.DnssrvRpcRecord
):
117 def __init__(self
, target
, port
, priority
=0, weight
=100, serial
=1, ttl
=900,
118 rank
=dnsp
.DNS_RANK_ZONE
):
119 super(SRVRecord
, self
).__init
__()
120 self
.wType
= dnsp
.DNS_TYPE_SRV
122 self
.dwSerial
= serial
123 self
.dwTtlSeconds
= ttl
125 srv
.nameTarget
= target
127 srv
.wPriority
= priority
131 class TXTRecord(dnsp
.DnssrvRpcRecord
):
132 def __init__(self
, slist
, serial
=1, ttl
=900, rank
=dnsp
.DNS_RANK_ZONE
):
133 super(TXTRecord
, self
).__init
__()
134 self
.wType
= dnsp
.DNS_TYPE_TXT
136 self
.dwSerial
= serial
137 self
.dwTtlSeconds
= ttl
138 stringlist
= dnsp
.string_list()
139 stringlist
.count
= len(slist
)
140 stringlist
.str = slist
141 self
.data
= stringlist
143 class TypeProperty(dnsp
.DnsProperty
):
144 def __init__(self
, zone_type
=dnsp
.DNS_ZONE_TYPE_PRIMARY
):
145 super(TypeProperty
, self
).__init
__()
148 self
.id = dnsp
.DSPROPERTY_ZONE_TYPE
149 self
.data
= zone_type
151 class AllowUpdateProperty(dnsp
.DnsProperty
):
152 def __init__(self
, allow_update
=dnsp
.DNS_ZONE_UPDATE_SECURE
):
153 super(AllowUpdateProperty
, self
).__init
__()
156 self
.id = dnsp
.DSPROPERTY_ZONE_ALLOW_UPDATE
157 self
.data
= allow_update
159 class SecureTimeProperty(dnsp
.DnsProperty
):
160 def __init__(self
, secure_time
=0):
161 super(SecureTimeProperty
, self
).__init
__()
164 self
.id = dnsp
.DSPROPERTY_ZONE_SECURE_TIME
165 self
.data
= secure_time
167 class NorefreshIntervalProperty(dnsp
.DnsProperty
):
168 def __init__(self
, norefresh_interval
=0):
169 super(NorefreshIntervalProperty
, self
).__init
__()
172 self
.id = dnsp
.DSPROPERTY_ZONE_NOREFRESH_INTERVAL
173 self
.data
= norefresh_interval
175 class RefreshIntervalProperty(dnsp
.DnsProperty
):
176 def __init__(self
, refresh_interval
=0):
177 super(RefreshIntervalProperty
, self
).__init
__()
180 self
.id = dnsp
.DSPROPERTY_ZONE_REFRESH_INTERVAL
181 self
.data
= refresh_interval
183 class AgingStateProperty(dnsp
.DnsProperty
):
184 def __init__(self
, aging_enabled
=0):
185 super(AgingStateProperty
, self
).__init
__()
188 self
.id = dnsp
.DSPROPERTY_ZONE_AGING_STATE
189 self
.data
= aging_enabled
191 class AgingEnabledTimeProperty(dnsp
.DnsProperty
):
192 def __init__(self
, next_cycle_hours
=0):
193 super(AgingEnabledTimeProperty
, self
).__init
__()
196 self
.id = dnsp
.DSPROPERTY_ZONE_AGING_ENABLED_TIME
197 self
.data
= next_cycle_hours
199 def setup_dns_partitions(samdb
, domainsid
, domaindn
, forestdn
, configdn
, serverdn
):
200 domainzone_dn
= "DC=DomainDnsZones,%s" % domaindn
201 forestzone_dn
= "DC=ForestDnsZones,%s" % forestdn
202 descriptor
= get_dns_partition_descriptor(domainsid
)
203 setup_add_ldif(samdb
, setup_path("provision_dnszones_partitions.ldif"), {
204 "DOMAINZONE_DN": domainzone_dn
,
205 "FORESTZONE_DN": forestzone_dn
,
206 "SECDESC" : b64encode(descriptor
)
209 domainzone_guid
= get_domainguid(samdb
, domainzone_dn
)
210 forestzone_guid
= get_domainguid(samdb
, forestzone_dn
)
212 domainzone_guid
= str(uuid
.uuid4())
213 forestzone_guid
= str(uuid
.uuid4())
215 domainzone_dns
= ldb
.Dn(samdb
, domainzone_dn
).canonical_ex_str().strip()
216 forestzone_dns
= ldb
.Dn(samdb
, forestzone_dn
).canonical_ex_str().strip()
218 setup_add_ldif(samdb
, setup_path("provision_dnszones_add.ldif"), {
219 "DOMAINZONE_DN": domainzone_dn
,
220 "FORESTZONE_DN": forestzone_dn
,
221 "DOMAINZONE_GUID": domainzone_guid
,
222 "FORESTZONE_GUID": forestzone_guid
,
223 "DOMAINZONE_DNS": domainzone_dns
,
224 "FORESTZONE_DNS": forestzone_dns
,
225 "CONFIGDN": configdn
,
226 "SERVERDN": serverdn
,
229 setup_modify_ldif(samdb
, setup_path("provision_dnszones_modify.ldif"), {
230 "CONFIGDN": configdn
,
231 "SERVERDN": serverdn
,
232 "DOMAINZONE_DN": domainzone_dn
,
233 "FORESTZONE_DN": forestzone_dn
,
237 def add_dns_accounts(samdb
, domaindn
):
238 setup_add_ldif(samdb
, setup_path("provision_dns_accounts_add.ldif"), {
239 "DOMAINDN": domaindn
,
242 def add_dns_container(samdb
, domaindn
, prefix
, domainsid
, dnsadmins_sid
):
243 # CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
244 sddl
= "O:SYG:SYD:AI" \
245 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
246 "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)" \
247 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
248 "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
249 "S:AI" % dnsadmins_sid
250 sec
= security
.descriptor
.from_sddl(sddl
, domainsid
)
251 msg
= ldb
.Message(ldb
.Dn(samdb
, "CN=MicrosoftDNS,%s,%s" % (prefix
, domaindn
)))
252 msg
["objectClass"] = ["top", "container"]
253 msg
["nTSecurityDescriptor"] = ldb
.MessageElement(ndr_pack(sec
), ldb
.FLAG_MOD_ADD
,
254 "nTSecurityDescriptor")
257 def add_rootservers(samdb
, domaindn
, prefix
):
259 rootservers
["a.root-servers.net"] = "198.41.0.4"
260 rootservers
["b.root-servers.net"] = "192.228.79.201"
261 rootservers
["c.root-servers.net"] = "192.33.4.12"
262 rootservers
["d.root-servers.net"] = "128.8.10.90"
263 rootservers
["e.root-servers.net"] = "192.203.230.10"
264 rootservers
["f.root-servers.net"] = "192.5.5.241"
265 rootservers
["g.root-servers.net"] = "192.112.36.4"
266 rootservers
["h.root-servers.net"] = "128.63.2.53"
267 rootservers
["i.root-servers.net"] = "192.36.148.17"
268 rootservers
["j.root-servers.net"] = "192.58.128.30"
269 rootservers
["k.root-servers.net"] = "193.0.14.129"
270 rootservers
["l.root-servers.net"] = "199.7.83.42"
271 rootservers
["m.root-servers.net"] = "202.12.27.33"
274 rootservers_v6
["a.root-servers.net"] = "2001:503:ba3e::2:30"
275 rootservers_v6
["f.root-servers.net"] = "2001:500:2f::f"
276 rootservers_v6
["h.root-servers.net"] = "2001:500:1::803f:235"
277 rootservers_v6
["j.root-servers.net"] = "2001:503:c27::2:30"
278 rootservers_v6
["k.root-servers.net"] = "2001:7fd::1"
279 rootservers_v6
["m.root-servers.net"] = "2001:dc3::35"
281 container_dn
= "DC=RootDNSServers,CN=MicrosoftDNS,%s,%s" % (prefix
, domaindn
)
283 # Add DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
284 msg
= ldb
.Message(ldb
.Dn(samdb
, container_dn
))
286 props
.append(ndr_pack(TypeProperty(zone_type
=dnsp
.DNS_ZONE_TYPE_CACHE
)))
287 props
.append(ndr_pack(AllowUpdateProperty(allow_update
=dnsp
.DNS_ZONE_UPDATE_OFF
)))
288 props
.append(ndr_pack(SecureTimeProperty()))
289 props
.append(ndr_pack(NorefreshIntervalProperty()))
290 props
.append(ndr_pack(RefreshIntervalProperty()))
291 props
.append(ndr_pack(AgingStateProperty()))
292 props
.append(ndr_pack(AgingEnabledTimeProperty()))
293 msg
["objectClass"] = ["top", "dnsZone"]
294 msg
["cn"] = ldb
.MessageElement("Zone", ldb
.FLAG_MOD_ADD
, "cn")
295 msg
["dNSProperty"] = ldb
.MessageElement(props
, ldb
.FLAG_MOD_ADD
, "dNSProperty")
298 # Add DC=@,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
300 for rserver
in rootservers
:
301 record
.append(ndr_pack(NSRecord(rserver
, serial
=0, ttl
=0, rank
=dnsp
.DNS_RANK_ROOT_HINT
)))
303 msg
= ldb
.Message(ldb
.Dn(samdb
, "DC=@,%s" % container_dn
))
304 msg
["objectClass"] = ["top", "dnsNode"]
305 msg
["dnsRecord"] = ldb
.MessageElement(record
, ldb
.FLAG_MOD_ADD
, "dnsRecord")
308 # Add DC=<rootserver>,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
309 for rserver
in rootservers
:
310 record
= [ndr_pack(ARecord(rootservers
[rserver
], serial
=0, ttl
=0, rank
=dnsp
.DNS_RANK_ROOT_HINT
))]
311 # Add AAAA record as well (How does W2K* add IPv6 records?)
312 #if rserver in rootservers_v6:
313 # record.append(ndr_pack(AAAARecord(rootservers_v6[rserver], serial=0, ttl=0)))
314 msg
= ldb
.Message(ldb
.Dn(samdb
, "DC=%s,%s" % (rserver
, container_dn
)))
315 msg
["objectClass"] = ["top", "dnsNode"]
316 msg
["dnsRecord"] = ldb
.MessageElement(record
, ldb
.FLAG_MOD_ADD
, "dnsRecord")
319 def add_at_record(samdb
, container_dn
, prefix
, hostname
, dnsdomain
, hostip
, hostip6
):
321 fqdn_hostname
= "%s.%s" % (hostname
, dnsdomain
)
326 at_soa_record
= SOARecord(fqdn_hostname
, "hostmaster.%s" % dnsdomain
)
327 at_records
.append(ndr_pack(at_soa_record
))
330 at_ns_record
= NSRecord(fqdn_hostname
)
331 at_records
.append(ndr_pack(at_ns_record
))
333 if hostip
is not None:
335 at_a_record
= ARecord(hostip
)
336 at_records
.append(ndr_pack(at_a_record
))
338 if hostip6
is not None:
340 at_aaaa_record
= AAAARecord(hostip6
)
341 at_records
.append(ndr_pack(at_aaaa_record
))
343 msg
= ldb
.Message(ldb
.Dn(samdb
, "DC=@,%s" % container_dn
))
344 msg
["objectClass"] = ["top", "dnsNode"]
345 msg
["dnsRecord"] = ldb
.MessageElement(at_records
, ldb
.FLAG_MOD_ADD
, "dnsRecord")
348 def add_srv_record(samdb
, container_dn
, prefix
, host
, port
):
349 srv_record
= SRVRecord(host
, port
)
350 msg
= ldb
.Message(ldb
.Dn(samdb
, "%s,%s" % (prefix
, container_dn
)))
351 msg
["objectClass"] = ["top", "dnsNode"]
352 msg
["dnsRecord"] = ldb
.MessageElement(ndr_pack(srv_record
), ldb
.FLAG_MOD_ADD
, "dnsRecord")
355 def add_ns_record(samdb
, container_dn
, prefix
, host
):
356 ns_record
= NSRecord(host
)
357 msg
= ldb
.Message(ldb
.Dn(samdb
, "%s,%s" % (prefix
, container_dn
)))
358 msg
["objectClass"] = ["top", "dnsNode"]
359 msg
["dnsRecord"] = ldb
.MessageElement(ndr_pack(ns_record
), ldb
.FLAG_MOD_ADD
, "dnsRecord")
362 def add_ns_glue_record(samdb
, container_dn
, prefix
, host
):
363 ns_record
= NSRecord(host
, rank
=dnsp
.DNS_RANK_NS_GLUE
)
364 msg
= ldb
.Message(ldb
.Dn(samdb
, "%s,%s" % (prefix
, container_dn
)))
365 msg
["objectClass"] = ["top", "dnsNode"]
366 msg
["dnsRecord"] = ldb
.MessageElement(ndr_pack(ns_record
), ldb
.FLAG_MOD_ADD
, "dnsRecord")
369 def add_cname_record(samdb
, container_dn
, prefix
, host
):
370 cname_record
= CNameRecord(host
)
371 msg
= ldb
.Message(ldb
.Dn(samdb
, "%s,%s" % (prefix
, container_dn
)))
372 msg
["objectClass"] = ["top", "dnsNode"]
373 msg
["dnsRecord"] = ldb
.MessageElement(ndr_pack(cname_record
), ldb
.FLAG_MOD_ADD
, "dnsRecord")
376 def add_host_record(samdb
, container_dn
, prefix
, hostip
, hostip6
):
379 a_record
= ARecord(hostip
)
380 host_records
.append(ndr_pack(a_record
))
382 aaaa_record
= AAAARecord(hostip6
)
383 host_records
.append(ndr_pack(aaaa_record
))
385 msg
= ldb
.Message(ldb
.Dn(samdb
, "%s,%s" % (prefix
, container_dn
)))
386 msg
["objectClass"] = ["top", "dnsNode"]
387 msg
["dnsRecord"] = ldb
.MessageElement(host_records
, ldb
.FLAG_MOD_ADD
, "dnsRecord")
390 def add_domain_record(samdb
, domaindn
, prefix
, dnsdomain
, domainsid
, dnsadmins_sid
):
391 # DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
392 sddl
= "O:SYG:BAD:AI" \
393 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA)" \
395 "(A;;RPLCLORC;;;WD)" \
396 "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
397 "(A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
398 "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;%s)" \
399 "(A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED)" \
400 "(OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
401 "(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
403 "(A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
404 "S:AI" % dnsadmins_sid
405 sec
= security
.descriptor
.from_sddl(sddl
, domainsid
)
407 props
.append(ndr_pack(TypeProperty()))
408 props
.append(ndr_pack(AllowUpdateProperty()))
409 props
.append(ndr_pack(SecureTimeProperty()))
410 props
.append(ndr_pack(NorefreshIntervalProperty(norefresh_interval
=168)))
411 props
.append(ndr_pack(RefreshIntervalProperty(refresh_interval
=168)))
412 props
.append(ndr_pack(AgingStateProperty()))
413 props
.append(ndr_pack(AgingEnabledTimeProperty()))
414 msg
= ldb
.Message(ldb
.Dn(samdb
, "DC=%s,CN=MicrosoftDNS,%s,%s" % (dnsdomain
, prefix
, domaindn
)))
415 msg
["objectClass"] = ["top", "dnsZone"]
416 msg
["ntSecurityDescriptor"] = ldb
.MessageElement(ndr_pack(sec
), ldb
.FLAG_MOD_ADD
,
417 "nTSecurityDescriptor")
418 msg
["dNSProperty"] = ldb
.MessageElement(props
, ldb
.FLAG_MOD_ADD
, "dNSProperty")
421 def add_msdcs_record(samdb
, forestdn
, prefix
, dnsforest
):
422 # DC=_msdcs.<DNSFOREST>,CN=MicrosoftDNS,<PREFIX>,<FORESTDN>
423 msg
= ldb
.Message(ldb
.Dn(samdb
, "DC=_msdcs.%s,CN=MicrosoftDNS,%s,%s" %
424 (dnsforest
, prefix
, forestdn
)))
425 msg
["objectClass"] = ["top", "dnsZone"]
429 def add_dc_domain_records(samdb
, domaindn
, prefix
, site
, dnsdomain
, hostname
, hostip
, hostip6
):
431 fqdn_hostname
= "%s.%s" % (hostname
, dnsdomain
)
433 # Set up domain container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
434 domain_container_dn
= ldb
.Dn(samdb
, "DC=%s,CN=MicrosoftDNS,%s,%s" %
435 (dnsdomain
, prefix
, domaindn
))
438 add_at_record(samdb
, domain_container_dn
, "DC=@", hostname
, dnsdomain
, hostip
, hostip6
)
440 # DC=<HOSTNAME> record
441 add_host_record(samdb
, domain_container_dn
, "DC=%s" % hostname
, hostip
, hostip6
)
443 # DC=_kerberos._tcp record
444 add_srv_record(samdb
, domain_container_dn
, "DC=_kerberos._tcp", fqdn_hostname
, 88)
446 # DC=_kerberos._tcp.<SITENAME>._sites record
447 add_srv_record(samdb
, domain_container_dn
, "DC=_kerberos._tcp.%s._sites" % site
,
450 # DC=_kerberos._udp record
451 add_srv_record(samdb
, domain_container_dn
, "DC=_kerberos._udp", fqdn_hostname
, 88)
453 # DC=_kpasswd._tcp record
454 add_srv_record(samdb
, domain_container_dn
, "DC=_kpasswd._tcp", fqdn_hostname
, 464)
456 # DC=_kpasswd._udp record
457 add_srv_record(samdb
, domain_container_dn
, "DC=_kpasswd._udp", fqdn_hostname
, 464)
459 # DC=_ldap._tcp record
460 add_srv_record(samdb
, domain_container_dn
, "DC=_ldap._tcp", fqdn_hostname
, 389)
462 # DC=_ldap._tcp.<SITENAME>._sites record
463 add_srv_record(samdb
, domain_container_dn
, "DC=_ldap._tcp.%s._sites" % site
,
466 # FIXME: The number of SRV records depend on the various roles this DC has.
467 # _gc and _msdcs records are added if the we are the forest dc and not subdomain dc
469 # Assumption: current DC is GC and add all the entries
472 add_srv_record(samdb
, domain_container_dn
, "DC=_gc._tcp", fqdn_hostname
, 3268)
474 # DC=_gc._tcp.<SITENAME>,_sites record
475 add_srv_record(samdb
, domain_container_dn
, "DC=_gc._tcp.%s._sites" % site
, fqdn_hostname
, 3268)
478 add_ns_glue_record(samdb
, domain_container_dn
, "DC=_msdcs", fqdn_hostname
)
480 # FIXME: Following entries are added only if DomainDnsZones and ForestDnsZones partitions
483 # Assumption: Additional entries won't hurt on os_level = 2000
485 # DC=_ldap._tcp.<SITENAME>._sites.DomainDnsZones
486 add_srv_record(samdb
, domain_container_dn
, "DC=_ldap._tcp.%s._sites.DomainDnsZones" % site
,
489 # DC=_ldap._tcp.<SITENAME>._sites.ForestDnsZones
490 add_srv_record(samdb
, domain_container_dn
, "DC=_ldap._tcp.%s._sites.ForestDnsZones" % site
,
493 # DC=_ldap._tcp.DomainDnsZones
494 add_srv_record(samdb
, domain_container_dn
, "DC=_ldap._tcp.DomainDnsZones",
497 # DC=_ldap._tcp.ForestDnsZones
498 add_srv_record(samdb
, domain_container_dn
, "DC=_ldap._tcp.ForestDnsZones",
502 add_host_record(samdb
, domain_container_dn
, "DC=DomainDnsZones", hostip
, hostip6
)
505 add_host_record(samdb
, domain_container_dn
, "DC=ForestDnsZones", hostip
, hostip6
)
508 def add_dc_msdcs_records(samdb
, forestdn
, prefix
, site
, dnsforest
, hostname
,
509 hostip
, hostip6
, domainguid
, ntdsguid
):
511 fqdn_hostname
= "%s.%s" % (hostname
, dnsforest
)
513 # Set up forest container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
514 forest_container_dn
= ldb
.Dn(samdb
, "DC=_msdcs.%s,CN=MicrosoftDNS,%s,%s" %
515 (dnsforest
, prefix
, forestdn
))
518 add_at_record(samdb
, forest_container_dn
, "DC=@", hostname
, dnsforest
, None, None)
520 # DC=_kerberos._tcp.dc record
521 add_srv_record(samdb
, forest_container_dn
, "DC=_kerberos._tcp.dc", fqdn_hostname
, 88)
523 # DC=_kerberos._tcp.<SITENAME>._sites.dc record
524 add_srv_record(samdb
, forest_container_dn
, "DC=_kerberos._tcp.%s._sites.dc" % site
,
527 # DC=_ldap._tcp.dc record
528 add_srv_record(samdb
, forest_container_dn
, "DC=_ldap._tcp.dc", fqdn_hostname
, 389)
530 # DC=_ldap._tcp.<SITENAME>._sites.dc record
531 add_srv_record(samdb
, forest_container_dn
, "DC=_ldap._tcp.%s._sites.dc" % site
,
534 # DC=_ldap._tcp.<SITENAME>._sites.gc record
535 add_srv_record(samdb
, forest_container_dn
, "DC=_ldap._tcp.%s._sites.gc" % site
,
538 # DC=_ldap._tcp.gc record
539 add_srv_record(samdb
, forest_container_dn
, "DC=_ldap._tcp.gc", fqdn_hostname
, 3268)
541 # DC=_ldap._tcp.pdc record
542 add_srv_record(samdb
, forest_container_dn
, "DC=_ldap._tcp.pdc", fqdn_hostname
, 389)
545 add_host_record(samdb
, forest_container_dn
, "DC=gc", hostip
, hostip6
)
547 # DC=_ldap._tcp.<DOMAINGUID>.domains record
548 add_srv_record(samdb
, forest_container_dn
, "DC=_ldap._tcp.%s.domains" % domainguid
,
552 add_cname_record(samdb
, forest_container_dn
, "DC=%s" % ntdsguid
, fqdn_hostname
)
555 def secretsdb_setup_dns(secretsdb
, names
, private_dir
, realm
,
556 dnsdomain
, dns_keytab_path
, dnspass
):
557 """Add DNS specific bits to a secrets database.
559 :param secretsdb: Ldb Handle to the secrets database
560 :param names: Names shortcut
561 :param machinepass: Machine password
564 os
.unlink(os
.path
.join(private_dir
, dns_keytab_path
))
568 setup_ldb(secretsdb
, setup_path("secrets_dns.ldif"), {
570 "DNSDOMAIN": dnsdomain
,
571 "DNS_KEYTAB": dns_keytab_path
,
572 "DNSPASS_B64": b64encode(dnspass
),
573 "HOSTNAME": names
.hostname
,
574 "DNSNAME" : '%s.%s' % (
575 names
.netbiosname
.lower(), names
.dnsdomain
.lower())
579 def create_dns_dir(logger
, paths
):
580 """Write out a DNS zone file, from the info in the current database.
582 :param logger: Logger object
583 :param paths: paths object
585 dns_dir
= os
.path
.dirname(paths
.dns
)
588 shutil
.rmtree(dns_dir
, True)
592 os
.mkdir(dns_dir
, 0770)
594 if paths
.bind_gid
is not None:
596 os
.chown(dns_dir
, -1, paths
.bind_gid
)
597 # chmod needed to cope with umask
598 os
.chmod(dns_dir
, 0770)
600 if not os
.environ
.has_key('SAMBA_SELFTEST'):
601 logger
.error("Failed to chown %s to bind gid %u" % (
602 dns_dir
, paths
.bind_gid
))
605 def create_zone_file(lp
, logger
, paths
, targetdir
, dnsdomain
,
606 hostip
, hostip6
, hostname
, realm
, domainguid
,
608 """Write out a DNS zone file, from the info in the current database.
610 :param paths: paths object
611 :param dnsdomain: DNS Domain name
612 :param domaindn: DN of the Domain
613 :param hostip: Local IPv4 IP
614 :param hostip6: Local IPv6 IP
615 :param hostname: Local hostname
616 :param realm: Realm name
617 :param domainguid: GUID of the domain.
618 :param ntdsguid: GUID of the hosts nTDSDSA record.
620 assert isinstance(domainguid
, str)
622 if hostip6
is not None:
623 hostip6_base_line
= " IN AAAA " + hostip6
624 hostip6_host_line
= hostname
+ " IN AAAA " + hostip6
625 gc_msdcs_ip6_line
= "gc._msdcs IN AAAA " + hostip6
627 hostip6_base_line
= ""
628 hostip6_host_line
= ""
629 gc_msdcs_ip6_line
= ""
631 if hostip
is not None:
632 hostip_base_line
= " IN A " + hostip
633 hostip_host_line
= hostname
+ " IN A " + hostip
634 gc_msdcs_ip_line
= "gc._msdcs IN A " + hostip
636 hostip_base_line
= ""
637 hostip_host_line
= ""
638 gc_msdcs_ip_line
= ""
640 # we need to freeze the zone while we update the contents
641 if targetdir
is None:
642 rndc
= ' '.join(lp
.get("rndc command"))
643 os
.system(rndc
+ " freeze " + lp
.get("realm"))
645 setup_file(setup_path("provision.zone"), paths
.dns
, {
646 "HOSTNAME": hostname
,
647 "DNSDOMAIN": dnsdomain
,
649 "HOSTIP_BASE_LINE": hostip_base_line
,
650 "HOSTIP_HOST_LINE": hostip_host_line
,
651 "DOMAINGUID": domainguid
,
652 "DATESTRING": time
.strftime("%Y%m%d%H"),
654 "NTDSGUID": ntdsguid
,
655 "HOSTIP6_BASE_LINE": hostip6_base_line
,
656 "HOSTIP6_HOST_LINE": hostip6_host_line
,
657 "GC_MSDCS_IP_LINE": gc_msdcs_ip_line
,
658 "GC_MSDCS_IP6_LINE": gc_msdcs_ip6_line
,
661 if paths
.bind_gid
is not None:
663 os
.chown(paths
.dns
, -1, paths
.bind_gid
)
664 # chmod needed to cope with umask
665 os
.chmod(paths
.dns
, 0664)
667 if not os
.environ
.has_key('SAMBA_SELFTEST'):
668 logger
.error("Failed to chown %s to bind gid %u" % (
669 paths
.dns
, paths
.bind_gid
))
671 if targetdir
is None:
672 os
.system(rndc
+ " unfreeze " + lp
.get("realm"))
674 def tdb_copy(logger
, file1
, file2
):
675 """Copy tdb file using tdbbackup utility and rename it
677 # Find the location of tdbbackup tool
678 dirs
= ["bin", samba
.param
.bin_dir()] + os
.getenv('PATH').split(os
.pathsep
)
680 toolpath
= os
.path
.join(d
, "tdbbackup")
681 if os
.path
.exists(toolpath
):
683 status
= os
.system("%s -s '.dns' %s" % (toolpath
, file1
))
685 os
.rename("%s.dns" % file1
, file2
)
687 raise Exception("Error copying %s" % file1
)
689 def create_samdb_copy(samdb
, logger
, paths
, names
, domainsid
, domainguid
):
690 """Create a copy of samdb and give write permissions to named for dns partitions
692 private_dir
= paths
.private_dir
693 samldb_dir
= os
.path
.join(private_dir
, "sam.ldb.d")
694 dns_dir
= os
.path
.dirname(paths
.dns
)
695 dns_samldb_dir
= os
.path
.join(dns_dir
, "sam.ldb.d")
697 # Find the partitions and corresponding filenames
699 res
= samdb
.search(base
="@PARTITION", scope
=ldb
.SCOPE_BASE
, attrs
=["partition"])
700 for tmp
in res
[0]["partition"]:
701 (nc
, fname
) = tmp
.split(':')
702 partfile
[nc
.upper()] = fname
704 # Create empty domain partition
705 domaindn
= names
.domaindn
.upper()
706 domainpart_file
= os
.path
.join(dns_dir
, partfile
[domaindn
])
708 os
.mkdir(dns_samldb_dir
)
709 file(domainpart_file
, 'w').close()
711 # Fill the basedn and @OPTION records in domain partition
712 dom_ldb
= samba
.Ldb(domainpart_file
)
713 domainguid_line
= "objectGUID: %s\n-" % domainguid
714 descr
= b64encode(get_domain_descriptor(domainsid
))
715 setup_add_ldif(dom_ldb
, setup_path("provision_basedn.ldif"), {
716 "DOMAINDN" : names
.domaindn
,
717 "DOMAINGUID" : domainguid_line
,
718 "DOMAINSID" : str(domainsid
),
719 "DESCRIPTOR" : descr
})
720 setup_add_ldif(dom_ldb
, setup_path("provision_basedn_options.ldif"), None)
722 logger
.error("Failed to setup database for BIND, AD based DNS cannot be used")
724 del partfile
[domaindn
]
726 # Link dns partitions and metadata
727 domainzonedn
= "DC=DOMAINDNSZONES,%s" % names
.domaindn
.upper()
728 forestzonedn
= "DC=FORESTDNSZONES,%s" % names
.rootdn
.upper()
729 domainzone_file
= partfile
[domainzonedn
]
730 forestzone_file
= partfile
[forestzonedn
]
731 metadata_file
= "metadata.tdb"
733 os
.link(os
.path
.join(samldb_dir
, metadata_file
),
734 os
.path
.join(dns_samldb_dir
, metadata_file
))
735 os
.link(os
.path
.join(private_dir
, domainzone_file
),
736 os
.path
.join(dns_dir
, domainzone_file
))
737 os
.link(os
.path
.join(private_dir
, forestzone_file
),
738 os
.path
.join(dns_dir
, forestzone_file
))
740 logger
.error("Failed to setup database for BIND, AD based DNS cannot be used")
742 del partfile
[domainzonedn
]
743 del partfile
[forestzonedn
]
745 # Copy root, config, schema partitions (and any other if any)
746 # Since samdb is open in the current process, copy them in a child process
749 os
.path
.join(private_dir
, "sam.ldb"),
750 os
.path
.join(dns_dir
, "sam.ldb"))
754 os
.path
.join(private_dir
, pfile
),
755 os
.path
.join(dns_dir
, pfile
))
757 logger
.error("Failed to setup database for BIND, AD based DNS cannot be used")
760 # Give bind read/write permissions dns partitions
761 if paths
.bind_gid
is not None:
763 os
.chown(samldb_dir
, -1, paths
.bind_gid
)
764 os
.chmod(samldb_dir
, 0750)
766 for dirname
, dirs
, files
in os
.walk(dns_dir
):
768 dpath
= os
.path
.join(dirname
, d
)
769 os
.chown(dpath
, -1, paths
.bind_gid
)
770 os
.chmod(dpath
, 0770)
772 if f
.endswith('.ldb') or f
.endswith('.tdb'):
773 fpath
= os
.path
.join(dirname
, f
)
774 os
.chown(fpath
, -1, paths
.bind_gid
)
775 os
.chmod(fpath
, 0660)
777 if not os
.environ
.has_key('SAMBA_SELFTEST'):
778 logger
.error("Failed to set permissions to sam.ldb* files, fix manually")
780 if not os
.environ
.has_key('SAMBA_SELFTEST'):
781 logger
.warning("""Unable to find group id for BIND,
782 set permissions to sam.ldb* files manually""")
785 def create_dns_update_list(lp
, logger
, paths
):
786 """Write out a dns_update_list file"""
787 # note that we use no variable substitution on this file
788 # the substitution is done at runtime by samba_dnsupdate, samba_spnupdate
789 setup_file(setup_path("dns_update_list"), paths
.dns_update_list
, None)
790 setup_file(setup_path("spn_update_list"), paths
.spn_update_list
, None)
793 def create_named_conf(paths
, realm
, dnsdomain
, dns_backend
):
794 """Write out a file containing zone statements suitable for inclusion in a
795 named.conf file (including GSS-TSIG configuration).
797 :param paths: all paths
798 :param realm: Realm name
799 :param dnsdomain: DNS Domain name
800 :param dns_backend: DNS backend type
801 :param keytab_name: File name of DNS keytab file
804 if dns_backend
== "BIND9_FLATFILE":
805 setup_file(setup_path("named.conf"), paths
.namedconf
, {
806 "DNSDOMAIN": dnsdomain
,
808 "ZONE_FILE": paths
.dns
,
809 "REALM_WC": "*." + ".".join(realm
.split(".")[1:]),
810 "NAMED_CONF": paths
.namedconf
,
811 "NAMED_CONF_UPDATE": paths
.namedconf_update
814 setup_file(setup_path("named.conf.update"), paths
.namedconf_update
)
816 elif dns_backend
== "BIND9_DLZ":
817 setup_file(setup_path("named.conf.dlz"), paths
.namedconf
, {
818 "NAMED_CONF": paths
.namedconf
,
819 "MODULESDIR" : samba
.param
.modules_dir(),
823 def create_named_txt(path
, realm
, dnsdomain
, dnsname
, private_dir
,
825 """Write out a file containing zone statements suitable for inclusion in a
826 named.conf file (including GSS-TSIG configuration).
828 :param path: Path of the new named.conf file.
829 :param realm: Realm name
830 :param dnsdomain: DNS Domain name
831 :param private_dir: Path to private directory
832 :param keytab_name: File name of DNS keytab file
834 setup_file(setup_path("named.txt"), path
, {
835 "DNSDOMAIN": dnsdomain
,
838 "DNS_KEYTAB": keytab_name
,
839 "DNS_KEYTAB_ABS": os
.path
.join(private_dir
, keytab_name
),
840 "PRIVATE_DIR": private_dir
844 def is_valid_dns_backend(dns_backend
):
845 return dns_backend
in ("BIND9_FLATFILE", "BIND9_DLZ", "SAMBA_INTERNAL", "NONE")
848 def is_valid_os_level(os_level
):
849 return DS_DOMAIN_FUNCTION_2000
<= os_level
<= DS_DOMAIN_FUNCTION_2008_R2
852 def create_dns_legacy(samdb
, domainsid
, forestdn
, dnsadmins_sid
):
853 # Set up MicrosoftDNS container
854 add_dns_container(samdb
, forestdn
, "CN=System", domainsid
, dnsadmins_sid
)
856 add_rootservers(samdb
, forestdn
, "CN=System")
859 def fill_dns_data_legacy(samdb
, domainsid
, forestdn
, dnsdomain
, site
, hostname
,
860 hostip
, hostip6
, dnsadmins_sid
):
862 add_domain_record(samdb
, forestdn
, "CN=System", dnsdomain
, domainsid
,
865 # Add DNS records for a DC in domain
866 add_dc_domain_records(samdb
, forestdn
, "CN=System", site
, dnsdomain
,
867 hostname
, hostip
, hostip6
)
870 def create_dns_partitions(samdb
, domainsid
, names
, domaindn
, forestdn
,
872 # Set up additional partitions (DomainDnsZones, ForstDnsZones)
873 setup_dns_partitions(samdb
, domainsid
, domaindn
, forestdn
,
874 names
.configdn
, names
.serverdn
)
876 # Set up MicrosoftDNS containers
877 add_dns_container(samdb
, domaindn
, "DC=DomainDnsZones", domainsid
,
879 add_dns_container(samdb
, forestdn
, "DC=ForestDnsZones", domainsid
,
883 def fill_dns_data_partitions(samdb
, domainsid
, site
, domaindn
, forestdn
,
884 dnsdomain
, dnsforest
, hostname
, hostip
, hostip6
,
885 domainguid
, ntdsguid
, dnsadmins_sid
, autofill
=True):
886 """Fill data in various AD partitions
888 :param samdb: LDB object connected to sam.ldb file
889 :param domainsid: Domain SID (as dom_sid object)
890 :param site: Site name to create hostnames in
891 :param domaindn: DN of the domain
892 :param forestdn: DN of the forest
893 :param dnsdomain: DNS name of the domain
894 :param dnsforest: DNS name of the forest
895 :param hostname: Host name of this DC
896 :param hostip: IPv4 addresses
897 :param hostip6: IPv6 addresses
898 :param domainguid: Domain GUID
899 :param ntdsguid: NTDS GUID
900 :param dnsadmins_sid: SID for DnsAdmins group
901 :param autofill: Create DNS records (using fixed template)
904 ##### Set up DC=DomainDnsZones,<DOMAINDN>
905 # Add rootserver records
906 add_rootservers(samdb
, domaindn
, "DC=DomainDnsZones")
909 add_domain_record(samdb
, domaindn
, "DC=DomainDnsZones", dnsdomain
,
910 domainsid
, dnsadmins_sid
)
912 # Add DNS records for a DC in domain
914 add_dc_domain_records(samdb
, domaindn
, "DC=DomainDnsZones", site
,
915 dnsdomain
, hostname
, hostip
, hostip6
)
917 ##### Set up DC=ForestDnsZones,<DOMAINDN>
919 add_msdcs_record(samdb
, forestdn
, "DC=ForestDnsZones", dnsforest
)
921 # Add DNS records for a DC in forest
923 add_dc_msdcs_records(samdb
, forestdn
, "DC=ForestDnsZones", site
,
924 dnsforest
, hostname
, hostip
, hostip6
,
925 domainguid
, ntdsguid
)
928 def setup_ad_dns(samdb
, secretsdb
, domainsid
, names
, paths
, lp
, logger
, dns_backend
,
929 os_level
, site
, dnspass
=None, hostip
=None, hostip6
=None,
931 """Provision DNS information (assuming GC role)
933 :param samdb: LDB object connected to sam.ldb file
934 :param secretsdb: LDB object connected to secrets.ldb file
935 :param domainsid: Domain SID (as dom_sid object)
936 :param names: Names shortcut
937 :param paths: Paths shortcut
938 :param lp: Loadparm object
939 :param logger: Logger object
940 :param dns_backend: Type of DNS backend
941 :param os_level: Functional level (treated as os level)
942 :param site: Site to create hostnames in
943 :param dnspass: Password for bind's DNS account
944 :param hostip: IPv4 address
945 :param hostip6: IPv6 address
946 :param targetdir: Target directory for creating DNS-related files for BIND9
949 if not is_valid_dns_backend(dns_backend
):
950 raise Exception("Invalid dns backend: %r" % dns_backend
)
952 if not is_valid_os_level(os_level
):
953 raise Exception("Invalid os level: %r" % os_level
)
955 if dns_backend
is "NONE":
956 logger
.info("No DNS backend set, not configuring DNS")
959 # Add dns accounts (DnsAdmins, DnsUpdateProxy) in domain
960 logger
.info("Adding DNS accounts")
961 add_dns_accounts(samdb
, names
.domaindn
)
963 # If dns_backend is BIND9_FLATFILE
964 # Populate only CN=MicrosoftDNS,CN=System,<FORESTDN>
966 # If dns_backend is SAMBA_INTERNAL or BIND9_DLZ
967 # Populate DNS partitions
969 # If os_level < 2003 (DS_DOMAIN_FUNCTION_2000)
970 # All dns records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
972 # If os_level >= 2003 (DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008,
973 # DS_DOMAIN_FUNCTION_2008_R2)
974 # Root server records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
975 # Domain records are in CN=MicrosoftDNS,CN=System,<FORESTDN>
976 # Domain records are in CN=MicrosoftDNS,DC=DomainDnsZones,<DOMAINDN>
977 # Forest records are in CN=MicrosoftDNS,DC=ForestDnsZones,<FORESTDN>
978 domaindn
= names
.domaindn
979 forestdn
= samdb
.get_root_basedn().get_linearized()
981 dnsdomain
= names
.dnsdomain
.lower()
982 dnsforest
= dnsdomain
984 hostname
= names
.netbiosname
.lower()
986 dnsadmins_sid
= get_dnsadmins_sid(samdb
, domaindn
)
987 domainguid
= get_domainguid(samdb
, domaindn
)
990 logger
.info("Creating CN=MicrosoftDNS,CN=System,%s" % forestdn
)
991 create_dns_legacy(samdb
, domainsid
, forestdn
, dnsadmins_sid
)
993 if os_level
== DS_DOMAIN_FUNCTION_2000
:
994 # Populating legacy dns
995 logger
.info("Populating CN=MicrosoftDNS,CN=System,%s" % forestdn
)
996 fill_dns_data_legacy(samdb
, domainsid
, forestdn
, dnsdomain
, site
,
997 hostname
, hostip
, hostip6
, dnsadmins_sid
)
999 elif dns_backend
in ("SAMBA_INTERNAL", "BIND9_DLZ") and \
1000 os_level
>= DS_DOMAIN_FUNCTION_2003
:
1002 # Create DNS partitions
1003 logger
.info("Creating DomainDnsZones and ForestDnsZones partitions")
1004 create_dns_partitions(samdb
, domainsid
, names
, domaindn
, forestdn
,
1007 # Populating dns partitions
1008 logger
.info("Populating DomainDnsZones and ForestDnsZones partitions")
1009 fill_dns_data_partitions(samdb
, domainsid
, site
, domaindn
, forestdn
,
1010 dnsdomain
, dnsforest
, hostname
, hostip
, hostip6
,
1011 domainguid
, names
.ntdsguid
, dnsadmins_sid
)
1013 if dns_backend
.startswith("BIND9_"):
1014 setup_bind9_dns(samdb
, secretsdb
, domainsid
, names
, paths
, lp
, logger
, dns_backend
,
1015 os_level
, site
=site
, dnspass
=dnspass
, hostip
=hostip
, hostip6
=hostip6
,
1016 targetdir
=targetdir
)
1018 def setup_bind9_dns(samdb
, secretsdb
, domainsid
, names
, paths
, lp
, logger
, dns_backend
,
1019 os_level
, site
=None, dnspass
=None, hostip
=None, hostip6
=None,
1021 """Provision DNS information (assuming BIND9 backend in DC role)
1023 :param samdb: LDB object connected to sam.ldb file
1024 :param secretsdb: LDB object connected to secrets.ldb file
1025 :param domainsid: Domain SID (as dom_sid object)
1026 :param names: Names shortcut
1027 :param paths: Paths shortcut
1028 :param lp: Loadparm object
1029 :param logger: Logger object
1030 :param dns_backend: Type of DNS backend
1031 :param os_level: Functional level (treated as os level)
1032 :param site: Site to create hostnames in
1033 :param dnspass: Password for bind's DNS account
1034 :param hostip: IPv4 address
1035 :param hostip6: IPv6 address
1036 :param targetdir: Target directory for creating DNS-related files for BIND9
1039 if not is_valid_dns_backend(dns_backend
) or not dns_backend
.startswith("BIND9_"):
1040 raise Exception("Invalid dns backend: %r" % dns_backend
)
1042 if not is_valid_os_level(os_level
):
1043 raise Exception("Invalid os level: %r" % os_level
)
1045 domaindn
= names
.domaindn
1047 domainguid
= get_domainguid(samdb
, domaindn
)
1049 secretsdb_setup_dns(secretsdb
, names
,
1050 paths
.private_dir
, realm
=names
.realm
,
1051 dnsdomain
=names
.dnsdomain
,
1052 dns_keytab_path
=paths
.dns_keytab
, dnspass
=dnspass
)
1054 create_dns_dir(logger
, paths
)
1056 if dns_backend
== "BIND9_FLATFILE":
1057 create_zone_file(lp
, logger
, paths
, targetdir
, site
=site
,
1058 dnsdomain
=names
.dnsdomain
, hostip
=hostip
, hostip6
=hostip6
,
1059 hostname
=names
.hostname
, realm
=names
.realm
,
1060 domainguid
=domainguid
, ntdsguid
=names
.ntdsguid
)
1062 if dns_backend
== "BIND9_DLZ" and os_level
>= DS_DOMAIN_FUNCTION_2003
:
1063 create_samdb_copy(samdb
, logger
, paths
, names
, domainsid
, domainguid
)
1065 create_named_conf(paths
, realm
=names
.realm
,
1066 dnsdomain
=names
.dnsdomain
, dns_backend
=dns_backend
)
1068 create_named_txt(paths
.namedtxt
,
1069 realm
=names
.realm
, dnsdomain
=names
.dnsdomain
,
1070 dnsname
= "%s.%s" % (names
.hostname
, names
.dnsdomain
),
1071 private_dir
=paths
.private_dir
,
1072 keytab_name
=paths
.dns_keytab
)
1073 logger
.info("See %s for an example configuration include file for BIND", paths
.namedconf
)
1074 logger
.info("and %s for further documentation required for secure DNS "
1075 "updates", paths
.namedtxt
)