1package ProFTPD::Tests::Config::Limit::Anonymous; 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 anon_limit_write => { 20 order => ++$order, 21 test_class => [qw(forking rootprivs)], 22 }, 23 24 anon_limit_write_changing_dirs => { 25 order => ++$order, 26 test_class => [qw(forking rootprivs)], 27 }, 28 29 anon_limit_write_with_ftpaccess => { 30 order => ++$order, 31 test_class => [qw(forking rootprivs)], 32 }, 33 34 anon_limit_login_dns_name => { 35 order => ++$order, 36 test_class => [qw(forking rootprivs)], 37 }, 38 39 anon_limit_write_allow_stor_using_abs_path => { 40 order => ++$order, 41 test_class => [qw(forking rootprivs)], 42 }, 43 44 anon_limit_write_allow_stor_using_rel_path => { 45 order => ++$order, 46 test_class => [qw(forking rootprivs)], 47 }, 48 49}; 50 51sub new { 52 return shift()->SUPER::new(@_); 53} 54 55sub list_tests { 56 return testsuite_get_runnable_tests($TESTS); 57} 58 59sub anon_limit_write { 60 my $self = shift; 61 my $tmpdir = $self->{tmpdir}; 62 63 my $config_file = "$tmpdir/limit.conf"; 64 my $pid_file = File::Spec->rel2abs("$tmpdir/limit.pid"); 65 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/limit.scoreboard"); 66 67 my $log_file = File::Spec->rel2abs('tests.log'); 68 69 my $auth_user_file = File::Spec->rel2abs("$tmpdir/limit.passwd"); 70 my $auth_group_file = File::Spec->rel2abs("$tmpdir/limit.group"); 71 72 my ($config_user, $config_group) = config_get_identity(); 73 74 my $anon_dir = File::Spec->rel2abs($tmpdir); 75 my $uid = 500; 76 my $gid = 500; 77 78 # Make sure that, if we're running as root, that the home directory has 79 # permissions/privs set for the account we create 80 if ($< == 0) { 81 unless (chmod(0755, $anon_dir)) { 82 die("Can't set perms on $anon_dir to 0755: $!"); 83 } 84 85 unless (chown($uid, $gid, $anon_dir)) { 86 die("Can't set owner of $anon_dir to $uid/$gid: $!"); 87 } 88 } 89 90 auth_user_write($auth_user_file, $config_user, 'test', $uid, $gid, '/tmp', 91 '/bin/bash'); 92 auth_group_write($auth_group_file, $config_group, $gid, $config_user); 93 94 # Test the config mentioned here: 95 # 96 # http://forums.proftpd.org/smf/index.php/topic,4076.0.html 97 # 98 # Specifically this portion: 99 # 100 # <Anonymous> 101 # <Directory *> 102 # <Limit WRITE> 103 # DenyAll 104 # </Limit> 105 # </Directory> 106 # </Anonymous> 107 # 108 # Does the use of '*' there allow creation of directories there? 109 110 my $config = { 111 PidFile => $pid_file, 112 ScoreboardFile => $scoreboard_file, 113 SystemLog => $log_file, 114 115 AuthUserFile => $auth_user_file, 116 AuthGroupFile => $auth_group_file, 117 118 IfModules => { 119 'mod_delay.c' => { 120 DelayEngine => 'off', 121 }, 122 }, 123 }; 124 125 my ($port, $user, $group) = config_write($config_file, $config); 126 127 if (open(my $fh, ">> $config_file")) { 128 print $fh <<EOC; 129<Anonymous $anon_dir> 130 User $config_user 131 Group $config_group 132 UserAlias anonymous $config_user 133 RequireValidShell off 134 135 <Directory *> 136 <Limit WRITE> 137 DenyAll 138 </Limit> 139 </Directory> 140</Anonymous> 141EOC 142 unless (close($fh)) { 143 die("Can't write $config_file: $!"); 144 } 145 146 } else { 147 die("Can't open $config_file: $!"); 148 } 149 150 # Open pipes, for use between the parent and child processes. Specifically, 151 # the child will indicate when it's done with its test by writing a message 152 # to the parent. 153 my ($rfh, $wfh); 154 unless (pipe($rfh, $wfh)) { 155 die("Can't open pipe: $!"); 156 } 157 158 my $ex; 159 160 # Fork child 161 $self->handle_sigchld(); 162 defined(my $pid = fork()) or die("Can't fork: $!"); 163 if ($pid) { 164 eval { 165 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 166 $client->login('anonymous', 'ftp@nospam.org'); 167 168 eval { $client->mkd('testdir') }; 169 unless ($@) { 170 die("MKD testdir succeeded unexpectedly"); 171 } 172 173 my $resp_code = $client->response_code(); 174 my $resp_msg = $client->response_msg(); 175 176 my $expected; 177 178 $expected = 550; 179 $self->assert($expected == $resp_code, 180 test_msg("Expected response code $expected, got $resp_code")); 181 182 $expected = "testdir: Permission denied"; 183 $self->assert($expected eq $resp_msg, 184 test_msg("Expected response message '$expected', got '$resp_msg'")); 185 }; 186 187 if ($@) { 188 $ex = $@; 189 } 190 191 $wfh->print("done\n"); 192 $wfh->flush(); 193 194 } else { 195 eval { server_wait($config_file, $rfh) }; 196 if ($@) { 197 warn($@); 198 exit 1; 199 } 200 201 exit 0; 202 } 203 204 # Stop server 205 server_stop($pid_file); 206 207 $self->assert_child_ok($pid); 208 209 if ($ex) { 210 die($ex); 211 } 212 213 unlink($log_file); 214} 215 216sub anon_limit_write_changing_dirs { 217 my $self = shift; 218 my $tmpdir = $self->{tmpdir}; 219 220 my $config_file = "$tmpdir/limit.conf"; 221 my $pid_file = File::Spec->rel2abs("$tmpdir/limit.pid"); 222 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/limit.scoreboard"); 223 224 my $log_file = File::Spec->rel2abs('tests.log'); 225 226 my $auth_user_file = File::Spec->rel2abs("$tmpdir/limit.passwd"); 227 my $auth_group_file = File::Spec->rel2abs("$tmpdir/limit.group"); 228 229 my ($config_user, $config_group) = config_get_identity(); 230 231 my $anon_dir = File::Spec->rel2abs($tmpdir); 232 my $uid = 500; 233 my $gid = 500; 234 235 my $sub_dir = File::Spec->rel2abs("$tmpdir/subdir"); 236 mkpath($sub_dir); 237 238 # Make sure that, if we're running as root, that the home directory has 239 # permissions/privs set for the account we create 240 if ($< == 0) { 241 unless (chmod(0755, $anon_dir, $sub_dir)) { 242 die("Can't set perms on $anon_dir, $sub_dir to 0755: $!"); 243 } 244 245 unless (chown($uid, $gid, $anon_dir, $sub_dir)) { 246 die("Can't set owner of $anon_dir, $sub_dir to $uid/$gid: $!"); 247 } 248 } 249 250 auth_user_write($auth_user_file, $config_user, 'test', $uid, $gid, '/tmp', 251 '/bin/bash'); 252 auth_group_write($auth_group_file, $config_group, $gid, $config_user); 253 254 # Test the config mentioned here: 255 # 256 # http://forums.proftpd.org/smf/index.php/topic,4076.0.html 257 # 258 # Specifically this portion: 259 # 260 # <Anonymous> 261 # <Directory *> 262 # <Limit WRITE> 263 # DenyAll 264 # </Limit> 265 # </Directory> 266 # </Anonymous> 267 # 268 # Does the use of '*' there allow creation of directories there? 269 270 my $config = { 271 PidFile => $pid_file, 272 ScoreboardFile => $scoreboard_file, 273 SystemLog => $log_file, 274 275 AuthUserFile => $auth_user_file, 276 AuthGroupFile => $auth_group_file, 277 278 IfModules => { 279 'mod_delay.c' => { 280 DelayEngine => 'off', 281 }, 282 }, 283 }; 284 285 my ($port, $user, $group) = config_write($config_file, $config); 286 287 if (open(my $fh, ">> $config_file")) { 288 print $fh <<EOC; 289<Anonymous $anon_dir> 290 User $config_user 291 Group $config_group 292 UserAlias anonymous $config_user 293 RequireValidShell off 294 295 <Directory *> 296 <Limit WRITE> 297 DenyAll 298 </Limit> 299 </Directory> 300</Anonymous> 301EOC 302 unless (close($fh)) { 303 die("Can't write $config_file: $!"); 304 } 305 306 } else { 307 die("Can't open $config_file: $!"); 308 } 309 310 # Open pipes, for use between the parent and child processes. Specifically, 311 # the child will indicate when it's done with its test by writing a message 312 # to the parent. 313 my ($rfh, $wfh); 314 unless (pipe($rfh, $wfh)) { 315 die("Can't open pipe: $!"); 316 } 317 318 my $ex; 319 320 # Fork child 321 $self->handle_sigchld(); 322 defined(my $pid = fork()) or die("Can't fork: $!"); 323 if ($pid) { 324 eval { 325 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 326 $client->login('anonymous', 'ftp@nospam.org'); 327 $client->cwd('subdir'); 328 329 eval { $client->mkd('testdir') }; 330 unless ($@) { 331 die("MKD testdir succeeded unexpectedly"); 332 } 333 334 my $resp_code = $client->response_code(); 335 my $resp_msg = $client->response_msg(); 336 337 my $expected; 338 339 $expected = 550; 340 $self->assert($expected == $resp_code, 341 test_msg("Expected response code $expected, got $resp_code")); 342 343 $expected = "testdir: Permission denied"; 344 $self->assert($expected eq $resp_msg, 345 test_msg("Expected response message '$expected', got '$resp_msg'")); 346 347 # Now try to create a directory one level up from where we are 348 eval { $client->mkd('../testdir') }; 349 unless ($@) { 350 die("MKD ../testdir succeeded unexpectedly"); 351 } 352 353 $resp_code = $client->response_code(); 354 $resp_msg = $client->response_msg(); 355 356 $expected = 550; 357 $self->assert($expected == $resp_code, 358 test_msg("Expected response code $expected, got $resp_code")); 359 360 $expected = "../testdir: Permission denied"; 361 $self->assert($expected eq $resp_msg, 362 test_msg("Expected response message '$expected', got '$resp_msg'")); 363 }; 364 365 if ($@) { 366 $ex = $@; 367 } 368 369 $wfh->print("done\n"); 370 $wfh->flush(); 371 372 } else { 373 eval { server_wait($config_file, $rfh) }; 374 if ($@) { 375 warn($@); 376 exit 1; 377 } 378 379 exit 0; 380 } 381 382 # Stop server 383 server_stop($pid_file); 384 385 $self->assert_child_ok($pid); 386 387 if ($ex) { 388 die($ex); 389 } 390 391 unlink($log_file); 392} 393 394sub anon_limit_write_with_ftpaccess { 395 my $self = shift; 396 my $tmpdir = $self->{tmpdir}; 397 398 my $config_file = "$tmpdir/limit.conf"; 399 my $pid_file = File::Spec->rel2abs("$tmpdir/limit.pid"); 400 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/limit.scoreboard"); 401 402 my $log_file = File::Spec->rel2abs('tests.log'); 403 404 my $auth_user_file = File::Spec->rel2abs("$tmpdir/limit.passwd"); 405 my $auth_group_file = File::Spec->rel2abs("$tmpdir/limit.group"); 406 407 my ($config_user, $config_group) = config_get_identity(); 408 409 my $anon_dir = File::Spec->rel2abs($tmpdir); 410 my $uid = 500; 411 my $gid = 500; 412 413 my $sub_dir = File::Spec->rel2abs("$tmpdir/subdir"); 414 mkpath($sub_dir); 415 416 # Make sure that, if we're running as root, that the home directory has 417 # permissions/privs set for the account we create 418 if ($< == 0) { 419 unless (chmod(0755, $anon_dir, $sub_dir)) { 420 die("Can't set perms on $anon_dir, $sub_dir to 0755: $!"); 421 } 422 423 unless (chown($uid, $gid, $anon_dir, $sub_dir)) { 424 die("Can't set owner of $anon_dir, $sub_dir to $uid/$gid: $!"); 425 } 426 } 427 428 # Create a .ftpaccess file in the sub-directory. 429 if (open(my $fh, "> $anon_dir/.ftpaccess")) { 430 print $fh <<EOC; 431DirFakeUser on foo 432EOC 433 unless (close($fh)) { 434 die("Can't write $anon_dir/.ftpaccess: $!"); 435 } 436 437 } else { 438 die("Can't open $anon_dir/.ftpaccess: $!"); 439 } 440 441 auth_user_write($auth_user_file, $config_user, 'test', $uid, $gid, '/tmp', 442 '/bin/bash'); 443 auth_group_write($auth_group_file, $config_group, $gid, $config_user); 444 445 # Test the config mentioned here: 446 # 447 # http://forums.proftpd.org/smf/index.php/topic,4076.0.html 448 # 449 # Specifically this portion: 450 # 451 # <Anonymous> 452 # <Directory *> 453 # <Limit WRITE> 454 # DenyAll 455 # </Limit> 456 # </Directory> 457 # </Anonymous> 458 # 459 # Does the use of '*' there allow creation of directories there? 460 461 my $config = { 462 PidFile => $pid_file, 463 ScoreboardFile => $scoreboard_file, 464 SystemLog => $log_file, 465 466 AuthUserFile => $auth_user_file, 467 AuthGroupFile => $auth_group_file, 468 469 AllowOverride => 'on', 470 471 IfModules => { 472 'mod_delay.c' => { 473 DelayEngine => 'off', 474 }, 475 }, 476 }; 477 478 my ($port, $user, $group) = config_write($config_file, $config); 479 480 if (open(my $fh, ">> $config_file")) { 481 print $fh <<EOC; 482<Anonymous $anon_dir> 483 User $config_user 484 Group $config_group 485 UserAlias anonymous $config_user 486 RequireValidShell off 487 488 <Directory *> 489 <Limit WRITE> 490 DenyAll 491 </Limit> 492 </Directory> 493</Anonymous> 494EOC 495 unless (close($fh)) { 496 die("Can't write $config_file: $!"); 497 } 498 499 } else { 500 die("Can't open $config_file: $!"); 501 } 502 503 # Open pipes, for use between the parent and child processes. Specifically, 504 # the child will indicate when it's done with its test by writing a message 505 # to the parent. 506 my ($rfh, $wfh); 507 unless (pipe($rfh, $wfh)) { 508 die("Can't open pipe: $!"); 509 } 510 511 my $ex; 512 513 # Fork child 514 $self->handle_sigchld(); 515 defined(my $pid = fork()) or die("Can't fork: $!"); 516 if ($pid) { 517 eval { 518 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 519 $client->login('anonymous', 'ftp@nospam.org'); 520 $client->cwd('subdir'); 521 522 eval { $client->mkd('testdir') }; 523 unless ($@) { 524 die("MKD testdir succeeded unexpectedly"); 525 } 526 527 my $resp_code = $client->response_code(); 528 my $resp_msg = $client->response_msg(); 529 530 my $expected; 531 532 $expected = 550; 533 $self->assert($expected == $resp_code, 534 test_msg("Expected response code $expected, got $resp_code")); 535 536 $expected = "testdir: Permission denied"; 537 $self->assert($expected eq $resp_msg, 538 test_msg("Expected response message '$expected', got '$resp_msg'")); 539 540 # Now try to create a directory one level up from where we are 541 eval { $client->mkd('../testdir') }; 542 unless ($@) { 543 die("MKD ../testdir succeeded unexpectedly"); 544 } 545 546 $resp_code = $client->response_code(); 547 $resp_msg = $client->response_msg(); 548 549 $expected = 550; 550 $self->assert($expected == $resp_code, 551 test_msg("Expected response code $expected, got $resp_code")); 552 553 $expected = "../testdir: Permission denied"; 554 $self->assert($expected eq $resp_msg, 555 test_msg("Expected response message '$expected', got '$resp_msg'")); 556 557 $client->cwd('/'); 558 559 eval { $client->mkd('testdir') }; 560 unless ($@) { 561 die("MKD testdir succeeded unexpectedly"); 562 } 563 564 $resp_code = $client->response_code(); 565 $resp_msg = $client->response_msg(); 566 567 $expected = 550; 568 $self->assert($expected == $resp_code, 569 test_msg("Expected response code $expected, got $resp_code")); 570 571 $expected = "testdir: Permission denied"; 572 $self->assert($expected eq $resp_msg, 573 test_msg("Expected response message '$expected', got '$resp_msg'")); 574 }; 575 576 if ($@) { 577 $ex = $@; 578 } 579 580 $wfh->print("done\n"); 581 $wfh->flush(); 582 583 } else { 584 eval { server_wait($config_file, $rfh) }; 585 if ($@) { 586 warn($@); 587 exit 1; 588 } 589 590 exit 0; 591 } 592 593 # Stop server 594 server_stop($pid_file); 595 596 $self->assert_child_ok($pid); 597 598 if ($ex) { 599 die($ex); 600 } 601 602 unlink($log_file); 603} 604 605sub anon_limit_login_dns_name { 606 my $self = shift; 607 my $tmpdir = $self->{tmpdir}; 608 609 my $config_file = "$tmpdir/limit.conf"; 610 my $pid_file = File::Spec->rel2abs("$tmpdir/limit.pid"); 611 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/limit.scoreboard"); 612 613 my $log_file = File::Spec->rel2abs('tests.log'); 614 615 my $auth_user_file = File::Spec->rel2abs("$tmpdir/limit.passwd"); 616 my $auth_group_file = File::Spec->rel2abs("$tmpdir/limit.group"); 617 618 my ($config_user, $config_group) = config_get_identity(); 619 620 my $anon_dir = File::Spec->rel2abs($tmpdir); 621 my $uid = 500; 622 my $gid = 500; 623 624 # Make sure that, if we're running as root, that the home directory has 625 # permissions/privs set for the account we create 626 if ($< == 0) { 627 unless (chmod(0755, $anon_dir)) { 628 die("Can't set perms on $anon_dir to 0755: $!"); 629 } 630 631 unless (chown($uid, $gid, $anon_dir)) { 632 die("Can't set owner of $anon_dir to $uid/$gid: $!"); 633 } 634 } 635 636 auth_user_write($auth_user_file, $config_user, 'test', $uid, $gid, '/tmp', 637 '/bin/bash'); 638 auth_group_write($auth_group_file, $config_group, $gid, $config_user); 639 640 # Test the config mentioned here: 641 # 642 # http://forums.proftpd.org/smf/index.php/topic,4436.0.html 643 # 644 # Specifically this portion: 645 # 646 # <Anonymous> 647 # <Limit LOGIN> 648 # Allow from <dns-name> 649 # DenyAll 650 # </Limit> 651 # </Anonymous> 652 653 my $config = { 654 PidFile => $pid_file, 655 ScoreboardFile => $scoreboard_file, 656 SystemLog => $log_file, 657 TraceLog => $log_file, 658 Trace => 'DEFAULT:10 netacl:10 netaddr:10 dns:10', 659 660 AuthUserFile => $auth_user_file, 661 AuthGroupFile => $auth_group_file, 662 UseReverseDNS => 'on', 663 664 IfModules => { 665 'mod_delay.c' => { 666 DelayEngine => 'off', 667 }, 668 }, 669 }; 670 671 my ($port, $user, $group) = config_write($config_file, $config); 672 673 if (open(my $fh, ">> $config_file")) { 674 print $fh <<EOC; 675<Anonymous $anon_dir> 676 User $config_user 677 Group $config_group 678 UserAlias anonymous $config_user 679 RequireValidShell off 680 681 <Limit LOGIN> 682 Allow from localhost 683 DenyAll 684 </Limit> 685</Anonymous> 686EOC 687 unless (close($fh)) { 688 die("Can't write $config_file: $!"); 689 } 690 691 } else { 692 die("Can't open $config_file: $!"); 693 } 694 695 # Open pipes, for use between the parent and child processes. Specifically, 696 # the child will indicate when it's done with its test by writing a message 697 # to the parent. 698 my ($rfh, $wfh); 699 unless (pipe($rfh, $wfh)) { 700 die("Can't open pipe: $!"); 701 } 702 703 my $ex; 704 705 # Fork child 706 $self->handle_sigchld(); 707 defined(my $pid = fork()) or die("Can't fork: $!"); 708 if ($pid) { 709 eval { 710 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 711 $client->login('anonymous', 'ftp@nospam.org'); 712 }; 713 714 if ($@) { 715 $ex = $@; 716 } 717 718 $wfh->print("done\n"); 719 $wfh->flush(); 720 721 } else { 722 eval { server_wait($config_file, $rfh) }; 723 if ($@) { 724 warn($@); 725 exit 1; 726 } 727 728 exit 0; 729 } 730 731 # Stop server 732 server_stop($pid_file); 733 734 $self->assert_child_ok($pid); 735 736 if ($ex) { 737 die($ex); 738 } 739 740 unlink($log_file); 741} 742 743sub anon_limit_write_allow_stor_using_abs_path { 744 my $self = shift; 745 my $tmpdir = $self->{tmpdir}; 746 747 my $config_file = "$tmpdir/limit.conf"; 748 my $pid_file = File::Spec->rel2abs("$tmpdir/limit.pid"); 749 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/limit.scoreboard"); 750 751 my $log_file = File::Spec->rel2abs('tests.log'); 752 753 my $auth_user_file = File::Spec->rel2abs("$tmpdir/limit.passwd"); 754 my $auth_group_file = File::Spec->rel2abs("$tmpdir/limit.group"); 755 756 my ($config_user, $config_group) = config_get_identity(); 757 758 my $anon_dir = File::Spec->rel2abs($tmpdir); 759 my $uid = 500; 760 my $gid = 500; 761 762 my $uploads_dir = File::Spec->rel2abs("$anon_dir/uploads"); 763 mkpath($uploads_dir); 764 765 my $test_file = File::Spec->rel2abs("$uploads_dir/test.txt"); 766 767 # Make sure that, if we're running as root, that the home directory has 768 # permissions/privs set for the account we create 769 if ($< == 0) { 770 unless (chmod(0755, $anon_dir, $uploads_dir)) { 771 die("Can't set perms on $anon_dir to 0755: $!"); 772 } 773 774 unless (chown($uid, $gid, $anon_dir, $uploads_dir)) { 775 die("Can't set owner of $anon_dir to $uid/$gid: $!"); 776 } 777 } 778 779 auth_user_write($auth_user_file, $config_user, 'test', $uid, $gid, '/tmp', 780 '/bin/bash'); 781 auth_group_write($auth_group_file, $config_group, $gid, $config_user); 782 783 # Test this config: 784 # 785 # <Anonymous> 786 # <Limit WRITE SITE_CHMOD> 787 # DenyAll 788 # </Limit> 789 # 790 # <Directory uploads/*> 791 # <Limit STOR> 792 # AllowAll 793 # </Limit> 794 # </Directory> 795 # </Anonymous> 796 797 my $config = { 798 PidFile => $pid_file, 799 ScoreboardFile => $scoreboard_file, 800 SystemLog => $log_file, 801 802 AuthUserFile => $auth_user_file, 803 AuthGroupFile => $auth_group_file, 804 805 IfModules => { 806 'mod_delay.c' => { 807 DelayEngine => 'off', 808 }, 809 }, 810 }; 811 812 my ($port, $user, $group) = config_write($config_file, $config); 813 814 if (open(my $fh, ">> $config_file")) { 815 print $fh <<EOC; 816<Anonymous $anon_dir> 817 User $config_user 818 Group $config_group 819 UserAlias anonymous $config_user 820 RequireValidShell off 821 822 <Limit WRITE SITE_CHMOD> 823 DenyAll 824 </Limit> 825 826 <Directory uploads/*> 827 <Limit STOR> 828 AllowAll 829 </Limit> 830 </Directory> 831</Anonymous> 832EOC 833 unless (close($fh)) { 834 die("Can't write $config_file: $!"); 835 } 836 837 } else { 838 die("Can't open $config_file: $!"); 839 } 840 841 # Open pipes, for use between the parent and child processes. Specifically, 842 # the child will indicate when it's done with its test by writing a message 843 # to the parent. 844 my ($rfh, $wfh); 845 unless (pipe($rfh, $wfh)) { 846 die("Can't open pipe: $!"); 847 } 848 849 my $ex; 850 851 # Fork child 852 $self->handle_sigchld(); 853 defined(my $pid = fork()) or die("Can't fork: $!"); 854 if ($pid) { 855 eval { 856 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 857 $client->login('anonymous', 'ftp@nospam.org'); 858 859 my $conn = $client->stor_raw('uploads/test.txt'); 860 unless ($conn) { 861 die("STOR uploads/test.txt failed:" . $client->response_code() . " " . 862 $client->response_msg()); 863 } 864 865 my $buf = "Hello, World!\n"; 866 $conn->write($buf, length($buf), 15); 867 eval { $conn->close() }; 868 869 my $resp_code = $client->response_code(); 870 my $resp_msg = $client->response_msg(); 871 872 $self->assert_transfer_ok($resp_code, $resp_msg); 873 874 $client->quit(); 875 876 $self->assert(-f $test_file, 877 test_msg("File $test_file does not exist as expected")); 878 }; 879 880 if ($@) { 881 $ex = $@; 882 } 883 884 $wfh->print("done\n"); 885 $wfh->flush(); 886 887 } else { 888 eval { server_wait($config_file, $rfh) }; 889 if ($@) { 890 warn($@); 891 exit 1; 892 } 893 894 exit 0; 895 } 896 897 # Stop server 898 server_stop($pid_file); 899 900 $self->assert_child_ok($pid); 901 902 if ($ex) { 903 die($ex); 904 } 905 906 unlink($log_file); 907} 908 909sub anon_limit_write_allow_stor_using_rel_path { 910 my $self = shift; 911 my $tmpdir = $self->{tmpdir}; 912 913 my $config_file = "$tmpdir/limit.conf"; 914 my $pid_file = File::Spec->rel2abs("$tmpdir/limit.pid"); 915 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/limit.scoreboard"); 916 917 my $log_file = File::Spec->rel2abs('tests.log'); 918 919 my $auth_user_file = File::Spec->rel2abs("$tmpdir/limit.passwd"); 920 my $auth_group_file = File::Spec->rel2abs("$tmpdir/limit.group"); 921 922 my ($config_user, $config_group) = config_get_identity(); 923 924 my $anon_dir = File::Spec->rel2abs($tmpdir); 925 my $uid = 500; 926 my $gid = 500; 927 928 my $uploads_dir = File::Spec->rel2abs("$anon_dir/uploads"); 929 mkpath($uploads_dir); 930 931 my $test_file = File::Spec->rel2abs("$uploads_dir/test.txt"); 932 933 # Make sure that, if we're running as root, that the home directory has 934 # permissions/privs set for the account we create 935 if ($< == 0) { 936 unless (chmod(0755, $anon_dir, $uploads_dir)) { 937 die("Can't set perms on $anon_dir to 0755: $!"); 938 } 939 940 unless (chown($uid, $gid, $anon_dir, $uploads_dir)) { 941 die("Can't set owner of $anon_dir to $uid/$gid: $!"); 942 } 943 } 944 945 auth_user_write($auth_user_file, $config_user, 'test', $uid, $gid, '/tmp', 946 '/bin/bash'); 947 auth_group_write($auth_group_file, $config_group, $gid, $config_user); 948 949 # Test this config: 950 # 951 # <Anonymous> 952 # <Limit WRITE SITE_CHMOD> 953 # DenyAll 954 # </Limit> 955 # 956 # <Directory uploads/*> 957 # <Limit STOR> 958 # AllowAll 959 # </Limit> 960 # </Directory> 961 # </Anonymous> 962 963 my $config = { 964 PidFile => $pid_file, 965 ScoreboardFile => $scoreboard_file, 966 SystemLog => $log_file, 967 968 AuthUserFile => $auth_user_file, 969 AuthGroupFile => $auth_group_file, 970 971 IfModules => { 972 'mod_delay.c' => { 973 DelayEngine => 'off', 974 }, 975 }, 976 }; 977 978 my ($port, $user, $group) = config_write($config_file, $config); 979 980 if (open(my $fh, ">> $config_file")) { 981 print $fh <<EOC; 982<Anonymous $anon_dir> 983 User $config_user 984 Group $config_group 985 UserAlias anonymous $config_user 986 RequireValidShell off 987 988 <Limit WRITE SITE_CHMOD> 989 DenyAll 990 </Limit> 991 992 <Directory uploads/*> 993 <Limit STOR> 994 AllowAll 995 </Limit> 996 </Directory> 997</Anonymous> 998EOC 999 unless (close($fh)) { 1000 die("Can't write $config_file: $!"); 1001 } 1002 1003 } else { 1004 die("Can't open $config_file: $!"); 1005 } 1006 1007 # Open pipes, for use between the parent and child processes. Specifically, 1008 # the child will indicate when it's done with its test by writing a message 1009 # to the parent. 1010 my ($rfh, $wfh); 1011 unless (pipe($rfh, $wfh)) { 1012 die("Can't open pipe: $!"); 1013 } 1014 1015 my $ex; 1016 1017 # Fork child 1018 $self->handle_sigchld(); 1019 defined(my $pid = fork()) or die("Can't fork: $!"); 1020 if ($pid) { 1021 eval { 1022 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1023 $client->login('anonymous', 'ftp@nospam.org'); 1024 $client->cwd('uploads'); 1025 1026 my $conn = $client->stor_raw('test.txt'); 1027 unless ($conn) { 1028 die("STOR test.txt failed:" . $client->response_code() . " " . 1029 $client->response_msg()); 1030 } 1031 1032 my $buf = "Hello, World!\n"; 1033 $conn->write($buf, length($buf), 15); 1034 eval { $conn->close() }; 1035 1036 my $resp_code = $client->response_code(); 1037 my $resp_msg = $client->response_msg(); 1038 1039 $self->assert_transfer_ok($resp_code, $resp_msg); 1040 1041 $client->quit(); 1042 1043 $self->assert(-f $test_file, 1044 test_msg("File $test_file does not exist as expected")); 1045 }; 1046 1047 if ($@) { 1048 $ex = $@; 1049 } 1050 1051 $wfh->print("done\n"); 1052 $wfh->flush(); 1053 1054 } else { 1055 eval { server_wait($config_file, $rfh) }; 1056 if ($@) { 1057 warn($@); 1058 exit 1; 1059 } 1060 1061 exit 0; 1062 } 1063 1064 # Stop server 1065 server_stop($pid_file); 1066 1067 $self->assert_child_ok($pid); 1068 1069 if ($ex) { 1070 die($ex); 1071 } 1072 1073 unlink($log_file); 1074} 1075 10761; 1077