source: src/router/proftpd/tests/t/lib/ProFTPD/Tests/Modules/mod_site_misc.pm @ 14672

Last change on this file since 14672 was 14672, checked in by BrainSlayer, 3 years ago

proftp update

File size: 23.4 KB
Line 
1package ProFTPD::Tests::Modules::mod_site_misc;
2
3use lib qw(t/lib);
4use base qw(Test::Unit::TestCase ProFTPD::TestSuite::Child);
5use strict;
6
7use File::Path qw(mkpath rmtree);
8use File::Spec;
9use IO::Handle;
10
11use ProFTPD::TestSuite::FTP;
12use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
13
14$| = 1;
15
16my $order = 0;
17
18my $TESTS = {
19  site_misc_mkdir_ok => {
20    order => ++$order,
21    test_class => [qw(forking)],
22  },
23
24  site_misc_rmdir_ok => {
25    order => ++$order,
26    test_class => [qw(forking)],
27  },
28
29  site_misc_symlink_ok => {
30    order => ++$order,
31    test_class => [qw(forking)],
32  },
33
34  site_misc_utime_ok => {
35    order => ++$order,
36    test_class => [qw(forking)],
37  },
38
39  site_misc_utime_with_sec_ok => {
40    order => ++$order,
41    test_class => [qw(forking)],
42  },
43
44  site_feat_ok => {
45    order => ++$order,
46    test_class => [qw(forking)],
47  },
48
49  # This tests the scenario to which NcFTPd was vulnerable
50  #
51  #  http://www.doecirc.energy.gov/bulletins/t-195.shtml
52  site_misc_symlink_ncftpd_chroot_bug => {
53    order => ++$order,
54    test_class => [qw(forking rootprivs)],
55  },
56
57};
58
59sub new {
60  return shift()->SUPER::new(@_);
61}
62
63sub list_tests {
64  return testsuite_get_runnable_tests($TESTS);
65}
66
67sub set_up {
68  my $self = shift;
69  $self->{tmpdir} = testsuite_get_tmp_dir();
70
71  # Create temporary scratch dir
72  eval { mkpath($self->{tmpdir}) };
73  if ($@) {
74    my $abs_path = File::Spec->rel2abs($self->{tmpdir});
75    die("Can't create dir $abs_path: $@");
76  }
77}
78
79sub tear_down {
80  my $self = shift;
81
82  # Remove temporary scratch dir
83  if ($self->{tmpdir}) {
84    eval { rmtree($self->{tmpdir}) };
85  }
86
87  undef $self;
88}
89
90sub site_misc_mkdir_ok {
91  my $self = shift;
92  my $tmpdir = $self->{tmpdir};
93
94  my $config_file = "$tmpdir/site.conf";
95  my $pid_file = File::Spec->rel2abs("$tmpdir/site.pid");
96  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/site.scoreboard");
97
98  my $log_file = File::Spec->rel2abs('tests.log');
99
100  my $auth_user_file = File::Spec->rel2abs("$tmpdir/site.passwd");
101  my $auth_group_file = File::Spec->rel2abs("$tmpdir/site.group");
102
103  my $user = 'proftpd';
104  my $passwd = 'test';
105  my $home_dir = File::Spec->rel2abs($tmpdir);
106  my $uid = 500;
107  my $gid = 500;
108
109  my $test_dir = File::Spec->rel2abs("$tmpdir/foo/bar/baz");
110
111  # Make sure that, if we're running as root, that the home directory has
112  # permissions/privs set for the account we create
113  if ($< == 0) {
114    unless (chmod(0755, $home_dir)) {
115      die("Can't set perms on $home_dir to 0755: $!");
116    }
117
118    unless (chown($uid, $gid, $home_dir)) {
119      die("Can't set owner of $home_dir to $uid/$gid: $!");
120    }
121  }
122
123  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
124    '/bin/bash');
125  auth_group_write($auth_group_file, 'ftpd', $gid, $user);
126
127  my $config = {
128    PidFile => $pid_file,
129    ScoreboardFile => $scoreboard_file,
130    SystemLog => $log_file,
131
132    AuthUserFile => $auth_user_file,
133    AuthGroupFile => $auth_group_file,
134
135    IfModules => {
136      'mod_delay.c' => {
137        DelayEngine => 'off',
138      },
139    },
140  };
141
142  my ($port, $config_user, $config_group) = config_write($config_file, $config);
143
144  # Open pipes, for use between the parent and child processes.  Specifically,
145  # the child will indicate when it's done with its test by writing a message
146  # to the parent.
147  my ($rfh, $wfh);
148  unless (pipe($rfh, $wfh)) {
149    die("Can't open pipe: $!");
150  }
151
152  my $ex;
153
154  # Fork child
155  $self->handle_sigchld();
156  defined(my $pid = fork()) or die("Can't fork: $!");
157  if ($pid) {
158    eval {
159      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
160      $client->login($user, $passwd);
161
162      my ($resp_code, $resp_msg);
163      ($resp_code, $resp_msg) = $client->site('MKDIR', 'foo/bar/baz');
164
165      my $expected;
166
167      $expected = 200;
168      $self->assert($expected == $resp_code,
169        test_msg("Expected $expected, got $resp_code"));
170
171      $expected = "SITE MKDIR command successful";
172      $self->assert($expected eq $resp_msg,
173        test_msg("Expected '$expected', got '$resp_msg'"));
174
175      # Make sure that the test dir is present
176      unless (-d $test_dir) {
177        die("Directory $test_dir does not exist");
178      }
179    };
180
181    if ($@) {
182      $ex = $@;
183    }
184
185    $wfh->print("done\n");
186    $wfh->flush();
187
188  } else {
189    eval { server_wait($config_file, $rfh) };
190    if ($@) {
191      warn($@);
192      exit 1;
193    }
194
195    exit 0;
196  }
197
198  # Stop server
199  server_stop($pid_file);
200
201  $self->assert_child_ok($pid);
202
203  if ($ex) {
204    die($ex);
205  }
206
207  unlink($log_file);
208}
209
210sub site_misc_rmdir_ok {
211  my $self = shift;
212  my $tmpdir = $self->{tmpdir};
213
214  my $config_file = "$tmpdir/site.conf";
215  my $pid_file = File::Spec->rel2abs("$tmpdir/site.pid");
216  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/site.scoreboard");
217
218  my $log_file = File::Spec->rel2abs('tests.log');
219
220  my $auth_user_file = File::Spec->rel2abs("$tmpdir/site.passwd");
221  my $auth_group_file = File::Spec->rel2abs("$tmpdir/site.group");
222
223  my $user = 'proftpd';
224  my $passwd = 'test';
225  my $home_dir = File::Spec->rel2abs($tmpdir);
226  my $uid = 500;
227  my $gid = 500;
228
229  my $sub_dir = File::Spec->rel2abs("$tmpdir/foo/bar/baz");
230  mkpath($sub_dir);
231
232  my $test_dirs = [
233    File::Spec->rel2abs("$tmpdir/foo"),
234    File::Spec->rel2abs("$tmpdir/foo/bar"),
235    $sub_dir,
236  ];
237
238  my $test_file = File::Spec->rel2abs("$tmpdir/foo/bar/quxx.txt");
239  if (open(my $fh, "> $test_file")) {
240    print $fh "Quzz\n";
241
242    unless (close($fh)) {
243      die("Can't write $test_file: $!");
244    }
245
246  } else {
247    die("Can't open $test_file: $!");
248  }
249
250  # Make sure that, if we're running as root, that the home directory has
251  # permissions/privs set for the account we create
252  if ($< == 0) {
253    unless (chmod(0755, $home_dir)) {
254      die("Can't set perms on $home_dir to 0755: $!");
255    }
256
257    unless (chown($uid, $gid, $home_dir)) {
258      die("Can't set owner of $home_dir to $uid/$gid: $!");
259    }
260  }
261
262  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
263    '/bin/bash');
264  auth_group_write($auth_group_file, 'ftpd', $gid, $user);
265
266  my $config = {
267    PidFile => $pid_file,
268    ScoreboardFile => $scoreboard_file,
269    SystemLog => $log_file,
270
271    AuthUserFile => $auth_user_file,
272    AuthGroupFile => $auth_group_file,
273
274    IfModules => {
275      'mod_delay.c' => {
276        DelayEngine => 'off',
277      },
278    },
279  };
280
281  my ($port, $config_user, $config_group) = config_write($config_file, $config);
282
283  # Open pipes, for use between the parent and child processes.  Specifically,
284  # the child will indicate when it's done with its test by writing a message
285  # to the parent.
286  my ($rfh, $wfh);
287  unless (pipe($rfh, $wfh)) {
288    die("Can't open pipe: $!");
289  }
290
291  my $ex;
292
293  # Fork child
294  $self->handle_sigchld();
295  defined(my $pid = fork()) or die("Can't fork: $!");
296  if ($pid) {
297    eval {
298      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
299      $client->login($user, $passwd);
300
301      my ($resp_code, $resp_msg);
302      ($resp_code, $resp_msg) = $client->site('RMDIR', 'foo');
303
304      my $expected;
305
306      $expected = 200;
307      $self->assert($expected == $resp_code,
308        test_msg("Expected $expected, got $resp_code"));
309
310      $expected = "SITE RMDIR command successful";
311      $self->assert($expected eq $resp_msg,
312        test_msg("Expected '$expected', got '$resp_msg'"));
313
314      # Make sure that the test file is gone, along with all of the
315      # test dirs.
316      if (-f $test_file) {
317        die("File $test_file exists, should be deleted");
318      }
319
320      foreach my $test_dir (@$test_dirs) {
321        if (-d $test_dir) {
322          die("Directory $test_dir exists, should be deleted");
323        }
324      }
325    };
326
327    if ($@) {
328      $ex = $@;
329    }
330
331    $wfh->print("done\n");
332    $wfh->flush();
333
334  } else {
335    eval { server_wait($config_file, $rfh) };
336    if ($@) {
337      warn($@);
338      exit 1;
339    }
340
341    exit 0;
342  }
343
344  # Stop server
345  server_stop($pid_file);
346
347  $self->assert_child_ok($pid);
348
349  if ($ex) {
350    die($ex);
351  }
352
353  unlink($log_file);
354}
355
356sub site_misc_symlink_ok {
357  my $self = shift;
358  my $tmpdir = $self->{tmpdir};
359
360  my $config_file = "$tmpdir/site.conf";
361  my $pid_file = File::Spec->rel2abs("$tmpdir/site.pid");
362  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/site.scoreboard");
363
364  my $log_file = File::Spec->rel2abs('tests.log');
365
366  my $auth_user_file = File::Spec->rel2abs("$tmpdir/site.passwd");
367  my $auth_group_file = File::Spec->rel2abs("$tmpdir/site.group");
368
369  my $user = 'proftpd';
370  my $passwd = 'test';
371  my $home_dir = File::Spec->rel2abs($tmpdir);
372  my $uid = 500;
373  my $gid = 500;
374
375  my $test_symlink = File::Spec->rel2abs("$tmpdir/foo");
376
377  # Make sure that, if we're running as root, that the home directory has
378  # permissions/privs set for the account we create
379  if ($< == 0) {
380    unless (chmod(0755, $home_dir)) {
381      die("Can't set perms on $home_dir to 0755: $!");
382    }
383
384    unless (chown($uid, $gid, $home_dir)) {
385      die("Can't set owner of $home_dir to $uid/$gid: $!");
386    }
387  }
388
389  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
390    '/bin/bash');
391  auth_group_write($auth_group_file, 'ftpd', $gid, $user);
392
393  my $config = {
394    PidFile => $pid_file,
395    ScoreboardFile => $scoreboard_file,
396    SystemLog => $log_file,
397
398    AuthUserFile => $auth_user_file,
399    AuthGroupFile => $auth_group_file,
400
401    IfModules => {
402      'mod_delay.c' => {
403        DelayEngine => 'off',
404      },
405    },
406  };
407
408  my ($port, $config_user, $config_group) = config_write($config_file, $config);
409
410  # Open pipes, for use between the parent and child processes.  Specifically,
411  # the child will indicate when it's done with its test by writing a message
412  # to the parent.
413  my ($rfh, $wfh);
414  unless (pipe($rfh, $wfh)) {
415    die("Can't open pipe: $!");
416  }
417
418  my $ex;
419
420  # Fork child
421  $self->handle_sigchld();
422  defined(my $pid = fork()) or die("Can't fork: $!");
423  if ($pid) {
424    eval {
425      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
426      $client->login($user, $passwd);
427
428      my ($resp_code, $resp_msg);
429      ($resp_code, $resp_msg) = $client->site('SYMLINK', 'site.conf', 'foo');
430
431      my $expected;
432
433      $expected = 200;
434      $self->assert($expected == $resp_code,
435        test_msg("Expected $expected, got $resp_code"));
436
437      $expected = "SITE SYMLINK command successful";
438      $self->assert($expected eq $resp_msg,
439        test_msg("Expected '$expected', got '$resp_msg'"));
440
441      unless (-l $test_symlink) {
442        die("Symlink $test_symlink does not exist");
443      }
444    };
445
446    if ($@) {
447      $ex = $@;
448    }
449
450    $wfh->print("done\n");
451    $wfh->flush();
452
453  } else {
454    eval { server_wait($config_file, $rfh) };
455    if ($@) {
456      warn($@);
457      exit 1;
458    }
459
460    exit 0;
461  }
462
463  # Stop server
464  server_stop($pid_file);
465
466  $self->assert_child_ok($pid);
467
468  if ($ex) {
469    die($ex);
470  }
471
472  unlink($log_file);
473}
474
475sub site_misc_utime_ok {
476  my $self = shift;
477  my $tmpdir = $self->{tmpdir};
478
479  my $config_file = "$tmpdir/site.conf";
480  my $pid_file = File::Spec->rel2abs("$tmpdir/site.pid");
481  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/site.scoreboard");
482
483  my $log_file = File::Spec->rel2abs('tests.log');
484
485  my $auth_user_file = File::Spec->rel2abs("$tmpdir/site.passwd");
486  my $auth_group_file = File::Spec->rel2abs("$tmpdir/site.group");
487
488  my $user = 'proftpd';
489  my $passwd = 'test';
490  my $home_dir = File::Spec->rel2abs($tmpdir);
491  my $uid = 500;
492  my $gid = 500;
493
494  # Make sure that, if we're running as root, that the home directory has
495  # permissions/privs set for the account we create
496  if ($< == 0) {
497    unless (chmod(0755, $home_dir)) {
498      die("Can't set perms on $home_dir to 0755: $!");
499    }
500
501    unless (chown($uid, $gid, $home_dir)) {
502      die("Can't set owner of $home_dir to $uid/$gid: $!");
503    }
504  }
505
506  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
507    '/bin/bash');
508  auth_group_write($auth_group_file, 'ftpd', $gid, $user);
509
510  my $config = {
511    PidFile => $pid_file,
512    ScoreboardFile => $scoreboard_file,
513    SystemLog => $log_file,
514
515    AuthUserFile => $auth_user_file,
516    AuthGroupFile => $auth_group_file,
517
518    IfModules => {
519      'mod_delay.c' => {
520        DelayEngine => 'off',
521      },
522    },
523  };
524
525  my ($port, $config_user, $config_group) = config_write($config_file, $config);
526
527  # Open pipes, for use between the parent and child processes.  Specifically,
528  # the child will indicate when it's done with its test by writing a message
529  # to the parent.
530  my ($rfh, $wfh);
531  unless (pipe($rfh, $wfh)) {
532    die("Can't open pipe: $!");
533  }
534
535  my $ex;
536
537  # Fork child
538  $self->handle_sigchld();
539  defined(my $pid = fork()) or die("Can't fork: $!");
540  if ($pid) {
541    eval {
542      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
543      $client->login($user, $passwd);
544
545      my ($resp_code, $resp_msg);
546      ($resp_code, $resp_msg) = $client->site('UTIME', '200002240826',
547        'site.conf');
548
549      my $expected;
550
551      $expected = 200;
552      $self->assert($expected == $resp_code,
553        test_msg("Expected $expected, got $resp_code"));
554
555      $expected = "SITE UTIME command successful";
556      $self->assert($expected eq $resp_msg,
557        test_msg("Expected '$expected', got '$resp_msg'"));
558
559      my ($atime, $mtime) = (stat($config_file))[8,9];
560
561      $expected = 951380760;
562      $self->assert($expected == $atime,
563        test_msg("Expected $expected, got $atime"));
564      $self->assert($expected == $mtime,
565        test_msg("Expected $expected, got $mtime"));
566    };
567
568    if ($@) {
569      $ex = $@;
570    }
571
572    $wfh->print("done\n");
573    $wfh->flush();
574
575  } else {
576    eval { server_wait($config_file, $rfh) };
577    if ($@) {
578      warn($@);
579      exit 1;
580    }
581
582    exit 0;
583  }
584
585  # Stop server
586  server_stop($pid_file);
587
588  $self->assert_child_ok($pid);
589
590  if ($ex) {
591    die($ex);
592  }
593
594  unlink($log_file);
595}
596
597sub site_misc_utime_with_sec_ok {
598  my $self = shift;
599  my $tmpdir = $self->{tmpdir};
600
601  my $config_file = "$tmpdir/site.conf";
602  my $pid_file = File::Spec->rel2abs("$tmpdir/site.pid");
603  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/site.scoreboard");
604
605  my $log_file = File::Spec->rel2abs('tests.log');
606
607  my $auth_user_file = File::Spec->rel2abs("$tmpdir/site.passwd");
608  my $auth_group_file = File::Spec->rel2abs("$tmpdir/site.group");
609
610  my $user = 'proftpd';
611  my $passwd = 'test';
612  my $home_dir = File::Spec->rel2abs($tmpdir);
613  my $uid = 500;
614  my $gid = 500;
615
616  # Make sure that, if we're running as root, that the home directory has
617  # permissions/privs set for the account we create
618  if ($< == 0) {
619    unless (chmod(0755, $home_dir)) {
620      die("Can't set perms on $home_dir to 0755: $!");
621    }
622
623    unless (chown($uid, $gid, $home_dir)) {
624      die("Can't set owner of $home_dir to $uid/$gid: $!");
625    }
626  }
627
628  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
629    '/bin/bash');
630  auth_group_write($auth_group_file, 'ftpd', $gid, $user);
631
632  my $config = {
633    PidFile => $pid_file,
634    ScoreboardFile => $scoreboard_file,
635    SystemLog => $log_file,
636
637    AuthUserFile => $auth_user_file,
638    AuthGroupFile => $auth_group_file,
639
640    IfModules => {
641      'mod_delay.c' => {
642        DelayEngine => 'off',
643      },
644    },
645  };
646
647  my ($port, $config_user, $config_group) = config_write($config_file, $config);
648
649  # Open pipes, for use between the parent and child processes.  Specifically,
650  # the child will indicate when it's done with its test by writing a message
651  # to the parent.
652  my ($rfh, $wfh);
653  unless (pipe($rfh, $wfh)) {
654    die("Can't open pipe: $!");
655  }
656
657  my $ex;
658
659  # Fork child
660  $self->handle_sigchld();
661  defined(my $pid = fork()) or die("Can't fork: $!");
662  if ($pid) {
663    eval {
664      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
665      $client->login($user, $passwd);
666
667      my ($resp_code, $resp_msg);
668      ($resp_code, $resp_msg) = $client->site('UTIME', '20000224082601',
669        'site.conf');
670
671      my $expected;
672
673      $expected = 200;
674      $self->assert($expected == $resp_code,
675        test_msg("Expected $expected, got $resp_code"));
676
677      $expected = "SITE UTIME command successful";
678      $self->assert($expected eq $resp_msg,
679        test_msg("Expected '$expected', got '$resp_msg'"));
680
681      my ($atime, $mtime) = (stat($config_file))[8,9];
682
683      $expected = 951380761;
684      $self->assert($expected == $atime,
685        test_msg("Expected $expected, got $atime"));
686      $self->assert($expected == $mtime,
687        test_msg("Expected $expected, got $mtime"));
688    };
689
690    if ($@) {
691      $ex = $@;
692    }
693
694    $wfh->print("done\n");
695    $wfh->flush();
696
697  } else {
698    eval { server_wait($config_file, $rfh) };
699    if ($@) {
700      warn($@);
701      exit 1;
702    }
703
704    exit 0;
705  }
706
707  # Stop server
708  server_stop($pid_file);
709
710  $self->assert_child_ok($pid);
711
712  if ($ex) {
713    die($ex);
714  }
715
716  unlink($log_file);
717}
718
719sub site_feat_ok {
720  my $self = shift;
721  my $tmpdir = $self->{tmpdir};
722
723  my $config_file = "$tmpdir/site.conf";
724  my $pid_file = File::Spec->rel2abs("$tmpdir/site.pid");
725  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/site.scoreboard");
726
727  my $log_file = File::Spec->rel2abs('tests.log');
728
729  my $auth_user_file = File::Spec->rel2abs("$tmpdir/site.passwd");
730  my $auth_group_file = File::Spec->rel2abs("$tmpdir/site.group");
731
732  my $user = 'proftpd';
733  my $passwd = 'test';
734  my $home_dir = File::Spec->rel2abs($tmpdir);
735  my $uid = 500;
736  my $gid = 500;
737
738  my $test_dir = File::Spec->rel2abs("$tmpdir/foo/bar/baz");
739
740  # Make sure that, if we're running as root, that the home directory has
741  # permissions/privs set for the account we create
742  if ($< == 0) {
743    unless (chmod(0755, $home_dir)) {
744      die("Can't set perms on $home_dir to 0755: $!");
745    }
746
747    unless (chown($uid, $gid, $home_dir)) {
748      die("Can't set owner of $home_dir to $uid/$gid: $!");
749    }
750  }
751
752  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
753    '/bin/bash');
754  auth_group_write($auth_group_file, 'ftpd', $gid, $user);
755
756  my $config = {
757    PidFile => $pid_file,
758    ScoreboardFile => $scoreboard_file,
759    SystemLog => $log_file,
760
761    AuthUserFile => $auth_user_file,
762    AuthGroupFile => $auth_group_file,
763
764    IfModules => {
765      'mod_delay.c' => {
766        DelayEngine => 'off',
767      },
768    },
769  };
770
771  my ($port, $config_user, $config_group) = config_write($config_file, $config);
772
773  # Open pipes, for use between the parent and child processes.  Specifically,
774  # the child will indicate when it's done with its test by writing a message
775  # to the parent.
776  my ($rfh, $wfh);
777  unless (pipe($rfh, $wfh)) {
778    die("Can't open pipe: $!");
779  }
780
781  my $ex;
782
783  # Fork child
784  $self->handle_sigchld();
785  defined(my $pid = fork()) or die("Can't fork: $!");
786  if ($pid) {
787    eval {
788      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
789
790      $client->feat();
791      my $resp_code = $client->response_code();
792      my $resp_msgs = $client->response_msgs();
793
794      my $expected;
795
796      $expected = 211;
797      $self->assert($expected == $resp_code,
798        test_msg("Expected $expected, got $resp_code"));
799
800      my $nfeat = scalar(@$resp_msgs);
801
802      my $feats = {
803        ' SITE MKDIR' => 1,
804        ' SITE RMDIR' => 1,
805        ' SITE SYMLINK' => 1,
806        ' SITE UTIME' => 1,
807      };
808
809      for (my $i = 0; $i < $nfeat; $i++) {
810        if (defined($feats->{$resp_msgs->[$i]})) {
811          delete($feats->{$resp_msgs->[$i]});
812        }
813      }
814
815      my $remain_misc_feats = scalar(keys(%$feats));
816      $self->assert($remain_misc_feats == 0,
817        test_msg("Unexpected 0, got $remain_misc_feats"));
818    };
819
820    if ($@) {
821      $ex = $@;
822    }
823
824    $wfh->print("done\n");
825    $wfh->flush();
826
827  } else {
828    eval { server_wait($config_file, $rfh) };
829    if ($@) {
830      warn($@);
831      exit 1;
832    }
833
834    exit 0;
835  }
836
837  # Stop server
838  server_stop($pid_file);
839
840  $self->assert_child_ok($pid);
841
842  if ($ex) {
843    die($ex);
844  }
845
846  unlink($log_file);
847}
848
849sub site_misc_symlink_ncftpd_chroot_bug {
850  my $self = shift;
851  my $tmpdir = $self->{tmpdir};
852
853  my $config_file = "$tmpdir/site.conf";
854  my $pid_file = File::Spec->rel2abs("$tmpdir/site.pid");
855  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/site.scoreboard");
856
857  my $log_file = File::Spec->rel2abs('tests.log');
858
859  my $auth_user_file = File::Spec->rel2abs("$tmpdir/site.passwd");
860  my $auth_group_file = File::Spec->rel2abs("$tmpdir/site.group");
861
862  my $user = 'proftpd';
863  my $passwd = 'test';
864  my $home_dir = File::Spec->rel2abs($tmpdir);
865  my $uid = 500;
866  my $gid = 500;
867
868  my $test_symlink = File::Spec->rel2abs("$home_dir/hack/.message");
869
870  # Make sure that, if we're running as root, that the home directory has
871  # permissions/privs set for the account we create
872  if ($< == 0) {
873    unless (chmod(0755, $home_dir)) {
874      die("Can't set perms on $home_dir to 0755: $!");
875    }
876
877    unless (chown($uid, $gid, $home_dir)) {
878      die("Can't set owner of $home_dir to $uid/$gid: $!");
879    }
880  }
881
882  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
883    '/bin/bash');
884  auth_group_write($auth_group_file, 'ftpd', $gid, $user);
885
886  my $config = {
887    PidFile => $pid_file,
888    ScoreboardFile => $scoreboard_file,
889    SystemLog => $log_file,
890
891    AuthUserFile => $auth_user_file,
892    AuthGroupFile => $auth_group_file,
893    DefaultRoot => '~',
894    DisplayChdir => '.message',
895
896    IfModules => {
897      'mod_delay.c' => {
898        DelayEngine => 'off',
899      },
900    },
901  };
902
903  my ($port, $config_user, $config_group) = config_write($config_file, $config);
904
905  # Open pipes, for use between the parent and child processes.  Specifically,
906  # the child will indicate when it's done with its test by writing a message
907  # to the parent.
908  my ($rfh, $wfh);
909  unless (pipe($rfh, $wfh)) {
910    die("Can't open pipe: $!");
911  }
912
913  my $ex;
914
915  # Fork child
916  $self->handle_sigchld();
917  defined(my $pid = fork()) or die("Can't fork: $!");
918  if ($pid) {
919    eval {
920      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port, 1);
921      $client->login($user, $passwd);
922
923      my ($expected, $resp_code, $resp_msg);
924
925      my $conn = $client->retr_raw('/etc/passwd');
926      if ($conn) {
927        die("RETR /etc/passwd succeeded unexpectedly");
928      }
929
930      $resp_code = $client->response_code();
931      $resp_msg = $client->response_msg();
932       
933      $expected = 550;
934      $self->assert($expected == $resp_code,
935        test_msg("Expected $expected, got $resp_code"));
936
937      $expected = "/etc/passwd: No such file or directory";
938      $self->assert($expected eq $resp_msg,
939        test_msg("Expected '$expected', got '$resp_msg'"));
940
941      ($resp_code, $resp_msg) = $client->mkd('hack');
942
943      $expected = 257;
944      $self->assert($expected == $resp_code,
945        test_msg("Expected $expected, got $resp_code"));
946
947      $expected = "\"/hack\" - Directory successfully created";
948      $self->assert($expected eq $resp_msg,
949        test_msg("Expected '$expected', got '$resp_msg'"));
950
951      eval { $client->site('SYMLINK', '/etc/passwd', 'hack/.message') };
952      unless ($@) {
953        die("SITE SYMLINK succeeded unexpectedly");
954      }
955
956      $resp_code = $client->response_code();
957      $resp_msg = $client->response_msg();
958
959      $expected = 550;
960      $self->assert($expected == $resp_code,
961        test_msg("Expected $expected, got $resp_code"));
962
963      $expected = "SYMLINK /etc/passwd hack/.message: No such file or directory";
964      $self->assert($expected eq $resp_msg,
965        test_msg("Expected '$expected', got '$resp_msg'"));
966
967      $client->quit();
968    };
969
970    if ($@) {
971      $ex = $@;
972    }
973
974    $wfh->print("done\n");
975    $wfh->flush();
976
977  } else {
978    eval { server_wait($config_file, $rfh) };
979    if ($@) {
980      warn($@);
981      exit 1;
982    }
983
984    exit 0;
985  }
986
987  # Stop server
988  server_stop($pid_file);
989
990  $self->assert_child_ok($pid);
991
992  if ($ex) {
993    die($ex);
994  }
995
996  unlink($log_file);
997}
998
9991;
Note: See TracBrowser for help on using the repository browser.