1package ProFTPD::Tests::Config::RLimitCPU;
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  rlimitcpu_max => {
19    order => ++$order,
20    test_class => [qw(forking)],
21  },
22
23  rlimitcpu_session_max => {
24    order => ++$order,
25    test_class => [qw(forking)],
26  },
27
28  rlimitcpu_session_min => {
29    order => ++$order,
30    test_class => [qw(forking)],
31  },
32
33  rlimitcpu_daemon_max => {
34    order => ++$order,
35    test_class => [qw(forking)],
36  },
37
38  rlimitcpu_daemon_min => {
39    order => ++$order,
40    test_class => [qw(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 rlimitcpu_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    RLimitCPU => '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 rlimitcpu_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    RLimitCPU => '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 rlimitcpu_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    RLimitCPU => 'session 0',
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      eval { ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 0, 1) };
338      unless ($@) {
339        die("Connecting to server succeeded unexpectedly");
340      }
341    };
342
343    if ($@) {
344      $ex = $@;
345    }
346
347    $wfh->print("done\n");
348    $wfh->flush();
349
350  } else {
351    eval { server_wait($config_file, $rfh) };
352    if ($@) {
353      warn($@);
354      exit 1;
355    }
356
357    exit 0;
358  }
359
360  if ($ex) {
361    test_append_logfile($log_file, $ex);
362    unlink($log_file);
363
364    die($ex);
365  }
366
367  unlink($log_file);
368}
369
370sub rlimitcpu_daemon_max {
371  my $self = shift;
372  my $tmpdir = $self->{tmpdir};
373
374  my $config_file = "$tmpdir/config.conf";
375  my $pid_file = File::Spec->rel2abs("$tmpdir/config.pid");
376  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/config.scoreboard");
377
378  my $log_file = test_get_logfile();
379
380  my $auth_user_file = File::Spec->rel2abs("$tmpdir/config.passwd");
381  my $auth_group_file = File::Spec->rel2abs("$tmpdir/config.group");
382
383  my $user = 'proftpd';
384  my $passwd = 'test';
385  my $group = 'ftpd';
386  my $home_dir = File::Spec->rel2abs($tmpdir);
387  my $uid = 500;
388  my $gid = 500;
389
390  # Make sure that, if we're running as root, that the home directory has
391  # permissions/privs set for the account we create
392  if ($< == 0) {
393    unless (chmod(0755, $home_dir)) {
394      die("Can't set perms on $home_dir to 0755: $!");
395    }
396
397    unless (chown($uid, $gid, $home_dir)) {
398      die("Can't set owner of $home_dir to $uid/$gid: $!");
399    }
400  }
401
402  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
403    '/bin/bash');
404  auth_group_write($auth_group_file, $group, $gid, $user);
405
406  my $config = {
407    PidFile => $pid_file,
408    ScoreboardFile => $scoreboard_file,
409    SystemLog => $log_file,
410
411    AuthUserFile => $auth_user_file,
412    AuthGroupFile => $auth_group_file,
413
414    RLimitCPU => 'daemon max',
415
416    IfModules => {
417      'mod_delay.c' => {
418        DelayEngine => 'off',
419      },
420    },
421  };
422
423  my ($port, $config_user, $config_group) = config_write($config_file, $config);
424
425  # Open pipes, for use between the parent and child processes.  Specifically,
426  # the child will indicate when it's done with its test by writing a message
427  # to the parent.
428  my ($rfh, $wfh);
429  unless (pipe($rfh, $wfh)) {
430    die("Can't open pipe: $!");
431  }
432
433  my $ex;
434
435  # Fork child
436  $self->handle_sigchld();
437  defined(my $pid = fork()) or die("Can't fork: $!");
438  if ($pid) {
439    eval {
440      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
441      $client->login($user, $passwd);
442      $client->quit();
443    };
444
445    if ($@) {
446      $ex = $@;
447    }
448
449    $wfh->print("done\n");
450    $wfh->flush();
451
452  } else {
453    eval { server_wait($config_file, $rfh) };
454    if ($@) {
455      warn($@);
456      exit 1;
457    }
458
459    exit 0;
460  }
461
462  # Stop server
463  server_stop($pid_file);
464
465  $self->assert_child_ok($pid);
466
467  if ($ex) {
468    test_append_logfile($log_file, $ex);
469    unlink($log_file);
470
471    die($ex);
472  }
473
474  unlink($log_file);
475}
476
477sub rlimitcpu_daemon_min {
478  my $self = shift;
479  my $tmpdir = $self->{tmpdir};
480
481  my $config_file = "$tmpdir/config.conf";
482  my $pid_file = File::Spec->rel2abs("$tmpdir/config.pid");
483  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/config.scoreboard");
484
485  my $log_file = test_get_logfile();
486
487  my $auth_user_file = File::Spec->rel2abs("$tmpdir/config.passwd");
488  my $auth_group_file = File::Spec->rel2abs("$tmpdir/config.group");
489
490  my $user = 'proftpd';
491  my $passwd = 'test';
492  my $group = 'ftpd';
493  my $home_dir = File::Spec->rel2abs($tmpdir);
494  my $uid = 500;
495  my $gid = 500;
496
497  # Make sure that, if we're running as root, that the home directory has
498  # permissions/privs set for the account we create
499  if ($< == 0) {
500    unless (chmod(0755, $home_dir)) {
501      die("Can't set perms on $home_dir to 0755: $!");
502    }
503
504    unless (chown($uid, $gid, $home_dir)) {
505      die("Can't set owner of $home_dir to $uid/$gid: $!");
506    }
507  }
508
509  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
510    '/bin/bash');
511  auth_group_write($auth_group_file, $group, $gid, $user);
512
513  my $config = {
514    PidFile => $pid_file,
515    ScoreboardFile => $scoreboard_file,
516    SystemLog => $log_file,
517
518    AuthUserFile => $auth_user_file,
519    AuthGroupFile => $auth_group_file,
520
521    RLimitCPU => 'daemon 0',
522
523    IfModules => {
524      'mod_delay.c' => {
525        DelayEngine => 'off',
526      },
527    },
528  };
529
530  my ($port, $config_user, $config_group) = config_write($config_file, $config);
531
532  my $ex;
533
534  eval { server_start($config_file, $pid_file) };
535  unless ($@) {
536    # Stop server
537    server_stop($pid_file);
538
539    $ex = "Server started up successfully unexpectedly";
540  }
541
542  if ($ex) {
543    test_append_logfile($log_file, $ex);
544    unlink($log_file);
545
546    die($ex);
547  }
548
549  unlink($log_file);
550}
551
5521;
553