Annotation of embedaddon/curl/tests/ftpserver.pl, revision 1.1
1.1 ! misho 1: #!/usr/bin/env perl
! 2: #***************************************************************************
! 3: # _ _ ____ _
! 4: # Project ___| | | | _ \| |
! 5: # / __| | | | |_) | |
! 6: # | (__| |_| | _ <| |___
! 7: # \___|\___/|_| \_\_____|
! 8: #
! 9: # Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
! 10: #
! 11: # This software is licensed as described in the file COPYING, which
! 12: # you should have received as part of this distribution. The terms
! 13: # are also available at https://curl.haxx.se/docs/copyright.html.
! 14: #
! 15: # You may opt to use, copy, modify, merge, publish, distribute and/or sell
! 16: # copies of the Software, and permit persons to whom the Software is
! 17: # furnished to do so, under the terms of the COPYING file.
! 18: #
! 19: # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
! 20: # KIND, either express or implied.
! 21: #
! 22: ###########################################################################
! 23:
! 24: # This is a server designed for the curl test suite.
! 25: #
! 26: # In December 2009 we started remaking the server to support more protocols
! 27: # that are similar in spirit. Like POP3, IMAP and SMTP in addition to the FTP
! 28: # it already supported since a long time. Note that it still only supports one
! 29: # protocol per invoke. You need to start multiple servers to support multiple
! 30: # protocols simultaneously.
! 31: #
! 32: # It is meant to exercise curl, it is not meant to be a fully working
! 33: # or even very standard compliant server.
! 34: #
! 35: # You may optionally specify port on the command line, otherwise it'll
! 36: # default to port 8921.
! 37: #
! 38: # All socket/network/TCP related stuff is done by the 'sockfilt' program.
! 39: #
! 40:
! 41: BEGIN {
! 42: push(@INC, $ENV{'srcdir'}) if(defined $ENV{'srcdir'});
! 43: push(@INC, ".");
! 44: # sub second timestamping needs Time::HiRes
! 45: eval {
! 46: no warnings "all";
! 47: require Time::HiRes;
! 48: import Time::HiRes qw( gettimeofday );
! 49: }
! 50: }
! 51:
! 52: use strict;
! 53: use warnings;
! 54: use IPC::Open2;
! 55: use Digest::MD5;
! 56:
! 57: require "getpart.pm";
! 58: require "ftp.pm";
! 59: require "directories.pm";
! 60:
! 61: use serverhelp qw(
! 62: servername_str
! 63: server_pidfilename
! 64: server_logfilename
! 65: mainsockf_pidfilename
! 66: mainsockf_logfilename
! 67: datasockf_pidfilename
! 68: datasockf_logfilename
! 69: );
! 70:
! 71: use sshhelp qw(
! 72: exe_ext
! 73: );
! 74:
! 75: #**********************************************************************
! 76: # global vars...
! 77: #
! 78: my $verbose = 0; # set to 1 for debugging
! 79: my $idstr = ""; # server instance string
! 80: my $idnum = 1; # server instance number
! 81: my $ipvnum = 4; # server IPv number (4 or 6)
! 82: my $proto = 'ftp'; # default server protocol
! 83: my $srcdir; # directory where ftpserver.pl is located
! 84: my $srvrname; # server name for presentation purposes
! 85: my $cwd_testno; # test case numbers extracted from CWD command
! 86: my $path = '.';
! 87: my $logdir = $path .'/log';
! 88:
! 89: #**********************************************************************
! 90: # global vars used for server address and primary listener port
! 91: #
! 92: my $port = 8921; # default primary listener port
! 93: my $listenaddr = '127.0.0.1'; # default address for listener port
! 94:
! 95: #**********************************************************************
! 96: # global vars used for file names
! 97: #
! 98: my $pidfile; # server pid file name
! 99: my $portfile=".ftpserver.port"; # server port file name
! 100: my $logfile; # server log file name
! 101: my $mainsockf_pidfile; # pid file for primary connection sockfilt process
! 102: my $mainsockf_logfile; # log file for primary connection sockfilt process
! 103: my $datasockf_pidfile; # pid file for secondary connection sockfilt process
! 104: my $datasockf_logfile; # log file for secondary connection sockfilt process
! 105:
! 106: #**********************************************************************
! 107: # global vars used for server logs advisor read lock handling
! 108: #
! 109: my $SERVERLOGS_LOCK = 'log/serverlogs.lock';
! 110: my $serverlogslocked = 0;
! 111:
! 112: #**********************************************************************
! 113: # global vars used for child processes PID tracking
! 114: #
! 115: my $sfpid; # PID for primary connection sockfilt process
! 116: my $slavepid; # PID for secondary connection sockfilt process
! 117:
! 118: #**********************************************************************
! 119: # global typeglob filehandle vars to read/write from/to sockfilters
! 120: #
! 121: local *SFREAD; # used to read from primary connection
! 122: local *SFWRITE; # used to write to primary connection
! 123: local *DREAD; # used to read from secondary connection
! 124: local *DWRITE; # used to write to secondary connection
! 125:
! 126: my $sockfilt_timeout = 5; # default timeout for sockfilter eXsysreads
! 127:
! 128: #**********************************************************************
! 129: # global vars which depend on server protocol selection
! 130: #
! 131: my %commandfunc; # protocol command specific function callbacks
! 132: my %displaytext; # text returned to client before callback runs
! 133:
! 134: #**********************************************************************
! 135: # global vars customized for each test from the server commands file
! 136: #
! 137: my $ctrldelay; # set if server should throttle ctrl stream
! 138: my $datadelay; # set if server should throttle data stream
! 139: my $retrweirdo; # set if ftp server should use RETRWEIRDO
! 140: my $retrnosize; # set if ftp server should use RETRNOSIZE
! 141: my $pasvbadip; # set if ftp server should use PASVBADIP
! 142: my $nosave; # set if ftp server should not save uploaded data
! 143: my $nodataconn; # set if ftp srvr doesn't establish or accepts data channel
! 144: my $nodataconn425; # set if ftp srvr doesn't establish data ch and replies 425
! 145: my $nodataconn421; # set if ftp srvr doesn't establish data ch and replies 421
! 146: my $nodataconn150; # set if ftp srvr doesn't establish data ch and replies 150
! 147: my @capabilities; # set if server supports capability commands
! 148: my @auth_mechs; # set if server supports authentication commands
! 149: my %fulltextreply; #
! 150: my %commandreply; #
! 151: my %customcount; #
! 152: my %delayreply; #
! 153:
! 154: #**********************************************************************
! 155: # global variables for to test ftp wildcardmatching or other test that
! 156: # need flexible LIST responses.. and corresponding files.
! 157: # $ftptargetdir is keeping the fake "name" of LIST directory.
! 158: #
! 159: my $ftplistparserstate;
! 160: my $ftptargetdir="";
! 161:
! 162: #**********************************************************************
! 163: # global variables used when running a ftp server to keep state info
! 164: # relative to the secondary or data sockfilt process. Values of these
! 165: # variables should only be modified using datasockf_state() sub, given
! 166: # that they are closely related and relationship is a bit awkward.
! 167: #
! 168: my $datasockf_state = 'STOPPED'; # see datasockf_state() sub
! 169: my $datasockf_mode = 'none'; # ['none','active','passive']
! 170: my $datasockf_runs = 'no'; # ['no','yes']
! 171: my $datasockf_conn = 'no'; # ['no','yes']
! 172:
! 173: #**********************************************************************
! 174: # global vars used for signal handling
! 175: #
! 176: my $got_exit_signal = 0; # set if program should finish execution ASAP
! 177: my $exit_signal; # first signal handled in exit_signal_handler
! 178:
! 179: #**********************************************************************
! 180: # Mail related definitions
! 181: #
! 182: my $TEXT_PASSWORD = "secret";
! 183: my $POP3_TIMESTAMP = "<1972.987654321\@curl>";
! 184:
! 185: #**********************************************************************
! 186: # exit_signal_handler will be triggered to indicate that the program
! 187: # should finish its execution in a controlled way as soon as possible.
! 188: # For now, program will also terminate from within this handler.
! 189: #
! 190: sub exit_signal_handler {
! 191: my $signame = shift;
! 192: # For now, simply mimic old behavior.
! 193: killsockfilters($proto, $ipvnum, $idnum, $verbose);
! 194: unlink($pidfile);
! 195: unlink($portfile);
! 196: if($serverlogslocked) {
! 197: $serverlogslocked = 0;
! 198: clear_advisor_read_lock($SERVERLOGS_LOCK);
! 199: }
! 200: exit;
! 201: }
! 202:
! 203: #**********************************************************************
! 204: # logmsg is general message logging subroutine for our test servers.
! 205: #
! 206: sub logmsg {
! 207: my $now;
! 208: # sub second timestamping needs Time::HiRes
! 209: if($Time::HiRes::VERSION) {
! 210: my ($seconds, $usec) = gettimeofday();
! 211: my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
! 212: localtime($seconds);
! 213: $now = sprintf("%02d:%02d:%02d.%06d ", $hour, $min, $sec, $usec);
! 214: }
! 215: else {
! 216: my $seconds = time();
! 217: my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
! 218: localtime($seconds);
! 219: $now = sprintf("%02d:%02d:%02d ", $hour, $min, $sec);
! 220: }
! 221: if(open(LOGFILEFH, ">>$logfile")) {
! 222: print LOGFILEFH $now;
! 223: print LOGFILEFH @_;
! 224: close(LOGFILEFH);
! 225: }
! 226: }
! 227:
! 228: sub ftpmsg {
! 229: # append to the server.input file
! 230: open(INPUT, ">>log/server$idstr.input") ||
! 231: logmsg "failed to open log/server$idstr.input\n";
! 232:
! 233: print INPUT @_;
! 234: close(INPUT);
! 235:
! 236: # use this, open->print->close system only to make the file
! 237: # open as little as possible, to make the test suite run
! 238: # better on windows/cygwin
! 239: }
! 240:
! 241: #**********************************************************************
! 242: # eXsysread is a wrapper around perl's sysread() function. This will
! 243: # repeat the call to sysread() until it has actually read the complete
! 244: # number of requested bytes or an unrecoverable condition occurs.
! 245: # On success returns a positive value, the number of bytes requested.
! 246: # On failure or timeout returns zero.
! 247: #
! 248: sub eXsysread {
! 249: my $FH = shift;
! 250: my $scalar = shift;
! 251: my $nbytes = shift;
! 252: my $timeout = shift; # A zero timeout disables eXsysread() time limit
! 253: #
! 254: my $time_limited = 0;
! 255: my $timeout_rest = 0;
! 256: my $start_time = 0;
! 257: my $nread = 0;
! 258: my $rc;
! 259:
! 260: $$scalar = "";
! 261:
! 262: if((not defined $nbytes) || ($nbytes < 1)) {
! 263: logmsg "Error: eXsysread() failure: " .
! 264: "length argument must be positive\n";
! 265: return 0;
! 266: }
! 267: if((not defined $timeout) || ($timeout < 0)) {
! 268: logmsg "Error: eXsysread() failure: " .
! 269: "timeout argument must be zero or positive\n";
! 270: return 0;
! 271: }
! 272: if($timeout > 0) {
! 273: # caller sets eXsysread() time limit
! 274: $time_limited = 1;
! 275: $timeout_rest = $timeout;
! 276: $start_time = int(time());
! 277: }
! 278:
! 279: while($nread < $nbytes) {
! 280: if($time_limited) {
! 281: eval {
! 282: local $SIG{ALRM} = sub { die "alarm\n"; };
! 283: alarm $timeout_rest;
! 284: $rc = sysread($FH, $$scalar, $nbytes - $nread, $nread);
! 285: alarm 0;
! 286: };
! 287: $timeout_rest = $timeout - (int(time()) - $start_time);
! 288: if($timeout_rest < 1) {
! 289: logmsg "Error: eXsysread() failure: timed out\n";
! 290: return 0;
! 291: }
! 292: }
! 293: else {
! 294: $rc = sysread($FH, $$scalar, $nbytes - $nread, $nread);
! 295: }
! 296: if($got_exit_signal) {
! 297: logmsg "Error: eXsysread() failure: signalled to die\n";
! 298: return 0;
! 299: }
! 300: if(not defined $rc) {
! 301: if($!{EINTR}) {
! 302: logmsg "Warning: retrying sysread() interrupted system call\n";
! 303: next;
! 304: }
! 305: if($!{EAGAIN}) {
! 306: logmsg "Warning: retrying sysread() due to EAGAIN\n";
! 307: next;
! 308: }
! 309: if($!{EWOULDBLOCK}) {
! 310: logmsg "Warning: retrying sysread() due to EWOULDBLOCK\n";
! 311: next;
! 312: }
! 313: logmsg "Error: sysread() failure: $!\n";
! 314: return 0;
! 315: }
! 316: if($rc < 0) {
! 317: logmsg "Error: sysread() failure: returned negative value $rc\n";
! 318: return 0;
! 319: }
! 320: if($rc == 0) {
! 321: logmsg "Error: sysread() failure: read zero bytes\n";
! 322: return 0;
! 323: }
! 324: $nread += $rc;
! 325: }
! 326: return $nread;
! 327: }
! 328:
! 329: #**********************************************************************
! 330: # read_mainsockf attempts to read the given amount of output from the
! 331: # sockfilter which is in use for the main or primary connection. This
! 332: # reads untranslated sockfilt lingo which may hold data read from the
! 333: # main or primary socket. On success returns 1, otherwise zero.
! 334: #
! 335: sub read_mainsockf {
! 336: my $scalar = shift;
! 337: my $nbytes = shift;
! 338: my $timeout = shift; # Optional argument, if zero blocks indefinitely
! 339: my $FH = \*SFREAD;
! 340:
! 341: if(not defined $timeout) {
! 342: $timeout = $sockfilt_timeout + ($nbytes >> 12);
! 343: }
! 344: if(eXsysread($FH, $scalar, $nbytes, $timeout) != $nbytes) {
! 345: my ($fcaller, $lcaller) = (caller)[1,2];
! 346: logmsg "Error: read_mainsockf() failure at $fcaller " .
! 347: "line $lcaller. Due to eXsysread() failure\n";
! 348: return 0;
! 349: }
! 350: return 1;
! 351: }
! 352:
! 353: #**********************************************************************
! 354: # read_datasockf attempts to read the given amount of output from the
! 355: # sockfilter which is in use for the data or secondary connection. This
! 356: # reads untranslated sockfilt lingo which may hold data read from the
! 357: # data or secondary socket. On success returns 1, otherwise zero.
! 358: #
! 359: sub read_datasockf {
! 360: my $scalar = shift;
! 361: my $nbytes = shift;
! 362: my $timeout = shift; # Optional argument, if zero blocks indefinitely
! 363: my $FH = \*DREAD;
! 364:
! 365: if(not defined $timeout) {
! 366: $timeout = $sockfilt_timeout + ($nbytes >> 12);
! 367: }
! 368: if(eXsysread($FH, $scalar, $nbytes, $timeout) != $nbytes) {
! 369: my ($fcaller, $lcaller) = (caller)[1,2];
! 370: logmsg "Error: read_datasockf() failure at $fcaller " .
! 371: "line $lcaller. Due to eXsysread() failure\n";
! 372: return 0;
! 373: }
! 374: return 1;
! 375: }
! 376:
! 377: sub sysread_or_die {
! 378: my $FH = shift;
! 379: my $scalar = shift;
! 380: my $length = shift;
! 381: my $fcaller;
! 382: my $lcaller;
! 383: my $result;
! 384:
! 385: $result = sysread($$FH, $$scalar, $length);
! 386:
! 387: if(not defined $result) {
! 388: ($fcaller, $lcaller) = (caller)[1,2];
! 389: logmsg "Failed to read input\n";
! 390: logmsg "Error: $srvrname server, sysread error: $!\n";
! 391: logmsg "Exited from sysread_or_die() at $fcaller " .
! 392: "line $lcaller. $srvrname server, sysread error: $!\n";
! 393: killsockfilters($proto, $ipvnum, $idnum, $verbose);
! 394: unlink($pidfile);
! 395: unlink($portfile);
! 396: if($serverlogslocked) {
! 397: $serverlogslocked = 0;
! 398: clear_advisor_read_lock($SERVERLOGS_LOCK);
! 399: }
! 400: exit;
! 401: }
! 402: elsif($result == 0) {
! 403: ($fcaller, $lcaller) = (caller)[1,2];
! 404: logmsg "Failed to read input\n";
! 405: logmsg "Error: $srvrname server, read zero\n";
! 406: logmsg "Exited from sysread_or_die() at $fcaller " .
! 407: "line $lcaller. $srvrname server, read zero\n";
! 408: killsockfilters($proto, $ipvnum, $idnum, $verbose);
! 409: unlink($pidfile);
! 410: unlink($portfile);
! 411: if($serverlogslocked) {
! 412: $serverlogslocked = 0;
! 413: clear_advisor_read_lock($SERVERLOGS_LOCK);
! 414: }
! 415: exit;
! 416: }
! 417:
! 418: return $result;
! 419: }
! 420:
! 421: sub startsf {
! 422: my $mainsockfcmd = "./server/sockfilt".exe_ext('SRV')." " .
! 423: "--ipv$ipvnum --port $port " .
! 424: "--pidfile \"$mainsockf_pidfile\" " .
! 425: "--portfile \"$portfile\" " .
! 426: "--logfile \"$mainsockf_logfile\"";
! 427: $sfpid = open2(*SFREAD, *SFWRITE, $mainsockfcmd);
! 428:
! 429: print STDERR "$mainsockfcmd\n" if($verbose);
! 430:
! 431: print SFWRITE "PING\n";
! 432: my $pong;
! 433: sysread_or_die(\*SFREAD, \$pong, 5);
! 434:
! 435: if($pong !~ /^PONG/) {
! 436: logmsg "Failed sockfilt command: $mainsockfcmd\n";
! 437: killsockfilters($proto, $ipvnum, $idnum, $verbose);
! 438: unlink($pidfile);
! 439: unlink($portfile);
! 440: if($serverlogslocked) {
! 441: $serverlogslocked = 0;
! 442: clear_advisor_read_lock($SERVERLOGS_LOCK);
! 443: }
! 444: die "Failed to start sockfilt!";
! 445: }
! 446: }
! 447:
! 448: #**********************************************************************
! 449: # Returns the given test's reply data
! 450: #
! 451: sub getreplydata {
! 452: my ($testno) = @_;
! 453: my $testpart = "";
! 454:
! 455: $testno =~ s/^([^0-9]*)//;
! 456: if($testno > 10000) {
! 457: $testpart = $testno % 10000;
! 458: $testno = int($testno / 10000);
! 459: }
! 460:
! 461: loadtest("$srcdir/data/test$testno");
! 462:
! 463: my @data = getpart("reply", "data$testpart");
! 464: if((!@data) && ($testpart ne "")) {
! 465: @data = getpart("reply", "data");
! 466: }
! 467:
! 468: return @data;
! 469: }
! 470:
! 471: sub sockfilt {
! 472: my $l;
! 473: foreach $l (@_) {
! 474: printf SFWRITE "DATA\n%04x\n", length($l);
! 475: print SFWRITE $l;
! 476: }
! 477: }
! 478:
! 479: sub sockfiltsecondary {
! 480: my $l;
! 481: foreach $l (@_) {
! 482: printf DWRITE "DATA\n%04x\n", length($l);
! 483: print DWRITE $l;
! 484: }
! 485: }
! 486:
! 487: #**********************************************************************
! 488: # Send data to the client on the control stream, which happens to be plain
! 489: # stdout.
! 490: #
! 491: sub sendcontrol {
! 492: if(!$ctrldelay) {
! 493: # spit it all out at once
! 494: sockfilt @_;
! 495: }
! 496: else {
! 497: my $a = join("", @_);
! 498: my @a = split("", $a);
! 499:
! 500: for(@a) {
! 501: sockfilt $_;
! 502: portable_sleep(0.01);
! 503: }
! 504: }
! 505: my $log;
! 506: foreach $log (@_) {
! 507: my $l = $log;
! 508: $l =~ s/\r/[CR]/g;
! 509: $l =~ s/\n/[LF]/g;
! 510: logmsg "> \"$l\"\n";
! 511: }
! 512: }
! 513:
! 514: #**********************************************************************
! 515: # Send data to the FTP client on the data stream when data connection
! 516: # is actually established. Given that this sub should only be called
! 517: # when a data connection is supposed to be established, calling this
! 518: # without a data connection is an indication of weak logic somewhere.
! 519: #
! 520: sub senddata {
! 521: my $l;
! 522: if($datasockf_conn eq 'no') {
! 523: logmsg "WARNING: Detected data sending attempt without DATA channel\n";
! 524: foreach $l (@_) {
! 525: logmsg "WARNING: Data swallowed: $l\n"
! 526: }
! 527: return;
! 528: }
! 529:
! 530: foreach $l (@_) {
! 531: if(!$datadelay) {
! 532: # spit it all out at once
! 533: sockfiltsecondary $l;
! 534: }
! 535: else {
! 536: # pause between each byte
! 537: for (split(//,$l)) {
! 538: sockfiltsecondary $_;
! 539: portable_sleep(0.01);
! 540: }
! 541: }
! 542: }
! 543: }
! 544:
! 545: #**********************************************************************
! 546: # protocolsetup initializes the 'displaytext' and 'commandfunc' hashes
! 547: # for the given protocol. References to protocol command callbacks are
! 548: # stored in 'commandfunc' hash, and text which will be returned to the
! 549: # client before the command callback runs is stored in 'displaytext'.
! 550: #
! 551: sub protocolsetup {
! 552: my $proto = $_[0];
! 553:
! 554: if($proto eq 'ftp') {
! 555: %commandfunc = (
! 556: 'PORT' => \&PORT_ftp,
! 557: 'EPRT' => \&PORT_ftp,
! 558: 'LIST' => \&LIST_ftp,
! 559: 'NLST' => \&NLST_ftp,
! 560: 'PASV' => \&PASV_ftp,
! 561: 'CWD' => \&CWD_ftp,
! 562: 'PWD' => \&PWD_ftp,
! 563: 'EPSV' => \&PASV_ftp,
! 564: 'RETR' => \&RETR_ftp,
! 565: 'SIZE' => \&SIZE_ftp,
! 566: 'REST' => \&REST_ftp,
! 567: 'STOR' => \&STOR_ftp,
! 568: 'APPE' => \&STOR_ftp, # append looks like upload
! 569: 'MDTM' => \&MDTM_ftp,
! 570: );
! 571: %displaytext = (
! 572: 'USER' => '331 We are happy you popped in!',
! 573: 'PASS' => '230 Welcome you silly person',
! 574: 'PORT' => '200 You said PORT - I say FINE',
! 575: 'TYPE' => '200 I modify TYPE as you wanted',
! 576: 'LIST' => '150 here comes a directory',
! 577: 'NLST' => '150 here comes a directory',
! 578: 'CWD' => '250 CWD command successful.',
! 579: 'SYST' => '215 UNIX Type: L8', # just fake something
! 580: 'QUIT' => '221 bye bye baby', # just reply something
! 581: 'MKD' => '257 Created your requested directory',
! 582: 'REST' => '350 Yeah yeah we set it there for you',
! 583: 'DELE' => '200 OK OK OK whatever you say',
! 584: 'RNFR' => '350 Received your order. Please provide more',
! 585: 'RNTO' => '250 Ok, thanks. File renaming completed.',
! 586: 'NOOP' => '200 Yes, I\'m very good at doing nothing.',
! 587: 'PBSZ' => '500 PBSZ not implemented',
! 588: 'PROT' => '500 PROT not implemented',
! 589: 'welcome' => join("",
! 590: '220- _ _ ____ _ '."\r\n",
! 591: '220- ___| | | | _ \| | '."\r\n",
! 592: '220- / __| | | | |_) | | '."\r\n",
! 593: '220- | (__| |_| | _ {| |___ '."\r\n",
! 594: '220 \___|\___/|_| \_\_____|'."\r\n")
! 595: );
! 596: }
! 597: elsif($proto eq 'pop3') {
! 598: %commandfunc = (
! 599: 'APOP' => \&APOP_pop3,
! 600: 'AUTH' => \&AUTH_pop3,
! 601: 'CAPA' => \&CAPA_pop3,
! 602: 'DELE' => \&DELE_pop3,
! 603: 'LIST' => \&LIST_pop3,
! 604: 'NOOP' => \&NOOP_pop3,
! 605: 'PASS' => \&PASS_pop3,
! 606: 'QUIT' => \&QUIT_pop3,
! 607: 'RETR' => \&RETR_pop3,
! 608: 'RSET' => \&RSET_pop3,
! 609: 'STAT' => \&STAT_pop3,
! 610: 'TOP' => \&TOP_pop3,
! 611: 'UIDL' => \&UIDL_pop3,
! 612: 'USER' => \&USER_pop3,
! 613: );
! 614: %displaytext = (
! 615: 'welcome' => join("",
! 616: ' _ _ ____ _ '."\r\n",
! 617: ' ___| | | | _ \| | '."\r\n",
! 618: ' / __| | | | |_) | | '."\r\n",
! 619: ' | (__| |_| | _ {| |___ '."\r\n",
! 620: ' \___|\___/|_| \_\_____|'."\r\n",
! 621: '+OK curl POP3 server ready to serve '."\r\n")
! 622: );
! 623: }
! 624: elsif($proto eq 'imap') {
! 625: %commandfunc = (
! 626: 'APPEND' => \&APPEND_imap,
! 627: 'CAPABILITY' => \&CAPABILITY_imap,
! 628: 'CHECK' => \&CHECK_imap,
! 629: 'CLOSE' => \&CLOSE_imap,
! 630: 'COPY' => \©_imap,
! 631: 'CREATE' => \&CREATE_imap,
! 632: 'DELETE' => \&DELETE_imap,
! 633: 'EXAMINE' => \&EXAMINE_imap,
! 634: 'EXPUNGE' => \&EXPUNGE_imap,
! 635: 'FETCH' => \&FETCH_imap,
! 636: 'LIST' => \&LIST_imap,
! 637: 'LSUB' => \&LSUB_imap,
! 638: 'LOGIN' => \&LOGIN_imap,
! 639: 'LOGOUT' => \&LOGOUT_imap,
! 640: 'NOOP' => \&NOOP_imap,
! 641: 'RENAME' => \&RENAME_imap,
! 642: 'SEARCH' => \&SEARCH_imap,
! 643: 'SELECT' => \&SELECT_imap,
! 644: 'STATUS' => \&STATUS_imap,
! 645: 'STORE' => \&STORE_imap,
! 646: 'UID' => \&UID_imap,
! 647: );
! 648: %displaytext = (
! 649: 'welcome' => join("",
! 650: ' _ _ ____ _ '."\r\n",
! 651: ' ___| | | | _ \| | '."\r\n",
! 652: ' / __| | | | |_) | | '."\r\n",
! 653: ' | (__| |_| | _ {| |___ '."\r\n",
! 654: ' \___|\___/|_| \_\_____|'."\r\n",
! 655: '* OK curl IMAP server ready to serve'."\r\n")
! 656: );
! 657: }
! 658: elsif($proto eq 'smtp') {
! 659: %commandfunc = (
! 660: 'DATA' => \&DATA_smtp,
! 661: 'EHLO' => \&EHLO_smtp,
! 662: 'EXPN' => \&EXPN_smtp,
! 663: 'HELO' => \&HELO_smtp,
! 664: 'HELP' => \&HELP_smtp,
! 665: 'MAIL' => \&MAIL_smtp,
! 666: 'NOOP' => \&NOOP_smtp,
! 667: 'RSET' => \&RSET_smtp,
! 668: 'RCPT' => \&RCPT_smtp,
! 669: 'VRFY' => \&VRFY_smtp,
! 670: 'QUIT' => \&QUIT_smtp,
! 671: );
! 672: %displaytext = (
! 673: 'welcome' => join("",
! 674: '220- _ _ ____ _ '."\r\n",
! 675: '220- ___| | | | _ \| | '."\r\n",
! 676: '220- / __| | | | |_) | | '."\r\n",
! 677: '220- | (__| |_| | _ {| |___ '."\r\n",
! 678: '220 \___|\___/|_| \_\_____|'."\r\n")
! 679: );
! 680: }
! 681: }
! 682:
! 683: sub close_dataconn {
! 684: my ($closed)=@_; # non-zero if already disconnected
! 685:
! 686: my $datapid = processexists($datasockf_pidfile);
! 687:
! 688: logmsg "=====> Closing $datasockf_mode DATA connection...\n";
! 689:
! 690: if(!$closed) {
! 691: if($datapid > 0) {
! 692: logmsg "Server disconnects $datasockf_mode DATA connection\n";
! 693: print DWRITE "DISC\n";
! 694: my $i;
! 695: sysread DREAD, $i, 5;
! 696: logmsg "Server disconnected $datasockf_mode DATA connection\n";
! 697: }
! 698: else {
! 699: logmsg "Server finds $datasockf_mode DATA connection already ".
! 700: "disconnected\n";
! 701: }
! 702: }
! 703: else {
! 704: logmsg "Server knows $datasockf_mode DATA connection is already ".
! 705: "disconnected\n";
! 706: }
! 707:
! 708: if($datapid > 0) {
! 709: logmsg "DATA sockfilt for $datasockf_mode data channel quits ".
! 710: "(pid $datapid)\n";
! 711: print DWRITE "QUIT\n";
! 712: pidwait($datapid, 0);
! 713: unlink($datasockf_pidfile) if(-f $datasockf_pidfile);
! 714: logmsg "DATA sockfilt for $datasockf_mode data channel quit ".
! 715: "(pid $datapid)\n";
! 716: }
! 717: else {
! 718: logmsg "DATA sockfilt for $datasockf_mode data channel already ".
! 719: "dead\n";
! 720: }
! 721:
! 722: logmsg "=====> Closed $datasockf_mode DATA connection\n";
! 723:
! 724: datasockf_state('STOPPED');
! 725: }
! 726:
! 727: ################
! 728: ################ SMTP commands
! 729: ################
! 730:
! 731: # The type of server (SMTP or ESMTP)
! 732: my $smtp_type;
! 733:
! 734: # The client (which normally contains the test number)
! 735: my $smtp_client;
! 736:
! 737: sub EHLO_smtp {
! 738: my ($client) = @_;
! 739: my @data;
! 740:
! 741: # TODO: Get the IP address of the client connection to use in the
! 742: # EHLO response when the client doesn't specify one but for now use
! 743: # 127.0.0.1
! 744: if(!$client) {
! 745: $client = "[127.0.0.1]";
! 746: }
! 747:
! 748: # Set the server type to ESMTP
! 749: $smtp_type = "ESMTP";
! 750:
! 751: # Calculate the EHLO response
! 752: push @data, "$smtp_type pingpong test server Hello $client";
! 753:
! 754: if((@capabilities) || (@auth_mechs)) {
! 755: my $mechs;
! 756:
! 757: for my $c (@capabilities) {
! 758: push @data, $c;
! 759: }
! 760:
! 761: for my $am (@auth_mechs) {
! 762: if(!$mechs) {
! 763: $mechs = "$am";
! 764: }
! 765: else {
! 766: $mechs .= " $am";
! 767: }
! 768: }
! 769:
! 770: if($mechs) {
! 771: push @data, "AUTH $mechs";
! 772: }
! 773: }
! 774:
! 775: # Send the EHLO response
! 776: for(my $i = 0; $i < @data; $i++) {
! 777: my $d = $data[$i];
! 778:
! 779: if($i < @data - 1) {
! 780: sendcontrol "250-$d\r\n";
! 781: }
! 782: else {
! 783: sendcontrol "250 $d\r\n";
! 784: }
! 785: }
! 786:
! 787: # Store the client (as it may contain the test number)
! 788: $smtp_client = $client;
! 789:
! 790: return 0;
! 791: }
! 792:
! 793: sub HELO_smtp {
! 794: my ($client) = @_;
! 795:
! 796: # TODO: Get the IP address of the client connection to use in the HELO
! 797: # response when the client doesn't specify one but for now use 127.0.0.1
! 798: if(!$client) {
! 799: $client = "[127.0.0.1]";
! 800: }
! 801:
! 802: # Set the server type to SMTP
! 803: $smtp_type = "SMTP";
! 804:
! 805: # Send the HELO response
! 806: sendcontrol "250 $smtp_type pingpong test server Hello $client\r\n";
! 807:
! 808: # Store the client (as it may contain the test number)
! 809: $smtp_client = $client;
! 810:
! 811: return 0;
! 812: }
! 813:
! 814: sub MAIL_smtp {
! 815: my ($args) = @_;
! 816:
! 817: logmsg "MAIL_smtp got $args\n";
! 818:
! 819: if (!$args) {
! 820: sendcontrol "501 Unrecognized parameter\r\n";
! 821: }
! 822: else {
! 823: my $from;
! 824: my $size;
! 825: my $smtputf8 = grep /^SMTPUTF8$/, @capabilities;
! 826: my @elements = split(/ /, $args);
! 827:
! 828: # Get the FROM and SIZE parameters
! 829: for my $e (@elements) {
! 830: if($e =~ /^FROM:(.*)$/) {
! 831: $from = $1;
! 832: }
! 833: elsif($e =~ /^SIZE=(\d+)$/) {
! 834: $size = $1;
! 835: }
! 836: }
! 837:
! 838: # Validate the from address (only <> and a valid email address inside
! 839: # <> are allowed, such as <user@example.com>)
! 840: if (($from eq "<>") ||
! 841: (!$smtputf8 && $from =~
! 842: /^<([a-zA-Z0-9._%+-]+)\@(([a-zA-Z0-9-]+)\.)+([a-zA-Z]{2,4})>$/) ||
! 843: ($smtputf8 && $from =~
! 844: /^<([a-zA-Z0-9\x{80}-\x{ff}._%+-]+)\@(([a-zA-Z0-9\x{80}-\x{ff}-]+)\.)+([a-zA-Z]{2,4})>$/)) {
! 845: my @found;
! 846: my $valid = 1;
! 847:
! 848: # Check the capabilities for SIZE and if the specified size is
! 849: # greater than the message size then reject it
! 850: if (@found = grep /^SIZE (\d+)$/, @capabilities) {
! 851: if ($found[0] =~ /^SIZE (\d+)$/) {
! 852: if ($size > $1) {
! 853: $valid = 0;
! 854: }
! 855: }
! 856: }
! 857:
! 858: if(!$valid) {
! 859: sendcontrol "552 Message size too large\r\n";
! 860: }
! 861: else {
! 862: sendcontrol "250 Sender OK\r\n";
! 863: }
! 864: }
! 865: else {
! 866: sendcontrol "501 Invalid address\r\n";
! 867: }
! 868: }
! 869:
! 870: return 0;
! 871: }
! 872:
! 873: sub RCPT_smtp {
! 874: my ($args) = @_;
! 875:
! 876: logmsg "RCPT_smtp got $args\n";
! 877:
! 878: # Get the TO parameter
! 879: if($args !~ /^TO:(.*)/) {
! 880: sendcontrol "501 Unrecognized parameter\r\n";
! 881: }
! 882: else {
! 883: my $smtputf8 = grep /^SMTPUTF8$/, @capabilities;
! 884: my $to = $1;
! 885:
! 886: # Validate the to address (only a valid email address inside <> is
! 887: # allowed, such as <user@example.com>)
! 888: if ((!$smtputf8 && $to =~
! 889: /^<([a-zA-Z0-9._%+-]+)\@(([a-zA-Z0-9-]+)\.)+([a-zA-Z]{2,4})>$/) ||
! 890: ($smtputf8 && $to =~
! 891: /^<([a-zA-Z0-9\x{80}-\x{ff}._%+-]+)\@(([a-zA-Z0-9\x{80}-\x{ff}-]+)\.)+([a-zA-Z]{2,4})>$/)) {
! 892: sendcontrol "250 Recipient OK\r\n";
! 893: }
! 894: else {
! 895: sendcontrol "501 Invalid address\r\n";
! 896: }
! 897: }
! 898:
! 899: return 0;
! 900: }
! 901:
! 902: sub DATA_smtp {
! 903: my ($args) = @_;
! 904:
! 905: if ($args) {
! 906: sendcontrol "501 Unrecognized parameter\r\n";
! 907: }
! 908: elsif ($smtp_client !~ /^(\d*)$/) {
! 909: sendcontrol "501 Invalid arguments\r\n";
! 910: }
! 911: else {
! 912: sendcontrol "354 Show me the mail\r\n";
! 913:
! 914: my $testno = $smtp_client;
! 915: my $filename = "log/upload.$testno";
! 916:
! 917: logmsg "Store test number $testno in $filename\n";
! 918:
! 919: open(FILE, ">$filename") ||
! 920: return 0; # failed to open output
! 921:
! 922: my $line;
! 923: my $ulsize=0;
! 924: my $disc=0;
! 925: my $raw;
! 926: while (5 == (sysread \*SFREAD, $line, 5)) {
! 927: if($line eq "DATA\n") {
! 928: my $i;
! 929: my $eob;
! 930: sysread \*SFREAD, $i, 5;
! 931:
! 932: my $size = 0;
! 933: if($i =~ /^([0-9a-fA-F]{4})\n/) {
! 934: $size = hex($1);
! 935: }
! 936:
! 937: read_mainsockf(\$line, $size);
! 938:
! 939: $ulsize += $size;
! 940: print FILE $line if(!$nosave);
! 941:
! 942: $raw .= $line;
! 943: if($raw =~ /(?:^|\x0d\x0a)\x2e\x0d\x0a/) {
! 944: # end of data marker!
! 945: $eob = 1;
! 946: }
! 947:
! 948: logmsg "> Appending $size bytes to file\n";
! 949:
! 950: if($eob) {
! 951: logmsg "Found SMTP EOB marker\n";
! 952: last;
! 953: }
! 954: }
! 955: elsif($line eq "DISC\n") {
! 956: # disconnect!
! 957: $disc=1;
! 958: last;
! 959: }
! 960: else {
! 961: logmsg "No support for: $line";
! 962: last;
! 963: }
! 964: }
! 965:
! 966: if($nosave) {
! 967: print FILE "$ulsize bytes would've been stored here\n";
! 968: }
! 969:
! 970: close(FILE);
! 971:
! 972: logmsg "received $ulsize bytes upload\n";
! 973:
! 974: sendcontrol "250 OK, data received!\r\n";
! 975: }
! 976:
! 977: return 0;
! 978: }
! 979:
! 980: sub NOOP_smtp {
! 981: my ($args) = @_;
! 982:
! 983: if($args) {
! 984: sendcontrol "501 Unrecognized parameter\r\n";
! 985: }
! 986: else {
! 987: sendcontrol "250 OK\r\n";
! 988: }
! 989:
! 990: return 0;
! 991: }
! 992:
! 993: sub RSET_smtp {
! 994: my ($args) = @_;
! 995:
! 996: if($args) {
! 997: sendcontrol "501 Unrecognized parameter\r\n";
! 998: }
! 999: else {
! 1000: sendcontrol "250 Resetting\r\n";
! 1001: }
! 1002:
! 1003: return 0;
! 1004: }
! 1005:
! 1006: sub HELP_smtp {
! 1007: my ($args) = @_;
! 1008:
! 1009: # One argument is optional
! 1010: if($args) {
! 1011: logmsg "HELP_smtp got $args\n";
! 1012: }
! 1013:
! 1014: if($smtp_client eq "verifiedserver") {
! 1015: # This is the secret command that verifies that this actually is
! 1016: # the curl test server
! 1017: sendcontrol "214 WE ROOLZ: $$\r\n";
! 1018:
! 1019: if($verbose) {
! 1020: print STDERR "FTPD: We returned proof we are the test server\n";
! 1021: }
! 1022:
! 1023: logmsg "return proof we are we\n";
! 1024: }
! 1025: else {
! 1026: sendcontrol "214-This server supports the following commands:\r\n";
! 1027:
! 1028: if(@auth_mechs) {
! 1029: sendcontrol "214 HELO EHLO RCPT DATA RSET MAIL VRFY EXPN QUIT HELP AUTH\r\n";
! 1030: }
! 1031: else {
! 1032: sendcontrol "214 HELO EHLO RCPT DATA RSET MAIL VRFY EXPN QUIT HELP\r\n";
! 1033: }
! 1034: }
! 1035:
! 1036: return 0;
! 1037: }
! 1038:
! 1039: sub VRFY_smtp {
! 1040: my ($args) = @_;
! 1041: my ($username, $address) = split(/ /, $args, 2);
! 1042:
! 1043: logmsg "VRFY_smtp got $args\n";
! 1044:
! 1045: if($username eq "") {
! 1046: sendcontrol "501 Unrecognized parameter\r\n";
! 1047: }
! 1048: else {
! 1049: my $smtputf8 = grep /^SMTPUTF8$/, @capabilities;
! 1050:
! 1051: # Validate the username (only a valid local or external username is
! 1052: # allowed, such as user or user@example.com)
! 1053: if ((!$smtputf8 && $username =~
! 1054: /^([a-zA-Z0-9._%+-]+)(\@(([a-zA-Z0-9-]+)\.)+([a-zA-Z]{2,4}))?$/) ||
! 1055: ($smtputf8 && $username =~
! 1056: /^([a-zA-Z0-9\x{80}-\x{ff}._%+-]+)(\@(([a-zA-Z0-9\x{80}-\x{ff}-]+)\.)+([a-zA-Z]{2,4}))?$/)) {
! 1057:
! 1058: my @data = getreplydata($smtp_client);
! 1059:
! 1060: if(!@data) {
! 1061: if ($username !~
! 1062: /^([a-zA-Z0-9._%+-]+)\@(([a-zA-Z0-9-]+)\.)+([a-zA-Z]{2,4})$/) {
! 1063: push @data, "250 <$username\@example.com>\r\n"
! 1064: }
! 1065: else {
! 1066: push @data, "250 <$username>\r\n"
! 1067: }
! 1068: }
! 1069:
! 1070: for my $d (@data) {
! 1071: sendcontrol $d;
! 1072: }
! 1073: }
! 1074: else {
! 1075: sendcontrol "501 Invalid address\r\n";
! 1076: }
! 1077: }
! 1078:
! 1079: return 0;
! 1080: }
! 1081:
! 1082: sub EXPN_smtp {
! 1083: my ($list_name) = @_;
! 1084:
! 1085: logmsg "EXPN_smtp got $list_name\n";
! 1086:
! 1087: if(!$list_name) {
! 1088: sendcontrol "501 Unrecognized parameter\r\n";
! 1089: }
! 1090: else {
! 1091: my @data = getreplydata($smtp_client);
! 1092:
! 1093: for my $d (@data) {
! 1094: sendcontrol $d;
! 1095: }
! 1096: }
! 1097:
! 1098: return 0;
! 1099: }
! 1100:
! 1101: sub QUIT_smtp {
! 1102: sendcontrol "221 curl $smtp_type server signing off\r\n";
! 1103:
! 1104: return 0;
! 1105: }
! 1106:
! 1107: # What was deleted by IMAP STORE / POP3 DELE commands
! 1108: my @deleted;
! 1109:
! 1110: ################
! 1111: ################ IMAP commands
! 1112: ################
! 1113:
! 1114: # global to allow the command functions to read it
! 1115: my $cmdid;
! 1116:
! 1117: # what was picked by SELECT
! 1118: my $selected;
! 1119:
! 1120: # Any IMAP parameter can come in escaped and in double quotes.
! 1121: # This function is dumb (so far) and just removes the quotes if present.
! 1122: sub fix_imap_params {
! 1123: foreach (@_) {
! 1124: $_ = $1 if /^"(.*)"$/;
! 1125: }
! 1126: }
! 1127:
! 1128: sub CAPABILITY_imap {
! 1129: if((!@capabilities) && (!@auth_mechs)) {
! 1130: sendcontrol "$cmdid BAD Command\r\n";
! 1131: }
! 1132: else {
! 1133: my $data;
! 1134:
! 1135: # Calculate the CAPABILITY response
! 1136: $data = "* CAPABILITY IMAP4";
! 1137:
! 1138: for my $c (@capabilities) {
! 1139: $data .= " $c";
! 1140: }
! 1141:
! 1142: for my $am (@auth_mechs) {
! 1143: $data .= " AUTH=$am";
! 1144: }
! 1145:
! 1146: $data .= " pingpong test server\r\n";
! 1147:
! 1148: # Send the CAPABILITY response
! 1149: sendcontrol $data;
! 1150: sendcontrol "$cmdid OK CAPABILITY completed\r\n";
! 1151: }
! 1152:
! 1153: return 0;
! 1154: }
! 1155:
! 1156: sub LOGIN_imap {
! 1157: my ($args) = @_;
! 1158: my ($user, $password) = split(/ /, $args, 2);
! 1159: fix_imap_params($user, $password);
! 1160:
! 1161: logmsg "LOGIN_imap got $args\n";
! 1162:
! 1163: if ($user eq "") {
! 1164: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1165: }
! 1166: else {
! 1167: sendcontrol "$cmdid OK LOGIN completed\r\n";
! 1168: }
! 1169:
! 1170: return 0;
! 1171: }
! 1172:
! 1173: sub SELECT_imap {
! 1174: my ($mailbox) = @_;
! 1175: fix_imap_params($mailbox);
! 1176:
! 1177: logmsg "SELECT_imap got test $mailbox\n";
! 1178:
! 1179: if($mailbox eq "") {
! 1180: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1181: }
! 1182: else {
! 1183: # Example from RFC 3501, 6.3.1. SELECT Command
! 1184: sendcontrol "* 172 EXISTS\r\n";
! 1185: sendcontrol "* 1 RECENT\r\n";
! 1186: sendcontrol "* OK [UNSEEN 12] Message 12 is first unseen\r\n";
! 1187: sendcontrol "* OK [UIDVALIDITY 3857529045] UIDs valid\r\n";
! 1188: sendcontrol "* OK [UIDNEXT 4392] Predicted next UID\r\n";
! 1189: sendcontrol "* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n";
! 1190: sendcontrol "* OK [PERMANENTFLAGS (\\Deleted \\Seen \\*)] Limited\r\n";
! 1191: sendcontrol "$cmdid OK [READ-WRITE] SELECT completed\r\n";
! 1192:
! 1193: $selected = $mailbox;
! 1194: }
! 1195:
! 1196: return 0;
! 1197: }
! 1198:
! 1199: sub FETCH_imap {
! 1200: my ($args) = @_;
! 1201: my ($uid, $how) = split(/ /, $args, 2);
! 1202: fix_imap_params($uid, $how);
! 1203:
! 1204: logmsg "FETCH_imap got $args\n";
! 1205:
! 1206: if ($selected eq "") {
! 1207: sendcontrol "$cmdid BAD Command received in Invalid state\r\n";
! 1208: }
! 1209: else {
! 1210: my @data;
! 1211: my $size;
! 1212:
! 1213: if($selected eq "verifiedserver") {
! 1214: # this is the secret command that verifies that this actually is
! 1215: # the curl test server
! 1216: my $response = "WE ROOLZ: $$\r\n";
! 1217: if($verbose) {
! 1218: print STDERR "FTPD: We returned proof we are the test server\n";
! 1219: }
! 1220: $data[0] = $response;
! 1221: logmsg "return proof we are we\n";
! 1222: }
! 1223: else {
! 1224: # send mail content
! 1225: logmsg "retrieve a mail\n";
! 1226:
! 1227: @data = getreplydata($selected);
! 1228: }
! 1229:
! 1230: for (@data) {
! 1231: $size += length($_);
! 1232: }
! 1233:
! 1234: sendcontrol "* $uid FETCH ($how {$size}\r\n";
! 1235:
! 1236: for my $d (@data) {
! 1237: sendcontrol $d;
! 1238: }
! 1239:
! 1240: sendcontrol ")\r\n";
! 1241: sendcontrol "$cmdid OK FETCH completed\r\n";
! 1242: }
! 1243:
! 1244: return 0;
! 1245: }
! 1246:
! 1247: sub APPEND_imap {
! 1248: my ($args) = @_;
! 1249:
! 1250: logmsg "APPEND_imap got $args\r\n";
! 1251:
! 1252: $args =~ /^([^ ]+) [^{]*\{(\d+)\}$/;
! 1253: my ($mailbox, $size) = ($1, $2);
! 1254: fix_imap_params($mailbox);
! 1255:
! 1256: if($mailbox eq "") {
! 1257: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1258: }
! 1259: else {
! 1260: sendcontrol "+ Ready for literal data\r\n";
! 1261:
! 1262: my $testno = $mailbox;
! 1263: my $filename = "log/upload.$testno";
! 1264:
! 1265: logmsg "Store test number $testno in $filename\n";
! 1266:
! 1267: open(FILE, ">$filename") ||
! 1268: return 0; # failed to open output
! 1269:
! 1270: my $received = 0;
! 1271: my $line;
! 1272: while(5 == (sysread \*SFREAD, $line, 5)) {
! 1273: if($line eq "DATA\n") {
! 1274: sysread \*SFREAD, $line, 5;
! 1275:
! 1276: my $chunksize = 0;
! 1277: if($line =~ /^([0-9a-fA-F]{4})\n/) {
! 1278: $chunksize = hex($1);
! 1279: }
! 1280:
! 1281: read_mainsockf(\$line, $chunksize);
! 1282:
! 1283: my $left = $size - $received;
! 1284: my $datasize = ($left > $chunksize) ? $chunksize : $left;
! 1285:
! 1286: if($datasize > 0) {
! 1287: logmsg "> Appending $datasize bytes to file\n";
! 1288: print FILE substr($line, 0, $datasize) if(!$nosave);
! 1289: $line = substr($line, $datasize);
! 1290:
! 1291: $received += $datasize;
! 1292: if($received == $size) {
! 1293: logmsg "Received all data, waiting for final CRLF.\n";
! 1294: }
! 1295: }
! 1296:
! 1297: if($received == $size && $line eq "\r\n") {
! 1298: last;
! 1299: }
! 1300: }
! 1301: elsif($line eq "DISC\n") {
! 1302: logmsg "Unexpected disconnect!\n";
! 1303: last;
! 1304: }
! 1305: else {
! 1306: logmsg "No support for: $line";
! 1307: last;
! 1308: }
! 1309: }
! 1310:
! 1311: if($nosave) {
! 1312: print FILE "$size bytes would've been stored here\n";
! 1313: }
! 1314:
! 1315: close(FILE);
! 1316:
! 1317: logmsg "received $size bytes upload\n";
! 1318:
! 1319: sendcontrol "$cmdid OK APPEND completed\r\n";
! 1320: }
! 1321:
! 1322: return 0;
! 1323: }
! 1324:
! 1325: sub STORE_imap {
! 1326: my ($args) = @_;
! 1327: my ($uid, $what, $value) = split(/ /, $args, 3);
! 1328: fix_imap_params($uid);
! 1329:
! 1330: logmsg "STORE_imap got $args\n";
! 1331:
! 1332: if ($selected eq "") {
! 1333: sendcontrol "$cmdid BAD Command received in Invalid state\r\n";
! 1334: }
! 1335: elsif (($uid eq "") || ($what ne "+Flags") || ($value eq "")) {
! 1336: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1337: }
! 1338: else {
! 1339: if($value eq "\\Deleted") {
! 1340: push(@deleted, $uid);
! 1341: }
! 1342:
! 1343: sendcontrol "* $uid FETCH (FLAGS (\\Seen $value))\r\n";
! 1344: sendcontrol "$cmdid OK STORE completed\r\n";
! 1345: }
! 1346:
! 1347: return 0;
! 1348: }
! 1349:
! 1350: sub LIST_imap {
! 1351: my ($args) = @_;
! 1352: my ($reference, $mailbox) = split(/ /, $args, 2);
! 1353: fix_imap_params($reference, $mailbox);
! 1354:
! 1355: logmsg "LIST_imap got $args\n";
! 1356:
! 1357: if ($reference eq "") {
! 1358: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1359: }
! 1360: elsif ($reference eq "verifiedserver") {
! 1361: # this is the secret command that verifies that this actually is
! 1362: # the curl test server
! 1363: sendcontrol "* LIST () \"/\" \"WE ROOLZ: $$\"\r\n";
! 1364: sendcontrol "$cmdid OK LIST Completed\r\n";
! 1365:
! 1366: if($verbose) {
! 1367: print STDERR "FTPD: We returned proof we are the test server\n";
! 1368: }
! 1369:
! 1370: logmsg "return proof we are we\n";
! 1371: }
! 1372: else {
! 1373: my @data = getreplydata($reference);
! 1374:
! 1375: for my $d (@data) {
! 1376: sendcontrol $d;
! 1377: }
! 1378:
! 1379: sendcontrol "$cmdid OK LIST Completed\r\n";
! 1380: }
! 1381:
! 1382: return 0;
! 1383: }
! 1384:
! 1385: sub LSUB_imap {
! 1386: my ($args) = @_;
! 1387: my ($reference, $mailbox) = split(/ /, $args, 2);
! 1388: fix_imap_params($reference, $mailbox);
! 1389:
! 1390: logmsg "LSUB_imap got $args\n";
! 1391:
! 1392: if ($reference eq "") {
! 1393: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1394: }
! 1395: else {
! 1396: my @data = getreplydata($reference);
! 1397:
! 1398: for my $d (@data) {
! 1399: sendcontrol $d;
! 1400: }
! 1401:
! 1402: sendcontrol "$cmdid OK LSUB Completed\r\n";
! 1403: }
! 1404:
! 1405: return 0;
! 1406: }
! 1407:
! 1408: sub EXAMINE_imap {
! 1409: my ($mailbox) = @_;
! 1410: fix_imap_params($mailbox);
! 1411:
! 1412: logmsg "EXAMINE_imap got $mailbox\n";
! 1413:
! 1414: if ($mailbox eq "") {
! 1415: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1416: }
! 1417: else {
! 1418: my @data = getreplydata($mailbox);
! 1419:
! 1420: for my $d (@data) {
! 1421: sendcontrol $d;
! 1422: }
! 1423:
! 1424: sendcontrol "$cmdid OK [READ-ONLY] EXAMINE completed\r\n";
! 1425: }
! 1426:
! 1427: return 0;
! 1428: }
! 1429:
! 1430: sub STATUS_imap {
! 1431: my ($args) = @_;
! 1432: my ($mailbox, $what) = split(/ /, $args, 2);
! 1433: fix_imap_params($mailbox);
! 1434:
! 1435: logmsg "STATUS_imap got $args\n";
! 1436:
! 1437: if ($mailbox eq "") {
! 1438: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1439: }
! 1440: else {
! 1441: my @data = getreplydata($mailbox);
! 1442:
! 1443: for my $d (@data) {
! 1444: sendcontrol $d;
! 1445: }
! 1446:
! 1447: sendcontrol "$cmdid OK STATUS completed\r\n";
! 1448: }
! 1449:
! 1450: return 0;
! 1451: }
! 1452:
! 1453: sub SEARCH_imap {
! 1454: my ($what) = @_;
! 1455: fix_imap_params($what);
! 1456:
! 1457: logmsg "SEARCH_imap got $what\n";
! 1458:
! 1459: if ($selected eq "") {
! 1460: sendcontrol "$cmdid BAD Command received in Invalid state\r\n";
! 1461: }
! 1462: elsif ($what eq "") {
! 1463: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1464: }
! 1465: else {
! 1466: my @data = getreplydata($selected);
! 1467:
! 1468: for my $d (@data) {
! 1469: sendcontrol $d;
! 1470: }
! 1471:
! 1472: sendcontrol "$cmdid OK SEARCH completed\r\n";
! 1473: }
! 1474:
! 1475: return 0;
! 1476: }
! 1477:
! 1478: sub CREATE_imap {
! 1479: my ($args) = @_;
! 1480: fix_imap_params($args);
! 1481:
! 1482: logmsg "CREATE_imap got $args\n";
! 1483:
! 1484: if ($args eq "") {
! 1485: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1486: }
! 1487: else {
! 1488: sendcontrol "$cmdid OK CREATE completed\r\n";
! 1489: }
! 1490:
! 1491: return 0;
! 1492: }
! 1493:
! 1494: sub DELETE_imap {
! 1495: my ($args) = @_;
! 1496: fix_imap_params($args);
! 1497:
! 1498: logmsg "DELETE_imap got $args\n";
! 1499:
! 1500: if ($args eq "") {
! 1501: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1502: }
! 1503: else {
! 1504: sendcontrol "$cmdid OK DELETE completed\r\n";
! 1505: }
! 1506:
! 1507: return 0;
! 1508: }
! 1509:
! 1510: sub RENAME_imap {
! 1511: my ($args) = @_;
! 1512: my ($from_mailbox, $to_mailbox) = split(/ /, $args, 2);
! 1513: fix_imap_params($from_mailbox, $to_mailbox);
! 1514:
! 1515: logmsg "RENAME_imap got $args\n";
! 1516:
! 1517: if (($from_mailbox eq "") || ($to_mailbox eq "")) {
! 1518: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1519: }
! 1520: else {
! 1521: sendcontrol "$cmdid OK RENAME completed\r\n";
! 1522: }
! 1523:
! 1524: return 0;
! 1525: }
! 1526:
! 1527: sub CHECK_imap {
! 1528: if ($selected eq "") {
! 1529: sendcontrol "$cmdid BAD Command received in Invalid state\r\n";
! 1530: }
! 1531: else {
! 1532: sendcontrol "$cmdid OK CHECK completed\r\n";
! 1533: }
! 1534:
! 1535: return 0;
! 1536: }
! 1537:
! 1538: sub CLOSE_imap {
! 1539: if ($selected eq "") {
! 1540: sendcontrol "$cmdid BAD Command received in Invalid state\r\n";
! 1541: }
! 1542: elsif (!@deleted) {
! 1543: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1544: }
! 1545: else {
! 1546: sendcontrol "$cmdid OK CLOSE completed\r\n";
! 1547:
! 1548: @deleted = ();
! 1549: }
! 1550:
! 1551: return 0;
! 1552: }
! 1553:
! 1554: sub EXPUNGE_imap {
! 1555: if ($selected eq "") {
! 1556: sendcontrol "$cmdid BAD Command received in Invalid state\r\n";
! 1557: }
! 1558: else {
! 1559: if (!@deleted) {
! 1560: # Report the number of existing messages as per the SELECT
! 1561: # command
! 1562: sendcontrol "* 172 EXISTS\r\n";
! 1563: }
! 1564: else {
! 1565: # Report the message UIDs being deleted
! 1566: for my $d (@deleted) {
! 1567: sendcontrol "* $d EXPUNGE\r\n";
! 1568: }
! 1569:
! 1570: @deleted = ();
! 1571: }
! 1572:
! 1573: sendcontrol "$cmdid OK EXPUNGE completed\r\n";
! 1574: }
! 1575:
! 1576: return 0;
! 1577: }
! 1578:
! 1579: sub COPY_imap {
! 1580: my ($args) = @_;
! 1581: my ($uid, $mailbox) = split(/ /, $args, 2);
! 1582: fix_imap_params($uid, $mailbox);
! 1583:
! 1584: logmsg "COPY_imap got $args\n";
! 1585:
! 1586: if (($uid eq "") || ($mailbox eq "")) {
! 1587: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1588: }
! 1589: else {
! 1590: sendcontrol "$cmdid OK COPY completed\r\n";
! 1591: }
! 1592:
! 1593: return 0;
! 1594: }
! 1595:
! 1596: sub UID_imap {
! 1597: my ($args) = @_;
! 1598: my ($command) = split(/ /, $args, 1);
! 1599: fix_imap_params($command);
! 1600:
! 1601: logmsg "UID_imap got $args\n";
! 1602:
! 1603: if ($selected eq "") {
! 1604: sendcontrol "$cmdid BAD Command received in Invalid state\r\n";
! 1605: }
! 1606: elsif (substr($command, 0, 5) eq "FETCH"){
! 1607: my $func = $commandfunc{"FETCH"};
! 1608: if($func) {
! 1609: &$func($args, $command);
! 1610: }
! 1611: }
! 1612: elsif (($command ne "COPY") &&
! 1613: ($command ne "STORE") && ($command ne "SEARCH")) {
! 1614: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1615: }
! 1616: else {
! 1617: my @data = getreplydata($selected);
! 1618:
! 1619: for my $d (@data) {
! 1620: sendcontrol $d;
! 1621: }
! 1622:
! 1623: sendcontrol "$cmdid OK $command completed\r\n";
! 1624: }
! 1625:
! 1626: return 0;
! 1627: }
! 1628:
! 1629: sub NOOP_imap {
! 1630: my ($args) = @_;
! 1631: my @data = (
! 1632: "* 22 EXPUNGE\r\n",
! 1633: "* 23 EXISTS\r\n",
! 1634: "* 3 RECENT\r\n",
! 1635: "* 14 FETCH (FLAGS (\\Seen \\Deleted))\r\n",
! 1636: );
! 1637:
! 1638: if ($args) {
! 1639: sendcontrol "$cmdid BAD Command Argument\r\n";
! 1640: }
! 1641: else {
! 1642: for my $d (@data) {
! 1643: sendcontrol $d;
! 1644: }
! 1645:
! 1646: sendcontrol "$cmdid OK NOOP completed\r\n";
! 1647: }
! 1648:
! 1649: return 0;
! 1650: }
! 1651:
! 1652: sub LOGOUT_imap {
! 1653: sendcontrol "* BYE curl IMAP server signing off\r\n";
! 1654: sendcontrol "$cmdid OK LOGOUT completed\r\n";
! 1655:
! 1656: return 0;
! 1657: }
! 1658:
! 1659: ################
! 1660: ################ POP3 commands
! 1661: ################
! 1662:
! 1663: # Who is attempting to log in
! 1664: my $username;
! 1665:
! 1666: sub CAPA_pop3 {
! 1667: my @list = ();
! 1668: my $mechs;
! 1669:
! 1670: # Calculate the capability list based on the specified capabilities
! 1671: # (except APOP) and any authentication mechanisms
! 1672: for my $c (@capabilities) {
! 1673: push @list, "$c\r\n" unless $c eq "APOP";
! 1674: }
! 1675:
! 1676: for my $am (@auth_mechs) {
! 1677: if(!$mechs) {
! 1678: $mechs = "$am";
! 1679: }
! 1680: else {
! 1681: $mechs .= " $am";
! 1682: }
! 1683: }
! 1684:
! 1685: if($mechs) {
! 1686: push @list, "SASL $mechs\r\n";
! 1687: }
! 1688:
! 1689: if(!@list) {
! 1690: sendcontrol "-ERR Unrecognized command\r\n";
! 1691: }
! 1692: else {
! 1693: my @data = ();
! 1694:
! 1695: # Calculate the CAPA response
! 1696: push @data, "+OK List of capabilities follows\r\n";
! 1697:
! 1698: for my $l (@list) {
! 1699: push @data, "$l\r\n";
! 1700: }
! 1701:
! 1702: push @data, "IMPLEMENTATION POP3 pingpong test server\r\n";
! 1703:
! 1704: # Send the CAPA response
! 1705: for my $d (@data) {
! 1706: sendcontrol $d;
! 1707: }
! 1708:
! 1709: # End with the magic 3-byte end of listing marker
! 1710: sendcontrol ".\r\n";
! 1711: }
! 1712:
! 1713: return 0;
! 1714: }
! 1715:
! 1716: sub APOP_pop3 {
! 1717: my ($args) = @_;
! 1718: my ($user, $secret) = split(/ /, $args, 2);
! 1719:
! 1720: if (!grep /^APOP$/, @capabilities) {
! 1721: sendcontrol "-ERR Unrecognized command\r\n";
! 1722: }
! 1723: elsif (($user eq "") || ($secret eq "")) {
! 1724: sendcontrol "-ERR Protocol error\r\n";
! 1725: }
! 1726: else {
! 1727: my $digest = Digest::MD5::md5_hex($POP3_TIMESTAMP, $TEXT_PASSWORD);
! 1728:
! 1729: if ($secret ne $digest) {
! 1730: sendcontrol "-ERR Login failure\r\n";
! 1731: }
! 1732: else {
! 1733: sendcontrol "+OK Login successful\r\n";
! 1734: }
! 1735: }
! 1736:
! 1737: return 0;
! 1738: }
! 1739:
! 1740: sub AUTH_pop3 {
! 1741: if(!@auth_mechs) {
! 1742: sendcontrol "-ERR Unrecognized command\r\n";
! 1743: }
! 1744: else {
! 1745: my @data = ();
! 1746:
! 1747: # Calculate the AUTH response
! 1748: push @data, "+OK List of supported mechanisms follows\r\n";
! 1749:
! 1750: for my $am (@auth_mechs) {
! 1751: push @data, "$am\r\n";
! 1752: }
! 1753:
! 1754: # Send the AUTH response
! 1755: for my $d (@data) {
! 1756: sendcontrol $d;
! 1757: }
! 1758:
! 1759: # End with the magic 3-byte end of listing marker
! 1760: sendcontrol ".\r\n";
! 1761: }
! 1762:
! 1763: return 0;
! 1764: }
! 1765:
! 1766: sub USER_pop3 {
! 1767: my ($user) = @_;
! 1768:
! 1769: logmsg "USER_pop3 got $user\n";
! 1770:
! 1771: if (!$user) {
! 1772: sendcontrol "-ERR Protocol error\r\n";
! 1773: }
! 1774: else {
! 1775: $username = $user;
! 1776:
! 1777: sendcontrol "+OK\r\n";
! 1778: }
! 1779:
! 1780: return 0;
! 1781: }
! 1782:
! 1783: sub PASS_pop3 {
! 1784: my ($password) = @_;
! 1785:
! 1786: logmsg "PASS_pop3 got $password\n";
! 1787:
! 1788: sendcontrol "+OK Login successful\r\n";
! 1789:
! 1790: return 0;
! 1791: }
! 1792:
! 1793: sub RETR_pop3 {
! 1794: my ($msgid) = @_;
! 1795: my @data;
! 1796:
! 1797: if($msgid =~ /^verifiedserver$/) {
! 1798: # this is the secret command that verifies that this actually is
! 1799: # the curl test server
! 1800: my $response = "WE ROOLZ: $$\r\n";
! 1801: if($verbose) {
! 1802: print STDERR "FTPD: We returned proof we are the test server\n";
! 1803: }
! 1804: $data[0] = $response;
! 1805: logmsg "return proof we are we\n";
! 1806: }
! 1807: else {
! 1808: # send mail content
! 1809: logmsg "retrieve a mail\n";
! 1810:
! 1811: @data = getreplydata($msgid);
! 1812: }
! 1813:
! 1814: sendcontrol "+OK Mail transfer starts\r\n";
! 1815:
! 1816: for my $d (@data) {
! 1817: sendcontrol $d;
! 1818: }
! 1819:
! 1820: # end with the magic 3-byte end of mail marker, assumes that the
! 1821: # mail body ends with a CRLF!
! 1822: sendcontrol ".\r\n";
! 1823:
! 1824: return 0;
! 1825: }
! 1826:
! 1827: sub LIST_pop3 {
! 1828: # This is a built-in fake-message list
! 1829: my @data = (
! 1830: "1 100\r\n",
! 1831: "2 4294967400\r\n", # > 4 GB
! 1832: "3 200\r\n",
! 1833: );
! 1834:
! 1835: logmsg "retrieve a message list\n";
! 1836:
! 1837: sendcontrol "+OK Listing starts\r\n";
! 1838:
! 1839: for my $d (@data) {
! 1840: sendcontrol $d;
! 1841: }
! 1842:
! 1843: # End with the magic 3-byte end of listing marker
! 1844: sendcontrol ".\r\n";
! 1845:
! 1846: return 0;
! 1847: }
! 1848:
! 1849: sub DELE_pop3 {
! 1850: my ($msgid) = @_;
! 1851:
! 1852: logmsg "DELE_pop3 got $msgid\n";
! 1853:
! 1854: if (!$msgid) {
! 1855: sendcontrol "-ERR Protocol error\r\n";
! 1856: }
! 1857: else {
! 1858: push (@deleted, $msgid);
! 1859:
! 1860: sendcontrol "+OK\r\n";
! 1861: }
! 1862:
! 1863: return 0;
! 1864: }
! 1865:
! 1866: sub STAT_pop3 {
! 1867: my ($args) = @_;
! 1868:
! 1869: if ($args) {
! 1870: sendcontrol "-ERR Protocol error\r\n";
! 1871: }
! 1872: else {
! 1873: # Send statistics for the built-in fake message list as
! 1874: # detailed in the LIST_pop3 function above
! 1875: sendcontrol "+OK 3 4294967800\r\n";
! 1876: }
! 1877:
! 1878: return 0;
! 1879: }
! 1880:
! 1881: sub NOOP_pop3 {
! 1882: my ($args) = @_;
! 1883:
! 1884: if ($args) {
! 1885: sendcontrol "-ERR Protocol error\r\n";
! 1886: }
! 1887: else {
! 1888: sendcontrol "+OK\r\n";
! 1889: }
! 1890:
! 1891: return 0;
! 1892: }
! 1893:
! 1894: sub UIDL_pop3 {
! 1895: # This is a built-in fake-message UID list
! 1896: my @data = (
! 1897: "1 1\r\n",
! 1898: "2 2\r\n",
! 1899: "3 4\r\n", # Note that UID 3 is a simulated "deleted" message
! 1900: );
! 1901:
! 1902: if (!grep /^UIDL$/, @capabilities) {
! 1903: sendcontrol "-ERR Unrecognized command\r\n";
! 1904: }
! 1905: else {
! 1906: logmsg "retrieve a message UID list\n";
! 1907:
! 1908: sendcontrol "+OK Listing starts\r\n";
! 1909:
! 1910: for my $d (@data) {
! 1911: sendcontrol $d;
! 1912: }
! 1913:
! 1914: # End with the magic 3-byte end of listing marker
! 1915: sendcontrol ".\r\n";
! 1916: }
! 1917:
! 1918: return 0;
! 1919: }
! 1920:
! 1921: sub TOP_pop3 {
! 1922: my ($args) = @_;
! 1923: my ($msgid, $lines) = split(/ /, $args, 2);
! 1924:
! 1925: logmsg "TOP_pop3 got $args\n";
! 1926:
! 1927: if (!grep /^TOP$/, @capabilities) {
! 1928: sendcontrol "-ERR Unrecognized command\r\n";
! 1929: }
! 1930: elsif (($msgid eq "") || ($lines eq "")) {
! 1931: sendcontrol "-ERR Protocol error\r\n";
! 1932: }
! 1933: else {
! 1934: if ($lines == "0") {
! 1935: logmsg "retrieve header of mail\n";
! 1936: }
! 1937: else {
! 1938: logmsg "retrieve top $lines lines of mail\n";
! 1939: }
! 1940:
! 1941: my @data = getreplydata($msgid);
! 1942:
! 1943: sendcontrol "+OK Mail transfer starts\r\n";
! 1944:
! 1945: # Send mail content
! 1946: for my $d (@data) {
! 1947: sendcontrol $d;
! 1948: }
! 1949:
! 1950: # End with the magic 3-byte end of mail marker, assumes that the
! 1951: # mail body ends with a CRLF!
! 1952: sendcontrol ".\r\n";
! 1953: }
! 1954:
! 1955: return 0;
! 1956: }
! 1957:
! 1958: sub RSET_pop3 {
! 1959: my ($args) = @_;
! 1960:
! 1961: if ($args) {
! 1962: sendcontrol "-ERR Protocol error\r\n";
! 1963: }
! 1964: else {
! 1965: if (@deleted) {
! 1966: logmsg "resetting @deleted message(s)\n";
! 1967:
! 1968: @deleted = ();
! 1969: }
! 1970:
! 1971: sendcontrol "+OK\r\n";
! 1972: }
! 1973:
! 1974: return 0;
! 1975: }
! 1976:
! 1977: sub QUIT_pop3 {
! 1978: if(@deleted) {
! 1979: logmsg "deleting @deleted message(s)\n";
! 1980:
! 1981: @deleted = ();
! 1982: }
! 1983:
! 1984: sendcontrol "+OK curl POP3 server signing off\r\n";
! 1985:
! 1986: return 0;
! 1987: }
! 1988:
! 1989: ################
! 1990: ################ FTP commands
! 1991: ################
! 1992: my $rest=0;
! 1993: sub REST_ftp {
! 1994: $rest = $_[0];
! 1995: logmsg "Set REST position to $rest\n"
! 1996: }
! 1997:
! 1998: sub switch_directory_goto {
! 1999: my $target_dir = $_;
! 2000:
! 2001: if(!$ftptargetdir) {
! 2002: $ftptargetdir = "/";
! 2003: }
! 2004:
! 2005: if($target_dir eq "") {
! 2006: $ftptargetdir = "/";
! 2007: }
! 2008: elsif($target_dir eq "..") {
! 2009: if($ftptargetdir eq "/") {
! 2010: $ftptargetdir = "/";
! 2011: }
! 2012: else {
! 2013: $ftptargetdir =~ s/[[:alnum:]]+\/$//;
! 2014: }
! 2015: }
! 2016: else {
! 2017: $ftptargetdir .= $target_dir . "/";
! 2018: }
! 2019: }
! 2020:
! 2021: sub switch_directory {
! 2022: my $target_dir = $_[0];
! 2023:
! 2024: if($target_dir =~ /^test-(\d+)/) {
! 2025: $cwd_testno = $1;
! 2026: }
! 2027: elsif($target_dir eq "/") {
! 2028: $ftptargetdir = "/";
! 2029: }
! 2030: else {
! 2031: my @dirs = split("/", $target_dir);
! 2032: for(@dirs) {
! 2033: switch_directory_goto($_);
! 2034: }
! 2035: }
! 2036: }
! 2037:
! 2038: sub CWD_ftp {
! 2039: my ($folder, $fullcommand) = $_[0];
! 2040: switch_directory($folder);
! 2041: if($ftptargetdir =~ /^\/fully_simulated/) {
! 2042: $ftplistparserstate = "enabled";
! 2043: }
! 2044: else {
! 2045: undef $ftplistparserstate;
! 2046: }
! 2047: }
! 2048:
! 2049: sub PWD_ftp {
! 2050: my $mydir;
! 2051: $mydir = $ftptargetdir ? $ftptargetdir : "/";
! 2052:
! 2053: if($mydir ne "/") {
! 2054: $mydir =~ s/\/$//;
! 2055: }
! 2056: sendcontrol "257 \"$mydir\" is current directory\r\n";
! 2057: }
! 2058:
! 2059: sub LIST_ftp {
! 2060: # print "150 ASCII data connection for /bin/ls (193.15.23.1,59196) (0 bytes)\r\n";
! 2061:
! 2062: # this is a built-in fake-dir ;-)
! 2063: my @ftpdir=("total 20\r\n",
! 2064: "drwxr-xr-x 8 98 98 512 Oct 22 13:06 .\r\n",
! 2065: "drwxr-xr-x 8 98 98 512 Oct 22 13:06 ..\r\n",
! 2066: "drwxr-xr-x 2 98 98 512 May 2 1996 .NeXT\r\n",
! 2067: "-r--r--r-- 1 0 1 35 Jul 16 1996 README\r\n",
! 2068: "lrwxrwxrwx 1 0 1 7 Dec 9 1999 bin -> usr/bin\r\n",
! 2069: "dr-xr-xr-x 2 0 1 512 Oct 1 1997 dev\r\n",
! 2070: "drwxrwxrwx 2 98 98 512 May 29 16:04 download.html\r\n",
! 2071: "dr-xr-xr-x 2 0 1 512 Nov 30 1995 etc\r\n",
! 2072: "drwxrwxrwx 2 98 1 512 Oct 30 14:33 pub\r\n",
! 2073: "dr-xr-xr-x 5 0 1 512 Oct 1 1997 usr\r\n");
! 2074:
! 2075: if($datasockf_conn eq 'no') {
! 2076: if($nodataconn425) {
! 2077: sendcontrol "150 Opening data connection\r\n";
! 2078: sendcontrol "425 Can't open data connection\r\n";
! 2079: }
! 2080: elsif($nodataconn421) {
! 2081: sendcontrol "150 Opening data connection\r\n";
! 2082: sendcontrol "421 Connection timed out\r\n";
! 2083: }
! 2084: elsif($nodataconn150) {
! 2085: sendcontrol "150 Opening data connection\r\n";
! 2086: # client shall timeout
! 2087: }
! 2088: else {
! 2089: # client shall timeout
! 2090: }
! 2091: return 0;
! 2092: }
! 2093:
! 2094: if($ftplistparserstate) {
! 2095: @ftpdir = ftp_contentlist($ftptargetdir);
! 2096: }
! 2097:
! 2098: logmsg "pass LIST data on data connection\n";
! 2099:
! 2100: if($cwd_testno) {
! 2101: loadtest("$srcdir/data/test$cwd_testno");
! 2102:
! 2103: my @data = getpart("reply", "data");
! 2104: for(@data) {
! 2105: my $send = $_;
! 2106: # convert all \n to \r\n for ASCII transfer
! 2107: $send =~ s/\r\n/\n/g;
! 2108: $send =~ s/\n/\r\n/g;
! 2109: logmsg "send $send as data\n";
! 2110: senddata $send;
! 2111: }
! 2112: $cwd_testno = 0; # forget it again
! 2113: }
! 2114: else {
! 2115: # old hard-coded style
! 2116: for(@ftpdir) {
! 2117: senddata $_;
! 2118: }
! 2119: }
! 2120: close_dataconn(0);
! 2121: sendcontrol "226 ASCII transfer complete\r\n";
! 2122: return 0;
! 2123: }
! 2124:
! 2125: sub NLST_ftp {
! 2126: my @ftpdir=("file", "with space", "fake", "..", " ..", "funny", "README");
! 2127:
! 2128: if($datasockf_conn eq 'no') {
! 2129: if($nodataconn425) {
! 2130: sendcontrol "150 Opening data connection\r\n";
! 2131: sendcontrol "425 Can't open data connection\r\n";
! 2132: }
! 2133: elsif($nodataconn421) {
! 2134: sendcontrol "150 Opening data connection\r\n";
! 2135: sendcontrol "421 Connection timed out\r\n";
! 2136: }
! 2137: elsif($nodataconn150) {
! 2138: sendcontrol "150 Opening data connection\r\n";
! 2139: # client shall timeout
! 2140: }
! 2141: else {
! 2142: # client shall timeout
! 2143: }
! 2144: return 0;
! 2145: }
! 2146:
! 2147: logmsg "pass NLST data on data connection\n";
! 2148: for(@ftpdir) {
! 2149: senddata "$_\r\n";
! 2150: }
! 2151: close_dataconn(0);
! 2152: sendcontrol "226 ASCII transfer complete\r\n";
! 2153: return 0;
! 2154: }
! 2155:
! 2156: sub MDTM_ftp {
! 2157: my $testno = $_[0];
! 2158: my $testpart = "";
! 2159: if ($testno > 10000) {
! 2160: $testpart = $testno % 10000;
! 2161: $testno = int($testno / 10000);
! 2162: }
! 2163:
! 2164: loadtest("$srcdir/data/test$testno");
! 2165:
! 2166: my @data = getpart("reply", "mdtm");
! 2167:
! 2168: my $reply = $data[0];
! 2169: chomp $reply if($reply);
! 2170:
! 2171: if($reply && ($reply =~ /^[+-]?\d+$/) && ($reply < 0)) {
! 2172: sendcontrol "550 $testno: no such file.\r\n";
! 2173: }
! 2174: elsif($reply) {
! 2175: sendcontrol "$reply\r\n";
! 2176: }
! 2177: else {
! 2178: sendcontrol "500 MDTM: no such command.\r\n";
! 2179: }
! 2180: return 0;
! 2181: }
! 2182:
! 2183: sub SIZE_ftp {
! 2184: my $testno = $_[0];
! 2185: if($ftplistparserstate) {
! 2186: my $size = wildcard_filesize($ftptargetdir, $testno);
! 2187: if($size == -1) {
! 2188: sendcontrol "550 $testno: No such file or directory.\r\n";
! 2189: }
! 2190: else {
! 2191: sendcontrol "213 $size\r\n";
! 2192: }
! 2193: return 0;
! 2194: }
! 2195:
! 2196: if($testno =~ /^verifiedserver$/) {
! 2197: my $response = "WE ROOLZ: $$\r\n";
! 2198: my $size = length($response);
! 2199: sendcontrol "213 $size\r\n";
! 2200: return 0;
! 2201: }
! 2202:
! 2203: if($testno =~ /(\d+)\/?$/) {
! 2204: $testno = $1;
! 2205: }
! 2206: else {
! 2207: print STDERR "SIZE_ftp: invalid test number: $testno\n";
! 2208: return 1;
! 2209: }
! 2210:
! 2211: my $testpart = "";
! 2212: if($testno > 10000) {
! 2213: $testpart = $testno % 10000;
! 2214: $testno = int($testno / 10000);
! 2215: }
! 2216:
! 2217: loadtest("$srcdir/data/test$testno");
! 2218:
! 2219: my @data = getpart("reply", "size");
! 2220:
! 2221: my $size = $data[0];
! 2222:
! 2223: if($size) {
! 2224: if($size > -1) {
! 2225: sendcontrol "213 $size\r\n";
! 2226: }
! 2227: else {
! 2228: sendcontrol "550 $testno: No such file or directory.\r\n";
! 2229: }
! 2230: }
! 2231: else {
! 2232: $size=0;
! 2233: @data = getpart("reply", "data$testpart");
! 2234: for(@data) {
! 2235: $size += length($_);
! 2236: }
! 2237: if($size) {
! 2238: sendcontrol "213 $size\r\n";
! 2239: }
! 2240: else {
! 2241: sendcontrol "550 $testno: No such file or directory.\r\n";
! 2242: }
! 2243: }
! 2244: return 0;
! 2245: }
! 2246:
! 2247: sub RETR_ftp {
! 2248: my ($testno) = @_;
! 2249:
! 2250: if($datasockf_conn eq 'no') {
! 2251: if($nodataconn425) {
! 2252: sendcontrol "150 Opening data connection\r\n";
! 2253: sendcontrol "425 Can't open data connection\r\n";
! 2254: }
! 2255: elsif($nodataconn421) {
! 2256: sendcontrol "150 Opening data connection\r\n";
! 2257: sendcontrol "421 Connection timed out\r\n";
! 2258: }
! 2259: elsif($nodataconn150) {
! 2260: sendcontrol "150 Opening data connection\r\n";
! 2261: # client shall timeout
! 2262: }
! 2263: else {
! 2264: # client shall timeout
! 2265: }
! 2266: return 0;
! 2267: }
! 2268:
! 2269: if($ftplistparserstate) {
! 2270: my @content = wildcard_getfile($ftptargetdir, $testno);
! 2271: if($content[0] == -1) {
! 2272: #file not found
! 2273: }
! 2274: else {
! 2275: my $size = length $content[1];
! 2276: sendcontrol "150 Binary data connection for $testno ($size bytes).\r\n",
! 2277: senddata $content[1];
! 2278: close_dataconn(0);
! 2279: sendcontrol "226 File transfer complete\r\n";
! 2280: }
! 2281: return 0;
! 2282: }
! 2283:
! 2284: if($testno =~ /^verifiedserver$/) {
! 2285: # this is the secret command that verifies that this actually is
! 2286: # the curl test server
! 2287: my $response = "WE ROOLZ: $$\r\n";
! 2288: my $len = length($response);
! 2289: sendcontrol "150 Binary junk ($len bytes).\r\n";
! 2290: senddata "WE ROOLZ: $$\r\n";
! 2291: close_dataconn(0);
! 2292: sendcontrol "226 File transfer complete\r\n";
! 2293: if($verbose) {
! 2294: print STDERR "FTPD: We returned proof we are the test server\n";
! 2295: }
! 2296: return 0;
! 2297: }
! 2298:
! 2299: $testno =~ s/^([^0-9]*)//;
! 2300: my $testpart = "";
! 2301: if ($testno > 10000) {
! 2302: $testpart = $testno % 10000;
! 2303: $testno = int($testno / 10000);
! 2304: }
! 2305:
! 2306: loadtest("$srcdir/data/test$testno");
! 2307:
! 2308: my @data = getpart("reply", "data$testpart");
! 2309:
! 2310: my $size=0;
! 2311: for(@data) {
! 2312: $size += length($_);
! 2313: }
! 2314:
! 2315: my %hash = getpartattr("reply", "data$testpart");
! 2316:
! 2317: if($size || $hash{'sendzero'}) {
! 2318:
! 2319: if($rest) {
! 2320: # move read pointer forward
! 2321: $size -= $rest;
! 2322: logmsg "REST $rest was removed from size, makes $size left\n";
! 2323: $rest = 0; # reset REST offset again
! 2324: }
! 2325: if($retrweirdo) {
! 2326: sendcontrol "150 Binary data connection for $testno () ($size bytes).\r\n",
! 2327: "226 File transfer complete\r\n";
! 2328:
! 2329: for(@data) {
! 2330: my $send = $_;
! 2331: senddata $send;
! 2332: }
! 2333: close_dataconn(0);
! 2334: $retrweirdo=0; # switch off the weirdo again!
! 2335: }
! 2336: else {
! 2337: my $sz = "($size bytes)";
! 2338: if($retrnosize) {
! 2339: $sz = "size?";
! 2340: }
! 2341:
! 2342: sendcontrol "150 Binary data connection for $testno () $sz.\r\n";
! 2343:
! 2344: for(@data) {
! 2345: my $send = $_;
! 2346: senddata $send;
! 2347: }
! 2348: close_dataconn(0);
! 2349: sendcontrol "226 File transfer complete\r\n";
! 2350: }
! 2351: }
! 2352: else {
! 2353: sendcontrol "550 $testno: No such file or directory.\r\n";
! 2354: }
! 2355: return 0;
! 2356: }
! 2357:
! 2358: sub STOR_ftp {
! 2359: my $testno=$_[0];
! 2360:
! 2361: my $filename = "log/upload.$testno";
! 2362:
! 2363: if($datasockf_conn eq 'no') {
! 2364: if($nodataconn425) {
! 2365: sendcontrol "150 Opening data connection\r\n";
! 2366: sendcontrol "425 Can't open data connection\r\n";
! 2367: }
! 2368: elsif($nodataconn421) {
! 2369: sendcontrol "150 Opening data connection\r\n";
! 2370: sendcontrol "421 Connection timed out\r\n";
! 2371: }
! 2372: elsif($nodataconn150) {
! 2373: sendcontrol "150 Opening data connection\r\n";
! 2374: # client shall timeout
! 2375: }
! 2376: else {
! 2377: # client shall timeout
! 2378: }
! 2379: return 0;
! 2380: }
! 2381:
! 2382: logmsg "STOR test number $testno in $filename\n";
! 2383:
! 2384: sendcontrol "125 Gimme gimme gimme!\r\n";
! 2385:
! 2386: open(FILE, ">$filename") ||
! 2387: return 0; # failed to open output
! 2388:
! 2389: my $line;
! 2390: my $ulsize=0;
! 2391: my $disc=0;
! 2392: while (5 == (sysread DREAD, $line, 5)) {
! 2393: if($line eq "DATA\n") {
! 2394: my $i;
! 2395: sysread DREAD, $i, 5;
! 2396:
! 2397: my $size = 0;
! 2398: if($i =~ /^([0-9a-fA-F]{4})\n/) {
! 2399: $size = hex($1);
! 2400: }
! 2401:
! 2402: read_datasockf(\$line, $size);
! 2403:
! 2404: #print STDERR " GOT: $size bytes\n";
! 2405:
! 2406: $ulsize += $size;
! 2407: print FILE $line if(!$nosave);
! 2408: logmsg "> Appending $size bytes to file\n";
! 2409: }
! 2410: elsif($line eq "DISC\n") {
! 2411: # disconnect!
! 2412: $disc=1;
! 2413: last;
! 2414: }
! 2415: else {
! 2416: logmsg "No support for: $line";
! 2417: last;
! 2418: }
! 2419: }
! 2420: if($nosave) {
! 2421: print FILE "$ulsize bytes would've been stored here\n";
! 2422: }
! 2423: close(FILE);
! 2424: close_dataconn($disc);
! 2425: logmsg "received $ulsize bytes upload\n";
! 2426: sendcontrol "226 File transfer complete\r\n";
! 2427: return 0;
! 2428: }
! 2429:
! 2430: sub PASV_ftp {
! 2431: my ($arg, $cmd)=@_;
! 2432: my $pasvport;
! 2433: my $bindonly = ($nodataconn) ? '--bindonly' : '';
! 2434:
! 2435: # kill previous data connection sockfilt when alive
! 2436: if($datasockf_runs eq 'yes') {
! 2437: killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data');
! 2438: logmsg "DATA sockfilt for $datasockf_mode data channel killed\n";
! 2439: }
! 2440: datasockf_state('STOPPED');
! 2441:
! 2442: logmsg "====> Passive DATA channel requested by client\n";
! 2443:
! 2444: logmsg "DATA sockfilt for passive data channel starting...\n";
! 2445:
! 2446: # We fire up a new sockfilt to do the data transfer for us.
! 2447: my $datasockfcmd = "./server/sockfilt".exe_ext('SRV')." " .
! 2448: "--ipv$ipvnum $bindonly --port 0 " .
! 2449: "--pidfile \"$datasockf_pidfile\" " .
! 2450: "--logfile \"$datasockf_logfile\"";
! 2451: $slavepid = open2(\*DREAD, \*DWRITE, $datasockfcmd);
! 2452:
! 2453: if($nodataconn) {
! 2454: datasockf_state('PASSIVE_NODATACONN');
! 2455: }
! 2456: else {
! 2457: datasockf_state('PASSIVE');
! 2458: }
! 2459:
! 2460: print STDERR "$datasockfcmd\n" if($verbose);
! 2461:
! 2462: print DWRITE "PING\n";
! 2463: my $pong;
! 2464: sysread_or_die(\*DREAD, \$pong, 5);
! 2465:
! 2466: if($pong =~ /^FAIL/) {
! 2467: logmsg "DATA sockfilt said: FAIL\n";
! 2468: logmsg "DATA sockfilt for passive data channel failed\n";
! 2469: logmsg "DATA sockfilt not running\n";
! 2470: datasockf_state('STOPPED');
! 2471: sendcontrol "500 no free ports!\r\n";
! 2472: return;
! 2473: }
! 2474: elsif($pong !~ /^PONG/) {
! 2475: logmsg "DATA sockfilt unexpected response: $pong\n";
! 2476: logmsg "DATA sockfilt for passive data channel failed\n";
! 2477: logmsg "DATA sockfilt killed now\n";
! 2478: killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data');
! 2479: logmsg "DATA sockfilt not running\n";
! 2480: datasockf_state('STOPPED');
! 2481: sendcontrol "500 no free ports!\r\n";
! 2482: return;
! 2483: }
! 2484:
! 2485: logmsg "DATA sockfilt for passive data channel started (pid $slavepid)\n";
! 2486:
! 2487: # Find out on what port we listen on or have bound
! 2488: my $i;
! 2489: print DWRITE "PORT\n";
! 2490:
! 2491: # READ the response code
! 2492: sysread_or_die(\*DREAD, \$i, 5);
! 2493:
! 2494: # READ the response size
! 2495: sysread_or_die(\*DREAD, \$i, 5);
! 2496:
! 2497: my $size = 0;
! 2498: if($i =~ /^([0-9a-fA-F]{4})\n/) {
! 2499: $size = hex($1);
! 2500: }
! 2501:
! 2502: # READ the response data
! 2503: read_datasockf(\$i, $size);
! 2504:
! 2505: # The data is in the format
! 2506: # IPvX/NNN
! 2507:
! 2508: if($i =~ /IPv(\d)\/(\d+)/) {
! 2509: # FIX: deal with IP protocol version
! 2510: $pasvport = $2;
! 2511: }
! 2512:
! 2513: if(!$pasvport) {
! 2514: logmsg "DATA sockfilt unknown listener port\n";
! 2515: logmsg "DATA sockfilt for passive data channel failed\n";
! 2516: logmsg "DATA sockfilt killed now\n";
! 2517: killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data');
! 2518: logmsg "DATA sockfilt not running\n";
! 2519: datasockf_state('STOPPED');
! 2520: sendcontrol "500 no free ports!\r\n";
! 2521: return;
! 2522: }
! 2523:
! 2524: if($nodataconn) {
! 2525: my $str = nodataconn_str();
! 2526: logmsg "DATA sockfilt for passive data channel ($str) bound on port ".
! 2527: "$pasvport\n";
! 2528: }
! 2529: else {
! 2530: logmsg "DATA sockfilt for passive data channel listens on port ".
! 2531: "$pasvport\n";
! 2532: }
! 2533:
! 2534: if($cmd ne "EPSV") {
! 2535: # PASV reply
! 2536: my $p=$listenaddr;
! 2537: $p =~ s/\./,/g;
! 2538: if($pasvbadip) {
! 2539: $p="1,2,3,4";
! 2540: }
! 2541: sendcontrol sprintf("227 Entering Passive Mode ($p,%d,%d)\n",
! 2542: int($pasvport/256), int($pasvport%256));
! 2543: }
! 2544: else {
! 2545: # EPSV reply
! 2546: sendcontrol sprintf("229 Entering Passive Mode (|||%d|)\n", $pasvport);
! 2547: }
! 2548:
! 2549: logmsg "Client has been notified that DATA conn ".
! 2550: "will be accepted on port $pasvport\n";
! 2551:
! 2552: if($nodataconn) {
! 2553: my $str = nodataconn_str();
! 2554: logmsg "====> Client fooled ($str)\n";
! 2555: return;
! 2556: }
! 2557:
! 2558: eval {
! 2559: local $SIG{ALRM} = sub { die "alarm\n" };
! 2560:
! 2561: # assume swift operations unless explicitly slow
! 2562: alarm ($datadelay?20:10);
! 2563:
! 2564: # Wait for 'CNCT'
! 2565: my $input;
! 2566:
! 2567: # FIX: Monitor ctrl conn for disconnect
! 2568:
! 2569: while(sysread(DREAD, $input, 5)) {
! 2570:
! 2571: if($input !~ /^CNCT/) {
! 2572: # we wait for a connected client
! 2573: logmsg "Odd, we got $input from client\n";
! 2574: next;
! 2575: }
! 2576: logmsg "Client connects to port $pasvport\n";
! 2577: last;
! 2578: }
! 2579: alarm 0;
! 2580: };
! 2581: if ($@) {
! 2582: # timed out
! 2583: logmsg "$srvrname server timed out awaiting data connection ".
! 2584: "on port $pasvport\n";
! 2585: logmsg "accept failed or connection not even attempted\n";
! 2586: logmsg "DATA sockfilt killed now\n";
! 2587: killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data');
! 2588: logmsg "DATA sockfilt not running\n";
! 2589: datasockf_state('STOPPED');
! 2590: return;
! 2591: }
! 2592: else {
! 2593: logmsg "====> Client established passive DATA connection ".
! 2594: "on port $pasvport\n";
! 2595: }
! 2596:
! 2597: return;
! 2598: }
! 2599:
! 2600: #
! 2601: # Support both PORT and EPRT here.
! 2602: #
! 2603:
! 2604: sub PORT_ftp {
! 2605: my ($arg, $cmd) = @_;
! 2606: my $port;
! 2607: my $addr;
! 2608:
! 2609: # kill previous data connection sockfilt when alive
! 2610: if($datasockf_runs eq 'yes') {
! 2611: killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data');
! 2612: logmsg "DATA sockfilt for $datasockf_mode data channel killed\n";
! 2613: }
! 2614: datasockf_state('STOPPED');
! 2615:
! 2616: logmsg "====> Active DATA channel requested by client\n";
! 2617:
! 2618: # We always ignore the given IP and use localhost.
! 2619:
! 2620: if($cmd eq "PORT") {
! 2621: if($arg !~ /(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)/) {
! 2622: logmsg "DATA sockfilt for active data channel not started ".
! 2623: "(bad PORT-line: $arg)\n";
! 2624: sendcontrol "500 silly you, go away\r\n";
! 2625: return;
! 2626: }
! 2627: $port = ($5<<8)+$6;
! 2628: $addr = "$1.$2.$3.$4";
! 2629: }
! 2630: # EPRT |2|::1|49706|
! 2631: elsif($cmd eq "EPRT") {
! 2632: if($arg !~ /(\d+)\|([^\|]+)\|(\d+)/) {
! 2633: logmsg "DATA sockfilt for active data channel not started ".
! 2634: "(bad EPRT-line: $arg)\n";
! 2635: sendcontrol "500 silly you, go away\r\n";
! 2636: return;
! 2637: }
! 2638: sendcontrol "200 Thanks for dropping by. We contact you later\r\n";
! 2639: $port = $3;
! 2640: $addr = $2;
! 2641: }
! 2642: else {
! 2643: logmsg "DATA sockfilt for active data channel not started ".
! 2644: "(invalid command: $cmd)\n";
! 2645: sendcontrol "500 we don't like $cmd now\r\n";
! 2646: return;
! 2647: }
! 2648:
! 2649: if(!$port || $port > 65535) {
! 2650: logmsg "DATA sockfilt for active data channel not started ".
! 2651: "(illegal PORT number: $port)\n";
! 2652: return;
! 2653: }
! 2654:
! 2655: if($nodataconn) {
! 2656: my $str = nodataconn_str();
! 2657: logmsg "DATA sockfilt for active data channel not started ($str)\n";
! 2658: datasockf_state('ACTIVE_NODATACONN');
! 2659: logmsg "====> Active DATA channel not established\n";
! 2660: return;
! 2661: }
! 2662:
! 2663: logmsg "DATA sockfilt for active data channel starting...\n";
! 2664:
! 2665: # We fire up a new sockfilt to do the data transfer for us.
! 2666: my $datasockfcmd = "./server/sockfilt".exe_ext('SRV')." " .
! 2667: "--ipv$ipvnum --connect $port --addr \"$addr\" " .
! 2668: "--pidfile \"$datasockf_pidfile\" " .
! 2669: "--logfile \"$datasockf_logfile\"";
! 2670: $slavepid = open2(\*DREAD, \*DWRITE, $datasockfcmd);
! 2671:
! 2672: datasockf_state('ACTIVE');
! 2673:
! 2674: print STDERR "$datasockfcmd\n" if($verbose);
! 2675:
! 2676: print DWRITE "PING\n";
! 2677: my $pong;
! 2678: sysread_or_die(\*DREAD, \$pong, 5);
! 2679:
! 2680: if($pong =~ /^FAIL/) {
! 2681: logmsg "DATA sockfilt said: FAIL\n";
! 2682: logmsg "DATA sockfilt for active data channel failed\n";
! 2683: logmsg "DATA sockfilt not running\n";
! 2684: datasockf_state('STOPPED');
! 2685: # client shall timeout awaiting connection from server
! 2686: return;
! 2687: }
! 2688: elsif($pong !~ /^PONG/) {
! 2689: logmsg "DATA sockfilt unexpected response: $pong\n";
! 2690: logmsg "DATA sockfilt for active data channel failed\n";
! 2691: logmsg "DATA sockfilt killed now\n";
! 2692: killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data');
! 2693: logmsg "DATA sockfilt not running\n";
! 2694: datasockf_state('STOPPED');
! 2695: # client shall timeout awaiting connection from server
! 2696: return;
! 2697: }
! 2698:
! 2699: logmsg "DATA sockfilt for active data channel started (pid $slavepid)\n";
! 2700:
! 2701: logmsg "====> Active DATA channel connected to client port $port\n";
! 2702:
! 2703: return;
! 2704: }
! 2705:
! 2706: #**********************************************************************
! 2707: # datasockf_state is used to change variables that keep state info
! 2708: # relative to the FTP secondary or data sockfilt process as soon as
! 2709: # one of the five possible stable states is reached. Variables that
! 2710: # are modified by this sub may be checked independently but should
! 2711: # not be changed except by calling this sub.
! 2712: #
! 2713: sub datasockf_state {
! 2714: my $state = $_[0];
! 2715:
! 2716: if($state eq 'STOPPED') {
! 2717: # Data sockfilter initial state, not running,
! 2718: # not connected and not used.
! 2719: $datasockf_state = $state;
! 2720: $datasockf_mode = 'none';
! 2721: $datasockf_runs = 'no';
! 2722: $datasockf_conn = 'no';
! 2723: }
! 2724: elsif($state eq 'PASSIVE') {
! 2725: # Data sockfilter accepted connection from client.
! 2726: $datasockf_state = $state;
! 2727: $datasockf_mode = 'passive';
! 2728: $datasockf_runs = 'yes';
! 2729: $datasockf_conn = 'yes';
! 2730: }
! 2731: elsif($state eq 'ACTIVE') {
! 2732: # Data sockfilter has connected to client.
! 2733: $datasockf_state = $state;
! 2734: $datasockf_mode = 'active';
! 2735: $datasockf_runs = 'yes';
! 2736: $datasockf_conn = 'yes';
! 2737: }
! 2738: elsif($state eq 'PASSIVE_NODATACONN') {
! 2739: # Data sockfilter bound port without listening,
! 2740: # client won't be able to establish data connection.
! 2741: $datasockf_state = $state;
! 2742: $datasockf_mode = 'passive';
! 2743: $datasockf_runs = 'yes';
! 2744: $datasockf_conn = 'no';
! 2745: }
! 2746: elsif($state eq 'ACTIVE_NODATACONN') {
! 2747: # Data sockfilter does not even run,
! 2748: # client awaits data connection from server in vain.
! 2749: $datasockf_state = $state;
! 2750: $datasockf_mode = 'active';
! 2751: $datasockf_runs = 'no';
! 2752: $datasockf_conn = 'no';
! 2753: }
! 2754: else {
! 2755: die "Internal error. Unknown datasockf state: $state!";
! 2756: }
! 2757: }
! 2758:
! 2759: #**********************************************************************
! 2760: # nodataconn_str returns string of effective nodataconn command. Notice
! 2761: # that $nodataconn may be set alone or in addition to a $nodataconnXXX.
! 2762: #
! 2763: sub nodataconn_str {
! 2764: my $str;
! 2765: # order matters
! 2766: $str = 'NODATACONN' if($nodataconn);
! 2767: $str = 'NODATACONN425' if($nodataconn425);
! 2768: $str = 'NODATACONN421' if($nodataconn421);
! 2769: $str = 'NODATACONN150' if($nodataconn150);
! 2770: return "$str";
! 2771: }
! 2772:
! 2773: #**********************************************************************
! 2774: # customize configures test server operation for each curl test, reading
! 2775: # configuration commands/parameters from server commands file each time
! 2776: # a new client control connection is established with the test server.
! 2777: # On success returns 1, otherwise zero.
! 2778: #
! 2779: sub customize {
! 2780: $ctrldelay = 0; # default is no throttling of the ctrl stream
! 2781: $datadelay = 0; # default is no throttling of the data stream
! 2782: $retrweirdo = 0; # default is no use of RETRWEIRDO
! 2783: $retrnosize = 0; # default is no use of RETRNOSIZE
! 2784: $pasvbadip = 0; # default is no use of PASVBADIP
! 2785: $nosave = 0; # default is to actually save uploaded data to file
! 2786: $nodataconn = 0; # default is to establish or accept data channel
! 2787: $nodataconn425 = 0; # default is to not send 425 without data channel
! 2788: $nodataconn421 = 0; # default is to not send 421 without data channel
! 2789: $nodataconn150 = 0; # default is to not send 150 without data channel
! 2790: @capabilities = (); # default is to not support capability commands
! 2791: @auth_mechs = (); # default is to not support authentication commands
! 2792: %fulltextreply = ();#
! 2793: %commandreply = (); #
! 2794: %customcount = (); #
! 2795: %delayreply = (); #
! 2796:
! 2797: open(CUSTOM, "<log/ftpserver.cmd") ||
! 2798: return 1;
! 2799:
! 2800: logmsg "FTPD: Getting commands from log/ftpserver.cmd\n";
! 2801:
! 2802: while(<CUSTOM>) {
! 2803: if($_ =~ /REPLY \"([A-Z]+ [A-Za-z0-9+-\/=\*. ]+)\" (.*)/) {
! 2804: $fulltextreply{$1}=eval "qq{$2}";
! 2805: logmsg "FTPD: set custom reply for $1\n";
! 2806: }
! 2807: elsif($_ =~ /REPLY(LF|) ([A-Za-z0-9+\/=\*]*) (.*)/) {
! 2808: $commandreply{$2}=eval "qq{$3}";
! 2809: if($1 ne "LF") {
! 2810: $commandreply{$2}.="\r\n";
! 2811: }
! 2812: else {
! 2813: $commandreply{$2}.="\n";
! 2814: }
! 2815: if($2 eq "") {
! 2816: logmsg "FTPD: set custom reply for empty command\n";
! 2817: }
! 2818: else {
! 2819: logmsg "FTPD: set custom reply for $2 command\n";
! 2820: }
! 2821: }
! 2822: elsif($_ =~ /COUNT ([A-Z]+) (.*)/) {
! 2823: # we blank the custom reply for this command when having
! 2824: # been used this number of times
! 2825: $customcount{$1}=$2;
! 2826: logmsg "FTPD: blank custom reply for $1 command after $2 uses\n";
! 2827: }
! 2828: elsif($_ =~ /DELAY ([A-Z]+) (\d*)/) {
! 2829: $delayreply{$1}=$2;
! 2830: logmsg "FTPD: delay reply for $1 with $2 seconds\n";
! 2831: }
! 2832: elsif($_ =~ /SLOWDOWN/) {
! 2833: $ctrldelay=1;
! 2834: $datadelay=1;
! 2835: logmsg "FTPD: send response with 0.01 sec delay between each byte\n";
! 2836: }
! 2837: elsif($_ =~ /RETRWEIRDO/) {
! 2838: logmsg "FTPD: instructed to use RETRWEIRDO\n";
! 2839: $retrweirdo=1;
! 2840: }
! 2841: elsif($_ =~ /RETRNOSIZE/) {
! 2842: logmsg "FTPD: instructed to use RETRNOSIZE\n";
! 2843: $retrnosize=1;
! 2844: }
! 2845: elsif($_ =~ /PASVBADIP/) {
! 2846: logmsg "FTPD: instructed to use PASVBADIP\n";
! 2847: $pasvbadip=1;
! 2848: }
! 2849: elsif($_ =~ /NODATACONN425/) {
! 2850: # applies to both active and passive FTP modes
! 2851: logmsg "FTPD: instructed to use NODATACONN425\n";
! 2852: $nodataconn425=1;
! 2853: $nodataconn=1;
! 2854: }
! 2855: elsif($_ =~ /NODATACONN421/) {
! 2856: # applies to both active and passive FTP modes
! 2857: logmsg "FTPD: instructed to use NODATACONN421\n";
! 2858: $nodataconn421=1;
! 2859: $nodataconn=1;
! 2860: }
! 2861: elsif($_ =~ /NODATACONN150/) {
! 2862: # applies to both active and passive FTP modes
! 2863: logmsg "FTPD: instructed to use NODATACONN150\n";
! 2864: $nodataconn150=1;
! 2865: $nodataconn=1;
! 2866: }
! 2867: elsif($_ =~ /NODATACONN/) {
! 2868: # applies to both active and passive FTP modes
! 2869: logmsg "FTPD: instructed to use NODATACONN\n";
! 2870: $nodataconn=1;
! 2871: }
! 2872: elsif($_ =~ /CAPA (.*)/) {
! 2873: logmsg "FTPD: instructed to support CAPABILITY command\n";
! 2874: @capabilities = split(/ (?!(?:[^" ]|[^"] [^"])+")/, $1);
! 2875: foreach (@capabilities) {
! 2876: $_ = $1 if /^"(.*)"$/;
! 2877: }
! 2878: }
! 2879: elsif($_ =~ /AUTH (.*)/) {
! 2880: logmsg "FTPD: instructed to support AUTHENTICATION command\n";
! 2881: @auth_mechs = split(/ /, $1);
! 2882: }
! 2883: elsif($_ =~ /NOSAVE/) {
! 2884: # don't actually store the file we upload - to be used when
! 2885: # uploading insanely huge amounts
! 2886: $nosave = 1;
! 2887: logmsg "FTPD: NOSAVE prevents saving of uploaded data\n";
! 2888: }
! 2889: }
! 2890: close(CUSTOM);
! 2891: }
! 2892:
! 2893: #----------------------------------------------------------------------
! 2894: #----------------------------------------------------------------------
! 2895: #--------------------------- END OF SUBS ----------------------------
! 2896: #----------------------------------------------------------------------
! 2897: #----------------------------------------------------------------------
! 2898:
! 2899: #**********************************************************************
! 2900: # Parse command line options
! 2901: #
! 2902: # Options:
! 2903: #
! 2904: # --verbose # verbose
! 2905: # --srcdir # source directory
! 2906: # --id # server instance number
! 2907: # --proto # server protocol
! 2908: # --pidfile # server pid file
! 2909: # --portfile # server port file
! 2910: # --logfile # server log file
! 2911: # --ipv4 # server IP version 4
! 2912: # --ipv6 # server IP version 6
! 2913: # --port # server listener port
! 2914: # --addr # server address for listener port binding
! 2915: #
! 2916: while(@ARGV) {
! 2917: if($ARGV[0] eq '--verbose') {
! 2918: $verbose = 1;
! 2919: }
! 2920: elsif($ARGV[0] eq '--srcdir') {
! 2921: if($ARGV[1]) {
! 2922: $srcdir = $ARGV[1];
! 2923: shift @ARGV;
! 2924: }
! 2925: }
! 2926: elsif($ARGV[0] eq '--id') {
! 2927: if($ARGV[1] && ($ARGV[1] =~ /^(\d+)$/)) {
! 2928: $idnum = $1 if($1 > 0);
! 2929: shift @ARGV;
! 2930: }
! 2931: }
! 2932: elsif($ARGV[0] eq '--proto') {
! 2933: if($ARGV[1] && ($ARGV[1] =~ /^(ftp|imap|pop3|smtp)$/)) {
! 2934: $proto = $1;
! 2935: shift @ARGV;
! 2936: }
! 2937: else {
! 2938: die "unsupported protocol $ARGV[1]";
! 2939: }
! 2940: }
! 2941: elsif($ARGV[0] eq '--pidfile') {
! 2942: if($ARGV[1]) {
! 2943: $pidfile = $ARGV[1];
! 2944: shift @ARGV;
! 2945: }
! 2946: }
! 2947: elsif($ARGV[0] eq '--portfile') {
! 2948: if($ARGV[1]) {
! 2949: $portfile = $ARGV[1];
! 2950: shift @ARGV;
! 2951: }
! 2952: }
! 2953: elsif($ARGV[0] eq '--logfile') {
! 2954: if($ARGV[1]) {
! 2955: $logfile = $ARGV[1];
! 2956: shift @ARGV;
! 2957: }
! 2958: }
! 2959: elsif($ARGV[0] eq '--ipv4') {
! 2960: $ipvnum = 4;
! 2961: $listenaddr = '127.0.0.1' if($listenaddr eq '::1');
! 2962: }
! 2963: elsif($ARGV[0] eq '--ipv6') {
! 2964: $ipvnum = 6;
! 2965: $listenaddr = '::1' if($listenaddr eq '127.0.0.1');
! 2966: }
! 2967: elsif($ARGV[0] eq '--port') {
! 2968: if($ARGV[1] =~ /^(\d+)$/) {
! 2969: $port = $1;
! 2970: shift @ARGV;
! 2971: }
! 2972: }
! 2973: elsif($ARGV[0] eq '--addr') {
! 2974: if($ARGV[1]) {
! 2975: my $tmpstr = $ARGV[1];
! 2976: if($tmpstr =~ /^(\d\d?\d?)\.(\d\d?\d?)\.(\d\d?\d?)\.(\d\d?\d?)$/) {
! 2977: $listenaddr = "$1.$2.$3.$4" if($ipvnum == 4);
! 2978: }
! 2979: elsif($ipvnum == 6) {
! 2980: $listenaddr = $tmpstr;
! 2981: $listenaddr =~ s/^\[(.*)\]$/$1/;
! 2982: }
! 2983: shift @ARGV;
! 2984: }
! 2985: }
! 2986: else {
! 2987: print STDERR "\nWarning: ftpserver.pl unknown parameter: $ARGV[0]\n";
! 2988: }
! 2989: shift @ARGV;
! 2990: }
! 2991:
! 2992: #***************************************************************************
! 2993: # Initialize command line option dependent variables
! 2994: #
! 2995:
! 2996: if(!$srcdir) {
! 2997: $srcdir = $ENV{'srcdir'} || '.';
! 2998: }
! 2999: if(!$pidfile) {
! 3000: $pidfile = "$path/". server_pidfilename($proto, $ipvnum, $idnum);
! 3001: }
! 3002: if(!$logfile) {
! 3003: $logfile = server_logfilename($logdir, $proto, $ipvnum, $idnum);
! 3004: }
! 3005:
! 3006: $mainsockf_pidfile = "$path/".
! 3007: mainsockf_pidfilename($proto, $ipvnum, $idnum);
! 3008: $mainsockf_logfile =
! 3009: mainsockf_logfilename($logdir, $proto, $ipvnum, $idnum);
! 3010:
! 3011: if($proto eq 'ftp') {
! 3012: $datasockf_pidfile = "$path/".
! 3013: datasockf_pidfilename($proto, $ipvnum, $idnum);
! 3014: $datasockf_logfile =
! 3015: datasockf_logfilename($logdir, $proto, $ipvnum, $idnum);
! 3016: }
! 3017:
! 3018: $srvrname = servername_str($proto, $ipvnum, $idnum);
! 3019:
! 3020: $idstr = "$idnum" if($idnum > 1);
! 3021:
! 3022: protocolsetup($proto);
! 3023:
! 3024: $SIG{INT} = \&exit_signal_handler;
! 3025: $SIG{TERM} = \&exit_signal_handler;
! 3026:
! 3027: startsf();
! 3028:
! 3029: # actual port
! 3030: if($portfile && !$port) {
! 3031: my $aport;
! 3032: open(P, "<$portfile");
! 3033: $aport = <P>;
! 3034: close(P);
! 3035: $port = 0 + $aport;
! 3036: }
! 3037:
! 3038: logmsg sprintf("%s server listens on port IPv${ipvnum}/${port}\n", uc($proto));
! 3039:
! 3040: open(PID, ">$pidfile");
! 3041: print PID $$."\n";
! 3042: close(PID);
! 3043:
! 3044: logmsg("logged pid $$ in $pidfile\n");
! 3045:
! 3046: while(1) {
! 3047:
! 3048: # kill previous data connection sockfilt when alive
! 3049: if($datasockf_runs eq 'yes') {
! 3050: killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data');
! 3051: logmsg "DATA sockfilt for $datasockf_mode data channel killed now\n";
! 3052: }
! 3053: datasockf_state('STOPPED');
! 3054:
! 3055: #
! 3056: # We read 'sockfilt' commands.
! 3057: #
! 3058: my $input;
! 3059:
! 3060: logmsg "Awaiting input\n";
! 3061: sysread_or_die(\*SFREAD, \$input, 5);
! 3062:
! 3063: if($input !~ /^CNCT/) {
! 3064: # we wait for a connected client
! 3065: logmsg "MAIN sockfilt said: $input";
! 3066: next;
! 3067: }
! 3068: logmsg "====> Client connect\n";
! 3069:
! 3070: set_advisor_read_lock($SERVERLOGS_LOCK);
! 3071: $serverlogslocked = 1;
! 3072:
! 3073: # flush data:
! 3074: $| = 1;
! 3075:
! 3076: &customize(); # read test control instructions
! 3077:
! 3078: my $welcome = $commandreply{"welcome"};
! 3079: if(!$welcome) {
! 3080: $welcome = $displaytext{"welcome"};
! 3081: }
! 3082: else {
! 3083: # clear it after use
! 3084: $commandreply{"welcome"}="";
! 3085: if($welcome !~ /\r\n\z/) {
! 3086: $welcome .= "\r\n";
! 3087: }
! 3088: }
! 3089: sendcontrol $welcome;
! 3090:
! 3091: #remove global variables from last connection
! 3092: if($ftplistparserstate) {
! 3093: undef $ftplistparserstate;
! 3094: }
! 3095: if($ftptargetdir) {
! 3096: $ftptargetdir = "";
! 3097: }
! 3098:
! 3099: if($verbose) {
! 3100: print STDERR "OUT: $welcome";
! 3101: }
! 3102:
! 3103: my $full = "";
! 3104:
! 3105: while(1) {
! 3106: my $i;
! 3107:
! 3108: # Now we expect to read DATA\n[hex size]\n[prot], where the [prot]
! 3109: # part only is FTP lingo.
! 3110:
! 3111: # COMMAND
! 3112: sysread_or_die(\*SFREAD, \$i, 5);
! 3113:
! 3114: if($i !~ /^DATA/) {
! 3115: logmsg "MAIN sockfilt said $i";
! 3116: if($i =~ /^DISC/) {
! 3117: # disconnect
! 3118: last;
! 3119: }
! 3120: next;
! 3121: }
! 3122:
! 3123: # SIZE of data
! 3124: sysread_or_die(\*SFREAD, \$i, 5);
! 3125:
! 3126: my $size = 0;
! 3127: if($i =~ /^([0-9a-fA-F]{4})\n/) {
! 3128: $size = hex($1);
! 3129: }
! 3130:
! 3131: # data
! 3132: read_mainsockf(\$input, $size);
! 3133:
! 3134: ftpmsg $input;
! 3135:
! 3136: $full .= $input;
! 3137:
! 3138: # Loop until command completion
! 3139: next unless($full =~ /\r\n$/);
! 3140:
! 3141: # Remove trailing CRLF.
! 3142: $full =~ s/[\n\r]+$//;
! 3143:
! 3144: my $FTPCMD;
! 3145: my $FTPARG;
! 3146: if($proto eq "imap") {
! 3147: # IMAP is different with its identifier first on the command line
! 3148: if(($full =~ /^([^ ]+) ([^ ]+) (.*)/) ||
! 3149: ($full =~ /^([^ ]+) ([^ ]+)/)) {
! 3150: $cmdid=$1; # set the global variable
! 3151: $FTPCMD=$2;
! 3152: $FTPARG=$3;
! 3153: }
! 3154: # IMAP authentication cancellation
! 3155: elsif($full =~ /^\*$/) {
! 3156: # Command id has already been set
! 3157: $FTPCMD="*";
! 3158: $FTPARG="";
! 3159: }
! 3160: # IMAP long "commands" are base64 authentication data
! 3161: elsif($full =~ /^[A-Z0-9+\/]*={0,2}$/i) {
! 3162: # Command id has already been set
! 3163: $FTPCMD=$full;
! 3164: $FTPARG="";
! 3165: }
! 3166: else {
! 3167: sendcontrol "$full BAD Command\r\n";
! 3168: last;
! 3169: }
! 3170: }
! 3171: elsif($full =~ /^([A-Z]{3,4})(\s(.*))?$/i) {
! 3172: $FTPCMD=$1;
! 3173: $FTPARG=$3;
! 3174: }
! 3175: elsif($proto eq "pop3") {
! 3176: # POP3 authentication cancellation
! 3177: if($full =~ /^\*$/) {
! 3178: $FTPCMD="*";
! 3179: $FTPARG="";
! 3180: }
! 3181: # POP3 long "commands" are base64 authentication data
! 3182: elsif($full =~ /^[A-Z0-9+\/]*={0,2}$/i) {
! 3183: $FTPCMD=$full;
! 3184: $FTPARG="";
! 3185: }
! 3186: else {
! 3187: sendcontrol "-ERR Unrecognized command\r\n";
! 3188: last;
! 3189: }
! 3190: }
! 3191: elsif($proto eq "smtp") {
! 3192: # SMTP authentication cancellation
! 3193: if($full =~ /^\*$/) {
! 3194: $FTPCMD="*";
! 3195: $FTPARG="";
! 3196: }
! 3197: # SMTP long "commands" are base64 authentication data
! 3198: elsif($full =~ /^[A-Z0-9+\/]{0,512}={0,2}$/i) {
! 3199: $FTPCMD=$full;
! 3200: $FTPARG="";
! 3201: }
! 3202: else {
! 3203: sendcontrol "500 Unrecognized command\r\n";
! 3204: last;
! 3205: }
! 3206: }
! 3207: else {
! 3208: sendcontrol "500 Unrecognized command\r\n";
! 3209: last;
! 3210: }
! 3211:
! 3212: logmsg "< \"$full\"\n";
! 3213:
! 3214: if($verbose) {
! 3215: print STDERR "IN: $full\n";
! 3216: }
! 3217:
! 3218: $full = "";
! 3219:
! 3220: my $delay = $delayreply{$FTPCMD};
! 3221: if($delay) {
! 3222: # just go sleep this many seconds!
! 3223: logmsg("Sleep for $delay seconds\n");
! 3224: my $twentieths = $delay * 20;
! 3225: while($twentieths--) {
! 3226: portable_sleep(0.05) unless($got_exit_signal);
! 3227: }
! 3228: }
! 3229:
! 3230: my $check = 1; # no response yet
! 3231:
! 3232: # See if there is a custom reply for the full text
! 3233: my $fulltext = $FTPARG ? $FTPCMD . " " . $FTPARG : $FTPCMD;
! 3234: my $text = $fulltextreply{$fulltext};
! 3235: if($text && ($text ne "")) {
! 3236: sendcontrol "$text\r\n";
! 3237: $check = 0;
! 3238: }
! 3239: else {
! 3240: # See if there is a custom reply for the command
! 3241: $text = $commandreply{$FTPCMD};
! 3242: if($text && ($text ne "")) {
! 3243: if($customcount{$FTPCMD} && (!--$customcount{$FTPCMD})) {
! 3244: # used enough times so blank the custom command reply
! 3245: $commandreply{$FTPCMD}="";
! 3246: }
! 3247:
! 3248: sendcontrol $text;
! 3249: $check = 0;
! 3250: }
! 3251: else {
! 3252: # See if there is any display text for the command
! 3253: $text = $displaytext{$FTPCMD};
! 3254: if($text && ($text ne "")) {
! 3255: if($proto eq 'imap') {
! 3256: sendcontrol "$cmdid $text\r\n";
! 3257: }
! 3258: else {
! 3259: sendcontrol "$text\r\n";
! 3260: }
! 3261:
! 3262: $check = 0;
! 3263: }
! 3264:
! 3265: # only perform this if we're not faking a reply
! 3266: my $func = $commandfunc{uc($FTPCMD)};
! 3267: if($func) {
! 3268: &$func($FTPARG, $FTPCMD);
! 3269: $check = 0;
! 3270: }
! 3271: }
! 3272: }
! 3273:
! 3274: if($check) {
! 3275: logmsg "$FTPCMD wasn't handled!\n";
! 3276: if($proto eq 'pop3') {
! 3277: sendcontrol "-ERR $FTPCMD is not dealt with!\r\n";
! 3278: }
! 3279: elsif($proto eq 'imap') {
! 3280: sendcontrol "$cmdid BAD $FTPCMD is not dealt with!\r\n";
! 3281: }
! 3282: else {
! 3283: sendcontrol "500 $FTPCMD is not dealt with!\r\n";
! 3284: }
! 3285: }
! 3286:
! 3287: } # while(1)
! 3288: logmsg "====> Client disconnected\n";
! 3289:
! 3290: if($serverlogslocked) {
! 3291: $serverlogslocked = 0;
! 3292: clear_advisor_read_lock($SERVERLOGS_LOCK);
! 3293: }
! 3294: }
! 3295:
! 3296: killsockfilters($proto, $ipvnum, $idnum, $verbose);
! 3297: unlink($pidfile);
! 3298: if($serverlogslocked) {
! 3299: $serverlogslocked = 0;
! 3300: clear_advisor_read_lock($SERVERLOGS_LOCK);
! 3301: }
! 3302:
! 3303: exit;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>