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