Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/netbsd-10]: src/usr.bin/ftp Pull up following revision(s) (requested by ...



details:   https://anonhg.NetBSD.org/src/rev/20e3c840fc1c
branches:  netbsd-10
changeset: 375847:20e3c840fc1c
user:      martin <martin%NetBSD.org@localhost>
date:      Tue May 16 16:26:03 2023 +0000

description:
Pull up following revision(s) (requested by lukem in ticket #171):

        usr.bin/ftp/ssl.c: revision 1.15
        usr.bin/ftp/util.c: revision 1.167
        usr.bin/ftp/ftp.c: revision 1.175
        usr.bin/ftp/version.h: revision 1.97

add timeout for ssl connect

Implement a timeout for SSL connection setup, using -q QUITTIME,
defaulting to 60 seconds.

SSL_connect(3) (unlike connect(2)) doesn't timeout by default.
Adapt ssl error messages destination: if unexpected error
from local API, use warn()/warnx() to stderr;
if expected error from a network operation (e.g., timeouts),
use fprintf to ttyout (which might be stdout).

Consistently use ftp_poll() instead of select();
ssl.c (using select()) was added 7 years after the
previous uses of select() were converted to poll().

Check EAGAIN as well as existing EINTR error from ftp_poll(),
for portability.

diffstat:

 usr.bin/ftp/ftp.c     |   10 +-
 usr.bin/ftp/ssl.c     |  215 ++++++++++++++++++++++++++++++++-----------------
 usr.bin/ftp/util.c    |    8 +-
 usr.bin/ftp/version.h |    4 +-
 4 files changed, 152 insertions(+), 85 deletions(-)

diffs (truncated from 425 to 300 lines):

diff -r 461e77e88801 -r 20e3c840fc1c usr.bin/ftp/ftp.c
--- a/usr.bin/ftp/ftp.c Tue May 16 16:23:45 2023 +0000
+++ b/usr.bin/ftp/ftp.c Tue May 16 16:26:03 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ftp.c,v 1.174 2021/08/26 06:23:24 lukem Exp $  */
+/*     $NetBSD: ftp.c,v 1.174.2.1 2023/05/16 16:26:03 martin Exp $     */
 
 /*-
  * Copyright (c) 1996-2021 The NetBSD Foundation, Inc.
@@ -92,7 +92,7 @@
 #if 0
 static char sccsid[] = "@(#)ftp.c      8.6 (Berkeley) 10/27/94";
 #else
-__RCSID("$NetBSD: ftp.c,v 1.174 2021/08/26 06:23:24 lukem Exp $");
+__RCSID("$NetBSD: ftp.c,v 1.174.2.1 2023/05/16 16:26:03 martin Exp $");
 #endif
 #endif /* not lint */
 
@@ -1733,7 +1733,8 @@ dataconn(const char *lmode)
                if (timeout < 0)
                        timeout = 0;
                rv = ftp_poll(pfd, 1, timeout);
-       } while (rv == -1 && errno == EINTR);   /* loop until poll ! EINTR */
+                       /* loop until poll !EINTR && !EAGAIN */
+       } while (rv == -1 && (errno == EINTR || errno == EAGAIN));
        if (rv == -1) {
                warn("Can't poll waiting before accept");
                goto dataconn_failed;
@@ -1747,7 +1748,8 @@ dataconn(const char *lmode)
        fromlen = myctladdr.su_len;
        do {
                s = accept(data, (struct sockaddr *) &from.si_su, &fromlen);
-       } while (s == -1 && errno == EINTR);    /* loop until accept ! EINTR */
+                       /* loop until accept !EINTR && !EAGAIN */
+       } while (s == -1 && (errno == EINTR || errno == EAGAIN));
        if (s == -1) {
                warn("Can't accept data connection");
                goto dataconn_failed;
diff -r 461e77e88801 -r 20e3c840fc1c usr.bin/ftp/ssl.c
--- a/usr.bin/ftp/ssl.c Tue May 16 16:23:45 2023 +0000
+++ b/usr.bin/ftp/ssl.c Tue May 16 16:26:03 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ssl.c,v 1.12.2.2 2023/05/16 16:23:45 martin Exp $      */
+/*     $NetBSD: ssl.c,v 1.12.2.3 2023/05/16 16:26:03 martin Exp $      */
 
 /*-
  * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
@@ -35,9 +35,10 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: ssl.c,v 1.12.2.2 2023/05/16 16:23:45 martin Exp $");
+__RCSID("$NetBSD: ssl.c,v 1.12.2.3 2023/05/16 16:26:03 martin Exp $");
 #endif
 
+#include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
@@ -48,7 +49,6 @@
 #include <unistd.h>
 
 #include <sys/param.h>
-#include <sys/select.h>
 #include <sys/uio.h>
 
 #include <netinet/tcp.h>
@@ -96,40 +96,35 @@ struct fetch_connect {
 static ssize_t
 fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
 {
-       struct timeval now, timeout, delta;
-       fd_set writefds;
+       struct timeval timeout, now, delta;
        ssize_t len, total;
        int fd = conn->sd;
-       int r;
+       int rv, timeout_secs;
+       struct pollfd pfd[1];
 
-       if (quit_time > 0) {
-               FD_ZERO(&writefds);
-               gettimeofday(&timeout, NULL);
-               timeout.tv_sec += quit_time;
-       }
+       pfd[0].fd = fd;
+       pfd[0].events = POLLOUT;
+       gettimeofday(&timeout, NULL);
+       timeout.tv_sec += quit_time;
 
        total = 0;
        while (iovcnt > 0) {
-               while (quit_time > 0 && !FD_ISSET(fd, &writefds)) {
-                       FD_SET(fd, &writefds);
-                       gettimeofday(&now, NULL);
-                       delta.tv_sec = timeout.tv_sec - now.tv_sec;
-                       delta.tv_usec = timeout.tv_usec - now.tv_usec;
-                       if (delta.tv_usec < 0) {
-                               delta.tv_usec += 1000000;
-                               delta.tv_sec--;
-                       }
-                       if (delta.tv_sec < 0) {
+               if (quit_time > 0) {    /* enforce timeout */
+                       do {
+                               (void)gettimeofday(&now, NULL);
+                               timersub(&timeout, &now, &delta);
+                               timeout_secs = delta.tv_sec * 1000 + delta.tv_usec/1000;
+                               if (timeout_secs < 0)
+                                       timeout_secs = 0;
+                               rv = ftp_poll(pfd, 1, timeout_secs);
+                                       /* loop until poll !EINTR && !EAGAIN */
+                       } while (rv == -1 && (errno == EINTR || errno == EAGAIN));
+                       if (rv == -1)
+                               return -1;
+                       if (rv == 0) {
                                errno = ETIMEDOUT;
                                return -1;
                        }
-                       errno = 0;
-                       r = select(fd + 1, NULL, &writefds, NULL, &delta);
-                       if (r == -1) {
-                               if (errno == EINTR)
-                                       continue;
-                               return -1;
-                       }
                }
                errno = 0;
 #ifdef WITH_SSL
@@ -330,7 +325,7 @@ fetch_nonssl_read(int sd, void *buf, siz
 
        rlen = read(sd, buf, len);
        if (rlen == -1) {
-               if (errno == EAGAIN || errno == EINTR)
+               if (errno == EINTR || errno == EAGAIN)
                        return FETCH_READ_WAIT;
                return FETCH_READ_ERROR;
        }
@@ -365,33 +360,43 @@ fetch_wait(struct fetch_connect *conn, s
 {
        struct timeval now, delta;
        int fd = conn->sd;
-       fd_set fds;
+       int rv, timeout_secs;
+       struct pollfd pfd[1];
 
-       FD_ZERO(&fds);
-       while (!FD_ISSET(fd, &fds)) {
-               FD_SET(fd, &fds);
+       pfd[0].fd = fd;
+       if (rlen == FETCH_READ_WAIT) {
+               pfd[0].events = POLLIN;
+       } else if (rlen == FETCH_WRITE_WAIT) {
+               pfd[0].events = POLLOUT;
+       } else {
+               pfd[0].events = 0;
+       }
+
+       do {
                if (quit_time > 0) {
                        gettimeofday(&now, NULL);
-                       if (!timercmp(timeout, &now, >)) {
-                               fprintf(ttyout, "\r\n%s: transfer aborted"
-                                   " because stalled for %lu sec.\r\n",
-                                   getprogname(), (unsigned long)quit_time);
-                               errno = ETIMEDOUT;
-                               conn->iserr = ETIMEDOUT;
-                               return -1;
-                       }
                        timersub(timeout, &now, &delta);
+                       timeout_secs = delta.tv_sec * 1000 + delta.tv_usec/1000;
+                       if (timeout_secs < 0)
+                               timeout_secs = 0;
+               } else {
+                       timeout_secs = INFTIM;
                }
                errno = 0;
-               if (select(fd + 1,
-                       rlen == FETCH_READ_WAIT ? &fds : NULL,
-                       rlen == FETCH_WRITE_WAIT ? &fds : NULL,
-                       NULL, quit_time > 0 ? &delta : NULL) < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       conn->iserr = errno;
-                       return -1;
-               }
+               rv = ftp_poll(pfd, 1, timeout_secs);
+                               /* loop until poll !EINTR && !EAGAIN */
+       } while (rv == -1 && (errno == EINTR || errno == EAGAIN));
+       if (rv == 0) {          /* poll timeout */
+               fprintf(ttyout, "\r\n%s: transfer aborted"
+                   " because stalled for %lu sec.\r\n",
+                   getprogname(), (unsigned long)quit_time);
+               errno = ETIMEDOUT;
+               conn->iserr = ETIMEDOUT;
+               return -1;
+       }
+       if (rv == -1) {         /* poll error */
+               conn->iserr = errno;
+               return -1;
        }
        return 0;
 }
@@ -432,7 +437,7 @@ fetch_read(void *ptr, size_t size, size_
        while (len > 0) {
                /*
                 * The socket is non-blocking.  Instead of the canonical
-                * select() -> read(), we do the following:
+                * poll() -> read(), we do the following:
                 *
                 * 1) call read() or SSL_read().
                 * 2) if an error occurred, return -1.
@@ -440,7 +445,7 @@ fetch_read(void *ptr, size_t size, size_
                 *    update our counters and loop.
                 * 4) if read() or SSL_read() signaled EOF, return.
                 * 5) if we did not receive any data but we're not at EOF,
-                *    call select().
+                *    call poll().
                 *
                 * In the SSL case, this is necessary because if we
                 * receive a close notification, we have to call
@@ -462,7 +467,7 @@ fetch_read(void *ptr, size_t size, size_
                        return total;
                case FETCH_READ_ERROR:
                        conn->iserr = errno;
-                       if (errno == EINTR)
+                       if (errno == EINTR || errno == EAGAIN)
                                fetch_cache_data(conn, start, total);
                        return 0;
                case FETCH_READ_WAIT:
@@ -584,19 +589,28 @@ fetch_getline(struct fetch_connect *conn
 }
 
 #ifdef WITH_SSL
+/*
+ * Start the SSL/TLS negotiation.
+ * Socket fcntl flags are temporarily updated to include O_NONBLOCK;
+ * these will not be reverted on connection failure.
+ * Returns pointer to allocated SSL structure on success,
+ * or NULL upon failure.
+ */
 void *
 fetch_start_ssl(int sock, const char *servername)
 {
-       SSL *ssl;
-       SSL_CTX *ctx;
+       SSL *ssl = NULL;
+       SSL_CTX *ctx = NULL;
        X509_VERIFY_PARAM *param;
-       int ret, ssl_err;
+       int ret, ssl_err, flags, rv, timeout_secs;
        int verify = !ftp_truthy("sslnoverify", getoptionvalue("sslnoverify"), 0);
+       struct timeval timeout, now, delta;
+       struct pollfd pfd[1];
 
        /* Init the SSL library and context */
        if (!SSL_library_init()){
-               fprintf(ttyout, "SSL library init failed\n");
-               return NULL;
+               warnx("SSL library init failed");
+               goto cleanup_start_ssl;
        }
 
        SSL_load_error_strings();
@@ -610,41 +624,85 @@ fetch_start_ssl(int sock, const char *se
 
        ssl = SSL_new(ctx);
        if (ssl == NULL){
-               fprintf(ttyout, "SSL context creation failed\n");
-               SSL_CTX_free(ctx);
-               return NULL;
+               warnx("SSL context creation failed");
+               goto cleanup_start_ssl;
        }
 
        if (verify) {
                param = SSL_get0_param(ssl);
                if (!X509_VERIFY_PARAM_set1_host(param, servername,
                    strlen(servername))) {
-                       fprintf(ttyout, "SSL verification setup failed\n");
-                       SSL_free(ssl);
-                       SSL_CTX_free(ctx);
-                       return NULL;
+                       warnx("SSL verification setup failed");
+                       goto cleanup_start_ssl;
                }
 
                /* Enable peer verification, (using the default callback) */
                SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
        }
 
+                                               /* save current socket flags */
+       if ((flags = fcntl(sock, F_GETFL, 0)) == -1) {
+               warn("Can't %s socket flags for SSL connect to `%s'",
+                   "save", servername);
+               goto cleanup_start_ssl;
+       }
+                                               /* set non-blocking connect */
+       if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1) {
+               warn("Can't set socket non-blocking for SSL connect to `%s'",
+                   servername);



Home | Main Index | Thread Index | Old Index