selftest: abstract Samba3 provision a bit
[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 $scriptdir = "$RealBin/..";
269         my $conffile = "$prefix/smb.conf";
270
271         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';
272         open(CONF, ">$conffile");
273         print CONF "
274 [global]
275         workgroup = $domain
276
277         private dir = $privatedir
278         pid directory = $piddir
279         lock directory = $lockdir
280         log file = $logdir/log.\%m
281         log level = 0
282
283         name resolve order = bcast
284
285         netbios name = TORTURE_6
286         interfaces = $torture_interfaces
287         panic action = $scriptdir/gdb_backtrace \%d %\$(MAKE_TEST_BINARY)
288
289         passdb backend = tdbsam
290         ";
291         close(CONF);
292 }
293
294 sub provision($$$$$$)
295 {
296         my ($self, $prefix, $server, $swiface, $password, $extra_options) = @_;
297
298         ##
299         ## setup the various environment variables we need
300         ##
301
302         my %ret = ();
303         my $server_ip = "127.0.0.$swiface";
304         my $domain = "SAMBA-TEST";
305
306         my $unix_name = ($ENV{USER} or $ENV{LOGNAME} or `PATH=/usr/ucb:$ENV{PATH} whoami`);
307         chomp $unix_name;
308         my $unix_uid = $>;
309         my $unix_gids_str = $);
310         my @unix_gids = split(" ", $unix_gids_str);
311         my $password = "test";
312
313         my $srcdir="$RealBin/..";
314         my $scriptdir="$srcdir/selftest";
315         my $prefix_abs = abs_path($prefix);
316         my $bindir_abs = abs_path($self->{bindir});
317
318         my @dirs = ();
319
320         my $shrdir="$prefix_abs/share";
321         push(@dirs,$shrdir);
322
323         my $libdir="$prefix_abs/lib";
324         push(@dirs,$libdir);
325
326         my $piddir="$prefix_abs/pid";
327         push(@dirs,$piddir);
328
329         my $privatedir="$prefix_abs/private";
330         push(@dirs,$privatedir);
331
332         my $lockdir="$prefix_abs/lockdir";
333         push(@dirs,$lockdir);
334
335         my $logdir="$prefix_abs/logs";
336         push(@dirs,$logdir);
337
338         # this gets autocreated by winbindd
339         my $wbsockdir="$prefix_abs/winbindd";
340         my $wbsockprivdir="$lockdir/winbindd_privileged";
341
342         ## 
343         ## create the test directory layout
344         ##
345         mkdir($prefix_abs, 0777);
346         print "CREATE TEST ENVIRONMENT IN '$prefix'...";
347         system("rm -rf $prefix_abs/*");
348         mkdir($_, 0777) foreach(@dirs);
349
350         my $conffile="$libdir/server.conf";
351
352         my $nss_wrapper_pl = "$ENV{PERL} $srcdir/../lib/nss_wrapper/nss_wrapper.pl";
353         my $nss_wrapper_passwd = "$privatedir/passwd";
354         my $nss_wrapper_group = "$privatedir/group";
355
356         open(CONF, ">$conffile") or die("Unable to open $conffile");
357         print CONF "
358 [global]
359         netbios name = $server
360         interfaces = $server_ip/8
361         bind interfaces only = yes
362         panic action = $scriptdir/gdb_backtrace %d %\$(MAKE_TEST_BINARY)
363
364         workgroup = $domain
365
366         private dir = $privatedir
367         pid directory = $piddir
368         lock directory = $lockdir
369         log file = $logdir/log.\%m
370         log level = 0
371
372         name resolve order = bcast
373
374         state directory = $lockdir
375         cache directory = $lockdir
376
377         passdb backend = tdbsam
378
379         time server = yes
380
381         add user script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action add --name %u
382         add machine script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action add --name %u
383         delete user script = $nss_wrapper_pl --path $nss_wrapper_passwd --type passwd --action delete --name %u
384
385         kernel oplocks = no
386         kernel change notify = no
387
388         syslog = no
389         printing = bsd
390         printcap name = /dev/null
391
392         winbindd:socket dir = $wbsockdir
393         idmap uid = 100000-200000
394         idmap gid = 100000-200000
395
396 #       min receivefile size = 4000
397
398         read only = no
399         smbd:sharedelay = 100000
400         smbd:writetimeupdatedelay = 500000
401         map hidden = yes
402         map system = yes
403         create mask = 755
404         vfs objects = $bindir_abs/xattr_tdb.so $bindir_abs/streams_depot.so
405
406         # Begin extra options
407         $extra_options
408         # End extra options
409
410         #Include user defined custom parameters if set
411         $ENV{INCLUDE_CUSTOM_CONF}
412
413 [tmp]
414         path = $shrdir
415 [hideunread]
416         copy = tmp
417         hide unreadable = yes
418 [hideunwrite]
419         copy = tmp
420         hide unwriteable files = yes
421 [print1]
422         copy = tmp
423         printable = yes
424         printing = test
425 [print2]
426         copy = print1
427 [print3]
428         copy = print1
429 [print4]
430         copy = print1
431         ";
432         close(CONF);
433
434         ##
435         ## create a test account
436         ##
437
438         open(PASSWD, ">$nss_wrapper_passwd") or die("Unable to open $nss_wrapper_passwd");
439         print PASSWD "
440 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 "
447 nobody:x:65533:
448 nogroup:x:65534:nobody
449 $unix_name-group:x:$unix_gids[0]:
450 ";
451         close(GROUP);
452
453         $ENV{NSS_WRAPPER_PASSWD} = $nss_wrapper_passwd;
454         $ENV{NSS_WRAPPER_GROUP} = $nss_wrapper_group;
455
456         open(PWD, "|".$self->binpath("smbpasswd")." -c $conffile -L -s -a $unix_name >/dev/null");
457         print PWD "$password\n$password\n";
458         close(PWD) or die("Unable to set password for test account");
459
460         $ENV{NSS_WRAPPER_PASSWD} = undef;
461         $ENV{NSS_WRAPPER_GROUP} = undef;
462
463         print "DONE\n";
464
465         $ret{SERVER_IP} = $server_ip;
466         $ret{NMBD_TEST_LOG} = "$prefix/nmbd_test.log";
467         $ret{WINBINDD_TEST_LOG} = "$prefix/winbindd_test.log";
468         $ret{SMBD_TEST_LOG} = "$prefix/smbd_test.log";
469         $ret{SERVERCONFFILE} = $conffile;
470         $ret{CONFIGURATION} ="-s $conffile";
471         $ret{SERVER} = $server;
472         $ret{USERNAME} = $unix_name;
473         $ret{DOMAIN} = $domain;
474         $ret{NETBIOSNAME} = $server;
475         $ret{PASSWORD} = $password;
476         $ret{PIDDIR} = $piddir;
477         $ret{WINBINDD_SOCKET_DIR} = $wbsockdir;
478         $ret{WINBINDD_PRIV_PIPE_DIR} = $wbsockprivdir;
479         $ret{SOCKET_WRAPPER_DEFAULT_IFACE} => $swiface,
480         $ret{NSS_WRAPPER_PASSWD} = $nss_wrapper_passwd;
481         $ret{NSS_WRAPPER_GROUP} = $nss_wrapper_group;
482
483         return \%ret;
484 }
485
486 sub wait_for_start($$)
487 {
488         my ($self, $envvars) = @_;
489
490         # give time for nbt server to register its names
491         print "delaying for nbt name registration\n";
492         sleep(10);
493         # This will return quickly when things are up, but be slow if we need to wait for (eg) SSL init 
494         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U $envvars->{SERVER_IP} __SAMBA__");
495         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} __SAMBA__");
496         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U 127.255.255.255 __SAMBA__");
497         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} -U $envvars->{SERVER_IP} $envvars->{SERVER}");
498         system($self->binpath("nmblookup") ." $envvars->{CONFIGURATION} $envvars->{SERVER}");
499         # make sure smbd is also up set
500         print "wait for smbd\n";
501         system($self->binpath("smbclient") ." $envvars->{CONFIGURATION} -L $envvars->{SERVER_IP} -U% -p 139 | head -2");
502         system($self->binpath("smbclient") ." $envvars->{CONFIGURATION} -L $envvars->{SERVER_IP} -U% -p 139 | head -2");
503
504         print "creating BUILTIN\\Administrators\n";
505         $ENV{WINBINDD_SOCKET_DIR} = $envvars->{WINBINDD_SOCKET_DIR};
506         system($self->binpath("net") ." $envvars->{CONFIGURATION} sam createbuiltingroup Administrators");
507         $ENV{WINBINDD_SOCKET_DIR} = undef;
508
509         print $self->getlog_env($envvars);
510 }
511
512 1;