2011-06-27 13:25:39 +04:00
# Unix SMB/CIFS implementation.
# backend code for provisioning DNS for a Samba4 server
#
# Copyright (C) Kai Blin <kai@samba.org> 2011
2011-09-05 10:19:02 +04:00
# Copyright (C) Amitay Isaacs <amitay@gmail.com> 2011
2011-06-27 13:25:39 +04:00
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
""" DNS-related provisioning """
import os
2011-09-05 10:19:02 +04:00
import uuid
2011-10-21 13:56:10 +04:00
import shutil
import time
2011-06-27 13:25:39 +04:00
import ldb
2011-09-20 11:30:10 +04:00
from base64 import b64encode
2013-12-19 06:06:51 +04:00
import subprocess
2011-06-27 13:25:39 +04:00
import samba
2013-02-17 11:14:06 +04:00
from samba . tdb_util import tdb_copy
2011-09-05 10:19:02 +04:00
from samba . ndr import ndr_pack , ndr_unpack
2012-09-16 02:34:00 +04:00
from samba import setup_file
2011-09-20 11:30:10 +04:00
from samba . dcerpc import dnsp , misc , security
2011-09-05 10:19:02 +04:00
from samba . dsdb import (
DS_DOMAIN_FUNCTION_2000 ,
DS_DOMAIN_FUNCTION_2003 ,
DS_DOMAIN_FUNCTION_2008_R2
)
2013-03-21 06:34:26 +04:00
from samba . descriptor import (
2011-09-20 03:58:42 +04:00
get_domain_descriptor ,
2013-01-23 19:27:17 +04:00
get_domain_delete_protected1_descriptor ,
get_domain_delete_protected2_descriptor ,
get_dns_partition_descriptor ,
get_dns_forest_microsoft_dns_descriptor ,
get_dns_domain_microsoft_dns_descriptor
2011-09-20 03:58:42 +04:00
)
2011-12-11 10:00:03 +04:00
from samba . provision . common import (
setup_path ,
setup_add_ldif ,
setup_modify_ldif ,
2013-09-09 03:54:23 +04:00
setup_ldb ,
FILL_FULL ,
FILL_SUBDOMAIN ,
FILL_NT4SYNC ,
FILL_DRS ,
2011-12-11 10:00:03 +04:00
)
2011-09-05 10:19:02 +04:00
def get_domainguid ( samdb , domaindn ) :
res = samdb . search ( base = domaindn , scope = ldb . SCOPE_BASE , attrs = [ " objectGUID " ] )
domainguid = str ( ndr_unpack ( misc . GUID , res [ 0 ] [ " objectGUID " ] [ 0 ] ) )
return domainguid
2012-09-16 02:34:00 +04:00
2011-11-28 07:18:31 +04:00
def get_dnsadmins_sid ( samdb , domaindn ) :
res = samdb . search ( base = " CN=DnsAdmins,CN=Users, %s " % domaindn , scope = ldb . SCOPE_BASE ,
attrs = [ " objectSid " ] )
dnsadmins_sid = ndr_unpack ( security . dom_sid , res [ 0 ] [ " objectSid " ] [ 0 ] )
return dnsadmins_sid
2012-09-16 02:34:00 +04:00
2011-06-27 13:25:39 +04:00
class ARecord ( dnsp . DnssrvRpcRecord ) :
2012-09-16 02:34:00 +04:00
2011-10-07 08:39:58 +04:00
def __init__ ( self , ip_addr , serial = 1 , ttl = 900 , rank = dnsp . DNS_RANK_ZONE ) :
2011-06-27 13:25:39 +04:00
super ( ARecord , self ) . __init__ ( )
self . wType = dnsp . DNS_TYPE_A
2011-10-07 08:39:58 +04:00
self . rank = rank
2011-06-27 13:25:39 +04:00
self . dwSerial = serial
self . dwTtlSeconds = ttl
self . data = ip_addr
2012-09-16 02:34:00 +04:00
2011-06-27 13:25:39 +04:00
class AAAARecord ( dnsp . DnssrvRpcRecord ) :
2012-09-16 02:34:00 +04:00
2011-10-07 08:39:58 +04:00
def __init__ ( self , ip6_addr , serial = 1 , ttl = 900 , rank = dnsp . DNS_RANK_ZONE ) :
2011-06-27 13:25:39 +04:00
super ( AAAARecord , self ) . __init__ ( )
self . wType = dnsp . DNS_TYPE_AAAA
2011-10-07 08:39:58 +04:00
self . rank = rank
2011-06-27 13:25:39 +04:00
self . dwSerial = serial
self . dwTtlSeconds = ttl
self . data = ip6_addr
2012-09-16 02:34:00 +04:00
2011-09-05 10:19:02 +04:00
class CNameRecord ( dnsp . DnssrvRpcRecord ) :
2012-09-16 02:34:00 +04:00
2011-10-07 08:39:58 +04:00
def __init__ ( self , cname , serial = 1 , ttl = 900 , rank = dnsp . DNS_RANK_ZONE ) :
2011-09-05 10:19:02 +04:00
super ( CNameRecord , self ) . __init__ ( )
self . wType = dnsp . DNS_TYPE_CNAME
2011-10-07 08:39:58 +04:00
self . rank = rank
2011-09-05 10:19:02 +04:00
self . dwSerial = serial
self . dwTtlSeconds = ttl
self . data = cname
2012-09-16 02:34:00 +04:00
2011-06-27 13:25:39 +04:00
class NSRecord ( dnsp . DnssrvRpcRecord ) :
2012-09-16 02:34:00 +04:00
2011-10-07 08:39:58 +04:00
def __init__ ( self , dns_server , serial = 1 , ttl = 900 , rank = dnsp . DNS_RANK_ZONE ) :
2011-06-27 13:25:39 +04:00
super ( NSRecord , self ) . __init__ ( )
self . wType = dnsp . DNS_TYPE_NS
2011-10-07 08:39:58 +04:00
self . rank = rank
2011-06-27 13:25:39 +04:00
self . dwSerial = serial
self . dwTtlSeconds = ttl
self . data = dns_server
2012-09-16 02:34:00 +04:00
2011-06-27 13:25:39 +04:00
class SOARecord ( dnsp . DnssrvRpcRecord ) :
2012-09-16 02:34:00 +04:00
2011-06-27 13:25:39 +04:00
def __init__ ( self , mname , rname , serial = 1 , refresh = 900 , retry = 600 ,
2011-10-07 08:39:58 +04:00
expire = 86400 , minimum = 3600 , ttl = 3600 , rank = dnsp . DNS_RANK_ZONE ) :
2011-06-27 13:25:39 +04:00
super ( SOARecord , self ) . __init__ ( )
self . wType = dnsp . DNS_TYPE_SOA
2011-10-07 08:39:58 +04:00
self . rank = rank
2011-06-27 13:25:39 +04:00
self . dwSerial = serial
self . dwTtlSeconds = ttl
soa = dnsp . soa ( )
soa . serial = serial
soa . refresh = refresh
soa . retry = retry
soa . expire = expire
soa . mname = mname
soa . rname = rname
2014-05-16 20:33:42 +04:00
soa . minimum = minimum
2011-06-27 13:25:39 +04:00
self . data = soa
2012-09-16 02:34:00 +04:00
2011-06-27 13:25:39 +04:00
class SRVRecord ( dnsp . DnssrvRpcRecord ) :
2012-09-16 02:34:00 +04:00
2011-10-07 08:39:58 +04:00
def __init__ ( self , target , port , priority = 0 , weight = 100 , serial = 1 , ttl = 900 ,
rank = dnsp . DNS_RANK_ZONE ) :
2011-06-27 13:25:39 +04:00
super ( SRVRecord , self ) . __init__ ( )
self . wType = dnsp . DNS_TYPE_SRV
2011-10-07 08:39:58 +04:00
self . rank = rank
2011-06-27 13:25:39 +04:00
self . dwSerial = serial
self . dwTtlSeconds = ttl
srv = dnsp . srv ( )
srv . nameTarget = target
srv . wPort = port
srv . wPriority = priority
srv . wWeight = weight
self . data = srv
2012-09-16 02:34:00 +04:00
2012-02-02 06:31:53 +04:00
class TXTRecord ( dnsp . DnssrvRpcRecord ) :
2012-09-16 02:34:00 +04:00
2012-02-28 07:59:39 +04:00
def __init__ ( self , slist , serial = 1 , ttl = 900 , rank = dnsp . DNS_RANK_ZONE ) :
2012-02-02 06:31:53 +04:00
super ( TXTRecord , self ) . __init__ ( )
self . wType = dnsp . DNS_TYPE_TXT
self . rank = rank
self . dwSerial = serial
self . dwTtlSeconds = ttl
2012-02-28 07:59:39 +04:00
stringlist = dnsp . string_list ( )
stringlist . count = len ( slist )
stringlist . str = slist
self . data = stringlist
2012-02-02 06:31:53 +04:00
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
class TypeProperty ( dnsp . DnsProperty ) :
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
def __init__ ( self , zone_type = dnsp . DNS_ZONE_TYPE_PRIMARY ) :
super ( TypeProperty , self ) . __init__ ( )
2012-01-03 06:51:00 +04:00
self . wDataLength = 1
2011-12-14 07:47:05 +04:00
self . version = 1
self . id = dnsp . DSPROPERTY_ZONE_TYPE
self . data = zone_type
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
class AllowUpdateProperty ( dnsp . DnsProperty ) :
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
def __init__ ( self , allow_update = dnsp . DNS_ZONE_UPDATE_SECURE ) :
super ( AllowUpdateProperty , self ) . __init__ ( )
2012-01-03 06:51:00 +04:00
self . wDataLength = 1
2011-12-14 07:47:05 +04:00
self . version = 1
self . id = dnsp . DSPROPERTY_ZONE_ALLOW_UPDATE
self . data = allow_update
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
class SecureTimeProperty ( dnsp . DnsProperty ) :
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
def __init__ ( self , secure_time = 0 ) :
super ( SecureTimeProperty , self ) . __init__ ( )
2012-01-03 06:51:00 +04:00
self . wDataLength = 1
2011-12-14 07:47:05 +04:00
self . version = 1
self . id = dnsp . DSPROPERTY_ZONE_SECURE_TIME
self . data = secure_time
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
class NorefreshIntervalProperty ( dnsp . DnsProperty ) :
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
def __init__ ( self , norefresh_interval = 0 ) :
super ( NorefreshIntervalProperty , self ) . __init__ ( )
2012-01-03 06:51:00 +04:00
self . wDataLength = 1
2011-12-14 07:47:05 +04:00
self . version = 1
self . id = dnsp . DSPROPERTY_ZONE_NOREFRESH_INTERVAL
self . data = norefresh_interval
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
class RefreshIntervalProperty ( dnsp . DnsProperty ) :
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
def __init__ ( self , refresh_interval = 0 ) :
super ( RefreshIntervalProperty , self ) . __init__ ( )
2012-01-03 06:51:00 +04:00
self . wDataLength = 1
2011-12-14 07:47:05 +04:00
self . version = 1
self . id = dnsp . DSPROPERTY_ZONE_REFRESH_INTERVAL
self . data = refresh_interval
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
class AgingStateProperty ( dnsp . DnsProperty ) :
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
def __init__ ( self , aging_enabled = 0 ) :
super ( AgingStateProperty , self ) . __init__ ( )
2012-01-03 06:51:00 +04:00
self . wDataLength = 1
2011-12-14 07:47:05 +04:00
self . version = 1
self . id = dnsp . DSPROPERTY_ZONE_AGING_STATE
self . data = aging_enabled
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
class AgingEnabledTimeProperty ( dnsp . DnsProperty ) :
2012-09-16 02:34:00 +04:00
2011-12-14 07:47:05 +04:00
def __init__ ( self , next_cycle_hours = 0 ) :
super ( AgingEnabledTimeProperty , self ) . __init__ ( )
2012-01-03 06:51:00 +04:00
self . wDataLength = 1
2011-12-14 07:47:05 +04:00
self . version = 1 ;
self . id = dnsp . DSPROPERTY_ZONE_AGING_ENABLED_TIME
self . data = next_cycle_hours
2012-09-16 02:34:00 +04:00
def setup_dns_partitions ( samdb , domainsid , domaindn , forestdn , configdn ,
2013-09-09 03:54:23 +04:00
serverdn , fill_level ) :
2011-09-05 10:19:02 +04:00
domainzone_dn = " DC=DomainDnsZones, %s " % domaindn
forestzone_dn = " DC=ForestDnsZones, %s " % forestdn
2011-11-16 04:18:18 +04:00
descriptor = get_dns_partition_descriptor ( domainsid )
2013-09-09 03:54:23 +04:00
2011-12-11 10:00:03 +04:00
setup_add_ldif ( samdb , setup_path ( " provision_dnszones_partitions.ldif " ) , {
2013-09-09 03:54:23 +04:00
" ZONE_DN " : domainzone_dn ,
2011-11-16 04:18:18 +04:00
" SECDESC " : b64encode ( descriptor )
2011-09-05 10:19:02 +04:00
} )
2013-09-09 03:54:23 +04:00
if fill_level != FILL_SUBDOMAIN :
setup_add_ldif ( samdb , setup_path ( " provision_dnszones_partitions.ldif " ) , {
" ZONE_DN " : forestzone_dn ,
" SECDESC " : b64encode ( descriptor )
} )
2011-06-27 13:25:39 +04:00
2011-09-05 10:19:02 +04:00
domainzone_guid = get_domainguid ( samdb , domainzone_dn )
domainzone_guid = str ( uuid . uuid4 ( ) )
domainzone_dns = ldb . Dn ( samdb , domainzone_dn ) . canonical_ex_str ( ) . strip ( )
2013-01-23 19:27:17 +04:00
protected1_desc = get_domain_delete_protected1_descriptor ( domainsid )
protected2_desc = get_domain_delete_protected2_descriptor ( domainsid )
2011-12-11 10:00:03 +04:00
setup_add_ldif ( samdb , setup_path ( " provision_dnszones_add.ldif " ) , {
2013-09-09 03:54:23 +04:00
" ZONE_DN " : domainzone_dn ,
" ZONE_GUID " : domainzone_guid ,
" ZONE_DNS " : domainzone_dns ,
2011-09-05 10:19:02 +04:00
" CONFIGDN " : configdn ,
2011-09-06 10:22:45 +04:00
" SERVERDN " : serverdn ,
2013-01-23 19:27:17 +04:00
" LOSTANDFOUND_DESCRIPTOR " : b64encode ( protected2_desc ) ,
" INFRASTRUCTURE_DESCRIPTOR " : b64encode ( protected1_desc ) ,
2011-09-05 10:19:02 +04:00
} )
2011-12-11 10:00:03 +04:00
setup_modify_ldif ( samdb , setup_path ( " provision_dnszones_modify.ldif " ) , {
2011-09-05 10:19:02 +04:00
" CONFIGDN " : configdn ,
" SERVERDN " : serverdn ,
2013-09-09 03:54:23 +04:00
" ZONE_DN " : domainzone_dn ,
2011-09-05 10:19:02 +04:00
} )
2013-09-09 03:54:23 +04:00
if fill_level != FILL_SUBDOMAIN :
2013-10-16 05:43:39 +04:00
forestzone_guid = get_domainguid ( samdb , forestzone_dn )
forestzone_guid = str ( uuid . uuid4 ( ) )
forestzone_dns = ldb . Dn ( samdb , forestzone_dn ) . canonical_ex_str ( ) . strip ( )
2013-09-09 03:54:23 +04:00
setup_add_ldif ( samdb , setup_path ( " provision_dnszones_add.ldif " ) , {
" ZONE_DN " : forestzone_dn ,
" ZONE_GUID " : forestzone_guid ,
" ZONE_DNS " : forestzone_dns ,
" CONFIGDN " : configdn ,
" SERVERDN " : serverdn ,
" LOSTANDFOUND_DESCRIPTOR " : b64encode ( protected2_desc ) ,
" INFRASTRUCTURE_DESCRIPTOR " : b64encode ( protected1_desc ) ,
} )
setup_modify_ldif ( samdb , setup_path ( " provision_dnszones_modify.ldif " ) , {
" CONFIGDN " : configdn ,
" SERVERDN " : serverdn ,
" ZONE_DN " : forestzone_dn ,
} )
2011-09-05 10:19:02 +04:00
def add_dns_accounts ( samdb , domaindn ) :
2011-12-11 10:00:03 +04:00
setup_add_ldif ( samdb , setup_path ( " provision_dns_accounts_add.ldif " ) , {
2011-09-05 10:19:02 +04:00
" DOMAINDN " : domaindn ,
} )
2012-09-16 02:34:00 +04:00
2013-01-23 19:27:17 +04:00
def add_dns_container ( samdb , domaindn , prefix , domain_sid , dnsadmins_sid , forest = False ) :
name_map = { ' DnsAdmins ' : str ( dnsadmins_sid ) }
if forest is True :
sd_val = get_dns_forest_microsoft_dns_descriptor ( domain_sid ,
name_map = name_map )
else :
sd_val = get_dns_domain_microsoft_dns_descriptor ( domain_sid ,
name_map = name_map )
2011-09-05 10:19:02 +04:00
# CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
msg = ldb . Message ( ldb . Dn ( samdb , " CN=MicrosoftDNS, %s , %s " % ( prefix , domaindn ) ) )
msg [ " objectClass " ] = [ " top " , " container " ]
2013-01-23 19:27:17 +04:00
msg [ " nTSecurityDescriptor " ] = ldb . MessageElement ( sd_val , ldb . FLAG_MOD_ADD ,
2011-12-14 07:47:05 +04:00
" nTSecurityDescriptor " )
2011-09-05 10:19:02 +04:00
samdb . add ( msg )
2011-06-27 13:25:39 +04:00
2012-09-16 02:34:00 +04:00
2011-09-05 10:19:02 +04:00
def add_rootservers ( samdb , domaindn , prefix ) :
rootservers = { }
rootservers [ " a.root-servers.net " ] = " 198.41.0.4 "
rootservers [ " b.root-servers.net " ] = " 192.228.79.201 "
rootservers [ " c.root-servers.net " ] = " 192.33.4.12 "
rootservers [ " d.root-servers.net " ] = " 128.8.10.90 "
rootservers [ " e.root-servers.net " ] = " 192.203.230.10 "
rootservers [ " f.root-servers.net " ] = " 192.5.5.241 "
rootservers [ " g.root-servers.net " ] = " 192.112.36.4 "
rootservers [ " h.root-servers.net " ] = " 128.63.2.53 "
rootservers [ " i.root-servers.net " ] = " 192.36.148.17 "
rootservers [ " j.root-servers.net " ] = " 192.58.128.30 "
rootservers [ " k.root-servers.net " ] = " 193.0.14.129 "
rootservers [ " l.root-servers.net " ] = " 199.7.83.42 "
rootservers [ " m.root-servers.net " ] = " 202.12.27.33 "
2011-06-27 13:25:39 +04:00
2011-09-05 10:19:02 +04:00
rootservers_v6 = { }
rootservers_v6 [ " a.root-servers.net " ] = " 2001:503:ba3e::2:30 "
rootservers_v6 [ " f.root-servers.net " ] = " 2001:500:2f::f "
rootservers_v6 [ " h.root-servers.net " ] = " 2001:500:1::803f:235 "
rootservers_v6 [ " j.root-servers.net " ] = " 2001:503:c27::2:30 "
rootservers_v6 [ " k.root-servers.net " ] = " 2001:7fd::1 "
rootservers_v6 [ " m.root-servers.net " ] = " 2001:dc3::35 "
container_dn = " DC=RootDNSServers,CN=MicrosoftDNS, %s , %s " % ( prefix , domaindn )
# Add DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
msg = ldb . Message ( ldb . Dn ( samdb , container_dn ) )
2011-12-14 07:47:05 +04:00
props = [ ]
props . append ( ndr_pack ( TypeProperty ( zone_type = dnsp . DNS_ZONE_TYPE_CACHE ) ) )
props . append ( ndr_pack ( AllowUpdateProperty ( allow_update = dnsp . DNS_ZONE_UPDATE_OFF ) ) )
props . append ( ndr_pack ( SecureTimeProperty ( ) ) )
props . append ( ndr_pack ( NorefreshIntervalProperty ( ) ) )
props . append ( ndr_pack ( RefreshIntervalProperty ( ) ) )
props . append ( ndr_pack ( AgingStateProperty ( ) ) )
props . append ( ndr_pack ( AgingEnabledTimeProperty ( ) ) )
2011-09-05 10:19:02 +04:00
msg [ " objectClass " ] = [ " top " , " dnsZone " ]
2011-09-20 11:33:20 +04:00
msg [ " cn " ] = ldb . MessageElement ( " Zone " , ldb . FLAG_MOD_ADD , " cn " )
2011-12-14 07:47:05 +04:00
msg [ " dNSProperty " ] = ldb . MessageElement ( props , ldb . FLAG_MOD_ADD , " dNSProperty " )
2011-09-05 10:19:02 +04:00
samdb . add ( msg )
# Add DC=@,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
record = [ ]
for rserver in rootservers :
2011-10-07 08:39:58 +04:00
record . append ( ndr_pack ( NSRecord ( rserver , serial = 0 , ttl = 0 , rank = dnsp . DNS_RANK_ROOT_HINT ) ) )
2011-09-05 10:19:02 +04:00
msg = ldb . Message ( ldb . Dn ( samdb , " DC=@, %s " % container_dn ) )
msg [ " objectClass " ] = [ " top " , " dnsNode " ]
msg [ " dnsRecord " ] = ldb . MessageElement ( record , ldb . FLAG_MOD_ADD , " dnsRecord " )
samdb . add ( msg )
# Add DC=<rootserver>,DC=RootDNSServers,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
for rserver in rootservers :
2011-10-07 08:39:58 +04:00
record = [ ndr_pack ( ARecord ( rootservers [ rserver ] , serial = 0 , ttl = 0 , rank = dnsp . DNS_RANK_ROOT_HINT ) ) ]
2011-09-05 10:19:02 +04:00
# Add AAAA record as well (How does W2K* add IPv6 records?)
#if rserver in rootservers_v6:
# record.append(ndr_pack(AAAARecord(rootservers_v6[rserver], serial=0, ttl=0)))
msg = ldb . Message ( ldb . Dn ( samdb , " DC= %s , %s " % ( rserver , container_dn ) ) )
msg [ " objectClass " ] = [ " top " , " dnsNode " ]
msg [ " dnsRecord " ] = ldb . MessageElement ( record , ldb . FLAG_MOD_ADD , " dnsRecord " )
samdb . add ( msg )
def add_at_record ( samdb , container_dn , prefix , hostname , dnsdomain , hostip , hostip6 ) :
fqdn_hostname = " %s . %s " % ( hostname , dnsdomain )
at_records = [ ]
# SOA record
at_soa_record = SOARecord ( fqdn_hostname , " hostmaster. %s " % dnsdomain )
at_records . append ( ndr_pack ( at_soa_record ) )
# NS record
at_ns_record = NSRecord ( fqdn_hostname )
at_records . append ( ndr_pack ( at_ns_record ) )
2011-06-27 13:25:39 +04:00
if hostip is not None :
# A record
at_a_record = ARecord ( hostip )
2011-09-05 10:19:02 +04:00
at_records . append ( ndr_pack ( at_a_record ) )
2011-06-27 13:25:39 +04:00
if hostip6 is not None :
2011-09-05 10:19:02 +04:00
# AAAA record
2011-06-27 13:25:39 +04:00
at_aaaa_record = AAAARecord ( hostip6 )
2011-09-05 10:19:02 +04:00
at_records . append ( ndr_pack ( at_aaaa_record ) )
2011-06-27 13:25:39 +04:00
2011-09-05 10:19:02 +04:00
msg = ldb . Message ( ldb . Dn ( samdb , " DC=@, %s " % container_dn ) )
2011-06-27 13:25:39 +04:00
msg [ " objectClass " ] = [ " top " , " dnsNode " ]
2011-09-05 10:19:02 +04:00
msg [ " dnsRecord " ] = ldb . MessageElement ( at_records , ldb . FLAG_MOD_ADD , " dnsRecord " )
2011-06-27 13:25:39 +04:00
samdb . add ( msg )
2012-09-16 02:34:00 +04:00
2011-09-05 10:19:02 +04:00
def add_srv_record ( samdb , container_dn , prefix , host , port ) :
srv_record = SRVRecord ( host , port )
msg = ldb . Message ( ldb . Dn ( samdb , " %s , %s " % ( prefix , container_dn ) ) )
2011-06-27 13:25:39 +04:00
msg [ " objectClass " ] = [ " top " , " dnsNode " ]
2011-09-05 10:19:02 +04:00
msg [ " dnsRecord " ] = ldb . MessageElement ( ndr_pack ( srv_record ) , ldb . FLAG_MOD_ADD , " dnsRecord " )
2011-06-27 13:25:39 +04:00
samdb . add ( msg )
2012-09-16 02:34:00 +04:00
2011-09-05 10:19:02 +04:00
def add_ns_record ( samdb , container_dn , prefix , host ) :
ns_record = NSRecord ( host )
msg = ldb . Message ( ldb . Dn ( samdb , " %s , %s " % ( prefix , container_dn ) ) )
2011-06-27 13:25:39 +04:00
msg [ " objectClass " ] = [ " top " , " dnsNode " ]
2011-09-05 10:19:02 +04:00
msg [ " dnsRecord " ] = ldb . MessageElement ( ndr_pack ( ns_record ) , ldb . FLAG_MOD_ADD , " dnsRecord " )
2011-06-27 13:25:39 +04:00
samdb . add ( msg )
2012-09-16 02:34:00 +04:00
2011-10-07 08:39:58 +04:00
def add_ns_glue_record ( samdb , container_dn , prefix , host ) :
ns_record = NSRecord ( host , rank = dnsp . DNS_RANK_NS_GLUE )
msg = ldb . Message ( ldb . Dn ( samdb , " %s , %s " % ( prefix , container_dn ) ) )
msg [ " objectClass " ] = [ " top " , " dnsNode " ]
msg [ " dnsRecord " ] = ldb . MessageElement ( ndr_pack ( ns_record ) , ldb . FLAG_MOD_ADD , " dnsRecord " )
samdb . add ( msg )
2012-09-16 02:34:00 +04:00
2011-09-05 10:19:02 +04:00
def add_cname_record ( samdb , container_dn , prefix , host ) :
cname_record = CNameRecord ( host )
msg = ldb . Message ( ldb . Dn ( samdb , " %s , %s " % ( prefix , container_dn ) ) )
2011-06-27 13:25:39 +04:00
msg [ " objectClass " ] = [ " top " , " dnsNode " ]
2011-09-05 10:19:02 +04:00
msg [ " dnsRecord " ] = ldb . MessageElement ( ndr_pack ( cname_record ) , ldb . FLAG_MOD_ADD , " dnsRecord " )
2011-06-27 13:25:39 +04:00
samdb . add ( msg )
2012-09-16 02:34:00 +04:00
2011-09-05 10:19:02 +04:00
def add_host_record ( samdb , container_dn , prefix , hostip , hostip6 ) :
host_records = [ ]
if hostip :
a_record = ARecord ( hostip )
host_records . append ( ndr_pack ( a_record ) )
if hostip6 :
aaaa_record = AAAARecord ( hostip6 )
host_records . append ( ndr_pack ( aaaa_record ) )
if host_records :
msg = ldb . Message ( ldb . Dn ( samdb , " %s , %s " % ( prefix , container_dn ) ) )
msg [ " objectClass " ] = [ " top " , " dnsNode " ]
msg [ " dnsRecord " ] = ldb . MessageElement ( host_records , ldb . FLAG_MOD_ADD , " dnsRecord " )
samdb . add ( msg )
2011-06-27 13:25:39 +04:00
2012-09-16 02:34:00 +04:00
2011-11-28 07:18:31 +04:00
def add_domain_record ( samdb , domaindn , prefix , dnsdomain , domainsid , dnsadmins_sid ) :
2011-09-05 10:19:02 +04:00
# DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
2011-09-20 11:30:10 +04:00
sddl = " O:SYG:BAD:AI " \
" (A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;DA) " \
" (A;;CC;;;AU) " \
" (A;;RPLCLORC;;;WD) " \
" (A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY) " \
" (A;CI;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED) " \
2011-11-28 07:18:31 +04:00
" (A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;; %s ) " \
2011-09-20 11:30:10 +04:00
" (A;CIID;RPWPCRCCDCLCRCWOWDSDDTSW;;;ED) " \
" (OA;CIID;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS) " \
" (A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA) " \
" (A;CIID;LC;;;RU) " \
" (A;CIID;RPWPCRCCLCLORCWOWDSDSW;;;BA) " \
2011-11-28 07:18:31 +04:00
" S:AI " % dnsadmins_sid
2011-09-20 11:30:10 +04:00
sec = security . descriptor . from_sddl ( sddl , domainsid )
2011-12-14 07:47:05 +04:00
props = [ ]
props . append ( ndr_pack ( TypeProperty ( ) ) )
props . append ( ndr_pack ( AllowUpdateProperty ( ) ) )
props . append ( ndr_pack ( SecureTimeProperty ( ) ) )
props . append ( ndr_pack ( NorefreshIntervalProperty ( norefresh_interval = 168 ) ) )
props . append ( ndr_pack ( RefreshIntervalProperty ( refresh_interval = 168 ) ) )
props . append ( ndr_pack ( AgingStateProperty ( ) ) )
props . append ( ndr_pack ( AgingEnabledTimeProperty ( ) ) )
2011-09-05 10:19:02 +04:00
msg = ldb . Message ( ldb . Dn ( samdb , " DC= %s ,CN=MicrosoftDNS, %s , %s " % ( dnsdomain , prefix , domaindn ) ) )
msg [ " objectClass " ] = [ " top " , " dnsZone " ]
2011-12-14 07:47:05 +04:00
msg [ " ntSecurityDescriptor " ] = ldb . MessageElement ( ndr_pack ( sec ) , ldb . FLAG_MOD_ADD ,
" nTSecurityDescriptor " )
msg [ " dNSProperty " ] = ldb . MessageElement ( props , ldb . FLAG_MOD_ADD , " dNSProperty " )
2011-06-27 13:25:39 +04:00
samdb . add ( msg )
2012-09-16 02:34:00 +04:00
2011-09-05 10:19:02 +04:00
def add_msdcs_record ( samdb , forestdn , prefix , dnsforest ) :
# DC=_msdcs.<DNSFOREST>,CN=MicrosoftDNS,<PREFIX>,<FORESTDN>
msg = ldb . Message ( ldb . Dn ( samdb , " DC=_msdcs. %s ,CN=MicrosoftDNS, %s , %s " %
( dnsforest , prefix , forestdn ) ) )
msg [ " objectClass " ] = [ " top " , " dnsZone " ]
2011-06-27 13:25:39 +04:00
samdb . add ( msg )
2012-09-16 02:34:00 +04:00
def add_dc_domain_records ( samdb , domaindn , prefix , site , dnsdomain , hostname ,
hostip , hostip6 ) :
2011-06-27 13:25:39 +04:00
2011-09-05 10:19:02 +04:00
fqdn_hostname = " %s . %s " % ( hostname , dnsdomain )
2011-06-27 13:25:39 +04:00
2011-09-05 10:19:02 +04:00
# Set up domain container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
domain_container_dn = ldb . Dn ( samdb , " DC= %s ,CN=MicrosoftDNS, %s , %s " %
( dnsdomain , prefix , domaindn ) )
2011-06-27 13:25:39 +04:00
2011-09-05 10:19:02 +04:00
# DC=@ record
2012-09-16 02:34:00 +04:00
add_at_record ( samdb , domain_container_dn , " DC=@ " , hostname , dnsdomain ,
hostip , hostip6 )
2011-06-27 13:25:39 +04:00
2011-09-05 10:19:02 +04:00
# DC=<HOSTNAME> record
2012-09-16 02:34:00 +04:00
add_host_record ( samdb , domain_container_dn , " DC= %s " % hostname , hostip ,
hostip6 )
2011-06-27 13:25:39 +04:00
2011-09-05 10:19:02 +04:00
# DC=_kerberos._tcp record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn , " DC=_kerberos._tcp " ,
fqdn_hostname , 88 )
2011-09-05 10:19:02 +04:00
# DC=_kerberos._tcp.<SITENAME>._sites record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn , " DC=_kerberos._tcp. %s ._sites " %
site , fqdn_hostname , 88 )
2011-09-05 10:19:02 +04:00
# DC=_kerberos._udp record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn , " DC=_kerberos._udp " ,
fqdn_hostname , 88 )
2011-09-05 10:19:02 +04:00
# DC=_kpasswd._tcp record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn , " DC=_kpasswd._tcp " ,
fqdn_hostname , 464 )
2011-09-05 10:19:02 +04:00
# DC=_kpasswd._udp record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn , " DC=_kpasswd._udp " ,
fqdn_hostname , 464 )
2011-09-05 10:19:02 +04:00
# DC=_ldap._tcp record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn , " DC=_ldap._tcp " , fqdn_hostname ,
389 )
2011-09-05 10:19:02 +04:00
# DC=_ldap._tcp.<SITENAME>._sites record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn , " DC=_ldap._tcp. %s ._sites " %
site , fqdn_hostname , 389 )
2011-09-05 10:19:02 +04:00
# FIXME: The number of SRV records depend on the various roles this DC has.
# _gc and _msdcs records are added if the we are the forest dc and not subdomain dc
#
# Assumption: current DC is GC and add all the entries
# DC=_gc._tcp record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn , " DC=_gc._tcp " , fqdn_hostname ,
3268 )
2011-09-05 10:19:02 +04:00
# DC=_gc._tcp.<SITENAME>,_sites record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn , " DC=_gc._tcp. %s ._sites " % site ,
fqdn_hostname , 3268 )
2011-09-05 10:19:02 +04:00
# DC=_msdcs record
2011-10-07 08:39:58 +04:00
add_ns_glue_record ( samdb , domain_container_dn , " DC=_msdcs " , fqdn_hostname )
2011-09-05 10:19:02 +04:00
# FIXME: Following entries are added only if DomainDnsZones and ForestDnsZones partitions
# are created
#
# Assumption: Additional entries won't hurt on os_level = 2000
# DC=_ldap._tcp.<SITENAME>._sites.DomainDnsZones
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn ,
" DC=_ldap._tcp. %s ._sites.DomainDnsZones " % site , fqdn_hostname ,
389 )
2011-09-05 10:19:02 +04:00
# DC=_ldap._tcp.<SITENAME>._sites.ForestDnsZones
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , domain_container_dn ,
" DC=_ldap._tcp. %s ._sites.ForestDnsZones " % site , fqdn_hostname ,
389 )
2011-09-05 10:19:02 +04:00
# DC=_ldap._tcp.DomainDnsZones
add_srv_record ( samdb , domain_container_dn , " DC=_ldap._tcp.DomainDnsZones " ,
fqdn_hostname , 389 )
# DC=_ldap._tcp.ForestDnsZones
add_srv_record ( samdb , domain_container_dn , " DC=_ldap._tcp.ForestDnsZones " ,
fqdn_hostname , 389 )
# DC=DomainDnsZones
2012-09-16 02:34:00 +04:00
add_host_record ( samdb , domain_container_dn , " DC=DomainDnsZones " , hostip ,
hostip6 )
2011-09-05 10:19:02 +04:00
# DC=ForestDnsZones
2012-09-16 02:34:00 +04:00
add_host_record ( samdb , domain_container_dn , " DC=ForestDnsZones " , hostip ,
hostip6 )
2011-09-05 10:19:02 +04:00
def add_dc_msdcs_records ( samdb , forestdn , prefix , site , dnsforest , hostname ,
hostip , hostip6 , domainguid , ntdsguid ) :
fqdn_hostname = " %s . %s " % ( hostname , dnsforest )
# Set up forest container - DC=<DNSDOMAIN>,CN=MicrosoftDNS,<PREFIX>,<DOMAINDN>
forest_container_dn = ldb . Dn ( samdb , " DC=_msdcs. %s ,CN=MicrosoftDNS, %s , %s " %
( dnsforest , prefix , forestdn ) )
# DC=@ record
2012-09-16 02:34:00 +04:00
add_at_record ( samdb , forest_container_dn , " DC=@ " , hostname , dnsforest ,
None , None )
2011-09-05 10:19:02 +04:00
# DC=_kerberos._tcp.dc record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , forest_container_dn , " DC=_kerberos._tcp.dc " ,
fqdn_hostname , 88 )
2011-09-05 10:19:02 +04:00
# DC=_kerberos._tcp.<SITENAME>._sites.dc record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , forest_container_dn ,
" DC=_kerberos._tcp. %s ._sites.dc " % site , fqdn_hostname , 88 )
2011-09-05 10:19:02 +04:00
# DC=_ldap._tcp.dc record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , forest_container_dn , " DC=_ldap._tcp.dc " ,
fqdn_hostname , 389 )
2011-09-05 10:19:02 +04:00
# DC=_ldap._tcp.<SITENAME>._sites.dc record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , forest_container_dn , " DC=_ldap._tcp. %s ._sites.dc " %
site , fqdn_hostname , 389 )
2011-09-05 10:19:02 +04:00
# DC=_ldap._tcp.<SITENAME>._sites.gc record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , forest_container_dn , " DC=_ldap._tcp. %s ._sites.gc " %
site , fqdn_hostname , 3268 )
2011-09-05 10:19:02 +04:00
# DC=_ldap._tcp.gc record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , forest_container_dn , " DC=_ldap._tcp.gc " ,
fqdn_hostname , 3268 )
2011-09-05 10:19:02 +04:00
# DC=_ldap._tcp.pdc record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , forest_container_dn , " DC=_ldap._tcp.pdc " ,
fqdn_hostname , 389 )
2011-09-05 10:19:02 +04:00
# DC=gc record
add_host_record ( samdb , forest_container_dn , " DC=gc " , hostip , hostip6 )
# DC=_ldap._tcp.<DOMAINGUID>.domains record
2012-09-16 02:34:00 +04:00
add_srv_record ( samdb , forest_container_dn ,
" DC=_ldap._tcp. %s .domains " % domainguid , fqdn_hostname , 389 )
2011-09-05 10:19:02 +04:00
# DC=<NTDSGUID>
2012-09-16 02:34:00 +04:00
add_cname_record ( samdb , forest_container_dn , " DC= %s " % ntdsguid ,
fqdn_hostname )
2011-09-05 10:19:02 +04:00
2011-10-21 13:04:07 +04:00
def secretsdb_setup_dns ( secretsdb , names , private_dir , realm ,
2012-12-24 01:56:50 +04:00
dnsdomain , dns_keytab_path , dnspass , key_version_number ) :
2011-10-21 13:04:07 +04:00
""" Add DNS specific bits to a secrets database.
: param secretsdb : Ldb Handle to the secrets database
: param names : Names shortcut
: param machinepass : Machine password
"""
try :
os . unlink ( os . path . join ( private_dir , dns_keytab_path ) )
except OSError :
pass
2012-12-24 01:56:50 +04:00
if key_version_number is None :
key_version_number = 1
2011-10-21 13:04:07 +04:00
setup_ldb ( secretsdb , setup_path ( " secrets_dns.ldif " ) , {
" REALM " : realm ,
" DNSDOMAIN " : dnsdomain ,
" DNS_KEYTAB " : dns_keytab_path ,
" DNSPASS_B64 " : b64encode ( dnspass ) ,
2012-12-24 01:56:50 +04:00
" KEY_VERSION_NUMBER " : str ( key_version_number ) ,
2011-10-21 13:04:07 +04:00
" HOSTNAME " : names . hostname ,
" DNSNAME " : ' %s . %s ' % (
names . netbiosname . lower ( ) , names . dnsdomain . lower ( ) )
} )
2011-10-21 13:56:10 +04:00
def create_dns_dir ( logger , paths ) :
""" Write out a DNS zone file, from the info in the current database.
: param logger : Logger object
: param paths : paths object
"""
dns_dir = os . path . dirname ( paths . dns )
try :
shutil . rmtree ( dns_dir , True )
except OSError :
pass
os . mkdir ( dns_dir , 0770 )
if paths . bind_gid is not None :
try :
os . chown ( dns_dir , - 1 , paths . bind_gid )
# chmod needed to cope with umask
os . chmod ( dns_dir , 0770 )
except OSError :
if not os . environ . has_key ( ' SAMBA_SELFTEST ' ) :
logger . error ( " Failed to chown %s to bind gid %u " % (
dns_dir , paths . bind_gid ) )
def create_zone_file ( lp , logger , paths , targetdir , dnsdomain ,
hostip , hostip6 , hostname , realm , domainguid ,
ntdsguid , site ) :
""" Write out a DNS zone file, from the info in the current database.
: param paths : paths object
: param dnsdomain : DNS Domain name
: param domaindn : DN of the Domain
: param hostip : Local IPv4 IP
: param hostip6 : Local IPv6 IP
: param hostname : Local hostname
: param realm : Realm name
: param domainguid : GUID of the domain .
: param ntdsguid : GUID of the hosts nTDSDSA record .
"""
assert isinstance ( domainguid , str )
if hostip6 is not None :
hostip6_base_line = " IN AAAA " + hostip6
hostip6_host_line = hostname + " IN AAAA " + hostip6
gc_msdcs_ip6_line = " gc._msdcs IN AAAA " + hostip6
else :
hostip6_base_line = " "
hostip6_host_line = " "
gc_msdcs_ip6_line = " "
if hostip is not None :
hostip_base_line = " IN A " + hostip
hostip_host_line = hostname + " IN A " + hostip
gc_msdcs_ip_line = " gc._msdcs IN A " + hostip
else :
hostip_base_line = " "
hostip_host_line = " "
gc_msdcs_ip_line = " "
# we need to freeze the zone while we update the contents
if targetdir is None :
rndc = ' ' . join ( lp . get ( " rndc command " ) )
os . system ( rndc + " freeze " + lp . get ( " realm " ) )
setup_file ( setup_path ( " provision.zone " ) , paths . dns , {
" HOSTNAME " : hostname ,
" DNSDOMAIN " : dnsdomain ,
" REALM " : realm ,
" HOSTIP_BASE_LINE " : hostip_base_line ,
" HOSTIP_HOST_LINE " : hostip_host_line ,
" DOMAINGUID " : domainguid ,
" DATESTRING " : time . strftime ( " % Y % m %d % H " ) ,
" DEFAULTSITE " : site ,
" NTDSGUID " : ntdsguid ,
" HOSTIP6_BASE_LINE " : hostip6_base_line ,
" HOSTIP6_HOST_LINE " : hostip6_host_line ,
" GC_MSDCS_IP_LINE " : gc_msdcs_ip_line ,
" GC_MSDCS_IP6_LINE " : gc_msdcs_ip6_line ,
} )
if paths . bind_gid is not None :
try :
os . chown ( paths . dns , - 1 , paths . bind_gid )
# chmod needed to cope with umask
os . chmod ( paths . dns , 0664 )
except OSError :
if not os . environ . has_key ( ' SAMBA_SELFTEST ' ) :
logger . error ( " Failed to chown %s to bind gid %u " % (
paths . dns , paths . bind_gid ) )
if targetdir is None :
os . system ( rndc + " unfreeze " + lp . get ( " realm " ) )
2012-09-16 02:34:00 +04:00
2011-12-12 03:53:55 +04:00
def create_samdb_copy ( samdb , logger , paths , names , domainsid , domainguid ) :
2011-09-20 03:58:42 +04:00
""" Create a copy of samdb and give write permissions to named for dns partitions
"""
private_dir = paths . private_dir
samldb_dir = os . path . join ( private_dir , " sam.ldb.d " )
dns_dir = os . path . dirname ( paths . dns )
dns_samldb_dir = os . path . join ( dns_dir , " sam.ldb.d " )
2011-12-12 03:53:55 +04:00
# Find the partitions and corresponding filenames
partfile = { }
res = samdb . search ( base = " @PARTITION " , scope = ldb . SCOPE_BASE , attrs = [ " partition " ] )
for tmp in res [ 0 ] [ " partition " ] :
( nc , fname ) = tmp . split ( ' : ' )
partfile [ nc . upper ( ) ] = fname
# Create empty domain partition
domaindn = names . domaindn . upper ( )
domainpart_file = os . path . join ( dns_dir , partfile [ domaindn ] )
2011-09-20 03:58:42 +04:00
try :
os . mkdir ( dns_samldb_dir )
2011-12-12 03:53:55 +04:00
file ( domainpart_file , ' w ' ) . close ( )
# Fill the basedn and @OPTION records in domain partition
dom_ldb = samba . Ldb ( domainpart_file )
domainguid_line = " objectGUID: %s \n - " % domainguid
descr = b64encode ( get_domain_descriptor ( domainsid ) )
setup_add_ldif ( dom_ldb , setup_path ( " provision_basedn.ldif " ) , {
" DOMAINDN " : names . domaindn ,
" DOMAINGUID " : domainguid_line ,
" DOMAINSID " : str ( domainsid ) ,
" DESCRIPTOR " : descr } )
2012-09-16 02:34:00 +04:00
setup_add_ldif ( dom_ldb ,
setup_path ( " provision_basedn_options.ldif " ) , None )
2012-02-25 18:56:25 +04:00
except :
2012-09-16 02:34:00 +04:00
logger . error (
" Failed to setup database for BIND, AD based DNS cannot be used " )
2011-09-20 03:58:42 +04:00
raise
2014-08-27 07:09:22 +04:00
# This line is critical to the security of the whole scheme.
# We assume there is no secret data in the (to be left out of
# date and essentially read-only) config, schema and metadata partitions.
#
# Only the stub of the domain partition is created above.
#
# That way, things like the krbtgt key do not leak.
2011-12-12 03:53:55 +04:00
del partfile [ domaindn ]
2011-09-20 03:58:42 +04:00
2011-12-12 03:53:55 +04:00
# Link dns partitions and metadata
domainzonedn = " DC=DOMAINDNSZONES, %s " % names . domaindn . upper ( )
forestzonedn = " DC=FORESTDNSZONES, %s " % names . rootdn . upper ( )
2014-08-14 06:47:38 +04:00
2011-12-12 03:53:55 +04:00
domainzone_file = partfile [ domainzonedn ]
2014-08-14 06:47:38 +04:00
forestzone_file = partfile . get ( forestzonedn )
2011-12-12 03:53:55 +04:00
metadata_file = " metadata.tdb "
2011-09-20 03:58:42 +04:00
try :
os . link ( os . path . join ( samldb_dir , metadata_file ) ,
os . path . join ( dns_samldb_dir , metadata_file ) )
2011-12-12 03:53:55 +04:00
os . link ( os . path . join ( private_dir , domainzone_file ) ,
os . path . join ( dns_dir , domainzone_file ) )
2014-08-14 06:47:38 +04:00
if forestzone_file :
os . link ( os . path . join ( private_dir , forestzone_file ) ,
os . path . join ( dns_dir , forestzone_file ) )
2011-12-12 03:53:55 +04:00
except OSError :
2012-09-16 02:34:00 +04:00
logger . error (
" Failed to setup database for BIND, AD based DNS cannot be used " )
2011-12-12 03:53:55 +04:00
raise
del partfile [ domainzonedn ]
2014-08-14 06:47:38 +04:00
if forestzone_file :
del partfile [ forestzonedn ]
2011-12-12 03:53:55 +04:00
# Copy root, config, schema partitions (and any other if any)
# Since samdb is open in the current process, copy them in a child process
2011-09-20 03:58:42 +04:00
try :
2013-02-17 10:57:42 +04:00
tdb_copy ( os . path . join ( private_dir , " sam.ldb " ) ,
2011-12-12 03:53:55 +04:00
os . path . join ( dns_dir , " sam.ldb " ) )
for nc in partfile :
pfile = partfile [ nc ]
2013-02-17 10:57:42 +04:00
tdb_copy ( os . path . join ( private_dir , pfile ) ,
2011-12-12 03:53:55 +04:00
os . path . join ( dns_dir , pfile ) )
2012-02-25 18:56:25 +04:00
except :
2012-09-16 02:34:00 +04:00
logger . error (
" Failed to setup database for BIND, AD based DNS cannot be used " )
2011-09-20 03:58:42 +04:00
raise
# Give bind read/write permissions dns partitions
if paths . bind_gid is not None :
try :
os . chown ( samldb_dir , - 1 , paths . bind_gid )
os . chmod ( samldb_dir , 0750 )
2011-12-12 03:53:55 +04:00
for dirname , dirs , files in os . walk ( dns_dir ) :
for d in dirs :
dpath = os . path . join ( dirname , d )
os . chown ( dpath , - 1 , paths . bind_gid )
os . chmod ( dpath , 0770 )
for f in files :
if f . endswith ( ' .ldb ' ) or f . endswith ( ' .tdb ' ) :
fpath = os . path . join ( dirname , f )
os . chown ( fpath , - 1 , paths . bind_gid )
os . chmod ( fpath , 0660 )
2011-09-20 03:58:42 +04:00
except OSError :
if not os . environ . has_key ( ' SAMBA_SELFTEST ' ) :
2012-09-16 02:34:00 +04:00
logger . error (
" Failed to set permissions to sam.ldb* files, fix manually " )
2011-09-20 03:58:42 +04:00
else :
if not os . environ . has_key ( ' SAMBA_SELFTEST ' ) :
logger . warning ( """ Unable to find group id for BIND,
set permissions to sam . ldb * files manually """ )
2011-10-21 13:56:10 +04:00
def create_dns_update_list ( lp , logger , paths ) :
""" Write out a dns_update_list file """
# note that we use no variable substitution on this file
# the substitution is done at runtime by samba_dnsupdate, samba_spnupdate
setup_file ( setup_path ( " dns_update_list " ) , paths . dns_update_list , None )
setup_file ( setup_path ( " spn_update_list " ) , paths . spn_update_list , None )
2013-12-19 06:06:51 +04:00
def create_named_conf ( paths , realm , dnsdomain , dns_backend , logger ) :
2011-10-21 13:56:10 +04:00
""" Write out a file containing zone statements suitable for inclusion in a
named . conf file ( including GSS - TSIG configuration ) .
: param paths : all paths
: param realm : Realm name
: param dnsdomain : DNS Domain name
: param dns_backend : DNS backend type
: param keytab_name : File name of DNS keytab file
2013-12-19 06:06:51 +04:00
: param logger : Logger object
2011-10-21 13:56:10 +04:00
"""
2013-12-19 06:06:51 +04:00
# TODO: This really should have been done as a top level import.
# It is done here to avoid a depencency loop. That is, we move
# ProvisioningError to another file, and have all the provision
# scripts import it from there.
from samba . provision import ProvisioningError
2011-10-21 13:56:10 +04:00
if dns_backend == " BIND9_FLATFILE " :
setup_file ( setup_path ( " named.conf " ) , paths . namedconf , {
" DNSDOMAIN " : dnsdomain ,
" REALM " : realm ,
" ZONE_FILE " : paths . dns ,
" REALM_WC " : " *. " + " . " . join ( realm . split ( " . " ) [ 1 : ] ) ,
" NAMED_CONF " : paths . namedconf ,
" NAMED_CONF_UPDATE " : paths . namedconf_update
} )
setup_file ( setup_path ( " named.conf.update " ) , paths . namedconf_update )
elif dns_backend == " BIND9_DLZ " :
2013-12-19 06:06:51 +04:00
bind_info = subprocess . Popen ( [ ' named -V ' ] , shell = True ,
stdout = subprocess . PIPE ,
stderr = subprocess . STDOUT ,
cwd = ' . ' ) . communicate ( ) [ 0 ]
2014-10-20 09:40:05 +04:00
bind9_8 = ' # '
bind9_9 = ' # '
2013-12-19 06:06:51 +04:00
if bind_info . upper ( ) . find ( ' BIND 9.8 ' ) != - 1 :
2014-10-20 09:40:05 +04:00
bind9_8 = ' '
2013-12-19 06:06:51 +04:00
elif bind_info . upper ( ) . find ( ' BIND 9.9 ' ) != - 1 :
2014-10-20 09:40:05 +04:00
bind9_9 = ' '
2013-12-19 06:06:51 +04:00
elif bind_info . upper ( ) . find ( ' BIND 9.7 ' ) != - 1 :
raise ProvisioningError ( " DLZ option incompatible with BIND 9.7. " )
else :
logger . warning ( " BIND version unknown, please modify %s manually. " % paths . namedconf )
2011-10-21 13:56:10 +04:00
setup_file ( setup_path ( " named.conf.dlz " ) , paths . namedconf , {
" NAMED_CONF " : paths . namedconf ,
2012-04-05 10:51:24 +04:00
" MODULESDIR " : samba . param . modules_dir ( ) ,
2014-10-20 09:40:05 +04:00
" BIND9_8 " : bind9_8 ,
" BIND9_9 " : bind9_9
2011-10-21 13:56:10 +04:00
} )
def create_named_txt ( path , realm , dnsdomain , dnsname , private_dir ,
keytab_name ) :
""" Write out a file containing zone statements suitable for inclusion in a
named . conf file ( including GSS - TSIG configuration ) .
: param path : Path of the new named . conf file .
: param realm : Realm name
: param dnsdomain : DNS Domain name
: param private_dir : Path to private directory
: param keytab_name : File name of DNS keytab file
"""
setup_file ( setup_path ( " named.txt " ) , path , {
" DNSDOMAIN " : dnsdomain ,
" DNSNAME " : dnsname ,
" REALM " : realm ,
" DNS_KEYTAB " : keytab_name ,
" DNS_KEYTAB_ABS " : os . path . join ( private_dir , keytab_name ) ,
" PRIVATE_DIR " : private_dir
} )
2011-10-15 15:48:28 +04:00
def is_valid_dns_backend ( dns_backend ) :
2012-01-31 08:33:54 +04:00
return dns_backend in ( " BIND9_FLATFILE " , " BIND9_DLZ " , " SAMBA_INTERNAL " , " NONE " )
2011-10-15 15:48:28 +04:00
2011-10-15 15:52:57 +04:00
def is_valid_os_level ( os_level ) :
return DS_DOMAIN_FUNCTION_2000 < = os_level < = DS_DOMAIN_FUNCTION_2008_R2
2012-01-31 08:33:54 +04:00
def create_dns_legacy ( samdb , domainsid , forestdn , dnsadmins_sid ) :
# Set up MicrosoftDNS container
add_dns_container ( samdb , forestdn , " CN=System " , domainsid , dnsadmins_sid )
# Add root servers
add_rootservers ( samdb , forestdn , " CN=System " )
def fill_dns_data_legacy ( samdb , domainsid , forestdn , dnsdomain , site , hostname ,
2012-02-23 09:36:33 +04:00
hostip , hostip6 , dnsadmins_sid ) :
2012-01-31 08:33:54 +04:00
# Add domain record
add_domain_record ( samdb , forestdn , " CN=System " , dnsdomain , domainsid ,
dnsadmins_sid )
# Add DNS records for a DC in domain
add_dc_domain_records ( samdb , forestdn , " CN=System " , site , dnsdomain ,
hostname , hostip , hostip6 )
def create_dns_partitions ( samdb , domainsid , names , domaindn , forestdn ,
2013-09-09 03:54:23 +04:00
dnsadmins_sid , fill_level ) :
2012-01-31 08:33:54 +04:00
# Set up additional partitions (DomainDnsZones, ForstDnsZones)
setup_dns_partitions ( samdb , domainsid , domaindn , forestdn ,
2013-09-09 03:54:23 +04:00
names . configdn , names . serverdn , fill_level )
2012-01-31 08:33:54 +04:00
# Set up MicrosoftDNS containers
add_dns_container ( samdb , domaindn , " DC=DomainDnsZones " , domainsid ,
dnsadmins_sid )
2013-09-09 03:54:23 +04:00
if fill_level != FILL_SUBDOMAIN :
add_dns_container ( samdb , forestdn , " DC=ForestDnsZones " , domainsid ,
dnsadmins_sid , forest = True )
2012-01-31 08:33:54 +04:00
def fill_dns_data_partitions ( samdb , domainsid , site , domaindn , forestdn ,
2013-09-09 03:54:23 +04:00
dnsdomain , dnsforest , hostname , hostip , hostip6 ,
domainguid , ntdsguid , dnsadmins_sid , autofill = True ,
fill_level = FILL_FULL ) :
2012-01-31 08:33:54 +04:00
""" Fill data in various AD partitions
: param samdb : LDB object connected to sam . ldb file
: param domainsid : Domain SID ( as dom_sid object )
: param site : Site name to create hostnames in
: param domaindn : DN of the domain
: param forestdn : DN of the forest
: param dnsdomain : DNS name of the domain
: param dnsforest : DNS name of the forest
: param hostname : Host name of this DC
: param hostip : IPv4 addresses
: param hostip6 : IPv6 addresses
: param domainguid : Domain GUID
: param ntdsguid : NTDS GUID
: param dnsadmins_sid : SID for DnsAdmins group
: param autofill : Create DNS records ( using fixed template )
"""
##### Set up DC=DomainDnsZones,<DOMAINDN>
# Add rootserver records
add_rootservers ( samdb , domaindn , " DC=DomainDnsZones " )
# Add domain record
add_domain_record ( samdb , domaindn , " DC=DomainDnsZones " , dnsdomain ,
domainsid , dnsadmins_sid )
# Add DNS records for a DC in domain
if autofill :
add_dc_domain_records ( samdb , domaindn , " DC=DomainDnsZones " , site ,
dnsdomain , hostname , hostip , hostip6 )
2013-09-09 03:54:23 +04:00
if fill_level != FILL_SUBDOMAIN :
##### Set up DC=ForestDnsZones,<FORESTDN>
# Add _msdcs record
add_msdcs_record ( samdb , forestdn , " DC=ForestDnsZones " , dnsforest )
2012-01-31 08:33:54 +04:00
2013-09-09 03:54:23 +04:00
# Add DNS records for a DC in forest
if autofill :
add_dc_msdcs_records ( samdb , forestdn , " DC=ForestDnsZones " , site ,
dnsforest , hostname , hostip , hostip6 ,
domainguid , ntdsguid )
2012-01-31 08:33:54 +04:00
2014-08-08 10:43:47 +04:00
def setup_ad_dns ( samdb , secretsdb , names , paths , lp , logger ,
2014-06-10 17:35:47 +04:00
dns_backend , os_level , dnspass = None , hostip = None , hostip6 = None ,
2013-09-09 03:54:23 +04:00
targetdir = None , fill_level = FILL_FULL ) :
2011-09-05 10:19:02 +04:00
""" Provision DNS information (assuming GC role)
: param samdb : LDB object connected to sam . ldb file
2011-10-21 13:04:07 +04:00
: param secretsdb : LDB object connected to secrets . ldb file
2011-09-05 10:19:02 +04:00
: param names : Names shortcut
2011-10-21 13:04:07 +04:00
: param paths : Paths shortcut
2011-10-21 13:56:10 +04:00
: param lp : Loadparm object
2011-09-05 10:19:02 +04:00
: param logger : Logger object
2011-10-15 15:48:28 +04:00
: param dns_backend : Type of DNS backend
2011-10-15 15:52:57 +04:00
: param os_level : Functional level ( treated as os level )
2011-10-21 13:04:07 +04:00
: param dnspass : Password for bind ' s DNS account
2011-09-05 10:19:02 +04:00
: param hostip : IPv4 address
: param hostip6 : IPv6 address
2011-10-21 13:56:10 +04:00
: param targetdir : Target directory for creating DNS - related files for BIND9
2011-09-05 10:19:02 +04:00
"""
2011-10-15 15:48:28 +04:00
if not is_valid_dns_backend ( dns_backend ) :
raise Exception ( " Invalid dns backend: %r " % dns_backend )
2011-10-15 15:52:57 +04:00
if not is_valid_os_level ( os_level ) :
raise Exception ( " Invalid os level: %r " % os_level )
2012-10-11 19:11:44 +04:00
if dns_backend == " NONE " :
2011-10-15 15:48:28 +04:00
logger . info ( " No DNS backend set, not configuring DNS " )
return
2011-09-05 10:19:02 +04:00
2012-01-31 08:33:54 +04:00
# Add dns accounts (DnsAdmins, DnsUpdateProxy) in domain
logger . info ( " Adding DNS accounts " )
add_dns_accounts ( samdb , names . domaindn )
2011-10-15 14:17:14 +04:00
# If dns_backend is BIND9_FLATFILE
2013-10-09 11:37:52 +04:00
# Populate only CN=MicrosoftDNS,CN=System,<DOMAINDN>
2011-09-05 10:19:02 +04:00
#
2011-10-15 14:27:55 +04:00
# If dns_backend is SAMBA_INTERNAL or BIND9_DLZ
2011-09-05 10:19:02 +04:00
# Populate DNS partitions
# If os_level < 2003 (DS_DOMAIN_FUNCTION_2000)
2013-10-09 11:37:52 +04:00
# All dns records are in CN=MicrosoftDNS,CN=System,<DOMAINDN>
2011-09-05 10:19:02 +04:00
#
# If os_level >= 2003 (DS_DOMAIN_FUNCTION_2003, DS_DOMAIN_FUNCTION_2008,
# DS_DOMAIN_FUNCTION_2008_R2)
2013-10-09 11:37:52 +04:00
# Root server records are in CN=MicrosoftDNS,CN=System,<DOMAINDN>
# Domain records are in CN=MicrosoftDNS,CN=System,<DOMAINDN>
2011-09-05 10:19:02 +04:00
# Domain records are in CN=MicrosoftDNS,DC=DomainDnsZones,<DOMAINDN>
2011-12-08 10:34:57 +04:00
# Forest records are in CN=MicrosoftDNS,DC=ForestDnsZones,<FORESTDN>
2011-09-05 10:19:02 +04:00
domaindn = names . domaindn
forestdn = samdb . get_root_basedn ( ) . get_linearized ( )
dnsdomain = names . dnsdomain . lower ( )
dnsforest = dnsdomain
2014-06-10 17:35:47 +04:00
site = names . sitename
2011-09-05 10:19:02 +04:00
hostname = names . netbiosname . lower ( )
2012-01-31 08:33:54 +04:00
dnsadmins_sid = get_dnsadmins_sid ( samdb , domaindn )
2011-09-05 10:19:02 +04:00
domainguid = get_domainguid ( samdb , domaindn )
2012-01-31 08:33:54 +04:00
# Create CN=System
2013-10-09 11:37:52 +04:00
logger . info ( " Creating CN=MicrosoftDNS,CN=System, %s " % domaindn )
2014-08-08 10:43:47 +04:00
create_dns_legacy ( samdb , names . domainsid , domaindn , dnsadmins_sid )
2011-09-05 10:19:02 +04:00
if os_level == DS_DOMAIN_FUNCTION_2000 :
2012-01-31 08:33:54 +04:00
# Populating legacy dns
2013-10-09 11:37:52 +04:00
logger . info ( " Populating CN=MicrosoftDNS,CN=System, %s " % domaindn )
2014-08-08 10:43:47 +04:00
fill_dns_data_legacy ( samdb , names . domainsid , domaindn , dnsdomain , site ,
2012-02-23 09:36:33 +04:00
hostname , hostip , hostip6 , dnsadmins_sid )
2011-09-05 10:19:02 +04:00
2011-10-15 15:52:57 +04:00
elif dns_backend in ( " SAMBA_INTERNAL " , " BIND9_DLZ " ) and \
os_level > = DS_DOMAIN_FUNCTION_2003 :
2011-09-05 10:19:02 +04:00
2012-01-31 08:33:54 +04:00
# Create DNS partitions
2011-09-05 10:19:02 +04:00
logger . info ( " Creating DomainDnsZones and ForestDnsZones partitions " )
2014-08-08 10:43:47 +04:00
create_dns_partitions ( samdb , names . domainsid , names , domaindn , forestdn ,
2013-09-09 03:54:23 +04:00
dnsadmins_sid , fill_level )
2011-06-27 13:25:39 +04:00
2012-01-31 08:33:54 +04:00
# Populating dns partitions
logger . info ( " Populating DomainDnsZones and ForestDnsZones partitions " )
2014-08-08 10:43:47 +04:00
fill_dns_data_partitions ( samdb , names . domainsid , site , domaindn , forestdn ,
2013-09-09 03:54:23 +04:00
dnsdomain , dnsforest , hostname , hostip , hostip6 ,
domainguid , names . ntdsguid , dnsadmins_sid ,
fill_level = fill_level )
2011-10-21 13:04:07 +04:00
if dns_backend . startswith ( " BIND9_ " ) :
2014-08-08 10:43:47 +04:00
setup_bind9_dns ( samdb , secretsdb , names , paths , lp , logger ,
2013-09-09 03:54:23 +04:00
dns_backend , os_level , site = site , dnspass = dnspass , hostip = hostip ,
hostip6 = hostip6 , targetdir = targetdir )
2012-09-16 02:34:00 +04:00
2012-06-24 15:10:34 +04:00
2014-08-08 10:43:47 +04:00
def setup_bind9_dns ( samdb , secretsdb , names , paths , lp , logger ,
2012-09-16 02:34:00 +04:00
dns_backend , os_level , site = None , dnspass = None , hostip = None ,
2012-12-24 01:56:50 +04:00
hostip6 = None , targetdir = None , key_version_number = None ) :
2012-06-24 15:10:34 +04:00
""" Provision DNS information (assuming BIND9 backend in DC role)
: param samdb : LDB object connected to sam . ldb file
: param secretsdb : LDB object connected to secrets . ldb file
: param names : Names shortcut
: param paths : Paths shortcut
: param lp : Loadparm object
: param logger : Logger object
: param dns_backend : Type of DNS backend
: param os_level : Functional level ( treated as os level )
: param site : Site to create hostnames in
: param dnspass : Password for bind ' s DNS account
: param hostip : IPv4 address
: param hostip6 : IPv6 address
: param targetdir : Target directory for creating DNS - related files for BIND9
"""
2012-09-16 02:34:00 +04:00
if ( not is_valid_dns_backend ( dns_backend ) or
not dns_backend . startswith ( " BIND9_ " ) ) :
2012-06-24 15:10:34 +04:00
raise Exception ( " Invalid dns backend: %r " % dns_backend )
if not is_valid_os_level ( os_level ) :
raise Exception ( " Invalid os level: %r " % os_level )
domaindn = names . domaindn
domainguid = get_domainguid ( samdb , domaindn )
secretsdb_setup_dns ( secretsdb , names ,
paths . private_dir , realm = names . realm ,
dnsdomain = names . dnsdomain ,
2012-12-24 01:56:50 +04:00
dns_keytab_path = paths . dns_keytab , dnspass = dnspass ,
key_version_number = key_version_number )
2012-06-24 15:10:34 +04:00
create_dns_dir ( logger , paths )
if dns_backend == " BIND9_FLATFILE " :
create_zone_file ( lp , logger , paths , targetdir , site = site ,
2012-09-16 02:34:00 +04:00
dnsdomain = names . dnsdomain , hostip = hostip ,
hostip6 = hostip6 , hostname = names . hostname ,
realm = names . realm , domainguid = domainguid ,
ntdsguid = names . ntdsguid )
2012-06-24 15:10:34 +04:00
if dns_backend == " BIND9_DLZ " and os_level > = DS_DOMAIN_FUNCTION_2003 :
2014-08-08 10:43:47 +04:00
create_samdb_copy ( samdb , logger , paths , names , names . domainsid , domainguid )
2012-06-24 15:10:34 +04:00
create_named_conf ( paths , realm = names . realm ,
2013-12-19 06:06:51 +04:00
dnsdomain = names . dnsdomain , dns_backend = dns_backend ,
logger = logger )
2012-06-24 15:10:34 +04:00
create_named_txt ( paths . namedtxt ,
realm = names . realm , dnsdomain = names . dnsdomain ,
dnsname = " %s . %s " % ( names . hostname , names . dnsdomain ) ,
private_dir = paths . private_dir ,
keytab_name = paths . dns_keytab )
2012-09-16 02:34:00 +04:00
logger . info ( " See %s for an example configuration include file for BIND " ,
paths . namedconf )
2012-06-24 15:10:34 +04:00
logger . info ( " and %s for further documentation required for secure DNS "
" updates " , paths . namedtxt )