1package ProFTPD::Tests::Modules::mod_ratio; 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 ratio_bug3600 => { 19 order => ++$order, 20 test_class => [qw(bug forking)], 21 }, 22 23 ratio_after_disconnect => { 24 order => ++$order, 25 test_class => [qw(bug forking)], 26 }, 27 28 ratio_userratio_with_credit => { 29 order => ++$order, 30 test_class => [qw(bug forking)], 31 }, 32 33}; 34 35sub new { 36 return shift()->SUPER::new(@_); 37} 38 39sub list_tests { 40 return testsuite_get_runnable_tests($TESTS); 41} 42 43sub ratio_bug3600 { 44 my $self = shift; 45 my $tmpdir = $self->{tmpdir}; 46 47 my $config_file = "$tmpdir/ratio.conf"; 48 my $pid_file = File::Spec->rel2abs("$tmpdir/ratio.pid"); 49 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ratio.scoreboard"); 50 51 my $log_file = test_get_logfile(); 52 53 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ratio.passwd"); 54 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ratio.group"); 55 56 my $user = 'proftpd'; 57 my $passwd = 'test'; 58 my $group = 'ftpd'; 59 my $home_dir = File::Spec->rel2abs($tmpdir); 60 my $uid = 500; 61 my $gid = 500; 62 63 # Make sure that, if we're running as root, that the home directory has 64 # permissions/privs set for the account we create 65 if ($< == 0) { 66 unless (chmod(0755, $home_dir)) { 67 die("Can't set perms on $home_dir to 0755: $!"); 68 } 69 70 unless (chown($uid, $gid, $home_dir)) { 71 die("Can't set owner of $home_dir to $uid/$gid: $!"); 72 } 73 } 74 75 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 76 '/bin/bash'); 77 auth_group_write($auth_group_file, $group, $gid, $user); 78 79 my $ratio_file = File::Spec->rel2abs("$home_dir/.ratio"); 80 if (open(my $fh, "> $ratio_file")) { 81 unless (close($fh)) { 82 die("Can't write $ratio_file: $!"); 83 } 84 85 } else { 86 die("Can't open $ratio_file: $!"); 87 } 88 89 my $config = { 90 PidFile => $pid_file, 91 ScoreboardFile => $scoreboard_file, 92 SystemLog => $log_file, 93 TraceLog => $log_file, 94 Trace => 'response:10', 95 96 AuthUserFile => $auth_user_file, 97 AuthGroupFile => $auth_group_file, 98 99 IfModules => { 100 'mod_delay.c' => { 101 DelayEngine => 'off', 102 }, 103 104 'mod_ratio.c' => { 105 Ratios => 'on', 106 }, 107 }, 108 }; 109 110 my ($port, $config_user, $config_group) = config_write($config_file, $config); 111 112 # Open pipes, for use between the parent and child processes. Specifically, 113 # the child will indicate when it's done with its test by writing a message 114 # to the parent. 115 my ($rfh, $wfh); 116 unless (pipe($rfh, $wfh)) { 117 die("Can't open pipe: $!"); 118 } 119 120 my $ex; 121 122 # Fork child 123 $self->handle_sigchld(); 124 defined(my $pid = fork()) or die("Can't fork: $!"); 125 if ($pid) { 126 eval { 127 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 128 $client->login($user, $passwd); 129 130 my $resp_code = $client->response_code(); 131 my $resp_msg = $client->response_msg(0); 132 133 my $expected; 134 135 $expected = 230; 136 $self->assert($expected == $resp_code, 137 test_msg("Expected response code $expected, got $resp_code")); 138 139 $expected = "Down: 0 Files (0mb) Up: 0 Files (0mb) 10,000,000:1 CR: LEECH"; 140 $self->assert($expected eq $resp_msg, 141 test_msg("Expected response message '$expected', got '$resp_msg'")); 142 143 ($resp_code, $resp_msg) = $client->syst(); 144 145 $expected = 215; 146 $self->assert($expected == $resp_code, 147 test_msg("Expected response code $expected, got $resp_code")); 148 149 $expected = "UNIX Type: L8"; 150 $self->assert($expected eq $resp_msg, 151 test_msg("Expected response message '$expected', got '$resp_msg'")); 152 153 $client->quit(); 154 }; 155 156 if ($@) { 157 $ex = $@; 158 } 159 160 $wfh->print("done\n"); 161 $wfh->flush(); 162 163 } else { 164 eval { server_wait($config_file, $rfh) }; 165 if ($@) { 166 warn($@); 167 exit 1; 168 } 169 170 exit 0; 171 } 172 173 # Stop server 174 server_stop($pid_file); 175 176 $self->assert_child_ok($pid); 177 178 if ($ex) { 179 test_append_logfile($log_file, $ex); 180 unlink($log_file); 181 182 die($ex); 183 } 184 185 unlink($log_file); 186} 187 188sub ratio_after_disconnect { 189 my $self = shift; 190 my $tmpdir = $self->{tmpdir}; 191 192 my $config_file = "$tmpdir/ratio.conf"; 193 my $pid_file = File::Spec->rel2abs("$tmpdir/ratio.pid"); 194 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ratio.scoreboard"); 195 196 my $log_file = test_get_logfile(); 197 198 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ratio.passwd"); 199 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ratio.group"); 200 201 my $user = 'proftpd'; 202 my $passwd = 'test'; 203 my $group = 'ftpd'; 204 my $home_dir = File::Spec->rel2abs($tmpdir); 205 my $uid = 500; 206 my $gid = 500; 207 208 # Make sure that, if we're running as root, that the home directory has 209 # permissions/privs set for the account we create 210 if ($< == 0) { 211 unless (chmod(0755, $home_dir)) { 212 die("Can't set perms on $home_dir to 0755: $!"); 213 } 214 215 unless (chown($uid, $gid, $home_dir)) { 216 die("Can't set owner of $home_dir to $uid/$gid: $!"); 217 } 218 } 219 220 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 221 '/bin/bash'); 222 auth_group_write($auth_group_file, $group, $gid, $user); 223 224 my $ratio_file = File::Spec->rel2abs("$home_dir/ratios.dat"); 225 if (open(my $fh, "> $ratio_file")) { 226 unless (close($fh)) { 227 die("Can't write $ratio_file: $!"); 228 } 229 230 } else { 231 die("Can't open $ratio_file: $!"); 232 } 233 234 my $ratio_tmp_file = File::Spec->rel2abs("$home_dir/ratios.tmp"); 235 236 my $config = { 237 PidFile => $pid_file, 238 ScoreboardFile => $scoreboard_file, 239 SystemLog => $log_file, 240 TraceLog => $log_file, 241 Trace => 'response:10', 242 243 AuthUserFile => $auth_user_file, 244 AuthGroupFile => $auth_group_file, 245 246 IfModules => { 247 'mod_delay.c' => { 248 DelayEngine => 'off', 249 }, 250 251 'mod_ratio.c' => { 252 Ratios => 'on', 253 SaveRatios => 'on', 254 RatioFile => $ratio_file, 255 RatioTempFile => $ratio_tmp_file, 256 CwdRatioMsg => "Please Upload first", 257 FileRatioErrMsg => "Come on, gimme a lil more", 258 ByteRatioErrMsg => "COME ON NOW", 259 }, 260 }, 261 }; 262 263 my ($port, $config_user, $config_group) = config_write($config_file, $config); 264 265 # Open pipes, for use between the parent and child processes. Specifically, 266 # the child will indicate when it's done with its test by writing a message 267 # to the parent. 268 my ($rfh, $wfh); 269 unless (pipe($rfh, $wfh)) { 270 die("Can't open pipe: $!"); 271 } 272 273 my $ex; 274 275 # Fork child 276 $self->handle_sigchld(); 277 defined(my $pid = fork()) or die("Can't fork: $!"); 278 if ($pid) { 279 eval { 280 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 281 $client->login($user, $passwd); 282 283 my $resp_code = $client->response_code(); 284 my $resp_msg = $client->response_msg(0); 285 286 my $expected; 287 288 $expected = 230; 289 $self->assert($expected == $resp_code, 290 test_msg("Expected response code $expected, got $resp_code")); 291 292 $expected = "Down: 0 Files (0mb) Up: 0 Files (0mb) 10,000,000:1 CR: LEECH"; 293 $self->assert($expected eq $resp_msg, 294 test_msg("Expected response message '$expected', got '$resp_msg'")); 295 296 my $conn = $client->stor_raw("test.txt"); 297 unless ($conn) { 298 die("STOR test.txt failed: " . $client->response_code() . " " . 299 $client->response_msg()); 300 } 301 302 my $buf = "Hello, World!"; 303 $conn->write($buf, length($buf), 5); 304 eval { $conn->close() }; 305 306 $resp_code = $client->response_code(); 307 $resp_msg = $client->response_msg(1); 308 $self->assert_transfer_ok($resp_code, $resp_msg); 309 310 $conn = $client->retr_raw("test.txt"); 311 unless ($conn) { 312 die("RETR test.txt failed: " . $client->response_code() . " " . 313 $client->response_msg()); 314 } 315 316 $conn->read($buf, 8192, 5); 317 eval { $conn->close() }; 318 319 $resp_code = $client->response_code(); 320 $resp_msg = $client->response_msg(1); 321 $self->assert_transfer_ok($resp_code, $resp_msg); 322 323 $client->quit(); 324 }; 325 326 if ($@) { 327 $ex = $@; 328 } 329 330 $wfh->print("done\n"); 331 $wfh->flush(); 332 333 } else { 334 eval { server_wait($config_file, $rfh) }; 335 if ($@) { 336 warn($@); 337 exit 1; 338 } 339 340 exit 0; 341 } 342 343 # Stop server 344 server_stop($pid_file); 345 346 $self->assert_child_ok($pid); 347 348 if (open(my $fh, "< $ratio_file")) { 349 my $line = <$fh>; 350 chomp($line); 351 close($fh); 352 353 my $expected = "$user|2|0|1|0"; 354 $self->assert($line eq $expected, 355 test_msg("Expected RatioFile content '$expected', got '$line'")); 356 357 } else { 358 die("Can't read $ratio_file: $!"); 359 } 360 361 if ($ex) { 362 test_append_logfile($log_file, $ex); 363 unlink($log_file); 364 365 die($ex); 366 } 367 368 unlink($log_file); 369} 370 371# See: https://bugs.launchpad.net/ubuntu/+source/proftpd-dfsg/+bug/479963 372sub ratio_userratio_with_credit { 373 my $self = shift; 374 my $tmpdir = $self->{tmpdir}; 375 376 my $config_file = "$tmpdir/ratio.conf"; 377 my $pid_file = File::Spec->rel2abs("$tmpdir/ratio.pid"); 378 my $scoreboard_file = File::Spec->rel2abs("$tmpdir/ratio.scoreboard"); 379 380 my $log_file = test_get_logfile(); 381 382 my $auth_user_file = File::Spec->rel2abs("$tmpdir/ratio.passwd"); 383 my $auth_group_file = File::Spec->rel2abs("$tmpdir/ratio.group"); 384 385 my $user = 'proftpd'; 386 my $passwd = 'test'; 387 my $group = 'ftpd'; 388 my $home_dir = File::Spec->rel2abs($tmpdir); 389 my $uid = 500; 390 my $gid = 500; 391 392 # Make sure that, if we're running as root, that the home directory has 393 # permissions/privs set for the account we create 394 if ($< == 0) { 395 unless (chmod(0755, $home_dir)) { 396 die("Can't set perms on $home_dir to 0755: $!"); 397 } 398 399 unless (chown($uid, $gid, $home_dir)) { 400 die("Can't set owner of $home_dir to $uid/$gid: $!"); 401 } 402 } 403 404 auth_user_write($auth_user_file, $user, $passwd, $uid, $gid, $home_dir, 405 '/bin/bash'); 406 auth_group_write($auth_group_file, $group, $gid, $user); 407 408 my $ratio_file = File::Spec->rel2abs("$home_dir/ratios.dat"); 409 if (open(my $fh, "> $ratio_file")) { 410 print $fh "$user|7|102404|1|51218\n"; 411 412 unless (close($fh)) { 413 die("Can't write $ratio_file: $!"); 414 } 415 416 } else { 417 die("Can't open $ratio_file: $!"); 418 } 419 420 my $ratio_tmp_file = File::Spec->rel2abs("$home_dir/ratios.tmp"); 421 if (open(my $fh, "> $ratio_tmp_file")) { 422 print $fh "$user|7|102404|1|51218\n"; 423 424 unless (close($fh)) { 425 die("Can't write $ratio_tmp_file: $!"); 426 } 427 428 } else { 429 die("Can't open $ratio_tmp_file: $!"); 430 } 431 432 my $config = { 433 PidFile => $pid_file, 434 ScoreboardFile => $scoreboard_file, 435 SystemLog => $log_file, 436 TraceLog => $log_file, 437 Trace => 'response:10', 438 439 AuthUserFile => $auth_user_file, 440 AuthGroupFile => $auth_group_file, 441 442 IfModules => { 443 'mod_delay.c' => { 444 DelayEngine => 'off', 445 }, 446 447 'mod_ratio.c' => { 448 Ratios => 'on', 449 SaveRatios => 'on', 450 RatioFile => $ratio_file, 451 RatioTempFile => $ratio_tmp_file, 452 CwdRatioMsg => "Please Upload first", 453 FileRatioErrMsg => "Come on, gimme a lil more", 454 ByteRatioErrMsg => "COME ON NOW", 455 UserRatio => '* 0 0 5 2355200', 456 }, 457 }, 458 }; 459 460 my ($port, $config_user, $config_group) = config_write($config_file, $config); 461 462 # Open pipes, for use between the parent and child processes. Specifically, 463 # the child will indicate when it's done with its test by writing a message 464 # to the parent. 465 my ($rfh, $wfh); 466 unless (pipe($rfh, $wfh)) { 467 die("Can't open pipe: $!"); 468 } 469 470 my $ex; 471 472 # Fork child 473 $self->handle_sigchld(); 474 defined(my $pid = fork()) or die("Can't fork: $!"); 475 if ($pid) { 476 eval { 477 my $client = ProFTPD::TestSuite::FTP->new('127.0.0.1', $port); 478 $client->login($user, $passwd); 479 480 my $resp_code = $client->response_code(); 481 my $resp_msg = $client->response_msg(0); 482 483 my $expected; 484 485 $expected = 230; 486 $self->assert($expected == $resp_code, 487 test_msg("Expected response code $expected, got $resp_code")); 488 489 $expected = "Down: 1 Files (0mb) Up: 7 Files (0mb) 1:5B CR: 2300"; 490 $self->assert($expected eq $resp_msg, 491 test_msg("Expected response message '$expected', got '$resp_msg'")); 492 493 my $conn = $client->stor_raw("test.txt"); 494 unless ($conn) { 495 die("STOR test.txt failed: " . $client->response_code() . " " . 496 $client->response_msg()); 497 } 498 499 my $buf = "Hello, World!"; 500 $conn->write($buf, length($buf), 5); 501 eval { $conn->close() }; 502 503 $resp_code = $client->response_code(); 504 $resp_msg = $client->response_msg(1); 505 $self->assert_transfer_ok($resp_code, $resp_msg); 506 507 $conn = $client->retr_raw("test.txt"); 508 unless ($conn) { 509 die("RETR test.txt failed: " . $client->response_code() . " " . 510 $client->response_msg()); 511 } 512 513 $conn->read($buf, 8192, 5); 514 eval { $conn->close() }; 515 516 $resp_code = $client->response_code(); 517 $resp_msg = $client->response_msg(1); 518 $self->assert_transfer_ok($resp_code, $resp_msg); 519 520 $client->quit(); 521 }; 522 523 if ($@) { 524 $ex = $@; 525 } 526 527 $wfh->print("done\n"); 528 $wfh->flush(); 529 530 } else { 531 eval { server_wait($config_file, $rfh) }; 532 if ($@) { 533 warn($@); 534 exit 1; 535 } 536 537 exit 0; 538 } 539 540 # Stop server 541 server_stop($pid_file); 542 543 $self->assert_child_ok($pid); 544 545 if (open(my $fh, "< $ratio_file")) { 546 my $line = <$fh>; 547 chomp($line); 548 close($fh); 549 550 my $expected = "$user|7|102404|1|51218"; 551 $self->assert($line eq $expected, 552 test_msg("Expected RatioFile content '$expected', got '$line'")); 553 554 } else { 555 die("Can't read $ratio_file: $!"); 556 } 557 558 if ($ex) { 559 test_append_logfile($log_file, $ex); 560 unlink($log_file); 561 562 die($ex); 563 } 564 565 unlink($log_file); 566} 567 5681; 569