Catch up to current, requested by christos in ticket #1763:

usr.bin/ftp/Makefile                            up to 1.39
        usr.bin/ftp/cmds.c                              up to 1.141
        usr.bin/ftp/complete.c                          up to 1.47
        usr.bin/ftp/domacro.c                           up to 1.23
        usr.bin/ftp/extern.h                            up to 1.82
        usr.bin/ftp/fetch.c                             up to 1.235
        usr.bin/ftp/ftp.1                               up to 1.147
        usr.bin/ftp/ftp.c                               up to 1.174
        usr.bin/ftp/ftp_var.h                           up to 1.86
        usr.bin/ftp/main.c                              up to 1.128
        usr.bin/ftp/progressbar.c                       up to 1.24
        usr.bin/ftp/progressbar.h                       up to 1.9
        usr.bin/ftp/ssl.c                               up to 1.12
        usr.bin/ftp/ssl.h                               up to 1.5
        usr.bin/ftp/util.c                              up to 1.164
        usr.bin/ftp/version.h                           up to 1.94

ftp(1): validate address from PASV and LPSV response.
ftp(1): use raw write(2) instead of fwrite(3) to avoid stream
corruption because of the progress bar interrupts.
Fixes for PR 56219 and PR 55857.
PR 57003: Support relative redirects.
This commit is contained in:
martin 2022-09-12 17:08:13 +00:00
parent 5579b97d32
commit 71d7fc346c
16 changed files with 786 additions and 502 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.37.2.2 2022/09/12 15:05:21 martin Exp $
# $NetBSD: Makefile,v 1.37.2.3 2022/09/12 17:08:13 martin Exp $
# from: @(#)Makefile 8.2 (Berkeley) 4/3/94
.include <bsd.own.mk>
@ -8,6 +8,7 @@ USE_FORT?= yes # network client
PROG= ftp
SRCS= cmds.c cmdtab.c complete.c domacro.c fetch.c ftp.c main.c \
progressbar.c ruserpass.c util.c
SRCS+= ssl.c
# Uncomment the following to provide defaults for gate-ftp operation
#
@ -19,7 +20,6 @@ CPPFLAGS+=-DNO_EDITCOMPLETE -DNO_ABOUT -DNO_AUTH -DNO_HELP -DNO_STATUS -DNO_DEBU
LDADD+= -ledit -lterminfo
DPADD+= ${LIBEDIT} ${LIBTERMINFO}
CPPFLAGS+= -DWITH_SSL
SRCS+=ssl.c
LDADD+= -lssl -lcrypto
DPADD+= ${LIBSSL} ${LIBCRYPTO}
.endif
@ -31,4 +31,6 @@ CPPFLAGS+= -DINET6
cmds.o fetch.o: version.h
main.o: ftp_var.h
CWARNFLAGS.gcc+= ${GCC_NO_FORMAT_OVERFLOW}
.include <bsd.prog.mk>

View File

@ -1,7 +1,7 @@
/* $NetBSD: cmds.c,v 1.137.8.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: cmds.c,v 1.137.8.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
* Copyright (c) 1996-2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -96,7 +96,7 @@
#if 0
static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94";
#else
__RCSID("$NetBSD: cmds.c,v 1.137.8.2 2022/09/12 15:05:21 martin Exp $");
__RCSID("$NetBSD: cmds.c,v 1.137.8.3 2022/09/12 17:08:13 martin Exp $");
#endif
#endif /* not lint */
@ -1131,7 +1131,7 @@ setdebug(int argc, char *argv[])
options |= SO_DEBUG;
else
options &= ~SO_DEBUG;
fprintf(ttyout, "Debugging %s (ftp_debug=%d).\n", onoff(ftp_debug), ftp_debug);
fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(ftp_debug), ftp_debug);
code = ftp_debug > 0;
}
@ -1158,7 +1158,8 @@ cd(int argc, char *argv[])
}
if (r == COMPLETE) {
dirchange = 1;
updateremotecwd();
remotecwd[0] = '\0';
remcwdvalid = 0;
}
}
@ -1544,9 +1545,9 @@ pwd(int argc, char *argv[])
UPRINTF("usage: %s\n", argv[0]);
return;
}
if (! remotecwd[0])
if (!remcwdvalid || remotecwd[0] == '\0')
updateremotecwd();
if (! remotecwd[0])
if (remotecwd[0] == '\0')
fprintf(ttyout, "Unable to determine remote directory\n");
else {
fprintf(ttyout, "Remote directory: %s\n", remotecwd);
@ -1775,6 +1776,18 @@ quit(int argc, char *argv[])
exit(0);
}
void __dead
justquit(void)
{
quit(0, NULL);
/*
* quit is not __dead, but for our invocation it never will return,
* but some compilers are not smart enough to find this out.
*/
exit(0);
}
/*
* Terminate session, but don't exit.
* May be called with 0, NULL.
@ -2184,7 +2197,7 @@ LOOP:
}
break;
}
/* intentional drop through */
/* FALLTHROUGH */
default:
*cp2++ = *cp1;
break;
@ -2359,7 +2372,8 @@ cdup(int argc, char *argv[])
}
if (r == COMPLETE) {
dirchange = 1;
updateremotecwd();
remotecwd[0] = '\0';
remcwdvalid = 0;
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: complete.c,v 1.46.38.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: complete.c,v 1.46.38.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: complete.c,v 1.46.38.2 2022/09/12 15:05:21 martin Exp $");
__RCSID("$NetBSD: complete.c,v 1.46.38.3 2022/09/12 17:08:13 martin Exp $");
#endif /* not lint */
/*
@ -99,11 +99,10 @@ complete_ambiguous(char *word, int list, StringList *words)
}
if (!list) {
matchlen = 0;
lastmatch = words->sl_str[0];
matchlen = strlen(lastmatch);
for (i = 1 ; i < words->sl_cur ; i++) {
for (j = wordlen ; j < strlen(words->sl_str[i]); j++)
for (j = wordlen; j < strlen(words->sl_str[i]); j++)
if (lastmatch[j] != words->sl_str[i][j])
break;
if (j < matchlen)

View File

@ -1,4 +1,4 @@
/* $NetBSD: domacro.c,v 1.22.38.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: domacro.c,v 1.22.38.3 2022/09/12 17:08:13 martin Exp $ */
/*
* Copyright (c) 1985, 1993, 1994
@ -34,7 +34,7 @@
#if 0
static char sccsid[] = "@(#)domacro.c 8.3 (Berkeley) 4/2/94";
#else
__RCSID("$NetBSD: domacro.c,v 1.22.38.2 2022/09/12 15:05:21 martin Exp $");
__RCSID("$NetBSD: domacro.c,v 1.22.38.3 2022/09/12 17:08:13 martin Exp $");
#endif
#endif /* not lint */
@ -102,7 +102,7 @@ domacro(int argc, char *argv[])
}
break;
}
/* intentional drop through */
/* FALLTHROUGH */
default:
*cp2++ = *cp1;
break;

View File

@ -1,4 +1,4 @@
/* $NetBSD: extern.h,v 1.80.24.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: extern.h,v 1.80.24.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
@ -173,6 +173,7 @@ void pswitch(int);
void put(int, char **);
void pwd(int, char **);
void quit(int, char **);
void justquit(void) __dead;
void quote(int, char **);
void quote1(const char *, int, char **);
void recvrequest(const char *, const char *, const char *,
@ -242,7 +243,14 @@ 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);
#ifndef SMALL
void *ftp_malloc(size_t);
StringList *ftp_sl_init(void);
void ftp_sl_add(StringList *, char *);
char *ftp_strdup(const char *);
#else
#define ftp_malloc(a) malloc(a);
#define ftp_sl_init() sl_init()
#define ftp_sl_add(a, b) sl_add((a), (b))
#define ftp_strdup(a) strdup(a)
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: fetch.c,v 1.228.4.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: fetch.c,v 1.228.4.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1997-2015 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: fetch.c,v 1.228.4.2 2022/09/12 15:05:21 martin Exp $");
__RCSID("$NetBSD: fetch.c,v 1.228.4.3 2022/09/12 17:08:13 martin Exp $");
#endif /* not lint */
/*
@ -106,12 +106,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 *);
@ -138,6 +139,43 @@ static int redirect_loop;
((urltype) == HTTP_URL_T)
#endif
/**
* fwrite(3) replacement that just uses write(2). Many stdio implementations
* don't handle interrupts properly and corrupt the output. We are taking
* alarm interrupts because of the progress bar.
*
* Assumes `fp' is pristine with no prior I/O calls on it.
*/
static size_t
maxwrite(const void *buf, size_t size, size_t nmemb, FILE *fp)
{
const char *p = buf;
ssize_t nwr = 0;
ssize_t n;
int fd = fileno(fp);
size *= nmemb; /* assume no overflow */
while (size > 0) {
if ((n = write(fd, p, size)) == -1) {
switch (errno) {
case EINTR:
case EAGAIN:
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
case EWOULDBLOCK:
#endif
continue;
default:
return nwr;
}
}
p += n;
nwr += n;
size -= n;
}
return nwr;
}
/*
* Determine if token is the next word in buf (case insensitive).
* If so, advance buf past the token and any trailing LWS, and
@ -237,7 +275,7 @@ auth_url(const char *challenge, char **response, const struct authinfo *auth)
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'",
@ -299,7 +337,7 @@ auth_url(const char *challenge, char **response, const struct authinfo *auth)
*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);
@ -330,7 +368,7 @@ base64_encode(const unsigned char *clear, size_t len, unsigned char *encoded)
| ((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)
@ -363,6 +401,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):
@ -398,7 +472,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;
@ -409,29 +483,26 @@ parse_url(const char *url, const char *desc, struct urlinfo *ui,
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:
@ -440,6 +511,7 @@ parse_url(const char *url, const char *desc, struct urlinfo *ui,
return (-1);
}
if (*url == '\0')
return (0);
@ -504,7 +576,8 @@ parse_url(const char *url, const char *desc, struct urlinfo *ui,
#endif /* INET6 */
if ((cp = strchr(thost, ':')) != NULL)
*cp++ = '\0';
ui->host = thost;
if (*thost != '\0')
ui->host = thost;
/* look for [:port] */
if (cp != NULL) {
@ -519,7 +592,9 @@ parse_url(const char *url, const char *desc, struct urlinfo *ui,
}
ui->portnum = nport;
tport = cp;
}
} else
tport = get_port(ui);
if (tport != NULL)
ui->port = ftp_strdup(tport);
@ -530,8 +605,8 @@ parse_url(const char *url, const char *desc, struct urlinfo *ui,
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));
@ -544,7 +619,7 @@ sigjmp_buf httpabort;
static int
ftp_socket(const struct urlinfo *ui, void **ssl)
{
struct addrinfo hints, *res, *res0 = NULL;
struct addrinfo hints, *res, *res0 = NULL;
int error;
int s;
const char *host = ui->host;
@ -649,7 +724,7 @@ handle_noproxy(const char *host, in_port_t portnum)
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;
@ -681,7 +756,7 @@ handle_proxy(const char *url, const char *penv, struct urlinfo *ui,
}
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) ||
@ -852,9 +927,9 @@ print_connect(FETCH *fin, const struct urlinfo *ui)
}
#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)
@ -953,7 +1028,7 @@ parse_posinfo(const char **cp, struct posinfo *pi)
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;
@ -988,7 +1063,8 @@ do_auth(int hcode, const char *url, const char *penv, struct authinfo *wauth,
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);
}
@ -999,12 +1075,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;
@ -1119,18 +1195,19 @@ negotiate_connection(FETCH *fin, const char *url, const char *penv,
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:
@ -1195,7 +1272,7 @@ connectmethod(FETCH *fin, const char *url, const char *penv,
message = ftp_strdup(ep);
break;
}
for (;;) {
int len;
if (getresponseline(fin, buf, sizeof(buf), &len) != C_OK)
@ -1224,7 +1301,8 @@ connectmethod(FETCH *fin, const char *url, const char *penv,
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:
@ -1262,7 +1340,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;
@ -1271,18 +1350,18 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
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;
const char *cp;
char *ep;
char *auth;
char *volatile auth;
char *volatile savefile;
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 *);
@ -1295,7 +1374,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
DPRINTF("%s: `%s' proxyenv `%s'\n", __func__, url, STRorNULL(penv));
oldquit = oldalrm = oldint = oldpipe = NULL;
oldquit = oldalrm = oldint = oldpipe = SIG_ERR;
closefunc = NULL;
fin = NULL;
fout = NULL;
@ -1315,7 +1394,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
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);
@ -1331,7 +1410,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
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;
}
@ -1386,7 +1465,8 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
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;
@ -1460,7 +1540,8 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
#ifdef WITH_SSL
if (isproxy && oui.utype == HTTPS_URL_T) {
switch (connectmethod(fin, url, penv, &oui, &ui,
&wauth, &pauth, &auth, &hasleading, &rval)) {
&wauth, &pauth, __UNVOLATILE(&auth), &hasleading,
&rval)) {
case C_CLEANUP:
goto cleanup_fetch_url;
case C_IMPROPER:
@ -1496,7 +1577,8 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
alarmtimer(0);
switch (negotiate_connection(fin, url, penv, &pi,
&mtime, &wauth, &pauth, &rval, &ischunked, &auth)) {
&mtime, &wauth, &pauth, &rval, &ischunked,
__UNVOLATILE(&auth), &ui)) {
case C_OK:
break;
case C_CLEANUP:
@ -1570,9 +1652,9 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
bytes = 0;
hashbytes = mark;
if (oldalrm) {
if (oldalrm != SIG_ERR) {
(void)xsignal(SIGALRM, oldalrm);
oldalrm = NULL;
oldalrm = SIG_ERR;
}
progressmeter(-1);
@ -1603,7 +1685,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
}
/*
* 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.
*/
@ -1638,13 +1720,17 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
if (ischunked)
bufrem = MIN(chunksize, bufrem);
while (bufrem > 0) {
size_t nr = MIN((off_t)bufsize, bufrem);
flen = fetch_read(xferbuf, sizeof(char),
MIN((off_t)bufsize, bufrem), fin);
if (flen <= 0)
nr, fin);
if (flen == 0) {
if (fetch_error(fin))
goto chunkerror;
goto chunkdone;
}
bytes += flen;
bufrem -= flen;
if (fwrite(xferbuf, sizeof(char), flen, fout)
if (maxwrite(xferbuf, sizeof(char), flen, fout)
!= flen) {
warn("Writing `%s'", savefile);
goto cleanup_fetch_url;
@ -1692,7 +1778,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
} while (ischunked);
/* XXX: deal with optional trailer & CRLF here? */
chunkerror:
if (hash && !progress && bytes > 0) {
if (bytes < mark)
(void)putc('#', ttyout);
@ -1730,14 +1816,14 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
warnx("Improper response from `%s:%s'", ui.host, ui.port);
cleanup_fetch_url:
if (oldint)
if (oldint != SIG_ERR)
(void)xsignal(SIGINT, oldint);
if (oldpipe)
if (oldpipe != SIG_ERR)
(void)xsignal(SIGPIPE, oldpipe);
if (oldalrm)
if (oldalrm != SIG_ERR)
(void)xsignal(SIGALRM, oldalrm);
if (oldquit)
(void)xsignal(SIGQUIT, oldpipe);
if (oldquit != SIG_ERR)
(void)xsignal(SIGQUIT, oldquit);
if (fin != NULL)
fetch_close(fin);
else if (s != -1)
@ -1807,10 +1893,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;
@ -1819,7 +1905,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);
@ -1831,7 +1917,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)
@ -1873,12 +1960,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.
@ -1909,8 +1996,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));
@ -1959,7 +2046,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);
}
/*
@ -1981,7 +2068,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.
@ -2024,7 +2111,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"
@ -2041,7 +2128,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));
@ -2097,14 +2184,15 @@ fetch_ftp(const char *url)
mget(xargc, xargv);
interactive = ointeractive;
} else {
if (outfile == NULL) {
char *destfile = outfile;
if (destfile == NULL) {
cp = strrchr(file, '/'); /* find savefile */
if (cp != NULL)
outfile = cp + 1;
destfile = cp + 1;
else
outfile = file;
destfile = file;
}
xargv[2] = (char *)outfile;
xargv[2] = (char *)destfile;
xargv[3] = NULL;
xargc++;
if (restartautofetch)
@ -2135,7 +2223,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;
@ -2184,7 +2272,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://
@ -2198,14 +2286,21 @@ go_fetch(const char *url)
if ((p = strstr(url, "://")) != NULL && ! STRNEQUAL(url, FTP_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()
* Othewise, use fetch_ftp().
* 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));
}
@ -2248,10 +2343,11 @@ 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] != '|')
outfile = NULL;
&& outfile[0] != '|') {
FREEPTR(outfile);
}
if (rval > 0)
rval = argpos + 1;
}
@ -2286,7 +2382,7 @@ auto_put(int argc, char **argv, const char *uploadserver)
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);
@ -2295,7 +2391,7 @@ auto_put(int argc, char **argv, const char *uploadserver)
* 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);
@ -2319,7 +2415,7 @@ auto_put(int argc, char **argv, const char *uploadserver)
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 */

View File

@ -1,6 +1,6 @@
.\" $NetBSD: ftp.1,v 1.135.8.2 2022/09/12 15:05:21 martin Exp $
.\" $NetBSD: ftp.1,v 1.135.8.3 2022/09/12 17:08:13 martin Exp $
.\"
.\" Copyright (c) 1996-2015 The NetBSD Foundation, Inc.
.\" Copyright (c) 1996-2021 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
@ -57,7 +57,7 @@
.\"
.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94
.\"
.Dd April 24, 2015
.Dd August 29, 2022
.Dt FTP 1
.Os
.Sh NAME
@ -65,7 +65,7 @@
.Nd Internet file transfer program
.Sh SYNOPSIS
.Nm
.Op Fl 46AadefginpRtVv
.Op Fl 46AadefginpRtVv?
.Op Fl N Ar netrc
.Op Fl o Ar output
.Op Fl P Ar port
@ -84,12 +84,11 @@
.Xc
.Oc
.Ek
.Op Fl x Ar xferbufsize
.Op Fl x Ar xfersize
.Bk -words
.\" [[user@]host [port]]
.Oo
.Oo Ar user Ns Li \&@ Oc Ns Ar host
.Op Ar port
.Oo Ar user Ns Li \&@ Oc Ns Ar host Oo Ar port Oc
.Oc
.Ek
.Bk -words
@ -122,7 +121,7 @@
.Ar host Oo Li \&: Ar port Oc
.Li / Ar path
.Op Li /
.Op Li ;type= Ar X
.Op Li ;type= Ar type
.Oc
.Sm on
.Ek
@ -139,12 +138,24 @@
.Oc
.Sm on
.Ek
.Op Ar \&.\&.\&.
.Bk -words
.\" [https://[user[:password]@]host[:port]/path]
.Sm off
.Oo
.Li https://
.Oo Ar user
.Op Li \&: Ar password
.Li \&@ Oc
.Ar host Oo Li \&: Ar port Oc
.Li / Ar path
.Oc
.Sm on
.Ek
.Ar \&...
.Nm
.Bk -words
.Fl u Ar URL Ar file
.Fl u Ar url Ar
.Ek
.Op Ar \&.\&.\&.
.Sh DESCRIPTION
.Nm
is the user interface to the Internet standard File Transfer Protocol.
@ -173,10 +184,13 @@ Forces
.Nm
to only use IPv6 addresses.
.It Fl A
Force active mode ftp.
Force active mode
.Tn FTP .
By default,
.Nm
will try to use passive mode ftp and fall back to active mode
will try to use passive mode
.Tn FTP
and fall back to active mode
if passive is not supported by the server.
This option causes
.Nm
@ -284,12 +298,14 @@ bytes/second.
Refer to
.Ic rate
for more information.
.It Fl u Ar URL file Op \&.\&.\&.
.It Fl u Ar url Ar
Upload files on the command line to
.Ar URL
.Ar url
where
.Ar URL
is one of the ftp URL types as supported by auto-fetch
.Ar url
is one of the
.Sq Li ftp://
URL types as supported by auto-fetch
(with an optional target filename for single file uploads), and
.Ar file
is one or more local files to be uploaded.
@ -312,12 +328,14 @@ Forces
.Nm
to show all responses from the remote server, as well
as report on data transfer statistics.
.It Fl x Ar xferbufsize
.It Fl x Ar xfersize
Set the size of the socket send and receive buffers to
.Ar xferbufsize .
.Ar xfersize .
Refer to
.Ic xferbuf
for more information.
.It Fl ?
Display help to stdout, and exit.
.El
.Pp
The client host with which
@ -334,7 +352,7 @@ from the user.
When
.Nm
is awaiting commands from the user the prompt
.Ql ftp\*[Gt]
.Ql ftp>
is provided to the user.
The following commands are recognized
by
@ -442,6 +460,16 @@ when an ascii type transfer is made, these linefeeds may be
distinguished from a record delimiter only when
.Ic \&cr
is off.
.It Ic debug Op Ar debug-value
Toggle debugging mode.
If an optional
.Ar debug-value
is specified it is used to set the debugging level.
When debugging is on,
.Nm
prints each command sent to the remote machine, preceded
by the string
.Ql \-\-> .
.It Ic delete Ar remote-file
Delete the file
.Ar remote-file
@ -477,18 +505,16 @@ Toggle command line editing, and context sensitive command and file
completion.
This is automatically enabled if input is from a terminal, and
disabled otherwise.
.It Ic epsv epsv4 epsv6
.It Ic epsv , epsv4 , epsv6
Toggle the use of the extended
.Dv EPSV
and
.Dv EPRT
commands on all IP, IPv4, and IPv6 connections respectively.
First try
.Dv EPSV /
.Dv EPRT ,
.Dv EPSV Ns \^/\^ Ns Dv EPRT ,
and then
.Dv PASV /
.Dv PORT .
.Dv PASV Ns \^/\^ Ns Dv PORT .
This is enabled by default.
If an extended command fails then this option will be temporarily
disabled for the duration of the current connection, or until
@ -519,19 +545,11 @@ format is
.It Ic ftp Ar host Op Ar port
A synonym for
.Ic open .
.It Ic ftp_debug Op Ar ftp_debug-value
Toggle debugging mode.
If an optional
.Ar ftp_debug-value
is specified it is used to set the debugging level.
When debugging is on,
.Nm
prints each command sent to the remote machine, preceded
by the string
.Ql \-\-\*[Gt] .
.It Ic gate Op Ar host Op Ar port
Toggle gate-ftp mode, which used to connect through the
TIS FWTK and Gauntlet ftp proxies.
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
.Ev FTPSERVER
@ -589,9 +607,11 @@ each remote file name is expanded
separately on the remote machine and the lists are not merged.
Expansion of a directory name is likely to be
different from expansion of the name of an ordinary file:
the exact result depends on the foreign operating system and ftp server,
the exact result depends on the foreign operating system and
.Tn FTP
server,
and can be previewed by doing
.Ql mls remote-files \-
.Sq Li mls remote-files \- .
Note:
.Ic mget ,
.Ic mput
@ -672,32 +692,32 @@ To invoke a macro, use the
command (see above).
.Pp
The macro processor interprets
.Sq $
.Ql $
and
.Sq \e
.Ql \e
as special characters.
A
.Sq $
.Ql $
followed by a number (or numbers) is replaced by the
corresponding argument on the macro invocation command line.
A
.Sq $
.Ql $
followed by an
.Sq i
.Ql i
signals the macro processor that the executing macro is to be
looped.
On the first pass
.Dq $i
.Ql $i
is replaced by the first argument on the macro invocation command
line, on the second pass it is replaced by the second argument,
and so on.
A
.Sq \e
.Ql \e
followed by any character is replaced by that character.
Use the
.Sq \e
.Ql \e
to prevent special treatment of the
.Sq $ .
.Ql $ .
.It Ic mdelete Op Ar remote-files
Delete the
.Ar remote-files
@ -732,7 +752,7 @@ Files are transferred into the local working directory,
which can be changed with
.Ql lcd directory ;
new local directories can be created with
.Ql "\&! mkdir directory" .
.Sq Li "\&! mkdir directory" .
.It Ic mkdir Ar directory-name
Make a directory on the remote machine.
.It Ic mls Ar remote-files local-file
@ -755,7 +775,7 @@ Display the contents of
in a machine-parsable form, using
.Dv MLSD .
The format of display can be changed with
.Sq "remopts mlst ..." .
.Sq Li "remopts mlst ..." .
.It Ic mlst Op Ar remote-path
Display the details about
.Ar remote-path
@ -763,7 +783,7 @@ Display the details about
in a machine-parsable form, using
.Dv MLST .
The format of display can be changed with
.Sq "remopts mlst ..." .
.Sq Li "remopts mlst ..." .
.It Ic mode Ar mode-name
Set the file transfer
.Ic mode
@ -809,7 +829,7 @@ If the file does not
exist on the current system, the remote file is considered
.Ic newer .
Otherwise, this command is identical to
.Ar get .
.Ic get .
.It Ic nlist Op Ar remote-path Op Ar local-file
A synonym for
.Ic ls .
@ -834,7 +854,8 @@ The mapping follows the pattern set by
.Ar inpattern
and
.Ar outpattern .
.Op Ar Inpattern
.Pp
.Ar inpattern
is a template for incoming filenames (which may have already been
processed according to the
.Ic ntrans
@ -843,16 +864,16 @@ and
settings).
Variable templating is accomplished by including the
sequences
.Dq $1 ,
.Dq $2 ,
\&...
.Dq $9
.Ql $1 ,
.Ql $2 ,
\&...\|,
.Ql $9
in
.Ar inpattern .
Use
.Sq \e
.Ql \e
to prevent this special treatment of the
.Sq $
.Ql $
character.
All other characters are treated literally, and are used to determine the
.Ic nmap
@ -860,53 +881,72 @@ All other characters are treated literally, and are used to determine the
variable values.
For example, given
.Ar inpattern
$1.$2 and the remote file name "mydata.data", $1 would have the value
"mydata", and $2 would have the value "data".
.Sq Li $1.$2
and the remote file name
.Sq Li mydata.data ,
.Ql $1
would have the value
.Sq Li mydata ,
and
.Ql $2
would have the value
.Sq Li data .
.Pp
The
.Ar outpattern
determines the resulting mapped filename.
The sequences
.Dq $1 ,
.Dq $2 ,
\&...
.Dq $9
.Ql $1 ,
.Ql $2 ,
\&...\|,
.Ql $9
are replaced by any value resulting from the
.Ar inpattern
template.
The sequence
.Dq $0
.Ql $0
is replaced by the original filename.
Additionally, the sequence
.Dq Op Ar seq1 , Ar seq2
is replaced by
.Op Ar seq1
.Ar seq1
if
.Ar seq1
is not a null string; otherwise it is replaced by
.Ar seq2 .
For example, the command
.Pp
.Bd -literal -offset indent -compact
nmap $1.$2.$3 [$1,$2].[$2,file]
.Ed
.Dl nmap $1.$2.$3 [$1,$2].[$2,file]
.Pp
would yield
the output filename "myfile.data" for input filenames "myfile.data" and
"myfile.data.old", "myfile.file" for the input filename "myfile", and
"myfile.myfile" for the input filename ".myfile".
the output filename
.Sq Li myfile.data
for input filenames
.Sq Li myfile.data
and
.Sq Li myfile.data.old ,
.Sq Li myfile.file
for the input filename
.Sq Li myfile ,
and
.Sq Li myfile.myfile
for the input filename
.Sq Li "\&.myfile" .
Spaces may be included in
.Ar outpattern ,
as in the example:
.Dl nmap $1 sed "s/ *$//" \*[Gt] $1
.Pp
.Dl nmap $1 sed "s/ *$//" > $1
.Pp
Use the
.Sq \e
.Ql \e
character to prevent special treatment
of the
.Sq $ ,
.Sq \&[ ,
.Sq \&] ,
.Ql $ ,
.Ql \&[ ,
.Ql \&] ,
and
.Sq \&,
.Ql \&,
characters.
.It Ic ntrans Op Ar inchars Op Ar outchars
Set or unset the filename character translation mechanism.
@ -1027,7 +1067,7 @@ The progress bar will be disabled for a transfer that has
as
.Sq Fl
or a command that starts with
.Sq \&| .
.Ql \&| .
Refer to
.Sx FILE NAMING CONVENTIONS
for more information.
@ -1081,7 +1121,9 @@ Any other response will answer
.Sq yes
to the current file.
.It Ic proxy Ar ftp-command
Execute an ftp command on a secondary control connection.
Execute an
.Tn FTP
command on a secondary control connection.
This command allows simultaneous connection to two remote
.Tn FTP
servers for transferring files between the two servers.
@ -1090,11 +1132,13 @@ The first
command should be an
.Ic open ,
to establish the secondary control connection.
Enter the command "proxy ?" to see other
Enter the command
.Sq Li "proxy ?"
to see other
.Tn FTP
commands executable on the secondary connection.
The following commands behave differently when prefaced by
.Ic proxy :
.Ic proxy\^ :
.Ic open
will not define new macros during the auto-login process,
.Ic close
@ -1139,7 +1183,7 @@ machine.
.It Ic quit
A synonym for
.Ic bye .
.It Ic quote Ar arg1 arg2 ...
.It Ic quote Op Ar arg ...
The arguments specified are sent, verbatim, to the remote
.Tn FTP
server.
@ -1153,7 +1197,7 @@ is 0, disable the throttle.
.Pp
.Ar direction
may be one of:
.Bl -tag -width "all" -offset indent -compact
.Bl -tag -width ".Cm all" -offset indent -compact
.It Cm all
Both directions.
.It Cm get
@ -1166,7 +1210,7 @@ Outgoing transfers.
can be modified on the fly by
.Ar increment
bytes (default: 1024) each time a given signal is received:
.Bl -tag -width "SIGUSR1" -offset indent
.Bl -tag -width ".Dv SIGUSR1" -offset indent
.It Dv SIGUSR1
Increment
.Ar maximum
@ -1224,7 +1268,7 @@ to
Remote
.Tn FTP
commands known to support options include:
.Sq MLST
.Dv MLST
(used for
.Dv MLSD
and
@ -1277,10 +1321,16 @@ local filename for a
.Ic get
or
.Ic mget
command, a ".1" is appended to the name.
command, a
.Ql \&.1
is appended to the name.
If the resulting name matches another existing file,
a ".2" is appended to the original name.
If this process continues up to ".99", an error
a
.Ql \&.2
is appended to the original name.
If this process continues up to
.Ql .99 ,
an error
message is printed, and the transfer does not take place.
The generated unique filename will be reported.
Note that
@ -1358,7 +1408,7 @@ Defaults to
Defaults to
.Ev $FTPRPROMPT .
.El
.It Ic site Ar arg1 arg2 ...
.It Ic site Op Ar arg ...
The arguments specified are sent, verbatim, to the remote
.Tn FTP
server as a
@ -1479,7 +1529,7 @@ A synonym for
.Pp
Command arguments which have embedded spaces may be quoted with
quote
.Sq \&"
.Ql \&\(dq
marks.
.Pp
Commands which toggle settings can take an explicit
@ -1514,7 +1564,7 @@ If
receives a
.Dv SIGINFO
(see the
.Dq status
.Cm status
argument of
.Xr stty 1 )
or
@ -1544,7 +1594,7 @@ contains a glob character and globbing is enabled,
(see
.Ic glob ) ,
then the equivalent of
.Ql mget path
.Sq Li mget path
is performed.
.Pp
If the directory component of
@ -1557,10 +1607,10 @@ of
in the current directory.
Otherwise, the full remote name is used as the local name,
relative to the local root directory.
.\" ftp://[user[:password]@]host[:port]/path[/][;type=X]
.\" ftp://[user[:password]@]host[:port]/path[/][;type=type]
.It Li ftp:// Ns Oo Ar user Ns Oo Ns Li \&: Ns Ar password Oc Ns Li \&@ Oc \
Ns Ar host Ns Oo Li \&: Ns Ar port Oc Ns Li / Ns Ar path Ns Oo Li / Oc \
Ns Oo Li ;type= Ns Ar X Oc
Ns Oo Li ;type= Ns Ar type Oc
An
.Tn FTP
URL, retrieved using the
@ -1583,9 +1633,9 @@ In this case, use
if supplied, otherwise prompt the user for one.
.Pp
If a suffix of
.Sq ;type=A
.Sq Li \&;type=A
or
.Sq ;type=I
.Sq Li \&;type=I
is supplied, then the transfer type will take place as
ascii or binary (respectively).
The default transfer type is binary.
@ -1596,7 +1646,7 @@ In order to be compliant with
interprets the
.Ar path
part of an
.Dq ftp://
.Sq Li ftp://
auto-fetch URL as follows:
.Bl -bullet
.It
@ -1676,20 +1726,20 @@ user.
If the
.Pa /
directory is required, use a leading path of
.Dq %2F .
.Sq Li \&%2F .
If a user's home directory is required (and the remote server supports
the syntax), use a leading path of
.Dq %7Euser/ .
.Sq Li \&%7E Ns Ar user Ns Li / .
For example, to retrieve
.Pa /etc/motd
from
.Sq localhost
.Sq Li localhost
as the user
.Sq myname
.Sq Li myname
with the password
.Sq mypass ,
.Sq Li mypass ,
use
.Dq ftp://myname:mypass@localhost/%2fetc/motd
.Sq Li ftp://myname:mypass@localhost/%2fetc/motd
.It
The exact
.Ic cd
@ -1697,11 +1747,11 @@ and
.Ic get
commands can be controlled by careful choice of
where to use
.Sq /
.Sq Li /
and where to use
.Sq %2F
.Sq Li \&%2F
(or
.Sq %2f ) .
.Sq Li %2f ) .
For example, the following URLs correspond to the
equivalents of the indicated commands:
.Bl -tag -width "ftp://host/%2Fdir1%2Fdir2%2Ffile"
@ -1748,9 +1798,9 @@ If
authorization is required to retrieve
.Ar path ,
and
.Sq user
.Ar user
(and optionally
.Sq password )
.Ar password\^ )
is in the URL, use them for the first attempt to authenticate.
.\" https://[user[:password]@]host[:port]/path
.It Li https:// Ns Oo Ar user Ns Oo Li \&: Ns Ar password Oc Ns Li \&@ Oc \
@ -1770,9 +1820,9 @@ If
authorization is required to retrieve
.Ar path ,
and
.Sq user
.Ar user
(and optionally
.Sq password )
.Ar password\^ )
is in the URL, use them for the first attempt to authenticate.
There is currently no certificate validation and verification.
.\" file:///path
@ -1815,7 +1865,7 @@ is recommended, to avoid writing to unexpected file names.
If a classic format or an
.Tn FTP
URL format has a trailing
.Sq /
.Ql /
or an empty
.Ar path
component, then
@ -1847,9 +1897,9 @@ proxies will be restarted.
For
.Tn FTP ,
this is implemented by using
.Nm reget
.Ic reget
instead of
.Nm get .
.Ic get .
For
.Tn HTTP ,
this is implemented by using the
@ -1863,7 +1913,7 @@ to enter a username and password to authenticate with.
When specifying IPv6 numeric addresses in a URL, you need to
surround the address in square brackets.
E.g.:
.Dq ftp://[::1]:21/ .
.Sq Li 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
@ -1886,7 +1936,9 @@ sending the requested file.
.Pp
If the terminal interrupt key sequence is used whilst
.Nm
is awaiting a reply from the remote server for the ABOR processing,
is awaiting a reply from the remote server for the
.Dv ABOR
processing,
then the connection will be closed.
This is different from the traditional behaviour (which ignores the
terminal interrupt during this phase), but is considered more useful.
@ -1899,13 +1951,13 @@ commands are processed according to the following rules.
If the file name
.Sq Fl
is specified, the
.Ar stdin
.Va stdin
(for reading) or
.Ar stdout
.Va stdout
(for writing) is used.
.It
If the first character of the file name is
.Sq \&| ,
.Ql \&| ,
the
remainder of the argument is interpreted as a shell command.
.Nm
@ -1915,13 +1967,12 @@ with the argument supplied, and reads (writes) from the stdout
(stdin).
If the shell command includes spaces, the argument
must be quoted; e.g.
.Dq Qq Li \&| ls\ \-lt .
.Sq Li \(dq|\~ls\~\-lt\(dq .
A particularly
useful example of this mechanism is:
.Dq Li dir \&"\&" \&|more .
.Sq Li dir\~\(dq\(dq\~|more .
.It
Failing the above checks, if
.Dq globbing
Failing the above checks, if globbing
is enabled, local file names are expanded according to the rules
used in the
.Xr csh 1 ;
@ -1932,7 +1983,7 @@ If the
.Nm
command expects a single local file (e.g.
.Ic put ) ,
only the first filename generated by the "globbing" operation is used.
only the first filename generated by the globbing operation is used.
.It
For
.Ic mget
@ -2133,7 +2184,7 @@ The
.Xr editline 3
library is configured with a
.Pa .editrc
file - refer to
file \(em refer to
.Xr editrc 5
for more information.
.Pp
@ -2150,7 +2201,7 @@ By default, this is bound to the TAB key.
By default,
.Nm
displays a command line prompt of
.Dq "ftp\*[Gt] "
.Sq Li ftp>\~
to the user.
This can be changed with the
.Ic "set prompt"
@ -2167,42 +2218,42 @@ information:
.It Li \&%/
The current remote working directory.
.\" %c[[0]n], %.[[0]n]
.It \&%c Ns Oo Oo Li 0 Oc Ns Ar n Oc , Ns Li \&%. Ns Oo Oo Li 0 Oc Ns Ar n Oc
.It Li \&%c Ns Oo Oo Li 0 Oc Ns Ar n Oc , Li \&%. Ns Oo Oo Li 0 Oc Ns Ar n Oc
The trailing component of the current remote working directory, or
.Em n
.Ar n
trailing components if a digit
.Em n
.Ar n
is given.
If
.Em n
.Ar n
begins with
.Sq 0 ,
.Ql 0 ,
the number of skipped components precede the trailing component(s) in
the format
.\" ``/<number>trailing''
.Do
.Sm off
.Li / Li \*[Lt] Va number Li \*[Gt]
.Va trailing
.Li / Li < Ar number Li >
.Ar trailing
.Sm on
.Dc
(for
.Sq \&%c )
.Ql \&%c )
or
.\" ``...trailing''
.Dq Li \&... Ns Va trailing
.Dq Li \&... Ns Ar trailing
(for
.Sq \&%. ) .
.Ql \&%. ) .
.It Li \&%M
The remote host name.
.It Li \&%m
The remote host name, up to the first
.Sq \&. .
The remote host name, up to the first dot
.Ql \&. .
.It Li \&%n
The remote user name.
.It Li \&%%
A single
.Sq % .
A single percent character
.Ql % .
.El
.Sh ENVIRONMENT
.Nm
@ -2213,7 +2264,7 @@ Password to send in an anonymous
.Tn FTP
transfer.
Defaults to
.Dq Li `whoami`@ .
.Dq Li \&\`whoami\`@ .
.It Ev FTPMODE
Overrides the default operation mode.
Support values are:
@ -2234,14 +2285,13 @@ only
.It Ev FTPPROMPT
Command-line prompt to use.
Defaults to
.Dq "ftp\*[Gt] " .
.Sq Li ftp>\~ .
Refer to
.Sx COMMAND LINE PROMPT
for more information.
.It Ev FTPRPROMPT
Command-line right side prompt to use.
Defaults to
.Dq "" .
Defaults to empty string.
Refer to
.Sx COMMAND LINE PROMPT
for more information.
@ -2254,9 +2304,9 @@ Port to use when connecting to gate-ftp server when
.Ic gate
is enabled.
Default is port returned by a
.Fn getservbyname
.Xr getservbyname 3
lookup of
.Dq ftpgate/tcp .
.Dq Li ftpgate/tcp .
.It Ev FTPUSERAGENT
The value to send for the
.Tn HTTP
@ -2270,6 +2320,8 @@ file, if one exists.
An alternate location of the
.Pa .netrc
file.
.It Ev NO_CERT_VERIFY
Don't verify SSL certificates.
.It Ev PAGER
Used by various commands to display files.
Defaults to
@ -2304,9 +2356,9 @@ If
.Dq unsafe
URL characters are required in the username or password
(for example
.Sq @
.Ql @
or
.Sq / ) ,
.Ql / ) ,
encode them with
.Li RFC 3986
.Sq Li \&% Ns Ar XX
@ -2323,10 +2375,22 @@ may be incompatible with other programs that use it
.Em NOTE :
this is not used for interactive sessions, only for command-line
fetches.
.It Ev https_proxy
URL of
.Tn HTTPS
proxy to use when making
.Tn HTTPS
URL requests.
.Pp
See
.Ev http_proxy
for further notes about proxy use.
.It Ev no_proxy
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 ":port", which restricts
Each entry may have an optional trailing
.Sq Li \&: Ns Ar port ,
which restricts
the matching to connections to that port.
.El
.Sh EXTENDED PASSIVE MODE AND FIREWALLS

View File

@ -1,7 +1,7 @@
/* $NetBSD: ftp.c,v 1.167.6.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: ftp.c,v 1.167.6.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
* Copyright (c) 1996-2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -92,7 +92,7 @@
#if 0
static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
#else
__RCSID("$NetBSD: ftp.c,v 1.167.6.2 2022/09/12 15:05:21 martin Exp $");
__RCSID("$NetBSD: ftp.c,v 1.167.6.3 2022/09/12 17:08:13 martin Exp $");
#endif
#endif /* not lint */
@ -280,6 +280,11 @@ hookup(const char *host, const char *port)
goto bad;
}
if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE,
(void *)&on, sizeof(on)) == -1) {
DWARN("setsockopt %s (ignored)", "SO_KEEPALIVE");
}
if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE,
(void *)&on, sizeof(on)) == -1) {
DWARN("setsockopt %s (ignored)", "SO_OOBINLINE");
@ -320,6 +325,17 @@ cmdtimeout(int notused)
errno = oerrno;
}
static int
issighandler(sigfunc func)
{
return (func != SIG_IGN &&
func != SIG_DFL &&
#ifdef SIG_HOLD
func != SIG_HOLD &&
#endif
func != SIG_ERR);
}
/*VARARGS*/
int
command(const char *fmt, ...)
@ -359,8 +375,9 @@ command(const char *fmt, ...)
(void)fflush(cout);
cpend = 1;
r = getreply(!strcmp(fmt, "QUIT"));
if (abrtflag && oldsigint != SIG_IGN)
if (abrtflag && issighandler(oldsigint)) {
(*oldsigint)(SIGINT);
}
(void)xsignal(SIGINT, oldsigint);
return (r);
}
@ -510,11 +527,14 @@ getreply(int expecteof)
(void)xsignal(SIGALRM, oldsigalrm);
if (code == 421 || originalcode == 421)
lostpeer(0);
if (abrtflag && oldsigint != cmdabort && oldsigint != SIG_IGN)
if (abrtflag && oldsigint != cmdabort &&
issighandler(oldsigint)) {
(*oldsigint)(SIGINT);
}
if (timeoutflag && oldsigalrm != cmdtimeout &&
oldsigalrm != SIG_IGN)
issighandler(oldsigalrm)) {
(*oldsigalrm)(SIGINT);
}
return (n - '0');
}
}
@ -578,7 +598,7 @@ abortxfer(int notused)
/*
* Read data from infd & write to outfd, using buf/bufsize as the temporary
* buffer, dealing with short writes.
* buffer, dealing with short reads or writes.
* If rate_limit != 0, rate-limit the transfer.
* If hash_interval != 0, fputc('c', ttyout) every hash_interval bytes.
* Updates global variables: bytes.
@ -612,15 +632,25 @@ copy_bytes(int infd, int outfd, char *buf, size_t bufsize,
bufrem = bufchunk;
while (bufrem > 0) {
inc = read(infd, buf, MIN((off_t)bufsize, bufrem));
if (inc <= 0)
if (inc < 0) {
if (errno == EINTR || errno == EAGAIN) {
continue;
}
goto copy_done;
} else if (inc == 0) {
goto copy_done;
}
bytes += inc;
bufrem -= inc;
bufp = buf;
while (inc > 0) {
outc = write(outfd, bufp, inc);
if (outc < 0)
if (outc < 0) {
if (errno == EINTR || errno == EAGAIN) {
continue;
}
goto copy_done;
}
inc -= outc;
bufp += outc;
}
@ -670,7 +700,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
FILE *volatile dout;
int (*volatile closefunc)(FILE *);
sigfunc volatile oldintr;
sigfunc volatile oldintp;
sigfunc volatile oldpipe;
off_t volatile hashbytes;
int hash_interval;
const char *lmode;
@ -697,8 +727,8 @@ sendrequest(const char *cmd, const char *local, const char *remote,
if (curtype != type)
changetype(type, 0);
closefunc = NULL;
oldintr = NULL;
oldintp = NULL;
oldintr = SIG_ERR;
oldpipe = SIG_ERR;
lmode = "w";
if (sigsetjmp(xferabort, 1)) {
while (cpend)
@ -712,7 +742,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
fin = stdin;
progress = 0;
} else if (*local == '|') {
oldintp = xsignal(SIGPIPE, SIG_IGN);
oldpipe = xsignal(SIGPIPE, SIG_IGN);
fin = popen(local + 1, "r");
if (fin == NULL) {
warn("Can't execute `%s'", local + 1);
@ -786,7 +816,9 @@ sendrequest(const char *cmd, const char *local, const char *remote,
}
progressmeter(-1);
oldintp = xsignal(SIGPIPE, SIG_IGN);
if (oldpipe == SIG_ERR) {
oldpipe = xsignal(SIGPIPE, SIG_IGN);
}
hash_interval = (hash && (!progress || filesize < 0)) ? mark : 0;
switch (curtype) {
@ -855,7 +887,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
abort:
(void)xsignal(SIGINT, oldintr);
oldintr = NULL;
oldintr = SIG_ERR;
if (!cpend) {
code = -1;
goto cleanupsend;
@ -874,10 +906,10 @@ sendrequest(const char *cmd, const char *local, const char *remote,
ptransfer(0);
cleanupsend:
if (oldintr)
if (oldintr != SIG_ERR)
(void)xsignal(SIGINT, oldintr);
if (oldintp)
(void)xsignal(SIGPIPE, oldintp);
if (oldpipe != SIG_ERR)
(void)xsignal(SIGPIPE, oldpipe);
if (data >= 0) {
(void)close(data);
data = -1;
@ -899,7 +931,7 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
FILE *volatile din;
int (*volatile closefunc)(FILE *);
sigfunc volatile oldintr;
sigfunc volatile oldintp;
sigfunc volatile oldpipe;
int c, d;
int volatile is_retr;
int volatile tcrflag;
@ -935,8 +967,8 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
return;
}
closefunc = NULL;
oldintr = NULL;
oldintp = NULL;
oldintr = SIG_ERR;
oldpipe = SIG_ERR;
tcrflag = !crflag && is_retr;
if (sigsetjmp(xferabort, 1)) {
while (cpend)
@ -1017,7 +1049,7 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
progress = 0;
preserve = 0;
} else if (!ignorespecial && *local == '|') {
oldintp = xsignal(SIGPIPE, SIG_IGN);
oldpipe = xsignal(SIGPIPE, SIG_IGN);
fout = popen(local + 1, "w");
if (fout == NULL) {
warn("Can't execute `%s'", local+1);
@ -1183,10 +1215,10 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
ptransfer(0);
cleanuprecv:
if (oldintr)
if (oldintr != SIG_ERR)
(void)xsignal(SIGINT, oldintr);
if (oldintp)
(void)xsignal(SIGPIPE, oldintp);
if (oldpipe != SIG_ERR)
(void)xsignal(SIGPIPE, oldpipe);
if (data >= 0) {
(void)close(data);
data = -1;
@ -1349,13 +1381,11 @@ initconn(void)
if (data_addr.su_family != AF_INET) {
fputs(
"Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
error = 1;
goto bad;
}
if (code / 10 == 22 && code != 227) {
fputs("wrong server: return code must be 227\n",
ttyout);
error = 1;
goto bad;
}
error = sscanf(pasv, "%u,%u,%u,%u,%u,%u",
@ -1364,21 +1394,24 @@ initconn(void)
if (error != 6) {
fputs(
"Passive mode address scan failure. Shouldn't happen!\n", ttyout);
error = 1;
goto bad;
}
error = 0;
memset(&data_addr, 0, sizeof(data_addr));
data_addr.su_family = AF_INET;
data_addr.su_len = sizeof(struct sockaddr_in);
data_addr.si_su.su_sin.sin_addr.s_addr =
htonl(pack4(addr, 0));
data_addr.su_port = htons(pack2(port, 0));
if (data_addr.si_su.su_sin.sin_addr.s_addr !=
hisctladdr.si_su.su_sin.sin_addr.s_addr) {
fputs("Passive mode address mismatch.\n",
ttyout);
goto bad;
}
} else if (strcmp(pasvcmd, "LPSV") == 0) {
if (code / 10 == 22 && code != 228) {
fputs("wrong server: return code must be 228\n",
ttyout);
error = 1;
goto bad;
}
switch (data_addr.su_family) {
@ -1391,23 +1424,26 @@ initconn(void)
if (error != 9) {
fputs(
"Passive mode address scan failure. Shouldn't happen!\n", ttyout);
error = 1;
goto bad;
}
if (af != 4 || hal != 4 || pal != 2) {
fputs(
"Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
error = 1;
goto bad;
}
error = 0;
memset(&data_addr, 0, sizeof(data_addr));
data_addr.su_family = AF_INET;
data_addr.su_len = sizeof(struct sockaddr_in);
data_addr.si_su.su_sin.sin_addr.s_addr =
htonl(pack4(addr, 0));
data_addr.su_port = htons(pack2(port, 0));
if (data_addr.si_su.su_sin.sin_addr.s_addr !=
hisctladdr.si_su.su_sin.sin_addr.s_addr) {
fputs("Passive mode address mismatch.\n",
ttyout);
goto bad;
}
break;
#ifdef INET6
case AF_INET6:
@ -1423,17 +1459,14 @@ initconn(void)
if (error != 21) {
fputs(
"Passive mode address scan failure. Shouldn't happen!\n", ttyout);
error = 1;
goto bad;
}
if (af != 6 || hal != 16 || pal != 2) {
fputs(
"Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
error = 1;
goto bad;
}
error = 0;
memset(&data_addr, 0, sizeof(data_addr));
data_addr.su_family = AF_INET6;
data_addr.su_len = sizeof(struct sockaddr_in6);
@ -1445,10 +1478,19 @@ initconn(void)
}
}
data_addr.su_port = htons(pack2(port, 0));
if (memcmp(
&data_addr.si_su.su_sin6.sin6_addr,
&hisctladdr.si_su.su_sin6.sin6_addr,
sizeof(data_addr.si_su.su_sin6.sin6_addr))) {
fputs("Passive mode address mismatch.\n",
ttyout);
goto bad;
}
break;
#endif
default:
error = 1;
fputs("Unknown passive mode AF.\n", ttyout);
goto bad;
}
} else if (strcmp(pasvcmd, "EPSV") == 0) {
char delim[4];
@ -1457,20 +1499,17 @@ initconn(void)
if (code / 10 == 22 && code != 229) {
fputs("wrong server: return code must be 229\n",
ttyout);
error = 1;
goto bad;
}
if (sscanf(pasv, "%c%c%c%d%c", &delim[0],
&delim[1], &delim[2], &port[1],
&delim[3]) != 5) {
fputs("parse error!\n", ttyout);
error = 1;
goto bad;
}
if (delim[0] != delim[1] || delim[0] != delim[2]
|| delim[0] != delim[3]) {
fputs("parse error!\n", ttyout);
error = 1;
goto bad;
}
data_addr = hisctladdr;
@ -1553,8 +1592,8 @@ initconn(void)
result = COMPLETE + 1;
break;
}
/* FALLTHROUGH */
#ifdef INET6
/* FALLTHROUGH */
case AF_INET6:
if (!epsv6 || epsv6bad) {
result = COMPLETE + 1;
@ -1856,7 +1895,7 @@ proxtrans(const char *cmd, const char *local, const char *remote)
int volatile secndflag;
const char *volatile cmd2;
oldintr = NULL;
oldintr = SIG_ERR;
secndflag = 0;
if (strcmp(cmd, "RETR"))
cmd2 = "RETR";
@ -2047,7 +2086,7 @@ gunique(const char *local)
* needs to get back to a known state.
*/
static void
abort_squared(int dummy)
abort_squared(int signo)
{
char msgbuf[100];
size_t len;
@ -2057,7 +2096,7 @@ abort_squared(int dummy)
len = strlcpy(msgbuf, "\nremote abort aborted; closing connection.\n",
sizeof(msgbuf));
write(fileno(ttyout), msgbuf, len);
lostpeer(0);
lostpeer(signo);
siglongjmp(xferabort, 1);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ftp_var.h,v 1.84.8.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: ftp_var.h,v 1.84.8.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
@ -269,6 +269,7 @@ GLOBAL int unix_server; /* server is unix, can use binary for ascii */
GLOBAL int unix_proxy; /* proxy is unix, can use binary for ascii */
GLOBAL char localcwd[MAXPATHLEN]; /* local dir */
GLOBAL char remotecwd[MAXPATHLEN]; /* remote dir */
GLOBAL int remcwdvalid; /* remotecwd has been updated */
GLOBAL char *username; /* name of user logged in as. (dynamic) */
GLOBAL sa_family_t family; /* address family to use for connections */
@ -340,7 +341,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

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.123.8.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: main.c,v 1.123.8.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1996-2015 The NetBSD Foundation, Inc.
@ -98,7 +98,7 @@ __COPYRIGHT("@(#) Copyright (c) 1985, 1989, 1993, 1994\
#if 0
static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 10/9/94";
#else
__RCSID("$NetBSD: main.c,v 1.123.8.2 2022/09/12 15:05:21 martin Exp $");
__RCSID("$NetBSD: main.c,v 1.123.8.3 2022/09/12 17:08:13 martin Exp $");
#endif
#endif /* not lint */
@ -130,7 +130,8 @@ __RCSID("$NetBSD: main.c,v 1.123.8.2 2022/09/12 15:05:21 martin Exp $");
#define NO_PROXY "no_proxy" /* env var with list of non-proxied
* hosts, comma or space separated */
__dead static void usage(void);
static int usage(void);
static int usage_help(void);
static void setupoption(const char *, const char *, const char *);
int
@ -266,7 +267,7 @@ main(int volatile argc, char **volatile argv)
}
}
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;
@ -324,7 +325,7 @@ main(int volatile argc, char **volatile argv)
break;
case 'o':
outfile = optarg;
outfile = ftp_strdup(optarg);
if (strcmp(outfile, "-") == 0)
ttyout = stderr;
break;
@ -378,15 +379,15 @@ main(int volatile argc, char **volatile argv)
if (*cp == '\0') {
warnx("Bad throttle value `%s'",
optarg);
usage();
/* NOTREACHED */
return usage();
}
targv[targc++] = cp;
if (targc >= 5)
break;
}
if (parserate(targc, targv, 1) == -1)
usage();
if (parserate(targc, targv, 1) == -1) {
return usage();
}
free(oac);
break;
}
@ -415,8 +416,19 @@ main(int volatile argc, char **volatile argv)
rcvbuf_size = sndbuf_size;
break;
case '?':
if (optopt == '?') {
return usage_help();
}
warnx("-%c: unknown option", optopt);
return usage();
case ':':
warnx("-%c: missing argument", optopt);
return usage();
default:
usage();
errx(1, "unimplemented option -%c", ch);
}
}
/* set line buffering on ttyout */
@ -464,7 +476,6 @@ main(int volatile argc, char **volatile argv)
if (localhome == NULL && !EMPTYSTRING(pw->pw_dir))
localhome = ftp_strdup(pw->pw_dir);
localname = ftp_strdup(pw->pw_name);
anonuser = localname;
}
if (netrc[0] == '\0' && localhome != NULL) {
if (strlcpy(netrc, localhome, sizeof(netrc)) >= sizeof(netrc) ||
@ -573,8 +584,9 @@ main(int volatile argc, char **volatile argv)
retry_connect = 0; /* connected, stop hiding msgs */
}
}
if (isupload)
usage();
if (isupload) {
return usage();
}
#ifndef NO_EDITCOMPLETE
controlediting();
@ -661,7 +673,7 @@ cmdscanner(void)
case -2: /* error */
if (fromatty)
putc('\n', ttyout);
quit(0, NULL);
justquit();
/* NOTREACHED */
case -3: /* too long; try again */
fputs("Sorry, input line is too long.\n",
@ -683,7 +695,7 @@ cmdscanner(void)
if (buf == NULL || num == 0) {
if (fromatty)
putc('\n', ttyout);
quit(0, NULL);
justquit();
}
if (num >= sizeof(line)) {
fputs("Sorry, input line is too long.\n",
@ -837,7 +849,6 @@ slurpstring(void)
slrflag++;
INC_CHKCURSOR(stringbase);
return ((*sb == '!') ? bangstr : dollarstr);
/* NOTREACHED */
case 1:
slrflag++;
altarg = stringbase;
@ -966,7 +977,7 @@ help(int argc, char *argv[])
cmd = argv[0];
isusage = (strcmp(cmd, "usage") == 0);
if (argc == 0 || (isusage && argc == 1)) {
UPRINTF("usage: %s [command [...]]\n", cmd);
UPRINTF("usage: %s [command ...]\n", cmd);
return;
}
if (argc == 1) {
@ -1045,20 +1056,69 @@ setupoption(const char *name, const char *value, const char *defaultvalue)
set_option(name, value ? value : defaultvalue, 0);
}
void
static void
synopsis(FILE * stream)
{
const char * progname = getprogname();
fprintf(stream,
"usage: %s [-46AadefginpRtVv] [-N NETRC] [-o OUTPUT] [-P PORT] [-q QUITTIME]\n"
" [-r RETRY] [-s SRCADDR] [-T DIR,MAX[,INC]] [-x XFERSIZE]\n"
" [[USER@]HOST [PORT]]\n"
" [[USER@]HOST:[PATH][/]]\n"
" [file:///PATH]\n"
" [ftp://[USER[:PASSWORD]@]HOST[:PORT]/PATH[/][;type=TYPE]]\n"
" [http://[USER[:PASSWORD]@]HOST[:PORT]/PATH]\n"
#ifdef WITH_SSL
" [https://[USER[:PASSWORD]@]HOST[:PORT]/PATH]\n"
#endif
" ...\n"
" %s -u URL FILE ...\n"
" %s -?\n",
progname, progname, progname);
}
static int
usage_help(void)
{
synopsis(stdout);
#ifndef NO_USAGE
printf(
" -4 Only use IPv4 addresses\n"
" -6 Only use IPv6 addresses\n"
" -A Force active mode\n"
" -a Use anonymous login\n"
" -d Enable debugging\n"
" -e Disable command-line editing\n"
" -f Force cache reload for FTP or HTTP proxy transfers\n"
" -g Disable file name globbing\n"
" -i Disable interactive prompt during multiple file transfers\n"
" -N NETRC Use NETRC instead of ~/.netrc\n"
" -n Disable auto-login\n"
" -o OUTPUT Save auto-fetched files to OUTPUT\n"
" -P PORT Use port PORT\n"
" -p Force passive mode\n"
" -q QUITTIME Quit if connection stalls for QUITTIME seconds\n"
" -R Restart non-proxy auto-fetch\n"
" -r RETRY Retry failed connection attempts after RETRY seconds\n"
" -s SRCADDR Use source address SRCADDR\n"
" -t Enable packet tracing\n"
" -T DIR,MAX[,INC]\n"
" Set maximum transfer rate for direction DIR to MAX bytes/s,\n"
" with optional increment INC bytes/s\n"
" -u URL URL to upload file arguments to\n"
" -V Disable verbose and progress\n"
" -v Enable verbose and progress\n"
" -x XFERSIZE Set socket send and receive size to XFERSIZE\n"
" -? Display this help and exit\n"
);
#endif
return EXIT_SUCCESS;
}
static int
usage(void)
{
const char *progname = getprogname();
(void)fprintf(stderr,
"usage: %s [-46AadefginpRtVv] [-N netrc] [-o outfile] [-P port] [-q quittime]\n"
" [-r retry] [-s srcaddr] [-T dir,max[,inc]] [-x xferbufsize]\n"
" [[user@]host [port]] [host:path[/]] [file:///file]\n"
" [ftp://[user[:pass]@]host[:port]/path[/]]\n"
" [http://[user[:pass]@]host[:port]/path] [...]\n"
#ifdef WITH_SSL
" [https://[user[:pass]@]host[:port]/path] [...]\n"
#endif
" %s -u URL file [...]\n", progname, progname);
exit(1);
synopsis(stderr);
return EXIT_FAILURE;
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: progressbar.c,v 1.22.24.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: progressbar.c,v 1.22.24.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
* Copyright (c) 1997-2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -31,7 +31,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: progressbar.c,v 1.22.24.2 2022/09/12 15:05:21 martin Exp $");
__RCSID("$NetBSD: progressbar.c,v 1.22.24.3 2022/09/12 17:08:13 martin Exp $");
#endif /* not lint */
/*
@ -87,6 +87,7 @@ updateprogressmeter(int dummy)
/*
* List of order of magnitude suffixes, per IEC 60027-2.
*/
#if !defined(NO_PROGRESS) || !defined(STANDALONE_PROGRESS)
static const char * const suffixes[] = {
"", /* 2^0 (byte) */
"KiB", /* 2^10 Kibibyte */
@ -102,6 +103,7 @@ static const char * const suffixes[] = {
#endif
};
#define NSUFFIXES (int)(sizeof(suffixes) / sizeof(suffixes[0]))
#endif
/*
* Display a transfer progress bar if progress is non-zero.
@ -139,8 +141,10 @@ progressmeter(int flag)
* these appropriately.
*/
#endif
#if !defined(NO_PROGRESS) || !defined(STANDALONE_PROGRESS)
size_t len;
char buf[256]; /* workspace for progress bar */
#endif
#ifndef NO_PROGRESS
#define BAROVERHEAD 45 /* non `*' portion of progress bar */
/*
@ -189,7 +193,7 @@ progressmeter(int flag)
if (quit_time > 0 || progress) {
#endif /* !STANDALONE_PROGRESS */
if (flag == -1) {
(void)xsignal_restart(SIGALRM, updateprogressmeter, 1);
(void)xsignal(SIGALRM, updateprogressmeter);
alarmtimer(1); /* set alarm timer for 1 Hz */
} else if (flag == 1) {
alarmtimer(0);
@ -400,73 +404,21 @@ alarmtimer(int wait)
setitimer(ITIMER_REAL, &itv, NULL);
}
/*
* Install a POSIX signal handler, allowing the invoker to set whether
* the signal should be restartable or not
* Install a non-restartable POSIX signal handler.
*/
sigfunc
xsignal_restart(int sig, sigfunc func, int restartable)
xsignal(int sig, sigfunc func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
#if defined(SA_RESTART) /* 4.4BSD, Posix(?), SVR4 */
act.sa_flags = restartable ? SA_RESTART : 0;
#elif defined(SA_INTERRUPT) /* SunOS 4.x */
act.sa_flags = restartable ? 0 : SA_INTERRUPT;
#else
#error "system must have SA_RESTART or SA_INTERRUPT"
act.sa_flags = 0;
#if defined(SA_INTERRUPT) /* SunOS 4.x */
act.sa_flags = SA_INTERRUPT;
#endif
if (sigaction(sig, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
}
/*
* Install a signal handler with the `restartable' flag set dependent upon
* which signal is being set. (This is a wrapper to xsignal_restart())
*/
sigfunc
xsignal(int sig, sigfunc func)
{
int restartable;
/*
* Some signals print output or change the state of the process.
* There should be restartable, so that reads and writes are
* not affected. Some signals should cause program flow to change;
* these signals should not be restartable, so that the system call
* will return with EINTR, and the program will go do something
* different. If the signal handler calls longjmp() or siglongjmp(),
* it doesn't matter if it's restartable.
*/
switch(sig) {
#ifdef SIGINFO
case SIGINFO:
#endif
case SIGQUIT:
case SIGUSR1:
case SIGUSR2:
case SIGWINCH:
restartable = 1;
break;
case SIGALRM:
case SIGINT:
case SIGPIPE:
restartable = 0;
break;
default:
/*
* This is unpleasant, but I don't know what would be better.
* Right now, this "can't happen"
*/
errx(1, "xsignal_restart: called with signal %d", sig);
}
return(xsignal_restart(sig, func, restartable));
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: progressbar.h,v 1.8.38.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: progressbar.h,v 1.8.38.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1996-2009 The NetBSD Foundation, Inc.
* Copyright (c) 1996-2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -68,7 +68,6 @@ int foregroundproc(void);
void alarmtimer(int);
void progressmeter(int);
sigfunc xsignal(int, sigfunc);
sigfunc xsignal_restart(int, sigfunc, int);
#ifndef STANDALONE_PROGRESS
void psummary(int);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ssl.c,v 1.5.8.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: ssl.c,v 1.5.8.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
@ -34,12 +34,17 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: ssl.c,v 1.5.8.2 2022/09/12 15:05:21 martin Exp $");
__RCSID("$NetBSD: ssl.c,v 1.5.8.3 2022/09/12 17:08:13 martin Exp $");
#endif
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/select.h>
@ -47,11 +52,14 @@ __RCSID("$NetBSD: ssl.c,v 1.5.8.2 2022/09/12 15:05:21 martin Exp $");
#include <netinet/tcp.h>
#include <netinet/in.h>
#ifdef WITH_SSL
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif
#include "ssl.h"
@ -74,7 +82,9 @@ struct fetch_connect {
int issock;
int iserr;
int iseof;
#ifdef WITH_SSL
SSL *ssl; /* SSL handle */
#endif
};
/*
@ -87,6 +97,7 @@ fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
struct timeval now, timeout, delta;
fd_set writefds;
ssize_t len, total;
int fd = conn->sd;
int r;
if (quit_time > 0) {
@ -97,8 +108,8 @@ fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
total = 0;
while (iovcnt > 0) {
while (quit_time > 0 && !FD_ISSET(conn->sd, &writefds)) {
FD_SET(conn->sd, &writefds);
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;
@ -111,7 +122,7 @@ fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
return -1;
}
errno = 0;
r = select(conn->sd + 1, NULL, &writefds, NULL, &delta);
r = select(fd + 1, NULL, &writefds, NULL, &delta);
if (r == -1) {
if (errno == EINTR)
continue;
@ -119,10 +130,12 @@ fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
}
}
errno = 0;
#ifdef WITH_SSL
if (conn->ssl != NULL)
len = SSL_write(conn->ssl, iov->iov_base, iov->iov_len);
else
len = writev(conn->sd, iov, iovcnt);
#endif
len = writev(fd, iov, iovcnt);
if (len == 0) {
/* we consider a short write a failure */
/* XXX perhaps we shouldn't in the SSL case */
@ -130,7 +143,7 @@ fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
return -1;
}
if (len < 0) {
if (errno == EINTR)
if (errno == EINTR || errno == EAGAIN)
continue;
return -1;
}
@ -148,11 +161,8 @@ fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
return total;
}
/*
* Write to a connection w/ timeout
*/
static int
fetch_write(struct fetch_connect *conn, const char *str, size_t len)
static ssize_t
fetch_write(const void *str, size_t len, struct fetch_connect *conn)
{
struct iovec iov[1];
@ -181,7 +191,7 @@ fetch_printf(struct fetch_connect *conn, const char *fmt, ...)
return -1;
}
r = fetch_write(conn, msg, len);
r = fetch_write(msg, len, conn);
free(msg);
return r;
}
@ -210,15 +220,16 @@ fetch_clearerr(struct fetch_connect *conn)
int
fetch_flush(struct fetch_connect *conn)
{
int v;
if (conn->issock) {
int fd = conn->sd;
int v;
#ifdef TCP_NOPUSH
v = 0;
setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v));
setsockopt(fd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v));
#endif
v = 1;
setsockopt(conn->sd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
}
return 0;
}
@ -271,44 +282,44 @@ fetch_fdopen(int sd, const char *fmode)
int
fetch_close(struct fetch_connect *conn)
{
int rv = 0;
if (conn == NULL)
return 0;
if (conn != NULL) {
fetch_flush(conn);
SSL_free(conn->ssl);
rv = close(conn->sd);
if (rv < 0) {
errno = rv;
rv = EOF;
}
free(conn->cache.buf);
free(conn->buf);
free(conn);
}
return rv;
fetch_flush(conn);
#ifdef WITH_SSL
SSL_free(conn->ssl);
#endif
close(conn->sd);
free(conn->cache.buf);
free(conn->buf);
free(conn);
return 0;
}
#define FETCH_WRITE_WAIT -3
#define FETCH_READ_WAIT -2
#define FETCH_READ_ERROR -1
#ifdef WITH_SSL
static ssize_t
fetch_ssl_read(SSL *ssl, void *buf, size_t len)
{
ssize_t rlen;
int ssl_err;
rlen = SSL_read(ssl, buf, len);
if (rlen < 0) {
ssl_err = SSL_get_error(ssl, rlen);
if (ssl_err == SSL_ERROR_WANT_READ ||
ssl_err == SSL_ERROR_WANT_WRITE) {
return FETCH_READ_WAIT;
}
if (rlen >= 0)
return rlen;
switch (SSL_get_error(ssl, rlen)) {
case SSL_ERROR_WANT_READ:
return FETCH_READ_WAIT;
case SSL_ERROR_WANT_WRITE:
return FETCH_WRITE_WAIT;
default:
ERR_print_errors_fp(ttyout);
return FETCH_READ_ERROR;
}
return rlen;
}
#endif /* WITH_SSL */
static ssize_t
fetch_nonssl_read(int sd, void *buf, size_t len)
@ -316,7 +327,7 @@ fetch_nonssl_read(int sd, void *buf, size_t len)
ssize_t rlen;
rlen = read(sd, buf, len);
if (rlen < 0) {
if (rlen == -1) {
if (errno == EAGAIN || errno == EINTR)
return FETCH_READ_WAIT;
return FETCH_READ_ERROR;
@ -347,14 +358,49 @@ fetch_cache_data(struct fetch_connect *conn, char *src, size_t nbytes)
return 0;
}
ssize_t
static int
fetch_wait(struct fetch_connect *conn, ssize_t rlen, struct timeval *timeout)
{
struct timeval now, delta;
int fd = conn->sd;
fd_set fds;
FD_ZERO(&fds);
while (!FD_ISSET(fd, &fds)) {
FD_SET(fd, &fds);
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);
}
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;
}
}
return 0;
}
size_t
fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
{
struct timeval now, timeout, delta;
fd_set readfds;
ssize_t rlen, total;
size_t len;
char *start, *buf;
struct timeval timeout;
if (quit_time > 0) {
gettimeofday(&timeout, NULL);
@ -402,40 +448,31 @@ fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
* In the non-SSL case, it may improve performance (very
* slightly) when reading small amounts of data.
*/
#ifdef WITH_SSL
if (conn->ssl != NULL)
rlen = fetch_ssl_read(conn->ssl, buf, len);
else
#endif
rlen = fetch_nonssl_read(conn->sd, buf, len);
if (rlen == 0) {
switch (rlen) {
case 0:
conn->iseof = 1;
return total;
case FETCH_READ_ERROR:
conn->iserr = errno;
if (errno == EINTR)
fetch_cache_data(conn, start, total);
return 0;
case FETCH_READ_WAIT:
case FETCH_WRITE_WAIT:
if (fetch_wait(conn, rlen, &timeout) == -1)
return 0;
break;
} else if (rlen > 0) {
default:
len -= rlen;
buf += rlen;
total += rlen;
continue;
} else if (rlen == FETCH_READ_ERROR) {
if (errno == EINTR)
fetch_cache_data(conn, start, total);
return -1;
}
FD_ZERO(&readfds);
while (!FD_ISSET(conn->sd, &readfds)) {
FD_SET(conn->sd, &readfds);
if (quit_time > 0) {
gettimeofday(&now, NULL);
if (!timercmp(&timeout, &now, >)) {
errno = ETIMEDOUT;
return -1;
}
timersub(&timeout, &now, &delta);
}
errno = 0;
if (select(conn->sd + 1, &readfds, NULL, NULL,
quit_time > 0 ? &delta : NULL) < 0) {
if (errno == EINTR)
continue;
return -1;
}
break;
}
}
return total;
@ -450,7 +487,7 @@ char *
fetch_getln(char *str, int size, struct fetch_connect *conn)
{
size_t tmpsize;
ssize_t len;
size_t len;
char c;
if (conn->buf == NULL) {
@ -473,13 +510,12 @@ fetch_getln(char *str, int size, struct fetch_connect *conn)
conn->buflen = 0;
do {
len = fetch_read(&c, sizeof(c), 1, conn);
if (len == -1) {
conn->iserr = 1;
return NULL;
}
if (len == 0) {
conn->iseof = 1;
break;
if (conn->iserr)
return NULL;
if (conn->iseof)
break;
abort();
}
conn->buf[conn->buflen++] = c;
if (conn->buflen == conn->bufsize) {
@ -531,8 +567,8 @@ fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen,
} else if (len == buflen - 1) { /* line too long */
while (1) {
char c;
ssize_t rlen = fetch_read(&c, sizeof(c), 1, conn);
if (rlen <= 0 || c == '\n')
size_t rlen = fetch_read(&c, sizeof(c), 1, conn);
if (rlen == 0 || c == '\n')
break;
}
if (errormsg)
@ -545,12 +581,15 @@ fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen,
return len;
}
#ifdef WITH_SSL
void *
fetch_start_ssl(int sock, const char *servername)
{
SSL *ssl;
SSL_CTX *ctx;
X509_VERIFY_PARAM *param;
int ret, ssl_err;
int verify = 0; // getenv("NO_CERT_VERIFY") == NULL;
/* Init the SSL library and context */
if (!SSL_library_init()){
@ -562,6 +601,10 @@ fetch_start_ssl(int sock, const char *servername)
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){
@ -569,6 +612,19 @@ fetch_start_ssl(int sock, const char *servername)
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");
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");
@ -605,10 +661,13 @@ fetch_start_ssl(int sock, const char *servername)
return ssl;
}
#endif /* WITH_SSL */
void
fetch_set_ssl(struct fetch_connect *conn, void *ssl)
{
#ifdef WITH_SSL
conn->ssl = ssl;
#endif
}

View File

@ -1,7 +1,7 @@
/* $NetBSD: ssl.h,v 1.3.8.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: ssl.h,v 1.3.8.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* Copyright (c) 2012-2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -25,7 +25,6 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef WITH_SSL
#define FETCH struct fetch_connect
struct fetch_connect;
@ -38,26 +37,8 @@ int fetch_flush(struct fetch_connect *);
struct fetch_connect *fetch_open(const char *, const char *);
struct fetch_connect *fetch_fdopen(int, const char *);
int fetch_close(struct fetch_connect *);
ssize_t fetch_read(void *, size_t, size_t, struct fetch_connect *);
size_t fetch_read(void *, size_t, size_t, struct fetch_connect *);
char *fetch_getln(char *, int, struct fetch_connect *);
int fetch_getline(struct fetch_connect *, char *, size_t, const char **);
void fetch_set_ssl(struct fetch_connect *, void *);
void *fetch_start_ssl(int, const char *);
#else /* !WITH_SSL */
#define FETCH FILE
#define fetch_printf fprintf
#define fetch_fileno fileno
#define fetch_error ferror
#define fetch_flush fflush
#define fetch_open fopen
#define fetch_fdopen fdopen
#define fetch_close fclose
#define fetch_read fread
#define fetch_getln fgets
#define fetch_getline get_line
#define fetch_set_ssl(a, b)
#endif /* !WITH_SSL */

View File

@ -1,7 +1,7 @@
/* $NetBSD: util.c,v 1.158.22.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: util.c,v 1.158.22.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
* Copyright (c) 1997-2020 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -64,7 +64,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: util.c,v 1.158.22.2 2022/09/12 15:05:21 martin Exp $");
__RCSID("$NetBSD: util.c,v 1.158.22.3 2022/09/12 17:08:13 martin Exp $");
#endif /* not lint */
/*
@ -171,7 +171,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)
@ -324,9 +324,10 @@ intr(int signo)
/*
* Signal handler for lost connections; cleanup various elements of
* the connection state, and call cleanuppeer() to finish it off.
* This function is not signal safe, so exit if called by a signal.
*/
void
lostpeer(int dummy)
lostpeer(int signo)
{
int oerrno = errno;
@ -356,6 +357,9 @@ lostpeer(int dummy)
proxflag = 0;
pswitch(0);
cleanuppeer();
if (signo) {
errx(1, "lostpeer due to signal %d", signo);
}
errno = oerrno;
}
@ -478,7 +482,8 @@ ftp_login(const char *host, const char *luser, const char *lpass)
}
}
updatelocalcwd();
updateremotecwd();
remotecwd[0] = '\0';
remcwdvalid = 0;
cleanup_ftp_login:
FREEPTR(fuser);
@ -615,7 +620,7 @@ remglob(char *argv[], int doswitch, const char **errbuf)
* 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)
@ -726,7 +731,7 @@ remotemodtime(const char *file, int noisy)
*frac++ = '\0';
if (strlen(timestr) == 15 && strncmp(timestr, "191", 3) == 0) {
/*
* XXX: Workaround for lame ftpd's that return
* XXX: Workaround for buggy ftp servers that return
* `19100' instead of `2000'
*/
fprintf(ttyout,
@ -835,6 +840,7 @@ updateremotecwd(void)
size_t i;
char *cp;
remcwdvalid = 1; /* whether it works or not, we are done */
overbose = verbose;
ocode = code;
if (ftp_debug == 0)
@ -1174,6 +1180,8 @@ formatbuf(char *buf, size_t len, const char *src)
case '/':
case '.':
case 'c':
if (connected && !remcwdvalid)
updateremotecwd();
p2 = connected ? remotecwd : "";
updirs = pdirs = 0;
@ -1487,6 +1495,7 @@ ftp_poll(struct pollfd *fds, int nfds, int timeout)
return poll(fds, nfds, timeout);
}
#ifndef SMALL
/*
* malloc() with inbuilt error checking
*/
@ -1541,3 +1550,4 @@ ftp_strdup(const char *str)
err(1, "Unable to allocate memory for string copy");
return (s);
}
#endif

View File

@ -1,7 +1,7 @@
/* $NetBSD: version.h,v 1.87.8.2 2022/09/12 15:05:21 martin Exp $ */
/* $NetBSD: version.h,v 1.87.8.3 2022/09/12 17:08:13 martin Exp $ */
/*-
* Copyright (c) 1999-2015 The NetBSD Foundation, Inc.
* Copyright (c) 1999-2021 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -34,5 +34,5 @@
#endif
#ifndef FTP_VERSION
#define FTP_VERSION "20150912"
#define FTP_VERSION "20210826"
#endif