1package ProFTPD::Tests::Modules::mod_auth_file;
2
3use lib qw(t/lib);
4use base qw(ProFTPD::TestSuite::Child);
5use strict;
6
7use Cwd;
8use File::Path qw(mkpath);
9use File::Spec;
10use IO::Handle;
11
12use ProFTPD::TestSuite::FTP;
13use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
14
15$| = 1;
16
17my $order = 0;
18
19my $TESTS = {
20  auth_user_file_id_range_ok => {
21    order => ++$order,
22    test_class => [qw(forking)],
23  },
24
25  auth_user_file_id_range_failed => {
26    order => ++$order,
27    test_class => [qw(forking)],
28  },
29
30  auth_user_file_home_filter_ok => {
31    order => ++$order,
32    test_class => [qw(forking)],
33  },
34
35  auth_user_file_home_filter_failed => {
36    order => ++$order,
37    test_class => [qw(forking)],
38  },
39
40  auth_user_file_name_filter_ok => {
41    order => ++$order,
42    test_class => [qw(forking)],
43  },
44
45  auth_user_file_name_filter_failed => {
46    order => ++$order,
47    test_class => [qw(forking)],
48  },
49
50  auth_group_file_id_range_ok => {
51    order => ++$order,
52    test_class => [qw(forking)],
53  },
54
55  auth_group_file_id_range_failed => {
56    order => ++$order,
57    test_class => [qw(forking)],
58  },
59
60  auth_group_file_name_filter_ok => {
61    order => ++$order,
62    test_class => [qw(forking)],
63  },
64
65  auth_group_file_name_filter_failed => {
66    order => ++$order,
67    test_class => [qw(forking)],
68  },
69
70  auth_user_file_at_symbol_ok => {
71    order => ++$order,
72    test_class => [qw(forking)],
73  },
74
75  auth_user_file_world_readable_bug3892 => {
76    order => ++$order,
77    test_class => [qw(bug forking)],
78  },
79
80  auth_user_file_world_writable_bug3892 => {
81    order => ++$order,
82    test_class => [qw(bug forking)],
83  },
84
85  auth_user_file_world_readable_insecure_perms_opt => {
86    order => ++$order,
87    test_class => [qw(bug forking)],
88  },
89
90  auth_group_file_world_readable_bug3892 => {
91    order => ++$order,
92    test_class => [qw(bug forking)],
93  },
94
95  auth_group_file_world_writable_bug3892 => {
96    order => ++$order,
97    test_class => [qw(bug forking)],
98  },
99
100  auth_user_file_world_writable_parent_dir_bug3892 => {
101    order => ++$order,
102    test_class => [qw(bug forking)],
103  },
104
105  auth_user_file_symlink_world_writable_parent_dir_bug3892 => {
106    order => ++$order,
107    test_class => [qw(bug forking)],
108  },
109
110  auth_user_file_bad_syntax_bug3985 => {
111    order => ++$order,
112    test_class => [qw(bug forking)],
113  },
114
115  auth_group_file_bad_syntax_bug3985 => {
116    order => ++$order,
117    test_class => [qw(bug forking)],
118  },
119
120  auth_file_symlink_segfault_bug4145 => {
121    order => ++$order,
122    test_class => [qw(bug forking)],
123  },
124
125};
126
127sub new {
128  return shift()->SUPER::new(@_);
129}
130
131sub list_tests {
132  return testsuite_get_runnable_tests($TESTS);
133}
134
135sub auth_user_file_id_range_ok {
136  my $self = shift;
137  my $tmpdir = $self->{tmpdir};
138
139  my $config_file = "$tmpdir/authfile.conf";
140  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
141  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
142
143  my $log_file = test_get_logfile();
144
145  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
146  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
147
148  my $user = 'proftpd';
149  my $passwd = 'test';
150  my $group = 'ftpd';
151  my $home_dir = File::Spec->rel2abs($tmpdir);
152  my $uid = 500;
153  my $gid = 500;
154
155  # Make sure that, if we're running as root, that the home directory has
156  # permissions/privs set for the account we create
157  if ($< == 0) {
158    unless (chmod(0755, $home_dir)) {
159      die("Can't set perms on $home_dir to 0755: $!");
160    }
161
162    unless (chown($uid, $gid, $home_dir)) {
163      die("Can't set owner of $home_dir to $uid/$gid: $!");
164    }
165  }
166
167  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
168    '/bin/bash');
169  auth_group_write($auth_group_file, $group, $gid, $user);
170
171  my $config = {
172    PidFile => $pid_file,
173    ScoreboardFile => $scoreboard_file,
174    SystemLog => $log_file,
175
176    AuthUserFile => "$auth_user_file id 100-500",
177    AuthGroupFile => $auth_group_file,
178
179    IfModules => {
180      'mod_delay.c' => {
181        DelayEngine => 'off',
182      },
183    },
184  };
185
186  my ($port, $config_user, $config_group) = config_write($config_file, $config);
187
188  # Open pipes, for use between the parent and child processes.  Specifically,
189  # the child will indicate when it's done with its test by writing a message
190  # to the parent.
191  my ($rfh, $wfh);
192  unless (pipe($rfh, $wfh)) {
193    die("Can't open pipe: $!");
194  }
195
196  my $ex;
197
198  # Fork child
199  $self->handle_sigchld();
200  defined(my $pid = fork()) or die("Can't fork: $!");
201  if ($pid) {
202    eval {
203      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
204      $client->login($user, $passwd);
205      $client->quit();
206    };
207
208    if ($@) {
209      $ex = $@;
210    }
211
212    $wfh->print("done\n");
213    $wfh->flush();
214
215  } else {
216    eval { server_wait($config_file, $rfh) };
217    if ($@) {
218      warn($@);
219      exit 1;
220    }
221
222    exit 0;
223  }
224
225  # Stop server
226  server_stop($pid_file);
227
228  $self->assert_child_ok($pid);
229
230  if ($ex) {
231    test_append_logfile($log_file, $ex);
232    unlink($log_file);
233
234    die($ex);
235  }
236
237  unlink($log_file);
238}
239
240sub auth_user_file_id_range_failed {
241  my $self = shift;
242  my $tmpdir = $self->{tmpdir};
243
244  my $config_file = "$tmpdir/authfile.conf";
245  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
246  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
247
248  my $log_file = test_get_logfile();
249
250  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
251  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
252
253  my $user = 'proftpd';
254  my $passwd = 'test';
255  my $group = 'ftpd';
256  my $home_dir = File::Spec->rel2abs($tmpdir);
257  my $uid = 1000;
258  my $gid = 1000;
259
260  # Make sure that, if we're running as root, that the home directory has
261  # permissions/privs set for the account we create
262  if ($< == 0) {
263    unless (chmod(0755, $home_dir)) {
264      die("Can't set perms on $home_dir to 0755: $!");
265    }
266
267    unless (chown($uid, $gid, $home_dir)) {
268      die("Can't set owner of $home_dir to $uid/$gid: $!");
269    }
270  }
271
272  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
273    '/bin/bash');
274  auth_group_write($auth_group_file, $group, $gid, $user);
275
276  my $config = {
277    PidFile => $pid_file,
278    ScoreboardFile => $scoreboard_file,
279    SystemLog => $log_file,
280
281    AuthUserFile => "$auth_user_file id 100-500",
282    AuthGroupFile => $auth_group_file,
283
284    IfModules => {
285      'mod_delay.c' => {
286        DelayEngine => 'off',
287      },
288    },
289  };
290
291  my ($port, $config_user, $config_group) = config_write($config_file, $config);
292
293  # Open pipes, for use between the parent and child processes.  Specifically,
294  # the child will indicate when it's done with its test by writing a message
295  # to the parent.
296  my ($rfh, $wfh);
297  unless (pipe($rfh, $wfh)) {
298    die("Can't open pipe: $!");
299  }
300
301  my $ex;
302
303  # Fork child
304  $self->handle_sigchld();
305  defined(my $pid = fork()) or die("Can't fork: $!");
306  if ($pid) {
307    eval {
308      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
309      eval { $client->login($user, $passwd) };
310      unless ($@) {
311        die("Login succeeded unexpectedly");
312      }
313
314      $client->quit();
315    };
316
317    if ($@) {
318      $ex = $@;
319    }
320
321    $wfh->print("done\n");
322    $wfh->flush();
323
324  } else {
325    eval { server_wait($config_file, $rfh) };
326    if ($@) {
327      warn($@);
328      exit 1;
329    }
330
331    exit 0;
332  }
333
334  # Stop server
335  server_stop($pid_file);
336
337  $self->assert_child_ok($pid);
338
339  if ($ex) {
340    test_append_logfile($log_file, $ex);
341    unlink($log_file);
342
343    die($ex);
344  }
345
346  unlink($log_file);
347}
348
349sub auth_user_file_home_filter_ok {
350  my $self = shift;
351  my $tmpdir = $self->{tmpdir};
352
353  my $config_file = "$tmpdir/authfile.conf";
354  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
355  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
356
357  my $log_file = test_get_logfile();
358
359  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
360  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
361
362  my $user = 'proftpd';
363  my $passwd = 'test';
364  my $group = 'ftpd';
365  my $home_dir = File::Spec->rel2abs("$tmpdir/$user");
366  mkpath($home_dir);
367  my $uid = 500;
368  my $gid = 500;
369
370  # Make sure that, if we're running as root, that the home directory has
371  # permissions/privs set for the account we create
372  if ($< == 0) {
373    unless (chmod(0755, $home_dir)) {
374      die("Can't set perms on $home_dir to 0755: $!");
375    }
376
377    unless (chown($uid, $gid, $home_dir)) {
378      die("Can't set owner of $home_dir to $uid/$gid: $!");
379    }
380  }
381
382  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
383    '/bin/bash');
384  auth_group_write($auth_group_file, $group, $gid, $user);
385
386  my $config = {
387    PidFile => $pid_file,
388    ScoreboardFile => $scoreboard_file,
389    SystemLog => $log_file,
390
391    AuthUserFile => "$auth_user_file home $user\$",
392    AuthGroupFile => $auth_group_file,
393
394    IfModules => {
395      'mod_delay.c' => {
396        DelayEngine => 'off',
397      },
398    },
399  };
400
401  my ($port, $config_user, $config_group) = config_write($config_file, $config);
402
403  # Open pipes, for use between the parent and child processes.  Specifically,
404  # the child will indicate when it's done with its test by writing a message
405  # to the parent.
406  my ($rfh, $wfh);
407  unless (pipe($rfh, $wfh)) {
408    die("Can't open pipe: $!");
409  }
410
411  my $ex;
412
413  # Fork child
414  $self->handle_sigchld();
415  defined(my $pid = fork()) or die("Can't fork: $!");
416  if ($pid) {
417    eval {
418      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
419      $client->login($user, $passwd);
420      $client->quit();
421    };
422
423    if ($@) {
424      $ex = $@;
425    }
426
427    $wfh->print("done\n");
428    $wfh->flush();
429
430  } else {
431    eval { server_wait($config_file, $rfh) };
432    if ($@) {
433      warn($@);
434      exit 1;
435    }
436
437    exit 0;
438  }
439
440  # Stop server
441  server_stop($pid_file);
442
443  $self->assert_child_ok($pid);
444
445  if ($ex) {
446    test_append_logfile($log_file, $ex);
447    unlink($log_file);
448
449    die($ex);
450  }
451
452  unlink($log_file);
453}
454
455sub auth_user_file_home_filter_failed {
456  my $self = shift;
457  my $tmpdir = $self->{tmpdir};
458
459  my $config_file = "$tmpdir/authfile.conf";
460  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
461  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
462
463  my $log_file = test_get_logfile();
464
465  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
466  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
467
468  my $user = 'proftpd';
469  my $passwd = 'test';
470  my $group = 'ftpd';
471  my $home_dir = File::Spec->rel2abs($tmpdir);
472  my $uid = 500;
473  my $gid = 500;
474
475  # Make sure that, if we're running as root, that the home directory has
476  # permissions/privs set for the account we create
477  if ($< == 0) {
478    unless (chmod(0755, $home_dir)) {
479      die("Can't set perms on $home_dir to 0755: $!");
480    }
481
482    unless (chown($uid, $gid, $home_dir)) {
483      die("Can't set owner of $home_dir to $uid/$gid: $!");
484    }
485  }
486
487  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
488    '/bin/bash');
489  auth_group_write($auth_group_file, $group, $gid, $user);
490
491  my $config = {
492    PidFile => $pid_file,
493    ScoreboardFile => $scoreboard_file,
494    SystemLog => $log_file,
495
496    AuthUserFile => "$auth_user_file home ^3133tH\@x0R\$",
497    AuthGroupFile => $auth_group_file,
498
499    IfModules => {
500      'mod_delay.c' => {
501        DelayEngine => 'off',
502      },
503    },
504  };
505
506  my ($port, $config_user, $config_group) = config_write($config_file, $config);
507
508  # Open pipes, for use between the parent and child processes.  Specifically,
509  # the child will indicate when it's done with its test by writing a message
510  # to the parent.
511  my ($rfh, $wfh);
512  unless (pipe($rfh, $wfh)) {
513    die("Can't open pipe: $!");
514  }
515
516  my $ex;
517
518  # Fork child
519  $self->handle_sigchld();
520  defined(my $pid = fork()) or die("Can't fork: $!");
521  if ($pid) {
522    eval {
523      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
524      eval { $client->login($user, $passwd) };
525      unless ($@) {
526        die("Login succeeded unexpectedly");
527      }
528
529      $client->quit();
530    };
531
532    if ($@) {
533      $ex = $@;
534    }
535
536    $wfh->print("done\n");
537    $wfh->flush();
538
539  } else {
540    eval { server_wait($config_file, $rfh) };
541    if ($@) {
542      warn($@);
543      exit 1;
544    }
545
546    exit 0;
547  }
548
549  # Stop server
550  server_stop($pid_file);
551
552  $self->assert_child_ok($pid);
553
554  if ($ex) {
555    test_append_logfile($log_file, $ex);
556    unlink($log_file);
557
558    die($ex);
559  }
560
561  unlink($log_file);
562}
563
564sub auth_user_file_name_filter_ok {
565  my $self = shift;
566  my $tmpdir = $self->{tmpdir};
567
568  my $config_file = "$tmpdir/authfile.conf";
569  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
570  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
571
572  my $log_file = test_get_logfile();
573
574  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
575  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
576
577  my $user = 'proftpd';
578  my $passwd = 'test';
579  my $group = 'ftpd';
580  my $home_dir = File::Spec->rel2abs($tmpdir);
581  my $uid = 500;
582  my $gid = 500;
583
584  # Make sure that, if we're running as root, that the home directory has
585  # permissions/privs set for the account we create
586  if ($< == 0) {
587    unless (chmod(0755, $home_dir)) {
588      die("Can't set perms on $home_dir to 0755: $!");
589    }
590
591    unless (chown($uid, $gid, $home_dir)) {
592      die("Can't set owner of $home_dir to $uid/$gid: $!");
593    }
594  }
595
596  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
597    '/bin/bash');
598  auth_group_write($auth_group_file, $group, $gid, $user);
599
600  my $config = {
601    PidFile => $pid_file,
602    ScoreboardFile => $scoreboard_file,
603    SystemLog => $log_file,
604
605    AuthUserFile => "$auth_user_file name ^$user\$",
606    AuthGroupFile => $auth_group_file,
607
608    IfModules => {
609      'mod_delay.c' => {
610        DelayEngine => 'off',
611      },
612    },
613  };
614
615  my ($port, $config_user, $config_group) = config_write($config_file, $config);
616
617  # Open pipes, for use between the parent and child processes.  Specifically,
618  # the child will indicate when it's done with its test by writing a message
619  # to the parent.
620  my ($rfh, $wfh);
621  unless (pipe($rfh, $wfh)) {
622    die("Can't open pipe: $!");
623  }
624
625  my $ex;
626
627  # Fork child
628  $self->handle_sigchld();
629  defined(my $pid = fork()) or die("Can't fork: $!");
630  if ($pid) {
631    eval {
632      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
633      $client->login($user, $passwd);
634      $client->quit();
635    };
636
637    if ($@) {
638      $ex = $@;
639    }
640
641    $wfh->print("done\n");
642    $wfh->flush();
643
644  } else {
645    eval { server_wait($config_file, $rfh) };
646    if ($@) {
647      warn($@);
648      exit 1;
649    }
650
651    exit 0;
652  }
653
654  # Stop server
655  server_stop($pid_file);
656
657  $self->assert_child_ok($pid);
658
659  if ($ex) {
660    test_append_logfile($log_file, $ex);
661    unlink($log_file);
662
663    die($ex);
664  }
665
666  unlink($log_file);
667}
668
669sub auth_user_file_name_filter_failed {
670  my $self = shift;
671  my $tmpdir = $self->{tmpdir};
672
673  my $config_file = "$tmpdir/authfile.conf";
674  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
675  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
676
677  my $log_file = test_get_logfile();
678
679  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
680  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
681
682  my $user = 'proftpd';
683  my $passwd = 'test';
684  my $group = 'ftpd';
685  my $home_dir = File::Spec->rel2abs($tmpdir);
686  my $uid = 500;
687  my $gid = 500;
688
689  # Make sure that, if we're running as root, that the home directory has
690  # permissions/privs set for the account we create
691  if ($< == 0) {
692    unless (chmod(0755, $home_dir)) {
693      die("Can't set perms on $home_dir to 0755: $!");
694    }
695
696    unless (chown($uid, $gid, $home_dir)) {
697      die("Can't set owner of $home_dir to $uid/$gid: $!");
698    }
699  }
700
701  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
702    '/bin/bash');
703  auth_group_write($auth_group_file, $group, $gid, $user);
704
705  my $config = {
706    PidFile => $pid_file,
707    ScoreboardFile => $scoreboard_file,
708    SystemLog => $log_file,
709
710    AuthUserFile => "$auth_user_file name ^3133tH\@x0R\$",
711    AuthGroupFile => $auth_group_file,
712
713    IfModules => {
714      'mod_delay.c' => {
715        DelayEngine => 'off',
716      },
717    },
718  };
719
720  my ($port, $config_user, $config_group) = config_write($config_file, $config);
721
722  # Open pipes, for use between the parent and child processes.  Specifically,
723  # the child will indicate when it's done with its test by writing a message
724  # to the parent.
725  my ($rfh, $wfh);
726  unless (pipe($rfh, $wfh)) {
727    die("Can't open pipe: $!");
728  }
729
730  my $ex;
731
732  # Fork child
733  $self->handle_sigchld();
734  defined(my $pid = fork()) or die("Can't fork: $!");
735  if ($pid) {
736    eval {
737      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
738      eval { $client->login($user, $passwd) };
739      unless ($@) {
740        die("Login succeeded unexpectedly");
741      }
742
743      $client->quit();
744    };
745
746    if ($@) {
747      $ex = $@;
748    }
749
750    $wfh->print("done\n");
751    $wfh->flush();
752
753  } else {
754    eval { server_wait($config_file, $rfh) };
755    if ($@) {
756      warn($@);
757      exit 1;
758    }
759
760    exit 0;
761  }
762
763  # Stop server
764  server_stop($pid_file);
765
766  $self->assert_child_ok($pid);
767
768  if ($ex) {
769    test_append_logfile($log_file, $ex);
770    unlink($log_file);
771
772    die($ex);
773  }
774
775  unlink($log_file);
776}
777
778sub auth_group_file_id_range_ok {
779  my $self = shift;
780  my $tmpdir = $self->{tmpdir};
781
782  my $config_file = "$tmpdir/authfile.conf";
783  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
784  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
785
786  my $log_file = test_get_logfile();
787
788  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
789  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
790
791  my $user = 'proftpd';
792  my $passwd = 'test';
793  my $group = 'ftpd';
794  my $home_dir = File::Spec->rel2abs($tmpdir);
795  my $uid = 500;
796  my $gid = 500;
797
798  # Make sure that, if we're running as root, that the home directory has
799  # permissions/privs set for the account we create
800  if ($< == 0) {
801    unless (chmod(0755, $home_dir)) {
802      die("Can't set perms on $home_dir to 0755: $!");
803    }
804
805    unless (chown($uid, $gid, $home_dir)) {
806      die("Can't set owner of $home_dir to $uid/$gid: $!");
807    }
808  }
809
810  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
811    '/bin/bash');
812  auth_group_write($auth_group_file, $group, $gid, $user);
813
814  my $config = {
815    PidFile => $pid_file,
816    ScoreboardFile => $scoreboard_file,
817    SystemLog => $log_file,
818
819    AuthUserFile => $auth_user_file,
820    AuthGroupFile => "$auth_group_file id 100-500",
821
822    IfModules => {
823      'mod_delay.c' => {
824        DelayEngine => 'off',
825      },
826    },
827  };
828
829  my ($port, $config_user, $config_group) = config_write($config_file, $config);
830
831  if (open(my $fh, ">> $config_file")) {
832    print $fh <<EOC;
833<Limit LOGIN>
834  AllowGroup $group
835  DenyAll
836</Limit>
837EOC
838
839    unless (close($fh)) {
840      die("Can't write $config_file: $!");
841    }
842
843  } else {
844    die("Can't open $config_file: $!");
845  }
846
847  # Open pipes, for use between the parent and child processes.  Specifically,
848  # the child will indicate when it's done with its test by writing a message
849  # to the parent.
850  my ($rfh, $wfh);
851  unless (pipe($rfh, $wfh)) {
852    die("Can't open pipe: $!");
853  }
854
855  my $ex;
856
857  # Fork child
858  $self->handle_sigchld();
859  defined(my $pid = fork()) or die("Can't fork: $!");
860  if ($pid) {
861    eval {
862      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
863      $client->login($user, $passwd);
864      $client->quit();
865    };
866
867    if ($@) {
868      $ex = $@;
869    }
870
871    $wfh->print("done\n");
872    $wfh->flush();
873
874  } else {
875    eval { server_wait($config_file, $rfh) };
876    if ($@) {
877      warn($@);
878      exit 1;
879    }
880
881    exit 0;
882  }
883
884  # Stop server
885  server_stop($pid_file);
886
887  $self->assert_child_ok($pid);
888
889  if ($ex) {
890    test_append_logfile($log_file, $ex);
891    unlink($log_file);
892
893    die($ex);
894  }
895
896  unlink($log_file);
897}
898
899sub auth_group_file_id_range_failed {
900  my $self = shift;
901  my $tmpdir = $self->{tmpdir};
902
903  my $config_file = "$tmpdir/authfile.conf";
904  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
905  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
906
907  my $log_file = test_get_logfile();
908
909  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
910  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
911
912  my $user = 'proftpd';
913  my $passwd = 'test';
914  my $group = 'ftpd';
915  my $home_dir = File::Spec->rel2abs($tmpdir);
916  my $uid = 1000;
917  my $gid = 1000;
918
919  # Make sure that, if we're running as root, that the home directory has
920  # permissions/privs set for the account we create
921  if ($< == 0) {
922    unless (chmod(0755, $home_dir)) {
923      die("Can't set perms on $home_dir to 0755: $!");
924    }
925
926    unless (chown($uid, $gid, $home_dir)) {
927      die("Can't set owner of $home_dir to $uid/$gid: $!");
928    }
929  }
930
931  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
932    '/bin/bash');
933  auth_group_write($auth_group_file, $group, $gid, $user);
934
935  my $config = {
936    PidFile => $pid_file,
937    ScoreboardFile => $scoreboard_file,
938    SystemLog => $log_file,
939
940    AuthUserFile => $auth_user_file,
941    AuthGroupFile => "$auth_group_file id 100-500",
942
943    IfModules => {
944      'mod_delay.c' => {
945        DelayEngine => 'off',
946      },
947    },
948  };
949
950  my ($port, $config_user, $config_group) = config_write($config_file, $config);
951
952  if (open(my $fh, ">> $config_file")) {
953    print $fh <<EOC;
954<Limit LOGIN>
955  AllowGroup $group
956  DenyAll
957</Limit>
958EOC
959
960    unless (close($fh)) {
961      die("Can't write $config_file: $!");
962    }
963
964  } else {
965    die("Can't open $config_file: $!");
966  }
967
968  # Open pipes, for use between the parent and child processes.  Specifically,
969  # the child will indicate when it's done with its test by writing a message
970  # to the parent.
971  my ($rfh, $wfh);
972  unless (pipe($rfh, $wfh)) {
973    die("Can't open pipe: $!");
974  }
975
976  my $ex;
977
978  # Fork child
979  $self->handle_sigchld();
980  defined(my $pid = fork()) or die("Can't fork: $!");
981  if ($pid) {
982    eval {
983      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
984      eval { $client->login($user, $passwd) };
985      unless ($@) {
986        die("Login succeeded unexpectedly");
987      }
988
989      $client->quit();
990    };
991
992    if ($@) {
993      $ex = $@;
994    }
995
996    $wfh->print("done\n");
997    $wfh->flush();
998
999  } else {
1000    eval { server_wait($config_file, $rfh) };
1001    if ($@) {
1002      warn($@);
1003      exit 1;
1004    }
1005
1006    exit 0;
1007  }
1008
1009  # Stop server
1010  server_stop($pid_file);
1011
1012  $self->assert_child_ok($pid);
1013
1014  if ($ex) {
1015    test_append_logfile($log_file, $ex);
1016    unlink($log_file);
1017
1018    die($ex);
1019  }
1020
1021  unlink($log_file);
1022}
1023
1024sub auth_group_file_name_filter_ok {
1025  my $self = shift;
1026  my $tmpdir = $self->{tmpdir};
1027
1028  my $config_file = "$tmpdir/authfile.conf";
1029  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
1030  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
1031
1032  my $log_file = test_get_logfile();
1033
1034  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
1035  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
1036
1037  my $user = 'proftpd';
1038  my $passwd = 'test';
1039  my $group = 'ftpd';
1040  my $home_dir = File::Spec->rel2abs($tmpdir);
1041  my $uid = 500;
1042  my $gid = 500;
1043
1044  # Make sure that, if we're running as root, that the home directory has
1045  # permissions/privs set for the account we create
1046  if ($< == 0) {
1047    unless (chmod(0755, $home_dir)) {
1048      die("Can't set perms on $home_dir to 0755: $!");
1049    }
1050
1051    unless (chown($uid, $gid, $home_dir)) {
1052      die("Can't set owner of $home_dir to $uid/$gid: $!");
1053    }
1054  }
1055
1056  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1057    '/bin/bash');
1058  auth_group_write($auth_group_file, $group, $gid, $user);
1059
1060  my $config = {
1061    PidFile => $pid_file,
1062    ScoreboardFile => $scoreboard_file,
1063    SystemLog => $log_file,
1064
1065    AuthUserFile => $auth_user_file,
1066    AuthGroupFile => "$auth_group_file name ^$group\$",
1067
1068    IfModules => {
1069      'mod_delay.c' => {
1070        DelayEngine => 'off',
1071      },
1072    },
1073  };
1074
1075  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1076
1077  if (open(my $fh, ">> $config_file")) {
1078    print $fh <<EOC;
1079<Limit LOGIN>
1080  AllowGroup $group
1081  DenyAll
1082</Limit>
1083EOC
1084
1085    unless (close($fh)) {
1086      die("Can't write $config_file: $!");
1087    }
1088
1089  } else {
1090    die("Can't open $config_file: $!");
1091  }
1092
1093  # Open pipes, for use between the parent and child processes.  Specifically,
1094  # the child will indicate when it's done with its test by writing a message
1095  # to the parent.
1096  my ($rfh, $wfh);
1097  unless (pipe($rfh, $wfh)) {
1098    die("Can't open pipe: $!");
1099  }
1100
1101  my $ex;
1102
1103  # Fork child
1104  $self->handle_sigchld();
1105  defined(my $pid = fork()) or die("Can't fork: $!");
1106  if ($pid) {
1107    eval {
1108      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1109      $client->login($user, $passwd);
1110      $client->quit();
1111    };
1112
1113    if ($@) {
1114      $ex = $@;
1115    }
1116
1117    $wfh->print("done\n");
1118    $wfh->flush();
1119
1120  } else {
1121    eval { server_wait($config_file, $rfh) };
1122    if ($@) {
1123      warn($@);
1124      exit 1;
1125    }
1126
1127    exit 0;
1128  }
1129
1130  # Stop server
1131  server_stop($pid_file);
1132
1133  $self->assert_child_ok($pid);
1134
1135  if ($ex) {
1136    test_append_logfile($log_file, $ex);
1137    unlink($log_file);
1138
1139    die($ex);
1140  }
1141
1142  unlink($log_file);
1143}
1144
1145sub auth_group_file_name_filter_failed {
1146  my $self = shift;
1147  my $tmpdir = $self->{tmpdir};
1148
1149  my $config_file = "$tmpdir/authfile.conf";
1150  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
1151  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
1152
1153  my $log_file = test_get_logfile();
1154
1155  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
1156  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
1157
1158  my $user = 'proftpd';
1159  my $passwd = 'test';
1160  my $group = 'ftpd';
1161  my $home_dir = File::Spec->rel2abs($tmpdir);
1162  my $uid = 500;
1163  my $gid = 500;
1164
1165  # Make sure that, if we're running as root, that the home directory has
1166  # permissions/privs set for the account we create
1167  if ($< == 0) {
1168    unless (chmod(0755, $home_dir)) {
1169      die("Can't set perms on $home_dir to 0755: $!");
1170    }
1171
1172    unless (chown($uid, $gid, $home_dir)) {
1173      die("Can't set owner of $home_dir to $uid/$gid: $!");
1174    }
1175  }
1176
1177  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1178    '/bin/bash');
1179  auth_group_write($auth_group_file, $group, $gid, $user);
1180
1181  my $config = {
1182    PidFile => $pid_file,
1183    ScoreboardFile => $scoreboard_file,
1184    SystemLog => $log_file,
1185
1186    AuthUserFile => $auth_user_file,
1187    AuthGroupFile => "$auth_group_file name ^3133tH\@x0R\$",
1188
1189    IfModules => {
1190      'mod_delay.c' => {
1191        DelayEngine => 'off',
1192      },
1193    },
1194  };
1195
1196  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1197
1198  if (open(my $fh, ">> $config_file")) {
1199    print $fh <<EOC;
1200<Limit LOGIN>
1201  AllowGroup $group
1202  DenyAll
1203</Limit>
1204EOC
1205
1206    unless (close($fh)) {
1207      die("Can't write $config_file: $!");
1208    }
1209
1210  } else {
1211    die("Can't open $config_file: $!");
1212  }
1213
1214  # Open pipes, for use between the parent and child processes.  Specifically,
1215  # the child will indicate when it's done with its test by writing a message
1216  # to the parent.
1217  my ($rfh, $wfh);
1218  unless (pipe($rfh, $wfh)) {
1219    die("Can't open pipe: $!");
1220  }
1221
1222  my $ex;
1223
1224  # Fork child
1225  $self->handle_sigchld();
1226  defined(my $pid = fork()) or die("Can't fork: $!");
1227  if ($pid) {
1228    eval {
1229      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1230      eval { $client->login($user, $passwd) };
1231      unless ($@) {
1232        die("Login succeeded unexpectedly");
1233      }
1234
1235      $client->quit();
1236    };
1237
1238    if ($@) {
1239      $ex = $@;
1240    }
1241
1242    $wfh->print("done\n");
1243    $wfh->flush();
1244
1245  } else {
1246    eval { server_wait($config_file, $rfh) };
1247    if ($@) {
1248      warn($@);
1249      exit 1;
1250    }
1251
1252    exit 0;
1253  }
1254
1255  # Stop server
1256  server_stop($pid_file);
1257
1258  $self->assert_child_ok($pid);
1259
1260  if ($ex) {
1261    test_append_logfile($log_file, $ex);
1262    unlink($log_file);
1263
1264    die($ex);
1265  }
1266
1267  unlink($log_file);
1268}
1269
1270sub auth_user_file_at_symbol_ok {
1271  my $self = shift;
1272  my $tmpdir = $self->{tmpdir};
1273
1274  my $config_file = "$tmpdir/authfile.conf";
1275  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
1276  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
1277
1278  my $log_file = test_get_logfile();
1279
1280  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
1281  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
1282
1283  my $user = 'proftpd@proftpd.org';
1284  my $passwd = 'test';
1285  my $group = 'ftpd';
1286  my $home_dir = File::Spec->rel2abs($tmpdir);
1287  my $uid = 500;
1288  my $gid = 500;
1289
1290  # Make sure that, if we're running as root, that the home directory has
1291  # permissions/privs set for the account we create
1292  if ($< == 0) {
1293    unless (chmod(0755, $home_dir)) {
1294      die("Can't set perms on $home_dir to 0755: $!");
1295    }
1296
1297    unless (chown($uid, $gid, $home_dir)) {
1298      die("Can't set owner of $home_dir to $uid/$gid: $!");
1299    }
1300  }
1301
1302  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1303    '/bin/bash');
1304  auth_group_write($auth_group_file, $group, $gid, $user);
1305
1306  my $config = {
1307    PidFile => $pid_file,
1308    ScoreboardFile => $scoreboard_file,
1309    SystemLog => $log_file,
1310
1311    AuthUserFile => $auth_user_file,
1312    AuthGroupFile => $auth_group_file,
1313
1314    IfModules => {
1315      'mod_delay.c' => {
1316        DelayEngine => 'off',
1317      },
1318    },
1319  };
1320
1321  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1322
1323  # Open pipes, for use between the parent and child processes.  Specifically,
1324  # the child will indicate when it's done with its test by writing a message
1325  # to the parent.
1326  my ($rfh, $wfh);
1327  unless (pipe($rfh, $wfh)) {
1328    die("Can't open pipe: $!");
1329  }
1330
1331  my $ex;
1332
1333  # Fork child
1334  $self->handle_sigchld();
1335  defined(my $pid = fork()) or die("Can't fork: $!");
1336  if ($pid) {
1337    eval {
1338      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1339      $client->login($user, $passwd);
1340      $client->quit();
1341    };
1342
1343    if ($@) {
1344      $ex = $@;
1345    }
1346
1347    $wfh->print("done\n");
1348    $wfh->flush();
1349
1350  } else {
1351    eval { server_wait($config_file, $rfh) };
1352    if ($@) {
1353      warn($@);
1354      exit 1;
1355    }
1356
1357    exit 0;
1358  }
1359
1360  # Stop server
1361  server_stop($pid_file);
1362
1363  $self->assert_child_ok($pid);
1364
1365  if ($ex) {
1366    test_append_logfile($log_file, $ex);
1367    unlink($log_file);
1368
1369    die($ex);
1370  }
1371
1372  unlink($log_file);
1373}
1374
1375sub auth_user_file_world_readable_bug3892 {
1376  my $self = shift;
1377  my $tmpdir = $self->{tmpdir};
1378
1379  my $config_file = "$tmpdir/authfile.conf";
1380  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
1381  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
1382
1383  my $log_file = test_get_logfile();
1384
1385  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
1386  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
1387
1388  my $user = 'proftpd';
1389  my $passwd = 'test';
1390  my $group = 'ftpd';
1391  my $home_dir = File::Spec->rel2abs($tmpdir);
1392  my $uid = 500;
1393  my $gid = 500;
1394
1395  # Make sure that, if we're running as root, that the home directory has
1396  # permissions/privs set for the account we create
1397  if ($< == 0) {
1398    unless (chmod(0755, $home_dir)) {
1399      die("Can't set perms on $home_dir to 0755: $!");
1400    }
1401
1402    unless (chown($uid, $gid, $home_dir)) {
1403      die("Can't set owner of $home_dir to $uid/$gid: $!");
1404    }
1405  }
1406
1407  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1408    '/bin/bash');
1409  auth_group_write($auth_group_file, $group, $gid, $user);
1410
1411  # Deliberately set world-readable perms on the AuthUserFile, to trigger
1412  # the checks done for Bug#3892.
1413  unless (chmod(0444, $auth_user_file)) {
1414    die("Can't set perms on $auth_user_file: $!");
1415  }
1416
1417  my $config = {
1418    PidFile => $pid_file,
1419    ScoreboardFile => $scoreboard_file,
1420    SystemLog => $log_file,
1421
1422    AuthUserFile => $auth_user_file,
1423    AuthGroupFile => $auth_group_file,
1424
1425    IfModules => {
1426      'mod_delay.c' => {
1427        DelayEngine => 'off',
1428      },
1429    },
1430  };
1431
1432  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1433
1434  eval { server_start($config_file, $pid_file) };
1435  unless ($@) {
1436    server_stop($pid_file);
1437
1438    my $ex = "Server started up unexpectedly with world-readable AuthUserFile";
1439    test_append_logfile($log_file, $ex);
1440    unlink($log_file);
1441
1442    die($ex);
1443  }
1444
1445  unlink($log_file);
1446}
1447
1448sub auth_user_file_world_writable_bug3892 {
1449  my $self = shift;
1450  my $tmpdir = $self->{tmpdir};
1451
1452  my $config_file = "$tmpdir/authfile.conf";
1453  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
1454  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
1455
1456  my $log_file = test_get_logfile();
1457
1458  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
1459  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
1460
1461  my $user = 'proftpd';
1462  my $passwd = 'test';
1463  my $group = 'ftpd';
1464  my $home_dir = File::Spec->rel2abs($tmpdir);
1465  my $uid = 500;
1466  my $gid = 500;
1467
1468  # Make sure that, if we're running as root, that the home directory has
1469  # permissions/privs set for the account we create
1470  if ($< == 0) {
1471    unless (chmod(0755, $home_dir)) {
1472      die("Can't set perms on $home_dir to 0755: $!");
1473    }
1474
1475    unless (chown($uid, $gid, $home_dir)) {
1476      die("Can't set owner of $home_dir to $uid/$gid: $!");
1477    }
1478  }
1479
1480  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1481    '/bin/bash');
1482  auth_group_write($auth_group_file, $group, $gid, $user);
1483
1484  # Deliberately set world-writable perms on the AuthUserFile, to trigger
1485  # the checks done for Bug#3892.
1486  unless (chmod(0442, $auth_user_file)) {
1487    die("Can't set perms on $auth_user_file: $!");
1488  }
1489
1490  my $config = {
1491    PidFile => $pid_file,
1492    ScoreboardFile => $scoreboard_file,
1493    SystemLog => $log_file,
1494
1495    AuthUserFile => $auth_user_file,
1496    AuthGroupFile => $auth_group_file,
1497
1498    IfModules => {
1499      'mod_delay.c' => {
1500        DelayEngine => 'off',
1501      },
1502    },
1503  };
1504
1505  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1506
1507  eval { server_start($config_file, $pid_file) };
1508  unless ($@) {
1509    server_stop($pid_file);
1510
1511    my $ex = "Server started up unexpectedly with world-writable AuthUserFile";
1512    test_append_logfile($log_file, $ex);
1513    unlink($log_file);
1514
1515    die($ex);
1516  }
1517
1518  unlink($log_file);
1519}
1520
1521sub auth_user_file_world_readable_insecure_perms_opt {
1522  my $self = shift;
1523  my $tmpdir = $self->{tmpdir};
1524  my $setup = test_setup($tmpdir, 'authfile');
1525
1526  # Deliberately set world-readable perms on the AuthUserFile, to trigger
1527  # the checks done for Bug#3892.
1528  unless (chmod(0444, $setup->{auth_user_file})) {
1529    die("Can't set perms on $setup->{auth_user_file}: $!");
1530  }
1531
1532  my $config = {
1533    PidFile => $setup->{pid_file},
1534    ScoreboardFile => $setup->{scoreboard_file},
1535    SystemLog => $setup->{log_file},
1536
1537    IfModules => {
1538      'mod_delay.c' => {
1539        DelayEngine => 'off',
1540      },
1541    },
1542  };
1543
1544  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
1545    $config);
1546
1547  # Note that we set this AuthFileOption here using an array, so that the
1548  # order of the directives is deterministic!
1549  if (open(my $fh, ">> $setup->{config_file}")) {
1550    print $fh <<EOC;
1551AuthFileOptions InsecurePerms
1552AuthUserFile $setup->{auth_user_file}
1553AuthGroupFile $setup->{auth_group_file}
1554EOC
1555    unless (close($fh)) {
1556      die("Can't write $setup->{config_file}: $!");
1557    }
1558
1559  } else {
1560    die("Can't open $setup->{config_file}: $!");
1561  }
1562
1563  my $ex;
1564
1565  eval { server_start($setup->{config_file}, $setup->{pid_file}) };
1566  if ($@) {
1567    $ex = $@;
1568
1569  } else {
1570    server_stop($setup->{pid_file});
1571  }
1572
1573  test_cleanup($setup->{log_file}, $ex);
1574}
1575
1576sub auth_group_file_world_readable_bug3892 {
1577  my $self = shift;
1578  my $tmpdir = $self->{tmpdir};
1579
1580  my $config_file = "$tmpdir/authfile.conf";
1581  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
1582  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
1583
1584  my $log_file = test_get_logfile();
1585
1586  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
1587  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
1588
1589  my $user = 'proftpd';
1590  my $passwd = 'test';
1591  my $group = 'ftpd';
1592  my $home_dir = File::Spec->rel2abs($tmpdir);
1593  my $uid = 500;
1594  my $gid = 500;
1595
1596  # Make sure that, if we're running as root, that the home directory has
1597  # permissions/privs set for the account we create
1598  if ($< == 0) {
1599    unless (chmod(0755, $home_dir)) {
1600      die("Can't set perms on $home_dir to 0755: $!");
1601    }
1602
1603    unless (chown($uid, $gid, $home_dir)) {
1604      die("Can't set owner of $home_dir to $uid/$gid: $!");
1605    }
1606  }
1607
1608  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1609    '/bin/bash');
1610  auth_group_write($auth_group_file, $group, $gid, $user);
1611
1612  # Deliberately set world-readable perms on the AuthGroupFile, to trigger
1613  # the checks done for Bug#3892.
1614  unless (chmod(0444, $auth_group_file)) {
1615    die("Can't set perms on $auth_group_file: $!");
1616  }
1617
1618  my $config = {
1619    PidFile => $pid_file,
1620    ScoreboardFile => $scoreboard_file,
1621    SystemLog => $log_file,
1622
1623    AuthUserFile => $auth_user_file,
1624    AuthGroupFile => $auth_group_file,
1625
1626    IfModules => {
1627      'mod_delay.c' => {
1628        DelayEngine => 'off',
1629      },
1630    },
1631  };
1632
1633  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1634
1635  eval { server_start($config_file, $pid_file) };
1636  if ($@) {
1637    my $ex = $@;
1638    test_append_logfile($log_file, $ex);
1639    unlink($log_file);
1640
1641    die($ex);
1642  }
1643
1644  server_stop($pid_file);
1645  unlink($log_file);
1646}
1647
1648sub auth_group_file_world_writable_bug3892 {
1649  my $self = shift;
1650  my $tmpdir = $self->{tmpdir};
1651
1652  my $config_file = "$tmpdir/authfile.conf";
1653  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
1654  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
1655
1656  my $log_file = test_get_logfile();
1657
1658  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
1659  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
1660
1661  my $user = 'proftpd';
1662  my $passwd = 'test';
1663  my $group = 'ftpd';
1664  my $home_dir = File::Spec->rel2abs($tmpdir);
1665  my $uid = 500;
1666  my $gid = 500;
1667
1668  # Make sure that, if we're running as root, that the home directory has
1669  # permissions/privs set for the account we create
1670  if ($< == 0) {
1671    unless (chmod(0755, $home_dir)) {
1672      die("Can't set perms on $home_dir to 0755: $!");
1673    }
1674
1675    unless (chown($uid, $gid, $home_dir)) {
1676      die("Can't set owner of $home_dir to $uid/$gid: $!");
1677    }
1678  }
1679
1680  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1681    '/bin/bash');
1682  auth_group_write($auth_group_file, $group, $gid, $user);
1683
1684  # Deliberately set world-writable perms on the AuthGroupFile, to trigger
1685  # the checks done for Bug#3892.
1686  unless (chmod(0442, $auth_group_file)) {
1687    die("Can't set perms on $auth_group_file: $!");
1688  }
1689
1690  my $config = {
1691    PidFile => $pid_file,
1692    ScoreboardFile => $scoreboard_file,
1693    SystemLog => $log_file,
1694
1695    AuthUserFile => $auth_user_file,
1696    AuthGroupFile => $auth_group_file,
1697
1698    IfModules => {
1699      'mod_delay.c' => {
1700        DelayEngine => 'off',
1701      },
1702    },
1703  };
1704
1705  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1706
1707  eval { server_start($config_file, $pid_file) };
1708  unless ($@) {
1709    server_stop($pid_file);
1710
1711    my $ex = "Server started up unexpectedly with world-writable AuthGroupFile";
1712    test_append_logfile($log_file, $ex);
1713    unlink($log_file);
1714
1715    die($ex);
1716  }
1717
1718  unlink($log_file);
1719}
1720
1721sub auth_user_file_world_writable_parent_dir_bug3892 {
1722  my $self = shift;
1723  my $tmpdir = $self->{tmpdir};
1724
1725  my $config_file = "$tmpdir/authfile.conf";
1726  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
1727  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
1728
1729  my $log_file = test_get_logfile();
1730
1731  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
1732  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
1733
1734  my $user = 'proftpd';
1735  my $passwd = 'test';
1736  my $group = 'ftpd';
1737  my $home_dir = File::Spec->rel2abs($tmpdir);
1738  my $uid = 500;
1739  my $gid = 500;
1740
1741  # Make sure that, if we're running as root, that the home directory has
1742  # permissions/privs set for the account we create
1743  if ($< == 0) {
1744    unless (chmod(0755, $home_dir)) {
1745      die("Can't set perms on $home_dir to 0755: $!");
1746    }
1747
1748    unless (chown($uid, $gid, $home_dir)) {
1749      die("Can't set owner of $home_dir to $uid/$gid: $!");
1750    }
1751  }
1752
1753  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1754    '/bin/bash');
1755  auth_group_write($auth_group_file, $group, $gid, $user);
1756
1757  # Deliberately set world-writable perms on the parent directory of the
1758  # AuthUserFile, to trigger the checks done for Bug#3892.
1759  unless (chmod(0777, $tmpdir)) {
1760    die("Can't set perms on $tmpdir: $!");
1761  }
1762
1763  my $config = {
1764    PidFile => $pid_file,
1765    ScoreboardFile => $scoreboard_file,
1766    SystemLog => $log_file,
1767
1768    AuthUserFile => $auth_user_file,
1769    AuthGroupFile => $auth_group_file,
1770
1771    IfModules => {
1772      'mod_delay.c' => {
1773        DelayEngine => 'off',
1774      },
1775    },
1776  };
1777
1778  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1779
1780  eval { server_start($config_file, $pid_file) };
1781  unless ($@) {
1782    server_stop($pid_file);
1783
1784    my $ex = "Server started up unexpectedly with world-writable AuthUserFile parent directory";
1785    test_append_logfile($log_file, $ex);
1786    unlink($log_file);
1787
1788    die($ex);
1789  }
1790
1791  unlink($log_file);
1792}
1793
1794sub auth_user_file_symlink_world_writable_parent_dir_bug3892 {
1795  my $self = shift;
1796  my $tmpdir = $self->{tmpdir};
1797
1798  my $config_file = "$tmpdir/authfile.conf";
1799  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
1800  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
1801
1802  my $log_file = test_get_logfile();
1803
1804  my $etc_dir = File::Spec->rel2abs("$tmpdir/etc");
1805  mkpath($etc_dir);
1806
1807  my $auth_user_file = File::Spec->rel2abs("$tmpdir/etc/authfile.passwd");
1808  my $auth_group_file = File::Spec->rel2abs("$tmpdir/etc/authfile.group");
1809
1810  my $user = 'proftpd';
1811  my $passwd = 'test';
1812  my $group = 'ftpd';
1813  my $home_dir = File::Spec->rel2abs($tmpdir);
1814  my $uid = 500;
1815  my $gid = 500;
1816
1817  my $test_dir = File::Spec->rel2abs("$tmpdir/test.d");
1818  mkpath($test_dir);
1819  my $auth_user_symlink = File::Spec->rel2abs("$tmpdir/test.d/authfile.lnk");
1820
1821  # Make sure that, if we're running as root, that the home directory has
1822  # permissions/privs set for the account we create
1823  #
1824  # Deliberately set world-writable perms on the symlink parent
1825  # directory, to trigger the checks done for Bug#3892.
1826
1827  if ($< == 0) {
1828    unless (chmod(0750, $home_dir, $etc_dir)) {
1829      die("Can't set perms on $home_dir to 0750: $!");
1830    }
1831
1832    unless (chmod(0777, $test_dir)) {
1833      die("Can't set perms on $etc_dir to 0777: $!");
1834    }
1835
1836    unless (chown($uid, $gid, $home_dir, $etc_dir, $test_dir)) {
1837      die("Can't set owner of $home_dir to $uid/$gid: $!");
1838    }
1839
1840  } else {
1841    unless (chmod(0750, $home_dir, $etc_dir)) {
1842      die("Can't set perms on $home_dir to 0750: $!");
1843    }
1844
1845    unless (chmod(0777, $test_dir)) {
1846      die("Can't set perms on $test_dir to 0777: $!");
1847    }
1848  }
1849
1850  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1851    '/bin/bash');
1852  auth_group_write($auth_group_file, $group, $gid, $user);
1853
1854  my $cwd = getcwd();
1855  unless (chdir($test_dir)) {
1856    die("Can't chdir to $test_dir: $!");
1857  }
1858
1859  unless (symlink($auth_user_file, 'authfile.lnk')) {
1860    die("Can't symlink '$auth_user_file' to 'authfile.lnk': $!");
1861  }
1862
1863  unless (chdir($cwd)) {
1864    die("Can't chdir to $cwd: $!");
1865  }
1866
1867  my $config = {
1868    PidFile => $pid_file,
1869    ScoreboardFile => $scoreboard_file,
1870    SystemLog => $log_file,
1871
1872    AuthUserFile => $auth_user_symlink,
1873    AuthGroupFile => $auth_group_file,
1874
1875    IfModules => {
1876      'mod_delay.c' => {
1877        DelayEngine => 'off',
1878      },
1879    },
1880  };
1881
1882  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1883
1884  eval { server_start($config_file, $pid_file) };
1885  unless ($@) {
1886    server_stop($pid_file);
1887
1888    my $ex = "Server started up unexpectedly with symlink AuthUserFile";
1889    test_append_logfile($log_file, $ex);
1890    unlink($log_file);
1891
1892    die($ex);
1893  }
1894
1895  unlink($log_file);
1896}
1897
1898sub auth_user_file_bad_syntax_bug3985 {
1899  my $self = shift;
1900  my $tmpdir = $self->{tmpdir};
1901
1902  my $config_file = "$tmpdir/authfile.conf";
1903  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
1904  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
1905
1906  my $log_file = test_get_logfile();
1907
1908  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
1909  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
1910
1911  my $user = 'proftpd';
1912  my $passwd = 'test';
1913  my $group = 'ftpd';
1914  my $home_dir = File::Spec->rel2abs($tmpdir);
1915  my $uid = 500;
1916  my $gid = 500;
1917
1918  # Make sure that, if we're running as root, that the home directory has
1919  # permissions/privs set for the account we create
1920  if ($< == 0) {
1921    unless (chmod(0755, $home_dir)) {
1922      die("Can't set perms on $home_dir to 0755: $!");
1923    }
1924
1925    unless (chown($uid, $gid, $home_dir)) {
1926      die("Can't set owner of $home_dir to $uid/$gid: $!");
1927    }
1928  }
1929
1930  # Test that mod_auth_file correctly deals with malformed AuthUserFile
1931  # entries (per Bug#3985).
1932  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1933    '/bin/bash', "FirstName:LastName");
1934
1935  auth_group_write($auth_group_file, $group, $gid, $user);
1936
1937  my $config = {
1938    PidFile => $pid_file,
1939    ScoreboardFile => $scoreboard_file,
1940    SystemLog => $log_file,
1941
1942    AuthUserFile => $auth_user_file,
1943    AuthGroupFile => $auth_group_file,
1944
1945    IfModules => {
1946      'mod_delay.c' => {
1947        DelayEngine => 'off',
1948      },
1949    },
1950  };
1951
1952  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1953
1954  # Open pipes, for use between the parent and child processes.  Specifically,
1955  # the child will indicate when it's done with its test by writing a message
1956  # to the parent.
1957  my ($rfh, $wfh);
1958  unless (pipe($rfh, $wfh)) {
1959    die("Can't open pipe: $!");
1960  }
1961
1962  my $ex;
1963
1964  # Fork child
1965  $self->handle_sigchld();
1966  defined(my $pid = fork()) or die("Can't fork: $!");
1967  if ($pid) {
1968    eval {
1969      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1970      eval { $client->login($user, $passwd) };
1971      unless ($@) {
1972        $client->quit();
1973        die("Login succeeded unexpectedly");
1974      }
1975    };
1976
1977    if ($@) {
1978      $ex = $@;
1979    }
1980
1981    $wfh->print("done\n");
1982    $wfh->flush();
1983
1984  } else {
1985    eval { server_wait($config_file, $rfh) };
1986    if ($@) {
1987      warn($@);
1988      exit 1;
1989    }
1990
1991    exit 0;
1992  }
1993
1994  # Stop server
1995  server_stop($pid_file);
1996
1997  $self->assert_child_ok($pid);
1998
1999  if ($ex) {
2000    test_append_logfile($log_file, $ex);
2001    unlink($log_file);
2002
2003    die($ex);
2004  }
2005
2006  unlink($log_file);
2007}
2008
2009sub auth_group_file_bad_syntax_bug3985 {
2010  my $self = shift;
2011  my $tmpdir = $self->{tmpdir};
2012
2013  my $config_file = "$tmpdir/authfile.conf";
2014  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
2015  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
2016
2017  my $log_file = test_get_logfile();
2018
2019  my $auth_user_file = File::Spec->rel2abs("$tmpdir/authfile.passwd");
2020  my $auth_group_file = File::Spec->rel2abs("$tmpdir/authfile.group");
2021
2022  my $user = 'proftpd';
2023  my $passwd = 'test';
2024  my $group = 'ftpd';
2025  my $home_dir = File::Spec->rel2abs($tmpdir);
2026  my $uid = 500;
2027  my $gid = 500;
2028
2029  # Make sure that, if we're running as root, that the home directory has
2030  # permissions/privs set for the account we create
2031  if ($< == 0) {
2032    unless (chmod(0755, $home_dir)) {
2033      die("Can't set perms on $home_dir to 0755: $!");
2034    }
2035
2036    unless (chown($uid, $gid, $home_dir)) {
2037      die("Can't set owner of $home_dir to $uid/$gid: $!");
2038    }
2039  }
2040
2041  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2042    '/bin/bash');
2043
2044  # Test that mod_auth_file correctly deals with malformed AuthGroupFile
2045  # entries (per Bug#3985).
2046  auth_group_write($auth_group_file, "yarr:$group", $gid, $user);
2047
2048  my $config = {
2049    PidFile => $pid_file,
2050    ScoreboardFile => $scoreboard_file,
2051    SystemLog => $log_file,
2052
2053    AuthUserFile => $auth_user_file,
2054    AuthGroupFile => $auth_group_file,
2055
2056    IfModules => {
2057      'mod_delay.c' => {
2058        DelayEngine => 'off',
2059      },
2060    },
2061  };
2062
2063  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2064
2065  if (open(my $fh, ">> $config_file")) {
2066    print $fh <<EOC;
2067<Limit LOGIN>
2068  DenyGroup $group
2069  AllowAll
2070</Limit>
2071EOC
2072
2073    unless (close($fh)) {
2074      die("Can't write $config_file: $!");
2075    }
2076
2077  } else {
2078    die("Can't open $config_file: $!");
2079  }
2080
2081  # Open pipes, for use between the parent and child processes.  Specifically,
2082  # the child will indicate when it's done with its test by writing a message
2083  # to the parent.
2084  my ($rfh, $wfh);
2085  unless (pipe($rfh, $wfh)) {
2086    die("Can't open pipe: $!");
2087  }
2088
2089  my $ex;
2090
2091  # Fork child
2092  $self->handle_sigchld();
2093  defined(my $pid = fork()) or die("Can't fork: $!");
2094  if ($pid) {
2095    eval {
2096      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2097
2098      # Despite the <Limit LOGIN> line for our group, we should still
2099      # succeed in logging in, because of the malformed AuthGroupFile
2100      # entry.
2101      $client->login($user, $passwd);
2102
2103      $client->quit();
2104    };
2105
2106    if ($@) {
2107      $ex = $@;
2108    }
2109
2110    $wfh->print("done\n");
2111    $wfh->flush();
2112
2113  } else {
2114    eval { server_wait($config_file, $rfh) };
2115    if ($@) {
2116      warn($@);
2117      exit 1;
2118    }
2119
2120    exit 0;
2121  }
2122
2123  # Stop server
2124  server_stop($pid_file);
2125
2126  $self->assert_child_ok($pid);
2127
2128  if ($ex) {
2129    test_append_logfile($log_file, $ex);
2130    unlink($log_file);
2131
2132    die($ex);
2133  }
2134
2135  unlink($log_file);
2136}
2137
2138sub auth_file_symlink_segfault_bug4145 {
2139  my $self = shift;
2140  my $tmpdir = $self->{tmpdir};
2141
2142  my $config_file = "$tmpdir/authfile.conf";
2143  my $pid_file = File::Spec->rel2abs("$tmpdir/authfile.pid");
2144  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/authfile.scoreboard");
2145
2146  my $log_file = test_get_logfile();
2147
2148  my $authfiles_parent_dir = File::Spec->rel2abs("$tmpdir/etc");
2149  mkpath($authfiles_parent_dir);
2150
2151  my $authfiles_dir = File::Spec->rel2abs("$authfiles_parent_dir/proftpd");
2152  mkpath($authfiles_dir);
2153
2154  my $auth_user_file = File::Spec->rel2abs("$authfiles_dir/authfile.passwd");
2155  my $auth_group_file = File::Spec->rel2abs("$authfiles_dir/authfile.group");
2156
2157  # Create symlinks using a relative path to the Auth files, to reproduce
2158  # Bug#4145.
2159  my $cwd = getcwd();
2160  unless (chdir($authfiles_dir)) {
2161    die("Can't chdir to $authfiles_dir: $!");
2162  }
2163
2164  unless (symlink('authfile.passwd', "passwd.lnk")) {
2165    die("Can't symlink '$auth_user_file' to 'passwd.lnk': $!");
2166  }
2167
2168  unless (symlink('authfile.group', "group.lnk")) {
2169    die("Can't symlink '$auth_group_file' to 'group.lnk': $!");
2170  }
2171
2172  unless (chdir($cwd)) {
2173    die("Can't chdir to $cwd: $!");
2174  }
2175
2176  my $auth_user_symlink = File::Spec->rel2abs($authfiles_dir) . "/passwd.lnk";
2177  my $auth_group_symlink = File::Spec->rel2abs($authfiles_dir) . "/group.lnk";
2178
2179  my $user = 'proftpd';
2180  my $passwd = 'test';
2181  my $group = 'ftpd';
2182  my $home_dir = File::Spec->rel2abs($tmpdir);
2183  my $uid = 500;
2184  my $gid = 500;
2185
2186  # Make sure that, if we're running as root, that the home directory has
2187  # permissions/privs set for the account we create
2188  if ($< == 0) {
2189    unless (chmod(0755, $home_dir, $authfiles_parent_dir, $authfiles_dir)) {
2190      die("Can't set perms on $home_dir to 0755: $!");
2191    }
2192
2193    unless (chown($uid, $gid, $home_dir, $authfiles_parent_dir, $authfiles_dir)) {
2194      die("Can't set owner of $home_dir to $uid/$gid: $!");
2195    }
2196  }
2197
2198  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2199    '/bin/bash');
2200
2201  # Test that mod_auth_file correctly deals with malformed AuthGroupFile
2202  # entries (per Bug#3985).
2203  auth_group_write($auth_group_file, "yarr:$group", $gid, $user);
2204
2205  my $config = {
2206    PidFile => $pid_file,
2207    ScoreboardFile => $scoreboard_file,
2208    SystemLog => $log_file,
2209
2210    AuthUserFile => $auth_user_symlink,
2211    AuthGroupFile => $auth_group_symlink,
2212
2213    IfModules => {
2214      'mod_delay.c' => {
2215        DelayEngine => 'off',
2216      },
2217    },
2218  };
2219
2220  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2221
2222  # Open pipes, for use between the parent and child processes.  Specifically,
2223  # the child will indicate when it's done with its test by writing a message
2224  # to the parent.
2225  my ($rfh, $wfh);
2226  unless (pipe($rfh, $wfh)) {
2227    die("Can't open pipe: $!");
2228  }
2229
2230  my $ex;
2231
2232  # Fork child
2233  $self->handle_sigchld();
2234  defined(my $pid = fork()) or die("Can't fork: $!");
2235  if ($pid) {
2236    eval {
2237      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2238      $client->login($user, $passwd);
2239      $client->quit();
2240    };
2241
2242    if ($@) {
2243      $ex = $@;
2244    }
2245
2246    $wfh->print("done\n");
2247    $wfh->flush();
2248
2249  } else {
2250    eval { server_wait($config_file, $rfh) };
2251    if ($@) {
2252      warn($@);
2253      exit 1;
2254    }
2255
2256    exit 0;
2257  }
2258
2259  # Stop server
2260  server_stop($pid_file);
2261
2262  $self->assert_child_ok($pid);
2263
2264  if ($ex) {
2265    test_append_logfile($log_file, $ex);
2266    unlink($log_file);
2267
2268    die($ex);
2269  }
2270
2271  unlink($log_file);
2272}
2273
22741;
2275