1package ProFTPD::Tests::Config::MaxTransfersPerHost;
2
3use lib qw(t/lib);
4use base qw(ProFTPD::TestSuite::Child);
5use strict;
6
7use File::Spec;
8use IO::Handle;
9
10use ProFTPD::TestSuite::FTP;
11use ProFTPD::TestSuite::Utils qw(:auth :config :running :test :testsuite);
12
13$| = 1;
14
15my $order = 0;
16
17my $TESTS = {
18  maxtransfersperhost_retr => {
19    order => ++$order,
20    test_class => [qw(forking)],
21  },
22
23  maxtransfersperhost_retr_custom_message => {
24    order => ++$order,
25    test_class => [qw(forking)],
26  },
27
28};
29
30sub new {
31  return shift()->SUPER::new(@_);
32}
33
34sub list_tests {
35  return testsuite_get_runnable_tests($TESTS);
36}
37
38sub maxtransfersperhost_retr {
39  my $self = shift;
40  my $tmpdir = $self->{tmpdir};
41  my $setup = test_setup($tmpdir, 'config');
42
43  my $test_file = File::Spec->rel2abs($setup->{config_file});
44  my $max_transfers = 1;
45
46  my $config = {
47    PidFile => $setup->{pid_file},
48    ScoreboardFile => $setup->{scoreboard_file},
49    SystemLog => $setup->{log_file},
50
51    AuthUserFile => $setup->{auth_user_file},
52    AuthGroupFile => $setup->{auth_group_file},
53    MaxTransfersPerHost => "RETR $max_transfers",
54
55    IfModules => {
56      'mod_delay.c' => {
57        DelayEngine => 'off',
58      },
59    },
60  };
61
62  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
63    $config);
64
65  # Open pipes, for use between the parent and child processes.  Specifically,
66  # the child will indicate when it's done with its test by writing a message
67  # to the parent.
68  my ($rfh, $wfh);
69  unless (pipe($rfh, $wfh)) {
70    die("Can't open pipe: $!");
71  }
72
73  my $ex;
74
75  # Fork child
76  $self->handle_sigchld();
77  defined(my $pid = fork()) or die("Can't fork: $!");
78  if ($pid) {
79    eval {
80      # First client should be able to connect and log in...
81      my $client1 = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
82      $client1->login($setup->{user}, $setup->{passwd});
83      my $conn1 = $client1->retr_raw($test_file);
84      unless ($conn1) {
85        die("RETR failed: " . $client1->response_code() . " " .
86          $client1->response_msg());
87      }
88
89      my $client2 = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
90      $client2->login($setup->{user}, $setup->{passwd});
91      my $conn2 = $client2->retr_raw($test_file);
92      if ($conn2) {
93        die("RETR succeeded unexpectedly");
94      }
95
96      my $resp_code = $client2->response_code();
97      my $resp_msg = $client2->response_msg();
98
99      my $expected;
100
101      $expected = 451;
102      $self->assert($expected == $resp_code,
103        test_msg("Expected response code $expected, got $resp_code"));
104
105      $expected = "Sorry, the maximum number of data transfers ($max_transfers) from your host are currently being used.";
106      $self->assert($expected eq $resp_msg,
107        test_msg("Expected response message '$expected', got '$resp_msg'"));
108
109      $client1->quit();
110      $client2->quit();
111    };
112
113    if ($@) {
114      $ex = $@;
115    }
116
117    $wfh->print("done\n");
118    $wfh->flush();
119
120  } else {
121    eval { server_wait($setup->{config_file}, $rfh) };
122    if ($@) {
123      warn($@);
124      exit 1;
125    }
126
127    exit 0;
128  }
129
130  # Stop server
131  server_stop($setup->{pid_file});
132
133  $self->assert_child_ok($pid);
134  test_cleanup($setup->{log_file}, $ex);
135}
136
137sub maxtransfersperhost_retr_custom_message {
138  my $self = shift;
139  my $tmpdir = $self->{tmpdir};
140  my $setup = test_setup($tmpdir, 'config');
141
142  my $test_file = File::Spec->rel2abs($setup->{config_file});
143  my $max_transfers = 1;
144
145  my $config = {
146    PidFile => $setup->{pid_file},
147    ScoreboardFile => $setup->{scoreboard_file},
148    SystemLog => $setup->{log_file},
149
150    AuthUserFile => $setup->{auth_user_file},
151    AuthGroupFile => $setup->{auth_group_file},
152    MaxTransfersPerHost => "RETR $max_transfers \"Too many transfers from your host\"",
153
154    IfModules => {
155      'mod_delay.c' => {
156        DelayEngine => 'off',
157      },
158    },
159  };
160
161  my ($port, $config_user, $config_group) = config_write($setup->{config_file},
162    $config);
163
164  # Open pipes, for use between the parent and child processes.  Specifically,
165  # the child will indicate when it's done with its test by writing a message
166  # to the parent.
167  my ($rfh, $wfh);
168  unless (pipe($rfh, $wfh)) {
169    die("Can't open pipe: $!");
170  }
171
172  my $ex;
173
174  # Fork child
175  $self->handle_sigchld();
176  defined(my $pid = fork()) or die("Can't fork: $!");
177  if ($pid) {
178    eval {
179      # First client should be able to connect and log in...
180      my $client1 = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
181      $client1->login($setup->{user}, $setup->{passwd});
182      my $conn1 = $client1->retr_raw($test_file);
183      unless ($conn1) {
184        die("RETR failed: " . $client1->response_code() . " " .
185          $client1->response_msg());
186      }
187
188      my $client2 = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port);
189      $client2->login($setup->{user}, $setup->{passwd});
190      my $conn2 = $client2->retr_raw($test_file);
191      if ($conn2) {
192        die("RETR succeeded unexpectedly");
193      }
194
195      my $resp_code = $client2->response_code();
196      my $resp_msg = $client2->response_msg();
197
198      my $expected;
199
200      $expected = 451;
201      $self->assert($expected == $resp_code,
202        test_msg("Expected response code $expected, got $resp_code"));
203
204      $expected = 'Too many transfers from your host';
205      $self->assert($expected eq $resp_msg,
206        test_msg("Expected response message '$expected', got '$resp_msg'"));
207
208      $client1->quit();
209      $client2->quit();
210    };
211
212    if ($@) {
213      $ex = $@;
214    }
215
216    $wfh->print("done\n");
217    $wfh->flush();
218
219  } else {
220    eval { server_wait($setup->{config_file}, $rfh) };
221    if ($@) {
222      warn($@);
223      exit 1;
224    }
225
226    exit 0;
227  }
228
229  # Stop server
230  server_stop($setup->{pid_file});
231
232  $self->assert_child_ok($pid);
233  test_cleanup($setup->{log_file}, $ex);
234}
235
2361;
237