1package ProFTPD::Tests::Modules::mod_wrap2_sql;
2
3use lib qw(t/lib);
4use base qw(ProFTPD::TestSuite::Child);
5use strict;
6
7use File::Spec;
8use IO::Handle;
9use IO::Socket::INET6;
10
11use ProFTPD::TestSuite::FTP;
12use ProFTPD::TestSuite::Utils qw(:auth :config :features :running :test :testsuite);
13
14$| = 1;
15
16my $order = 0;
17
18my $TESTS = {
19  wrap2_allow_msg => {
20    order => ++$order,
21    test_class => [qw(forking)],
22  },
23
24  wrap2_deny_msg => {
25    order => ++$order,
26    test_class => [qw(forking)],
27  },
28
29  wrap2_engine => {
30    order => ++$order,
31    test_class => [qw(forking)],
32  },
33
34  wrap2_sql_allow_table => {
35    order => ++$order,
36    test_class => [qw(forking)],
37  },
38
39  wrap2_sql_allow_table_multi_rows_multi_entries => {
40    order => ++$order,
41    test_class => [qw(bug forking)],
42  },
43
44  wrap2_sql_allow_table_all => {
45    order => ++$order,
46    test_class => [qw(bug forking)],
47  },
48
49  wrap2_sql_deny_table_ip_addr => {
50    order => ++$order,
51    test_class => [qw(forking)],
52  },
53
54  wrap2_sql_deny_table_ipv4_netmask => {
55    order => ++$order,
56    test_class => [qw(forking)],
57  },
58
59  wrap2_sql_deny_table_ipv4mappedv6_netmask => {
60    order => ++$order,
61    test_class => [qw(bug feature_ipv6 forking)],
62  },
63
64  wrap2_sql_deny_table_ipv6_netmask_bug3606 => {
65    order => ++$order,
66    test_class => [qw(bug feature_ipv6 forking)],
67  },
68
69  wrap2_sql_deny_table_dns_name => {
70    order => ++$order,
71    test_class => [qw(forking)],
72  },
73
74  wrap2_sql_deny_table_dns_domain_bug3558 => {
75    order => ++$order,
76    test_class => [qw(bug forking)],
77  },
78
79  wrap2_sql_user_tables => {
80    order => ++$order,
81    test_class => [qw(forking)],
82  },
83
84  wrap2_sql_group_tables => {
85    order => ++$order,
86    test_class => [qw(forking)],
87  },
88
89  wrap2_sql_bug3215 => {
90    order => ++$order,
91    test_class => [qw(bug forking)],
92  },
93
94  wrap2_bug3341 => {
95    order => ++$order,
96    test_class => [qw(bug forking)],
97  },
98
99  wrap2_sql_opt_check_on_connect_bug3508 => {
100    order => ++$order,
101    test_class => [qw(bug forking)],
102  },
103
104  wrap2_allow_msg_bug3538 => {
105    order => ++$order,
106    test_class => [qw(forking)],
107  },
108
109  wrap2_allow_msg_anon_bug3538 => {
110    order => ++$order,
111    test_class => [qw(forking rootprivs)],
112  },
113
114  wrap2_sql_deny_event_exec_bug3209 => {
115    order => ++$order,
116    test_class => [qw(forking mod_exec)],
117  },
118
119};
120
121sub new {
122  return shift()->SUPER::new(@_);
123}
124
125sub list_tests {
126  return testsuite_get_runnable_tests($TESTS);
127}
128
129sub wrap2_allow_msg {
130  my $self = shift;
131  my $tmpdir = $self->{tmpdir};
132
133  my $config_file = "$tmpdir/wrap2.conf";
134  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
135  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
136
137  my $log_file = test_get_logfile();
138
139  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
140  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
141
142  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
143
144  # Build up sqlite3 command to create allow, deny tables and populate them
145  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
146
147  my $fh;
148  if (open($fh, "> $db_script")) {
149    print $fh <<EOS;
150CREATE TABLE ftpallow (
151  name TEXT,
152  allowed TEXT
153);
154
155CREATE TABLE ftpdeny (
156  name TEXT,
157  denied TEXT
158);
159
160EOS
161
162    unless (close($fh)) {
163      die("Can't write $db_script: $!");
164    }
165
166  } else {
167    die("Can't open $db_script: $!");
168  }
169
170  my $cmd = "sqlite3 $db_file < $db_script";
171
172  if ($ENV{TEST_VERBOSE}) {
173    print STDERR "Executing sqlite3: $cmd\n";
174  }
175
176  my @output = `$cmd`;
177
178  unlink($db_script);
179
180  my $user = 'proftpd';
181  my $passwd = 'test';
182  my $group = 'ftpd';
183  my $home_dir = File::Spec->rel2abs($tmpdir);
184  my $uid = 500;
185  my $gid = 500;
186
187  # Make sure that, if we're running as root, that the home directory has
188  # permissions/privs set for the account we create
189  if ($< == 0) {
190    unless (chmod(0755, $home_dir)) {
191      die("Can't set perms on $home_dir to 0755: $!");
192    }
193
194    unless (chown($uid, $gid, $home_dir)) {
195      die("Can't set owner of $home_dir to $uid/$gid: $!");
196    }
197  }
198
199  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
200    '/bin/bash');
201  auth_group_write($auth_group_file, $group, $gid, $user);
202
203  my $timeout_idle = 30;
204
205  my $config = {
206    PidFile => $pid_file,
207    ScoreboardFile => $scoreboard_file,
208    SystemLog => $log_file,
209
210    AuthUserFile => $auth_user_file,
211    AuthGroupFile => $auth_group_file,
212    TimeoutIdle => $timeout_idle,
213
214    IfModules => {
215      'mod_delay.c' => {
216        DelayEngine => 'off',
217      },
218
219      'mod_sql_sqlite.c' => [
220        'SQLAuthenticate off',
221        "SQLConnectInfo $db_file",
222        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
223        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
224        "SQLLogFile $log_file",
225      ],
226
227      'mod_wrap2_sql.c' => {
228        WrapEngine => 'on',
229        WrapAllowMsg => '"User %u allowed by access rules"',
230        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
231        WrapLog => $log_file,
232      },
233    },
234  };
235
236  my ($port, $config_user, $config_group) = config_write($config_file, $config);
237
238  # Open pipes, for use between the parent and child processes.  Specifically,
239  # the child will indicate when it's done with its test by writing a message
240  # to the parent.
241  my ($rfh, $wfh);
242  unless (pipe($rfh, $wfh)) {
243    die("Can't open pipe: $!");
244  }
245
246  my $ex;
247
248  # Fork child
249  $self->handle_sigchld();
250  defined(my $pid = fork()) or die("Can't fork: $!");
251  if ($pid) {
252    eval {
253      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
254      $client->login($user, $passwd);
255
256      my $resp_code = $client->response_code();
257      my $resp_msg = $client->response_msg(0);
258
259      my $expected;
260
261      $expected = 230;
262      $self->assert($expected == $resp_code,
263        test_msg("Expected response code $expected, got $resp_code"));
264
265      $expected = "User $user allowed by access rules";
266      $self->assert($expected eq $resp_msg,
267        test_msg("Expected response message '$expected', got '$resp_msg'"));
268    };
269
270    if ($@) {
271      $ex = $@;
272    }
273
274    $wfh->print("done\n");
275    $wfh->flush();
276
277  } else {
278    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
279    if ($@) {
280      warn($@);
281      exit 1;
282    }
283
284    exit 0;
285  }
286
287  # Stop server
288  server_stop($pid_file);
289
290  $self->assert_child_ok($pid);
291
292  if ($ex) {
293    test_append_logfile($log_file, $ex);
294    unlink($log_file);
295
296    die($ex);
297  }
298
299  unlink($log_file);
300}
301
302sub wrap2_deny_msg {
303  my $self = shift;
304  my $tmpdir = $self->{tmpdir};
305
306  my $config_file = "$tmpdir/wrap2.conf";
307  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
308  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
309
310  my $log_file = test_get_logfile();
311
312  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
313  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
314
315  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
316
317  # Build up sqlite3 command to create allow, deny tables and populate them
318  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
319
320  my $fh;
321  if (open($fh, "> $db_script")) {
322    print $fh <<EOS;
323CREATE TABLE ftpallow (
324  name TEXT,
325  allowed TEXT
326);
327
328CREATE TABLE ftpdeny (
329  name TEXT,
330  denied TEXT
331);
332
333INSERT INTO ftpdeny (name, denied) VALUES ('', 'ALL');
334EOS
335
336    unless (close($fh)) {
337      die("Can't write $db_script: $!");
338    }
339
340  } else {
341    die("Can't open $db_script: $!");
342  }
343
344  my $cmd = "sqlite3 $db_file < $db_script";
345
346  if ($ENV{TEST_VERBOSE}) {
347    print STDERR "Executing sqlite3: $cmd\n";
348  }
349
350  my @output = `$cmd`;
351
352  unlink($db_script);
353
354  my $user = 'proftpd';
355  my $passwd = 'test';
356  my $group = 'ftpd';
357  my $home_dir = File::Spec->rel2abs($tmpdir);
358  my $uid = 500;
359  my $gid = 500;
360
361  # Make sure that, if we're running as root, that the home directory has
362  # permissions/privs set for the account we create
363  if ($< == 0) {
364    unless (chmod(0755, $home_dir)) {
365      die("Can't set perms on $home_dir to 0755: $!");
366    }
367
368    unless (chown($uid, $gid, $home_dir)) {
369      die("Can't set owner of $home_dir to $uid/$gid: $!");
370    }
371  }
372
373  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
374    '/bin/bash');
375  auth_group_write($auth_group_file, $group, $gid, $user);
376
377  my $timeout_idle = 30;
378
379  my $config = {
380    PidFile => $pid_file,
381    ScoreboardFile => $scoreboard_file,
382    SystemLog => $log_file,
383
384    AuthUserFile => $auth_user_file,
385    AuthGroupFile => $auth_group_file,
386    TimeoutIdle => $timeout_idle,
387
388    IfModules => {
389      'mod_delay.c' => {
390        DelayEngine => 'off',
391      },
392
393      'mod_sql_sqlite.c' => [
394        'SQLAuthenticate off',
395        "SQLConnectInfo $db_file",
396        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
397        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
398        "SQLLogFile $log_file",
399      ],
400
401      'mod_wrap2_sql.c' => {
402        WrapEngine => 'on',
403        WrapDenyMsg => '"User %u rejected by access rules"',
404        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
405        WrapLog => $log_file,
406      },
407    },
408  };
409
410  my ($port, $config_user, $config_group) = config_write($config_file, $config);
411
412  # Open pipes, for use between the parent and child processes.  Specifically,
413  # the child will indicate when it's done with its test by writing a message
414  # to the parent.
415  my ($rfh, $wfh);
416  unless (pipe($rfh, $wfh)) {
417    die("Can't open pipe: $!");
418  }
419
420  my $ex;
421
422  # Fork child
423  $self->handle_sigchld();
424  defined(my $pid = fork()) or die("Can't fork: $!");
425  if ($pid) {
426    eval {
427      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
428
429      my ($resp_code, $resp_msg);
430
431      eval { $client->login($user, $passwd) };
432      unless ($@) {
433        die("Login succeeded unexpectedly");
434
435      } else {
436        $resp_code = $client->response_code();
437        $resp_msg = $client->response_msg();
438      }
439
440      my $expected;
441
442      $expected = 530;
443      $self->assert($expected == $resp_code,
444        test_msg("Expected response code $expected, got $resp_code"));
445
446      $expected = "User $user rejected by access rules";
447      $self->assert($expected eq $resp_msg,
448        test_msg("Expected response message '$expected', got '$resp_msg'"));
449    };
450
451    if ($@) {
452      $ex = $@;
453    }
454
455    $wfh->print("done\n");
456    $wfh->flush();
457
458  } else {
459    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
460    if ($@) {
461      warn($@);
462      exit 1;
463    }
464
465    exit 0;
466  }
467
468  # Stop server
469  server_stop($pid_file);
470
471  $self->assert_child_ok($pid);
472
473  if ($ex) {
474    test_append_logfile($log_file, $ex);
475    unlink($log_file);
476
477    die($ex);
478  }
479
480  unlink($log_file);
481}
482
483sub wrap2_engine {
484  my $self = shift;
485  my $tmpdir = $self->{tmpdir};
486
487  my $config_file = "$tmpdir/wrap2.conf";
488  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
489  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
490
491  my $log_file = test_get_logfile();
492
493  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
494  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
495
496  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
497
498  # Build up sqlite3 command to create allow, deny tables and populate them
499  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
500
501  my $fh;
502  if (open($fh, "> $db_script")) {
503    print $fh <<EOS;
504CREATE TABLE ftpallow (
505  name TEXT,
506  allowed TEXT
507);
508
509CREATE TABLE ftpdeny (
510  name TEXT,
511  denied TEXT
512);
513
514INSERT INTO ftpdeny (name, denied) VALUES ('', 'ALL');
515EOS
516
517    unless (close($fh)) {
518      die("Can't write $db_script: $!");
519    }
520
521  } else {
522    die("Can't open $db_script: $!");
523  }
524
525  my $cmd = "sqlite3 $db_file < $db_script";
526
527  if ($ENV{TEST_VERBOSE}) {
528    print STDERR "Executing sqlite3: $cmd\n";
529  }
530
531  my @output = `$cmd`;
532
533  unlink($db_script);
534
535  my $user = 'proftpd';
536  my $passwd = 'test';
537  my $group = 'ftpd';
538  my $home_dir = File::Spec->rel2abs($tmpdir);
539  my $uid = 500;
540  my $gid = 500;
541
542  # Make sure that, if we're running as root, that the home directory has
543  # permissions/privs set for the account we create
544  if ($< == 0) {
545    unless (chmod(0755, $home_dir)) {
546      die("Can't set perms on $home_dir to 0755: $!");
547    }
548
549    unless (chown($uid, $gid, $home_dir)) {
550      die("Can't set owner of $home_dir to $uid/$gid: $!");
551    }
552  }
553
554  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
555    '/bin/bash');
556  auth_group_write($auth_group_file, $group, $gid, $user);
557
558  my $timeout_idle = 30;
559
560  my $config = {
561    PidFile => $pid_file,
562    ScoreboardFile => $scoreboard_file,
563    SystemLog => $log_file,
564
565    AuthUserFile => $auth_user_file,
566    AuthGroupFile => $auth_group_file,
567    TimeoutIdle => $timeout_idle,
568
569    IfModules => {
570      'mod_delay.c' => {
571        DelayEngine => 'off',
572      },
573
574      'mod_sql_sqlite.c' => [
575        'SQLAuthenticate off',
576        "SQLConnectInfo $db_file",
577        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
578        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
579        "SQLLogFile $log_file",
580      ],
581
582      'mod_wrap2_sql.c' => {
583        WrapEngine => 'off',
584        WrapAllowMsg => '"User %u allowed by access rules"',
585        WrapDenyMsg => '"User %u rejected by access rules"',
586        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
587      },
588    },
589  };
590
591  my ($port, $config_user, $config_group) = config_write($config_file, $config);
592
593  # Open pipes, for use between the parent and child processes.  Specifically,
594  # the child will indicate when it's done with its test by writing a message
595  # to the parent.
596  my ($rfh, $wfh);
597  unless (pipe($rfh, $wfh)) {
598    die("Can't open pipe: $!");
599  }
600
601  my $ex;
602
603  # Fork child
604  $self->handle_sigchld();
605  defined(my $pid = fork()) or die("Can't fork: $!");
606  if ($pid) {
607    eval {
608      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
609      my ($resp_code, $resp_msg) = $client->login($user, $passwd);
610
611      my $expected;
612
613      $expected = 230;
614      $self->assert($expected == $resp_code,
615        test_msg("Expected response code $expected, got $resp_code"));
616
617      $expected = "User $user logged in";
618      $self->assert($expected eq $resp_msg,
619        test_msg("Expected response message '$expected', got '$resp_msg'"));
620    };
621
622    if ($@) {
623      $ex = $@;
624    }
625
626    $wfh->print("done\n");
627    $wfh->flush();
628
629  } else {
630    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
631    if ($@) {
632      warn($@);
633      exit 1;
634    }
635
636    exit 0;
637  }
638
639  # Stop server
640  server_stop($pid_file);
641
642  $self->assert_child_ok($pid);
643
644  if ($ex) {
645    test_append_logfile($log_file, $ex);
646    unlink($log_file);
647
648    die($ex);
649  }
650
651  unlink($log_file);
652}
653
654sub wrap2_sql_allow_table {
655  my $self = shift;
656  my $tmpdir = $self->{tmpdir};
657
658  my $config_file = "$tmpdir/wrap2.conf";
659  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
660  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
661
662  my $log_file = test_get_logfile();
663
664  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
665  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
666
667  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
668
669  # Build up sqlite3 command to create allow, deny tables and populate them
670  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
671
672  my $fh;
673  if (open($fh, "> $db_script")) {
674    print $fh <<EOS;
675CREATE TABLE ftpallow (
676  name TEXT,
677  allowed TEXT
678);
679
680CREATE TABLE ftpdeny (
681  name TEXT,
682  denied TEXT
683);
684
685EOS
686
687    unless (close($fh)) {
688      die("Can't write $db_script: $!");
689    }
690
691  } else {
692    die("Can't open $db_script: $!");
693  }
694
695  my $cmd = "sqlite3 $db_file < $db_script";
696
697  if ($ENV{TEST_VERBOSE}) {
698    print STDERR "Executing sqlite3: $cmd\n";
699  }
700
701  my @output = `$cmd`;
702
703  unlink($db_script);
704
705  my $user = 'proftpd';
706  my $passwd = 'test';
707  my $group = 'ftpd';
708  my $home_dir = File::Spec->rel2abs($tmpdir);
709  my $uid = 500;
710  my $gid = 500;
711
712  # Make sure that, if we're running as root, that the home directory has
713  # permissions/privs set for the account we create
714  if ($< == 0) {
715    unless (chmod(0755, $home_dir)) {
716      die("Can't set perms on $home_dir to 0755: $!");
717    }
718
719    unless (chown($uid, $gid, $home_dir)) {
720      die("Can't set owner of $home_dir to $uid/$gid: $!");
721    }
722  }
723
724  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
725    '/bin/bash');
726  auth_group_write($auth_group_file, $group, $gid, $user);
727
728  my $timeout_idle = 30;
729
730  my $config = {
731    PidFile => $pid_file,
732    ScoreboardFile => $scoreboard_file,
733    SystemLog => $log_file,
734
735    AuthUserFile => $auth_user_file,
736    AuthGroupFile => $auth_group_file,
737    TimeoutIdle => $timeout_idle,
738
739    IfModules => {
740      'mod_delay.c' => {
741        DelayEngine => 'off',
742      },
743
744      'mod_sql_sqlite.c' => [
745        'SQLAuthenticate off',
746        "SQLConnectInfo $db_file",
747        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
748        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
749        "SQLLogFile $log_file",
750      ],
751
752      'mod_wrap2_sql.c' => {
753        WrapEngine => 'on',
754        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
755      },
756    },
757  };
758
759  my ($port, $config_user, $config_group) = config_write($config_file, $config);
760
761  # Open pipes, for use between the parent and child processes.  Specifically,
762  # the child will indicate when it's done with its test by writing a message
763  # to the parent.
764  my ($rfh, $wfh);
765  unless (pipe($rfh, $wfh)) {
766    die("Can't open pipe: $!");
767  }
768
769  my $ex;
770
771  # Fork child
772  $self->handle_sigchld();
773  defined(my $pid = fork()) or die("Can't fork: $!");
774  if ($pid) {
775    eval {
776      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
777      my ($resp_code, $resp_msg) = $client->login($user, $passwd);
778
779      my $expected;
780
781      $expected = 230;
782      $self->assert($expected == $resp_code,
783        test_msg("Expected response code $expected, got $resp_code"));
784
785      $expected = "User $user logged in";
786      $self->assert($expected eq $resp_msg,
787        test_msg("Expected response message '$expected', got '$resp_msg'"));
788    };
789
790    if ($@) {
791      $ex = $@;
792    }
793
794    $wfh->print("done\n");
795    $wfh->flush();
796
797  } else {
798    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
799    if ($@) {
800      warn($@);
801      exit 1;
802    }
803
804    exit 0;
805  }
806
807  # Stop server
808  server_stop($pid_file);
809
810  $self->assert_child_ok($pid);
811
812  if ($ex) {
813    die($ex);
814  }
815
816  if (open($fh, "> $db_script")) {
817    print $fh <<EOS;
818INSERT INTO ftpallow (name, allowed) VALUES ('', '127.0.0.1');
819EOS
820    unless (close($fh)) {
821      die("Can't write $db_script: $!");
822    }
823
824  } else {
825    die("Can't open $db_script: $!");
826  }
827
828  $cmd = "sqlite3 $db_file < $db_script";
829
830  if ($ENV{TEST_VERBOSE}) {
831    print STDERR "Executing sqlite3: $cmd\n";
832  }
833
834  @output = `$cmd`;
835
836  unlink($db_script);
837
838  ($port, $config_user, $config_group) = config_write($config_file, $config);
839
840  # Fork child
841  $self->handle_sigchld();
842  defined($pid = fork()) or die("Can't fork: $!");
843  if ($pid) {
844    eval {
845      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
846      my ($resp_code, $resp_msg) = $client->login($user, $passwd);
847
848      my $expected;
849
850      $expected = 230;
851      $self->assert($expected == $resp_code,
852        test_msg("Expected response code $expected, got $resp_code"));
853
854      $expected = "User $user logged in";
855      $self->assert($expected eq $resp_msg,
856        test_msg("Expected response message '$expected', got '$resp_msg'"));
857    };
858
859    if ($@) {
860      $ex = $@;
861    }
862
863    $wfh->print("done\n");
864    $wfh->flush();
865
866  } else {
867    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
868    if ($@) {
869      warn($@);
870      exit 1;
871    }
872
873    exit 0;
874  }
875
876  # Stop server
877  server_stop($pid_file);
878
879  $self->assert_child_ok($pid);
880
881  if ($ex) {
882    test_append_logfile($log_file, $ex);
883    unlink($log_file);
884
885    die($ex);
886  }
887
888  unlink($log_file);
889}
890
891sub wrap2_sql_allow_table_multi_rows_multi_entries {
892  my $self = shift;
893  my $tmpdir = $self->{tmpdir};
894
895  my $config_file = "$tmpdir/wrap2.conf";
896  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
897  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
898
899  my $log_file = test_get_logfile();
900
901  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
902  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
903
904  my $user = 'proftpd';
905  my $passwd = 'test';
906  my $group = 'ftpd';
907  my $home_dir = File::Spec->rel2abs($tmpdir);
908  my $uid = 500;
909  my $gid = 500;
910
911  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
912
913  # Build up sqlite3 command to create allow, deny tables and populate them
914  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
915
916  my $fh;
917  if (open($fh, "> $db_script")) {
918    print $fh <<EOS;
919CREATE TABLE ftpallow (
920  name TEXT,
921  allowed TEXT
922);
923
924INSERT INTO ftpallow (name, allowed) VALUES ('', '192.168.127.5, 192.168.127.6');
925INSERT INTO ftpallow (name, allowed) VALUES ('', '192.168.127.1 192.168.127.2 127.0.0.1');
926INSERT INTO ftpallow (name, allowed) VALUES ('', '192.168.127.3,192.168.127.4 127.0.0.1');
927
928CREATE TABLE ftpdeny (
929  name TEXT,
930  denied TEXT
931);
932
933INSERT INTO ftpdeny (name, denied) VALUES ('', 'ALL');
934EOS
935
936    unless (close($fh)) {
937      die("Can't write $db_script: $!");
938    }
939
940  } else {
941    die("Can't open $db_script: $!");
942  }
943
944  my $cmd = "sqlite3 $db_file < $db_script";
945  if ($ENV{TEST_VERBOSE}) {
946    print STDERR "Executing sqlite3: $cmd\n";
947  }
948
949  my @output = `$cmd`;
950
951  unlink($db_script);
952
953  # Make sure that, if we're running as root, that the home directory has
954  # permissions/privs set for the account we create
955  if ($< == 0) {
956    unless (chmod(0755, $home_dir)) {
957      die("Can't set perms on $home_dir to 0755: $!");
958    }
959
960    unless (chown($uid, $gid, $home_dir)) {
961      die("Can't set owner of $home_dir to $uid/$gid: $!");
962    }
963  }
964
965  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
966    '/bin/bash');
967  auth_group_write($auth_group_file, $group, $gid, $user);
968
969  my $timeout_idle = 30;
970
971  my $config = {
972    PidFile => $pid_file,
973    ScoreboardFile => $scoreboard_file,
974    SystemLog => $log_file,
975
976    AuthUserFile => $auth_user_file,
977    AuthGroupFile => $auth_group_file,
978    TimeoutIdle => $timeout_idle,
979
980    IfModules => {
981      'mod_delay.c' => {
982        DelayEngine => 'off',
983      },
984
985      'mod_sql_sqlite.c' => [
986        'SQLAuthenticate off',
987        "SQLConnectInfo $db_file",
988        "SQLLogFile $log_file",
989        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
990        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
991      ],
992
993      'mod_wrap2_sql.c' => {
994        WrapEngine => 'on',
995        WrapLog => $log_file,
996        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
997      },
998    },
999  };
1000
1001  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1002
1003  # Open pipes, for use between the parent and child processes.  Specifically,
1004  # the child will indicate when it's done with its test by writing a message
1005  # to the parent.
1006  my ($rfh, $wfh);
1007  unless (pipe($rfh, $wfh)) {
1008    die("Can't open pipe: $!");
1009  }
1010
1011  my $ex;
1012
1013  # Fork child
1014  $self->handle_sigchld();
1015  defined(my $pid = fork()) or die("Can't fork: $!");
1016  if ($pid) {
1017    eval {
1018      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1019      my ($resp_code, $resp_msg) = $client->login($user, $passwd);
1020
1021      my $expected;
1022
1023      $expected = 230;
1024      $self->assert($expected == $resp_code,
1025        test_msg("Expected response code $expected, got $resp_code"));
1026
1027      $expected = "User $user logged in";
1028      $self->assert($expected eq $resp_msg,
1029        test_msg("Expected response message '$expected', got '$resp_msg'"));
1030    };
1031
1032    if ($@) {
1033      $ex = $@;
1034    }
1035
1036    $wfh->print("done\n");
1037    $wfh->flush();
1038
1039  } else {
1040    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
1041    if ($@) {
1042      warn($@);
1043      exit 1;
1044    }
1045
1046    exit 0;
1047  }
1048
1049  # Stop server
1050  server_stop($pid_file);
1051
1052  $self->assert_child_ok($pid);
1053
1054  if ($ex) {
1055    test_append_logfile($log_file, $ex);
1056    unlink($log_file);
1057
1058    die($ex);
1059  }
1060
1061  unlink($log_file);
1062}
1063
1064sub wrap2_sql_allow_table_all {
1065  my $self = shift;
1066  my $tmpdir = $self->{tmpdir};
1067
1068  my $config_file = "$tmpdir/wrap2.conf";
1069  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
1070  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
1071
1072  my $log_file = test_get_logfile();
1073
1074  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
1075  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
1076
1077  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
1078
1079  # Build up sqlite3 command to create allow, deny tables and populate them
1080  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
1081
1082  my $fh;
1083  if (open($fh, "> $db_script")) {
1084    print $fh <<EOS;
1085CREATE TABLE ftpallow (
1086  name TEXT,
1087  allowed TEXT
1088);
1089
1090INSERT INTO ftpallow (name, allowed) VALUES ('', 'ALL');
1091
1092CREATE TABLE ftpdeny (
1093  name TEXT,
1094  denied TEXT
1095);
1096
1097INSERT INTO ftpdeny (name, allowed) VALUES ('', 'ALL');
1098EOS
1099
1100    unless (close($fh)) {
1101      die("Can't write $db_script: $!");
1102    }
1103
1104  } else {
1105    die("Can't open $db_script: $!");
1106  }
1107
1108  my $cmd = "sqlite3 $db_file < $db_script";
1109  if ($ENV{TEST_VERBOSE}) {
1110    print STDERR "Executing sqlite3: $cmd\n";
1111  }
1112
1113  my @output = `$cmd`;
1114
1115  unlink($db_script);
1116
1117  my $user = 'proftpd';
1118  my $passwd = 'test';
1119  my $group = 'ftpd';
1120  my $home_dir = File::Spec->rel2abs($tmpdir);
1121  my $uid = 500;
1122  my $gid = 500;
1123
1124  # Make sure that, if we're running as root, that the home directory has
1125  # permissions/privs set for the account we create
1126  if ($< == 0) {
1127    unless (chmod(0755, $home_dir)) {
1128      die("Can't set perms on $home_dir to 0755: $!");
1129    }
1130
1131    unless (chown($uid, $gid, $home_dir)) {
1132      die("Can't set owner of $home_dir to $uid/$gid: $!");
1133    }
1134  }
1135
1136  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1137    '/bin/bash');
1138  auth_group_write($auth_group_file, $group, $gid, $user);
1139
1140  my $timeout_idle = 30;
1141
1142  my $config = {
1143    TraceLog => $log_file,
1144    Trace => 'dns:10',
1145    PidFile => $pid_file,
1146    ScoreboardFile => $scoreboard_file,
1147    SystemLog => $log_file,
1148
1149    AuthUserFile => $auth_user_file,
1150    AuthGroupFile => $auth_group_file,
1151    TimeoutIdle => $timeout_idle,
1152
1153    IfModules => {
1154      'mod_delay.c' => {
1155        DelayEngine => 'off',
1156      },
1157
1158      'mod_sql_sqlite.c' => [
1159        'SQLAuthenticate off',
1160        "SQLConnectInfo $db_file",
1161        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
1162        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
1163        "SQLLogFile $log_file",
1164      ],
1165
1166      'mod_wrap2_sql.c' => {
1167        WrapEngine => 'on',
1168        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
1169      },
1170    },
1171  };
1172
1173  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1174
1175  # Open pipes, for use between the parent and child processes.  Specifically,
1176  # the child will indicate when it's done with its test by writing a message
1177  # to the parent.
1178  my ($rfh, $wfh);
1179  unless (pipe($rfh, $wfh)) {
1180    die("Can't open pipe: $!");
1181  }
1182
1183  my $ex;
1184
1185  # Fork child
1186  $self->handle_sigchld();
1187  defined(my $pid = fork()) or die("Can't fork: $!");
1188  if ($pid) {
1189    eval {
1190      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1191      my ($resp_code, $resp_msg) = $client->login($user, $passwd);
1192
1193      my $expected;
1194
1195      $expected = 230;
1196      $self->assert($expected == $resp_code,
1197        test_msg("Expected response code $expected, got $resp_code"));
1198
1199      $expected = "User $user logged in";
1200      $self->assert($expected eq $resp_msg,
1201        test_msg("Expected response message '$expected', got '$resp_msg'"));
1202    };
1203
1204    if ($@) {
1205      $ex = $@;
1206    }
1207
1208    $wfh->print("done\n");
1209    $wfh->flush();
1210
1211  } else {
1212    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
1213    if ($@) {
1214      warn($@);
1215      exit 1;
1216    }
1217
1218    exit 0;
1219  }
1220
1221  # Stop server
1222  server_stop($pid_file);
1223
1224  $self->assert_child_ok($pid);
1225
1226  if ($ex) {
1227    test_append_logfile($log_file, $ex);
1228    unlink($log_file);
1229
1230    die($ex);
1231  }
1232
1233  unlink($log_file);
1234}
1235
1236sub wrap2_sql_deny_table_ip_addr {
1237  my $self = shift;
1238  my $tmpdir = $self->{tmpdir};
1239
1240  my $config_file = "$tmpdir/wrap2.conf";
1241  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
1242  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
1243
1244  my $log_file = test_get_logfile();
1245
1246  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
1247  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
1248
1249  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
1250
1251  # Build up sqlite3 command to create allow, deny tables and populate them
1252  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
1253
1254  my $fh;
1255  if (open($fh, "> $db_script")) {
1256    print $fh <<EOS;
1257CREATE TABLE ftpallow (
1258  name TEXT,
1259  allowed TEXT
1260);
1261
1262CREATE TABLE ftpdeny (
1263  name TEXT,
1264  denied TEXT
1265);
1266
1267INSERT INTO ftpdeny (name, denied) VALUES ('', 'ALL');
1268EOS
1269
1270    unless (close($fh)) {
1271      die("Can't write $db_script: $!");
1272    }
1273
1274  } else {
1275    die("Can't open $db_script: $!");
1276  }
1277
1278  my $cmd = "sqlite3 $db_file < $db_script";
1279
1280  if ($ENV{TEST_VERBOSE}) {
1281    print STDERR "Executing sqlite3: $cmd\n";
1282  }
1283
1284  my @output = `$cmd`;
1285
1286  unlink($db_script);
1287
1288  my $user = 'proftpd';
1289  my $passwd = 'test';
1290  my $group = 'ftpd';
1291  my $home_dir = File::Spec->rel2abs($tmpdir);
1292  my $uid = 500;
1293  my $gid = 500;
1294
1295  # Make sure that, if we're running as root, that the home directory has
1296  # permissions/privs set for the account we create
1297  if ($< == 0) {
1298    unless (chmod(0755, $home_dir)) {
1299      die("Can't set perms on $home_dir to 0755: $!");
1300    }
1301
1302    unless (chown($uid, $gid, $home_dir)) {
1303      die("Can't set owner of $home_dir to $uid/$gid: $!");
1304    }
1305  }
1306
1307  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1308    '/bin/bash');
1309  auth_group_write($auth_group_file, $group, $gid, $user);
1310
1311  my $timeout_idle = 30;
1312
1313  my $config = {
1314    PidFile => $pid_file,
1315    ScoreboardFile => $scoreboard_file,
1316    SystemLog => $log_file,
1317
1318    AuthUserFile => $auth_user_file,
1319    AuthGroupFile => $auth_group_file,
1320    TimeoutIdle => $timeout_idle,
1321
1322    IfModules => {
1323      'mod_delay.c' => {
1324        DelayEngine => 'off',
1325      },
1326
1327      'mod_sql_sqlite.c' => [
1328        "SQLAuthenticate off",
1329        "SQLConnectInfo $db_file",
1330        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
1331        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
1332        "SQLLogFile $log_file",
1333      ],
1334
1335      'mod_wrap2_sql.c' => {
1336        WrapEngine => 'on',
1337        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
1338        WrapLog => $log_file,
1339      },
1340    },
1341  };
1342
1343  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1344
1345  # Open pipes, for use between the parent and child processes.  Specifically,
1346  # the child will indicate when it's done with its test by writing a message
1347  # to the parent.
1348  my ($rfh, $wfh);
1349  unless (pipe($rfh, $wfh)) {
1350    die("Can't open pipe: $!");
1351  }
1352
1353  my $ex;
1354
1355  # Fork child
1356  $self->handle_sigchld();
1357  defined(my $pid = fork()) or die("Can't fork: $!");
1358  if ($pid) {
1359    eval {
1360      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1361      eval { $client->login($user, $passwd) };
1362      unless ($@) {
1363        die("Login succeeded unexpectedly");
1364      }
1365
1366      my $resp_code = $client->response_code();
1367      my $resp_msg = $client->response_msg();
1368
1369      my $expected;
1370
1371      $expected = 530;
1372      $self->assert($expected == $resp_code,
1373        test_msg("Expected response code $expected, got $resp_code"));
1374
1375      $expected = "Access denied";
1376      $self->assert($expected eq $resp_msg,
1377        test_msg("Expected response message '$expected', got '$resp_msg'"));
1378    };
1379
1380    if ($@) {
1381      $ex = $@;
1382    }
1383
1384    $wfh->print("done\n");
1385    $wfh->flush();
1386
1387  } else {
1388    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
1389    if ($@) {
1390      warn($@);
1391      exit 1;
1392    }
1393
1394    exit 0;
1395  }
1396
1397  # Stop server
1398  server_stop($pid_file);
1399
1400  $self->assert_child_ok($pid);
1401
1402  if ($ex) {
1403    die($ex);
1404  }
1405
1406  if (open($fh, "> $db_script")) {
1407    print $fh <<EOS;
1408DELETE FROM ftpdeny;
1409INSERT INTO ftpdeny (name, denied) VALUES ('', '127.0.0.1');
1410EOS
1411    unless (close($fh)) {
1412      die("Can't write $db_script: $!");
1413    }
1414
1415  } else {
1416    die("Can't open $db_script: $!");
1417  }
1418
1419  $cmd = "sqlite3 $db_file < $db_script";
1420
1421  if ($ENV{TEST_VERBOSE}) {
1422    print STDERR "Executing sqlite3: $cmd\n";
1423  }
1424
1425  @output = `$cmd`;
1426
1427  unlink($db_script);
1428
1429  ($port, $config_user, $config_group) = config_write($config_file, $config);
1430
1431  # Fork child
1432  $self->handle_sigchld();
1433  defined($pid = fork()) or die("Can't fork: $!");
1434  if ($pid) {
1435    eval {
1436      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1437      eval { $client->login($user, $passwd) };
1438      unless ($@) {
1439        die("Login succeeded unexpectedly");
1440      }
1441
1442      my $resp_code = $client->response_code();
1443      my $resp_msg = $client->response_msg();
1444
1445      my $expected;
1446
1447      $expected = 530;
1448      $self->assert($expected == $resp_code,
1449        test_msg("Expected response code $expected, got $resp_code"));
1450
1451      $expected = "Access denied";
1452      $self->assert($expected eq $resp_msg,
1453        test_msg("Expected response message '$expected', got '$resp_msg'"));
1454    };
1455
1456    if ($@) {
1457      $ex = $@;
1458    }
1459
1460    $wfh->print("done\n");
1461    $wfh->flush();
1462
1463  } else {
1464    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
1465    if ($@) {
1466      warn($@);
1467      exit 1;
1468    }
1469
1470    exit 0;
1471  }
1472
1473  # Stop server
1474  server_stop($pid_file);
1475
1476  $self->assert_child_ok($pid);
1477
1478  if ($ex) {
1479    test_append_logfile($log_file, $ex);
1480    unlink($log_file);
1481
1482    die($ex);
1483  }
1484
1485  unlink($log_file);
1486}
1487
1488sub wrap2_sql_deny_table_ipv4_netmask {
1489  my $self = shift;
1490  my $tmpdir = $self->{tmpdir};
1491
1492  my $config_file = "$tmpdir/wrap2.conf";
1493  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
1494  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
1495
1496  my $log_file = test_get_logfile();
1497
1498  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
1499  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
1500
1501  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
1502
1503  # Build up sqlite3 command to create allow, deny tables and populate them
1504  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
1505
1506  my $fh;
1507  if (open($fh, "> $db_script")) {
1508    print $fh <<EOS;
1509CREATE TABLE ftpallow (
1510  name TEXT,
1511  allowed TEXT
1512);
1513
1514CREATE TABLE ftpdeny (
1515  name TEXT,
1516  denied TEXT
1517);
1518
1519INSERT INTO ftpdeny (name, denied) VALUES ('', 'ALL');
1520EOS
1521
1522    unless (close($fh)) {
1523      die("Can't write $db_script: $!");
1524    }
1525
1526  } else {
1527    die("Can't open $db_script: $!");
1528  }
1529
1530  my $cmd = "sqlite3 $db_file < $db_script";
1531
1532  if ($ENV{TEST_VERBOSE}) {
1533    print STDERR "Executing sqlite3: $cmd\n";
1534  }
1535
1536  my @output = `$cmd`;
1537
1538  unlink($db_script);
1539
1540  my $user = 'proftpd';
1541  my $passwd = 'test';
1542  my $group = 'ftpd';
1543  my $home_dir = File::Spec->rel2abs($tmpdir);
1544  my $uid = 500;
1545  my $gid = 500;
1546
1547  # Make sure that, if we're running as root, that the home directory has
1548  # permissions/privs set for the account we create
1549  if ($< == 0) {
1550    unless (chmod(0755, $home_dir)) {
1551      die("Can't set perms on $home_dir to 0755: $!");
1552    }
1553
1554    unless (chown($uid, $gid, $home_dir)) {
1555      die("Can't set owner of $home_dir to $uid/$gid: $!");
1556    }
1557  }
1558
1559  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1560    '/bin/bash');
1561  auth_group_write($auth_group_file, $group, $gid, $user);
1562
1563  my $timeout_idle = 30;
1564
1565  my $config = {
1566    PidFile => $pid_file,
1567    ScoreboardFile => $scoreboard_file,
1568    SystemLog => $log_file,
1569
1570    AuthUserFile => $auth_user_file,
1571    AuthGroupFile => $auth_group_file,
1572    TimeoutIdle => $timeout_idle,
1573
1574    IfModules => {
1575      'mod_delay.c' => {
1576        DelayEngine => 'off',
1577      },
1578
1579      'mod_sql_sqlite.c' => [
1580        "SQLAuthenticate off",
1581        "SQLConnectInfo $db_file",
1582        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
1583        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
1584        "SQLLogFile $log_file",
1585      ],
1586
1587      'mod_wrap2_sql.c' => {
1588        WrapEngine => 'on',
1589        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
1590        WrapLog => $log_file,
1591      },
1592    },
1593  };
1594
1595  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1596
1597  # Open pipes, for use between the parent and child processes.  Specifically,
1598  # the child will indicate when it's done with its test by writing a message
1599  # to the parent.
1600  my ($rfh, $wfh);
1601  unless (pipe($rfh, $wfh)) {
1602    die("Can't open pipe: $!");
1603  }
1604
1605  my $ex;
1606
1607  # Fork child
1608  $self->handle_sigchld();
1609  defined(my $pid = fork()) or die("Can't fork: $!");
1610  if ($pid) {
1611    eval {
1612      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1613      eval { $client->login($user, $passwd) };
1614      unless ($@) {
1615        die("Login succeeded unexpectedly");
1616      }
1617
1618      my $resp_code = $client->response_code();
1619      my $resp_msg = $client->response_msg();
1620
1621      my $expected;
1622
1623      $expected = 530;
1624      $self->assert($expected == $resp_code,
1625        test_msg("Expected response code $expected, got $resp_code"));
1626
1627      $expected = "Access denied";
1628      $self->assert($expected eq $resp_msg,
1629        test_msg("Expected response message '$expected', got '$resp_msg'"));
1630    };
1631
1632    if ($@) {
1633      $ex = $@;
1634    }
1635
1636    $wfh->print("done\n");
1637    $wfh->flush();
1638
1639  } else {
1640    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
1641    if ($@) {
1642      warn($@);
1643      exit 1;
1644    }
1645
1646    exit 0;
1647  }
1648
1649  # Stop server
1650  server_stop($pid_file);
1651
1652  $self->assert_child_ok($pid);
1653
1654  if ($ex) {
1655    die($ex);
1656  }
1657
1658  if (open($fh, "> $db_script")) {
1659    print $fh <<EOS;
1660DELETE FROM ftpdeny;
1661INSERT INTO ftpdeny (name, denied) VALUES ('', '127.0.0.0/255.255.255.0');
1662EOS
1663    unless (close($fh)) {
1664      die("Can't write $db_script: $!");
1665    }
1666
1667  } else {
1668    die("Can't open $db_script: $!");
1669  }
1670
1671  $cmd = "sqlite3 $db_file < $db_script";
1672
1673  if ($ENV{TEST_VERBOSE}) {
1674    print STDERR "Executing sqlite3: $cmd\n";
1675  }
1676
1677  @output = `$cmd`;
1678
1679  unlink($db_script);
1680
1681  ($port, $config_user, $config_group) = config_write($config_file, $config);
1682
1683  # Fork child
1684  $self->handle_sigchld();
1685  defined($pid = fork()) or die("Can't fork: $!");
1686  if ($pid) {
1687    eval {
1688      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1689      eval { $client->login($user, $passwd) };
1690      unless ($@) {
1691        die("Login succeeded unexpectedly");
1692      }
1693
1694      my $resp_code = $client->response_code();
1695      my $resp_msg = $client->response_msg();
1696
1697      my $expected;
1698
1699      $expected = 530;
1700      $self->assert($expected == $resp_code,
1701        test_msg("Expected response code $expected, got $resp_code"));
1702
1703      $expected = "Access denied";
1704      $self->assert($expected eq $resp_msg,
1705        test_msg("Expected response message '$expected', got '$resp_msg'"));
1706    };
1707
1708    if ($@) {
1709      $ex = $@;
1710    }
1711
1712    $wfh->print("done\n");
1713    $wfh->flush();
1714
1715  } else {
1716    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
1717    if ($@) {
1718      warn($@);
1719      exit 1;
1720    }
1721
1722    exit 0;
1723  }
1724
1725  # Stop server
1726  server_stop($pid_file);
1727
1728  $self->assert_child_ok($pid);
1729
1730  if ($ex) {
1731    test_append_logfile($log_file, $ex);
1732    unlink($log_file);
1733
1734    die($ex);
1735  }
1736
1737  unlink($log_file);
1738}
1739
1740sub wrap2_sql_deny_table_ipv4mappedv6_netmask {
1741  my $self = shift;
1742  my $tmpdir = $self->{tmpdir};
1743
1744  my $config_file = "$tmpdir/wrap2.conf";
1745  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
1746  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
1747
1748  my $log_file = test_get_logfile();
1749
1750  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
1751  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
1752
1753  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
1754
1755  # Build up sqlite3 command to create allow, deny tables and populate them
1756  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
1757
1758  my $fh;
1759  if (open($fh, "> $db_script")) {
1760    print $fh <<EOS;
1761CREATE TABLE ftpallow (
1762  name TEXT,
1763  allowed TEXT
1764);
1765
1766CREATE TABLE ftpdeny (
1767  name TEXT,
1768  denied TEXT
1769);
1770
1771INSERT INTO ftpdeny (name, denied) VALUES ('', 'ALL');
1772EOS
1773
1774    unless (close($fh)) {
1775      die("Can't write $db_script: $!");
1776    }
1777
1778  } else {
1779    die("Can't open $db_script: $!");
1780  }
1781
1782  my $cmd = "sqlite3 $db_file < $db_script";
1783
1784  if ($ENV{TEST_VERBOSE}) {
1785    print STDERR "Executing sqlite3: $cmd\n";
1786  }
1787
1788  my @output = `$cmd`;
1789
1790  unlink($db_script);
1791
1792  my $user = 'proftpd';
1793  my $passwd = 'test';
1794  my $group = 'ftpd';
1795  my $home_dir = File::Spec->rel2abs($tmpdir);
1796  my $uid = 500;
1797  my $gid = 500;
1798
1799  # Make sure that, if we're running as root, that the home directory has
1800  # permissions/privs set for the account we create
1801  if ($< == 0) {
1802    unless (chmod(0755, $home_dir)) {
1803      die("Can't set perms on $home_dir to 0755: $!");
1804    }
1805
1806    unless (chown($uid, $gid, $home_dir)) {
1807      die("Can't set owner of $home_dir to $uid/$gid: $!");
1808    }
1809  }
1810
1811  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1812    '/bin/bash');
1813  auth_group_write($auth_group_file, $group, $gid, $user);
1814
1815  my $timeout_idle = 30;
1816
1817  my $config = {
1818    PidFile => $pid_file,
1819    ScoreboardFile => $scoreboard_file,
1820    SystemLog => $log_file,
1821
1822    AuthUserFile => $auth_user_file,
1823    AuthGroupFile => $auth_group_file,
1824    TimeoutIdle => $timeout_idle,
1825
1826    UseIPv6 => 'on',
1827
1828    IfModules => {
1829      'mod_delay.c' => {
1830        DelayEngine => 'off',
1831      },
1832
1833      'mod_sql_sqlite.c' => [
1834        "SQLAuthenticate off",
1835        "SQLConnectInfo $db_file",
1836        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
1837        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
1838        "SQLLogFile $log_file",
1839      ],
1840
1841      'mod_wrap2_sql.c' => {
1842        WrapEngine => 'on',
1843        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
1844        WrapLog => $log_file,
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      eval { $client->login($user, $passwd) };
1868      unless ($@) {
1869        die("Login succeeded unexpectedly");
1870      }
1871
1872      my $resp_code = $client->response_code();
1873      my $resp_msg = $client->response_msg();
1874
1875      my $expected;
1876
1877      $expected = 530;
1878      $self->assert($expected == $resp_code,
1879        test_msg("Expected response code $expected, got $resp_code"));
1880
1881      $expected = "Access denied";
1882      $self->assert($expected eq $resp_msg,
1883        test_msg("Expected response message '$expected', got '$resp_msg'"));
1884    };
1885
1886    if ($@) {
1887      $ex = $@;
1888    }
1889
1890    $wfh->print("done\n");
1891    $wfh->flush();
1892
1893  } else {
1894    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
1895    if ($@) {
1896      warn($@);
1897      exit 1;
1898    }
1899
1900    exit 0;
1901  }
1902
1903  # Stop server
1904  server_stop($pid_file);
1905
1906  $self->assert_child_ok($pid);
1907
1908  if ($ex) {
1909    die($ex);
1910  }
1911
1912  if (open($fh, "> $db_script")) {
1913    print $fh <<EOS;
1914DELETE FROM ftpdeny;
1915INSERT INTO ftpdeny (name, denied) VALUES ('', '127.0.0.0/255.255.255.0');
1916EOS
1917    unless (close($fh)) {
1918      die("Can't write $db_script: $!");
1919    }
1920
1921  } else {
1922    die("Can't open $db_script: $!");
1923  }
1924
1925  $cmd = "sqlite3 $db_file < $db_script";
1926
1927  if ($ENV{TEST_VERBOSE}) {
1928    print STDERR "Executing sqlite3: $cmd\n";
1929  }
1930
1931  @output = `$cmd`;
1932
1933  unlink($db_script);
1934
1935  ($port, $config_user, $config_group) = config_write($config_file, $config);
1936
1937  # Fork child
1938  $self->handle_sigchld();
1939  defined($pid = fork()) or die("Can't fork: $!");
1940  if ($pid) {
1941    eval {
1942      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1943
1944      eval { $client->login($user, $passwd) };
1945      unless ($@) {
1946        die("Login succeeded unexpectedly");
1947      }
1948
1949      my $resp_code = $client->response_code();
1950      my $resp_msg = $client->response_msg();
1951
1952      my $expected;
1953
1954      $expected = 530;
1955      $self->assert($expected == $resp_code,
1956        test_msg("Expected response code $expected, got $resp_code"));
1957
1958      $expected = "Access denied";
1959      $self->assert($expected eq $resp_msg,
1960        test_msg("Expected response message '$expected', got '$resp_msg'"));
1961    };
1962
1963    if ($@) {
1964      $ex = $@;
1965    }
1966
1967    $wfh->print("done\n");
1968    $wfh->flush();
1969
1970  } else {
1971    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
1972    if ($@) {
1973      warn($@);
1974      exit 1;
1975    }
1976
1977    exit 0;
1978  }
1979
1980  # Stop server
1981  server_stop($pid_file);
1982
1983  $self->assert_child_ok($pid);
1984
1985  if ($ex) {
1986    test_append_logfile($log_file, $ex);
1987    unlink($log_file);
1988
1989    die($ex);
1990  }
1991
1992  unlink($log_file);
1993}
1994
1995sub wrap2_sql_deny_table_ipv6_netmask_bug3606 {
1996  my $self = shift;
1997  my $tmpdir = $self->{tmpdir};
1998
1999  my $config_file = "$tmpdir/wrap2.conf";
2000  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
2001  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
2002
2003  my $log_file = test_get_logfile();
2004
2005  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
2006  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
2007
2008  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
2009
2010  # Build up sqlite3 command to create allow, deny tables and populate them
2011  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
2012
2013  my $fh;
2014  if (open($fh, "> $db_script")) {
2015    print $fh <<EOS;
2016CREATE TABLE ftpallow (
2017  name TEXT,
2018  allowed TEXT
2019);
2020
2021CREATE TABLE ftpdeny (
2022  name TEXT,
2023  denied TEXT
2024);
2025
2026INSERT INTO ftpdeny (name, denied) VALUES ('', 'ALL');
2027EOS
2028
2029    unless (close($fh)) {
2030      die("Can't write $db_script: $!");
2031    }
2032
2033  } else {
2034    die("Can't open $db_script: $!");
2035  }
2036
2037  my $cmd = "sqlite3 $db_file < $db_script";
2038
2039  if ($ENV{TEST_VERBOSE}) {
2040    print STDERR "Executing sqlite3: $cmd\n";
2041  }
2042
2043  my @output = `$cmd`;
2044
2045  unlink($db_script);
2046
2047  my $user = 'proftpd';
2048  my $passwd = 'test';
2049  my $group = 'ftpd';
2050  my $home_dir = File::Spec->rel2abs($tmpdir);
2051  my $uid = 500;
2052  my $gid = 500;
2053
2054  # Make sure that, if we're running as root, that the home directory has
2055  # permissions/privs set for the account we create
2056  if ($< == 0) {
2057    unless (chmod(0755, $home_dir)) {
2058      die("Can't set perms on $home_dir to 0755: $!");
2059    }
2060
2061    unless (chown($uid, $gid, $home_dir)) {
2062      die("Can't set owner of $home_dir to $uid/$gid: $!");
2063    }
2064  }
2065
2066  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2067    '/bin/bash');
2068  auth_group_write($auth_group_file, $group, $gid, $user);
2069
2070  my $timeout_idle = 30;
2071
2072  my $config = {
2073    PidFile => $pid_file,
2074    ScoreboardFile => $scoreboard_file,
2075    SystemLog => $log_file,
2076
2077    AuthUserFile => $auth_user_file,
2078    AuthGroupFile => $auth_group_file,
2079    TimeoutIdle => $timeout_idle,
2080
2081    DefaultAddress => '::1',
2082    UseIPv6 => 'on',
2083
2084    IfModules => {
2085      'mod_delay.c' => {
2086        DelayEngine => 'off',
2087      },
2088
2089      'mod_sql_sqlite.c' => [
2090        "SQLAuthenticate off",
2091        "SQLConnectInfo $db_file",
2092        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
2093        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
2094        "SQLLogFile $log_file",
2095      ],
2096
2097      'mod_wrap2_sql.c' => {
2098        WrapEngine => 'on',
2099        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
2100        WrapLog => $log_file,
2101      },
2102    },
2103  };
2104
2105  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2106
2107  # Open pipes, for use between the parent and child processes.  Specifically,
2108  # the child will indicate when it's done with its test by writing a message
2109  # to the parent.
2110  my ($rfh, $wfh);
2111  unless (pipe($rfh, $wfh)) {
2112    die("Can't open pipe: $!");
2113  }
2114
2115  my $ex;
2116
2117  # Fork child
2118  $self->handle_sigchld();
2119  defined(my $pid = fork()) or die("Can't fork: $!");
2120  if ($pid) {
2121    eval {
2122      sleep(2);
2123
2124      my $client = IO::Socket::INET6->new(
2125        PeerAddr => '::1',
2126        PeerPort => $port,
2127        Proto => 'tcp',
2128        Timeout => 5,
2129      );
2130      unless ($client) {
2131        die("Can't connect to ::1: $!");
2132      }
2133
2134      # Read the banner
2135      my $banner = <$client>;
2136
2137      # Send the USER command
2138      my $cmd = "USER $user\r\n";
2139      $client->print($cmd);
2140      $client->flush();
2141
2142      # Read USER response
2143      my $resp = <$client>;
2144
2145      my $expected = "331 Password required for $user\r\n";
2146      $self->assert($expected eq $resp,
2147        test_msg("Expected '$expected', got '$resp'"));
2148
2149      # Send the PASS command
2150      $cmd = "PASS $passwd\r\n";
2151      $client->print($cmd);
2152      $client->flush();
2153
2154      # Read PASS response
2155      $resp = <$client>;
2156
2157      $expected = "530 Access denied\r\n";
2158      $self->assert($expected eq $resp,
2159        test_msg("Expected '$expected', got '$resp'"));
2160
2161      $client->close();
2162    };
2163
2164    if ($@) {
2165      $ex = $@;
2166    }
2167
2168    $wfh->print("done\n");
2169    $wfh->flush();
2170
2171  } else {
2172    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
2173    if ($@) {
2174      warn($@);
2175      exit 1;
2176    }
2177
2178    exit 0;
2179  }
2180
2181  # Stop server
2182  server_stop($pid_file);
2183
2184  $self->assert_child_ok($pid);
2185
2186  if ($ex) {
2187    die($ex);
2188  }
2189
2190  if (open($fh, "> $db_script")) {
2191    print $fh <<EOS;
2192DELETE FROM ftpdeny;
2193INSERT INTO ftpdeny (name, denied) VALUES ('', '[::1]/32');
2194EOS
2195    unless (close($fh)) {
2196      die("Can't write $db_script: $!");
2197    }
2198
2199  } else {
2200    die("Can't open $db_script: $!");
2201  }
2202
2203  $cmd = "sqlite3 $db_file < $db_script";
2204
2205  if ($ENV{TEST_VERBOSE}) {
2206    print STDERR "Executing sqlite3: $cmd\n";
2207  }
2208
2209  @output = `$cmd`;
2210
2211  unlink($db_script);
2212
2213  ($port, $config_user, $config_group) = config_write($config_file, $config);
2214
2215  # Fork child
2216  $self->handle_sigchld();
2217  defined($pid = fork()) or die("Can't fork: $!");
2218  if ($pid) {
2219    eval {
2220      sleep(2);
2221
2222      my $client = IO::Socket::INET6->new(
2223        PeerAddr => '::1',
2224        PeerPort => $port,
2225        Proto => 'tcp',
2226        Timeout => 5,
2227      );
2228      unless ($client) {
2229        die("Can't connect to ::1: $!");
2230      }
2231
2232      # Read the banner
2233      my $banner = <$client>;
2234
2235      # Send the USER command
2236      my $cmd = "USER $user\r\n";
2237      $client->print($cmd);
2238      $client->flush();
2239
2240      # Read USER response
2241      my $resp = <$client>;
2242
2243      my $expected = "331 Password required for $user\r\n";
2244      $self->assert($expected eq $resp,
2245        test_msg("Expected '$expected', got '$resp'"));
2246
2247      # Send the PASS command
2248      $cmd = "PASS $passwd\r\n";
2249      $client->print($cmd);
2250      $client->flush();
2251
2252      # Read PASS response
2253      $resp = <$client>;
2254
2255      $expected = "530 Access denied\r\n";
2256      $self->assert($expected eq $resp,
2257        test_msg("Expected '$expected', got '$resp'"));
2258
2259      $client->close();
2260    };
2261
2262    if ($@) {
2263      $ex = $@;
2264    }
2265
2266    $wfh->print("done\n");
2267    $wfh->flush();
2268
2269  } else {
2270    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
2271    if ($@) {
2272      warn($@);
2273      exit 1;
2274    }
2275
2276    exit 0;
2277  }
2278
2279  # Stop server
2280  server_stop($pid_file);
2281
2282  $self->assert_child_ok($pid);
2283
2284  if ($ex) {
2285    test_append_logfile($log_file, $ex);
2286    unlink($log_file);
2287
2288    die($ex);
2289  }
2290
2291  unlink($log_file);
2292}
2293
2294sub wrap2_sql_deny_table_dns_name {
2295  my $self = shift;
2296  my $tmpdir = $self->{tmpdir};
2297
2298  my $config_file = "$tmpdir/wrap2.conf";
2299  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
2300  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
2301
2302  my $log_file = test_get_logfile();
2303
2304  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
2305  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
2306
2307  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
2308
2309  # Build up sqlite3 command to create allow, deny tables and populate them
2310  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
2311
2312  my $fh;
2313  if (open($fh, "> $db_script")) {
2314    print $fh <<EOS;
2315CREATE TABLE ftpallow (
2316  name TEXT,
2317  allowed TEXT
2318);
2319
2320CREATE TABLE ftpdeny (
2321  name TEXT,
2322  denied TEXT
2323);
2324
2325INSERT INTO ftpdeny (name, denied) VALUES ('', 'ALL');
2326EOS
2327
2328    unless (close($fh)) {
2329      die("Can't write $db_script: $!");
2330    }
2331
2332  } else {
2333    die("Can't open $db_script: $!");
2334  }
2335
2336  my $cmd = "sqlite3 $db_file < $db_script";
2337
2338  if ($ENV{TEST_VERBOSE}) {
2339    print STDERR "Executing sqlite3: $cmd\n";
2340  }
2341
2342  my @output = `$cmd`;
2343
2344  unlink($db_script);
2345
2346  my $user = 'proftpd';
2347  my $passwd = 'test';
2348  my $group = 'ftpd';
2349  my $home_dir = File::Spec->rel2abs($tmpdir);
2350  my $uid = 500;
2351  my $gid = 500;
2352
2353  # Make sure that, if we're running as root, that the home directory has
2354  # permissions/privs set for the account we create
2355  if ($< == 0) {
2356    unless (chmod(0755, $home_dir)) {
2357      die("Can't set perms on $home_dir to 0755: $!");
2358    }
2359
2360    unless (chown($uid, $gid, $home_dir)) {
2361      die("Can't set owner of $home_dir to $uid/$gid: $!");
2362    }
2363  }
2364
2365  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2366    '/bin/bash');
2367  auth_group_write($auth_group_file, $group, $gid, $user);
2368
2369  my $timeout_idle = 30;
2370
2371  my $config = {
2372    PidFile => $pid_file,
2373    ScoreboardFile => $scoreboard_file,
2374    SystemLog => $log_file,
2375
2376    AuthUserFile => $auth_user_file,
2377    AuthGroupFile => $auth_group_file,
2378    TimeoutIdle => $timeout_idle,
2379    UseReverseDNS => 'on',
2380
2381    IfModules => {
2382      'mod_delay.c' => {
2383        DelayEngine => 'off',
2384      },
2385
2386      'mod_sql_sqlite.c' => [
2387        'SQLAuthenticate off',
2388        "SQLConnectInfo $db_file",
2389        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
2390        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
2391        "SQLLogFile $log_file",
2392      ],
2393
2394      'mod_wrap2_sql.c' => {
2395        WrapEngine => 'on',
2396        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
2397        WrapLog => $log_file,
2398      },
2399    },
2400  };
2401
2402  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2403
2404  # Open pipes, for use between the parent and child processes.  Specifically,
2405  # the child will indicate when it's done with its test by writing a message
2406  # to the parent.
2407  my ($rfh, $wfh);
2408  unless (pipe($rfh, $wfh)) {
2409    die("Can't open pipe: $!");
2410  }
2411
2412  my $ex;
2413
2414  # Fork child
2415  $self->handle_sigchld();
2416  defined(my $pid = fork()) or die("Can't fork: $!");
2417  if ($pid) {
2418    eval {
2419      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2420      eval { $client->login($user, $passwd) };
2421      unless ($@) {
2422        die("Login succeeded unexpectedly");
2423      }
2424
2425      my $resp_code = $client->response_code();
2426      my $resp_msg = $client->response_msg();
2427
2428      my $expected;
2429
2430      $expected = 530;
2431      $self->assert($expected == $resp_code,
2432        test_msg("Expected response code $expected, got $resp_code"));
2433
2434      $expected = "Access denied";
2435      $self->assert($expected eq $resp_msg,
2436        test_msg("Expected response message '$expected', got '$resp_msg'"));
2437    };
2438
2439    if ($@) {
2440      $ex = $@;
2441    }
2442
2443    $wfh->print("done\n");
2444    $wfh->flush();
2445
2446  } else {
2447    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
2448    if ($@) {
2449      warn($@);
2450      exit 1;
2451    }
2452
2453    exit 0;
2454  }
2455
2456  # Stop server
2457  server_stop($pid_file);
2458
2459  $self->assert_child_ok($pid);
2460
2461  if ($ex) {
2462    die($ex);
2463  }
2464
2465  if (open($fh, "> $db_script")) {
2466    print $fh <<EOS;
2467DELETE FROM ftpdeny;
2468INSERT INTO ftpdeny (name, denied) VALUES ('', 'localhost');
2469EOS
2470    unless (close($fh)) {
2471      die("Can't write $db_script: $!");
2472    }
2473
2474  } else {
2475    die("Can't open $db_script: $!");
2476  }
2477
2478  $cmd = "sqlite3 $db_file < $db_script";
2479
2480  if ($ENV{TEST_VERBOSE}) {
2481    print STDERR "Executing sqlite3: $cmd\n";
2482  }
2483
2484  @output = `$cmd`;
2485
2486  unlink($db_script);
2487
2488  ($port, $config_user, $config_group) = config_write($config_file, $config);
2489
2490  # Fork child
2491  $self->handle_sigchld();
2492  defined($pid = fork()) or die("Can't fork: $!");
2493  if ($pid) {
2494    eval {
2495      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2496      eval { $client->login($user, $passwd) };
2497      unless ($@) {
2498        die("Login succeeded unexpectedly");
2499      }
2500
2501      my $resp_code = $client->response_code();
2502      my $resp_msg = $client->response_msg();
2503
2504      my $expected;
2505
2506      $expected = 530;
2507      $self->assert($expected == $resp_code,
2508        test_msg("Expected response code $expected, got $resp_code"));
2509
2510      $expected = "Access denied";
2511      $self->assert($expected eq $resp_msg,
2512        test_msg("Expected response message '$expected', got '$resp_msg'"));
2513    };
2514
2515    if ($@) {
2516      $ex = $@;
2517    }
2518
2519    $wfh->print("done\n");
2520    $wfh->flush();
2521
2522  } else {
2523    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
2524    if ($@) {
2525      warn($@);
2526      exit 1;
2527    }
2528
2529    exit 0;
2530  }
2531
2532  # Stop server
2533  server_stop($pid_file);
2534
2535  $self->assert_child_ok($pid);
2536
2537  if ($ex) {
2538    test_append_logfile($log_file, $ex);
2539    unlink($log_file);
2540
2541    die($ex);
2542  }
2543
2544  unlink($log_file);
2545}
2546
2547sub wrap2_sql_deny_table_dns_domain_bug3558 {
2548  my $self = shift;
2549  my $tmpdir = $self->{tmpdir};
2550
2551  my $config_file = "$tmpdir/wrap2.conf";
2552  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
2553  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
2554
2555  my $log_file = test_get_logfile();
2556
2557  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
2558  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
2559
2560  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
2561
2562  # Build up sqlite3 command to create allow, deny tables and populate them
2563  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
2564
2565  my $fh;
2566  if (open($fh, "> $db_script")) {
2567    print $fh <<EOS;
2568CREATE TABLE ftpallow (
2569  name TEXT,
2570  allowed TEXT
2571);
2572
2573CREATE TABLE ftpdeny (
2574  name TEXT,
2575  denied TEXT
2576);
2577
2578INSERT INTO ftpdeny (name, denied) VALUES ('', 'ALL');
2579EOS
2580
2581    unless (close($fh)) {
2582      die("Can't write $db_script: $!");
2583    }
2584
2585  } else {
2586    die("Can't open $db_script: $!");
2587  }
2588
2589  my $cmd = "sqlite3 $db_file < $db_script";
2590
2591  if ($ENV{TEST_VERBOSE}) {
2592    print STDERR "Executing sqlite3: $cmd\n";
2593  }
2594
2595  my @output = `$cmd`;
2596
2597  unlink($db_script);
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  # Make sure that, if we're running as root, that the home directory has
2607  # permissions/privs set for the account we create
2608  if ($< == 0) {
2609    unless (chmod(0755, $home_dir)) {
2610      die("Can't set perms on $home_dir to 0755: $!");
2611    }
2612
2613    unless (chown($uid, $gid, $home_dir)) {
2614      die("Can't set owner of $home_dir to $uid/$gid: $!");
2615    }
2616  }
2617
2618  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2619    '/bin/bash');
2620  auth_group_write($auth_group_file, $group, $gid, $user);
2621
2622  my $timeout_idle = 30;
2623
2624  my $config = {
2625    PidFile => $pid_file,
2626    ScoreboardFile => $scoreboard_file,
2627    SystemLog => $log_file,
2628    TraceLog => $log_file,
2629    Trace => 'dns:20',
2630
2631    AuthUserFile => $auth_user_file,
2632    AuthGroupFile => $auth_group_file,
2633    TimeoutIdle => $timeout_idle,
2634
2635    UseReverseDNS => 'on',
2636
2637    IfModules => {
2638      'mod_delay.c' => {
2639        DelayEngine => 'off',
2640      },
2641
2642      'mod_sql_sqlite.c' => [
2643        'SQLAuthenticate off',
2644        "SQLConnectInfo $db_file",
2645        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
2646        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
2647        "SQLLogFile $log_file",
2648      ],
2649
2650      'mod_wrap2_sql.c' => {
2651        WrapEngine => 'on',
2652        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
2653        WrapLog => $log_file,
2654        WrapOptions => 'CheckAllNames',
2655      },
2656    },
2657  };
2658
2659  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2660
2661  # Open pipes, for use between the parent and child processes.  Specifically,
2662  # the child will indicate when it's done with its test by writing a message
2663  # to the parent.
2664  my ($rfh, $wfh);
2665  unless (pipe($rfh, $wfh)) {
2666    die("Can't open pipe: $!");
2667  }
2668
2669  my $ex;
2670
2671  # Fork child
2672  $self->handle_sigchld();
2673  defined(my $pid = fork()) or die("Can't fork: $!");
2674  if ($pid) {
2675    eval {
2676      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2677      eval { $client->login($user, $passwd) };
2678      unless ($@) {
2679        die("Login succeeded unexpectedly");
2680      }
2681
2682      my $resp_code = $client->response_code();
2683      my $resp_msg = $client->response_msg();
2684
2685      my $expected;
2686
2687      $expected = 530;
2688      $self->assert($expected == $resp_code,
2689        test_msg("Expected response code $expected, got $resp_code"));
2690
2691      $expected = "Access denied";
2692      $self->assert($expected eq $resp_msg,
2693        test_msg("Expected response message '$expected', got '$resp_msg'"));
2694    };
2695
2696    if ($@) {
2697      $ex = $@;
2698    }
2699
2700    $wfh->print("done\n");
2701    $wfh->flush();
2702
2703  } else {
2704    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
2705    if ($@) {
2706      warn($@);
2707      exit 1;
2708    }
2709
2710    exit 0;
2711  }
2712
2713  # Stop server
2714  server_stop($pid_file);
2715
2716  $self->assert_child_ok($pid);
2717
2718  if ($ex) {
2719    die($ex);
2720  }
2721
2722  if (open($fh, "> $db_script")) {
2723    print $fh <<EOS;
2724DELETE FROM ftpdeny;
2725INSERT INTO ftpdeny (name, denied) VALUES ('', '.castaglia.org');
2726EOS
2727    unless (close($fh)) {
2728      die("Can't write $db_script: $!");
2729    }
2730
2731  } else {
2732    die("Can't open $db_script: $!");
2733  }
2734
2735  $cmd = "sqlite3 $db_file < $db_script";
2736
2737  if ($ENV{TEST_VERBOSE}) {
2738    print STDERR "Executing sqlite3: $cmd\n";
2739  }
2740
2741  @output = `$cmd`;
2742
2743  unlink($db_script);
2744
2745  ($port, $config_user, $config_group) = config_write($config_file, $config);
2746
2747  # Fork child
2748  $self->handle_sigchld();
2749  defined($pid = fork()) or die("Can't fork: $!");
2750  if ($pid) {
2751    eval {
2752      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2753      eval { $client->login($user, $passwd) };
2754      unless ($@) {
2755        die("Login succeeded unexpectedly");
2756      }
2757
2758      my $resp_code = $client->response_code();
2759      my $resp_msg = $client->response_msg();
2760
2761      my $expected;
2762
2763      $expected = 530;
2764      $self->assert($expected == $resp_code,
2765        test_msg("Expected response code $expected, got $resp_code"));
2766
2767      $expected = "Access denied";
2768      $self->assert($expected eq $resp_msg,
2769        test_msg("Expected response message '$expected', got '$resp_msg'"));
2770    };
2771
2772    if ($@) {
2773      $ex = $@;
2774    }
2775
2776    $wfh->print("done\n");
2777    $wfh->flush();
2778
2779  } else {
2780    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
2781    if ($@) {
2782      warn($@);
2783      exit 1;
2784    }
2785
2786    exit 0;
2787  }
2788
2789  # Stop server
2790  server_stop($pid_file);
2791
2792  $self->assert_child_ok($pid);
2793
2794  if ($ex) {
2795    test_append_logfile($log_file, $ex);
2796    unlink($log_file);
2797
2798    die($ex);
2799  }
2800
2801  unlink($log_file);
2802}
2803
2804sub wrap2_sql_user_tables {
2805  my $self = shift;
2806  my $tmpdir = $self->{tmpdir};
2807
2808  my $config_file = "$tmpdir/wrap2.conf";
2809  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
2810  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
2811
2812  my $log_file = test_get_logfile();
2813
2814  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
2815  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
2816
2817  my $user = 'proftpd';
2818  my $passwd = 'test';
2819  my $group = 'ftpd';
2820  my $home_dir = File::Spec->rel2abs($tmpdir);
2821  my $uid = 500;
2822  my $gid = 500;
2823
2824  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
2825
2826  # Build up sqlite3 command to create allow, deny tables and populate them
2827  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
2828
2829  my $fh;
2830  if (open($fh, "> $db_script")) {
2831    print $fh <<EOS;
2832CREATE TABLE ftpallow (
2833  name TEXT,
2834  allowed TEXT
2835);
2836
2837CREATE TABLE ftpdeny (
2838  name TEXT,
2839  denied TEXT
2840);
2841
2842INSERT INTO ftpdeny (name, denied) VALUES ('$user', 'ALL');
2843EOS
2844
2845    unless (close($fh)) {
2846      die("Can't write $db_script: $!");
2847    }
2848
2849  } else {
2850    die("Can't open $db_script: $!");
2851  }
2852
2853  my $cmd = "sqlite3 $db_file < $db_script";
2854
2855  if ($ENV{TEST_VERBOSE}) {
2856    print STDERR "Executing sqlite3: $cmd\n";
2857  }
2858
2859  my @output = `$cmd`;
2860
2861  unlink($db_script);
2862
2863  # Make sure that, if we're running as root, that the home directory has
2864  # permissions/privs set for the account we create
2865  if ($< == 0) {
2866    unless (chmod(0755, $home_dir)) {
2867      die("Can't set perms on $home_dir to 0755: $!");
2868    }
2869
2870    unless (chown($uid, $gid, $home_dir)) {
2871      die("Can't set owner of $home_dir to $uid/$gid: $!");
2872    }
2873  }
2874
2875  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2876    '/bin/bash');
2877  auth_group_write($auth_group_file, $group, $gid, $user);
2878
2879  my $timeout_idle = 30;
2880
2881  my $config = {
2882    PidFile => $pid_file,
2883    ScoreboardFile => $scoreboard_file,
2884    SystemLog => $log_file,
2885
2886    AuthUserFile => $auth_user_file,
2887    AuthGroupFile => $auth_group_file,
2888    TimeoutIdle => $timeout_idle,
2889
2890    IfModules => {
2891      'mod_delay.c' => {
2892        DelayEngine => 'off',
2893      },
2894
2895      'mod_sql_sqlite.c' => [
2896        'SQLAuthenticate off',
2897        "SQLConnectInfo $db_file",
2898        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
2899        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
2900        "SQLLogFile $log_file",
2901      ],
2902
2903      'mod_wrap2_sql.c' => {
2904        WrapEngine => 'on',
2905        WrapUserTables => "!$user sql:/get-allowed-clients sql:/get-denied-clients",
2906        WrapLog => $log_file,
2907      },
2908    },
2909  };
2910
2911  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2912
2913  # Open pipes, for use between the parent and child processes.  Specifically,
2914  # the child will indicate when it's done with its test by writing a message
2915  # to the parent.
2916  my ($rfh, $wfh);
2917  unless (pipe($rfh, $wfh)) {
2918    die("Can't open pipe: $!");
2919  }
2920
2921  my $ex;
2922
2923  # Fork child
2924  $self->handle_sigchld();
2925  defined(my $pid = fork()) or die("Can't fork: $!");
2926  if ($pid) {
2927    eval {
2928      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2929      my ($resp_code, $resp_msg) = $client->login($user, $passwd);
2930
2931      my $expected;
2932
2933      $expected = 230;
2934      $self->assert($expected == $resp_code,
2935        test_msg("Expected response code $expected, got $resp_code"));
2936
2937      $expected = "User $user logged in";
2938      $self->assert($expected eq $resp_msg,
2939        test_msg("Expected response message '$expected', got '$resp_msg'"));
2940    };
2941
2942    if ($@) {
2943      $ex = $@;
2944    }
2945
2946    $wfh->print("done\n");
2947    $wfh->flush();
2948
2949  } else {
2950    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
2951    if ($@) {
2952      warn($@);
2953      exit 1;
2954    }
2955
2956    exit 0;
2957  }
2958
2959  # Stop server
2960  server_stop($pid_file);
2961
2962  $self->assert_child_ok($pid);
2963
2964  if ($ex) {
2965    die($ex);
2966  }
2967
2968  # Modify the config a little
2969  $config->{IfModules}->{'mod_wrap2_sql.c'}->{WrapUserTables} = "$user sql:/get-allowed-clients sql:/get-denied-clients";
2970
2971  ($port, $config_user, $config_group) = config_write($config_file, $config);
2972
2973  # Fork child
2974  $self->handle_sigchld();
2975  defined($pid = fork()) or die("Can't fork: $!");
2976  if ($pid) {
2977    eval {
2978      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2979      eval { $client->login($user, $passwd) };
2980      unless ($@) {
2981        die("Login succeeded unexpectedly");
2982      }
2983
2984      my $resp_code = $client->response_code();
2985      my $resp_msg = $client->response_msg();
2986
2987      my $expected;
2988
2989      $expected = 530;
2990      $self->assert($expected == $resp_code,
2991        test_msg("Expected response code $expected, got $resp_code"));
2992
2993      $expected = "Access denied";
2994      $self->assert($expected eq $resp_msg,
2995        test_msg("Expected response message '$expected', got '$resp_msg'"));
2996    };
2997
2998    if ($@) {
2999      $ex = $@;
3000    }
3001
3002    $wfh->print("done\n");
3003    $wfh->flush();
3004
3005  } else {
3006    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
3007    if ($@) {
3008      warn($@);
3009      exit 1;
3010    }
3011
3012    exit 0;
3013  }
3014
3015  # Stop server
3016  server_stop($pid_file);
3017
3018  $self->assert_child_ok($pid);
3019
3020  if ($ex) {
3021    test_append_logfile($log_file, $ex);
3022    unlink($log_file);
3023
3024    die($ex);
3025  }
3026
3027  unlink($log_file);
3028}
3029
3030sub wrap2_sql_group_tables {
3031  my $self = shift;
3032  my $tmpdir = $self->{tmpdir};
3033
3034  my $config_file = "$tmpdir/wrap2.conf";
3035  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
3036  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
3037
3038  my $log_file = test_get_logfile();
3039
3040  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
3041  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
3042
3043  my $user = 'proftpd';
3044  my $passwd = 'test';
3045  my $group = 'ftpd';
3046  my $home_dir = File::Spec->rel2abs($tmpdir);
3047  my $uid = 500;
3048  my $gid = 500;
3049
3050  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
3051
3052  # Build up sqlite3 command to create allow, deny tables and populate them
3053  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
3054
3055  my $fh;
3056  if (open($fh, "> $db_script")) {
3057    print $fh <<EOS;
3058CREATE TABLE ftpallow (
3059  name TEXT,
3060  allowed TEXT
3061);
3062
3063CREATE TABLE ftpdeny (
3064  name TEXT,
3065  denied TEXT
3066);
3067
3068INSERT INTO ftpdeny (name, denied) VALUES ('$group', 'ALL');
3069EOS
3070
3071    unless (close($fh)) {
3072      die("Can't write $db_script: $!");
3073    }
3074
3075  } else {
3076    die("Can't open $db_script: $!");
3077  }
3078
3079  my $cmd = "sqlite3 $db_file < $db_script";
3080
3081  if ($ENV{TEST_VERBOSE}) {
3082    print STDERR "Executing sqlite3: $cmd\n";
3083  }
3084
3085  my @output = `$cmd`;
3086
3087  unlink($db_script);
3088
3089  # Make sure that, if we're running as root, that the home directory has
3090  # permissions/privs set for the account we create
3091  if ($< == 0) {
3092    unless (chmod(0755, $home_dir)) {
3093      die("Can't set perms on $home_dir to 0755: $!");
3094    }
3095
3096    unless (chown($uid, $gid, $home_dir)) {
3097      die("Can't set owner of $home_dir to $uid/$gid: $!");
3098    }
3099  }
3100
3101  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
3102    '/bin/bash');
3103  auth_group_write($auth_group_file, $group, $gid, $user);
3104
3105  my $timeout_idle = 30;
3106
3107  my $config = {
3108    PidFile => $pid_file,
3109    ScoreboardFile => $scoreboard_file,
3110    SystemLog => $log_file,
3111
3112    AuthUserFile => $auth_user_file,
3113    AuthGroupFile => $auth_group_file,
3114    TimeoutIdle => $timeout_idle,
3115
3116    IfModules => {
3117      'mod_delay.c' => {
3118        DelayEngine => 'off',
3119      },
3120
3121      'mod_sql_sqlite.c' => [
3122        'SQLAuthenticate off',
3123        "SQLConnectInfo $db_file",
3124        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
3125        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
3126        "SQLLogFile $log_file",
3127      ],
3128
3129      'mod_wrap2_sql.c' => {
3130        WrapEngine => 'on',
3131        WrapGroupTables => "foo sql:/get-allowed-clients sql:/get-denied-clients",
3132        WrapLog => $log_file,
3133      },
3134    },
3135  };
3136
3137  my ($port, $config_user, $config_group) = config_write($config_file, $config);
3138
3139  # Open pipes, for use between the parent and child processes.  Specifically,
3140  # the child will indicate when it's done with its test by writing a message
3141  # to the parent.
3142  my ($rfh, $wfh);
3143  unless (pipe($rfh, $wfh)) {
3144    die("Can't open pipe: $!");
3145  }
3146
3147  my $ex;
3148
3149  # Fork child
3150  $self->handle_sigchld();
3151  defined(my $pid = fork()) or die("Can't fork: $!");
3152  if ($pid) {
3153    eval {
3154      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
3155      my ($resp_code, $resp_msg) = $client->login($user, $passwd);
3156
3157      my $expected;
3158
3159      $expected = 230;
3160      $self->assert($expected == $resp_code,
3161        test_msg("Expected response code $expected, got $resp_code"));
3162
3163      $expected = "User $user logged in";
3164      $self->assert($expected eq $resp_msg,
3165        test_msg("Expected response message '$expected', got '$resp_msg'"));
3166    };
3167
3168    if ($@) {
3169      $ex = $@;
3170    }
3171
3172    $wfh->print("done\n");
3173    $wfh->flush();
3174
3175  } else {
3176    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
3177    if ($@) {
3178      warn($@);
3179      exit 1;
3180    }
3181
3182    exit 0;
3183  }
3184
3185  # Stop server
3186  server_stop($pid_file);
3187
3188  $self->assert_child_ok($pid);
3189
3190  if ($ex) {
3191    die($ex);
3192  }
3193
3194  # Modify the config a little
3195  $config->{IfModules}->{'mod_wrap2_sql.c'}->{WrapGroupTables} = "ftpd sql:/get-allowed-clients sql:/get-denied-clients";
3196
3197  ($port, $config_user, $config_group) = config_write($config_file, $config);
3198
3199  # Fork child
3200  $self->handle_sigchld();
3201  defined($pid = fork()) or die("Can't fork: $!");
3202  if ($pid) {
3203    eval {
3204      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
3205      eval { $client->login($user, $passwd) };
3206      unless ($@) {
3207        die("Login succeeded unexpectedly");
3208      }
3209
3210      my $resp_code = $client->response_code();
3211      my $resp_msg = $client->response_msg();
3212
3213      my $expected;
3214
3215      $expected = 530;
3216      $self->assert($expected == $resp_code,
3217        test_msg("Expected response code $expected, got $resp_code"));
3218
3219      $expected = "Access denied";
3220      $self->assert($expected eq $resp_msg,
3221        test_msg("Expected response message '$expected', got '$resp_msg'"));
3222    };
3223
3224    if ($@) {
3225      $ex = $@;
3226    }
3227
3228    $wfh->print("done\n");
3229    $wfh->flush();
3230
3231  } else {
3232    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
3233    if ($@) {
3234      warn($@);
3235      exit 1;
3236    }
3237
3238    exit 0;
3239  }
3240
3241  # Stop server
3242  server_stop($pid_file);
3243
3244  $self->assert_child_ok($pid);
3245
3246  if ($ex) {
3247    test_append_logfile($log_file, $ex);
3248    unlink($log_file);
3249
3250    die($ex);
3251  }
3252
3253  unlink($log_file);
3254}
3255
3256sub wrap2_sql_bug3215 {
3257  my $self = shift;
3258  my $tmpdir = $self->{tmpdir};
3259
3260  my $config_file = "$tmpdir/wrap2.conf";
3261  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
3262  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
3263
3264  my $log_file = test_get_logfile();
3265
3266  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
3267  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
3268
3269  my $user = 'proftpd';
3270  my $passwd = 'test';
3271  my $group = 'ftpd';
3272  my $home_dir = File::Spec->rel2abs($tmpdir);
3273  my $uid = 500;
3274  my $gid = 500;
3275
3276  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
3277
3278  # Build up sqlite3 command to create allow, deny tables and populate them
3279  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
3280
3281  my $fh;
3282  if (open($fh, "> $db_script")) {
3283    print $fh <<EOS;
3284CREATE TABLE ftpallow (
3285  allowed TEXT
3286);
3287
3288INSERT INTO ftpallow (allowed) VALUES ('192.168.0.1,192.168.0.2 192.168.0.3, 192.168.0.4 127.0.0.1');
3289
3290CREATE TABLE ftpdeny (
3291  denied TEXT
3292);
3293
3294INSERT INTO ftpdeny (denied) VALUES ('ALL');
3295EOS
3296
3297    unless (close($fh)) {
3298      die("Can't write $db_script: $!");
3299    }
3300
3301  } else {
3302    die("Can't open $db_script: $!");
3303  }
3304
3305  my $cmd = "sqlite3 $db_file < $db_script";
3306
3307  if ($ENV{TEST_VERBOSE}) {
3308    print STDERR "Executing sqlite3: $cmd\n";
3309  }
3310
3311  my @output = `$cmd`;
3312
3313  unlink($db_script);
3314
3315  # Make sure that, if we're running as root, that the home directory has
3316  # permissions/privs set for the account we create
3317  if ($< == 0) {
3318    unless (chmod(0755, $home_dir)) {
3319      die("Can't set perms on $home_dir to 0755: $!");
3320    }
3321
3322    unless (chown($uid, $gid, $home_dir)) {
3323      die("Can't set owner of $home_dir to $uid/$gid: $!");
3324    }
3325  }
3326
3327  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
3328    '/bin/bash');
3329  auth_group_write($auth_group_file, $group, $gid, $user);
3330
3331  my $timeout_idle = 30;
3332
3333  my $config = {
3334    PidFile => $pid_file,
3335    ScoreboardFile => $scoreboard_file,
3336    SystemLog => $log_file,
3337
3338    AuthUserFile => $auth_user_file,
3339    AuthGroupFile => $auth_group_file,
3340    TimeoutIdle => $timeout_idle,
3341
3342    IfModules => {
3343      'mod_delay.c' => {
3344        DelayEngine => 'off',
3345      },
3346
3347      'mod_sql_sqlite.c' => [
3348        'SQLAuthenticate off',
3349        "SQLConnectInfo $db_file",
3350        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow"',
3351        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny"',
3352        "SQLLogFile $log_file",
3353      ],
3354
3355      'mod_wrap2_sql.c' => {
3356        WrapEngine => 'on',
3357        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
3358        WrapLog => $log_file,
3359      },
3360    },
3361  };
3362
3363  my ($port, $config_user, $config_group) = config_write($config_file, $config);
3364
3365  # Open pipes, for use between the parent and child processes.  Specifically,
3366  # the child will indicate when it's done with its test by writing a message
3367  # to the parent.
3368  my ($rfh, $wfh);
3369  unless (pipe($rfh, $wfh)) {
3370    die("Can't open pipe: $!");
3371  }
3372
3373  my $ex;
3374
3375  # Fork child
3376  $self->handle_sigchld();
3377  defined(my $pid = fork()) or die("Can't fork: $!");
3378  if ($pid) {
3379    eval {
3380      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
3381      my ($resp_code, $resp_msg) = $client->login($user, $passwd);
3382
3383      my $expected;
3384
3385      $expected = 230;
3386      $self->assert($expected == $resp_code,
3387        test_msg("Expected response code $expected, got $resp_code"));
3388
3389      $expected = "User $user logged in";
3390      $self->assert($expected eq $resp_msg,
3391        test_msg("Expected response message '$expected', got '$resp_msg'"));
3392    };
3393
3394    if ($@) {
3395      $ex = $@;
3396    }
3397
3398    $wfh->print("done\n");
3399    $wfh->flush();
3400
3401  } else {
3402    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
3403    if ($@) {
3404      warn($@);
3405      exit 1;
3406    }
3407
3408    exit 0;
3409  }
3410
3411  # Stop server
3412  server_stop($pid_file);
3413
3414  $self->assert_child_ok($pid);
3415
3416  if ($ex) {
3417    test_append_logfile($log_file, $ex);
3418    unlink($log_file);
3419
3420    die($ex);
3421  }
3422
3423  unlink($log_file);
3424}
3425
3426sub wrap2_bug3341 {
3427  my $self = shift;
3428  my $tmpdir = $self->{tmpdir};
3429
3430  my $config_file = "$tmpdir/wrap2.conf";
3431  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
3432  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
3433
3434  my $log_file = test_get_logfile();
3435
3436  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
3437  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
3438
3439  my $user = 'proftpd';
3440  my $passwd = 'test';
3441  my $group = 'ftpd';
3442  my $home_dir = File::Spec->rel2abs($tmpdir);
3443  my $uid = 500;
3444  my $gid = 500;
3445
3446  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
3447
3448  # Build up sqlite3 command to create allow, deny tables and populate them
3449  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
3450
3451  my $fh;
3452  if (open($fh, "> $db_script")) {
3453    print $fh <<EOS;
3454CREATE TABLE ftpallow (
3455  allowed TEXT
3456);
3457
3458INSERT INTO ftpallow (allowed) VALUES ('192.168.0.1,192.168.0.2 192.168.0.3, 192.168.0.4 127.0.0.1');
3459
3460CREATE TABLE ftpdeny (
3461  denied TEXT
3462);
3463
3464INSERT INTO ftpdeny (denied) VALUES ('ALL');
3465EOS
3466
3467    unless (close($fh)) {
3468      die("Can't write $db_script: $!");
3469    }
3470
3471  } else {
3472    die("Can't open $db_script: $!");
3473  }
3474
3475  my $cmd = "sqlite3 $db_file < $db_script";
3476
3477  if ($ENV{TEST_VERBOSE}) {
3478    print STDERR "Executing sqlite3: $cmd\n";
3479  }
3480
3481  my @output = `$cmd`;
3482
3483  unlink($db_script);
3484
3485  # Make sure that, if we're running as root, that the home directory has
3486  # permissions/privs set for the account we create
3487  if ($< == 0) {
3488    unless (chmod(0755, $home_dir)) {
3489      die("Can't set perms on $home_dir to 0755: $!");
3490    }
3491
3492    unless (chown($uid, $gid, $home_dir)) {
3493      die("Can't set owner of $home_dir to $uid/$gid: $!");
3494    }
3495  }
3496
3497  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
3498    '/bin/bash');
3499  auth_group_write($auth_group_file, $group, $gid, $user);
3500
3501  my $timeout_idle = 30;
3502
3503  my $config = {
3504    PidFile => $pid_file,
3505    ScoreboardFile => $scoreboard_file,
3506    SystemLog => $log_file,
3507
3508    AuthUserFile => $auth_user_file,
3509    AuthGroupFile => $auth_group_file,
3510    TimeoutIdle => $timeout_idle,
3511
3512    IfModules => {
3513      'mod_delay.c' => {
3514        DelayEngine => 'off',
3515      },
3516
3517      'mod_sql_sqlite.c' => [
3518        'SQLAuthenticate off',
3519        "SQLConnectInfo $db_file",
3520        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow"',
3521        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny"',
3522        "SQLLogFile $log_file",
3523      ],
3524
3525      'mod_wrap2_sql.c' => {
3526        WrapEngine => 'on',
3527        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
3528        WrapLog => $log_file,
3529      },
3530    },
3531  };
3532
3533  my ($port, $config_user, $config_group) = config_write($config_file, $config);
3534
3535  # Open pipes, for use between the parent and child processes.  Specifically,
3536  # the child will indicate when it's done with its test by writing a message
3537  # to the parent.
3538  my ($rfh, $wfh);
3539  unless (pipe($rfh, $wfh)) {
3540    die("Can't open pipe: $!");
3541  }
3542
3543  my $ex;
3544
3545  # Fork child
3546  $self->handle_sigchld();
3547  defined(my $pid = fork()) or die("Can't fork: $!");
3548  if ($pid) {
3549    eval {
3550      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
3551
3552      # As per Bug#3341, we need to send a bad password twice.  The second
3553      # attempt triggered a segfault in mod_wrap2.
3554      eval { $client->login($user, 'foo') };
3555      unless ($@) {
3556        die("Login succeeded unexpectedly");
3557      }
3558
3559      my $resp_code = $client->response_code();
3560      my $resp_msg = $client->response_msg();
3561
3562      my $expected;
3563
3564      $expected = 530;
3565      $self->assert($expected == $resp_code,
3566        test_msg("Expected response code $expected, got $resp_code"));
3567
3568      $expected = "Login incorrect.";
3569      $self->assert($expected eq $resp_msg,
3570        test_msg("Expected response message '$expected', got '$resp_msg'"));
3571
3572      # Now try to login again
3573      eval { $client->login($user, 'foo') };
3574      unless ($@) {
3575        die("Login succeeded unexpectedly");
3576      }
3577
3578      $resp_code = $client->response_code();
3579      $resp_msg = $client->response_msg();
3580
3581      $expected = 530;
3582      $self->assert($expected == $resp_code,
3583        test_msg("Expected response code $expected, got $resp_code"));
3584
3585      $expected = "Login incorrect.";
3586      $self->assert($expected eq $resp_msg,
3587        test_msg("Expected response message '$expected', got '$resp_msg'"));
3588
3589      ($resp_code, $resp_msg) = $client->login($user, $passwd);
3590
3591      $expected = 230;
3592      $self->assert($expected == $resp_code,
3593        test_msg("Expected response code $expected, got $resp_code"));
3594
3595      $expected = "User $user logged in";
3596      $self->assert($expected eq $resp_msg,
3597        test_msg("Expected response message '$expected', got '$resp_msg'"));
3598    };
3599
3600    if ($@) {
3601      $ex = $@;
3602    }
3603
3604    $wfh->print("done\n");
3605    $wfh->flush();
3606
3607  } else {
3608    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
3609    if ($@) {
3610      warn($@);
3611      exit 1;
3612    }
3613
3614    exit 0;
3615  }
3616
3617  # Stop server
3618  server_stop($pid_file);
3619
3620  $self->assert_child_ok($pid);
3621
3622  if ($ex) {
3623    test_append_logfile($log_file, $ex);
3624    unlink($log_file);
3625
3626    die($ex);
3627  }
3628
3629  unlink($log_file);
3630}
3631
3632sub wrap2_sql_opt_check_on_connect_bug3508 {
3633  my $self = shift;
3634  my $tmpdir = $self->{tmpdir};
3635
3636  # XXX NOTE: In order for the CheckOnConnect WrapOption to work properly
3637  # with mod_wrap2_sql, the module load order must be very specific, e.g.:
3638  #
3639  #  --with-modules=mod_wrap2:mod_wrap2_sql:mod_sql:mod_sqlite
3640  #
3641  # Specifically, mod_sql and its backend(s) MUST appear AFTER mod_wrap2 and
3642  # its submodules in the module load order list.  This is necessary because
3643  # mod_sql's session init callback is where the database connection is
3644  # defined.  If mod_wrap2 appears after mod_sql in the module load order
3645  # list, then mod_wrap2's session init callback is called first, and it
3646  # will try to use mod_wrap2_sql to get the table data, which will try to
3647  # use mod_sql -- and the database connection won't be defined.  And only
3648  # mod_sql has the knowledge of how to handle the SQLConnectInfo directive,
3649  # which is needed in order to define/create that database connection.
3650
3651  my $mod_list = feature_get_compiled_modules();
3652  my ($mod_wrap2_idx, $mod_sql_idx);
3653
3654  my $nmodules = scalar(@$mod_list);
3655  for (my $i = 0; $i < $nmodules; $i++) {
3656    if ($mod_list->[$i] =~ /mod_wrap2\.c/) {
3657      $mod_wrap2_idx = $i;
3658    }
3659
3660    if ($mod_list->[$i] =~ /mod_sql\.c/) {
3661      $mod_sql_idx = $i;
3662    }
3663  }
3664
3665  if ($mod_sql_idx < $mod_wrap2_idx) {
3666    print STDERR " + unable to run 'wrap2_sql_opt_check_on_connect_bug3508' test with current module order (mod_sql appears BEFORE mod_wrap2), skipping\n";
3667    return;
3668  }
3669
3670  my $config_file = "$tmpdir/wrap2.conf";
3671  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
3672  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
3673
3674  my $log_file = test_get_logfile();
3675
3676  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
3677  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
3678
3679  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
3680
3681  # Build up sqlite3 command to create allow, deny tables and populate them
3682  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
3683
3684  my $fh;
3685  if (open($fh, "> $db_script")) {
3686    print $fh <<EOS;
3687CREATE TABLE ftpallow (
3688  name TEXT,
3689  allowed TEXT
3690);
3691
3692CREATE TABLE ftpdeny (
3693  name TEXT,
3694  denied TEXT
3695);
3696
3697EOS
3698
3699    unless (close($fh)) {
3700      die("Can't write $db_script: $!");
3701    }
3702
3703  } else {
3704    die("Can't open $db_script: $!");
3705  }
3706
3707  my $cmd = "sqlite3 $db_file < $db_script";
3708
3709  if ($ENV{TEST_VERBOSE}) {
3710    print STDERR "Executing sqlite3: $cmd\n";
3711  }
3712
3713  my @output = `$cmd`;
3714  if (scalar(@output) &&
3715      $ENV{TEST_VERBOSE}) {
3716    print STDERR "Output: ", join("", @output), "\n";
3717  }
3718
3719  unlink($db_script);
3720
3721  my $user = 'proftpd';
3722  my $passwd = 'test';
3723  my $group = 'ftpd';
3724  my $home_dir = File::Spec->rel2abs($tmpdir);
3725  my $uid = 500;
3726  my $gid = 500;
3727
3728  # Make sure that, if we're running as root, that the home directory has
3729  # permissions/privs set for the account we create
3730  if ($< == 0) {
3731    unless (chmod(0755, $home_dir)) {
3732      die("Can't set perms on $home_dir to 0755: $!");
3733    }
3734
3735    unless (chown($uid, $gid, $home_dir)) {
3736      die("Can't set owner of $home_dir to $uid/$gid: $!");
3737    }
3738  }
3739
3740  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
3741    '/bin/bash');
3742  auth_group_write($auth_group_file, $group, $gid, $user);
3743
3744  my $timeout_idle = 30;
3745
3746  my $config = {
3747    PidFile => $pid_file,
3748    ScoreboardFile => $scoreboard_file,
3749    SystemLog => $log_file,
3750
3751    AuthUserFile => $auth_user_file,
3752    AuthGroupFile => $auth_group_file,
3753    TimeoutIdle => $timeout_idle,
3754
3755    IfModules => {
3756      'mod_delay.c' => {
3757        DelayEngine => 'off',
3758      },
3759
3760      'mod_sql_sqlite.c' => [
3761        'SQLAuthenticate off',
3762        "SQLConnectInfo $db_file",
3763        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
3764        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
3765        "SQLLogFile $log_file",
3766      ],
3767
3768      'mod_wrap2_sql.c' => {
3769        WrapEngine => 'on',
3770        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
3771        WrapLog => $log_file,
3772        WrapOptions => 'CheckOnConnect',
3773      },
3774    },
3775  };
3776
3777  my ($port, $config_user, $config_group) = config_write($config_file, $config);
3778
3779  # Open pipes, for use between the parent and child processes.  Specifically,
3780  # the child will indicate when it's done with its test by writing a message
3781  # to the parent.
3782  my ($rfh, $wfh);
3783  unless (pipe($rfh, $wfh)) {
3784    die("Can't open pipe: $!");
3785  }
3786
3787  my $ex;
3788
3789  # Fork child
3790  $self->handle_sigchld();
3791  defined(my $pid = fork()) or die("Can't fork: $!");
3792  if ($pid) {
3793    eval {
3794      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
3795      my ($resp_code, $resp_msg) = $client->login($user, $passwd);
3796
3797      my $expected;
3798
3799      $expected = 230;
3800      $self->assert($expected == $resp_code,
3801        test_msg("Expected response code $expected, got $resp_code"));
3802
3803      $expected = "User $user logged in";
3804      $self->assert($expected eq $resp_msg,
3805        test_msg("Expected response message '$expected', got '$resp_msg'"));
3806    };
3807
3808    if ($@) {
3809      $ex = $@;
3810    }
3811
3812    $wfh->print("done\n");
3813    $wfh->flush();
3814
3815  } else {
3816    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
3817    if ($@) {
3818      warn($@);
3819      exit 1;
3820    }
3821
3822    exit 0;
3823  }
3824
3825  # Stop server
3826  server_stop($pid_file);
3827
3828  $self->assert_child_ok($pid);
3829
3830  if ($ex) {
3831    die($ex);
3832  }
3833
3834  if (open($fh, "> $db_script")) {
3835    print $fh <<EOS;
3836INSERT INTO ftpdeny (name, denied) VALUES ('', '127.0.0.1');
3837EOS
3838    unless (close($fh)) {
3839      die("Can't write $db_script: $!");
3840    }
3841
3842  } else {
3843    die("Can't open $db_script: $!");
3844  }
3845
3846  $cmd = "sqlite3 $db_file < $db_script";
3847
3848  if ($ENV{TEST_VERBOSE}) {
3849    print STDERR "Executing sqlite3: $cmd\n";
3850  }
3851
3852  @output = `$cmd`;
3853  if (scalar(@output) &&
3854      $ENV{TEST_VERBOSE}) {
3855    print STDERR "Output: ", join('', @output), "\n";
3856  }
3857
3858  unlink($db_script);
3859
3860  ($port, $config_user, $config_group) = config_write($config_file, $config);
3861
3862  # Fork child
3863  $self->handle_sigchld();
3864  defined($pid = fork()) or die("Can't fork: $!");
3865  if ($pid) {
3866    eval {
3867      my $client;
3868
3869      eval {
3870        $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, undef, 2);
3871      };
3872      unless ($@) {
3873        die("Connect succeeded unexpectedly");
3874      }
3875
3876      my $ex = ProFTPD::TestSuite::FTP::get_connect_exception();
3877
3878      my $expected = "Access denied";
3879      $self->assert($expected eq $ex,
3880        test_msg("Expected '$expected', got '$ex'"));
3881    };
3882
3883    if ($@) {
3884      $ex = $@;
3885    }
3886
3887    $wfh->print("done\n");
3888    $wfh->flush();
3889
3890  } else {
3891    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
3892    if ($@) {
3893      warn($@);
3894      exit 1;
3895    }
3896
3897    exit 0;
3898  }
3899
3900  # Stop server
3901  server_stop($pid_file);
3902
3903  $self->assert_child_ok($pid);
3904
3905  if ($ex) {
3906    test_append_logfile($log_file, $ex);
3907    unlink($log_file);
3908
3909    die($ex);
3910  }
3911
3912  unlink($log_file);
3913}
3914
3915sub wrap2_allow_msg_bug3538 {
3916  my $self = shift;
3917  my $tmpdir = $self->{tmpdir};
3918
3919  my $config_file = "$tmpdir/wrap2.conf";
3920  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
3921  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
3922
3923  my $log_file = test_get_logfile();
3924
3925  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
3926  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
3927
3928  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
3929
3930  # Build up sqlite3 command to create allow, deny tables and populate them
3931  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
3932
3933  my $fh;
3934  if (open($fh, "> $db_script")) {
3935    print $fh <<EOS;
3936CREATE TABLE ftpallow (
3937  name TEXT,
3938  allowed TEXT
3939);
3940
3941CREATE TABLE ftpdeny (
3942  name TEXT,
3943  denied TEXT
3944);
3945
3946EOS
3947
3948    unless (close($fh)) {
3949      die("Can't write $db_script: $!");
3950    }
3951
3952  } else {
3953    die("Can't open $db_script: $!");
3954  }
3955
3956  my $cmd = "sqlite3 $db_file < $db_script";
3957
3958  if ($ENV{TEST_VERBOSE}) {
3959    print STDERR "Executing sqlite3: $cmd\n";
3960  }
3961
3962  my @output = `$cmd`;
3963
3964  unlink($db_script);
3965
3966  my $user = 'proftpd';
3967  my $passwd = 'test';
3968  my $group = 'ftpd';
3969  my $home_dir = File::Spec->rel2abs($tmpdir);
3970  my $uid = 500;
3971  my $gid = 500;
3972
3973  # Make sure that, if we're running as root, that the home directory has
3974  # permissions/privs set for the account we create
3975  if ($< == 0) {
3976    unless (chmod(0755, $home_dir)) {
3977      die("Can't set perms on $home_dir to 0755: $!");
3978    }
3979
3980    unless (chown($uid, $gid, $home_dir)) {
3981      die("Can't set owner of $home_dir to $uid/$gid: $!");
3982    }
3983  }
3984
3985  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
3986    '/bin/bash');
3987  auth_group_write($auth_group_file, $group, $gid, $user);
3988
3989  my $timeout_idle = 30;
3990
3991  my $config = {
3992    PidFile => $pid_file,
3993    ScoreboardFile => $scoreboard_file,
3994    SystemLog => $log_file,
3995
3996    AccessGrantMsg => '"User %u logged in."',
3997    AuthUserFile => $auth_user_file,
3998    AuthGroupFile => $auth_group_file,
3999    TimeoutIdle => $timeout_idle,
4000
4001    IfModules => {
4002      'mod_delay.c' => {
4003        DelayEngine => 'off',
4004      },
4005
4006      'mod_sql_sqlite.c' => [
4007        'SQLAuthenticate off',
4008        "SQLConnectInfo $db_file",
4009        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
4010        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
4011        "SQLLogFile $log_file",
4012      ],
4013
4014      'mod_wrap2_sql.c' => {
4015        WrapEngine => 'on',
4016        WrapAllowMsg => '"User %u allowed by access rules"',
4017        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
4018        WrapLog => $log_file,
4019      },
4020    },
4021  };
4022
4023  my ($port, $config_user, $config_group) = config_write($config_file, $config);
4024
4025  # Open pipes, for use between the parent and child processes.  Specifically,
4026  # the child will indicate when it's done with its test by writing a message
4027  # to the parent.
4028  my ($rfh, $wfh);
4029  unless (pipe($rfh, $wfh)) {
4030    die("Can't open pipe: $!");
4031  }
4032
4033  my $ex;
4034
4035  # Fork child
4036  $self->handle_sigchld();
4037  defined(my $pid = fork()) or die("Can't fork: $!");
4038  if ($pid) {
4039    eval {
4040      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
4041      $client->login($user, $passwd);
4042
4043      my $resp_code = $client->response_code();
4044      my $resp_msg = $client->response_msg(0);
4045
4046      my $expected;
4047
4048      $expected = 230;
4049      $self->assert($expected == $resp_code,
4050        test_msg("Expected response code $expected, got $resp_code"));
4051
4052      $expected = "User $user allowed by access rules";
4053      $self->assert($expected eq $resp_msg,
4054        test_msg("Expected response message '$expected', got '$resp_msg'"));
4055
4056      $resp_msg = $client->response_msg(1);
4057
4058      $expected = "User $user logged in.";
4059      $self->assert($expected eq $resp_msg,
4060        test_msg("Expected response meessage '$expected', got '$resp_msg'"));
4061    };
4062
4063    if ($@) {
4064      $ex = $@;
4065    }
4066
4067    $wfh->print("done\n");
4068    $wfh->flush();
4069
4070  } else {
4071    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
4072    if ($@) {
4073      warn($@);
4074      exit 1;
4075    }
4076
4077    exit 0;
4078  }
4079
4080  # Stop server
4081  server_stop($pid_file);
4082
4083  $self->assert_child_ok($pid);
4084
4085  if ($ex) {
4086    test_append_logfile($log_file, $ex);
4087    unlink($log_file);
4088
4089    die($ex);
4090  }
4091
4092  unlink($log_file);
4093}
4094
4095sub wrap2_allow_msg_anon_bug3538 {
4096  my $self = shift;
4097  my $tmpdir = $self->{tmpdir};
4098
4099  my $config_file = "$tmpdir/wrap2.conf";
4100  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
4101  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
4102
4103  my $log_file = test_get_logfile();
4104
4105  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
4106  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
4107
4108  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
4109
4110  # Build up sqlite3 command to create allow, deny tables and populate them
4111  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
4112
4113  my $fh;
4114  if (open($fh, "> $db_script")) {
4115    print $fh <<EOS;
4116CREATE TABLE ftpallow (
4117  name TEXT,
4118  allowed TEXT
4119);
4120
4121CREATE TABLE ftpdeny (
4122  name TEXT,
4123  denied TEXT
4124);
4125
4126EOS
4127
4128    unless (close($fh)) {
4129      die("Can't write $db_script: $!");
4130    }
4131
4132  } else {
4133    die("Can't open $db_script: $!");
4134  }
4135
4136  my $cmd = "sqlite3 $db_file < $db_script";
4137
4138  if ($ENV{TEST_VERBOSE}) {
4139    print STDERR "Executing sqlite3: $cmd\n";
4140  }
4141
4142  my @output = `$cmd`;
4143
4144  unlink($db_script);
4145
4146  my ($test_user, $test_group) = config_get_identity();
4147  my $passwd = 'test';
4148  my $home_dir = File::Spec->rel2abs($tmpdir);
4149  my $uid = 500;
4150  my $gid = 500;
4151
4152  # Make sure that, if we're running as root, that the home directory has
4153  # permissions/privs set for the account we create
4154  if ($< == 0) {
4155    unless (chmod(0755, $home_dir)) {
4156      die("Can't set perms on $home_dir to 0755: $!");
4157    }
4158
4159    unless (chown($uid, $gid, $home_dir)) {
4160      die("Can't set owner of $home_dir to $uid/$gid: $!");
4161    }
4162  }
4163
4164  auth_user_write($auth_user_file, $test_user, $passwd, $uid, $gid, '/tmp',
4165    '/bin/bash');
4166  auth_group_write($auth_group_file, $test_group, $gid, $test_user);
4167
4168  my $timeout_idle = 30;
4169
4170  my $config = {
4171    PidFile => $pid_file,
4172    ScoreboardFile => $scoreboard_file,
4173    SystemLog => $log_file,
4174
4175    AccessGrantMsg => '"User %u logged in."',
4176    AuthUserFile => $auth_user_file,
4177    AuthGroupFile => $auth_group_file,
4178    TimeoutIdle => $timeout_idle,
4179
4180    Anonymous => {
4181      $home_dir => {
4182        User => $test_user,
4183        Group => $test_group,
4184        UserAlias => "anonymous $test_user",
4185        RequireValidShell => 'off',
4186      },
4187    },
4188
4189    IfModules => {
4190      'mod_delay.c' => {
4191        DelayEngine => 'off',
4192      },
4193
4194      'mod_sql_sqlite.c' => [
4195        'SQLAuthenticate off',
4196        "SQLConnectInfo $db_file",
4197        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
4198        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
4199        "SQLLogFile $log_file",
4200      ],
4201
4202      'mod_wrap2_sql.c' => {
4203        WrapEngine => 'on',
4204        WrapAllowMsg => '"User %u allowed by access rules"',
4205        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
4206        WrapLog => $log_file,
4207      },
4208    },
4209  };
4210
4211  my ($port, $config_user, $config_group) = config_write($config_file, $config);
4212
4213  # Open pipes, for use between the parent and child processes.  Specifically,
4214  # the child will indicate when it's done with its test by writing a message
4215  # to the parent.
4216  my ($rfh, $wfh);
4217  unless (pipe($rfh, $wfh)) {
4218    die("Can't open pipe: $!");
4219  }
4220
4221  my $ex;
4222
4223  # Fork child
4224  $self->handle_sigchld();
4225  defined(my $pid = fork()) or die("Can't fork: $!");
4226  if ($pid) {
4227    eval {
4228      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
4229
4230      $client->login('anonymous', 'ftp@nospam.org');
4231
4232      my $resp_code = $client->response_code();
4233      my $resp_msg = $client->response_msg(0);
4234
4235      my $expected;
4236
4237      $expected = 230;
4238      $self->assert($expected == $resp_code,
4239        test_msg("Expected $expected, got $resp_code"));
4240
4241      $expected = "User anonymous logged in.";
4242      $self->assert($expected eq $resp_msg,
4243        test_msg("Expected '$expected', got '$resp_msg'"));
4244
4245      $resp_msg = $client->response_msg(1);
4246
4247      $expected = "User anonymous allowed by access rules";
4248      $self->assert($expected eq $resp_msg,
4249        test_msg("Expected '$expected', got '$resp_msg'"));
4250    };
4251
4252    if ($@) {
4253      $ex = $@;
4254    }
4255
4256    $wfh->print("done\n");
4257    $wfh->flush();
4258
4259  } else {
4260    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
4261    if ($@) {
4262      warn($@);
4263      exit 1;
4264    }
4265
4266    exit 0;
4267  }
4268
4269  # Stop server
4270  server_stop($pid_file);
4271
4272  $self->assert_child_ok($pid);
4273
4274  if ($ex) {
4275    test_append_logfile($log_file, $ex);
4276    unlink($log_file);
4277
4278    die($ex);
4279  }
4280
4281  unlink($log_file);
4282}
4283
4284sub wrap2_sql_deny_event_exec_bug3209 {
4285  my $self = shift;
4286  my $tmpdir = $self->{tmpdir};
4287
4288  my $config_file = "$tmpdir/wrap2.conf";
4289  my $pid_file = File::Spec->rel2abs("$tmpdir/wrap2.pid");
4290  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/wrap2.scoreboard");
4291
4292  my $log_file = test_get_logfile();
4293
4294  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
4295  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
4296
4297  my $db_file = File::Spec->rel2abs("$tmpdir/wrap2.db");
4298
4299  # Build up sqlite3 command to create allow, deny tables and populate them
4300  my $db_script = File::Spec->rel2abs("$tmpdir/wrap2.sql");
4301
4302  my $fh;
4303  if (open($fh, "> $db_script")) {
4304    print $fh <<EOS;
4305CREATE TABLE ftpallow (
4306  name TEXT,
4307  allowed TEXT
4308);
4309
4310CREATE TABLE ftpdeny (
4311  name TEXT,
4312  denied TEXT
4313);
4314
4315INSERT INTO ftpdeny (name, denied) VALUES ('', 'ALL');
4316EOS
4317
4318    unless (close($fh)) {
4319      die("Can't write $db_script: $!");
4320    }
4321
4322  } else {
4323    die("Can't open $db_script: $!");
4324  }
4325
4326  my $cmd = "sqlite3 $db_file < $db_script";
4327
4328  if ($ENV{TEST_VERBOSE}) {
4329    print STDERR "Executing sqlite3: $cmd\n";
4330  }
4331
4332  my @output = `$cmd`;
4333
4334  unlink($db_script);
4335
4336  my $user = 'proftpd';
4337  my $passwd = 'test';
4338  my $group = 'ftpd';
4339  my $home_dir = File::Spec->rel2abs($tmpdir);
4340  my $uid = 500;
4341  my $gid = 500;
4342
4343  # Make sure that, if we're running as root, that the home directory has
4344  # permissions/privs set for the account we create
4345  if ($< == 0) {
4346    unless (chmod(0755, $home_dir)) {
4347      die("Can't set perms on $home_dir to 0755: $!");
4348    }
4349
4350    unless (chown($uid, $gid, $home_dir)) {
4351      die("Can't set owner of $home_dir to $uid/$gid: $!");
4352    }
4353  }
4354
4355  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
4356    '/bin/bash');
4357  auth_group_write($auth_group_file, $group, $gid, $user);
4358
4359  my $event_file = File::Spec->rel2abs("$tmpdir/denied-client.txt");
4360  my $spawn_script = File::Spec->rel2abs("$tmpdir/spawn.sh");
4361  if (open(my $fh, "> $spawn_script")) {
4362    print $fh <<EOS;
4363#!/usr/bin/env bash
4364echo $@ > $event_file
4365exit
4366EOS
4367    unless (close($fh)) {
4368      die("Can't write $spawn_script: $!");
4369    }
4370
4371    unless (chmod(0777, $spawn_script)) {
4372      die("Can't set perms on $spawn_script to 0777: $!");
4373    }
4374
4375  } else {
4376    die("Can't open $spawn_script: $!");
4377  }
4378
4379  my $timeout_idle = 30;
4380
4381  my $config = {
4382    PidFile => $pid_file,
4383    ScoreboardFile => $scoreboard_file,
4384    SystemLog => $log_file,
4385    TraceLog => $log_file,
4386    Trace => 'event:20',
4387
4388    AuthUserFile => $auth_user_file,
4389    AuthGroupFile => $auth_group_file,
4390    TimeoutIdle => $timeout_idle,
4391
4392    IfModules => {
4393      'mod_delay.c' => {
4394        DelayEngine => 'off',
4395      },
4396
4397      'mod_exec.c' => {
4398        ExecEngine => 'on',
4399        ExecLog => $log_file,
4400        ExecTimeout => 1,
4401        ExecOnEvent => "mod_wrap.connection-denied $spawn_script %a",
4402      },
4403
4404      'mod_sql_sqlite.c' => [
4405        "SQLAuthenticate off",
4406        "SQLConnectInfo $db_file",
4407        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%{0}\'"',
4408        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%{0}\'"',
4409        "SQLLogFile $log_file",
4410      ],
4411
4412      'mod_wrap2_sql.c' => {
4413        WrapEngine => 'on',
4414        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
4415        WrapLog => $log_file,
4416      },
4417    },
4418  };
4419
4420  my ($port, $config_user, $config_group) = config_write($config_file, $config);
4421
4422  # Open pipes, for use between the parent and child processes.  Specifically,
4423  # the child will indicate when it's done with its test by writing a message
4424  # to the parent.
4425  my ($rfh, $wfh);
4426  unless (pipe($rfh, $wfh)) {
4427    die("Can't open pipe: $!");
4428  }
4429
4430  my $ex;
4431
4432  # Fork child
4433  $self->handle_sigchld();
4434  defined(my $pid = fork()) or die("Can't fork: $!");
4435  if ($pid) {
4436    eval {
4437      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
4438      eval { $client->login($user, $passwd) };
4439      unless ($@) {
4440        die("Login succeeded unexpectedly");
4441      }
4442
4443      my $resp_code = $client->response_code();
4444      my $resp_msg = $client->response_msg();
4445
4446      my $expected;
4447
4448      $expected = 530;
4449      $self->assert($expected == $resp_code,
4450        test_msg("Expected $expected, got $resp_code"));
4451
4452      $expected = "Access denied";
4453      $self->assert($expected eq $resp_msg,
4454        test_msg("Expected '$expected', got '$resp_msg'"));
4455
4456      if (open(my $fh, "< $event_file")) {
4457        my $line = <$fh>;
4458        chomp($line);
4459        close($fh);
4460
4461        my $expected = '127.0.0.1';
4462        $self->assert($expected eq $line,
4463          test_msg("Expected line '$expected', got '$line'"));
4464
4465      } else {
4466        die("Can't read $event_file: $!");
4467      }
4468
4469    };
4470
4471    if ($@) {
4472      $ex = $@;
4473    }
4474
4475    $wfh->print("done\n");
4476    $wfh->flush();
4477
4478  } else {
4479    eval { server_wait($config_file, $rfh, $timeout_idle + 2) };
4480    if ($@) {
4481      warn($@);
4482      exit 1;
4483    }
4484
4485    exit 0;
4486  }
4487
4488  # Stop server
4489  server_stop($pid_file);
4490
4491  $self->assert_child_ok($pid);
4492
4493  if ($ex) {
4494    test_append_logfile($log_file, $ex);
4495    unlink($log_file);
4496
4497    die($ex);
4498  }
4499
4500  unlink($log_file);
4501}
4502
45031;
4504