source: src/router/proftpd/tests/t/lib/ProFTPD/Tests/Modules/mod_sql_passwd.pm @ 14674

Last change on this file since 14674 was 14674, checked in by BrainSlayer, 3 years ago

test cases

File size: 65.5 KB
Line 
1package ProFTPD::Tests::Modules::mod_sql_passwd;
2
3use lib qw(t/lib);
4use base qw(Test::Unit::TestCase ProFTPD::TestSuite::Child);
5use strict;
6
7use File::Path qw(mkpath rmtree);
8use File::Spec;
9use IO::Handle;
10
11use ProFTPD::TestSuite::FTP;
12use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
13
14$| = 1;
15
16my $order = 0;
17
18my $TESTS = {
19  sql_passwd_md5_base64 => {
20    order => ++$order,
21    test_class => [qw(forking)],
22  },
23
24  sql_passwd_md5_hex_lc => {
25    order => ++$order,
26    test_class => [qw(forking)],
27  },
28
29  sql_passwd_md5_hex_uc => {
30    order => ++$order,
31    test_class => [qw(forking)],
32  },
33
34  sql_passwd_sha1_base64 => {
35    order => ++$order,
36    test_class => [qw(forking)],
37  },
38
39  sql_passwd_sha1_hex_lc => {
40    order => ++$order,
41    test_class => [qw(forking)],
42  },
43
44  sql_passwd_sha1_hex_uc => {
45    order => ++$order,
46    test_class => [qw(forking)],
47  },
48
49  sql_passwd_engine_off => {
50    order => ++$order,
51    test_class => [qw(forking)],
52  },
53
54  sql_passwd_salt_file => {
55    order => ++$order,
56    test_class => [qw(forking)],
57  },
58
59  sql_passwd_salt_file_trailing_newline => {
60    order => ++$order,
61    test_class => [qw(forking)],
62  },
63
64  sql_passwd_salt_file_prepend => {
65    order => ++$order,
66    test_class => [qw(forking)],
67  },
68
69  sql_passwd_sha256_base64_bug3344 => {
70    order => ++$order,
71    test_class => [qw(forking)],
72  },
73
74  sql_passwd_sha256_hex_lc_bug3344 => {
75    order => ++$order,
76    test_class => [qw(forking)],
77  },
78
79  sql_passwd_sha256_hex_uc_bug3344 => {
80    order => ++$order,
81    test_class => [qw(forking)],
82  },
83
84  sql_passwd_sha512_base64_bug3344 => {
85    order => ++$order,
86    test_class => [qw(forking)],
87  },
88
89  sql_passwd_sha512_hex_lc_bug3344 => {
90    order => ++$order,
91    test_class => [qw(forking)],
92  },
93
94  sql_passwd_sha512_hex_uc_bug3344 => {
95    order => ++$order,
96    test_class => [qw(forking)],
97  },
98
99  sql_passwd_user_salt_name => {
100    order => ++$order,
101    test_class => [qw(forking)],
102  },
103
104  sql_passwd_user_salt_sql => {
105    order => ++$order,
106    test_class => [qw(forking)],
107  },
108
109};
110
111sub new {
112  return shift()->SUPER::new(@_);
113}
114
115sub list_tests {
116  return testsuite_get_runnable_tests($TESTS);
117}
118
119sub set_up {
120  my $self = shift;
121  $self->{tmpdir} = testsuite_get_tmp_dir();
122
123  # Create temporary scratch dir
124  eval { mkpath($self->{tmpdir}) };
125  if ($@) {
126    my $abs_path = File::Spec->rel2abs($self->{tmpdir});
127    die("Can't create dir $abs_path: $@");
128  }
129}
130
131sub tear_down {
132  my $self = shift;
133
134  # Remove temporary scratch dir
135  if ($self->{tmpdir}) {
136    eval { rmtree($self->{tmpdir}) };
137  }
138
139  undef $self;
140}
141
142sub sql_passwd_md5_base64 {
143  my $self = shift;
144  my $tmpdir = $self->{tmpdir};
145
146  my $config_file = "$tmpdir/sqlpasswd.conf";
147  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
148  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
149
150  my $log_file = File::Spec->rel2abs('tests.log');
151
152  my $user = 'proftpd';
153
154  # I used:
155  #
156  #  `/bin/echo -n "test" | openssl dgst -binary -md5 | openssl enc -base64`
157  #
158  # to generate this password.
159  my $passwd = 'CY9rzUYh03PK3k6DJie09g==';
160
161  my $home_dir = File::Spec->rel2abs($tmpdir);
162  my $uid = 500;
163  my $gid = 500;
164
165  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
166
167  # Build up sqlite3 command to create users, groups tables and populate them
168  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
169
170  if (open(my $fh, "> $db_script")) {
171    print $fh <<EOS;
172CREATE TABLE users (
173  userid TEXT,
174  passwd TEXT,
175  uid INTEGER,
176  gid INTEGER,
177  homedir TEXT,
178  shell TEXT
179);
180INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
181
182CREATE TABLE groups (
183  groupname TEXT,
184  gid INTEGER,
185  members TEXT
186);
187INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
188EOS
189
190    unless (close($fh)) {
191      die("Can't write $db_script: $!");
192    }
193
194  } else {
195    die("Can't open $db_script: $!");
196  }
197
198  my $cmd = "sqlite3 $db_file < $db_script";
199
200  if ($ENV{TEST_VERBOSE}) {
201    print STDERR "Executing sqlite3: $cmd\n";
202  }
203
204  my @output = `$cmd`;
205  if (scalar(@output) &&
206      $ENV{TEST_VERBOSE}) {
207    print STDERR "Output: ", join('', @output), "\n";
208  }
209
210  my $config = {
211    PidFile => $pid_file,
212    ScoreboardFile => $scoreboard_file,
213    SystemLog => $log_file,
214
215    IfModules => {
216      'mod_delay.c' => {
217        DelayEngine => 'off',
218      },
219
220      'mod_sql.c' => {
221        SQLAuthTypes => 'md5',
222        SQLBackend => 'sqlite3',
223        SQLConnectInfo => $db_file,
224        SQLLogFile => $log_file,
225      },
226
227      'mod_sql_passwd.c' => {
228        SQLPasswordEngine => 'on',
229        SQLPasswordEncoding => 'base64',
230      },
231    },
232  };
233
234  my ($port, $config_user, $config_group) = config_write($config_file, $config);
235
236  # Open pipes, for use between the parent and child processes.  Specifically,
237  # the child will indicate when it's done with its test by writing a message
238  # to the parent.
239  my ($rfh, $wfh);
240  unless (pipe($rfh, $wfh)) {
241    die("Can't open pipe: $!");
242  }
243
244  my $ex;
245
246  # Fork child
247  $self->handle_sigchld();
248  defined(my $pid = fork()) or die("Can't fork: $!");
249  if ($pid) {
250    eval {
251      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
252      $client->login($user, "test");
253
254      my $resp_msgs = $client->response_msgs();
255      my $nmsgs = scalar(@$resp_msgs);
256
257      my $expected;
258
259      $expected = 1;
260      $self->assert($expected == $nmsgs,
261        test_msg("Expected $expected, got $nmsgs"));
262
263      $expected = "User proftpd logged in";
264      $self->assert($expected eq $resp_msgs->[0],
265        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
266
267    };
268
269    if ($@) {
270      $ex = $@;
271    }
272
273    $wfh->print("done\n");
274    $wfh->flush();
275
276  } else {
277    eval { server_wait($config_file, $rfh) };
278    if ($@) {
279      warn($@);
280      exit 1;
281    }
282
283    exit 0;
284  }
285
286  # Stop server
287  server_stop($pid_file);
288
289  $self->assert_child_ok($pid);
290
291  if ($ex) {
292    die($ex);
293  }
294
295  unlink($log_file);
296}
297
298sub sql_passwd_md5_hex_lc {
299  my $self = shift;
300  my $tmpdir = $self->{tmpdir};
301
302  my $config_file = "$tmpdir/sqlpasswd.conf";
303  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
304  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
305
306  my $log_file = File::Spec->rel2abs('tests.log');
307
308  my $user = 'proftpd';
309
310  # I used:
311  #
312  #  `/bin/echo -n "test" | openssl dgst -hex -md5`
313  #
314  # to generate this password.
315  my $passwd = '098f6bcd4621d373cade4e832627b4f6';
316
317  my $home_dir = File::Spec->rel2abs($tmpdir);
318  my $uid = 500;
319  my $gid = 500;
320
321  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
322
323  # Build up sqlite3 command to create users, groups tables and populate them
324  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
325
326  if (open(my $fh, "> $db_script")) {
327    print $fh <<EOS;
328CREATE TABLE users (
329  userid TEXT,
330  passwd TEXT,
331  uid INTEGER,
332  gid INTEGER,
333  homedir TEXT,
334  shell TEXT
335);
336INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
337
338CREATE TABLE groups (
339  groupname TEXT,
340  gid INTEGER,
341  members TEXT
342);
343INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
344EOS
345
346    unless (close($fh)) {
347      die("Can't write $db_script: $!");
348    }
349
350  } else {
351    die("Can't open $db_script: $!");
352  }
353
354  my $cmd = "sqlite3 $db_file < $db_script";
355
356  if ($ENV{TEST_VERBOSE}) {
357    print STDERR "Executing sqlite3: $cmd\n";
358  }
359
360  my @output = `$cmd`;
361  if (scalar(@output) &&
362      $ENV{TEST_VERBOSE}) {
363    print STDERR "Output: ", join('', @output), "\n";
364  }
365
366  my $config = {
367    PidFile => $pid_file,
368    ScoreboardFile => $scoreboard_file,
369    SystemLog => $log_file,
370
371    IfModules => {
372      'mod_delay.c' => {
373        DelayEngine => 'off',
374      },
375
376      'mod_sql.c' => {
377        SQLAuthTypes => 'md5',
378        SQLBackend => 'sqlite3',
379        SQLConnectInfo => $db_file,
380        SQLLogFile => $log_file,
381      },
382
383      'mod_sql_passwd.c' => {
384        SQLPasswordEngine => 'on',
385        SQLPasswordEncoding => 'hex',
386      },
387    },
388  };
389
390  my ($port, $config_user, $config_group) = config_write($config_file, $config);
391
392  # Open pipes, for use between the parent and child processes.  Specifically,
393  # the child will indicate when it's done with its test by writing a message
394  # to the parent.
395  my ($rfh, $wfh);
396  unless (pipe($rfh, $wfh)) {
397    die("Can't open pipe: $!");
398  }
399
400  my $ex;
401
402  # Fork child
403  $self->handle_sigchld();
404  defined(my $pid = fork()) or die("Can't fork: $!");
405  if ($pid) {
406    eval {
407      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
408      $client->login($user, "test");
409
410      my $resp_msgs = $client->response_msgs();
411      my $nmsgs = scalar(@$resp_msgs);
412
413      my $expected;
414
415      $expected = 1;
416      $self->assert($expected == $nmsgs,
417        test_msg("Expected $expected, got $nmsgs"));
418
419      $expected = "User proftpd logged in";
420      $self->assert($expected eq $resp_msgs->[0],
421        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
422
423    };
424
425    if ($@) {
426      $ex = $@;
427    }
428
429    $wfh->print("done\n");
430    $wfh->flush();
431
432  } else {
433    eval { server_wait($config_file, $rfh) };
434    if ($@) {
435      warn($@);
436      exit 1;
437    }
438
439    exit 0;
440  }
441
442  # Stop server
443  server_stop($pid_file);
444
445  $self->assert_child_ok($pid);
446
447  if ($ex) {
448    die($ex);
449  }
450
451  unlink($log_file);
452}
453
454sub sql_passwd_md5_hex_uc {
455  my $self = shift;
456  my $tmpdir = $self->{tmpdir};
457
458  my $config_file = "$tmpdir/sqlpasswd.conf";
459  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
460  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
461
462  my $log_file = File::Spec->rel2abs('tests.log');
463
464  my $user = 'proftpd';
465
466  # I used:
467  #
468  #  `/bin/echo -n "test" | openssl dgst -hex -md5`
469  #
470  # to generate this password.  Then I manually made all of the letters be
471  # in uppercase.  Tedious.
472  my $passwd = '098F6BCD4621D373CADE4E832627B4F6';
473
474  my $home_dir = File::Spec->rel2abs($tmpdir);
475  my $uid = 500;
476  my $gid = 500;
477
478  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
479
480  # Build up sqlite3 command to create users, groups tables and populate them
481  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
482
483  if (open(my $fh, "> $db_script")) {
484    print $fh <<EOS;
485CREATE TABLE users (
486  userid TEXT,
487  passwd TEXT,
488  uid INTEGER,
489  gid INTEGER,
490  homedir TEXT,
491  shell TEXT
492);
493INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
494
495CREATE TABLE groups (
496  groupname TEXT,
497  gid INTEGER,
498  members TEXT
499);
500INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
501EOS
502
503    unless (close($fh)) {
504      die("Can't write $db_script: $!");
505    }
506
507  } else {
508    die("Can't open $db_script: $!");
509  }
510
511  my $cmd = "sqlite3 $db_file < $db_script";
512
513  if ($ENV{TEST_VERBOSE}) {
514    print STDERR "Executing sqlite3: $cmd\n";
515  }
516
517  my @output = `$cmd`;
518  if (scalar(@output) &&
519      $ENV{TEST_VERBOSE}) {
520    print STDERR "Output: ", join('', @output), "\n";
521  }
522
523  my $config = {
524    PidFile => $pid_file,
525    ScoreboardFile => $scoreboard_file,
526    SystemLog => $log_file,
527
528    IfModules => {
529      'mod_delay.c' => {
530        DelayEngine => 'off',
531      },
532
533      'mod_sql.c' => {
534        SQLAuthTypes => 'md5',
535        SQLBackend => 'sqlite3',
536        SQLConnectInfo => $db_file,
537        SQLLogFile => $log_file,
538      },
539
540      'mod_sql_passwd.c' => {
541        SQLPasswordEngine => 'on',
542        SQLPasswordEncoding => 'HEX',
543      },
544    },
545  };
546
547  my ($port, $config_user, $config_group) = config_write($config_file, $config);
548
549  # Open pipes, for use between the parent and child processes.  Specifically,
550  # the child will indicate when it's done with its test by writing a message
551  # to the parent.
552  my ($rfh, $wfh);
553  unless (pipe($rfh, $wfh)) {
554    die("Can't open pipe: $!");
555  }
556
557  my $ex;
558
559  # Fork child
560  $self->handle_sigchld();
561  defined(my $pid = fork()) or die("Can't fork: $!");
562  if ($pid) {
563    eval {
564      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
565      $client->login($user, "test");
566
567      my $resp_msgs = $client->response_msgs();
568      my $nmsgs = scalar(@$resp_msgs);
569
570      my $expected;
571
572      $expected = 1;
573      $self->assert($expected == $nmsgs,
574        test_msg("Expected $expected, got $nmsgs"));
575
576      $expected = "User proftpd logged in";
577      $self->assert($expected eq $resp_msgs->[0],
578        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
579
580    };
581
582    if ($@) {
583      $ex = $@;
584    }
585
586    $wfh->print("done\n");
587    $wfh->flush();
588
589  } else {
590    eval { server_wait($config_file, $rfh) };
591    if ($@) {
592      warn($@);
593      exit 1;
594    }
595
596    exit 0;
597  }
598
599  # Stop server
600  server_stop($pid_file);
601
602  $self->assert_child_ok($pid);
603
604  if ($ex) {
605    die($ex);
606  }
607
608  unlink($log_file);
609}
610
611sub sql_passwd_sha1_base64 {
612  my $self = shift;
613  my $tmpdir = $self->{tmpdir};
614
615  my $config_file = "$tmpdir/sqlpasswd.conf";
616  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
617  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
618
619  my $log_file = File::Spec->rel2abs('tests.log');
620
621  my $user = 'proftpd';
622
623  # I used:
624  #
625  #  `/bin/echo -n "test" | openssl dgst -binary -sha1 | openssl enc -base64`
626  #
627  # to generate this password.
628  my $passwd = 'qUqP5cyxm6YcTAhz05Hph5gvu9M=';
629
630  my $home_dir = File::Spec->rel2abs($tmpdir);
631  my $uid = 500;
632  my $gid = 500;
633
634  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
635
636  # Build up sqlite3 command to create users, groups tables and populate them
637  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
638
639  if (open(my $fh, "> $db_script")) {
640    print $fh <<EOS;
641CREATE TABLE users (
642  userid TEXT,
643  passwd TEXT,
644  uid INTEGER,
645  gid INTEGER,
646  homedir TEXT,
647  shell TEXT
648);
649INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
650
651CREATE TABLE groups (
652  groupname TEXT,
653  gid INTEGER,
654  members TEXT
655);
656INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
657EOS
658
659    unless (close($fh)) {
660      die("Can't write $db_script: $!");
661    }
662
663  } else {
664    die("Can't open $db_script: $!");
665  }
666
667  my $cmd = "sqlite3 $db_file < $db_script";
668
669  if ($ENV{TEST_VERBOSE}) {
670    print STDERR "Executing sqlite3: $cmd\n";
671  }
672
673  my @output = `$cmd`;
674  if (scalar(@output) &&
675      $ENV{TEST_VERBOSE}) {
676    print STDERR "Output: ", join('', @output), "\n";
677  }
678
679  my $config = {
680    PidFile => $pid_file,
681    ScoreboardFile => $scoreboard_file,
682    SystemLog => $log_file,
683
684    IfModules => {
685      'mod_delay.c' => {
686        DelayEngine => 'off',
687      },
688
689      'mod_sql.c' => {
690        SQLAuthTypes => 'sha1',
691        SQLBackend => 'sqlite3',
692        SQLConnectInfo => $db_file,
693        SQLLogFile => $log_file,
694      },
695
696      'mod_sql_passwd.c' => {
697        SQLPasswordEngine => 'on',
698        SQLPasswordEncoding => 'base64',
699      },
700    },
701  };
702
703  my ($port, $config_user, $config_group) = config_write($config_file, $config);
704
705  # Open pipes, for use between the parent and child processes.  Specifically,
706  # the child will indicate when it's done with its test by writing a message
707  # to the parent.
708  my ($rfh, $wfh);
709  unless (pipe($rfh, $wfh)) {
710    die("Can't open pipe: $!");
711  }
712
713  my $ex;
714
715  # Fork child
716  $self->handle_sigchld();
717  defined(my $pid = fork()) or die("Can't fork: $!");
718  if ($pid) {
719    eval {
720      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
721      $client->login($user, "test");
722
723      my $resp_msgs = $client->response_msgs();
724      my $nmsgs = scalar(@$resp_msgs);
725
726      my $expected;
727
728      $expected = 1;
729      $self->assert($expected == $nmsgs,
730        test_msg("Expected $expected, got $nmsgs"));
731
732      $expected = "User proftpd logged in";
733      $self->assert($expected eq $resp_msgs->[0],
734        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
735
736    };
737
738    if ($@) {
739      $ex = $@;
740    }
741
742    $wfh->print("done\n");
743    $wfh->flush();
744
745  } else {
746    eval { server_wait($config_file, $rfh) };
747    if ($@) {
748      warn($@);
749      exit 1;
750    }
751
752    exit 0;
753  }
754
755  # Stop server
756  server_stop($pid_file);
757
758  $self->assert_child_ok($pid);
759
760  if ($ex) {
761    die($ex);
762  }
763
764  unlink($log_file);
765}
766
767sub sql_passwd_sha1_hex_lc {
768  my $self = shift;
769  my $tmpdir = $self->{tmpdir};
770
771  my $config_file = "$tmpdir/sqlpasswd.conf";
772  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
773  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
774
775  my $log_file = File::Spec->rel2abs('tests.log');
776
777  my $user = 'proftpd';
778
779  # I used:
780  #
781  #  `/bin/echo -n "test" | openssl dgst -hex -sha1`
782  #
783  # to generate this password.
784  my $passwd = 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3';
785
786  my $home_dir = File::Spec->rel2abs($tmpdir);
787  my $uid = 500;
788  my $gid = 500;
789
790  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
791
792  # Build up sqlite3 command to create users, groups tables and populate them
793  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
794
795  if (open(my $fh, "> $db_script")) {
796    print $fh <<EOS;
797CREATE TABLE users (
798  userid TEXT,
799  passwd TEXT,
800  uid INTEGER,
801  gid INTEGER,
802  homedir TEXT,
803  shell TEXT
804);
805INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
806
807CREATE TABLE groups (
808  groupname TEXT,
809  gid INTEGER,
810  members TEXT
811);
812INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
813EOS
814
815    unless (close($fh)) {
816      die("Can't write $db_script: $!");
817    }
818
819  } else {
820    die("Can't open $db_script: $!");
821  }
822
823  my $cmd = "sqlite3 $db_file < $db_script";
824
825  if ($ENV{TEST_VERBOSE}) {
826    print STDERR "Executing sqlite3: $cmd\n";
827  }
828
829  my @output = `$cmd`;
830  if (scalar(@output) &&
831      $ENV{TEST_VERBOSE}) {
832    print STDERR "Output: ", join('', @output), "\n";
833  }
834
835  my $config = {
836    PidFile => $pid_file,
837    ScoreboardFile => $scoreboard_file,
838    SystemLog => $log_file,
839
840    IfModules => {
841      'mod_delay.c' => {
842        DelayEngine => 'off',
843      },
844
845      'mod_sql.c' => {
846        SQLAuthTypes => 'sha1',
847        SQLBackend => 'sqlite3',
848        SQLConnectInfo => $db_file,
849        SQLLogFile => $log_file,
850      },
851
852      'mod_sql_passwd.c' => {
853        SQLPasswordEngine => 'on',
854        SQLPasswordEncoding => 'hex',
855      },
856    },
857  };
858
859  my ($port, $config_user, $config_group) = config_write($config_file, $config);
860
861  # Open pipes, for use between the parent and child processes.  Specifically,
862  # the child will indicate when it's done with its test by writing a message
863  # to the parent.
864  my ($rfh, $wfh);
865  unless (pipe($rfh, $wfh)) {
866    die("Can't open pipe: $!");
867  }
868
869  my $ex;
870
871  # Fork child
872  $self->handle_sigchld();
873  defined(my $pid = fork()) or die("Can't fork: $!");
874  if ($pid) {
875    eval {
876      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
877      $client->login($user, "test");
878
879      my $resp_msgs = $client->response_msgs();
880      my $nmsgs = scalar(@$resp_msgs);
881
882      my $expected;
883
884      $expected = 1;
885      $self->assert($expected == $nmsgs,
886        test_msg("Expected $expected, got $nmsgs"));
887
888      $expected = "User proftpd logged in";
889      $self->assert($expected eq $resp_msgs->[0],
890        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
891
892    };
893
894    if ($@) {
895      $ex = $@;
896    }
897
898    $wfh->print("done\n");
899    $wfh->flush();
900
901  } else {
902    eval { server_wait($config_file, $rfh) };
903    if ($@) {
904      warn($@);
905      exit 1;
906    }
907
908    exit 0;
909  }
910
911  # Stop server
912  server_stop($pid_file);
913
914  $self->assert_child_ok($pid);
915
916  if ($ex) {
917    die($ex);
918  }
919
920  unlink($log_file);
921}
922
923sub sql_passwd_sha1_hex_uc {
924  my $self = shift;
925  my $tmpdir = $self->{tmpdir};
926
927  my $config_file = "$tmpdir/sqlpasswd.conf";
928  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
929  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
930
931  my $log_file = File::Spec->rel2abs('tests.log');
932
933  my $user = 'proftpd';
934
935  # I used:
936  #
937  #  `/bin/echo -n "test" | openssl dgst -hex -sha1`
938  #
939  # to generate this password.  Then I manually made all of the letters be
940  # in uppercase.  Tedious.
941  my $passwd = 'A94A8FE5CCB19BA61C4C0873D391E987982FBBD3';
942
943  my $home_dir = File::Spec->rel2abs($tmpdir);
944  my $uid = 500;
945  my $gid = 500;
946
947  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
948
949  # Build up sqlite3 command to create users, groups tables and populate them
950  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
951
952  if (open(my $fh, "> $db_script")) {
953    print $fh <<EOS;
954CREATE TABLE users (
955  userid TEXT,
956  passwd TEXT,
957  uid INTEGER,
958  gid INTEGER,
959  homedir TEXT,
960  shell TEXT
961);
962INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
963
964CREATE TABLE groups (
965  groupname TEXT,
966  gid INTEGER,
967  members TEXT
968);
969INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
970EOS
971
972    unless (close($fh)) {
973      die("Can't write $db_script: $!");
974    }
975
976  } else {
977    die("Can't open $db_script: $!");
978  }
979
980  my $cmd = "sqlite3 $db_file < $db_script";
981
982  if ($ENV{TEST_VERBOSE}) {
983    print STDERR "Executing sqlite3: $cmd\n";
984  }
985
986  my @output = `$cmd`;
987  if (scalar(@output) &&
988      $ENV{TEST_VERBOSE}) {
989    print STDERR "Output: ", join('', @output), "\n";
990  }
991
992  my $config = {
993    PidFile => $pid_file,
994    ScoreboardFile => $scoreboard_file,
995    SystemLog => $log_file,
996
997    IfModules => {
998      'mod_delay.c' => {
999        DelayEngine => 'off',
1000      },
1001
1002      'mod_sql.c' => {
1003        SQLAuthTypes => 'sha1',
1004        SQLBackend => 'sqlite3',
1005        SQLConnectInfo => $db_file,
1006        SQLLogFile => $log_file,
1007      },
1008
1009      'mod_sql_passwd.c' => {
1010        SQLPasswordEngine => 'on',
1011        SQLPasswordEncoding => 'HEX',
1012      },
1013    },
1014  };
1015
1016  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1017
1018  # Open pipes, for use between the parent and child processes.  Specifically,
1019  # the child will indicate when it's done with its test by writing a message
1020  # to the parent.
1021  my ($rfh, $wfh);
1022  unless (pipe($rfh, $wfh)) {
1023    die("Can't open pipe: $!");
1024  }
1025
1026  my $ex;
1027
1028  # Fork child
1029  $self->handle_sigchld();
1030  defined(my $pid = fork()) or die("Can't fork: $!");
1031  if ($pid) {
1032    eval {
1033      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1034      $client->login($user, "test");
1035
1036      my $resp_msgs = $client->response_msgs();
1037      my $nmsgs = scalar(@$resp_msgs);
1038
1039      my $expected;
1040
1041      $expected = 1;
1042      $self->assert($expected == $nmsgs,
1043        test_msg("Expected $expected, got $nmsgs"));
1044
1045      $expected = "User proftpd logged in";
1046      $self->assert($expected eq $resp_msgs->[0],
1047        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
1048
1049    };
1050
1051    if ($@) {
1052      $ex = $@;
1053    }
1054
1055    $wfh->print("done\n");
1056    $wfh->flush();
1057
1058  } else {
1059    eval { server_wait($config_file, $rfh) };
1060    if ($@) {
1061      warn($@);
1062      exit 1;
1063    }
1064
1065    exit 0;
1066  }
1067
1068  # Stop server
1069  server_stop($pid_file);
1070
1071  $self->assert_child_ok($pid);
1072
1073  if ($ex) {
1074    die($ex);
1075  }
1076
1077  unlink($log_file);
1078}
1079
1080sub sql_passwd_engine_off {
1081  my $self = shift;
1082  my $tmpdir = $self->{tmpdir};
1083
1084  my $config_file = "$tmpdir/sqlpasswd.conf";
1085  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
1086  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
1087
1088  my $log_file = File::Spec->rel2abs('tests.log');
1089
1090  my $user = 'proftpd';
1091
1092  # I used:
1093  #
1094  #  `/bin/echo -n "test" | openssl dgst -binary -md5 | openssl enc -base64`
1095  #
1096  # to generate this password.
1097  my $passwd = 'CY9rzUYh03PK3k6DJie09g==';
1098
1099  my $home_dir = File::Spec->rel2abs($tmpdir);
1100  my $uid = 500;
1101  my $gid = 500;
1102
1103  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
1104
1105  # Build up sqlite3 command to create users, groups tables and populate them
1106  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
1107
1108  if (open(my $fh, "> $db_script")) {
1109    print $fh <<EOS;
1110CREATE TABLE users (
1111  userid TEXT,
1112  passwd TEXT,
1113  uid INTEGER,
1114  gid INTEGER,
1115  homedir TEXT,
1116  shell TEXT
1117);
1118INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
1119
1120CREATE TABLE groups (
1121  groupname TEXT,
1122  gid INTEGER,
1123  members TEXT
1124);
1125INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
1126EOS
1127
1128    unless (close($fh)) {
1129      die("Can't write $db_script: $!");
1130    }
1131
1132  } else {
1133    die("Can't open $db_script: $!");
1134  }
1135
1136  my $cmd = "sqlite3 $db_file < $db_script";
1137
1138  if ($ENV{TEST_VERBOSE}) {
1139    print STDERR "Executing sqlite3: $cmd\n";
1140  }
1141
1142  my @output = `$cmd`;
1143  if (scalar(@output) &&
1144      $ENV{TEST_VERBOSE}) {
1145    print STDERR "Output: ", join('', @output), "\n";
1146  }
1147
1148  my $config = {
1149    PidFile => $pid_file,
1150    ScoreboardFile => $scoreboard_file,
1151    SystemLog => $log_file,
1152
1153    IfModules => {
1154      'mod_delay.c' => {
1155        DelayEngine => 'off',
1156      },
1157
1158      'mod_sql.c' => {
1159        SQLAuthTypes => 'md5',
1160        SQLBackend => 'sqlite3',
1161        SQLConnectInfo => $db_file,
1162        SQLLogFile => $log_file,
1163      },
1164
1165      'mod_sql_passwd.c' => {
1166        SQLPasswordEngine => 'off',
1167        SQLPasswordEncoding => 'base64',
1168      },
1169    },
1170  };
1171
1172  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1173
1174  # Open pipes, for use between the parent and child processes.  Specifically,
1175  # the child will indicate when it's done with its test by writing a message
1176  # to the parent.
1177  my ($rfh, $wfh);
1178  unless (pipe($rfh, $wfh)) {
1179    die("Can't open pipe: $!");
1180  }
1181
1182  my $ex;
1183
1184  # Fork child
1185  $self->handle_sigchld();
1186  defined(my $pid = fork()) or die("Can't fork: $!");
1187  if ($pid) {
1188    eval {
1189      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1190      eval { $client->login($user, "test") };
1191      unless ($@) {
1192        die("Login succeeded unexpectedly");
1193      }
1194
1195      my $resp_code = $client->response_code();
1196      my $resp_msg = $client->response_msg();
1197
1198      my $expected;
1199
1200      $expected = 530;
1201      $self->assert($expected == $resp_code,
1202        test_msg("Expected $expected, got $resp_code"));
1203
1204      $expected = "Login incorrect.";
1205      $self->assert($expected eq $resp_msg,
1206        test_msg("Expected '$expected', got '$resp_msg'"));
1207    };
1208
1209    if ($@) {
1210      $ex = $@;
1211    }
1212
1213    $wfh->print("done\n");
1214    $wfh->flush();
1215
1216  } else {
1217    eval { server_wait($config_file, $rfh) };
1218    if ($@) {
1219      warn($@);
1220      exit 1;
1221    }
1222
1223    exit 0;
1224  }
1225
1226  # Stop server
1227  server_stop($pid_file);
1228
1229  $self->assert_child_ok($pid);
1230
1231  if ($ex) {
1232    die($ex);
1233  }
1234
1235  unlink($log_file);
1236}
1237
1238sub sql_passwd_salt_file {
1239  my $self = shift;
1240  my $tmpdir = $self->{tmpdir};
1241
1242  my $config_file = "$tmpdir/sqlpasswd.conf";
1243  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
1244  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
1245
1246  my $log_file = File::Spec->rel2abs('tests.log');
1247
1248  my $salt = '8Hkqr7bnPaZ52j81VvuoWdOEuq6EeXwpiIw5Q679xzvEqwe128';
1249
1250  my $user = 'proftpd';
1251
1252  # I used:
1253  #
1254  #  Digest::SHA1::sha1_hex((lc("password")) . $salt);
1255  #
1256  # to generate this password.
1257  my $passwd = '975838a6aebc87d384535df6f7226274813353aa';
1258
1259  my $home_dir = File::Spec->rel2abs($tmpdir);
1260  my $uid = 500;
1261  my $gid = 500;
1262
1263  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
1264
1265  # Build up sqlite3 command to create users, groups tables and populate them
1266  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
1267
1268  if (open(my $fh, "> $db_script")) {
1269    print $fh <<EOS;
1270CREATE TABLE users (
1271  userid TEXT,
1272  passwd TEXT,
1273  uid INTEGER,
1274  gid INTEGER,
1275  homedir TEXT,
1276  shell TEXT
1277);
1278INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
1279
1280CREATE TABLE groups (
1281  groupname TEXT,
1282  gid INTEGER,
1283  members TEXT
1284);
1285INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
1286EOS
1287
1288    unless (close($fh)) {
1289      die("Can't write $db_script: $!");
1290    }
1291
1292  } else {
1293    die("Can't open $db_script: $!");
1294  }
1295
1296  my $cmd = "sqlite3 $db_file < $db_script";
1297
1298  if ($ENV{TEST_VERBOSE}) {
1299    print STDERR "Executing sqlite3: $cmd\n";
1300  }
1301
1302  my @output = `$cmd`;
1303  if (scalar(@output) &&
1304      $ENV{TEST_VERBOSE}) {
1305    print STDERR "Output: ", join('', @output), "\n";
1306  }
1307
1308  my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt");
1309  if (open(my $fh, "> $salt_file")) {
1310    binmode($fh);
1311    print $fh $salt;
1312
1313    unless (close($fh)) {
1314      die("Can't write $salt_file: $!");
1315    }
1316
1317  } else {
1318    die("Can't open $salt_file: $!");
1319  }
1320
1321  my $config = {
1322    PidFile => $pid_file,
1323    ScoreboardFile => $scoreboard_file,
1324    SystemLog => $log_file,
1325
1326    IfModules => {
1327      'mod_delay.c' => {
1328        DelayEngine => 'off',
1329      },
1330
1331      'mod_sql.c' => {
1332        SQLAuthTypes => 'sha1',
1333        SQLBackend => 'sqlite3',
1334        SQLConnectInfo => $db_file,
1335        SQLLogFile => $log_file,
1336      },
1337
1338      'mod_sql_passwd.c' => {
1339        SQLPasswordEngine => 'on',
1340        SQLPasswordEncoding => 'hex',
1341        SQLPasswordSaltFile => $salt_file,
1342      },
1343    },
1344  };
1345
1346  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1347
1348  # Open pipes, for use between the parent and child processes.  Specifically,
1349  # the child will indicate when it's done with its test by writing a message
1350  # to the parent.
1351  my ($rfh, $wfh);
1352  unless (pipe($rfh, $wfh)) {
1353    die("Can't open pipe: $!");
1354  }
1355
1356  my $ex;
1357
1358  # Fork child
1359  $self->handle_sigchld();
1360  defined(my $pid = fork()) or die("Can't fork: $!");
1361  if ($pid) {
1362    eval {
1363      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1364      $client->login($user, "password");
1365
1366      my $resp_msgs = $client->response_msgs();
1367      my $nmsgs = scalar(@$resp_msgs);
1368
1369      my $expected;
1370
1371      $expected = 1;
1372      $self->assert($expected == $nmsgs,
1373        test_msg("Expected $expected, got $nmsgs"));
1374
1375      $expected = "User proftpd logged in";
1376      $self->assert($expected eq $resp_msgs->[0],
1377        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
1378
1379    };
1380
1381    if ($@) {
1382      $ex = $@;
1383    }
1384
1385    $wfh->print("done\n");
1386    $wfh->flush();
1387
1388  } else {
1389    eval { server_wait($config_file, $rfh) };
1390    if ($@) {
1391      warn($@);
1392      exit 1;
1393    }
1394
1395    exit 0;
1396  }
1397
1398  # Stop server
1399  server_stop($pid_file);
1400
1401  $self->assert_child_ok($pid);
1402
1403  if ($ex) {
1404    die($ex);
1405  }
1406
1407  unlink($log_file);
1408}
1409
1410sub sql_passwd_salt_file_trailing_newline {
1411  my $self = shift;
1412  my $tmpdir = $self->{tmpdir};
1413
1414  my $config_file = "$tmpdir/sqlpasswd.conf";
1415  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
1416  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
1417
1418  my $log_file = File::Spec->rel2abs('tests.log');
1419
1420  my $salt = '8Hkqr7bnPaZ52j81VvuoWdOEuq6EeXwpiIw5Q679xzvEqwe128';
1421
1422  my $user = 'proftpd';
1423
1424  # I used:
1425  #
1426  #  Digest::SHA1::sha1_hex((lc("password")) . $salt);
1427  #
1428  # to generate this password.
1429  my $passwd = '975838a6aebc87d384535df6f7226274813353aa';
1430
1431  my $home_dir = File::Spec->rel2abs($tmpdir);
1432  my $uid = 500;
1433  my $gid = 500;
1434
1435  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
1436
1437  # Build up sqlite3 command to create users, groups tables and populate them
1438  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
1439
1440  if (open(my $fh, "> $db_script")) {
1441    print $fh <<EOS;
1442CREATE TABLE users (
1443  userid TEXT,
1444  passwd TEXT,
1445  uid INTEGER,
1446  gid INTEGER,
1447  homedir TEXT,
1448  shell TEXT
1449);
1450INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
1451
1452CREATE TABLE groups (
1453  groupname TEXT,
1454  gid INTEGER,
1455  members TEXT
1456);
1457INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
1458EOS
1459
1460    unless (close($fh)) {
1461      die("Can't write $db_script: $!");
1462    }
1463
1464  } else {
1465    die("Can't open $db_script: $!");
1466  }
1467
1468  my $cmd = "sqlite3 $db_file < $db_script";
1469
1470  if ($ENV{TEST_VERBOSE}) {
1471    print STDERR "Executing sqlite3: $cmd\n";
1472  }
1473
1474  my @output = `$cmd`;
1475  if (scalar(@output) &&
1476      $ENV{TEST_VERBOSE}) {
1477    print STDERR "Output: ", join('', @output), "\n";
1478  }
1479
1480  my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt");
1481  if (open(my $fh, "> $salt_file")) {
1482    binmode($fh);
1483
1484    # In this case, we deliberately write a trailing newline with the salt,
1485    # to make sure that mod_sql_passwd handles it.
1486    print $fh "$salt\n";
1487
1488    unless (close($fh)) {
1489      die("Can't write $salt_file: $!");
1490    }
1491
1492  } else {
1493    die("Can't open $salt_file: $!");
1494  }
1495
1496  my $config = {
1497    PidFile => $pid_file,
1498    ScoreboardFile => $scoreboard_file,
1499    SystemLog => $log_file,
1500
1501    IfModules => {
1502      'mod_delay.c' => {
1503        DelayEngine => 'off',
1504      },
1505
1506      'mod_sql.c' => {
1507        SQLAuthTypes => 'sha1',
1508        SQLBackend => 'sqlite3',
1509        SQLConnectInfo => $db_file,
1510        SQLLogFile => $log_file,
1511      },
1512
1513      'mod_sql_passwd.c' => {
1514        SQLPasswordEngine => 'on',
1515        SQLPasswordEncoding => 'hex',
1516        SQLPasswordSaltFile => $salt_file,
1517      },
1518    },
1519  };
1520
1521  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1522
1523  # Open pipes, for use between the parent and child processes.  Specifically,
1524  # the child will indicate when it's done with its test by writing a message
1525  # to the parent.
1526  my ($rfh, $wfh);
1527  unless (pipe($rfh, $wfh)) {
1528    die("Can't open pipe: $!");
1529  }
1530
1531  my $ex;
1532
1533  # Fork child
1534  $self->handle_sigchld();
1535  defined(my $pid = fork()) or die("Can't fork: $!");
1536  if ($pid) {
1537    eval {
1538      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1539      $client->login($user, "password");
1540
1541      my $resp_msgs = $client->response_msgs();
1542      my $nmsgs = scalar(@$resp_msgs);
1543
1544      my $expected;
1545
1546      $expected = 1;
1547      $self->assert($expected == $nmsgs,
1548        test_msg("Expected $expected, got $nmsgs"));
1549
1550      $expected = "User proftpd logged in";
1551      $self->assert($expected eq $resp_msgs->[0],
1552        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
1553
1554    };
1555
1556    if ($@) {
1557      $ex = $@;
1558    }
1559
1560    $wfh->print("done\n");
1561    $wfh->flush();
1562
1563  } else {
1564    eval { server_wait($config_file, $rfh) };
1565    if ($@) {
1566      warn($@);
1567      exit 1;
1568    }
1569
1570    exit 0;
1571  }
1572
1573  # Stop server
1574  server_stop($pid_file);
1575
1576  $self->assert_child_ok($pid);
1577
1578  if ($ex) {
1579    die($ex);
1580  }
1581
1582  unlink($log_file);
1583}
1584
1585sub sql_passwd_salt_file_prepend {
1586  my $self = shift;
1587  my $tmpdir = $self->{tmpdir};
1588
1589  my $config_file = "$tmpdir/sqlpasswd.conf";
1590  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
1591  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
1592
1593  my $log_file = File::Spec->rel2abs('tests.log');
1594
1595  my $salt = '8Hkqr7bnPaZ52j81VvuoWdOEuq6EeXwpiIw5Q679xzvEqwe128';
1596
1597  my $user = 'proftpd';
1598
1599  # I used:
1600  #
1601  #  Digest::SHA1::sha1_hex($salt . lc("password"));
1602  #
1603  # to generate this password.
1604  my $passwd = 'c16542a729162ec1228919a21b36775d63391b78';
1605
1606  my $home_dir = File::Spec->rel2abs($tmpdir);
1607  my $uid = 500;
1608  my $gid = 500;
1609
1610  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
1611
1612  # Build up sqlite3 command to create users, groups tables and populate them
1613  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
1614
1615  if (open(my $fh, "> $db_script")) {
1616    print $fh <<EOS;
1617CREATE TABLE users (
1618  userid TEXT,
1619  passwd TEXT,
1620  uid INTEGER,
1621  gid INTEGER,
1622  homedir TEXT,
1623  shell TEXT
1624);
1625INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
1626
1627CREATE TABLE groups (
1628  groupname TEXT,
1629  gid INTEGER,
1630  members TEXT
1631);
1632INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
1633EOS
1634
1635    unless (close($fh)) {
1636      die("Can't write $db_script: $!");
1637    }
1638
1639  } else {
1640    die("Can't open $db_script: $!");
1641  }
1642
1643  my $cmd = "sqlite3 $db_file < $db_script";
1644
1645  if ($ENV{TEST_VERBOSE}) {
1646    print STDERR "Executing sqlite3: $cmd\n";
1647  }
1648
1649  my @output = `$cmd`;
1650  if (scalar(@output) &&
1651      $ENV{TEST_VERBOSE}) {
1652    print STDERR "Output: ", join('', @output), "\n";
1653  }
1654
1655  my $salt_file = File::Spec->rel2abs("$home_dir/sqlpasswd.salt");
1656  if (open(my $fh, "> $salt_file")) {
1657    binmode($fh);
1658    print $fh $salt;
1659
1660    unless (close($fh)) {
1661      die("Can't write $salt_file: $!");
1662    }
1663
1664  } else {
1665    die("Can't open $salt_file: $!");
1666  }
1667
1668  my $config = {
1669    PidFile => $pid_file,
1670    ScoreboardFile => $scoreboard_file,
1671    SystemLog => $log_file,
1672
1673    IfModules => {
1674      'mod_delay.c' => {
1675        DelayEngine => 'off',
1676      },
1677
1678      'mod_sql.c' => {
1679        SQLAuthTypes => 'sha1',
1680        SQLBackend => 'sqlite3',
1681        SQLConnectInfo => $db_file,
1682        SQLLogFile => $log_file,
1683      },
1684
1685      'mod_sql_passwd.c' => {
1686        SQLPasswordEngine => 'on',
1687        SQLPasswordEncoding => 'hex',
1688        SQLPasswordSaltFile => "$salt_file prepend",
1689      },
1690    },
1691  };
1692
1693  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1694
1695  # Open pipes, for use between the parent and child processes.  Specifically,
1696  # the child will indicate when it's done with its test by writing a message
1697  # to the parent.
1698  my ($rfh, $wfh);
1699  unless (pipe($rfh, $wfh)) {
1700    die("Can't open pipe: $!");
1701  }
1702
1703  my $ex;
1704
1705  # Fork child
1706  $self->handle_sigchld();
1707  defined(my $pid = fork()) or die("Can't fork: $!");
1708  if ($pid) {
1709    eval {
1710      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1711      $client->login($user, "password");
1712
1713      my $resp_msgs = $client->response_msgs();
1714      my $nmsgs = scalar(@$resp_msgs);
1715
1716      my $expected;
1717
1718      $expected = 1;
1719      $self->assert($expected == $nmsgs,
1720        test_msg("Expected $expected, got $nmsgs"));
1721
1722      $expected = "User proftpd logged in";
1723      $self->assert($expected eq $resp_msgs->[0],
1724        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
1725
1726    };
1727
1728    if ($@) {
1729      $ex = $@;
1730    }
1731
1732    $wfh->print("done\n");
1733    $wfh->flush();
1734
1735  } else {
1736    eval { server_wait($config_file, $rfh) };
1737    if ($@) {
1738      warn($@);
1739      exit 1;
1740    }
1741
1742    exit 0;
1743  }
1744
1745  # Stop server
1746  server_stop($pid_file);
1747
1748  $self->assert_child_ok($pid);
1749
1750  if ($ex) {
1751    die($ex);
1752  }
1753
1754  unlink($log_file);
1755}
1756
1757sub sql_passwd_sha256_base64_bug3344 {
1758  my $self = shift;
1759  my $tmpdir = $self->{tmpdir};
1760
1761  my $config_file = "$tmpdir/sqlpasswd.conf";
1762  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
1763  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
1764
1765  my $log_file = File::Spec->rel2abs('tests.log');
1766
1767  my $user = 'proftpd';
1768
1769  # I used:
1770  #
1771  #  `/bin/echo -n "test" | openssl dgst -binary -sha256 | openssl enc -base64`
1772  #
1773  # to generate this password.
1774  my $passwd = 'n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=';
1775
1776  my $home_dir = File::Spec->rel2abs($tmpdir);
1777  my $uid = 500;
1778  my $gid = 500;
1779
1780  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
1781
1782  # Build up sqlite3 command to create users, groups tables and populate them
1783  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
1784
1785  if (open(my $fh, "> $db_script")) {
1786    print $fh <<EOS;
1787CREATE TABLE users (
1788  userid TEXT,
1789  passwd TEXT,
1790  uid INTEGER,
1791  gid INTEGER,
1792  homedir TEXT,
1793  shell TEXT
1794);
1795INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
1796
1797CREATE TABLE groups (
1798  groupname TEXT,
1799  gid INTEGER,
1800  members TEXT
1801);
1802INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
1803EOS
1804
1805    unless (close($fh)) {
1806      die("Can't write $db_script: $!");
1807    }
1808
1809  } else {
1810    die("Can't open $db_script: $!");
1811  }
1812
1813  my $cmd = "sqlite3 $db_file < $db_script";
1814
1815  if ($ENV{TEST_VERBOSE}) {
1816    print STDERR "Executing sqlite3: $cmd\n";
1817  }
1818
1819  my @output = `$cmd`;
1820  if (scalar(@output) &&
1821      $ENV{TEST_VERBOSE}) {
1822    print STDERR "Output: ", join('', @output), "\n";
1823  }
1824
1825  my $config = {
1826    PidFile => $pid_file,
1827    ScoreboardFile => $scoreboard_file,
1828    SystemLog => $log_file,
1829
1830    IfModules => {
1831      'mod_delay.c' => {
1832        DelayEngine => 'off',
1833      },
1834
1835      'mod_sql.c' => {
1836        SQLAuthTypes => 'sha256',
1837        SQLBackend => 'sqlite3',
1838        SQLConnectInfo => $db_file,
1839        SQLLogFile => $log_file,
1840      },
1841
1842      'mod_sql_passwd.c' => {
1843        SQLPasswordEngine => 'on',
1844        SQLPasswordEncoding => 'base64',
1845      },
1846    },
1847  };
1848
1849  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1850
1851  # Open pipes, for use between the parent and child processes.  Specifically,
1852  # the child will indicate when it's done with its test by writing a message
1853  # to the parent.
1854  my ($rfh, $wfh);
1855  unless (pipe($rfh, $wfh)) {
1856    die("Can't open pipe: $!");
1857  }
1858
1859  my $ex;
1860
1861  # Fork child
1862  $self->handle_sigchld();
1863  defined(my $pid = fork()) or die("Can't fork: $!");
1864  if ($pid) {
1865    eval {
1866      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1867      $client->login($user, "test");
1868
1869      my $resp_msgs = $client->response_msgs();
1870      my $nmsgs = scalar(@$resp_msgs);
1871
1872      my $expected;
1873
1874      $expected = 1;
1875      $self->assert($expected == $nmsgs,
1876        test_msg("Expected $expected, got $nmsgs"));
1877
1878      $expected = "User proftpd logged in";
1879      $self->assert($expected eq $resp_msgs->[0],
1880        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
1881
1882    };
1883
1884    if ($@) {
1885      $ex = $@;
1886    }
1887
1888    $wfh->print("done\n");
1889    $wfh->flush();
1890
1891  } else {
1892    eval { server_wait($config_file, $rfh) };
1893    if ($@) {
1894      warn($@);
1895      exit 1;
1896    }
1897
1898    exit 0;
1899  }
1900
1901  # Stop server
1902  server_stop($pid_file);
1903
1904  $self->assert_child_ok($pid);
1905
1906  if ($ex) {
1907    die($ex);
1908  }
1909
1910  unlink($log_file);
1911}
1912
1913sub sql_passwd_sha256_hex_lc_bug3344 {
1914  my $self = shift;
1915  my $tmpdir = $self->{tmpdir};
1916
1917  my $config_file = "$tmpdir/sqlpasswd.conf";
1918  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
1919  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
1920
1921  my $log_file = File::Spec->rel2abs('tests.log');
1922
1923  my $user = 'proftpd';
1924
1925  # I used:
1926  #
1927  #  `/bin/echo -n "test" | openssl dgst -hex -sha256`
1928  #
1929  # to generate this password.
1930  my $passwd = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08';
1931
1932  my $home_dir = File::Spec->rel2abs($tmpdir);
1933  my $uid = 500;
1934  my $gid = 500;
1935
1936  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
1937
1938  # Build up sqlite3 command to create users, groups tables and populate them
1939  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
1940
1941  if (open(my $fh, "> $db_script")) {
1942    print $fh <<EOS;
1943CREATE TABLE users (
1944  userid TEXT,
1945  passwd TEXT,
1946  uid INTEGER,
1947  gid INTEGER,
1948  homedir TEXT,
1949  shell TEXT
1950);
1951INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
1952
1953CREATE TABLE groups (
1954  groupname TEXT,
1955  gid INTEGER,
1956  members TEXT
1957);
1958INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
1959EOS
1960
1961    unless (close($fh)) {
1962      die("Can't write $db_script: $!");
1963    }
1964
1965  } else {
1966    die("Can't open $db_script: $!");
1967  }
1968
1969  my $cmd = "sqlite3 $db_file < $db_script";
1970
1971  if ($ENV{TEST_VERBOSE}) {
1972    print STDERR "Executing sqlite3: $cmd\n";
1973  }
1974
1975  my @output = `$cmd`;
1976  if (scalar(@output) &&
1977      $ENV{TEST_VERBOSE}) {
1978    print STDERR "Output: ", join('', @output), "\n";
1979  }
1980
1981  my $config = {
1982    PidFile => $pid_file,
1983    ScoreboardFile => $scoreboard_file,
1984    SystemLog => $log_file,
1985
1986    IfModules => {
1987      'mod_delay.c' => {
1988        DelayEngine => 'off',
1989      },
1990
1991      'mod_sql.c' => {
1992        SQLAuthTypes => 'sha256',
1993        SQLBackend => 'sqlite3',
1994        SQLConnectInfo => $db_file,
1995        SQLLogFile => $log_file,
1996      },
1997
1998      'mod_sql_passwd.c' => {
1999        SQLPasswordEngine => 'on',
2000        SQLPasswordEncoding => 'hex',
2001      },
2002    },
2003  };
2004
2005  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2006
2007  # Open pipes, for use between the parent and child processes.  Specifically,
2008  # the child will indicate when it's done with its test by writing a message
2009  # to the parent.
2010  my ($rfh, $wfh);
2011  unless (pipe($rfh, $wfh)) {
2012    die("Can't open pipe: $!");
2013  }
2014
2015  my $ex;
2016
2017  # Fork child
2018  $self->handle_sigchld();
2019  defined(my $pid = fork()) or die("Can't fork: $!");
2020  if ($pid) {
2021    eval {
2022      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2023      $client->login($user, "test");
2024
2025      my $resp_msgs = $client->response_msgs();
2026      my $nmsgs = scalar(@$resp_msgs);
2027
2028      my $expected;
2029
2030      $expected = 1;
2031      $self->assert($expected == $nmsgs,
2032        test_msg("Expected $expected, got $nmsgs"));
2033
2034      $expected = "User proftpd logged in";
2035      $self->assert($expected eq $resp_msgs->[0],
2036        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
2037
2038    };
2039
2040    if ($@) {
2041      $ex = $@;
2042    }
2043
2044    $wfh->print("done\n");
2045    $wfh->flush();
2046
2047  } else {
2048    eval { server_wait($config_file, $rfh) };
2049    if ($@) {
2050      warn($@);
2051      exit 1;
2052    }
2053
2054    exit 0;
2055  }
2056
2057  # Stop server
2058  server_stop($pid_file);
2059
2060  $self->assert_child_ok($pid);
2061
2062  if ($ex) {
2063    die($ex);
2064  }
2065
2066  unlink($log_file);
2067}
2068
2069sub sql_passwd_sha256_hex_uc_bug3344 {
2070  my $self = shift;
2071  my $tmpdir = $self->{tmpdir};
2072
2073  my $config_file = "$tmpdir/sqlpasswd.conf";
2074  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
2075  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
2076
2077  my $log_file = File::Spec->rel2abs('tests.log');
2078
2079  my $user = 'proftpd';
2080
2081  # I used:
2082  #
2083  #  `/bin/echo -n "test" | openssl dgst -hex -sha256`
2084  #
2085  # to generate this password.  Then I manually made all of the letters be
2086  # in uppercase.  Tedious.
2087  my $passwd = '9F86D081884C7D659A2FEAA0C55AD015A3BF4F1B2B0B822CD15D6C15B0F00A08';
2088
2089  my $home_dir = File::Spec->rel2abs($tmpdir);
2090  my $uid = 500;
2091  my $gid = 500;
2092
2093  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
2094
2095  # Build up sqlite3 command to create users, groups tables and populate them
2096  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
2097
2098  if (open(my $fh, "> $db_script")) {
2099    print $fh <<EOS;
2100CREATE TABLE users (
2101  userid TEXT,
2102  passwd TEXT,
2103  uid INTEGER,
2104  gid INTEGER,
2105  homedir TEXT,
2106  shell TEXT
2107);
2108INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
2109
2110CREATE TABLE groups (
2111  groupname TEXT,
2112  gid INTEGER,
2113  members TEXT
2114);
2115INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
2116EOS
2117
2118    unless (close($fh)) {
2119      die("Can't write $db_script: $!");
2120    }
2121
2122  } else {
2123    die("Can't open $db_script: $!");
2124  }
2125
2126  my $cmd = "sqlite3 $db_file < $db_script";
2127
2128  if ($ENV{TEST_VERBOSE}) {
2129    print STDERR "Executing sqlite3: $cmd\n";
2130  }
2131
2132  my @output = `$cmd`;
2133  if (scalar(@output) &&
2134      $ENV{TEST_VERBOSE}) {
2135    print STDERR "Output: ", join('', @output), "\n";
2136  }
2137
2138  my $config = {
2139    PidFile => $pid_file,
2140    ScoreboardFile => $scoreboard_file,
2141    SystemLog => $log_file,
2142
2143    IfModules => {
2144      'mod_delay.c' => {
2145        DelayEngine => 'off',
2146      },
2147
2148      'mod_sql.c' => {
2149        SQLAuthTypes => 'sha256',
2150        SQLBackend => 'sqlite3',
2151        SQLConnectInfo => $db_file,
2152        SQLLogFile => $log_file,
2153      },
2154
2155      'mod_sql_passwd.c' => {
2156        SQLPasswordEngine => 'on',
2157        SQLPasswordEncoding => 'HEX',
2158      },
2159    },
2160  };
2161
2162  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2163
2164  # Open pipes, for use between the parent and child processes.  Specifically,
2165  # the child will indicate when it's done with its test by writing a message
2166  # to the parent.
2167  my ($rfh, $wfh);
2168  unless (pipe($rfh, $wfh)) {
2169    die("Can't open pipe: $!");
2170  }
2171
2172  my $ex;
2173
2174  # Fork child
2175  $self->handle_sigchld();
2176  defined(my $pid = fork()) or die("Can't fork: $!");
2177  if ($pid) {
2178    eval {
2179      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2180      $client->login($user, "test");
2181
2182      my $resp_msgs = $client->response_msgs();
2183      my $nmsgs = scalar(@$resp_msgs);
2184
2185      my $expected;
2186
2187      $expected = 1;
2188      $self->assert($expected == $nmsgs,
2189        test_msg("Expected $expected, got $nmsgs"));
2190
2191      $expected = "User proftpd logged in";
2192      $self->assert($expected eq $resp_msgs->[0],
2193        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
2194
2195    };
2196
2197    if ($@) {
2198      $ex = $@;
2199    }
2200
2201    $wfh->print("done\n");
2202    $wfh->flush();
2203
2204  } else {
2205    eval { server_wait($config_file, $rfh) };
2206    if ($@) {
2207      warn($@);
2208      exit 1;
2209    }
2210
2211    exit 0;
2212  }
2213
2214  # Stop server
2215  server_stop($pid_file);
2216
2217  $self->assert_child_ok($pid);
2218
2219  if ($ex) {
2220    die($ex);
2221  }
2222
2223  unlink($log_file);
2224}
2225
2226sub sql_passwd_sha512_base64_bug3344 {
2227  my $self = shift;
2228  my $tmpdir = $self->{tmpdir};
2229
2230  my $config_file = "$tmpdir/sqlpasswd.conf";
2231  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
2232  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
2233
2234  my $log_file = File::Spec->rel2abs('tests.log');
2235
2236  my $user = 'proftpd';
2237
2238  # I used:
2239  #
2240  #  `/bin/echo -n "test" | openssl dgst -binary -sha512 | openssl enc -base64 -A`
2241  #
2242  # to generate this password.
2243  my $passwd = '7iaw3Ur350mqGo7jwQrpkj9hiYB3Lkc/iBml1JQODbJ6wYX4oOHV+E+IvIh/1nsUNzLDBMxfqa2Ob1f1ACio/w==';
2244
2245  my $home_dir = File::Spec->rel2abs($tmpdir);
2246  my $uid = 500;
2247  my $gid = 500;
2248
2249  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
2250
2251  # Build up sqlite3 command to create users, groups tables and populate them
2252  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
2253
2254  if (open(my $fh, "> $db_script")) {
2255    print $fh <<EOS;
2256CREATE TABLE users (
2257  userid TEXT,
2258  passwd TEXT,
2259  uid INTEGER,
2260  gid INTEGER,
2261  homedir TEXT,
2262  shell TEXT
2263);
2264INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
2265
2266CREATE TABLE groups (
2267  groupname TEXT,
2268  gid INTEGER,
2269  members TEXT
2270);
2271INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
2272EOS
2273
2274    unless (close($fh)) {
2275      die("Can't write $db_script: $!");
2276    }
2277
2278  } else {
2279    die("Can't open $db_script: $!");
2280  }
2281
2282  my $cmd = "sqlite3 $db_file < $db_script";
2283
2284  if ($ENV{TEST_VERBOSE}) {
2285    print STDERR "Executing sqlite3: $cmd\n";
2286  }
2287
2288  my @output = `$cmd`;
2289  if (scalar(@output) &&
2290      $ENV{TEST_VERBOSE}) {
2291    print STDERR "Output: ", join('', @output), "\n";
2292  }
2293
2294  my $config = {
2295    PidFile => $pid_file,
2296    ScoreboardFile => $scoreboard_file,
2297    SystemLog => $log_file,
2298
2299    IfModules => {
2300      'mod_delay.c' => {
2301        DelayEngine => 'off',
2302      },
2303
2304      'mod_sql.c' => {
2305        SQLAuthTypes => 'sha512',
2306        SQLBackend => 'sqlite3',
2307        SQLConnectInfo => $db_file,
2308        SQLLogFile => $log_file,
2309      },
2310
2311      'mod_sql_passwd.c' => {
2312        SQLPasswordEngine => 'on',
2313        SQLPasswordEncoding => 'base64',
2314      },
2315    },
2316  };
2317
2318  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2319
2320  # Open pipes, for use between the parent and child processes.  Specifically,
2321  # the child will indicate when it's done with its test by writing a message
2322  # to the parent.
2323  my ($rfh, $wfh);
2324  unless (pipe($rfh, $wfh)) {
2325    die("Can't open pipe: $!");
2326  }
2327
2328  my $ex;
2329
2330  # Fork child
2331  $self->handle_sigchld();
2332  defined(my $pid = fork()) or die("Can't fork: $!");
2333  if ($pid) {
2334    eval {
2335      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2336      $client->login($user, "test");
2337
2338      my $resp_msgs = $client->response_msgs();
2339      my $nmsgs = scalar(@$resp_msgs);
2340
2341      my $expected;
2342
2343      $expected = 1;
2344      $self->assert($expected == $nmsgs,
2345        test_msg("Expected $expected, got $nmsgs"));
2346
2347      $expected = "User proftpd logged in";
2348      $self->assert($expected eq $resp_msgs->[0],
2349        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
2350
2351    };
2352
2353    if ($@) {
2354      $ex = $@;
2355    }
2356
2357    $wfh->print("done\n");
2358    $wfh->flush();
2359
2360  } else {
2361    eval { server_wait($config_file, $rfh) };
2362    if ($@) {
2363      warn($@);
2364      exit 1;
2365    }
2366
2367    exit 0;
2368  }
2369
2370  # Stop server
2371  server_stop($pid_file);
2372
2373  $self->assert_child_ok($pid);
2374
2375  if ($ex) {
2376    die($ex);
2377  }
2378
2379  unlink($log_file);
2380}
2381
2382sub sql_passwd_sha512_hex_lc_bug3344 {
2383  my $self = shift;
2384  my $tmpdir = $self->{tmpdir};
2385
2386  my $config_file = "$tmpdir/sqlpasswd.conf";
2387  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
2388  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
2389
2390  my $log_file = File::Spec->rel2abs('tests.log');
2391
2392  my $user = 'proftpd';
2393
2394  # I used:
2395  #
2396  #  `/bin/echo -n "test" | openssl dgst -hex -sha512`
2397  #
2398  # to generate this password.
2399  my $passwd = 'ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff';
2400
2401  my $home_dir = File::Spec->rel2abs($tmpdir);
2402  my $uid = 500;
2403  my $gid = 500;
2404
2405  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
2406
2407  # Build up sqlite3 command to create users, groups tables and populate them
2408  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
2409
2410  if (open(my $fh, "> $db_script")) {
2411    print $fh <<EOS;
2412CREATE TABLE users (
2413  userid TEXT,
2414  passwd TEXT,
2415  uid INTEGER,
2416  gid INTEGER,
2417  homedir TEXT,
2418  shell TEXT
2419);
2420INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
2421
2422CREATE TABLE groups (
2423  groupname TEXT,
2424  gid INTEGER,
2425  members TEXT
2426);
2427INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
2428EOS
2429
2430    unless (close($fh)) {
2431      die("Can't write $db_script: $!");
2432    }
2433
2434  } else {
2435    die("Can't open $db_script: $!");
2436  }
2437
2438  my $cmd = "sqlite3 $db_file < $db_script";
2439
2440  if ($ENV{TEST_VERBOSE}) {
2441    print STDERR "Executing sqlite3: $cmd\n";
2442  }
2443
2444  my @output = `$cmd`;
2445  if (scalar(@output) &&
2446      $ENV{TEST_VERBOSE}) {
2447    print STDERR "Output: ", join('', @output), "\n";
2448  }
2449
2450  my $config = {
2451    PidFile => $pid_file,
2452    ScoreboardFile => $scoreboard_file,
2453    SystemLog => $log_file,
2454
2455    IfModules => {
2456      'mod_delay.c' => {
2457        DelayEngine => 'off',
2458      },
2459
2460      'mod_sql.c' => {
2461        SQLAuthTypes => 'sha512',
2462        SQLBackend => 'sqlite3',
2463        SQLConnectInfo => $db_file,
2464        SQLLogFile => $log_file,
2465      },
2466
2467      'mod_sql_passwd.c' => {
2468        SQLPasswordEngine => 'on',
2469        SQLPasswordEncoding => 'hex',
2470      },
2471    },
2472  };
2473
2474  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2475
2476  # Open pipes, for use between the parent and child processes.  Specifically,
2477  # the child will indicate when it's done with its test by writing a message
2478  # to the parent.
2479  my ($rfh, $wfh);
2480  unless (pipe($rfh, $wfh)) {
2481    die("Can't open pipe: $!");
2482  }
2483
2484  my $ex;
2485
2486  # Fork child
2487  $self->handle_sigchld();
2488  defined(my $pid = fork()) or die("Can't fork: $!");
2489  if ($pid) {
2490    eval {
2491      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2492      $client->login($user, "test");
2493
2494      my $resp_msgs = $client->response_msgs();
2495      my $nmsgs = scalar(@$resp_msgs);
2496
2497      my $expected;
2498
2499      $expected = 1;
2500      $self->assert($expected == $nmsgs,
2501        test_msg("Expected $expected, got $nmsgs"));
2502
2503      $expected = "User proftpd logged in";
2504      $self->assert($expected eq $resp_msgs->[0],
2505        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
2506
2507    };
2508
2509    if ($@) {
2510      $ex = $@;
2511    }
2512
2513    $wfh->print("done\n");
2514    $wfh->flush();
2515
2516  } else {
2517    eval { server_wait($config_file, $rfh) };
2518    if ($@) {
2519      warn($@);
2520      exit 1;
2521    }
2522
2523    exit 0;
2524  }
2525
2526  # Stop server
2527  server_stop($pid_file);
2528
2529  $self->assert_child_ok($pid);
2530
2531  if ($ex) {
2532    die($ex);
2533  }
2534
2535  unlink($log_file);
2536}
2537
2538sub sql_passwd_sha512_hex_uc_bug3344 {
2539  my $self = shift;
2540  my $tmpdir = $self->{tmpdir};
2541
2542  my $config_file = "$tmpdir/sqlpasswd.conf";
2543  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
2544  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
2545
2546  my $log_file = File::Spec->rel2abs('tests.log');
2547
2548  my $user = 'proftpd';
2549
2550  # I used:
2551  #
2552  #  `/bin/echo -n "test" | openssl dgst -hex -sha512`
2553  #
2554  # to generate this password.  Then I manually made all of the letters be
2555  # in uppercase.  Tedious.
2556  my $passwd = 'EE26B0DD4AF7E749AA1A8EE3C10AE9923F618980772E473F8819A5D4940E0DB27AC185F8A0E1D5F84F88BC887FD67B143732C304CC5FA9AD8E6F57F50028A8FF';
2557
2558  my $home_dir = File::Spec->rel2abs($tmpdir);
2559  my $uid = 500;
2560  my $gid = 500;
2561
2562  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
2563
2564  # Build up sqlite3 command to create users, groups tables and populate them
2565  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
2566
2567  if (open(my $fh, "> $db_script")) {
2568    print $fh <<EOS;
2569CREATE TABLE users (
2570  userid TEXT,
2571  passwd TEXT,
2572  uid INTEGER,
2573  gid INTEGER,
2574  homedir TEXT,
2575  shell TEXT
2576);
2577INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', 500, 500, '$home_dir', '/bin/bash');
2578
2579CREATE TABLE groups (
2580  groupname TEXT,
2581  gid INTEGER,
2582  members TEXT
2583);
2584INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', 500, '$user');
2585EOS
2586
2587    unless (close($fh)) {
2588      die("Can't write $db_script: $!");
2589    }
2590
2591  } else {
2592    die("Can't open $db_script: $!");
2593  }
2594
2595  my $cmd = "sqlite3 $db_file < $db_script";
2596
2597  if ($ENV{TEST_VERBOSE}) {
2598    print STDERR "Executing sqlite3: $cmd\n";
2599  }
2600
2601  my @output = `$cmd`;
2602  if (scalar(@output) &&
2603      $ENV{TEST_VERBOSE}) {
2604    print STDERR "Output: ", join('', @output), "\n";
2605  }
2606
2607  my $config = {
2608    PidFile => $pid_file,
2609    ScoreboardFile => $scoreboard_file,
2610    SystemLog => $log_file,
2611
2612    IfModules => {
2613      'mod_delay.c' => {
2614        DelayEngine => 'off',
2615      },
2616
2617      'mod_sql.c' => {
2618        SQLAuthTypes => 'sha512',
2619        SQLBackend => 'sqlite3',
2620        SQLConnectInfo => $db_file,
2621        SQLLogFile => $log_file,
2622      },
2623
2624      'mod_sql_passwd.c' => {
2625        SQLPasswordEngine => 'on',
2626        SQLPasswordEncoding => 'HEX',
2627      },
2628    },
2629  };
2630
2631  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2632
2633  # Open pipes, for use between the parent and child processes.  Specifically,
2634  # the child will indicate when it's done with its test by writing a message
2635  # to the parent.
2636  my ($rfh, $wfh);
2637  unless (pipe($rfh, $wfh)) {
2638    die("Can't open pipe: $!");
2639  }
2640
2641  my $ex;
2642
2643  # Fork child
2644  $self->handle_sigchld();
2645  defined(my $pid = fork()) or die("Can't fork: $!");
2646  if ($pid) {
2647    eval {
2648      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2649      $client->login($user, "test");
2650
2651      my $resp_msgs = $client->response_msgs();
2652      my $nmsgs = scalar(@$resp_msgs);
2653
2654      my $expected;
2655
2656      $expected = 1;
2657      $self->assert($expected == $nmsgs,
2658        test_msg("Expected $expected, got $nmsgs"));
2659
2660      $expected = "User proftpd logged in";
2661      $self->assert($expected eq $resp_msgs->[0],
2662        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
2663
2664    };
2665
2666    if ($@) {
2667      $ex = $@;
2668    }
2669
2670    $wfh->print("done\n");
2671    $wfh->flush();
2672
2673  } else {
2674    eval { server_wait($config_file, $rfh) };
2675    if ($@) {
2676      warn($@);
2677      exit 1;
2678    }
2679
2680    exit 0;
2681  }
2682
2683  # Stop server
2684  server_stop($pid_file);
2685
2686  $self->assert_child_ok($pid);
2687
2688  if ($ex) {
2689    die($ex);
2690  }
2691
2692  unlink($log_file);
2693}
2694
2695sub sql_passwd_user_salt_name {
2696  my $self = shift;
2697  my $tmpdir = $self->{tmpdir};
2698
2699  my $config_file = "$tmpdir/sqlpasswd.conf";
2700  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
2701  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
2702
2703  my $log_file = File::Spec->rel2abs('tests.log');
2704
2705  my $user = 'proftpd';
2706
2707  # I used:
2708  #
2709  #  Digest::SHA1::sha1_hex((lc("password")) . $user);
2710  #
2711  # to generate this password.
2712  my $passwd = '0934e2799b96d7f93fdfaaa13853dfa291e09cb1';
2713
2714  my $home_dir = File::Spec->rel2abs($tmpdir);
2715  my $uid = 500;
2716  my $gid = 500;
2717
2718  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
2719
2720  # Build up sqlite3 command to create users, groups tables and populate them
2721  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
2722
2723  if (open(my $fh, "> $db_script")) {
2724    print $fh <<EOS;
2725CREATE TABLE users (
2726  userid TEXT,
2727  passwd TEXT,
2728  uid INTEGER,
2729  gid INTEGER,
2730  homedir TEXT,
2731  shell TEXT
2732);
2733INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash');
2734
2735CREATE TABLE groups (
2736  groupname TEXT,
2737  gid INTEGER,
2738  members TEXT
2739);
2740INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', $gid, '$user');
2741EOS
2742
2743    unless (close($fh)) {
2744      die("Can't write $db_script: $!");
2745    }
2746
2747  } else {
2748    die("Can't open $db_script: $!");
2749  }
2750
2751  my $cmd = "sqlite3 $db_file < $db_script";
2752
2753  if ($ENV{TEST_VERBOSE}) {
2754    print STDERR "Executing sqlite3: $cmd\n";
2755  }
2756
2757  my @output = `$cmd`;
2758  if (scalar(@output) &&
2759      $ENV{TEST_VERBOSE}) {
2760    print STDERR "Output: ", join('', @output), "\n";
2761  }
2762
2763  my $config = {
2764    PidFile => $pid_file,
2765    ScoreboardFile => $scoreboard_file,
2766    SystemLog => $log_file,
2767
2768    IfModules => {
2769      'mod_delay.c' => {
2770        DelayEngine => 'off',
2771      },
2772
2773      'mod_sql.c' => {
2774        SQLAuthTypes => 'sha1',
2775        SQLBackend => 'sqlite3',
2776        SQLConnectInfo => $db_file,
2777        SQLLogFile => $log_file,
2778      },
2779
2780      'mod_sql_passwd.c' => {
2781        SQLPasswordEngine => 'on',
2782        SQLPasswordEncoding => 'hex',
2783        SQLPasswordUserSalt => 'name',
2784      },
2785    },
2786  };
2787
2788  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2789
2790  # Open pipes, for use between the parent and child processes.  Specifically,
2791  # the child will indicate when it's done with its test by writing a message
2792  # to the parent.
2793  my ($rfh, $wfh);
2794  unless (pipe($rfh, $wfh)) {
2795    die("Can't open pipe: $!");
2796  }
2797
2798  my $ex;
2799
2800  # Fork child
2801  $self->handle_sigchld();
2802  defined(my $pid = fork()) or die("Can't fork: $!");
2803  if ($pid) {
2804    eval {
2805      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2806      $client->login($user, "password");
2807
2808      my $resp_msgs = $client->response_msgs();
2809      my $nmsgs = scalar(@$resp_msgs);
2810
2811      my $expected;
2812
2813      $expected = 1;
2814      $self->assert($expected == $nmsgs,
2815        test_msg("Expected $expected, got $nmsgs"));
2816
2817      $expected = "User proftpd logged in";
2818      $self->assert($expected eq $resp_msgs->[0],
2819        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
2820
2821    };
2822
2823    if ($@) {
2824      $ex = $@;
2825    }
2826
2827    $wfh->print("done\n");
2828    $wfh->flush();
2829
2830  } else {
2831    eval { server_wait($config_file, $rfh) };
2832    if ($@) {
2833      warn($@);
2834      exit 1;
2835    }
2836
2837    exit 0;
2838  }
2839
2840  # Stop server
2841  server_stop($pid_file);
2842
2843  $self->assert_child_ok($pid);
2844
2845  if ($ex) {
2846    die($ex);
2847  }
2848
2849  unlink($log_file);
2850}
2851
2852sub sql_passwd_user_salt_sql {
2853  my $self = shift;
2854  my $tmpdir = $self->{tmpdir};
2855
2856  my $config_file = "$tmpdir/sqlpasswd.conf";
2857  my $pid_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.pid");
2858  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sqlpasswd.scoreboard");
2859
2860  my $log_file = File::Spec->rel2abs('tests.log');
2861
2862  my $user = 'proftpd';
2863
2864  my $salt = 'MyS00p3r$3kr3t$@lt';
2865
2866  # I used:
2867  #
2868  #  Digest::SHA1::sha1_hex((lc("password")) . $salt);
2869  #
2870  # to generate this password.
2871  my $passwd = 'cbaae8ec99dad240e86b64c66d31272b39a87e2e';
2872
2873  my $home_dir = File::Spec->rel2abs($tmpdir);
2874  my $uid = 500;
2875  my $gid = 500;
2876
2877  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
2878
2879  # Build up sqlite3 command to create users, groups tables and populate them
2880  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
2881
2882  if (open(my $fh, "> $db_script")) {
2883    print $fh <<EOS;
2884CREATE TABLE users (
2885  userid TEXT,
2886  passwd TEXT,
2887  uid INTEGER,
2888  gid INTEGER,
2889  homedir TEXT,
2890  shell TEXT
2891);
2892INSERT INTO users (userid, passwd, uid, gid, homedir, shell) VALUES ('$user', '$passwd', $uid, $gid, '$home_dir', '/bin/bash');
2893
2894CREATE TABLE groups (
2895  groupname TEXT,
2896  gid INTEGER,
2897  members TEXT
2898);
2899INSERT INTO groups (groupname, gid, members) VALUES ('ftpd', $gid, '$user');
2900
2901CREATE TABLE user_salts (
2902  userid TEXT,
2903  salt TEXT
2904);
2905INSERT INTO user_salts (userid, salt) VALUES ('$user', '$salt');
2906EOS
2907
2908    unless (close($fh)) {
2909      die("Can't write $db_script: $!");
2910    }
2911
2912  } else {
2913    die("Can't open $db_script: $!");
2914  }
2915
2916  my $cmd = "sqlite3 $db_file < $db_script";
2917
2918  if ($ENV{TEST_VERBOSE}) {
2919    print STDERR "Executing sqlite3: $cmd\n";
2920  }
2921
2922  my @output = `$cmd`;
2923  if (scalar(@output) &&
2924      $ENV{TEST_VERBOSE}) {
2925    print STDERR "Output: ", join('', @output), "\n";
2926  }
2927
2928  my $config = {
2929    PidFile => $pid_file,
2930    ScoreboardFile => $scoreboard_file,
2931    SystemLog => $log_file,
2932
2933    IfModules => {
2934      'mod_delay.c' => {
2935        DelayEngine => 'off',
2936      },
2937
2938      'mod_sql.c' => {
2939        SQLAuthTypes => 'sha1',
2940        SQLBackend => 'sqlite3',
2941        SQLConnectInfo => $db_file,
2942        SQLLogFile => $log_file,
2943        SQLNamedQuery => 'get-user-salt SELECT "salt FROM user_salts WHERE userid = \'%{0}\'"',
2944      },
2945
2946      'mod_sql_passwd.c' => {
2947        SQLPasswordEngine => 'on',
2948        SQLPasswordEncoding => 'hex',
2949        SQLPasswordUserSalt => 'sql:/get-user-salt',
2950      },
2951    },
2952  };
2953
2954  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2955
2956  # Open pipes, for use between the parent and child processes.  Specifically,
2957  # the child will indicate when it's done with its test by writing a message
2958  # to the parent.
2959  my ($rfh, $wfh);
2960  unless (pipe($rfh, $wfh)) {
2961    die("Can't open pipe: $!");
2962  }
2963
2964  my $ex;
2965
2966  # Fork child
2967  $self->handle_sigchld();
2968  defined(my $pid = fork()) or die("Can't fork: $!");
2969  if ($pid) {
2970    eval {
2971      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2972      $client->login($user, "password");
2973
2974      my $resp_msgs = $client->response_msgs();
2975      my $nmsgs = scalar(@$resp_msgs);
2976
2977      my $expected;
2978
2979      $expected = 1;
2980      $self->assert($expected == $nmsgs,
2981        test_msg("Expected $expected, got $nmsgs"));
2982
2983      $expected = "User proftpd logged in";
2984      $self->assert($expected eq $resp_msgs->[0],
2985        test_msg("Expected '$expected', got '$resp_msgs->[0]'"));
2986
2987    };
2988
2989    if ($@) {
2990      $ex = $@;
2991    }
2992
2993    $wfh->print("done\n");
2994    $wfh->flush();
2995
2996  } else {
2997    eval { server_wait($config_file, $rfh) };
2998    if ($@) {
2999      warn($@);
3000      exit 1;
3001    }
3002
3003    exit 0;
3004  }
3005
3006  # Stop server
3007  server_stop($pid_file);
3008
3009  $self->assert_child_ok($pid);
3010
3011  if ($ex) {
3012    die($ex);
3013  }
3014
3015  unlink($log_file);
3016}
3017
30181;
Note: See TracBrowser for help on using the repository browser.