Date: Mon, 23 Apr 2001 12:03:24 -0700 (PDT) From: Mark Trostler <trostler@juniper.net> To: FreeBSD-gnats-submit@freebsd.org Cc: des@freebsd.org Subject: bin/26803: 'fetch' additions & small fix Message-ID: <200104231903.f3NJ3Oh10392@trostler-bsd.juniper.net>
next in thread | raw e-mail | index | archive | help
>Number: 26803 >Category: bin >Synopsis: Fix fetch to allow FTP puts in '-o' & allow '@' sign in URL >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Mon Apr 23 12:10:02 PDT 2001 >Closed-Date: >Last-Modified: >Originator: Mark Trostler >Release: FreeBSD 4.2-RELEASE i386 >Organization: Juniper Networks >Environment: Any >Description: fetch does now allow FTP URLs as '-o' values. Also passwords w/'@' signs in them cause fetch to barf - like an email address for the username 'anonymous' Also if user specifies 'prompt' or '?' as password prompt user for password Also if no password is specified & user is not FTP_ANONYMOUS prompt user for password Also will take file from machine w/o 'file://' in front of it. Also can now use fetch as ftp relay. Maybe you guys are interested in this? >How-To-Repeat: Specify a URL of form ftp://anonymous:trostler@juniper.net@ftp.juniper.net/pub/file & barfola With patch you can now say: fetch /path/to/local/file -o ftp://tros:prompt@ftp.jniper.net/put/it/here or even: fetch ftp://mark:pass@ftp.somewhere.else.com -o ftp://tros:prompt@ftp.jniper.net/put/it/here >Fix: Index: lib/libfetch/fetch.c =================================================================== RCS file: /cvs/junos-2001/src/lib/libfetch/fetch.c,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 fetch.c --- lib/libfetch/fetch.c 2001/03/31 04:37:14 1.1.1.1 +++ lib/libfetch/fetch.c 2001/04/23 17:36:20 @@ -1,4 +1,4 @@ -/*- +/* * Copyright (c) 1998 Dag-Erling Coïdan Smørgrav * All rights reserved. * @@ -306,35 +306,56 @@ fetchParseURL(char *URL) /* scheme name */ if ((p = strstr(URL, ":/"))) { - snprintf(u->scheme, URL_SCHEMELEN+1, "%.*s", p - URL, URL); - URL = ++p; - /* - * Only one slash: no host, leave slash as part of document - * Two slashes: host follows, strip slashes - */ - if (URL[1] == '/') - URL = (p += 2); - } else { - p = URL; - } + snprintf(u->scheme, URL_SCHEMELEN+1, "%.*s", p - URL, URL); + URL = ++p; + /* + * Only one slash: no host, leave slash as part of document + * Two slashes: host follows, strip slashes + */ + if (URL[1] == '/') + URL = (p += 2); + } else + p = URL; + if (!*URL || *URL == '/') - goto nohost; + goto nohost; p = strpbrk(URL, "/@"); if (p && *p == '@') { /* username */ for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++) if (i < URL_USERLEN) - u->user[i++] = *q; + u->user[i++] = *q; + /* + * Code to correctly suck in passwords with '@' signs in 'em + */ /* password */ - if (*q == ':') - for (q++, i = 0; (*q != ':') && (*q != '@'); q++) - if (i < URL_PWDLEN) - u->pwd[i++] = *q; - - p++; - } else p = URL; + if (*q == ':') { + int double_at = 0; + if (strchr(p+1,'@')) { // the double '@' sign!! + double_at = 1; + p++; // It's current pointing at the first '@' sign + p = strpbrk(p, "/@"); // Move pointer ahead to real hostname + } + for (q++,i = 0; (*q != ':') && (double_at ? double_at : *q != '@'); + q++) { + + if (i < URL_PWDLEN) { + if (*q == '@') + double_at--; + u->pwd[i++] = *q; + } + } + + } + + p++; // Advance past '@' + + } + else + p = URL; /* hostname */ #ifdef INET6 @@ -395,7 +416,7 @@ nohost: goto ouch; } - DEBUG(fprintf(stderr, + DEBUG(fprintf(stderr, "scheme: [\033[1m%s\033[m]\n" "user: [\033[1m%s\033[m]\n" "password: [\033[1m%s\033[m]\n" Index: lib/libfetch/ftp.c =================================================================== RCS file: /cvs/junos-2001/src/lib/libfetch/ftp.c,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 ftp.c --- lib/libfetch/ftp.c 2001/03/31 04:37:14 1.1.1.1 +++ lib/libfetch/ftp.c 2001/04/23 17:36:21 @@ -755,36 +755,57 @@ _ftp_connect(struct url *url, struct url /* expect welcome message */ if ((e = _ftp_chkerr(cd)) != FTP_SERVICE_READY) - goto fouch; + goto fouch; /* XXX FTP_AUTH, and maybe .netrc */ + /* + * First normalize 'anonymous' user to FTP_ANONYMOUS_USER + * Then ask user for password if not provided or they typed + * 'prompt' or '?' as the password + * (not that a '?' is gonna get thru the CLI - just for + * total backwards compaitbility) + */ /* send user name and password */ user = url->user; if (!user || !*user) - user = getenv("FTP_LOGIN"); - if (!user || !*user) - user = FTP_ANONYMOUS_USER; + user = getenv("FTP_LOGIN"); + if (!user || !*user || (strcmp(user,"anonymous") == 0)) + user = FTP_ANONYMOUS_USER; if (purl && url->port == _fetch_default_port(url->scheme)) - e = _ftp_cmd(cd, "USER %s@%s", user, url->host); + e = _ftp_cmd(cd, "USER %s@%s", user, url->host); else if (purl) - e = _ftp_cmd(cd, "USER %s@%s@%d", user, url->host, url->port); + e = _ftp_cmd(cd, "USER %s@%s@%d", user, url->host, url->port); else - e = _ftp_cmd(cd, "USER %s", user); + e = _ftp_cmd(cd, "USER %s", user); /* did the server request a password? */ if (e == FTP_NEED_PASSWORD) { - pwd = url->pwd; - if (!pwd || !*pwd) - pwd = getenv("FTP_PASSWORD"); - if (!pwd || !*pwd) { - if ((logname = getlogin()) == 0) - logname = FTP_ANONYMOUS_PASSWORD; - gethostname(localhost, sizeof localhost); - snprintf(pbuf, sizeof pbuf, "%s@%s", logname, localhost); - pwd = pbuf; - } - e = _ftp_cmd(cd, "PASS %s", pwd); + pwd = url->pwd; + if (!pwd || !*pwd) + pwd = getenv("FTP_PASSWORD"); + if ((!pwd || !*pwd) && (strcmp(user,FTP_ANONYMOUS_USER) ==0)) { + if ((logname = getlogin()) == 0) + logname = FTP_ANONYMOUS_PASSWORD; + gethostname(localhost, sizeof localhost); + snprintf(pbuf, sizeof pbuf, "%s@%s", logname, localhost); + pwd = pbuf; + } + else if (!pwd || !*pwd || (strcmp(pwd,"prompt") == 0) || + (strcmp(pwd,"?") ==0)) { + + char *prompt; + char *pass; + + asprintf(&prompt, "Password for %s@%s:", user, url->host); + pass = getpass(prompt); + pwd = strdup(pass); + memset(pass, 0, strlen(pass)); + free(prompt); + } + e = _ftp_cmd(cd, "PASS %s", pwd); } /* did the server request an account? */ Index: lib/libftpio/ftpio.c =================================================================== RCS file: /cvs/junos-2001/src/lib/libftpio/ftpio.c,v retrieving revision 1.9 diff -u -p -r1.9 ftpio.c --- lib/libftpio/ftpio.c 2001/04/02 04:17:51 1.9 +++ lib/libftpio/ftpio.c 2001/04/23 17:36:21 @@ -481,7 +481,7 @@ ftpPutURLAf(char *url, int af, char *use * into characters along the way. This is destructive. */ -static char * +char * decode_url_escapes (char *src) { char *dst, *save; Index: usr.bin/fetch/fetch.c =================================================================== RCS file: /cvs/junos-2001/src/usr.bin/fetch/fetch.c,v retrieving revision 1.2 diff -u -p -r1.2 fetch.c --- usr.bin/fetch/fetch.c 2001/04/02 04:18:32 1.2 +++ usr.bin/fetch/fetch.c 2001/04/23 17:37:33 @@ -178,7 +178,7 @@ stat_end(struct xferstat *xs) int fetch(char *URL, char *path) { - struct url *url; + struct url *url, *output_url; struct url_stat us; struct stat sb; struct xferstat xs; @@ -191,6 +191,23 @@ fetch(char *URL, char *path) f = of = NULL; + /* + * see if the 'target' URL is just a plain file + * If so make a full path to it + */ + if (!stat(URL,&sb)) { + // We got ourselves a regular file! + // Get the full path to it so the fetchParseURL routine + // doesn't barf on it + if (*URL != '/') { + char * full_path = NULL; + full_path = getcwd(full_path, MAXPATHLEN); + asprintf(&URL,"%s/%s",full_path,URL); + free(full_path); + } + } + /* parse URL */ if ((url = fetchParseURL(URL)) == NULL) { warnx("%s: parse error", URL); @@ -276,6 +293,7 @@ fetch(char *URL, char *path) sb.st_size = -1; } + /* start the transfer */ if ((f = fetchXGet(url, &us, flags)) == NULL) { warnx("%s: %s", path, fetchLastErrString); @@ -316,6 +334,12 @@ fetch(char *URL, char *path) us.size, us.mtime); } + /* parse output URL */ + if ((output_url = fetchParseURL(path)) == NULL) { + warnx("%s: parse error", path); + goto failure; + } + /* open output file */ if (o_stdout) { /* output to stdout */ @@ -370,15 +394,29 @@ fetch(char *URL, char *path) goto success; } if (!of) { - /* - * We don't yet have an output file; either this is a vanilla - * run with no special flags, or the local and remote files - * didn't match. - */ - if ((of = fopen(path, "w")) == NULL) { - warn("%s: open()", path); - goto failure; - } + /* + * We don't yet have an output file; either this is a vanilla + * run with no special flags, or the local and remote files + * didn't match. + */ + /* + * Check it we're outputting to FTP or not! + * if so get FILE* from fetch lib & not from fopen + */ + if (!strcmp(output_url->scheme, SCHEME_FTP)) { + if ((of = fetchPutURL(path, NULL)) == NULL) { + warn("%s: open()", path); + goto failure; + } + } + else { + if ((of = fopen(path, "w")) == NULL) { + warn("%s: open()", path); + goto failure; + } + } } count = url->offset; @@ -475,18 +513,18 @@ fetch(char *URL, char *path) return r; } -void +static void usage(void) { - /* XXX badly out of synch */ fprintf(stderr, - "Usage: fetch [-1AFHMPRabdlmnpqrstv] [-o outputfile] [-S bytes]\n" - " [-B bytes] [-T seconds] [-w seconds]\n" - " [-f file -h host [-c dir] | URL ...]\n" - ); + "usage: fetch [-ADHILMNPRTVablmnpqrstv] [-o outputfile] " + "[-S bytes]\n" + " [-f file -h host [-c dir] | URL]\n"); + exit(EX_USAGE); } + #define PARSENUM(NAME, TYPE) \ int \ NAME(char *s, TYPE *v) \ @@ -700,13 +738,13 @@ main(int argc, char *argv[]) if (o_flag) { if (o_stdout) { - e = fetch(*argv, "-"); + e = fetch(*argv, "-"); } else if (o_directory) { - asprintf(&q, "%s/%s", o_filename, p); - e = fetch(*argv, q); - free(q); + asprintf(&q, "%s/%s", o_filename, p); + e = fetch(*argv, q); + free(q); } else { - e = fetch(*argv, o_filename); + e = fetch(*argv, o_filename); } } else { e = fetch(*argv, p); >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200104231903.f3NJ3Oh10392>