2011-04-18 11:38:35 +04:00
#!/usr/bin/perl
# Bootstrap Samba and run a number of tests against it.
# Copyright (C) 2005-2007 Jelmer Vernooij <jelmer@samba.org>
# Published under the GNU GPL, v3 or later.
package Samba ;
use strict ;
2019-12-07 12:37:00 +03:00
use warnings ;
2011-04-18 11:38:35 +04:00
use target::Samba3 ;
use target::Samba4 ;
2012-03-04 10:30:45 +04:00
use POSIX ;
2013-11-08 12:49:25 +04:00
use Cwd qw( abs_path ) ;
2020-01-28 16:46:09 +03:00
use IO::Poll qw( POLLIN ) ;
2011-04-18 11:38:35 +04:00
sub new ($$$$$) {
2020-02-04 19:03:17 +03:00
my ( $ classname , $ bindir , $ srcdir , $ server_maxtime ,
$ opt_socket_wrapper_pcap , $ opt_socket_wrapper_keep_pcap ) = @ _ ;
2011-04-18 11:38:35 +04:00
my $ self = {
2020-02-04 19:03:17 +03:00
opt_socket_wrapper_pcap = > $ opt_socket_wrapper_pcap ,
opt_socket_wrapper_keep_pcap = > $ opt_socket_wrapper_keep_pcap ,
2011-04-18 11:38:35 +04:00
} ;
2019-10-30 23:53:39 +03:00
$ self - > { samba3 } = new Samba3 ( $ self , $ bindir , $ srcdir , $ server_maxtime ) ;
$ self - > { samba4 } = new Samba4 ( $ self , $ bindir , $ srcdir , $ server_maxtime ) ;
2011-04-18 11:38:35 +04:00
bless $ self ;
return $ self ;
}
2018-02-21 03:33:49 +03:00
% Samba:: ENV_DEPS = ( % Samba3:: ENV_DEPS , % Samba4:: ENV_DEPS ) ;
our % ENV_DEPS ;
2019-01-17 07:18:48 +03:00
% Samba:: ENV_DEPS_POST = ( % Samba3:: ENV_DEPS_POST , % Samba4:: ENV_DEPS_POST ) ;
our % ENV_DEPS_POST ;
2018-02-21 03:33:49 +03:00
% Samba:: ENV_TARGETS = (
( map { $ _ = > "Samba3" } keys % Samba3:: ENV_DEPS ) ,
( map { $ _ = > "Samba4" } keys % Samba4:: ENV_DEPS ) ,
) ;
our % ENV_TARGETS ;
% Samba:: ENV_NEEDS_AD_DC = (
( map { $ _ = > 1 } keys % Samba4:: ENV_DEPS )
) ;
our % ENV_NEEDS_AD_DC ;
foreach my $ env ( keys % Samba3:: ENV_DEPS ) {
$ ENV_NEEDS_AD_DC { $ env } = ( $ env =~ /^ad_/ ) ;
}
2020-02-04 19:03:17 +03:00
sub setup_pcap ($$)
{
my ( $ self , $ name ) = @ _ ;
return unless ( $ self - > { opt_socket_wrapper_pcap } ) ;
return unless defined ( $ ENV { SOCKET_WRAPPER_PCAP_DIR } ) ;
my $ fname = $ name ;
$ fname =~ s%[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\-]%_%g ;
my $ pcap_file = "$ENV{SOCKET_WRAPPER_PCAP_DIR}/$fname.pcap" ;
SocketWrapper:: setup_pcap ( $ pcap_file ) ;
return $ pcap_file ;
}
sub cleanup_pcap ($$$)
{
my ( $ self , $ pcap_file , $ exitcode ) = @ _ ;
return unless ( $ self - > { opt_socket_wrapper_pcap } ) ;
return if ( $ self - > { opt_socket_wrapper_keep_pcap } ) ;
return unless ( $ exitcode == 0 ) ;
return unless defined ( $ pcap_file ) ;
unlink ( $ pcap_file ) ;
}
2011-04-18 11:38:35 +04:00
sub setup_env ($$$)
{
my ( $ self , $ envname , $ path ) = @ _ ;
2018-02-21 03:33:49 +03:00
my $ targetname = $ ENV_TARGETS { $ envname } ;
if ( not defined ( $ targetname ) ) {
2011-04-18 11:38:35 +04:00
warn ( "Samba can't provide environment '$envname'" ) ;
2012-02-23 09:34:47 +04:00
return "UNKNOWN" ;
}
2018-02-21 03:33:49 +03:00
my % targetlookup = (
"Samba3" = > $ self - > { samba3 } ,
"Samba4" = > $ self - > { samba4 }
) ;
my $ target = $ targetlookup { $ targetname } ;
if ( defined ( $ target - > { vars } - > { $ envname } ) ) {
return $ target - > { vars } - > { $ envname } ;
}
2019-01-17 07:18:48 +03:00
$ target - > { vars } - > { $ envname } = "" ;
2018-02-21 03:33:49 +03:00
my @ dep_vars ;
foreach ( @ { $ ENV_DEPS { $ envname } } ) {
my $ vars = $ self - > setup_env ( $ _ , $ path ) ;
if ( defined ( $ vars ) ) {
push ( @ dep_vars , $ vars ) ;
} else {
warn ( "Failed setting up $_ as a dependency of $envname" ) ;
return undef ;
}
}
$ ENV { ENVNAME } = $ envname ;
# Avoid hitting system krb5.conf -
# An env that needs Kerberos will reset this to the real value.
$ ENV { KRB5_CONFIG } = "$path/no_krb5.conf" ;
my $ setup_name = $ ENV_TARGETS { $ envname } . "::setup_" . $ envname ;
my $ setup_sub = \ & $ setup_name ;
2019-11-14 19:36:36 +03:00
my $ setup_pcap_file = $ self - > setup_pcap ( "env-$ENV{ENVNAME}-setup" ) ;
2018-02-21 03:33:49 +03:00
my $ env = & $ setup_sub ( $ target , "$path/$envname" , @ dep_vars ) ;
2019-11-14 19:36:36 +03:00
$ self - > cleanup_pcap ( $ setup_pcap_file , not defined ( $ env ) ) ;
SocketWrapper:: setup_pcap ( undef ) ;
2018-02-21 03:33:49 +03:00
if ( not defined ( $ env ) ) {
2012-02-23 09:34:47 +04:00
warn ( "failed to start up environment '$envname'" ) ;
2011-04-18 11:38:35 +04:00
return undef ;
}
2018-02-21 03:33:49 +03:00
$ target - > { vars } - > { $ envname } = $ env ;
$ target - > { vars } - > { $ envname } - > { target } = $ target ;
2019-01-17 07:18:48 +03:00
foreach ( @ { $ ENV_DEPS_POST { $ envname } } ) {
2019-12-07 13:20:29 +03:00
if ( not defined $ _ ) {
continue ;
}
2019-01-17 07:18:48 +03:00
my $ vars = $ self - > setup_env ( $ _ , $ path ) ;
if ( not defined ( $ vars ) ) {
return undef ;
}
}
2011-04-18 11:38:35 +04:00
return $ env ;
}
2011-04-27 05:19:20 +04:00
sub bindir_path ($$) {
my ( $ object , $ path ) = @ _ ;
2012-01-26 02:42:27 +04:00
my $ valpath = "$object->{bindir}/$path" ;
2018-09-27 11:30:40 +03:00
my $ python_cmd = "" ;
my $ result = $ path ;
if ( defined $ ENV { 'PYTHON' } ) {
$ python_cmd = $ ENV { 'PYTHON' } . " " ;
}
2011-04-27 05:19:20 +04:00
2018-09-27 11:30:40 +03:00
if ( - f $ valpath or - d $ valpath ) {
$ result = $ valpath ;
}
# make sure we prepend samba-tool with calling $PYTHON python version
if ( $ path eq "samba-tool" ) {
$ result = $ python_cmd . $ result ;
}
return $ result ;
2011-04-27 05:19:20 +04:00
}
2012-10-03 10:36:34 +04:00
sub nss_wrapper_winbind_so_path ($) {
my ( $ object ) = @ _ ;
my $ ret = $ ENV { NSS_WRAPPER_WINBIND_SO_PATH } ;
if ( not defined ( $ ret ) ) {
2014-12-18 22:13:44 +03:00
$ ret = bindir_path ( $ object , "shared/libnss_wrapper_winbind.so.2" ) ;
2013-11-08 12:49:25 +04:00
$ ret = abs_path ( $ ret ) ;
2012-10-03 10:36:34 +04:00
}
return $ ret ;
}
2016-01-09 23:21:25 +03:00
sub copy_file_content ($$)
{
my ( $ in , $ out ) = @ _ ;
open ( IN , "${in}" ) or die ( "failed to open in[${in}] for reading: $!" ) ;
open ( OUT , ">${out}" ) or die ( "failed to open out[${out}] for writing: $!" ) ;
while ( <IN> ) {
print OUT $ _ ;
}
close ( OUT ) ;
close ( IN ) ;
}
sub prepare_keyblobs ($)
{
my ( $ ctx ) = @ _ ;
my $ cadir = "$ENV{SRCDIR_ABS}/selftest/manage-ca/CA-samba.example.com" ;
my $ cacert = "$cadir/Public/CA-samba.example.com-cert.pem" ;
my $ cacrl_pem = "$cadir/Public/CA-samba.example.com-crl.pem" ;
my $ dcdnsname = "$ctx->{hostname}.$ctx->{dnsname}" ;
my $ dcdir = "$cadir/DCs/$dcdnsname" ;
my $ dccert = "$dcdir/DC-$dcdnsname-cert.pem" ;
my $ dckey_private = "$dcdir/DC-$dcdnsname-private-key.pem" ;
2016-06-03 22:46:13 +03:00
my $ adminprincipalname = "administrator\@$ctx->{dnsname}" ;
my $ admindir = "$cadir/Users/$adminprincipalname" ;
my $ admincert = "$admindir/USER-$adminprincipalname-cert.pem" ;
my $ adminkey_private = "$admindir/USER-$adminprincipalname-private-key.pem" ;
2016-06-03 22:46:13 +03:00
my $ pkinitprincipalname = "pkinit\@$ctx->{dnsname}" ;
2019-12-07 13:15:00 +03:00
my $ ca_pkinitdir = "$cadir/Users/$pkinitprincipalname" ;
my $ pkinitcert = "$ca_pkinitdir/USER-$pkinitprincipalname-cert.pem" ;
my $ pkinitkey_private = "$ca_pkinitdir/USER-$pkinitprincipalname-private-key.pem" ;
2016-01-09 23:21:25 +03:00
my $ tlsdir = "$ctx->{tlsdir}" ;
my $ pkinitdir = "$ctx->{prefix_abs}/pkinit" ;
#TLS and PKINIT crypto blobs
my $ dhfile = "$tlsdir/dhparms.pem" ;
my $ cafile = "$tlsdir/ca.pem" ;
my $ crlfile = "$tlsdir/crl.pem" ;
my $ certfile = "$tlsdir/cert.pem" ;
my $ keyfile = "$tlsdir/key.pem" ;
2016-06-03 22:46:13 +03:00
my $ admincertfile = "$pkinitdir/USER-$adminprincipalname-cert.pem" ;
my $ adminkeyfile = "$pkinitdir/USER-$adminprincipalname-private-key.pem" ;
2016-06-03 22:46:13 +03:00
my $ pkinitcertfile = "$pkinitdir/USER-$pkinitprincipalname-cert.pem" ;
my $ pkinitkeyfile = "$pkinitdir/USER-$pkinitprincipalname-private-key.pem" ;
2016-01-09 23:21:25 +03:00
mkdir ( $ tlsdir , 0700 ) ;
mkdir ( $ pkinitdir , 0700 ) ;
my $ oldumask = umask ;
umask 0077 ;
# This is specified here to avoid draining entropy on every run
# generate by
# openssl dhparam -out dhparms.pem -text -2 8192
open ( DHFILE , ">$dhfile" ) ;
print DHFILE << EOF ;
- - - - - BEGIN DH PARAMETERS - - - - -
MIIECAKCBAEAlcpjuJptCzC2bIIApLuyFLw2nODQUztqs /peysY9e3LgWh/x rc87
SWJNSUrqFJFh2m357WH0XGcTdTk0b /8aIYIWjbwEhWR/ 5 hZ + 1 x2TDrX1awkYayAe
pr0arycmWHaAmhw + m + dBdj2O2jRMe7gn0ha85JALNl + Z3wv2q2eys8TIiQ2dbHPx
XvpMmlAv7QHZnpSpX /XgueQr6T3EYggljppZwk1fe4W2cxBjCv9w/ Q83pJXMEVVB
WESEQPZC38v6hVIXIlF4J7jXjV3 + NtCLL4nvsy0jrLEntyKz5OB8sNPRzJr0Ju2Y
yXORCSMMXMygP + dxJtQ6txzQYWyaCYN1HqHDZy3cFL9Qy8kTFqIcW56Lti2GsW / p
jSMzEOa1NevhKNFL3dSZJx5m + 5 ZeMvWXlCqXSptmVdbs5wz5jkMUm / E6pVfM5lyb
Ttlcq2iYPqnJz1jcL5xwhoufID8zSJCPJ7C0jb0Ngy5wLIUZfjXJUXxUyxTnNR9i
N9Sc + UkDvLxnCW + qzjyPXGlQU1SsJwMLWa2ZecL / uYE4bOdcN3g + 5 WHkevyDnXqR
+ yy9x7sGXjBT3bRWK5tVHJWOi6eBu1hp39U6aK8oOJWiUt3vmC2qEdIsT6JaLNNi
YKrSfRGBf19IJBaagen1S19bb3dnmwoU1RaWM0EeJQW1oXOBg7zLisB2yuu5azBn
tse00 + 0 nc + GbH2y + jP0sE7xil1QeilZl + aQ3tX9vL0cnCa + 8602 kXxU7P5HaX2 + d
05 pvoHmeZbDV85io36oF976gBYeYN + qAkTUMsIZhuLQDuyn0963XOLyn1Pm6SBrU
OkIZXW7WoKEuO /YSfizUIqXwmAMJjnEMJCWG51MZZKx/ /9Hsdp1RXSm/ bRSbvXB7
MscjvQYWmfCFnIk8LYnEt3Yey40srEiS9xyZqdrvobxz + sU1XcqR38kpVf4gKASL
xURia64s4emuJF + YHIObyydazQ + 6 /wX/ C + m + nyfhuxSO6j1janPwtYbU + Uj3TzeM
04 K1mpPQpZcaMdZZiNiu7i8VJlOPKAz7aJT8TnMMF5GMyzyLpSMpc + NF9L / BSocV
/ cUM4wQT2PTHrcyYzmTVH7c9bzBkuxqrwVB1BY1jitDV9LIYIVBglKcX88qrfHIM
XiXPAIwGclD59qm2cG8OdM9NA5pNMI119KuUAIJsUdgPbR1LkT2XTT15YVoHmFSQ
DlaWOXn4td031jr0EisX8QtFR7 + /0Nfoni6ydFGs5fNH/ L1ckq6FEO4OhgucJw9H
YRmiFlsQBQNny78vNchwZne3ZixkShtGW0hWDdi2n + h7St1peNJCNJjMbEhRsPRx
RmNGWh4AL8rho4RO9OBao0MnUdjbbffD + wIBAg ==
- - - - - END DH PARAMETERS - - - - -
EOF
close ( DHFILE ) ;
if ( ! - e $ { dckey_private } ) {
umask $ oldumask ;
return ;
}
copy_file_content ( $ { cacert } , $ { cafile } ) ;
copy_file_content ( $ { cacrl_pem } , $ { crlfile } ) ;
copy_file_content ( $ { dccert } , $ { certfile } ) ;
copy_file_content ( $ { dckey_private } , $ { keyfile } ) ;
2016-06-03 22:46:13 +03:00
if ( - e $ { adminkey_private } ) {
copy_file_content ( $ { admincert } , $ { admincertfile } ) ;
copy_file_content ( $ { adminkey_private } , $ { adminkeyfile } ) ;
2016-01-09 23:21:25 +03:00
}
2016-06-03 22:46:13 +03:00
if ( - e $ { pkinitkey_private } ) {
copy_file_content ( $ { pkinitcert } , $ { pkinitcertfile } ) ;
copy_file_content ( $ { pkinitkey_private } , $ { pkinitkeyfile } ) ;
}
2016-01-09 23:21:25 +03:00
# COMPAT stuff to be removed in a later commit
my $ kdccertfile = "$tlsdir/kdc.pem" ;
copy_file_content ( $ { dccert } , $ { kdccertfile } ) ;
umask $ oldumask ;
}
2011-08-26 10:02:01 +04:00
sub mk_krb5_conf ($$)
2011-04-19 10:38:46 +04:00
{
2015-03-24 21:05:10 +03:00
my ( $ ctx ) = @ _ ;
2011-04-19 10:38:46 +04:00
unless ( open ( KRB5CONF , ">$ctx->{krb5_conf}" ) ) {
2011-05-08 08:54:50 +04:00
warn ( "can't open $ctx->{krb5_conf}$?" ) ;
2011-04-19 10:38:46 +04:00
return undef ;
}
2011-08-26 10:02:01 +04:00
my $ our_realms_stanza = mk_realms_stanza ( $ ctx - > { realm } ,
$ ctx - > { dnsname } ,
$ ctx - > { domain } ,
$ ctx - > { kdc_ipv4 } ) ;
2011-04-19 10:38:46 +04:00
print KRB5CONF "
#Generated krb5.conf for $ctx->{realm}
[ libdefaults ]
default_realm = $ ctx - > { realm }
2015-07-09 11:11:22 +03:00
dns_lookup_realm = false
2015-03-24 21:05:10 +03:00
dns_lookup_kdc = true
2011-04-19 10:38:46 +04:00
ticket_lifetime = 24 h
forwardable = yes
2019-02-11 23:34:54 +03:00
2016-07-05 17:16:17 +03:00
# We are running on the same machine, do not correct
# system clock differences
kdc_timesync = 0
2011-04-19 10:38:46 +04:00
2016-04-27 02:00:14 +03:00
" ;
2019-02-11 23:34:54 +03:00
if ( defined ( $ ENV { MITKRB5 } ) ) {
print KRB5CONF "
# Set the grace clocskew to 5 seconds
# This is especially required by samba3.raw.session krb5 and
# reauth tests when not using Heimdal
clockskew = 5
" ;
}
2016-09-22 19:46:28 +03:00
if ( defined ( $ ctx - > { krb5_ccname } ) ) {
print KRB5CONF "
default_ccache_name = $ ctx - > { krb5_ccname }
" ;
}
2016-04-27 02:00:14 +03:00
if ( defined ( $ ctx - > { supported_enctypes } ) ) {
print KRB5CONF "
default_etypes = $ ctx - > { supported_enctypes }
default_as_etypes = $ ctx - > { supported_enctypes }
default_tgs_enctypes = $ ctx - > { supported_enctypes }
default_tkt_enctypes = $ ctx - > { supported_enctypes }
permitted_enctypes = $ ctx - > { supported_enctypes }
" ;
}
print KRB5CONF "
2011-04-19 10:38:46 +04:00
[ realms ]
2011-08-26 10:02:01 +04:00
$ our_realms_stanza
2011-04-19 10:38:46 +04:00
" ;
2011-08-26 10:02:01 +04:00
2011-04-19 10:38:46 +04:00
if ( defined ( $ ctx - > { tlsdir } ) ) {
print KRB5CONF "
[ appdefaults ]
pkinit_anchors = FILE: $ ctx - > { tlsdir } / ca . pem
[ kdc ]
enable - pkinit = true
pkinit_identity = FILE: $ ctx - > { tlsdir } /kdc.pem,$ctx->{tlsdir}/ key . pem
pkinit_anchors = FILE: $ ctx - > { tlsdir } / ca . pem
" ;
}
close ( KRB5CONF ) ;
}
2011-08-26 10:02:01 +04:00
sub mk_realms_stanza ($$$$)
{
my ( $ realm , $ dnsname , $ domain , $ kdc_ipv4 ) = @ _ ;
2015-01-21 07:27:09 +03:00
my $ lc_domain = lc ( $ domain ) ;
2016-10-12 08:00:34 +03:00
2011-08-26 10:02:01 +04:00
my $ realms_stanza = "
$ realm = {
kdc = $ kdc_ipv4:88
admin_server = $ kdc_ipv4:88
default_domain = $ dnsname
}
$ dnsname = {
kdc = $ kdc_ipv4:88
admin_server = $ kdc_ipv4:88
default_domain = $ dnsname
}
$ domain = {
kdc = $ kdc_ipv4:88
admin_server = $ kdc_ipv4:88
default_domain = $ dnsname
}
2015-01-21 07:27:09 +03:00
$ lc_domain = {
kdc = $ kdc_ipv4:88
admin_server = $ kdc_ipv4:88
default_domain = $ dnsname
}
2011-08-26 10:02:01 +04:00
" ;
return $ realms_stanza ;
}
2014-04-30 11:32:49 +04:00
sub mk_mitkdc_conf ($$)
{
# samba_kdb_dir is the path to mit_samba.so
my ( $ ctx , $ samba_kdb_dir ) = @ _ ;
unless ( open ( KDCCONF , ">$ctx->{mitkdc_conf}" ) ) {
warn ( "can't open $ctx->{mitkdc_conf}$?" ) ;
return undef ;
}
print KDCCONF "
# Generated kdc.conf for $ctx->{realm}
[ kdcdefaults ]
kdc_ports = 88
kdc_tcp_ports = 88
[ realms ]
$ ctx - > { realm } = {
}
$ ctx - > { dnsname } = {
}
$ ctx - > { domain } = {
}
[ dbmodules ]
db_module_dir = $ samba_kdb_dir
$ ctx - > { realm } = {
db_library = samba
}
$ ctx - > { dnsname } = {
db_library = samba
}
$ ctx - > { domain } = {
db_library = samba
}
[ logging ]
kdc = FILE: $ ctx - > { logdir } / mit_kdc . log
" ;
close ( KDCCONF ) ;
}
2019-10-31 17:37:40 +03:00
sub mk_resolv_conf ($$)
{
my ( $ ctx ) = @ _ ;
unless ( open ( RESOLV_CONF , ">$ctx->{resolv_conf}" ) ) {
warn ( "can't open $ctx->{resolv_conf}$?" ) ;
return undef ;
}
print RESOLV_CONF "nameserver $ctx->{dns_ipv4}\n" ;
print RESOLV_CONF "nameserver $ctx->{dns_ipv6}\n" ;
close ( RESOLV_CONF ) ;
}
2019-02-20 06:09:54 +03:00
sub realm_to_ip_mappings
{
2019-02-20 06:34:23 +03:00
# this maps the DNS realms for the various testenvs to the corresponding
# PDC (i.e. the first DC created for that realm).
my % realm_to_pdc_mapping = (
'adnonssdom.samba.example.com' = > 'addc_no_nss' ,
'adnontlmdom.samba.example.com' = > 'addc_no_ntlm' ,
'samba2000.example.com' = > 'dc5' ,
'samba2003.example.com' = > 'dc6' ,
'samba2008r2.example.com' = > 'dc7' ,
'addom.samba.example.com' = > 'addc' ,
'sub.samba.example.com' = > 'localsubdc' ,
'chgdcpassword.samba.example.com' = > 'chgdcpass' ,
'backupdom.samba.example.com' = > 'backupfromdc' ,
'renamedom.samba.example.com' = > 'renamedc' ,
'labdom.samba.example.com' = > 'labdc' ,
2019-01-17 07:18:48 +03:00
'schema.samba.example.com' = > 'liveupgrade1dc' ,
2020-02-27 03:47:31 +03:00
'prockilldom.samba.example.com' = > 'prockilldc' ,
'proclimit.samba.example.com' = > 'proclimitdc' ,
2019-02-20 06:34:23 +03:00
'samba.example.com' = > 'localdc' ,
2019-02-20 06:09:54 +03:00
) ;
my @ mapping = ( ) ;
2019-02-20 06:34:23 +03:00
# convert the hashmap to a list of key=value strings, where key is the
# realm and value is the IP address
while ( my ( $ realm , $ pdc ) = each ( % realm_to_pdc_mapping ) ) {
my $ ipaddr = get_ipv4_addr ( $ pdc ) ;
push ( @ mapping , "$realm=$ipaddr" ) ;
2019-02-20 06:09:54 +03:00
}
# return the mapping as a single comma-separated string
return join ( ',' , @ mapping ) ;
}
2012-03-02 04:44:56 +04:00
sub get_interface ($)
{
2019-02-14 06:19:50 +03:00
my ( $ netbiosname ) = @ _ ;
$ netbiosname = lc ( $ netbiosname ) ;
# this maps the SOCKET_WRAPPER_DEFAULT_IFACE value for each possible
# testenv to the DC's NETBIOS name. This value also corresponds to last
# digit of the DC's IP address. Note that the NETBIOS name may differ from
# the testenv name.
2019-02-20 06:09:54 +03:00
# Note that when adding a DC with a new realm, also update
# get_realm_ip_mappings() above.
2019-02-14 06:19:50 +03:00
my % testenv_iface_mapping = (
localnt4dc2 = > 3 ,
localnt4member3 = > 4 ,
localshare4 = > 5 ,
# 6 is spare
localktest6 = > 7 ,
maptoguest = > 8 ,
localnt4dc9 = > 9 ,
# 10 is spare
2019-03-18 07:55:39 +03:00
# 11-16 are used by selftest.pl for the client.conf. Most tests only
# use the first .11 IP. However, some tests (like winsreplication) rely
# on the client having multiple IPs.
2019-02-14 06:19:50 +03:00
client = > 11 ,
addc_no_nss = > 17 ,
addc_no_ntlm = > 18 ,
idmapadmember = > 19 ,
idmapridmember = > 20 ,
localdc = > 21 ,
localvampiredc = > 22 ,
s4member = > 23 ,
localrpcproxy = > 24 ,
dc5 = > 25 ,
dc6 = > 26 ,
dc7 = > 27 ,
rodc = > 28 ,
localadmember = > 29 ,
addc = > 30 ,
localsubdc = > 31 ,
chgdcpass = > 32 ,
promotedvdc = > 33 ,
rfc2307member = > 34 ,
fileserver = > 35 ,
fakednsforwarder1 = > 36 ,
fakednsforwarder2 = > 37 ,
s4member_dflt = > 38 ,
vampire2000dc = > 39 ,
backupfromdc = > 40 ,
restoredc = > 41 ,
renamedc = > 42 ,
labdc = > 43 ,
offlinebackupdc = > 44 ,
customdc = > 45 ,
prockilldc = > 46 ,
proclimitdc = > 47 ,
2019-01-17 07:18:48 +03:00
liveupgrade1dc = > 48 ,
liveupgrade2dc = > 49 ,
2016-07-12 14:12:24 +03:00
ctdb0 = > 50 ,
ctdb1 = > 51 ,
ctdb2 = > 52 ,
2019-02-14 06:19:50 +03:00
rootdnsforwarder = > 64 ,
2019-01-17 07:18:48 +03:00
# Note: that you also need to update dns_hub.py when adding a new
# multi-DC testenv
2019-02-14 06:19:50 +03:00
# update lib/socket_wrapper/socket_wrapper.c
# #define MAX_WRAPPED_INTERFACES 64
# if you wish to have more than 64 interfaces
) ;
if ( not defined ( $ testenv_iface_mapping { $ netbiosname } ) ) {
die ( ) ;
}
return $ testenv_iface_mapping { $ netbiosname } ;
2012-03-02 04:44:56 +04:00
}
2012-03-04 10:30:45 +04:00
2019-02-19 06:18:11 +03:00
sub get_ipv4_addr
{
2019-03-18 07:55:39 +03:00
my ( $ hostname , $ iface_num ) = @ _ ;
2019-02-19 06:18:11 +03:00
my $ swiface = Samba:: get_interface ( $ hostname ) ;
2019-03-18 07:55:39 +03:00
# Handle testenvs with multiple different addresses, i.e. IP multihoming.
# Currently only the selftest client has multiple IPv4 addresses.
if ( defined ( $ iface_num ) ) {
$ swiface += $ iface_num ;
}
2019-05-23 08:44:37 +03:00
if ( use_namespaces ( ) ) {
# use real IPs if selftest is running in its own network namespace
return "10.0.0.$swiface" ;
} else {
# use loopback IPs with socket-wrapper
return "127.0.0.$swiface" ;
}
2019-02-19 06:18:11 +03:00
}
sub get_ipv6_addr
{
( my $ hostname ) = @ _ ;
my $ swiface = Samba:: get_interface ( $ hostname ) ;
return sprintf ( "fd00:0000:0000:0000:0000:0000:5357:5f%02x" , $ swiface ) ;
}
2019-03-12 04:00:55 +03:00
# returns the 'interfaces' setting for smb.conf, i.e. the IPv4/IPv6
# addresses for testenv
sub get_interfaces_config
{
2019-03-18 07:55:39 +03:00
my ( $ hostname , $ num_ips ) = @ _ ;
my $ interfaces = "" ;
# We give the client.conf multiple different IPv4 addresses.
# All other testenvs generally just have one IPv4 address.
if ( ! defined ( $ num_ips ) ) {
$ num_ips = 1 ;
}
for ( my $ i = 0 ; $ i < $ num_ips ; $ i + + ) {
my $ ipv4_addr = Samba:: get_ipv4_addr ( $ hostname , $ i ) ;
2019-05-23 08:44:37 +03:00
if ( use_namespaces ( ) ) {
# use a /24 subnet with network namespaces
$ interfaces . = "$ipv4_addr/24 " ;
} else {
$ interfaces . = "$ipv4_addr/8 " ;
}
2019-03-18 07:55:39 +03:00
}
2019-03-12 04:00:55 +03:00
my $ ipv6_addr = Samba:: get_ipv6_addr ( $ hostname ) ;
2019-03-18 07:55:39 +03:00
$ interfaces . = "$ipv6_addr/64" ;
2019-03-12 04:00:55 +03:00
2019-03-18 07:55:39 +03:00
return $ interfaces ;
2019-03-12 04:00:55 +03:00
}
2012-03-04 10:30:45 +04:00
sub cleanup_child ($$)
{
my ( $ pid , $ name ) = @ _ ;
2014-09-04 14:55:53 +04:00
2016-05-14 01:49:40 +03:00
if ( ! defined ( $ pid ) ) {
print STDERR "cleanup_child: pid not defined ... not calling waitpid\n" ;
return - 1 ;
2014-09-04 14:55:53 +04:00
}
2016-05-14 01:49:40 +03:00
my $ childpid = waitpid ( $ pid , WNOHANG ) ;
2012-03-04 10:30:45 +04:00
if ( $ childpid == 0 ) {
} elsif ( $ childpid < 0 ) {
2016-05-14 01:38:48 +03:00
printf STDERR "%s child process %d isn't here any more\n" , $ name , $ pid ;
2012-03-04 10:30:45 +04:00
return $ childpid ;
2016-05-14 01:51:19 +03:00
} elsif ( $? & 127 ) {
2012-03-04 10:30:45 +04:00
printf STDERR "%s child process %d, died with signal %d, %s coredump\n" ,
2016-05-14 01:44:18 +03:00
$ name , $ childpid , ( $? & 127 ) , ( $? & 128 ) ? 'with' : 'without' ;
2012-03-04 10:30:45 +04:00
} else {
printf STDERR "%s child process %d exited with value %d\n" , $ name , $ childpid , $? >> 8 ;
}
return $ childpid ;
}
2018-02-26 16:56:27 +03:00
sub random_domain_sid ()
{
my $ domain_sid = "S-1-5-21-" . int ( rand ( 4294967295 ) ) . "-" . int ( rand ( 4294967295 ) ) . "-" . int ( rand ( 4294967295 ) ) ;
return $ domain_sid ;
}
2019-05-21 02:27:45 +03:00
# sets the environment variables ready for running a given process
sub set_env_for_process
{
2019-05-23 06:47:46 +03:00
my ( $ proc_name , $ env_vars , $ proc_envs ) = @ _ ;
2019-05-21 02:27:45 +03:00
2019-05-23 06:47:46 +03:00
if ( not defined ( $ proc_envs ) ) {
$ proc_envs = get_env_for_process ( $ proc_name , $ env_vars ) ;
}
2019-05-21 02:27:45 +03:00
foreach my $ key ( keys % { $ proc_envs } ) {
$ ENV { $ key } = $ proc_envs - > { $ key } ;
}
}
sub get_env_for_process
{
2019-05-23 06:47:46 +03:00
my ( $ proc_name , $ env_vars ) = @ _ ;
2019-05-21 02:27:45 +03:00
my $ proc_envs = {
2020-02-27 13:21:51 +03:00
RESOLV_CONF = > $ env_vars - > { RESOLV_CONF } ,
2019-05-21 02:27:45 +03:00
KRB5_CONFIG = > $ env_vars - > { KRB5_CONFIG } ,
KRB5CCNAME = > "$env_vars->{KRB5_CCACHE}.$proc_name" ,
SELFTEST_WINBINDD_SOCKET_DIR = > $ env_vars - > { SELFTEST_WINBINDD_SOCKET_DIR } ,
NMBD_SOCKET_DIR = > $ env_vars - > { NMBD_SOCKET_DIR } ,
NSS_WRAPPER_PASSWD = > $ env_vars - > { NSS_WRAPPER_PASSWD } ,
NSS_WRAPPER_GROUP = > $ env_vars - > { NSS_WRAPPER_GROUP } ,
NSS_WRAPPER_HOSTS = > $ env_vars - > { NSS_WRAPPER_HOSTS } ,
NSS_WRAPPER_HOSTNAME = > $ env_vars - > { NSS_WRAPPER_HOSTNAME } ,
NSS_WRAPPER_MODULE_SO_PATH = > $ env_vars - > { NSS_WRAPPER_MODULE_SO_PATH } ,
NSS_WRAPPER_MODULE_FN_PREFIX = > $ env_vars - > { NSS_WRAPPER_MODULE_FN_PREFIX } ,
UID_WRAPPER_ROOT = > "1" ,
ENVNAME = > "$ENV{ENVNAME}.$proc_name" ,
} ;
2019-05-23 06:47:46 +03:00
if ( defined ( $ env_vars - > { RESOLV_WRAPPER_CONF } ) ) {
$ proc_envs - > { RESOLV_WRAPPER_CONF } = $ env_vars - > { RESOLV_WRAPPER_CONF } ;
} else {
$ proc_envs - > { RESOLV_WRAPPER_HOSTS } = $ env_vars - > { RESOLV_WRAPPER_HOSTS } ;
2019-05-21 02:27:45 +03:00
}
return $ proc_envs ;
}
2019-05-23 07:35:07 +03:00
sub fork_and_exec
{
2020-01-30 17:49:59 +03:00
my ( $ self , $ env_vars , $ daemon_ctx , $ STDIN_READER , $ child_cleanup ) = @ _ ;
2019-10-30 23:53:39 +03:00
my $ SambaCtx = $ self ;
$ SambaCtx = $ self - > { SambaCtx } if defined ( $ self - > { SambaCtx } ) ;
2019-05-23 07:35:07 +03:00
2020-01-30 17:49:59 +03:00
# we close the child's write-end of the pipe and redirect the
# read-end to its stdin. That way the daemon will receive an
# EOF on stdin when parent selftest process closes its
# write-end.
$ child_cleanup // = sub { close ( $ env_vars - > { STDIN_PIPE } ) } ;
2019-05-23 07:35:07 +03:00
unlink ( $ daemon_ctx - > { LOG_FILE } ) ;
print "STARTING $daemon_ctx->{NAME} for $ENV{ENVNAME}..." ;
2019-05-23 08:44:37 +03:00
my $ parent_pid = $$ ;
2019-05-23 07:35:07 +03:00
my $ pid = fork ( ) ;
# exec the daemon in the child process
if ( $ pid == 0 ) {
2019-05-23 08:44:37 +03:00
my @ preargs = ( ) ;
2019-05-23 07:35:07 +03:00
# redirect the daemon's stdout/stderr to a log file
if ( defined ( $ daemon_ctx - > { TEE_STDOUT } ) ) {
# in some cases, we want out from samba to go to the log file,
# but also to the users terminal when running 'make test' on the
# command line. This puts it on stderr on the terminal
open STDOUT , "| tee $daemon_ctx->{LOG_FILE} 1>&2" ;
} else {
open STDOUT , ">$daemon_ctx->{LOG_FILE}" ;
}
open STDERR , '>&STDOUT' ;
SocketWrapper:: set_default_iface ( $ env_vars - > { SOCKET_WRAPPER_DEFAULT_IFACE } ) ;
if ( defined ( $ daemon_ctx - > { PCAP_FILE } ) ) {
2019-10-30 23:53:39 +03:00
$ SambaCtx - > setup_pcap ( "$daemon_ctx->{PCAP_FILE}" ) ;
2019-05-23 07:35:07 +03:00
}
# setup ENV variables in the child process
set_env_for_process ( $ daemon_ctx - > { NAME } , $ env_vars ,
$ daemon_ctx - > { ENV_VARS } ) ;
2020-01-30 17:49:59 +03:00
$ child_cleanup - > ( ) ;
2020-01-28 16:41:11 +03:00
2019-05-23 07:35:07 +03:00
# not all s3 daemons run in all testenvs (e.g. fileserver doesn't
# run winbindd). In which case, the child process just sleeps
if ( defined ( $ daemon_ctx - > { SKIP_DAEMON } ) ) {
$ SIG { USR1 } = $ SIG { ALRM } = $ SIG { INT } = $ SIG { QUIT } = $ SIG { TERM } = sub {
my $ signame = shift ;
print ( "Skip $daemon_ctx->{NAME} received signal $signame" ) ;
exit 0 ;
} ;
2020-01-28 16:46:09 +03:00
my $ poll = IO::Poll - > new ( ) ;
$ poll - > mask ( $ STDIN_READER , POLLIN ) ;
$ poll - > poll ( $ self - > { server_maxtime } ) ;
2019-05-23 07:35:07 +03:00
exit 0 ;
}
$ ENV { MAKE_TEST_BINARY } = $ daemon_ctx - > { BINARY_PATH } ;
open STDIN , ">&" , $ STDIN_READER or die "can't dup STDIN_READER to STDIN: $!" ;
2019-05-23 08:44:37 +03:00
# if using kernel namespaces, prepend the command so the process runs in
# its own namespace
if ( Samba:: use_namespaces ( ) ) {
@ preargs = ns_exec_preargs ( $ parent_pid , $ env_vars ) ;
}
2019-05-23 07:35:07 +03:00
# the command args are stored as an array reference (because...Perl),
# so convert the reference back to an array
my @ full_cmd = @ { $ daemon_ctx - > { FULL_CMD } } ;
2019-05-23 08:44:37 +03:00
exec ( @ preargs , @ full_cmd ) or die ( "Unable to start $ENV{MAKE_TEST_BINARY}: $!" ) ;
2019-05-23 07:35:07 +03:00
}
2019-05-23 08:44:37 +03:00
2019-05-23 07:35:07 +03:00
print "DONE ($pid)\n" ;
2019-05-23 08:44:37 +03:00
# if using kernel namespaces, we now establish a connection between the
# main selftest namespace (i.e. this process) and the new child namespace
if ( use_namespaces ( ) ) {
ns_child_forked ( $ pid , $ env_vars ) ;
}
2019-05-23 07:35:07 +03:00
return $ pid ;
}
2019-02-26 03:26:25 +03:00
my @ exported_envvars = (
# domain stuff
"DOMAIN" ,
"DNSNAME" ,
"REALM" ,
"DOMSID" ,
# stuff related to a trusted domain
"TRUST_SERVER" ,
"TRUST_USERNAME" ,
"TRUST_PASSWORD" ,
"TRUST_DOMAIN" ,
"TRUST_REALM" ,
"TRUST_DOMSID" ,
2017-03-20 13:39:41 +03:00
# stuff related to a trusted domain, on a trust_member
# the domain behind a forest trust (two-way)
"TRUST_F_BOTH_SERVER" ,
"TRUST_F_BOTH_SERVER_IP" ,
"TRUST_F_BOTH_SERVER_IPV6" ,
"TRUST_F_BOTH_NETBIOSNAME" ,
"TRUST_F_BOTH_USERNAME" ,
"TRUST_F_BOTH_PASSWORD" ,
"TRUST_F_BOTH_DOMAIN" ,
"TRUST_F_BOTH_REALM" ,
# stuff related to a trusted domain, on a trust_member
# the domain behind an external trust (two-way)
"TRUST_E_BOTH_SERVER" ,
"TRUST_E_BOTH_SERVER_IP" ,
"TRUST_E_BOTH_SERVER_IPV6" ,
"TRUST_E_BOTH_NETBIOSNAME" ,
"TRUST_E_BOTH_USERNAME" ,
"TRUST_E_BOTH_PASSWORD" ,
"TRUST_E_BOTH_DOMAIN" ,
"TRUST_E_BOTH_REALM" ,
2019-02-26 03:26:25 +03:00
# domain controller stuff
"DC_SERVER" ,
"DC_SERVER_IP" ,
"DC_SERVER_IPV6" ,
"DC_NETBIOSNAME" ,
"DC_NETBIOSALIAS" ,
# server stuff
"SERVER" ,
"SERVER_IP" ,
"SERVER_IPV6" ,
"NETBIOSNAME" ,
"NETBIOSALIAS" ,
"SAMSID" ,
# only use these 2 as a last resort. Some tests need to test both client-
# side and server-side. In this case, run as default client, ans access
# server's smb.conf as needed, typically using:
# param.LoadParm(filename_for_non_global_lp=os.environ['SERVERCONFFILE'])
"SERVERCONFFILE" ,
"DC_SERVERCONFFILE" ,
# user stuff
"USERNAME" ,
"USERID" ,
"PASSWORD" ,
"DC_USERNAME" ,
"DC_PASSWORD" ,
# UID/GID for rfc2307 mapping tests
"UID_RFC2307TEST" ,
"GID_RFC2307TEST" ,
# misc stuff
"KRB5_CONFIG" ,
"KRB5CCNAME" ,
"SELFTEST_WINBINDD_SOCKET_DIR" ,
"NMBD_SOCKET_DIR" ,
"LOCAL_PATH" ,
"DNS_FORWARDER1" ,
"DNS_FORWARDER2" ,
"RESOLV_CONF" ,
"UNACCEPTABLE_PASSWORD" ,
"LOCK_DIR" ,
"SMBD_TEST_LOG" ,
# nss_wrapper
"NSS_WRAPPER_PASSWD" ,
"NSS_WRAPPER_GROUP" ,
"NSS_WRAPPER_HOSTS" ,
"NSS_WRAPPER_HOSTNAME" ,
"NSS_WRAPPER_MODULE_SO_PATH" ,
"NSS_WRAPPER_MODULE_FN_PREFIX" ,
# resolv_wrapper
"RESOLV_WRAPPER_CONF" ,
"RESOLV_WRAPPER_HOSTS" ,
) ;
sub exported_envvars_str
{
my ( $ testenv_vars ) = @ _ ;
my $ out = "" ;
foreach ( @ exported_envvars ) {
next unless defined ( $ testenv_vars - > { $ _ } ) ;
$ out . = $ _ . "=" . $ testenv_vars - > { $ _ } . "\n" ;
}
return $ out ;
}
sub clear_exported_envvars
{
foreach ( @ exported_envvars ) {
delete $ ENV { $ _ } ;
}
}
sub export_envvars
{
my ( $ testenv_vars ) = @ _ ;
foreach ( @ exported_envvars ) {
if ( defined ( $ testenv_vars - > { $ _ } ) ) {
$ ENV { $ _ } = $ testenv_vars - > { $ _ } ;
} else {
delete $ ENV { $ _ } ;
}
}
}
2019-02-26 05:52:28 +03:00
sub export_envvars_to_file
{
my ( $ filepath , $ testenv_vars ) = @ _ ;
my $ env_str = exported_envvars_str ( $ testenv_vars ) ;
open ( FILE , "> $filepath" ) ;
print FILE "$env_str" ;
close ( FILE ) ;
}
2019-05-23 08:44:37 +03:00
# Returns true if kernel namespaces are being used instead of socket-wrapper.
# The default is false.
sub use_namespaces
{
return defined ( $ ENV { USE_NAMESPACES } ) ;
}
# returns a given testenv's interface-name (only when USE_NAMESPACES=1)
sub ns_interface_name
{
my ( $ hostname ) = @ _ ;
# when using namespaces, each testenv has its own vethX interface,
# where X = Samba::get_interface(testenv_name)
my $ iface = get_interface ( $ hostname ) ;
return "veth$iface" ;
}
# Called after a new child namespace has been forked
sub ns_child_forked
{
my ( $ child_pid , $ env_vars ) = @ _ ;
# we only need to do this for the first child forked for this testenv
if ( defined ( $ env_vars - > { NS_PID } ) ) {
return ;
}
# store the child PID. It's the only way the main (selftest) namespace can
# access the new child (testenv) namespace.
$ env_vars - > { NS_PID } = $ child_pid ;
# Add the new child namespace's interface to the main selftest bridge.
# This connects together the various testenvs so that selftest can talk to
# them all
my $ iface = ns_interface_name ( $ env_vars - > { NETBIOSNAME } ) ;
system "$ENV{SRCDIR}/selftest/ns/add_bridge_iface.sh $iface-br selftest0" ;
}
# returns args to prepend to a command in order to execute it the correct
# namespace for the testenv (creating a new namespace if needed).
# This should only used when USE_NAMESPACES=1 is set.
sub ns_exec_preargs
{
my ( $ parent_pid , $ env_vars ) = @ _ ;
# NS_PID stores the pid of the first child daemon run in this namespace
if ( defined ( $ env_vars - > { NS_PID } ) ) {
# the namespace has already been created previously. So we use nsenter
# to execute the command in the given testenv's namespace. We need to
# use the NS_PID to identify this particular namespace
return ( "nsenter" , "-t" , "$env_vars->{NS_PID}" , "--net" ) ;
} else {
# We need to create a new namespace for this daemon (i.e. we're
# setting up a new testenv). First, write the environment variables to
# an exports.sh file for this testenv (for convenient access by the
# namespace scripts).
my $ exports_file = "$env_vars->{TESTENV_DIR}/exports.sh" ;
export_envvars_to_file ( $ exports_file , $ env_vars ) ;
# when using namespaces, each testenv has its own veth interface
my $ interface = ns_interface_name ( $ env_vars - > { NETBIOSNAME } ) ;
# we use unshare to create a new network namespace. The start_in_ns.sh
# helper script gets run first to setup the new namespace's interfaces.
# (This all gets prepended around the actual command to run in the new
# namespace)
return ( "unshare" , "--net" , "$ENV{SRCDIR}/selftest/ns/start_in_ns.sh" ,
$ interface , $ exports_file , $ parent_pid ) ;
}
}
2019-12-07 13:17:26 +03:00
sub check_env {
my ( $ self , $ envvars ) = @ _ ;
return 1 ;
}
sub teardown_env {
my ( $ self , $ env ) = @ _ ;
return 1 ;
}
sub getlog_env {
return '' ;
}
2011-04-18 11:38:35 +04:00
1 ;