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