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