]> git.ipfire.org Git - thirdparty/squid.git/blame - src/FtpServer.cc
FEAT response with excessive whitespace
[thirdparty/squid.git] / src / FtpServer.cc
CommitLineData
434a79b0
DK
1/*
2 * DEBUG: section 09 File Transfer Protocol (FTP)
3 *
4 */
5
6#include "squid.h"
7
8#include "FtpServer.h"
9#include "Mem.h"
10#include "SquidConfig.h"
11#include "StatCounters.h"
12#include "client_side.h"
13#include "comm/ConnOpener.h"
000e664b 14#include "comm/TcpAcceptor.h"
434a79b0
DK
15#include "comm/Write.h"
16#include "errorpage.h"
17#include "fd.h"
000e664b 18#include "ip/tools.h"
54a6c0cd 19#include "SquidString.h"
434a79b0
DK
20#include "tools.h"
21#include "wordlist.h"
54a6c0cd 22#include <set>
434a79b0
DK
23
24namespace Ftp {
25
26const char *const crlf = "\r\n";
27
28/// \ingroup ServerProtocolFTPInternal
29static char *
30escapeIAC(const char *buf)
31{
32 int n;
33 char *ret;
34 unsigned const char *p;
35 unsigned char *r;
36
37 for (p = (unsigned const char *)buf, n = 1; *p; ++n, ++p)
38 if (*p == 255)
39 ++n;
40
41 ret = (char *)xmalloc(n);
42
43 for (p = (unsigned const char *)buf, r=(unsigned char *)ret; *p; ++p) {
44 *r = *p;
45 ++r;
46
47 if (*p == 255) {
48 *r = 255;
49 ++r;
50 }
51 }
52
53 *r = '\0';
54 ++r;
55 assert((r - (unsigned char *)ret) == n );
56 return ret;
57}
58
59/// configures the channel with a descriptor and registers a close handler
60void
73950ceb 61FtpChannel::opened(const Comm::ConnectionPointer &newConn,
434a79b0
DK
62 const AsyncCall::Pointer &aCloser)
63{
64 assert(!Comm::IsConnOpen(conn));
65 assert(closer == NULL);
66
67 assert(Comm::IsConnOpen(newConn));
68 assert(aCloser != NULL);
69
70 conn = newConn;
71 closer = aCloser;
72 comm_add_close_handler(conn->fd, closer);
73}
74
75/// planned close: removes the close handler and calls comm_close
76void
73950ceb 77FtpChannel::close()
434a79b0
DK
78{
79 // channels with active listeners will be closed when the listener handler dies.
80 if (Comm::IsConnOpen(conn)) {
81 comm_remove_close_handler(conn->fd, closer);
82 conn->close(); // we do not expect to be called back
83 }
84 clear();
85}
86
87void
73950ceb 88FtpChannel::forget()
434a79b0
DK
89{
90 if (Comm::IsConnOpen(conn))
91 comm_remove_close_handler(conn->fd, closer);
29f23abf 92 clear();
434a79b0
DK
93}
94
95void
73950ceb 96FtpChannel::clear()
434a79b0
DK
97{
98 conn = NULL;
99 closer = NULL;
100}
101
102ServerStateData::ServerStateData(FwdState *fwdState):
103 AsyncJob("Ftp::ServerStateData"), ::ServerStateData(fwdState)
104{
105 ++statCounter.server.all.requests;
106 ++statCounter.server.ftp.requests;
107
108 ctrl.last_command = xstrdup("Connect to server");
109 ctrl.buf = static_cast<char *>(memAllocBuf(4096, &ctrl.size));
110 ctrl.offset = 0;
111
112 typedef CommCbMemFunT<ServerStateData, CommCloseCbParams> Dialer;
113 const AsyncCall::Pointer closer = JobCallback(9, 5, Dialer, this,
114 ServerStateData::ctrlClosed);
115 ctrl.opened(fwdState->serverConnection(), closer);
116}
117
73950ceb
AR
118void
119ServerStateData::DataChannel::addr(const Ip::Address &import)
120{
121 static char addrBuf[MAX_IPSTRLEN];
122 import.toStr(addrBuf, sizeof(addrBuf));
123 xfree(host);
124 host = xstrdup(addrBuf);
125 port = import.port();
126}
127
434a79b0
DK
128ServerStateData::~ServerStateData()
129{
130 if (data.opener != NULL) {
131 data.opener->cancel("Ftp::ServerStateData destructed");
132 data.opener = NULL;
133 }
134 data.close();
135
136 if (ctrl.buf) {
137 memFreeBuf(ctrl.size, ctrl.buf);
138 ctrl.buf = NULL;
139 }
140 if (ctrl.message)
141 wordlistDestroy(&ctrl.message);
142 safe_free(ctrl.last_command);
143 safe_free(ctrl.last_reply);
144
145 if (data.readBuf) {
146 if (!data.readBuf->isNull())
147 data.readBuf->clean();
148
149 delete data.readBuf;
150 }
151
152 safe_free(old_request);
153
154 safe_free(old_reply);
155
156 fwd = NULL; // refcounted
157}
158
159void
160ServerStateData::start()
161{
162 scheduleReadControlReply(0);
163}
164
adaff124
DK
165void
166ServerStateData::initReadBuf()
167{
168 if (data.readBuf == NULL) {
169 data.readBuf = new MemBuf;
170 data.readBuf->init(4096, SQUID_TCP_SO_RCVBUF);
171 }
172}
173
434a79b0
DK
174/**
175 * Close the FTP server connection(s). Used by serverComplete().
176 */
177void
178ServerStateData::closeServer()
179{
180 if (Comm::IsConnOpen(ctrl.conn)) {
181 debugs(9,3, HERE << "closing FTP server FD " << ctrl.conn->fd << ", this " << this);
182 fwd->unregister(ctrl.conn);
183 ctrl.close();
184 }
185
186 if (Comm::IsConnOpen(data.conn)) {
187 debugs(9,3, HERE << "closing FTP data FD " << data.conn->fd << ", this " << this);
188 data.close();
189 }
190
191 debugs(9,3, HERE << "FTP ctrl and data connections closed. this " << this);
192}
193
194/**
195 * Did we close all FTP server connection(s)?
196 *
197 \retval true Both server control and data channels are closed. And not waiting for a new data connection to open.
198 \retval false Either control channel or data is still active.
199 */
200bool
201ServerStateData::doneWithServer() const
202{
203 return !Comm::IsConnOpen(ctrl.conn) && !Comm::IsConnOpen(data.conn);
204}
205
206void
207ServerStateData::failed(err_type error, int xerrno)
208{
209 debugs(9,3,HERE << "entry-null=" << (entry?entry->isEmpty():0) << ", entry=" << entry);
434a79b0 210
434a79b0
DK
211 const char *command, *reply;
212 const Http::StatusCode httpStatus = failedHttpStatus(error);
213 ErrorState *const ftperr = new ErrorState(error, httpStatus, fwd->request);
214 ftperr->xerrno = xerrno;
215
216 ftperr->ftp.server_msg = ctrl.message;
217 ctrl.message = NULL;
218
219 if (old_request)
220 command = old_request;
221 else
222 command = ctrl.last_command;
223
224 if (command && strncmp(command, "PASS", 4) == 0)
225 command = "PASS <yourpassword>";
226
227 if (old_reply)
228 reply = old_reply;
229 else
230 reply = ctrl.last_reply;
231
232 if (command)
233 ftperr->ftp.request = xstrdup(command);
234
235 if (reply)
236 ftperr->ftp.reply = xstrdup(reply);
237
000e664b 238 fwd->request->detailError(error, xerrno);
719c885c
AR
239 fwd->fail(ftperr);
240
241 closeServer(); // we failed, so no serverComplete()
434a79b0
DK
242}
243
244Http::StatusCode
245ServerStateData::failedHttpStatus(err_type &error)
246{
247 if (error == ERR_NONE)
248 error = ERR_FTP_FAILURE;
249 return error == ERR_READ_TIMEOUT ? Http::scGateway_Timeout :
250 Http::scBadGateway;
251}
252
253/**
254 * DPW 2007-04-23
255 * Looks like there are no longer anymore callers that set
256 * buffered_ok=1. Perhaps it can be removed at some point.
257 */
258void
259ServerStateData::scheduleReadControlReply(int buffered_ok)
260{
261 debugs(9, 3, HERE << ctrl.conn);
262
263 if (buffered_ok && ctrl.offset > 0) {
264 /* We've already read some reply data */
265 handleControlReply();
266 } else {
267 /*
268 * Cancel the timeout on the Data socket (if any) and
269 * establish one on the control socket.
270 */
271 if (Comm::IsConnOpen(data.conn)) {
272 commUnsetConnTimeout(data.conn);
273 }
274
275 typedef CommCbMemFunT<ServerStateData, CommTimeoutCbParams> TimeoutDialer;
276 AsyncCall::Pointer timeoutCall = JobCallback(9, 5, TimeoutDialer, this, ServerStateData::timeout);
277 commSetConnTimeout(ctrl.conn, Config.Timeout.read, timeoutCall);
278
279 typedef CommCbMemFunT<ServerStateData, CommIoCbParams> Dialer;
280 AsyncCall::Pointer reader = JobCallback(9, 5, Dialer, this, ServerStateData::readControlReply);
281 comm_read(ctrl.conn, ctrl.buf + ctrl.offset, ctrl.size - ctrl.offset, reader);
282 }
283}
284
285void
286ServerStateData::readControlReply(const CommIoCbParams &io)
287{
288 debugs(9, 3, HERE << "FD " << io.fd << ", Read " << io.size << " bytes");
289
290 if (io.size > 0) {
291 kb_incr(&(statCounter.server.all.kbytes_in), io.size);
292 kb_incr(&(statCounter.server.ftp.kbytes_in), io.size);
293 }
294
295 if (io.flag == COMM_ERR_CLOSING)
296 return;
297
298 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
299 abortTransaction("entry aborted during control reply read");
300 return;
301 }
302
303 assert(ctrl.offset < ctrl.size);
304
305 if (io.flag == COMM_OK && io.size > 0) {
306 fd_bytes(io.fd, io.size, FD_READ);
307 }
308
309 if (io.flag != COMM_OK) {
310 debugs(50, ignoreErrno(io.xerrno) ? 3 : DBG_IMPORTANT,
311 "ftpReadControlReply: read error: " << xstrerr(io.xerrno));
312
313 if (ignoreErrno(io.xerrno)) {
314 scheduleReadControlReply(0);
315 } else {
316 failed(ERR_READ_ERROR, io.xerrno);
317 /* failed closes ctrl.conn and frees ftpState */
318 }
319 return;
320 }
321
322 if (io.size == 0) {
323 if (entry->store_status == STORE_PENDING) {
324 failed(ERR_FTP_FAILURE, 0);
325 /* failed closes ctrl.conn and frees ftpState */
326 return;
327 }
328
329 /* XXX this may end up having to be serverComplete() .. */
330 abortTransaction("zero control reply read");
331 return;
332 }
333
334 unsigned int len =io.size + ctrl.offset;
335 ctrl.offset = len;
336 assert(len <= ctrl.size);
337 handleControlReply();
338}
339
340void
341ServerStateData::handleControlReply()
342{
343 debugs(9, 3, HERE);
344
345 size_t bytes_used = 0;
346 wordlistDestroy(&ctrl.message);
434a79b0 347
a2c7f09a 348 if (!parseControlReply(bytes_used)) {
434a79b0
DK
349 /* didn't get complete reply yet */
350
351 if (ctrl.offset == ctrl.size) {
352 ctrl.buf = (char *)memReallocBuf(ctrl.buf, ctrl.size << 1, &ctrl.size);
353 }
354
355 scheduleReadControlReply(0);
356 return;
a2c7f09a
AR
357 }
358
359 assert(ctrl.message); // the entire FTP server response, line by line
360 assert(ctrl.replycode >= 0); // FTP status code (from the last line)
361 assert(ctrl.last_reply); // FTP reason (from the last line)
362
363 if (ctrl.offset == bytes_used) {
434a79b0
DK
364 /* used it all up */
365 ctrl.offset = 0;
366 } else {
367 /* Got some data past the complete reply */
368 assert(bytes_used < ctrl.offset);
369 ctrl.offset -= bytes_used;
370 memmove(ctrl.buf, ctrl.buf + bytes_used, ctrl.offset);
371 }
372
434a79b0
DK
373 debugs(9, 3, HERE << "state=" << state << ", code=" << ctrl.replycode);
374}
375
376bool
73950ceb 377ServerStateData::handlePasvReply(Ip::Address &srvAddr)
434a79b0
DK
378{
379 int code = ctrl.replycode;
434a79b0 380 char *buf;
434a79b0
DK
381 debugs(9, 3, HERE);
382
383 if (code != 227) {
384 debugs(9, 2, "PASV not supported by remote end");
385 return false;
386 }
387
388 /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
389 /* ANSI sez [^0-9] is undefined, it breaks on Watcom cc */
390 debugs(9, 5, HERE << "scanning: " << ctrl.last_reply);
391
392 buf = ctrl.last_reply + strcspn(ctrl.last_reply, "0123456789");
393
cff221ee
AR
394 const char *forceIp = Config.Ftp.sanitycheck ?
395 fd_table[ctrl.conn->fd].ipaddr : NULL;
73950ceb 396 if (!Ftp::ParseIpPort(buf, forceIp, srvAddr)) {
434a79b0
DK
397 debugs(9, DBG_IMPORTANT, "Unsafe PASV reply from " <<
398 ctrl.conn->remote << ": " << ctrl.last_reply);
399 return false;
400 }
401
73950ceb
AR
402 data.addr(srvAddr);
403
434a79b0
DK
404 return true;
405}
406
000e664b
AR
407bool
408ServerStateData::handleEpsvReply(Ip::Address &remoteAddr)
409{
410 int code = ctrl.replycode;
411 char *buf;
412 debugs(9, 3, HERE);
413
414 if (code != 229 && code != 522) {
415 if (code == 200) {
416 /* handle broken servers (RFC 2428 says OK code for EPSV MUST be 229 not 200) */
417 /* vsftpd for one send '200 EPSV ALL ok.' without even port info.
418 * Its okay to re-send EPSV 1/2 but nothing else. */
419 debugs(9, DBG_IMPORTANT, "Broken FTP Server at " << ctrl.conn->remote << ". Wrong accept code for EPSV");
420 } else {
421 debugs(9, 2, "EPSV not supported by remote end");
422 }
423 return sendPassive();
424 }
425
426 if (code == 522) {
427 /* server response with list of supported methods */
428 /* 522 Network protocol not supported, use (1) */
429 /* 522 Network protocol not supported, use (1,2) */
430 /* 522 Network protocol not supported, use (2) */
431 /* TODO: handle the (1,2) case. We might get it back after EPSV ALL
432 * which means close data + control without self-destructing and re-open from scratch. */
433 debugs(9, 5, HERE << "scanning: " << ctrl.last_reply);
434 buf = ctrl.last_reply;
435 while (buf != NULL && *buf != '\0' && *buf != '\n' && *buf != '(')
436 ++buf;
437 if (buf != NULL && *buf == '\n')
438 ++buf;
439
440 if (buf == NULL || *buf == '\0') {
441 /* handle broken server (RFC 2428 says MUST specify supported protocols in 522) */
442 debugs(9, DBG_IMPORTANT, "Broken FTP Server at " << ctrl.conn->remote << ". 522 error missing protocol negotiation hints");
443 return sendPassive();
444 } else if (strcmp(buf, "(1)") == 0) {
445 state = SENT_EPSV_2; /* simulate having sent and failed EPSV 2 */
446 return sendPassive();
447 } else if (strcmp(buf, "(2)") == 0) {
448 if (Ip::EnableIpv6) {
449 /* If server only supports EPSV 2 and we have already tried that. Go straight to EPRT */
450 if (state == SENT_EPSV_2) {
451 return sendEprt();
452 } else {
453 /* or try the next Passive mode down the chain. */
454 return sendPassive();
455 }
456 } else {
457 /* Server only accept EPSV in IPv6 traffic. */
458 state = SENT_EPSV_1; /* simulate having sent and failed EPSV 1 */
459 return sendPassive();
460 }
461 } else {
462 /* handle broken server (RFC 2428 says MUST specify supported protocols in 522) */
463 debugs(9, DBG_IMPORTANT, "WARNING: Server at " << ctrl.conn->remote << " sent unknown protocol negotiation hint: " << buf);
464 return sendPassive();
465 }
466 failed(ERR_FTP_FAILURE, 0);
467 return false;
468 }
469
470 /* 229 Entering Extended Passive Mode (|||port|) */
471 /* ANSI sez [^0-9] is undefined, it breaks on Watcom cc */
472 debugs(9, 5, "scanning: " << ctrl.last_reply);
473
474 buf = ctrl.last_reply + strcspn(ctrl.last_reply, "(");
475
476 char h1, h2, h3, h4;
477 unsigned short port;
478 int n = sscanf(buf, "(%c%c%c%hu%c)", &h1, &h2, &h3, &port, &h4);
479
480 if (n < 4 || h1 != h2 || h1 != h3 || h1 != h4) {
481 debugs(9, DBG_IMPORTANT, "Invalid EPSV reply from " <<
482 ctrl.conn->remote << ": " <<
483 ctrl.last_reply);
484
485 return sendPassive();
486 }
487
488 if (0 == port) {
489 debugs(9, DBG_IMPORTANT, "Unsafe EPSV reply from " <<
490 ctrl.conn->remote << ": " <<
491 ctrl.last_reply);
492
493 return sendPassive();
494 }
495
496 if (Config.Ftp.sanitycheck) {
497 if (port < 1024) {
498 debugs(9, DBG_IMPORTANT, "Unsafe EPSV reply from " <<
499 ctrl.conn->remote << ": " <<
500 ctrl.last_reply);
501
502 return sendPassive();
503 }
504 }
505
506 remoteAddr = ctrl.conn->remote;
507 remoteAddr.port(port);
508 data.addr(remoteAddr);
509 return true;
510}
511
512// The server-side EPRT and PORT commands are not yet implemented.
513// The ServerStateData::sendEprt() will fail because of the unimplemented
514// openListenSocket() or sendPort() methods
515bool
516ServerStateData::sendEprt()
517{
518 if (!Config.Ftp.eprt) {
519 /* Disabled. Switch immediately to attempting old PORT command. */
520 debugs(9, 3, "EPRT disabled by local administrator");
521 return sendPort();
522 }
523
524 debugs(9, 3, HERE);
525
526 if (!openListenSocket()) {
527 failed(ERR_FTP_FAILURE, 0);
528 return false;
529 }
530
531 debugs(9, 3, "Listening for FTP data connection with FD " << data.conn);
532 if (!Comm::IsConnOpen(data.conn)) {
533 /* XXX Need to set error message */
534 failed(ERR_FTP_FAILURE, 0);
535 return false;
536 }
537
538 static MemBuf mb;
539 mb.reset();
540 char buf[MAX_IPSTRLEN];
541 /* RFC 2428 defines EPRT as IPv6 equivalent to IPv4 PORT command. */
542 /* Which can be used by EITHER protocol. */
543 debugs(9, 3, "Listening for FTP data connection on port" << comm_local_port(data.conn->fd) << " or port?" << data.conn->local.port());
544 mb.Printf("EPRT |%d|%s|%d|%s",
545 ( data.conn->local.isIPv6() ? 2 : 1 ),
546 data.conn->local.toStr(buf,MAX_IPSTRLEN),
547 comm_local_port(data.conn->fd), Ftp::crlf );
548
549 state = SENT_EPRT;
550 writeCommand(mb.content());
551 return true;
552}
553
554bool
555ServerStateData::sendPort()
556{
557 failed(ERR_FTP_FAILURE, 0);
558 return false;
559}
560
561bool
562ServerStateData::sendPassive()
563{
564 debugs(9, 3, HERE);
565
566 /** \par
567 * Checks for EPSV ALL special conditions:
568 * If enabled to be sent, squid MUST NOT request any other connect methods.
569 * If 'ALL' is sent and fails the entire FTP Session fails.
570 * NP: By my reading exact EPSV protocols maybe attempted, but only EPSV method. */
571 if (Config.Ftp.epsv_all && state == SENT_EPSV_1 ) {
572 // We are here because the last "EPSV 1" failed, but because of epsv_all
573 // no other method allowed.
574 debugs(9, DBG_IMPORTANT, "FTP does not allow PASV method after 'EPSV ALL' has been sent.");
575 failed(ERR_FTP_FAILURE, 0);
576 return false;
577 }
578
579
580 /// Closes any old FTP-Data connection which may exist. */
581 data.close();
582
583 /** \par
584 * Checks for previous EPSV/PASV failures on this server/session.
585 * Diverts to EPRT immediately if they are not working. */
586 if (!Config.Ftp.passive || state == SENT_PASV) {
587 sendEprt();
588 return true;
589 }
590
591 static MemBuf mb;
592 mb.reset();
593 /** \par
594 * Send EPSV (ALL,2,1) or PASV on the control channel.
595 *
596 * - EPSV ALL is used if enabled.
597 * - EPSV 2 is used if ALL is disabled and IPv6 is available and ctrl channel is IPv6.
598 * - EPSV 1 is used if EPSV 2 (IPv6) fails or is not available or ctrl channel is IPv4.
599 * - PASV is used if EPSV 1 fails.
600 */
601 switch (state) {
602 case SENT_EPSV_ALL: /* EPSV ALL resulted in a bad response. Try ther EPSV methods. */
603 if (ctrl.conn->local.isIPv6()) {
604 debugs(9, 5, HERE << "FTP Channel is IPv6 (" << ctrl.conn->remote << ") attempting EPSV 2 after EPSV ALL has failed.");
605 mb.Printf("EPSV 2%s", Ftp::crlf);
606 state = SENT_EPSV_2;
607 break;
608 }
609 // else fall through to skip EPSV 2
610
611 case Ftp::ServerStateData::SENT_EPSV_2: /* EPSV IPv6 failed. Try EPSV IPv4 */
612 if (ctrl.conn->local.isIPv4()) {
613 debugs(9, 5, HERE << "FTP Channel is IPv4 (" << ctrl.conn->remote << ") attempting EPSV 1 after EPSV ALL has failed.");
614 mb.Printf("EPSV 1%s", Ftp::crlf);
615 state = SENT_EPSV_1;
616 break;
617 } else if (Config.Ftp.epsv_all) {
618 debugs(9, DBG_IMPORTANT, "FTP does not allow PASV method after 'EPSV ALL' has been sent.");
619 failed(ERR_FTP_FAILURE, 0);
620 return false;
621 }
622 // else fall through to skip EPSV 1
623
624 case SENT_EPSV_1: /* EPSV options exhausted. Try PASV now. */
625 debugs(9, 5, HERE << "FTP Channel (" << ctrl.conn->remote << ") rejects EPSV connection attempts. Trying PASV instead.");
626 mb.Printf("PASV%s", Ftp::crlf);
627 state = SENT_PASV;
628 break;
629
630 default:
631 if (!Config.Ftp.epsv) {
632 debugs(9, 5, HERE << "EPSV support manually disabled. Sending PASV for FTP Channel (" << ctrl.conn->remote <<")");
633 mb.Printf("PASV%s", Ftp::crlf);
634 state = SENT_PASV;
635 } else if (Config.Ftp.epsv_all) {
636 debugs(9, 5, HERE << "EPSV ALL manually enabled. Attempting with FTP Channel (" << ctrl.conn->remote <<")");
637 mb.Printf("EPSV ALL%s", Ftp::crlf);
638 state = SENT_EPSV_ALL;
639 } else {
640 if (ctrl.conn->local.isIPv6()) {
641 debugs(9, 5, HERE << "FTP Channel (" << ctrl.conn->remote << "). Sending default EPSV 2");
642 mb.Printf("EPSV 2%s", Ftp::crlf);
643 state = SENT_EPSV_2;
644 }
645 if (ctrl.conn->local.isIPv4()) {
646 debugs(9, 5, HERE << "Channel (" << ctrl.conn->remote <<"). Sending default EPSV 1");
647 mb.Printf("EPSV 1%s", Ftp::crlf);
648 state = SENT_EPSV_1;
649 }
650 }
651 break;
652 }
653
654 if (ctrl.message)
655 wordlistDestroy(&ctrl.message);
656 ctrl.message = NULL; //No message to return to client.
657 ctrl.offset = 0; //reset readed response, to make room read the next response
658
659 writeCommand(mb.content());
660
661 return true;
662
663
664 /*
665 * ugly hack for ftp servers like ftp.netscape.com that sometimes
666 * dont acknowledge PASV commands. Use connect timeout to be faster then read timeout (minutes).
667 */
668 /*
669 typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
670 AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
671 TimeoutDialer, ftpState, FtpStateData::timeout);
672 commSetConnTimeout(ftpState->ctrl.conn, Config.Timeout.connect, timeoutCall);
673 return true;
674 */
675}
676
677
434a79b0
DK
678void
679ServerStateData::connectDataChannel()
680{
681 safe_free(ctrl.last_command);
682
683 safe_free(ctrl.last_reply);
684
685 ctrl.last_command = xstrdup("Connect to server data port");
686
73950ceb 687 // Generate a new data channel descriptor to be opened.
434a79b0
DK
688 Comm::ConnectionPointer conn = new Comm::Connection;
689 conn->local = ctrl.conn->local;
73950ceb
AR
690 conn->local.port(0);
691 conn->remote = data.host;
692 conn->remote.port(data.port);
434a79b0
DK
693
694 debugs(9, 3, HERE << "connecting to " << conn->remote);
695
696 data.opener = commCbCall(9,3, "Ftp::ServerStateData::dataChannelConnected",
697 CommConnectCbPtrFun(ServerStateData::dataChannelConnected, this));
698 Comm::ConnOpener *cs = new Comm::ConnOpener(conn, data.opener, Config.Timeout.connect);
73950ceb 699 cs->setHost(data.host);
434a79b0
DK
700 AsyncJob::Start(cs);
701}
702
703void
704ServerStateData::dataChannelConnected(const Comm::ConnectionPointer &conn, comm_err_t status, int xerrno, void *data)
705{
706 ServerStateData *ftpState = static_cast<ServerStateData *>(data);
707 ftpState->dataChannelConnected(conn, status, xerrno);
708}
709
000e664b
AR
710bool
711ServerStateData::openListenSocket()
712{
713 return false;
714}
715
434a79b0
DK
716/// creates a data channel Comm close callback
717AsyncCall::Pointer
718ServerStateData::dataCloser()
719{
720 typedef CommCbMemFunT<ServerStateData, CommCloseCbParams> Dialer;
721 return JobCallback(9, 5, Dialer, this, ServerStateData::dataClosed);
722}
723
724/// handler called by Comm when FTP data channel is closed unexpectedly
725void
726ServerStateData::dataClosed(const CommCloseCbParams &io)
727{
728 debugs(9, 4, HERE);
729 if (data.listenConn != NULL) {
730 data.listenConn->close();
731 data.listenConn = NULL;
732 // NP clear() does the: data.fd = -1;
733 }
734 data.clear();
735}
736
737void
738ServerStateData::writeCommand(const char *buf)
739{
740 char *ebuf;
741 /* trace FTP protocol communications at level 2 */
742 debugs(9, 2, "ftp<< " << buf);
743
744 if (Config.Ftp.telnet)
745 ebuf = escapeIAC(buf);
746 else
747 ebuf = xstrdup(buf);
748
749 safe_free(ctrl.last_command);
750
751 safe_free(ctrl.last_reply);
752
753 ctrl.last_command = ebuf;
754
755 if (!Comm::IsConnOpen(ctrl.conn)) {
756 debugs(9, 2, HERE << "cannot send to closing ctrl " << ctrl.conn);
757 // TODO: assert(ctrl.closer != NULL);
758 return;
759 }
760
761 typedef CommCbMemFunT<ServerStateData, CommIoCbParams> Dialer;
762 AsyncCall::Pointer call = JobCallback(9, 5, Dialer, this,
763 ServerStateData::writeCommandCallback);
764 Comm::Write(ctrl.conn, ctrl.last_command, strlen(ctrl.last_command), call, NULL);
765
766 scheduleReadControlReply(0);
767}
768
769void
770ServerStateData::writeCommandCallback(const CommIoCbParams &io)
771{
772
773 debugs(9, 5, HERE << "wrote " << io.size << " bytes");
774
775 if (io.size > 0) {
776 fd_bytes(io.fd, io.size, FD_WRITE);
777 kb_incr(&(statCounter.server.all.kbytes_out), io.size);
778 kb_incr(&(statCounter.server.ftp.kbytes_out), io.size);
779 }
780
781 if (io.flag == COMM_ERR_CLOSING)
782 return;
783
784 if (io.flag) {
785 debugs(9, DBG_IMPORTANT, "ftpWriteCommandCallback: " << io.conn << ": " << xstrerr(io.xerrno));
786 failed(ERR_WRITE_ERROR, io.xerrno);
787 /* failed closes ctrl.conn and frees ftpState */
788 return;
789 }
790}
791
792/// handler called by Comm when FTP control channel is closed unexpectedly
793void
794ServerStateData::ctrlClosed(const CommCloseCbParams &io)
795{
796 debugs(9, 4, HERE);
797 ctrl.clear();
798 mustStop("Ftp::ServerStateData::ctrlClosed");
799}
800
801void
802ServerStateData::timeout(const CommTimeoutCbParams &io)
803{
804 debugs(9, 4, HERE << io.conn << ": '" << entry->url() << "'" );
805
806 if (abortOnBadEntry("entry went bad while waiting for a timeout"))
807 return;
808
809 failed(ERR_READ_TIMEOUT, 0);
810 /* failed() closes ctrl.conn and frees ftpState */
811}
812
813const Comm::ConnectionPointer &
814ServerStateData::dataConnection() const
815{
816 return data.conn;
817}
818
819void
820ServerStateData::maybeReadVirginBody()
821{
822 // too late to read
823 if (!Comm::IsConnOpen(data.conn) || fd_table[data.conn->fd].closing())
824 return;
825
826 if (data.read_pending)
827 return;
828
adaff124
DK
829 initReadBuf();
830
434a79b0
DK
831 const int read_sz = replyBodySpace(*data.readBuf, 0);
832
833 debugs(11,9, HERE << "FTP may read up to " << read_sz << " bytes");
834
835 if (read_sz < 2) // see http.cc
836 return;
837
838 data.read_pending = true;
839
840 typedef CommCbMemFunT<ServerStateData, CommTimeoutCbParams> TimeoutDialer;
841 AsyncCall::Pointer timeoutCall = JobCallback(9, 5,
842 TimeoutDialer, this, ServerStateData::timeout);
843 commSetConnTimeout(data.conn, Config.Timeout.read, timeoutCall);
844
845 debugs(9,5,HERE << "queueing read on FD " << data.conn->fd);
846
847 typedef CommCbMemFunT<ServerStateData, CommIoCbParams> Dialer;
848 entry->delayAwareRead(data.conn, data.readBuf->space(), read_sz,
849 JobCallback(9, 5, Dialer, this, ServerStateData::dataRead));
850}
851
852void
853ServerStateData::dataRead(const CommIoCbParams &io)
854{
855 int j;
856 int bin;
857
858 data.read_pending = false;
859
860 debugs(9, 3, HERE << "FD " << io.fd << " Read " << io.size << " bytes");
861
862 if (io.size > 0) {
863 kb_incr(&(statCounter.server.all.kbytes_in), io.size);
864 kb_incr(&(statCounter.server.ftp.kbytes_in), io.size);
865 }
866
867 if (io.flag == COMM_ERR_CLOSING)
868 return;
869
870 assert(io.fd == data.conn->fd);
871
872 if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
873 abortTransaction("entry aborted during dataRead");
874 return;
875 }
876
877 if (io.flag == COMM_OK && io.size > 0) {
878 debugs(9, 5, HERE << "appended " << io.size << " bytes to readBuf");
879 data.readBuf->appended(io.size);
880#if USE_DELAY_POOLS
881 DelayId delayId = entry->mem_obj->mostBytesAllowed();
882 delayId.bytesIn(io.size);
883#endif
884 ++ IOStats.Ftp.reads;
885
886 for (j = io.size - 1, bin = 0; j; ++bin)
887 j >>= 1;
888
889 ++ IOStats.Ftp.read_hist[bin];
890 }
891
892 if (io.flag != COMM_OK) {
893 debugs(50, ignoreErrno(io.xerrno) ? 3 : DBG_IMPORTANT,
894 HERE << "read error: " << xstrerr(io.xerrno));
895
896 if (ignoreErrno(io.xerrno)) {
897 typedef CommCbMemFunT<ServerStateData, CommTimeoutCbParams> TimeoutDialer;
898 AsyncCall::Pointer timeoutCall =
899 JobCallback(9, 5, TimeoutDialer, this,
900 ServerStateData::timeout);
901 commSetConnTimeout(io.conn, Config.Timeout.read, timeoutCall);
902
903 maybeReadVirginBody();
904 } else {
905 failed(ERR_READ_ERROR, 0);
906 /* failed closes ctrl.conn and frees ftpState */
907 return;
908 }
909 } else if (io.size == 0) {
910 debugs(9,3, HERE << "Calling dataComplete() because io.size == 0");
911 /*
912 * DPW 2007-04-23
913 * Dangerous curves ahead. This call to dataComplete was
914 * calling scheduleReadControlReply, handleControlReply,
915 * and then ftpReadTransferDone. If ftpReadTransferDone
916 * gets unexpected status code, it closes down the control
917 * socket and our FtpStateData object gets destroyed. As
918 * a workaround we no longer set the 'buffered_ok' flag in
919 * the scheduleReadControlReply call.
920 */
921 dataComplete();
922 }
923
924 processReplyBody();
925}
926
927void
928ServerStateData::dataComplete()
929{
930 debugs(9, 3,HERE);
931
932 /* Connection closed; transfer done. */
933
934 /// Close data channel, if any, to conserve resources while we wait.
935 data.close();
936
937 /* expect the "transfer complete" message on the control socket */
938 /*
939 * DPW 2007-04-23
940 * Previously, this was the only place where we set the
941 * 'buffered_ok' flag when calling scheduleReadControlReply().
942 * It caused some problems if the FTP server returns an unexpected
943 * status code after the data command. FtpStateData was being
944 * deleted in the middle of dataRead().
945 */
946 /* AYJ: 2011-01-13: Bug 2581.
947 * 226 status is possibly waiting in the ctrl buffer.
948 * The connection will hang if we DONT send buffered_ok.
949 * This happens on all transfers which can be completly sent by the
950 * server before the 150 started status message is read in by Squid.
951 * ie all transfers of about one packet hang.
952 */
953 scheduleReadControlReply(1);
954}
955
956/**
957 * Quickly abort the transaction
958 *
959 \todo destruction should be sufficient as the destructor should cleanup,
960 * including canceling close handlers
961 */
962void
963ServerStateData::abortTransaction(const char *reason)
964{
965 debugs(9, 3, HERE << "aborting transaction for " << reason <<
966 "; FD " << (ctrl.conn!=NULL?ctrl.conn->fd:-1) << ", Data FD " << (data.conn!=NULL?data.conn->fd:-1) << ", this " << this);
967 if (Comm::IsConnOpen(ctrl.conn)) {
968 ctrl.conn->close();
969 return;
970 }
971
972 fwd->handleUnregisteredServerEnd();
973 mustStop("ServerStateData::abortTransaction");
974}
975
976/**
977 * Cancel the timeout on the Control socket and establish one
978 * on the data socket
979 */
980void
981ServerStateData::switchTimeoutToDataChannel()
982{
983 commUnsetConnTimeout(ctrl.conn);
984
985 typedef CommCbMemFunT<ServerStateData, CommTimeoutCbParams> TimeoutDialer;
986 AsyncCall::Pointer timeoutCall = JobCallback(9, 5, TimeoutDialer, this,
987 ServerStateData::timeout);
988 commSetConnTimeout(data.conn, Config.Timeout.read, timeoutCall);
989}
990
991void
992ServerStateData::sentRequestBody(const CommIoCbParams &io)
993{
994 if (io.size > 0)
995 kb_incr(&(statCounter.server.ftp.kbytes_out), io.size);
996 ::ServerStateData::sentRequestBody(io);
997}
998
999/**
1000 * called after we wrote the last byte of the request body
1001 */
1002void
1003ServerStateData::doneSendingRequestBody()
1004{
1005 ::ServerStateData::doneSendingRequestBody();
1006 debugs(9,3, HERE);
1007 dataComplete();
1008 /* NP: RFC 959 3.3. DATA CONNECTION MANAGEMENT
1009 * if transfer type is 'stream' call dataComplete()
1010 * otherwise leave open. (reschedule control channel read?)
1011 */
1012}
1013
a2c7f09a
AR
1014/// Parses FTP server control response into ctrl structure fields,
1015/// setting bytesUsed and returning true on success.
1016bool
1017ServerStateData::parseControlReply(size_t &bytesUsed)
434a79b0
DK
1018{
1019 char *s;
1020 char *sbuf;
1021 char *end;
1022 int usable;
1023 int complete = 0;
1024 wordlist *head = NULL;
1025 wordlist *list;
1026 wordlist **tail = &head;
434a79b0 1027 size_t linelen;
434a79b0
DK
1028 debugs(9, 3, HERE);
1029 /*
1030 * We need a NULL-terminated buffer for scanning, ick
1031 */
a2c7f09a 1032 const size_t len = ctrl.offset;
434a79b0 1033 sbuf = (char *)xmalloc(len + 1);
a2c7f09a 1034 xstrncpy(sbuf, ctrl.buf, len + 1);
434a79b0
DK
1035 end = sbuf + len - 1;
1036
1037 while (*end != '\r' && *end != '\n' && end > sbuf)
1038 --end;
1039
1040 usable = end - sbuf;
1041
1042 debugs(9, 3, HERE << "usable = " << usable);
1043
1044 if (usable == 0) {
1045 debugs(9, 3, HERE << "didn't find end of line");
1046 safe_free(sbuf);
a2c7f09a 1047 return false;
434a79b0
DK
1048 }
1049
1050 debugs(9, 3, HERE << len << " bytes to play with");
1051 ++end;
1052 s = sbuf;
1053 s += strspn(s, crlf);
1054
1055 for (; s < end; s += strcspn(s, crlf), s += strspn(s, crlf)) {
1056 if (complete)
1057 break;
1058
1059 debugs(9, 5, HERE << "s = {" << s << "}");
1060
1061 linelen = strcspn(s, crlf) + 1;
1062
1063 if (linelen < 2)
1064 break;
1065
1066 if (linelen > 3)
1067 complete = (*s >= '0' && *s <= '9' && *(s + 3) == ' ');
1068
434a79b0
DK
1069 list = new wordlist();
1070
a2c7f09a 1071 list->key = (char *)xmalloc(linelen);
434a79b0 1072
a2c7f09a 1073 xstrncpy(list->key, s, linelen);
434a79b0
DK
1074
1075 /* trace the FTP communication chat at level 2 */
a2c7f09a
AR
1076 debugs(9, 2, "ftp>> " << list->key);
1077
1078 if (complete) {
1079 // use list->key for last_reply because s contains the new line
1080 ctrl.last_reply = xstrdup(list->key + 4);
1081 ctrl.replycode = atoi(list->key);
1082 }
434a79b0
DK
1083
1084 *tail = list;
1085
1086 tail = &list->next;
1087 }
1088
a2c7f09a 1089 bytesUsed = static_cast<size_t>(s - sbuf);
434a79b0
DK
1090 safe_free(sbuf);
1091
a2c7f09a 1092 if (!complete) {
434a79b0 1093 wordlistDestroy(&head);
a2c7f09a
AR
1094 return false;
1095 }
434a79b0 1096
a2c7f09a
AR
1097 ctrl.message = head;
1098 assert(ctrl.replycode >= 0);
1099 assert(ctrl.last_reply);
1100 assert(ctrl.message);
1101 return true;
434a79b0
DK
1102}
1103
1104}; // namespace Ftp
cff221ee
AR
1105
1106
1107bool
1108Ftp::ParseIpPort(const char *buf, const char *forceIp, Ip::Address &addr)
1109{
1110 int h1, h2, h3, h4;
1111 int p1, p2;
1112 const int n = sscanf(buf, "%d,%d,%d,%d,%d,%d",
1113 &h1, &h2, &h3, &h4, &p1, &p2);
1114
1115 if (n != 6 || p1 < 0 || p2 < 0 || p1 > 255 || p2 > 255)
1116 return false;
1117
1118 if (forceIp) {
1119 addr = forceIp; // but the above code still validates the IP we got
1120 } else {
1121 static char ipBuf[1024];
1122 snprintf(ipBuf, sizeof(ipBuf), "%d.%d.%d.%d", h1, h2, h3, h4);
1123 addr = ipBuf;
1124
73950ceb 1125 if (addr.isAnyAddr())
cff221ee
AR
1126 return false;
1127 }
1128
1129 const int port = ((p1 << 8) + p2);
1130
1131 if (port <= 0)
1132 return false;
1133
1134 if (Config.Ftp.sanitycheck && port < 1024)
1135 return false;
1136
73950ceb 1137 addr.port(port);
cff221ee
AR
1138 return true;
1139}
000e664b
AR
1140
1141bool
1142Ftp::ParseProtoIpPort(const char *buf, Ip::Address &addr)
1143{
1144
1145 const char delim = *buf;
1146 const char *s = buf + 1;
1147 const char *e = s;
1148 const int proto = strtol(s, const_cast<char**>(&e), 10);
1149 if ((proto != 1 && proto != 2) || *e != delim)
1150 return false;
1151
1152 s = e + 1;
1153 e = strchr(s, delim);
1154 char ip[MAX_IPSTRLEN];
1155 if (static_cast<size_t>(e - s) >= sizeof(ip))
1156 return false;
1157 strncpy(ip, s, e - s);
1158 ip[e - s] = '\0';
1159 addr = ip;
1160
1161 if (addr.isAnyAddr())
1162 return false;
1163
1164 if ((proto == 2) != addr.isIPv6()) // proto ID mismatches address version
1165 return false;
1166
1167 s = e + 1; // skip port delimiter
1168 const int port = strtol(s, const_cast<char**>(&e), 10);
1169 if (port < 0 || *e != '|')
1170 return false;
1171
1172 if (Config.Ftp.sanitycheck && port < 1024)
1173 return false;
1174
1175 addr.port(port);
1176 return true;
1177}
54a6c0cd
CT
1178
1179const char *
1180Ftp::unescapeDoubleQuoted(const char *quotedPath)
1181{
1182 static MemBuf path;
1183 path.reset();
1184 const char *s = quotedPath;
1185 if (*s == '"') {
1186 ++s;
1187 bool parseDone = false;
1188 while (!parseDone) {
1189 if (const char *e = strchr(s, '"')) {
1190 path.append(s, e - s);
1191 s = e + 1;
1192 if (*s == '"') {
1193 path.append(s, 1);
1194 ++s;
1195 } else
1196 parseDone = true;
1197 } else { //parse error
1198 parseDone = true;
1199 path.reset();
1200 }
1201 }
1202 }
1203 return path.content();
1204}
1205
1206bool
1207Ftp::hasPathParameter(const String &cmd)
1208{
1209 static const char *pathCommandsStr[]= {"CWD","SMNT", "RETR", "STOR", "APPE",
1210 "RNFR", "RNTO", "DELE", "RMD", "MKD",
45880cbd 1211 "LIST", "NLST", "STAT", "MLSD", "MLST"};
54a6c0cd
CT
1212 static const std::set<String> pathCommands(pathCommandsStr, pathCommandsStr + sizeof(pathCommandsStr)/sizeof(pathCommandsStr[0]));
1213 return pathCommands.find(cmd) != pathCommands.end();
1214}