Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Posting-Version: version B 2.10.2 9/18/84 SMI; site sun.uucp
Path: utzoo!watmath!clyde!burl!ulysses!allegra!mit-eddie!genrad!decvax!decwrl!sun!guy
From: guy@sun.uucp (Guy Harris)
Newsgroups: net.bugs.4bsd
Subject: Several bugs in "ftp"
Message-ID: <2356@sun.uucp>
Date: Wed, 26-Jun-85 06:46:56 EDT
Article-I.D.: sun.2356
Posted: Wed Jun 26 06:46:56 1985
Date-Received: Fri, 28-Jun-85 00:43:20 EDT
Distribution: net
Organization: Sun Microsystems, Inc.
Lines: 449
Index: ucb/ftp/cmds.c ucb/ftp/ftp.c ucb/ftp/getpass.c ucb/ftp/main.c 4.2BSD
Description:
1) The "!" command has an undocumented feature; if it's invoked in
the form "!", the is executed and control
returns to "ftp" when it exits. This is nicely consistent
with most other UNIX commands (I wish more commands would
interpret an undecorated "!" as a request to spawn an
interactive subshell, as "ftp" does). However, instead of
just handing the to an "sh -c", it tries to do the
"glob"bing and tokenizing itself and does an "execvp" directly.
This does not work correctly.
Also, when invoked without a , it prefixes the
shell's name with a "-", causing it to be run as a login shell,
which is wrong. (And if the shell is not "sh", it prefixes
it with a "+" instead.)
2) If you try to retrieve something into a local file, and you
don't have write permission on the file, it tests whether
you have write permission on the directory containing that file.
However, the test is wrong - if the local file name is a path
containing slashes, it does a test on a null pathname rather
than on the containing directory.
3) The code that reads reply codes throws some reply codes away;
see my previous posting.
4) "ftp" should permit passwords of at least 50 characters in
length; see a previous bug posting by, I believe, rws@mit-bold.
(I think 4.3BSD almost fixes this, but the code limits passwords
to 49 characters.)
Repeat-By:
1) Try
ftp>!echo "*.c"
and notice that it does not print "*.c". Then try
ftp>!
and do a "ps"; note that you're running "-sh" or "+csh" (or something
like that).
2) Try doing a "get" where the target file is not in the current
directory and is in a directory where you don't have write
permission. It won't complain, but it won't do it either.
Fix:
Here's an omnibus set of fixes:
*** /arch/4.2/usr/src/ucb/ftp/cmds.c Tue Jul 26 21:34:47 1983
--- 4.2.fixed/cmds.c Wed Jun 26 03:17:10 1985
***************
*** 703,709
dest = argv[argc - 1];
argv[argc - 1] = NULL;
if (strcmp(dest, "-"))
! if (globulize(&dest) && confirm("local-file", dest))
return;
cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
for (mode = "w"; cp = remglob(argc, argv); mode = "a")
--- 703,709 -----
dest = argv[argc - 1];
argv[argc - 1] = NULL;
if (strcmp(dest, "-"))
! if (!globulize(&dest) || !confirm("local-file", dest))
return;
cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
for (mode = "w"; cp = remglob(argc, argv); mode = "a")
***************
*** 728,733
close(pid);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
if (argc <= 1) {
shell = getenv("SHELL");
if (shell == NULL)
--- 728,739 -----
close(pid);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
+ shell = getenv("SHELL");
+ if (shell == NULL)
+ shell = "/bin/sh";
+ namep = rindex(shell,'/');
+ if (namep == NULL)
+ namep = shell;
if (argc <= 1) {
if (debug) {
printf ("%s\n", shell);
***************
*** 729,744
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
if (argc <= 1) {
- shell = getenv("SHELL");
- if (shell == NULL)
- shell = "/bin/sh";
- namep = rindex(shell,'/');
- if (namep == NULL)
- namep = shell;
- strcpy(shellnam,"-");
- strcat(shellnam, ++namep);
- if (strcmp(namep, "sh") != 0)
- shellnam[0] = '+';
if (debug) {
printf ("%s\n", shell);
fflush (stdout);
--- 735,740 -----
if (namep == NULL)
namep = shell;
if (argc <= 1) {
if (debug) {
printf ("%s\n", shell);
fflush (stdout);
***************
*** 743,759
printf ("%s\n", shell);
fflush (stdout);
}
! execl(shell, shellnam, 0);
! perror(shell);
! exit(1);
! }
! cpp = &argv[1];
! if (argc > 2) {
! if ((gargs = glob(cpp)) != NULL)
! cpp = gargs;
! if (globerr != NULL) {
! printf("%s\n", globerr);
! exit(1);
}
}
if (debug) {
--- 739,755 -----
printf ("%s\n", shell);
fflush (stdout);
}
! execl(shell, shell, (char *)0);
! } else {
! char *args[4]; /* "sh" "-c" NULL */
!
! args[0] = shell;
! args[1] = "-c";
! args[2] = argv[1];
! args[3] = NULL;
! if (debug) {
! printf("%s -c %s\n", shell, argv[1]);
! fflush(stdout);
}
execv(shell, args);
}
***************
*** 755,760
printf("%s\n", globerr);
exit(1);
}
}
if (debug) {
register char **zip = cpp;
--- 751,757 -----
printf("%s -c %s\n", shell, argv[1]);
fflush(stdout);
}
+ execv(shell, args);
}
perror(shell);
exit(1);
***************
*** 756,772
exit(1);
}
}
! if (debug) {
! register char **zip = cpp;
!
! printf("%s", *zip);
! while (*++zip != NULL)
! printf(" %s", *zip);
! printf("\n");
! fflush(stdout);
! }
! execvp(argv[1], cpp);
! perror(argv[1]);
exit(1);
}
if (pid > 0)
--- 753,759 -----
}
execv(shell, args);
}
! perror(shell);
exit(1);
}
if (pid > 0)
*** /arch/4.2/usr/src/ucb/ftp/ftp.c Tue Jul 26 21:34:47 1983
--- 4.2.fixed/ftp.c Wed Jun 26 03:46:14 1985
***************
*** 182,189
originalcode = code;
continue;
}
! if (expecteof || empty(cin))
! return (n - '0');
}
}
--- 182,188 -----
originalcode = code;
continue;
}
! return (n - '0');
}
}
***************
*** 187,206
}
}
- empty(f)
- FILE *f;
- {
- long mask;
- struct timeval t;
-
- if (f->_cnt > 0)
- return (0);
- mask = (1 << fileno(f));
- t.tv_sec = t.tv_usec = 0;
- (void) select(20, &mask, 0, 0, &t);
- return (mask == 0);
- }
-
jmp_buf sendabort;
abortsend()
--- 186,191 -----
}
}
jmp_buf sendabort;
abortsend()
***************
*** 356,362
oldintr = signal(SIGINT, abortrecv);
if (strcmp(local, "-") && *local != '|')
if (access(local, 2) < 0) {
! char *dir = rindex(local, '/');
if (dir != NULL)
*dir = 0;
--- 341,348 -----
oldintr = signal(SIGINT, abortrecv);
if (strcmp(local, "-") && *local != '|')
if (access(local, 2) < 0) {
! if (errno == ENOENT) {
! char *dir = rindex(local, '/');
if (dir != NULL)
*dir = 0;
***************
*** 358,366
if (access(local, 2) < 0) {
char *dir = rindex(local, '/');
! if (dir != NULL)
! *dir = 0;
! if (access(dir ? dir : ".", 2) < 0) {
perror(local);
goto bad;
}
--- 344,358 -----
if (errno == ENOENT) {
char *dir = rindex(local, '/');
! if (dir != NULL)
! *dir = 0;
! if (access(dir ? local : ".", 2) < 0) {
! perror(local);
! goto bad;
! }
! if (dir != NULL)
! *dir = '/';
! } else {
perror(local);
goto bad;
}
***************
*** 364,371
perror(local);
goto bad;
}
- if (dir != NULL)
- *dir = '/';
}
if (initconn())
goto bad;
--- 356,361 -----
perror(local);
goto bad;
}
}
if (initconn())
goto bad;
***************
*** 493,499
}
if (!sendport)
if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) {
! perror("ftp: setsockopt (resuse address)");
goto bad;
}
if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) {
--- 483,489 -----
}
if (!sendport)
if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0) {
! perror("ftp: setsockopt (reuse address)");
goto bad;
}
if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) {
*** /arch/4.2/usr/src/ucb/ftp/getpass.c Tue Jul 26 21:34:48 1983
--- 4.2.fixed/getpass.c Sun Apr 7 12:22:25 1985
***************
*** 15,21
register char *p;
register c;
FILE *fi;
! static char pbuf[9];
int (*signal())();
int (*sig)();
--- 15,21 -----
register char *p;
register c;
FILE *fi;
! static char pbuf[51];
int (*signal())();
int (*sig)();
***************
*** 30,36
stty(fileno(fi), &ttyb);
fprintf(stderr, "%s", prompt); fflush(stderr);
for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
! if (p < &pbuf[8])
*p++ = c;
}
*p = '\0';
--- 30,36 -----
stty(fileno(fi), &ttyb);
fprintf(stderr, "%s", prompt); fflush(stderr);
for (p=pbuf; (c = getc(fi))!='\n' && c!=EOF;) {
! if (p < &pbuf[50])
*p++ = c;
}
*p = '\0';
*** /arch/4.2/usr/src/ucb/ftp/main.c Tue Jul 26 21:34:48 1983
--- 4.2.fixed/main.c Sun Apr 7 12:22:26 1985
***************
*** 251,257
argp = margv;
stringbase = line; /* scan from first of buffer */
argbase = argbuf; /* store from first of buffer */
! while (*argp++ = slurpstring())
margc++;
}
--- 251,261 -----
argp = margv;
stringbase = line; /* scan from first of buffer */
argbase = argbuf; /* store from first of buffer */
! while (*stringbase == ' ' || *stringbase == '\t')
! stringbase++; /* skip initial white space */
! if (*stringbase == '!') { /* handle shell escapes specially */
! stringbase++;
! *argp++ = "!"; /* command name is "!" */
margc++;
while (*stringbase == ' ' || *stringbase == '\t')
stringbase++; /* skip white space */
***************
*** 253,258
argbase = argbuf; /* store from first of buffer */
while (*argp++ = slurpstring())
margc++;
}
/*
--- 257,273 -----
stringbase++;
*argp++ = "!"; /* command name is "!" */
margc++;
+ while (*stringbase == ' ' || *stringbase == '\t')
+ stringbase++; /* skip white space */
+ if (*stringbase != '\0') {
+ *argp++ = stringbase; /* argument is entire command string */
+ margc++;
+ }
+ *argp++ = NULL;
+ } else {
+ while (*argp++ = slurpstring())
+ margc++;
+ }
}
/*
***************
*** 268,277
register char *ap = argbase;
char *tmp = argbase; /* will return this if token found */
- if (*sb == '!') { /* recognize ! as a token for shell */
- stringbase++;
- return ("!");
- }
S0:
switch (*sb) {
--- 283,288 -----
register char *ap = argbase;
char *tmp = argbase; /* will return this if token found */
S0:
switch (*sb) {