selftest: add "member" environment for Samba3
[metze/samba/wip.git] / selftest / target / Samba3.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 Samba3;
7
8 use strict;
9 use Cwd qw(abs_path);
10 use FindBin qw($RealBin);
11 use POSIX;
12
13 sub binpath($$)
14 {
15         my ($self, $binary) = @_;
16
17         if (defined($self->{bindir})) {
18                 my $path = "$self->{bindir}/$binary";
19                 -f $path or die("File $path doesn't exist");
20                 return $path;
21         }
22
23         return $binary;
24 }
25
26 sub new($$) {
27         my ($classname, $bindir) = @_;
28         my $self = { bindir => $bindir };
29         bless $self;
30         return $self;
31 }
32
33 sub teardown_env($$)
34 {
35         my ($self, $envvars) = @_;
36
37         my $smbdpid = read_pid($envvars, "smbd");
38         my $nmbdpid = read_pid($envvars, "nmbd");
39         my $winbinddpid = read_pid($envvars, "winbindd");
40
41         $self->stop_sig_term($smbdpid);
42         $self->stop_sig_term($nmbdpid);
43         $self->stop_sig_term($winbinddpid);
44         $self->stop_sig_kill($smbdpid);
45         $self->stop_sig_kill($nmbdpid);
46         $self->stop_sig_kill($winbinddpid);
47
48         return 0;
49 }
50
51 sub getlog_env_app($$$)
52 {
53         my ($self, $envvars, $name) = @_;
54
55         my $title = "$name LOG of: $envvars->{NETBIOSNAME}\n";
56         my $out = $title;
57
58         open(LOG, "<".$envvars->{$name."_TEST_LOG"});
59
60         seek(LOG, $envvars->{$name."_TEST_LOG_POS"}, SEEK_SET);
61         while (<LOG>) {
62                 $out .= $_;
63         }
64         $envvars->{$name."_TEST_LOG_POS"} = tell(LOG);
65         close(LOG);
66
67         return "" if $out eq $title;
68  
69         return $out;
70 }
71
72 sub getlog_env($$)
73 {
74         my ($self, $envvars) = @_;
75         my $ret = "";
76
77         $ret .= $self->getlog_env_app($envvars, "SMBD");
78         $ret .= $self->getlog_env_app($envvars, "NMBD");
79         $ret .= $self->getlog_env_app($envvars, "WINBINDD");
80
81         return $ret;
82 }
83
84 sub check_env($$)
85 {
86         my ($self, $envvars) = @_;
87
88         # TODO ...
89         return 1;
90 }
91
92 sub setup_env($$$)
93 {
94         my ($self, $envname, $path) = @_;
95         
96         if ($envname eq "dc") {
97                 return $self->setup_dc("$path/dc");
98         } elsif ($envname eq "member") {
99                 if (not defined($self->{vars}->{dc})) {
100                         $self->setup_dc("$path/dc");
101                 }
102                 return $self->setup_member("$path/member", $self->{vars}->{dc});
103         } else {
104                 return undef;
105         }
106 }
107
108 sub setup_dc($$)
109 {
110         my ($self, $path) = @_;
111
112         print "PROVISIONING DC...";
113
114         my $dc_options = "
115         domain master = yes
116         domain logons = yes
117 ";
118
119         my $vars = $self->provision($path,
120                                     "LOCALDC2",
121                                     2,
122                                     "localdc2pass",
123                                     $dc_options);
124
125         $self->check_or_start($vars,
126                               ($ENV{NMBD_MAXTIME} or 2700),
127                               ($ENV{WINBINDD_MAXTIME} or 2700),
128                               ($ENV{SMBD_MAXTIME} or 2700));
129
130         $self->wait_for_start($vars);
131
132         $self->{vars}->{dc} = $vars;
133
134         return $vars;
135 }
136
137 sub setup_member($$$)
138 {
139         my ($self, $prefix, $dcvars) = @_;
140
141         print "PROVISIONING MEMBER...";
142
143         my $member_options = "
144         security = domain
145 ";
146         my $ret = $self->provision($prefix,
147                                    "LOCALMEMBER3",
148                                    3,
149                                    "localmember3pass",
150                                    $member_options);
151
152         $ret or die("Unable to provision");
153
154         my $net = $self->binpath("net");
155         my $cmd = "";
156         $cmd .= "SOCKET_WRAPPER_DEFAULT_IFACE=\"$ret->{SOCKET_WRAPPER_DEFAULT_IFACE}\" ";
157         $cmd .= "$net join $ret->{CONFIGURATION} $dcvars->{DOMAIN} member";
158         $cmd .= " -U$dcvars->{USERNAME}\%$dcvars->{PASSWORD}";
159
160         system($cmd) == 0 or die("Join failed\n$cmd");
161
162         $self->check_or_start($ret,
163                               ($ENV{NMBD_MAXTIME} or 2700),
164                               ($ENV{WINBINDD_MAXTIME} or 2700),
165                               ($ENV{SMBD_MAXTIME} or 2700));
166
167         $self->wait_for_start($ret);
168
169         $ret->{DC_SERVER} = $dcvars->{SERVER};
170         $ret->{DC_SERVER_IP} = $dcvars->{SERVER_IP};
171         $ret->{DC_NETBIOSNAME} = $dcvars->{NETBIOSNAME};
172         $ret->{DC_USERNAME} = $dcvars->{USERNAME};
173         $ret->{DC_PASSWORD} = $dcvars->{PASSWORD};
174
175         return $ret;
176 }
177
178 sub stop($)
179 {
180         my ($self) = @_;
181 }
182
183 sub stop_sig_term($$) {
184         my ($self, $pid) = @_;
185         kill("USR1", $pid) or kill("ALRM", $pid) or warn("Unable to kill $pid: $!");
186 }
187
188 sub stop_sig_kill($$) {
189         my ($self, $pid) = @_;
190         kill("ALRM", $pid) or warn("Unable to kill $pid: $!");
191 }
192
193 sub write_pid($$$)
194 {
195         my ($env_vars, $app, $pid) = @_;
196
197         open(PID, ">$env_vars->{PIDDIR}/timelimit.$app.pid");
198         print PID $pid;
199         close(PID);
200 }
201
202 sub read_pid($$)
203 {
204         my ($env_vars, $app) = @_;
205
206         open(PID, "<$env_vars->{PIDDIR}/timelimit.$app.pid");
207         my $pid = <PID>;
208         close(PID);
209         return $pid;
210 }
211
212 sub check_or_start($$$$) {
213         my ($self, $env_vars, $nmbd_maxtime, $winbindd_maxtime, $smbd_maxtime) = @_;
214
215         unlink($env_vars->{NMBD_TEST_LOG});
216         print "STARTING NMBD...";
217         my $pid = fork();
218         if ($pid == 0) {
219                 open STDOUT, ">$env_vars->{NMBD_TEST_LOG}";
220                 open STDERR, '>&STDOUT';
221
222                 SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
223
224                 $ENV{WINBINDD_SOCKET_DIR} = $env_vars->{WINBINDD_SOCKET_DIR};
225
226                 $ENV{NSS_WRAPPER_PASSWD} = $env_vars->{NSS_WRAPPER_PASSWD};
227                 $ENV{NSS_WRAPPER_GROUP} = $env_vars->{NSS_WRAPPER_GROUP};
228
229                 my @optargs = ("-d0");
230                 if (defined($ENV{NMBD_OPTIONS})) {
231                         @optargs = split(/ /, $ENV{NMBD_OPTIONS});
232                 }
233
234                 $ENV{MAKE_TEST_BINARY} = $self->binpath("nmbd");
235
236                 my @preargs = ($self->binpath("timelimit"), $nmbd_maxtime);
237                 if(defined($ENV{NMBD_VALGRIND})) { 
238                         @preargs = split(/ /, $ENV{NMBD_VALGRIND});
239                 }
240
241                 exec(@preargs, $self->binpath("nmbd"), "-F", "-S", "--no-process-group", "-s", $env_vars->{SERVERCONFFILE}, @optargs) or die("Unable to start nmbd: $!");
242         }
243         write_pid($env_vars, "nmbd", $pid);
244         print "DONE\n";
245
246         unlink($env_vars->{WINBINDD_TEST_LOG});
247         print "STARTING WINBINDD...";
248         $pid = fork();
249         if ($pid == 0) {
250                 open STDOUT, ">$env_vars->{WINBINDD_TEST_LOG}";
251                 open STDERR, '>&STDOUT';
252
253                 SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
254
255                 $ENV{WINBINDD_SOCKET_DIR} = $env_vars->{WINBINDD_SOCKET_DIR};
256
257                 $ENV{NSS_WRAPPER_PASSWD} = $env_vars->{NSS_WRAPPER_PASSWD};
258                 $ENV{NSS_WRAPPER_GROUP} = $env_vars->{NSS_WRAPPER_GROUP};
259
260                 my @optargs = ("-d0");
261                 if (defined($ENV{WINBINDD_OPTIONS})) {
262                         @optargs = split(/ /, $ENV{WINBINDD_OPTIONS});
263                 }
264
265                 $ENV{MAKE_TEST_BINARY} = $self->binpath("winbindd");
266
267                 my @preargs = ($self->binpath("timelimit"), $winbindd_maxtime);
268                 if(defined($ENV{WINBINDD_VALGRIND})) {
269                         @preargs = split(/ /, $ENV{WINBINDD_VALGRIND});
270                 }
271
272                 exec(@preargs, $self->binpath("winbindd"), "-F", "-S", "--no-process-group", "-s", $env_vars->{SERVERCONFFILE}, @optargs) or die("Unable to start winbindd: $!");
273         }
274         write_pid($env_vars, "winbindd", $pid);
275         print "DONE\n";
276
277         unlink($env_vars->{SMBD_TEST_LOG});
278         print "STARTING SMBD...";
279         $pid = fork();
280         if ($pid == 0) {
281                 open STDOUT, ">$env_vars->{SMBD_TEST_LOG}";
282                 open STDERR, '>&STDOUT';
283
284                 SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
285
286                 $ENV{WINBINDD_SOCKET_DIR} = $env_vars->{WINBINDD_SOCKET_DIR};
287
288                 $ENV{NSS_WRAPPER_PASSWD} = $env_vars->{NSS_WRAPPER_PASSWD};
289                 $ENV{NSS_WRAPPER_GROUP} = $env_vars->{NSS_WRAPPER_GROUP};
290
291                 $ENV{MAKE_TEST_BINARY} = $self->binpath("smbd");
292                 my @optargs = ("-d0");
293                 if (defined($ENV{SMBD_OPTIONS})) {
294                         @optargs = split(/ /, $ENV{SMBD_OPTIONS});
295                 }
296                 my @preargs = ($self->binpath("timelimit"), $smbd_maxtime);
297                 if(defined($ENV{SMBD_VALGRIND})) {
298                         @preargs = split(/ /,$ENV{SMBD_VALGRIND});
299                 }
300                 exec(@preargs, $self->binpath("smbd"), "-F", "-S", "--no-process-group", "-s", $env_vars->{SERVERCONFFILE}, @optargs) or die("Unable to start smbd: $!");
301         }
302         write_pid($env_vars, "smbd", $pid);
303         print "DONE\n";
304
305         return 0;
306 }
307
308 sub create_clientconf($$$)
309 {
310         my ($self, $prefix, $domain) = @_;
311
312         my $lockdir = "$prefix/locks";
313         my $logdir = "$prefix/logs";
314         my $piddir = "$prefix/pid";
315         my $privatedir = "$prefix/private";
316         my $conffile = "$prefix/smb.conf";
317
318         my $torture_interfaces='127.0.0.6/8,127.0.0.7/8,127.0.0.8/8,127.0.0.9/8,127.0.0.10/8,127.0.0.11/8';
319         open(CONF, ">$conffile");
320         print CONF "
321 [global]
322         workgroup = $domain
323
324         private dir = $privatedir
325         pid directory = $piddir
326         lock directory = $lockdir
327         log file = $logdir/log.\%m
328         log level = 0
329
330         name resolve order = bcast
331
332         netbios name = TORTURE_6
333         interfaces = $torture_interfaces
334         panic action = $RealBin/gdb_backtrace \%d %\$(MAKE_TEST_BINARY)
335
336         passdb backend = tdbsam
337         ";
338         close(CONF);
339 }
340
341 sub provision($$$$$$)
342 {
343         my ($self, $prefix, $server, $swiface, $password, $extra_options) = @_;
344
345         ##
346         ## setup the various environment variables we need
347         ##
348
349         my %ret = ();
350         my $server_ip = "127.0.0.$swiface";
351         my $domain = "SAMBA-TEST";
352
353         my $unix_name = ($ENV{USER} or $ENV{LOGNAME} or `PATH=/usr/ucb:$ENV{PATH} whoami`);
354         chomp $unix_name;
355         my $unix_uid = $>;
356         my $unix_gids_str = $);
357         my @unix_gids = split(" ", $unix_gids_str);
358
359         my $prefix_abs = abs_path($prefix);
360         my $bindir_abs = abs_path($self->{bindir});
361
362         my @dirs = ();
363
364         my $shrdir="$prefix_abs/share";
365         push(@dirs,$shrdir);
366
367         my $libdir="$prefix_abs/lib";
368         push(@dirs,$libdir);
369
370         my $piddir="$prefix_abs/pid";
371         push(@dirs,$piddir);
372
373         my $privatedir="$prefix_abs/private";
374         push(@dirs,$privatedir);
375
376         my $lockdir="$prefix_abs/lockdir";
377         push(@dirs,$lockdir);
378
379         my $logdir="$prefix_abs/logs";
380         push(@dirs,$logdir);
381
382         # this gets autocreated by winbindd
383         my $wbsockdir="$prefix_abs/winbindd";
384         my $wbsockprivdir="$lockdir/winbindd_privileged";
385
386         ## 
387         ## create the test directory layout
388         ##
389         mkdir($prefix_abs, 0777);
390         print "CREATE TEST ENVIRONMENT IN '$prefix'...";
391         system("rm -rf $prefix_abs/*");
392         mkdir($_, 0777) foreach(@dirs);
393
394         my $conffile="$libdir/server.conf";
395
396         my $nss_wrapper_pl = "$ENV{PERL} $RealBin/../lib/nss_wrapper/nss_wrapper.pl";
397         my $nss_wrapper_passwd = "$privatedir/passwd";
398         my $nss_wrapper_group = "$privatedir/group";
399
400         open(CONF, ">$conffile") or die("Unable to open $conffile");
401         print CONF "
402 [global]
403         netbios name = $server
404         interfaces = $server_ip/8
405         bind interfaces only = yes
406         panic action = $RealBin/gdb_backtrace %d %\$(MAKE_TEST_BINARY)
407
408         workgroup = $domain
409
410         private dir = $privatedir
411         pid directory = $piddir
412         lock directory = $lockdir
413         log file = $logdir/log.\%m
414         log level = 0
415
416         name resolve order = bcast
417
418         state directory = $lockdir
419         cache directory = $lockdir
420
421         passdb backend = tdbsam
422
423         time server = yes
424
425         add user script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action add --name %u
426         add machine script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action add --name %u
427         delete user script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action delete --name %u
428
429         kernel oplocks = no
430         kernel change notify = no
431
432         syslog = no
433         printing = bsd
434         printcap name = /dev/null
435
436         winbindd:socket dir = $wbsockdir
437         idmap uid = 100000-200000
438         idmap gid = 100000-200000
439
440 #       min receivefile size = 4000
441
442         read only = no
443         smbd:sharedelay = 100000
444         smbd:writetimeupdatedelay = 500000
445         map hidden = yes
446         map system = yes
447         create mask = 755
448         vfs objects = $bindir_abs/xattr_tdb.so $bindir_abs/streams_depot.so
449
450         # Begin extra options
451         $extra_options
452         # End extra options
453
454         #Include user defined custom parameters if set
455 ";
456
457         if (defined($ENV{INCLUDE_CUSTOM_CONF})) {
458                 print CONF "\t$ENV{INCLUDE_CUSTOM_CONF}\n";
459         }
460
461         print CONF "
462 [tmp]
463         path = $shrdir
464 [hideunread]
465         copy = tmp
466         hide unreadable = yes
467 [hideunwrite]
468         copy = tmp
469         hide unwriteable files = yes
470 [print1]
471         copy = tmp
472         printable = yes
473         printing = test
474 [print2]
475         copy = print1
476 [print3]
477         copy = print1
478 [print4]
479         copy = print1
480         ";
481         close(CONF);
482
483         ##
484         ## create a test account
485         ##
486
487         open(PASSWD, ">$nss_wrapper_passwd") or die("Unable to open $nss_wrapper_passwd");
488         print PASSWD "nobody:x:65534:65533:nobody gecos:$prefix_abs:/bin/false
489 $unix_name:x:$unix_uid:$unix_gids[0]:$unix_name gecos:$prefix_abs:/bin/false
490 ";
491         close(PASSWD);
492
493         open(GROUP, ">$nss_wrapper_group") or die("Unable to open $nss_wrapper_group");
494         print GROUP "nobody:x:65533:
495 nogroup:x:65534:nobody
496 $unix_name-group:x:$unix_gids[0]:
497 ";
498         close(GROUP);
499
500         $ENV{NSS_WRAPPER_PASSWD} = $nss_wrapper_passwd;
501         $ENV{NSS_WRAPPER_GROUP} = $nss_wrapper_group;
502
503         open(PWD, "|".$self->binpath("smbpasswd")." -c $conffile -L -s -a $unix_name >/dev/null");
504         print PWD "$password\n$password\n";
505         close(PWD) or die("Unable to set password for test account");
506
507         delete $ENV{NSS_WRAPPER_PASSWD};
508         delete $ENV{NSS_WRAPPER_GROUP};
509
510         print "DONE\n";
511
512         $ret{SERVER_IP} = $server_ip;
513         $ret{NMBD_TEST_LOG} = "$prefix/nmbd_test.log";
514         $ret{NMBD_TEST_LOG_POS} = 0;
515         $ret{WINBINDD_TEST_LOG} = "$prefix/winbindd_test.log";
516         $ret{WINBINDD_TEST_LOG_POS} = 0;
517         $ret{SMBD_TEST_LOG} = "$prefix/smbd_test.log";
518         $ret{SMBD_TEST_LOG_POS} = 0;
519         $ret{SERVERCONFFILE} = $conffile;
520         $ret{CONFIGURATION} ="-s $conffile";
521         $ret{SERVER} = $server;
522         $ret{USERNAME} = $unix_name;
523         $ret{DOMAIN} = $domain;
524         $ret{NETBIOSNAME} = $server;
525         $ret{PASSWORD} = $password;
526         $ret{PIDDIR} = $piddir;
527         $ret{WINBINDD_SOCKET_DIR} = $wbsockdir;
528         $ret{WINBINDD_PRIV_PIPE_DIR} = $wbsockprivdir;
529         $ret{SOCKET_WRAPPER_DEFAULT_IFACE} = $swiface;
530         $ret{NSS_WRAPPER_PASSWD} = $nss_wrapper_passwd;
531         $ret{NSS_WRAPPER_GROUP} = $nss_wrapper_group;
532
533         return \%ret;
534 }
535
536 sub wait_for_start($$)
537 {
538         my ($self, $envvars) = @_;
539
540         # give time for nbt server to register its names
541         print "delaying for nbt name registration\n";
542         sleep(10);
543         # This will return quickly when things are up, but be slow if we need to wait for (eg) SSL init 
544         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U $envvars->{SERVER_IP} __SAMBA__");
545         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} __SAMBA__");
546         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U 127.255.255.255 __SAMBA__");
547         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U $envvars->{SERVER_IP} $envvars->{SERVER}");
548         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} $envvars->{SERVER}");
549         # make sure smbd is also up set
550         print "wait for smbd\n";
551         system($self->binpath("smbclient") ." $envvars->{CONFIGURATION} -L $envvars->{SERVER_IP} -U% -p 139 | head -2");
552         system($self->binpath("smbclient") ." $envvars->{CONFIGURATION} -L $envvars->{SERVER_IP} -U% -p 139 | head -2");
553
554         print "creating BUILTIN\\Administrators\n";
555         $ENV{WINBINDD_SOCKET_DIR} = $envvars->{WINBINDD_SOCKET_DIR};
556         system($self->binpath("net") ." $envvars->{CONFIGURATION} sam createbuiltingroup Administrators");
557         delete $ENV{WINBINDD_SOCKET_DIR};
558
559         print $self->getlog_env($envvars);
560 }
561
562 1;