Module Name:    othersrc
Committed By:   lukem
Date:           Sun Apr  9 00:56:07 UTC 2023

Modified Files:
        othersrc/usr.bin/tnftp/src: cmdtab.c extern.h fetch.c ftp.1 ftp_var.h
            main.c ssl.c util.c version.h

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


To generate a diff of this commit:
cvs rdiff -u -r1.12 -r1.13 othersrc/usr.bin/tnftp/src/cmdtab.c
cvs rdiff -u -r1.14 -r1.15 othersrc/usr.bin/tnftp/src/extern.h
cvs rdiff -u -r1.26 -r1.27 othersrc/usr.bin/tnftp/src/fetch.c
cvs rdiff -u -r1.18 -r1.19 othersrc/usr.bin/tnftp/src/ftp.1
cvs rdiff -u -r1.13 -r1.14 othersrc/usr.bin/tnftp/src/ftp_var.h
cvs rdiff -u -r1.22 -r1.23 othersrc/usr.bin/tnftp/src/main.c
cvs rdiff -u -r1.7 -r1.8 othersrc/usr.bin/tnftp/src/ssl.c
cvs rdiff -u -r1.25 -r1.26 othersrc/usr.bin/tnftp/src/util.c
cvs rdiff -u -r1.10 -r1.11 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/cmdtab.c
diff -u othersrc/usr.bin/tnftp/src/cmdtab.c:1.12 othersrc/usr.bin/tnftp/src/cmdtab.c:1.13
--- othersrc/usr.bin/tnftp/src/cmdtab.c:1.12	Sun May  5 11:17:30 2013
+++ othersrc/usr.bin/tnftp/src/cmdtab.c	Sun Apr  9 00:56:07 2023
@@ -1,8 +1,8 @@
-/*	$NetBSD: cmdtab.c,v 1.12 2013/05/05 11:17:30 lukem Exp $	*/
-/*	from	NetBSD: cmdtab.c,v 1.52 2012/12/22 16:57:09 christos Exp	*/
+/*	$NetBSD: cmdtab.c,v 1.13 2023/04/09 00:56:07 lukem Exp $	*/
+/*	from	NetBSD: cmdtab.c,v 1.53 2023/02/25 12:07:25 mlelstv Exp	*/
 
 /*-
- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996-2023 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -68,7 +68,7 @@
 #if 0
 static char sccsid[] = "@(#)cmdtab.c	8.4 (Berkeley) 10/9/94";
 #else
-__RCSID(" NetBSD: cmdtab.c,v 1.52 2012/12/22 16:57:09 christos Exp  ");
+__RCSID(" NetBSD: cmdtab.c,v 1.53 2023/02/25 12:07:25 mlelstv Exp  ");
 #endif
 #endif /* not lint */
 
@@ -303,13 +303,14 @@ struct cmd cmdtab[] = {
 };
 
 struct option optiontab[] = {
-	{ "anonpass",	NULL },
-	{ "ftp_proxy",	NULL },
-	{ "http_proxy",	NULL },
-	{ "https_proxy",NULL },
-	{ "no_proxy",	NULL },
-	{ "pager",	NULL },
-	{ "prompt",	NULL },
-	{ "rprompt",	NULL },
-	{ NULL,		NULL },
+	{ "anonpass",	   NULL },
+	{ "ftp_proxy",	   NULL },
+	{ "http_proxy",	   NULL },
+	{ "https_proxy",   NULL },
+	{ "no_proxy",	   NULL },
+	{ "pager",	   NULL },
+	{ "prompt",	   NULL },
+	{ "rprompt",	   NULL },
+	{ "sslnoverify"   ,NULL },
+	{ NULL,		   NULL },
 };

Index: othersrc/usr.bin/tnftp/src/extern.h
diff -u othersrc/usr.bin/tnftp/src/extern.h:1.14 othersrc/usr.bin/tnftp/src/extern.h:1.15
--- othersrc/usr.bin/tnftp/src/extern.h:1.14	Sat Jul  4 09:59:07 2020
+++ othersrc/usr.bin/tnftp/src/extern.h	Sun Apr  9 00:56:07 2023
@@ -1,8 +1,8 @@
-/*	$NetBSD: extern.h,v 1.14 2020/07/04 09:59:07 lukem Exp $	*/
-/*	from	NetBSD: extern.h,v 1.82 2019/06/22 23:40:53 christos Exp	*/
+/*	$NetBSD: extern.h,v 1.15 2023/04/09 00:56:07 lukem Exp $	*/
+/*	from	NetBSD: extern.h,v 1.83 2023/02/25 12:07:25 mlelstv Exp	*/
 
 /*-
- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996-2023 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -244,6 +244,7 @@ void	user(int, char **);
 int	ftp_connect(int, const struct sockaddr *, socklen_t, int);
 int	ftp_listen(int, int);
 int	ftp_poll(struct pollfd *, int, int);
+int	ftp_truthy(const char *, const char *, int);
 #ifndef SMALL
 void   *ftp_malloc(size_t);
 StringList *ftp_sl_init(void);

Index: othersrc/usr.bin/tnftp/src/fetch.c
diff -u othersrc/usr.bin/tnftp/src/fetch.c:1.26 othersrc/usr.bin/tnftp/src/fetch.c:1.27
--- othersrc/usr.bin/tnftp/src/fetch.c:1.26	Fri Aug 27 01:38:49 2021
+++ othersrc/usr.bin/tnftp/src/fetch.c	Sun Apr  9 00:56:07 2023
@@ -1,5 +1,5 @@
-/*	$NetBSD: fetch.c,v 1.26 2021/08/27 01:38:49 lukem Exp $	*/
-/*	from	NetBSD: fetch.c,v 1.234 2021/08/01 15:29:30 andvar Exp	*/
+/*	$NetBSD: fetch.c,v 1.27 2023/04/09 00:56:07 lukem Exp $	*/
+/*	from	NetBSD: fetch.c,v 1.236 2023/02/25 12:07:25 mlelstv Exp	*/
 
 /*-
  * Copyright (c) 1997-2015 The NetBSD Foundation, Inc.
@@ -42,7 +42,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID(" NetBSD: fetch.c,v 1.234 2021/08/01 15:29:30 andvar Exp  ");
+__RCSID(" NetBSD: fetch.c,v 1.236 2023/02/25 12:07:25 mlelstv Exp  ");
 #endif /* not lint */
 
 /*
@@ -113,12 +113,13 @@ __dead static void	timeouthttp(int);
 static int	auth_url(const char *, char **, const struct authinfo *);
 static void	base64_encode(const unsigned char *, size_t, unsigned char *);
 #endif
-static int	go_fetch(const char *);
+static int	go_fetch(const char *, struct urlinfo *);
 static int	fetch_ftp(const char *);
-static int	fetch_url(const char *, const char *, char *, char *);
+static int	fetch_url(const char *, const char *, char *, char *,
+    struct urlinfo *);
 static const char *match_token(const char **, const char *);
 static int	parse_url(const char *, const char *, struct urlinfo *,
-    struct authinfo *);
+    struct authinfo *, struct urlinfo *);
 static void	url_decode(char *);
 static void	freeauthinfo(struct authinfo *);
 static void	freeurlinfo(struct urlinfo *);
@@ -281,7 +282,7 @@ auth_url(const char *challenge, char **r
 	scheme = "Basic";	/* only support Basic authentication */
 	gotpass = NULL;
 
-	DPRINTF("auth_url: challenge `%s'\n", challenge);
+	DPRINTF("%s: challenge `%s'\n", __func__, challenge);
 
 	if (! match_token(&cp, scheme)) {
 		warnx("Unsupported authentication challenge `%s'",
@@ -343,7 +344,7 @@ auth_url(const char *challenge, char **r
 	*response = ftp_malloc(rlen);
 	(void)strlcpy(*response, scheme, rlen);
 	len = strlcat(*response, " ", rlen);
-			/* use  `clen - 1'  to not encode the trailing NUL */
+			/* use	`clen - 1'  to not encode the trailing NUL */
 	base64_encode((unsigned char *)clear, clen - 1,
 	    (unsigned char *)*response + len);
 	memset(clear, 0, clen);
@@ -374,7 +375,7 @@ base64_encode(const unsigned char *clear
 			    | ((clear[i + 1] >> 4) & 0x0f)];
 		*(cp++) = enc[((clear[i + 1] << 2) & 0x3c)
 			    | ((clear[i + 2] >> 6) & 0x03)];
-		*(cp++) = enc[((clear[i + 2]     ) & 0x3f)];
+		*(cp++) = enc[((clear[i + 2]	 ) & 0x3f)];
 	}
 	*cp = '\0';
 	while (i-- > len)
@@ -407,6 +408,42 @@ url_decode(char *url)
 	*q = '\0';
 }
 
+static const char *
+get_port(const struct urlinfo *ui)
+{
+
+	switch(ui->utype) {
+	case HTTP_URL_T:
+		return httpport;
+	case FTP_URL_T:
+		return ftpport;
+	case FILE_URL_T:
+		return "";
+#ifdef WITH_SSL
+	case HTTPS_URL_T:
+		return httpsport;
+#endif
+	default:
+		return NULL;
+	}
+}
+
+static int
+use_relative(const struct urlinfo *ui)
+{
+	if (ui == NULL)
+		return 0;
+	switch (ui->utype) {
+	case HTTP_URL_T:
+	case FILE_URL_T:
+#ifdef WITH_SSL
+	case HTTPS_URL_T:
+#endif
+		return 1;
+	default:
+		return 0;
+	}
+}
 
 /*
  * Parse URL of form (per RFC 3986):
@@ -442,7 +479,7 @@ url_decode(char *url)
 
 static int
 parse_url(const char *url, const char *desc, struct urlinfo *ui,
-    struct authinfo *auth) 
+    struct authinfo *auth, struct urlinfo *rui)
 {
 	const char	*origurl, *tport;
 	char		*cp, *ep, *thost;
@@ -453,29 +490,26 @@ parse_url(const char *url, const char *d
 	DPRINTF("parse_url: %s `%s'\n", desc, url);
 
 	origurl = url;
-	tport = NULL;
 
 	if (STRNEQUAL(url, HTTP_URL)) {
 		url += sizeof(HTTP_URL) - 1;
 		ui->utype = HTTP_URL_T;
 		ui->portnum = HTTP_PORT;
-		tport = httpport;
 	} else if (STRNEQUAL(url, FTP_URL)) {
 		url += sizeof(FTP_URL) - 1;
 		ui->utype = FTP_URL_T;
 		ui->portnum = FTP_PORT;
-		tport = ftpport;
 	} else if (STRNEQUAL(url, FILE_URL)) {
 		url += sizeof(FILE_URL) - 1;
 		ui->utype = FILE_URL_T;
-		tport = "";
 #ifdef WITH_SSL
 	} else if (STRNEQUAL(url, HTTPS_URL)) {
 		url += sizeof(HTTPS_URL) - 1;
 		ui->utype = HTTPS_URL_T;
 		ui->portnum = HTTPS_PORT;
-		tport = httpsport;
 #endif
+	} else if (rui != NULL) {
+		copyurlinfo(ui, rui);
 	} else {
 		warnx("Invalid %s `%s'", desc, url);
  cleanup_parse_url:
@@ -484,6 +518,7 @@ parse_url(const char *url, const char *d
 		return (-1);
 	}
 
+
 	if (*url == '\0')
 		return (0);
 
@@ -548,7 +583,8 @@ parse_url(const char *url, const char *d
 #endif /* INET6 */
 		if ((cp = strchr(thost, ':')) != NULL)
 			*cp++ = '\0';
-	ui->host = thost;
+	if (*thost != '\0')
+		ui->host = thost;
 
 			/* look for [:port] */
 	if (cp != NULL) {
@@ -563,7 +599,9 @@ parse_url(const char *url, const char *d
 		}
 		ui->portnum = nport;
 		tport = cp;
-	}
+	} else
+		tport = get_port(ui);
+
 
 	if (tport != NULL)
 		ui->port = ftp_strdup(tport);
@@ -574,8 +612,8 @@ parse_url(const char *url, const char *d
 		ui->path = ftp_strdup(emptypath);
 	}
 
-	DPRINTF("parse_url: user `%s' pass `%s' host %s port %s(%d) "
-	    "path `%s'\n",
+	DPRINTF("%s: user `%s' pass `%s' host %s port %s(%d) "
+	    "path `%s'\n", __func__,
 	    STRorNULL(auth->user), STRorNULL(auth->pass),
 	    STRorNULL(ui->host), STRorNULL(ui->port),
 	    ui->portnum ? ui->portnum : -1, STRorNULL(ui->path));
@@ -586,13 +624,15 @@ parse_url(const char *url, const char *d
 sigjmp_buf	httpabort;
 
 static int
-ftp_socket(const struct urlinfo *ui, void **ssl)
+ftp_socket(const struct urlinfo *ui, void **ssl, struct authinfo *auth)
 {
-	struct addrinfo	hints, *res, *res0 = NULL;
+	struct addrinfo hints, *res, *res0 = NULL;
 	int error;
 	int s;
 	const char *host = ui->host;
 	const char *port = ui->port;
+	char *fuser = NULL, *pass = NULL, *facct = NULL;
+	int n;
 
 	if (ui->utype != HTTPS_URL_T)
 		ssl = NULL;
@@ -657,6 +697,28 @@ ftp_socket(const struct urlinfo *ui, voi
 			continue;
 		}
 
+		if (ruserpass("", &fuser, &pass, &facct) < 0) {
+			close(s);
+			s = -1;
+			continue;
+		}
+
+		if (autologin) {
+			if (fuser != NULL && auth->user == NULL)
+				auth->user = ftp_strdup(fuser);
+			if (pass != NULL && auth->pass == NULL)
+				auth->pass = ftp_strdup(pass);
+		}
+
+		for (n = 0; n < macnum; ++n) {
+			if (!strcmp("init", macros[n].mac_name)) {
+				(void)strlcpy(line, "$init", sizeof(line));
+				makeargv();
+				domacro(margc, margv);
+				break;
+			}
+		}
+
 #ifdef WITH_SSL
 		if (ssl) {
 			if ((*ssl = fetch_start_ssl(s, host)) == NULL) {
@@ -668,6 +730,15 @@ ftp_socket(const struct urlinfo *ui, voi
 #endif
 		break;
 	}
+
+	FREEPTR(fuser);
+	if (pass != NULL)
+		memset(pass, 0, strlen(pass));
+	FREEPTR(pass);
+	if (facct != NULL)
+		memset(facct, 0, strlen(facct));
+	FREEPTR(facct);
+
 	if (res0)
 		freeaddrinfo(res0);
 	return s;
@@ -693,7 +764,7 @@ handle_noproxy(const char *host, in_port
 		if (*cp == '\0')
 			continue;
 		if ((np = strrchr(cp, ':')) != NULL) {
-			*np++ =  '\0';
+			*np++ =	 '\0';
 			np_port = strtoul(np, &ep, 10);
 			if (*np == '\0' || *ep != '\0')
 				continue;
@@ -725,7 +796,7 @@ handle_proxy(const char *url, const char
 	}
 
 	initurlinfo(&pui);
-	if (parse_url(penv, "proxy URL", &pui, pauth) == -1)
+	if (parse_url(penv, "proxy URL", &pui, pauth, NULL) == -1)
 		return -1;
 
 	if ((!IS_HTTP_TYPE(pui.utype) && pui.utype != FTP_URL_T) ||
@@ -896,9 +967,9 @@ print_connect(FETCH *fin, const struct u
 }
 #endif
 
-#define C_OK 0
-#define C_CLEANUP 1
-#define C_IMPROPER 2
+#define	C_OK 0
+#define	C_CLEANUP 1
+#define	C_IMPROPER 2
 
 static int
 getresponseline(FETCH *fin, char *buf, size_t buflen, int *len)
@@ -997,7 +1068,7 @@ parse_posinfo(const char **cp, struct po
 static void
 do_auth(int hcode, const char *url, const char *penv, struct authinfo *wauth,
     struct authinfo *pauth, char **auth, const char *message,
-    volatile int *rval)
+    volatile int *rval, struct urlinfo *ui)
 {
 	struct authinfo aauth;
 	char *response;
@@ -1032,7 +1103,8 @@ do_auth(int hcode, const char *url, cons
 	if (auth_url(*auth, &response, &aauth) == 0) {
 		*rval = fetch_url(url, penv,
 		    hcode == 401 ? pauth->auth : response,
-		    hcode == 401 ? response: wauth->auth);
+		    hcode == 401 ? response : wauth->auth,
+		    ui);
 		memset(response, 0, strlen(response));
 		FREEPTR(response);
 	}
@@ -1043,12 +1115,12 @@ static int
 negotiate_connection(FETCH *fin, const char *url, const char *penv,
     struct posinfo *pi, time_t *mtime, struct authinfo *wauth,
     struct authinfo *pauth, volatile int *rval, volatile int *ischunked,
-    char **auth)
+    char **auth, struct urlinfo *ui)
 {
 	int			len, hcode, rv;
 	char			buf[FTPBUFLEN], *ep;
 	const char		*cp, *token;
-	char 			*location, *message;
+	char			*location, *message;
 
 	*auth = message = location = NULL;
 
@@ -1163,18 +1235,19 @@ negotiate_connection(FETCH *fin, const c
 				fprintf(ttyout, "Redirected via %s\n",
 				    location);
 			*rval = fetch_url(url, location,
-			    pauth->auth, wauth->auth);
+			    pauth->auth, wauth->auth, ui);
 		} else {
 			if (verbose)
 				fprintf(ttyout, "Redirected to %s\n",
 				    location);
-			*rval = go_fetch(location);
+			*rval = go_fetch(location, ui);
 		}
 		goto cleanup_fetch_url;
 #ifndef NO_AUTH
 	case 401:
 	case 407:
-		do_auth(hcode, url, penv, wauth, pauth, auth, message, rval);
+		do_auth(hcode, url, penv, wauth, pauth, auth, message, rval,
+		    ui);
 		goto cleanup_fetch_url;
 #endif
 	default:
@@ -1239,7 +1312,7 @@ connectmethod(FETCH *fin, const char *ur
 		message = ftp_strdup(ep);
 		break;
 	}
-		
+
 	for (;;) {
 		int len;
 		if (getresponseline(fin, buf, sizeof(buf), &len) != C_OK)
@@ -1268,7 +1341,8 @@ connectmethod(FETCH *fin, const char *ur
 		break;
 #ifndef NO_AUTH
 	case 407:
-		do_auth(hcode, url, penv, wauth, pauth, auth, message, rval);
+		do_auth(hcode, url, penv, wauth, pauth, auth, message, rval,
+		    ui);
 		goto cleanup_fetch_url;
 #endif
 	default:
@@ -1306,7 +1380,8 @@ out:
  * is still open (e.g, ftp xfer with trailing /)
  */
 static int
-fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
+fetch_url(const char *url, const char *proxyenv, char *proxyauth,
+    char *wwwauth, struct urlinfo *rui)
 {
 	sigfunc volatile	oldint;
 	sigfunc volatile	oldpipe;
@@ -1315,7 +1390,7 @@ fetch_url(const char *url, const char *p
 	int volatile		s;
 	struct stat		sb;
 	int volatile		isproxy;
-	int volatile 		rval, ischunked;
+	int volatile		rval, ischunked;
 	size_t			flen;
 	static size_t		bufsize;
 	static char		*xferbuf;
@@ -1326,7 +1401,7 @@ fetch_url(const char *url, const char *p
 	char			*volatile location;
 	char			*volatile message;
 	char			*volatile decodedpath;
-	struct authinfo 	wauth, pauth;
+	struct authinfo		wauth, pauth;
 	struct posinfo		pi;
 	off_t			hashbytes;
 	int			(*volatile closefunc)(FILE *);
@@ -1359,7 +1434,7 @@ fetch_url(const char *url, const char *p
 	if (sigsetjmp(httpabort, 1))
 		goto cleanup_fetch_url;
 
-	if (parse_url(url, "URL", &ui, &wauth) == -1)
+	if (parse_url(url, "URL", &ui, &wauth, rui) == -1)
 		goto cleanup_fetch_url;
 
 	copyurlinfo(&oui, &ui);
@@ -1375,7 +1450,7 @@ fetch_url(const char *url, const char *p
 			rval = fetch_ftp(url);
 			goto cleanup_fetch_url;
 		}
-		if (!IS_HTTP_TYPE(ui.utype) || outfile == NULL)  {
+		if (!IS_HTTP_TYPE(ui.utype) || outfile == NULL)	 {
 			warnx("Invalid URL (no file after host) `%s'", url);
 			goto cleanup_fetch_url;
 		}
@@ -1430,7 +1505,8 @@ fetch_url(const char *url, const char *p
 			filesize = sb.st_size;
 		}
 		if (restart_point) {
-			if (lseek(fetch_fileno(fin), restart_point, SEEK_SET) < 0) {
+			if (lseek(fetch_fileno(fin), restart_point, SEEK_SET) 
+			    < 0) {
 				warn("Can't seek to restart `%s'",
 				    decodedpath);
 				goto cleanup_fetch_url;
@@ -1448,6 +1524,10 @@ fetch_url(const char *url, const char *p
 		}
 	} else {				/* ftp:// or http:// URLs */
 		int hasleading;
+		static char hostnamebuf[MAXHOSTNAMELEN];
+
+		(void)strlcpy(hostnamebuf, ui.host, sizeof(hostnamebuf));
+		hostname = hostnamebuf;
 
 		if (penv == NULL) {
 #ifdef WITH_SSL
@@ -1481,7 +1561,7 @@ fetch_url(const char *url, const char *p
 			}
 		} /* ! EMPTYSTRING(penv) */
 
-		s = ftp_socket(&ui, &ssl);
+		s = ftp_socket(&ui, &ssl, &wauth);
 		if (s < 0) {
 			warnx("Can't connect to `%s:%s'", ui.host, ui.port);
 			goto cleanup_fetch_url;
@@ -1542,7 +1622,7 @@ fetch_url(const char *url, const char *p
 
 		switch (negotiate_connection(fin, url, penv, &pi,
 		    &mtime, &wauth, &pauth, &rval, &ischunked,
-		    __UNVOLATILE(&auth))) {
+		    __UNVOLATILE(&auth), &ui)) {
 		case C_OK:
 			break;
 		case C_CLEANUP:
@@ -1649,7 +1729,7 @@ fetch_url(const char *url, const char *p
 			}
 
 				/*
-				 * XXX:	Work around bug in Apache 1.3.9 and
+				 * XXX: Work around bug in Apache 1.3.9 and
 				 *	1.3.11, which incorrectly put trailing
 				 *	space after the chunk-size.
 				 */
@@ -1857,10 +1937,10 @@ fetch_ftp(const char *url)
 	char		 dirbuf[4];
 	int		 dirhasglob, filehasglob, rval, transtype, xargc;
 	int		 oanonftp, oautologin;
-	struct authinfo  auth;
+	struct authinfo	 auth;
 	struct urlinfo	 ui;
 
-	DPRINTF("fetch_ftp: `%s'\n", url);
+	DPRINTF("%s: `%s'\n", __func__, url);
 	dir = file = NULL;
 	rval = 1;
 	transtype = TYPE_I;
@@ -1869,7 +1949,7 @@ fetch_ftp(const char *url)
 	initauthinfo(&auth, NULL);
 
 	if (STRNEQUAL(url, FTP_URL)) {
-		if ((parse_url(url, "URL", &ui, &auth) == -1) ||
+		if ((parse_url(url, "URL", &ui, &auth, NULL) == -1) ||
 		    (auth.user != NULL && *auth.user == '\0') ||
 		    EMPTYSTRING(ui.host)) {
 			warnx("Invalid URL `%s'", url);
@@ -1881,7 +1961,8 @@ fetch_ftp(const char *url)
 		 */
 
 					/* check for trailing ';type=[aid]' */
-		if (! EMPTYSTRING(ui.path) && (cp = strrchr(ui.path, ';')) != NULL) {
+		if (! EMPTYSTRING(ui.path)
+		    && (cp = strrchr(ui.path, ';')) != NULL) {
 			if (strcasecmp(cp, ";type=a") == 0)
 				transtype = TYPE_A;
 			else if (strcasecmp(cp, ";type=i") == 0)
@@ -1923,12 +2004,12 @@ fetch_ftp(const char *url)
 		 * If we are dealing with classic `[user@]host:[path]' syntax,
 		 * then a path of the form `/file' (resulting from input of the
 		 * form `host:/file') means that we should do "CWD /" before
-		 * retrieving the file.  So we set dir="/" and file="file".
+		 * retrieving the file.	 So we set dir="/" and file="file".
 		 *
 		 * But if we are dealing with URLs like `ftp://host/path' then
 		 * a path of the form `/file' (resulting from a URL of the form
 		 * `ftp://host//file') means that we should do `CWD ' (with an
-		 * empty argument) before retrieving the file.  So we set
+		 * empty argument) before retrieving the file.	So we set
 		 * dir="" and file="file".
 		 *
 		 * If the path does not contain / at all, we set dir=NULL.
@@ -1959,8 +2040,8 @@ fetch_ftp(const char *url)
 		url_decode(file);
 		/* but still don't url_decode(dir) */
 	}
-	DPRINTF("fetch_ftp: user `%s' pass `%s' host %s port %s "
-	    "path `%s' dir `%s' file `%s'\n",
+	DPRINTF("%s: user `%s' pass `%s' host %s port %s "
+	    "path `%s' dir `%s' file `%s'\n", __func__,
 	    STRorNULL(auth.user), STRorNULL(auth.pass),
 	    STRorNULL(ui.host), STRorNULL(ui.port),
 	    STRorNULL(ui.path), STRorNULL(dir), STRorNULL(file));
@@ -2009,7 +2090,7 @@ fetch_ftp(const char *url)
 		setbinary(1, xargv);
 		break;
 	default:
-		errx(1, "fetch_ftp: unknown transfer type %d", transtype);
+		errx(1, "%s: unknown transfer type %d", __func__, transtype);
 	}
 
 		/*
@@ -2031,7 +2112,7 @@ fetch_ftp(const char *url)
 		 * (urltype is FTP_URL_T), then RFC 3986 says we need to
 		 * send a separate CWD command for each unescaped "/"
 		 * in the path, and we have to interpret %hex escaping
-		 * *after* we find the slashes.  It's possible to get
+		 * *after* we find the slashes.	 It's possible to get
 		 * empty components here, (from multiple adjacent
 		 * slashes in the path) and RFC 3986 says that we should
 		 * still do `CWD ' (with a null argument) in such cases.
@@ -2074,7 +2155,7 @@ fetch_ftp(const char *url)
 		 *		"CWD /", "CWD foo", "CWD bar", "RETR file"
 		 * ftp://host/%2Ffoo/bar/file	dir="%2Ffoo/bar"
 		 *		"CWD /foo", "CWD bar", "RETR file"
-		 * ftp://host/%2Ffoo%2Fbar/file	dir="%2Ffoo%2Fbar"
+		 * ftp://host/%2Ffoo%2Fbar/file dir="%2Ffoo%2Fbar"
 		 *		"CWD /foo/bar", "RETR file"
 		 * ftp://host/%2Ffoo%2Fbar%2Ffile	dir=NULL
 		 *		"RETR /foo/bar/file"
@@ -2091,7 +2172,7 @@ fetch_ftp(const char *url)
 				url_decode(dir);
 			} else
 				nextpart = NULL;
-			DPRINTF("fetch_ftp: dir `%s', nextpart `%s'\n",
+			DPRINTF("%s: dir `%s', nextpart `%s'\n", __func__,
 			    STRorNULL(dir), STRorNULL(nextpart));
 			if (ui.utype == FTP_URL_T || *dir != '\0') {
 				(void)strlcpy(cmdbuf, "cd", sizeof(cmdbuf));
@@ -2186,7 +2267,7 @@ fetch_ftp(const char *url)
  * is still open (e.g, ftp xfer with trailing /)
  */
 static int
-go_fetch(const char *url)
+go_fetch(const char *url, struct urlinfo *rui)
 {
 	char *proxyenv;
 	char *p;
@@ -2235,7 +2316,7 @@ go_fetch(const char *url)
 	    || STRNEQUAL(url, HTTPS_URL)
 #endif
 	    || STRNEQUAL(url, FILE_URL))
-		return (fetch_url(url, NULL, NULL, NULL));
+		return (fetch_url(url, NULL, NULL, NULL, rui));
 
 	/*
 	 * If it contains "://" but does not begin with ftp://
@@ -2250,13 +2331,20 @@ go_fetch(const char *url)
 		errx(1, "Unsupported URL scheme `%.*s'", (int)(p - url), url);
 
 	/*
+	 * Refer to previous urlinfo if provided. This makes relative
+	 * redirects work.
+	 */
+	if (use_relative(rui))
+	    return fetch_url(url, NULL, NULL, NULL, rui);
+
+	/*
 	 * Try FTP URL-style and host:file arguments next.
 	 * If ftpproxy is set with an FTP URL, use fetch_url()
 	 * Otherwise, use fetch_ftp().
 	 */
 	proxyenv = getoptionvalue("ftp_proxy");
 	if (!EMPTYSTRING(proxyenv) && STRNEQUAL(url, FTP_URL))
-		return (fetch_url(url, NULL, NULL, NULL));
+		return (fetch_url(url, NULL, NULL, NULL, rui));
 
 	return (fetch_ftp(url));
 }
@@ -2299,7 +2387,7 @@ auto_fetch(int argc, char *argv[])
 		redirect_loop = 0;
 		if (!anonftp)
 			anonftp = 2;	/* Handle "automatic" transfers. */
-		rval = go_fetch(argv[argpos]);
+		rval = go_fetch(argv[argpos], NULL);
 		if (outfile != NULL && strcmp(outfile, "-") != 0
 		    && outfile[0] != '|') {
 			FREEPTR(outfile);
@@ -2338,7 +2426,7 @@ auto_put(int argc, char **argv, const ch
 	pathsep = NULL;
 	rval = 1;
 
-	DPRINTF("auto_put: target `%s'\n", uploadserver);
+	DPRINTF("%s: target `%s'\n", __func__, uploadserver);
 
 	path = ftp_strdup(uploadserver);
 	len = strlen(path);
@@ -2347,7 +2435,7 @@ auto_put(int argc, char **argv, const ch
 			 * make sure we always pass a directory to auto_fetch
 			 */
 		if (argc > 1) {		/* more than one file to upload */
-			len = strlen(uploadserver) + 2;	/* path + "/" + "\0" */
+			len = strlen(uploadserver) + 2; /* path + "/" + "\0" */
 			free(path);
 			path = (char *)ftp_malloc(len);
 			(void)strlcpy(path, uploadserver, len);
@@ -2371,7 +2459,7 @@ auto_put(int argc, char **argv, const ch
 			uargc++;
 		}
 	}
-	DPRINTF("auto_put: URL `%s' argv[2] `%s'\n",
+	DPRINTF("%s: URL `%s' argv[2] `%s'\n", __func__,
 	    path, STRorNULL(uargv[2]));
 
 			/* connect and cwd */

Index: othersrc/usr.bin/tnftp/src/ftp.1
diff -u othersrc/usr.bin/tnftp/src/ftp.1:1.18 othersrc/usr.bin/tnftp/src/ftp.1:1.19
--- othersrc/usr.bin/tnftp/src/ftp.1:1.18	Fri Aug 27 01:38:49 2021
+++ othersrc/usr.bin/tnftp/src/ftp.1	Sun Apr  9 00:56:07 2023
@@ -1,7 +1,7 @@
-.\" 	$NetBSD: ftp.1,v 1.18 2021/08/27 01:38:49 lukem Exp $
-.\" 	from	NetBSD: ftp.1,v 1.146 2021/04/25 09:09:55 lukem Exp
+.\" 	$NetBSD: ftp.1,v 1.19 2023/04/09 00:56:07 lukem Exp $
+.\" 	from	NetBSD: ftp.1,v 1.150 2023/02/25 17:37:09 uwe Exp
 .\"
-.\" Copyright (c) 1996-2021 The NetBSD Foundation, Inc.
+.\" Copyright (c) 1996-2023 The NetBSD Foundation, Inc.
 .\" All rights reserved.
 .\"
 .\" This code is derived from software contributed to The NetBSD Foundation
@@ -58,7 +58,7 @@
 .\"
 .\"	@(#)ftp.1	8.3 (Berkeley) 10/9/94
 .\"
-.Dd April 25, 2021
+.Dd February 25, 2023
 .Dt FTP 1
 .Os
 .Sh NAME
@@ -78,9 +78,9 @@
 .Oo
 .Fl T Xo
 .Sm off
-.Ar dir ,
+.Ar dir Cm \&,
 .Ar max
-.Op , Ar inc
+.Op Cm \&, Ar inc
 .Sm on
 .Xc
 .Oc
@@ -240,11 +240,14 @@ will check the
 an account on the remote machine.
 If no entry exists,
 .Nm
-will prompt for the remote machine login name (default is the user
-identity on the local machine), and, if necessary, prompt for a password
+will prompt for the remote machine login name
+.Pq default is the user identity on the local machine ,
+and, if necessary, prompt for a password
 and an account with which to login.
 To override the auto-login for auto-fetch transfers, specify the
-username (and optionally, password) as appropriate.
+username
+.Pq and optionally, password
+as appropriate.
 .It Fl o Ar output
 When auto-fetching files, save the contents in
 .Ar output .
@@ -255,9 +258,9 @@ below.
 If
 .Ar output
 is not
-.Sq -
+.Sq Fl
 or doesn't start with
-.Sq \&| ,
+.Sq Cm \&| ,
 then only the first file specified will be retrieved into
 .Ar output ;
 all other files will be retrieved into the basename of their
@@ -287,7 +290,7 @@ Uses
 as the local IP address for all connections.
 .It Fl t
 Enables packet tracing.
-.It Fl T Ar direction Ns , Ns Ar maximum Ns Oo , Ns Ar increment Oc
+.It Fl T Ar direction Ns Cm \&, Ns Ar maximum\| Ns Oo Cm \&, Ns Ar increment Oc
 Set the maximum transfer rate for
 .Ar direction
 to
@@ -305,9 +308,10 @@ Upload files on the command line to
 where
 .Ar url
 is one of the
-.Sq Li ftp://
+.Ql ftp://
 URL types as supported by auto-fetch
-(with an optional target filename for single file uploads), and
+.Pq with an optional target filename for single file uploads ,
+and
 .Ar file
 is one or more local files to be uploaded.
 .It Fl V
@@ -321,10 +325,13 @@ Enable
 .Ic verbose
 and
 .Ic progress .
-This is the default if output is to a terminal (and in the case of
+This is the default if output is to a terminal
+.Po
+and in the case of
 .Ic progress ,
 .Nm
-is the foreground process).
+is the foreground process
+.Pc .
 Forces
 .Nm
 to show all responses from the remote server, as well
@@ -335,7 +342,7 @@ Set the size of the socket send and rece
 Refer to
 .Ic xferbuf
 for more information.
-.It Fl ?
+.It Fl \&?
 Display help to stdout, and exit.
 .El
 .Pp
@@ -357,7 +364,7 @@ is awaiting commands from the user the p
 is provided to the user.
 The following commands are recognized
 by
-.Nm ftp :
+.Nm :
 .Bl -tag -width Ic
 .It Ic \&! Op Ar command Op Ar args
 Invoke an interactive shell on the local machine.
@@ -455,7 +462,7 @@ sequence to conform with the
 single linefeed record
 delimiter.
 Records on
-.Pf non\- Ns Ux
+.Pf non\- Ux
 remote systems may contain single linefeeds;
 when an ascii type transfer is made, these linefeeds may be
 distinguished from a record delimiter only when
@@ -528,9 +535,8 @@ is executed again.
 A synonym for
 .Ic bye .
 .It Ic features
-Display what features the remote server supports (using the
-.Dv FEAT
-command).
+Display what features the remote server supports
+.Pq using the Dv FEAT No command .
 .It Ic fget Ar localfile
 Retrieve the files listed in
 .Ar localfile ,
@@ -542,7 +548,7 @@ to
 .Ar format .
 The default (and only supported)
 format is
-.Dq non-print .
+.Ql non-print .
 .It Ic ftp Ar host Op Ar port
 A synonym for
 .Ic open .
@@ -552,9 +558,11 @@ TIS FWTK and Gauntlet
 .Tn FTP
 proxies.
 This will not be permitted if the gate-ftp server hasn't been set
-(either explicitly by the user, or from the
+.Po
+either explicitly by the user, or from the
 .Ev FTPSERVER
-environment variable).
+environment variable
+.Pc .
 If
 .Ar host
 is given,
@@ -626,7 +634,7 @@ transferring a
 archive of the subtree (in binary mode).
 .It Ic hash Op Ar size
 Toggle hash-sign
-.Pq Sq #
+.Pq Ql #
 printing for each data block transferred.
 The size of a data block defaults to 1024 bytes.
 This can be changed by specifying
@@ -676,16 +684,24 @@ A synonym for
 Define a macro.
 Subsequent lines are stored as the macro
 .Ar macro-name  ;
-a null line (consecutive newline characters in a file or carriage
-returns from the terminal) terminates macro input mode.
+a null line
+.Po
+consecutive newline characters in a file or carriage
+returns from the terminal
+.Pc
+terminates macro input mode.
 There is a limit of 16 macros and 4096 total characters in all
 defined macros.
 Macro names can be a maximum of 8 characters.
 Macros are only applicable to the current session they are
-defined within (or if defined outside a session, to the session
+defined within
+.Po
+or if defined outside a session, to the session
 invoked with the next
 .Ic open
-command), and remain defined until a
+command
+.Pc ,
+and remain defined until a
 .Ic close
 command is executed.
 To invoke a macro, use the
@@ -751,9 +767,9 @@ and
 settings.
 Files are transferred into the local working directory,
 which can be changed with
-.Ql lcd directory ;
+.Ic lcd Ar directory ;
 new local directories can be created with
-.Sq Li "\&! mkdir directory" .
+.Ic \&! mkdir Ar directory .
 .It Ic mkdir Ar directory-name
 Make a directory on the remote machine.
 .It Ic mls Ar remote-files local-file
@@ -772,27 +788,28 @@ output.
 .It Ic mlsd Op Ar remote-path
 Display the contents of
 .Ar remote-path
-(which should default to the current directory if not given)
+.Pq which should default to the current directory if not given
 in a machine-parsable form, using
 .Dv MLSD .
 The format of display can be changed with
-.Sq Li "remopts mlst ..." .
+.Sq Ic remopts mlst Ar \&... .
 .It Ic mlst Op Ar remote-path
 Display the details about
 .Ar remote-path
-(which should default to the current directory if not given)
+.Pq which should default to the current directory if not given
 in a machine-parsable form, using
 .Dv MLST .
 The format of display can be changed with
-.Sq Li "remopts mlst ..." .
+.Sq Ic remopts mlst Ar \&... .
 .It Ic mode Ar mode-name
 Set the file transfer
 .Ic mode
 to
 .Ar mode-name .
-The default (and only supported)
+The default
+.Pq and only supported
 mode is
-.Dq stream .
+.Ql stream .
 .It Ic modtime Ar remote-file
 Show the last modification time of the file on the remote machine, in
 .Li RFC 2822
@@ -857,12 +874,14 @@ and
 .Ar outpattern .
 .Pp
 .Ar inpattern
-is a template for incoming filenames (which may have already been
-processed according to the
+is a template for incoming filenames
+.Po
+which may have already been processed according to the
 .Ic ntrans
 and
 .Ic case
-settings).
+settings
+.Pc .
 Variable templating is accomplished by including the
 sequences
 .Ql $1 ,
@@ -882,16 +901,16 @@ All other characters are treated literal
 variable values.
 For example, given
 .Ar inpattern
-.Sq Li $1.$2
+.Ql $1.$2
 and the remote file name
-.Sq Li mydata.data ,
+.Ql mydata.data ,
 .Ql $1
 would have the value
-.Sq Li mydata ,
+.Ql mydata ,
 and
 .Ql $2
 would have the value
-.Sq Li data .
+.Ql data .
 .Pp
 The
 .Ar outpattern
@@ -908,7 +927,9 @@ The sequence
 .Ql $0
 is replaced by the original filename.
 Additionally, the sequence
-.Dq Op Ar seq1 , Ar seq2
+.Sm off
+.Li \&[ Ar seq1 Li \&, Ar seq2 Li \&]
+.Sm on
 is replaced by
 .Ar seq1
 if
@@ -921,18 +942,18 @@ For example, the command
 .Pp
 would yield
 the output filename
-.Sq Li myfile.data
+.Ql myfile.data
 for input filenames
-.Sq Li myfile.data
+.Ql myfile.data
 and
-.Sq Li myfile.data.old ,
-.Sq Li myfile.file
+.Ql myfile.data.old ,
+.Ql myfile.file
 for the input filename
-.Sq Li myfile ,
+.Ql myfile ,
 and
-.Sq Li myfile.myfile
+.Ql myfile.myfile
 for the input filename
-.Sq Li "\&.myfile" .
+.Ql \&.myfile .
 Spaces may be included in
 .Ar outpattern  ,
 as in the example:
@@ -1031,13 +1052,15 @@ Passive mode is useful when using
 .Nm
 through a gateway router or host that controls the directionality of
 traffic.
-(Note that though
+.Po
+Note that though
 .Tn FTP
 servers are required to support the
 .Dv PASV
 command by
 .Li RFC 1123 ,
-some do not.)
+some do not.
+.Pc
 .It Ic pdir Op Ar remote-path
 Perform
 .Ic dir
@@ -1105,9 +1128,11 @@ and do not transfer the file.
 Answer
 .Sq yes
 to the current file, and turn off prompt mode
-(as is
-.Dq prompt off
-had been given).
+.Po
+as if
+.Ic prompt off
+had been given
+.Pc .
 .It Cm q
 Terminate the current operation.
 .It Cm y
@@ -1265,15 +1290,17 @@ server for
 .Ar command
 to
 .Ar command-options
-(whose absence is handled on a command-specific basis).
+.Pq whose absence is handled on a command-specific basis .
 Remote
 .Tn FTP
 commands known to support options include:
 .Dv MLST
-(used for
+.Po
+used for
 .Dv MLSD
 and
-.Dv MLST ) .
+.Dv MLST
+.Pc .
 .It Ic rename Op Ar from Op Ar to
 Rename the file
 .Ar from
@@ -1383,7 +1410,7 @@ and
 .Ar value
 are not given, display all of the options and their values.
 The currently supported options are:
-.Bl -tag -width "https_proxy" -offset indent
+.Bl -tag -width ".Cm sslnoverify" -offset indent
 .It Cm anonpass
 Defaults to
 .Ev $FTPANONPASS
@@ -1408,6 +1435,9 @@ Defaults to
 .It Cm rprompt
 Defaults to
 .Ev $FTPRPROMPT .
+.It Cm sslnoverify
+Defaults to
+.Ev $FTPSSLNOVERIFY .
 .El
 .It Ic site Op Ar arg ...
 The arguments specified are sent, verbatim, to the remote
@@ -1432,7 +1462,7 @@ to
 .Ar struct-name .
 The default (and only supported)
 structure is
-.Dq file .
+.Ql file .
 .It Ic sunique
 Toggle storing of files on remote machine under unique file names.
 The remote
@@ -1540,11 +1570,13 @@ or
 argument to force the setting appropriately.
 .Pp
 Commands which take a byte count as an argument
-(e.g.,
+.Po
+e.g.,
 .Ic hash ,
 .Ic rate ,
 and
-.Ic xferbuf )
+.Ic xferbuf
+.Pc
 support an optional suffix on the argument which changes the
 interpretation of the argument.
 Supported suffixes are:
@@ -1564,10 +1596,12 @@ If
 .Nm
 receives a
 .Dv SIGINFO
-(see the
+.Po
+see the
 .Cm status
 argument of
-.Xr stty 1 )
+.Xr stty 1
+.Pc
 or
 .Dv SIGQUIT
 signal whilst a transfer is in progress, the current transfer rate
@@ -1595,7 +1629,7 @@ contains a glob character and globbing i
 (see
 .Ic glob ) ,
 then the equivalent of
-.Sq Li mget path
+.Ic mget Ar path
 is performed.
 .Pp
 If the directory component of
@@ -1634,9 +1668,9 @@ In this case, use
 if supplied, otherwise prompt the user for one.
 .Pp
 If a suffix of
-.Sq Li \&;type=A
+.Ql \&;type=A
 or
-.Sq Li \&;type=I
+.Ql \&;type=I
 is supplied, then the transfer type will take place as
 ascii or binary (respectively).
 The default transfer type is binary.
@@ -1647,12 +1681,12 @@ In order to be compliant with
 interprets the
 .Ar path
 part of an
-.Sq Li ftp://
+.Ql ftp://
 auto-fetch URL as follows:
 .Bl -bullet
 .It
 The
-.Sq Li /
+.Ql /
 immediately after the
 .Ar host Ns Oo Li \&: Ns Ar port Oc
 is interpreted as a separator before the
@@ -1679,11 +1713,11 @@ command.
 .It
 Empty name components,
 which result from
-.Sq Li //
+.Ql //
 within the
 .Ar path ,
 or from an extra
-.Sq Li /
+.Ql /
 at the beginning of the
 .Ar path ,
 will cause the equivalent of a
@@ -1692,7 +1726,7 @@ command without a directory name.
 This is unlikely to be useful.
 .It
 Any
-.Sq Li \&% Ns Ar XX
+.Sq Cm \&% Ns Ar XX\^
 codes
 (per
 .Li RFC 3986 )
@@ -1708,13 +1742,15 @@ or
 .Ic get
 command.
 Some often-used codes are
-.Sq Li \&%2F
+.Ql \&%2F
 (which represents
-.Sq Li / )
+.Ql / )
 and
-.Sq Li \&%7E
-(which represents
-.Sq Li ~ ) .
+.Ql \&%7E
+.Po
+which represents
+.Ql ~
+.Pc .
 .El
 .Pp
 The above interpretation has the following consequences:
@@ -1727,20 +1763,21 @@ user.
 If the
 .Pa /
 directory is required, use a leading path of
-.Sq Li \&%2F .
-If a user's home directory is required (and the remote server supports
-the syntax), use a leading path of
-.Sq Li \&%7E Ns Ar user Ns Li / .
+.Ql \&%2F .
+If a user's home directory is required
+.Pq and the remote server supports the syntax ,
+use a leading path of
+.Ql \&%7E Ns Ar user Ns Li / .
 For example, to retrieve
 .Pa /etc/motd
 from
-.Sq Li localhost
+.Ql localhost
 as the user
-.Sq Li myname
+.Ql myname
 with the password
-.Sq Li mypass ,
+.Ql mypass ,
 use
-.Sq Li ftp://myname:mypass@localhost/%2fetc/motd
+.Ql ftp://myname:mypass@localhost/%2fetc/motd
 .It
 The exact
 .Ic cd
@@ -1748,32 +1785,46 @@ and
 .Ic get
 commands can be controlled by careful choice of
 where to use
-.Sq Li /
+.Ql /
 and where to use
-.Sq Li \&%2F
+.Ql \&%2F
 (or
-.Sq Li %2f ) .
+.Ql %2f ) .
 For example, the following URLs correspond to the
 equivalents of the indicated commands:
 .Bl -tag -width "ftp://host/%2Fdir1%2Fdir2%2Ffile";
-.It ftp://host/dir1/dir2/file
-.Dq "cd dir1" ,
-.Dq "cd dir2" ,
-.Dq "get file" .
-.It ftp://host/%2Fdir1/dir2/file
-.Dq "cd /dir1" ,
-.Dq "cd dir2" ,
-.Dq "get file" .
-.It ftp://host/dir1%2Fdir2/file
-.Dq "cd dir1/dir2" ,
-.Dq "get file" .
-.It ftp://host/%2Fdir1%2Fdir2/file
-.Dq "cd /dir1/dir2" ,
-.Dq "get file" .
-.It ftp://host/dir1%2Fdir2%2Ffile
-.Dq "get dir1/dir2/file" .
-.It ftp://host/%2Fdir1%2Fdir2%2Ffile
-.Dq "get /dir1/dir2/file" .
+.It Xo \" ftp://host/dir1/dir2/file
+.Sm off
+.Ic ftp:// Ar host
+.Ic / Ar dir1
+.Ic / Ar dir2
+.Ic / Ar file
+.Sm on
+.Xc
+.Ic cd Ar dir1 ,
+.Ic cd Ar dir2 ,
+.Ic get Ar file .
+.It Xo \" ftp://host/%2Fdir1/dir2/file
+.Sm off
+.Ic ftp:// Ar host
+.Ic /%2F Ar dir1
+.Ic / Ar dir2
+.Ic / Ar file
+.Sm on
+.Xc
+.Ic cd / Ns Ar dir1 ,
+.Ic cd Ar dir2 ,
+.Ic get Ar file .
+.It Xo \" ftp://host/dir1%2Fdir2/file
+.Sm off
+.Ic ftp:// Ar host
+.Ic / Ar dir1
+.Ic %2F Ar dir2
+.Ic / Ar file
+.Sm on
+.Xc
+.Ic cd Ar dir1 Ns Ic / Ns Ar dir2 ,
+.Ic get Ar file .
 .El
 .It
 You must have appropriate access permission for each of the
@@ -1914,7 +1965,7 @@ to enter a username and password to auth
 When specifying IPv6 numeric addresses in a URL, you need to
 surround the address in square brackets.
 E.g.:
-.Sq Li ftp://[::1]:21/ .
+.Ql ftp://[::1]:21/ .
 This is because colons are used in IPv6 numeric address as well as
 being the separator for the port number.
 .Sh ABORTING A FILE TRANSFER
@@ -1968,10 +2019,10 @@ with the argument supplied, and reads (w
 (stdin).
 If the shell command includes spaces, the argument
 must be quoted; e.g.
-.Sq Li \(dq|\~ls\~\-lt\(dq .
+.Ql \*q|\~ls\~\-lt\*q .
 A particularly
 useful example of this mechanism is:
-.Sq Li dir\~\(dq\(dq\~|more .
+.Ql dir\~\*q\*q\~|more .
 .It
 Failing the above checks, if globbing
 is enabled, local file names are expanded according to the rules
@@ -2313,6 +2364,8 @@ The value to send for the
 .Tn HTTP
 User-Agent
 header.
+.It Ev FTPSSLNOVERIFY
+Set to 1 to not verify SSL certificates.
 .It Ev HOME
 For default location of a
 .Pa .netrc
@@ -2360,7 +2413,7 @@ or
 .Ql / ) ,
 encode them with
 .Li RFC 3986
-.Sq Li \&% Ns Ar XX
+.Ql \&% Ns Ar XX\^
 encoding.
 .Pp
 Note that the use of a username and password in
@@ -2388,7 +2441,7 @@ for further notes about proxy use.
 A space or comma separated list of hosts (or domains) for which
 proxying is not to be used.
 Each entry may have an optional trailing
-.Sq Li \&: Ns Ar port ,
+.Ql \&: Ns Ar port ,
 which restricts
 the matching to connections to that port.
 .El

Index: othersrc/usr.bin/tnftp/src/ftp_var.h
diff -u othersrc/usr.bin/tnftp/src/ftp_var.h:1.13 othersrc/usr.bin/tnftp/src/ftp_var.h:1.14
--- othersrc/usr.bin/tnftp/src/ftp_var.h:1.13	Sat Jul  4 09:59:07 2020
+++ othersrc/usr.bin/tnftp/src/ftp_var.h	Sun Apr  9 00:56:07 2023
@@ -1,5 +1,5 @@
-/*	$NetBSD: ftp_var.h,v 1.13 2020/07/04 09:59:07 lukem Exp $	*/
-/*	from	NetBSD: ftp_var.h,v 1.85 2017/11/20 21:11:36 kre Exp	*/
+/*	$NetBSD: ftp_var.h,v 1.14 2023/04/09 00:56:07 lukem Exp $	*/
+/*	from	NetBSD: ftp_var.h,v 1.86 2021/09/10 21:52:17 rillig Exp	*/
 
 /*-
  * Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
@@ -346,7 +346,7 @@ extern	struct option	optiontab[];
 #define DPRINTF(...)	(void)0
 #define DWARN(...)	(void)0
 #else
-#define DWFTP(a)	do a; while (/*CONSTCOND*/0)
+#define DWFTP(a)	do a; while (0)
 #define DPRINTF(...)	DWFTP(if (ftp_debug) (void)fprintf(ttyout, __VA_ARGS__))
 #define DWARN(...)	DWFTP(if (ftp_debug) warn(__VA_ARGS__))
 #endif

Index: othersrc/usr.bin/tnftp/src/main.c
diff -u othersrc/usr.bin/tnftp/src/main.c:1.22 othersrc/usr.bin/tnftp/src/main.c:1.23
--- othersrc/usr.bin/tnftp/src/main.c:1.22	Sun Apr 25 07:50:37 2021
+++ othersrc/usr.bin/tnftp/src/main.c	Sun Apr  9 00:56:07 2023
@@ -1,8 +1,8 @@
-/*	$NetBSD: main.c,v 1.22 2021/04/25 07:50:37 lukem Exp $	*/
-/*	from	NetBSD: main.c,v 1.127 2020/07/18 03:00:37 lukem Exp	*/
+/*	$NetBSD: main.c,v 1.23 2023/04/09 00:56:07 lukem Exp $	*/
+/*	from	NetBSD: main.c,v 1.129 2023/02/25 12:07:25 mlelstv Exp	*/
 
 /*-
- * Copyright (c) 1996-2015 The NetBSD Foundation, Inc.
+ * Copyright (c) 1996-2023 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -103,7 +103,7 @@ __COPYRIGHT("@(#) Copyright (c) 1985, 19
 #if 0
 static char sccsid[] = "@(#)main.c	8.6 (Berkeley) 10/9/94";
 #else
-__RCSID(" NetBSD: main.c,v 1.127 2020/07/18 03:00:37 lukem Exp  ");
+__RCSID(" NetBSD: main.c,v 1.129 2023/02/25 12:07:25 mlelstv Exp  ");
 #endif
 #endif /* not lint */
 
@@ -276,7 +276,7 @@ main(int volatile argc, char **volatile 
 		}
 	}
 
-	while ((ch = getopt(argc, argv, "?46AadefginN:o:pP:q:r:Rs:tT:u:vVx:")) != -1) {
+	while ((ch = getopt(argc, argv, ":46AadefginN:o:pP:q:r:Rs:tT:u:vVx:")) != -1) {
 		switch (ch) {
 		case '4':
 			family = AF_INET;
@@ -429,6 +429,11 @@ main(int volatile argc, char **volatile 
 			if (optopt == '?') {
 				return usage_help();
 			}
+			warnx("-%c: unknown option", optopt);
+			return usage();
+
+		case ':':
+			warnx("-%c: missing argument", optopt);
 			return usage();
 
 		default:
@@ -516,6 +521,7 @@ main(int volatile argc, char **volatile 
 	setupoption("pager",		getenv("PAGER"),	DEFAULTPAGER);
 	setupoption("prompt",		getenv("FTPPROMPT"),	DEFAULTPROMPT);
 	setupoption("rprompt",		getenv("FTPRPROMPT"),	DEFAULTRPROMPT);
+	setupoption("sslnoverify",   	getenv("FTPSSLNOVERIFY"),	"");
 
 	free(anonpass);
 

Index: othersrc/usr.bin/tnftp/src/ssl.c
diff -u othersrc/usr.bin/tnftp/src/ssl.c:1.7 othersrc/usr.bin/tnftp/src/ssl.c:1.8
--- othersrc/usr.bin/tnftp/src/ssl.c:1.7	Fri Aug 27 01:48:01 2021
+++ othersrc/usr.bin/tnftp/src/ssl.c	Sun Apr  9 00:56:07 2023
@@ -1,10 +1,11 @@
-/*	$NetBSD: ssl.c,v 1.7 2021/08/27 01:48:01 lukem Exp $	*/
-/*	from	NetBSD: ssl.c,v 1.10 2021/06/03 10:23:33 lukem Exp	*/
+/*	$NetBSD: ssl.c,v 1.8 2023/04/09 00:56:07 lukem Exp $	*/
+/*	from	NetBSD: ssl.c,v 1.13 2023/02/25 12:07:25 mlelstv Exp	*/
 
 /*-
  * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
  * Copyright (c) 2008, 2010 Joerg Sonnenberger <jo...@netbsd.org>
  * Copyright (c) 2015 Thomas Klausner <w...@netbsd.org>
+ * Copyright (c) 2023 Michael van Elst <mlel...@netbsd.org>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -39,7 +40,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID(" NetBSD: ssl.c,v 1.10 2021/06/03 10:23:33 lukem Exp  ");
+__RCSID(" NetBSD: ssl.c,v 1.13 2023/02/25 12:07:25 mlelstv Exp  ");
 #endif
 
 #include <errno.h>
@@ -70,6 +71,11 @@ __RCSID(" NetBSD: ssl.c,v 1.10 2021/06/0
 
 #include "ssl.h"
 
+#include <stringlist.h>
+#include <histedit.h>
+#include <sys/poll.h>
+#include "extern.h"
+
 extern int quit_time, verbose, ftp_debug;
 extern FILE *ttyout;
 
@@ -594,7 +600,9 @@ fetch_start_ssl(int sock, const char *se
 {
 	SSL *ssl;
 	SSL_CTX *ctx;
+	X509_VERIFY_PARAM *param;
 	int ret, ssl_err;
+	int verify = !ftp_truthy("sslnoverify", getoptionvalue("sslnoverify"), 0);
 
 	/* Init the SSL library and context */
 	if (!SSL_library_init()){
@@ -606,6 +614,10 @@ fetch_start_ssl(int sock, const char *se
 
 	ctx = SSL_CTX_new(SSLv23_client_method());
 	SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+	if (verify) {
+		SSL_CTX_set_default_verify_paths(ctx);
+		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+	}
 
 	ssl = SSL_new(ctx);
 	if (ssl == NULL){
@@ -613,9 +625,25 @@ fetch_start_ssl(int sock, const char *se
 		SSL_CTX_free(ctx);
 		return NULL;
 	}
+
+	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;
+		}
+
+		/* Enable peer verification, (using the default callback) */
+		SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
+	}
+
 	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;
 	}
@@ -625,6 +653,7 @@ fetch_start_ssl(int sock, const char *se
 		    ssl_err != SSL_ERROR_WANT_WRITE) {
 			ERR_print_errors_fp(ttyout);
 			SSL_free(ssl);
+			SSL_CTX_free(ctx);
 			return NULL;
 		}
 	}

Index: othersrc/usr.bin/tnftp/src/util.c
diff -u othersrc/usr.bin/tnftp/src/util.c:1.25 othersrc/usr.bin/tnftp/src/util.c:1.26
--- othersrc/usr.bin/tnftp/src/util.c:1.25	Fri Aug 27 01:38:49 2021
+++ othersrc/usr.bin/tnftp/src/util.c	Sun Apr  9 00:56:07 2023
@@ -1,8 +1,8 @@
-/*	$NetBSD: util.c,v 1.25 2021/08/27 01:38:49 lukem Exp $	*/
-/*	from	NetBSD: util.c,v 1.162 2021/04/25 08:26:35 lukem Exp	*/
+/*	$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	*/
 
 /*-
- * Copyright (c) 1997-2020 The NetBSD Foundation, Inc.
+ * Copyright (c) 1997-2023 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -69,7 +69,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID(" NetBSD: util.c,v 1.162 2021/04/25 08:26:35 lukem Exp  ");
+__RCSID(" NetBSD: util.c,v 1.166 2023/02/25 12:07:25 mlelstv Exp  ");
 #endif /* not lint */
 
 /*
@@ -178,7 +178,7 @@ parse_feat(const char *fline)
 			 * work-around broken ProFTPd servers that can't
 			 * even obey RFC 2389.
 			 */
-	while (*fline && isspace((int)*fline))
+	while (*fline && isspace((unsigned char)*fline))
 		fline++;
 
 	if (strcasecmp(fline, "MDTM") == 0)
@@ -216,7 +216,7 @@ getremoteinfo(void)
 			    os_len, reply_string + 4);
 		}
 		/*
-		 * Decide whether we should default to bninary.
+		 * Decide whether we should default to binary.
 		 * Traditionally checked for "215 UNIX Type: L8", but
 		 * some printers report "Linux" ! so be more forgiving.
 		 * In reality we probably almost never want text any more.
@@ -627,7 +627,7 @@ remglob(char *argv[], int doswitch, cons
  * return value. Can't control multiple values being expanded from the
  * expression, we return only the first.
  * Returns NULL on error, or a pointer to a buffer containing the filename
- * that's the caller's responsiblity to free(3) when finished with.
+ * that's the caller's responsibility to free(3) when finished with.
  */
 char *
 globulize(const char *pattern)
@@ -1564,6 +1564,26 @@ ftp_poll(struct pollfd *fds, int nfds, i
 #endif
 }
 
+/*
+ * Evaluate a "boolean" string, accept only "1" as true and "0" as false
+ * Anything else returns the default value.
+ * Warn about an invalid value that isn't empty.
+ */
+int
+ftp_truthy(const char *name, const char *str, int defvalue)
+{
+
+	if (strcmp(str, "1") == 0)
+		return 1;
+	else if (strcmp(str, "0") == 0)
+		return 0;
+
+	if (*str)
+		warn("Option %s must be boolean (1 or 0)\n", name);
+
+	return defvalue;
+}
+
 #ifndef SMALL
 /*
  * malloc() with inbuilt error checking

Index: othersrc/usr.bin/tnftp/src/version.h
diff -u othersrc/usr.bin/tnftp/src/version.h:1.10 othersrc/usr.bin/tnftp/src/version.h:1.11
--- othersrc/usr.bin/tnftp/src/version.h:1.10	Fri Aug 27 01:38:49 2021
+++ othersrc/usr.bin/tnftp/src/version.h	Sun Apr  9 00:56:07 2023
@@ -1,8 +1,8 @@
-/*	$NetBSD: version.h,v 1.10 2021/08/27 01:38:49 lukem Exp $	*/
-/*	from	NetBSD: version.h,v 1.94 2021/08/26 06:25:59 lukem Exp	*/
+/*	$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	*/
 
 /*-
- * Copyright (c) 1999-2021 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999-2023 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -35,5 +35,5 @@
 #endif
 
 #ifndef FTP_VERSION
-#define	FTP_VERSION	"20210826"
+#define	FTP_VERSION	"20230225"
 #endif

Reply via email to