121739Sdist /* 266672Spendry * Copyright (c) 1985, 1989, 1993, 1994 362010Sbostic * The Regents of the University of California. All rights reserved. 433737Sbostic * 542665Sbostic * %sccs.include.redist.c% 621739Sdist */ 721739Sdist 810296Ssam #ifndef lint 9*67794Smckusick static char sccsid[] = "@(#)ftp.c 8.5 (Berkeley) 10/09/94"; 1033737Sbostic #endif /* not lint */ 1110296Ssam 1236940Skarels #include <sys/param.h> 1310296Ssam #include <sys/stat.h> 1410296Ssam #include <sys/ioctl.h> 1510296Ssam #include <sys/socket.h> 1613614Ssam #include <sys/time.h> 1736935Skarels #include <sys/file.h> 1810296Ssam 1910296Ssam #include <netinet/in.h> 2044340Skarels #include <netinet/in_systm.h> 2144340Skarels #include <netinet/ip.h> 2266670Spendry #include <arpa/inet.h> 2312397Ssam #include <arpa/ftp.h> 2426048Sminshall #include <arpa/telnet.h> 2510296Ssam 2666670Spendry #include <ctype.h> 2766670Spendry #include <err.h> 2866670Spendry #include <errno.h> 2966670Spendry #include <fcntl.h> 3010296Ssam #include <netdb.h> 3126048Sminshall #include <pwd.h> 3266670Spendry #include <signal.h> 3366670Spendry #include <stdio.h> 3454192Sbostic #include <stdlib.h> 3554192Sbostic #include <string.h> 3666670Spendry #include <unistd.h> 3766670Spendry #include <varargs.h> 3810296Ssam 3936940Skarels #include "ftp_var.h" 4036940Skarels 4166670Spendry extern int h_errno; 4266670Spendry 4310296Ssam struct sockaddr_in hisctladdr; 4410296Ssam struct sockaddr_in data_addr; 4510296Ssam int data = -1; 4626048Sminshall int abrtflag = 0; 4766670Spendry jmp_buf ptabort; 4866670Spendry int ptabflg; 4926048Sminshall int ptflag = 0; 5010296Ssam struct sockaddr_in myctladdr; 5137225Skarels off_t restart_point = 0; 5210296Ssam 5338202Srick 5410296Ssam FILE *cin, *cout; 5510296Ssam 5625904Skarels char * 5710296Ssam hookup(host, port) 5810296Ssam char *host; 5910296Ssam int port; 6010296Ssam { 6166670Spendry struct hostent *hp = 0; 6244340Skarels int s, len, tos; 6325904Skarels static char hostnamebuf[80]; 6410296Ssam 6566670Spendry memset((char *)&hisctladdr, 0, sizeof (hisctladdr)); 6625904Skarels hisctladdr.sin_addr.s_addr = inet_addr(host); 6725904Skarels if (hisctladdr.sin_addr.s_addr != -1) { 6825904Skarels hisctladdr.sin_family = AF_INET; 6936940Skarels (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf)); 7036940Skarels } else { 7125100Sbloom hp = gethostbyname(host); 7225904Skarels if (hp == NULL) { 7366670Spendry warnx("%s: %s", host, hstrerror(h_errno)); 7426048Sminshall code = -1; 7566670Spendry return ((char *) 0); 7625904Skarels } 7725904Skarels hisctladdr.sin_family = hp->h_addrtype; 7866670Spendry memmove((caddr_t)&hisctladdr.sin_addr, 7966670Spendry hp->h_addr_list[0], hp->h_length); 8036940Skarels (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf)); 8110296Ssam } 8225904Skarels hostname = hostnamebuf; 8325904Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 8410296Ssam if (s < 0) { 8566670Spendry warn("socket"); 8626048Sminshall code = -1; 8710296Ssam return (0); 8810296Ssam } 8910296Ssam hisctladdr.sin_port = port; 9038133Srick while (connect(s, (struct sockaddr *)&hisctladdr, sizeof (hisctladdr)) < 0) { 9125904Skarels if (hp && hp->h_addr_list[1]) { 9225904Skarels int oerrno = errno; 9366670Spendry char *ia; 9425904Skarels 9566670Spendry ia = inet_ntoa(hisctladdr.sin_addr); 9625904Skarels errno = oerrno; 9766670Spendry warn("connect to address %s", ia); 9825904Skarels hp->h_addr_list++; 9966670Spendry memmove((caddr_t)&hisctladdr.sin_addr, 10066670Spendry hp->h_addr_list[0], hp->h_length); 10126496Sminshall fprintf(stdout, "Trying %s...\n", 10225904Skarels inet_ntoa(hisctladdr.sin_addr)); 10326813Skarels (void) close(s); 10426813Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 10526813Skarels if (s < 0) { 10666670Spendry warn("socket"); 10726813Skarels code = -1; 10826813Skarels return (0); 10926813Skarels } 11025904Skarels continue; 11125904Skarels } 11266670Spendry warn("connect"); 11326048Sminshall code = -1; 11410296Ssam goto bad; 11510296Ssam } 11611627Ssam len = sizeof (myctladdr); 11738133Srick if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) { 11866670Spendry warn("getsockname"); 11926048Sminshall code = -1; 12010296Ssam goto bad; 12110296Ssam } 12244340Skarels #ifdef IP_TOS 12344340Skarels tos = IPTOS_LOWDELAY; 12444340Skarels if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) 12566670Spendry warn("setsockopt TOS (ignored)"); 12644340Skarels #endif 12710296Ssam cin = fdopen(s, "r"); 12810296Ssam cout = fdopen(s, "w"); 12911219Ssam if (cin == NULL || cout == NULL) { 13066670Spendry warnx("fdopen failed."); 13110296Ssam if (cin) 13226496Sminshall (void) fclose(cin); 13310296Ssam if (cout) 13426496Sminshall (void) fclose(cout); 13526048Sminshall code = -1; 13610296Ssam goto bad; 13710296Ssam } 13810296Ssam if (verbose) 13926067Sminshall printf("Connected to %s.\n", hostname); 14027687Sminshall if (getreply(0) > 2) { /* read startup message from server */ 14126048Sminshall if (cin) 14226496Sminshall (void) fclose(cin); 14326048Sminshall if (cout) 14426496Sminshall (void) fclose(cout); 14526048Sminshall code = -1; 14626048Sminshall goto bad; 14726048Sminshall } 14827687Sminshall #ifdef SO_OOBINLINE 14927687Sminshall { 15027687Sminshall int on = 1; 15126048Sminshall 15240193Sbostic if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) 15327687Sminshall < 0 && debug) { 15466670Spendry warn("setsockopt"); 15527687Sminshall } 15627687Sminshall } 15738133Srick #endif /* SO_OOBINLINE */ 15826048Sminshall 15925904Skarels return (hostname); 16010296Ssam bad: 16126496Sminshall (void) close(s); 16225904Skarels return ((char *)0); 16310296Ssam } 16410296Ssam 16566670Spendry int 16625904Skarels login(host) 16725904Skarels char *host; 16810296Ssam { 16926048Sminshall char tmp[80]; 17066670Spendry char *user, *pass, *acct; 17126048Sminshall int n, aflag = 0; 17210296Ssam 17326048Sminshall user = pass = acct = 0; 17426048Sminshall if (ruserpass(host, &user, &pass, &acct) < 0) { 17526048Sminshall code = -1; 17666670Spendry return (0); 17726048Sminshall } 17837458Skarels while (user == NULL) { 17926048Sminshall char *myname = getlogin(); 18026048Sminshall 18126048Sminshall if (myname == NULL) { 18226048Sminshall struct passwd *pp = getpwuid(getuid()); 18326048Sminshall 18426448Slepreau if (pp != NULL) 18526048Sminshall myname = pp->pw_name; 18626048Sminshall } 18737458Skarels if (myname) 18837458Skarels printf("Name (%s:%s): ", host, myname); 18937458Skarels else 19037458Skarels printf("Name (%s): ", host); 19126048Sminshall (void) fgets(tmp, sizeof(tmp) - 1, stdin); 19226048Sminshall tmp[strlen(tmp) - 1] = '\0'; 19326448Slepreau if (*tmp == '\0') 19426048Sminshall user = myname; 19526448Slepreau else 19626048Sminshall user = tmp; 19726048Sminshall } 19810296Ssam n = command("USER %s", user); 19926048Sminshall if (n == CONTINUE) { 20026448Slepreau if (pass == NULL) 20135659Sbostic pass = getpass("Password:"); 20210296Ssam n = command("PASS %s", pass); 20326048Sminshall } 20410296Ssam if (n == CONTINUE) { 20526048Sminshall aflag++; 20635659Sbostic acct = getpass("Account:"); 20710296Ssam n = command("ACCT %s", acct); 20810296Ssam } 20910296Ssam if (n != COMPLETE) { 21066670Spendry warnx("Login failed."); 21110296Ssam return (0); 21210296Ssam } 21326448Slepreau if (!aflag && acct != NULL) 21426048Sminshall (void) command("ACCT %s", acct); 21526448Slepreau if (proxy) 21666670Spendry return (1); 21726048Sminshall for (n = 0; n < macnum; ++n) { 21826048Sminshall if (!strcmp("init", macros[n].mac_name)) { 21926496Sminshall (void) strcpy(line, "$init"); 22026048Sminshall makeargv(); 22126048Sminshall domacro(margc, margv); 22226048Sminshall break; 22326048Sminshall } 22426048Sminshall } 22510296Ssam return (1); 22610296Ssam } 22710296Ssam 22840193Sbostic void 22926048Sminshall cmdabort() 23026048Sminshall { 23126048Sminshall 23226048Sminshall printf("\n"); 23326048Sminshall (void) fflush(stdout); 23426048Sminshall abrtflag++; 23526448Slepreau if (ptflag) 23626048Sminshall longjmp(ptabort,1); 23726048Sminshall } 23826048Sminshall 23938133Srick /*VARARGS*/ 24066670Spendry int 24138133Srick command(va_alist) 24238133Srick va_dcl 24338133Srick { 24438133Srick va_list ap; 24510296Ssam char *fmt; 24638133Srick int r; 24740193Sbostic sig_t oldintr; 24810296Ssam 24926048Sminshall abrtflag = 0; 25010296Ssam if (debug) { 25110296Ssam printf("---> "); 25238133Srick va_start(ap); 25338133Srick fmt = va_arg(ap, char *); 25438133Srick if (strncmp("PASS ", fmt, 5) == 0) 25538133Srick printf("PASS XXXX"); 25638133Srick else 25738133Srick vfprintf(stdout, fmt, ap); 25838133Srick va_end(ap); 25910296Ssam printf("\n"); 26010296Ssam (void) fflush(stdout); 26110296Ssam } 26211219Ssam if (cout == NULL) { 26366670Spendry warn("No control connection for command"); 26426048Sminshall code = -1; 26511219Ssam return (0); 26611219Ssam } 26738133Srick oldintr = signal(SIGINT, cmdabort); 26838133Srick va_start(ap); 26938133Srick fmt = va_arg(ap, char *); 27038133Srick vfprintf(cout, fmt, ap); 27138133Srick va_end(ap); 27210296Ssam fprintf(cout, "\r\n"); 27310296Ssam (void) fflush(cout); 27426048Sminshall cpend = 1; 27526048Sminshall r = getreply(!strcmp(fmt, "QUIT")); 27626448Slepreau if (abrtflag && oldintr != SIG_IGN) 27746828Sbostic (*oldintr)(SIGINT); 27826048Sminshall (void) signal(SIGINT, oldintr); 27966670Spendry return (r); 28010296Ssam } 28110296Ssam 28237229Skarels char reply_string[BUFSIZ]; /* last line of previous reply */ 28336935Skarels 28466670Spendry int 28510296Ssam getreply(expecteof) 28610296Ssam int expecteof; 28710296Ssam { 28866670Spendry int c, n; 28966670Spendry int dig; 29038133Srick int originalcode = 0, continuation = 0; 29140193Sbostic sig_t oldintr; 29226048Sminshall int pflag = 0; 29366670Spendry char *cp, *pt = pasv; 29410296Ssam 29538133Srick oldintr = signal(SIGINT, cmdabort); 29610296Ssam for (;;) { 29710296Ssam dig = n = code = 0; 29837229Skarels cp = reply_string; 29910296Ssam while ((c = getc(cin)) != '\n') { 30027687Sminshall if (c == IAC) { /* handle telnet commands */ 30127687Sminshall switch (c = getc(cin)) { 30227687Sminshall case WILL: 30327687Sminshall case WONT: 30427687Sminshall c = getc(cin); 30538133Srick fprintf(cout, "%c%c%c", IAC, DONT, c); 30627687Sminshall (void) fflush(cout); 30727687Sminshall break; 30827687Sminshall case DO: 30927687Sminshall case DONT: 31027687Sminshall c = getc(cin); 31138133Srick fprintf(cout, "%c%c%c", IAC, WONT, c); 31227687Sminshall (void) fflush(cout); 31327687Sminshall break; 31427687Sminshall default: 31527687Sminshall break; 31627687Sminshall } 31727687Sminshall continue; 31827687Sminshall } 31910296Ssam dig++; 32010296Ssam if (c == EOF) { 32126048Sminshall if (expecteof) { 32226048Sminshall (void) signal(SIGINT,oldintr); 32326048Sminshall code = 221; 32410296Ssam return (0); 32526048Sminshall } 32610296Ssam lostpeer(); 32726048Sminshall if (verbose) { 32826048Sminshall printf("421 Service not available, remote server has closed connection\n"); 32926048Sminshall (void) fflush(stdout); 33026048Sminshall } 33133772Scsvsj code = 421; 33266670Spendry return (4); 33310296Ssam } 33426048Sminshall if (c != '\r' && (verbose > 0 || 33526048Sminshall (verbose > -1 && n == '5' && dig > 4))) { 33626448Slepreau if (proxflag && 33726448Slepreau (dig == 1 || dig == 5 && verbose == 0)) 33826048Sminshall printf("%s:",hostname); 33926496Sminshall (void) putchar(c); 34026048Sminshall } 34110296Ssam if (dig < 4 && isdigit(c)) 34210296Ssam code = code * 10 + (c - '0'); 34326448Slepreau if (!pflag && code == 227) 34426048Sminshall pflag = 1; 34526448Slepreau if (dig > 4 && pflag == 1 && isdigit(c)) 34626048Sminshall pflag = 2; 34726048Sminshall if (pflag == 2) { 34826448Slepreau if (c != '\r' && c != ')') 34926048Sminshall *pt++ = c; 35026048Sminshall else { 35126048Sminshall *pt = '\0'; 35226048Sminshall pflag = 3; 35326048Sminshall } 35426048Sminshall } 35526048Sminshall if (dig == 4 && c == '-') { 35626448Slepreau if (continuation) 35726048Sminshall code = 0; 35810296Ssam continuation++; 35926048Sminshall } 36010296Ssam if (n == 0) 36110296Ssam n = c; 36237229Skarels if (cp < &reply_string[sizeof(reply_string) - 1]) 36337229Skarels *cp++ = c; 36410296Ssam } 36526048Sminshall if (verbose > 0 || verbose > -1 && n == '5') { 36626496Sminshall (void) putchar(c); 36711346Ssam (void) fflush (stdout); 36811346Ssam } 36910296Ssam if (continuation && code != originalcode) { 37010296Ssam if (originalcode == 0) 37110296Ssam originalcode = code; 37210296Ssam continue; 37310296Ssam } 37436935Skarels *cp = '\0'; 37526448Slepreau if (n != '1') 37626048Sminshall cpend = 0; 37726048Sminshall (void) signal(SIGINT,oldintr); 37826448Slepreau if (code == 421 || originalcode == 421) 37926048Sminshall lostpeer(); 38026448Slepreau if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) 38146828Sbostic (*oldintr)(SIGINT); 38225907Smckusick return (n - '0'); 38310296Ssam } 38410296Ssam } 38510296Ssam 38666670Spendry int 38726048Sminshall empty(mask, sec) 38827687Sminshall struct fd_set *mask; 38926048Sminshall int sec; 39026048Sminshall { 39126048Sminshall struct timeval t; 39226048Sminshall 39326048Sminshall t.tv_sec = (long) sec; 39426048Sminshall t.tv_usec = 0; 39566670Spendry return (select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t)); 39626048Sminshall } 39726048Sminshall 39810296Ssam jmp_buf sendabort; 39910296Ssam 40040193Sbostic void 40110296Ssam abortsend() 40210296Ssam { 40310296Ssam 40426048Sminshall mflag = 0; 40526048Sminshall abrtflag = 0; 40638133Srick printf("\nsend aborted\nwaiting for remote to finish abort\n"); 40726048Sminshall (void) fflush(stdout); 40810296Ssam longjmp(sendabort, 1); 40910296Ssam } 41010296Ssam 41136940Skarels #define HASHBYTES 1024 41236940Skarels 41366670Spendry void 41437225Skarels sendrequest(cmd, local, remote, printnames) 41510296Ssam char *cmd, *local, *remote; 41637225Skarels int printnames; 41710296Ssam { 41840193Sbostic struct stat st; 41940193Sbostic struct timeval start, stop; 42066670Spendry int c, d; 42135659Sbostic FILE *fin, *dout = 0, *popen(); 42266670Spendry int (*closefunc) __P((FILE *)); 42340193Sbostic sig_t oldintr, oldintp; 42436940Skarels long bytes = 0, hashbytes = HASHBYTES; 42540193Sbostic char *lmode, buf[BUFSIZ], *bufp; 42610296Ssam 42737225Skarels if (verbose && printnames) { 42837225Skarels if (local && *local != '-') 42937225Skarels printf("local: %s ", local); 43037225Skarels if (remote) 43137225Skarels printf("remote: %s\n", remote); 43237225Skarels } 43326048Sminshall if (proxy) { 43426048Sminshall proxtrans(cmd, local, remote); 43526048Sminshall return; 43626048Sminshall } 43738033Skarels if (curtype != type) 43838033Skarels changetype(type, 0); 43910296Ssam closefunc = NULL; 44026048Sminshall oldintr = NULL; 44126048Sminshall oldintp = NULL; 44240193Sbostic lmode = "w"; 44326048Sminshall if (setjmp(sendabort)) { 44426048Sminshall while (cpend) { 44526048Sminshall (void) getreply(0); 44626048Sminshall } 44726048Sminshall if (data >= 0) { 44826048Sminshall (void) close(data); 44926048Sminshall data = -1; 45026048Sminshall } 45126448Slepreau if (oldintr) 45226048Sminshall (void) signal(SIGINT,oldintr); 45326448Slepreau if (oldintp) 45426048Sminshall (void) signal(SIGPIPE,oldintp); 45526048Sminshall code = -1; 45626048Sminshall return; 45726048Sminshall } 45810296Ssam oldintr = signal(SIGINT, abortsend); 45910296Ssam if (strcmp(local, "-") == 0) 46010296Ssam fin = stdin; 46110296Ssam else if (*local == '|') { 46226048Sminshall oldintp = signal(SIGPIPE,SIG_IGN); 46335659Sbostic fin = popen(local + 1, "r"); 46410296Ssam if (fin == NULL) { 46566670Spendry warn("%s", local + 1); 46626048Sminshall (void) signal(SIGINT, oldintr); 46726048Sminshall (void) signal(SIGPIPE, oldintp); 46826048Sminshall code = -1; 46926048Sminshall return; 47010296Ssam } 47135659Sbostic closefunc = pclose; 47210296Ssam } else { 47310296Ssam fin = fopen(local, "r"); 47410296Ssam if (fin == NULL) { 47566670Spendry warn("local: %s", local); 47626048Sminshall (void) signal(SIGINT, oldintr); 47726048Sminshall code = -1; 47826048Sminshall return; 47910296Ssam } 48010296Ssam closefunc = fclose; 48110296Ssam if (fstat(fileno(fin), &st) < 0 || 48210296Ssam (st.st_mode&S_IFMT) != S_IFREG) { 48326496Sminshall fprintf(stdout, "%s: not a plain file.\n", local); 48426048Sminshall (void) signal(SIGINT, oldintr); 48536935Skarels fclose(fin); 48626048Sminshall code = -1; 48726048Sminshall return; 48810296Ssam } 48910296Ssam } 49026048Sminshall if (initconn()) { 49126048Sminshall (void) signal(SIGINT, oldintr); 49226448Slepreau if (oldintp) 49326048Sminshall (void) signal(SIGPIPE, oldintp); 49426048Sminshall code = -1; 49536935Skarels if (closefunc != NULL) 49636935Skarels (*closefunc)(fin); 49726048Sminshall return; 49826048Sminshall } 49926448Slepreau if (setjmp(sendabort)) 50026048Sminshall goto abort; 50136935Skarels 50237225Skarels if (restart_point && 50337225Skarels (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { 50466724Spendry int rc; 50566724Spendry 50666724Spendry switch (curtype) { 50766724Spendry case TYPE_A: 50866724Spendry rc = fseek(fin, (long) restart_point, SEEK_SET); 50966724Spendry break; 51066724Spendry case TYPE_I: 51166724Spendry case TYPE_L: 51266724Spendry rc = lseek(fileno(fin), restart_point, SEEK_SET); 51366724Spendry break; 51466724Spendry } 51566724Spendry if (rc < 0) { 51666670Spendry warn("local: %s", local); 51737225Skarels restart_point = 0; 51837225Skarels if (closefunc != NULL) 51937225Skarels (*closefunc)(fin); 52037225Skarels return; 52137225Skarels } 52237225Skarels if (command("REST %ld", (long) restart_point) 52337225Skarels != CONTINUE) { 52437225Skarels restart_point = 0; 52537225Skarels if (closefunc != NULL) 52637225Skarels (*closefunc)(fin); 52737225Skarels return; 52837225Skarels } 52937225Skarels restart_point = 0; 53040193Sbostic lmode = "r+w"; 53137225Skarels } 53210296Ssam if (remote) { 53326048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 53426048Sminshall (void) signal(SIGINT, oldintr); 53526448Slepreau if (oldintp) 53626048Sminshall (void) signal(SIGPIPE, oldintp); 53736935Skarels if (closefunc != NULL) 53836935Skarels (*closefunc)(fin); 53926048Sminshall return; 54026048Sminshall } 54110296Ssam } else 54226048Sminshall if (command("%s", cmd) != PRELIM) { 54326048Sminshall (void) signal(SIGINT, oldintr); 54426448Slepreau if (oldintp) 54526048Sminshall (void) signal(SIGPIPE, oldintp); 54636935Skarels if (closefunc != NULL) 54736935Skarels (*closefunc)(fin); 54826048Sminshall return; 54926048Sminshall } 55040193Sbostic dout = dataconn(lmode); 55126448Slepreau if (dout == NULL) 55226048Sminshall goto abort; 55326496Sminshall (void) gettimeofday(&start, (struct timezone *)0); 55436935Skarels oldintp = signal(SIGPIPE, SIG_IGN); 55542278Skarels switch (curtype) { 55611219Ssam 55711219Ssam case TYPE_I: 55811219Ssam case TYPE_L: 55911346Ssam errno = d = 0; 56036942Skarels while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) { 56111219Ssam bytes += c; 56236942Skarels for (bufp = buf; c > 0; c -= d, bufp += d) 56336942Skarels if ((d = write(fileno(dout), bufp, c)) <= 0) 56436942Skarels break; 56511651Ssam if (hash) { 56636940Skarels while (bytes >= hashbytes) { 56736940Skarels (void) putchar('#'); 56836940Skarels hashbytes += HASHBYTES; 56936940Skarels } 57026496Sminshall (void) fflush(stdout); 57111651Ssam } 57211219Ssam } 57313213Ssam if (hash && bytes > 0) { 57436940Skarels if (bytes < HASHBYTES) 57536940Skarels (void) putchar('#'); 57626496Sminshall (void) putchar('\n'); 57726496Sminshall (void) fflush(stdout); 57811651Ssam } 57911219Ssam if (c < 0) 58066670Spendry warn("local: %s", local); 58148507Srick if (d < 0) { 58248507Srick if (errno != EPIPE) 58366670Spendry warn("netout"); 58436935Skarels bytes = -1; 58536935Skarels } 58611219Ssam break; 58711219Ssam 58811219Ssam case TYPE_A: 58911219Ssam while ((c = getc(fin)) != EOF) { 59011219Ssam if (c == '\n') { 59111651Ssam while (hash && (bytes >= hashbytes)) { 59226496Sminshall (void) putchar('#'); 59326496Sminshall (void) fflush(stdout); 59436940Skarels hashbytes += HASHBYTES; 59511651Ssam } 59611219Ssam if (ferror(dout)) 59711219Ssam break; 59826496Sminshall (void) putc('\r', dout); 59911219Ssam bytes++; 60011219Ssam } 60126496Sminshall (void) putc(c, dout); 60211219Ssam bytes++; 60326048Sminshall /* if (c == '\r') { */ 60466670Spendry /* (void) putc('\0', dout); // this violates rfc */ 60526048Sminshall /* bytes++; */ 60626048Sminshall /* } */ 60711219Ssam } 60811651Ssam if (hash) { 60913213Ssam if (bytes < hashbytes) 61026496Sminshall (void) putchar('#'); 61126496Sminshall (void) putchar('\n'); 61226496Sminshall (void) fflush(stdout); 61311651Ssam } 61411219Ssam if (ferror(fin)) 61566670Spendry warn("local: %s", local); 61636935Skarels if (ferror(dout)) { 61736935Skarels if (errno != EPIPE) 61866670Spendry warn("netout"); 61936935Skarels bytes = -1; 62036935Skarels } 62111219Ssam break; 62210296Ssam } 62326496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 62410296Ssam if (closefunc != NULL) 62526048Sminshall (*closefunc)(fin); 62610296Ssam (void) fclose(dout); 62726048Sminshall (void) getreply(0); 62826048Sminshall (void) signal(SIGINT, oldintr); 62936935Skarels if (oldintp) 63036935Skarels (void) signal(SIGPIPE, oldintp); 63135699Sbostic if (bytes > 0) 63237225Skarels ptransfer("sent", bytes, &start, &stop); 63310296Ssam return; 63426048Sminshall abort: 63526496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 63626048Sminshall (void) signal(SIGINT, oldintr); 63726448Slepreau if (oldintp) 63826048Sminshall (void) signal(SIGPIPE, oldintp); 63926048Sminshall if (!cpend) { 64026048Sminshall code = -1; 64126048Sminshall return; 64226048Sminshall } 64326048Sminshall if (data >= 0) { 64426048Sminshall (void) close(data); 64526048Sminshall data = -1; 64626048Sminshall } 64726448Slepreau if (dout) 64826048Sminshall (void) fclose(dout); 64926048Sminshall (void) getreply(0); 65026048Sminshall code = -1; 65110296Ssam if (closefunc != NULL && fin != NULL) 65226048Sminshall (*closefunc)(fin); 65335699Sbostic if (bytes > 0) 65437225Skarels ptransfer("sent", bytes, &start, &stop); 65510296Ssam } 65610296Ssam 65710296Ssam jmp_buf recvabort; 65810296Ssam 65940193Sbostic void 66010296Ssam abortrecv() 66110296Ssam { 66210296Ssam 66326048Sminshall mflag = 0; 66426048Sminshall abrtflag = 0; 66538133Srick printf("\nreceive aborted\nwaiting for remote to finish abort\n"); 66626048Sminshall (void) fflush(stdout); 66710296Ssam longjmp(recvabort, 1); 66810296Ssam } 66910296Ssam 67066670Spendry void 67140193Sbostic recvrequest(cmd, local, remote, lmode, printnames) 67240193Sbostic char *cmd, *local, *remote, *lmode; 67366670Spendry int printnames; 67410296Ssam { 67566670Spendry FILE *fout, *din = 0; 67666670Spendry int (*closefunc) __P((FILE *)); 67740193Sbostic sig_t oldintr, oldintp; 67866670Spendry int c, d, is_retr, tcrflag, bare_lfs = 0; 67938133Srick static int bufsize; 68036944Skarels static char *buf; 68136940Skarels long bytes = 0, hashbytes = HASHBYTES; 68210296Ssam struct timeval start, stop; 68336940Skarels struct stat st; 68410296Ssam 68536935Skarels is_retr = strcmp(cmd, "RETR") == 0; 68637225Skarels if (is_retr && verbose && printnames) { 68737225Skarels if (local && *local != '-') 68837225Skarels printf("local: %s ", local); 68937225Skarels if (remote) 69037225Skarels printf("remote: %s\n", remote); 69137225Skarels } 69236935Skarels if (proxy && is_retr) { 69326048Sminshall proxtrans(cmd, local, remote); 69426048Sminshall return; 69526048Sminshall } 69610296Ssam closefunc = NULL; 69726048Sminshall oldintr = NULL; 69826048Sminshall oldintp = NULL; 69936935Skarels tcrflag = !crflag && is_retr; 70026048Sminshall if (setjmp(recvabort)) { 70126048Sminshall while (cpend) { 70226048Sminshall (void) getreply(0); 70326048Sminshall } 70426048Sminshall if (data >= 0) { 70526048Sminshall (void) close(data); 70626048Sminshall data = -1; 70726048Sminshall } 70826448Slepreau if (oldintr) 70926048Sminshall (void) signal(SIGINT, oldintr); 71026048Sminshall code = -1; 71126048Sminshall return; 71226048Sminshall } 71310296Ssam oldintr = signal(SIGINT, abortrecv); 71426048Sminshall if (strcmp(local, "-") && *local != '|') { 71510296Ssam if (access(local, 2) < 0) { 71666670Spendry char *dir = strrchr(local, '/'); 71710296Ssam 71826048Sminshall if (errno != ENOENT && errno != EACCES) { 71966670Spendry warn("local: %s", local); 72026048Sminshall (void) signal(SIGINT, oldintr); 72126048Sminshall code = -1; 72226048Sminshall return; 72310296Ssam } 72426048Sminshall if (dir != NULL) 72526048Sminshall *dir = 0; 72626048Sminshall d = access(dir ? local : ".", 2); 72726048Sminshall if (dir != NULL) 72826048Sminshall *dir = '/'; 72926048Sminshall if (d < 0) { 73066670Spendry warn("local: %s", local); 73126048Sminshall (void) signal(SIGINT, oldintr); 73226048Sminshall code = -1; 73326048Sminshall return; 73426048Sminshall } 73526048Sminshall if (!runique && errno == EACCES && 73636935Skarels chmod(local, 0600) < 0) { 73766670Spendry warn("local: %s", local); 73826048Sminshall (void) signal(SIGINT, oldintr); 73938202Srick (void) signal(SIGINT, oldintr); 74026048Sminshall code = -1; 74126048Sminshall return; 74226048Sminshall } 74326048Sminshall if (runique && errno == EACCES && 74426048Sminshall (local = gunique(local)) == NULL) { 74526048Sminshall (void) signal(SIGINT, oldintr); 74626048Sminshall code = -1; 74726048Sminshall return; 74826048Sminshall } 74910296Ssam } 75026048Sminshall else if (runique && (local = gunique(local)) == NULL) { 75126048Sminshall (void) signal(SIGINT, oldintr); 75226048Sminshall code = -1; 75326048Sminshall return; 75426048Sminshall } 75526048Sminshall } 75638033Skarels if (!is_retr) { 75738033Skarels if (curtype != TYPE_A) 75838033Skarels changetype(TYPE_A, 0); 75938033Skarels } else if (curtype != type) 76038033Skarels changetype(type, 0); 76126048Sminshall if (initconn()) { 76226048Sminshall (void) signal(SIGINT, oldintr); 76326048Sminshall code = -1; 76426048Sminshall return; 76526048Sminshall } 76626448Slepreau if (setjmp(recvabort)) 76726048Sminshall goto abort; 76838033Skarels if (is_retr && restart_point && 76938033Skarels command("REST %ld", (long) restart_point) != CONTINUE) 77038033Skarels return; 77110296Ssam if (remote) { 77226048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 77326048Sminshall (void) signal(SIGINT, oldintr); 77426048Sminshall return; 77526048Sminshall } 77626048Sminshall } else { 77726048Sminshall if (command("%s", cmd) != PRELIM) { 77826048Sminshall (void) signal(SIGINT, oldintr); 77926048Sminshall return; 78026048Sminshall } 78126048Sminshall } 78226048Sminshall din = dataconn("r"); 78326048Sminshall if (din == NULL) 78426048Sminshall goto abort; 78526448Slepreau if (strcmp(local, "-") == 0) 78610296Ssam fout = stdout; 78710296Ssam else if (*local == '|') { 78826048Sminshall oldintp = signal(SIGPIPE, SIG_IGN); 78935659Sbostic fout = popen(local + 1, "w"); 79026048Sminshall if (fout == NULL) { 79166670Spendry warn("%s", local+1); 79226048Sminshall goto abort; 79326048Sminshall } 79435659Sbostic closefunc = pclose; 79536940Skarels } else { 79640193Sbostic fout = fopen(local, lmode); 79726048Sminshall if (fout == NULL) { 79866670Spendry warn("local: %s", local); 79926048Sminshall goto abort; 80026048Sminshall } 80110296Ssam closefunc = fclose; 80210296Ssam } 80336940Skarels if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) 80436940Skarels st.st_blksize = BUFSIZ; 80536940Skarels if (st.st_blksize > bufsize) { 80636940Skarels if (buf) 80736940Skarels (void) free(buf); 80838133Srick buf = malloc((unsigned)st.st_blksize); 80936940Skarels if (buf == NULL) { 81066670Spendry warn("malloc"); 81136944Skarels bufsize = 0; 81236940Skarels goto abort; 81336940Skarels } 81436940Skarels bufsize = st.st_blksize; 81536940Skarels } 81626496Sminshall (void) gettimeofday(&start, (struct timezone *)0); 81738033Skarels switch (curtype) { 81811219Ssam 81911219Ssam case TYPE_I: 82011219Ssam case TYPE_L: 82137225Skarels if (restart_point && 82266724Spendry lseek(fileno(fout), restart_point, SEEK_SET) < 0) { 82366670Spendry warn("local: %s", local); 82437225Skarels if (closefunc != NULL) 82537225Skarels (*closefunc)(fout); 82637225Skarels return; 82737225Skarels } 82811346Ssam errno = d = 0; 82936940Skarels while ((c = read(fileno(din), buf, bufsize)) > 0) { 83036944Skarels if ((d = write(fileno(fout), buf, c)) != c) 83111219Ssam break; 83211219Ssam bytes += c; 83311651Ssam if (hash) { 83436940Skarels while (bytes >= hashbytes) { 83536940Skarels (void) putchar('#'); 83636940Skarels hashbytes += HASHBYTES; 83736940Skarels } 83826496Sminshall (void) fflush(stdout); 83911651Ssam } 84011219Ssam } 84113213Ssam if (hash && bytes > 0) { 84236940Skarels if (bytes < HASHBYTES) 84336940Skarels (void) putchar('#'); 84426496Sminshall (void) putchar('\n'); 84526496Sminshall (void) fflush(stdout); 84611651Ssam } 84736935Skarels if (c < 0) { 84836935Skarels if (errno != EPIPE) 84966670Spendry warn("netin"); 85036935Skarels bytes = -1; 85136935Skarels } 85236942Skarels if (d < c) { 85336942Skarels if (d < 0) 85466670Spendry warn("local: %s", local); 85536942Skarels else 85666670Spendry warnx("%s: short write", local); 85736942Skarels } 85811219Ssam break; 85911219Ssam 86011219Ssam case TYPE_A: 86137225Skarels if (restart_point) { 86266670Spendry int i, n, ch; 86337225Skarels 86466724Spendry if (fseek(fout, 0L, SEEK_SET) < 0) 86537225Skarels goto done; 86637225Skarels n = restart_point; 86740193Sbostic for (i = 0; i++ < n;) { 86840193Sbostic if ((ch = getc(fout)) == EOF) 86937225Skarels goto done; 87040193Sbostic if (ch == '\n') 87137225Skarels i++; 87237225Skarels } 87366724Spendry if (fseek(fout, 0L, SEEK_CUR) < 0) { 87437225Skarels done: 87566670Spendry warn("local: %s", local); 87637225Skarels if (closefunc != NULL) 87737225Skarels (*closefunc)(fout); 87837225Skarels return; 87937225Skarels } 88037225Skarels } 88111219Ssam while ((c = getc(din)) != EOF) { 88238133Srick if (c == '\n') 88338133Srick bare_lfs++; 88427749Sminshall while (c == '\r') { 88511651Ssam while (hash && (bytes >= hashbytes)) { 88626496Sminshall (void) putchar('#'); 88726496Sminshall (void) fflush(stdout); 88836940Skarels hashbytes += HASHBYTES; 88911651Ssam } 89010296Ssam bytes++; 89126048Sminshall if ((c = getc(din)) != '\n' || tcrflag) { 89236940Skarels if (ferror(fout)) 89336940Skarels goto break2; 89436940Skarels (void) putc('\r', fout); 89536942Skarels if (c == '\0') { 89636942Skarels bytes++; 89736940Skarels goto contin2; 89836942Skarels } 89936942Skarels if (c == EOF) 90036942Skarels goto contin2; 90111219Ssam } 90211219Ssam } 90336940Skarels (void) putc(c, fout); 90411219Ssam bytes++; 90536940Skarels contin2: ; 90610296Ssam } 90736940Skarels break2: 90838133Srick if (bare_lfs) { 90938133Srick printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs); 91038133Srick printf("File may not have transferred correctly.\n"); 91138133Srick } 91211651Ssam if (hash) { 91313213Ssam if (bytes < hashbytes) 91426496Sminshall (void) putchar('#'); 91526496Sminshall (void) putchar('\n'); 91626496Sminshall (void) fflush(stdout); 91711651Ssam } 91836944Skarels if (ferror(din)) { 91936935Skarels if (errno != EPIPE) 92066670Spendry warn("netin"); 92136935Skarels bytes = -1; 92236935Skarels } 92336940Skarels if (ferror(fout)) 92466670Spendry warn("local: %s", local); 92511219Ssam break; 92610296Ssam } 92726448Slepreau if (closefunc != NULL) 92826048Sminshall (*closefunc)(fout); 92926496Sminshall (void) signal(SIGINT, oldintr); 93026448Slepreau if (oldintp) 93126048Sminshall (void) signal(SIGPIPE, oldintp); 93226496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 93310296Ssam (void) fclose(din); 93426048Sminshall (void) getreply(0); 93536935Skarels if (bytes > 0 && is_retr) 93637225Skarels ptransfer("received", bytes, &start, &stop); 93726048Sminshall return; 93826048Sminshall abort: 93926048Sminshall 94027687Sminshall /* abort using RFC959 recommended IP,SYNC sequence */ 94126048Sminshall 94226496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 94326448Slepreau if (oldintp) 94426048Sminshall (void) signal(SIGPIPE, oldintr); 94538133Srick (void) signal(SIGINT, SIG_IGN); 94626048Sminshall if (!cpend) { 94726048Sminshall code = -1; 94838133Srick (void) signal(SIGINT, oldintr); 94926048Sminshall return; 95026048Sminshall } 95126048Sminshall 95238133Srick abort_remote(din); 95326048Sminshall code = -1; 95426048Sminshall if (data >= 0) { 95526048Sminshall (void) close(data); 95626048Sminshall data = -1; 95726048Sminshall } 95826448Slepreau if (closefunc != NULL && fout != NULL) 95926048Sminshall (*closefunc)(fout); 96026448Slepreau if (din) 96126048Sminshall (void) fclose(din); 96235699Sbostic if (bytes > 0) 96337225Skarels ptransfer("received", bytes, &start, &stop); 96438133Srick (void) signal(SIGINT, oldintr); 96510296Ssam } 96610296Ssam 96710296Ssam /* 96840193Sbostic * Need to start a listen on the data channel before we send the command, 96940193Sbostic * otherwise the server's connect may fail. 97010296Ssam */ 97166670Spendry int 97210296Ssam initconn() 97310296Ssam { 97466670Spendry char *p, *a; 97526048Sminshall int result, len, tmpno = 0; 97626993Skarels int on = 1; 977*67794Smckusick int a0, a1, a2, a3, p0, p1; 97810296Ssam 979*67794Smckusick if (passivemode) { 980*67794Smckusick data = socket(AF_INET, SOCK_STREAM, 0); 981*67794Smckusick if (data < 0) { 982*67794Smckusick perror("ftp: socket"); 983*67794Smckusick return(1); 984*67794Smckusick } 985*67794Smckusick if ((options & SO_DEBUG) && 986*67794Smckusick setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, 987*67794Smckusick sizeof (on)) < 0) 988*67794Smckusick perror("ftp: setsockopt (ignored)"); 989*67794Smckusick if (command("PASV") != COMPLETE) { 990*67794Smckusick printf("Passive mode refused.\n"); 991*67794Smckusick goto bad; 992*67794Smckusick } 993*67794Smckusick 994*67794Smckusick /* 995*67794Smckusick * What we've got at this point is a string of comma 996*67794Smckusick * separated one-byte unsigned integer values. 997*67794Smckusick * The first four are the an IP address. The fifth is 998*67794Smckusick * the MSB of the port number, the sixth is the LSB. 999*67794Smckusick * From that we'll prepare a sockaddr_in. 1000*67794Smckusick */ 1001*67794Smckusick 1002*67794Smckusick if (sscanf(pasv,"%d,%d,%d,%d,%d,%d", 1003*67794Smckusick &a0, &a1, &a2, &a3, &p0, &p1) != 6) { 1004*67794Smckusick printf("Passive mode address scan failure. " 1005*67794Smckusick "Shouldn't happen!\n"); 1006*67794Smckusick goto bad; 1007*67794Smckusick } 1008*67794Smckusick 1009*67794Smckusick bzero(&data_addr, sizeof(data_addr)); 1010*67794Smckusick data_addr.sin_family = AF_INET; 1011*67794Smckusick a = (char *)&data_addr.sin_addr.s_addr; 1012*67794Smckusick a[0] = a0 & 0xff; 1013*67794Smckusick a[1] = a1 & 0xff; 1014*67794Smckusick a[2] = a2 & 0xff; 1015*67794Smckusick a[3] = a3 & 0xff; 1016*67794Smckusick p = (char *)&data_addr.sin_port; 1017*67794Smckusick p[0] = p0 & 0xff; 1018*67794Smckusick p[1] = p1 & 0xff; 1019*67794Smckusick 1020*67794Smckusick if (connect(data, (struct sockaddr *)&data_addr, 1021*67794Smckusick sizeof(data_addr)) < 0) { 1022*67794Smckusick perror("ftp: connect"); 1023*67794Smckusick goto bad; 1024*67794Smckusick } 1025*67794Smckusick #ifdef IP_TOS 1026*67794Smckusick on = IPTOS_THROUGHPUT; 1027*67794Smckusick if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, 1028*67794Smckusick sizeof(int)) < 0) 1029*67794Smckusick perror("ftp: setsockopt TOS (ignored)"); 1030*67794Smckusick #endif 1031*67794Smckusick return(0); 1032*67794Smckusick } 1033*67794Smckusick 103411651Ssam noport: 103510296Ssam data_addr = myctladdr; 103611651Ssam if (sendport) 103711651Ssam data_addr.sin_port = 0; /* let system pick one */ 103811651Ssam if (data != -1) 103938133Srick (void) close(data); 104018287Sralph data = socket(AF_INET, SOCK_STREAM, 0); 104110296Ssam if (data < 0) { 104266670Spendry warn("socket"); 104326448Slepreau if (tmpno) 104426048Sminshall sendport = 1; 104510296Ssam return (1); 104610296Ssam } 104712397Ssam if (!sendport) 104827687Sminshall if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { 104966670Spendry warn("setsockopt (reuse address)"); 105012397Ssam goto bad; 105112397Ssam } 105226496Sminshall if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { 105366670Spendry warn("bind"); 105410296Ssam goto bad; 105510296Ssam } 105610296Ssam if (options & SO_DEBUG && 105727687Sminshall setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) 105866670Spendry warn("setsockopt (ignored)"); 105911627Ssam len = sizeof (data_addr); 106038133Srick if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) { 106166670Spendry warn("getsockname"); 106210296Ssam goto bad; 106310296Ssam } 106426448Slepreau if (listen(data, 1) < 0) 106566670Spendry warn("listen"); 106611651Ssam if (sendport) { 106711651Ssam a = (char *)&data_addr.sin_addr; 106811651Ssam p = (char *)&data_addr.sin_port; 106910296Ssam #define UC(b) (((int)b)&0xff) 107011651Ssam result = 107111651Ssam command("PORT %d,%d,%d,%d,%d,%d", 107211651Ssam UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 107311651Ssam UC(p[0]), UC(p[1])); 107411651Ssam if (result == ERROR && sendport == -1) { 107511651Ssam sendport = 0; 107626048Sminshall tmpno = 1; 107711651Ssam goto noport; 107811651Ssam } 107911651Ssam return (result != COMPLETE); 108011651Ssam } 108126448Slepreau if (tmpno) 108226048Sminshall sendport = 1; 108344340Skarels #ifdef IP_TOS 108444340Skarels on = IPTOS_THROUGHPUT; 108544340Skarels if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 108666670Spendry warn("setsockopt TOS (ignored)"); 108744340Skarels #endif 108811651Ssam return (0); 108910296Ssam bad: 109010296Ssam (void) close(data), data = -1; 109126448Slepreau if (tmpno) 109226048Sminshall sendport = 1; 109310296Ssam return (1); 109410296Ssam } 109510296Ssam 109610296Ssam FILE * 109740193Sbostic dataconn(lmode) 109840193Sbostic char *lmode; 109910296Ssam { 110010296Ssam struct sockaddr_in from; 110144340Skarels int s, fromlen = sizeof (from), tos; 110210296Ssam 1103*67794Smckusick if (passivemode) 1104*67794Smckusick return (fdopen(data, lmode)); 1105*67794Smckusick 110626496Sminshall s = accept(data, (struct sockaddr *) &from, &fromlen); 110710296Ssam if (s < 0) { 110866670Spendry warn("accept"); 110910296Ssam (void) close(data), data = -1; 111010296Ssam return (NULL); 111110296Ssam } 111210296Ssam (void) close(data); 111310296Ssam data = s; 111444340Skarels #ifdef IP_TOS 111544340Skarels tos = IPTOS_THROUGHPUT; 111644340Skarels if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0) 111766670Spendry warn("setsockopt TOS (ignored)"); 111844340Skarels #endif 111940193Sbostic return (fdopen(data, lmode)); 112010296Ssam } 112110296Ssam 112266670Spendry void 112337225Skarels ptransfer(direction, bytes, t0, t1) 112437225Skarels char *direction; 112511651Ssam long bytes; 112610296Ssam struct timeval *t0, *t1; 112710296Ssam { 112810296Ssam struct timeval td; 1129*67794Smckusick float s; 1130*67794Smckusick long bs; 113110296Ssam 113235699Sbostic if (verbose) { 113335699Sbostic tvsub(&td, t1, t0); 113435699Sbostic s = td.tv_sec + (td.tv_usec / 1000000.); 113510296Ssam #define nz(x) ((x) == 0 ? 1 : (x)) 113635699Sbostic bs = bytes / nz(s); 1137*67794Smckusick printf("%ld bytes %s in %.3g seconds (%ld bytes/s)\n", 1138*67794Smckusick bytes, direction, s, bs); 113935699Sbostic } 114010296Ssam } 114110296Ssam 114266670Spendry /* 114366670Spendry void 114466670Spendry tvadd(tsum, t0) 114510296Ssam struct timeval *tsum, *t0; 114610296Ssam { 114710296Ssam 114810296Ssam tsum->tv_sec += t0->tv_sec; 114910296Ssam tsum->tv_usec += t0->tv_usec; 115010296Ssam if (tsum->tv_usec > 1000000) 115110296Ssam tsum->tv_sec++, tsum->tv_usec -= 1000000; 115266670Spendry } 115366670Spendry */ 115410296Ssam 115566670Spendry void 115610296Ssam tvsub(tdiff, t1, t0) 115710296Ssam struct timeval *tdiff, *t1, *t0; 115810296Ssam { 115910296Ssam 116010296Ssam tdiff->tv_sec = t1->tv_sec - t0->tv_sec; 116110296Ssam tdiff->tv_usec = t1->tv_usec - t0->tv_usec; 116210296Ssam if (tdiff->tv_usec < 0) 116310296Ssam tdiff->tv_sec--, tdiff->tv_usec += 1000000; 116410296Ssam } 116526048Sminshall 116640193Sbostic void 116726048Sminshall psabort() 116826048Sminshall { 116926048Sminshall 117026048Sminshall abrtflag++; 117126048Sminshall } 117226048Sminshall 117366670Spendry void 117426048Sminshall pswitch(flag) 117526048Sminshall int flag; 117626048Sminshall { 117740193Sbostic sig_t oldintr; 117826048Sminshall static struct comvars { 117926048Sminshall int connect; 118028469Skarels char name[MAXHOSTNAMELEN]; 118126048Sminshall struct sockaddr_in mctl; 118226048Sminshall struct sockaddr_in hctl; 118326048Sminshall FILE *in; 118426048Sminshall FILE *out; 118526048Sminshall int tpe; 118638033Skarels int curtpe; 118726048Sminshall int cpnd; 118826048Sminshall int sunqe; 118926048Sminshall int runqe; 119026048Sminshall int mcse; 119126048Sminshall int ntflg; 119226048Sminshall char nti[17]; 119326048Sminshall char nto[17]; 119426048Sminshall int mapflg; 119526048Sminshall char mi[MAXPATHLEN]; 119626048Sminshall char mo[MAXPATHLEN]; 119738033Skarels } proxstruct, tmpstruct; 119826048Sminshall struct comvars *ip, *op; 119926048Sminshall 120026048Sminshall abrtflag = 0; 120126048Sminshall oldintr = signal(SIGINT, psabort); 120226048Sminshall if (flag) { 120326448Slepreau if (proxy) 120426048Sminshall return; 120526048Sminshall ip = &tmpstruct; 120626048Sminshall op = &proxstruct; 120726048Sminshall proxy++; 120838033Skarels } else { 120926448Slepreau if (!proxy) 121026048Sminshall return; 121126048Sminshall ip = &proxstruct; 121226048Sminshall op = &tmpstruct; 121326048Sminshall proxy = 0; 121426048Sminshall } 121526048Sminshall ip->connect = connected; 121626048Sminshall connected = op->connect; 121728469Skarels if (hostname) { 121828469Skarels (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1); 121928469Skarels ip->name[strlen(ip->name)] = '\0'; 122028469Skarels } else 122128469Skarels ip->name[0] = 0; 122226048Sminshall hostname = op->name; 122326048Sminshall ip->hctl = hisctladdr; 122426048Sminshall hisctladdr = op->hctl; 122526048Sminshall ip->mctl = myctladdr; 122626048Sminshall myctladdr = op->mctl; 122726048Sminshall ip->in = cin; 122826048Sminshall cin = op->in; 122926048Sminshall ip->out = cout; 123026048Sminshall cout = op->out; 123126048Sminshall ip->tpe = type; 123226048Sminshall type = op->tpe; 123338033Skarels ip->curtpe = curtype; 123438033Skarels curtype = op->curtpe; 123526048Sminshall ip->cpnd = cpend; 123626048Sminshall cpend = op->cpnd; 123726048Sminshall ip->sunqe = sunique; 123826048Sminshall sunique = op->sunqe; 123926048Sminshall ip->runqe = runique; 124026048Sminshall runique = op->runqe; 124126048Sminshall ip->mcse = mcase; 124226048Sminshall mcase = op->mcse; 124326048Sminshall ip->ntflg = ntflag; 124426048Sminshall ntflag = op->ntflg; 124526496Sminshall (void) strncpy(ip->nti, ntin, 16); 124626048Sminshall (ip->nti)[strlen(ip->nti)] = '\0'; 124726496Sminshall (void) strcpy(ntin, op->nti); 124826496Sminshall (void) strncpy(ip->nto, ntout, 16); 124926048Sminshall (ip->nto)[strlen(ip->nto)] = '\0'; 125026496Sminshall (void) strcpy(ntout, op->nto); 125126048Sminshall ip->mapflg = mapflag; 125226048Sminshall mapflag = op->mapflg; 125326496Sminshall (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1); 125426048Sminshall (ip->mi)[strlen(ip->mi)] = '\0'; 125526496Sminshall (void) strcpy(mapin, op->mi); 125626496Sminshall (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1); 125726048Sminshall (ip->mo)[strlen(ip->mo)] = '\0'; 125826496Sminshall (void) strcpy(mapout, op->mo); 125926048Sminshall (void) signal(SIGINT, oldintr); 126026048Sminshall if (abrtflag) { 126126048Sminshall abrtflag = 0; 126246828Sbostic (*oldintr)(SIGINT); 126326448Slepreau } 126426048Sminshall } 126526048Sminshall 126640193Sbostic void 126726048Sminshall abortpt() 126826048Sminshall { 126966670Spendry 127026048Sminshall printf("\n"); 127126496Sminshall (void) fflush(stdout); 127226048Sminshall ptabflg++; 127326048Sminshall mflag = 0; 127426048Sminshall abrtflag = 0; 127526048Sminshall longjmp(ptabort, 1); 127626048Sminshall } 127726048Sminshall 127866670Spendry void 127926048Sminshall proxtrans(cmd, local, remote) 128026048Sminshall char *cmd, *local, *remote; 128126048Sminshall { 128240193Sbostic sig_t oldintr; 128338133Srick int secndflag = 0, prox_type, nfnd; 128426048Sminshall char *cmd2; 128526496Sminshall struct fd_set mask; 128626048Sminshall 128726448Slepreau if (strcmp(cmd, "RETR")) 128826048Sminshall cmd2 = "RETR"; 128926448Slepreau else 129026048Sminshall cmd2 = runique ? "STOU" : "STOR"; 129138033Skarels if ((prox_type = type) == 0) { 129238033Skarels if (unix_server && unix_proxy) 129338033Skarels prox_type = TYPE_I; 129438033Skarels else 129538033Skarels prox_type = TYPE_A; 129638033Skarels } 129738033Skarels if (curtype != prox_type) 129838033Skarels changetype(prox_type, 1); 129926048Sminshall if (command("PASV") != COMPLETE) { 130038033Skarels printf("proxy server does not support third party transfers.\n"); 130126048Sminshall return; 130226048Sminshall } 130326048Sminshall pswitch(0); 130426048Sminshall if (!connected) { 130526048Sminshall printf("No primary connection\n"); 130626048Sminshall pswitch(1); 130726048Sminshall code = -1; 130826048Sminshall return; 130926048Sminshall } 131038033Skarels if (curtype != prox_type) 131138033Skarels changetype(prox_type, 1); 131226048Sminshall if (command("PORT %s", pasv) != COMPLETE) { 131326048Sminshall pswitch(1); 131426048Sminshall return; 131526048Sminshall } 131626448Slepreau if (setjmp(ptabort)) 131726048Sminshall goto abort; 131826048Sminshall oldintr = signal(SIGINT, abortpt); 131926048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 132026048Sminshall (void) signal(SIGINT, oldintr); 132126048Sminshall pswitch(1); 132226048Sminshall return; 132326048Sminshall } 132426048Sminshall sleep(2); 132526048Sminshall pswitch(1); 132626048Sminshall secndflag++; 132726448Slepreau if (command("%s %s", cmd2, local) != PRELIM) 132826048Sminshall goto abort; 132926048Sminshall ptflag++; 133026048Sminshall (void) getreply(0); 133126048Sminshall pswitch(0); 133226048Sminshall (void) getreply(0); 133326048Sminshall (void) signal(SIGINT, oldintr); 133426048Sminshall pswitch(1); 133526048Sminshall ptflag = 0; 133626048Sminshall printf("local: %s remote: %s\n", local, remote); 133726048Sminshall return; 133826048Sminshall abort: 133926048Sminshall (void) signal(SIGINT, SIG_IGN); 134026048Sminshall ptflag = 0; 134126448Slepreau if (strcmp(cmd, "RETR") && !proxy) 134226048Sminshall pswitch(1); 134326448Slepreau else if (!strcmp(cmd, "RETR") && proxy) 134426048Sminshall pswitch(0); 134526048Sminshall if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ 134626048Sminshall if (command("%s %s", cmd2, local) != PRELIM) { 134726048Sminshall pswitch(0); 134838133Srick if (cpend) 134938133Srick abort_remote((FILE *) NULL); 135026048Sminshall } 135126048Sminshall pswitch(1); 135226448Slepreau if (ptabflg) 135326048Sminshall code = -1; 135426048Sminshall (void) signal(SIGINT, oldintr); 135526048Sminshall return; 135626048Sminshall } 135738133Srick if (cpend) 135838133Srick abort_remote((FILE *) NULL); 135926048Sminshall pswitch(!proxy); 136026048Sminshall if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ 136126048Sminshall if (command("%s %s", cmd2, local) != PRELIM) { 136226048Sminshall pswitch(0); 136338133Srick if (cpend) 136438133Srick abort_remote((FILE *) NULL); 136526048Sminshall pswitch(1); 136626448Slepreau if (ptabflg) 136726048Sminshall code = -1; 136826048Sminshall (void) signal(SIGINT, oldintr); 136926048Sminshall return; 137026048Sminshall } 137126048Sminshall } 137238133Srick if (cpend) 137338133Srick abort_remote((FILE *) NULL); 137426048Sminshall pswitch(!proxy); 137526048Sminshall if (cpend) { 137627687Sminshall FD_ZERO(&mask); 137726496Sminshall FD_SET(fileno(cin), &mask); 137838133Srick if ((nfnd = empty(&mask, 10)) <= 0) { 137927687Sminshall if (nfnd < 0) { 138066670Spendry warn("abort"); 138127687Sminshall } 138226448Slepreau if (ptabflg) 138326048Sminshall code = -1; 138426048Sminshall lostpeer(); 138526048Sminshall } 138626048Sminshall (void) getreply(0); 138726048Sminshall (void) getreply(0); 138826048Sminshall } 138926448Slepreau if (proxy) 139026048Sminshall pswitch(0); 139126048Sminshall pswitch(1); 139226448Slepreau if (ptabflg) 139326048Sminshall code = -1; 139426048Sminshall (void) signal(SIGINT, oldintr); 139526048Sminshall } 139626048Sminshall 139766670Spendry void 139866670Spendry reset(argc, argv) 139966670Spendry int argc; 140066670Spendry char *argv[]; 140126048Sminshall { 140226496Sminshall struct fd_set mask; 140326496Sminshall int nfnd = 1; 140426048Sminshall 140527687Sminshall FD_ZERO(&mask); 140630946Scsvsj while (nfnd > 0) { 140726496Sminshall FD_SET(fileno(cin), &mask); 140827687Sminshall if ((nfnd = empty(&mask,0)) < 0) { 140966670Spendry warn("reset"); 141026048Sminshall code = -1; 141126048Sminshall lostpeer(); 141226048Sminshall } 141327687Sminshall else if (nfnd) { 141426048Sminshall (void) getreply(0); 141526496Sminshall } 141626048Sminshall } 141726048Sminshall } 141826048Sminshall 141926048Sminshall char * 142026048Sminshall gunique(local) 142126048Sminshall char *local; 142226048Sminshall { 142326048Sminshall static char new[MAXPATHLEN]; 142466670Spendry char *cp = strrchr(local, '/'); 142526048Sminshall int d, count=0; 142626048Sminshall char ext = '1'; 142726048Sminshall 142826448Slepreau if (cp) 142926048Sminshall *cp = '\0'; 143026048Sminshall d = access(cp ? local : ".", 2); 143126448Slepreau if (cp) 143226048Sminshall *cp = '/'; 143326048Sminshall if (d < 0) { 143466670Spendry warn("local: %s", local); 143566670Spendry return ((char *) 0); 143626048Sminshall } 143726048Sminshall (void) strcpy(new, local); 143826048Sminshall cp = new + strlen(new); 143926048Sminshall *cp++ = '.'; 144026048Sminshall while (!d) { 144126048Sminshall if (++count == 100) { 144226048Sminshall printf("runique: can't find unique file name.\n"); 144366670Spendry return ((char *) 0); 144426048Sminshall } 144526048Sminshall *cp++ = ext; 144626048Sminshall *cp = '\0'; 144726448Slepreau if (ext == '9') 144826048Sminshall ext = '0'; 144926448Slepreau else 145026048Sminshall ext++; 145126448Slepreau if ((d = access(new, 0)) < 0) 145226048Sminshall break; 145326448Slepreau if (ext != '0') 145426048Sminshall cp--; 145526448Slepreau else if (*(cp - 2) == '.') 145626048Sminshall *(cp - 1) = '1'; 145726048Sminshall else { 145826048Sminshall *(cp - 2) = *(cp - 2) + 1; 145926048Sminshall cp--; 146026048Sminshall } 146126048Sminshall } 146266670Spendry return (new); 146326048Sminshall } 146438133Srick 146566670Spendry void 146638133Srick abort_remote(din) 146766670Spendry FILE *din; 146838133Srick { 146938133Srick char buf[BUFSIZ]; 147038133Srick int nfnd; 147138133Srick struct fd_set mask; 147238133Srick 147338133Srick /* 147438133Srick * send IAC in urgent mode instead of DM because 4.3BSD places oob mark 147538133Srick * after urgent byte rather than before as is protocol now 147638133Srick */ 147738133Srick sprintf(buf, "%c%c%c", IAC, IP, IAC); 147838133Srick if (send(fileno(cout), buf, 3, MSG_OOB) != 3) 147966670Spendry warn("abort"); 148038133Srick fprintf(cout,"%cABOR\r\n", DM); 148138133Srick (void) fflush(cout); 148238133Srick FD_ZERO(&mask); 148338133Srick FD_SET(fileno(cin), &mask); 148438133Srick if (din) { 148538133Srick FD_SET(fileno(din), &mask); 148638133Srick } 148738133Srick if ((nfnd = empty(&mask, 10)) <= 0) { 148838133Srick if (nfnd < 0) { 148966670Spendry warn("abort"); 149038133Srick } 149138133Srick if (ptabflg) 149238133Srick code = -1; 149338133Srick lostpeer(); 149438133Srick } 149538133Srick if (din && FD_ISSET(fileno(din), &mask)) { 149638133Srick while (read(fileno(din), buf, BUFSIZ) > 0) 149738133Srick /* LOOP */; 149838133Srick } 149938133Srick if (getreply(0) == ERROR && code == 552) { 150038133Srick /* 552 needed for nic style abort */ 150138133Srick (void) getreply(0); 150238133Srick } 150338133Srick (void) getreply(0); 150438133Srick } 1505