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($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
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}");
145 print $self->getlog_env($testenv_vars);
148 sub write_ldb_file($$$)
150 my ($self, $file, $ldif) = @_;
152 open(LDIF, "|$self->{bindir}/ldbadd -H $file >/dev/null");
157 sub add_wins_config($$)
159 my ($self, $privatedir) = @_;
161 return $self->write_ldb_file("$privatedir/wins_config.ldb", "
162 dn: name=TORTURE_6,CN=PARTNERS
163 objectClass: wreplPartner
172 sub mk_fedora($$$$$$)
174 my ($self, $ldapdir, $basedn, $root, $password, $privatedir, $configuration) = @_;
178 my $fedora_ds_inf = "$ldapdir/fedorads.inf";
179 my $fedora_ds_initial_ldif = "$ldapdir/fedorads-initial.ldif";
181 #Make the subdirectory be as fedora DS would expect
182 my $fedora_ds_dir = "$ldapdir/slapd-samba4";
184 my $pidfile = "$fedora_ds_dir/logs/slapd-samba4.pid";
186 open(CONF, ">$fedora_ds_inf");
189 SuiteSpotUserID = $root
190 FullMachineName= localhost
194 ldapifilepath=$ldapdir/ldapi
196 RootDN= cn=Manager,$basedn
198 ServerIdentifier= samba4
199 InstallLdifFile=$fedora_ds_initial_ldif
201 inst_dir= $fedora_ds_dir
202 config_dir= $fedora_ds_dir
203 schema_dir= $fedora_ds_dir/schema
204 lock_dir= $fedora_ds_dir/lock
205 log_dir= $fedora_ds_dir/logs
206 run_dir= $fedora_ds_dir/logs
207 db_dir= $fedora_ds_dir/db
208 bak_dir= $fedora_ds_dir/bak
209 tmp_dir= $fedora_ds_dir/tmp
210 ldif_dir= $fedora_ds_dir/ldif
211 cert_dir= $fedora_ds_dir
217 open(LDIF, ">$fedora_ds_initial_ldif");
219 # These entries need to be added to get the container for the
220 # provision to be aimed at.
222 dn: cn=\"dc=$basedn\",cn=mapping tree,cn=config
224 objectclass: extensibleObject
225 objectclass: nsMappingTree
226 nsslapd-state: backend
227 nsslapd-backend: userData
230 dn: cn=userData,cn=ldbm database,cn=plugins,cn=config
231 objectclass: extensibleObject
232 objectclass: nsBackendInstance
233 nsslapd-suffix: $basedn
237 system("perl $ENV{FEDORA_DS_PREFIX}/bin/ds_newinst.pl $fedora_ds_inf >&2") == 0 or return 0;
239 foreach(<$fedora_ds_dir/schema/*>) {
240 unlink unless (/00core.*/);
243 open(LDIF, ">>$fedora_ds_dir/dse.ldif");
244 print LDIF "dn: cn=bitwise,cn=plugins,cn=config
246 objectClass: nsSlapdPlugin
247 objectClass: extensibleObject
249 nsslapd-pluginPath: $ENV{FEDORA_DS_PREFIX}/lib/fedora-ds/plugins/libbitwise-plugin.so
250 nsslapd-pluginInitfunc: bitwise_init
251 nsslapd-pluginType: matchingRule
252 nsslapd-pluginEnabled: on
253 nsslapd-pluginId: bitwise
254 nsslapd-pluginVersion: 1.1.0a3
255 nsslapd-pluginVendor: Fedora Project
256 nsslapd-pluginDescription: Allow bitwise matching rules
260 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");
262 return ($fedora_ds_dir, $pidfile);
265 sub mk_openldap($$$$$$$$)
267 my ($self, $ldapdir, $basedn, $password, $privatedir, $dnsname, $configuration, $provision_options) = @_;
269 my $slapd_conf = "$ldapdir/slapd.conf";
270 my $pidfile = "$ldapdir/slapd.pid";
271 my $modconf = "$ldapdir/modules.conf";
273 mkdir($_) foreach ($ldapdir, "$ldapdir/db", "$ldapdir/db/bdb-logs",
276 open(CONF, ">$slapd_conf");
280 include $ldapdir/ad.schema
283 argsfile $ldapdir/slapd.args
285 access to * by * write
290 uid=([^,]*),cn=$dnsname,cn=digest-md5,cn=auth
291 ldap:///$basedn??sub?(samAccountName=\$1)
294 uid=([^,]*),cn=([^,]*),cn=digest-md5,cn=auth
295 ldap:///$basedn??sub?(samAccountName=\$1)
299 defaultsearchbase \"$basedn\"
304 rootdn \"cn=Manager,$basedn\"
306 directory $ldapdir/db
308 index samAccountName eq
311 index objectCategory eq
318 index lDAPDisplayName eq
321 index nETBIOSName eq pres
323 #syncprov is stable in OpenLDAP 2.3, and available in 2.2.
324 #We only need this for the contextCSN attribute anyway....
326 syncprov-checkpoint 100 10
327 syncprov-sessionlog 100
332 open(CONF, ">$ldapdir/db/DB_CONFIG");
335 # Set the database in memory cache size.
337 set_cachesize 0 524288 0
341 # Set database flags (this is a test environment, we don't need to fsync()).
343 set_flags DB_TXN_NOSYNC
348 set_lg_regionmax 104857
351 set_lg_dir $ldapdir/db/bdb-logs
355 # Set temporary file creation directory.
357 set_tmp_dir $ldapdir/db/tmp
361 #This uses the provision we just did, to read out the schema
362 system("$self->{bindir}/ad2oLschema $configuration -H $privatedir/sam.ldb -I $self->{setupdir}/schema-map-openldap-2.3 -O $ldapdir/ad.schema >&2");
364 #Now create an LDAP baseDN
365 system("$self->{bindir}/smbscript $self->{setupdir}/provision $provision_options --ldap-base >&2");
367 my $oldpath = $ENV{PATH};
368 $ENV{PATH} = "/usr/local/sbin:/usr/sbin:/sbin:$ENV{PATH}";
371 open(CONF, ">$modconf"); close(CONF);
373 if (system("slaptest -u -f $slapd_conf >&2") != 0) {
374 open(CONF, ">$modconf");
375 # enable slapd modules
377 modulepath /usr/lib/ldap
384 system("slaptest -u -f $slapd_conf") == 0 or die("slaptest still fails after adding modules");
385 system("slapadd -f $slapd_conf < $privatedir/$dnsname.ldif >/dev/null") == 0 or die("slapadd failed");
387 system("slaptest -f $slapd_conf >/dev/null") == 0 or
388 die ("slaptest after database load failed");
390 $ENV{PATH} = $oldpath;
392 return ($slapd_conf, $pidfile);
397 my ($self, $prefix, $server_role, $domain, $netbiosname, $swiface) = @_;
399 my $smbd_loglevel = 1;
400 my $username = "administrator";
401 my $realm = "SAMBA.EXAMPLE.COM";
402 my $dnsname = "samba.example.com";
403 my $basedn = "dc=samba,dc=example,dc=com";
404 my $password = "penguin";
405 my $root = ($ENV{USER} or $ENV{LOGNAME} or `whoami`);
406 my $server = "localhost";
407 my $srcdir="$RealBin/../..";
408 -d $prefix or mkdir($prefix) or die("Unable to create $prefix");
409 my $prefix_abs = abs_path($prefix);
410 my $tmpdir = "$prefix_abs/tmp";
411 my $etcdir = "$prefix_abs/etc";
412 my $piddir = "$prefix_abs/pid";
413 my $conffile = "$etcdir/smb.conf";
414 my $krb5_config = "$etcdir/krb5.conf";
415 my $privatedir = "$prefix_abs/private";
416 my $ncalrpcdir = "$prefix_abs/ncalrpc";
417 my $lockdir = "$prefix_abs/lockdir";
418 my $winbindd_socket_dir = "$prefix_abs/winbind_socket";
420 my $configuration = "--configfile=$conffile";
421 my $ldapdir = "$prefix_abs/ldap";
423 my $tlsdir = "$privatedir/tls";
425 my $ifaceipv4 = "127.0.0.$swiface";
426 my $interfaces = "$ifaceipv4/8";
428 (system("rm -rf $prefix/*") == 0) or die("Unable to clean up");
429 mkdir($_) foreach ($privatedir, $etcdir, $piddir, $ncalrpcdir, $lockdir,
432 open(CONFFILE, ">$conffile");
435 netbios name = $netbiosname
436 netbios aliases = $server
439 private dir = $privatedir
440 pid directory = $piddir
441 ncalrpc dir = $ncalrpcdir
443 setup directory = $self->{setupdir}
444 js include = $srcdir/scripting/libjs
445 winbindd socket directory = $winbindd_socket_dir
446 name resolve order = bcast
447 interfaces = $interfaces
448 tls dh params file = $tlsdir/dhparms.pem
449 panic action = $srcdir/script/gdb_backtrace \%PID% \%PROG%
451 server role = $server_role
453 server max protocol = SMB2
454 notify:inotify = false
456 system:anonymous = true
457 #We don't want to pass our self-tests if the PAC code is wrong
458 gensec:require_pac = true
459 log level = $smbd_loglevel
464 ntvfs handler = posix
465 posix:sharedelay = 100000
466 posix:eadb = $lockdir/eadb.tdb
471 cifs:server = $netbiosname
473 #There is no username specified here, instead the client is expected
474 #to log in with kerberos, and smbd will used delegated credentials.
479 ntvfs handler = simple
483 ntvfs handler = cifsposix
487 die ("Unable to create key blobs") if
488 (system("TLSDIR=$tlsdir $RealBin/mk-keyblobs.sh") != 0);
490 open(KRB5CONF, ">$krb5_config");
492 #Generated krb5.conf for $realm
495 default_realm = $realm
496 dns_lookup_realm = false
497 dns_lookup_kdc = false
498 ticket_lifetime = 24h
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 admin_server = 127.0.0.1:88
515 default_domain = $dnsname
519 pkinit_anchors = FILE:$tlsdir/ca.pem
523 pkinit_identity = FILE:$tlsdir/kdc.pem,$tlsdir/key.pem
524 pkinit_anchors = FILE:$tlsdir/ca.pem
531 #Ensure the config file is valid before we start
532 if (system("$self->{bindir}/testparm $configuration -v --suppress-prompt >/dev/null 2>&1") != 0) {
533 system("$self->{bindir}/testparm $configuration >&2");
534 die("Failed to create configuration!");
537 (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!");
539 my @provision_options = ($configuration);
540 push (@provision_options, "--host-name=$netbiosname");
541 push (@provision_options, "--host-ip=$ifaceipv4");
542 push (@provision_options, "--quiet");
543 push (@provision_options, "--domain $domain");
544 push (@provision_options, "--realm $realm");
545 push (@provision_options, "--adminpass $password");
546 push (@provision_options, "--root=$root");
547 push (@provision_options, "--simple-bind-dn=cn=Manager,$basedn");
548 push (@provision_options, "--password=$password");
549 push (@provision_options, "--root=$root");
551 (system("$self->{bindir}/smbscript $self->{setupdir}/provision " . join(' ', @provision_options) . ">&2") == 0) or die("Unable to provision");
553 my $ldap_uri= "$ldapdir/ldapi";
554 $ldap_uri =~ s|/|%2F|g;
555 $ldap_uri = "ldapi://$ldap_uri";
558 KRB5_CONFIG => $krb5_config,
561 NETBIOSNAME => $netbiosname,
562 LDAP_URI => $ldap_uri,
564 USERNAME => $username,
566 PASSWORD => $password,
568 WINBINDD_SOCKET_DIR => $winbindd_socket_dir,
569 NCALRPCDIR => $ncalrpcdir,
570 CONFIGURATION => $configuration,
571 SOCKET_WRAPPER_DEFAULT_IFACE => $swiface
574 if (not defined($self->{ldap})) {
575 } elsif ($self->{ldap} eq "openldap") {
576 ($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");
577 } elsif ($self->{ldap} eq "fedora") {
578 ($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");
579 push (@provision_options, "--ldap-module=nsuniqueid");
582 $ret->{PROVISION_OPTIONS} = join(' ', @provision_options);
587 sub provision_member($$$)
589 my ($self, $prefix, $dcvars) = @_;
590 print "PROVISIONING MEMBER...";
592 my $ret = $self->provision($prefix, "member server", "SAMBADOMAIN",
595 $ret or die("Unable to provision");
597 system("$self->{bindir}/net join $ret->{CONFIGURATION} $dcvars->{DOMAIN} member -U$dcvars->{USERNAME}\%$dcvars->{PASSWORD}") == 0 or die("Join failed");
599 $ret->{SMBD_TEST_FIFO} = "$prefix/smbd_test.fifo";
600 $ret->{SMBD_TEST_LOG} = "$prefix/smbd_test.log";
601 $ret->{SMBD_TEST_LOG_POS} = 0;
607 my ($self, $prefix) = @_;
609 print "PROVISIONING DC...";
610 my $ret = $self->provision($prefix, "domain controller", "SAMBADOMAIN",
613 $self->add_wins_config("$prefix/private") or
614 die("Unable to add wins configuration");
616 $ret->{SMBD_TEST_FIFO} = "$prefix/smbd_test.fifo";
617 $ret->{SMBD_TEST_LOG} = "$prefix/smbd_test.log";
618 $ret->{SMBD_TEST_LOG_POS} = 0;
622 sub provision_ldap($$)
624 my ($self, $envvars) = @_;
625 my $provision_aci = "";
627 if ($self->{ldap} eq "fedora") {
628 #it is easier to base64 encode this than correctly escape it:
629 # (targetattr = "*") (version 3.0;acl "full access to all by all";allow (all)(userdn = "ldap:///anyone");)
630 $provision_aci = "--aci=aci:: KHRhcmdldGF0dHIgPSAiKiIpICh2ZXJzaW9uIDMuMDthY2wgImZ1bGwgYWNjZXNzIHRvIGFsbCBieSBhbGwiO2FsbG93IChhbGwpKHVzZXJkbiA9ICJsZGFwOi8vL2FueW9uZSIpOykK";
633 system("$self->{bindir}/smbscript $self->{setupdir}/provision $envvars->{PROVISION_OPTIONS} \"$provision_aci\" --ldap-backend=$envvars->{LDAP_URI}") and
634 die("LDAP PROVISIONING failed: $self->{bindir}/smbscript $self->{setupdir}/provision $envvars->{PROVISION_OPTIONS} \"$provision_aci\" --ldap-backend=$envvars->{LDAP_URI}");
639 my ($self, $envvars) = @_;
645 my $failed = $? >> 8;
647 if (-f "$envvars->{PIDDIR}/smbd.pid" ) {
648 open(IN, "<$envvars->{PIDDIR}/smbd.pid") or die("unable to open smbd pid file");
653 $self->slapd_stop($envvars) if ($self->{ldap});
660 my ($self, $envvars) = @_;
661 my $title = "SMBD LOG of: $envvars->{NETBIOSNAME}\n";
664 open(LOG, "<$envvars->{SMBD_TEST_LOG}");
666 seek(LOG, $envvars->{SMBD_TEST_LOG_POS}, SEEK_SET);
670 $envvars->{SMBD_TEST_LOG_POS} = tell(LOG);
673 return "" if $out eq $title;
680 my ($self, $envvars) = @_;
682 return 1 if (-p $envvars->{SMBD_TEST_FIFO});
689 my ($self, $envname, $path) = @_;
691 if ($envname eq "dc") {
692 return $self->setup_dc("$path/dc");
693 } elsif ($envname eq "member") {
694 if (not defined($self->{vars}->{dc})) {
695 $self->setup_dc("$path/dc");
697 return $self->setup_member("$path/member", $self->{vars}->{dc});
699 die("Samba4 can't provide environment '$envname'");
703 sub setup_member($$$$)
705 my ($self, $path, $dc_vars) = @_;
707 my $env = $self->provision_member($path, $dc_vars);
709 $self->check_or_start($env, ($ENV{SMBD_MAX_TIME} or 5400));
711 $self->wait_for_start($env);
718 my ($self, $path) = @_;
720 my $env = $self->provision_dc($path);
722 $self->check_or_start($env,
723 ($ENV{SMBD_MAX_TIME} or 5400));
725 $self->wait_for_start($env);
727 $self->{vars}->{dc} = $env;