e1bea16523b9031072176cd46820c011cb1ca838
[ira/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("KILL", $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                 if ($nmbd_maxtime eq "skip") {
230                         $SIG{USR1} = $SIG{ALRM} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
231                                 my $signame = shift;
232                                 print("Skip nmbd received signal $signame");
233                                 exit 0;
234                         };
235                         sleep(999999);
236                         exit 0;
237                 }
238
239                 my @optargs = ("-d0");
240                 if (defined($ENV{NMBD_OPTIONS})) {
241                         @optargs = split(/ /, $ENV{NMBD_OPTIONS});
242                 }
243
244                 $ENV{MAKE_TEST_BINARY} = $self->binpath("nmbd");
245
246                 my @preargs = ($self->binpath("timelimit"), $nmbd_maxtime);
247                 if(defined($ENV{NMBD_VALGRIND})) { 
248                         @preargs = split(/ /, $ENV{NMBD_VALGRIND});
249                 }
250
251                 exec(@preargs, $self->binpath("nmbd"), "-F", "-S", "--no-process-group", "-s", $env_vars->{SERVERCONFFILE}, @optargs) or die("Unable to start nmbd: $!");
252         }
253         write_pid($env_vars, "nmbd", $pid);
254         print "DONE\n";
255
256         unlink($env_vars->{WINBINDD_TEST_LOG});
257         print "STARTING WINBINDD...";
258         $pid = fork();
259         if ($pid == 0) {
260                 open STDOUT, ">$env_vars->{WINBINDD_TEST_LOG}";
261                 open STDERR, '>&STDOUT';
262
263                 SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
264
265                 $ENV{WINBINDD_SOCKET_DIR} = $env_vars->{WINBINDD_SOCKET_DIR};
266
267                 $ENV{NSS_WRAPPER_PASSWD} = $env_vars->{NSS_WRAPPER_PASSWD};
268                 $ENV{NSS_WRAPPER_GROUP} = $env_vars->{NSS_WRAPPER_GROUP};
269
270                 if ($winbindd_maxtime eq "skip") {
271                         $SIG{USR1} = $SIG{ALRM} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
272                                 my $signame = shift;
273                                 print("Skip winbindd received signal $signame");
274                                 exit 0;
275                         };
276                         sleep(999999);
277                         exit 0;
278                 }
279
280                 my @optargs = ("-d0");
281                 if (defined($ENV{WINBINDD_OPTIONS})) {
282                         @optargs = split(/ /, $ENV{WINBINDD_OPTIONS});
283                 }
284
285                 $ENV{MAKE_TEST_BINARY} = $self->binpath("winbindd");
286
287                 my @preargs = ($self->binpath("timelimit"), $winbindd_maxtime);
288                 if(defined($ENV{WINBINDD_VALGRIND})) {
289                         @preargs = split(/ /, $ENV{WINBINDD_VALGRIND});
290                 }
291
292                 exec(@preargs, $self->binpath("winbindd"), "-F", "-S", "--no-process-group", "-s", $env_vars->{SERVERCONFFILE}, @optargs) or die("Unable to start winbindd: $!");
293         }
294         write_pid($env_vars, "winbindd", $pid);
295         print "DONE\n";
296
297         unlink($env_vars->{SMBD_TEST_LOG});
298         print "STARTING SMBD...";
299         $pid = fork();
300         if ($pid == 0) {
301                 open STDOUT, ">$env_vars->{SMBD_TEST_LOG}";
302                 open STDERR, '>&STDOUT';
303
304                 SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
305
306                 $ENV{WINBINDD_SOCKET_DIR} = $env_vars->{WINBINDD_SOCKET_DIR};
307
308                 $ENV{NSS_WRAPPER_PASSWD} = $env_vars->{NSS_WRAPPER_PASSWD};
309                 $ENV{NSS_WRAPPER_GROUP} = $env_vars->{NSS_WRAPPER_GROUP};
310
311                 if ($smbd_maxtime eq "skip") {
312                         $SIG{USR1} = $SIG{ALRM} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
313                                 my $signame = shift;
314                                 print("Skip smbd received signal $signame");
315                                 exit 0;
316                         };
317                         sleep(999999);
318                         exit 0;
319                 }
320
321                 $ENV{MAKE_TEST_BINARY} = $self->binpath("smbd");
322                 my @optargs = ("-d0");
323                 if (defined($ENV{SMBD_OPTIONS})) {
324                         @optargs = split(/ /, $ENV{SMBD_OPTIONS});
325                 }
326                 my @preargs = ($self->binpath("timelimit"), $smbd_maxtime);
327                 if(defined($ENV{SMBD_VALGRIND})) {
328                         @preargs = split(/ /,$ENV{SMBD_VALGRIND});
329                 }
330                 exec(@preargs, $self->binpath("smbd"), "-F", "-S", "--no-process-group", "-s", $env_vars->{SERVERCONFFILE}, @optargs) or die("Unable to start smbd: $!");
331         }
332         write_pid($env_vars, "smbd", $pid);
333         print "DONE\n";
334
335         return 0;
336 }
337
338 sub create_clientconf($$$)
339 {
340         my ($self, $prefix, $domain) = @_;
341
342         my $lockdir = "$prefix/locks";
343         my $logdir = "$prefix/logs";
344         my $piddir = "$prefix/pid";
345         my $privatedir = "$prefix/private";
346         my $conffile = "$prefix/smb.conf";
347
348         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';
349         open(CONF, ">$conffile");
350         print CONF "
351 [global]
352         workgroup = $domain
353
354         private dir = $privatedir
355         pid directory = $piddir
356         lock directory = $lockdir
357         log file = $logdir/log.\%m
358         log level = 0
359
360         name resolve order = bcast
361
362         netbios name = TORTURE_6
363         interfaces = $torture_interfaces
364         panic action = $RealBin/gdb_backtrace \%d %\$(MAKE_TEST_BINARY)
365
366         passdb backend = tdbsam
367         ";
368         close(CONF);
369 }
370
371 sub provision($$$$$$)
372 {
373         my ($self, $prefix, $server, $swiface, $password, $extra_options) = @_;
374
375         ##
376         ## setup the various environment variables we need
377         ##
378
379         my %ret = ();
380         my $server_ip = "127.0.0.$swiface";
381         my $domain = "SAMBA-TEST";
382
383         my $unix_name = ($ENV{USER} or $ENV{LOGNAME} or `PATH=/usr/ucb:$ENV{PATH} whoami`);
384         chomp $unix_name;
385         my $unix_uid = $>;
386         my $unix_gids_str = $);
387         my @unix_gids = split(" ", $unix_gids_str);
388
389         my $prefix_abs = abs_path($prefix);
390         my $bindir_abs = abs_path($self->{bindir});
391
392         my @dirs = ();
393
394         my $shrdir="$prefix_abs/share";
395         push(@dirs,$shrdir);
396
397         my $libdir="$prefix_abs/lib";
398         push(@dirs,$libdir);
399
400         my $piddir="$prefix_abs/pid";
401         push(@dirs,$piddir);
402
403         my $privatedir="$prefix_abs/private";
404         push(@dirs,$privatedir);
405
406         my $lockdir="$prefix_abs/lockdir";
407         push(@dirs,$lockdir);
408
409         my $logdir="$prefix_abs/logs";
410         push(@dirs,$logdir);
411
412         # this gets autocreated by winbindd
413         my $wbsockdir="$prefix_abs/winbindd";
414         my $wbsockprivdir="$lockdir/winbindd_privileged";
415
416         ## 
417         ## create the test directory layout
418         ##
419         die ("prefix_abs = ''") if $prefix_abs eq "";
420         die ("prefix_abs = '/'") if $prefix_abs eq "/";
421
422         mkdir($prefix_abs, 0777);
423         print "CREATE TEST ENVIRONMENT IN '$prefix'...";
424         system("rm -rf $prefix_abs/*");
425         mkdir($_, 0777) foreach(@dirs);
426
427         my $conffile="$libdir/server.conf";
428
429         my $nss_wrapper_pl = "$ENV{PERL} $RealBin/../lib/nss_wrapper/nss_wrapper.pl";
430         my $nss_wrapper_passwd = "$privatedir/passwd";
431         my $nss_wrapper_group = "$privatedir/group";
432
433         open(CONF, ">$conffile") or die("Unable to open $conffile");
434         print CONF "
435 [global]
436         netbios name = $server
437         interfaces = $server_ip/8
438         bind interfaces only = yes
439         panic action = $RealBin/gdb_backtrace %d %\$(MAKE_TEST_BINARY)
440
441         workgroup = $domain
442
443         private dir = $privatedir
444         pid directory = $piddir
445         lock directory = $lockdir
446         log file = $logdir/log.\%m
447         log level = 0
448
449         name resolve order = bcast
450
451         state directory = $lockdir
452         cache directory = $lockdir
453
454         passdb backend = tdbsam
455
456         time server = yes
457
458         add user script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action add --name %u
459         add machine script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action add --name %u
460         delete user script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action delete --name %u
461
462         kernel oplocks = no
463         kernel change notify = no
464
465         syslog = no
466         printing = bsd
467         printcap name = /dev/null
468
469         winbindd:socket dir = $wbsockdir
470         idmap uid = 100000-200000
471         idmap gid = 100000-200000
472
473 #       min receivefile size = 4000
474
475         read only = no
476         smbd:sharedelay = 100000
477         smbd:writetimeupdatedelay = 500000
478         map hidden = yes
479         map system = yes
480         create mask = 755
481         vfs objects = $bindir_abs/xattr_tdb.so $bindir_abs/streams_depot.so
482
483         # Begin extra options
484         $extra_options
485         # End extra options
486
487         #Include user defined custom parameters if set
488 ";
489
490         if (defined($ENV{INCLUDE_CUSTOM_CONF})) {
491                 print CONF "\t$ENV{INCLUDE_CUSTOM_CONF}\n";
492         }
493
494         print CONF "
495 [tmp]
496         path = $shrdir
497 [hideunread]
498         copy = tmp
499         hide unreadable = yes
500 [hideunwrite]
501         copy = tmp
502         hide unwriteable files = yes
503 [print1]
504         copy = tmp
505         printable = yes
506         printing = test
507 [print2]
508         copy = print1
509 [print3]
510         copy = print1
511 [print4]
512         copy = print1
513         ";
514         close(CONF);
515
516         ##
517         ## create a test account
518         ##
519
520         open(PASSWD, ">$nss_wrapper_passwd") or die("Unable to open $nss_wrapper_passwd");
521         print PASSWD "nobody:x:65534:65533:nobody gecos:$prefix_abs:/bin/false
522 $unix_name:x:$unix_uid:$unix_gids[0]:$unix_name gecos:$prefix_abs:/bin/false
523 ";
524         close(PASSWD);
525
526         open(GROUP, ">$nss_wrapper_group") or die("Unable to open $nss_wrapper_group");
527         print GROUP "nobody:x:65533:
528 nogroup:x:65534:nobody
529 $unix_name-group:x:$unix_gids[0]:
530 ";
531         close(GROUP);
532
533         $ENV{NSS_WRAPPER_PASSWD} = $nss_wrapper_passwd;
534         $ENV{NSS_WRAPPER_GROUP} = $nss_wrapper_group;
535
536         open(PWD, "|".$self->binpath("smbpasswd")." -c $conffile -L -s -a $unix_name >/dev/null");
537         print PWD "$password\n$password\n";
538         close(PWD) or die("Unable to set password for test account");
539
540         delete $ENV{NSS_WRAPPER_PASSWD};
541         delete $ENV{NSS_WRAPPER_GROUP};
542
543         print "DONE\n";
544
545         $ret{SERVER_IP} = $server_ip;
546         $ret{NMBD_TEST_LOG} = "$prefix/nmbd_test.log";
547         $ret{NMBD_TEST_LOG_POS} = 0;
548         $ret{WINBINDD_TEST_LOG} = "$prefix/winbindd_test.log";
549         $ret{WINBINDD_TEST_LOG_POS} = 0;
550         $ret{SMBD_TEST_LOG} = "$prefix/smbd_test.log";
551         $ret{SMBD_TEST_LOG_POS} = 0;
552         $ret{SERVERCONFFILE} = $conffile;
553         $ret{CONFIGURATION} ="-s $conffile";
554         $ret{SERVER} = $server;
555         $ret{USERNAME} = $unix_name;
556         $ret{DOMAIN} = $domain;
557         $ret{NETBIOSNAME} = $server;
558         $ret{PASSWORD} = $password;
559         $ret{PIDDIR} = $piddir;
560         $ret{WINBINDD_SOCKET_DIR} = $wbsockdir;
561         $ret{WINBINDD_PRIV_PIPE_DIR} = $wbsockprivdir;
562         $ret{SOCKET_WRAPPER_DEFAULT_IFACE} = $swiface;
563         $ret{NSS_WRAPPER_PASSWD} = $nss_wrapper_passwd;
564         $ret{NSS_WRAPPER_GROUP} = $nss_wrapper_group;
565
566         return \%ret;
567 }
568
569 sub wait_for_start($$)
570 {
571         my ($self, $envvars) = @_;
572
573         # give time for nbt server to register its names
574         print "delaying for nbt name registration\n";
575         sleep(10);
576         # This will return quickly when things are up, but be slow if we need to wait for (eg) SSL init 
577         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U $envvars->{SERVER_IP} __SAMBA__");
578         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} __SAMBA__");
579         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U 127.255.255.255 __SAMBA__");
580         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U $envvars->{SERVER_IP} $envvars->{SERVER}");
581         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} $envvars->{SERVER}");
582         # make sure smbd is also up set
583         print "wait for smbd\n";
584         system($self->binpath("smbclient") ." $envvars->{CONFIGURATION} -L $envvars->{SERVER_IP} -U% -p 139 | head -2");
585         system($self->binpath("smbclient") ." $envvars->{CONFIGURATION} -L $envvars->{SERVER_IP} -U% -p 139 | head -2");
586
587         print $self->getlog_env($envvars);
588 }
589
590 1;