2011-06-27 16:32:22 -04:00
# domain management
#
# Copyright Matthias Dieter Wallnoefer 2009
# Copyright Andrew Kroeger 2009
2012-09-25 22:34:36 +02:00
# Copyright Jelmer Vernooij 2007-2012
2011-06-27 16:32:22 -04:00
# Copyright Giampaolo Lauria 2011
2011-12-04 23:00:57 +01:00
# Copyright Matthieu Patou <mat@matws.net> 2011
2012-09-10 14:05:14 +02:00
# Copyright Andrew Bartlett 2008
# Copyright Stefan Metzmacher 2012
2011-06-27 16:32:22 -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/>.
#
import samba . getopt as options
import ldb
2011-12-04 23:00:57 +01:00
import string
2011-10-13 23:08:32 +02:00
import os
2012-09-10 14:05:14 +02:00
import sys
2011-09-12 16:03:34 +10:00
import tempfile
import logging
2011-06-28 15:06:41 -04:00
from samba . net import Net , LIBNET_JOIN_AUTOMATIC
2011-10-08 14:34:35 +02:00
import samba . ntacls
2011-08-24 15:39:51 +10:00
from samba . join import join_RODC , join_DC , join_subdomain
2011-06-27 16:32:22 -04:00
from samba . auth import system_session
from samba . samdb import SamDB
2011-12-04 23:00:57 +01:00
from samba . dcerpc import drsuapi
2011-06-27 16:32:22 -04:00
from samba . dcerpc . samr import DOMAIN_PASSWORD_COMPLEX , DOMAIN_PASSWORD_STORE_CLEARTEXT
from samba . netcmd import (
Command ,
CommandError ,
SuperCommand ,
Option
)
2011-09-27 17:46:14 -07:00
from samba . netcmd . common import netcmd_get_domain_infos_via_cldap
2011-09-12 16:03:34 +10:00
from samba . samba3 import Samba3
from samba . samba3 import param as s3param
from samba . upgrade import upgrade_from_samba3
2011-12-04 23:00:57 +01:00
from samba . drs_utils import (
sendDsReplicaSync , drsuapi_connect , drsException ,
sendRemoveDsServer )
2011-06-27 16:32:22 -04:00
2011-06-28 11:41:39 -04:00
from samba . dsdb import (
DS_DOMAIN_FUNCTION_2000 ,
DS_DOMAIN_FUNCTION_2003 ,
DS_DOMAIN_FUNCTION_2003_MIXED ,
DS_DOMAIN_FUNCTION_2008 ,
DS_DOMAIN_FUNCTION_2008_R2 ,
2011-12-04 23:00:57 +01:00
DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL ,
DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL ,
UF_WORKSTATION_TRUST_ACCOUNT ,
UF_SERVER_TRUST_ACCOUNT ,
UF_TRUSTED_FOR_DELEGATION
2011-06-28 11:41:39 -04:00
)
2012-09-10 14:05:14 +02:00
from samba . credentials import DONT_USE_KERBEROS
from samba . provision import (
provision ,
2013-09-09 11:54:23 +12:00
ProvisioningError
)
from samba . provision . common import (
2012-09-10 14:05:14 +02:00
FILL_FULL ,
FILL_NT4SYNC ,
2013-09-09 11:54:23 +12:00
FILL_DRS
)
2012-09-10 14:05:14 +02:00
2011-09-13 21:02:43 +10:00
def get_testparm_var ( testparm , smbconf , varname ) :
cmd = " %s -s -l --parameter-name= ' %s ' %s 2>/dev/null " % ( testparm , varname , smbconf )
2011-09-12 20:57:10 +02:00
output = os . popen ( cmd , ' r ' ) . readline ( )
return output . strip ( )
2011-06-28 11:41:39 -04:00
2012-05-18 15:24:38 +03:00
try :
import samba . dckeytab
class cmd_domain_export_keytab ( Command ) :
2012-10-08 12:32:58 +02:00
""" Dump Kerberos keys of the domain into a keytab. """
2011-10-08 14:34:35 +02:00
2012-05-18 15:24:38 +03:00
synopsis = " % prog <keytab> [options] "
2011-09-02 13:21:49 -04:00
2012-05-18 15:24:38 +03:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
}
2011-06-28 12:19:08 -04:00
2012-05-18 15:24:38 +03:00
takes_options = [
Option ( " --principal " , help = " extract only this principal " , type = str ) ,
]
2012-02-06 16:33:38 +01:00
2012-05-18 15:24:38 +03:00
takes_args = [ " keytab " ]
2011-06-28 12:19:08 -04:00
2012-05-18 15:24:38 +03:00
def run ( self , keytab , credopts = None , sambaopts = None , versionopts = None , principal = None ) :
lp = sambaopts . get_loadparm ( )
net = Net ( None , lp )
net . export_keytab ( keytab = keytab , principal = principal )
except :
cmd_domain_export_keytab = None
2011-06-28 12:19:08 -04:00
2012-02-06 22:06:09 +01:00
2011-09-27 17:46:14 -07:00
class cmd_domain_info ( Command ) :
2012-10-08 12:32:58 +02:00
""" Print basic info about a domain and the DC passed as parameter. """
2011-09-27 17:46:14 -07:00
2012-01-24 13:02:13 +01:00
synopsis = " % prog <ip_address> [options] "
2011-09-27 17:46:14 -07:00
takes_options = [
]
2012-02-06 22:06:09 +01:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
}
2011-09-27 17:46:14 -07:00
takes_args = [ " address " ]
def run ( self , address , credopts = None , sambaopts = None , versionopts = None ) :
lp = sambaopts . get_loadparm ( )
2011-11-23 21:29:18 +01:00
try :
res = netcmd_get_domain_infos_via_cldap ( lp , None , address )
except RuntimeError :
raise CommandError ( " Invalid IP address ' " + address + " ' ! " )
2012-09-16 14:18:39 +02:00
self . outf . write ( " Forest : %s \n " % res . forest )
self . outf . write ( " Domain : %s \n " % res . dns_domain )
self . outf . write ( " Netbios domain : %s \n " % res . domain_name )
self . outf . write ( " DC name : %s \n " % res . pdc_dns_name )
self . outf . write ( " DC netbios name : %s \n " % res . pdc_name )
self . outf . write ( " Server site : %s \n " % res . server_site )
self . outf . write ( " Client site : %s \n " % res . client_site )
2011-09-27 17:46:14 -07:00
2012-09-10 14:05:14 +02:00
class cmd_domain_provision ( Command ) :
2012-09-24 08:21:27 +02:00
""" Provision a domain. """
2012-09-10 14:05:14 +02:00
2012-09-24 08:21:27 +02:00
synopsis = " % prog [options] "
2012-09-10 14:05:14 +02:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
}
takes_options = [
Option ( " --interactive " , help = " Ask for names " , action = " store_true " ) ,
Option ( " --domain " , type = " string " , metavar = " DOMAIN " ,
help = " set domain " ) ,
Option ( " --domain-guid " , type = " string " , metavar = " GUID " ,
help = " set domainguid (otherwise random) " ) ,
Option ( " --domain-sid " , type = " string " , metavar = " SID " ,
help = " set domainsid (otherwise random) " ) ,
Option ( " --ntds-guid " , type = " string " , metavar = " GUID " ,
help = " set NTDS object GUID (otherwise random) " ) ,
Option ( " --invocationid " , type = " string " , metavar = " GUID " ,
help = " set invocationid (otherwise random) " ) ,
Option ( " --host-name " , type = " string " , metavar = " HOSTNAME " ,
help = " set hostname " ) ,
Option ( " --host-ip " , type = " string " , metavar = " IPADDRESS " ,
help = " set IPv4 ipaddress " ) ,
Option ( " --host-ip6 " , type = " string " , metavar = " IP6ADDRESS " ,
help = " set IPv6 ipaddress " ) ,
Option ( " --adminpass " , type = " string " , metavar = " PASSWORD " ,
help = " choose admin password (otherwise random) " ) ,
Option ( " --krbtgtpass " , type = " string " , metavar = " PASSWORD " ,
help = " choose krbtgt password (otherwise random) " ) ,
Option ( " --machinepass " , type = " string " , metavar = " PASSWORD " ,
help = " choose machine password (otherwise random) " ) ,
Option ( " --dns-backend " , type = " choice " , metavar = " NAMESERVER-BACKEND " ,
choices = [ " SAMBA_INTERNAL " , " BIND9_FLATFILE " , " BIND9_DLZ " , " NONE " ] ,
2012-09-27 09:30:47 -07:00
help = " The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
" BIND9_FLATFILE uses bind9 text database to store zone information, "
" BIND9_DLZ uses samba4 AD to store zone information, "
2012-09-10 14:05:14 +02:00
" NONE skips the DNS setup entirely (not recommended) " ,
2012-09-11 09:07:47 +02:00
default = " SAMBA_INTERNAL " ) ,
2012-09-10 14:05:14 +02:00
Option ( " --dnspass " , type = " string " , metavar = " PASSWORD " ,
help = " choose dns password (otherwise random) " ) ,
Option ( " --ldapadminpass " , type = " string " , metavar = " PASSWORD " ,
help = " choose password to set between Samba and it ' s LDAP backend (otherwise random) " ) ,
Option ( " --root " , type = " string " , metavar = " USERNAME " ,
help = " choose ' root ' unix username " ) ,
Option ( " --nobody " , type = " string " , metavar = " USERNAME " ,
help = " choose ' nobody ' user " ) ,
Option ( " --users " , type = " string " , metavar = " GROUPNAME " ,
help = " choose ' users ' group " ) ,
Option ( " --quiet " , help = " Be quiet " , action = " store_true " ) ,
Option ( " --blank " , action = " store_true " ,
help = " do not add users or groups, just the structure " ) ,
Option ( " --ldap-backend-type " , type = " choice " , metavar = " LDAP-BACKEND-TYPE " ,
help = " Test initialisation support for unsupported LDAP backend type (fedora-ds or openldap) DO NOT USE " ,
choices = [ " fedora-ds " , " openldap " ] ) ,
Option ( " --server-role " , type = " choice " , metavar = " ROLE " ,
choices = [ " domain controller " , " dc " , " member server " , " member " , " standalone " ] ,
help = " The server role (domain controller | dc | member server | member | standalone). Default is dc. " ,
default = " domain controller " ) ,
Option ( " --function-level " , type = " choice " , metavar = " FOR-FUN-LEVEL " ,
choices = [ " 2000 " , " 2003 " , " 2008 " , " 2008_R2 " ] ,
help = " The domain and forest function level (2000 | 2003 | 2008 | 2008_R2 - always native). Default is (Windows) 2003 Native. " ,
default = " 2003 " ) ,
Option ( " --next-rid " , type = " int " , metavar = " NEXTRID " , default = 1000 ,
help = " The initial nextRid value (only needed for upgrades). Default is 1000. " ) ,
Option ( " --partitions-only " ,
help = " Configure Samba ' s partitions, but do not modify them (ie, join a BDC) " , action = " store_true " ) ,
Option ( " --targetdir " , type = " string " , metavar = " DIR " ,
help = " Set target directory " ) ,
Option ( " --ol-mmr-urls " , type = " string " , metavar = " LDAPSERVER " ,
help = " List of LDAP-URLS [ ldap://<FQHN>:<PORT>/ (where <PORT> has to be different than 389!) ] separated with comma ( \" , \" ) for use with OpenLDAP-MMR (Multi-Master-Replication), e.g.: \" ldap://s4dc1:9000,ldap://s4dc2:9000 \" " ) ,
Option ( " --use-xattrs " , type = " choice " , choices = [ " yes " , " no " , " auto " ] , help = " Define if we should use the native fs capabilities or a tdb file for storing attributes likes ntacl, auto tries to make an inteligent guess based on the user rights and system capabilities " , default = " auto " ) ,
Option ( " --use-ntvfs " , action = " store_true " , help = " Use NTVFS for the fileserver (default = no) " ) ,
Option ( " --use-rfc2307 " , action = " store_true " , help = " Use AD to store posix attributes (default = no) " ) ,
]
2013-09-24 10:26:05 -07:00
openldap_options = [
Option ( " --ldap-dryrun-mode " , help = " Configure LDAP backend, but do not run any binaries and exit early. Used only for the test environment. DO NOT USE " ,
action = " store_true " ) ,
Option ( " --slapd-path " , type = " string " , metavar = " SLAPD-PATH " ,
help = " Path to slapd for LDAP backend [e.g.: ' /usr/local/libexec/slapd ' ]. Required for Setup with LDAP-Backend. OpenLDAP Version >= 2.4.17 should be used. " ) ,
Option ( " --ldap-backend-extra-port " , type = " int " , metavar = " LDAP-BACKEND-EXTRA-PORT " , help = " Additional TCP port for LDAP backend server (to use for replication) " ) ,
Option ( " --ldap-backend-forced-uri " , type = " string " , metavar = " LDAP-BACKEND-FORCED-URI " ,
help = " Force the LDAP backend connection to be to a particular URI. Use this ONLY for ' existing ' backends, or when debugging the interaction with the LDAP backend and you need to intercept the LDA " ) ,
Option ( " --ldap-backend-nosync " , help = " Configure LDAP backend not to call fsync() (for performance in test environments) " , action = " store_true " ) ,
]
if os . getenv ( ' TEST_LDAP ' , " no " ) == " yes " :
takes_options . extend ( openldap_options )
2012-09-10 14:05:14 +02:00
takes_args = [ ]
2013-09-26 10:19:18 -07:00
def run ( self , sambaopts = None , versionopts = None ,
2012-09-16 14:18:39 +02:00
interactive = None ,
domain = None ,
domain_guid = None ,
domain_sid = None ,
ntds_guid = None ,
invocationid = None ,
host_name = None ,
host_ip = None ,
host_ip6 = None ,
adminpass = None ,
krbtgtpass = None ,
machinepass = None ,
dns_backend = None ,
dns_forwarder = None ,
dnspass = None ,
ldapadminpass = None ,
root = None ,
nobody = None ,
users = None ,
quiet = None ,
blank = None ,
ldap_backend_type = None ,
server_role = None ,
function_level = None ,
next_rid = None ,
partitions_only = None ,
targetdir = None ,
ol_mmr_urls = None ,
use_xattrs = None ,
2013-09-24 10:26:05 -07:00
slapd_path = None ,
2012-09-16 14:18:39 +02:00
use_ntvfs = None ,
2013-09-24 10:26:05 -07:00
use_rfc2307 = None ,
ldap_backend_nosync = None ,
ldap_backend_extra_port = None ,
ldap_backend_forced_uri = None ,
ldap_dryrun_mode = None ) :
2012-09-10 14:05:14 +02:00
2012-09-12 12:31:38 +02:00
self . logger = self . get_logger ( " provision " )
2012-09-10 14:05:14 +02:00
if quiet :
2012-09-12 12:31:38 +02:00
self . logger . setLevel ( logging . WARNING )
2012-09-10 14:05:14 +02:00
else :
2012-09-12 12:31:38 +02:00
self . logger . setLevel ( logging . INFO )
2012-09-10 14:05:14 +02:00
lp = sambaopts . get_loadparm ( )
smbconf = lp . configfile
2012-09-24 23:02:05 +02:00
if dns_forwarder is not None :
suggested_forwarder = dns_forwarder
2012-09-24 08:26:12 +02:00
else :
2012-09-24 23:02:05 +02:00
suggested_forwarder = self . _get_nameserver_ip ( )
2012-09-26 17:24:40 -07:00
if suggested_forwarder is None :
suggested_forwarder = " none "
2012-09-12 12:31:38 +02:00
2012-09-10 14:05:14 +02:00
if len ( self . raw_argv ) == 1 :
interactive = True
if interactive :
from getpass import getpass
import socket
def ask ( prompt , default = None ) :
if default is not None :
print " %s [ %s ]: " % ( prompt , default ) ,
else :
print " %s : " % ( prompt , ) ,
return sys . stdin . readline ( ) . rstrip ( " \n " ) or default
try :
default = socket . getfqdn ( ) . split ( " . " , 1 ) [ 1 ] . upper ( )
except IndexError :
default = None
realm = ask ( " Realm " , default )
if realm in ( None , " " ) :
raise CommandError ( " No realm set! " )
try :
default = realm . split ( " . " ) [ 0 ]
except IndexError :
default = None
domain = ask ( " Domain " , default )
if domain is None :
raise CommandError ( " No domain set! " )
server_role = ask ( " Server Role (dc, member, standalone) " , " dc " )
2012-09-11 09:07:47 +02:00
dns_backend = ask ( " DNS backend (SAMBA_INTERNAL, BIND9_FLATFILE, BIND9_DLZ, NONE) " , " SAMBA_INTERNAL " )
2012-09-10 14:05:14 +02:00
if dns_backend in ( None , ' ' ) :
raise CommandError ( " No DNS backend set! " )
2012-09-12 12:31:38 +02:00
if dns_backend == " SAMBA_INTERNAL " :
dns_forwarder = ask ( " DNS forwarder IP address (write ' none ' to disable forwarding) " , suggested_forwarder )
if dns_forwarder . lower ( ) in ( None , ' none ' ) :
suggested_forwarder = None
dns_forwarder = None
2012-09-10 14:05:14 +02:00
while True :
adminpassplain = getpass ( " Administrator password: " )
if not adminpassplain :
2012-09-16 14:18:39 +02:00
self . errf . write ( " Invalid administrator password. \n " )
2012-09-10 14:05:14 +02:00
else :
adminpassverify = getpass ( " Retype password: " )
if not adminpassplain == adminpassverify :
2012-09-16 14:18:39 +02:00
self . errf . write ( " Sorry, passwords do not match. \n " )
2012-09-10 14:05:14 +02:00
else :
adminpass = adminpassplain
break
else :
realm = sambaopts . _lp . get ( ' realm ' )
if realm is None :
raise CommandError ( " No realm set! " )
if domain is None :
raise CommandError ( " No domain set! " )
if not adminpass :
2012-09-12 12:31:38 +02:00
self . logger . info ( " Administrator password will be set randomly! " )
2012-09-10 14:05:14 +02:00
if function_level == " 2000 " :
dom_for_fun_level = DS_DOMAIN_FUNCTION_2000
elif function_level == " 2003 " :
dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
elif function_level == " 2008 " :
dom_for_fun_level = DS_DOMAIN_FUNCTION_2008
elif function_level == " 2008_R2 " :
dom_for_fun_level = DS_DOMAIN_FUNCTION_2008_R2
2012-09-12 12:31:38 +02:00
if dns_backend == " SAMBA_INTERNAL " and dns_forwarder is None :
dns_forwarder = suggested_forwarder
2012-09-10 14:05:14 +02:00
samdb_fill = FILL_FULL
if blank :
samdb_fill = FILL_NT4SYNC
elif partitions_only :
samdb_fill = FILL_DRS
if targetdir is not None :
if not os . path . isdir ( targetdir ) :
os . mkdir ( targetdir )
eadb = True
if use_xattrs == " yes " :
eadb = False
elif use_xattrs == " auto " and not lp . get ( " posix:eadb " ) :
if targetdir :
file = tempfile . NamedTemporaryFile ( dir = os . path . abspath ( targetdir ) )
else :
file = tempfile . NamedTemporaryFile ( dir = os . path . abspath ( os . path . dirname ( lp . get ( " private dir " ) ) ) )
try :
try :
samba . ntacls . setntacl ( lp , file . name ,
" O:S-1-5-32G:S-1-5-32 " , " S-1-5-32 " , " native " )
eadb = False
except Exception :
2012-09-12 12:31:38 +02:00
self . logger . info ( " You are not root or your system do not support xattr, using tdb backend for attributes. " )
2012-09-10 14:05:14 +02:00
finally :
file . close ( )
if eadb :
2012-09-12 12:31:38 +02:00
self . logger . info ( " not using extended attributes to store ACLs and other metadata. If you intend to use this provision in production, rerun the script as root on a system supporting xattrs. " )
2013-09-24 10:26:05 -07:00
if ldap_backend_type == " existing " :
if dap_backend_forced_uri is not None :
logger . warn ( " You have specified to use an existing LDAP server as the backend, please make sure an LDAP server is running at %s " % ldap_backend_forced_uri )
else :
logger . info ( " You have specified to use an existing LDAP server as the backend, please make sure an LDAP server is running at the default location " )
else :
if ldap_backend_forced_uri is not None :
logger . warn ( " You have specified to use an fixed URI %s for connecting to your LDAP server backend. This is NOT RECOMMENDED, as our default communiation over ldapi:// is more secure and much less " )
2012-09-10 14:05:14 +02:00
session = system_session ( )
try :
2012-09-12 12:31:38 +02:00
result = provision ( self . logger ,
2013-09-26 10:19:18 -07:00
session , smbconf = smbconf , targetdir = targetdir ,
2012-09-10 14:05:14 +02:00
samdb_fill = samdb_fill , realm = realm , domain = domain ,
domainguid = domain_guid , domainsid = domain_sid ,
hostname = host_name ,
hostip = host_ip , hostip6 = host_ip6 ,
ntdsguid = ntds_guid ,
invocationid = invocationid , adminpass = adminpass ,
krbtgtpass = krbtgtpass , machinepass = machinepass ,
2012-09-12 12:31:38 +02:00
dns_backend = dns_backend , dns_forwarder = dns_forwarder ,
2012-09-10 14:05:14 +02:00
dnspass = dnspass , root = root , nobody = nobody ,
2012-10-16 13:08:22 +11:00
users = users ,
2012-09-10 14:05:14 +02:00
serverrole = server_role , dom_for_fun_level = dom_for_fun_level ,
backend_type = ldap_backend_type ,
2013-09-24 10:26:05 -07:00
ldapadminpass = ldapadminpass , ol_mmr_urls = ol_mmr_urls , slapd_path = slapd_path ,
2012-09-24 09:20:46 +02:00
useeadb = eadb , next_rid = next_rid , lp = lp , use_ntvfs = use_ntvfs ,
2013-09-24 10:26:05 -07:00
use_rfc2307 = use_rfc2307 , skip_sysvolacl = False ,
ldap_backend_extra_port = ldap_backend_extra_port ,
ldap_backend_forced_uri = ldap_backend_forced_uri ,
nosync = ldap_backend_nosync , ldap_dryrun_mode = ldap_dryrun_mode )
2012-09-10 14:05:14 +02:00
except ProvisioningError , e :
raise CommandError ( " Provision failed " , e )
2012-09-12 12:31:38 +02:00
result . report_logger ( self . logger )
def _get_nameserver_ip ( self ) :
2012-10-08 12:32:58 +02:00
""" Grab the nameserver IP address from /etc/resolv.conf. """
2012-09-12 12:31:38 +02:00
from os import path
RESOLV_CONF = " /etc/resolv.conf "
if not path . isfile ( RESOLV_CONF ) :
self . logger . warning ( " Failed to locate %s " % RESOLV_CONF )
return None
handle = None
try :
handle = open ( RESOLV_CONF , ' r ' )
for line in handle :
if not line . startswith ( ' nameserver ' ) :
continue
# we want the last non-space continuous string of the line
return line . strip ( ) . split ( ) [ - 1 ]
finally :
if handle is not None :
handle . close ( )
self . logger . warning ( " No nameserver found in %s " % RESOLV_CONF )
2011-06-28 12:19:08 -04:00
2012-07-06 15:38:06 +10:00
class cmd_domain_dcpromo ( Command ) :
2012-10-08 12:32:58 +02:00
""" Promote an existing domain member or NT4 PDC to an AD DC. """
2012-07-06 15:38:06 +10:00
synopsis = " % prog <dnsdomain> [DC|RODC] [options] "
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
takes_options = [
Option ( " --server " , help = " DC to join " , type = str ) ,
Option ( " --site " , help = " site to join " , type = str ) ,
Option ( " --targetdir " , help = " where to store provision " , type = str ) ,
Option ( " --domain-critical-only " ,
help = " only replicate critical domain objects " ,
action = " store_true " ) ,
Option ( " --machinepass " , type = str , metavar = " PASSWORD " ,
help = " choose machine password (otherwise random) " ) ,
Option ( " --use-ntvfs " , help = " Use NTVFS for the fileserver (default = no) " ,
action = " store_true " ) ,
Option ( " --dns-backend " , type = " choice " , metavar = " NAMESERVER-BACKEND " ,
choices = [ " SAMBA_INTERNAL " , " BIND9_DLZ " , " NONE " ] ,
2012-09-27 09:30:47 -07:00
help = " The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
" BIND9_DLZ uses samba4 AD to store zone information, "
2012-07-06 15:38:06 +10:00
" NONE skips the DNS setup entirely (this DC will not be a DNS server) " ,
2013-09-09 09:53:37 +12:00
default = " SAMBA_INTERNAL " ) ,
Option ( " --quiet " , help = " Be quiet " , action = " store_true " ) ,
Option ( " --verbose " , help = " Be verbose " , action = " store_true " )
]
2012-07-06 15:38:06 +10:00
takes_args = [ " domain " , " role? " ]
def run ( self , domain , role = None , sambaopts = None , credopts = None ,
versionopts = None , server = None , site = None , targetdir = None ,
domain_critical_only = False , parent_domain = None , machinepass = None ,
2013-09-09 09:53:37 +12:00
use_ntvfs = False , dns_backend = None ,
quiet = False , verbose = False ) :
2012-07-06 15:38:06 +10:00
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
net = Net ( creds , lp , server = credopts . ipaddress )
2013-09-09 09:53:37 +12:00
if site is None :
site = " Default-First-Site-Name "
logger = self . get_logger ( )
if verbose :
logger . setLevel ( logging . DEBUG )
elif quiet :
logger . setLevel ( logging . WARNING )
else :
logger . setLevel ( logging . INFO )
2012-07-06 15:38:06 +10:00
if site is None :
site = " Default-First-Site-Name "
netbios_name = lp . get ( " netbios name " )
if not role is None :
role = role . upper ( )
if role == " DC " :
2013-09-09 09:53:37 +12:00
join_DC ( logger = logger , server = server , creds = creds , lp = lp , domain = domain ,
2012-07-06 15:38:06 +10:00
site = site , netbios_name = netbios_name , targetdir = targetdir ,
domain_critical_only = domain_critical_only ,
2012-09-16 14:18:39 +02:00
machinepass = machinepass , use_ntvfs = use_ntvfs ,
dns_backend = dns_backend ,
2012-07-06 15:38:06 +10:00
promote_existing = True )
elif role == " RODC " :
2013-09-09 09:53:37 +12:00
join_RODC ( logger = logger , server = server , creds = creds , lp = lp , domain = domain ,
2012-07-06 15:38:06 +10:00
site = site , netbios_name = netbios_name , targetdir = targetdir ,
domain_critical_only = domain_critical_only ,
machinepass = machinepass , use_ntvfs = use_ntvfs , dns_backend = dns_backend ,
promote_existing = True )
else :
raise CommandError ( " Invalid role ' %s ' (possible values: DC, RODC) " % role )
2011-06-28 15:06:41 -04:00
class cmd_domain_join ( Command ) :
2012-10-08 12:32:58 +02:00
""" Join domain as either member or backup domain controller. """
2011-06-28 15:06:41 -04:00
2011-10-13 23:27:22 +02:00
synopsis = " % prog <dnsdomain> [DC|RODC|MEMBER|SUBDOMAIN] [options] "
2011-06-28 15:06:41 -04:00
2012-02-06 16:33:38 +01:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2011-06-28 15:06:41 -04:00
takes_options = [
Option ( " --server " , help = " DC to join " , type = str ) ,
Option ( " --site " , help = " site to join " , type = str ) ,
Option ( " --targetdir " , help = " where to store provision " , type = str ) ,
2011-08-24 15:39:51 +10:00
Option ( " --parent-domain " , help = " parent domain to create subdomain under " , type = str ) ,
2011-08-08 11:15:35 +02:00
Option ( " --domain-critical-only " ,
help = " only replicate critical domain objects " ,
action = " store_true " ) ,
2011-11-16 15:32:47 +01:00
Option ( " --machinepass " , type = str , metavar = " PASSWORD " ,
2012-06-05 01:32:42 +03:00
help = " choose machine password (otherwise random) " ) ,
2013-09-06 15:46:05 +12:00
Option ( " --adminpass " , type = " string " , metavar = " PASSWORD " ,
help = " choose adminstrator password when joining as a subdomain (otherwise random) " ) ,
2012-06-05 01:32:42 +03:00
Option ( " --use-ntvfs " , help = " Use NTVFS for the fileserver (default = no) " ,
2012-06-21 23:46:21 +10:00
action = " store_true " ) ,
Option ( " --dns-backend " , type = " choice " , metavar = " NAMESERVER-BACKEND " ,
choices = [ " SAMBA_INTERNAL " , " BIND9_DLZ " , " NONE " ] ,
2012-09-27 09:30:47 -07:00
help = " The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
" BIND9_DLZ uses samba4 AD to store zone information, "
2012-06-21 23:46:21 +10:00
" NONE skips the DNS setup entirely (this DC will not be a DNS server) " ,
2013-09-09 09:53:37 +12:00
default = " SAMBA_INTERNAL " ) ,
Option ( " --quiet " , help = " Be quiet " , action = " store_true " ) ,
Option ( " --verbose " , help = " Be verbose " , action = " store_true " )
2012-06-21 23:46:21 +10:00
]
2011-06-28 15:06:41 -04:00
takes_args = [ " domain " , " role? " ]
def run ( self , domain , role = None , sambaopts = None , credopts = None ,
2011-08-08 11:15:35 +02:00
versionopts = None , server = None , site = None , targetdir = None ,
2012-06-05 01:32:42 +03:00
domain_critical_only = False , parent_domain = None , machinepass = None ,
2013-09-09 09:53:37 +12:00
use_ntvfs = False , dns_backend = None , adminpass = None ,
quiet = False , verbose = False ) :
2011-06-28 15:06:41 -04:00
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
net = Net ( creds , lp , server = credopts . ipaddress )
if site is None :
site = " Default-First-Site-Name "
2013-09-09 09:53:37 +12:00
logger = self . get_logger ( )
if verbose :
logger . setLevel ( logging . DEBUG )
elif quiet :
logger . setLevel ( logging . WARNING )
else :
logger . setLevel ( logging . INFO )
2011-06-28 15:06:41 -04:00
netbios_name = lp . get ( " netbios name " )
if not role is None :
role = role . upper ( )
if role is None or role == " MEMBER " :
2012-09-16 14:18:39 +02:00
( join_password , sid , domain_name ) = net . join_member (
domain , netbios_name , LIBNET_JOIN_AUTOMATIC ,
machinepass = machinepass )
2011-06-28 15:06:41 -04:00
2012-09-16 14:18:39 +02:00
self . errf . write ( " Joined domain %s ( %s ) \n " % ( domain_name , sid ) )
2011-06-28 15:06:41 -04:00
elif role == " DC " :
2013-09-09 09:53:37 +12:00
join_DC ( logger = logger , server = server , creds = creds , lp = lp , domain = domain ,
2011-08-08 11:15:35 +02:00
site = site , netbios_name = netbios_name , targetdir = targetdir ,
2011-11-16 15:32:47 +01:00
domain_critical_only = domain_critical_only ,
2012-06-21 23:46:21 +10:00
machinepass = machinepass , use_ntvfs = use_ntvfs , dns_backend = dns_backend )
2011-06-28 15:06:41 -04:00
elif role == " RODC " :
2013-09-09 09:53:37 +12:00
join_RODC ( logger = logger , server = server , creds = creds , lp = lp , domain = domain ,
2011-08-08 11:15:35 +02:00
site = site , netbios_name = netbios_name , targetdir = targetdir ,
2011-11-16 15:32:47 +01:00
domain_critical_only = domain_critical_only ,
2012-09-16 14:18:39 +02:00
machinepass = machinepass , use_ntvfs = use_ntvfs ,
dns_backend = dns_backend )
2011-08-24 15:39:51 +10:00
elif role == " SUBDOMAIN " :
2013-09-09 09:56:58 +12:00
if not adminpass :
logger . info ( " Administrator password will be set randomly! " )
2011-08-24 15:39:51 +10:00
netbios_domain = lp . get ( " workgroup " )
if parent_domain is None :
parent_domain = " . " . join ( domain . split ( " . " ) [ 1 : ] )
2013-09-09 09:53:37 +12:00
join_subdomain ( logger = logger , server = server , creds = creds , lp = lp , dnsdomain = domain ,
2013-09-06 15:46:05 +12:00
parent_domain = parent_domain , site = site ,
netbios_name = netbios_name , netbios_domain = netbios_domain ,
targetdir = targetdir , machinepass = machinepass ,
use_ntvfs = use_ntvfs , dns_backend = dns_backend ,
adminpass = adminpass )
2011-06-28 15:06:41 -04:00
else :
2011-11-01 15:21:32 -04:00
raise CommandError ( " Invalid role ' %s ' (possible values: MEMBER, DC, RODC, SUBDOMAIN) " % role )
2011-06-28 15:06:41 -04:00
2011-12-04 23:00:57 +01:00
class cmd_domain_demote ( Command ) :
2012-10-08 12:32:58 +02:00
""" Demote ourselves from the role of Domain Controller. """
2011-12-04 23:00:57 +01:00
synopsis = " % prog [options] "
takes_options = [
Option ( " --server " , help = " DC to force replication before demote " , type = str ) ,
Option ( " --targetdir " , help = " where provision is stored " , type = str ) ,
]
2012-02-06 22:06:09 +01:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
}
2011-12-04 23:00:57 +01:00
def run ( self , sambaopts = None , credopts = None ,
versionopts = None , server = None , targetdir = None ) :
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
net = Net ( creds , lp , server = credopts . ipaddress )
netbios_name = lp . get ( " netbios name " )
samdb = SamDB ( session_info = system_session ( ) , credentials = creds , lp = lp )
if not server :
res = samdb . search ( expression = ' (&(objectClass=computer)(serverReferenceBL=*)) ' , attrs = [ " dnsHostName " , " name " ] )
if ( len ( res ) == 0 ) :
raise CommandError ( " Unable to search for servers " )
if ( len ( res ) == 1 ) :
raise CommandError ( " You are the latest server in the domain " )
server = None
for e in res :
if str ( e [ " name " ] ) . lower ( ) != netbios_name . lower ( ) :
server = e [ " dnsHostName " ]
break
ntds_guid = samdb . get_ntds_GUID ( )
2012-09-16 14:18:39 +02:00
msg = samdb . search ( base = str ( samdb . get_config_basedn ( ) ) ,
scope = ldb . SCOPE_SUBTREE , expression = " (objectGUID= %s ) " % ntds_guid ,
attrs = [ ' options ' ] )
2011-12-04 23:00:57 +01:00
if len ( msg ) == 0 or " options " not in msg [ 0 ] :
raise CommandError ( " Failed to find options on %s " % ntds_guid )
2011-12-04 23:19:55 +01:00
ntds_dn = msg [ 0 ] . dn
2011-12-04 23:00:57 +01:00
dsa_options = int ( str ( msg [ 0 ] [ ' options ' ] ) )
2011-12-04 23:19:55 +01:00
res = samdb . search ( expression = " (fSMORoleOwner= %s ) " % str ( ntds_dn ) ,
controls = [ " search_options:1:2 " ] )
if len ( res ) != 0 :
2012-04-19 12:13:41 +02:00
raise CommandError ( " Current DC is still the owner of %d role(s), use the role command to transfer roles to another DC " % len ( res ) )
2011-12-04 23:19:55 +01:00
2012-09-16 14:18:39 +02:00
self . errf . write ( " Using %s as partner server for the demotion \n " %
server )
2011-12-04 23:19:55 +01:00
( drsuapiBind , drsuapi_handle , supportedExtensions ) = drsuapi_connect ( server , lp , creds )
2012-09-16 14:18:39 +02:00
self . errf . write ( " Desactivating inbound replication \n " )
2011-12-04 23:00:57 +01:00
nmsg = ldb . Message ( )
nmsg . dn = msg [ 0 ] . dn
dsa_options | = DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
nmsg [ " options " ] = ldb . MessageElement ( str ( dsa_options ) , ldb . FLAG_MOD_REPLACE , " options " )
samdb . modify ( nmsg )
if not ( dsa_options & DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL ) and not samdb . am_rodc ( ) :
2012-09-16 14:18:39 +02:00
self . errf . write ( " Asking partner server %s to synchronize from us \n "
% server )
2011-12-04 23:00:57 +01:00
for part in ( samdb . get_schema_basedn ( ) ,
samdb . get_config_basedn ( ) ,
samdb . get_root_basedn ( ) ) :
try :
sendDsReplicaSync ( drsuapiBind , drsuapi_handle , ntds_guid , str ( part ) , drsuapi . DRSUAPI_DRS_WRIT_REP )
except drsException , e :
2012-09-16 14:18:39 +02:00
self . errf . write (
" Error while demoting, "
" re-enabling inbound replication \n " )
2011-12-04 23:00:57 +01:00
dsa_options ^ = DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
nmsg [ " options " ] = ldb . MessageElement ( str ( dsa_options ) , ldb . FLAG_MOD_REPLACE , " options " )
samdb . modify ( nmsg )
raise CommandError ( " Error while sending a DsReplicaSync for partion %s " % str ( part ) , e )
try :
remote_samdb = SamDB ( url = " ldap:// %s " % server ,
session_info = system_session ( ) ,
credentials = creds , lp = lp )
2012-09-16 14:18:39 +02:00
self . errf . write ( " Changing userControl and container \n " )
2011-12-04 23:00:57 +01:00
res = remote_samdb . search ( base = str ( remote_samdb . get_root_basedn ( ) ) ,
expression = " (&(objectClass=user)(sAMAccountName= %s $)) " %
netbios_name . upper ( ) ,
attrs = [ " userAccountControl " ] )
dc_dn = res [ 0 ] . dn
uac = int ( str ( res [ 0 ] [ " userAccountControl " ] ) )
except Exception , e :
2012-09-16 14:18:39 +02:00
self . errf . write (
" Error while demoting, re-enabling inbound replication \n " )
dsa_options ^ = DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
nmsg [ " options " ] = ldb . MessageElement ( str ( dsa_options ) , ldb . FLAG_MOD_REPLACE , " options " )
samdb . modify ( nmsg )
raise CommandError ( " Error while changing account control " , e )
2011-12-04 23:00:57 +01:00
if ( len ( res ) != 1 ) :
2012-09-16 14:18:39 +02:00
self . errf . write (
" Error while demoting, re-enabling inbound replication " )
2011-12-04 23:00:57 +01:00
dsa_options ^ = DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
nmsg [ " options " ] = ldb . MessageElement ( str ( dsa_options ) , ldb . FLAG_MOD_REPLACE , " options " )
samdb . modify ( nmsg )
raise CommandError ( " Unable to find object with samaccountName = %s $ "
" in the remote dc " % netbios_name . upper ( ) )
olduac = uac
uac ^ = ( UF_SERVER_TRUST_ACCOUNT | UF_TRUSTED_FOR_DELEGATION )
uac | = UF_WORKSTATION_TRUST_ACCOUNT
msg = ldb . Message ( )
msg . dn = dc_dn
msg [ " userAccountControl " ] = ldb . MessageElement ( " %d " % uac ,
ldb . FLAG_MOD_REPLACE ,
" userAccountControl " )
try :
remote_samdb . modify ( msg )
except Exception , e :
2012-09-16 14:18:39 +02:00
self . errf . write (
" Error while demoting, re-enabling inbound replication " )
2011-12-04 23:00:57 +01:00
dsa_options ^ = DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
nmsg [ " options " ] = ldb . MessageElement ( str ( dsa_options ) , ldb . FLAG_MOD_REPLACE , " options " )
samdb . modify ( nmsg )
raise CommandError ( " Error while changing account control " , e )
parent = msg . dn . parent ( )
rdn = str ( res [ 0 ] . dn )
rdn = string . replace ( rdn , " , %s " % str ( parent ) , " " )
# Let's move to the Computer container
i = 0
newrdn = rdn
computer_dn = ldb . Dn ( remote_samdb , " CN=Computers, %s " % str ( remote_samdb . get_root_basedn ( ) ) )
res = remote_samdb . search ( base = computer_dn , expression = rdn , scope = ldb . SCOPE_ONELEVEL )
if ( len ( res ) != 0 ) :
res = remote_samdb . search ( base = computer_dn , expression = " %s - %d " % ( rdn , i ) ,
scope = ldb . SCOPE_ONELEVEL )
while ( len ( res ) != 0 and i < 100 ) :
i = i + 1
res = remote_samdb . search ( base = computer_dn , expression = " %s - %d " % ( rdn , i ) ,
scope = ldb . SCOPE_ONELEVEL )
if i == 100 :
2012-09-16 14:18:39 +02:00
self . errf . write (
" Error while demoting, re-enabling inbound replication \n " )
2011-12-04 23:00:57 +01:00
dsa_options ^ = DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
nmsg [ " options " ] = ldb . MessageElement ( str ( dsa_options ) , ldb . FLAG_MOD_REPLACE , " options " )
samdb . modify ( nmsg )
msg = ldb . Message ( )
msg . dn = dc_dn
msg [ " userAccountControl " ] = ldb . MessageElement ( " %d " % uac ,
ldb . FLAG_MOD_REPLACE ,
" userAccountControl " )
remote_samdb . modify ( msg )
raise CommandError ( " Unable to find a slot for renaming %s , "
" all names from %s -1 to %s - %d seemed used " %
( str ( dc_dn ) , rdn , rdn , i - 9 ) )
newrdn = " %s - %d " % ( rdn , i )
try :
newdn = ldb . Dn ( remote_samdb , " %s , %s " % ( newrdn , str ( computer_dn ) ) )
remote_samdb . rename ( dc_dn , newdn )
except Exception , e :
2012-09-16 14:18:39 +02:00
self . errf . write (
" Error while demoting, re-enabling inbound replication \n " )
2011-12-04 23:00:57 +01:00
dsa_options ^ = DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
nmsg [ " options " ] = ldb . MessageElement ( str ( dsa_options ) , ldb . FLAG_MOD_REPLACE , " options " )
samdb . modify ( nmsg )
msg = ldb . Message ( )
msg . dn = dc_dn
msg [ " userAccountControl " ] = ldb . MessageElement ( " %d " % uac ,
ldb . FLAG_MOD_REPLACE ,
" userAccountControl " )
remote_samdb . modify ( msg )
raise CommandError ( " Error while renaming %s to %s " % ( str ( dc_dn ) , str ( newdn ) ) , e )
server_dsa_dn = samdb . get_serverName ( )
domain = remote_samdb . get_root_basedn ( )
try :
sendRemoveDsServer ( drsuapiBind , drsuapi_handle , server_dsa_dn , domain )
except drsException , e :
2012-09-16 14:18:39 +02:00
self . errf . write (
" Error while demoting, re-enabling inbound replication \n " )
2011-12-04 23:00:57 +01:00
dsa_options ^ = DS_NTDSDSA_OPT_DISABLE_INBOUND_REPL
nmsg [ " options " ] = ldb . MessageElement ( str ( dsa_options ) , ldb . FLAG_MOD_REPLACE , " options " )
samdb . modify ( nmsg )
msg = ldb . Message ( )
msg . dn = newdn
msg [ " userAccountControl " ] = ldb . MessageElement ( " %d " % uac ,
ldb . FLAG_MOD_REPLACE ,
" userAccountControl " )
print str ( dc_dn )
remote_samdb . modify ( msg )
remote_samdb . rename ( newdn , dc_dn )
raise CommandError ( " Error while sending a removeDsServer " , e )
for s in ( " CN=Entreprise,CN=Microsoft System Volumes,CN=System,CN=Configuration " ,
" CN= %s ,CN=Microsoft System Volumes,CN=System,CN=Configuration " % lp . get ( " realm " ) ,
" CN=Domain System Volumes (SYSVOL share),CN=File Replication Service,CN=System " ) :
try :
remote_samdb . delete ( ldb . Dn ( remote_samdb ,
" %s , %s , %s " % ( str ( rdn ) , s , str ( remote_samdb . get_root_basedn ( ) ) ) ) )
except ldb . LdbError , l :
pass
for s in ( " CN=Entreprise,CN=NTFRS Subscriptions " ,
" CN= %s , CN=NTFRS Subscriptions " % lp . get ( " realm " ) ,
" CN=Domain system Volumes (SYSVOL Share), CN=NTFRS Subscriptions " ,
" CN=NTFRS Subscriptions " ) :
try :
remote_samdb . delete ( ldb . Dn ( remote_samdb ,
" %s , %s " % ( s , str ( newdn ) ) ) )
except ldb . LdbError , l :
pass
2012-09-16 14:18:39 +02:00
self . errf . write ( " Demote successfull \n " )
2011-12-04 23:00:57 +01:00
2011-06-28 11:41:39 -04:00
class cmd_domain_level ( Command ) :
2012-10-08 12:32:58 +02:00
""" Raise domain and forest function levels. """
2011-06-28 11:41:39 -04:00
2011-10-13 23:27:22 +02:00
synopsis = " % prog (show|raise <options>) [options] "
2011-06-28 11:41:39 -04:00
2012-02-06 16:33:38 +01:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" credopts " : options . CredentialsOptions ,
" versionopts " : options . VersionOptions ,
}
2011-06-28 11:41:39 -04:00
takes_options = [
2011-07-25 11:56:10 -04:00
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " , type = str ,
metavar = " URL " , dest = " H " ) ,
2011-06-28 11:41:39 -04:00
Option ( " --quiet " , help = " Be quiet " , action = " store_true " ) ,
2011-09-11 17:31:38 +02:00
Option ( " --forest-level " , type = " choice " , choices = [ " 2003 " , " 2008 " , " 2008_R2 " ] ,
2011-06-28 11:41:39 -04:00
help = " The forest function level (2003 | 2008 | 2008_R2) " ) ,
2011-09-11 17:31:38 +02:00
Option ( " --domain-level " , type = " choice " , choices = [ " 2003 " , " 2008 " , " 2008_R2 " ] ,
2011-09-09 15:27:25 +02:00
help = " The domain function level (2003 | 2008 | 2008_R2) " )
2011-06-28 11:41:39 -04:00
]
takes_args = [ " subcommand " ]
2011-09-11 17:31:38 +02:00
def run ( self , subcommand , H = None , forest_level = None , domain_level = None ,
quiet = False , credopts = None , sambaopts = None , versionopts = None ) :
2011-06-28 11:41:39 -04:00
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp , fallback_machine = True )
samdb = SamDB ( url = H , session_info = system_session ( ) ,
credentials = creds , lp = lp )
domain_dn = samdb . domain_dn ( )
2011-09-16 15:15:35 +10:00
res_forest = samdb . search ( " CN=Partitions, %s " % samdb . get_config_basedn ( ) ,
2011-06-28 11:41:39 -04:00
scope = ldb . SCOPE_BASE , attrs = [ " msDS-Behavior-Version " ] )
assert len ( res_forest ) == 1
res_domain = samdb . search ( domain_dn , scope = ldb . SCOPE_BASE ,
attrs = [ " msDS-Behavior-Version " , " nTMixedDomain " ] )
assert len ( res_domain ) == 1
2011-09-16 15:15:35 +10:00
res_dc_s = samdb . search ( " CN=Sites, %s " % samdb . get_config_basedn ( ) ,
2011-06-28 11:41:39 -04:00
scope = ldb . SCOPE_SUBTREE , expression = " (objectClass=nTDSDSA) " ,
attrs = [ " msDS-Behavior-Version " ] )
assert len ( res_dc_s ) > = 1
try :
level_forest = int ( res_forest [ 0 ] [ " msDS-Behavior-Version " ] [ 0 ] )
level_domain = int ( res_domain [ 0 ] [ " msDS-Behavior-Version " ] [ 0 ] )
level_domain_mixed = int ( res_domain [ 0 ] [ " nTMixedDomain " ] [ 0 ] )
min_level_dc = int ( res_dc_s [ 0 ] [ " msDS-Behavior-Version " ] [ 0 ] ) # Init value
for msg in res_dc_s :
if int ( msg [ " msDS-Behavior-Version " ] [ 0 ] ) < min_level_dc :
min_level_dc = int ( msg [ " msDS-Behavior-Version " ] [ 0 ] )
if level_forest < 0 or level_domain < 0 :
raise CommandError ( " Domain and/or forest function level(s) is/are invalid. Correct them or reprovision! " )
if min_level_dc < 0 :
raise CommandError ( " Lowest function level of a DC is invalid. Correct this or reprovision! " )
if level_forest > level_domain :
raise CommandError ( " Forest function level is higher than the domain level(s). Correct this or reprovision! " )
if level_domain > min_level_dc :
raise CommandError ( " Domain function level is higher than the lowest function level of a DC. Correct this or reprovision! " )
except KeyError :
raise CommandError ( " Could not retrieve the actual domain, forest level and/or lowest DC function level! " )
if subcommand == " show " :
self . message ( " Domain and forest function level for domain ' %s ' " % domain_dn )
if level_forest == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0 :
self . message ( " \n ATTENTION: You run SAMBA 4 on a forest function level lower than Windows 2000 (Native). This isn ' t supported! Please raise! " )
if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0 :
self . message ( " \n ATTENTION: You run SAMBA 4 on a domain function level lower than Windows 2000 (Native). This isn ' t supported! Please raise! " )
if min_level_dc == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0 :
self . message ( " \n ATTENTION: You run SAMBA 4 on a lowest function level of a DC lower than Windows 2003. This isn ' t supported! Please step-up or upgrade the concerning DC(s)! " )
self . message ( " " )
if level_forest == DS_DOMAIN_FUNCTION_2000 :
outstr = " 2000 "
elif level_forest == DS_DOMAIN_FUNCTION_2003_MIXED :
outstr = " 2003 with mixed domains/interim (NT4 DC support) "
elif level_forest == DS_DOMAIN_FUNCTION_2003 :
outstr = " 2003 "
elif level_forest == DS_DOMAIN_FUNCTION_2008 :
outstr = " 2008 "
elif level_forest == DS_DOMAIN_FUNCTION_2008_R2 :
outstr = " 2008 R2 "
else :
outstr = " higher than 2008 R2 "
self . message ( " Forest function level: (Windows) " + outstr )
if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0 :
outstr = " 2000 mixed (NT4 DC support) "
elif level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed == 0 :
outstr = " 2000 "
elif level_domain == DS_DOMAIN_FUNCTION_2003_MIXED :
outstr = " 2003 with mixed domains/interim (NT4 DC support) "
elif level_domain == DS_DOMAIN_FUNCTION_2003 :
outstr = " 2003 "
elif level_domain == DS_DOMAIN_FUNCTION_2008 :
outstr = " 2008 "
elif level_domain == DS_DOMAIN_FUNCTION_2008_R2 :
outstr = " 2008 R2 "
else :
outstr = " higher than 2008 R2 "
2011-09-09 15:27:25 +02:00
self . message ( " Domain function level: (Windows) " + outstr )
if min_level_dc == DS_DOMAIN_FUNCTION_2000 :
outstr = " 2000 "
elif min_level_dc == DS_DOMAIN_FUNCTION_2003 :
outstr = " 2003 "
elif min_level_dc == DS_DOMAIN_FUNCTION_2008 :
outstr = " 2008 "
elif min_level_dc == DS_DOMAIN_FUNCTION_2008_R2 :
outstr = " 2008 R2 "
else :
outstr = " higher than 2008 R2 "
2011-06-28 11:41:39 -04:00
self . message ( " Lowest function level of a DC: (Windows) " + outstr )
elif subcommand == " raise " :
msgs = [ ]
2011-09-11 17:31:38 +02:00
if domain_level is not None :
if domain_level == " 2003 " :
2011-06-28 11:41:39 -04:00
new_level_domain = DS_DOMAIN_FUNCTION_2003
2011-09-11 17:31:38 +02:00
elif domain_level == " 2008 " :
2011-06-28 11:41:39 -04:00
new_level_domain = DS_DOMAIN_FUNCTION_2008
2011-09-11 17:31:38 +02:00
elif domain_level == " 2008_R2 " :
2011-06-28 11:41:39 -04:00
new_level_domain = DS_DOMAIN_FUNCTION_2008_R2
if new_level_domain < = level_domain and level_domain_mixed == 0 :
2011-11-01 15:21:32 -04:00
raise CommandError ( " Domain function level can ' t be smaller than or equal to the actual one! " )
2011-06-28 11:41:39 -04:00
if new_level_domain > min_level_dc :
raise CommandError ( " Domain function level can ' t be higher than the lowest function level of a DC! " )
# Deactivate mixed/interim domain support
if level_domain_mixed != 0 :
# Directly on the base DN
m = ldb . Message ( )
m . dn = ldb . Dn ( samdb , domain_dn )
m [ " nTMixedDomain " ] = ldb . MessageElement ( " 0 " ,
ldb . FLAG_MOD_REPLACE , " nTMixedDomain " )
samdb . modify ( m )
# Under partitions
m = ldb . Message ( )
2012-03-02 20:00:04 +01:00
m . dn = ldb . Dn ( samdb , " CN= " + lp . get ( " workgroup " ) + " ,CN=Partitions, %s " % samdb . get_config_basedn ( ) )
2011-06-28 11:41:39 -04:00
m [ " nTMixedDomain " ] = ldb . MessageElement ( " 0 " ,
ldb . FLAG_MOD_REPLACE , " nTMixedDomain " )
try :
samdb . modify ( m )
except ldb . LdbError , ( enum , emsg ) :
if enum != ldb . ERR_UNWILLING_TO_PERFORM :
raise
# Directly on the base DN
m = ldb . Message ( )
m . dn = ldb . Dn ( samdb , domain_dn )
2011-09-09 15:27:25 +02:00
m [ " msDS-Behavior-Version " ] = ldb . MessageElement (
str ( new_level_domain ) , ldb . FLAG_MOD_REPLACE ,
2011-06-28 11:41:39 -04:00
" msDS-Behavior-Version " )
samdb . modify ( m )
# Under partitions
m = ldb . Message ( )
m . dn = ldb . Dn ( samdb , " CN= " + lp . get ( " workgroup " )
2012-03-02 20:00:04 +01:00
+ " ,CN=Partitions, %s " % samdb . get_config_basedn ( ) )
2011-06-28 11:41:39 -04:00
m [ " msDS-Behavior-Version " ] = ldb . MessageElement (
str ( new_level_domain ) , ldb . FLAG_MOD_REPLACE ,
" msDS-Behavior-Version " )
try :
samdb . modify ( m )
except ldb . LdbError , ( enum , emsg ) :
if enum != ldb . ERR_UNWILLING_TO_PERFORM :
raise
level_domain = new_level_domain
msgs . append ( " Domain function level changed! " )
2011-09-11 17:31:38 +02:00
if forest_level is not None :
if forest_level == " 2003 " :
2011-06-28 11:41:39 -04:00
new_level_forest = DS_DOMAIN_FUNCTION_2003
2011-09-11 17:31:38 +02:00
elif forest_level == " 2008 " :
2011-06-28 11:41:39 -04:00
new_level_forest = DS_DOMAIN_FUNCTION_2008
2011-09-11 17:31:38 +02:00
elif forest_level == " 2008_R2 " :
2011-06-28 11:41:39 -04:00
new_level_forest = DS_DOMAIN_FUNCTION_2008_R2
if new_level_forest < = level_forest :
2011-11-01 15:21:32 -04:00
raise CommandError ( " Forest function level can ' t be smaller than or equal to the actual one! " )
2011-06-28 11:41:39 -04:00
if new_level_forest > level_domain :
raise CommandError ( " Forest function level can ' t be higher than the domain function level(s). Please raise it/them first! " )
m = ldb . Message ( )
2012-03-02 20:00:04 +01:00
m . dn = ldb . Dn ( samdb , " CN=Partitions, %s " % samdb . get_config_basedn ( ) )
2011-06-28 11:41:39 -04:00
m [ " msDS-Behavior-Version " ] = ldb . MessageElement (
str ( new_level_forest ) , ldb . FLAG_MOD_REPLACE ,
" msDS-Behavior-Version " )
samdb . modify ( m )
msgs . append ( " Forest function level changed! " )
msgs . append ( " All changes applied successfully! " )
self . message ( " \n " . join ( msgs ) )
else :
2011-11-01 15:21:32 -04:00
raise CommandError ( " invalid argument: ' %s ' (choose from ' show ' , ' raise ' ) " % subcommand )
2011-06-28 11:41:39 -04:00
2011-06-27 16:32:22 -04:00
class cmd_domain_passwordsettings ( Command ) :
2012-10-08 12:32:58 +02:00
""" Set password settings.
2011-06-27 16:32:22 -04:00
Password complexity , history length , minimum password length , the minimum
and maximum password age ) on a Samba4 server .
"""
2011-10-13 23:27:22 +02:00
synopsis = " % prog (show|set <options>) [options] "
2011-06-27 16:32:22 -04:00
2012-02-06 16:33:38 +01:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions ,
" credopts " : options . CredentialsOptions ,
}
2011-06-27 16:32:22 -04:00
takes_options = [
2011-07-25 11:56:10 -04:00
Option ( " -H " , " --URL " , help = " LDB URL for database or target server " , type = str ,
metavar = " URL " , dest = " H " ) ,
2011-06-27 16:32:22 -04:00
Option ( " --quiet " , help = " Be quiet " , action = " store_true " ) ,
Option ( " --complexity " , type = " choice " , choices = [ " on " , " off " , " default " ] ,
help = " The password complexity (on | off | default). Default is ' on ' " ) ,
Option ( " --store-plaintext " , type = " choice " , choices = [ " on " , " off " , " default " ] ,
help = " Store plaintext passwords where account have ' store passwords with reversible encryption ' set (on | off | default). Default is ' off ' " ) ,
Option ( " --history-length " ,
help = " The password history length (<integer> | default). Default is 24. " , type = str ) ,
Option ( " --min-pwd-length " ,
help = " The minimum password length (<integer> | default). Default is 7. " , type = str ) ,
Option ( " --min-pwd-age " ,
help = " The minimum password age (<integer in days> | default). Default is 1. " , type = str ) ,
Option ( " --max-pwd-age " ,
help = " The maximum password age (<integer in days> | default). Default is 43. " , type = str ) ,
]
takes_args = [ " subcommand " ]
def run ( self , subcommand , H = None , min_pwd_age = None , max_pwd_age = None ,
quiet = False , complexity = None , store_plaintext = None , history_length = None ,
min_pwd_length = None , credopts = None , sambaopts = None ,
versionopts = None ) :
lp = sambaopts . get_loadparm ( )
creds = credopts . get_credentials ( lp )
samdb = SamDB ( url = H , session_info = system_session ( ) ,
credentials = creds , lp = lp )
domain_dn = samdb . domain_dn ( )
res = samdb . search ( domain_dn , scope = ldb . SCOPE_BASE ,
attrs = [ " pwdProperties " , " pwdHistoryLength " , " minPwdLength " ,
" minPwdAge " , " maxPwdAge " ] )
assert ( len ( res ) == 1 )
try :
pwd_props = int ( res [ 0 ] [ " pwdProperties " ] [ 0 ] )
pwd_hist_len = int ( res [ 0 ] [ " pwdHistoryLength " ] [ 0 ] )
cur_min_pwd_len = int ( res [ 0 ] [ " minPwdLength " ] [ 0 ] )
# ticks -> days
cur_min_pwd_age = int ( abs ( int ( res [ 0 ] [ " minPwdAge " ] [ 0 ] ) ) / ( 1e7 * 60 * 60 * 24 ) )
2011-11-17 09:34:57 +11:00
if int ( res [ 0 ] [ " maxPwdAge " ] [ 0 ] ) == - 0x8000000000000000 :
cur_max_pwd_age = 0
else :
cur_max_pwd_age = int ( abs ( int ( res [ 0 ] [ " maxPwdAge " ] [ 0 ] ) ) / ( 1e7 * 60 * 60 * 24 ) )
2011-06-27 16:32:22 -04:00
except Exception , e :
raise CommandError ( " Could not retrieve password properties! " , e )
if subcommand == " show " :
self . message ( " Password informations for domain ' %s ' " % domain_dn )
self . message ( " " )
if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0 :
self . message ( " Password complexity: on " )
else :
self . message ( " Password complexity: off " )
if pwd_props & DOMAIN_PASSWORD_STORE_CLEARTEXT != 0 :
self . message ( " Store plaintext passwords: on " )
else :
self . message ( " Store plaintext passwords: off " )
self . message ( " Password history length: %d " % pwd_hist_len )
self . message ( " Minimum password length: %d " % cur_min_pwd_len )
self . message ( " Minimum password age (days): %d " % cur_min_pwd_age )
self . message ( " Maximum password age (days): %d " % cur_max_pwd_age )
elif subcommand == " set " :
msgs = [ ]
m = ldb . Message ( )
m . dn = ldb . Dn ( samdb , domain_dn )
if complexity is not None :
if complexity == " on " or complexity == " default " :
pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX
msgs . append ( " Password complexity activated! " )
elif complexity == " off " :
pwd_props = pwd_props & ( ~ DOMAIN_PASSWORD_COMPLEX )
msgs . append ( " Password complexity deactivated! " )
if store_plaintext is not None :
if store_plaintext == " on " or store_plaintext == " default " :
pwd_props = pwd_props | DOMAIN_PASSWORD_STORE_CLEARTEXT
msgs . append ( " Plaintext password storage for changed passwords activated! " )
elif store_plaintext == " off " :
pwd_props = pwd_props & ( ~ DOMAIN_PASSWORD_STORE_CLEARTEXT )
msgs . append ( " Plaintext password storage for changed passwords deactivated! " )
if complexity is not None or store_plaintext is not None :
m [ " pwdProperties " ] = ldb . MessageElement ( str ( pwd_props ) ,
ldb . FLAG_MOD_REPLACE , " pwdProperties " )
if history_length is not None :
if history_length == " default " :
pwd_hist_len = 24
else :
pwd_hist_len = int ( history_length )
if pwd_hist_len < 0 or pwd_hist_len > 24 :
raise CommandError ( " Password history length must be in the range of 0 to 24! " )
m [ " pwdHistoryLength " ] = ldb . MessageElement ( str ( pwd_hist_len ) ,
ldb . FLAG_MOD_REPLACE , " pwdHistoryLength " )
msgs . append ( " Password history length changed! " )
if min_pwd_length is not None :
if min_pwd_length == " default " :
min_pwd_len = 7
else :
min_pwd_len = int ( min_pwd_length )
if min_pwd_len < 0 or min_pwd_len > 14 :
raise CommandError ( " Minimum password length must be in the range of 0 to 14! " )
m [ " minPwdLength " ] = ldb . MessageElement ( str ( min_pwd_len ) ,
ldb . FLAG_MOD_REPLACE , " minPwdLength " )
msgs . append ( " Minimum password length changed! " )
if min_pwd_age is not None :
if min_pwd_age == " default " :
min_pwd_age = 1
else :
min_pwd_age = int ( min_pwd_age )
if min_pwd_age < 0 or min_pwd_age > 998 :
raise CommandError ( " Minimum password age must be in the range of 0 to 998! " )
# days -> ticks
min_pwd_age_ticks = - int ( min_pwd_age * ( 24 * 60 * 60 * 1e7 ) )
m [ " minPwdAge " ] = ldb . MessageElement ( str ( min_pwd_age_ticks ) ,
ldb . FLAG_MOD_REPLACE , " minPwdAge " )
msgs . append ( " Minimum password age changed! " )
if max_pwd_age is not None :
if max_pwd_age == " default " :
max_pwd_age = 43
else :
max_pwd_age = int ( max_pwd_age )
if max_pwd_age < 0 or max_pwd_age > 999 :
raise CommandError ( " Maximum password age must be in the range of 0 to 999! " )
# days -> ticks
2011-11-17 09:34:57 +11:00
if max_pwd_age == 0 :
max_pwd_age_ticks = - 0x8000000000000000
else :
max_pwd_age_ticks = - int ( max_pwd_age * ( 24 * 60 * 60 * 1e7 ) )
2011-06-27 16:32:22 -04:00
m [ " maxPwdAge " ] = ldb . MessageElement ( str ( max_pwd_age_ticks ) ,
ldb . FLAG_MOD_REPLACE , " maxPwdAge " )
msgs . append ( " Maximum password age changed! " )
if max_pwd_age > 0 and min_pwd_age > = max_pwd_age :
raise CommandError ( " Maximum password age ( %d ) must be greater than minimum password age ( %d )! " % ( max_pwd_age , min_pwd_age ) )
2011-07-19 11:39:52 +10:00
if len ( m ) == 0 :
raise CommandError ( " You must specify at least one option to set. Try --help " )
2011-06-27 16:32:22 -04:00
samdb . modify ( m )
msgs . append ( " All changes applied successfully! " )
self . message ( " \n " . join ( msgs ) )
else :
raise CommandError ( " Wrong argument ' %s ' ! " % subcommand )
2012-06-16 13:06:44 +10:00
class cmd_domain_classicupgrade ( Command ) :
""" Upgrade from Samba classic (NT4-like) database to Samba AD DC database.
2011-09-12 16:03:34 +10:00
2012-06-16 13:06:44 +10:00
Specify either a directory with all Samba classic DC databases and state files ( with - - dbdir ) or
the testparm utility from your classic installation ( with - - testparm ) .
2011-10-13 23:08:32 +02:00
"""
2011-09-12 16:03:34 +10:00
2012-06-16 13:06:44 +10:00
synopsis = " % prog [options] <classic_smb_conf> "
2011-09-12 16:03:34 +10:00
takes_optiongroups = {
" sambaopts " : options . SambaOptions ,
" versionopts " : options . VersionOptions
}
takes_options = [
2011-10-19 09:37:47 +11:00
Option ( " --dbdir " , type = " string " , metavar = " DIR " ,
2012-06-16 13:06:44 +10:00
help = " Path to samba classic DC database directory " ) ,
2011-09-12 16:03:34 +10:00
Option ( " --testparm " , type = " string " , metavar = " PATH " ,
2012-06-16 13:06:44 +10:00
help = " Path to samba classic DC testparm utility from the previous installation. This allows the default paths of the previous installation to be followed " ) ,
2011-09-13 21:02:43 +10:00
Option ( " --targetdir " , type = " string " , metavar = " DIR " ,
help = " Path prefix where the new Samba 4.0 AD domain should be initialised " ) ,
2011-11-01 15:16:53 -04:00
Option ( " --quiet " , help = " Be quiet " , action = " store_true " ) ,
2011-11-17 18:51:14 +11:00
Option ( " --verbose " , help = " Be verbose " , action = " store_true " ) ,
2011-09-12 16:03:34 +10:00
Option ( " --use-xattrs " , type = " choice " , choices = [ " yes " , " no " , " auto " ] , metavar = " [yes|no|auto] " ,
help = " Define if we should use the native fs capabilities or a tdb file for storing attributes likes ntacl, auto tries to make an inteligent guess based on the user rights and system capabilities " , default = " auto " ) ,
2012-08-22 06:58:19 +10:00
Option ( " --use-ntvfs " , help = " Use NTVFS for the fileserver (default = no) " ,
action = " store_true " ) ,
2012-06-24 16:31:37 +10:00
Option ( " --dns-backend " , type = " choice " , metavar = " NAMESERVER-BACKEND " ,
choices = [ " SAMBA_INTERNAL " , " BIND9_FLATFILE " , " BIND9_DLZ " , " NONE " ] ,
2012-09-27 09:30:47 -07:00
help = " The DNS server backend. SAMBA_INTERNAL is the builtin name server (default), "
" BIND9_FLATFILE uses bind9 text database to store zone information, "
" BIND9_DLZ uses samba4 AD to store zone information, "
2012-06-24 16:31:37 +10:00
" NONE skips the DNS setup entirely (this DC will not be a DNS server) " ,
2012-09-11 09:07:47 +02:00
default = " SAMBA_INTERNAL " )
2011-09-12 16:03:34 +10:00
]
2011-09-13 21:02:43 +10:00
takes_args = [ " smbconf " ]
2011-09-12 16:03:34 +10:00
2012-09-25 22:34:36 +02:00
def run ( self , smbconf = None , targetdir = None , dbdir = None , testparm = None ,
2012-06-24 16:31:37 +10:00
quiet = False , verbose = False , use_xattrs = None , sambaopts = None , versionopts = None ,
2012-08-22 06:58:19 +10:00
dns_backend = None , use_ntvfs = False ) :
2011-09-12 16:03:34 +10:00
if not os . path . exists ( smbconf ) :
raise CommandError ( " File %s does not exist " % smbconf )
2012-02-06 22:06:09 +01:00
2011-09-12 16:03:34 +10:00
if testparm and not os . path . exists ( testparm ) :
raise CommandError ( " Testparm utility %s does not exist " % testparm )
2011-10-19 09:37:47 +11:00
if dbdir and not os . path . exists ( dbdir ) :
raise CommandError ( " Directory %s does not exist " % dbdir )
2011-09-12 16:03:34 +10:00
2011-10-19 09:37:47 +11:00
if not dbdir and not testparm :
raise CommandError ( " Please specify either dbdir or testparm " )
2011-09-12 16:03:34 +10:00
2011-10-12 23:21:52 +02:00
logger = self . get_logger ( )
2011-11-17 18:51:14 +11:00
if verbose :
logger . setLevel ( logging . DEBUG )
elif quiet :
2011-09-13 00:19:51 +02:00
logger . setLevel ( logging . WARNING )
2011-09-12 16:03:34 +10:00
else :
2011-09-13 00:19:51 +02:00
logger . setLevel ( logging . INFO )
2011-09-12 16:03:34 +10:00
2011-11-11 18:32:55 +01:00
if dbdir and testparm :
logger . warning ( " both dbdir and testparm specified, ignoring dbdir. " )
dbdir = None
2011-09-12 16:03:34 +10:00
lp = sambaopts . get_loadparm ( )
s3conf = s3param . get_context ( )
2011-09-13 21:02:43 +10:00
if sambaopts . realm :
s3conf . set ( " realm " , sambaopts . realm )
2011-09-12 16:03:34 +10:00
2012-02-07 01:09:41 +01:00
if targetdir is not None :
if not os . path . isdir ( targetdir ) :
os . mkdir ( targetdir )
2011-09-12 16:03:34 +10:00
eadb = True
if use_xattrs == " yes " :
2011-09-13 00:19:51 +02:00
eadb = False
2011-09-12 16:03:34 +10:00
elif use_xattrs == " auto " and not s3conf . get ( " posix:eadb " ) :
2011-10-14 11:22:20 +02:00
if targetdir :
2012-02-02 22:52:28 -03:00
tmpfile = tempfile . NamedTemporaryFile ( dir = os . path . abspath ( targetdir ) )
2011-10-14 11:22:20 +02:00
else :
2012-02-02 22:52:28 -03:00
tmpfile = tempfile . NamedTemporaryFile ( dir = os . path . abspath ( os . path . dirname ( lp . get ( " private dir " ) ) ) )
2011-09-13 00:19:51 +02:00
try :
2012-02-07 01:09:41 +01:00
try :
samba . ntacls . setntacl ( lp , tmpfile . name ,
" O:S-1-5-32G:S-1-5-32 " , " S-1-5-32 " , " native " )
eadb = False
except Exception :
# FIXME: Don't catch all exceptions here
logger . info ( " You are not root or your system do not support xattr, using tdb backend for attributes. "
" If you intend to use this provision in production, rerun the script as root on a system supporting xattrs. " )
finally :
tmpfile . close ( )
2011-09-12 16:03:34 +10:00
2011-10-19 09:37:47 +11:00
# Set correct default values from dbdir or testparm
2011-09-12 16:03:34 +10:00
paths = { }
2011-10-19 09:37:47 +11:00
if dbdir :
paths [ " state directory " ] = dbdir
paths [ " private dir " ] = dbdir
paths [ " lock directory " ] = dbdir
2012-06-16 15:34:50 +10:00
paths [ " smb passwd file " ] = dbdir + " /smbpasswd "
2011-09-12 16:03:34 +10:00
else :
2011-09-13 21:02:43 +10:00
paths [ " state directory " ] = get_testparm_var ( testparm , smbconf , " state directory " )
paths [ " private dir " ] = get_testparm_var ( testparm , smbconf , " private dir " )
2012-06-16 15:34:50 +10:00
paths [ " smb passwd file " ] = get_testparm_var ( testparm , smbconf , " smb passwd file " )
2011-09-13 21:02:43 +10:00
paths [ " lock directory " ] = get_testparm_var ( testparm , smbconf , " lock directory " )
2011-09-14 10:12:30 +02:00
# "testparm" from Samba 3 < 3.4.x is not aware of the parameter
# "state directory", instead make use of "lock directory"
if len ( paths [ " state directory " ] ) == 0 :
paths [ " state directory " ] = paths [ " lock directory " ]
2011-09-12 16:03:34 +10:00
for p in paths :
s3conf . set ( p , paths [ p ] )
2012-09-25 22:34:36 +02:00
2011-09-12 16:03:34 +10:00
# load smb.conf parameters
logger . info ( " Reading smb.conf " )
s3conf . load ( smbconf )
samba3 = Samba3 ( smbconf , s3conf )
2012-09-25 22:34:36 +02:00
2011-09-12 16:03:34 +10:00
logger . info ( " Provisioning " )
2012-09-25 22:34:36 +02:00
upgrade_from_samba3 ( samba3 , logger , targetdir , session_info = system_session ( ) ,
2012-08-22 06:58:19 +10:00
useeadb = eadb , dns_backend = dns_backend , use_ntvfs = use_ntvfs )
2011-09-12 16:03:34 +10:00
2012-09-25 22:34:36 +02:00
class cmd_domain_samba3upgrade ( cmd_domain_classicupgrade ) :
__doc__ = cmd_domain_classicupgrade . __doc__
# This command is present for backwards compatibility only,
# and should not be shown.
hidden = True
2011-06-27 16:32:22 -04:00
class cmd_domain ( SuperCommand ) :
2012-10-09 11:53:21 +02:00
""" Domain management. """
2011-06-27 16:32:22 -04:00
subcommands = { }
2011-12-04 23:00:57 +01:00
subcommands [ " demote " ] = cmd_domain_demote ( )
2012-09-25 22:34:36 +02:00
if cmd_domain_export_keytab is not None :
2012-05-18 15:24:38 +03:00
subcommands [ " exportkeytab " ] = cmd_domain_export_keytab ( )
2011-09-27 17:46:14 -07:00
subcommands [ " info " ] = cmd_domain_info ( )
2012-09-10 14:05:14 +02:00
subcommands [ " provision " ] = cmd_domain_provision ( )
2011-06-28 15:06:41 -04:00
subcommands [ " join " ] = cmd_domain_join ( )
2012-07-06 15:38:06 +10:00
subcommands [ " dcpromo " ] = cmd_domain_dcpromo ( )
2011-06-28 11:41:39 -04:00
subcommands [ " level " ] = cmd_domain_level ( )
2011-06-27 16:32:22 -04:00
subcommands [ " passwordsettings " ] = cmd_domain_passwordsettings ( )
2012-06-16 13:06:44 +10:00
subcommands [ " classicupgrade " ] = cmd_domain_classicupgrade ( )
2012-09-25 22:34:36 +02:00
subcommands [ " samba3upgrade " ] = cmd_domain_samba3upgrade ( )