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