? 20120604-nbsd-ftp-https.diff Index: Makefile =================================================================== RCS file: /cvsroot/src/usr.bin/ftp/Makefile,v retrieving revision 1.35 diff -u -p -r1.35 Makefile --- Makefile 14 Aug 2011 12:58:15 -0000 1.35 +++ Makefile 4 Jun 2012 15:08:21 -0000 @@ -18,6 +18,11 @@ CPPFLAGS+=-DNO_EDITCOMPLETE -DNO_ABOUT - .else LDADD+= -ledit -lterminfo DPADD+= ${LIBEDIT} ${LIBTERMINFO} +.if (${MKCRYPTO} != "no") +CPPFLAGS+= -DWITH_SSL +LDADD+= -lssl -lcrypto +DPADD+= ${LIBSSL} ${LIBCRYPTO} +.endif .endif .if (!defined(SMALLPROG) || defined(SMALLPROG_INET6)) && (${USE_INET6} != "no") Index: fetch.c =================================================================== RCS file: /cvsroot/src/usr.bin/ftp/fetch.c,v retrieving revision 1.197 diff -u -p -r1.197 fetch.c --- fetch.c 24 Feb 2012 19:53:31 -0000 1.197 +++ fetch.c 4 Jun 2012 15:08:22 -0000 @@ -64,11 +64,23 @@ __RCSID("$NetBSD: fetch.c,v 1.197 2012/0 #include #include +#ifdef WITH_SSL +#include +#include +#include +#include +#include +#include +#endif + #include "ftp_var.h" #include "version.h" typedef enum { UNKNOWN_URL_T=-1, +#ifdef WITH_SSL + HTTPS_URL_T, +#endif HTTP_URL_T, FTP_URL_T, FILE_URL_T, @@ -100,7 +112,542 @@ static int redirect_loop; #define FILE_URL "file://" /* file URL prefix */ #define FTP_URL "ftp://" /* ftp URL prefix */ #define HTTP_URL "http://" /* http URL prefix */ +#ifdef WITH_SSL +#define HTTPS_URL "https://" /* https URL prefix */ +#define IS_HTTP_TYPE(urltype) \ + (((urltype) == HTTP_URL_T) || ((urltype) == HTTPS_URL_T)) + +struct fetch_connect { + int sd; /* file/socket descriptor */ + char *buf; /* buffer */ + size_t bufsize; /* buffer size */ + size_t bufoffset; /* offset of buffer contents */ + size_t buflen; /* length of buffer contents */ + int issock; + int iserr; + int iseof; + SSL *ssl; /* SSL handle */ + SSL_CTX *ssl_ctx; /* SSL context */ + X509 *ssl_cert; /* server certificate */ + const SSL_METHOD *ssl_meth; /* SSL method */ +}; +typedef struct fetch_connect fetch_connect_t; + +/* + * Write a vector to a connection w/ timeout + * Note: can modify the iovec. + */ +static ssize_t +fetch_writev(fetch_connect_t *conn, struct iovec *iov, int iovcnt) +{ + struct timeval now, timeout, delta; + fd_set writefds; + ssize_t len, total; + int r; + + if (quit_time > 0) { + FD_ZERO(&writefds); + gettimeofday(&timeout, NULL); + timeout.tv_sec += quit_time; + } + + total = 0; + while (iovcnt > 0) { + while (quit_time > 0 && !FD_ISSET(conn->sd, &writefds)) { + FD_SET(conn->sd, &writefds); + gettimeofday(&now, NULL); + delta.tv_sec = timeout.tv_sec - now.tv_sec; + delta.tv_usec = timeout.tv_usec - now.tv_usec; + if (delta.tv_usec < 0) { + delta.tv_usec += 1000000; + delta.tv_sec--; + } + if (delta.tv_sec < 0) { + errno = ETIMEDOUT; + return (-1); + } + errno = 0; + r = select(conn->sd + 1, NULL, &writefds, NULL, &delta); + if (r == -1) { + if (errno == EINTR) + continue; + return (-1); + } + } + errno = 0; + if (conn->ssl != NULL) + len = SSL_write(conn->ssl, iov->iov_base, iov->iov_len); + else + len = writev(conn->sd, iov, iovcnt); + if (len == 0) { + /* we consider a short write a failure */ + /* XXX perhaps we shouldn't in the SSL case */ + errno = EPIPE; + return (-1); + } + if (len < 0) { + if (errno == EINTR) + continue; + return (-1); + } + total += len; + while (iovcnt > 0 && len >= (ssize_t)iov->iov_len) { + len -= iov->iov_len; + iov++; + iovcnt--; + } + if (iovcnt > 0) { + iov->iov_len -= len; + iov->iov_base = (char *)iov->iov_base + len; + } + } + return (total); +} + +static int +fetch_write(fetch_connect_t *conn, const char *str, size_t len) +{ + struct iovec iov[1]; + + iov[0].iov_base = (char *)__UNCONST(str); + iov[0].iov_len = len; + return (fetch_writev(conn, iov, 1)); +} + +/* + * Send a formatted line; optionally echo to terminal + */ +static int +fetch_printf(fetch_connect_t *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); + free(msg); + return (r); +} + +static fetch_connect_t * +fetch_open(const char *fname, const char *fmode) +{ + fetch_connect_t *conn; + int fd; + + fd = open(fname, O_RDONLY); + if (fd < 0) + return (NULL); + + if ((conn = calloc(1, sizeof(*conn))) == NULL) { + close(fd); + return (NULL); + } + + conn->sd = fd; + conn->issock = 0; + return (conn); +} + +static void +fetch_close(fetch_connect_t *conn) +{ + + if (conn != NULL) { + if (conn->buf != NULL) { + free(conn->buf); + conn->buf = NULL; + } + conn->bufoffset = 0; + conn->buflen = 0; + conn->bufsize = 0; + if (conn->ssl != NULL) { + SSL_CTX_free(conn->ssl_ctx); + conn->ssl_ctx = NULL; + SSL_free(conn->ssl); + conn->ssl = NULL; + } + if (conn->sd >= 0) { + close(conn->sd); + conn->sd = -1; + } + } +} + +static int +fetch_fileno(fetch_connect_t *conn) +{ + + return (conn->sd); +} + +static fetch_connect_t * +fetch_fdopen(int sd, const char *fmode) +{ + fetch_connect_t *conn; + int opt = 1; + + if ((conn = calloc(1, sizeof(*conn))) == NULL) + return (NULL); + + conn->sd = sd; + conn->issock = 1; + fcntl(sd, F_SETFD, FD_CLOEXEC); + setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#ifdef TCP_NOPUSH + setsockopt(sd, IPPROTO_TCP, TCP_NOPUSH, &opt, sizeof(opt)); +#endif + return (conn); +} + +static int +fetch_flush(fetch_connect_t *conn) +{ + int v; + + if (conn->issock) { +#ifdef TCP_NOPUSH + v = 0; + setsockopt(conn->sd, IPPROTO_TCP, TCP_NOPUSH, &v, sizeof(v)); +#endif + v = 1; + setsockopt(conn->sd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v)); + } + return (0); +} + +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 (-2); + } else { + ERR_print_errors_fp(ttyout); + return (-1); + } + } + return (rlen); +} + +static ssize_t +fetch_socket_read(int sd, void *buf, size_t len) +{ + ssize_t rlen; + + rlen = read(sd, buf, len); + if (rlen < 0) { + if (errno == EAGAIN || errno == EINTR /* XXX cache */) { + return (-2); + } else { + return (-1); + } + } + return (rlen); +} + +static ssize_t +fetch_read(void *ptr, size_t size, size_t nmemb, fetch_connect_t *conn) +{ + struct timeval now, timeout, delta; + fd_set readfds; + ssize_t rlen, total; + size_t len; + char *start, *buf; + + if (quit_time > 0) { + gettimeofday(&timeout, NULL); + timeout.tv_sec += quit_time; + } + + total = 0; + start = buf = ptr; + len = size * nmemb; + +#if 0 + if (conn->cache.len > 0) { + /* + * The last invocation of fetch_read was interrupted by a + * signal after some data had been read from the socket. Copy + * the cached data into the supplied buffer before trying to + * read from the socket again. + */ + total = (conn->cache.len < len) ? conn->cache.len : len; + memcpy(buf, conn->cache.buf, total); + + conn->cache.len -= total; + conn->cache.pos += total; + len -= total; + buf += total; + } +#endif + + while (len > 0) { + /* + * The socket is non-blocking. Instead of the canonical + * select() -> read(), we do the following: + * + * 1) call read() or SSL_read(). + * 2) if an error occurred, return -1. + * 3) if we received data but we still expect more, + * update our counters and loop. + * 4) if read() or SSL_read() signaled EOF, return. + * 5) if we did not receive any data but we're not at EOF, + * call select(). + * + * In the SSL case, this is necessary because if we + * receive a close notification, we have to call + * SSL_read() one additional time after we've read + * everything we received. + * + * In the non-SSL case, it may improve performance (very + * slightly) when reading small amounts of data. + */ + if (conn->ssl != NULL) + rlen = fetch_ssl_read(conn->ssl, buf, len); + else + rlen = fetch_socket_read(conn->sd, buf, len); + if (rlen == 0) { + break; + } else if (rlen > 0) { + len -= rlen; + buf += rlen; + total += rlen; + continue; + } else if (rlen == -2) { +#if 0 + if (errno == EINTR) + fetch_cache_data(conn, start, total); +#endif + 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 0 + if (errno == EINTR) { + if (fetchRestartCalls) + continue; + /* Save anything that was read. */ + fetch_cache_data(conn, start, total); + } +#endif + return (-1); + } + } + } + return (total); +} + +/* + * Read a line of text from a connection w/ timeout + */ +static char * +fetch_getln(char *str, int size, fetch_connect_t *conn) +{ + char *tmp; + size_t tmpsize; + ssize_t len; + char c; + + if (conn->buf == NULL) { + if ((conn->buf = malloc(1024)) == NULL) { + errno = ENOMEM; + conn->iserr = 1; + return (NULL); + } + conn->bufsize = 1024; + } + + if (conn->iserr || conn->iseof) + return (NULL); + + if (conn->buflen - conn->bufoffset > 0) + goto done; + + conn->buf[0] = '\0'; + conn->bufoffset = 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; + } + conn->buf[conn->buflen++] = c; + if (conn->buflen == conn->bufsize) { + tmp = conn->buf; + tmpsize = conn->bufsize * 2 + 1; + if ((tmp = realloc(tmp, tmpsize)) == NULL) { + errno = ENOMEM; + conn->iserr = 1; + return (NULL); + } + conn->buf = tmp; + conn->bufsize = tmpsize; + } + } while (c != '\n'); + + if (conn->buflen == 0) + return (NULL); + done: + tmpsize = MIN(size - 1, (int)(conn->buflen - conn->bufoffset)); + memcpy(str, conn->buf + conn->bufoffset, tmpsize); + str[tmpsize] = '\0'; + conn->bufoffset += tmpsize; + return (str); +} + +static int +fetch_getline(fetch_connect_t *conn, char *buf, size_t buflen, + const char **errormsg) +{ + size_t len; + int rv; + + if (fetch_getln(buf, buflen, conn) == NULL) { + if (conn->iseof) { /* EOF */ + rv = -2; + if (errormsg) + *errormsg = "\nEOF received"; + } else { /* error */ + rv = -1; + if (errormsg) + *errormsg = "Error encountered"; + } + conn->iserr = 0; + return (rv); + } + len = strlen(buf); + if (buf[len - 1] == '\n') { /* clear any trailing newline */ + buf[--len] = '\0'; + } 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') + break; + } + if (errormsg) + *errormsg = "Input line is too long"; + conn->iserr = 0; + return (-3); + } + if (errormsg) + *errormsg = NULL; + return (len); +} + +static int +fetch_error(fetch_connect_t *conn) +{ + + return conn->iserr; +} + +static int +fetch_ssl(fetch_connect_t *conn) +{ + int ret, ssl_err; + + /* Init the SSL library and context */ + if (!SSL_library_init()){ + fprintf(ttyout, "SSL library init failed\n"); + return (-1); + } + + SSL_load_error_strings(); + + conn->ssl_meth = SSLv23_client_method(); + conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth); + SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY); + + conn->ssl = SSL_new(conn->ssl_ctx); + if (conn->ssl == NULL){ + fprintf(ttyout, "SSL context creation failed\n"); + SSL_CTX_free(conn->ssl_ctx); + conn->ssl_ctx = NULL; + return (-1); + } + SSL_set_fd(conn->ssl, conn->sd); + while ((ret = SSL_connect(conn->ssl)) == -1) { + ssl_err = SSL_get_error(conn->ssl, ret); + if (ssl_err != SSL_ERROR_WANT_READ && + ssl_err != SSL_ERROR_WANT_WRITE) { + ERR_print_errors_fp(ttyout); + SSL_CTX_free(conn->ssl_ctx); + conn->ssl_ctx = NULL; + SSL_free(conn->ssl); + conn->ssl = NULL; + return (-1); + } + } + + if (ftp_debug && verbose) { + X509_NAME *name; + char *str; + + fprintf(ttyout, "SSL connection established using %s\n", + SSL_get_cipher(conn->ssl)); + conn->ssl_cert = SSL_get_peer_certificate(conn->ssl); + name = X509_get_subject_name(conn->ssl_cert); + str = X509_NAME_oneline(name, 0, 0); + fprintf(ttyout, "Certificate subject: %s\n", str); + free(str); + name = X509_get_issuer_name(conn->ssl_cert); + str = X509_NAME_oneline(name, 0, 0); + fprintf(ttyout, "Certificate issuer: %s\n", str); + free(str); + } + + return (0); +} +#else /* !WITH_SSL */ +#define IS_HTTP_TYPE(urltype) ((urltype) == HTTP_URL_T) +typedef FILE fetch_connect_t; +#define fetch_printf fprintf +#define fetch_open fopen +#define fetch_close fclose +#define fetch_fileno fileno +#define fetch_fdopen fdopen +#define fetch_flush fflush +#define fetch_read fread +#define fetch_getln fgets +#define fetch_getline get_line +#define fetch_error ferror +#endif /* !WITH_SSL */ /* * Determine if token is the next word in buf (case insensitive). @@ -346,6 +893,13 @@ parse_url(const char *url, const char *d } else if (STRNEQUAL(url, FILE_URL)) { url += sizeof(FILE_URL) - 1; *utype = FILE_URL_T; +#ifdef WITH_SSL + } else if (STRNEQUAL(url, HTTPS_URL)) { + url += sizeof(HTTPS_URL) - 1; + *utype = HTTPS_URL_T; + *portnum = HTTPS_PORT; + tport = httpsport; +#endif } else { warnx("Invalid %s `%s'", desc, url); cleanup_parse_url: @@ -498,17 +1052,21 @@ fetch_url(const char *url, const char *p char *puser, *ppass, *useragent; off_t hashbytes, rangestart, rangeend, entitylen; int (*volatile closefunc)(FILE *); - FILE *volatile fin; + fetch_connect_t *volatile fin; FILE *volatile fout; time_t mtime; url_t urltype; in_port_t portnum; +#ifdef WITH_SSL + fetch_connect_t sslconn; +#endif DPRINTF("fetch_url: `%s' proxyenv `%s'\n", url, STRorNULL(proxyenv)); oldintr = oldintp = NULL; closefunc = NULL; - fin = fout = NULL; + fin = NULL; + fout = NULL; s = -1; savefile = NULL; auth = location = message = NULL; @@ -531,7 +1089,7 @@ fetch_url(const char *url, const char *p rval = fetch_ftp(url); goto cleanup_fetch_url; } - if (urltype != HTTP_URL_T || outfile == NULL) { + if (!IS_HTTP_TYPE(urltype) || outfile == NULL) { warnx("Invalid URL (no file after host) `%s'", url); goto cleanup_fetch_url; } @@ -571,17 +1129,17 @@ fetch_url(const char *url, const char *p } if (urltype == FILE_URL_T) { /* file:// URLs */ direction = "copied"; - fin = fopen(decodedpath, "r"); + fin = fetch_open(decodedpath, "r"); if (fin == NULL) { warn("Can't open `%s'", decodedpath); goto cleanup_fetch_url; } - if (fstat(fileno(fin), &sb) == 0) { + if (fstat(fetch_fileno(fin), &sb) == 0) { mtime = sb.st_mtime; filesize = sb.st_size; } if (restart_point) { - if (lseek(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; @@ -599,7 +1157,7 @@ fetch_url(const char *url, const char *p int hasleading; if (proxyenv == NULL) { - if (urltype == HTTP_URL_T) + if (IS_HTTP_TYPE(urltype)) proxyenv = getoptionvalue("http_proxy"); else if (urltype == FTP_URL_T) proxyenv = getoptionvalue("ftp_proxy"); @@ -660,7 +1218,7 @@ fetch_url(const char *url, const char *p &ppath) == -1) goto cleanup_fetch_url; - if ((purltype != HTTP_URL_T + if ((!IS_HTTP_TYPE(purltype) && purltype != FTP_URL_T) || EMPTYSTRING(phost) || (! EMPTYSTRING(ppath) @@ -690,6 +1248,7 @@ fetch_url(const char *url, const char *p FREEPTR(path); path = ftp_strdup(url); FREEPTR(ppath); + urltype = purltype; } } /* ! EMPTYSTRING(proxyenv) */ @@ -709,6 +1268,10 @@ fetch_url(const char *url, const char *p host = res0->ai_canonname; s = -1; +#ifdef WITH_SSL + memset(&sslconn, 0, sizeof(sslconn)); + sslconn.sd = -1; +#endif for (res = res0; res; res = res->ai_next) { char hname[NI_MAXHOST], sname[NI_MAXSERV]; @@ -740,6 +1303,17 @@ fetch_url(const char *url, const char *p continue; } +#ifdef WITH_SSL + if (urltype == HTTPS_URL_T) { + sslconn.sd = s; + if (fetch_ssl(&sslconn) < 0) { + close(s); + s = -1; + continue; + } + } +#endif + /* success */ break; } @@ -749,7 +1323,15 @@ fetch_url(const char *url, const char *p goto cleanup_fetch_url; } - fin = fdopen(s, "r+"); + fin = fetch_fdopen(s, "r+"); +#ifdef WITH_SSL + if (urltype == HTTPS_URL_T) { + fin->ssl = sslconn.ssl; + fin->ssl_ctx = sslconn.ssl_ctx; + fin->ssl_cert = sslconn.ssl_cert; + fin->ssl_meth = sslconn.ssl_meth; + } +#endif /* * Construct and send the request. */ @@ -764,11 +1346,11 @@ fetch_url(const char *url, const char *p leading = ", "; hasleading++; } - fprintf(fin, "GET %s HTTP/1.0\r\n", path); + fetch_printf(fin, "GET %s HTTP/1.0\r\n", path); if (flushcache) - fprintf(fin, "Pragma: no-cache\r\n"); + fetch_printf(fin, "Pragma: no-cache\r\n"); } else { - fprintf(fin, "GET %s HTTP/1.1\r\n", path); + fetch_printf(fin, "GET %s HTTP/1.1\r\n", path); if (strchr(host, ':')) { char *h, *p; @@ -781,18 +1363,23 @@ fetch_url(const char *url, const char *p (p = strchr(h, '%')) != NULL) { *p = '\0'; } - fprintf(fin, "Host: [%s]", h); + fetch_printf(fin, "Host: [%s]", h); free(h); } else - fprintf(fin, "Host: %s", host); + fetch_printf(fin, "Host: %s", host); +#ifdef WITH_SSL + if ((urltype == HTTP_URL_T && portnum != HTTP_PORT) || + (urltype == HTTPS_URL_T && portnum != HTTPS_PORT)) +#else if (portnum != HTTP_PORT) - fprintf(fin, ":%u", portnum); - fprintf(fin, "\r\n"); - fprintf(fin, "Accept: */*\r\n"); - fprintf(fin, "Connection: close\r\n"); +#endif + fetch_printf(fin, ":%u", portnum); + fetch_printf(fin, "\r\n"); + fetch_printf(fin, "Accept: */*\r\n"); + fetch_printf(fin, "Connection: close\r\n"); if (restart_point) { fputs(leading, ttyout); - fprintf(fin, "Range: bytes=" LLF "-\r\n", + fprintf(ttyout, "Range: bytes=" LLF "-\r\n", (LLT)restart_point); fprintf(ttyout, "restarting at " LLF, (LLT)restart_point); @@ -800,12 +1387,12 @@ fetch_url(const char *url, const char *p hasleading++; } if (flushcache) - fprintf(fin, "Cache-Control: no-cache\r\n"); + fetch_printf(fin, "Cache-Control: no-cache\r\n"); } if ((useragent=getenv("FTPUSERAGENT")) != NULL) { - fprintf(fin, "User-Agent: %s\r\n", useragent); + fetch_printf(fin, "User-Agent: %s\r\n", useragent); } else { - fprintf(fin, "User-Agent: %s/%s\r\n", + fetch_printf(fin, "User-Agent: %s/%s\r\n", FTP_PRODUCT, FTP_VERSION); } if (wwwauth) { @@ -815,7 +1402,7 @@ fetch_url(const char *url, const char *p leading = ", "; hasleading++; } - fprintf(fin, "Authorization: %s\r\n", wwwauth); + fetch_printf(fin, "Authorization: %s\r\n", wwwauth); } if (proxyauth) { if (verbose) { @@ -824,18 +1411,18 @@ fetch_url(const char *url, const char *p leading = ", "; hasleading++; } - fprintf(fin, "Proxy-Authorization: %s\r\n", proxyauth); + fetch_printf(fin, "Proxy-Authorization: %s\r\n", proxyauth); } if (verbose && hasleading) fputs(")\n", ttyout); - fprintf(fin, "\r\n"); - if (fflush(fin) == EOF) { + fetch_printf(fin, "\r\n"); + if (fetch_flush(fin) == EOF) { warn("Writing HTTP request"); goto cleanup_fetch_url; } /* Read the response */ - len = get_line(fin, buf, sizeof(buf), &errormsg); + len = fetch_getline(fin, buf, sizeof(buf), &errormsg); if (len < 0) { if (*errormsg == '\n') errormsg++; @@ -859,7 +1446,7 @@ fetch_url(const char *url, const char *p /* Read the rest of the header. */ while (1) { - len = get_line(fin, buf, sizeof(buf), &errormsg); + len = fetch_getline(fin, buf, sizeof(buf), &errormsg); if (len < 0) { if (*errormsg == '\n') errormsg++; @@ -1147,7 +1734,7 @@ fetch_url(const char *url, const char *p lastchunk = 0; /* read chunk-size */ if (ischunked) { - if (fgets(xferbuf, bufsize, fin) == NULL) { + if (fetch_getln(xferbuf, bufsize, fin) == NULL) { warnx("Unexpected EOF reading chunk-size"); goto cleanup_fetch_url; } @@ -1200,7 +1787,7 @@ fetch_url(const char *url, const char *p if (ischunked) bufrem = MIN(chunksize, bufrem); while (bufrem > 0) { - flen = fread(xferbuf, sizeof(char), + flen = fetch_read(xferbuf, sizeof(char), MIN((off_t)bufsize, bufrem), fin); if (flen <= 0) goto chunkdone; @@ -1239,7 +1826,7 @@ fetch_url(const char *url, const char *p /* read CRLF after chunk*/ chunkdone: if (ischunked) { - if (fgets(xferbuf, bufsize, fin) == NULL) { + if (fetch_getln(xferbuf, bufsize, fin) == NULL) { warnx("Unexpected EOF reading chunk CRLF"); goto cleanup_fetch_url; } @@ -1259,7 +1846,7 @@ fetch_url(const char *url, const char *p (void)putc('#', ttyout); (void)putc('\n', ttyout); } - if (ferror(fin)) { + if (fetch_error(fin)) { warn("Reading file"); goto cleanup_fetch_url; } @@ -1296,7 +1883,7 @@ fetch_url(const char *url, const char *p if (oldintp) (void)xsignal(SIGPIPE, oldintp); if (fin != NULL) - fclose(fin); + fetch_close(fin); else if (s != -1) close(s); if (closefunc != NULL && fout != NULL) @@ -1728,7 +2315,11 @@ go_fetch(const char *url) /* * Check for file:// and http:// URLs. */ - if (STRNEQUAL(url, HTTP_URL) || STRNEQUAL(url, FILE_URL)) + if (STRNEQUAL(url, HTTP_URL) +#ifdef WITH_SSL + || STRNEQUAL(url, HTTPS_URL) +#endif + || STRNEQUAL(url, FILE_URL)) return (fetch_url(url, NULL, NULL, NULL)); /* Index: ftp_var.h =================================================================== RCS file: /cvsroot/src/usr.bin/ftp/ftp_var.h,v retrieving revision 1.81 diff -u -p -r1.81 ftp_var.h --- ftp_var.h 12 Apr 2009 10:18:52 -0000 1.81 +++ ftp_var.h 4 Jun 2012 15:08:22 -0000 @@ -177,6 +177,7 @@ enum { #define FTP_PORT 21 /* default if ! getservbyname("ftp/tcp") */ #define HTTP_PORT 80 /* default if ! getservbyname("http/tcp") */ +#define HTTPS_PORT 443 /* default if ! getservbyname("https/tcp") */ #ifndef GATE_PORT #define GATE_PORT 21 /* default if ! getservbyname("ftpgate/tcp") */ #endif @@ -273,6 +274,9 @@ GLOBAL char *username; /* name of user 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 *httpsport; /* port number to use for HTTPS connections */ +#endif GLOBAL const char *gateport; /* port number to use for gateftp connections */ GLOBAL struct addrinfo *bindai; /* local address to bind as */ Index: main.c =================================================================== RCS file: /cvsroot/src/usr.bin/ftp/main.c,v retrieving revision 1.120 diff -u -p -r1.120 main.c --- main.c 10 Dec 2011 05:53:58 -0000 1.120 +++ main.c 4 Jun 2012 15:08:22 -0000 @@ -150,6 +150,9 @@ main(int volatile argc, char **volatile ftpport = "ftp"; httpport = "http"; +#ifdef WITH_SSL + httpsport = "https"; +#endif gateport = NULL; cp = getenv("FTPSERVERPORT"); if (cp != NULL) @@ -1044,6 +1047,9 @@ usage(void) " [[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); }