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