1package ProFTPD::Tests::Modules::mod_sql_sqlite; 2 3use lib qw(t/lib); 4use base qw(ProFTPD::TestSuite::Child); 5use strict; 6 7use Carp; 8use File::Path qw(mkpath); 9use File::Spec; 10use IO::Handle; 11use Sys::HostAddr; 12 13use ProFTPD::TestSuite::FTP; 14use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite); 15 16$| = 1; 17 18my $order = 0; 19 20my $TESTS = { 21 sql_bug2045 => { 22 order => ++$order, 23 test_class => [qw(bug forking)], 24 }, 25 26 sql_bug2922 => { 27 order => ++$order, 28 test_class => [qw(bug forking rootprivs)], 29 }, 30 31 sql_bug3116 => { 32 order => ++$order, 33 test_class => [qw(bug forking)], 34 }, 35 36 sql_bug3124 => { 37 order => ++$order, 38 test_class => [qw(bug forking)], 39 }, 40 41 sql_sqlite_bug3126 => { 42 order => ++$order, 43 test_class => [qw(bug forking)], 44 }, 45 46 sql_user_where_clause_ok => { 47 order => ++$order, 48 test_class => [qw(forking)], 49 }, 50 51 sql_user_where_clause_with_vars_ok => { 52 order => ++$order, 53 test_class => [qw(forking)], 54 }, 55 56 sql_group_where_clause_ok => { 57 order => ++$order, 58 test_class => [qw(forking)], 59 }, 60 61 sql_bug3149 => { 62 order => ++$order, 63 test_class => [qw(bug forking)], 64 }, 65 66 sql_sqllog => { 67 order => ++$order, 68 test_class => [qw(forking)], 69 }, 70 71 sql_sqlite_sqllog_with_chroot => { 72 order => ++$order, 73 test_class => [qw(forking rootprivs)], 74 }, 75 76 sql_user_info_different_table_names => { 77 order => ++$order, 78 test_class => [qw(forking)], 79 }, 80 81 sql_custom_user_info => { 82 order => ++$order, 83 test_class => [qw(forking)], 84 }, 85 86 sql_custom_user_info_null_ids => { 87 order => ++$order, 88 test_class => [qw(forking)], 89 }, 90 91 sql_userset_bug2434 => { 92 order => ++$order, 93 test_class => [qw(bug forking rootprivs)], 94 }, 95 96 sql_usersetfast_bug2434 => { 97 order => ++$order, 98 test_class => [qw(bug forking rootprivs)], 99 }, 100 101 sql_custom_group_info_bug3043 => { 102 order => ++$order, 103 test_class => [qw(bug forking)], 104 }, 105 106 sql_groupset_bug3043 => { 107 order => ++$order, 108 test_class => [qw(bug forking rootprivs)], 109 }, 110 111 sql_groupsetfast_bug3043 => { 112 order => ++$order, 113 test_class => [qw(bug forking rootprivs)], 114 }, 115 116 sql_sqllog_var_w => { 117 order => ++$order, 118 test_class => [qw(forking)], 119 }, 120 121 sql_sqllog_var_w_chrooted => { 122 order => ++$order, 123 test_class => [qw(forking rootprivs)], 124 }, 125 126 sql_openssl_auth_type_md5 => { 127 order => ++$order, 128 test_class => [qw(feature_openssl forking)], 129 }, 130 131 sql_openssl_auth_type_sha1 => { 132 order => ++$order, 133 test_class => [qw(feature_openssl forking)], 134 }, 135 136 sql_sqllog_var_S => { 137 order => ++$order, 138 test_class => [qw(forking)], 139 }, 140 141 sql_sqllog_var_S_err => { 142 order => ++$order, 143 test_class => [qw(forking)], 144 }, 145 146 sql_negative_cache_bug3282 => { 147 order => ++$order, 148 test_class => [qw(bug forking)], 149 }, 150 151 sql_sqllog_var_T_rnfr => { 152 order => ++$order, 153 test_class => [qw(bug forking)], 154 }, 155 156 sql_sqllog_var_T_retr => { 157 order => ++$order, 158 test_class => [qw(bug forking)], 159 }, 160 161 sql_sqllog_var_transfer_millisecs_retr_bug4218 => { 162 order => ++$order, 163 test_class => [qw(bug forking)], 164 }, 165 166 sql_sqllog_var_R_retr_bug4218 => { 167 order => ++$order, 168 test_class => [qw(bug forking)], 169 }, 170 171 sql_sqllog_exit => { 172 order => ++$order, 173 test_class => [qw(forking)], 174 }, 175 176 sql_sqllog_exit_var_remote_port_bug4296 => { 177 order => ++$order, 178 test_class => [qw(bug forking)], 179 }, 180 181 sql_sqllog_var_d_bug3395 => { 182 order => ++$order, 183 test_class => [qw(bug forking)], 184 }, 185 186 sql_sqllog_var_d_chroot_bug3395 => { 187 order => ++$order, 188 test_class => [qw(bug forking rootprivs)], 189 }, 190 191 sql_sqllog_var_uid_gid_bug3390 => { 192 order => ++$order, 193 test_class => [qw(bug forking)], 194 }, 195 196 sql_sqlite_auth_type_backend_bug3511 => { 197 order => ++$order, 198 test_class => [qw(bug forking)], 199 }, 200 201 sql_sqllog_pass_ok_var_s_bug3528 => { 202 order => ++$order, 203 test_class => [qw(bug forking)], 204 }, 205 206 sql_sqllog_pass_failed_var_s_bug3528 => { 207 order => ++$order, 208 test_class => [qw(bug forking)], 209 }, 210 211 sql_sqllog_pass_failed_bug4301 => { 212 order => ++$order, 213 test_class => [qw(bug forking)], 214 }, 215 216 sql_sqlshowinfo_pass_bug3423 => { 217 order => ++$order, 218 test_class => [qw(bug forking)], 219 }, 220 221 sql_sqlshowinfo_list_bug3423 => { 222 order => ++$order, 223 test_class => [qw(bug forking)], 224 }, 225 226 sql_multiple_users_shared_uid_gid => { 227 order => ++$order, 228 test_class => [qw(bug forking)], 229 }, 230 231 sql_resolve_tag_bug3536 => { 232 order => ++$order, 233 test_class => [qw(bug forking inprogress)], 234 }, 235 236 sql_sqllog_vars_I_O_bug3554 => { 237 order => ++$order, 238 test_class => [qw(bug forking)], 239 }, 240 241 sql_sqllog_note_var_unique_id_bug3572 => { 242 order => ++$order, 243 test_class => [qw(bug forking mod_unique_id)], 244 }, 245 246 sql_sqllog_note_var_rewrite_bug3572 => { 247 order => ++$order, 248 test_class => [qw(bug forking mod_rewrite)], 249 }, 250 251 sql_sqllog_note_sql_user_info => { 252 order => ++$order, 253 test_class => [qw(forking)], 254 }, 255 256 sql_sqllog_var_E => { 257 order => ++$order, 258 test_class => [qw(forking)], 259 }, 260 261 sql_named_conn_bug3262 => { 262 order => ++$order, 263 test_class => [qw(bug forking)], 264 }, 265 266 sql_named_conn_sqllog_exit_bug3645 => { 267 order => ++$order, 268 test_class => [qw(bug forking rootprivs)], 269 }, 270 271 sql_sqllog_vars_H_L_matching_server_bug3620 => { 272 order => ++$order, 273 test_class => [qw(bug forking)], 274 }, 275 276 sql_sqllog_vars_H_L_default_server_bug3620 => { 277 order => ++$order, 278 test_class => [qw(bug forking)], 279 }, 280 281 sql_sqllog_exit_ifuser => { 282 order => ++$order, 283 test_class => [qw(forking mod_ifsession)], 284 }, 285 286 sql_sqllog_exit_ifgroup => { 287 order => ++$order, 288 test_class => [qw(forking mod_ifsession)], 289 }, 290 291 sql_sqllog_multi_pass_ifclass_bug4025 => { 292 order => ++$order, 293 test_class => [qw(forking mod_ifsession)], 294 }, 295 296 sql_opt_no_disconnect_on_error_with_extlog_bug3633 => { 297 order => ++$order, 298 test_class => [qw(bug forking)], 299 }, 300 301 sql_sqllog_ignore_errors_bad_table_bug3692 => { 302 order => ++$order, 303 test_class => [qw(bug forking)], 304 }, 305 306 sql_sqllog_ignore_errors_bad_db_bug3692 => { 307 order => ++$order, 308 test_class => [qw(bug forking)], 309 }, 310 311 sql_sqllog_var_xfer_status_nonxfer => { 312 order => ++$order, 313 test_class => [qw(forking)], 314 }, 315 316 sql_sqllog_var_xfer_status_success_download => { 317 order => ++$order, 318 test_class => [qw(forking)], 319 }, 320 321 sql_sqllog_var_xfer_status_success_upload => { 322 order => ++$order, 323 test_class => [qw(forking)], 324 }, 325 326 sql_sqllog_var_xfer_status_cancelled => { 327 order => ++$order, 328 test_class => [qw(forking)], 329 }, 330 331 sql_sqllog_var_xfer_status_failed => { 332 order => ++$order, 333 test_class => [qw(forking)], 334 }, 335 336 sql_sqllog_var_xfer_status_timeout => { 337 order => ++$order, 338 test_class => [qw(forking)], 339 }, 340 341 sql_sqllog_var_xfer_status_filtered => { 342 order => ++$order, 343 test_class => [qw(forking)], 344 }, 345 346 sql_sqllog_var_xfer_failure_none => { 347 order => ++$order, 348 test_class => [qw(forking)], 349 }, 350 351 sql_sqllog_var_xfer_failure_reason => { 352 order => ++$order, 353 test_class => [qw(forking)], 354 }, 355 356 sql_sqlshowinfo_pass_failed_bug3782 => { 357 order => ++$order, 358 test_class => [qw(bug forking)], 359 }, 360 361 sql_sqllog_preauth_var_U_bug3822 => { 362 order => ++$order, 363 test_class => [qw(bug forking)], 364 }, 365 366 sql_sqllog_preauth_var_u_bug3822 => { 367 order => ++$order, 368 test_class => [qw(bug forking)], 369 }, 370 371 sql_sqlite_maxhostsperuser => { 372 order => ++$order, 373 test_class => [qw(forking mod_unique_id)], 374 }, 375 376 sql_sqllog_var_micros_ts_bug3889 => { 377 order => ++$order, 378 test_class => [qw(bug forking)], 379 }, 380 381 sql_sqllog_var_millis_ts_bug3889 => { 382 order => ++$order, 383 test_class => [qw(bug forking)], 384 }, 385 386 sql_sqllog_var_iso8601_ts_bug3889 => { 387 order => ++$order, 388 test_class => [qw(bug forking)], 389 }, 390 391 sql_sqllog_var_note_ftps_without_tls_issue1232 => { 392 order => ++$order, 393 test_class => [qw(bug forking)], 394 }, 395 396 sql_sqllog_var_note_ftps_with_tls_issue1232 => { 397 order => ++$order, 398 test_class => [qw(bug forking mod_tls)], 399 }, 400 401 sql_sqllogonevent_bug3893 => { 402 order => ++$order, 403 test_class => [qw(bug forking)], 404 }, 405 406 sql_userprimarykey_bug3864 => { 407 order => ++$order, 408 test_class => [qw(bug forking)], 409 }, 410 411 sql_userprimarykey_custom_bug3864 => { 412 order => ++$order, 413 test_class => [qw(bug forking)], 414 }, 415 416 sql_groupprimarykey_bug3864 => { 417 order => ++$order, 418 test_class => [qw(bug forking)], 419 }, 420 421 sql_groupprimarykey_custom_bug3864 => { 422 order => ++$order, 423 test_class => [qw(bug forking)], 424 }, 425 426 sql_sqllog_var_basename_bug3987 => { 427 order => ++$order, 428 test_class => [qw(bug forking)], 429 }, 430 431 sql_user_info_defaulthomedir_bug4083 => { 432 order => ++$order, 433 test_class => [qw(bug forking)], 434 }, 435 436 sql_user_info_null_uid_gid_columns => { 437 order => ++$order, 438 test_class => [qw(forking)], 439 }, 440 441 sql_64_bit_uid_bug4164 => { 442 order => ++$order, 443 test_class => [qw(bug forking)], 444 }, 445 446 sql_sqllog_var_remote_port => { 447 order => ++$order, 448 test_class => [qw(forking)], 449 }, 450 451 sql_userowner_issue346 => { 452 order => ++$order, 453 test_class => [qw(forking rootprivs)], 454 }, 455 456 sql_sqlite_log_db_enoent_issue654 => { 457 order => ++$order, 458 test_class => [qw(forking bug)], 459 }, 460 461 sql_namebased_vhost_using_host_issue882 => { 462 order => ++$order, 463 test_class => [qw(forking bug)], 464 }, 465 466 sql_namebased_vhost_using_sni_issue882 => { 467 order => ++$order, 468 test_class => [qw(forking bug mod_tls)], 469 }, 470}; 471 472sub new { 473 return shift()->SUPER::new(@_); 474} 475 476sub list_tests { 477 return testsuite_get_runnable_tests($TESTS); 478} 479 480sub build_db { 481 my $cmd = shift; 482 my $db_script = shift; 483 my $check_exit_status = shift; 484 $check_exit_status = 0 unless defined $check_exit_status; 485 486 if ($ENV{TEST_VERBOSE}) { 487 print STDERR "Executing sqlite3: $cmd\n"; 488 } 489 490 my @output = `$cmd`; 491 my $exit_status = $?; 492 493 if ($ENV{TEST_VERBOSE}) { 494 print STDERR "Output: ", join('', @output), "\n"; 495 } 496 497 if ($check_exit_status) { 498 if ($? != 0) { 499 croak("'$cmd' failed"); 500 } 501 } 502 503 unlink($db_script); 504 return 1; 505} 506 507sub sql_bug2045 { 508 my $self = shift; 509 my $tmpdir = $self->{tmpdir}; 510 my $setup = test_setup($tmpdir, 'sqlite'); 511 512 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 513 514 # Build up sqlite3 command to create users, groups tables and populate them 515 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 516 517 if (open(my $fh, "> $db_script")) { 518 print $fh <<EOS; 519CREATE TABLE users ( 520 userid TEXT, 521 passwd TEXT, 522 uid INTEGER, 523 gid INTEGER, 524 homedir TEXT, 525 shell TEXT, 526 lastdir TEXT 527); 528INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$setup->{user}', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash'); 529 530CREATE TABLE groups ( 531 groupname TEXT, 532 gid INTEGER, 533 members TEXT 534); 535INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); 536EOS 537 538 unless (close($fh)) { 539 die("Can't write $db_script: $!"); 540 } 541 542 } else { 543 die("Can't open $db_script: $!"); 544 } 545 546 my $cmd = "sqlite3 $db_file < $db_script"; 547 build_db($cmd, $db_script); 548 549 # Make sure that, if we're running as root, the database file has 550 # the permissions/privs set for use by proftpd 551 if ($< == 0) { 552 unless (chmod(0666, $db_file)) { 553 die("Can't set perms on $db_file to 0666: $!"); 554 } 555 } 556 557 my $config = { 558 PidFile => $setup->{pid_file}, 559 ScoreboardFile => $setup->{scoreboard_file}, 560 SystemLog => $setup->{log_file}, 561 TraceLog => $setup->{log_file}, 562 Trace => 'sql:20', 563 564 IfModules => { 565 'mod_delay.c' => { 566 DelayEngine => 'off', 567 }, 568 569 'mod_sql.c' => { 570 SQLAuthTypes => 'plaintext', 571 SQLBackend => 'sqlite3', 572 SQLConnectInfo => $db_file, 573 SQLLogFile => $setup->{log_file}, 574 SQLNamedQuery => 'lastdir SELECT "lastdir FROM users WHERE userid = \'%u\'"', 575 SQLShowInfo => 'PASS "230" "\"%{lastdir}\" was the last directory"', 576 }, 577 }, 578 }; 579 580 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 581 $config); 582 583 # Open pipes, for use between the parent and child processes. Specifically, 584 # the child will indicate when it's done with its test by writing a message 585 # to the parent. 586 my ($rfh, $wfh); 587 unless (pipe($rfh, $wfh)) { 588 die("Can't open pipe: $!"); 589 } 590 591 my $ex; 592 593 # Fork child 594 $self->handle_sigchld(); 595 defined(my $pid = fork()) or die("Can't fork: $!"); 596 if ($pid) { 597 eval { 598 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 599 $client->login($setup->{user}, $setup->{passwd}); 600 601 my $resp_msgs = $client->response_msgs(); 602 my $nmsgs = scalar(@$resp_msgs); 603 604 my $expected = 1; 605 $self->assert($expected == $nmsgs, "Expected $expected, got $nmsgs"); 606 607 $expected = "User proftpd logged in"; 608 $self->assert($expected eq $resp_msgs->[0], 609 "Expected '$expected', got '$resp_msgs->[0]'"); 610 }; 611 if ($@) { 612 $ex = $@; 613 } 614 615 $wfh->print("done\n"); 616 $wfh->flush(); 617 618 } else { 619 eval { server_wait($setup->{config_file}, $rfh) }; 620 if ($@) { 621 warn($@); 622 exit 1; 623 } 624 625 exit 0; 626 } 627 628 # Stop server 629 server_stop($setup->{pid_file}); 630 $self->assert_child_ok($pid); 631 632 test_cleanup($setup->{log_file}, $ex); 633} 634 635sub sql_bug2922 { 636 my $self = shift; 637 my $tmpdir = $self->{tmpdir}; 638 639 my $config_file = "$tmpdir/sqlite.conf"; 640 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 641 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 642 643 my $log_file = test_get_logfile(); 644 645 # Bug#2922 occurred because mod_sql would "authenticate" the plaintext 646 # password (if configured to do so) of a user whose info did NOT come from 647 # mod_sql. 648 649 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 650 651 # Build up sqlite3 command to create users, groups tables and populate them 652 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 653 654 if (open(my $fh, "> $db_script")) { 655 print $fh <<EOS; 656CREATE TABLE users ( 657 userid TEXT, 658 passwd TEXT, 659 uid INTEGER, 660 gid INTEGER, 661 homedir TEXT, 662 shell TEXT 663); 664 665CREATE TABLE groups ( 666 groupname TEXT, 667 gid INTEGER, 668 members TEXT 669); 670EOS 671 672 unless (close($fh)) { 673 die("Can't write $db_script: $!"); 674 } 675 676 } else { 677 die("Can't open $db_script: $!"); 678 } 679 680 my $cmd = "sqlite3 $db_file < $db_script"; 681 build_db($cmd, $db_script); 682 683 # Make sure that, if we're running as root, the database file has 684 # the permissions/privs set for use by proftpd 685 if ($< == 0) { 686 unless (chmod(0666, $db_file)) { 687 die("Can't set perms on $db_file to 0666: $!"); 688 } 689 } 690 691 my $config = { 692 PidFile => $pid_file, 693 ScoreboardFile => $scoreboard_file, 694 SystemLog => $log_file, 695 696 MaxLoginAttempts => 100, 697 698 IfModules => { 699 'mod_delay.c' => { 700 DelayEngine => 'off', 701 }, 702 703 'mod_sql.c' => { 704 SQLAuthTypes => 'plaintext', 705 SQLBackend => 'sqlite3', 706 SQLConnectInfo => $db_file, 707 SQLLogFile => $log_file, 708 }, 709 }, 710 }; 711 712 my ($port, $config_user, $config_group) = config_write($config_file, $config); 713 714 # Open pipes, for use between the parent and child processes. Specifically, 715 # the child will indicate when it's done with its test by writing a message 716 # to the parent. 717 my ($rfh, $wfh); 718 unless (pipe($rfh, $wfh)) { 719 die("Can't open pipe: $!"); 720 } 721 722 my $ex; 723 724 # Fork child 725 $self->handle_sigchld(); 726 defined(my $pid = fork()) or die("Can't fork: $!"); 727 if ($pid) { 728 eval { 729 # Bug#2922 would allow a login which should NOT happen. So if 730 # *any* of the following logins succeed, we have a problem. 731 732 my $accounts = [ 733 { user => 'bin', passwd => '*' }, 734 { user => 'bin', passwd => 'x' }, 735 { user => 'daemon', passwd => '*' }, 736 { user => 'daemon', passwd => 'x' }, 737 { user => 'mysql', passwd => '*' }, 738 { user => 'mysql', passwd => 'x' }, 739 ]; 740 741 foreach my $account (@$accounts) { 742 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 743 my $user = $account->{user}; 744 my $passwd = $account->{passwd}; 745 746 eval { $client->login($user, $passwd) }; 747 unless ($@) { 748 die("Logged in unexpectedly"); 749 } 750 } 751 }; 752 753 if ($@) { 754 $ex = $@; 755 } 756 757 $wfh->print("done\n"); 758 $wfh->flush(); 759 760 } else { 761 eval { server_wait($config_file, $rfh, 30) }; 762 if ($@) { 763 warn($@); 764 exit 1; 765 } 766 767 exit 0; 768 } 769 770 # Stop server 771 server_stop($pid_file); 772 773 $self->assert_child_ok($pid); 774 775 if ($ex) { 776 test_append_logfile($log_file, $ex); 777 unlink($log_file); 778 779 die($ex); 780 } 781 782 unlink($log_file); 783} 784 785sub sql_bug3116 { 786 my $self = shift; 787 my $tmpdir = $self->{tmpdir}; 788 789 my $config_file = "$tmpdir/sqlite.conf"; 790 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 791 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 792 793 my $log_file = test_get_logfile(); 794 795 # Bug#3116 occurred because mod_sql was treating percent signs in user 796 # (and group) names as variables to be substituted. 797 798 my $user = 'proftpd%proftpd.org'; 799 my $passwd = 'test'; 800 my $group = 'ftpd'; 801 my $home_dir = File::Spec->rel2abs($tmpdir); 802 803 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 804 805 # Build up sqlite3 command to create users, groups tables and populate them 806 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 807 808 if (open(my $fh, "> $db_script")) { 809 print $fh <<EOS; 810CREATE TABLE users ( 811 userid TEXT, 812 passwd TEXT, 813 uid INTEGER, 814 gid INTEGER, 815 homedir TEXT, 816 shell TEXT 817); 818INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash'); 819 820CREATE TABLE groups ( 821 groupname TEXT, 822 gid INTEGER, 823 members TEXT 824); 825INSERT INTO groups (groupname, gid, members) VALUES ('$group', 500, '$user'); 826INSERT INTO groups (groupname, gid, members) VALUES ('ftpadm', 501, '$user'); 827EOS 828 829 unless (close($fh)) { 830 die("Can't write $db_script: $!"); 831 } 832 833 } else { 834 die("Can't open $db_script: $!"); 835 } 836 837 my $cmd = "sqlite3 -echo $db_file < $db_script 2>&1"; 838 build_db($cmd, $db_script); 839 840 # Make sure that, if we're running as root, the database file has 841 # the permissions/privs set for use by proftpd 842 if ($< == 0) { 843 unless (chmod(0666, $db_file)) { 844 die("Can't set perms on $db_file to 0666: $!"); 845 } 846 } 847 848 my $config = { 849 PidFile => $pid_file, 850 ScoreboardFile => $scoreboard_file, 851 SystemLog => $log_file, 852 853 IfModules => { 854 'mod_delay.c' => { 855 DelayEngine => 'off', 856 }, 857 858 'mod_sql.c' => { 859 SQLAuthTypes => 'plaintext', 860 SQLBackend => 'sqlite3', 861 SQLConnectInfo => $db_file, 862 SQLLogFile => $log_file, 863 }, 864 }, 865 }; 866 867 my ($port, $config_user, $config_group) = config_write($config_file, $config); 868 869 # Open pipes, for use between the parent and child processes. Specifically, 870 # the child will indicate when it's done with its test by writing a message 871 # to the parent. 872 my ($rfh, $wfh); 873 unless (pipe($rfh, $wfh)) { 874 die("Can't open pipe: $!"); 875 } 876 877 my $ex; 878 879 # Fork child 880 $self->handle_sigchld(); 881 defined(my $pid = fork()) or die("Can't fork: $!"); 882 if ($pid) { 883 eval { 884 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 885 886 # Bug#3116 would prevent a login from occurring, so we only need to 887 # attempt a login. 888 $client->login($user, $passwd, 5); 889 }; 890 891 if ($@) { 892 $ex = $@; 893 } 894 895 $wfh->print("done\n"); 896 $wfh->flush(); 897 898 } else { 899 eval { server_wait($config_file, $rfh) }; 900 if ($@) { 901 warn($@); 902 exit 1; 903 } 904 905 exit 0; 906 } 907 908 # Stop server 909 server_stop($pid_file); 910 911 $self->assert_child_ok($pid); 912 913 if ($ex) { 914 test_append_logfile($log_file, $ex); 915 unlink($log_file); 916 917 die($ex); 918 } 919 920 unlink($log_file); 921} 922 923sub sql_bug3124 { 924 my $self = shift; 925 my $tmpdir = $self->{tmpdir}; 926 927 my $config_file = "$tmpdir/sqlite.conf"; 928 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 929 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 930 931 my $log_file = test_get_logfile(); 932 933 my $user = 'proftpd'; 934 my $passwd = 'test'; 935 my $group = 'ftpd'; 936 my $home_dir = File::Spec->rel2abs($tmpdir); 937 938 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 939 940 # Build up sqlite3 command to create users, groups tables and populate them 941 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 942 943 if (open(my $fh, "> $db_script")) { 944 print $fh <<EOS; 945CREATE TABLE users ( 946 userid TEXT, 947 passwd TEXT, 948 uid INTEGER, 949 gid INTEGER, 950 homedir TEXT, 951 shell TEXT 952); 953INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash'); 954 955CREATE TABLE groups ( 956 groupname TEXT, 957 gid INTEGER, 958 members TEXT 959); 960EOS 961 962 unless (close($fh)) { 963 die("Can't write $db_script: $!"); 964 } 965 966 } else { 967 die("Can't open $db_script: $!"); 968 } 969 970 my $cmd = "sqlite3 $db_file < $db_script"; 971 build_db($cmd, $db_script); 972 973 # Make sure that, if we're running as root, the database file has 974 # the permissions/privs set for use by proftpd 975 if ($< == 0) { 976 unless (chmod(0666, $db_file)) { 977 die("Can't set perms on $db_file to 0666: $!"); 978 } 979 } 980 981 # Bug#3124 occurred when SQLNegativeCache was on, and there was no group 982 # info; it would cause a segfault. 983 984 my $config = { 985 PidFile => $pid_file, 986 ScoreboardFile => $scoreboard_file, 987 SystemLog => $log_file, 988 989 IfModules => { 990 'mod_delay.c' => { 991 DelayEngine => 'off', 992 }, 993 994 'mod_sql.c' => { 995 SQLAuthTypes => 'plaintext', 996 SQLBackend => 'sqlite3', 997 SQLConnectInfo => $db_file, 998 SQLLogFile => $log_file, 999 SQLNegativeCache => 'on', 1000 }, 1001 }, 1002 }; 1003 1004 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1005 1006 # Open pipes, for use between the parent and child processes. Specifically, 1007 # the child will indicate when it's done with its test by writing a message 1008 # to the parent. 1009 my ($rfh, $wfh); 1010 unless (pipe($rfh, $wfh)) { 1011 die("Can't open pipe: $!"); 1012 } 1013 1014 my $ex; 1015 1016 # Fork child 1017 $self->handle_sigchld(); 1018 defined(my $pid = fork()) or die("Can't fork: $!"); 1019 if ($pid) { 1020 eval { 1021 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1022 1023 # Bug#3124 would prevent a login from occurring, so we only need to 1024 # attempt a login. 1025 $client->login($user, $passwd, 5); 1026 }; 1027 1028 if ($@) { 1029 $ex = $@; 1030 } 1031 1032 $wfh->print("done\n"); 1033 $wfh->flush(); 1034 1035 } else { 1036 eval { server_wait($config_file, $rfh) }; 1037 if ($@) { 1038 warn($@); 1039 exit 1; 1040 } 1041 1042 exit 0; 1043 } 1044 1045 # Stop server 1046 server_stop($pid_file); 1047 1048 $self->assert_child_ok($pid); 1049 1050 if ($ex) { 1051 test_append_logfile($log_file, $ex); 1052 unlink($log_file); 1053 1054 die($ex); 1055 } 1056 1057 unlink($log_file); 1058} 1059 1060sub sql_sqlite_bug3126 { 1061 my $self = shift; 1062 my $tmpdir = $self->{tmpdir}; 1063 1064 my $config_file = "$tmpdir/sqlite.conf"; 1065 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 1066 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 1067 1068 my $log_file = test_get_logfile(); 1069 1070 my $user = 'proftpd'; 1071 my $passwd = 'test'; 1072 my $group = 'ftpd'; 1073 my $home_dir = File::Spec->rel2abs($tmpdir); 1074 1075 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1076 1077 # Build up sqlite3 command to create users, groups tables and populate them 1078 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1079 1080 if (open(my $fh, "> $db_script")) { 1081 print $fh <<EOS; 1082CREATE TABLE users ( 1083 userid TEXT, 1084 passwd TEXT, 1085 uid INTEGER, 1086 gid INTEGER, 1087 homedir TEXT, 1088 shell TEXT 1089); 1090INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash'); 1091 1092CREATE TABLE groups ( 1093 groupname TEXT, 1094 gid INTEGER, 1095 members TEXT 1096); 1097INSERT INTO groups (groupname, gid, members) VALUES ('$group', 500, '$user'); 1098INSERT INTO groups (groupname, gid, members) VALUES ('ftpadm', 501, '$user'); 1099EOS 1100 1101 unless (close($fh)) { 1102 die("Can't write $db_script: $!"); 1103 } 1104 1105 } else { 1106 die("Can't open $db_script: $!"); 1107 } 1108 1109 my $cmd = "sqlite3 $db_file < $db_script"; 1110 build_db($cmd, $db_script); 1111 1112 # Make sure that, if we're running as root, the database file has 1113 # the permissions/privs set for use by proftpd 1114 if ($< == 0) { 1115 unless (chmod(0666, $db_file)) { 1116 die("Can't set perms on $db_file to 0666: $!"); 1117 } 1118 } 1119 1120 my $config = { 1121 PidFile => $pid_file, 1122 ScoreboardFile => $scoreboard_file, 1123 SystemLog => $log_file, 1124 1125 IfModules => { 1126 'mod_delay.c' => { 1127 DelayEngine => 'off', 1128 }, 1129 1130 'mod_sql.c' => { 1131 SQLAuthTypes => 'plaintext', 1132 SQLBackend => 'sqlite3', 1133 SQLConnectInfo => $db_file, 1134 SQLLogFile => $log_file, 1135 }, 1136 }, 1137 }; 1138 1139 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1140 1141 # Open pipes, for use between the parent and child processes. Specifically, 1142 # the child will indicate when it's done with its test by writing a message 1143 # to the parent. 1144 my ($rfh, $wfh); 1145 unless (pipe($rfh, $wfh)) { 1146 die("Can't open pipe: $!"); 1147 } 1148 1149 my $ex; 1150 1151 # Fork child 1152 $self->handle_sigchld(); 1153 defined(my $pid = fork()) or die("Can't fork: $!"); 1154 if ($pid) { 1155 eval { 1156 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1157 1158 # Bug#3126 would prevent a login from occurring, so we only need to 1159 # attempt a login. 1160 $client->login($user, $passwd, 5); 1161 }; 1162 1163 if ($@) { 1164 $ex = $@; 1165 } 1166 1167 $wfh->print("done\n"); 1168 $wfh->flush(); 1169 1170 } else { 1171 eval { server_wait($config_file, $rfh) }; 1172 if ($@) { 1173 warn($@); 1174 exit 1; 1175 } 1176 1177 exit 0; 1178 } 1179 1180 # Stop server 1181 server_stop($pid_file); 1182 1183 $self->assert_child_ok($pid); 1184 1185 if ($ex) { 1186 test_append_logfile($log_file, $ex); 1187 unlink($log_file); 1188 1189 die($ex); 1190 } 1191 1192 unlink($log_file); 1193} 1194 1195sub sql_user_where_clause_ok { 1196 my $self = shift; 1197 my $tmpdir = $self->{tmpdir}; 1198 1199 my $config_file = "$tmpdir/sqlite.conf"; 1200 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 1201 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 1202 1203 my $log_file = test_get_logfile(); 1204 1205 my $user1 = 'proftpd'; 1206 my $user2 = 'proftpd2'; 1207 my $passwd = 'test'; 1208 my $group = 'ftpd'; 1209 my $home_dir = File::Spec->rel2abs($tmpdir); 1210 1211 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1212 1213 # Build up sqlite3 command to create users, groups tables and populate them 1214 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1215 1216 if (open(my $fh, "> $db_script")) { 1217 print $fh <<EOS; 1218CREATE TABLE users ( 1219 userid TEXT, 1220 passwd TEXT, 1221 uid INTEGER, 1222 gid INTEGER, 1223 homedir TEXT, 1224 shell TEXT, 1225 allowed TEXT 1226); 1227INSERT INTO users (userid, passwd, uid, gid, homedir, shell, allowed) VALUES ('$user1', '$passwd', 500, 500, '$home_dir', '/bin/bash', 'false'); 1228INSERT INTO users (userid, passwd, uid, gid, homedir, shell, allowed) VALUES ('$user2', '$passwd', 500, 500, '$home_dir', '/bin/bash', 'true'); 1229 1230CREATE TABLE groups ( 1231 groupname TEXT, 1232 gid INTEGER, 1233 members TEXT 1234); 1235INSERT INTO groups (groupname, gid, members) VALUES ('$group', 500, '$user1,$user2'); 1236EOS 1237 1238 unless (close($fh)) { 1239 die("Can't write $db_script: $!"); 1240 } 1241 1242 } else { 1243 die("Can't open $db_script: $!"); 1244 } 1245 1246 my $cmd = "sqlite3 $db_file < $db_script"; 1247 build_db($cmd, $db_script); 1248 1249 # Make sure that, if we're running as root, the database file has 1250 # the permissions/privs set for use by proftpd 1251 if ($< == 0) { 1252 unless (chmod(0666, $db_file)) { 1253 die("Can't set perms on $db_file to 0666: $!"); 1254 } 1255 } 1256 1257 my $config = { 1258 PidFile => $pid_file, 1259 ScoreboardFile => $scoreboard_file, 1260 SystemLog => $log_file, 1261 1262 IfModules => { 1263 'mod_delay.c' => { 1264 DelayEngine => 'off', 1265 }, 1266 1267 'mod_sql.c' => { 1268 SQLAuthTypes => 'plaintext', 1269 SQLBackend => 'sqlite3', 1270 SQLConnectInfo => $db_file, 1271 SQLLogFile => $log_file, 1272 SQLUserWhereClause => '"allowed = \'true\'"', 1273 }, 1274 }, 1275 }; 1276 1277 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1278 1279 # Open pipes, for use between the parent and child processes. Specifically, 1280 # the child will indicate when it's done with its test by writing a message 1281 # to the parent. 1282 my ($rfh, $wfh); 1283 unless (pipe($rfh, $wfh)) { 1284 die("Can't open pipe: $!"); 1285 } 1286 1287 my $ex; 1288 1289 # Fork child 1290 $self->handle_sigchld(); 1291 defined(my $pid = fork()) or die("Can't fork: $!"); 1292 if ($pid) { 1293 eval { 1294 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1295 1296 # This account should not be allowed to login based on the 1297 # SQLUserWhereClause... 1298 eval { $client->login($user1, $passwd) }; 1299 unless ($@) { 1300 die("Login for user '$user1' succeeded unexpectedly"); 1301 } 1302 1303 # ...but this one should succeed. 1304 $client->login($user2, $passwd); 1305 }; 1306 1307 if ($@) { 1308 $ex = $@; 1309 } 1310 1311 $wfh->print("done\n"); 1312 $wfh->flush(); 1313 1314 } else { 1315 eval { server_wait($config_file, $rfh) }; 1316 if ($@) { 1317 warn($@); 1318 exit 1; 1319 } 1320 1321 exit 0; 1322 } 1323 1324 # Stop server 1325 server_stop($pid_file); 1326 1327 $self->assert_child_ok($pid); 1328 1329 if ($ex) { 1330 test_append_logfile($log_file, $ex); 1331 unlink($log_file); 1332 1333 die($ex); 1334 } 1335 1336 unlink($log_file); 1337} 1338 1339sub sql_user_where_clause_with_vars_ok { 1340 my $self = shift; 1341 my $tmpdir = $self->{tmpdir}; 1342 my $setup = test_setup($tmpdir, 'sqlite'); 1343 1344 my $user2 = 'proftpd2'; 1345 1346 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1347 1348 # Build up sqlite3 command to create users, groups tables and populate them 1349 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1350 1351 if (open(my $fh, "> $db_script")) { 1352 print $fh <<EOS; 1353CREATE TABLE users ( 1354 userid TEXT, 1355 passwd TEXT, 1356 uid INTEGER, 1357 gid INTEGER, 1358 homedir TEXT, 1359 shell TEXT, 1360 allowed_ip TEXT 1361); 1362INSERT INTO users (userid, passwd, uid, gid, homedir, shell, allowed_ip) VALUES ('$setup->{user}', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash', '1.2.3.4'); 1363INSERT INTO users (userid, passwd, uid, gid, homedir, shell, allowed_ip) VALUES ('$user2', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash', '127.0.0.1'); 1364 1365CREATE TABLE groups ( 1366 groupname TEXT, 1367 gid INTEGER, 1368 members TEXT 1369); 1370INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user},$user2'); 1371EOS 1372 1373 unless (close($fh)) { 1374 die("Can't write $db_script: $!"); 1375 } 1376 1377 } else { 1378 die("Can't open $db_script: $!"); 1379 } 1380 1381 my $cmd = "sqlite3 $db_file < $db_script"; 1382 build_db($cmd, $db_script); 1383 1384 # Make sure that, if we're running as root, the database file has 1385 # the permissions/privs set for use by proftpd 1386 if ($< == 0) { 1387 unless (chmod(0666, $db_file)) { 1388 die("Can't set perms on $db_file to 0666: $!"); 1389 } 1390 } 1391 1392 my $config = { 1393 PidFile => $setup->{pid_file}, 1394 ScoreboardFile => $setup->{scoreboard_file}, 1395 SystemLog => $setup->{log_file}, 1396 TraceLog => $setup->{log_file}, 1397 Trace => 'jot:20 sql:20', 1398 1399 IfModules => { 1400 'mod_delay.c' => { 1401 DelayEngine => 'off', 1402 }, 1403 1404 'mod_sql.c' => { 1405 SQLAuthTypes => 'plaintext', 1406 SQLBackend => 'sqlite3', 1407 SQLConnectInfo => $db_file, 1408 SQLLogFile => $setup->{log_file}, 1409 SQLUserWhereClause => '"allowed_ip = \'%L\'"', 1410 }, 1411 }, 1412 }; 1413 1414 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1415 $config); 1416 1417 # Open pipes, for use between the parent and child processes. Specifically, 1418 # the child will indicate when it's done with its test by writing a message 1419 # to the parent. 1420 my ($rfh, $wfh); 1421 unless (pipe($rfh, $wfh)) { 1422 die("Can't open pipe: $!"); 1423 } 1424 1425 my $ex; 1426 1427 # Fork child 1428 $self->handle_sigchld(); 1429 defined(my $pid = fork()) or die("Can't fork: $!"); 1430 if ($pid) { 1431 eval { 1432 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1433 1434 # This account should not be allowed to login based on the 1435 # SQLUserWhereClause... 1436 eval { $client->login($setup->{user}, $setup->{passwd}) }; 1437 unless ($@) { 1438 die("Login for user '$setup->{user}' succeeded unexpectedly"); 1439 } 1440 1441 # ...but this one should succeed. 1442 $client->login($user2, $setup->{passwd}); 1443 $client->quit(); 1444 }; 1445 if ($@) { 1446 $ex = $@; 1447 } 1448 1449 $wfh->print("done\n"); 1450 $wfh->flush(); 1451 1452 } else { 1453 eval { server_wait($setup->{config_file}, $rfh) }; 1454 if ($@) { 1455 warn($@); 1456 exit 1; 1457 } 1458 1459 exit 0; 1460 } 1461 1462 # Stop server 1463 server_stop($setup->{pid_file}); 1464 $self->assert_child_ok($pid); 1465 1466 test_cleanup($setup->{log_file}, $ex); 1467} 1468 1469sub sql_group_where_clause_ok { 1470 my $self = shift; 1471 my $tmpdir = $self->{tmpdir}; 1472 1473 my $config_file = "$tmpdir/sqlite.conf"; 1474 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 1475 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 1476 1477 my $log_file = test_get_logfile(); 1478 1479 my $user = 'proftpd'; 1480 my $passwd = 'test'; 1481 my $group = 'ftpd'; 1482 my $home_dir = File::Spec->rel2abs($tmpdir); 1483 my $uid = 500; 1484 my $gid= 500; 1485 1486 my $acl_group = 'whitelist'; 1487 1488 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1489 1490 # Build up sqlite3 command to create users, groups tables and populate them 1491 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1492 1493 if (open(my $fh, "> $db_script")) { 1494 print $fh <<EOS; 1495CREATE TABLE users ( 1496 userid TEXT, 1497 passwd TEXT, 1498 uid INTEGER, 1499 gid INTEGER, 1500 homedir TEXT, 1501 shell TEXT 1502); 1503INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 1504 1505CREATE TABLE groups ( 1506 groupname TEXT, 1507 gid INTEGER, 1508 members TEXT, 1509 allowed TEXT 1510); 1511INSERT INTO groups (groupname, gid, members, allowed) VALUES ('$group', $gid, '$user', 'false'); 1512INSERT INTO groups (groupname, gid, members, allowed) VALUES ('$acl_group', $gid, '$user', 'true'); 1513EOS 1514 1515 unless (close($fh)) { 1516 die("Can't write $db_script: $!"); 1517 } 1518 1519 } else { 1520 die("Can't open $db_script: $!"); 1521 } 1522 1523 my $cmd = "sqlite3 $db_file < $db_script"; 1524 build_db($cmd, $db_script); 1525 1526 # Make sure that, if we're running as root, the database file has 1527 # the permissions/privs set for use by proftpd 1528 if ($< == 0) { 1529 unless (chmod(0666, $db_file)) { 1530 die("Can't set perms on $db_file to 0666: $!"); 1531 } 1532 } 1533 1534 my $config = { 1535 PidFile => $pid_file, 1536 ScoreboardFile => $scoreboard_file, 1537 SystemLog => $log_file, 1538 1539 IfModules => { 1540 'mod_delay.c' => { 1541 DelayEngine => 'off', 1542 }, 1543 1544 'mod_sql.c' => { 1545 AuthOrder => 'mod_sql.c', 1546 1547 SQLAuthenticate => 'users groups', 1548 SQLAuthTypes => 'plaintext', 1549 SQLBackend => 'sqlite3', 1550 SQLConnectInfo => $db_file, 1551 SQLLogFile => $log_file, 1552 SQLGroupWhereClause => '"allowed = \'true\'"', 1553 SQLOptions => 'useNormalizedGroupSchema', 1554 }, 1555 }, 1556 }; 1557 1558 my ($port, $config_user, $config_group) = config_write($config_file, $config); 1559 1560 if (open(my $fh, ">> $config_file")) { 1561 print $fh <<EOC; 1562 1563<Limit LOGIN> 1564 AllowGroup $acl_group 1565 DenyAll 1566</Limit> 1567EOC 1568 unless (close($fh)) { 1569 die("Can't write $config_file: $!"); 1570 } 1571 1572 } else { 1573 die("Can't open $config_file: $!"); 1574 } 1575 1576 # Open pipes, for use between the parent and child processes. Specifically, 1577 # the child will indicate when it's done with its test by writing a message 1578 # to the parent. 1579 my ($rfh, $wfh); 1580 unless (pipe($rfh, $wfh)) { 1581 die("Can't open pipe: $!"); 1582 } 1583 1584 my $ex; 1585 1586 # Fork child 1587 $self->handle_sigchld(); 1588 defined(my $pid = fork()) or die("Can't fork: $!"); 1589 if ($pid) { 1590 eval { 1591 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1592 $client->login($user, $passwd); 1593 $client->quit(); 1594 }; 1595 1596 if ($@) { 1597 $ex = $@; 1598 } 1599 1600 $wfh->print("done\n"); 1601 $wfh->flush(); 1602 1603 } else { 1604 eval { server_wait($config_file, $rfh) }; 1605 if ($@) { 1606 warn($@); 1607 exit 1; 1608 } 1609 1610 exit 0; 1611 } 1612 1613 # Stop server 1614 server_stop($pid_file); 1615 1616 $self->assert_child_ok($pid); 1617 1618 if ($ex) { 1619 test_append_logfile($log_file, $ex); 1620 unlink($log_file); 1621 1622 die($ex); 1623 } 1624 1625 unlink($log_file); 1626} 1627 1628sub sql_bug3149 { 1629 my $self = shift; 1630 my $tmpdir = $self->{tmpdir}; 1631 my $setup = test_setup($tmpdir, 'sqlite'); 1632 1633 my $user2 = 'proftpd2'; 1634 1635 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1636 1637 # Build up sqlite3 command to create users, groups tables and populate them 1638 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1639 1640 if (open(my $fh, "> $db_script")) { 1641 print $fh <<EOS; 1642CREATE TABLE users ( 1643 userid TEXT, 1644 passwd TEXT, 1645 uid INTEGER, 1646 gid INTEGER, 1647 homedir TEXT, 1648 shell TEXT, 1649 host TEXT 1650); 1651INSERT INTO users (userid, passwd, uid, gid, homedir, shell, host) VALUES ('$setup->{user}', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash', 'remotehost'); 1652INSERT INTO users (userid, passwd, uid, gid, homedir, shell, host) VALUES ('$user2', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash', '127.0.0.1'); 1653 1654CREATE TABLE groups ( 1655 groupname TEXT, 1656 gid INTEGER, 1657 members TEXT 1658); 1659INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user},$user2'); 1660EOS 1661 1662 unless (close($fh)) { 1663 die("Can't write $db_script: $!"); 1664 } 1665 1666 } else { 1667 die("Can't open $db_script: $!"); 1668 } 1669 1670 my $cmd = "sqlite3 $db_file < $db_script"; 1671 build_db($cmd, $db_script); 1672 1673 # Make sure that, if we're running as root, the database file has 1674 # the permissions/privs set for use by proftpd 1675 if ($< == 0) { 1676 unless (chmod(0666, $db_file)) { 1677 die("Can't set perms on $db_file to 0666: $!"); 1678 } 1679 } 1680 1681 my $config = { 1682 PidFile => $setup->{pid_file}, 1683 ScoreboardFile => $setup->{scoreboard_file}, 1684 SystemLog => $setup->{log_file}, 1685 TraceLog => $setup->{log_file}, 1686 Trace => 'jot:20 sql:20', 1687 1688 IfModules => { 1689 'mod_delay.c' => { 1690 DelayEngine => 'off', 1691 }, 1692 1693 # Bug#3149 occurred because mod_sql's resolve_short_tag() function 1694 # was not able to resolve %V properly (it was deferencing a bad pointer). 1695 'mod_sql.c' => { 1696 SQLAuthTypes => 'plaintext', 1697 SQLBackend => 'sqlite3', 1698 SQLConnectInfo => $db_file, 1699 SQLLogFile => $setup->{log_file}, 1700 SQLUserWhereClause => '"host=\'%V\'"', 1701 }, 1702 }, 1703 }; 1704 1705 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1706 $config); 1707 1708 # Open pipes, for use between the parent and child processes. Specifically, 1709 # the child will indicate when it's done with its test by writing a message 1710 # to the parent. 1711 my ($rfh, $wfh); 1712 unless (pipe($rfh, $wfh)) { 1713 die("Can't open pipe: $!"); 1714 } 1715 1716 my $ex; 1717 1718 # Fork child 1719 $self->handle_sigchld(); 1720 defined(my $pid = fork()) or die("Can't fork: $!"); 1721 if ($pid) { 1722 eval { 1723 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1724 1725 # This account should not be allowed to login based on the 1726 # SQLUserWhereClause... 1727 eval { $client->login($setup->{user}, $setup->{passwd}) }; 1728 unless ($@) { 1729 die("Login for user '$setup->{user}' succeeded unexpectedly"); 1730 } 1731 1732 # ...but this one should succeed. 1733 $client->login($user2, $setup->{passwd}); 1734 $client->quit(); 1735 }; 1736 if ($@) { 1737 $ex = $@; 1738 } 1739 1740 $wfh->print("done\n"); 1741 $wfh->flush(); 1742 1743 } else { 1744 eval { server_wait($setup->{config_file}, $rfh) }; 1745 if ($@) { 1746 warn($@); 1747 exit 1; 1748 } 1749 1750 exit 0; 1751 } 1752 1753 # Stop server 1754 server_stop($setup->{pid_file}); 1755 $self->assert_child_ok($pid); 1756 1757 test_cleanup($setup->{log_file}, $ex); 1758} 1759 1760sub get_sessions { 1761 my $db_file = shift; 1762 my $where = shift; 1763 1764 my $sql = "SELECT user, ip_addr, timestamp FROM ftpsessions"; 1765 if ($where) { 1766 $sql .= " WHERE $where"; 1767 } 1768 1769 my $cmd = "sqlite3 $db_file \"$sql\""; 1770 1771 if ($ENV{TEST_VERBOSE}) { 1772 print STDERR "Executing sqlite3: $cmd\n"; 1773 } 1774 1775 my $res = join('', `$cmd`); 1776 chomp($res); 1777 1778 # The default sqlite3 delimiter is '|' 1779 return split(/\|/, $res); 1780} 1781 1782sub sql_sqllog { 1783 my $self = shift; 1784 my $tmpdir = $self->{tmpdir}; 1785 my $setup = test_setup($tmpdir, 'sqlite'); 1786 1787 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1788 1789 # Build up sqlite3 command to create users, groups tables and populate them 1790 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1791 1792 if (open(my $fh, "> $db_script")) { 1793 print $fh <<EOS; 1794CREATE TABLE ftpsessions ( 1795 user TEXT, 1796 ip_addr TEXT, 1797 timestamp TEXT 1798); 1799EOS 1800 1801 unless (close($fh)) { 1802 die("Can't write $db_script: $!"); 1803 } 1804 1805 } else { 1806 die("Can't open $db_script: $!"); 1807 } 1808 1809 my $cmd = "sqlite3 $db_file < $db_script"; 1810 build_db($cmd, $db_script); 1811 1812 # Make sure that, if we're running as root, the database file has 1813 # the permissions/privs set for use by proftpd 1814 if ($< == 0) { 1815 unless (chmod(0666, $db_file)) { 1816 die("Can't set perms on $db_file to 0666: $!"); 1817 } 1818 } 1819 1820 my $config = { 1821 PidFile => $setup->{pid_file}, 1822 ScoreboardFile => $setup->{scoreboard_file}, 1823 SystemLog => $setup->{log_file}, 1824 TraceLog => $setup->{log_file}, 1825 Trace => 'jot:20 sql:20', 1826 1827 AuthUserFile => $setup->{auth_user_file}, 1828 AuthGroupFile => $setup->{auth_group_file}, 1829 1830 IfModules => { 1831 'mod_delay.c' => { 1832 DelayEngine => 'off', 1833 }, 1834 1835 'mod_sql.c' => { 1836 SQLEngine => 'log', 1837 SQLBackend => 'sqlite3', 1838 SQLConnectInfo => $db_file, 1839 SQLLogFile => $setup->{log_file}, 1840 SQLNamedQuery => 'session_start FREEFORM "INSERT INTO ftpsessions (user, ip_addr, timestamp) VALUES (\'%u\', \'%L\', \'%{time:%Y-%m-%d %H:%M:%S}\')"', 1841 SQLLog => 'PASS session_start', 1842 }, 1843 }, 1844 }; 1845 1846 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 1847 $config); 1848 1849 # Open pipes, for use between the parent and child processes. Specifically, 1850 # the child will indicate when it's done with its test by writing a message 1851 # to the parent. 1852 my ($rfh, $wfh); 1853 unless (pipe($rfh, $wfh)) { 1854 die("Can't open pipe: $!"); 1855 } 1856 1857 my $ex; 1858 1859 # Fork child 1860 $self->handle_sigchld(); 1861 defined(my $pid = fork()) or die("Can't fork: $!"); 1862 if ($pid) { 1863 eval { 1864 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 1865 $client->login($setup->{user}, $setup->{passwd}); 1866 $client->quit(); 1867 }; 1868 if ($@) { 1869 $ex = $@; 1870 } 1871 1872 $wfh->print("done\n"); 1873 $wfh->flush(); 1874 1875 } else { 1876 eval { server_wait($setup->{config_file}, $rfh) }; 1877 if ($@) { 1878 warn($@); 1879 exit 1; 1880 } 1881 1882 exit 0; 1883 } 1884 1885 # Stop server 1886 server_stop($setup->{pid_file}); 1887 $self->assert_child_ok($pid); 1888 1889 if ($ex) { 1890 test_cleanup($setup->{log_file}, $ex); 1891 } 1892 1893 eval { 1894 my ($login, $ip_addr, $timestamp) = get_sessions($db_file, 1895 "user = \'$setup->{user}\'"); 1896 1897 my $expected = $setup->{user}; 1898 $self->assert($expected eq $login, "Expected '$expected', got '$login'"); 1899 1900 $expected = '127.0.0.1'; 1901 $self->assert($expected eq $ip_addr, 1902 "Expected '$expected', got '$ip_addr'"); 1903 1904 $expected = '\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}'; 1905 $self->assert(qr/$expected/, $timestamp, 1906 "Expected '$expected', got '$timestamp'"); 1907 }; 1908 if ($@) { 1909 $ex = $@; 1910 } 1911 1912 test_cleanup($setup->{log_file}, $ex); 1913} 1914 1915sub sql_sqlite_sqllog_with_chroot { 1916 my $self = shift; 1917 my $tmpdir = $self->{tmpdir}; 1918 1919 my $config_file = "$tmpdir/sqlite.conf"; 1920 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 1921 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 1922 1923 my $log_file = test_get_logfile(); 1924 1925 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 1926 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 1927 1928 my $user = 'proftpd'; 1929 my $passwd = 'test'; 1930 my $group = 'ftpd'; 1931 my $home_dir = File::Spec->rel2abs($tmpdir); 1932 my $uid = 500; 1933 my $gid = 500; 1934 1935 # Make sure that, if we're running as root, that the home directory has 1936 # permissions/privs set for the account we create 1937 if ($< == 0) { 1938 unless (chmod(0755, $home_dir)) { 1939 die("Can't set perms on $home_dir to 0755: $!"); 1940 } 1941 1942 unless (chown($uid, $gid, $home_dir)) { 1943 die("Can't set owner of $home_dir to $uid/$gid: $!"); 1944 } 1945 } 1946 1947 my $tmp_dir = File::Spec->rel2abs("$tmpdir/tmp"); 1948 mkpath($tmp_dir); 1949 if ($< == 0) { 1950 unless (chmod(0777, $tmp_dir)) { 1951 die("Can't set perms on $tmp_dir to 0777: $!"); 1952 } 1953 } 1954 1955 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 1956 '/bin/bash'); 1957 auth_group_write($auth_group_file, '$group', $gid, $user); 1958 1959 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 1960 1961 # Build up sqlite3 command to create users, groups tables and populate them 1962 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 1963 1964 if (open(my $fh, "> $db_script")) { 1965 print $fh <<EOS; 1966CREATE TABLE ftpsessions ( 1967 user TEXT, 1968 ip_addr TEXT, 1969 timestamp TEXT 1970); 1971EOS 1972 1973 unless (close($fh)) { 1974 die("Can't write $db_script: $!"); 1975 } 1976 1977 } else { 1978 die("Can't open $db_script: $!"); 1979 } 1980 1981 my $cmd = "sqlite3 $db_file < $db_script"; 1982 build_db($cmd, $db_script); 1983 1984 # Make sure that, if we're running as root, the database file has 1985 # the permissions/privs set for use by proftpd 1986 if ($< == 0) { 1987 unless (chmod(0666, $db_file)) { 1988 die("Can't set perms on $db_file to 0666: $!"); 1989 } 1990 } 1991 1992 my $config = { 1993 PidFile => $pid_file, 1994 ScoreboardFile => $scoreboard_file, 1995 SystemLog => $log_file, 1996 1997 AuthUserFile => $auth_user_file, 1998 AuthGroupFile => $auth_group_file, 1999 DefaultRoot => '~', 2000 2001 IfModules => { 2002 'mod_delay.c' => { 2003 DelayEngine => 'off', 2004 }, 2005 2006 'mod_sql.c' => { 2007 SQLEngine => 'log', 2008 SQLBackend => 'sqlite3', 2009 SQLConnectInfo => "$db_file foo bar PERCONNECTION", 2010 SQLLogFile => $log_file, 2011 SQLNamedQuery => 'session_start FREEFORM "INSERT INTO ftpsessions (user, ip_addr, timestamp) VALUES (\'%u\', \'%L\', \'%{time:%Y-%m-%d %H:%M:%S}\')"', 2012 SQLLog => 'PASS session_start', 2013 }, 2014 }, 2015 }; 2016 2017 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2018 2019 # Open pipes, for use between the parent and child processes. Specifically, 2020 # the child will indicate when it's done with its test by writing a message 2021 # to the parent. 2022 my ($rfh, $wfh); 2023 unless (pipe($rfh, $wfh)) { 2024 die("Can't open pipe: $!"); 2025 } 2026 2027 my $ex; 2028 2029 # Fork child 2030 $self->handle_sigchld(); 2031 defined(my $pid = fork()) or die("Can't fork: $!"); 2032 if ($pid) { 2033 eval { 2034 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2035 2036 $client->login($user, $passwd); 2037 }; 2038 2039 if ($@) { 2040 $ex = $@; 2041 } 2042 2043 $wfh->print("done\n"); 2044 $wfh->flush(); 2045 2046 } else { 2047 eval { server_wait($config_file, $rfh) }; 2048 if ($@) { 2049 warn($@); 2050 exit 1; 2051 } 2052 2053 exit 0; 2054 } 2055 2056 # Stop server 2057 server_stop($pid_file); 2058 2059 $self->assert_child_ok($pid); 2060 2061 if ($ex) { 2062 test_append_logfile($log_file, $ex); 2063 unlink($log_file); 2064 2065 die($ex); 2066 } 2067 2068 my ($login, $ip_addr, $timestamp) = get_sessions($db_file, 2069 "user = \'$user\'"); 2070 2071 my $expected; 2072 2073 $expected = $user; 2074 $self->assert($expected eq $login, 2075 test_msg("Expected '$expected', got '$login'")); 2076 2077 $expected = '127.0.0.1'; 2078 $self->assert($expected eq $ip_addr, 2079 test_msg("Expected '$expected', got '$ip_addr'")); 2080 2081 $expected = '\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}'; 2082 $self->assert(qr/$expected/, $timestamp, 2083 test_msg("Expected '$expected', got '$timestamp'")); 2084 2085 unlink($log_file); 2086} 2087 2088sub sql_user_info_different_table_names { 2089 my $self = shift; 2090 my $tmpdir = $self->{tmpdir}; 2091 2092 my $config_file = "$tmpdir/sqlite.conf"; 2093 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 2094 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 2095 2096 my $log_file = test_get_logfile(); 2097 2098 my $user = 'proftpd'; 2099 my $passwd = 'test'; 2100 my $group = 'ftpd'; 2101 my $home_dir = File::Spec->rel2abs($tmpdir); 2102 my $uid = 500; 2103 my $gid = 500; 2104 2105 # Make sure that, if we're running as root, that the home directory has 2106 # permissions/privs set for the account we create 2107 if ($< == 0) { 2108 unless (chmod(0755, $home_dir)) { 2109 die("Can't set perms on $home_dir to 0755: $!"); 2110 } 2111 2112 unless (chown($uid, $gid, $home_dir)) { 2113 die("Can't set owner of $home_dir to $uid/$gid: $!"); 2114 } 2115 } 2116 2117 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2118 2119 # Build up sqlite3 command to create users, groups tables and populate them 2120 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2121 2122 if (open(my $fh, "> $db_script")) { 2123 print $fh <<EOS; 2124CREATE TABLE ftpusers ( 2125 userid TEXT, 2126 passwd TEXT, 2127 uid INTEGER, 2128 gid INTEGER, 2129 homedir TEXT, 2130 shell TEXT 2131); 2132INSERT INTO ftpusers (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 2133 2134CREATE TABLE ftpgroups ( 2135 groupname TEXT, 2136 gid INTEGER, 2137 members TEXT 2138); 2139INSERT INTO ftpgroups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2140EOS 2141 2142 unless (close($fh)) { 2143 die("Can't write $db_script: $!"); 2144 } 2145 2146 } else { 2147 die("Can't open $db_script: $!"); 2148 } 2149 2150 my $cmd = "sqlite3 $db_file < $db_script"; 2151 build_db($cmd, $db_script); 2152 2153 # Make sure that, if we're running as root, the database file has 2154 # the permissions/privs set for use by proftpd 2155 if ($< == 0) { 2156 unless (chmod(0666, $db_file)) { 2157 die("Can't set perms on $db_file to 0666: $!"); 2158 } 2159 } 2160 2161 my $config = { 2162 PidFile => $pid_file, 2163 ScoreboardFile => $scoreboard_file, 2164 SystemLog => $log_file, 2165 2166 IfModules => { 2167 'mod_delay.c' => { 2168 DelayEngine => 'off', 2169 }, 2170 2171 'mod_sql.c' => [ 2172 'SQLAuthTypes plaintext', 2173 'SQLBackend sqlite3', 2174 "SQLConnectInfo $db_file", 2175 "SQLLogFile $log_file", 2176 'SQLUserInfo ftpusers userid passwd uid gid homedir shell', 2177 'SQLGroupInfo ftpgroups groupname gid members', 2178 ], 2179 }, 2180 2181 }; 2182 2183 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2184 2185 # Open pipes, for use between the parent and child processes. Specifically, 2186 # the child will indicate when it's done with its test by writing a message 2187 # to the parent. 2188 my ($rfh, $wfh); 2189 unless (pipe($rfh, $wfh)) { 2190 die("Can't open pipe: $!"); 2191 } 2192 2193 my $ex; 2194 2195 # Fork child 2196 $self->handle_sigchld(); 2197 defined(my $pid = fork()) or die("Can't fork: $!"); 2198 if ($pid) { 2199 eval { 2200 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2201 $client->login($user, $passwd); 2202 2203 my $resp_msgs = $client->response_msgs(); 2204 my $nmsgs = scalar(@$resp_msgs); 2205 2206 my $expected; 2207 2208 $expected = 1; 2209 $self->assert($expected == $nmsgs, 2210 test_msg("Expected $expected, got $nmsgs")); 2211 2212 $expected = "User proftpd logged in"; 2213 $self->assert($expected eq $resp_msgs->[0], 2214 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2215 2216 }; 2217 2218 if ($@) { 2219 $ex = $@; 2220 } 2221 2222 $wfh->print("done\n"); 2223 $wfh->flush(); 2224 2225 } else { 2226 eval { server_wait($config_file, $rfh) }; 2227 if ($@) { 2228 warn($@); 2229 exit 1; 2230 } 2231 2232 exit 0; 2233 } 2234 2235 # Stop server 2236 server_stop($pid_file); 2237 2238 $self->assert_child_ok($pid); 2239 2240 if ($ex) { 2241 test_append_logfile($log_file, $ex); 2242 unlink($log_file); 2243 2244 die($ex); 2245 } 2246 2247 unlink($log_file); 2248} 2249 2250sub sql_custom_user_info { 2251 my $self = shift; 2252 my $tmpdir = $self->{tmpdir}; 2253 2254 my $config_file = "$tmpdir/sqlite.conf"; 2255 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 2256 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 2257 2258 my $log_file = test_get_logfile(); 2259 2260 my $user = 'proftpd'; 2261 my $passwd = 'test'; 2262 my $group = 'ftpd'; 2263 my $home_dir = File::Spec->rel2abs($tmpdir); 2264 my $uid = 500; 2265 my $gid = 500; 2266 2267 # Make sure that, if we're running as root, that the home directory has 2268 # permissions/privs set for the account we create 2269 if ($< == 0) { 2270 unless (chmod(0755, $home_dir)) { 2271 die("Can't set perms on $home_dir to 0755: $!"); 2272 } 2273 2274 unless (chown($uid, $gid, $home_dir)) { 2275 die("Can't set owner of $home_dir to $uid/$gid: $!"); 2276 } 2277 } 2278 2279 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2280 2281 # Build up sqlite3 command to create users, groups tables and populate them 2282 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2283 2284 if (open(my $fh, "> $db_script")) { 2285 print $fh <<EOS; 2286CREATE TABLE ftpusers ( 2287 userid TEXT, 2288 passwd TEXT, 2289 uid INTEGER, 2290 gid INTEGER, 2291 homedir TEXT, 2292 shell TEXT, 2293 lastdir TEXT 2294); 2295INSERT INTO ftpusers (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 2296 2297CREATE TABLE groups ( 2298 groupname TEXT, 2299 gid INTEGER, 2300 members TEXT 2301); 2302INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2303EOS 2304 2305 unless (close($fh)) { 2306 die("Can't write $db_script: $!"); 2307 } 2308 2309 } else { 2310 die("Can't open $db_script: $!"); 2311 } 2312 2313 my $cmd = "sqlite3 $db_file < $db_script"; 2314 build_db($cmd, $db_script); 2315 2316 # Make sure that, if we're running as root, the database file has 2317 # the permissions/privs set for use by proftpd 2318 if ($< == 0) { 2319 unless (chmod(0666, $db_file)) { 2320 die("Can't set perms on $db_file to 0666: $!"); 2321 } 2322 } 2323 2324 my $config = { 2325 PidFile => $pid_file, 2326 ScoreboardFile => $scoreboard_file, 2327 SystemLog => $log_file, 2328 2329 IfModules => { 2330 'mod_delay.c' => { 2331 DelayEngine => 'off', 2332 }, 2333 2334 'mod_sql.c' => [ 2335 'SQLAuthTypes plaintext', 2336 'SQLBackend sqlite3', 2337 "SQLConnectInfo $db_file", 2338 "SQLLogFile $log_file", 2339 'SQLNamedQuery get-user-by-name SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers WHERE userid = \'%U\'"', 2340 'SQLNamedQuery get-user-by-id SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers WHERE uid = %{0}"', 2341 'SQLNamedQuery get-user-names SELECT "userid FROM ftpusers"', 2342 'SQLNamedQuery get-all-users SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers"', 2343 'SQLUserInfo custom:/get-user-by-name/get-user-by-id/get-user-names/get-all-users', 2344 ], 2345 }, 2346 2347 2348 }; 2349 2350 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2351 2352 # Open pipes, for use between the parent and child processes. Specifically, 2353 # the child will indicate when it's done with its test by writing a message 2354 # to the parent. 2355 my ($rfh, $wfh); 2356 unless (pipe($rfh, $wfh)) { 2357 die("Can't open pipe: $!"); 2358 } 2359 2360 my $ex; 2361 2362 # Fork child 2363 $self->handle_sigchld(); 2364 defined(my $pid = fork()) or die("Can't fork: $!"); 2365 if ($pid) { 2366 eval { 2367 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2368 2369 $client->login($user, $passwd); 2370 2371 my $resp_msgs = $client->response_msgs(); 2372 my $nmsgs = scalar(@$resp_msgs); 2373 2374 my $expected; 2375 2376 $expected = 1; 2377 $self->assert($expected == $nmsgs, 2378 test_msg("Expected $expected, got $nmsgs")); 2379 2380 $expected = "User proftpd logged in"; 2381 $self->assert($expected eq $resp_msgs->[0], 2382 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2383 2384 }; 2385 2386 if ($@) { 2387 $ex = $@; 2388 } 2389 2390 $wfh->print("done\n"); 2391 $wfh->flush(); 2392 2393 } else { 2394 eval { server_wait($config_file, $rfh) }; 2395 if ($@) { 2396 warn($@); 2397 exit 1; 2398 } 2399 2400 exit 0; 2401 } 2402 2403 # Stop server 2404 server_stop($pid_file); 2405 2406 $self->assert_child_ok($pid); 2407 2408 if ($ex) { 2409 test_append_logfile($log_file, $ex); 2410 unlink($log_file); 2411 2412 die($ex); 2413 } 2414 2415 unlink($log_file); 2416} 2417 2418sub sql_custom_user_info_null_ids { 2419 my $self = shift; 2420 my $tmpdir = $self->{tmpdir}; 2421 2422 my $config_file = "$tmpdir/sqlite.conf"; 2423 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 2424 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 2425 2426 my $log_file = test_get_logfile(); 2427 2428 my $user = 'proftpd'; 2429 my $passwd = 'test'; 2430 my $group = 'ftpd'; 2431 my $home_dir = File::Spec->rel2abs($tmpdir); 2432 my $uid = 500; 2433 my $gid = 500; 2434 2435 # Make sure that, if we're running as root, that the home directory has 2436 # permissions/privs set for the account we create 2437 if ($< == 0) { 2438 unless (chmod(0755, $home_dir)) { 2439 die("Can't set perms on $home_dir to 0755: $!"); 2440 } 2441 2442 unless (chown($uid, $gid, $home_dir)) { 2443 die("Can't set owner of $home_dir to $uid/$gid: $!"); 2444 } 2445 } 2446 2447 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2448 2449 # Build up sqlite3 command to create users, groups tables and populate them 2450 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2451 2452 if (open(my $fh, "> $db_script")) { 2453 # Note: by inserting/using NULL for the uid and gid columns, we will 2454 # force mod_sql to use the SQLDefaultUID/SQLDefaultGID values (rather than 2455 # e.g. segfaulting). 2456 2457 print $fh <<EOS; 2458CREATE TABLE ftpusers ( 2459 userid TEXT, 2460 passwd TEXT, 2461 uid INTEGER, 2462 gid INTEGER, 2463 homedir TEXT, 2464 shell TEXT, 2465 lastdir TEXT 2466); 2467INSERT INTO ftpusers (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', NULL, NULL, '$home_dir', '/bin/bash'); 2468 2469CREATE TABLE groups ( 2470 groupname TEXT, 2471 gid INTEGER, 2472 members TEXT 2473); 2474INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2475EOS 2476 2477 unless (close($fh)) { 2478 die("Can't write $db_script: $!"); 2479 } 2480 2481 } else { 2482 die("Can't open $db_script: $!"); 2483 } 2484 2485 my $cmd = "sqlite3 $db_file < $db_script"; 2486 build_db($cmd, $db_script); 2487 2488 # Make sure that, if we're running as root, the database file has 2489 # the permissions/privs set for use by proftpd 2490 if ($< == 0) { 2491 unless (chmod(0666, $db_file)) { 2492 die("Can't set perms on $db_file to 0666: $!"); 2493 } 2494 } 2495 2496 my $config = { 2497 PidFile => $pid_file, 2498 ScoreboardFile => $scoreboard_file, 2499 SystemLog => $log_file, 2500 2501 IfModules => { 2502 'mod_delay.c' => { 2503 DelayEngine => 'off', 2504 }, 2505 2506 'mod_sql.c' => [ 2507 'SQLAuthTypes plaintext', 2508 'SQLBackend sqlite3', 2509 "SQLConnectInfo $db_file", 2510 "SQLLogFile $log_file", 2511 'SQLNamedQuery get-user-by-name SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers WHERE userid = \'%U\'"', 2512 'SQLNamedQuery get-user-by-id SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers WHERE uid = %{0}"', 2513 'SQLNamedQuery get-user-names SELECT "userid FROM ftpusers"', 2514 'SQLNamedQuery get-all-users SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers"', 2515 'SQLUserInfo custom:/get-user-by-name/get-user-by-id/get-user-names/get-all-users', 2516 ], 2517 }, 2518 2519 2520 }; 2521 2522 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2523 2524 # Open pipes, for use between the parent and child processes. Specifically, 2525 # the child will indicate when it's done with its test by writing a message 2526 # to the parent. 2527 my ($rfh, $wfh); 2528 unless (pipe($rfh, $wfh)) { 2529 die("Can't open pipe: $!"); 2530 } 2531 2532 my $ex; 2533 2534 # Fork child 2535 $self->handle_sigchld(); 2536 defined(my $pid = fork()) or die("Can't fork: $!"); 2537 if ($pid) { 2538 eval { 2539 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2540 $client->login($user, $passwd); 2541 2542 my $resp_msgs = $client->response_msgs(); 2543 my $nmsgs = scalar(@$resp_msgs); 2544 2545 my $expected; 2546 2547 $expected = 1; 2548 $self->assert($expected == $nmsgs, 2549 test_msg("Expected $expected, got $nmsgs")); 2550 2551 $expected = "User proftpd logged in"; 2552 $self->assert($expected eq $resp_msgs->[0], 2553 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2554 2555 }; 2556 2557 if ($@) { 2558 $ex = $@; 2559 } 2560 2561 $wfh->print("done\n"); 2562 $wfh->flush(); 2563 2564 } else { 2565 eval { server_wait($config_file, $rfh) }; 2566 if ($@) { 2567 warn($@); 2568 exit 1; 2569 } 2570 2571 exit 0; 2572 } 2573 2574 # Stop server 2575 server_stop($pid_file); 2576 2577 $self->assert_child_ok($pid); 2578 2579 if ($ex) { 2580 test_append_logfile($log_file, $ex); 2581 unlink($log_file); 2582 2583 die($ex); 2584 } 2585 2586 unlink($log_file); 2587} 2588 2589sub sql_userset_bug2434 { 2590 my $self = shift; 2591 my $tmpdir = $self->{tmpdir}; 2592 2593 my $config_file = "$tmpdir/sqlite.conf"; 2594 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 2595 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 2596 2597 my $log_file = test_get_logfile(); 2598 2599 my $user = 'proftpd'; 2600 my $passwd = 'test'; 2601 my $group = 'ftpd'; 2602 my $home_dir = File::Spec->rel2abs($tmpdir); 2603 my $uid = 500; 2604 my $gid = 500; 2605 2606 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2607 2608 # Build up sqlite3 command to create users, groups tables and populate them 2609 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2610 2611 if (open(my $fh, "> $db_script")) { 2612 print $fh <<EOS; 2613CREATE TABLE ftpusers ( 2614 userid TEXT, 2615 passwd TEXT, 2616 uid INTEGER, 2617 gid INTEGER, 2618 homedir TEXT, 2619 shell TEXT, 2620 lastdir TEXT 2621); 2622INSERT INTO ftpusers (userid, passwd, uid, gid, homedir, shell) VALUES ('foo', '$passwd', 500, 500, '$home_dir', '/bin/bash'); 2623INSERT INTO ftpusers (userid, passwd, uid, gid, homedir, shell) VALUES ('bar', '$passwd', 500, 500, '$home_dir', '/bin/bash'); 2624INSERT INTO ftpusers (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 2625 2626CREATE TABLE groups ( 2627 groupname TEXT, 2628 gid INTEGER, 2629 members TEXT 2630); 2631INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2632EOS 2633 2634 unless (close($fh)) { 2635 die("Can't write $db_script: $!"); 2636 } 2637 2638 } else { 2639 die("Can't open $db_script: $!"); 2640 } 2641 2642 my $cmd = "sqlite3 $db_file < $db_script"; 2643 build_db($cmd, $db_script); 2644 2645 # Make sure that, if we're running as root, the database file has 2646 # the permissions/privs set for use by proftpd 2647 if ($< == 0) { 2648 unless (chmod(0666, $db_file)) { 2649 die("Can't set perms on $db_file to 0666: $!"); 2650 } 2651 } 2652 2653 my $config = { 2654 PidFile => $pid_file, 2655 ScoreboardFile => $scoreboard_file, 2656 SystemLog => $log_file, 2657 2658 # This bug requires that a chroot occur in order to be tickled. 2659 DefaultRoot => '~', 2660 2661 IfModules => { 2662 'mod_delay.c' => { 2663 DelayEngine => 'off', 2664 }, 2665 2666 'mod_sql.c' => [ 2667 'SQLAuthenticate users userset groups', 2668 'SQLAuthTypes plaintext', 2669 'SQLBackend sqlite3', 2670 "SQLConnectInfo $db_file", 2671 "SQLLogFile $log_file", 2672 'SQLNamedQuery get-all-users SELECT "userid FROM ftpusers"', 2673 'SQLNamedQuery get-user-by-name SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers WHERE userid = \'%U\'"', 2674 'SQLNamedQuery get-user-by-id SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers WHERE uid = %{0}"', 2675 'SQLUserInfo custom:/get-user-by-name/get-user-by-id/get-all-users', 2676 ], 2677 }, 2678 }; 2679 2680 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2681 2682 # Open pipes, for use between the parent and child processes. Specifically, 2683 # the child will indicate when it's done with its test by writing a message 2684 # to the parent. 2685 my ($rfh, $wfh); 2686 unless (pipe($rfh, $wfh)) { 2687 die("Can't open pipe: $!"); 2688 } 2689 2690 my $ex; 2691 2692 # Fork child 2693 $self->handle_sigchld(); 2694 defined(my $pid = fork()) or die("Can't fork: $!"); 2695 if ($pid) { 2696 eval { 2697 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2698 2699 $client->login($user, $passwd); 2700 2701 my $resp_msgs = $client->response_msgs(); 2702 my $nmsgs = scalar(@$resp_msgs); 2703 2704 my $expected; 2705 2706 $expected = 1; 2707 $self->assert($expected == $nmsgs, 2708 test_msg("Expected $expected, got $nmsgs")); 2709 2710 $expected = "User proftpd logged in"; 2711 $self->assert($expected eq $resp_msgs->[0], 2712 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2713 2714 }; 2715 2716 if ($@) { 2717 $ex = $@; 2718 } 2719 2720 $wfh->print("done\n"); 2721 $wfh->flush(); 2722 2723 } else { 2724 eval { server_wait($config_file, $rfh) }; 2725 if ($@) { 2726 warn($@); 2727 exit 1; 2728 } 2729 2730 exit 0; 2731 } 2732 2733 # Stop server 2734 server_stop($pid_file); 2735 2736 $self->assert_child_ok($pid); 2737 2738 if ($ex) { 2739 test_append_logfile($log_file, $ex); 2740 unlink($log_file); 2741 2742 die($ex); 2743 } 2744 2745 unlink($log_file); 2746} 2747 2748sub sql_usersetfast_bug2434 { 2749 my $self = shift; 2750 my $tmpdir = $self->{tmpdir}; 2751 2752 my $config_file = "$tmpdir/sqlite.conf"; 2753 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 2754 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 2755 2756 my $log_file = test_get_logfile(); 2757 2758 my $user = 'proftpd'; 2759 my $passwd = 'test'; 2760 my $group = 'ftpd'; 2761 my $home_dir = File::Spec->rel2abs($tmpdir); 2762 my $uid = 500; 2763 my $gid = 500; 2764 2765 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2766 2767 # Build up sqlite3 command to create users, groups tables and populate them 2768 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2769 2770 if (open(my $fh, "> $db_script")) { 2771 print $fh <<EOS; 2772CREATE TABLE ftpusers ( 2773 userid TEXT, 2774 passwd TEXT, 2775 uid INTEGER, 2776 gid INTEGER, 2777 homedir TEXT, 2778 shell TEXT, 2779 lastdir TEXT 2780); 2781INSERT INTO ftpusers (userid, passwd, uid, gid, homedir, shell) VALUES ('foo', '$passwd', 500, 500, '$home_dir', '/bin/bash'); 2782INSERT INTO ftpusers (userid, passwd, uid, gid, homedir, shell) VALUES ('bar', '$passwd', 500, 500, '$home_dir', '/bin/bash'); 2783INSERT INTO ftpusers (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 build_db($cmd, $db_script); 2803 2804 # Make sure that, if we're running as root, the database file has 2805 # the permissions/privs set for use by proftpd 2806 if ($< == 0) { 2807 unless (chmod(0666, $db_file)) { 2808 die("Can't set perms on $db_file to 0666: $!"); 2809 } 2810 } 2811 2812 my $config = { 2813 PidFile => $pid_file, 2814 ScoreboardFile => $scoreboard_file, 2815 SystemLog => $log_file, 2816 2817 # This bug requires that a chroot occur in order to be tickled. 2818 DefaultRoot => '~', 2819 2820 IfModules => { 2821 'mod_delay.c' => { 2822 DelayEngine => 'off', 2823 }, 2824 2825 'mod_sql.c' => [ 2826 'SQLAuthenticate users usersetfast groups', 2827 'SQLAuthTypes plaintext', 2828 'SQLBackend sqlite3', 2829 "SQLConnectInfo $db_file", 2830 "SQLLogFile $log_file", 2831 'SQLNamedQuery get-all-usernames SELECT "userid FROM ftpusers"', 2832 'SQLNamedQuery get-all-users SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers"', 2833 'SQLNamedQuery get-user-by-name SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers WHERE userid = \'%U\'"', 2834 'SQLNamedQuery get-user-by-id SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers WHERE uid = %{0}"', 2835 'SQLUserInfo custom:/get-user-by-name/get-user-by-id/get-all-usernames/get-all-users', 2836 ], 2837 }, 2838 }; 2839 2840 my ($port, $config_user, $config_group) = config_write($config_file, $config); 2841 2842 # Open pipes, for use between the parent and child processes. Specifically, 2843 # the child will indicate when it's done with its test by writing a message 2844 # to the parent. 2845 my ($rfh, $wfh); 2846 unless (pipe($rfh, $wfh)) { 2847 die("Can't open pipe: $!"); 2848 } 2849 2850 my $ex; 2851 2852 # Fork child 2853 $self->handle_sigchld(); 2854 defined(my $pid = fork()) or die("Can't fork: $!"); 2855 if ($pid) { 2856 eval { 2857 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 2858 2859 $client->login($user, $passwd); 2860 2861 my $resp_msgs = $client->response_msgs(); 2862 my $nmsgs = scalar(@$resp_msgs); 2863 2864 my $expected; 2865 2866 $expected = 1; 2867 $self->assert($expected == $nmsgs, 2868 test_msg("Expected $expected, got $nmsgs")); 2869 2870 $expected = "User proftpd logged in"; 2871 $self->assert($expected eq $resp_msgs->[0], 2872 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 2873 2874 }; 2875 2876 if ($@) { 2877 $ex = $@; 2878 } 2879 2880 $wfh->print("done\n"); 2881 $wfh->flush(); 2882 2883 } else { 2884 eval { server_wait($config_file, $rfh) }; 2885 if ($@) { 2886 warn($@); 2887 exit 1; 2888 } 2889 2890 exit 0; 2891 } 2892 2893 # Stop server 2894 server_stop($pid_file); 2895 2896 $self->assert_child_ok($pid); 2897 2898 if ($ex) { 2899 test_append_logfile($log_file, $ex); 2900 unlink($log_file); 2901 2902 die($ex); 2903 } 2904 2905 unlink($log_file); 2906} 2907 2908sub sql_custom_group_info_bug3043 { 2909 my $self = shift; 2910 my $tmpdir = $self->{tmpdir}; 2911 2912 my $config_file = "$tmpdir/sqlite.conf"; 2913 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 2914 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 2915 2916 my $log_file = test_get_logfile(); 2917 2918 my $user = 'proftpd'; 2919 my $passwd = 'test'; 2920 my $group = 'ftpd'; 2921 my $home_dir = File::Spec->rel2abs($tmpdir); 2922 my $uid = 500; 2923 my $gid = 500; 2924 2925 # Make sure that, if we're running as root, that the home directory has 2926 # permissions/privs set for the account we create 2927 if ($< == 0) { 2928 unless (chmod(0755, $home_dir)) { 2929 die("Can't set perms on $home_dir to 0755: $!"); 2930 } 2931 2932 unless (chown($uid, $gid, $home_dir)) { 2933 die("Can't set owner of $home_dir to $uid/$gid: $!"); 2934 } 2935 } 2936 2937 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 2938 2939 # Build up sqlite3 command to create users, groups tables and populate them 2940 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 2941 2942 if (open(my $fh, "> $db_script")) { 2943 print $fh <<EOS; 2944CREATE TABLE users ( 2945 userid TEXT, 2946 passwd TEXT, 2947 uid INTEGER, 2948 gid INTEGER, 2949 homedir TEXT, 2950 shell TEXT 2951); 2952INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 2953 2954CREATE TABLE ftpgroups ( 2955 groupname TEXT, 2956 gid INTEGER, 2957 members TEXT 2958); 2959INSERT INTO ftpgroups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 2960EOS 2961 2962 unless (close($fh)) { 2963 die("Can't write $db_script: $!"); 2964 } 2965 2966 } else { 2967 die("Can't open $db_script: $!"); 2968 } 2969 2970 my $cmd = "sqlite3 $db_file < $db_script"; 2971 build_db($cmd, $db_script); 2972 2973 # Make sure that, if we're running as root, the database file has 2974 # the permissions/privs set for use by proftpd 2975 if ($< == 0) { 2976 unless (chmod(0666, $db_file)) { 2977 die("Can't set perms on $db_file to 0666: $!"); 2978 } 2979 } 2980 2981 my $config = { 2982 PidFile => $pid_file, 2983 ScoreboardFile => $scoreboard_file, 2984 SystemLog => $log_file, 2985 2986 IfModules => { 2987 'mod_delay.c' => { 2988 DelayEngine => 'off', 2989 }, 2990 2991 'mod_sql.c' => [ 2992 'SQLMinID 0', 2993 'SQLAuthenticate users groups', 2994 'SQLAuthTypes plaintext', 2995 'SQLBackend sqlite3', 2996 "SQLConnectInfo $db_file", 2997 "SQLLogFile $log_file", 2998 'SQLNamedQuery get-group-by-name SELECT "groupname, gid, members FROM ftpgroups WHERE groupname = \'%{0}\'"', 2999 'SQLNamedQuery get-group-by-id SELECT "groupname, gid, members FROM ftpgroups WHERE gid = %{0}"', 3000 'SQLNamedQuery get-members-by-user SELECT "members FROM ftpgroups WHERE (members LIKE \'%%,%{0},%%\' OR members LIKE \'%{0},%%\' OR members LIKE \'%%,%{0}\')"', 3001 'SQLGroupInfo custom:/get-group-by-name/get-group-by-id/get-members-by-user', 3002 ], 3003 }, 3004 }; 3005 3006 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3007 3008 # Open pipes, for use between the parent and child processes. Specifically, 3009 # the child will indicate when it's done with its test by writing a message 3010 # to the parent. 3011 my ($rfh, $wfh); 3012 unless (pipe($rfh, $wfh)) { 3013 die("Can't open pipe: $!"); 3014 } 3015 3016 my $ex; 3017 3018 # Fork child 3019 $self->handle_sigchld(); 3020 defined(my $pid = fork()) or die("Can't fork: $!"); 3021 if ($pid) { 3022 eval { 3023 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3024 3025 $client->login($user, $passwd); 3026 3027 my $resp_msgs = $client->response_msgs(); 3028 my $nmsgs = scalar(@$resp_msgs); 3029 3030 my $expected; 3031 3032 $expected = 1; 3033 $self->assert($expected == $nmsgs, 3034 test_msg("Expected $expected, got $nmsgs")); 3035 3036 $expected = "User proftpd logged in"; 3037 $self->assert($expected eq $resp_msgs->[0], 3038 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 3039 3040 }; 3041 3042 if ($@) { 3043 $ex = $@; 3044 } 3045 3046 $wfh->print("done\n"); 3047 $wfh->flush(); 3048 3049 } else { 3050 eval { server_wait($config_file, $rfh) }; 3051 if ($@) { 3052 warn($@); 3053 exit 1; 3054 } 3055 3056 exit 0; 3057 } 3058 3059 # Stop server 3060 server_stop($pid_file); 3061 3062 $self->assert_child_ok($pid); 3063 3064 if ($ex) { 3065 test_append_logfile($log_file, $ex); 3066 unlink($log_file); 3067 3068 die($ex); 3069 } 3070 3071 unlink($log_file); 3072} 3073 3074sub sql_groupset_bug3043 { 3075 my $self = shift; 3076 my $tmpdir = $self->{tmpdir}; 3077 3078 my $config_file = "$tmpdir/sqlite.conf"; 3079 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 3080 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 3081 3082 my $log_file = test_get_logfile(); 3083 3084 my $user = 'proftpd'; 3085 my $passwd = 'test'; 3086 my $group = 'ftpd'; 3087 my $home_dir = File::Spec->rel2abs($tmpdir); 3088 my $uid = 500; 3089 my $gid = 500; 3090 3091 # Make sure that, if we're running as root, that the home directory has 3092 # permissions/privs set for the account we create 3093 if ($< == 0) { 3094 unless (chmod(0755, $home_dir)) { 3095 die("Can't set perms on $home_dir to 0755: $!"); 3096 } 3097 3098 unless (chown($uid, $gid, $home_dir)) { 3099 die("Can't set owner of $home_dir to $uid/$gid: $!"); 3100 } 3101 } 3102 3103 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3104 3105 # Build up sqlite3 command to create users, groups tables and populate them 3106 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3107 3108 if (open(my $fh, "> $db_script")) { 3109 print $fh <<EOS; 3110CREATE TABLE users ( 3111 userid TEXT, 3112 passwd TEXT, 3113 uid INTEGER, 3114 gid INTEGER, 3115 homedir TEXT, 3116 shell TEXT 3117); 3118INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 3119 3120CREATE TABLE ftpgroups ( 3121 groupname TEXT, 3122 gid INTEGER, 3123 members TEXT 3124); 3125INSERT INTO ftpgroups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 3126EOS 3127 3128 unless (close($fh)) { 3129 die("Can't write $db_script: $!"); 3130 } 3131 3132 } else { 3133 die("Can't open $db_script: $!"); 3134 } 3135 3136 my $cmd = "sqlite3 $db_file < $db_script"; 3137 build_db($cmd, $db_script); 3138 3139 # Make sure that, if we're running as root, the database file has 3140 # the permissions/privs set for use by proftpd 3141 if ($< == 0) { 3142 unless (chmod(0666, $db_file)) { 3143 die("Can't set perms on $db_file to 0666: $!"); 3144 } 3145 } 3146 3147 my $config = { 3148 PidFile => $pid_file, 3149 ScoreboardFile => $scoreboard_file, 3150 SystemLog => $log_file, 3151 3152 IfModules => { 3153 'mod_delay.c' => { 3154 DelayEngine => 'off', 3155 }, 3156 3157 'mod_sql.c' => [ 3158 'SQLMinID 0', 3159 'SQLAuthenticate users groups groupset', 3160 'SQLAuthTypes plaintext', 3161 'SQLBackend sqlite3', 3162 "SQLConnectInfo $db_file", 3163 "SQLLogFile $log_file", 3164 'SQLNamedQuery get-group-by-name SELECT "groupname, gid, members FROM ftpgroups WHERE groupname = \'%{0}\'"', 3165 'SQLNamedQuery get-group-by-id SELECT "groupname, gid, members FROM ftpgroups WHERE gid = %{0}"', 3166 'SQLNamedQuery get-members-by-user SELECT "members FROM ftpgroups WHERE (members LIKE \'%%,%{0},%%\' OR members LIKE \'%{0},%%\' OR members LIKE \'%%,%{0}\')"', 3167 'SQLNamedQuery get-all-groupnames SELECT "groupname FROM ftpgroups"', 3168 'SQLGroupInfo custom:/get-group-by-name/get-group-by-id/get-members-by-user/get-all-groupnames', 3169 ], 3170 }, 3171 }; 3172 3173 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3174 3175 # Open pipes, for use between the parent and child processes. Specifically, 3176 # the child will indicate when it's done with its test by writing a message 3177 # to the parent. 3178 my ($rfh, $wfh); 3179 unless (pipe($rfh, $wfh)) { 3180 die("Can't open pipe: $!"); 3181 } 3182 3183 my $ex; 3184 3185 # Fork child 3186 $self->handle_sigchld(); 3187 defined(my $pid = fork()) or die("Can't fork: $!"); 3188 if ($pid) { 3189 eval { 3190 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3191 3192 $client->login($user, $passwd); 3193 3194 my $resp_msgs = $client->response_msgs(); 3195 my $nmsgs = scalar(@$resp_msgs); 3196 3197 my $expected; 3198 3199 $expected = 1; 3200 $self->assert($expected == $nmsgs, 3201 test_msg("Expected $expected, got $nmsgs")); 3202 3203 $expected = "User proftpd logged in"; 3204 $self->assert($expected eq $resp_msgs->[0], 3205 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 3206 3207 }; 3208 3209 if ($@) { 3210 $ex = $@; 3211 } 3212 3213 $wfh->print("done\n"); 3214 $wfh->flush(); 3215 3216 } else { 3217 eval { server_wait($config_file, $rfh) }; 3218 if ($@) { 3219 warn($@); 3220 exit 1; 3221 } 3222 3223 exit 0; 3224 } 3225 3226 # Stop server 3227 server_stop($pid_file); 3228 3229 $self->assert_child_ok($pid); 3230 3231 if ($ex) { 3232 test_append_logfile($log_file, $ex); 3233 unlink($log_file); 3234 3235 die($ex); 3236 } 3237 3238 unlink($log_file); 3239} 3240 3241sub sql_groupsetfast_bug3043 { 3242 my $self = shift; 3243 my $tmpdir = $self->{tmpdir}; 3244 3245 my $config_file = "$tmpdir/sqlite.conf"; 3246 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 3247 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 3248 3249 my $log_file = test_get_logfile(); 3250 3251 my $user = 'proftpd'; 3252 my $passwd = 'test'; 3253 my $group = 'ftpd'; 3254 my $home_dir = File::Spec->rel2abs($tmpdir); 3255 my $uid = 500; 3256 my $gid = 500; 3257 3258 # Make sure that, if we're running as root, that the home directory has 3259 # permissions/privs set for the account we create 3260 if ($< == 0) { 3261 unless (chmod(0755, $home_dir)) { 3262 die("Can't set perms on $home_dir to 0755: $!"); 3263 } 3264 3265 unless (chown($uid, $gid, $home_dir)) { 3266 die("Can't set owner of $home_dir to $uid/$gid: $!"); 3267 } 3268 } 3269 3270 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3271 3272 # Build up sqlite3 command to create users, groups tables and populate them 3273 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3274 3275 if (open(my $fh, "> $db_script")) { 3276 print $fh <<EOS; 3277CREATE TABLE users ( 3278 userid TEXT, 3279 passwd TEXT, 3280 uid INTEGER, 3281 gid INTEGER, 3282 homedir TEXT, 3283 shell TEXT 3284); 3285INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 3286 3287CREATE TABLE ftpgroups ( 3288 groupname TEXT, 3289 gid INTEGER, 3290 members TEXT 3291); 3292INSERT INTO ftpgroups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 3293EOS 3294 3295 unless (close($fh)) { 3296 die("Can't write $db_script: $!"); 3297 } 3298 3299 } else { 3300 die("Can't open $db_script: $!"); 3301 } 3302 3303 my $cmd = "sqlite3 $db_file < $db_script"; 3304 build_db($cmd, $db_script); 3305 3306 # Make sure that, if we're running as root, the database file has 3307 # the permissions/privs set for use by proftpd 3308 if ($< == 0) { 3309 unless (chmod(0666, $db_file)) { 3310 die("Can't set perms on $db_file to 0666: $!"); 3311 } 3312 } 3313 3314 my $config = { 3315 PidFile => $pid_file, 3316 ScoreboardFile => $scoreboard_file, 3317 SystemLog => $log_file, 3318 3319 IfModules => { 3320 'mod_delay.c' => { 3321 DelayEngine => 'off', 3322 }, 3323 3324 'mod_sql.c' => [ 3325 'SQLMinID 0', 3326 'SQLAuthenticate users groups groupsetfast', 3327 'SQLAuthTypes plaintext', 3328 'SQLBackend sqlite3', 3329 "SQLConnectInfo $db_file", 3330 "SQLLogFile $log_file", 3331 'SQLNamedQuery get-group-by-name SELECT "groupname, gid, members FROM ftpgroups WHERE groupname = \'%{0}\'"', 3332 'SQLNamedQuery get-group-by-id SELECT "groupname, gid, members FROM ftpgroups WHERE gid = %{0}"', 3333 'SQLNamedQuery get-group-by-member SELECT "groupname, gid, members FROM ftpgroups WHERE (members LIKE \'%%,%{0},%%\' OR members LIKE \'%{0},%%\' OR members LIKE \'%%,%{0}\')"', 3334 'SQLNamedQuery get-all-groupnames SELECT "groupname FROM ftpgroups"', 3335 'SQLNamedQuery get-all-groups SELECT "groupname, gid, members FROM ftpgroups"', 3336 'SQLGroupInfo custom:/get-group-by-name/get-group-by-id/get-group-by-member/get-all-groupnames/get-all-groups', 3337 ], 3338 }, 3339 }; 3340 3341 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3342 3343 # Open pipes, for use between the parent and child processes. Specifically, 3344 # the child will indicate when it's done with its test by writing a message 3345 # to the parent. 3346 my ($rfh, $wfh); 3347 unless (pipe($rfh, $wfh)) { 3348 die("Can't open pipe: $!"); 3349 } 3350 3351 my $ex; 3352 3353 # Fork child 3354 $self->handle_sigchld(); 3355 defined(my $pid = fork()) or die("Can't fork: $!"); 3356 if ($pid) { 3357 eval { 3358 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3359 3360 $client->login($user, $passwd); 3361 3362 my $resp_msgs = $client->response_msgs(); 3363 my $nmsgs = scalar(@$resp_msgs); 3364 3365 my $expected; 3366 3367 $expected = 1; 3368 $self->assert($expected == $nmsgs, 3369 test_msg("Expected $expected, got $nmsgs")); 3370 3371 $expected = "User proftpd logged in"; 3372 $self->assert($expected eq $resp_msgs->[0], 3373 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 3374 3375 }; 3376 3377 if ($@) { 3378 $ex = $@; 3379 } 3380 3381 $wfh->print("done\n"); 3382 $wfh->flush(); 3383 3384 } else { 3385 eval { server_wait($config_file, $rfh) }; 3386 if ($@) { 3387 warn($@); 3388 exit 1; 3389 } 3390 3391 exit 0; 3392 } 3393 3394 # Stop server 3395 server_stop($pid_file); 3396 3397 $self->assert_child_ok($pid); 3398 3399 if ($ex) { 3400 test_append_logfile($log_file, $ex); 3401 unlink($log_file); 3402 3403 die($ex); 3404 } 3405 3406 unlink($log_file); 3407} 3408 3409sub get_renames { 3410 my $db_file = shift; 3411 my $where = shift; 3412 3413 my $sql = "SELECT user, ip_addr, rename_from FROM ftpsessions"; 3414 if ($where) { 3415 $sql .= " WHERE $where"; 3416 } 3417 3418 my $cmd = "sqlite3 $db_file \"$sql\""; 3419 3420 if ($ENV{TEST_VERBOSE}) { 3421 print STDERR "Executing sqlite3: $cmd\n"; 3422 } 3423 3424 my $res = join('', `$cmd`); 3425 chomp($res); 3426 3427 # The default sqlite3 delimiter is '|' 3428 return split(/\|/, $res); 3429} 3430 3431sub sql_sqllog_var_w { 3432 my $self = shift; 3433 my $tmpdir = $self->{tmpdir}; 3434 3435 my $config_file = "$tmpdir/sqlite.conf"; 3436 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 3437 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 3438 3439 my $log_file = test_get_logfile(); 3440 3441 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 3442 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 3443 3444 my $user = 'proftpd'; 3445 my $passwd = 'test'; 3446 my $group = 'ftpd'; 3447 my $home_dir = File::Spec->rel2abs($tmpdir); 3448 my $uid = 500; 3449 my $gid = 500; 3450 3451 # Make sure that, if we're running as root, that the home directory has 3452 # permissions/privs set for the account we create 3453 if ($< == 0) { 3454 unless (chmod(0755, $home_dir)) { 3455 die("Can't set perms on $home_dir to 0755: $!"); 3456 } 3457 3458 unless (chown($uid, $gid, $home_dir)) { 3459 die("Can't set owner of $home_dir to $uid/$gid: $!"); 3460 } 3461 } 3462 3463 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 3464 '/bin/bash'); 3465 auth_group_write($auth_group_file, $group, $gid, $user); 3466 3467 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3468 3469 # Build up sqlite3 command to create users, groups tables and populate them 3470 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3471 3472 if (open(my $fh, "> $db_script")) { 3473 print $fh <<EOS; 3474CREATE TABLE ftpsessions ( 3475 user TEXT, 3476 ip_addr TEXT, 3477 rename_from TEXT 3478); 3479EOS 3480 3481 unless (close($fh)) { 3482 die("Can't write $db_script: $!"); 3483 } 3484 3485 } else { 3486 die("Can't open $db_script: $!"); 3487 } 3488 3489 my $cmd = "sqlite3 $db_file < $db_script"; 3490 build_db($cmd, $db_script); 3491 3492 # Make sure that, if we're running as root, the database file has 3493 # the permissions/privs set for use by proftpd 3494 if ($< == 0) { 3495 unless (chmod(0666, $db_file)) { 3496 die("Can't set perms on $db_file to 0666: $!"); 3497 } 3498 } 3499 3500 my $src_file = File::Spec->rel2abs("$tmpdir/test.txt"); 3501 if (open(my $fh, "> $src_file")) { 3502 close($fh); 3503 3504 } else { 3505 die("Can't open $src_file: $!"); 3506 } 3507 3508 my $dst_file = File::Spec->rel2abs("$tmpdir/foo.txt"); 3509 3510 my $config = { 3511 PidFile => $pid_file, 3512 ScoreboardFile => $scoreboard_file, 3513 SystemLog => $log_file, 3514 3515 AuthUserFile => $auth_user_file, 3516 AuthGroupFile => $auth_group_file, 3517 3518 IfModules => { 3519 'mod_delay.c' => { 3520 DelayEngine => 'off', 3521 }, 3522 3523 'mod_sql.c' => { 3524 SQLEngine => 'log', 3525 SQLBackend => 'sqlite3', 3526 SQLConnectInfo => $db_file, 3527 SQLLogFile => $log_file, 3528 SQLNamedQuery => 'rename FREEFORM "INSERT INTO ftpsessions (user, ip_addr, rename_from) VALUES (\'%u\', \'%L\', \'%w\')"', 3529 SQLLog => 'RNTO rename', 3530 }, 3531 }, 3532 }; 3533 3534 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3535 3536 # Open pipes, for use between the parent and child processes. Specifically, 3537 # the child will indicate when it's done with its test by writing a message 3538 # to the parent. 3539 my ($rfh, $wfh); 3540 unless (pipe($rfh, $wfh)) { 3541 die("Can't open pipe: $!"); 3542 } 3543 3544 my $ex; 3545 3546 # Fork child 3547 $self->handle_sigchld(); 3548 defined(my $pid = fork()) or die("Can't fork: $!"); 3549 if ($pid) { 3550 eval { 3551 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3552 $client->login($user, $passwd); 3553 $client->rnfr('test.txt'); 3554 $client->rnto('foo.txt'); 3555 }; 3556 3557 if ($@) { 3558 $ex = $@; 3559 } 3560 3561 $wfh->print("done\n"); 3562 $wfh->flush(); 3563 3564 } else { 3565 eval { server_wait($config_file, $rfh) }; 3566 if ($@) { 3567 warn($@); 3568 exit 1; 3569 } 3570 3571 exit 0; 3572 } 3573 3574 # Stop server 3575 server_stop($pid_file); 3576 3577 $self->assert_child_ok($pid); 3578 3579 if ($ex) { 3580 test_append_logfile($log_file, $ex); 3581 unlink($log_file); 3582 3583 die($ex); 3584 } 3585 3586 my ($login, $ip_addr, $rnfr_path) = get_renames($db_file, "user = \'$user\'"); 3587 3588 my $expected; 3589 3590 $expected = $user; 3591 $self->assert($expected eq $login, 3592 test_msg("Expected '$expected', got '$login'")); 3593 3594 $expected = '127.0.0.1'; 3595 $self->assert($expected eq $ip_addr, 3596 test_msg("Expected '$expected', got '$ip_addr'")); 3597 3598 if ($^O eq 'darwin') { 3599 # MacOSX-specific hack 3600 $src_file = '/private' . $src_file; 3601 } 3602 3603 $expected = $src_file; 3604 $self->assert($expected eq $rnfr_path, 3605 test_msg("Expected '$expected', got '$rnfr_path'")); 3606 3607 unlink($log_file); 3608} 3609 3610sub sql_sqllog_var_w_chrooted { 3611 my $self = shift; 3612 my $tmpdir = $self->{tmpdir}; 3613 3614 my $config_file = "$tmpdir/sqlite.conf"; 3615 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 3616 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 3617 3618 my $log_file = test_get_logfile(); 3619 3620 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 3621 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 3622 3623 my $user = 'proftpd'; 3624 my $passwd = 'test'; 3625 my $group = 'ftpd'; 3626 my $home_dir = File::Spec->rel2abs($tmpdir); 3627 my $uid = 500; 3628 my $gid = 500; 3629 3630 # Make sure that, if we're running as root, that the home directory has 3631 # permissions/privs set for the account we create 3632 if ($< == 0) { 3633 unless (chmod(0755, $home_dir)) { 3634 die("Can't set perms on $home_dir to 0755: $!"); 3635 } 3636 3637 unless (chown($uid, $gid, $home_dir)) { 3638 die("Can't set owner of $home_dir to $uid/$gid: $!"); 3639 } 3640 } 3641 3642 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 3643 '/bin/bash'); 3644 auth_group_write($auth_group_file, $group, $gid, $user); 3645 3646 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3647 3648 # Build up sqlite3 command to create users, groups tables and populate them 3649 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3650 3651 if (open(my $fh, "> $db_script")) { 3652 print $fh <<EOS; 3653CREATE TABLE ftpsessions ( 3654 user TEXT, 3655 ip_addr TEXT, 3656 rename_from TEXT 3657); 3658EOS 3659 3660 unless (close($fh)) { 3661 die("Can't write $db_script: $!"); 3662 } 3663 3664 } else { 3665 die("Can't open $db_script: $!"); 3666 } 3667 3668 my $cmd = "sqlite3 $db_file < $db_script"; 3669 build_db($cmd, $db_script); 3670 3671 # Make sure that, if we're running as root, the database file has 3672 # the permissions/privs set for use by proftpd 3673 if ($< == 0) { 3674 unless (chmod(0666, $db_file)) { 3675 die("Can't set perms on $db_file to 0666: $!"); 3676 } 3677 } 3678 3679 my $src_file = File::Spec->rel2abs("$tmpdir/test.txt"); 3680 if (open(my $fh, "> $src_file")) { 3681 close($fh); 3682 3683 } else { 3684 die("Can't open $src_file: $!"); 3685 } 3686 3687 my $dst_file = File::Spec->rel2abs("$tmpdir/foo.txt"); 3688 3689 my $config = { 3690 PidFile => $pid_file, 3691 ScoreboardFile => $scoreboard_file, 3692 SystemLog => $log_file, 3693 3694 AuthUserFile => $auth_user_file, 3695 AuthGroupFile => $auth_group_file, 3696 DefaultRoot => '~', 3697 3698 IfModules => { 3699 'mod_delay.c' => { 3700 DelayEngine => 'off', 3701 }, 3702 3703 'mod_sql.c' => { 3704 SQLEngine => 'log', 3705 SQLBackend => 'sqlite3', 3706 SQLConnectInfo => "$db_file foo bar PERCONNECTION", 3707 SQLLogFile => $log_file, 3708 SQLNamedQuery => 'rename FREEFORM "INSERT INTO ftpsessions (user, ip_addr, rename_from) VALUES (\'%u\', \'%L\', \'%w\')"', 3709 SQLLog => 'RNTO rename', 3710 }, 3711 }, 3712 }; 3713 3714 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3715 3716 # Open pipes, for use between the parent and child processes. Specifically, 3717 # the child will indicate when it's done with its test by writing a message 3718 # to the parent. 3719 my ($rfh, $wfh); 3720 unless (pipe($rfh, $wfh)) { 3721 die("Can't open pipe: $!"); 3722 } 3723 3724 my $ex; 3725 3726 # Fork child 3727 $self->handle_sigchld(); 3728 defined(my $pid = fork()) or die("Can't fork: $!"); 3729 if ($pid) { 3730 eval { 3731 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3732 3733 $client->login($user, $passwd); 3734 $client->rnfr('test.txt'); 3735 $client->rnto('foo.txt'); 3736 }; 3737 3738 if ($@) { 3739 $ex = $@; 3740 } 3741 3742 $wfh->print("done\n"); 3743 $wfh->flush(); 3744 3745 } else { 3746 eval { server_wait($config_file, $rfh) }; 3747 if ($@) { 3748 warn($@); 3749 exit 1; 3750 } 3751 3752 exit 0; 3753 } 3754 3755 # Stop server 3756 server_stop($pid_file); 3757 3758 $self->assert_child_ok($pid); 3759 3760 if ($ex) { 3761 test_append_logfile($log_file, $ex); 3762 unlink($log_file); 3763 3764 die($ex); 3765 } 3766 3767 my ($login, $ip_addr, $rnfr_path) = get_renames($db_file, "user = \'$user\'"); 3768 3769 my $expected; 3770 3771 $expected = $user; 3772 $self->assert($expected eq $login, 3773 test_msg("Expected '$expected', got '$login'")); 3774 3775 $expected = '127.0.0.1'; 3776 $self->assert($expected eq $ip_addr, 3777 test_msg("Expected '$expected', got '$ip_addr'")); 3778 3779 $expected = $src_file; 3780 $self->assert($expected eq $rnfr_path, 3781 test_msg("Expected '$expected', got '$rnfr_path'")); 3782 3783 unlink($log_file); 3784} 3785 3786sub sql_openssl_auth_type_md5 { 3787 my $self = shift; 3788 my $tmpdir = $self->{tmpdir}; 3789 3790 my $config_file = "$tmpdir/sqlite.conf"; 3791 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 3792 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 3793 3794 my $log_file = test_get_logfile(); 3795 3796 my $user = 'proftpd'; 3797 my $passwd = '{md5}X03MO1qnZdYdgyfeuILPmQ=='; 3798 my $group = 'ftpd'; 3799 my $home_dir = File::Spec->rel2abs($tmpdir); 3800 my $uid = 500; 3801 my $gid = 500; 3802 3803 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3804 3805 # Build up sqlite3 command to create users, groups tables and populate them 3806 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3807 3808 if (open(my $fh, "> $db_script")) { 3809 print $fh <<EOS; 3810CREATE TABLE users ( 3811 userid TEXT, 3812 passwd TEXT, 3813 uid INTEGER, 3814 gid INTEGER, 3815 homedir TEXT, 3816 shell TEXT, 3817 lastdir TEXT 3818); 3819INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 3820 3821CREATE TABLE groups ( 3822 groupname TEXT, 3823 gid INTEGER, 3824 members TEXT 3825); 3826INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 3827EOS 3828 3829 unless (close($fh)) { 3830 die("Can't write $db_script: $!"); 3831 } 3832 3833 } else { 3834 die("Can't open $db_script: $!"); 3835 } 3836 3837 my $cmd = "sqlite3 $db_file < $db_script"; 3838 build_db($cmd, $db_script); 3839 3840 # Make sure that, if we're running as root, the database file has 3841 # the permissions/privs set for use by proftpd 3842 if ($< == 0) { 3843 unless (chmod(0666, $db_file)) { 3844 die("Can't set perms on $db_file to 0666: $!"); 3845 } 3846 } 3847 3848 my $config = { 3849 PidFile => $pid_file, 3850 ScoreboardFile => $scoreboard_file, 3851 SystemLog => $log_file, 3852 3853 IfModules => { 3854 'mod_delay.c' => { 3855 DelayEngine => 'off', 3856 }, 3857 3858 'mod_sql.c' => { 3859 SQLAuthTypes => 'OpenSSL', 3860 SQLBackend => 'sqlite3', 3861 SQLConnectInfo => $db_file, 3862 SQLLogFile => $log_file, 3863 }, 3864 }, 3865 }; 3866 3867 my ($port, $config_user, $config_group) = config_write($config_file, $config); 3868 3869 # Open pipes, for use between the parent and child processes. Specifically, 3870 # the child will indicate when it's done with its test by writing a message 3871 # to the parent. 3872 my ($rfh, $wfh); 3873 unless (pipe($rfh, $wfh)) { 3874 die("Can't open pipe: $!"); 3875 } 3876 3877 my $ex; 3878 3879 # Fork child 3880 $self->handle_sigchld(); 3881 defined(my $pid = fork()) or die("Can't fork: $!"); 3882 if ($pid) { 3883 eval { 3884 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 3885 3886 $client->login($user, 'password'); 3887 3888 my $resp_msgs = $client->response_msgs(); 3889 my $nmsgs = scalar(@$resp_msgs); 3890 3891 my $expected; 3892 3893 $expected = 1; 3894 $self->assert($expected == $nmsgs, 3895 test_msg("Expected $expected, got $nmsgs")); 3896 3897 $expected = "User proftpd logged in"; 3898 $self->assert($expected eq $resp_msgs->[0], 3899 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 3900 3901 }; 3902 3903 if ($@) { 3904 $ex = $@; 3905 } 3906 3907 $wfh->print("done\n"); 3908 $wfh->flush(); 3909 3910 } else { 3911 eval { server_wait($config_file, $rfh) }; 3912 if ($@) { 3913 warn($@); 3914 exit 1; 3915 } 3916 3917 exit 0; 3918 } 3919 3920 # Stop server 3921 server_stop($pid_file); 3922 3923 $self->assert_child_ok($pid); 3924 3925 if ($ex) { 3926 test_append_logfile($log_file, $ex); 3927 unlink($log_file); 3928 3929 die($ex); 3930 } 3931 3932 unlink($log_file); 3933} 3934 3935sub sql_openssl_auth_type_sha1 { 3936 my $self = shift; 3937 my $tmpdir = $self->{tmpdir}; 3938 3939 my $config_file = "$tmpdir/sqlite.conf"; 3940 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 3941 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 3942 3943 my $log_file = test_get_logfile(); 3944 3945 my $user = 'proftpd'; 3946 my $passwd = '{sha1}W6ph5Mm5Pz8GgiULbPgzG37mj9g='; 3947 my $group = 'ftpd'; 3948 my $home_dir = File::Spec->rel2abs($tmpdir); 3949 my $uid = 500; 3950 my $gid = 500; 3951 3952 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 3953 3954 # Build up sqlite3 command to create users, groups tables and populate them 3955 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 3956 3957 if (open(my $fh, "> $db_script")) { 3958 print $fh <<EOS; 3959CREATE TABLE users ( 3960 userid TEXT, 3961 passwd TEXT, 3962 uid INTEGER, 3963 gid INTEGER, 3964 homedir TEXT, 3965 shell TEXT, 3966 lastdir TEXT 3967); 3968INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 3969 3970CREATE TABLE groups ( 3971 groupname TEXT, 3972 gid INTEGER, 3973 members TEXT 3974); 3975INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 3976EOS 3977 3978 unless (close($fh)) { 3979 die("Can't write $db_script: $!"); 3980 } 3981 3982 } else { 3983 die("Can't open $db_script: $!"); 3984 } 3985 3986 my $cmd = "sqlite3 $db_file < $db_script"; 3987 build_db($cmd, $db_script); 3988 3989 # Make sure that, if we're running as root, the database file has 3990 # the permissions/privs set for use by proftpd 3991 if ($< == 0) { 3992 unless (chmod(0666, $db_file)) { 3993 die("Can't set perms on $db_file to 0666: $!"); 3994 } 3995 } 3996 3997 my $config = { 3998 PidFile => $pid_file, 3999 ScoreboardFile => $scoreboard_file, 4000 SystemLog => $log_file, 4001 4002 IfModules => { 4003 'mod_delay.c' => { 4004 DelayEngine => 'off', 4005 }, 4006 4007 'mod_sql.c' => { 4008 SQLAuthTypes => 'OpenSSL', 4009 SQLBackend => 'sqlite3', 4010 SQLConnectInfo => $db_file, 4011 SQLLogFile => $log_file, 4012 }, 4013 }, 4014 }; 4015 4016 my ($port, $config_user, $config_group) = config_write($config_file, $config); 4017 4018 # Open pipes, for use between the parent and child processes. Specifically, 4019 # the child will indicate when it's done with its test by writing a message 4020 # to the parent. 4021 my ($rfh, $wfh); 4022 unless (pipe($rfh, $wfh)) { 4023 die("Can't open pipe: $!"); 4024 } 4025 4026 my $ex; 4027 4028 # Fork child 4029 $self->handle_sigchld(); 4030 defined(my $pid = fork()) or die("Can't fork: $!"); 4031 if ($pid) { 4032 eval { 4033 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4034 4035 $client->login($user, 'password'); 4036 4037 my $resp_msgs = $client->response_msgs(); 4038 my $nmsgs = scalar(@$resp_msgs); 4039 4040 my $expected; 4041 4042 $expected = 1; 4043 $self->assert($expected == $nmsgs, 4044 test_msg("Expected $expected, got $nmsgs")); 4045 4046 $expected = "User proftpd logged in"; 4047 $self->assert($expected eq $resp_msgs->[0], 4048 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 4049 4050 }; 4051 4052 if ($@) { 4053 $ex = $@; 4054 } 4055 4056 $wfh->print("done\n"); 4057 $wfh->flush(); 4058 4059 } else { 4060 eval { server_wait($config_file, $rfh) }; 4061 if ($@) { 4062 warn($@); 4063 exit 1; 4064 } 4065 4066 exit 0; 4067 } 4068 4069 # Stop server 4070 server_stop($pid_file); 4071 4072 $self->assert_child_ok($pid); 4073 4074 if ($ex) { 4075 test_append_logfile($log_file, $ex); 4076 unlink($log_file); 4077 4078 die($ex); 4079 } 4080 4081 unlink($log_file); 4082} 4083 4084sub get_resp_mesgs { 4085 my $db_file = shift; 4086 my $where = shift; 4087 my $cols = shift; 4088 4089 my $sql = "SELECT $cols FROM ftpsessions"; 4090 if ($where) { 4091 $sql .= " WHERE $where"; 4092 } 4093 4094 my $cmd = "sqlite3 $db_file \"$sql\""; 4095 4096 if ($ENV{TEST_VERBOSE}) { 4097 print STDERR "Executing sqlite3: $cmd\n"; 4098 } 4099 4100 my $res = join('', `$cmd`); 4101 chomp($res); 4102 4103 # The default sqlite3 delimiter is '|' 4104 return split(/\|/, $res); 4105} 4106 4107sub sql_sqllog_var_S { 4108 my $self = shift; 4109 my $tmpdir = $self->{tmpdir}; 4110 4111 my $config_file = "$tmpdir/sqlite.conf"; 4112 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 4113 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 4114 4115 my $log_file = test_get_logfile(); 4116 4117 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 4118 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 4119 4120 my $user = 'proftpd'; 4121 my $passwd = 'test'; 4122 my $group = 'ftpd'; 4123 my $home_dir = File::Spec->rel2abs($tmpdir); 4124 my $uid = 500; 4125 my $gid = 500; 4126 4127 # Make sure that, if we're running as root, that the home directory has 4128 # permissions/privs set for the account we create 4129 if ($< == 0) { 4130 unless (chmod(0755, $home_dir)) { 4131 die("Can't set perms on $home_dir to 0755: $!"); 4132 } 4133 4134 unless (chown($uid, $gid, $home_dir)) { 4135 die("Can't set owner of $home_dir to $uid/$gid: $!"); 4136 } 4137 } 4138 4139 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 4140 '/bin/bash'); 4141 auth_group_write($auth_group_file, $group, $gid, $user); 4142 4143 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4144 4145 # Build up sqlite3 command to create users, groups tables and populate them 4146 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4147 4148 if (open(my $fh, "> $db_script")) { 4149 print $fh <<EOS; 4150CREATE TABLE ftpsessions ( 4151 user TEXT, 4152 ip_addr TEXT, 4153 resp_mesg TEXT 4154); 4155EOS 4156 4157 unless (close($fh)) { 4158 die("Can't write $db_script: $!"); 4159 } 4160 4161 } else { 4162 die("Can't open $db_script: $!"); 4163 } 4164 4165 my $cmd = "sqlite3 $db_file < $db_script"; 4166 build_db($cmd, $db_script); 4167 4168 # Make sure that, if we're running as root, the database file has 4169 # the permissions/privs set for use by proftpd 4170 if ($< == 0) { 4171 unless (chmod(0666, $db_file)) { 4172 die("Can't set perms on $db_file to 0666: $!"); 4173 } 4174 } 4175 4176 my $config = { 4177 PidFile => $pid_file, 4178 ScoreboardFile => $scoreboard_file, 4179 SystemLog => $log_file, 4180 4181 AuthUserFile => $auth_user_file, 4182 AuthGroupFile => $auth_group_file, 4183 4184 IfModules => { 4185 'mod_delay.c' => { 4186 DelayEngine => 'off', 4187 }, 4188 4189 'mod_sql.c' => { 4190 SQLEngine => 'log', 4191 SQLBackend => 'sqlite3', 4192 SQLConnectInfo => $db_file, 4193 SQLLogFile => $log_file, 4194 SQLNamedQuery => 'info FREEFORM "INSERT INTO ftpsessions (user, ip_addr, resp_mesg) VALUES (\'%u\', \'%L\', \'%S\')"', 4195 SQLLog => 'LIST info', 4196 }, 4197 }, 4198 }; 4199 4200 my ($port, $config_user, $config_group) = config_write($config_file, $config); 4201 4202 # Open pipes, for use between the parent and child processes. Specifically, 4203 # the child will indicate when it's done with its test by writing a message 4204 # to the parent. 4205 my ($rfh, $wfh); 4206 unless (pipe($rfh, $wfh)) { 4207 die("Can't open pipe: $!"); 4208 } 4209 4210 my $ex; 4211 4212 # Fork child 4213 $self->handle_sigchld(); 4214 defined(my $pid = fork()) or die("Can't fork: $!"); 4215 if ($pid) { 4216 eval { 4217 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4218 $client->login($user, $passwd); 4219 $client->list(); 4220 $client->quit(); 4221 }; 4222 4223 if ($@) { 4224 $ex = $@; 4225 } 4226 4227 $wfh->print("done\n"); 4228 $wfh->flush(); 4229 4230 } else { 4231 eval { server_wait($config_file, $rfh) }; 4232 if ($@) { 4233 warn($@); 4234 exit 1; 4235 } 4236 4237 exit 0; 4238 } 4239 4240 # Stop server 4241 server_stop($pid_file); 4242 4243 $self->assert_child_ok($pid); 4244 4245 if ($ex) { 4246 test_append_logfile($log_file, $ex); 4247 unlink($log_file); 4248 4249 die($ex); 4250 } 4251 4252 my ($login, $ip_addr, $resp_mesg) = get_resp_mesgs($db_file, 4253 "user = \'$user\'", "user, ip_addr, resp_mesg"); 4254 4255 my $expected; 4256 4257 $expected = $user; 4258 $self->assert($expected eq $login, 4259 test_msg("Expected '$expected', got '$login'")); 4260 4261 $expected = '127.0.0.1'; 4262 $self->assert($expected eq $ip_addr, 4263 test_msg("Expected '$expected', got '$ip_addr'")); 4264 4265 $expected = 'Transfer complete'; 4266 $self->assert($expected eq $resp_mesg, 4267 test_msg("Expected '$expected', got '$resp_mesg'")); 4268 4269 unlink($log_file); 4270} 4271 4272sub sql_sqllog_var_S_err { 4273 my $self = shift; 4274 my $tmpdir = $self->{tmpdir}; 4275 my $setup = test_setup($tmpdir, 'sqlite'); 4276 4277 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4278 4279 # Build up sqlite3 command to create users, groups tables and populate them 4280 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4281 4282 if (open(my $fh, "> $db_script")) { 4283 print $fh <<EOS; 4284CREATE TABLE ftpsessions ( 4285 user TEXT, 4286 ip_addr TEXT, 4287 resp_mesg TEXT 4288); 4289EOS 4290 4291 unless (close($fh)) { 4292 die("Can't write $db_script: $!"); 4293 } 4294 4295 } else { 4296 die("Can't open $db_script: $!"); 4297 } 4298 4299 my $cmd = "sqlite3 $db_file < $db_script"; 4300 build_db($cmd, $db_script); 4301 4302 # Make sure that, if we're running as root, the database file has 4303 # the permissions/privs set for use by proftpd 4304 if ($< == 0) { 4305 unless (chmod(0666, $db_file)) { 4306 die("Can't set perms on $db_file to 0666: $!"); 4307 } 4308 } 4309 4310 my $config = { 4311 PidFile => $setup->{pid_file}, 4312 ScoreboardFile => $setup->{scoreboard_file}, 4313 SystemLog => $setup->{log_file}, 4314 TraceLog => $setup->{log_file}, 4315 Trace => 'jot:20 sql:20', 4316 4317 AuthUserFile => $setup->{auth_user_file}, 4318 AuthGroupFile => $setup->{auth_group_file}, 4319 4320 IfModules => { 4321 'mod_delay.c' => { 4322 DelayEngine => 'off', 4323 }, 4324 4325 'mod_sql.c' => { 4326 SQLEngine => 'log', 4327 SQLBackend => 'sqlite3', 4328 SQLConnectInfo => $db_file, 4329 SQLLogFile => $setup->{log_file}, 4330 SQLNamedQuery => 'info FREEFORM "INSERT INTO ftpsessions (user, ip_addr, resp_mesg) VALUES (\'%u\', \'%L\', \'%S\')"', 4331 SQLLog => 'ERR_* info', 4332 }, 4333 }, 4334 }; 4335 4336 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 4337 $config); 4338 4339 # Open pipes, for use between the parent and child processes. Specifically, 4340 # the child will indicate when it's done with its test by writing a message 4341 # to the parent. 4342 my ($rfh, $wfh); 4343 unless (pipe($rfh, $wfh)) { 4344 die("Can't open pipe: $!"); 4345 } 4346 4347 my $ex; 4348 4349 # Fork child 4350 $self->handle_sigchld(); 4351 defined(my $pid = fork()) or die("Can't fork: $!"); 4352 if ($pid) { 4353 eval { 4354 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4355 $client->login($setup->{user}, $setup->{passwd}); 4356 eval { $client->quote('CLIENT', 'NcFTP 3.2.2 linux-x86_64-glibc2.3') }; 4357 $client->quit(); 4358 }; 4359 if ($@) { 4360 $ex = $@; 4361 } 4362 4363 $wfh->print("done\n"); 4364 $wfh->flush(); 4365 4366 } else { 4367 eval { server_wait($setup->{config_file}, $rfh) }; 4368 if ($@) { 4369 warn($@); 4370 exit 1; 4371 } 4372 4373 exit 0; 4374 } 4375 4376 # Stop server 4377 server_stop($setup->{pid_file}); 4378 $self->assert_child_ok($pid); 4379 4380 if ($ex) { 4381 test_cleanup($setup->{log_file}, $ex); 4382 } 4383 4384 eval { 4385 my ($login, $ip_addr, $resp_mesg) = get_resp_mesgs($db_file, 4386 "user = \'$setup->{user}\'", "user, ip_addr, resp_mesg"); 4387 4388 my $expected = $setup->{user}; 4389 $self->assert($expected eq $login, "Expected '$expected', got '$login'"); 4390 4391 $expected = '127.0.0.1'; 4392 $self->assert($expected eq $ip_addr, 4393 "Expected '$expected', got '$ip_addr'"); 4394 4395 $expected = 'CLIENT not understood'; 4396 $self->assert($expected eq $resp_mesg, 4397 "Expected '$expected', got '$resp_mesg'"); 4398 }; 4399 if ($@) { 4400 $ex = $@; 4401 } 4402 4403 test_cleanup($setup->{log_file}, $ex); 4404} 4405 4406sub sql_negative_cache_bug3282 { 4407 my $self = shift; 4408 my $tmpdir = $self->{tmpdir}; 4409 4410 my $config_file = "$tmpdir/sqlite.conf"; 4411 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 4412 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 4413 4414 my $log_file = test_get_logfile(); 4415 4416 my $user = 'proftpd'; 4417 my $passwd = 'test'; 4418 my $group = 'ftpd'; 4419 my $home_dir = File::Spec->rel2abs($tmpdir); 4420 my $uid = 500; 4421 my $gid = 500; 4422 4423 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4424 4425 # Build up sqlite3 command to create users, groups tables and populate them 4426 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4427 4428 if (open(my $fh, "> $db_script")) { 4429 print $fh <<EOS; 4430CREATE TABLE users ( 4431 userid TEXT, 4432 passwd TEXT, 4433 uid INTEGER, 4434 gid INTEGER, 4435 homedir TEXT, 4436 shell TEXT, 4437 lastdir TEXT 4438); 4439INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 4440 4441CREATE TABLE groups ( 4442 groupname TEXT, 4443 gid INTEGER, 4444 members TEXT 4445); 4446INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 4447EOS 4448 4449 unless (close($fh)) { 4450 die("Can't write $db_script: $!"); 4451 } 4452 4453 } else { 4454 die("Can't open $db_script: $!"); 4455 } 4456 4457 my $cmd = "sqlite3 $db_file < $db_script"; 4458 build_db($cmd, $db_script); 4459 4460 # Make sure that, if we're running as root, the database file has 4461 # the permissions/privs set for use by proftpd 4462 if ($< == 0) { 4463 unless (chmod(0666, $db_file)) { 4464 die("Can't set perms on $db_file to 0666: $!"); 4465 } 4466 } 4467 4468 my $config = { 4469 PidFile => $pid_file, 4470 ScoreboardFile => $scoreboard_file, 4471 SystemLog => $log_file, 4472 TraceLog => $log_file, 4473 Trace => 'auth:10', 4474 4475 IfModules => { 4476 'mod_delay.c' => { 4477 DelayEngine => 'off', 4478 }, 4479 4480 'mod_sql.c' => { 4481 SQLAuthTypes => 'plaintext', 4482 SQLBackend => 'sqlite3', 4483 SQLConnectInfo => $db_file, 4484 SQLLogFile => $log_file, 4485 SQLNegativeCache => 'on', 4486 }, 4487 }, 4488 }; 4489 4490 my ($port, $config_user, $config_group) = config_write($config_file, $config); 4491 4492 # Open pipes, for use between the parent and child processes. Specifically, 4493 # the child will indicate when it's done with its test by writing a message 4494 # to the parent. 4495 my ($rfh, $wfh); 4496 unless (pipe($rfh, $wfh)) { 4497 die("Can't open pipe: $!"); 4498 } 4499 4500 my $ex; 4501 4502 # Fork child 4503 $self->handle_sigchld(); 4504 defined(my $pid = fork()) or die("Can't fork: $!"); 4505 if ($pid) { 4506 eval { 4507 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4508 4509 eval { $client->login('foo', 'foo') }; 4510 unless ($@) { 4511 die("Login succeeded unexpectedly"); 4512 } 4513 4514 $client->login($user, $passwd); 4515 4516 my $expected; 4517 4518 my $resp_msgs = $client->response_msgs(); 4519 my $nmsgs = scalar(@$resp_msgs); 4520 4521 $expected = 1; 4522 $self->assert($expected == $nmsgs, 4523 test_msg("Expected $expected, got $nmsgs")); 4524 4525 $expected = "User proftpd logged in"; 4526 $self->assert($expected eq $resp_msgs->[0], 4527 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 4528 }; 4529 4530 if ($@) { 4531 $ex = $@; 4532 } 4533 4534 $wfh->print("done\n"); 4535 $wfh->flush(); 4536 4537 } else { 4538 eval { server_wait($config_file, $rfh) }; 4539 if ($@) { 4540 warn($@); 4541 exit 1; 4542 } 4543 4544 exit 0; 4545 } 4546 4547 # Stop server 4548 server_stop($pid_file); 4549 4550 $self->assert_child_ok($pid); 4551 4552 if ($ex) { 4553 test_append_logfile($log_file, $ex); 4554 unlink($log_file); 4555 4556 die($ex); 4557 } 4558 4559 unlink($log_file); 4560} 4561 4562sub sql_sqllog_var_T_rnfr { 4563 my $self = shift; 4564 my $tmpdir = $self->{tmpdir}; 4565 my $setup = test_setup($tmpdir, 'sqlite'); 4566 4567 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4568 4569 # Build up sqlite3 command to create users, groups tables and populate them 4570 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4571 4572 if (open(my $fh, "> $db_script")) { 4573 print $fh <<EOS; 4574CREATE TABLE ftpsessions ( 4575 user TEXT, 4576 ip_addr TEXT, 4577 rename_from TEXT, 4578 rename_time FLOAT 4579); 4580EOS 4581 4582 unless (close($fh)) { 4583 die("Can't write $db_script: $!"); 4584 } 4585 4586 } else { 4587 die("Can't open $db_script: $!"); 4588 } 4589 4590 my $cmd = "sqlite3 $db_file < $db_script"; 4591 build_db($cmd, $db_script); 4592 4593 # Make sure that, if we're running as root, the database file has 4594 # the permissions/privs set for use by proftpd 4595 if ($< == 0) { 4596 unless (chmod(0666, $db_file)) { 4597 die("Can't set perms on $db_file to 0666: $!"); 4598 } 4599 } 4600 4601 my $src_file = File::Spec->rel2abs("$tmpdir/test.txt"); 4602 if (open(my $fh, "> $src_file")) { 4603 close($fh); 4604 4605 } else { 4606 die("Can't open $src_file: $!"); 4607 } 4608 4609 my $dst_file = File::Spec->rel2abs("$tmpdir/foo.txt"); 4610 4611 my $config = { 4612 PidFile => $setup->{pid_file}, 4613 ScoreboardFile => $setup->{scoreboard_file}, 4614 SystemLog => $setup->{log_file}, 4615 TraceLog => $setup->{log_file}, 4616 Trace => 'jot:20 sql:20', 4617 4618 AuthUserFile => $setup->{auth_user_file}, 4619 AuthGroupFile => $setup->{auth_group_file}, 4620 4621 IfModules => { 4622 'mod_delay.c' => { 4623 DelayEngine => 'off', 4624 }, 4625 4626 'mod_sql.c' => { 4627 SQLEngine => 'log', 4628 SQLBackend => 'sqlite3', 4629 SQLConnectInfo => $db_file, 4630 SQLLogFile => $setup->{log_file}, 4631 SQLNamedQuery => 'rename FREEFORM "INSERT INTO ftpsessions (user, ip_addr, rename_from, rename_time) VALUES (\'%u\', \'%L\', \'%w\', %T)"', 4632 SQLLog => 'RNTO rename', 4633 }, 4634 }, 4635 }; 4636 4637 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 4638 $config); 4639 4640 # Open pipes, for use between the parent and child processes. Specifically, 4641 # the child will indicate when it's done with its test by writing a message 4642 # to the parent. 4643 my ($rfh, $wfh); 4644 unless (pipe($rfh, $wfh)) { 4645 die("Can't open pipe: $!"); 4646 } 4647 4648 my $ex; 4649 4650 # Fork child 4651 $self->handle_sigchld(); 4652 defined(my $pid = fork()) or die("Can't fork: $!"); 4653 if ($pid) { 4654 eval { 4655 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 4656 $client->login($setup->{user}, $setup->{passwd}); 4657 $client->rnfr('test.txt'); 4658 $client->rnto('foo.txt'); 4659 }; 4660 if ($@) { 4661 $ex = $@; 4662 } 4663 4664 $wfh->print("done\n"); 4665 $wfh->flush(); 4666 4667 } else { 4668 eval { server_wait($setup->{config_file}, $rfh) }; 4669 if ($@) { 4670 warn($@); 4671 exit 1; 4672 } 4673 4674 exit 0; 4675 } 4676 4677 # Stop server 4678 server_stop($setup->{pid_file}); 4679 $self->assert_child_ok($pid); 4680 4681 if ($ex) { 4682 test_cleanup($setup->{log_file}, $ex); 4683 } 4684 4685 eval { 4686 my $query = "SELECT user, ip_addr, rename_from, rename_time FROM ftpsessions WHERE user = \'$setup->{user}\'"; 4687 $cmd = "sqlite3 $db_file \"$query\""; 4688 4689 if ($ENV{TEST_VERBOSE}) { 4690 print STDERR "Executing sqlite3: $cmd\n"; 4691 } 4692 4693 my $res = join('', `$cmd`); 4694 chomp($res); 4695 4696 my ($login, $ip_addr, $rnfr_path, $rename_time) = split(/\|/, $res); 4697 4698 my $expected = $setup->{user}; 4699 $self->assert($expected eq $login, "Expected '$expected', got '$login'"); 4700 4701 $expected = '127.0.0.1'; 4702 $self->assert($expected eq $ip_addr, 4703 "Expected '$expected', got '$ip_addr'"); 4704 4705 if ($^O eq 'darwin') { 4706 # MacOSX-specific hack 4707 $src_file = '/private' . $src_file; 4708 } 4709 4710 $expected = $src_file; 4711 $self->assert($expected eq $rnfr_path, 4712 "Expected '$expected', got '$rnfr_path'"); 4713 4714 $expected = '0.0'; 4715 $self->assert($expected eq $rename_time, 4716 "Expected '$expected', got '$rename_time'"); 4717 }; 4718 if ($@) { 4719 $ex = $@; 4720 } 4721 4722 test_cleanup($setup->{log_file}, $ex); 4723} 4724 4725sub sql_sqllog_var_T_retr { 4726 my $self = shift; 4727 my $tmpdir = $self->{tmpdir}; 4728 my $setup = test_setup($tmpdir, 'sqlite'); 4729 4730 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4731 4732 # Build up sqlite3 command to create users, groups tables and populate them 4733 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4734 4735 if (open(my $fh, "> $db_script")) { 4736 print $fh <<EOS; 4737CREATE TABLE ftpsessions ( 4738 user TEXT PRIMARY KEY, 4739 ip_addr TEXT, 4740 download_time FLOAT 4741); 4742EOS 4743 4744 unless (close($fh)) { 4745 die("Can't write $db_script: $!"); 4746 } 4747 4748 } else { 4749 die("Can't open $db_script: $!"); 4750 } 4751 4752 my $cmd = "sqlite3 $db_file < $db_script"; 4753 build_db($cmd, $db_script); 4754 4755 # Make sure that, if we're running as root, the database file has 4756 # the permissions/privs set for use by proftpd 4757 if ($< == 0) { 4758 unless (chmod(0666, $db_file)) { 4759 die("Can't set perms on $db_file to 0666: $!"); 4760 } 4761 } 4762 4763 my $config = { 4764 PidFile => $setup->{pid_file}, 4765 ScoreboardFile => $setup->{scoreboard_file}, 4766 SystemLog => $setup->{log_file}, 4767 4768 AuthUserFile => $setup->{auth_user_file}, 4769 AuthGroupFile => $setup->{auth_group_file}, 4770 4771 IfModules => { 4772 'mod_delay.c' => { 4773 DelayEngine => 'off', 4774 }, 4775 4776 'mod_sql.c' => { 4777 SQLEngine => 'log', 4778 SQLBackend => 'sqlite3', 4779 SQLConnectInfo => $db_file, 4780 SQLLogFile => $setup->{log_file}, 4781 SQLNamedQuery => 'download FREEFORM "INSERT INTO ftpsessions (user, ip_addr, download_time) VALUES (\'%u\', \'%L\', %T)"', 4782 SQLLog => 'RETR download', 4783 }, 4784 }, 4785 }; 4786 4787 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 4788 $config); 4789 4790 # Open pipes, for use between the parent and child processes. Specifically, 4791 # the child will indicate when it's done with its test by writing a message 4792 # to the parent. 4793 my ($rfh, $wfh); 4794 unless (pipe($rfh, $wfh)) { 4795 die("Can't open pipe: $!"); 4796 } 4797 4798 my $ex; 4799 4800 # Fork child 4801 $self->handle_sigchld(); 4802 defined(my $pid = fork()) or die("Can't fork: $!"); 4803 if ($pid) { 4804 eval { 4805 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 4806 $client->login($setup->{user}, $setup->{passwd}); 4807 4808 my $conn = $client->retr_raw('sqlite.conf'); 4809 unless ($conn) { 4810 die("RETR sqlite.conf failed: " . $client->response_code() . " " . 4811 $client->response_msg()); 4812 } 4813 4814 my $buf; 4815 while ($conn->read($buf, 8192, 30)) { 4816 } 4817 $conn->close(); 4818 4819 my $resp_code = $client->response_code(); 4820 my $resp_msg = $client->response_msg(); 4821 $self->assert_transfer_ok($resp_code, $resp_msg); 4822 4823 $client->quit(); 4824 }; 4825 4826 if ($@) { 4827 $ex = $@; 4828 } 4829 4830 $wfh->print("done\n"); 4831 $wfh->flush(); 4832 4833 } else { 4834 eval { server_wait($setup->{config_file}, $rfh) }; 4835 if ($@) { 4836 warn($@); 4837 exit 1; 4838 } 4839 4840 exit 0; 4841 } 4842 4843 # Stop server 4844 server_stop($setup->{pid_file}); 4845 $self->assert_child_ok($pid); 4846 4847 eval { 4848 my $query = "SELECT user, ip_addr, download_time FROM ftpsessions WHERE user = \'$setup->{user}\'"; 4849 $cmd = "sqlite3 $db_file \"$query\""; 4850 4851 if ($ENV{TEST_VERBOSE}) { 4852 print STDERR "Executing sqlite3: $cmd\n"; 4853 } 4854 4855 my $res = join('', `$cmd`); 4856 chomp($res); 4857 4858 my ($login, $ip_addr, $download_time) = split(/\|/, $res); 4859 4860 if ($ENV{TEST_VERBOSE}) { 4861 print STDERR "# login = '$login', ip_addr = '$ip_addr', download_time = $download_time\n"; 4862 } 4863 4864 my $expected; 4865 4866 $expected = $setup->{user}; 4867 $self->assert($expected eq $login, 4868 test_msg("Expected '$expected', got '$login'")); 4869 4870 $expected = '127.0.0.1'; 4871 $self->assert($expected eq $ip_addr, 4872 test_msg("Expected '$expected', got '$ip_addr'")); 4873 4874 $self->assert($download_time > 0.0, 4875 test_msg("Expected > 0.0, got $download_time")); 4876 }; 4877 if ($@) { 4878 $ex = $@; 4879 } 4880 4881 test_cleanup($setup->{log_file}, $ex); 4882} 4883 4884sub sql_sqllog_var_transfer_millisecs_retr_bug4218 { 4885 my $self = shift; 4886 my $tmpdir = $self->{tmpdir}; 4887 my $setup = test_setup($tmpdir, 'sqlite'); 4888 4889 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 4890 4891 # Build up sqlite3 command to create users, groups tables and populate them 4892 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 4893 4894 if (open(my $fh, "> $db_script")) { 4895 print $fh <<EOS; 4896CREATE TABLE ftpsessions ( 4897 user TEXT PRIMARY KEY, 4898 ip_addr TEXT, 4899 download_ms INTEGER 4900); 4901EOS 4902 4903 unless (close($fh)) { 4904 die("Can't write $db_script: $!"); 4905 } 4906 4907 } else { 4908 die("Can't open $db_script: $!"); 4909 } 4910 4911 my $cmd = "sqlite3 $db_file < $db_script"; 4912 build_db($cmd, $db_script); 4913 4914 # Make sure that, if we're running as root, the database file has 4915 # the permissions/privs set for use by proftpd 4916 if ($< == 0) { 4917 unless (chmod(0666, $db_file)) { 4918 die("Can't set perms on $db_file to 0666: $!"); 4919 } 4920 } 4921 4922 my $config = { 4923 PidFile => $setup->{pid_file}, 4924 ScoreboardFile => $setup->{scoreboard_file}, 4925 SystemLog => $setup->{log_file}, 4926 4927 AuthUserFile => $setup->{auth_user_file}, 4928 AuthGroupFile => $setup->{auth_group_file}, 4929 4930 IfModules => { 4931 'mod_delay.c' => { 4932 DelayEngine => 'off', 4933 }, 4934 4935 'mod_sql.c' => { 4936 SQLEngine => 'log', 4937 SQLBackend => 'sqlite3', 4938 SQLConnectInfo => $db_file, 4939 SQLLogFile => $setup->{log_file}, 4940 SQLNamedQuery => 'download FREEFORM "INSERT INTO ftpsessions (user, ip_addr, download_ms) VALUES (\'%u\', \'%L\', %{transfer-millisecs})"', 4941 SQLLog => 'RETR download', 4942 }, 4943 }, 4944 }; 4945 4946 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 4947 $config); 4948 4949 # Open pipes, for use between the parent and child processes. Specifically, 4950 # the child will indicate when it's done with its test by writing a message 4951 # to the parent. 4952 my ($rfh, $wfh); 4953 unless (pipe($rfh, $wfh)) { 4954 die("Can't open pipe: $!"); 4955 } 4956 4957 my $ex; 4958 4959 # Fork child 4960 $self->handle_sigchld(); 4961 defined(my $pid = fork()) or die("Can't fork: $!"); 4962 if ($pid) { 4963 eval { 4964 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 4965 $client->login($setup->{user}, $setup->{passwd}); 4966 4967 my $conn = $client->retr_raw('sqlite.conf'); 4968 unless ($conn) { 4969 die("RETR sqlite.conf failed: " . $client->response_code() . " " . 4970 $client->response_msg()); 4971 } 4972 4973 my $buf; 4974 while ($conn->read($buf, 8192, 30)) { 4975 } 4976 $conn->close(); 4977 4978 my $resp_code = $client->response_code(); 4979 my $resp_msg = $client->response_msg(); 4980 $self->assert_transfer_ok($resp_code, $resp_msg); 4981 4982 $client->quit(); 4983 }; 4984 4985 if ($@) { 4986 $ex = $@; 4987 } 4988 4989 $wfh->print("done\n"); 4990 $wfh->flush(); 4991 4992 } else { 4993 eval { server_wait($setup->{config_file}, $rfh) }; 4994 if ($@) { 4995 warn($@); 4996 exit 1; 4997 } 4998 4999 exit 0; 5000 } 5001 5002 # Stop server 5003 server_stop($setup->{pid_file}); 5004 $self->assert_child_ok($pid); 5005 5006 eval { 5007 my $query = "SELECT user, ip_addr, download_ms FROM ftpsessions WHERE user = \'$setup->{user}\'"; 5008 $cmd = "sqlite3 $db_file \"$query\""; 5009 5010 if ($ENV{TEST_VERBOSE}) { 5011 print STDERR "Executing sqlite3: $cmd\n"; 5012 } 5013 5014 my $res = join('', `$cmd`); 5015 chomp($res); 5016 5017 my ($login, $ip_addr, $download_ms) = split(/\|/, $res); 5018 5019 if ($ENV{TEST_VERBOSE}) { 5020 print STDERR "# login = '$login', ip_addr = '$ip_addr', download_ms = $download_ms\n"; 5021 } 5022 5023 my $expected; 5024 5025 $expected = $setup->{user}; 5026 $self->assert($expected eq $login, 5027 test_msg("Expected '$expected', got '$login'")); 5028 5029 $expected = '127.0.0.1'; 5030 $self->assert($expected eq $ip_addr, 5031 test_msg("Expected '$expected', got '$ip_addr'")); 5032 5033 $self->assert($download_ms > 0, 5034 test_msg("Expected > 0, got $download_ms")); 5035 }; 5036 if ($@) { 5037 $ex = $@; 5038 } 5039 5040 test_cleanup($setup->{log_file}, $ex); 5041} 5042 5043sub sql_sqllog_var_R_retr_bug4218 { 5044 my $self = shift; 5045 my $tmpdir = $self->{tmpdir}; 5046 my $setup = test_setup($tmpdir, 'sqlite'); 5047 5048 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5049 5050 # Build up sqlite3 command to create users, groups tables and populate them 5051 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5052 5053 if (open(my $fh, "> $db_script")) { 5054 print $fh <<EOS; 5055CREATE TABLE ftpsessions ( 5056 user TEXT PRIMARY KEY, 5057 ip_addr TEXT, 5058 response_ms INTEGER 5059); 5060EOS 5061 5062 unless (close($fh)) { 5063 die("Can't write $db_script: $!"); 5064 } 5065 5066 } else { 5067 die("Can't open $db_script: $!"); 5068 } 5069 5070 my $cmd = "sqlite3 $db_file < $db_script"; 5071 build_db($cmd, $db_script); 5072 5073 # Make sure that, if we're running as root, the database file has 5074 # the permissions/privs set for use by proftpd 5075 if ($< == 0) { 5076 unless (chmod(0666, $db_file)) { 5077 die("Can't set perms on $db_file to 0666: $!"); 5078 } 5079 } 5080 5081 my $config = { 5082 PidFile => $setup->{pid_file}, 5083 ScoreboardFile => $setup->{scoreboard_file}, 5084 SystemLog => $setup->{log_file}, 5085 5086 AuthUserFile => $setup->{auth_user_file}, 5087 AuthGroupFile => $setup->{auth_group_file}, 5088 5089 IfModules => { 5090 'mod_delay.c' => { 5091 DelayEngine => 'off', 5092 }, 5093 5094 'mod_sql.c' => { 5095 SQLEngine => 'log', 5096 SQLBackend => 'sqlite3', 5097 SQLConnectInfo => $db_file, 5098 SQLLogFile => $setup->{log_file}, 5099 SQLNamedQuery => 'download FREEFORM "INSERT INTO ftpsessions (user, ip_addr, response_ms) VALUES (\'%u\', \'%L\', %R)"', 5100 SQLLog => 'RETR download', 5101 }, 5102 }, 5103 }; 5104 5105 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 5106 $config); 5107 5108 # Open pipes, for use between the parent and child processes. Specifically, 5109 # the child will indicate when it's done with its test by writing a message 5110 # to the parent. 5111 my ($rfh, $wfh); 5112 unless (pipe($rfh, $wfh)) { 5113 die("Can't open pipe: $!"); 5114 } 5115 5116 my $ex; 5117 5118 # Fork child 5119 $self->handle_sigchld(); 5120 defined(my $pid = fork()) or die("Can't fork: $!"); 5121 if ($pid) { 5122 eval { 5123 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1); 5124 $client->login($setup->{user}, $setup->{passwd}); 5125 5126 my $conn = $client->retr_raw('sqlite.conf'); 5127 unless ($conn) { 5128 die("RETR sqlite.conf failed: " . $client->response_code() . " " . 5129 $client->response_msg()); 5130 } 5131 5132 my $buf; 5133 while ($conn->read($buf, 8192, 30)) { 5134 } 5135 $conn->close(); 5136 5137 my $resp_code = $client->response_code(); 5138 my $resp_msg = $client->response_msg(); 5139 $self->assert_transfer_ok($resp_code, $resp_msg); 5140 5141 $client->quit(); 5142 }; 5143 5144 if ($@) { 5145 $ex = $@; 5146 } 5147 5148 $wfh->print("done\n"); 5149 $wfh->flush(); 5150 5151 } else { 5152 eval { server_wait($setup->{config_file}, $rfh) }; 5153 if ($@) { 5154 warn($@); 5155 exit 1; 5156 } 5157 5158 exit 0; 5159 } 5160 5161 # Stop server 5162 server_stop($setup->{pid_file}); 5163 $self->assert_child_ok($pid); 5164 5165 eval { 5166 my $query = "SELECT user, ip_addr, response_ms FROM ftpsessions WHERE user = \'$setup->{user}\'"; 5167 $cmd = "sqlite3 $db_file \"$query\""; 5168 5169 if ($ENV{TEST_VERBOSE}) { 5170 print STDERR "Executing sqlite3: $cmd\n"; 5171 } 5172 5173 my $res = join('', `$cmd`); 5174 chomp($res); 5175 5176 my ($login, $ip_addr, $response_ms) = split(/\|/, $res); 5177 5178 if ($ENV{TEST_VERBOSE}) { 5179 print STDERR "# login = '$login', ip_addr = '$ip_addr', response_ms = $response_ms\n"; 5180 } 5181 5182 my $expected; 5183 5184 $expected = $setup->{user}; 5185 $self->assert($expected eq $login, 5186 test_msg("Expected '$expected', got '$login'")); 5187 5188 $expected = '127.0.0.1'; 5189 $self->assert($expected eq $ip_addr, 5190 test_msg("Expected '$expected', got '$ip_addr'")); 5191 5192 $self->assert($response_ms > 0, 5193 test_msg("Expected > 0, got $response_ms")); 5194 }; 5195 if ($@) { 5196 $ex = $@; 5197 } 5198 5199 test_cleanup($setup->{log_file}, $ex); 5200} 5201 5202sub sql_sqllog_exit { 5203 my $self = shift; 5204 my $tmpdir = $self->{tmpdir}; 5205 5206 my $config_file = "$tmpdir/sqlite.conf"; 5207 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 5208 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 5209 5210 my $log_file = test_get_logfile(); 5211 5212 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 5213 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 5214 5215 my $user = 'proftpd'; 5216 my $passwd = 'test'; 5217 my $group = 'ftpd'; 5218 my $home_dir = File::Spec->rel2abs($tmpdir); 5219 my $uid = 500; 5220 my $gid = 500; 5221 5222 # Make sure that, if we're running as root, that the home directory has 5223 # permissions/privs set for the account we create 5224 if ($< == 0) { 5225 unless (chmod(0755, $home_dir)) { 5226 die("Can't set perms on $home_dir to 0755: $!"); 5227 } 5228 5229 unless (chown($uid, $gid, $home_dir)) { 5230 die("Can't set owner of $home_dir to $uid/$gid: $!"); 5231 } 5232 } 5233 5234 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 5235 '/bin/bash'); 5236 auth_group_write($auth_group_file, $group, $gid, $user); 5237 5238 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5239 5240 # Build up sqlite3 command to create users, groups tables and populate them 5241 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5242 5243 if (open(my $fh, "> $db_script")) { 5244 print $fh <<EOS; 5245CREATE TABLE ftpsessions ( 5246 user TEXT, 5247 ip_addr TEXT 5248); 5249EOS 5250 5251 unless (close($fh)) { 5252 die("Can't write $db_script: $!"); 5253 } 5254 5255 } else { 5256 die("Can't open $db_script: $!"); 5257 } 5258 5259 my $cmd = "sqlite3 $db_file < $db_script"; 5260 build_db($cmd, $db_script); 5261 5262 # Make sure that, if we're running as root, the database file has 5263 # the permissions/privs set for use by proftpd 5264 if ($< == 0) { 5265 unless (chmod(0666, $db_file)) { 5266 die("Can't set perms on $db_file to 0666: $!"); 5267 } 5268 } 5269 5270 my $config = { 5271 PidFile => $pid_file, 5272 ScoreboardFile => $scoreboard_file, 5273 SystemLog => $log_file, 5274 5275 AuthUserFile => $auth_user_file, 5276 AuthGroupFile => $auth_group_file, 5277 5278 IfModules => { 5279 'mod_delay.c' => { 5280 DelayEngine => 'off', 5281 }, 5282 5283 'mod_sql.c' => { 5284 SQLEngine => 'log', 5285 SQLBackend => 'sqlite3', 5286 SQLConnectInfo => $db_file, 5287 SQLLogFile => $log_file, 5288 SQLNamedQuery => 'logout FREEFORM "INSERT INTO ftpsessions (user, ip_addr) VALUES (\'%u\', \'%L\')"', 5289 SQLLog => 'EXIT logout', 5290 }, 5291 }, 5292 }; 5293 5294 my ($port, $config_user, $config_group) = config_write($config_file, $config); 5295 5296 # Open pipes, for use between the parent and child processes. Specifically, 5297 # the child will indicate when it's done with its test by writing a message 5298 # to the parent. 5299 my ($rfh, $wfh); 5300 unless (pipe($rfh, $wfh)) { 5301 die("Can't open pipe: $!"); 5302 } 5303 5304 my $ex; 5305 5306 # Fork child 5307 $self->handle_sigchld(); 5308 defined(my $pid = fork()) or die("Can't fork: $!"); 5309 if ($pid) { 5310 eval { 5311 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 5312 5313 $client->login($user, $passwd); 5314 $client->quit(); 5315 }; 5316 5317 if ($@) { 5318 $ex = $@; 5319 } 5320 5321 $wfh->print("done\n"); 5322 $wfh->flush(); 5323 5324 } else { 5325 eval { server_wait($config_file, $rfh) }; 5326 if ($@) { 5327 warn($@); 5328 exit 1; 5329 } 5330 5331 exit 0; 5332 } 5333 5334 # Stop server 5335 server_stop($pid_file); 5336 5337 $self->assert_child_ok($pid); 5338 5339 if ($ex) { 5340 test_append_logfile($log_file, $ex); 5341 unlink($log_file); 5342 5343 die($ex); 5344 } 5345 5346 my $query = "SELECT user, ip_addr FROM ftpsessions WHERE user = \'$user\'"; 5347 $cmd = "sqlite3 $db_file \"$query\""; 5348 5349 if ($ENV{TEST_VERBOSE}) { 5350 print STDERR "Executing sqlite3: $cmd\n"; 5351 } 5352 5353 my $res = join('', `$cmd`); 5354 chomp($res); 5355 5356 my ($login, $ip_addr) = split(/\|/, $res); 5357 5358 my $expected; 5359 5360 $expected = $user; 5361 $self->assert($expected eq $login, 5362 test_msg("Expected '$expected', got '$login'")); 5363 5364 $expected = '127.0.0.1'; 5365 $self->assert($expected eq $ip_addr, 5366 test_msg("Expected '$expected', got '$ip_addr'")); 5367 5368 unlink($log_file); 5369} 5370 5371sub sql_sqllog_exit_var_remote_port_bug4296 { 5372 my $self = shift; 5373 my $tmpdir = $self->{tmpdir}; 5374 my $setup = test_setup($tmpdir, 'sqlite'); 5375 5376 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5377 5378 # Build up sqlite3 command to create users, groups tables and populate them 5379 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5380 5381 if (open(my $fh, "> $db_script")) { 5382 print $fh <<EOS; 5383CREATE TABLE ftpsessions ( 5384 user TEXT, 5385 ip_addr TEXT, 5386 port NUMBER 5387); 5388EOS 5389 5390 unless (close($fh)) { 5391 die("Can't write $db_script: $!"); 5392 } 5393 5394 } else { 5395 die("Can't open $db_script: $!"); 5396 } 5397 5398 my $cmd = "sqlite3 $db_file < $db_script"; 5399 build_db($cmd, $db_script); 5400 5401 # Make sure that, if we're running as root, the database file has 5402 # the permissions/privs set for use by proftpd 5403 if ($< == 0) { 5404 unless (chmod(0666, $db_file)) { 5405 die("Can't set perms on $db_file to 0666: $!"); 5406 } 5407 } 5408 5409 my $config = { 5410 PidFile => $setup->{pid_file}, 5411 ScoreboardFile => $setup->{scoreboard_file}, 5412 SystemLog => $setup->{log_file}, 5413 TraceLog => $setup->{log_file}, 5414 Trace => 'jot:20 sql:20', 5415 5416 AuthUserFile => $setup->{auth_user_file}, 5417 AuthGroupFile => $setup->{auth_group_file}, 5418 5419 IfModules => { 5420 'mod_delay.c' => { 5421 DelayEngine => 'off', 5422 }, 5423 5424 'mod_sql.c' => { 5425 SQLEngine => 'log', 5426 SQLBackend => 'sqlite3', 5427 SQLConnectInfo => $db_file, 5428 SQLLogFile => $setup->{log_file}, 5429 SQLNamedQuery => 'logout FREEFORM "INSERT INTO ftpsessions (user, ip_addr, port) VALUES (\'%u\', \'%L\', %{remote-port})"', 5430 SQLLog => 'EXIT logout', 5431 }, 5432 }, 5433 }; 5434 5435 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 5436 $config); 5437 5438 # Open pipes, for use between the parent and child processes. Specifically, 5439 # the child will indicate when it's done with its test by writing a message 5440 # to the parent. 5441 my ($rfh, $wfh); 5442 unless (pipe($rfh, $wfh)) { 5443 die("Can't open pipe: $!"); 5444 } 5445 5446 my $ex; 5447 5448 # Fork child 5449 $self->handle_sigchld(); 5450 defined(my $pid = fork()) or die("Can't fork: $!"); 5451 if ($pid) { 5452 eval { 5453 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 5454 $client->login($setup->{user}, $setup->{passwd}); 5455 $client->quit(); 5456 }; 5457 if ($@) { 5458 $ex = $@; 5459 } 5460 5461 $wfh->print("done\n"); 5462 $wfh->flush(); 5463 5464 } else { 5465 eval { server_wait($setup->{config_file}, $rfh) }; 5466 if ($@) { 5467 warn($@); 5468 exit 1; 5469 } 5470 5471 exit 0; 5472 } 5473 5474 # Stop server 5475 server_stop($setup->{pid_file}); 5476 $self->assert_child_ok($pid); 5477 5478 if ($ex) { 5479 test_cleanup($setup->{log_file}, $ex); 5480 } 5481 5482 eval { 5483 my $query = "SELECT * FROM ftpsessions where user = '$setup->{user}'"; 5484 $cmd = "sqlite3 $db_file \"$query\""; 5485 5486 if ($ENV{TEST_VERBOSE}) { 5487 print STDERR "Executing sqlite3: $cmd\n"; 5488 } 5489 5490 my $output = `$cmd`; 5491 my $res = join('', `$cmd`); 5492 chomp($res); 5493 5494 my ($login, $ip_addr, $remote_port) = split(/\|/, $res); 5495 5496 my $expected = $setup->{user}; 5497 $self->assert($expected eq $login, "Expected '$expected', got '$login'"); 5498 5499 $expected = '127.0.0.1'; 5500 $self->assert($expected eq $ip_addr, 5501 "Expected '$expected', got '$ip_addr'"); 5502 }; 5503 if ($@) { 5504 $ex = $@; 5505 } 5506 5507 test_cleanup($setup->{log_file}, $ex); 5508} 5509 5510sub get_locations { 5511 my $db_file = shift; 5512 my $where = shift; 5513 5514 my $sql = "SELECT user, ip_addr, dir FROM ftpsessions"; 5515 if ($where) { 5516 $sql .= " WHERE $where"; 5517 } 5518 5519 my $cmd = "sqlite3 $db_file \"$sql\""; 5520 5521 if ($ENV{TEST_VERBOSE}) { 5522 print STDERR "Executing sqlite3: $cmd\n"; 5523 } 5524 5525 my $res = join('', `$cmd`); 5526 chomp($res); 5527 5528 if ($ENV{TEST_VERBOSE}) { 5529 print STDERR "Results: $res\n"; 5530 } 5531 5532 # The default sqlite3 delimiter is '|' 5533 return split(/\|/, $res); 5534} 5535 5536sub sql_sqllog_var_d_bug3395 { 5537 my $self = shift; 5538 my $tmpdir = $self->{tmpdir}; 5539 my $setup = test_setup($tmpdir, 'sqlite'); 5540 5541 my $sub_dir = File::Spec->rel2abs("$tmpdir/foo"); 5542 mkpath($sub_dir); 5543 5544 # Make sure that, if we're running as root, that the home directory has 5545 # permissions/privs set for the account we create 5546 if ($< == 0) { 5547 unless (chmod(0755, $sub_dir)) { 5548 die("Can't set perms on $sub_dir to 0755: $!"); 5549 } 5550 5551 unless (chown($setup->{uid}, $setup->{gid}, $sub_dir)) { 5552 die("Can't set owner of $sub_dir to $setup->{uid}/$setup->{gid}: $!"); 5553 } 5554 } 5555 5556 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5557 5558 # Build up sqlite3 command to create users, groups tables and populate them 5559 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5560 5561 if (open(my $fh, "> $db_script")) { 5562 print $fh <<EOS; 5563CREATE TABLE ftpsessions ( 5564 user TEXT, 5565 ip_addr TEXT, 5566 dir TEXT 5567); 5568EOS 5569 5570 unless (close($fh)) { 5571 die("Can't write $db_script: $!"); 5572 } 5573 5574 } else { 5575 die("Can't open $db_script: $!"); 5576 } 5577 5578 my $cmd = "sqlite3 $db_file < $db_script"; 5579 build_db($cmd, $db_script); 5580 5581 # Make sure that, if we're running as root, the database file has 5582 # the permissions/privs set for use by proftpd 5583 if ($< == 0) { 5584 unless (chmod(0666, $db_file)) { 5585 die("Can't set perms on $db_file to 0666: $!"); 5586 } 5587 } 5588 5589 my $config = { 5590 PidFile => $setup->{pid_file}, 5591 ScoreboardFile => $setup->{scoreboard_file}, 5592 SystemLog => $setup->{log_file}, 5593 TraceLog => $setup->{log_file}, 5594 Trace => 'jot:20 sql:20', 5595 5596 AuthUserFile => $setup->{auth_user_file}, 5597 AuthGroupFile => $setup->{auth_group_file}, 5598 5599 IfModules => { 5600 'mod_delay.c' => { 5601 DelayEngine => 'off', 5602 }, 5603 5604 'mod_sql.c' => { 5605 SQLEngine => 'log', 5606 SQLBackend => 'sqlite3', 5607 SQLConnectInfo => $db_file, 5608 SQLLogFile => $setup->{log_file}, 5609 SQLNamedQuery => 'location FREEFORM "INSERT INTO ftpsessions (user, ip_addr, dir) VALUES (\'%u\', \'%L\', \'%d\')"', 5610 SQLLog => 'EXIT location', 5611 }, 5612 }, 5613 }; 5614 5615 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 5616 $config); 5617 5618 # Open pipes, for use between the parent and child processes. Specifically, 5619 # the child will indicate when it's done with its test by writing a message 5620 # to the parent. 5621 my ($rfh, $wfh); 5622 unless (pipe($rfh, $wfh)) { 5623 die("Can't open pipe: $!"); 5624 } 5625 5626 my $ex; 5627 5628 # Fork child 5629 $self->handle_sigchld(); 5630 defined(my $pid = fork()) or die("Can't fork: $!"); 5631 if ($pid) { 5632 eval { 5633 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 5634 $client->login($setup->{user}, $setup->{passwd}); 5635 $client->cwd('foo'); 5636 $client->quit(); 5637 }; 5638 if ($@) { 5639 $ex = $@; 5640 } 5641 5642 $wfh->print("done\n"); 5643 $wfh->flush(); 5644 5645 } else { 5646 eval { server_wait($setup->{config_file}, $rfh) }; 5647 if ($@) { 5648 warn($@); 5649 exit 1; 5650 } 5651 5652 exit 0; 5653 } 5654 5655 # Stop server 5656 server_stop($setup->{pid_file}); 5657 $self->assert_child_ok($pid); 5658 5659 if ($ex) { 5660 test_cleanup($setup->{log_file}, $ex); 5661 } 5662 5663 eval { 5664 my ($login, $ip_addr, $dir) = get_locations($db_file, "user = \'$setup->{user}\'"); 5665 5666 my $expected = $setup->{user}; 5667 $self->assert($expected eq $login, "Expected '$expected', got '$login'"); 5668 5669 $expected = '127.0.0.1'; 5670 $self->assert($expected eq $ip_addr, 5671 "Expected '$expected', got '$ip_addr'"); 5672 5673 if ($^O eq 'darwin') { 5674 # MacOSX-specific hack 5675 $sub_dir = '/private' . $sub_dir; 5676 } 5677 5678 $expected = $sub_dir; 5679 $self->assert($expected eq $dir, "Expected '$expected', got '$dir'"); 5680 }; 5681 if ($@) { 5682 $ex = $@; 5683 } 5684 5685 test_cleanup($setup->{log_file}, $ex); 5686} 5687 5688sub sql_sqllog_var_d_chroot_bug3395 { 5689 my $self = shift; 5690 my $tmpdir = $self->{tmpdir}; 5691 5692 my $config_file = "$tmpdir/sqlite.conf"; 5693 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 5694 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 5695 5696 my $log_file = test_get_logfile(); 5697 5698 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 5699 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 5700 5701 my $user = 'proftpd'; 5702 my $passwd = 'test'; 5703 my $group = 'ftpd'; 5704 my $home_dir = File::Spec->rel2abs($tmpdir); 5705 my $uid = 500; 5706 my $gid = 500; 5707 5708 my $sub_dir = File::Spec->rel2abs("$tmpdir/foo"); 5709 mkpath($sub_dir); 5710 5711 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 5712 '/bin/bash'); 5713 auth_group_write($auth_group_file, $group, $gid, $user); 5714 5715 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5716 5717 # Build up sqlite3 command to create users, groups tables and populate them 5718 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5719 5720 if (open(my $fh, "> $db_script")) { 5721 print $fh <<EOS; 5722CREATE TABLE ftpsessions ( 5723 user TEXT, 5724 ip_addr TEXT, 5725 dir TEXT 5726); 5727EOS 5728 5729 unless (close($fh)) { 5730 die("Can't write $db_script: $!"); 5731 } 5732 5733 } else { 5734 die("Can't open $db_script: $!"); 5735 } 5736 5737 my $cmd = "sqlite3 $db_file < $db_script"; 5738 build_db($cmd, $db_script); 5739 5740 # Make sure that, if we're running as root, that the home directory has 5741 # permissions/privs set for the account we create 5742 if ($< == 0) { 5743 unless (chmod(0755, $home_dir, $sub_dir)) { 5744 die("Can't set perms on $home_dir to 0755: $!"); 5745 } 5746 5747 unless (chown($uid, $gid, $home_dir, $sub_dir)) { 5748 die("Can't set owner of $home_dir to $uid/$gid: $!"); 5749 } 5750 5751 unless (chmod(0666, $db_file)) { 5752 die("Can't set perms on $db_file to 0666: $!"); 5753 } 5754 } 5755 5756 my $config = { 5757 PidFile => $pid_file, 5758 ScoreboardFile => $scoreboard_file, 5759 SystemLog => $log_file, 5760 5761 AuthUserFile => $auth_user_file, 5762 AuthGroupFile => $auth_group_file, 5763 5764 IfModules => { 5765 'mod_delay.c' => { 5766 DelayEngine => 'off', 5767 }, 5768 5769 'mod_sql.c' => { 5770 SQLEngine => 'log', 5771 SQLBackend => 'sqlite3', 5772 SQLConnectInfo => "$db_file foo bar PERCONNECTION", 5773 SQLLogFile => $log_file, 5774 SQLNamedQuery => 'location FREEFORM "INSERT INTO ftpsessions (user, ip_addr, dir) VALUES (\'%u\', \'%L\', \'%d\')"', 5775 SQLLog => 'EXIT location', 5776 }, 5777 }, 5778 }; 5779 5780 my ($port, $config_user, $config_group) = config_write($config_file, $config); 5781 5782 # Open pipes, for use between the parent and child processes. Specifically, 5783 # the child will indicate when it's done with its test by writing a message 5784 # to the parent. 5785 my ($rfh, $wfh); 5786 unless (pipe($rfh, $wfh)) { 5787 die("Can't open pipe: $!"); 5788 } 5789 5790 my $ex; 5791 5792 # Fork child 5793 $self->handle_sigchld(); 5794 defined(my $pid = fork()) or die("Can't fork: $!"); 5795 if ($pid) { 5796 eval { 5797 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 5798 $client->login($user, $passwd); 5799 $client->cwd('foo'); 5800 $client->quit(); 5801 }; 5802 5803 if ($@) { 5804 $ex = $@; 5805 } 5806 5807 $wfh->print("done\n"); 5808 $wfh->flush(); 5809 5810 } else { 5811 eval { server_wait($config_file, $rfh) }; 5812 if ($@) { 5813 warn($@); 5814 exit 1; 5815 } 5816 5817 exit 0; 5818 } 5819 5820 # Stop server 5821 server_stop($pid_file); 5822 5823 $self->assert_child_ok($pid); 5824 5825 if ($ex) { 5826 test_append_logfile($log_file, $ex); 5827 unlink($log_file); 5828 5829 die($ex); 5830 } 5831 5832 my ($login, $ip_addr, $dir) = get_locations($db_file, "user = \'$user\'"); 5833 5834 my $expected; 5835 5836 $expected = $user; 5837 $self->assert($expected eq $login, 5838 test_msg("Expected '$expected', got '$login'")); 5839 5840 $expected = '127.0.0.1'; 5841 $self->assert($expected eq $ip_addr, 5842 test_msg("Expected '$expected', got '$ip_addr'")); 5843 5844 $expected = $sub_dir; 5845 $self->assert($expected eq $dir, 5846 test_msg("Expected '$expected', got '$dir'")); 5847 5848 unlink($log_file); 5849} 5850 5851sub get_ids { 5852 my $db_file = shift; 5853 my $where = shift; 5854 5855 my $sql = "SELECT user, ip_addr, uid, gid FROM ftpsessions"; 5856 if ($where) { 5857 $sql .= " WHERE $where"; 5858 } 5859 5860 my $cmd = "sqlite3 $db_file \"$sql\""; 5861 5862 if ($ENV{TEST_VERBOSE}) { 5863 print STDERR "Executing sqlite3: $cmd\n"; 5864 } 5865 5866 my $res = join('', `$cmd`); 5867 chomp($res); 5868 5869 # The default sqlite3 delimiter is '|' 5870 return split(/\|/, $res); 5871} 5872 5873sub sql_sqllog_var_uid_gid_bug3390 { 5874 my $self = shift; 5875 my $tmpdir = $self->{tmpdir}; 5876 5877 my $config_file = "$tmpdir/sqlite.conf"; 5878 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 5879 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 5880 5881 my $log_file = test_get_logfile(); 5882 5883 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 5884 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 5885 5886 my $user = 'proftpd'; 5887 my $passwd = 'test'; 5888 my $group = 'ftpd'; 5889 my $home_dir = File::Spec->rel2abs($tmpdir); 5890 my $uid = 500; 5891 my $gid = 500; 5892 5893 my $sub_dir = File::Spec->rel2abs("$tmpdir/foo"); 5894 mkpath($sub_dir); 5895 5896 # Make sure that, if we're running as root, that the home directory has 5897 # permissions/privs set for the account we create 5898 if ($< == 0) { 5899 unless (chmod(0755, $home_dir, $sub_dir)) { 5900 die("Can't set perms on $home_dir to 0755: $!"); 5901 } 5902 5903 unless (chown($uid, $gid, $home_dir, $sub_dir)) { 5904 die("Can't set owner of $home_dir to $uid/$gid: $!"); 5905 } 5906 } 5907 5908 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 5909 '/bin/bash'); 5910 auth_group_write($auth_group_file, $group, $gid, $user); 5911 5912 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 5913 5914 # Build up sqlite3 command to create users, groups tables and populate them 5915 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 5916 5917 if (open(my $fh, "> $db_script")) { 5918 print $fh <<EOS; 5919CREATE TABLE ftpsessions ( 5920 user TEXT, 5921 ip_addr TEXT, 5922 uid NUMBER, 5923 gid NUMBER 5924); 5925EOS 5926 5927 unless (close($fh)) { 5928 die("Can't write $db_script: $!"); 5929 } 5930 5931 } else { 5932 die("Can't open $db_script: $!"); 5933 } 5934 5935 my $cmd = "sqlite3 $db_file < $db_script"; 5936 build_db($cmd, $db_script); 5937 5938 # Make sure that, if we're running as root, the database file has 5939 # the permissions/privs set for use by proftpd 5940 if ($< == 0) { 5941 unless (chmod(0666, $db_file)) { 5942 die("Can't set perms on $db_file to 0666: $!"); 5943 } 5944 } 5945 5946 my $config = { 5947 PidFile => $pid_file, 5948 ScoreboardFile => $scoreboard_file, 5949 SystemLog => $log_file, 5950 5951 AuthUserFile => $auth_user_file, 5952 AuthGroupFile => $auth_group_file, 5953 5954 IfModules => { 5955 'mod_delay.c' => { 5956 DelayEngine => 'off', 5957 }, 5958 5959 'mod_sql.c' => { 5960 SQLEngine => 'log', 5961 SQLBackend => 'sqlite3', 5962 SQLConnectInfo => "$db_file foo bar PERCONNECTION", 5963 SQLLogFile => $log_file, 5964 SQLNamedQuery => 'location FREEFORM "INSERT INTO ftpsessions (user, ip_addr, uid, gid) VALUES (\'%u\', \'%L\', %{uid}, %{gid})"', 5965 SQLLog => 'PASS location', 5966 }, 5967 }, 5968 }; 5969 5970 my ($port, $config_user, $config_group) = config_write($config_file, $config); 5971 5972 # Open pipes, for use between the parent and child processes. Specifically, 5973 # the child will indicate when it's done with its test by writing a message 5974 # to the parent. 5975 my ($rfh, $wfh); 5976 unless (pipe($rfh, $wfh)) { 5977 die("Can't open pipe: $!"); 5978 } 5979 5980 my $ex; 5981 5982 # Fork child 5983 $self->handle_sigchld(); 5984 defined(my $pid = fork()) or die("Can't fork: $!"); 5985 if ($pid) { 5986 eval { 5987 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 5988 $client->login($user, $passwd); 5989 $client->cwd('foo'); 5990 $client->quit(); 5991 }; 5992 5993 if ($@) { 5994 $ex = $@; 5995 } 5996 5997 $wfh->print("done\n"); 5998 $wfh->flush(); 5999 6000 } else { 6001 eval { server_wait($config_file, $rfh) }; 6002 if ($@) { 6003 warn($@); 6004 exit 1; 6005 } 6006 6007 exit 0; 6008 } 6009 6010 # Stop server 6011 server_stop($pid_file); 6012 6013 $self->assert_child_ok($pid); 6014 6015 if ($ex) { 6016 test_append_logfile($log_file, $ex); 6017 unlink($log_file); 6018 6019 die($ex); 6020 } 6021 6022 my ($login, $ip_addr, $sql_uid, $sql_gid) = get_ids($db_file, "user = \'$user\'"); 6023 6024 my $expected; 6025 6026 $expected = $user; 6027 $self->assert($expected eq $login, 6028 test_msg("Expected '$expected', got '$login'")); 6029 6030 $expected = '127.0.0.1'; 6031 $self->assert($expected eq $ip_addr, 6032 test_msg("Expected '$expected', got '$ip_addr'")); 6033 6034 $expected = $uid; 6035 $self->assert($expected == $sql_uid, 6036 test_msg("Expected $expected, got $sql_uid")); 6037 6038 $expected = $gid; 6039 $self->assert($expected == $sql_gid, 6040 test_msg("Expected $expected, got $sql_gid")); 6041 6042 unlink($log_file); 6043} 6044 6045sub sql_sqlite_auth_type_backend_bug3511 { 6046 my $self = shift; 6047 my $tmpdir = $self->{tmpdir}; 6048 my $setup = test_setup($tmpdir, 'sqlite'); 6049 6050 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6051 6052 my $config = { 6053 PidFile => $setup->{pid_file}, 6054 ScoreboardFile => $setup->{scoreboard_file}, 6055 SystemLog => $setup->{log_file}, 6056 6057 IfModules => { 6058 'mod_delay.c' => { 6059 DelayEngine => 'off', 6060 }, 6061 6062 'mod_sql.c' => { 6063 SQLAuthTypes => 'backend', 6064 SQLBackend => 'sqlite3', 6065 SQLConnectInfo => $db_file, 6066 SQLLogFile => $setup->{log_file}, 6067 }, 6068 }, 6069 }; 6070 6071 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 6072 $config); 6073 6074 # As of Bug#4281, the mod_sql module no longer supports the "Backend" 6075 # SQLAuthType itself. Which means that attempting to use it here, with 6076 # mod_sql_sqlite, will cause the server to not start up at all. 6077 6078 my $ex; 6079 6080 # This should silently fail. 6081 server_start($setup->{config_file}); 6082 6083 # This is where we detect the actual problem. 6084 eval { server_stop($setup->{pid_file}) }; 6085 unless ($@) { 6086 $ex = "Server start with bad config unexpectedly"; 6087 } 6088 6089 test_cleanup($setup->{log_file}, $ex); 6090} 6091 6092sub sql_sqllog_pass_ok_var_s_bug3528 { 6093 my $self = shift; 6094 my $tmpdir = $self->{tmpdir}; 6095 6096 my $config_file = "$tmpdir/sqlite.conf"; 6097 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 6098 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 6099 6100 my $log_file = test_get_logfile(); 6101 6102 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 6103 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 6104 6105 my $user = 'proftpd'; 6106 my $passwd = 'test'; 6107 my $group = 'ftpd'; 6108 my $home_dir = File::Spec->rel2abs($tmpdir); 6109 my $uid = 500; 6110 my $gid = 500; 6111 6112 # Make sure that, if we're running as root, that the home directory has 6113 # permissions/privs set for the account we create 6114 if ($< == 0) { 6115 unless (chmod(0755, $home_dir)) { 6116 die("Can't set perms on $home_dir to 0755: $!"); 6117 } 6118 6119 unless (chown($uid, $gid, $home_dir)) { 6120 die("Can't set owner of $home_dir to $uid/$gid: $!"); 6121 } 6122 } 6123 6124 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 6125 '/bin/bash'); 6126 auth_group_write($auth_group_file, $group, $gid, $user); 6127 6128 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6129 6130 # Build up sqlite3 command to create users, groups tables and populate them 6131 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6132 6133 if (open(my $fh, "> $db_script")) { 6134 print $fh <<EOS; 6135CREATE TABLE ftpsessions ( 6136 user TEXT, 6137 resp_code TEXT, 6138 resp_mesg TEXT 6139); 6140EOS 6141 6142 unless (close($fh)) { 6143 die("Can't write $db_script: $!"); 6144 } 6145 6146 } else { 6147 die("Can't open $db_script: $!"); 6148 } 6149 6150 my $cmd = "sqlite3 $db_file < $db_script"; 6151 build_db($cmd, $db_script); 6152 6153 # Make sure that, if we're running as root, the database file has 6154 # the permissions/privs set for use by proftpd 6155 if ($< == 0) { 6156 unless (chmod(0666, $db_file)) { 6157 die("Can't set perms on $db_file to 0666: $!"); 6158 } 6159 } 6160 6161 my $config = { 6162 PidFile => $pid_file, 6163 ScoreboardFile => $scoreboard_file, 6164 SystemLog => $log_file, 6165 6166 AuthUserFile => $auth_user_file, 6167 AuthGroupFile => $auth_group_file, 6168 6169 IfModules => { 6170 'mod_delay.c' => { 6171 DelayEngine => 'off', 6172 }, 6173 6174 'mod_sql.c' => { 6175 SQLEngine => 'log', 6176 SQLBackend => 'sqlite3', 6177 SQLConnectInfo => $db_file, 6178 SQLLogFile => $log_file, 6179 SQLNamedQuery => 'info FREEFORM "INSERT INTO ftpsessions (user, resp_code, resp_mesg) VALUES (\'%u\', \'%s\', \'%S\')"', 6180 SQLLog => 'PASS,ERR_PASS info', 6181 }, 6182 }, 6183 }; 6184 6185 my ($port, $config_user, $config_group) = config_write($config_file, $config); 6186 6187 # Open pipes, for use between the parent and child processes. Specifically, 6188 # the child will indicate when it's done with its test by writing a message 6189 # to the parent. 6190 my ($rfh, $wfh); 6191 unless (pipe($rfh, $wfh)) { 6192 die("Can't open pipe: $!"); 6193 } 6194 6195 my $ex; 6196 6197 # Fork child 6198 $self->handle_sigchld(); 6199 defined(my $pid = fork()) or die("Can't fork: $!"); 6200 if ($pid) { 6201 eval { 6202 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6203 $client->login($user, $passwd); 6204 $client->quit(); 6205 }; 6206 6207 if ($@) { 6208 $ex = $@; 6209 } 6210 6211 $wfh->print("done\n"); 6212 $wfh->flush(); 6213 6214 } else { 6215 eval { server_wait($config_file, $rfh) }; 6216 if ($@) { 6217 warn($@); 6218 exit 1; 6219 } 6220 6221 exit 0; 6222 } 6223 6224 # Stop server 6225 server_stop($pid_file); 6226 6227 $self->assert_child_ok($pid); 6228 6229 if ($ex) { 6230 test_append_logfile($log_file, $ex); 6231 unlink($log_file); 6232 6233 die($ex); 6234 } 6235 6236 my ($login, $resp_code, $resp_mesg) = get_resp_mesgs($db_file, 6237 undef, "user, resp_code, resp_mesg"); 6238 6239 my $expected; 6240 6241 $expected = 230; 6242 $self->assert($expected eq $resp_code, 6243 test_msg("Expected '$expected', got '$resp_code'")); 6244 6245 $expected = "User $user logged in"; 6246 $self->assert($expected eq $resp_mesg, 6247 test_msg("Expected '$expected', got '$resp_mesg'")); 6248 6249 unlink($log_file); 6250} 6251 6252sub sql_sqllog_pass_failed_var_s_bug3528 { 6253 my $self = shift; 6254 my $tmpdir = $self->{tmpdir}; 6255 6256 my $config_file = "$tmpdir/sqlite.conf"; 6257 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 6258 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 6259 6260 my $log_file = test_get_logfile(); 6261 6262 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 6263 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 6264 6265 my $user = 'proftpd'; 6266 my $passwd = 'test'; 6267 my $group = 'ftpd'; 6268 my $home_dir = File::Spec->rel2abs($tmpdir); 6269 my $uid = 500; 6270 my $gid = 500; 6271 6272 # Make sure that, if we're running as root, that the home directory has 6273 # permissions/privs set for the account we create 6274 if ($< == 0) { 6275 unless (chmod(0755, $home_dir)) { 6276 die("Can't set perms on $home_dir to 0755: $!"); 6277 } 6278 6279 unless (chown($uid, $gid, $home_dir)) { 6280 die("Can't set owner of $home_dir to $uid/$gid: $!"); 6281 } 6282 } 6283 6284 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 6285 '/bin/bash'); 6286 auth_group_write($auth_group_file, $group, $gid, $user); 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 ftpsessions ( 6296 user TEXT, 6297 resp_code TEXT, 6298 resp_mesg TEXT 6299); 6300EOS 6301 6302 unless (close($fh)) { 6303 die("Can't write $db_script: $!"); 6304 } 6305 6306 } else { 6307 die("Can't open $db_script: $!"); 6308 } 6309 6310 my $cmd = "sqlite3 $db_file < $db_script"; 6311 build_db($cmd, $db_script); 6312 6313 # Make sure that, if we're running as root, the database file has 6314 # the permissions/privs set for use by proftpd 6315 if ($< == 0) { 6316 unless (chmod(0666, $db_file)) { 6317 die("Can't set perms on $db_file to 0666: $!"); 6318 } 6319 } 6320 6321 my $config = { 6322 PidFile => $pid_file, 6323 ScoreboardFile => $scoreboard_file, 6324 SystemLog => $log_file, 6325 6326 AuthUserFile => $auth_user_file, 6327 AuthGroupFile => $auth_group_file, 6328 6329 IfModules => { 6330 'mod_delay.c' => { 6331 DelayEngine => 'off', 6332 }, 6333 6334 'mod_sql.c' => { 6335 SQLEngine => 'log', 6336 SQLBackend => 'sqlite3', 6337 SQLConnectInfo => $db_file, 6338 SQLLogFile => $log_file, 6339 SQLNamedQuery => 'info FREEFORM "INSERT INTO ftpsessions (user, resp_code, resp_mesg) VALUES (\'%u\', \'%s\', \'%S\')"', 6340 SQLLog => 'PASS,ERR_PASS info', 6341 }, 6342 }, 6343 }; 6344 6345 my ($port, $config_user, $config_group) = config_write($config_file, $config); 6346 6347 # Open pipes, for use between the parent and child processes. Specifically, 6348 # the child will indicate when it's done with its test by writing a message 6349 # to the parent. 6350 my ($rfh, $wfh); 6351 unless (pipe($rfh, $wfh)) { 6352 die("Can't open pipe: $!"); 6353 } 6354 6355 my $ex; 6356 6357 # Fork child 6358 $self->handle_sigchld(); 6359 defined(my $pid = fork()) or die("Can't fork: $!"); 6360 if ($pid) { 6361 eval { 6362 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6363 eval { $client->login($user, 'foobar') }; 6364 unless ($@) { 6365 die("Login succeeded unexpectedly"); 6366 } 6367 6368 $client->quit(); 6369 }; 6370 6371 if ($@) { 6372 $ex = $@; 6373 } 6374 6375 $wfh->print("done\n"); 6376 $wfh->flush(); 6377 6378 } else { 6379 eval { server_wait($config_file, $rfh) }; 6380 if ($@) { 6381 warn($@); 6382 exit 1; 6383 } 6384 6385 exit 0; 6386 } 6387 6388 # Stop server 6389 server_stop($pid_file); 6390 6391 $self->assert_child_ok($pid); 6392 6393 if ($ex) { 6394 test_append_logfile($log_file, $ex); 6395 unlink($log_file); 6396 6397 die($ex); 6398 } 6399 6400 my ($login, $resp_code, $resp_mesg) = get_resp_mesgs($db_file, 6401 undef, "user, resp_code, resp_mesg"); 6402 6403 my $expected; 6404 6405 $expected = 530; 6406 $self->assert($expected eq $resp_code, 6407 test_msg("Expected '$expected', got '$resp_code'")); 6408 6409 $expected = "Login incorrect."; 6410 $self->assert($expected eq $resp_mesg, 6411 test_msg("Expected '$expected', got '$resp_mesg'")); 6412 6413 unlink($log_file); 6414} 6415 6416sub sql_sqllog_pass_failed_bug4301 { 6417 my $self = shift; 6418 my $tmpdir = $self->{tmpdir}; 6419 6420 my $config_file = "$tmpdir/sqlite.conf"; 6421 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 6422 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 6423 6424 my $log_file = test_get_logfile(); 6425 6426 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 6427 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 6428 6429 my $user = 'proftpd'; 6430 my $passwd = 'test'; 6431 my $group = 'ftpd'; 6432 my $home_dir = File::Spec->rel2abs($tmpdir); 6433 my $uid = 500; 6434 my $gid = 500; 6435 6436 # Make sure that, if we're running as root, that the home directory has 6437 # permissions/privs set for the account we create 6438 if ($< == 0) { 6439 unless (chmod(0755, $home_dir)) { 6440 die("Can't set perms on $home_dir to 0755: $!"); 6441 } 6442 6443 unless (chown($uid, $gid, $home_dir)) { 6444 die("Can't set owner of $home_dir to $uid/$gid: $!"); 6445 } 6446 } 6447 6448 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 6449 '/bin/bash'); 6450 auth_group_write($auth_group_file, $group, $gid, $user); 6451 6452 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6453 6454 # Build up sqlite3 command to create users, groups tables and populate them 6455 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6456 6457 if (open(my $fh, "> $db_script")) { 6458 print $fh <<EOS; 6459CREATE TABLE ftpsessions ( 6460 user TEXT, 6461 resp_code TEXT, 6462 resp_mesg TEXT 6463); 6464EOS 6465 6466 unless (close($fh)) { 6467 die("Can't write $db_script: $!"); 6468 } 6469 6470 } else { 6471 die("Can't open $db_script: $!"); 6472 } 6473 6474 my $cmd = "sqlite3 $db_file < $db_script"; 6475 build_db($cmd, $db_script); 6476 6477 # Make sure that, if we're running as root, the database file has 6478 # the permissions/privs set for use by proftpd 6479 if ($< == 0) { 6480 unless (chmod(0666, $db_file)) { 6481 die("Can't set perms on $db_file to 0666: $!"); 6482 } 6483 } 6484 6485 my $config = { 6486 PidFile => $pid_file, 6487 ScoreboardFile => $scoreboard_file, 6488 SystemLog => $log_file, 6489 6490 AuthUserFile => $auth_user_file, 6491 AuthGroupFile => $auth_group_file, 6492 6493 IfModules => { 6494 'mod_delay.c' => { 6495 DelayEngine => 'off', 6496 }, 6497 6498 'mod_sql.c' => { 6499 SQLEngine => 'log', 6500 SQLBackend => 'sqlite3', 6501 SQLConnectInfo => $db_file, 6502 SQLLogFile => $log_file, 6503 SQLNamedQuery => 'info FREEFORM "INSERT INTO ftpsessions (user, resp_code, resp_mesg) VALUES (\'%u\', \'%s\', \'%S\')"', 6504 SQLLog => 'PASS info', 6505 }, 6506 }, 6507 }; 6508 6509 my ($port, $config_user, $config_group) = config_write($config_file, $config); 6510 6511 # Open pipes, for use between the parent and child processes. Specifically, 6512 # the child will indicate when it's done with its test by writing a message 6513 # to the parent. 6514 my ($rfh, $wfh); 6515 unless (pipe($rfh, $wfh)) { 6516 die("Can't open pipe: $!"); 6517 } 6518 6519 my $ex; 6520 6521 # Fork child 6522 $self->handle_sigchld(); 6523 defined(my $pid = fork()) or die("Can't fork: $!"); 6524 if ($pid) { 6525 eval { 6526 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6527 $client->user($user); 6528 eval { $client->pass('') }; 6529 unless ($@) { 6530 die("PASS succeeded unexpectedly"); 6531 } 6532 6533 $client->quit(); 6534 }; 6535 6536 if ($@) { 6537 $ex = $@; 6538 } 6539 6540 $wfh->print("done\n"); 6541 $wfh->flush(); 6542 6543 } else { 6544 eval { server_wait($config_file, $rfh) }; 6545 if ($@) { 6546 warn($@); 6547 exit 1; 6548 } 6549 6550 exit 0; 6551 } 6552 6553 # Stop server 6554 server_stop($pid_file); 6555 $self->assert_child_ok($pid); 6556 6557 if ($ex) { 6558 test_append_logfile($log_file, $ex); 6559 unlink($log_file); 6560 6561 die($ex); 6562 } 6563 6564 # We want to ensure/assert that a failed PASS command does NOT cause 6565 # the SQLLog directive to be triggered (Bug#4301). 6566 eval { 6567 my ($login, $resp_code, $resp_mesg) = get_resp_mesgs($db_file, 6568 undef, "user, resp_code, resp_mesg"); 6569 $self->assert(!defined($resp_code), "Expected undef, got $resp_code"); 6570 $self->assert(!defined($resp_mesg), "Expected undef, got '$resp_mesg'"); 6571 }; 6572 if ($@) { 6573 $ex = $@; 6574 } 6575 6576 if ($ex) { 6577 test_append_logfile($log_file, $ex); 6578 unlink($log_file); 6579 6580 die($ex); 6581 } 6582 6583 unlink($log_file); 6584} 6585 6586sub sql_sqlshowinfo_pass_bug3423 { 6587 my $self = shift; 6588 my $tmpdir = $self->{tmpdir}; 6589 my $setup = test_setup($tmpdir, 'sqlite'); 6590 6591 my $lastdir = '/path/to/lastdir'; 6592 6593 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6594 6595 # Build up sqlite3 command to create users, groups tables and populate them 6596 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6597 6598 if (open(my $fh, "> $db_script")) { 6599 print $fh <<EOS; 6600CREATE TABLE users ( 6601 userid TEXT, 6602 passwd TEXT, 6603 uid INTEGER, 6604 gid INTEGER, 6605 homedir TEXT, 6606 shell TEXT, 6607 lastdir TEXT 6608); 6609INSERT INTO users (userid, passwd, uid, gid, homedir, shell, lastdir) VALUES ('$setup->{user}', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash', '$lastdir'); 6610 6611CREATE TABLE groups ( 6612 groupname TEXT, 6613 gid INTEGER, 6614 members TEXT 6615); 6616INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); 6617EOS 6618 6619 unless (close($fh)) { 6620 die("Can't write $db_script: $!"); 6621 } 6622 6623 } else { 6624 die("Can't open $db_script: $!"); 6625 } 6626 6627 my $cmd = "sqlite3 $db_file < $db_script"; 6628 build_db($cmd, $db_script); 6629 6630 # Make sure that, if we're running as root, the database file has 6631 # the permissions/privs set for use by proftpd 6632 if ($< == 0) { 6633 unless (chmod(0666, $db_file)) { 6634 die("Can't set perms on $db_file to 0666: $!"); 6635 } 6636 } 6637 6638 my $config = { 6639 PidFile => $setup->{pid_file}, 6640 ScoreboardFile => $setup->{scoreboard_file}, 6641 SystemLog => $setup->{log_file}, 6642 TraceLog => $setup->{log_file}, 6643 Trace => 'jot:20 sql:20', 6644 6645 IfModules => { 6646 'mod_delay.c' => { 6647 DelayEngine => 'off', 6648 }, 6649 6650 'mod_sql.c' => [ 6651 'AuthOrder mod_sql.c', 6652 6653 'SQLAuthenticate users groups', 6654 'SQLAuthTypes plaintext', 6655 'SQLBackend sqlite3', 6656 "SQLConnectInfo $db_file", 6657 "SQLLogFile $setup->{log_file}", 6658 'SQLMinID 100', 6659 6660 'SQLNamedQuery lastdir SELECT "lastdir FROM users WHERE userid = \'%u\'"', 6661 6662 # Configure the equivalent of a multiline DisplayLogin file 6663 # using the SQLShowInfo directive 6664 'SQLShowInfo PASS 230 " "', 6665 'SQLShowInfo PASS 230 "Greetings, %u"', 6666 'SQLShowInfo PASS 230 "Last directory: \"%{lastdir}\""', 6667 'SQLShowInfo PASS 230 "-"', 6668 ], 6669 }, 6670 }; 6671 6672 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 6673 $config); 6674 6675 # Open pipes, for use between the parent and child processes. Specifically, 6676 # the child will indicate when it's done with its test by writing a message 6677 # to the parent. 6678 my ($rfh, $wfh); 6679 unless (pipe($rfh, $wfh)) { 6680 die("Can't open pipe: $!"); 6681 } 6682 6683 my $ex; 6684 6685 # Fork child 6686 $self->handle_sigchld(); 6687 defined(my $pid = fork()) or die("Can't fork: $!"); 6688 if ($pid) { 6689 eval { 6690 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6691 $client->login($setup->{user}, $setup->{passwd}); 6692 6693 my $resp_msgs = $client->response_msgs(); 6694 my $nmsgs = scalar(@$resp_msgs); 6695 6696 my $expected = 5; 6697 $self->assert($expected == $nmsgs, "Expected $expected, got $nmsgs"); 6698 6699 $expected = " "; 6700 $self->assert($expected eq $resp_msgs->[0], 6701 "Expected '$expected', got '$resp_msgs->[0]'"); 6702 6703 $expected = " Greetings, $setup->{user}"; 6704 $self->assert($expected eq $resp_msgs->[1], 6705 "Expected '$expected', got '$resp_msgs->[1]'"); 6706 6707 $expected = " Last directory: \"$lastdir\""; 6708 $self->assert($expected eq $resp_msgs->[2], 6709 "Expected '$expected', got '$resp_msgs->[2]'"); 6710 6711 $expected = " -"; 6712 $self->assert($expected eq $resp_msgs->[3], 6713 "Expected '$expected', got '$resp_msgs->[3]'"); 6714 6715 $expected = "User $setup->{user} logged in"; 6716 $self->assert($expected eq $resp_msgs->[4], 6717 "Expected '$expected', got '$resp_msgs->[4]'"); 6718 6719 $client->quit(); 6720 }; 6721 if ($@) { 6722 $ex = $@; 6723 } 6724 6725 $wfh->print("done\n"); 6726 $wfh->flush(); 6727 6728 } else { 6729 eval { server_wait($setup->{config_file}, $rfh) }; 6730 if ($@) { 6731 warn($@); 6732 exit 1; 6733 } 6734 6735 exit 0; 6736 } 6737 6738 # Stop server 6739 server_stop($setup->{pid_file}); 6740 $self->assert_child_ok($pid); 6741 6742 test_cleanup($setup->{log_file}, $ex); 6743} 6744 6745sub sql_sqlshowinfo_list_bug3423 { 6746 my $self = shift; 6747 my $tmpdir = $self->{tmpdir}; 6748 my $setup = test_setup($tmpdir, 'sqlite'); 6749 6750 my $lastdir = '/path/to/lastdir'; 6751 6752 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6753 6754 # Build up sqlite3 command to create users, groups tables and populate them 6755 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6756 6757 if (open(my $fh, "> $db_script")) { 6758 print $fh <<EOS; 6759CREATE TABLE users ( 6760 userid TEXT, 6761 passwd TEXT, 6762 uid INTEGER, 6763 gid INTEGER, 6764 homedir TEXT, 6765 shell TEXT, 6766 lastdir TEXT 6767); 6768INSERT INTO users (userid, passwd, uid, gid, homedir, shell, lastdir) VALUES ('$setup->{user}', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash', '$lastdir'); 6769 6770CREATE TABLE groups ( 6771 groupname TEXT, 6772 gid INTEGER, 6773 members TEXT 6774); 6775INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); 6776EOS 6777 6778 unless (close($fh)) { 6779 die("Can't write $db_script: $!"); 6780 } 6781 6782 } else { 6783 die("Can't open $db_script: $!"); 6784 } 6785 6786 my $cmd = "sqlite3 $db_file < $db_script"; 6787 build_db($cmd, $db_script); 6788 6789 # Make sure that, if we're running as root, the database file has 6790 # the permissions/privs set for use by proftpd 6791 if ($< == 0) { 6792 unless (chmod(0666, $db_file)) { 6793 die("Can't set perms on $db_file to 0666: $!"); 6794 } 6795 } 6796 6797 my $config = { 6798 PidFile => $setup->{pid_file}, 6799 ScoreboardFile => $setup->{scoreboard_file}, 6800 SystemLog => $setup->{log_file}, 6801 TraceLog => $setup->{log_file}, 6802 Trace => 'jot:20 sql:20', 6803 6804 IfModules => { 6805 'mod_delay.c' => { 6806 DelayEngine => 'off', 6807 }, 6808 6809 'mod_sql.c' => [ 6810 'AuthOrder mod_sql.c', 6811 6812 'SQLAuthenticate users groups', 6813 'SQLAuthTypes plaintext', 6814 'SQLBackend sqlite3', 6815 "SQLConnectInfo $db_file", 6816 "SQLLogFile $setup->{log_file}", 6817 'SQLMinID 100', 6818 6819 # Configure the equivalent of a multiline DisplayLogin file 6820 # using the SQLShowInfo directive 6821 6822 'SQLShowInfo LIST 226 "Get that directory listing OK, %u?"', 6823 'SQLShowInfo LIST 226 "-"', 6824 ], 6825 }, 6826 }; 6827 6828 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 6829 $config); 6830 6831 # Open pipes, for use between the parent and child processes. Specifically, 6832 # the child will indicate when it's done with its test by writing a message 6833 # to the parent. 6834 my ($rfh, $wfh); 6835 unless (pipe($rfh, $wfh)) { 6836 die("Can't open pipe: $!"); 6837 } 6838 6839 my $ex; 6840 6841 # Fork child 6842 $self->handle_sigchld(); 6843 defined(my $pid = fork()) or die("Can't fork: $!"); 6844 if ($pid) { 6845 eval { 6846 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 6847 $client->login($setup->{user}, $setup->{passwd}); 6848 6849 my $resp_code = $client->response_code(); 6850 my $resp_msg = $client->response_msg(); 6851 6852 my $expected = 230; 6853 $self->assert($expected == $resp_code, 6854 "Expected response code $expected, got $resp_code"); 6855 6856 $expected = "User $setup->{user} logged in"; 6857 $self->assert($expected eq $resp_msg, 6858 "Expected response message '$expected', got '$resp_msg'"); 6859 6860 my $conn = $client->list_raw(); 6861 unless ($conn) { 6862 die("LIST failed unexpectedly: " . $client->response_code() . " " . 6863 $client->response_msg()); 6864 } 6865 6866 my $buf; 6867 $conn->read($buf, 8192, 25); 6868 eval { $conn->close() }; 6869 6870 $resp_code = $client->response_code(); 6871 6872 $expected = 226; 6873 $self->assert($expected == $resp_code, 6874 "Expected response code $expected, got $resp_code"); 6875 6876 my $resp_msgs = $client->response_msgs(); 6877 my $nmsgs = scalar(@$resp_msgs); 6878 6879 $expected = 4; 6880 $self->assert($expected == $nmsgs, "Expected $expected, got $nmsgs"); 6881 6882 $expected = "Opening ASCII mode data connection for file list"; 6883 $self->assert($expected eq $resp_msgs->[0], 6884 "Expected response message '$expected', got '$resp_msgs->[0]'"); 6885 6886 $expected = "Transfer complete"; 6887 $self->assert($expected eq $resp_msgs->[1], 6888 "Expected response message '$expected', got '$resp_msgs->[1]'"); 6889 6890 $expected = " Get that directory listing OK, $setup->{user}?"; 6891 $self->assert($expected eq $resp_msgs->[2], 6892 "Expected response message '$expected', got '$resp_msgs->[2]'"); 6893 6894 $expected = "-"; 6895 $self->assert($expected eq $resp_msgs->[3], 6896 "Expected response message '$expected', got '$resp_msgs->[3]'"); 6897 6898 $client->quit(); 6899 }; 6900 if ($@) { 6901 $ex = $@; 6902 } 6903 6904 $wfh->print("done\n"); 6905 $wfh->flush(); 6906 6907 } else { 6908 eval { server_wait($setup->{config_file}, $rfh) }; 6909 if ($@) { 6910 warn($@); 6911 exit 1; 6912 } 6913 6914 exit 0; 6915 } 6916 6917 # Stop server 6918 server_stop($setup->{pid_file}); 6919 $self->assert_child_ok($pid); 6920 6921 test_cleanup($setup->{log_file}, $ex); 6922} 6923 6924sub sql_multiple_users_shared_uid_gid { 6925 my $self = shift; 6926 my $tmpdir = $self->{tmpdir}; 6927 6928 my $config_file = "$tmpdir/sqlite.conf"; 6929 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 6930 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 6931 6932 my $log_file = test_get_logfile(); 6933 6934 my $user = 'proftpd'; 6935 my $passwd = 'test'; 6936 my $group = 'ftpd'; 6937 my $home_dir = File::Spec->rel2abs($tmpdir); 6938 my $uid = 500; 6939 my $gid = 500; 6940 6941 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 6942 6943 # Build up sqlite3 command to create users, groups tables and populate them 6944 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 6945 6946 if (open(my $fh, "> $db_script")) { 6947 print $fh <<EOU; 6948CREATE TABLE users ( 6949 userid TEXT, 6950 passwd TEXT, 6951 uid INTEGER, 6952 gid INTEGER, 6953 homedir TEXT, 6954 shell TEXT 6955); 6956EOU 6957 6958 for (my $i = 1; $i <= 10; $i++) { 6959 my $name = $user . $i; 6960 6961 print $fh "INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$name', '$passwd', $uid, $gid, '$home_dir', '/bin/bash');\n"; 6962 } 6963 6964 print $fh <<EOG; 6965CREATE TABLE groups ( 6966 groupname TEXT, 6967 gid INTEGER, 6968 members TEXT 6969); 6970EOG 6971 6972 my $group_members = ($user . '1'); 6973 for (my $i = 2; $i <= 5; $i++) { 6974 my $name = $user . $i; 6975 $group_members .= ",$name"; 6976 } 6977 6978 my $group_name = ($group . '1'); 6979 print $fh "INSERT INTO groups (groupname, gid, members) VALUES ('$group_name', $gid, '$group_members');\n"; 6980 6981 $group_members = ($user . '6'); 6982 for (my $i = 7; $i <= 10; $i++) { 6983 my $name = $user . $i; 6984 $group_members .= ",$name"; 6985 } 6986 6987 $group_name = ($group . '2'); 6988 print $fh "INSERT INTO groups (groupname, gid, members) VALUES ('$group_name', $gid, '$group_members');\n"; 6989 6990 unless (close($fh)) { 6991 die("Can't write $db_script: $!"); 6992 } 6993 6994 } else { 6995 die("Can't open $db_script: $!"); 6996 } 6997 6998 my $cmd = "sqlite3 $db_file < $db_script"; 6999 build_db($cmd, $db_script); 7000 7001 # Make sure that, if we're running as root, the database file has 7002 # the permissions/privs set for use by proftpd 7003 if ($< == 0) { 7004 unless (chmod(0666, $db_file)) { 7005 die("Can't set perms on $db_file to 0666: $!"); 7006 } 7007 } 7008 7009 my $config = { 7010 PidFile => $pid_file, 7011 ScoreboardFile => $scoreboard_file, 7012 SystemLog => $log_file, 7013 7014 IfModules => { 7015 'mod_delay.c' => { 7016 DelayEngine => 'off', 7017 }, 7018 7019 'mod_sql.c' => [ 7020 'AuthOrder mod_sql.c', 7021 7022 'SQLAuthenticate users groups', 7023 'SQLAuthTypes plaintext', 7024 'SQLBackend sqlite3', 7025 "SQLConnectInfo $db_file", 7026 "SQLLogFile $log_file", 7027 'SQLMinID 100', 7028 ], 7029 }, 7030 }; 7031 7032 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7033 7034 # Open pipes, for use between the parent and child processes. Specifically, 7035 # the child will indicate when it's done with its test by writing a message 7036 # to the parent. 7037 my ($rfh, $wfh); 7038 unless (pipe($rfh, $wfh)) { 7039 die("Can't open pipe: $!"); 7040 } 7041 7042 my $ex; 7043 7044 # Fork child 7045 $self->handle_sigchld(); 7046 defined(my $pid = fork()) or die("Can't fork: $!"); 7047 if ($pid) { 7048 eval { 7049 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7050 7051 my $name = $user . '10'; 7052 $client->login($name, $passwd); 7053 $client->quit(); 7054 }; 7055 7056 if ($@) { 7057 $ex = $@; 7058 } 7059 7060 $wfh->print("done\n"); 7061 $wfh->flush(); 7062 7063 } else { 7064 eval { server_wait($config_file, $rfh) }; 7065 if ($@) { 7066 warn($@); 7067 exit 1; 7068 } 7069 7070 exit 0; 7071 } 7072 7073 # Stop server 7074 server_stop($pid_file); 7075 7076 $self->assert_child_ok($pid); 7077 7078 if ($ex) { 7079 test_append_logfile($log_file, $ex); 7080 unlink($log_file); 7081 7082 die($ex); 7083 } 7084 7085 unlink($log_file); 7086} 7087 7088sub get_cmds { 7089 my $db_file = shift; 7090 my $where = shift; 7091 7092 my $sql = "SELECT user, ip_addr, command, request FROM ftpsessions"; 7093 if ($where) { 7094 $sql .= " WHERE $where"; 7095 } 7096 7097 my $cmd = "sqlite3 $db_file \"$sql\""; 7098 7099 if ($ENV{TEST_VERBOSE}) { 7100 print STDERR "Executing sqlite3: $cmd\n"; 7101 } 7102 7103 my $rows = [`$cmd`]; 7104 7105 if ($ENV{TEST_VERBOSE}) { 7106 use Data::Dumper; 7107 print STDERR "Results: ", Dumper($rows), "\n"; 7108 } 7109 7110 my $res; 7111 7112 # Return the last row found, for now 7113 foreach my $row (@$rows) { 7114 chomp($row); 7115 7116 # The default sqlite3 delimiter is '|' 7117 $res = [split(/\|/, $row)]; 7118 } 7119 7120 return unless $res; 7121 return @$res; 7122} 7123 7124sub sql_resolve_tag_bug3536 { 7125 my $self = shift; 7126 my $tmpdir = $self->{tmpdir}; 7127 7128 my $config_file = "$tmpdir/sqlite.conf"; 7129 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 7130 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 7131 7132 my $log_file = test_get_logfile(); 7133 7134 my $user = 'proftpd'; 7135 my $passwd = 'test'; 7136 my $group = 'ftpd'; 7137 my $home_dir = File::Spec->rel2abs($tmpdir); 7138 my $uid = 500; 7139 my $gid = 500; 7140 7141 # Make sure that, if we're running as root, that the home directory has 7142 # permissions/privs set for the account we create 7143 if ($< == 0) { 7144 unless (chmod(0755, $home_dir)) { 7145 die("Can't set perms on $home_dir to 0755: $!"); 7146 } 7147 7148 unless (chown($uid, $gid, $home_dir)) { 7149 die("Can't set owner of $home_dir to $uid/$gid: $!"); 7150 } 7151 } 7152 7153 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 7154 7155 # Build up sqlite3 command to create users, groups tables and populate them 7156 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 7157 7158 if (open(my $fh, "> $db_script")) { 7159 print $fh <<EOS; 7160CREATE TABLE users ( 7161 userid TEXT, 7162 passwd TEXT, 7163 uid INTEGER, 7164 gid INTEGER, 7165 homedir TEXT, 7166 shell TEXT 7167); 7168INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 7169 7170CREATE TABLE groups ( 7171 groupname TEXT, 7172 gid INTEGER, 7173 members TEXT 7174); 7175INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 7176 7177CREATE TABLE ftpsessions ( 7178 user TEXT, 7179 ip_addr TEXT, 7180 command TEXT, 7181 request TEXT 7182); 7183EOS 7184 7185 unless (close($fh)) { 7186 die("Can't write $db_script: $!"); 7187 } 7188 7189 } else { 7190 die("Can't open $db_script: $!"); 7191 } 7192 7193 my $cmd = "sqlite3 $db_file < $db_script"; 7194 build_db($cmd, $db_script); 7195 7196 # Make sure that, if we're running as root, the database file has 7197 # the permissions/privs set for use by proftpd 7198 if ($< == 0) { 7199 unless (chmod(0666, $db_file)) { 7200 die("Can't set perms on $db_file to 0666: $!"); 7201 } 7202 } 7203 7204 my $config = { 7205 PidFile => $pid_file, 7206 ScoreboardFile => $scoreboard_file, 7207 SystemLog => $log_file, 7208 TraceLog => $log_file, 7209 Trace => 'sql:20', 7210 7211 IfModules => { 7212 'mod_delay.c' => { 7213 DelayEngine => 'off', 7214 }, 7215 7216 'mod_sql.c' => { 7217 SQLAuthTypes => 'plaintext', 7218 SQLBackend => 'sqlite3', 7219 SQLConnectInfo => $db_file, 7220 SQLLogFile => $log_file, 7221 SQLNamedQuery => 'command FREEFORM "INSERT INTO ftpsessions (user, ip_addr, command, request) VALUES (\'%u\', \'%L\', \'%m\', \'%r\')"', 7222 SQLLog => '* command', 7223 }, 7224 }, 7225 }; 7226 7227 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7228 7229 # Open pipes, for use between the parent and child processes. Specifically, 7230 # the child will indicate when it's done with its test by writing a message 7231 # to the parent. 7232 my ($rfh, $wfh); 7233 unless (pipe($rfh, $wfh)) { 7234 die("Can't open pipe: $!"); 7235 } 7236 7237 my $ex; 7238 7239 # Fork child 7240 $self->handle_sigchld(); 7241 defined(my $pid = fork()) or die("Can't fork: $!"); 7242 if ($pid) { 7243 eval { 7244 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7245 7246 # Ignore errors for these commands 7247 eval { 7248 my $name = "AAAAAAAAAA%m%m%mA%m%m%mA%m%mAA%m%m%m%m%mA%m%Z%m%mA%m%mAA%mA%ZAA%m%m%m%m%m%mA%m%ZAAA%m%m%m%m%m%m%m%m%m%m%m%m%m%m%mAa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0A%%%m%r%m%Z"; 7249 $client->user($name); 7250 }; 7251 }; 7252 7253 if ($@) { 7254 $ex = $@; 7255 } 7256 7257 $wfh->print("done\n"); 7258 $wfh->flush(); 7259 7260 } else { 7261 eval { server_wait($config_file, $rfh) }; 7262 if ($@) { 7263 warn($@); 7264 exit 1; 7265 } 7266 7267 exit 0; 7268 } 7269 7270 # Stop server 7271 server_stop($pid_file); 7272 7273 $self->assert_child_ok($pid); 7274 7275 if ($ex) { 7276 test_append_logfile($log_file, $ex); 7277 unlink($log_file); 7278 7279 die($ex); 7280 } 7281 7282 my ($login, $ip_addr, $req); 7283 ($login, $ip_addr, $cmd, $req) = get_cmds($db_file, "user = \'$config_user\'"); 7284 7285 $self->assert(!defined($login), test_msg("Expected undef, got '$login'")); 7286 $self->assert(!defined($ip_addr), test_msg("Expected undef, got '$ip_addr'")); 7287 7288 unlink($log_file); 7289} 7290 7291sub get_session_io { 7292 my $db_file = shift; 7293 my $where = shift; 7294 7295 my $sql = "SELECT user, ip_addr, bytes_in, bytes_out FROM ftpsessions"; 7296 if ($where) { 7297 $sql .= " WHERE $where"; 7298 } 7299 7300 my $cmd = "sqlite3 $db_file \"$sql\""; 7301 7302 if ($ENV{TEST_VERBOSE}) { 7303 print STDERR "Executing sqlite3: $cmd\n"; 7304 } 7305 7306 my $res = join('', `$cmd`); 7307 chomp($res); 7308 7309 # The default sqlite3 delimiter is '|' 7310 return split(/\|/, $res); 7311} 7312 7313sub sql_sqllog_vars_I_O_bug3554 { 7314 my $self = shift; 7315 my $tmpdir = $self->{tmpdir}; 7316 my $setup = test_setup($tmpdir, 'sqlite'); 7317 7318 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 7319 7320 # Build up sqlite3 command to create users, groups tables and populate them 7321 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 7322 7323 if (open(my $fh, "> $db_script")) { 7324 print $fh <<EOS; 7325CREATE TABLE ftpsessions ( 7326 user TEXT, 7327 ip_addr TEXT, 7328 bytes_in NUMBER, 7329 bytes_out NUMBER 7330); 7331EOS 7332 7333 unless (close($fh)) { 7334 die("Can't write $db_script: $!"); 7335 } 7336 7337 } else { 7338 die("Can't open $db_script: $!"); 7339 } 7340 7341 my $cmd = "sqlite3 $db_file < $db_script"; 7342 build_db($cmd, $db_script); 7343 7344 # Make sure that, if we're running as root, the database file has 7345 # the permissions/privs set for use by proftpd 7346 if ($< == 0) { 7347 unless (chmod(0666, $db_file)) { 7348 die("Can't set perms on $db_file to 0666: $!"); 7349 } 7350 } 7351 7352 my $config = { 7353 PidFile => $setup->{pid_file}, 7354 ScoreboardFile => $setup->{scoreboard_file}, 7355 SystemLog => $setup->{log_file}, 7356 TraceLog => $setup->{log_file}, 7357 Trace => 'DEFAULT:10 jot:20 sql:20', 7358 7359 AuthUserFile => $setup->{auth_user_file}, 7360 AuthGroupFile => $setup->{auth_group_file}, 7361 7362 IfModules => { 7363 'mod_delay.c' => { 7364 DelayEngine => 'off', 7365 }, 7366 7367 'mod_sql.c' => { 7368 SQLEngine => 'log', 7369 SQLBackend => 'sqlite3', 7370 SQLConnectInfo => $db_file, 7371 SQLLogFile => $setup->{log_file}, 7372 SQLNamedQuery => 'session_io FREEFORM "INSERT INTO ftpsessions (user, ip_addr, bytes_in, bytes_out) VALUES (\'%u\', \'%L\', %I, %O)"', 7373 SQLLog => 'EXIT session_io', 7374 }, 7375 }, 7376 }; 7377 7378 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 7379 $config); 7380 7381 # Open pipes, for use between the parent and child processes. Specifically, 7382 # the child will indicate when it's done with its test by writing a message 7383 # to the parent. 7384 my ($rfh, $wfh); 7385 unless (pipe($rfh, $wfh)) { 7386 die("Can't open pipe: $!"); 7387 } 7388 7389 my $ex; 7390 7391 # Fork child 7392 $self->handle_sigchld(); 7393 defined(my $pid = fork()) or die("Can't fork: $!"); 7394 if ($pid) { 7395 eval { 7396 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7397 $client->login($setup->{user}, $setup->{passwd}); 7398 $client->type('ascii'); 7399 7400 my $conn = $client->stor_raw('test.txt'); 7401 unless ($conn) { 7402 die("STOR test.txt failed: " . $client->response_code() . " " . 7403 $client->response_msg()); 7404 } 7405 7406 my $buf = "ABCD\n" x 8; 7407 $conn->write($buf, length($buf), 30); 7408 $conn->close(); 7409 7410 my $resp_code = $client->response_code(); 7411 my $resp_msg = $client->response_msg(); 7412 7413 $client->quit(); 7414 7415 my $expected = 226; 7416 $self->assert($expected == $resp_code, 7417 "Expected response code $expected, got $resp_code"); 7418 7419 $expected = 'Transfer complete'; 7420 $self->assert($expected eq $resp_msg, 7421 "Expected response message '$expected', got '$resp_msg'"); 7422 }; 7423 if ($@) { 7424 $ex = $@; 7425 } 7426 7427 $wfh->print("done\n"); 7428 $wfh->flush(); 7429 7430 } else { 7431 eval { server_wait($setup->{config_file}, $rfh) }; 7432 if ($@) { 7433 warn($@); 7434 exit 1; 7435 } 7436 7437 exit 0; 7438 } 7439 7440 # Stop server 7441 server_stop($setup->{pid_file}); 7442 $self->assert_child_ok($pid); 7443 7444 if ($ex) { 7445 test_cleanup($setup->{log_file}, $ex); 7446 } 7447 7448 eval { 7449 my ($login, $ip_addr, $bytes_in, $bytes_out) = get_session_io($db_file, 7450 "user = \'$setup->{user}\'"); 7451 7452 my $expected = $setup->{user}; 7453 $self->assert($expected eq $login, "Expected '$expected', got '$login'"); 7454 7455 $expected = '127.0.0.1'; 7456 $self->assert($expected eq $ip_addr, 7457 "Expected '$expected', got '$ip_addr'"); 7458 7459 $expected = 108; 7460 $self->assert($expected == $bytes_in, 7461 "Expected $expected, got $bytes_in"); 7462 7463 # Why would this number vary so widely? It's because of the notation 7464 # used to express the port number in a PASV response. That port 7465 # number is ephemeral, chosen by the kernel. 7466 7467 my $expected_min = 232; 7468 my $expected_max = 236; 7469 $self->assert($expected_min <= $bytes_out || 7470 $expected_max >= $bytes_out, 7471 "Expected $expected_min - $expected_max, got $bytes_out"); 7472 }; 7473 if ($@) { 7474 $ex = $@; 7475 } 7476 7477 test_cleanup($setup->{log_file}, $ex); 7478} 7479 7480sub get_session_id { 7481 my $db_file = shift; 7482 my $where = shift; 7483 7484 my $sql = "SELECT user, ip_addr, session_id FROM ftpsessions"; 7485 if ($where) { 7486 $sql .= " WHERE $where"; 7487 } 7488 7489 my $cmd = "sqlite3 $db_file \"$sql\""; 7490 7491 if ($ENV{TEST_VERBOSE}) { 7492 print STDERR "Executing sqlite3: $cmd\n"; 7493 } 7494 7495 my $res = join('', `$cmd`); 7496 chomp($res); 7497 7498 # The default sqlite3 delimiter is '|' 7499 return split(/\|/, $res); 7500} 7501 7502sub sql_sqllog_note_var_unique_id_bug3572 { 7503 my $self = shift; 7504 my $tmpdir = $self->{tmpdir}; 7505 7506 my $config_file = "$tmpdir/sqlite.conf"; 7507 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 7508 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 7509 7510 my $log_file = test_get_logfile(); 7511 7512 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 7513 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 7514 7515 my $user = 'proftpd'; 7516 my $passwd = 'test'; 7517 my $group = 'ftpd'; 7518 my $home_dir = File::Spec->rel2abs($tmpdir); 7519 my $uid = 500; 7520 my $gid = 500; 7521 7522 # Make sure that, if we're running as root, that the home directory has 7523 # permissions/privs set for the account we create 7524 if ($< == 0) { 7525 unless (chmod(0755, $home_dir)) { 7526 die("Can't set perms on $home_dir to 0755: $!"); 7527 } 7528 7529 unless (chown($uid, $gid, $home_dir)) { 7530 die("Can't set owner of $home_dir to $uid/$gid: $!"); 7531 } 7532 } 7533 7534 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 7535 '/bin/bash'); 7536 auth_group_write($auth_group_file, $group, $gid, $user); 7537 7538 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 7539 7540 # Build up sqlite3 command to create users, groups tables and populate them 7541 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 7542 7543 if (open(my $fh, "> $db_script")) { 7544 print $fh <<EOS; 7545CREATE TABLE ftpsessions ( 7546 user TEXT, 7547 ip_addr TEXT, 7548 session_id TEXT 7549); 7550EOS 7551 7552 unless (close($fh)) { 7553 die("Can't write $db_script: $!"); 7554 } 7555 7556 } else { 7557 die("Can't open $db_script: $!"); 7558 } 7559 7560 my $cmd = "sqlite3 $db_file < $db_script"; 7561 build_db($cmd, $db_script); 7562 7563 # Make sure that, if we're running as root, the database file has 7564 # the permissions/privs set for use by proftpd 7565 if ($< == 0) { 7566 unless (chmod(0666, $db_file)) { 7567 die("Can't set perms on $db_file to 0666: $!"); 7568 } 7569 } 7570 7571 my $config = { 7572 PidFile => $pid_file, 7573 ScoreboardFile => $scoreboard_file, 7574 SystemLog => $log_file, 7575 TraceLog => $log_file, 7576 Trace => 'DEFAULT:10', 7577 7578 AuthUserFile => $auth_user_file, 7579 AuthGroupFile => $auth_group_file, 7580 7581 IfModules => { 7582 'mod_delay.c' => { 7583 DelayEngine => 'off', 7584 }, 7585 7586 'mod_sql.c' => { 7587 SQLEngine => 'log', 7588 SQLBackend => 'sqlite3', 7589 SQLConnectInfo => $db_file, 7590 SQLLogFile => $log_file, 7591 SQLNamedQuery => 'session_id FREEFORM "INSERT INTO ftpsessions (user, ip_addr, session_id) VALUES (\'%u\', \'%L\', \'%{note:UNIQUE_ID}\')"', 7592 SQLLog => 'PASS session_id', 7593 }, 7594 }, 7595 }; 7596 7597 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7598 7599 # Open pipes, for use between the parent and child processes. Specifically, 7600 # the child will indicate when it's done with its test by writing a message 7601 # to the parent. 7602 my ($rfh, $wfh); 7603 unless (pipe($rfh, $wfh)) { 7604 die("Can't open pipe: $!"); 7605 } 7606 7607 my $ex; 7608 7609 # Fork child 7610 $self->handle_sigchld(); 7611 defined(my $pid = fork()) or die("Can't fork: $!"); 7612 if ($pid) { 7613 eval { 7614 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7615 $client->login($user, $passwd); 7616 $client->quit(); 7617 }; 7618 7619 if ($@) { 7620 $ex = $@; 7621 } 7622 7623 $wfh->print("done\n"); 7624 $wfh->flush(); 7625 7626 } else { 7627 eval { server_wait($config_file, $rfh) }; 7628 if ($@) { 7629 warn($@); 7630 exit 1; 7631 } 7632 7633 exit 0; 7634 } 7635 7636 # Stop server 7637 server_stop($pid_file); 7638 7639 $self->assert_child_ok($pid); 7640 7641 if ($ex) { 7642 test_append_logfile($log_file, $ex); 7643 unlink($log_file); 7644 7645 die($ex); 7646 } 7647 7648 my ($login, $ip_addr, $session_id) = get_session_id($db_file, 7649 "user = \'$user\'"); 7650 7651 my $expected; 7652 7653 $expected = $user; 7654 $self->assert($expected eq $login, 7655 test_msg("Expected '$expected', got '$login'")); 7656 7657 $expected = '127.0.0.1'; 7658 $self->assert($expected eq $ip_addr, 7659 test_msg("Expected '$expected', got '$ip_addr'")); 7660 7661 $self->assert($session_id ne '', 7662 test_msg("Expected session ID ($session_id), got ''")); 7663 7664 unlink($log_file); 7665} 7666 7667sub sql_sqllog_note_var_rewrite_bug3572 { 7668 my $self = shift; 7669 my $tmpdir = $self->{tmpdir}; 7670 7671 my $config_file = "$tmpdir/sqlite.conf"; 7672 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 7673 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 7674 7675 my $log_file = test_get_logfile(); 7676 7677 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 7678 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 7679 7680 my $user = 'proftpd'; 7681 my $passwd = 'test'; 7682 my $group = 'ftpd'; 7683 my $home_dir = File::Spec->rel2abs($tmpdir); 7684 my $uid = 500; 7685 my $gid = 500; 7686 7687 my $domain = 'proftpd.org'; 7688 7689 # Make sure that, if we're running as root, that the home directory has 7690 # permissions/privs set for the account we create 7691 if ($< == 0) { 7692 unless (chmod(0755, $home_dir)) { 7693 die("Can't set perms on $home_dir to 0755: $!"); 7694 } 7695 7696 unless (chown($uid, $gid, $home_dir)) { 7697 die("Can't set owner of $home_dir to $uid/$gid: $!"); 7698 } 7699 } 7700 7701 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 7702 '/bin/bash'); 7703 auth_group_write($auth_group_file, $group, $gid, $user); 7704 7705 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 7706 7707 # Build up sqlite3 command to create users, groups tables and populate them 7708 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 7709 7710 if (open(my $fh, "> $db_script")) { 7711 print $fh <<EOS; 7712CREATE TABLE ftpsessions ( 7713 user TEXT, 7714 ip_addr TEXT, 7715 session_id TEXT 7716); 7717EOS 7718 7719 unless (close($fh)) { 7720 die("Can't write $db_script: $!"); 7721 } 7722 7723 } else { 7724 die("Can't open $db_script: $!"); 7725 } 7726 7727 my $cmd = "sqlite3 $db_file < $db_script"; 7728 build_db($cmd, $db_script); 7729 7730 # Make sure that, if we're running as root, the database file has 7731 # the permissions/privs set for use by proftpd 7732 if ($< == 0) { 7733 unless (chmod(0666, $db_file)) { 7734 die("Can't set perms on $db_file to 0666: $!"); 7735 } 7736 } 7737 7738 my $config = { 7739 PidFile => $pid_file, 7740 ScoreboardFile => $scoreboard_file, 7741 SystemLog => $log_file, 7742 TraceLog => $log_file, 7743 Trace => 'rewrite:10 sql:20 table:20', 7744 7745 AuthUserFile => $auth_user_file, 7746 AuthGroupFile => $auth_group_file, 7747 7748 IfModules => { 7749 'mod_delay.c' => { 7750 DelayEngine => 'off', 7751 }, 7752 7753 'mod_rewrite.c' => [ 7754 'RewriteEngine on', 7755 "RewriteLog $log_file", 7756 7757 'RewriteCondition %m USER', 7758 'RewriteRule ^(.*#)?([-_.0-9A-Za-z]+)(@)?(.*)? $2', 7759 ], 7760 7761 'mod_sql.c' => { 7762 SQLEngine => 'log', 7763 SQLBackend => 'sqlite3', 7764 SQLConnectInfo => $db_file, 7765 SQLLogFile => $log_file, 7766 SQLNamedQuery => 'session_id FREEFORM "INSERT INTO ftpsessions (user, ip_addr, session_id) VALUES (\'%U\', \'%L\', \'%{note:mod_rewrite.$4}\')"', 7767 SQLLog => 'USER session_id', 7768 }, 7769 }, 7770 }; 7771 7772 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7773 7774 # Open pipes, for use between the parent and child processes. Specifically, 7775 # the child will indicate when it's done with its test by writing a message 7776 # to the parent. 7777 my ($rfh, $wfh); 7778 unless (pipe($rfh, $wfh)) { 7779 die("Can't open pipe: $!"); 7780 } 7781 7782 my $ex; 7783 7784 # Fork child 7785 $self->handle_sigchld(); 7786 defined(my $pid = fork()) or die("Can't fork: $!"); 7787 if ($pid) { 7788 eval { 7789 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7790 7791 my $login = $user . '@' . $domain; 7792 $client->login($login, $passwd); 7793 $client->quit(); 7794 }; 7795 7796 if ($@) { 7797 $ex = $@; 7798 } 7799 7800 $wfh->print("done\n"); 7801 $wfh->flush(); 7802 7803 } else { 7804 eval { server_wait($config_file, $rfh) }; 7805 if ($@) { 7806 warn($@); 7807 exit 1; 7808 } 7809 7810 exit 0; 7811 } 7812 7813 # Stop server 7814 server_stop($pid_file); 7815 7816 $self->assert_child_ok($pid); 7817 7818 if ($ex) { 7819 test_append_logfile($log_file, $ex); 7820 unlink($log_file); 7821 7822 die($ex); 7823 } 7824 7825 my ($login, $ip_addr, $session_id) = get_session_id($db_file, 7826 "user = \'$user\'"); 7827 7828 my $expected; 7829 7830 $expected = $user; 7831 $self->assert($expected eq $login, 7832 test_msg("Expected '$expected', got '$login'")); 7833 7834 $expected = '127.0.0.1'; 7835 $self->assert($expected eq $ip_addr, 7836 test_msg("Expected '$expected', got '$ip_addr'")); 7837 7838 $expected = $domain; 7839 $self->assert($expected eq $session_id, 7840 test_msg("Expected '$expected', got '$session_id'")); 7841 7842 unlink($log_file); 7843} 7844 7845sub get_sql_notes { 7846 my $db_file = shift; 7847 my $where = shift; 7848 7849 my $sql = "SELECT user, primary_group, home, shell FROM ftpnotes"; 7850 if ($where) { 7851 $sql .= " WHERE $where"; 7852 } 7853 7854 my $cmd = "sqlite3 $db_file \"$sql\""; 7855 7856 if ($ENV{TEST_VERBOSE}) { 7857 print STDERR "Executing sqlite3: $cmd\n"; 7858 } 7859 7860 my $res = join('', `$cmd`); 7861 chomp($res); 7862 7863 # The default sqlite3 delimiter is '|' 7864 return split(/\|/, $res); 7865} 7866 7867sub sql_sqllog_note_sql_user_info { 7868 my $self = shift; 7869 my $tmpdir = $self->{tmpdir}; 7870 7871 my $config_file = "$tmpdir/sqlite.conf"; 7872 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 7873 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 7874 7875 my $log_file = test_get_logfile(); 7876 7877 my $user = 'proftpd'; 7878 my $group = 'ftpd', 7879 my $passwd = 'test'; 7880 my $home_dir = File::Spec->rel2abs($tmpdir); 7881 my $uid = 500; 7882 my $gid = 500; 7883 my $shell = '/bin/bash'; 7884 7885 # Make sure that, if we're running as root, that the home directory has 7886 # permissions/privs set for the account we create 7887 if ($< == 0) { 7888 unless (chmod(0755, $home_dir)) { 7889 die("Can't set perms on $home_dir to 0755: $!"); 7890 } 7891 7892 unless (chown($uid, $gid, $home_dir)) { 7893 die("Can't set owner of $home_dir to $uid/$gid: $!"); 7894 } 7895 } 7896 7897 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 7898 7899 # Build up sqlite3 command to create users, groups tables and populate them 7900 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 7901 7902 if (open(my $fh, "> $db_script")) { 7903 print $fh <<EOS; 7904CREATE TABLE users ( 7905 userid TEXT, 7906 passwd TEXT, 7907 uid INTEGER, 7908 gid INTEGER, 7909 homedir TEXT, 7910 shell TEXT, 7911 lastdir TEXT 7912); 7913INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '$shell'); 7914 7915CREATE TABLE groups ( 7916 groupname TEXT, 7917 gid INTEGER, 7918 members TEXT 7919); 7920INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 7921 7922CREATE TABLE ftpnotes ( 7923 user TEXT, 7924 primary_group TEXT, 7925 home TEXT, 7926 shell TEXT 7927); 7928EOS 7929 7930 unless (close($fh)) { 7931 die("Can't write $db_script: $!"); 7932 } 7933 7934 } else { 7935 die("Can't open $db_script: $!"); 7936 } 7937 7938 my $cmd = "sqlite3 $db_file < $db_script"; 7939 build_db($cmd, $db_script); 7940 7941 # Make sure that, if we're running as root, the database file has 7942 # the permissions/privs set for use by proftpd 7943 if ($< == 0) { 7944 unless (chmod(0666, $db_file)) { 7945 die("Can't set perms on $db_file to 0666: $!"); 7946 } 7947 } 7948 7949 my $config = { 7950 PidFile => $pid_file, 7951 ScoreboardFile => $scoreboard_file, 7952 SystemLog => $log_file, 7953 TraceLog => $log_file, 7954 Trace => 'DEFAULT:10 sql:20', 7955 7956 IfModules => { 7957 'mod_delay.c' => { 7958 DelayEngine => 'off', 7959 }, 7960 7961 'mod_sql.c' => { 7962 SQLAuthTypes => 'plaintext', 7963 SQLBackend => 'sqlite3', 7964 SQLConnectInfo => $db_file, 7965 SQLMinID => 100, 7966 SQLLogFile => $log_file, 7967 SQLNamedQuery => 'sql_notes FREEFORM "INSERT INTO ftpnotes (user, primary_group, home, shell) VALUES (\'%u\', \'%{note:primary-group}\', \'%{note:home}\', \'%{note:shell}\')"', 7968 SQLLog => 'PASS sql_notes', 7969 }, 7970 }, 7971 }; 7972 7973 my ($port, $config_user, $config_group) = config_write($config_file, $config); 7974 7975 # Open pipes, for use between the parent and child processes. Specifically, 7976 # the child will indicate when it's done with its test by writing a message 7977 # to the parent. 7978 my ($rfh, $wfh); 7979 unless (pipe($rfh, $wfh)) { 7980 die("Can't open pipe: $!"); 7981 } 7982 7983 my $ex; 7984 7985 # Fork child 7986 $self->handle_sigchld(); 7987 defined(my $pid = fork()) or die("Can't fork: $!"); 7988 if ($pid) { 7989 eval { 7990 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 7991 $client->login($user, $passwd); 7992 $client->quit(); 7993 }; 7994 7995 if ($@) { 7996 $ex = $@; 7997 } 7998 7999 $wfh->print("done\n"); 8000 $wfh->flush(); 8001 8002 } else { 8003 eval { server_wait($config_file, $rfh) }; 8004 if ($@) { 8005 warn($@); 8006 exit 1; 8007 } 8008 8009 exit 0; 8010 } 8011 8012 # Stop server 8013 server_stop($pid_file); 8014 8015 $self->assert_child_ok($pid); 8016 8017 if ($ex) { 8018 test_append_logfile($log_file, $ex); 8019 unlink($log_file); 8020 8021 die($ex); 8022 } 8023 8024 my ($login, $sql_group, $sql_home, $sql_shell) = get_sql_notes($db_file, 8025 "user = \'$user\'"); 8026 8027 my $expected; 8028 8029 $expected = $user; 8030 $self->assert($expected eq $login, 8031 test_msg("Expected '$expected', got '$login'")); 8032 8033 $expected = $group; 8034 $self->assert($expected eq $sql_group, 8035 test_msg("Expected '$expected', got '$sql_group'")); 8036 8037 $expected = $home_dir; 8038 $self->assert($expected eq $sql_home, 8039 test_msg("Expected '$expected', got '$sql_home'")); 8040 8041 $expected = $shell; 8042 $self->assert($expected eq $sql_shell, 8043 test_msg("Expected '$expected', got '$sql_shell'")); 8044 8045 unlink($log_file); 8046} 8047 8048sub sql_sqllog_var_E { 8049 my $self = shift; 8050 my $tmpdir = $self->{tmpdir}; 8051 my $setup = test_setup($tmpdir, 'sqlite'); 8052 8053 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 8054 8055 # Build up sqlite3 command to create users, groups tables and populate them 8056 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 8057 8058 if (open(my $fh, "> $db_script")) { 8059 print $fh <<EOS; 8060CREATE TABLE ftpsessions ( 8061 user TEXT, 8062 ip_addr TEXT, 8063 resp_mesg TEXT 8064); 8065EOS 8066 8067 unless (close($fh)) { 8068 die("Can't write $db_script: $!"); 8069 } 8070 8071 } else { 8072 die("Can't open $db_script: $!"); 8073 } 8074 8075 my $cmd = "sqlite3 $db_file < $db_script"; 8076 build_db($cmd, $db_script); 8077 8078 # Make sure that, if we're running as root, the database file has 8079 # the permissions/privs set for use by proftpd 8080 if ($< == 0) { 8081 unless (chmod(0666, $db_file)) { 8082 die("Can't set perms on $db_file to 0666: $!"); 8083 } 8084 } 8085 8086 my $config = { 8087 PidFile => $setup->{pid_file}, 8088 ScoreboardFile => $setup->{scoreboard_file}, 8089 SystemLog => $setup->{log_file}, 8090 TraceLog => $setup->{log_file}, 8091 Trace => 'jot:20 sql:20', 8092 8093 AuthUserFile => $setup->{auth_user_file}, 8094 AuthGroupFile => $setup->{auth_group_file}, 8095 8096 IfModules => { 8097 'mod_delay.c' => { 8098 DelayEngine => 'off', 8099 }, 8100 8101 'mod_sql.c' => { 8102 SQLEngine => 'log', 8103 SQLBackend => 'sqlite3', 8104 SQLConnectInfo => $db_file, 8105 SQLLogFile => $setup->{log_file}, 8106 SQLNamedQuery => 'info FREEFORM "INSERT INTO ftpsessions (user, ip_addr, resp_mesg) VALUES (\'%u\', \'%L\', \'%E\')"', 8107 SQLLog => 'EXIT info', 8108 }, 8109 }, 8110 }; 8111 8112 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 8113 $config); 8114 8115 # Open pipes, for use between the parent and child processes. Specifically, 8116 # the child will indicate when it's done with its test by writing a message 8117 # to the parent. 8118 my ($rfh, $wfh); 8119 unless (pipe($rfh, $wfh)) { 8120 die("Can't open pipe: $!"); 8121 } 8122 8123 my $ex; 8124 8125 # Fork child 8126 $self->handle_sigchld(); 8127 defined(my $pid = fork()) or die("Can't fork: $!"); 8128 if ($pid) { 8129 eval { 8130 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 8131 $client->login($setup->{user}, $setup->{passwd}); 8132 $client->list(); 8133 $client->quit(); 8134 }; 8135 if ($@) { 8136 $ex = $@; 8137 } 8138 8139 $wfh->print("done\n"); 8140 $wfh->flush(); 8141 8142 } else { 8143 eval { server_wait($setup->{config_file}, $rfh) }; 8144 if ($@) { 8145 warn($@); 8146 exit 1; 8147 } 8148 8149 exit 0; 8150 } 8151 8152 # Stop server 8153 server_stop($setup->{pid_file}); 8154 $self->assert_child_ok($pid); 8155 8156 if ($ex) { 8157 test_cleanup($setup->{log_file}, $ex); 8158 } 8159 8160 eval { 8161 my ($login, $ip_addr, $resp_mesg) = get_resp_mesgs($db_file, 8162 "user = \'$setup->{user}\'", "user, ip_addr, resp_mesg"); 8163 8164 my $expected = $setup->{user}; 8165 $self->assert($expected eq $login, "Expected '$expected', got '$login'"); 8166 8167 $expected = '127.0.0.1'; 8168 $self->assert($expected eq $ip_addr, 8169 "Expected '$expected', got '$ip_addr'"); 8170 8171 $expected = 'Quit'; 8172 $self->assert($expected eq $resp_mesg, 8173 "Expected '$expected', got '$resp_mesg'"); 8174 }; 8175 if ($@) { 8176 $ex = $@; 8177 } 8178 8179 test_cleanup($setup->{log_file}, $ex); 8180} 8181 8182sub sql_named_conn_bug3262 { 8183 my $self = shift; 8184 my $tmpdir = $self->{tmpdir}; 8185 8186 my $config_file = "$tmpdir/sqlite.conf"; 8187 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 8188 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 8189 8190 my $log_file = test_get_logfile(); 8191 8192 my $user = 'proftpd'; 8193 my $passwd = 'test'; 8194 my $group = 'ftpd'; 8195 my $home_dir = File::Spec->rel2abs($tmpdir); 8196 my $uid = 500; 8197 my $gid = 500; 8198 8199 # Make sure that, if we're running as root, that the home directory has 8200 # permissions/privs set for the account we create 8201 if ($< == 0) { 8202 unless (chmod(0755, $home_dir)) { 8203 die("Can't set perms on $home_dir to 0755: $!"); 8204 } 8205 8206 unless (chown($uid, $gid, $home_dir)) { 8207 die("Can't set owner of $home_dir to $uid/$gid: $!"); 8208 } 8209 } 8210 8211 my $userdb_file = File::Spec->rel2abs("$tmpdir/proftpd-users.db"); 8212 8213 # Build up sqlite3 command to create users, groups tables and populate them 8214 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd-users.sql"); 8215 8216 if (open(my $fh, "> $db_script")) { 8217 print $fh <<EOS; 8218CREATE TABLE ftpusers ( 8219 userid TEXT, 8220 passwd TEXT, 8221 uid INTEGER, 8222 gid INTEGER, 8223 homedir TEXT, 8224 shell TEXT, 8225 lastdir TEXT 8226); 8227INSERT INTO ftpusers (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 8228 8229CREATE TABLE groups ( 8230 groupname TEXT, 8231 gid INTEGER, 8232 members TEXT 8233); 8234INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 8235 8236CREATE TABLE ftpsessions ( 8237 user TEXT, 8238 ip_addr TEXT, 8239 timestamp TEXT 8240); 8241 8242EOS 8243 8244 unless (close($fh)) { 8245 die("Can't write $db_script: $!"); 8246 } 8247 8248 } else { 8249 die("Can't open $db_script: $!"); 8250 } 8251 8252 my $cmd = "sqlite3 $userdb_file < $db_script"; 8253 build_db($cmd, $db_script); 8254 8255 my $logdb_file = File::Spec->rel2abs("$tmpdir/proftpd-log.db"); 8256 8257 # Build up sqlite3 command to create users, groups tables and populate them 8258 $db_script = File::Spec->rel2abs("$tmpdir/proftpd-log.sql"); 8259 8260 if (open(my $fh, "> $db_script")) { 8261 print $fh <<EOS; 8262CREATE TABLE ftpsessions ( 8263 user TEXT, 8264 ip_addr TEXT, 8265 timestamp TEXT 8266); 8267 8268EOS 8269 8270 unless (close($fh)) { 8271 die("Can't write $db_script: $!"); 8272 } 8273 8274 } else { 8275 die("Can't open $db_script: $!"); 8276 } 8277 8278 $cmd = "sqlite3 $logdb_file < $db_script"; 8279 build_db($cmd, $db_script); 8280 8281 # Make sure that, if we're running as root, the database file has 8282 # the permissions/privs set for use by proftpd 8283 if ($< == 0) { 8284 unless (chmod(0666, $userdb_file, $logdb_file)) { 8285 die("Can't set perms on $userdb_file, $logdb_file to 0666: $!"); 8286 } 8287 } 8288 8289 my $config = { 8290 PidFile => $pid_file, 8291 ScoreboardFile => $scoreboard_file, 8292 SystemLog => $log_file, 8293 8294 IfModules => { 8295 'mod_delay.c' => { 8296 DelayEngine => 'off', 8297 }, 8298 8299 'mod_sql.c' => [ 8300 'SQLAuthTypes plaintext', 8301 'SQLBackend sqlite3', 8302 "SQLConnectInfo $userdb_file", 8303 "SQLNamedConnectInfo logdb sqlite3 $logdb_file foo bar PERSESSION", 8304 "SQLLogFile $log_file", 8305 'SQLNamedQuery get-user-by-name SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers WHERE userid = \'%U\'"', 8306 'SQLNamedQuery get-user-by-id SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers WHERE uid = %{0}"', 8307 'SQLNamedQuery get-user-names SELECT "userid FROM ftpusers"', 8308 'SQLNamedQuery get-all-users SELECT "userid, passwd, uid, gid, homedir, shell FROM ftpusers"', 8309 'SQLUserInfo custom:/get-user-by-name/get-user-by-id/get-user-names/get-all-users', 8310 'SQLNamedQuery session_start FREEFORM "INSERT INTO ftpsessions (user, ip_addr, timestamp) VALUES (\'%u\', \'%L\', \'%{time:%Y-%m-%d %H:%M:%S}\')" logdb', 8311 'SQLLog PASS session_start', 8312 ], 8313 }, 8314 }; 8315 8316 my ($port, $config_user, $config_group) = config_write($config_file, $config); 8317 8318 # Open pipes, for use between the parent and child processes. Specifically, 8319 # the child will indicate when it's done with its test by writing a message 8320 # to the parent. 8321 my ($rfh, $wfh); 8322 unless (pipe($rfh, $wfh)) { 8323 die("Can't open pipe: $!"); 8324 } 8325 8326 my $ex; 8327 8328 # Fork child 8329 $self->handle_sigchld(); 8330 defined(my $pid = fork()) or die("Can't fork: $!"); 8331 if ($pid) { 8332 eval { 8333 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 8334 8335 $client->login($user, $passwd); 8336 8337 my $resp_msgs = $client->response_msgs(); 8338 my $nmsgs = scalar(@$resp_msgs); 8339 8340 my $expected; 8341 8342 $expected = 1; 8343 $self->assert($expected == $nmsgs, 8344 test_msg("Expected $expected, got $nmsgs")); 8345 8346 $expected = "User proftpd logged in"; 8347 $self->assert($expected eq $resp_msgs->[0], 8348 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 8349 8350 }; 8351 8352 if ($@) { 8353 $ex = $@; 8354 } 8355 8356 $wfh->print("done\n"); 8357 $wfh->flush(); 8358 8359 } else { 8360 eval { server_wait($config_file, $rfh) }; 8361 if ($@) { 8362 warn($@); 8363 exit 1; 8364 } 8365 8366 exit 0; 8367 } 8368 8369 # Stop server 8370 server_stop($pid_file); 8371 8372 $self->assert_child_ok($pid); 8373 8374 if ($ex) { 8375 test_append_logfile($log_file, $ex); 8376 unlink($log_file); 8377 8378 die($ex); 8379 } 8380 8381 my ($login, $ip_addr, $timestamp) = get_sessions($userdb_file, 8382 "user = \'$user\'"); 8383 8384 $self->assert(!defined($login), 8385 test_msg("Expected undef, got '$login'")); 8386 8387 $self->assert(!defined($ip_addr), 8388 test_msg("Expected undef, got '$ip_addr'")); 8389 8390 $self->assert(!defined($timestamp), 8391 test_msg("Expected undef, got '$timestamp'")); 8392 8393 ($login, $ip_addr, $timestamp) = get_sessions($logdb_file, 8394 "user = \'$user\'"); 8395 8396 my $expected; 8397 8398 $expected = $user; 8399 $self->assert($expected eq $login, 8400 test_msg("Expected '$expected', got '$login'")); 8401 8402 $expected = '127.0.0.1'; 8403 $self->assert($expected eq $ip_addr, 8404 test_msg("Expected '$expected', got '$ip_addr'")); 8405 8406 $expected = '\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}'; 8407 $self->assert(qr/$expected/, $timestamp, 8408 test_msg("Expected '$expected', got '$timestamp'")); 8409 8410 unlink($log_file); 8411} 8412 8413sub sql_named_conn_sqllog_exit_bug3645 { 8414 my $self = shift; 8415 my $tmpdir = $self->{tmpdir}; 8416 8417 my $config_file = "$tmpdir/sqlite.conf"; 8418 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 8419 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 8420 8421 my $log_file = test_get_logfile(); 8422 8423 my $user = 'proftpd'; 8424 my $passwd = 'test'; 8425 my $group = 'ftpd'; 8426 my $home_dir = File::Spec->rel2abs($tmpdir); 8427 my $uid = 500; 8428 my $gid = 500; 8429 8430 # Make sure that, if we're running as root, that the home directory has 8431 # permissions/privs set for the account we create 8432 if ($< == 0) { 8433 unless (chmod(0755, $home_dir)) { 8434 die("Can't set perms on $home_dir to 0755: $!"); 8435 } 8436 8437 unless (chown($uid, $gid, $home_dir)) { 8438 die("Can't set owner of $home_dir to $uid/$gid: $!"); 8439 } 8440 } 8441 8442 my $userdb_file = File::Spec->rel2abs("$tmpdir/proftpd-users.db"); 8443 8444 # Build up sqlite3 command to create users, groups tables and populate them 8445 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd-users.sql"); 8446 8447 if (open(my $fh, "> $db_script")) { 8448 print $fh <<EOS; 8449CREATE TABLE users ( 8450 userid TEXT, 8451 passwd TEXT, 8452 uid INTEGER, 8453 gid INTEGER, 8454 homedir TEXT, 8455 shell TEXT 8456); 8457INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 8458 8459CREATE TABLE groups ( 8460 groupname TEXT, 8461 gid INTEGER, 8462 members TEXT 8463); 8464INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 8465EOS 8466 8467 unless (close($fh)) { 8468 die("Can't write $db_script: $!"); 8469 } 8470 8471 } else { 8472 die("Can't open $db_script: $!"); 8473 } 8474 8475 my $cmd = "sqlite3 $userdb_file < $db_script"; 8476 build_db($cmd, $db_script); 8477 8478 my $logdb_file = File::Spec->rel2abs("$tmpdir/proftpd-log.db"); 8479 8480 # Build up sqlite3 command to create users, groups tables and populate them 8481 $db_script = File::Spec->rel2abs("$tmpdir/proftpd-log.sql"); 8482 8483 if (open(my $fh, "> $db_script")) { 8484 print $fh <<EOS; 8485CREATE TABLE ftpsessions ( 8486 user TEXT, 8487 ip_addr TEXT, 8488 timestamp TEXT 8489); 8490 8491EOS 8492 8493 unless (close($fh)) { 8494 die("Can't write $db_script: $!"); 8495 } 8496 8497 } else { 8498 die("Can't open $db_script: $!"); 8499 } 8500 8501 $cmd = "sqlite3 $logdb_file < $db_script"; 8502 build_db($cmd, $db_script); 8503 8504 # Make sure that, if we're running as root, the database file has 8505 # the permissions/privs set for use by proftpd 8506 if ($< == 0) { 8507 unless (chmod(0666, $userdb_file, $logdb_file)) { 8508 die("Can't set perms on $userdb_file, $logdb_file to 0666: $!"); 8509 } 8510 } 8511 8512 my $config = { 8513 PidFile => $pid_file, 8514 ScoreboardFile => $scoreboard_file, 8515 SystemLog => $log_file, 8516 8517 DefaultRoot => '~', 8518 8519 IfModules => { 8520 'mod_delay.c' => { 8521 DelayEngine => 'off', 8522 }, 8523 8524 'mod_sql.c' => [ 8525 'SQLAuthTypes plaintext', 8526 'SQLBackend sqlite3', 8527 "SQLConnectInfo $userdb_file", 8528 "SQLNamedConnectInfo logdb sqlite3 $logdb_file", 8529 "SQLLogFile $log_file", 8530 'SQLNamedQuery session_end FREEFORM "INSERT INTO ftpsessions (user, ip_addr, timestamp) VALUES (\'%u\', \'%L\', \'%{time:%Y-%m-%d %H:%M:%S}\')" logdb', 8531 'SQLLog EXIT session_end', 8532 ], 8533 }, 8534 }; 8535 8536 my ($port, $config_user, $config_group) = config_write($config_file, $config); 8537 8538 # Open pipes, for use between the parent and child processes. Specifically, 8539 # the child will indicate when it's done with its test by writing a message 8540 # to the parent. 8541 my ($rfh, $wfh); 8542 unless (pipe($rfh, $wfh)) { 8543 die("Can't open pipe: $!"); 8544 } 8545 8546 my $ex; 8547 8548 # Fork child 8549 $self->handle_sigchld(); 8550 defined(my $pid = fork()) or die("Can't fork: $!"); 8551 if ($pid) { 8552 eval { 8553 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 8554 8555 $client->login($user, $passwd); 8556 8557 my $resp_msgs = $client->response_msgs(); 8558 my $nmsgs = scalar(@$resp_msgs); 8559 8560 my $expected; 8561 8562 $expected = 1; 8563 $self->assert($expected == $nmsgs, 8564 test_msg("Expected $expected, got $nmsgs")); 8565 8566 $expected = "User proftpd logged in"; 8567 $self->assert($expected eq $resp_msgs->[0], 8568 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 8569 8570 }; 8571 8572 if ($@) { 8573 $ex = $@; 8574 } 8575 8576 $wfh->print("done\n"); 8577 $wfh->flush(); 8578 8579 } else { 8580 eval { server_wait($config_file, $rfh) }; 8581 if ($@) { 8582 warn($@); 8583 exit 1; 8584 } 8585 8586 exit 0; 8587 } 8588 8589 # Stop server 8590 server_stop($pid_file); 8591 8592 $self->assert_child_ok($pid); 8593 8594 if ($ex) { 8595 test_append_logfile($log_file, $ex); 8596 unlink($log_file); 8597 8598 die($ex); 8599 } 8600 8601 my ($login, $ip_addr, $timestamp) = get_sessions($userdb_file, 8602 "user = \'$user\'"); 8603 8604 $self->assert(!defined($login), 8605 test_msg("Expected undef, got '$login'")); 8606 8607 $self->assert(!defined($ip_addr), 8608 test_msg("Expected undef, got '$ip_addr'")); 8609 8610 $self->assert(!defined($timestamp), 8611 test_msg("Expected undef, got '$timestamp'")); 8612 8613 ($login, $ip_addr, $timestamp) = get_sessions($logdb_file, 8614 "user = \'$user\'"); 8615 8616 my $expected; 8617 8618 $expected = $user; 8619 $self->assert($expected eq $login, 8620 test_msg("Expected '$expected', got '$login'")); 8621 8622 $expected = '127.0.0.1'; 8623 $self->assert($expected eq $ip_addr, 8624 test_msg("Expected '$expected', got '$ip_addr'")); 8625 8626 $expected = '\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}'; 8627 $self->assert(qr/$expected/, $timestamp, 8628 test_msg("Expected '$expected', got '$timestamp'")); 8629 8630 unlink($log_file); 8631} 8632 8633sub sql_sqllog_vars_H_L_matching_server_bug3620 { 8634 my $self = shift; 8635 my $tmpdir = $self->{tmpdir}; 8636 my $setup = test_setup($tmpdir, 'sqlite'); 8637 8638 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 8639 8640 # Build up sqlite3 command to create users, groups tables and populate them 8641 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 8642 8643 if (open(my $fh, "> $db_script")) { 8644 print $fh <<EOS; 8645CREATE TABLE ftpsessions ( 8646 user TEXT, 8647 ip_addr TEXT, 8648 rename_from TEXT 8649); 8650EOS 8651 8652 unless (close($fh)) { 8653 die("Can't write $db_script: $!"); 8654 } 8655 8656 } else { 8657 die("Can't open $db_script: $!"); 8658 } 8659 8660 my $cmd = "sqlite3 $db_file < $db_script"; 8661 build_db($cmd, $db_script); 8662 8663 # Make sure that, if we're running as root, the database file has 8664 # the permissions/privs set for use by proftpd 8665 if ($< == 0) { 8666 unless (chmod(0666, $db_file)) { 8667 die("Can't set perms on $db_file to 0666: $!"); 8668 } 8669 } 8670 8671 my $src_file = File::Spec->rel2abs("$tmpdir/test.txt"); 8672 if (open(my $fh, "> $src_file")) { 8673 close($fh); 8674 8675 } else { 8676 die("Can't open $src_file: $!"); 8677 } 8678 8679 my $dst_file = File::Spec->rel2abs("$tmpdir/foo.txt"); 8680 8681 my $config = { 8682 PidFile => $setup->{pid_file}, 8683 ScoreboardFile => $setup->{scoreboard_file}, 8684 SystemLog => $setup->{log_file}, 8685 TraceLog => $setup->{log_file}, 8686 Trace => 'jot:20 sql:20', 8687 8688 AuthUserFile => $setup->{auth_user_file}, 8689 AuthGroupFile => $setup->{auth_group_file}, 8690 DefaultServer => 'off', 8691 SocketBindTight => 'off', 8692 Port => '0', 8693 8694 IfModules => { 8695 'mod_delay.c' => { 8696 DelayEngine => 'off', 8697 }, 8698 }, 8699 }; 8700 8701 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 8702 $config); 8703 8704 my $sysaddr = Sys::HostAddr->new(); 8705 my $real_addr = $sysaddr->main_ip(); 8706 my $real_port = ProFTPD::TestSuite::Utils::get_high_numbered_port(); 8707 my $vhost_addr = '0.0.0.0'; 8708 8709 if (open(my $fh, ">> $setup->{config_file}")) { 8710 print $fh <<EOC; 8711<VirtualHost $vhost_addr> 8712 ServerName "DefaultServer VHost" 8713 Port $real_port 8714 DefaultServer on 8715 8716 AuthUserFile $setup->{auth_user_file} 8717 AuthGroupFile $setup->{auth_group_file} 8718 RequireValidShell off 8719 WtmpLog off 8720 8721 <IfModule mod_sql.c> 8722 SQLEngine log 8723 SQLBackend sqlite3 8724 SQLConnectInfo $db_file 8725 SQLLogFile $setup->{log_file} 8726 SQLNamedQuery session_start FREEFORM "INSERT INTO ftpsessions (user, ip_addr, rename_from) VALUES ('%u', '%L', '%H')" 8727 SQLLog PASS session_start 8728 </IfModule> 8729</VirtualHost> 8730EOC 8731 unless (close($fh)) { 8732 die("Can't write $setup->{config_file}: $!"); 8733 } 8734 8735 } else { 8736 die("Can't open $setup->{config_file}: $!"); 8737 } 8738 8739 # Open pipes, for use between the parent and child processes. Specifically, 8740 # the child will indicate when it's done with its test by writing a message 8741 # to the parent. 8742 my ($rfh, $wfh); 8743 unless (pipe($rfh, $wfh)) { 8744 die("Can't open pipe: $!"); 8745 } 8746 8747 my $ex; 8748 8749 # Fork child 8750 $self->handle_sigchld(); 8751 defined(my $pid = fork()) or die("Can't fork: $!"); 8752 if ($pid) { 8753 eval { 8754 my $client = ProFTPD::TestSuite::FTP->new($real_addr, $real_port); 8755 $client->login($setup->{user}, $setup->{passwd}); 8756 $client->quit(); 8757 }; 8758 if ($@) { 8759 $ex = $@; 8760 } 8761 8762 $wfh->print("done\n"); 8763 $wfh->flush(); 8764 8765 } else { 8766 eval { server_wait($setup->{config_file}, $rfh) }; 8767 if ($@) { 8768 warn($@); 8769 exit 1; 8770 } 8771 8772 exit 0; 8773 } 8774 8775 # Stop server 8776 server_stop($setup->{pid_file}); 8777 $self->assert_child_ok($pid); 8778 8779 if ($ex) { 8780 test_cleanup($setup->{log_file}, $ex); 8781 } 8782 8783 eval { 8784 my ($login, $ip_addr, $sess_vhost_addr) = get_renames($db_file, "user = \'$setup->{user}\'"); 8785 8786 my $expected = $setup->{user}; 8787 $self->assert($expected eq $login, 8788 test_msg("Expected '$expected', got '$login'")); 8789 8790 $expected = $real_addr; 8791 $self->assert($expected eq $ip_addr, 8792 test_msg("Expected '$expected', got '$ip_addr'")); 8793 8794 $expected = $vhost_addr; 8795 $self->assert($expected eq $sess_vhost_addr, 8796 test_msg("Expected '$expected', got '$sess_vhost_addr'")); 8797 }; 8798 if ($@) { 8799 $ex = $@; 8800 } 8801 8802 test_cleanup($setup->{log_file}, $ex); 8803} 8804 8805sub sql_sqllog_vars_H_L_default_server_bug3620 { 8806 my $self = shift; 8807 my $tmpdir = $self->{tmpdir}; 8808 my $setup = test_setup($tmpdir, 'sqlite'); 8809 8810 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 8811 8812 # Build up sqlite3 command to create users, groups tables and populate them 8813 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 8814 8815 if (open(my $fh, "> $db_script")) { 8816 print $fh <<EOS; 8817CREATE TABLE ftpsessions ( 8818 user TEXT, 8819 ip_addr TEXT, 8820 rename_from TEXT 8821); 8822EOS 8823 8824 unless (close($fh)) { 8825 die("Can't write $db_script: $!"); 8826 } 8827 8828 } else { 8829 die("Can't open $db_script: $!"); 8830 } 8831 8832 my $cmd = "sqlite3 $db_file < $db_script"; 8833 build_db($cmd, $db_script); 8834 8835 # Make sure that, if we're running as root, the database file has 8836 # the permissions/privs set for use by proftpd 8837 if ($< == 0) { 8838 unless (chmod(0666, $db_file)) { 8839 die("Can't set perms on $db_file to 0666: $!"); 8840 } 8841 } 8842 8843 my $src_file = File::Spec->rel2abs("$tmpdir/test.txt"); 8844 if (open(my $fh, "> $src_file")) { 8845 close($fh); 8846 8847 } else { 8848 die("Can't open $src_file: $!"); 8849 } 8850 8851 my $dst_file = File::Spec->rel2abs("$tmpdir/foo.txt"); 8852 8853 my $config = { 8854 PidFile => $setup->{pid_file}, 8855 ScoreboardFile => $setup->{scoreboard_file}, 8856 SystemLog => $setup->{log_file}, 8857 TraceLog => $setup->{log_file}, 8858 Trace => 'jot:20 sql:20', 8859 8860 AuthUserFile => $setup->{auth_user_file}, 8861 AuthGroupFile => $setup->{auth_group_file}, 8862 8863 DefaultServer => 'off', 8864 SocketBindTight => 'off', 8865 Port => '0', 8866 8867 IfModules => { 8868 'mod_delay.c' => { 8869 DelayEngine => 'off', 8870 }, 8871 8872 'mod_sql.c' => { 8873 SQLEngine => 'log', 8874 SQLBackend => 'sqlite3', 8875 SQLConnectInfo => $db_file, 8876 SQLLogFile => $setup->{log_file}, 8877 SQLNamedQuery => 'session_start FREEFORM "INSERT INTO ftpsessions (user, ip_addr, rename_from) VALUES (\'%u\', \'%L\', \'%H\')"', 8878 SQLLog => 'PASS session_start', 8879 }, 8880 }, 8881 }; 8882 8883 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 8884 $config); 8885 8886 my $sysaddr = Sys::HostAddr->new(); 8887 my $real_addr = $sysaddr->main_ip(); 8888 my $real_port = ProFTPD::TestSuite::Utils::get_high_numbered_port(); 8889 my $vhost_addr = '0.0.0.0'; 8890 8891 if (open(my $fh, ">> $setup->{config_file}")) { 8892 print $fh <<EOC; 8893 8894<VirtualHost $vhost_addr> 8895 ServerName "DefaultServer VHost" 8896 Port $real_port 8897 DefaultServer on 8898 8899 AuthUserFile $setup->{auth_user_file} 8900 AuthGroupFile $setup->{auth_group_file} 8901 RequireValidShell off 8902 WtmpLog off 8903 8904 <IfModule mod_sql.c> 8905 SQLEngine log 8906 SQLBackend sqlite3 8907 SQLConnectInfo $db_file 8908 SQLLogFile $setup->{log_file} 8909 SQLNamedQuery session_start FREEFORM "INSERT INTO ftpsessions (user, ip_addr, rename_from) VALUES (\'%u\', \'%L\', \'%H\')" 8910 SQLLog PASS session_start 8911 </IfModule> 8912</VirtualHost> 8913EOC 8914 unless (close($fh)) { 8915 die("Can't write $setup->{config_file}: $!"); 8916 } 8917 8918 } else { 8919 die("Can't open $setup->{config_file}: $!"); 8920 } 8921 8922 # Open pipes, for use between the parent and child processes. Specifically, 8923 # the child will indicate when it's done with its test by writing a message 8924 # to the parent. 8925 my ($rfh, $wfh); 8926 unless (pipe($rfh, $wfh)) { 8927 die("Can't open pipe: $!"); 8928 } 8929 8930 my $ex; 8931 8932 # Fork child 8933 $self->handle_sigchld(); 8934 defined(my $pid = fork()) or die("Can't fork: $!"); 8935 if ($pid) { 8936 eval { 8937 my $client = ProFTPD::TestSuite::FTP->new($real_addr, $real_port); 8938 $client->login($setup->{user}, $setup->{passwd}); 8939 $client->quit(); 8940 }; 8941 if ($@) { 8942 $ex = $@; 8943 } 8944 8945 $wfh->print("done\n"); 8946 $wfh->flush(); 8947 8948 } else { 8949 eval { server_wait($setup->{config_file}, $rfh) }; 8950 if ($@) { 8951 warn($@); 8952 exit 1; 8953 } 8954 8955 exit 0; 8956 } 8957 8958 # Stop server 8959 server_stop($setup->{pid_file}); 8960 $self->assert_child_ok($pid); 8961 8962 if ($ex) { 8963 test_cleanup($setup->{log_file}, $ex); 8964 } 8965 8966 eval { 8967 my ($login, $ip_addr, $sess_addr) = get_renames($db_file, "user = \'$setup->{user}\'"); 8968 8969 my $expected = $setup->{user}; 8970 $self->assert($expected eq $login, "Expected '$expected', got '$login'"); 8971 8972 $expected = $real_addr; 8973 $self->assert($expected eq $ip_addr, 8974 "Expected '$expected', got '$ip_addr'"); 8975 8976 $expected = $vhost_addr; 8977 $self->assert($expected eq $sess_addr, 8978 "Expected '$expected', got '$sess_addr'"); 8979 }; 8980 if ($@) { 8981 $ex = $@; 8982 } 8983 8984 test_cleanup($setup->{log_file}, $ex); 8985} 8986 8987sub sql_sqllog_exit_ifuser { 8988 my $self = shift; 8989 my $tmpdir = $self->{tmpdir}; 8990 8991 my $config_file = "$tmpdir/sqlite.conf"; 8992 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 8993 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 8994 8995 my $log_file = test_get_logfile(); 8996 8997 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 8998 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 8999 9000 my $user = 'proftpd'; 9001 my $passwd = 'test'; 9002 my $group = 'ftpd'; 9003 my $home_dir = File::Spec->rel2abs($tmpdir); 9004 my $uid = 500; 9005 my $gid = 500; 9006 9007 # Make sure that, if we're running as root, that the home directory has 9008 # permissions/privs set for the account we create 9009 if ($< == 0) { 9010 unless (chmod(0755, $home_dir)) { 9011 die("Can't set perms on $home_dir to 0755: $!"); 9012 } 9013 9014 unless (chown($uid, $gid, $home_dir)) { 9015 die("Can't set owner of $home_dir to $uid/$gid: $!"); 9016 } 9017 } 9018 9019 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 9020 '/bin/bash'); 9021 auth_group_write($auth_group_file, $group, $gid, $user); 9022 9023 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 9024 9025 # Build up sqlite3 command to create users, groups tables and populate them 9026 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 9027 9028 if (open(my $fh, "> $db_script")) { 9029 print $fh <<EOS; 9030CREATE TABLE ftpsessions ( 9031 user TEXT, 9032 ip_addr TEXT 9033); 9034EOS 9035 9036 unless (close($fh)) { 9037 die("Can't write $db_script: $!"); 9038 } 9039 9040 } else { 9041 die("Can't open $db_script: $!"); 9042 } 9043 9044 my $cmd = "sqlite3 $db_file < $db_script"; 9045 build_db($cmd, $db_script); 9046 9047 # Make sure that, if we're running as root, the database file has 9048 # the permissions/privs set for use by proftpd 9049 if ($< == 0) { 9050 unless (chmod(0666, $db_file)) { 9051 die("Can't set perms on $db_file to 0666: $!"); 9052 } 9053 } 9054 9055 my $config = { 9056 PidFile => $pid_file, 9057 ScoreboardFile => $scoreboard_file, 9058 SystemLog => $log_file, 9059 9060 AuthUserFile => $auth_user_file, 9061 AuthGroupFile => $auth_group_file, 9062 9063 IfModules => { 9064 'mod_delay.c' => { 9065 DelayEngine => 'off', 9066 }, 9067 9068 'mod_sql.c' => { 9069 SQLEngine => 'log', 9070 SQLBackend => 'sqlite3', 9071 SQLConnectInfo => $db_file, 9072 SQLLogFile => $log_file, 9073 SQLNamedQuery => 'logout FREEFORM "INSERT INTO ftpsessions (user, ip_addr) VALUES (\'%u\', \'%L\')"', 9074 }, 9075 }, 9076 }; 9077 9078 my ($port, $config_user, $config_group) = config_write($config_file, $config); 9079 9080 if (open(my $fh, ">> $config_file")) { 9081 print $fh <<EOC; 9082<IfModule mod_ifsession.c> 9083 <IfUser regex .*> 9084 SQLLog EXIT logout 9085 </IfUser> 9086</IfModule> 9087EOC 9088 unless (close($fh)) { 9089 die("Can't write $config_file: $!"); 9090 } 9091 9092 } else { 9093 die("Can't open $config_file: $!"); 9094 } 9095 9096 # Open pipes, for use between the parent and child processes. Specifically, 9097 # the child will indicate when it's done with its test by writing a message 9098 # to the parent. 9099 my ($rfh, $wfh); 9100 unless (pipe($rfh, $wfh)) { 9101 die("Can't open pipe: $!"); 9102 } 9103 9104 my $ex; 9105 9106 # Fork child 9107 $self->handle_sigchld(); 9108 defined(my $pid = fork()) or die("Can't fork: $!"); 9109 if ($pid) { 9110 eval { 9111 9112 # First, just connect and quit, without logging in 9113 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 9114 $client->quit(); 9115 9116 # Then connect, login, and quit 9117 $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 9118 $client->login($user, $passwd); 9119 $client->quit(); 9120 }; 9121 9122 if ($@) { 9123 $ex = $@; 9124 } 9125 9126 $wfh->print("done\n"); 9127 $wfh->flush(); 9128 9129 } else { 9130 eval { server_wait($config_file, $rfh) }; 9131 if ($@) { 9132 warn($@); 9133 exit 1; 9134 } 9135 9136 exit 0; 9137 } 9138 9139 # Stop server 9140 server_stop($pid_file); 9141 9142 $self->assert_child_ok($pid); 9143 9144 if ($ex) { 9145 test_append_logfile($log_file, $ex); 9146 unlink($log_file); 9147 9148 die($ex); 9149 } 9150 9151 my $query = "SELECT user, ip_addr FROM ftpsessions"; 9152 $cmd = "sqlite3 $db_file \"$query\""; 9153 9154 if ($ENV{TEST_VERBOSE}) { 9155 print STDERR "Executing sqlite3: $cmd\n"; 9156 } 9157 9158 my @res = `$cmd`; 9159 my $res = join('', @res); 9160 chomp($res); 9161 9162 my ($login, $ip_addr) = split(/\|/, $res); 9163 9164 my $expected; 9165 9166 $expected = $user; 9167 $self->assert($expected eq $login, 9168 test_msg("Expected '$expected', got '$login'")); 9169 9170 $expected = '127.0.0.1'; 9171 $self->assert($expected eq $ip_addr, 9172 test_msg("Expected '$expected', got '$ip_addr'")); 9173 9174 unlink($log_file); 9175} 9176 9177sub sql_sqllog_exit_ifgroup { 9178 my $self = shift; 9179 my $tmpdir = $self->{tmpdir}; 9180 9181 my $config_file = "$tmpdir/sqlite.conf"; 9182 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 9183 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 9184 9185 my $log_file = test_get_logfile(); 9186 9187 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 9188 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 9189 9190 my $user = 'proftpd'; 9191 my $passwd = 'test'; 9192 my $group = 'ftpd'; 9193 my $home_dir = File::Spec->rel2abs($tmpdir); 9194 my $uid = 500; 9195 my $gid = 500; 9196 9197 # Make sure that, if we're running as root, that the home directory has 9198 # permissions/privs set for the account we create 9199 if ($< == 0) { 9200 unless (chmod(0755, $home_dir)) { 9201 die("Can't set perms on $home_dir to 0755: $!"); 9202 } 9203 9204 unless (chown($uid, $gid, $home_dir)) { 9205 die("Can't set owner of $home_dir to $uid/$gid: $!"); 9206 } 9207 } 9208 9209 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 9210 '/bin/bash'); 9211 auth_group_write($auth_group_file, $group, $gid, $user); 9212 9213 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 9214 9215 # Build up sqlite3 command to create users, groups tables and populate them 9216 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 9217 9218 if (open(my $fh, "> $db_script")) { 9219 print $fh <<EOS; 9220CREATE TABLE ftpsessions ( 9221 user TEXT, 9222 ip_addr TEXT 9223); 9224EOS 9225 9226 unless (close($fh)) { 9227 die("Can't write $db_script: $!"); 9228 } 9229 9230 } else { 9231 die("Can't open $db_script: $!"); 9232 } 9233 9234 my $cmd = "sqlite3 $db_file < $db_script"; 9235 build_db($cmd, $db_script); 9236 9237 # Make sure that, if we're running as root, the database file has 9238 # the permissions/privs set for use by proftpd 9239 if ($< == 0) { 9240 unless (chmod(0666, $db_file)) { 9241 die("Can't set perms on $db_file to 0666: $!"); 9242 } 9243 } 9244 9245 my $config = { 9246 PidFile => $pid_file, 9247 ScoreboardFile => $scoreboard_file, 9248 SystemLog => $log_file, 9249 9250 AuthUserFile => $auth_user_file, 9251 AuthGroupFile => $auth_group_file, 9252 9253 IfModules => { 9254 'mod_delay.c' => { 9255 DelayEngine => 'off', 9256 }, 9257 9258 'mod_sql.c' => { 9259 SQLEngine => 'log', 9260 SQLBackend => 'sqlite3', 9261 SQLConnectInfo => $db_file, 9262 SQLLogFile => $log_file, 9263 SQLNamedQuery => 'logout FREEFORM "INSERT INTO ftpsessions (user, ip_addr) VALUES (\'%u\', \'%L\')"', 9264 }, 9265 }, 9266 }; 9267 9268 my ($port, $config_user, $config_group) = config_write($config_file, $config); 9269 9270 if (open(my $fh, ">> $config_file")) { 9271 print $fh <<EOC; 9272<IfModule mod_ifsession.c> 9273 <IfGroup regex .*> 9274 SQLLog EXIT logout 9275 </IfGroup> 9276</IfModule> 9277EOC 9278 unless (close($fh)) { 9279 die("Can't write $config_file: $!"); 9280 } 9281 9282 } else { 9283 die("Can't open $config_file: $!"); 9284 } 9285 9286 # Open pipes, for use between the parent and child processes. Specifically, 9287 # the child will indicate when it's done with its test by writing a message 9288 # to the parent. 9289 my ($rfh, $wfh); 9290 unless (pipe($rfh, $wfh)) { 9291 die("Can't open pipe: $!"); 9292 } 9293 9294 my $ex; 9295 9296 # Fork child 9297 $self->handle_sigchld(); 9298 defined(my $pid = fork()) or die("Can't fork: $!"); 9299 if ($pid) { 9300 eval { 9301 9302 # First, just connect and quit, without logging in 9303 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 9304 $client->quit(); 9305 9306 # Then connect, login, and quit 9307 $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 9308 $client->login($user, $passwd); 9309 $client->quit(); 9310 }; 9311 9312 if ($@) { 9313 $ex = $@; 9314 } 9315 9316 $wfh->print("done\n"); 9317 $wfh->flush(); 9318 9319 } else { 9320 eval { server_wait($config_file, $rfh) }; 9321 if ($@) { 9322 warn($@); 9323 exit 1; 9324 } 9325 9326 exit 0; 9327 } 9328 9329 # Stop server 9330 server_stop($pid_file); 9331 9332 $self->assert_child_ok($pid); 9333 9334 if ($ex) { 9335 test_append_logfile($log_file, $ex); 9336 unlink($log_file); 9337 9338 die($ex); 9339 } 9340 9341 my $query = "SELECT user, ip_addr FROM ftpsessions"; 9342 $cmd = "sqlite3 $db_file \"$query\""; 9343 9344 if ($ENV{TEST_VERBOSE}) { 9345 print STDERR "Executing sqlite3: $cmd\n"; 9346 } 9347 9348 my @res = `$cmd`; 9349 my $res = join('', @res); 9350 chomp($res); 9351 9352 my ($login, $ip_addr) = split(/\|/, $res); 9353 9354 my $expected; 9355 9356 $expected = $user; 9357 $self->assert($expected eq $login, 9358 test_msg("Expected '$expected', got '$login'")); 9359 9360 $expected = '127.0.0.1'; 9361 $self->assert($expected eq $ip_addr, 9362 test_msg("Expected '$expected', got '$ip_addr'")); 9363 9364 unlink($log_file); 9365} 9366 9367sub sql_sqllog_multi_pass_ifclass_bug4025 { 9368 my $self = shift; 9369 my $tmpdir = $self->{tmpdir}; 9370 9371 my $config_file = "$tmpdir/sqlite.conf"; 9372 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 9373 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 9374 9375 my $log_file = test_get_logfile(); 9376 9377 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 9378 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 9379 9380 my $user = 'proftpd'; 9381 my $passwd = 'test'; 9382 my $group = 'ftpd'; 9383 my $home_dir = File::Spec->rel2abs($tmpdir); 9384 my $uid = 500; 9385 my $gid = 500; 9386 9387 # Make sure that, if we're running as root, that the home directory has 9388 # permissions/privs set for the account we create 9389 if ($< == 0) { 9390 unless (chmod(0755, $home_dir)) { 9391 die("Can't set perms on $home_dir to 0755: $!"); 9392 } 9393 9394 unless (chown($uid, $gid, $home_dir)) { 9395 die("Can't set owner of $home_dir to $uid/$gid: $!"); 9396 } 9397 } 9398 9399 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 9400 '/bin/bash'); 9401 auth_group_write($auth_group_file, $group, $gid, $user); 9402 9403 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 9404 9405 # Build up sqlite3 command to create users, groups tables and populate them 9406 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 9407 9408 if (open(my $fh, "> $db_script")) { 9409 print $fh <<EOS; 9410CREATE TABLE ftpsessions ( 9411 user TEXT, 9412 ip_addr TEXT 9413); 9414EOS 9415 9416 unless (close($fh)) { 9417 die("Can't write $db_script: $!"); 9418 } 9419 9420 } else { 9421 die("Can't open $db_script: $!"); 9422 } 9423 9424 my $cmd = "sqlite3 $db_file < $db_script"; 9425 build_db($cmd, $db_script); 9426 9427 # Make sure that, if we're running as root, the database file has 9428 # the permissions/privs set for use by proftpd 9429 if ($< == 0) { 9430 unless (chmod(0666, $db_file)) { 9431 die("Can't set perms on $db_file to 0666: $!"); 9432 } 9433 } 9434 9435 my $config = { 9436 PidFile => $pid_file, 9437 ScoreboardFile => $scoreboard_file, 9438 SystemLog => $log_file, 9439 TraceLog => $log_file, 9440 Trace => 'DEFAULT:10 ifsession:20', 9441 9442 AuthUserFile => $auth_user_file, 9443 AuthGroupFile => $auth_group_file, 9444 AuthOrder => 'mod_auth_file.c', 9445 9446 IfModules => { 9447 'mod_delay.c' => { 9448 DelayEngine => 'off', 9449 }, 9450 9451 'mod_sql.c' => [ 9452 'SQLEngine log', 9453 'SQLBackend sqlite3', 9454 "SQLConnectInfo $db_file", 9455 "SQLLogFile $log_file", 9456 'SQLNamedQuery login_ip FREEFORM "INSERT INTO ftpsessions (ip_addr) VALUES (\'%L\')"', 9457 'SQLNamedQuery login_user FREEFORM "INSERT INTO ftpsessions (user) VALUES (\'%u\')"', 9458 ], 9459 }, 9460 }; 9461 9462 my ($port, $config_user, $config_group) = config_write($config_file, $config); 9463 9464 if (open(my $fh, ">> $config_file")) { 9465 print $fh <<EOC; 9466<Class test> 9467 From 127.0.0.1 9468</Class> 9469 9470<IfModule mod_ifsession.c> 9471 <IfClass test> 9472 SQLLog PASS login_ip 9473 SQLLog PASS login_user 9474 </IfClass> 9475</IfModule> 9476EOC 9477 unless (close($fh)) { 9478 die("Can't write $config_file: $!"); 9479 } 9480 9481 } else { 9482 die("Can't open $config_file: $!"); 9483 } 9484 9485 # Open pipes, for use between the parent and child processes. Specifically, 9486 # the child will indicate when it's done with its test by writing a message 9487 # to the parent. 9488 my ($rfh, $wfh); 9489 unless (pipe($rfh, $wfh)) { 9490 die("Can't open pipe: $!"); 9491 } 9492 9493 my $ex; 9494 9495 # Fork child 9496 $self->handle_sigchld(); 9497 defined(my $pid = fork()) or die("Can't fork: $!"); 9498 if ($pid) { 9499 eval { 9500 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 9501 $client->login($user, $passwd); 9502 $client->quit(); 9503 }; 9504 9505 if ($@) { 9506 $ex = $@; 9507 } 9508 9509 $wfh->print("done\n"); 9510 $wfh->flush(); 9511 9512 } else { 9513 eval { server_wait($config_file, $rfh) }; 9514 if ($@) { 9515 warn($@); 9516 exit 1; 9517 } 9518 9519 exit 0; 9520 } 9521 9522 # Stop server 9523 server_stop($pid_file); 9524 9525 $self->assert_child_ok($pid); 9526 9527 if ($ex) { 9528 test_append_logfile($log_file, $ex); 9529 unlink($log_file); 9530 9531 die($ex); 9532 } 9533 9534 my $query = "SELECT user, ip_addr FROM ftpsessions"; 9535 $cmd = "sqlite3 $db_file \"$query\""; 9536 9537 if ($ENV{TEST_VERBOSE}) { 9538 print STDERR "Executing sqlite3: $cmd\n"; 9539 } 9540 9541 my @res = `$cmd`; 9542 my $res = join('', @res); 9543 $res =~ s/\n//g; 9544 chomp($res); 9545 9546 my ($login, $ip_addr) = split(/\|+/, $res); 9547 9548 my $expected; 9549 9550 $expected = $user; 9551 $self->assert($expected eq $login, 9552 test_msg("Expected '$expected', got '$login'")); 9553 9554 $expected = '127.0.0.1'; 9555 $self->assert($expected eq $ip_addr, 9556 test_msg("Expected '$expected', got '$ip_addr'")); 9557 9558 unlink($log_file); 9559} 9560 9561sub sql_opt_no_disconnect_on_error_with_extlog_bug3633 { 9562 my $self = shift; 9563 my $tmpdir = $self->{tmpdir}; 9564 9565 my $config_file = "$tmpdir/sqlite.conf"; 9566 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 9567 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 9568 9569 my $log_file = test_get_logfile(); 9570 9571 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 9572 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 9573 9574 my $user = 'proftpd'; 9575 my $passwd = 'test'; 9576 my $group = 'ftpd'; 9577 my $home_dir = File::Spec->rel2abs($tmpdir); 9578 my $uid = 500; 9579 my $gid = 500; 9580 9581 # Make sure that, if we're running as root, that the home directory has 9582 # permissions/privs set for the account we create 9583 if ($< == 0) { 9584 unless (chmod(0755, $home_dir)) { 9585 die("Can't set perms on $home_dir to 0755: $!"); 9586 } 9587 9588 unless (chown($uid, $gid, $home_dir)) { 9589 die("Can't set owner of $home_dir to $uid/$gid: $!"); 9590 } 9591 } 9592 9593 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 9594 '/bin/bash'); 9595 auth_group_write($auth_group_file, $group, $gid, $user); 9596 9597 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 9598 9599 # Build up sqlite3 command to create users, groups tables and populate them 9600 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 9601 9602 if (open(my $fh, "> $db_script")) { 9603 print $fh <<EOS; 9604CREATE TABLE ftpsessions ( 9605 user TEXT, 9606 ip_addr TEXT, 9607 timestamp TEXT 9608); 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 build_db($cmd, $db_script); 9621 9622 # Make sure that, if we're running as root, the database file has 9623 # the permissions/privs set for use by proftpd 9624 if ($< == 0) { 9625 unless (chmod(0666, $db_file)) { 9626 die("Can't set perms on $db_file to 0666: $!"); 9627 } 9628 } 9629 9630 my $test_file = File::Spec->rel2abs("$home_dir/test.txt"); 9631 if (open(my $fh, "> $test_file")) { 9632 print $fh "Hello, World!\n"; 9633 unless (close($fh)) { 9634 die("Can't write $test_file: $!"); 9635 } 9636 9637 } else { 9638 die("Can't open $test_file: $!"); 9639 } 9640 9641 my $ext_log = File::Spec->rel2abs("$tmpdir/custom.log"); 9642 9643 my $config = { 9644 PidFile => $pid_file, 9645 ScoreboardFile => $scoreboard_file, 9646 SystemLog => $log_file, 9647 TraceLog => $log_file, 9648 Trace => 'DEFAULT:10 sql:20', 9649 9650 AuthUserFile => $auth_user_file, 9651 AuthGroupFile => $auth_group_file, 9652 9653 LogFormat => 'custom "%m %f"', 9654 ExtendedLog => "$ext_log ALL custom", 9655 9656 IfModules => { 9657 'mod_delay.c' => { 9658 DelayEngine => 'off', 9659 }, 9660 9661 'mod_sql.c' => { 9662 SQLEngine => 'log', 9663 SQLBackend => 'sqlite3', 9664 SQLConnectInfo => $db_file, 9665 SQLLogFile => $log_file, 9666 SQLNamedQuery => 'log_dele FREEFORM "INSERT INTO ftpsessions (user, ip_addr, ts) VALUES (\'%u\', \'%L\', \'%{time:%Y-%m-%d %H:%M:%S}\')"', 9667 SQLLog => 'DELE log_dele', 9668 9669 SQLOptions => 'noDisconnectOnError', 9670 }, 9671 }, 9672 }; 9673 9674 my ($port, $config_user, $config_group) = config_write($config_file, $config); 9675 9676 # Open pipes, for use between the parent and child processes. Specifically, 9677 # the child will indicate when it's done with its test by writing a message 9678 # to the parent. 9679 my ($rfh, $wfh); 9680 unless (pipe($rfh, $wfh)) { 9681 die("Can't open pipe: $!"); 9682 } 9683 9684 my $ex; 9685 9686 # Fork child 9687 $self->handle_sigchld(); 9688 defined(my $pid = fork()) or die("Can't fork: $!"); 9689 if ($pid) { 9690 eval { 9691 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 9692 9693 $client->login($user, $passwd); 9694 $client->dele('test.txt'); 9695 $client->quit(); 9696 }; 9697 9698 if ($@) { 9699 $ex = $@; 9700 } 9701 9702 $wfh->print("done\n"); 9703 $wfh->flush(); 9704 9705 } else { 9706 eval { server_wait($config_file, $rfh) }; 9707 if ($@) { 9708 warn($@); 9709 exit 1; 9710 } 9711 9712 exit 0; 9713 } 9714 9715 # Stop server 9716 server_stop($pid_file); 9717 9718 $self->assert_child_ok($pid); 9719 9720 if ($ex) { 9721 test_append_logfile($log_file, $ex); 9722 unlink($log_file); 9723 9724 die($ex); 9725 } 9726 9727 # Now, read in the ExtendedLog, and see whether the %f variable was 9728 # properly written out. 9729 if (open(my $fh, "< $ext_log")) { 9730 my $ok = 0; 9731 9732 while (my $line = <$fh>) { 9733 chomp($line); 9734 9735 # We're only interested in the DELE log line 9736 unless ($line =~ /^DELE (.*)$/i) { 9737 next; 9738 } 9739 9740 my $name = $1; 9741 9742 if ($^O eq 'darwin') { 9743 # MacOSX-specific hack 9744 $test_file = '/private' . $test_file; 9745 } 9746 9747 my $expected = $test_file; 9748 $self->assert($expected eq $name, 9749 test_msg("Expected '$expected', got '$name'")); 9750 9751 $ok = 1; 9752 } 9753 9754 close($fh); 9755 9756 $self->assert($ok, test_msg("Expected ExtendedLog messages not found")); 9757 9758 } else { 9759 die("Can't read $ext_log: $!"); 9760 } 9761 9762 unlink($log_file); 9763} 9764 9765sub sql_sqllog_ignore_errors_bad_table_bug3692 { 9766 my $self = shift; 9767 my $tmpdir = $self->{tmpdir}; 9768 9769 my $config_file = "$tmpdir/sqlite.conf"; 9770 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 9771 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 9772 9773 my $log_file = test_get_logfile(); 9774 9775 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 9776 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 9777 9778 my $user = 'proftpd'; 9779 my $passwd = 'test'; 9780 my $group = 'ftpd'; 9781 my $home_dir = File::Spec->rel2abs($tmpdir); 9782 my $uid = 500; 9783 my $gid = 500; 9784 9785 # Make sure that, if we're running as root, that the home directory has 9786 # permissions/privs set for the account we create 9787 if ($< == 0) { 9788 unless (chmod(0755, $home_dir)) { 9789 die("Can't set perms on $home_dir to 0755: $!"); 9790 } 9791 9792 unless (chown($uid, $gid, $home_dir)) { 9793 die("Can't set owner of $home_dir to $uid/$gid: $!"); 9794 } 9795 } 9796 9797 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 9798 '/bin/bash'); 9799 auth_group_write($auth_group_file, $group, $gid, $user); 9800 9801 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 9802 9803 # Build up sqlite3 command to create users, groups tables and populate them 9804 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 9805 9806 if (open(my $fh, "> $db_script")) { 9807 print $fh <<EOS; 9808CREATE TABLE ftpsessions ( 9809 user TEXT, 9810 ip_addr TEXT, 9811 timestamp TEXT 9812); 9813EOS 9814 9815 unless (close($fh)) { 9816 die("Can't write $db_script: $!"); 9817 } 9818 9819 } else { 9820 die("Can't open $db_script: $!"); 9821 } 9822 9823 my $cmd = "sqlite3 $db_file < $db_script"; 9824 build_db($cmd, $db_script); 9825 9826 # Make sure that, if we're running as root, the database file has 9827 # the permissions/privs set for use by proftpd 9828 if ($< == 0) { 9829 unless (chmod(0666, $db_file)) { 9830 die("Can't set perms on $db_file to 0666: $!"); 9831 } 9832 } 9833 9834 my $config = { 9835 PidFile => $pid_file, 9836 ScoreboardFile => $scoreboard_file, 9837 SystemLog => $log_file, 9838 9839 AuthUserFile => $auth_user_file, 9840 AuthGroupFile => $auth_group_file, 9841 9842 IfModules => { 9843 'mod_delay.c' => { 9844 DelayEngine => 'off', 9845 }, 9846 9847 'mod_sql.c' => { 9848 SQLEngine => 'log', 9849 SQLBackend => 'sqlite3', 9850 SQLConnectInfo => $db_file, 9851 SQLLogFile => $log_file, 9852 SQLNamedQuery => 'session_start FREEFORM "INSERT INTO ftpsessions (user, ip_addr, ts) VALUES (\'%u\', \'%L\', \'%{time:%Y-%m-%d %H:%M:%S}\')"', 9853 SQLLog => 'PASS session_start IGNORE_ERRORS', 9854 }, 9855 }, 9856 }; 9857 9858 my ($port, $config_user, $config_group) = config_write($config_file, $config); 9859 9860 # Open pipes, for use between the parent and child processes. Specifically, 9861 # the child will indicate when it's done with its test by writing a message 9862 # to the parent. 9863 my ($rfh, $wfh); 9864 unless (pipe($rfh, $wfh)) { 9865 die("Can't open pipe: $!"); 9866 } 9867 9868 my $ex; 9869 9870 # Fork child 9871 $self->handle_sigchld(); 9872 defined(my $pid = fork()) or die("Can't fork: $!"); 9873 if ($pid) { 9874 eval { 9875 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 9876 9877 $client->login($user, $passwd); 9878 }; 9879 9880 if ($@) { 9881 $ex = $@; 9882 } 9883 9884 $wfh->print("done\n"); 9885 $wfh->flush(); 9886 9887 } else { 9888 eval { server_wait($config_file, $rfh) }; 9889 if ($@) { 9890 warn($@); 9891 exit 1; 9892 } 9893 9894 exit 0; 9895 } 9896 9897 # Stop server 9898 server_stop($pid_file); 9899 9900 $self->assert_child_ok($pid); 9901 9902 if ($ex) { 9903 test_append_logfile($log_file, $ex); 9904 unlink($log_file); 9905 9906 die($ex); 9907 } 9908 9909 unlink($log_file); 9910} 9911 9912sub sql_sqllog_ignore_errors_bad_db_bug3692 { 9913 my $self = shift; 9914 my $tmpdir = $self->{tmpdir}; 9915 9916 my $config_file = "$tmpdir/sqlite.conf"; 9917 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 9918 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 9919 9920 my $log_file = test_get_logfile(); 9921 9922 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 9923 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 9924 9925 my $user = 'proftpd'; 9926 my $passwd = 'test'; 9927 my $group = 'ftpd'; 9928 my $home_dir = File::Spec->rel2abs($tmpdir); 9929 my $uid = 500; 9930 my $gid = 500; 9931 9932 # Make sure that, if we're running as root, that the home directory has 9933 # permissions/privs set for the account we create 9934 if ($< == 0) { 9935 unless (chmod(0755, $home_dir)) { 9936 die("Can't set perms on $home_dir to 0755: $!"); 9937 } 9938 9939 unless (chown($uid, $gid, $home_dir)) { 9940 die("Can't set owner of $home_dir to $uid/$gid: $!"); 9941 } 9942 } 9943 9944 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 9945 '/bin/bash'); 9946 auth_group_write($auth_group_file, $group, $gid, $user); 9947 9948 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 9949 9950 # Build up sqlite3 command to create users, groups tables and populate them 9951 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 9952 9953 if (open(my $fh, "> $db_script")) { 9954 print $fh <<EOS; 9955CREATE TABLE ftpsessions ( 9956 user TEXT, 9957 ip_addr TEXT, 9958 timestamp TEXT 9959); 9960EOS 9961 9962 unless (close($fh)) { 9963 die("Can't write $db_script: $!"); 9964 } 9965 9966 } else { 9967 die("Can't open $db_script: $!"); 9968 } 9969 9970 my $cmd = "sqlite3 $db_file < $db_script"; 9971 build_db($cmd, $db_script); 9972 9973 # Make sure that, if we're running as root, the database file has 9974 # the permissions/privs set for use by proftpd 9975 if ($< == 0) { 9976 unless (chmod(0666, $db_file)) { 9977 die("Can't set perms on $db_file to 0666: $!"); 9978 } 9979 } 9980 9981 my $config = { 9982 PidFile => $pid_file, 9983 ScoreboardFile => $scoreboard_file, 9984 SystemLog => $log_file, 9985 9986 AuthUserFile => $auth_user_file, 9987 AuthGroupFile => $auth_group_file, 9988 9989 IfModules => { 9990 'mod_delay.c' => { 9991 DelayEngine => 'off', 9992 }, 9993 9994 'mod_sql.c' => { 9995 SQLEngine => 'log', 9996 SQLBackend => 'sqlite3', 9997 SQLConnectInfo => "/foobar/$db_file", 9998 SQLLogFile => $log_file, 9999 SQLNamedQuery => 'session_start FREEFORM "INSERT INTO ftpsessions (user, ip_addr, ts) VALUES (\'%u\', \'%L\', \'%{time:%Y-%m-%d %H:%M:%S}\')"', 10000 SQLLog => 'PASS session_start IGNORE_ERRORS', 10001 }, 10002 }, 10003 }; 10004 10005 my ($port, $config_user, $config_group) = config_write($config_file, $config); 10006 10007 # Open pipes, for use between the parent and child processes. Specifically, 10008 # the child will indicate when it's done with its test by writing a message 10009 # to the parent. 10010 my ($rfh, $wfh); 10011 unless (pipe($rfh, $wfh)) { 10012 die("Can't open pipe: $!"); 10013 } 10014 10015 my $ex; 10016 10017 # Fork child 10018 $self->handle_sigchld(); 10019 defined(my $pid = fork()) or die("Can't fork: $!"); 10020 if ($pid) { 10021 eval { 10022 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 10023 10024 $client->login($user, $passwd); 10025 }; 10026 10027 if ($@) { 10028 $ex = $@; 10029 } 10030 10031 $wfh->print("done\n"); 10032 $wfh->flush(); 10033 10034 } else { 10035 eval { server_wait($config_file, $rfh) }; 10036 if ($@) { 10037 warn($@); 10038 exit 1; 10039 } 10040 10041 exit 0; 10042 } 10043 10044 # Stop server 10045 server_stop($pid_file); 10046 10047 $self->assert_child_ok($pid); 10048 10049 if ($ex) { 10050 test_append_logfile($log_file, $ex); 10051 unlink($log_file); 10052 10053 die($ex); 10054 } 10055 10056 unlink($log_file); 10057} 10058 10059sub get_xfer_status { 10060 my $db_file = shift; 10061 my $where = shift; 10062 10063 my $sql = "SELECT user, ip_addr, xfer_status, xfer_path FROM ftpsessions"; 10064 if ($where) { 10065 $sql .= " WHERE $where"; 10066 } 10067 $sql .= " LIMIT 1"; 10068 10069 my $cmd = "sqlite3 $db_file \"$sql\""; 10070 10071 if ($ENV{TEST_VERBOSE}) { 10072 print STDERR "Executing sqlite3: $cmd\n"; 10073 } 10074 10075 my $res = join('', `$cmd`); 10076 chomp($res); 10077 10078 # The default sqlite3 delimiter is '|' 10079 return map { chomp($_); $_; } split(/\|/, $res); 10080} 10081 10082sub sql_sqllog_var_xfer_status_nonxfer { 10083 my $self = shift; 10084 my $tmpdir = $self->{tmpdir}; 10085 10086 my $config_file = "$tmpdir/sqlite.conf"; 10087 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 10088 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 10089 10090 my $log_file = test_get_logfile(); 10091 10092 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 10093 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 10094 10095 my $user = 'proftpd'; 10096 my $passwd = 'test'; 10097 my $group = 'ftpd'; 10098 my $home_dir = File::Spec->rel2abs($tmpdir); 10099 my $uid = 500; 10100 my $gid = 500; 10101 10102 # Make sure that, if we're running as root, that the home directory has 10103 # permissions/privs set for the account we create 10104 if ($< == 0) { 10105 unless (chmod(0755, $home_dir)) { 10106 die("Can't set perms on $home_dir to 0755: $!"); 10107 } 10108 10109 unless (chown($uid, $gid, $home_dir)) { 10110 die("Can't set owner of $home_dir to $uid/$gid: $!"); 10111 } 10112 } 10113 10114 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 10115 '/bin/bash'); 10116 auth_group_write($auth_group_file, $group, $gid, $user); 10117 10118 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 10119 10120 # Build up sqlite3 command to create users, groups tables and populate them 10121 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 10122 10123 if (open(my $fh, "> $db_script")) { 10124 print $fh <<EOS; 10125CREATE TABLE ftpsessions ( 10126 user TEXT, 10127 ip_addr TEXT, 10128 xfer_status TEXT, 10129 xfer_path TEXT 10130); 10131EOS 10132 10133 unless (close($fh)) { 10134 die("Can't write $db_script: $!"); 10135 } 10136 10137 } else { 10138 die("Can't open $db_script: $!"); 10139 } 10140 10141 my $cmd = "sqlite3 $db_file < $db_script"; 10142 build_db($cmd, $db_script); 10143 10144 # Make sure that, if we're running as root, the database file has 10145 # the permissions/privs set for use by proftpd 10146 if ($< == 0) { 10147 unless (chmod(0666, $db_file)) { 10148 die("Can't set perms on $db_file to 0666: $!"); 10149 } 10150 } 10151 10152 my $test_file = File::Spec->rel2abs("$tmpdir/test.txt"); 10153 if (open(my $fh, "> $test_file")) { 10154 close($fh); 10155 10156 } else { 10157 die("Can't open $test_file: $!"); 10158 } 10159 10160 my $config = { 10161 PidFile => $pid_file, 10162 ScoreboardFile => $scoreboard_file, 10163 SystemLog => $log_file, 10164 TraceLog => $log_file, 10165 Trace => 'sql:20 command:20 netio:20', 10166 10167 AuthUserFile => $auth_user_file, 10168 AuthGroupFile => $auth_group_file, 10169 10170 IfModules => { 10171 'mod_delay.c' => { 10172 DelayEngine => 'off', 10173 }, 10174 10175 'mod_sql.c' => { 10176 SQLEngine => 'log', 10177 SQLBackend => 'sqlite3', 10178 SQLConnectInfo => $db_file, 10179 SQLLogFile => $log_file, 10180 SQLNamedQuery => 'xfer_status FREEFORM "INSERT INTO ftpsessions (user, ip_addr, xfer_status, xfer_path) VALUES (\'%u\', \'%L\', \'%{transfer-status}\', \'%f\')"', 10181 SQLLog => 'PWD xfer_status', 10182 }, 10183 }, 10184 }; 10185 10186 my ($port, $config_user, $config_group) = config_write($config_file, $config); 10187 10188 # Open pipes, for use between the parent and child processes. Specifically, 10189 # the child will indicate when it's done with its test by writing a message 10190 # to the parent. 10191 my ($rfh, $wfh); 10192 unless (pipe($rfh, $wfh)) { 10193 die("Can't open pipe: $!"); 10194 } 10195 10196 my $ex; 10197 10198 # Fork child 10199 $self->handle_sigchld(); 10200 defined(my $pid = fork()) or die("Can't fork: $!"); 10201 if ($pid) { 10202 eval { 10203 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 10204 $client->login($user, $passwd); 10205 $client->pwd(); 10206 $client->quit(); 10207 }; 10208 10209 if ($@) { 10210 $ex = $@; 10211 } 10212 10213 $wfh->print("done\n"); 10214 $wfh->flush(); 10215 10216 } else { 10217 eval { server_wait($config_file, $rfh) }; 10218 if ($@) { 10219 warn($@); 10220 exit 1; 10221 } 10222 10223 exit 0; 10224 } 10225 10226 # Stop server 10227 server_stop($pid_file); 10228 10229 $self->assert_child_ok($pid); 10230 10231 if ($ex) { 10232 test_append_logfile($log_file, $ex); 10233 unlink($log_file); 10234 10235 die($ex); 10236 } 10237 10238 my ($login, $ip_addr, $xfer_status, $xfer_path) = get_xfer_status($db_file, "user = \'$user\'"); 10239 10240 my $expected; 10241 10242 $expected = $user; 10243 $self->assert($expected eq $login, 10244 test_msg("Expected user '$expected', got '$login'")); 10245 10246 $expected = '127.0.0.1'; 10247 $self->assert($expected eq $ip_addr, 10248 test_msg("Expected IP address '$expected', got '$ip_addr'")); 10249 10250 $expected = '-'; 10251 $self->assert($expected eq $xfer_status, 10252 test_msg("Expected transfer status '$expected', got '$xfer_status'")); 10253 10254 if ($^O eq 'darwin') { 10255 # MacOSX-specific hack 10256 $home_dir = '/private' . $home_dir; 10257 } 10258 10259 $expected = $home_dir; 10260 $self->assert($expected eq $xfer_path, 10261 test_msg("Expected file path '$expected', got '$xfer_path'")); 10262 10263 unlink($log_file); 10264} 10265 10266sub sql_sqllog_var_xfer_status_success_download { 10267 my $self = shift; 10268 my $tmpdir = $self->{tmpdir}; 10269 10270 my $config_file = "$tmpdir/sqlite.conf"; 10271 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 10272 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 10273 10274 my $log_file = test_get_logfile(); 10275 10276 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 10277 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 10278 10279 my $user = 'proftpd'; 10280 my $passwd = 'test'; 10281 my $group = 'ftpd'; 10282 my $home_dir = File::Spec->rel2abs($tmpdir); 10283 my $uid = 500; 10284 my $gid = 500; 10285 10286 # Make sure that, if we're running as root, that the home directory has 10287 # permissions/privs set for the account we create 10288 if ($< == 0) { 10289 unless (chmod(0755, $home_dir)) { 10290 die("Can't set perms on $home_dir to 0755: $!"); 10291 } 10292 10293 unless (chown($uid, $gid, $home_dir)) { 10294 die("Can't set owner of $home_dir to $uid/$gid: $!"); 10295 } 10296 } 10297 10298 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 10299 '/bin/bash'); 10300 auth_group_write($auth_group_file, $group, $gid, $user); 10301 10302 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 10303 10304 # Build up sqlite3 command to create users, groups tables and populate them 10305 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 10306 10307 if (open(my $fh, "> $db_script")) { 10308 print $fh <<EOS; 10309CREATE TABLE ftpsessions ( 10310 user TEXT, 10311 ip_addr TEXT, 10312 xfer_status TEXT, 10313 xfer_path TEXT 10314); 10315EOS 10316 10317 unless (close($fh)) { 10318 die("Can't write $db_script: $!"); 10319 } 10320 10321 } else { 10322 die("Can't open $db_script: $!"); 10323 } 10324 10325 my $cmd = "sqlite3 $db_file < $db_script"; 10326 build_db($cmd, $db_script); 10327 10328 # Make sure that, if we're running as root, the database file has 10329 # the permissions/privs set for use by proftpd 10330 if ($< == 0) { 10331 unless (chmod(0666, $db_file)) { 10332 die("Can't set perms on $db_file to 0666: $!"); 10333 } 10334 } 10335 10336 my $test_file = File::Spec->rel2abs("$tmpdir/test.txt"); 10337 if (open(my $fh, "> $test_file")) { 10338 close($fh); 10339 10340 } else { 10341 die("Can't open $test_file: $!"); 10342 } 10343 10344 my $config = { 10345 PidFile => $pid_file, 10346 ScoreboardFile => $scoreboard_file, 10347 SystemLog => $log_file, 10348 TraceLog => $log_file, 10349 Trace => 'sql:20 command:20 netio:20', 10350 10351 AuthUserFile => $auth_user_file, 10352 AuthGroupFile => $auth_group_file, 10353 10354 IfModules => { 10355 'mod_delay.c' => { 10356 DelayEngine => 'off', 10357 }, 10358 10359 'mod_sql.c' => { 10360 SQLEngine => 'log', 10361 SQLBackend => 'sqlite3', 10362 SQLConnectInfo => $db_file, 10363 SQLLogFile => $log_file, 10364 SQLNamedQuery => 'xfer_status FREEFORM "INSERT INTO ftpsessions (user, ip_addr, xfer_status, xfer_path) VALUES (\'%u\', \'%L\', \'%{transfer-status}\', \'%f\')"', 10365 SQLLog => 'ERR_RETR,RETR xfer_status', 10366 }, 10367 }, 10368 }; 10369 10370 my ($port, $config_user, $config_group) = config_write($config_file, $config); 10371 10372 # Open pipes, for use between the parent and child processes. Specifically, 10373 # the child will indicate when it's done with its test by writing a message 10374 # to the parent. 10375 my ($rfh, $wfh); 10376 unless (pipe($rfh, $wfh)) { 10377 die("Can't open pipe: $!"); 10378 } 10379 10380 my $ex; 10381 10382 # Fork child 10383 $self->handle_sigchld(); 10384 defined(my $pid = fork()) or die("Can't fork: $!"); 10385 if ($pid) { 10386 eval { 10387 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 10388 $client->login($user, $passwd); 10389 10390 my $conn = $client->retr_raw('test.txt'); 10391 unless ($conn) { 10392 die("RETR test.txt failed: " . $client->response_code() . " " . 10393 $client->response_msg()); 10394 } 10395 10396 my $buf; 10397 $conn->read($buf, 8192, 25); 10398 eval { $conn->close() }; 10399 10400 my $resp_code = $client->response_code(); 10401 my $resp_msg = $client->response_msg(); 10402 10403 $self->assert_transfer_ok($resp_code, $resp_msg); 10404 10405 $client->quit(); 10406 }; 10407 10408 if ($@) { 10409 $ex = $@; 10410 } 10411 10412 $wfh->print("done\n"); 10413 $wfh->flush(); 10414 10415 } else { 10416 eval { server_wait($config_file, $rfh) }; 10417 if ($@) { 10418 warn($@); 10419 exit 1; 10420 } 10421 10422 exit 0; 10423 } 10424 10425 # Stop server 10426 server_stop($pid_file); 10427 10428 $self->assert_child_ok($pid); 10429 10430 if ($ex) { 10431 test_append_logfile($log_file, $ex); 10432 unlink($log_file); 10433 10434 die($ex); 10435 } 10436 10437 my ($login, $ip_addr, $xfer_status, $xfer_path) = get_xfer_status($db_file, "user = \'$user\'"); 10438 10439 my $expected; 10440 10441 $expected = $user; 10442 $self->assert($expected eq $login, 10443 test_msg("Expected user '$expected', got '$login'")); 10444 10445 $expected = '127.0.0.1'; 10446 $self->assert($expected eq $ip_addr, 10447 test_msg("Expected IP address '$expected', got '$ip_addr'")); 10448 10449 $expected = 'success'; 10450 $self->assert($expected eq $xfer_status, 10451 test_msg("Expected transfer status '$expected', got '$xfer_status'")); 10452 10453 if ($^O eq 'darwin') { 10454 # MacOSX-specific hack 10455 $test_file = '/private' . $test_file; 10456 } 10457 10458 $expected = $test_file; 10459 $self->assert($expected eq $xfer_path, 10460 test_msg("Expected file path '$expected', got '$xfer_path'")); 10461 10462 unlink($log_file); 10463} 10464 10465sub sql_sqllog_var_xfer_status_success_upload { 10466 my $self = shift; 10467 my $tmpdir = $self->{tmpdir}; 10468 10469 my $config_file = "$tmpdir/sqlite.conf"; 10470 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 10471 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 10472 10473 my $log_file = test_get_logfile(); 10474 10475 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 10476 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 10477 10478 my $user = 'proftpd'; 10479 my $passwd = 'test'; 10480 my $group = 'ftpd'; 10481 my $home_dir = File::Spec->rel2abs($tmpdir); 10482 my $uid = 500; 10483 my $gid = 500; 10484 10485 # Make sure that, if we're running as root, that the home directory has 10486 # permissions/privs set for the account we create 10487 if ($< == 0) { 10488 unless (chmod(0755, $home_dir)) { 10489 die("Can't set perms on $home_dir to 0755: $!"); 10490 } 10491 10492 unless (chown($uid, $gid, $home_dir)) { 10493 die("Can't set owner of $home_dir to $uid/$gid: $!"); 10494 } 10495 } 10496 10497 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 10498 '/bin/bash'); 10499 auth_group_write($auth_group_file, $group, $gid, $user); 10500 10501 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 10502 10503 # Build up sqlite3 command to create users, groups tables and populate them 10504 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 10505 10506 if (open(my $fh, "> $db_script")) { 10507 print $fh <<EOS; 10508CREATE TABLE ftpsessions ( 10509 user TEXT, 10510 ip_addr TEXT, 10511 xfer_status TEXT, 10512 xfer_path TEXT 10513); 10514EOS 10515 10516 unless (close($fh)) { 10517 die("Can't write $db_script: $!"); 10518 } 10519 10520 } else { 10521 die("Can't open $db_script: $!"); 10522 } 10523 10524 my $cmd = "sqlite3 $db_file < $db_script"; 10525 build_db($cmd, $db_script); 10526 10527 # Make sure that, if we're running as root, the database file has 10528 # the permissions/privs set for use by proftpd 10529 if ($< == 0) { 10530 unless (chmod(0666, $db_file)) { 10531 die("Can't set perms on $db_file to 0666: $!"); 10532 } 10533 } 10534 10535 my $test_file = File::Spec->rel2abs("$tmpdir/test.txt"); 10536 10537 my $config = { 10538 PidFile => $pid_file, 10539 ScoreboardFile => $scoreboard_file, 10540 SystemLog => $log_file, 10541 TraceLog => $log_file, 10542 Trace => 'sql:20 command:20 netio:20', 10543 10544 AuthUserFile => $auth_user_file, 10545 AuthGroupFile => $auth_group_file, 10546 10547 IfModules => { 10548 'mod_delay.c' => { 10549 DelayEngine => 'off', 10550 }, 10551 10552 'mod_sql.c' => { 10553 SQLEngine => 'log', 10554 SQLBackend => 'sqlite3', 10555 SQLConnectInfo => $db_file, 10556 SQLLogFile => $log_file, 10557 SQLNamedQuery => 'xfer_status FREEFORM "INSERT INTO ftpsessions (user, ip_addr, xfer_status, xfer_path) VALUES (\'%u\', \'%L\', \'%{transfer-status}\', \'%f\')"', 10558 SQLLog => 'ERR_STOR,STOR xfer_status', 10559 }, 10560 }, 10561 }; 10562 10563 my ($port, $config_user, $config_group) = config_write($config_file, $config); 10564 10565 # Open pipes, for use between the parent and child processes. Specifically, 10566 # the child will indicate when it's done with its test by writing a message 10567 # to the parent. 10568 my ($rfh, $wfh); 10569 unless (pipe($rfh, $wfh)) { 10570 die("Can't open pipe: $!"); 10571 } 10572 10573 my $ex; 10574 10575 # Fork child 10576 $self->handle_sigchld(); 10577 defined(my $pid = fork()) or die("Can't fork: $!"); 10578 if ($pid) { 10579 eval { 10580 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 10581 $client->login($user, $passwd); 10582 10583 my $conn = $client->stor_raw('test.txt'); 10584 unless ($conn) { 10585 die("STOR test.txt failed: " . $client->response_code() . " " . 10586 $client->response_msg()); 10587 } 10588 10589 my $buf = "Hello, World!\n"; 10590 $conn->write($buf, length($buf), 25); 10591 eval { $conn->close() }; 10592 10593 my $resp_code = $client->response_code(); 10594 my $resp_msg = $client->response_msg(); 10595 10596 $self->assert_transfer_ok($resp_code, $resp_msg); 10597 10598 $client->quit(); 10599 }; 10600 10601 if ($@) { 10602 $ex = $@; 10603 } 10604 10605 $wfh->print("done\n"); 10606 $wfh->flush(); 10607 10608 } else { 10609 eval { server_wait($config_file, $rfh) }; 10610 if ($@) { 10611 warn($@); 10612 exit 1; 10613 } 10614 10615 exit 0; 10616 } 10617 10618 # Stop server 10619 server_stop($pid_file); 10620 10621 $self->assert_child_ok($pid); 10622 10623 if ($ex) { 10624 test_append_logfile($log_file, $ex); 10625 unlink($log_file); 10626 10627 die($ex); 10628 } 10629 10630 my ($login, $ip_addr, $xfer_status, $xfer_path) = get_xfer_status($db_file, "user = \'$user\'"); 10631 10632 my $expected; 10633 10634 $expected = $user; 10635 $self->assert($expected eq $login, 10636 test_msg("Expected user '$expected', got '$login'")); 10637 10638 $expected = '127.0.0.1'; 10639 $self->assert($expected eq $ip_addr, 10640 test_msg("Expected IP address '$expected', got '$ip_addr'")); 10641 10642 $expected = 'success'; 10643 $self->assert($expected eq $xfer_status, 10644 test_msg("Expected transfer status '$expected', got '$xfer_status'")); 10645 10646 if ($^O eq 'darwin') { 10647 # MacOSX-specific hack 10648 $test_file = '/private' . $test_file; 10649 } 10650 10651 $expected = $test_file; 10652 $self->assert($expected eq $xfer_path, 10653 test_msg("Expected file path '$expected', got '$xfer_path'")); 10654 10655 unlink($log_file); 10656} 10657 10658sub sql_sqllog_var_xfer_status_cancelled { 10659 my $self = shift; 10660 my $tmpdir = $self->{tmpdir}; 10661 10662 my $config_file = "$tmpdir/sqlite.conf"; 10663 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 10664 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 10665 10666 my $log_file = test_get_logfile(); 10667 10668 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 10669 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 10670 10671 my $user = 'proftpd'; 10672 my $passwd = 'test'; 10673 my $group = 'ftpd'; 10674 my $home_dir = File::Spec->rel2abs($tmpdir); 10675 my $uid = 500; 10676 my $gid = 500; 10677 10678 # Make sure that, if we're running as root, that the home directory has 10679 # permissions/privs set for the account we create 10680 if ($< == 0) { 10681 unless (chmod(0755, $home_dir)) { 10682 die("Can't set perms on $home_dir to 0755: $!"); 10683 } 10684 10685 unless (chown($uid, $gid, $home_dir)) { 10686 die("Can't set owner of $home_dir to $uid/$gid: $!"); 10687 } 10688 } 10689 10690 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 10691 '/bin/bash'); 10692 auth_group_write($auth_group_file, $group, $gid, $user); 10693 10694 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 10695 10696 # Build up sqlite3 command to create users, groups tables and populate them 10697 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 10698 10699 if (open(my $fh, "> $db_script")) { 10700 print $fh <<EOS; 10701CREATE TABLE ftpsessions ( 10702 user TEXT, 10703 ip_addr TEXT, 10704 xfer_status TEXT, 10705 xfer_path TEXT 10706); 10707EOS 10708 10709 unless (close($fh)) { 10710 die("Can't write $db_script: $!"); 10711 } 10712 10713 } else { 10714 die("Can't open $db_script: $!"); 10715 } 10716 10717 my $cmd = "sqlite3 $db_file < $db_script"; 10718 build_db($cmd, $db_script); 10719 10720 # Make sure that, if we're running as root, the database file has 10721 # the permissions/privs set for use by proftpd 10722 if ($< == 0) { 10723 unless (chmod(0666, $db_file)) { 10724 die("Can't set perms on $db_file to 0666: $!"); 10725 } 10726 } 10727 10728 my $test_file = File::Spec->rel2abs("$tmpdir/test.txt"); 10729 if (open(my $fh, "> $test_file")) { 10730 print $fh "ABCDefgh" x 32768; 10731 10732 unless (close($fh)) { 10733 die("Can't write $test_file: $!"); 10734 } 10735 10736 } else { 10737 die("Can't open $test_file: $!"); 10738 } 10739 10740 my $config = { 10741 PidFile => $pid_file, 10742 ScoreboardFile => $scoreboard_file, 10743 SystemLog => $log_file, 10744 TraceLog => $log_file, 10745 Trace => 'sql:20 command:20 netio:20', 10746 10747 AuthUserFile => $auth_user_file, 10748 AuthGroupFile => $auth_group_file, 10749 10750 IfModules => { 10751 'mod_delay.c' => { 10752 DelayEngine => 'off', 10753 }, 10754 10755 'mod_sql.c' => { 10756 SQLEngine => 'log', 10757 SQLBackend => 'sqlite3', 10758 SQLConnectInfo => $db_file, 10759 SQLLogFile => $log_file, 10760 SQLNamedQuery => 'xfer_status FREEFORM "INSERT INTO ftpsessions (user, ip_addr, xfer_status, xfer_path) VALUES (\'%u\', \'%L\', \'%{transfer-status}\', \'%f\')"', 10761 SQLLog => 'ERR_RETR,RETR xfer_status', 10762 }, 10763 }, 10764 }; 10765 10766 my ($port, $config_user, $config_group) = config_write($config_file, $config); 10767 10768 # Open pipes, for use between the parent and child processes. Specifically, 10769 # the child will indicate when it's done with its test by writing a message 10770 # to the parent. 10771 my ($rfh, $wfh); 10772 unless (pipe($rfh, $wfh)) { 10773 die("Can't open pipe: $!"); 10774 } 10775 10776 my $ex; 10777 10778 # Fork child 10779 $self->handle_sigchld(); 10780 defined(my $pid = fork()) or die("Can't fork: $!"); 10781 if ($pid) { 10782 eval { 10783 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 10784 $client->login($user, $passwd); 10785 10786 my $conn = $client->retr_raw('test.txt'); 10787 unless ($conn) { 10788 die("RETR test.txt failed: " . $client->response_code() . " " . 10789 $client->response_msg()); 10790 } 10791 10792 my $buf; 10793 $conn->read($buf, 4, 25); 10794 eval { $conn->abort() }; 10795 10796 my $resp_code = $client->response_code(); 10797 my $resp_msg = $client->response_msg(); 10798 10799 $self->assert_transfer_ok($resp_code, $resp_msg, 1); 10800 10801 $client->quit(); 10802 }; 10803 10804 if ($@) { 10805 $ex = $@; 10806 } 10807 10808 $wfh->print("done\n"); 10809 $wfh->flush(); 10810 10811 } else { 10812 eval { server_wait($config_file, $rfh) }; 10813 if ($@) { 10814 warn($@); 10815 exit 1; 10816 } 10817 10818 exit 0; 10819 } 10820 10821 # Stop server 10822 server_stop($pid_file); 10823 10824 $self->assert_child_ok($pid); 10825 10826 if ($ex) { 10827 test_append_logfile($log_file, $ex); 10828 unlink($log_file); 10829 10830 die($ex); 10831 } 10832 10833 my ($login, $ip_addr, $xfer_status, $xfer_path) = get_xfer_status($db_file, "user = \'$user\'"); 10834 10835 my $expected; 10836 10837 $expected = $user; 10838 $self->assert($expected eq $login, 10839 test_msg("Expected user '$expected', got '$login'")); 10840 10841 $expected = '127.0.0.1'; 10842 $self->assert($expected eq $ip_addr, 10843 test_msg("Expected IP address '$expected', got '$ip_addr'")); 10844 10845 $expected = 'cancelled'; 10846 $self->assert($expected eq $xfer_status, 10847 test_msg("Expected transfer status '$expected', got '$xfer_status'")); 10848 10849 if ($^O eq 'darwin') { 10850 # MacOSX-specific hack 10851 $test_file = '/private' . $test_file; 10852 } 10853 10854 $expected = $test_file; 10855 $self->assert($expected eq $xfer_path, 10856 test_msg("Expected file path '$expected', got '$xfer_path'")); 10857 10858 unlink($log_file); 10859} 10860 10861sub sql_sqllog_var_xfer_status_failed { 10862 my $self = shift; 10863 my $tmpdir = $self->{tmpdir}; 10864 10865 my $config_file = "$tmpdir/sqlite.conf"; 10866 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 10867 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 10868 10869 my $log_file = test_get_logfile(); 10870 10871 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 10872 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 10873 10874 my $user = 'proftpd'; 10875 my $passwd = 'test'; 10876 my $group = 'ftpd'; 10877 my $home_dir = File::Spec->rel2abs($tmpdir); 10878 my $uid = 500; 10879 my $gid = 500; 10880 10881 # Make sure that, if we're running as root, that the home directory has 10882 # permissions/privs set for the account we create 10883 if ($< == 0) { 10884 unless (chmod(0755, $home_dir)) { 10885 die("Can't set perms on $home_dir to 0755: $!"); 10886 } 10887 10888 unless (chown($uid, $gid, $home_dir)) { 10889 die("Can't set owner of $home_dir to $uid/$gid: $!"); 10890 } 10891 } 10892 10893 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 10894 '/bin/bash'); 10895 auth_group_write($auth_group_file, $group, $gid, $user); 10896 10897 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 10898 10899 # Build up sqlite3 command to create users, groups tables and populate them 10900 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 10901 10902 if (open(my $fh, "> $db_script")) { 10903 print $fh <<EOS; 10904CREATE TABLE ftpsessions ( 10905 user TEXT, 10906 ip_addr TEXT, 10907 xfer_status TEXT, 10908 xfer_path TEXT 10909); 10910EOS 10911 10912 unless (close($fh)) { 10913 die("Can't write $db_script: $!"); 10914 } 10915 10916 } else { 10917 die("Can't open $db_script: $!"); 10918 } 10919 10920 my $cmd = "sqlite3 $db_file < $db_script"; 10921 build_db($cmd, $db_script); 10922 10923 # Make sure that, if we're running as root, the database file has 10924 # the permissions/privs set for use by proftpd 10925 if ($< == 0) { 10926 unless (chmod(0666, $db_file)) { 10927 die("Can't set perms on $db_file to 0666: $!"); 10928 } 10929 } 10930 10931 my $test_file = File::Spec->rel2abs("$tmpdir/test.txt"); 10932 if (open(my $fh, "> $test_file")) { 10933 print $fh "ABCDefgh" x 32768; 10934 10935 unless (close($fh)) { 10936 die("Can't write $test_file: $!"); 10937 } 10938 10939 } else { 10940 die("Can't open $test_file: $!"); 10941 } 10942 10943 my $config = { 10944 PidFile => $pid_file, 10945 ScoreboardFile => $scoreboard_file, 10946 SystemLog => $log_file, 10947 TraceLog => $log_file, 10948 Trace => 'sql:20 command:20 netio:20', 10949 10950 AuthUserFile => $auth_user_file, 10951 AuthGroupFile => $auth_group_file, 10952 10953 # This is used to tickle the "failed" transfer status 10954 MaxRetrieveFileSize => '12 B', 10955 10956 IfModules => { 10957 'mod_delay.c' => { 10958 DelayEngine => 'off', 10959 }, 10960 10961 'mod_sql.c' => { 10962 SQLEngine => 'log', 10963 SQLBackend => 'sqlite3', 10964 SQLConnectInfo => $db_file, 10965 SQLLogFile => $log_file, 10966 SQLNamedQuery => 'xfer_status FREEFORM "INSERT INTO ftpsessions (user, ip_addr, xfer_status, xfer_path) VALUES (\'%u\', \'%L\', \'%{transfer-status}\', \'%f\')"', 10967 SQLLog => 'ERR_RETR,RETR xfer_status', 10968 }, 10969 }, 10970 }; 10971 10972 my ($port, $config_user, $config_group) = config_write($config_file, $config); 10973 10974 # Open pipes, for use between the parent and child processes. Specifically, 10975 # the child will indicate when it's done with its test by writing a message 10976 # to the parent. 10977 my ($rfh, $wfh); 10978 unless (pipe($rfh, $wfh)) { 10979 die("Can't open pipe: $!"); 10980 } 10981 10982 my $ex; 10983 10984 # Fork child 10985 $self->handle_sigchld(); 10986 defined(my $pid = fork()) or die("Can't fork: $!"); 10987 if ($pid) { 10988 eval { 10989 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 10990 $client->login($user, $passwd); 10991 10992 my $conn = $client->retr_raw('test.txt'); 10993 unless ($conn) { 10994 die("RETR test.txt failed: " . $client->response_code() . " " . 10995 $client->response_msg()); 10996 } 10997 10998 my $buf; 10999 $conn->read($buf, 4, 25); 11000 eval { $conn->close() }; 11001 11002 # Make the control connection go away uncleanly 11003 $client->quit(); 11004 }; 11005 11006 if ($@) { 11007 $ex = $@; 11008 } 11009 11010 $wfh->print("done\n"); 11011 $wfh->flush(); 11012 11013 } else { 11014 eval { server_wait($config_file, $rfh) }; 11015 if ($@) { 11016 warn($@); 11017 exit 1; 11018 } 11019 11020 exit 0; 11021 } 11022 11023 # Stop server 11024 server_stop($pid_file); 11025 11026 $self->assert_child_ok($pid); 11027 11028 if ($ex) { 11029 test_append_logfile($log_file, $ex); 11030 unlink($log_file); 11031 11032 die($ex); 11033 } 11034 11035 my ($login, $ip_addr, $xfer_status, $xfer_path) = get_xfer_status($db_file, "user = \'$user\'"); 11036 11037 my $expected; 11038 11039 $expected = $user; 11040 $self->assert($expected eq $login, 11041 test_msg("Expected user '$expected', got '$login'")); 11042 11043 $expected = '127.0.0.1'; 11044 $self->assert($expected eq $ip_addr, 11045 test_msg("Expected IP address '$expected', got '$ip_addr'")); 11046 11047 $expected = 'failed'; 11048 $self->assert($expected eq $xfer_status, 11049 test_msg("Expected transfer status '$expected', got '$xfer_status'")); 11050 11051 if ($^O eq 'darwin') { 11052 # MacOSX-specific hack 11053 $test_file = '/private' . $test_file; 11054 } 11055 11056 $expected = $test_file; 11057 $self->assert($expected eq $xfer_path, 11058 test_msg("Expected file path '$expected', got '$xfer_path'")); 11059 11060 unlink($log_file); 11061} 11062 11063sub sql_sqllog_var_xfer_status_timeout { 11064 my $self = shift; 11065 my $tmpdir = $self->{tmpdir}; 11066 11067 my $config_file = "$tmpdir/sqlite.conf"; 11068 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 11069 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 11070 11071 my $log_file = test_get_logfile(); 11072 11073 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 11074 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 11075 11076 my $user = 'proftpd'; 11077 my $passwd = 'test'; 11078 my $group = 'ftpd'; 11079 my $home_dir = File::Spec->rel2abs($tmpdir); 11080 my $uid = 500; 11081 my $gid = 500; 11082 11083 # Make sure that, if we're running as root, that the home directory has 11084 # permissions/privs set for the account we create 11085 if ($< == 0) { 11086 unless (chmod(0755, $home_dir)) { 11087 die("Can't set perms on $home_dir to 0755: $!"); 11088 } 11089 11090 unless (chown($uid, $gid, $home_dir)) { 11091 die("Can't set owner of $home_dir to $uid/$gid: $!"); 11092 } 11093 } 11094 11095 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 11096 '/bin/bash'); 11097 auth_group_write($auth_group_file, $group, $gid, $user); 11098 11099 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 11100 11101 # Build up sqlite3 command to create users, groups tables and populate them 11102 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 11103 11104 if (open(my $fh, "> $db_script")) { 11105 print $fh <<EOS; 11106CREATE TABLE ftpsessions ( 11107 user TEXT, 11108 ip_addr TEXT, 11109 xfer_status TEXT, 11110 xfer_path TEXT 11111); 11112EOS 11113 11114 unless (close($fh)) { 11115 die("Can't write $db_script: $!"); 11116 } 11117 11118 } else { 11119 die("Can't open $db_script: $!"); 11120 } 11121 11122 my $cmd = "sqlite3 $db_file < $db_script"; 11123 build_db($cmd, $db_script); 11124 11125 # Make sure that, if we're running as root, the database file has 11126 # the permissions/privs set for use by proftpd 11127 if ($< == 0) { 11128 unless (chmod(0666, $db_file)) { 11129 die("Can't set perms on $db_file to 0666: $!"); 11130 } 11131 } 11132 11133 my $test_file = File::Spec->rel2abs("$tmpdir/test.txt"); 11134 if (open(my $fh, "> $test_file")) { 11135 print $fh "ABCDefgh" x 32768; 11136 11137 unless (close($fh)) { 11138 die("Can't write $test_file: $!"); 11139 } 11140 11141 } else { 11142 die("Can't open $test_file: $!"); 11143 } 11144 11145 my $timeout_stalled = 1; 11146 11147 my $config = { 11148 PidFile => $pid_file, 11149 ScoreboardFile => $scoreboard_file, 11150 SystemLog => $log_file, 11151 TraceLog => $log_file, 11152 Trace => 'sql:20 command:20 netio:20', 11153 11154 AuthUserFile => $auth_user_file, 11155 AuthGroupFile => $auth_group_file, 11156 11157 # This is used to tickle the "timeout" transfer status 11158 TimeoutStalled => $timeout_stalled, 11159 11160 IfModules => { 11161 'mod_delay.c' => { 11162 DelayEngine => 'off', 11163 }, 11164 11165 'mod_sql.c' => { 11166 SQLEngine => 'log', 11167 SQLBackend => 'sqlite3', 11168 SQLConnectInfo => $db_file, 11169 SQLLogFile => $log_file, 11170 SQLNamedQuery => 'xfer_status FREEFORM "INSERT INTO ftpsessions (user, ip_addr, xfer_status, xfer_path) VALUES (\'%u\', \'%L\', \'%{transfer-status}\', \'%f\')"', 11171 SQLLog => 'ERR_RETR,RETR,EXIT xfer_status', 11172 }, 11173 }, 11174 }; 11175 11176 my ($port, $config_user, $config_group) = config_write($config_file, $config); 11177 11178 # Open pipes, for use between the parent and child processes. Specifically, 11179 # the child will indicate when it's done with its test by writing a message 11180 # to the parent. 11181 my ($rfh, $wfh); 11182 unless (pipe($rfh, $wfh)) { 11183 die("Can't open pipe: $!"); 11184 } 11185 11186 my $ex; 11187 11188 # Fork child 11189 $self->handle_sigchld(); 11190 defined(my $pid = fork()) or die("Can't fork: $!"); 11191 if ($pid) { 11192 eval { 11193 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 11194 $client->login($user, $passwd); 11195 $client->type('ascii'); 11196 11197 my $conn = $client->retr_raw('test.txt'); 11198 unless ($conn) { 11199 die("RETR test.xt failed: " . $client->response_code() . " " . 11200 $client->response_msg()); 11201 } 11202 11203 sleep($timeout_stalled + 1); 11204 11205 my $buf; 11206 $conn->read($buf, 32, 25); 11207 sleep($timeout_stalled); 11208 eval { $conn->close() }; 11209 11210 eval { $client->noop() }; 11211 unless ($@) { 11212 die("NOOP succeeded unexpectedly"); 11213 } 11214 11215 my $resp_code = $client->response_code(); 11216 my $resp_msg = $client->response_msg(); 11217 11218 my $expected; 11219 11220 # Perl's Net::Cmd module uses a very non-standard 599 code to 11221 # indicate that the connection is closed 11222 $expected = 599; 11223 $self->assert($expected == $resp_code, 11224 test_msg("Expected $expected, got $resp_code")); 11225 11226 $expected = "Connection closed"; 11227 $self->assert($expected eq $resp_msg, 11228 test_msg("Expected '$expected', got '$resp_msg'")); 11229 }; 11230 11231 if ($@) { 11232 $ex = $@; 11233 } 11234 11235 $wfh->print("done\n"); 11236 $wfh->flush(); 11237 11238 } else { 11239 eval { server_wait($config_file, $rfh) }; 11240 if ($@) { 11241 warn($@); 11242 exit 1; 11243 } 11244 11245 exit 0; 11246 } 11247 11248 # Stop server 11249 server_stop($pid_file); 11250 11251 $self->assert_child_ok($pid); 11252 11253 if ($ex) { 11254 test_append_logfile($log_file, $ex); 11255 unlink($log_file); 11256 11257 die($ex); 11258 } 11259 11260 my ($login, $ip_addr, $xfer_status, $xfer_path) = get_xfer_status($db_file, "user = \'$user\'"); 11261 11262 my $expected; 11263 11264 $expected = $user; 11265 $self->assert($expected eq $login, 11266 test_msg("Expected user '$expected', got '$login'")); 11267 11268 $expected = '127.0.0.1'; 11269 $self->assert($expected eq $ip_addr, 11270 test_msg("Expected IP address '$expected', got '$ip_addr'")); 11271 11272 $expected = '^(timeout|failed)$'; 11273 $self->assert(qr/$expected/, $xfer_status, 11274 test_msg("Expected transfer status '$expected', got '$xfer_status'")); 11275 11276 if ($xfer_status eq 'timeout') { 11277 if ($^O eq 'darwin') { 11278 # MacOSX-specific hack 11279 $test_file = '/private' . $test_file; 11280 } 11281 11282 $expected = $test_file; 11283 $self->assert($expected eq $xfer_path, 11284 test_msg("Expected file path '$expected', got '$xfer_path'")); 11285 } 11286 11287 unlink($log_file); 11288} 11289 11290sub sql_sqllog_var_xfer_status_filtered { 11291 my $self = shift; 11292 my $tmpdir = $self->{tmpdir}; 11293 11294 my $config_file = "$tmpdir/sqlite.conf"; 11295 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 11296 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 11297 11298 my $log_file = test_get_logfile(); 11299 11300 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 11301 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 11302 11303 my $user = 'proftpd'; 11304 my $passwd = 'test'; 11305 my $group = 'ftpd'; 11306 my $home_dir = File::Spec->rel2abs($tmpdir); 11307 my $uid = 500; 11308 my $gid = 500; 11309 11310 # Make sure that, if we're running as root, that the home directory has 11311 # permissions/privs set for the account we create 11312 if ($< == 0) { 11313 unless (chmod(0755, $home_dir)) { 11314 die("Can't set perms on $home_dir to 0755: $!"); 11315 } 11316 11317 unless (chown($uid, $gid, $home_dir)) { 11318 die("Can't set owner of $home_dir to $uid/$gid: $!"); 11319 } 11320 } 11321 11322 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 11323 '/bin/bash'); 11324 auth_group_write($auth_group_file, $group, $gid, $user); 11325 11326 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 11327 11328 # Build up sqlite3 command to create users, groups tables and populate them 11329 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 11330 11331 if (open(my $fh, "> $db_script")) { 11332 print $fh <<EOS; 11333CREATE TABLE ftpsessions ( 11334 user TEXT, 11335 ip_addr TEXT, 11336 xfer_status TEXT, 11337 xfer_path TEXT 11338); 11339EOS 11340 11341 unless (close($fh)) { 11342 die("Can't write $db_script: $!"); 11343 } 11344 11345 } else { 11346 die("Can't open $db_script: $!"); 11347 } 11348 11349 my $cmd = "sqlite3 $db_file < $db_script"; 11350 build_db($cmd, $db_script); 11351 11352 # Make sure that, if we're running as root, the database file has 11353 # the permissions/privs set for use by proftpd 11354 if ($< == 0) { 11355 unless (chmod(0666, $db_file)) { 11356 die("Can't set perms on $db_file to 0666: $!"); 11357 } 11358 } 11359 11360 my $test_file = File::Spec->rel2abs("$tmpdir/test.txt"); 11361 if (open(my $fh, "> $test_file")) { 11362 print $fh "ABCDefgh" x 32768; 11363 11364 unless (close($fh)) { 11365 die("Can't write $test_file: $!"); 11366 } 11367 11368 } else { 11369 die("Can't open $test_file: $!"); 11370 } 11371 11372 my $config = { 11373 PidFile => $pid_file, 11374 ScoreboardFile => $scoreboard_file, 11375 SystemLog => $log_file, 11376 TraceLog => $log_file, 11377 Trace => 'sql:20 command:20 netio:20', 11378 11379 AuthUserFile => $auth_user_file, 11380 AuthGroupFile => $auth_group_file, 11381 11382 PathDenyFilter => '^.*\.csv$', 11383 11384 IfModules => { 11385 'mod_delay.c' => { 11386 DelayEngine => 'off', 11387 }, 11388 11389 'mod_sql.c' => { 11390 SQLEngine => 'log', 11391 SQLBackend => 'sqlite3', 11392 SQLConnectInfo => $db_file, 11393 SQLLogFile => $log_file, 11394 SQLNamedQuery => 'xfer_status FREEFORM "INSERT INTO ftpsessions (user, ip_addr, xfer_status, xfer_path) VALUES (\'%u\', \'%L\', \'%{transfer-status}\', \'%f\')"', 11395 SQLLog => 'ERR_STOR,STOR,EXIT xfer_status', 11396 }, 11397 }, 11398 }; 11399 11400 my ($port, $config_user, $config_group) = config_write($config_file, $config); 11401 11402 # Open pipes, for use between the parent and child processes. Specifically, 11403 # the child will indicate when it's done with its test by writing a message 11404 # to the parent. 11405 my ($rfh, $wfh); 11406 unless (pipe($rfh, $wfh)) { 11407 die("Can't open pipe: $!"); 11408 } 11409 11410 my $ex; 11411 11412 # Fork child 11413 $self->handle_sigchld(); 11414 defined(my $pid = fork()) or die("Can't fork: $!"); 11415 if ($pid) { 11416 eval { 11417 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 11418 $client->login($user, $passwd); 11419 $client->type('ascii'); 11420 11421 my $conn = $client->stor_raw('test.csv'); 11422 if ($conn) { 11423 die("RETR test.csv succeeded unexpectedly"); 11424 } 11425 11426 my $resp_code = $client->response_code(); 11427 my $resp_msg = $client->response_msg(); 11428 $client->quit(); 11429 11430 my $expected = 550; 11431 $self->assert($expected == $resp_code, 11432 "Expected response code $expected, got $resp_code"); 11433 11434 $expected = "test.csv: Forbidden filename"; 11435 $self->assert($expected eq $resp_msg, 11436 "Expected '$expected', got '$resp_msg'"); 11437 }; 11438 11439 if ($@) { 11440 $ex = $@; 11441 } 11442 11443 $wfh->print("done\n"); 11444 $wfh->flush(); 11445 11446 } else { 11447 eval { server_wait($config_file, $rfh) }; 11448 if ($@) { 11449 warn($@); 11450 exit 1; 11451 } 11452 11453 exit 0; 11454 } 11455 11456 # Stop server 11457 server_stop($pid_file); 11458 11459 $self->assert_child_ok($pid); 11460 11461 if ($ex) { 11462 test_append_logfile($log_file, $ex); 11463 unlink($log_file); 11464 11465 die($ex); 11466 } 11467 11468 my ($login, $ip_addr, $xfer_status, $xfer_path) = get_xfer_status($db_file, "user = \'$user\'"); 11469 11470 my $expected; 11471 11472 $expected = $user; 11473 $self->assert($expected eq $login, 11474 test_msg("Expected user '$expected', got '$login'")); 11475 11476 $expected = '127.0.0.1'; 11477 $self->assert($expected eq $ip_addr, 11478 test_msg("Expected IP address '$expected', got '$ip_addr'")); 11479 11480 $expected = '^(timeout|failed)$'; 11481 $self->assert(qr/$expected/, $xfer_status, 11482 test_msg("Expected transfer status '$expected', got '$xfer_status'")); 11483 11484 if ($xfer_status eq 'timeout') { 11485 if ($^O eq 'darwin') { 11486 # MacOSX-specific hack 11487 $test_file = '/private' . $test_file; 11488 } 11489 11490 $expected = $test_file; 11491 $self->assert($expected eq $xfer_path, 11492 test_msg("Expected file path '$expected', got '$xfer_path'")); 11493 } 11494 11495 unlink($log_file); 11496} 11497 11498sub get_xfer_failure { 11499 my $db_file = shift; 11500 my $where = shift; 11501 11502 my $sql = "SELECT user, ip_addr, xfer_status, xfer_failure, xfer_path FROM ftpsessions"; 11503 if ($where) { 11504 $sql .= " WHERE $where"; 11505 } 11506 $sql .= " LIMIT 1"; 11507 11508 my $cmd = "sqlite3 $db_file \"$sql\""; 11509 11510 if ($ENV{TEST_VERBOSE}) { 11511 print STDERR "Executing sqlite3: $cmd\n"; 11512 } 11513 11514 my $res = join('', `$cmd`); 11515 chomp($res); 11516 11517 # The default sqlite3 delimiter is '|' 11518 return split(/\|/, $res); 11519} 11520 11521sub sql_sqllog_var_xfer_failure_none { 11522 my $self = shift; 11523 my $tmpdir = $self->{tmpdir}; 11524 11525 my $config_file = "$tmpdir/sqlite.conf"; 11526 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 11527 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 11528 11529 my $log_file = test_get_logfile(); 11530 11531 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 11532 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 11533 11534 my $user = 'proftpd'; 11535 my $passwd = 'test'; 11536 my $group = 'ftpd'; 11537 my $home_dir = File::Spec->rel2abs($tmpdir); 11538 my $uid = 500; 11539 my $gid = 500; 11540 11541 # Make sure that, if we're running as root, that the home directory has 11542 # permissions/privs set for the account we create 11543 if ($< == 0) { 11544 unless (chmod(0755, $home_dir)) { 11545 die("Can't set perms on $home_dir to 0755: $!"); 11546 } 11547 11548 unless (chown($uid, $gid, $home_dir)) { 11549 die("Can't set owner of $home_dir to $uid/$gid: $!"); 11550 } 11551 } 11552 11553 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 11554 '/bin/bash'); 11555 auth_group_write($auth_group_file, $group, $gid, $user); 11556 11557 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 11558 11559 # Build up sqlite3 command to create users, groups tables and populate them 11560 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 11561 11562 if (open(my $fh, "> $db_script")) { 11563 print $fh <<EOS; 11564CREATE TABLE ftpsessions ( 11565 user TEXT, 11566 ip_addr TEXT, 11567 xfer_status TEXT, 11568 xfer_failure TEXT, 11569 xfer_path TEXT 11570); 11571EOS 11572 11573 unless (close($fh)) { 11574 die("Can't write $db_script: $!"); 11575 } 11576 11577 } else { 11578 die("Can't open $db_script: $!"); 11579 } 11580 11581 my $cmd = "sqlite3 $db_file < $db_script"; 11582 build_db($cmd, $db_script); 11583 11584 # Make sure that, if we're running as root, the database file has 11585 # the permissions/privs set for use by proftpd 11586 if ($< == 0) { 11587 unless (chmod(0666, $db_file)) { 11588 die("Can't set perms on $db_file to 0666: $!"); 11589 } 11590 } 11591 11592 my $test_file = File::Spec->rel2abs("$tmpdir/test.txt"); 11593 if (open(my $fh, "> $test_file")) { 11594 close($fh); 11595 11596 } else { 11597 die("Can't open $test_file: $!"); 11598 } 11599 11600 my $config = { 11601 PidFile => $pid_file, 11602 ScoreboardFile => $scoreboard_file, 11603 SystemLog => $log_file, 11604 TraceLog => $log_file, 11605 Trace => 'sql:20 command:20 netio:20', 11606 11607 AuthUserFile => $auth_user_file, 11608 AuthGroupFile => $auth_group_file, 11609 11610 IfModules => { 11611 'mod_delay.c' => { 11612 DelayEngine => 'off', 11613 }, 11614 11615 'mod_sql.c' => { 11616 SQLEngine => 'log', 11617 SQLBackend => 'sqlite3', 11618 SQLConnectInfo => $db_file, 11619 SQLLogFile => $log_file, 11620 SQLNamedQuery => 'xfer_reason FREEFORM "INSERT INTO ftpsessions (user, ip_addr, xfer_status, xfer_failure, xfer_path) VALUES (\'%u\', \'%L\', \'%{transfer-status}\', \'%{transfer-failure}\', \'%f\')"', 11621 SQLLog => 'ERR_RETR,RETR xfer_reason', 11622 }, 11623 }, 11624 }; 11625 11626 my ($port, $config_user, $config_group) = config_write($config_file, $config); 11627 11628 # Open pipes, for use between the parent and child processes. Specifically, 11629 # the child will indicate when it's done with its test by writing a message 11630 # to the parent. 11631 my ($rfh, $wfh); 11632 unless (pipe($rfh, $wfh)) { 11633 die("Can't open pipe: $!"); 11634 } 11635 11636 my $ex; 11637 11638 # Fork child 11639 $self->handle_sigchld(); 11640 defined(my $pid = fork()) or die("Can't fork: $!"); 11641 if ($pid) { 11642 eval { 11643 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 11644 $client->login($user, $passwd); 11645 11646 my $conn = $client->retr_raw('test.txt'); 11647 unless ($conn) { 11648 die("RETR test.txt failed: " . $client->response_code() . " " . 11649 $client->response_msg()); 11650 } 11651 11652 my $buf; 11653 $conn->read($buf, 8192, 25); 11654 eval { $conn->close() }; 11655 11656 my $resp_code = $client->response_code(); 11657 my $resp_msg = $client->response_msg(); 11658 11659 $self->assert_transfer_ok($resp_code, $resp_msg); 11660 11661 $client->quit(); 11662 }; 11663 11664 if ($@) { 11665 $ex = $@; 11666 } 11667 11668 $wfh->print("done\n"); 11669 $wfh->flush(); 11670 11671 } else { 11672 eval { server_wait($config_file, $rfh) }; 11673 if ($@) { 11674 warn($@); 11675 exit 1; 11676 } 11677 11678 exit 0; 11679 } 11680 11681 # Stop server 11682 server_stop($pid_file); 11683 11684 $self->assert_child_ok($pid); 11685 11686 if ($ex) { 11687 test_append_logfile($log_file, $ex); 11688 unlink($log_file); 11689 11690 die($ex); 11691 } 11692 11693 my ($login, $ip_addr, $xfer_status, $xfer_failure, $xfer_path) = get_xfer_failure($db_file, "user = \'$user\'"); 11694 11695 my $expected; 11696 11697 $expected = $user; 11698 $self->assert($expected eq $login, 11699 test_msg("Expected user '$expected', got '$login'")); 11700 11701 $expected = '127.0.0.1'; 11702 $self->assert($expected eq $ip_addr, 11703 test_msg("Expected IP address '$expected', got '$ip_addr'")); 11704 11705 $expected = 'success'; 11706 $self->assert($expected eq $xfer_status, 11707 test_msg("Expected transfer status '$expected', got '$xfer_status'")); 11708 11709 $expected = '-'; 11710 $self->assert($expected eq $xfer_failure, 11711 test_msg("Expected transfer failure '$expected', got '$xfer_failure'")); 11712 11713 if ($^O eq 'darwin') { 11714 # MacOSX-specific hack 11715 $test_file = '/private' . $test_file; 11716 } 11717 11718 $expected = $test_file; 11719 $self->assert($expected eq $xfer_path, 11720 test_msg("Expected file path '$expected', got '$xfer_path'")); 11721 11722 unlink($log_file); 11723} 11724 11725sub sql_sqllog_var_xfer_failure_reason { 11726 my $self = shift; 11727 my $tmpdir = $self->{tmpdir}; 11728 11729 my $config_file = "$tmpdir/sqlite.conf"; 11730 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 11731 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 11732 11733 my $log_file = test_get_logfile(); 11734 11735 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 11736 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 11737 11738 my $user = 'proftpd'; 11739 my $passwd = 'test'; 11740 my $group = 'ftpd'; 11741 my $home_dir = File::Spec->rel2abs($tmpdir); 11742 my $uid = 500; 11743 my $gid = 500; 11744 11745 # Make sure that, if we're running as root, that the home directory has 11746 # permissions/privs set for the account we create 11747 if ($< == 0) { 11748 unless (chmod(0755, $home_dir)) { 11749 die("Can't set perms on $home_dir to 0755: $!"); 11750 } 11751 11752 unless (chown($uid, $gid, $home_dir)) { 11753 die("Can't set owner of $home_dir to $uid/$gid: $!"); 11754 } 11755 } 11756 11757 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 11758 '/bin/bash'); 11759 auth_group_write($auth_group_file, $group, $gid, $user); 11760 11761 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 11762 11763 # Build up sqlite3 command to create users, groups tables and populate them 11764 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 11765 11766 if (open(my $fh, "> $db_script")) { 11767 print $fh <<EOS; 11768CREATE TABLE ftpsessions ( 11769 user TEXT, 11770 ip_addr TEXT, 11771 xfer_status TEXT, 11772 xfer_failure TEXT, 11773 xfer_path TEXT 11774); 11775EOS 11776 11777 unless (close($fh)) { 11778 die("Can't write $db_script: $!"); 11779 } 11780 11781 } else { 11782 die("Can't open $db_script: $!"); 11783 } 11784 11785 my $cmd = "sqlite3 $db_file < $db_script"; 11786 build_db($cmd, $db_script); 11787 11788 # Make sure that, if we're running as root, the database file has 11789 # the permissions/privs set for use by proftpd 11790 if ($< == 0) { 11791 unless (chmod(0666, $db_file)) { 11792 die("Can't set perms on $db_file to 0666: $!"); 11793 } 11794 } 11795 11796 my $test_file = File::Spec->rel2abs("$tmpdir/test.txt"); 11797 if (open(my $fh, "> $test_file")) { 11798 print $fh "ABCD" x 1024; 11799 close($fh); 11800 11801 } else { 11802 die("Can't open $test_file: $!"); 11803 } 11804 11805 my $config = { 11806 PidFile => $pid_file, 11807 ScoreboardFile => $scoreboard_file, 11808 SystemLog => $log_file, 11809 TraceLog => $log_file, 11810 Trace => 'sql:20 command:20 netio:20', 11811 11812 AuthUserFile => $auth_user_file, 11813 AuthGroupFile => $auth_group_file, 11814 11815 # This is used to tickle the "failed" transfer status 11816 MaxRetrieveFileSize => '12 B', 11817 11818 IfModules => { 11819 'mod_delay.c' => { 11820 DelayEngine => 'off', 11821 }, 11822 11823 'mod_sql.c' => { 11824 SQLEngine => 'log', 11825 SQLBackend => 'sqlite3', 11826 SQLConnectInfo => $db_file, 11827 SQLLogFile => $log_file, 11828 SQLNamedQuery => 'xfer_reason FREEFORM "INSERT INTO ftpsessions (user, ip_addr, xfer_status, xfer_failure, xfer_path) VALUES (\'%u\', \'%L\', \'%{transfer-status}\', \'%{transfer-failure}\', \'%f\')"', 11829 SQLLog => 'ERR_RETR,RETR xfer_reason', 11830 }, 11831 }, 11832 }; 11833 11834 my ($port, $config_user, $config_group) = config_write($config_file, $config); 11835 11836 # Open pipes, for use between the parent and child processes. Specifically, 11837 # the child will indicate when it's done with its test by writing a message 11838 # to the parent. 11839 my ($rfh, $wfh); 11840 unless (pipe($rfh, $wfh)) { 11841 die("Can't open pipe: $!"); 11842 } 11843 11844 my $ex; 11845 11846 # Fork child 11847 $self->handle_sigchld(); 11848 defined(my $pid = fork()) or die("Can't fork: $!"); 11849 if ($pid) { 11850 eval { 11851 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 11852 $client->login($user, $passwd); 11853 11854 my $conn = $client->retr_raw('test.txt'); 11855 unless ($conn) { 11856 die("RETR test.txt failed: " . $client->response_code() . " " . 11857 $client->response_msg()); 11858 } 11859 11860 my $buf; 11861 $conn->read($buf, 8192, 25); 11862 eval { $conn->close() }; 11863 11864 my $resp_code = $client->response_code(); 11865 my $resp_msg = $client->response_msg(); 11866 11867 my $expected = 426; 11868 $self->assert($expected == $resp_code, 11869 test_msg("Expected response code $expected, got $resp_code")); 11870 11871 $expected = 'Transfer aborted'; 11872 $self->assert(qr/$expected/, $resp_msg, 11873 test_msg("Expected response message '$expected', got '$resp_msg'")); 11874 11875 $client->quit(); 11876 }; 11877 11878 if ($@) { 11879 $ex = $@; 11880 } 11881 11882 $wfh->print("done\n"); 11883 $wfh->flush(); 11884 11885 } else { 11886 eval { server_wait($config_file, $rfh) }; 11887 if ($@) { 11888 warn($@); 11889 exit 1; 11890 } 11891 11892 exit 0; 11893 } 11894 11895 # Stop server 11896 server_stop($pid_file); 11897 11898 $self->assert_child_ok($pid); 11899 11900 if ($ex) { 11901 test_append_logfile($log_file, $ex); 11902 unlink($log_file); 11903 11904 die($ex); 11905 } 11906 11907 my ($login, $ip_addr, $xfer_status, $xfer_failure, $xfer_path) = get_xfer_failure($db_file, "user = \'$user\'"); 11908 11909 my $expected; 11910 11911 $expected = $user; 11912 $self->assert($expected eq $login, 11913 test_msg("Expected user '$expected', got '$login'")); 11914 11915 $expected = '127.0.0.1'; 11916 $self->assert($expected eq $ip_addr, 11917 test_msg("Expected IP address '$expected', got '$ip_addr'")); 11918 11919 $expected = 'failed'; 11920 $self->assert($expected eq $xfer_status, 11921 test_msg("Expected transfer status '$expected', got '$xfer_status'")); 11922 11923 $expected = 'Operation not permitted'; 11924 $self->assert($expected eq $xfer_failure, 11925 test_msg("Expected transfer failure '$expected', got '$xfer_failure'")); 11926 11927 if ($^O eq 'darwin') { 11928 # MacOSX-specific hack 11929 $test_file = '/private' . $test_file; 11930 } 11931 11932 $expected = $test_file; 11933 $self->assert($expected eq $xfer_path, 11934 test_msg("Expected file path '$expected', got '$xfer_path'")); 11935 11936 unlink($log_file); 11937} 11938 11939sub sql_sqlshowinfo_pass_failed_bug3782 { 11940 my $self = shift; 11941 my $tmpdir = $self->{tmpdir}; 11942 my $setup = test_setup($tmpdir, 'sqlite'); 11943 11944 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 11945 11946 # Build up sqlite3 command to create users, groups tables and populate them 11947 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 11948 11949 if (open(my $fh, "> $db_script")) { 11950 print $fh <<EOS; 11951CREATE TABLE users ( 11952 userid TEXT, 11953 passwd TEXT, 11954 uid INTEGER, 11955 gid INTEGER, 11956 homedir TEXT, 11957 shell TEXT, 11958 secure_only INTEGER 11959); 11960INSERT INTO users (userid, passwd, uid, gid, homedir, shell, secure_only) VALUES ('$setup->{user}', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash', 1); 11961 11962CREATE TABLE groups ( 11963 groupname TEXT, 11964 gid INTEGER, 11965 members TEXT 11966); 11967INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); 11968 11969CREATE TABLE login_responses ( 11970 secure_only INTEGER, 11971 response TEXT 11972); 11973 11974INSERT INTO login_responses (secure_only, response) VALUES (0, "Login failed."); 11975INSERT INTO login_responses (secure_only, response) VALUES (1, "You may not log into this account via FTP. Please use SFTP instead."); 11976EOS 11977 11978 unless (close($fh)) { 11979 die("Can't write $db_script: $!"); 11980 } 11981 11982 } else { 11983 die("Can't open $db_script: $!"); 11984 } 11985 11986 my $cmd = "sqlite3 $db_file < $db_script"; 11987 build_db($cmd, $db_script); 11988 11989 # Make sure that, if we're running as root, the database file has 11990 # the permissions/privs set for use by proftpd 11991 if ($< == 0) { 11992 unless (chmod(0666, $db_file)) { 11993 die("Can't set perms on $db_file to 0666: $!"); 11994 } 11995 } 11996 11997 my $config = { 11998 PidFile => $setup->{pid_file}, 11999 ScoreboardFile => $setup->{scoreboard_file}, 12000 SystemLog => $setup->{log_file}, 12001 TraceLog => $setup->{log_file}, 12002 Trace => 'jot:20 response:20 sql:20', 12003 12004 IfModules => { 12005 'mod_delay.c' => { 12006 DelayEngine => 'off', 12007 }, 12008 12009 'mod_sql.c' => [ 12010 'AuthOrder mod_sql.c', 12011 12012 'SQLAuthenticate users groups', 12013 'SQLAuthTypes plaintext', 12014 'SQLBackend sqlite3', 12015 "SQLConnectInfo $db_file", 12016 "SQLLogFile $setup->{log_file}", 12017 'SQLMinID 100', 12018 12019 'SQLUserWhereClause "secure_only != 1"', 12020 'SQLNamedQuery login_failure SELECT "response FROM users u, login_responses lr WHERE u.userid = \'%U\' AND u.secure_only = lr.secure_only"', 12021 12022 # Configure the equivalent of a multiline DisplayLogin file 12023 # using the SQLShowInfo directive 12024 12025 'SQLShowInfo ERR_PASS 530 "Sorry, %U"', 12026 'SQLShowInfo ERR_PASS 530 "%{login_failure}"', 12027 'SQLShowInfo ERR_PASS 530 " "', 12028 ], 12029 }, 12030 }; 12031 12032 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 12033 $config); 12034 12035 # Open pipes, for use between the parent and child processes. Specifically, 12036 # the child will indicate when it's done with its test by writing a message 12037 # to the parent. 12038 my ($rfh, $wfh); 12039 unless (pipe($rfh, $wfh)) { 12040 die("Can't open pipe: $!"); 12041 } 12042 12043 my $ex; 12044 12045 # Fork child 12046 $self->handle_sigchld(); 12047 defined(my $pid = fork()) or die("Can't fork: $!"); 12048 if ($pid) { 12049 eval { 12050 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 12051 eval { $client->login($setup->{user}, $setup->{passwd}) }; 12052 unless ($@) { 12053 die("Login succeeded unexpectedly"); 12054 } 12055 12056 my $resp_msgs = $client->response_msgs(); 12057 my $nmsgs = scalar(@$resp_msgs); 12058 12059 my $expected = 4; 12060 $self->assert($expected == $nmsgs, "Expected $expected, got $nmsgs"); 12061 12062 $expected = "Login incorrect."; 12063 $self->assert($expected eq $resp_msgs->[0], 12064 "Expected response '$expected', got '$resp_msgs->[0]'"); 12065 12066 $expected = " Sorry, $setup->{user}"; 12067 $self->assert($expected eq $resp_msgs->[1], 12068 "Expected response '$expected', got '$resp_msgs->[1]'"); 12069 12070 $expected = " You may not log into this account via FTP. Please use SFTP instead."; 12071 $self->assert($expected eq $resp_msgs->[2], 12072 "Expected response '$expected', got '$resp_msgs->[2]'"); 12073 12074 $client->quit(); 12075 }; 12076 if ($@) { 12077 $ex = $@; 12078 } 12079 12080 $wfh->print("done\n"); 12081 $wfh->flush(); 12082 12083 } else { 12084 eval { server_wait($setup->{config_file}, $rfh) }; 12085 if ($@) { 12086 warn($@); 12087 exit 1; 12088 } 12089 12090 exit 0; 12091 } 12092 12093 # Stop server 12094 server_stop($setup->{pid_file}); 12095 $self->assert_child_ok($pid); 12096 12097 test_cleanup($setup->{log_file}, $ex); 12098} 12099 12100sub sql_sqllog_preauth_var_U_bug3822 { 12101 my $self = shift; 12102 my $tmpdir = $self->{tmpdir}; 12103 12104 my $config_file = "$tmpdir/sqlite.conf"; 12105 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 12106 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 12107 12108 my $log_file = test_get_logfile(); 12109 12110 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 12111 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 12112 12113 my $user = 'proftpd'; 12114 my $passwd = 'test'; 12115 my $group = 'ftpd'; 12116 my $home_dir = File::Spec->rel2abs($tmpdir); 12117 my $uid = 500; 12118 my $gid = 500; 12119 12120 # Make sure that, if we're running as root, that the home directory has 12121 # permissions/privs set for the account we create 12122 if ($< == 0) { 12123 unless (chmod(0755, $home_dir)) { 12124 die("Can't set perms on $home_dir to 0755: $!"); 12125 } 12126 12127 unless (chown($uid, $gid, $home_dir)) { 12128 die("Can't set owner of $home_dir to $uid/$gid: $!"); 12129 } 12130 } 12131 12132 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 12133 '/bin/bash'); 12134 auth_group_write($auth_group_file, $group, $gid, $user); 12135 12136 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 12137 12138 # Build up sqlite3 command to create users, groups tables and populate them 12139 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 12140 12141 if (open(my $fh, "> $db_script")) { 12142 print $fh <<EOS; 12143CREATE TABLE ftpsessions ( 12144 user TEXT, 12145 ip_addr TEXT, 12146 resp_mesg TEXT 12147); 12148EOS 12149 12150 unless (close($fh)) { 12151 die("Can't write $db_script: $!"); 12152 } 12153 12154 } else { 12155 die("Can't open $db_script: $!"); 12156 } 12157 12158 my $cmd = "sqlite3 $db_file < $db_script"; 12159 build_db($cmd, $db_script); 12160 12161 # Make sure that, if we're running as root, the database file has 12162 # the permissions/privs set for use by proftpd 12163 if ($< == 0) { 12164 unless (chmod(0666, $db_file)) { 12165 die("Can't set perms on $db_file to 0666: $!"); 12166 } 12167 } 12168 12169 my $config = { 12170 PidFile => $pid_file, 12171 ScoreboardFile => $scoreboard_file, 12172 SystemLog => $log_file, 12173 12174 AuthUserFile => $auth_user_file, 12175 AuthGroupFile => $auth_group_file, 12176 12177 IfModules => { 12178 'mod_delay.c' => { 12179 DelayEngine => 'off', 12180 }, 12181 12182 'mod_sql.c' => { 12183 SQLEngine => 'log', 12184 SQLBackend => 'sqlite3', 12185 SQLConnectInfo => "$db_file foo bar PERCONNECTION", 12186 SQLLogFile => $log_file, 12187 SQLNamedQuery => 'info FREEFORM "INSERT INTO ftpsessions (user, ip_addr, resp_mesg) VALUES (\'%U\', \'%L\', \'%S\')"', 12188 SQLLog => 'ERR_PWD info', 12189 }, 12190 }, 12191 }; 12192 12193 my ($port, $config_user, $config_group) = config_write($config_file, $config); 12194 12195 # Open pipes, for use between the parent and child processes. Specifically, 12196 # the child will indicate when it's done with its test by writing a message 12197 # to the parent. 12198 my ($rfh, $wfh); 12199 unless (pipe($rfh, $wfh)) { 12200 die("Can't open pipe: $!"); 12201 } 12202 12203 my $ex; 12204 12205 # Fork child 12206 $self->handle_sigchld(); 12207 defined(my $pid = fork()) or die("Can't fork: $!"); 12208 if ($pid) { 12209 eval { 12210 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 12211 eval { $client->pwd() }; 12212 unless ($@) { 12213 die("PWD succeeded unexpectedly"); 12214 } 12215 12216 $client->login($user, $passwd); 12217 $client->quit(); 12218 }; 12219 12220 if ($@) { 12221 $ex = $@; 12222 } 12223 12224 $wfh->print("done\n"); 12225 $wfh->flush(); 12226 12227 } else { 12228 eval { server_wait($config_file, $rfh) }; 12229 if ($@) { 12230 warn($@); 12231 exit 1; 12232 } 12233 12234 exit 0; 12235 } 12236 12237 # Stop server 12238 server_stop($pid_file); 12239 12240 $self->assert_child_ok($pid); 12241 12242 if ($ex) { 12243 test_append_logfile($log_file, $ex); 12244 unlink($log_file); 12245 12246 die($ex); 12247 } 12248 12249 my ($login, $ip_addr, $resp_mesg) = get_resp_mesgs($db_file, 12250 "user = '-'", "user, ip_addr, resp_mesg"); 12251 12252 my $expected; 12253 12254 $expected = '-'; 12255 $self->assert($expected eq $login, 12256 test_msg("Expected '$expected', got '$login'")); 12257 12258 $expected = '127.0.0.1'; 12259 $self->assert($expected eq $ip_addr, 12260 test_msg("Expected '$expected', got '$ip_addr'")); 12261 12262 $expected = 'Please login with USER and PASS'; 12263 $self->assert($expected eq $resp_mesg, 12264 test_msg("Expected '$expected', got '$resp_mesg'")); 12265 12266 unlink($log_file); 12267} 12268 12269sub sql_sqllog_preauth_var_u_bug3822 { 12270 my $self = shift; 12271 my $tmpdir = $self->{tmpdir}; 12272 12273 my $config_file = "$tmpdir/sqlite.conf"; 12274 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 12275 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 12276 12277 my $log_file = test_get_logfile(); 12278 12279 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 12280 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 12281 12282 my $user = 'proftpd'; 12283 my $passwd = 'test'; 12284 my $group = 'ftpd'; 12285 my $home_dir = File::Spec->rel2abs($tmpdir); 12286 my $uid = 500; 12287 my $gid = 500; 12288 12289 # Make sure that, if we're running as root, that the home directory has 12290 # permissions/privs set for the account we create 12291 if ($< == 0) { 12292 unless (chmod(0755, $home_dir)) { 12293 die("Can't set perms on $home_dir to 0755: $!"); 12294 } 12295 12296 unless (chown($uid, $gid, $home_dir)) { 12297 die("Can't set owner of $home_dir to $uid/$gid: $!"); 12298 } 12299 } 12300 12301 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 12302 '/bin/bash'); 12303 auth_group_write($auth_group_file, $group, $gid, $user); 12304 12305 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 12306 12307 # Build up sqlite3 command to create users, groups tables and populate them 12308 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 12309 12310 if (open(my $fh, "> $db_script")) { 12311 print $fh <<EOS; 12312CREATE TABLE ftpsessions ( 12313 user TEXT, 12314 ip_addr TEXT, 12315 resp_mesg TEXT 12316); 12317EOS 12318 12319 unless (close($fh)) { 12320 die("Can't write $db_script: $!"); 12321 } 12322 12323 } else { 12324 die("Can't open $db_script: $!"); 12325 } 12326 12327 my $cmd = "sqlite3 $db_file < $db_script"; 12328 build_db($cmd, $db_script); 12329 12330 # Make sure that, if we're running as root, the database file has 12331 # the permissions/privs set for use by proftpd 12332 if ($< == 0) { 12333 unless (chmod(0666, $db_file)) { 12334 die("Can't set perms on $db_file to 0666: $!"); 12335 } 12336 } 12337 12338 my $config = { 12339 PidFile => $pid_file, 12340 ScoreboardFile => $scoreboard_file, 12341 SystemLog => $log_file, 12342 12343 AuthUserFile => $auth_user_file, 12344 AuthGroupFile => $auth_group_file, 12345 12346 IfModules => { 12347 'mod_delay.c' => { 12348 DelayEngine => 'off', 12349 }, 12350 12351 'mod_sql.c' => { 12352 SQLEngine => 'log', 12353 SQLBackend => 'sqlite3', 12354 SQLConnectInfo => "$db_file foo bar PERCONNECTION", 12355 SQLLogFile => $log_file, 12356 SQLNamedQuery => 'info FREEFORM "INSERT INTO ftpsessions (user, ip_addr, resp_mesg) VALUES (\'%u\', \'%L\', \'%S\')"', 12357 SQLLog => 'ERR_PWD info', 12358 }, 12359 }, 12360 }; 12361 12362 my ($port, $config_user, $config_group) = config_write($config_file, $config); 12363 12364 # Open pipes, for use between the parent and child processes. Specifically, 12365 # the child will indicate when it's done with its test by writing a message 12366 # to the parent. 12367 my ($rfh, $wfh); 12368 unless (pipe($rfh, $wfh)) { 12369 die("Can't open pipe: $!"); 12370 } 12371 12372 my $ex; 12373 12374 # Fork child 12375 $self->handle_sigchld(); 12376 defined(my $pid = fork()) or die("Can't fork: $!"); 12377 if ($pid) { 12378 eval { 12379 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 12380 eval { $client->pwd() }; 12381 unless ($@) { 12382 die("PWD succeeded unexpectedly"); 12383 } 12384 12385 $client->login($user, $passwd); 12386 $client->quit(); 12387 }; 12388 12389 if ($@) { 12390 $ex = $@; 12391 } 12392 12393 $wfh->print("done\n"); 12394 $wfh->flush(); 12395 12396 } else { 12397 eval { server_wait($config_file, $rfh) }; 12398 if ($@) { 12399 warn($@); 12400 exit 1; 12401 } 12402 12403 exit 0; 12404 } 12405 12406 # Stop server 12407 server_stop($pid_file); 12408 12409 $self->assert_child_ok($pid); 12410 12411 if ($ex) { 12412 test_append_logfile($log_file, $ex); 12413 unlink($log_file); 12414 12415 die($ex); 12416 } 12417 12418 my ($login, $ip_addr, $resp_mesg) = get_resp_mesgs($db_file, 12419 "user = '-'", "user, ip_addr, resp_mesg"); 12420 12421 my $expected; 12422 12423 $expected = '-'; 12424 $self->assert($expected eq $login, 12425 test_msg("Expected '$expected', got '$login'")); 12426 12427 $expected = '127.0.0.1'; 12428 $self->assert($expected eq $ip_addr, 12429 test_msg("Expected '$expected', got '$ip_addr'")); 12430 12431 $expected = 'Please login with USER and PASS'; 12432 $self->assert($expected eq $resp_mesg, 12433 test_msg("Expected '$expected', got '$resp_mesg'")); 12434 12435 unlink($log_file); 12436} 12437 12438sub sql_sqlite_maxhostsperuser { 12439 my $self = shift; 12440 my $tmpdir = $self->{tmpdir}; 12441 12442 my $config_file = "$tmpdir/sqlite.conf"; 12443 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 12444 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 12445 12446 my $log_file = test_get_logfile(); 12447 12448 my $user = 'proftpd'; 12449 my $passwd = 'test'; 12450 my $group = 'ftpd'; 12451 my $home_dir = File::Spec->rel2abs($tmpdir); 12452 my $uid = 500; 12453 my $gid = 500; 12454 12455 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 12456 12457 # Build up sqlite3 command to create users, groups tables and populate them 12458 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 12459 12460 if (open(my $fh, "> $db_script")) { 12461 print $fh <<EOS; 12462CREATE TABLE users ( 12463 userid TEXT, 12464 passwd TEXT, 12465 uid INTEGER, 12466 gid INTEGER, 12467 homedir TEXT, 12468 shell TEXT 12469); 12470CREATE INDEX i_users_userid ON users.userid; 12471CREATE INDEX i_users_uid ON users.uid; 12472INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 12473 12474CREATE TABLE groups ( 12475 groupname TEXT, 12476 gid INTEGER, 12477 members TEXT 12478); 12479CREATE INDEX i_groups_gid ON groups.gid; 12480INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 12481 12482CREATE TABLE user_hosts ( 12483 session_id TEXT, 12484 userid TEXT, 12485 host TEXT 12486); 12487CREATE INDEX i_user_hosts_userid ON user_hosts.userid; 12488INSERT INTO user_hosts (session_id, userid, host) VALUES ('abc', '$user', '127.0.0.1'); 12489 12490EOS 12491 12492 unless (close($fh)) { 12493 die("Can't write $db_script: $!"); 12494 } 12495 12496 } else { 12497 die("Can't open $db_script: $!"); 12498 } 12499 12500 my $cmd = "sqlite3 $db_file < $db_script"; 12501 build_db($cmd, $db_script); 12502 12503 # Make sure that, if we're running as root, the database file has 12504 # the permissions/privs set for use by proftpd 12505 if ($< == 0) { 12506 unless (chmod(0666, $db_file)) { 12507 die("Can't set perms on $db_file to 0666: $!"); 12508 } 12509 } 12510 12511 my $config = { 12512 PidFile => $pid_file, 12513 ScoreboardFile => $scoreboard_file, 12514 SystemLog => $log_file, 12515 TraceLog => $log_file, 12516 Trace => 'response:20 sql:20', 12517 12518 IfModules => { 12519 'mod_delay.c' => { 12520 DelayEngine => 'off', 12521 }, 12522 12523 'mod_sql.c' => [ 12524 'AuthOrder mod_sql.c', 12525 12526 'SQLAuthenticate users groups', 12527 'SQLAuthTypes plaintext', 12528 'SQLBackend sqlite3', 12529 "SQLConnectInfo $db_file", 12530 "SQLLogFile $log_file", 12531 'SQLMinID 100', 12532 12533 # Here, the MaxHostsPerUser limit is 3; it has to be hardcoded into 12534 # the SQL query, unfortunately. (Or maybe use a config file variable?) 12535 # 12536 # The LEFT JOIN is necessary for dealing with the case where the 12537 # user_hosts table has no matching rows for the user logging in. 12538 'SQLNamedQuery get-user-by-name SELECT "u.userid, u.passwd, u.uid, u.gid, u.homedir, u.shell, COUNT(uh.session_id) AS count FROM users u JOIN user_hosts uh ON u.userid = \"%U\" GROUP BY u.userid HAVING (count >= 0 AND count < 4)"', 12539 'SQLNamedQuery get-user-by-id SELECT "userid, passwd, uid, gid, homedir, shell FROM users WHERE uid = %{0}"', 12540 'SQLUserInfo custom:/get-user-by-name/get-user-by-id', 12541 12542 'SQLNamedQuery add-user-host FREEFORM "INSERT INTO user_hosts (session_id, userid, host) VALUES (\'%{env:UNIQUE_ID}\', \'%u\', \'%a\')"', 12543 'SQLLog PASS add-user-host', 12544 12545 'SQLNamedQuery remove-user-host FREEFORM "DELETE FROM user_hosts WHERE session_id = \"%{env:UNIQUE_ID}\"', 12546 'SQLLog EXIT remove-user-host', 12547 12548 'SQLShowInfo ERR_PASS 530 "Sorry, the maximum number of hosts for this user are already connected."', 12549 ], 12550 }, 12551 }; 12552 12553 my ($port, $config_user, $config_group) = config_write($config_file, $config); 12554 12555 # Open pipes, for use between the parent and child processes. Specifically, 12556 # the child will indicate when it's done with its test by writing a message 12557 # to the parent. 12558 my ($rfh, $wfh); 12559 unless (pipe($rfh, $wfh)) { 12560 die("Can't open pipe: $!"); 12561 } 12562 12563 my $ex; 12564 12565 # Fork child 12566 $self->handle_sigchld(); 12567 defined(my $pid = fork()) or die("Can't fork: $!"); 12568 if ($pid) { 12569 eval { 12570 my $client1 = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 12571 $client1->login($user, $passwd); 12572 12573 my $client2 = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 12574 $client2->login($user, $passwd); 12575 12576 my $client3 = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 12577 $client3->login($user, $passwd); 12578 12579 my $client4 = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 12580 eval { $client4->login($user, $passwd) }; 12581 unless ($@) { 12582 die("Fourth login succeeded unexpectedly"); 12583 } 12584 12585 my $resp_code = $client4->response_code(); 12586 my $resp_msgs = $client4->response_msgs(); 12587 12588 my $expected = 530; 12589 $self->assert($expected == $resp_code, 12590 test_msg("Expected response code $expected, got $resp_code")); 12591 12592 $expected = "Login incorrect."; 12593 $self->assert($expected eq $resp_msgs->[0], 12594 test_msg("Expected response '$expected', got '$resp_msgs->[0]'")); 12595 12596 $expected = "Sorry, the maximum number of hosts for this user are already connected."; 12597 $self->assert($expected eq $resp_msgs->[1], 12598 test_msg("Expected response '$expected', got '$resp_msgs->[1]'")); 12599 12600 $client4->quit(); 12601 12602 $client3->quit(); 12603 12604 $client4 = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 12605 $client4->login($user, $passwd); 12606 $client4->quit(); 12607 12608 $client2->quit(); 12609 $client1->quit(); 12610 }; 12611 12612 if ($@) { 12613 $ex = $@; 12614 } 12615 12616 $wfh->print("done\n"); 12617 $wfh->flush(); 12618 12619 } else { 12620 eval { server_wait($config_file, $rfh) }; 12621 if ($@) { 12622 warn($@); 12623 exit 1; 12624 } 12625 12626 exit 0; 12627 } 12628 12629 # Stop server 12630 server_stop($pid_file); 12631 12632 $self->assert_child_ok($pid); 12633 12634 if ($ex) { 12635 test_append_logfile($log_file, $ex); 12636 unlink($log_file); 12637 12638 die($ex); 12639 } 12640 12641 unlink($log_file); 12642} 12643 12644sub get_logins { 12645 my $db_file = shift; 12646 my $where = shift; 12647 12648 my $sql = "SELECT user, ip_addr, ts FROM ftpsessions"; 12649 if ($where) { 12650 $sql .= " WHERE $where"; 12651 } 12652 12653 my $cmd = "sqlite3 $db_file \"$sql\""; 12654 12655 if ($ENV{TEST_VERBOSE}) { 12656 print STDERR "Executing sqlite3: $cmd\n"; 12657 } 12658 12659 my $res = join('', `$cmd`); 12660 chomp($res); 12661 12662 # The default sqlite3 delimiter is '|' 12663 return split(/\|/, $res); 12664} 12665 12666sub sql_sqllog_var_micros_ts_bug3889 { 12667 my $self = shift; 12668 my $tmpdir = $self->{tmpdir}; 12669 12670 my $config_file = "$tmpdir/sqlite.conf"; 12671 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 12672 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 12673 12674 my $log_file = test_get_logfile(); 12675 12676 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 12677 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 12678 12679 my $user = 'proftpd'; 12680 my $passwd = 'test'; 12681 my $group = 'ftpd'; 12682 my $home_dir = File::Spec->rel2abs($tmpdir); 12683 my $uid = 500; 12684 my $gid = 500; 12685 12686 # Make sure that, if we're running as root, that the home directory has 12687 # permissions/privs set for the account we create 12688 if ($< == 0) { 12689 unless (chmod(0755, $home_dir)) { 12690 die("Can't set perms on $home_dir to 0755: $!"); 12691 } 12692 12693 unless (chown($uid, $gid, $home_dir)) { 12694 die("Can't set owner of $home_dir to $uid/$gid: $!"); 12695 } 12696 } 12697 12698 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 12699 '/bin/bash'); 12700 auth_group_write($auth_group_file, $group, $gid, $user); 12701 12702 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 12703 12704 # Build up sqlite3 command to create users, groups tables and populate them 12705 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 12706 12707 if (open(my $fh, "> $db_script")) { 12708 print $fh <<EOS; 12709CREATE TABLE ftpsessions ( 12710 user TEXT, 12711 ip_addr TEXT, 12712 ts TEXT 12713); 12714EOS 12715 12716 unless (close($fh)) { 12717 die("Can't write $db_script: $!"); 12718 } 12719 12720 } else { 12721 die("Can't open $db_script: $!"); 12722 } 12723 12724 my $cmd = "sqlite3 $db_file < $db_script"; 12725 build_db($cmd, $db_script); 12726 12727 # Make sure that, if we're running as root, the database file has 12728 # the permissions/privs set for use by proftpd 12729 if ($< == 0) { 12730 unless (chmod(0666, $db_file)) { 12731 die("Can't set perms on $db_file to 0666: $!"); 12732 } 12733 } 12734 12735 my $src_file = File::Spec->rel2abs("$tmpdir/test.txt"); 12736 if (open(my $fh, "> $src_file")) { 12737 close($fh); 12738 12739 } else { 12740 die("Can't open $src_file: $!"); 12741 } 12742 12743 my $dst_file = File::Spec->rel2abs("$tmpdir/foo.txt"); 12744 12745 my $config = { 12746 PidFile => $pid_file, 12747 ScoreboardFile => $scoreboard_file, 12748 SystemLog => $log_file, 12749 12750 AuthUserFile => $auth_user_file, 12751 AuthGroupFile => $auth_group_file, 12752 12753 IfModules => { 12754 'mod_delay.c' => { 12755 DelayEngine => 'off', 12756 }, 12757 12758 'mod_sql.c' => { 12759 SQLEngine => 'log', 12760 SQLBackend => 'sqlite3', 12761 SQLConnectInfo => $db_file, 12762 SQLLogFile => $log_file, 12763 SQLNamedQuery => 'login FREEFORM "INSERT INTO ftpsessions (user, ip_addr, ts) VALUES (\'%u\', \'%L\', \'%{microsecs}\')"', 12764 SQLLog => 'PASS login', 12765 }, 12766 }, 12767 }; 12768 12769 my ($port, $config_user, $config_group) = config_write($config_file, $config); 12770 12771 # Open pipes, for use between the parent and child processes. Specifically, 12772 # the child will indicate when it's done with its test by writing a message 12773 # to the parent. 12774 my ($rfh, $wfh); 12775 unless (pipe($rfh, $wfh)) { 12776 die("Can't open pipe: $!"); 12777 } 12778 12779 my $ex; 12780 12781 # Fork child 12782 $self->handle_sigchld(); 12783 defined(my $pid = fork()) or die("Can't fork: $!"); 12784 if ($pid) { 12785 eval { 12786 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 12787 $client->login($user, $passwd); 12788 $client->quit(); 12789 }; 12790 12791 if ($@) { 12792 $ex = $@; 12793 } 12794 12795 $wfh->print("done\n"); 12796 $wfh->flush(); 12797 12798 } else { 12799 eval { server_wait($config_file, $rfh) }; 12800 if ($@) { 12801 warn($@); 12802 exit 1; 12803 } 12804 12805 exit 0; 12806 } 12807 12808 # Stop server 12809 server_stop($pid_file); 12810 12811 $self->assert_child_ok($pid); 12812 12813 if ($ex) { 12814 test_append_logfile($log_file, $ex); 12815 unlink($log_file); 12816 12817 die($ex); 12818 } 12819 12820 my ($login, $ip_addr, $ts) = get_logins($db_file, "user = \'$user\'"); 12821 12822 my $expected; 12823 12824 $expected = $user; 12825 $self->assert($expected eq $login, 12826 test_msg("Expected login user '$expected', got '$login'")); 12827 12828 $expected = '127.0.0.1'; 12829 $self->assert($expected eq $ip_addr, 12830 test_msg("Expected IP address '$expected', got '$ip_addr'")); 12831 12832 $expected = '\d{6}'; 12833 $self->assert(qr/$expected/, $ts, 12834 test_msg("Expected timestamp '$expected', got '$ts'")); 12835 12836 unlink($log_file); 12837} 12838 12839sub sql_sqllog_var_millis_ts_bug3889 { 12840 my $self = shift; 12841 my $tmpdir = $self->{tmpdir}; 12842 12843 my $config_file = "$tmpdir/sqlite.conf"; 12844 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 12845 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 12846 12847 my $log_file = test_get_logfile(); 12848 12849 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 12850 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 12851 12852 my $user = 'proftpd'; 12853 my $passwd = 'test'; 12854 my $group = 'ftpd'; 12855 my $home_dir = File::Spec->rel2abs($tmpdir); 12856 my $uid = 500; 12857 my $gid = 500; 12858 12859 # Make sure that, if we're running as root, that the home directory has 12860 # permissions/privs set for the account we create 12861 if ($< == 0) { 12862 unless (chmod(0755, $home_dir)) { 12863 die("Can't set perms on $home_dir to 0755: $!"); 12864 } 12865 12866 unless (chown($uid, $gid, $home_dir)) { 12867 die("Can't set owner of $home_dir to $uid/$gid: $!"); 12868 } 12869 } 12870 12871 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 12872 '/bin/bash'); 12873 auth_group_write($auth_group_file, $group, $gid, $user); 12874 12875 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 12876 12877 # Build up sqlite3 command to create users, groups tables and populate them 12878 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 12879 12880 if (open(my $fh, "> $db_script")) { 12881 print $fh <<EOS; 12882CREATE TABLE ftpsessions ( 12883 user TEXT, 12884 ip_addr TEXT, 12885 ts TEXT 12886); 12887EOS 12888 12889 unless (close($fh)) { 12890 die("Can't write $db_script: $!"); 12891 } 12892 12893 } else { 12894 die("Can't open $db_script: $!"); 12895 } 12896 12897 my $cmd = "sqlite3 $db_file < $db_script"; 12898 build_db($cmd, $db_script); 12899 12900 # Make sure that, if we're running as root, the database file has 12901 # the permissions/privs set for use by proftpd 12902 if ($< == 0) { 12903 unless (chmod(0666, $db_file)) { 12904 die("Can't set perms on $db_file to 0666: $!"); 12905 } 12906 } 12907 12908 my $src_file = File::Spec->rel2abs("$tmpdir/test.txt"); 12909 if (open(my $fh, "> $src_file")) { 12910 close($fh); 12911 12912 } else { 12913 die("Can't open $src_file: $!"); 12914 } 12915 12916 my $dst_file = File::Spec->rel2abs("$tmpdir/foo.txt"); 12917 12918 my $config = { 12919 PidFile => $pid_file, 12920 ScoreboardFile => $scoreboard_file, 12921 SystemLog => $log_file, 12922 12923 AuthUserFile => $auth_user_file, 12924 AuthGroupFile => $auth_group_file, 12925 12926 IfModules => { 12927 'mod_delay.c' => { 12928 DelayEngine => 'off', 12929 }, 12930 12931 'mod_sql.c' => { 12932 SQLEngine => 'log', 12933 SQLBackend => 'sqlite3', 12934 SQLConnectInfo => $db_file, 12935 SQLLogFile => $log_file, 12936 SQLNamedQuery => 'login FREEFORM "INSERT INTO ftpsessions (user, ip_addr, ts) VALUES (\'%u\', \'%L\', \'%{millisecs}\')"', 12937 SQLLog => 'PASS login', 12938 }, 12939 }, 12940 }; 12941 12942 my ($port, $config_user, $config_group) = config_write($config_file, $config); 12943 12944 # Open pipes, for use between the parent and child processes. Specifically, 12945 # the child will indicate when it's done with its test by writing a message 12946 # to the parent. 12947 my ($rfh, $wfh); 12948 unless (pipe($rfh, $wfh)) { 12949 die("Can't open pipe: $!"); 12950 } 12951 12952 my $ex; 12953 12954 # Fork child 12955 $self->handle_sigchld(); 12956 defined(my $pid = fork()) or die("Can't fork: $!"); 12957 if ($pid) { 12958 eval { 12959 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 12960 $client->login($user, $passwd); 12961 $client->quit(); 12962 }; 12963 12964 if ($@) { 12965 $ex = $@; 12966 } 12967 12968 $wfh->print("done\n"); 12969 $wfh->flush(); 12970 12971 } else { 12972 eval { server_wait($config_file, $rfh) }; 12973 if ($@) { 12974 warn($@); 12975 exit 1; 12976 } 12977 12978 exit 0; 12979 } 12980 12981 # Stop server 12982 server_stop($pid_file); 12983 12984 $self->assert_child_ok($pid); 12985 12986 if ($ex) { 12987 test_append_logfile($log_file, $ex); 12988 unlink($log_file); 12989 12990 die($ex); 12991 } 12992 12993 my ($login, $ip_addr, $ts) = get_logins($db_file, "user = \'$user\'"); 12994 12995 my $expected; 12996 12997 $expected = $user; 12998 $self->assert($expected eq $login, 12999 test_msg("Expected login user '$expected', got '$login'")); 13000 13001 $expected = '127.0.0.1'; 13002 $self->assert($expected eq $ip_addr, 13003 test_msg("Expected IP address '$expected', got '$ip_addr'")); 13004 13005 $expected = '\d{3}'; 13006 $self->assert(qr/$expected/, $ts, 13007 test_msg("Expected timestamp '$expected', got '$ts'")); 13008 13009 unlink($log_file); 13010} 13011 13012sub sql_sqllog_var_iso8601_ts_bug3889 { 13013 my $self = shift; 13014 my $tmpdir = $self->{tmpdir}; 13015 13016 my $config_file = "$tmpdir/sqlite.conf"; 13017 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 13018 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 13019 13020 my $log_file = test_get_logfile(); 13021 13022 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 13023 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 13024 13025 my $user = 'proftpd'; 13026 my $passwd = 'test'; 13027 my $group = 'ftpd'; 13028 my $home_dir = File::Spec->rel2abs($tmpdir); 13029 my $uid = 500; 13030 my $gid = 500; 13031 13032 # Make sure that, if we're running as root, that the home directory has 13033 # permissions/privs set for the account we create 13034 if ($< == 0) { 13035 unless (chmod(0755, $home_dir)) { 13036 die("Can't set perms on $home_dir to 0755: $!"); 13037 } 13038 13039 unless (chown($uid, $gid, $home_dir)) { 13040 die("Can't set owner of $home_dir to $uid/$gid: $!"); 13041 } 13042 } 13043 13044 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 13045 '/bin/bash'); 13046 auth_group_write($auth_group_file, $group, $gid, $user); 13047 13048 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 13049 13050 # Build up sqlite3 command to create users, groups tables and populate them 13051 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 13052 13053 if (open(my $fh, "> $db_script")) { 13054 print $fh <<EOS; 13055CREATE TABLE ftpsessions ( 13056 user TEXT, 13057 ip_addr TEXT, 13058 ts TEXT 13059); 13060EOS 13061 13062 unless (close($fh)) { 13063 die("Can't write $db_script: $!"); 13064 } 13065 13066 } else { 13067 die("Can't open $db_script: $!"); 13068 } 13069 13070 my $cmd = "sqlite3 $db_file < $db_script"; 13071 build_db($cmd, $db_script); 13072 13073 # Make sure that, if we're running as root, the database file has 13074 # the permissions/privs set for use by proftpd 13075 if ($< == 0) { 13076 unless (chmod(0666, $db_file)) { 13077 die("Can't set perms on $db_file to 0666: $!"); 13078 } 13079 } 13080 13081 my $src_file = File::Spec->rel2abs("$tmpdir/test.txt"); 13082 if (open(my $fh, "> $src_file")) { 13083 close($fh); 13084 13085 } else { 13086 die("Can't open $src_file: $!"); 13087 } 13088 13089 my $dst_file = File::Spec->rel2abs("$tmpdir/foo.txt"); 13090 13091 my $config = { 13092 PidFile => $pid_file, 13093 ScoreboardFile => $scoreboard_file, 13094 SystemLog => $log_file, 13095 13096 AuthUserFile => $auth_user_file, 13097 AuthGroupFile => $auth_group_file, 13098 13099 IfModules => { 13100 'mod_delay.c' => { 13101 DelayEngine => 'off', 13102 }, 13103 13104 'mod_sql.c' => { 13105 SQLEngine => 'log', 13106 SQLBackend => 'sqlite3', 13107 SQLConnectInfo => $db_file, 13108 SQLLogFile => $log_file, 13109 SQLNamedQuery => 'login FREEFORM "INSERT INTO ftpsessions (user, ip_addr, ts) VALUES (\'%u\', \'%L\', \'%{iso8601}\')"', 13110 SQLLog => 'PASS login', 13111 }, 13112 }, 13113 }; 13114 13115 my ($port, $config_user, $config_group) = config_write($config_file, $config); 13116 13117 # Open pipes, for use between the parent and child processes. Specifically, 13118 # the child will indicate when it's done with its test by writing a message 13119 # to the parent. 13120 my ($rfh, $wfh); 13121 unless (pipe($rfh, $wfh)) { 13122 die("Can't open pipe: $!"); 13123 } 13124 13125 my $ex; 13126 13127 # Fork child 13128 $self->handle_sigchld(); 13129 defined(my $pid = fork()) or die("Can't fork: $!"); 13130 if ($pid) { 13131 eval { 13132 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 13133 $client->login($user, $passwd); 13134 $client->quit(); 13135 }; 13136 13137 if ($@) { 13138 $ex = $@; 13139 } 13140 13141 $wfh->print("done\n"); 13142 $wfh->flush(); 13143 13144 } else { 13145 eval { server_wait($config_file, $rfh) }; 13146 if ($@) { 13147 warn($@); 13148 exit 1; 13149 } 13150 13151 exit 0; 13152 } 13153 13154 # Stop server 13155 server_stop($pid_file); 13156 13157 $self->assert_child_ok($pid); 13158 13159 if ($ex) { 13160 test_append_logfile($log_file, $ex); 13161 unlink($log_file); 13162 13163 die($ex); 13164 } 13165 13166 my ($login, $ip_addr, $ts) = get_logins($db_file, "user = \'$user\'"); 13167 13168 my $expected; 13169 13170 $expected = $user; 13171 $self->assert($expected eq $login, 13172 test_msg("Expected login user '$expected', got '$login'")); 13173 13174 $expected = '127.0.0.1'; 13175 $self->assert($expected eq $ip_addr, 13176 test_msg("Expected IP address '$expected', got '$ip_addr'")); 13177 13178 $expected = '\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2},\d{3}'; 13179 $self->assert(qr/$expected/, $ts, 13180 test_msg("Expected timestamp '$expected', got '$ts'")); 13181 13182 unlink($log_file); 13183} 13184 13185sub sql_sqllogonevent_bug3893 { 13186 my $self = shift; 13187 my $tmpdir = $self->{tmpdir}; 13188 my $setup = test_setup($tmpdir, 'sqlite'); 13189 13190 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 13191 13192 # Build up sqlite3 command to create users, groups tables and populate them 13193 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 13194 13195 if (open(my $fh, "> $db_script")) { 13196 print $fh <<EOS; 13197CREATE TABLE ftpsessions ( 13198 user TEXT, 13199 ip_addr TEXT, 13200 timestamp TEXT 13201); 13202EOS 13203 13204 unless (close($fh)) { 13205 die("Can't write $db_script: $!"); 13206 } 13207 13208 } else { 13209 die("Can't open $db_script: $!"); 13210 } 13211 13212 my $cmd = "sqlite3 $db_file < $db_script"; 13213 build_db($cmd, $db_script); 13214 13215 # Make sure that, if we're running as root, the database file has 13216 # the permissions/privs set for use by proftpd 13217 if ($< == 0) { 13218 unless (chmod(0666, $db_file)) { 13219 die("Can't set perms on $db_file to 0666: $!"); 13220 } 13221 } 13222 13223 my $max_login_attempts = 2; 13224 13225 my $config = { 13226 PidFile => $setup->{pid_file}, 13227 ScoreboardFile => $setup->{scoreboard_file}, 13228 SystemLog => $setup->{log_file}, 13229 TraceLog => $setup->{log_file}, 13230 Trace => 'jot:20 sql:20 sql.sqlite:20', 13231 13232 AuthOrder => 'mod_auth_file.c', 13233 AuthUserFile => $setup->{auth_user_file}, 13234 AuthGroupFile => $setup->{auth_group_file}, 13235 MaxLoginAttempts => $max_login_attempts, 13236 13237 IfModules => { 13238 'mod_delay.c' => { 13239 DelayEngine => 'off', 13240 }, 13241 13242 'mod_sql.c' => { 13243 SQLEngine => 'log', 13244 SQLBackend => 'sqlite3', 13245 SQLConnectInfo => $db_file, 13246 SQLLogFile => $setup->{log_file}, 13247 SQLNamedQuery => 'max_logins_exceeded FREEFORM "INSERT INTO ftpsessions (user, ip_addr, timestamp) VALUES (\'%U\', \'%L\', \'%{time:%Y-%m-%d %H:%M:%S}\')"', 13248 SQLLogOnEvent => 'MaxLoginAttempts max_logins_exceeded', 13249 }, 13250 }, 13251 }; 13252 13253 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 13254 $config); 13255 13256 # Open pipes, for use between the parent and child processes. Specifically, 13257 # the child will indicate when it's done with its test by writing a message 13258 # to the parent. 13259 my ($rfh, $wfh); 13260 unless (pipe($rfh, $wfh)) { 13261 die("Can't open pipe: $!"); 13262 } 13263 13264 my $ex; 13265 13266 # Fork child 13267 $self->handle_sigchld(); 13268 defined(my $pid = fork()) or die("Can't fork: $!"); 13269 if ($pid) { 13270 eval { 13271 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 13272 eval { $client->login($setup->{user}, 'badpassword') }; 13273 unless ($@) { 13274 die("Login succeeded unexpectedly"); 13275 } 13276 13277 eval { $client->login($setup->{user}, 'badpassword') }; 13278 unless ($@) { 13279 die("Login succeeded unexpectedly"); 13280 } 13281 }; 13282 if ($@) { 13283 $ex = $@; 13284 } 13285 13286 $wfh->print("done\n"); 13287 $wfh->flush(); 13288 13289 } else { 13290 eval { server_wait($setup->{config_file}, $rfh) }; 13291 if ($@) { 13292 warn($@); 13293 exit 1; 13294 } 13295 13296 exit 0; 13297 } 13298 13299 # Stop server 13300 server_stop($setup->{pid_file}); 13301 $self->assert_child_ok($pid); 13302 13303 if ($ex) { 13304 test_cleanup($setup->{log_file}, $ex); 13305 } 13306 13307 eval { 13308 my ($login, $ip_addr, $timestamp) = get_sessions($db_file, 13309 "user = \'$setup->{user}\'"); 13310 13311 my $expected = $setup->{user}; 13312 $self->assert($expected eq $login, 13313 test_msg("Expected '$expected', got '$login'")); 13314 13315 $expected = '127.0.0.1'; 13316 $self->assert($expected eq $ip_addr, 13317 test_msg("Expected '$expected', got '$ip_addr'")); 13318 13319 $expected = '\d{4}\-\d{2}\-\d{2} \d{2}:\d{2}:\d{2}'; 13320 $self->assert(qr/$expected/, $timestamp, 13321 test_msg("Expected '$expected', got '$timestamp'")); 13322 }; 13323 if ($@) { 13324 $ex = $@; 13325 } 13326 13327 test_cleanup($setup->{log_file}, $ex); 13328} 13329 13330sub get_session_with_primary_key { 13331 my $db_file = shift; 13332 my $where = shift; 13333 13334 my $sql = "SELECT name, ip_addr, primary_key FROM sessions"; 13335 if ($where) { 13336 $sql .= " WHERE $where"; 13337 } 13338 13339 my $cmd = "sqlite3 $db_file \"$sql\""; 13340 13341 if ($ENV{TEST_VERBOSE}) { 13342 print STDERR "Executing sqlite3: $cmd\n"; 13343 } 13344 13345 my $res = join('', `$cmd`); 13346 chomp($res); 13347 13348 # The default sqlite3 delimiter is '|' 13349 return split(/\|/, $res); 13350} 13351 13352sub sql_userprimarykey_bug3864 { 13353 my $self = shift; 13354 my $tmpdir = $self->{tmpdir}; 13355 13356 my $config_file = "$tmpdir/sqlite.conf"; 13357 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 13358 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 13359 13360 my $log_file = test_get_logfile(); 13361 13362 my $user = 'proftpd'; 13363 my $passwd = 'test'; 13364 my $group = 'ftpd'; 13365 my $home_dir = File::Spec->rel2abs($tmpdir); 13366 my $uid = 500; 13367 my $gid = 500; 13368 13369 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 13370 13371 # Build up sqlite3 command to create users, groups tables and populate them 13372 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 13373 13374 if (open(my $fh, "> $db_script")) { 13375 print $fh <<EOS; 13376CREATE TABLE users ( 13377 userid TEXT, 13378 passwd TEXT, 13379 uid INTEGER, 13380 gid INTEGER, 13381 homedir TEXT, 13382 shell TEXT 13383); 13384INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 13385 13386CREATE TABLE groups ( 13387 groupname TEXT, 13388 gid INTEGER, 13389 members TEXT 13390); 13391INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 13392 13393CREATE TABLE sessions ( 13394 name TEXT, 13395 ip_addr TEXT, 13396 primary_key INTEGER 13397); 13398EOS 13399 13400 unless (close($fh)) { 13401 die("Can't write $db_script: $!"); 13402 } 13403 13404 } else { 13405 die("Can't open $db_script: $!"); 13406 } 13407 13408 my $cmd = "sqlite3 $db_file < $db_script"; 13409 build_db($cmd, $db_script); 13410 13411 # Make sure that, if we're running as root, the database file has 13412 # the permissions/privs set for use by proftpd 13413 if ($< == 0) { 13414 unless (chmod(0666, $db_file)) { 13415 die("Can't set perms on $db_file to 0666: $!"); 13416 } 13417 } 13418 13419 my $config = { 13420 PidFile => $pid_file, 13421 ScoreboardFile => $scoreboard_file, 13422 SystemLog => $log_file, 13423 TraceLog => $log_file, 13424 Trace => 'sql:20', 13425 13426 IfModules => { 13427 'mod_delay.c' => { 13428 DelayEngine => 'off', 13429 }, 13430 13431 'mod_sql.c' => { 13432 SQLAuthTypes => 'plaintext', 13433 SQLBackend => 'sqlite3', 13434 SQLConnectInfo => $db_file, 13435 SQLLogFile => $log_file, 13436 SQLMinID => 200, 13437 13438 SQLUserPrimaryKey => 'uid', 13439 13440 SQLNamedQuery => 'session_start FREEFORM "INSERT INTO sessions (name, ip_addr, primary_key) VALUES (\'%u\', \'%L\', %{note:sql.user-primary-key})"', 13441 SQLLog => 'PASS session_start', 13442 }, 13443 }, 13444 }; 13445 13446 my ($port, $config_user, $config_group) = config_write($config_file, $config); 13447 13448 # Open pipes, for use between the parent and child processes. Specifically, 13449 # the child will indicate when it's done with its test by writing a message 13450 # to the parent. 13451 my ($rfh, $wfh); 13452 unless (pipe($rfh, $wfh)) { 13453 die("Can't open pipe: $!"); 13454 } 13455 13456 my $ex; 13457 13458 # Fork child 13459 $self->handle_sigchld(); 13460 defined(my $pid = fork()) or die("Can't fork: $!"); 13461 if ($pid) { 13462 eval { 13463 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 13464 $client->login($user, $passwd); 13465 $client->quit(); 13466 }; 13467 13468 if ($@) { 13469 $ex = $@; 13470 } 13471 13472 $wfh->print("done\n"); 13473 $wfh->flush(); 13474 13475 } else { 13476 eval { server_wait($config_file, $rfh) }; 13477 if ($@) { 13478 warn($@); 13479 exit 1; 13480 } 13481 13482 exit 0; 13483 } 13484 13485 # Stop server 13486 server_stop($pid_file); 13487 13488 $self->assert_child_ok($pid); 13489 13490 if ($ex) { 13491 test_append_logfile($log_file, $ex); 13492 unlink($log_file); 13493 13494 die($ex); 13495 } 13496 13497 eval { 13498 my ($name, $ip_addr, $primary_key) = get_session_with_primary_key($db_file, 13499 "name = \'$user\'"); 13500 13501 my $expected; 13502 13503 $expected = $user; 13504 $self->assert($expected eq $name, 13505 test_msg("Expected name '$expected', got '$name'")); 13506 13507 $expected = '127.0.0.1'; 13508 $self->assert($expected eq $ip_addr, 13509 test_msg("Expected IP address '$expected', got '$ip_addr'")); 13510 13511 $expected = $uid; 13512 $self->assert($expected == $primary_key, 13513 test_msg("Expected primary key $expected, got $primary_key")); 13514 }; 13515 if ($@) { 13516 $ex = $@; 13517 } 13518 13519 if ($ex) { 13520 test_append_logfile($log_file, $ex); 13521 unlink($log_file); 13522 13523 die($ex); 13524 } 13525 13526 unlink($log_file); 13527} 13528 13529sub sql_userprimarykey_custom_bug3864 { 13530 my $self = shift; 13531 my $tmpdir = $self->{tmpdir}; 13532 13533 my $config_file = "$tmpdir/sqlite.conf"; 13534 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 13535 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 13536 13537 my $log_file = test_get_logfile(); 13538 13539 my $user = 'proftpd'; 13540 my $passwd = 'test'; 13541 my $group = 'ftpd'; 13542 my $home_dir = File::Spec->rel2abs($tmpdir); 13543 my $uid = 500; 13544 my $gid = 500; 13545 13546 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 13547 13548 # Build up sqlite3 command to create users, groups tables and populate them 13549 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 13550 13551 if (open(my $fh, "> $db_script")) { 13552 print $fh <<EOS; 13553CREATE TABLE users ( 13554 userid TEXT, 13555 passwd TEXT, 13556 uid INTEGER, 13557 gid INTEGER, 13558 homedir TEXT, 13559 shell TEXT, 13560 primary_key INTEGER 13561); 13562INSERT INTO users (userid, passwd, uid, gid, homedir, shell, primary_key) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash', $uid); 13563 13564CREATE TABLE groups ( 13565 groupname TEXT, 13566 gid INTEGER, 13567 members TEXT 13568); 13569INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 13570 13571CREATE TABLE sessions ( 13572 name TEXT, 13573 ip_addr TEXT, 13574 primary_key INTEGER 13575); 13576EOS 13577 13578 unless (close($fh)) { 13579 die("Can't write $db_script: $!"); 13580 } 13581 13582 } else { 13583 die("Can't open $db_script: $!"); 13584 } 13585 13586 my $cmd = "sqlite3 $db_file < $db_script"; 13587 build_db($cmd, $db_script); 13588 13589 # Make sure that, if we're running as root, the database file has 13590 # the permissions/privs set for use by proftpd 13591 if ($< == 0) { 13592 unless (chmod(0666, $db_file)) { 13593 die("Can't set perms on $db_file to 0666: $!"); 13594 } 13595 } 13596 13597 my $config = { 13598 PidFile => $pid_file, 13599 ScoreboardFile => $scoreboard_file, 13600 SystemLog => $log_file, 13601 TraceLog => $log_file, 13602 Trace => 'sql:20', 13603 13604 IfModules => { 13605 'mod_delay.c' => { 13606 DelayEngine => 'off', 13607 }, 13608 13609 'mod_sql.c' => [ 13610 'SQLAuthTypes plaintext', 13611 'SQLBackend sqlite3', 13612 "SQLConnectInfo $db_file", 13613 "SQLLogFile $log_file", 13614 'SQLMinID 200', 13615 13616 'SQLNamedQuery get-user-primary-key SELECT "primary_key FROM users WHERE userid = \'%{0}\'"', 13617 'SQLUserPrimaryKey custom:/get-user-primary-key', 13618 13619 'SQLNamedQuery session_start FREEFORM "INSERT INTO sessions (name, ip_addr, primary_key) VALUES (\'%u\', \'%L\', %{note:sql.user-primary-key})"', 13620 'SQLLog PASS session_start', 13621 ], 13622 }, 13623 }; 13624 13625 my ($port, $config_user, $config_group) = config_write($config_file, $config); 13626 13627 # Open pipes, for use between the parent and child processes. Specifically, 13628 # the child will indicate when it's done with its test by writing a message 13629 # to the parent. 13630 my ($rfh, $wfh); 13631 unless (pipe($rfh, $wfh)) { 13632 die("Can't open pipe: $!"); 13633 } 13634 13635 my $ex; 13636 13637 # Fork child 13638 $self->handle_sigchld(); 13639 defined(my $pid = fork()) or die("Can't fork: $!"); 13640 if ($pid) { 13641 eval { 13642 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 13643 $client->login($user, $passwd); 13644 $client->quit(); 13645 }; 13646 13647 if ($@) { 13648 $ex = $@; 13649 } 13650 13651 $wfh->print("done\n"); 13652 $wfh->flush(); 13653 13654 } else { 13655 eval { server_wait($config_file, $rfh) }; 13656 if ($@) { 13657 warn($@); 13658 exit 1; 13659 } 13660 13661 exit 0; 13662 } 13663 13664 # Stop server 13665 server_stop($pid_file); 13666 13667 $self->assert_child_ok($pid); 13668 13669 if ($ex) { 13670 test_append_logfile($log_file, $ex); 13671 unlink($log_file); 13672 13673 die($ex); 13674 } 13675 13676 eval { 13677 my ($name, $ip_addr, $primary_key) = get_session_with_primary_key($db_file, 13678 "name = \'$user\'"); 13679 13680 my $expected; 13681 13682 $expected = $user; 13683 $self->assert($expected eq $name, 13684 test_msg("Expected name '$expected', got '$name'")); 13685 13686 $expected = '127.0.0.1'; 13687 $self->assert($expected eq $ip_addr, 13688 test_msg("Expected IP address '$expected', got '$ip_addr'")); 13689 13690 $expected = $uid; 13691 $self->assert($expected == $primary_key, 13692 test_msg("Expected primary key $expected, got $primary_key")); 13693 }; 13694 if ($@) { 13695 $ex = $@; 13696 } 13697 13698 if ($ex) { 13699 test_append_logfile($log_file, $ex); 13700 unlink($log_file); 13701 13702 die($ex); 13703 } 13704 13705 unlink($log_file); 13706} 13707 13708sub sql_groupprimarykey_bug3864 { 13709 my $self = shift; 13710 my $tmpdir = $self->{tmpdir}; 13711 13712 my $config_file = "$tmpdir/sqlite.conf"; 13713 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 13714 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 13715 13716 my $log_file = test_get_logfile(); 13717 13718 my $user = 'proftpd'; 13719 my $passwd = 'test'; 13720 my $group = 'ftpd'; 13721 my $home_dir = File::Spec->rel2abs($tmpdir); 13722 my $uid = 500; 13723 my $gid = 500; 13724 13725 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 13726 13727 # Build up sqlite3 command to create users, groups tables and populate them 13728 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 13729 13730 if (open(my $fh, "> $db_script")) { 13731 print $fh <<EOS; 13732CREATE TABLE users ( 13733 userid TEXT, 13734 passwd TEXT, 13735 uid INTEGER, 13736 gid INTEGER, 13737 homedir TEXT, 13738 shell TEXT 13739); 13740INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 13741 13742CREATE TABLE groups ( 13743 groupname TEXT, 13744 gid INTEGER, 13745 members TEXT 13746); 13747INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 13748 13749CREATE TABLE sessions ( 13750 name TEXT, 13751 ip_addr TEXT, 13752 primary_key INTEGER 13753); 13754EOS 13755 13756 unless (close($fh)) { 13757 die("Can't write $db_script: $!"); 13758 } 13759 13760 } else { 13761 die("Can't open $db_script: $!"); 13762 } 13763 13764 my $cmd = "sqlite3 $db_file < $db_script"; 13765 build_db($cmd, $db_script); 13766 13767 # Make sure that, if we're running as root, the database file has 13768 # the permissions/privs set for use by proftpd 13769 if ($< == 0) { 13770 unless (chmod(0666, $db_file)) { 13771 die("Can't set perms on $db_file to 0666: $!"); 13772 } 13773 } 13774 13775 my $config = { 13776 PidFile => $pid_file, 13777 ScoreboardFile => $scoreboard_file, 13778 SystemLog => $log_file, 13779 TraceLog => $log_file, 13780 Trace => 'sql:20', 13781 13782 IfModules => { 13783 'mod_delay.c' => { 13784 DelayEngine => 'off', 13785 }, 13786 13787 'mod_sql.c' => { 13788 SQLAuthTypes => 'plaintext', 13789 SQLBackend => 'sqlite3', 13790 SQLConnectInfo => $db_file, 13791 SQLLogFile => $log_file, 13792 SQLMinID => 200, 13793 13794 SQLGroupPrimaryKey => 'gid', 13795 13796 SQLNamedQuery => 'session_start FREEFORM "INSERT INTO sessions (name, ip_addr, primary_key) VALUES (\'%g\', \'%L\', %{note:sql.group-primary-key})"', 13797 SQLLog => 'PASS session_start', 13798 }, 13799 }, 13800 }; 13801 13802 my ($port, $config_user, $config_group) = config_write($config_file, $config); 13803 13804 # Open pipes, for use between the parent and child processes. Specifically, 13805 # the child will indicate when it's done with its test by writing a message 13806 # to the parent. 13807 my ($rfh, $wfh); 13808 unless (pipe($rfh, $wfh)) { 13809 die("Can't open pipe: $!"); 13810 } 13811 13812 my $ex; 13813 13814 # Fork child 13815 $self->handle_sigchld(); 13816 defined(my $pid = fork()) or die("Can't fork: $!"); 13817 if ($pid) { 13818 eval { 13819 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 13820 $client->login($user, $passwd); 13821 $client->quit(); 13822 }; 13823 13824 if ($@) { 13825 $ex = $@; 13826 } 13827 13828 $wfh->print("done\n"); 13829 $wfh->flush(); 13830 13831 } else { 13832 eval { server_wait($config_file, $rfh) }; 13833 if ($@) { 13834 warn($@); 13835 exit 1; 13836 } 13837 13838 exit 0; 13839 } 13840 13841 # Stop server 13842 server_stop($pid_file); 13843 13844 $self->assert_child_ok($pid); 13845 13846 if ($ex) { 13847 test_append_logfile($log_file, $ex); 13848 unlink($log_file); 13849 13850 die($ex); 13851 } 13852 13853 eval { 13854 my ($name, $ip_addr, $primary_key) = get_session_with_primary_key($db_file, 13855 "name = \'$group\'"); 13856 13857 my $expected; 13858 13859 $expected = $group; 13860 $self->assert($expected eq $name, 13861 test_msg("Expected name '$expected', got '$name'")); 13862 13863 $expected = '127.0.0.1'; 13864 $self->assert($expected eq $ip_addr, 13865 test_msg("Expected IP address '$expected', got '$ip_addr'")); 13866 13867 $expected = $uid; 13868 $self->assert($expected == $primary_key, 13869 test_msg("Expected primary key $expected, got $primary_key")); 13870 }; 13871 if ($@) { 13872 $ex = $@; 13873 } 13874 13875 if ($ex) { 13876 test_append_logfile($log_file, $ex); 13877 unlink($log_file); 13878 13879 die($ex); 13880 } 13881 13882 unlink($log_file); 13883} 13884 13885sub sql_groupprimarykey_custom_bug3864 { 13886 my $self = shift; 13887 my $tmpdir = $self->{tmpdir}; 13888 my $setup = test_setup($tmpdir, 'sqlite'); 13889 13890 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 13891 13892 # Build up sqlite3 command to create users, groups tables and populate them 13893 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 13894 13895 if (open(my $fh, "> $db_script")) { 13896 print $fh <<EOS; 13897CREATE TABLE users ( 13898 userid TEXT, 13899 passwd TEXT, 13900 uid INTEGER, 13901 gid INTEGER, 13902 homedir TEXT, 13903 shell TEXT 13904); 13905INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$setup->{user}', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash'); 13906 13907CREATE TABLE groups ( 13908 groupname TEXT, 13909 gid INTEGER, 13910 members TEXT, 13911 primary_key INTEGER 13912); 13913INSERT INTO groups (groupname, gid, members, primary_key) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}', $setup->{gid}); 13914 13915CREATE TABLE sessions ( 13916 name TEXT, 13917 ip_addr TEXT, 13918 primary_key INTEGER 13919); 13920EOS 13921 unless (close($fh)) { 13922 die("Can't write $db_script: $!"); 13923 } 13924 13925 } else { 13926 die("Can't open $db_script: $!"); 13927 } 13928 13929 my $cmd = "sqlite3 $db_file < $db_script"; 13930 build_db($cmd, $db_script); 13931 13932 # Make sure that, if we're running as root, the database file has 13933 # the permissions/privs set for use by proftpd 13934 if ($< == 0) { 13935 unless (chmod(0666, $db_file)) { 13936 die("Can't set perms on $db_file to 0666: $!"); 13937 } 13938 } 13939 13940 my $config = { 13941 PidFile => $setup->{pid_file}, 13942 ScoreboardFile => $setup->{scoreboard_file}, 13943 SystemLog => $setup->{log_file}, 13944 TraceLog => $setup->{log_file}, 13945 Trace => 'jot:20 sql:20', 13946 13947 IfModules => { 13948 'mod_delay.c' => { 13949 DelayEngine => 'off', 13950 }, 13951 13952 'mod_sql.c' => [ 13953 'SQLAuthTypes plaintext', 13954 'SQLBackend sqlite3', 13955 "SQLConnectInfo $db_file", 13956 "SQLLogFile $setup->{log_file}", 13957 'SQLMinID 200', 13958 13959 'SQLNamedQuery get-group-primary-key SELECT "primary_key from groups WHERE groupname = \'%{0}\'"', 13960 'SQLGroupPrimaryKey custom:/get-group-primary-key', 13961 13962 'SQLNamedQuery session_start FREEFORM "INSERT INTO sessions (name, ip_addr, primary_key) VALUES (\'%g\', \'%L\', %{note:sql.group-primary-key})"', 13963 'SQLLog PASS session_start', 13964 ], 13965 }, 13966 }; 13967 13968 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 13969 $config); 13970 13971 # Open pipes, for use between the parent and child processes. Specifically, 13972 # the child will indicate when it's done with its test by writing a message 13973 # to the parent. 13974 my ($rfh, $wfh); 13975 unless (pipe($rfh, $wfh)) { 13976 die("Can't open pipe: $!"); 13977 } 13978 13979 my $ex; 13980 13981 # Fork child 13982 $self->handle_sigchld(); 13983 defined(my $pid = fork()) or die("Can't fork: $!"); 13984 if ($pid) { 13985 eval { 13986 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 13987 $client->login($setup->{user}, $setup->{passwd}); 13988 $client->quit(); 13989 }; 13990 if ($@) { 13991 $ex = $@; 13992 } 13993 13994 $wfh->print("done\n"); 13995 $wfh->flush(); 13996 13997 } else { 13998 eval { server_wait($setup->{config_file}, $rfh) }; 13999 if ($@) { 14000 warn($@); 14001 exit 1; 14002 } 14003 14004 exit 0; 14005 } 14006 14007 # Stop server 14008 server_stop($setup->{pid_file}); 14009 $self->assert_child_ok($pid); 14010 14011 if ($ex) { 14012 test_cleanup($setup->{log_file}, $ex); 14013 } 14014 14015 eval { 14016 my ($name, $ip_addr, $primary_key) = get_session_with_primary_key($db_file, 14017 "name = \'$setup->{group}\'"); 14018 14019 my $expected = $setup->{group}; 14020 $self->assert($expected eq $name, "Expected name '$expected', got '$name'"); 14021 14022 $expected = '127.0.0.1'; 14023 $self->assert($expected eq $ip_addr, 14024 "Expected IP address '$expected', got '$ip_addr'"); 14025 14026 $expected = $setup->{gid}; 14027 $self->assert($expected == $primary_key, 14028 "Expected primary key $expected, got $primary_key"); 14029 }; 14030 if ($@) { 14031 $ex = $@; 14032 } 14033 14034 test_cleanup($setup->{log_file}, $ex); 14035} 14036 14037sub sql_sqllog_var_basename_bug3987 { 14038 my $self = shift; 14039 my $tmpdir = $self->{tmpdir}; 14040 14041 my $config_file = "$tmpdir/sqlite.conf"; 14042 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 14043 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 14044 14045 my $log_file = test_get_logfile(); 14046 14047 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 14048 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 14049 14050 my $user = 'proftpd'; 14051 my $passwd = 'test'; 14052 my $group = 'ftpd'; 14053 my $home_dir = File::Spec->rel2abs($tmpdir); 14054 my $uid = 500; 14055 my $gid = 500; 14056 14057 # Make sure that, if we're running as root, that the home directory has 14058 # permissions/privs set for the account we create 14059 if ($< == 0) { 14060 unless (chmod(0755, $home_dir)) { 14061 die("Can't set perms on $home_dir to 0755: $!"); 14062 } 14063 14064 unless (chown($uid, $gid, $home_dir)) { 14065 die("Can't set owner of $home_dir to $uid/$gid: $!"); 14066 } 14067 } 14068 14069 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 14070 '/bin/bash'); 14071 auth_group_write($auth_group_file, $group, $gid, $user); 14072 14073 my $test_file = File::Spec->rel2abs($config_file); 14074 14075 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 14076 14077 # Build up sqlite3 command to create users, groups tables and populate them 14078 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 14079 14080 if (open(my $fh, "> $db_script")) { 14081 print $fh <<EOS; 14082CREATE TABLE ftpsessions ( 14083 user TEXT, 14084 ip_addr TEXT, 14085 dir TEXT 14086); 14087EOS 14088 14089 unless (close($fh)) { 14090 die("Can't write $db_script: $!"); 14091 } 14092 14093 } else { 14094 die("Can't open $db_script: $!"); 14095 } 14096 14097 my $cmd = "sqlite3 $db_file < $db_script"; 14098 build_db($cmd, $db_script); 14099 14100 # Make sure that, if we're running as root, the database file has 14101 # the permissions/privs set for use by proftpd 14102 if ($< == 0) { 14103 unless (chmod(0666, $db_file)) { 14104 die("Can't set perms on $db_file to 0666: $!"); 14105 } 14106 } 14107 14108 my $config = { 14109 PidFile => $pid_file, 14110 ScoreboardFile => $scoreboard_file, 14111 SystemLog => $log_file, 14112 14113 AuthUserFile => $auth_user_file, 14114 AuthGroupFile => $auth_group_file, 14115 14116 IfModules => { 14117 'mod_delay.c' => { 14118 DelayEngine => 'off', 14119 }, 14120 14121 'mod_sql.c' => { 14122 SQLEngine => 'log', 14123 SQLBackend => 'sqlite3', 14124 SQLConnectInfo => $db_file, 14125 SQLLogFile => $log_file, 14126 SQLNamedQuery => 'filename FREEFORM "INSERT INTO ftpsessions (user, ip_addr, dir) VALUES (\'%u\', \'%L\', \'%{basename}\')"', 14127 SQLLog => 'RETR filename', 14128 }, 14129 }, 14130 }; 14131 14132 my ($port, $config_user, $config_group) = config_write($config_file, $config); 14133 14134 # Open pipes, for use between the parent and child processes. Specifically, 14135 # the child will indicate when it's done with its test by writing a message 14136 # to the parent. 14137 my ($rfh, $wfh); 14138 unless (pipe($rfh, $wfh)) { 14139 die("Can't open pipe: $!"); 14140 } 14141 14142 my $ex; 14143 14144 # Fork child 14145 $self->handle_sigchld(); 14146 defined(my $pid = fork()) or die("Can't fork: $!"); 14147 if ($pid) { 14148 eval { 14149 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 14150 $client->login($user, $passwd); 14151 14152 my $conn = $client->retr_raw($test_file); 14153 unless ($conn) { 14154 die("Failed to RETR: " . $client->response_code() . " " . 14155 $client->response_msg()); 14156 } 14157 14158 my $buf; 14159 $conn->read($buf, 8192, 30); 14160 eval { $conn->close() }; 14161 14162 my $resp_code = $client->response_code(); 14163 my $resp_msg = $client->response_msg(); 14164 $self->assert_transfer_ok($resp_code, $resp_msg); 14165 14166 $client->quit(); 14167 }; 14168 14169 if ($@) { 14170 $ex = $@; 14171 } 14172 14173 $wfh->print("done\n"); 14174 $wfh->flush(); 14175 14176 } else { 14177 eval { server_wait($config_file, $rfh) }; 14178 if ($@) { 14179 warn($@); 14180 exit 1; 14181 } 14182 14183 exit 0; 14184 } 14185 14186 # Stop server 14187 server_stop($pid_file); 14188 14189 $self->assert_child_ok($pid); 14190 14191 if ($ex) { 14192 test_append_logfile($log_file, $ex); 14193 unlink($log_file); 14194 14195 die($ex); 14196 } 14197 14198 # Note: We are simply re-using the existing get_locations() function here 14199 # for convenience/expedience. 14200 my ($login, $ip_addr, $name) = get_locations($db_file, "user = \'$user\'"); 14201 14202 my $expected; 14203 14204 $expected = $user; 14205 $self->assert($expected eq $login, 14206 test_msg("Expected '$expected', got '$login'")); 14207 14208 $expected = '127.0.0.1'; 14209 $self->assert($expected eq $ip_addr, 14210 test_msg("Expected '$expected', got '$ip_addr'")); 14211 14212 $expected = 'sqlite.conf'; 14213 $self->assert($expected eq $name, 14214 test_msg("Expected '$expected', got '$name'")); 14215 14216 unlink($log_file); 14217} 14218 14219sub sql_user_info_defaulthomedir_bug4083 { 14220 my $self = shift; 14221 my $tmpdir = $self->{tmpdir}; 14222 14223 my $config_file = "$tmpdir/sqlite.conf"; 14224 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 14225 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 14226 14227 my $log_file = test_get_logfile(); 14228 14229 my $user = 'proftpd'; 14230 my $passwd = 'test'; 14231 my $group = 'ftpd'; 14232 my $home_dir = File::Spec->rel2abs("$tmpdir/$user"); 14233 mkpath($home_dir); 14234 my $uid = 500; 14235 my $gid = 500; 14236 14237 my $default_home = File::Spec->rel2abs($tmpdir) . '/%u'; 14238 14239 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 14240 14241 # Build up sqlite3 command to create users, groups tables and populate them 14242 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 14243 14244 if (open(my $fh, "> $db_script")) { 14245 print $fh <<EOS; 14246CREATE TABLE users ( 14247 userid TEXT, 14248 passwd TEXT, 14249 uid INTEGER, 14250 gid INTEGER 14251); 14252INSERT INTO users (userid, passwd, uid, gid) VALUES ('$user', '$passwd', $uid, $gid); 14253 14254EOS 14255 14256 unless (close($fh)) { 14257 die("Can't write $db_script: $!"); 14258 } 14259 14260 } else { 14261 die("Can't open $db_script: $!"); 14262 } 14263 14264 my $cmd = "sqlite3 $db_file < $db_script"; 14265 build_db($cmd, $db_script); 14266 14267 # Make sure that, if we're running as root, the database file has 14268 # the permissions/privs set for use by proftpd 14269 if ($< == 0) { 14270 unless (chmod(0666, $db_file)) { 14271 die("Can't set perms on $db_file to 0666: $!"); 14272 } 14273 } 14274 14275 my $config = { 14276 PidFile => $pid_file, 14277 ScoreboardFile => $scoreboard_file, 14278 SystemLog => $log_file, 14279 14280 IfModules => { 14281 'mod_delay.c' => { 14282 DelayEngine => 'off', 14283 }, 14284 14285 'mod_sql.c' => { 14286 SQLAuthenticate => 'users', 14287 SQLAuthTypes => 'plaintext', 14288 SQLBackend => 'sqlite3', 14289 SQLConnectInfo => $db_file, 14290 SQLLogFile => $log_file, 14291 SQLUserInfo => 'users userid passwd uid gid Null Null', 14292 SQLDefaultHomedir => $default_home, 14293 }, 14294 }, 14295 }; 14296 14297 my ($port, $config_user, $config_group) = config_write($config_file, $config); 14298 14299 # Open pipes, for use between the parent and child processes. Specifically, 14300 # the child will indicate when it's done with its test by writing a message 14301 # to the parent. 14302 my ($rfh, $wfh); 14303 unless (pipe($rfh, $wfh)) { 14304 die("Can't open pipe: $!"); 14305 } 14306 14307 my $ex; 14308 14309 # Fork child 14310 $self->handle_sigchld(); 14311 defined(my $pid = fork()) or die("Can't fork: $!"); 14312 if ($pid) { 14313 eval { 14314 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 14315 $client->login($user, $passwd); 14316 14317 my $resp_msgs = $client->response_msgs(); 14318 my $nmsgs = scalar(@$resp_msgs); 14319 14320 my $expected; 14321 14322 $expected = 1; 14323 $self->assert($expected == $nmsgs, 14324 test_msg("Expected $expected, got $nmsgs")); 14325 14326 $expected = "User proftpd logged in"; 14327 $self->assert($expected eq $resp_msgs->[0], 14328 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 14329 }; 14330 14331 if ($@) { 14332 $ex = $@; 14333 } 14334 14335 $wfh->print("done\n"); 14336 $wfh->flush(); 14337 14338 } else { 14339 eval { server_wait($config_file, $rfh) }; 14340 if ($@) { 14341 warn($@); 14342 exit 1; 14343 } 14344 14345 exit 0; 14346 } 14347 14348 # Stop server 14349 server_stop($pid_file); 14350 14351 $self->assert_child_ok($pid); 14352 14353 if ($ex) { 14354 test_append_logfile($log_file, $ex); 14355 unlink($log_file); 14356 14357 die($ex); 14358 } 14359 14360 unlink($log_file); 14361} 14362 14363sub sql_user_info_null_uid_gid_columns { 14364 my $self = shift; 14365 my $tmpdir = $self->{tmpdir}; 14366 14367 my $config_file = "$tmpdir/sqlite.conf"; 14368 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 14369 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 14370 14371 my $log_file = test_get_logfile(); 14372 14373 my $user = 'proftpd'; 14374 my $passwd = 'test'; 14375 my $group = 'ftpd'; 14376 my $home_dir = File::Spec->rel2abs($tmpdir); 14377 my $uid = 500; 14378 my $gid = 500; 14379 14380 my $default_home = '/tmp'; 14381 my $default_uid = 14; 14382 my $default_gid = 28; 14383 14384 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 14385 14386 # Build up sqlite3 command to create users, groups tables and populate them 14387 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 14388 14389 if (open(my $fh, "> $db_script")) { 14390 print $fh <<EOS; 14391CREATE TABLE users ( 14392 userid TEXT, 14393 passwd TEXT 14394); 14395INSERT INTO users (userid, passwd) VALUES ('$user', '$passwd'); 14396 14397CREATE TABLE groups ( 14398 groupname TEXT, 14399 gid INTEGER, 14400 members TEXT 14401); 14402INSERT INTO groups (groupname, gid, members) VALUES ('$group', $default_gid, '$user'); 14403 14404EOS 14405 14406 unless (close($fh)) { 14407 die("Can't write $db_script: $!"); 14408 } 14409 14410 } else { 14411 die("Can't open $db_script: $!"); 14412 } 14413 14414 my $cmd = "sqlite3 $db_file < $db_script"; 14415 build_db($cmd, $db_script); 14416 14417 # Make sure that, if we're running as root, the database file has 14418 # the permissions/privs set for use by proftpd 14419 if ($< == 0) { 14420 unless (chmod(0666, $db_file)) { 14421 die("Can't set perms on $db_file to 0666: $!"); 14422 } 14423 } 14424 14425 my $config = { 14426 PidFile => $pid_file, 14427 ScoreboardFile => $scoreboard_file, 14428 SystemLog => $log_file, 14429 14430 IfModules => { 14431 'mod_delay.c' => { 14432 DelayEngine => 'off', 14433 }, 14434 14435 'mod_sql.c' => { 14436 SQLAuthenticate => 'users groups', 14437 SQLAuthTypes => 'plaintext', 14438 SQLBackend => 'sqlite3', 14439 SQLConnectInfo => $db_file, 14440 SQLLogFile => $log_file, 14441 SQLUserInfo => 'users userid passwd Null Null Null Null', 14442 SQLDefaultUID => $default_uid, 14443 SQLDefaultGID => $default_gid, 14444 SQLDefaultHomedir => $default_home, 14445 }, 14446 }, 14447 }; 14448 14449 my ($port, $config_user, $config_group) = config_write($config_file, $config); 14450 14451 # Open pipes, for use between the parent and child processes. Specifically, 14452 # the child will indicate when it's done with its test by writing a message 14453 # to the parent. 14454 my ($rfh, $wfh); 14455 unless (pipe($rfh, $wfh)) { 14456 die("Can't open pipe: $!"); 14457 } 14458 14459 my $ex; 14460 14461 # Fork child 14462 $self->handle_sigchld(); 14463 defined(my $pid = fork()) or die("Can't fork: $!"); 14464 if ($pid) { 14465 eval { 14466 sleep(2); 14467 14468 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 14469 $client->login($user, $passwd); 14470 14471 my $resp_msgs = $client->response_msgs(); 14472 my $nmsgs = scalar(@$resp_msgs); 14473 14474 my $expected; 14475 14476 $expected = 1; 14477 $self->assert($expected == $nmsgs, 14478 test_msg("Expected $expected, got $nmsgs")); 14479 14480 $expected = "User proftpd logged in"; 14481 $self->assert($expected eq $resp_msgs->[0], 14482 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 14483 }; 14484 14485 if ($@) { 14486 $ex = $@; 14487 } 14488 14489 $wfh->print("done\n"); 14490 $wfh->flush(); 14491 14492 } else { 14493 eval { server_wait($config_file, $rfh) }; 14494 if ($@) { 14495 warn($@); 14496 exit 1; 14497 } 14498 14499 exit 0; 14500 } 14501 14502 # Stop server 14503 server_stop($pid_file); 14504 14505 $self->assert_child_ok($pid); 14506 14507 if ($ex) { 14508 test_append_logfile($log_file, $ex); 14509 unlink($log_file); 14510 14511 die($ex); 14512 } 14513 14514 unlink($log_file); 14515} 14516 14517sub sql_64_bit_uid_bug4164 { 14518 my $self = shift; 14519 my $tmpdir = $self->{tmpdir}; 14520 14521 my $config_file = "$tmpdir/sqlite.conf"; 14522 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 14523 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 14524 14525 my $log_file = test_get_logfile(); 14526 14527 my $user = 'proftpd'; 14528 my $passwd = 'test'; 14529 my $group = 'ftpd'; 14530 my $home_dir = File::Spec->rel2abs($tmpdir); 14531 14532 # See: https://github.com/proftpd/proftpd/issues/74 14533 my $uid = 25440237859; 14534 my $gid = 500; 14535 14536 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 14537 14538 # Build up sqlite3 command to create users, groups tables and populate them 14539 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 14540 14541 if (open(my $fh, "> $db_script")) { 14542 print $fh <<EOS; 14543CREATE TABLE users ( 14544 userid TEXT, 14545 passwd TEXT, 14546 uid INTEGER, 14547 gid INTEGER, 14548 homedir TEXT, 14549 shell TEXT 14550); 14551INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash'); 14552 14553CREATE TABLE groups ( 14554 groupname TEXT, 14555 gid INTEGER, 14556 members TEXT 14557); 14558INSERT INTO groups (groupname, gid, members) VALUES ('$group', $gid, '$user'); 14559EOS 14560 14561 unless (close($fh)) { 14562 die("Can't write $db_script: $!"); 14563 } 14564 14565 } else { 14566 die("Can't open $db_script: $!"); 14567 } 14568 14569 my $cmd = "sqlite3 $db_file < $db_script"; 14570 build_db($cmd, $db_script); 14571 14572 # Make sure that, if we're running as root, the database file has 14573 # the permissions/privs set for use by proftpd 14574 if ($< == 0) { 14575 unless (chmod(0666, $db_file)) { 14576 die("Can't set perms on $db_file to 0666: $!"); 14577 } 14578 } 14579 14580 my $config = { 14581 PidFile => $pid_file, 14582 ScoreboardFile => $scoreboard_file, 14583 SystemLog => $log_file, 14584 14585 IfModules => { 14586 'mod_delay.c' => { 14587 DelayEngine => 'off', 14588 }, 14589 14590 'mod_sql.c' => { 14591 SQLAuthTypes => 'plaintext', 14592 SQLBackend => 'sqlite3', 14593 SQLConnectInfo => $db_file, 14594 SQLLogFile => $log_file, 14595 SQLMinID => 100, 14596 }, 14597 }, 14598 }; 14599 14600 my ($port, $config_user, $config_group) = config_write($config_file, $config); 14601 14602 # Open pipes, for use between the parent and child processes. Specifically, 14603 # the child will indicate when it's done with its test by writing a message 14604 # to the parent. 14605 my ($rfh, $wfh); 14606 unless (pipe($rfh, $wfh)) { 14607 die("Can't open pipe: $!"); 14608 } 14609 14610 my $ex; 14611 14612 # Fork child 14613 $self->handle_sigchld(); 14614 defined(my $pid = fork()) or die("Can't fork: $!"); 14615 if ($pid) { 14616 eval { 14617 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 14618 $client->login($user, $passwd); 14619 14620 my $resp_msgs = $client->response_msgs(); 14621 my $nmsgs = scalar(@$resp_msgs); 14622 14623 my $expected; 14624 14625 $expected = 1; 14626 $self->assert($expected == $nmsgs, 14627 test_msg("Expected $expected, got $nmsgs")); 14628 14629 $expected = "User proftpd logged in"; 14630 $self->assert($expected eq $resp_msgs->[0], 14631 test_msg("Expected '$expected', got '$resp_msgs->[0]'")); 14632 14633 $client->quit(); 14634 }; 14635 14636 if ($@) { 14637 $ex = $@; 14638 } 14639 14640 $wfh->print("done\n"); 14641 $wfh->flush(); 14642 14643 } else { 14644 eval { server_wait($config_file, $rfh) }; 14645 if ($@) { 14646 warn($@); 14647 exit 1; 14648 } 14649 14650 exit 0; 14651 } 14652 14653 # Stop server 14654 server_stop($pid_file); 14655 14656 $self->assert_child_ok($pid); 14657 14658 if ($ex) { 14659 test_append_logfile($log_file, $ex); 14660 unlink($log_file); 14661 14662 die($ex); 14663 } 14664 14665 unlink($log_file); 14666} 14667 14668sub get_port { 14669 my $db_file = shift; 14670 my $where = shift; 14671 14672 my $sql = "SELECT user, ip_addr, port FROM ftpsessions"; 14673 if ($where) { 14674 $sql .= " WHERE $where"; 14675 } 14676 14677 my $cmd = "sqlite3 $db_file \"$sql\""; 14678 14679 if ($ENV{TEST_VERBOSE}) { 14680 print STDERR "Executing sqlite3: $cmd\n"; 14681 } 14682 14683 my $res = join('', `$cmd`); 14684 chomp($res); 14685 14686 # The default sqlite3 delimiter is '|' 14687 return split(/\|/, $res); 14688} 14689 14690sub sql_sqllog_var_remote_port { 14691 my $self = shift; 14692 my $tmpdir = $self->{tmpdir}; 14693 14694 my $config_file = "$tmpdir/sqlite.conf"; 14695 my $pid_file = File::Spec->rel2abs("$tmpdir/sqlite.pid"); 14696 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlite.scoreboard"); 14697 14698 my $log_file = test_get_logfile(); 14699 14700 my $auth_user_file = File::Spec->rel2abs("$tmpdir/sqlite.passwd"); 14701 my $auth_group_file = File::Spec->rel2abs("$tmpdir/sqlite.group"); 14702 14703 my $user = 'proftpd'; 14704 my $passwd = 'test'; 14705 my $group = 'ftpd'; 14706 my $home_dir = File::Spec->rel2abs($tmpdir); 14707 my $uid = 500; 14708 my $gid = 500; 14709 14710 # Make sure that, if we're running as root, that the home directory has 14711 # permissions/privs set for the account we create 14712 if ($< == 0) { 14713 unless (chmod(0755, $home_dir)) { 14714 die("Can't set perms on $home_dir to 0755: $!"); 14715 } 14716 14717 unless (chown($uid, $gid, $home_dir)) { 14718 die("Can't set owner of $home_dir to $uid/$gid: $!"); 14719 } 14720 } 14721 14722 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 14723 '/bin/bash'); 14724 auth_group_write($auth_group_file, $group, $gid, $user); 14725 14726 my $test_file = File::Spec->rel2abs($config_file); 14727 14728 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 14729 14730 # Build up sqlite3 command to create users, groups tables and populate them 14731 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 14732 14733 if (open(my $fh, "> $db_script")) { 14734 print $fh <<EOS; 14735CREATE TABLE ftpsessions ( 14736 user TEXT, 14737 ip_addr TEXT, 14738 port NUMBER 14739); 14740EOS 14741 14742 unless (close($fh)) { 14743 die("Can't write $db_script: $!"); 14744 } 14745 14746 } else { 14747 die("Can't open $db_script: $!"); 14748 } 14749 14750 my $cmd = "sqlite3 $db_file < $db_script"; 14751 build_db($cmd, $db_script); 14752 14753 # Make sure that, if we're running as root, the database file has 14754 # the permissions/privs set for use by proftpd 14755 if ($< == 0) { 14756 unless (chmod(0666, $db_file)) { 14757 die("Can't set perms on $db_file to 0666: $!"); 14758 } 14759 } 14760 14761 my $config = { 14762 PidFile => $pid_file, 14763 ScoreboardFile => $scoreboard_file, 14764 SystemLog => $log_file, 14765 14766 AuthUserFile => $auth_user_file, 14767 AuthGroupFile => $auth_group_file, 14768 14769 IfModules => { 14770 'mod_delay.c' => { 14771 DelayEngine => 'off', 14772 }, 14773 14774 'mod_sql.c' => { 14775 SQLEngine => 'log', 14776 SQLBackend => 'sqlite3', 14777 SQLConnectInfo => $db_file, 14778 SQLLogFile => $log_file, 14779 SQLNamedQuery => 'filename FREEFORM "INSERT INTO ftpsessions (user, ip_addr, port) VALUES (\'%u\', \'%L\', %{remote-port})"', 14780 SQLLog => 'RETR filename', 14781 }, 14782 }, 14783 }; 14784 14785 my ($port, $config_user, $config_group) = config_write($config_file, $config); 14786 14787 # Open pipes, for use between the parent and child processes. Specifically, 14788 # the child will indicate when it's done with its test by writing a message 14789 # to the parent. 14790 my ($rfh, $wfh); 14791 unless (pipe($rfh, $wfh)) { 14792 die("Can't open pipe: $!"); 14793 } 14794 14795 my $ex; 14796 14797 # Fork child 14798 $self->handle_sigchld(); 14799 defined(my $pid = fork()) or die("Can't fork: $!"); 14800 if ($pid) { 14801 eval { 14802 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 14803 $client->login($user, $passwd); 14804 14805 my $conn = $client->retr_raw($test_file); 14806 unless ($conn) { 14807 die("Failed to RETR: " . $client->response_code() . " " . 14808 $client->response_msg()); 14809 } 14810 14811 my $buf; 14812 $conn->read($buf, 8192, 30); 14813 eval { $conn->close() }; 14814 14815 my $resp_code = $client->response_code(); 14816 my $resp_msg = $client->response_msg(); 14817 $self->assert_transfer_ok($resp_code, $resp_msg); 14818 14819 $client->quit(); 14820 }; 14821 14822 if ($@) { 14823 $ex = $@; 14824 } 14825 14826 $wfh->print("done\n"); 14827 $wfh->flush(); 14828 14829 } else { 14830 eval { server_wait($config_file, $rfh) }; 14831 if ($@) { 14832 warn($@); 14833 exit 1; 14834 } 14835 14836 exit 0; 14837 } 14838 14839 # Stop server 14840 server_stop($pid_file); 14841 $self->assert_child_ok($pid); 14842 14843 if ($ex) { 14844 test_append_logfile($log_file, $ex); 14845 unlink($log_file); 14846 14847 die($ex); 14848 } 14849 14850 my ($login, $ip_addr, $port) = get_port($db_file, "user = \'$user\'"); 14851 14852 my $expected = $user; 14853 $self->assert($expected eq $login, 14854 test_msg("Expected '$expected', got '$login'")); 14855 14856 $expected = '127.0.0.1'; 14857 $self->assert($expected eq $ip_addr, 14858 test_msg("Expected '$expected', got '$ip_addr'")); 14859 14860 $expected = '^\d+$'; 14861 $self->assert(qr/$expected/, $port, 14862 test_msg("Expected '$expected', got '$port'")); 14863 14864 unlink($log_file); 14865} 14866 14867sub get_ftps { 14868 my $db_file = shift; 14869 my $where = shift; 14870 14871 my $sql = "SELECT user, ip_addr, ftps FROM ftpsessions"; 14872 if ($where) { 14873 $sql .= " WHERE $where"; 14874 } 14875 14876 my $cmd = "sqlite3 $db_file \"$sql\""; 14877 14878 if ($ENV{TEST_VERBOSE}) { 14879 print STDERR "Executing sqlite3: $cmd\n"; 14880 } 14881 14882 my $res = join('', `$cmd`); 14883 chomp($res); 14884 14885 # The default sqlite3 delimiter is '|' 14886 return split(/\|/, $res); 14887} 14888 14889sub sql_sqllog_var_note_ftps_without_tls_issue1232 { 14890 my $self = shift; 14891 my $tmpdir = $self->{tmpdir}; 14892 my $setup = test_setup($tmpdir, 'sqlite'); 14893 14894 my $test_file = File::Spec->rel2abs($setup->{config_file}); 14895 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 14896 14897 # Build up sqlite3 command to create users, groups tables and populate them 14898 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 14899 14900 if (open(my $fh, "> $db_script")) { 14901 print $fh <<EOS; 14902CREATE TABLE ftpsessions ( 14903 user TEXT, 14904 ip_addr TEXT, 14905 ftps TEXT 14906); 14907EOS 14908 14909 unless (close($fh)) { 14910 die("Can't write $db_script: $!"); 14911 } 14912 14913 } else { 14914 die("Can't open $db_script: $!"); 14915 } 14916 14917 my $cmd = "sqlite3 $db_file < $db_script"; 14918 build_db($cmd, $db_script); 14919 14920 # Make sure that, if we're running as root, the database file has 14921 # the permissions/privs set for use by proftpd 14922 if ($< == 0) { 14923 unless (chmod(0666, $db_file)) { 14924 die("Can't set perms on $db_file to 0666: $!"); 14925 } 14926 } 14927 14928 my $config = { 14929 PidFile => $setup->{pid_file}, 14930 ScoreboardFile => $setup->{scoreboard_file}, 14931 SystemLog => $setup->{log_file}, 14932 TraceLog => $setup->{log_file}, 14933 14934 AuthUserFile => $setup->{auth_user_file}, 14935 AuthGroupFile => $setup->{auth_group_file}, 14936 14937 IfModules => { 14938 'mod_delay.c' => { 14939 DelayEngine => 'off', 14940 }, 14941 14942 'mod_sql.c' => { 14943 SQLEngine => 'log', 14944 SQLBackend => 'sqlite3', 14945 SQLConnectInfo => $db_file, 14946 SQLLogFile => $setup->{log_file}, 14947 SQLNamedQuery => 'on_login FREEFORM "INSERT INTO ftpsessions (user, ip_addr, ftps) VALUES (\'%u\', \'%L\', \'%{note:FTPS}\')"', 14948 SQLLog => 'PASS on_login', 14949 }, 14950 }, 14951 }; 14952 14953 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 14954 $config); 14955 14956 # Open pipes, for use between the parent and child processes. Specifically, 14957 # the child will indicate when it's done with its test by writing a message 14958 # to the parent. 14959 my ($rfh, $wfh); 14960 unless (pipe($rfh, $wfh)) { 14961 die("Can't open pipe: $!"); 14962 } 14963 14964 my $ex; 14965 14966 # Fork child 14967 $self->handle_sigchld(); 14968 defined(my $pid = fork()) or die("Can't fork: $!"); 14969 if ($pid) { 14970 eval { 14971 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 14972 $client->login($setup->{user}, $setup->{passwd}); 14973 14974 my $conn = $client->retr_raw($test_file); 14975 unless ($conn) { 14976 die("Failed to RETR: " . $client->response_code() . " " . 14977 $client->response_msg()); 14978 } 14979 14980 my $buf; 14981 $conn->read($buf, 8192, 30); 14982 eval { $conn->close() }; 14983 14984 my $resp_code = $client->response_code(); 14985 my $resp_msg = $client->response_msg(); 14986 $self->assert_transfer_ok($resp_code, $resp_msg); 14987 14988 $client->quit(); 14989 }; 14990 if ($@) { 14991 $ex = $@; 14992 } 14993 14994 $wfh->print("done\n"); 14995 $wfh->flush(); 14996 14997 } else { 14998 eval { server_wait($setup->{config_file}, $rfh) }; 14999 if ($@) { 15000 warn($@); 15001 exit 1; 15002 } 15003 15004 exit 0; 15005 } 15006 15007 # Stop server 15008 server_stop($setup->{pid_file}); 15009 $self->assert_child_ok($pid); 15010 15011 test_cleanup($setup->{log_file}, $ex) if $ex; 15012 15013 eval { 15014 my ($login, $ip_addr, $ftps); 15015 ($login, $ip_addr, $ftps) = get_ftps($db_file, "user = \'$setup->{user}\'"); 15016 15017 my $expected = $setup->{user}; 15018 $self->assert($expected eq $login, 15019 test_msg("Expected '$expected', got '$login'")); 15020 15021 $expected = '127.0.0.1'; 15022 $self->assert($expected eq $ip_addr, 15023 test_msg("Expected '$expected', got '$ip_addr'")); 15024 15025 $expected = ''; 15026 $self->assert(qr/$expected/, $ftps, 15027 test_msg("Expected '$expected', got '$ftps'")); 15028 }; 15029 if ($@) { 15030 $ex = $@; 15031 } 15032 15033 test_cleanup($setup->{log_file}, $ex); 15034} 15035 15036sub sql_sqllog_var_note_ftps_with_tls_issue1232 { 15037 my $self = shift; 15038 my $tmpdir = $self->{tmpdir}; 15039 my $setup = test_setup($tmpdir, 'sqlite'); 15040 15041 my $test_file = File::Spec->rel2abs($setup->{config_file}); 15042 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 15043 15044 # Build up sqlite3 command to create users, groups tables and populate them 15045 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 15046 15047 if (open(my $fh, "> $db_script")) { 15048 print $fh <<EOS; 15049CREATE TABLE ftpsessions ( 15050 user TEXT, 15051 ip_addr TEXT, 15052 ftps TEXT 15053); 15054EOS 15055 15056 unless (close($fh)) { 15057 die("Can't write $db_script: $!"); 15058 } 15059 15060 } else { 15061 die("Can't open $db_script: $!"); 15062 } 15063 15064 my $cmd = "sqlite3 $db_file < $db_script"; 15065 build_db($cmd, $db_script); 15066 15067 # Make sure that, if we're running as root, the database file has 15068 # the permissions/privs set for use by proftpd 15069 if ($< == 0) { 15070 unless (chmod(0666, $db_file)) { 15071 die("Can't set perms on $db_file to 0666: $!"); 15072 } 15073 } 15074 15075 my $cert_file = File::Spec->rel2abs('t/etc/modules/mod_tls/server-cert.pem'); 15076 my $ca_file = File::Spec->rel2abs('t/etc/modules/mod_tls/ca-cert.pem'); 15077 15078 my $config = { 15079 PidFile => $setup->{pid_file}, 15080 ScoreboardFile => $setup->{scoreboard_file}, 15081 SystemLog => $setup->{log_file}, 15082 TraceLog => $setup->{log_file}, 15083 Trace => 'jot:30 sql:20 tls:20', 15084 15085 AuthUserFile => $setup->{auth_user_file}, 15086 AuthGroupFile => $setup->{auth_group_file}, 15087 15088 IfModules => { 15089 'mod_delay.c' => { 15090 DelayEngine => 'off', 15091 }, 15092 15093 'mod_sql.c' => { 15094 SQLEngine => 'log', 15095 SQLBackend => 'sqlite3', 15096 SQLConnectInfo => $db_file, 15097 SQLLogFile => $setup->{log_file}, 15098 SQLNamedQuery => 'on_login FREEFORM "INSERT INTO ftpsessions (user, ip_addr, ftps) VALUES (\'%u\', \'%L\', \'%{note:FTPS}\')"', 15099 SQLLog => 'PASS on_login', 15100 }, 15101 15102 'mod_tls.c' => { 15103 TLSEngine => 'on', 15104 TLSLog => $setup->{log_file}, 15105 TLSRequired => 'on', 15106 TLSRSACertificateFile => $cert_file, 15107 TLSCACertificateFile => $ca_file, 15108 }, 15109 }, 15110 }; 15111 15112 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 15113 $config); 15114 15115 # Open pipes, for use between the parent and child processes. Specifically, 15116 # the child will indicate when it's done with its test by writing a message 15117 # to the parent. 15118 my ($rfh, $wfh); 15119 unless (pipe($rfh, $wfh)) { 15120 die("Can't open pipe: $!"); 15121 } 15122 15123 require Net::FTPSSL; 15124 15125 my $ex; 15126 15127 # Fork child 15128 $self->handle_sigchld(); 15129 defined(my $pid = fork()) or die("Can't fork: $!"); 15130 if ($pid) { 15131 eval { 15132 # Give the server a chance to start up 15133 sleep(2); 15134 15135 my $client = Net::FTPSSL->new('127.0.0.1', 15136 Encryption => 'E', 15137 Port => $port, 15138 ); 15139 15140 unless ($client) { 15141 die("Can't connect to FTPS server: " . IO::Socket::SSL::errstr()); 15142 } 15143 15144 unless ($client->login($setup->{user}, $setup->{passwd})) { 15145 die("Login failed unexpectedly: " + $client->message()); 15146 } 15147 15148 $client->quit(); 15149 }; 15150 if ($@) { 15151 $ex = $@; 15152 } 15153 15154 $wfh->print("done\n"); 15155 $wfh->flush(); 15156 15157 } else { 15158 eval { server_wait($setup->{config_file}, $rfh) }; 15159 if ($@) { 15160 warn($@); 15161 exit 1; 15162 } 15163 15164 exit 0; 15165 } 15166 15167 # Stop server 15168 server_stop($setup->{pid_file}); 15169 $self->assert_child_ok($pid); 15170 15171 test_cleanup($setup->{log_file}, $ex) if $ex; 15172 15173 eval { 15174 my ($login, $ip_addr, $ftps); 15175 ($login, $ip_addr, $ftps) = get_ftps($db_file, "user = \'$setup->{user}\'"); 15176 15177 my $expected = $setup->{user}; 15178 $self->assert($expected eq $login, 15179 test_msg("Expected '$expected', got '$login'")); 15180 15181 $expected = '127.0.0.1'; 15182 $self->assert($expected eq $ip_addr, 15183 test_msg("Expected '$expected', got '$ip_addr'")); 15184 15185 $expected = '1'; 15186 $self->assert(qr/$expected/, $ftps, 15187 test_msg("Expected '$expected', got '$ftps'")); 15188 }; 15189 if ($@) { 15190 $ex = $@; 15191 } 15192 15193 test_cleanup($setup->{log_file}, $ex); 15194} 15195 15196sub sql_userowner_issue346 { 15197 my $self = shift; 15198 my $tmpdir = $self->{tmpdir}; 15199 my $setup = test_setup($tmpdir, 'sqlite'); 15200 15201 my $uid = 0; 15202 my $gid = 0; 15203 15204 my $test_file = File::Spec->rel2abs("$tmpdir/test.dat"); 15205 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 15206 15207 # Build up sqlite3 command to create users, groups tables and populate them 15208 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 15209 15210 if (open(my $fh, "> $db_script")) { 15211 print $fh <<EOS; 15212CREATE TABLE users ( 15213 userid TEXT, 15214 passwd TEXT, 15215 uid INTEGER, 15216 gid INTEGER, 15217 homedir TEXT, 15218 shell TEXT, 15219 lastdir TEXT 15220); 15221INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$setup->{user}', '$setup->{passwd}', $uid, $gid, '$setup->{home_dir}', '/bin/bash'); 15222 15223CREATE TABLE groups ( 15224 groupname TEXT, 15225 gid INTEGER, 15226 members TEXT 15227); 15228INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $gid, '$setup->{user}'); 15229EOS 15230 15231 unless (close($fh)) { 15232 die("Can't write $db_script: $!"); 15233 } 15234 15235 } else { 15236 die("Can't open $db_script: $!"); 15237 } 15238 15239 my $cmd = "sqlite3 $db_file < $db_script"; 15240 build_db($cmd, $db_script); 15241 15242 # Make sure that, if we're running as root, the database file has 15243 # the permissions/privs set for use by proftpd 15244 if ($< == 0) { 15245 unless (chmod(0666, $db_file)) { 15246 die("Can't set perms on $db_file to 0666: $!"); 15247 } 15248 } 15249 15250 my $config = { 15251 PidFile => $setup->{pid_file}, 15252 ScoreboardFile => $setup->{scoreboard_file}, 15253 SystemLog => $setup->{log_file}, 15254 15255 RootLogin => 'on', 15256 RootRevoke => 'off', 15257 15258 Directory => { 15259 '/' => { 15260 UserOwner => 'www', 15261 GroupOwner => 'www', 15262 }, 15263 }, 15264 15265 IfModules => { 15266 'mod_delay.c' => { 15267 DelayEngine => 'off', 15268 }, 15269 15270 'mod_sql.c' => { 15271 SQLAuthTypes => 'plaintext', 15272 SQLBackend => 'sqlite3', 15273 SQLConnectInfo => $db_file, 15274 SQLLogFile => $setup->{log_file}, 15275 SQLMinUserUID => 0, 15276 SQLMinUserGID => 0, 15277 SQLMinID => 0, 15278 }, 15279 }, 15280 }; 15281 15282 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 15283 $config); 15284 15285 # Open pipes, for use between the parent and child processes. Specifically, 15286 # the child will indicate when it's done with its test by writing a message 15287 # to the parent. 15288 my ($rfh, $wfh); 15289 unless (pipe($rfh, $wfh)) { 15290 die("Can't open pipe: $!"); 15291 } 15292 15293 my $ex; 15294 15295 # Fork child 15296 $self->handle_sigchld(); 15297 defined(my $pid = fork()) or die("Can't fork: $!"); 15298 if ($pid) { 15299 eval { 15300 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0); 15301 $client->login($setup->{user}, $setup->{passwd}); 15302 15303 my $conn = $client->stor_raw('test.dat'); 15304 unless ($conn) { 15305 die("STOR test.dat failed: " . $client->response_code() . " " . 15306 $client->response_msg()); 15307 } 15308 15309 my $text = "Hello, World!\n"; 15310 $conn->write($text, length($text), 10); 15311 eval { $conn->close() }; 15312 15313 my $resp_code = $client->response_code(); 15314 my $resp_msg = $client->response_msg(); 15315 $self->assert_transfer_ok($resp_code, $resp_msg); 15316 $client->quit(); 15317 15318 $self->assert(-f $test_file, 15319 "File $test_file does not exist as expected"); 15320 15321 my $file_uid = (stat($test_file))[4]; 15322 my $file_gid = (stat($test_file))[5]; 15323 15324 $self->assert($file_uid != 0, "Expected UID non-0, got $file_uid"); 15325 $self->assert($file_gid != 0, "Expected GID non-0, got $file_gid"); 15326 }; 15327 15328 if ($@) { 15329 $ex = $@; 15330 } 15331 15332 $wfh->print("done\n"); 15333 $wfh->flush(); 15334 15335 } else { 15336 eval { server_wait($setup->{config_file}, $rfh) }; 15337 if ($@) { 15338 warn($@); 15339 exit 1; 15340 } 15341 15342 exit 0; 15343 } 15344 15345 # Stop server 15346 server_stop($setup->{pid_file}); 15347 $self->assert_child_ok($pid); 15348 15349 test_cleanup($setup->{log_file}, $ex); 15350} 15351 15352sub sql_sqlite_log_db_enoent_issue654 { 15353 my $self = shift; 15354 my $tmpdir = $self->{tmpdir}; 15355 my $setup = test_setup($tmpdir, 'sqlite'); 15356 15357 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 15358 15359 my $config = { 15360 PidFile => $setup->{pid_file}, 15361 ScoreboardFile => $setup->{scoreboard_file}, 15362 SystemLog => $setup->{log_file}, 15363 TraceLog => $setup->{log_file}, 15364 Trace => 'sql:20', 15365 15366 AuthUserFile => $setup->{auth_user_file}, 15367 AuthGroupFile => $setup->{auth_group_file}, 15368 15369 IfModules => { 15370 'mod_delay.c' => { 15371 DelayEngine => 'off', 15372 }, 15373 15374 'mod_sql.c' => { 15375 SQLEngine => 'log', 15376 SQLBackend => 'sqlite3', 15377 SQLConnectInfo => $db_file, 15378 SQLLogFile => $setup->{log_file}, 15379 SQLNamedQuery => 'session_start FREEFORM "INSERT INTO ftpsessions (user, ip_addr, timestamp) VALUES (\'%u\', \'%L\', \'%{time:%Y-%m-%d %H:%M:%S}\')"', 15380 SQLLog => 'PASS session_start', 15381 }, 15382 }, 15383 }; 15384 15385 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 15386 $config); 15387 15388 # Open pipes, for use between the parent and child processes. Specifically, 15389 # the child will indicate when it's done with its test by writing a message 15390 # to the parent. 15391 my ($rfh, $wfh); 15392 unless (pipe($rfh, $wfh)) { 15393 die("Can't open pipe: $!"); 15394 } 15395 15396 my $ex; 15397 15398 # Fork child 15399 $self->handle_sigchld(); 15400 defined(my $pid = fork()) or die("Can't fork: $!"); 15401 if ($pid) { 15402 eval { 15403 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 15404 eval { $client->login($setup->{user}, $setup->{passwd}) }; 15405 unless ($@) { 15406 $client->quit(); 15407 die("Login succeeded unexpectedly"); 15408 } 15409 }; 15410 if ($@) { 15411 $ex = $@; 15412 } 15413 15414 $wfh->print("done\n"); 15415 $wfh->flush(); 15416 15417 } else { 15418 eval { server_wait($setup->{config_file}, $rfh) }; 15419 if ($@) { 15420 warn($@); 15421 exit 1; 15422 } 15423 15424 exit 0; 15425 } 15426 15427 # Stop server 15428 server_stop($setup->{pid_file}); 15429 $self->assert_child_ok($pid); 15430 15431 test_cleanup($setup->{log_file}, $ex); 15432} 15433 15434sub sql_namebased_vhost_using_host_issue882 { 15435 my $self = shift; 15436 my $tmpdir = $self->{tmpdir}; 15437 my $setup = test_setup($tmpdir, 'sqlite'); 15438 15439 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 15440 15441 # Build up sqlite3 command to create users, groups tables and populate them 15442 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 15443 15444 if (open(my $fh, "> $db_script")) { 15445 print $fh <<EOS; 15446CREATE TABLE users ( 15447 userid TEXT, 15448 passwd TEXT, 15449 uid INTEGER, 15450 gid INTEGER, 15451 homedir TEXT, 15452 shell TEXT, 15453 lastdir TEXT 15454); 15455INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$setup->{user}', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash'); 15456CREATE TABLE groups ( 15457 groupname TEXT, 15458 gid INTEGER, 15459 members TEXT 15460); 15461INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); 15462EOS 15463 15464 unless (close($fh)) { 15465 die("Can't write $db_script: $!"); 15466 } 15467 15468 } else { 15469 die("Can't open $db_script: $!"); 15470 } 15471 15472 my $cmd = "sqlite3 $db_file < $db_script"; 15473 build_db($cmd, $db_script); 15474 15475 # Make sure that, if we're running as root, the database file has 15476 # the permissions/privs set for use by proftpd 15477 if ($< == 0) { 15478 unless (chmod(0666, $db_file)) { 15479 die("Can't set perms on $db_file to 0666: $!"); 15480 } 15481 } 15482 15483 my $config = { 15484 PidFile => $setup->{pid_file}, 15485 ScoreboardFile => $setup->{scoreboard_file}, 15486 SystemLog => $setup->{log_file}, 15487 TraceLog => $setup->{log_file}, 15488 Trace => 'sql:20', 15489 15490 AuthUserFile => $setup->{auth_user_file}, 15491 AuthGroupFile => $setup->{auth_group_file}, 15492 15493 Global => { 15494 AuthOrder => 'mod_sql.c', 15495 SQLAuthTypes => 'plaintext', 15496 SQLEngine => 'on', 15497 SQLBackend => 'sqlite3', 15498 SQLConnectInfo => $db_file, 15499 SQLLogFile => $setup->{log_file}, 15500 }, 15501 15502 IfModules => { 15503 'mod_delay.c' => { 15504 DelayEngine => 'off', 15505 }, 15506 }, 15507 }; 15508 15509 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 15510 $config); 15511 15512 my $server_alias = 'ftp.example.com'; 15513 15514 if (open(my $fh, ">> $setup->{config_file}")) { 15515 print $fh <<EOC; 15516<VirtualHost 127.0.0.1> 15517 Port $port 15518 ServerAlias $server_alias 15519 WtmpLog off 15520 TransferLog none 15521</VirtualHost> 15522EOC 15523 } else { 15524 die("Can't open $setup->{config_file}: $!"); 15525 } 15526 15527 # Open pipes, for use between the parent and child processes. Specifically, 15528 # the child will indicate when it's done with its test by writing a message 15529 # to the parent. 15530 my ($rfh, $wfh); 15531 unless (pipe($rfh, $wfh)) { 15532 die("Can't open pipe: $!"); 15533 } 15534 15535 my $ex; 15536 15537 # Fork child 15538 $self->handle_sigchld(); 15539 defined(my $pid = fork()) or die("Can't fork: $!"); 15540 if ($pid) { 15541 eval { 15542 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 15543 $client->host($server_alias); 15544 $client->login($setup->{user}, $setup->{passwd}); 15545 $client->quit(); 15546 }; 15547 if ($@) { 15548 $ex = $@; 15549 } 15550 15551 $wfh->print("done\n"); 15552 $wfh->flush(); 15553 15554 } else { 15555 eval { server_wait($setup->{config_file}, $rfh) }; 15556 if ($@) { 15557 warn($@); 15558 exit 1; 15559 } 15560 15561 exit 0; 15562 } 15563 15564 # Stop server 15565 server_stop($setup->{pid_file}); 15566 $self->assert_child_ok($pid); 15567 15568 test_cleanup($setup->{log_file}, $ex); 15569} 15570 15571sub sql_namebased_vhost_using_sni_issue882 { 15572 my $self = shift; 15573 my $tmpdir = $self->{tmpdir}; 15574 my $setup = test_setup($tmpdir, 'sqlite'); 15575 15576 my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db"); 15577 15578 # Build up sqlite3 command to create users, groups tables and populate them 15579 my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql"); 15580 15581 if (open(my $fh, "> $db_script")) { 15582 print $fh <<EOS; 15583CREATE TABLE users ( 15584 userid TEXT, 15585 passwd TEXT, 15586 uid INTEGER, 15587 gid INTEGER, 15588 homedir TEXT, 15589 shell TEXT, 15590 lastdir TEXT 15591); 15592INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$setup->{user}', '$setup->{passwd}', $setup->{uid}, $setup->{gid}, '$setup->{home_dir}', '/bin/bash'); 15593CREATE TABLE groups ( 15594 groupname TEXT, 15595 gid INTEGER, 15596 members TEXT 15597); 15598INSERT INTO groups (groupname, gid, members) VALUES ('$setup->{group}', $setup->{gid}, '$setup->{user}'); 15599EOS 15600 15601 unless (close($fh)) { 15602 die("Can't write $db_script: $!"); 15603 } 15604 15605 } else { 15606 die("Can't open $db_script: $!"); 15607 } 15608 15609 my $cmd = "sqlite3 $db_file < $db_script"; 15610 build_db($cmd, $db_script); 15611 15612 # Make sure that, if we're running as root, the database file has 15613 # the permissions/privs set for use by proftpd 15614 if ($< == 0) { 15615 unless (chmod(0666, $db_file)) { 15616 die("Can't set perms on $db_file to 0666: $!"); 15617 } 15618 } 15619 15620 my $cert_file = File::Spec->rel2abs('t/etc/modules/mod_tls/server-cert.pem'); 15621 my $ca_file = File::Spec->rel2abs('t/etc/modules/mod_tls/ca-cert.pem'); 15622 15623 my $config = { 15624 PidFile => $setup->{pid_file}, 15625 ScoreboardFile => $setup->{scoreboard_file}, 15626 SystemLog => $setup->{log_file}, 15627 TraceLog => $setup->{log_file}, 15628 Trace => 'command:20 event:20 sql:20 tls:20', 15629 15630 AuthUserFile => $setup->{auth_user_file}, 15631 AuthGroupFile => $setup->{auth_group_file}, 15632 15633 Global => { 15634 AuthOrder => 'mod_sql.c', 15635 SQLAuthTypes => 'plaintext', 15636 SQLEngine => 'on', 15637 SQLBackend => 'sqlite3', 15638 SQLConnectInfo => $db_file, 15639 SQLLogFile => $setup->{log_file}, 15640 }, 15641 15642 IfModules => { 15643 'mod_delay.c' => { 15644 DelayEngine => 'off', 15645 }, 15646 15647 'mod_tls.c' => { 15648 TLSEngine => 'on', 15649 TLSLog => $setup->{log_file}, 15650 TLSRequired => 'on', 15651 TLSRSACertificateFile => $cert_file, 15652 TLSCACertificateFile => $ca_file, 15653 }, 15654 }, 15655 }; 15656 15657 my ($port, $config_user, $config_group) = config_write($setup->{config_file}, 15658 $config); 15659 15660 my $server_alias = 'ftp.example.com'; 15661 15662 if (open(my $fh, ">> $setup->{config_file}")) { 15663 print $fh <<EOC; 15664<VirtualHost 127.0.0.1> 15665 Port $port 15666 ServerAlias $server_alias 15667 WtmpLog off 15668 TransferLog none 15669</VirtualHost> 15670EOC 15671 } else { 15672 die("Can't open $setup->{config_file}: $!"); 15673 } 15674 15675 # Open pipes, for use between the parent and child processes. Specifically, 15676 # the child will indicate when it's done with its test by writing a message 15677 # to the parent. 15678 my ($rfh, $wfh); 15679 unless (pipe($rfh, $wfh)) { 15680 die("Can't open pipe: $!"); 15681 } 15682 15683 require Net::FTPSSL; 15684 15685 my $ex; 15686 15687 # Fork child 15688 $self->handle_sigchld(); 15689 defined(my $pid = fork()) or die("Can't fork: $!"); 15690 if ($pid) { 15691 eval { 15692 # Give the server a chance to start up 15693 sleep(2); 15694 15695 my $client = Net::FTPSSL->new('127.0.0.1', 15696 Encryption => 'E', 15697 Port => $port, 15698 SSL_hostname => $server_alias, 15699 ); 15700 15701 unless ($client) { 15702 die("Can't connect to FTPS server: " . IO::Socket::SSL::errstr()); 15703 } 15704 15705 unless ($client->login($setup->{user}, $setup->{passwd})) { 15706 die("Login failed unexpectedly: " + $client->message()); 15707 } 15708 15709 $client->quit(); 15710 }; 15711 if ($@) { 15712 $ex = $@; 15713 } 15714 15715 $wfh->print("done\n"); 15716 $wfh->flush(); 15717 15718 } else { 15719 eval { server_wait($setup->{config_file}, $rfh) }; 15720 if ($@) { 15721 warn($@); 15722 exit 1; 15723 } 15724 15725 exit 0; 15726 } 15727 15728 # Stop server 15729 server_stop($setup->{pid_file}); 15730 $self->assert_child_ok($pid); 15731 15732 test_cleanup($setup->{log_file}, $ex); 15733} 15734 157351; 15736