X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/98c50518c04eefe9ebf5c1593074a759374f0747..522da3e451a5c5d93d6523b197c81de222ba5402:/usr/src/usr.bin/ftp/ftp.c diff --git a/usr/src/usr.bin/ftp/ftp.c b/usr/src/usr.bin/ftp/ftp.c index 5c47733e60..e064bd0da7 100644 --- a/usr/src/usr.bin/ftp/ftp.c +++ b/usr/src/usr.bin/ftp/ftp.c @@ -1,162 +1,180 @@ /* - * Copyright (c) 1985 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. + * Copyright (c) 1985, 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * %sccs.include.redist.c% */ #ifndef lint -static char sccsid[] = "@(#)ftp.c 5.8 (Berkeley) %G%"; -#endif not lint - -#include "ftp_var.h" +static char sccsid[] = "@(#)ftp.c 8.3 (Berkeley) %G%"; +#endif /* not lint */ +#include #include #include #include #include +#include #include +#include +#include +#include #include #include -#include -#include +#include +#include #include -#include #include +#include #include +#include +#include +#include +#include +#include +#include + +#include "ftp_var.h" + +extern int h_errno; struct sockaddr_in hisctladdr; struct sockaddr_in data_addr; int data = -1; -int telflag = 0; int abrtflag = 0; +jmp_buf ptabort; +int ptabflg; int ptflag = 0; -int connected; struct sockaddr_in myctladdr; + FILE *cin, *cout; -FILE *dataconn(); char * hookup(host, port) char *host; int port; { - register struct hostent *hp = 0; - int s,len,oldverbose; + struct hostent *hp = 0; + int s, len, tos; static char hostnamebuf[80]; - char msg[2]; - bzero((char *)&hisctladdr, sizeof (hisctladdr)); + memset((char *)&hisctladdr, 0, sizeof (hisctladdr)); hisctladdr.sin_addr.s_addr = inet_addr(host); if (hisctladdr.sin_addr.s_addr != -1) { hisctladdr.sin_family = AF_INET; - (void) strcpy(hostnamebuf, host); - } - else { + (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf)); + } else { hp = gethostbyname(host); if (hp == NULL) { - printf("%s: unknown host\n", host); + warnx("%s: %s", host, hstrerror(h_errno)); code = -1; - return((char *) 0); + return ((char *) 0); } hisctladdr.sin_family = hp->h_addrtype; - bcopy(hp->h_addr_list[0], - (caddr_t)&hisctladdr.sin_addr, hp->h_length); - (void) strcpy(hostnamebuf, hp->h_name); + memmove((caddr_t)&hisctladdr.sin_addr, + hp->h_addr_list[0], hp->h_length); + (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf)); } hostname = hostnamebuf; s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); if (s < 0) { - perror("ftp: socket"); + warn("socket"); code = -1; return (0); } hisctladdr.sin_port = port; - while (connect(s, (caddr_t)&hisctladdr, sizeof (hisctladdr)) < 0) { + while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) { if (hp && hp->h_addr_list[1]) { int oerrno = errno; + char *ia; - fprintf(stderr, "ftp: connect to address %s: ", - inet_ntoa(hisctladdr.sin_addr)); + ia = inet_ntoa(hisctladdr.sin_addr); errno = oerrno; - perror(0); + warn("connect to address %s", ia); hp->h_addr_list++; - bcopy(hp->h_addr_list[0], - (caddr_t)&hisctladdr.sin_addr, hp->h_length); - fprintf(stderr, "Trying %s...\n", + memmove((caddr_t)&hisctladdr.sin_addr, + hp->h_addr_list[0], hp->h_length); + fprintf(stdout, "Trying %s...\n", inet_ntoa(hisctladdr.sin_addr)); + (void) close(s); + s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); + if (s < 0) { + warn("socket"); + code = -1; + return (0); + } continue; } - perror("ftp: connect"); + warn("connect"); code = -1; goto bad; } len = sizeof (myctladdr); - if (getsockname(s, (char *)&myctladdr, &len) < 0) { - perror("ftp: getsockname"); + if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) { + warn("getsockname"); code = -1; goto bad; } +#ifdef IP_TOS + tos = IPTOS_LOWDELAY; + if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) + warn("setsockopt TOS (ignored)"); +#endif cin = fdopen(s, "r"); cout = fdopen(s, "w"); if (cin == NULL || cout == NULL) { - fprintf(stderr, "ftp: fdopen failed.\n"); + warnx("fdopen failed."); if (cin) - fclose(cin); + (void) fclose(cin); if (cout) - fclose(cout); + (void) fclose(cout); code = -1; goto bad; } if (verbose) printf("Connected to %s.\n", hostname); - if (getreply(0) != 2) { /* read startup message from server */ + if (getreply(0) > 2) { /* read startup message from server */ if (cin) - fclose(cin); + (void) fclose(cin); if (cout) - fclose(cout); + (void) fclose(cout); code = -1; goto bad; } +#ifdef SO_OOBINLINE + { + int on = 1; -/* test to see if server command parser understands TELNET SYNC command */ + if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) + < 0 && debug) { + warn("setsockopt"); + } + } +#endif /* SO_OOBINLINE */ - fprintf(cout,"%c%c",IAC,NOP); - (void) fflush(cout); - *msg = IAC; - *(msg+1) = DM; - if (send(s,msg,2,MSG_OOB) != 2) - perror("sync"); - oldverbose = verbose; - if (!debug) - verbose = -1; - if (command("NOOP") == COMPLETE) - telflag = 1; - else - telflag = 0; - verbose = oldverbose; return (hostname); bad: - close(s); + (void) close(s); return ((char *)0); } +int login(host) char *host; { char tmp[80]; - char *user, *pass, *acct, *getlogin(), *getpass(); + char *user, *pass, *acct; int n, aflag = 0; user = pass = acct = 0; if (ruserpass(host, &user, &pass, &acct) < 0) { - disconnect(); code = -1; - return(0); + return (0); } - if (user == NULL) { + while (user == NULL) { char *myname = getlogin(); if (myname == NULL) { @@ -165,7 +183,10 @@ login(host) if (pp != NULL) myname = pp->pw_name; } - printf("Name (%s:%s): ", host, myname); + if (myname) + printf("Name (%s:%s): ", host, myname); + else + printf("Name (%s): ", host); (void) fgets(tmp, sizeof(tmp) - 1, stdin); tmp[strlen(tmp) - 1] = '\0'; if (*tmp == '\0') @@ -185,16 +206,16 @@ login(host) n = command("ACCT %s", acct); } if (n != COMPLETE) { - fprintf(stderr, "Login failed.\n"); + warnx("Login failed."); return (0); } if (!aflag && acct != NULL) (void) command("ACCT %s", acct); if (proxy) - return(1); + return (1); for (n = 0; n < macnum; ++n) { if (!strcmp("init", macros[n].mac_name)) { - strcpy(line, "$init"); + (void) strcpy(line, "$init"); makeargv(); domacro(margc, margv); break; @@ -203,9 +224,9 @@ login(host) return (1); } +void cmdabort() { - extern jmp_buf ptabort; printf("\n"); (void) fflush(stdout); @@ -214,51 +235,86 @@ cmdabort() longjmp(ptabort,1); } -/*VARARGS 1*/ -command(fmt, args) - char *fmt; +/*VARARGS*/ +int +command(va_alist) +va_dcl { - int r, (*oldintr)(), cmdabort(); + va_list ap; + char *fmt; + int r; + sig_t oldintr; abrtflag = 0; if (debug) { printf("---> "); - _doprnt(fmt, &args, stdout); + va_start(ap); + fmt = va_arg(ap, char *); + if (strncmp("PASS ", fmt, 5) == 0) + printf("PASS XXXX"); + else + vfprintf(stdout, fmt, ap); + va_end(ap); printf("\n"); (void) fflush(stdout); } if (cout == NULL) { - perror ("No control connection for command"); + warn("No control connection for command"); code = -1; return (0); } - oldintr = signal(SIGINT,cmdabort); - _doprnt(fmt, &args, cout); + oldintr = signal(SIGINT, cmdabort); + va_start(ap); + fmt = va_arg(ap, char *); + vfprintf(cout, fmt, ap); + va_end(ap); fprintf(cout, "\r\n"); (void) fflush(cout); cpend = 1; r = getreply(!strcmp(fmt, "QUIT")); if (abrtflag && oldintr != SIG_IGN) - (*oldintr)(); + (*oldintr)(SIGINT); (void) signal(SIGINT, oldintr); - return(r); + return (r); } -#include +char reply_string[BUFSIZ]; /* last line of previous reply */ +int getreply(expecteof) int expecteof; { - register int c, n; - register int dig; - int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort(); + int c, n; + int dig; + int originalcode = 0, continuation = 0; + sig_t oldintr; int pflag = 0; - char *pt = pasv; + char *cp, *pt = pasv; - oldintr = signal(SIGINT,cmdabort); + oldintr = signal(SIGINT, cmdabort); for (;;) { dig = n = code = 0; + cp = reply_string; while ((c = getc(cin)) != '\n') { + if (c == IAC) { /* handle telnet commands */ + switch (c = getc(cin)) { + case WILL: + case WONT: + c = getc(cin); + fprintf(cout, "%c%c%c", IAC, DONT, c); + (void) fflush(cout); + break; + case DO: + case DONT: + c = getc(cin); + fprintf(cout, "%c%c%c", IAC, WONT, c); + (void) fflush(cout); + break; + default: + break; + } + continue; + } dig++; if (c == EOF) { if (expecteof) { @@ -270,16 +326,16 @@ getreply(expecteof) if (verbose) { printf("421 Service not available, remote server has closed connection\n"); (void) fflush(stdout); - code = 421; - return(4); } + code = 421; + return (4); } if (c != '\r' && (verbose > 0 || (verbose > -1 && n == '5' && dig > 4))) { if (proxflag && (dig == 1 || dig == 5 && verbose == 0)) printf("%s:",hostname); - putchar(c); + (void) putchar(c); } if (dig < 4 && isdigit(c)) code = code * 10 + (c - '0'); @@ -302,9 +358,11 @@ getreply(expecteof) } if (n == 0) n = c; + if (cp < &reply_string[sizeof(reply_string) - 1]) + *cp++ = c; } if (verbose > 0 || verbose > -1 && n == '5') { - putchar(c); + (void) putchar(c); (void) fflush (stdout); } if (continuation && code != originalcode) { @@ -312,61 +370,75 @@ getreply(expecteof) originalcode = code; continue; } + *cp = '\0'; if (n != '1') cpend = 0; (void) signal(SIGINT,oldintr); if (code == 421 || originalcode == 421) lostpeer(); if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) - (*oldintr)(); + (*oldintr)(SIGINT); return (n - '0'); } } +int empty(mask, sec) - long mask; + struct fd_set *mask; int sec; { struct timeval t; t.tv_sec = (long) sec; t.tv_usec = 0; - if (select(20, &mask, 0, 0, &t) < 0) - return(-1); - return (mask); + return (select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t)); } jmp_buf sendabort; +void abortsend() { mflag = 0; abrtflag = 0; - printf("\nsend aborted\n"); + printf("\nsend aborted\nwaiting for remote to finish abort\n"); (void) fflush(stdout); longjmp(sendabort, 1); } -sendrequest(cmd, local, remote) +#define HASHBYTES 1024 + +void +sendrequest(cmd, local, remote, printnames) char *cmd, *local, *remote; + int printnames; { - FILE *fin, *dout = 0, *popen(); - int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); - int abortsend(); - char buf[BUFSIZ]; - long bytes = 0, hashbytes = sizeof (buf); - register int c, d; struct stat st; struct timeval start, stop; + int c, d; + FILE *fin, *dout = 0, *popen(); + int (*closefunc) __P((FILE *)); + char buf[BUFSIZ], *bufp; + long bytes = 0, hashbytes = HASHBYTES; + char *lmode, buf[BUFSIZ], *bufp; + if (verbose && printnames) { + if (local && *local != '-') + printf("local: %s ", local); + if (remote) + printf("remote: %s\n", remote); + } if (proxy) { proxtrans(cmd, local, remote); return; } + if (curtype != type) + changetype(type, 0); closefunc = NULL; oldintr = NULL; oldintp = NULL; + lmode = "w"; if (setjmp(sendabort)) { while (cpend) { (void) getreply(0); @@ -389,7 +461,7 @@ sendrequest(cmd, local, remote) oldintp = signal(SIGPIPE,SIG_IGN); fin = popen(local + 1, "r"); if (fin == NULL) { - perror(local + 1); + warn("%s", local + 1); (void) signal(SIGINT, oldintr); (void) signal(SIGPIPE, oldintp); code = -1; @@ -399,7 +471,7 @@ sendrequest(cmd, local, remote) } else { fin = fopen(local, "r"); if (fin == NULL) { - perror(local); + warn("local: %s", local); (void) signal(SIGINT, oldintr); code = -1; return; @@ -407,8 +479,9 @@ sendrequest(cmd, local, remote) closefunc = fclose; if (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG) { - fprintf(stderr, "%s: not a plain file.\n", local); + fprintf(stdout, "%s: not a plain file.\n", local); (void) signal(SIGINT, oldintr); + fclose(fin); code = -1; return; } @@ -418,15 +491,20 @@ sendrequest(cmd, local, remote) if (oldintp) (void) signal(SIGPIPE, oldintp); code = -1; + if (closefunc != NULL) + (*closefunc)(fin); return; } if (setjmp(sendabort)) goto abort; + if (remote) { if (command("%s %s", cmd, remote) != PRELIM) { (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); + if (closefunc != NULL) + (*closefunc)(fin); return; } } else @@ -434,79 +512,101 @@ sendrequest(cmd, local, remote) (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); + if (closefunc != NULL) + (*closefunc)(fin); return; } - dout = dataconn("w"); + dout = dataconn(lmode); if (dout == NULL) goto abort; - gettimeofday(&start, (struct timezone *)0); - switch (type) { + (void) gettimeofday(&start, (struct timezone *)0); + oldintp = signal(SIGPIPE, SIG_IGN); + switch (curtype) { case TYPE_I: case TYPE_L: errno = d = 0; - while ((c = read(fileno (fin), buf, sizeof (buf))) > 0) { - if ((d = write(fileno (dout), buf, c)) < 0) - break; + while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) { bytes += c; + for (bufp = buf; c > 0; c -= d, bufp += d) + if ((d = write(fileno(dout), bufp, c)) <= 0) + break; + for (bufp = buf; c > 0; c -= d, bufp += d) + if ((d = write(fileno(dout), bufp, c)) <= 0) + break; if (hash) { - putchar('#'); - fflush(stdout); + while (bytes >= hashbytes) { + (void) putchar('#'); + hashbytes += HASHBYTES; + } + (void) fflush(stdout); } } if (hash && bytes > 0) { - putchar('\n'); - fflush(stdout); + if (bytes < HASHBYTES) + (void) putchar('#'); + (void) putchar('\n'); + (void) fflush(stdout); } if (c < 0) - perror(local); - if (d < 0) - perror("netout"); + warn("local: %s", local); + if (d <= 0) { + if (d == 0) + fprintf(stderr, "netout: write returned 0?\n"); + else if (errno != EPIPE) + warn("netout"); + bytes = -1; + } break; case TYPE_A: while ((c = getc(fin)) != EOF) { if (c == '\n') { while (hash && (bytes >= hashbytes)) { - putchar('#'); - fflush(stdout); - hashbytes += sizeof (buf); + (void) putchar('#'); + (void) fflush(stdout); + hashbytes += HASHBYTES; } if (ferror(dout)) break; - putc('\r', dout); + (void) putc('\r', dout); bytes++; } - putc(c, dout); + (void) putc(c, dout); bytes++; /* if (c == '\r') { */ - /* putc('\0', dout); /* this violates rfc */ + /* (void) putc('\0', dout); // this violates rfc */ /* bytes++; */ /* } */ } if (hash) { if (bytes < hashbytes) - putchar('#'); - putchar('\n'); - fflush(stdout); + (void) putchar('#'); + (void) putchar('\n'); + (void) fflush(stdout); } if (ferror(fin)) - perror(local); - if (ferror(dout)) - perror("netout"); + warn("local: %s", local); + if (ferror(dout)) { + if (errno != EPIPE) + warn("netout"); + bytes = -1; + } break; } - gettimeofday(&stop, (struct timezone *)0); + (void) gettimeofday(&stop, (struct timezone *)0); if (closefunc != NULL) (*closefunc)(fin); (void) fclose(dout); (void) getreply(0); (void) signal(SIGINT, oldintr); - if (bytes > 0 && verbose) - ptransfer("sent", bytes, &start, &stop, local, remote); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + if (bytes > 0) + ptransfer("sent", bytes, &start, &stop); return; abort: - gettimeofday(&stop, (struct timezone *)0); + (void) gettimeofday(&stop, (struct timezone *)0); (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); @@ -524,41 +624,51 @@ abort: code = -1; if (closefunc != NULL && fin != NULL) (*closefunc)(fin); - if (bytes > 0 && verbose) - ptransfer("sent", bytes, &start, &stop, local, remote); + if (bytes > 0) + ptransfer("sent", bytes, &start, &stop); } jmp_buf recvabort; +void abortrecv() { mflag = 0; abrtflag = 0; - printf("\n"); + printf("\nreceive aborted\nwaiting for remote to finish abort\n"); (void) fflush(stdout); longjmp(recvabort, 1); } -recvrequest(cmd, local, remote, mode) - char *cmd, *local, *remote, *mode; +void +recvrequest(cmd, local, remote, lmode, printnames) + char *cmd, *local, *remote, *lmode; + int printnames; { - FILE *fout, *din = 0, *popen(); - int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); - int abortrecv(), oldverbose, oldtype = 0, tcrflag; - char buf[BUFSIZ], *gunique(); - long bytes = 0, hashbytes = sizeof (buf), mask; - register int c, d; + char *bufp, *gunique(), msg; + static char *buf; + static int bufsize; + static char *buf; + long bytes = 0, hashbytes = HASHBYTES; struct timeval start, stop; + struct stat st; - if (proxy && strcmp(cmd,"RETR") == 0) { + is_retr = strcmp(cmd, "RETR") == 0; + if (is_retr && verbose && printnames) { + if (local && *local != '-') + printf("local: %s ", local); + if (remote) + printf("remote: %s\n", remote); + } + if (proxy && is_retr) { proxtrans(cmd, local, remote); return; } closefunc = NULL; oldintr = NULL; oldintp = NULL; - tcrflag = !crflag && !strcmp(cmd, "RETR"); + tcrflag = !crflag && is_retr; if (setjmp(recvabort)) { while (cpend) { (void) getreply(0); @@ -575,10 +685,10 @@ recvrequest(cmd, local, remote, mode) oldintr = signal(SIGINT, abortrecv); if (strcmp(local, "-") && *local != '|') { if (access(local, 2) < 0) { - char *dir = rindex(local, '/'); + char *dir = strrchr(local, '/'); if (errno != ENOENT && errno != EACCES) { - perror(local); + warn("local: %s", local); (void) signal(SIGINT, oldintr); code = -1; return; @@ -589,14 +699,15 @@ recvrequest(cmd, local, remote, mode) if (dir != NULL) *dir = '/'; if (d < 0) { - perror(local); + warn("local: %s", local); (void) signal(SIGINT, oldintr); code = -1; return; } if (!runique && errno == EACCES && - chmod(local,0600) < 0) { - perror(local); + chmod(local, 0600) < 0) { + warn("local: %s", local); + (void) signal(SIGINT, oldintr); (void) signal(SIGINT, oldintr); code = -1; return; @@ -614,6 +725,11 @@ recvrequest(cmd, local, remote, mode) return; } } + if (!is_retr) { + if (curtype != TYPE_A) + changetype(TYPE_A, 0); + } else if (curtype != type) + changetype(type, 0); if (initconn()) { (void) signal(SIGINT, oldintr); code = -1; @@ -621,54 +737,17 @@ recvrequest(cmd, local, remote, mode) } if (setjmp(recvabort)) goto abort; - if (strcmp(cmd, "RETR") && type != TYPE_A) { - oldtype = type; - oldverbose = verbose; - if (!debug) - verbose = 0; - setascii(); - verbose = oldverbose; - } + if (is_retr && restart_point && + command("REST %ld", (long) restart_point) != CONTINUE) + return; if (remote) { if (command("%s %s", cmd, remote) != PRELIM) { (void) signal(SIGINT, oldintr); - if (oldtype) { - if (!debug) - verbose = 0; - switch (oldtype) { - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } - verbose = oldverbose; - } return; } } else { if (command("%s", cmd) != PRELIM) { (void) signal(SIGINT, oldintr); - if (oldtype) { - if (!debug) - verbose = 0; - switch (oldtype) { - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } - verbose = oldverbose; - } return; } } @@ -681,164 +760,145 @@ recvrequest(cmd, local, remote, mode) oldintp = signal(SIGPIPE, SIG_IGN); fout = popen(local + 1, "w"); if (fout == NULL) { - perror(local+1); + warn("%s", local+1); goto abort; } closefunc = pclose; - } - else { - fout = fopen(local, mode); + } else { + fout = fopen(local, lmode); if (fout == NULL) { - perror(local); + warn("local: %s", local); goto abort; } closefunc = fclose; } - gettimeofday(&start, (struct timezone *)0); - switch (type) { + if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) + st.st_blksize = BUFSIZ; + if (st.st_blksize > bufsize) { + if (buf) + (void) free(buf); + buf = malloc((unsigned)st.st_blksize); + if (buf == NULL) { + warn("malloc"); + bufsize = 0; + bufsize = 0; + goto abort; + } + bufsize = st.st_blksize; + } + (void) gettimeofday(&start, (struct timezone *)0); + switch (curtype) { case TYPE_I: case TYPE_L: errno = d = 0; - while ((c = read(fileno(din), buf, sizeof (buf))) > 0) { - if ((d = write(fileno(fout), buf, c)) < 0) + while ((c = read(fileno(din), buf, bufsize)) > 0) { + if ((d = write(fileno(fout), buf, c)) != c) break; bytes += c; if (hash) { - putchar('#'); - fflush(stdout); + while (bytes >= hashbytes) { + (void) putchar('#'); + hashbytes += HASHBYTES; + } + (void) fflush(stdout); } } if (hash && bytes > 0) { - putchar('\n'); - fflush(stdout); + if (bytes < HASHBYTES) + (void) putchar('#'); + (void) putchar('\n'); + (void) fflush(stdout); + } + if (c < 0) { + if (errno != EPIPE) + warn("netin"); + bytes = -1; + } + if (d < c) { + if (d < 0) + perror(local); + else + fprintf(stderr, "%s: short write\n", local); } - if (c < 0) - perror("netin"); - if (d < 0) - perror(local); break; case TYPE_A: while ((c = getc(din)) != EOF) { - if (c == '\r') { + if (c == '\n') + bare_lfs++; + while (c == '\r') { while (hash && (bytes >= hashbytes)) { - putchar('#'); - fflush(stdout); - hashbytes += sizeof (buf); + (void) putchar('#'); + (void) fflush(stdout); + hashbytes += HASHBYTES; } bytes++; if ((c = getc(din)) != '\n' || tcrflag) { - if (ferror (fout)) - break; - putc ('\r', fout); + if (ferror(fout)) + goto break2; + (void) putc('\r', fout); + if (c == '\0') { + bytes++; + goto contin2; + } + if (c == EOF) + goto contin2; + } + if (c == EOF) + goto contin2; } - /*if (c == '\0') { - bytes++; - continue; - }*/ } - putc (c, fout); + (void) putc(c, fout); bytes++; + contin2: ; + } +break2: + if (bare_lfs) { + printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs); + printf("File may not have transferred correctly.\n"); } if (hash) { if (bytes < hashbytes) - putchar('#'); - putchar('\n'); - fflush(stdout); + (void) putchar('#'); + (void) putchar('\n'); + (void) fflush(stdout); } - if (ferror (din)) - perror ("netin"); - if (ferror (fout)) - perror (local); + if (ferror(din)) { + if (errno != EPIPE) + warn("netin"); + bytes = -1; + } + if (ferror(fout)) + warn("local: %s", local); break; } if (closefunc != NULL) (*closefunc)(fout); - signal(SIGINT, oldintr); + (void) signal(SIGINT, oldintr); if (oldintp) (void) signal(SIGPIPE, oldintp); - gettimeofday(&stop, (struct timezone *)0); + (void) gettimeofday(&stop, (struct timezone *)0); (void) fclose(din); (void) getreply(0); - if (bytes > 0 && verbose) - ptransfer("received", bytes, &start, &stop, local, remote); - if (oldtype) { - if (!debug) - verbose = 0; - switch (oldtype) { - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } - verbose = oldverbose; - } + if (bytes > 0 && is_retr) + ptransfer("received", bytes, &start, &stop); return; abort: -/* if server command parser understands TELNET commands, abort using */ -/* recommended IP,SYNC sequence */ +/* abort using RFC959 recommended IP,SYNC sequence */ - gettimeofday(&stop, (struct timezone *)0); + (void) gettimeofday(&stop, (struct timezone *)0); if (oldintp) (void) signal(SIGPIPE, oldintr); - (void) signal(SIGINT,SIG_IGN); - if (oldtype) { - if (!debug) - verbose = 0; - switch (oldtype) { - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } - verbose = oldverbose; - } + (void) signal(SIGINT, SIG_IGN); if (!cpend) { code = -1; - (void) signal(SIGINT,oldintr); + (void) signal(SIGINT, oldintr); return; } - if (telflag) { - char msg[2]; - - fprintf(cout,"%c%c",IAC,IP); - (void) fflush(cout); - *msg = IAC; - *(msg+1) = DM; - if (send(fileno(cout),msg,2,MSG_OOB) != 2) - perror("abort"); - } - fprintf(cout,"ABOR\r\n"); - (void) fflush(cout); - mask = (1 << fileno(cin)) | (din ? (1 << fileno(din)) : 0); - if ((mask = empty(mask,10)) < 0) { - perror("abort"); - code = -1; - lostpeer(); - } - if (din && mask & (1 << fileno(din))) - while ((c = read(fileno(din), buf, sizeof (buf))) > 0) - ; - if ((c = getreply(0)) == ERROR) { /* needed for nic style abort */ - if (data >= 0) { - close(data); - data = -1; - } - (void) getreply(0); - } - (void) getreply(0); + + abort_remote(din); code = -1; if (data >= 0) { (void) close(data); @@ -848,21 +908,19 @@ abort: (*closefunc)(fout); if (din) (void) fclose(din); - if (bytes > 0 && verbose) - ptransfer("received", bytes, &start, &stop, local, remote); - (void) signal(SIGINT,oldintr); + if (bytes > 0) + ptransfer("received", bytes, &start, &stop); + (void) signal(SIGINT, oldintr); } /* - * Need to start a listen on the data channel - * before we send the command, otherwise the - * server's connect may fail. + * Need to start a listen on the data channel before we send the command, + * otherwise the server's connect may fail. */ -static int sendport = -1; - +int initconn() { - register char *p, *a; + char *p, *a; int result, len, tmpno = 0; int on = 1; @@ -871,33 +929,33 @@ noport: if (sendport) data_addr.sin_port = 0; /* let system pick one */ if (data != -1) - (void) close (data); + (void) close(data); data = socket(AF_INET, SOCK_STREAM, 0); if (data < 0) { - perror("ftp: socket"); + warn("socket"); if (tmpno) sendport = 1; return (1); } if (!sendport) - if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) { - perror("ftp: setsockopt (resuse address)"); + if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { + warn("setsockopt (reuse address)"); goto bad; } - if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) { - perror("ftp: bind"); + if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { + warn("bind"); goto bad; } if (options & SO_DEBUG && - setsockopt(data, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) - perror("ftp: setsockopt (ignored)"); + setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) + warn("setsockopt (ignored)"); len = sizeof (data_addr); - if (getsockname(data, (char *)&data_addr, &len) < 0) { - perror("ftp: getsockname"); + if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) { + warn("getsockname"); goto bad; } if (listen(data, 1) < 0) - perror("ftp: listen"); + warn("listen"); if (sendport) { a = (char *)&data_addr.sin_addr; p = (char *)&data_addr.sin_port; @@ -915,6 +973,11 @@ noport: } if (tmpno) sendport = 1; +#ifdef IP_TOS + on = IPTOS_THROUGHPUT; + if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) + warn("setsockopt TOS (ignored)"); +#endif return (0); bad: (void) close(data), data = -1; @@ -924,43 +987,49 @@ bad: } FILE * -dataconn(mode) - char *mode; +dataconn(lmode) + char *lmode; { struct sockaddr_in from; - int s, fromlen = sizeof (from); + int s, fromlen = sizeof (from), tos; - s = accept(data, &from, &fromlen, 0); + s = accept(data, (struct sockaddr *) &from, &fromlen); if (s < 0) { - perror("ftp: accept"); + warn("accept"); (void) close(data), data = -1; return (NULL); } (void) close(data); data = s; - return (fdopen(data, mode)); +#ifdef IP_TOS + tos = IPTOS_THROUGHPUT; + if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) + warn("setsockopt TOS (ignored)"); +#endif + return (fdopen(data, lmode)); } -ptransfer(direction, bytes, t0, t1, local, remote) - char *direction, *local, *remote; +void +ptransfer(direction, bytes, t0, t1) + char *direction; long bytes; struct timeval *t0, *t1; { struct timeval td; float s, bs; - tvsub(&td, t1, t0); - s = td.tv_sec + (td.tv_usec / 1000000.); + if (verbose) { + tvsub(&td, t1, t0); + s = td.tv_sec + (td.tv_usec / 1000000.); #define nz(x) ((x) == 0 ? 1 : (x)) - bs = bytes / nz(s); - if (local && *local != '-') - printf("local: %s ", local); - if (remote) - printf("remote: %s\n", remote); - printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n", - bytes, direction, s, bs / 1024.); + bs = bytes / nz(s); + printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n", + bytes, direction, s, bs / 1024.); + } } +/* +void tvadd(tsum, t0) struct timeval *tsum, *t0; { @@ -970,7 +1039,9 @@ tvadd(tsum, t0) if (tsum->tv_usec > 1000000) tsum->tv_sec++, tsum->tv_usec -= 1000000; } +*/ +void tvsub(tdiff, t1, t0) struct timeval *tdiff, *t1, *t0; { @@ -981,27 +1052,27 @@ tvsub(tdiff, t1, t0) tdiff->tv_sec--, tdiff->tv_usec += 1000000; } +void psabort() { - extern int abrtflag; abrtflag++; } +void pswitch(flag) int flag; { - extern int proxy, abrtflag; - int (*oldintr)(); + sig_t oldintr; static struct comvars { int connect; - char name[32]; + char name[MAXHOSTNAMELEN]; struct sockaddr_in mctl; struct sockaddr_in hctl; FILE *in; FILE *out; - int tflag; int tpe; + int curtpe; int cpnd; int sunqe; int runqe; @@ -1012,7 +1083,7 @@ pswitch(flag) int mapflg; char mi[MAXPATHLEN]; char mo[MAXPATHLEN]; - } proxstruct, tmpstruct; + } proxstruct, tmpstruct; struct comvars *ip, *op; abrtflag = 0; @@ -1023,8 +1094,7 @@ pswitch(flag) ip = &tmpstruct; op = &proxstruct; proxy++; - } - else { + } else { if (!proxy) return; ip = &proxstruct; @@ -1033,8 +1103,11 @@ pswitch(flag) } ip->connect = connected; connected = op->connect; - strncpy(ip->name, hostname, 31); - (ip->name)[strlen(ip->name)] = '\0'; + if (hostname) { + (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1); + ip->name[strlen(ip->name)] = '\0'; + } else + ip->name[0] = 0; hostname = op->name; ip->hctl = hisctladdr; hisctladdr = op->hctl; @@ -1044,12 +1117,10 @@ pswitch(flag) cin = op->in; ip->out = cout; cout = op->out; - ip->tflag = telflag; - telflag = op->tflag; ip->tpe = type; type = op->tpe; - if (!type) - type = 1; + ip->curtpe = curtype; + curtype = op->curtpe; ip->cpnd = cpend; cpend = op->cpnd; ip->sunqe = sunique; @@ -1060,57 +1131,64 @@ pswitch(flag) mcase = op->mcse; ip->ntflg = ntflag; ntflag = op->ntflg; - strncpy(ip->nti, ntin, 16); + (void) strncpy(ip->nti, ntin, 16); (ip->nti)[strlen(ip->nti)] = '\0'; - strcpy(ntin, op->nti); - strncpy(ip->nto, ntout, 16); + (void) strcpy(ntin, op->nti); + (void) strncpy(ip->nto, ntout, 16); (ip->nto)[strlen(ip->nto)] = '\0'; - strcpy(ntout, op->nto); + (void) strcpy(ntout, op->nto); ip->mapflg = mapflag; mapflag = op->mapflg; - strncpy(ip->mi, mapin, MAXPATHLEN - 1); + (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1); (ip->mi)[strlen(ip->mi)] = '\0'; - strcpy(mapin, op->mi); - strncpy(ip->mo, mapout, MAXPATHLEN - 1); + (void) strcpy(mapin, op->mi); + (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1); (ip->mo)[strlen(ip->mo)] = '\0'; - strcpy(mapout, op->mo); + (void) strcpy(mapout, op->mo); (void) signal(SIGINT, oldintr); if (abrtflag) { abrtflag = 0; - (*oldintr)(); + (*oldintr)(SIGINT); } } -jmp_buf ptabort; -int ptabflg; - +void abortpt() { + printf("\n"); - fflush(stdout); + (void) fflush(stdout); ptabflg++; mflag = 0; abrtflag = 0; longjmp(ptabort, 1); } +void proxtrans(cmd, local, remote) char *cmd, *local, *remote; { - int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0; - extern jmp_buf ptabort; + sig_t oldintr; + int secndflag = 0, prox_type, nfnd; char *cmd2; - long mask; + struct fd_set mask; if (strcmp(cmd, "RETR")) cmd2 = "RETR"; else cmd2 = runique ? "STOU" : "STOR"; + if ((prox_type = type) == 0) { + if (unix_server && unix_proxy) + prox_type = TYPE_I; + else + prox_type = TYPE_A; + } + if (curtype != prox_type) + changetype(prox_type, 1); if (command("PASV") != COMPLETE) { - printf("proxy server does not support third part transfers.\n"); + printf("proxy server does not support third party transfers.\n"); return; } - tmptype = type; pswitch(0); if (!connected) { printf("No primary connection\n"); @@ -1118,40 +1196,9 @@ proxtrans(cmd, local, remote) code = -1; return; } - if (type != tmptype) { - oldtype = type; - switch (tmptype) { - case TYPE_A: - setascii(); - break; - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } - } + if (curtype != prox_type) + changetype(prox_type, 1); if (command("PORT %s", pasv) != COMPLETE) { - switch (oldtype) { - case 0: - break; - case TYPE_A: - setascii(); - break; - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } pswitch(1); return; } @@ -1160,22 +1207,6 @@ proxtrans(cmd, local, remote) oldintr = signal(SIGINT, abortpt); if (command("%s %s", cmd, remote) != PRELIM) { (void) signal(SIGINT, oldintr); - switch (oldtype) { - case 0: - break; - case TYPE_A: - setascii(); - break; - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } pswitch(1); return; } @@ -1189,22 +1220,6 @@ proxtrans(cmd, local, remote) pswitch(0); (void) getreply(0); (void) signal(SIGINT, oldintr); - switch (oldtype) { - case 0: - break; - case TYPE_A: - setascii(); - break; - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } pswitch(1); ptflag = 0; printf("local: %s remote: %s\n", local, remote); @@ -1219,45 +1234,8 @@ abort: if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ if (command("%s %s", cmd2, local) != PRELIM) { pswitch(0); - switch (oldtype) { - case 0: - break; - case TYPE_A: - setascii(); - break; - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } - if (cpend && telflag) { - char msg[2]; - - fprintf(cout,"%c%c",IAC,IP); - (void) fflush(cout); - *msg = IAC; - *(msg+1) = DM; - if (send(fileno(cout),msg,2,MSG_OOB) != 2) - perror("abort"); - } - if (cpend) { - fprintf(cout,"ABOR\r\n"); - (void) fflush(cout); - mask = 1 << fileno(cin); - if ((mask = empty(mask,10)) < 0) { - perror("abort"); - if (ptabflg) - code = -1; - lostpeer(); - } - (void) getreply(0); - (void) getreply(0); - } + if (cpend) + abort_remote((FILE *) NULL); } pswitch(1); if (ptabflg) @@ -1265,72 +1243,14 @@ abort: (void) signal(SIGINT, oldintr); return; } - if (cpend && telflag) { - char msg[2]; - - fprintf(cout,"%c%c",IAC,IP); - (void) fflush(cout); - *msg = IAC; - *(msg+1) = DM; - if (send(fileno(cout),msg,2,MSG_OOB) != 2) - perror("abort"); - } - if (cpend) { - fprintf(cout,"ABOR\r\n"); - (void) fflush(cout); - mask = 1 << fileno(cin); - if ((mask = empty(mask,10)) < 0) { - perror("abort"); - if (ptabflg) - code = -1; - lostpeer(); - } - (void) getreply(0); - (void) getreply(0); - } + if (cpend) + abort_remote((FILE *) NULL); pswitch(!proxy); if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ if (command("%s %s", cmd2, local) != PRELIM) { pswitch(0); - switch (oldtype) { - case 0: - break; - case TYPE_A: - setascii(); - break; - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } - if (cpend && telflag) { - char msg[2]; - - fprintf(cout,"%c%c",IAC,IP); - (void) fflush(cout); - *msg = IAC; - *(msg+1) = DM; - if (send(fileno(cout),msg,2,MSG_OOB) != 2) - perror("abort"); - } - if (cpend) { - fprintf(cout,"ABOR\r\n"); - (void) fflush(cout); - mask = 1 << fileno(cin); - if ((mask = empty(mask,10)) < 0) { - perror("abort"); - if (ptabflg) - code = -1; - lostpeer(); - } - (void) getreply(0); - (void) getreply(0); - } + if (cpend) + abort_remote((FILE *) NULL); pswitch(1); if (ptabflg) code = -1; @@ -1338,34 +1258,16 @@ abort: return; } } - if (cpend && telflag) { - char msg[2]; - - fprintf(cout,"%c%c",IAC,IP); - (void) fflush(cout); - *msg = IAC; - *(msg+1) = DM; - if (send(fileno(cout),msg,2,MSG_OOB) != 2) - perror("abort"); - } - if (cpend) { - fprintf(cout,"ABOR\r\n"); - (void) fflush(cout); - mask = 1 << fileno(cin); - if ((mask = empty(mask,10)) < 0) { - perror("abort"); - if (ptabflg) - code = -1; - lostpeer(); - } - (void) getreply(0); - (void) getreply(0); - } + if (cpend) + abort_remote((FILE *) NULL); pswitch(!proxy); if (cpend) { - mask = 1 << fileno(cin); - if ((mask = empty(mask,10)) < 0) { - perror("abort"); + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask, 10)) <= 0) { + if (nfnd < 0) { + warn("abort"); + } if (ptabflg) code = -1; lostpeer(); @@ -1375,41 +1277,31 @@ abort: } if (proxy) pswitch(0); - switch (oldtype) { - case 0: - break; - case TYPE_A: - setascii(); - break; - case TYPE_I: - setbinary(); - break; - case TYPE_E: - setebcdic(); - break; - case TYPE_L: - settenex(); - break; - } pswitch(1); if (ptabflg) code = -1; (void) signal(SIGINT, oldintr); } -reset() +void +reset(argc, argv) + int argc; + char *argv[]; { - long mask; - - mask = 1 << fileno(cin); - while (mask > 0) { - if ((mask = empty(mask,0)) < 0) { - perror("reset"); + struct fd_set mask; + int nfnd = 1; + + FD_ZERO(&mask); + while (nfnd > 0) { + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask,0)) < 0) { + warn("reset"); code = -1; lostpeer(); } - if (mask > 0) + else if (nfnd) { (void) getreply(0); + } } } @@ -1418,7 +1310,7 @@ gunique(local) char *local; { static char new[MAXPATHLEN]; - char *cp = rindex(local, '/'); + char *cp = strrchr(local, '/'); int d, count=0; char ext = '1'; @@ -1428,8 +1320,8 @@ gunique(local) if (cp) *cp = '/'; if (d < 0) { - perror(local); - return((char *) 0); + warn("local: %s", local); + return ((char *) 0); } (void) strcpy(new, local); cp = new + strlen(new); @@ -1437,7 +1329,7 @@ gunique(local) while (!d) { if (++count == 100) { printf("runique: can't find unique file name.\n"); - return((char *) 0); + return ((char *) 0); } *cp++ = ext; *cp = '\0'; @@ -1456,5 +1348,46 @@ gunique(local) cp--; } } - return(new); + return (new); +} + +void +abort_remote(din) + FILE *din; +{ + char buf[BUFSIZ]; + int nfnd; + struct fd_set mask; + + /* + * send IAC in urgent mode instead of DM because 4.3BSD places oob mark + * after urgent byte rather than before as is protocol now + */ + sprintf(buf, "%c%c%c", IAC, IP, IAC); + if (send(fileno(cout), buf, 3, MSG_OOB) != 3) + warn("abort"); + fprintf(cout,"%cABOR\r\n", DM); + (void) fflush(cout); + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if (din) { + FD_SET(fileno(din), &mask); + } + if ((nfnd = empty(&mask, 10)) <= 0) { + if (nfnd < 0) { + warn("abort"); + } + if (ptabflg) + code = -1; + lostpeer(); + } + if (din && FD_ISSET(fileno(din), &mask)) { + while (read(fileno(din), buf, BUFSIZ) > 0) + /* LOOP */; + } + if (getreply(0) == ERROR && code == 552) { + /* 552 needed for nic style abort */ + (void) getreply(0); + } + (void) getreply(0); }