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