1package ProFTPD::Tests::Config::PathDenyFilter; 2 3use lib qw(t/lib); 4use base qw(ProFTPD::TestSuite::Child); 5use strict; 6 7use File::Path qw(mkpath); 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 pathdenyfilter_dele_allowed => { 20 order => ++$order, 21 test_class => [qw(forking)], 22 }, 23 24 pathdenyfilter_dele_denied => { 25 order => ++$order, 26 test_class => [qw(forking)], 27 }, 28 29 pathdenyfilter_mkd_allowed => { 30 order => ++$order, 31 test_class => [qw(forking)], 32 }, 33 34 pathdenyfilter_mkd_denied => { 35 order => ++$order, 36 test_class => [qw(forking)], 37 }, 38 39 pathdenyfilter_rmd_allowed => { 40 order => ++$order, 41 test_class => [qw(forking)], 42 }, 43 44 pathdenyfilter_rmd_denied => { 45 order => ++$order, 46 test_class => [qw(forking)], 47 }, 48 49 pathdenyfilter_rnfr_allowed => { 50 order => ++$order, 51 test_class => [qw(forking)], 52 }, 53 54 pathdenyfilter_rnfr_denied => { 55 order => ++$order, 56 test_class => [qw(forking)], 57 }, 58 59 pathdenyfilter_rnto_allowed => { 60 order => ++$order, 61 test_class => [qw(forking)], 62 }, 63 64 pathdenyfilter_rnto_denied => { 65 order => ++$order, 66 test_class => [qw(forking)], 67 }, 68 69 pathdenyfilter_stor_allowed => { 70 order => ++$order, 71 test_class => [qw(forking)], 72 }, 73 74 pathdenyfilter_stor_denied => { 75 order => ++$order, 76 test_class => [qw(forking)], 77 }, 78 79 pathdenyfilter_stor_denied_bug3032 => { 80 order => ++$order, 81 test_class => [qw(bug forking)], 82 }, 83 84 pathdenyfilter_stor_trailing_space => { 85 order => ++$order, 86 test_class => [qw(forking)], 87 }, 88 89 pathdenyfilter_stor_leading_space => { 90 order => ++$order, 91 test_class => [qw(forking)], 92 }, 93 94 pathdenyfilter_stor_leading_trailing_space => { 95 order => ++$order, 96 test_class => [qw(forking)], 97 }, 98 99 pathdenyfilter_stor_denied_nocase_bug3592 => { 100 order => ++$order, 101 test_class => [qw(bug forking)], 102 }, 103 104 pathdenyfilter_stor_dotfiles_denied => { 105 order => ++$order, 106 test_class => [qw(forking)], 107 }, 108 109}; 110 111sub new { 112 return shift()->SUPER::new(@_); 113} 114 115sub list_tests { 116 return testsuite_get_runnable_tests($TESTS); 117} 118 119sub pathdenyfilter_dele_allowed { 120 my $self = shift; 121 my $tmpdir = $self->{tmpdir}; 122 my $setup = test_setup($tmpdir, 'config'); 123 124 my $test_file = File::Spec->rel2abs("$tmpdir/test.txt"); 125 if (open(my $fh, "> $test_file")) { 126 close($fh); 127 128 } else { 129 die("Can't open $test_file: $!"); 130 } 131 132 my $config = { 133 PidFile => $setup->{pid_file}, 134 ScoreboardFile => $setup->{scoreboard_file}, 135 SystemLog => $setup->{log_file}, 136 137 AuthUserFile => $setup->{auth_user_file}, 138 AuthGroupFile => $setup->{auth_group_file}, 139 DefaultChdir => '~', 140 141 AllowOverwrite => 'on', 142 PathDenyFilter => '\.tmp$', 143 144 IfModules => { 145 'mod_delay.c' => { 146 DelayEngine => 'off', 147 }, 148 }, 149 }; 150 151 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 152 $config); 153 154 # Open pipes, for use between the parent and child processes. Specifically, 155 # the child will indicate when it's done with its test by writing a message 156 # to the parent. 157 my ($rfh, $wfh); 158 unless (pipe($rfh, $wfh)) { 159 die("Can't open pipe: $!"); 160 } 161 162 my $ex; 163 164 # Fork child 165 $self->handle_sigchld(); 166 defined(my $pid = fork()) or die("Can't fork: $!"); 167 if ($pid) { 168 eval { 169 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 170 $client->login($setup->{user}, $setup->{passwd}); 171 172 my ($resp_code, $resp_msg) = $client->dele('test.txt'); 173 174 my $expected = 250; 175 $self->assert($expected == $resp_code, 176 test_msg("Expected response code $expected, got $resp_code")); 177 178 $expected = 'DELE command successful'; 179 $self->assert($expected eq $resp_msg, 180 test_msg("Expected response message '$expected', got '$resp_msg'")); 181 182 $client->quit(); 183 }; 184 if ($@) { 185 $ex = $@; 186 } 187 188 $wfh->print("done\n"); 189 $wfh->flush(); 190 191 } else { 192 eval { server_wait($setup->{config_file}, $rfh) }; 193 if ($@) { 194 warn($@); 195 exit 1; 196 } 197 198 exit 0; 199 } 200 201 # Stop server 202 server_stop($setup->{pid_file}); 203 $self->assert_child_ok($pid); 204 205 test_cleanup($setup->{log_file}, $ex); 206} 207 208sub pathdenyfilter_dele_denied { 209 my $self = shift; 210 my $tmpdir = $self->{tmpdir}; 211 my $setup = test_setup($tmpdir, 'config'); 212 213 my $config = { 214 PidFile => $setup->{pid_file}, 215 ScoreboardFile => $setup->{scoreboard_file}, 216 SystemLog => $setup->{log_file}, 217 218 AuthUserFile => $setup->{auth_user_file}, 219 AuthGroupFile => $setup->{auth_group_file}, 220 DefaultChdir => '~', 221 222 PathDenyFilter => '\.txt$', 223 224 IfModules => { 225 'mod_delay.c' => { 226 DelayEngine => 'off', 227 }, 228 }, 229 }; 230 231 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 232 $config); 233 234 # Open pipes, for use between the parent and child processes. Specifically, 235 # the child will indicate when it's done with its test by writing a message 236 # to the parent. 237 my ($rfh, $wfh); 238 unless (pipe($rfh, $wfh)) { 239 die("Can't open pipe: $!"); 240 } 241 242 my $ex; 243 244 # Fork child 245 $self->handle_sigchld(); 246 defined(my $pid = fork()) or die("Can't fork: $!"); 247 if ($pid) { 248 eval { 249 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 250 $client->login($setup->{user}, $setup->{passwd}); 251 252 my $filename = 'test.txt'; 253 254 eval { $client->dele($filename) }; 255 unless ($@) { 256 die("DELE $filename succeeded unexpectedly"); 257 } 258 259 my $resp_code = $client->response_code(); 260 my $resp_msg = $client->response_msg(); 261 262 my $expected = 550; 263 $self->assert($expected == $resp_code, 264 test_msg("Expected response code $expected, got $resp_code")); 265 266 $expected = "$filename: Forbidden filename"; 267 $self->assert($expected eq $resp_msg, 268 test_msg("Expected response message '$expected', got '$resp_msg'")); 269 270 $client->quit(); 271 }; 272 if ($@) { 273 $ex = $@; 274 } 275 276 $wfh->print("done\n"); 277 $wfh->flush(); 278 279 } else { 280 eval { server_wait($setup->{config_file}, $rfh) }; 281 if ($@) { 282 warn($@); 283 exit 1; 284 } 285 286 exit 0; 287 } 288 289 # Stop server 290 server_stop($setup->{pid_file}); 291 $self->assert_child_ok($pid); 292 293 test_cleanup($setup->{log_file}, $ex); 294} 295 296sub pathdenyfilter_mkd_allowed { 297 my $self = shift; 298 my $tmpdir = $self->{tmpdir}; 299 my $setup = test_setup($tmpdir, 'config'); 300 301 my $path = File::Spec->rel2abs("$tmpdir/subdir.d"); 302 303 my $config = { 304 PidFile => $setup->{pid_file}, 305 ScoreboardFile => $setup->{scoreboard_file}, 306 SystemLog => $setup->{log_file}, 307 308 AuthUserFile => $setup->{auth_user_file}, 309 AuthGroupFile => $setup->{auth_group_file}, 310 DefaultChdir => '~', 311 312 AllowOverwrite => 'on', 313 PathDenyFilter => '\.dir$', 314 315 IfModules => { 316 'mod_delay.c' => { 317 DelayEngine => 'off', 318 }, 319 }, 320 }; 321 322 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 323 $config); 324 325 # Open pipes, for use between the parent and child processes. Specifically, 326 # the child will indicate when it's done with its test by writing a message 327 # to the parent. 328 my ($rfh, $wfh); 329 unless (pipe($rfh, $wfh)) { 330 die("Can't open pipe: $!"); 331 } 332 333 my $ex; 334 335 # Fork child 336 $self->handle_sigchld(); 337 defined(my $pid = fork()) or die("Can't fork: $!"); 338 if ($pid) { 339 eval { 340 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 341 $client->login($setup->{user}, $setup->{passwd}); 342 343 my ($resp_code, $resp_msg) = $client->mkd('subdir.d'); 344 345 my $expected = 257; 346 $self->assert($expected == $resp_code, 347 test_msg("Expected response code $expected, got $resp_code")); 348 349 # Mac OSX hack 350 if ($^O eq 'darwin') { 351 $path = '/private' . $path; 352 } 353 354 $expected = "\"$path\" - Directory successfully created"; 355 $self->assert($expected eq $resp_msg, 356 test_msg("Expected response message '$expected', got '$resp_msg'")); 357 358 $client->quit(); 359 }; 360 if ($@) { 361 $ex = $@; 362 } 363 364 $wfh->print("done\n"); 365 $wfh->flush(); 366 367 } else { 368 eval { server_wait($setup->{config_file}, $rfh) }; 369 if ($@) { 370 warn($@); 371 exit 1; 372 } 373 374 exit 0; 375 } 376 377 # Stop server 378 server_stop($setup->{pid_file}); 379 $self->assert_child_ok($pid); 380 381 test_cleanup($setup->{log_file}, $ex); 382} 383 384sub pathdenyfilter_mkd_denied { 385 my $self = shift; 386 my $tmpdir = $self->{tmpdir}; 387 my $setup = test_setup($tmpdir, 'config'); 388 389 my $config = { 390 PidFile => $setup->{pid_file}, 391 ScoreboardFile => $setup->{scoreboard_file}, 392 SystemLog => $setup->{log_file}, 393 394 AuthUserFile => $setup->{auth_user_file}, 395 AuthGroupFile => $setup->{auth_group_file}, 396 DefaultChdir => '~', 397 398 PathDenyFilter => '\.dir$', 399 400 IfModules => { 401 'mod_delay.c' => { 402 DelayEngine => 'off', 403 }, 404 }, 405 }; 406 407 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 408 $config); 409 410 # Open pipes, for use between the parent and child processes. Specifically, 411 # the child will indicate when it's done with its test by writing a message 412 # to the parent. 413 my ($rfh, $wfh); 414 unless (pipe($rfh, $wfh)) { 415 die("Can't open pipe: $!"); 416 } 417 418 my $ex; 419 420 # Fork child 421 $self->handle_sigchld(); 422 defined(my $pid = fork()) or die("Can't fork: $!"); 423 if ($pid) { 424 eval { 425 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 426 $client->login($setup->{user}, $setup->{passwd}); 427 428 my $dirname = 'subdir.dir'; 429 430 eval { $client->mkd($dirname) }; 431 unless ($@) { 432 die("MKD $dirname succeeded unexpectedly"); 433 } 434 435 my $resp_code = $client->response_code(); 436 my $resp_msg = $client->response_msg(); 437 438 my $expected = 550; 439 $self->assert($expected == $resp_code, 440 test_msg("Expected response code $expected, got $resp_code")); 441 442 $expected = "$dirname: Forbidden filename"; 443 $self->assert($expected eq $resp_msg, 444 test_msg("Expected response message '$expected', got '$resp_msg'")); 445 446 $client->quit(); 447 }; 448 if ($@) { 449 $ex = $@; 450 } 451 452 $wfh->print("done\n"); 453 $wfh->flush(); 454 455 } else { 456 eval { server_wait($setup->{config_file}, $rfh) }; 457 if ($@) { 458 warn($@); 459 exit 1; 460 } 461 462 exit 0; 463 } 464 465 # Stop server 466 server_stop($setup->{pid_file}); 467 $self->assert_child_ok($pid); 468 469 test_cleanup($setup->{log_file}, $ex); 470} 471 472sub pathdenyfilter_rmd_allowed { 473 my $self = shift; 474 my $tmpdir = $self->{tmpdir}; 475 my $setup = test_setup($tmpdir, 'config'); 476 477 mkpath("$tmpdir/subdir.d"); 478 479 my $config = { 480 PidFile => $setup->{pid_file}, 481 ScoreboardFile => $setup->{scoreboard_file}, 482 SystemLog => $setup->{log_file}, 483 484 AuthUserFile => $setup->{auth_user_file}, 485 AuthGroupFile => $setup->{auth_group_file}, 486 DefaultChdir => '~', 487 488 AllowOverwrite => 'on', 489 PathDenyFilter => '\.dir$', 490 491 IfModules => { 492 'mod_delay.c' => { 493 DelayEngine => 'off', 494 }, 495 }, 496 }; 497 498 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 499 $config); 500 501 # Open pipes, for use between the parent and child processes. Specifically, 502 # the child will indicate when it's done with its test by writing a message 503 # to the parent. 504 my ($rfh, $wfh); 505 unless (pipe($rfh, $wfh)) { 506 die("Can't open pipe: $!"); 507 } 508 509 my $ex; 510 511 # Fork child 512 $self->handle_sigchld(); 513 defined(my $pid = fork()) or die("Can't fork: $!"); 514 if ($pid) { 515 eval { 516 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 517 $client->login($setup->{user}, $setup->{passwd}); 518 519 my ($resp_code, $resp_msg) = $client->rmd('subdir.d'); 520 521 my $expected = 250; 522 $self->assert($expected == $resp_code, 523 test_msg("Expected response code $expected, got $resp_code")); 524 525 $expected = 'RMD command successful'; 526 $self->assert($expected eq $resp_msg, 527 test_msg("Expected response message '$expected', got '$resp_msg'")); 528 529 $client->quit(); 530 }; 531 if ($@) { 532 $ex = $@; 533 } 534 535 $wfh->print("done\n"); 536 $wfh->flush(); 537 538 } else { 539 eval { server_wait($setup->{config_file}, $rfh) }; 540 if ($@) { 541 warn($@); 542 exit 1; 543 } 544 545 exit 0; 546 } 547 548 # Stop server 549 server_stop($setup->{pid_file}); 550 $self->assert_child_ok($pid); 551 552 test_cleanup($setup->{log_file}, $ex); 553} 554 555sub pathdenyfilter_rmd_denied { 556 my $self = shift; 557 my $tmpdir = $self->{tmpdir}; 558 my $setup = test_setup($tmpdir, 'config'); 559 560 my $config = { 561 PidFile => $setup->{pid_file}, 562 ScoreboardFile => $setup->{scoreboard_file}, 563 SystemLog => $setup->{log_file}, 564 565 AuthUserFile => $setup->{auth_user_file}, 566 AuthGroupFile => $setup->{auth_group_file}, 567 DefaultChdir => '~', 568 569 PathDenyFilter => '\.dir$', 570 571 IfModules => { 572 'mod_delay.c' => { 573 DelayEngine => 'off', 574 }, 575 }, 576 }; 577 578 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 579 $config); 580 581 # Open pipes, for use between the parent and child processes. Specifically, 582 # the child will indicate when it's done with its test by writing a message 583 # to the parent. 584 my ($rfh, $wfh); 585 unless (pipe($rfh, $wfh)) { 586 die("Can't open pipe: $!"); 587 } 588 589 my $ex; 590 591 # Fork child 592 $self->handle_sigchld(); 593 defined(my $pid = fork()) or die("Can't fork: $!"); 594 if ($pid) { 595 eval { 596 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 597 $client->login($setup->{user}, $setup->{passwd}); 598 599 my $dirname = 'subdir.dir'; 600 601 eval { $client->rmd($dirname) }; 602 unless ($@) { 603 die("RMD $dirname succeeded unexpectedly"); 604 } 605 606 my $resp_code = $client->response_code(); 607 my $resp_msg = $client->response_msg(); 608 609 my $expected = 550; 610 $self->assert($expected == $resp_code, 611 test_msg("Expected response code $expected, got $resp_code")); 612 613 $expected = "$dirname: Forbidden filename"; 614 $self->assert($expected eq $resp_msg, 615 test_msg("Expected response message '$expected', got '$resp_msg'")); 616 617 $client->quit(); 618 }; 619 if ($@) { 620 $ex = $@; 621 } 622 623 $wfh->print("done\n"); 624 $wfh->flush(); 625 626 } else { 627 eval { server_wait($setup->{config_file}, $rfh) }; 628 if ($@) { 629 warn($@); 630 exit 1; 631 } 632 633 exit 0; 634 } 635 636 # Stop server 637 server_stop($setup->{pid_file}); 638 $self->assert_child_ok($pid); 639 640 test_cleanup($setup->{log_file}, $ex); 641} 642 643sub pathdenyfilter_rnfr_allowed { 644 my $self = shift; 645 my $tmpdir = $self->{tmpdir}; 646 my $setup = test_setup($tmpdir, 'config'); 647 648 mkpath("$tmpdir/subdir.d"); 649 650 my $config = { 651 PidFile => $setup->{pid_file}, 652 ScoreboardFile => $setup->{scoreboard_file}, 653 SystemLog => $setup->{log_file}, 654 655 AuthUserFile => $setup->{auth_user_file}, 656 AuthGroupFile => $setup->{auth_group_file}, 657 DefaultChdir => '~', 658 659 AllowOverwrite => 'on', 660 PathDenyFilter => '\.dir$', 661 662 IfModules => { 663 'mod_delay.c' => { 664 DelayEngine => 'off', 665 }, 666 }, 667 }; 668 669 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 670 $config); 671 672 # Open pipes, for use between the parent and child processes. Specifically, 673 # the child will indicate when it's done with its test by writing a message 674 # to the parent. 675 my ($rfh, $wfh); 676 unless (pipe($rfh, $wfh)) { 677 die("Can't open pipe: $!"); 678 } 679 680 my $ex; 681 682 # Fork child 683 $self->handle_sigchld(); 684 defined(my $pid = fork()) or die("Can't fork: $!"); 685 if ($pid) { 686 eval { 687 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 688 $client->login($setup->{user}, $setup->{passwd}); 689 690 my ($resp_code, $resp_msg) = $client->rnfr('subdir.d'); 691 692 my $expected = 350; 693 $self->assert($expected == $resp_code, 694 test_msg("Expected response code $expected, got $resp_code")); 695 696 $expected = 'File or directory exists, ready for destination name'; 697 $self->assert($expected eq $resp_msg, 698 test_msg("Expected response message '$expected', got '$resp_msg'")); 699 700 $client->quit(); 701 }; 702 if ($@) { 703 $ex = $@; 704 } 705 706 $wfh->print("done\n"); 707 $wfh->flush(); 708 709 } else { 710 eval { server_wait($setup->{config_file}, $rfh) }; 711 if ($@) { 712 warn($@); 713 exit 1; 714 } 715 716 exit 0; 717 } 718 719 # Stop server 720 server_stop($setup->{pid_file}); 721 $self->assert_child_ok($pid); 722 723 test_cleanup($setup->{log_file}, $ex); 724} 725 726sub pathdenyfilter_rnfr_denied { 727 my $self = shift; 728 my $tmpdir = $self->{tmpdir}; 729 my $setup = test_setup($tmpdir, 'config'); 730 731 my $config = { 732 PidFile => $setup->{pid_file}, 733 ScoreboardFile => $setup->{scoreboard_file}, 734 SystemLog => $setup->{log_file}, 735 736 AuthUserFile => $setup->{auth_user_file}, 737 AuthGroupFile => $setup->{auth_group_file}, 738 DefaultChdir => '~', 739 740 PathDenyFilter => '\.d$', 741 742 IfModules => { 743 'mod_delay.c' => { 744 DelayEngine => 'off', 745 }, 746 }, 747 }; 748 749 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 750 $config); 751 752 # Open pipes, for use between the parent and child processes. Specifically, 753 # the child will indicate when it's done with its test by writing a message 754 # to the parent. 755 my ($rfh, $wfh); 756 unless (pipe($rfh, $wfh)) { 757 die("Can't open pipe: $!"); 758 } 759 760 my $ex; 761 762 # Fork child 763 $self->handle_sigchld(); 764 defined(my $pid = fork()) or die("Can't fork: $!"); 765 if ($pid) { 766 eval { 767 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 768 $client->login($setup->{user}, $setup->{passwd}); 769 770 my $dirname = 'subdir.d'; 771 772 eval { $client->rnfr($dirname) }; 773 unless ($@) { 774 die("RNFR $dirname succeeded unexpectedly"); 775 } 776 777 my $resp_code = $client->response_code(); 778 my $resp_msg = $client->response_msg(); 779 780 my $expected = 550; 781 $self->assert($expected == $resp_code, 782 test_msg("Expected response code $expected, got $resp_code")); 783 784 $expected = "$dirname: Forbidden filename"; 785 $self->assert($expected eq $resp_msg, 786 test_msg("Expected response message '$expected', got '$resp_msg'")); 787 788 $client->quit(); 789 }; 790 if ($@) { 791 $ex = $@; 792 } 793 794 $wfh->print("done\n"); 795 $wfh->flush(); 796 797 } else { 798 eval { server_wait($setup->{config_file}, $rfh) }; 799 if ($@) { 800 warn($@); 801 exit 1; 802 } 803 804 exit 0; 805 } 806 807 # Stop server 808 server_stop($setup->{pid_file}); 809 $self->assert_child_ok($pid); 810 811 test_cleanup($setup->{log_file}, $ex); 812} 813 814sub pathdenyfilter_rnto_allowed { 815 my $self = shift; 816 my $tmpdir = $self->{tmpdir}; 817 my $setup = test_setup($tmpdir, 'config'); 818 819 my $sub_dir = File::Spec->rel2abs("$tmpdir/subdir.d"); 820 mkpath($sub_dir); 821 822 if ($< == 0) { 823 unless (chown($setup->{uid}, $setup->{gid}, $sub_dir)) { 824 die("Can't set owner of $sub_dir to $setup->{uid}/$setup->{gid}: $!"); 825 } 826 } 827 828 my $config = { 829 PidFile => $setup->{pid_file}, 830 ScoreboardFile => $setup->{scoreboard_file}, 831 SystemLog => $setup->{log_file}, 832 833 AuthUserFile => $setup->{auth_user_file}, 834 AuthGroupFile => $setup->{auth_group_file}, 835 DefaultChdir => '~', 836 837 AllowOverwrite => 'on', 838 PathDenyFilter => '\.dir$', 839 840 IfModules => { 841 'mod_delay.c' => { 842 DelayEngine => 'off', 843 }, 844 }, 845 }; 846 847 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 848 $config); 849 850 # Open pipes, for use between the parent and child processes. Specifically, 851 # the child will indicate when it's done with its test by writing a message 852 # to the parent. 853 my ($rfh, $wfh); 854 unless (pipe($rfh, $wfh)) { 855 die("Can't open pipe: $!"); 856 } 857 858 my $ex; 859 860 # Fork child 861 $self->handle_sigchld(); 862 defined(my $pid = fork()) or die("Can't fork: $!"); 863 if ($pid) { 864 eval { 865 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 866 $client->login($setup->{user}, $setup->{passwd}); 867 868 $client->rnfr('subdir.d'); 869 my ($resp_code, $resp_msg) = $client->rnto('foo.d'); 870 871 my $expected = 250; 872 $self->assert($expected == $resp_code, 873 test_msg("Expected response code $expected, got $resp_code")); 874 875 $expected = 'Rename successful'; 876 $self->assert($expected eq $resp_msg, 877 test_msg("Expected response message '$expected', got '$resp_msg'")); 878 879 $client->quit(); 880 }; 881 if ($@) { 882 $ex = $@; 883 } 884 885 $wfh->print("done\n"); 886 $wfh->flush(); 887 888 } else { 889 eval { server_wait($setup->{config_file}, $rfh) }; 890 if ($@) { 891 warn($@); 892 exit 1; 893 } 894 895 exit 0; 896 } 897 898 # Stop server 899 server_stop($setup->{pid_file}); 900 $self->assert_child_ok($pid); 901 902 test_cleanup($setup->{log_file}, $ex); 903} 904 905sub pathdenyfilter_rnto_denied { 906 my $self = shift; 907 my $tmpdir = $self->{tmpdir}; 908 my $setup = test_setup($tmpdir, 'config'); 909 910 mkpath("$tmpdir/subdir.d"); 911 912 my $config = { 913 PidFile => $setup->{pid_file}, 914 ScoreboardFile => $setup->{scoreboard_file}, 915 SystemLog => $setup->{log_file}, 916 917 AuthUserFile => $setup->{auth_user_file}, 918 AuthGroupFile => $setup->{auth_group_file}, 919 DefaultChdir => '~', 920 921 PathDenyFilter => '\.dir$', 922 923 IfModules => { 924 'mod_delay.c' => { 925 DelayEngine => 'off', 926 }, 927 }, 928 }; 929 930 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 931 $config); 932 933 # Open pipes, for use between the parent and child processes. Specifically, 934 # the child will indicate when it's done with its test by writing a message 935 # to the parent. 936 my ($rfh, $wfh); 937 unless (pipe($rfh, $wfh)) { 938 die("Can't open pipe: $!"); 939 } 940 941 my $ex; 942 943 # Fork child 944 $self->handle_sigchld(); 945 defined(my $pid = fork()) or die("Can't fork: $!"); 946 if ($pid) { 947 eval { 948 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 949 $client->login($setup->{user}, $setup->{passwd}); 950 951 $client->rnfr('subdir.d'); 952 my $dirname = 'foo.dir'; 953 954 eval { $client->rnto($dirname) }; 955 unless ($@) { 956 die("RNTO $dirname succeeded unexpectedly"); 957 } 958 959 my $resp_code = $client->response_code(); 960 my $resp_msg = $client->response_msg(); 961 962 my $expected = 550; 963 $self->assert($expected == $resp_code, 964 test_msg("Expected response code $expected, got $resp_code")); 965 966 $expected = "$dirname: Forbidden filename"; 967 $self->assert($expected eq $resp_msg, 968 test_msg("Expected response message '$expected', got '$resp_msg'")); 969 970 $client->quit(); 971 }; 972 if ($@) { 973 $ex = $@; 974 } 975 976 $wfh->print("done\n"); 977 $wfh->flush(); 978 979 } else { 980 eval { server_wait($setup->{config_file}, $rfh) }; 981 if ($@) { 982 warn($@); 983 exit 1; 984 } 985 986 exit 0; 987 } 988 989 # Stop server 990 server_stop($setup->{pid_file}); 991 $self->assert_child_ok($pid); 992 993 test_cleanup($setup->{log_file}, $ex); 994} 995 996sub pathdenyfilter_stor_allowed { 997 my $self = shift; 998 my $tmpdir = $self->{tmpdir}; 999 my $setup = test_setup($tmpdir, 'config'); 1000 1001 my $config = { 1002 PidFile => $setup->{pid_file}, 1003 ScoreboardFile => $setup->{scoreboard_file}, 1004 SystemLog => $setup->{log_file}, 1005 1006 AuthUserFile => $setup->{auth_user_file}, 1007 AuthGroupFile => $setup->{auth_group_file}, 1008 DefaultChdir => '~', 1009 1010 AllowOverwrite => 'on', 1011 PathDenyFilter => '\.jpg$', 1012 1013 IfModules => { 1014 'mod_delay.c' => { 1015 DelayEngine => 'off', 1016 }, 1017 }, 1018 }; 1019 1020 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1021 $config); 1022 1023 # Open pipes, for use between the parent and child processes. Specifically, 1024 # the child will indicate when it's done with its test by writing a message 1025 # to the parent. 1026 my ($rfh, $wfh); 1027 unless (pipe($rfh, $wfh)) { 1028 die("Can't open pipe: $!"); 1029 } 1030 1031 my $ex; 1032 1033 # Fork child 1034 $self->handle_sigchld(); 1035 defined(my $pid = fork()) or die("Can't fork: $!"); 1036 if ($pid) { 1037 eval { 1038 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1039 $client->login($setup->{user}, $setup->{passwd}); 1040 1041 my $conn = $client->stor_raw('test.txt'); 1042 unless ($conn) { 1043 die("Failed to STOR test.txt: " . $client->response_code() . " " . 1044 $client->response_msg()); 1045 } 1046 1047 my $buf = "Hello, World!\n"; 1048 $conn->write($buf, length($buf)); 1049 $conn->close(); 1050 1051 my $resp_code = $client->response_code(); 1052 my $resp_msg = $client->response_msg(); 1053 1054 my $expected = 226; 1055 $self->assert($expected == $resp_code, 1056 test_msg("Expected response code $expected, got $resp_code")); 1057 1058 $expected = 'Transfer complete'; 1059 $self->assert($expected eq $resp_msg, 1060 test_msg("Expected response message '$expected', got '$resp_msg'")); 1061 1062 $client->quit(); 1063 }; 1064 if ($@) { 1065 $ex = $@; 1066 } 1067 1068 $wfh->print("done\n"); 1069 $wfh->flush(); 1070 1071 } else { 1072 eval { server_wait($setup->{config_file}, $rfh) }; 1073 if ($@) { 1074 warn($@); 1075 exit 1; 1076 } 1077 1078 exit 0; 1079 } 1080 1081 # Stop server 1082 server_stop($setup->{pid_file}); 1083 $self->assert_child_ok($pid); 1084 1085 test_cleanup($setup->{log_file}, $ex); 1086} 1087 1088sub pathdenyfilter_stor_denied { 1089 my $self = shift; 1090 my $tmpdir = $self->{tmpdir}; 1091 my $setup = test_setup($tmpdir, 'config'); 1092 1093 my $config = { 1094 PidFile => $setup->{pid_file}, 1095 ScoreboardFile => $setup->{scoreboard_file}, 1096 SystemLog => $setup->{log_file}, 1097 1098 AuthUserFile => $setup->{auth_user_file}, 1099 AuthGroupFile => $setup->{auth_group_file}, 1100 DefaultChdir => '~', 1101 1102 AllowOverwrite => 'on', 1103 PathDenyFilter => '\.jpg$', 1104 1105 IfModules => { 1106 'mod_delay.c' => { 1107 DelayEngine => 'off', 1108 }, 1109 }, 1110 }; 1111 1112 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1113 $config); 1114 1115 # Open pipes, for use between the parent and child processes. Specifically, 1116 # the child will indicate when it's done with its test by writing a message 1117 # to the parent. 1118 my ($rfh, $wfh); 1119 unless (pipe($rfh, $wfh)) { 1120 die("Can't open pipe: $!"); 1121 } 1122 1123 my $ex; 1124 1125 # Fork child 1126 $self->handle_sigchld(); 1127 defined(my $pid = fork()) or die("Can't fork: $!"); 1128 if ($pid) { 1129 eval { 1130 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1131 $client->login($setup->{user}, $setup->{passwd}); 1132 1133 my $filename = 'test.jpg'; 1134 1135 my $conn = $client->stor_raw($filename); 1136 if ($conn) { 1137 die("STOR test.txt succeeded unexpectedly"); 1138 } 1139 1140 my $resp_code = $client->response_code(); 1141 my $resp_msg = $client->response_msg(); 1142 1143 my $expected = 550; 1144 $self->assert($expected == $resp_code, 1145 test_msg("Expected response code $expected, got $resp_code")); 1146 1147 $expected = "$filename: Forbidden filename"; 1148 $self->assert($expected eq $resp_msg, 1149 test_msg("Expected response message '$expected', got '$resp_msg'")); 1150 1151 $client->quit(); 1152 }; 1153 if ($@) { 1154 $ex = $@; 1155 } 1156 1157 $wfh->print("done\n"); 1158 $wfh->flush(); 1159 1160 } else { 1161 eval { server_wait($setup->{config_file}, $rfh) }; 1162 if ($@) { 1163 warn($@); 1164 exit 1; 1165 } 1166 1167 exit 0; 1168 } 1169 1170 # Stop server 1171 server_stop($setup->{pid_file}); 1172 $self->assert_child_ok($pid); 1173 1174 test_cleanup($setup->{log_file}, $ex); 1175} 1176 1177sub pathdenyfilter_stor_denied_bug3032 { 1178 my $self = shift; 1179 my $tmpdir = $self->{tmpdir}; 1180 my $setup = test_setup($tmpdir, 'config'); 1181 1182 my $config = { 1183 PidFile => $setup->{pid_file}, 1184 ScoreboardFile => $setup->{scoreboard_file}, 1185 SystemLog => $setup->{log_file}, 1186 1187 AuthUserFile => $setup->{auth_user_file}, 1188 AuthGroupFile => $setup->{auth_group_file}, 1189 DefaultChdir => '~', 1190 1191 AllowOverwrite => 'on', 1192 PathDenyFilter => '[^[:print:]]', 1193 1194 IfModules => { 1195 'mod_delay.c' => { 1196 DelayEngine => 'off', 1197 }, 1198 }, 1199 }; 1200 1201 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1202 $config); 1203 1204 # Open pipes, for use between the parent and child processes. Specifically, 1205 # the child will indicate when it's done with its test by writing a message 1206 # to the parent. 1207 my ($rfh, $wfh); 1208 unless (pipe($rfh, $wfh)) { 1209 die("Can't open pipe: $!"); 1210 } 1211 1212 my $ex; 1213 1214 # Fork child 1215 $self->handle_sigchld(); 1216 defined(my $pid = fork()) or die("Can't fork: $!"); 1217 if ($pid) { 1218 eval { 1219 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1220 $client->login($setup->{user}, $setup->{passwd}); 1221 1222 my $filename = "test\b"; 1223 1224 my $conn = $client->stor_raw($filename); 1225 if ($conn) { 1226 die("STOR test.txt succeeded unexpectedly"); 1227 } 1228 1229 my $resp_code = $client->response_code(); 1230 my $resp_msg = $client->response_msg(); 1231 1232 my $expected = 550; 1233 $self->assert($expected == $resp_code, 1234 test_msg("Expected response code $expected, got $resp_code")); 1235 1236 $expected = "$filename: Forbidden filename"; 1237 $self->assert($expected eq $resp_msg, 1238 test_msg("Expected response message '$expected', got '$resp_msg'")); 1239 1240 $client->quit(); 1241 }; 1242 if ($@) { 1243 $ex = $@; 1244 } 1245 1246 $wfh->print("done\n"); 1247 $wfh->flush(); 1248 1249 } else { 1250 eval { server_wait($setup->{config_file}, $rfh) }; 1251 if ($@) { 1252 warn($@); 1253 exit 1; 1254 } 1255 1256 exit 0; 1257 } 1258 1259 # Stop server 1260 server_stop($setup->{pid_file}); 1261 $self->assert_child_ok($pid); 1262 1263 test_cleanup($setup->{log_file}, $ex); 1264} 1265 1266sub pathdenyfilter_stor_trailing_space { 1267 my $self = shift; 1268 my $tmpdir = $self->{tmpdir}; 1269 my $setup = test_setup($tmpdir, 'config'); 1270 1271 my $config = { 1272 PidFile => $setup->{pid_file}, 1273 ScoreboardFile => $setup->{scoreboard_file}, 1274 SystemLog => $setup->{log_file}, 1275 1276 AuthUserFile => $setup->{auth_user_file}, 1277 AuthGroupFile => $setup->{auth_group_file}, 1278 DefaultChdir => '~', 1279 1280 AllowOverwrite => 'on', 1281 PathDenyFilter => '"\.* $"', 1282 1283 IfModules => { 1284 'mod_delay.c' => { 1285 DelayEngine => 'off', 1286 }, 1287 }, 1288 }; 1289 1290 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1291 $config); 1292 1293 # Open pipes, for use between the parent and child processes. Specifically, 1294 # the child will indicate when it's done with its test by writing a message 1295 # to the parent. 1296 my ($rfh, $wfh); 1297 unless (pipe($rfh, $wfh)) { 1298 die("Can't open pipe: $!"); 1299 } 1300 1301 my $ex; 1302 1303 # Fork child 1304 $self->handle_sigchld(); 1305 defined(my $pid = fork()) or die("Can't fork: $!"); 1306 if ($pid) { 1307 eval { 1308 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1309 $client->login($setup->{user}, $setup->{passwd}); 1310 1311 my $filename = 'test '; 1312 1313 my $conn = $client->stor_raw($filename); 1314 if ($conn) { 1315 die("STOR $filename succeeded unexpectedly"); 1316 } 1317 1318 my $resp_code = $client->response_code(); 1319 my $resp_msg = $client->response_msg(); 1320 1321 my $expected = 550; 1322 $self->assert($expected == $resp_code, 1323 test_msg("Expected response code $expected, got $resp_code")); 1324 1325 $expected = "$filename: Forbidden filename"; 1326 $self->assert($expected eq $resp_msg, 1327 test_msg("Expected response message '$expected', got '$resp_msg'")); 1328 1329 $client->quit(); 1330 }; 1331 if ($@) { 1332 $ex = $@; 1333 } 1334 1335 $wfh->print("done\n"); 1336 $wfh->flush(); 1337 1338 } else { 1339 eval { server_wait($setup->{config_file}, $rfh) }; 1340 if ($@) { 1341 warn($@); 1342 exit 1; 1343 } 1344 1345 exit 0; 1346 } 1347 1348 # Stop server 1349 server_stop($setup->{pid_file}); 1350 $self->assert_child_ok($pid); 1351 1352 test_cleanup($setup->{log_file}, $ex); 1353} 1354 1355sub pathdenyfilter_stor_leading_space { 1356 my $self = shift; 1357 my $tmpdir = $self->{tmpdir}; 1358 my $setup = test_setup($tmpdir, 'config'); 1359 1360 my $config = { 1361 PidFile => $setup->{pid_file}, 1362 ScoreboardFile => $setup->{scoreboard_file}, 1363 SystemLog => $setup->{log_file}, 1364 1365 AuthUserFile => $setup->{auth_user_file}, 1366 AuthGroupFile => $setup->{auth_group_file}, 1367 DefaultChdir => '~', 1368 1369 AllowOverwrite => 'on', 1370 PathDenyFilter => '"(\.*/)? [^/]*$"', 1371 1372 IfModules => { 1373 'mod_delay.c' => { 1374 DelayEngine => 'off', 1375 }, 1376 }, 1377 }; 1378 1379 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1380 $config); 1381 1382 # Open pipes, for use between the parent and child processes. Specifically, 1383 # the child will indicate when it's done with its test by writing a message 1384 # to the parent. 1385 my ($rfh, $wfh); 1386 unless (pipe($rfh, $wfh)) { 1387 die("Can't open pipe: $!"); 1388 } 1389 1390 my $ex; 1391 1392 # Fork child 1393 $self->handle_sigchld(); 1394 defined(my $pid = fork()) or die("Can't fork: $!"); 1395 if ($pid) { 1396 eval { 1397 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1398 $client->login($setup->{user}, $setup->{passwd}); 1399 1400 my $filename = ' test'; 1401 1402 my $conn = $client->stor_raw($filename); 1403 if ($conn) { 1404 die("STOR $filename succeeded unexpectedly"); 1405 } 1406 1407 my $resp_code = $client->response_code(); 1408 my $resp_msg = $client->response_msg(); 1409 1410 my $expected = 550; 1411 $self->assert($expected == $resp_code, 1412 test_msg("Expected response code $expected, got $resp_code")); 1413 1414 $expected = "$filename: Forbidden filename"; 1415 $self->assert($expected eq $resp_msg, 1416 test_msg("Expected response message '$expected', got '$resp_msg'")); 1417 1418 $client->quit(); 1419 }; 1420 if ($@) { 1421 $ex = $@; 1422 } 1423 1424 $wfh->print("done\n"); 1425 $wfh->flush(); 1426 1427 } else { 1428 eval { server_wait($setup->{config_file}, $rfh) }; 1429 if ($@) { 1430 warn($@); 1431 exit 1; 1432 } 1433 1434 exit 0; 1435 } 1436 1437 # Stop server 1438 server_stop($setup->{pid_file}); 1439 $self->assert_child_ok($pid); 1440 1441 test_cleanup($setup->{log_file}, $ex); 1442} 1443 1444sub pathdenyfilter_stor_leading_trailing_space { 1445 my $self = shift; 1446 my $tmpdir = $self->{tmpdir}; 1447 my $setup = test_setup($tmpdir, 'config'); 1448 1449 my $config = { 1450 PidFile => $setup->{pid_file}, 1451 ScoreboardFile => $setup->{scoreboard_file}, 1452 SystemLog => $setup->{log_file}, 1453 1454 AuthUserFile => $setup->{auth_user_file}, 1455 AuthGroupFile => $setup->{auth_group_file}, 1456 DefaultChdir => '~', 1457 1458 AllowOverwrite => 'on', 1459 PathDenyFilter => '"(\.*/)?( [^/]*$|\.* $)"', 1460 1461 IfModules => { 1462 'mod_delay.c' => { 1463 DelayEngine => 'off', 1464 }, 1465 }, 1466 }; 1467 1468 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1469 $config); 1470 1471 # Open pipes, for use between the parent and child processes. Specifically, 1472 # the child will indicate when it's done with its test by writing a message 1473 # to the parent. 1474 my ($rfh, $wfh); 1475 unless (pipe($rfh, $wfh)) { 1476 die("Can't open pipe: $!"); 1477 } 1478 1479 my $ex; 1480 1481 # Fork child 1482 $self->handle_sigchld(); 1483 defined(my $pid = fork()) or die("Can't fork: $!"); 1484 if ($pid) { 1485 eval { 1486 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1487 $client->login($setup->{user}, $setup->{passwd}); 1488 1489 my $filename = ' test '; 1490 1491 my $conn = $client->stor_raw($filename); 1492 if ($conn) { 1493 die("STOR $filename succeeded unexpectedly"); 1494 } 1495 1496 my $resp_code = $client->response_code(); 1497 my $resp_msg = $client->response_msg(); 1498 1499 my $expected = 550; 1500 $self->assert($expected == $resp_code, 1501 test_msg("Expected response code $expected, got $resp_code")); 1502 1503 $expected = "$filename: Forbidden filename"; 1504 $self->assert($expected eq $resp_msg, 1505 test_msg("Expected response message '$expected', got '$resp_msg'")); 1506 1507 $client->quit(); 1508 }; 1509 if ($@) { 1510 $ex = $@; 1511 } 1512 1513 $wfh->print("done\n"); 1514 $wfh->flush(); 1515 1516 } else { 1517 eval { server_wait($setup->{config_file}, $rfh) }; 1518 if ($@) { 1519 warn($@); 1520 exit 1; 1521 } 1522 1523 exit 0; 1524 } 1525 1526 # Stop server 1527 server_stop($setup->{pid_file}); 1528 $self->assert_child_ok($pid); 1529 1530 test_cleanup($setup->{log_file}, $ex); 1531} 1532 1533sub pathdenyfilter_stor_denied_nocase_bug3592 { 1534 my $self = shift; 1535 my $tmpdir = $self->{tmpdir}; 1536 my $setup = test_setup($tmpdir, 'config'); 1537 1538 my $config = { 1539 PidFile => $setup->{pid_file}, 1540 ScoreboardFile => $setup->{scoreboard_file}, 1541 SystemLog => $setup->{log_file}, 1542 1543 AuthUserFile => $setup->{auth_user_file}, 1544 AuthGroupFile => $setup->{auth_group_file}, 1545 DefaultChdir => '~', 1546 1547 AllowOverwrite => 'on', 1548 PathDenyFilter => '\.jpg$ [nocase]', 1549 1550 IfModules => { 1551 'mod_delay.c' => { 1552 DelayEngine => 'off', 1553 }, 1554 }, 1555 }; 1556 1557 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1558 $config); 1559 1560 # Open pipes, for use between the parent and child processes. Specifically, 1561 # the child will indicate when it's done with its test by writing a message 1562 # to the parent. 1563 my ($rfh, $wfh); 1564 unless (pipe($rfh, $wfh)) { 1565 die("Can't open pipe: $!"); 1566 } 1567 1568 my $ex; 1569 1570 # Fork child 1571 $self->handle_sigchld(); 1572 defined(my $pid = fork()) or die("Can't fork: $!"); 1573 if ($pid) { 1574 eval { 1575 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1576 $client->login($setup->{user}, $setup->{passwd}); 1577 1578 my $filename = 'test.JpG'; 1579 1580 my $conn = $client->stor_raw($filename); 1581 if ($conn) { 1582 die("STOR test.txt succeeded unexpectedly"); 1583 } 1584 1585 my $resp_code = $client->response_code(); 1586 my $resp_msg = $client->response_msg(); 1587 1588 my $expected = 550; 1589 $self->assert($expected == $resp_code, 1590 test_msg("Expected response code $expected, got $resp_code")); 1591 1592 $expected = "$filename: Forbidden filename"; 1593 $self->assert($expected eq $resp_msg, 1594 test_msg("Expected response message '$expected', got '$resp_msg'")); 1595 1596 $client->quit(); 1597 }; 1598 if ($@) { 1599 $ex = $@; 1600 } 1601 1602 $wfh->print("done\n"); 1603 $wfh->flush(); 1604 1605 } else { 1606 eval { server_wait($setup->{config_file}, $rfh) }; 1607 if ($@) { 1608 warn($@); 1609 exit 1; 1610 } 1611 1612 exit 0; 1613 } 1614 1615 # Stop server 1616 server_stop($setup->{pid_file}); 1617 $self->assert_child_ok($pid); 1618 1619 test_cleanup($setup->{log_file}, $ex); 1620} 1621 1622sub pathdenyfilter_stor_dotfiles_denied { 1623 my $self = shift; 1624 my $tmpdir = $self->{tmpdir}; 1625 my $setup = test_setup($tmpdir, 'config'); 1626 1627 my $config = { 1628 PidFile => $setup->{pid_file}, 1629 ScoreboardFile => $setup->{scoreboard_file}, 1630 SystemLog => $setup->{log_file}, 1631 TraceLog => $setup->{log_file}, 1632 Trace => 'filter:10', 1633 1634 AuthUserFile => $setup->{auth_user_file}, 1635 AuthGroupFile => $setup->{auth_group_file}, 1636 DefaultChdir => '~', 1637 1638 AllowOverwrite => 'on', 1639 PathDenyFilter => '\.[^/]*$', 1640 1641 IfModules => { 1642 'mod_delay.c' => { 1643 DelayEngine => 'off', 1644 }, 1645 }, 1646 }; 1647 1648 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1649 $config); 1650 1651 # Open pipes, for use between the parent and child processes. Specifically, 1652 # the child will indicate when it's done with its test by writing a message 1653 # to the parent. 1654 my ($rfh, $wfh); 1655 unless (pipe($rfh, $wfh)) { 1656 die("Can't open pipe: $!"); 1657 } 1658 1659 my $ex; 1660 1661 # Fork child 1662 $self->handle_sigchld(); 1663 defined(my $pid = fork()) or die("Can't fork: $!"); 1664 if ($pid) { 1665 eval { 1666 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1667 $client->login($setup->{user}, $setup->{passwd}); 1668 1669 my $filename = '.ftpaccess'; 1670 1671 my $conn = $client->stor_raw($filename); 1672 if ($conn) { 1673 die("STOR $filename succeeded unexpectedly"); 1674 } 1675 1676 my $resp_code = $client->response_code(); 1677 my $resp_msg = $client->response_msg(); 1678 1679 my $expected = 550; 1680 $self->assert($expected == $resp_code, 1681 test_msg("Expected response code $expected, got $resp_code")); 1682 1683 $expected = "$filename: Forbidden filename"; 1684 $self->assert($expected eq $resp_msg, 1685 test_msg("Expected response message '$expected', got '$resp_msg'")); 1686 1687 $client->quit(); 1688 }; 1689 if ($@) { 1690 $ex = $@; 1691 } 1692 1693 $wfh->print("done\n"); 1694 $wfh->flush(); 1695 1696 } else { 1697 eval { server_wait($setup->{config_file}, $rfh) }; 1698 if ($@) { 1699 warn($@); 1700 exit 1; 1701 } 1702 1703 exit 0; 1704 } 1705 1706 # Stop server 1707 server_stop($setup->{pid_file}); 1708 $self->assert_child_ok($pid); 1709 1710 test_cleanup($setup->{log_file}, $ex); 1711} 1712 17131; 1714