2010-11-27 15:48:20 +03:00
# implement samba_tool drs commands
#
# Copyright Andrew Tridgell 2010
#
2010-11-28 02:41:53 +03:00
# based on C implementation by Kamen Mazdrashki <kamen.mazdrashki@postpath.com>
#
2010-11-27 15:48:20 +03: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/>.
#
import samba . getopt as options
import ldb
2015-08-17 06:33:31 +03:00
import logging
2010-11-27 15:48:20 +03:00
from samba . auth import system_session
from samba . netcmd import (
Command ,
CommandError ,
Option ,
SuperCommand ,
)
from samba . samdb import SamDB
from samba import drs_utils , nttime2string , dsdb
from samba . dcerpc import drsuapi , misc
2010-12-08 00:20:54 +03:00
import common
2015-08-17 06:33:31 +03:00
from samba . join import join_clone
2010-11-27 15:48:20 +03:00
def drsuapi_connect ( ctx ) :
''' make a DRSUAPI connection to the server '''
try :
2011-11-28 23:48:59 +04:00
( ctx . drsuapi , ctx . drsuapi_handle , ctx . bind_supported_extensions ) = drs_utils . drsuapi_connect ( ctx . server , ctx . lp , ctx . creds )
2010-11-29 06:15:57 +03:00
except Exception , e :
raise CommandError ( " DRS connection to %s failed " % ctx . server , e )
2010-11-27 15:48:20 +03:00
def samdb_connect ( ctx ) :
''' make a ldap connection to the server '''
try :
ctx . samdb = SamDB ( url = " ldap:// %s " % ctx . server ,
session_info = system_session ( ) ,
credentials = ctx . creds , lp = ctx . lp )
2010-11-29 06:15:57 +03:00
except Exception , e :
raise CommandError ( " LDAP connection to %s failed " % ctx . server , e )
2010-11-27 15:48:20 +03:00
def drs_errmsg ( werr ) :
''' return " was successful " or an error string '''
( ecode , estring ) = werr
if ecode == 0 :
return " was successful "
return " failed, result %u ( %s ) " % ( ecode , estring )
2011-09-02 21:56:51 +04:00
2010-11-27 15:48:20 +03:00
def attr_default ( msg , attrname , default ) :
''' get an attribute from a ldap msg with a default '''
if attrname in msg :
return msg [ attrname ] [ 0 ]
return default
2011-09-02 21:56:51 +04:00
2010-11-27 15:48:20 +03:00
def drs_parse_ntds_dn ( ntds_dn ) :
''' parse a NTDS DN returning a site and server '''
a = ntds_dn . split ( ' , ' )
if a [ 0 ] != " CN=NTDS Settings " or a [ 2 ] != " CN=Servers " or a [ 4 ] != ' CN=Sites ' :
raise RuntimeError ( " bad NTDS DN %s " % ntds_dn )
server = a [ 1 ] . split ( ' = ' ) [ 1 ]
site = a [ 3 ] . split ( ' = ' ) [ 1 ]
return ( site , server )
2011-09-02 21:56:51 +04:00
2011-02-07 15:13:06 +03:00
2011-09-02 21:56:51 +04:00
2010-11-27 15:48:20 +03:00
class cmd_drs_showrepl ( Command ) :
2012-10-08 14:32:58 +04:00
""" Show replication status. """
2010-11-27 15:48:20 +03:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog [<DC>] [options] "
2010-11-27 15:48:20 +03:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2010-12-08 00:20:54 +03:00
takes_args = [ " DC? " ]
2010-11-27 15:48:20 +03:00
def print_neighbour ( self , n ) :
''' print one set of neighbour information '''
2011-02-09 04:00:06 +03:00
self . message ( " %s " % n . naming_context_dn )
2010-12-01 08:40:17 +03:00
try :
( site , server ) = drs_parse_ntds_dn ( n . source_dsa_obj_dn )
2011-02-09 04:00:06 +03:00
self . message ( " \t %s \ %s via RPC " % ( site , server ) )
2010-12-01 08:40:17 +03:00
except RuntimeError :
2011-02-09 04:00:06 +03:00
self . message ( " \t NTDS DN: %s " % n . source_dsa_obj_dn )
self . message ( " \t \t DSA object GUID: %s " % n . source_dsa_obj_guid )
self . message ( " \t \t Last attempt @ %s %s " % ( nttime2string ( n . last_attempt ) ,
drs_errmsg ( n . result_last_attempt ) ) )
self . message ( " \t \t %u consecutive failure(s). " % n . consecutive_sync_failures )
self . message ( " \t \t Last success @ %s " % nttime2string ( n . last_success ) )
self . message ( " " )
2010-11-27 15:48:20 +03:00
def drsuapi_ReplicaInfo ( ctx , info_type ) :
''' call a DsReplicaInfo '''
req1 = drsuapi . DsReplicaGetInfoRequest1 ( )
req1 . info_type = info_type
try :
( info_type , info ) = ctx . drsuapi . DsReplicaGetInfo ( ctx . drsuapi_handle , 1 , req1 )
2010-11-29 06:15:57 +03:00
except Exception , e :
raise CommandError ( " DsReplicaGetInfo of type %u failed " % info_type , e )
2010-11-27 15:48:20 +03:00
return ( info_type , info )
2010-12-08 00:20:54 +03:00
def run ( self , DC = None , sambaopts = None ,
2010-11-27 15:48:20 +03:00
credopts = None , versionopts = None , server = None ) :
self . lp = sambaopts . get_loadparm ( )
2010-12-08 00:20:54 +03:00
if DC is None :
DC = common . netcmd_dnsname ( self . lp )
self . server = DC
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2010-11-27 15:48:20 +03:00
drsuapi_connect ( self )
samdb_connect ( self )
# show domain information
2011-12-04 17:23:34 +04:00
ntds_dn = self . samdb . get_dsServiceName ( )
2010-11-27 15:48:20 +03:00
server_dns = self . samdb . search ( base = " " , scope = ldb . SCOPE_BASE , attrs = [ " dnsHostName " ] ) [ 0 ] [ ' dnsHostName ' ] [ 0 ]
( site , server ) = drs_parse_ntds_dn ( ntds_dn )
2010-12-08 00:20:54 +03:00
try :
ntds = self . samdb . search ( base = ntds_dn , scope = ldb . SCOPE_BASE , attrs = [ ' options ' , ' objectGUID ' , ' invocationId ' ] )
except Exception , e :
raise CommandError ( " Failed to search NTDS DN %s " % ntds_dn )
2010-11-27 15:48:20 +03:00
conn = self . samdb . search ( base = ntds_dn , expression = " (objectClass=nTDSConnection) " )
2011-02-09 04:00:06 +03:00
self . message ( " %s \\ %s " % ( site , server ) )
self . message ( " DSA Options: 0x %08x " % int ( attr_default ( ntds [ 0 ] , " options " , 0 ) ) )
self . message ( " DSA object GUID: %s " % self . samdb . schema_format_value ( " objectGUID " , ntds [ 0 ] [ " objectGUID " ] [ 0 ] ) )
self . message ( " DSA invocationId: %s \n " % self . samdb . schema_format_value ( " objectGUID " , ntds [ 0 ] [ " invocationId " ] [ 0 ] ) )
2010-11-27 15:48:20 +03:00
2011-02-09 04:00:06 +03:00
self . message ( " ==== INBOUND NEIGHBORS ==== \n " )
2010-11-27 15:48:20 +03:00
( info_type , info ) = self . drsuapi_ReplicaInfo ( drsuapi . DRSUAPI_DS_REPLICA_INFO_NEIGHBORS )
for n in info . array :
self . print_neighbour ( n )
2011-02-09 04:00:06 +03:00
self . message ( " ==== OUTBOUND NEIGHBORS ==== \n " )
2010-11-27 15:48:20 +03:00
( info_type , info ) = self . drsuapi_ReplicaInfo ( drsuapi . DRSUAPI_DS_REPLICA_INFO_REPSTO )
for n in info . array :
self . print_neighbour ( n )
reasons = [ ' NTDSCONN_KCC_GC_TOPOLOGY ' ,
' NTDSCONN_KCC_RING_TOPOLOGY ' ,
' NTDSCONN_KCC_MINIMIZE_HOPS_TOPOLOGY ' ,
' NTDSCONN_KCC_STALE_SERVERS_TOPOLOGY ' ,
' NTDSCONN_KCC_OSCILLATING_CONNECTION_TOPOLOGY ' ,
' NTDSCONN_KCC_INTERSITE_GC_TOPOLOGY ' ,
' NTDSCONN_KCC_INTERSITE_TOPOLOGY ' ,
' NTDSCONN_KCC_SERVER_FAILOVER_TOPOLOGY ' ,
' NTDSCONN_KCC_SITE_FAILOVER_TOPOLOGY ' ,
' NTDSCONN_KCC_REDUNDANT_SERVER_TOPOLOGY ' ]
2011-02-09 04:00:06 +03:00
self . message ( " ==== KCC CONNECTION OBJECTS ==== \n " )
2010-11-27 15:48:20 +03:00
for c in conn :
2011-02-09 04:00:06 +03:00
self . message ( " Connection -- " )
2013-06-10 05:43:18 +04:00
c_rdn , sep , c_server_dn = c [ ' fromServer ' ] [ 0 ] . partition ( ' , ' )
try :
c_server_res = self . samdb . search ( base = c_server_dn , scope = ldb . SCOPE_BASE , attrs = [ " dnsHostName " ] )
c_server_dns = c_server_res [ 0 ] [ " dnsHostName " ] [ 0 ]
except ldb . LdbError , ( errno , _ ) :
if errno == ldb . ERR_NO_SUCH_OBJECT :
self . message ( " \t WARNING: Connection to DELETED server! " )
c_server_dns = " "
except KeyError :
c_server_dns = " "
2011-02-09 04:00:06 +03:00
self . message ( " \t Connection name: %s " % c [ ' name ' ] [ 0 ] )
self . message ( " \t Enabled : %s " % attr_default ( c , ' enabledConnection ' , ' TRUE ' ) )
2012-08-14 16:35:13 +04:00
self . message ( " \t Server DNS name : %s " % c_server_dns )
2011-02-09 04:00:06 +03:00
self . message ( " \t Server DN name : %s " % c [ ' fromServer ' ] [ 0 ] )
self . message ( " \t \t TransportType: RPC " )
self . message ( " \t \t options: 0x %08X " % int ( attr_default ( c , ' options ' , 0 ) ) )
2010-11-27 15:48:20 +03:00
if not ' mS-DS-ReplicatesNCReason ' in c :
2011-02-09 04:00:06 +03:00
self . message ( " Warning: No NC replicated for Connection! " )
2010-11-27 15:48:20 +03:00
continue
for r in c [ ' mS-DS-ReplicatesNCReason ' ] :
a = str ( r ) . split ( ' : ' )
2011-02-09 04:00:06 +03:00
self . message ( " \t \t ReplicatesNC: %s " % a [ 3 ] )
self . message ( " \t \t Reason: 0x %08x " % int ( a [ 2 ] ) )
2010-11-27 15:48:20 +03:00
for s in reasons :
if getattr ( dsdb , s , 0 ) & int ( a [ 2 ] ) :
2011-02-09 04:00:06 +03:00
self . message ( " \t \t \t %s " % s )
2010-11-27 15:48:20 +03:00
2011-09-02 21:56:51 +04:00
2010-11-27 15:48:20 +03:00
class cmd_drs_kcc ( Command ) :
2012-10-08 14:32:58 +04:00
""" Trigger knowledge consistency center run. """
2010-11-27 15:48:20 +03:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog [<DC>] [options] "
2010-11-27 15:48:20 +03:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2010-12-08 00:20:54 +03:00
takes_args = [ " DC? " ]
2010-11-27 15:48:20 +03:00
2010-12-08 00:20:54 +03:00
def run ( self , DC = None , sambaopts = None ,
2010-11-27 15:48:20 +03:00
credopts = None , versionopts = None , server = None ) :
self . lp = sambaopts . get_loadparm ( )
2010-12-08 00:20:54 +03:00
if DC is None :
DC = common . netcmd_dnsname ( self . lp )
self . server = DC
2010-11-27 15:48:20 +03:00
2010-12-08 00:20:54 +03:00
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2010-11-27 15:48:20 +03:00
drsuapi_connect ( self )
req1 = drsuapi . DsExecuteKCC1 ( )
try :
self . drsuapi . DsExecuteKCC ( self . drsuapi_handle , 1 , req1 )
2010-11-29 06:15:57 +03:00
except Exception , e :
raise CommandError ( " DsExecuteKCC failed " , e )
2011-02-09 04:00:06 +03:00
self . message ( " Consistency check on %s successful. " % DC )
2010-11-27 15:48:20 +03:00
2011-09-02 21:56:51 +04:00
2011-06-09 09:01:30 +04:00
def drs_local_replicate ( self , SOURCE_DC , NC ) :
''' replicate from a source DC to the local SAM '''
2011-09-02 21:56:51 +04:00
2011-06-09 09:01:30 +04:00
self . server = SOURCE_DC
drsuapi_connect ( self )
self . local_samdb = SamDB ( session_info = system_session ( ) , url = None ,
credentials = self . creds , lp = self . lp )
self . samdb = SamDB ( url = " ldap:// %s " % self . server ,
session_info = system_session ( ) ,
credentials = self . creds , lp = self . lp )
# work out the source and destination GUIDs
res = self . local_samdb . search ( base = " " , scope = ldb . SCOPE_BASE , attrs = [ " dsServiceName " ] )
self . ntds_dn = res [ 0 ] [ " dsServiceName " ] [ 0 ]
res = self . local_samdb . search ( base = self . ntds_dn , scope = ldb . SCOPE_BASE , attrs = [ " objectGUID " ] )
self . ntds_guid = misc . GUID ( self . samdb . schema_format_value ( " objectGUID " , res [ 0 ] [ " objectGUID " ] [ 0 ] ) )
source_dsa_invocation_id = misc . GUID ( self . samdb . get_invocation_id ( ) )
2013-09-19 01:27:26 +04:00
dest_dsa_invocation_id = misc . GUID ( self . local_samdb . get_invocation_id ( ) )
2011-06-09 09:01:30 +04:00
destination_dsa_guid = self . ntds_guid
self . samdb . transaction_start ( )
repl = drs_utils . drs_Replicate ( " ncacn_ip_tcp: %s [seal] " % self . server , self . lp ,
2013-09-19 01:27:26 +04:00
self . creds , self . local_samdb , dest_dsa_invocation_id )
2015-02-20 07:54:32 +03:00
# Work out if we are an RODC, so that a forced local replicate
# with the admin pw does not sync passwords
rodc = self . local_samdb . am_rodc ( )
2011-06-09 09:01:30 +04:00
try :
2015-02-20 07:54:32 +03:00
repl . replicate ( NC , source_dsa_invocation_id , destination_dsa_guid , rodc = rodc )
2011-06-09 09:01:30 +04:00
except Exception , e :
raise CommandError ( " Error replicating DN %s " % NC , e )
self . samdb . transaction_commit ( )
2010-11-27 15:48:20 +03:00
class cmd_drs_replicate ( Command ) :
2012-10-08 14:32:58 +04:00
""" Replicate a naming context between two DCs. """
2010-11-27 15:48:20 +03:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog <destinationDC> <sourceDC> <NC> [options] "
2010-11-27 15:48:20 +03:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2010-11-27 15:48:20 +03:00
takes_args = [ " DEST_DC " , " SOURCE_DC " , " NC " ]
takes_options = [
Option ( " --add-ref " , help = " use ADD_REF to add to repsTo on source " , action = " store_true " ) ,
2011-02-02 08:02:06 +03:00
Option ( " --sync-forced " , help = " use SYNC_FORCED to force inbound replication " , action = " store_true " ) ,
2011-09-23 11:38:08 +04:00
Option ( " --sync-all " , help = " use SYNC_ALL to replicate from all DCs " , action = " store_true " ) ,
Option ( " --full-sync " , help = " resync all objects " , action = " store_true " ) ,
2011-06-09 09:01:30 +04:00
Option ( " --local " , help = " pull changes directly into the local database (destination DC is ignored) " , action = " store_true " ) ,
2010-11-27 15:48:20 +03:00
]
2011-09-23 11:38:08 +04:00
def run ( self , DEST_DC , SOURCE_DC , NC ,
add_ref = False , sync_forced = False , sync_all = False , full_sync = False ,
local = False , sambaopts = None , credopts = None , versionopts = None , server = None ) :
2010-11-27 15:48:20 +03:00
self . server = DEST_DC
self . lp = sambaopts . get_loadparm ( )
2010-12-08 00:20:54 +03:00
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2010-11-27 15:48:20 +03:00
2011-06-09 09:01:30 +04:00
if local :
drs_local_replicate ( self , SOURCE_DC , NC )
return
2010-11-27 15:48:20 +03:00
drsuapi_connect ( self )
samdb_connect ( self )
# we need to find the NTDS GUID of the source DC
msg = self . samdb . search ( base = self . samdb . get_config_basedn ( ) ,
2011-07-28 11:14:28 +04:00
expression = " (&(objectCategory=server)(|(name= %s )(dNSHostName= %s ))) " % (
ldb . binary_encode ( SOURCE_DC ) ,
ldb . binary_encode ( SOURCE_DC ) ) ,
2010-11-27 15:48:20 +03:00
attrs = [ ] )
if len ( msg ) == 0 :
raise CommandError ( " Failed to find source DC %s " % SOURCE_DC )
server_dn = msg [ 0 ] [ ' dn ' ]
msg = self . samdb . search ( base = server_dn , scope = ldb . SCOPE_ONELEVEL ,
2010-11-28 14:54:02 +03:00
expression = " (|(objectCategory=nTDSDSA)(objectCategory=nTDSDSARO)) " ,
2010-11-27 15:48:20 +03:00
attrs = [ ' objectGUID ' , ' options ' ] )
if len ( msg ) == 0 :
raise CommandError ( " Failed to find source NTDS DN %s " % SOURCE_DC )
source_dsa_guid = msg [ 0 ] [ ' objectGUID ' ] [ 0 ]
2011-11-28 22:31:57 +04:00
dsa_options = int ( attr_default ( msg , ' options ' , 0 ) )
2010-11-27 15:48:20 +03:00
2011-11-28 23:48:59 +04:00
req_options = 0
2011-11-28 22:31:57 +04:00
if not ( dsa_options & dsdb . DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL ) :
2011-11-28 23:48:59 +04:00
req_options | = drsuapi . DRSUAPI_DRS_WRIT_REP
2010-11-27 15:48:20 +03:00
if add_ref :
2011-11-28 23:48:59 +04:00
req_options | = drsuapi . DRSUAPI_DRS_ADD_REF
2011-02-02 08:02:06 +03:00
if sync_forced :
2011-11-28 23:48:59 +04:00
req_options | = drsuapi . DRSUAPI_DRS_SYNC_FORCED
2011-09-23 11:38:08 +04:00
if sync_all :
2011-11-28 23:48:59 +04:00
req_options | = drsuapi . DRSUAPI_DRS_SYNC_ALL
2011-09-23 11:38:08 +04:00
if full_sync :
2011-11-28 23:48:59 +04:00
req_options | = drsuapi . DRSUAPI_DRS_FULL_SYNC_NOW
2010-11-27 15:48:20 +03:00
try :
2011-11-28 23:48:59 +04:00
drs_utils . sendDsReplicaSync ( self . drsuapi , self . drsuapi_handle , source_dsa_guid , NC , req_options )
except drs_utils . drsException , estr :
2010-11-29 06:15:57 +03:00
raise CommandError ( " DsReplicaSync failed " , estr )
2011-02-09 04:00:06 +03:00
self . message ( " Replicate from %s to %s was successful. " % ( SOURCE_DC , DEST_DC ) )
2010-11-27 15:48:20 +03:00
class cmd_drs_bind ( Command ) :
2012-10-08 14:32:58 +04:00
""" Show DRS capabilities of a server. """
2010-11-27 15:48:20 +03:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog [<DC>] [options] "
2010-11-27 15:48:20 +03:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2010-12-08 00:20:54 +03:00
takes_args = [ " DC? " ]
2010-11-27 15:48:20 +03:00
2010-12-08 00:20:54 +03:00
def run ( self , DC = None , sambaopts = None ,
2010-11-27 15:48:20 +03:00
credopts = None , versionopts = None , server = None ) :
self . lp = sambaopts . get_loadparm ( )
2010-12-08 00:20:54 +03:00
if DC is None :
DC = common . netcmd_dnsname ( self . lp )
self . server = DC
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
2010-11-27 15:48:20 +03:00
drsuapi_connect ( self )
bind_info = drsuapi . DsBindInfoCtr ( )
bind_info . length = 28
bind_info . info = drsuapi . DsBindInfo28 ( )
( info , handle ) = self . drsuapi . DsBind ( misc . GUID ( drsuapi . DRSUAPI_DS_BIND_GUID ) , bind_info )
optmap = [
2011-09-13 02:20:03 +04:00
( " DRSUAPI_SUPPORTED_EXTENSION_BASE " , " DRS_EXT_BASE " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION " , " DRS_EXT_ASYNCREPL " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI " , " DRS_EXT_REMOVEAPI " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2 " , " DRS_EXT_MOVEREQ_V2 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS " , " DRS_EXT_GETCHG_DEFLATE " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1 " , " DRS_EXT_DCINFO_V1 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION " , " DRS_EXT_RESTORE_USN_OPTIMIZATION " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY " , " DRS_EXT_ADDENTRY " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE " , " DRS_EXT_KCC_EXECUTE " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2 " , " DRS_EXT_ADDENTRY_V2 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION " , " DRS_EXT_LINKED_VALUE_REPLICATION " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2 " , " DRS_EXT_DCINFO_V2 " ) ,
2010-11-27 15:48:20 +03:00
( " DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD " , " DRS_EXT_INSTANCE_TYPE_NOT_REQ_ON_MOD " ) ,
2011-09-13 02:20:03 +04:00
( " DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND " , " DRS_EXT_CRYPTO_BIND " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO " , " DRS_EXT_GET_REPL_INFO " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION " , " DRS_EXT_STRONG_ENCRYPTION " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01 " , " DRS_EXT_DCINFO_VFFFFFFFF " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP " , " DRS_EXT_TRANSITIVE_MEMBERSHIP " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY " , " DRS_EXT_ADD_SID_HISTORY " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3 " , " DRS_EXT_POST_BETA3 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V5 " , " DRS_EXT_GETCHGREQ_V5 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2 " , " DRS_EXT_GETMEMBERSHIPS2 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6 " , " DRS_EXT_GETCHGREQ_V6 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS " , " DRS_EXT_NONDOMAIN_NCS " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8 " , " DRS_EXT_GETCHGREQ_V8 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5 " , " DRS_EXT_GETCHGREPLY_V5 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6 " , " DRS_EXT_GETCHGREPLY_V6 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3 " , " DRS_EXT_WHISTLER_BETA3 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7 " , " DRS_EXT_WHISTLER_BETA3 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT " , " DRS_EXT_WHISTLER_BETA3 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS " , " DRS_EXT_W2K3_DEFLATE " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10 " , " DRS_EXT_GETCHGREQ_V10 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_RESERVED_PART2 " , " DRS_EXT_RESERVED_FOR_WIN2K_OR_DOTNET_PART2 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_RESERVED_PART3 " , " DRS_EXT_RESERVED_FOR_WIN2K_OR_DOTNET_PART3 " )
2010-11-27 15:48:20 +03:00
]
optmap_ext = [
2011-09-13 02:20:03 +04:00
( " DRSUAPI_SUPPORTED_EXTENSION_ADAM " , " DRS_EXT_ADAM " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2 " , " DRS_EXT_LH_BETA2 " ) ,
( " DRSUAPI_SUPPORTED_EXTENSION_RECYCLE_BIN " , " DRS_EXT_RECYCLE_BIN " ) ]
2010-11-27 15:48:20 +03:00
2011-02-09 04:00:06 +03:00
self . message ( " Bind to %s succeeded. " % DC )
self . message ( " Extensions supported: " )
2010-11-27 15:48:20 +03:00
for ( opt , str ) in optmap :
optval = getattr ( drsuapi , opt , 0 )
if info . info . supported_extensions & optval :
yesno = " Yes "
else :
yesno = " No "
2011-02-09 04:00:06 +03:00
self . message ( " %-60s : %s ( %s ) " % ( opt , yesno , str ) )
2010-11-27 15:48:20 +03:00
if isinstance ( info . info , drsuapi . DsBindInfo48 ) :
2011-02-09 04:00:06 +03:00
self . message ( " \n Extended Extensions supported: " )
2010-11-27 15:48:20 +03:00
for ( opt , str ) in optmap_ext :
optval = getattr ( drsuapi , opt , 0 )
if info . info . supported_extensions_ext & optval :
yesno = " Yes "
else :
yesno = " No "
2011-02-09 04:00:06 +03:00
self . message ( " %-60s : %s ( %s ) " % ( opt , yesno , str ) )
2010-11-27 15:48:20 +03:00
2011-02-09 04:00:06 +03:00
self . message ( " \n Site GUID: %s " % info . info . site_guid )
self . message ( " Repl epoch: %u " % info . info . repl_epoch )
2010-11-27 15:48:20 +03:00
if isinstance ( info . info , drsuapi . DsBindInfo48 ) :
2011-02-09 04:00:06 +03:00
self . message ( " Forest GUID: %s " % info . info . config_dn_guid )
2010-11-27 15:48:20 +03:00
2011-02-04 05:14:13 +03:00
class cmd_drs_options ( Command ) :
2012-10-08 14:32:58 +04:00
""" Query or change ' options ' for NTDS Settings object of a Domain Controller. """
2011-02-04 05:14:13 +03:00
2011-10-14 01:27:22 +04:00
synopsis = " % prog [<DC>] [options] "
2011-02-04 05:14:13 +03:00
2012-02-06 19:33:38 +04:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2011-03-28 08:32:15 +04:00
takes_args = [ " DC? " ]
2011-02-04 05:14:13 +03:00
takes_options = [
2011-09-02 21:56:51 +04:00
Option ( " --dsa-option " , help = " DSA option to enable/disable " , type = " str " ,
metavar = " { +|-}IS_GC | { +|-}DISABLE_INBOUND_REPL | { +|-}DISABLE_OUTBOUND_REPL | { +|-}DISABLE_NTDSCONN_XLATE " ) ,
2011-02-04 05:14:13 +03:00
]
option_map = { " IS_GC " : 0x00000001 ,
" DISABLE_INBOUND_REPL " : 0x00000002 ,
" DISABLE_OUTBOUND_REPL " : 0x00000004 ,
" DISABLE_NTDSCONN_XLATE " : 0x00000008 }
2011-03-28 08:32:15 +04:00
def run ( self , DC = None , dsa_option = None ,
2011-02-04 05:14:13 +03:00
sambaopts = None , credopts = None , versionopts = None ) :
self . lp = sambaopts . get_loadparm ( )
if DC is None :
DC = common . netcmd_dnsname ( self . lp )
self . server = DC
self . creds = credopts . get_credentials ( self . lp , fallback_machine = True )
samdb_connect ( self )
2011-12-04 17:23:34 +04:00
ntds_dn = self . samdb . get_dsServiceName ( )
2011-02-04 05:14:13 +03:00
res = self . samdb . search ( base = ntds_dn , scope = ldb . SCOPE_BASE , attrs = [ " options " ] )
dsa_opts = int ( res [ 0 ] [ " options " ] [ 0 ] )
# print out current DSA options
cur_opts = [ x for x in self . option_map if self . option_map [ x ] & dsa_opts ]
self . message ( " Current DSA options: " + " , " . join ( cur_opts ) )
# modify options
if dsa_option :
if dsa_option [ : 1 ] not in ( " + " , " - " ) :
raise CommandError ( " Unknown option %s " % dsa_option )
flag = dsa_option [ 1 : ]
if flag not in self . option_map . keys ( ) :
raise CommandError ( " Unknown option %s " % dsa_option )
if dsa_option [ : 1 ] == " + " :
dsa_opts | = self . option_map [ flag ]
else :
dsa_opts & = ~ self . option_map [ flag ]
#save new options
m = ldb . Message ( )
m . dn = ldb . Dn ( self . samdb , ntds_dn )
m [ " options " ] = ldb . MessageElement ( str ( dsa_opts ) , ldb . FLAG_MOD_REPLACE , " options " )
self . samdb . modify ( m )
# print out new DSA options
cur_opts = [ x for x in self . option_map if self . option_map [ x ] & dsa_opts ]
self . message ( " New DSA options: " + " , " . join ( cur_opts ) )
2015-08-17 06:33:31 +03:00
class cmd_drs_clone_dc_database ( Command ) :
""" Replicate an initial clone of domain, but DO NOT JOIN it. """
synopsis = " % prog <dnsdomain> [options] "
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
takes_options = [
Option ( " --server " , help = " DC to join " , type = str ) ,
Option ( " --targetdir " , help = " where to store provision " , type = str ) ,
Option ( " --quiet " , help = " Be quiet " , action = " store_true " ) ,
Option ( " --verbose " , help = " Be verbose " , action = " store_true " )
]
takes_args = [ " domain " ]
def run ( self , domain , sambaopts = None , credopts = None ,
versionopts = None , server = None , targetdir = None ,
quiet = False , verbose = False ) :
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
logger = self . get_logger ( )
if verbose :
logger . setLevel ( logging . DEBUG )
elif quiet :
logger . setLevel ( logging . WARNING )
else :
logger . setLevel ( logging . INFO )
join_clone ( logger = logger , server = server , creds = creds , lp = lp , domain = domain ,
targetdir = targetdir )
2010-11-27 15:48:20 +03:00
class cmd_drs ( SuperCommand ) :
2012-10-09 13:53:21 +04:00
""" Directory Replication Services (DRS) management. """
2010-11-27 15:48:20 +03:00
subcommands = { }
subcommands [ " bind " ] = cmd_drs_bind ( )
subcommands [ " kcc " ] = cmd_drs_kcc ( )
subcommands [ " replicate " ] = cmd_drs_replicate ( )
subcommands [ " showrepl " ] = cmd_drs_showrepl ( )
2011-02-04 05:14:13 +03:00
subcommands [ " options " ] = cmd_drs_options ( )
2015-08-17 06:33:31 +03:00
subcommands [ " clone-dc-database " ] = cmd_drs_clone_dc_database ( )