Module Name:    othersrc
Committed By:   lukem
Date:           Sat May  6 09:32:18 UTC 2023

Modified Files:
        othersrc/usr.bin/tnftp/src: ftp.c ssl.c util.c version.h

Log Message:
Merge from tag NetBSD-20230226 to tag NetBSD-20230505


To generate a diff of this commit:
cvs rdiff -u -r1.24 -r1.25 othersrc/usr.bin/tnftp/src/ftp.c
cvs rdiff -u -r1.9 -r1.10 othersrc/usr.bin/tnftp/src/ssl.c
cvs rdiff -u -r1.26 -r1.27 othersrc/usr.bin/tnftp/src/util.c
cvs rdiff -u -r1.11 -r1.12 othersrc/usr.bin/tnftp/src/version.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: othersrc/usr.bin/tnftp/src/ftp.c
diff -u othersrc/usr.bin/tnftp/src/ftp.c:1.24 othersrc/usr.bin/tnftp/src/ftp.c:1.25
--- othersrc/usr.bin/tnftp/src/ftp.c:1.24	Fri Aug 27 01:38:49 2021
+++ othersrc/usr.bin/tnftp/src/ftp.c	Sat May  6 09:32:18 2023
@@ -1,5 +1,5 @@
-/*	$NetBSD: ftp.c,v 1.24 2021/08/27 01:38:49 lukem Exp $	*/
-/*	from	NetBSD: ftp.c,v 1.174 2021/08/26 06:23:24 lukem Exp	*/
+/*	$NetBSD: ftp.c,v 1.25 2023/05/06 09:32:18 lukem Exp $	*/
+/*	from	NetBSD: ftp.c,v 1.175 2023/05/05 15:46:06 lukem Exp	*/
 
 /*-
  * Copyright (c) 1996-2021 The NetBSD Foundation, Inc.
@@ -98,7 +98,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.175 2023/05/05 15:46:06 lukem Exp  ");
 #endif
 #endif /* not lint */
 
@@ -1741,7 +1741,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;
@@ -1755,7 +1756,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;

Index: othersrc/usr.bin/tnftp/src/ssl.c
diff -u othersrc/usr.bin/tnftp/src/ssl.c:1.9 othersrc/usr.bin/tnftp/src/ssl.c:1.10
--- othersrc/usr.bin/tnftp/src/ssl.c:1.9	Sun Apr  9 06:17:55 2023
+++ othersrc/usr.bin/tnftp/src/ssl.c	Sat May  6 09:32:18 2023
@@ -1,5 +1,5 @@
-/*	$NetBSD: ssl.c,v 1.9 2023/04/09 06:17:55 lukem Exp $	*/
-/*	from	NetBSD: ssl.c,v 1.14 2023/04/09 06:10:03 lukem Exp	*/
+/*	$NetBSD: ssl.c,v 1.10 2023/05/06 09:32:18 lukem Exp $	*/
+/*	from	NetBSD: ssl.c,v 1.15 2023/05/05 15:46:06 lukem Exp	*/
 
 /*-
  * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
@@ -40,9 +40,10 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID(" NetBSD: ssl.c,v 1.14 2023/04/09 06:10:03 lukem Exp  ");
+__RCSID(" NetBSD: ssl.c,v 1.15 2023/05/05 15:46:06 lukem Exp  ");
 #endif
 
+#include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <stdarg.h>
@@ -53,7 +54,6 @@ __RCSID(" NetBSD: ssl.c,v 1.14 2023/04/0
 #include <unistd.h>
 
 #include <sys/param.h>
-#include <sys/select.h>
 #include <sys/uio.h>
 
 #include <netinet/tcp.h>
@@ -103,38 +103,33 @@ 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) {
-				errno = ETIMEDOUT;
+		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;
-			}
-			errno = 0;
-			r = select(fd + 1, NULL, &writefds, NULL, &delta);
-			if (r == -1) {
-				if (errno == EINTR)
-					continue;
+			if (rv == 0) {
+				errno = ETIMEDOUT;
 				return -1;
 			}
 		}
@@ -337,7 +332,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;
 	}
@@ -372,33 +367,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];
+
+	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;
+	}
 
-	FD_ZERO(&fds);
-	while (!FD_ISSET(fd, &fds)) {
-		FD_SET(fd, &fds);
+	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;
 }
@@ -439,7 +444,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.
@@ -447,7 +452,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
@@ -469,7 +474,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:
@@ -591,19 +596,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();
@@ -617,43 +631,87 @@ 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);
+		goto cleanup_start_ssl;
+	}
+
+	/* NOTE: we now must restore socket flags on successful connection */
+
+	(void)gettimeofday(&timeout, NULL);	/* setup SSL_connect() timeout */
+	timeout.tv_sec += (quit_time > 0) ? quit_time: 60;
+						/* without -q, default to 60s */
+
 	SSL_set_fd(ssl, sock);
 	if (!SSL_set_tlsext_host_name(ssl, __UNCONST(servername))) {
-		fprintf(ttyout, "SSL hostname setting failed\n");
-		SSL_free(ssl);
-		SSL_CTX_free(ctx);
-		return NULL;
+		warnx("SSL hostname setting failed");
+		goto cleanup_start_ssl;
 	}
-	while ((ret = SSL_connect(ssl)) == -1) {
+	pfd[0].fd = sock;
+	pfd[0].events = 0;
+	while ((ret = SSL_connect(ssl)) <= 0) {
 		ssl_err = SSL_get_error(ssl, ret);
-		if (ssl_err != SSL_ERROR_WANT_READ &&
-		    ssl_err != SSL_ERROR_WANT_WRITE) {
+		DPRINTF("%s: SSL_connect() ret=%d ssl_err=%d\n",
+		    __func__, ret, ssl_err);
+		if (ret == 0) { /* unsuccessful handshake */
 			ERR_print_errors_fp(ttyout);
-			SSL_free(ssl);
-			SSL_CTX_free(ctx);
-			return NULL;
+			goto cleanup_start_ssl;
+		}
+		if (ssl_err == SSL_ERROR_WANT_READ) {
+			pfd[0].events = POLLIN;
+		} else if (ssl_err == SSL_ERROR_WANT_WRITE) {
+			pfd[0].events = POLLOUT;
+		} else {
+			ERR_print_errors_fp(ttyout);
+			goto cleanup_start_ssl;
+		}
+		(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);
+		if (rv == 0) {		/* poll for SSL_connect() timed out */
+			fprintf(ttyout, "Timeout establishing SSL connection to `%s'\n",
+			    servername);
+			goto cleanup_start_ssl;
+		} else if (rv == -1 && errno != EINTR && errno != EAGAIN) {
+			warn("Error polling for SSL connect to `%s'", servername);
+			goto cleanup_start_ssl;
 		}
 	}
 
+	if (fcntl(sock, F_SETFL, flags) == -1) {
+						/* restore socket flags */
+		warn("Can't %s socket flags for SSL connect to `%s'",
+		    "restore", servername);
+		goto cleanup_start_ssl;
+	}
+
 	if (ftp_debug && verbose) {
 		X509 *cert;
 		X509_NAME *name;
@@ -673,6 +731,13 @@ fetch_start_ssl(int sock, const char *se
 	}
 
 	return ssl;
+
+ cleanup_start_ssl:
+	if (ssl)
+		SSL_free(ssl);
+	if (ctx)
+		SSL_CTX_free(ctx);
+	return NULL;
 }
 #endif /* WITH_SSL */
 

Index: othersrc/usr.bin/tnftp/src/util.c
diff -u othersrc/usr.bin/tnftp/src/util.c:1.26 othersrc/usr.bin/tnftp/src/util.c:1.27
--- othersrc/usr.bin/tnftp/src/util.c:1.26	Sun Apr  9 00:56:07 2023
+++ othersrc/usr.bin/tnftp/src/util.c	Sat May  6 09:32:18 2023
@@ -1,5 +1,5 @@
-/*	$NetBSD: util.c,v 1.26 2023/04/09 00:56:07 lukem Exp $	*/
-/*	from	NetBSD: util.c,v 1.166 2023/02/25 12:07:25 mlelstv Exp	*/
+/*	$NetBSD: util.c,v 1.27 2023/05/06 09:32:18 lukem Exp $	*/
+/*	from	NetBSD: util.c,v 1.167 2023/05/05 15:46:06 lukem Exp	*/
 
 /*-
  * Copyright (c) 1997-2023 The NetBSD Foundation, Inc.
@@ -69,7 +69,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID(" NetBSD: util.c,v 1.166 2023/02/25 12:07:25 mlelstv Exp  ");
+__RCSID(" NetBSD: util.c,v 1.167 2023/05/05 15:46:06 lukem Exp  ");
 #endif /* not lint */
 
 /*
@@ -1450,8 +1450,8 @@ ftp_connect(int sock, const struct socka
 			}
 			pfd[0].revents = 0;
 			rv = ftp_poll(pfd, 1, timeout);
-						/* loop until poll ! EINTR */
-		} while (rv == -1 && errno == EINTR);
+					/* loop until poll !EINTR && !EAGAIN */
+		} while (rv == -1 && (errno == EINTR || errno == EAGAIN));
 
 		if (rv == 0) {			/* poll (connect) timed out */
 			errno = ETIMEDOUT;

Index: othersrc/usr.bin/tnftp/src/version.h
diff -u othersrc/usr.bin/tnftp/src/version.h:1.11 othersrc/usr.bin/tnftp/src/version.h:1.12
--- othersrc/usr.bin/tnftp/src/version.h:1.11	Sun Apr  9 00:56:07 2023
+++ othersrc/usr.bin/tnftp/src/version.h	Sat May  6 09:32:18 2023
@@ -1,5 +1,5 @@
-/*	$NetBSD: version.h,v 1.11 2023/04/09 00:56:07 lukem Exp $	*/
-/*	from	NetBSD: version.h,v 1.96 2023/02/25 12:07:25 mlelstv Exp	*/
+/*	$NetBSD: version.h,v 1.12 2023/05/06 09:32:18 lukem Exp $	*/
+/*	from	NetBSD: version.h,v 1.97 2023/05/05 15:46:06 lukem Exp	*/
 
 /*-
  * Copyright (c) 1999-2023 The NetBSD Foundation, Inc.
@@ -35,5 +35,5 @@
 #endif
 
 #ifndef FTP_VERSION
-#define	FTP_VERSION	"20230225"
+#define	FTP_VERSION	"20230505"
 #endif

Reply via email to