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