1package ProFTPD::Tests::Modules::mod_lang;
2
3use lib qw(t/lib);
4use base qw(ProFTPD::TestSuite::Child);
5use strict;
6
7use File::Copy;
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  lang_feat_default => {
21    order => ++$order,
22    test_class => [qw(forking)],
23  },
24
25  lang_feat_engine_off => {
26    order => ++$order,
27    test_class => [qw(forking)],
28  },
29
30  lang_lang_none_ok => {
31    order => ++$order,
32    test_class => [qw(forking)],
33  },
34
35  lang_lang_env_ok => {
36    order => ++$order,
37    test_class => [qw(forking)],
38  },
39
40  lang_lang_default_ok => {
41    order => ++$order,
42    test_class => [qw(forking)],
43  },
44
45  lang_lang_unknown_failed => {
46    order => ++$order,
47    test_class => [qw(forking)],
48  },
49
50  lang_opts_utf8_ok => {
51    order => ++$order,
52    test_class => [qw(forking)],
53  },
54
55  lang_opts_utf8_nonbool_failed => {
56    order => ++$order,
57    test_class => [qw(forking)],
58  },
59
60  lang_lang_default_en_US => {
61    order => ++$order,
62    test_class => [qw(forking)],
63  },
64
65  lang_lang_default_en_US_UTF8 => {
66    order => ++$order,
67    test_class => [qw(forking)],
68  },
69
70  lang_opts_utf8_useencoding_on => {
71    order => ++$order,
72    test_class => [qw(forking)],
73  },
74
75  lang_opts_utf8_useencoding_off => {
76    order => ++$order,
77    test_class => [qw(forking)],
78  },
79
80  lang_opts_utf8_useencoding_charsets => {
81    order => ++$order,
82    test_class => [qw(forking)],
83  },
84
85  lang_opts_utf8_useencoding_charsets_strict => {
86    order => ++$order,
87    test_class => [qw(forking)],
88  },
89
90  lang_opts_utf8_useencoding_charsets_strict_with_utf8 => {
91    order => ++$order,
92    test_class => [qw(forking)],
93  },
94
95  lang_opts_utf8_useencoding_charsets_with_env => {
96    order => ++$order,
97    test_class => [qw(forking)],
98  },
99
100  lang_useencoding_latin1_utf8 => {
101    order => ++$order,
102    test_class => [qw(forking)],
103  },
104
105  lang_useencoding_utf8_latin1 => {
106    order => ++$order,
107    test_class => [qw(forking)],
108  },
109
110  lang_opts_utf8_prefer_server_encoding_bug4125 => {
111    order => ++$order,
112    test_class => [qw(bug forking)],
113  },
114
115  lang_opts_utf8_useencoding_charsets_prefer_server_encoding_bug4125 => {
116    order => ++$order,
117    test_class => [qw(bug forking)],
118  },
119
120  lang_useencoding_ascii_utf8_require_valid_encoding_bug4125 => {
121    order => ++$order,
122    test_class => [qw(bug forking)],
123  },
124
125  lang_useencoding_latin1_utf8_per_user_bug4214 => {
126    order => ++$order,
127    test_class => [qw(forking mod_ifsession)],
128  },
129
130  lang_useencoding_utf8_latin1_per_user_bug4214 => {
131    order => ++$order,
132    test_class => [qw(forking mod_ifsession)],
133  },
134
135};
136
137sub new {
138  return shift()->SUPER::new(@_);
139}
140
141sub list_tests {
142  return testsuite_get_runnable_tests($TESTS);
143}
144
145sub lang_feat_default {
146  my $self = shift;
147  my $tmpdir = $self->{tmpdir};
148
149  my $config_file = "$tmpdir/lang.conf";
150  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
151  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
152
153  my $log_file = test_get_logfile();
154
155  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
156  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
157
158  my $user = 'proftpd';
159  my $passwd = 'test';
160  my $group = 'ftpd';
161  my $home_dir = File::Spec->rel2abs($tmpdir);
162  my $uid = 500;
163  my $gid = 500;
164
165  # Make sure that, if we're running as root, that the home directory has
166  # permissions/privs set for the account we create
167  if ($< == 0) {
168    unless (chmod(0755, $home_dir)) {
169      die("Can't set perms on $home_dir to 0755: $!");
170    }
171
172    unless (chown($uid, $gid, $home_dir)) {
173      die("Can't set owner of $home_dir to $uid/$gid: $!");
174    }
175  }
176
177  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
178    '/bin/bash');
179  auth_group_write($auth_group_file, $group, $gid, $user);
180
181  my $config = {
182    PidFile => $pid_file,
183    ScoreboardFile => $scoreboard_file,
184    SystemLog => $log_file,
185
186    AuthUserFile => $auth_user_file,
187    AuthGroupFile => $auth_group_file,
188
189    IfModules => {
190      'mod_delay.c' => {
191        DelayEngine => 'off',
192      },
193    },
194  };
195
196  my ($port, $config_user, $config_group) = config_write($config_file, $config);
197
198  # Open pipes, for use between the parent and child processes.  Specifically,
199  # the child will indicate when it's done with its test by writing a message
200  # to the parent.
201  my ($rfh, $wfh);
202  unless (pipe($rfh, $wfh)) {
203    die("Can't open pipe: $!");
204  }
205
206  my $ex;
207
208  # Fork child
209  $self->handle_sigchld();
210  defined(my $pid = fork()) or die("Can't fork: $!");
211  if ($pid) {
212    eval {
213      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
214      $client->login($user, $passwd);
215
216      $client->feat();
217      my $resp_code = $client->response_code();
218      my $resp_msgs = $client->response_msgs();
219
220      my $expected;
221
222      $expected = 211;
223      $self->assert($expected == $resp_code,
224        test_msg("Expected $expected, got $resp_code"));
225
226      my $feats = {
227        ' UTF8' => 1,
228
229        # One of the following will appear in the FEAT list, depending
230        # on the underlying platform.
231        ' LANG en_US' => 1,
232        ' LANG en-US' => 1,
233        ' LANG en-US*' => 1,
234        ' LANG en_US.UTF-8' => 1,
235        ' LANG en-US.UTF-8' => 1,
236        ' LANG en-US.UTF-8*' => 1,
237      };
238
239      my $seen = 0;
240
241      my $nfeat = scalar(@$resp_msgs);
242      for (my $i = 0; $i < $nfeat; $i++) {
243        if (defined($feats->{$resp_msgs->[$i]})) {
244          $seen++;
245        }
246      }
247
248      $expected = 2;
249      $self->assert($expected == $seen,
250        test_msg("Expected $expected, got $seen"));
251    };
252
253    if ($@) {
254      $ex = $@;
255    }
256
257    $wfh->print("done\n");
258    $wfh->flush();
259
260  } else {
261    eval { server_wait($config_file, $rfh) };
262    if ($@) {
263      warn($@);
264      exit 1;
265    }
266
267    exit 0;
268  }
269
270  # Stop server
271  server_stop($pid_file);
272
273  $self->assert_child_ok($pid);
274
275  if ($ex) {
276    test_append_logfile($log_file, $ex);
277    unlink($log_file);
278
279    die($ex);
280  }
281
282  unlink($log_file);
283}
284
285sub lang_feat_engine_off {
286  my $self = shift;
287  my $tmpdir = $self->{tmpdir};
288
289  my $config_file = "$tmpdir/lang.conf";
290  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
291  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
292
293  my $log_file = test_get_logfile();
294
295  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
296  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
297
298  my $user = 'proftpd';
299  my $passwd = 'test';
300  my $group = 'ftpd';
301  my $home_dir = File::Spec->rel2abs($tmpdir);
302  my $uid = 500;
303  my $gid = 500;
304
305  # Make sure that, if we're running as root, that the home directory has
306  # permissions/privs set for the account we create
307  if ($< == 0) {
308    unless (chmod(0755, $home_dir)) {
309      die("Can't set perms on $home_dir to 0755: $!");
310    }
311
312    unless (chown($uid, $gid, $home_dir)) {
313      die("Can't set owner of $home_dir to $uid/$gid: $!");
314    }
315  }
316
317  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
318    '/bin/bash');
319  auth_group_write($auth_group_file, $group, $gid, $user);
320
321  my $config = {
322    PidFile => $pid_file,
323    ScoreboardFile => $scoreboard_file,
324    SystemLog => $log_file,
325
326    AuthUserFile => $auth_user_file,
327    AuthGroupFile => $auth_group_file,
328
329    IfModules => {
330      'mod_delay.c' => {
331        DelayEngine => 'off',
332      },
333
334      'mod_lang.c' => {
335        LangEngine => 'off',
336      },
337    },
338  };
339
340  my ($port, $config_user, $config_group) = config_write($config_file, $config);
341
342  # Open pipes, for use between the parent and child processes.  Specifically,
343  # the child will indicate when it's done with its test by writing a message
344  # to the parent.
345  my ($rfh, $wfh);
346  unless (pipe($rfh, $wfh)) {
347    die("Can't open pipe: $!");
348  }
349
350  my $ex;
351
352  # Fork child
353  $self->handle_sigchld();
354  defined(my $pid = fork()) or die("Can't fork: $!");
355  if ($pid) {
356    eval {
357      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
358      $client->login($user, $passwd);
359
360      $client->feat();
361      my $resp_code = $client->response_code();
362      my $resp_msgs = $client->response_msgs();
363
364      my $expected;
365
366      $expected = 211;
367      $self->assert($expected == $resp_code,
368        test_msg("Expected $expected, got $resp_code"));
369
370      my $feats = {
371        # None of the following should appear in the FEAT list
372
373        ' UTF8' => 1,
374        ' LANG en_US' => 1,
375        ' LANG en-US' => 1,
376        ' LANG en-US*' => 1,
377        ' LANG en_US.UTF-8' => 1,
378        ' LANG en-US.UTF-8' => 1,
379        ' LANG en-US.UTF-8*' => 1,
380      };
381
382      my $seen = 0;
383
384      my $nfeat = scalar(@$resp_msgs);
385      for (my $i = 0; $i < $nfeat; $i++) {
386        if (defined($feats->{$resp_msgs->[$i]})) {
387          $seen++;
388        }
389      }
390
391      $expected = 0;
392      $self->assert($expected == $seen,
393        test_msg("Expected $expected, got $seen"));
394    };
395
396    if ($@) {
397      $ex = $@;
398    }
399
400    $wfh->print("done\n");
401    $wfh->flush();
402
403  } else {
404    eval { server_wait($config_file, $rfh) };
405    if ($@) {
406      warn($@);
407      exit 1;
408    }
409
410    exit 0;
411  }
412
413  # Stop server
414  server_stop($pid_file);
415
416  $self->assert_child_ok($pid);
417
418  if ($ex) {
419    test_append_logfile($log_file, $ex);
420    unlink($log_file);
421
422    die($ex);
423  }
424
425  unlink($log_file);
426}
427
428sub lang_lang_none_ok {
429  my $self = shift;
430  my $tmpdir = $self->{tmpdir};
431
432  my $config_file = "$tmpdir/lang.conf";
433  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
434  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
435
436  my $log_file = test_get_logfile();
437
438  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
439  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
440
441  my $user = 'proftpd';
442  my $passwd = 'test';
443  my $group = 'ftpd';
444  my $home_dir = File::Spec->rel2abs($tmpdir);
445  my $uid = 500;
446  my $gid = 500;
447
448  # Make sure that, if we're running as root, that the home directory has
449  # permissions/privs set for the account we create
450  if ($< == 0) {
451    unless (chmod(0755, $home_dir)) {
452      die("Can't set perms on $home_dir to 0755: $!");
453    }
454
455    unless (chown($uid, $gid, $home_dir)) {
456      die("Can't set owner of $home_dir to $uid/$gid: $!");
457    }
458  }
459
460  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
461    '/bin/bash');
462  auth_group_write($auth_group_file, $group, $gid, $user);
463
464  my $config = {
465    PidFile => $pid_file,
466    ScoreboardFile => $scoreboard_file,
467    SystemLog => $log_file,
468
469    AuthUserFile => $auth_user_file,
470    AuthGroupFile => $auth_group_file,
471
472    IfModules => {
473      'mod_delay.c' => {
474        DelayEngine => 'off',
475      },
476    },
477  };
478
479  my ($port, $config_user, $config_group) = config_write($config_file, $config);
480
481  # Open pipes, for use between the parent and child processes.  Specifically,
482  # the child will indicate when it's done with its test by writing a message
483  # to the parent.
484  my ($rfh, $wfh);
485  unless (pipe($rfh, $wfh)) {
486    die("Can't open pipe: $!");
487  }
488
489  my $ex;
490
491  # Fork child
492  $self->handle_sigchld();
493  defined(my $pid = fork()) or die("Can't fork: $!");
494  if ($pid) {
495    eval {
496      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
497
498      my ($resp_code, $resp_msg) = $client->lang();
499
500      my $expected;
501
502      $expected = 200;
503      $self->assert($expected == $resp_code,
504        test_msg("Expected $expected, got $resp_code"));
505
506      $expected = 'Using default language \S+';
507      $self->assert(qr/$expected/, $resp_msg,
508        test_msg("Expected '$expected', got '$resp_msg'"));
509    };
510
511    if ($@) {
512      $ex = $@;
513    }
514
515    $wfh->print("done\n");
516    $wfh->flush();
517
518  } else {
519    eval { server_wait($config_file, $rfh) };
520    if ($@) {
521      warn($@);
522      exit 1;
523    }
524
525    exit 0;
526  }
527
528  # Stop server
529  server_stop($pid_file);
530
531  $self->assert_child_ok($pid);
532
533  if ($ex) {
534    test_append_logfile($log_file, $ex);
535    unlink($log_file);
536
537    die($ex);
538  }
539
540  unlink($log_file);
541}
542
543sub lang_lang_env_ok {
544  my $self = shift;
545  my $tmpdir = $self->{tmpdir};
546
547  my $config_file = "$tmpdir/lang.conf";
548  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
549  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
550
551  my $log_file = test_get_logfile();
552
553  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
554  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
555
556  my $user = 'proftpd';
557  my $passwd = 'test';
558  my $group = 'ftpd';
559  my $home_dir = File::Spec->rel2abs($tmpdir);
560  my $uid = 500;
561  my $gid = 500;
562
563  # Make sure that, if we're running as root, that the home directory has
564  # permissions/privs set for the account we create
565  if ($< == 0) {
566    unless (chmod(0755, $home_dir)) {
567      die("Can't set perms on $home_dir to 0755: $!");
568    }
569
570    unless (chown($uid, $gid, $home_dir)) {
571      die("Can't set owner of $home_dir to $uid/$gid: $!");
572    }
573  }
574
575  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
576    '/bin/bash');
577  auth_group_write($auth_group_file, $group, $gid, $user);
578
579  my $config = {
580    PidFile => $pid_file,
581    ScoreboardFile => $scoreboard_file,
582    SystemLog => $log_file,
583
584    AuthUserFile => $auth_user_file,
585    AuthGroupFile => $auth_group_file,
586
587    IfModules => {
588      'mod_delay.c' => {
589        DelayEngine => 'off',
590      },
591    },
592  };
593
594  my ($port, $config_user, $config_group) = config_write($config_file, $config);
595
596  my $lang = 'en_US';
597
598  # Open pipes, for use between the parent and child processes.  Specifically,
599  # the child will indicate when it's done with its test by writing a message
600  # to the parent.
601  my ($rfh, $wfh);
602  unless (pipe($rfh, $wfh)) {
603    die("Can't open pipe: $!");
604  }
605
606  my $ex;
607
608  # Fork child
609  $self->handle_sigchld();
610  defined(my $pid = fork()) or die("Can't fork: $!");
611  if ($pid) {
612    eval {
613      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
614
615      my ($resp_code, $resp_msg) = $client->lang();
616
617      my $expected;
618
619      $expected = 200;
620      $self->assert($expected == $resp_code,
621        test_msg("Expected $expected, got $resp_code"));
622
623      $expected = "Using default language $lang";
624      $self->assert(qr/$expected/, $resp_msg,
625        test_msg("Expected '$expected', got '$resp_msg'"));
626    };
627
628    if ($@) {
629      $ex = $@;
630    }
631
632    $wfh->print("done\n");
633    $wfh->flush();
634
635  } else {
636    # Specify a LANG environment variable, for mod_lang to pick up
637    $ENV{LANG} = $lang;
638
639    eval { server_wait($config_file, $rfh) };
640    if ($@) {
641      warn($@);
642      exit 1;
643    }
644
645    exit 0;
646  }
647
648  # Stop server
649  server_stop($pid_file);
650
651  $self->assert_child_ok($pid);
652
653  if ($ex) {
654    test_append_logfile($log_file, $ex);
655    unlink($log_file);
656
657    die($ex);
658  }
659
660  unlink($log_file);
661}
662
663sub lang_lang_default_ok {
664  my $self = shift;
665  my $tmpdir = $self->{tmpdir};
666
667  my $config_file = "$tmpdir/lang.conf";
668  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
669  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
670
671  my $log_file = test_get_logfile();
672
673  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
674  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
675
676  my $user = 'proftpd';
677  my $passwd = 'test';
678  my $group = 'ftpd';
679  my $home_dir = File::Spec->rel2abs($tmpdir);
680  my $uid = 500;
681  my $gid = 500;
682
683  # Make sure that, if we're running as root, that the home directory has
684  # permissions/privs set for the account we create
685  if ($< == 0) {
686    unless (chmod(0755, $home_dir)) {
687      die("Can't set perms on $home_dir to 0755: $!");
688    }
689
690    unless (chown($uid, $gid, $home_dir)) {
691      die("Can't set owner of $home_dir to $uid/$gid: $!");
692    }
693  }
694
695  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
696    '/bin/bash');
697  auth_group_write($auth_group_file, $group, $gid, $user);
698
699  my $config = {
700    PidFile => $pid_file,
701    ScoreboardFile => $scoreboard_file,
702    SystemLog => $log_file,
703
704    AuthUserFile => $auth_user_file,
705    AuthGroupFile => $auth_group_file,
706
707    IfModules => {
708      'mod_delay.c' => {
709        DelayEngine => 'off',
710      },
711    },
712  };
713
714  my ($port, $config_user, $config_group) = config_write($config_file, $config);
715
716  # Open pipes, for use between the parent and child processes.  Specifically,
717  # the child will indicate when it's done with its test by writing a message
718  # to the parent.
719  my ($rfh, $wfh);
720  unless (pipe($rfh, $wfh)) {
721    die("Can't open pipe: $!");
722  }
723
724  my $ex;
725
726  # Fork child
727  $self->handle_sigchld();
728  defined(my $pid = fork()) or die("Can't fork: $!");
729  if ($pid) {
730    eval {
731      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
732
733      my ($resp_code, $resp_msg);
734
735      # First, find out what the default language is.
736      ($resp_code, $resp_msg) = $client->lang();
737
738      my $expected;
739
740      $expected = 200;
741      $self->assert($expected == $resp_code,
742        test_msg("Expected $expected, got $resp_code"));
743
744      $expected = '^Using default language (\S+)$';
745      $self->assert(qr/$expected/, $resp_msg,
746        test_msg("Expected '$expected', got '$resp_msg'"));
747
748      $resp_msg =~ /$expected/;
749      my $default_lang = $1;
750
751      ($resp_code, $resp_msg) = $client->lang($default_lang);
752
753      $expected = 200;
754      $self->assert($expected == $resp_code,
755        test_msg("Expected $expected, got $resp_code"));
756
757      $expected = "Using language $default_lang";
758      $self->assert($expected eq $resp_msg,
759        test_msg("Expected '$expected', got '$resp_msg'"));
760    };
761
762    if ($@) {
763      $ex = $@;
764    }
765
766    $wfh->print("done\n");
767    $wfh->flush();
768
769  } else {
770    eval { server_wait($config_file, $rfh) };
771    if ($@) {
772      warn($@);
773      exit 1;
774    }
775
776    exit 0;
777  }
778
779  # Stop server
780  server_stop($pid_file);
781
782  $self->assert_child_ok($pid);
783
784  if ($ex) {
785    test_append_logfile($log_file, $ex);
786    unlink($log_file);
787
788    die($ex);
789  }
790
791  unlink($log_file);
792}
793
794sub lang_lang_unknown_failed {
795  my $self = shift;
796  my $tmpdir = $self->{tmpdir};
797
798  my $config_file = "$tmpdir/lang.conf";
799  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
800  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
801
802  my $log_file = test_get_logfile();
803
804  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
805  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
806
807  my $user = 'proftpd';
808  my $passwd = 'test';
809  my $group = 'ftpd';
810  my $home_dir = File::Spec->rel2abs($tmpdir);
811  my $uid = 500;
812  my $gid = 500;
813
814  # Make sure that, if we're running as root, that the home directory has
815  # permissions/privs set for the account we create
816  if ($< == 0) {
817    unless (chmod(0755, $home_dir)) {
818      die("Can't set perms on $home_dir to 0755: $!");
819    }
820
821    unless (chown($uid, $gid, $home_dir)) {
822      die("Can't set owner of $home_dir to $uid/$gid: $!");
823    }
824  }
825
826  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
827    '/bin/bash');
828  auth_group_write($auth_group_file, $group, $gid, $user);
829
830  my $config = {
831    PidFile => $pid_file,
832    ScoreboardFile => $scoreboard_file,
833    SystemLog => $log_file,
834
835    AuthUserFile => $auth_user_file,
836    AuthGroupFile => $auth_group_file,
837
838    IfModules => {
839      'mod_delay.c' => {
840        DelayEngine => 'off',
841      },
842    },
843  };
844
845  my ($port, $config_user, $config_group) = config_write($config_file, $config);
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
864      my ($resp_code, $resp_msg);
865
866      eval { $client->lang('foobarbaz') };
867      unless ($@) {
868        die("LANG succeeded unexpectedly");
869
870      } else {
871        $resp_code = $client->response_code();
872        $resp_msg = $client->response_msg();
873      }
874
875      my $expected;
876
877      $expected = 504;
878      $self->assert($expected == $resp_code,
879        test_msg("Expected $expected, got $resp_code"));
880
881      $expected = 'Language foobarbaz not supported';
882      $self->assert($expected eq $resp_msg,
883        test_msg("Expected '$expected', got '$resp_msg'"));
884    };
885
886    if ($@) {
887      $ex = $@;
888    }
889
890    $wfh->print("done\n");
891    $wfh->flush();
892
893  } else {
894    eval { server_wait($config_file, $rfh) };
895    if ($@) {
896      warn($@);
897      exit 1;
898    }
899
900    exit 0;
901  }
902
903  # Stop server
904  server_stop($pid_file);
905
906  $self->assert_child_ok($pid);
907
908  if ($ex) {
909    test_append_logfile($log_file, $ex);
910    unlink($log_file);
911
912    die($ex);
913  }
914
915  unlink($log_file);
916}
917
918sub lang_opts_utf8_ok {
919  my $self = shift;
920  my $tmpdir = $self->{tmpdir};
921
922  my $config_file = "$tmpdir/lang.conf";
923  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
924  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
925
926  my $log_file = test_get_logfile();
927
928  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
929  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
930
931  my $user = 'proftpd';
932  my $passwd = 'test';
933  my $group = 'ftpd';
934  my $home_dir = File::Spec->rel2abs($tmpdir);
935  my $uid = 500;
936  my $gid = 500;
937
938  # Make sure that, if we're running as root, that the home directory has
939  # permissions/privs set for the account we create
940  if ($< == 0) {
941    unless (chmod(0755, $home_dir)) {
942      die("Can't set perms on $home_dir to 0755: $!");
943    }
944
945    unless (chown($uid, $gid, $home_dir)) {
946      die("Can't set owner of $home_dir to $uid/$gid: $!");
947    }
948  }
949
950  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
951    '/bin/bash');
952  auth_group_write($auth_group_file, $group, $gid, $user);
953
954  my $config = {
955    PidFile => $pid_file,
956    ScoreboardFile => $scoreboard_file,
957    SystemLog => $log_file,
958
959    AuthUserFile => $auth_user_file,
960    AuthGroupFile => $auth_group_file,
961
962    IfModules => {
963      'mod_delay.c' => {
964        DelayEngine => 'off',
965      },
966    },
967  };
968
969  my ($port, $config_user, $config_group) = config_write($config_file, $config);
970
971  # Open pipes, for use between the parent and child processes.  Specifically,
972  # the child will indicate when it's done with its test by writing a message
973  # to the parent.
974  my ($rfh, $wfh);
975  unless (pipe($rfh, $wfh)) {
976    die("Can't open pipe: $!");
977  }
978
979  my $ex;
980
981  # Fork child
982  $self->handle_sigchld();
983  defined(my $pid = fork()) or die("Can't fork: $!");
984  if ($pid) {
985    eval {
986      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
987      my ($resp_code, $resp_msg) = $client->opts('UTF8', 'off');
988
989      my $expected;
990
991      $expected = 200;
992      $self->assert($expected == $resp_code,
993        test_msg("Expected response code $expected, got $resp_code"));
994
995      $expected = 'UTF8 set to off';
996      $self->assert($expected eq $resp_msg,
997        test_msg("Expected response message '$expected', got '$resp_msg'"));
998
999      ($resp_code, $resp_msg) = $client->opts('UTF8', 'on');
1000
1001      $expected = 200;
1002      $self->assert($expected == $resp_code,
1003        test_msg("Expected response code $expected, got $resp_code"));
1004
1005      $expected = 'UTF8 set to on';
1006      $self->assert($expected eq $resp_msg,
1007        test_msg("Expected response message '$expected', got '$resp_msg'"));
1008    };
1009
1010    if ($@) {
1011      $ex = $@;
1012    }
1013
1014    $wfh->print("done\n");
1015    $wfh->flush();
1016
1017  } else {
1018    eval { server_wait($config_file, $rfh) };
1019    if ($@) {
1020      warn($@);
1021      exit 1;
1022    }
1023
1024    exit 0;
1025  }
1026
1027  # Stop server
1028  server_stop($pid_file);
1029
1030  $self->assert_child_ok($pid);
1031
1032  if ($ex) {
1033    test_append_logfile($log_file, $ex);
1034    unlink($log_file);
1035
1036    die($ex);
1037  }
1038
1039  unlink($log_file);
1040}
1041
1042sub lang_opts_utf8_nonbool_failed {
1043  my $self = shift;
1044  my $tmpdir = $self->{tmpdir};
1045
1046  my $config_file = "$tmpdir/lang.conf";
1047  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
1048  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
1049
1050  my $log_file = test_get_logfile();
1051
1052  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
1053  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
1054
1055  my $user = 'proftpd';
1056  my $passwd = 'test';
1057  my $group = 'ftpd';
1058  my $home_dir = File::Spec->rel2abs($tmpdir);
1059  my $uid = 500;
1060  my $gid = 500;
1061
1062  # Make sure that, if we're running as root, that the home directory has
1063  # permissions/privs set for the account we create
1064  if ($< == 0) {
1065    unless (chmod(0755, $home_dir)) {
1066      die("Can't set perms on $home_dir to 0755: $!");
1067    }
1068
1069    unless (chown($uid, $gid, $home_dir)) {
1070      die("Can't set owner of $home_dir to $uid/$gid: $!");
1071    }
1072  }
1073
1074  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1075    '/bin/bash');
1076  auth_group_write($auth_group_file, $group, $gid, $user);
1077
1078  my $config = {
1079    PidFile => $pid_file,
1080    ScoreboardFile => $scoreboard_file,
1081    SystemLog => $log_file,
1082
1083    AuthUserFile => $auth_user_file,
1084    AuthGroupFile => $auth_group_file,
1085
1086    IfModules => {
1087      'mod_delay.c' => {
1088        DelayEngine => 'off',
1089      },
1090    },
1091  };
1092
1093  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1094
1095  # Open pipes, for use between the parent and child processes.  Specifically,
1096  # the child will indicate when it's done with its test by writing a message
1097  # to the parent.
1098  my ($rfh, $wfh);
1099  unless (pipe($rfh, $wfh)) {
1100    die("Can't open pipe: $!");
1101  }
1102
1103  my $ex;
1104
1105  # Fork child
1106  $self->handle_sigchld();
1107  defined(my $pid = fork()) or die("Can't fork: $!");
1108  if ($pid) {
1109    eval {
1110      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1111
1112      my ($resp_code, $resp_msg);
1113
1114      eval { $client->opts('UTF8', 'foobar') };
1115      unless ($@) {
1116        die("OPTS UTF8 succeeded unexpectedly");
1117
1118      } else {
1119        $resp_code = $client->response_code();
1120        $resp_msg = $client->response_msg();
1121      }
1122
1123      my $expected;
1124
1125      $expected = 501;
1126      $self->assert($expected == $resp_code,
1127        test_msg("Expected $expected, got $resp_code"));
1128
1129      $expected = "'OPTS UTF8' not understood";
1130      $self->assert($expected eq $resp_msg,
1131        test_msg("Expected '$expected', got '$resp_msg'"));
1132    };
1133
1134    if ($@) {
1135      $ex = $@;
1136    }
1137
1138    $wfh->print("done\n");
1139    $wfh->flush();
1140
1141  } else {
1142    eval { server_wait($config_file, $rfh) };
1143    if ($@) {
1144      warn($@);
1145      exit 1;
1146    }
1147
1148    exit 0;
1149  }
1150
1151  # Stop server
1152  server_stop($pid_file);
1153
1154  $self->assert_child_ok($pid);
1155
1156  if ($ex) {
1157    test_append_logfile($log_file, $ex);
1158    unlink($log_file);
1159
1160    die($ex);
1161  }
1162
1163  unlink($log_file);
1164}
1165
1166sub lang_lang_default_en_US {
1167  my $self = shift;
1168  my $tmpdir = $self->{tmpdir};
1169
1170  my $config_file = "$tmpdir/lang.conf";
1171  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
1172  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
1173
1174  my $log_file = test_get_logfile();
1175
1176  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
1177  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
1178
1179  my $user = 'proftpd';
1180  my $passwd = 'test';
1181  my $group = 'ftpd';
1182  my $home_dir = File::Spec->rel2abs($tmpdir);
1183  my $uid = 500;
1184  my $gid = 500;
1185
1186  # Make sure that, if we're running as root, that the home directory has
1187  # permissions/privs set for the account we create
1188  if ($< == 0) {
1189    unless (chmod(0755, $home_dir)) {
1190      die("Can't set perms on $home_dir to 0755: $!");
1191    }
1192
1193    unless (chown($uid, $gid, $home_dir)) {
1194      die("Can't set owner of $home_dir to $uid/$gid: $!");
1195    }
1196  }
1197
1198  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1199    '/bin/bash');
1200  auth_group_write($auth_group_file, $group, $gid, $user);
1201
1202  # Copy the en_US.mo file from the locale/ directory into a directory
1203  # that we can tell mod_lang to find.
1204
1205  my $lang_path = File::Spec->rel2abs("$tmpdir/locale");
1206  mkpath("$lang_path/en_US/LC_MESSAGES");
1207
1208  copy("../locale/en_US.mo", "$lang_path/en_US/LC_MESSAGES/proftpd.mo");
1209
1210  my $config = {
1211    PidFile => $pid_file,
1212    ScoreboardFile => $scoreboard_file,
1213    SystemLog => $log_file,
1214
1215    AuthUserFile => $auth_user_file,
1216    AuthGroupFile => $auth_group_file,
1217
1218    IfModules => {
1219      'mod_delay.c' => {
1220        DelayEngine => 'off',
1221      },
1222
1223      'mod_lang.c' => {
1224        LangPath => $lang_path,
1225        LangDefault => 'en_US',
1226      },
1227    },
1228  };
1229
1230  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1231
1232  # Open pipes, for use between the parent and child processes.  Specifically,
1233  # the child will indicate when it's done with its test by writing a message
1234  # to the parent.
1235  my ($rfh, $wfh);
1236  unless (pipe($rfh, $wfh)) {
1237    die("Can't open pipe: $!");
1238  }
1239
1240  my $ex;
1241
1242  # Fork child
1243  $self->handle_sigchld();
1244  defined(my $pid = fork()) or die("Can't fork: $!");
1245  if ($pid) {
1246    eval {
1247      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1248      my ($resp_code, $resp_msg) = $client->user($user);
1249
1250      my $expected;
1251
1252      $expected = 331;
1253      $self->assert($expected == $resp_code,
1254        test_msg("Expected $expected, got $resp_code"));
1255
1256      $expected = "Password required for $user";
1257      $self->assert($expected eq $resp_msg,
1258        test_msg("Expected '$expected', got '$resp_msg'"));
1259    };
1260
1261    if ($@) {
1262      $ex = $@;
1263    }
1264
1265    $wfh->print("done\n");
1266    $wfh->flush();
1267
1268  } else {
1269    eval { server_wait($config_file, $rfh) };
1270    if ($@) {
1271      warn($@);
1272      exit 1;
1273    }
1274
1275    exit 0;
1276  }
1277
1278  # Stop server
1279  server_stop($pid_file);
1280
1281  $self->assert_child_ok($pid);
1282
1283  if ($ex) {
1284    test_append_logfile($log_file, $ex);
1285    unlink($log_file);
1286
1287    die($ex);
1288  }
1289
1290  unlink($log_file);
1291}
1292
1293sub lang_lang_default_en_US_UTF8 {
1294  my $self = shift;
1295  my $tmpdir = $self->{tmpdir};
1296
1297  my $config_file = "$tmpdir/lang.conf";
1298  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
1299  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
1300
1301  my $log_file = test_get_logfile();
1302
1303  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
1304  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
1305
1306  my $user = 'proftpd';
1307  my $passwd = 'test';
1308  my $group = 'ftpd';
1309  my $home_dir = File::Spec->rel2abs($tmpdir);
1310  my $uid = 500;
1311  my $gid = 500;
1312
1313  # Make sure that, if we're running as root, that the home directory has
1314  # permissions/privs set for the account we create
1315  if ($< == 0) {
1316    unless (chmod(0755, $home_dir)) {
1317      die("Can't set perms on $home_dir to 0755: $!");
1318    }
1319
1320    unless (chown($uid, $gid, $home_dir)) {
1321      die("Can't set owner of $home_dir to $uid/$gid: $!");
1322    }
1323  }
1324
1325  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1326    '/bin/bash');
1327  auth_group_write($auth_group_file, $group, $gid, $user);
1328
1329  # Copy the en_US.mo file from the locale/ directory into a directory
1330  # that we can tell mod_lang to find.
1331
1332  my $lang_path = File::Spec->rel2abs("$tmpdir/locale");
1333  mkpath("$lang_path/en_US/LC_MESSAGES");
1334
1335  copy("../locale/en_US.mo", "$lang_path/en_US/LC_MESSAGES/proftpd.mo");
1336
1337  my $config = {
1338    PidFile => $pid_file,
1339    ScoreboardFile => $scoreboard_file,
1340    SystemLog => $log_file,
1341
1342    AuthUserFile => $auth_user_file,
1343    AuthGroupFile => $auth_group_file,
1344
1345    IfModules => {
1346      'mod_delay.c' => {
1347        DelayEngine => 'off',
1348      },
1349
1350      'mod_lang.c' => {
1351        LangPath => $lang_path,
1352        LangDefault => 'en_US.UTF-8',
1353      },
1354    },
1355  };
1356
1357  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1358
1359  # Open pipes, for use between the parent and child processes.  Specifically,
1360  # the child will indicate when it's done with its test by writing a message
1361  # to the parent.
1362  my ($rfh, $wfh);
1363  unless (pipe($rfh, $wfh)) {
1364    die("Can't open pipe: $!");
1365  }
1366
1367  my $ex;
1368
1369  # Fork child
1370  $self->handle_sigchld();
1371  defined(my $pid = fork()) or die("Can't fork: $!");
1372  if ($pid) {
1373    eval {
1374      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1375      my ($resp_code, $resp_msg) = $client->user($user);
1376
1377      my $expected;
1378
1379      $expected = 331;
1380      $self->assert($expected == $resp_code,
1381        test_msg("Expected $expected, got $resp_code"));
1382
1383      $expected = "Password required for $user";
1384      $self->assert($expected eq $resp_msg,
1385        test_msg("Expected '$expected', got '$resp_msg'"));
1386    };
1387
1388    if ($@) {
1389      $ex = $@;
1390    }
1391
1392    $wfh->print("done\n");
1393    $wfh->flush();
1394
1395  } else {
1396    eval { server_wait($config_file, $rfh) };
1397    if ($@) {
1398      warn($@);
1399      exit 1;
1400    }
1401
1402    exit 0;
1403  }
1404
1405  # Stop server
1406  server_stop($pid_file);
1407
1408  $self->assert_child_ok($pid);
1409
1410  if ($ex) {
1411    test_append_logfile($log_file, $ex);
1412    unlink($log_file);
1413
1414    die($ex);
1415  }
1416
1417  unlink($log_file);
1418}
1419
1420sub lang_opts_utf8_useencoding_on {
1421  my $self = shift;
1422  my $tmpdir = $self->{tmpdir};
1423
1424  my $config_file = "$tmpdir/lang.conf";
1425  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
1426  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
1427
1428  my $log_file = test_get_logfile();
1429
1430  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
1431  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
1432
1433  my $user = 'proftpd';
1434  my $passwd = 'test';
1435  my $group = 'ftpd';
1436  my $home_dir = File::Spec->rel2abs($tmpdir);
1437  my $uid = 500;
1438  my $gid = 500;
1439
1440  # Make sure that, if we're running as root, that the home directory has
1441  # permissions/privs set for the account we create
1442  if ($< == 0) {
1443    unless (chmod(0755, $home_dir)) {
1444      die("Can't set perms on $home_dir to 0755: $!");
1445    }
1446
1447    unless (chown($uid, $gid, $home_dir)) {
1448      die("Can't set owner of $home_dir to $uid/$gid: $!");
1449    }
1450  }
1451
1452  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1453    '/bin/bash');
1454  auth_group_write($auth_group_file, $group, $gid, $user);
1455
1456  my $config = {
1457    PidFile => $pid_file,
1458    ScoreboardFile => $scoreboard_file,
1459    SystemLog => $log_file,
1460
1461    AuthUserFile => $auth_user_file,
1462    AuthGroupFile => $auth_group_file,
1463
1464    IfModules => {
1465      'mod_delay.c' => {
1466        DelayEngine => 'off',
1467      },
1468
1469      'mod_lang.c' => {
1470        UseEncoding => 'on',
1471      },
1472    },
1473  };
1474
1475  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1476
1477  # Open pipes, for use between the parent and child processes.  Specifically,
1478  # the child will indicate when it's done with its test by writing a message
1479  # to the parent.
1480  my ($rfh, $wfh);
1481  unless (pipe($rfh, $wfh)) {
1482    die("Can't open pipe: $!");
1483  }
1484
1485  my $ex;
1486
1487  # Fork child
1488  $self->handle_sigchld();
1489  defined(my $pid = fork()) or die("Can't fork: $!");
1490  if ($pid) {
1491    eval {
1492      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1493
1494      eval { $client->opts('UTF8', 'off') };
1495      unless ($@) {
1496        die("OPTS UTF8 off succeeded unexpectedly");
1497      }
1498
1499      my $resp_code = $client->response_code();
1500      my $resp_msg = $client->response_msg();
1501
1502      my $expected;
1503
1504      $expected = 451;
1505      $self->assert($expected == $resp_code,
1506        test_msg("Expected response code $expected, got $resp_code"));
1507
1508      $expected = 'Unable to accept OPTS UTF8';
1509      $self->assert($expected eq $resp_msg,
1510        test_msg("Expected response message '$expected', got '$resp_msg'"));
1511
1512      ($resp_code, $resp_msg) = $client->opts('UTF8', 'on');
1513
1514      $expected = 200;
1515      $self->assert($expected == $resp_code,
1516        test_msg("Expected response code $expected, got $resp_code"));
1517
1518      $expected = 'UTF8 set to on';
1519      $self->assert($expected eq $resp_msg,
1520        test_msg("Expected '$expected', got '$resp_msg'"));
1521    };
1522
1523    if ($@) {
1524      $ex = $@;
1525    }
1526
1527    $wfh->print("done\n");
1528    $wfh->flush();
1529
1530  } else {
1531    eval { server_wait($config_file, $rfh) };
1532    if ($@) {
1533      warn($@);
1534      exit 1;
1535    }
1536
1537    exit 0;
1538  }
1539
1540  # Stop server
1541  server_stop($pid_file);
1542
1543  $self->assert_child_ok($pid);
1544
1545  if ($ex) {
1546    test_append_logfile($log_file, $ex);
1547    unlink($log_file);
1548
1549    die($ex);
1550  }
1551
1552  unlink($log_file);
1553}
1554
1555sub lang_opts_utf8_useencoding_off {
1556  my $self = shift;
1557  my $tmpdir = $self->{tmpdir};
1558
1559  my $config_file = "$tmpdir/lang.conf";
1560  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
1561  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
1562
1563  my $log_file = test_get_logfile();
1564
1565  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
1566  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
1567
1568  my $user = 'proftpd';
1569  my $passwd = 'test';
1570  my $group = 'ftpd';
1571  my $home_dir = File::Spec->rel2abs($tmpdir);
1572  my $uid = 500;
1573  my $gid = 500;
1574
1575  # Make sure that, if we're running as root, that the home directory has
1576  # permissions/privs set for the account we create
1577  if ($< == 0) {
1578    unless (chmod(0755, $home_dir)) {
1579      die("Can't set perms on $home_dir to 0755: $!");
1580    }
1581
1582    unless (chown($uid, $gid, $home_dir)) {
1583      die("Can't set owner of $home_dir to $uid/$gid: $!");
1584    }
1585  }
1586
1587  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1588    '/bin/bash');
1589  auth_group_write($auth_group_file, $group, $gid, $user);
1590
1591  my $config = {
1592    PidFile => $pid_file,
1593    ScoreboardFile => $scoreboard_file,
1594    SystemLog => $log_file,
1595
1596    AuthUserFile => $auth_user_file,
1597    AuthGroupFile => $auth_group_file,
1598
1599    IfModules => {
1600      'mod_delay.c' => {
1601        DelayEngine => 'off',
1602      },
1603
1604      'mod_lang.c' => {
1605        UseEncoding => 'off',
1606      },
1607    },
1608  };
1609
1610  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1611
1612  # Open pipes, for use between the parent and child processes.  Specifically,
1613  # the child will indicate when it's done with its test by writing a message
1614  # to the parent.
1615  my ($rfh, $wfh);
1616  unless (pipe($rfh, $wfh)) {
1617    die("Can't open pipe: $!");
1618  }
1619
1620  my $ex;
1621
1622  # Fork child
1623  $self->handle_sigchld();
1624  defined(my $pid = fork()) or die("Can't fork: $!");
1625  if ($pid) {
1626    eval {
1627      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1628
1629      my ($resp_code, $resp_msg);
1630
1631      ($resp_code, $resp_msg) = $client->opts('UTF8', 'off');
1632
1633      my $expected;
1634
1635      $expected = 200;
1636      $self->assert($expected == $resp_code,
1637        test_msg("Expected $expected, got $resp_code"));
1638
1639      $expected = 'UTF8 set to off';
1640      $self->assert($expected eq $resp_msg,
1641        test_msg("Expected '$expected', got '$resp_msg'"));
1642
1643      $expected = 200;
1644      $self->assert($expected == $resp_code,
1645        test_msg("Expected $expected, got $resp_code"));
1646
1647      eval { $client->opts('UTF8', 'on') };
1648      unless ($@) {
1649        die("OPTS UTF8 on succeeded unexpectedly");
1650      }
1651
1652      $resp_code = $client->response_code();
1653      $resp_msg = $client->response_msg();
1654
1655      $expected = 451;
1656      $self->assert($expected == $resp_code,
1657        test_msg("Expected response code $expected, got $resp_code"));
1658
1659      $expected = 'Unable to accept OPTS UTF8';
1660      $self->assert($expected eq $resp_msg,
1661        test_msg("Expected response message '$expected', got '$resp_msg'"));
1662    };
1663
1664    if ($@) {
1665      $ex = $@;
1666    }
1667
1668    $wfh->print("done\n");
1669    $wfh->flush();
1670
1671  } else {
1672    eval { server_wait($config_file, $rfh) };
1673    if ($@) {
1674      warn($@);
1675      exit 1;
1676    }
1677
1678    exit 0;
1679  }
1680
1681  # Stop server
1682  server_stop($pid_file);
1683
1684  $self->assert_child_ok($pid);
1685
1686  if ($ex) {
1687    test_append_logfile($log_file, $ex);
1688    unlink($log_file);
1689
1690    die($ex);
1691  }
1692
1693  unlink($log_file);
1694}
1695
1696sub lang_opts_utf8_useencoding_charsets {
1697  my $self = shift;
1698  my $tmpdir = $self->{tmpdir};
1699
1700  my $config_file = "$tmpdir/lang.conf";
1701  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
1702  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
1703
1704  my $log_file = test_get_logfile();
1705
1706  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
1707  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
1708
1709  my $user = 'proftpd';
1710  my $passwd = 'test';
1711  my $group = 'ftpd';
1712  my $home_dir = File::Spec->rel2abs($tmpdir);
1713  my $uid = 500;
1714  my $gid = 500;
1715
1716  # Make sure that, if we're running as root, that the home directory has
1717  # permissions/privs set for the account we create
1718  if ($< == 0) {
1719    unless (chmod(0755, $home_dir)) {
1720      die("Can't set perms on $home_dir to 0755: $!");
1721    }
1722
1723    unless (chown($uid, $gid, $home_dir)) {
1724      die("Can't set owner of $home_dir to $uid/$gid: $!");
1725    }
1726  }
1727
1728  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1729    '/bin/bash');
1730  auth_group_write($auth_group_file, $group, $gid, $user);
1731
1732  my $config = {
1733    PidFile => $pid_file,
1734    ScoreboardFile => $scoreboard_file,
1735    SystemLog => $log_file,
1736    TraceLog => $log_file,
1737    Trace => 'encode:10',
1738
1739    AuthUserFile => $auth_user_file,
1740    AuthGroupFile => $auth_group_file,
1741
1742    IfModules => {
1743      'mod_delay.c' => {
1744        DelayEngine => 'off',
1745      },
1746
1747      'mod_lang.c' => {
1748        UseEncoding => 'iso-8859-1 iso-8859-1',
1749      },
1750    },
1751  };
1752
1753  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1754
1755  # Open pipes, for use between the parent and child processes.  Specifically,
1756  # the child will indicate when it's done with its test by writing a message
1757  # to the parent.
1758  my ($rfh, $wfh);
1759  unless (pipe($rfh, $wfh)) {
1760    die("Can't open pipe: $!");
1761  }
1762
1763  my $ex;
1764
1765  # Fork child
1766  $self->handle_sigchld();
1767  defined(my $pid = fork()) or die("Can't fork: $!");
1768  if ($pid) {
1769    eval {
1770      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1771      my ($resp_code, $resp_msg) = $client->opts('UTF8', 'off');
1772
1773      my $expected;
1774
1775      $expected = 200;
1776      $self->assert($expected == $resp_code,
1777        test_msg("Expected response code $expected, got $resp_code"));
1778
1779      $expected = 'UTF8 set to off';
1780      $self->assert($expected eq $resp_msg,
1781        test_msg("Expected response message '$expected', got '$resp_msg'"));
1782
1783      ($resp_code, $resp_msg) = $client->opts('UTF8', 'on');
1784
1785      $expected = 200;
1786      $self->assert($expected == $resp_code,
1787        test_msg("Expected response code $expected, got $resp_code"));
1788
1789      $expected = 'UTF8 set to on';
1790      $self->assert($expected eq $resp_msg,
1791        test_msg("Expected response message '$expected', got '$resp_msg'"));
1792    };
1793
1794    if ($@) {
1795      $ex = $@;
1796    }
1797
1798    $wfh->print("done\n");
1799    $wfh->flush();
1800
1801  } else {
1802    eval { server_wait($config_file, $rfh) };
1803    if ($@) {
1804      warn($@);
1805      exit 1;
1806    }
1807
1808    exit 0;
1809  }
1810
1811  # Stop server
1812  server_stop($pid_file);
1813
1814  $self->assert_child_ok($pid);
1815
1816  if ($ex) {
1817    test_append_logfile($log_file, $ex);
1818    unlink($log_file);
1819
1820    die($ex);
1821  }
1822
1823  unlink($log_file);
1824}
1825
1826sub lang_opts_utf8_useencoding_charsets_strict {
1827  my $self = shift;
1828  my $tmpdir = $self->{tmpdir};
1829
1830  my $config_file = "$tmpdir/lang.conf";
1831  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
1832  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
1833
1834  my $log_file = test_get_logfile();
1835
1836  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
1837  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
1838
1839  my $user = 'proftpd';
1840  my $passwd = 'test';
1841  my $group = 'ftpd';
1842  my $home_dir = File::Spec->rel2abs($tmpdir);
1843  my $uid = 500;
1844  my $gid = 500;
1845
1846  # Make sure that, if we're running as root, that the home directory has
1847  # permissions/privs set for the account we create
1848  if ($< == 0) {
1849    unless (chmod(0755, $home_dir)) {
1850      die("Can't set perms on $home_dir to 0755: $!");
1851    }
1852
1853    unless (chown($uid, $gid, $home_dir)) {
1854      die("Can't set owner of $home_dir to $uid/$gid: $!");
1855    }
1856  }
1857
1858  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
1859    '/bin/bash');
1860  auth_group_write($auth_group_file, $group, $gid, $user);
1861
1862  my $config = {
1863    PidFile => $pid_file,
1864    ScoreboardFile => $scoreboard_file,
1865    SystemLog => $log_file,
1866    TraceLog => $log_file,
1867    Trace => 'encode:10',
1868
1869    AuthUserFile => $auth_user_file,
1870    AuthGroupFile => $auth_group_file,
1871
1872    IfModules => {
1873      'mod_delay.c' => {
1874        DelayEngine => 'off',
1875      },
1876
1877      'mod_lang.c' => {
1878        UseEncoding => 'iso-8859-1 iso-8859-1 strict',
1879      },
1880    },
1881  };
1882
1883  my ($port, $config_user, $config_group) = config_write($config_file, $config);
1884
1885  # Open pipes, for use between the parent and child processes.  Specifically,
1886  # the child will indicate when it's done with its test by writing a message
1887  # to the parent.
1888  my ($rfh, $wfh);
1889  unless (pipe($rfh, $wfh)) {
1890    die("Can't open pipe: $!");
1891  }
1892
1893  my $ex;
1894
1895  # Fork child
1896  $self->handle_sigchld();
1897  defined(my $pid = fork()) or die("Can't fork: $!");
1898  if ($pid) {
1899    eval {
1900      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
1901
1902      # Make sure the OPTS UTF8 command does not appear in the FEAT listing;
1903      # see Bug#3737.
1904      $client->feat();
1905      my $resp_code = $client->response_code();
1906      my $resp_msgs = $client->response_msgs();
1907
1908      my $expected;
1909
1910      $expected = 211;
1911      $self->assert($expected == $resp_code,
1912        test_msg("Expected response code $expected, got $resp_code"));
1913
1914      foreach my $feat (@$resp_msgs) {
1915        if ($feat =~ /^ UTF8$/) {
1916          die("'$feat' feature listed unexpectedly via FEAT");
1917        }
1918      }
1919
1920      my $resp_msg;
1921      ($resp_code, $resp_msg) = $client->opts('UTF8', 'off');
1922
1923      $expected = 200;
1924      $self->assert($expected == $resp_code,
1925        test_msg("Expected response code $expected, got $resp_code"));
1926
1927      $expected = 'UTF8 set to off';
1928      $self->assert($expected eq $resp_msg,
1929        test_msg("Expected response message '$expected', got '$resp_msg'"));
1930
1931      eval { $client->opts('UTF8', 'on') };
1932      unless ($@) {
1933        die("OPTS UTF8 on succeeded unexpectedly");
1934      }
1935
1936      $resp_code = $client->response_code();
1937      $resp_msg = $client->response_msg();
1938
1939      $expected = 451;
1940      $self->assert($expected == $resp_code,
1941        test_msg("Expected response code $expected, got $resp_code"));
1942
1943      $expected = 'Unable to accept OPTS UTF8';
1944      $self->assert($expected eq $resp_msg,
1945        test_msg("Expected response message '$expected', got '$resp_msg'"));
1946    };
1947
1948    if ($@) {
1949      $ex = $@;
1950    }
1951
1952    $wfh->print("done\n");
1953    $wfh->flush();
1954
1955  } else {
1956    eval { server_wait($config_file, $rfh) };
1957    if ($@) {
1958      warn($@);
1959      exit 1;
1960    }
1961
1962    exit 0;
1963  }
1964
1965  # Stop server
1966  server_stop($pid_file);
1967
1968  $self->assert_child_ok($pid);
1969
1970  if ($ex) {
1971    test_append_logfile($log_file, $ex);
1972    unlink($log_file);
1973
1974    die($ex);
1975  }
1976
1977  unlink($log_file);
1978}
1979
1980sub lang_opts_utf8_useencoding_charsets_strict_with_utf8 {
1981  my $self = shift;
1982  my $tmpdir = $self->{tmpdir};
1983
1984  my $config_file = "$tmpdir/lang.conf";
1985  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
1986  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
1987
1988  my $log_file = test_get_logfile();
1989
1990  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
1991  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
1992
1993  my $user = 'proftpd';
1994  my $passwd = 'test';
1995  my $group = 'ftpd';
1996  my $home_dir = File::Spec->rel2abs($tmpdir);
1997  my $uid = 500;
1998  my $gid = 500;
1999
2000  # Make sure that, if we're running as root, that the home directory has
2001  # permissions/privs set for the account we create
2002  if ($< == 0) {
2003    unless (chmod(0755, $home_dir)) {
2004      die("Can't set perms on $home_dir to 0755: $!");
2005    }
2006
2007    unless (chown($uid, $gid, $home_dir)) {
2008      die("Can't set owner of $home_dir to $uid/$gid: $!");
2009    }
2010  }
2011
2012  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2013    '/bin/bash');
2014  auth_group_write($auth_group_file, $group, $gid, $user);
2015
2016  my $config = {
2017    PidFile => $pid_file,
2018    ScoreboardFile => $scoreboard_file,
2019    SystemLog => $log_file,
2020    TraceLog => $log_file,
2021    Trace => 'encode:10',
2022
2023    AuthUserFile => $auth_user_file,
2024    AuthGroupFile => $auth_group_file,
2025
2026    IfModules => {
2027      'mod_delay.c' => {
2028        DelayEngine => 'off',
2029      },
2030
2031      'mod_lang.c' => {
2032        UseEncoding => 'iso-8859-1 utf-8 strict',
2033      },
2034    },
2035  };
2036
2037  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2038
2039  # Open pipes, for use between the parent and child processes.  Specifically,
2040  # the child will indicate when it's done with its test by writing a message
2041  # to the parent.
2042  my ($rfh, $wfh);
2043  unless (pipe($rfh, $wfh)) {
2044    die("Can't open pipe: $!");
2045  }
2046
2047  my $ex;
2048
2049  # Fork child
2050  $self->handle_sigchld();
2051  defined(my $pid = fork()) or die("Can't fork: $!");
2052  if ($pid) {
2053    eval {
2054      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2055
2056      # Make sure the OPTS UTF8 command does not appear in the FEAT listing;
2057      # see Bug#3737.
2058      $client->feat();
2059      my $resp_code = $client->response_code();
2060      my $resp_msgs = $client->response_msgs();
2061
2062      my $expected;
2063
2064      $expected = 211;
2065      $self->assert($expected == $resp_code,
2066        test_msg("Expected response code $expected, got $resp_code"));
2067
2068      # Since our strict UseEncoding expects UTF8, we should see UTF8
2069      # listed in the FEAT output (see Bug#3737).
2070      my $have_utf8 = 0;
2071      foreach my $feat (@$resp_msgs) {
2072        if ($feat =~ /^ UTF8$/) {
2073          $have_utf8 = 1;
2074          last;
2075        }
2076      }
2077
2078      $self->assert($have_utf8,
2079        test_msg("UTF8 feature not listed as expected via FEAT"));
2080
2081      eval { $client->opts('UTF8', 'off') };
2082      unless ($@) {
2083        die("OPTS UTF8 off succeeded unexpectedly");
2084      }
2085
2086      $resp_code = $client->response_code();
2087      my $resp_msg = $client->response_msg();
2088
2089      $expected = 451;
2090      $self->assert($expected == $resp_code,
2091        test_msg("Expected response code $expected, got $resp_code"));
2092
2093      $expected = 'Unable to accept OPTS UTF8';
2094      $self->assert($expected eq $resp_msg,
2095        test_msg("Expected response message '$expected', got '$resp_msg'"));
2096
2097      ($resp_code, $resp_msg) = $client->opts('UTF8', 'on');
2098
2099      $expected = 200;
2100      $self->assert($expected == $resp_code,
2101        test_msg("Expected response code $expected, got $resp_code"));
2102
2103      $expected = 'UTF8 set to on';
2104      $self->assert($expected eq $resp_msg,
2105        test_msg("Expected response message '$expected', got '$resp_msg'"));
2106    };
2107
2108    if ($@) {
2109      $ex = $@;
2110    }
2111
2112    $wfh->print("done\n");
2113    $wfh->flush();
2114
2115  } else {
2116    eval { server_wait($config_file, $rfh) };
2117    if ($@) {
2118      warn($@);
2119      exit 1;
2120    }
2121
2122    exit 0;
2123  }
2124
2125  # Stop server
2126  server_stop($pid_file);
2127
2128  $self->assert_child_ok($pid);
2129
2130  if ($ex) {
2131    test_append_logfile($log_file, $ex);
2132    unlink($log_file);
2133
2134    die($ex);
2135  }
2136
2137  unlink($log_file);
2138}
2139
2140sub lang_opts_utf8_useencoding_charsets_with_env {
2141  my $self = shift;
2142  my $tmpdir = $self->{tmpdir};
2143
2144  my $config_file = "$tmpdir/lang.conf";
2145  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
2146  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
2147
2148  my $log_file = test_get_logfile();
2149
2150  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
2151  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
2152
2153  my $user = 'proftpd';
2154  my $passwd = 'test';
2155  my $group = 'ftpd';
2156  my $home_dir = File::Spec->rel2abs($tmpdir);
2157  my $uid = 500;
2158  my $gid = 500;
2159
2160  # Make sure that, if we're running as root, that the home directory has
2161  # permissions/privs set for the account we create
2162  if ($< == 0) {
2163    unless (chmod(0755, $home_dir)) {
2164      die("Can't set perms on $home_dir to 0755: $!");
2165    }
2166
2167    unless (chown($uid, $gid, $home_dir)) {
2168      die("Can't set owner of $home_dir to $uid/$gid: $!");
2169    }
2170  }
2171
2172  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2173    '/bin/bash');
2174  auth_group_write($auth_group_file, $group, $gid, $user);
2175
2176  # Copy the en_US.mo file from the locale/ directory into a directory
2177  # that we can tell mod_lang to find.
2178
2179  my $lang_path = File::Spec->rel2abs("$tmpdir/locale");
2180  mkpath("$lang_path/en_US/LC_MESSAGES");
2181
2182  copy("../locale/en_US.mo", "$lang_path/en_US/LC_MESSAGES/proftpd.mo");
2183
2184  my $config = {
2185    PidFile => $pid_file,
2186    ScoreboardFile => $scoreboard_file,
2187    SystemLog => $log_file,
2188    TraceLog => $log_file,
2189    Trace => 'encode:10',
2190
2191    AuthUserFile => $auth_user_file,
2192    AuthGroupFile => $auth_group_file,
2193
2194    IfModules => {
2195      'mod_delay.c' => {
2196        DelayEngine => 'off',
2197      },
2198
2199      'mod_lang.c' => {
2200        UseEncoding => 'iso-8859-1 iso-8859-1',
2201      },
2202    },
2203  };
2204
2205  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2206
2207  # Open pipes, for use between the parent and child processes.  Specifically,
2208  # the child will indicate when it's done with its test by writing a message
2209  # to the parent.
2210  my ($rfh, $wfh);
2211  unless (pipe($rfh, $wfh)) {
2212    die("Can't open pipe: $!");
2213  }
2214
2215  my $ex;
2216
2217  # Fork child
2218  $self->handle_sigchld();
2219  defined(my $pid = fork()) or die("Can't fork: $!");
2220  if ($pid) {
2221    eval {
2222      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2223      my ($resp_code, $resp_msg) = $client->opts('UTF8', 'on');
2224
2225      my $expected;
2226
2227      $expected = 200;
2228      $self->assert($expected == $resp_code,
2229        test_msg("Expected response code $expected, got $resp_code"));
2230
2231      $expected = 'UTF8 set to on';
2232      $self->assert($expected eq $resp_msg,
2233        test_msg("Expected response message '$expected', got '$resp_msg'"));
2234
2235      ($resp_code, $resp_msg) = $client->opts('UTF8', 'on');
2236
2237      $expected = 200;
2238      $self->assert($expected == $resp_code,
2239        test_msg("Expected response code $expected, got $resp_code"));
2240
2241      $expected = 'UTF8 set to on';
2242      $self->assert($expected eq $resp_msg,
2243        test_msg("Expected response message '$expected', got '$resp_msg'"));
2244    };
2245
2246    if ($@) {
2247      $ex = $@;
2248    }
2249
2250    $wfh->print("done\n");
2251    $wfh->flush();
2252
2253  } else {
2254    # Before we start the server, set the LANG environment variable to
2255    # something like "en_US.utf8", see what happens.
2256    #
2257    # Note: The list of allowed values here should be dynamically determined
2258    # by calling `locale -a'.
2259    $ENV{LANG} = "en_US.utf8";
2260
2261    eval { server_wait($config_file, $rfh) };
2262    if ($@) {
2263      warn($@);
2264      exit 1;
2265    }
2266
2267    exit 0;
2268  }
2269
2270  # Stop server
2271  server_stop($pid_file);
2272
2273  $self->assert_child_ok($pid);
2274
2275  if ($ex) {
2276    test_append_logfile($log_file, $ex);
2277    unlink($log_file);
2278
2279    die($ex);
2280  }
2281
2282  unlink($log_file);
2283}
2284
2285sub lang_useencoding_latin1_utf8 {
2286  my $self = shift;
2287  my $tmpdir = $self->{tmpdir};
2288
2289  my $config_file = "$tmpdir/lang.conf";
2290  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
2291  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
2292
2293  my $log_file = test_get_logfile();
2294
2295  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
2296  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
2297
2298  my $user = 'proftpd';
2299  my $passwd = 'test';
2300  my $group = 'ftpd';
2301  my $home_dir = File::Spec->rel2abs($tmpdir);
2302  my $uid = 500;
2303  my $gid = 500;
2304
2305  # Make sure that, if we're running as root, that the home directory has
2306  # permissions/privs set for the account we create
2307  if ($< == 0) {
2308    unless (chmod(0755, $home_dir)) {
2309      die("Can't set perms on $home_dir to 0755: $!");
2310    }
2311
2312    unless (chown($uid, $gid, $home_dir)) {
2313      die("Can't set owner of $home_dir to $uid/$gid: $!");
2314    }
2315  }
2316
2317  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2318    '/bin/bash');
2319  auth_group_write($auth_group_file, $group, $gid, $user);
2320
2321  my $test_file = File::Spec->rel2abs("$home_dir/üöä");
2322
2323  my $config = {
2324    PidFile => $pid_file,
2325    ScoreboardFile => $scoreboard_file,
2326    SystemLog => $log_file,
2327    TraceLog => $log_file,
2328    Trace => 'encode:20',
2329
2330    AuthUserFile => $auth_user_file,
2331    AuthGroupFile => $auth_group_file,
2332
2333    IfModules => {
2334      'mod_delay.c' => {
2335        DelayEngine => 'off',
2336      },
2337
2338      'mod_lang.c' => {
2339        UseEncoding => 'utf-8 iso-8859-1',
2340      },
2341    },
2342  };
2343
2344  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2345
2346  # Open pipes, for use between the parent and child processes.  Specifically,
2347  # the child will indicate when it's done with its test by writing a message
2348  # to the parent.
2349  my ($rfh, $wfh);
2350  unless (pipe($rfh, $wfh)) {
2351    die("Can't open pipe: $!");
2352  }
2353
2354  my $ex;
2355
2356  # Fork child
2357  $self->handle_sigchld();
2358  defined(my $pid = fork()) or die("Can't fork: $!");
2359  if ($pid) {
2360    eval {
2361      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2362      $client->login($user, $passwd);
2363
2364      my $name = "üöä";
2365
2366      my $conn = $client->stor_raw($name);
2367      unless ($conn) {
2368        die("STOR $name failed: " . $client->response_code() . " " .
2369          $client->response_msg());
2370      }
2371
2372      my $buf = "Hello, world\n";
2373      $conn->write($buf, length($buf), 15);
2374      eval { $conn->close() };
2375
2376      my $resp_code = $client->response_code();
2377      my $resp_msg = $client->response_msg();
2378      $self->assert_transfer_ok($resp_code, $resp_msg);
2379
2380      $client->quit();
2381
2382      $self->assert(-f $test_file,
2383        test_msg("File $test_file does not exist as expected"));
2384    };
2385
2386    if ($@) {
2387      $ex = $@;
2388    }
2389
2390    $wfh->print("done\n");
2391    $wfh->flush();
2392
2393  } else {
2394    eval { server_wait($config_file, $rfh) };
2395    if ($@) {
2396      warn($@);
2397      exit 1;
2398    }
2399
2400    exit 0;
2401  }
2402
2403  # Stop server
2404  server_stop($pid_file);
2405
2406  $self->assert_child_ok($pid);
2407
2408  if ($ex) {
2409    test_append_logfile($log_file, $ex);
2410    unlink($log_file);
2411
2412    die($ex);
2413  }
2414
2415  unlink($log_file);
2416}
2417
2418sub lang_useencoding_utf8_latin1 {
2419  my $self = shift;
2420  my $tmpdir = $self->{tmpdir};
2421
2422  my $config_file = "$tmpdir/lang.conf";
2423  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
2424  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
2425
2426  my $log_file = test_get_logfile();
2427
2428  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
2429  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
2430
2431  my $user = 'proftpd';
2432  my $passwd = 'test';
2433  my $group = 'ftpd';
2434  my $home_dir = File::Spec->rel2abs($tmpdir);
2435  my $uid = 500;
2436  my $gid = 500;
2437
2438  # Make sure that, if we're running as root, that the home directory has
2439  # permissions/privs set for the account we create
2440  if ($< == 0) {
2441    unless (chmod(0755, $home_dir)) {
2442      die("Can't set perms on $home_dir to 0755: $!");
2443    }
2444
2445    unless (chown($uid, $gid, $home_dir)) {
2446      die("Can't set owner of $home_dir to $uid/$gid: $!");
2447    }
2448  }
2449
2450  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2451    '/bin/bash');
2452  auth_group_write($auth_group_file, $group, $gid, $user);
2453
2454  my $test_file = File::Spec->rel2abs("$home_dir/Grafik-Zentrumäüu.png");
2455  if ($^O eq 'darwin') {
2456    # MacOSX hack
2457    $test_file = ('/private' . $test_file);
2458  }
2459
2460  my $config = {
2461    PidFile => $pid_file,
2462    ScoreboardFile => $scoreboard_file,
2463    SystemLog => $log_file,
2464    TraceLog => $log_file,
2465    Trace => 'encode:20',
2466
2467    AuthUserFile => $auth_user_file,
2468    AuthGroupFile => $auth_group_file,
2469
2470    IfModules => {
2471      'mod_delay.c' => {
2472        DelayEngine => 'off',
2473      },
2474
2475      'mod_lang.c' => {
2476        UseEncoding => 'utf-8 iso-8859-1',
2477      },
2478    },
2479  };
2480
2481  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2482
2483  # Open pipes, for use between the parent and child processes.  Specifically,
2484  # the child will indicate when it's done with its test by writing a message
2485  # to the parent.
2486  my ($rfh, $wfh);
2487  unless (pipe($rfh, $wfh)) {
2488    die("Can't open pipe: $!");
2489  }
2490
2491  my $ex;
2492
2493  # Fork child
2494  $self->handle_sigchld();
2495  defined(my $pid = fork()) or die("Can't fork: $!");
2496  if ($pid) {
2497    eval {
2498      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2499      $client->login($user, $passwd);
2500
2501      my $name = "Grafik-Zentrumäüu.png";
2502
2503      my $conn = $client->stor_raw($name);
2504      unless ($conn) {
2505        die("STOR $name failed: " . $client->response_code() . " " .
2506          $client->response_msg());
2507      }
2508
2509      my $buf = "Hello, world\n";
2510      $conn->write($buf, length($buf), 15);
2511      eval { $conn->close() };
2512
2513      my $resp_code = $client->response_code();
2514      my $resp_msg = $client->response_msg();
2515      $self->assert_transfer_ok($resp_code, $resp_msg);
2516
2517      $client->quit();
2518
2519      $self->assert(-f $test_file,
2520        test_msg("File $test_file does not exist as expected"));
2521    };
2522
2523    if ($@) {
2524      $ex = $@;
2525    }
2526
2527    $wfh->print("done\n");
2528    $wfh->flush();
2529
2530  } else {
2531    eval { server_wait($config_file, $rfh) };
2532    if ($@) {
2533      warn($@);
2534      exit 1;
2535    }
2536
2537    exit 0;
2538  }
2539
2540  # Stop server
2541  server_stop($pid_file);
2542
2543  $self->assert_child_ok($pid);
2544
2545  if ($ex) {
2546    test_append_logfile($log_file, $ex);
2547    unlink($log_file);
2548
2549    die($ex);
2550  }
2551
2552  unlink($log_file);
2553}
2554
2555sub lang_opts_utf8_prefer_server_encoding_bug4125 {
2556  my $self = shift;
2557  my $tmpdir = $self->{tmpdir};
2558
2559  my $config_file = "$tmpdir/lang.conf";
2560  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
2561  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
2562
2563  my $log_file = test_get_logfile();
2564
2565  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
2566  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
2567
2568  my $user = 'proftpd';
2569  my $passwd = 'test';
2570  my $group = 'ftpd';
2571  my $home_dir = File::Spec->rel2abs($tmpdir);
2572  my $uid = 500;
2573  my $gid = 500;
2574
2575  # Make sure that, if we're running as root, that the home directory has
2576  # permissions/privs set for the account we create
2577  if ($< == 0) {
2578    unless (chmod(0755, $home_dir)) {
2579      die("Can't set perms on $home_dir to 0755: $!");
2580    }
2581
2582    unless (chown($uid, $gid, $home_dir)) {
2583      die("Can't set owner of $home_dir to $uid/$gid: $!");
2584    }
2585  }
2586
2587  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2588    '/bin/bash');
2589  auth_group_write($auth_group_file, $group, $gid, $user);
2590
2591  my $config = {
2592    PidFile => $pid_file,
2593    ScoreboardFile => $scoreboard_file,
2594    SystemLog => $log_file,
2595    TraceLog => $log_file,
2596    Trace => 'encode:10',
2597
2598    AuthUserFile => $auth_user_file,
2599    AuthGroupFile => $auth_group_file,
2600
2601    IfModules => {
2602      'mod_delay.c' => {
2603        DelayEngine => 'off',
2604      },
2605
2606      'mod_lang.c' => {
2607        LangOptions => 'PreferServerEncoding',
2608        UseEncoding => 'iso-8859-1 iso-8859-1',
2609      },
2610    },
2611  };
2612
2613  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2614
2615  # Open pipes, for use between the parent and child processes.  Specifically,
2616  # the child will indicate when it's done with its test by writing a message
2617  # to the parent.
2618  my ($rfh, $wfh);
2619  unless (pipe($rfh, $wfh)) {
2620    die("Can't open pipe: $!");
2621  }
2622
2623  my $ex;
2624
2625  # Fork child
2626  $self->handle_sigchld();
2627  defined(my $pid = fork()) or die("Can't fork: $!");
2628  if ($pid) {
2629    eval {
2630      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2631
2632      # Make sure the OPTS UTF8 command does not appear in the FEAT listing;
2633      # see Bug#3737.
2634      $client->feat();
2635      my $resp_code = $client->response_code();
2636      my $resp_msgs = $client->response_msgs();
2637
2638      my $expected;
2639
2640      $expected = 211;
2641      $self->assert($expected == $resp_code,
2642        test_msg("Expected response code $expected, got $resp_code"));
2643
2644      foreach my $feat (@$resp_msgs) {
2645        if ($feat =~ /^ UTF8$/) {
2646          die("'$feat' feature listed unexpectedly via FEAT");
2647        }
2648      }
2649
2650      my $resp_msg;
2651      ($resp_code, $resp_msg) = $client->opts('UTF8', 'off');
2652
2653      $expected = 200;
2654      $self->assert($expected == $resp_code,
2655        test_msg("Expected response code $expected, got $resp_code"));
2656
2657      $expected = 'UTF8 set to off';
2658      $self->assert($expected eq $resp_msg,
2659        test_msg("Expected response message '$expected', got '$resp_msg'"));
2660
2661      eval { $client->opts('UTF8', 'on') };
2662      unless ($@) {
2663        die("OPTS UTF8 on succeeded unexpectedly");
2664      }
2665
2666      $resp_code = $client->response_code();
2667      $resp_msg = $client->response_msg();
2668
2669      $expected = 451;
2670      $self->assert($expected == $resp_code,
2671        test_msg("Expected response code $expected, got $resp_code"));
2672
2673      $expected = 'Unable to accept OPTS UTF8';
2674      $self->assert($expected eq $resp_msg,
2675        test_msg("Expected response message '$expected', got '$resp_msg'"));
2676    };
2677
2678    if ($@) {
2679      $ex = $@;
2680    }
2681
2682    $wfh->print("done\n");
2683    $wfh->flush();
2684
2685  } else {
2686    eval { server_wait($config_file, $rfh) };
2687    if ($@) {
2688      warn($@);
2689      exit 1;
2690    }
2691
2692    exit 0;
2693  }
2694
2695  # Stop server
2696  server_stop($pid_file);
2697
2698  $self->assert_child_ok($pid);
2699
2700  if ($ex) {
2701    test_append_logfile($log_file, $ex);
2702    unlink($log_file);
2703
2704    die($ex);
2705  }
2706
2707  unlink($log_file);
2708}
2709
2710sub lang_opts_utf8_useencoding_charsets_prefer_server_encoding_bug4125 {
2711  my $self = shift;
2712  my $tmpdir = $self->{tmpdir};
2713
2714  my $config_file = "$tmpdir/lang.conf";
2715  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
2716  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
2717
2718  my $log_file = test_get_logfile();
2719
2720  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
2721  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
2722
2723  my $user = 'proftpd';
2724  my $passwd = 'test';
2725  my $group = 'ftpd';
2726  my $home_dir = File::Spec->rel2abs($tmpdir);
2727  my $uid = 500;
2728  my $gid = 500;
2729
2730  # Make sure that, if we're running as root, that the home directory has
2731  # permissions/privs set for the account we create
2732  if ($< == 0) {
2733    unless (chmod(0755, $home_dir)) {
2734      die("Can't set perms on $home_dir to 0755: $!");
2735    }
2736
2737    unless (chown($uid, $gid, $home_dir)) {
2738      die("Can't set owner of $home_dir to $uid/$gid: $!");
2739    }
2740  }
2741
2742  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2743    '/bin/bash');
2744  auth_group_write($auth_group_file, $group, $gid, $user);
2745
2746  my $config = {
2747    PidFile => $pid_file,
2748    ScoreboardFile => $scoreboard_file,
2749    SystemLog => $log_file,
2750    TraceLog => $log_file,
2751    Trace => 'encode:10',
2752
2753    AuthUserFile => $auth_user_file,
2754    AuthGroupFile => $auth_group_file,
2755
2756    IfModules => {
2757      'mod_delay.c' => {
2758        DelayEngine => 'off',
2759      },
2760
2761      'mod_lang.c' => {
2762        LangOptions => 'PreferServerEncoding',
2763        UseEncoding => 'iso-8859-1 utf-8',
2764      },
2765    },
2766  };
2767
2768  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2769
2770  # Open pipes, for use between the parent and child processes.  Specifically,
2771  # the child will indicate when it's done with its test by writing a message
2772  # to the parent.
2773  my ($rfh, $wfh);
2774  unless (pipe($rfh, $wfh)) {
2775    die("Can't open pipe: $!");
2776  }
2777
2778  my $ex;
2779
2780  # Fork child
2781  $self->handle_sigchld();
2782  defined(my $pid = fork()) or die("Can't fork: $!");
2783  if ($pid) {
2784    eval {
2785      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2786
2787      # Make sure the OPTS UTF8 command does not appear in the FEAT listing;
2788      # see Bug#3737.
2789      $client->feat();
2790      my $resp_code = $client->response_code();
2791      my $resp_msgs = $client->response_msgs();
2792
2793      my $expected;
2794
2795      $expected = 211;
2796      $self->assert($expected == $resp_code,
2797        test_msg("Expected response code $expected, got $resp_code"));
2798
2799      # Since our strict UseEncoding expects UTF8, we should see UTF8
2800      # listed in the FEAT output (see Bug#3737).
2801      my $have_utf8 = 0;
2802      foreach my $feat (@$resp_msgs) {
2803        if ($feat =~ /^ UTF8$/) {
2804          $have_utf8 = 1;
2805          last;
2806        }
2807      }
2808
2809      $self->assert($have_utf8,
2810        test_msg("UTF8 feature not listed as expected via FEAT"));
2811
2812      eval { $client->opts('UTF8', 'off') };
2813      unless ($@) {
2814        die("OPTS UTF8 off succeeded unexpectedly");
2815      }
2816
2817      $resp_code = $client->response_code();
2818      my $resp_msg = $client->response_msg();
2819
2820      $expected = 451;
2821      $self->assert($expected == $resp_code,
2822        test_msg("Expected response code $expected, got $resp_code"));
2823
2824      $expected = 'Unable to accept OPTS UTF8';
2825      $self->assert($expected eq $resp_msg,
2826        test_msg("Expected response message '$expected', got '$resp_msg'"));
2827
2828      ($resp_code, $resp_msg) = $client->opts('UTF8', 'on');
2829
2830      $expected = 200;
2831      $self->assert($expected == $resp_code,
2832        test_msg("Expected response code $expected, got $resp_code"));
2833
2834      $expected = 'UTF8 set to on';
2835      $self->assert($expected eq $resp_msg,
2836        test_msg("Expected response message '$expected', got '$resp_msg'"));
2837    };
2838
2839    if ($@) {
2840      $ex = $@;
2841    }
2842
2843    $wfh->print("done\n");
2844    $wfh->flush();
2845
2846  } else {
2847    eval { server_wait($config_file, $rfh) };
2848    if ($@) {
2849      warn($@);
2850      exit 1;
2851    }
2852
2853    exit 0;
2854  }
2855
2856  # Stop server
2857  server_stop($pid_file);
2858
2859  $self->assert_child_ok($pid);
2860
2861  if ($ex) {
2862    test_append_logfile($log_file, $ex);
2863    unlink($log_file);
2864
2865    die($ex);
2866  }
2867
2868  unlink($log_file);
2869}
2870
2871sub lang_useencoding_ascii_utf8_require_valid_encoding_bug4125 {
2872  my $self = shift;
2873  my $tmpdir = $self->{tmpdir};
2874
2875  my $config_file = "$tmpdir/lang.conf";
2876  my $pid_file = File::Spec->rel2abs("$tmpdir/lang.pid");
2877  my $scoreboard_file = File::Spec->rel2abs("$tmpdir/lang.scoreboard");
2878
2879  my $log_file = test_get_logfile();
2880
2881  my $auth_user_file = File::Spec->rel2abs("$tmpdir/lang.passwd");
2882  my $auth_group_file = File::Spec->rel2abs("$tmpdir/lang.group");
2883
2884  my $user = 'proftpd';
2885  my $passwd = 'test';
2886  my $group = 'ftpd';
2887  my $home_dir = File::Spec->rel2abs($tmpdir);
2888  my $uid = 500;
2889  my $gid = 500;
2890
2891  # Make sure that, if we're running as root, that the home directory has
2892  # permissions/privs set for the account we create
2893  if ($< == 0) {
2894    unless (chmod(0755, $home_dir)) {
2895      die("Can't set perms on $home_dir to 0755: $!");
2896    }
2897
2898    unless (chown($uid, $gid, $home_dir)) {
2899      die("Can't set owner of $home_dir to $uid/$gid: $!");
2900    }
2901  }
2902
2903  auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir,
2904    '/bin/bash');
2905  auth_group_write($auth_group_file, $group, $gid, $user);
2906
2907  my $test_file = File::Spec->rel2abs("$home_dir/üöä");
2908
2909  my $config = {
2910    PidFile => $pid_file,
2911    ScoreboardFile => $scoreboard_file,
2912    SystemLog => $log_file,
2913    TraceLog => $log_file,
2914    Trace => 'encode:20',
2915
2916    AuthUserFile => $auth_user_file,
2917    AuthGroupFile => $auth_group_file,
2918
2919    IfModules => {
2920      'mod_delay.c' => {
2921        DelayEngine => 'off',
2922      },
2923
2924      'mod_lang.c' => {
2925        LangOptions => 'RequireValidEncoding',
2926        UseEncoding => 'utf-8 us-ascii',
2927      },
2928    },
2929  };
2930
2931  my ($port, $config_user, $config_group) = config_write($config_file, $config);
2932
2933  # Open pipes, for use between the parent and child processes.  Specifically,
2934  # the child will indicate when it's done with its test by writing a message
2935  # to the parent.
2936  my ($rfh, $wfh);
2937  unless (pipe($rfh, $wfh)) {
2938    die("Can't open pipe: $!");
2939  }
2940
2941  my $ex;
2942
2943  # Fork child
2944  $self->handle_sigchld();
2945  defined(my $pid = fork()) or die("Can't fork: $!");
2946  if ($pid) {
2947    eval {
2948      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
2949      $client->login($user, $passwd);
2950
2951      my $name = "üöä";
2952
2953      my $conn = $client->stor_raw($name);
2954      if ($conn) {
2955        die("STORE $name succeeded unexpectedly");
2956      }
2957
2958      my $resp_code = $client->response_code();
2959      my $resp_msg = $client->response_msg();
2960
2961      $client->quit();
2962
2963      my $expected = 550;
2964      $self->assert($expected == $resp_code,
2965        test_msg("Expected response code $expected, got $resp_code"));
2966
2967      $expected = 'Illegal character sequence';
2968      $self->assert(qr/$expected/, $resp_msg,
2969        test_msg("Expected response message '$expected', got '$resp_msg'"));
2970    };
2971
2972    if ($@) {
2973      $ex = $@;
2974    }
2975
2976    $wfh->print("done\n");
2977    $wfh->flush();
2978
2979  } else {
2980    eval { server_wait($config_file, $rfh) };
2981    if ($@) {
2982      warn($@);
2983      exit 1;
2984    }
2985
2986    exit 0;
2987  }
2988
2989  # Stop server
2990  server_stop($pid_file);
2991
2992  $self->assert_child_ok($pid);
2993
2994  if ($ex) {
2995    test_append_logfile($log_file, $ex);
2996    unlink($log_file);
2997
2998    die($ex);
2999  }
3000
3001  unlink($log_file);
3002}
3003
3004sub lang_useencoding_latin1_utf8_per_user_bug4214 {
3005  my $self = shift;
3006  my $tmpdir = $self->{tmpdir};
3007  my $setup = test_setup($tmpdir, 'lang');
3008
3009  my $test_file = File::Spec->rel2abs("$setup->{home_dir}/üöä");
3010
3011  my $config = {
3012    PidFile => $setup->{pid_file},
3013    ScoreboardFile => $setup->{scoreboard_file},
3014    SystemLog => $setup->{log_file},
3015    TraceLog => $setup->{log_file},
3016    Trace => 'encode:20',
3017
3018    AuthUserFile => $setup->{auth_user_file},
3019    AuthGroupFile => $setup->{auth_group_file},
3020
3021    IfModules => {
3022      'mod_delay.c' => {
3023        DelayEngine => 'off',
3024      },
3025    },
3026  };
3027
3028  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
3029    $config);
3030
3031  if (open(my $fh, ">> $setup->{config_file}")) {
3032    print $fh <<EOC;
3033<IfModule mod_lang.c>
3034  <IfUser $setup->{user}>
3035    UseEncoding utf-8 iso-8859-1
3036  </IfUser>
3037</IfModule>
3038EOC
3039    unless (close($fh)) {
3040      die("Can't write $setup->{config_file}: $!");
3041    }
3042
3043  } else {
3044    die("Can't open $setup->{config_file}: $!");
3045  }
3046
3047  # Open pipes, for use between the parent and child processes.  Specifically,
3048  # the child will indicate when it's done with its test by writing a message
3049  # to the parent.
3050  my ($rfh, $wfh);
3051  unless (pipe($rfh, $wfh)) {
3052    die("Can't open pipe: $!");
3053  }
3054
3055  my $ex;
3056
3057  # Fork child
3058  $self->handle_sigchld();
3059  defined(my $pid = fork()) or die("Can't fork: $!");
3060  if ($pid) {
3061    eval {
3062      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
3063      $client->login($setup->{user}, $setup->{passwd});
3064
3065      my $name = "üöä";
3066
3067      my $conn = $client->stor_raw($name);
3068      unless ($conn) {
3069        die("STOR $name failed: " . $client->response_code() . " " .
3070          $client->response_msg());
3071      }
3072
3073      my $buf = "Hello, world\n";
3074      $conn->write($buf, length($buf), 15);
3075      eval { $conn->close() };
3076
3077      my $resp_code = $client->response_code();
3078      my $resp_msg = $client->response_msg();
3079      $self->assert_transfer_ok($resp_code, $resp_msg);
3080
3081      $client->quit();
3082
3083      $self->assert(-f $test_file,
3084        test_msg("File $test_file does not exist as expected"));
3085    };
3086
3087    if ($@) {
3088      $ex = $@;
3089    }
3090
3091    $wfh->print("done\n");
3092    $wfh->flush();
3093
3094  } else {
3095    eval { server_wait($setup->{config_file}, $rfh) };
3096    if ($@) {
3097      warn($@);
3098      exit 1;
3099    }
3100
3101    exit 0;
3102  }
3103
3104  # Stop server
3105  server_stop($setup->{pid_file});
3106  $self->assert_child_ok($pid);
3107  test_cleanup($setup->{log_file}, $ex);
3108}
3109
3110sub lang_useencoding_utf8_latin1_per_user_bug4214 {
3111  my $self = shift;
3112  my $tmpdir = $self->{tmpdir};
3113  my $setup = test_setup($tmpdir, 'lang');
3114
3115  my $test_file = File::Spec->rel2abs("$setup->{home_dir}/Grafik-Zentrumäüu.png");
3116  if ($^O eq 'darwin') {
3117    # MacOSX hack
3118    $test_file = ('/private' . $test_file);
3119  }
3120
3121  my $config = {
3122    PidFile => $setup->{pid_file},
3123    ScoreboardFile => $setup->{scoreboard_file},
3124    SystemLog => $setup->{log_file},
3125    TraceLog => $setup->{log_file},
3126    Trace => 'encode:20',
3127
3128    AuthUserFile => $setup->{auth_user_file},
3129    AuthGroupFile => $setup->{auth_group_file},
3130
3131    IfModules => {
3132      'mod_delay.c' => {
3133        DelayEngine => 'off',
3134      },
3135    },
3136  };
3137
3138  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
3139    $config);
3140
3141  if (open(my $fh, ">> $setup->{config_file}")) {
3142    print $fh <<EOC;
3143<IfModule mod_lang.c>
3144  <IfUser $setup->{user}>
3145    UseEncoding utf-8 iso-8859-1
3146  </IfUser>
3147</IfModule>
3148EOC
3149    unless (close($fh)) {
3150      die("Can't write $setup->{config_file}: $!");
3151    }
3152
3153  } else {
3154    die("Can't open $setup->{config_file}: $!");
3155  }
3156
3157  # Open pipes, for use between the parent and child processes.  Specifically,
3158  # the child will indicate when it's done with its test by writing a message
3159  # to the parent.
3160  my ($rfh, $wfh);
3161  unless (pipe($rfh, $wfh)) {
3162    die("Can't open pipe: $!");
3163  }
3164
3165  my $ex;
3166
3167  # Fork child
3168  $self->handle_sigchld();
3169  defined(my $pid = fork()) or die("Can't fork: $!");
3170  if ($pid) {
3171    eval {
3172      my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
3173      $client->login($setup->{user}, $setup->{passwd});
3174
3175      my $name = "Grafik-Zentrumäüu.png";
3176
3177      my $conn = $client->stor_raw($name);
3178      unless ($conn) {
3179        die("STOR $name failed: " . $client->response_code() . " " .
3180          $client->response_msg());
3181      }
3182
3183      my $buf = "Hello, world\n";
3184      $conn->write($buf, length($buf), 15);
3185      eval { $conn->close() };
3186
3187      my $resp_code = $client->response_code();
3188      my $resp_msg = $client->response_msg();
3189      $self->assert_transfer_ok($resp_code, $resp_msg);
3190
3191      $client->quit();
3192
3193      $self->assert(-f $test_file,
3194        test_msg("File $test_file does not exist as expected"));
3195    };
3196
3197    if ($@) {
3198      $ex = $@;
3199    }
3200
3201    $wfh->print("done\n");
3202    $wfh->flush();
3203
3204  } else {
3205    eval { server_wait($setup->{config_file}, $rfh) };
3206    if ($@) {
3207      warn($@);
3208      exit 1;
3209    }
3210
3211    exit 0;
3212  }
3213
3214  # Stop server
3215  server_stop($setup->{pid_file});
3216  $self->assert_child_ok($pid);
3217  test_cleanup($setup->{log_file}, $ex);
3218}
3219
32201;
3221