1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00

Bug 941: Survive an unexpected number of 227 or 229 FTP responses.

And document the functions a little.

[ From commit 71ff470f2e in ELinks
  0.11.2.GIT.  --KON ]
This commit is contained in:
Kalle Olavi Niemitalo 2007-04-12 01:02:00 +03:00 committed by Kalle Olavi Niemitalo
parent 253f55b222
commit 049cc9c6b3

View File

@ -906,12 +906,21 @@ next:
return file_len; return file_len;
} }
/* Connect to the host and port specified by a passive FTP server. */
static int static int
ftp_data_connect(struct connection *conn, int pf, struct sockaddr_storage *sa, ftp_data_connect(struct connection *conn, int pf, struct sockaddr_storage *sa,
int size_of_sockaddr) int size_of_sockaddr)
{ {
int fd = socket(pf, SOCK_STREAM, 0); int fd;
if (conn->data_socket->fd != -1) {
/* The server maliciously sent multiple 227 or 229
* responses. Do not leak the previous data_socket. */
abort_connection(conn, S_FTP_ERROR);
return -1;
}
fd = socket(pf, SOCK_STREAM, 0);
if (fd < 0 || set_nonblocking_fd(fd) < 0) { if (fd < 0 || set_nonblocking_fd(fd) < 0) {
abort_connection(conn, S_FTP_ERROR); abort_connection(conn, S_FTP_ERROR);
return -1; return -1;
@ -1036,6 +1045,21 @@ ftp_retr_file(struct socket *socket, struct read_buffer *rb)
} }
} }
if (conn->data_socket->fd == -1) {
/* The passive FTP server did not send a 227 or 229
* response. We check this down here, rather than
* immediately after getting the response to the PASV
* or EPSV command, to make sure that nothing can
* close the socket between the check and the
* following set_handlers call.
*
* If we were using active FTP, then
* get_ftp_data_socket would have created the
* data_socket without waiting for anything from the
* server. */
abort_connection(conn, S_FTP_ERROR);
return;
}
set_handlers(conn->data_socket->fd, (select_handler_T) ftp_data_accept, set_handlers(conn->data_socket->fd, (select_handler_T) ftp_data_accept,
NULL, NULL, conn); NULL, NULL, conn);
@ -1302,12 +1326,26 @@ ftp_process_dirlist(struct cache_entry *cached, off_t *pos,
} }
} }
/* This is the initial read handler for conn->data_socket->fd,
* which may be either trying to connect to a passive FTP server or
* listening for a connection from an active FTP server. In active
* FTP, this function then accepts the connection and replaces
* conn->data_socket->fd with the resulting socket. In any case,
* this function does not read any data from the FTP server, but
* rather hands the socket over to got_something_from_data_connection,
* which then does the reads. */
static void static void
ftp_data_accept(struct connection *conn) ftp_data_accept(struct connection *conn)
{ {
struct ftp_connection_info *ftp = conn->info; struct ftp_connection_info *ftp = conn->info;
int newsock; int newsock;
/* Because this function is called only as a read handler of
* conn->data_socket->fd, the socket must be valid if we get
* here. */
assert(conn->data_socket->fd >= 0);
if_assert_failed return;
set_connection_timeout(conn); set_connection_timeout(conn);
clear_handlers(conn->data_socket->fd); clear_handlers(conn->data_socket->fd);
@ -1333,6 +1371,9 @@ ftp_data_accept(struct connection *conn)
NULL, NULL, conn); NULL, NULL, conn);
} }
/* A read handler for conn->data_socket->fd. This function reads
* data from the FTP server, reformats it to HTML if it's a directory
* listing, and adds the result to the cache entry. */
static void static void
got_something_from_data_connection(struct connection *conn) got_something_from_data_connection(struct connection *conn)
{ {
@ -1340,6 +1381,12 @@ got_something_from_data_connection(struct connection *conn)
struct ftp_dir_html_format format; struct ftp_dir_html_format format;
ssize_t len; ssize_t len;
/* Because this function is called only as a read handler of
* conn->data_socket->fd, the socket must be valid if we get
* here. */
assert(conn->data_socket->fd >= 0);
if_assert_failed return;
/* XXX: This probably belongs rather to connect.c ? */ /* XXX: This probably belongs rather to connect.c ? */
set_connection_timeout(conn); set_connection_timeout(conn);