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.
10 use FindBin qw($RealBin);
14 my ($classname, $bindir, $ldap, $setupdir) = @_;
28 my ($self, $env_vars) = @_;
30 my $uri = $env_vars->{LDAP_URI};
32 # running slapd in the background means it stays in the same process group, so it can be
34 if ($self->{ldap} eq "fedora") {
35 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 &");
36 } elsif ($self->{ldap} eq "openldap") {
37 my $oldpath = $ENV{PATH};
38 $ENV{PATH} = "/usr/local/sbin:/usr/sbin:/sbin:$ENV{PATH}";
39 system("slapd -d0 -f $env_vars->{SLAPD_CONF} -h $uri > $env_vars->{LDAPDIR}/logs 2>&1 &");
40 $ENV{PATH} = $oldpath;
42 while (system("$self->{bindir}/ldbsearch -H $uri -s base -b \"\" supportedLDAPVersion > /dev/null") != 0) {
45 $self->slapd_stop($env_vars);
55 my ($self, $envvars) = @_;
56 if ($self->{ldap} eq "fedora") {
57 system("$envvars->{LDAPDIR}/slapd-samba4/stop-slapd");
58 } elsif ($self->{ldap} eq "openldap") {
59 open(IN, "<$envvars->{OPENLDAP_PIDFILE}") or
60 die("unable to open slapd pid file: $envvars->{OPENLDAP_PIDFILE}");
66 sub check_or_start($$$)
68 my ($self, $env_vars, $max_time) = @_;
69 return 0 if ( -p $env_vars->{SMBD_TEST_FIFO});
71 unlink($env_vars->{SMBD_TEST_FIFO});
72 POSIX::mkfifo($env_vars->{SMBD_TEST_FIFO}, 0700);
73 unlink($env_vars->{SMBD_TEST_LOG});
75 print "STARTING SMBD... ";
78 open STDIN, $env_vars->{SMBD_TEST_FIFO};
79 open STDOUT, ">$env_vars->{SMBD_TEST_LOG}";
80 open STDERR, '>&STDOUT';
82 SocketWrapper::set_default_iface(1);
84 # Start slapd before smbd, but with the fifo on stdin
85 if (defined($self->{ldap})) {
86 $self->slapd_start($env_vars) or
87 die("couldn't start slapd");
89 print "LDAP PROVISIONING...";
90 $self->provision_ldap($env_vars);
94 if (defined($ENV{SMBD_VALGRIND})) {
95 $valgrind = $ENV{SMBD_VALGRIND};
98 $ENV{KRB5_CONFIG} = $env_vars->{KRB5_CONFIG};
101 if (defined($max_time)) {
102 $optarg = "--maximum-runtime=$max_time ";
104 my $ret = system("$valgrind $self->{bindir}/smbd $optarg $env_vars->{CONFIGURATION} -M single -i --leak-report-full");
106 print "Unable to start smbd: $ret: $!\n";
109 unlink($env_vars->{SMBD_TEST_FIFO});
112 print "smbd exits with status $exit\n";
113 } elsif ( $ret & 127 ) {
114 print "smbd got signal ".($ret & 127)." and exits with $exit!\n";
117 print "smbd failed with status $exit!\n";
123 open(DATA, ">$env_vars->{SMBD_TEST_FIFO}");
128 sub wait_for_start($$)
130 my ($self, $testenv_vars) = @_;
131 # give time for nbt server to register its names
132 print "delaying for nbt name registration\n";
134 # This will return quickly when things are up, but be slow if we
135 # need to wait for (eg) SSL init
136 system("bin/nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{SERVER}");
137 system("bin/nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER} $testenv_vars->{SERVER}");
138 system("bin/nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{SERVER}");
139 system("bin/nmblookup $testenv_vars->{CONFIGURATION} -U $testenv_vars->{SERVER} $testenv_vars->{NETBIOSNAME}");
140 system("bin/nmblookup $testenv_vars->{CONFIGURATION} $testenv_vars->{NETBIOSNAME}");
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}");
146 sub write_ldb_file($$$)
148 my ($self, $file, $ldif) = @_;
150 open(LDIF, "|$self->{bindir}/ldbadd -H $file >/dev/null");
155 sub add_wins_config($$)
157 my ($self, $privatedir) = @_;
159 return $self->write_ldb_file("$privatedir/wins_config.ldb", "
160 dn: name=TORTURE_6,CN=PARTNERS
161 objectClass: wreplPartner
170 sub mk_fedora($$$$$$)
172 my ($self, $ldapdir, $basedn, $root, $password, $privatedir, $configuration) = @_;
176 my $fedora_ds_inf = "$ldapdir/fedorads.inf";
177 my $fedora_ds_initial_ldif = "$ldapdir/fedorads-initial.ldif";
179 #Make the subdirectory be as fedora DS would expect
180 my $fedora_ds_dir = "$ldapdir/slapd-samba4";
182 my $pidfile = "$fedora_ds_dir/logs/slapd-samba4.pid";
184 open(CONF, ">$fedora_ds_inf");
187 SuiteSpotUserID = $root
188 FullMachineName= localhost
192 ldapifilepath=$ldapdir/ldapi
194 RootDN= cn=Manager,$basedn
196 ServerIdentifier= samba4
197 InstallLdifFile=$fedora_ds_initial_ldif
199 inst_dir= $fedora_ds_dir
200 config_dir= $fedora_ds_dir
201 schema_dir= $fedora_ds_dir/schema
202 lock_dir= $fedora_ds_dir/lock
203 log_dir= $fedora_ds_dir/logs
204 run_dir= $fedora_ds_dir/logs
205 db_dir= $fedora_ds_dir/db
206 bak_dir= $fedora_ds_dir/bak
207 tmp_dir= $fedora_ds_dir/tmp
208 ldif_dir= $fedora_ds_dir/ldif
209 cert_dir= $fedora_ds_dir
215 open(LDIF, ">$fedora_ds_initial_ldif");
217 # These entries need to be added to get the container for the
218 # provision to be aimed at.
220 dn: cn=\"dc=$basedn\",cn=mapping tree,cn=config
222 objectclass: extensibleObject
223 objectclass: nsMappingTree
224 nsslapd-state: backend
225 nsslapd-backend: userData
228 dn: cn=userData,cn=ldbm database,cn=plugins,cn=config
229 objectclass: extensibleObject
230 objectclass: nsBackendInstance
231 nsslapd-suffix: $basedn
235 system("perl $ENV{FEDORA_DS_PREFIX}/bin/ds_newinst.pl $fedora_ds_inf >&2") == 0 or return 0;
237 foreach(<$fedora_ds_dir/schema/*>) {
238 unlink unless (/00core.*/);
241 open(LDIF, ">>$fedora_ds_dir/dse.ldif");
242 print LDIF "dn: cn=bitwise,cn=plugins,cn=config
244 objectClass: nsSlapdPlugin
245 objectClass: extensibleObject
247 nsslapd-pluginPath: $ENV{FEDORA_DS_PREFIX}/lib/fedora-ds/plugins/libbitwise-plugin.so
248 nsslapd-pluginInitfunc: bitwise_init
249 nsslapd-pluginType: matchingRule
250 nsslapd-pluginEnabled: on
251 nsslapd-pluginId: bitwise
252 nsslapd-pluginVersion: 1.1.0a3
253 nsslapd-pluginVendor: Fedora Project
254 nsslapd-pluginDescription: Allow bitwise matching rules
258 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");
260 return ($fedora_ds_dir, $pidfile);
263 sub mk_openldap($$$$$$$$)
265 my ($self, $ldapdir, $basedn, $password, $privatedir, $dnsname, $configuration, $provision_options) = @_;
267 my $slapd_conf = "$ldapdir/slapd.conf";
268 my $pidfile = "$ldapdir/slapd.pid";
269 my $modconf = "$ldapdir/modules.conf";
271 mkdir($_) foreach ($ldapdir, "$ldapdir/db", "$ldapdir/db/bdb-logs",
274 open(CONF, ">$slapd_conf");
278 include $ldapdir/ad.schema
281 argsfile $ldapdir/slapd.args
283 access to * by * write
288 uid=([^,]*),cn=$dnsname,cn=digest-md5,cn=auth
289 ldap:///$basedn??sub?(samAccountName=\$1)
292 uid=([^,]*),cn=([^,]*),cn=digest-md5,cn=auth
293 ldap:///$basedn??sub?(samAccountName=\$1)
297 defaultsearchbase \"$basedn\"
302 rootdn \"cn=Manager,$basedn\"
304 directory $ldapdir/db
306 index samAccountName eq
309 index objectCategory eq
316 index lDAPDisplayName eq
319 index nETBIOSName eq pres
321 #syncprov is stable in OpenLDAP 2.3, and available in 2.2.
322 #We only need this for the contextCSN attribute anyway....
324 syncprov-checkpoint 100 10
325 syncprov-sessionlog 100
330 open(CONF, ">$ldapdir/db/DB_CONFIG");
333 # Set the database in memory cache size.
335 set_cachesize 0 524288 0
339 # Set database flags (this is a test environment, we don't need to fsync()).
341 set_flags DB_TXN_NOSYNC
346 set_lg_regionmax 104857
349 set_lg_dir $ldapdir/db/bdb-logs
353 # Set temporary file creation directory.
355 set_tmp_dir $ldapdir/db/tmp
359 #This uses the provision we just did, to read out the schema
360 system("$self->{bindir}/ad2oLschema $configuration -H $privatedir/sam.ldb -I $self->{setupdir}/schema-map-openldap-2.3 -O $ldapdir/ad.schema >&2");
362 #Now create an LDAP baseDN
363 system("$self->{bindir}/smbscript $self->{setupdir}/provision $provision_options --ldap-base >&2");
365 my $oldpath = $ENV{PATH};
366 $ENV{PATH} = "/usr/local/sbin:/usr/sbin:/sbin:$ENV{PATH}";
369 open(CONF, ">$modconf"); close(CONF);
371 if (system("slaptest -u -f $slapd_conf >&2") != 0) {
372 open(CONF, ">$modconf");
373 # enable slapd modules
375 modulepath /usr/lib/ldap
382 system("slaptest -u -f $slapd_conf") == 0 or die("slaptest still fails after adding modules");
383 system("slapadd -f $slapd_conf < $privatedir/$dnsname.ldif >/dev/null") == 0 or die("slapadd failed");
385 system("slaptest -f $slapd_conf >/dev/null") == 0 or
386 die ("slaptest after database load failed");
388 $ENV{PATH} = $oldpath;
390 return ($slapd_conf, $pidfile);
395 my ($self, $prefix, $server_role, $domain, $netbiosname) = @_;
397 my $smbd_loglevel = 1;
398 my $username = "administrator";
399 my $realm = "SAMBA.EXAMPLE.COM";
400 my $dnsname = "samba.example.com";
401 my $basedn = "dc=samba,dc=example,dc=com";
402 my $password = "penguin";
403 my $root = ($ENV{USER} or $ENV{LOGNAME} or `whoami`);
404 my $server = "localhost";
405 my $srcdir="$RealBin/../..";
406 -d $prefix or mkdir($prefix) or die("Unable to create $prefix");
407 my $prefix_abs = abs_path($prefix);
408 my $tmpdir = "$prefix_abs/tmp";
409 my $etcdir = "$prefix_abs/etc";
410 my $piddir = "$prefix_abs/pid";
411 my $conffile = "$etcdir/smb.conf";
412 my $krb5_config = "$etcdir/krb5.conf";
413 my $privatedir = "$prefix_abs/private";
414 my $ncalrpcdir = "$prefix_abs/ncalrpc";
415 my $lockdir= "$prefix_abs/lockdir";
417 my $winbindd_socket_dir = "$prefix_abs/winbind_socket";
418 my $configuration = "--configfile=$conffile";
419 my $ldapdir = "$prefix_abs/ldap";
421 my $tlsdir = "$privatedir/tls";
423 (system("rm -rf $prefix/*") == 0) or die("Unable to clean up");
424 mkdir($_) foreach ($privatedir, $etcdir, $piddir, $ncalrpcdir, $lockdir,
427 open(CONFFILE, ">$conffile");
430 netbios name = $netbiosname
431 netbios aliases = $server
434 private dir = $privatedir
435 pid directory = $piddir
436 ncalrpc dir = $ncalrpcdir
438 setup directory = $self->{setupdir}
439 js include = $srcdir/scripting/libjs
440 winbindd socket directory = $winbindd_socket_dir
441 name resolve order = bcast
442 interfaces = 127.0.0.1/8
443 tls dh params file = $tlsdir/dhparms.pem
444 panic action = $srcdir/script/gdb_backtrace \%PID% \%PROG%
446 server role = $server_role
448 server max protocol = SMB2
449 notify:inotify = false
451 system:anonymous = true
452 #We don't want to pass our self-tests if the PAC code is wrong
453 gensec:require_pac = true
454 log level = $smbd_loglevel
459 ntvfs handler = posix
460 posix:sharedelay = 100000
461 posix:eadb = $lockdir/eadb.tdb
466 cifs:server = $netbiosname
468 #There is no username specified here, instead the client is expected
469 #to log in with kerberos, and smbd will used delegated credentials.
474 ntvfs handler = simple
478 ntvfs handler = cifsposix
482 die ("Unable to create key blobs") if
483 (system("TLSDIR=$tlsdir $RealBin/mk-keyblobs.sh") != 0);
485 open(KRB5CONF, ">$krb5_config");
487 #Generated krb5.conf for $realm
490 default_realm = $realm
491 dns_lookup_realm = false
492 dns_lookup_kdc = false
493 ticket_lifetime = 24h
499 admin_server = 127.0.0.1:88
500 default_domain = $dnsname
504 admin_server = 127.0.0.1:88
505 default_domain = $dnsname
509 admin_server = 127.0.0.1:88
510 default_domain = $dnsname
514 pkinit_anchors = FILE:$tlsdir/ca.pem
518 pkinit_identity = FILE:$tlsdir/kdc.pem,$tlsdir/key.pem
519 pkinit_anchors = FILE:$tlsdir/ca.pem
526 #Ensure the config file is valid before we start
527 if (system("$self->{bindir}/testparm $configuration -v --suppress-prompt >/dev/null 2>&1") != 0) {
528 system("$self->{bindir}/testparm $configuration >&2");
529 die("Failed to create configuration!");
532 (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 configuration!");
534 my @provision_options = ($configuration);
535 push (@provision_options, "--host-name=$netbiosname");
536 push (@provision_options, "--host-ip=127.0.0.1");
537 push (@provision_options, "--quiet");
538 push (@provision_options, "--domain $domain");
539 push (@provision_options, "--realm $realm");
540 push (@provision_options, "--adminpass $password");
541 push (@provision_options, "--root=$root");
542 push (@provision_options, "--simple-bind-dn=cn=Manager,$basedn");
543 push (@provision_options, "--password=$password");
544 push (@provision_options, "--root=$root");
546 (system("$self->{bindir}/smbscript $self->{setupdir}/provision " . join(' ', @provision_options) . ">&2") == 0) or die("Unable to provision");
548 my $ldap_uri= "$ldapdir/ldapi";
549 $ldap_uri =~ s|/|%2F|g;
550 $ldap_uri = "ldapi://$ldap_uri";
553 KRB5_CONFIG => $krb5_config,
556 NETBIOSNAME => $netbiosname,
557 LDAP_URI => $ldap_uri,
559 USERNAME => $username,
561 PASSWORD => $password,
563 WINBINDD_SOCKET_DIR => $winbindd_socket_dir,
564 NCALRPCDIR => $ncalrpcdir,
565 CONFIGURATION => $configuration
568 if (not defined($self->{ldap})) {
569 } elsif ($self->{ldap} eq "openldap") {
570 ($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");
571 } elsif ($self->{ldap} eq "fedora") {
572 ($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");
573 push (@provision_options, "--ldap-module=nsuniqueid");
576 $ret->{PROVISION_OPTIONS} = join(' ', @provision_options);
581 sub provision_member($$$)
583 my ($self, $prefix, $dcvars) = @_;
584 print "PROVISIONING MEMBER...";
586 my $ret = $self->provision($prefix, "member server", "SAMBADOMAIN",
589 $ret or die("Unable to provision");
591 system("$self->{bindir}/net join $ret->{CONFIGURATION} $dcvars->{DOMAIN} member -U$dcvars->{USERNAME}\%$dcvars->{PASSWORD}") == 0 or die("Join failed");
593 $ret->{SMBD_TEST_FIFO} = "$prefix/smbd_test.fifo";
594 $ret->{SMBD_TEST_LOG} = "$prefix/smbd_test.log";
600 my ($self, $prefix) = @_;
602 print "PROVISIONING DC...";
603 my $ret = $self->provision($prefix, "domain controller", "SAMBADOMAIN",
606 $self->add_wins_config("$prefix/private") or
607 die("Unable to add wins configuration");
609 $ret->{SMBD_TEST_FIFO} = "$prefix/smbd_test.fifo";
610 $ret->{SMBD_TEST_LOG} = "$prefix/smbd_test.log";
614 sub provision_ldap($$)
616 my ($self, $envvars) = @_;
617 my $provision_aci = "";
619 if ($self->{ldap} eq "fedora") {
620 #it is easier to base64 encode this than correctly escape it:
621 # (targetattr = "*") (version 3.0;acl "full access to all by all";allow (all)(userdn = "ldap:///anyone");)
622 $provision_aci = "--aci=aci:: KHRhcmdldGF0dHIgPSAiKiIpICh2ZXJzaW9uIDMuMDthY2wgImZ1bGwgYWNjZXNzIHRvIGFsbCBieSBhbGwiO2FsbG93IChhbGwpKHVzZXJkbiA9ICJsZGFwOi8vL2FueW9uZSIpOykK";
625 system("$self->{bindir}/smbscript $self->{setupdir}/provision $envvars->{PROVISION_OPTIONS} \"$provision_aci\" --ldap-backend=$envvars->{LDAP_URI}") and
626 die("LDAP PROVISIONING failed: $self->{bindir}/smbscript $self->{setupdir}/provision $envvars->{PROVISION_OPTIONS} \"$provision_aci\" --ldap-backend=$envvars->{LDAP_URI}");
631 my ($self, $envvars) = @_;
637 my $failed = $? >> 8;
639 if (-f "$envvars->{PIDDIR}/smbd.pid" ) {
640 open(IN, "<$envvars->{PIDDIR}/smbd.pid") or die("unable to open smbd pid file");
645 $self->slapd_stop($envvars) if ($self->{ldap});
652 my ($self, $envname, $path) = @_;
654 if ($envname eq "dc") {
655 return $self->setup_dc("$path/dc");
656 } elsif ($envname eq "member") {
657 if (not defined($self->{vars}->{dc})) {
658 $self->setup_dc("$path/dc");
660 return $self->setup_member("$path/member", $self->{vars}->{dc});
662 die("Samba4 can't provide environment '$envname'");
666 sub setup_member($$$$)
668 my ($self, $path, $dc_vars) = @_;
670 my $env = $self->provision_member($path, $dc_vars);
672 $self->check_or_start($env, ($ENV{SMBD_MAX_TIME} or 5400));
674 $self->wait_for_start($env);
681 my ($self, $path) = @_;
683 my $env = $self->provision_dc($path);
685 $self->check_or_start($env,
686 ($ENV{SMBD_MAX_TIME} or 5400));
688 $self->wait_for_start($env);
690 $self->{vars}->{dc} = $env;