121739Sdist /* 236942Skarels * Copyright (c) 1985, 1989 Regents of the University of California. 333737Sbostic * All rights reserved. 433737Sbostic * 533737Sbostic * Redistribution and use in source and binary forms are permitted 634901Sbostic * provided that the above copyright notice and this paragraph are 734901Sbostic * duplicated in all such forms and that any documentation, 834901Sbostic * advertising materials, and other materials related to such 934901Sbostic * distribution and use acknowledge that the software was developed 1034901Sbostic * by the University of California, Berkeley. The name of the 1134901Sbostic * University may not be used to endorse or promote products derived 1234901Sbostic * from this software without specific prior written permission. 1334901Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434901Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1536935Skarels * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621739Sdist */ 1721739Sdist 1810296Ssam #ifndef lint 19*37458Skarels static char sccsid[] = "@(#)ftp.c 5.28 (Berkeley) 04/20/89"; 2033737Sbostic #endif /* not lint */ 2110296Ssam 2236940Skarels #include <sys/param.h> 2310296Ssam #include <sys/stat.h> 2410296Ssam #include <sys/ioctl.h> 2510296Ssam #include <sys/socket.h> 2613614Ssam #include <sys/time.h> 2736935Skarels #include <sys/file.h> 2810296Ssam 2910296Ssam #include <netinet/in.h> 3012397Ssam #include <arpa/ftp.h> 3126048Sminshall #include <arpa/telnet.h> 3210296Ssam 3310296Ssam #include <stdio.h> 3410296Ssam #include <signal.h> 3510296Ssam #include <errno.h> 3610296Ssam #include <netdb.h> 3726048Sminshall #include <fcntl.h> 3826048Sminshall #include <pwd.h> 3910296Ssam 4036940Skarels #include "ftp_var.h" 4136940Skarels 4210296Ssam struct sockaddr_in hisctladdr; 4310296Ssam struct sockaddr_in data_addr; 4410296Ssam int data = -1; 4526048Sminshall int abrtflag = 0; 4626048Sminshall int ptflag = 0; 4710296Ssam int connected; 48*37458Skarels int allbinary; 4910296Ssam struct sockaddr_in myctladdr; 5026496Sminshall uid_t getuid(); 5137225Skarels off_t restart_point = 0; 5210296Ssam 5310296Ssam FILE *cin, *cout; 5410296Ssam FILE *dataconn(); 5510296Ssam 5625904Skarels char * 5710296Ssam hookup(host, port) 5810296Ssam char *host; 5910296Ssam int port; 6010296Ssam { 6125904Skarels register struct hostent *hp = 0; 6227687Sminshall int s,len; 6325904Skarels static char hostnamebuf[80]; 6410296Ssam 6510296Ssam bzero((char *)&hisctladdr, 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) { 7335792Sbostic fprintf(stderr, "ftp: %s: ", host); 7435792Sbostic herror((char *)NULL); 7526048Sminshall code = -1; 7626048Sminshall return((char *) 0); 7725904Skarels } 7825904Skarels hisctladdr.sin_family = hp->h_addrtype; 7925904Skarels bcopy(hp->h_addr_list[0], 8025904Skarels (caddr_t)&hisctladdr.sin_addr, hp->h_length); 8136940Skarels (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf)); 8210296Ssam } 8325904Skarels hostname = hostnamebuf; 8425904Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 8510296Ssam if (s < 0) { 8610296Ssam perror("ftp: socket"); 8726048Sminshall code = -1; 8810296Ssam return (0); 8910296Ssam } 9010296Ssam hisctladdr.sin_port = port; 9126496Sminshall while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) { 9225904Skarels if (hp && hp->h_addr_list[1]) { 9325904Skarels int oerrno = errno; 9425904Skarels 9525904Skarels fprintf(stderr, "ftp: connect to address %s: ", 9625904Skarels inet_ntoa(hisctladdr.sin_addr)); 9725904Skarels errno = oerrno; 9826496Sminshall perror((char *) 0); 9925904Skarels hp->h_addr_list++; 10025904Skarels bcopy(hp->h_addr_list[0], 10126048Sminshall (caddr_t)&hisctladdr.sin_addr, hp->h_length); 10226496Sminshall fprintf(stdout, "Trying %s...\n", 10325904Skarels inet_ntoa(hisctladdr.sin_addr)); 10426813Skarels (void) close(s); 10526813Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 10626813Skarels if (s < 0) { 10726813Skarels perror("ftp: socket"); 10826813Skarels code = -1; 10926813Skarels return (0); 11026813Skarels } 11125904Skarels continue; 11225904Skarels } 11310296Ssam perror("ftp: connect"); 11426048Sminshall code = -1; 11510296Ssam goto bad; 11610296Ssam } 11711627Ssam len = sizeof (myctladdr); 11811627Ssam if (getsockname(s, (char *)&myctladdr, &len) < 0) { 11911627Ssam perror("ftp: getsockname"); 12026048Sminshall code = -1; 12110296Ssam goto bad; 12210296Ssam } 12310296Ssam cin = fdopen(s, "r"); 12410296Ssam cout = fdopen(s, "w"); 12511219Ssam if (cin == NULL || cout == NULL) { 12610296Ssam fprintf(stderr, "ftp: fdopen failed.\n"); 12710296Ssam if (cin) 12826496Sminshall (void) fclose(cin); 12910296Ssam if (cout) 13026496Sminshall (void) fclose(cout); 13126048Sminshall code = -1; 13210296Ssam goto bad; 13310296Ssam } 13410296Ssam if (verbose) 13526067Sminshall printf("Connected to %s.\n", hostname); 13627687Sminshall if (getreply(0) > 2) { /* read startup message from server */ 13726048Sminshall if (cin) 13826496Sminshall (void) fclose(cin); 13926048Sminshall if (cout) 14026496Sminshall (void) fclose(cout); 14126048Sminshall code = -1; 14226048Sminshall goto bad; 14326048Sminshall } 14427687Sminshall #ifdef SO_OOBINLINE 14527687Sminshall { 14627687Sminshall int on = 1; 14726048Sminshall 14827687Sminshall if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) 14927687Sminshall < 0 && debug) { 15027687Sminshall perror("ftp: setsockopt"); 15127687Sminshall } 15227687Sminshall } 15327687Sminshall #endif SO_OOBINLINE 15426048Sminshall 15525904Skarels return (hostname); 15610296Ssam bad: 15726496Sminshall (void) close(s); 15825904Skarels return ((char *)0); 15910296Ssam } 16010296Ssam 16125904Skarels login(host) 16225904Skarels char *host; 16310296Ssam { 16426048Sminshall char tmp[80]; 16535659Sbostic char *user, *pass, *acct, *getlogin(), *getpass(); 16626048Sminshall int n, aflag = 0; 16710296Ssam 16826048Sminshall user = pass = acct = 0; 16926048Sminshall if (ruserpass(host, &user, &pass, &acct) < 0) { 17026048Sminshall code = -1; 17126048Sminshall return(0); 17226048Sminshall } 173*37458Skarels while (user == NULL) { 17426048Sminshall char *myname = getlogin(); 17526048Sminshall 17626048Sminshall if (myname == NULL) { 17726048Sminshall struct passwd *pp = getpwuid(getuid()); 17826048Sminshall 17926448Slepreau if (pp != NULL) 18026048Sminshall myname = pp->pw_name; 18126048Sminshall } 182*37458Skarels if (myname) 183*37458Skarels printf("Name (%s:%s): ", host, myname); 184*37458Skarels else 185*37458Skarels printf("Name (%s): ", host); 18626048Sminshall (void) fgets(tmp, sizeof(tmp) - 1, stdin); 18726048Sminshall tmp[strlen(tmp) - 1] = '\0'; 18826448Slepreau if (*tmp == '\0') 18926048Sminshall user = myname; 19026448Slepreau else 19126048Sminshall user = tmp; 19226048Sminshall } 19310296Ssam n = command("USER %s", user); 19426048Sminshall if (n == CONTINUE) { 19526448Slepreau if (pass == NULL) 19635659Sbostic pass = getpass("Password:"); 19710296Ssam n = command("PASS %s", pass); 19826048Sminshall } 19910296Ssam if (n == CONTINUE) { 20026048Sminshall aflag++; 20135659Sbostic acct = getpass("Account:"); 20210296Ssam n = command("ACCT %s", acct); 20310296Ssam } 20410296Ssam if (n != COMPLETE) { 20510296Ssam fprintf(stderr, "Login failed.\n"); 20610296Ssam return (0); 20710296Ssam } 20826448Slepreau if (!aflag && acct != NULL) 20926048Sminshall (void) command("ACCT %s", acct); 21026448Slepreau if (proxy) 21126048Sminshall return(1); 21226048Sminshall for (n = 0; n < macnum; ++n) { 21326048Sminshall if (!strcmp("init", macros[n].mac_name)) { 21426496Sminshall (void) strcpy(line, "$init"); 21526048Sminshall makeargv(); 21626048Sminshall domacro(margc, margv); 21726048Sminshall break; 21826048Sminshall } 21926048Sminshall } 22010296Ssam return (1); 22110296Ssam } 22210296Ssam 22326048Sminshall cmdabort() 22426048Sminshall { 22526048Sminshall extern jmp_buf ptabort; 22626048Sminshall 22726048Sminshall printf("\n"); 22826048Sminshall (void) fflush(stdout); 22926048Sminshall abrtflag++; 23026448Slepreau if (ptflag) 23126048Sminshall longjmp(ptabort,1); 23226048Sminshall } 23326048Sminshall 23426496Sminshall /*VARARGS1*/ 23510296Ssam command(fmt, args) 23610296Ssam char *fmt; 23710296Ssam { 23826048Sminshall int r, (*oldintr)(), cmdabort(); 23910296Ssam 24026048Sminshall abrtflag = 0; 24110296Ssam if (debug) { 24210296Ssam printf("---> "); 24310296Ssam _doprnt(fmt, &args, stdout); 24410296Ssam printf("\n"); 24510296Ssam (void) fflush(stdout); 24610296Ssam } 24711219Ssam if (cout == NULL) { 24811219Ssam perror ("No control connection for command"); 24926048Sminshall code = -1; 25011219Ssam return (0); 25111219Ssam } 25226048Sminshall oldintr = signal(SIGINT,cmdabort); 25310296Ssam _doprnt(fmt, &args, cout); 25410296Ssam fprintf(cout, "\r\n"); 25510296Ssam (void) fflush(cout); 25626048Sminshall cpend = 1; 25726048Sminshall r = getreply(!strcmp(fmt, "QUIT")); 25826448Slepreau if (abrtflag && oldintr != SIG_IGN) 25926048Sminshall (*oldintr)(); 26026048Sminshall (void) signal(SIGINT, oldintr); 26126048Sminshall return(r); 26210296Ssam } 26310296Ssam 26437229Skarels char reply_string[BUFSIZ]; /* last line of previous reply */ 26536935Skarels 26610296Ssam #include <ctype.h> 26710296Ssam 26810296Ssam getreply(expecteof) 26910296Ssam int expecteof; 27010296Ssam { 27111219Ssam register int c, n; 27226048Sminshall register int dig; 27336935Skarels register char *cp; 27426048Sminshall int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort(); 27526048Sminshall int pflag = 0; 27626048Sminshall char *pt = pasv; 27710296Ssam 27826048Sminshall oldintr = signal(SIGINT,cmdabort); 27910296Ssam for (;;) { 28010296Ssam dig = n = code = 0; 28137229Skarels cp = reply_string; 28210296Ssam while ((c = getc(cin)) != '\n') { 28327687Sminshall if (c == IAC) { /* handle telnet commands */ 28427687Sminshall switch (c = getc(cin)) { 28527687Sminshall case WILL: 28627687Sminshall case WONT: 28727687Sminshall c = getc(cin); 28836940Skarels fprintf(cout, "%c%c%c",IAC,DONT,c); 28927687Sminshall (void) fflush(cout); 29027687Sminshall break; 29127687Sminshall case DO: 29227687Sminshall case DONT: 29327687Sminshall c = getc(cin); 29436940Skarels fprintf(cout, "%c%c%c",IAC,WONT,c); 29527687Sminshall (void) fflush(cout); 29627687Sminshall break; 29727687Sminshall default: 29827687Sminshall break; 29927687Sminshall } 30027687Sminshall continue; 30127687Sminshall } 30210296Ssam dig++; 30310296Ssam if (c == EOF) { 30426048Sminshall if (expecteof) { 30526048Sminshall (void) signal(SIGINT,oldintr); 30626048Sminshall code = 221; 30710296Ssam return (0); 30826048Sminshall } 30910296Ssam lostpeer(); 31026048Sminshall if (verbose) { 31126048Sminshall printf("421 Service not available, remote server has closed connection\n"); 31226048Sminshall (void) fflush(stdout); 31326048Sminshall } 31433772Scsvsj code = 421; 31533772Scsvsj return(4); 31610296Ssam } 31726048Sminshall if (c != '\r' && (verbose > 0 || 31826048Sminshall (verbose > -1 && n == '5' && dig > 4))) { 31926448Slepreau if (proxflag && 32026448Slepreau (dig == 1 || dig == 5 && verbose == 0)) 32126048Sminshall printf("%s:",hostname); 32226496Sminshall (void) putchar(c); 32326048Sminshall } 32410296Ssam if (dig < 4 && isdigit(c)) 32510296Ssam code = code * 10 + (c - '0'); 32626448Slepreau if (!pflag && code == 227) 32726048Sminshall pflag = 1; 32826448Slepreau if (dig > 4 && pflag == 1 && isdigit(c)) 32926048Sminshall pflag = 2; 33026048Sminshall if (pflag == 2) { 33126448Slepreau if (c != '\r' && c != ')') 33226048Sminshall *pt++ = c; 33326048Sminshall else { 33426048Sminshall *pt = '\0'; 33526048Sminshall pflag = 3; 33626048Sminshall } 33726048Sminshall } 33826048Sminshall if (dig == 4 && c == '-') { 33926448Slepreau if (continuation) 34026048Sminshall code = 0; 34110296Ssam continuation++; 34226048Sminshall } 34310296Ssam if (n == 0) 34410296Ssam n = c; 34537229Skarels if (cp < &reply_string[sizeof(reply_string) - 1]) 34637229Skarels *cp++ = c; 34710296Ssam } 34826048Sminshall if (verbose > 0 || verbose > -1 && n == '5') { 34926496Sminshall (void) putchar(c); 35011346Ssam (void) fflush (stdout); 35111346Ssam } 35210296Ssam if (continuation && code != originalcode) { 35310296Ssam if (originalcode == 0) 35410296Ssam originalcode = code; 35510296Ssam continue; 35610296Ssam } 35736935Skarels *cp = '\0'; 35826448Slepreau if (n != '1') 35926048Sminshall cpend = 0; 36026048Sminshall (void) signal(SIGINT,oldintr); 36126448Slepreau if (code == 421 || originalcode == 421) 36226048Sminshall lostpeer(); 36326448Slepreau if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) 36426048Sminshall (*oldintr)(); 36525907Smckusick return (n - '0'); 36610296Ssam } 36710296Ssam } 36810296Ssam 36926048Sminshall empty(mask, sec) 37027687Sminshall struct fd_set *mask; 37126048Sminshall int sec; 37226048Sminshall { 37326048Sminshall struct timeval t; 37426048Sminshall 37526048Sminshall t.tv_sec = (long) sec; 37626048Sminshall t.tv_usec = 0; 37727687Sminshall return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t)); 37826048Sminshall } 37926048Sminshall 38010296Ssam jmp_buf sendabort; 38110296Ssam 38210296Ssam abortsend() 38310296Ssam { 38410296Ssam 38526048Sminshall mflag = 0; 38626048Sminshall abrtflag = 0; 38726048Sminshall printf("\nsend aborted\n"); 38826048Sminshall (void) fflush(stdout); 38910296Ssam longjmp(sendabort, 1); 39010296Ssam } 39110296Ssam 39236940Skarels #define HASHBYTES 1024 39336940Skarels 39437225Skarels sendrequest(cmd, local, remote, printnames) 39510296Ssam char *cmd, *local, *remote; 39637225Skarels int printnames; 39710296Ssam { 39835659Sbostic FILE *fin, *dout = 0, *popen(); 39935659Sbostic int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); 40026048Sminshall int abortsend(); 40136942Skarels char buf[BUFSIZ], *bufp; 40236940Skarels long bytes = 0, hashbytes = HASHBYTES; 40311346Ssam register int c, d; 40410296Ssam struct stat st; 40510296Ssam struct timeval start, stop; 40636935Skarels char *mode; 40710296Ssam 40837225Skarels if (verbose && printnames) { 40937225Skarels if (local && *local != '-') 41037225Skarels printf("local: %s ", local); 41137225Skarels if (remote) 41237225Skarels printf("remote: %s\n", remote); 41337225Skarels } 41426048Sminshall if (proxy) { 41526048Sminshall proxtrans(cmd, local, remote); 41626048Sminshall return; 41726048Sminshall } 41810296Ssam closefunc = NULL; 41926048Sminshall oldintr = NULL; 42026048Sminshall oldintp = NULL; 42136935Skarels mode = "w"; 42226048Sminshall if (setjmp(sendabort)) { 42326048Sminshall while (cpend) { 42426048Sminshall (void) getreply(0); 42526048Sminshall } 42626048Sminshall if (data >= 0) { 42726048Sminshall (void) close(data); 42826048Sminshall data = -1; 42926048Sminshall } 43026448Slepreau if (oldintr) 43126048Sminshall (void) signal(SIGINT,oldintr); 43226448Slepreau if (oldintp) 43326048Sminshall (void) signal(SIGPIPE,oldintp); 43426048Sminshall code = -1; 43526048Sminshall return; 43626048Sminshall } 43710296Ssam oldintr = signal(SIGINT, abortsend); 43810296Ssam if (strcmp(local, "-") == 0) 43910296Ssam fin = stdin; 44010296Ssam else if (*local == '|') { 44126048Sminshall oldintp = signal(SIGPIPE,SIG_IGN); 44235659Sbostic fin = popen(local + 1, "r"); 44310296Ssam if (fin == NULL) { 44426048Sminshall perror(local + 1); 44526048Sminshall (void) signal(SIGINT, oldintr); 44626048Sminshall (void) signal(SIGPIPE, oldintp); 44726048Sminshall code = -1; 44826048Sminshall return; 44910296Ssam } 45035659Sbostic closefunc = pclose; 45110296Ssam } else { 45210296Ssam fin = fopen(local, "r"); 45310296Ssam if (fin == NULL) { 45410296Ssam perror(local); 45526048Sminshall (void) signal(SIGINT, oldintr); 45626048Sminshall code = -1; 45726048Sminshall return; 45810296Ssam } 45910296Ssam closefunc = fclose; 46010296Ssam if (fstat(fileno(fin), &st) < 0 || 46110296Ssam (st.st_mode&S_IFMT) != S_IFREG) { 46226496Sminshall fprintf(stdout, "%s: not a plain file.\n", local); 46326048Sminshall (void) signal(SIGINT, oldintr); 46436935Skarels fclose(fin); 46526048Sminshall code = -1; 46626048Sminshall return; 46710296Ssam } 46810296Ssam } 46926048Sminshall if (initconn()) { 47026048Sminshall (void) signal(SIGINT, oldintr); 47126448Slepreau if (oldintp) 47226048Sminshall (void) signal(SIGPIPE, oldintp); 47326048Sminshall code = -1; 47436935Skarels if (closefunc != NULL) 47536935Skarels (*closefunc)(fin); 47626048Sminshall return; 47726048Sminshall } 47826448Slepreau if (setjmp(sendabort)) 47926048Sminshall goto abort; 48036935Skarels 48137225Skarels if (restart_point && 48237225Skarels (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { 48337225Skarels if (fseek(fin, (long) restart_point, 0) < 0) { 48437225Skarels perror(local); 48537225Skarels restart_point = 0; 48637225Skarels if (closefunc != NULL) 48737225Skarels (*closefunc)(fin); 48837225Skarels return; 48937225Skarels } 49037225Skarels if (command("REST %ld", (long) restart_point) 49137225Skarels != CONTINUE) { 49237225Skarels restart_point = 0; 49337225Skarels if (closefunc != NULL) 49437225Skarels (*closefunc)(fin); 49537225Skarels return; 49637225Skarels } 49737225Skarels restart_point = 0; 49837225Skarels mode = "r+w"; 49937225Skarels } 50010296Ssam if (remote) { 50126048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 50226048Sminshall (void) signal(SIGINT, oldintr); 50326448Slepreau if (oldintp) 50426048Sminshall (void) signal(SIGPIPE, oldintp); 50536935Skarels if (closefunc != NULL) 50636935Skarels (*closefunc)(fin); 50726048Sminshall return; 50826048Sminshall } 50910296Ssam } else 51026048Sminshall if (command("%s", cmd) != PRELIM) { 51126048Sminshall (void) signal(SIGINT, oldintr); 51226448Slepreau if (oldintp) 51326048Sminshall (void) signal(SIGPIPE, oldintp); 51436935Skarels if (closefunc != NULL) 51536935Skarels (*closefunc)(fin); 51626048Sminshall return; 51726048Sminshall } 51836935Skarels dout = dataconn(mode); 51926448Slepreau if (dout == NULL) 52026048Sminshall goto abort; 52126496Sminshall (void) gettimeofday(&start, (struct timezone *)0); 52236935Skarels oldintp = signal(SIGPIPE, SIG_IGN); 52311219Ssam switch (type) { 52411219Ssam 52511219Ssam case TYPE_I: 52611219Ssam case TYPE_L: 52711346Ssam errno = d = 0; 52836942Skarels while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) { 52911219Ssam bytes += c; 53036942Skarels for (bufp = buf; c > 0; c -= d, bufp += d) 53136942Skarels if ((d = write(fileno(dout), bufp, c)) <= 0) 53236942Skarels break; 53311651Ssam if (hash) { 53436940Skarels while (bytes >= hashbytes) { 53536940Skarels (void) putchar('#'); 53636940Skarels hashbytes += HASHBYTES; 53736940Skarels } 53826496Sminshall (void) fflush(stdout); 53911651Ssam } 54011219Ssam } 54113213Ssam if (hash && bytes > 0) { 54236940Skarels if (bytes < HASHBYTES) 54336940Skarels (void) putchar('#'); 54426496Sminshall (void) putchar('\n'); 54526496Sminshall (void) fflush(stdout); 54611651Ssam } 54711219Ssam if (c < 0) 54811219Ssam perror(local); 54936942Skarels if (d <= 0) { 55036942Skarels if (d == 0) 55136942Skarels fprintf(stderr, "netout: write returned 0?\n"); 55236942Skarels else if (errno != EPIPE) 55336935Skarels perror("netout"); 55436935Skarels bytes = -1; 55536935Skarels } 55611219Ssam break; 55711219Ssam 55811219Ssam case TYPE_A: 55911219Ssam while ((c = getc(fin)) != EOF) { 56011219Ssam if (c == '\n') { 56111651Ssam while (hash && (bytes >= hashbytes)) { 56226496Sminshall (void) putchar('#'); 56326496Sminshall (void) fflush(stdout); 56436940Skarels hashbytes += HASHBYTES; 56511651Ssam } 56611219Ssam if (ferror(dout)) 56711219Ssam break; 56826496Sminshall (void) putc('\r', dout); 56911219Ssam bytes++; 57011219Ssam } 57126496Sminshall (void) putc(c, dout); 57211219Ssam bytes++; 57326048Sminshall /* if (c == '\r') { */ 57426496Sminshall /* (void) putc('\0', dout); /* this violates rfc */ 57526048Sminshall /* bytes++; */ 57626048Sminshall /* } */ 57711219Ssam } 57811651Ssam if (hash) { 57913213Ssam if (bytes < hashbytes) 58026496Sminshall (void) putchar('#'); 58126496Sminshall (void) putchar('\n'); 58226496Sminshall (void) fflush(stdout); 58311651Ssam } 58411219Ssam if (ferror(fin)) 58511219Ssam perror(local); 58636935Skarels if (ferror(dout)) { 58736935Skarels if (errno != EPIPE) 58836935Skarels perror("netout"); 58936935Skarels bytes = -1; 59036935Skarels } 59111219Ssam break; 59210296Ssam } 59326496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 59410296Ssam if (closefunc != NULL) 59526048Sminshall (*closefunc)(fin); 59610296Ssam (void) fclose(dout); 59726048Sminshall (void) getreply(0); 59826048Sminshall (void) signal(SIGINT, oldintr); 59936935Skarels if (oldintp) 60036935Skarels (void) signal(SIGPIPE, oldintp); 60135699Sbostic if (bytes > 0) 60237225Skarels ptransfer("sent", bytes, &start, &stop); 60310296Ssam return; 60426048Sminshall abort: 60526496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 60626048Sminshall (void) signal(SIGINT, oldintr); 60726448Slepreau if (oldintp) 60826048Sminshall (void) signal(SIGPIPE, oldintp); 60926048Sminshall if (!cpend) { 61026048Sminshall code = -1; 61126048Sminshall return; 61226048Sminshall } 61326048Sminshall if (data >= 0) { 61426048Sminshall (void) close(data); 61526048Sminshall data = -1; 61626048Sminshall } 61726448Slepreau if (dout) 61826048Sminshall (void) fclose(dout); 61926048Sminshall (void) getreply(0); 62026048Sminshall code = -1; 62110296Ssam if (closefunc != NULL && fin != NULL) 62226048Sminshall (*closefunc)(fin); 62335699Sbostic if (bytes > 0) 62437225Skarels ptransfer("sent", bytes, &start, &stop); 62510296Ssam } 62610296Ssam 62710296Ssam jmp_buf recvabort; 62810296Ssam 62910296Ssam abortrecv() 63010296Ssam { 63110296Ssam 63226048Sminshall mflag = 0; 63326048Sminshall abrtflag = 0; 63426048Sminshall printf("\n"); 63526048Sminshall (void) fflush(stdout); 63610296Ssam longjmp(recvabort, 1); 63710296Ssam } 63810296Ssam 63937225Skarels recvrequest(cmd, local, remote, mode, printnames) 64011651Ssam char *cmd, *local, *remote, *mode; 64110296Ssam { 64235659Sbostic FILE *fout, *din = 0, *popen(); 64335659Sbostic int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); 64436935Skarels int abortrecv(), oldverbose, oldtype = 0, is_retr, tcrflag, nfnd; 64536944Skarels char *bufp, *gunique(), msg; 64636944Skarels static char *buf; 64736940Skarels static int bufsize; 64836940Skarels long bytes = 0, hashbytes = HASHBYTES; 64926496Sminshall struct fd_set mask; 65011346Ssam register int c, d; 65110296Ssam struct timeval start, stop; 65236940Skarels struct stat st; 65336940Skarels extern char *malloc(); 65410296Ssam 65536935Skarels is_retr = strcmp(cmd, "RETR") == 0; 65637225Skarels if (is_retr && verbose && printnames) { 65737225Skarels if (local && *local != '-') 65837225Skarels printf("local: %s ", local); 65937225Skarels if (remote) 66037225Skarels printf("remote: %s\n", remote); 66137225Skarels } 66236935Skarels if (proxy && is_retr) { 66326048Sminshall proxtrans(cmd, local, remote); 66426048Sminshall return; 66526048Sminshall } 66610296Ssam closefunc = NULL; 66726048Sminshall oldintr = NULL; 66826048Sminshall oldintp = NULL; 66936935Skarels tcrflag = !crflag && is_retr; 67026048Sminshall if (setjmp(recvabort)) { 67126048Sminshall while (cpend) { 67226048Sminshall (void) getreply(0); 67326048Sminshall } 67426048Sminshall if (data >= 0) { 67526048Sminshall (void) close(data); 67626048Sminshall data = -1; 67726048Sminshall } 67826448Slepreau if (oldintr) 67926048Sminshall (void) signal(SIGINT, oldintr); 68026048Sminshall code = -1; 68126048Sminshall return; 68226048Sminshall } 68310296Ssam oldintr = signal(SIGINT, abortrecv); 68426048Sminshall if (strcmp(local, "-") && *local != '|') { 68510296Ssam if (access(local, 2) < 0) { 68626048Sminshall char *dir = rindex(local, '/'); 68710296Ssam 68826048Sminshall if (errno != ENOENT && errno != EACCES) { 68910296Ssam perror(local); 69026048Sminshall (void) signal(SIGINT, oldintr); 69126048Sminshall code = -1; 69226048Sminshall return; 69310296Ssam } 69426048Sminshall if (dir != NULL) 69526048Sminshall *dir = 0; 69626048Sminshall d = access(dir ? local : ".", 2); 69726048Sminshall if (dir != NULL) 69826048Sminshall *dir = '/'; 69926048Sminshall if (d < 0) { 70026048Sminshall perror(local); 70126048Sminshall (void) signal(SIGINT, oldintr); 70226048Sminshall code = -1; 70326048Sminshall return; 70426048Sminshall } 70526048Sminshall if (!runique && errno == EACCES && 70636935Skarels chmod(local, 0600) < 0) { 70726048Sminshall perror(local); 70826048Sminshall (void) signal(SIGINT, oldintr); 70926048Sminshall code = -1; 71026048Sminshall return; 71126048Sminshall } 71226048Sminshall if (runique && errno == EACCES && 71326048Sminshall (local = gunique(local)) == NULL) { 71426048Sminshall (void) signal(SIGINT, oldintr); 71526048Sminshall code = -1; 71626048Sminshall return; 71726048Sminshall } 71810296Ssam } 71926048Sminshall else if (runique && (local = gunique(local)) == NULL) { 72026048Sminshall (void) signal(SIGINT, oldintr); 72126048Sminshall code = -1; 72226048Sminshall return; 72326048Sminshall } 72426048Sminshall } 72526048Sminshall if (initconn()) { 72626048Sminshall (void) signal(SIGINT, oldintr); 72726048Sminshall code = -1; 72826048Sminshall return; 72926048Sminshall } 73026448Slepreau if (setjmp(recvabort)) 73126048Sminshall goto abort; 73236935Skarels if (!is_retr) { 733*37458Skarels if (type != TYPE_A && (allbinary == 0 || type != TYPE_I)) { 73436935Skarels oldtype = type; 73536935Skarels oldverbose = verbose; 73636935Skarels if (!debug) 73736935Skarels verbose = 0; 73836935Skarels setascii(); 73936935Skarels verbose = oldverbose; 74036935Skarels } 74137225Skarels } else if (restart_point) { 74237225Skarels if (command("REST %ld", (long) restart_point) != CONTINUE) 74337225Skarels return; 74426048Sminshall } 74510296Ssam if (remote) { 74626048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 74726048Sminshall (void) signal(SIGINT, oldintr); 74826048Sminshall if (oldtype) { 74926448Slepreau if (!debug) 75026048Sminshall verbose = 0; 75126048Sminshall switch (oldtype) { 75226048Sminshall case TYPE_I: 75326048Sminshall setbinary(); 75426048Sminshall break; 75526048Sminshall case TYPE_E: 75626048Sminshall setebcdic(); 75726048Sminshall break; 75826048Sminshall case TYPE_L: 75926048Sminshall settenex(); 76026048Sminshall break; 76136942Skarels } 76226048Sminshall verbose = oldverbose; 76326048Sminshall } 76426048Sminshall return; 76526048Sminshall } 76626048Sminshall } else { 76726048Sminshall if (command("%s", cmd) != PRELIM) { 76826048Sminshall (void) signal(SIGINT, oldintr); 76926048Sminshall if (oldtype) { 77026448Slepreau if (!debug) 77126048Sminshall verbose = 0; 77226048Sminshall switch (oldtype) { 77326048Sminshall case TYPE_I: 77426048Sminshall setbinary(); 77526048Sminshall break; 77626048Sminshall case TYPE_E: 77726048Sminshall setebcdic(); 77826048Sminshall break; 77926048Sminshall case TYPE_L: 78026048Sminshall settenex(); 78126048Sminshall break; 78236942Skarels } 78326048Sminshall verbose = oldverbose; 78426048Sminshall } 78526048Sminshall return; 78626048Sminshall } 78726048Sminshall } 78826048Sminshall din = dataconn("r"); 78926048Sminshall if (din == NULL) 79026048Sminshall goto abort; 79126448Slepreau if (strcmp(local, "-") == 0) 79210296Ssam fout = stdout; 79310296Ssam else if (*local == '|') { 79426048Sminshall oldintp = signal(SIGPIPE, SIG_IGN); 79535659Sbostic fout = popen(local + 1, "w"); 79626048Sminshall if (fout == NULL) { 79726048Sminshall perror(local+1); 79826048Sminshall goto abort; 79926048Sminshall } 80035659Sbostic closefunc = pclose; 80136940Skarels } else { 80211651Ssam fout = fopen(local, mode); 80326048Sminshall if (fout == NULL) { 80426048Sminshall perror(local); 80526048Sminshall goto abort; 80626048Sminshall } 80710296Ssam closefunc = fclose; 80810296Ssam } 80936940Skarels if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) 81036940Skarels st.st_blksize = BUFSIZ; 81136940Skarels if (st.st_blksize > bufsize) { 81236940Skarels if (buf) 81336940Skarels (void) free(buf); 81436940Skarels buf = malloc(st.st_blksize); 81536940Skarels if (buf == NULL) { 81636940Skarels perror("malloc"); 81736944Skarels bufsize = 0; 81836940Skarels goto abort; 81936940Skarels } 82036940Skarels bufsize = st.st_blksize; 82136940Skarels } 82226496Sminshall (void) gettimeofday(&start, (struct timezone *)0); 82311219Ssam switch (type) { 82411219Ssam 82511219Ssam case TYPE_I: 82611219Ssam case TYPE_L: 82737225Skarels if (restart_point && 82837225Skarels lseek(fileno(fout), (long) restart_point, L_SET) < 0) { 82937225Skarels perror(local); 83037225Skarels if (closefunc != NULL) 83137225Skarels (*closefunc)(fout); 83237225Skarels return; 83337225Skarels } 83411346Ssam errno = d = 0; 83536940Skarels while ((c = read(fileno(din), buf, bufsize)) > 0) { 83636944Skarels if ((d = write(fileno(fout), buf, c)) != c) 83711219Ssam break; 83811219Ssam bytes += c; 83911651Ssam if (hash) { 84036940Skarels while (bytes >= hashbytes) { 84136940Skarels (void) putchar('#'); 84236940Skarels hashbytes += HASHBYTES; 84336940Skarels } 84426496Sminshall (void) fflush(stdout); 84511651Ssam } 84611219Ssam } 84713213Ssam if (hash && bytes > 0) { 84836940Skarels if (bytes < HASHBYTES) 84936940Skarels (void) putchar('#'); 85026496Sminshall (void) putchar('\n'); 85126496Sminshall (void) fflush(stdout); 85211651Ssam } 85336935Skarels if (c < 0) { 85436935Skarels if (errno != EPIPE) 85536935Skarels perror("netin"); 85636935Skarels bytes = -1; 85736935Skarels } 85836942Skarels if (d < c) { 85936942Skarels if (d < 0) 86036942Skarels perror(local); 86136942Skarels else 86236942Skarels fprintf(stderr, "%s: short write\n", local); 86336942Skarels } 86411219Ssam break; 86511219Ssam 86611219Ssam case TYPE_A: 86737225Skarels if (restart_point) { 86837225Skarels register int i, n, c; 86937225Skarels 87037225Skarels if (fseek(fout, 0L, L_SET) < 0) 87137225Skarels goto done; 87237225Skarels n = restart_point; 87337225Skarels i = 0; 87437225Skarels while (i++ < n) { 87537225Skarels if ((c=getc(fout)) == EOF) 87637225Skarels goto done; 87737225Skarels if (c == '\n') 87837225Skarels i++; 87937225Skarels } 88037225Skarels if (fseek(fout, 0L, L_INCR) < 0) { 88137225Skarels done: 88237225Skarels perror(local); 88337225Skarels if (closefunc != NULL) 88437225Skarels (*closefunc)(fout); 88537225Skarels return; 88637225Skarels } 88737225Skarels } 88811219Ssam while ((c = getc(din)) != EOF) { 88927749Sminshall while (c == '\r') { 89011651Ssam while (hash && (bytes >= hashbytes)) { 89126496Sminshall (void) putchar('#'); 89226496Sminshall (void) fflush(stdout); 89336940Skarels hashbytes += HASHBYTES; 89411651Ssam } 89510296Ssam bytes++; 89626048Sminshall if ((c = getc(din)) != '\n' || tcrflag) { 89736940Skarels if (ferror(fout)) 89836940Skarels goto break2; 89936940Skarels (void) putc('\r', fout); 90036942Skarels if (c == '\0') { 90136942Skarels bytes++; 90236940Skarels goto contin2; 90336942Skarels } 90436942Skarels if (c == EOF) 90536942Skarels goto contin2; 90611219Ssam } 90711219Ssam } 90836940Skarels (void) putc(c, fout); 90911219Ssam bytes++; 91036940Skarels contin2: ; 91110296Ssam } 91236940Skarels break2: 91311651Ssam if (hash) { 91413213Ssam if (bytes < hashbytes) 91526496Sminshall (void) putchar('#'); 91626496Sminshall (void) putchar('\n'); 91726496Sminshall (void) fflush(stdout); 91811651Ssam } 91936944Skarels if (ferror(din)) { 92036935Skarels if (errno != EPIPE) 92136944Skarels perror("netin"); 92236935Skarels bytes = -1; 92336935Skarels } 92436940Skarels if (ferror(fout)) 92536944Skarels perror(local); 92611219Ssam break; 92710296Ssam } 92826448Slepreau if (closefunc != NULL) 92926048Sminshall (*closefunc)(fout); 93026496Sminshall (void) signal(SIGINT, oldintr); 93126448Slepreau if (oldintp) 93226048Sminshall (void) signal(SIGPIPE, oldintp); 93326496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 93410296Ssam (void) fclose(din); 93526048Sminshall (void) getreply(0); 93636935Skarels if (bytes > 0 && is_retr) 93737225Skarels ptransfer("received", bytes, &start, &stop); 93826048Sminshall if (oldtype) { 93926448Slepreau if (!debug) 94026048Sminshall verbose = 0; 94126048Sminshall switch (oldtype) { 94226048Sminshall case TYPE_I: 94326048Sminshall setbinary(); 94426048Sminshall break; 94526048Sminshall case TYPE_E: 94626048Sminshall setebcdic(); 94726048Sminshall break; 94826048Sminshall case TYPE_L: 94926048Sminshall settenex(); 95026048Sminshall break; 95126048Sminshall } 95226048Sminshall verbose = oldverbose; 95326048Sminshall } 95426048Sminshall return; 95526048Sminshall abort: 95626048Sminshall 95727687Sminshall /* abort using RFC959 recommended IP,SYNC sequence */ 95826048Sminshall 95926496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 96026448Slepreau if (oldintp) 96126048Sminshall (void) signal(SIGPIPE, oldintr); 96226048Sminshall (void) signal(SIGINT,SIG_IGN); 96326048Sminshall if (oldtype) { 96426448Slepreau if (!debug) 96526048Sminshall verbose = 0; 96626048Sminshall switch (oldtype) { 96726048Sminshall case TYPE_I: 96826048Sminshall setbinary(); 96926048Sminshall break; 97026048Sminshall case TYPE_E: 97126048Sminshall setebcdic(); 97226048Sminshall break; 97326048Sminshall case TYPE_L: 97426048Sminshall settenex(); 97526048Sminshall break; 97626048Sminshall } 97726048Sminshall verbose = oldverbose; 97826048Sminshall } 97926048Sminshall if (!cpend) { 98026048Sminshall code = -1; 98126048Sminshall (void) signal(SIGINT,oldintr); 98226048Sminshall return; 98326048Sminshall } 98426048Sminshall 98527687Sminshall fprintf(cout,"%c%c",IAC,IP); 98627687Sminshall (void) fflush(cout); 98727687Sminshall msg = IAC; 98827687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */ 98927687Sminshall /* after urgent byte rather than before as now is protocol */ 99027687Sminshall if (send(fileno(cout),&msg,1,MSG_OOB) != 1) { 99127687Sminshall perror("abort"); 99226048Sminshall } 99327687Sminshall fprintf(cout,"%cABOR\r\n",DM); 99426048Sminshall (void) fflush(cout); 99527687Sminshall FD_ZERO(&mask); 99626496Sminshall FD_SET(fileno(cin), &mask); 99726496Sminshall if (din) { 99826496Sminshall FD_SET(fileno(din), &mask); 99926496Sminshall } 100027687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 100127687Sminshall if (nfnd < 0) { 100227687Sminshall perror("abort"); 100327687Sminshall } 100426048Sminshall code = -1; 100526048Sminshall lostpeer(); 100626048Sminshall } 100726496Sminshall if (din && FD_ISSET(fileno(din), &mask)) { 100836940Skarels while ((c = read(fileno(din), buf, bufsize)) > 0) 100926448Slepreau ; 101026496Sminshall } 101127687Sminshall if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */ 101226048Sminshall if (data >= 0) { 101326496Sminshall (void) close(data); 101426048Sminshall data = -1; 101526048Sminshall } 101625907Smckusick (void) getreply(0); 101725907Smckusick } 101826048Sminshall (void) getreply(0); 101926048Sminshall code = -1; 102026048Sminshall if (data >= 0) { 102126048Sminshall (void) close(data); 102226048Sminshall data = -1; 102326048Sminshall } 102426448Slepreau if (closefunc != NULL && fout != NULL) 102526048Sminshall (*closefunc)(fout); 102626448Slepreau if (din) 102726048Sminshall (void) fclose(din); 102835699Sbostic if (bytes > 0) 102937225Skarels ptransfer("received", bytes, &start, &stop); 103026048Sminshall (void) signal(SIGINT,oldintr); 103110296Ssam } 103210296Ssam 103310296Ssam /* 103410296Ssam * Need to start a listen on the data channel 103510296Ssam * before we send the command, otherwise the 103610296Ssam * server's connect may fail. 103710296Ssam */ 103833224Sbostic int sendport = -1; 103911651Ssam 104010296Ssam initconn() 104110296Ssam { 104210296Ssam register char *p, *a; 104326048Sminshall int result, len, tmpno = 0; 104426993Skarels int on = 1; 104510296Ssam 104611651Ssam noport: 104710296Ssam data_addr = myctladdr; 104811651Ssam if (sendport) 104911651Ssam data_addr.sin_port = 0; /* let system pick one */ 105011651Ssam if (data != -1) 105111651Ssam (void) close (data); 105218287Sralph data = socket(AF_INET, SOCK_STREAM, 0); 105310296Ssam if (data < 0) { 105410296Ssam perror("ftp: socket"); 105526448Slepreau if (tmpno) 105626048Sminshall sendport = 1; 105710296Ssam return (1); 105810296Ssam } 105912397Ssam if (!sendport) 106027687Sminshall if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { 106133224Sbostic perror("ftp: setsockopt (reuse address)"); 106212397Ssam goto bad; 106312397Ssam } 106426496Sminshall if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { 106510296Ssam perror("ftp: bind"); 106610296Ssam goto bad; 106710296Ssam } 106810296Ssam if (options & SO_DEBUG && 106927687Sminshall setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) 107010296Ssam perror("ftp: setsockopt (ignored)"); 107111627Ssam len = sizeof (data_addr); 107211627Ssam if (getsockname(data, (char *)&data_addr, &len) < 0) { 107311627Ssam perror("ftp: getsockname"); 107410296Ssam goto bad; 107510296Ssam } 107626448Slepreau if (listen(data, 1) < 0) 107710296Ssam perror("ftp: listen"); 107811651Ssam if (sendport) { 107911651Ssam a = (char *)&data_addr.sin_addr; 108011651Ssam p = (char *)&data_addr.sin_port; 108110296Ssam #define UC(b) (((int)b)&0xff) 108211651Ssam result = 108311651Ssam command("PORT %d,%d,%d,%d,%d,%d", 108411651Ssam UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 108511651Ssam UC(p[0]), UC(p[1])); 108611651Ssam if (result == ERROR && sendport == -1) { 108711651Ssam sendport = 0; 108826048Sminshall tmpno = 1; 108911651Ssam goto noport; 109011651Ssam } 109111651Ssam return (result != COMPLETE); 109211651Ssam } 109326448Slepreau if (tmpno) 109426048Sminshall sendport = 1; 109511651Ssam return (0); 109610296Ssam bad: 109710296Ssam (void) close(data), data = -1; 109826448Slepreau if (tmpno) 109926048Sminshall sendport = 1; 110010296Ssam return (1); 110110296Ssam } 110210296Ssam 110310296Ssam FILE * 110410296Ssam dataconn(mode) 110510296Ssam char *mode; 110610296Ssam { 110710296Ssam struct sockaddr_in from; 110810296Ssam int s, fromlen = sizeof (from); 110910296Ssam 111026496Sminshall s = accept(data, (struct sockaddr *) &from, &fromlen); 111110296Ssam if (s < 0) { 111210296Ssam perror("ftp: accept"); 111310296Ssam (void) close(data), data = -1; 111410296Ssam return (NULL); 111510296Ssam } 111610296Ssam (void) close(data); 111710296Ssam data = s; 111810296Ssam return (fdopen(data, mode)); 111910296Ssam } 112010296Ssam 112137225Skarels ptransfer(direction, bytes, t0, t1) 112237225Skarels char *direction; 112311651Ssam long bytes; 112410296Ssam struct timeval *t0, *t1; 112510296Ssam { 112610296Ssam struct timeval td; 112716437Sleres float s, bs; 112810296Ssam 112935699Sbostic if (verbose) { 113035699Sbostic tvsub(&td, t1, t0); 113135699Sbostic s = td.tv_sec + (td.tv_usec / 1000000.); 113210296Ssam #define nz(x) ((x) == 0 ? 1 : (x)) 113335699Sbostic bs = bytes / nz(s); 113435699Sbostic printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n", 113535699Sbostic bytes, direction, s, bs / 1024.); 113635699Sbostic } 113710296Ssam } 113810296Ssam 113926496Sminshall /*tvadd(tsum, t0) 114010296Ssam struct timeval *tsum, *t0; 114110296Ssam { 114210296Ssam 114310296Ssam tsum->tv_sec += t0->tv_sec; 114410296Ssam tsum->tv_usec += t0->tv_usec; 114510296Ssam if (tsum->tv_usec > 1000000) 114610296Ssam tsum->tv_sec++, tsum->tv_usec -= 1000000; 114726496Sminshall } */ 114810296Ssam 114910296Ssam tvsub(tdiff, t1, t0) 115010296Ssam struct timeval *tdiff, *t1, *t0; 115110296Ssam { 115210296Ssam 115310296Ssam tdiff->tv_sec = t1->tv_sec - t0->tv_sec; 115410296Ssam tdiff->tv_usec = t1->tv_usec - t0->tv_usec; 115510296Ssam if (tdiff->tv_usec < 0) 115610296Ssam tdiff->tv_sec--, tdiff->tv_usec += 1000000; 115710296Ssam } 115826048Sminshall 115926048Sminshall psabort() 116026048Sminshall { 116126048Sminshall extern int abrtflag; 116226048Sminshall 116326048Sminshall abrtflag++; 116426048Sminshall } 116526048Sminshall 116626048Sminshall pswitch(flag) 116726048Sminshall int flag; 116826048Sminshall { 116926048Sminshall extern int proxy, abrtflag; 117026048Sminshall int (*oldintr)(); 117126048Sminshall static struct comvars { 117226048Sminshall int connect; 117328469Skarels char name[MAXHOSTNAMELEN]; 117426048Sminshall struct sockaddr_in mctl; 117526048Sminshall struct sockaddr_in hctl; 117626048Sminshall FILE *in; 117726048Sminshall FILE *out; 117826048Sminshall int tpe; 117926048Sminshall int cpnd; 118026048Sminshall int sunqe; 118126048Sminshall int runqe; 118226048Sminshall int mcse; 118326048Sminshall int ntflg; 118426048Sminshall char nti[17]; 118526048Sminshall char nto[17]; 118626048Sminshall int mapflg; 118726048Sminshall char mi[MAXPATHLEN]; 118826048Sminshall char mo[MAXPATHLEN]; 118926048Sminshall } proxstruct, tmpstruct; 119026048Sminshall struct comvars *ip, *op; 119126048Sminshall 119226048Sminshall abrtflag = 0; 119326048Sminshall oldintr = signal(SIGINT, psabort); 119426048Sminshall if (flag) { 119526448Slepreau if (proxy) 119626048Sminshall return; 119726048Sminshall ip = &tmpstruct; 119826048Sminshall op = &proxstruct; 119926048Sminshall proxy++; 120026048Sminshall } 120126048Sminshall else { 120226448Slepreau if (!proxy) 120326048Sminshall return; 120426048Sminshall ip = &proxstruct; 120526048Sminshall op = &tmpstruct; 120626048Sminshall proxy = 0; 120726048Sminshall } 120826048Sminshall ip->connect = connected; 120926048Sminshall connected = op->connect; 121028469Skarels if (hostname) { 121128469Skarels (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1); 121228469Skarels ip->name[strlen(ip->name)] = '\0'; 121328469Skarels } else 121428469Skarels ip->name[0] = 0; 121526048Sminshall hostname = op->name; 121626048Sminshall ip->hctl = hisctladdr; 121726048Sminshall hisctladdr = op->hctl; 121826048Sminshall ip->mctl = myctladdr; 121926048Sminshall myctladdr = op->mctl; 122026048Sminshall ip->in = cin; 122126048Sminshall cin = op->in; 122226048Sminshall ip->out = cout; 122326048Sminshall cout = op->out; 122426048Sminshall ip->tpe = type; 122526048Sminshall type = op->tpe; 122626448Slepreau if (!type) 122726048Sminshall type = 1; 122826048Sminshall ip->cpnd = cpend; 122926048Sminshall cpend = op->cpnd; 123026048Sminshall ip->sunqe = sunique; 123126048Sminshall sunique = op->sunqe; 123226048Sminshall ip->runqe = runique; 123326048Sminshall runique = op->runqe; 123426048Sminshall ip->mcse = mcase; 123526048Sminshall mcase = op->mcse; 123626048Sminshall ip->ntflg = ntflag; 123726048Sminshall ntflag = op->ntflg; 123826496Sminshall (void) strncpy(ip->nti, ntin, 16); 123926048Sminshall (ip->nti)[strlen(ip->nti)] = '\0'; 124026496Sminshall (void) strcpy(ntin, op->nti); 124126496Sminshall (void) strncpy(ip->nto, ntout, 16); 124226048Sminshall (ip->nto)[strlen(ip->nto)] = '\0'; 124326496Sminshall (void) strcpy(ntout, op->nto); 124426048Sminshall ip->mapflg = mapflag; 124526048Sminshall mapflag = op->mapflg; 124626496Sminshall (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1); 124726048Sminshall (ip->mi)[strlen(ip->mi)] = '\0'; 124826496Sminshall (void) strcpy(mapin, op->mi); 124926496Sminshall (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1); 125026048Sminshall (ip->mo)[strlen(ip->mo)] = '\0'; 125126496Sminshall (void) strcpy(mapout, op->mo); 125226048Sminshall (void) signal(SIGINT, oldintr); 125326048Sminshall if (abrtflag) { 125426048Sminshall abrtflag = 0; 125526048Sminshall (*oldintr)(); 125626448Slepreau } 125726048Sminshall } 125826048Sminshall 125926048Sminshall jmp_buf ptabort; 126026048Sminshall int ptabflg; 126126048Sminshall 126226048Sminshall abortpt() 126326048Sminshall { 126426048Sminshall printf("\n"); 126526496Sminshall (void) fflush(stdout); 126626048Sminshall ptabflg++; 126726048Sminshall mflag = 0; 126826048Sminshall abrtflag = 0; 126926048Sminshall longjmp(ptabort, 1); 127026048Sminshall } 127126048Sminshall 127226048Sminshall proxtrans(cmd, local, remote) 127326048Sminshall char *cmd, *local, *remote; 127426048Sminshall { 127527687Sminshall int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd; 127626048Sminshall extern jmp_buf ptabort; 127726048Sminshall char *cmd2; 127826496Sminshall struct fd_set mask; 127926048Sminshall 128026448Slepreau if (strcmp(cmd, "RETR")) 128126048Sminshall cmd2 = "RETR"; 128226448Slepreau else 128326048Sminshall cmd2 = runique ? "STOU" : "STOR"; 128426048Sminshall if (command("PASV") != COMPLETE) { 128526048Sminshall printf("proxy server does not support third part transfers.\n"); 128626048Sminshall return; 128726048Sminshall } 128826048Sminshall tmptype = type; 128926048Sminshall pswitch(0); 129026048Sminshall if (!connected) { 129126048Sminshall printf("No primary connection\n"); 129226048Sminshall pswitch(1); 129326048Sminshall code = -1; 129426048Sminshall return; 129526048Sminshall } 129626048Sminshall if (type != tmptype) { 129726048Sminshall oldtype = type; 129826048Sminshall switch (tmptype) { 129926048Sminshall case TYPE_A: 130026048Sminshall setascii(); 130126048Sminshall break; 130226048Sminshall case TYPE_I: 130326048Sminshall setbinary(); 130426048Sminshall break; 130526048Sminshall case TYPE_E: 130626048Sminshall setebcdic(); 130726048Sminshall break; 130826048Sminshall case TYPE_L: 130926048Sminshall settenex(); 131026048Sminshall break; 131126048Sminshall } 131226048Sminshall } 131326048Sminshall if (command("PORT %s", pasv) != COMPLETE) { 131426048Sminshall switch (oldtype) { 131526048Sminshall case 0: 131626048Sminshall break; 131726048Sminshall case TYPE_A: 131826048Sminshall setascii(); 131926048Sminshall break; 132026048Sminshall case TYPE_I: 132126048Sminshall setbinary(); 132226048Sminshall break; 132326048Sminshall case TYPE_E: 132426048Sminshall setebcdic(); 132526048Sminshall break; 132626048Sminshall case TYPE_L: 132726048Sminshall settenex(); 132826048Sminshall break; 132926048Sminshall } 133026048Sminshall pswitch(1); 133126048Sminshall return; 133226048Sminshall } 133326448Slepreau if (setjmp(ptabort)) 133426048Sminshall goto abort; 133526048Sminshall oldintr = signal(SIGINT, abortpt); 133626048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 133726048Sminshall (void) signal(SIGINT, oldintr); 133826048Sminshall switch (oldtype) { 133926048Sminshall case 0: 134026048Sminshall break; 134126048Sminshall case TYPE_A: 134226048Sminshall setascii(); 134326048Sminshall break; 134426048Sminshall case TYPE_I: 134526048Sminshall setbinary(); 134626048Sminshall break; 134726048Sminshall case TYPE_E: 134826048Sminshall setebcdic(); 134926048Sminshall break; 135026048Sminshall case TYPE_L: 135126048Sminshall settenex(); 135226048Sminshall break; 135326048Sminshall } 135426048Sminshall pswitch(1); 135526048Sminshall return; 135626048Sminshall } 135726048Sminshall sleep(2); 135826048Sminshall pswitch(1); 135926048Sminshall secndflag++; 136026448Slepreau if (command("%s %s", cmd2, local) != PRELIM) 136126048Sminshall goto abort; 136226048Sminshall ptflag++; 136326048Sminshall (void) getreply(0); 136426048Sminshall pswitch(0); 136526048Sminshall (void) getreply(0); 136626048Sminshall (void) signal(SIGINT, oldintr); 136726048Sminshall switch (oldtype) { 136826048Sminshall case 0: 136926048Sminshall break; 137026048Sminshall case TYPE_A: 137126048Sminshall setascii(); 137226048Sminshall break; 137326048Sminshall case TYPE_I: 137426048Sminshall setbinary(); 137526048Sminshall break; 137626048Sminshall case TYPE_E: 137726048Sminshall setebcdic(); 137826048Sminshall break; 137926048Sminshall case TYPE_L: 138026048Sminshall settenex(); 138126048Sminshall break; 138226048Sminshall } 138326048Sminshall pswitch(1); 138426048Sminshall ptflag = 0; 138526048Sminshall printf("local: %s remote: %s\n", local, remote); 138626048Sminshall return; 138726048Sminshall abort: 138826048Sminshall (void) signal(SIGINT, SIG_IGN); 138926048Sminshall ptflag = 0; 139026448Slepreau if (strcmp(cmd, "RETR") && !proxy) 139126048Sminshall pswitch(1); 139226448Slepreau else if (!strcmp(cmd, "RETR") && proxy) 139326048Sminshall pswitch(0); 139426048Sminshall if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ 139526048Sminshall if (command("%s %s", cmd2, local) != PRELIM) { 139626048Sminshall pswitch(0); 139726048Sminshall switch (oldtype) { 139826048Sminshall case 0: 139926048Sminshall break; 140026048Sminshall case TYPE_A: 140126048Sminshall setascii(); 140226048Sminshall break; 140326048Sminshall case TYPE_I: 140426048Sminshall setbinary(); 140526048Sminshall break; 140626048Sminshall case TYPE_E: 140726048Sminshall setebcdic(); 140826048Sminshall break; 140926048Sminshall case TYPE_L: 141026048Sminshall settenex(); 141126048Sminshall break; 141226048Sminshall } 141327687Sminshall if (cpend) { 141426048Sminshall char msg[2]; 141526048Sminshall 141626048Sminshall fprintf(cout,"%c%c",IAC,IP); 141726048Sminshall (void) fflush(cout); 141826048Sminshall *msg = IAC; 141926048Sminshall *(msg+1) = DM; 142026448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 142126048Sminshall perror("abort"); 142226048Sminshall fprintf(cout,"ABOR\r\n"); 142326048Sminshall (void) fflush(cout); 142427687Sminshall FD_ZERO(&mask); 142526496Sminshall FD_SET(fileno(cin), &mask); 142627687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 142727687Sminshall if (nfnd < 0) { 142827687Sminshall perror("abort"); 142927687Sminshall } 143026448Slepreau if (ptabflg) 143126048Sminshall code = -1; 143226048Sminshall lostpeer(); 143326048Sminshall } 143426048Sminshall (void) getreply(0); 143526048Sminshall (void) getreply(0); 143626048Sminshall } 143726048Sminshall } 143826048Sminshall pswitch(1); 143926448Slepreau if (ptabflg) 144026048Sminshall code = -1; 144126048Sminshall (void) signal(SIGINT, oldintr); 144226048Sminshall return; 144326048Sminshall } 144427687Sminshall if (cpend) { 144526048Sminshall char msg[2]; 144626048Sminshall 144726048Sminshall fprintf(cout,"%c%c",IAC,IP); 144826048Sminshall (void) fflush(cout); 144926048Sminshall *msg = IAC; 145026048Sminshall *(msg+1) = DM; 145126448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 145226048Sminshall perror("abort"); 145326048Sminshall fprintf(cout,"ABOR\r\n"); 145426048Sminshall (void) fflush(cout); 145527687Sminshall FD_ZERO(&mask); 145626496Sminshall FD_SET(fileno(cin), &mask); 145727687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 145827687Sminshall if (nfnd < 0) { 145927687Sminshall perror("abort"); 146027687Sminshall } 146126448Slepreau if (ptabflg) 146226048Sminshall code = -1; 146326048Sminshall lostpeer(); 146426048Sminshall } 146526048Sminshall (void) getreply(0); 146626048Sminshall (void) getreply(0); 146726048Sminshall } 146826048Sminshall pswitch(!proxy); 146926048Sminshall if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ 147026048Sminshall if (command("%s %s", cmd2, local) != PRELIM) { 147126048Sminshall pswitch(0); 147226048Sminshall switch (oldtype) { 147326048Sminshall case 0: 147426048Sminshall break; 147526048Sminshall case TYPE_A: 147626048Sminshall setascii(); 147726048Sminshall break; 147826048Sminshall case TYPE_I: 147926048Sminshall setbinary(); 148026048Sminshall break; 148126048Sminshall case TYPE_E: 148226048Sminshall setebcdic(); 148326048Sminshall break; 148426048Sminshall case TYPE_L: 148526048Sminshall settenex(); 148626048Sminshall break; 148726048Sminshall } 148827687Sminshall if (cpend) { 148926048Sminshall char msg[2]; 149026048Sminshall 149126048Sminshall fprintf(cout,"%c%c",IAC,IP); 149226048Sminshall (void) fflush(cout); 149326048Sminshall *msg = IAC; 149426048Sminshall *(msg+1) = DM; 149526448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 149626048Sminshall perror("abort"); 149726048Sminshall fprintf(cout,"ABOR\r\n"); 149826048Sminshall (void) fflush(cout); 149927687Sminshall FD_ZERO(&mask); 150026496Sminshall FD_SET(fileno(cin), &mask); 150127687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 150227687Sminshall if (nfnd < 0) { 150327687Sminshall perror("abort"); 150427687Sminshall } 150526448Slepreau if (ptabflg) 150626048Sminshall code = -1; 150726048Sminshall lostpeer(); 150826048Sminshall } 150926048Sminshall (void) getreply(0); 151026048Sminshall (void) getreply(0); 151126048Sminshall } 151226048Sminshall pswitch(1); 151326448Slepreau if (ptabflg) 151426048Sminshall code = -1; 151526048Sminshall (void) signal(SIGINT, oldintr); 151626048Sminshall return; 151726048Sminshall } 151826048Sminshall } 151927687Sminshall if (cpend) { 152026048Sminshall char msg[2]; 152126048Sminshall 152226048Sminshall fprintf(cout,"%c%c",IAC,IP); 152326048Sminshall (void) fflush(cout); 152426048Sminshall *msg = IAC; 152526048Sminshall *(msg+1) = DM; 152626448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 152726048Sminshall perror("abort"); 152826048Sminshall fprintf(cout,"ABOR\r\n"); 152926048Sminshall (void) fflush(cout); 153027687Sminshall FD_ZERO(&mask); 153126496Sminshall FD_SET(fileno(cin), &mask); 153227687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 153327687Sminshall if (nfnd < 0) { 153427687Sminshall perror("abort"); 153527687Sminshall } 153626448Slepreau if (ptabflg) 153726048Sminshall code = -1; 153826048Sminshall lostpeer(); 153926048Sminshall } 154026048Sminshall (void) getreply(0); 154126048Sminshall (void) getreply(0); 154226048Sminshall } 154326048Sminshall pswitch(!proxy); 154426048Sminshall if (cpend) { 154527687Sminshall FD_ZERO(&mask); 154626496Sminshall FD_SET(fileno(cin), &mask); 154727687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 154827687Sminshall if (nfnd < 0) { 154927687Sminshall perror("abort"); 155027687Sminshall } 155126448Slepreau if (ptabflg) 155226048Sminshall code = -1; 155326048Sminshall lostpeer(); 155426048Sminshall } 155526048Sminshall (void) getreply(0); 155626048Sminshall (void) getreply(0); 155726048Sminshall } 155826448Slepreau if (proxy) 155926048Sminshall pswitch(0); 156026048Sminshall switch (oldtype) { 156126048Sminshall case 0: 156226048Sminshall break; 156326048Sminshall case TYPE_A: 156426048Sminshall setascii(); 156526048Sminshall break; 156626048Sminshall case TYPE_I: 156726048Sminshall setbinary(); 156826048Sminshall break; 156926048Sminshall case TYPE_E: 157026048Sminshall setebcdic(); 157126048Sminshall break; 157226048Sminshall case TYPE_L: 157326048Sminshall settenex(); 157426048Sminshall break; 157526048Sminshall } 157626048Sminshall pswitch(1); 157726448Slepreau if (ptabflg) 157826048Sminshall code = -1; 157926048Sminshall (void) signal(SIGINT, oldintr); 158026048Sminshall } 158126048Sminshall 158226048Sminshall reset() 158326048Sminshall { 158426496Sminshall struct fd_set mask; 158526496Sminshall int nfnd = 1; 158626048Sminshall 158727687Sminshall FD_ZERO(&mask); 158830946Scsvsj while (nfnd > 0) { 158926496Sminshall FD_SET(fileno(cin), &mask); 159027687Sminshall if ((nfnd = empty(&mask,0)) < 0) { 159126048Sminshall perror("reset"); 159226048Sminshall code = -1; 159326048Sminshall lostpeer(); 159426048Sminshall } 159527687Sminshall else if (nfnd) { 159626048Sminshall (void) getreply(0); 159726496Sminshall } 159826048Sminshall } 159926048Sminshall } 160026048Sminshall 160126048Sminshall char * 160226048Sminshall gunique(local) 160326048Sminshall char *local; 160426048Sminshall { 160526048Sminshall static char new[MAXPATHLEN]; 160626048Sminshall char *cp = rindex(local, '/'); 160726048Sminshall int d, count=0; 160826048Sminshall char ext = '1'; 160926048Sminshall 161026448Slepreau if (cp) 161126048Sminshall *cp = '\0'; 161226048Sminshall d = access(cp ? local : ".", 2); 161326448Slepreau if (cp) 161426048Sminshall *cp = '/'; 161526048Sminshall if (d < 0) { 161626048Sminshall perror(local); 161726048Sminshall return((char *) 0); 161826048Sminshall } 161926048Sminshall (void) strcpy(new, local); 162026048Sminshall cp = new + strlen(new); 162126048Sminshall *cp++ = '.'; 162226048Sminshall while (!d) { 162326048Sminshall if (++count == 100) { 162426048Sminshall printf("runique: can't find unique file name.\n"); 162526048Sminshall return((char *) 0); 162626048Sminshall } 162726048Sminshall *cp++ = ext; 162826048Sminshall *cp = '\0'; 162926448Slepreau if (ext == '9') 163026048Sminshall ext = '0'; 163126448Slepreau else 163226048Sminshall ext++; 163326448Slepreau if ((d = access(new, 0)) < 0) 163426048Sminshall break; 163526448Slepreau if (ext != '0') 163626048Sminshall cp--; 163726448Slepreau else if (*(cp - 2) == '.') 163826048Sminshall *(cp - 1) = '1'; 163926048Sminshall else { 164026048Sminshall *(cp - 2) = *(cp - 2) + 1; 164126048Sminshall cp--; 164226048Sminshall } 164326048Sminshall } 164426048Sminshall return(new); 164526048Sminshall } 1646