r22478: Update the LDAP backend code to handle initialisation of multiple
[samba.git] / source4 / script / tests / 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
13 sub new($$$$) {
14         my ($classname, $bindir, $ldap, $setupdir) = @_;
15         my $self = { 
16                 vars => {}, 
17                 ldap => $ldap, 
18                 bindir => $bindir, 
19                 setupdir => $setupdir 
20         };
21         bless $self;
22         return $self;
23 }
24
25 sub openldap_start($$$) {
26         my ($slapd_conf, $uri, $logs) = @_;
27         my $oldpath = $ENV{PATH};
28         $ENV{PATH} = "/usr/local/sbin:/usr/sbin:/sbin:$ENV{PATH}";
29         system("slapd -d0 -f $slapd_conf -h $uri > $logs 2>&1 &");
30         $ENV{PATH} = $oldpath;
31 }
32
33 sub slapd_start($$)
34 {
35         my $count = 0;
36         my ($self, $env_vars) = @_;
37
38         my $uri = $env_vars->{LDAP_URI};
39
40         # running slapd in the background means it stays in the same process group, so it can be
41         # killed by timelimit
42         if ($self->{ldap} eq "fedora") {
43                 system("$ENV{FEDORA_DS_PREFIX}/sbin/ns-slapd -D $env_vars->{FEDORA_DS_DIR} -d0 -i $env_vars->{FEDORA_DS_PIDFILE}> $env_vars->{LDAPDIR}/logs 2>&1 &");
44         } elsif ($self->{ldap} eq "openldap") {
45                 openldap_start($env_vars->{SLAPD_CONF}, $uri, "$env_vars->{LDAPDIR}/logs");
46         }
47         while (system("$self->{bindir}/ldbsearch -H $uri -s base -b \"\" supportedLDAPVersion > /dev/null") != 0) {
48                 $count++;
49                 if ($count > 40) {
50                     $self->slapd_stop($env_vars);
51                     return 0;
52                 }
53                 sleep(1);
54         }
55         return 1;
56 }
57
58 sub slapd_stop($$)
59 {
60         my ($self, $envvars) = @_;
61         if ($self->{ldap} eq "fedora") {
62                 system("$envvars->{LDAPDIR}/slapd-samba4/stop-slapd");
63         } elsif ($self->{ldap} eq "openldap") {
64                 open(IN, "<$envvars->{OPENLDAP_PIDFILE}") or 
65                         die("unable to open slapd pid file: $envvars->{OPENLDAP_PIDFILE}");
66                 kill 9, <IN>;
67                 close(IN);
68         }
69 }
70
71 sub check_or_start($$$) 
72 {
73         my ($self, $env_vars, $max_time) = @_;
74         return 0 if ( -p $env_vars->{SMBD_TEST_FIFO});
75
76         unlink($env_vars->{SMBD_TEST_FIFO});
77         POSIX::mkfifo($env_vars->{SMBD_TEST_FIFO}, 0700);
78         unlink($env_vars->{SMBD_TEST_LOG});
79         
80         print "STARTING SMBD... ";
81         my $pid = fork();
82         if ($pid == 0) {
83                 open STDIN, $env_vars->{SMBD_TEST_FIFO};
84                 open STDOUT, ">$env_vars->{SMBD_TEST_LOG}";
85                 open STDERR, '>&STDOUT';
86                 
87                 SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
88
89                 my $valgrind = "";
90                 if (defined($ENV{SMBD_VALGRIND})) {
91                     $valgrind = $ENV{SMBD_VALGRIND};
92                 } 
93
94                 $ENV{KRB5_CONFIG} = $env_vars->{KRB5_CONFIG}; 
95
96                 # Start slapd before smbd, but with the fifo on stdin
97                 if (defined($self->{ldap})) {
98                     $self->slapd_start($env_vars) or 
99                         die("couldn't start slapd (2nd time)");
100                 }
101
102                 my $optarg = "";
103                 if (defined($max_time)) {
104                         $optarg = "--maximum-runtime=$max_time ";
105                 }
106                 my $ret = system("$valgrind $self->{bindir}/smbd $optarg $env_vars->{CONFIGURATION} -M single -i --leak-report-full");
107                 if ($? == -1) {
108                         print "Unable to start smbd: $ret: $!\n";
109                         exit 1;
110                 }
111                 unlink($env_vars->{SMBD_TEST_FIFO});
112                 my $exit = $? >> 8;
113                 if ( $ret == 0 ) {
114                         print "smbd exits with status $exit\n";
115                 } elsif ( $ret & 127 ) {
116                         print "smbd got signal ".($ret & 127)." and exits with $exit!\n";
117                 } else {
118                         $ret = $? >> 8;
119                         print "smbd failed with status $exit!\n";
120                 }
121                 exit $exit;
122         }
123         print "DONE\n";
124
125         open(DATA, ">$env_vars->{SMBD_TEST_FIFO}");
126
127         return $pid;
128 }
129
130 sub wait_for_start($$)
131 {
132         my ($self, $testenv_vars) = @_;
133         # give time for nbt server to register its names
134         print "delaying for nbt name registration\n";
135
136         # This will return quickly when things are up, but be slow if we 
137         # need to wait for (eg) SSL init 
138         system("bin/nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{SERVER}");
139         system("bin/nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER} $testenv_vars->{SERVER}");
140         system("bin/nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{SERVER}");
141         system("bin/nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER} $testenv_vars->{NETBIOSNAME}");
142         system("bin/nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
143         system("bin/nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER} $testenv_vars->{NETBIOSNAME}");
144         system("bin/nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
145         system("bin/nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER} $testenv_vars->{NETBIOSNAME}");
146         system("bin/nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
147         system("bin/nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER} $testenv_vars->{NETBIOSNAME}");
148
149         print $self->getlog_env($testenv_vars);
150 }
151
152 sub write_ldb_file($$$)
153 {
154         my ($self, $file, $ldif) = @_;
155
156         open(LDIF, "|$self->{bindir}/ldbadd -H $file >/dev/null");
157         print LDIF $ldif;
158         return close(LDIF);
159 }
160
161 sub add_wins_config($$)
162 {
163         my ($self, $privatedir) = @_;
164
165         return $self->write_ldb_file("$privatedir/wins_config.ldb", "
166 dn: name=TORTURE_6,CN=PARTNERS
167 objectClass: wreplPartner
168 name: TORTURE_6
169 address: 127.0.0.6
170 pullInterval: 0
171 pushChangeCount: 0
172 type: 0x3
173 ");
174 }
175
176 sub mk_fedora($$$$$$)
177 {
178         my ($self, $ldapdir, $basedn, $root, $password, $privatedir, $configuration) = @_;
179
180         mkdir($ldapdir, 0777);
181
182         my $fedora_ds_inf = "$ldapdir/fedorads.inf";
183         my $fedora_ds_initial_ldif = "$ldapdir/fedorads-initial.ldif";
184
185         #Make the subdirectory be as fedora DS would expect
186         my $fedora_ds_dir = "$ldapdir/slapd-samba4";
187
188         my $pidfile = "$fedora_ds_dir/logs/slapd-samba4.pid";
189
190         open(CONF, ">$fedora_ds_inf");
191         print CONF "
192 [General]
193 SuiteSpotUserID = $root
194 FullMachineName=   localhost
195 ServerRoot=   $ldapdir
196
197 [slapd]
198 ldapifilepath=$ldapdir/ldapi
199 Suffix= $basedn
200 RootDN= cn=Manager,$basedn
201 RootDNPwd= $password
202 ServerIdentifier= samba4
203 InstallLdifFile=$fedora_ds_initial_ldif
204
205 inst_dir= $fedora_ds_dir
206 config_dir= $fedora_ds_dir
207 schema_dir= $fedora_ds_dir/schema
208 lock_dir= $fedora_ds_dir/lock
209 log_dir= $fedora_ds_dir/logs
210 run_dir= $fedora_ds_dir/logs
211 db_dir= $fedora_ds_dir/db
212 bak_dir= $fedora_ds_dir/bak
213 tmp_dir= $fedora_ds_dir/tmp
214 ldif_dir= $fedora_ds_dir/ldif
215 cert_dir= $fedora_ds_dir
216
217 start_server= 0
218 ";
219         close(CONF);
220
221         open(LDIF, ">$fedora_ds_initial_ldif");
222         print LDIF "
223 # These entries need to be added to get the container for the 
224 # provision to be aimed at.
225
226 dn: cn=\"$basedn\",cn=mapping tree,cn=config
227 objectclass: top
228 objectclass: extensibleObject
229 objectclass: nsMappingTree
230 nsslapd-state: backend
231 nsslapd-backend: userData
232 cn: $basedn
233
234 dn: cn=userData,cn=ldbm database,cn=plugins,cn=config
235 objectclass: extensibleObject
236 objectclass: nsBackendInstance
237 nsslapd-suffix: $basedn
238 cn=userData
239
240 dn: cn=\"cn=Configuration,$basedn\",cn=mapping tree,cn=config
241 objectclass: top
242 objectclass: extensibleObject
243 objectclass: nsMappingTree
244 nsslapd-state: backend
245 nsslapd-backend: configData
246 nsslapd-parent-suffix: $basedn
247 cn: cn=Configuration,$basedn
248
249 dn: cn=configData,cn=ldbm database,cn=plugins,cn=config
250 objectclass: extensibleObject
251 objectclass: nsBackendInstance
252 nsslapd-suffix: cn=Configuration,$basedn
253 cn=configData
254
255 dn: cn=\"cn=Schema,cn=Configuration,$basedn\",cn=mapping tree,cn=config
256 objectclass: top
257 objectclass: extensibleObject
258 objectclass: nsMappingTree
259 nsslapd-state: backend
260 nsslapd-backend: schemaData
261 nsslapd-parent-suffix: cn=Configuration,$basedn
262 cn: cn=Schema,cn=Configuration,$basedn
263
264 dn: cn=schemaData,cn=ldbm database,cn=plugins,cn=config
265 objectclass: extensibleObject
266 objectclass: nsBackendInstance
267 nsslapd-suffix: cn=Schema,cn=Configuration,$basedn
268 cn=schemaData
269 ";
270         close(LDIF);
271
272 my $dir = getcwd();
273 chdir "$ENV{FEDORA_DS_PREFIX}/bin" || die;
274         if (system("perl $ENV{FEDORA_DS_PREFIX}/bin/ds_newinst.pl $fedora_ds_inf >&2") != 0) {
275             chdir $dir;
276             die("perl $ENV{FEDORA_DS_PREFIX}/bin/ds_newinst.pl $fedora_ds_inf FAILED: $?");
277         }
278         chdir $dir || die;
279         foreach(<$fedora_ds_dir/schema/*>) {
280                 unlink unless (/00core.*/);
281         }
282
283         open(LDIF, ">>$fedora_ds_dir/dse.ldif");
284         print LDIF "dn: cn=bitwise,cn=plugins,cn=config
285 objectClass: top
286 objectClass: nsSlapdPlugin
287 objectClass: extensibleObject
288 cn: bitwise
289 nsslapd-pluginPath: $ENV{FEDORA_DS_PREFIX}/lib/fedora-ds/plugins/libbitwise-plugin.so
290 nsslapd-pluginInitfunc: bitwise_init
291 nsslapd-pluginType: matchingRule
292 nsslapd-pluginEnabled: on
293 nsslapd-pluginId: bitwise
294 nsslapd-pluginVersion: 1.1.0a3
295 nsslapd-pluginVendor: Fedora Project
296 nsslapd-pluginDescription: Allow bitwise matching rules
297 ";
298         close(LDIF);
299
300         system("$self->{bindir}/ad2oLschema $configuration -H $privatedir/sam.ldb --option=convert:target=fedora-ds -I $self->{setupdir}/schema-map-fedora-ds-1.0 -O $fedora_ds_dir/schema/99_ad.ldif >&2") == 0 or die("schema conversion for Fedora DS failed");
301
302         return ($fedora_ds_dir, $pidfile);
303 }
304
305 sub write_openldap_dbconfig($) {
306     my ( $ldapdbdir ) = @_;
307         open(CONF, ">$ldapdbdir/DB_CONFIG");
308         print CONF "
309 #
310         # Set the database in memory cache size.
311         #
312         set_cachesize   0       524288        0
313         
314         
315         #
316         # Set database flags (this is a test environment, we don't need to fsync()).
317         #               
318         set_flags       DB_TXN_NOSYNC
319         
320         #
321         # Set log values.
322         #
323         set_lg_regionmax        104857
324         set_lg_max              1048576
325         set_lg_bsize            209715
326         set_lg_dir              $ldapdbdir/bdb-logs
327         
328         
329         #
330         # Set temporary file creation directory.
331         #                       
332         set_tmp_dir             $ldapdbdir/tmp
333         ";
334         close(CONF);
335
336
337 }
338
339 sub mk_openldap($$$$$$$$)
340 {
341         my ($self, $ldapdir, $basedn, $password, $privatedir, $dnsname, $configuration, $provision_options) = @_;
342
343         my $slapd_conf = "$ldapdir/slapd.conf";
344         my $pidfile = "$ldapdir/slapd.pid";
345         my $modconf = "$ldapdir/modules.conf";
346
347         mkdir($_, 0777) foreach ($ldapdir, "$ldapdir/db", "$ldapdir/db/user", "$ldapdir/db/config", "$ldapdir/db/schema", "$ldapdir/db/bdb-logs", 
348                 "$ldapdir/db/tmp");
349
350         open(CONF, ">$slapd_conf");
351         print CONF "
352 loglevel 0
353
354 include $ldapdir/ad.schema
355
356 pidfile         $pidfile
357 argsfile        $ldapdir/slapd.args
358 sasl-realm $dnsname
359 access to * by * write
360
361 allow update_anon
362
363 authz-regexp
364           uid=([^,]*),cn=$dnsname,cn=digest-md5,cn=auth
365           ldap:///$basedn??sub?(samAccountName=\$1)
366
367 authz-regexp
368           uid=([^,]*),cn=([^,]*),cn=digest-md5,cn=auth
369           ldap:///$basedn??sub?(samAccountName=\$1)
370
371 include $modconf
372
373 defaultsearchbase \"$basedn\"
374
375 backend         bdb
376 database        bdb
377 suffix          \"cn=Schema,cn=Configuration,$basedn\"
378 directory       $ldapdir/db/schema
379 index           objectClass eq
380 index           samAccountName eq
381 index name eq
382 index objectCategory eq
383 index lDAPDisplayName eq
384 index subClassOf eq
385
386 database        bdb
387 suffix          \"cn=Configuration,$basedn\"
388 directory       $ldapdir/db/config
389 index           objectClass eq
390 index           samAccountName eq
391 index name eq
392 index objectSid eq
393 index objectCategory eq
394 index nCName eq pres
395 index subClassOf eq
396 index dnsRoot eq
397 index nETBIOSName eq pres
398
399 database        bdb
400 suffix          \"$basedn\"
401 rootdn          \"cn=Manager,$basedn\"
402 rootpw          $password
403 directory       $ldapdir/db/user
404 index           objectClass eq
405 index           samAccountName eq
406 index name eq
407 index objectSid eq
408 index objectCategory eq
409 index member eq
410 index uidNumber eq
411 index gidNumber eq
412 index unixName eq
413 index privilege eq
414 index nCName eq pres
415 index lDAPDisplayName eq
416 index subClassOf eq
417 index dnsRoot eq
418 index nETBIOSName eq pres
419
420 #syncprov is stable in OpenLDAP 2.3, and available in 2.2.  
421 #We only need this for the contextCSN attribute anyway....
422 overlay syncprov
423 syncprov-checkpoint 100 10
424 syncprov-sessionlog 100
425 ";
426
427         close(CONF);
428         
429         write_openldap_dbconfig("$ldapdir/db/user");
430         write_openldap_dbconfig("$ldapdir/db/config");
431         write_openldap_dbconfig("$ldapdir/db/schema");
432
433         #This uses the provision we just did, to read out the schema
434         system("$self->{bindir}/ad2oLschema $configuration -H $privatedir/sam.ldb -I $self->{setupdir}/schema-map-openldap-2.3 -O $ldapdir/ad.schema >&2") == 0 or die("schema conversion for OpenLDAP failed");
435
436         #Now create an LDAP baseDN
437         system("$self->{bindir}/smbscript $self->{setupdir}/provision $provision_options --ldap-base >&2") == 0 or die("creating an OpenLDAP basedn failed");
438
439         my $oldpath = $ENV{PATH};
440         $ENV{PATH} = "/usr/local/sbin:/usr/sbin:/sbin:$ENV{PATH}";
441
442         unlink($modconf);
443         open(CONF, ">$modconf"); close(CONF);
444
445         if (system("slaptest -u -f $slapd_conf >&2") != 0) {
446                 open(CONF, ">$modconf"); 
447                 # enable slapd modules
448                 print CONF "
449 modulepath      /usr/lib/ldap
450 moduleload      back_bdb
451 moduleload      syncprov
452 ";
453                 close(CONF);
454         }
455
456         system("slaptest -u -f $slapd_conf") == 0 or die("slaptest still fails after adding modules");
457         system("slapadd -b $basedn -f $slapd_conf -l $privatedir/$dnsname.ldif >/dev/null") == 0 or die("slapadd failed");
458         system("slapadd -b cn=Configuration,$basedn -f $slapd_conf -l $privatedir/$dnsname-config.ldif >/dev/null") == 0 or die("slapadd failed");
459         system("slapadd -b cn=Schema,cn=Configuration,$basedn -f $slapd_conf -l $privatedir/$dnsname-schema.ldif >/dev/null") == 0 or die("slapadd failed");
460
461     system("slaptest -f $slapd_conf >/dev/null") == 0 or 
462                 die ("slaptest after database load failed");
463     
464         $ENV{PATH} = $oldpath;
465
466         return ($slapd_conf, $pidfile);
467 }
468
469 sub provision($$$$$)
470 {
471         my ($self, $prefix, $server_role, $domain, $netbiosname, $swiface) = @_;
472
473         my $smbd_loglevel = 1;
474         my $username = "administrator";
475         my $realm = "SAMBA.EXAMPLE.COM";
476         my $dnsname = "samba.example.com";
477         my $basedn = "dc=samba,dc=example,dc=com";
478         my $password = "penguin";
479         my $root = ($ENV{USER} or $ENV{LOGNAME} or `whoami`);
480         my $server = "localhost";
481         my $srcdir="$RealBin/../..";
482         -d $prefix or mkdir($prefix, 0777) or die("Unable to create $prefix");
483         my $prefix_abs = abs_path($prefix);
484         my $tmpdir = "$prefix_abs/tmp";
485         my $etcdir = "$prefix_abs/etc";
486         my $piddir = "$prefix_abs/pid";
487         my $conffile = "$etcdir/smb.conf";
488         my $krb5_config = "$etcdir/krb5.conf";
489         my $privatedir = "$prefix_abs/private";
490         my $ncalrpcdir = "$prefix_abs/ncalrpc";
491         my $lockdir = "$prefix_abs/lockdir";
492         my $winbindd_socket_dir = "$prefix_abs/winbind_socket";
493
494         my $configuration = "--configfile=$conffile";
495         my $ldapdir = "$prefix_abs/ldap";
496
497         my $tlsdir = "$privatedir/tls";
498
499         my $ifaceipv4 = "127.0.0.$swiface";
500         my $interfaces = "$ifaceipv4/8";
501
502         (system("rm -rf $prefix/*") == 0) or die("Unable to clean up");
503         mkdir($_, 0777) foreach ($privatedir, $etcdir, $piddir, $ncalrpcdir, $lockdir, 
504                 $tmpdir);
505
506         open(CONFFILE, ">$conffile");
507         print CONFFILE "
508 [global]
509         netbios name = $netbiosname
510         netbios aliases = $server
511         workgroup = $domain
512         realm = $realm
513         private dir = $privatedir
514         pid directory = $piddir
515         ncalrpc dir = $ncalrpcdir
516         lock dir = $lockdir
517         setup directory = $self->{setupdir}
518         js include = $srcdir/scripting/libjs
519         winbindd socket directory = $winbindd_socket_dir
520         name resolve order = bcast
521         interfaces = $interfaces
522         tls dh params file = $tlsdir/dhparms.pem
523         panic action = $srcdir/script/gdb_backtrace \%PID% \%PROG%
524         wins support = yes
525         server role = $server_role
526         max xmit = 32K
527         server max protocol = SMB2
528         notify:inotify = false
529         ldb:nosync = true
530         system:anonymous = true
531 #We don't want to pass our self-tests if the PAC code is wrong
532         gensec:require_pac = true
533         log level = $smbd_loglevel
534
535 [tmp]
536         path = $tmpdir
537         read only = no
538         ntvfs handler = posix
539         posix:sharedelay = 100000
540         posix:eadb = $lockdir/eadb.tdb
541
542 [cifs]
543         read only = no
544         ntvfs handler = cifs
545         cifs:server = $netbiosname
546         cifs:share = tmp
547 #There is no username specified here, instead the client is expected
548 #to log in with kerberos, and smbd will used delegated credentials.
549
550 [simple]
551         path = $tmpdir
552         read only = no
553         ntvfs handler = simple
554
555 [cifsposixtestshare]
556         copy = simple
557         ntvfs handler = cifsposix   
558 ";
559         close(CONFFILE);
560
561         die ("Unable to create key blobs") if
562                 (system("TLSDIR=$tlsdir $RealBin/mk-keyblobs.sh") != 0);
563
564         open(KRB5CONF, ">$krb5_config");
565         print KRB5CONF "
566 #Generated krb5.conf for $realm
567
568 [libdefaults]
569  default_realm = $realm
570  dns_lookup_realm = false
571  dns_lookup_kdc = false
572  ticket_lifetime = 24h
573  forwardable = yes
574
575 [realms]
576  $realm = {
577   kdc = 127.0.0.1:88
578   admin_server = 127.0.0.1:88
579   default_domain = $dnsname
580  }
581  $dnsname = {
582   kdc = 127.0.0.1:88
583   admin_server = 127.0.0.1:88
584   default_domain = $dnsname
585  }
586  $domain = {
587   kdc = 127.0.0.1:88
588   admin_server = 127.0.0.1:88
589   default_domain = $dnsname
590  }
591
592 [appdefaults]
593         pkinit_anchors = FILE:$tlsdir/ca.pem
594
595 [kdc]
596         enable-pkinit = true
597         pkinit_identity = FILE:$tlsdir/kdc.pem,$tlsdir/key.pem
598         pkinit_anchors = FILE:$tlsdir/ca.pem
599
600 [domain_realm]
601  .$dnsname = $realm
602 ";
603         close(KRB5CONF);
604
605 #Ensure the config file is valid before we start
606         if (system("$self->{bindir}/testparm $configuration -v --suppress-prompt >/dev/null 2>&1") != 0) {
607                 system("$self->{bindir}/testparm $configuration >&2");
608                 die("Failed to create a valid smb.conf configuration!");
609         }
610
611         (system("($self->{bindir}/testparm $configuration -v --suppress-prompt --parameter-name=\"netbios name\" --section-name=global 2> /dev/null | grep -i ^$netbiosname ) >/dev/null 2>&1") == 0) or die("Failed to create a valid smb.conf configuration!");
612
613         my @provision_options = ($configuration);
614         push (@provision_options, "--host-name=$netbiosname");
615         push (@provision_options, "--host-ip=$ifaceipv4");
616         push (@provision_options, "--quiet");
617         push (@provision_options, "--domain $domain");
618         push (@provision_options, "--realm $realm");
619         push (@provision_options, "--adminpass $password");
620         push (@provision_options, "--root=$root");
621         push (@provision_options, "--simple-bind-dn=cn=Manager,$basedn");
622         push (@provision_options, "--password=$password");
623         push (@provision_options, "--root=$root");
624
625         (system("$self->{bindir}/smbscript $self->{setupdir}/provision " .  join(' ', @provision_options) . ">&2") == 0) or die("Unable to provision");
626
627         my $ldap_uri= "$ldapdir/ldapi";
628         $ldap_uri =~ s|/|%2F|g;
629         $ldap_uri = "ldapi://$ldap_uri";
630
631         my $ret = {
632                 KRB5_CONFIG => $krb5_config,
633                 PIDDIR => $piddir,
634                 SERVER => $server,
635                 NETBIOSNAME => $netbiosname,
636                 LDAP_URI => $ldap_uri,
637                 DOMAIN => $domain,
638                 USERNAME => $username,
639                 REALM => $realm,
640                 PASSWORD => $password,
641                 LDAPDIR => $ldapdir,
642                 WINBINDD_SOCKET_DIR => $winbindd_socket_dir,
643                 NCALRPCDIR => $ncalrpcdir,
644                 CONFIGURATION => $configuration,
645                 SOCKET_WRAPPER_DEFAULT_IFACE => $swiface
646         };
647
648         $ret->{PROVISION_OPTIONS} = join(' ', @provision_options);
649
650         if (defined($self->{ldap})) {
651
652                 if ($self->{ldap} eq "openldap") {
653                        ($ret->{SLAPD_CONF}, $ret->{OPENLDAP_PIDFILE}) = $self->mk_openldap($ldapdir, $basedn, $password, $privatedir, $dnsname, $configuration, join(' ', @provision_options)) or die("Unable to create openldap directories");
654                 } elsif ($self->{ldap} eq "fedora") {
655                        ($ret->{FEDORA_DS_DIR}, $ret->{FEDORA_DS_PIDFILE}) = $self->mk_fedora($ldapdir, $basedn, $root, $password, $privatedir, $configuration) or die("Unable to create fedora ds directories");
656                        push (@provision_options, "--ldap-module=nsuniqueid");
657                 }
658
659                 $self->slapd_start($ret) or 
660                         die("couldn't start slapd");
661                     
662                 print "LDAP PROVISIONING...";
663                 $self->provision_ldap($ret);
664
665                 $self->slapd_stop($ret) or 
666                         die("couldn't stop slapd");
667         }
668         return $ret; 
669 }
670
671 sub provision_member($$$)
672 {
673         my ($self, $prefix, $dcvars) = @_;
674         print "PROVISIONING MEMBER...";
675
676         my $ret = $self->provision($prefix, "member server", "SAMBADOMAIN", 
677                 "localmember", 3);
678
679         $ret or die("Unable to provision");
680
681         system("$self->{bindir}/net join $ret->{CONFIGURATION} $dcvars->{DOMAIN} member -U$dcvars->{USERNAME}\%$dcvars->{PASSWORD}") == 0 or die("Join failed");
682
683         $ret->{SMBD_TEST_FIFO} = "$prefix/smbd_test.fifo";
684         $ret->{SMBD_TEST_LOG} = "$prefix/smbd_test.log";
685         $ret->{SMBD_TEST_LOG_POS} = 0;
686         return $ret;
687 }
688
689 sub provision_dc($$)
690 {
691         my ($self, $prefix) = @_;
692
693         print "PROVISIONING DC...";
694         my $ret = $self->provision($prefix, "domain controller", "SAMBADOMAIN", 
695                 "localtest", 1);
696
697         $self->add_wins_config("$prefix/private") or 
698                 die("Unable to add wins configuration");
699
700         $ret->{SMBD_TEST_FIFO} = "$prefix/smbd_test.fifo";
701         $ret->{SMBD_TEST_LOG} = "$prefix/smbd_test.log";
702         $ret->{SMBD_TEST_LOG_POS} = 0;
703         return $ret;
704 }
705
706 sub provision_ldap($$)
707 {
708         my ($self, $envvars) = @_;
709         my $provision_aci = "";
710         
711         if ($self->{ldap} eq "fedora") {
712                 #it is easier to base64 encode this than correctly escape it:
713                 # (targetattr = "*") (version 3.0;acl "full access to all by all";allow (all)(userdn = "ldap:///anyone");)
714                 $provision_aci = "--aci=aci:: KHRhcmdldGF0dHIgPSAiKiIpICh2ZXJzaW9uIDMuMDthY2wgImZ1bGwgYWNjZXNzIHRvIGFsbCBieSBhbGwiO2FsbG93IChhbGwpKHVzZXJkbiA9ICJsZGFwOi8vL2FueW9uZSIpOykK";
715         }
716
717         system("$self->{bindir}/smbscript $self->{setupdir}/provision $envvars->{PROVISION_OPTIONS} \"$provision_aci\" --ldap-backend=$envvars->{LDAP_URI}") and
718                 die("LDAP PROVISIONING failed: $self->{bindir}/smbscript $self->{setupdir}/provision $envvars->{PROVISION_OPTIONS} \"$provision_aci\" --ldap-backend=$envvars->{LDAP_URI}");
719 }
720
721 sub teardown_env($$)
722 {
723         my ($self, $envvars) = @_;
724
725         close(DATA);
726
727         sleep(2);
728
729         my $failed = $? >> 8;
730
731         if (-f "$envvars->{PIDDIR}/smbd.pid" ) {
732                 open(IN, "<$envvars->{PIDDIR}/smbd.pid") or die("unable to open smbd pid file");
733                 kill 9, <IN>;
734                 close(IN);
735         }
736
737         $self->slapd_stop($envvars) if ($self->{ldap});
738
739         print $self->getlog_env($envvars);
740
741         return $failed;
742 }
743
744 sub getlog_env($$)
745 {
746         my ($self, $envvars) = @_;
747         my $title = "SMBD LOG of: $envvars->{NETBIOSNAME}\n";
748         my $out = $title;
749
750         open(LOG, "<$envvars->{SMBD_TEST_LOG}");
751
752         seek(LOG, $envvars->{SMBD_TEST_LOG_POS}, SEEK_SET);
753         while (<LOG>) {
754                 $out .= $_;
755         }
756         $envvars->{SMBD_TEST_LOG_POS} = tell(LOG);
757         close(LOG);
758
759         return "" if $out eq $title;
760  
761         return $out;
762 }
763
764 sub check_env($$)
765 {
766         my ($self, $envvars) = @_;
767
768         return 1 if (-p $envvars->{SMBD_TEST_FIFO});
769
770         print $self->getlog_env($envvars);
771
772         return 0;
773 }
774
775 sub setup_env($$$)
776 {
777         my ($self, $envname, $path) = @_;
778
779         if ($envname eq "dc") {
780                 return $self->setup_dc("$path/dc");
781         } elsif ($envname eq "member") {
782                 if (not defined($self->{vars}->{dc})) {
783                         $self->setup_dc("$path/dc");
784                 }
785                 return $self->setup_member("$path/member", $self->{vars}->{dc});
786         } else {
787                 die("Samba4 can't provide environment '$envname'");
788         }
789 }
790
791 sub setup_member($$$$)
792 {
793         my ($self, $path, $dc_vars) = @_;
794
795         my $env = $self->provision_member($path, $dc_vars);
796
797         $self->check_or_start($env, ($ENV{SMBD_MAXTIME} or 6500));
798
799         $self->wait_for_start($env);
800
801         return $env;
802 }
803
804 sub setup_dc($$)
805 {
806         my ($self, $path) = @_;
807
808         my $env = $self->provision_dc($path);
809
810         $self->check_or_start($env, 
811                 ($ENV{SMBD_MAXTIME} or 6500));
812
813         $self->wait_for_start($env);
814
815         $self->{vars}->{dc} = $env;
816
817         return $env;
818 }
819
820 sub stop($)
821 {
822         my ($self) = @_;
823 }
824
825 1;