NetBSD Problem Report #47920
From www@NetBSD.org Wed Jun 12 12:01:29 2013
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
(Client CN "mail.NetBSD.org", Issuer "Postmaster NetBSD.org" (verified OK))
by mollari.NetBSD.org (Postfix) with ESMTPS id ED8477069D
for <gnats-bugs@gnats.NetBSD.org>; Wed, 12 Jun 2013 12:01:29 +0000 (UTC)
Message-Id: <20130612120123.0D96D706B1@mollari.NetBSD.org>
Date: Wed, 12 Jun 2013 12:01:23 +0000 (UTC)
From: nonakap@gmail.com
Reply-To: nonakap@gmail.com
To: gnats-bugs@NetBSD.org
Subject: ftp(1): FTPS support
X-Send-Pr-Version: www-1.0
>Number: 47920
>Category: bin
>Synopsis: ftp(1): FTPS support
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: bin-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Wed Jun 12 12:05:00 +0000 2013
>Originator: NONAKA Kimihiro
>Release: 6.99.21
>Organization:
>Environment:
NetBSD koharu.myhome.local 6.99.21 NetBSD 6.99.21 (KOHARU) #1985: Thu Jun 6 22:05:15 JST 2013 nonaka@koharu.myhome.local:/usr/obj.amd64/sys/arch/amd64/compile/KOHARU amd64
>Description:
ftp(1): FTPS support
>How-To-Repeat:
>Fix:
Apply following patch.
diff --git a/extern.h b/extern.h
index e856ef4..41e899b 100644
--- a/extern.h
+++ b/extern.h
@@ -89,11 +89,13 @@
* SUCH DAMAGE.
*/
+#include "ssl.h"
+
struct sockaddr;
struct tm;
struct addrinfo;
-void abort_remote(FILE *);
+void abort_remote(FETCH *);
void account(int, char **);
void ai_unmapped(struct addrinfo *);
int another(int *, char ***, const char *);
@@ -114,7 +116,7 @@ unsigned char complete(EditLine *, int);
void controlediting(void);
#endif /* !NO_EDITCOMPLETE */
void crankrate(int);
-FILE *dataconn(const char *);
+FETCH *dataconn(const char *);
void delete(int, char **);
void disconnect(int, char **);
void do_chmod(int, char **);
diff --git a/fetch.c b/fetch.c
index e837d8f..d0b2ed2 100644
--- a/fetch.c
+++ b/fetch.c
@@ -64,7 +64,6 @@ __RCSID("$NetBSD: fetch.c,v 1.202 2013/02/23 13:47:36 christos Exp $");
#include <unistd.h>
#include <time.h>
-#include "ssl.h"
#include "ftp_var.h"
#include "version.h"
@@ -75,6 +74,10 @@ typedef enum {
HTTPS_URL_T,
#endif
FTP_URL_T,
+#ifdef WITH_SSL
+ FTPS_URL_T,
+ FTPES_URL_T,
+#endif
FILE_URL_T,
CLASSIC_URL_T
} url_t;
@@ -105,14 +108,18 @@ static int redirect_loop;
#define FTP_URL "ftp://" /* ftp URL prefix */
#define HTTP_URL "http://" /* http URL prefix */
#ifdef WITH_SSL
+#define FTPS_URL "ftps://" /* ftps URL prefix */
+#define FTPES_URL "ftpes://" /* ftpes URL prefix */
#define HTTPS_URL "https://" /* https URL prefix */
-#define IS_HTTP_TYPE(urltype) \
- (((urltype) == HTTP_URL_T) || ((urltype) == HTTPS_URL_T))
-#else
-#define IS_HTTP_TYPE(urltype) \
- ((urltype) == HTTP_URL_T)
-#endif
+#define IS_FTP_TYPE(t) \
+ (((t) == FTP_URL_T) || ((t) == FTPS_URL_T) || ((t) == FTPES_URL_T))
+#define IS_HTTP_TYPE(t) \
+ (((t) == HTTP_URL_T) || ((t) == HTTPS_URL_T))
+#else /* !WITH_SSL */
+#define IS_FTP_TYPE(t) ((t) == FTP_URL_T)
+#define IS_HTTP_TYPE(t) ((t) == HTTP_URL_T)
+#endif /* WITH_SSL */
/*
* Determine if token is the next word in buf (case insensitive).
@@ -364,6 +371,20 @@ parse_url(const char *url, const char *desc, url_t *utype,
*utype = HTTPS_URL_T;
*portnum = HTTPS_PORT;
tport = httpsport;
+ } else if (STRNEQUAL(url, FTPS_URL)) {
+ url += sizeof(FTPS_URL) - 1;
+ *utype = FTPS_URL_T;
+ *portnum = FTPS_PORT;
+ tport = ftpsport;
+ ftpssl = 1;
+ ftps_explicit = 0;
+ } else if (STRNEQUAL(url, FTPES_URL)) {
+ url += sizeof(FTPES_URL) - 1;
+ *utype = FTPES_URL_T;
+ *portnum = FTPS_PORT;
+ tport = ftpsport;
+ ftpssl = 1;
+ ftps_explicit = 1;
#endif
} else {
warnx("Invalid %s `%s'", desc, url);
@@ -389,14 +410,14 @@ parse_url(const char *url, const char *desc, url_t *utype,
len = ep - url;
thost = (char *)ftp_malloc(len + 1);
(void)strlcpy(thost, url, len + 1);
- if (*utype == FTP_URL_T) /* skip first / for ftp URLs */
+ if (IS_FTP_TYPE(*utype)) /* skip first / for ftp URLs */
ep++;
*path = ftp_strdup(ep);
}
cp = strchr(thost, '@'); /* look for user[:pass]@ in URLs */
if (cp != NULL) {
- if (*utype == FTP_URL_T)
+ if (IS_FTP_TYPE(*utype))
anonftp = 0; /* disable anonftp */
*uuser = thost;
*cp = '\0';
@@ -463,7 +484,7 @@ parse_url(const char *url, const char *desc, url_t *utype,
*port = ftp_strdup(tport);
if (*path == NULL) {
const char *emptypath = "/";
- if (*utype == FTP_URL_T) /* skip first / for ftp URLs */
+ if (IS_FTP_TYPE(*utype)) /* skip first / for ftp URLs */
emptypath++;
*path = ftp_strdup(emptypath);
}
@@ -523,7 +544,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
url_t urltype;
in_port_t portnum;
#ifdef WITH_SSL
- void *ssl;
+ struct fetch_ssl *volatile ssl;
#endif
DPRINTF("fetch_url: `%s' proxyenv `%s'\n", url, STRorNULL(proxyenv));
@@ -550,7 +571,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
}
if (EMPTYSTRING(path)) {
- if (urltype == FTP_URL_T) {
+ if (IS_FTP_TYPE(urltype)) {
rval = fetch_ftp(url);
goto cleanup_fetch_url;
}
@@ -574,7 +595,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
}
DPRINTF("fetch_url: savefile `%s'\n", savefile);
if (EMPTYSTRING(savefile)) {
- if (urltype == FTP_URL_T) {
+ if (IS_FTP_TYPE(urltype)) {
rval = fetch_ftp(url);
goto cleanup_fetch_url;
}
@@ -631,7 +652,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
#endif
if (proxyenv == NULL && IS_HTTP_TYPE(urltype))
proxyenv = getoptionvalue("http_proxy");
- else if (urltype == FTP_URL_T)
+ else if (IS_FTP_TYPE(urltype))
proxyenv = getoptionvalue("ftp_proxy");
}
direction = "retrieved";
@@ -673,7 +694,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
}
}
FREEPTR(np_copy);
- if (isproxy == 0 && urltype == FTP_URL_T) {
+ if (isproxy == 0 && IS_FTP_TYPE(urltype)) {
rval = fetch_ftp(url);
goto cleanup_fetch_url;
}
@@ -691,7 +712,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
goto cleanup_fetch_url;
if ((!IS_HTTP_TYPE(purltype)
- && purltype != FTP_URL_T) ||
+ && !IS_FTP_TYPE(purltype)) ||
EMPTYSTRING(phost) ||
(! EMPTYSTRING(ppath)
&& strcmp(ppath, "/") != 0)) {
@@ -791,11 +812,26 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
if (s < 0) {
warnx("Can't connect to `%s:%s'", host, port);
+#ifdef WITH_SSL
+ fetch_stop_ssl(ssl);
+#endif
goto cleanup_fetch_url;
}
fin = fetch_fdopen(s, "r+");
- fetch_set_ssl(fin, ssl);
+ if (fin == NULL) {
+ warnx("fdopen failed");
+#ifdef WITH_SSL
+ fetch_stop_ssl(ssl);
+#endif
+ goto cleanup_fetch_url;
+ }
+#ifdef WITH_SSL
+ if (urltype == HTTPS_URL_T) {
+ fetch_set_ssl(fin, ssl);
+ ssl = NULL;
+ }
+#endif
/*
* Construct and send the request.
@@ -1254,7 +1290,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
while (bufrem > 0) {
flen = fetch_read(xferbuf, sizeof(char),
MIN((off_t)bufsize, bufrem), fin);
- if (flen <= 0)
+ if (flen == 0)
goto chunkdone;
bytes += flen;
bufrem -= flen;
@@ -1414,7 +1450,12 @@ fetch_ftp(const char *url)
rval = 1;
transtype = TYPE_I;
- if (STRNEQUAL(url, FTP_URL)) {
+ if (STRNEQUAL(url, FTP_URL)
+#ifdef WITH_SSL
+ || STRNEQUAL(url, FTPS_URL)
+ || STRNEQUAL(url, FTPES_URL)
+#endif
+ ) {
if ((parse_url(url, "URL", &urltype, &uuser, &pass,
&host, &port, &portnum, &path) == -1) ||
(uuser != NULL && *uuser == '\0') ||
@@ -1502,7 +1543,7 @@ fetch_ftp(const char *url)
}
} else
dir = NULL;
- if (urltype == FTP_URL_T && file != NULL) {
+ if (IS_FTP_TYPE(urltype) && file != NULL) {
url_decode(file);
/* but still don't url_decode(dir) */
}
@@ -1628,7 +1669,7 @@ fetch_ftp(const char *url)
* Note that we don't need `dir' after this point.
*/
do {
- if (urltype == FTP_URL_T) {
+ if (IS_FTP_TYPE(urltype)) {
nextpart = strchr(dir, '/');
if (nextpart) {
*nextpart = '\0';
@@ -1639,7 +1680,7 @@ fetch_ftp(const char *url)
nextpart = NULL;
DPRINTF("fetch_ftp: dir `%s', nextpart `%s'\n",
STRorNULL(dir), STRorNULL(nextpart));
- if (urltype == FTP_URL_T || *dir != '\0') {
+ if (IS_FTP_TYPE(urltype) || *dir != '\0') {
(void)strlcpy(cmdbuf, "cd", sizeof(cmdbuf));
xargv[0] = cmdbuf;
xargv[1] = dir;
@@ -1796,7 +1837,11 @@ go_fetch(const char *url)
* part before the colon is a host name, not an URL scheme,
* so we don't try to match that here.
*/
- if ((p = strstr(url, "://")) != NULL && ! STRNEQUAL(url, FTP_URL))
+ if ((p = strstr(url, "://")) != NULL && ! STRNEQUAL(url, FTP_URL)
+#ifdef WITH_SSL
+ && ! STRNEQUAL(url, FTPS_URL) && ! STRNEQUAL(url, FTPES_URL)
+#endif
+ )
errx(1, "Unsupported URL scheme `%.*s'", (int)(p - url), url);
/*
@@ -1805,7 +1850,11 @@ go_fetch(const char *url)
* Othewise, use fetch_ftp().
*/
proxyenv = getoptionvalue("ftp_proxy");
- if (!EMPTYSTRING(proxyenv) && STRNEQUAL(url, FTP_URL))
+ if (!EMPTYSTRING(proxyenv) && (STRNEQUAL(url, FTP_URL)
+#ifdef WITH_SSL
+ || STRNEQUAL(url, FTPS_URL) || STRNEQUAL(url, FTPES_URL)
+#endif
+ ))
return (fetch_url(url, NULL, NULL, NULL));
return (fetch_ftp(url));
diff --git a/ftp.c b/ftp.c
index d1a8785..d43a35b 100644
--- a/ftp.c
+++ b/ftp.c
@@ -131,7 +131,7 @@ int ptabflg;
int ptflag = 0;
char pasv[BUFSIZ]; /* passive port for proxy data connection */
-static int empty(FILE *, FILE *, int);
+static int empty(FETCH *, FETCH *, int);
__dead static void abort_squared(int);
struct sockinet {
@@ -164,6 +164,9 @@ hookup(const char *host, const char *port)
static char hostnamebuf[MAXHOSTNAMELEN];
socklen_t len;
int on = 1;
+#ifdef WITH_SSL
+ struct fetch_ssl *ssl = NULL;
+#endif
memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
memset((char *)&myctladdr, 0, sizeof (myctladdr));
@@ -202,6 +205,9 @@ hookup(const char *host, const char *port)
/* if we have multiple possibilities */
fprintf(ttyout, "Trying %s:%s ...\n", hname, sname);
}
+#ifdef WITH_SSL
+ retry:
+#endif
s = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);
if (s < 0) {
warn("Can't create socket for connection to `%s:%s'",
@@ -215,6 +221,21 @@ hookup(const char *host, const char *port)
continue;
}
+#ifdef WITH_SSL
+ if (ftpssl && !ftps_explicit) {
+ if ((ssl = fetch_start_ssl(s)) == NULL) {
+ close(s);
+ s = -1;
+ if (ftps_fallback) {
+ ftps_explicit = 1;
+ goto retry;
+ } else {
+ continue;
+ }
+ }
+ }
+#endif
+
/* finally we got one */
break;
}
@@ -248,24 +269,31 @@ hookup(const char *host, const char *port)
}
}
#endif
- cin = fdopen(s, "r");
- cout = fdopen(s, "w");
+ cin = fetch_fdopen(s, "r");
+ cout = fetch_fdopen(s, "w");
if (cin == NULL || cout == NULL) {
warnx("Can't fdopen socket");
if (cin)
- (void)fclose(cin);
+ (void)fetch_close(cin);
if (cout)
- (void)fclose(cout);
+ (void)fetch_close(cout);
code = -1;
goto bad;
}
+#ifdef WITH_SSL
+ if (ftpssl && !ftps_explicit) {
+ fetch_set_ssl(cin, ssl);
+ fetch_set_ssl(cout, ssl);
+ ssl = NULL;
+ }
+#endif
if (verbose)
fprintf(ttyout, "Connected to %s.\n", hostname);
if (getreply(0) > 2) { /* read startup message from server */
if (cin)
- (void)fclose(cin);
+ (void)fetch_close(cin);
if (cout)
- (void)fclose(cout);
+ (void)fetch_close(cout);
code = -1;
goto bad;
}
@@ -277,6 +305,9 @@ hookup(const char *host, const char *port)
return (hostname);
bad:
+#ifdef WITH_SSL
+ fetch_stop_ssl(ssl);
+#endif
(void)close(s);
return (NULL);
}
@@ -343,10 +374,10 @@ command(const char *fmt, ...)
oldsigint = xsignal(SIGINT, cmdabort);
va_start(ap, fmt);
- vfprintf(cout, fmt, ap);
+ fetch_vprintf(cout, fmt, ap);
va_end(ap);
- fputs("\r\n", cout);
- (void)fflush(cout);
+ fetch_printf(cout, "%s", "\r\n");
+ (void)fetch_flush(cout);
cpend = 1;
r = getreply(!strcmp(fmt, "QUIT"));
if (abrtflag && oldsigint != SIG_IGN)
@@ -382,20 +413,22 @@ getreply(int expecteof)
dig = n = code = 0;
cp = current_line;
while (alarmtimer(quit_time ? quit_time : 60),
- ((c = getc(cin)) != '\n')) {
+ ((c = fetch_getc(cin)) != '\n')) {
if (c == IAC) { /* handle telnet commands */
- switch (c = getc(cin)) {
+ switch (c = fetch_getc(cin)) {
case WILL:
case WONT:
- c = getc(cin);
- fprintf(cout, "%c%c%c", IAC, DONT, c);
- (void)fflush(cout);
+ c = fetch_getc(cin);
+ fetch_printf(cout, "%c%c%c", IAC, DONT,
+ c);
+ (void)fetch_flush(cout);
break;
case DO:
case DONT:
- c = getc(cin);
- fprintf(cout, "%c%c%c", IAC, WONT, c);
- (void)fflush(cout);
+ c = fetch_getc(cin);
+ fetch_printf(cout, "%c%c%c", IAC, WONT,
+ c);
+ (void)fetch_flush(cout);
break;
default:
break;
@@ -412,7 +445,7 @@ getreply(int expecteof)
int reply_abrtflag = abrtflag;
alarmtimer(0);
- if (expecteof && feof(cin)) {
+ if (expecteof && fetch_eof(cin)) {
(void)xsignal(SIGINT, oldsigint);
(void)xsignal(SIGALRM, oldsigalrm);
code = 221;
@@ -510,19 +543,19 @@ getreply(int expecteof)
}
static int
-empty(FILE *ecin, FILE *din, int sec)
+empty(FETCH *ecin, FETCH *din, int sec)
{
int nr, nfd;
struct pollfd pfd[2];
nfd = 0;
if (ecin) {
- pfd[nfd].fd = fileno(ecin);
+ pfd[nfd].fd = fetch_fileno(ecin);
pfd[nfd++].events = POLLIN;
}
if (din) {
- pfd[nfd].fd = fileno(din);
+ pfd[nfd].fd = fetch_fileno(din);
pfd[nfd++].events = POLLIN;
}
@@ -576,15 +609,16 @@ abortxfer(int notused)
* In the case of error, errno contains the appropriate error code.
*/
static int
-copy_bytes(int infd, int outfd, char *buf, size_t bufsize,
+copy_bytes(FETCH *infd, FETCH *outfd, char *buf, size_t bufsize,
int rate_limit, int hash_interval)
{
volatile off_t hashc;
- ssize_t inc, outc;
+ size_t inc, outc;
char *bufp;
struct timeval tvthen, tvnow, tvdiff;
off_t bufrem, bufchunk;
int serr;
+ int rv = 0;
hashc = hash_interval;
if (rate_limit)
@@ -601,16 +635,23 @@ copy_bytes(int infd, int outfd, char *buf, size_t bufsize,
/* copy bufchunk at a time */
bufrem = bufchunk;
while (bufrem > 0) {
- inc = read(infd, buf, MIN((off_t)bufsize, bufrem));
- if (inc <= 0)
+ inc = fetch_read(buf, 1, MIN((off_t)bufsize, bufrem),
+ infd);
+ if (inc == 0) {
+ if (!fetch_eof(infd))
+ rv = 1;
goto copy_done;
+ }
bytes += inc;
bufrem -= inc;
bufp = buf;
while (inc > 0) {
- outc = write(outfd, bufp, inc);
- if (outc < 0)
+ outc = fetch_write(bufp, 1, inc, outfd);
+ if (outc == 0) {
+ if (fetch_error(outfd))
+ rv = 2;
goto copy_done;
+ }
inc -= outc;
bufp += outc;
}
@@ -642,12 +683,7 @@ copy_bytes(int infd, int outfd, char *buf, size_t bufsize,
(void)fflush(ttyout);
}
errno = serr;
- if (inc == -1)
- return 1;
- if (outc == -1)
- return 2;
-
- return 0;
+ return rv;
}
void
@@ -657,7 +693,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
struct stat st;
int c;
FILE *volatile fin;
- FILE *volatile dout;
+ FETCH *volatile dout;
int (*volatile closefunc)(FILE *);
sigfunc volatile oldintr;
sigfunc volatile oldintp;
@@ -667,6 +703,10 @@ sendrequest(const char *cmd, const char *local, const char *remote,
static size_t bufsize;
static char *buf;
int oprogress;
+#ifdef WITH_SSL
+ FETCH *volatile fin2;
+ int fdin;
+#endif
hashbytes = mark;
direction = "sent";
@@ -783,8 +823,22 @@ sendrequest(const char *cmd, const char *local, const char *remote,
case TYPE_I:
case TYPE_L:
- c = copy_bytes(fileno(fin), fileno(dout), buf, bufsize,
- rate_put, hash_interval);
+#ifdef WITH_SSL
+ c = 1;
+ fdin = dup(fileno(fin));
+ if (fdin >= 0) {
+ fin2 = fetch_fdopen(fdin, "r");
+ if (fin2 != NULL) {
+ c = copy_bytes(fin2, dout, buf, bufsize,
+ rate_put, hash_interval);
+ fetch_close(fin2);
+ } else
+ close(fdin);
+ }
+#else /* !WITH_SSL */
+ c = copy_bytes(fin, dout, buf, bufsize, rate_put,
+ hash_interval);
+#endif /* WITH_SSL */
if (c == 1) {
warn("Reading `%s'", local);
} else if (c == 2) {
@@ -802,16 +856,16 @@ sendrequest(const char *cmd, const char *local, const char *remote,
(void)fflush(ttyout);
hashbytes += mark;
}
- if (ferror(dout))
+ if (fetch_error(dout))
break;
- (void)putc('\r', dout);
+ (void)fetch_putc('\r', dout);
bytes++;
}
- (void)putc(c, dout);
+ (void)fetch_putc(c, dout);
bytes++;
#if 0 /* this violates RFC 959 */
if (c == '\r') {
- (void)putc('\0', dout);
+ (void)fetch_putc('\0', dout);
bytes++;
}
#endif
@@ -823,7 +877,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
}
if (ferror(fin))
warn("Reading `%s'", local);
- if (ferror(dout)) {
+ if (fetch_error(dout)) {
if (errno != EPIPE)
warn("Writing to network");
bytes = -1;
@@ -836,7 +890,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
(*closefunc)(fin);
fin = NULL;
}
- (void)fclose(dout);
+ (void)fetch_close(dout);
dout = NULL;
(void)getreply(0);
if (bytes > 0)
@@ -855,7 +909,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
data = -1;
}
if (dout) {
- (void)fclose(dout);
+ (void)fetch_close(dout);
dout = NULL;
}
(void)getreply(0);
@@ -875,7 +929,7 @@ sendrequest(const char *cmd, const char *local, const char *remote,
if (closefunc != NULL && fin != NULL)
(*closefunc)(fin);
if (dout)
- (void)fclose(dout);
+ (void)fetch_close(dout);
progress = oprogress;
restart_point = 0;
bytes = 0;
@@ -886,7 +940,7 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
const char *lmode, int printnames, int ignorespecial)
{
FILE *volatile fout;
- FILE *volatile din;
+ FETCH *volatile din;
int (*volatile closefunc)(FILE *);
sigfunc volatile oldintr;
sigfunc volatile oldintp;
@@ -903,6 +957,11 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
struct timeval tval[2];
int oprogress;
int opreserve;
+#ifdef WITH_SSL
+ const char *fmode;
+ FETCH *volatile fout2;
+ int fdout;
+#endif
fout = NULL;
din = NULL;
@@ -1003,11 +1062,17 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
if (din == NULL)
goto abort;
if (!ignorespecial && strcmp(local, "-") == 0) {
+#ifdef WITH_SSL
+ fmode = "w";
+#endif
fout = stdout;
progress = 0;
preserve = 0;
} else if (!ignorespecial && *local == '|') {
oldintp = xsignal(SIGPIPE, SIG_IGN);
+#ifdef WITH_SSL
+ fmode = "w";
+#endif
fout = popen(local + 1, "w");
if (fout == NULL) {
warn("Can't execute `%s'", local+1);
@@ -1017,6 +1082,9 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
preserve = 0;
closefunc = pclose;
} else {
+#ifdef WITH_SSL
+ fmode = lmode;
+#endif
fout = fopen(local, lmode);
if (fout == NULL) {
warn("Can't open `%s'", local);
@@ -1049,8 +1117,22 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
warn("Can't seek to restart `%s'", local);
goto cleanuprecv;
}
- c = copy_bytes(fileno(din), fileno(fout), buf, bufsize,
- rate_get, hash_interval);
+#ifdef WITH_SSL
+ c = 2;
+ fdout = dup(fileno(fout));
+ if (fdout >= 0) {
+ fout2 = fetch_fdopen(fdout, fmode);
+ if (fout2 != NULL) {
+ c = copy_bytes(din, fout2, buf, bufsize,
+ rate_get, hash_interval);
+ fetch_close(fout2);
+ } else
+ close(fdout);
+ }
+#else /* !WITH_SSL */
+ c = copy_bytes(din, fout, buf, bufsize, rate_get,
+ hash_interval);
+#endif /* WITH_SSL */
if (c == 1) {
if (errno != EPIPE)
warn("Reading from network");
@@ -1079,7 +1161,7 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
goto cleanuprecv;
}
}
- while ((c = getc(din)) != EOF) {
+ while ((c = fetch_getc(din)) != EOF) {
if (c == '\n')
bare_lfs++;
while (c == '\r') {
@@ -1089,7 +1171,7 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
hashbytes += mark;
}
bytes++;
- if ((c = getc(din)) != '\n' || tcrflag) {
+ if ((c = fetch_getc(din)) != '\n' || tcrflag) {
if (ferror(fout))
goto break2;
(void)putc('\r', fout);
@@ -1111,7 +1193,7 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
(void)putc('#', ttyout);
(void)putc('\n', ttyout);
}
- if (ferror(din)) {
+ if (fetch_error(din)) {
if (errno != EPIPE)
warn("Reading from network");
bytes = -1;
@@ -1126,7 +1208,7 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
(*closefunc)(fout);
fout = NULL;
}
- (void)fclose(din);
+ (void)fetch_close(din);
din = NULL;
(void)getreply(0);
if (bare_lfs) {
@@ -1184,7 +1266,7 @@ recvrequest(const char *cmd, const char *volatile local, const char *remote,
if (closefunc != NULL && fout != NULL)
(*closefunc)(fout);
if (din)
- (void)fclose(din);
+ (void)fetch_close(din);
progress = oprogress;
preserve = opreserve;
bytes = 0;
@@ -1650,7 +1732,7 @@ initconn(void)
return (1);
}
-FILE *
+FETCH *
dataconn(const char *lmode)
{
struct sockinet from;
@@ -1658,9 +1740,13 @@ dataconn(const char *lmode)
struct timeval endtime, now, td;
struct pollfd pfd[1];
socklen_t fromlen;
+ FETCH *conn;
+#ifdef WITH_SSL
+ struct fetch_ssl *ssl;
+#endif
if (passivemode) /* passive data connection */
- return (fdopen(data, lmode));
+ goto dataconn_open;
/* active mode data connection */
@@ -1718,7 +1804,27 @@ dataconn(const char *lmode)
}
}
#endif
- return (fdopen(data, lmode));
+ dataconn_open:
+#ifdef WITH_SSL
+ ssl = NULL;
+ if (ftpssl) {
+ if ((ssl = fetch_start_ssl(data)) == NULL) {
+ warn("SSL negotiation failed on data connection");
+ goto dataconn_failed;
+ }
+ }
+#endif
+ conn = fetch_fdopen(data, lmode);
+#ifdef WITH_SSL
+ if (ftpssl) {
+ if (conn == NULL) {
+ fetch_stop_ssl(ssl);
+ goto dataconn_failed;
+ }
+ fetch_set_ssl(conn, ssl);
+ }
+#endif
+ return conn;
dataconn_failed:
(void)close(data);
@@ -1746,8 +1852,8 @@ pswitch(int flag)
char name[MAXHOSTNAMELEN];
struct sockinet mctl;
struct sockinet hctl;
- FILE *in;
- FILE *out;
+ FETCH *in;
+ FETCH *out;
int tpe;
int curtpe;
int cpnd;
@@ -2052,7 +2158,7 @@ abort_squared(int dummy)
}
void
-abort_remote(FILE *din)
+abort_remote(FETCH *din)
{
char buf[BUFSIZ];
int nfnd;
@@ -2071,10 +2177,10 @@ abort_remote(FILE *din)
buf[0] = IAC;
buf[1] = IP;
buf[2] = IAC;
- if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
+ if (fetch_send(cout, buf, 3, MSG_OOB) != 3)
warn("Can't send abort message");
- fprintf(cout, "%cABOR\r\n", DM);
- (void)fflush(cout);
+ fetch_printf(cout, "%cABOR\r\n", DM);
+ (void)fetch_flush(cout);
if ((nfnd = empty(cin, din, 10)) <= 0) {
if (nfnd < 0)
warn("Can't send abort message");
@@ -2083,7 +2189,7 @@ abort_remote(FILE *din)
lostpeer(0);
}
if (din && (nfnd & 2)) {
- while (read(fileno(din), buf, BUFSIZ) > 0)
+ while (fetch_read(buf, 1, BUFSIZ, din) > 0)
continue;
}
if (getreply(0) == ERROR && code == 552) {
diff --git a/ftp_var.h b/ftp_var.h
index 7e5040a..7db055e 100644
--- a/ftp_var.h
+++ b/ftp_var.h
@@ -116,6 +116,7 @@
#include "extern.h"
#include "progressbar.h"
+#include "ssl.h"
/*
* Format of command table.
@@ -162,6 +163,9 @@ enum {
FEAT_REST_STREAM, /* RESTart STREAM */
FEAT_SIZE, /* SIZE */
FEAT_TVFS, /* TVFS (not used) */
+ FEAT_PBSZ, /* PBSZ */
+ FEAT_PROT, /* PROT */
+ FEAT_AUTH_TLS, /* AUTH TLS */
FEAT_max
};
@@ -176,6 +180,7 @@ enum {
#define DEFAULTINCR 1024 /* default increment for `rate' command */
#define FTP_PORT 21 /* default if ! getservbyname("ftp/tcp") */
+#define FTPS_PORT 990 /* default if ! getservbyname("ftps/tcp") */
#define HTTP_PORT 80 /* default if ! getservbyname("http/tcp") */
#define HTTPS_PORT 443 /* default if ! getservbyname("https/tcp") */
#ifndef GATE_PORT
@@ -255,6 +260,11 @@ GLOBAL int epsv6; /* use EPSV/EPRT on IPv6 connections */
GLOBAL int epsv6bad; /* EPSV doesn't work on the current server */
GLOBAL int editing; /* command line editing enabled */
GLOBAL int features[FEAT_max]; /* remote FEATures supported */
+#ifdef WITH_SSL
+GLOBAL int ftpssl; /* use FTPS */
+GLOBAL int ftps_explicit; /* FTPS explicit mode */
+GLOBAL int ftps_fallback; /* explicit mode from implicit mode */
+#endif
#ifndef NO_EDITCOMPLETE
GLOBAL EditLine *el; /* editline(3) status structure */
@@ -275,6 +285,7 @@ GLOBAL sa_family_t family; /* address family to use for connections */
GLOBAL const char *ftpport; /* port number to use for FTP connections */
GLOBAL const char *httpport; /* port number to use for HTTP connections */
#ifdef WITH_SSL
+GLOBAL const char *ftpsport; /* port number to use for FTPS connections */
GLOBAL const char *httpsport; /* port number to use for HTTPS connections */
#endif
GLOBAL const char *gateport; /* port number to use for gateftp connections */
@@ -315,8 +326,8 @@ GLOBAL void (*reply_callback)(const char *);
GLOBAL volatile sig_atomic_t sigint_raised;
-GLOBAL FILE *cin;
-GLOBAL FILE *cout;
+GLOBAL FETCH *cin;
+GLOBAL FETCH *cout;
GLOBAL int data;
extern struct cmd cmdtab[];
diff --git a/main.c b/main.c
index c84364d..438fc2a 100644
--- a/main.c
+++ b/main.c
@@ -152,6 +152,7 @@ main(int volatile argc, char **volatile argv)
ftpport = "ftp";
httpport = "http";
#ifdef WITH_SSL
+ ftpsport = "ftps";
httpsport = "https";
#endif
gateport = NULL;
@@ -201,6 +202,11 @@ main(int volatile argc, char **volatile argv)
#else
family = AF_INET; /* force AF_INET if no INET6 support */
#endif
+#ifdef WITH_SSL
+ ftpssl = 0;
+ ftps_explicit = 0;
+ ftps_fallback = 1;
+#endif
netrc[0] = '\0';
cp = getenv("NETRC");
@@ -335,6 +341,9 @@ main(int volatile argc, char **volatile argv)
break;
case 'P':
+#ifdef WITH_SSL
+ ftpsport =
+#endif
ftpport = optarg;
break;
@@ -1048,6 +1057,10 @@ usage(void)
" [-r retry] [-s srcaddr] [-T dir,max[,inc]]\n"
" [[user@]host [port]] [host:path[/]] [file:///file]\n"
" [ftp://[user[:pass]@]host[:port]/path[/]]\n"
+#ifdef WITH_SSL
+" [ftps://[user[:pass]@]host[:port]/path[/]]\n" /* Implicit */
+" [ftpes://[user[:pass]@]host[:port]/path[/]]\n" /* Explicit */
+#endif
" [http://[user[:pass]@]host[:port]/path] [...]\n"
#ifdef WITH_SSL
" [https://[user[:pass]@]host[:port]/path] [...]\n"
diff --git a/ssl.c b/ssl.c
index b34c864..1439af3 100644
--- a/ssl.c
+++ b/ssl.c
@@ -42,6 +42,7 @@ __RCSID("$NetBSD: ssl.c,v 1.2 2012/12/24 22:12:28 christos Exp $");
#include <sys/param.h>
#include <sys/select.h>
+#include <sys/stat.h>
#include <sys/uio.h>
#include <netinet/tcp.h>
@@ -57,6 +58,11 @@ __RCSID("$NetBSD: ssl.c,v 1.2 2012/12/24 22:12:28 christos Exp $");
extern int quit_time, verbose, ftp_debug;
extern FILE *ttyout;
+struct fetch_ssl {
+ SSL *ssl;
+ int refcnt;
+};
+
struct fetch_connect {
int sd; /* file/socket descriptor */
char *buf; /* buffer */
@@ -73,7 +79,7 @@ struct fetch_connect {
int issock;
int iserr;
int iseof;
- SSL *ssl; /* SSL handle */
+ struct fetch_ssl *ssl; /* SSL handle */
};
/*
@@ -119,7 +125,8 @@ fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
}
errno = 0;
if (conn->ssl != NULL)
- len = SSL_write(conn->ssl, iov->iov_base, iov->iov_len);
+ len = SSL_write(conn->ssl->ssl, iov->iov_base,
+ iov->iov_len);
else
len = writev(conn->sd, iov, iovcnt);
if (len == 0) {
@@ -150,14 +157,23 @@ fetch_writev(struct fetch_connect *conn, struct iovec *iov, int iovcnt)
/*
* Write to a connection w/ timeout
*/
-static int
-fetch_write(struct fetch_connect *conn, const char *str, size_t len)
+size_t
+fetch_write(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
{
struct iovec iov[1];
+ int rv;
- iov[0].iov_base = (char *)__UNCONST(str);
- iov[0].iov_len = len;
- return fetch_writev(conn, iov, 1);
+ if (size == 0 || nmemb == 0)
+ return 0;
+
+ iov[0].iov_base = ptr;
+ iov[0].iov_len = size * nmemb;
+ rv = fetch_writev(conn, iov, 1);
+ if (rv < 0) {
+ conn->iserr = 1;
+ return 0;
+ }
+ return rv;
}
/*
@@ -167,24 +183,35 @@ int
fetch_printf(struct fetch_connect *conn, const char *fmt, ...)
{
va_list ap;
+ int r;
+
+ va_start(ap, fmt);
+ r = fetch_vprintf(conn, fmt, ap);
+ va_end(ap);
+
+ return r;
+}
+
+int
+fetch_vprintf(struct fetch_connect *conn, const char *fmt, va_list ap)
+{
size_t len;
char *msg;
int r;
- va_start(ap, fmt);
len = vasprintf(&msg, fmt, ap);
- va_end(ap);
if (msg == NULL) {
errno = ENOMEM;
return -1;
}
- r = fetch_write(conn, msg, len);
+ r = fetch_write(msg, 1, len, conn);
free(msg);
return r;
}
+
int
fetch_fileno(struct fetch_connect *conn)
{
@@ -207,6 +234,13 @@ fetch_clearerr(struct fetch_connect *conn)
}
int
+fetch_eof(struct fetch_connect *conn)
+{
+
+ return conn->iseof;
+}
+
+int
fetch_flush(struct fetch_connect *conn)
{
int v;
@@ -227,9 +261,47 @@ struct fetch_connect *
fetch_open(const char *fname, const char *fmode)
{
struct fetch_connect *conn;
+ int mode, option;
int fd;
- fd = open(fname, O_RDONLY); /* XXX: fmode */
+ switch (*fmode++) {
+ default: /* illegal mode */
+ return NULL;
+ case 'r': /* open for reading */
+ mode = O_RDONLY;
+ option = 0;
+ break;
+ case 'w': /* open for writing */
+ mode = O_WRONLY;
+ option = O_CREAT | O_TRUNC;
+ break;
+ case 'a': /* open for appending */
+ mode = O_WRONLY;
+ option = O_CREAT | O_APPEND;
+ break;
+ }
+ for (; *fmode != '\0'; fmode++) {
+ switch (*fmode) {
+ case '+':
+ mode = O_RDWR;
+ break;
+ case 'f':
+ option |= O_NONBLOCK;
+ break;
+ case 'e':
+ option |= O_CLOEXEC;
+ break;
+ case 'x':
+ option |= O_EXCL;
+ break;
+ case 'b':
+ break;
+ default: /* We could produce a warning here */
+ break;
+ }
+ }
+
+ fd = open(fname, mode | option);
if (fd < 0)
return NULL;
@@ -248,22 +320,28 @@ struct fetch_connect *
fetch_fdopen(int sd, const char *fmode)
{
struct fetch_connect *conn;
+ struct stat sb;
#if defined(SO_NOSIGPIPE) || defined(TCP_NOPUSH)
int opt = 1;
#endif
+ if (fstat(sd, &sb) < 0)
+ return NULL;
+
if ((conn = calloc(1, sizeof(*conn))) == NULL)
return NULL;
conn->sd = sd;
- conn->issock = 1;
- fcntl(sd, F_SETFD, FD_CLOEXEC);
+ if (S_ISSOCK(sb.st_mode)) {
+ conn->issock = 1;
+ fcntl(sd, F_SETFD, FD_CLOEXEC);
#ifdef SO_NOSIGPIPE
- setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
+ setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
#endif
#ifdef TCP_NOPUSH
- setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt));
+ setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt));
#endif
+ }
return conn;
}
@@ -274,7 +352,7 @@ fetch_close(struct fetch_connect *conn)
if (conn != NULL) {
fetch_flush(conn);
- SSL_free(conn->ssl);
+ fetch_free_ssl(conn);
rv = close(conn->sd);
if (rv < 0) {
errno = rv;
@@ -287,8 +365,9 @@ fetch_close(struct fetch_connect *conn)
return rv;
}
-#define FETCH_READ_WAIT -2
-#define FETCH_READ_ERROR -1
+#define FETCH_READ_INTR -4
+#define FETCH_READ_WAIT -3
+#define FETCH_READ_ERROR -2
static ssize_t
fetch_ssl_read(SSL *ssl, void *buf, size_t len)
@@ -299,6 +378,9 @@ fetch_ssl_read(SSL *ssl, void *buf, size_t len)
rlen = SSL_read(ssl, buf, len);
if (rlen < 0) {
ssl_err = SSL_get_error(ssl, rlen);
+ if (ssl_err == SSL_ERROR_SYSCALL && errno == EINTR) {
+ return FETCH_READ_INTR;
+ }
if (ssl_err == SSL_ERROR_WANT_READ ||
ssl_err == SSL_ERROR_WANT_WRITE) {
return FETCH_READ_WAIT;
@@ -316,7 +398,9 @@ fetch_nonssl_read(int sd, void *buf, size_t len)
rlen = read(sd, buf, len);
if (rlen < 0) {
- if (errno == EAGAIN || errno == EINTR)
+ if (errno == EINTR)
+ return FETCH_READ_INTR;
+ if (errno == EAGAIN)
return FETCH_READ_WAIT;
return FETCH_READ_ERROR;
}
@@ -346,8 +430,8 @@ fetch_cache_data(struct fetch_connect *conn, char *src, size_t nbytes)
return 0;
}
-ssize_t
-fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
+static ssize_t
+fetch_read1(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
{
struct timeval now, timeout, delta;
fd_set readfds;
@@ -402,7 +486,7 @@ fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
* slightly) when reading small amounts of data.
*/
if (conn->ssl != NULL)
- rlen = fetch_ssl_read(conn->ssl, buf, len);
+ rlen = fetch_ssl_read(conn->ssl->ssl, buf, len);
else
rlen = fetch_nonssl_read(conn->sd, buf, len);
if (rlen == 0) {
@@ -412,9 +496,10 @@ fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
buf += rlen;
total += rlen;
continue;
+ } else if (rlen == FETCH_READ_INTR) {
+ fetch_cache_data(conn, start, total);
+ return -1;
} else if (rlen == FETCH_READ_ERROR) {
- if (errno == EINTR)
- fetch_cache_data(conn, start, total);
return -1;
}
FD_ZERO(&readfds);
@@ -440,6 +525,23 @@ fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
return total;
}
+size_t
+fetch_read(void *ptr, size_t size, size_t nmemb, struct fetch_connect *conn)
+{
+ ssize_t rlen;
+
+ rlen = fetch_read1(ptr, size, nmemb, conn);
+ if (rlen == -1) {
+ conn->iserr = 1;
+ return 0;
+ }
+ if (rlen == 0) {
+ conn->iseof = 1;
+ return 0;
+ }
+ return rlen;
+}
+
#define MIN_BUF_SIZE 1024
/*
@@ -449,8 +551,7 @@ char *
fetch_getln(char *str, int size, struct fetch_connect *conn)
{
size_t tmpsize;
- ssize_t len;
- char c;
+ int c;
if (conn->buf == NULL) {
if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
@@ -471,14 +572,11 @@ fetch_getln(char *str, int size, struct fetch_connect *conn)
conn->bufpos = 0;
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;
+ c = fetch_getc(conn);
+ if (c == EOF) {
+ if (fetch_error(conn))
+ return NULL;
+ break; /* EOF */
}
conn->buf[conn->buflen++] = c;
if (conn->buflen == conn->bufsize) {
@@ -530,7 +628,7 @@ 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);
+ ssize_t rlen = fetch_read1(&c, 1, sizeof(c), conn);
if (rlen <= 0 || c == '\n')
break;
}
@@ -544,9 +642,54 @@ fetch_getline(struct fetch_connect *conn, char *buf, size_t buflen,
return len;
}
-void *
+int
+fetch_getc(struct fetch_connect *conn)
+{
+ ssize_t rlen;
+ char c;
+
+ rlen = fetch_read1(&c, 1, sizeof(c), conn);
+ if (rlen == -1) {
+ conn->iserr = 1;
+ return EOF;
+ }
+ if (rlen == 0) {
+ conn->iseof = 1;
+ return EOF;
+ }
+ return c;
+}
+
+int
+fetch_putc(int c, struct fetch_connect *conn)
+{
+ char buf[1];
+ int r;
+
+ buf[0] = c;
+ r = fetch_write(buf, 1, 1, conn);
+ if (r < 0)
+ return EOF;
+ return c;
+}
+
+ssize_t
+fetch_send(struct fetch_connect *conn, const void *msg, size_t len, int flags)
+{
+ struct iovec iov[1];
+
+ if (conn->ssl == NULL)
+ return send(fetch_fileno(conn), msg, len, flags);
+
+ iov[0].iov_base = __UNCONST(msg);
+ iov[0].iov_len = len;
+ return fetch_writev(conn, iov, 1);
+}
+
+struct fetch_ssl *
fetch_start_ssl(int sock)
{
+ struct fetch_ssl *fssl;
SSL *ssl;
SSL_CTX *ctx;
int ret, ssl_err;
@@ -562,9 +705,17 @@ fetch_start_ssl(int sock)
ctx = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
+ fssl = calloc(1, sizeof(*fssl));
+ if (fssl == NULL) {
+ fprintf(ttyout, "SSL memory allocation failed\n");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+
ssl = SSL_new(ctx);
if (ssl == NULL){
fprintf(ttyout, "SSL context creation failed\n");
+ free(fssl);
SSL_CTX_free(ctx);
return NULL;
}
@@ -575,6 +726,7 @@ fetch_start_ssl(int sock)
ssl_err != SSL_ERROR_WANT_WRITE) {
ERR_print_errors_fp(ttyout);
SSL_free(ssl);
+ free(fssl);
return NULL;
}
}
@@ -597,12 +749,39 @@ fetch_start_ssl(int sock)
free(str);
}
- return ssl;
+ fssl->ssl = ssl;
+ fssl->refcnt = 0;
+ return fssl;
+}
+
+void
+fetch_stop_ssl(struct fetch_ssl *ssl)
+{
+
+ if (ssl != NULL) {
+ SSL_free(ssl->ssl);
+ free(ssl);
+ }
}
+void
+fetch_set_ssl(struct fetch_connect *conn, struct fetch_ssl *ssl)
+{
+
+ if (ssl != NULL) {
+ ssl->refcnt++;
+ conn->ssl = ssl;
+ }
+}
void
-fetch_set_ssl(struct fetch_connect *conn, void *ssl)
+fetch_free_ssl(struct fetch_connect *conn)
{
- conn->ssl = ssl;
+
+ if (conn != NULL && conn->ssl != NULL) {
+ if (--conn->ssl->refcnt <= 0) {
+ fetch_stop_ssl(conn->ssl);
+ conn->ssl = NULL;
+ }
+ }
}
diff --git a/ssl.h b/ssl.h
index 9ecc759..fc872a5 100644
--- a/ssl.h
+++ b/ssl.h
@@ -25,38 +25,60 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
+
+#ifndef FTP_SSL_H
+#define FTP_SSL_H
+
#ifdef WITH_SSL
+#include <stdarg.h>
+
#define FETCH struct fetch_connect
struct fetch_connect;
+struct fetch_ssl;
-int fetch_printf(struct fetch_connect *, const char *fmt, ...);
+int fetch_printf(struct fetch_connect *, const char *, ...);
+int fetch_vprintf(struct fetch_connect *, const char *, va_list);
int fetch_fileno(struct fetch_connect *);
int fetch_error(struct fetch_connect *);
+int fetch_eof(struct fetch_connect *);
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_write(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);
+int fetch_getc(struct fetch_connect *);
+int fetch_putc(int, struct fetch_connect *);
+ssize_t fetch_send(struct fetch_connect *, const void *, size_t, int);
+void fetch_set_ssl(struct fetch_connect *, struct fetch_ssl *);
+void fetch_free_ssl(struct fetch_connect *);
+struct fetch_ssl *fetch_start_ssl(int);
+void fetch_stop_ssl(struct fetch_ssl *);
#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 */
+#define fetch_printf fprintf
+#define fetch_vprintf vfprintf
+#define fetch_fileno fileno
+#define fetch_error ferror
+#define fetch_eof feof
+#define fetch_flush fflush
+#define fetch_open fopen
+#define fetch_fdopen fdopen
+#define fetch_close fclose
+#define fetch_write fwrite
+#define fetch_read fread
+#define fetch_getln fgets
+#define fetch_getline get_line
+#define fetch_getc getc
+#define fetch_putc putc
+#define fetch_send(f,m,l,fl) send(fileno((f)),(m),(l),(fl))
+
+#endif /* WITH_SSL */
+
+#endif /* FTP_SSL_H */
diff --git a/util.c b/util.c
index ee610c6..976ca3b 100644
--- a/util.c
+++ b/util.c
@@ -124,6 +124,10 @@ setpeer(int argc, char *argv[])
}
if (gatemode)
port = gateport;
+#ifdef WITH_SSL
+ else if (ftpssl)
+ port = ftpsport;
+#endif
else
port = ftpport;
if (argc > 2)
@@ -184,6 +188,14 @@ parse_feat(const char *fline)
features[FEAT_SIZE] = 1;
else if (strcasecmp(fline, "TVFS") == 0)
features[FEAT_TVFS] = 1;
+#ifdef WITH_SSL
+ else if (strcasecmp(fline, "PBSZ") == 0)
+ features[FEAT_PBSZ] = 1;
+ else if (strcasecmp(fline, "PROT") == 0)
+ features[FEAT_PROT] = 1;
+ else if (strcasecmp(fline, "AUTH TLS") == 0)
+ features[FEAT_AUTH_TLS] = 1;
+#endif
}
/*
@@ -266,6 +278,11 @@ getremoteinfo(void)
DEBUG_FEAT(FEAT_REST_STREAM);
DEBUG_FEAT(FEAT_SIZE);
DEBUG_FEAT(FEAT_TVFS);
+#ifdef WITH_SSL
+ DEBUG_FEAT(FEAT_PBSZ);
+ DEBUG_FEAT(FEAT_PROT);
+ DEBUG_FEAT(FEAT_AUTH_TLS);
+#endif
#undef DEBUG_FEAT
}
#endif
@@ -285,7 +302,7 @@ cleanuppeer(void)
{
if (cout)
- (void)fclose(cout);
+ (void)fetch_close(cout);
cout = NULL;
connected = 0;
unix_server = 0;
@@ -333,8 +350,8 @@ lostpeer(int dummy)
alarmtimer(0);
if (connected) {
if (cout != NULL) {
- (void)shutdown(fileno(cout), 1+1);
- (void)fclose(cout);
+ (void)shutdown(fetch_fileno(cout), 1+1);
+ (void)fetch_close(cout);
cout = NULL;
}
if (data >= 0) {
@@ -347,8 +364,8 @@ lostpeer(int dummy)
pswitch(1);
if (connected) {
if (cout != NULL) {
- (void)shutdown(fileno(cout), 1+1);
- (void)fclose(cout);
+ (void)shutdown(fetch_fileno(cout), 1+1);
+ (void)fetch_close(cout);
cout = NULL;
}
connected = 0;
@@ -372,6 +389,11 @@ ftp_login(const char *host, const char *luser, const char *lpass)
char emptypass[] = "";
const char *errormsg;
int n, aflag, rval, nlen;
+#ifdef WITH_SSL
+ static const char *sslprot[] = { "TLS", "SSL" };
+ struct fetch_ssl *ssl;
+ size_t i;
+#endif
aflag = rval = 0;
fuser = pass = facct = NULL;
@@ -429,7 +451,34 @@ ftp_login(const char *host, const char *luser, const char *lpass)
fuser = nuser;
}
- n = command("USER %s", fuser);
+ n = COMPLETE;
+#ifdef WITH_SSL
+ if (ftpssl && ftps_explicit) {
+ for (i = 0; i < sizeof(sslprot) / sizeof(sslprot[0]); i++) {
+ n = command("AUTH %s", sslprot[i]);
+ if (n == COMPLETE) {
+ ssl = fetch_start_ssl(fetch_fileno(cout));
+ if (ssl != NULL) {
+ fetch_set_ssl(cin, ssl);
+ fetch_set_ssl(cout, ssl);
+ } else
+ n = ERROR;
+ break;
+ } else if (n != TRANSIENT && n != ERROR) {
+ n = ERROR;
+ break;
+ }
+ }
+ if (n == COMPLETE) {
+ n = command("PBSZ 0");
+ if (n == COMPLETE) {
+ n = command("PROT P");
+ }
+ }
+ }
+#endif
+ if (n == COMPLETE)
+ n = command("USER %s", fuser);
if (n == CONTINUE) {
if (pass == NULL) {
p = getpass("Password: ");
--
1.8.2.3
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.