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.
5
6# NOTE: Refer to the README for more details about the various testenvs,
7# and tips about adding new testenvs.
8
9package Samba4;
10
11use strict;
12use Cwd qw(abs_path);
13use FindBin qw($RealBin);
14use POSIX;
15use SocketWrapper;
16use target::Samba;
17use target::Samba3;
18use Archive::Tar;
19use File::Path 'make_path';
20
21sub new($$$$$) {
22	my ($classname, $bindir, $srcdir, $server_maxtime) = @_;
23
24	my $self = {
25		vars => {},
26		bindir => $bindir,
27		srcdir => $srcdir,
28		server_maxtime => $server_maxtime,
29		target3 => new Samba3($bindir, $srcdir, $server_maxtime)
30	};
31	bless $self;
32	return $self;
33}
34
35sub scriptdir_path($$) {
36	my ($self, $path) = @_;
37	return "$self->{srcdir}/source4/scripting/$path";
38}
39
40sub check_or_start($$$)
41{
42        my ($self, $env_vars, $process_model) = @_;
43	my $STDIN_READER;
44
45	my $env_ok = $self->check_env($env_vars);
46	if ($env_ok) {
47		return $env_vars->{SAMBA_PID};
48	} elsif (defined($env_vars->{SAMBA_PID})) {
49		warn("SAMBA PID $env_vars->{SAMBA_PID} is not running (died)");
50		return undef;
51	}
52
53	# use a pipe for stdin in the child processes. This allows
54	# those processes to monitor the pipe for EOF to ensure they
55	# exit when the test script exits
56	pipe($STDIN_READER, $env_vars->{STDIN_PIPE});
57
58	# build up the command to run samba
59	my @preargs = ();
60	my @optargs = ();
61	if (defined($ENV{SAMBA_OPTIONS})) {
62		@optargs = split(/ /, $ENV{SAMBA_OPTIONS});
63	}
64	if(defined($ENV{SAMBA_VALGRIND})) {
65		@preargs = split(/ /,$ENV{SAMBA_VALGRIND});
66	}
67
68	if (defined($process_model)) {
69		push @optargs, ("-M", $process_model);
70	}
71	my $binary = Samba::bindir_path($self, "samba");
72	my @full_cmd = (@preargs, $binary, "-i",
73			"--no-process-group", "--maximum-runtime=$self->{server_maxtime}",
74			$env_vars->{CONFIGURATION}, @optargs);
75
76	# the samba process takes some additional env variables (compared to s3)
77	my $samba_envs = Samba::get_env_for_process("samba", $env_vars);
78	$samba_envs->{RESOLV_CONF} = $env_vars->{RESOLV_CONF};
79	$samba_envs->{UID_WRAPPER} = "1";
80	if (defined($ENV{MITKRB5})) {
81		$samba_envs->{KRB5_KDC_PROFILE} = $env_vars->{MITKDC_CONFIG};
82	}
83
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		ENV_VARS => $samba_envs,
92	};
93	my $pid = Samba::fork_and_exec($self, $env_vars, $daemon_ctx, $STDIN_READER);
94
95	$env_vars->{SAMBA_PID} = $pid;
96
97	# close the parent's read-end of the pipe
98	close($STDIN_READER);
99
100	if ($self->wait_for_start($env_vars) != 0) {
101	    warn("Samba $pid failed to start up");
102	    return undef;
103	}
104
105	return $pid;
106}
107
108sub wait_for_start($$)
109{
110	my ($self, $testenv_vars) = @_;
111	my $count = 0;
112	my $ret = 0;
113
114	if (not $self->check_env($testenv_vars)) {
115	    warn("unable to confirm Samba $testenv_vars->{SAMBA_PID} is running");
116	    return -1;
117	}
118
119	# This will return quickly when things are up, but be slow if we
120	# need to wait for (eg) SSL init
121	my $nmblookup =  Samba::bindir_path($self, "nmblookup4");
122
123	do {
124		$ret = system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{SERVER}");
125		if ($ret != 0) {
126			sleep(1);
127		} else {
128			system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{SERVER}");
129			system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
130			system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{NETBIOSNAME}");
131			system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
132			system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{NETBIOSNAME}");
133			system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{SERVER}");
134			system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{SERVER}");
135			system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
136			system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{NETBIOSNAME}");
137			system("$nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
138			system("$nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER_IP} $testenv_vars->{NETBIOSNAME}");
139		}
140		$count++;
141	} while ($ret != 0 && $count < 20);
142	if ($count == 20) {
143		teardown_env($self, $testenv_vars);
144		warn("nbt not reachable after 20 retries\n");
145		return -1;
146	}
147
148	# Ensure we have the first RID Set before we start tests.  This makes the tests more reliable.
149	if ($testenv_vars->{SERVER_ROLE} eq "domain controller") {
150		print "waiting for working LDAP and a RID Set to be allocated\n";
151		my $ldbsearch = Samba::bindir_path($self, "ldbsearch");
152		my $count = 0;
153		my $base_dn = "DC=".join(",DC=", split(/\./, $testenv_vars->{REALM}));
154
155		my $search_dn = $base_dn;
156		if ($testenv_vars->{NETBIOSNAME} ne "RODC") {
157			# TODO currently no check for actual rIDAllocationPool
158			$search_dn = "cn=RID Set,cn=$testenv_vars->{NETBIOSNAME},ou=domain controllers,$base_dn";
159		}
160		my $max_wait = 60;
161
162		# Add hosts file for name lookups
163		my $cmd = "NSS_WRAPPER_HOSTS='$testenv_vars->{NSS_WRAPPER_HOSTS}' ";
164		if (defined($testenv_vars->{RESOLV_WRAPPER_CONF})) {
165			$cmd .= "RESOLV_WRAPPER_CONF='$testenv_vars->{RESOLV_WRAPPER_CONF}' ";
166		} else {
167			$cmd .= "RESOLV_WRAPPER_HOSTS='$testenv_vars->{RESOLV_WRAPPER_HOSTS}' ";
168		}
169		$cmd .= "RESOLV_CONF='$testenv_vars->{RESOLV_CONF}' ";
170
171		$cmd .= "$ldbsearch ";
172		$cmd .= "$testenv_vars->{CONFIGURATION} ";
173		$cmd .= "-H ldap://$testenv_vars->{SERVER} ";
174		$cmd .= "-U$testenv_vars->{USERNAME}%$testenv_vars->{PASSWORD} ";
175		$cmd .= "-s base ";
176		$cmd .= "-b '$search_dn' ";
177		while (system("$cmd >/dev/null") != 0) {
178			$count++;
179			if ($count > $max_wait) {
180				teardown_env($self, $testenv_vars);
181				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}");
182				return -1;
183			}
184			print "Waiting for working LDAP...\n";
185			sleep(1);
186		}
187	}
188
189	my $wbinfo =  Samba::bindir_path($self, "wbinfo");
190
191	$count = 0;
192	do {
193		my $cmd = "NSS_WRAPPER_PASSWD=$testenv_vars->{NSS_WRAPPER_PASSWD} ";
194		$cmd .= "NSS_WRAPPER_GROUP=$testenv_vars->{NSS_WRAPPER_GROUP} ";
195		$cmd .= "SELFTEST_WINBINDD_SOCKET_DIR=$testenv_vars->{SELFTEST_WINBINDD_SOCKET_DIR} ";
196		$cmd .= "$wbinfo -P";
197		$ret = system($cmd);
198
199		if ($ret != 0) {
200			sleep(1);
201		}
202		$count++;
203	} while ($ret != 0 && $count < 20);
204	if ($count == 20) {
205		teardown_env($self, $testenv_vars);
206		warn("winbind not reachable after 20 retries\n");
207		return -1;
208	}
209
210	# Ensure we registered all our names
211	if ($testenv_vars->{SERVER_ROLE} eq "domain controller") {
212		my $max_wait = 120;
213		print "Waiting for dns_update_cache to be created.\n";
214		$count = 0;
215		while (not -e "$testenv_vars->{PRIVATEDIR}/dns_update_cache") {
216			$count++;
217			if ($count > $max_wait) {
218				teardown_env($self, $testenv_vars);
219				warn("Timed out ($max_wait sec) waiting for dns_update_cache PID $testenv_vars->{SAMBA_PID}");
220				return -1;
221			}
222			print "Waiting for dns_update_cache to be created...\n";
223			sleep(1);
224		}
225		print "Waiting for dns_update_cache to be filled.\n";
226		$count = 0;
227		while ((-s "$testenv_vars->{PRIVATEDIR}/dns_update_cache") == 0) {
228			$count++;
229			if ($count > $max_wait) {
230				teardown_env($self, $testenv_vars);
231				warn("Timed out ($max_wait sec) waiting for dns_update_cache PID $testenv_vars->{SAMBA_PID}");
232				return -1;
233			}
234			print "Waiting for dns_update_cache to be filled...\n";
235			sleep(1);
236		}
237	}
238
239	print $self->getlog_env($testenv_vars);
240
241	print "READY ($testenv_vars->{SAMBA_PID})\n";
242
243	return 0
244}
245
246sub write_ldb_file($$$)
247{
248	my ($self, $file, $ldif) = @_;
249
250	my $ldbadd =  Samba::bindir_path($self, "ldbadd");
251	open(LDIF, "|$ldbadd -H $file >/dev/null");
252	print LDIF $ldif;
253	return(close(LDIF));
254}
255
256sub add_wins_config($$)
257{
258	my ($self, $privatedir) = @_;
259	my $client_ip = Samba::get_ipv4_addr("client");
260
261	return $self->write_ldb_file("$privatedir/wins_config.ldb", "
262dn: name=TORTURE_11,CN=PARTNERS
263objectClass: wreplPartner
264name: TORTURE_11
265address: $client_ip
266pullInterval: 0
267pushChangeCount: 0
268type: 0x3
269");
270}
271
272sub setup_dns_hub_internal($$$)
273{
274	my ($self, $hostname, $prefix) = @_;
275	my $STDIN_READER;
276
277	unless(-d $prefix or make_path($prefix, 0777)) {
278		warn("Unable to create $prefix");
279		return undef;
280	}
281	my $prefix_abs = abs_path($prefix);
282
283	die ("prefix=''") if $prefix_abs eq "";
284	die ("prefix='/'") if $prefix_abs eq "/";
285
286	unless (system("rm -rf $prefix_abs/*") == 0) {
287		warn("Unable to clean up");
288	}
289
290	my $env = undef;
291	$env->{NETBIOSNAME} = $hostname;
292
293	$env->{SERVER_IP} = Samba::get_ipv4_addr($hostname);
294	$env->{SERVER_IPV6} = Samba::get_ipv6_addr($hostname);
295	$env->{SOCKET_WRAPPER_DEFAULT_IFACE} = Samba::get_interface($hostname);
296	$env->{DNS_HUB_LOG} = "$prefix_abs/dns_hub.log";
297	$env->{RESOLV_CONF} = "$prefix_abs/resolv.conf";
298	$env->{TESTENV_DIR} = $prefix_abs;
299
300	open(RESOLV_CONF, ">$env->{RESOLV_CONF}");
301	print RESOLV_CONF "nameserver $env->{SERVER_IP}\n";
302	print RESOLV_CONF "nameserver $env->{SERVER_IPV6}\n";
303	close(RESOLV_CONF);
304
305	my @preargs = ();
306	my @args = ();
307	if (!defined($ENV{PYTHON})) {
308	    push (@preargs, "env");
309	    push (@preargs, "python");
310	} else {
311	    push (@preargs, $ENV{PYTHON});
312	}
313	my $binary = "$self->{srcdir}/selftest/target/dns_hub.py";
314	push (@args, "$self->{server_maxtime}");
315	push (@args, "$env->{SERVER_IP}");
316	push (@args, Samba::realm_to_ip_mappings());
317	my @full_cmd = (@preargs, $binary, @args);
318
319	my $daemon_ctx = {
320		NAME => "dnshub",
321		BINARY_PATH => $binary,
322		FULL_CMD => [ @full_cmd ],
323		LOG_FILE => $env->{DNS_HUB_LOG},
324		TEE_STDOUT => 1,
325		PCAP_FILE => "$ENV{SOCKET_WRAPPER_PCAP_DIR}/env-$hostname$.pcap",
326		ENV_VARS => {},
327	};
328
329	# use a pipe for stdin in the child processes. This allows
330	# those processes to monitor the pipe for EOF to ensure they
331	# exit when the test script exits
332	pipe($STDIN_READER, $env->{STDIN_PIPE});
333
334	my $pid = Samba::fork_and_exec($self, $env, $daemon_ctx, $STDIN_READER);
335
336	$env->{SAMBA_PID} = $pid;
337	$env->{KRB5_CONFIG} = "$prefix_abs/no_krb5.conf";
338
339	# close the parent's read-end of the pipe
340	close($STDIN_READER);
341
342	return $env;
343}
344
345sub setup_dns_hub
346{
347	my ($self, $prefix) = @_;
348
349	my $hostname = "rootdnsforwarder";
350
351	my $env = $self->setup_dns_hub_internal("$hostname", "$prefix/$hostname");
352
353	$self->{dns_hub_env} = $env;
354
355	return $env;
356}
357
358sub get_dns_hub_env($)
359{
360	my ($self, $prefix) = @_;
361
362	if (defined($self->{dns_hub_env})) {
363	        return $self->{dns_hub_env};
364	}
365
366	die("get_dns_hub_env() not setup 'dns_hub_env'");
367	return undef;
368}
369
370# Returns the environmental variables that we pass to samba-tool commands
371sub get_cmd_env_vars
372{
373	my ($self, $localenv) = @_;
374
375	my $cmd_env = "NSS_WRAPPER_HOSTS='$localenv->{NSS_WRAPPER_HOSTS}' ";
376	$cmd_env .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$localenv->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
377	if (defined($localenv->{RESOLV_WRAPPER_CONF})) {
378		$cmd_env .= "RESOLV_WRAPPER_CONF=\"$localenv->{RESOLV_WRAPPER_CONF}\" ";
379	} else {
380		$cmd_env .= "RESOLV_WRAPPER_HOSTS=\"$localenv->{RESOLV_WRAPPER_HOSTS}\" ";
381	}
382	$cmd_env .= " KRB5_CONFIG=\"$localenv->{KRB5_CONFIG}\" ";
383	$cmd_env .= "KRB5CCNAME=\"$localenv->{KRB5_CCACHE}\" ";
384	$cmd_env .= "RESOLV_CONF=\"$localenv->{RESOLV_CONF}\" ";
385
386	return $cmd_env;
387}
388
389# Sets up a forest trust namespace.
390# (Note this is different to kernel namespaces, setup by the
391# USE_NAMESPACES=1 option)
392sub setup_namespaces($$:$$)
393{
394	my ($self, $localenv, $upn_array, $spn_array) = @_;
395
396	@{$upn_array} = [] unless defined($upn_array);
397	my $upn_args = "";
398	foreach my $upn (@{$upn_array}) {
399		$upn_args .= " --add-upn-suffix=$upn";
400	}
401
402	@{$spn_array} = [] unless defined($spn_array);
403	my $spn_args = "";
404	foreach my $spn (@{$spn_array}) {
405		$spn_args .= " --add-spn-suffix=$spn";
406	}
407
408	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
409
410	my $cmd_env = $self->get_cmd_env_vars($localenv);
411
412	my $cmd_config = " $localenv->{CONFIGURATION}";
413
414	my $namespaces = $cmd_env;
415	$namespaces .= " $samba_tool domain trust namespaces $upn_args $spn_args";
416	$namespaces .= $cmd_config;
417	unless (system($namespaces) == 0) {
418		warn("Failed to add namespaces \n$namespaces");
419		return;
420	}
421
422	return;
423}
424
425sub setup_trust($$$$$)
426{
427	my ($self, $localenv, $remoteenv, $type, $extra_args) = @_;
428
429	$localenv->{TRUST_SERVER} = $remoteenv->{SERVER};
430
431	$localenv->{TRUST_USERNAME} = $remoteenv->{USERNAME};
432	$localenv->{TRUST_PASSWORD} = $remoteenv->{PASSWORD};
433	$localenv->{TRUST_DOMAIN} = $remoteenv->{DOMAIN};
434	$localenv->{TRUST_REALM} = $remoteenv->{REALM};
435	$localenv->{TRUST_DOMSID} = $remoteenv->{DOMSID};
436
437	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
438
439	# setup the trust
440	my $cmd_env = $self->get_cmd_env_vars($localenv);
441
442	my $cmd_config = " $localenv->{CONFIGURATION}";
443	my $cmd_creds = $cmd_config;
444	$cmd_creds .= " -U$localenv->{TRUST_DOMAIN}\\\\$localenv->{TRUST_USERNAME}\%$localenv->{TRUST_PASSWORD}";
445
446	my $create = $cmd_env;
447	$create .= " $samba_tool domain trust create --type=${type} $localenv->{TRUST_REALM}";
448	$create .= " $extra_args";
449	$create .= $cmd_creds;
450	unless (system($create) == 0) {
451		warn("Failed to create trust \n$create");
452		return undef;
453	}
454
455	my $groupname = "g_$localenv->{TRUST_DOMAIN}";
456	my $groupadd = $cmd_env;
457	$groupadd .= " $samba_tool group add '$groupname' --group-scope=Domain $cmd_config";
458	unless (system($groupadd) == 0) {
459		warn("Failed to create group \n$groupadd");
460		return undef;
461	}
462	my $groupmem = $cmd_env;
463	$groupmem .= " $samba_tool group addmembers '$groupname' '$localenv->{TRUST_DOMSID}-513' $cmd_config";
464	unless (system($groupmem) == 0) {
465		warn("Failed to add group member \n$groupmem");
466		return undef;
467	}
468
469	return $localenv
470}
471
472sub provision_raw_prepare($$$$$$$$$$$$)
473{
474	my ($self, $prefix, $server_role, $hostname,
475	    $domain, $realm, $samsid, $functional_level,
476	    $password, $kdc_ipv4, $kdc_ipv6) = @_;
477	my $ctx;
478	my $python_cmd = "";
479	if (defined $ENV{PYTHON}) {
480		$python_cmd = $ENV{PYTHON} . " ";
481	}
482	$ctx->{python} = $python_cmd;
483	my $netbiosname = uc($hostname);
484
485	unless(-d $prefix or mkdir($prefix, 0777)) {
486		warn("Unable to create $prefix");
487		return undef;
488	}
489	my $prefix_abs = abs_path($prefix);
490
491	die ("prefix=''") if $prefix_abs eq "";
492	die ("prefix='/'") if $prefix_abs eq "/";
493
494	unless (system("rm -rf $prefix_abs/*") == 0) {
495		warn("Unable to clean up");
496	}
497
498
499	my $swiface = Samba::get_interface($hostname);
500
501	$ctx->{prefix} = $prefix;
502	$ctx->{prefix_abs} = $prefix_abs;
503
504	$ctx->{server_role} = $server_role;
505	$ctx->{hostname} = $hostname;
506	$ctx->{netbiosname} = $netbiosname;
507	$ctx->{swiface} = $swiface;
508	$ctx->{password} = $password;
509	$ctx->{kdc_ipv4} = $kdc_ipv4;
510	$ctx->{kdc_ipv6} = $kdc_ipv6;
511	$ctx->{krb5_ccname} = "$prefix_abs/krb5cc_%{uid}";
512	if ($functional_level eq "2000") {
513		$ctx->{supported_enctypes} = "arcfour-hmac-md5 des-cbc-md5 des-cbc-crc"
514	}
515
516#
517# Set smbd log level here.
518#
519	$ctx->{server_loglevel} =$ENV{SERVER_LOG_LEVEL} || 1;
520	$ctx->{username} = "Administrator";
521	$ctx->{domain} = $domain;
522	$ctx->{realm} = uc($realm);
523	$ctx->{dnsname} = lc($realm);
524	$ctx->{samsid} = $samsid;
525
526	$ctx->{functional_level} = $functional_level;
527
528	my $unix_name = ($ENV{USER} or $ENV{LOGNAME} or `whoami`);
529	chomp $unix_name;
530	$ctx->{unix_name} = $unix_name;
531	$ctx->{unix_uid} = $>;
532	my @mygid = split(" ", $();
533	$ctx->{unix_gid} = $mygid[0];
534	$ctx->{unix_gids_str} = $);
535	@{$ctx->{unix_gids}} = split(" ", $ctx->{unix_gids_str});
536
537	$ctx->{etcdir} = "$prefix_abs/etc";
538	$ctx->{piddir} = "$prefix_abs/pid";
539	$ctx->{smb_conf} = "$ctx->{etcdir}/smb.conf";
540	$ctx->{krb5_conf} = "$ctx->{etcdir}/krb5.conf";
541	$ctx->{krb5_ccache} = "$prefix_abs/krb5_ccache";
542	$ctx->{mitkdc_conf} = "$ctx->{etcdir}/mitkdc.conf";
543	$ctx->{privatedir} = "$prefix_abs/private";
544	$ctx->{binddnsdir} = "$prefix_abs/bind-dns";
545	$ctx->{ncalrpcdir} = "$prefix_abs/ncalrpc";
546	$ctx->{lockdir} = "$prefix_abs/lockdir";
547	$ctx->{logdir} = "$prefix_abs/logs";
548	$ctx->{statedir} = "$prefix_abs/statedir";
549	$ctx->{cachedir} = "$prefix_abs/cachedir";
550	$ctx->{winbindd_socket_dir} = "$prefix_abs/winbindd_socket";
551	$ctx->{ntp_signd_socket_dir} = "$prefix_abs/ntp_signd_socket";
552	$ctx->{nsswrap_passwd} = "$ctx->{etcdir}/passwd";
553	$ctx->{nsswrap_group} = "$ctx->{etcdir}/group";
554	$ctx->{nsswrap_hosts} = "$ENV{SELFTEST_PREFIX}/hosts";
555	$ctx->{nsswrap_hostname} = "$ctx->{hostname}.$ctx->{dnsname}";
556	if ($ENV{SAMBA_DNS_FAKING}) {
557		$ctx->{dns_host_file} = "$ENV{SELFTEST_PREFIX}/dns_host_file";
558		$ctx->{samba_dnsupdate} = "$ENV{SRCDIR_ABS}/source4/scripting/bin/samba_dnsupdate -s $ctx->{smb_conf} --all-interfaces --use-file=$ctx->{dns_host_file}";
559		$ctx->{samba_dnsupdate} = $python_cmd .  $ctx->{samba_dnsupdate};
560	} else {
561	        $ctx->{samba_dnsupdate} = "$ENV{SRCDIR_ABS}/source4/scripting/bin/samba_dnsupdate -s $ctx->{smb_conf} --all-interfaces";
562		$ctx->{samba_dnsupdate} = $python_cmd .  $ctx->{samba_dnsupdate};
563		$ctx->{use_resolv_wrapper} = 1;
564	}
565
566	my $dns_hub = $self->get_dns_hub_env();
567	$ctx->{resolv_conf} = $dns_hub->{RESOLV_CONF};
568
569	$ctx->{tlsdir} = "$ctx->{privatedir}/tls";
570
571	$ctx->{ipv4} = Samba::get_ipv4_addr($hostname);
572	$ctx->{ipv6} = Samba::get_ipv6_addr($hostname);
573
574	push(@{$ctx->{directories}}, $ctx->{privatedir});
575	push(@{$ctx->{directories}}, $ctx->{binddnsdir});
576	push(@{$ctx->{directories}}, $ctx->{etcdir});
577	push(@{$ctx->{directories}}, $ctx->{piddir});
578	push(@{$ctx->{directories}}, $ctx->{lockdir});
579	push(@{$ctx->{directories}}, $ctx->{logdir});
580	push(@{$ctx->{directories}}, $ctx->{statedir});
581	push(@{$ctx->{directories}}, $ctx->{cachedir});
582
583	$ctx->{smb_conf_extra_options} = "";
584
585	my @provision_options = ();
586	push (@provision_options, "KRB5_CONFIG=\"$ctx->{krb5_conf}\"");
587	push (@provision_options, "KRB5_CCACHE=\"$ctx->{krb5_ccache}\"");
588	push (@provision_options, "NSS_WRAPPER_PASSWD=\"$ctx->{nsswrap_passwd}\"");
589	push (@provision_options, "NSS_WRAPPER_GROUP=\"$ctx->{nsswrap_group}\"");
590	push (@provision_options, "NSS_WRAPPER_HOSTS=\"$ctx->{nsswrap_hosts}\"");
591	push (@provision_options, "NSS_WRAPPER_HOSTNAME=\"$ctx->{nsswrap_hostname}\"");
592	if (defined($ctx->{use_resolv_wrapper})) {
593		push (@provision_options, "RESOLV_WRAPPER_CONF=\"$ctx->{resolv_conf}\"");
594		push (@provision_options, "RESOLV_CONF=\"$ctx->{resolv_conf}\"");
595	} else {
596		push (@provision_options, "RESOLV_WRAPPER_HOSTS=\"$ctx->{dns_host_file}\"");
597	}
598	if (defined($ENV{GDB_PROVISION})) {
599		push (@provision_options, "gdb --args");
600		if (!defined($ENV{PYTHON})) {
601		    push (@provision_options, "env");
602		    push (@provision_options, "python");
603		}
604	}
605	if (defined($ENV{VALGRIND_PROVISION})) {
606		push (@provision_options, "valgrind");
607		if (!defined($ENV{PYTHON})) {
608		    push (@provision_options, "env");
609		    push (@provision_options, "python");
610		}
611	}
612
613	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
614
615	push (@provision_options, $samba_tool);
616	push (@provision_options, "domain");
617	push (@provision_options, "provision");
618	push (@provision_options, "--configfile=$ctx->{smb_conf}");
619	push (@provision_options, "--host-name=$ctx->{hostname}");
620	push (@provision_options, "--host-ip=$ctx->{ipv4}");
621	push (@provision_options, "--quiet");
622	push (@provision_options, "--domain=$ctx->{domain}");
623	push (@provision_options, "--realm=$ctx->{realm}");
624	if (defined($ctx->{samsid})) {
625		push (@provision_options, "--domain-sid=$ctx->{samsid}");
626	}
627	push (@provision_options, "--adminpass=$ctx->{password}");
628	push (@provision_options, "--krbtgtpass=krbtgt$ctx->{password}");
629	push (@provision_options, "--machinepass=machine$ctx->{password}");
630	push (@provision_options, "--root=$ctx->{unix_name}");
631	push (@provision_options, "--server-role=\"$ctx->{server_role}\"");
632	push (@provision_options, "--function-level=\"$ctx->{functional_level}\"");
633
634	@{$ctx->{provision_options}} = @provision_options;
635
636	return $ctx;
637}
638
639sub has_option
640{
641	my ($self, $keyword, @options_list) = @_;
642
643	# convert the options-list to a hash-map for easy keyword lookup
644	my %options_dict = map { $_ => 1 } @options_list;
645
646	return exists $options_dict{$keyword};
647}
648
649#
650# Step1 creates the basic configuration
651#
652sub provision_raw_step1($$)
653{
654	my ($self, $ctx) = @_;
655
656	mkdir($_, 0777) foreach (@{$ctx->{directories}});
657
658	##
659	## lockdir and piddir must be 0755
660	##
661	chmod 0755, $ctx->{lockdir};
662	chmod 0755, $ctx->{piddir};
663
664	unless (open(CONFFILE, ">$ctx->{smb_conf}")) {
665		warn("can't open $ctx->{smb_conf}$?");
666		return undef;
667	}
668
669	Samba::prepare_keyblobs($ctx);
670	my $crlfile = "$ctx->{tlsdir}/crl.pem";
671	$crlfile = "" unless -e ${crlfile};
672
673	# work out which file server to use. Default to source3 smbd (s3fs),
674	# unless the source4 NTVFS (smb) file server has been specified
675	my $services = "-smb +s3fs";
676	if ($self->has_option("--use-ntvfs", @{$ctx->{provision_options}})) {
677		$services = "+smb -s3fs";
678	}
679
680	my $interfaces = Samba::get_interfaces_config($ctx->{netbiosname});
681
682	print CONFFILE "
683[global]
684	netbios name = $ctx->{netbiosname}
685	posix:eadb = $ctx->{statedir}/eadb.tdb
686	workgroup = $ctx->{domain}
687	realm = $ctx->{realm}
688	private dir = $ctx->{privatedir}
689	binddns dir = $ctx->{binddnsdir}
690	pid directory = $ctx->{piddir}
691	ncalrpc dir = $ctx->{ncalrpcdir}
692	lock dir = $ctx->{lockdir}
693	state directory = $ctx->{statedir}
694	cache directory = $ctx->{cachedir}
695	winbindd socket directory = $ctx->{winbindd_socket_dir}
696	ntp signd socket directory = $ctx->{ntp_signd_socket_dir}
697	winbind separator = /
698	interfaces = $interfaces
699	tls dh params file = $ctx->{tlsdir}/dhparms.pem
700	tls crlfile = ${crlfile}
701	tls verify peer = no_check
702	panic action = $RealBin/gdb_backtrace \%d
703	wins support = yes
704	server role = $ctx->{server_role}
705	server services = +echo $services
706        dcerpc endpoint servers = +winreg +srvsvc
707	notify:inotify = false
708	ldb:nosync = true
709	ldap server require strong auth = yes
710#We don't want to pass our self-tests if the PAC code is wrong
711	gensec:require_pac = true
712	log file = $ctx->{logdir}/log.\%m
713	log level = $ctx->{server_loglevel}
714	lanman auth = Yes
715	ntlm auth = Yes
716	client min protocol = CORE
717	server min protocol = LANMAN1
718	mangled names = yes
719	dns update command = $ctx->{samba_dnsupdate}
720	spn update command = $ctx->{python} $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_spnupdate -s $ctx->{smb_conf}
721	gpo update command = $ctx->{python} $ENV{SRCDIR_ABS}/source4/scripting/bin/samba-gpupdate -s $ctx->{smb_conf} --target=Computer
722	samba kcc command = $ctx->{python} $ENV{SRCDIR_ABS}/source4/scripting/bin/samba_kcc
723	dreplsrv:periodic_startup_interval = 0
724	dsdb:schema update allowed = yes
725
726        vfs objects = dfs_samba4 acl_xattr fake_acls xattr_tdb streams_depot
727
728        idmap_ldb:use rfc2307=yes
729	winbind enum users = yes
730	winbind enum groups = yes
731
732        rpc server port:netlogon = 1026
733	include system krb5 conf = no
734
735";
736
737	print CONFFILE "
738
739	# Begin extra options
740	$ctx->{smb_conf_extra_options}
741	# End extra options
742";
743	close(CONFFILE);
744
745        #Default the KDC IP to the server's IP
746	if (not defined($ctx->{kdc_ipv4})) {
747		$ctx->{kdc_ipv4} = $ctx->{ipv4};
748	}
749	if (not defined($ctx->{kdc_ipv6})) {
750		$ctx->{kdc_ipv6} = $ctx->{ipv6};
751	}
752
753	Samba::mk_krb5_conf($ctx);
754	Samba::mk_mitkdc_conf($ctx, abs_path(Samba::bindir_path($self, "shared")));
755
756	open(PWD, ">$ctx->{nsswrap_passwd}");
757	if ($ctx->{unix_uid} != 0) {
758		print PWD "root:x:0:0:root gecos:$ctx->{prefix_abs}:/bin/false\n";
759	}
760	print PWD "$ctx->{unix_name}:x:$ctx->{unix_uid}:65531:$ctx->{unix_name} gecos:$ctx->{prefix_abs}:/bin/false\n";
761	print PWD "nobody:x:65534:65533:nobody gecos:$ctx->{prefix_abs}:/bin/false
762pdbtest:x:65533:65533:pdbtest gecos:$ctx->{prefix_abs}:/bin/false
763pdbtest2:x:65532:65533:pdbtest gecos:$ctx->{prefix_abs}:/bin/false
764pdbtest3:x:65531:65533:pdbtest gecos:$ctx->{prefix_abs}:/bin/false
765pdbtest4:x:65530:65533:pdbtest gecos:$ctx->{prefix_abs}:/bin/false
766";
767	close(PWD);
768        my $uid_rfc2307test = 65533;
769
770	open(GRP, ">$ctx->{nsswrap_group}");
771	if ($ctx->{unix_gid} != 0) {
772		print GRP "root:x:0:\n";
773	}
774	print GRP "$ctx->{unix_name}:x:$ctx->{unix_gid}:\n";
775	print GRP "wheel:x:10:
776users:x:65531:
777nobody:x:65533:
778nogroup:x:65534:nobody
779";
780	close(GRP);
781        my $gid_rfc2307test = 65532;
782
783	my $hostname = lc($ctx->{hostname});
784	open(HOSTS, ">>$ctx->{nsswrap_hosts}");
785	if ($hostname eq "localdc") {
786		print HOSTS "$ctx->{ipv4} ${hostname}.$ctx->{dnsname} $ctx->{dnsname} ${hostname}\n";
787		print HOSTS "$ctx->{ipv6} ${hostname}.$ctx->{dnsname} $ctx->{dnsname} ${hostname}\n";
788	} else {
789		print HOSTS "$ctx->{ipv4} ${hostname}.$ctx->{dnsname} ${hostname}\n";
790		print HOSTS "$ctx->{ipv6} ${hostname}.$ctx->{dnsname} ${hostname}\n";
791	}
792	close(HOSTS);
793
794	my $configuration = "--configfile=$ctx->{smb_conf}";
795
796#Ensure the config file is valid before we start
797	my $testparm = Samba::bindir_path($self, "samba-tool") . " testparm";
798	if (system("$testparm $configuration -v --suppress-prompt >/dev/null 2>&1") != 0) {
799		system("$testparm -v --suppress-prompt $configuration >&2");
800		warn("Failed to create a valid smb.conf configuration $testparm!");
801		return undef;
802	}
803	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) {
804		warn("Failed to create a valid smb.conf configuration! $testparm $configuration -v --suppress-prompt --parameter-name=\"netbios name\" --section-name=global");
805		return undef;
806	}
807
808	# Return the environment variables for the new testenv DC.
809	# Note that we have SERVER_X and DC_SERVER_X variables (which have the same
810	# value initially). In a 2 DC setup, $DC_SERVER_X will always be the PDC.
811	my $ret = {
812		KRB5_CONFIG => $ctx->{krb5_conf},
813		KRB5_CCACHE => $ctx->{krb5_ccache},
814		MITKDC_CONFIG => $ctx->{mitkdc_conf},
815		PIDDIR => $ctx->{piddir},
816		SERVER => $ctx->{hostname},
817		DC_SERVER => $ctx->{hostname},
818		SERVER_IP => $ctx->{ipv4},
819		DC_SERVER_IP => $ctx->{ipv4},
820		SERVER_IPV6 => $ctx->{ipv6},
821		DC_SERVER_IPV6 => $ctx->{ipv6},
822		NETBIOSNAME => $ctx->{netbiosname},
823		DC_NETBIOSNAME => $ctx->{netbiosname},
824		DOMAIN => $ctx->{domain},
825		USERNAME => $ctx->{username},
826		DC_USERNAME => $ctx->{username},
827		REALM => $ctx->{realm},
828		DNSNAME => $ctx->{dnsname},
829		SAMSID => $ctx->{samsid},
830		PASSWORD => $ctx->{password},
831		DC_PASSWORD => $ctx->{password},
832		LDAPDIR => $ctx->{ldapdir},
833		LDAP_INSTANCE => $ctx->{ldap_instance},
834		SELFTEST_WINBINDD_SOCKET_DIR => $ctx->{winbindd_socket_dir},
835		NCALRPCDIR => $ctx->{ncalrpcdir},
836		LOCKDIR => $ctx->{lockdir},
837		STATEDIR => $ctx->{statedir},
838		CACHEDIR => $ctx->{cachedir},
839		PRIVATEDIR => $ctx->{privatedir},
840		BINDDNSDIR => $ctx->{binddnsdir},
841		SERVERCONFFILE => $ctx->{smb_conf},
842		TESTENV_DIR => $ctx->{prefix_abs},
843		CONFIGURATION => $configuration,
844		SOCKET_WRAPPER_DEFAULT_IFACE => $ctx->{swiface},
845		NSS_WRAPPER_PASSWD => $ctx->{nsswrap_passwd},
846		NSS_WRAPPER_GROUP => $ctx->{nsswrap_group},
847		NSS_WRAPPER_HOSTS => $ctx->{nsswrap_hosts},
848		NSS_WRAPPER_HOSTNAME => $ctx->{nsswrap_hostname},
849		SAMBA_TEST_FIFO => "$ctx->{prefix}/samba_test.fifo",
850		SAMBA_TEST_LOG => "$ctx->{prefix}/samba_test.log",
851		SAMBA_TEST_LOG_POS => 0,
852		NSS_WRAPPER_MODULE_SO_PATH => Samba::nss_wrapper_winbind_so_path($self),
853		NSS_WRAPPER_MODULE_FN_PREFIX => "winbind",
854                LOCAL_PATH => $ctx->{share},
855                UID_RFC2307TEST => $uid_rfc2307test,
856                GID_RFC2307TEST => $gid_rfc2307test,
857                SERVER_ROLE => $ctx->{server_role},
858	        RESOLV_CONF => $ctx->{resolv_conf}
859	};
860
861	if (defined($ctx->{use_resolv_wrapper})) {
862	        $ret->{RESOLV_WRAPPER_CONF} = $ctx->{resolv_conf};
863	} else {
864		$ret->{RESOLV_WRAPPER_HOSTS} = $ctx->{dns_host_file};
865	}
866
867	if ($ctx->{server_role} eq "domain controller") {
868		$ret->{DOMSID} = $ret->{SAMSID};
869	}
870
871	return $ret;
872}
873
874#
875# Step2 runs the provision script
876#
877sub provision_raw_step2($$$)
878{
879	my ($self, $ctx, $ret) = @_;
880
881	my $provision_cmd = join(" ", @{$ctx->{provision_options}});
882	unless (system($provision_cmd) == 0) {
883		warn("Unable to provision: \n$provision_cmd\n");
884		return undef;
885	}
886
887	my $testallowed_account = "testallowed";
888	my $samba_tool_cmd = "";
889	$samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
890	$samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
891	$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
892	    . " user create --configfile=$ctx->{smb_conf} $testallowed_account $ctx->{password}";
893	unless (system($samba_tool_cmd) == 0) {
894		warn("Unable to add testallowed user: \n$samba_tool_cmd\n");
895		return undef;
896	}
897
898	my $ldbmodify = "";
899	$ldbmodify .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
900	$ldbmodify .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
901	$ldbmodify .= Samba::bindir_path($self, "ldbmodify");
902	$ldbmodify .=  " --configfile=$ctx->{smb_conf}";
903	my $base_dn = "DC=".join(",DC=", split(/\./, $ctx->{realm}));
904
905	if ($ctx->{server_role} ne "domain controller") {
906		$base_dn = "DC=$ctx->{netbiosname}";
907	}
908
909	my $user_dn = "cn=$testallowed_account,cn=users,$base_dn";
910	$testallowed_account = "testallowed account";
911	open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb");
912	print LDIF "dn: $user_dn
913changetype: modify
914replace: samAccountName
915samAccountName: $testallowed_account
916-
917";
918	close(LDIF);
919
920	open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb");
921	print LDIF "dn: $user_dn
922changetype: modify
923replace: userPrincipalName
924userPrincipalName: testallowed upn\@$ctx->{realm}
925replace: servicePrincipalName
926servicePrincipalName: host/testallowed
927-
928";
929	close(LDIF);
930
931	$samba_tool_cmd = "";
932	$samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
933	$samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
934	$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
935	    . " user create --configfile=$ctx->{smb_conf} testdenied $ctx->{password}";
936	unless (system($samba_tool_cmd) == 0) {
937		warn("Unable to add testdenied user: \n$samba_tool_cmd\n");
938		return undef;
939	}
940
941	my $user_dn = "cn=testdenied,cn=users,$base_dn";
942	open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb");
943	print LDIF "dn: $user_dn
944changetype: modify
945replace: userPrincipalName
946userPrincipalName: testdenied_upn\@$ctx->{realm}.upn
947-
948";
949	close(LDIF);
950
951	$samba_tool_cmd = "";
952	$samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
953	$samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
954	$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
955	    . " user create --configfile=$ctx->{smb_conf} testupnspn $ctx->{password}";
956	unless (system($samba_tool_cmd) == 0) {
957		warn("Unable to add testupnspn user: \n$samba_tool_cmd\n");
958		return undef;
959	}
960
961	my $user_dn = "cn=testupnspn,cn=users,$base_dn";
962	open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb");
963	print LDIF "dn: $user_dn
964changetype: modify
965replace: userPrincipalName
966userPrincipalName: http/testupnspn.$ctx->{dnsname}\@$ctx->{realm}
967replace: servicePrincipalName
968servicePrincipalName: http/testupnspn.$ctx->{dnsname}
969-
970";
971	close(LDIF);
972
973	$samba_tool_cmd = "";
974	$samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
975	$samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
976	$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
977	    . " group addmembers --configfile=$ctx->{smb_conf} 'Allowed RODC Password Replication Group' '$testallowed_account'";
978	unless (system($samba_tool_cmd) == 0) {
979		warn("Unable to add '$testallowed_account' user to 'Allowed RODC Password Replication Group': \n$samba_tool_cmd\n");
980		return undef;
981	}
982
983	# Create to users alice and bob!
984	my $user_account_array = ["alice", "bob", "jane"];
985
986	foreach my $user_account (@{$user_account_array}) {
987		my $samba_tool_cmd = "";
988
989		$samba_tool_cmd .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
990		$samba_tool_cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
991		$samba_tool_cmd .= Samba::bindir_path($self, "samba-tool")
992		    . " user create --configfile=$ctx->{smb_conf} $user_account Secret007";
993		unless (system($samba_tool_cmd) == 0) {
994			warn("Unable to create user: $user_account\n$samba_tool_cmd\n");
995			return undef;
996		}
997	}
998
999	my $ldbmodify = "";
1000	$ldbmodify .= "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
1001	$ldbmodify .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
1002	$ldbmodify .= Samba::bindir_path($self, "ldbmodify");
1003	$ldbmodify .=  " --configfile=$ctx->{smb_conf}";
1004	my $base_dn = "DC=".join(",DC=", split(/\./, $ctx->{realm}));
1005	my $user_dn = "cn=jane,cn=users,$base_dn";
1006
1007	open(LDIF, "|$ldbmodify -H $ctx->{privatedir}/sam.ldb");
1008	print LDIF "dn: $user_dn
1009changetype: modify
1010replace: userPrincipalName
1011userPrincipalName: jane.doe\@$ctx->{realm}
1012-
1013";
1014	close(LDIF);
1015
1016	return $ret;
1017}
1018
1019sub provision($$$$$$$$$$)
1020{
1021	my ($self, $prefix, $server_role, $hostname,
1022	    $domain, $realm, $functional_level,
1023	    $password, $kdc_ipv4, $kdc_ipv6, $extra_smbconf_options, $extra_smbconf_shares,
1024	    $extra_provision_options) = @_;
1025
1026	my $samsid = Samba::random_domain_sid();
1027
1028	my $ctx = $self->provision_raw_prepare($prefix, $server_role,
1029					       $hostname,
1030					       $domain, $realm,
1031					       $samsid,
1032					       $functional_level,
1033					       $password, $kdc_ipv4, $kdc_ipv6);
1034
1035	if (defined($extra_provision_options)) {
1036		push (@{$ctx->{provision_options}}, @{$extra_provision_options});
1037	}
1038
1039	$ctx->{share} = "$ctx->{prefix_abs}/share";
1040	push(@{$ctx->{directories}}, "$ctx->{share}");
1041	push(@{$ctx->{directories}}, "$ctx->{share}/test1");
1042	push(@{$ctx->{directories}}, "$ctx->{share}/test2");
1043
1044	# precreate directories for printer drivers
1045	push(@{$ctx->{directories}}, "$ctx->{share}/W32X86");
1046	push(@{$ctx->{directories}}, "$ctx->{share}/x64");
1047	push(@{$ctx->{directories}}, "$ctx->{share}/WIN40");
1048
1049	my $msdfs = "no";
1050	$msdfs = "yes" if ($server_role eq "domain controller");
1051	$ctx->{smb_conf_extra_options} = "
1052
1053	max xmit = 32K
1054	server max protocol = SMB2
1055	host msdfs = $msdfs
1056	lanman auth = yes
1057
1058	# fruit:copyfile is a global option
1059	fruit:copyfile = yes
1060
1061	$extra_smbconf_options
1062
1063[tmp]
1064	path = $ctx->{share}
1065	read only = no
1066	posix:sharedelay = 100000
1067	posix:oplocktimeout = 3
1068	posix:writetimeupdatedelay = 500000
1069
1070[xcopy_share]
1071	path = $ctx->{share}
1072	read only = no
1073	posix:sharedelay = 100000
1074	posix:oplocktimeout = 3
1075	posix:writetimeupdatedelay = 500000
1076	create mask = 777
1077	force create mode = 777
1078
1079[posix_share]
1080	path = $ctx->{share}
1081	read only = no
1082	create mask = 0777
1083	force create mode = 0
1084	directory mask = 0777
1085	force directory mode = 0
1086
1087[test1]
1088	path = $ctx->{share}/test1
1089	read only = no
1090	posix:sharedelay = 100000
1091	posix:oplocktimeout = 3
1092	posix:writetimeupdatedelay = 500000
1093
1094[test2]
1095	path = $ctx->{share}/test2
1096	read only = no
1097	posix:sharedelay = 100000
1098	posix:oplocktimeout = 3
1099	posix:writetimeupdatedelay = 500000
1100
1101[cifs]
1102	path = $ctx->{share}/_ignore_cifs_
1103	read only = no
1104	ntvfs handler = cifs
1105	cifs:server = $ctx->{netbiosname}
1106	cifs:share = tmp
1107	cifs:use-s4u2proxy = yes
1108	# There is no username specified here, instead the client is expected
1109	# to log in with kerberos, and the serverwill use delegated credentials.
1110	# Or the server tries s4u2self/s4u2proxy to impersonate the client
1111
1112[simple]
1113	path = $ctx->{share}
1114	read only = no
1115	ntvfs handler = simple
1116
1117[sysvol]
1118	path = $ctx->{statedir}/sysvol
1119	read only = no
1120
1121[netlogon]
1122	path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
1123	read only = no
1124
1125[cifsposix]
1126	copy = simple
1127	ntvfs handler = cifsposix
1128
1129[vfs_fruit]
1130	path = $ctx->{share}
1131	vfs objects = catia fruit streams_xattr acl_xattr
1132	ea support = yes
1133	fruit:resource = file
1134	fruit:metadata = netatalk
1135	fruit:locking = netatalk
1136	fruit:encoding = native
1137
1138[xattr]
1139	path = $ctx->{share}
1140        # This can be used for testing real fs xattr stuff
1141	vfs objects = streams_xattr acl_xattr
1142
1143$extra_smbconf_shares
1144";
1145
1146	my $ret = $self->provision_raw_step1($ctx);
1147	unless (defined $ret) {
1148		return undef;
1149	}
1150
1151	return $self->provision_raw_step2($ctx, $ret);
1152}
1153
1154# For multi-DC testenvs, we want $DC_SERVER to always be the PDC (i.e. the
1155# original DC) in the testenv. $SERVER is always the joined DC that we are
1156# actually running the test against
1157sub set_pdc_env_vars
1158{
1159	my ($self, $env, $dcvars) = @_;
1160
1161	$env->{DC_SERVER} = $dcvars->{DC_SERVER};
1162	$env->{DC_SERVER_IP} = $dcvars->{DC_SERVER_IP};
1163	$env->{DC_SERVER_IPV6} = $dcvars->{DC_SERVER_IPV6};
1164	$env->{DC_SERVERCONFFILE} = $dcvars->{SERVERCONFFILE};
1165	$env->{DC_NETBIOSNAME} = $dcvars->{DC_NETBIOSNAME};
1166	$env->{DC_USERNAME} = $dcvars->{DC_USERNAME};
1167	$env->{DC_PASSWORD} = $dcvars->{DC_PASSWORD};
1168}
1169
1170sub provision_s4member($$$$$)
1171{
1172	my ($self, $prefix, $dcvars, $hostname, $more_conf) = @_;
1173	print "PROVISIONING MEMBER...\n";
1174	my $extra_smb_conf = "
1175        passdb backend = samba_dsdb
1176winbindd:use external pipes = true
1177
1178# the source4 smb server doesn't allow signing by default
1179server signing = enabled
1180raw NTLMv2 auth = yes
1181
1182rpc_server:default = external
1183rpc_server:svcctl = embedded
1184rpc_server:srvsvc = embedded
1185rpc_server:eventlog = embedded
1186rpc_server:ntsvcs = embedded
1187rpc_server:winreg = embedded
1188rpc_server:spoolss = embedded
1189rpc_daemon:spoolssd = embedded
1190rpc_server:tcpip = no
1191";
1192	if ($more_conf) {
1193		$extra_smb_conf = $extra_smb_conf . $more_conf . "\n";
1194	}
1195	my $extra_provision_options = ["--use-ntvfs"];
1196	my $ret = $self->provision($prefix,
1197				   "member server",
1198				   $hostname,
1199				   $dcvars->{DOMAIN},
1200				   $dcvars->{REALM},
1201				   "2008",
1202				   "locMEMpass3",
1203				   $dcvars->{SERVER_IP},
1204				   $dcvars->{SERVER_IPV6},
1205				   $extra_smb_conf, "",
1206				   $extra_provision_options);
1207	unless ($ret) {
1208		return undef;
1209	}
1210
1211	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
1212	my $cmd = $self->get_cmd_env_vars($ret);
1213	$cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} member";
1214	$cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
1215	$cmd .= " --machinepass=machine$ret->{PASSWORD}";
1216
1217	unless (system($cmd) == 0) {
1218		warn("Join failed\n$cmd");
1219		return undef;
1220	}
1221
1222	$ret->{DOMSID} = $dcvars->{DOMSID};
1223	$self->set_pdc_env_vars($ret, $dcvars);
1224
1225	return $ret;
1226}
1227
1228sub provision_rpc_proxy($$$)
1229{
1230	my ($self, $prefix, $dcvars) = @_;
1231	print "PROVISIONING RPC PROXY...\n";
1232
1233	my $extra_smbconf_options = "
1234        passdb backend = samba_dsdb
1235
1236	# rpc_proxy
1237	dcerpc_remote:binding = ncacn_ip_tcp:$dcvars->{SERVER}
1238	dcerpc endpoint servers = epmapper, remote
1239	dcerpc_remote:interfaces = rpcecho
1240	dcerpc_remote:allow_anonymous_fallback = yes
1241
1242[cifs_to_dc]
1243	path = /tmp/_ignore_cifs_to_dc_/_none_
1244	read only = no
1245	ntvfs handler = cifs
1246	cifs:server = $dcvars->{SERVER}
1247	cifs:share = cifs
1248	cifs:use-s4u2proxy = yes
1249	# There is no username specified here, instead the client is expected
1250	# to log in with kerberos, and the serverwill use delegated credentials.
1251	# Or the server tries s4u2self/s4u2proxy to impersonate the client
1252
1253";
1254
1255	my $extra_provision_options = ["--use-ntvfs"];
1256	my $ret = $self->provision($prefix,
1257				   "member server",
1258				   "localrpcproxy",
1259				   $dcvars->{DOMAIN},
1260				   $dcvars->{REALM},
1261				   "2008",
1262				   "locRPCproxypass4",
1263				   $dcvars->{SERVER_IP},
1264				   $dcvars->{SERVER_IPV6},
1265				   $extra_smbconf_options, "",
1266				   $extra_provision_options);
1267	unless ($ret) {
1268		return undef;
1269	}
1270
1271	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
1272
1273	# The joind runs in the context of the rpc_proxy/member for now
1274	my $cmd = $self->get_cmd_env_vars($ret);
1275	$cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} member";
1276	$cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
1277	$cmd .= " --machinepass=machine$ret->{PASSWORD}";
1278
1279	unless (system($cmd) == 0) {
1280		warn("Join failed\n$cmd");
1281		return undef;
1282	}
1283
1284	# Setting up delegation runs in the context of the DC for now
1285	$cmd = "";
1286	$cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$dcvars->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
1287	$cmd .= "KRB5_CONFIG=\"$dcvars->{KRB5_CONFIG}\" ";
1288	$cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
1289	$cmd .= "RESOLV_CONF=\"$dcvars->{RESOLV_CONF}\" ";
1290	$cmd .= "$samba_tool delegation for-any-protocol '$ret->{NETBIOSNAME}\$' on";
1291        $cmd .= " $dcvars->{CONFIGURATION}";
1292        print $cmd;
1293
1294	unless (system($cmd) == 0) {
1295		warn("Delegation failed\n$cmd");
1296		return undef;
1297	}
1298
1299	# Setting up delegation runs in the context of the DC for now
1300	$cmd = "";
1301	$cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$dcvars->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
1302	$cmd .= "KRB5_CONFIG=\"$dcvars->{KRB5_CONFIG}\" ";
1303	$cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
1304	$cmd .= "RESOLV_CONF=\"$dcvars->{RESOLV_CONF}\" ";
1305	$cmd .= "$samba_tool delegation add-service '$ret->{NETBIOSNAME}\$' cifs/$dcvars->{SERVER}";
1306        $cmd .= " $dcvars->{CONFIGURATION}";
1307
1308	unless (system($cmd) == 0) {
1309		warn("Delegation failed\n$cmd");
1310		return undef;
1311	}
1312
1313	$ret->{DOMSID} = $dcvars->{DOMSID};
1314	$self->set_pdc_env_vars($ret, $dcvars);
1315
1316	return $ret;
1317}
1318
1319sub provision_promoted_dc($$$)
1320{
1321	my ($self, $prefix, $dcvars) = @_;
1322	print "PROVISIONING PROMOTED DC...\n";
1323
1324	# We do this so that we don't run the provision.  That's the job of 'samba-tool domain dcpromo'.
1325	my $ctx = $self->provision_raw_prepare($prefix, "domain controller",
1326					       "promotedvdc",
1327					       $dcvars->{DOMAIN},
1328					       $dcvars->{REALM},
1329					       $dcvars->{SAMSID},
1330					       "2008",
1331					       $dcvars->{PASSWORD},
1332					       $dcvars->{SERVER_IP},
1333					       $dcvars->{SERVER_IPV6});
1334
1335	$ctx->{smb_conf_extra_options} = "
1336	max xmit = 32K
1337	server max protocol = SMB2
1338
1339        ntlm auth = ntlmv2-only
1340
1341[sysvol]
1342	path = $ctx->{statedir}/sysvol
1343	read only = yes
1344
1345[netlogon]
1346	path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
1347	read only = no
1348
1349";
1350
1351	my $ret = $self->provision_raw_step1($ctx);
1352	unless ($ret) {
1353		return undef;
1354	}
1355
1356	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
1357	my $cmd = $self->get_cmd_env_vars($ret);
1358	$cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} MEMBER --realm=$dcvars->{REALM}";
1359	$cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
1360	$cmd .= " --machinepass=machine$ret->{PASSWORD}";
1361
1362	unless (system($cmd) == 0) {
1363		warn("Join failed\n$cmd");
1364		return undef;
1365	}
1366
1367	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
1368	my $cmd = $self->get_cmd_env_vars($ret);
1369	$cmd .= "$samba_tool domain dcpromo $ret->{CONFIGURATION} $dcvars->{REALM} DC --realm=$dcvars->{REALM}";
1370	$cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
1371	$cmd .= " --machinepass=machine$ret->{PASSWORD} --dns-backend=BIND9_DLZ";
1372
1373	unless (system($cmd) == 0) {
1374		warn("Join failed\n$cmd");
1375		return undef;
1376	}
1377
1378	$self->set_pdc_env_vars($ret, $dcvars);
1379
1380	return $ret;
1381}
1382
1383sub provision_vampire_dc($$$)
1384{
1385	my ($self, $prefix, $dcvars, $fl) = @_;
1386	print "PROVISIONING VAMPIRE DC @ FL $fl...\n";
1387	my $name = "localvampiredc";
1388	my $extra_conf = "";
1389
1390	if ($fl == "2000") {
1391		$name = "vampire2000dc";
1392	} else {
1393		$extra_conf = "drs: immediate link sync = yes
1394                       drs: max link sync = 250";
1395	}
1396
1397	# We do this so that we don't run the provision.  That's the job of 'net vampire'.
1398	my $ctx = $self->provision_raw_prepare($prefix, "domain controller",
1399					       $name,
1400					       $dcvars->{DOMAIN},
1401					       $dcvars->{REALM},
1402					       $dcvars->{DOMSID},
1403					       $fl,
1404					       $dcvars->{PASSWORD},
1405					       $dcvars->{SERVER_IP},
1406					       $dcvars->{SERVER_IPV6});
1407
1408	$ctx->{smb_conf_extra_options} = "
1409	max xmit = 32K
1410	server max protocol = SMB2
1411
1412        ntlm auth = mschapv2-and-ntlmv2-only
1413	$extra_conf
1414
1415[sysvol]
1416	path = $ctx->{statedir}/sysvol
1417	read only = yes
1418
1419[netlogon]
1420	path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
1421	read only = no
1422
1423";
1424
1425	my $ret = $self->provision_raw_step1($ctx);
1426	unless ($ret) {
1427		return undef;
1428	}
1429
1430	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
1431	my $cmd = $self->get_cmd_env_vars($ret);
1432	$cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} DC --realm=$dcvars->{REALM}";
1433	$cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD} --domain-critical-only";
1434	$cmd .= " --machinepass=machine$ret->{PASSWORD}";
1435	$cmd .= " --backend-store=mdb";
1436
1437	unless (system($cmd) == 0) {
1438		warn("Join failed\n$cmd");
1439		return undef;
1440	}
1441
1442	$self->set_pdc_env_vars($ret, $dcvars);
1443	$ret->{DC_REALM} = $dcvars->{DC_REALM};
1444
1445	return $ret;
1446}
1447
1448sub provision_ad_dc_ntvfs($$$)
1449{
1450	my ($self, $prefix, $extra_provision_options) = @_;
1451
1452	# We keep the old 'winbind' name here in server services to
1453	# ensure upgrades which used that name still work with the now
1454	# alias.
1455
1456	print "PROVISIONING AD DC (NTVFS)...\n";
1457        my $extra_conf_options = "netbios aliases = localDC1-a
1458        server services = +winbind -winbindd
1459	ldap server require strong auth = allow_sasl_over_tls
1460	allow nt4 crypto = yes
1461	raw NTLMv2 auth = yes
1462	lsa over netlogon = yes
1463        rpc server port = 1027
1464        auth event notification = true
1465	dsdb event notification = true
1466	dsdb password event notification = true
1467	dsdb group change notification = true
1468	server schannel = auto
1469	";
1470	push (@{$extra_provision_options}, "--use-ntvfs");
1471	my $ret = $self->provision($prefix,
1472				   "domain controller",
1473				   "localdc",
1474				   "SAMBADOMAIN",
1475				   "samba.example.com",
1476				   "2008",
1477				   "locDCpass1",
1478				   undef,
1479				   undef,
1480				   $extra_conf_options,
1481				   "",
1482				   $extra_provision_options);
1483	unless ($ret) {
1484		return undef;
1485	}
1486
1487	unless($self->add_wins_config("$prefix/private")) {
1488		warn("Unable to add wins configuration");
1489		return undef;
1490	}
1491	$ret->{NETBIOSALIAS} = "localdc1-a";
1492	$ret->{DC_REALM} = $ret->{REALM};
1493
1494	return $ret;
1495}
1496
1497sub provision_fl2000dc($$)
1498{
1499	my ($self, $prefix) = @_;
1500
1501	print "PROVISIONING DC WITH FOREST LEVEL 2000...\n";
1502	my $extra_conf_options = "
1503	spnego:simulate_w2k=yes
1504	ntlmssp_server:force_old_spnego=yes
1505";
1506	my $extra_provision_options = ["--base-schema=2008_R2"];
1507	# This environment uses plain text secrets
1508	# i.e. secret attributes are not encrypted on disk.
1509	# This allows testing of the --plaintext-secrets option for
1510	# provision
1511	push (@{$extra_provision_options}, "--plaintext-secrets");
1512	my $ret = $self->provision($prefix,
1513				   "domain controller",
1514				   "dc5",
1515				   "SAMBA2000",
1516				   "samba2000.example.com",
1517				   "2000",
1518				   "locDCpass5",
1519				   undef,
1520				   undef,
1521				   $extra_conf_options,
1522				   "",
1523				   $extra_provision_options);
1524	unless ($ret) {
1525		return undef;
1526	}
1527
1528	unless($self->add_wins_config("$prefix/private")) {
1529		warn("Unable to add wins configuration");
1530		return undef;
1531	}
1532	$ret->{DC_REALM} = $ret->{REALM};
1533
1534	return $ret;
1535}
1536
1537sub provision_fl2003dc($$$)
1538{
1539	my ($self, $prefix, $dcvars) = @_;
1540	my $ip_addr1 = Samba::get_ipv4_addr("fakednsforwarder1");
1541	my $ip_addr2 = Samba::get_ipv4_addr("fakednsforwarder2");
1542
1543	print "PROVISIONING DC WITH FOREST LEVEL 2003...\n";
1544	my $extra_conf_options = "allow dns updates = nonsecure and secure
1545	dcesrv:header signing = no
1546	dcesrv:max auth states = 0
1547	dns forwarder = $ip_addr1 $ip_addr2";
1548	my $extra_provision_options = ["--base-schema=2008_R2"];
1549	my $ret = $self->provision($prefix,
1550				   "domain controller",
1551				   "dc6",
1552				   "SAMBA2003",
1553				   "samba2003.example.com",
1554				   "2003",
1555				   "locDCpass6",
1556				   undef,
1557				   undef,
1558				   $extra_conf_options,
1559				   "",
1560				   $extra_provision_options);
1561	unless (defined $ret) {
1562		return undef;
1563	}
1564
1565	$ret->{DNS_FORWARDER1} = $ip_addr1;
1566	$ret->{DNS_FORWARDER2} = $ip_addr2;
1567
1568	my @samba_tool_options;
1569	push (@samba_tool_options, Samba::bindir_path($self, "samba-tool"));
1570	push (@samba_tool_options, "domain");
1571	push (@samba_tool_options, "passwordsettings");
1572	push (@samba_tool_options, "set");
1573	push (@samba_tool_options, "--configfile=$ret->{SERVERCONFFILE}");
1574	push (@samba_tool_options, "--min-pwd-age=0");
1575	push (@samba_tool_options, "--history-length=1");
1576
1577	my $samba_tool_cmd = join(" ", @samba_tool_options);
1578
1579	unless (system($samba_tool_cmd) == 0) {
1580		warn("Unable to set min password age to 0: \n$samba_tool_cmd\n");
1581		return undef;
1582	}
1583
1584	unless($self->add_wins_config("$prefix/private")) {
1585		warn("Unable to add wins configuration");
1586		return undef;
1587	}
1588
1589	return $ret;
1590}
1591
1592sub provision_fl2008r2dc($$$)
1593{
1594	my ($self, $prefix, $dcvars) = @_;
1595
1596	print "PROVISIONING DC WITH FOREST LEVEL 2008r2...\n";
1597        my $extra_conf_options = "
1598	ldap server require strong auth = no
1599        # delay by 10 seconds, 10^7 usecs
1600	ldap_server:delay_expire_disconnect = 10000
1601";
1602	my $extra_provision_options = ["--base-schema=2008_R2"];
1603	my $ret = $self->provision($prefix,
1604				   "domain controller",
1605				   "dc7",
1606				   "SAMBA2008R2",
1607				   "samba2008R2.example.com",
1608				   "2008_R2",
1609				   "locDCpass7",
1610				   undef,
1611				   undef,
1612				   $extra_conf_options,
1613				   "",
1614				   $extra_provision_options);
1615	unless (defined $ret) {
1616		return undef;
1617	}
1618
1619	unless ($self->add_wins_config("$prefix/private")) {
1620		warn("Unable to add wins configuration");
1621		return undef;
1622	}
1623	$ret->{DC_REALM} = $ret->{REALM};
1624
1625	return $ret;
1626}
1627
1628
1629sub provision_rodc($$$)
1630{
1631	my ($self, $prefix, $dcvars) = @_;
1632	print "PROVISIONING RODC...\n";
1633
1634	# We do this so that we don't run the provision.  That's the job of 'net join RODC'.
1635	my $ctx = $self->provision_raw_prepare($prefix, "domain controller",
1636					       "rodc",
1637					       $dcvars->{DOMAIN},
1638					       $dcvars->{REALM},
1639					       $dcvars->{DOMSID},
1640					       "2008",
1641					       $dcvars->{PASSWORD},
1642					       $dcvars->{SERVER_IP},
1643					       $dcvars->{SERVER_IPV6});
1644	unless ($ctx) {
1645		return undef;
1646	}
1647
1648	$ctx->{share} = "$ctx->{prefix_abs}/share";
1649	push(@{$ctx->{directories}}, "$ctx->{share}");
1650
1651	$ctx->{smb_conf_extra_options} = "
1652	max xmit = 32K
1653	server max protocol = SMB2
1654	password server = $dcvars->{DC_SERVER}
1655
1656[sysvol]
1657	path = $ctx->{statedir}/sysvol
1658	read only = yes
1659
1660[netlogon]
1661	path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
1662	read only = yes
1663
1664[tmp]
1665	path = $ctx->{share}
1666	read only = no
1667	posix:sharedelay = 10000
1668	posix:oplocktimeout = 3
1669	posix:writetimeupdatedelay = 50000
1670
1671";
1672
1673	my $ret = $self->provision_raw_step1($ctx);
1674	unless ($ret) {
1675		return undef;
1676	}
1677
1678	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
1679	my $cmd = $self->get_cmd_env_vars($ret);
1680	$cmd .= "$samba_tool domain join $ret->{CONFIGURATION} $dcvars->{REALM} RODC";
1681	$cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
1682	$cmd .= " --server=$dcvars->{DC_SERVER}";
1683
1684	unless (system($cmd) == 0) {
1685		warn("RODC join failed\n$cmd");
1686		return undef;
1687	}
1688
1689        # This ensures deterministic behaviour for tests that want to have the 'testallowed account'
1690        # user password verified on the RODC
1691	my $testallowed_account = "testallowed account";
1692	$cmd = "KRB5_CONFIG=\"$ret->{KRB5_CONFIG}\" ";
1693	$cmd .= "KRB5CCNAME=\"$ret->{KRB5_CCACHE}\" ";
1694	$cmd .= "RESOLV_CONF=\"$ret->{RESOLV_CONF}\" ";
1695	$cmd .= "$samba_tool rodc preload '$testallowed_account' $ret->{CONFIGURATION}";
1696	$cmd .= " --server=$dcvars->{DC_SERVER}";
1697
1698	unless (system($cmd) == 0) {
1699		warn("RODC join failed\n$cmd");
1700		return undef;
1701	}
1702
1703	# we overwrite the kdc after the RODC join
1704	# so that use the RODC as kdc and test
1705	# the proxy code
1706	$ctx->{kdc_ipv4} = $ret->{SERVER_IP};
1707	$ctx->{kdc_ipv6} = $ret->{SERVER_IPV6};
1708	Samba::mk_krb5_conf($ctx);
1709	Samba::mk_mitkdc_conf($ctx, abs_path(Samba::bindir_path($self, "shared")));
1710
1711	$self->set_pdc_env_vars($ret, $dcvars);
1712
1713	return $ret;
1714}
1715
1716sub read_config_h($)
1717{
1718	my ($name) = @_;
1719	my %ret = {};
1720	open(LF, "<$name") or die("unable to read $name: $!");
1721	while (<LF>) {
1722		chomp;
1723		next if not (/^#define /);
1724		if (/^#define (.*?)[ \t]+(.*?)$/) {
1725			$ret{$1} = $2;
1726			next;
1727		}
1728		if (/^#define (.*?)[ \t]+$/) {
1729			$ret{$1} = 1;;
1730			next;
1731		}
1732	}
1733	close(LF);
1734	return \%ret;
1735}
1736
1737sub provision_ad_dc($$$$$$)
1738{
1739	my ($self, $prefix, $hostname, $domain, $realm, $smbconf_args,
1740		$extra_provision_options) = @_;
1741
1742	my $prefix_abs = abs_path($prefix);
1743
1744	my $bindir_abs = abs_path($self->{bindir});
1745	my $lockdir="$prefix_abs/lockdir";
1746        my $conffile="$prefix_abs/etc/smb.conf";
1747
1748	my $require_mutexes = "dbwrap_tdb_require_mutexes:* = yes";
1749	$require_mutexes = "" if ($ENV{SELFTEST_DONT_REQUIRE_TDB_MUTEX_SUPPORT} eq "1");
1750
1751	my $config_h = {};
1752
1753	if (defined($ENV{CONFIG_H})) {
1754		$config_h = read_config_h($ENV{CONFIG_H});
1755	}
1756
1757	my $password_hash_gpg_key_ids = "password hash gpg key ids = 4952E40301FAB41A";
1758	$password_hash_gpg_key_ids = "" unless defined($config_h->{HAVE_GPGME});
1759
1760	my $extra_smbconf_options = "
1761        xattr_tdb:file = $prefix_abs/statedir/xattr.tdb
1762
1763	dbwrap_tdb_mutexes:* = yes
1764	${require_mutexes}
1765
1766	${password_hash_gpg_key_ids}
1767
1768	kernel oplocks = no
1769	kernel change notify = no
1770	smb2 leases = no
1771
1772	logging = file
1773	printing = bsd
1774	printcap name = /dev/null
1775
1776	max protocol = SMB3
1777	read only = no
1778
1779	smbd:sharedelay = 100000
1780	smbd:writetimeupdatedelay = 500000
1781	create mask = 755
1782	dos filemode = yes
1783	check parent directory delete on close = yes
1784
1785        dcerpc endpoint servers = -winreg -srvsvc
1786
1787	printcap name = /dev/null
1788
1789	addprinter command = $ENV{SRCDIR_ABS}/source3/script/tests/printing/modprinter.pl -a -s $conffile --
1790	deleteprinter command = $ENV{SRCDIR_ABS}/source3/script/tests/printing/modprinter.pl -d -s $conffile --
1791
1792	printing = vlp
1793	print command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb print %p %s
1794	lpq command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb lpq %p
1795	lp rm command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb lprm %p %j
1796	lp pause command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb lppause %p %j
1797	lp resume command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb lpresume %p %j
1798	queue pause command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb queuepause %p
1799	queue resume command = $bindir_abs/vlp tdbfile=$lockdir/vlp.tdb queueresume %p
1800	lpq cache time = 0
1801	print notify backchannel = yes
1802
1803	server schannel = auto
1804        auth event notification = true
1805	dsdb event notification = true
1806	dsdb password event notification = true
1807	dsdb group change notification = true
1808        $smbconf_args
1809";
1810
1811	my $extra_smbconf_shares = "
1812
1813[tmpenc]
1814	copy = tmp
1815	smb encrypt = required
1816
1817[tmpcase]
1818	copy = tmp
1819	case sensitive = yes
1820
1821[tmpguest]
1822	copy = tmp
1823        guest ok = yes
1824
1825[hideunread]
1826	copy = tmp
1827	hide unreadable = yes
1828
1829[durable]
1830	copy = tmp
1831	kernel share modes = no
1832	kernel oplocks = no
1833	posix locking = no
1834
1835[print\$]
1836	copy = tmp
1837
1838[print1]
1839	copy = tmp
1840	printable = yes
1841
1842[print2]
1843	copy = print1
1844[print3]
1845	copy = print1
1846[print4]
1847	copy = print1
1848	guest ok = yes
1849[lp]
1850	copy = print1
1851";
1852
1853	push (@{$extra_provision_options}, "--backend-store=mdb");
1854	print "PROVISIONING AD DC...\n";
1855	my $ret = $self->provision($prefix,
1856				   "domain controller",
1857				   $hostname,
1858				   $domain,
1859				   $realm,
1860				   "2008",
1861				   "locDCpass1",
1862				   undef,
1863				   undef,
1864				   $extra_smbconf_options,
1865				   $extra_smbconf_shares,
1866				   $extra_provision_options);
1867	unless (defined $ret) {
1868		return undef;
1869	}
1870
1871	unless($self->add_wins_config("$prefix/private")) {
1872		warn("Unable to add wins configuration");
1873		return undef;
1874	}
1875
1876	return $ret;
1877}
1878
1879sub provision_chgdcpass($$)
1880{
1881	my ($self, $prefix) = @_;
1882
1883	print "PROVISIONING CHGDCPASS...\n";
1884	# This environment disallows the use of this password
1885	# (and also removes the default AD complexity checks)
1886	my $unacceptable_password = "Paßßword-widk3Dsle32jxdBdskldsk55klASKQ";
1887	my $extra_smb_conf = "
1888	check password script = $self->{srcdir}/selftest/checkpassword_arg1.sh ${unacceptable_password}
1889	allow dcerpc auth level connect:lsarpc = yes
1890	dcesrv:max auth states = 8
1891";
1892	my $extra_provision_options = ["--dns-backend=BIND9_DLZ"];
1893	my $ret = $self->provision($prefix,
1894				   "domain controller",
1895				   "chgdcpass",
1896				   "CHDCDOMAIN",
1897				   "chgdcpassword.samba.example.com",
1898				   "2008",
1899				   "chgDCpass1",
1900				   undef,
1901				   undef,
1902				   $extra_smb_conf,
1903				   "",
1904				   $extra_provision_options);
1905	unless (defined $ret) {
1906		return undef;
1907	}
1908
1909	unless($self->add_wins_config("$prefix/private")) {
1910		warn("Unable to add wins configuration");
1911		return undef;
1912	}
1913
1914	# Remove secrets.tdb from this environment to test that we
1915	# still start up on systems without the new matching
1916	# secrets.tdb records.
1917	unless (unlink("$ret->{PRIVATEDIR}/secrets.tdb") || unlink("$ret->{PRIVATEDIR}/secrets.ntdb")) {
1918		warn("Unable to remove $ret->{PRIVATEDIR}/secrets.tdb added during provision");
1919		return undef;
1920	}
1921
1922	$ret->{UNACCEPTABLE_PASSWORD} = $unacceptable_password;
1923
1924	return $ret;
1925}
1926
1927sub teardown_env_terminate($$)
1928{
1929	my ($self, $envvars) = @_;
1930	my $pid;
1931
1932	# This should cause samba to terminate gracefully
1933	my $smbcontrol = Samba::bindir_path($self, "smbcontrol");
1934	my $cmd = "";
1935	$cmd .= "$smbcontrol samba shutdown $envvars->{CONFIGURATION}";
1936	my $ret = system($cmd);
1937	if ($ret != 0) {
1938		warn "'$cmd' failed with '$ret'\n";
1939	}
1940
1941	# This should cause samba to terminate gracefully
1942	close($envvars->{STDIN_PIPE});
1943
1944	$pid = $envvars->{SAMBA_PID};
1945	my $count = 0;
1946	my $childpid;
1947
1948	# This should give it time to write out the gcov data
1949	until ($count > 15) {
1950	    if (Samba::cleanup_child($pid, "samba") != 0) {
1951		return;
1952	    }
1953	    sleep(1);
1954	    $count++;
1955	}
1956
1957	# After 15 Seconds, work out why this thing is still alive
1958	warn "server process $pid took more than $count seconds to exit, showing backtrace:\n";
1959	system("$self->{srcdir}/selftest/gdb_backtrace $pid");
1960
1961	until ($count > 30) {
1962	    if (Samba::cleanup_child($pid, "samba") != 0) {
1963		return;
1964	    }
1965	    sleep(1);
1966	    $count++;
1967	}
1968
1969	if (kill(0, $pid)) {
1970	    warn "server process $pid took more than $count seconds to exit, sending SIGTERM\n";
1971	    kill "TERM", $pid;
1972	}
1973
1974	until ($count > 40) {
1975	    if (Samba::cleanup_child($pid, "samba") != 0) {
1976		return;
1977	    }
1978	    sleep(1);
1979	    $count++;
1980	}
1981	# If it is still around, kill it
1982	if (kill(0, $pid)) {
1983	    warn "server process $pid took more than $count seconds to exit, killing\n with SIGKILL\n";
1984	    kill 9, $pid;
1985	}
1986	return;
1987}
1988
1989sub teardown_env($$)
1990{
1991	my ($self, $envvars) = @_;
1992	teardown_env_terminate($self, $envvars);
1993
1994	print $self->getlog_env($envvars);
1995
1996	return;
1997}
1998
1999sub getlog_env($$)
2000{
2001	my ($self, $envvars) = @_;
2002	my $title = "SAMBA LOG of: $envvars->{NETBIOSNAME} pid $envvars->{SAMBA_PID}\n";
2003	my $out = $title;
2004
2005	open(LOG, "<$envvars->{SAMBA_TEST_LOG}");
2006
2007	seek(LOG, $envvars->{SAMBA_TEST_LOG_POS}, SEEK_SET);
2008	while (<LOG>) {
2009		$out .= $_;
2010	}
2011	$envvars->{SAMBA_TEST_LOG_POS} = tell(LOG);
2012	close(LOG);
2013
2014	return "" if $out eq $title;
2015
2016	return $out;
2017}
2018
2019sub check_env($$)
2020{
2021	my ($self, $envvars) = @_;
2022	my $samba_pid = $envvars->{SAMBA_PID};
2023
2024	if (not defined($samba_pid)) {
2025	    return 0;
2026	} elsif ($samba_pid > 0) {
2027	    my $childpid = Samba::cleanup_child($samba_pid, "samba");
2028
2029	    if ($childpid == 0) {
2030		return 1;
2031	    }
2032	    return 0;
2033	} else {
2034	    return 1;
2035	}
2036}
2037
2038# Declare the environments Samba4 makes available.
2039# To be set up, they will be called as
2040#   samba4->setup_$envname($self, $path, $dep_1_vars, $dep_2_vars, ...)
2041# The interdependencies between the testenvs are declared below. Some testenvs
2042# are dependent on another testenv running first, e.g. vampire_dc is dependent
2043# on ad_dc_ntvfs because vampire_dc joins ad_dc_ntvfs's domain. All DCs are
2044# dependent on dns_hub, which handles resolving DNS queries for the realm.
2045%Samba4::ENV_DEPS = (
2046	# name               => [dep_1, dep_2, ...],
2047	dns_hub              => [],
2048	ad_dc_ntvfs          => ["dns_hub"],
2049	ad_dc                => ["dns_hub"],
2050	ad_dc_no_nss         => ["dns_hub"],
2051	ad_dc_no_ntlm        => ["dns_hub"],
2052
2053	fl2008r2dc           => ["ad_dc"],
2054	fl2003dc             => ["ad_dc"],
2055	fl2000dc             => ["dns_hub"],
2056
2057	vampire_2000_dc      => ["fl2000dc"],
2058	vampire_dc           => ["ad_dc_ntvfs"],
2059	promoted_dc          => ["ad_dc_ntvfs"],
2060
2061	rodc                 => ["ad_dc_ntvfs"],
2062	rpc_proxy            => ["ad_dc_ntvfs"],
2063	chgdcpass            => ["dns_hub"],
2064
2065	s4member_dflt_domain => ["ad_dc_ntvfs"],
2066	s4member             => ["ad_dc_ntvfs"],
2067
2068	# envs that test the server process model
2069	proclimitdc          => ["dns_hub"],
2070	preforkrestartdc     => ["dns_hub"],
2071
2072	# backup/restore testenvs
2073	backupfromdc         => ["dns_hub"],
2074	customdc             => ["dns_hub"],
2075	restoredc            => ["backupfromdc"],
2076	renamedc             => ["backupfromdc"],
2077	offlinebackupdc      => ["backupfromdc"],
2078	labdc                => ["backupfromdc"],
2079
2080	# aliases in order to split autbuild tasks
2081	fl2008dc             => ["ad_dc"],
2082	ad_dc_default        => ["ad_dc"],
2083	ad_dc_slowtests      => ["ad_dc"],
2084	ad_dc_backup         => ["ad_dc"],
2085
2086	schema_dc      => ["dns_hub"],
2087	schema_pair_dc => ["schema_dc"],
2088
2089	none                 => [],
2090);
2091
2092%Samba4::ENV_DEPS_POST = (
2093	schema_dc => ["schema_pair_dc"],
2094);
2095
2096sub return_alias_env
2097{
2098	my ($self, $path, $env) = @_;
2099
2100	# just an alias
2101	return $env;
2102}
2103
2104sub setup_fl2008dc
2105{
2106	my ($self, $path) = @_;
2107
2108	my $extra_args = ["--base-schema=2008_R2"];
2109	my $env = $self->provision_ad_dc_ntvfs($path, $extra_args);
2110	if (defined $env) {
2111	        if (not defined($self->check_or_start($env, "standard"))) {
2112		    warn("Failed to start fl2008dc");
2113		        return undef;
2114		}
2115	}
2116	return $env;
2117}
2118
2119sub setup_ad_dc_default
2120{
2121	my ($self, $path, $dep_env) = @_;
2122	return $self->return_alias_env($path, $dep_env)
2123}
2124
2125sub setup_ad_dc_slowtests
2126{
2127	my ($self, $path, $dep_env) = @_;
2128	return $self->return_alias_env($path, $dep_env)
2129}
2130
2131sub setup_ad_dc_backup
2132{
2133	my ($self, $path, $dep_env) = @_;
2134	return $self->return_alias_env($path, $dep_env)
2135}
2136
2137sub setup_s4member
2138{
2139	my ($self, $path, $dc_vars) = @_;
2140
2141	my $env = $self->provision_s4member($path, $dc_vars, "s4member");
2142
2143	if (defined $env) {
2144	        if (not defined($self->check_or_start($env, "standard"))) {
2145		        return undef;
2146		}
2147	}
2148
2149	return $env;
2150}
2151
2152sub setup_s4member_dflt_domain
2153{
2154	my ($self, $path, $dc_vars) = @_;
2155
2156	my $env = $self->provision_s4member($path, $dc_vars, "s4member_dflt",
2157					    "winbind use default domain = yes");
2158
2159	if (defined $env) {
2160	        if (not defined($self->check_or_start($env, "standard"))) {
2161		        return undef;
2162		}
2163	}
2164
2165	return $env;
2166}
2167
2168sub setup_rpc_proxy
2169{
2170	my ($self, $path, $dc_vars) = @_;
2171
2172	my $env = $self->provision_rpc_proxy($path, $dc_vars);
2173
2174	if (defined $env) {
2175	        if (not defined($self->check_or_start($env, "standard"))) {
2176		        return undef;
2177		}
2178	}
2179	return $env;
2180}
2181
2182sub setup_ad_dc_ntvfs
2183{
2184	my ($self, $path) = @_;
2185
2186	my $env = $self->provision_ad_dc_ntvfs($path, undef);
2187	if (defined $env) {
2188	        if (not defined($self->check_or_start($env, "standard"))) {
2189		    warn("Failed to start ad_dc_ntvfs");
2190		        return undef;
2191		}
2192	}
2193	return $env;
2194}
2195
2196sub setup_chgdcpass
2197{
2198	my ($self, $path) = @_;
2199
2200	my $env = $self->provision_chgdcpass($path);
2201	if (defined $env) {
2202	        if (not defined($self->check_or_start($env, "standard"))) {
2203		        return undef;
2204		}
2205	}
2206	return $env;
2207}
2208
2209sub setup_fl2000dc
2210{
2211	my ($self, $path) = @_;
2212
2213	my $env = $self->provision_fl2000dc($path);
2214	if (defined $env) {
2215	        if (not defined($self->check_or_start($env, "standard"))) {
2216		        return undef;
2217		}
2218	}
2219
2220	return $env;
2221}
2222
2223sub setup_fl2003dc
2224{
2225	my ($self, $path, $dc_vars) = @_;
2226
2227	my $env = $self->provision_fl2003dc($path);
2228
2229	if (defined $env) {
2230	        if (not defined($self->check_or_start($env, "standard"))) {
2231		        return undef;
2232		}
2233
2234		$env = $self->setup_trust($env, $dc_vars, "external", "--no-aes-keys");
2235	}
2236	return $env;
2237}
2238
2239sub setup_fl2008r2dc
2240{
2241	my ($self, $path, $dc_vars) = @_;
2242
2243	my $env = $self->provision_fl2008r2dc($path);
2244
2245	if (defined $env) {
2246	        if (not defined($self->check_or_start($env, "standard"))) {
2247		        return undef;
2248		}
2249
2250		my $upn_array = ["$env->{REALM}.upn"];
2251		my $spn_array = ["$env->{REALM}.spn"];
2252
2253		$self->setup_namespaces($env, $upn_array, $spn_array);
2254
2255		$env = $self->setup_trust($env, $dc_vars, "forest", "");
2256	}
2257
2258	return $env;
2259}
2260
2261sub setup_vampire_dc
2262{
2263	return setup_generic_vampire_dc(@_, "2008");
2264}
2265
2266sub setup_vampire_2000_dc
2267{
2268	return setup_generic_vampire_dc(@_, "2000");
2269}
2270
2271sub setup_generic_vampire_dc
2272{
2273	my ($self, $path, $dc_vars, $fl) = @_;
2274
2275	my $env = $self->provision_vampire_dc($path, $dc_vars, $fl);
2276
2277	if (defined $env) {
2278	        if (not defined($self->check_or_start($env, "single"))) {
2279		        return undef;
2280		}
2281
2282		# force replicated DC to update repsTo/repsFrom
2283		# for vampired partitions
2284		my $samba_tool =  Samba::bindir_path($self, "samba-tool");
2285
2286		# as 'vampired' dc may add data in its local replica
2287		# we need to synchronize data between DCs
2288		my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
2289		my $cmd = $self->get_cmd_env_vars($env);
2290		$cmd .= " $samba_tool drs replicate $env->{DC_SERVER} $env->{SERVER}";
2291		$cmd .= " $dc_vars->{CONFIGURATION}";
2292		$cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
2293		# replicate Configuration NC
2294		my $cmd_repl = "$cmd \"CN=Configuration,$base_dn\"";
2295		unless(system($cmd_repl) == 0) {
2296			warn("Failed to replicate\n$cmd_repl");
2297			return undef;
2298		}
2299		# replicate Default NC
2300		$cmd_repl = "$cmd \"$base_dn\"";
2301		unless(system($cmd_repl) == 0) {
2302			warn("Failed to replicate\n$cmd_repl");
2303			return undef;
2304		}
2305
2306		# Pull in a full set of changes from the main DC
2307		my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
2308		$cmd = $self->get_cmd_env_vars($env);
2309		$cmd .= " $samba_tool drs replicate $env->{SERVER} $env->{DC_SERVER}";
2310		$cmd .= " $dc_vars->{CONFIGURATION}";
2311		$cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
2312		# replicate Configuration NC
2313		my $cmd_repl = "$cmd \"CN=Configuration,$base_dn\"";
2314		unless(system($cmd_repl) == 0) {
2315			warn("Failed to replicate\n$cmd_repl");
2316			return undef;
2317		}
2318		# replicate Default NC
2319		$cmd_repl = "$cmd \"$base_dn\"";
2320		unless(system($cmd_repl) == 0) {
2321			warn("Failed to replicate\n$cmd_repl");
2322			return undef;
2323		}
2324	}
2325
2326	return $env;
2327}
2328
2329sub setup_promoted_dc
2330{
2331	my ($self, $path, $dc_vars) = @_;
2332
2333	my $env = $self->provision_promoted_dc($path, $dc_vars);
2334
2335	if (defined $env) {
2336	        if (not defined($self->check_or_start($env, "single"))) {
2337		        return undef;
2338		}
2339
2340		# force source and replicated DC to update repsTo/repsFrom
2341		# for vampired partitions
2342		my $samba_tool =  Samba::bindir_path($self, "samba-tool");
2343		my $cmd = "NSS_WRAPPER_HOSTS='$env->{NSS_WRAPPER_HOSTS}' ";
2344		# as 'vampired' dc may add data in its local replica
2345		# we need to synchronize data between DCs
2346		my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
2347		$cmd = "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\"";
2348		$cmd .= " KRB5_CONFIG=\"$env->{KRB5_CONFIG}\"";
2349		$cmd .= "KRB5CCNAME=\"$env->{KRB5_CCACHE}\" ";
2350		$cmd .= "RESOLV_CONF=\"$env->{RESOLV_CONF}\" ";
2351		$cmd .= " $samba_tool drs replicate $env->{DC_SERVER} $env->{SERVER}";
2352		$cmd .= " $dc_vars->{CONFIGURATION}";
2353		$cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
2354		# replicate Configuration NC
2355		my $cmd_repl = "$cmd \"CN=Configuration,$base_dn\"";
2356		unless(system($cmd_repl) == 0) {
2357			warn("Failed to replicate\n$cmd_repl");
2358			return undef;
2359		}
2360		# replicate Default NC
2361		$cmd_repl = "$cmd \"$base_dn\"";
2362		unless(system($cmd_repl) == 0) {
2363			warn("Failed to replicate\n$cmd_repl");
2364			return undef;
2365		}
2366	}
2367
2368	return $env;
2369}
2370
2371sub setup_rodc
2372{
2373	my ($self, $path, $dc_vars) = @_;
2374
2375	my $env = $self->provision_rodc($path, $dc_vars);
2376
2377	unless ($env) {
2378		return undef;
2379	}
2380
2381	if (not defined($self->check_or_start($env, "standard"))) {
2382	    return undef;
2383	}
2384
2385	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
2386	my $cmd = "";
2387
2388	my $base_dn = "DC=".join(",DC=", split(/\./, $dc_vars->{REALM}));
2389	$cmd .= "NSS_WRAPPER_HOSTS='$env->{NSS_WRAPPER_HOSTS}' ";
2390	$cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\"";
2391	$cmd .= " KRB5_CONFIG=\"$env->{KRB5_CONFIG}\"";
2392	$cmd .= "KRB5CCNAME=\"$env->{KRB5_CCACHE}\" ";
2393	$cmd .= "RESOLV_CONF=\"$env->{RESOLV_CONF}\" ";
2394	$cmd .= " $samba_tool drs replicate $env->{SERVER} $env->{DC_SERVER}";
2395	$cmd .= " $dc_vars->{CONFIGURATION}";
2396	$cmd .= " -U$dc_vars->{DC_USERNAME}\%$dc_vars->{DC_PASSWORD}";
2397	# replicate Configuration NC
2398	my $cmd_repl = "$cmd \"CN=Configuration,$base_dn\"";
2399	unless(system($cmd_repl) == 0) {
2400	    warn("Failed to replicate\n$cmd_repl");
2401	    return undef;
2402	}
2403	# replicate Default NC
2404	$cmd_repl = "$cmd \"$base_dn\"";
2405	unless(system($cmd_repl) == 0) {
2406	    warn("Failed to replicate\n$cmd_repl");
2407	    return undef;
2408	}
2409
2410	return $env;
2411}
2412
2413sub setup_ad_dc
2414{
2415	my ($self, $path) = @_;
2416
2417	# If we didn't build with ADS, pretend this env was never available
2418	if (not $self->{target3}->have_ads()) {
2419	       return "UNKNOWN";
2420	}
2421
2422	my $env = $self->provision_ad_dc($path, "addc", "ADDOMAIN",
2423					 "addom.samba.example.com", "", undef);
2424	unless ($env) {
2425		return undef;
2426	}
2427
2428	if (not defined($self->check_or_start($env, "prefork"))) {
2429	    return undef;
2430	}
2431
2432	my $upn_array = ["$env->{REALM}.upn"];
2433	my $spn_array = ["$env->{REALM}.spn"];
2434
2435	$self->setup_namespaces($env, $upn_array, $spn_array);
2436
2437	return $env;
2438}
2439
2440sub setup_ad_dc_no_nss
2441{
2442	my ($self, $path) = @_;
2443
2444	# If we didn't build with ADS, pretend this env was never available
2445	if (not $self->{target3}->have_ads()) {
2446	       return "UNKNOWN";
2447	}
2448
2449	my $env = $self->provision_ad_dc($path, "addc_no_nss", "ADNONSSDOMAIN",
2450					 "adnonssdom.samba.example.com", "", undef);
2451	unless ($env) {
2452		return undef;
2453	}
2454
2455	$env->{NSS_WRAPPER_MODULE_SO_PATH} = undef;
2456	$env->{NSS_WRAPPER_MODULE_FN_PREFIX} = undef;
2457
2458	if (not defined($self->check_or_start($env, "single"))) {
2459	    return undef;
2460	}
2461
2462	my $upn_array = ["$env->{REALM}.upn"];
2463	my $spn_array = ["$env->{REALM}.spn"];
2464
2465	$self->setup_namespaces($env, $upn_array, $spn_array);
2466
2467	return $env;
2468}
2469
2470sub setup_ad_dc_no_ntlm
2471{
2472	my ($self, $path) = @_;
2473
2474	# If we didn't build with ADS, pretend this env was never available
2475	if (not $self->{target3}->have_ads()) {
2476	       return "UNKNOWN";
2477	}
2478
2479	my $env = $self->provision_ad_dc($path, "addc_no_ntlm", "ADNONTLMDOMAIN",
2480					 "adnontlmdom.samba.example.com",
2481					 "ntlm auth = disabled", undef);
2482	unless ($env) {
2483		return undef;
2484	}
2485
2486	if (not defined($self->check_or_start($env, "prefork"))) {
2487	    return undef;
2488	}
2489
2490	my $upn_array = ["$env->{REALM}.upn"];
2491	my $spn_array = ["$env->{REALM}.spn"];
2492
2493	$self->setup_namespaces($env, $upn_array, $spn_array);
2494
2495	return $env;
2496}
2497
2498#
2499# AD DC test environment used solely to test pre-fork process restarts.
2500# As processes get killed off and restarted it should not be used for other
2501sub setup_preforkrestartdc
2502{
2503	my ($self, $path) = @_;
2504
2505	# If we didn't build with ADS, pretend this env was never available
2506	if (not $self->{target3}->have_ads()) {
2507	       return "UNKNOWN";
2508	}
2509
2510	# note DC name must be <= 15 chars so we use 'prockill' instead of
2511	# 'preforkrestart'
2512	my $env = $self->provision_ad_dc(
2513		$path,
2514		"prockilldc",
2515		"PROCKILLDOMAIN",
2516		"prockilldom.samba.example.com",
2517		"prefork backoff increment = 5\nprefork maximum backoff=10");
2518	unless ($env) {
2519		return undef;
2520	}
2521
2522	$env->{NSS_WRAPPER_MODULE_SO_PATH} = undef;
2523	$env->{NSS_WRAPPER_MODULE_FN_PREFIX} = undef;
2524
2525	if (not defined($self->check_or_start($env, "prefork"))) {
2526	    return undef;
2527	}
2528
2529	my $upn_array = ["$env->{REALM}.upn"];
2530	my $spn_array = ["$env->{REALM}.spn"];
2531
2532	$self->setup_namespaces($env, $upn_array, $spn_array);
2533
2534	return $env;
2535}
2536
2537#
2538# ad_dc test environment used solely to test standard process model connection
2539# process limits. As the limit is set artificially low it should not be used
2540# for other tests.
2541sub setup_proclimitdc
2542{
2543	my ($self, $path) = @_;
2544
2545	# If we didn't build with ADS, pretend this env was never available
2546	if (not $self->{target3}->have_ads()) {
2547	       return "UNKNOWN";
2548	}
2549
2550	my $env = $self->provision_ad_dc(
2551		$path,
2552		"proclimitdc",
2553		"PROCLIMITDOM",
2554		"proclimit.samba.example.com",
2555		"max smbd processes = 20");
2556	unless ($env) {
2557		return undef;
2558	}
2559
2560	$env->{NSS_WRAPPER_MODULE_SO_PATH} = undef;
2561	$env->{NSS_WRAPPER_MODULE_FN_PREFIX} = undef;
2562
2563	if (not defined($self->check_or_start($env, "standard"))) {
2564	    return undef;
2565	}
2566
2567	my $upn_array = ["$env->{REALM}.upn"];
2568	my $spn_array = ["$env->{REALM}.spn"];
2569
2570	$self->setup_namespaces($env, $upn_array, $spn_array);
2571
2572	return $env;
2573}
2574
2575# Used to test a live upgrade of the schema on a 2 DC network.
2576sub setup_schema_dc
2577{
2578	my ($self, $path) = @_;
2579
2580	# provision the PDC using an older base schema
2581	my $provision_args = ["--base-schema=2008_R2", "--backend-store=mdb"];
2582
2583	my $env = $self->provision_ad_dc($path, "liveupgrade1dc", "SCHEMADOMAIN",
2584					 "schema.samba.example.com",
2585					 "drs: max link sync = 2",
2586					 $provision_args);
2587	unless ($env) {
2588		return undef;
2589	}
2590
2591	if (not defined($self->check_or_start($env, "prefork"))) {
2592	    return undef;
2593	}
2594
2595	my $upn_array = ["$env->{REALM}.upn"];
2596	my $spn_array = ["$env->{REALM}.spn"];
2597
2598	$self->setup_namespaces($env, $upn_array, $spn_array);
2599
2600	return $env;
2601}
2602
2603# the second DC in the live schema upgrade pair
2604sub setup_schema_pair_dc
2605{
2606	# note: dcvars contains the env info for the dependent testenv ('schema_dc')
2607	my ($self, $prefix, $dcvars) = @_;
2608	print "Preparing SCHEMA UPGRADE PAIR DC...\n";
2609
2610	my ($env, $ctx) = $self->prepare_dc_testenv($prefix, "liveupgrade2dc",
2611						    $dcvars->{DOMAIN},
2612						    $dcvars->{REALM},
2613						    $dcvars->{PASSWORD},
2614						    "");
2615
2616	my $samba_tool =  Samba::bindir_path($self, "samba-tool");
2617	my $cmd_vars = "NSS_WRAPPER_HOSTS='$env->{NSS_WRAPPER_HOSTS}' ";
2618	$cmd_vars .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
2619	if (defined($env->{RESOLV_WRAPPER_CONF})) {
2620		$cmd_vars .= "RESOLV_WRAPPER_CONF=\"$env->{RESOLV_WRAPPER_CONF}\" ";
2621	} else {
2622		$cmd_vars .= "RESOLV_WRAPPER_HOSTS=\"$env->{RESOLV_WRAPPER_HOSTS}\" ";
2623	}
2624	$cmd_vars .= "KRB5_CONFIG=\"$env->{KRB5_CONFIG}\" ";
2625	$cmd_vars .= "KRB5CCNAME=\"$env->{KRB5_CCACHE}\" ";
2626	$cmd_vars .= "RESOLV_CONF=\"$env->{RESOLV_CONF}\" ";
2627
2628	my $join_cmd = $cmd_vars;
2629	$join_cmd .= "$samba_tool domain join $env->{CONFIGURATION} $dcvars->{REALM} DC --realm=$dcvars->{REALM}";
2630	$join_cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD} ";
2631	$join_cmd .= " --backend-store=mdb";
2632
2633	my $upgrade_cmd = $cmd_vars;
2634	$upgrade_cmd .= "$samba_tool domain schemaupgrade $dcvars->{CONFIGURATION}";
2635	$upgrade_cmd .= " -U$dcvars->{USERNAME}\%$dcvars->{PASSWORD}";
2636
2637	my $repl_cmd = $cmd_vars;
2638	$repl_cmd .= "$samba_tool drs replicate $env->{SERVER} $dcvars->{SERVER}";
2639        $repl_cmd .= " CN=Schema,CN=Configuration,DC=schema,DC=samba,DC=example,DC=com";
2640	$repl_cmd .= " -U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
2641
2642	unless (system($join_cmd) == 0) {
2643		warn("Join failed\n$join_cmd");
2644		return undef;
2645	}
2646
2647	$env->{DC_SERVER} = $dcvars->{SERVER};
2648	$env->{DC_SERVER_IP} = $dcvars->{SERVER_IP};
2649	$env->{DC_SERVER_IPV6} = $dcvars->{SERVER_IPV6};
2650	$env->{DC_NETBIOSNAME} = $dcvars->{NETBIOSNAME};
2651
2652	# start samba for the new DC
2653	if (not defined($self->check_or_start($env, "standard"))) {
2654	    return undef;
2655	}
2656
2657	unless (system($upgrade_cmd) == 0) {
2658		warn("Schema upgrade failed\n$upgrade_cmd");
2659		return undef;
2660	}
2661
2662	unless (system($repl_cmd) == 0) {
2663		warn("Post-update schema replication failed\n$repl_cmd");
2664		return undef;
2665	}
2666
2667	return $env;
2668}
2669
2670# Sets up a DC that's solely used to do a domain backup from. We then use the
2671# backupfrom-DC to create the restore-DC - this proves that the backup/restore
2672# process will create a Samba DC that will actually start up.
2673# We don't use the backup-DC for anything else because its domain will conflict
2674# with the restore DC.
2675sub setup_backupfromdc
2676{
2677	my ($self, $path) = @_;
2678
2679	# If we didn't build with ADS, pretend this env was never available
2680	if (not $self->{target3}->have_ads()) {
2681	       return "UNKNOWN";
2682	}
2683
2684	my $provision_args = ["--site=Backup-Site"];
2685
2686	my $env = $self->provision_ad_dc($path, "backupfromdc", "BACKUPDOMAIN",
2687					 "backupdom.samba.example.com",
2688					 "samba kcc command = /bin/true",
2689					 $provision_args);
2690	unless ($env) {
2691		return undef;
2692	}
2693
2694	if (not defined($self->check_or_start($env))) {
2695	    return undef;
2696	}
2697
2698	my $upn_array = ["$env->{REALM}.upn"];
2699	my $spn_array = ["$env->{REALM}.spn"];
2700
2701	$self->setup_namespaces($env, $upn_array, $spn_array);
2702
2703	# Set up a dangling forward link to an expunged object
2704	#
2705	# We need this to ensure that the "samba-tool domain backup rename"
2706	# that is part of the creation of the labdc environment can
2707	# cope with this situation on the source DC.
2708
2709	if (not $self->write_ldb_file("$env->{PRIVATEDIR}/sam.ldb", "
2710dn: ou=linktest,dc=backupdom,dc=samba,dc=example,dc=com
2711objectclass: organizationalUnit
2712-
2713
2714dn: cn=linkto,ou=linktest,dc=backupdom,dc=samba,dc=example,dc=com
2715objectclass: msExchConfigurationContainer
2716-
2717
2718dn: cn=linkfrom,ou=linktest,dc=backupdom,dc=samba,dc=example,dc=com
2719objectclass: msExchConfigurationContainer
2720addressBookRoots: cn=linkto,ou=linktest,dc=backupdom,dc=samba,dc=example,dc=com
2721-
2722
2723")) {
2724	    return undef;
2725	}
2726	my $ldbdel = Samba::bindir_path($self, "ldbdel");
2727	my $cmd = "$ldbdel -H $env->{PRIVATEDIR}/sam.ldb cn=linkto,ou=linktest,dc=backupdom,dc=samba,dc=example,dc=com";
2728
2729	unless(system($cmd) == 0) {
2730		warn("Failed to delete link target: \n$cmd");
2731		return undef;
2732	}
2733
2734	# Expunge will ensure that linkto is totally wiped from the DB
2735	my $samba_tool = Samba::bindir_path($self, "samba-tool");
2736	$cmd = "$samba_tool  domain tombstones expunge --tombstone-lifetime=0 $env->{CONFIGURATION}";
2737
2738	unless(system($cmd) == 0) {
2739		warn("Failed to expunge link target: \n$cmd");
2740		return undef;
2741	}
2742	return $env;
2743}
2744
2745# returns the server/user-auth params needed to run an online backup cmd
2746sub get_backup_server_args
2747{
2748	# dcvars contains the env info for the backup DC testenv
2749	my ($self, $dcvars) = @_;
2750	my $server = $dcvars->{DC_SERVER_IP};
2751	my $server_args = "--server=$server ";
2752	$server_args .= "-U$dcvars->{DC_USERNAME}\%$dcvars->{DC_PASSWORD}";
2753	$server_args .= " $dcvars->{CONFIGURATION}";
2754
2755	return $server_args;
2756}
2757
2758# Creates a backup of a running testenv DC
2759sub create_backup
2760{
2761	# note: dcvars contains the env info for the backup DC testenv
2762	my ($self, $env, $dcvars, $backupdir, $backup_cmd) = @_;
2763
2764	# get all the env variables we pass in with the samba-tool command
2765	my $cmd_env = "NSS_WRAPPER_HOSTS='$env->{NSS_WRAPPER_HOSTS}' ";
2766	$cmd_env .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$env->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
2767	if (defined($env->{RESOLV_WRAPPER_CONF})) {
2768		$cmd_env .= "RESOLV_WRAPPER_CONF=\"$env->{RESOLV_WRAPPER_CONF}\" ";
2769	} else {
2770		$cmd_env .= "RESOLV_WRAPPER_HOSTS=\"$env->{RESOLV_WRAPPER_HOSTS}\" ";
2771	}
2772	# Note: use the backupfrom-DC's krb5.conf to do the backup
2773	$cmd_env .= " KRB5_CONFIG=\"$dcvars->{KRB5_CONFIG}\" ";
2774	$cmd_env .= "KRB5CCNAME=\"$env->{KRB5_CCACHE}\" ";
2775
2776	# use samba-tool to create a backup from the 'backupfromdc' DC
2777	my $cmd = "";
2778	my $samba_tool = Samba::bindir_path($self, "samba-tool");
2779
2780	$cmd .= "$cmd_env $samba_tool domain backup $backup_cmd";
2781	$cmd .= " --targetdir=$backupdir";
2782
2783	print "Executing: $cmd\n";
2784	unless(system($cmd) == 0) {
2785		warn("Failed to create backup using: \n$cmd");
2786		return undef;
2787	}
2788
2789	# get the name of the backup file created
2790	opendir(DIR, $backupdir);
2791	my @files = grep(/\.tar/, readdir(DIR));
2792	closedir(DIR);
2793
2794	if(scalar @files != 1) {
2795		warn("Backup file not found in directory $backupdir\n");
2796		return undef;
2797	}
2798	my $backup_file = "$backupdir/$files[0]";
2799	print "Using backup file $backup_file...\n";
2800
2801	return $backup_file;
2802}
2803
2804# Restores a backup-file to populate a testenv for a new DC
2805sub restore_backup_file
2806{
2807	my ($self, $backup_file, $restore_opts, $restoredir, $smbconf) = @_;
2808
2809	# pass the restore command the testenv's smb.conf that we've already
2810	# generated. But move it to a temp-dir first, so that the restore doesn't
2811	# overwrite it
2812	my $tmpdir = File::Temp->newdir();
2813	my $tmpconf = "$tmpdir/smb.conf";
2814	my $cmd = "cp $smbconf $tmpconf";
2815	unless(system($cmd) == 0) {
2816		warn("Failed to backup smb.conf using: \n$cmd");
2817		return -1;
2818	}
2819
2820	my $samba_tool = Samba::bindir_path($self, "samba-tool");
2821	$cmd = "$samba_tool domain backup restore --backup-file=$backup_file";
2822	$cmd .= " --targetdir=$restoredir $restore_opts --configfile=$tmpconf";
2823
2824	print "Executing: $cmd\n";
2825	unless(system($cmd) == 0) {
2826		warn("Failed to restore backup using: \n$cmd");
2827		return -1;
2828	}
2829
2830	print "Restore complete\n";
2831	return 0
2832}
2833
2834# sets up the initial directory and returns the new testenv's env info
2835# (without actually doing a 'domain join')
2836sub prepare_dc_testenv
2837{
2838	my ($self, $prefix, $dcname, $domain, $realm,
2839		$password, $conf_options) = @_;
2840
2841	my $ctx = $self->provision_raw_prepare($prefix, "domain controller",
2842					       $dcname,
2843					       $domain,
2844					       $realm,
2845					       undef,
2846					       "2008",
2847					       $password,
2848					       undef,
2849					       undef);
2850
2851	# the restore uses a slightly different state-dir location to other testenvs
2852	$ctx->{statedir} = "$ctx->{prefix_abs}/state";
2853	push(@{$ctx->{directories}}, "$ctx->{statedir}");
2854
2855	# add support for sysvol/netlogon/tmp shares
2856	$ctx->{share} = "$ctx->{prefix_abs}/share";
2857	push(@{$ctx->{directories}}, "$ctx->{share}");
2858	push(@{$ctx->{directories}}, "$ctx->{share}/test1");
2859
2860	$ctx->{smb_conf_extra_options} = "
2861	$conf_options
2862	max xmit = 32K
2863	server max protocol = SMB2
2864	samba kcc command = /bin/true
2865	xattr_tdb:file = $ctx->{statedir}/xattr.tdb
2866
2867[sysvol]
2868	path = $ctx->{statedir}/sysvol
2869	read only = no
2870
2871[netlogon]
2872	path = $ctx->{statedir}/sysvol/$ctx->{dnsname}/scripts
2873	read only = no
2874
2875[tmp]
2876	path = $ctx->{share}
2877	read only = no
2878	posix:sharedelay = 10000
2879	posix:oplocktimeout = 3
2880	posix:writetimeupdatedelay = 50000
2881
2882[test1]
2883	path = $ctx->{share}/test1
2884	read only = no
2885	posix:sharedelay = 100000
2886	posix:oplocktimeout = 3
2887	posix:writetimeupdatedelay = 500000
2888";
2889
2890	my $env = $self->provision_raw_step1($ctx);
2891
2892    return ($env, $ctx);
2893}
2894
2895
2896# Set up a DC testenv solely by using the samba-tool domain backup/restore
2897# commands. This proves that we can backup an online DC ('backupfromdc') and
2898# use the backup file to create a valid, working samba DC.
2899sub setup_restoredc
2900{
2901	# note: dcvars contains the env info for the dependent testenv ('backupfromdc')
2902	my ($self, $prefix, $dcvars) = @_;
2903	print "Preparing RESTORE DC...\n";
2904
2905	# we arbitrarily designate the restored DC as having SMBv1 disabled
2906	my $extra_conf = "
2907	server min protocol = SMB2
2908	client min protocol = SMB2
2909	prefork children = 1";
2910
2911	my ($env, $ctx) = $self->prepare_dc_testenv($prefix, "restoredc",
2912						    $dcvars->{DOMAIN},
2913						    $dcvars->{REALM},
2914						    $dcvars->{PASSWORD},
2915						    $extra_conf);
2916
2917	# create a backup of the 'backupfromdc'
2918	my $backupdir = File::Temp->newdir();
2919	my $server_args = $self->get_backup_server_args($dcvars);
2920	my $backup_args = "online $server_args";
2921	my $backup_file = $self->create_backup($env, $dcvars, $backupdir,
2922					       $backup_args);
2923	unless($backup_file) {
2924		return undef;
2925	}
2926
2927	# restore the backup file to populate the restore-DC testenv
2928	my $restore_dir = abs_path($prefix);
2929	my $ret = $self->restore_backup_file($backup_file,
2930					     "--newservername=$env->{SERVER}",
2931					     $restore_dir, $env->{SERVERCONFFILE});
2932	unless ($ret == 0) {
2933		return undef;
2934	}
2935
2936	# start samba for the restored DC
2937	if (not defined($self->check_or_start($env))) {
2938	    return undef;
2939	}
2940
2941	return $env;
2942}
2943
2944# Set up a DC testenv solely by using the 'samba-tool domain backup rename' and
2945# restore commands. This proves that we can backup and rename an online DC
2946# ('backupfromdc') and use the backup file to create a valid, working samba DC.
2947sub setup_renamedc
2948{
2949	# note: dcvars contains the env info for the dependent testenv ('backupfromdc')
2950	my ($self, $prefix, $dcvars) = @_;
2951	print "Preparing RENAME DC...\n";
2952	my $extra_conf = "prefork children = 1";
2953
2954	my $realm = "renamedom.samba.example.com";
2955	my ($env, $ctx) = $self->prepare_dc_testenv($prefix, "renamedc",
2956						    "RENAMEDOMAIN", $realm,
2957						    $dcvars->{PASSWORD}, $extra_conf);
2958
2959	# create a backup of the 'backupfromdc' which renames the domain
2960	my $backupdir = File::Temp->newdir();
2961	my $server_args = $self->get_backup_server_args($dcvars);
2962	my $backup_args = "rename $env->{DOMAIN} $env->{REALM} $server_args";
2963	$backup_args .= " --backend-store=tdb";
2964	my $backup_file = $self->create_backup($env, $dcvars, $backupdir,
2965					       $backup_args);
2966	unless($backup_file) {
2967		return undef;
2968	}
2969
2970	# restore the backup file to populate the rename-DC testenv
2971	my $restore_dir = abs_path($prefix);
2972	my $restore_opts =  "--newservername=$env->{SERVER} --host-ip=$env->{SERVER_IP}";
2973	my $ret = $self->restore_backup_file($backup_file, $restore_opts,
2974					     $restore_dir, $env->{SERVERCONFFILE});
2975	unless ($ret == 0) {
2976		return undef;
2977	}
2978
2979	# start samba for the restored DC
2980	if (not defined($self->check_or_start($env))) {
2981	    return undef;
2982	}
2983
2984	my $upn_array = ["$env->{REALM}.upn"];
2985	my $spn_array = ["$env->{REALM}.spn"];
2986
2987	$self->setup_namespaces($env, $upn_array, $spn_array);
2988
2989	return $env;
2990}
2991
2992# Set up a DC testenv solely by using the 'samba-tool domain backup offline' and
2993# restore commands. This proves that we do an offline backup of a local DC
2994# ('backupfromdc') and use the backup file to create a valid, working samba DC.
2995sub setup_offlinebackupdc
2996{
2997	# note: dcvars contains the env info for the dependent testenv ('backupfromdc')
2998	my ($self, $prefix, $dcvars) = @_;
2999	print "Preparing OFFLINE BACKUP DC...\n";
3000	my $extra_conf = "prefork children = 1";
3001
3002	my ($env, $ctx) = $self->prepare_dc_testenv($prefix, "offlinebackupdc",
3003						    $dcvars->{DOMAIN},
3004						    $dcvars->{REALM},
3005						    $dcvars->{PASSWORD}, $extra_conf);
3006
3007	# create an offline backup of the 'backupfromdc' target
3008	my $backupdir = File::Temp->newdir();
3009	my $cmd = "offline -s $dcvars->{SERVERCONFFILE}";
3010	my $backup_file = $self->create_backup($env, $dcvars,
3011					       $backupdir, $cmd);
3012
3013	unless($backup_file) {
3014		return undef;
3015	}
3016
3017	# restore the backup file to populate the rename-DC testenv
3018	my $restore_dir = abs_path($prefix);
3019	my $restore_opts =  "--newservername=$env->{SERVER} --host-ip=$env->{SERVER_IP}";
3020	my $ret = $self->restore_backup_file($backup_file, $restore_opts,
3021					     $restore_dir, $env->{SERVERCONFFILE});
3022	unless ($ret == 0) {
3023		return undef;
3024	}
3025
3026	# re-create the testenv's krb5.conf (the restore may have overwritten it)
3027	Samba::mk_krb5_conf($ctx);
3028
3029	# start samba for the restored DC
3030	if (not defined($self->check_or_start($env))) {
3031	    return undef;
3032	}
3033
3034	return $env;
3035}
3036
3037# Set up a DC testenv solely by using the samba-tool 'domain backup rename' and
3038# restore commands, using the --no-secrets option. This proves that we can
3039# create a realistic lab environment from an online DC ('backupfromdc').
3040sub setup_labdc
3041{
3042	# note: dcvars contains the env info for the dependent testenv ('backupfromdc')
3043	my ($self, $prefix, $dcvars) = @_;
3044	print "Preparing LAB-DOMAIN DC...\n";
3045	my $extra_conf = "prefork children = 1";
3046
3047	my ($env, $ctx) = $self->prepare_dc_testenv($prefix, "labdc",
3048						    "LABDOMAIN",
3049						    "labdom.samba.example.com",
3050						    $dcvars->{PASSWORD}, $extra_conf);
3051
3052	# create a backup of the 'backupfromdc' which renames the domain and uses
3053	# the --no-secrets option to scrub any sensitive info
3054	my $backupdir = File::Temp->newdir();
3055	my $server_args = $self->get_backup_server_args($dcvars);
3056	my $backup_args = "rename $env->{DOMAIN} $env->{REALM} $server_args";
3057	$backup_args .= " --no-secrets --backend-store=mdb";
3058	my $backup_file = $self->create_backup($env, $dcvars, $backupdir,
3059					       $backup_args);
3060	unless($backup_file) {
3061		return undef;
3062	}
3063
3064	# restore the backup file to populate the lab-DC testenv
3065	my $restore_dir = abs_path($prefix);
3066	my $restore_opts =  "--newservername=$env->{SERVER} --host-ip=$env->{SERVER_IP}";
3067	my $ret = $self->restore_backup_file($backup_file, $restore_opts,
3068					     $restore_dir, $env->{SERVERCONFFILE});
3069	unless ($ret == 0) {
3070		return undef;
3071	}
3072
3073	# because we don't include any secrets in the backup, we need to reset the
3074	# admin user's password back to what the testenv expects
3075	my $samba_tool = Samba::bindir_path($self, "samba-tool");
3076	my $cmd = "$samba_tool user setpassword $env->{USERNAME} ";
3077	$cmd .= "--newpassword=$env->{PASSWORD} -H $restore_dir/private/sam.ldb";
3078	$cmd .= " $env->{CONFIGURATION}";
3079
3080	unless(system($cmd) == 0) {
3081		warn("Failed to reset admin's password: \n$cmd");
3082		return undef;
3083	}
3084
3085	# start samba for the restored DC
3086	if (not defined($self->check_or_start($env))) {
3087	    return undef;
3088	}
3089
3090	my $upn_array = ["$env->{REALM}.upn"];
3091	my $spn_array = ["$env->{REALM}.spn"];
3092
3093	$self->setup_namespaces($env, $upn_array, $spn_array);
3094
3095	return $env;
3096}
3097
3098# Inspects a backup *.tar.bz2 file and determines the realm/domain it contains
3099sub get_backup_domain_realm
3100{
3101	my ($self, $backup_file) = @_;
3102
3103	print "Determining REALM/DOMAIN values in backup...\n";
3104
3105	# The backup will have the correct domain/realm values in the smb.conf.
3106	# So we can work out the env variables the testenv should use based on
3107	# that. Let's start by extracting the smb.conf
3108	my $tar = Archive::Tar->new($backup_file);
3109	my $tmpdir = File::Temp->newdir();
3110	my $smbconf = "$tmpdir/smb.conf";
3111
3112	# note that the filepaths within the tar-file differ slightly for online
3113	# and offline backups
3114	if ($tar->contains_file("etc/smb.conf")) {
3115		$tar->extract_file("etc/smb.conf", $smbconf);
3116	} elsif ($tar->contains_file("./etc/smb.conf")) {
3117		$tar->extract_file("./etc/smb.conf", $smbconf);
3118	} else {
3119		warn("Could not find smb.conf in $backup_file");
3120		return undef, undef;
3121	}
3122
3123	# make sure we don't try to create locks/sockets in the default install
3124	# location (i.e. /usr/local/samba/)
3125	my $options = "--option=\"private dir = $tmpdir\"";
3126	$options .=  " --option=\"lock dir = $tmpdir\"";
3127
3128	# now use testparm to read the values we're interested in
3129	my $testparm = Samba::bindir_path($self, "testparm");
3130	my $domain = `$testparm $smbconf -sl --parameter-name=WORKGROUP $options`;
3131	my $realm = `$testparm $smbconf -sl --parameter-name=REALM $options`;
3132	chomp $realm;
3133	chomp $domain;
3134	print "Backup-file REALM is $realm, DOMAIN is $domain\n";
3135
3136	return ($domain, $realm);
3137}
3138
3139# This spins up a custom testenv that can be based on any backup-file you want.
3140# This is just intended for manual testing (rather than automated test-cases)
3141sub setup_customdc
3142{
3143	my ($self, $prefix) = @_;
3144	print "Preparing CUSTOM RESTORE DC...\n";
3145	my $dc_name = "customdc";
3146	my $password = "locDCpass1";
3147	my $backup_file = $ENV{'BACKUP_FILE'};
3148
3149	# user must specify a backup file to restore via an ENV variable, i.e.
3150	# BACKUP_FILE=backup-blah.tar.bz2 SELFTEST_TESTENV=customdc make testenv
3151	if (not defined($backup_file)) {
3152		warn("Please specify BACKUP_FILE");
3153		return undef;
3154	}
3155
3156	# work out the correct domain/realm env values from the backup-file
3157	my ($domain, $realm) = $self->get_backup_domain_realm($backup_file);
3158	if ($domain eq '' or $realm eq '') {
3159		warn("Could not determine domain or realm");
3160		return undef;
3161	}
3162
3163	# create a placeholder directory and smb.conf, as well as the env vars.
3164	my ($env, $ctx) = $self->prepare_dc_testenv($prefix, $dc_name,
3165						    $domain, $realm, $password, "");
3166
3167	# restore the specified backup file to populate the testenv
3168	my $restore_dir = abs_path($prefix);
3169	my $ret = $self->restore_backup_file($backup_file,
3170					     "--newservername=$env->{SERVER}",
3171					     $restore_dir, $env->{SERVERCONFFILE});
3172	unless ($ret == 0) {
3173		return undef;
3174	}
3175
3176	# Change the admin password to the testenv default, just in case it's
3177	# different, or in case this was a --no-secrets backup
3178	my $samba_tool = Samba::bindir_path($self, "samba-tool");
3179	my $cmd = "$samba_tool user setpassword $env->{USERNAME} ";
3180	$cmd .= "--newpassword=$password -H $restore_dir/private/sam.ldb";
3181	$cmd .= " $env->{CONFIGURATION}";
3182
3183	unless(system($cmd) == 0) {
3184		warn("Failed to reset admin's password: \n$cmd");
3185		return undef;
3186	}
3187
3188	# re-create the testenv's krb5.conf (the restore may have overwritten it,
3189	# if the backup-file was an offline backup)
3190	Samba::mk_krb5_conf($ctx);
3191
3192	# start samba for the restored DC
3193	if (not defined($self->check_or_start($env))) {
3194	    return undef;
3195	}
3196
3197	# if this was a backup-rename, then we may need to setup namespaces
3198	my $upn_array = ["$env->{REALM}.upn"];
3199	my $spn_array = ["$env->{REALM}.spn"];
3200
3201	$self->setup_namespaces($env, $upn_array, $spn_array);
3202
3203	return $env;
3204}
3205
3206sub setup_none
3207{
3208	my ($self, $path) = @_;
3209
3210	my $ret = {
3211		KRB5_CONFIG => abs_path($path) . "/no_krb5.conf",
3212		SAMBA_PID => -1,
3213	}
3214}
3215
32161;
3217