source: src/router/proftpd/tests/t/lib/ProFTPD/Tests/Modules/mod_tls_shmcache.pm @ 17880

Last change on this file since 17880 was 17880, checked in by BrainSlayer, 19 months ago

update

File size: 7.2 KB
Line 
1package ProFTPD::Tests::Modules::mod_tls_shmcache;
2
3use lib qw(t/lib);
4use base qw(ProFTPD::TestSuite::Child);
5use strict;
6
7use File::Spec;
8use IO::Handle;
9use IPC::Open3;
10
11use ProFTPD::TestSuite::FTP;
12use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
13
14$| = 1;
15
16my $order = 0;
17
18my $TESTS = {
19  tls_sess_cache_shm => {
20    order => ++$order,
21    test_class => [qw(forking)],
22  },
23
24};
25
26sub new {
27  return shift()->SUPER::new(@_);
28}
29
30sub list_tests {
31  # Check for the required Perl modules:
32  #
33  #  Net-SSLeay
34  #  IO-Socket-SSL
35  #  Net-FTPSSL
36
37  my $required = [qw(
38    Net::SSLeay
39    IO::Socket::SSL
40    Net::FTPSSL
41  )];
42
43  foreach my $req (@$required) {
44    eval "use $req";
45    if ($@) {
46      print STDERR "\nWARNING:\n + Module '$req' not found, skipping all tests\n";
47
48      if ($ENV{TEST_VERBOSE}) {
49        print STDERR "Unable to load $req: $@\n";
50      }
51
52      return qw(testsuite_empty_test);
53    }
54  }
55
56  return testsuite_get_runnable_tests($TESTS);
57}
58
59sub tls_sess_cache_shm {
60  my $self = shift;
61  my $tmpdir = $self->{tmpdir};
62
63  my $config_file = "$tmpdir/tls.conf";
64  my $pid_file = File::Spec->rel2abs("$tmpdir/tls.pid");
65  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/tls.scoreboard");
66
67  my $log_file = File::Spec->rel2abs('tests.log');
68
69  my $auth_user_file = File::Spec->rel2abs("$tmpdir/tls.passwd");
70  my $auth_group_file = File::Spec->rel2abs("$tmpdir/tls.group");
71
72  my $user = 'proftpd';
73  my $passwd = 'test';
74  my $group = 'ftpd';
75  my $home_dir = File::Spec->rel2abs($tmpdir);
76  my $uid = 500;
77  my $gid = 500;
78
79  # Make sure that, if we're running as root, that the home directory has
80  # permissions/privs set for the account we create
81  if ($< == 0) {
82    unless (chmod(0755, $home_dir)) {
83      die("Can't set perms on $home_dir to 0755: $!");
84    }
85
86    unless (chown($uid, $gid, $home_dir)) {
87      die("Can't set owner of $home_dir to $uid/$gid: $!");
88    }
89  }
90
91  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
92    '/bin/bash');
93  auth_group_write($auth_group_file, $group, $gid, $user);
94
95  my $cert_file = File::Spec->rel2abs('t/etc/modules/mod_tls/server-cert.pem');
96  my $ca_file = File::Spec->rel2abs('t/etc/modules/mod_tls/ca-cert.pem');
97
98  my $shm_path = File::Spec->rel2abs("$tmpdir/tls-shmcache");
99  my $sessid_file = File::Spec->rel2abs("$tmpdir/sessid.pem");
100
101  my $config = {
102    PidFile => $pid_file,
103    ScoreboardFile => $scoreboard_file,
104    SystemLog => $log_file,
105    TraceLog => $log_file,
106    Trace => 'tls_shmcache:20',
107
108    AuthUserFile => $auth_user_file,
109    AuthGroupFile => $auth_group_file,
110
111    IfModules => {
112      'mod_delay.c' => {
113        DelayEngine => 'off',
114      },
115
116      'mod_tls.c' => {
117        TLSEngine => 'on',
118        TLSLog => $log_file,
119        TLSProtocol => 'SSLv3 TLSv1',
120        TLSRequired => 'on',
121        TLSRSACertificateFile => $cert_file,
122        TLSCACertificateFile => $ca_file,
123        TLSVerifyClient => 'off',
124      },
125
126      'mod_tls_shmcache.c' => {
127        # 10332 is the minimum number of bytes for shmcache
128        TLSSessionCache => "shm:/file=$shm_path&size=10332",
129      },
130    },
131  };
132
133  my ($port, $config_user, $config_group) = config_write($config_file, $config);
134
135  # Open pipes, for use between the parent and child processes.  Specifically,
136  # the child will indicate when it's done with its test by writing a message
137  # to the parent.
138  my ($rfh, $wfh);
139  unless (pipe($rfh, $wfh)) {
140    die("Can't open pipe: $!");
141  }
142
143  my $ex;
144
145  # Fork child
146  $self->handle_sigchld();
147  defined(my $pid = fork()) or die("Can't fork: $!");
148  if ($pid) {
149    eval {
150      # Give the server a chance to start up
151      sleep(2);
152
153      # To test SSL session resumption, we use the command-line
154      # openssl s_client tool, rather than any Perl module.
155
156      # XXX Some OpenSSL versions' of s_client do not support the 'ftp'
157      # parameter for -starttls; in this case, point the openssl binary
158      # to be used to a version which does support this.
159      my $openssl = 'openssl';
160
161      my @cmd = (
162        $openssl,
163        's_client',
164        '-connect',
165        "127.0.0.1:$port",
166        '-starttls',
167        'ftp',
168        '-sess_out',
169        $sessid_file,
170      );
171
172      my $tls_rh = IO::Handle->new();
173      my $tls_wh = IO::Handle->new();
174      my $tls_eh = IO::Handle->new();
175
176      $tls_wh->autoflush(1);
177
178      local $SIG{CHLD} = 'DEFAULT';
179
180      if ($ENV{TEST_VERBOSE}) {
181        print STDERR "Executing: ", join(' ', @cmd), "\n";
182      }
183
184      my $tls_pid = open3($tls_wh, $tls_rh, $tls_eh, @cmd);
185      print $tls_wh "quit\n";
186      waitpid($tls_pid, 0);
187
188      my ($res, $cipher_str, $err_str, $out_str);
189      if ($? >> 8) {
190        $err_str = join('', <$tls_eh>);
191        $res = 0;
192
193      } else {
194        my $output = [<$tls_rh>];
195
196        # Specifically look for the line containing 'Cipher is'
197        foreach my $line (@$output) {
198          if ($line =~ /Cipher is/) {
199            $cipher_str = $line;
200            chomp($cipher_str);
201          }
202        }
203
204        if ($ENV{TEST_VERBOSE}) {
205          $out_str = join('', @$output);
206          print STDERR "Stdout: $out_str\n";
207        }
208
209        if ($ENV{TEST_VERBOSE}) {
210          $err_str = join('', <$tls_eh>);
211          print STDERR "Stderr: $err_str\n";
212        }
213
214        $res = 1;
215      }
216
217      unless ($res) {
218        die("Can't talk to server: $err_str");
219      }
220
221      my $expected = '^New';
222      $self->assert(qr/$expected/, $cipher_str,
223        test_msg("Expected '$expected', got '$cipher_str'"));
224
225      @cmd = (
226        $openssl,
227        's_client',
228        '-connect',
229        "127.0.0.1:$port",
230        '-starttls',
231        'ftp',
232        '-sess_in',
233        $sessid_file,
234      );
235
236      $tls_rh = IO::Handle->new();
237      $tls_wh = IO::Handle->new();
238      $tls_eh = IO::Handle->new();
239
240      $tls_wh->autoflush(1);
241
242      if ($ENV{TEST_VERBOSE}) {
243        print STDERR "Executing: ", join(' ', @cmd), "\n";
244      }
245
246      $tls_pid = open3($tls_wh, $tls_rh, $tls_eh, @cmd);
247      print $tls_wh "quit\n";
248      waitpid($tls_pid, 0);
249
250      $res = 0;
251      $cipher_str = undef;
252      $err_str = undef;
253      $out_str = undef;
254
255      if ($? >> 8) {
256        $err_str = join('', <$tls_eh>);
257        $res = 0;
258
259      } else {
260        my $output = [<$tls_rh>];
261
262        # Specifically look for the line containing 'Cipher is'
263        foreach my $line (@$output) {
264          if ($line =~ /Cipher is/) {
265            $cipher_str = $line;
266            chomp($cipher_str);
267          }
268        }
269
270        if ($ENV{TEST_VERBOSE}) {
271          $out_str = join('', @$output);
272          print STDERR "Stdout: $out_str\n";
273        }
274
275        if ($ENV{TEST_VERBOSE}) {
276          $err_str = join('', <$tls_eh>);
277          print STDERR "Stderr: $err_str\n";
278        }
279
280        $res = 1;
281      }
282
283      unless ($res) {
284        die("Can't talk to server: $err_str");
285      }
286
287      $expected = '^Reused';
288      $self->assert(qr/$expected/, $cipher_str,
289        test_msg("Expected '$expected', got '$cipher_str'"));
290    };
291
292    if ($@) {
293      $ex = $@;
294    }
295
296    $wfh->print("done\n");
297    $wfh->flush();
298
299  } else {
300    eval { server_wait($config_file, $rfh, 45) };
301    if ($@) {
302      warn($@);
303      exit 1;
304    }
305
306    exit 0;
307  }
308
309  # Stop server
310  server_stop($pid_file);
311
312  $self->assert_child_ok($pid);
313
314  if ($ex) {
315    die($ex);
316  }
317
318  unlink($log_file);
319}
320
3211;
Note: See TracBrowser for help on using the repository browser.