1package ProFTPD::Tests::Config::RLimitOpenFiles;
2
3use lib qw(t/lib);
4use base qw(ProFTPD::TestSuite::Child);
5use strict;
6
7use File::Spec;
8use IO::Handle;
9
10use ProFTPD::TestSuite::FTP;
11use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
12
13$| = 1;
14
15my $order = 0;
16
17my $TESTS = {
18  rlimitopenfiles_max => {
19    order => ++$order,
20    test_class => [qw(forking)],
21  },
22
23  rlimitopenfiles_session_max => {
24    order => ++$order,
25    test_class => [qw(forking)],
26  },
27
28  rlimitopenfiles_session_min => {
29    order => ++$order,
30    test_class => [qw(forking)],
31  },
32
33  rlimitopenfiles_daemon_max => {
34    order => ++$order,
35    test_class => [qw(bug forking)],
36  },
37
38  rlimitopenfiles_daemon_min => {
39    order => ++$order,
40    test_class => [qw(bug forking)],
41  },
42
43};
44
45sub new {
46  return shift()->SUPER::new(@_);
47}
48
49sub list_tests {
50  return testsuite_get_runnable_tests($TESTS);
51}
52
53sub rlimitopenfiles_max {
54  my $self = shift;
55  my $tmpdir = $self->{tmpdir};
56
57  my $config_file = "$tmpdir/config.conf";
58  my $pid_file = File::Spec->rel2abs("$tmpdir/config.pid");
59  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/config.scoreboard");
60
61  my $log_file = test_get_logfile();
62
63  my $auth_user_file = File::Spec->rel2abs("$tmpdir/config.passwd");
64  my $auth_group_file = File::Spec->rel2abs("$tmpdir/config.group");
65
66  my $user = 'proftpd';
67  my $passwd = 'test';
68  my $group = 'ftpd';
69  my $home_dir = File::Spec->rel2abs($tmpdir);
70  my $uid = 500;
71  my $gid = 500;
72
73  # Make sure that, if we're running as root, that the home directory has
74  # permissions/privs set for the account we create
75  if ($< == 0) {
76    unless (chmod(0755, $home_dir)) {
77      die("Can't set perms on $home_dir to 0755: $!");
78    }
79
80    unless (chown($uid, $gid, $home_dir)) {
81      die("Can't set owner of $home_dir to $uid/$gid: $!");
82    }
83  }
84
85  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
86    '/bin/bash');
87  auth_group_write($auth_group_file, $group, $gid, $user);
88
89  my $config = {
90    PidFile => $pid_file,
91    ScoreboardFile => $scoreboard_file,
92    SystemLog => $log_file,
93
94    AuthUserFile => $auth_user_file,
95    AuthGroupFile => $auth_group_file,
96
97    RLimitOpenFiles => 'max',
98
99    IfModules => {
100      'mod_delay.c' => {
101        DelayEngine => 'off',
102      },
103    },
104  };
105
106  my ($port, $config_user, $config_group) = config_write($config_file, $config);
107
108  # Open pipes, for use between the parent and child processes.  Specifically,
109  # the child will indicate when it's done with its test by writing a message
110  # to the parent.
111  my ($rfh, $wfh);
112  unless (pipe($rfh, $wfh)) {
113    die("Can't open pipe: $!");
114  }
115
116  my $ex;
117
118  # Fork child
119  $self->handle_sigchld();
120  defined(my $pid = fork()) or die("Can't fork: $!");
121  if ($pid) {
122    eval {
123      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
124      $client->login($user, $passwd);
125      $client->quit();
126    };
127
128    if ($@) {
129      $ex = $@;
130    }
131
132    $wfh->print("done\n");
133    $wfh->flush();
134
135  } else {
136    eval { server_wait($config_file, $rfh) };
137    if ($@) {
138      warn($@);
139      exit 1;
140    }
141
142    exit 0;
143  }
144
145  # Stop server
146  server_stop($pid_file);
147
148  $self->assert_child_ok($pid);
149
150  if ($ex) {
151    test_append_logfile($log_file, $ex);
152    unlink($log_file);
153
154    die($ex);
155  }
156
157  unlink($log_file);
158}
159
160sub rlimitopenfiles_session_max {
161  my $self = shift;
162  my $tmpdir = $self->{tmpdir};
163
164  my $config_file = "$tmpdir/config.conf";
165  my $pid_file = File::Spec->rel2abs("$tmpdir/config.pid");
166  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/config.scoreboard");
167
168  my $log_file = test_get_logfile();
169
170  my $auth_user_file = File::Spec->rel2abs("$tmpdir/config.passwd");
171  my $auth_group_file = File::Spec->rel2abs("$tmpdir/config.group");
172
173  my $user = 'proftpd';
174  my $passwd = 'test';
175  my $group = 'ftpd';
176  my $home_dir = File::Spec->rel2abs($tmpdir);
177  my $uid = 500;
178  my $gid = 500;
179
180  # Make sure that, if we're running as root, that the home directory has
181  # permissions/privs set for the account we create
182  if ($< == 0) {
183    unless (chmod(0755, $home_dir)) {
184      die("Can't set perms on $home_dir to 0755: $!");
185    }
186
187    unless (chown($uid, $gid, $home_dir)) {
188      die("Can't set owner of $home_dir to $uid/$gid: $!");
189    }
190  }
191
192  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
193    '/bin/bash');
194  auth_group_write($auth_group_file, $group, $gid, $user);
195
196  my $config = {
197    PidFile => $pid_file,
198    ScoreboardFile => $scoreboard_file,
199    SystemLog => $log_file,
200
201    AuthUserFile => $auth_user_file,
202    AuthGroupFile => $auth_group_file,
203
204    RLimitOpenFiles => 'session max',
205
206    IfModules => {
207      'mod_delay.c' => {
208        DelayEngine => 'off',
209      },
210    },
211  };
212
213  my ($port, $config_user, $config_group) = config_write($config_file, $config);
214
215  # Open pipes, for use between the parent and child processes.  Specifically,
216  # the child will indicate when it's done with its test by writing a message
217  # to the parent.
218  my ($rfh, $wfh);
219  unless (pipe($rfh, $wfh)) {
220    die("Can't open pipe: $!");
221  }
222
223  my $ex;
224
225  # Fork child
226  $self->handle_sigchld();
227  defined(my $pid = fork()) or die("Can't fork: $!");
228  if ($pid) {
229    eval {
230      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
231      $client->login($user, $passwd);
232      $client->quit();
233    };
234
235    if ($@) {
236      $ex = $@;
237    }
238
239    $wfh->print("done\n");
240    $wfh->flush();
241
242  } else {
243    eval { server_wait($config_file, $rfh) };
244    if ($@) {
245      warn($@);
246      exit 1;
247    }
248
249    exit 0;
250  }
251
252  # Stop server
253  server_stop($pid_file);
254
255  $self->assert_child_ok($pid);
256
257  if ($ex) {
258    test_append_logfile($log_file, $ex);
259    unlink($log_file);
260
261    die($ex);
262  }
263
264  unlink($log_file);
265}
266
267sub rlimitopenfiles_session_min {
268  my $self = shift;
269  my $tmpdir = $self->{tmpdir};
270
271  my $config_file = "$tmpdir/config.conf";
272  my $pid_file = File::Spec->rel2abs("$tmpdir/config.pid");
273  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/config.scoreboard");
274
275  my $log_file = test_get_logfile();
276
277  my $auth_user_file = File::Spec->rel2abs("$tmpdir/config.passwd");
278  my $auth_group_file = File::Spec->rel2abs("$tmpdir/config.group");
279
280  my $user = 'proftpd';
281  my $passwd = 'test';
282  my $group = 'ftpd';
283  my $home_dir = File::Spec->rel2abs($tmpdir);
284  my $uid = 500;
285  my $gid = 500;
286
287  # Make sure that, if we're running as root, that the home directory has
288  # permissions/privs set for the account we create
289  if ($< == 0) {
290    unless (chmod(0755, $home_dir)) {
291      die("Can't set perms on $home_dir to 0755: $!");
292    }
293
294    unless (chown($uid, $gid, $home_dir)) {
295      die("Can't set owner of $home_dir to $uid/$gid: $!");
296    }
297  }
298
299  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
300    '/bin/bash');
301  auth_group_write($auth_group_file, $group, $gid, $user);
302
303  my $config = {
304    PidFile => $pid_file,
305    ScoreboardFile => $scoreboard_file,
306    SystemLog => $log_file,
307
308    AuthUserFile => $auth_user_file,
309    AuthGroupFile => $auth_group_file,
310
311    RLimitOpenFiles => 'session 6',
312
313    IfModules => {
314      'mod_delay.c' => {
315        DelayEngine => 'off',
316      },
317    },
318  };
319
320  my ($port, $config_user, $config_group) = config_write($config_file, $config);
321
322  # Open pipes, for use between the parent and child processes.  Specifically,
323  # the child will indicate when it's done with its test by writing a message
324  # to the parent.
325  my ($rfh, $wfh);
326  unless (pipe($rfh, $wfh)) {
327    die("Can't open pipe: $!");
328  }
329
330  my $ex;
331
332  # Fork child
333  $self->handle_sigchld();
334  defined(my $pid = fork()) or die("Can't fork: $!");
335  if ($pid) {
336    eval {
337      # We allotted enough fds to allow client to connect, but NOT to login
338      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
339      eval { $client->login($user, $passwd) };
340      unless ($@) {
341        die("Login succeeded unexpectedly");
342      }
343
344      $client->quit();
345    };
346
347    if ($@) {
348      $ex = $@;
349    }
350
351    $wfh->print("done\n");
352    $wfh->flush();
353
354  } else {
355    eval { server_wait($config_file, $rfh) };
356    if ($@) {
357      warn($@);
358      exit 1;
359    }
360
361    exit 0;
362  }
363
364  # Stop server
365  server_stop($pid_file);
366
367  $self->assert_child_ok($pid);
368
369  if ($ex) {
370    test_append_logfile($log_file, $ex);
371    unlink($log_file);
372
373    die($ex);
374  }
375
376  unlink($log_file);
377}
378
379sub rlimitopenfiles_daemon_max {
380  my $self = shift;
381  my $tmpdir = $self->{tmpdir};
382
383  my $config_file = "$tmpdir/config.conf";
384  my $pid_file = File::Spec->rel2abs("$tmpdir/config.pid");
385  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/config.scoreboard");
386
387  my $log_file = test_get_logfile();
388
389  my $auth_user_file = File::Spec->rel2abs("$tmpdir/config.passwd");
390  my $auth_group_file = File::Spec->rel2abs("$tmpdir/config.group");
391
392  my $user = 'proftpd';
393  my $passwd = 'test';
394  my $group = 'ftpd';
395  my $home_dir = File::Spec->rel2abs($tmpdir);
396  my $uid = 500;
397  my $gid = 500;
398
399  # Make sure that, if we're running as root, that the home directory has
400  # permissions/privs set for the account we create
401  if ($< == 0) {
402    unless (chmod(0755, $home_dir)) {
403      die("Can't set perms on $home_dir to 0755: $!");
404    }
405
406    unless (chown($uid, $gid, $home_dir)) {
407      die("Can't set owner of $home_dir to $uid/$gid: $!");
408    }
409  }
410
411  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
412    '/bin/bash');
413  auth_group_write($auth_group_file, $group, $gid, $user);
414
415  my $config = {
416    PidFile => $pid_file,
417    ScoreboardFile => $scoreboard_file,
418    SystemLog => $log_file,
419
420    AuthUserFile => $auth_user_file,
421    AuthGroupFile => $auth_group_file,
422
423    RLimitOpenFiles => 'daemon max',
424
425    IfModules => {
426      'mod_delay.c' => {
427        DelayEngine => 'off',
428      },
429    },
430  };
431
432  my ($port, $config_user, $config_group) = config_write($config_file, $config);
433
434  # Open pipes, for use between the parent and child processes.  Specifically,
435  # the child will indicate when it's done with its test by writing a message
436  # to the parent.
437  my ($rfh, $wfh);
438  unless (pipe($rfh, $wfh)) {
439    die("Can't open pipe: $!");
440  }
441
442  my $ex;
443
444  # Fork child
445  $self->handle_sigchld();
446  defined(my $pid = fork()) or die("Can't fork: $!");
447  if ($pid) {
448    eval {
449      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
450      $client->login($user, $passwd);
451      $client->quit();
452    };
453
454    if ($@) {
455      $ex = $@;
456    }
457
458    $wfh->print("done\n");
459    $wfh->flush();
460
461  } else {
462    eval { server_wait($config_file, $rfh) };
463    if ($@) {
464      warn($@);
465      exit 1;
466    }
467
468    exit 0;
469  }
470
471  # Stop server
472  server_stop($pid_file);
473
474  $self->assert_child_ok($pid);
475
476  if ($ex) {
477    test_append_logfile($log_file, $ex);
478    unlink($log_file);
479
480    die($ex);
481  }
482
483  unlink($log_file);
484}
485
486sub rlimitopenfiles_daemon_min {
487  my $self = shift;
488  my $tmpdir = $self->{tmpdir};
489
490  my $config_file = "$tmpdir/config.conf";
491  my $pid_file = File::Spec->rel2abs("$tmpdir/config.pid");
492  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/config.scoreboard");
493
494  my $log_file = test_get_logfile();
495
496  my $auth_user_file = File::Spec->rel2abs("$tmpdir/config.passwd");
497  my $auth_group_file = File::Spec->rel2abs("$tmpdir/config.group");
498
499  my $user = 'proftpd';
500  my $passwd = 'test';
501  my $group = 'ftpd';
502  my $home_dir = File::Spec->rel2abs($tmpdir);
503  my $uid = 500;
504  my $gid = 500;
505
506  # Make sure that, if we're running as root, that the home directory has
507  # permissions/privs set for the account we create
508  if ($< == 0) {
509    unless (chmod(0755, $home_dir)) {
510      die("Can't set perms on $home_dir to 0755: $!");
511    }
512
513    unless (chown($uid, $gid, $home_dir)) {
514      die("Can't set owner of $home_dir to $uid/$gid: $!");
515    }
516  }
517
518  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
519    '/bin/bash');
520  auth_group_write($auth_group_file, $group, $gid, $user);
521
522  my $config = {
523    PidFile => $pid_file,
524    ScoreboardFile => $scoreboard_file,
525    SystemLog => $log_file,
526
527    AuthUserFile => $auth_user_file,
528    AuthGroupFile => $auth_group_file,
529
530    RLimitOpenFiles => 'daemon 3',
531
532    IfModules => {
533      'mod_delay.c' => {
534        DelayEngine => 'off',
535      },
536    },
537  };
538
539  my ($port, $config_user, $config_group) = config_write($config_file, $config);
540
541  # Open pipes, for use between the parent and child processes.  Specifically,
542  # the child will indicate when it's done with its test by writing a message
543  # to the parent.
544  my ($rfh, $wfh);
545  unless (pipe($rfh, $wfh)) {
546    die("Can't open pipe: $!");
547  }
548
549  my $ex;
550
551  # Fork child
552  $self->handle_sigchld();
553  defined(my $pid = fork()) or die("Can't fork: $!");
554  if ($pid) {
555    eval {
556      # We allowed just enough fds for the server to start up, but not
557      # much else.
558      eval { ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1) };
559      unless ($@) {
560        die("Connecting to server succeeded unexpectedly");
561      }
562    };
563
564    if ($@) {
565      $ex = $@;
566    }
567
568    $wfh->print("done\n");
569    $wfh->flush();
570
571  } else {
572    eval { server_wait($config_file, $rfh) };
573    if ($@) {
574      warn($@);
575      exit 1;
576    }
577
578    exit 0;
579  }
580
581  # Stop server
582  server_stop($pid_file);
583
584  $self->assert_child_ok($pid);
585
586  if ($ex) {
587    test_append_logfile($log_file, $ex);
588    unlink($log_file);
589
590    die($ex);
591  }
592
593#  unlink($log_file);
594}
595
5961;
597