1package ProFTPD::Tests::Config::RewriteHome;
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  rewritehome_ok => {
19    order => ++$order,
20    test_class => [qw(forking mod_rewrite)],
21  },
22
23  rewritehome_bad_home => {
24    order => ++$order,
25    test_class => [qw(forking mod_rewrite)],
26  },
27
28  rewritehome_chroot_bug3348 => {
29    order => ++$order,
30    test_class => [qw(bug forking mod_rewrite rootprivs)],
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 rewritehome_ok {
44  my $self = shift;
45  my $tmpdir = $self->{tmpdir};
46
47  my $config_file = "$tmpdir/config.conf";
48  my $pid_file = File::Spec->rel2abs("$tmpdir/config.pid");
49  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/config.scoreboard");
50
51  my $log_file = File::Spec->rel2abs('tests.log');
52
53  my $auth_user_file = File::Spec->rel2abs("$tmpdir/config.passwd");
54  my $auth_group_file = File::Spec->rel2abs("$tmpdir/config.group");
55
56  my $user = 'proftpd';
57  my $passwd = 'test';
58  my $group = 'ftpd';
59  my $home_dir = File::Spec->rel2abs($tmpdir);
60  my $uid = 500;
61  my $gid = 500;
62
63  # Make sure that, if we're running as root, that the home directory has
64  # permissions/privs set for the account we create
65  if ($< == 0) {
66    unless (chmod(0755, $home_dir)) {
67      die("Can't set perms on $home_dir to 0755: $!");
68    }
69
70    unless (chown($uid, $gid, $home_dir)) {
71      die("Can't set owner of $home_dir to $uid/$gid: $!");
72    }
73  }
74
75  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, '/foo/bar/baz',
76    '/bin/bash');
77  auth_group_write($auth_group_file, $group, $gid, $user);
78
79  my $config = {
80    PidFile => $pid_file,
81    ScoreboardFile => $scoreboard_file,
82    SystemLog => $log_file,
83
84    AuthUserFile => $auth_user_file,
85    AuthGroupFile => $auth_group_file,
86
87    IfModules => {
88      'mod_delay.c' => {
89        DelayEngine => 'off',
90      },
91
92      'mod_rewrite.c' => [
93        'RewriteHome on',
94        'RewriteEngine on',
95        "RewriteLog $log_file",
96        'RewriteCondition %m REWRITE_HOME',
97        "RewriteRule ^(.*) $home_dir",
98      ],
99    },
100  };
101
102  my ($port, $config_user, $config_group) = config_write($config_file, $config);
103
104  # Open pipes, for use between the parent and child processes.  Specifically,
105  # the child will indicate when it's done with its test by writing a message
106  # to the parent.
107  my ($rfh, $wfh);
108  unless (pipe($rfh, $wfh)) {
109    die("Can't open pipe: $!");
110  }
111
112  my $ex;
113
114  # Fork child
115  $self->handle_sigchld();
116  defined(my $pid = fork()) or die("Can't fork: $!");
117  if ($pid) {
118    eval {
119      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
120      $client->login($user, $passwd);
121
122      my ($resp_code, $resp_msg) = $client->pwd();
123
124      my $expected;
125
126      $expected = 257;
127      $self->assert($expected == $resp_code,
128        test_msg("Expected $expected, got $resp_code"));
129
130      $expected = "\"$home_dir\" is the current directory";
131      $self->assert($expected eq $resp_msg,
132        test_msg("Expected '$expected', got '$resp_msg'"));
133    };
134
135    if ($@) {
136      $ex = $@;
137    }
138
139    $wfh->print("done\n");
140    $wfh->flush();
141
142  } else {
143    eval { server_wait($config_file, $rfh) };
144    if ($@) {
145      warn($@);
146      exit 1;
147    }
148
149    exit 0;
150  }
151
152  # Stop server
153  server_stop($pid_file);
154
155  $self->assert_child_ok($pid);
156
157  if ($ex) {
158    die($ex);
159  }
160
161  unlink($log_file);
162}
163
164sub rewritehome_bad_home {
165  my $self = shift;
166  my $tmpdir = $self->{tmpdir};
167
168  my $config_file = "$tmpdir/config.conf";
169  my $pid_file = File::Spec->rel2abs("$tmpdir/config.pid");
170  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/config.scoreboard");
171
172  my $log_file = File::Spec->rel2abs('tests.log');
173
174  my $auth_user_file = File::Spec->rel2abs("$tmpdir/config.passwd");
175  my $auth_group_file = File::Spec->rel2abs("$tmpdir/config.group");
176
177  my $user = 'proftpd';
178  my $passwd = 'test';
179  my $group = 'ftpd';
180  my $home_dir = File::Spec->rel2abs($tmpdir);
181  my $uid = 500;
182  my $gid = 500;
183
184  # Make sure that, if we're running as root, that the home directory has
185  # permissions/privs set for the account we create
186  if ($< == 0) {
187    unless (chmod(0755, $home_dir)) {
188      die("Can't set perms on $home_dir to 0755: $!");
189    }
190
191    unless (chown($uid, $gid, $home_dir)) {
192      die("Can't set owner of $home_dir to $uid/$gid: $!");
193    }
194  }
195
196  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
197    '/bin/bash');
198  auth_group_write($auth_group_file, $group, $gid, $user);
199
200  my $config = {
201    PidFile => $pid_file,
202    ScoreboardFile => $scoreboard_file,
203    SystemLog => $log_file,
204
205    AuthUserFile => $auth_user_file,
206    AuthGroupFile => $auth_group_file,
207
208    IfModules => {
209      'mod_delay.c' => {
210        DelayEngine => 'off',
211      },
212
213      'mod_rewrite.c' => [
214        'RewriteHome on',
215        'RewriteEngine on',
216        "RewriteLog $log_file",
217        'RewriteCondition %m REWRITE_HOME',
218        'RewriteRule ^(.*) /foo/bar/baz/quxx/quzz/alef/bet',
219      ],
220    },
221  };
222
223  my ($port, $config_user, $config_group) = config_write($config_file, $config);
224
225  # Open pipes, for use between the parent and child processes.  Specifically,
226  # the child will indicate when it's done with its test by writing a message
227  # to the parent.
228  my ($rfh, $wfh);
229  unless (pipe($rfh, $wfh)) {
230    die("Can't open pipe: $!");
231  }
232
233  my $ex;
234
235  # Fork child
236  $self->handle_sigchld();
237  defined(my $pid = fork()) or die("Can't fork: $!");
238  if ($pid) {
239    eval {
240      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
241
242      # Because we rewrote the home directory to one that doesn't exist,
243      # the login should not succeed.
244      eval { $client->login($user, $passwd) };
245      unless ($@) {
246        die("Login succeeded expectedly");
247      }
248    };
249
250    if ($@) {
251      $ex = $@;
252    }
253
254    $wfh->print("done\n");
255    $wfh->flush();
256
257  } else {
258    eval { server_wait($config_file, $rfh) };
259    if ($@) {
260      warn($@);
261      exit 1;
262    }
263
264    exit 0;
265  }
266
267  # Stop server
268  server_stop($pid_file);
269
270  $self->assert_child_ok($pid);
271
272  if ($ex) {
273    die($ex);
274  }
275
276  unlink($log_file);
277}
278
279sub rewritehome_chroot_bug3348 {
280  my $self = shift;
281  my $tmpdir = $self->{tmpdir};
282
283  my $config_file = "$tmpdir/config.conf";
284  my $pid_file = File::Spec->rel2abs("$tmpdir/config.pid");
285  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/config.scoreboard");
286
287  my $log_file = File::Spec->rel2abs('tests.log');
288
289  my $auth_user_file = File::Spec->rel2abs("$tmpdir/config.passwd");
290  my $auth_group_file = File::Spec->rel2abs("$tmpdir/config.group");
291
292  my $user = 'proftpd';
293  my $passwd = 'test';
294  my $group = 'ftpd';
295  my $home_dir = File::Spec->rel2abs($tmpdir);
296  my $uid = 500;
297  my $gid = 500;
298
299  # Make sure that, if we're running as root, that the home directory has
300  # permissions/privs set for the account we create
301  if ($< == 0) {
302    unless (chmod(0755, $home_dir)) {
303      die("Can't set perms on $home_dir to 0755: $!");
304    }
305
306    unless (chown($uid, $gid, $home_dir)) {
307      die("Can't set owner of $home_dir to $uid/$gid: $!");
308    }
309  }
310
311  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, '/foo/bar/baz',
312    '/bin/bash');
313  auth_group_write($auth_group_file, $group, $gid, $user);
314
315  my $config = {
316    PidFile => $pid_file,
317    ScoreboardFile => $scoreboard_file,
318    SystemLog => $log_file,
319
320    AuthUserFile => $auth_user_file,
321    AuthGroupFile => $auth_group_file,
322    DefaultRoot => '~/',
323
324    IfModules => {
325      'mod_delay.c' => {
326        DelayEngine => 'off',
327      },
328
329      'mod_rewrite.c' => [
330        'RewriteHome on',
331        'RewriteEngine on',
332        "RewriteLog $log_file",
333        'RewriteCondition %m REWRITE_HOME',
334        "RewriteRule ^(.*) $home_dir",
335      ],
336    },
337  };
338
339  my ($port, $config_user, $config_group) = config_write($config_file, $config);
340
341  # Open pipes, for use between the parent and child processes.  Specifically,
342  # the child will indicate when it's done with its test by writing a message
343  # to the parent.
344  my ($rfh, $wfh);
345  unless (pipe($rfh, $wfh)) {
346    die("Can't open pipe: $!");
347  }
348
349  my $ex;
350
351  # Fork child
352  $self->handle_sigchld();
353  defined(my $pid = fork()) or die("Can't fork: $!");
354  if ($pid) {
355    eval {
356      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
357      $client->login($user, $passwd);
358
359      my ($resp_code, $resp_msg) = $client->pwd();
360
361      my $expected;
362
363      $expected = 257;
364      $self->assert($expected == $resp_code,
365        test_msg("Expected $expected, got $resp_code"));
366
367      $expected = "\"/\" is the current directory";
368      $self->assert($expected eq $resp_msg,
369        test_msg("Expected '$expected', got '$resp_msg'"));
370    };
371
372    if ($@) {
373      $ex = $@;
374    }
375
376    $wfh->print("done\n");
377    $wfh->flush();
378
379  } else {
380    eval { server_wait($config_file, $rfh) };
381    if ($@) {
382      warn($@);
383      exit 1;
384    }
385
386    exit 0;
387  }
388
389  # Stop server
390  server_stop($pid_file);
391
392  $self->assert_child_ok($pid);
393
394  if ($ex) {
395    die($ex);
396  }
397
398  unlink($log_file);
399}
400
4011;
402