1package ProFTPD::Tests::Modules::mod_sql_passwd; 2 3use lib qw(t/lib); 4use base qw(ProFTPD::TestSuite::Child); 5use strict; 6 7use File::Spec; 8use IO::Handle; 9 10use ProFTPD::TestSuite::FTP; 11use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite); 12 13$| = 1; 14 15my $order = 0; 16 17my $TESTS = { 18 sql_passwd_host => { 19 order => ++$order, 20 test_class => [qw(forking)], 21 }, 22 23 sql_passwd_md5_base64 => { 24 order => ++$order, 25 test_class => [qw(forking)], 26 }, 27 28 sql_passwd_md5_hex_lc => { 29 order => ++$order, 30 test_class => [qw(forking)], 31 }, 32 33 sql_passwd_md5_hex_uc => { 34 order => ++$order, 35 test_class => [qw(forking)], 36 }, 37 38 sql_passwd_sha1_base64 => { 39 order => ++$order, 40 test_class => [qw(forking)], 41 }, 42 43 sql_passwd_sha1_hex_lc => { 44 order => ++$order, 45 test_class => [qw(forking)], 46 }, 47 48 sql_passwd_sha1_hex_uc => { 49 order => ++$order, 50 test_class => [qw(forking)], 51 }, 52 53 sql_passwd_engine_off => { 54 order => ++$order, 55 test_class => [qw(forking)], 56 }, 57 58 sql_passwd_salt_file => { 59 order => ++$order, 60 test_class => [qw(forking)], 61 }, 62 63 sql_passwd_salt_file_trailing_newline => { 64 order => ++$order, 65 test_class => [qw(forking)], 66 }, 67 68 sql_passwd_salt_file_prepend => { 69 order => ++$order, 70 test_class => [qw(forking)], 71 }, 72 73 sql_passwd_sha256_base64_bug3344 => { 74 order => ++$order, 75 test_class => [qw(forking)], 76 }, 77 78 sql_passwd_sha256_hex_lc_bug3344 => { 79 order => ++$order, 80 test_class => [qw(forking)], 81 }, 82 83 sql_passwd_sha256_hex_uc_bug3344 => { 84 order => ++$order, 85 test_class => [qw(forking)], 86 }, 87 88 sql_passwd_sha512_base64_bug3344 => { 89 order => ++$order, 90 test_class => [qw(forking)], 91 }, 92 93 sql_passwd_sha512_hex_lc_bug3344 => { 94 order => ++$order, 95 test_class => [qw(forking)], 96 }, 97 98 sql_passwd_sha512_hex_uc_bug3344 => { 99 order => ++$order, 100 test_class => [qw(forking)], 101 }, 102 103 sql_passwd_user_salt_name => { 104 order => ++$order, 105 test_class => [qw(forking)], 106 }, 107 108 sql_passwd_user_salt_sql => { 109 order => ++$order, 110 test_class => [qw(forking)], 111 }, 112 113 sql_passwd_md5_hash_encode_salt_password_bug3500 => { 114 order => ++$order, 115 test_class => [qw(bug forking)], 116 }, 117 118 sql_passwd_md5_hash_encode_password_bug3500 => { 119 order => ++$order, 120 test_class => [qw(bug forking)], 121 }, 122 123 sql_passwd_md5_rounds_bug3500 => { 124 order => ++$order, 125 test_class => [qw(bug forking)], 126 }, 127 128 sql_passwd_md5_rounds_hash_encode_salt_password_bug3500 => { 129 order => ++$order, 130 test_class => [qw(bug forking)], 131 }, 132 133 sql_passwd_md5_hash_password => { 134 order => ++$order, 135 test_class => [qw(forking)], 136 }, 137 138 sql_passwd_md5_hash_salt => { 139 order => ++$order, 140 test_class => [qw(forking)], 141 }, 142 143 sql_passwd_sha1_encode_salt_hash_encode_password => { 144 order => ++$order, 145 test_class => [qw(forking)], 146 }, 147 148 sql_passwd_pbkdf2_sha1_base64 => { 149 order => ++$order, 150 test_class => [qw(forking)], 151 }, 152 153 sql_passwd_pbkdf2_sha1_hex_lc => { 154 order => ++$order, 155 test_class => [qw(forking)], 156 }, 157 158 sql_passwd_pbkdf2_sha1_hex_uc => { 159 order => ++$order, 160 test_class => [qw(forking)], 161 }, 162 163 sql_passwd_pbkdf2_sha512_hex_lc => { 164 order => ++$order, 165 test_class => [qw(forking)], 166 }, 167 168 sql_passwd_pbkdf2_per_user_bug4052 => { 169 order => ++$order, 170 test_class => [qw(forking bug)], 171 }, 172 173 sql_passwd_salt_file_with_user_salt => { 174 order => ++$order, 175 test_class => [qw(forking)], 176 }, 177 178 sql_passwd_user_salt_sql_base64_bug4138 => { 179 order => ++$order, 180 test_class => [qw(bug forking)], 181 }, 182 183 sql_passwd_user_salt_sql_hex_lc_bug4138 => { 184 order => ++$order, 185 test_class => [qw(bug forking)], 186 }, 187 188 sql_passwd_user_salt_sql_hex_uc_bug4138 => { 189 order => ++$order, 190 test_class => [qw(bug forking)], 191 }, 192 193 sql_passwd_salt_file_base64_bug4138 => { 194 order => ++$order, 195 test_class => [qw(bug forking)], 196 }, 197 198 sql_passwd_salt_file_hex_lc_bug4138 => { 199 order => ++$order, 200 test_class => [qw(bug forking)], 201 }, 202 203 sql_passwd_salt_file_hex_uc_bug4138 => { 204 order => ++$order, 205 test_class => [qw(bug forking)], 206 }, 207 208 sql_passwd_scrypt_base64_interactive_cost => { 209 order => ++$order, 210 test_class => [qw(feature_sodium forking)], 211 }, 212 213 sql_passwd_scrypt_hex_lc_interactive_cost => { 214 order => ++$order, 215 test_class => [qw(feature_sodium forking)], 216 }, 217 218 sql_passwd_scrypt_hex_uc_interactive_cost => { 219 order => ++$order, 220 test_class => [qw(feature_sodium forking)], 221 }, 222 223 sql_passwd_scrypt_base64_sensitive_cost => { 224 order => ++$order, 225 test_class => [qw(feature_sodium forking)], 226 }, 227 228 sql_passwd_scrypt_hex_lc_sensitive_cost => { 229 order => ++$order, 230 test_class => [qw(feature_sodium forking)], 231 }, 232 233 sql_passwd_scrypt_hex_uc_sensitive_cost => { 234 order => ++$order, 235 test_class => [qw(feature_sodium forking)], 236 }, 237 238 sql_passwd_scrypt_hex_uc_sensitive_cost_len_64 => { 239 order => ++$order, 240 test_class => [qw(feature_sodium forking)], 241 }, 242 243 sql_passwd_argon2_base64_interactive_cost => { 244 order => ++$order, 245 test_class => [qw(feature_sodium forking)], 246 }, 247 248 sql_passwd_argon2_hex_lc_interactive_cost => { 249 order => ++$order, 250 test_class => [qw(feature_sodium forking)], 251 }, 252 253 sql_passwd_argon2_hex_uc_interactive_cost => { 254 order => ++$order, 255 test_class => [qw(feature_sodium forking)], 256 }, 257 258 sql_passwd_argon2_base64_interactive_cost => { 259 order => ++$order, 260 test_class => [qw(feature_sodium forking)], 261 }, 262 263 sql_passwd_argon2_hex_lc_sensitive_cost => { 264 order => ++$order, 265 test_class => [qw(feature_sodium forking)], 266 }, 267 268 sql_passwd_argon2_hex_uc_sensitive_cost => { 269 order => ++$order, 270 test_class => [qw(feature_sodium forking)], 271 }, 272 273 sql_passwd_argon2_hex_uc_sensitive_cost_len_64 => { 274 order => ++$order, 275 test_class => [qw(feature_sodium forking)], 276 }, 277 278 sql_passwd_bcrypt => { 279 order => ++$order, 280 test_class => [qw(forking)], 281 }, 282 283 sql_passwd_bcrypt_php_variant => { 284 order => ++$order, 285 test_class => [qw(forking)], 286 }, 287 288}; 289 290sub new { 291 return shift()->SUPER::new(@_); 292} 293 294sub list_tests { 295 return testsuite_get_runnable_tests($TESTS); 296} 297 298sub sql_passwd_host { 299 my $self = shift; 300 my $tmpdir = $self->{tmpdir}; 301 302 # I used: 303 # 304 # `/bin/echo -n "test" | openssl dgst -binary -md5 | openssl enc -base64` 305 # 306 # to generate this password. 307 my $passwd = 'CY9rzUYh03PK3k6DJie09g=='; 308 309 my $setup = test_setup($tmpdir, 'sql_passwd', undef, $passwd); 310 311 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 312 313 # Build up sqlite3 command to create users, groups tables and populate them 314 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 315 316 if (open(my $fh, "> $db_script")) { 317 print $fh <<EOS; 318CREATE TABLE users ( 319 userid TEXT, 320 passwd TEXT, 321 uid INTEGER, 322 gid INTEGER, 323 homedir TEXT, 324 shell TEXT 325); 326INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$setup->{user}', '$passwd', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash'); 327 328CREATE TABLE groups ( 329 groupname TEXT, 330 gid INTEGER, 331 members TEXT 332); 333INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); 334EOS 335 336 unless (close($fh)) { 337 die("Can't write $db_script: $!"); 338 } 339 340 } else { 341 die("Can't open $db_script: $!"); 342 } 343 344 my $cmd = "sqlite3 $db_file < $db_script"; 345 346 if ($ENV{TEST_VERBOSE}) { 347 print STDERR "Executing sqlite3: $cmd\n"; 348 } 349 350 my @output = `$cmd`; 351 if (scalar(@output) && 352 $ENV{TEST_VERBOSE}) { 353 print STDERR "Output: ", join('', @output), "\n"; 354 } 355 356 my $config = { 357 PidFile => $setup->{pid_file}, 358 ScoreboardFile => $setup->{scoreboard_file}, 359 SystemLog => $setup->{log_file}, 360 361 IfModules => { 362 'mod_delay.c' => { 363 DelayEngine => 'off', 364 }, 365 366 'mod_sql.c' => { 367 SQLEngine => 'off', 368 }, 369 370 'mod_sql_passwd.c' => { 371 SQLPasswordEngine => 'off', 372 }, 373 }, 374 }; 375 376 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 377 $config); 378 379 my $host = 'localhost'; 380 381 if (open(my $fh, ">> $setup->{config_file}")) { 382 print $fh <<EOC; 383# This virtual host is name-based 384<VirtualHost 127.0.0.1> 385 Port $port 386 ServerAlias $host 387 ServerName "SQL Passwd Server" 388 389 <IfModule mod_delay.c> 390 DelayEngine off 391 </IfModule> 392 393 <IfModule mod_sql.c> 394 SQLAuthTypes md5 395 SQLBackend sqlite3 396 SQLConnectInfo $db_file 397 SQLLogFile $setup->{log_file} 398 </IfModule> 399 400 <IfModule mod_sql_passwd.c> 401 SQLPasswordEngine on 402 SQLPasswordEncoding base64 403 </IfModule> 404</VirtualHost> 405EOC 406 unless (close($fh)) { 407 die("Can't write $setup->{config_file}: $!"); 408 } 409 410 } else { 411 die("Can't open $setup->{config_file}: $!"); 412 } 413 414 # Open pipes, for use between the parent and child processes. Specifically, 415 # the child will indicate when it's done with its test by writing a message 416 # to the parent. 417 my ($rfh, $wfh); 418 unless (pipe($rfh, $wfh)) { 419 die("Can't open pipe: $!"); 420 } 421 422 my $ex; 423 424 # Fork child 425 $self->handle_sigchld(); 426 defined(my $pid = fork()) or die("Can't fork: $!"); 427 if ($pid) { 428 eval { 429 sleep(1); 430 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 431 $client->host($host); 432 $client->login($setup->{user}, "test"); 433 434 my $resp_msgs = $client->response_msgs(); 435 my $nmsgs = scalar(@$resp_msgs); 436 437 my $expected = 1; 438 $self->assert($expected == $nmsgs, 439 test_msg("Expected $expected, got $nmsgs")); 440 441 $expected = "User $setup->{user} logged in"; 442 $self->assert($expected eq $resp_msgs->[0], 443 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 444 }; 445 if ($@) { 446 $ex = $@; 447 } 448 449 $wfh->print("done\n"); 450 $wfh->flush(); 451 452 } else { 453 eval { server_wait($setup->{config_file}, $rfh) }; 454 if ($@) { 455 warn($@); 456 exit 1; 457 } 458 459 exit 0; 460 } 461 462 # Stop server 463 server_stop($setup->{pid_file}); 464 $self->assert_child_ok($pid); 465 466 test_cleanup($setup->{log_file}, $ex); 467} 468 469sub sql_passwd_md5_base64 { 470 my $self = shift; 471 my $tmpdir = $self->{tmpdir}; 472 473 # I used: 474 # 475 # `/bin/echo -n "test" | openssl dgst -binary -md5 | openssl enc -base64` 476 # 477 # to generate this password. 478 my $passwd = 'CY9rzUYh03PK3k6DJie09g=='; 479 480 my $setup = test_setup($tmpdir, 'sql_passwd', undef, $passwd); 481 482 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 483 484 # Build up sqlite3 command to create users, groups tables and populate them 485 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 486 487 if (open(my $fh, "> $db_script")) { 488 print $fh <<EOS; 489CREATE TABLE users ( 490 userid TEXT, 491 passwd TEXT, 492 uid INTEGER, 493 gid INTEGER, 494 homedir TEXT, 495 shell TEXT 496); 497INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$setup->{user}', '$passwd', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash'); 498 499CREATE TABLE groups ( 500 groupname TEXT, 501 gid INTEGER, 502 members TEXT 503); 504INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); 505EOS 506 507 unless (close($fh)) { 508 die("Can't write $db_script: $!"); 509 } 510 511 } else { 512 die("Can't open $db_script: $!"); 513 } 514 515 my $cmd = "sqlite3 $db_file < $db_script"; 516 517 if ($ENV{TEST_VERBOSE}) { 518 print STDERR "Executing sqlite3: $cmd\n"; 519 } 520 521 my @output = `$cmd`; 522 if (scalar(@output) && 523 $ENV{TEST_VERBOSE}) { 524 print STDERR "Output: ", join('', @output), "\n"; 525 } 526 527 my $config = { 528 PidFile => $setup->{pid_file}, 529 ScoreboardFile => $setup->{scoreboard_file}, 530 SystemLog => $setup->{log_file}, 531 532 IfModules => { 533 'mod_delay.c' => { 534 DelayEngine => 'off', 535 }, 536 537 'mod_sql.c' => { 538 SQLAuthTypes => 'md5', 539 SQLBackend => 'sqlite3', 540 SQLConnectInfo => $db_file, 541 SQLLogFile => $setup->{log_file}, 542 }, 543 544 'mod_sql_passwd.c' => { 545 SQLPasswordEngine => 'on', 546 SQLPasswordEncoding => 'base64', 547 }, 548 }, 549 }; 550 551 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 552 $config); 553 554 # Open pipes, for use between the parent and child processes. Specifically, 555 # the child will indicate when it's done with its test by writing a message 556 # to the parent. 557 my ($rfh, $wfh); 558 unless (pipe($rfh, $wfh)) { 559 die("Can't open pipe: $!"); 560 } 561 562 my $ex; 563 564 # Fork child 565 $self->handle_sigchld(); 566 defined(my $pid = fork()) or die("Can't fork: $!"); 567 if ($pid) { 568 eval { 569 sleep(1); 570 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 571 $client->login($setup->{user}, "test"); 572 573 my $resp_msgs = $client->response_msgs(); 574 my $nmsgs = scalar(@$resp_msgs); 575 576 my $expected = 1; 577 $self->assert($expected == $nmsgs, 578 test_msg("Expected $expected, got $nmsgs")); 579 580 $expected = "User $setup->{user} logged in"; 581 $self->assert($expected eq $resp_msgs->[0], 582 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 583 }; 584 if ($@) { 585 $ex = $@; 586 } 587 588 $wfh->print("done\n"); 589 $wfh->flush(); 590 591 } else { 592 eval { server_wait($setup->{config_file}, $rfh) }; 593 if ($@) { 594 warn($@); 595 exit 1; 596 } 597 598 exit 0; 599 } 600 601 # Stop server 602 server_stop($setup->{pid_file}); 603 $self->assert_child_ok($pid); 604 605 test_cleanup($setup->{log_file}, $ex); 606} 607 608sub sql_passwd_md5_hex_lc { 609 my $self = shift; 610 my $tmpdir = $self->{tmpdir}; 611 612 my $config_file = "$tmpdir/sqlpasswd.conf"; 613 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 614 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 615 616 my $log_file = test_get_logfile(); 617 618 my $user = 'proftpd'; 619 my $group = 'ftpd'; 620 621 # I used: 622 # 623 # `/bin/echo -n "test" | openssl dgst -hex -md5` 624 # 625 # to generate this password. 626 my $passwd = '098f6bcd4621d373cade4e832627b4f6'; 627 628 my $home_dir = File::Spec->rel2abs($tmpdir); 629 my $uid = 500; 630 my $gid = 500; 631 632 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 633 634 # Build up sqlite3 command to create users, groups tables and populate them 635 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 636 637 if (open(my $fh, "> $db_script")) { 638 print $fh <<EOS; 639CREATE TABLE users ( 640 userid TEXT, 641 passwd TEXT, 642 uid INTEGER, 643 gid INTEGER, 644 homedir TEXT, 645 shell TEXT 646); 647INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 648 649CREATE TABLE groups ( 650 groupname TEXT, 651 gid INTEGER, 652 members TEXT 653); 654INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 655EOS 656 657 unless (close($fh)) { 658 die("Can't write $db_script: $!"); 659 } 660 661 } else { 662 die("Can't open $db_script: $!"); 663 } 664 665 my $cmd = "sqlite3 $db_file < $db_script"; 666 667 if ($ENV{TEST_VERBOSE}) { 668 print STDERR "Executing sqlite3: $cmd\n"; 669 } 670 671 my @output = `$cmd`; 672 if (scalar(@output) && 673 $ENV{TEST_VERBOSE}) { 674 print STDERR "Output: ", join('', @output), "\n"; 675 } 676 677 my $config = { 678 PidFile => $pid_file, 679 ScoreboardFile => $scoreboard_file, 680 SystemLog => $log_file, 681 682 IfModules => { 683 'mod_delay.c' => { 684 DelayEngine => 'off', 685 }, 686 687 'mod_sql.c' => { 688 SQLAuthTypes => 'md5', 689 SQLBackend => 'sqlite3', 690 SQLConnectInfo => $db_file, 691 SQLLogFile => $log_file, 692 }, 693 694 'mod_sql_passwd.c' => { 695 SQLPasswordEngine => 'on', 696 SQLPasswordEncoding => 'hex', 697 }, 698 }, 699 }; 700 701 my ($port, $config_user, $config_group) = config_write($config_file, $config); 702 703 # Open pipes, for use between the parent and child processes. Specifically, 704 # the child will indicate when it's done with its test by writing a message 705 # to the parent. 706 my ($rfh, $wfh); 707 unless (pipe($rfh, $wfh)) { 708 die("Can't open pipe: $!"); 709 } 710 711 my $ex; 712 713 # Fork child 714 $self->handle_sigchld(); 715 defined(my $pid = fork()) or die("Can't fork: $!"); 716 if ($pid) { 717 eval { 718 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 719 $client->login($user, "test"); 720 721 my $resp_msgs = $client->response_msgs(); 722 my $nmsgs = scalar(@$resp_msgs); 723 724 my $expected; 725 726 $expected = 1; 727 $self->assert($expected == $nmsgs, 728 test_msg("Expected $expected, got $nmsgs")); 729 730 $expected = "User proftpd logged in"; 731 $self->assert($expected eq $resp_msgs->[0], 732 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 733 734 }; 735 736 if ($@) { 737 $ex = $@; 738 } 739 740 $wfh->print("done\n"); 741 $wfh->flush(); 742 743 } else { 744 eval { server_wait($config_file, $rfh) }; 745 if ($@) { 746 warn($@); 747 exit 1; 748 } 749 750 exit 0; 751 } 752 753 # Stop server 754 server_stop($pid_file); 755 756 $self->assert_child_ok($pid); 757 758 if ($ex) { 759 test_append_logfile($log_file, $ex); 760 unlink($log_file); 761 762 die($ex); 763 } 764 765 unlink($log_file); 766} 767 768sub sql_passwd_md5_hex_uc { 769 my $self = shift; 770 my $tmpdir = $self->{tmpdir}; 771 772 my $config_file = "$tmpdir/sqlpasswd.conf"; 773 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 774 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 775 776 my $log_file = test_get_logfile(); 777 778 my $user = 'proftpd'; 779 my $group = 'ftpd'; 780 781 # I used: 782 # 783 # `/bin/echo -n "test" | openssl dgst -hex -md5` 784 # 785 # to generate this password. Then I manually made all of the letters be 786 # in uppercase. Tedious. 787 my $passwd = '098F6BCD4621D373CADE4E832627B4F6'; 788 789 my $home_dir = File::Spec->rel2abs($tmpdir); 790 my $uid = 500; 791 my $gid = 500; 792 793 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 794 795 # Build up sqlite3 command to create users, groups tables and populate them 796 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 797 798 if (open(my $fh, "> $db_script")) { 799 print $fh <<EOS; 800CREATE TABLE users ( 801 userid TEXT, 802 passwd TEXT, 803 uid INTEGER, 804 gid INTEGER, 805 homedir TEXT, 806 shell TEXT 807); 808INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 809 810CREATE TABLE groups ( 811 groupname TEXT, 812 gid INTEGER, 813 members TEXT 814); 815INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 816EOS 817 818 unless (close($fh)) { 819 die("Can't write $db_script: $!"); 820 } 821 822 } else { 823 die("Can't open $db_script: $!"); 824 } 825 826 my $cmd = "sqlite3 $db_file < $db_script"; 827 828 if ($ENV{TEST_VERBOSE}) { 829 print STDERR "Executing sqlite3: $cmd\n"; 830 } 831 832 my @output = `$cmd`; 833 if (scalar(@output) && 834 $ENV{TEST_VERBOSE}) { 835 print STDERR "Output: ", join('', @output), "\n"; 836 } 837 838 my $config = { 839 PidFile => $pid_file, 840 ScoreboardFile => $scoreboard_file, 841 SystemLog => $log_file, 842 843 IfModules => { 844 'mod_delay.c' => { 845 DelayEngine => 'off', 846 }, 847 848 'mod_sql.c' => { 849 SQLAuthTypes => 'md5', 850 SQLBackend => 'sqlite3', 851 SQLConnectInfo => $db_file, 852 SQLLogFile => $log_file, 853 }, 854 855 'mod_sql_passwd.c' => { 856 SQLPasswordEngine => 'on', 857 SQLPasswordEncoding => 'HEX', 858 }, 859 }, 860 }; 861 862 my ($port, $config_user, $config_group) = config_write($config_file, $config); 863 864 # Open pipes, for use between the parent and child processes. Specifically, 865 # the child will indicate when it's done with its test by writing a message 866 # to the parent. 867 my ($rfh, $wfh); 868 unless (pipe($rfh, $wfh)) { 869 die("Can't open pipe: $!"); 870 } 871 872 my $ex; 873 874 # Fork child 875 $self->handle_sigchld(); 876 defined(my $pid = fork()) or die("Can't fork: $!"); 877 if ($pid) { 878 eval { 879 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 880 $client->login($user, "test"); 881 882 my $resp_msgs = $client->response_msgs(); 883 my $nmsgs = scalar(@$resp_msgs); 884 885 my $expected; 886 887 $expected = 1; 888 $self->assert($expected == $nmsgs, 889 test_msg("Expected $expected, got $nmsgs")); 890 891 $expected = "User proftpd logged in"; 892 $self->assert($expected eq $resp_msgs->[0], 893 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 894 895 }; 896 897 if ($@) { 898 $ex = $@; 899 } 900 901 $wfh->print("done\n"); 902 $wfh->flush(); 903 904 } else { 905 eval { server_wait($config_file, $rfh) }; 906 if ($@) { 907 warn($@); 908 exit 1; 909 } 910 911 exit 0; 912 } 913 914 # Stop server 915 server_stop($pid_file); 916 917 $self->assert_child_ok($pid); 918 919 if ($ex) { 920 test_append_logfile($log_file, $ex); 921 unlink($log_file); 922 923 die($ex); 924 } 925 926 unlink($log_file); 927} 928 929sub sql_passwd_sha1_base64 { 930 my $self = shift; 931 my $tmpdir = $self->{tmpdir}; 932 933 my $config_file = "$tmpdir/sqlpasswd.conf"; 934 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 935 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 936 937 my $log_file = test_get_logfile(); 938 939 my $user = 'proftpd'; 940 my $group = 'ftpd'; 941 942 # I used: 943 # 944 # `/bin/echo -n "test" | openssl dgst -binary -sha1 | openssl enc -base64` 945 # 946 # to generate this password. 947 my $passwd = 'qUqP5cyxm6YcTAhz05Hph5gvu9M='; 948 949 my $home_dir = File::Spec->rel2abs($tmpdir); 950 my $uid = 500; 951 my $gid = 500; 952 953 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 954 955 # Build up sqlite3 command to create users, groups tables and populate them 956 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 957 958 if (open(my $fh, "> $db_script")) { 959 print $fh <<EOS; 960CREATE TABLE users ( 961 userid TEXT, 962 passwd TEXT, 963 uid INTEGER, 964 gid INTEGER, 965 homedir TEXT, 966 shell TEXT 967); 968INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 969 970CREATE TABLE groups ( 971 groupname TEXT, 972 gid INTEGER, 973 members TEXT 974); 975INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 976EOS 977 978 unless (close($fh)) { 979 die("Can't write $db_script: $!"); 980 } 981 982 } else { 983 die("Can't open $db_script: $!"); 984 } 985 986 my $cmd = "sqlite3 $db_file < $db_script"; 987 988 if ($ENV{TEST_VERBOSE}) { 989 print STDERR "Executing sqlite3: $cmd\n"; 990 } 991 992 my @output = `$cmd`; 993 if (scalar(@output) && 994 $ENV{TEST_VERBOSE}) { 995 print STDERR "Output: ", join('', @output), "\n"; 996 } 997 998 my $config = { 999 PidFile => $pid_file, 1000 ScoreboardFile => $scoreboard_file, 1001 SystemLog => $log_file, 1002 1003 IfModules => { 1004 'mod_delay.c' => { 1005 DelayEngine => 'off', 1006 }, 1007 1008 'mod_sql.c' => { 1009 SQLAuthTypes => 'sha1', 1010 SQLBackend => 'sqlite3', 1011 SQLConnectInfo => $db_file, 1012 SQLLogFile => $log_file, 1013 }, 1014 1015 'mod_sql_passwd.c' => { 1016 SQLPasswordEngine => 'on', 1017 SQLPasswordEncoding => 'base64', 1018 }, 1019 }, 1020 }; 1021 1022 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1023 1024 # Open pipes, for use between the parent and child processes. Specifically, 1025 # the child will indicate when it's done with its test by writing a message 1026 # to the parent. 1027 my ($rfh, $wfh); 1028 unless (pipe($rfh, $wfh)) { 1029 die("Can't open pipe: $!"); 1030 } 1031 1032 my $ex; 1033 1034 # Fork child 1035 $self->handle_sigchld(); 1036 defined(my $pid = fork()) or die("Can't fork: $!"); 1037 if ($pid) { 1038 eval { 1039 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1040 $client->login($user, "test"); 1041 1042 my $resp_msgs = $client->response_msgs(); 1043 my $nmsgs = scalar(@$resp_msgs); 1044 1045 my $expected; 1046 1047 $expected = 1; 1048 $self->assert($expected == $nmsgs, 1049 test_msg("Expected $expected, got $nmsgs")); 1050 1051 $expected = "User proftpd logged in"; 1052 $self->assert($expected eq $resp_msgs->[0], 1053 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 1054 1055 }; 1056 1057 if ($@) { 1058 $ex = $@; 1059 } 1060 1061 $wfh->print("done\n"); 1062 $wfh->flush(); 1063 1064 } else { 1065 eval { server_wait($config_file, $rfh) }; 1066 if ($@) { 1067 warn($@); 1068 exit 1; 1069 } 1070 1071 exit 0; 1072 } 1073 1074 # Stop server 1075 server_stop($pid_file); 1076 1077 $self->assert_child_ok($pid); 1078 1079 if ($ex) { 1080 test_append_logfile($log_file, $ex); 1081 unlink($log_file); 1082 1083 die($ex); 1084 } 1085 1086 unlink($log_file); 1087} 1088 1089sub sql_passwd_sha1_hex_lc { 1090 my $self = shift; 1091 my $tmpdir = $self->{tmpdir}; 1092 1093 my $config_file = "$tmpdir/sqlpasswd.conf"; 1094 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 1095 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 1096 1097 my $log_file = test_get_logfile(); 1098 1099 my $user = 'proftpd'; 1100 my $group = 'ftpd'; 1101 1102 # I used: 1103 # 1104 # `/bin/echo -n "test" | openssl dgst -hex -sha1` 1105 # 1106 # to generate this password. 1107 my $passwd = 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'; 1108 1109 my $home_dir = File::Spec->rel2abs($tmpdir); 1110 my $uid = 500; 1111 my $gid = 500; 1112 1113 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1114 1115 # Build up sqlite3 command to create users, groups tables and populate them 1116 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1117 1118 if (open(my $fh, "> $db_script")) { 1119 print $fh <<EOS; 1120CREATE TABLE users ( 1121 userid TEXT, 1122 passwd TEXT, 1123 uid INTEGER, 1124 gid INTEGER, 1125 homedir TEXT, 1126 shell TEXT 1127); 1128INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 1129 1130CREATE TABLE groups ( 1131 groupname TEXT, 1132 gid INTEGER, 1133 members TEXT 1134); 1135INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 1136EOS 1137 1138 unless (close($fh)) { 1139 die("Can't write $db_script: $!"); 1140 } 1141 1142 } else { 1143 die("Can't open $db_script: $!"); 1144 } 1145 1146 my $cmd = "sqlite3 $db_file < $db_script"; 1147 1148 if ($ENV{TEST_VERBOSE}) { 1149 print STDERR "Executing sqlite3: $cmd\n"; 1150 } 1151 1152 my @output = `$cmd`; 1153 if (scalar(@output) && 1154 $ENV{TEST_VERBOSE}) { 1155 print STDERR "Output: ", join('', @output), "\n"; 1156 } 1157 1158 my $config = { 1159 PidFile => $pid_file, 1160 ScoreboardFile => $scoreboard_file, 1161 SystemLog => $log_file, 1162 1163 IfModules => { 1164 'mod_delay.c' => { 1165 DelayEngine => 'off', 1166 }, 1167 1168 'mod_sql.c' => { 1169 SQLAuthTypes => 'sha1', 1170 SQLBackend => 'sqlite3', 1171 SQLConnectInfo => $db_file, 1172 SQLLogFile => $log_file, 1173 }, 1174 1175 'mod_sql_passwd.c' => { 1176 SQLPasswordEngine => 'on', 1177 SQLPasswordEncoding => 'hex', 1178 }, 1179 }, 1180 }; 1181 1182 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1183 1184 # Open pipes, for use between the parent and child processes. Specifically, 1185 # the child will indicate when it's done with its test by writing a message 1186 # to the parent. 1187 my ($rfh, $wfh); 1188 unless (pipe($rfh, $wfh)) { 1189 die("Can't open pipe: $!"); 1190 } 1191 1192 my $ex; 1193 1194 # Fork child 1195 $self->handle_sigchld(); 1196 defined(my $pid = fork()) or die("Can't fork: $!"); 1197 if ($pid) { 1198 eval { 1199 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1200 $client->login($user, "test"); 1201 1202 my $resp_msgs = $client->response_msgs(); 1203 my $nmsgs = scalar(@$resp_msgs); 1204 1205 my $expected; 1206 1207 $expected = 1; 1208 $self->assert($expected == $nmsgs, 1209 test_msg("Expected $expected, got $nmsgs")); 1210 1211 $expected = "User proftpd logged in"; 1212 $self->assert($expected eq $resp_msgs->[0], 1213 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 1214 1215 }; 1216 1217 if ($@) { 1218 $ex = $@; 1219 } 1220 1221 $wfh->print("done\n"); 1222 $wfh->flush(); 1223 1224 } else { 1225 eval { server_wait($config_file, $rfh) }; 1226 if ($@) { 1227 warn($@); 1228 exit 1; 1229 } 1230 1231 exit 0; 1232 } 1233 1234 # Stop server 1235 server_stop($pid_file); 1236 1237 $self->assert_child_ok($pid); 1238 1239 if ($ex) { 1240 test_append_logfile($log_file, $ex); 1241 unlink($log_file); 1242 1243 die($ex); 1244 } 1245 1246 unlink($log_file); 1247} 1248 1249sub sql_passwd_sha1_hex_uc { 1250 my $self = shift; 1251 my $tmpdir = $self->{tmpdir}; 1252 1253 my $config_file = "$tmpdir/sqlpasswd.conf"; 1254 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 1255 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 1256 1257 my $log_file = test_get_logfile(); 1258 1259 my $user = 'proftpd'; 1260 my $group = 'ftpd'; 1261 1262 # I used: 1263 # 1264 # `/bin/echo -n "test" | openssl dgst -hex -sha1` 1265 # 1266 # to generate this password. Then I manually made all of the letters be 1267 # in uppercase. Tedious. 1268 my $passwd = 'A94A8FE5CCB19BA61C4C0873D391E987982FBBD3'; 1269 1270 my $home_dir = File::Spec->rel2abs($tmpdir); 1271 my $uid = 500; 1272 my $gid = 500; 1273 1274 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1275 1276 # Build up sqlite3 command to create users, groups tables and populate them 1277 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1278 1279 if (open(my $fh, "> $db_script")) { 1280 print $fh <<EOS; 1281CREATE TABLE users ( 1282 userid TEXT, 1283 passwd TEXT, 1284 uid INTEGER, 1285 gid INTEGER, 1286 homedir TEXT, 1287 shell TEXT 1288); 1289INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 1290 1291CREATE TABLE groups ( 1292 groupname TEXT, 1293 gid INTEGER, 1294 members TEXT 1295); 1296INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 1297EOS 1298 1299 unless (close($fh)) { 1300 die("Can't write $db_script: $!"); 1301 } 1302 1303 } else { 1304 die("Can't open $db_script: $!"); 1305 } 1306 1307 my $cmd = "sqlite3 $db_file < $db_script"; 1308 1309 if ($ENV{TEST_VERBOSE}) { 1310 print STDERR "Executing sqlite3: $cmd\n"; 1311 } 1312 1313 my @output = `$cmd`; 1314 if (scalar(@output) && 1315 $ENV{TEST_VERBOSE}) { 1316 print STDERR "Output: ", join('', @output), "\n"; 1317 } 1318 1319 my $config = { 1320 PidFile => $pid_file, 1321 ScoreboardFile => $scoreboard_file, 1322 SystemLog => $log_file, 1323 1324 IfModules => { 1325 'mod_delay.c' => { 1326 DelayEngine => 'off', 1327 }, 1328 1329 'mod_sql.c' => { 1330 SQLAuthTypes => 'sha1', 1331 SQLBackend => 'sqlite3', 1332 SQLConnectInfo => $db_file, 1333 SQLLogFile => $log_file, 1334 }, 1335 1336 'mod_sql_passwd.c' => { 1337 SQLPasswordEngine => 'on', 1338 SQLPasswordEncoding => 'HEX', 1339 }, 1340 }, 1341 }; 1342 1343 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1344 1345 # Open pipes, for use between the parent and child processes. Specifically, 1346 # the child will indicate when it's done with its test by writing a message 1347 # to the parent. 1348 my ($rfh, $wfh); 1349 unless (pipe($rfh, $wfh)) { 1350 die("Can't open pipe: $!"); 1351 } 1352 1353 my $ex; 1354 1355 # Fork child 1356 $self->handle_sigchld(); 1357 defined(my $pid = fork()) or die("Can't fork: $!"); 1358 if ($pid) { 1359 eval { 1360 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1361 $client->login($user, "test"); 1362 1363 my $resp_msgs = $client->response_msgs(); 1364 my $nmsgs = scalar(@$resp_msgs); 1365 1366 my $expected; 1367 1368 $expected = 1; 1369 $self->assert($expected == $nmsgs, 1370 test_msg("Expected $expected, got $nmsgs")); 1371 1372 $expected = "User proftpd logged in"; 1373 $self->assert($expected eq $resp_msgs->[0], 1374 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 1375 1376 }; 1377 1378 if ($@) { 1379 $ex = $@; 1380 } 1381 1382 $wfh->print("done\n"); 1383 $wfh->flush(); 1384 1385 } else { 1386 eval { server_wait($config_file, $rfh) }; 1387 if ($@) { 1388 warn($@); 1389 exit 1; 1390 } 1391 1392 exit 0; 1393 } 1394 1395 # Stop server 1396 server_stop($pid_file); 1397 1398 $self->assert_child_ok($pid); 1399 1400 if ($ex) { 1401 test_append_logfile($log_file, $ex); 1402 unlink($log_file); 1403 1404 die($ex); 1405 } 1406 1407 unlink($log_file); 1408} 1409 1410sub sql_passwd_engine_off { 1411 my $self = shift; 1412 my $tmpdir = $self->{tmpdir}; 1413 1414 my $config_file = "$tmpdir/sqlpasswd.conf"; 1415 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 1416 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 1417 1418 my $log_file = test_get_logfile(); 1419 1420 my $user = 'proftpd'; 1421 my $group = 'ftpd'; 1422 1423 # I used: 1424 # 1425 # `/bin/echo -n "test" | openssl dgst -binary -md5 | openssl enc -base64` 1426 # 1427 # to generate this password. 1428 my $passwd = 'CY9rzUYh03PK3k6DJie09g=='; 1429 1430 my $home_dir = File::Spec->rel2abs($tmpdir); 1431 my $uid = 500; 1432 my $gid = 500; 1433 1434 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1435 1436 # Build up sqlite3 command to create users, groups tables and populate them 1437 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1438 1439 if (open(my $fh, "> $db_script")) { 1440 print $fh <<EOS; 1441CREATE TABLE users ( 1442 userid TEXT, 1443 passwd TEXT, 1444 uid INTEGER, 1445 gid INTEGER, 1446 homedir TEXT, 1447 shell TEXT 1448); 1449INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 1450 1451CREATE TABLE groups ( 1452 groupname TEXT, 1453 gid INTEGER, 1454 members TEXT 1455); 1456INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 1457EOS 1458 1459 unless (close($fh)) { 1460 die("Can't write $db_script: $!"); 1461 } 1462 1463 } else { 1464 die("Can't open $db_script: $!"); 1465 } 1466 1467 my $cmd = "sqlite3 $db_file < $db_script"; 1468 1469 if ($ENV{TEST_VERBOSE}) { 1470 print STDERR "Executing sqlite3: $cmd\n"; 1471 } 1472 1473 my @output = `$cmd`; 1474 if (scalar(@output) && 1475 $ENV{TEST_VERBOSE}) { 1476 print STDERR "Output: ", join('', @output), "\n"; 1477 } 1478 1479 my $config = { 1480 PidFile => $pid_file, 1481 ScoreboardFile => $scoreboard_file, 1482 SystemLog => $log_file, 1483 1484 IfModules => { 1485 'mod_delay.c' => { 1486 DelayEngine => 'off', 1487 }, 1488 1489 'mod_sql.c' => { 1490 SQLAuthTypes => 'md5', 1491 SQLBackend => 'sqlite3', 1492 SQLConnectInfo => $db_file, 1493 SQLLogFile => $log_file, 1494 }, 1495 1496 'mod_sql_passwd.c' => { 1497 SQLPasswordEngine => 'off', 1498 SQLPasswordEncoding => 'base64', 1499 }, 1500 }, 1501 }; 1502 1503 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1504 1505 # Open pipes, for use between the parent and child processes. Specifically, 1506 # the child will indicate when it's done with its test by writing a message 1507 # to the parent. 1508 my ($rfh, $wfh); 1509 unless (pipe($rfh, $wfh)) { 1510 die("Can't open pipe: $!"); 1511 } 1512 1513 my $ex; 1514 1515 # Fork child 1516 $self->handle_sigchld(); 1517 defined(my $pid = fork()) or die("Can't fork: $!"); 1518 if ($pid) { 1519 eval { 1520 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1521 eval { $client->login($user, "test") }; 1522 unless ($@) { 1523 die("Login succeeded unexpectedly"); 1524 } 1525 1526 my $resp_code = $client->response_code(); 1527 my $resp_msg = $client->response_msg(); 1528 1529 my $expected; 1530 1531 $expected = 530; 1532 $self->assert($expected == $resp_code, 1533 test_msg("Expected $expected, got $resp_code")); 1534 1535 $expected = "Login incorrect."; 1536 $self->assert($expected eq $resp_msg, 1537 test_msg("Expected '$expected', got '$resp_msg'")); 1538 }; 1539 1540 if ($@) { 1541 $ex = $@; 1542 } 1543 1544 $wfh->print("done\n"); 1545 $wfh->flush(); 1546 1547 } else { 1548 eval { server_wait($config_file, $rfh) }; 1549 if ($@) { 1550 warn($@); 1551 exit 1; 1552 } 1553 1554 exit 0; 1555 } 1556 1557 # Stop server 1558 server_stop($pid_file); 1559 1560 $self->assert_child_ok($pid); 1561 1562 if ($ex) { 1563 test_append_logfile($log_file, $ex); 1564 unlink($log_file); 1565 1566 die($ex); 1567 } 1568 1569 unlink($log_file); 1570} 1571 1572sub sql_passwd_salt_file { 1573 my $self = shift; 1574 my $tmpdir = $self->{tmpdir}; 1575 1576 my $config_file = "$tmpdir/sqlpasswd.conf"; 1577 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 1578 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 1579 1580 my $log_file = test_get_logfile(); 1581 1582 my $salt = '8Hkqr7bnPaZ52j81VvuoWdOEuq6EeXwpiIw5Q679xzvEqwe128'; 1583 1584 my $user = 'proftpd'; 1585 my $group = 'ftpd'; 1586 1587 # I used: 1588 # 1589 # Digest::SHA1::sha1_hex((lc("password")) . $salt); 1590 # 1591 # to generate this password. 1592 my $passwd = '975838a6aebc87d384535df6f7226274813353aa'; 1593 1594 my $home_dir = File::Spec->rel2abs($tmpdir); 1595 my $uid = 500; 1596 my $gid = 500; 1597 1598 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1599 1600 # Build up sqlite3 command to create users, groups tables and populate them 1601 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1602 1603 if (open(my $fh, "> $db_script")) { 1604 print $fh <<EOS; 1605CREATE TABLE users ( 1606 userid TEXT, 1607 passwd TEXT, 1608 uid INTEGER, 1609 gid INTEGER, 1610 homedir TEXT, 1611 shell TEXT 1612); 1613INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 1614 1615CREATE TABLE groups ( 1616 groupname TEXT, 1617 gid INTEGER, 1618 members TEXT 1619); 1620INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 1621EOS 1622 1623 unless (close($fh)) { 1624 die("Can't write $db_script: $!"); 1625 } 1626 1627 } else { 1628 die("Can't open $db_script: $!"); 1629 } 1630 1631 my $cmd = "sqlite3 $db_file < $db_script"; 1632 1633 if ($ENV{TEST_VERBOSE}) { 1634 print STDERR "Executing sqlite3: $cmd\n"; 1635 } 1636 1637 my @output = `$cmd`; 1638 if (scalar(@output) && 1639 $ENV{TEST_VERBOSE}) { 1640 print STDERR "Output: ", join('', @output), "\n"; 1641 } 1642 1643 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 1644 if (open(my $fh, "> $salt_file")) { 1645 binmode($fh); 1646 print $fh $salt; 1647 1648 unless (close($fh)) { 1649 die("Can't write $salt_file: $!"); 1650 } 1651 1652 } else { 1653 die("Can't open $salt_file: $!"); 1654 } 1655 1656 my $config = { 1657 PidFile => $pid_file, 1658 ScoreboardFile => $scoreboard_file, 1659 SystemLog => $log_file, 1660 1661 IfModules => { 1662 'mod_delay.c' => { 1663 DelayEngine => 'off', 1664 }, 1665 1666 'mod_sql.c' => { 1667 SQLAuthTypes => 'sha1', 1668 SQLBackend => 'sqlite3', 1669 SQLConnectInfo => $db_file, 1670 SQLLogFile => $log_file, 1671 }, 1672 1673 'mod_sql_passwd.c' => { 1674 SQLPasswordEngine => 'on', 1675 SQLPasswordEncoding => 'hex', 1676 SQLPasswordSaltFile => $salt_file, 1677 }, 1678 }, 1679 }; 1680 1681 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1682 1683 # Open pipes, for use between the parent and child processes. Specifically, 1684 # the child will indicate when it's done with its test by writing a message 1685 # to the parent. 1686 my ($rfh, $wfh); 1687 unless (pipe($rfh, $wfh)) { 1688 die("Can't open pipe: $!"); 1689 } 1690 1691 my $ex; 1692 1693 # Fork child 1694 $self->handle_sigchld(); 1695 defined(my $pid = fork()) or die("Can't fork: $!"); 1696 if ($pid) { 1697 eval { 1698 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1699 $client->login($user, "password"); 1700 1701 my $resp_msgs = $client->response_msgs(); 1702 my $nmsgs = scalar(@$resp_msgs); 1703 1704 my $expected; 1705 1706 $expected = 1; 1707 $self->assert($expected == $nmsgs, 1708 test_msg("Expected $expected, got $nmsgs")); 1709 1710 $expected = "User proftpd logged in"; 1711 $self->assert($expected eq $resp_msgs->[0], 1712 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 1713 1714 }; 1715 1716 if ($@) { 1717 $ex = $@; 1718 } 1719 1720 $wfh->print("done\n"); 1721 $wfh->flush(); 1722 1723 } else { 1724 eval { server_wait($config_file, $rfh) }; 1725 if ($@) { 1726 warn($@); 1727 exit 1; 1728 } 1729 1730 exit 0; 1731 } 1732 1733 # Stop server 1734 server_stop($pid_file); 1735 1736 $self->assert_child_ok($pid); 1737 1738 if ($ex) { 1739 test_append_logfile($log_file, $ex); 1740 unlink($log_file); 1741 1742 die($ex); 1743 } 1744 1745 unlink($log_file); 1746} 1747 1748sub sql_passwd_salt_file_trailing_newline { 1749 my $self = shift; 1750 my $tmpdir = $self->{tmpdir}; 1751 1752 my $config_file = "$tmpdir/sqlpasswd.conf"; 1753 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 1754 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 1755 1756 my $log_file = test_get_logfile(); 1757 1758 my $salt = '8Hkqr7bnPaZ52j81VvuoWdOEuq6EeXwpiIw5Q679xzvEqwe128'; 1759 1760 my $user = 'proftpd'; 1761 my $group = 'ftpd'; 1762 1763 # I used: 1764 # 1765 # Digest::SHA1::sha1_hex((lc("password")) . $salt); 1766 # 1767 # to generate this password. 1768 my $passwd = '975838a6aebc87d384535df6f7226274813353aa'; 1769 1770 my $home_dir = File::Spec->rel2abs($tmpdir); 1771 my $uid = 500; 1772 my $gid = 500; 1773 1774 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1775 1776 # Build up sqlite3 command to create users, groups tables and populate them 1777 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1778 1779 if (open(my $fh, "> $db_script")) { 1780 print $fh <<EOS; 1781CREATE TABLE users ( 1782 userid TEXT, 1783 passwd TEXT, 1784 uid INTEGER, 1785 gid INTEGER, 1786 homedir TEXT, 1787 shell TEXT 1788); 1789INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 1790 1791CREATE TABLE groups ( 1792 groupname TEXT, 1793 gid INTEGER, 1794 members TEXT 1795); 1796INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 1797EOS 1798 1799 unless (close($fh)) { 1800 die("Can't write $db_script: $!"); 1801 } 1802 1803 } else { 1804 die("Can't open $db_script: $!"); 1805 } 1806 1807 my $cmd = "sqlite3 $db_file < $db_script"; 1808 1809 if ($ENV{TEST_VERBOSE}) { 1810 print STDERR "Executing sqlite3: $cmd\n"; 1811 } 1812 1813 my @output = `$cmd`; 1814 if (scalar(@output) && 1815 $ENV{TEST_VERBOSE}) { 1816 print STDERR "Output: ", join('', @output), "\n"; 1817 } 1818 1819 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 1820 if (open(my $fh, "> $salt_file")) { 1821 binmode($fh); 1822 1823 # In this case, we deliberately write a trailing newline with the salt, 1824 # to make sure that mod_sql_passwd handles it. 1825 print $fh "$salt\n"; 1826 1827 unless (close($fh)) { 1828 die("Can't write $salt_file: $!"); 1829 } 1830 1831 } else { 1832 die("Can't open $salt_file: $!"); 1833 } 1834 1835 my $config = { 1836 PidFile => $pid_file, 1837 ScoreboardFile => $scoreboard_file, 1838 SystemLog => $log_file, 1839 1840 IfModules => { 1841 'mod_delay.c' => { 1842 DelayEngine => 'off', 1843 }, 1844 1845 'mod_sql.c' => { 1846 SQLAuthTypes => 'sha1', 1847 SQLBackend => 'sqlite3', 1848 SQLConnectInfo => $db_file, 1849 SQLLogFile => $log_file, 1850 }, 1851 1852 'mod_sql_passwd.c' => { 1853 SQLPasswordEngine => 'on', 1854 SQLPasswordEncoding => 'hex', 1855 SQLPasswordSaltFile => $salt_file, 1856 }, 1857 }, 1858 }; 1859 1860 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1861 1862 # Open pipes, for use between the parent and child processes. Specifically, 1863 # the child will indicate when it's done with its test by writing a message 1864 # to the parent. 1865 my ($rfh, $wfh); 1866 unless (pipe($rfh, $wfh)) { 1867 die("Can't open pipe: $!"); 1868 } 1869 1870 my $ex; 1871 1872 # Fork child 1873 $self->handle_sigchld(); 1874 defined(my $pid = fork()) or die("Can't fork: $!"); 1875 if ($pid) { 1876 eval { 1877 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1878 $client->login($user, "password"); 1879 1880 my $resp_msgs = $client->response_msgs(); 1881 my $nmsgs = scalar(@$resp_msgs); 1882 1883 my $expected; 1884 1885 $expected = 1; 1886 $self->assert($expected == $nmsgs, 1887 test_msg("Expected $expected, got $nmsgs")); 1888 1889 $expected = "User proftpd logged in"; 1890 $self->assert($expected eq $resp_msgs->[0], 1891 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 1892 1893 }; 1894 1895 if ($@) { 1896 $ex = $@; 1897 } 1898 1899 $wfh->print("done\n"); 1900 $wfh->flush(); 1901 1902 } else { 1903 eval { server_wait($config_file, $rfh) }; 1904 if ($@) { 1905 warn($@); 1906 exit 1; 1907 } 1908 1909 exit 0; 1910 } 1911 1912 # Stop server 1913 server_stop($pid_file); 1914 1915 $self->assert_child_ok($pid); 1916 1917 if ($ex) { 1918 test_append_logfile($log_file, $ex); 1919 unlink($log_file); 1920 1921 die($ex); 1922 } 1923 1924 unlink($log_file); 1925} 1926 1927sub sql_passwd_salt_file_prepend { 1928 my $self = shift; 1929 my $tmpdir = $self->{tmpdir}; 1930 1931 my $config_file = "$tmpdir/sqlpasswd.conf"; 1932 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 1933 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 1934 1935 my $log_file = test_get_logfile(); 1936 1937 my $salt = '8Hkqr7bnPaZ52j81VvuoWdOEuq6EeXwpiIw5Q679xzvEqwe128'; 1938 1939 my $user = 'proftpd'; 1940 my $group = 'ftpd'; 1941 1942 # I used: 1943 # 1944 # Digest::SHA1::sha1_hex($salt . lc("password")); 1945 # 1946 # to generate this password. 1947 my $passwd = 'c16542a729162ec1228919a21b36775d63391b78'; 1948 1949 my $home_dir = File::Spec->rel2abs($tmpdir); 1950 my $uid = 500; 1951 my $gid = 500; 1952 1953 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1954 1955 # Build up sqlite3 command to create users, groups tables and populate them 1956 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1957 1958 if (open(my $fh, "> $db_script")) { 1959 print $fh <<EOS; 1960CREATE TABLE users ( 1961 userid TEXT, 1962 passwd TEXT, 1963 uid INTEGER, 1964 gid INTEGER, 1965 homedir TEXT, 1966 shell TEXT 1967); 1968INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 1969 1970CREATE TABLE groups ( 1971 groupname TEXT, 1972 gid INTEGER, 1973 members TEXT 1974); 1975INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 1976EOS 1977 1978 unless (close($fh)) { 1979 die("Can't write $db_script: $!"); 1980 } 1981 1982 } else { 1983 die("Can't open $db_script: $!"); 1984 } 1985 1986 my $cmd = "sqlite3 $db_file < $db_script"; 1987 1988 if ($ENV{TEST_VERBOSE}) { 1989 print STDERR "Executing sqlite3: $cmd\n"; 1990 } 1991 1992 my @output = `$cmd`; 1993 if (scalar(@output) && 1994 $ENV{TEST_VERBOSE}) { 1995 print STDERR "Output: ", join('', @output), "\n"; 1996 } 1997 1998 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 1999 if (open(my $fh, "> $salt_file")) { 2000 binmode($fh); 2001 print $fh $salt; 2002 2003 unless (close($fh)) { 2004 die("Can't write $salt_file: $!"); 2005 } 2006 2007 } else { 2008 die("Can't open $salt_file: $!"); 2009 } 2010 2011 my $config = { 2012 PidFile => $pid_file, 2013 ScoreboardFile => $scoreboard_file, 2014 SystemLog => $log_file, 2015 2016 IfModules => { 2017 'mod_delay.c' => { 2018 DelayEngine => 'off', 2019 }, 2020 2021 'mod_sql.c' => { 2022 SQLAuthTypes => 'sha1', 2023 SQLBackend => 'sqlite3', 2024 SQLConnectInfo => $db_file, 2025 SQLLogFile => $log_file, 2026 }, 2027 2028 'mod_sql_passwd.c' => { 2029 SQLPasswordEngine => 'on', 2030 SQLPasswordEncoding => 'hex', 2031 SQLPasswordSaltFile => "$salt_file Prepend", 2032 }, 2033 }, 2034 }; 2035 2036 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2037 2038 # Open pipes, for use between the parent and child processes. Specifically, 2039 # the child will indicate when it's done with its test by writing a message 2040 # to the parent. 2041 my ($rfh, $wfh); 2042 unless (pipe($rfh, $wfh)) { 2043 die("Can't open pipe: $!"); 2044 } 2045 2046 my $ex; 2047 2048 # Fork child 2049 $self->handle_sigchld(); 2050 defined(my $pid = fork()) or die("Can't fork: $!"); 2051 if ($pid) { 2052 eval { 2053 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2054 $client->login($user, "password"); 2055 2056 my $resp_msgs = $client->response_msgs(); 2057 my $nmsgs = scalar(@$resp_msgs); 2058 2059 my $expected; 2060 2061 $expected = 1; 2062 $self->assert($expected == $nmsgs, 2063 test_msg("Expected $expected, got $nmsgs")); 2064 2065 $expected = "User proftpd logged in"; 2066 $self->assert($expected eq $resp_msgs->[0], 2067 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2068 2069 }; 2070 2071 if ($@) { 2072 $ex = $@; 2073 } 2074 2075 $wfh->print("done\n"); 2076 $wfh->flush(); 2077 2078 } else { 2079 eval { server_wait($config_file, $rfh) }; 2080 if ($@) { 2081 warn($@); 2082 exit 1; 2083 } 2084 2085 exit 0; 2086 } 2087 2088 # Stop server 2089 server_stop($pid_file); 2090 2091 $self->assert_child_ok($pid); 2092 2093 if ($ex) { 2094 test_append_logfile($log_file, $ex); 2095 unlink($log_file); 2096 2097 die($ex); 2098 } 2099 2100 unlink($log_file); 2101} 2102 2103sub sql_passwd_sha256_base64_bug3344 { 2104 my $self = shift; 2105 my $tmpdir = $self->{tmpdir}; 2106 2107 my $config_file = "$tmpdir/sqlpasswd.conf"; 2108 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 2109 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 2110 2111 my $log_file = test_get_logfile(); 2112 2113 my $user = 'proftpd'; 2114 my $group = 'ftpd'; 2115 2116 # I used: 2117 # 2118 # `/bin/echo -n "test" | openssl dgst -binary -sha256 | openssl enc -base64` 2119 # 2120 # to generate this password. 2121 my $passwd = 'n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg='; 2122 2123 my $home_dir = File::Spec->rel2abs($tmpdir); 2124 my $uid = 500; 2125 my $gid = 500; 2126 2127 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2128 2129 # Build up sqlite3 command to create users, groups tables and populate them 2130 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2131 2132 if (open(my $fh, "> $db_script")) { 2133 print $fh <<EOS; 2134CREATE TABLE users ( 2135 userid TEXT, 2136 passwd TEXT, 2137 uid INTEGER, 2138 gid INTEGER, 2139 homedir TEXT, 2140 shell TEXT 2141); 2142INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 2143 2144CREATE TABLE groups ( 2145 groupname TEXT, 2146 gid INTEGER, 2147 members TEXT 2148); 2149INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2150EOS 2151 2152 unless (close($fh)) { 2153 die("Can't write $db_script: $!"); 2154 } 2155 2156 } else { 2157 die("Can't open $db_script: $!"); 2158 } 2159 2160 my $cmd = "sqlite3 $db_file < $db_script"; 2161 2162 if ($ENV{TEST_VERBOSE}) { 2163 print STDERR "Executing sqlite3: $cmd\n"; 2164 } 2165 2166 my @output = `$cmd`; 2167 if (scalar(@output) && 2168 $ENV{TEST_VERBOSE}) { 2169 print STDERR "Output: ", join('', @output), "\n"; 2170 } 2171 2172 my $config = { 2173 PidFile => $pid_file, 2174 ScoreboardFile => $scoreboard_file, 2175 SystemLog => $log_file, 2176 2177 IfModules => { 2178 'mod_delay.c' => { 2179 DelayEngine => 'off', 2180 }, 2181 2182 'mod_sql.c' => { 2183 SQLAuthTypes => 'sha256', 2184 SQLBackend => 'sqlite3', 2185 SQLConnectInfo => $db_file, 2186 SQLLogFile => $log_file, 2187 }, 2188 2189 'mod_sql_passwd.c' => { 2190 SQLPasswordEngine => 'on', 2191 SQLPasswordEncoding => 'base64', 2192 }, 2193 }, 2194 }; 2195 2196 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2197 2198 # Open pipes, for use between the parent and child processes. Specifically, 2199 # the child will indicate when it's done with its test by writing a message 2200 # to the parent. 2201 my ($rfh, $wfh); 2202 unless (pipe($rfh, $wfh)) { 2203 die("Can't open pipe: $!"); 2204 } 2205 2206 my $ex; 2207 2208 # Fork child 2209 $self->handle_sigchld(); 2210 defined(my $pid = fork()) or die("Can't fork: $!"); 2211 if ($pid) { 2212 eval { 2213 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2214 $client->login($user, "test"); 2215 2216 my $resp_msgs = $client->response_msgs(); 2217 my $nmsgs = scalar(@$resp_msgs); 2218 2219 my $expected; 2220 2221 $expected = 1; 2222 $self->assert($expected == $nmsgs, 2223 test_msg("Expected $expected, got $nmsgs")); 2224 2225 $expected = "User proftpd logged in"; 2226 $self->assert($expected eq $resp_msgs->[0], 2227 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2228 2229 }; 2230 2231 if ($@) { 2232 $ex = $@; 2233 } 2234 2235 $wfh->print("done\n"); 2236 $wfh->flush(); 2237 2238 } else { 2239 eval { server_wait($config_file, $rfh) }; 2240 if ($@) { 2241 warn($@); 2242 exit 1; 2243 } 2244 2245 exit 0; 2246 } 2247 2248 # Stop server 2249 server_stop($pid_file); 2250 2251 $self->assert_child_ok($pid); 2252 2253 if ($ex) { 2254 test_append_logfile($log_file, $ex); 2255 unlink($log_file); 2256 2257 die($ex); 2258 } 2259 2260 unlink($log_file); 2261} 2262 2263sub sql_passwd_sha256_hex_lc_bug3344 { 2264 my $self = shift; 2265 my $tmpdir = $self->{tmpdir}; 2266 2267 my $config_file = "$tmpdir/sqlpasswd.conf"; 2268 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 2269 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 2270 2271 my $log_file = test_get_logfile(); 2272 2273 my $user = 'proftpd'; 2274 my $group = 'ftpd'; 2275 2276 # I used: 2277 # 2278 # `/bin/echo -n "test" | openssl dgst -hex -sha256` 2279 # 2280 # to generate this password. 2281 my $passwd = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'; 2282 2283 my $home_dir = File::Spec->rel2abs($tmpdir); 2284 my $uid = 500; 2285 my $gid = 500; 2286 2287 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2288 2289 # Build up sqlite3 command to create users, groups tables and populate them 2290 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2291 2292 if (open(my $fh, "> $db_script")) { 2293 print $fh <<EOS; 2294CREATE TABLE users ( 2295 userid TEXT, 2296 passwd TEXT, 2297 uid INTEGER, 2298 gid INTEGER, 2299 homedir TEXT, 2300 shell TEXT 2301); 2302INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 2303 2304CREATE TABLE groups ( 2305 groupname TEXT, 2306 gid INTEGER, 2307 members TEXT 2308); 2309INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2310EOS 2311 2312 unless (close($fh)) { 2313 die("Can't write $db_script: $!"); 2314 } 2315 2316 } else { 2317 die("Can't open $db_script: $!"); 2318 } 2319 2320 my $cmd = "sqlite3 $db_file < $db_script"; 2321 2322 if ($ENV{TEST_VERBOSE}) { 2323 print STDERR "Executing sqlite3: $cmd\n"; 2324 } 2325 2326 my @output = `$cmd`; 2327 if (scalar(@output) && 2328 $ENV{TEST_VERBOSE}) { 2329 print STDERR "Output: ", join('', @output), "\n"; 2330 } 2331 2332 my $config = { 2333 PidFile => $pid_file, 2334 ScoreboardFile => $scoreboard_file, 2335 SystemLog => $log_file, 2336 2337 IfModules => { 2338 'mod_delay.c' => { 2339 DelayEngine => 'off', 2340 }, 2341 2342 'mod_sql.c' => { 2343 SQLAuthTypes => 'sha256', 2344 SQLBackend => 'sqlite3', 2345 SQLConnectInfo => $db_file, 2346 SQLLogFile => $log_file, 2347 }, 2348 2349 'mod_sql_passwd.c' => { 2350 SQLPasswordEngine => 'on', 2351 SQLPasswordEncoding => 'hex', 2352 }, 2353 }, 2354 }; 2355 2356 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2357 2358 # Open pipes, for use between the parent and child processes. Specifically, 2359 # the child will indicate when it's done with its test by writing a message 2360 # to the parent. 2361 my ($rfh, $wfh); 2362 unless (pipe($rfh, $wfh)) { 2363 die("Can't open pipe: $!"); 2364 } 2365 2366 my $ex; 2367 2368 # Fork child 2369 $self->handle_sigchld(); 2370 defined(my $pid = fork()) or die("Can't fork: $!"); 2371 if ($pid) { 2372 eval { 2373 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2374 $client->login($user, "test"); 2375 2376 my $resp_msgs = $client->response_msgs(); 2377 my $nmsgs = scalar(@$resp_msgs); 2378 2379 my $expected; 2380 2381 $expected = 1; 2382 $self->assert($expected == $nmsgs, 2383 test_msg("Expected $expected, got $nmsgs")); 2384 2385 $expected = "User proftpd logged in"; 2386 $self->assert($expected eq $resp_msgs->[0], 2387 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2388 2389 }; 2390 2391 if ($@) { 2392 $ex = $@; 2393 } 2394 2395 $wfh->print("done\n"); 2396 $wfh->flush(); 2397 2398 } else { 2399 eval { server_wait($config_file, $rfh) }; 2400 if ($@) { 2401 warn($@); 2402 exit 1; 2403 } 2404 2405 exit 0; 2406 } 2407 2408 # Stop server 2409 server_stop($pid_file); 2410 2411 $self->assert_child_ok($pid); 2412 2413 if ($ex) { 2414 test_append_logfile($log_file, $ex); 2415 unlink($log_file); 2416 2417 die($ex); 2418 } 2419 2420 unlink($log_file); 2421} 2422 2423sub sql_passwd_sha256_hex_uc_bug3344 { 2424 my $self = shift; 2425 my $tmpdir = $self->{tmpdir}; 2426 2427 my $config_file = "$tmpdir/sqlpasswd.conf"; 2428 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 2429 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 2430 2431 my $log_file = test_get_logfile(); 2432 2433 my $user = 'proftpd'; 2434 my $group = 'ftpd'; 2435 2436 # I used: 2437 # 2438 # `/bin/echo -n "test" | openssl dgst -hex -sha256` 2439 # 2440 # to generate this password. Then I manually made all of the letters be 2441 # in uppercase. Tedious. 2442 my $passwd = '9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08'; 2443 2444 my $home_dir = File::Spec->rel2abs($tmpdir); 2445 my $uid = 500; 2446 my $gid = 500; 2447 2448 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2449 2450 # Build up sqlite3 command to create users, groups tables and populate them 2451 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2452 2453 if (open(my $fh, "> $db_script")) { 2454 print $fh <<EOS; 2455CREATE TABLE users ( 2456 userid TEXT, 2457 passwd TEXT, 2458 uid INTEGER, 2459 gid INTEGER, 2460 homedir TEXT, 2461 shell TEXT 2462); 2463INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 2464 2465CREATE TABLE groups ( 2466 groupname TEXT, 2467 gid INTEGER, 2468 members TEXT 2469); 2470INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2471EOS 2472 2473 unless (close($fh)) { 2474 die("Can't write $db_script: $!"); 2475 } 2476 2477 } else { 2478 die("Can't open $db_script: $!"); 2479 } 2480 2481 my $cmd = "sqlite3 $db_file < $db_script"; 2482 2483 if ($ENV{TEST_VERBOSE}) { 2484 print STDERR "Executing sqlite3: $cmd\n"; 2485 } 2486 2487 my @output = `$cmd`; 2488 if (scalar(@output) && 2489 $ENV{TEST_VERBOSE}) { 2490 print STDERR "Output: ", join('', @output), "\n"; 2491 } 2492 2493 my $config = { 2494 PidFile => $pid_file, 2495 ScoreboardFile => $scoreboard_file, 2496 SystemLog => $log_file, 2497 2498 IfModules => { 2499 'mod_delay.c' => { 2500 DelayEngine => 'off', 2501 }, 2502 2503 'mod_sql.c' => { 2504 SQLAuthTypes => 'sha256', 2505 SQLBackend => 'sqlite3', 2506 SQLConnectInfo => $db_file, 2507 SQLLogFile => $log_file, 2508 }, 2509 2510 'mod_sql_passwd.c' => { 2511 SQLPasswordEngine => 'on', 2512 SQLPasswordEncoding => 'HEX', 2513 }, 2514 }, 2515 }; 2516 2517 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2518 2519 # Open pipes, for use between the parent and child processes. Specifically, 2520 # the child will indicate when it's done with its test by writing a message 2521 # to the parent. 2522 my ($rfh, $wfh); 2523 unless (pipe($rfh, $wfh)) { 2524 die("Can't open pipe: $!"); 2525 } 2526 2527 my $ex; 2528 2529 # Fork child 2530 $self->handle_sigchld(); 2531 defined(my $pid = fork()) or die("Can't fork: $!"); 2532 if ($pid) { 2533 eval { 2534 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2535 $client->login($user, "test"); 2536 2537 my $resp_msgs = $client->response_msgs(); 2538 my $nmsgs = scalar(@$resp_msgs); 2539 2540 my $expected; 2541 2542 $expected = 1; 2543 $self->assert($expected == $nmsgs, 2544 test_msg("Expected $expected, got $nmsgs")); 2545 2546 $expected = "User proftpd logged in"; 2547 $self->assert($expected eq $resp_msgs->[0], 2548 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2549 2550 }; 2551 2552 if ($@) { 2553 $ex = $@; 2554 } 2555 2556 $wfh->print("done\n"); 2557 $wfh->flush(); 2558 2559 } else { 2560 eval { server_wait($config_file, $rfh) }; 2561 if ($@) { 2562 warn($@); 2563 exit 1; 2564 } 2565 2566 exit 0; 2567 } 2568 2569 # Stop server 2570 server_stop($pid_file); 2571 2572 $self->assert_child_ok($pid); 2573 2574 if ($ex) { 2575 test_append_logfile($log_file, $ex); 2576 unlink($log_file); 2577 2578 die($ex); 2579 } 2580 2581 unlink($log_file); 2582} 2583 2584sub sql_passwd_sha512_base64_bug3344 { 2585 my $self = shift; 2586 my $tmpdir = $self->{tmpdir}; 2587 2588 my $config_file = "$tmpdir/sqlpasswd.conf"; 2589 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 2590 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 2591 2592 my $log_file = test_get_logfile(); 2593 2594 my $user = 'proftpd'; 2595 my $group = 'ftpd'; 2596 2597 # I used: 2598 # 2599 # `/bin/echo -n "test" | openssl dgst -binary -sha512 | openssl enc -base64 -A` 2600 # 2601 # to generate this password. 2602 my $passwd = '7iaw3Ur350mqGo7jwQrpkj9hiYB3Lkc/iBml1JQODbJ6wYX4oOHV+E+IvIh/1nsUNzLDBMxfqa2Ob1f1ACio/w=='; 2603 2604 my $home_dir = File::Spec->rel2abs($tmpdir); 2605 my $uid = 500; 2606 my $gid = 500; 2607 2608 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2609 2610 # Build up sqlite3 command to create users, groups tables and populate them 2611 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2612 2613 if (open(my $fh, "> $db_script")) { 2614 print $fh <<EOS; 2615CREATE TABLE users ( 2616 userid TEXT, 2617 passwd TEXT, 2618 uid INTEGER, 2619 gid INTEGER, 2620 homedir TEXT, 2621 shell TEXT 2622); 2623INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 2624 2625CREATE TABLE groups ( 2626 groupname TEXT, 2627 gid INTEGER, 2628 members TEXT 2629); 2630INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2631EOS 2632 2633 unless (close($fh)) { 2634 die("Can't write $db_script: $!"); 2635 } 2636 2637 } else { 2638 die("Can't open $db_script: $!"); 2639 } 2640 2641 my $cmd = "sqlite3 $db_file < $db_script"; 2642 2643 if ($ENV{TEST_VERBOSE}) { 2644 print STDERR "Executing sqlite3: $cmd\n"; 2645 } 2646 2647 my @output = `$cmd`; 2648 if (scalar(@output) && 2649 $ENV{TEST_VERBOSE}) { 2650 print STDERR "Output: ", join('', @output), "\n"; 2651 } 2652 2653 my $config = { 2654 PidFile => $pid_file, 2655 ScoreboardFile => $scoreboard_file, 2656 SystemLog => $log_file, 2657 2658 IfModules => { 2659 'mod_delay.c' => { 2660 DelayEngine => 'off', 2661 }, 2662 2663 'mod_sql.c' => { 2664 SQLAuthTypes => 'sha512', 2665 SQLBackend => 'sqlite3', 2666 SQLConnectInfo => $db_file, 2667 SQLLogFile => $log_file, 2668 }, 2669 2670 'mod_sql_passwd.c' => { 2671 SQLPasswordEngine => 'on', 2672 SQLPasswordEncoding => 'base64', 2673 }, 2674 }, 2675 }; 2676 2677 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2678 2679 # Open pipes, for use between the parent and child processes. Specifically, 2680 # the child will indicate when it's done with its test by writing a message 2681 # to the parent. 2682 my ($rfh, $wfh); 2683 unless (pipe($rfh, $wfh)) { 2684 die("Can't open pipe: $!"); 2685 } 2686 2687 my $ex; 2688 2689 # Fork child 2690 $self->handle_sigchld(); 2691 defined(my $pid = fork()) or die("Can't fork: $!"); 2692 if ($pid) { 2693 eval { 2694 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2695 $client->login($user, "test"); 2696 2697 my $resp_msgs = $client->response_msgs(); 2698 my $nmsgs = scalar(@$resp_msgs); 2699 2700 my $expected; 2701 2702 $expected = 1; 2703 $self->assert($expected == $nmsgs, 2704 test_msg("Expected $expected, got $nmsgs")); 2705 2706 $expected = "User proftpd logged in"; 2707 $self->assert($expected eq $resp_msgs->[0], 2708 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2709 2710 }; 2711 2712 if ($@) { 2713 $ex = $@; 2714 } 2715 2716 $wfh->print("done\n"); 2717 $wfh->flush(); 2718 2719 } else { 2720 eval { server_wait($config_file, $rfh) }; 2721 if ($@) { 2722 warn($@); 2723 exit 1; 2724 } 2725 2726 exit 0; 2727 } 2728 2729 # Stop server 2730 server_stop($pid_file); 2731 2732 $self->assert_child_ok($pid); 2733 2734 if ($ex) { 2735 test_append_logfile($log_file, $ex); 2736 unlink($log_file); 2737 2738 die($ex); 2739 } 2740 2741 unlink($log_file); 2742} 2743 2744sub sql_passwd_sha512_hex_lc_bug3344 { 2745 my $self = shift; 2746 my $tmpdir = $self->{tmpdir}; 2747 2748 my $config_file = "$tmpdir/sqlpasswd.conf"; 2749 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 2750 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 2751 2752 my $log_file = test_get_logfile(); 2753 2754 my $user = 'proftpd'; 2755 my $group = 'ftpd'; 2756 2757 # I used: 2758 # 2759 # `/bin/echo -n "test" | openssl dgst -hex -sha512` 2760 # 2761 # to generate this password. 2762 my $passwd = 'ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff'; 2763 2764 my $home_dir = File::Spec->rel2abs($tmpdir); 2765 my $uid = 500; 2766 my $gid = 500; 2767 2768 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2769 2770 # Build up sqlite3 command to create users, groups tables and populate them 2771 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2772 2773 if (open(my $fh, "> $db_script")) { 2774 print $fh <<EOS; 2775CREATE TABLE users ( 2776 userid TEXT, 2777 passwd TEXT, 2778 uid INTEGER, 2779 gid INTEGER, 2780 homedir TEXT, 2781 shell TEXT 2782); 2783INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 2784 2785CREATE TABLE groups ( 2786 groupname TEXT, 2787 gid INTEGER, 2788 members TEXT 2789); 2790INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2791EOS 2792 2793 unless (close($fh)) { 2794 die("Can't write $db_script: $!"); 2795 } 2796 2797 } else { 2798 die("Can't open $db_script: $!"); 2799 } 2800 2801 my $cmd = "sqlite3 $db_file < $db_script"; 2802 2803 if ($ENV{TEST_VERBOSE}) { 2804 print STDERR "Executing sqlite3: $cmd\n"; 2805 } 2806 2807 my @output = `$cmd`; 2808 if (scalar(@output) && 2809 $ENV{TEST_VERBOSE}) { 2810 print STDERR "Output: ", join('', @output), "\n"; 2811 } 2812 2813 my $config = { 2814 PidFile => $pid_file, 2815 ScoreboardFile => $scoreboard_file, 2816 SystemLog => $log_file, 2817 2818 IfModules => { 2819 'mod_delay.c' => { 2820 DelayEngine => 'off', 2821 }, 2822 2823 'mod_sql.c' => { 2824 SQLAuthTypes => 'sha512', 2825 SQLBackend => 'sqlite3', 2826 SQLConnectInfo => $db_file, 2827 SQLLogFile => $log_file, 2828 }, 2829 2830 'mod_sql_passwd.c' => { 2831 SQLPasswordEngine => 'on', 2832 SQLPasswordEncoding => 'hex', 2833 }, 2834 }, 2835 }; 2836 2837 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2838 2839 # Open pipes, for use between the parent and child processes. Specifically, 2840 # the child will indicate when it's done with its test by writing a message 2841 # to the parent. 2842 my ($rfh, $wfh); 2843 unless (pipe($rfh, $wfh)) { 2844 die("Can't open pipe: $!"); 2845 } 2846 2847 my $ex; 2848 2849 # Fork child 2850 $self->handle_sigchld(); 2851 defined(my $pid = fork()) or die("Can't fork: $!"); 2852 if ($pid) { 2853 eval { 2854 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2855 $client->login($user, "test"); 2856 2857 my $resp_msgs = $client->response_msgs(); 2858 my $nmsgs = scalar(@$resp_msgs); 2859 2860 my $expected; 2861 2862 $expected = 1; 2863 $self->assert($expected == $nmsgs, 2864 test_msg("Expected $expected, got $nmsgs")); 2865 2866 $expected = "User proftpd logged in"; 2867 $self->assert($expected eq $resp_msgs->[0], 2868 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2869 2870 }; 2871 2872 if ($@) { 2873 $ex = $@; 2874 } 2875 2876 $wfh->print("done\n"); 2877 $wfh->flush(); 2878 2879 } else { 2880 eval { server_wait($config_file, $rfh) }; 2881 if ($@) { 2882 warn($@); 2883 exit 1; 2884 } 2885 2886 exit 0; 2887 } 2888 2889 # Stop server 2890 server_stop($pid_file); 2891 2892 $self->assert_child_ok($pid); 2893 2894 if ($ex) { 2895 test_append_logfile($log_file, $ex); 2896 unlink($log_file); 2897 2898 die($ex); 2899 } 2900 2901 unlink($log_file); 2902} 2903 2904sub sql_passwd_sha512_hex_uc_bug3344 { 2905 my $self = shift; 2906 my $tmpdir = $self->{tmpdir}; 2907 2908 my $config_file = "$tmpdir/sqlpasswd.conf"; 2909 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 2910 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 2911 2912 my $log_file = test_get_logfile(); 2913 2914 my $user = 'proftpd'; 2915 my $group = 'ftpd'; 2916 2917 # I used: 2918 # 2919 # `/bin/echo -n "test" | openssl dgst -hex -sha512` 2920 # 2921 # to generate this password. Then I manually made all of the letters be 2922 # in uppercase. Tedious. 2923 my $passwd = 'EE26B0DD4AF7E749AA1A8EE3C10AE9923F618980772E473F8819A5D4940E0DB27AC185F8A0E1D5F84F88BC887FD67B143732C304CC5FA9AD8E6F57F50028A8FF'; 2924 2925 my $home_dir = File::Spec->rel2abs($tmpdir); 2926 my $uid = 500; 2927 my $gid = 500; 2928 2929 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2930 2931 # Build up sqlite3 command to create users, groups tables and populate them 2932 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2933 2934 if (open(my $fh, "> $db_script")) { 2935 print $fh <<EOS; 2936CREATE TABLE users ( 2937 userid TEXT, 2938 passwd TEXT, 2939 uid INTEGER, 2940 gid INTEGER, 2941 homedir TEXT, 2942 shell TEXT 2943); 2944INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 2945 2946CREATE TABLE groups ( 2947 groupname TEXT, 2948 gid INTEGER, 2949 members TEXT 2950); 2951INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2952EOS 2953 2954 unless (close($fh)) { 2955 die("Can't write $db_script: $!"); 2956 } 2957 2958 } else { 2959 die("Can't open $db_script: $!"); 2960 } 2961 2962 my $cmd = "sqlite3 $db_file < $db_script"; 2963 2964 if ($ENV{TEST_VERBOSE}) { 2965 print STDERR "Executing sqlite3: $cmd\n"; 2966 } 2967 2968 my @output = `$cmd`; 2969 if (scalar(@output) && 2970 $ENV{TEST_VERBOSE}) { 2971 print STDERR "Output: ", join('', @output), "\n"; 2972 } 2973 2974 my $config = { 2975 PidFile => $pid_file, 2976 ScoreboardFile => $scoreboard_file, 2977 SystemLog => $log_file, 2978 2979 IfModules => { 2980 'mod_delay.c' => { 2981 DelayEngine => 'off', 2982 }, 2983 2984 'mod_sql.c' => { 2985 SQLAuthTypes => 'sha512', 2986 SQLBackend => 'sqlite3', 2987 SQLConnectInfo => $db_file, 2988 SQLLogFile => $log_file, 2989 }, 2990 2991 'mod_sql_passwd.c' => { 2992 SQLPasswordEngine => 'on', 2993 SQLPasswordEncoding => 'HEX', 2994 }, 2995 }, 2996 }; 2997 2998 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2999 3000 # Open pipes, for use between the parent and child processes. Specifically, 3001 # the child will indicate when it's done with its test by writing a message 3002 # to the parent. 3003 my ($rfh, $wfh); 3004 unless (pipe($rfh, $wfh)) { 3005 die("Can't open pipe: $!"); 3006 } 3007 3008 my $ex; 3009 3010 # Fork child 3011 $self->handle_sigchld(); 3012 defined(my $pid = fork()) or die("Can't fork: $!"); 3013 if ($pid) { 3014 eval { 3015 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3016 $client->login($user, "test"); 3017 3018 my $resp_msgs = $client->response_msgs(); 3019 my $nmsgs = scalar(@$resp_msgs); 3020 3021 my $expected; 3022 3023 $expected = 1; 3024 $self->assert($expected == $nmsgs, 3025 test_msg("Expected $expected, got $nmsgs")); 3026 3027 $expected = "User proftpd logged in"; 3028 $self->assert($expected eq $resp_msgs->[0], 3029 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 3030 3031 }; 3032 3033 if ($@) { 3034 $ex = $@; 3035 } 3036 3037 $wfh->print("done\n"); 3038 $wfh->flush(); 3039 3040 } else { 3041 eval { server_wait($config_file, $rfh) }; 3042 if ($@) { 3043 warn($@); 3044 exit 1; 3045 } 3046 3047 exit 0; 3048 } 3049 3050 # Stop server 3051 server_stop($pid_file); 3052 3053 $self->assert_child_ok($pid); 3054 3055 if ($ex) { 3056 test_append_logfile($log_file, $ex); 3057 unlink($log_file); 3058 3059 die($ex); 3060 } 3061 3062 unlink($log_file); 3063} 3064 3065sub sql_passwd_user_salt_name { 3066 my $self = shift; 3067 my $tmpdir = $self->{tmpdir}; 3068 3069 my $config_file = "$tmpdir/sqlpasswd.conf"; 3070 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 3071 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 3072 3073 my $log_file = test_get_logfile(); 3074 3075 my $user = 'proftpd'; 3076 my $group = 'ftpd'; 3077 3078 # I used: 3079 # 3080 # Digest::SHA1::sha1_hex((lc("password")) . $user); 3081 # 3082 # to generate this password. 3083 my $passwd = '0934e2799b96d7f93fdfaaa13853dfa291e09cb1'; 3084 3085 my $home_dir = File::Spec->rel2abs($tmpdir); 3086 my $uid = 500; 3087 my $gid = 500; 3088 3089 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3090 3091 # Build up sqlite3 command to create users, groups tables and populate them 3092 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3093 3094 if (open(my $fh, "> $db_script")) { 3095 print $fh <<EOS; 3096CREATE TABLE users ( 3097 userid TEXT, 3098 passwd TEXT, 3099 uid INTEGER, 3100 gid INTEGER, 3101 homedir TEXT, 3102 shell TEXT 3103); 3104INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 3105 3106CREATE TABLE groups ( 3107 groupname TEXT, 3108 gid INTEGER, 3109 members TEXT 3110); 3111INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', $gid, '$user'); 3112EOS 3113 3114 unless (close($fh)) { 3115 die("Can't write $db_script: $!"); 3116 } 3117 3118 } else { 3119 die("Can't open $db_script: $!"); 3120 } 3121 3122 my $cmd = "sqlite3 $db_file < $db_script"; 3123 3124 if ($ENV{TEST_VERBOSE}) { 3125 print STDERR "Executing sqlite3: $cmd\n"; 3126 } 3127 3128 my @output = `$cmd`; 3129 if (scalar(@output) && 3130 $ENV{TEST_VERBOSE}) { 3131 print STDERR "Output: ", join('', @output), "\n"; 3132 } 3133 3134 my $config = { 3135 PidFile => $pid_file, 3136 ScoreboardFile => $scoreboard_file, 3137 SystemLog => $log_file, 3138 3139 IfModules => { 3140 'mod_delay.c' => { 3141 DelayEngine => 'off', 3142 }, 3143 3144 'mod_sql.c' => { 3145 SQLAuthTypes => 'sha1', 3146 SQLBackend => 'sqlite3', 3147 SQLConnectInfo => $db_file, 3148 SQLLogFile => $log_file, 3149 }, 3150 3151 'mod_sql_passwd.c' => { 3152 SQLPasswordEngine => 'on', 3153 SQLPasswordEncoding => 'hex', 3154 SQLPasswordUserSalt => 'name', 3155 }, 3156 }, 3157 }; 3158 3159 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3160 3161 # Open pipes, for use between the parent and child processes. Specifically, 3162 # the child will indicate when it's done with its test by writing a message 3163 # to the parent. 3164 my ($rfh, $wfh); 3165 unless (pipe($rfh, $wfh)) { 3166 die("Can't open pipe: $!"); 3167 } 3168 3169 my $ex; 3170 3171 # Fork child 3172 $self->handle_sigchld(); 3173 defined(my $pid = fork()) or die("Can't fork: $!"); 3174 if ($pid) { 3175 eval { 3176 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3177 $client->login($user, "password"); 3178 3179 my $resp_msgs = $client->response_msgs(); 3180 my $nmsgs = scalar(@$resp_msgs); 3181 3182 my $expected; 3183 3184 $expected = 1; 3185 $self->assert($expected == $nmsgs, 3186 test_msg("Expected $expected, got $nmsgs")); 3187 3188 $expected = "User proftpd logged in"; 3189 $self->assert($expected eq $resp_msgs->[0], 3190 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 3191 3192 }; 3193 3194 if ($@) { 3195 $ex = $@; 3196 } 3197 3198 $wfh->print("done\n"); 3199 $wfh->flush(); 3200 3201 } else { 3202 eval { server_wait($config_file, $rfh) }; 3203 if ($@) { 3204 warn($@); 3205 exit 1; 3206 } 3207 3208 exit 0; 3209 } 3210 3211 # Stop server 3212 server_stop($pid_file); 3213 3214 $self->assert_child_ok($pid); 3215 3216 if ($ex) { 3217 test_append_logfile($log_file, $ex); 3218 unlink($log_file); 3219 3220 die($ex); 3221 } 3222 3223 unlink($log_file); 3224} 3225 3226sub sql_passwd_user_salt_sql { 3227 my $self = shift; 3228 my $tmpdir = $self->{tmpdir}; 3229 3230 my $config_file = "$tmpdir/sqlpasswd.conf"; 3231 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 3232 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 3233 3234 my $log_file = test_get_logfile(); 3235 3236 my $user = 'proftpd'; 3237 3238 my $salt = 'MyS00p3r$3kr3t$@lt'; 3239 3240 # I used: 3241 # 3242 # Digest::SHA1::sha1_hex((lc("password")) . $salt); 3243 # 3244 # to generate this password. 3245 my $passwd = 'cbaae8ec99dad240e86b64c66d31272b39a87e2e'; 3246 3247 my $home_dir = File::Spec->rel2abs($tmpdir); 3248 my $uid = 500; 3249 my $gid = 500; 3250 3251 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3252 3253 # Build up sqlite3 command to create users, groups tables and populate them 3254 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3255 3256 if (open(my $fh, "> $db_script")) { 3257 print $fh <<EOS; 3258CREATE TABLE users ( 3259 userid TEXT, 3260 passwd TEXT, 3261 uid INTEGER, 3262 gid INTEGER, 3263 homedir TEXT, 3264 shell TEXT 3265); 3266INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 3267 3268CREATE TABLE groups ( 3269 groupname TEXT, 3270 gid INTEGER, 3271 members TEXT 3272); 3273INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', $gid, '$user'); 3274 3275CREATE TABLE user_salts ( 3276 userid TEXT, 3277 salt TEXT 3278); 3279INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt'); 3280EOS 3281 3282 unless (close($fh)) { 3283 die("Can't write $db_script: $!"); 3284 } 3285 3286 } else { 3287 die("Can't open $db_script: $!"); 3288 } 3289 3290 my $cmd = "sqlite3 $db_file < $db_script"; 3291 3292 if ($ENV{TEST_VERBOSE}) { 3293 print STDERR "Executing sqlite3: $cmd\n"; 3294 } 3295 3296 my @output = `$cmd`; 3297 if (scalar(@output) && 3298 $ENV{TEST_VERBOSE}) { 3299 print STDERR "Output: ", join('', @output), "\n"; 3300 } 3301 3302 my $config = { 3303 PidFile => $pid_file, 3304 ScoreboardFile => $scoreboard_file, 3305 SystemLog => $log_file, 3306 3307 IfModules => { 3308 'mod_delay.c' => { 3309 DelayEngine => 'off', 3310 }, 3311 3312 'mod_sql.c' => { 3313 SQLAuthTypes => 'sha1', 3314 SQLBackend => 'sqlite3', 3315 SQLConnectInfo => $db_file, 3316 SQLLogFile => $log_file, 3317 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 3318 }, 3319 3320 'mod_sql_passwd.c' => { 3321 SQLPasswordEngine => 'on', 3322 SQLPasswordEncoding => 'hex', 3323 SQLPasswordUserSalt => 'sql:/get-user-salt', 3324 }, 3325 }, 3326 }; 3327 3328 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3329 3330 # Open pipes, for use between the parent and child processes. Specifically, 3331 # the child will indicate when it's done with its test by writing a message 3332 # to the parent. 3333 my ($rfh, $wfh); 3334 unless (pipe($rfh, $wfh)) { 3335 die("Can't open pipe: $!"); 3336 } 3337 3338 my $ex; 3339 3340 # Fork child 3341 $self->handle_sigchld(); 3342 defined(my $pid = fork()) or die("Can't fork: $!"); 3343 if ($pid) { 3344 eval { 3345 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3346 $client->login($user, "password"); 3347 3348 my $resp_msgs = $client->response_msgs(); 3349 my $nmsgs = scalar(@$resp_msgs); 3350 3351 my $expected; 3352 3353 $expected = 1; 3354 $self->assert($expected == $nmsgs, 3355 test_msg("Expected $expected, got $nmsgs")); 3356 3357 $expected = "User proftpd logged in"; 3358 $self->assert($expected eq $resp_msgs->[0], 3359 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 3360 3361 }; 3362 3363 if ($@) { 3364 $ex = $@; 3365 } 3366 3367 $wfh->print("done\n"); 3368 $wfh->flush(); 3369 3370 } else { 3371 eval { server_wait($config_file, $rfh) }; 3372 if ($@) { 3373 warn($@); 3374 exit 1; 3375 } 3376 3377 exit 0; 3378 } 3379 3380 # Stop server 3381 server_stop($pid_file); 3382 3383 $self->assert_child_ok($pid); 3384 3385 if ($ex) { 3386 test_append_logfile($log_file, $ex); 3387 unlink($log_file); 3388 3389 die($ex); 3390 } 3391 3392 unlink($log_file); 3393} 3394 3395sub sql_passwd_md5_hash_encode_salt_password_bug3500 { 3396 my $self = shift; 3397 my $tmpdir = $self->{tmpdir}; 3398 3399 my $config_file = "$tmpdir/sqlpasswd.conf"; 3400 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 3401 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 3402 3403 my $log_file = test_get_logfile(); 3404 3405 my $user = 'proftpd'; 3406 3407 # See http://bugs.proftpd.org/show_bug.cgi?id=3500 for more details 3408 3409 my $passwd = 'password'; 3410 my $salt = ':(Km-'; 3411 3412 # I used: 3413 # 3414 # Digest::MD5::md5_hex(Digest::MD5::md5_hex($salt) . 3415 # Digest::MD5::md5_hex($passwd)); 3416 # 3417 # to generate this password. 3418 my $db_passwd = 'e434ada7d8d3db4924d3b2bfe3bf1ce4'; 3419 3420 my $group = 'ftpd'; 3421 my $home_dir = File::Spec->rel2abs($tmpdir); 3422 my $uid = 500; 3423 my $gid = 500; 3424 3425 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3426 3427 # Build up sqlite3 command to create users, groups tables and populate them 3428 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3429 3430 if (open(my $fh, "> $db_script")) { 3431 print $fh <<EOS; 3432CREATE TABLE users ( 3433 userid TEXT, 3434 passwd TEXT, 3435 uid INTEGER, 3436 gid INTEGER, 3437 homedir TEXT, 3438 shell TEXT 3439); 3440INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$db_passwd', $uid, $gid, '$home_dir', '/bin/bash'); 3441 3442CREATE TABLE groups ( 3443 groupname TEXT, 3444 gid INTEGER, 3445 members TEXT 3446); 3447INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 3448 3449CREATE TABLE user_salts ( 3450 userid TEXT, 3451 salt TEXT 3452); 3453INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt'); 3454EOS 3455 3456 unless (close($fh)) { 3457 die("Can't write $db_script: $!"); 3458 } 3459 3460 } else { 3461 die("Can't open $db_script: $!"); 3462 } 3463 3464 my $cmd = "sqlite3 $db_file < $db_script"; 3465 3466 if ($ENV{TEST_VERBOSE}) { 3467 print STDERR "Executing sqlite3: $cmd\n"; 3468 } 3469 3470 my @output = `$cmd`; 3471 if (scalar(@output) && 3472 $ENV{TEST_VERBOSE}) { 3473 print STDERR "Output: ", join('', @output), "\n"; 3474 } 3475 3476 my $config = { 3477 PidFile => $pid_file, 3478 ScoreboardFile => $scoreboard_file, 3479 SystemLog => $log_file, 3480 3481 IfModules => { 3482 'mod_delay.c' => { 3483 DelayEngine => 'off', 3484 }, 3485 3486 'mod_sql.c' => { 3487 SQLAuthTypes => 'md5', 3488 SQLBackend => 'sqlite3', 3489 SQLConnectInfo => $db_file, 3490 SQLLogFile => $log_file, 3491 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 3492 SQLMinID => '100', 3493 }, 3494 3495 'mod_sql_passwd.c' => { 3496 SQLPasswordEngine => 'on', 3497 SQLPasswordEncoding => 'hex', 3498 SQLPasswordUserSalt => 'sql:/get-user-salt Prepend', 3499 3500 # Tell mod_sql_passwd to transform both the salt and the password 3501 # before transforming the combination of them. 3502 SQLPasswordOptions => 'HashEncodeSalt HashEncodePassword', 3503 }, 3504 }, 3505 }; 3506 3507 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3508 3509 # Open pipes, for use between the parent and child processes. Specifically, 3510 # the child will indicate when it's done with its test by writing a message 3511 # to the parent. 3512 my ($rfh, $wfh); 3513 unless (pipe($rfh, $wfh)) { 3514 die("Can't open pipe: $!"); 3515 } 3516 3517 my $ex; 3518 3519 # Fork child 3520 $self->handle_sigchld(); 3521 defined(my $pid = fork()) or die("Can't fork: $!"); 3522 if ($pid) { 3523 eval { 3524 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3525 $client->login($user, $passwd); 3526 3527 my $resp_msgs = $client->response_msgs(); 3528 my $nmsgs = scalar(@$resp_msgs); 3529 3530 my $expected; 3531 3532 $expected = 1; 3533 $self->assert($expected == $nmsgs, 3534 test_msg("Expected $expected, got $nmsgs")); 3535 3536 $expected = "User proftpd logged in"; 3537 $self->assert($expected eq $resp_msgs->[0], 3538 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 3539 3540 }; 3541 3542 if ($@) { 3543 $ex = $@; 3544 } 3545 3546 $wfh->print("done\n"); 3547 $wfh->flush(); 3548 3549 } else { 3550 eval { server_wait($config_file, $rfh) }; 3551 if ($@) { 3552 warn($@); 3553 exit 1; 3554 } 3555 3556 exit 0; 3557 } 3558 3559 # Stop server 3560 server_stop($pid_file); 3561 3562 $self->assert_child_ok($pid); 3563 3564 if ($ex) { 3565 test_append_logfile($log_file, $ex); 3566 unlink($log_file); 3567 3568 die($ex); 3569 } 3570 3571 unlink($log_file); 3572} 3573 3574sub sql_passwd_md5_hash_encode_password_bug3500 { 3575 my $self = shift; 3576 my $tmpdir = $self->{tmpdir}; 3577 3578 my $config_file = "$tmpdir/sqlpasswd.conf"; 3579 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 3580 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 3581 3582 my $log_file = test_get_logfile(); 3583 3584 my $user = 'proftpd'; 3585 3586 # See http://bugs.proftpd.org/show_bug.cgi?id=3500 for more details 3587 3588 my $passwd = 'password'; 3589 3590 # I used: 3591 # 3592 # Digest::MD5::md5_hex($passwd) 3593 # 3594 # to generate this password. 3595 my $db_passwd = '5f4dcc3b5aa765d61d8327deb882cf99'; 3596 3597 my $group = 'ftpd'; 3598 my $home_dir = File::Spec->rel2abs($tmpdir); 3599 my $uid = 500; 3600 my $gid = 500; 3601 3602 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3603 3604 # Build up sqlite3 command to create users, groups tables and populate them 3605 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3606 3607 if (open(my $fh, "> $db_script")) { 3608 print $fh <<EOS; 3609CREATE TABLE users ( 3610 userid TEXT, 3611 passwd TEXT, 3612 uid INTEGER, 3613 gid INTEGER, 3614 homedir TEXT, 3615 shell TEXT 3616); 3617INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$db_passwd', $uid, $gid, '$home_dir', '/bin/bash'); 3618 3619CREATE TABLE groups ( 3620 groupname TEXT, 3621 gid INTEGER, 3622 members TEXT 3623); 3624INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 3625 3626EOS 3627 3628 unless (close($fh)) { 3629 die("Can't write $db_script: $!"); 3630 } 3631 3632 } else { 3633 die("Can't open $db_script: $!"); 3634 } 3635 3636 my $cmd = "sqlite3 $db_file < $db_script"; 3637 3638 if ($ENV{TEST_VERBOSE}) { 3639 print STDERR "Executing sqlite3: $cmd\n"; 3640 } 3641 3642 my @output = `$cmd`; 3643 if (scalar(@output) && 3644 $ENV{TEST_VERBOSE}) { 3645 print STDERR "Output: ", join('', @output), "\n"; 3646 } 3647 3648 my $config = { 3649 PidFile => $pid_file, 3650 ScoreboardFile => $scoreboard_file, 3651 SystemLog => $log_file, 3652 3653 IfModules => { 3654 'mod_delay.c' => { 3655 DelayEngine => 'off', 3656 }, 3657 3658 'mod_sql.c' => { 3659 SQLAuthTypes => 'md5', 3660 SQLBackend => 'sqlite3', 3661 SQLConnectInfo => $db_file, 3662 SQLLogFile => $log_file, 3663 SQLMinID => '100', 3664 }, 3665 3666 'mod_sql_passwd.c' => { 3667 SQLPasswordEngine => 'on', 3668 SQLPasswordEncoding => 'hex', 3669 3670 # Tell mod_sql_passwd to transform the password 3671 # before transforming the combination of them. 3672 SQLPasswordOptions => 'HashEncodePassword', 3673 }, 3674 }, 3675 }; 3676 3677 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3678 3679 # Open pipes, for use between the parent and child processes. Specifically, 3680 # the child will indicate when it's done with its test by writing a message 3681 # to the parent. 3682 my ($rfh, $wfh); 3683 unless (pipe($rfh, $wfh)) { 3684 die("Can't open pipe: $!"); 3685 } 3686 3687 my $ex; 3688 3689 # Fork child 3690 $self->handle_sigchld(); 3691 defined(my $pid = fork()) or die("Can't fork: $!"); 3692 if ($pid) { 3693 eval { 3694 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3695 $client->login($user, $passwd); 3696 3697 my $resp_msgs = $client->response_msgs(); 3698 my $nmsgs = scalar(@$resp_msgs); 3699 3700 my $expected; 3701 3702 $expected = 1; 3703 $self->assert($expected == $nmsgs, 3704 test_msg("Expected $expected, got $nmsgs")); 3705 3706 $expected = "User proftpd logged in"; 3707 $self->assert($expected eq $resp_msgs->[0], 3708 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 3709 3710 }; 3711 3712 if ($@) { 3713 $ex = $@; 3714 } 3715 3716 $wfh->print("done\n"); 3717 $wfh->flush(); 3718 3719 } else { 3720 eval { server_wait($config_file, $rfh) }; 3721 if ($@) { 3722 warn($@); 3723 exit 1; 3724 } 3725 3726 exit 0; 3727 } 3728 3729 # Stop server 3730 server_stop($pid_file); 3731 3732 $self->assert_child_ok($pid); 3733 3734 if ($ex) { 3735 test_append_logfile($log_file, $ex); 3736 unlink($log_file); 3737 3738 die($ex); 3739 } 3740 3741 unlink($log_file); 3742} 3743 3744sub sql_passwd_md5_rounds_bug3500 { 3745 my $self = shift; 3746 my $tmpdir = $self->{tmpdir}; 3747 3748 my $config_file = "$tmpdir/sqlpasswd.conf"; 3749 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 3750 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 3751 3752 my $log_file = test_get_logfile(); 3753 3754 my $user = 'proftpd'; 3755 3756 # See http://bugs.proftpd.org/show_bug.cgi?id=3500 for more details 3757 3758 my $passwd = 'Password'; 3759 my $salt = 'Sav0ryS4lt'; 3760 3761 # I used: 3762 # 3763 # Digest::MD5::md5_hex( 3764 # Digest::MD5::md5_hex( 3765 # Digest::MD5::md5_hex($salt . $passwd))); 3766 # 3767 # to generate this password. 3768 my $db_passwd = 'ca71e8bd1170c941633124ea4e424320'; 3769 3770 my $group = 'ftpd'; 3771 my $home_dir = File::Spec->rel2abs($tmpdir); 3772 my $uid = 500; 3773 my $gid = 500; 3774 3775 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3776 3777 # Build up sqlite3 command to create users, groups tables and populate them 3778 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3779 3780 if (open(my $fh, "> $db_script")) { 3781 print $fh <<EOS; 3782CREATE TABLE users ( 3783 userid TEXT, 3784 passwd TEXT, 3785 uid INTEGER, 3786 gid INTEGER, 3787 homedir TEXT, 3788 shell TEXT 3789); 3790INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$db_passwd', $uid, $gid, '$home_dir', '/bin/bash'); 3791 3792CREATE TABLE groups ( 3793 groupname TEXT, 3794 gid INTEGER, 3795 members TEXT 3796); 3797INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 3798 3799CREATE TABLE user_salts ( 3800 userid TEXT, 3801 salt TEXT 3802); 3803INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt'); 3804EOS 3805 3806 unless (close($fh)) { 3807 die("Can't write $db_script: $!"); 3808 } 3809 3810 } else { 3811 die("Can't open $db_script: $!"); 3812 } 3813 3814 my $cmd = "sqlite3 $db_file < $db_script"; 3815 3816 if ($ENV{TEST_VERBOSE}) { 3817 print STDERR "Executing sqlite3: $cmd\n"; 3818 } 3819 3820 my @output = `$cmd`; 3821 if (scalar(@output) && 3822 $ENV{TEST_VERBOSE}) { 3823 print STDERR "Output: ", join('', @output), "\n"; 3824 } 3825 3826 my $config = { 3827 PidFile => $pid_file, 3828 ScoreboardFile => $scoreboard_file, 3829 SystemLog => $log_file, 3830 3831 IfModules => { 3832 'mod_delay.c' => { 3833 DelayEngine => 'off', 3834 }, 3835 3836 'mod_sql.c' => { 3837 SQLAuthTypes => 'md5', 3838 SQLBackend => 'sqlite3', 3839 SQLConnectInfo => $db_file, 3840 SQLLogFile => $log_file, 3841 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 3842 SQLMinID => '100', 3843 }, 3844 3845 'mod_sql_passwd.c' => { 3846 SQLPasswordEngine => 'on', 3847 SQLPasswordEncoding => 'hex', 3848 SQLPasswordUserSalt => 'sql:/get-user-salt Prepend', 3849 3850 # Tell mod_sql_passwd to use three rounds of transformation 3851 SQLPasswordRounds => '3', 3852 }, 3853 }, 3854 }; 3855 3856 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3857 3858 # Open pipes, for use between the parent and child processes. Specifically, 3859 # the child will indicate when it's done with its test by writing a message 3860 # to the parent. 3861 my ($rfh, $wfh); 3862 unless (pipe($rfh, $wfh)) { 3863 die("Can't open pipe: $!"); 3864 } 3865 3866 my $ex; 3867 3868 # Fork child 3869 $self->handle_sigchld(); 3870 defined(my $pid = fork()) or die("Can't fork: $!"); 3871 if ($pid) { 3872 eval { 3873 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3874 $client->login($user, $passwd); 3875 3876 my $resp_msgs = $client->response_msgs(); 3877 my $nmsgs = scalar(@$resp_msgs); 3878 3879 my $expected; 3880 3881 $expected = 1; 3882 $self->assert($expected == $nmsgs, 3883 test_msg("Expected $expected, got $nmsgs")); 3884 3885 $expected = "User proftpd logged in"; 3886 $self->assert($expected eq $resp_msgs->[0], 3887 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 3888 3889 }; 3890 3891 if ($@) { 3892 $ex = $@; 3893 } 3894 3895 $wfh->print("done\n"); 3896 $wfh->flush(); 3897 3898 } else { 3899 eval { server_wait($config_file, $rfh) }; 3900 if ($@) { 3901 warn($@); 3902 exit 1; 3903 } 3904 3905 exit 0; 3906 } 3907 3908 # Stop server 3909 server_stop($pid_file); 3910 3911 $self->assert_child_ok($pid); 3912 3913 if ($ex) { 3914 test_append_logfile($log_file, $ex); 3915 unlink($log_file); 3916 3917 die($ex); 3918 } 3919 3920 unlink($log_file); 3921} 3922 3923sub sql_passwd_md5_rounds_hash_encode_salt_password_bug3500 { 3924 my $self = shift; 3925 my $tmpdir = $self->{tmpdir}; 3926 3927 my $config_file = "$tmpdir/sqlpasswd.conf"; 3928 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 3929 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 3930 3931 my $log_file = test_get_logfile(); 3932 3933 my $user = 'proftpd'; 3934 3935 # See http://bugs.proftpd.org/show_bug.cgi?id=3500 for more details 3936 3937 my $passwd = 'Password'; 3938 my $salt = 'Sav0ryS4lt'; 3939 3940 # I used: 3941 # 3942 # Digest::MD5::md5_hex( 3943 # Digest::MD5::md5_hex( 3944 # Digest::MD5::md5_hex( 3945 # Digest::MD5::md5_hex($salt) . Digest::MD5::md5_hex($passwd)))); 3946 # 3947 # to generate this password. 3948 my $db_passwd = 'b317dcd1738a96a608c27607dd8179c0'; 3949 3950 my $group = 'ftpd'; 3951 my $home_dir = File::Spec->rel2abs($tmpdir); 3952 my $uid = 500; 3953 my $gid = 500; 3954 3955 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3956 3957 # Build up sqlite3 command to create users, groups tables and populate them 3958 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3959 3960 if (open(my $fh, "> $db_script")) { 3961 print $fh <<EOS; 3962CREATE TABLE users ( 3963 userid TEXT, 3964 passwd TEXT, 3965 uid INTEGER, 3966 gid INTEGER, 3967 homedir TEXT, 3968 shell TEXT 3969); 3970INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$db_passwd', $uid, $gid, '$home_dir', '/bin/bash'); 3971 3972CREATE TABLE groups ( 3973 groupname TEXT, 3974 gid INTEGER, 3975 members TEXT 3976); 3977INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 3978 3979CREATE TABLE user_salts ( 3980 userid TEXT, 3981 salt TEXT 3982); 3983INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt'); 3984EOS 3985 3986 unless (close($fh)) { 3987 die("Can't write $db_script: $!"); 3988 } 3989 3990 } else { 3991 die("Can't open $db_script: $!"); 3992 } 3993 3994 my $cmd = "sqlite3 $db_file < $db_script"; 3995 3996 if ($ENV{TEST_VERBOSE}) { 3997 print STDERR "Executing sqlite3: $cmd\n"; 3998 } 3999 4000 my @output = `$cmd`; 4001 if (scalar(@output) && 4002 $ENV{TEST_VERBOSE}) { 4003 print STDERR "Output: ", join('', @output), "\n"; 4004 } 4005 4006 my $config = { 4007 PidFile => $pid_file, 4008 ScoreboardFile => $scoreboard_file, 4009 SystemLog => $log_file, 4010 4011 IfModules => { 4012 'mod_delay.c' => { 4013 DelayEngine => 'off', 4014 }, 4015 4016 'mod_sql.c' => { 4017 SQLAuthTypes => 'md5', 4018 SQLBackend => 'sqlite3', 4019 SQLConnectInfo => $db_file, 4020 SQLLogFile => $log_file, 4021 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 4022 SQLMinID => '100', 4023 }, 4024 4025 'mod_sql_passwd.c' => { 4026 SQLPasswordEngine => 'on', 4027 SQLPasswordEncoding => 'hex', 4028 SQLPasswordUserSalt => 'sql:/get-user-salt Prepend', 4029 4030 # Tell mod_sql_passwd to transform salt and password 4031 SQLPasswordOptions => 'HashEncodePassword HashEncodeSalt', 4032 4033 # Tell mod_sql_passwd to use three rounds of transformation 4034 SQLPasswordRounds => '3', 4035 }, 4036 }, 4037 }; 4038 4039 my ($port, $config_user, $config_group) = config_write($config_file, $config); 4040 4041 # Open pipes, for use between the parent and child processes. Specifically, 4042 # the child will indicate when it's done with its test by writing a message 4043 # to the parent. 4044 my ($rfh, $wfh); 4045 unless (pipe($rfh, $wfh)) { 4046 die("Can't open pipe: $!"); 4047 } 4048 4049 my $ex; 4050 4051 # Fork child 4052 $self->handle_sigchld(); 4053 defined(my $pid = fork()) or die("Can't fork: $!"); 4054 if ($pid) { 4055 eval { 4056 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4057 $client->login($user, $passwd); 4058 4059 my $resp_msgs = $client->response_msgs(); 4060 my $nmsgs = scalar(@$resp_msgs); 4061 4062 my $expected; 4063 4064 $expected = 1; 4065 $self->assert($expected == $nmsgs, 4066 test_msg("Expected $expected, got $nmsgs")); 4067 4068 $expected = "User proftpd logged in"; 4069 $self->assert($expected eq $resp_msgs->[0], 4070 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 4071 4072 }; 4073 4074 if ($@) { 4075 $ex = $@; 4076 } 4077 4078 $wfh->print("done\n"); 4079 $wfh->flush(); 4080 4081 } else { 4082 eval { server_wait($config_file, $rfh) }; 4083 if ($@) { 4084 warn($@); 4085 exit 1; 4086 } 4087 4088 exit 0; 4089 } 4090 4091 # Stop server 4092 server_stop($pid_file); 4093 4094 $self->assert_child_ok($pid); 4095 4096 if ($ex) { 4097 test_append_logfile($log_file, $ex); 4098 unlink($log_file); 4099 4100 die($ex); 4101 } 4102 4103 unlink($log_file); 4104} 4105 4106sub sql_passwd_md5_hash_password { 4107 my $self = shift; 4108 my $tmpdir = $self->{tmpdir}; 4109 4110 my $config_file = "$tmpdir/sqlpasswd.conf"; 4111 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 4112 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 4113 4114 my $log_file = test_get_logfile(); 4115 4116 my $user = 'proftpd'; 4117 4118 # See http://bugs.proftpd.org/show_bug.cgi?id=3500 for more details 4119 4120 my $passwd = 'password'; 4121 4122 # I used: 4123 # 4124 # Digest::MD5::md5_hex(Digest::MD5::md5($passwd)); 4125 # 4126 # to generate this password. 4127 my $db_passwd = '9bf4b3611c53176f5c649aa4fc1ff6b2'; 4128 4129 my $group = 'ftpd'; 4130 my $home_dir = File::Spec->rel2abs($tmpdir); 4131 my $uid = 500; 4132 my $gid = 500; 4133 4134 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4135 4136 # Build up sqlite3 command to create users, groups tables and populate them 4137 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4138 4139 if (open(my $fh, "> $db_script")) { 4140 print $fh <<EOS; 4141CREATE TABLE users ( 4142 userid TEXT, 4143 passwd TEXT, 4144 uid INTEGER, 4145 gid INTEGER, 4146 homedir TEXT, 4147 shell TEXT 4148); 4149INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$db_passwd', $uid, $gid, '$home_dir', '/bin/bash'); 4150 4151CREATE TABLE groups ( 4152 groupname TEXT, 4153 gid INTEGER, 4154 members TEXT 4155); 4156INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 4157 4158EOS 4159 4160 unless (close($fh)) { 4161 die("Can't write $db_script: $!"); 4162 } 4163 4164 } else { 4165 die("Can't open $db_script: $!"); 4166 } 4167 4168 my $cmd = "sqlite3 $db_file < $db_script"; 4169 4170 if ($ENV{TEST_VERBOSE}) { 4171 print STDERR "Executing sqlite3: $cmd\n"; 4172 } 4173 4174 my @output = `$cmd`; 4175 if (scalar(@output) && 4176 $ENV{TEST_VERBOSE}) { 4177 print STDERR "Output: ", join('', @output), "\n"; 4178 } 4179 4180 my $config = { 4181 PidFile => $pid_file, 4182 ScoreboardFile => $scoreboard_file, 4183 SystemLog => $log_file, 4184 4185 IfModules => { 4186 'mod_delay.c' => { 4187 DelayEngine => 'off', 4188 }, 4189 4190 'mod_sql.c' => { 4191 SQLAuthTypes => 'md5', 4192 SQLBackend => 'sqlite3', 4193 SQLConnectInfo => $db_file, 4194 SQLLogFile => $log_file, 4195 SQLMinID => '100', 4196 }, 4197 4198 'mod_sql_passwd.c' => { 4199 SQLPasswordEngine => 'on', 4200 SQLPasswordEncoding => 'hex', 4201 4202 SQLPasswordOptions => 'HashPassword', 4203 }, 4204 }, 4205 }; 4206 4207 my ($port, $config_user, $config_group) = config_write($config_file, $config); 4208 4209 # Open pipes, for use between the parent and child processes. Specifically, 4210 # the child will indicate when it's done with its test by writing a message 4211 # to the parent. 4212 my ($rfh, $wfh); 4213 unless (pipe($rfh, $wfh)) { 4214 die("Can't open pipe: $!"); 4215 } 4216 4217 my $ex; 4218 4219 # Fork child 4220 $self->handle_sigchld(); 4221 defined(my $pid = fork()) or die("Can't fork: $!"); 4222 if ($pid) { 4223 eval { 4224 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4225 $client->login($user, $passwd); 4226 4227 my $resp_msgs = $client->response_msgs(); 4228 my $nmsgs = scalar(@$resp_msgs); 4229 4230 my $expected; 4231 4232 $expected = 1; 4233 $self->assert($expected == $nmsgs, 4234 test_msg("Expected $expected, got $nmsgs")); 4235 4236 $expected = "User proftpd logged in"; 4237 $self->assert($expected eq $resp_msgs->[0], 4238 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 4239 4240 }; 4241 4242 if ($@) { 4243 $ex = $@; 4244 } 4245 4246 $wfh->print("done\n"); 4247 $wfh->flush(); 4248 4249 } else { 4250 eval { server_wait($config_file, $rfh) }; 4251 if ($@) { 4252 warn($@); 4253 exit 1; 4254 } 4255 4256 exit 0; 4257 } 4258 4259 # Stop server 4260 server_stop($pid_file); 4261 4262 $self->assert_child_ok($pid); 4263 4264 if ($ex) { 4265 test_append_logfile($log_file, $ex); 4266 unlink($log_file); 4267 4268 die($ex); 4269 } 4270 4271 unlink($log_file); 4272} 4273 4274sub sql_passwd_md5_hash_salt { 4275 my $self = shift; 4276 my $tmpdir = $self->{tmpdir}; 4277 4278 my $config_file = "$tmpdir/sqlpasswd.conf"; 4279 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 4280 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 4281 4282 my $log_file = test_get_logfile(); 4283 4284 my $user = 'proftpd'; 4285 4286 # See http://bugs.proftpd.org/show_bug.cgi?id=3500 for more details 4287 4288 my $passwd = 'password'; 4289 my $salt = ':(Km-'; 4290 4291 # I used: 4292 # 4293 # Digest::MD5::md5_hex(Digest::MD5::md5($salt) . $passwd); 4294 # 4295 # to generate this password. 4296 my $db_passwd = '6d829eb1782d1295a04a983da3d1286d'; 4297 4298 my $group = 'ftpd'; 4299 my $home_dir = File::Spec->rel2abs($tmpdir); 4300 my $uid = 500; 4301 my $gid = 500; 4302 4303 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4304 4305 # Build up sqlite3 command to create users, groups tables and populate them 4306 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4307 4308 if (open(my $fh, "> $db_script")) { 4309 print $fh <<EOS; 4310CREATE TABLE users ( 4311 userid TEXT, 4312 passwd TEXT, 4313 uid INTEGER, 4314 gid INTEGER, 4315 homedir TEXT, 4316 shell TEXT 4317); 4318INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$db_passwd', $uid, $gid, '$home_dir', '/bin/bash'); 4319 4320CREATE TABLE groups ( 4321 groupname TEXT, 4322 gid INTEGER, 4323 members TEXT 4324); 4325INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 4326 4327CREATE TABLE user_salts ( 4328 userid TEXT, 4329 salt TEXT 4330); 4331INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt'); 4332EOS 4333 4334 unless (close($fh)) { 4335 die("Can't write $db_script: $!"); 4336 } 4337 4338 } else { 4339 die("Can't open $db_script: $!"); 4340 } 4341 4342 my $cmd = "sqlite3 $db_file < $db_script"; 4343 4344 if ($ENV{TEST_VERBOSE}) { 4345 print STDERR "Executing sqlite3: $cmd\n"; 4346 } 4347 4348 my @output = `$cmd`; 4349 if (scalar(@output) && 4350 $ENV{TEST_VERBOSE}) { 4351 print STDERR "Output: ", join('', @output), "\n"; 4352 } 4353 4354 my $config = { 4355 PidFile => $pid_file, 4356 ScoreboardFile => $scoreboard_file, 4357 SystemLog => $log_file, 4358 4359 IfModules => { 4360 'mod_delay.c' => { 4361 DelayEngine => 'off', 4362 }, 4363 4364 'mod_sql.c' => { 4365 SQLAuthTypes => 'md5', 4366 SQLBackend => 'sqlite3', 4367 SQLConnectInfo => $db_file, 4368 SQLLogFile => $log_file, 4369 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 4370 SQLMinID => '100', 4371 }, 4372 4373 'mod_sql_passwd.c' => { 4374 SQLPasswordEngine => 'on', 4375 SQLPasswordEncoding => 'hex', 4376 SQLPasswordUserSalt => 'sql:/get-user-salt Prepend', 4377 4378 SQLPasswordOptions => 'HashSalt', 4379 }, 4380 }, 4381 }; 4382 4383 my ($port, $config_user, $config_group) = config_write($config_file, $config); 4384 4385 # Open pipes, for use between the parent and child processes. Specifically, 4386 # the child will indicate when it's done with its test by writing a message 4387 # to the parent. 4388 my ($rfh, $wfh); 4389 unless (pipe($rfh, $wfh)) { 4390 die("Can't open pipe: $!"); 4391 } 4392 4393 my $ex; 4394 4395 # Fork child 4396 $self->handle_sigchld(); 4397 defined(my $pid = fork()) or die("Can't fork: $!"); 4398 if ($pid) { 4399 eval { 4400 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4401 $client->login($user, $passwd); 4402 4403 my $resp_msgs = $client->response_msgs(); 4404 my $nmsgs = scalar(@$resp_msgs); 4405 4406 my $expected; 4407 4408 $expected = 1; 4409 $self->assert($expected == $nmsgs, 4410 test_msg("Expected $expected, got $nmsgs")); 4411 4412 $expected = "User proftpd logged in"; 4413 $self->assert($expected eq $resp_msgs->[0], 4414 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 4415 4416 }; 4417 4418 if ($@) { 4419 $ex = $@; 4420 } 4421 4422 $wfh->print("done\n"); 4423 $wfh->flush(); 4424 4425 } else { 4426 eval { server_wait($config_file, $rfh) }; 4427 if ($@) { 4428 warn($@); 4429 exit 1; 4430 } 4431 4432 exit 0; 4433 } 4434 4435 # Stop server 4436 server_stop($pid_file); 4437 4438 $self->assert_child_ok($pid); 4439 4440 if ($ex) { 4441 test_append_logfile($log_file, $ex); 4442 unlink($log_file); 4443 4444 die($ex); 4445 } 4446 4447 unlink($log_file); 4448} 4449 4450sub sql_passwd_md5_encode_salt { 4451 my $self = shift; 4452 my $tmpdir = $self->{tmpdir}; 4453 4454 my $config_file = "$tmpdir/sqlpasswd.conf"; 4455 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 4456 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 4457 4458 my $log_file = test_get_logfile(); 4459 4460 my $user = 'proftpd'; 4461 4462 # See http://bugs.proftpd.org/show_bug.cgi?id=3500 for more details 4463 4464 my $passwd = 'password'; 4465 my $salt = ':(Km-'; 4466 4467 # I used: 4468 # 4469 # Digest::MD5::md5_hex(Digest::MD5::md5_hex($salt) . 4470 # Digest::MD5::md5_hex($passwd)); 4471 # 4472 # to generate this password. 4473 my $db_passwd = 'e434ada7d8d3db4924d3b2bfe3bf1ce4'; 4474 4475 my $group = 'ftpd'; 4476 my $home_dir = File::Spec->rel2abs($tmpdir); 4477 my $uid = 500; 4478 my $gid = 500; 4479 4480 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4481 4482 # Build up sqlite3 command to create users, groups tables and populate them 4483 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4484 4485 if (open(my $fh, "> $db_script")) { 4486 print $fh <<EOS; 4487CREATE TABLE users ( 4488 userid TEXT, 4489 passwd TEXT, 4490 uid INTEGER, 4491 gid INTEGER, 4492 homedir TEXT, 4493 shell TEXT 4494); 4495INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$db_passwd', $uid, $gid, '$home_dir', '/bin/bash'); 4496 4497CREATE TABLE groups ( 4498 groupname TEXT, 4499 gid INTEGER, 4500 members TEXT 4501); 4502INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 4503 4504CREATE TABLE user_salts ( 4505 userid TEXT, 4506 salt TEXT 4507); 4508INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt'); 4509EOS 4510 4511 unless (close($fh)) { 4512 die("Can't write $db_script: $!"); 4513 } 4514 4515 } else { 4516 die("Can't open $db_script: $!"); 4517 } 4518 4519 my $cmd = "sqlite3 $db_file < $db_script"; 4520 4521 if ($ENV{TEST_VERBOSE}) { 4522 print STDERR "Executing sqlite3: $cmd\n"; 4523 } 4524 4525 my @output = `$cmd`; 4526 if (scalar(@output) && 4527 $ENV{TEST_VERBOSE}) { 4528 print STDERR "Output: ", join('', @output), "\n"; 4529 } 4530 4531 my $config = { 4532 PidFile => $pid_file, 4533 ScoreboardFile => $scoreboard_file, 4534 SystemLog => $log_file, 4535 4536 IfModules => { 4537 'mod_delay.c' => { 4538 DelayEngine => 'off', 4539 }, 4540 4541 'mod_sql.c' => { 4542 SQLAuthTypes => 'md5', 4543 SQLBackend => 'sqlite3', 4544 SQLConnectInfo => $db_file, 4545 SQLLogFile => $log_file, 4546 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 4547 SQLMinID => '100', 4548 }, 4549 4550 'mod_sql_passwd.c' => { 4551 SQLPasswordEngine => 'on', 4552 SQLPasswordEncoding => 'hex', 4553 SQLPasswordUserSalt => 'sql:/get-user-salt Prepend', 4554 4555 # Tell mod_sql_passwd to transform both the salt and the password 4556 # before transforming the combination of them. 4557 SQLPasswordOptions => 'HashEncodeSalt HashEncodePassword', 4558 }, 4559 }, 4560 }; 4561 4562 my ($port, $config_user, $config_group) = config_write($config_file, $config); 4563 4564 # Open pipes, for use between the parent and child processes. Specifically, 4565 # the child will indicate when it's done with its test by writing a message 4566 # to the parent. 4567 my ($rfh, $wfh); 4568 unless (pipe($rfh, $wfh)) { 4569 die("Can't open pipe: $!"); 4570 } 4571 4572 my $ex; 4573 4574 # Fork child 4575 $self->handle_sigchld(); 4576 defined(my $pid = fork()) or die("Can't fork: $!"); 4577 if ($pid) { 4578 eval { 4579 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4580 $client->login($user, $passwd); 4581 4582 my $resp_msgs = $client->response_msgs(); 4583 my $nmsgs = scalar(@$resp_msgs); 4584 4585 my $expected; 4586 4587 $expected = 1; 4588 $self->assert($expected == $nmsgs, 4589 test_msg("Expected $expected, got $nmsgs")); 4590 4591 $expected = "User proftpd logged in"; 4592 $self->assert($expected eq $resp_msgs->[0], 4593 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 4594 4595 }; 4596 4597 if ($@) { 4598 $ex = $@; 4599 } 4600 4601 $wfh->print("done\n"); 4602 $wfh->flush(); 4603 4604 } else { 4605 eval { server_wait($config_file, $rfh) }; 4606 if ($@) { 4607 warn($@); 4608 exit 1; 4609 } 4610 4611 exit 0; 4612 } 4613 4614 # Stop server 4615 server_stop($pid_file); 4616 4617 $self->assert_child_ok($pid); 4618 4619 if ($ex) { 4620 test_append_logfile($log_file, $ex); 4621 unlink($log_file); 4622 4623 die($ex); 4624 } 4625 4626 unlink($log_file); 4627} 4628 4629sub sql_passwd_sha1_encode_salt_hash_encode_password { 4630 my $self = shift; 4631 my $tmpdir = $self->{tmpdir}; 4632 4633 my $config_file = "$tmpdir/sqlpasswd.conf"; 4634 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 4635 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 4636 4637 my $log_file = test_get_logfile(); 4638 4639 my $user = 'proftpd'; 4640 4641 # See http://forums.proftpd.org/smf/index.php/topic,3733.0.html for more 4642 # details 4643 4644 my $passwd = 'test1234'; 4645 my $salt = '48d84dc8792accc3770117c804f1b5ce'; 4646 4647 # I used: 4648 # 4649 # Digest::SHA1::sha1_hex($salt . Digest::SHA1::sha1_hex($passwd)) 4650 # 4651 # to generate this password. 4652 my $db_passwd = '03cb508a6c32e33a21695ed139e6f7cb4e479a76'; 4653 4654 my $group = 'ftpd'; 4655 my $home_dir = File::Spec->rel2abs($tmpdir); 4656 my $uid = 500; 4657 my $gid = 500; 4658 4659 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4660 4661 # Build up sqlite3 command to create users, groups tables and populate them 4662 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4663 4664 if (open(my $fh, "> $db_script")) { 4665 print $fh <<EOS; 4666CREATE TABLE users ( 4667 userid TEXT, 4668 passwd TEXT, 4669 uid INTEGER, 4670 gid INTEGER, 4671 homedir TEXT, 4672 shell TEXT 4673); 4674INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$db_passwd', $uid, $gid, '$home_dir', '/bin/bash'); 4675 4676CREATE TABLE groups ( 4677 groupname TEXT, 4678 gid INTEGER, 4679 members TEXT 4680); 4681INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 4682 4683CREATE TABLE user_salts ( 4684 userid TEXT, 4685 salt TEXT 4686); 4687INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt'); 4688 4689EOS 4690 4691 unless (close($fh)) { 4692 die("Can't write $db_script: $!"); 4693 } 4694 4695 } else { 4696 die("Can't open $db_script: $!"); 4697 } 4698 4699 my $cmd = "sqlite3 $db_file < $db_script"; 4700 4701 if ($ENV{TEST_VERBOSE}) { 4702 print STDERR "Executing sqlite3: $cmd\n"; 4703 } 4704 4705 my @output = `$cmd`; 4706 if (scalar(@output) && 4707 $ENV{TEST_VERBOSE}) { 4708 print STDERR "Output: ", join('', @output), "\n"; 4709 } 4710 4711 my $config = { 4712 PidFile => $pid_file, 4713 ScoreboardFile => $scoreboard_file, 4714 SystemLog => $log_file, 4715 4716 IfModules => { 4717 'mod_delay.c' => { 4718 DelayEngine => 'off', 4719 }, 4720 4721 'mod_sql.c' => { 4722 SQLAuthTypes => 'sha1', 4723 SQLBackend => 'sqlite3', 4724 SQLConnectInfo => $db_file, 4725 SQLLogFile => $log_file, 4726 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 4727 SQLMinID => '100', 4728 }, 4729 4730 'mod_sql_passwd.c' => { 4731 SQLPasswordEngine => 'on', 4732 SQLPasswordEncoding => 'hex', 4733 SQLPasswordUserSalt => 'sql:/get-user-salt Prepend', 4734 SQLPasswordOptions => 'HashEncodePassword', 4735 }, 4736 }, 4737 }; 4738 4739 my ($port, $config_user, $config_group) = config_write($config_file, $config); 4740 4741 # Open pipes, for use between the parent and child processes. Specifically, 4742 # the child will indicate when it's done with its test by writing a message 4743 # to the parent. 4744 my ($rfh, $wfh); 4745 unless (pipe($rfh, $wfh)) { 4746 die("Can't open pipe: $!"); 4747 } 4748 4749 my $ex; 4750 4751 # Fork child 4752 $self->handle_sigchld(); 4753 defined(my $pid = fork()) or die("Can't fork: $!"); 4754 if ($pid) { 4755 eval { 4756 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4757 $client->login($user, $passwd); 4758 4759 my $resp_msgs = $client->response_msgs(); 4760 my $nmsgs = scalar(@$resp_msgs); 4761 4762 my $expected; 4763 4764 $expected = 1; 4765 $self->assert($expected == $nmsgs, 4766 test_msg("Expected $expected, got $nmsgs")); 4767 4768 $expected = "User proftpd logged in"; 4769 $self->assert($expected eq $resp_msgs->[0], 4770 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 4771 4772 }; 4773 4774 if ($@) { 4775 $ex = $@; 4776 } 4777 4778 $wfh->print("done\n"); 4779 $wfh->flush(); 4780 4781 } else { 4782 eval { server_wait($config_file, $rfh) }; 4783 if ($@) { 4784 warn($@); 4785 exit 1; 4786 } 4787 4788 exit 0; 4789 } 4790 4791 # Stop server 4792 server_stop($pid_file); 4793 4794 $self->assert_child_ok($pid); 4795 4796 if ($ex) { 4797 test_append_logfile($log_file, $ex); 4798 unlink($log_file); 4799 4800 die($ex); 4801 } 4802 4803 unlink($log_file); 4804} 4805 4806sub sql_passwd_pbkdf2_sha1_base64 { 4807 my $self = shift; 4808 my $tmpdir = $self->{tmpdir}; 4809 4810 my $config_file = "$tmpdir/sqlpasswd.conf"; 4811 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 4812 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 4813 4814 my $log_file = test_get_logfile(); 4815 4816 my $user = 'proftpd'; 4817 my $group = 'ftpd'; 4818 4819 # RFC 6070: PKCS#5 PBKDF2 Test Vectors 4820 # 4821 # Input: 4822 # P = "password" (8 octets) 4823 # S = "salt" (4 octets) 4824 # c = 4096 4825 # dkLen = 20 4826 # 4827 # Output: 4828 # DK = 4b 00 79 01 b7 65 48 9a 4829 # be ad 49 d9 26 f7 21 d0 4830 # 65 a4 29 c1 (20 octets) 4831 # 4832 # Base64: 4833 # DK = SwB5AbdlSJq+rUnZJvch0GWkKcE= 4834 # 4835 my $passwd = "SwB5AbdlSJq+rUnZJvch0GWkKcE="; 4836 4837 my $home_dir = File::Spec->rel2abs($tmpdir); 4838 my $uid = 500; 4839 my $gid = 500; 4840 4841 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4842 4843 # Build up sqlite3 command to create users, groups tables and populate them 4844 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4845 4846 if (open(my $fh, "> $db_script")) { 4847 print $fh <<EOS; 4848CREATE TABLE users ( 4849 userid TEXT, 4850 passwd TEXT, 4851 uid INTEGER, 4852 gid INTEGER, 4853 homedir TEXT, 4854 shell TEXT 4855); 4856INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 4857 4858CREATE TABLE groups ( 4859 groupname TEXT, 4860 gid INTEGER, 4861 members TEXT 4862); 4863INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 4864EOS 4865 4866 unless (close($fh)) { 4867 die("Can't write $db_script: $!"); 4868 } 4869 4870 } else { 4871 die("Can't open $db_script: $!"); 4872 } 4873 4874 my $cmd = "sqlite3 $db_file < $db_script"; 4875 4876 if ($ENV{TEST_VERBOSE}) { 4877 print STDERR "Executing sqlite3: $cmd\n"; 4878 } 4879 4880 my @output = `$cmd`; 4881 if (scalar(@output) && 4882 $ENV{TEST_VERBOSE}) { 4883 print STDERR "Output: ", join('', @output), "\n"; 4884 } 4885 4886 my $salt = 'salt'; 4887 4888 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 4889 if (open(my $fh, "> $salt_file")) { 4890 binmode($fh); 4891 print $fh $salt; 4892 4893 unless (close($fh)) { 4894 die("Can't write $salt_file: $!"); 4895 } 4896 4897 } else { 4898 die("Can't open $salt_file: $!"); 4899 } 4900 4901 my $config = { 4902 PidFile => $pid_file, 4903 ScoreboardFile => $scoreboard_file, 4904 SystemLog => $log_file, 4905 4906 IfModules => { 4907 'mod_delay.c' => { 4908 DelayEngine => 'off', 4909 }, 4910 4911 'mod_sql.c' => { 4912 SQLAuthTypes => 'pbkdf2', 4913 SQLBackend => 'sqlite3', 4914 SQLConnectInfo => $db_file, 4915 SQLLogFile => $log_file, 4916 }, 4917 4918 'mod_sql_passwd.c' => { 4919 SQLPasswordEngine => 'on', 4920 SQLPasswordEncoding => 'base64', 4921 SQLPasswordPBKDF2 => 'sha1 4096 20', 4922 SQLPasswordSaltFile => $salt_file, 4923 }, 4924 }, 4925 }; 4926 4927 my ($port, $config_user, $config_group) = config_write($config_file, $config); 4928 4929 # Open pipes, for use between the parent and child processes. Specifically, 4930 # the child will indicate when it's done with its test by writing a message 4931 # to the parent. 4932 my ($rfh, $wfh); 4933 unless (pipe($rfh, $wfh)) { 4934 die("Can't open pipe: $!"); 4935 } 4936 4937 my $ex; 4938 4939 # Fork child 4940 $self->handle_sigchld(); 4941 defined(my $pid = fork()) or die("Can't fork: $!"); 4942 if ($pid) { 4943 eval { 4944 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4945 $client->login($user, "password"); 4946 4947 my $resp_msgs = $client->response_msgs(); 4948 my $nmsgs = scalar(@$resp_msgs); 4949 4950 my $expected; 4951 4952 $expected = 1; 4953 $self->assert($expected == $nmsgs, 4954 test_msg("Expected $expected, got $nmsgs")); 4955 4956 $expected = "User proftpd logged in"; 4957 $self->assert($expected eq $resp_msgs->[0], 4958 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 4959 4960 }; 4961 4962 if ($@) { 4963 $ex = $@; 4964 } 4965 4966 $wfh->print("done\n"); 4967 $wfh->flush(); 4968 4969 } else { 4970 eval { server_wait($config_file, $rfh) }; 4971 if ($@) { 4972 warn($@); 4973 exit 1; 4974 } 4975 4976 exit 0; 4977 } 4978 4979 # Stop server 4980 server_stop($pid_file); 4981 4982 $self->assert_child_ok($pid); 4983 4984 if ($ex) { 4985 test_append_logfile($log_file, $ex); 4986 unlink($log_file); 4987 4988 die($ex); 4989 } 4990 4991 unlink($log_file); 4992} 4993 4994sub sql_passwd_pbkdf2_sha1_hex_lc { 4995 my $self = shift; 4996 my $tmpdir = $self->{tmpdir}; 4997 4998 my $config_file = "$tmpdir/sqlpasswd.conf"; 4999 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 5000 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 5001 5002 my $log_file = test_get_logfile(); 5003 5004 my $user = 'proftpd'; 5005 my $group = 'ftpd'; 5006 5007 # RFC 6070: PKCS#5 PBKDF2 Test Vectors 5008 # 5009 # Input: 5010 # P = "password" (8 octets) 5011 # S = "salt" (4 octets) 5012 # c = 4096 5013 # dkLen = 20 5014 # 5015 # Output: 5016 # DK = 4b 00 79 01 b7 65 48 9a 5017 # be ad 49 d9 26 f7 21 d0 5018 # 65 a4 29 c1 (20 octets) 5019 my $passwd = "4b007901b765489abead49d926f721d065a429c1"; 5020 5021 my $home_dir = File::Spec->rel2abs($tmpdir); 5022 my $uid = 500; 5023 my $gid = 500; 5024 5025 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5026 5027 # Build up sqlite3 command to create users, groups tables and populate them 5028 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5029 5030 if (open(my $fh, "> $db_script")) { 5031 print $fh <<EOS; 5032CREATE TABLE users ( 5033 userid TEXT, 5034 passwd TEXT, 5035 uid INTEGER, 5036 gid INTEGER, 5037 homedir TEXT, 5038 shell TEXT 5039); 5040INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 5041 5042CREATE TABLE groups ( 5043 groupname TEXT, 5044 gid INTEGER, 5045 members TEXT 5046); 5047INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 5048EOS 5049 5050 unless (close($fh)) { 5051 die("Can't write $db_script: $!"); 5052 } 5053 5054 } else { 5055 die("Can't open $db_script: $!"); 5056 } 5057 5058 my $cmd = "sqlite3 $db_file < $db_script"; 5059 5060 if ($ENV{TEST_VERBOSE}) { 5061 print STDERR "Executing sqlite3: $cmd\n"; 5062 } 5063 5064 my @output = `$cmd`; 5065 if (scalar(@output) && 5066 $ENV{TEST_VERBOSE}) { 5067 print STDERR "Output: ", join('', @output), "\n"; 5068 } 5069 5070 my $salt = 'salt'; 5071 5072 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 5073 if (open(my $fh, "> $salt_file")) { 5074 binmode($fh); 5075 print $fh $salt; 5076 5077 unless (close($fh)) { 5078 die("Can't write $salt_file: $!"); 5079 } 5080 5081 } else { 5082 die("Can't open $salt_file: $!"); 5083 } 5084 5085 my $config = { 5086 PidFile => $pid_file, 5087 ScoreboardFile => $scoreboard_file, 5088 SystemLog => $log_file, 5089 5090 IfModules => { 5091 'mod_delay.c' => { 5092 DelayEngine => 'off', 5093 }, 5094 5095 'mod_sql.c' => { 5096 SQLAuthTypes => 'pbkdf2', 5097 SQLBackend => 'sqlite3', 5098 SQLConnectInfo => $db_file, 5099 SQLLogFile => $log_file, 5100 }, 5101 5102 'mod_sql_passwd.c' => { 5103 SQLPasswordEngine => 'on', 5104 SQLPasswordEncoding => 'hex', 5105 SQLPasswordPBKDF2 => 'sha1 4096 20', 5106 SQLPasswordSaltFile => $salt_file, 5107 }, 5108 }, 5109 }; 5110 5111 my ($port, $config_user, $config_group) = config_write($config_file, $config); 5112 5113 # Open pipes, for use between the parent and child processes. Specifically, 5114 # the child will indicate when it's done with its test by writing a message 5115 # to the parent. 5116 my ($rfh, $wfh); 5117 unless (pipe($rfh, $wfh)) { 5118 die("Can't open pipe: $!"); 5119 } 5120 5121 my $ex; 5122 5123 # Fork child 5124 $self->handle_sigchld(); 5125 defined(my $pid = fork()) or die("Can't fork: $!"); 5126 if ($pid) { 5127 eval { 5128 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 5129 $client->login($user, "password"); 5130 5131 my $resp_msgs = $client->response_msgs(); 5132 my $nmsgs = scalar(@$resp_msgs); 5133 5134 my $expected; 5135 5136 $expected = 1; 5137 $self->assert($expected == $nmsgs, 5138 test_msg("Expected $expected, got $nmsgs")); 5139 5140 $expected = "User proftpd logged in"; 5141 $self->assert($expected eq $resp_msgs->[0], 5142 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 5143 5144 }; 5145 5146 if ($@) { 5147 $ex = $@; 5148 } 5149 5150 $wfh->print("done\n"); 5151 $wfh->flush(); 5152 5153 } else { 5154 eval { server_wait($config_file, $rfh) }; 5155 if ($@) { 5156 warn($@); 5157 exit 1; 5158 } 5159 5160 exit 0; 5161 } 5162 5163 # Stop server 5164 server_stop($pid_file); 5165 5166 $self->assert_child_ok($pid); 5167 5168 if ($ex) { 5169 test_append_logfile($log_file, $ex); 5170 unlink($log_file); 5171 5172 die($ex); 5173 } 5174 5175 unlink($log_file); 5176} 5177 5178sub sql_passwd_pbkdf2_sha1_hex_uc { 5179 my $self = shift; 5180 my $tmpdir = $self->{tmpdir}; 5181 5182 my $config_file = "$tmpdir/sqlpasswd.conf"; 5183 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 5184 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 5185 5186 my $log_file = test_get_logfile(); 5187 5188 my $user = 'proftpd'; 5189 my $group = 'ftpd'; 5190 5191 # RFC 6070: PKCS#5 PBKDF2 Test Vectors 5192 # 5193 # Input: 5194 # P = "password" (8 octets) 5195 # S = "salt" (4 octets) 5196 # c = 4096 5197 # dkLen = 20 5198 # 5199 # Output: 5200 # DK = 4b 00 79 01 b7 65 48 9a 5201 # be ad 49 d9 26 f7 21 d0 5202 # 65 a4 29 c1 (20 octets) 5203 my $passwd = "4B007901B765489ABEAD49D926F721D065A429C1"; 5204 5205 my $home_dir = File::Spec->rel2abs($tmpdir); 5206 my $uid = 500; 5207 my $gid = 500; 5208 5209 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5210 5211 # Build up sqlite3 command to create users, groups tables and populate them 5212 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5213 5214 if (open(my $fh, "> $db_script")) { 5215 print $fh <<EOS; 5216CREATE TABLE users ( 5217 userid TEXT, 5218 passwd TEXT, 5219 uid INTEGER, 5220 gid INTEGER, 5221 homedir TEXT, 5222 shell TEXT 5223); 5224INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 5225 5226CREATE TABLE groups ( 5227 groupname TEXT, 5228 gid INTEGER, 5229 members TEXT 5230); 5231INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 5232EOS 5233 5234 unless (close($fh)) { 5235 die("Can't write $db_script: $!"); 5236 } 5237 5238 } else { 5239 die("Can't open $db_script: $!"); 5240 } 5241 5242 my $cmd = "sqlite3 $db_file < $db_script"; 5243 5244 if ($ENV{TEST_VERBOSE}) { 5245 print STDERR "Executing sqlite3: $cmd\n"; 5246 } 5247 5248 my @output = `$cmd`; 5249 if (scalar(@output) && 5250 $ENV{TEST_VERBOSE}) { 5251 print STDERR "Output: ", join('', @output), "\n"; 5252 } 5253 5254 my $salt = 'salt'; 5255 5256 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 5257 if (open(my $fh, "> $salt_file")) { 5258 binmode($fh); 5259 print $fh $salt; 5260 5261 unless (close($fh)) { 5262 die("Can't write $salt_file: $!"); 5263 } 5264 5265 } else { 5266 die("Can't open $salt_file: $!"); 5267 } 5268 5269 my $config = { 5270 PidFile => $pid_file, 5271 ScoreboardFile => $scoreboard_file, 5272 SystemLog => $log_file, 5273 5274 IfModules => { 5275 'mod_delay.c' => { 5276 DelayEngine => 'off', 5277 }, 5278 5279 'mod_sql.c' => { 5280 SQLAuthTypes => 'pbkdf2', 5281 SQLBackend => 'sqlite3', 5282 SQLConnectInfo => $db_file, 5283 SQLLogFile => $log_file, 5284 }, 5285 5286 'mod_sql_passwd.c' => { 5287 SQLPasswordEngine => 'on', 5288 SQLPasswordEncoding => 'HEX', 5289 SQLPasswordPBKDF2 => 'sha1 4096 20', 5290 SQLPasswordSaltFile => $salt_file, 5291 }, 5292 }, 5293 }; 5294 5295 my ($port, $config_user, $config_group) = config_write($config_file, $config); 5296 5297 # Open pipes, for use between the parent and child processes. Specifically, 5298 # the child will indicate when it's done with its test by writing a message 5299 # to the parent. 5300 my ($rfh, $wfh); 5301 unless (pipe($rfh, $wfh)) { 5302 die("Can't open pipe: $!"); 5303 } 5304 5305 my $ex; 5306 5307 # Fork child 5308 $self->handle_sigchld(); 5309 defined(my $pid = fork()) or die("Can't fork: $!"); 5310 if ($pid) { 5311 eval { 5312 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 5313 $client->login($user, "password"); 5314 5315 my $resp_msgs = $client->response_msgs(); 5316 my $nmsgs = scalar(@$resp_msgs); 5317 5318 my $expected; 5319 5320 $expected = 1; 5321 $self->assert($expected == $nmsgs, 5322 test_msg("Expected $expected, got $nmsgs")); 5323 5324 $expected = "User proftpd logged in"; 5325 $self->assert($expected eq $resp_msgs->[0], 5326 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 5327 5328 }; 5329 5330 if ($@) { 5331 $ex = $@; 5332 } 5333 5334 $wfh->print("done\n"); 5335 $wfh->flush(); 5336 5337 } else { 5338 eval { server_wait($config_file, $rfh) }; 5339 if ($@) { 5340 warn($@); 5341 exit 1; 5342 } 5343 5344 exit 0; 5345 } 5346 5347 # Stop server 5348 server_stop($pid_file); 5349 5350 $self->assert_child_ok($pid); 5351 5352 if ($ex) { 5353 test_append_logfile($log_file, $ex); 5354 unlink($log_file); 5355 5356 die($ex); 5357 } 5358 5359 unlink($log_file); 5360} 5361 5362sub sql_passwd_pbkdf2_sha512_hex_lc { 5363 my $self = shift; 5364 my $tmpdir = $self->{tmpdir}; 5365 5366 my $config_file = "$tmpdir/sqlpasswd.conf"; 5367 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 5368 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 5369 5370 my $log_file = test_get_logfile(); 5371 5372 my $user = 'proftpd'; 5373 my $group = 'ftpd'; 5374 5375 # See: 5376 # http://stackoverflow.com/questions/15593184/pbkdf2-hmac-sha-512-test-vectors 5377 my $passwd = '867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252c02d470a285a0501bad999bfe943c08f050235d7d68b1da55e63f73b60a57fce'; 5378 5379 my $home_dir = File::Spec->rel2abs($tmpdir); 5380 my $uid = 500; 5381 my $gid = 500; 5382 5383 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5384 5385 # Build up sqlite3 command to create users, groups tables and populate them 5386 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5387 5388 if (open(my $fh, "> $db_script")) { 5389 print $fh <<EOS; 5390CREATE TABLE users ( 5391 userid TEXT, 5392 passwd TEXT, 5393 uid INTEGER, 5394 gid INTEGER, 5395 homedir TEXT, 5396 shell TEXT 5397); 5398INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 5399 5400CREATE TABLE groups ( 5401 groupname TEXT, 5402 gid INTEGER, 5403 members TEXT 5404); 5405INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 5406EOS 5407 5408 unless (close($fh)) { 5409 die("Can't write $db_script: $!"); 5410 } 5411 5412 } else { 5413 die("Can't open $db_script: $!"); 5414 } 5415 5416 my $cmd = "sqlite3 $db_file < $db_script"; 5417 5418 if ($ENV{TEST_VERBOSE}) { 5419 print STDERR "Executing sqlite3: $cmd\n"; 5420 } 5421 5422 my @output = `$cmd`; 5423 if (scalar(@output) && 5424 $ENV{TEST_VERBOSE}) { 5425 print STDERR "Output: ", join('', @output), "\n"; 5426 } 5427 5428 my $salt = 'salt'; 5429 5430 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 5431 if (open(my $fh, "> $salt_file")) { 5432 binmode($fh); 5433 print $fh $salt; 5434 5435 unless (close($fh)) { 5436 die("Can't write $salt_file: $!"); 5437 } 5438 5439 } else { 5440 die("Can't open $salt_file: $!"); 5441 } 5442 5443 my $config = { 5444 PidFile => $pid_file, 5445 ScoreboardFile => $scoreboard_file, 5446 SystemLog => $log_file, 5447 5448 IfModules => { 5449 'mod_delay.c' => { 5450 DelayEngine => 'off', 5451 }, 5452 5453 'mod_sql.c' => { 5454 SQLAuthTypes => 'pbkdf2', 5455 SQLBackend => 'sqlite3', 5456 SQLConnectInfo => $db_file, 5457 SQLLogFile => $log_file, 5458 }, 5459 5460 'mod_sql_passwd.c' => { 5461 SQLPasswordEngine => 'on', 5462 SQLPasswordEncoding => 'hex', 5463 SQLPasswordPBKDF2 => 'sha512 1 64', 5464 SQLPasswordSaltFile => $salt_file, 5465 }, 5466 }, 5467 }; 5468 5469 my ($port, $config_user, $config_group) = config_write($config_file, $config); 5470 5471 # Open pipes, for use between the parent and child processes. Specifically, 5472 # the child will indicate when it's done with its test by writing a message 5473 # to the parent. 5474 my ($rfh, $wfh); 5475 unless (pipe($rfh, $wfh)) { 5476 die("Can't open pipe: $!"); 5477 } 5478 5479 my $ex; 5480 5481 # Fork child 5482 $self->handle_sigchld(); 5483 defined(my $pid = fork()) or die("Can't fork: $!"); 5484 if ($pid) { 5485 eval { 5486 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 5487 $client->login($user, "password"); 5488 5489 my $resp_msgs = $client->response_msgs(); 5490 my $nmsgs = scalar(@$resp_msgs); 5491 5492 my $expected; 5493 5494 $expected = 1; 5495 $self->assert($expected == $nmsgs, 5496 test_msg("Expected $expected, got $nmsgs")); 5497 5498 $expected = "User proftpd logged in"; 5499 $self->assert($expected eq $resp_msgs->[0], 5500 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 5501 5502 }; 5503 5504 if ($@) { 5505 $ex = $@; 5506 } 5507 5508 $wfh->print("done\n"); 5509 $wfh->flush(); 5510 5511 } else { 5512 eval { server_wait($config_file, $rfh) }; 5513 if ($@) { 5514 warn($@); 5515 exit 1; 5516 } 5517 5518 exit 0; 5519 } 5520 5521 # Stop server 5522 server_stop($pid_file); 5523 5524 $self->assert_child_ok($pid); 5525 5526 if ($ex) { 5527 test_append_logfile($log_file, $ex); 5528 unlink($log_file); 5529 5530 die($ex); 5531 } 5532 5533 unlink($log_file); 5534} 5535 5536sub sql_passwd_pbkdf2_per_user_bug4052 { 5537 my $self = shift; 5538 my $tmpdir = $self->{tmpdir}; 5539 5540 my $config_file = "$tmpdir/sqlpasswd.conf"; 5541 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 5542 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 5543 5544 my $log_file = test_get_logfile(); 5545 5546 my $user = 'proftpd'; 5547 my $group = 'ftpd'; 5548 5549 # RFC 6070: PKCS#5 PBKDF2 Test Vectors 5550 # 5551 # Input: 5552 # P = "password" (8 octets) 5553 # S = "salt" (4 octets) 5554 # c = 4096 5555 # dkLen = 20 5556 # 5557 # Output: 5558 # DK = 4b 00 79 01 b7 65 48 9a 5559 # be ad 49 d9 26 f7 21 d0 5560 # 65 a4 29 c1 (20 octets) 5561 # 5562 # Base64: 5563 # DK = SwB5AbdlSJq+rUnZJvch0GWkKcE= 5564 # 5565 my $passwd = "SwB5AbdlSJq+rUnZJvch0GWkKcE="; 5566 5567 my $home_dir = File::Spec->rel2abs($tmpdir); 5568 my $uid = 500; 5569 my $gid = 500; 5570 5571 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5572 5573 # Build up sqlite3 command to create users, groups tables and populate them 5574 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5575 5576 if (open(my $fh, "> $db_script")) { 5577 print $fh <<EOS; 5578CREATE TABLE users ( 5579 userid TEXT, 5580 passwd TEXT, 5581 uid INTEGER, 5582 gid INTEGER, 5583 homedir TEXT, 5584 shell TEXT 5585); 5586INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 5587 5588CREATE TABLE groups ( 5589 groupname TEXT, 5590 gid INTEGER, 5591 members TEXT 5592); 5593INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 5594 5595CREATE TABLE user_pbkdf2 ( 5596 userid TEXT, 5597 algo TEXT, 5598 rounds INTEGER, 5599 len INTEGER 5600); 5601INSERT INTO user_pbkdf2 (userid, algo, rounds, len) VALUES ('$user', 'sha1', 4096, 20); 5602EOS 5603 5604 unless (close($fh)) { 5605 die("Can't write $db_script: $!"); 5606 } 5607 5608 } else { 5609 die("Can't open $db_script: $!"); 5610 } 5611 5612 my $cmd = "sqlite3 $db_file < $db_script"; 5613 5614 if ($ENV{TEST_VERBOSE}) { 5615 print STDERR "Executing sqlite3: $cmd\n"; 5616 } 5617 5618 my @output = `$cmd`; 5619 if (scalar(@output) && 5620 $ENV{TEST_VERBOSE}) { 5621 print STDERR "Output: ", join('', @output), "\n"; 5622 } 5623 5624 my $salt = 'salt'; 5625 5626 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 5627 if (open(my $fh, "> $salt_file")) { 5628 binmode($fh); 5629 print $fh $salt; 5630 5631 unless (close($fh)) { 5632 die("Can't write $salt_file: $!"); 5633 } 5634 5635 } else { 5636 die("Can't open $salt_file: $!"); 5637 } 5638 5639 my $config = { 5640 PidFile => $pid_file, 5641 ScoreboardFile => $scoreboard_file, 5642 SystemLog => $log_file, 5643 5644 IfModules => { 5645 'mod_delay.c' => { 5646 DelayEngine => 'off', 5647 }, 5648 5649 'mod_sql.c' => { 5650 SQLAuthTypes => 'pbkdf2', 5651 SQLBackend => 'sqlite3', 5652 SQLConnectInfo => $db_file, 5653 SQLLogFile => $log_file, 5654 SQLNamedQuery => 'get-user-pbkdf2 SELECT "algo, rounds, len FROM user_pbkdf2 WHERE userid = \'%{0}\'"', 5655 }, 5656 5657 'mod_sql_passwd.c' => { 5658 SQLPasswordEngine => 'on', 5659 SQLPasswordEncoding => 'base64', 5660 SQLPasswordPBKDF2 => 'sql:/get-user-pbkdf2', 5661 SQLPasswordSaltFile => $salt_file, 5662 }, 5663 }, 5664 }; 5665 5666 my ($port, $config_user, $config_group) = config_write($config_file, $config); 5667 5668 # Open pipes, for use between the parent and child processes. Specifically, 5669 # the child will indicate when it's done with its test by writing a message 5670 # to the parent. 5671 my ($rfh, $wfh); 5672 unless (pipe($rfh, $wfh)) { 5673 die("Can't open pipe: $!"); 5674 } 5675 5676 my $ex; 5677 5678 # Fork child 5679 $self->handle_sigchld(); 5680 defined(my $pid = fork()) or die("Can't fork: $!"); 5681 if ($pid) { 5682 eval { 5683 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 5684 $client->login($user, "password"); 5685 5686 my $resp_msgs = $client->response_msgs(); 5687 my $nmsgs = scalar(@$resp_msgs); 5688 5689 my $expected; 5690 5691 $expected = 1; 5692 $self->assert($expected == $nmsgs, 5693 test_msg("Expected $expected, got $nmsgs")); 5694 5695 $expected = "User proftpd logged in"; 5696 $self->assert($expected eq $resp_msgs->[0], 5697 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 5698 }; 5699 5700 if ($@) { 5701 $ex = $@; 5702 } 5703 5704 $wfh->print("done\n"); 5705 $wfh->flush(); 5706 5707 } else { 5708 eval { server_wait($config_file, $rfh) }; 5709 if ($@) { 5710 warn($@); 5711 exit 1; 5712 } 5713 5714 exit 0; 5715 } 5716 5717 # Stop server 5718 server_stop($pid_file); 5719 5720 $self->assert_child_ok($pid); 5721 5722 if ($ex) { 5723 test_append_logfile($log_file, $ex); 5724 unlink($log_file); 5725 5726 die($ex); 5727 } 5728 5729 unlink($log_file); 5730} 5731 5732sub sql_passwd_salt_file_with_user_salt { 5733 my $self = shift; 5734 my $tmpdir = $self->{tmpdir}; 5735 5736 my $config_file = "$tmpdir/sqlpasswd.conf"; 5737 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 5738 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 5739 5740 my $log_file = test_get_logfile(); 5741 5742 my $global_salt = '8Hkqr7bnPaZ52j81VvuoWdOEuq6EeXwpiIw5Q679xzvEqwe128'; 5743 my $user_salt = 'MyS00p3r$3kr3t$@lt'; 5744 5745 my $user = 'proftpd'; 5746 my $group = 'ftpd'; 5747 5748 # I used: 5749 # 5750 # Digest::SHA1::sha1_hex($user_salt . (lc("password")) . $global_salt); 5751 # 5752 # to generate this password. 5753 my $passwd = 'b939d5c8e2857d9e8d27b87939a27fb986cd41ef'; 5754 5755 my $home_dir = File::Spec->rel2abs($tmpdir); 5756 my $uid = 500; 5757 my $gid = 500; 5758 5759 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5760 5761 # Build up sqlite3 command to create users, groups tables and populate them 5762 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5763 5764 if (open(my $fh, "> $db_script")) { 5765 print $fh <<EOS; 5766CREATE TABLE users ( 5767 userid TEXT, 5768 passwd TEXT, 5769 uid INTEGER, 5770 gid INTEGER, 5771 homedir TEXT, 5772 shell TEXT 5773); 5774INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 5775 5776CREATE TABLE groups ( 5777 groupname TEXT, 5778 gid INTEGER, 5779 members TEXT 5780); 5781INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 5782 5783CREATE TABLE user_salts ( 5784 userid TEXT, 5785 salt TEXT 5786); 5787INSERT INTO user_salts (userid, salt) VALUES ('$user', '$user_salt'); 5788EOS 5789 5790 unless (close($fh)) { 5791 die("Can't write $db_script: $!"); 5792 } 5793 5794 } else { 5795 die("Can't open $db_script: $!"); 5796 } 5797 5798 my $cmd = "sqlite3 $db_file < $db_script"; 5799 5800 if ($ENV{TEST_VERBOSE}) { 5801 print STDERR "Executing sqlite3: $cmd\n"; 5802 } 5803 5804 my @output = `$cmd`; 5805 if (scalar(@output) && 5806 $ENV{TEST_VERBOSE}) { 5807 print STDERR "Output: ", join('', @output), "\n"; 5808 } 5809 5810 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 5811 if (open(my $fh, "> $salt_file")) { 5812 binmode($fh); 5813 print $fh "$global_salt\n"; 5814 5815 unless (close($fh)) { 5816 die("Can't write $salt_file: $!"); 5817 } 5818 5819 } else { 5820 die("Can't open $salt_file: $!"); 5821 } 5822 5823 my $config = { 5824 PidFile => $pid_file, 5825 ScoreboardFile => $scoreboard_file, 5826 SystemLog => $log_file, 5827 TraceLog => $log_file, 5828 Trace => 'sql.passwd:20', 5829 5830 IfModules => { 5831 'mod_delay.c' => { 5832 DelayEngine => 'off', 5833 }, 5834 5835 'mod_sql.c' => { 5836 SQLAuthTypes => 'sha1', 5837 SQLBackend => 'sqlite3', 5838 SQLConnectInfo => $db_file, 5839 SQLLogFile => $log_file, 5840 SQLMinID => '100', 5841 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 5842 }, 5843 5844 'mod_sql_passwd.c' => { 5845 SQLPasswordEngine => 'on', 5846 SQLPasswordEncoding => 'hex', 5847 SQLPasswordSaltFile => "$salt_file Append", 5848 SQLPasswordUserSalt => "sql:/get-user-salt Prepend", 5849 }, 5850 }, 5851 }; 5852 5853 my ($port, $config_user, $config_group) = config_write($config_file, $config); 5854 5855 # Open pipes, for use between the parent and child processes. Specifically, 5856 # the child will indicate when it's done with its test by writing a message 5857 # to the parent. 5858 my ($rfh, $wfh); 5859 unless (pipe($rfh, $wfh)) { 5860 die("Can't open pipe: $!"); 5861 } 5862 5863 my $ex; 5864 5865 # Fork child 5866 $self->handle_sigchld(); 5867 defined(my $pid = fork()) or die("Can't fork: $!"); 5868 if ($pid) { 5869 eval { 5870 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 5871 $client->login($user, "password"); 5872 5873 my $resp_msgs = $client->response_msgs(); 5874 my $nmsgs = scalar(@$resp_msgs); 5875 5876 my $expected; 5877 5878 $expected = 1; 5879 $self->assert($expected == $nmsgs, 5880 test_msg("Expected $expected, got $nmsgs")); 5881 5882 $expected = "User proftpd logged in"; 5883 $self->assert($expected eq $resp_msgs->[0], 5884 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 5885 5886 }; 5887 5888 if ($@) { 5889 $ex = $@; 5890 } 5891 5892 $wfh->print("done\n"); 5893 $wfh->flush(); 5894 5895 } else { 5896 eval { server_wait($config_file, $rfh) }; 5897 if ($@) { 5898 warn($@); 5899 exit 1; 5900 } 5901 5902 exit 0; 5903 } 5904 5905 # Stop server 5906 server_stop($pid_file); 5907 5908 $self->assert_child_ok($pid); 5909 5910 if ($ex) { 5911 test_append_logfile($log_file, $ex); 5912 unlink($log_file); 5913 5914 die($ex); 5915 } 5916 5917 unlink($log_file); 5918} 5919 5920sub sql_passwd_user_salt_sql_base64_bug4138 { 5921 my $self = shift; 5922 my $tmpdir = $self->{tmpdir}; 5923 5924 my $config_file = "$tmpdir/sqlpasswd.conf"; 5925 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 5926 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 5927 5928 my $log_file = test_get_logfile(); 5929 5930 my $user = 'proftpd'; 5931 5932 # This base64-encoded salt data has embedded NULs 5933 my $salt = 'p8CCsyWyyDX/infYBQBolKobDsQlWca9LLgteqD+rSo='; 5934 5935 # I used: 5936 # 5937 # Digest::SHA1::sha1_hex((lc("password")) . $decoded_salt); 5938 # 5939 # to generate this password. 5940 my $passwd = '39ff37588e1a56b243b00cb6479a716ef50fc980'; 5941 5942 my $home_dir = File::Spec->rel2abs($tmpdir); 5943 my $uid = 500; 5944 my $gid = 500; 5945 5946 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5947 5948 # Build up sqlite3 command to create users, groups tables and populate them 5949 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5950 5951 if (open(my $fh, "> $db_script")) { 5952 print $fh <<EOS; 5953CREATE TABLE users ( 5954 userid TEXT, 5955 passwd TEXT, 5956 uid INTEGER, 5957 gid INTEGER, 5958 homedir TEXT, 5959 shell TEXT 5960); 5961INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 5962 5963CREATE TABLE groups ( 5964 groupname TEXT, 5965 gid INTEGER, 5966 members TEXT 5967); 5968INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', $gid, '$user'); 5969 5970CREATE TABLE user_salts ( 5971 userid TEXT, 5972 salt TEXT 5973); 5974INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt'); 5975EOS 5976 5977 unless (close($fh)) { 5978 die("Can't write $db_script: $!"); 5979 } 5980 5981 } else { 5982 die("Can't open $db_script: $!"); 5983 } 5984 5985 my $cmd = "sqlite3 $db_file < $db_script"; 5986 5987 if ($ENV{TEST_VERBOSE}) { 5988 print STDERR "Executing sqlite3: $cmd\n"; 5989 } 5990 5991 my @output = `$cmd`; 5992 if (scalar(@output) && 5993 $ENV{TEST_VERBOSE}) { 5994 print STDERR "Output: ", join('', @output), "\n"; 5995 } 5996 5997 my $config = { 5998 PidFile => $pid_file, 5999 ScoreboardFile => $scoreboard_file, 6000 SystemLog => $log_file, 6001 6002 IfModules => { 6003 'mod_delay.c' => { 6004 DelayEngine => 'off', 6005 }, 6006 6007 'mod_sql.c' => { 6008 SQLAuthTypes => 'sha1', 6009 SQLBackend => 'sqlite3', 6010 SQLConnectInfo => $db_file, 6011 SQLLogFile => $log_file, 6012 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 6013 }, 6014 6015 'mod_sql_passwd.c' => { 6016 SQLPasswordEngine => 'on', 6017 SQLPasswordEncoding => 'hex', 6018 SQLPasswordSaltEncoding => 'base64', 6019 SQLPasswordUserSalt => 'sql:/get-user-salt', 6020 }, 6021 }, 6022 }; 6023 6024 my ($port, $config_user, $config_group) = config_write($config_file, $config); 6025 6026 # Open pipes, for use between the parent and child processes. Specifically, 6027 # the child will indicate when it's done with its test by writing a message 6028 # to the parent. 6029 my ($rfh, $wfh); 6030 unless (pipe($rfh, $wfh)) { 6031 die("Can't open pipe: $!"); 6032 } 6033 6034 my $ex; 6035 6036 # Fork child 6037 $self->handle_sigchld(); 6038 defined(my $pid = fork()) or die("Can't fork: $!"); 6039 if ($pid) { 6040 eval { 6041 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6042 $client->login($user, "password"); 6043 6044 my $resp_msgs = $client->response_msgs(); 6045 my $nmsgs = scalar(@$resp_msgs); 6046 6047 my $expected; 6048 6049 $expected = 1; 6050 $self->assert($expected == $nmsgs, 6051 test_msg("Expected $expected, got $nmsgs")); 6052 6053 $expected = "User proftpd logged in"; 6054 $self->assert($expected eq $resp_msgs->[0], 6055 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 6056 6057 }; 6058 6059 if ($@) { 6060 $ex = $@; 6061 } 6062 6063 $wfh->print("done\n"); 6064 $wfh->flush(); 6065 6066 } else { 6067 eval { server_wait($config_file, $rfh) }; 6068 if ($@) { 6069 warn($@); 6070 exit 1; 6071 } 6072 6073 exit 0; 6074 } 6075 6076 # Stop server 6077 server_stop($pid_file); 6078 6079 $self->assert_child_ok($pid); 6080 6081 if ($ex) { 6082 test_append_logfile($log_file, $ex); 6083 unlink($log_file); 6084 6085 die($ex); 6086 } 6087 6088 unlink($log_file); 6089} 6090 6091sub sql_passwd_user_salt_sql_hex_lc_bug4138 { 6092 my $self = shift; 6093 my $tmpdir = $self->{tmpdir}; 6094 6095 my $config_file = "$tmpdir/sqlpasswd.conf"; 6096 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 6097 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 6098 6099 my $log_file = test_get_logfile(); 6100 6101 my $user = 'proftpd'; 6102 6103 # This hex-encoded salt data has embedded NULs 6104 my $salt = 'a7c082b325b2c835ff8a77d805006894aa1b0ec42559c6bd2cb82d7aa0fead2a'; 6105 6106 # I used: 6107 # 6108 # Digest::SHA1::sha1_hex((lc("password")) . $decoded_salt); 6109 # 6110 # to generate this password. 6111 my $passwd = '39ff37588e1a56b243b00cb6479a716ef50fc980'; 6112 6113 my $home_dir = File::Spec->rel2abs($tmpdir); 6114 my $uid = 500; 6115 my $gid = 500; 6116 6117 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6118 6119 # Build up sqlite3 command to create users, groups tables and populate them 6120 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6121 6122 if (open(my $fh, "> $db_script")) { 6123 print $fh <<EOS; 6124CREATE TABLE users ( 6125 userid TEXT, 6126 passwd TEXT, 6127 uid INTEGER, 6128 gid INTEGER, 6129 homedir TEXT, 6130 shell TEXT 6131); 6132INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 6133 6134CREATE TABLE groups ( 6135 groupname TEXT, 6136 gid INTEGER, 6137 members TEXT 6138); 6139INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', $gid, '$user'); 6140 6141CREATE TABLE user_salts ( 6142 userid TEXT, 6143 salt TEXT 6144); 6145INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt'); 6146EOS 6147 6148 unless (close($fh)) { 6149 die("Can't write $db_script: $!"); 6150 } 6151 6152 } else { 6153 die("Can't open $db_script: $!"); 6154 } 6155 6156 my $cmd = "sqlite3 $db_file < $db_script"; 6157 6158 if ($ENV{TEST_VERBOSE}) { 6159 print STDERR "Executing sqlite3: $cmd\n"; 6160 } 6161 6162 my @output = `$cmd`; 6163 if (scalar(@output) && 6164 $ENV{TEST_VERBOSE}) { 6165 print STDERR "Output: ", join('', @output), "\n"; 6166 } 6167 6168 my $config = { 6169 PidFile => $pid_file, 6170 ScoreboardFile => $scoreboard_file, 6171 SystemLog => $log_file, 6172 6173 IfModules => { 6174 'mod_delay.c' => { 6175 DelayEngine => 'off', 6176 }, 6177 6178 'mod_sql.c' => { 6179 SQLAuthTypes => 'sha1', 6180 SQLBackend => 'sqlite3', 6181 SQLConnectInfo => $db_file, 6182 SQLLogFile => $log_file, 6183 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 6184 }, 6185 6186 'mod_sql_passwd.c' => { 6187 SQLPasswordEngine => 'on', 6188 SQLPasswordEncoding => 'hex', 6189 SQLPasswordSaltEncoding => 'hex', 6190 SQLPasswordUserSalt => 'sql:/get-user-salt', 6191 }, 6192 }, 6193 }; 6194 6195 my ($port, $config_user, $config_group) = config_write($config_file, $config); 6196 6197 # Open pipes, for use between the parent and child processes. Specifically, 6198 # the child will indicate when it's done with its test by writing a message 6199 # to the parent. 6200 my ($rfh, $wfh); 6201 unless (pipe($rfh, $wfh)) { 6202 die("Can't open pipe: $!"); 6203 } 6204 6205 my $ex; 6206 6207 # Fork child 6208 $self->handle_sigchld(); 6209 defined(my $pid = fork()) or die("Can't fork: $!"); 6210 if ($pid) { 6211 eval { 6212 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6213 $client->login($user, "password"); 6214 6215 my $resp_msgs = $client->response_msgs(); 6216 my $nmsgs = scalar(@$resp_msgs); 6217 6218 my $expected; 6219 6220 $expected = 1; 6221 $self->assert($expected == $nmsgs, 6222 test_msg("Expected $expected, got $nmsgs")); 6223 6224 $expected = "User proftpd logged in"; 6225 $self->assert($expected eq $resp_msgs->[0], 6226 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 6227 6228 }; 6229 6230 if ($@) { 6231 $ex = $@; 6232 } 6233 6234 $wfh->print("done\n"); 6235 $wfh->flush(); 6236 6237 } else { 6238 eval { server_wait($config_file, $rfh) }; 6239 if ($@) { 6240 warn($@); 6241 exit 1; 6242 } 6243 6244 exit 0; 6245 } 6246 6247 # Stop server 6248 server_stop($pid_file); 6249 6250 $self->assert_child_ok($pid); 6251 6252 if ($ex) { 6253 test_append_logfile($log_file, $ex); 6254 unlink($log_file); 6255 6256 die($ex); 6257 } 6258 6259 unlink($log_file); 6260} 6261 6262sub sql_passwd_user_salt_sql_hex_uc_bug4138 { 6263 my $self = shift; 6264 my $tmpdir = $self->{tmpdir}; 6265 6266 my $config_file = "$tmpdir/sqlpasswd.conf"; 6267 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 6268 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 6269 6270 my $log_file = test_get_logfile(); 6271 6272 my $user = 'proftpd'; 6273 6274 # This hex-encoded salt data has embedded NULs 6275 my $salt = 'A7C082B325B2C835FF8A77D805006894AA1B0EC42559C6BD2CB82D7AA0FEAD2A'; 6276 6277 # I used: 6278 # 6279 # Digest::SHA1::sha1_hex((lc("password")) . $decoded_salt); 6280 # 6281 # to generate this password. 6282 my $passwd = '39ff37588e1a56b243b00cb6479a716ef50fc980'; 6283 6284 my $home_dir = File::Spec->rel2abs($tmpdir); 6285 my $uid = 500; 6286 my $gid = 500; 6287 6288 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6289 6290 # Build up sqlite3 command to create users, groups tables and populate them 6291 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6292 6293 if (open(my $fh, "> $db_script")) { 6294 print $fh <<EOS; 6295CREATE TABLE users ( 6296 userid TEXT, 6297 passwd TEXT, 6298 uid INTEGER, 6299 gid INTEGER, 6300 homedir TEXT, 6301 shell TEXT 6302); 6303INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 6304 6305CREATE TABLE groups ( 6306 groupname TEXT, 6307 gid INTEGER, 6308 members TEXT 6309); 6310INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', $gid, '$user'); 6311 6312CREATE TABLE user_salts ( 6313 userid TEXT, 6314 salt TEXT 6315); 6316INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt'); 6317EOS 6318 6319 unless (close($fh)) { 6320 die("Can't write $db_script: $!"); 6321 } 6322 6323 } else { 6324 die("Can't open $db_script: $!"); 6325 } 6326 6327 my $cmd = "sqlite3 $db_file < $db_script"; 6328 6329 if ($ENV{TEST_VERBOSE}) { 6330 print STDERR "Executing sqlite3: $cmd\n"; 6331 } 6332 6333 my @output = `$cmd`; 6334 if (scalar(@output) && 6335 $ENV{TEST_VERBOSE}) { 6336 print STDERR "Output: ", join('', @output), "\n"; 6337 } 6338 6339 my $config = { 6340 PidFile => $pid_file, 6341 ScoreboardFile => $scoreboard_file, 6342 SystemLog => $log_file, 6343 6344 IfModules => { 6345 'mod_delay.c' => { 6346 DelayEngine => 'off', 6347 }, 6348 6349 'mod_sql.c' => { 6350 SQLAuthTypes => 'sha1', 6351 SQLBackend => 'sqlite3', 6352 SQLConnectInfo => $db_file, 6353 SQLLogFile => $log_file, 6354 SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"', 6355 }, 6356 6357 'mod_sql_passwd.c' => { 6358 SQLPasswordEngine => 'on', 6359 SQLPasswordEncoding => 'hex', 6360 SQLPasswordSaltEncoding => 'HEX', 6361 SQLPasswordUserSalt => 'sql:/get-user-salt', 6362 }, 6363 }, 6364 }; 6365 6366 my ($port, $config_user, $config_group) = config_write($config_file, $config); 6367 6368 # Open pipes, for use between the parent and child processes. Specifically, 6369 # the child will indicate when it's done with its test by writing a message 6370 # to the parent. 6371 my ($rfh, $wfh); 6372 unless (pipe($rfh, $wfh)) { 6373 die("Can't open pipe: $!"); 6374 } 6375 6376 my $ex; 6377 6378 # Fork child 6379 $self->handle_sigchld(); 6380 defined(my $pid = fork()) or die("Can't fork: $!"); 6381 if ($pid) { 6382 eval { 6383 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6384 $client->login($user, "password"); 6385 6386 my $resp_msgs = $client->response_msgs(); 6387 my $nmsgs = scalar(@$resp_msgs); 6388 6389 my $expected; 6390 6391 $expected = 1; 6392 $self->assert($expected == $nmsgs, 6393 test_msg("Expected $expected, got $nmsgs")); 6394 6395 $expected = "User proftpd logged in"; 6396 $self->assert($expected eq $resp_msgs->[0], 6397 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 6398 6399 }; 6400 6401 if ($@) { 6402 $ex = $@; 6403 } 6404 6405 $wfh->print("done\n"); 6406 $wfh->flush(); 6407 6408 } else { 6409 eval { server_wait($config_file, $rfh) }; 6410 if ($@) { 6411 warn($@); 6412 exit 1; 6413 } 6414 6415 exit 0; 6416 } 6417 6418 # Stop server 6419 server_stop($pid_file); 6420 6421 $self->assert_child_ok($pid); 6422 6423 if ($ex) { 6424 test_append_logfile($log_file, $ex); 6425 unlink($log_file); 6426 6427 die($ex); 6428 } 6429 6430 unlink($log_file); 6431} 6432 6433sub sql_passwd_salt_file_base64_bug4138 { 6434 my $self = shift; 6435 my $tmpdir = $self->{tmpdir}; 6436 6437 my $config_file = "$tmpdir/sqlpasswd.conf"; 6438 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 6439 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 6440 6441 my $log_file = test_get_logfile(); 6442 6443 # This base64-encoded salt data has embedded NULs 6444 my $salt = 'p8CCsyWyyDX/infYBQBolKobDsQlWca9LLgteqD+rSo='; 6445 6446 my $user = 'proftpd'; 6447 my $group = 'ftpd'; 6448 6449 # I used: 6450 # 6451 # Digest::SHA1::sha1_hex((lc("password")) . $decoded_salt); 6452 # 6453 # to generate this password. 6454 my $passwd = '39ff37588e1a56b243b00cb6479a716ef50fc980'; 6455 6456 my $home_dir = File::Spec->rel2abs($tmpdir); 6457 my $uid = 500; 6458 my $gid = 500; 6459 6460 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6461 6462 # Build up sqlite3 command to create users, groups tables and populate them 6463 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6464 6465 if (open(my $fh, "> $db_script")) { 6466 print $fh <<EOS; 6467CREATE TABLE users ( 6468 userid TEXT, 6469 passwd TEXT, 6470 uid INTEGER, 6471 gid INTEGER, 6472 homedir TEXT, 6473 shell TEXT 6474); 6475INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 6476 6477CREATE TABLE groups ( 6478 groupname TEXT, 6479 gid INTEGER, 6480 members TEXT 6481); 6482INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 6483EOS 6484 6485 unless (close($fh)) { 6486 die("Can't write $db_script: $!"); 6487 } 6488 6489 } else { 6490 die("Can't open $db_script: $!"); 6491 } 6492 6493 my $cmd = "sqlite3 $db_file < $db_script"; 6494 6495 if ($ENV{TEST_VERBOSE}) { 6496 print STDERR "Executing sqlite3: $cmd\n"; 6497 } 6498 6499 my @output = `$cmd`; 6500 if (scalar(@output) && 6501 $ENV{TEST_VERBOSE}) { 6502 print STDERR "Output: ", join('', @output), "\n"; 6503 } 6504 6505 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 6506 if (open(my $fh, "> $salt_file")) { 6507 binmode($fh); 6508 print $fh $salt; 6509 6510 unless (close($fh)) { 6511 die("Can't write $salt_file: $!"); 6512 } 6513 6514 } else { 6515 die("Can't open $salt_file: $!"); 6516 } 6517 6518 my $config = { 6519 PidFile => $pid_file, 6520 ScoreboardFile => $scoreboard_file, 6521 SystemLog => $log_file, 6522 6523 IfModules => { 6524 'mod_delay.c' => { 6525 DelayEngine => 'off', 6526 }, 6527 6528 'mod_sql.c' => { 6529 SQLAuthTypes => 'sha1', 6530 SQLBackend => 'sqlite3', 6531 SQLConnectInfo => $db_file, 6532 SQLLogFile => $log_file, 6533 }, 6534 6535 'mod_sql_passwd.c' => { 6536 SQLPasswordEngine => 'on', 6537 SQLPasswordEncoding => 'hex', 6538 SQLPasswordSaltEncoding => 'base64', 6539 SQLPasswordSaltFile => $salt_file, 6540 }, 6541 }, 6542 }; 6543 6544 my ($port, $config_user, $config_group) = config_write($config_file, $config); 6545 6546 # Open pipes, for use between the parent and child processes. Specifically, 6547 # the child will indicate when it's done with its test by writing a message 6548 # to the parent. 6549 my ($rfh, $wfh); 6550 unless (pipe($rfh, $wfh)) { 6551 die("Can't open pipe: $!"); 6552 } 6553 6554 my $ex; 6555 6556 # Fork child 6557 $self->handle_sigchld(); 6558 defined(my $pid = fork()) or die("Can't fork: $!"); 6559 if ($pid) { 6560 eval { 6561 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6562 $client->login($user, "password"); 6563 6564 my $resp_msgs = $client->response_msgs(); 6565 my $nmsgs = scalar(@$resp_msgs); 6566 6567 my $expected; 6568 6569 $expected = 1; 6570 $self->assert($expected == $nmsgs, 6571 test_msg("Expected $expected, got $nmsgs")); 6572 6573 $expected = "User proftpd logged in"; 6574 $self->assert($expected eq $resp_msgs->[0], 6575 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 6576 6577 }; 6578 6579 if ($@) { 6580 $ex = $@; 6581 } 6582 6583 $wfh->print("done\n"); 6584 $wfh->flush(); 6585 6586 } else { 6587 eval { server_wait($config_file, $rfh) }; 6588 if ($@) { 6589 warn($@); 6590 exit 1; 6591 } 6592 6593 exit 0; 6594 } 6595 6596 # Stop server 6597 server_stop($pid_file); 6598 6599 $self->assert_child_ok($pid); 6600 6601 if ($ex) { 6602 test_append_logfile($log_file, $ex); 6603 unlink($log_file); 6604 6605 die($ex); 6606 } 6607 6608 unlink($log_file); 6609} 6610 6611sub sql_passwd_salt_file_hex_lc_bug4138 { 6612 my $self = shift; 6613 my $tmpdir = $self->{tmpdir}; 6614 6615 my $config_file = "$tmpdir/sqlpasswd.conf"; 6616 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 6617 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 6618 6619 my $log_file = test_get_logfile(); 6620 6621 # This hex-encoded salt data has embedded NULs 6622 my $salt = 'a7c082b325b2c835ff8a77d805006894aa1b0ec42559c6bd2cb82d7aa0fead2a'; 6623 6624 my $user = 'proftpd'; 6625 my $group = 'ftpd'; 6626 6627 # I used: 6628 # 6629 # Digest::SHA1::sha1_hex((lc("password")) . $decoded_salt); 6630 # 6631 # to generate this password. 6632 my $passwd = '39ff37588e1a56b243b00cb6479a716ef50fc980'; 6633 6634 my $home_dir = File::Spec->rel2abs($tmpdir); 6635 my $uid = 500; 6636 my $gid = 500; 6637 6638 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6639 6640 # Build up sqlite3 command to create users, groups tables and populate them 6641 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6642 6643 if (open(my $fh, "> $db_script")) { 6644 print $fh <<EOS; 6645CREATE TABLE users ( 6646 userid TEXT, 6647 passwd TEXT, 6648 uid INTEGER, 6649 gid INTEGER, 6650 homedir TEXT, 6651 shell TEXT 6652); 6653INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 6654 6655CREATE TABLE groups ( 6656 groupname TEXT, 6657 gid INTEGER, 6658 members TEXT 6659); 6660INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 6661EOS 6662 6663 unless (close($fh)) { 6664 die("Can't write $db_script: $!"); 6665 } 6666 6667 } else { 6668 die("Can't open $db_script: $!"); 6669 } 6670 6671 my $cmd = "sqlite3 $db_file < $db_script"; 6672 6673 if ($ENV{TEST_VERBOSE}) { 6674 print STDERR "Executing sqlite3: $cmd\n"; 6675 } 6676 6677 my @output = `$cmd`; 6678 if (scalar(@output) && 6679 $ENV{TEST_VERBOSE}) { 6680 print STDERR "Output: ", join('', @output), "\n"; 6681 } 6682 6683 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 6684 if (open(my $fh, "> $salt_file")) { 6685 binmode($fh); 6686 print $fh $salt; 6687 6688 unless (close($fh)) { 6689 die("Can't write $salt_file: $!"); 6690 } 6691 6692 } else { 6693 die("Can't open $salt_file: $!"); 6694 } 6695 6696 my $config = { 6697 PidFile => $pid_file, 6698 ScoreboardFile => $scoreboard_file, 6699 SystemLog => $log_file, 6700 6701 IfModules => { 6702 'mod_delay.c' => { 6703 DelayEngine => 'off', 6704 }, 6705 6706 'mod_sql.c' => { 6707 SQLAuthTypes => 'sha1', 6708 SQLBackend => 'sqlite3', 6709 SQLConnectInfo => $db_file, 6710 SQLLogFile => $log_file, 6711 }, 6712 6713 'mod_sql_passwd.c' => { 6714 SQLPasswordEngine => 'on', 6715 SQLPasswordEncoding => 'hex', 6716 SQLPasswordSaltEncoding => 'hex', 6717 SQLPasswordSaltFile => $salt_file, 6718 }, 6719 }, 6720 }; 6721 6722 my ($port, $config_user, $config_group) = config_write($config_file, $config); 6723 6724 # Open pipes, for use between the parent and child processes. Specifically, 6725 # the child will indicate when it's done with its test by writing a message 6726 # to the parent. 6727 my ($rfh, $wfh); 6728 unless (pipe($rfh, $wfh)) { 6729 die("Can't open pipe: $!"); 6730 } 6731 6732 my $ex; 6733 6734 # Fork child 6735 $self->handle_sigchld(); 6736 defined(my $pid = fork()) or die("Can't fork: $!"); 6737 if ($pid) { 6738 eval { 6739 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6740 $client->login($user, "password"); 6741 6742 my $resp_msgs = $client->response_msgs(); 6743 my $nmsgs = scalar(@$resp_msgs); 6744 6745 my $expected; 6746 6747 $expected = 1; 6748 $self->assert($expected == $nmsgs, 6749 test_msg("Expected $expected, got $nmsgs")); 6750 6751 $expected = "User proftpd logged in"; 6752 $self->assert($expected eq $resp_msgs->[0], 6753 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 6754 6755 }; 6756 6757 if ($@) { 6758 $ex = $@; 6759 } 6760 6761 $wfh->print("done\n"); 6762 $wfh->flush(); 6763 6764 } else { 6765 eval { server_wait($config_file, $rfh) }; 6766 if ($@) { 6767 warn($@); 6768 exit 1; 6769 } 6770 6771 exit 0; 6772 } 6773 6774 # Stop server 6775 server_stop($pid_file); 6776 6777 $self->assert_child_ok($pid); 6778 6779 if ($ex) { 6780 test_append_logfile($log_file, $ex); 6781 unlink($log_file); 6782 6783 die($ex); 6784 } 6785 6786 unlink($log_file); 6787} 6788 6789sub sql_passwd_salt_file_hex_uc_bug4138 { 6790 my $self = shift; 6791 my $tmpdir = $self->{tmpdir}; 6792 6793 my $config_file = "$tmpdir/sqlpasswd.conf"; 6794 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 6795 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 6796 6797 my $log_file = test_get_logfile(); 6798 6799 # This hex-encoded salt data has embedded NULs 6800 my $salt = 'A7C082B325B2C835FF8A77D805006894AA1B0EC42559C6BD2CB82D7AA0FEAD2A'; 6801 6802 my $user = 'proftpd'; 6803 my $group = 'ftpd'; 6804 6805 # I used: 6806 # 6807 # Digest::SHA1::sha1_hex((lc("password")) . $decoded_salt); 6808 # 6809 # to generate this password. 6810 my $passwd = '39ff37588e1a56b243b00cb6479a716ef50fc980'; 6811 6812 my $home_dir = File::Spec->rel2abs($tmpdir); 6813 my $uid = 500; 6814 my $gid = 500; 6815 6816 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6817 6818 # Build up sqlite3 command to create users, groups tables and populate them 6819 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6820 6821 if (open(my $fh, "> $db_script")) { 6822 print $fh <<EOS; 6823CREATE TABLE users ( 6824 userid TEXT, 6825 passwd TEXT, 6826 uid INTEGER, 6827 gid INTEGER, 6828 homedir TEXT, 6829 shell TEXT 6830); 6831INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 6832 6833CREATE TABLE groups ( 6834 groupname TEXT, 6835 gid INTEGER, 6836 members TEXT 6837); 6838INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 6839EOS 6840 6841 unless (close($fh)) { 6842 die("Can't write $db_script: $!"); 6843 } 6844 6845 } else { 6846 die("Can't open $db_script: $!"); 6847 } 6848 6849 my $cmd = "sqlite3 $db_file < $db_script"; 6850 6851 if ($ENV{TEST_VERBOSE}) { 6852 print STDERR "Executing sqlite3: $cmd\n"; 6853 } 6854 6855 my @output = `$cmd`; 6856 if (scalar(@output) && 6857 $ENV{TEST_VERBOSE}) { 6858 print STDERR "Output: ", join('', @output), "\n"; 6859 } 6860 6861 my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt"); 6862 if (open(my $fh, "> $salt_file")) { 6863 binmode($fh); 6864 print $fh $salt; 6865 6866 unless (close($fh)) { 6867 die("Can't write $salt_file: $!"); 6868 } 6869 6870 } else { 6871 die("Can't open $salt_file: $!"); 6872 } 6873 6874 my $config = { 6875 PidFile => $pid_file, 6876 ScoreboardFile => $scoreboard_file, 6877 SystemLog => $log_file, 6878 6879 IfModules => { 6880 'mod_delay.c' => { 6881 DelayEngine => 'off', 6882 }, 6883 6884 'mod_sql.c' => { 6885 SQLAuthTypes => 'sha1', 6886 SQLBackend => 'sqlite3', 6887 SQLConnectInfo => $db_file, 6888 SQLLogFile => $log_file, 6889 }, 6890 6891 'mod_sql_passwd.c' => { 6892 SQLPasswordEngine => 'on', 6893 SQLPasswordEncoding => 'hex', 6894 SQLPasswordSaltEncoding => 'HEX', 6895 SQLPasswordSaltFile => $salt_file, 6896 }, 6897 }, 6898 }; 6899 6900 my ($port, $config_user, $config_group) = config_write($config_file, $config); 6901 6902 # Open pipes, for use between the parent and child processes. Specifically, 6903 # the child will indicate when it's done with its test by writing a message 6904 # to the parent. 6905 my ($rfh, $wfh); 6906 unless (pipe($rfh, $wfh)) { 6907 die("Can't open pipe: $!"); 6908 } 6909 6910 my $ex; 6911 6912 # Fork child 6913 $self->handle_sigchld(); 6914 defined(my $pid = fork()) or die("Can't fork: $!"); 6915 if ($pid) { 6916 eval { 6917 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6918 $client->login($user, "password"); 6919 6920 my $resp_msgs = $client->response_msgs(); 6921 my $nmsgs = scalar(@$resp_msgs); 6922 6923 my $expected; 6924 6925 $expected = 1; 6926 $self->assert($expected == $nmsgs, 6927 test_msg("Expected $expected, got $nmsgs")); 6928 6929 $expected = "User proftpd logged in"; 6930 $self->assert($expected eq $resp_msgs->[0], 6931 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 6932 6933 }; 6934 6935 if ($@) { 6936 $ex = $@; 6937 } 6938 6939 $wfh->print("done\n"); 6940 $wfh->flush(); 6941 6942 } else { 6943 eval { server_wait($config_file, $rfh) }; 6944 if ($@) { 6945 warn($@); 6946 exit 1; 6947 } 6948 6949 exit 0; 6950 } 6951 6952 # Stop server 6953 server_stop($pid_file); 6954 6955 $self->assert_child_ok($pid); 6956 6957 if ($ex) { 6958 test_append_logfile($log_file, $ex); 6959 unlink($log_file); 6960 6961 die($ex); 6962 } 6963 6964 unlink($log_file); 6965} 6966 6967sub sql_passwd_scrypt_base64_interactive_cost { 6968 my $self = shift; 6969 my $tmpdir = $self->{tmpdir}; 6970 6971 my $config_file = "$tmpdir/sqlpasswd.conf"; 6972 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 6973 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 6974 6975 my $log_file = test_get_logfile(); 6976 6977 my $user = 'proftpd'; 6978 my $group = 'ftpd'; 6979 6980 # I had to look at the mod_sql_passwd-generated logs to get this password; 6981 # this means it's a bit incestuous and thus suspect. 6982 my $passwd = 'ZI+02v+UMvtIvFBALSHyBiNu9At1h+HgN6xzI7nhAtM='; 6983 6984 my $home_dir = File::Spec->rel2abs($tmpdir); 6985 my $uid = 500; 6986 my $gid = 500; 6987 6988 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6989 6990 # Build up sqlite3 command to create users, groups tables and populate them 6991 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6992 6993 if (open(my $fh, "> $db_script")) { 6994 print $fh <<EOS; 6995CREATE TABLE users ( 6996 userid TEXT, 6997 passwd TEXT, 6998 uid INTEGER, 6999 gid INTEGER, 7000 homedir TEXT, 7001 shell TEXT 7002); 7003INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 7004 7005CREATE TABLE groups ( 7006 groupname TEXT, 7007 gid INTEGER, 7008 members TEXT 7009); 7010INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 7011EOS 7012 7013 unless (close($fh)) { 7014 die("Can't write $db_script: $!"); 7015 } 7016 7017 } else { 7018 die("Can't open $db_script: $!"); 7019 } 7020 7021 my $cmd = "sqlite3 $db_file < $db_script"; 7022 7023 if ($ENV{TEST_VERBOSE}) { 7024 print STDERR "Executing sqlite3: $cmd\n"; 7025 } 7026 7027 my @output = `$cmd`; 7028 if (scalar(@output) && 7029 $ENV{TEST_VERBOSE}) { 7030 print STDERR "Output: ", join('', @output), "\n"; 7031 } 7032 7033 # This hex-encoded salt data has embedded NULs 7034 my $salt = lc('A7C082B325B2C835FF8A77D805006894AA1B0EC42559C6BD2CB82D7AA0FEAD2A'); 7035 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 7036 if (open(my $fh, "> $salt_file")) { 7037 binmode($fh); 7038 print $fh $salt; 7039 7040 unless (close($fh)) { 7041 die("Can't write $salt_file: $!"); 7042 } 7043 7044 } else { 7045 die("Can't open $salt_file: $!"); 7046 } 7047 7048 my $config = { 7049 PidFile => $pid_file, 7050 ScoreboardFile => $scoreboard_file, 7051 SystemLog => $log_file, 7052 TraceLog => $log_file, 7053 Trace => 'sql.passwd:20', 7054 7055 IfModules => { 7056 'mod_delay.c' => { 7057 DelayEngine => 'off', 7058 }, 7059 7060 'mod_sql.c' => { 7061 SQLAuthTypes => 'scrypt', 7062 SQLBackend => 'sqlite3', 7063 SQLConnectInfo => $db_file, 7064 SQLLogFile => $log_file, 7065 }, 7066 7067 'mod_sql_passwd.c' => { 7068 SQLPasswordEngine => 'on', 7069 SQLPasswordEncoding => 'base64', 7070 SQLPasswordSaltEncoding => 'hex', 7071 SQLPasswordSaltFile => $salt_file, 7072 SQLPasswordCost => 'Interactive', 7073 }, 7074 }, 7075 }; 7076 7077 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7078 7079 # Open pipes, for use between the parent and child processes. Specifically, 7080 # the child will indicate when it's done with its test by writing a message 7081 # to the parent. 7082 my ($rfh, $wfh); 7083 unless (pipe($rfh, $wfh)) { 7084 die("Can't open pipe: $!"); 7085 } 7086 7087 my $ex; 7088 7089 # Fork child 7090 $self->handle_sigchld(); 7091 defined(my $pid = fork()) or die("Can't fork: $!"); 7092 if ($pid) { 7093 eval { 7094 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7095 $client->login($user, "test"); 7096 7097 my $resp_msgs = $client->response_msgs(); 7098 my $nmsgs = scalar(@$resp_msgs); 7099 7100 my $expected; 7101 7102 $expected = 1; 7103 $self->assert($expected == $nmsgs, 7104 test_msg("Expected response message count $expected, got $nmsgs")); 7105 7106 $expected = "User $user logged in"; 7107 $self->assert($expected eq $resp_msgs->[0], 7108 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 7109 }; 7110 7111 if ($@) { 7112 $ex = $@; 7113 } 7114 7115 $wfh->print("done\n"); 7116 $wfh->flush(); 7117 7118 } else { 7119 eval { server_wait($config_file, $rfh) }; 7120 if ($@) { 7121 warn($@); 7122 exit 1; 7123 } 7124 7125 exit 0; 7126 } 7127 7128 # Stop server 7129 server_stop($pid_file); 7130 7131 $self->assert_child_ok($pid); 7132 7133 if ($ex) { 7134 test_append_logfile($log_file, $ex); 7135 unlink($log_file); 7136 7137 die($ex); 7138 } 7139 7140 unlink($log_file); 7141} 7142 7143sub sql_passwd_scrypt_hex_lc_interactive_cost { 7144 my $self = shift; 7145 my $tmpdir = $self->{tmpdir}; 7146 7147 my $config_file = "$tmpdir/sqlpasswd.conf"; 7148 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 7149 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 7150 7151 my $log_file = test_get_logfile(); 7152 7153 my $user = 'proftpd'; 7154 my $group = 'ftpd'; 7155 7156 # I had to look at the mod_sql_passwd-generated logs to get this password; 7157 # this means it's a bit incestuous and thus suspect. 7158 my $passwd = '648fb4daff9432fb48bc50402d21f206236ef40b7587e1e037ac7323b9e102d3'; 7159 7160 my $home_dir = File::Spec->rel2abs($tmpdir); 7161 my $uid = 500; 7162 my $gid = 500; 7163 7164 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 7165 7166 # Build up sqlite3 command to create users, groups tables and populate them 7167 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 7168 7169 if (open(my $fh, "> $db_script")) { 7170 print $fh <<EOS; 7171CREATE TABLE users ( 7172 userid TEXT, 7173 passwd TEXT, 7174 uid INTEGER, 7175 gid INTEGER, 7176 homedir TEXT, 7177 shell TEXT 7178); 7179INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 7180 7181CREATE TABLE groups ( 7182 groupname TEXT, 7183 gid INTEGER, 7184 members TEXT 7185); 7186INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 7187EOS 7188 7189 unless (close($fh)) { 7190 die("Can't write $db_script: $!"); 7191 } 7192 7193 } else { 7194 die("Can't open $db_script: $!"); 7195 } 7196 7197 my $cmd = "sqlite3 $db_file < $db_script"; 7198 7199 if ($ENV{TEST_VERBOSE}) { 7200 print STDERR "Executing sqlite3: $cmd\n"; 7201 } 7202 7203 my @output = `$cmd`; 7204 if (scalar(@output) && 7205 $ENV{TEST_VERBOSE}) { 7206 print STDERR "Output: ", join('', @output), "\n"; 7207 } 7208 7209 # This hex-encoded salt data has embedded NULs 7210 my $salt = lc('A7C082B325B2C835FF8A77D805006894AA1B0EC42559C6BD2CB82D7AA0FEAD2A'); 7211 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 7212 if (open(my $fh, "> $salt_file")) { 7213 binmode($fh); 7214 print $fh $salt; 7215 7216 unless (close($fh)) { 7217 die("Can't write $salt_file: $!"); 7218 } 7219 7220 } else { 7221 die("Can't open $salt_file: $!"); 7222 } 7223 7224 my $config = { 7225 PidFile => $pid_file, 7226 ScoreboardFile => $scoreboard_file, 7227 SystemLog => $log_file, 7228 TraceLog => $log_file, 7229 Trace => 'sql.passwd:20', 7230 7231 IfModules => { 7232 'mod_delay.c' => { 7233 DelayEngine => 'off', 7234 }, 7235 7236 'mod_sql.c' => { 7237 SQLAuthTypes => 'scrypt', 7238 SQLBackend => 'sqlite3', 7239 SQLConnectInfo => $db_file, 7240 SQLLogFile => $log_file, 7241 }, 7242 7243 'mod_sql_passwd.c' => { 7244 SQLPasswordEngine => 'on', 7245 SQLPasswordEncoding => 'hex', 7246 SQLPasswordSaltEncoding => 'hex', 7247 SQLPasswordSaltFile => $salt_file, 7248 SQLPasswordCost => 'Interactive', 7249 }, 7250 }, 7251 }; 7252 7253 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7254 7255 # Open pipes, for use between the parent and child processes. Specifically, 7256 # the child will indicate when it's done with its test by writing a message 7257 # to the parent. 7258 my ($rfh, $wfh); 7259 unless (pipe($rfh, $wfh)) { 7260 die("Can't open pipe: $!"); 7261 } 7262 7263 my $ex; 7264 7265 # Fork child 7266 $self->handle_sigchld(); 7267 defined(my $pid = fork()) or die("Can't fork: $!"); 7268 if ($pid) { 7269 eval { 7270 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7271 $client->login($user, "test"); 7272 7273 my $resp_msgs = $client->response_msgs(); 7274 my $nmsgs = scalar(@$resp_msgs); 7275 7276 my $expected; 7277 7278 $expected = 1; 7279 $self->assert($expected == $nmsgs, 7280 test_msg("Expected response message count $expected, got $nmsgs")); 7281 7282 $expected = "User $user logged in"; 7283 $self->assert($expected eq $resp_msgs->[0], 7284 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 7285 }; 7286 7287 if ($@) { 7288 $ex = $@; 7289 } 7290 7291 $wfh->print("done\n"); 7292 $wfh->flush(); 7293 7294 } else { 7295 eval { server_wait($config_file, $rfh) }; 7296 if ($@) { 7297 warn($@); 7298 exit 1; 7299 } 7300 7301 exit 0; 7302 } 7303 7304 # Stop server 7305 server_stop($pid_file); 7306 7307 $self->assert_child_ok($pid); 7308 7309 if ($ex) { 7310 test_append_logfile($log_file, $ex); 7311 unlink($log_file); 7312 7313 die($ex); 7314 } 7315 7316 unlink($log_file); 7317} 7318 7319sub sql_passwd_scrypt_hex_uc_interactive_cost { 7320 my $self = shift; 7321 my $tmpdir = $self->{tmpdir}; 7322 7323 my $config_file = "$tmpdir/sqlpasswd.conf"; 7324 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 7325 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 7326 7327 my $log_file = test_get_logfile(); 7328 7329 my $user = 'proftpd'; 7330 my $group = 'ftpd'; 7331 7332 # I had to look at the mod_sql_passwd-generated logs to get this password; 7333 # this means it's a bit incestuous and thus suspect. 7334 my $passwd = uc('648fb4daff9432fb48bc50402d21f206236ef40b7587e1e037ac7323b9e102d3'); 7335 7336 my $home_dir = File::Spec->rel2abs($tmpdir); 7337 my $uid = 500; 7338 my $gid = 500; 7339 7340 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 7341 7342 # Build up sqlite3 command to create users, groups tables and populate them 7343 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 7344 7345 if (open(my $fh, "> $db_script")) { 7346 print $fh <<EOS; 7347CREATE TABLE users ( 7348 userid TEXT, 7349 passwd TEXT, 7350 uid INTEGER, 7351 gid INTEGER, 7352 homedir TEXT, 7353 shell TEXT 7354); 7355INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 7356 7357CREATE TABLE groups ( 7358 groupname TEXT, 7359 gid INTEGER, 7360 members TEXT 7361); 7362INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 7363EOS 7364 7365 unless (close($fh)) { 7366 die("Can't write $db_script: $!"); 7367 } 7368 7369 } else { 7370 die("Can't open $db_script: $!"); 7371 } 7372 7373 my $cmd = "sqlite3 $db_file < $db_script"; 7374 7375 if ($ENV{TEST_VERBOSE}) { 7376 print STDERR "Executing sqlite3: $cmd\n"; 7377 } 7378 7379 my @output = `$cmd`; 7380 if (scalar(@output) && 7381 $ENV{TEST_VERBOSE}) { 7382 print STDERR "Output: ", join('', @output), "\n"; 7383 } 7384 7385 # This hex-encoded salt data has embedded NULs 7386 my $salt = lc('A7C082B325B2C835FF8A77D805006894AA1B0EC42559C6BD2CB82D7AA0FEAD2A'); 7387 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 7388 if (open(my $fh, "> $salt_file")) { 7389 binmode($fh); 7390 print $fh $salt; 7391 7392 unless (close($fh)) { 7393 die("Can't write $salt_file: $!"); 7394 } 7395 7396 } else { 7397 die("Can't open $salt_file: $!"); 7398 } 7399 7400 my $config = { 7401 PidFile => $pid_file, 7402 ScoreboardFile => $scoreboard_file, 7403 SystemLog => $log_file, 7404 TraceLog => $log_file, 7405 Trace => 'sql.passwd:20', 7406 7407 IfModules => { 7408 'mod_delay.c' => { 7409 DelayEngine => 'off', 7410 }, 7411 7412 'mod_sql.c' => { 7413 SQLAuthTypes => 'scrypt', 7414 SQLBackend => 'sqlite3', 7415 SQLConnectInfo => $db_file, 7416 SQLLogFile => $log_file, 7417 }, 7418 7419 'mod_sql_passwd.c' => { 7420 SQLPasswordEngine => 'on', 7421 SQLPasswordEncoding => 'HEX', 7422 SQLPasswordSaltEncoding => 'hex', 7423 SQLPasswordSaltFile => $salt_file, 7424 SQLPasswordCost => 'Interactive', 7425 }, 7426 }, 7427 }; 7428 7429 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7430 7431 # Open pipes, for use between the parent and child processes. Specifically, 7432 # the child will indicate when it's done with its test by writing a message 7433 # to the parent. 7434 my ($rfh, $wfh); 7435 unless (pipe($rfh, $wfh)) { 7436 die("Can't open pipe: $!"); 7437 } 7438 7439 my $ex; 7440 7441 # Fork child 7442 $self->handle_sigchld(); 7443 defined(my $pid = fork()) or die("Can't fork: $!"); 7444 if ($pid) { 7445 eval { 7446 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7447 $client->login($user, "test"); 7448 7449 my $resp_msgs = $client->response_msgs(); 7450 my $nmsgs = scalar(@$resp_msgs); 7451 7452 my $expected; 7453 7454 $expected = 1; 7455 $self->assert($expected == $nmsgs, 7456 test_msg("Expected response message count $expected, got $nmsgs")); 7457 7458 $expected = "User $user logged in"; 7459 $self->assert($expected eq $resp_msgs->[0], 7460 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 7461 }; 7462 7463 if ($@) { 7464 $ex = $@; 7465 } 7466 7467 $wfh->print("done\n"); 7468 $wfh->flush(); 7469 7470 } else { 7471 eval { server_wait($config_file, $rfh) }; 7472 if ($@) { 7473 warn($@); 7474 exit 1; 7475 } 7476 7477 exit 0; 7478 } 7479 7480 # Stop server 7481 server_stop($pid_file); 7482 7483 $self->assert_child_ok($pid); 7484 7485 if ($ex) { 7486 test_append_logfile($log_file, $ex); 7487 unlink($log_file); 7488 7489 die($ex); 7490 } 7491 7492 unlink($log_file); 7493} 7494 7495sub sql_passwd_scrypt_base64_sensitive_cost { 7496 my $self = shift; 7497 my $tmpdir = $self->{tmpdir}; 7498 7499 my $config_file = "$tmpdir/sqlpasswd.conf"; 7500 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 7501 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 7502 7503 my $log_file = test_get_logfile(); 7504 7505 my $user = 'proftpd'; 7506 my $group = 'ftpd'; 7507 7508 # I had to look at the mod_sql_passwd-generated logs to get this password; 7509 # this means it's a bit incestuous and thus suspect. 7510 my $passwd = 'AxoE22pqKy/Vxa30TMz3D71E0LTQ45abmtVlXOyP2hA='; 7511 7512 my $home_dir = File::Spec->rel2abs($tmpdir); 7513 my $uid = 500; 7514 my $gid = 500; 7515 7516 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 7517 7518 # Build up sqlite3 command to create users, groups tables and populate them 7519 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 7520 7521 if (open(my $fh, "> $db_script")) { 7522 print $fh <<EOS; 7523CREATE TABLE users ( 7524 userid TEXT, 7525 passwd TEXT, 7526 uid INTEGER, 7527 gid INTEGER, 7528 homedir TEXT, 7529 shell TEXT 7530); 7531INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 7532 7533CREATE TABLE groups ( 7534 groupname TEXT, 7535 gid INTEGER, 7536 members TEXT 7537); 7538INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 7539EOS 7540 7541 unless (close($fh)) { 7542 die("Can't write $db_script: $!"); 7543 } 7544 7545 } else { 7546 die("Can't open $db_script: $!"); 7547 } 7548 7549 my $cmd = "sqlite3 $db_file < $db_script"; 7550 7551 if ($ENV{TEST_VERBOSE}) { 7552 print STDERR "Executing sqlite3: $cmd\n"; 7553 } 7554 7555 my @output = `$cmd`; 7556 if (scalar(@output) && 7557 $ENV{TEST_VERBOSE}) { 7558 print STDERR "Output: ", join('', @output), "\n"; 7559 } 7560 7561 # This hex-encoded salt data has embedded NULs 7562 my $salt = lc('A7C082B325B2C835FF8A77D805006894AA1B0EC42559C6BD2CB82D7AA0FEAD2A'); 7563 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 7564 if (open(my $fh, "> $salt_file")) { 7565 binmode($fh); 7566 print $fh $salt; 7567 7568 unless (close($fh)) { 7569 die("Can't write $salt_file: $!"); 7570 } 7571 7572 } else { 7573 die("Can't open $salt_file: $!"); 7574 } 7575 7576 my $config = { 7577 PidFile => $pid_file, 7578 ScoreboardFile => $scoreboard_file, 7579 SystemLog => $log_file, 7580 TraceLog => $log_file, 7581 Trace => 'sql.passwd:20', 7582 7583 IfModules => { 7584 'mod_delay.c' => { 7585 DelayEngine => 'off', 7586 }, 7587 7588 'mod_sql.c' => { 7589 SQLAuthTypes => 'scrypt', 7590 SQLBackend => 'sqlite3', 7591 SQLConnectInfo => $db_file, 7592 SQLLogFile => $log_file, 7593 }, 7594 7595 'mod_sql_passwd.c' => { 7596 SQLPasswordEngine => 'on', 7597 SQLPasswordEncoding => 'base64', 7598 SQLPasswordSaltEncoding => 'hex', 7599 SQLPasswordSaltFile => $salt_file, 7600 SQLPasswordCost => 'Sensitive', 7601 }, 7602 }, 7603 }; 7604 7605 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7606 7607 # Open pipes, for use between the parent and child processes. Specifically, 7608 # the child will indicate when it's done with its test by writing a message 7609 # to the parent. 7610 my ($rfh, $wfh); 7611 unless (pipe($rfh, $wfh)) { 7612 die("Can't open pipe: $!"); 7613 } 7614 7615 my $ex; 7616 7617 # Fork child 7618 $self->handle_sigchld(); 7619 defined(my $pid = fork()) or die("Can't fork: $!"); 7620 if ($pid) { 7621 eval { 7622 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7623 $client->login($user, "test"); 7624 7625 my $resp_msgs = $client->response_msgs(); 7626 my $nmsgs = scalar(@$resp_msgs); 7627 7628 my $expected; 7629 7630 $expected = 1; 7631 $self->assert($expected == $nmsgs, 7632 test_msg("Expected response message count $expected, got $nmsgs")); 7633 7634 $expected = "User $user logged in"; 7635 $self->assert($expected eq $resp_msgs->[0], 7636 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 7637 }; 7638 7639 if ($@) { 7640 $ex = $@; 7641 } 7642 7643 $wfh->print("done\n"); 7644 $wfh->flush(); 7645 7646 } else { 7647 eval { server_wait($config_file, $rfh) }; 7648 if ($@) { 7649 warn($@); 7650 exit 1; 7651 } 7652 7653 exit 0; 7654 } 7655 7656 # Stop server 7657 server_stop($pid_file); 7658 7659 $self->assert_child_ok($pid); 7660 7661 if ($ex) { 7662 test_append_logfile($log_file, $ex); 7663 unlink($log_file); 7664 7665 die($ex); 7666 } 7667 7668 unlink($log_file); 7669} 7670 7671sub sql_passwd_scrypt_hex_lc_sensitive_cost { 7672 my $self = shift; 7673 my $tmpdir = $self->{tmpdir}; 7674 7675 my $config_file = "$tmpdir/sqlpasswd.conf"; 7676 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 7677 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 7678 7679 my $log_file = test_get_logfile(); 7680 7681 my $user = 'proftpd'; 7682 my $group = 'ftpd'; 7683 7684 # I had to look at the mod_sql_passwd-generated logs to get this password; 7685 # this means it's a bit incestuous and thus suspect. 7686 my $passwd = '031a04db6a6a2b2fd5c5adf44cccf70fbd44d0b4d0e3969b9ad5655cec8fda10'; 7687 7688 my $home_dir = File::Spec->rel2abs($tmpdir); 7689 my $uid = 500; 7690 my $gid = 500; 7691 7692 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 7693 7694 # Build up sqlite3 command to create users, groups tables and populate them 7695 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 7696 7697 if (open(my $fh, "> $db_script")) { 7698 print $fh <<EOS; 7699CREATE TABLE users ( 7700 userid TEXT, 7701 passwd TEXT, 7702 uid INTEGER, 7703 gid INTEGER, 7704 homedir TEXT, 7705 shell TEXT 7706); 7707INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 7708 7709CREATE TABLE groups ( 7710 groupname TEXT, 7711 gid INTEGER, 7712 members TEXT 7713); 7714INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 7715EOS 7716 7717 unless (close($fh)) { 7718 die("Can't write $db_script: $!"); 7719 } 7720 7721 } else { 7722 die("Can't open $db_script: $!"); 7723 } 7724 7725 my $cmd = "sqlite3 $db_file < $db_script"; 7726 7727 if ($ENV{TEST_VERBOSE}) { 7728 print STDERR "Executing sqlite3: $cmd\n"; 7729 } 7730 7731 my @output = `$cmd`; 7732 if (scalar(@output) && 7733 $ENV{TEST_VERBOSE}) { 7734 print STDERR "Output: ", join('', @output), "\n"; 7735 } 7736 7737 # This hex-encoded salt data has embedded NULs 7738 my $salt = lc('A7C082B325B2C835FF8A77D805006894AA1B0EC42559C6BD2CB82D7AA0FEAD2A'); 7739 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 7740 if (open(my $fh, "> $salt_file")) { 7741 binmode($fh); 7742 print $fh $salt; 7743 7744 unless (close($fh)) { 7745 die("Can't write $salt_file: $!"); 7746 } 7747 7748 } else { 7749 die("Can't open $salt_file: $!"); 7750 } 7751 7752 my $config = { 7753 PidFile => $pid_file, 7754 ScoreboardFile => $scoreboard_file, 7755 SystemLog => $log_file, 7756 TraceLog => $log_file, 7757 Trace => 'sql.passwd:20', 7758 7759 IfModules => { 7760 'mod_delay.c' => { 7761 DelayEngine => 'off', 7762 }, 7763 7764 'mod_sql.c' => { 7765 SQLAuthTypes => 'scrypt', 7766 SQLBackend => 'sqlite3', 7767 SQLConnectInfo => $db_file, 7768 SQLLogFile => $log_file, 7769 }, 7770 7771 'mod_sql_passwd.c' => { 7772 SQLPasswordEngine => 'on', 7773 SQLPasswordEncoding => 'hex', 7774 SQLPasswordSaltEncoding => 'hex', 7775 SQLPasswordSaltFile => $salt_file, 7776 SQLPasswordCost => 'Sensitive', 7777 }, 7778 }, 7779 }; 7780 7781 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7782 7783 # Open pipes, for use between the parent and child processes. Specifically, 7784 # the child will indicate when it's done with its test by writing a message 7785 # to the parent. 7786 my ($rfh, $wfh); 7787 unless (pipe($rfh, $wfh)) { 7788 die("Can't open pipe: $!"); 7789 } 7790 7791 my $ex; 7792 7793 # Fork child 7794 $self->handle_sigchld(); 7795 defined(my $pid = fork()) or die("Can't fork: $!"); 7796 if ($pid) { 7797 eval { 7798 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7799 $client->login($user, "test"); 7800 7801 my $resp_msgs = $client->response_msgs(); 7802 my $nmsgs = scalar(@$resp_msgs); 7803 7804 my $expected; 7805 7806 $expected = 1; 7807 $self->assert($expected == $nmsgs, 7808 test_msg("Expected response message count $expected, got $nmsgs")); 7809 7810 $expected = "User $user logged in"; 7811 $self->assert($expected eq $resp_msgs->[0], 7812 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 7813 }; 7814 7815 if ($@) { 7816 $ex = $@; 7817 } 7818 7819 $wfh->print("done\n"); 7820 $wfh->flush(); 7821 7822 } else { 7823 eval { server_wait($config_file, $rfh) }; 7824 if ($@) { 7825 warn($@); 7826 exit 1; 7827 } 7828 7829 exit 0; 7830 } 7831 7832 # Stop server 7833 server_stop($pid_file); 7834 7835 $self->assert_child_ok($pid); 7836 7837 if ($ex) { 7838 test_append_logfile($log_file, $ex); 7839 unlink($log_file); 7840 7841 die($ex); 7842 } 7843 7844 unlink($log_file); 7845} 7846 7847sub sql_passwd_scrypt_hex_uc_sensitive_cost { 7848 my $self = shift; 7849 my $tmpdir = $self->{tmpdir}; 7850 7851 my $config_file = "$tmpdir/sqlpasswd.conf"; 7852 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 7853 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 7854 7855 my $log_file = test_get_logfile(); 7856 7857 my $user = 'proftpd'; 7858 my $group = 'ftpd'; 7859 7860 # I had to look at the mod_sql_passwd-generated logs to get this password; 7861 # this means it's a bit incestuous and thus suspect. 7862 my $passwd = uc('031a04db6a6a2b2fd5c5adf44cccf70fbd44d0b4d0e3969b9ad5655cec8fda10'); 7863 7864 my $home_dir = File::Spec->rel2abs($tmpdir); 7865 my $uid = 500; 7866 my $gid = 500; 7867 7868 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 7869 7870 # Build up sqlite3 command to create users, groups tables and populate them 7871 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 7872 7873 if (open(my $fh, "> $db_script")) { 7874 print $fh <<EOS; 7875CREATE TABLE users ( 7876 userid TEXT, 7877 passwd TEXT, 7878 uid INTEGER, 7879 gid INTEGER, 7880 homedir TEXT, 7881 shell TEXT 7882); 7883INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 7884 7885CREATE TABLE groups ( 7886 groupname TEXT, 7887 gid INTEGER, 7888 members TEXT 7889); 7890INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 7891EOS 7892 7893 unless (close($fh)) { 7894 die("Can't write $db_script: $!"); 7895 } 7896 7897 } else { 7898 die("Can't open $db_script: $!"); 7899 } 7900 7901 my $cmd = "sqlite3 $db_file < $db_script"; 7902 7903 if ($ENV{TEST_VERBOSE}) { 7904 print STDERR "Executing sqlite3: $cmd\n"; 7905 } 7906 7907 my @output = `$cmd`; 7908 if (scalar(@output) && 7909 $ENV{TEST_VERBOSE}) { 7910 print STDERR "Output: ", join('', @output), "\n"; 7911 } 7912 7913 # This hex-encoded salt data has embedded NULs 7914 my $salt = lc('A7C082B325B2C835FF8A77D805006894AA1B0EC42559C6BD2CB82D7AA0FEAD2A'); 7915 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 7916 if (open(my $fh, "> $salt_file")) { 7917 binmode($fh); 7918 print $fh $salt; 7919 7920 unless (close($fh)) { 7921 die("Can't write $salt_file: $!"); 7922 } 7923 7924 } else { 7925 die("Can't open $salt_file: $!"); 7926 } 7927 7928 my $config = { 7929 PidFile => $pid_file, 7930 ScoreboardFile => $scoreboard_file, 7931 SystemLog => $log_file, 7932 TraceLog => $log_file, 7933 Trace => 'sql.passwd:20', 7934 7935 IfModules => { 7936 'mod_delay.c' => { 7937 DelayEngine => 'off', 7938 }, 7939 7940 'mod_sql.c' => { 7941 SQLAuthTypes => 'scrypt', 7942 SQLBackend => 'sqlite3', 7943 SQLConnectInfo => $db_file, 7944 SQLLogFile => $log_file, 7945 }, 7946 7947 'mod_sql_passwd.c' => { 7948 SQLPasswordEngine => 'on', 7949 SQLPasswordEncoding => 'HEX', 7950 SQLPasswordSaltEncoding => 'hex', 7951 SQLPasswordSaltFile => $salt_file, 7952 SQLPasswordCost => 'Sensitive', 7953 }, 7954 }, 7955 }; 7956 7957 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7958 7959 # Open pipes, for use between the parent and child processes. Specifically, 7960 # the child will indicate when it's done with its test by writing a message 7961 # to the parent. 7962 my ($rfh, $wfh); 7963 unless (pipe($rfh, $wfh)) { 7964 die("Can't open pipe: $!"); 7965 } 7966 7967 my $ex; 7968 7969 # Fork child 7970 $self->handle_sigchld(); 7971 defined(my $pid = fork()) or die("Can't fork: $!"); 7972 if ($pid) { 7973 eval { 7974 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7975 $client->login($user, "test"); 7976 7977 my $resp_msgs = $client->response_msgs(); 7978 my $nmsgs = scalar(@$resp_msgs); 7979 7980 my $expected; 7981 7982 $expected = 1; 7983 $self->assert($expected == $nmsgs, 7984 test_msg("Expected response message count $expected, got $nmsgs")); 7985 7986 $expected = "User $user logged in"; 7987 $self->assert($expected eq $resp_msgs->[0], 7988 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 7989 }; 7990 7991 if ($@) { 7992 $ex = $@; 7993 } 7994 7995 $wfh->print("done\n"); 7996 $wfh->flush(); 7997 7998 } else { 7999 eval { server_wait($config_file, $rfh) }; 8000 if ($@) { 8001 warn($@); 8002 exit 1; 8003 } 8004 8005 exit 0; 8006 } 8007 8008 # Stop server 8009 server_stop($pid_file); 8010 8011 $self->assert_child_ok($pid); 8012 8013 if ($ex) { 8014 test_append_logfile($log_file, $ex); 8015 unlink($log_file); 8016 8017 die($ex); 8018 } 8019 8020 unlink($log_file); 8021} 8022 8023sub sql_passwd_scrypt_hex_uc_sensitive_cost_len_64 { 8024 my $self = shift; 8025 my $tmpdir = $self->{tmpdir}; 8026 8027 my $config_file = "$tmpdir/sqlpasswd.conf"; 8028 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 8029 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 8030 8031 my $log_file = test_get_logfile(); 8032 8033 my $user = 'proftpd'; 8034 my $group = 'ftpd'; 8035 8036 my $scrypt_hash_len = 64; 8037 8038 # I had to look at the mod_sql_passwd-generated logs to get this password; 8039 # this means it's a bit incestuous and thus suspect. 8040 my $passwd = uc('031a04db6a6a2b2fd5c5adf44cccf70fbd44d0b4d0e3969b9ad5655cec8fda10ae28c6b433df6575876c10212a0b9c26cddef82294a223fb72d6a2fc4aa173e0'); 8041 8042 my $home_dir = File::Spec->rel2abs($tmpdir); 8043 my $uid = 500; 8044 my $gid = 500; 8045 8046 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 8047 8048 # Build up sqlite3 command to create users, groups tables and populate them 8049 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 8050 8051 if (open(my $fh, "> $db_script")) { 8052 print $fh <<EOS; 8053CREATE TABLE users ( 8054 userid TEXT, 8055 passwd TEXT, 8056 uid INTEGER, 8057 gid INTEGER, 8058 homedir TEXT, 8059 shell TEXT 8060); 8061INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 8062 8063CREATE TABLE groups ( 8064 groupname TEXT, 8065 gid INTEGER, 8066 members TEXT 8067); 8068INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 8069EOS 8070 8071 unless (close($fh)) { 8072 die("Can't write $db_script: $!"); 8073 } 8074 8075 } else { 8076 die("Can't open $db_script: $!"); 8077 } 8078 8079 my $cmd = "sqlite3 $db_file < $db_script"; 8080 8081 if ($ENV{TEST_VERBOSE}) { 8082 print STDERR "Executing sqlite3: $cmd\n"; 8083 } 8084 8085 my @output = `$cmd`; 8086 if (scalar(@output) && 8087 $ENV{TEST_VERBOSE}) { 8088 print STDERR "Output: ", join('', @output), "\n"; 8089 } 8090 8091 # This hex-encoded salt data has embedded NULs 8092 my $salt = lc('A7C082B325B2C835FF8A77D805006894AA1B0EC42559C6BD2CB82D7AA0FEAD2A'); 8093 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 8094 if (open(my $fh, "> $salt_file")) { 8095 binmode($fh); 8096 print $fh $salt; 8097 8098 unless (close($fh)) { 8099 die("Can't write $salt_file: $!"); 8100 } 8101 8102 } else { 8103 die("Can't open $salt_file: $!"); 8104 } 8105 8106 my $config = { 8107 PidFile => $pid_file, 8108 ScoreboardFile => $scoreboard_file, 8109 SystemLog => $log_file, 8110 TraceLog => $log_file, 8111 Trace => 'sql.passwd:20', 8112 8113 IfModules => { 8114 'mod_delay.c' => { 8115 DelayEngine => 'off', 8116 }, 8117 8118 'mod_sql.c' => { 8119 SQLAuthTypes => 'scrypt', 8120 SQLBackend => 'sqlite3', 8121 SQLConnectInfo => $db_file, 8122 SQLLogFile => $log_file, 8123 }, 8124 8125 'mod_sql_passwd.c' => { 8126 SQLPasswordEngine => 'on', 8127 SQLPasswordEncoding => 'HEX', 8128 SQLPasswordSaltEncoding => 'hex', 8129 SQLPasswordSaltFile => $salt_file, 8130 SQLPasswordCost => 'Sensitive', 8131 SQLPasswordScrypt => $scrypt_hash_len, 8132 }, 8133 }, 8134 }; 8135 8136 my ($port, $config_user, $config_group) = config_write($config_file, $config); 8137 8138 # Open pipes, for use between the parent and child processes. Specifically, 8139 # the child will indicate when it's done with its test by writing a message 8140 # to the parent. 8141 my ($rfh, $wfh); 8142 unless (pipe($rfh, $wfh)) { 8143 die("Can't open pipe: $!"); 8144 } 8145 8146 my $ex; 8147 8148 # Fork child 8149 $self->handle_sigchld(); 8150 defined(my $pid = fork()) or die("Can't fork: $!"); 8151 if ($pid) { 8152 eval { 8153 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 8154 $client->login($user, "test"); 8155 8156 my $resp_msgs = $client->response_msgs(); 8157 my $nmsgs = scalar(@$resp_msgs); 8158 8159 my $expected; 8160 8161 $expected = 1; 8162 $self->assert($expected == $nmsgs, 8163 test_msg("Expected response message count $expected, got $nmsgs")); 8164 8165 $expected = "User $user logged in"; 8166 $self->assert($expected eq $resp_msgs->[0], 8167 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 8168 }; 8169 8170 if ($@) { 8171 $ex = $@; 8172 } 8173 8174 $wfh->print("done\n"); 8175 $wfh->flush(); 8176 8177 } else { 8178 eval { server_wait($config_file, $rfh) }; 8179 if ($@) { 8180 warn($@); 8181 exit 1; 8182 } 8183 8184 exit 0; 8185 } 8186 8187 # Stop server 8188 server_stop($pid_file); 8189 8190 $self->assert_child_ok($pid); 8191 8192 if ($ex) { 8193 test_append_logfile($log_file, $ex); 8194 unlink($log_file); 8195 8196 die($ex); 8197 } 8198 8199 unlink($log_file); 8200} 8201 8202sub sql_passwd_argon2_base64_interactive_cost { 8203 my $self = shift; 8204 my $tmpdir = $self->{tmpdir}; 8205 8206 my $config_file = "$tmpdir/sqlpasswd.conf"; 8207 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 8208 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 8209 8210 my $log_file = test_get_logfile(); 8211 8212 my $user = 'proftpd'; 8213 my $group = 'ftpd'; 8214 8215 # I had to look at the mod_sql_passwd-generated logs to get this password; 8216 # this means it's a bit incestuous and thus suspect. 8217 my $passwd = 'CMEEQfxzMwu2y7YuG3R1r5n/qC0g24DXPRLb3ZpI6ZU='; 8218 8219 my $home_dir = File::Spec->rel2abs($tmpdir); 8220 my $uid = 500; 8221 my $gid = 500; 8222 8223 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 8224 8225 # Build up sqlite3 command to create users, groups tables and populate them 8226 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 8227 8228 if (open(my $fh, "> $db_script")) { 8229 print $fh <<EOS; 8230CREATE TABLE users ( 8231 userid TEXT, 8232 passwd TEXT, 8233 uid INTEGER, 8234 gid INTEGER, 8235 homedir TEXT, 8236 shell TEXT 8237); 8238INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 8239 8240CREATE TABLE groups ( 8241 groupname TEXT, 8242 gid INTEGER, 8243 members TEXT 8244); 8245INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 8246EOS 8247 8248 unless (close($fh)) { 8249 die("Can't write $db_script: $!"); 8250 } 8251 8252 } else { 8253 die("Can't open $db_script: $!"); 8254 } 8255 8256 my $cmd = "sqlite3 $db_file < $db_script"; 8257 8258 if ($ENV{TEST_VERBOSE}) { 8259 print STDERR "Executing sqlite3: $cmd\n"; 8260 } 8261 8262 my @output = `$cmd`; 8263 if (scalar(@output) && 8264 $ENV{TEST_VERBOSE}) { 8265 print STDERR "Output: ", join('', @output), "\n"; 8266 } 8267 8268 # This hex-encoded salt data has embedded NULs 8269 my $salt = 'A7C082B325B2C835FF8A77D805006894'; 8270 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 8271 if (open(my $fh, "> $salt_file")) { 8272 binmode($fh); 8273 print $fh $salt; 8274 8275 unless (close($fh)) { 8276 die("Can't write $salt_file: $!"); 8277 } 8278 8279 } else { 8280 die("Can't open $salt_file: $!"); 8281 } 8282 8283 my $config = { 8284 PidFile => $pid_file, 8285 ScoreboardFile => $scoreboard_file, 8286 SystemLog => $log_file, 8287 TraceLog => $log_file, 8288 Trace => 'sql.passwd:20', 8289 8290 IfModules => { 8291 'mod_delay.c' => { 8292 DelayEngine => 'off', 8293 }, 8294 8295 'mod_sql.c' => { 8296 SQLAuthTypes => 'argon2', 8297 SQLBackend => 'sqlite3', 8298 SQLConnectInfo => $db_file, 8299 SQLLogFile => $log_file, 8300 }, 8301 8302 'mod_sql_passwd.c' => { 8303 SQLPasswordEngine => 'on', 8304 SQLPasswordEncoding => 'base64', 8305 SQLPasswordSaltEncoding => 'HEX', 8306 SQLPasswordSaltFile => $salt_file, 8307 SQLPasswordCost => 'Interactive', 8308 }, 8309 }, 8310 }; 8311 8312 my ($port, $config_user, $config_group) = config_write($config_file, $config); 8313 8314 # Open pipes, for use between the parent and child processes. Specifically, 8315 # the child will indicate when it's done with its test by writing a message 8316 # to the parent. 8317 my ($rfh, $wfh); 8318 unless (pipe($rfh, $wfh)) { 8319 die("Can't open pipe: $!"); 8320 } 8321 8322 my $ex; 8323 8324 # Fork child 8325 $self->handle_sigchld(); 8326 defined(my $pid = fork()) or die("Can't fork: $!"); 8327 if ($pid) { 8328 eval { 8329 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 8330 $client->login($user, "test"); 8331 8332 my $resp_msgs = $client->response_msgs(); 8333 my $nmsgs = scalar(@$resp_msgs); 8334 8335 my $expected; 8336 8337 $expected = 1; 8338 $self->assert($expected == $nmsgs, 8339 test_msg("Expected response message count $expected, got $nmsgs")); 8340 8341 $expected = "User $user logged in"; 8342 $self->assert($expected eq $resp_msgs->[0], 8343 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 8344 }; 8345 8346 if ($@) { 8347 $ex = $@; 8348 } 8349 8350 $wfh->print("done\n"); 8351 $wfh->flush(); 8352 8353 } else { 8354 eval { server_wait($config_file, $rfh) }; 8355 if ($@) { 8356 warn($@); 8357 exit 1; 8358 } 8359 8360 exit 0; 8361 } 8362 8363 # Stop server 8364 server_stop($pid_file); 8365 8366 $self->assert_child_ok($pid); 8367 8368 if ($ex) { 8369 test_append_logfile($log_file, $ex); 8370 unlink($log_file); 8371 8372 die($ex); 8373 } 8374 8375 unlink($log_file); 8376} 8377 8378sub sql_passwd_argon2_hex_lc_interactive_cost { 8379 my $self = shift; 8380 my $tmpdir = $self->{tmpdir}; 8381 8382 my $config_file = "$tmpdir/sqlpasswd.conf"; 8383 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 8384 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 8385 8386 my $log_file = test_get_logfile(); 8387 8388 my $user = 'proftpd'; 8389 my $group = 'ftpd'; 8390 8391 # I had to look at the mod_sql_passwd-generated logs to get this password; 8392 # this means it's a bit incestuous and thus suspect. 8393 my $passwd = '08c10441fc73330bb6cbb62e1b7475af99ffa82d20db80d73d12dbdd9a48e995'; 8394 8395 my $home_dir = File::Spec->rel2abs($tmpdir); 8396 my $uid = 500; 8397 my $gid = 500; 8398 8399 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 8400 8401 # Build up sqlite3 command to create users, groups tables and populate them 8402 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 8403 8404 if (open(my $fh, "> $db_script")) { 8405 print $fh <<EOS; 8406CREATE TABLE users ( 8407 userid TEXT, 8408 passwd TEXT, 8409 uid INTEGER, 8410 gid INTEGER, 8411 homedir TEXT, 8412 shell TEXT 8413); 8414INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 8415 8416CREATE TABLE groups ( 8417 groupname TEXT, 8418 gid INTEGER, 8419 members TEXT 8420); 8421INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 8422EOS 8423 8424 unless (close($fh)) { 8425 die("Can't write $db_script: $!"); 8426 } 8427 8428 } else { 8429 die("Can't open $db_script: $!"); 8430 } 8431 8432 my $cmd = "sqlite3 $db_file < $db_script"; 8433 8434 if ($ENV{TEST_VERBOSE}) { 8435 print STDERR "Executing sqlite3: $cmd\n"; 8436 } 8437 8438 my @output = `$cmd`; 8439 if (scalar(@output) && 8440 $ENV{TEST_VERBOSE}) { 8441 print STDERR "Output: ", join('', @output), "\n"; 8442 } 8443 8444 # This hex-encoded salt data has embedded NULs 8445 my $salt = lc('A7C082B325B2C835FF8A77D805006894'); 8446 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 8447 if (open(my $fh, "> $salt_file")) { 8448 binmode($fh); 8449 print $fh $salt; 8450 8451 unless (close($fh)) { 8452 die("Can't write $salt_file: $!"); 8453 } 8454 8455 } else { 8456 die("Can't open $salt_file: $!"); 8457 } 8458 8459 my $config = { 8460 PidFile => $pid_file, 8461 ScoreboardFile => $scoreboard_file, 8462 SystemLog => $log_file, 8463 TraceLog => $log_file, 8464 Trace => 'sql.passwd:20', 8465 8466 IfModules => { 8467 'mod_delay.c' => { 8468 DelayEngine => 'off', 8469 }, 8470 8471 'mod_sql.c' => { 8472 SQLAuthTypes => 'argon2', 8473 SQLBackend => 'sqlite3', 8474 SQLConnectInfo => $db_file, 8475 SQLLogFile => $log_file, 8476 }, 8477 8478 'mod_sql_passwd.c' => { 8479 SQLPasswordEngine => 'on', 8480 SQLPasswordEncoding => 'hex', 8481 SQLPasswordSaltEncoding => 'hex', 8482 SQLPasswordSaltFile => $salt_file, 8483 SQLPasswordCost => 'Interactive', 8484 }, 8485 }, 8486 }; 8487 8488 my ($port, $config_user, $config_group) = config_write($config_file, $config); 8489 8490 # Open pipes, for use between the parent and child processes. Specifically, 8491 # the child will indicate when it's done with its test by writing a message 8492 # to the parent. 8493 my ($rfh, $wfh); 8494 unless (pipe($rfh, $wfh)) { 8495 die("Can't open pipe: $!"); 8496 } 8497 8498 my $ex; 8499 8500 # Fork child 8501 $self->handle_sigchld(); 8502 defined(my $pid = fork()) or die("Can't fork: $!"); 8503 if ($pid) { 8504 eval { 8505 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 8506 $client->login($user, "test"); 8507 8508 my $resp_msgs = $client->response_msgs(); 8509 my $nmsgs = scalar(@$resp_msgs); 8510 8511 my $expected; 8512 8513 $expected = 1; 8514 $self->assert($expected == $nmsgs, 8515 test_msg("Expected response message count $expected, got $nmsgs")); 8516 8517 $expected = "User $user logged in"; 8518 $self->assert($expected eq $resp_msgs->[0], 8519 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 8520 }; 8521 8522 if ($@) { 8523 $ex = $@; 8524 } 8525 8526 $wfh->print("done\n"); 8527 $wfh->flush(); 8528 8529 } else { 8530 eval { server_wait($config_file, $rfh) }; 8531 if ($@) { 8532 warn($@); 8533 exit 1; 8534 } 8535 8536 exit 0; 8537 } 8538 8539 # Stop server 8540 server_stop($pid_file); 8541 8542 $self->assert_child_ok($pid); 8543 8544 if ($ex) { 8545 test_append_logfile($log_file, $ex); 8546 unlink($log_file); 8547 8548 die($ex); 8549 } 8550 8551 unlink($log_file); 8552} 8553 8554sub sql_passwd_argon2_hex_uc_interactive_cost { 8555 my $self = shift; 8556 my $tmpdir = $self->{tmpdir}; 8557 8558 my $config_file = "$tmpdir/sqlpasswd.conf"; 8559 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 8560 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 8561 8562 my $log_file = test_get_logfile(); 8563 8564 my $user = 'proftpd'; 8565 my $group = 'ftpd'; 8566 8567 # I had to look at the mod_sql_passwd-generated logs to get this password; 8568 # this means it's a bit incestuous and thus suspect. 8569 my $passwd = uc('08c10441fc73330bb6cbb62e1b7475af99ffa82d20db80d73d12dbdd9a48e995'); 8570 8571 my $home_dir = File::Spec->rel2abs($tmpdir); 8572 my $uid = 500; 8573 my $gid = 500; 8574 8575 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 8576 8577 # Build up sqlite3 command to create users, groups tables and populate them 8578 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 8579 8580 if (open(my $fh, "> $db_script")) { 8581 print $fh <<EOS; 8582CREATE TABLE users ( 8583 userid TEXT, 8584 passwd TEXT, 8585 uid INTEGER, 8586 gid INTEGER, 8587 homedir TEXT, 8588 shell TEXT 8589); 8590INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 8591 8592CREATE TABLE groups ( 8593 groupname TEXT, 8594 gid INTEGER, 8595 members TEXT 8596); 8597INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 8598EOS 8599 8600 unless (close($fh)) { 8601 die("Can't write $db_script: $!"); 8602 } 8603 8604 } else { 8605 die("Can't open $db_script: $!"); 8606 } 8607 8608 my $cmd = "sqlite3 $db_file < $db_script"; 8609 8610 if ($ENV{TEST_VERBOSE}) { 8611 print STDERR "Executing sqlite3: $cmd\n"; 8612 } 8613 8614 my @output = `$cmd`; 8615 if (scalar(@output) && 8616 $ENV{TEST_VERBOSE}) { 8617 print STDERR "Output: ", join('', @output), "\n"; 8618 } 8619 8620 # This hex-encoded salt data has embedded NULs 8621 my $salt = lc('A7C082B325B2C835FF8A77D805006894'); 8622 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 8623 if (open(my $fh, "> $salt_file")) { 8624 binmode($fh); 8625 print $fh $salt; 8626 8627 unless (close($fh)) { 8628 die("Can't write $salt_file: $!"); 8629 } 8630 8631 } else { 8632 die("Can't open $salt_file: $!"); 8633 } 8634 8635 my $config = { 8636 PidFile => $pid_file, 8637 ScoreboardFile => $scoreboard_file, 8638 SystemLog => $log_file, 8639 TraceLog => $log_file, 8640 Trace => 'sql.passwd:20', 8641 8642 IfModules => { 8643 'mod_delay.c' => { 8644 DelayEngine => 'off', 8645 }, 8646 8647 'mod_sql.c' => { 8648 SQLAuthTypes => 'argon2', 8649 SQLBackend => 'sqlite3', 8650 SQLConnectInfo => $db_file, 8651 SQLLogFile => $log_file, 8652 }, 8653 8654 'mod_sql_passwd.c' => { 8655 SQLPasswordEngine => 'on', 8656 SQLPasswordEncoding => 'HEX', 8657 SQLPasswordSaltEncoding => 'hex', 8658 SQLPasswordSaltFile => $salt_file, 8659 SQLPasswordCost => 'Interactive', 8660 }, 8661 }, 8662 }; 8663 8664 my ($port, $config_user, $config_group) = config_write($config_file, $config); 8665 8666 # Open pipes, for use between the parent and child processes. Specifically, 8667 # the child will indicate when it's done with its test by writing a message 8668 # to the parent. 8669 my ($rfh, $wfh); 8670 unless (pipe($rfh, $wfh)) { 8671 die("Can't open pipe: $!"); 8672 } 8673 8674 my $ex; 8675 8676 # Fork child 8677 $self->handle_sigchld(); 8678 defined(my $pid = fork()) or die("Can't fork: $!"); 8679 if ($pid) { 8680 eval { 8681 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 8682 $client->login($user, "test"); 8683 8684 my $resp_msgs = $client->response_msgs(); 8685 my $nmsgs = scalar(@$resp_msgs); 8686 8687 my $expected; 8688 8689 $expected = 1; 8690 $self->assert($expected == $nmsgs, 8691 test_msg("Expected response message count $expected, got $nmsgs")); 8692 8693 $expected = "User $user logged in"; 8694 $self->assert($expected eq $resp_msgs->[0], 8695 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 8696 }; 8697 8698 if ($@) { 8699 $ex = $@; 8700 } 8701 8702 $wfh->print("done\n"); 8703 $wfh->flush(); 8704 8705 } else { 8706 eval { server_wait($config_file, $rfh) }; 8707 if ($@) { 8708 warn($@); 8709 exit 1; 8710 } 8711 8712 exit 0; 8713 } 8714 8715 # Stop server 8716 server_stop($pid_file); 8717 8718 $self->assert_child_ok($pid); 8719 8720 if ($ex) { 8721 test_append_logfile($log_file, $ex); 8722 unlink($log_file); 8723 8724 die($ex); 8725 } 8726 8727 unlink($log_file); 8728} 8729 8730sub sql_passwd_argon2_base64_sensitive_cost { 8731 my $self = shift; 8732 my $tmpdir = $self->{tmpdir}; 8733 8734 my $config_file = "$tmpdir/sqlpasswd.conf"; 8735 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 8736 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 8737 8738 my $log_file = test_get_logfile(); 8739 8740 my $user = 'proftpd'; 8741 my $group = 'ftpd'; 8742 8743 # I had to look at the mod_sql_passwd-generated logs to get this password; 8744 # this means it's a bit incestuous and thus suspect. 8745 my $passwd = '6dZPscXkBbvrcU7FcLTuhKMqpjLlHItzRkLuic95h0k='; 8746 8747 my $home_dir = File::Spec->rel2abs($tmpdir); 8748 my $uid = 500; 8749 my $gid = 500; 8750 8751 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 8752 8753 # Build up sqlite3 command to create users, groups tables and populate them 8754 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 8755 8756 if (open(my $fh, "> $db_script")) { 8757 print $fh <<EOS; 8758CREATE TABLE users ( 8759 userid TEXT, 8760 passwd TEXT, 8761 uid INTEGER, 8762 gid INTEGER, 8763 homedir TEXT, 8764 shell TEXT 8765); 8766INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 8767 8768CREATE TABLE groups ( 8769 groupname TEXT, 8770 gid INTEGER, 8771 members TEXT 8772); 8773INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 8774EOS 8775 8776 unless (close($fh)) { 8777 die("Can't write $db_script: $!"); 8778 } 8779 8780 } else { 8781 die("Can't open $db_script: $!"); 8782 } 8783 8784 my $cmd = "sqlite3 $db_file < $db_script"; 8785 8786 if ($ENV{TEST_VERBOSE}) { 8787 print STDERR "Executing sqlite3: $cmd\n"; 8788 } 8789 8790 my @output = `$cmd`; 8791 if (scalar(@output) && 8792 $ENV{TEST_VERBOSE}) { 8793 print STDERR "Output: ", join('', @output), "\n"; 8794 } 8795 8796 # This hex-encoded salt data has embedded NULs 8797 my $salt = 'A7C082B325B2C835FF8A77D805006894'; 8798 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 8799 if (open(my $fh, "> $salt_file")) { 8800 binmode($fh); 8801 print $fh $salt; 8802 8803 unless (close($fh)) { 8804 die("Can't write $salt_file: $!"); 8805 } 8806 8807 } else { 8808 die("Can't open $salt_file: $!"); 8809 } 8810 8811 my $config = { 8812 PidFile => $pid_file, 8813 ScoreboardFile => $scoreboard_file, 8814 SystemLog => $log_file, 8815 TraceLog => $log_file, 8816 Trace => 'sql.passwd:20', 8817 8818 IfModules => { 8819 'mod_delay.c' => { 8820 DelayEngine => 'off', 8821 }, 8822 8823 'mod_sql.c' => { 8824 SQLAuthTypes => 'argon2', 8825 SQLBackend => 'sqlite3', 8826 SQLConnectInfo => $db_file, 8827 SQLLogFile => $log_file, 8828 }, 8829 8830 'mod_sql_passwd.c' => { 8831 SQLPasswordEngine => 'on', 8832 SQLPasswordEncoding => 'base64', 8833 SQLPasswordSaltEncoding => 'HEX', 8834 SQLPasswordSaltFile => $salt_file, 8835 SQLPasswordCost => 'Sensitive', 8836 }, 8837 }, 8838 }; 8839 8840 my ($port, $config_user, $config_group) = config_write($config_file, $config); 8841 8842 # Open pipes, for use between the parent and child processes. Specifically, 8843 # the child will indicate when it's done with its test by writing a message 8844 # to the parent. 8845 my ($rfh, $wfh); 8846 unless (pipe($rfh, $wfh)) { 8847 die("Can't open pipe: $!"); 8848 } 8849 8850 my $ex; 8851 8852 # Fork child 8853 $self->handle_sigchld(); 8854 defined(my $pid = fork()) or die("Can't fork: $!"); 8855 if ($pid) { 8856 eval { 8857 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 8858 $client->login($user, "test"); 8859 8860 my $resp_msgs = $client->response_msgs(); 8861 my $nmsgs = scalar(@$resp_msgs); 8862 8863 my $expected; 8864 8865 $expected = 1; 8866 $self->assert($expected == $nmsgs, 8867 test_msg("Expected response message count $expected, got $nmsgs")); 8868 8869 $expected = "User $user logged in"; 8870 $self->assert($expected eq $resp_msgs->[0], 8871 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 8872 }; 8873 8874 if ($@) { 8875 $ex = $@; 8876 } 8877 8878 $wfh->print("done\n"); 8879 $wfh->flush(); 8880 8881 } else { 8882 eval { server_wait($config_file, $rfh) }; 8883 if ($@) { 8884 warn($@); 8885 exit 1; 8886 } 8887 8888 exit 0; 8889 } 8890 8891 # Stop server 8892 server_stop($pid_file); 8893 8894 $self->assert_child_ok($pid); 8895 8896 if ($ex) { 8897 test_append_logfile($log_file, $ex); 8898 unlink($log_file); 8899 8900 die($ex); 8901 } 8902 8903 unlink($log_file); 8904} 8905 8906sub sql_passwd_argon2_hex_lc_sensitive_cost { 8907 my $self = shift; 8908 my $tmpdir = $self->{tmpdir}; 8909 8910 my $config_file = "$tmpdir/sqlpasswd.conf"; 8911 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 8912 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 8913 8914 my $log_file = test_get_logfile(); 8915 8916 my $user = 'proftpd'; 8917 my $group = 'ftpd'; 8918 8919 # I had to look at the mod_sql_passwd-generated logs to get this password; 8920 # this means it's a bit incestuous and thus suspect. 8921 my $passwd = 'e9d64fb1c5e405bbeb714ec570b4ee84a32aa632e51c8b734642ee89cf798749'; 8922 8923 my $home_dir = File::Spec->rel2abs($tmpdir); 8924 my $uid = 500; 8925 my $gid = 500; 8926 8927 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 8928 8929 # Build up sqlite3 command to create users, groups tables and populate them 8930 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 8931 8932 if (open(my $fh, "> $db_script")) { 8933 print $fh <<EOS; 8934CREATE TABLE users ( 8935 userid TEXT, 8936 passwd TEXT, 8937 uid INTEGER, 8938 gid INTEGER, 8939 homedir TEXT, 8940 shell TEXT 8941); 8942INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 8943 8944CREATE TABLE groups ( 8945 groupname TEXT, 8946 gid INTEGER, 8947 members TEXT 8948); 8949INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 8950EOS 8951 8952 unless (close($fh)) { 8953 die("Can't write $db_script: $!"); 8954 } 8955 8956 } else { 8957 die("Can't open $db_script: $!"); 8958 } 8959 8960 my $cmd = "sqlite3 $db_file < $db_script"; 8961 8962 if ($ENV{TEST_VERBOSE}) { 8963 print STDERR "Executing sqlite3: $cmd\n"; 8964 } 8965 8966 my @output = `$cmd`; 8967 if (scalar(@output) && 8968 $ENV{TEST_VERBOSE}) { 8969 print STDERR "Output: ", join('', @output), "\n"; 8970 } 8971 8972 # This hex-encoded salt data has embedded NULs 8973 my $salt = lc('A7C082B325B2C835FF8A77D805006894'); 8974 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 8975 if (open(my $fh, "> $salt_file")) { 8976 binmode($fh); 8977 print $fh $salt; 8978 8979 unless (close($fh)) { 8980 die("Can't write $salt_file: $!"); 8981 } 8982 8983 } else { 8984 die("Can't open $salt_file: $!"); 8985 } 8986 8987 my $config = { 8988 PidFile => $pid_file, 8989 ScoreboardFile => $scoreboard_file, 8990 SystemLog => $log_file, 8991 TraceLog => $log_file, 8992 Trace => 'sql.passwd:20', 8993 8994 IfModules => { 8995 'mod_delay.c' => { 8996 DelayEngine => 'off', 8997 }, 8998 8999 'mod_sql.c' => { 9000 SQLAuthTypes => 'argon2', 9001 SQLBackend => 'sqlite3', 9002 SQLConnectInfo => $db_file, 9003 SQLLogFile => $log_file, 9004 }, 9005 9006 'mod_sql_passwd.c' => { 9007 SQLPasswordEngine => 'on', 9008 SQLPasswordEncoding => 'hex', 9009 SQLPasswordSaltEncoding => 'hex', 9010 SQLPasswordSaltFile => $salt_file, 9011 SQLPasswordCost => 'Sensitive', 9012 }, 9013 }, 9014 }; 9015 9016 my ($port, $config_user, $config_group) = config_write($config_file, $config); 9017 9018 # Open pipes, for use between the parent and child processes. Specifically, 9019 # the child will indicate when it's done with its test by writing a message 9020 # to the parent. 9021 my ($rfh, $wfh); 9022 unless (pipe($rfh, $wfh)) { 9023 die("Can't open pipe: $!"); 9024 } 9025 9026 my $ex; 9027 9028 # Fork child 9029 $self->handle_sigchld(); 9030 defined(my $pid = fork()) or die("Can't fork: $!"); 9031 if ($pid) { 9032 eval { 9033 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 9034 $client->login($user, "test"); 9035 9036 my $resp_msgs = $client->response_msgs(); 9037 my $nmsgs = scalar(@$resp_msgs); 9038 9039 my $expected; 9040 9041 $expected = 1; 9042 $self->assert($expected == $nmsgs, 9043 test_msg("Expected response message count $expected, got $nmsgs")); 9044 9045 $expected = "User $user logged in"; 9046 $self->assert($expected eq $resp_msgs->[0], 9047 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 9048 }; 9049 9050 if ($@) { 9051 $ex = $@; 9052 } 9053 9054 $wfh->print("done\n"); 9055 $wfh->flush(); 9056 9057 } else { 9058 eval { server_wait($config_file, $rfh) }; 9059 if ($@) { 9060 warn($@); 9061 exit 1; 9062 } 9063 9064 exit 0; 9065 } 9066 9067 # Stop server 9068 server_stop($pid_file); 9069 9070 $self->assert_child_ok($pid); 9071 9072 if ($ex) { 9073 test_append_logfile($log_file, $ex); 9074 unlink($log_file); 9075 9076 die($ex); 9077 } 9078 9079 unlink($log_file); 9080} 9081 9082sub sql_passwd_argon2_hex_uc_sensitive_cost { 9083 my $self = shift; 9084 my $tmpdir = $self->{tmpdir}; 9085 9086 my $config_file = "$tmpdir/sqlpasswd.conf"; 9087 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 9088 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 9089 9090 my $log_file = test_get_logfile(); 9091 9092 my $user = 'proftpd'; 9093 my $group = 'ftpd'; 9094 9095 # I had to look at the mod_sql_passwd-generated logs to get this password; 9096 # this means it's a bit incestuous and thus suspect. 9097 my $passwd = uc('e9d64fb1c5e405bbeb714ec570b4ee84a32aa632e51c8b734642ee89cf798749'); 9098 9099 my $home_dir = File::Spec->rel2abs($tmpdir); 9100 my $uid = 500; 9101 my $gid = 500; 9102 9103 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 9104 9105 # Build up sqlite3 command to create users, groups tables and populate them 9106 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 9107 9108 if (open(my $fh, "> $db_script")) { 9109 print $fh <<EOS; 9110CREATE TABLE users ( 9111 userid TEXT, 9112 passwd TEXT, 9113 uid INTEGER, 9114 gid INTEGER, 9115 homedir TEXT, 9116 shell TEXT 9117); 9118INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 9119 9120CREATE TABLE groups ( 9121 groupname TEXT, 9122 gid INTEGER, 9123 members TEXT 9124); 9125INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 9126EOS 9127 9128 unless (close($fh)) { 9129 die("Can't write $db_script: $!"); 9130 } 9131 9132 } else { 9133 die("Can't open $db_script: $!"); 9134 } 9135 9136 my $cmd = "sqlite3 $db_file < $db_script"; 9137 9138 if ($ENV{TEST_VERBOSE}) { 9139 print STDERR "Executing sqlite3: $cmd\n"; 9140 } 9141 9142 my @output = `$cmd`; 9143 if (scalar(@output) && 9144 $ENV{TEST_VERBOSE}) { 9145 print STDERR "Output: ", join('', @output), "\n"; 9146 } 9147 9148 # This hex-encoded salt data has embedded NULs 9149 my $salt = 'A7C082B325B2C835FF8A77D805006894'; 9150 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 9151 if (open(my $fh, "> $salt_file")) { 9152 binmode($fh); 9153 print $fh $salt; 9154 9155 unless (close($fh)) { 9156 die("Can't write $salt_file: $!"); 9157 } 9158 9159 } else { 9160 die("Can't open $salt_file: $!"); 9161 } 9162 9163 my $config = { 9164 PidFile => $pid_file, 9165 ScoreboardFile => $scoreboard_file, 9166 SystemLog => $log_file, 9167 TraceLog => $log_file, 9168 Trace => 'sql.passwd:20', 9169 9170 IfModules => { 9171 'mod_delay.c' => { 9172 DelayEngine => 'off', 9173 }, 9174 9175 'mod_sql.c' => { 9176 SQLAuthTypes => 'argon2', 9177 SQLBackend => 'sqlite3', 9178 SQLConnectInfo => $db_file, 9179 SQLLogFile => $log_file, 9180 }, 9181 9182 'mod_sql_passwd.c' => { 9183 SQLPasswordEngine => 'on', 9184 SQLPasswordEncoding => 'HEX', 9185 SQLPasswordSaltEncoding => 'HEX', 9186 SQLPasswordSaltFile => $salt_file, 9187 SQLPasswordCost => 'Sensitive', 9188 }, 9189 }, 9190 }; 9191 9192 my ($port, $config_user, $config_group) = config_write($config_file, $config); 9193 9194 # Open pipes, for use between the parent and child processes. Specifically, 9195 # the child will indicate when it's done with its test by writing a message 9196 # to the parent. 9197 my ($rfh, $wfh); 9198 unless (pipe($rfh, $wfh)) { 9199 die("Can't open pipe: $!"); 9200 } 9201 9202 my $ex; 9203 9204 # Fork child 9205 $self->handle_sigchld(); 9206 defined(my $pid = fork()) or die("Can't fork: $!"); 9207 if ($pid) { 9208 eval { 9209 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 9210 $client->login($user, "test"); 9211 9212 my $resp_msgs = $client->response_msgs(); 9213 my $nmsgs = scalar(@$resp_msgs); 9214 9215 my $expected; 9216 9217 $expected = 1; 9218 $self->assert($expected == $nmsgs, 9219 test_msg("Expected response message count $expected, got $nmsgs")); 9220 9221 $expected = "User $user logged in"; 9222 $self->assert($expected eq $resp_msgs->[0], 9223 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 9224 }; 9225 9226 if ($@) { 9227 $ex = $@; 9228 } 9229 9230 $wfh->print("done\n"); 9231 $wfh->flush(); 9232 9233 } else { 9234 eval { server_wait($config_file, $rfh) }; 9235 if ($@) { 9236 warn($@); 9237 exit 1; 9238 } 9239 9240 exit 0; 9241 } 9242 9243 # Stop server 9244 server_stop($pid_file); 9245 9246 $self->assert_child_ok($pid); 9247 9248 if ($ex) { 9249 test_append_logfile($log_file, $ex); 9250 unlink($log_file); 9251 9252 die($ex); 9253 } 9254 9255 unlink($log_file); 9256} 9257 9258sub sql_passwd_argon2_hex_uc_sensitive_cost_len_64 { 9259 my $self = shift; 9260 my $tmpdir = $self->{tmpdir}; 9261 9262 my $config_file = "$tmpdir/sqlpasswd.conf"; 9263 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid"); 9264 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard"); 9265 9266 my $log_file = test_get_logfile(); 9267 9268 my $user = 'proftpd'; 9269 my $group = 'ftpd'; 9270 9271 my $argon2_hash_len = 64; 9272 9273 # I had to look at the mod_sql_passwd-generated logs to get this password; 9274 # this means it's a bit incestuous and thus suspect. 9275 my $passwd = uc('c7d9ca94cc8631322c30b8c39d8b9ba3350873a81acea38771e5ede737625a99bc904b33c8fd53cb314147cba409fe21fccf9f6bbb04f775f01076d2188a7dae'); 9276 9277 my $home_dir = File::Spec->rel2abs($tmpdir); 9278 my $uid = 500; 9279 my $gid = 500; 9280 9281 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 9282 9283 # Build up sqlite3 command to create users, groups tables and populate them 9284 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 9285 9286 if (open(my $fh, "> $db_script")) { 9287 print $fh <<EOS; 9288CREATE TABLE users ( 9289 userid TEXT, 9290 passwd TEXT, 9291 uid INTEGER, 9292 gid INTEGER, 9293 homedir TEXT, 9294 shell TEXT 9295); 9296INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 9297 9298CREATE TABLE groups ( 9299 groupname TEXT, 9300 gid INTEGER, 9301 members TEXT 9302); 9303INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 9304EOS 9305 9306 unless (close($fh)) { 9307 die("Can't write $db_script: $!"); 9308 } 9309 9310 } else { 9311 die("Can't open $db_script: $!"); 9312 } 9313 9314 my $cmd = "sqlite3 $db_file < $db_script"; 9315 9316 if ($ENV{TEST_VERBOSE}) { 9317 print STDERR "Executing sqlite3: $cmd\n"; 9318 } 9319 9320 my @output = `$cmd`; 9321 if (scalar(@output) && 9322 $ENV{TEST_VERBOSE}) { 9323 print STDERR "Output: ", join('', @output), "\n"; 9324 } 9325 9326 # This hex-encoded salt data has embedded NULs 9327 my $salt = 'A7C082B325B2C835FF8A77D805006894'; 9328 my $salt_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.salt"); 9329 if (open(my $fh, "> $salt_file")) { 9330 binmode($fh); 9331 print $fh $salt; 9332 9333 unless (close($fh)) { 9334 die("Can't write $salt_file: $!"); 9335 } 9336 9337 } else { 9338 die("Can't open $salt_file: $!"); 9339 } 9340 9341 my $config = { 9342 PidFile => $pid_file, 9343 ScoreboardFile => $scoreboard_file, 9344 SystemLog => $log_file, 9345 TraceLog => $log_file, 9346 Trace => 'sql.passwd:20', 9347 9348 IfModules => { 9349 'mod_delay.c' => { 9350 DelayEngine => 'off', 9351 }, 9352 9353 'mod_sql.c' => { 9354 SQLAuthTypes => 'argon2', 9355 SQLBackend => 'sqlite3', 9356 SQLConnectInfo => $db_file, 9357 SQLLogFile => $log_file, 9358 }, 9359 9360 'mod_sql_passwd.c' => { 9361 SQLPasswordEngine => 'on', 9362 SQLPasswordEncoding => 'HEX', 9363 SQLPasswordSaltEncoding => 'HEX', 9364 SQLPasswordSaltFile => $salt_file, 9365 SQLPasswordCost => 'Sensitive', 9366 SQLPasswordArgon2 => $argon2_hash_len, 9367 }, 9368 }, 9369 }; 9370 9371 my ($port, $config_user, $config_group) = config_write($config_file, $config); 9372 9373 # Open pipes, for use between the parent and child processes. Specifically, 9374 # the child will indicate when it's done with its test by writing a message 9375 # to the parent. 9376 my ($rfh, $wfh); 9377 unless (pipe($rfh, $wfh)) { 9378 die("Can't open pipe: $!"); 9379 } 9380 9381 my $ex; 9382 9383 # Fork child 9384 $self->handle_sigchld(); 9385 defined(my $pid = fork()) or die("Can't fork: $!"); 9386 if ($pid) { 9387 eval { 9388 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 9389 $client->login($user, "test"); 9390 9391 my $resp_msgs = $client->response_msgs(); 9392 my $nmsgs = scalar(@$resp_msgs); 9393 9394 my $expected; 9395 9396 $expected = 1; 9397 $self->assert($expected == $nmsgs, 9398 test_msg("Expected response message count $expected, got $nmsgs")); 9399 9400 $expected = "User $user logged in"; 9401 $self->assert($expected eq $resp_msgs->[0], 9402 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 9403 }; 9404 9405 if ($@) { 9406 $ex = $@; 9407 } 9408 9409 $wfh->print("done\n"); 9410 $wfh->flush(); 9411 9412 } else { 9413 eval { server_wait($config_file, $rfh) }; 9414 if ($@) { 9415 warn($@); 9416 exit 1; 9417 } 9418 9419 exit 0; 9420 } 9421 9422 # Stop server 9423 server_stop($pid_file); 9424 9425 $self->assert_child_ok($pid); 9426 9427 if ($ex) { 9428 test_append_logfile($log_file, $ex); 9429 unlink($log_file); 9430 9431 die($ex); 9432 } 9433 9434 unlink($log_file); 9435} 9436 9437sub sql_passwd_bcrypt { 9438 my $self = shift; 9439 my $tmpdir = $self->{tmpdir}; 9440 9441 # I used the bcrypt Python module to generate this password: 9442 # 9443 # $ cat passwd.py 9444 # import bcrypt 9445 # password = b"password" 9446 # hashed = bcrypt.hashpw(password, bcrypt.gensalt()) 9447 # print("hash for password '" + str(password) + ": " + str(hashed)) 9448 my $passwd = '$2b$12$IoFxXvbRQUKssPqFacJFFuZl1KXl5ULppqf0aLFjwCFnLRh3NbYSG'; 9449 9450 my $setup = test_setup($tmpdir, 'sql_passwd', undef, $passwd); 9451 9452 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 9453 9454 # Build up sqlite3 command to create users, groups tables and populate them 9455 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 9456 9457 if (open(my $fh, "> $db_script")) { 9458 print $fh <<EOS; 9459CREATE TABLE users ( 9460 userid TEXT, 9461 passwd TEXT, 9462 uid INTEGER, 9463 gid INTEGER, 9464 homedir TEXT, 9465 shell TEXT 9466); 9467INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$setup->{user}', '$passwd', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash'); 9468 9469CREATE TABLE groups ( 9470 groupname TEXT, 9471 gid INTEGER, 9472 members TEXT 9473); 9474INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); 9475EOS 9476 9477 unless (close($fh)) { 9478 die("Can't write $db_script: $!"); 9479 } 9480 9481 } else { 9482 die("Can't open $db_script: $!"); 9483 } 9484 9485 my $cmd = "sqlite3 $db_file < $db_script"; 9486 9487 if ($ENV{TEST_VERBOSE}) { 9488 print STDERR "Executing sqlite3: $cmd\n"; 9489 } 9490 9491 my @output = `$cmd`; 9492 if (scalar(@output) && 9493 $ENV{TEST_VERBOSE}) { 9494 print STDERR "Output: ", join('', @output), "\n"; 9495 } 9496 9497 my $config = { 9498 PidFile => $setup->{pid_file}, 9499 ScoreboardFile => $setup->{scoreboard_file}, 9500 SystemLog => $setup->{log_file}, 9501 9502 IfModules => { 9503 'mod_delay.c' => { 9504 DelayEngine => 'off', 9505 }, 9506 9507 'mod_sql.c' => { 9508 SQLAuthTypes => 'bcrypt', 9509 SQLBackend => 'sqlite3', 9510 SQLConnectInfo => $db_file, 9511 SQLLogFile => $setup->{log_file}, 9512 }, 9513 9514 'mod_sql_passwd.c' => { 9515 SQLPasswordEngine => 'on', 9516 SQLPasswordEncoding => 'base64', 9517 }, 9518 }, 9519 }; 9520 9521 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 9522 $config); 9523 9524 # Open pipes, for use between the parent and child processes. Specifically, 9525 # the child will indicate when it's done with its test by writing a message 9526 # to the parent. 9527 my ($rfh, $wfh); 9528 unless (pipe($rfh, $wfh)) { 9529 die("Can't open pipe: $!"); 9530 } 9531 9532 my $ex; 9533 9534 # Fork child 9535 $self->handle_sigchld(); 9536 defined(my $pid = fork()) or die("Can't fork: $!"); 9537 if ($pid) { 9538 eval { 9539 sleep(1); 9540 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 9541 $client->login($setup->{user}, "password"); 9542 9543 my $resp_msgs = $client->response_msgs(); 9544 my $nmsgs = scalar(@$resp_msgs); 9545 9546 my $expected = 1; 9547 $self->assert($expected == $nmsgs, 9548 test_msg("Expected $expected, got $nmsgs")); 9549 9550 $expected = "User $setup->{user} logged in"; 9551 $self->assert($expected eq $resp_msgs->[0], 9552 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 9553 }; 9554 if ($@) { 9555 $ex = $@; 9556 } 9557 9558 $wfh->print("done\n"); 9559 $wfh->flush(); 9560 9561 } else { 9562 eval { server_wait($setup->{config_file}, $rfh) }; 9563 if ($@) { 9564 warn($@); 9565 exit 1; 9566 } 9567 9568 exit 0; 9569 } 9570 9571 # Stop server 9572 server_stop($setup->{pid_file}); 9573 $self->assert_child_ok($pid); 9574 9575 test_cleanup($setup->{log_file}, $ex); 9576} 9577 9578sub sql_passwd_bcrypt_php_variant { 9579 my $self = shift; 9580 my $tmpdir = $self->{tmpdir}; 9581 9582 my $passwd = '$2y$14$r5BQoR3rAFQGnOEh73QrOOIsQJPjIYVF76IitsqqA7ix51SE/llCG'; 9583 9584 my $setup = test_setup($tmpdir, 'sql_passwd', undef, $passwd); 9585 9586 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 9587 9588 # Build up sqlite3 command to create users, groups tables and populate them 9589 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 9590 9591 if (open(my $fh, "> $db_script")) { 9592 print $fh <<EOS; 9593CREATE TABLE users ( 9594 userid TEXT, 9595 passwd TEXT, 9596 uid INTEGER, 9597 gid INTEGER, 9598 homedir TEXT, 9599 shell TEXT 9600); 9601INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$setup->{user}', '$passwd', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash'); 9602 9603CREATE TABLE groups ( 9604 groupname TEXT, 9605 gid INTEGER, 9606 members TEXT 9607); 9608INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); 9609EOS 9610 9611 unless (close($fh)) { 9612 die("Can't write $db_script: $!"); 9613 } 9614 9615 } else { 9616 die("Can't open $db_script: $!"); 9617 } 9618 9619 my $cmd = "sqlite3 $db_file < $db_script"; 9620 9621 if ($ENV{TEST_VERBOSE}) { 9622 print STDERR "Executing sqlite3: $cmd\n"; 9623 } 9624 9625 my @output = `$cmd`; 9626 if (scalar(@output) && 9627 $ENV{TEST_VERBOSE}) { 9628 print STDERR "Output: ", join('', @output), "\n"; 9629 } 9630 9631 my $config = { 9632 PidFile => $setup->{pid_file}, 9633 ScoreboardFile => $setup->{scoreboard_file}, 9634 SystemLog => $setup->{log_file}, 9635 9636 IfModules => { 9637 'mod_delay.c' => { 9638 DelayEngine => 'off', 9639 }, 9640 9641 'mod_sql.c' => { 9642 SQLAuthTypes => 'bcrypt', 9643 SQLBackend => 'sqlite3', 9644 SQLConnectInfo => $db_file, 9645 SQLLogFile => $setup->{log_file}, 9646 }, 9647 9648 'mod_sql_passwd.c' => { 9649 SQLPasswordEngine => 'on', 9650 SQLPasswordEncoding => 'base64', 9651 }, 9652 }, 9653 }; 9654 9655 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 9656 $config); 9657 9658 # Open pipes, for use between the parent and child processes. Specifically, 9659 # the child will indicate when it's done with its test by writing a message 9660 # to the parent. 9661 my ($rfh, $wfh); 9662 unless (pipe($rfh, $wfh)) { 9663 die("Can't open pipe: $!"); 9664 } 9665 9666 my $ex; 9667 9668 # Fork child 9669 $self->handle_sigchld(); 9670 defined(my $pid = fork()) or die("Can't fork: $!"); 9671 if ($pid) { 9672 eval { 9673 sleep(1); 9674 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 9675 $client->login($setup->{user}, "password"); 9676 9677 my $resp_msgs = $client->response_msgs(); 9678 my $nmsgs = scalar(@$resp_msgs); 9679 9680 my $expected = 1; 9681 $self->assert($expected == $nmsgs, 9682 test_msg("Expected $expected, got $nmsgs")); 9683 9684 $expected = "User $setup->{user} logged in"; 9685 $self->assert($expected eq $resp_msgs->[0], 9686 test_msg("Expected response message '$expected', got '$resp_msgs->[0]'")); 9687 }; 9688 if ($@) { 9689 $ex = $@; 9690 } 9691 9692 $wfh->print("done\n"); 9693 $wfh->flush(); 9694 9695 } else { 9696 eval { server_wait($setup->{config_file}, $rfh) }; 9697 if ($@) { 9698 warn($@); 9699 exit 1; 9700 } 9701 9702 exit 0; 9703 } 9704 9705 # Stop server 9706 server_stop($setup->{pid_file}); 9707 $self->assert_child_ok($pid); 9708 9709 test_cleanup($setup->{log_file}, $ex); 9710} 9711 97121; 9713