Re: (2) HTTP basic authentication for ftp(1) (RFC 2617)
On Mon, Aug 13, 2012 at 03:02:22AM +0200, Alexander Hall wrote: On 08/06/12 22:56, Christiano F. Haesbaert wrote: Please ignore the other thread, it takes ages for me to open my sent box over gprs, so I'm opening a new one. Index: fetch.c === RCS file: /cvs/src/usr.bin/ftp/fetch.c,v retrieving revision 1.105 diff -d -u -p -r1.105 fetch.c --- fetch.c 30 Apr 2012 13:41:26 - 1.105 +++ fetch.c 6 Aug 2012 20:49:51 - @@ -177,7 +177,7 @@ url_get(const char *origline, const char { char pbuf[NI_MAXSERV], hbuf[NI_MAXHOST], *cp, *portnum, *path, ststr[4]; char *hosttail, *cause = unknown, *newline, *host, *port, *buf = NULL; -char *epath, *redirurl, *loctail; +char *epath, *redirurl, *loctail, *h, *p; int error, i, isftpurl = 0, isfileurl = 0, isredirect = 0, rval = -1; struct addrinfo hints, *res0, *res, *ares = NULL; const char * volatile savefile; @@ -191,7 +191,7 @@ url_get(const char *origline, const char size_t len, wlen; #ifndef SMALL char *sslpath = NULL, *sslhost = NULL; -char *locbase, *full_host = NULL; +char *locbase, *full_host = NULL, *auth = NULL; const char *scheme; int ishttpsurl = 0; SSL_CTX *ssl_ctx = NULL; @@ -228,7 +228,20 @@ url_get(const char *origline, const char #endif /* !SMALL */ } else errx(1, url_get: Invalid URL '%s', newline); - +#ifndef SMALL +/* Look for auth header */ Hey halex thanks for the feedback :) - Is this safe for urls like http://some.host/path/e:mail@me/; ? - Should it be? - Should it maybe be done on the host part after the host/path separation? Not sure what the rfc's says on this. Chrome seems to accept the path I wrote above though. Hmm good point, I assumed @ was not valid on an url path, I'll check if the rfc says something, anyway, doing it after we separated the path seems like a better solution. +if (proxyenv == NULL +(!strcmp(scheme, HTTP_URL) || !strcmp(scheme, HTTPS_URL))) { +if ((p = strchr(host, '@')) != NULL) { +*p = 0; /* Kill @ */ +if ((auth = calloc(1, 64)) == NULL) Why not malloc? Also, if you allocate it at runtime, why fixed at 64? Why not make it sth like malloc((strlen(host) + 2) * 4 / 3) (well, or) calloc(4, (strlen(host) + 2) / 3) ? This makes sense, lteo did some digging and it is what freebsd and netbsd do. If I remember correctly I tried to find something about it on the RFC. +err(1, Can't allocate memory for authorization); +if (b64_ntop(host, strlen(host), auth, 64) == -1) (with appropriate fixing here ^^) +errx(1, error in base64 encoding); +host = p + 1; +} +} +#endif /* SMALL */ if (isfileurl) { path = host; } else { @@ -639,14 +652,19 @@ again: restart_point = 0; } #endif /* !SMALL */ -ftp_printf(fin, ssl, GET /%s %s\r\nHost: , epath, #ifndef SMALL The above leaves the pretty useless residue of: #endif /* !SMALL */ #ifndef SMALL Is this intentional? Whoops, no, good catch. -restart_point ? HTTP/1.1\r\nConnection: close : -#endif /* !SMALL */ -HTTP/1.0); +if (auth) { +ftp_printf(fin, ssl, +GET /%s %s\r\nAuthorization: Basic %s\r\nHost: , +epath, restart_point ? +HTTP/1.1\r\nConnection: close : HTTP/1.0, +auth); +free(auth); +} else +#endif /* SMALL */ +ftp_printf(fin, ssl, GET /%s %s\r\nHost: , epath, +HTTP/1.0); if (strchr(host, ':')) { -char *h, *p; - /* * strip off scoped address portion, since it's * local to node Index: ftp.1 === RCS file: /cvs/src/usr.bin/ftp/ftp.1,v retrieving revision 1.82 diff -d -u -p -r1.82 ftp.1 --- ftp.130 Apr 2012 13:41:26 - 1.82 +++ ftp.16 Aug 2012 20:22:14 - @@ -61,7 +61,8 @@ .Op Fl o Ar output .Op Fl s Ar srcaddr .Sm off -.No http:// Ar host Oo : Ar port +.No http:// Oo Ar user : password No @ +.Oc Ar host Oo : Ar port .Oc No / Ar file .Sm on .Ar ... @@ -71,7 +72,8 @@ .Op Fl o Ar output .Op Fl s Ar srcaddr .Sm off -.No https:// Ar host Oo : Ar port +.No https:// Oo Ar user : password No @ +.Oc Ar host Oo : Ar port .Oc No / Ar file .Sm on .Ar ... @@ -1278,12 +1280,12 @@ isn't defined, log in as .Ar user with a password
Re: (2) HTTP basic authentication for ftp(1) (RFC 2617)
I think I've hunt this down http://tools.ietf.org/html/rfc3986#section-3.3 If you follow the BNF for path, you have. path - path-absolute - segment-nz - 1*pchar - \ unreserved / pct-encoded / sub-delims / ':' / '@'. So it seems everything is allowed on path, I'll fix the diff.
Re: (2) HTTP basic authentication for ftp(1) (RFC 2617)
On Mon, Aug 13, 2012 at 04:33:40PM +0200, Christiano F. Haesbaert wrote: I think I've hunt this down http://tools.ietf.org/html/rfc3986#section-3.3 If you follow the BNF for path, you have. path - path-absolute - segment-nz - 1*pchar - \ unreserved / pct-encoded / sub-delims / ':' / '@'. So it seems everything is allowed on path, I'll fix the diff. So this addresses halex points, I tested on urls with @ and :, works fine. I still calloc and I use an extra byte since the auth string can be displayed on debug. Index: fetch.c === RCS file: /cvs/src/usr.bin/ftp/fetch.c,v retrieving revision 1.105 diff -d -u -p -r1.105 fetch.c --- fetch.c 30 Apr 2012 13:41:26 - 1.105 +++ fetch.c 13 Aug 2012 15:33:29 - @@ -177,7 +177,7 @@ url_get(const char *origline, const char { char pbuf[NI_MAXSERV], hbuf[NI_MAXHOST], *cp, *portnum, *path, ststr[4]; char *hosttail, *cause = unknown, *newline, *host, *port, *buf = NULL; - char *epath, *redirurl, *loctail; + char *epath, *redirurl, *loctail, *h, *p; int error, i, isftpurl = 0, isfileurl = 0, isredirect = 0, rval = -1; struct addrinfo hints, *res0, *res, *ares = NULL; const char * volatile savefile; @@ -191,7 +191,7 @@ url_get(const char *origline, const char size_t len, wlen; #ifndef SMALL char *sslpath = NULL, *sslhost = NULL; - char *locbase, *full_host = NULL; + char *locbase, *full_host = NULL, *auth = NULL; const char *scheme; int ishttpsurl = 0; SSL_CTX *ssl_ctx = NULL; @@ -250,6 +250,28 @@ url_get(const char *origline, const char warnx(No filename after host (use -o): %s, origline); goto cleanup_url_get; } +#ifndef SMALL + /* +* Look for auth header in host, since now host does not +* contain the path. Basic auth from RFC 2617, valid +* characters for path are in RFC 3986 section 3.3. +*/ + if (proxyenv == NULL + (!strcmp(scheme, HTTP_URL) || !strcmp(scheme, HTTPS_URL))) { + if ((p = strchr(host, '@')) != NULL) { + size_t authlen = (strlen(host) + 2) * 4 / 3 + 1; + + *p = 0; /* Kill @ */ + if ((auth = calloc(1, authlen)) == NULL) + err(1, Can't allocate memory for + authorization); + if (b64_ntop(host, strlen(host), + auth, authlen) == -1) + errx(1, error in base64 encoding); + host = p + 1; + } + } +#endif /* SMALL */ } noslash: @@ -460,8 +482,9 @@ noslash: if ((full_host = strdup(host)) == NULL) errx(1, Cannot allocate memory for hostname); if (debug) - fprintf(ttyout, host %s, port %s, path %s, save as %s.\n, - host, portnum, path, savefile); + fprintf(ttyout, host %s, port %s, path %s, + save as %s, auth %s.\n, + host, portnum, path, savefile, auth); #endif /* !SMALL */ memset(hints, 0, sizeof(hints)); @@ -638,15 +661,18 @@ again: else restart_point = 0; } -#endif /* !SMALL */ + if (auth) { + ftp_printf(fin, ssl, + GET /%s %s\r\nAuthorization: Basic %s\r\nHost: , + epath, restart_point ? + HTTP/1.1\r\nConnection: close : HTTP/1.0, + auth); + free(auth); + } else +#endif /* SMALL */ ftp_printf(fin, ssl, GET /%s %s\r\nHost: , epath, -#ifndef SMALL - restart_point ? HTTP/1.1\r\nConnection: close : -#endif /* !SMALL */ - HTTP/1.0); + HTTP/1.0); if (strchr(host, ':')) { - char *h, *p; - /* * strip off scoped address portion, since it's * local to node Index: ftp.1 === RCS file: /cvs/src/usr.bin/ftp/ftp.1,v retrieving revision 1.82 diff -d -u -p -r1.82 ftp.1 --- ftp.1 30 Apr 2012 13:41:26 - 1.82 +++ ftp.1 11 Aug 2012 20:08:00 - @@ -61,7 +61,8 @@ .Op Fl o Ar output .Op Fl s Ar srcaddr .Sm off -.No http:// Ar host Oo : Ar port +.No http:// Oo Ar user : password No @ +.Oc Ar host Oo : Ar port .Oc No / Ar file .Sm on .Ar ... @@ -71,7 +72,8 @@ .Op Fl o Ar output
Re: (2) HTTP basic authentication for ftp(1) (RFC 2617)
On 08/13/12 17:37, Christiano F. Haesbaert wrote: On Mon, Aug 13, 2012 at 04:33:40PM +0200, Christiano F. Haesbaert wrote: I think I've hunt this down http://tools.ietf.org/html/rfc3986#section-3.3 If you follow the BNF for path, you have. path - path-absolute - segment-nz - 1*pchar - \ unreserved / pct-encoded / sub-delims / ':' / '@'. So it seems everything is allowed on path, I'll fix the diff. So this addresses halex points, I tested on urls with @ and :, works fine. I still calloc and I use an extra byte since the auth string can be displayed on debug. Again, why calloc? IIRC b64_ntop() adds a trailing null. Index: fetch.c === RCS file: /cvs/src/usr.bin/ftp/fetch.c,v retrieving revision 1.105 diff -d -u -p -r1.105 fetch.c --- fetch.c 30 Apr 2012 13:41:26 - 1.105 +++ fetch.c 13 Aug 2012 15:33:29 - @@ -177,7 +177,7 @@ url_get(const char *origline, const char { char pbuf[NI_MAXSERV], hbuf[NI_MAXHOST], *cp, *portnum, *path, ststr[4]; char *hosttail, *cause = unknown, *newline, *host, *port, *buf = NULL; - char *epath, *redirurl, *loctail; + char *epath, *redirurl, *loctail, *h, *p; int error, i, isftpurl = 0, isfileurl = 0, isredirect = 0, rval = -1; struct addrinfo hints, *res0, *res, *ares = NULL; const char * volatile savefile; @@ -191,7 +191,7 @@ url_get(const char *origline, const char size_t len, wlen; #ifndef SMALL char *sslpath = NULL, *sslhost = NULL; - char *locbase, *full_host = NULL; + char *locbase, *full_host = NULL, *auth = NULL; const char *scheme; int ishttpsurl = 0; SSL_CTX *ssl_ctx = NULL; @@ -250,6 +250,28 @@ url_get(const char *origline, const char warnx(No filename after host (use -o): %s, origline); goto cleanup_url_get; } +#ifndef SMALL + /* +* Look for auth header in host, since now host does not +* contain the path. Basic auth from RFC 2617, valid +* characters for path are in RFC 3986 section 3.3. +*/ + if (proxyenv == NULL + (!strcmp(scheme, HTTP_URL) || !strcmp(scheme, HTTPS_URL))) { + if ((p = strchr(host, '@')) != NULL) { + size_t authlen = (strlen(host) + 2) * 4 / 3 + 1; + + *p = 0; /* Kill @ */ + if ((auth = calloc(1, authlen)) == NULL) + err(1, Can't allocate memory for + authorization); + if (b64_ntop(host, strlen(host), + auth, authlen) == -1) + errx(1, error in base64 encoding); + host = p + 1; + } + } +#endif /* SMALL */ } noslash: @@ -460,8 +482,9 @@ noslash: if ((full_host = strdup(host)) == NULL) errx(1, Cannot allocate memory for hostname); if (debug) - fprintf(ttyout, host %s, port %s, path %s, save as %s.\n, - host, portnum, path, savefile); + fprintf(ttyout, host %s, port %s, path %s, + save as %s, auth %s.\n, + host, portnum, path, savefile, auth); #endif /* !SMALL */ memset(hints, 0, sizeof(hints)); @@ -638,15 +661,18 @@ again: else restart_point = 0; } -#endif /* !SMALL */ + if (auth) { + ftp_printf(fin, ssl, + GET /%s %s\r\nAuthorization: Basic %s\r\nHost: , + epath, restart_point ? + HTTP/1.1\r\nConnection: close : HTTP/1.0, + auth); + free(auth); + } else +#endif /* SMALL */ ftp_printf(fin, ssl, GET /%s %s\r\nHost: , epath, -#ifndef SMALL - restart_point ? HTTP/1.1\r\nConnection: close : -#endif /* !SMALL */ - HTTP/1.0); + HTTP/1.0); if (strchr(host, ':')) { - char *h, *p; - /* * strip off scoped address portion, since it's * local to node Index: ftp.1 === RCS file: /cvs/src/usr.bin/ftp/ftp.1,v retrieving revision 1.82 diff -d -u -p -r1.82 ftp.1 --- ftp.1 30 Apr 2012 13:41:26 - 1.82 +++ ftp.1 11 Aug 2012 20:08:00 - @@ -61,7 +61,8 @@ .Op Fl o Ar output .Op Fl s Ar srcaddr .Sm off -.No http:// Ar host Oo : Ar port +.No http:// Oo Ar user :
Re: (2) HTTP basic authentication for ftp(1) (RFC 2617)
Final version, better allocation arith. ok ? Index: fetch.c === RCS file: /cvs/src/usr.bin/ftp/fetch.c,v retrieving revision 1.105 diff -d -u -p -r1.105 fetch.c --- fetch.c 30 Apr 2012 13:41:26 - 1.105 +++ fetch.c 13 Aug 2012 19:13:57 - @@ -177,7 +177,7 @@ url_get(const char *origline, const char { char pbuf[NI_MAXSERV], hbuf[NI_MAXHOST], *cp, *portnum, *path, ststr[4]; char *hosttail, *cause = unknown, *newline, *host, *port, *buf = NULL; - char *epath, *redirurl, *loctail; + char *epath, *redirurl, *loctail, *h, *p; int error, i, isftpurl = 0, isfileurl = 0, isredirect = 0, rval = -1; struct addrinfo hints, *res0, *res, *ares = NULL; const char * volatile savefile; @@ -191,7 +191,7 @@ url_get(const char *origline, const char size_t len, wlen; #ifndef SMALL char *sslpath = NULL, *sslhost = NULL; - char *locbase, *full_host = NULL; + char *locbase, *full_host = NULL, *auth = NULL; const char *scheme; int ishttpsurl = 0; SSL_CTX *ssl_ctx = NULL; @@ -250,6 +250,27 @@ url_get(const char *origline, const char warnx(No filename after host (use -o): %s, origline); goto cleanup_url_get; } +#ifndef SMALL + /* +* Look for auth header in host, since now host does not +* contain the path. Basic auth from RFC 2617, valid +* characters for path are in RFC 3986 section 3.3. +*/ + if (proxyenv == NULL + (!strcmp(scheme, HTTP_URL) || !strcmp(scheme, HTTPS_URL))) { + if ((p = strchr(host, '@')) != NULL) { + size_t authlen = (strlen(host) + 5) * 4 / 3; + *p = 0; /* Kill @ */ + if ((auth = malloc(authlen)) == NULL) + err(1, Can't allocate memory for + authorization); + if (b64_ntop(host, strlen(host), + auth, authlen) == -1) + errx(1, error in base64 encoding); + host = p + 1; + } + } +#endif /* SMALL */ } noslash: @@ -460,8 +481,9 @@ noslash: if ((full_host = strdup(host)) == NULL) errx(1, Cannot allocate memory for hostname); if (debug) - fprintf(ttyout, host %s, port %s, path %s, save as %s.\n, - host, portnum, path, savefile); + fprintf(ttyout, host %s, port %s, path %s, + save as %s, auth %s.\n, + host, portnum, path, savefile, auth); #endif /* !SMALL */ memset(hints, 0, sizeof(hints)); @@ -638,15 +660,18 @@ again: else restart_point = 0; } -#endif /* !SMALL */ + if (auth) { + ftp_printf(fin, ssl, + GET /%s %s\r\nAuthorization: Basic %s\r\nHost: , + epath, restart_point ? + HTTP/1.1\r\nConnection: close : HTTP/1.0, + auth); + free(auth); + } else +#endif /* SMALL */ ftp_printf(fin, ssl, GET /%s %s\r\nHost: , epath, -#ifndef SMALL - restart_point ? HTTP/1.1\r\nConnection: close : -#endif /* !SMALL */ - HTTP/1.0); + HTTP/1.0); if (strchr(host, ':')) { - char *h, *p; - /* * strip off scoped address portion, since it's * local to node Index: ftp.1 === RCS file: /cvs/src/usr.bin/ftp/ftp.1,v retrieving revision 1.82 diff -d -u -p -r1.82 ftp.1 --- ftp.1 30 Apr 2012 13:41:26 - 1.82 +++ ftp.1 11 Aug 2012 20:08:00 - @@ -61,7 +61,8 @@ .Op Fl o Ar output .Op Fl s Ar srcaddr .Sm off -.No http:// Ar host Oo : Ar port +.No http:// Oo Ar user : password No @ +.Oc Ar host Oo : Ar port .Oc No / Ar file .Sm on .Ar ... @@ -71,7 +72,8 @@ .Op Fl o Ar output .Op Fl s Ar srcaddr .Sm off -.No https:// Ar host Oo : Ar port +.No https:// Oo Ar user : password No @ +.Oc Ar host Oo : Ar port .Oc No / Ar file .Sm on .Ar ... @@ -1278,12 +1280,12 @@ isn't defined, log in as .Ar user with a password of .Ar password . -.It http://host[:port]/file +.It http://[user:password@]host[:port]/file An HTTP URL, retrieved using the HTTP protocol. If .Ev http_proxy is defined, it is used as a URL to an HTTP proxy server. -.It https://host[:port]/file +.It
Re: http anchor fix [Was: Re: (2) HTTP basic authentication for ftp(1) (RFC 2617)]
On Sat, Aug 11, 2012 at 09:47:23PM +0200, Christiano F. Haesbaert wrote: On Tue, Aug 07, 2012 at 11:50:26AM -0400, Eric P. Mangold wrote: [...] I would prefer this to be done on the path processing block, if possible. Just make sure you test the scheme for http/https, sorry for slacking on the revision. Could you give it a try ? Sure I'll try to have a look at it soon - thanks for taking the time to look at this :) Regards, Eric P. Mangold
Re: (2) HTTP basic authentication for ftp(1) (RFC 2617)
On 08/06/12 22:56, Christiano F. Haesbaert wrote: Please ignore the other thread, it takes ages for me to open my sent box over gprs, so I'm opening a new one. Index: fetch.c === RCS file: /cvs/src/usr.bin/ftp/fetch.c,v retrieving revision 1.105 diff -d -u -p -r1.105 fetch.c --- fetch.c 30 Apr 2012 13:41:26 - 1.105 +++ fetch.c 6 Aug 2012 20:49:51 - @@ -177,7 +177,7 @@ url_get(const char *origline, const char { char pbuf[NI_MAXSERV], hbuf[NI_MAXHOST], *cp, *portnum, *path, ststr[4]; char *hosttail, *cause = unknown, *newline, *host, *port, *buf = NULL; - char *epath, *redirurl, *loctail; + char *epath, *redirurl, *loctail, *h, *p; int error, i, isftpurl = 0, isfileurl = 0, isredirect = 0, rval = -1; struct addrinfo hints, *res0, *res, *ares = NULL; const char * volatile savefile; @@ -191,7 +191,7 @@ url_get(const char *origline, const char size_t len, wlen; #ifndef SMALL char *sslpath = NULL, *sslhost = NULL; - char *locbase, *full_host = NULL; + char *locbase, *full_host = NULL, *auth = NULL; const char *scheme; int ishttpsurl = 0; SSL_CTX *ssl_ctx = NULL; @@ -228,7 +228,20 @@ url_get(const char *origline, const char #endif /* !SMALL */ } else errx(1, url_get: Invalid URL '%s', newline); - +#ifndef SMALL + /* Look for auth header */ - Is this safe for urls like http://some.host/path/e:mail@me/; ? - Should it be? - Should it maybe be done on the host part after the host/path separation? Not sure what the rfc's says on this. Chrome seems to accept the path I wrote above though. + if (proxyenv == NULL + (!strcmp(scheme, HTTP_URL) || !strcmp(scheme, HTTPS_URL))) { + if ((p = strchr(host, '@')) != NULL) { + *p = 0; /* Kill @ */ + if ((auth = calloc(1, 64)) == NULL) Why not malloc? Also, if you allocate it at runtime, why fixed at 64? Why not make it sth like malloc((strlen(host) + 2) * 4 / 3) (well, or) calloc(4, (strlen(host) + 2) / 3) ? + err(1, Can't allocate memory for authorization); + if (b64_ntop(host, strlen(host), auth, 64) == -1) (with appropriate fixing here ^^) + errx(1, error in base64 encoding); + host = p + 1; + } + } +#endif /* SMALL */ if (isfileurl) { path = host; } else { @@ -639,14 +652,19 @@ again: restart_point = 0; } #endif /* !SMALL */ - ftp_printf(fin, ssl, GET /%s %s\r\nHost: , epath, #ifndef SMALL The above leaves the pretty useless residue of: #endif /* !SMALL */ #ifndef SMALL Is this intentional? - restart_point ? HTTP/1.1\r\nConnection: close : -#endif /* !SMALL */ - HTTP/1.0); + if (auth) { + ftp_printf(fin, ssl, + GET /%s %s\r\nAuthorization: Basic %s\r\nHost: , + epath, restart_point ? + HTTP/1.1\r\nConnection: close : HTTP/1.0, + auth); + free(auth); + } else +#endif /* SMALL */ + ftp_printf(fin, ssl, GET /%s %s\r\nHost: , epath, + HTTP/1.0); if (strchr(host, ':')) { - char *h, *p; - /* * strip off scoped address portion, since it's * local to node Index: ftp.1 === RCS file: /cvs/src/usr.bin/ftp/ftp.1,v retrieving revision 1.82 diff -d -u -p -r1.82 ftp.1 --- ftp.1 30 Apr 2012 13:41:26 - 1.82 +++ ftp.1 6 Aug 2012 20:22:14 - @@ -61,7 +61,8 @@ .Op Fl o Ar output .Op Fl s Ar srcaddr .Sm off -.No http:// Ar host Oo : Ar port +.No http:// Oo Ar user : password No @ +.Oc Ar host Oo : Ar port .Oc No / Ar file .Sm on .Ar ... @@ -71,7 +72,8 @@ .Op Fl o Ar output .Op Fl s Ar srcaddr .Sm off -.No https:// Ar host Oo : Ar port +.No https:// Oo Ar user : password No @ +.Oc Ar host Oo : Ar port .Oc No / Ar file .Sm on .Ar ... @@ -1278,12 +1280,12 @@ isn't defined, log in as .Ar user with a password of .Ar password . -.It http://host[:port]/file +.It http://[user:password@]host[:port]/file An HTTP URL, retrieved using the HTTP protocol. If .Ev http_proxy is defined, it is used as a URL to an HTTP proxy server. -.It https://host[:port]/file +.It https://[user:password@]host[:port]/file An HTTPS URL, retrieved using the HTTPS protocol. If .Ev http_proxy Index: main.c
Re: http anchor fix [Was: Re: (2) HTTP basic authentication for ftp(1) (RFC 2617)]
On Tue, Aug 07, 2012 at 11:50:26AM -0400, Eric P. Mangold wrote: Sorry for the top-post I was wondering if some of you (active) 'ftp' maintainers could evaluate my patch below. I posted this to the list ages ago, and tried following up with some former committers on the ftp code, but for whatever reason I never received any communication at all. It is a very simple patch, if someone could review it, and let me know if this is OK or not. I would apprciate it. original message follows... Hi, I was trying to use the 'ftp' program to retrieve the following URL: https://pypi.python.org/packages/source/p/pip/pip-1.0.2.tar.gz#md5=47ec6ff3f6d962696fe08d4c8264ad49 Which fails because it considers the fragment as part of the path, and so the server returns 404. These type of links are quite common these days and so it would be nice if 'ftp' would handle them. This is my first patch to OpenBSD, so please let me know if there is anyhthing else I can do to get this feature implemented. The patch is very simple, and I think, correct, as '#' is an unsafe character, and must always be URL-encoded if it is to appear literally in a URL and not be interpreted as the start of a fragment identifier. I would prefer this to be done on the path processing block, if possible. Just make sure you test the scheme for http/https, sorry for slacking on the revision. Could you give it a try ? if (isfileurl) { path = host; } else { path = strchr(host, '/'); /* Find path */ if (EMPTYSTRING(path)) { if (outfile) { /* No slash, but */ path=strchr(host,'\0'); /* we have outfile. */ goto noslash; } if (isftpurl) goto noftpautologin; warnx(No `/' after host (use -o): %s, origline); goto cleanup_url_get; } *path++ = '\0'; probably here if (EMPTYSTRING(path) !outfile) { if (isftpurl) goto noftpautologin; warnx(No filename after host (use -o): %s, origline); goto cleanup_url_get; } } Regards, Eric P. Mangold Index: fetch.c === RCS file: /cvs/src/usr.bin/ftp/fetch.c,v retrieving revision 1.103 diff -u -r1.103 fetch.c --- fetch.c 25 Aug 2010 20:32:37 - 1.103 +++ fetch.c 29 Oct 2011 03:34:02 - @@ -205,6 +205,11 @@ if (newline == NULL) errx(1, Can't allocate memory to parse URL); if (strncasecmp(newline, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) { +/* Remove any trailing fragment identifier from the HTTP URL. + * Fragments (HTTP anchors) are identified by a hash char ('#'), + * as per RFC 3986. */ +newline = strsep(newline, #); + host = newline + sizeof(HTTP_URL) - 1; #ifndef SMALL scheme = HTTP_URL; @@ -221,6 +226,11 @@ #ifndef SMALL scheme = FILE_URL; } else if (strncasecmp(newline, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0) { +/* Remove any trailing fragment identifier from the HTTPS URL. + * Fragments (HTTP anchors) are identified by a hash char ('#'), + * as per RFC 3986. */ +newline = strsep(newline, #); + host = newline + sizeof(HTTPS_URL) - 1; ishttpsurl = 1; scheme = HTTPS_URL; On Mon, Aug 06, 2012 at 10:56:28PM +0200, Christiano F. Haesbaert wrote: Please ignore the other thread, it takes ages for me to open my sent box over gprs, so I'm opening a new one. Index: fetch.c === RCS file: /cvs/src/usr.bin/ftp/fetch.c,v retrieving revision 1.105 diff -d -u -p -r1.105 fetch.c --- fetch.c 30 Apr 2012 13:41:26 - 1.105 +++ fetch.c 6 Aug 2012 20:49:51 - @@ -177,7 +177,7 @@ url_get(const char *origline, const char { char pbuf[NI_MAXSERV], hbuf[NI_MAXHOST], *cp, *portnum, *path, ststr[4]; char *hosttail, *cause = unknown, *newline, *host, *port, *buf = NULL; - char *epath, *redirurl, *loctail; + char *epath, *redirurl, *loctail, *h, *p; int error, i, isftpurl = 0, isfileurl = 0, isredirect = 0, rval = -1; struct addrinfo hints, *res0, *res, *ares = NULL; const char * volatile savefile; @@ -191,7 +191,7 @@ url_get(const char *origline, const char size_t len, wlen; #ifndef SMALL char *sslpath = NULL, *sslhost = NULL; - char *locbase,