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>
