2010-08-23 05:31:48 +04:00
#!/usr/bin/env python
#
# python join code
# Copyright Andrew Tridgell 2010
# Copyright Andrew Bartlett 2010
#
# 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/>.
#
2010-11-28 16:09:30 +03:00
""" Joining a domain. """
2010-08-23 05:31:48 +04:00
from samba . auth import system_session
from samba . samdb import SamDB
2010-11-28 16:09:30 +03:00
from samba import gensec , Ldb , drs_utils
2010-11-05 06:09:49 +03:00
import ldb , samba , sys , os , uuid
2010-11-28 16:09:30 +03:00
from samba . ndr import ndr_pack
from samba . dcerpc import security , drsuapi , misc , nbt
2010-08-23 05:31:48 +04:00
from samba . credentials import Credentials , DONT_USE_KERBEROS
2010-08-24 09:42:54 +04:00
from samba . provision import secretsdb_self_join , provision , FILL_DRS , find_setup_dir
2010-11-05 06:09:49 +03:00
from samba . schema import Schema
2010-08-24 09:42:54 +04:00
from samba . net import Net
import logging
2010-11-05 05:00:45 +03:00
import talloc
2010-08-23 05:31:48 +04:00
2010-08-25 06:34:15 +04:00
# this makes debugging easier
2010-11-05 05:00:45 +03:00
talloc . enable_null_tracking ( )
2010-08-25 06:34:15 +04:00
2010-11-05 06:09:49 +03:00
class dc_join :
''' perform a DC join '''
def __init__ ( ctx , server = None , creds = None , lp = None , site = None , netbios_name = None ,
targetdir = None , domain = None ) :
ctx . creds = creds
ctx . lp = lp
ctx . site = site
ctx . netbios_name = netbios_name
ctx . targetdir = targetdir
ctx . creds . set_gensec_features ( creds . get_gensec_features ( ) | gensec . FEATURE_SEAL )
ctx . net = Net ( creds = ctx . creds , lp = ctx . lp )
if server is not None :
ctx . server = server
else :
print ( " Finding a writeable DC for domain ' %s ' " % domain )
ctx . server = ctx . find_dc ( domain )
print ( " Found DC %s " % ctx . server )
ctx . samdb = SamDB ( url = " ldap:// %s " % ctx . server ,
session_info = system_session ( ) ,
credentials = ctx . creds , lp = ctx . lp )
ctx . myname = netbios_name
ctx . samname = " %s $ " % ctx . myname
ctx . base_dn = str ( ctx . samdb . get_default_basedn ( ) )
ctx . root_dn = str ( ctx . samdb . get_root_basedn ( ) )
ctx . schema_dn = str ( ctx . samdb . get_schema_basedn ( ) )
ctx . config_dn = str ( ctx . samdb . get_config_basedn ( ) )
ctx . domsid = ctx . samdb . get_domain_sid ( )
ctx . domain_name = ctx . get_domain_name ( )
2010-11-07 05:55:20 +03:00
lp . set ( " workgroup " , ctx . domain_name )
print ( " workgroup is %s " % ctx . domain_name )
2010-11-05 06:09:49 +03:00
ctx . dc_ntds_dn = ctx . get_dsServiceName ( )
ctx . dc_dnsHostName = ctx . get_dnsHostName ( )
2010-11-07 05:55:20 +03:00
ctx . behavior_version = ctx . get_behavior_version ( )
2010-11-10 01:14:57 +03:00
ctx . acct_pass = samba . generate_random_password ( 32 , 40 )
2010-11-05 06:09:49 +03:00
# work out the DNs of all the objects we will be adding
ctx . server_dn = " CN= %s ,CN=Servers,CN= %s ,CN=Sites, %s " % ( ctx . myname , ctx . site , ctx . config_dn )
ctx . ntds_dn = " CN=NTDS Settings, %s " % ctx . server_dn
2010-11-07 05:55:20 +03:00
topology_base = " CN=Topology,CN=Domain System Volume,CN=DFSR-GlobalSettings,CN=System, %s " % ctx . base_dn
if ctx . dn_exists ( topology_base ) :
ctx . topology_dn = " CN= %s , %s " % ( ctx . myname , topology_base )
else :
ctx . topology_dn = None
2010-11-05 06:09:49 +03:00
ctx . dnsdomain = ldb . Dn ( ctx . samdb , ctx . base_dn ) . canonical_str ( ) . split ( ' / ' ) [ 0 ]
2010-11-07 05:55:20 +03:00
2010-11-05 06:09:49 +03:00
ctx . realm = ctx . dnsdomain
2010-11-07 05:55:20 +03:00
lp . set ( " realm " , ctx . realm )
print ( " realm is %s " % ctx . realm )
2010-11-06 06:35:30 +03:00
ctx . dnshostname = " %s . %s " % ( ctx . myname . lower ( ) , ctx . dnsdomain )
2010-11-05 06:09:49 +03:00
ctx . acct_dn = " CN= %s ,OU=Domain Controllers, %s " % ( ctx . myname , ctx . base_dn )
ctx . setup_dir = find_setup_dir ( )
ctx . tmp_samdb = None
ctx . SPNs = [ " HOST/ %s " % ctx . myname ,
2010-11-06 06:35:30 +03:00
" HOST/ %s " % ctx . dnshostname ,
" GC/ %s / %s " % ( ctx . dnshostname , ctx . dnsdomain ) ]
2010-11-05 06:09:49 +03:00
# these elements are optional
ctx . never_reveal_sid = None
ctx . reveal_sid = None
ctx . connection_dn = None
ctx . RODC = False
ctx . krbtgt_dn = None
ctx . drsuapi = None
ctx . managedby = None
def del_noerror ( ctx , dn , recursive = False ) :
if recursive :
try :
res = ctx . samdb . search ( base = dn , scope = ldb . SCOPE_ONELEVEL , attrs = [ " dn " ] )
except :
return
for r in res :
ctx . del_noerror ( r . dn , recursive = True )
2010-08-23 05:31:48 +04:00
try :
2010-11-05 06:09:49 +03:00
ctx . samdb . delete ( dn )
2010-08-23 05:31:48 +04:00
print " Deleted %s " % dn
except :
pass
2010-08-24 09:42:54 +04:00
def cleanup_old_join ( ctx ) :
''' remove any DNs from a previous join '''
2010-08-23 05:31:48 +04:00
try :
# find the krbtgt link
2010-11-05 06:09:49 +03:00
print ( " checking samaccountname " )
res = ctx . samdb . search ( base = ctx . samdb . get_default_basedn ( ) ,
expression = ' samAccountName= %s ' % ctx . samname ,
attrs = [ " msDS-krbTgtLink " ] )
if res :
ctx . del_noerror ( res [ 0 ] . dn , recursive = True )
if ctx . connection_dn is not None :
ctx . del_noerror ( ctx . connection_dn )
if ctx . krbtgt_dn is not None :
ctx . del_noerror ( ctx . krbtgt_dn )
ctx . del_noerror ( ctx . ntds_dn )
ctx . del_noerror ( ctx . server_dn , recursive = True )
2010-11-07 05:55:20 +03:00
if ctx . topology_dn :
ctx . del_noerror ( ctx . topology_dn )
2010-11-05 06:09:49 +03:00
if res :
ctx . new_krbtgt_dn = res [ 0 ] [ " msDS-Krbtgtlink " ] [ 0 ]
ctx . del_noerror ( ctx . new_krbtgt_dn )
2010-08-23 05:31:48 +04:00
except :
pass
2010-09-14 12:22:13 +04:00
def find_dc ( ctx , domain ) :
''' find a writeable DC for the given domain '''
2010-11-05 06:09:49 +03:00
try :
ctx . cldap_ret = ctx . net . finddc ( domain , nbt . NBT_SERVER_LDAP | nbt . NBT_SERVER_DS | nbt . NBT_SERVER_WRITABLE )
except Exception , reason :
print ( " Failed to find a writeable DC for domain ' %s ' : %s " % ( domain , reason ) )
sys . exit ( 1 )
2010-09-20 00:20:33 +04:00
if ctx . cldap_ret . client_site is not None and ctx . cldap_ret . client_site != " " :
ctx . site = ctx . cldap_ret . client_site
2010-09-29 05:31:02 +04:00
return ctx . cldap_ret . pdc_dns_name
2010-09-14 12:22:13 +04:00
2010-11-05 06:09:49 +03:00
def get_dsServiceName ( ctx ) :
res = ctx . samdb . search ( base = " " , scope = ldb . SCOPE_BASE , attrs = [ " dsServiceName " ] )
2010-08-23 05:31:48 +04:00
return res [ 0 ] [ " dsServiceName " ] [ 0 ]
2010-11-07 05:55:20 +03:00
def get_behavior_version ( ctx ) :
res = ctx . samdb . search ( base = ctx . base_dn , scope = ldb . SCOPE_BASE , attrs = [ " msDS-Behavior-Version " ] )
if " msDS-Behavior-Version " in res [ 0 ] :
return int ( res [ 0 ] [ " msDS-Behavior-Version " ] [ 0 ] )
else :
return samba . dsdb . DS_DOMAIN_FUNCTION_2000
2010-11-05 06:09:49 +03:00
def get_dnsHostName ( ctx ) :
res = ctx . samdb . search ( base = " " , scope = ldb . SCOPE_BASE , attrs = [ " dnsHostName " ] )
2010-08-23 05:31:48 +04:00
return res [ 0 ] [ " dnsHostName " ] [ 0 ]
2010-11-05 06:09:49 +03:00
def get_domain_name ( ctx ) :
2010-09-09 12:02:08 +04:00
''' get netbios name of the domain from the partitions record '''
2010-11-05 06:09:49 +03:00
partitions_dn = ctx . samdb . get_partitions_dn ( )
res = ctx . samdb . search ( base = partitions_dn , scope = ldb . SCOPE_ONELEVEL , attrs = [ " nETBIOSName " ] ,
expression = ' ncName= %s ' % ctx . samdb . get_default_basedn ( ) )
2010-09-09 12:02:08 +04:00
return res [ 0 ] [ " nETBIOSName " ] [ 0 ]
2010-11-05 06:09:49 +03:00
def get_mysid ( ctx ) :
2010-11-07 05:55:20 +03:00
''' get the SID of the connected user. Only works with w2k8 and later,
so only used for RODC join '''
2010-11-05 06:09:49 +03:00
res = ctx . samdb . search ( base = " " , scope = ldb . SCOPE_BASE , attrs = [ " tokenGroups " ] )
2010-08-23 05:31:48 +04:00
binsid = res [ 0 ] [ " tokenGroups " ] [ 0 ]
2010-11-05 06:09:49 +03:00
return ctx . samdb . schema_format_value ( " objectSID " , binsid )
2010-08-24 17:37:25 +04:00
2010-11-07 05:55:20 +03:00
def dn_exists ( ctx , dn ) :
''' check if a DN exists '''
try :
res = ctx . samdb . search ( base = dn , scope = ldb . SCOPE_BASE , attrs = [ ] )
except ldb . LdbError , ( ERR_NO_SUCH_OBJECT , _ ) :
return False
return True
2010-11-05 06:09:49 +03:00
def add_krbtgt_account ( ctx ) :
''' RODCs need a special krbtgt account '''
2010-08-24 17:37:25 +04:00
print " Adding %s " % ctx . krbtgt_dn
rec = {
" dn " : ctx . krbtgt_dn ,
" objectclass " : " user " ,
" useraccountcontrol " : str ( samba . dsdb . UF_NORMAL_ACCOUNT |
samba . dsdb . UF_ACCOUNTDISABLE ) ,
" showinadvancedviewonly " : " TRUE " ,
2010-09-30 23:44:39 +04:00
" description " : " krbtgt for %s " % ctx . samname }
2010-08-24 17:37:25 +04:00
ctx . samdb . add ( rec , [ " rodc_join:1:1 " ] )
# now we need to search for the samAccountName attribute on the krbtgt DN,
# as this will have been magically set to the krbtgt number
res = ctx . samdb . search ( base = ctx . krbtgt_dn , scope = ldb . SCOPE_BASE , attrs = [ " samAccountName " ] )
ctx . krbtgt_name = res [ 0 ] [ " samAccountName " ] [ 0 ]
print " Got krbtgt_name= %s " % ctx . krbtgt_name
m = ldb . Message ( )
m . dn = ldb . Dn ( ctx . samdb , ctx . acct_dn )
m [ " msDS-krbTgtLink " ] = ldb . MessageElement ( ctx . krbtgt_dn ,
ldb . FLAG_MOD_REPLACE , " msDS-krbTgtLink " )
ctx . samdb . modify ( m )
ctx . new_krbtgt_dn = " CN= %s ,CN=Users, %s " % ( ctx . krbtgt_name , ctx . base_dn )
print " Renaming %s to %s " % ( ctx . krbtgt_dn , ctx . new_krbtgt_dn )
ctx . samdb . rename ( ctx . krbtgt_dn , ctx . new_krbtgt_dn )
2010-11-05 06:09:49 +03:00
def drsuapi_connect ( ctx ) :
''' make a DRSUAPI connection to the server '''
2010-11-17 03:08:59 +03:00
binding_options = " seal "
if ctx . lp . get ( " log level " ) > = 5 :
binding_options + = " ,print "
binding_string = " ncacn_ip_tcp: %s [ %s ] " % ( ctx . server , binding_options )
2010-11-05 06:09:49 +03:00
ctx . drsuapi = drsuapi . drsuapi ( binding_string , ctx . lp , ctx . creds )
2010-11-07 05:55:20 +03:00
( ctx . drsuapi_handle , ctx . bind_supported_extensions ) = drs_utils . drs_DsBind ( ctx . drsuapi )
2010-11-05 06:09:49 +03:00
def create_tmp_samdb ( ctx ) :
''' create a temporary samdb object for schema queries '''
def setup_path ( file ) :
return os . path . join ( ctx . setup_dir , file )
ctx . tmp_schema = Schema ( setup_path , security . dom_sid ( ctx . domsid ) ,
schemadn = ctx . schema_dn )
ctx . tmp_samdb = SamDB ( session_info = system_session ( ) , url = None , auto_connect = False ,
credentials = ctx . creds , lp = ctx . lp , global_schema = False ,
am_rodc = False )
ctx . tmp_samdb . set_schema ( ctx . tmp_schema )
def build_DsReplicaAttribute ( ctx , attrname , attrvalue ) :
''' build a DsReplicaAttributeCtr object '''
r = drsuapi . DsReplicaAttribute ( )
r . attid = ctx . tmp_samdb . get_attid_from_lDAPDisplayName ( attrname )
r . value_ctr = 1
def DsAddEntry ( ctx , rec ) :
''' add a record via the DRSUAPI DsAddEntry call '''
if ctx . drsuapi is None :
ctx . drsuapi_connect ( )
if ctx . tmp_samdb is None :
ctx . create_tmp_samdb ( )
id = drsuapi . DsReplicaObjectIdentifier ( )
id . dn = rec [ ' dn ' ]
attrs = [ ]
for a in rec :
if a == ' dn ' :
continue
if not isinstance ( rec [ a ] , list ) :
v = [ rec [ a ] ]
else :
v = rec [ a ]
rattr = ctx . tmp_samdb . dsdb_DsReplicaAttribute ( ctx . tmp_samdb , a , v )
attrs . append ( rattr )
attribute_ctr = drsuapi . DsReplicaAttributeCtr ( )
attribute_ctr . num_attributes = len ( attrs )
attribute_ctr . attributes = attrs
object = drsuapi . DsReplicaObject ( )
object . identifier = id
object . attribute_ctr = attribute_ctr
first_object = drsuapi . DsReplicaObjectListItem ( )
first_object . object = object
req2 = drsuapi . DsAddEntryRequest2 ( )
req2 . first_object = first_object
( level , ctr ) = ctx . drsuapi . DsAddEntry ( ctx . drsuapi_handle , 2 , req2 )
2010-11-17 03:09:59 +03:00
if ctr . err_ver != 1 :
raise RuntimeError ( " expected err_ver 1, got %u " % ctr . err_ver )
if ctr . err_data . status != ( 0 , ' WERR_OK ' ) :
print ( " DsAddEntry failed with status %s info %s " % ( ctr . err_data . status ,
ctr . err_data . info . extended_err ) )
raise RuntimeError ( " DsAddEntry failed " )
2010-11-05 06:09:49 +03:00
def join_add_objects ( ctx ) :
''' add the various objects needed for the join '''
print " Adding %s " % ctx . acct_dn
rec = {
" dn " : ctx . acct_dn ,
" objectClass " : " computer " ,
" displayname " : ctx . samname ,
" samaccountname " : ctx . samname ,
2010-11-18 10:48:03 +03:00
" userAccountControl " : str ( ctx . userAccountControl | samba . dsdb . UF_ACCOUNTDISABLE ) ,
2010-11-07 05:55:20 +03:00
" dnshostname " : ctx . dnshostname }
2010-11-15 23:41:54 +03:00
if ctx . behavior_version > = samba . dsdb . DS_DOMAIN_FUNCTION_2008 :
2010-11-07 05:55:20 +03:00
rec [ ' msDS-SupportedEncryptionTypes ' ] = str ( samba . dsdb . ENC_ALL_TYPES )
2010-11-05 06:09:49 +03:00
if ctx . managedby :
rec [ " managedby " ] = ctx . managedby
if ctx . never_reveal_sid :
rec [ " msDS-NeverRevealGroup " ] = ctx . never_reveal_sid
if ctx . reveal_sid :
rec [ " msDS-RevealOnDemandGroup " ] = ctx . reveal_sid
ctx . samdb . add ( rec )
if ctx . krbtgt_dn :
ctx . add_krbtgt_account ( )
2010-08-24 17:37:25 +04:00
print " Adding %s " % ctx . server_dn
rec = {
" dn " : ctx . server_dn ,
" objectclass " : " server " ,
" systemFlags " : str ( samba . dsdb . SYSTEM_FLAG_CONFIG_ALLOW_RENAME |
samba . dsdb . SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE |
samba . dsdb . SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE ) ,
" serverReference " : ctx . acct_dn ,
" dnsHostName " : ctx . dnshostname }
ctx . samdb . add ( rec )
2010-09-17 01:24:02 +04:00
# FIXME: the partition (NC) assignment has to be made dynamic
2010-08-24 17:37:25 +04:00
print " Adding %s " % ctx . ntds_dn
rec = {
" dn " : ctx . ntds_dn ,
" objectclass " : " nTDSDSA " ,
" systemFlags " : str ( samba . dsdb . SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE ) ,
2010-11-07 05:55:20 +03:00
" dMDLocation " : ctx . schema_dn }
2010-11-17 03:10:45 +03:00
if ctx . behavior_version > = samba . dsdb . DS_DOMAIN_FUNCTION_2003 :
2010-11-07 05:55:20 +03:00
rec [ " msDS-Behavior-Version " ] = str ( ctx . behavior_version )
2010-11-15 23:41:54 +03:00
if ctx . behavior_version > = samba . dsdb . DS_DOMAIN_FUNCTION_2003 :
2010-11-07 05:55:20 +03:00
rec [ " msDS-HasDomainNCs " ] = ctx . base_dn
2010-11-05 06:09:49 +03:00
if ctx . RODC :
rec [ " objectCategory " ] = " CN=NTDS-DSA-RO, %s " % ctx . schema_dn
rec [ " msDS-HasFullReplicaNCs " ] = [ ctx . base_dn , ctx . config_dn , ctx . schema_dn ]
rec [ " options " ] = " 37 "
ctx . samdb . add ( rec , [ " rodc_join:1:1 " ] )
else :
rec [ " objectCategory " ] = " CN=NTDS-DSA, %s " % ctx . schema_dn
rec [ " HasMasterNCs " ] = [ ctx . base_dn , ctx . config_dn , ctx . schema_dn ]
2010-11-07 05:55:20 +03:00
if ctx . behavior_version > = samba . dsdb . DS_DOMAIN_FUNCTION_2003 :
rec [ " msDS-HasMasterNCs " ] = [ ctx . base_dn , ctx . config_dn , ctx . schema_dn ]
2010-11-05 06:09:49 +03:00
rec [ " options " ] = " 1 "
2010-11-06 06:35:30 +03:00
rec [ " invocationId " ] = ndr_pack ( misc . GUID ( str ( uuid . uuid4 ( ) ) ) )
2010-11-05 06:09:49 +03:00
ctx . DsAddEntry ( rec )
2010-08-24 17:37:25 +04:00
# find the GUID of our NTDS DN
res = ctx . samdb . search ( base = ctx . ntds_dn , scope = ldb . SCOPE_BASE , attrs = [ " objectGUID " ] )
ctx . ntds_guid = misc . GUID ( ctx . samdb . schema_format_value ( " objectGUID " , res [ 0 ] [ " objectGUID " ] [ 0 ] ) )
2010-11-05 06:09:49 +03:00
if ctx . connection_dn is not None :
print " Adding %s " % ctx . connection_dn
rec = {
" dn " : ctx . connection_dn ,
" objectclass " : " nTDSConnection " ,
" enabledconnection " : " TRUE " ,
" options " : " 65 " ,
" fromServer " : ctx . dc_ntds_dn }
ctx . samdb . add ( rec )
2010-08-24 17:37:25 +04:00
2010-11-07 05:55:20 +03:00
if ctx . topology_dn :
print " Adding %s " % ctx . topology_dn
rec = {
" dn " : ctx . topology_dn ,
" objectclass " : " msDFSR-Member " ,
" msDFSR-ComputerReference " : ctx . acct_dn ,
" serverReference " : ctx . ntds_dn }
ctx . samdb . add ( rec )
2010-08-24 17:37:25 +04:00
2010-11-05 06:09:49 +03:00
print " Adding SPNs to %s " % ctx . acct_dn
2010-08-24 17:37:25 +04:00
m = ldb . Message ( )
m . dn = ldb . Dn ( ctx . samdb , ctx . acct_dn )
2010-11-05 06:09:49 +03:00
for i in range ( len ( ctx . SPNs ) ) :
ctx . SPNs [ i ] = ctx . SPNs [ i ] . replace ( " $NTDSGUID " , str ( ctx . ntds_guid ) )
m [ " servicePrincipalName " ] = ldb . MessageElement ( ctx . SPNs ,
2010-08-24 17:37:25 +04:00
ldb . FLAG_MOD_ADD ,
" servicePrincipalName " )
ctx . samdb . modify ( m )
print " Setting account password for %s " % ctx . samname
ctx . samdb . setpassword ( " (&(objectClass=user)(sAMAccountName= %s )) " % ctx . samname ,
ctx . acct_pass ,
force_change_at_next_login = False ,
username = ctx . samname )
2010-09-30 23:44:39 +04:00
res = ctx . samdb . search ( base = ctx . acct_dn , scope = ldb . SCOPE_BASE , attrs = [ " msDS-keyVersionNumber " ] )
2010-11-07 05:55:20 +03:00
ctx . key_version_number = int ( res [ 0 ] [ " msDS-keyVersionNumber " ] [ 0 ] )
2010-08-24 17:37:25 +04:00
2010-11-18 10:48:03 +03:00
print ( " Enabling account " )
m = ldb . Message ( )
m . dn = ldb . Dn ( ctx . samdb , ctx . acct_dn )
m [ " userAccountControl " ] = ldb . MessageElement ( str ( ctx . userAccountControl ) ,
ldb . FLAG_MOD_REPLACE ,
" userAccountControl " )
ctx . samdb . modify ( m )
2010-08-24 17:37:25 +04:00
def join_provision ( ctx ) :
''' provision the local SAM '''
print " Calling bare provision "
logger = logging . getLogger ( " provision " )
logger . addHandler ( logging . StreamHandler ( sys . stdout ) )
2010-11-05 06:09:49 +03:00
smbconf = ctx . lp . configfile
2010-08-24 17:37:25 +04:00
2010-11-05 06:09:49 +03:00
presult = provision ( ctx . setup_dir , logger , system_session ( ) , None ,
smbconf = smbconf , targetdir = ctx . targetdir , samdb_fill = FILL_DRS ,
2010-08-24 17:37:25 +04:00
realm = ctx . realm , rootdn = ctx . root_dn , domaindn = ctx . base_dn ,
schemadn = ctx . schema_dn ,
configdn = ctx . config_dn ,
serverdn = ctx . server_dn , domain = ctx . domain_name ,
2010-11-07 05:55:20 +03:00
hostname = ctx . myname , domainsid = ctx . domsid ,
2010-08-24 17:37:25 +04:00
machinepass = ctx . acct_pass , serverrole = " domain controller " ,
2010-11-11 02:45:13 +03:00
sitename = ctx . site , lp = ctx . lp )
2010-08-24 17:37:25 +04:00
print " Provision OK for domain DN %s " % presult . domaindn
ctx . local_samdb = presult . samdb
ctx . lp = presult . lp
2010-08-25 06:34:15 +04:00
ctx . paths = presult . paths
2010-08-24 17:37:25 +04:00
def join_replicate ( ctx ) :
''' replicate the SAM '''
print " Starting replication "
ctx . local_samdb . transaction_start ( )
2010-08-26 08:35:30 +04:00
source_dsa_invocation_id = misc . GUID ( ctx . samdb . get_invocation_id ( ) )
2010-11-07 05:55:20 +03:00
destination_dsa_guid = ctx . ntds_guid
2010-08-26 08:35:30 +04:00
2010-11-07 05:55:20 +03:00
if ctx . RODC :
repl_creds = Credentials ( )
repl_creds . guess ( ctx . lp )
repl_creds . set_kerberos_state ( DONT_USE_KERBEROS )
repl_creds . set_username ( ctx . samname )
repl_creds . set_password ( ctx . acct_pass )
else :
repl_creds = ctx . creds
2010-08-26 08:35:30 +04:00
2010-11-17 03:08:59 +03:00
binding_options = " seal "
if ctx . lp . get ( " debug level " ) > = 5 :
binding_options + = " ,print "
repl = drs_utils . drs_Replicate ( " ncacn_ip_tcp: %s [ %s ] " % ( ctx . server , binding_options ) ,
ctx . lp , repl_creds , ctx . local_samdb )
2010-08-24 17:37:25 +04:00
2010-11-07 05:55:20 +03:00
repl . replicate ( ctx . schema_dn , source_dsa_invocation_id , destination_dsa_guid ,
schema = True , rodc = ctx . RODC ,
replica_flags = ctx . replica_flags )
repl . replicate ( ctx . config_dn , source_dsa_invocation_id , destination_dsa_guid ,
rodc = ctx . RODC , replica_flags = ctx . replica_flags )
repl . replicate ( ctx . base_dn , source_dsa_invocation_id , destination_dsa_guid ,
rodc = ctx . RODC , replica_flags = ctx . replica_flags )
2010-11-05 06:09:49 +03:00
if ctx . RODC :
2010-11-07 05:55:20 +03:00
repl . replicate ( ctx . acct_dn , source_dsa_invocation_id , destination_dsa_guid ,
exop = drsuapi . DRSUAPI_EXOP_REPL_SECRET , rodc = True )
repl . replicate ( ctx . new_krbtgt_dn , source_dsa_invocation_id , destination_dsa_guid ,
exop = drsuapi . DRSUAPI_EXOP_REPL_SECRET , rodc = True )
2010-08-24 17:37:25 +04:00
print " Committing SAM database "
ctx . local_samdb . transaction_commit ( )
2010-08-25 06:34:15 +04:00
def join_finalise ( ctx ) :
''' finalise the join, mark us synchronised and setup secrets db '''
print " Setting isSynchronized "
m = ldb . Message ( )
m . dn = ldb . Dn ( ctx . samdb , ' @ROOTDSE ' )
m [ " isSynchronized " ] = ldb . MessageElement ( " TRUE " , ldb . FLAG_MOD_REPLACE , " isSynchronized " )
ctx . samdb . modify ( m )
secrets_ldb = Ldb ( ctx . paths . secrets , session_info = system_session ( ) , lp = ctx . lp )
print " Setting up secrets database "
secretsdb_self_join ( secrets_ldb , domain = ctx . domain_name ,
realm = ctx . realm ,
dnsdomain = ctx . dnsdomain ,
netbiosname = ctx . myname ,
domainsid = security . dom_sid ( ctx . domsid ) ,
machinepass = ctx . acct_pass ,
2010-11-05 11:09:45 +03:00
secure_channel_type = ctx . secure_channel_type ,
2010-09-30 23:44:39 +04:00
key_version_number = ctx . key_version_number )
2010-08-25 06:34:15 +04:00
2010-11-05 06:09:49 +03:00
def do_join ( ctx ) :
ctx . cleanup_old_join ( )
try :
ctx . join_add_objects ( )
ctx . join_provision ( )
ctx . join_replicate ( )
ctx . join_finalise ( )
except :
print " Join failed - cleaning up "
ctx . cleanup_old_join ( )
raise
2010-08-25 06:34:15 +04:00
2010-11-05 06:09:49 +03:00
def join_RODC ( server = None , creds = None , lp = None , site = None , netbios_name = None ,
targetdir = None , domain = None ) :
""" join as a RODC """
2010-09-15 12:52:11 +04:00
2010-11-05 06:09:49 +03:00
ctx = dc_join ( server , creds , lp , site , netbios_name , targetdir , domain )
2010-08-23 05:31:48 +04:00
2010-08-24 09:42:54 +04:00
ctx . krbtgt_dn = " CN=krbtgt_ %s ,CN=Users, %s " % ( ctx . myname , ctx . base_dn )
2010-08-23 05:31:48 +04:00
2010-08-24 17:37:25 +04:00
# setup some defaults for accounts that should be replicated to this RODC
ctx . never_reveal_sid = [ " <SID= %s - %s > " % ( ctx . domsid , security . DOMAIN_RID_RODC_DENY ) ,
" <SID= %s > " % security . SID_BUILTIN_ADMINISTRATORS ,
" <SID= %s > " % security . SID_BUILTIN_SERVER_OPERATORS ,
" <SID= %s > " % security . SID_BUILTIN_BACKUP_OPERATORS ,
" <SID= %s > " % security . SID_BUILTIN_ACCOUNT_OPERATORS ]
2010-08-25 06:34:15 +04:00
ctx . reveal_sid = " <SID= %s - %s > " % ( ctx . domsid , security . DOMAIN_RID_RODC_ALLOW )
2010-08-23 05:31:48 +04:00
2010-11-07 05:55:20 +03:00
mysid = ctx . get_mysid ( )
admin_dn = " <SID= %s > " % mysid
ctx . managedby = admin_dn
2010-08-23 05:31:48 +04:00
2010-11-05 06:09:49 +03:00
ctx . userAccountControl = ( samba . dsdb . UF_WORKSTATION_TRUST_ACCOUNT |
samba . dsdb . UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION |
samba . dsdb . UF_PARTIAL_SECRETS_ACCOUNT )
2010-08-23 05:31:48 +04:00
2010-11-05 06:09:49 +03:00
ctx . SPNs . extend ( [ " RestrictedKrbHost/ %s " % ctx . myname ,
" RestrictedKrbHost/ %s " % ctx . dnshostname ] )
2010-08-24 17:37:25 +04:00
2010-11-05 06:09:49 +03:00
ctx . connection_dn = " CN=RODC Connection (FRS), %s " % ctx . ntds_dn
2010-11-05 11:09:45 +03:00
ctx . secure_channel_type = misc . SEC_CHAN_RODC
2010-11-05 06:09:49 +03:00
ctx . RODC = True
2010-11-07 05:55:20 +03:00
ctx . replica_flags = ( drsuapi . DRSUAPI_DRS_INIT_SYNC |
drsuapi . DRSUAPI_DRS_PER_SYNC |
drsuapi . DRSUAPI_DRS_GET_ANC |
drsuapi . DRSUAPI_DRS_NEVER_SYNCED |
2010-11-18 10:48:42 +03:00
drsuapi . DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING |
drsuapi . DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP )
2010-11-05 06:09:49 +03:00
ctx . do_join ( )
2010-11-07 05:55:20 +03:00
2010-08-24 17:37:25 +04:00
print " Joined domain %s (SID %s ) as an RODC " % ( ctx . domain_name , ctx . domsid )
2010-08-23 05:31:48 +04:00
2010-11-05 06:09:49 +03:00
def join_DC ( server = None , creds = None , lp = None , site = None , netbios_name = None ,
targetdir = None , domain = None ) :
""" join as a DC """
ctx = dc_join ( server , creds , lp , site , netbios_name , targetdir , domain )
ctx . userAccountControl = samba . dsdb . UF_SERVER_TRUST_ACCOUNT | samba . dsdb . UF_TRUSTED_FOR_DELEGATION
ctx . SPNs . append ( ' E3514235-4B06-11D1-AB04-00C04FC2DCD2/$NTDSGUID/ %s ' % ctx . dnsdomain )
2010-11-05 11:09:45 +03:00
ctx . secure_channel_type = misc . SEC_CHAN_BDC
2010-11-05 06:09:49 +03:00
2010-11-07 05:55:20 +03:00
ctx . replica_flags = ( drsuapi . DRSUAPI_DRS_WRIT_REP |
drsuapi . DRSUAPI_DRS_INIT_SYNC |
drsuapi . DRSUAPI_DRS_PER_SYNC |
drsuapi . DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS |
drsuapi . DRSUAPI_DRS_NEVER_SYNCED )
2010-11-05 06:09:49 +03:00
ctx . do_join ( )
2010-11-07 05:55:20 +03:00
print " Joined domain %s (SID %s ) as a DC " % ( ctx . domain_name , ctx . domsid )