selftest: fix Samba3 bugs
[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         } else {
99                 return undef;
100         }
101 }
102
103 sub setup_dc($$)
104 {
105         my ($self, $path) = @_;
106
107         print "PROVISIONING DC...";
108
109         my $dc_options = "
110         domain master = yes
111         domain logons = yes
112 ";
113
114         my $vars = $self->provision($path,
115                                     "LOCALDC2",
116                                     2,
117                                     "localdc2pass",
118                                     $dc_options);
119
120         $self->check_or_start($vars,
121                               ($ENV{NMBD_MAXTIME} or 2700),
122                               ($ENV{WINBINDD_MAXTIME} or 2700),
123                               ($ENV{SMBD_MAXTIME} or 2700));
124
125         $self->wait_for_start($vars);
126
127         return $vars;
128 }
129
130 sub stop($)
131 {
132         my ($self) = @_;
133 }
134
135 sub stop_sig_term($$) {
136         my ($self, $pid) = @_;
137         kill("USR1", $pid) or kill("ALRM", $pid) or warn("Unable to kill $pid: $!");
138 }
139
140 sub stop_sig_kill($$) {
141         my ($self, $pid) = @_;
142         kill("ALRM", $pid) or warn("Unable to kill $pid: $!");
143 }
144
145 sub write_pid($$$)
146 {
147         my ($env_vars, $app, $pid) = @_;
148
149         open(PID, ">$env_vars->{PIDDIR}/timelimit.$app.pid");
150         print PID $pid;
151         close(PID);
152 }
153
154 sub read_pid($$)
155 {
156         my ($env_vars, $app) = @_;
157
158         open(PID, "<$env_vars->{PIDDIR}/timelimit.$app.pid");
159         my $pid = <PID>;
160         close(PID);
161         return $pid;
162 }
163
164 sub check_or_start($$$$) {
165         my ($self, $env_vars, $nmbd_maxtime, $winbindd_maxtime, $smbd_maxtime) = @_;
166
167         unlink($env_vars->{NMBD_TEST_LOG});
168         print "STARTING NMBD...";
169         my $pid = fork();
170         if ($pid == 0) {
171                 open STDOUT, ">$env_vars->{NMBD_TEST_LOG}";
172                 open STDERR, '>&STDOUT';
173
174                 SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
175
176                 $ENV{WINBINDD_SOCKET_DIR} = $env_vars->{WINBINDD_SOCKET_DIR};
177
178                 $ENV{NSS_WRAPPER_PASSWD} = $env_vars->{NSS_WRAPPER_PASSWD};
179                 $ENV{NSS_WRAPPER_GROUP} = $env_vars->{NSS_WRAPPER_GROUP};
180
181                 my @optargs = ("-d0");
182                 if (defined($ENV{NMBD_OPTIONS})) {
183                         @optargs = split(/ /, $ENV{NMBD_OPTIONS});
184                 }
185
186                 $ENV{MAKE_TEST_BINARY} = $self->binpath("nmbd");
187
188                 my @preargs = ($self->binpath("timelimit"), $nmbd_maxtime);
189                 if(defined($ENV{NMBD_VALGRIND})) { 
190                         @preargs = split(/ /, $ENV{NMBD_VALGRIND});
191                 }
192
193                 exec(@preargs, $self->binpath("nmbd"), "-F", "-S", "--no-process-group", "-s", $env_vars->{SERVERCONFFILE}, @optargs) or die("Unable to start nmbd: $!");
194         }
195         write_pid($env_vars, "nmbd", $pid);
196         print "DONE\n";
197
198         unlink($env_vars->{WINBINDD_TEST_LOG});
199         print "STARTING WINBINDD...";
200         $pid = fork();
201         if ($pid == 0) {
202                 open STDOUT, ">$env_vars->{WINBINDD_TEST_LOG}";
203                 open STDERR, '>&STDOUT';
204
205                 SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
206
207                 $ENV{WINBINDD_SOCKET_DIR} = $env_vars->{WINBINDD_SOCKET_DIR};
208
209                 $ENV{NSS_WRAPPER_PASSWD} = $env_vars->{NSS_WRAPPER_PASSWD};
210                 $ENV{NSS_WRAPPER_GROUP} = $env_vars->{NSS_WRAPPER_GROUP};
211
212                 my @optargs = ("-d0");
213                 if (defined($ENV{WINBINDD_OPTIONS})) {
214                         @optargs = split(/ /, $ENV{WINBINDD_OPTIONS});
215                 }
216
217                 $ENV{MAKE_TEST_BINARY} = $self->binpath("winbindd");
218
219                 my @preargs = ($self->binpath("timelimit"), $winbindd_maxtime);
220                 if(defined($ENV{WINBINDD_VALGRIND})) {
221                         @preargs = split(/ /, $ENV{WINBINDD_VALGRIND});
222                 }
223
224                 exec(@preargs, $self->binpath("winbindd"), "-F", "-S", "--no-process-group", "-s", $env_vars->{SERVERCONFFILE}, @optargs) or die("Unable to start winbindd: $!");
225         }
226         write_pid($env_vars, "winbindd", $pid);
227         print "DONE\n";
228
229         unlink($env_vars->{SMBD_TEST_LOG});
230         print "STARTING SMBD...";
231         $pid = fork();
232         if ($pid == 0) {
233                 open STDOUT, ">$env_vars->{SMBD_TEST_LOG}";
234                 open STDERR, '>&STDOUT';
235
236                 SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
237
238                 $ENV{WINBINDD_SOCKET_DIR} = $env_vars->{WINBINDD_SOCKET_DIR};
239
240                 $ENV{NSS_WRAPPER_PASSWD} = $env_vars->{NSS_WRAPPER_PASSWD};
241                 $ENV{NSS_WRAPPER_GROUP} = $env_vars->{NSS_WRAPPER_GROUP};
242
243                 $ENV{MAKE_TEST_BINARY} = $self->binpath("smbd");
244                 my @optargs = ("-d0");
245                 if (defined($ENV{SMBD_OPTIONS})) {
246                         @optargs = split(/ /, $ENV{SMBD_OPTIONS});
247                 }
248                 my @preargs = ($self->binpath("timelimit"), $smbd_maxtime);
249                 if(defined($ENV{SMBD_VALGRIND})) {
250                         @preargs = split(/ /,$ENV{SMBD_VALGRIND});
251                 }
252                 exec(@preargs, $self->binpath("smbd"), "-F", "-S", "--no-process-group", "-s", $env_vars->{SERVERCONFFILE}, @optargs) or die("Unable to start smbd: $!");
253         }
254         write_pid($env_vars, "smbd", $pid);
255         print "DONE\n";
256
257         return 0;
258 }
259
260 sub create_clientconf($$$)
261 {
262         my ($self, $prefix, $domain) = @_;
263
264         my $lockdir = "$prefix/locks";
265         my $logdir = "$prefix/logs";
266         my $piddir = "$prefix/pid";
267         my $privatedir = "$prefix/private";
268         my $conffile = "$prefix/smb.conf";
269
270         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';
271         open(CONF, ">$conffile");
272         print CONF "
273 [global]
274         workgroup = $domain
275
276         private dir = $privatedir
277         pid directory = $piddir
278         lock directory = $lockdir
279         log file = $logdir/log.\%m
280         log level = 0
281
282         name resolve order = bcast
283
284         netbios name = TORTURE_6
285         interfaces = $torture_interfaces
286         panic action = $RealBin/gdb_backtrace \%d %\$(MAKE_TEST_BINARY)
287
288         passdb backend = tdbsam
289         ";
290         close(CONF);
291 }
292
293 sub provision($$$$$$)
294 {
295         my ($self, $prefix, $server, $swiface, $password, $extra_options) = @_;
296
297         ##
298         ## setup the various environment variables we need
299         ##
300
301         my %ret = ();
302         my $server_ip = "127.0.0.$swiface";
303         my $domain = "SAMBA-TEST";
304
305         my $unix_name = ($ENV{USER} or $ENV{LOGNAME} or `PATH=/usr/ucb:$ENV{PATH} whoami`);
306         chomp $unix_name;
307         my $unix_uid = $>;
308         my $unix_gids_str = $);
309         my @unix_gids = split(" ", $unix_gids_str);
310
311         my $prefix_abs = abs_path($prefix);
312         my $bindir_abs = abs_path($self->{bindir});
313
314         my @dirs = ();
315
316         my $shrdir="$prefix_abs/share";
317         push(@dirs,$shrdir);
318
319         my $libdir="$prefix_abs/lib";
320         push(@dirs,$libdir);
321
322         my $piddir="$prefix_abs/pid";
323         push(@dirs,$piddir);
324
325         my $privatedir="$prefix_abs/private";
326         push(@dirs,$privatedir);
327
328         my $lockdir="$prefix_abs/lockdir";
329         push(@dirs,$lockdir);
330
331         my $logdir="$prefix_abs/logs";
332         push(@dirs,$logdir);
333
334         # this gets autocreated by winbindd
335         my $wbsockdir="$prefix_abs/winbindd";
336         my $wbsockprivdir="$lockdir/winbindd_privileged";
337
338         ## 
339         ## create the test directory layout
340         ##
341         mkdir($prefix_abs, 0777);
342         print "CREATE TEST ENVIRONMENT IN '$prefix'...";
343         system("rm -rf $prefix_abs/*");
344         mkdir($_, 0777) foreach(@dirs);
345
346         my $conffile="$libdir/server.conf";
347
348         my $nss_wrapper_pl = "$ENV{PERL} $RealBin/../lib/nss_wrapper/nss_wrapper.pl";
349         my $nss_wrapper_passwd = "$privatedir/passwd";
350         my $nss_wrapper_group = "$privatedir/group";
351
352         open(CONF, ">$conffile") or die("Unable to open $conffile");
353         print CONF "
354 [global]
355         netbios name = $server
356         interfaces = $server_ip/8
357         bind interfaces only = yes
358         panic action = $RealBin/gdb_backtrace %d %\$(MAKE_TEST_BINARY)
359
360         workgroup = $domain
361
362         private dir = $privatedir
363         pid directory = $piddir
364         lock directory = $lockdir
365         log file = $logdir/log.\%m
366         log level = 0
367
368         name resolve order = bcast
369
370         state directory = $lockdir
371         cache directory = $lockdir
372
373         passdb backend = tdbsam
374
375         time server = yes
376
377         add user script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action add --name %u
378         add machine script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action add --name %u
379         delete user script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action delete --name %u
380
381         kernel oplocks = no
382         kernel change notify = no
383
384         syslog = no
385         printing = bsd
386         printcap name = /dev/null
387
388         winbindd:socket dir = $wbsockdir
389         idmap uid = 100000-200000
390         idmap gid = 100000-200000
391
392 #       min receivefile size = 4000
393
394         read only = no
395         smbd:sharedelay = 100000
396         smbd:writetimeupdatedelay = 500000
397         map hidden = yes
398         map system = yes
399         create mask = 755
400         vfs objects = $bindir_abs/xattr_tdb.so $bindir_abs/streams_depot.so
401
402         # Begin extra options
403         $extra_options
404         # End extra options
405
406         #Include user defined custom parameters if set
407 ";
408
409         if (defined($ENV{INCLUDE_CUSTOM_CONF})) {
410                 print CONF "\t$ENV{INCLUDE_CUSTOM_CONF}\n";
411         }
412
413         print CONF "
414 [tmp]
415         path = $shrdir
416 [hideunread]
417         copy = tmp
418         hide unreadable = yes
419 [hideunwrite]
420         copy = tmp
421         hide unwriteable files = yes
422 [print1]
423         copy = tmp
424         printable = yes
425         printing = test
426 [print2]
427         copy = print1
428 [print3]
429         copy = print1
430 [print4]
431         copy = print1
432         ";
433         close(CONF);
434
435         ##
436         ## create a test account
437         ##
438
439         open(PASSWD, ">$nss_wrapper_passwd") or die("Unable to open $nss_wrapper_passwd");
440         print PASSWD "nobody:x:65534:65533:nobody gecos:$prefix_abs:/bin/false
441 $unix_name:x:$unix_uid:$unix_gids[0]:$unix_name gecos:$prefix_abs:/bin/false
442 ";
443         close(PASSWD);
444
445         open(GROUP, ">$nss_wrapper_group") or die("Unable to open $nss_wrapper_group");
446         print GROUP "nobody:x:65533:
447 nogroup:x:65534:nobody
448 $unix_name-group:x:$unix_gids[0]:
449 ";
450         close(GROUP);
451
452         $ENV{NSS_WRAPPER_PASSWD} = $nss_wrapper_passwd;
453         $ENV{NSS_WRAPPER_GROUP} = $nss_wrapper_group;
454
455         open(PWD, "|".$self->binpath("smbpasswd")." -c $conffile -L -s -a $unix_name >/dev/null");
456         print PWD "$password\n$password\n";
457         close(PWD) or die("Unable to set password for test account");
458
459         delete $ENV{NSS_WRAPPER_PASSWD};
460         delete $ENV{NSS_WRAPPER_GROUP};
461
462         print "DONE\n";
463
464         $ret{SERVER_IP} = $server_ip;
465         $ret{NMBD_TEST_LOG} = "$prefix/nmbd_test.log";
466         $ret{NMBD_TEST_LOG_POS} = 0;
467         $ret{WINBINDD_TEST_LOG} = "$prefix/winbindd_test.log";
468         $ret{WINBINDD_TEST_LOG_POS} = 0;
469         $ret{SMBD_TEST_LOG} = "$prefix/smbd_test.log";
470         $ret{SMBD_TEST_LOG_POS} = 0;
471         $ret{SERVERCONFFILE} = $conffile;
472         $ret{CONFIGURATION} ="-s $conffile";
473         $ret{SERVER} = $server;
474         $ret{USERNAME} = $unix_name;
475         $ret{DOMAIN} = $domain;
476         $ret{NETBIOSNAME} = $server;
477         $ret{PASSWORD} = $password;
478         $ret{PIDDIR} = $piddir;
479         $ret{WINBINDD_SOCKET_DIR} = $wbsockdir;
480         $ret{WINBINDD_PRIV_PIPE_DIR} = $wbsockprivdir;
481         $ret{SOCKET_WRAPPER_DEFAULT_IFACE} = $swiface;
482         $ret{NSS_WRAPPER_PASSWD} = $nss_wrapper_passwd;
483         $ret{NSS_WRAPPER_GROUP} = $nss_wrapper_group;
484
485         return \%ret;
486 }
487
488 sub wait_for_start($$)
489 {
490         my ($self, $envvars) = @_;
491
492         # give time for nbt server to register its names
493         print "delaying for nbt name registration\n";
494         sleep(10);
495         # This will return quickly when things are up, but be slow if we need to wait for (eg) SSL init 
496         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U $envvars->{SERVER_IP} __SAMBA__");
497         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} __SAMBA__");
498         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U 127.255.255.255 __SAMBA__");
499         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U $envvars->{SERVER_IP} $envvars->{SERVER}");
500         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} $envvars->{SERVER}");
501         # make sure smbd is also up set
502         print "wait for smbd\n";
503         system($self->binpath("smbclient") ." $envvars->{CONFIGURATION} -L $envvars->{SERVER_IP} -U% -p 139 | head -2");
504         system($self->binpath("smbclient") ." $envvars->{CONFIGURATION} -L $envvars->{SERVER_IP} -U% -p 139 | head -2");
505
506         print "creating BUILTIN\\Administrators\n";
507         $ENV{WINBINDD_SOCKET_DIR} = $envvars->{WINBINDD_SOCKET_DIR};
508         system($self->binpath("net") ." $envvars->{CONFIGURATION} sam createbuiltingroup Administrators");
509         delete $ENV{WINBINDD_SOCKET_DIR};
510
511         print $self->getlog_env($envvars);
512 }
513
514 1;