selftest: Remove trailing tabs/white spaces in Samba4.pm
[Samba.git] / selftest / target / Samba4.pm
blobc98c00c034c53110bec892fc6f305cf8036a5f8f
1 #!/usr/bin/perl
2 # Bootstrap Samba and run a number of tests against it.
3 # Copyright (C) 2005-2007 Jelmer Vernooij <jelmer@samba.org>
4 # Published under the GNU GPL, v3 or later.
6 # NOTE: Refer to the README for more details about the various testenvs,
7 # and tips about adding new testenvs.
9 package Samba4;
11 use strict;
12 use warnings;
13 use Cwd qw(abs_path);
14 use FindBin qw($RealBin);
15 use POSIX;
16 use SocketWrapper;
17 use target::Samba;
18 use target::Samba3;
19 use Archive::Tar;
21 sub new($$$$$) {
22 my ($classname, $SambaCtx, $bindir, $srcdir, $server_maxtime, $default_ldb_backend) = @_;
24 my $self = {
25 vars => {},
26 SambaCtx => $SambaCtx,
27 bindir => $bindir,
28 srcdir => $srcdir,
29 server_maxtime => $server_maxtime,
30 target3 => new Samba3($SambaCtx, $bindir, $srcdir, $server_maxtime),
31 default_ldb_backend => $default_ldb_backend,
33 bless $self;
34 return $self;
37 sub scriptdir_path($$) {
38 my ($self, $path) = @_;
39 return "$self->{srcdir}/source4/scripting/$path";
42 sub check_or_start($$$)
44 my ($self, $env_vars, $process_model) = @_;
45 my $STDIN_READER;
47 my $env_ok = $self->check_env($env_vars);
48 if ($env_ok) {
49 return $env_vars->{SAMBA_PID};
50 } elsif (defined($env_vars->{SAMBA_PID})) {
51 warn("SAMBA PID $env_vars->{SAMBA_PID} is not running (died)");
52 return undef;
55 # use a pipe for stdin in the child processes. This allows
56 # those processes to monitor the pipe for EOF to ensure they
57 # exit when the test script exits
58 pipe($STDIN_READER, $env_vars->{STDIN_PIPE});
60 # build up the command to run samba
61 my @preargs = ();
62 my @optargs = ();
63 if (defined($ENV{SAMBA_OPTIONS})) {
64 @optargs = split(/ /, $ENV{SAMBA_OPTIONS});
66 if(defined($ENV{SAMBA_VALGRIND})) {
67 @preargs = split(/ /,$ENV{SAMBA_VALGRIND});
70 if (defined($process_model)) {
71 push @optargs, ("-M", $process_model);
73 my $binary = Samba::bindir_path($self, "samba");
74 my @full_cmd = (@preargs, $binary, "-i",
75 "--no-process-group", "--maximum-runtime=$self->{server_maxtime}",
76 $env_vars->{CONFIGURATION}, @optargs);
78 # the samba process takes some additional env variables (compared to s3)
79 my $samba_envs = Samba::get_env_for_process("samba", $env_vars);
80 if (defined($ENV{MITKRB5})) {
81 $samba_envs->{KRB5_KDC_PROFILE} = $env_vars->{MITKDC_CONFIG};
84 # fork a child process and exec() samba
85 my $daemon_ctx = {
86 NAME => "samba",
87 BINARY_PATH => $binary,
88 FULL_CMD => [ @full_cmd ],
89 LOG_FILE => $env_vars->{SAMBA_TEST_LOG},
90 TEE_STDOUT => 1,
91 PCAP_FILE => "env-$ENV{ENVNAME}-samba",
92 ENV_VARS => $samba_envs,
94 my $pid = Samba::fork_and_exec($self, $env_vars, $daemon_ctx, $STDIN_READER);
96 $env_vars->{SAMBA_PID} = $pid;
98 # close the parent's read-end of the pipe
99 close($STDIN_READER);
101 if ($self->wait_for_start($env_vars) != 0) {
102 warn("Samba $pid failed to start up");
103 return undef;
106 return $pid;
109 sub wait_for_start($$)
111 my ($self, $testenv_vars) = @_;
112 my $count = 0;
113 my $ret = 0;
115 if (not $self->check_env($testenv_vars)) {
116 warn("unable to confirm Samba $testenv_vars->{SAMBA_PID} is running");
117 return -1;
120 # This will return quickly when things are up, but be slow if we
121 # need to wait for (eg) SSL init
122 my $nmblookup = Samba::bindir_path($self, "nmblookup4");
124 do {
125 $ret = system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{SERVER}");
126 if ($ret != 0) {
127 sleep(1);
128 } else {
129 system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{SERVER}");
130 system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
131 system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{NETBIOSNAME}");
132 system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
133 system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{NETBIOSNAME}");
134 system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{SERVER}");
135 system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{SERVER}");
136 system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
137 system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{NETBIOSNAME}");
138 system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
139 system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{NETBIOSNAME}");
141 $count++;
142 } while ($ret != 0 && $count < 20);
143 if ($count == 20) {
144 teardown_env($self, $testenv_vars);
145 warn("nbt not reachable after 20 retries\n");
146 return -1;
149 # Ensure we have the first RID Set before we start tests. This makes the tests more reliable.
150 if ($testenv_vars->{SERVER_ROLE} eq "domain controller") {
151 print "waiting for working LDAP and a RID Set to be allocated\n";
152 my $ldbsearch = Samba::bindir_path($self, "ldbsearch");
153 my $count = 0;
154 my $base_dn = "DC=".join(",DC=", split(/\./, $testenv_vars->{REALM}));
156 my $search_dn = $base_dn;
157 if ($testenv_vars->{NETBIOSNAME} ne "RODC") {
158 # TODO currently no check for actual rIDAllocationPool
159 $search_dn = "cn=RID Set,cn=$testenv_vars->{NETBIOSNAME},ou=domain controllers,$base_dn";
161 my $max_wait = 60;
163 # Add hosts file for name lookups
164 my $cmd = $self->get_cmd_env_vars($testenv_vars);
166 $cmd .= "$ldbsearch ";
167 $cmd .= "$testenv_vars->{CONFIGURATION} ";
168 $cmd .= "-H ldap://$testenv_vars->{SERVER} ";
169 $cmd .= "-U$testenv_vars->{USERNAME}%$testenv_vars->{PASSWORD} ";
170 $cmd .= "--scope base ";
171 $cmd .= "-b '$search_dn' ";
172 while (system("$cmd >/dev/null") != 0) {
173 $count++;
174 if ($count > $max_wait) {
175 teardown_env($self, $testenv_vars);
176 warn("Timed out ($max_wait sec) waiting for working LDAP and a RID Set to be allocated by $testenv_vars->{NETBIOSNAME} PID $testenv_vars->{SAMBA_PID}");
177 return -1;
179 print "Waiting for working LDAP...\n";
180 sleep(1);
184 my $wbinfo = Samba::bindir_path($self, "wbinfo");
186 $count = 0;
187 do {
188 my $cmd = "NSS_WRAPPER_PASSWD=$testenv_vars->{NSS_WRAPPER_PASSWD} ";
189 $cmd .= "NSS_WRAPPER_GROUP=$testenv_vars->{NSS_WRAPPER_GROUP} ";
190 $cmd .= "SELFTEST_WINBINDD_SOCKET_DIR=$testenv_vars->{SELFTEST_WINBINDD_SOCKET_DIR} ";
191 $cmd .= "$wbinfo -P";
192 $ret = system($cmd);
194 if ($ret != 0) {
195 sleep(1);
197 $count++;
198 } while ($ret != 0 && $count < 20);
199 if ($count == 20) {
200 teardown_env($self, $testenv_vars);
201 warn("winbind not reachable after 20 retries\n");
202 return -1;
205 # Ensure we registered all our names
206 if ($testenv_vars->{SERVER_ROLE} eq "domain controller") {
207 my $max_wait = 120;
208 my $dns_update_cache = "$testenv_vars->{PRIVATEDIR}/dns_update_cache";
209 print "Waiting for $dns_update_cache to be created.\n";
210 $count = 0;
211 while (not -e $dns_update_cache) {
212 $count++;
213 if ($count > $max_wait) {
214 teardown_env($self, $testenv_vars);
215 warn("Timed out ($max_wait sec) waiting for $dns_update_cache PID $testenv_vars->{SAMBA_PID}");
216 return -1;
218 print "Waiting for $dns_update_cache to be created...\n";
219 sleep(1);
221 print "Waiting for $dns_update_cache to be filled.\n";
222 $count = 0;
223 while ((-s "$dns_update_cache") == 0) {
224 $count++;
225 if ($count > $max_wait) {
226 teardown_env($self, $testenv_vars);
227 warn("Timed out ($max_wait sec) waiting for $dns_update_cache PID $testenv_vars->{SAMBA_PID}");
228 return -1;
230 print "Waiting for $dns_update_cache to be filled...\n";
231 sleep(1);
235 print $self->getlog_env($testenv_vars);
237 print "READY ($testenv_vars->{SAMBA_PID})\n";
239 return 0
242 sub write_ldb_file($$$)
244 my ($self, $file, $ldif_in) = @_;
246 my $ldbadd = Samba::bindir_path($self, "ldbadd");
247 open(my $ldif, "|$ldbadd -H $file > /dev/null")
248 or die "Failed to run $ldbadd: $!";
249 print $ldif $ldif_in;
250 close($ldif);
252 unless ($? == 0) {
253 warn("$ldbadd failed: $?");
254 return undef;
256 return 1;
259 sub add_wins_config($$)
261 my ($self, $privatedir) = @_;
262 my $client_ip = Samba::get_ipv4_addr("client");
264 return $self->write_ldb_file("$privatedir/wins_config.ldb", "
265 dn: name=TORTURE_11,CN=PARTNERS
266 objectClass: wreplPartner
267 name: TORTURE_11
268 address: $client_ip
269 pullInterval: 0
270 pushChangeCount: 0
271 type: 0x3
275 sub setup_dns_hub_internal($$$)
277 my ($self, $hostname, $prefix) = @_;
278 my $STDIN_READER;
280 unless(-d $prefix or mkdir($prefix, 0777)) {
281 warn("Unable to create $prefix");
282 return undef;
284 my $prefix_abs = abs_path($prefix);
286 die ("prefix=''") if $prefix_abs eq "";
287 die ("prefix='/'") if $prefix_abs eq "/";
289 unless (system("rm -rf $prefix_abs/*") == 0) {
290 warn("Unable to clean up");
293 my $env = undef;
294 $env->{NETBIOSNAME} = $hostname;
296 $env->{SERVER_IP} = Samba::get_ipv4_addr($hostname);
297 $env->{SERVER_IPV6} = Samba::get_ipv6_addr($hostname);
298 $env->{SOCKET_WRAPPER_DEFAULT_IFACE} = Samba::get_interface($hostname);
299 $env->{DNS_HUB_LOG} = "$prefix_abs/dns_hub.log";
300 $env->{RESOLV_CONF} = "$prefix_abs/resolv.conf";
301 $env->{TESTENV_DIR} = $prefix_abs;
303 my $ctx = undef;
304 $ctx->{resolv_conf} = $env->{RESOLV_CONF};
305 $ctx->{dns_ipv4} = $env->{SERVER_IP};
306 $ctx->{dns_ipv6} = $env->{SERVER_IPV6};
307 Samba::mk_resolv_conf($ctx);
309 my @preargs = ();
310 my @args = ();
311 if (!defined($ENV{PYTHON})) {
312 push (@preargs, "env");
313 push (@preargs, "python");
314 } else {
315 push (@preargs, $ENV{PYTHON});
317 my $binary = "$self->{srcdir}/selftest/target/dns_hub.py";
318 push (@args, "$self->{server_maxtime}");
319 push (@args, "$env->{SERVER_IP},$env->{SERVER_IPV6}");
320 push (@args, Samba::realm_to_ip_mappings());
321 my @full_cmd = (@preargs, $binary, @args);
323 my $daemon_ctx = {
324 NAME => "dnshub",
325 BINARY_PATH => $binary,
326 FULL_CMD => [ @full_cmd ],
327 LOG_FILE => $env->{DNS_HUB_LOG},
328 TEE_STDOUT => 1,
329 PCAP_FILE => "env-$ENV{ENVNAME}-dns_hub",
330 ENV_VARS => {},
333 # use a pipe for stdin in the child processes. This allows
334 # those processes to monitor the pipe for EOF to ensure they
335 # exit when the test script exits
336 pipe($STDIN_READER, $env->{STDIN_PIPE});
338 my $pid = Samba::fork_and_exec($self, $env, $daemon_ctx, $STDIN_READER);
340 $env->{SAMBA_PID} = $pid;
341 $env->{KRB5_CONFIG} = "$prefix_abs/no_krb5.conf";
343 # close the parent's read-end of the pipe
344 close($STDIN_READER);
346 return $env;
349 sub setup_dns_hub
351 my ($self, $prefix) = @_;
353 my $hostname = "rootdnsforwarder";
355 unless(-d $prefix or mkdir($prefix, 0777)) {
356 warn("Unable to create $prefix");
357 return undef;
359 my $env = $self->setup_dns_hub_internal("$hostname", "$prefix/$hostname");
361 $self->{dns_hub_env} = $env;
363 return $env;
366 sub get_dns_hub_env($)
368 my ($self, $prefix) = @_;
370 if (defined($self->{dns_hub_env})) {
371 return $self->{dns_hub_env};
374 die("get_dns_hub_env() not setup 'dns_hub_env'");
375 return undef;
378 sub return_env_value
380 my ($env, $overwrite, $key) = @_;
382 if (defined($overwrite) and defined($overwrite->{$key})) {
383 return $overwrite->{$key};
386 if (defined($env->{$key})) {
387 return $env->{$key};
390 return undef;
393 # Returns the environmental variables that we pass to samba-tool commands
394 sub get_cmd_env_vars
396 my ($self, $givenenv, $overwrite) = @_;
398 my @keys = (
399 "NSS_WRAPPER_HOSTS",
400 "SOCKET_WRAPPER_DEFAULT_IFACE",
401 "RESOLV_CONF",
402 "RESOLV_WRAPPER_CONF",
403 "RESOLV_WRAPPER_HOSTS",
404 "GNUTLS_FORCE_FIPS_MODE",
405 "OPENSSL_FORCE_FIPS_MODE",
406 "KRB5_CONFIG",
407 "KRB5_CCACHE",
408 "GNUPGHOME",
411 my $localenv = undef;
412 foreach my $key (@keys) {
413 my $v = return_env_value($givenenv, $overwrite, $key);
414 $localenv->{$key} = $v if defined($v);
417 my $cmd_env = "NSS_WRAPPER_HOSTS='$localenv->{NSS_WRAPPER_HOSTS}' ";
418 $cmd_env .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$localenv->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
419 if (defined($localenv->{RESOLV_WRAPPER_CONF})) {
420 $cmd_env .= "RESOLV_WRAPPER_CONF=\"$localenv->{RESOLV_WRAPPER_CONF}\" ";
421 } else {
422 $cmd_env .= "RESOLV_WRAPPER_HOSTS=\"$localenv->{RESOLV_WRAPPER_HOSTS}\" ";
424 if (defined($localenv->{GNUTLS_FORCE_FIPS_MODE})) {
425 $cmd_env .= "GNUTLS_FORCE_FIPS_MODE=$localenv->{GNUTLS_FORCE_FIPS_MODE} ";
427 if (defined($localenv->{OPENSSL_FORCE_FIPS_MODE})) {
428 $cmd_env .= "OPENSSL_FORCE_FIPS_MODE=$localenv->{OPENSSL_FORCE_FIPS_MODE} ";
430 $cmd_env .= "KRB5_CONFIG=\"$localenv->{KRB5_CONFIG}\" ";
431 $cmd_env .= "KRB5CCNAME=\"$localenv->{KRB5_CCACHE}\" ";
432 $cmd_env .= "RESOLV_CONF=\"$localenv->{RESOLV_CONF}\" ";
433 $cmd_env .= "GNUPGHOME=\"$localenv->{GNUPGHOME}\" ";
435 return $cmd_env;
438 # Sets up a forest trust namespace.
439 # (Note this is different to kernel namespaces, setup by the
440 # USE_NAMESPACES=1 option)
441 sub setup_namespaces
443 my ($self, $localenv, $upn_array, $spn_array) = @_;
445 @{$upn_array} = [] unless defined($upn_array);
446 my $upn_args = "";
447 foreach my $upn (@{$upn_array}) {
448 $upn_args .= " --add-upn-suffix=$upn";
451 @{$spn_array} = [] unless defined($spn_array);
452 my $spn_args = "";
453 foreach my $spn (@{$spn_array}) {
454 $spn_args .= " --add-spn-suffix=$spn";
457 my $samba_tool = Samba::bindir_path($self, "samba-tool");
459 my $cmd_env = $self->get_cmd_env_vars($localenv);
461 my $cmd_config = " $localenv->{CONFIGURATION}";
463 my $namespaces = $cmd_env;
464 $namespaces .= " $samba_tool domain trust namespaces $upn_args $spn_args";
465 $namespaces .= $cmd_config;
466 unless (system($namespaces) == 0) {
467 warn("Failed to add namespaces \n$namespaces");
468 return -1;
471 return 0;
474 sub setup_trust($$$$$)
476 my ($self, $localenv, $remoteenv, $type, $extra_args) = @_;
478 $localenv->{TRUST_SERVER} = $remoteenv->{SERVER};
479 $localenv->{TRUST_SERVER_IP} = $remoteenv->{SERVER_IP};
480 $localenv->{TRUST_DNSNAME} = $remoteenv->{DNSNAME};
482 $localenv->{TRUST_USERNAME} = $remoteenv->{USERNAME};
483 $localenv->{TRUST_PASSWORD} = $remoteenv->{PASSWORD};
484 $localenv->{TRUST_DOMAIN} = $remoteenv->{DOMAIN};
485 $localenv->{TRUST_REALM} = $remoteenv->{REALM};
486 $localenv->{TRUST_DOMSID} = $remoteenv->{DOMSID};
488 # Add trusted domain realms to krb5.conf
489 Samba::append_krb5_conf_trust_realms($localenv);
491 my $samba_tool = Samba::bindir_path($self, "samba-tool");
493 # setup the trust
494 my $cmd_env = $self->get_cmd_env_vars($localenv);
496 my $cmd_config = " $localenv->{CONFIGURATION}";
497 my $cmd_creds = $cmd_config;
498 $cmd_creds .= " -U$localenv->{TRUST_DOMAIN}\\\\$localenv->{TRUST_USERNAME}\%$localenv->{TRUST_PASSWORD}";
500 my $create = $cmd_env;
501 $create .= " $samba_tool domain trust create --type=${type} $localenv->{TRUST_REALM}";
502 $create .= " $extra_args";
503 $create .= $cmd_creds;
504 unless (system($create) == 0) {
505 warn("Failed to create trust \n$create");
506 return undef;
509 my $groupname = "g_$localenv->{TRUST_DOMAIN}";
510 my $groupadd = $cmd_env;
511 $groupadd .= " $samba_tool group add '$groupname' --group-scope=Domain $cmd_config";
512 unless (system($groupadd) == 0) {
513 warn("Failed to create group \n$groupadd");
514 return undef;
516 my $groupmem = $cmd_env;
517 $groupmem .= " $samba_tool group addmembers '$groupname' '$localenv->{TRUST_DOMSID}-513' $cmd_config";
518 unless (system($groupmem) == 0) {
519 warn("Failed to add group member \n$groupmem");
520 return undef;
523 return $localenv
526 sub provision_raw_prepare($$$$$$$$$$$$$$)
528 my ($self,
529 $prefix,
530 $server_role,
531 $hostname,
532 $domain,
533 $realm,
534 $samsid,
535 $functional_level,
536 $password,
537 $kdc_ipv4,
538 $kdc_ipv6,
539 $force_fips_mode,
540 $extra_provision_options) = @_;
541 my $ctx;
542 my $python_cmd = "";
543 if (defined $ENV{PYTHON}) {
544 $python_cmd = $ENV{PYTHON} . " ";
546 $ctx->{python} = $python_cmd;
547 my $netbiosname = uc($hostname);
549 unless(-d $prefix or mkdir($prefix, 0777)) {
550 warn("Unable to create $prefix");
551 return undef;
553 my $prefix_abs = abs_path($prefix);
555 die ("prefix=''") if $prefix_abs eq "";
556 die ("prefix='/'") if $prefix_abs eq "/";
558 unless (system("rm -rf $prefix_abs/*") == 0) {
559 warn("Unable to clean up");
563 my $swiface = Samba::get_interface($hostname);
565 $ctx->{prefix} = $prefix;
566 $ctx->{prefix_abs} = $prefix_abs;
568 $ctx->{server_role} = $server_role;
569 $ctx->{hostname} = $hostname;
570 $ctx->{netbiosname} = $netbiosname;
571 $ctx->{swiface} = $swiface;
572 $ctx->{password} = $password;
573 $ctx->{kdc_ipv4} = $kdc_ipv4;
574 $ctx->{kdc_ipv6} = $kdc_ipv6;
575 $ctx->{force_fips_mode} = $force_fips_mode;
576 $ctx->{krb5_ccname} = "$prefix_abs/krb5cc_%{uid}";
577 if ($functional_level eq "2000") {
578 $ctx->{supported_enctypes} = "arcfour-hmac-md5 des-cbc-md5 des-cbc-crc";
582 # Set smbd log level here.
584 $ctx->{server_loglevel} =$ENV{SERVER_LOG_LEVEL} || 1;
585 $ctx->{username} = "Administrator";
586 $ctx->{domain} = $domain;
587 $ctx->{realm} = uc($realm);
588 $ctx->{dnsname} = lc($realm);
589 $ctx->{samsid} = $samsid;
591 $ctx->{functional_level} = $functional_level;
593 my $unix_name = ($ENV{USER} or $ENV{LOGNAME} or `whoami`);
594 chomp $unix_name;
595 $ctx->{unix_name} = $unix_name;
596 $ctx->{unix_uid} = $>;
597 my @mygid = split(" ", $();
598 $ctx->{unix_gid} = $mygid[0];
599 $ctx->{unix_gids_str} = $);
600 @{$ctx->{unix_gids}} = split(" ", $ctx->{unix_gids_str});
602 $ctx->{etcdir} = "$prefix_abs/etc";
603 $ctx->{piddir} = "$prefix_abs/pid";
604 $ctx->{smb_conf} = "$ctx->{etcdir}/smb.conf";
605 $ctx->{krb5_conf} = "$ctx->{etcdir}/krb5.conf";
606 $ctx->{krb5_ccache} = "$prefix_abs/krb5_ccache";
607 $ctx->{mitkdc_conf} = "$ctx->{etcdir}/mitkdc.conf";
608 $ctx->{gnupghome} = "$prefix_abs/gnupg";
609 $ctx->{privatedir} = "$prefix_abs/private";
610 $ctx->{binddnsdir} = "$prefix_abs/bind-dns";
611 $ctx->{ncalrpcdir} = "$prefix_abs/ncalrpc";
612 $ctx->{lockdir} = "$prefix_abs/lockdir";
613 $ctx->{logdir} = "$prefix_abs/logs";
614 $ctx->{statedir} = "$prefix_abs/statedir";
615 $ctx->{cachedir} = "$prefix_abs/cachedir";
616 $ctx->{winbindd_socket_dir} = "$prefix_abs/wbsock";
617 $ctx->{ntp_signd_socket_dir} = "$prefix_abs/ntp_signd_socket";
618 $ctx->{nsswrap_passwd} = "$ctx->{etcdir}/passwd";
619 $ctx->{nsswrap_group} = "$ctx->{etcdir}/group";
620 $ctx->{nsswrap_hosts} = "$ENV{SELFTEST_PREFIX}/hosts";
621 $ctx->{nsswrap_hostname} = "$ctx->{hostname}.$ctx->{dnsname}";
622 if ($ENV{SAMBA_DNS_FAKING}) {
623 $ctx->{dns_host_file} = "$ENV{SELFTEST_PREFIX}/dns_host_file";
624 $ctx->{samba_dnsupdate} = "$ENV{SRCDIR_ABS}/source4/scripting/bin/samba_dnsupdate --configfile=$ctx->{smb_conf} --all-interfaces --use-file=$ctx->{dns_host_file}";
625 $ctx->{samba_dnsupdate} = $python_cmd . $ctx->{samba_dnsupdate};
626 } else {
627 $ctx->{samba_dnsupdate} = "$ENV{SRCDIR_ABS}/source4/scripting/bin/samba_dnsupdate --configfile=$ctx->{smb_conf} --all-interfaces";
628 $ctx->{samba_dnsupdate} = $python_cmd . $ctx->{samba_dnsupdate};
629 $ctx->{use_resolv_wrapper} = 1;
632 my $dns_hub = $self->get_dns_hub_env();
633 $ctx->{resolv_conf} = $dns_hub->{RESOLV_CONF};
635 $ctx->{tlsdir} = "$ctx->{privatedir}/tls";
637 $ctx->{ipv4} = Samba::get_ipv4_addr($hostname);
638 $ctx->{ipv6} = Samba::get_ipv6_addr($hostname);
640 push(@{$ctx->{directories}}, $ctx->{privatedir});
641 push(@{$ctx->{directories}}, $ctx->{binddnsdir});
642 push(@{$ctx->{directories}}, $ctx->{etcdir});
643 push(@{$ctx->{directories}}, $ctx->{piddir});
644 push(@{$ctx->{directories}}, $ctx->{lockdir});
645 push(@{$ctx->{directories}}, $ctx->{logdir});
646 push(@{$ctx->{directories}}, $ctx->{statedir});
647 push(@{$ctx->{directories}}, $ctx->{cachedir});
649 $ctx->{smb_conf_extra_options} = "";
651 my @provision_options = ();
652 push (@provision_options, "GNUPGHOME=\"$ctx->{gnupghome}\"");
653 push (@provision_options, "KRB5_CONFIG=\"$ctx->{krb5_conf}\"");
654 push (@provision_options, "KRB5CCNAME=\"$ctx->{krb5_ccache}\"");
655 push (@provision_options, "NSS_WRAPPER_PASSWD=\"$ctx->{nsswrap_passwd}\"");
656 push (@provision_options, "NSS_WRAPPER_GROUP=\"$ctx->{nsswrap_group}\"");
657 push (@provision_options, "NSS_WRAPPER_HOSTS=\"$ctx->{nsswrap_hosts}\"");
658 push (@provision_options, "NSS_WRAPPER_HOSTNAME=\"$ctx->{nsswrap_hostname}\"");
659 if (defined($ctx->{use_resolv_wrapper})) {
660 push (@provision_options, "RESOLV_WRAPPER_CONF=\"$ctx->{resolv_conf}\"");
661 push (@provision_options, "RESOLV_CONF=\"$ctx->{resolv_conf}\"");
662 } else {
663 push (@provision_options, "RESOLV_WRAPPER_HOSTS=\"$ctx->{dns_host_file}\"");
665 if (defined($ctx->{force_fips_mode})) {
666 push (@provision_options, "GNUTLS_FORCE_FIPS_MODE=1");
667 push (@provision_options, "OPENSSL_FORCE_FIPS_MODE=1");
670 if (defined($ENV{GDB_PROVISION})) {
671 push (@provision_options, "gdb --args");
672 if (!defined($ENV{PYTHON})) {
673 push (@provision_options, "env");
674 push (@provision_options, "python");
677 if (defined($ENV{VALGRIND_PROVISION})) {
678 push (@provision_options, "valgrind");
679 if (!defined($ENV{PYTHON})) {
680 push (@provision_options, "env");
681 push (@provision_options, "python");
685 my $samba_tool = Samba::bindir_path($self, "samba-tool");
687 push (@provision_options, $samba_tool);
688 push (@provision_options, "domain");
689 push (@provision_options, "provision");
690 push (@provision_options, "--configfile=$ctx->{smb_conf}");
691 push (@provision_options, "--host-name=$ctx->{hostname}");
692 push (@provision_options, "--host-ip=$ctx->{ipv4}");
693 push (@provision_options, "--quiet");
694 push (@provision_options, "--domain=$ctx->{domain}");
695 push (@provision_options, "--realm=$ctx->{realm}");
696 if (defined($ctx->{samsid})) {
697 push (@provision_options, "--domain-sid=$ctx->{samsid}");
699 push (@provision_options, "--adminpass=$ctx->{password}");
700 push (@provision_options, "--krbtgtpass=krbtgt$ctx->{password}");
701 push (@provision_options, "--machinepass=machine$ctx->{password}");
702 push (@provision_options, "--root=$ctx->{unix_name}");
703 push (@provision_options, "--server-role=\"$ctx->{server_role}\"");
704 push (@provision_options, "--function-level=\"$ctx->{functional_level}\"");
706 @{$ctx->{provision_options}} = @provision_options;
708 if (defined($extra_provision_options)) {
709 push (@{$ctx->{provision_options}}, @{$extra_provision_options});
712 return $ctx;
715 sub has_option
717 my ($self, $keyword, @options_list) = @_;
719 # convert the options-list to a hash-map for easy keyword lookup
720 my %options_dict = map { $_ => 1 } @options_list;
722 return exists $options_dict{$keyword};
726 # Step1 creates the basic configuration
728 sub provision_raw_step1($$)
730 my ($self, $ctx) = @_;
732 mkdir($_, 0777) foreach (@{$ctx->{directories}});
735 ## lockdir and piddir must be 0755
737 chmod 0755, $ctx->{lockdir};
738 chmod 0755, $ctx->{piddir};
740 unless (open(CONFFILE, ">$ctx->{smb_conf}")) {
741 warn("can't open $ctx->{smb_conf}$?");
742 return undef;
745 Samba::copy_gnupg_home($ctx);
746 Samba::prepare_keyblobs($ctx);
747 my $crlfile = "$ctx->{tlsdir}/crl.pem";
748 $crlfile = "" unless -e ${crlfile};
750 # work out which file server to use. Default to source3 smbd (s3fs),
751 # unless the source4 NTVFS (smb) file server has been specified
752 my $services = "-smb +s3fs";
753 if ($self->has_option("--use-ntvfs", @{$ctx->{provision_options}})) {
754 $services = "+smb -s3fs";
757 my $interfaces = Samba::get_interfaces_config($ctx->{netbiosname});
759 print CONFFILE "
760 [global]
761 netbios name = $ctx->{netbiosname}
762 posix:eadb = $ctx->{statedir}/eadb.tdb
763 workgroup = $ctx->{domain}
764 realm = $ctx->{realm}
765 private dir = $ctx->{privatedir}
766 binddns dir = $ctx->{binddnsdir}
767 pid directory = $ctx->{piddir}
768 ncalrpc dir = $ctx->{ncalrpcdir}
769 lock dir = $ctx->{lockdir}
770 state directory = $ctx->{statedir}
771 cache directory = $ctx->{cachedir}
772 winbindd socket directory = $ctx->{winbindd_socket_dir}
773 ntp signd socket directory = $ctx->{ntp_signd_socket_dir}
774 winbind separator = /
775 interfaces = $interfaces
776 tls dh params file = $ctx->{tlsdir}/dhparms.pem
777 tls crlfile = ${crlfile}
778 tls verify peer = no_check
779 panic action = $RealBin/gdb_backtrace \%d
780 smbd:suicide mode = yes
781 smbd:FSCTL_SMBTORTURE = yes
782 smbd:validate_oplock_types = yes
783 wins support = yes
784 server role = $ctx->{server_role}
785 server services = +echo $services
786 dcerpc endpoint servers = +winreg +srvsvc +rpcecho
787 notify:inotify = false
788 ldb:nosync = true
789 ldap server require strong auth = yes
790 log file = $ctx->{logdir}/log.\%m
791 log level = $ctx->{server_loglevel}
792 lanman auth = Yes
793 ntlm auth = Yes
794 client min protocol = SMB2_02
795 server min protocol = SMB2_02
796 mangled names = yes
797 dns update command = $ctx->{samba_dnsupdate}
798 spn update command = $ctx->{python} $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_spnupdate --configfile $ctx->{smb_conf}
799 gpo update command = $ctx->{python} $ENV{SRCDIR_ABS}/source4/scripting/bin/samba-gpupdate --configfile $ctx->{smb_conf} --target=Computer
800 samba kcc command = $ctx->{python} $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_kcc
801 dreplsrv:periodic_startup_interval = 0
802 dsdb:schema update allowed = yes
804 vfs objects = dfs_samba4 acl_xattr fake_acls xattr_tdb streams_depot
806 idmap_ldb:use rfc2307=yes
807 winbind enum users = yes
808 winbind enum groups = yes
810 rpc server port:netlogon = 1026
811 include system krb5 conf = no
813 debug syslog format = always
814 debug hires timestamp = yes
818 print CONFFILE "
820 # Begin extra options
821 $ctx->{smb_conf_extra_options}
822 # End extra options
824 close(CONFFILE);
826 #Default the KDC IP to the server's IP
827 if (not defined($ctx->{kdc_ipv4})) {
828 $ctx->{kdc_ipv4} = $ctx->{ipv4};
830 if (not defined($ctx->{kdc_ipv6})) {
831 $ctx->{kdc_ipv6} = $ctx->{ipv6};
834 Samba::mk_krb5_conf($ctx);
835 Samba::mk_mitkdc_conf($ctx, abs_path(Samba::bindir_path($self, "shared")));
837 open(PWD, ">$ctx->{nsswrap_passwd}");
838 if ($ctx->{unix_uid} != 0) {
839 print PWD "root:x:0:0:root gecos:$ctx->{prefix_abs}:/bin/false\n";
841 print PWD "$ctx->{unix_name}:x:$ctx->{unix_uid}:65531:$ctx->{unix_name} gecos:$ctx->{prefix_abs}:/bin/false\n";
842 print PWD "nobody:x:65534:65533:nobody gecos:$ctx->{prefix_abs}:/bin/false
843 pdbtest:x:65533:65533:pdbtest gecos:$ctx->{prefix_abs}:/bin/false
844 pdbtest2:x:65532:65533:pdbtest gecos:$ctx->{prefix_abs}:/bin/false
845 pdbtest3:x:65531:65533:pdbtest gecos:$ctx->{prefix_abs}:/bin/false
846 pdbtest4:x:65530:65533:pdbtest gecos:$ctx->{prefix_abs}:/bin/false
848 close(PWD);
849 my $uid_rfc2307test = 65533;
851 open(GRP, ">$ctx->{nsswrap_group}");
852 if ($ctx->{unix_gid} != 0) {
853 print GRP "root:x:0:\n";
855 print GRP "$ctx->{unix_name}:x:$ctx->{unix_gid}:\n";
856 print GRP "wheel:x:10:
857 users:x:65531:
858 nobody:x:65533:
859 nogroup:x:65534:nobody
861 close(GRP);
862 my $gid_rfc2307test = 65532;
864 my $hostname = lc($ctx->{hostname});
865 open(HOSTS, ">>$ctx->{nsswrap_hosts}");
866 if ($hostname eq "localdc") {
867 print HOSTS "$ctx->{ipv4} ${hostname}.$ctx->{dnsname} $ctx->{dnsname} ${hostname}\n";
868 print HOSTS "$ctx->{ipv6} ${hostname}.$ctx->{dnsname} $ctx->{dnsname} ${hostname}\n";
869 } else {
870 print HOSTS "$ctx->{ipv4} ${hostname}.$ctx->{dnsname} ${hostname}\n";
871 print HOSTS "$ctx->{ipv6} ${hostname}.$ctx->{dnsname} ${hostname}\n";
873 close(HOSTS);
875 my $configuration = "--configfile=$ctx->{smb_conf}";
877 #Ensure the config file is valid before we start
878 my $testparm = Samba::bindir_path($self, "samba-tool") . " testparm";
879 if (system("$testparm $configuration -v --suppress-prompt >/dev/null 2>&1") != 0) {
880 system("$testparm -v --suppress-prompt $configuration >&2");
881 warn("Failed to create a valid smb.conf configuration $testparm!");
882 return undef;
884 unless (system("($testparm $configuration -v --suppress-prompt --parameter-name=\"netbios name\" --section-name=global 2> /dev/null | grep -i \"^$ctx->{netbiosname}\" ) >/dev/null 2>&1") == 0) {
885 warn("Failed to create a valid smb.conf configuration! $testparm $configuration -v --suppress-prompt --parameter-name=\"netbios name\" --section-name=global");
886 return undef;
889 # Return the environment variables for the new testenv DC.
890 # Note that we have SERVER_X and DC_SERVER_X variables (which have the same
891 # value initially). In a 2 DC setup, $DC_SERVER_X will always be the PDC.
892 my $ret = {
893 GNUPGHOME => $ctx->{gnupghome},
894 KRB5_CONFIG => $ctx->{krb5_conf},
895 KRB5_CCACHE => $ctx->{krb5_ccache},
896 MITKDC_CONFIG => $ctx->{mitkdc_conf},
897 PIDDIR => $ctx->{piddir},
898 SERVER => $ctx->{hostname},
899 DC_SERVER => $ctx->{hostname},
900 SERVER_IP => $ctx->{ipv4},
901 DC_SERVER_IP => $ctx->{ipv4},
902 SERVER_IPV6 => $ctx->{ipv6},
903 DC_SERVER_IPV6 => $ctx->{ipv6},
904 NETBIOSNAME => $ctx->{netbiosname},
905 DC_NETBIOSNAME => $ctx->{netbiosname},
906 DOMAIN => $ctx->{domain},
907 USERNAME => $ctx->{username},
908 DC_USERNAME => $ctx->{username},
909 REALM => $ctx->{realm},
910 DNSNAME => $ctx->{dnsname},
911 SAMSID => $ctx->{samsid},
912 PASSWORD => $ctx->{password},
913 DC_PASSWORD => $ctx->{password},
914 LDAPDIR => $ctx->{ldapdir},
915 LDAP_INSTANCE => $ctx->{ldap_instance},
916 SELFTEST_WINBINDD_SOCKET_DIR => $ctx->{winbindd_socket_dir},
917 NCALRPCDIR => $ctx->{ncalrpcdir},
918 LOCKDIR => $ctx->{lockdir},
919 STATEDIR => $ctx->{statedir},
920 CACHEDIR => $ctx->{cachedir},
921 PRIVATEDIR => $ctx->{privatedir},
922 BINDDNSDIR => $ctx->{binddnsdir},
923 SERVERCONFFILE => $ctx->{smb_conf},
924 TESTENV_DIR => $ctx->{prefix_abs},
925 CONFIGURATION => $configuration,
926 SOCKET_WRAPPER_DEFAULT_IFACE => $ctx->{swiface},
927 NSS_WRAPPER_PASSWD => $ctx->{nsswrap_passwd},
928 NSS_WRAPPER_GROUP => $ctx->{nsswrap_group},
929 NSS_WRAPPER_HOSTS => $ctx->{nsswrap_hosts},
930 NSS_WRAPPER_HOSTNAME => $ctx->{nsswrap_hostname},
931 SAMBA_TEST_FIFO => "$ctx->{prefix}/samba_test.fifo",
932 SAMBA_TEST_LOG => "$ctx->{prefix}/samba_test.log",
933 SAMBA_TEST_LOG_POS => 0,
934 NSS_WRAPPER_MODULE_SO_PATH => Samba::nss_wrapper_winbind_so_path($self),
935 NSS_WRAPPER_MODULE_FN_PREFIX => "winbind",
936 LOCAL_PATH => $ctx->{share},
937 UID_RFC2307TEST => $uid_rfc2307test,
938 GID_RFC2307TEST => $gid_rfc2307test,
939 SERVER_ROLE => $ctx->{server_role},
940 RESOLV_CONF => $ctx->{resolv_conf},
941 KRB5_CRL_FILE => $crlfile,
944 if (defined($ctx->{use_resolv_wrapper})) {
945 $ret->{RESOLV_WRAPPER_CONF} = $ctx->{resolv_conf};
946 } else {
947 $ret->{RESOLV_WRAPPER_HOSTS} = $ctx->{dns_host_file};
949 if (defined($ctx->{force_fips_mode})) {
950 $ret->{GNUTLS_FORCE_FIPS_MODE} = "1",
951 $ret->{OPENSSL_FORCE_FIPS_MODE} = "1",
954 if ($ctx->{server_role} eq "domain controller") {
955 $ret->{DOMSID} = $ret->{SAMSID};
958 return $ret;
962 # Step2 runs the provision script
964 sub provision_raw_step2($$$)
966 my ($self, $ctx, $ret) = @_;
968 my $ldif;
970 my $provision_cmd = join(" ", @{$ctx->{provision_options}});
971 unless (system($provision_cmd) == 0) {
972 warn("Unable to provision: \n$provision_cmd\n");
973 return undef;
976 my $cmd_env = $self->get_cmd_env_vars($ret);
978 my $testallowed_account = "testallowed";
979 my $samba_tool_cmd = ${cmd_env};
980 $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
981 . " user create --configfile=$ctx->{smb_conf} $testallowed_account $ctx->{password}";
982 unless (system($samba_tool_cmd) == 0) {
983 warn("Unable to add testallowed user: \n$samba_tool_cmd\n");
984 return undef;
987 my $srv_account = "srv_account";
988 $samba_tool_cmd = ${cmd_env};
989 $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
990 . " user create --configfile=$ctx->{smb_conf} $srv_account $ctx->{password}";
991 unless (system($samba_tool_cmd) == 0) {
992 warn("Unable to add $srv_account user: \n$samba_tool_cmd\n");
993 return undef;
996 $samba_tool_cmd = ${cmd_env};
997 $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
998 . " spn add HOST/$srv_account --configfile=$ctx->{smb_conf} $srv_account";
999 unless (system($samba_tool_cmd) == 0) {
1000 warn("Unable to add spn for $srv_account: \n$samba_tool_cmd\n");
1001 return undef;
1004 my $ldbmodify = ${cmd_env};
1005 $ldbmodify .= Samba::bindir_path($self, "ldbmodify");
1006 $ldbmodify .= " --configfile=$ctx->{smb_conf}";
1007 my $base_dn = "DC=".join(",DC=", split(/\./, $ctx->{realm}));
1009 if ($ctx->{server_role} ne "domain controller") {
1010 $base_dn = "DC=$ctx->{netbiosname}";
1013 my $user_dn = "cn=$testallowed_account,cn=users,$base_dn";
1014 $testallowed_account = "testallowed account";
1015 open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb")
1016 or die "Failed to run $ldbmodify: $!";
1017 print $ldif "dn: $user_dn
1018 changetype: modify
1019 replace: samAccountName
1020 samAccountName: $testallowed_account
1023 close($ldif);
1024 unless ($? == 0) {
1025 warn("$ldbmodify failed: $?");
1026 return undef;
1029 open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb")
1030 or die "Failed to run $ldbmodify: $!";
1031 print $ldif "dn: $user_dn
1032 changetype: modify
1033 replace: userPrincipalName
1034 userPrincipalName: testallowed upn\@$ctx->{realm}
1035 replace: servicePrincipalName
1036 servicePrincipalName: host/testallowed
1039 close($ldif);
1040 unless ($? == 0) {
1041 warn("$ldbmodify failed: $?");
1042 return undef;
1045 $samba_tool_cmd = ${cmd_env};
1046 $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
1047 . " user create --configfile=$ctx->{smb_conf} testdenied $ctx->{password}";
1048 unless (system($samba_tool_cmd) == 0) {
1049 warn("Unable to add testdenied user: \n$samba_tool_cmd\n");
1050 return undef;
1053 $user_dn = "cn=testdenied,cn=users,$base_dn";
1054 open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb")
1055 or die "Failed to run $ldbmodify: $!";
1056 print $ldif "dn: $user_dn
1057 changetype: modify
1058 replace: userPrincipalName
1059 userPrincipalName: testdenied_upn\@$ctx->{realm}.upn
1062 close($ldif);
1063 unless ($? == 0) {
1064 warn("$ldbmodify failed: $?");
1065 return undef;
1068 $samba_tool_cmd = ${cmd_env};
1069 $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
1070 . " user create --configfile=$ctx->{smb_conf} testupnspn $ctx->{password}";
1071 unless (system($samba_tool_cmd) == 0) {
1072 warn("Unable to add testupnspn user: \n$samba_tool_cmd\n");
1073 return undef;
1076 $user_dn = "cn=testupnspn,cn=users,$base_dn";
1077 open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb")
1078 or die "Failed to run $ldbmodify: $!";
1079 print $ldif "dn: $user_dn
1080 changetype: modify
1081 replace: userPrincipalName
1082 userPrincipalName: http/testupnspn.$ctx->{dnsname}\@$ctx->{realm}
1083 replace: servicePrincipalName
1084 servicePrincipalName: http/testupnspn.$ctx->{dnsname}
1087 close($ldif);
1088 unless ($? == 0) {
1089 warn("$ldbmodify failed: $?");
1090 return undef;
1093 $samba_tool_cmd = ${cmd_env};
1094 $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
1095 . " group addmembers --configfile=$ctx->{smb_conf} 'Allowed RODC Password Replication Group' '$testallowed_account'";
1096 unless (system($samba_tool_cmd) == 0) {
1097 warn("Unable to add '$testallowed_account' user to 'Allowed RODC Password Replication Group': \n$samba_tool_cmd\n");
1098 return undef;
1101 # Create two users alice and bob!
1102 my $user_account_array = ["alice", "bob", "jane", "joe"];
1104 foreach my $user_account (@{$user_account_array}) {
1105 my $samba_tool_cmd = ${cmd_env};
1107 $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
1108 . " user create --configfile=$ctx->{smb_conf} $user_account Secret007";
1109 unless (system($samba_tool_cmd) == 0) {
1110 warn("Unable to create user: $user_account\n$samba_tool_cmd\n");
1111 return undef;
1115 my $group_array = ["Samba Users"];
1117 foreach my $group (@{$group_array}) {
1118 my $samba_tool_cmd = ${cmd_env};
1120 $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
1121 . " group add --configfile=$ctx->{smb_conf} \"$group\"";
1122 unless (system($samba_tool_cmd) == 0) {
1123 warn("Unable to create group: $group\n$samba_tool_cmd\n");
1124 return undef;
1128 # Add user joe to group "Samba Users"
1129 my $group = "Samba Users";
1130 my $user_account = "joe";
1132 $samba_tool_cmd = ${cmd_env};
1133 $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
1134 . " group addmembers --configfile=$ctx->{smb_conf} \"$group\" $user_account";
1135 unless (system($samba_tool_cmd) == 0) {
1136 warn("Unable to add " . $user_account . "to group group : $group\n$samba_tool_cmd\n");
1137 return undef;
1140 $group = "Samba Users";
1141 $user_account = "joe";
1143 $samba_tool_cmd = ${cmd_env};
1144 $samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
1145 . " user setprimarygroup --configfile=$ctx->{smb_conf} $user_account \"$group\"";
1146 unless (system($samba_tool_cmd) == 0) {
1147 warn("Unable to set primary group of user: $user_account\n$samba_tool_cmd\n");
1148 return undef;
1151 # Change the userPrincipalName for jane
1152 $user_dn = "cn=jane,cn=users,$base_dn";
1154 open($ldif, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb")
1155 or die "Failed to run $ldbmodify: $!";
1156 print $ldif "dn: $user_dn
1157 changetype: modify
1158 replace: userPrincipalName
1159 userPrincipalName: jane.doe\@$ctx->{realm}
1162 close($ldif);
1163 unless ($? == 0) {
1164 warn("$ldbmodify failed: $?");
1165 return undef;
1168 return $ret;
1171 sub provision($$$$$$$$$$$)
1173 my ($self,
1174 $prefix,
1175 $server_role,
1176 $hostname,
1177 $domain,
1178 $realm,
1179 $functional_level,
1180 $password,
1181 $kdc_ipv4,
1182 $kdc_ipv6,
1183 $force_fips_mode,
1184 $extra_smbconf_options,
1185 $extra_smbconf_shares,
1186 $extra_provision_options) = @_;
1188 my $samsid = Samba::random_domain_sid();
1190 my $ctx = $self->provision_raw_prepare($prefix, $server_role,
1191 $hostname,
1192 $domain, $realm,
1193 $samsid,
1194 $functional_level,
1195 $password,
1196 $kdc_ipv4,
1197 $kdc_ipv6,
1198 $force_fips_mode,
1199 $extra_provision_options);
1201 $ctx->{share} = "$ctx->{prefix_abs}/share";
1202 push(@{$ctx->{directories}}, "$ctx->{share}");
1203 push(@{$ctx->{directories}}, "$ctx->{share}/test1");
1204 push(@{$ctx->{directories}}, "$ctx->{share}/test2");
1206 # precreate directories for printer drivers
1207 push(@{$ctx->{directories}}, "$ctx->{share}/W32X86");
1208 push(@{$ctx->{directories}}, "$ctx->{share}/x64");
1209 push(@{$ctx->{directories}}, "$ctx->{share}/WIN40");
1211 my $msdfs = "no";
1212 $msdfs = "yes" if ($server_role eq "domain controller");
1213 $ctx->{smb_conf_extra_options} = "
1215 max xmit = 32K
1216 server max protocol = SMB2
1217 host msdfs = $msdfs
1218 lanman auth = yes
1220 # fruit:copyfile is a global option
1221 fruit:copyfile = yes
1223 $extra_smbconf_options
1225 [tmp]
1226 path = $ctx->{share}
1227 read only = no
1228 posix:sharedelay = 100000
1229 posix:oplocktimeout = 3
1230 posix:writetimeupdatedelay = 500000
1232 [xcopy_share]
1233 path = $ctx->{share}
1234 read only = no
1235 posix:sharedelay = 100000
1236 posix:oplocktimeout = 3
1237 posix:writetimeupdatedelay = 500000
1238 create mask = 777
1239 force create mode = 777
1241 [posix_share]
1242 path = $ctx->{share}
1243 read only = no
1244 create mask = 0777
1245 force create mode = 0
1246 directory mask = 0777
1247 force directory mode = 0
1249 [test1]
1250 path = $ctx->{share}/test1
1251 read only = no
1252 posix:sharedelay = 100000
1253 posix:oplocktimeout = 3
1254 posix:writetimeupdatedelay = 500000
1256 [test2]
1257 path = $ctx->{share}/test2
1258 read only = no
1259 posix:sharedelay = 100000
1260 posix:oplocktimeout = 3
1261 posix:writetimeupdatedelay = 500000
1263 [cifs]
1264 path = $ctx->{share}/_ignore_cifs_
1265 read only = no
1266 ntvfs handler = cifs
1267 cifs:server = $ctx->{netbiosname}
1268 cifs:share = tmp
1269 cifs:use-s4u2proxy = yes
1270 # There is no username specified here, instead the client is expected
1271 # to log in with kerberos, and the serverwill use delegated credentials.
1272 # Or the server tries s4u2self/s4u2proxy to impersonate the client
1274 [simple]
1275 path = $ctx->{share}
1276 read only = no
1277 ntvfs handler = simple
1279 [sysvol]
1280 path = $ctx->{statedir}/sysvol
1281 read only = no
1283 [netlogon]
1284 path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
1285 read only = no
1287 [cifsposix]
1288 copy = simple
1289 ntvfs handler = cifsposix
1291 [vfs_fruit]
1292 path = $ctx->{share}
1293 vfs objects = catia fruit streams_xattr acl_xattr
1294 ea support = yes
1295 fruit:resource = file
1296 fruit:metadata = netatalk
1297 fruit:locking = netatalk
1298 fruit:encoding = native
1300 [xattr]
1301 path = $ctx->{share}
1302 # This can be used for testing real fs xattr stuff
1303 vfs objects = streams_xattr acl_xattr
1305 $extra_smbconf_shares
1308 my $ret = $self->provision_raw_step1($ctx);
1309 unless (defined $ret) {
1310 return undef;
1313 return $self->provision_raw_step2($ctx, $ret);
1316 # For multi-DC testenvs, we want $DC_SERVER to always be the PDC (i.e. the
1317 # original DC) in the testenv. $SERVER is always the joined DC that we are
1318 # actually running the test against
1319 sub set_pdc_env_vars
1321 my ($self, $env, $dcvars) = @_;
1323 $env->{DC_SERVER} = $dcvars->{DC_SERVER};
1324 $env->{DC_SERVER_IP} = $dcvars->{DC_SERVER_IP};
1325 $env->{DC_SERVER_IPV6} = $dcvars->{DC_SERVER_IPV6};
1326 $env->{DC_SERVERCONFFILE} = $dcvars->{SERVERCONFFILE};
1327 $env->{DC_NETBIOSNAME} = $dcvars->{DC_NETBIOSNAME};
1328 $env->{DC_USERNAME} = $dcvars->{DC_USERNAME};
1329 $env->{DC_PASSWORD} = $dcvars->{DC_PASSWORD};
1332 sub provision_s4member($$$$$)
1334 my ($self, $prefix, $dcvars, $hostname, $more_conf) = @_;
1335 print "PROVISIONING MEMBER...\n";
1336 my $extra_smb_conf = "
1337 passdb backend = samba_dsdb
1338 winbindd:use external pipes = true
1340 # the source4 smb server doesn't allow signing by default
1341 server signing = enabled
1342 raw NTLMv2 auth = yes
1344 # override the new SMB2 only default
1345 client min protocol = CORE
1346 server min protocol = LANMAN1
1348 if ($more_conf) {
1349 $extra_smb_conf = $extra_smb_conf . $more_conf . "\n";
1351 my $extra_provision_options = ["--use-ntvfs"];
1352 my $ret = $self->provision($prefix,
1353 "member server",
1354 $hostname,
1355 $dcvars->{DOMAIN},
1356 $dcvars->{REALM},
1357 "2008",
1358 "locMEMpass3",
1359 $dcvars->{SERVER_IP},
1360 $dcvars->{SERVER_IPV6},
1361 undef,
1362 $extra_smb_conf, "",
1363 $extra_provision_options);
1364 unless ($ret) {
1365 return undef;
1368 my $samba_tool = Samba::bindir_path($self, "samba-tool");
1369 my $cmd = $self->get_cmd_env_vars($ret);
1370 $cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} --experimental-s4-member member";
1371 $cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
1372 $cmd .= " --machinepass=machine$ret->{PASSWORD}";
1374 unless (system($cmd) == 0) {
1375 warn("Join failed\n$cmd");
1376 return undef;
1379 $ret->{DOMSID} = $dcvars->{DOMSID};
1380 $self->set_pdc_env_vars($ret, $dcvars);
1382 return $ret;
1385 sub provision_rpc_proxy($$$)
1387 my ($self, $prefix, $dcvars) = @_;
1388 print "PROVISIONING RPC PROXY...\n";
1390 my $extra_smbconf_options = "
1391 passdb backend = samba_dsdb
1393 # rpc_proxy
1394 dcerpc_remote:binding = ncacn_ip_tcp:$dcvars->{SERVER}
1395 dcerpc endpoint servers = epmapper, remote
1396 dcerpc_remote:interfaces = rpcecho
1397 dcerpc_remote:allow_anonymous_fallback = yes
1398 # override the new SMB2 only default
1399 client min protocol = CORE
1400 server min protocol = LANMAN1
1401 [cifs_to_dc]
1402 path = /tmp/_ignore_cifs_to_dc_/_none_
1403 read only = no
1404 ntvfs handler = cifs
1405 cifs:server = $dcvars->{SERVER}
1406 cifs:share = cifs
1407 cifs:use-s4u2proxy = yes
1408 # There is no username specified here, instead the client is expected
1409 # to log in with kerberos, and the serverwill use delegated credentials.
1410 # Or the server tries s4u2self/s4u2proxy to impersonate the client
1414 my $extra_provision_options = ["--use-ntvfs"];
1415 my $ret = $self->provision($prefix,
1416 "member server",
1417 "localrpcproxy",
1418 $dcvars->{DOMAIN},
1419 $dcvars->{REALM},
1420 "2008",
1421 "locRPCproxypass4",
1422 $dcvars->{SERVER_IP},
1423 $dcvars->{SERVER_IPV6},
1424 undef,
1425 $extra_smbconf_options, "",
1426 $extra_provision_options);
1427 unless ($ret) {
1428 return undef;
1431 my $samba_tool = Samba::bindir_path($self, "samba-tool");
1433 # The joind runs in the context of the rpc_proxy/member for now
1434 my $cmd = $self->get_cmd_env_vars($ret);
1435 $cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} --experimental-s4-member member";
1436 $cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
1437 $cmd .= " --machinepass=machine$ret->{PASSWORD}";
1439 unless (system($cmd) == 0) {
1440 warn("Join failed\n$cmd");
1441 return undef;
1444 # Prepare a context of the DC, but using the local CCACHE.
1445 my $overwrite = undef;
1446 $overwrite->{KRB5_CCACHE} = $ret->{KRB5_CCACHE};
1447 my $dc_cmd_env = $self->get_cmd_env_vars($dcvars, $overwrite);
1449 # Setting up delegation runs in the context of the DC for now
1450 $cmd = $dc_cmd_env;
1451 $cmd .= "$samba_tool delegation for-any-protocol '$ret->{NETBIOSNAME}\$' on";
1452 $cmd .= " $dcvars->{CONFIGURATION}";
1453 print $cmd;
1455 unless (system($cmd) == 0) {
1456 warn("Delegation failed\n$cmd");
1457 return undef;
1460 # Setting up delegation runs in the context of the DC for now
1461 $cmd = $dc_cmd_env;
1462 $cmd .= "$samba_tool delegation add-service '$ret->{NETBIOSNAME}\$' cifs/$dcvars->{SERVER}";
1463 $cmd .= " $dcvars->{CONFIGURATION}";
1465 unless (system($cmd) == 0) {
1466 warn("Delegation failed\n$cmd");
1467 return undef;
1470 $ret->{DOMSID} = $dcvars->{DOMSID};
1471 $self->set_pdc_env_vars($ret, $dcvars);
1473 return $ret;
1476 sub provision_promoted_dc($$$)
1478 my ($self, $prefix, $dcvars) = @_;
1479 print "PROVISIONING PROMOTED DC...\n";
1481 # We do this so that we don't run the provision. That's the job of 'samba-tool domain dcpromo'.
1482 my $ctx = $self->provision_raw_prepare($prefix, "domain controller",
1483 "promotedvdc",
1484 $dcvars->{DOMAIN},
1485 $dcvars->{REALM},
1486 $dcvars->{SAMSID},
1487 "2008",
1488 $dcvars->{PASSWORD},
1489 $dcvars->{SERVER_IP},
1490 $dcvars->{SERVER_IPV6});
1492 $ctx->{smb_conf_extra_options} = "
1493 max xmit = 32K
1494 server max protocol = SMB2
1496 ntlm auth = ntlmv2-only
1498 kdc force enable rc4 weak session keys = yes
1500 [sysvol]
1501 path = $ctx->{statedir}/sysvol
1502 read only = yes
1504 [netlogon]
1505 path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
1506 read only = no
1510 my $ret = $self->provision_raw_step1($ctx);
1511 unless ($ret) {
1512 return undef;
1515 my $samba_tool = Samba::bindir_path($self, "samba-tool");
1516 my $cmd = $self->get_cmd_env_vars($ret);
1517 $cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} --experimental-s4-member MEMBER --realm=$dcvars->{REALM}";
1518 $cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
1519 $cmd .= " --machinepass=machine$ret->{PASSWORD}";
1521 unless (system($cmd) == 0) {
1522 warn("Join failed\n$cmd");
1523 return undef;
1526 $samba_tool = Samba::bindir_path($self, "samba-tool");
1527 $cmd = $self->get_cmd_env_vars($ret);
1528 $cmd .= "$samba_tool domain dcpromo $ret->{CONFIGURATION} $dcvars->{REALM} DC --realm=$dcvars->{REALM}";
1529 $cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
1530 $cmd .= " --machinepass=machine$ret->{PASSWORD} --dns-backend=BIND9_DLZ";
1532 unless (system($cmd) == 0) {
1533 warn("Join failed\n$cmd");
1534 return undef;
1537 $self->set_pdc_env_vars($ret, $dcvars);
1539 return $ret;
1542 sub provision_vampire_dc($$$)
1544 my ($self, $prefix, $dcvars, $fl) = @_;
1545 print "PROVISIONING VAMPIRE DC @ FL $fl...\n";
1546 my $name = "localvampiredc";
1547 my $extra_conf = "";
1549 if ($fl == "2000") {
1550 $name = "vampire2000dc";
1551 } else {
1552 $extra_conf = "drs: immediate link sync = yes
1553 drs: max link sync = 250";
1556 # We do this so that we don't run the provision. That's the job of 'net vampire'.
1557 my $ctx = $self->provision_raw_prepare($prefix, "domain controller",
1558 $name,
1559 $dcvars->{DOMAIN},
1560 $dcvars->{REALM},
1561 $dcvars->{DOMSID},
1562 $fl,
1563 $dcvars->{PASSWORD},
1564 $dcvars->{SERVER_IP},
1565 $dcvars->{SERVER_IPV6});
1567 $ctx->{smb_conf_extra_options} = "
1568 max xmit = 32K
1569 server max protocol = SMB2
1571 ntlm auth = mschapv2-and-ntlmv2-only
1572 $extra_conf
1574 [sysvol]
1575 path = $ctx->{statedir}/sysvol
1576 read only = yes
1578 [netlogon]
1579 path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
1580 read only = no
1584 my $ret = $self->provision_raw_step1($ctx);
1585 unless ($ret) {
1586 return undef;
1589 my $samba_tool = Samba::bindir_path($self, "samba-tool");
1590 my $cmd = $self->get_cmd_env_vars($ret);
1591 $cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} DC --realm=$dcvars->{REALM}";
1592 $cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD} --domain-critical-only";
1593 $cmd .= " --machinepass=machine$ret->{PASSWORD}";
1594 $cmd .= " --backend-store=$self->{default_ldb_backend}";
1596 unless (system($cmd) == 0) {
1597 warn("Join failed\n$cmd");
1598 return undef;
1601 $self->set_pdc_env_vars($ret, $dcvars);
1602 $ret->{DC_REALM} = $dcvars->{DC_REALM};
1604 return $ret;
1607 sub provision_ad_dc_ntvfs($$$)
1609 my ($self, $prefix, $extra_provision_options) = @_;
1611 # We keep the old 'winbind' name here in server services to
1612 # ensure upgrades which used that name still work with the now
1613 # alias.
1615 print "PROVISIONING AD DC (NTVFS)...\n";
1616 my $extra_conf_options = "netbios aliases = localDC1-a
1617 server services = +winbind -winbindd
1618 ldap server require strong auth = allow_sasl_over_tls
1619 raw NTLMv2 auth = yes
1620 lsa over netlogon = yes
1621 rpc server port = 1027
1622 auth event notification = true
1623 dsdb event notification = true
1624 dsdb password event notification = true
1625 dsdb group change notification = true
1626 # override the new SMB2 only default
1627 client min protocol = CORE
1628 server min protocol = LANMAN1
1630 CVE_2020_1472:warn_about_unused_debug_level = 3
1631 CVE_2022_38023:warn_about_unused_debug_level = 3
1632 allow nt4 crypto:torturetest\$ = yes
1633 server reject md5 schannel:schannel2\$ = no
1634 server reject md5 schannel:schannel3\$ = no
1635 server reject md5 schannel:schannel8\$ = no
1636 server reject md5 schannel:schannel9\$ = no
1637 server reject md5 schannel:torturetest\$ = no
1638 server reject md5 schannel:tests4u2proxywk\$ = no
1639 server reject md5 schannel:tests4u2selfbdc\$ = no
1640 server reject md5 schannel:tests4u2selfwk\$ = no
1641 server reject md5 schannel:torturepacbdc\$ = no
1642 server reject md5 schannel:torturepacwksta\$ = no
1643 server require schannel:schannel0\$ = no
1644 server require schannel:schannel1\$ = no
1645 server require schannel:schannel2\$ = no
1646 server require schannel:schannel3\$ = no
1647 server require schannel:schannel4\$ = no
1648 server require schannel:schannel5\$ = no
1649 server require schannel:schannel6\$ = no
1650 server require schannel:schannel7\$ = no
1651 server require schannel:schannel8\$ = no
1652 server require schannel:schannel9\$ = no
1653 server require schannel:schannel10\$ = no
1654 server require schannel:schannel11\$ = no
1655 server require schannel:torturetest\$ = no
1656 server schannel require seal:schannel0\$ = no
1657 server schannel require seal:schannel1\$ = no
1658 server schannel require seal:schannel2\$ = no
1659 server schannel require seal:schannel3\$ = no
1660 server schannel require seal:schannel4\$ = no
1661 server schannel require seal:schannel5\$ = no
1662 server schannel require seal:schannel6\$ = no
1663 server schannel require seal:schannel7\$ = no
1664 server schannel require seal:schannel8\$ = no
1665 server schannel require seal:schannel9\$ = no
1666 server schannel require seal:schannel10\$ = no
1667 server schannel require seal:schannel11\$ = no
1668 server schannel require seal:torturetest\$ = no
1670 # needed for 'samba.tests.auth_log' tests
1671 server require schannel:LOCALDC\$ = no
1672 server schannel require seal:LOCALDC\$ = no
1674 push (@{$extra_provision_options},
1675 "--base-schema=2008_R2",
1676 "--use-ntvfs");
1677 my $ret = $self->provision($prefix,
1678 "domain controller",
1679 "localdc",
1680 "SAMBADOMAIN",
1681 "samba.example.com",
1682 "2008",
1683 "locDCpass1",
1684 undef,
1685 undef,
1686 undef,
1687 $extra_conf_options,
1689 $extra_provision_options);
1690 unless ($ret) {
1691 return undef;
1694 unless($self->add_wins_config("$prefix/private")) {
1695 warn("Unable to add wins configuration");
1696 return undef;
1698 $ret->{NETBIOSALIAS} = "localdc1-a";
1699 $ret->{DC_REALM} = $ret->{REALM};
1701 return $ret;
1704 sub provision_fl2000dc($$)
1706 my ($self, $prefix) = @_;
1708 print "PROVISIONING DC WITH FOREST LEVEL 2000...\n";
1709 my $extra_conf_options = "
1710 kdc enable fast = no
1711 spnego:simulate_w2k=yes
1712 ntlmssp_server:force_old_spnego=yes
1714 CVE_2022_38023:warn_about_unused_debug_level = 3
1715 server reject md5 schannel:tests4u2proxywk\$ = no
1716 server reject md5 schannel:tests4u2selfbdc\$ = no
1717 server reject md5 schannel:tests4u2selfwk\$ = no
1718 server reject md5 schannel:torturepacbdc\$ = no
1719 server reject md5 schannel:torturepacwksta\$ = no
1721 my $extra_provision_options = ["--base-schema=2008_R2"];
1722 # This environment uses plain text secrets
1723 # i.e. secret attributes are not encrypted on disk.
1724 # This allows testing of the --plaintext-secrets option for
1725 # provision
1726 push (@{$extra_provision_options}, "--plaintext-secrets");
1727 my $ret = $self->provision($prefix,
1728 "domain controller",
1729 "dc5",
1730 "SAMBA2000",
1731 "samba2000.example.com",
1732 "2000",
1733 "locDCpass5",
1734 undef,
1735 undef,
1736 undef,
1737 $extra_conf_options,
1739 $extra_provision_options);
1740 unless ($ret) {
1741 return undef;
1744 unless($self->add_wins_config("$prefix/private")) {
1745 warn("Unable to add wins configuration");
1746 return undef;
1748 $ret->{DC_REALM} = $ret->{REALM};
1750 return $ret;
1753 sub provision_fl2003dc($$$)
1755 my ($self, $prefix, $dcvars) = @_;
1756 my $ip_addr1 = Samba::get_ipv4_addr("fakednsforwarder1");
1757 my $ip_addr2 = Samba::get_ipv6_addr("fakednsforwarder2");
1759 print "PROVISIONING DC WITH FOREST LEVEL 2003...\n";
1760 my $extra_conf_options = "
1761 allow dns updates = nonsecure and secure
1763 kdc enable fast = no
1764 dcesrv:header signing = no
1765 dcesrv:max auth states = 0
1767 dns forwarder = $ip_addr1 [$ip_addr2]:54
1769 CVE_2022_38023:warn_about_unused_debug_level = 3
1770 server reject md5 schannel:tests4u2proxywk\$ = no
1771 server reject md5 schannel:tests4u2selfbdc\$ = no
1772 server reject md5 schannel:tests4u2selfwk\$ = no
1773 server reject md5 schannel:torturepacbdc\$ = no
1774 server reject md5 schannel:torturepacwksta\$ = no
1777 my $extra_provision_options = ["--base-schema=2008_R2"];
1778 my $ret = $self->provision($prefix,
1779 "domain controller",
1780 "dc6",
1781 "SAMBA2003",
1782 "samba2003.example.com",
1783 "2003",
1784 "locDCpass6",
1785 undef,
1786 undef,
1787 undef,
1788 $extra_conf_options,
1790 $extra_provision_options);
1791 unless (defined $ret) {
1792 return undef;
1795 $ret->{DNS_FORWARDER1} = $ip_addr1;
1796 $ret->{DNS_FORWARDER2} = $ip_addr2;
1798 my @samba_tool_options;
1799 push (@samba_tool_options, Samba::bindir_path($self, "samba-tool"));
1800 push (@samba_tool_options, "domain");
1801 push (@samba_tool_options, "passwordsettings");
1802 push (@samba_tool_options, "set");
1803 push (@samba_tool_options, "--configfile=$ret->{SERVERCONFFILE}");
1804 push (@samba_tool_options, "--min-pwd-age=0");
1805 push (@samba_tool_options, "--history-length=1");
1807 my $samba_tool_cmd = join(" ", @samba_tool_options);
1809 unless (system($samba_tool_cmd) == 0) {
1810 warn("Unable to set min password age to 0: \n$samba_tool_cmd\n");
1811 return undef;
1814 unless($self->add_wins_config("$prefix/private")) {
1815 warn("Unable to add wins configuration");
1816 return undef;
1819 return $ret;
1822 sub provision_fl2008r2dc($$$)
1824 my ($self, $prefix, $dcvars) = @_;
1826 print "PROVISIONING DC WITH FOREST LEVEL 2008r2...\n";
1827 my $extra_conf_options = "
1828 ldap server require strong auth = no
1829 # delay by 10 seconds, 10^7 usecs
1830 ldap_server:delay_expire_disconnect = 10000
1832 CVE_2022_38023:warn_about_unused_debug_level = 3
1833 server reject md5 schannel:tests4u2proxywk\$ = no
1834 server reject md5 schannel:tests4u2selfbdc\$ = no
1835 server reject md5 schannel:tests4u2selfwk\$ = no
1836 server reject md5 schannel:torturepacbdc\$ = no
1837 server reject md5 schannel:torturepacwksta\$ = no
1839 my $extra_provision_options = ["--base-schema=2008_R2"];
1840 my $ret = $self->provision($prefix,
1841 "domain controller",
1842 "dc7",
1843 "SAMBA2008R2",
1844 "samba2008R2.example.com",
1845 "2008_R2",
1846 "locDCpass7",
1847 undef,
1848 undef,
1849 undef,
1850 $extra_conf_options,
1852 $extra_provision_options);
1853 unless (defined $ret) {
1854 return undef;
1857 unless ($self->add_wins_config("$prefix/private")) {
1858 warn("Unable to add wins configuration");
1859 return undef;
1861 $ret->{DC_REALM} = $ret->{REALM};
1863 return $ret;
1867 sub provision_rodc($$$)
1869 my ($self, $prefix, $dcvars) = @_;
1870 print "PROVISIONING RODC...\n";
1872 # We do this so that we don't run the provision. That's the job of 'net join RODC'.
1873 my $ctx = $self->provision_raw_prepare($prefix, "domain controller",
1874 "rodc",
1875 $dcvars->{DOMAIN},
1876 $dcvars->{REALM},
1877 $dcvars->{DOMSID},
1878 "2008",
1879 $dcvars->{PASSWORD},
1880 $dcvars->{SERVER_IP},
1881 $dcvars->{SERVER_IPV6});
1882 unless ($ctx) {
1883 return undef;
1886 $ctx->{share} = "$ctx->{prefix_abs}/share";
1887 push(@{$ctx->{directories}}, "$ctx->{share}");
1889 $ctx->{smb_conf_extra_options} = "
1890 max xmit = 32K
1891 server max protocol = SMB2
1892 password server = $dcvars->{DC_SERVER}
1894 [sysvol]
1895 path = $ctx->{statedir}/sysvol
1896 read only = yes
1898 [netlogon]
1899 path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
1900 read only = yes
1902 [tmp]
1903 path = $ctx->{share}
1904 read only = no
1905 posix:sharedelay = 10000
1906 posix:oplocktimeout = 3
1907 posix:writetimeupdatedelay = 50000
1911 my $ret = $self->provision_raw_step1($ctx);
1912 unless ($ret) {
1913 return undef;
1916 my $samba_tool = Samba::bindir_path($self, "samba-tool");
1917 my $cmd = $self->get_cmd_env_vars($ret);
1918 $cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} RODC";
1919 $cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
1920 $cmd .= " --server=$dcvars->{DC_SERVER}";
1922 unless (system($cmd) == 0) {
1923 warn("RODC join failed\n$cmd");
1924 return undef;
1927 # This ensures deterministic behaviour for tests that want to have the 'testallowed account'
1928 # user password verified on the RODC
1929 my $testallowed_account = "testallowed account";
1930 $cmd = $self->get_cmd_env_vars($ret);
1931 $cmd .= "$samba_tool rodc preload '$testallowed_account' $ret->{CONFIGURATION}";
1932 $cmd .= " --server=$dcvars->{DC_SERVER}";
1934 unless (system($cmd) == 0) {
1935 warn("RODC join failed\n$cmd");
1936 return undef;
1939 # we overwrite the kdc after the RODC join
1940 # so that use the RODC as kdc and test
1941 # the proxy code
1942 $ctx->{kdc_ipv4} = $ret->{SERVER_IP};
1943 $ctx->{kdc_ipv6} = $ret->{SERVER_IPV6};
1944 Samba::mk_krb5_conf($ctx);
1945 Samba::mk_mitkdc_conf($ctx, abs_path(Samba::bindir_path($self, "shared")));
1947 $self->set_pdc_env_vars($ret, $dcvars);
1949 return $ret;
1952 sub read_config_h($)
1954 my ($name) = @_;
1955 my %ret;
1956 open(LF, "<$name") or die("unable to read $name: $!");
1957 while (<LF>) {
1958 chomp;
1959 next if not (/^#define /);
1960 if (/^#define (.*?)[ \t]+(.*?)$/) {
1961 $ret{$1} = $2;
1962 next;
1964 if (/^#define (.*?)[ \t]+$/) {
1965 $ret{$1} = 1;;
1966 next;
1969 close(LF);
1970 return \%ret;
1973 sub provision_ad_dc()
1975 my ($self,
1976 $prefix,
1977 $hostname,
1978 $domain,
1979 $realm,
1980 $force_fips_mode,
1981 $smbconf_args,
1982 $extra_provision_options,
1983 $functional_level) = @_;
1985 my $prefix_abs = abs_path($prefix);
1987 my $bindir_abs = abs_path($self->{bindir});
1988 my $lockdir="$prefix_abs/lockdir";
1989 my $conffile="$prefix_abs/etc/smb.conf";
1991 my $require_mutexes = "dbwrap_tdb_require_mutexes:* = yes";
1992 if ($ENV{SELFTEST_DONT_REQUIRE_TDB_MUTEX_SUPPORT} // '' eq "1") {
1993 $require_mutexes = "";
1996 my $config_h = {};
1998 if (!defined($functional_level)) {
1999 $functional_level = "2016";
2002 # If we choose to have distinct environments for experimental
2003 # 2012 as well as the experimental 2016 support, we should
2004 # extend what we match here.
2005 if ($functional_level eq "2016") {
2006 $smbconf_args = "$smbconf_args
2008 [global]
2009 ad dc functional level = 2016
2012 if (defined($ENV{CONFIG_H})) {
2013 $config_h = read_config_h($ENV{CONFIG_H});
2016 my $password_hash_gpg_key_ids = "password hash gpg key ids = 4952E40301FAB41A";
2017 $password_hash_gpg_key_ids = "" unless defined($config_h->{HAVE_GPGME});
2019 my $extra_smbconf_options = "
2020 xattr_tdb:file = $prefix_abs/statedir/xattr.tdb
2022 dbwrap_tdb_mutexes:* = yes
2023 ${require_mutexes}
2025 ${password_hash_gpg_key_ids}
2027 kernel oplocks = no
2028 kernel change notify = no
2029 smb2 leases = no
2030 smb2 disable oplock break retry = yes
2031 server multi channel support = yes
2033 logging = file
2034 printing = bsd
2035 printcap name = /dev/null
2037 max protocol = SMB3
2038 read only = no
2040 smbd:sharedelay = 100000
2041 smbd:writetimeupdatedelay = 500000
2042 create mask = 755
2043 dos filemode = yes
2044 check parent directory delete on close = yes
2046 dcerpc endpoint servers = -winreg -srvsvc
2048 printcap name = /dev/null
2050 addprinter command = $ENV{SRCDIR_ABS}/source3/script/tests/printing/modprinter.pl -a -s $conffile --
2051 deleteprinter command = $ENV{SRCDIR_ABS}/source3/script/tests/printing/modprinter.pl -d -s $conffile --
2053 printing = vlp
2054 print command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb print %p %s
2055 lpq command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb lpq %p
2056 lp rm command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb lprm %p %j
2057 lp pause command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb lppause %p %j
2058 lp resume command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb lpresume %p %j
2059 queue pause command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb queuepause %p
2060 queue resume command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb queueresume %p
2061 lpq cache time = 0
2062 print notify backchannel = yes
2064 CVE_2020_1472:warn_about_unused_debug_level = 3
2065 CVE_2022_38023:warn_about_unused_debug_level = 3
2066 CVE_2022_38023:error_debug_level = 2
2067 server reject md5 schannel:schannel2\$ = no
2068 server reject md5 schannel:schannel3\$ = no
2069 server reject md5 schannel:schannel8\$ = no
2070 server reject md5 schannel:schannel9\$ = no
2071 server reject md5 schannel:torturetest\$ = no
2072 server reject md5 schannel:tests4u2proxywk\$ = no
2073 server reject md5 schannel:tests4u2selfbdc\$ = no
2074 server reject md5 schannel:tests4u2selfwk\$ = no
2075 server reject md5 schannel:torturepacbdc\$ = no
2076 server reject md5 schannel:torturepacwksta\$ = no
2077 server reject md5 schannel:samlogontest\$ = no
2078 server require schannel:schannel0\$ = no
2079 server require schannel:schannel1\$ = no
2080 server require schannel:schannel2\$ = no
2081 server require schannel:schannel3\$ = no
2082 server require schannel:schannel4\$ = no
2083 server require schannel:schannel5\$ = no
2084 server require schannel:schannel6\$ = no
2085 server require schannel:schannel7\$ = no
2086 server require schannel:schannel8\$ = no
2087 server require schannel:schannel9\$ = no
2088 server require schannel:schannel10\$ = no
2089 server require schannel:schannel11\$ = no
2090 server require schannel:torturetest\$ = no
2091 server schannel require seal:schannel0\$ = no
2092 server schannel require seal:schannel1\$ = no
2093 server schannel require seal:schannel2\$ = no
2094 server schannel require seal:schannel3\$ = no
2095 server schannel require seal:schannel4\$ = no
2096 server schannel require seal:schannel5\$ = no
2097 server schannel require seal:schannel6\$ = no
2098 server schannel require seal:schannel7\$ = no
2099 server schannel require seal:schannel8\$ = no
2100 server schannel require seal:schannel9\$ = no
2101 server schannel require seal:schannel10\$ = no
2102 server schannel require seal:schannel11\$ = no
2103 server schannel require seal:torturetest\$ = no
2105 auth event notification = true
2106 dsdb event notification = true
2107 dsdb password event notification = true
2108 dsdb group change notification = true
2109 $smbconf_args
2112 my $extra_smbconf_shares = "
2114 [tmpenc]
2115 copy = tmp
2116 smb encrypt = required
2118 [tmpcase]
2119 copy = tmp
2120 case sensitive = yes
2122 [tmpguest]
2123 copy = tmp
2124 guest ok = yes
2126 [hideunread]
2127 copy = tmp
2128 hide unreadable = yes
2130 [durable]
2131 copy = tmp
2132 kernel share modes = no
2133 kernel oplocks = no
2134 posix locking = no
2136 [print\$]
2137 copy = tmp
2139 [print1]
2140 copy = tmp
2141 printable = yes
2143 [print2]
2144 copy = print1
2145 [print3]
2146 copy = print1
2147 [print4]
2148 copy = print1
2149 guest ok = yes
2150 [lp]
2151 copy = print1
2154 push (@{$extra_provision_options}, "--backend-store=$self->{default_ldb_backend}");
2155 print "PROVISIONING AD DC...\n";
2156 my $ret = $self->provision($prefix,
2157 "domain controller",
2158 $hostname,
2159 $domain,
2160 $realm,
2161 $functional_level,
2162 "locDCpass1",
2163 undef,
2164 undef,
2165 $force_fips_mode,
2166 $extra_smbconf_options,
2167 $extra_smbconf_shares,
2168 $extra_provision_options);
2169 unless (defined $ret) {
2170 return undef;
2173 unless($self->add_wins_config("$prefix/private")) {
2174 warn("Unable to add wins configuration");
2175 return undef;
2178 return $ret;
2181 sub provision_chgdcpass($$)
2183 my ($self, $prefix) = @_;
2185 print "PROVISIONING CHGDCPASS...\n";
2186 # This environment disallows the use of this password
2187 # (and also removes the default AD complexity checks)
2188 my $unacceptable_password = "Paßßword-widk3Dsle32jxdBdskldsk55klASKQ";
2190 # This environment also sets some settings that are unusual,
2191 # to test specific behaviours. In particular, this
2192 # environment fails to correctly support DRSUAPI_DRS_GET_ANC
2193 # like Samba before 4.5 and DRSUAPI_DRS_GET_TGT before 4.8
2195 # Additionally, disabling DRSUAPI_DRS_GET_TGT causes all links
2196 # to be sent last (in the final chunk), which is like Samba
2197 # before 4.8.
2199 my $extra_smb_conf = "
2200 check password script = $self->{srcdir}/selftest/checkpassword_arg1.sh ${unacceptable_password}
2201 allow dcerpc auth level connect:lsarpc = yes
2202 dcesrv:max auth states = 8
2203 drs:broken_samba_4.5_get_anc_emulation = true
2204 drs:get_tgt_support = false
2206 my $extra_provision_options = ["--dns-backend=BIND9_DLZ"];
2207 my $ret = $self->provision($prefix,
2208 "domain controller",
2209 "chgdcpass",
2210 "CHDCDOMAIN",
2211 "chgdcpassword.samba.example.com",
2212 "2008",
2213 "chgDCpass1",
2214 undef,
2215 undef,
2216 undef,
2217 $extra_smb_conf,
2219 $extra_provision_options);
2220 unless (defined $ret) {
2221 return undef;
2224 unless($self->add_wins_config("$prefix/private")) {
2225 warn("Unable to add wins configuration");
2226 return undef;
2229 # Remove secrets.tdb from this environment to test that we
2230 # still start up on systems without the new matching
2231 # secrets.tdb records.
2232 unless (unlink("$ret->{PRIVATEDIR}/secrets.tdb") || unlink("$ret->{PRIVATEDIR}/secrets.ntdb")) {
2233 warn("Unable to remove $ret->{PRIVATEDIR}/secrets.tdb added during provision");
2234 return undef;
2237 $ret->{UNACCEPTABLE_PASSWORD} = $unacceptable_password;
2239 return $ret;
2242 sub teardown_env_terminate($$)
2244 my ($self, $envvars) = @_;
2245 my $pid;
2247 # This should cause samba to terminate gracefully
2248 my $smbcontrol = Samba::bindir_path($self, "smbcontrol");
2249 my $cmd = "";
2250 $cmd .= "$smbcontrol samba shutdown $envvars->{CONFIGURATION}";
2251 my $ret = system($cmd);
2252 if ($ret != 0) {
2253 warn "'$cmd' failed with '$ret'\n";
2256 # This should cause samba to terminate gracefully
2257 close($envvars->{STDIN_PIPE});
2259 $pid = $envvars->{SAMBA_PID};
2260 my $count = 0;
2261 my $childpid;
2263 # This should give it time to write out the gcov data
2264 until ($count > 15) {
2265 if (Samba::cleanup_child($pid, "samba") != 0) {
2266 return;
2268 sleep(1);
2269 $count++;
2272 # After 15 Seconds, work out why this thing is still alive
2273 warn "server process $pid took more than $count seconds to exit, showing backtrace:\n";
2274 system("$self->{srcdir}/selftest/gdb_backtrace $pid");
2276 until ($count > 30) {
2277 if (Samba::cleanup_child($pid, "samba") != 0) {
2278 return;
2280 sleep(1);
2281 $count++;
2284 if (kill(0, $pid)) {
2285 warn "server process $pid took more than $count seconds to exit, sending SIGTERM\n";
2286 kill "TERM", $pid;
2289 until ($count > 40) {
2290 if (Samba::cleanup_child($pid, "samba") != 0) {
2291 return;
2293 sleep(1);
2294 $count++;
2296 # If it is still around, kill it
2297 if (kill(0, $pid)) {
2298 warn "server process $pid took more than $count seconds to exit, killing\n with SIGKILL\n";
2299 kill 9, $pid;
2301 return;
2304 sub teardown_env($$)
2306 my ($self, $envvars) = @_;
2307 teardown_env_terminate($self, $envvars);
2309 print $self->getlog_env($envvars);
2311 return;
2314 sub getlog_env($$)
2316 my ($self, $envvars) = @_;
2317 my $title = "SAMBA LOG of: $envvars->{NETBIOSNAME} pid $envvars->{SAMBA_PID}\n";
2318 my $out = $title;
2320 open(LOG, "<$envvars->{SAMBA_TEST_LOG}");
2322 seek(LOG, $envvars->{SAMBA_TEST_LOG_POS}, SEEK_SET);
2323 while (<LOG>) {
2324 $out .= $_;
2326 $envvars->{SAMBA_TEST_LOG_POS} = tell(LOG);
2327 close(LOG);
2329 return "" if $out eq $title;
2331 return $out;
2334 sub check_env($$)
2336 my ($self, $envvars) = @_;
2337 my $samba_pid = $envvars->{SAMBA_PID};
2339 if (not defined($samba_pid)) {
2340 return 0;
2341 } elsif ($samba_pid > 0) {
2342 my $childpid = Samba::cleanup_child($samba_pid, "samba");
2344 if ($childpid == 0) {
2345 return 1;
2347 return 0;
2348 } else {
2349 return 1;
2353 # Declare the environments Samba4 makes available.
2354 # To be set up, they will be called as
2355 # samba4->setup_$envname($self, $path, $dep_1_vars, $dep_2_vars, ...)
2356 # The interdependencies between the testenvs are declared below. Some testenvs
2357 # are dependent on another testenv running first, e.g. vampire_dc is dependent
2358 # on ad_dc_ntvfs because vampire_dc joins ad_dc_ntvfs's domain. All DCs are
2359 # dependent on dns_hub, which handles resolving DNS queries for the realm.
2360 %Samba4::ENV_DEPS = (
2361 # name => [dep_1, dep_2, ...],
2362 dns_hub => [],
2363 ad_dc_ntvfs => ["dns_hub"],
2364 ad_dc_fips => ["dns_hub"],
2365 ad_dc => ["dns_hub"],
2366 ad_dc_smb1 => ["dns_hub"],
2367 ad_dc_smb1_done => ["ad_dc_smb1"],
2368 ad_dc_no_nss => ["dns_hub"],
2369 ad_dc_no_ntlm => ["dns_hub"],
2371 fl2008r2dc => ["ad_dc"],
2372 fl2003dc => ["ad_dc"],
2373 fl2000dc => ["ad_dc"],
2375 vampire_2000_dc => ["fl2000dc"],
2376 vampire_dc => ["ad_dc_ntvfs"],
2377 promoted_dc => ["ad_dc_ntvfs"],
2379 rodc => ["ad_dc_ntvfs"],
2380 rpc_proxy => ["ad_dc_ntvfs"],
2381 chgdcpass => ["dns_hub"],
2383 s4member_dflt_domain => ["ad_dc_ntvfs"],
2384 s4member => ["ad_dc_ntvfs"],
2386 # envs that test the server process model
2387 proclimitdc => ["dns_hub"],
2388 preforkrestartdc => ["dns_hub"],
2390 # backup/restore testenvs
2391 backupfromdc => ["dns_hub"],
2392 customdc => ["dns_hub"],
2393 restoredc => ["backupfromdc"],
2394 renamedc => ["backupfromdc"],
2395 offlinebackupdc => ["backupfromdc"],
2396 labdc => ["backupfromdc"],
2398 # aliases in order to split autobuild tasks
2399 fl2008dc => ["ad_dc_ntvfs"],
2400 ad_dc_default => ["ad_dc"],
2401 ad_dc_default_smb1 => ["ad_dc_smb1"],
2402 ad_dc_default_smb1_done => ["ad_dc_default_smb1"],
2403 ad_dc_slowtests => ["ad_dc"],
2404 ad_dc_backup => ["ad_dc"],
2406 schema_dc => ["dns_hub"],
2407 schema_pair_dc => ["schema_dc"],
2409 none => [],
2412 %Samba4::ENV_DEPS_POST = (
2413 schema_dc => ["schema_pair_dc"],
2416 sub return_alias_env
2418 my ($self, $path, $env) = @_;
2420 # just an alias
2421 return $env;
2424 sub setup_fl2008dc
2426 my ($self, $path, $dep_env) = @_;
2427 return $self->return_alias_env($path, $dep_env)
2430 sub setup_ad_dc_default
2432 my ($self, $path, $dep_env) = @_;
2433 return $self->return_alias_env($path, $dep_env)
2436 sub setup_ad_dc_default_smb1
2438 my ($self, $path, $dep_env) = @_;
2439 return $self->return_alias_env($path, $dep_env)
2442 sub setup_ad_dc_default_smb1_done
2444 my ($self, $path, $dep_env) = @_;
2445 return $self->return_alias_env($path, $dep_env)
2448 sub setup_ad_dc_slowtests
2450 my ($self, $path, $dep_env) = @_;
2451 return $self->return_alias_env($path, $dep_env)
2454 sub setup_ad_dc_backup
2456 my ($self, $path, $dep_env) = @_;
2457 return $self->return_alias_env($path, $dep_env)
2460 sub setup_s4member
2462 my ($self, $path, $dc_vars) = @_;
2464 my $env = $self->provision_s4member($path, $dc_vars, "s4member");
2466 if (defined $env) {
2467 if (not defined($self->check_or_start($env, "standard"))) {
2468 return undef;
2472 return $env;
2475 sub setup_s4member_dflt_domain
2477 my ($self, $path, $dc_vars) = @_;
2479 my $env = $self->provision_s4member($path, $dc_vars, "s4member_dflt",
2480 "winbind use default domain = yes");
2482 if (defined $env) {
2483 if (not defined($self->check_or_start($env, "standard"))) {
2484 return undef;
2488 return $env;
2491 sub setup_rpc_proxy
2493 my ($self, $path, $dc_vars) = @_;
2495 my $env = $self->provision_rpc_proxy($path, $dc_vars);
2497 if (defined $env) {
2498 if (not defined($self->check_or_start($env, "standard"))) {
2499 return undef;
2502 return $env;
2505 sub setup_ad_dc_ntvfs
2507 my ($self, $path) = @_;
2509 my $env = $self->provision_ad_dc_ntvfs($path, undef);
2510 if (defined $env) {
2511 if (not defined($self->check_or_start($env, "standard"))) {
2512 warn("Failed to start ad_dc_ntvfs");
2513 return undef;
2516 return $env;
2519 sub setup_chgdcpass
2521 my ($self, $path) = @_;
2523 my $env = $self->provision_chgdcpass($path);
2524 if (defined $env) {
2525 if (not defined($self->check_or_start($env, "standard"))) {
2526 return undef;
2529 return $env;
2532 sub setup_fl2000dc
2534 my ($self, $path, $dc_vars) = @_;
2536 my $env = $self->provision_fl2000dc($path);
2537 if (defined $env) {
2538 if (not defined($self->check_or_start($env, "standard"))) {
2539 return undef;
2542 $env = $self->setup_trust($env, $dc_vars, "external", "--no-aes-keys --direction=outgoing");
2545 return $env;
2548 sub setup_fl2003dc
2550 my ($self, $path, $dc_vars) = @_;
2552 my $env = $self->provision_fl2003dc($path);
2554 if (defined $env) {
2555 if (not defined($self->check_or_start($env, "standard"))) {
2556 return undef;
2559 $env = $self->setup_trust($env, $dc_vars, "external", "--no-aes-keys");
2561 return $env;
2564 sub setup_fl2008r2dc
2566 my ($self, $path, $dc_vars) = @_;
2568 my $env = $self->provision_fl2008r2dc($path);
2570 if (defined $env) {
2571 if (not defined($self->check_or_start($env, "standard"))) {
2572 return undef;
2575 my $upn_array = ["$env->{REALM}.upn"];
2576 my $spn_array = ["$env->{REALM}.spn"];
2578 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
2579 return undef;
2582 $env = $self->setup_trust($env, $dc_vars, "forest", "");
2585 return $env;
2588 sub setup_vampire_dc
2590 return setup_generic_vampire_dc(@_, "2008");
2593 sub setup_vampire_2000_dc
2595 return setup_generic_vampire_dc(@_, "2000");
2598 sub setup_generic_vampire_dc
2600 my ($self, $path, $dc_vars, $fl) = @_;
2602 my $env = $self->provision_vampire_dc($path, $dc_vars, $fl);
2604 if (defined $env) {
2605 if (not defined($self->check_or_start($env, "single"))) {
2606 return undef;
2609 # force replicated DC to update repsTo/repsFrom
2610 # for vampired partitions
2611 my $samba_tool = Samba::bindir_path($self, "samba-tool");
2613 # as 'vampired' dc may add data in its local replica
2614 # we need to synchronize data between DCs
2615 my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
2616 my $cmd = $self->get_cmd_env_vars($env);
2617 $cmd .= " $samba_tool drs replicate $env->{DC_SERVER} $env->{SERVER}";
2618 $cmd .= " $dc_vars->{CONFIGURATION}";
2619 $cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
2620 # replicate Configuration NC
2621 my $cmd_repl = "$cmd \"CN=Configuration,$base_dn\"";
2622 unless(system($cmd_repl) == 0) {
2623 warn("Failed to replicate\n$cmd_repl");
2624 return undef;
2626 # replicate Default NC
2627 $cmd_repl = "$cmd \"$base_dn\"";
2628 unless(system($cmd_repl) == 0) {
2629 warn("Failed to replicate\n$cmd_repl");
2630 return undef;
2633 # Pull in a full set of changes from the main DC
2634 $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
2635 $cmd = $self->get_cmd_env_vars($env);
2636 $cmd .= " $samba_tool drs replicate $env->{SERVER} $env->{DC_SERVER}";
2637 $cmd .= " $dc_vars->{CONFIGURATION}";
2638 $cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
2639 # replicate Configuration NC
2640 $cmd_repl = "$cmd \"CN=Configuration,$base_dn\"";
2641 unless(system($cmd_repl) == 0) {
2642 warn("Failed to replicate\n$cmd_repl");
2643 return undef;
2645 # replicate Default NC
2646 $cmd_repl = "$cmd \"$base_dn\"";
2647 unless(system($cmd_repl) == 0) {
2648 warn("Failed to replicate\n$cmd_repl");
2649 return undef;
2653 return $env;
2656 sub setup_promoted_dc
2658 my ($self, $path, $dc_vars) = @_;
2660 my $env = $self->provision_promoted_dc($path, $dc_vars);
2662 if (defined $env) {
2663 if (not defined($self->check_or_start($env, "single"))) {
2664 return undef;
2667 # force source and replicated DC to update repsTo/repsFrom
2668 # for vampired partitions
2669 my $samba_tool = Samba::bindir_path($self, "samba-tool");
2670 my $cmd = $self->get_cmd_env_vars($env);
2671 # as 'vampired' dc may add data in its local replica
2672 # we need to synchronize data between DCs
2673 my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
2674 $cmd .= " $samba_tool drs replicate $env->{DC_SERVER} $env->{SERVER}";
2675 $cmd .= " $dc_vars->{CONFIGURATION}";
2676 $cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
2677 # replicate Configuration NC
2678 my $cmd_repl = "$cmd \"CN=Configuration,$base_dn\"";
2679 unless(system($cmd_repl) == 0) {
2680 warn("Failed to replicate\n$cmd_repl");
2681 return undef;
2683 # replicate Default NC
2684 $cmd_repl = "$cmd \"$base_dn\"";
2685 unless(system($cmd_repl) == 0) {
2686 warn("Failed to replicate\n$cmd_repl");
2687 return undef;
2691 return $env;
2694 sub setup_rodc
2696 my ($self, $path, $dc_vars) = @_;
2698 my $env = $self->provision_rodc($path, $dc_vars);
2700 unless ($env) {
2701 return undef;
2704 if (not defined($self->check_or_start($env, "standard"))) {
2705 return undef;
2708 my $samba_tool = Samba::bindir_path($self, "samba-tool");
2709 my $cmd = $self->get_cmd_env_vars($env);
2711 my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
2712 $cmd .= " $samba_tool drs replicate $env->{SERVER} $env->{DC_SERVER}";
2713 $cmd .= " $dc_vars->{CONFIGURATION}";
2714 $cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
2715 # replicate Configuration NC
2716 my $cmd_repl = "$cmd \"CN=Configuration,$base_dn\"";
2717 unless(system($cmd_repl) == 0) {
2718 warn("Failed to replicate\n$cmd_repl");
2719 return undef;
2721 # replicate Default NC
2722 $cmd_repl = "$cmd \"$base_dn\"";
2723 unless(system($cmd_repl) == 0) {
2724 warn("Failed to replicate\n$cmd_repl");
2725 return undef;
2728 return $env;
2731 sub _setup_ad_dc
2733 my ($self, $path, $conf_opts, $server, $dom, $functional_level) = @_;
2735 # If we didn't build with ADS, pretend this env was never available
2736 if (not $self->{target3}->have_ads()) {
2737 return "UNKNOWN";
2740 if (!defined($conf_opts)) {
2741 $conf_opts = "";
2743 if (!defined($server)) {
2744 $server = "addc";
2746 if (!defined($dom)) {
2747 $dom = "addom.samba.example.com";
2749 my $env = $self->provision_ad_dc($path, $server, "ADDOMAIN",
2750 $dom,
2751 undef,
2752 $conf_opts,
2753 undef,
2754 $functional_level);
2755 unless ($env) {
2756 return undef;
2759 if (not defined($self->check_or_start($env, "prefork"))) {
2760 return undef;
2763 my $upn_array = ["$env->{REALM}.upn"];
2764 my $spn_array = ["$env->{REALM}.spn"];
2766 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
2767 return undef;
2770 return $env;
2773 sub setup_ad_dc
2775 my ($self, $path) = @_;
2776 return _setup_ad_dc($self, $path, undef, undef, undef);
2779 sub setup_ad_dc_smb1
2781 my ($self, $path) = @_;
2782 my $conf_opts = "
2783 [global]
2784 client min protocol = CORE
2785 server min protocol = LANMAN1
2787 # needed for 'samba.tests.auth_log' tests
2788 server require schannel:ADDCSMB1\$ = no
2789 server schannel require seal:ADDCSMB1\$ = no
2791 return _setup_ad_dc($self, $path, $conf_opts, "addcsmb1", "addom2.samba.example.com");
2794 sub setup_ad_dc_smb1_done
2796 my ($self, $path, $dep_env) = @_;
2797 return $self->return_alias_env($path, $dep_env);
2800 sub setup_ad_dc_no_nss
2802 my ($self, $path) = @_;
2804 # If we didn't build with ADS, pretend this env was never available
2805 if (not $self->{target3}->have_ads()) {
2806 return "UNKNOWN";
2809 my $env = $self->provision_ad_dc($path,
2810 "addc_no_nss",
2811 "ADNONSSDOMAIN",
2812 "adnonssdom.samba.example.com",
2813 undef,
2815 undef);
2816 unless ($env) {
2817 return undef;
2820 $env->{NSS_WRAPPER_MODULE_SO_PATH} = undef;
2821 $env->{NSS_WRAPPER_MODULE_FN_PREFIX} = undef;
2823 if (not defined($self->check_or_start($env, "single"))) {
2824 return undef;
2827 my $upn_array = ["$env->{REALM}.upn"];
2828 my $spn_array = ["$env->{REALM}.spn"];
2830 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
2831 return undef;
2834 return $env;
2837 sub setup_ad_dc_no_ntlm
2839 my ($self, $path) = @_;
2841 # If we didn't build with ADS, pretend this env was never available
2842 if (not $self->{target3}->have_ads()) {
2843 return "UNKNOWN";
2846 my $env = $self->provision_ad_dc($path,
2847 "addc_no_ntlm",
2848 "ADNONTLMDOMAIN",
2849 "adnontlmdom.samba.example.com",
2850 undef,
2851 "ntlm auth = disabled\nnt hash store = never",
2852 undef);
2853 unless ($env) {
2854 return undef;
2857 if (not defined($self->check_or_start($env, "prefork"))) {
2858 return undef;
2861 my $upn_array = ["$env->{REALM}.upn"];
2862 my $spn_array = ["$env->{REALM}.spn"];
2864 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
2865 return undef;
2868 return $env;
2871 sub setup_ad_dc_fips
2873 my ($self, $path) = @_;
2875 # If we didn't build with ADS, pretend this env was never available
2876 if (not $self->{target3}->have_ads()) {
2877 return "UNKNOWN";
2880 my $env = $self->provision_ad_dc($path,
2881 "fipsdc",
2882 "FIPSDOMAIN",
2883 "fips.samba.example.com",
2886 undef);
2887 unless ($env) {
2888 return undef;
2891 if (not defined($self->check_or_start($env, "prefork"))) {
2892 return undef;
2895 my $upn_array = ["$env->{REALM}.upn"];
2896 my $spn_array = ["$env->{REALM}.spn"];
2898 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
2899 return undef;
2902 return $env;
2906 # AD DC test environment used solely to test pre-fork process restarts.
2907 # As processes get killed off and restarted it should not be used for other
2908 sub setup_preforkrestartdc
2910 my ($self, $path) = @_;
2912 # If we didn't build with ADS, pretend this env was never available
2913 if (not $self->{target3}->have_ads()) {
2914 return "UNKNOWN";
2917 # note DC name must be <= 15 chars so we use 'prockill' instead of
2918 # 'preforkrestart'
2919 my $env = $self->provision_ad_dc($path,
2920 "prockilldc",
2921 "PROCKILLDOMAIN",
2922 "prockilldom.samba.example.com",
2923 undef,
2924 "prefork backoff increment = 5\nprefork maximum backoff=10",
2925 undef);
2926 unless ($env) {
2927 return undef;
2930 # We treat processes in this environment cruelly, sometimes
2931 # sending them SIGSEGV signals. We don't need gdb_backtrace
2932 # dissecting these fake crashes in precise detail.
2933 $env->{PLEASE_NO_GDB_BACKTRACE} = '1';
2935 $env->{NSS_WRAPPER_MODULE_SO_PATH} = undef;
2936 $env->{NSS_WRAPPER_MODULE_FN_PREFIX} = undef;
2938 if (not defined($self->check_or_start($env, "prefork"))) {
2939 return undef;
2942 my $upn_array = ["$env->{REALM}.upn"];
2943 my $spn_array = ["$env->{REALM}.spn"];
2945 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
2946 return undef;
2949 return $env;
2953 # ad_dc test environment used solely to test standard process model connection
2954 # process limits. As the limit is set artificially low it should not be used
2955 # for other tests.
2956 sub setup_proclimitdc
2958 my ($self, $path) = @_;
2960 # If we didn't build with ADS, pretend this env was never available
2961 if (not $self->{target3}->have_ads()) {
2962 return "UNKNOWN";
2965 my $env = $self->provision_ad_dc($path,
2966 "proclimitdc",
2967 "PROCLIMITDOM",
2968 "proclimit.samba.example.com",
2969 undef,
2970 "max smbd processes = 20",
2971 undef);
2972 unless ($env) {
2973 return undef;
2976 $env->{NSS_WRAPPER_MODULE_SO_PATH} = undef;
2977 $env->{NSS_WRAPPER_MODULE_FN_PREFIX} = undef;
2979 if (not defined($self->check_or_start($env, "standard"))) {
2980 return undef;
2983 my $upn_array = ["$env->{REALM}.upn"];
2984 my $spn_array = ["$env->{REALM}.spn"];
2986 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
2987 return undef;
2990 return $env;
2993 # Used to test a live upgrade of the schema on a 2 DC network.
2994 sub setup_schema_dc
2996 my ($self, $path) = @_;
2998 # provision the PDC using an older base schema
2999 my $provision_args = ["--base-schema=2008_R2", "--backend-store=$self->{default_ldb_backend}"];
3001 # We set the functional level to 2008_R2 to match the older
3002 # base-schema (to allow schema upgrade to be tested)
3003 my $env = $self->provision_ad_dc($path,
3004 "liveupgrade1dc",
3005 "SCHEMADOMAIN",
3006 "schema.samba.example.com",
3007 undef,
3008 "drs: max link sync = 2",
3009 $provision_args,
3010 "2008_R2");
3011 unless ($env) {
3012 return undef;
3015 if (not defined($self->check_or_start($env, "prefork"))) {
3016 return undef;
3019 my $upn_array = ["$env->{REALM}.upn"];
3020 my $spn_array = ["$env->{REALM}.spn"];
3022 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
3023 return undef;
3026 return $env;
3029 # the second DC in the live schema upgrade pair
3030 sub setup_schema_pair_dc
3032 # note: dcvars contains the env info for the dependent testenv ('schema_dc')
3033 my ($self, $prefix, $dcvars) = @_;
3034 print "Preparing SCHEMA UPGRADE PAIR DC...\n";
3036 my ($env, $ctx) = $self->prepare_dc_testenv($prefix, "liveupgrade2dc",
3037 $dcvars->{DOMAIN},
3038 $dcvars->{REALM},
3039 $dcvars->{PASSWORD},
3040 "");
3042 my $samba_tool = Samba::bindir_path($self, "samba-tool");
3043 my $cmd_vars = $self->get_cmd_env_vars($env);
3045 my $join_cmd = $cmd_vars;
3046 $join_cmd .= "$samba_tool domain join $env->{CONFIGURATION} $dcvars->{REALM} DC --realm=$dcvars->{REALM}";
3047 $join_cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD} ";
3048 $join_cmd .= " --backend-store=$self->{default_ldb_backend}";
3050 my $upgrade_cmd = $cmd_vars;
3051 $upgrade_cmd .= "$samba_tool domain schemaupgrade $dcvars->{CONFIGURATION}";
3052 $upgrade_cmd .= " -U$dcvars->{USERNAME}\%$dcvars->{PASSWORD}";
3054 my $repl_cmd = $cmd_vars;
3055 $repl_cmd .= "$samba_tool drs replicate $env->{SERVER} $dcvars->{SERVER}";
3056 $repl_cmd .= " CN=Schema,CN=Configuration,DC=schema,DC=samba,DC=example,DC=com";
3057 $repl_cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
3059 unless (system($join_cmd) == 0) {
3060 warn("Join failed\n$join_cmd");
3061 return undef;
3064 $env->{DC_SERVER} = $dcvars->{SERVER};
3065 $env->{DC_SERVER_IP} = $dcvars->{SERVER_IP};
3066 $env->{DC_SERVER_IPV6} = $dcvars->{SERVER_IPV6};
3067 $env->{DC_NETBIOSNAME} = $dcvars->{NETBIOSNAME};
3069 # start samba for the new DC
3070 if (not defined($self->check_or_start($env, "standard"))) {
3071 return undef;
3074 unless (system($upgrade_cmd) == 0) {
3075 warn("Schema upgrade failed\n$upgrade_cmd");
3076 return undef;
3079 unless (system($repl_cmd) == 0) {
3080 warn("Post-update schema replication failed\n$repl_cmd");
3081 return undef;
3084 return $env;
3087 # Sets up a DC that's solely used to do a domain backup from. We then use the
3088 # backupfrom-DC to create the restore-DC - this proves that the backup/restore
3089 # process will create a Samba DC that will actually start up.
3090 # We don't use the backup-DC for anything else because its domain will conflict
3091 # with the restore DC.
3092 sub setup_backupfromdc
3094 my ($self, $path) = @_;
3096 # If we didn't build with ADS, pretend this env was never available
3097 if (not $self->{target3}->have_ads()) {
3098 return "UNKNOWN";
3101 my $provision_args = ["--site=Backup-Site"];
3103 my $env = $self->provision_ad_dc($path,
3104 "backupfromdc",
3105 "BACKUPDOMAIN",
3106 "backupdom.samba.example.com",
3107 undef,
3108 "samba kcc command = /bin/true",
3109 $provision_args);
3110 unless ($env) {
3111 return undef;
3114 if (not defined($self->check_or_start($env))) {
3115 return undef;
3118 my $upn_array = ["$env->{REALM}.upn"];
3119 my $spn_array = ["$env->{REALM}.spn"];
3121 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
3122 return undef;
3125 # Set up a dangling forward link to an expunged object
3127 # We need this to ensure that the "samba-tool domain backup rename"
3128 # that is part of the creation of the labdc environment can
3129 # cope with this situation on the source DC.
3131 if (not $self->write_ldb_file("$env->{PRIVATEDIR}/sam.ldb", "
3132 dn: ou=linktest,dc=backupdom,dc=samba,dc=example,dc=com
3133 objectclass: organizationalUnit
3136 dn: cn=linkto,ou=linktest,dc=backupdom,dc=samba,dc=example,dc=com
3137 objectclass: msExchConfigurationContainer
3140 dn: cn=linkfrom,ou=linktest,dc=backupdom,dc=samba,dc=example,dc=com
3141 objectclass: msExchConfigurationContainer
3142 addressBookRoots: cn=linkto,ou=linktest,dc=backupdom,dc=samba,dc=example,dc=com
3145 ")) {
3146 return undef;
3148 my $ldbdel = Samba::bindir_path($self, "ldbdel");
3149 my $cmd = "$ldbdel -H $env->{PRIVATEDIR}/sam.ldb cn=linkto,ou=linktest,dc=backupdom,dc=samba,dc=example,dc=com";
3151 unless(system($cmd) == 0) {
3152 warn("Failed to delete link target: \n$cmd");
3153 return undef;
3156 # Expunge will ensure that linkto is totally wiped from the DB
3157 my $samba_tool = Samba::bindir_path($self, "samba-tool");
3158 $cmd = "$samba_tool domain tombstones expunge --tombstone-lifetime=0 $env->{CONFIGURATION}";
3160 unless(system($cmd) == 0) {
3161 warn("Failed to expunge link target: \n$cmd");
3162 return undef;
3164 return $env;
3167 # returns the server/user-auth params needed to run an online backup cmd
3168 sub get_backup_server_args
3170 # dcvars contains the env info for the backup DC testenv
3171 my ($self, $dcvars) = @_;
3172 my $server = $dcvars->{DC_SERVER_IP};
3173 my $server_args = "--server=$server ";
3174 $server_args .= "-U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
3175 $server_args .= " $dcvars->{CONFIGURATION}";
3177 return $server_args;
3180 # Creates a backup of a running testenv DC
3181 sub create_backup
3183 # note: dcvars contains the env info for the backup DC testenv
3184 my ($self, $env, $dcvars, $backupdir, $backup_cmd) = @_;
3186 # get all the env variables we pass in with the samba-tool command
3187 # Note: use the backupfrom-DC's krb5.conf to do the backup
3188 my $overwrite = undef;
3189 $overwrite->{KRB5_CONFIG} = $dcvars->{KRB5_CONFIG};
3190 my $cmd_env = $self->get_cmd_env_vars($env, $overwrite);
3192 # use samba-tool to create a backup from the 'backupfromdc' DC
3193 my $cmd = "";
3194 my $samba_tool = Samba::bindir_path($self, "samba-tool");
3196 $cmd .= "$cmd_env $samba_tool domain backup $backup_cmd";
3197 $cmd .= " --targetdir=$backupdir";
3199 print "Executing: $cmd\n";
3200 unless(system($cmd) == 0) {
3201 warn("Failed to create backup using: \n$cmd");
3202 return undef;
3205 # get the name of the backup file created
3206 opendir(DIR, $backupdir);
3207 my @files = grep(/\.tar/, readdir(DIR));
3208 closedir(DIR);
3210 if(scalar @files != 1) {
3211 warn("Backup file not found in directory $backupdir\n");
3212 return undef;
3214 my $backup_file = "$backupdir/$files[0]";
3215 print "Using backup file $backup_file...\n";
3217 return $backup_file;
3220 # Restores a backup-file to populate a testenv for a new DC
3221 sub restore_backup_file
3223 my ($self, $backup_file, $restore_opts, $restoredir, $smbconf) = @_;
3225 # pass the restore command the testenv's smb.conf that we've already
3226 # generated. But move it to a temp-dir first, so that the restore doesn't
3227 # overwrite it
3228 my $tmpdir = File::Temp->newdir();
3229 my $tmpconf = "$tmpdir/smb.conf";
3230 my $cmd = "cp $smbconf $tmpconf";
3231 unless(system($cmd) == 0) {
3232 warn("Failed to backup smb.conf using: \n$cmd");
3233 return -1;
3236 my $samba_tool = Samba::bindir_path($self, "samba-tool");
3237 $cmd = "$samba_tool domain backup restore --backup-file=$backup_file";
3238 $cmd .= " --targetdir=$restoredir $restore_opts --configfile=$tmpconf";
3240 print "Executing: $cmd\n";
3241 unless(system($cmd) == 0) {
3242 warn("Failed to restore backup using: \n$cmd");
3243 return -1;
3246 print "Restore complete\n";
3247 return 0
3250 # sets up the initial directory and returns the new testenv's env info
3251 # (without actually doing a 'domain join')
3252 sub prepare_dc_testenv
3254 my ($self, $prefix, $dcname, $domain, $realm,
3255 $password, $conf_options, $dnsupdate_options) = @_;
3257 my $ctx = $self->provision_raw_prepare($prefix, "domain controller",
3258 $dcname,
3259 $domain,
3260 $realm,
3261 undef,
3262 "2008",
3263 $password,
3264 undef,
3265 undef);
3267 # the restore uses a slightly different state-dir location to other testenvs
3268 $ctx->{statedir} = "$ctx->{prefix_abs}/state";
3269 push(@{$ctx->{directories}}, "$ctx->{statedir}");
3271 # add support for sysvol/netlogon/tmp shares
3272 $ctx->{share} = "$ctx->{prefix_abs}/share";
3273 push(@{$ctx->{directories}}, "$ctx->{share}");
3274 push(@{$ctx->{directories}}, "$ctx->{share}/test1");
3276 if (defined($dnsupdate_options)) {
3277 $ctx->{samba_dnsupdate} .= $dnsupdate_options;
3280 $ctx->{smb_conf_extra_options} = "
3281 $conf_options
3283 # Some of the DCs based on this will be in FL 2016 domains, so
3284 # claim FL 2016 DC capability
3285 ad dc functional level = 2016
3287 max xmit = 32K
3288 server max protocol = SMB2
3289 samba kcc command = /bin/true
3290 xattr_tdb:file = $ctx->{statedir}/xattr.tdb
3292 [sysvol]
3293 path = $ctx->{statedir}/sysvol
3294 read only = no
3296 [netlogon]
3297 path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
3298 read only = no
3300 [tmp]
3301 path = $ctx->{share}
3302 read only = no
3303 posix:sharedelay = 10000
3304 posix:oplocktimeout = 3
3305 posix:writetimeupdatedelay = 50000
3307 [test1]
3308 path = $ctx->{share}/test1
3309 read only = no
3310 posix:sharedelay = 100000
3311 posix:oplocktimeout = 3
3312 posix:writetimeupdatedelay = 500000
3315 my $env = $self->provision_raw_step1($ctx);
3317 return ($env, $ctx);
3321 # Set up a DC testenv solely by using the samba-tool domain backup/restore
3322 # commands. This proves that we can backup an online DC ('backupfromdc') and
3323 # use the backup file to create a valid, working samba DC.
3324 sub setup_restoredc
3326 # note: dcvars contains the env info for the dependent testenv ('backupfromdc')
3327 my ($self, $prefix, $dcvars) = @_;
3328 print "Preparing RESTORE DC...\n";
3330 # we arbitrarily designate the restored DC as having SMBv1 disabled
3331 my $extra_conf = "
3332 server min protocol = SMB2
3333 client min protocol = SMB2
3334 prefork children = 1";
3335 my $dnsupdate_options = " --use-samba-tool --no-credentials";
3337 my ($env, $ctx) = $self->prepare_dc_testenv($prefix, "restoredc",
3338 $dcvars->{DOMAIN},
3339 $dcvars->{REALM},
3340 $dcvars->{PASSWORD},
3341 $extra_conf,
3342 $dnsupdate_options);
3344 # create a backup of the 'backupfromdc'
3345 my $backupdir = File::Temp->newdir();
3346 my $server_args = $self->get_backup_server_args($dcvars);
3347 my $backup_args = "online $server_args";
3348 my $backup_file = $self->create_backup($env, $dcvars, $backupdir,
3349 $backup_args);
3350 unless($backup_file) {
3351 return undef;
3354 # restore the backup file to populate the restore-DC testenv
3355 my $restore_dir = abs_path($prefix);
3356 my $ret = $self->restore_backup_file($backup_file,
3357 "--newservername=$env->{SERVER}",
3358 $restore_dir, $env->{SERVERCONFFILE});
3359 unless ($ret == 0) {
3360 return undef;
3364 # As we create the same domain as a clone
3365 # we need a separate resolv.conf!
3367 $ctx->{resolv_conf} = "$ctx->{etcdir}/resolv.conf";
3368 $ctx->{dns_ipv4} = $ctx->{ipv4};
3369 $ctx->{dns_ipv6} = $ctx->{ipv6};
3370 Samba::mk_resolv_conf($ctx);
3371 $env->{RESOLV_CONF} = $ctx->{resolv_conf};
3373 # start samba for the restored DC
3374 if (not defined($self->check_or_start($env))) {
3375 return undef;
3378 return $env;
3381 # Set up a DC testenv solely by using the 'samba-tool domain backup rename' and
3382 # restore commands. This proves that we can backup and rename an online DC
3383 # ('backupfromdc') and use the backup file to create a valid, working samba DC.
3384 sub setup_renamedc
3386 # note: dcvars contains the env info for the dependent testenv ('backupfromdc')
3387 my ($self, $prefix, $dcvars) = @_;
3388 print "Preparing RENAME DC...\n";
3389 my $extra_conf = "prefork children = 1";
3391 my $realm = "renamedom.samba.example.com";
3392 my ($env, $ctx) = $self->prepare_dc_testenv($prefix, "renamedc",
3393 "RENAMEDOMAIN", $realm,
3394 $dcvars->{PASSWORD}, $extra_conf);
3396 # create a backup of the 'backupfromdc' which renames the domain
3397 my $backupdir = File::Temp->newdir();
3398 my $server_args = $self->get_backup_server_args($dcvars);
3399 my $backup_args = "rename $env->{DOMAIN} $env->{REALM} $server_args";
3400 $backup_args .= " --backend-store=tdb";
3401 my $backup_file = $self->create_backup($env, $dcvars, $backupdir,
3402 $backup_args);
3403 unless($backup_file) {
3404 return undef;
3407 # restore the backup file to populate the rename-DC testenv
3408 my $restore_dir = abs_path($prefix);
3409 my $restore_opts = "--newservername=$env->{SERVER} --host-ip=$env->{SERVER_IP}";
3410 my $ret = $self->restore_backup_file($backup_file, $restore_opts,
3411 $restore_dir, $env->{SERVERCONFFILE});
3412 unless ($ret == 0) {
3413 return undef;
3416 # start samba for the restored DC
3417 if (not defined($self->check_or_start($env))) {
3418 return undef;
3421 my $upn_array = ["$env->{REALM}.upn"];
3422 my $spn_array = ["$env->{REALM}.spn"];
3424 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
3425 return undef;
3428 return $env;
3431 # Set up a DC testenv solely by using the 'samba-tool domain backup offline' and
3432 # restore commands. This proves that we do an offline backup of a local DC
3433 # ('backupfromdc') and use the backup file to create a valid, working samba DC.
3434 sub setup_offlinebackupdc
3436 # note: dcvars contains the env info for the dependent testenv ('backupfromdc')
3437 my ($self, $prefix, $dcvars) = @_;
3438 print "Preparing OFFLINE BACKUP DC...\n";
3439 my $extra_conf = "prefork children = 1";
3440 my $dnsupdate_options = " --use-samba-tool --no-credentials";
3442 my ($env, $ctx) = $self->prepare_dc_testenv($prefix, "offlinebackupdc",
3443 $dcvars->{DOMAIN},
3444 $dcvars->{REALM},
3445 $dcvars->{PASSWORD},
3446 $extra_conf,
3447 $dnsupdate_options);
3449 # create an offline backup of the 'backupfromdc' target
3450 my $backupdir = File::Temp->newdir();
3451 my $cmd = "offline --configfile $dcvars->{SERVERCONFFILE}";
3452 my $backup_file = $self->create_backup($env, $dcvars,
3453 $backupdir, $cmd);
3455 unless($backup_file) {
3456 return undef;
3459 # restore the backup file to populate the rename-DC testenv
3460 my $restore_dir = abs_path($prefix);
3461 my $restore_opts = "--newservername=$env->{SERVER} --host-ip=$env->{SERVER_IP}";
3462 my $ret = $self->restore_backup_file($backup_file, $restore_opts,
3463 $restore_dir, $env->{SERVERCONFFILE});
3464 unless ($ret == 0) {
3465 return undef;
3469 # As we create the same domain as a clone
3470 # we need a separate resolv.conf!
3472 $ctx->{resolv_conf} = "$ctx->{etcdir}/resolv.conf";
3473 $ctx->{dns_ipv4} = $ctx->{ipv4};
3474 $ctx->{dns_ipv6} = $ctx->{ipv6};
3475 Samba::mk_resolv_conf($ctx);
3476 $env->{RESOLV_CONF} = $ctx->{resolv_conf};
3478 # re-create the testenv's krb5.conf (the restore may have overwritten it)
3479 Samba::mk_krb5_conf($ctx);
3481 # start samba for the restored DC
3482 if (not defined($self->check_or_start($env))) {
3483 return undef;
3486 return $env;
3489 # Set up a DC testenv solely by using the samba-tool 'domain backup rename' and
3490 # restore commands, using the --no-secrets option. This proves that we can
3491 # create a realistic lab environment from an online DC ('backupfromdc').
3492 sub setup_labdc
3494 # note: dcvars contains the env info for the dependent testenv ('backupfromdc')
3495 my ($self, $prefix, $dcvars) = @_;
3496 print "Preparing LAB-DOMAIN DC...\n";
3497 my $extra_conf = "prefork children = 1";
3499 my ($env, $ctx) = $self->prepare_dc_testenv($prefix, "labdc",
3500 "LABDOMAIN",
3501 "labdom.samba.example.com",
3502 $dcvars->{PASSWORD}, $extra_conf);
3504 # create a backup of the 'backupfromdc' which renames the domain and uses
3505 # the --no-secrets option to scrub any sensitive info
3506 my $backupdir = File::Temp->newdir();
3507 my $server_args = $self->get_backup_server_args($dcvars);
3508 my $backup_args = "rename $env->{DOMAIN} $env->{REALM} $server_args";
3509 $backup_args .= " --no-secrets --backend-store=$self->{default_ldb_backend}";
3510 my $backup_file = $self->create_backup($env, $dcvars, $backupdir,
3511 $backup_args);
3512 unless($backup_file) {
3513 return undef;
3516 # restore the backup file to populate the lab-DC testenv
3517 my $restore_dir = abs_path($prefix);
3518 my $restore_opts = "--newservername=$env->{SERVER} --host-ip=$env->{SERVER_IP}";
3519 my $ret = $self->restore_backup_file($backup_file, $restore_opts,
3520 $restore_dir, $env->{SERVERCONFFILE});
3521 unless ($ret == 0) {
3522 return undef;
3525 # because we don't include any secrets in the backup, we need to reset the
3526 # admin user's password back to what the testenv expects
3527 my $samba_tool = Samba::bindir_path($self, "samba-tool");
3528 my $cmd = "$samba_tool user setpassword $env->{USERNAME} ";
3529 $cmd .= "--newpassword=$env->{PASSWORD} -H $restore_dir/private/sam.ldb";
3530 $cmd .= " $env->{CONFIGURATION}";
3532 unless(system($cmd) == 0) {
3533 warn("Failed to reset admin's password: \n$cmd");
3534 return undef;
3537 # start samba for the restored DC
3538 if (not defined($self->check_or_start($env))) {
3539 return undef;
3542 my $upn_array = ["$env->{REALM}.upn"];
3543 my $spn_array = ["$env->{REALM}.spn"];
3545 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
3546 return undef;
3549 return $env;
3552 # Inspects a backup *.tar.bz2 file and determines the realm/domain it contains
3553 sub get_backup_domain_realm
3555 my ($self, $backup_file) = @_;
3557 print "Determining REALM/DOMAIN values in backup...\n";
3559 # The backup will have the correct domain/realm values in the smb.conf.
3560 # So we can work out the env variables the testenv should use based on
3561 # that. Let's start by extracting the smb.conf
3562 my $tar = Archive::Tar->new($backup_file);
3563 my $tmpdir = File::Temp->newdir();
3564 my $smbconf = "$tmpdir/smb.conf";
3566 # note that the filepaths within the tar-file differ slightly for online
3567 # and offline backups
3568 if ($tar->contains_file("etc/smb.conf")) {
3569 $tar->extract_file("etc/smb.conf", $smbconf);
3570 } elsif ($tar->contains_file("./etc/smb.conf")) {
3571 $tar->extract_file("./etc/smb.conf", $smbconf);
3572 } else {
3573 warn("Could not find smb.conf in $backup_file");
3574 return undef, undef;
3577 # make sure we don't try to create locks/sockets in the default install
3578 # location (i.e. /usr/local/samba/)
3579 my $options = "--option=\"private dir = $tmpdir\"";
3580 $options .= " --option=\"lock dir = $tmpdir\"";
3582 # now use testparm to read the values we're interested in
3583 my $testparm = Samba::bindir_path($self, "testparm");
3584 my $domain = `$testparm $smbconf -sl --parameter-name=WORKGROUP $options`;
3585 my $realm = `$testparm $smbconf -sl --parameter-name=REALM $options`;
3586 chomp $realm;
3587 chomp $domain;
3588 print "Backup-file REALM is $realm, DOMAIN is $domain\n";
3590 return ($domain, $realm);
3593 # This spins up a custom testenv that can be based on any backup-file you want.
3594 # This is just intended for manual testing (rather than automated test-cases)
3595 sub setup_customdc
3597 my ($self, $prefix) = @_;
3598 print "Preparing CUSTOM RESTORE DC...\n";
3599 my $dc_name = "customdc";
3600 my $password = "locDCpass1";
3601 my $backup_file = $ENV{'BACKUP_FILE'};
3602 my $dnsupdate_options = " --use-samba-tool --no-credentials";
3604 # user must specify a backup file to restore via an ENV variable, i.e.
3605 # BACKUP_FILE=backup-blah.tar.bz2 SELFTEST_TESTENV=customdc make testenv
3606 if (not defined($backup_file)) {
3607 warn("Please specify BACKUP_FILE");
3608 return undef;
3611 # work out the correct domain/realm env values from the backup-file
3612 my ($domain, $realm) = $self->get_backup_domain_realm($backup_file);
3613 if ($domain eq '' or $realm eq '') {
3614 warn("Could not determine domain or realm");
3615 return undef;
3618 # create a placeholder directory and smb.conf, as well as the env vars.
3619 my ($env, $ctx) = $self->prepare_dc_testenv($prefix, $dc_name,
3620 $domain, $realm, $password, "",
3621 $dnsupdate_options);
3623 # restore the specified backup file to populate the testenv
3624 my $restore_dir = abs_path($prefix);
3625 my $ret = $self->restore_backup_file($backup_file,
3626 "--newservername=$env->{SERVER}",
3627 $restore_dir, $env->{SERVERCONFFILE});
3628 unless ($ret == 0) {
3629 return undef;
3633 # As we create the same domain as a clone
3634 # we need a separate resolv.conf!
3636 $ctx->{resolv_conf} = "$ctx->{etcdir}/resolv.conf";
3637 $ctx->{dns_ipv4} = $ctx->{ipv4};
3638 $ctx->{dns_ipv6} = $ctx->{ipv6};
3639 Samba::mk_resolv_conf($ctx);
3640 $env->{RESOLV_CONF} = $ctx->{resolv_conf};
3642 # Change the admin password to the testenv default, just in case it's
3643 # different, or in case this was a --no-secrets backup
3644 my $samba_tool = Samba::bindir_path($self, "samba-tool");
3645 my $cmd = "$samba_tool user setpassword $env->{USERNAME} ";
3646 $cmd .= "--newpassword=$password -H $restore_dir/private/sam.ldb";
3647 $cmd .= " $env->{CONFIGURATION}";
3649 unless(system($cmd) == 0) {
3650 warn("Failed to reset admin's password: \n$cmd");
3651 return undef;
3654 # re-create the testenv's krb5.conf (the restore may have overwritten it,
3655 # if the backup-file was an offline backup)
3656 Samba::mk_krb5_conf($ctx);
3658 # start samba for the restored DC
3659 if (not defined($self->check_or_start($env))) {
3660 return undef;
3663 # if this was a backup-rename, then we may need to setup namespaces
3664 my $upn_array = ["$env->{REALM}.upn"];
3665 my $spn_array = ["$env->{REALM}.spn"];
3667 if ($self->setup_namespaces($env, $upn_array, $spn_array) != 0) {
3668 return undef;
3671 return $env;
3674 sub setup_none
3676 my ($self, $path) = @_;
3678 my $ret = {
3679 KRB5_CONFIG => abs_path($path) . "/no_krb5.conf",
3680 SAMBA_PID => -1,