Subject: Re: HTTPS support patch for /usr/bin/ftp
To: YAMAMOTO Shigeru <shigeru@iij.ad.jp>
From: Gary Thorpe <gathorpe79@yahoo.com>
List: current-users
Date: 07/29/2003 14:22:51
Why does an *ftp client* need http/https support? Or does this add SSL
support to the ftp client? Are there any ftp servers which support SSL?
If you want to download from HTTP/HTTPS servers, shouldn't you use
another tool (like wget), or is there no such tool in the base system?
--- YAMAMOTO Shigeru <shigeru@iij.ad.jp> wrote: >
> Hi, all,
>
> I make a patch to support HTTPS for /usr/bin/ftp.
> It is quick hack.
>
> Please try and test it.
>
> Thanks,
> -------
> YAMAMOTO Shigeru <shigeru@iij.ad.jp>
> > --- Makefile.org Tue Jul 29 14:14:50 2003
> +++ Makefile Tue Jul 29 14:19:23 2003
> @@ -9,8 +9,8 @@
> #
> #CPPFLAGS+=-DGATE_SERVER=\"ftp-gw.host\" # -DGATE_PORT=21
>
> -LDADD+= -ledit -ltermcap -lutil
> -DPADD+= ${LIBEDIT} ${LIBTERMCAP} ${LIBUTIL}
> +LDADD+= -ledit -ltermcap -lutil -lssl -lcrypto
> +DPADD+= ${LIBEDIT} ${LIBTERMCAP} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO}
>
> CPPFLAGS+= -DINET6
>
> --- fetch.c.org Tue Jul 29 14:14:57 2003
> +++ fetch.c Tue Jul 29 12:21:29 2003
> @@ -71,12 +71,18 @@
> #include <time.h>
> #include <util.h>
>
> +#include <openssl/bio.h>
> +#include <openssl/ssl.h>
> +
> #include "ftp_var.h"
> #include "version.h"
>
> +extern SSL_CTX* ssl_ctx; /* SSL CTX */
> +
> typedef enum {
> UNKNOWN_URL_T=-1,
> HTTP_URL_T,
> + HTTPS_URL_T,
> FTP_URL_T,
> FILE_URL_T,
> CLASSIC_URL_T
> @@ -99,6 +105,7 @@
> #define FILE_URL "file://" /* file URL prefix */
> #define FTP_URL "ftp://" /* ftp URL prefix */
> #define HTTP_URL "http://" /* http URL prefix */
> +#define HTTPS_URL "https://" /* https URL prefix */
>
>
> /*
> @@ -300,6 +307,11 @@
> *type = HTTP_URL_T;
> *portnum = HTTP_PORT;
> tport = httpport;
> + } else if (strncasecmp(url, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0)
> {
> + url += sizeof(HTTPS_URL) - 1;
> + *type = HTTPS_URL_T;
> + *portnum = HTTPS_PORT;
> + tport = httpsport;
> } else if (strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0) {
> url += sizeof(FTP_URL) - 1;
> *type = FTP_URL_T;
> @@ -412,6 +424,170 @@
> return (0);
> }
>
> +static
> +int
> +isescaped(const char* sp, char* p, int esc) {
> + int result = 0;
> +
> + if (esc == '\0') {
> + result = 1;
> + }
> + else {
> + size_t ne;
> + char* cp;
> +
> + for (ne = 0, cp = p; --cp >= sp && *cp == esc; ne ++) {
> + continue;
> + }
> +
> + result = ((ne & 1) != 0);
> + }
> +
> + return(result);
> +}
> +
> +static
> +char*
> +BIO_parseln(BIO* bio, size_t* len, size_t* lineno, const char
> delim[3], int flags) {
> + static const char dstr[3] = { '\\', '\\', '#' };
> + int cnt = 1;
> + char esc, con, com;
> + char nl;
> + char* buffer = NULL;
> + size_t length = 0;
> +
> + if (delim == NULL) {
> + delim = dstr;
> + }
> +
> + esc = delim[0];
> + con = delim[1];
> + com = delim[2];
> +
> + nl = '\n';
> +
> + cnt = 1;
> + while (cnt) {
> + char read_buffer[BUFSIZ];
> + size_t read_length = 0;
> +
> + cnt = 0;
> +
> + read_length = BIO_gets(bio, read_buffer, sizeof(read_buffer));
> + if (read_length > 0) {
> + if (read_length < sizeof(read_buffer) || read_buffer[read_length
> - 1] == nl) {
> + if (lineno) {
> + (*lineno) ++;
> + }
> + }
> +
> + if (read_length && com) {
> + char* cp;
> +
> + for (cp = read_buffer; cp < read_buffer + read_length; cp ++) {
> + if (*cp == com && !isescaped(read_buffer, cp, esc)) {
> + read_length = cp - read_buffer;
> + cnt = (read_length == 0 && buffer == NULL);
> + break;
> + }
> + }
> + }
> +
> + if (read_length && nl) {
> + char* cp;
> +
> + cp = &(read_buffer[read_length - 1]);
> + if (*cp == nl) {
> + read_length --;
> + }
> + }
> +
> + if (read_length && con) {
> + char* cp;
> +
> + cp = &(read_buffer[read_length - 1]);
> + if (*cp == con && !isescaped(read_buffer, cp, esc)) {
> + read_length --;
> + cnt = 1;
> + }
> + }
> +
> + if (read_length == 0 && buffer != NULL) {
> + continue;
> + }
> + else {
> + char* new;
> +
> + if ((new = realloc(buffer, length + read_length + 1)) == NULL) {
> + free(buffer);
> + }
> +
> + buffer = new;
> +
> + memcpy(buffer + length, read_buffer, read_length);
> + length += read_length;
> + buffer[length] = '\0';
> + }
> + }
> + }
> +
> + if ((flags & FPARSELN_UNESCALL) != 0 && esc && buffer != NULL &&
> strchr(buffer, esc) != NULL) {
> + char* ptr;
> + char* cp;
> +
> + ptr = cp = buffer;
> + while (cp[0] != '\0') {
> + int skipesc;
> +
> + while (cp[0] != '\0' && cp[0] != esc) {
> + *ptr = *cp;
> + ptr ++;
> + cp ++;
> + }
> +
> + if (cp[0] == '\0' || cp[1] == '\0') {
> + break;
> + }
> +
> + skipesc = 0;
> + if (cp[1] == com) {
> + skipesc += (flags & FPARSELN_UNESCCOMM);
> + }
> + if (cp[1] == con) {
> + skipesc += (flags & FPARSELN_UNESCCONT);
> + }
> + if (cp[1] == esc) {
> + skipesc += (flags & FPARSELN_UNESCESC);
> + }
> + if (cp[1] == com && cp[1] != con && cp[1] != esc) {
> + skipesc += (flags & FPARSELN_UNESCREST);
> + }
> +
> + if (skipesc) {
> + cp ++;
> + }
> + else {
> + *ptr = *cp;
> + ptr ++;
> + cp ++;
> + }
> +
> + *ptr = *cp;
> + ptr ++;
> + cp ++;
> + }
> +
> + *ptr = '\0';
> + length = strlen(buffer);
> + }
> +
> + if (len) {
> + (*len) = length;
> + }
> +
> + return(buffer);
> +}
> +
> sigjmp_buf httpabort;
>
> /*
> @@ -441,14 +617,16 @@
> char *puser, *ppass;
> off_t hashbytes, rangestart, rangeend, entitylen;
> int (*closefunc)(FILE *);
> - FILE *fin, *fout;
> + BIO* bio;
> + FILE *fout;
> time_t mtime;
> url_t urltype;
> in_port_t portnum;
>
> oldintr = oldintp = NULL;
> closefunc = NULL;
> - fin = fout = NULL;
> + bio = (BIO*)0;
> + fout = NULL;
> s = -1;
> buf = savefile = NULL;
> auth = location = message = NULL;
> @@ -458,7 +636,7 @@
>
> #ifdef __GNUC__ /* shut up gcc warnings */
> (void)&closefunc;
> - (void)&fin;
> + (void)&bio;
> (void)&fout;
> (void)&buf;
> (void)&savefile;
> @@ -487,7 +665,7 @@
> rval = fetch_ftp(url);
> goto cleanup_fetch_url;
> }
> - if (urltype != HTTP_URL_T || outfile == NULL) {
> + if (urltype != HTTP_URL_T || urltype != HTTPS_URL_T || outfile ==
> NULL) {
> warnx("Invalid URL (no file after host) `%s'", url);
> goto cleanup_fetch_url;
> }
> @@ -527,18 +705,21 @@
> restart_point = sb.st_size;
> }
> if (urltype == FILE_URL_T) { /* file:// URLs */
> + int fd;
> +
> direction = "copied";
> - fin = fopen(decodedpath, "r");
> - if (fin == NULL) {
> + bio = BIO_new_file(decodedpath, "r");
> + if (!bio) {
> warn("Cannot open file `%s'", decodedpath);
> goto cleanup_fetch_url;
> }
> - if (fstat(fileno(fin), &sb) == 0) {
> + BIO_get_fd(bio, &fd);
> + if (fstat(fd, &sb) == 0) {
> mtime = sb.st_mtime;
> filesize = sb.st_size;
> }
> if (restart_point) {
> - if (lseek(fileno(fin), restart_point, SEEK_SET) < 0) {
> + if (BIO_seek(bio, restart_point) < 0) {
> warn("Can't lseek to restart `%s'",
> decodedpath);
> goto cleanup_fetch_url;
> @@ -556,7 +737,7 @@
> int hasleading;
>
> if (proxyenv == NULL) {
> - if (urltype == HTTP_URL_T)
> + if (urltype == HTTP_URL_T || urltype == HTTPS_URL_T)
> proxyenv = getoptionvalue("http_proxy");
> else if (urltype == FTP_URL_T)
> proxyenv = getoptionvalue("ftp_proxy");
> @@ -613,6 +794,7 @@
> goto cleanup_fetch_url;
>
> if ((purltype != HTTP_URL_T
> + && purltype != HTTPS_URL_T
> && purltype != FTP_URL_T) ||
> EMPTYSTRING(phost) ||
> (! EMPTYSTRING(ppath)
> @@ -698,7 +880,54 @@
> goto cleanup_fetch_url;
> }
>
> - fin = fdopen(s, "r+");
> + bio = BIO_new(BIO_s_socket());
> + if (!bio) {
> + warn("Can't create BIO for socket");
> + goto cleanup_fetch_url;
> + }
> + else {
> + BIO_set_fd(bio, s, BIO_CLOSE);
> + }
> +
> + if (urltype == HTTPS_URL_T) {
> + BIO* new;
> + SSL* ssl;
> +
> + ssl = SSL_new(ssl_ctx);
> + if (!ssl) {
> + warn("Can't create SSL for HTTPS");
> + goto cleanup_fetch_url;
> + }
> + else {
> + SSL_set_connect_state(ssl);
> + }
> +
> + new = BIO_new(BIO_f_ssl());
> + if (new) {
> + warn("Can't create BIO for SSL");
> + goto cleanup_fetch_url;
> + }
> + else {
> + BIO_set_ssl(new, ssl, BIO_CLOSE);
> + BIO_push(new, bio);
> + bio = new;
> + }
> + }
> +
> + {
> + BIO* new;
> +
> + new = BIO_new(BIO_f_buffer());
> + if (new) {
> + warn("Can't create buffered BIO");
> + goto cleanup_fetch_url;
> + }
> + else {
> + BIO_push(new, bio);
> + bio = new;
> + }
> + }
> +
> /*
> * Construct and send the request.
> */
> @@ -713,11 +942,11 @@
> leading = ", ";
> hasleading++;
> }
> - fprintf(fin, "GET %s HTTP/1.0\r\n", path);
> + BIO_printf(bio, "GET %s HTTP/1.0\r\n", path);
> if (flushcache)
> - fprintf(fin, "Pragma: no-cache\r\n");
> + BIO_printf(bio, "Pragma: no-cache\r\n");
> } else {
> - fprintf(fin, "GET %s HTTP/1.1\r\n", path);
> + BIO_printf(bio, "GET %s HTTP/1.1\r\n", path);
> if (strchr(host, ':')) {
> char *h, *p;
>
> @@ -730,18 +959,18 @@
> (p = strchr(h, '%')) != NULL) {
> *p = '\0';
> }
> - fprintf(fin, "Host: [%s]", h);
> + BIO_printf(bio, "Host: [%s]", h);
> free(h);
> } else
> - fprintf(fin, "Host: %s", host);
> + BIO_printf(bio, "Host: %s", host);
> if (portnum != HTTP_PORT)
> - fprintf(fin, ":%u", portnum);
> - fprintf(fin, "\r\n");
> - fprintf(fin, "Accept: */*\r\n");
> - fprintf(fin, "Connection: close\r\n");
> + BIO_printf(bio, ":%u", portnum);
> + BIO_printf(bio, "\r\n");
> + BIO_printf(bio, "Accept: */*\r\n");
> + BIO_printf(bio, "Connection: close\r\n");
> if (restart_point) {
> fputs(leading, ttyout);
> - fprintf(fin, "Range: bytes=" LLF "-\r\n",
> + BIO_printf(bio, "Range: bytes=" LLF "-\r\n",
> (LLT)restart_point);
> fprintf(ttyout, "restarting at " LLF,
> (LLT)restart_point);
> @@ -749,9 +978,9 @@
> hasleading++;
> }
> if (flushcache)
> - fprintf(fin, "Cache-Control: no-cache\r\n");
> + BIO_printf(bio, "Cache-Control: no-cache\r\n");
> }
> - fprintf(fin, "User-Agent: %s/%s\r\n", FTP_PRODUCT, FTP_VERSION);
> + BIO_printf(bio, "User-Agent: %s/%s\r\n", FTP_PRODUCT,
> FTP_VERSION);
> if (wwwauth) {
> if (verbose) {
> fprintf(ttyout, "%swith authorization",
> @@ -759,7 +988,7 @@
> leading = ", ";
> hasleading++;
> }
> - fprintf(fin, "Authorization: %s\r\n", wwwauth);
> + BIO_printf(bio, "Authorization: %s\r\n", wwwauth);
> }
> if (proxyauth) {
> if (verbose) {
> @@ -768,18 +997,18 @@
> leading = ", ";
> hasleading++;
> }
> - fprintf(fin, "Proxy-Authorization: %s\r\n", proxyauth);
> + BIO_printf(bio, "Proxy-Authorization: %s\r\n", proxyauth);
> }
> if (verbose && hasleading)
> fputs(")\n", ttyout);
> - fprintf(fin, "\r\n");
> - if (fflush(fin) == EOF) {
> + BIO_printf(bio, "\r\n");
> + if (BIO_flush(bio) == EOF) {
> warn("Writing HTTP request");
> goto cleanup_fetch_url;
> }
>
> /* Read the response */
> - if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) {
> + if ((buf = BIO_parseln(bio, &len, NULL, "\0\0\0", 0)) == NULL) {
> warn("Receiving HTTP reply");
> goto cleanup_fetch_url;
> }
> @@ -802,7 +1031,7 @@
> /* Read the rest of the header. */
> FREEPTR(buf);
> while (1) {
> - if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0))
> + if ((buf = BIO_parseln(bio, &len, NULL, "\0\0\0", 0))
> == NULL) {
> warn("Receiving HTTP reply");
> goto cleanup_fetch_url;
> @@ -1114,7 +1343,7 @@
> chunksize = 0;
> /* read chunksize */
> if (ischunked) {
> - if (fgets(xferbuf, bufsize, fin) == NULL) {
> + if (BIO_gets(bio, xferbuf, bufsize) == NULL) {
> warnx("Unexpected EOF reading chunksize");
> goto cleanup_fetch_url;
> }
> @@ -1149,8 +1378,7 @@
> if (ischunked)
> bufrem = MIN(chunksize, bufrem);
> while (bufrem > 0) {
> - len = fread(xferbuf, sizeof(char),
> - MIN(bufsize, bufrem), fin);
> + len = BIO_read(bio, xferbuf, (sizeof(char) * MIN(bufsize,
> bufrem)));
> if (len <= 0)
> goto chunkdone;
> bytes += len;
> @@ -1188,7 +1416,7 @@
> /* read CRLF after chunk*/
> chunkdone:
> if (ischunked) {
> - if (fgets(xferbuf, bufsize, fin) == NULL)
> + if (BIO_gets(bio, xferbuf, bufsize) == NULL)
> break;
> if (strcmp(xferbuf, "\r\n") != 0) {
> warnx("Unexpected data following chunk");
> @@ -1201,10 +1429,12 @@
> (void)putc('#', ttyout);
> (void)putc('\n', ttyout);
> }
> +#if 0 /* XXX: how to re-write? */
> if (ferror(fin)) {
> warn("Reading file");
> goto cleanup_fetch_url;
> }
> +#endif
> progressmeter(1);
> bytes = 0;
> (void)fflush(fout);
> @@ -1237,8 +1467,8 @@
> (void)xsignal(SIGINT, oldintr);
> if (oldintp)
> (void)xsignal(SIGPIPE, oldintp);
> - if (fin != NULL)
> - fclose(fin);
> + if (!bio)
> + BIO_free_all(bio);
> else if (s != -1)
> close(s);
> if (closefunc != NULL && fout != NULL)
> @@ -1651,6 +1881,7 @@
> * Check for file:// and http:// URLs.
> */
> if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 ||
> + strncasecmp(url, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0 ||
> strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0)
> return (fetch_url(url, NULL, NULL, NULL));
>
> --- ftp_var.h.org Tue Jul 29 14:15:05 2003
> +++ ftp_var.h Tue Jul 29 11:40:22 2003
> @@ -172,6 +172,14 @@
> FEAT_max
> };
>
> +struct CA_Info {
> + char* path;
> + char* rootca;
> + char* privatekey;
> + char* certificate;
> +};
> +typedef struct CA_Info CA_Info_t;
> +
>
> /*
> * Global defines
> @@ -184,6 +192,7 @@
>
> #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
> @@ -279,7 +288,10 @@
> GLOBAL sa_family_t family; /* address family to use for connections
> */
> GLOBAL char *ftpport; /* port number to use for FTP connections */
> GLOBAL char *httpport; /* port number to use for HTTP connections */
> +GLOBAL char *httpsport; /* port number to use for HTTPS connections
> */
> GLOBAL char *gateport; /* port number to use for gateftp connections
> */
> +
> +GLOBAL CA_Info_t CAinfo; /* CA path, certificate and private key
> files */
>
> GLOBAL char *outfile; /* filename to output URLs to */
> GLOBAL int restartautofetch; /* restart auto-fetch */
> --- main.c.org Tue Jul 29 14:18:18 2003
> +++ main.c Tue Jul 29 11:42:04 2003
> @@ -129,6 +129,8 @@
> #include <unistd.h>
> #include <locale.h>
>
> +#include <openssl/ssl.h>
> +
> #define GLOBAL /* force GLOBAL decls in ftp_var.h to be declared */
> #include "ftp_var.h"
>
> @@ -137,9 +139,20 @@
> #define NO_PROXY "no_proxy" /* env var with list of non-proxied
> * hosts, comma or space separated */
>
> +GLOBAL SSL_CTX* ssl_ctx = (SSL_CTX*)0;
> +
> static void setupoption(char *, char *, char *);
> int main(int, char *[]);
>
> +static
> +void
> +free_ssl_ctx(void) {
> + if (ssl_ctx) {
> + SSL_CTX_free(ssl_ctx);
> + ssl_ctx = (SSL_CTX*)0;
> + }
> +}
> +
> int
> main(int argc, char *argv[])
> {
> @@ -152,6 +165,7 @@
>
> ftpport = "ftp";
> httpport = "http";
> + httpsport = "https";
> gateport = NULL;
> cp = getenv("FTPSERVERPORT");
> if (cp != NULL)
> @@ -280,6 +294,12 @@
> }
> }
>
> + /* set default key and CAs for SSL */
> + CAinfo.path = getenv("SSL_CAPATH");
> + CAinfo.rootca = getenv("SSL_ROOTCA");
> + CAinfo.privatekey = getenv("SSL_PRIVATEKEY");
> + CAinfo.certificate = getenv("SSL_CERTIFICATE");
> +
> while ((ch = getopt(argc, argv, "46AadefginN:o:pP:r:RtT:u:vV")) !=
> -1) {
> switch (ch) {
> case '4':
> @@ -490,6 +510,24 @@
> (void)&argc;
> (void)&argv;
> #endif
> +
> + /* initialize SSL CTX */
> + SSL_library_init();
> + SSL_load_error_strings();
> +
> + OpenSSL_add_ssl_algorithms();
> + ssl_ctx = SSL_CTX_new(SSLv23_client_method());
> +
> + if (CAinfo.certificate) {
> + SSL_CTX_use_certificate_chain_file(ssl_ctx, CAinfo.certificate);
> + }
> + if (CAinfo.privatekey) {
> + SSL_CTX_use_PrivateKey_file(ssl_ctx, CAinfo.privatekey,
> SSL_FILETYPE_PEM);
> + }
> + if (CAinfo.path || CAinfo.rootca) {
> + SSL_CTX_load_verify_locations(ssl_ctx, CAinfo.rootca,
> CAinfo.path);
> + }
> + atexit(free_ssl_ctx);
>
> if (argc > 0) {
> if (isupload) {
>
______________________________________________________________________
Post your free ad now! http://personals.yahoo.ca