Skip site navigation (1)Skip section navigation (2)
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>