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