X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/edf71f48c58f5a3f40d446b228782e9bc591aeac..300a5f744ec5365ffab691a4787777cfd67a1338:/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 f5b68ee6fb..dcf1be45a6 100644 --- a/usr/src/usr.bin/ftp/ftp.c +++ b/usr/src/usr.bin/ftp/ftp.c @@ -1,88 +1,109 @@ /* - * Copyright (c) 1980 Regents of the University of California. + * Copyright (c) 1985 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint -static char sccsid[] = "@(#)ftp.c 5.1 (Berkeley) %G%"; +static char sccsid[] = "@(#)ftp.c 5.15 (Berkeley) %G%"; #endif not lint -#include +#include "ftp_var.h" + #include #include #include #include +#include #include #include +#include #include #include #include #include - -#include "ftp_var.h" +#include +#include struct sockaddr_in hisctladdr; struct sockaddr_in data_addr; int data = -1; +int abrtflag = 0; +int ptflag = 0; int connected; struct sockaddr_in myctladdr; +uid_t getuid(); FILE *cin, *cout; FILE *dataconn(); -struct hostent * +char * hookup(host, port) char *host; int port; { - register struct hostent *hp; - int s, len; + register struct hostent *hp = 0; + int s,len; + static char hostnamebuf[80]; bzero((char *)&hisctladdr, sizeof (hisctladdr)); - hp = gethostbyname(host); - if (hp == NULL) { - static struct hostent def; - static struct in_addr defaddr; - static char namebuf[128]; - int inet_addr(); - - defaddr.s_addr = inet_addr(host); - if (defaddr.s_addr == -1) { - fprintf(stderr, "%s: Unknown host.\n", host); - return (0); - } - strcpy(namebuf, host); - def.h_name = namebuf; - hostname = namebuf; - def.h_addr = (char *)&defaddr; - def.h_length = sizeof (struct in_addr); - def.h_addrtype = AF_INET; - def.h_aliases = 0; - hp = &def; - } - hostname = hp->h_name; - hisctladdr.sin_family = hp->h_addrtype; - s = socket(hp->h_addrtype, SOCK_STREAM, 0); + 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 { + hp = gethostbyname(host); + if (hp == NULL) { + printf("%s: unknown host\n", host); + code = -1; + 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); + } + hostname = hostnamebuf; + s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); if (s < 0) { perror("ftp: socket"); + code = -1; return (0); } - if (bind(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) { - perror("ftp: bind"); - goto bad; - } - bcopy(hp->h_addr, (char *)&hisctladdr.sin_addr, hp->h_length); hisctladdr.sin_port = port; - if (connect(s, (char *)&hisctladdr, sizeof (hisctladdr), 0) < 0) { + while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) { + if (hp && hp->h_addr_list[1]) { + int oerrno = errno; + + fprintf(stderr, "ftp: connect to address %s: ", + inet_ntoa(hisctladdr.sin_addr)); + errno = oerrno; + perror((char *) 0); + hp->h_addr_list++; + bcopy(hp->h_addr_list[0], + (caddr_t)&hisctladdr.sin_addr, 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) { + perror("ftp: socket"); + code = -1; + return (0); + } + continue; + } perror("ftp: connect"); + code = -1; goto bad; } len = sizeof (myctladdr); if (getsockname(s, (char *)&myctladdr, &len) < 0) { perror("ftp: getsockname"); + code = -1; goto bad; } cin = fdopen(s, "r"); @@ -90,50 +111,117 @@ hookup(host, port) if (cin == NULL || cout == NULL) { fprintf(stderr, "ftp: fdopen failed.\n"); 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", hp->h_name); - (void) getreply(0); /* read startup message from server */ - return (hp); + printf("Connected to %s.\n", hostname); + if (getreply(0) > 2) { /* read startup message from server */ + if (cin) + (void) fclose(cin); + if (cout) + (void) fclose(cout); + code = -1; + goto bad; + } +#ifdef SO_OOBINLINE + { + int on = 1; + + if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) + < 0 && debug) { + perror("ftp: setsockopt"); + } + } +#endif SO_OOBINLINE + + return (hostname); bad: - close(s); - return ((struct hostent *)0); + (void) close(s); + return ((char *)0); } -login(hp) - struct hostent *hp; +login(host) + char *host; { - char acct[80]; - char *user, *pass; - int n; + char tmp[80]; + char *user, *pass, *acct, *getlogin(), *mygetpass(); + int n, aflag = 0; + + user = pass = acct = 0; + if (ruserpass(host, &user, &pass, &acct) < 0) { + disconnect(); + code = -1; + return(0); + } + if (user == NULL) { + char *myname = getlogin(); - user = pass = 0; - ruserpass(hp->h_name, &user, &pass); + if (myname == NULL) { + struct passwd *pp = getpwuid(getuid()); + + if (pp != NULL) + myname = pp->pw_name; + } + printf("Name (%s:%s): ", host, myname); + (void) fgets(tmp, sizeof(tmp) - 1, stdin); + tmp[strlen(tmp) - 1] = '\0'; + if (*tmp == '\0') + user = myname; + else + user = tmp; + } n = command("USER %s", user); - if (n == CONTINUE) + if (n == CONTINUE) { + if (pass == NULL) + pass = mygetpass("Password:"); n = command("PASS %s", pass); + } if (n == CONTINUE) { - printf("Account: "); (void) fflush(stdout); - (void) fgets(acct, sizeof(acct) - 1, stdin); - acct[strlen(acct) - 1] = '\0'; + aflag++; + acct = mygetpass("Account:"); n = command("ACCT %s", acct); } if (n != COMPLETE) { fprintf(stderr, "Login failed.\n"); return (0); } + if (!aflag && acct != NULL) + (void) command("ACCT %s", acct); + if (proxy) + return(1); + for (n = 0; n < macnum; ++n) { + if (!strcmp("init", macros[n].mac_name)) { + (void) strcpy(line, "$init"); + makeargv(); + domacro(margc, margv); + break; + } + } return (1); } -/*VARARGS 1*/ +cmdabort() +{ + extern jmp_buf ptabort; + + printf("\n"); + (void) fflush(stdout); + abrtflag++; + if (ptflag) + longjmp(ptabort,1); +} + +/*VARARGS1*/ command(fmt, args) char *fmt; { + int r, (*oldintr)(), cmdabort(); + abrtflag = 0; if (debug) { printf("---> "); _doprnt(fmt, &args, stdout); @@ -142,12 +230,19 @@ command(fmt, args) } if (cout == NULL) { perror ("No control connection for command"); + code = -1; return (0); } + oldintr = signal(SIGINT,cmdabort); _doprnt(fmt, &args, cout); fprintf(cout, "\r\n"); (void) fflush(cout); - return (getreply(!strcmp(fmt, "QUIT"))); + cpend = 1; + r = getreply(!strcmp(fmt, "QUIT")); + if (abrtflag && oldintr != SIG_IGN) + (*oldintr)(); + (void) signal(SIGINT, oldintr); + return(r); } #include @@ -156,31 +251,80 @@ getreply(expecteof) int expecteof; { register int c, n; - register int code, dig; - int originalcode = 0, continuation = 0; + register int dig; + int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort(); + int pflag = 0; + char *pt = pasv; + oldintr = signal(SIGINT,cmdabort); for (;;) { dig = n = code = 0; 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,WONT,c); + (void) fflush(cout); + break; + case DO: + case DONT: + c = getc(cin); + fprintf(cout, "%c%c%c",IAC,DONT,c); + (void) fflush(cout); + break; + default: + break; + } + continue; + } dig++; if (c == EOF) { - if (expecteof) + if (expecteof) { + (void) signal(SIGINT,oldintr); + code = 221; return (0); + } lostpeer(); - exit(1); + if (verbose) { + printf("421 Service not available, remote server has closed connection\n"); + (void) fflush(stdout); + 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); + (void) putchar(c); } - if (verbose && c != '\r' || - (n == '5' && dig > 4)) - putchar(c); if (dig < 4 && isdigit(c)) code = code * 10 + (c - '0'); - if (dig == 4 && c == '-') + if (!pflag && code == 227) + pflag = 1; + if (dig > 4 && pflag == 1 && isdigit(c)) + pflag = 2; + if (pflag == 2) { + if (c != '\r' && c != ')') + *pt++ = c; + else { + *pt = '\0'; + pflag = 3; + } + } + if (dig == 4 && c == '-') { + if (continuation) + code = 0; continuation++; + } if (n == 0) n = c; } - if (verbose || n == '5') { - putchar(c); + if (verbose > 0 || verbose > -1 && n == '5') { + (void) putchar(c); (void) fflush (stdout); } if (continuation && code != originalcode) { @@ -188,23 +332,26 @@ getreply(expecteof) originalcode = code; continue; } - if (expecteof || empty(cin)) - return (n - '0'); + if (n != '1') + cpend = 0; + (void) signal(SIGINT,oldintr); + if (code == 421 || originalcode == 421) + lostpeer(); + if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) + (*oldintr)(); + return (n - '0'); } } -empty(f) - FILE *f; +empty(mask, sec) + struct fd_set *mask; + int sec; { - 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); + t.tv_sec = (long) sec; + t.tv_usec = 0; + return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t)); } jmp_buf sendabort; @@ -212,58 +359,105 @@ jmp_buf sendabort; abortsend() { + mflag = 0; + abrtflag = 0; + printf("\nsend aborted\n"); + (void) fflush(stdout); longjmp(sendabort, 1); } sendrequest(cmd, local, remote) char *cmd, *local, *remote; { - FILE *fin, *dout, *popen(); - int (*closefunc)(), pclose(), fclose(), (*oldintr)(); + FILE *fin, *dout = 0, *mypopen(); + int (*closefunc)(), mypclose(), 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; + if (proxy) { + proxtrans(cmd, local, remote); + return; + } closefunc = NULL; - if (setjmp(sendabort)) - goto bad; + oldintr = NULL; + oldintp = NULL; + if (setjmp(sendabort)) { + while (cpend) { + (void) getreply(0); + } + if (data >= 0) { + (void) close(data); + data = -1; + } + if (oldintr) + (void) signal(SIGINT,oldintr); + if (oldintp) + (void) signal(SIGPIPE,oldintp); + code = -1; + return; + } oldintr = signal(SIGINT, abortsend); if (strcmp(local, "-") == 0) fin = stdin; else if (*local == '|') { - fin = popen(local + 1, "r"); + oldintp = signal(SIGPIPE,SIG_IGN); + fin = mypopen(local + 1, "r"); if (fin == NULL) { perror(local + 1); - goto bad; + (void) signal(SIGINT, oldintr); + (void) signal(SIGPIPE, oldintp); + code = -1; + return; } - closefunc = pclose; + closefunc = mypclose; } else { fin = fopen(local, "r"); if (fin == NULL) { perror(local); - goto bad; + (void) signal(SIGINT, oldintr); + code = -1; + return; } closefunc = fclose; if (fstat(fileno(fin), &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG) { - fprintf(stderr, "%s: not a plain file.\n", local); - goto bad; + fprintf(stdout, "%s: not a plain file.\n", local); + (void) signal(SIGINT, oldintr); + code = -1; + return; } } - if (initconn()) - goto bad; + if (initconn()) { + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + code = -1; + return; + } + if (setjmp(sendabort)) + goto abort; if (remote) { - if (command("%s %s", cmd, remote) != PRELIM) - goto bad; + if (command("%s %s", cmd, remote) != PRELIM) { + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + return; + } } else - if (command("%s", cmd) != PRELIM) - goto bad; + if (command("%s", cmd) != PRELIM) { + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + return; + } dout = dataconn("w"); if (dout == NULL) - goto bad; - gettimeofday(&start, (struct timezone *)0); + goto abort; + (void) gettimeofday(&start, (struct timezone *)0); switch (type) { case TYPE_I: @@ -274,13 +468,13 @@ sendrequest(cmd, local, remote) break; bytes += c; if (hash) { - putchar('#'); - fflush(stdout); + (void) putchar('#'); + (void) fflush(stdout); } } if (hash && bytes > 0) { - putchar('\n'); - fflush(stdout); + (void) putchar('\n'); + (void) fflush(stdout); } if (c < 0) perror(local); @@ -292,27 +486,27 @@ sendrequest(cmd, local, remote) while ((c = getc(fin)) != EOF) { if (c == '\n') { while (hash && (bytes >= hashbytes)) { - putchar('#'); - fflush(stdout); + (void) putchar('#'); + (void) fflush(stdout); hashbytes += sizeof (buf); } 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); - bytes++; - } + /* if (c == '\r') { */ + /* (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); @@ -320,22 +514,36 @@ sendrequest(cmd, local, remote) perror("netout"); break; } - gettimeofday(&stop, (struct timezone *)0); + (void) gettimeofday(&stop, (struct timezone *)0); if (closefunc != NULL) (*closefunc)(fin); (void) fclose(dout); (void) getreply(0); -done: - signal(SIGINT, oldintr); + (void) signal(SIGINT, oldintr); if (bytes > 0 && verbose) - ptransfer("sent", bytes, &start, &stop); + ptransfer("sent", bytes, &start, &stop, local, remote); return; -bad: - if (data >= 0) - (void) close(data), data = -1; +abort: + (void) gettimeofday(&stop, (struct timezone *)0); + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + if (!cpend) { + code = -1; + return; + } + if (data >= 0) { + (void) close(data); + data = -1; + } + if (dout) + (void) fclose(dout); + (void) getreply(0); + code = -1; if (closefunc != NULL && fin != NULL) (*closefunc)(fin); - goto done; + if (bytes > 0 && verbose) + ptransfer("sent", bytes, &start, &stop, local, remote); } jmp_buf recvabort; @@ -343,27 +551,57 @@ jmp_buf recvabort; abortrecv() { + mflag = 0; + abrtflag = 0; + printf("\n"); + (void) fflush(stdout); longjmp(recvabort, 1); } recvrequest(cmd, local, remote, mode) char *cmd, *local, *remote, *mode; { - FILE *fout, *din, *popen(); - int (*closefunc)(), pclose(), fclose(), (*oldintr)(); - char buf[BUFSIZ]; + FILE *fout, *din = 0, *mypopen(); + int (*closefunc)(), mypclose(), fclose(), (*oldintr)(), (*oldintp)(); + int abortrecv(), oldverbose, oldtype = 0, tcrflag, nfnd; + char buf[BUFSIZ], *gunique(), msg; long bytes = 0, hashbytes = sizeof (buf); + struct fd_set mask; register int c, d; struct timeval start, stop; + if (proxy && strcmp(cmd,"RETR") == 0) { + proxtrans(cmd, local, remote); + return; + } closefunc = NULL; - if (setjmp(recvabort)) - goto bad; + oldintr = NULL; + oldintp = NULL; + tcrflag = !crflag && !strcmp(cmd, "RETR"); + if (setjmp(recvabort)) { + while (cpend) { + (void) getreply(0); + } + if (data >= 0) { + (void) close(data); + data = -1; + } + if (oldintr) + (void) signal(SIGINT, oldintr); + code = -1; + return; + } oldintr = signal(SIGINT, abortrecv); - if (strcmp(local, "-") && *local != '|') + if (strcmp(local, "-") && *local != '|') { if (access(local, 2) < 0) { char *dir = rindex(local, '/'); + if (errno != ENOENT && errno != EACCES) { + perror(local); + (void) signal(SIGINT, oldintr); + code = -1; + return; + } if (dir != NULL) *dir = 0; d = access(dir ? local : ".", 2); @@ -371,34 +609,111 @@ recvrequest(cmd, local, remote, mode) *dir = '/'; if (d < 0) { perror(local); - goto bad; + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + if (!runique && errno == EACCES && + chmod(local,0600) < 0) { + perror(local); + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + if (runique && errno == EACCES && + (local = gunique(local)) == NULL) { + (void) signal(SIGINT, oldintr); + code = -1; + return; } } - if (initconn()) - goto bad; + else if (runique && (local = gunique(local)) == NULL) { + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + } + if (initconn()) { + (void) signal(SIGINT, oldintr); + code = -1; + return; + } + if (setjmp(recvabort)) + goto abort; + if (strcmp(cmd, "RETR") && type != TYPE_A) { + oldtype = type; + oldverbose = verbose; + if (!debug) + verbose = 0; + setascii(); + verbose = oldverbose; + } if (remote) { - if (command("%s %s", cmd, remote) != PRELIM) - goto bad; - } else - if (command("%s", cmd) != PRELIM) - goto bad; + 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; + } + } + din = dataconn("r"); + if (din == NULL) + goto abort; if (strcmp(local, "-") == 0) fout = stdout; else if (*local == '|') { - fout = popen(local + 1, "w"); - closefunc = pclose; - } else { + oldintp = signal(SIGPIPE, SIG_IGN); + fout = mypopen(local + 1, "w"); + if (fout == NULL) { + perror(local+1); + goto abort; + } + closefunc = mypclose; + } + else { fout = fopen(local, mode); + if (fout == NULL) { + perror(local); + goto abort; + } closefunc = fclose; } - if (fout == NULL) { - perror(local + 1); - goto bad; - } - din = dataconn("r"); - if (din == NULL) - goto bad; - gettimeofday(&start, (struct timezone *)0); + (void) gettimeofday(&start, (struct timezone *)0); switch (type) { case TYPE_I: @@ -409,13 +724,13 @@ recvrequest(cmd, local, remote, mode) break; bytes += c; if (hash) { - putchar('#'); - fflush(stdout); + (void) putchar('#'); + (void) fflush(stdout); } } if (hash && bytes > 0) { - putchar('\n'); - fflush(stdout); + (void) putchar('\n'); + (void) fflush(stdout); } if (c < 0) perror("netin"); @@ -425,31 +740,31 @@ recvrequest(cmd, local, remote, mode) case TYPE_A: while ((c = getc(din)) != EOF) { - if (c == '\r') { + while (c == '\r') { while (hash && (bytes >= hashbytes)) { - putchar('#'); - fflush(stdout); + (void) putchar('#'); + (void) fflush(stdout); hashbytes += sizeof (buf); } bytes++; - if ((c = getc(din)) != '\n') { + if ((c = getc(din)) != '\n' || tcrflag) { if (ferror (fout)) break; - putc ('\r', fout); + (void) putc ('\r', fout); } - if (c == '\0') { + /*if (c == '\0') { bytes++; continue; - } + }*/ } - putc (c, fout); + (void) putc (c, fout); bytes++; } if (hash) { if (bytes < hashbytes) - putchar('#'); - putchar('\n'); - fflush(stdout); + (void) putchar('#'); + (void) putchar('\n'); + (void) fflush(stdout); } if (ferror (din)) perror ("netin"); @@ -457,22 +772,109 @@ recvrequest(cmd, local, remote, mode) perror (local); break; } - gettimeofday(&stop, (struct timezone *)0); - (void) fclose(din); if (closefunc != NULL) (*closefunc)(fout); + (void) signal(SIGINT, oldintr); + if (oldintp) + (void) signal(SIGPIPE, oldintp); + (void) gettimeofday(&stop, (struct timezone *)0); + (void) fclose(din); (void) getreply(0); -done: - signal(SIGINT, oldintr); if (bytes > 0 && verbose) - ptransfer("received", bytes, &start, &stop); + 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; + } return; -bad: - if (data >= 0) - (void) close(data), data = -1; +abort: + +/* abort using RFC959 recommended IP,SYNC sequence */ + + (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; + } + if (!cpend) { + code = -1; + (void) signal(SIGINT,oldintr); + return; + } + + fprintf(cout,"%c%c",IAC,IP); + (void) fflush(cout); + msg = IAC; +/* send IAC in urgent mode instead of DM because UNIX places oob mark */ +/* after urgent byte rather than before as now is protocol */ + if (send(fileno(cout),&msg,1,MSG_OOB) != 1) { + perror("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) { + perror("abort"); + } + code = -1; + lostpeer(); + } + if (din && FD_ISSET(fileno(din), &mask)) { + while ((c = read(fileno(din), buf, sizeof (buf))) > 0) + ; + } + if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */ + if (data >= 0) { + (void) close(data); + data = -1; + } + (void) getreply(0); + } + (void) getreply(0); + code = -1; + if (data >= 0) { + (void) close(data); + data = -1; + } if (closefunc != NULL && fout != NULL) (*closefunc)(fout); - goto done; + if (din) + (void) fclose(din); + if (bytes > 0 && verbose) + ptransfer("received", bytes, &start, &stop, local, remote); + (void) signal(SIGINT,oldintr); } /* @@ -485,7 +887,7 @@ static int sendport = -1; initconn() { register char *p, *a; - int result, len; + int result, len, tmpno = 0; int on = 1; noport: @@ -497,29 +899,29 @@ noport: data = socket(AF_INET, SOCK_STREAM, 0); if (data < 0) { perror("ftp: socket"); + if (tmpno) + sendport = 1; return (1); } if (!sendport) - if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) { + if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { perror("ftp: setsockopt (resuse address)"); goto bad; } - if (bind(data, (char *)&data_addr, sizeof (data_addr), 0) < 0) { + if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { perror("ftp: bind"); goto bad; } if (options & SO_DEBUG && - setsockopt(data, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0) + setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) perror("ftp: setsockopt (ignored)"); len = sizeof (data_addr); if (getsockname(data, (char *)&data_addr, &len) < 0) { perror("ftp: getsockname"); goto bad; } - if (listen(data, 1) < 0) { + if (listen(data, 1) < 0) perror("ftp: listen"); - goto bad; - } if (sendport) { a = (char *)&data_addr.sin_addr; p = (char *)&data_addr.sin_port; @@ -530,13 +932,18 @@ noport: UC(p[0]), UC(p[1])); if (result == ERROR && sendport == -1) { sendport = 0; + tmpno = 1; goto noport; } return (result != COMPLETE); } + if (tmpno) + sendport = 1; return (0); bad: (void) close(data), data = -1; + if (tmpno) + sendport = 1; return (1); } @@ -547,7 +954,7 @@ dataconn(mode) struct sockaddr_in from; int s, fromlen = sizeof (from); - s = accept(data, &from, &fromlen, 0); + s = accept(data, (struct sockaddr *) &from, &fromlen); if (s < 0) { perror("ftp: accept"); (void) close(data), data = -1; @@ -558,8 +965,8 @@ dataconn(mode) return (fdopen(data, mode)); } -ptransfer(direction, bytes, t0, t1) - char *direction; +ptransfer(direction, bytes, t0, t1, local, remote) + char *direction, *local, *remote; long bytes; struct timeval *t0, *t1; { @@ -570,11 +977,15 @@ ptransfer(direction, bytes, t0, t1) 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.); } -tvadd(tsum, t0) +/*tvadd(tsum, t0) struct timeval *tsum, *t0; { @@ -582,7 +993,7 @@ tvadd(tsum, t0) tsum->tv_usec += t0->tv_usec; if (tsum->tv_usec > 1000000) tsum->tv_sec++, tsum->tv_usec -= 1000000; -} +} */ tvsub(tdiff, t1, t0) struct timeval *tdiff, *t1, *t0; @@ -593,3 +1004,491 @@ tvsub(tdiff, t1, t0) if (tdiff->tv_usec < 0) tdiff->tv_sec--, tdiff->tv_usec += 1000000; } + +psabort() +{ + extern int abrtflag; + + abrtflag++; +} + +pswitch(flag) + int flag; +{ + extern int proxy, abrtflag; + int (*oldintr)(); + static struct comvars { + int connect; + char name[MAXHOSTNAMELEN]; + struct sockaddr_in mctl; + struct sockaddr_in hctl; + FILE *in; + FILE *out; + int tpe; + int cpnd; + int sunqe; + int runqe; + int mcse; + int ntflg; + char nti[17]; + char nto[17]; + int mapflg; + char mi[MAXPATHLEN]; + char mo[MAXPATHLEN]; + } proxstruct, tmpstruct; + struct comvars *ip, *op; + + abrtflag = 0; + oldintr = signal(SIGINT, psabort); + if (flag) { + if (proxy) + return; + ip = &tmpstruct; + op = &proxstruct; + proxy++; + } + else { + if (!proxy) + return; + ip = &proxstruct; + op = &tmpstruct; + proxy = 0; + } + ip->connect = connected; + connected = op->connect; + 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; + ip->mctl = myctladdr; + myctladdr = op->mctl; + ip->in = cin; + cin = op->in; + ip->out = cout; + cout = op->out; + ip->tpe = type; + type = op->tpe; + if (!type) + type = 1; + ip->cpnd = cpend; + cpend = op->cpnd; + ip->sunqe = sunique; + sunique = op->sunqe; + ip->runqe = runique; + runique = op->runqe; + ip->mcse = mcase; + mcase = op->mcse; + ip->ntflg = ntflag; + ntflag = op->ntflg; + (void) strncpy(ip->nti, ntin, 16); + (ip->nti)[strlen(ip->nti)] = '\0'; + (void) strcpy(ntin, op->nti); + (void) strncpy(ip->nto, ntout, 16); + (ip->nto)[strlen(ip->nto)] = '\0'; + (void) strcpy(ntout, op->nto); + ip->mapflg = mapflag; + mapflag = op->mapflg; + (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1); + (ip->mi)[strlen(ip->mi)] = '\0'; + (void) strcpy(mapin, op->mi); + (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1); + (ip->mo)[strlen(ip->mo)] = '\0'; + (void) strcpy(mapout, op->mo); + (void) signal(SIGINT, oldintr); + if (abrtflag) { + abrtflag = 0; + (*oldintr)(); + } +} + +jmp_buf ptabort; +int ptabflg; + +abortpt() +{ + printf("\n"); + (void) fflush(stdout); + ptabflg++; + mflag = 0; + abrtflag = 0; + longjmp(ptabort, 1); +} + +proxtrans(cmd, local, remote) + char *cmd, *local, *remote; +{ + int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd; + extern jmp_buf ptabort; + char *cmd2; + struct fd_set mask; + + if (strcmp(cmd, "RETR")) + cmd2 = "RETR"; + else + cmd2 = runique ? "STOU" : "STOR"; + if (command("PASV") != COMPLETE) { + printf("proxy server does not support third part transfers.\n"); + return; + } + tmptype = type; + pswitch(0); + if (!connected) { + printf("No primary connection\n"); + pswitch(1); + 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 (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; + } + if (setjmp(ptabort)) + goto abort; + 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; + } + sleep(2); + pswitch(1); + secndflag++; + if (command("%s %s", cmd2, local) != PRELIM) + goto abort; + ptflag++; + (void) getreply(0); + 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); + return; +abort: + (void) signal(SIGINT, SIG_IGN); + ptflag = 0; + if (strcmp(cmd, "RETR") && !proxy) + pswitch(1); + else if (!strcmp(cmd, "RETR") && proxy) + pswitch(0); + 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) { + 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); + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask,10)) <= 0) { + if (nfnd < 0) { + perror("abort"); + } + if (ptabflg) + code = -1; + lostpeer(); + } + (void) getreply(0); + (void) getreply(0); + } + } + pswitch(1); + if (ptabflg) + code = -1; + (void) signal(SIGINT, oldintr); + return; + } + if (cpend) { + 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); + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask,10)) <= 0) { + if (nfnd < 0) { + perror("abort"); + } + if (ptabflg) + code = -1; + lostpeer(); + } + (void) getreply(0); + (void) getreply(0); + } + 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) { + 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); + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask,10)) <= 0) { + if (nfnd < 0) { + perror("abort"); + } + if (ptabflg) + code = -1; + lostpeer(); + } + (void) getreply(0); + (void) getreply(0); + } + pswitch(1); + if (ptabflg) + code = -1; + (void) signal(SIGINT, oldintr); + return; + } + } + if (cpend) { + 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); + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask,10)) <= 0) { + if (nfnd < 0) { + perror("abort"); + } + if (ptabflg) + code = -1; + lostpeer(); + } + (void) getreply(0); + (void) getreply(0); + } + pswitch(!proxy); + if (cpend) { + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask,10)) <= 0) { + if (nfnd < 0) { + perror("abort"); + } + if (ptabflg) + code = -1; + lostpeer(); + } + (void) getreply(0); + (void) getreply(0); + } + 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() +{ + struct fd_set mask; + int nfnd = 1; + + FD_ZERO(&mask); + while (nfnd > 0) { + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask,0)) < 0) { + perror("reset"); + code = -1; + lostpeer(); + } + else if (nfnd) { + (void) getreply(0); + } + } +} + +char * +gunique(local) + char *local; +{ + static char new[MAXPATHLEN]; + char *cp = rindex(local, '/'); + int d, count=0; + char ext = '1'; + + if (cp) + *cp = '\0'; + d = access(cp ? local : ".", 2); + if (cp) + *cp = '/'; + if (d < 0) { + perror(local); + return((char *) 0); + } + (void) strcpy(new, local); + cp = new + strlen(new); + *cp++ = '.'; + while (!d) { + if (++count == 100) { + printf("runique: can't find unique file name.\n"); + return((char *) 0); + } + *cp++ = ext; + *cp = '\0'; + if (ext == '9') + ext = '0'; + else + ext++; + if ((d = access(new, 0)) < 0) + break; + if (ext != '0') + cp--; + else if (*(cp - 2) == '.') + *(cp - 1) = '1'; + else { + *(cp - 2) = *(cp - 2) + 1; + cp--; + } + } + return(new); +}