1package ProFTPD::Tests::Modules::mod_ban; 2 3use lib qw(t/lib); 4use base qw(ProFTPD::TestSuite::Child); 5use strict; 6 7use Carp; 8use File::Spec; 9use IO::Handle; 10 11use ProFTPD::TestSuite::FTP; 12use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite); 13 14$| = 1; 15 16my $order = 0; 17 18my $TESTS = { 19 ban_on_event_max_login_attempts => { 20 order => ++$order, 21 test_class => [qw(forking)], 22 }, 23 24 ban_message => { 25 order => ++$order, 26 test_class => [qw(forking)], 27 }, 28 29 ban_ifclass_engine_on => { 30 order => ++$order, 31 test_class => [qw(forking mod_ifsession)], 32 }, 33 34 ban_ifclass_engine_off => { 35 order => ++$order, 36 test_class => [qw(forking mod_ifsession)], 37 }, 38 39 ban_max_logins_exceeded_bug3281 => { 40 order => ++$order, 41 test_class => [qw(bug forking)], 42 }, 43 44 ban_timeout_login_exceeded_bug3281 => { 45 order => ++$order, 46 test_class => [qw(bug forking)], 47 }, 48 49 ban_engine_vhost_bug3355 => { 50 order => ++$order, 51 test_class => [qw(bug forking)], 52 }, 53 54 ban_unhandled_cmd => { 55 order => ++$order, 56 test_class => [qw(forking)], 57 }, 58 59 ban_on_event_client_connect_rate => { 60 order => ++$order, 61 test_class => [qw(forking)], 62 }, 63 64 ban_sighup_bug3751 => { 65 order => ++$order, 66 test_class => [qw(bug forking os_linux)], 67 }, 68 69 ban_on_event_tlshandshake => { 70 order => ++$order, 71 test_class => [qw(forking mod_tls)], 72 }, 73 74 ban_on_event_rootlogin => { 75 order => ++$order, 76 test_class => [qw(forking)], 77 }, 78 79 ban_on_event_rootlogin_userdefined => { 80 order => ++$order, 81 test_class => [qw(forking)], 82 }, 83 84 ban_opt_any_server_issue1010 => { 85 order => ++$order, 86 test_class => [qw(forking)], 87 }, 88 89}; 90 91sub new { 92 return shift()->SUPER::new(@_); 93} 94 95sub list_tests { 96 return testsuite_get_runnable_tests($TESTS); 97} 98 99sub get_server_pid { 100 my $pid_file = shift; 101 102 my $pid; 103 if (open(my $fh, "< $pid_file")) { 104 $pid = <$fh>; 105 chomp($pid); 106 close($fh); 107 108 } else { 109 croak("Can't read $pid_file: $!"); 110 } 111 112 return $pid; 113} 114 115sub server_open_fds { 116 my $pid_file = shift; 117 118 my $pid = get_server_pid($pid_file); 119 120 my $proc_dir = "/proc/$pid/fd"; 121 if (opendir(my $dirh, $proc_dir)) { 122 my $count = 0; 123 124 # Only count entries whose names are numbers 125 while (my $dent = readdir($dirh)) { 126 if ($dent =~ /^\d+$/) { 127 $count++; 128 } 129 } 130 131 closedir($dirh); 132 return $count; 133 134 } else { 135 croak("Can't open directory '$proc_dir': $!"); 136 } 137} 138 139sub ban_on_event_max_login_attempts { 140 my $self = shift; 141 my $tmpdir = $self->{tmpdir}; 142 143 my $config_file = "$tmpdir/ban.conf"; 144 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 145 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 146 147 my $log_file = test_get_logfile(); 148 149 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 150 151 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 152 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 153 154 my $user = 'proftpd'; 155 my $passwd = 'test'; 156 my $group = 'ftpd'; 157 my $home_dir = File::Spec->rel2abs($tmpdir); 158 my $uid = 500; 159 my $gid = 500; 160 161 # Make sure that, if we're running as root, that the home directory has 162 # permissions/privs set for the account we create 163 if ($< == 0) { 164 unless (chmod(0755, $home_dir)) { 165 die("Can't set perms on $home_dir to 0755: $!"); 166 } 167 168 unless (chown($uid, $gid, $home_dir)) { 169 die("Can't set owner of $home_dir to $uid/$gid: $!"); 170 } 171 } 172 173 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 174 '/bin/bash'); 175 auth_group_write($auth_group_file, $group, $gid, $user); 176 177 my $config = { 178 PidFile => $pid_file, 179 ScoreboardFile => $scoreboard_file, 180 SystemLog => $log_file, 181 TraceLog => $log_file, 182 Trace => 'event:10', 183 184 AuthUserFile => $auth_user_file, 185 AuthGroupFile => $auth_group_file, 186 187 MaxLoginAttempts => 2, 188 189 IfModules => { 190 'mod_ban.c' => { 191 BanEngine => 'on', 192 BanLog => $log_file, 193 194 # This says to ban a client which exceeds the MaxLoginAttempts 195 # limit once within the last 1 minute will be banned for 5 secs 196 BanOnEvent => 'MaxLoginAttempts 1/00:01:00 00:00:05', 197 198 BanTable => $ban_tab, 199 }, 200 201 'mod_delay.c' => { 202 DelayEngine => 'off', 203 }, 204 }, 205 }; 206 207 my ($port, $config_user, $config_group) = config_write($config_file, $config); 208 209 # Open pipes, for use between the parent and child processes. Specifically, 210 # the child will indicate when it's done with its test by writing a message 211 # to the parent. 212 my ($rfh, $wfh); 213 unless (pipe($rfh, $wfh)) { 214 die("Can't open pipe: $!"); 215 } 216 217 my $ex; 218 219 # Fork child 220 $self->handle_sigchld(); 221 defined(my $pid = fork()) or die("Can't fork: $!"); 222 if ($pid) { 223 eval { 224 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 225 226 eval { $client->login($user, 'foo') }; 227 unless ($@) { 228 die("Login succeeded unexpectedly"); 229 } 230 231 my $resp_code = $client->response_code(); 232 my $resp_msg = $client->response_msg(); 233 234 my $expected; 235 236 $expected = 530; 237 $self->assert($expected == $resp_code, 238 test_msg("Expected $expected, got $resp_code")); 239 240 $expected = "Login incorrect."; 241 $self->assert($expected eq $resp_msg, 242 test_msg("Expected '$expected', got '$resp_msg'")); 243 244 eval { $client->login($user, 'foo') }; 245 unless ($@) { 246 die("Login succeeded unexpectedly"); 247 } 248 249 $resp_code = $client->response_code(); 250 $resp_msg = $client->response_msg(); 251 252 $expected = 530; 253 $self->assert($expected == $resp_code, 254 test_msg("Expected $expected, got $resp_code")); 255 256 $expected = "Login incorrect."; 257 $self->assert($expected eq $resp_msg, 258 test_msg("Expected '$expected', got '$resp_msg'")); 259 260 # Now try again with the correct info; we should be banned. Note 261 # that we have to create a separate connection for this. 262 263 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 264 undef, 0) }; 265 unless ($@) { 266 die("Connect succeeded unexpectedly"); 267 } 268 269 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 270 271 $expected = ""; 272 $self->assert($expected eq $conn_ex, 273 test_msg("Expected '$expected', got '$conn_ex'")); 274 }; 275 276 if ($@) { 277 $ex = $@; 278 } 279 280 $wfh->print("done\n"); 281 $wfh->flush(); 282 283 } else { 284 eval { server_wait($config_file, $rfh) }; 285 if ($@) { 286 warn($@); 287 exit 1; 288 } 289 290 exit 0; 291 } 292 293 # Stop server 294 server_stop($pid_file); 295 296 $self->assert_child_ok($pid); 297 298 if ($ex) { 299 test_append_logfile($log_file, $ex); 300 unlink($log_file); 301 302 die($ex); 303 } 304 305 unlink($log_file); 306} 307 308sub ban_message { 309 my $self = shift; 310 my $tmpdir = $self->{tmpdir}; 311 312 my $config_file = "$tmpdir/ban.conf"; 313 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 314 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 315 316 my $log_file = test_get_logfile(); 317 318 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 319 320 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 321 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 322 323 my $user = 'proftpd'; 324 my $passwd = 'test'; 325 my $group = 'ftpd'; 326 my $home_dir = File::Spec->rel2abs($tmpdir); 327 my $uid = 500; 328 my $gid = 500; 329 330 # Make sure that, if we're running as root, that the home directory has 331 # permissions/privs set for the account we create 332 if ($< == 0) { 333 unless (chmod(0755, $home_dir)) { 334 die("Can't set perms on $home_dir to 0755: $!"); 335 } 336 337 unless (chown($uid, $gid, $home_dir)) { 338 die("Can't set owner of $home_dir to $uid/$gid: $!"); 339 } 340 } 341 342 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 343 '/bin/bash'); 344 auth_group_write($auth_group_file, $group, $gid, $user); 345 346 my $config = { 347 PidFile => $pid_file, 348 ScoreboardFile => $scoreboard_file, 349 SystemLog => $log_file, 350 351 AuthUserFile => $auth_user_file, 352 AuthGroupFile => $auth_group_file, 353 354 MaxLoginAttempts => 2, 355 356 IfModules => { 357 'mod_ban.c' => { 358 BanEngine => 'on', 359 BanLog => $log_file, 360 361 # This says to ban a client which exceeds the MaxLoginAttempts 362 # limit once within the last 1 minute will be banned for 5 secs 363 BanOnEvent => 'MaxLoginAttempts 1/00:01:00 00:00:05', 364 365 BanTable => $ban_tab, 366 367 BanMessage => '"Go away %a (%c), or I shall taunt you (%u) a second time!"', 368 }, 369 370 'mod_delay.c' => { 371 DelayEngine => 'off', 372 }, 373 }, 374 }; 375 376 my ($port, $config_user, $config_group) = config_write($config_file, $config); 377 378 # Open pipes, for use between the parent and child processes. Specifically, 379 # the child will indicate when it's done with its test by writing a message 380 # to the parent. 381 my ($rfh, $wfh); 382 unless (pipe($rfh, $wfh)) { 383 die("Can't open pipe: $!"); 384 } 385 386 my $ex; 387 388 # Fork child 389 $self->handle_sigchld(); 390 defined(my $pid = fork()) or die("Can't fork: $!"); 391 if ($pid) { 392 eval { 393 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 394 395 eval { $client->login($user, 'foo') }; 396 unless ($@) { 397 die("Login succeeded unexpectedly"); 398 } 399 400 my $resp_code = $client->response_code(); 401 my $resp_msg = $client->response_msg(); 402 403 my $expected; 404 405 $expected = 530; 406 $self->assert($expected == $resp_code, 407 test_msg("Expected $expected, got $resp_code")); 408 409 $expected = "Login incorrect."; 410 $self->assert($expected eq $resp_msg, 411 test_msg("Expected '$expected', got '$resp_msg'")); 412 413 eval { $client->login($user, 'foo') }; 414 unless ($@) { 415 die("Login succeeded unexpectedly"); 416 } 417 418 $resp_code = $client->response_code(); 419 $resp_msg = $client->response_msg(); 420 421 $expected = 530; 422 $self->assert($expected == $resp_code, 423 test_msg("Expected $expected, got $resp_code")); 424 425 $expected = "Login incorrect."; 426 $self->assert($expected eq $resp_msg, 427 test_msg("Expected '$expected', got '$resp_msg'")); 428 429 # Now try again with the correct info; we should be banned. 430 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 431 undef, 0) }; 432 unless ($@) { 433 die("Connect succeeded unexpectedly"); 434 } 435 436 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 437 438 $expected = "Go away 127.0.0.1 ((none)), or I shall taunt you ((none)) a second time!"; 439 $self->assert($expected eq $conn_ex, 440 test_msg("Expected '$expected', got '$conn_ex'")); 441 }; 442 443 if ($@) { 444 $ex = $@; 445 } 446 447 $wfh->print("done\n"); 448 $wfh->flush(); 449 450 } else { 451 eval { server_wait($config_file, $rfh) }; 452 if ($@) { 453 warn($@); 454 exit 1; 455 } 456 457 exit 0; 458 } 459 460 # Stop server 461 server_stop($pid_file); 462 463 $self->assert_child_ok($pid); 464 465 if ($ex) { 466 test_append_logfile($log_file, $ex); 467 unlink($log_file); 468 469 die($ex); 470 } 471 472 unlink($log_file); 473} 474 475sub ban_ifclass_engine_on { 476 my $self = shift; 477 my $tmpdir = $self->{tmpdir}; 478 479 my $config_file = "$tmpdir/ban.conf"; 480 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 481 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 482 483 my $log_file = test_get_logfile(); 484 485 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 486 487 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 488 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 489 490 my $user = 'proftpd'; 491 my $passwd = 'test'; 492 my $group = 'ftpd'; 493 my $home_dir = File::Spec->rel2abs($tmpdir); 494 my $uid = 500; 495 my $gid = 500; 496 497 # Make sure that, if we're running as root, that the home directory has 498 # permissions/privs set for the account we create 499 if ($< == 0) { 500 unless (chmod(0755, $home_dir)) { 501 die("Can't set perms on $home_dir to 0755: $!"); 502 } 503 504 unless (chown($uid, $gid, $home_dir)) { 505 die("Can't set owner of $home_dir to $uid/$gid: $!"); 506 } 507 } 508 509 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 510 '/bin/bash'); 511 auth_group_write($auth_group_file, $group, $gid, $user); 512 513 my $config = { 514 PidFile => $pid_file, 515 ScoreboardFile => $scoreboard_file, 516 SystemLog => $log_file, 517 518 AuthUserFile => $auth_user_file, 519 AuthGroupFile => $auth_group_file, 520 521 MaxLoginAttempts => 2, 522 523 Class => { 524 test => { 525 From => '127.0.0.1', 526 }, 527 }, 528 529 IfModules => { 530 'mod_ban.c' => { 531 BanLog => $log_file, 532 533 # This says to ban a client which exceeds the MaxLoginAttempts 534 # limit once within the last 1 minute will be banned for 5 secs 535 BanOnEvent => 'MaxLoginAttempts 1/00:01:00 00:00:05', 536 537 BanTable => $ban_tab, 538 }, 539 540 'mod_delay.c' => { 541 DelayEngine => 'off', 542 }, 543 }, 544 }; 545 546 my ($port, $config_user, $config_group) = config_write($config_file, $config); 547 548 if (open(my $fh, ">> $config_file")) { 549 print $fh <<EOI; 550<IfClass test> 551 BanEngine on 552</IfClass> 553EOI 554 unless (close($fh)) { 555 die("Can't write $config_file: $!"); 556 } 557 558 } else { 559 die("Can't open $config_file: $!"); 560 } 561 562 # Open pipes, for use between the parent and child processes. Specifically, 563 # the child will indicate when it's done with its test by writing a message 564 # to the parent. 565 my ($rfh, $wfh); 566 unless (pipe($rfh, $wfh)) { 567 die("Can't open pipe: $!"); 568 } 569 570 my $ex; 571 572 # Fork child 573 $self->handle_sigchld(); 574 defined(my $pid = fork()) or die("Can't fork: $!"); 575 if ($pid) { 576 eval { 577 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 578 579 my ($resp_code, $resp_msg); 580 581 eval { $client->login($user, 'foo') }; 582 unless ($@) { 583 die("Login succeeded unexpectedly"); 584 585 } else { 586 $resp_code = $client->response_code(); 587 $resp_msg = $client->response_msg(); 588 } 589 590 my $expected; 591 592 $expected = 530; 593 $self->assert($expected == $resp_code, 594 test_msg("Expected $expected, got $resp_code")); 595 596 $expected = "Login incorrect."; 597 $self->assert($expected eq $resp_msg, 598 test_msg("Expected '$expected', got '$resp_msg'")); 599 600 eval { $client->login($user, 'foo') }; 601 unless ($@) { 602 die("Login succeeded unexpectedly"); 603 604 } else { 605 $resp_code = $client->response_code(); 606 $resp_msg = $client->response_msg(); 607 } 608 609 $expected = 530; 610 $self->assert($expected == $resp_code, 611 test_msg("Expected $expected, got $resp_code")); 612 613 $expected = "Login incorrect."; 614 $self->assert($expected eq $resp_msg, 615 test_msg("Expected '$expected', got '$resp_msg'")); 616 617 # Now try again with the correct info; we should be banned. Note 618 # that we have to create a separate connection for this. 619 620 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 621 undef, 0) }; 622 unless ($@) { 623 die("Connect succeeded unexpectedly"); 624 } 625 626 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 627 628 $expected = ""; 629 $self->assert($expected eq $conn_ex, 630 test_msg("Expected '$expected', got '$conn_ex'")); 631 }; 632 633 if ($@) { 634 $ex = $@; 635 } 636 637 $wfh->print("done\n"); 638 $wfh->flush(); 639 640 } else { 641 eval { server_wait($config_file, $rfh) }; 642 if ($@) { 643 warn($@); 644 exit 1; 645 } 646 647 exit 0; 648 } 649 650 # Stop server 651 server_stop($pid_file); 652 653 $self->assert_child_ok($pid); 654 655 if ($ex) { 656 test_append_logfile($log_file, $ex); 657 unlink($log_file); 658 659 die($ex); 660 } 661 662 unlink($log_file); 663} 664 665sub ban_ifclass_engine_off { 666 my $self = shift; 667 my $tmpdir = $self->{tmpdir}; 668 669 my $config_file = "$tmpdir/ban.conf"; 670 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 671 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 672 673 my $log_file = test_get_logfile(); 674 675 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 676 677 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 678 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 679 680 my $user = 'proftpd'; 681 my $passwd = 'test'; 682 my $group = 'ftpd'; 683 my $home_dir = File::Spec->rel2abs($tmpdir); 684 my $uid = 500; 685 my $gid = 500; 686 687 # Make sure that, if we're running as root, that the home directory has 688 # permissions/privs set for the account we create 689 if ($< == 0) { 690 unless (chmod(0755, $home_dir)) { 691 die("Can't set perms on $home_dir to 0755: $!"); 692 } 693 694 unless (chown($uid, $gid, $home_dir)) { 695 die("Can't set owner of $home_dir to $uid/$gid: $!"); 696 } 697 } 698 699 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 700 '/bin/bash'); 701 auth_group_write($auth_group_file, $group, $gid, $user); 702 703 my $config = { 704 PidFile => $pid_file, 705 ScoreboardFile => $scoreboard_file, 706 SystemLog => $log_file, 707 708 AuthUserFile => $auth_user_file, 709 AuthGroupFile => $auth_group_file, 710 711 MaxLoginAttempts => 1, 712 713 Class => { 714 test => { 715 From => '127.0.0.1', 716 }, 717 }, 718 719 IfModules => { 720 'mod_ban.c' => { 721 BanEngine => 'on', 722 BanLog => $log_file, 723 724 # This says to ban a client which exceeds the MaxLoginAttempts 725 # limit once within the last 1 minute will be banned for 5 secs 726 BanOnEvent => 'MaxLoginAttempts 1/00:01:00 00:00:05', 727 728 BanTable => $ban_tab, 729 }, 730 731 'mod_delay.c' => { 732 DelayEngine => 'off', 733 }, 734 }, 735 }; 736 737 my ($port, $config_user, $config_group) = config_write($config_file, $config); 738 739 if (open(my $fh, ">> $config_file")) { 740 print $fh <<EOI; 741<IfClass test> 742 BanEngine off 743</IfClass> 744EOI 745 unless (close($fh)) { 746 die("Can't write $config_file: $!"); 747 } 748 749 } else { 750 die("Can't open $config_file: $!"); 751 } 752 753 # Open pipes, for use between the parent and child processes. Specifically, 754 # the child will indicate when it's done with its test by writing a message 755 # to the parent. 756 my ($rfh, $wfh); 757 unless (pipe($rfh, $wfh)) { 758 die("Can't open pipe: $!"); 759 } 760 761 my $ex; 762 763 # Fork child 764 $self->handle_sigchld(); 765 defined(my $pid = fork()) or die("Can't fork: $!"); 766 if ($pid) { 767 eval { 768 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 769 770 my ($resp_code, $resp_msg); 771 772 eval { $client->login($user, 'foo') }; 773 unless ($@) { 774 die("Login succeeded unexpectedly"); 775 776 } else { 777 $resp_code = $client->response_code(); 778 $resp_msg = $client->response_msg(); 779 } 780 781 my $expected; 782 783 $expected = 530; 784 $self->assert($expected == $resp_code, 785 test_msg("Expected $expected, got $resp_code")); 786 787 $expected = "Login incorrect."; 788 $self->assert($expected eq $resp_msg, 789 test_msg("Expected '$expected', got '$resp_msg'")); 790 791 # Now try again with the correct info; we should NOT be banned. Note 792 # that we have to create a separate connection for this. 793 794 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 795 undef, 0) }; 796 if ($@) { 797 die("Connect failed unexpectedly"); 798 } 799 }; 800 801 if ($@) { 802 $ex = $@; 803 } 804 805 $wfh->print("done\n"); 806 $wfh->flush(); 807 808 } else { 809 eval { server_wait($config_file, $rfh) }; 810 if ($@) { 811 warn($@); 812 exit 1; 813 } 814 815 exit 0; 816 } 817 818 # Stop server 819 server_stop($pid_file); 820 821 $self->assert_child_ok($pid); 822 823 if ($ex) { 824 test_append_logfile($log_file, $ex); 825 unlink($log_file); 826 827 die($ex); 828 } 829 830 unlink($log_file); 831} 832 833sub ban_max_logins_exceeded_bug3281 { 834 my $self = shift; 835 my $tmpdir = $self->{tmpdir}; 836 837 my $config_file = "$tmpdir/ban.conf"; 838 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 839 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 840 841 my $log_file = test_get_logfile(); 842 843 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 844 845 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 846 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 847 848 my $user = 'proftpd'; 849 my $passwd = 'test'; 850 my $group = 'ftpd'; 851 my $home_dir = File::Spec->rel2abs($tmpdir); 852 my $uid = 500; 853 my $gid = 500; 854 855 # Make sure that, if we're running as root, that the home directory has 856 # permissions/privs set for the account we create 857 if ($< == 0) { 858 unless (chmod(0755, $home_dir)) { 859 die("Can't set perms on $home_dir to 0755: $!"); 860 } 861 862 unless (chown($uid, $gid, $home_dir)) { 863 die("Can't set owner of $home_dir to $uid/$gid: $!"); 864 } 865 } 866 867 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 868 '/bin/bash'); 869 auth_group_write($auth_group_file, $group, $gid, $user); 870 871 my $config = { 872 PidFile => $pid_file, 873 ScoreboardFile => $scoreboard_file, 874 SystemLog => $log_file, 875 TraceLog => $log_file, 876 Trace => 'lock:10 scoreboard:10', 877 878 AuthUserFile => $auth_user_file, 879 AuthGroupFile => $auth_group_file, 880 881 MaxLoginAttempts => 2, 882 883 IfModules => { 884 'mod_ban.c' => { 885 BanEngine => 'on', 886 BanLog => $log_file, 887 888 # This says to ban a client which exceeds the MaxLoginAttempts 889 # limit once within the last 1 minute will be banned for 5 secs 890 BanOnEvent => 'MaxLoginAttempts 1/00:01:00 00:00:05', 891 892 BanTable => $ban_tab, 893 }, 894 895 'mod_delay.c' => { 896 DelayEngine => 'off', 897 }, 898 }, 899 }; 900 901 my ($port, $config_user, $config_group) = config_write($config_file, $config); 902 903 # Open pipes, for use between the parent and child processes. Specifically, 904 # the child will indicate when it's done with its test by writing a message 905 # to the parent. 906 my ($rfh, $wfh); 907 unless (pipe($rfh, $wfh)) { 908 die("Can't open pipe: $!"); 909 } 910 911 my $ex; 912 913 # Fork child 914 $self->handle_sigchld(); 915 defined(my $pid = fork()) or die("Can't fork: $!"); 916 if ($pid) { 917 eval { 918 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 919 920 my ($resp_code, $resp_msg); 921 922 eval { $client->login($user, 'foo') }; 923 unless ($@) { 924 die("Login succeeded unexpectedly"); 925 926 } else { 927 $resp_code = $client->response_code(); 928 $resp_msg = $client->response_msg(); 929 } 930 931 my $expected; 932 933 $expected = 530; 934 $self->assert($expected == $resp_code, 935 test_msg("Expected $expected, got $resp_code")); 936 937 $expected = "Login incorrect."; 938 $self->assert($expected eq $resp_msg, 939 test_msg("Expected '$expected', got '$resp_msg'")); 940 941 # Try the login again 942 eval { $client->login($user, 'foo') }; 943 unless ($@) { 944 die("Login succeeded unexpectedly"); 945 946 } else { 947 $resp_code = $client->response_code(); 948 $resp_msg = $client->response_msg(); 949 } 950 951 $expected = 530; 952 $self->assert($expected == $resp_code, 953 test_msg("Expected $expected, got $resp_code")); 954 955 $expected = "Login incorrect."; 956 $self->assert($expected eq $resp_msg, 957 test_msg("Expected '$expected', got '$resp_msg'")); 958 959 # According to Bug#3281, the session process should be have closed/ended. 960 # Make sure this is the case. This QUIT command should fail. 961 eval { $client->quit() }; 962 unless ($@) { 963 die("QUIT succeeded unexpectedly"); 964 } 965 966 # Now try again with the correct info; we should be banned. Note 967 # that we have to create a separate connection for this. 968 969 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 970 undef, 0) }; 971 unless ($@) { 972 die("Connect succeeded unexpectedly"); 973 } 974 975 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 976 977 $expected = ""; 978 $self->assert($expected eq $conn_ex, 979 test_msg("Expected '$expected', got '$conn_ex'")); 980 }; 981 982 if ($@) { 983 $ex = $@; 984 } 985 986 $wfh->print("done\n"); 987 $wfh->flush(); 988 989 } else { 990 eval { server_wait($config_file, $rfh) }; 991 if ($@) { 992 warn($@); 993 exit 1; 994 } 995 996 exit 0; 997 } 998 999 # Stop server 1000 server_stop($pid_file); 1001 1002 $self->assert_child_ok($pid); 1003 1004 if ($ex) { 1005 test_append_logfile($log_file, $ex); 1006 unlink($log_file); 1007 1008 die($ex); 1009 } 1010 1011 unlink($log_file); 1012} 1013 1014sub ban_timeout_login_exceeded_bug3281 { 1015 my $self = shift; 1016 my $tmpdir = $self->{tmpdir}; 1017 my $setup = test_setup($tmpdir, 'ban'); 1018 1019 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 1020 1021 my $timeout_login = 1; 1022 1023 my $config = { 1024 PidFile => $setup->{pid_file}, 1025 ScoreboardFile => $setup->{scoreboard_file}, 1026 SystemLog => $setup->{log_file}, 1027 TraceLog => $setup->{log_file}, 1028 Trace => 'ban:10 event:10', 1029 1030 AuthUserFile => $setup->{auth_user_file}, 1031 AuthGroupFile => $setup->{auth_group_file}, 1032 1033 TimeoutLogin => $timeout_login, 1034 1035 IfModules => { 1036 'mod_ban.c' => { 1037 BanEngine => 'on', 1038 BanLog => $setup->{log_file}, 1039 1040 # This says to ban a client which exceeds the TimeoutLogin 1041 # limit once within the last 1 minute will be banned for 5 secs 1042 BanOnEvent => 'TimeoutLogin 1/00:01:00 00:00:05', 1043 1044 BanTable => $ban_tab, 1045 }, 1046 1047 'mod_delay.c' => { 1048 DelayEngine => 'off', 1049 }, 1050 }, 1051 }; 1052 1053 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1054 $config); 1055 1056 # Open pipes, for use between the parent and child processes. Specifically, 1057 # the child will indicate when it's done with its test by writing a message 1058 # to the parent. 1059 my ($rfh, $wfh); 1060 unless (pipe($rfh, $wfh)) { 1061 die("Can't open pipe: $!"); 1062 } 1063 1064 my $ex; 1065 1066 # Fork child 1067 $self->handle_sigchld(); 1068 defined(my $pid = fork()) or die("Can't fork: $!"); 1069 if ($pid) { 1070 eval { 1071 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1072 1073 # Wait more than the TimeoutLogin interval 1074 sleep($timeout_login + 1); 1075 1076 eval { $client->user($setup->{user}) }; 1077 unless ($@) { 1078 die("USER succeeded unexpectedly"); 1079 } 1080 1081 # According to Bug#3281, the session process should be have closed/ended. 1082 # Make sure this is the case. This QUIT command should fail. 1083 eval { $client->quit() }; 1084 unless ($@) { 1085 die("QUIT succeeded unexpectedly"); 1086 } 1087 1088 # Now try to connect; we should be banned. 1089 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 1090 undef, 0) }; 1091 unless ($@) { 1092 die("Connect succeeded unexpectedly"); 1093 } 1094 1095 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 1096 1097 my $expected = ""; 1098 $self->assert($expected eq $conn_ex, 1099 test_msg("Expected '$expected', got '$conn_ex'")); 1100 }; 1101 if ($@) { 1102 $ex = $@; 1103 } 1104 1105 $wfh->print("done\n"); 1106 $wfh->flush(); 1107 1108 } else { 1109 eval { server_wait($setup->{config_file}, $rfh, 15) }; 1110 if ($@) { 1111 warn($@); 1112 exit 1; 1113 } 1114 1115 exit 0; 1116 } 1117 1118 # Stop server 1119 server_stop($setup->{pid_file}); 1120 $self->assert_child_ok($pid); 1121 1122 test_cleanup($setup->{log_file}, $ex); 1123} 1124 1125sub ban_engine_vhost_bug3355 { 1126 my $self = shift; 1127 my $tmpdir = $self->{tmpdir}; 1128 1129 my $config_file = "$tmpdir/ban.conf"; 1130 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 1131 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 1132 1133 my $log_file = test_get_logfile(); 1134 1135 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 1136 1137 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 1138 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 1139 1140 my $user = 'proftpd'; 1141 my $passwd = 'test'; 1142 my $group = 'ftpd'; 1143 my $home_dir = File::Spec->rel2abs($tmpdir); 1144 my $uid = 500; 1145 my $gid = 500; 1146 1147 # Make sure that, if we're running as root, that the home directory has 1148 # permissions/privs set for the account we create 1149 if ($< == 0) { 1150 unless (chmod(0755, $home_dir)) { 1151 die("Can't set perms on $home_dir to 0755: $!"); 1152 } 1153 1154 unless (chown($uid, $gid, $home_dir)) { 1155 die("Can't set owner of $home_dir to $uid/$gid: $!"); 1156 } 1157 } 1158 1159 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 1160 '/bin/bash'); 1161 auth_group_write($auth_group_file, $group, $gid, $user); 1162 1163 my $max_login_attempts = 2; 1164 1165 my $config = { 1166 PidFile => $pid_file, 1167 ScoreboardFile => $scoreboard_file, 1168 SystemLog => $log_file, 1169 TraceLog => $log_file, 1170 Trace => 'event:10', 1171 DefaultServer => 'off', 1172 1173 AuthUserFile => $auth_user_file, 1174 AuthGroupFile => $auth_group_file, 1175 1176 MaxLoginAttempts => $max_login_attempts, 1177 1178 IfModules => { 1179 'mod_ban.c' => { 1180 BanLog => $log_file, 1181 1182 # This says to ban a client which exceeds the MaxLoginAttempts 1183 # limit once within the last 1 minute will be banned for 5 secs 1184 BanOnEvent => 'MaxLoginAttempts 1/00:01:00 00:00:05', 1185 1186 BanTable => $ban_tab, 1187 }, 1188 1189 'mod_delay.c' => { 1190 DelayEngine => 'off', 1191 }, 1192 }, 1193 }; 1194 1195 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1196 my $vhost_port = $port + 21; 1197 1198 if (open(my $fh, ">> $config_file")) { 1199 print $fh <<EOC; 1200<VirtualHost 127.0.0.1> 1201 Port $vhost_port 1202 AuthUserFile $auth_user_file 1203 AuthGroupFile $auth_group_file 1204 MaxLoginAttempts $max_login_attempts 1205 <IfModule mod_ban.c> 1206 BanEngine off 1207 </IfModule> 1208</VirtualHost> 1209EOC 1210 unless (close($fh)) { 1211 die("Can't write $config_file: $!"); 1212 } 1213 1214 } else { 1215 die("Can't open $config_file: $!"); 1216 } 1217 1218 # Open pipes, for use between the parent and child processes. Specifically, 1219 # the child will indicate when it's done with its test by writing a message 1220 # to the parent. 1221 my ($rfh, $wfh); 1222 unless (pipe($rfh, $wfh)) { 1223 die("Can't open pipe: $!"); 1224 } 1225 1226 my $ex; 1227 1228 # Fork child 1229 $self->handle_sigchld(); 1230 defined(my $pid = fork()) or die("Can't fork: $!"); 1231 if ($pid) { 1232 eval { 1233 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $vhost_port); 1234 1235 my ($resp_code, $resp_msg); 1236 1237 eval { $client->login($user, 'foo') }; 1238 unless ($@) { 1239 die("Login succeeded unexpectedly"); 1240 1241 } else { 1242 $resp_code = $client->response_code(); 1243 $resp_msg = $client->response_msg(); 1244 } 1245 1246 my $expected; 1247 1248 $expected = 530; 1249 $self->assert($expected == $resp_code, 1250 test_msg("Expected $expected, got $resp_code")); 1251 1252 $expected = "Login incorrect."; 1253 $self->assert($expected eq $resp_msg, 1254 test_msg("Expected '$expected', got '$resp_msg'")); 1255 1256 eval { $client->login($user, 'foo') }; 1257 unless ($@) { 1258 die("Login succeeded unexpectedly"); 1259 1260 } else { 1261 $resp_code = $client->response_code(); 1262 $resp_msg = $client->response_msg(); 1263 } 1264 1265 $expected = 530; 1266 $self->assert($expected == $resp_code, 1267 test_msg("Expected $expected, got $resp_code")); 1268 1269 $expected = "Login incorrect."; 1270 $self->assert($expected eq $resp_msg, 1271 test_msg("Expected '$expected', got '$resp_msg'")); 1272 1273 # Now try again with the correct info; we should be banned, except 1274 # that we are connecting to the <VirtualHost> which has mod_ban disabled. 1275 # Note that we have to create a separate connection for this. 1276 1277 $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $vhost_port); 1278 $client->login($user, $passwd); 1279 $client->quit(); 1280 }; 1281 1282 if ($@) { 1283 $ex = $@; 1284 } 1285 1286 $wfh->print("done\n"); 1287 $wfh->flush(); 1288 1289 } else { 1290 eval { server_wait($config_file, $rfh) }; 1291 if ($@) { 1292 warn($@); 1293 exit 1; 1294 } 1295 1296 exit 0; 1297 } 1298 1299 # Stop server 1300 server_stop($pid_file); 1301 1302 $self->assert_child_ok($pid); 1303 1304 if ($ex) { 1305 test_append_logfile($log_file, $ex); 1306 unlink($log_file); 1307 1308 die($ex); 1309 } 1310 1311 unlink($log_file); 1312} 1313 1314sub ban_unhandled_cmd { 1315 my $self = shift; 1316 my $tmpdir = $self->{tmpdir}; 1317 1318 my $config_file = "$tmpdir/ban.conf"; 1319 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 1320 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 1321 1322 my $log_file = test_get_logfile(); 1323 1324 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 1325 1326 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 1327 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 1328 1329 my $user = 'proftpd'; 1330 my $passwd = 'test'; 1331 my $group = 'ftpd'; 1332 my $home_dir = File::Spec->rel2abs($tmpdir); 1333 my $uid = 500; 1334 my $gid = 500; 1335 1336 # Make sure that, if we're running as root, that the home directory has 1337 # permissions/privs set for the account we create 1338 if ($< == 0) { 1339 unless (chmod(0755, $home_dir)) { 1340 die("Can't set perms on $home_dir to 0755: $!"); 1341 } 1342 1343 unless (chown($uid, $gid, $home_dir)) { 1344 die("Can't set owner of $home_dir to $uid/$gid: $!"); 1345 } 1346 } 1347 1348 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 1349 '/bin/bash'); 1350 auth_group_write($auth_group_file, $group, $gid, $user); 1351 1352 my $config = { 1353 PidFile => $pid_file, 1354 ScoreboardFile => $scoreboard_file, 1355 SystemLog => $log_file, 1356 TraceLog => $log_file, 1357 Trace => 'event:10', 1358 1359 AuthUserFile => $auth_user_file, 1360 AuthGroupFile => $auth_group_file, 1361 1362 MaxLoginAttempts => 1, 1363 1364 IfModules => { 1365 'mod_ban.c' => { 1366 BanEngine => 'on', 1367 BanLog => $log_file, 1368 1369 # This says to ban a client which sends unhandled commands 1370 # three times within the last 1 minute will be banned for 5 secs 1371 BanOnEvent => 'UnhandledCommand 3/00:01:00 00:00:05', 1372 1373 BanTable => $ban_tab, 1374 }, 1375 1376 'mod_delay.c' => { 1377 DelayEngine => 'off', 1378 }, 1379 }, 1380 }; 1381 1382 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1383 1384 # Open pipes, for use between the parent and child processes. Specifically, 1385 # the child will indicate when it's done with its test by writing a message 1386 # to the parent. 1387 my ($rfh, $wfh); 1388 unless (pipe($rfh, $wfh)) { 1389 die("Can't open pipe: $!"); 1390 } 1391 1392 my $ex; 1393 1394 # Fork child 1395 $self->handle_sigchld(); 1396 defined(my $pid = fork()) or die("Can't fork: $!"); 1397 if ($pid) { 1398 eval { 1399 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1400 1401 eval { $client->quote('FOO') }; 1402 unless ($@) { 1403 die("FOO command succeeded unexpectedly"); 1404 } 1405 1406 my $resp_code = $client->response_code(); 1407 my $resp_msg = $client->response_msg(); 1408 1409 my $expected; 1410 1411 $expected = 500; 1412 $self->assert($expected == $resp_code, 1413 test_msg("Expected $expected, got $resp_code")); 1414 1415 $expected = "FOO not understood"; 1416 $self->assert($expected eq $resp_msg, 1417 test_msg("Expected '$expected', got '$resp_msg'")); 1418 1419 eval { $client->quote('BAR') }; 1420 unless ($@) { 1421 die("BAR command succeeded unexpectedly"); 1422 } 1423 1424 $resp_code = $client->response_code(); 1425 $resp_msg = $client->response_msg(); 1426 1427 $expected = 500; 1428 $self->assert($expected == $resp_code, 1429 test_msg("Expected $expected, got $resp_code")); 1430 1431 $expected = "BAR not understood"; 1432 $self->assert($expected eq $resp_msg, 1433 test_msg("Expected '$expected', got '$resp_msg'")); 1434 1435 # The mod_ban rule will kick in as part of handling this command, so 1436 # this command shouldn't even get a response (which Net::FTP indicates 1437 # with a response code of "000"). 1438 1439 eval { $client->quote('BAZ') }; 1440 unless ($@) { 1441 die("BAZ command succeeded unexpectedly"); 1442 } 1443 1444 $resp_code = $client->response_code(); 1445 1446 $expected = 000; 1447 $self->assert($expected == $resp_code, 1448 test_msg("Expected $expected, got $resp_code")); 1449 1450 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 1451 undef, 0) }; 1452 unless ($@) { 1453 die("Connect succeeded unexpectedly"); 1454 } 1455 1456 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 1457 1458 $expected = ""; 1459 $self->assert($expected eq $conn_ex, 1460 test_msg("Expected '$expected', got '$conn_ex'")); 1461 }; 1462 1463 if ($@) { 1464 $ex = $@; 1465 } 1466 1467 $wfh->print("done\n"); 1468 $wfh->flush(); 1469 1470 } else { 1471 eval { server_wait($config_file, $rfh) }; 1472 if ($@) { 1473 warn($@); 1474 exit 1; 1475 } 1476 1477 exit 0; 1478 } 1479 1480 # Stop server 1481 server_stop($pid_file); 1482 1483 $self->assert_child_ok($pid); 1484 1485 if ($ex) { 1486 test_append_logfile($log_file, $ex); 1487 unlink($log_file); 1488 1489 die($ex); 1490 } 1491 1492 unlink($log_file); 1493} 1494 1495sub ban_on_event_client_connect_rate { 1496 my $self = shift; 1497 my $tmpdir = $self->{tmpdir}; 1498 1499 my $config_file = "$tmpdir/ban.conf"; 1500 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 1501 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 1502 1503 my $log_file = test_get_logfile(); 1504 1505 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 1506 1507 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 1508 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 1509 1510 my $user = 'proftpd'; 1511 my $passwd = 'test'; 1512 my $group = 'ftpd'; 1513 my $home_dir = File::Spec->rel2abs($tmpdir); 1514 my $uid = 500; 1515 my $gid = 500; 1516 1517 # Make sure that, if we're running as root, that the home directory has 1518 # permissions/privs set for the account we create 1519 if ($< == 0) { 1520 unless (chmod(0755, $home_dir)) { 1521 die("Can't set perms on $home_dir to 0755: $!"); 1522 } 1523 1524 unless (chown($uid, $gid, $home_dir)) { 1525 die("Can't set owner of $home_dir to $uid/$gid: $!"); 1526 } 1527 } 1528 1529 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 1530 '/bin/bash'); 1531 auth_group_write($auth_group_file, $group, $gid, $user); 1532 1533 my $config = { 1534 PidFile => $pid_file, 1535 ScoreboardFile => $scoreboard_file, 1536 SystemLog => $log_file, 1537 TraceLog => $log_file, 1538 Trace => 'event:10', 1539 1540 AuthUserFile => $auth_user_file, 1541 AuthGroupFile => $auth_group_file, 1542 1543 IfModules => { 1544 'mod_ban.c' => { 1545 BanEngine => 'on', 1546 BanLog => $log_file, 1547 1548 # This says to ban a client which connects more than twice in the 1549 # last 1 minute will be banned for 5 secs 1550 BanOnEvent => 'ClientConnectRate 2/00:01:00 00:00:05', 1551 1552 BanTable => $ban_tab, 1553 }, 1554 1555 'mod_delay.c' => { 1556 DelayEngine => 'off', 1557 }, 1558 }, 1559 }; 1560 1561 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1562 1563 # Open pipes, for use between the parent and child processes. Specifically, 1564 # the child will indicate when it's done with its test by writing a message 1565 # to the parent. 1566 my ($rfh, $wfh); 1567 unless (pipe($rfh, $wfh)) { 1568 die("Can't open pipe: $!"); 1569 } 1570 1571 my $ex; 1572 1573 # Fork child 1574 $self->handle_sigchld(); 1575 defined(my $pid = fork()) or die("Can't fork: $!"); 1576 if ($pid) { 1577 eval { 1578 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1579 1580 eval { $client->login($user, 'foo') }; 1581 unless ($@) { 1582 die("Login succeeded unexpectedly"); 1583 } 1584 1585 my $resp_code = $client->response_code(); 1586 my $resp_msg = $client->response_msg(); 1587 1588 my $expected; 1589 1590 $expected = 530; 1591 $self->assert($expected == $resp_code, 1592 test_msg("Expected $expected, got $resp_code")); 1593 1594 $expected = "Login incorrect."; 1595 $self->assert($expected eq $resp_msg, 1596 test_msg("Expected '$expected', got '$resp_msg'")); 1597 1598 eval { $client->login($user, 'foo') }; 1599 unless ($@) { 1600 die("Login succeeded unexpectedly"); 1601 } 1602 1603 $resp_code = $client->response_code(); 1604 $resp_msg = $client->response_msg(); 1605 1606 $expected = 530; 1607 $self->assert($expected == $resp_code, 1608 test_msg("Expected $expected, got $resp_code")); 1609 1610 $expected = "Login incorrect."; 1611 $self->assert($expected eq $resp_msg, 1612 test_msg("Expected '$expected', got '$resp_msg'")); 1613 1614 # Now try again with the correct info; we should be banned. Note 1615 # that we have to create a separate connection for this. 1616 1617 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 1618 undef, 0) }; 1619 unless ($@) { 1620 die("Connect succeeded unexpectedly"); 1621 } 1622 1623 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 1624 1625 $expected = ""; 1626 $self->assert($expected eq $conn_ex, 1627 test_msg("Expected '$expected', got '$conn_ex'")); 1628 }; 1629 1630 if ($@) { 1631 $ex = $@; 1632 } 1633 1634 $wfh->print("done\n"); 1635 $wfh->flush(); 1636 1637 } else { 1638 eval { server_wait($config_file, $rfh) }; 1639 if ($@) { 1640 warn($@); 1641 exit 1; 1642 } 1643 1644 exit 0; 1645 } 1646 1647 # Stop server 1648 server_stop($pid_file); 1649 1650 $self->assert_child_ok($pid); 1651 1652 if ($ex) { 1653 test_append_logfile($log_file, $ex); 1654 unlink($log_file); 1655 1656 die($ex); 1657 } 1658 1659 unlink($log_file); 1660} 1661 1662sub ban_sighup_bug3751 { 1663 my $self = shift; 1664 my $tmpdir = $self->{tmpdir}; 1665 1666 my $config_file = "$tmpdir/ban.conf"; 1667 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 1668 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 1669 1670 my $log_file = test_get_logfile(); 1671 1672 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 1673 1674 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 1675 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 1676 1677 my $user = 'proftpd'; 1678 my $passwd = 'test'; 1679 my $group = 'ftpd'; 1680 my $home_dir = File::Spec->rel2abs($tmpdir); 1681 my $uid = 500; 1682 my $gid = 500; 1683 1684 # Make sure that, if we're running as root, that the home directory has 1685 # permissions/privs set for the account we create 1686 if ($< == 0) { 1687 unless (chmod(0755, $home_dir)) { 1688 die("Can't set perms on $home_dir to 0755: $!"); 1689 } 1690 1691 unless (chown($uid, $gid, $home_dir)) { 1692 die("Can't set owner of $home_dir to $uid/$gid: $!"); 1693 } 1694 } 1695 1696 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 1697 '/bin/bash'); 1698 auth_group_write($auth_group_file, $group, $gid, $user); 1699 1700 my $config = { 1701 PidFile => $pid_file, 1702 ScoreboardFile => $scoreboard_file, 1703 SystemLog => $log_file, 1704 TraceLog => $log_file, 1705 Trace => 'event:10', 1706 1707 AuthUserFile => $auth_user_file, 1708 AuthGroupFile => $auth_group_file, 1709 1710 MaxLoginAttempts => 2, 1711 1712 IfModules => { 1713 'mod_ban.c' => { 1714 BanEngine => 'on', 1715 BanLog => $log_file, 1716 1717 # This says to ban a client which exceeds the MaxLoginAttempts 1718 # limit once within the last 1 minute will be banned for 5 secs 1719 BanOnEvent => 'MaxLoginAttempts 1/00:01:00 00:00:05', 1720 1721 BanTable => $ban_tab, 1722 }, 1723 1724 'mod_delay.c' => { 1725 DelayEngine => 'off', 1726 }, 1727 }, 1728 }; 1729 1730 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1731 1732 # Start the server 1733 server_start($config_file); 1734 sleep(1); 1735 1736 # Use proc(5) filesystem to count the number of open fds in the daemon 1737 my $orig_nfds = server_open_fds($pid_file); 1738 if ($ENV{TEST_VERBOSE}) { 1739 print STDERR "Found $orig_nfds open fds after server startup\n"; 1740 } 1741 1742 # Restart the server 1743 server_restart($pid_file); 1744 sleep(1); 1745 1746 # Count the open fds again, make sure we haven't leaked any 1747 my $restart_nfds = server_open_fds($pid_file); 1748 if ($ENV{TEST_VERBOSE}) { 1749 print STDERR "Found $restart_nfds open fds after server restart #1\n"; 1750 } 1751 1752 $self->assert($orig_nfds == $restart_nfds, 1753 test_msg("Expected $orig_nfds open fds, found $restart_nfds")); 1754 1755 # Restart the server 1756 server_restart($pid_file); 1757 sleep(1); 1758 1759 # And count the open fds one more time, to make doubly sure we are not 1760 # leaking fds. 1761 $restart_nfds = server_open_fds($pid_file); 1762 if ($ENV{TEST_VERBOSE}) { 1763 print STDERR "Found $restart_nfds open fds after server restart #2\n"; 1764 } 1765 1766 $self->assert($orig_nfds == $restart_nfds, 1767 test_msg("Expected $orig_nfds open fds, found $restart_nfds")); 1768 1769 # Stop server 1770 server_stop($pid_file); 1771 unlink($log_file); 1772} 1773 1774sub ban_on_event_tlshandshake { 1775 my $self = shift; 1776 my $tmpdir = $self->{tmpdir}; 1777 1778 my $config_file = "$tmpdir/ban.conf"; 1779 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 1780 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 1781 1782 my $log_file = test_get_logfile(); 1783 1784 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 1785 1786 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 1787 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 1788 1789 my $user = 'proftpd'; 1790 my $passwd = 'test'; 1791 my $group = 'ftpd'; 1792 my $home_dir = File::Spec->rel2abs($tmpdir); 1793 my $uid = 500; 1794 my $gid = 500; 1795 1796 # Make sure that, if we're running as root, that the home directory has 1797 # permissions/privs set for the account we create 1798 if ($< == 0) { 1799 unless (chmod(0755, $home_dir)) { 1800 die("Can't set perms on $home_dir to 0755: $!"); 1801 } 1802 1803 unless (chown($uid, $gid, $home_dir)) { 1804 die("Can't set owner of $home_dir to $uid/$gid: $!"); 1805 } 1806 } 1807 1808 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 1809 '/bin/bash'); 1810 auth_group_write($auth_group_file, $group, $gid, $user); 1811 1812 my $cert_file = File::Spec->rel2abs('t/etc/modules/mod_tls/server-cert.pem'); 1813 my $ca_file = File::Spec->rel2abs('t/etc/modules/mod_tls/ca-cert.pem'); 1814 1815 my $config = { 1816 PidFile => $pid_file, 1817 ScoreboardFile => $scoreboard_file, 1818 SystemLog => $log_file, 1819 TraceLog => $log_file, 1820 Trace => 'event:10', 1821 1822 AuthUserFile => $auth_user_file, 1823 AuthGroupFile => $auth_group_file, 1824 1825 IfModules => { 1826 'mod_ban.c' => { 1827 BanEngine => 'on', 1828 BanLog => $log_file, 1829 1830 # This says to ban a client which requests TLS handshakes (control 1831 # connection) more than twice in the last 1 minute will be banned for 1832 # 5 secs 1833 BanOnEvent => 'TLSHandshake 2/00:01:00 00:00:05', 1834 1835 BanTable => $ban_tab, 1836 }, 1837 1838 'mod_delay.c' => { 1839 DelayEngine => 'off', 1840 }, 1841 1842 'mod_tls.c' => { 1843 TLSEngine => 'on', 1844 TLSLog => $log_file, 1845 TLSRequired => 'on', 1846 TLSRSACertificateFile => $cert_file, 1847 TLSCACertificateFile => $ca_file, 1848 }, 1849 }, 1850 }; 1851 1852 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1853 1854 # Open pipes, for use between the parent and child processes. Specifically, 1855 # the child will indicate when it's done with its test by writing a message 1856 # to the parent. 1857 my ($rfh, $wfh); 1858 unless (pipe($rfh, $wfh)) { 1859 die("Can't open pipe: $!"); 1860 } 1861 1862 require Net::FTPSSL; 1863 1864 my $ex; 1865 1866 # Fork child 1867 $self->handle_sigchld(); 1868 defined(my $pid = fork()) or die("Can't fork: $!"); 1869 if ($pid) { 1870 eval { 1871 # Give the server a chance to start up 1872 sleep(2); 1873 1874 my $client_opts = { 1875 Encryption => 'E', 1876 Port => $port, 1877 }; 1878 1879 if ($ENV{TEST_VERBOSE}) { 1880 $client_opts->{Debug} = 1; 1881 } 1882 1883 my $client = Net::FTPSSL->new('127.0.0.1', $client_opts); 1884 unless ($client) { 1885 die("Can't connect to FTPS server: " . IO::Socket::SSL::errstr()); 1886 } 1887 1888 unless ($client->login($user, $passwd)) { 1889 die("Can't login: " . $client->last_message()); 1890 } 1891 1892 $client->quit(); 1893 1894 # Now try again; we should be banned. Note that we have to create a 1895 # separate connection for this. 1896 1897 $client = Net::FTPSSL->new('127.0.0.1', $client_opts); 1898 if ($client) { 1899 die("Client successfully connected to FTPS unexpectedly"); 1900 } 1901 1902 my $errstr = IO::Socket::SSL::errstr(); 1903 my $expected = 'connect attempt failed'; 1904 $self->assert(qr/$expected/, $errstr, 1905 test_msg("Expected error message '$expected', got '$errstr'")); 1906 }; 1907 1908 if ($@) { 1909 $ex = $@; 1910 } 1911 1912 $wfh->print("done\n"); 1913 $wfh->flush(); 1914 1915 } else { 1916 eval { server_wait($config_file, $rfh) }; 1917 if ($@) { 1918 warn($@); 1919 exit 1; 1920 } 1921 1922 exit 0; 1923 } 1924 1925 # Stop server 1926 server_stop($pid_file); 1927 1928 $self->assert_child_ok($pid); 1929 1930 if ($ex) { 1931 test_append_logfile($log_file, $ex); 1932 unlink($log_file); 1933 1934 die($ex); 1935 } 1936 1937 unlink($log_file); 1938} 1939 1940sub ban_on_event_rootlogin { 1941 my $self = shift; 1942 my $tmpdir = $self->{tmpdir}; 1943 1944 my $config_file = "$tmpdir/ban.conf"; 1945 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 1946 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 1947 1948 my $log_file = test_get_logfile(); 1949 1950 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 1951 1952 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 1953 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 1954 1955 my $user = 'proftpd'; 1956 my $passwd = 'test'; 1957 my $group = 'ftpd'; 1958 my $home_dir = File::Spec->rel2abs($tmpdir); 1959 my $uid = 500; 1960 my $gid = 500; 1961 1962 my $root_user = 'root'; 1963 my $root_passwd = 'root'; 1964 my $root_group = 'ftpd'; 1965 my $root_home_dir = File::Spec->rel2abs($tmpdir); 1966 my $root_uid = 0; 1967 my $root_gid = 0; 1968 1969 # Make sure that, if we're running as root, that the home directory has 1970 # permissions/privs set for the account we create 1971 if ($< == 0) { 1972 unless (chmod(0755, $home_dir)) { 1973 die("Can't set perms on $home_dir to 0755: $!"); 1974 } 1975 1976 unless (chown($uid, $gid, $home_dir)) { 1977 die("Can't set owner of $home_dir to $uid/$gid: $!"); 1978 } 1979 } 1980 1981 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 1982 '/bin/bash'); 1983 auth_group_write($auth_group_file, $group, $gid, $user); 1984 1985 auth_user_write($auth_user_file, $root_user, $root_passwd, $root_uid, 1986 $root_gid, $root_home_dir, '/bin/bash'); 1987 auth_group_write($auth_group_file, $root_group, $root_gid, $root_user); 1988 1989 my $config = { 1990 PidFile => $pid_file, 1991 ScoreboardFile => $scoreboard_file, 1992 SystemLog => $log_file, 1993 TraceLog => $log_file, 1994 Trace => 'event:10', 1995 1996 AuthUserFile => $auth_user_file, 1997 AuthGroupFile => $auth_group_file, 1998 RootLogin => 'off', 1999 2000 IfModules => { 2001 'mod_ban.c' => { 2002 BanEngine => 'on', 2003 BanLog => $log_file, 2004 2005 # This says to ban a client which requests a root login more than twice 2006 # in the last 1 minute will be banned for 5 secs 2007 BanOnEvent => 'RootLogin 2/00:01:00 00:00:05', 2008 2009 BanTable => $ban_tab, 2010 }, 2011 2012 'mod_delay.c' => { 2013 DelayEngine => 'off', 2014 }, 2015 }, 2016 }; 2017 2018 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2019 2020 # Open pipes, for use between the parent and child processes. Specifically, 2021 # the child will indicate when it's done with its test by writing a message 2022 # to the parent. 2023 my ($rfh, $wfh); 2024 unless (pipe($rfh, $wfh)) { 2025 die("Can't open pipe: $!"); 2026 } 2027 2028 require Net::FTPSSL; 2029 2030 my $ex; 2031 2032 # Fork child 2033 $self->handle_sigchld(); 2034 defined(my $pid = fork()) or die("Can't fork: $!"); 2035 if ($pid) { 2036 eval { 2037 # Give server time to start up 2038 sleep(2); 2039 2040 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2041 eval { $client->login($root_user, $root_passwd) }; 2042 unless ($@) { 2043 die("Login succeeded unexpectedly"); 2044 } 2045 2046 my $resp_code = $client->response_code(); 2047 my $resp_msg = $client->response_msg(); 2048 2049 my $expected; 2050 2051 $expected = 530; 2052 $self->assert($expected == $resp_code, 2053 test_msg("Expected response code $expected, got $resp_code")); 2054 2055 $expected = "Login incorrect."; 2056 $self->assert($expected eq $resp_msg, 2057 test_msg("Expected response message '$expected', got '$resp_msg'")); 2058 $client->quit(); 2059 2060 $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2061 $client->user($root_user); 2062 eval { $client->pass($root_passwd) }; 2063 unless ($@) { 2064 die("PASS succeeded unexpectedly"); 2065 } 2066 2067 $resp_code = $client->response_code(); 2068 $resp_msg = $client->response_msg(); 2069 2070 $expected = 000; 2071 $self->assert($expected == $resp_code, 2072 test_msg("Expected response code $expected, got $resp_code")); 2073 2074 # Now try again with the correct info; we should be banned. Note 2075 # that we have to create a separate connection for this. 2076 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 2077 undef, 0) }; 2078 unless ($@) { 2079 die("Connect succeeded unexpectedly"); 2080 } 2081 2082 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 2083 2084 $expected = ""; 2085 $self->assert($expected eq $conn_ex, 2086 test_msg("Expected '$expected', got '$conn_ex'")); 2087 }; 2088 2089 if ($@) { 2090 $ex = $@; 2091 } 2092 2093 $wfh->print("done\n"); 2094 $wfh->flush(); 2095 2096 } else { 2097 eval { server_wait($config_file, $rfh) }; 2098 if ($@) { 2099 warn($@); 2100 exit 1; 2101 } 2102 2103 exit 0; 2104 } 2105 2106 # Stop server 2107 server_stop($pid_file); 2108 2109 $self->assert_child_ok($pid); 2110 2111 if ($ex) { 2112 test_append_logfile($log_file, $ex); 2113 unlink($log_file); 2114 2115 die($ex); 2116 } 2117 2118 unlink($log_file); 2119} 2120 2121sub ban_on_event_rootlogin_userdefined { 2122 my $self = shift; 2123 my $tmpdir = $self->{tmpdir}; 2124 2125 my $config_file = "$tmpdir/ban.conf"; 2126 my $pid_file = File::Spec->rel2abs("$tmpdir/ban.pid"); 2127 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ban.scoreboard"); 2128 2129 my $log_file = test_get_logfile(); 2130 2131 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 2132 2133 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ban.passwd"); 2134 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ban.group"); 2135 2136 my $user = 'proftpd'; 2137 my $passwd = 'test'; 2138 my $group = 'ftpd'; 2139 my $home_dir = File::Spec->rel2abs($tmpdir); 2140 my $uid = 500; 2141 my $gid = 500; 2142 2143 my $root_user = 'root'; 2144 my $root_passwd = 'root'; 2145 my $root_group = 'ftpd'; 2146 my $root_home_dir = File::Spec->rel2abs($tmpdir); 2147 my $root_uid = 0; 2148 my $root_gid = 0; 2149 2150 # Make sure that, if we're running as root, that the home directory has 2151 # permissions/privs set for the account we create 2152 if ($< == 0) { 2153 unless (chmod(0755, $home_dir)) { 2154 die("Can't set perms on $home_dir to 0755: $!"); 2155 } 2156 2157 unless (chown($uid, $gid, $home_dir)) { 2158 die("Can't set owner of $home_dir to $uid/$gid: $!"); 2159 } 2160 } 2161 2162 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 2163 '/bin/bash'); 2164 auth_group_write($auth_group_file, $group, $gid, $user); 2165 2166 auth_user_write($auth_user_file, $root_user, $root_passwd, $root_uid, 2167 $root_gid, $root_home_dir, '/bin/bash'); 2168 auth_group_write($auth_group_file, $root_group, $root_gid, $root_user); 2169 2170 my $config = { 2171 PidFile => $pid_file, 2172 ScoreboardFile => $scoreboard_file, 2173 SystemLog => $log_file, 2174 TraceLog => $log_file, 2175 Trace => 'event:10', 2176 2177 AuthUserFile => $auth_user_file, 2178 AuthGroupFile => $auth_group_file, 2179 RootLogin => 'off', 2180 2181 IfModules => { 2182 'mod_ban.c' => { 2183 BanEngine => 'on', 2184 BanLog => $log_file, 2185 2186 # This says to ban a client which requests a root login more than twice 2187 # in the last 1 minute will be banned for 5 secs 2188 BanOnEvent => 'mod_auth.root-login 2/00:01:00 00:00:05', 2189 2190 BanTable => $ban_tab, 2191 }, 2192 2193 'mod_delay.c' => { 2194 DelayEngine => 'off', 2195 }, 2196 }, 2197 }; 2198 2199 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2200 2201 # Open pipes, for use between the parent and child processes. Specifically, 2202 # the child will indicate when it's done with its test by writing a message 2203 # to the parent. 2204 my ($rfh, $wfh); 2205 unless (pipe($rfh, $wfh)) { 2206 die("Can't open pipe: $!"); 2207 } 2208 2209 require Net::FTPSSL; 2210 2211 my $ex; 2212 2213 # Fork child 2214 $self->handle_sigchld(); 2215 defined(my $pid = fork()) or die("Can't fork: $!"); 2216 if ($pid) { 2217 eval { 2218 # Give server time to start up 2219 sleep(2); 2220 2221 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2222 eval { $client->login($root_user, $root_passwd) }; 2223 unless ($@) { 2224 die("Login succeeded unexpectedly"); 2225 } 2226 2227 my $resp_code = $client->response_code(); 2228 my $resp_msg = $client->response_msg(); 2229 2230 my $expected; 2231 2232 $expected = 530; 2233 $self->assert($expected == $resp_code, 2234 test_msg("Expected response code $expected, got $resp_code")); 2235 2236 $expected = "Login incorrect."; 2237 $self->assert($expected eq $resp_msg, 2238 test_msg("Expected response message '$expected', got '$resp_msg'")); 2239 $client->quit(); 2240 2241 $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2242 $client->user($root_user); 2243 eval { $client->pass($root_passwd) }; 2244 unless ($@) { 2245 die("PASS succeeded unexpectedly"); 2246 } 2247 2248 $resp_code = $client->response_code(); 2249 $resp_msg = $client->response_msg(); 2250 2251 $expected = 000; 2252 $self->assert($expected == $resp_code, 2253 test_msg("Expected response code $expected, got $resp_code")); 2254 2255 # Now try again with the correct info; we should be banned. Note 2256 # that we have to create a separate connection for this. 2257 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 2258 undef, 0) }; 2259 unless ($@) { 2260 die("Connect succeeded unexpectedly"); 2261 } 2262 2263 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 2264 2265 $expected = ""; 2266 $self->assert($expected eq $conn_ex, 2267 test_msg("Expected '$expected', got '$conn_ex'")); 2268 }; 2269 2270 if ($@) { 2271 $ex = $@; 2272 } 2273 2274 $wfh->print("done\n"); 2275 $wfh->flush(); 2276 2277 } else { 2278 eval { server_wait($config_file, $rfh) }; 2279 if ($@) { 2280 warn($@); 2281 exit 1; 2282 } 2283 2284 exit 0; 2285 } 2286 2287 # Stop server 2288 server_stop($pid_file); 2289 2290 $self->assert_child_ok($pid); 2291 2292 if ($ex) { 2293 test_append_logfile($log_file, $ex); 2294 unlink($log_file); 2295 2296 die($ex); 2297 } 2298 2299 unlink($log_file); 2300} 2301 2302sub ban_opt_any_server_issue1010 { 2303 my $self = shift; 2304 my $tmpdir = $self->{tmpdir}; 2305 my $setup = test_setup($tmpdir, 'ban'); 2306 2307 my $ban_tab = File::Spec->rel2abs("$tmpdir/ban.tab"); 2308 2309 my $vhost_port = ProFTPD::TestSuite::Utils::get_high_numbered_port(); 2310 $vhost_port += 11; 2311 2312 my $config = { 2313 PidFile => $setup->{pid_file}, 2314 ScoreboardFile => $setup->{scoreboard_file}, 2315 SystemLog => $setup->{log_file}, 2316 TraceLog => $setup->{log_file}, 2317 2318 AuthUserFile => $setup->{auth_user_file}, 2319 AuthGroupFile => $setup->{auth_group_file}, 2320 2321 MaxLoginAttempts => 2, 2322 2323 IfModules => { 2324 'mod_ban.c' => { 2325 BanEngine => 'on', 2326 BanLog => $setup->{log_file}, 2327 BanTable => $ban_tab, 2328 2329 # This says to ban a client which exceeds the MaxLoginAttempts 2330 # limit once within the last 1 minute will be banned for 15 secs 2331 BanOnEvent => 'MaxLoginAttempts 1/00:01:00 00:00:15', 2332 2333 BanOptions => 'MatchAnyServer', 2334 }, 2335 2336 'mod_delay.c' => { 2337 DelayEngine => 'off', 2338 }, 2339 }, 2340 }; 2341 2342 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 2343 $config); 2344 2345 if (open(my $fh, ">> $setup->{config_file}")) { 2346 print $fh <<EOC; 2347<VirtualHost 127.0.0.1> 2348 Port $vhost_port 2349 ServerName "Other Server" 2350 2351 WtmpLog off 2352 TransferLog none 2353 2354 <IfModule mod_ban.c> 2355 BanEngine on 2356 </IfModule> 2357</VirtualHost> 2358EOC 2359 unless (close($fh)) { 2360 die("Can't write $setup->{config_file}: $!"); 2361 } 2362 2363 } else { 2364 die("Can't open $setup->{config_file}: $!"); 2365 } 2366 2367 # Open pipes, for use between the parent and child processes. Specifically, 2368 # the child will indicate when it's done with its test by writing a message 2369 # to the parent. 2370 my ($rfh, $wfh); 2371 unless (pipe($rfh, $wfh)) { 2372 die("Can't open pipe: $!"); 2373 } 2374 2375 my $ex; 2376 2377 # Fork child 2378 $self->handle_sigchld(); 2379 defined(my $pid = fork()) or die("Can't fork: $!"); 2380 if ($pid) { 2381 eval { 2382 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2383 2384 eval { $client->login($setup->{user}, 'foo') }; 2385 unless ($@) { 2386 die("Login succeeded unexpectedly"); 2387 } 2388 2389 my $resp_code = $client->response_code(); 2390 my $resp_msg = $client->response_msg(); 2391 2392 my $expected = 530; 2393 $self->assert($expected == $resp_code, 2394 test_msg("Expected response code $expected, got $resp_code")); 2395 2396 $expected = 'Login incorrect.'; 2397 $self->assert($expected eq $resp_msg, 2398 test_msg("Expected response message '$expected', got '$resp_msg'")); 2399 2400 eval { $client->login($setup->{user}, 'foo') }; 2401 unless ($@) { 2402 die("Login succeeded unexpectedly"); 2403 } 2404 2405 $resp_code = $client->response_code(); 2406 $resp_msg = $client->response_msg(); 2407 2408 $expected = 530; 2409 $self->assert($expected == $resp_code, 2410 test_msg("Expected respones code $expected, got $resp_code")); 2411 2412 $expected = 'Login incorrect.'; 2413 $self->assert($expected eq $resp_msg, 2414 test_msg("Expected response message '$expected', got '$resp_msg'")); 2415 2416 # Now try again with the correct info; we should be banned. Note 2417 # that we have to create a separate connection for this. 2418 2419 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 2420 undef, 0) }; 2421 unless ($@) { 2422 die("Connect succeeded unexpectedly"); 2423 } 2424 2425 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 2426 2427 $expected = ''; 2428 $self->assert($expected eq $conn_ex, 2429 test_msg("Expected '$expected', got '$conn_ex'")); 2430 2431 # We should also be banned by the OTHER vhost in the config, to which 2432 # we have not connected at all. 2433 2434 eval { $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $vhost_port, 2435 undef, 0) }; 2436 unless ($@) { 2437 die("Connect succeeded unexpectedly"); 2438 } 2439 2440 my $conn_ex = ProFTPD::TestSuite::FTP::get_connect_exception(); 2441 2442 $expected = ''; 2443 $self->assert($expected eq $conn_ex, 2444 test_msg("Expected '$expected', got '$conn_ex'")); 2445 }; 2446 if ($@) { 2447 $ex = $@; 2448 } 2449 2450 $wfh->print("done\n"); 2451 $wfh->flush(); 2452 2453 } else { 2454 eval { server_wait($setup->{config_file}, $rfh) }; 2455 if ($@) { 2456 warn($@); 2457 exit 1; 2458 } 2459 2460 exit 0; 2461 } 2462 2463 # Stop server 2464 server_stop($setup->{pid_file}); 2465 $self->assert_child_ok($pid); 2466 2467 test_cleanup($setup->{log_file}, $ex); 2468} 2469 24701; 2471