1package ProFTPD::Tests::Modules::mod_sftp::wrap2;
2
3use lib qw(t/lib);
4use base qw(ProFTPD::TestSuite::Child);
5use strict;
6
7use File::Copy;
8use File::Path qw(mkpath rmtree);
9use File::Spec;
10use IO::Handle;
11use IPC::Open3;
12use POSIX qw(:fcntl_h);
13use Socket;
14
15use ProFTPD::TestSuite::FTP;
16use ProFTPD::TestSuite::Utils qw(:auth :config :features :running :test :testsuite);
17
18$| = 1;
19
20my $order = 0;
21
22my $TESTS = {
23  sftp_wrap2_file_login => {
24    order => ++$order,
25    test_class => [qw(bug forking mod_wrap2_file sftp ssh2)],
26  },
27
28  sftp_wrap2_sql_login => {
29    order => ++$order,
30    test_class => [qw(bug forking mod_sql_sqlite mod_wrap2_sql sftp ssh2)],
31  },
32
33  sftp_wrap2_deny_msg_on_connect_bug3670 => {
34    order => ++$order,
35    test_class => [qw(bug forking mod_wrap2_file sftp ssh2)],
36  },
37
38  sftp_wrap2_deny_msg_on_auth_bug3670 => {
39    order => ++$order,
40    test_class => [qw(bug forking mod_wrap2_file sftp ssh2)],
41  },
42
43  sftp_wrap2_deny_msg_var_u => {
44    order => ++$order,
45    test_class => [qw(bug forking mod_wrap2_file sftp ssh2)],
46  },
47
48};
49
50sub new {
51  return shift()->SUPER::new(@_);
52}
53
54sub list_tests {
55  # Check for the required Perl modules:
56  #
57  #  Net-SSH2
58  #  Net-SSH2-SFTP
59
60  my $required = [qw(
61    Net::SSH2
62    Net::SSH2::SFTP
63  )];
64
65  foreach my $req (@$required) {
66    eval "use $req";
67    if ($@) {
68      print STDERR "\nWARNING:\n + Module '$req' not found, skipping all tests\n";
69
70      if ($ENV{TEST_VERBOSE}) {
71        print STDERR "Unable to load $req: $@\n";
72      }
73
74      return qw(testsuite_empty_test);
75    }
76  }
77
78  return testsuite_get_runnable_tests($TESTS);
79}
80
81sub set_up {
82  my $self = shift;
83  $self->SUPER::set_up(@_);
84
85  # Make sure that mod_sftp does not complain about permissions on the hostkey
86  # files.
87
88  my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
89  my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
90
91  unless (chmod(0400, $rsa_host_key, $dsa_host_key)) {
92    die("Can't set perms on $rsa_host_key, $dsa_host_key: $!");
93  }
94}
95
96sub sftp_wrap2_file_login {
97  my $self = shift;
98  my $tmpdir = $self->{tmpdir};
99
100  my $config_file = "$tmpdir/sftp.conf";
101  my $pid_file = File::Spec->rel2abs("$tmpdir/sftp.pid");
102  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sftp.scoreboard");
103
104  my $log_file = test_get_logfile();
105
106  my $auth_user_file = File::Spec->rel2abs("$tmpdir/sftp.passwd");
107  my $auth_group_file = File::Spec->rel2abs("$tmpdir/sftp.group");
108
109  my $fh;
110  my $allow_file = File::Spec->rel2abs("$tmpdir/sftp.allow");
111  if (open($fh, "> $allow_file")) {
112    print $fh "proftpd: ALL\n";
113
114    unless (close($fh)) {
115      die("Can't write $allow_file: $!");
116    }
117
118  } else {
119    die("Can't open $allow_file: $!");
120  }
121
122  my $deny_file = File::Spec->rel2abs("$tmpdir/sftp.deny");
123  if (open($fh, "> $deny_file")) {
124    print $fh "ALL: ALL\n";
125
126    unless (close($fh)) {
127      die("Can't write $deny_file: $!");
128    }
129
130  } else {
131    die("Can't open $deny_file: $!");
132  }
133
134  my $user = 'proftpd';
135  my $passwd = 'test';
136  my $group = 'ftpd';
137  my $home_dir = File::Spec->rel2abs($tmpdir);
138  my $uid = 500;
139  my $gid = 500;
140
141  # Make sure that, if we're running as root, that the home directory has
142  # permissions/privs set for the account we create
143  if ($< == 0) {
144    unless (chmod(0755, $home_dir)) {
145      die("Can't set perms on $home_dir to 0755: $!");
146    }
147
148    unless (chown($uid, $gid, $home_dir)) {
149      die("Can't set owner of $home_dir to $uid/$gid: $!");
150    }
151  }
152
153  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
154    '/bin/bash');
155  auth_group_write($auth_group_file, $group, $gid, $user);
156
157  my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
158  my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
159
160  my $rsa_priv_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key');
161  my $rsa_pub_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key.pub');
162
163  my $config = {
164    PidFile => $pid_file,
165    ScoreboardFile => $scoreboard_file,
166    SystemLog => $log_file,
167    TraceLog => $log_file,
168    Trace => 'DEFAULT:10 ssh2:20 sftp:20 scp:20',
169
170    AuthUserFile => $auth_user_file,
171    AuthGroupFile => $auth_group_file,
172
173    IfModules => {
174      'mod_delay.c' => {
175        DelayEngine => 'off',
176      },
177
178      'mod_sftp.c' => [
179        "SFTPEngine on",
180        "SFTPLog $log_file",
181        "SFTPHostKey $rsa_host_key",
182        "SFTPHostKey $dsa_host_key",
183      ],
184
185      'mod_wrap2.c' => {
186        WrapEngine => 'on',
187        WrapLog => $log_file,
188        WrapTables => "file:$allow_file file:$deny_file",
189        WrapDenyMsg => "User '%u' denied by access rules",
190        WrapAllowMsg => "User '%u' allowed by access rules",
191      },
192    },
193  };
194
195  my ($port, $config_user, $config_group) = config_write($config_file, $config);
196
197  # Open pipes, for use between the parent and child processes.  Specifically,
198  # the child will indicate when it's done with its test by writing a message
199  # to the parent.
200  my ($rfh, $wfh);
201  unless (pipe($rfh, $wfh)) {
202    die("Can't open pipe: $!");
203  }
204
205  require Net::SSH2;
206
207  my $ex;
208
209  # Fork child
210  $self->handle_sigchld();
211  defined(my $pid = fork()) or die("Can't fork: $!");
212  if ($pid) {
213    eval {
214      my $ssh2 = Net::SSH2->new();
215
216      sleep(1);
217
218      unless ($ssh2->connect('127.0.0.1', $port)) {
219        my ($err_code, $err_name, $err_str) = $ssh2->error();
220        die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
221      }
222
223      if ($ssh2->auth_publickey($user, $rsa_pub_key, $rsa_priv_key)) {
224        die("Publickey auth succeeded unexpectedly");
225      }
226
227      unless ($ssh2->auth_password($user, $passwd)) {
228        my ($err_code, $err_name, $err_str) = $ssh2->error();
229        die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
230      }
231
232      my $sftp = $ssh2->sftp();
233      unless ($sftp) {
234        my ($err_code, $err_name, $err_str) = $ssh2->error();
235        die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
236      }
237
238      $sftp = undef;
239      $ssh2->disconnect();
240    };
241
242    if ($@) {
243      $ex = $@;
244    }
245
246    $wfh->print("done\n");
247    $wfh->flush();
248
249  } else {
250    eval { server_wait($config_file, $rfh) };
251    if ($@) {
252      warn($@);
253      exit 1;
254    }
255
256    exit 0;
257  }
258
259  # Stop server
260  server_stop($pid_file);
261
262  $self->assert_child_ok($pid);
263
264  if ($ex) {
265    test_append_logfile($log_file, $ex);
266    unlink($log_file);
267
268    die($ex);
269  }
270
271  unlink($log_file);
272}
273
274sub sftp_wrap2_sql_login {
275  my $self = shift;
276  my $tmpdir = $self->{tmpdir};
277
278  my $config_file = "$tmpdir/sftp.conf";
279  my $pid_file = File::Spec->rel2abs("$tmpdir/sftp.pid");
280  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sftp.scoreboard");
281
282  my $log_file = test_get_logfile();
283
284  my $auth_user_file = File::Spec->rel2abs("$tmpdir/wrap2.passwd");
285  my $auth_group_file = File::Spec->rel2abs("$tmpdir/wrap2.group");
286
287  my $user = 'proftpd';
288  my $passwd = 'test';
289  my $group = 'ftpd';
290  my $home_dir = File::Spec->rel2abs($tmpdir);
291  my $uid = 500;
292  my $gid = 500;
293
294  # Make sure that, if we're running as root, that the home directory has
295  # permissions/privs set for the account we create
296  if ($< == 0) {
297    unless (chmod(0755, $home_dir)) {
298      die("Can't set perms on $home_dir to 0755: $!");
299    }
300
301    unless (chown($uid, $gid, $home_dir)) {
302      die("Can't set owner of $home_dir to $uid/$gid: $!");
303    }
304  }
305
306  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
307    '/bin/bash');
308  auth_group_write($auth_group_file, $group, $gid, $user);
309
310  my $db_file = File::Spec->rel2abs("$tmpdir/proftpd.db");
311
312  # Build up sqlite3 command to create allow, deny tables and populate them
313  my $db_script = File::Spec->rel2abs("$tmpdir/proftpd.sql");
314
315  my $fh;
316  if (open($fh, "> $db_script")) {
317    print $fh <<EOS;
318CREATE TABLE ftpallow (
319  name TEXT,
320  allowed TEXT
321);
322INSERT INTO ftpallow (name, allowed) VALUES ('$user', 'ALL');
323
324CREATE TABLE ftpdeny (
325  name TEXT,
326  denied TEXT
327);
328
329EOS
330
331    unless (close($fh)) {
332      die("Can't write $db_script: $!");
333    }
334
335  } else {
336    die("Can't open $db_script: $!");
337  }
338
339  my $cmd = "sqlite3 $db_file < $db_script";
340
341  if ($ENV{TEST_VERBOSE}) {
342    print STDERR "Executing sqlite3: $cmd\n";
343  }
344
345  my @output = `$cmd`;
346  if (scalar(@output) > 0 &&
347      $ENV{TEST_VERBOSE}) {
348    print STDERR "Output: ", join('', @output), "\n";
349  }
350
351  unlink($db_script);
352
353  my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
354  my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
355
356  my $rsa_priv_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key');
357  my $rsa_pub_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key.pub');
358
359  my $config = {
360    PidFile => $pid_file,
361    ScoreboardFile => $scoreboard_file,
362    SystemLog => $log_file,
363    TraceLog => $log_file,
364    Trace => 'DEFAULT:10 ssh2:20 sftp:20 scp:20',
365
366    AuthUserFile => $auth_user_file,
367    AuthGroupFile => $auth_group_file,
368
369    IfModules => {
370      'mod_delay.c' => {
371        DelayEngine => 'off',
372      },
373
374      'mod_sftp.c' => [
375        "SFTPEngine on",
376        "SFTPLog $log_file",
377        "SFTPHostKey $rsa_host_key",
378        "SFTPHostKey $dsa_host_key",
379      ],
380
381      'mod_sql.c' => [
382        'SQLAuthenticate off',
383        "SQLConnectInfo $db_file",
384        'SQLNamedQuery get-allowed-clients SELECT "allowed FROM ftpallow WHERE name = \'%u\'"',
385        'SQLNamedQuery get-denied-clients SELECT "denied FROM ftpdeny WHERE name = \'%u\'"',
386        "SQLLogFile $log_file",
387      ],
388
389      'mod_wrap2.c' => {
390        WrapEngine => 'on',
391        WrapLog => $log_file,
392        WrapTables => "sql:/get-allowed-clients sql:/get-denied-clients",
393        WrapDenyMsg => "User '%u' denied by access rules",
394        WrapAllowMsg => "User '%u' allowed by access rules",
395      },
396    },
397  };
398
399  my ($port, $config_user, $config_group) = config_write($config_file, $config);
400
401  # Open pipes, for use between the parent and child processes.  Specifically,
402  # the child will indicate when it's done with its test by writing a message
403  # to the parent.
404  my ($rfh, $wfh);
405  unless (pipe($rfh, $wfh)) {
406    die("Can't open pipe: $!");
407  }
408
409  require Net::SSH2;
410
411  my $ex;
412
413  # Fork child
414  $self->handle_sigchld();
415  defined(my $pid = fork()) or die("Can't fork: $!");
416  if ($pid) {
417    eval {
418      my $ssh2 = Net::SSH2->new();
419
420      sleep(1);
421
422      unless ($ssh2->connect('127.0.0.1', $port)) {
423        my ($err_code, $err_name, $err_str) = $ssh2->error();
424        die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str");
425      }
426
427      if ($ssh2->auth_publickey($user, $rsa_pub_key, $rsa_priv_key)) {
428        die("Publickey auth succeeded unexpectedly");
429      }
430
431      unless ($ssh2->auth_password($user, $passwd)) {
432        my ($err_code, $err_name, $err_str) = $ssh2->error();
433        die("Can't login to SSH2 server: [$err_name] ($err_code) $err_str");
434      }
435
436      my $sftp = $ssh2->sftp();
437      unless ($sftp) {
438        my ($err_code, $err_name, $err_str) = $ssh2->error();
439        die("Can't use SFTP on SSH2 server: [$err_name] ($err_code) $err_str");
440      }
441
442      $sftp = undef;
443      $ssh2->disconnect();
444    };
445
446    if ($@) {
447      $ex = $@;
448    }
449
450    $wfh->print("done\n");
451    $wfh->flush();
452
453  } else {
454    eval { server_wait($config_file, $rfh) };
455    if ($@) {
456      warn($@);
457      exit 1;
458    }
459
460    exit 0;
461  }
462
463  # Stop server
464  server_stop($pid_file);
465
466  $self->assert_child_ok($pid);
467
468  if ($ex) {
469    test_append_logfile($log_file, $ex);
470    unlink($log_file);
471
472    die($ex);
473  }
474
475  unlink($log_file);
476}
477
478sub sftp_wrap2_deny_msg_on_connect_bug3670 {
479  my $self = shift;
480  my $tmpdir = $self->{tmpdir};
481
482  my $config_file = "$tmpdir/sftp.conf";
483  my $pid_file = File::Spec->rel2abs("$tmpdir/sftp.pid");
484  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sftp.scoreboard");
485
486  my $log_file = test_get_logfile();
487
488  my $auth_user_file = File::Spec->rel2abs("$tmpdir/sftp.passwd");
489  my $auth_group_file = File::Spec->rel2abs("$tmpdir/sftp.group");
490
491  my $fh;
492  my $allow_file = File::Spec->rel2abs("$tmpdir/sftp.allow");
493  if (open($fh, "> $allow_file")) {
494    close($fh);
495
496  } else {
497    die("Can't open $allow_file: $!");
498  }
499
500  my $deny_file = File::Spec->rel2abs("$tmpdir/sftp.deny");
501  if (open($fh, "> $deny_file")) {
502    print $fh "ALL: ALL\n";
503
504    unless (close($fh)) {
505      die("Can't write $deny_file: $!");
506    }
507
508  } else {
509    die("Can't open $deny_file: $!");
510  }
511
512  my $user = 'proftpd';
513  my $passwd = 'test';
514  my $group = 'ftpd';
515  my $home_dir = File::Spec->rel2abs($tmpdir);
516  my $uid = 500;
517  my $gid = 500;
518
519  # Make sure that, if we're running as root, that the home directory has
520  # permissions/privs set for the account we create
521  if ($< == 0) {
522    unless (chmod(0755, $home_dir)) {
523      die("Can't set perms on $home_dir to 0755: $!");
524    }
525
526    unless (chown($uid, $gid, $home_dir)) {
527      die("Can't set owner of $home_dir to $uid/$gid: $!");
528    }
529  }
530
531  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
532    '/bin/bash');
533  auth_group_write($auth_group_file, $group, $gid, $user);
534
535  my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
536  my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
537
538  my $rsa_priv_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key');
539  my $rsa_pub_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key.pub');
540
541  my $deny_msg = '"SFTP denied by access rules"';
542
543  # Note: This test only passes correctly IFF mod_sftp is loaded BEFORE
544  # mod_wrap2, not after.  This means that mod_sftp needs to appear AFTER
545  # mod_wrap2 in the --with-modules list, or appear BEFORE mod_wrap2 in
546  # a list of LoadModule directives.
547  #
548  # mod_sftp's sess_init() callback is where the 'SSH2' protocol is set
549  # for the session.  The event listener for mod_wrap2's "disconnect this
550  # client on connect because it isn't allowed by the access rules" has
551  # a condition that checks for whether the session is an SSH2 session or
552  # not (lest it trigger improperly for an FTP session).  So if mod_wrap2's
553  # sess_init() callback triggers first, it will disconnect the session
554  # (and generate the event) before mod_sftp's sess_init() callback has had
555  # a chance to set the "SSH2" bit for the session, then mod_sftp won't
556  # properly send the WrapDenyMsg to the SSH2 client.
557
558  my $config = {
559    PidFile => $pid_file,
560    ScoreboardFile => $scoreboard_file,
561    SystemLog => $log_file,
562    TraceLog => $log_file,
563    Trace => 'DEFAULT:10 ssh2:20 sftp:20 scp:20',
564
565    AuthUserFile => $auth_user_file,
566    AuthGroupFile => $auth_group_file,
567
568    IfModules => {
569      'mod_delay.c' => {
570        DelayEngine => 'off',
571      },
572
573      'mod_sftp.c' => [
574        "SFTPEngine on",
575        "SFTPLog $log_file",
576        "SFTPHostKey $rsa_host_key",
577        "SFTPHostKey $dsa_host_key",
578        "SFTPOptions PessimisticKexinit",
579      ],
580
581      'mod_wrap2.c' => {
582        WrapEngine => 'on',
583        WrapLog => $log_file,
584        WrapTables => "file:$allow_file file:$deny_file",
585        WrapDenyMsg => $deny_msg,
586        WrapOptions => 'CheckOnConnect',
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  require Net::SSH2;
602
603  my $ex;
604
605  # Fork child
606  $self->handle_sigchld();
607  defined(my $pid = fork()) or die("Can't fork: $!");
608  if ($pid) {
609    eval {
610      sleep(1);
611
612      my $proto = getprotobyname('tcp');
613
614      my $sock;
615      unless (socket($sock, PF_INET, SOCK_STREAM, $proto)) {
616        die("Can't create socket: $!");
617      }
618
619      my $in_addr = inet_aton('127.0.0.1');
620      my $addr = sockaddr_in($port, $in_addr);
621
622      unless (connect($sock, $addr)) {
623        die("Can't connect to 127.0.0.1:$port: $!");
624      }
625
626      print $sock "SSH-2.0-MySFTPTestClient\r\n";
627
628      my $buflen = 1024;
629      my $buf = '';
630      my $tmp;
631      my $res;
632
633      while (my $res = read($sock, $tmp, $buflen)) {
634        $buf .= $tmp;
635      }
636
637      close($sock);
638
639      chomp($buf);
640      $buf =~ s/"//g;
641
642      $deny_msg =~ s/'//g;
643      $deny_msg =~ s/"//g;
644
645      $self->assert(qr/$deny_msg/, $buf,
646        test_msg("Expected response '$deny_msg', got '$buf'"));
647    };
648
649    if ($@) {
650      $ex = $@;
651    }
652
653    $wfh->print("done\n");
654    $wfh->flush();
655
656  } else {
657    eval { server_wait($config_file, $rfh) };
658    if ($@) {
659      warn($@);
660      exit 1;
661    }
662
663    exit 0;
664  }
665
666  # Stop server
667  server_stop($pid_file);
668
669  $self->assert_child_ok($pid);
670
671  if ($ex) {
672    test_append_logfile($log_file, $ex);
673    unlink($log_file);
674
675    die($ex);
676  }
677
678  unlink($log_file);
679}
680
681sub sftp_wrap2_deny_msg_on_auth_bug3670 {
682  my $self = shift;
683  my $tmpdir = $self->{tmpdir};
684
685  my $config_file = "$tmpdir/sftp.conf";
686  my $pid_file = File::Spec->rel2abs("$tmpdir/sftp.pid");
687  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sftp.scoreboard");
688
689  my $log_file = test_get_logfile();
690
691  my $auth_user_file = File::Spec->rel2abs("$tmpdir/sftp.passwd");
692  my $auth_group_file = File::Spec->rel2abs("$tmpdir/sftp.group");
693
694  my $fh;
695  my $allow_file = File::Spec->rel2abs("$tmpdir/sftp.allow");
696  if (open($fh, "> $allow_file")) {
697    close($fh);
698
699  } else {
700    die("Can't open $allow_file: $!");
701  }
702
703  my $deny_file = File::Spec->rel2abs("$tmpdir/sftp.deny");
704  if (open($fh, "> $deny_file")) {
705    print $fh "ALL: ALL\n";
706
707    unless (close($fh)) {
708      die("Can't write $deny_file: $!");
709    }
710
711  } else {
712    die("Can't open $deny_file: $!");
713  }
714
715  my $user = 'proftpd';
716  my $passwd = 'test';
717  my $group = 'ftpd';
718  my $home_dir = File::Spec->rel2abs($tmpdir);
719  my $uid = 500;
720  my $gid = 500;
721
722  # Make sure that, if we're running as root, that the home directory has
723  # permissions/privs set for the account we create
724  if ($< == 0) {
725    unless (chmod(0755, $home_dir)) {
726      die("Can't set perms on $home_dir to 0755: $!");
727    }
728
729    unless (chown($uid, $gid, $home_dir)) {
730      die("Can't set owner of $home_dir to $uid/$gid: $!");
731    }
732  }
733
734  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
735    '/bin/bash');
736  auth_group_write($auth_group_file, $group, $gid, $user);
737
738  my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
739  my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
740
741  my $rsa_priv_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key');
742  my $rsa_pub_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key.pub');
743
744  my $deny_msg = '"SFTP denied by access rules"';
745
746  my $config = {
747    PidFile => $pid_file,
748    ScoreboardFile => $scoreboard_file,
749    SystemLog => $log_file,
750    TraceLog => $log_file,
751    Trace => 'DEFAULT:10 ssh2:20 sftp:20 scp:20',
752
753    AuthUserFile => $auth_user_file,
754    AuthGroupFile => $auth_group_file,
755
756    IfModules => {
757      'mod_delay.c' => {
758        DelayEngine => 'off',
759      },
760
761      'mod_sftp.c' => [
762        "SFTPEngine on",
763        "SFTPLog $log_file",
764        "SFTPHostKey $rsa_host_key",
765        "SFTPHostKey $dsa_host_key",
766      ],
767
768      'mod_wrap2.c' => {
769        WrapEngine => 'on',
770        WrapLog => $log_file,
771        WrapTables => "file:$allow_file file:$deny_file",
772        WrapDenyMsg => $deny_msg,
773      },
774    },
775  };
776
777  my ($port, $config_user, $config_group) = config_write($config_file, $config);
778
779  # Open pipes, for use between the parent and child processes.  Specifically,
780  # the child will indicate when it's done with its test by writing a message
781  # to the parent.
782  my ($rfh, $wfh);
783  unless (pipe($rfh, $wfh)) {
784    die("Can't open pipe: $!");
785  }
786
787  require Net::SSH2;
788
789  my $ex;
790
791  # Fork child
792  $self->handle_sigchld();
793  defined(my $pid = fork()) or die("Can't fork: $!");
794  if ($pid) {
795    eval {
796      my $ssh2 = Net::SSH2->new();
797
798      sleep(1);
799
800      unless ($ssh2->connect('127.0.0.1', $port)) {
801        my ($err_code, $err_name, $err_str) = $ssh2->error();
802        die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str (see unit test notes)");
803      }
804
805      if ($ssh2->auth_password($user, $passwd)) {
806        die("Password authentication succeeded unexpectedly");
807      }
808
809      my ($err_code, $err_name, $err_str) = $ssh2->error();
810
811      $ssh2->disconnect();
812
813      # Unfortunately, the Net::SSH2::SFTP API doesn't provide the error
814      # text as sent by the SFTP server.
815    };
816
817    if ($@) {
818      $ex = $@;
819    }
820
821    $wfh->print("done\n");
822    $wfh->flush();
823
824  } else {
825    eval { server_wait($config_file, $rfh) };
826    if ($@) {
827      warn($@);
828      exit 1;
829    }
830
831    exit 0;
832  }
833
834  # Stop server
835  server_stop($pid_file);
836
837  $self->assert_child_ok($pid);
838
839  if ($ex) {
840    test_append_logfile($log_file, $ex);
841    unlink($log_file);
842
843    die($ex);
844  }
845
846  unlink($log_file);
847}
848
849sub sftp_wrap2_deny_msg_var_u {
850  my $self = shift;
851  my $tmpdir = $self->{tmpdir};
852
853  my $config_file = "$tmpdir/sftp.conf";
854  my $pid_file = File::Spec->rel2abs("$tmpdir/sftp.pid");
855  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/sftp.scoreboard");
856
857  my $log_file = test_get_logfile();
858
859  my $auth_user_file = File::Spec->rel2abs("$tmpdir/sftp.passwd");
860  my $auth_group_file = File::Spec->rel2abs("$tmpdir/sftp.group");
861
862  my $fh;
863  my $allow_file = File::Spec->rel2abs("$tmpdir/sftp.allow");
864  if (open($fh, "> $allow_file")) {
865    close($fh);
866
867  } else {
868    die("Can't open $allow_file: $!");
869  }
870
871  my $deny_file = File::Spec->rel2abs("$tmpdir/sftp.deny");
872  if (open($fh, "> $deny_file")) {
873    print $fh "ALL: ALL\n";
874
875    unless (close($fh)) {
876      die("Can't write $deny_file: $!");
877    }
878
879  } else {
880    die("Can't open $deny_file: $!");
881  }
882
883  my $user = 'proftpd';
884  my $passwd = 'test';
885  my $group = 'ftpd';
886  my $home_dir = File::Spec->rel2abs($tmpdir);
887  my $uid = 500;
888  my $gid = 500;
889
890  # Make sure that, if we're running as root, that the home directory has
891  # permissions/privs set for the account we create
892  if ($< == 0) {
893    unless (chmod(0755, $home_dir)) {
894      die("Can't set perms on $home_dir to 0755: $!");
895    }
896
897    unless (chown($uid, $gid, $home_dir)) {
898      die("Can't set owner of $home_dir to $uid/$gid: $!");
899    }
900  }
901
902  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
903    '/bin/bash');
904  auth_group_write($auth_group_file, $group, $gid, $user);
905
906  my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
907  my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
908
909  my $rsa_priv_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key');
910  my $rsa_pub_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key.pub');
911
912  my $deny_msg = '"User %u denied by access rules"';
913
914  my $config = {
915    PidFile => $pid_file,
916    ScoreboardFile => $scoreboard_file,
917    SystemLog => $log_file,
918    TraceLog => $log_file,
919    Trace => 'DEFAULT:10 ssh2:20 sftp:20 scp:20',
920
921    AuthUserFile => $auth_user_file,
922    AuthGroupFile => $auth_group_file,
923
924    IfModules => {
925      'mod_delay.c' => {
926        DelayEngine => 'off',
927      },
928
929      'mod_sftp.c' => [
930        "SFTPEngine on",
931        "SFTPLog $log_file",
932        "SFTPHostKey $rsa_host_key",
933        "SFTPHostKey $dsa_host_key",
934      ],
935
936      'mod_wrap2.c' => {
937        WrapEngine => 'on',
938        WrapLog => $log_file,
939        WrapTables => "file:$allow_file file:$deny_file",
940        WrapDenyMsg => $deny_msg,
941      },
942    },
943  };
944
945  my ($port, $config_user, $config_group) = config_write($config_file, $config);
946
947  # Open pipes, for use between the parent and child processes.  Specifically,
948  # the child will indicate when it's done with its test by writing a message
949  # to the parent.
950  my ($rfh, $wfh);
951  unless (pipe($rfh, $wfh)) {
952    die("Can't open pipe: $!");
953  }
954
955  require Net::SSH2;
956
957  my $ex;
958
959  # Fork child
960  $self->handle_sigchld();
961  defined(my $pid = fork()) or die("Can't fork: $!");
962  if ($pid) {
963    eval {
964      my $ssh2 = Net::SSH2->new();
965
966      sleep(1);
967
968      unless ($ssh2->connect('127.0.0.1', $port)) {
969        my ($err_code, $err_name, $err_str) = $ssh2->error();
970        die("Can't connect to SSH2 server: [$err_name] ($err_code) $err_str (see unit test notes)");
971      }
972
973      if ($ssh2->auth_password($user, $passwd)) {
974        die("Password authentication succeeded unexpectedly");
975      }
976
977      my ($err_code, $err_name, $err_str) = $ssh2->error();
978
979      $ssh2->disconnect();
980
981      # Unfortunately, the Net::SSH2::SFTP API doesn't provide the error
982      # text as sent by the SFTP server.
983    };
984
985    if ($@) {
986      $ex = $@;
987    }
988
989    $wfh->print("done\n");
990    $wfh->flush();
991
992  } else {
993    eval { server_wait($config_file, $rfh) };
994    if ($@) {
995      warn($@);
996      exit 1;
997    }
998
999    exit 0;
1000  }
1001
1002  # Stop server
1003  server_stop($pid_file);
1004
1005  $self->assert_child_ok($pid);
1006
1007  if ($ex) {
1008    test_append_logfile($log_file, $ex);
1009    unlink($log_file);
1010
1011    die($ex);
1012  }
1013
1014  unlink($log_file);
1015}
1016
10171;
1018