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) {