From f62e5228fdcec4430bf7e9c67b226081a32b3344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Sun, 12 Jul 1998 22:34:40 +0000 Subject: [PATCH] Base64 code (and the MIT copyright) moved to http.c FTP STORe and APPEnd added. FTP proxy support added (untested). --- lib/libfetch/base64.c | 90 ---------------------- lib/libfetch/ftp.c | 139 +++++++++++++++------------------ lib/libfetch/http.c | 174 ++++++++++++++++++++++++++++++++++++++---- 3 files changed, 223 insertions(+), 180 deletions(-) delete mode 100644 lib/libfetch/base64.c diff --git a/lib/libfetch/base64.c b/lib/libfetch/base64.c deleted file mode 100644 index fcb628c79548..000000000000 --- a/lib/libfetch/base64.c +++ /dev/null @@ -1,90 +0,0 @@ -/*- - * Copyright 1997 Massachusetts Institute of Technology - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby - * granted, provided that both the above copyright notice and this - * permission notice appear in all copies, that both the above - * copyright notice and this permission notice appear in all - * supporting documentation, and that the name of M.I.T. not be used - * in advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. M.I.T. makes - * no representations about the suitability of this software for any - * purpose. It is provided "as is" without express or implied - * warranty. - * - * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS - * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT - * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: util.c,v 1.6 1998/02/20 05:08:53 jb Exp $ - */ - -#include - -/* - * Not much left of the original MIT code, but it's still derived from it - * so I'll keep their copyright. This is taken from util.c in MIT fetch. - * - * -- DES 1998/05/22 - */ - -/* - * Implement the `base64' encoding as described in RFC 1521. - */ -static const char base64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -int -fprint64(FILE *f, const unsigned char *buf) -{ - int len = 0, l = 0; - unsigned int tmp; - - while (buf[len]) - len++; - - while (len >= 3) { - tmp = buf[0] << 16 | buf[1] << 8 | buf[2]; - fprintf(f, "%c%c%c%c", - base64[(tmp >> 18) & 077], - base64[(tmp >> 12) & 077], - base64[(tmp >> 6) & 077], - base64[tmp & 077]); - len -= 3; - buf += 3; - l += 4; - } - - /* RFC 1521 enumerates these three possibilities... */ - switch(len) { - case 2: - tmp = buf[0] << 16 | buf[1] << 8; - fprintf(f, "%c%c%c=", - base64[(tmp >> 18) & 077], - base64[(tmp >> 12) & 077], - base64[(tmp >> 6) & 077]); - l += 4; - break; - case 1: - tmp = buf[0] << 16; - fprintf(f, "%c%c==", - base64[(tmp >> 18) & 077], - base64[(tmp >> 12) & 077]); - l += 4; - break; - case 0: - break; - } - - return l; -} diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c index 9f93297d6de1..b38a4e714898 100644 --- a/lib/libfetch/ftp.c +++ b/lib/libfetch/ftp.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: ftp.c,v 1.1.1.1 1998/07/09 16:52:42 des Exp $ + * $Id: ftp.c,v 1.3 1998/07/11 21:29:08 des Exp $ */ /* @@ -190,10 +190,10 @@ _ftp_cmd(FILE *f, char *fmt, ...) } /* - * Retrieve file + * Transfer file */ static FILE * -_ftp_retrieve(FILE *cf, char *file, int pasv) +_ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) { struct sockaddr_in sin; int sd = -1, l; @@ -252,7 +252,7 @@ _ftp_retrieve(FILE *cf, char *file, int pasv) goto sysouch; /* make the server initiate the transfer */ - if (_ftp_cmd(cf, "RETR %s" ENDL, s) != FTP_OPEN_DATA_CONNECTION) + if (_ftp_cmd(cf, "%s %s" ENDL, oper, s) != FTP_OPEN_DATA_CONNECTION) goto ouch; } else { @@ -281,7 +281,7 @@ _ftp_retrieve(FILE *cf, char *file, int pasv) goto ouch; /* make the server initiate the transfer */ - if (_ftp_cmd(cf, "RETR %s" ENDL, s) != FTP_OPEN_DATA_CONNECTION) + if (_ftp_cmd(cf, "%s %s" ENDL, oper, s) != FTP_OPEN_DATA_CONNECTION) goto ouch; /* accept the incoming connection and go to town */ @@ -291,7 +291,7 @@ _ftp_retrieve(FILE *cf, char *file, int pasv) sd = d; } - if ((df = fdopen(sd, "r")) == NULL) + if ((df = fdopen(sd, mode)) == NULL) goto sysouch; return df; @@ -302,34 +302,39 @@ _ftp_retrieve(FILE *cf, char *file, int pasv) return NULL; } -/* - * Store file - */ -static FILE * -_ftp_store(FILE *cf, char *file, int pasv) -{ - fprintf(stderr, "_ftp_store: not implemented yet.\n"); - - cf = cf; - file = file; - pasv = pasv; - return NULL; -} - /* * Log on to FTP server */ static FILE * _ftp_connect(char *host, int port, char *user, char *pwd) { - int sd, e; + int sd, e, pp = FTP_DEFAULT_PORT; + char *p, *q; FILE *f; - /* establish control connection */ - if ((sd = fetchConnect(host, port)) < 0) { + /* check for proxy */ + if ((p = getenv("FTP_PROXY")) != NULL) { + if ((q = strchr(p, ':')) != NULL) { + /* XXX check that it's a valid number */ + pp = atoi(q+1); + } + if (q) + *q = 0; + sd = fetchConnect(p, pp); + if (q) + *q = ':'; + } else { + /* no proxy, go straight to target */ + sd = fetchConnect(host, port); + } + + /* check connection */ + if (sd < 0) { _ftp_syserr(); return NULL; } + + /* streams make life easier */ if ((f = fdopen(sd, "r+")) == NULL) { _ftp_syserr(); goto ouch; @@ -340,20 +345,32 @@ _ftp_connect(char *host, int port, char *user, char *pwd) goto fouch; /* send user name and password */ - e = _ftp_cmd(f, "USER %s" ENDL, user); - if (e == FTP_NEED_PASSWORD) /* server requested a password */ + if (!user || !*user) + user = FTP_ANONYMOUS_USER; + e = p ? _ftp_cmd(f, "USER %s@%s@%d" ENDL, user, host, port) + : _ftp_cmd(f, "USER %s" ENDL, user); + + /* did the server request a password? */ + if (e == FTP_NEED_PASSWORD) { + if (!pwd || !*pwd) + pwd = FTP_ANONYMOUS_PASSWORD; e = _ftp_cmd(f, "PASS %s" ENDL, pwd); - if (e == FTP_NEED_ACCOUNT) /* server requested an account */ + } + + /* did the server request an account? */ + if (e == FTP_NEED_ACCOUNT) /* help! */ ; - if (e != FTP_LOGGED_IN) /* won't let us near the WaReZ */ + + /* we should be done by now */ + if (e != FTP_LOGGED_IN) goto fouch; /* might as well select mode and type at once */ #ifdef FTP_FORCE_STREAM_MODE - if (_ftp_cmd(f, "MODE S" ENDL) != FTP_OK) + if (_ftp_cmd(f, "MODE S" ENDL) != FTP_OK) /* default is S */ goto ouch; #endif - if (_ftp_cmd(f, "TYPE I" ENDL) != FTP_OK) + if (_ftp_cmd(f, "TYPE I" ENDL) != FTP_OK) /* default is A */ goto ouch; /* done */ @@ -390,19 +407,15 @@ _ftp_isconnected(url_t *url) && (url->port == cached_host.port)); } -FILE * -fetchGetFTP(url_t *url, char *flags) +/* + * FTP session + */ +static FILE * +fetchXxxFTP(url_t *url, char *oper, char *mode, char *flags) { FILE *cf = NULL; int e; -#ifdef DEFAULT_TO_ANONYMOUS - if (!url->user[0]) { - strcpy(url->user, FTP_ANONYMOUS_USER); - strcpy(url->pwd, FTP_ANONYMOUS_PASSWORD); - } -#endif - /* set default port */ if (!url->port) url->port = FTP_DEFAULT_PORT; @@ -427,50 +440,22 @@ fetchGetFTP(url_t *url, char *flags) } /* initiate the transfer */ - return _ftp_retrieve(cf, url->doc, (flags && strchr(flags, 'p'))); + return _ftp_transfer(cf, oper, url->doc, mode, (flags && strchr(flags, 'p'))); } /* - * Upload a file. - * Hmmm, that's almost an exact duplicate of the above... + * Itsy bitsy teeny weenie */ +FILE * +fetchGetFTP(url_t *url, char *flags) +{ + return fetchXxxFTP(url, "RETR", "r", flags); +} + FILE * fetchPutFTP(url_t *url, char *flags) { - FILE *cf = NULL; - int e; - -#ifdef DEFAULT_TO_ANONYMOUS - if (!url->user[0]) { - strcpy(url->user, FTP_ANONYMOUS_USER); - strcpy(url->pwd, FTP_ANONYMOUS_PASSWORD); - } -#endif - - /* set default port */ - if (!url->port) - url->port = htons(FTP_DEFAULT_PORT); - - /* try to use previously cached connection */ - if (_ftp_isconnected(url)) { - fprintf(cached_socket, "PWD" ENDL); - _ftp_chkerr(cached_socket, &e); - if (e > 0) - cf = cached_socket; - } - - /* connect to server */ - if (!cf) { - cf = _ftp_connect(url->host, url->port, url->user, url->pwd); - if (!cf) - return NULL; - if (cached_socket) - _ftp_disconnect(cached_socket); - cached_socket = cf; - memcpy(&cached_host, url, sizeof(url_t)); - } - - - /* initiate the transfer */ - return _ftp_store(cf, url->doc, (flags && strchr(flags, 'p'))); + if (flags && strchr(flags, 'a')) + return fetchXxxFTP(url, "APPE", "w", flags); + else return fetchXxxFTP(url, "STOR", "w", flags); } diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c index 3178e2a0d833..68b35254edd3 100644 --- a/lib/libfetch/http.c +++ b/lib/libfetch/http.c @@ -25,9 +25,41 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: http.c,v 1.1.1.1 1998/07/09 16:52:41 des Exp $ + * $Id: http.c,v 1.3 1998/07/11 21:29:08 des Exp $ */ +/* + * The base64 code in this file is based on code from MIT fetch, which + * has the following copyright and license: + * + *- + * Copyright 1997 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ + #include #include #include @@ -38,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -54,8 +87,6 @@ extern char *__progname; -extern int fprint64(FILE *f, const unsigned char *buf); - #define ENDL "\r\n" struct cookie @@ -71,6 +102,9 @@ struct cookie unsigned b_len, chunksize; }; +/* + * Look up error code + */ static const char * _http_errstring(int e) { @@ -82,6 +116,29 @@ _http_errstring(int e) return p->string; } +/* + * Send a formatted line; optionally echo to terminal + */ +static int +_http_cmd(FILE *f, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(f, fmt, ap); +#ifndef NDEBUG + fprintf(stderr, "\033[1m>>> "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\033[m"); +#endif + va_end(ap); + + return 0; /* XXX */ +} + +/* + * Fill the input buffer, do chunk decoding on the fly + */ static char * _http_fillbuf(struct cookie *c) { @@ -119,6 +176,9 @@ _http_fillbuf(struct cookie *c) return c->buf; } +/* + * Read function + */ static int _http_readfn(struct cookie *c, char *buf, int len) { @@ -142,6 +202,9 @@ _http_readfn(struct cookie *c, char *buf, int len) else return pos; } +/* + * Write function + */ static int _http_writefn(struct cookie *c, const char *buf, int len) { @@ -149,6 +212,9 @@ _http_writefn(struct cookie *c, const char *buf, int len) return r ? r : -1; } +/* + * Close function + */ static int _http_closefn(struct cookie *c) { @@ -157,6 +223,9 @@ _http_closefn(struct cookie *c) return (r == EOF) ? -1 : 0; } +/* + * Extract content type from cookie + */ char * fetchContentType(FILE *f) { @@ -167,6 +236,85 @@ fetchContentType(FILE *f) return f->_cookie ? (((struct cookie *)f->_cookie)->content_type) : NULL; } +/* + * Base64 encoding + */ +int +_http_base64(char *dst, char *src, int l) +{ + static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + int t, r = 0; + + while (l >= 3) { + t = (src[0] << 16) | (src[1] << 8) | src[2]; + dst[0] = base64[(t >> 18) & 0x3f]; + dst[1] = base64[(t >> 12) & 0x3f]; + dst[2] = base64[(t >> 6) & 0x3f]; + dst[3] = base64[(t >> 0) & 0x3f]; + src += 3; l -= 3; + dst += 4; r += 4; + } + + switch (l) { + case 2: + t = (src[0] << 16) | (src[1] << 8); + dst[0] = base64[(t >> 18) & 0x3f]; + dst[1] = base64[(t >> 12) & 0x3f]; + dst[2] = base64[(t >> 6) & 0x3f]; + dst[3] = '='; + dst += 4; + r += 4; + break; + case 1: + t = src[0] << 16; + dst[0] = base64[(t >> 18) & 0x3f]; + dst[1] = base64[(t >> 12) & 0x3f]; + dst[2] = dst[3] = '='; + dst += 4; + r += 4; + break; + case 0: + break; + } + + *dst = 0; + return r; +} + +/* + * Encode username and password + */ +char * +_http_auth(char *usr, char *pwd) +{ + int len, lu, lp; + char *str, *s; + + lu = strlen(usr); + lp = strlen(pwd); + + len = (lu * 4 + 2) / 3 /* user name, round up */ + + 1 /* colon */ + + (lp * 4 + 2) / 3 /* password, round up */ + + 1; /* null */ + + if ((s = str = (char *)malloc(len)) == NULL) + return NULL; + + s += _http_base64(s, usr, lu); + *s++ = ':'; + s += _http_base64(s, pwd, lp); + *s = 0; + + return str; +} + +/* + * retrieve a file by HTTP + */ FILE * fetchGetHTTP(url_t *URL, char *flags) { @@ -220,20 +368,20 @@ fetchGetHTTP(url_t *URL, char *flags) c->real_f = f; /* send request (proxies require absolute form, so use that) */ - fprintf(f, "GET http://%s:%d/%s HTTP/1.1" ENDL, - URL->host, URL->port, URL->doc); + _http_cmd(f, "GET http://%s:%d%s HTTP/1.1" ENDL, + URL->host, URL->port, URL->doc); /* start sending headers away */ if (URL->user[0] || URL->pwd[0]) { - fprintf(f, "Authorization: Basic "); - fprint64(f, (const unsigned char *)URL->user); - fputc(':', f); - fprint64(f, (const unsigned char *)URL->pwd); - fputs(ENDL, f); + char *auth_str = _http_auth(URL->user, URL->pwd); + if (!auth_str) + goto fouch; + _http_cmd(f, "Authorization: Basic %s" ENDL, auth_str); + free(auth_str); } - fprintf(f, "Host: %s:%d" ENDL, URL->host, URL->port); - fprintf(f, "User-Agent: %s " _LIBFETCH_VER ENDL, __progname); - fprintf(f, "Connection: close" ENDL ENDL); + _http_cmd(f, "Host: %s:%d" ENDL, URL->host, URL->port); + _http_cmd(f, "User-Agent: %s " _LIBFETCH_VER ENDL, __progname); + _http_cmd(f, "Connection: close" ENDL ENDL); /* get response */ if ((ln = fgetln(f, &len)) == NULL)