121739Sdist /* 2*36942Skarels * 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*36942Skarels static char sccsid[] = "@(#)ftp.c 5.24.1.1 (Berkeley) 03/01/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; 4810296Ssam struct sockaddr_in myctladdr; 4926496Sminshall uid_t getuid(); 50*36942Skarels #ifdef RESTART 5136935Skarels off_t restart_point = 0; 52*36942Skarels #endif 5310296Ssam 5410296Ssam FILE *cin, *cout; 5510296Ssam FILE *dataconn(); 5610296Ssam 5725904Skarels char * 5810296Ssam hookup(host, port) 5910296Ssam char *host; 6010296Ssam int port; 6110296Ssam { 6225904Skarels register struct hostent *hp = 0; 6327687Sminshall int s,len; 6425904Skarels static char hostnamebuf[80]; 6510296Ssam 6610296Ssam bzero((char *)&hisctladdr, sizeof (hisctladdr)); 6725904Skarels hisctladdr.sin_addr.s_addr = inet_addr(host); 6825904Skarels if (hisctladdr.sin_addr.s_addr != -1) { 6925904Skarels hisctladdr.sin_family = AF_INET; 7036940Skarels (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf)); 7136940Skarels } else { 7225100Sbloom hp = gethostbyname(host); 7325904Skarels if (hp == NULL) { 7435792Sbostic fprintf(stderr, "ftp: %s: ", host); 7535792Sbostic herror((char *)NULL); 7626048Sminshall code = -1; 7726048Sminshall return((char *) 0); 7825904Skarels } 7925904Skarels hisctladdr.sin_family = hp->h_addrtype; 8025904Skarels bcopy(hp->h_addr_list[0], 8125904Skarels (caddr_t)&hisctladdr.sin_addr, hp->h_length); 8236940Skarels (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf)); 8310296Ssam } 8425904Skarels hostname = hostnamebuf; 8525904Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 8610296Ssam if (s < 0) { 8710296Ssam perror("ftp: socket"); 8826048Sminshall code = -1; 8910296Ssam return (0); 9010296Ssam } 9110296Ssam hisctladdr.sin_port = port; 9226496Sminshall while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) { 9325904Skarels if (hp && hp->h_addr_list[1]) { 9425904Skarels int oerrno = errno; 9525904Skarels 9625904Skarels fprintf(stderr, "ftp: connect to address %s: ", 9725904Skarels inet_ntoa(hisctladdr.sin_addr)); 9825904Skarels errno = oerrno; 9926496Sminshall perror((char *) 0); 10025904Skarels hp->h_addr_list++; 10125904Skarels bcopy(hp->h_addr_list[0], 10226048Sminshall (caddr_t)&hisctladdr.sin_addr, hp->h_length); 10326496Sminshall fprintf(stdout, "Trying %s...\n", 10425904Skarels inet_ntoa(hisctladdr.sin_addr)); 10526813Skarels (void) close(s); 10626813Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 10726813Skarels if (s < 0) { 10826813Skarels perror("ftp: socket"); 10926813Skarels code = -1; 11026813Skarels return (0); 11126813Skarels } 11225904Skarels continue; 11325904Skarels } 11410296Ssam perror("ftp: connect"); 11526048Sminshall code = -1; 11610296Ssam goto bad; 11710296Ssam } 11811627Ssam len = sizeof (myctladdr); 11911627Ssam if (getsockname(s, (char *)&myctladdr, &len) < 0) { 12011627Ssam perror("ftp: getsockname"); 12126048Sminshall code = -1; 12210296Ssam goto bad; 12310296Ssam } 12410296Ssam cin = fdopen(s, "r"); 12510296Ssam cout = fdopen(s, "w"); 12611219Ssam if (cin == NULL || cout == NULL) { 12710296Ssam fprintf(stderr, "ftp: fdopen failed.\n"); 12810296Ssam if (cin) 12926496Sminshall (void) fclose(cin); 13010296Ssam if (cout) 13126496Sminshall (void) fclose(cout); 13226048Sminshall code = -1; 13310296Ssam goto bad; 13410296Ssam } 13510296Ssam if (verbose) 13626067Sminshall printf("Connected to %s.\n", hostname); 13727687Sminshall if (getreply(0) > 2) { /* read startup message from server */ 13826048Sminshall if (cin) 13926496Sminshall (void) fclose(cin); 14026048Sminshall if (cout) 14126496Sminshall (void) fclose(cout); 14226048Sminshall code = -1; 14326048Sminshall goto bad; 14426048Sminshall } 14527687Sminshall #ifdef SO_OOBINLINE 14627687Sminshall { 14727687Sminshall int on = 1; 14826048Sminshall 14927687Sminshall if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) 15027687Sminshall < 0 && debug) { 15127687Sminshall perror("ftp: setsockopt"); 15227687Sminshall } 15327687Sminshall } 15427687Sminshall #endif SO_OOBINLINE 15526048Sminshall 15625904Skarels return (hostname); 15710296Ssam bad: 15826496Sminshall (void) close(s); 15925904Skarels return ((char *)0); 16010296Ssam } 16110296Ssam 16225904Skarels login(host) 16325904Skarels char *host; 16410296Ssam { 16526048Sminshall char tmp[80]; 16635659Sbostic char *user, *pass, *acct, *getlogin(), *getpass(); 16726048Sminshall int n, aflag = 0; 16810296Ssam 16926048Sminshall user = pass = acct = 0; 17026048Sminshall if (ruserpass(host, &user, &pass, &acct) < 0) { 17126048Sminshall code = -1; 17226048Sminshall return(0); 17326048Sminshall } 17426048Sminshall if (user == NULL) { 17526048Sminshall char *myname = getlogin(); 17626048Sminshall 17726048Sminshall if (myname == NULL) { 17826048Sminshall struct passwd *pp = getpwuid(getuid()); 17926048Sminshall 18026448Slepreau if (pp != NULL) 18126048Sminshall myname = pp->pw_name; 18226048Sminshall } 18326048Sminshall printf("Name (%s:%s): ", host, myname); 18426048Sminshall (void) fgets(tmp, sizeof(tmp) - 1, stdin); 18526048Sminshall tmp[strlen(tmp) - 1] = '\0'; 18626448Slepreau if (*tmp == '\0') 18726048Sminshall user = myname; 18826448Slepreau else 18926048Sminshall user = tmp; 19026048Sminshall } 19110296Ssam n = command("USER %s", user); 19226048Sminshall if (n == CONTINUE) { 19326448Slepreau if (pass == NULL) 19435659Sbostic pass = getpass("Password:"); 19510296Ssam n = command("PASS %s", pass); 19626048Sminshall } 19710296Ssam if (n == CONTINUE) { 19826048Sminshall aflag++; 19935659Sbostic acct = getpass("Account:"); 20010296Ssam n = command("ACCT %s", acct); 20110296Ssam } 20210296Ssam if (n != COMPLETE) { 20310296Ssam fprintf(stderr, "Login failed.\n"); 20410296Ssam return (0); 20510296Ssam } 20626448Slepreau if (!aflag && acct != NULL) 20726048Sminshall (void) command("ACCT %s", acct); 20826448Slepreau if (proxy) 20926048Sminshall return(1); 21026048Sminshall for (n = 0; n < macnum; ++n) { 21126048Sminshall if (!strcmp("init", macros[n].mac_name)) { 21226496Sminshall (void) strcpy(line, "$init"); 21326048Sminshall makeargv(); 21426048Sminshall domacro(margc, margv); 21526048Sminshall break; 21626048Sminshall } 21726048Sminshall } 21810296Ssam return (1); 21910296Ssam } 22010296Ssam 22126048Sminshall cmdabort() 22226048Sminshall { 22326048Sminshall extern jmp_buf ptabort; 22426048Sminshall 22526048Sminshall printf("\n"); 22626048Sminshall (void) fflush(stdout); 22726048Sminshall abrtflag++; 22826448Slepreau if (ptflag) 22926048Sminshall longjmp(ptabort,1); 23026048Sminshall } 23126048Sminshall 23226496Sminshall /*VARARGS1*/ 23310296Ssam command(fmt, args) 23410296Ssam char *fmt; 23510296Ssam { 23626048Sminshall int r, (*oldintr)(), cmdabort(); 23710296Ssam 23826048Sminshall abrtflag = 0; 23910296Ssam if (debug) { 24010296Ssam printf("---> "); 24110296Ssam _doprnt(fmt, &args, stdout); 24210296Ssam printf("\n"); 24310296Ssam (void) fflush(stdout); 24410296Ssam } 24511219Ssam if (cout == NULL) { 24611219Ssam perror ("No control connection for command"); 24726048Sminshall code = -1; 24811219Ssam return (0); 24911219Ssam } 25026048Sminshall oldintr = signal(SIGINT,cmdabort); 25110296Ssam _doprnt(fmt, &args, cout); 25210296Ssam fprintf(cout, "\r\n"); 25310296Ssam (void) fflush(cout); 25426048Sminshall cpend = 1; 25526048Sminshall r = getreply(!strcmp(fmt, "QUIT")); 25626448Slepreau if (abrtflag && oldintr != SIG_IGN) 25726048Sminshall (*oldintr)(); 25826048Sminshall (void) signal(SIGINT, oldintr); 25926048Sminshall return(r); 26010296Ssam } 26110296Ssam 26236935Skarels char reply_string[BUFSIZ]; 26336935Skarels 26410296Ssam #include <ctype.h> 26510296Ssam 26610296Ssam getreply(expecteof) 26710296Ssam int expecteof; 26810296Ssam { 26911219Ssam register int c, n; 27026048Sminshall register int dig; 27136935Skarels register char *cp; 27226048Sminshall int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort(); 27326048Sminshall int pflag = 0; 27426048Sminshall char *pt = pasv; 27510296Ssam 27636935Skarels cp = reply_string; 27726048Sminshall oldintr = signal(SIGINT,cmdabort); 27810296Ssam for (;;) { 27910296Ssam dig = n = code = 0; 28010296Ssam while ((c = getc(cin)) != '\n') { 28127687Sminshall if (c == IAC) { /* handle telnet commands */ 28227687Sminshall switch (c = getc(cin)) { 28327687Sminshall case WILL: 28427687Sminshall case WONT: 28527687Sminshall c = getc(cin); 28636940Skarels fprintf(cout, "%c%c%c",IAC,DONT,c); 28727687Sminshall (void) fflush(cout); 28827687Sminshall break; 28927687Sminshall case DO: 29027687Sminshall case DONT: 29127687Sminshall c = getc(cin); 29236940Skarels fprintf(cout, "%c%c%c",IAC,WONT,c); 29327687Sminshall (void) fflush(cout); 29427687Sminshall break; 29527687Sminshall default: 29627687Sminshall break; 29727687Sminshall } 29827687Sminshall continue; 29927687Sminshall } 30010296Ssam dig++; 30110296Ssam if (c == EOF) { 30226048Sminshall if (expecteof) { 30326048Sminshall (void) signal(SIGINT,oldintr); 30426048Sminshall code = 221; 30510296Ssam return (0); 30626048Sminshall } 30710296Ssam lostpeer(); 30826048Sminshall if (verbose) { 30926048Sminshall printf("421 Service not available, remote server has closed connection\n"); 31026048Sminshall (void) fflush(stdout); 31126048Sminshall } 31233772Scsvsj code = 421; 31333772Scsvsj return(4); 31410296Ssam } 31526048Sminshall if (c != '\r' && (verbose > 0 || 31626048Sminshall (verbose > -1 && n == '5' && dig > 4))) { 31726448Slepreau if (proxflag && 31826448Slepreau (dig == 1 || dig == 5 && verbose == 0)) 31926048Sminshall printf("%s:",hostname); 32026496Sminshall (void) putchar(c); 32126048Sminshall } 32210296Ssam if (dig < 4 && isdigit(c)) 32310296Ssam code = code * 10 + (c - '0'); 32426448Slepreau if (!pflag && code == 227) 32526048Sminshall pflag = 1; 32626448Slepreau if (dig > 4 && pflag == 1 && isdigit(c)) 32726048Sminshall pflag = 2; 32826048Sminshall if (pflag == 2) { 32926448Slepreau if (c != '\r' && c != ')') 33026048Sminshall *pt++ = c; 33126048Sminshall else { 33226048Sminshall *pt = '\0'; 33326048Sminshall pflag = 3; 33426048Sminshall } 33526048Sminshall } 33626048Sminshall if (dig == 4 && c == '-') { 33726448Slepreau if (continuation) 33826048Sminshall code = 0; 33910296Ssam continuation++; 34026048Sminshall } 34110296Ssam if (n == 0) 34210296Ssam n = c; 34336935Skarels *cp++ = c; 34410296Ssam } 34526048Sminshall if (verbose > 0 || verbose > -1 && n == '5') { 34626496Sminshall (void) putchar(c); 34711346Ssam (void) fflush (stdout); 34811346Ssam } 34910296Ssam if (continuation && code != originalcode) { 35010296Ssam if (originalcode == 0) 35110296Ssam originalcode = code; 35210296Ssam continue; 35310296Ssam } 35436935Skarels *cp = '\0'; 35526448Slepreau if (n != '1') 35626048Sminshall cpend = 0; 35726048Sminshall (void) signal(SIGINT,oldintr); 35826448Slepreau if (code == 421 || originalcode == 421) 35926048Sminshall lostpeer(); 36026448Slepreau if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) 36126048Sminshall (*oldintr)(); 36225907Smckusick return (n - '0'); 36310296Ssam } 36410296Ssam } 36510296Ssam 36626048Sminshall empty(mask, sec) 36727687Sminshall struct fd_set *mask; 36826048Sminshall int sec; 36926048Sminshall { 37026048Sminshall struct timeval t; 37126048Sminshall 37226048Sminshall t.tv_sec = (long) sec; 37326048Sminshall t.tv_usec = 0; 37427687Sminshall return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t)); 37526048Sminshall } 37626048Sminshall 37710296Ssam jmp_buf sendabort; 37810296Ssam 37910296Ssam abortsend() 38010296Ssam { 38110296Ssam 38226048Sminshall mflag = 0; 38326048Sminshall abrtflag = 0; 38426048Sminshall printf("\nsend aborted\n"); 38526048Sminshall (void) fflush(stdout); 38610296Ssam longjmp(sendabort, 1); 38710296Ssam } 38810296Ssam 38936940Skarels #define HASHBYTES 1024 39036940Skarels 39110296Ssam sendrequest(cmd, local, remote) 39210296Ssam char *cmd, *local, *remote; 39310296Ssam { 39435659Sbostic FILE *fin, *dout = 0, *popen(); 39535659Sbostic int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); 39626048Sminshall int abortsend(); 397*36942Skarels char buf[BUFSIZ], *bufp; 39836940Skarels long bytes = 0, hashbytes = HASHBYTES; 39911346Ssam register int c, d; 40010296Ssam struct stat st; 40110296Ssam struct timeval start, stop; 40236935Skarels char *mode; 40310296Ssam 40426048Sminshall if (proxy) { 40526048Sminshall proxtrans(cmd, local, remote); 40626048Sminshall return; 40726048Sminshall } 40810296Ssam closefunc = NULL; 40926048Sminshall oldintr = NULL; 41026048Sminshall oldintp = NULL; 41136935Skarels mode = "w"; 41226048Sminshall if (setjmp(sendabort)) { 41326048Sminshall while (cpend) { 41426048Sminshall (void) getreply(0); 41526048Sminshall } 41626048Sminshall if (data >= 0) { 41726048Sminshall (void) close(data); 41826048Sminshall data = -1; 41926048Sminshall } 42026448Slepreau if (oldintr) 42126048Sminshall (void) signal(SIGINT,oldintr); 42226448Slepreau if (oldintp) 42326048Sminshall (void) signal(SIGPIPE,oldintp); 42426048Sminshall code = -1; 42526048Sminshall return; 42626048Sminshall } 42710296Ssam oldintr = signal(SIGINT, abortsend); 42810296Ssam if (strcmp(local, "-") == 0) 42910296Ssam fin = stdin; 43010296Ssam else if (*local == '|') { 43126048Sminshall oldintp = signal(SIGPIPE,SIG_IGN); 43235659Sbostic fin = popen(local + 1, "r"); 43310296Ssam if (fin == NULL) { 43426048Sminshall perror(local + 1); 43526048Sminshall (void) signal(SIGINT, oldintr); 43626048Sminshall (void) signal(SIGPIPE, oldintp); 43726048Sminshall code = -1; 43826048Sminshall return; 43910296Ssam } 44035659Sbostic closefunc = pclose; 44110296Ssam } else { 44210296Ssam fin = fopen(local, "r"); 44310296Ssam if (fin == NULL) { 44410296Ssam perror(local); 44526048Sminshall (void) signal(SIGINT, oldintr); 44626048Sminshall code = -1; 44726048Sminshall return; 44810296Ssam } 44910296Ssam closefunc = fclose; 45010296Ssam if (fstat(fileno(fin), &st) < 0 || 45110296Ssam (st.st_mode&S_IFMT) != S_IFREG) { 45226496Sminshall fprintf(stdout, "%s: not a plain file.\n", local); 45326048Sminshall (void) signal(SIGINT, oldintr); 45436935Skarels fclose(fin); 45526048Sminshall code = -1; 45626048Sminshall return; 45710296Ssam } 45810296Ssam } 45926048Sminshall if (initconn()) { 46026048Sminshall (void) signal(SIGINT, oldintr); 46126448Slepreau if (oldintp) 46226048Sminshall (void) signal(SIGPIPE, oldintp); 46326048Sminshall code = -1; 46436935Skarels if (closefunc != NULL) 46536935Skarels (*closefunc)(fin); 46626048Sminshall return; 46726048Sminshall } 46826448Slepreau if (setjmp(sendabort)) 46926048Sminshall goto abort; 47036935Skarels 471*36942Skarels #ifdef RESTART 472*36942Skarels if (restart_point && 473*36942Skarels (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { 474*36942Skarels if (fseek(fin, (long) restart_point, 0) < 0) { 475*36942Skarels perror(local); 47636935Skarels restart_point = 0; 477*36942Skarels if (closefunc != NULL) 478*36942Skarels (*closefunc)(fin); 479*36942Skarels return; 48036935Skarels } 481*36942Skarels if (command("REST %ld", (long) restart_point) 482*36942Skarels != CONTINUE) { 483*36942Skarels restart_point = 0; 484*36942Skarels if (closefunc != NULL) 485*36942Skarels (*closefunc)(fin); 486*36942Skarels return; 487*36942Skarels } 488*36942Skarels restart_point = 0; 489*36942Skarels mode = "r+w"; 49036935Skarels } 491*36942Skarels #endif 49210296Ssam if (remote) { 49326048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 49426048Sminshall (void) signal(SIGINT, oldintr); 49526448Slepreau if (oldintp) 49626048Sminshall (void) signal(SIGPIPE, oldintp); 49736935Skarels if (closefunc != NULL) 49836935Skarels (*closefunc)(fin); 49926048Sminshall return; 50026048Sminshall } 50110296Ssam } else 50226048Sminshall if (command("%s", cmd) != PRELIM) { 50326048Sminshall (void) signal(SIGINT, oldintr); 50426448Slepreau if (oldintp) 50526048Sminshall (void) signal(SIGPIPE, oldintp); 50636935Skarels if (closefunc != NULL) 50736935Skarels (*closefunc)(fin); 50826048Sminshall return; 50926048Sminshall } 51036935Skarels dout = dataconn(mode); 51126448Slepreau if (dout == NULL) 51226048Sminshall goto abort; 51326496Sminshall (void) gettimeofday(&start, (struct timezone *)0); 51436935Skarels oldintp = signal(SIGPIPE, SIG_IGN); 51511219Ssam switch (type) { 51611219Ssam 51711219Ssam case TYPE_I: 51811219Ssam case TYPE_L: 51911346Ssam errno = d = 0; 520*36942Skarels while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) { 52111219Ssam bytes += c; 522*36942Skarels for (bufp = buf; c > 0; c -= d, bufp += d) 523*36942Skarels if ((d = write(fileno(dout), bufp, c)) <= 0) 524*36942Skarels break; 52511651Ssam if (hash) { 52636940Skarels while (bytes >= hashbytes) { 52736940Skarels (void) putchar('#'); 52836940Skarels hashbytes += HASHBYTES; 52936940Skarels } 53026496Sminshall (void) fflush(stdout); 53111651Ssam } 53211219Ssam } 53313213Ssam if (hash && bytes > 0) { 53436940Skarels if (bytes < HASHBYTES) 53536940Skarels (void) putchar('#'); 53626496Sminshall (void) putchar('\n'); 53726496Sminshall (void) fflush(stdout); 53811651Ssam } 53911219Ssam if (c < 0) 54011219Ssam perror(local); 541*36942Skarels if (d <= 0) { 542*36942Skarels if (d == 0) 543*36942Skarels fprintf(stderr, "netout: write returned 0?\n"); 544*36942Skarels else if (errno != EPIPE) 54536935Skarels perror("netout"); 54636935Skarels bytes = -1; 54736935Skarels } 54811219Ssam break; 54911219Ssam 55011219Ssam case TYPE_A: 55111219Ssam while ((c = getc(fin)) != EOF) { 55211219Ssam if (c == '\n') { 55311651Ssam while (hash && (bytes >= hashbytes)) { 55426496Sminshall (void) putchar('#'); 55526496Sminshall (void) fflush(stdout); 55636940Skarels hashbytes += HASHBYTES; 55711651Ssam } 55811219Ssam if (ferror(dout)) 55911219Ssam break; 56026496Sminshall (void) putc('\r', dout); 56111219Ssam bytes++; 56211219Ssam } 56326496Sminshall (void) putc(c, dout); 56411219Ssam bytes++; 56526048Sminshall /* if (c == '\r') { */ 56626496Sminshall /* (void) putc('\0', dout); /* this violates rfc */ 56726048Sminshall /* bytes++; */ 56826048Sminshall /* } */ 56911219Ssam } 57011651Ssam if (hash) { 57113213Ssam if (bytes < hashbytes) 57226496Sminshall (void) putchar('#'); 57326496Sminshall (void) putchar('\n'); 57426496Sminshall (void) fflush(stdout); 57511651Ssam } 57611219Ssam if (ferror(fin)) 57711219Ssam perror(local); 57836935Skarels if (ferror(dout)) { 57936935Skarels if (errno != EPIPE) 58036935Skarels perror("netout"); 58136935Skarels bytes = -1; 58236935Skarels } 58311219Ssam break; 58410296Ssam } 58526496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 58610296Ssam if (closefunc != NULL) 58726048Sminshall (*closefunc)(fin); 58810296Ssam (void) fclose(dout); 58926048Sminshall (void) getreply(0); 59026048Sminshall (void) signal(SIGINT, oldintr); 59136935Skarels if (oldintp) 59236935Skarels (void) signal(SIGPIPE, oldintp); 59335699Sbostic if (bytes > 0) 59426048Sminshall ptransfer("sent", bytes, &start, &stop, local, remote); 59510296Ssam return; 59626048Sminshall abort: 59726496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 59826048Sminshall (void) signal(SIGINT, oldintr); 59926448Slepreau if (oldintp) 60026048Sminshall (void) signal(SIGPIPE, oldintp); 60126048Sminshall if (!cpend) { 60226048Sminshall code = -1; 60326048Sminshall return; 60426048Sminshall } 60526048Sminshall if (data >= 0) { 60626048Sminshall (void) close(data); 60726048Sminshall data = -1; 60826048Sminshall } 60926448Slepreau if (dout) 61026048Sminshall (void) fclose(dout); 61126048Sminshall (void) getreply(0); 61226048Sminshall code = -1; 61310296Ssam if (closefunc != NULL && fin != NULL) 61426048Sminshall (*closefunc)(fin); 61535699Sbostic if (bytes > 0) 61626048Sminshall ptransfer("sent", bytes, &start, &stop, local, remote); 61710296Ssam } 61810296Ssam 61910296Ssam jmp_buf recvabort; 62010296Ssam 62110296Ssam abortrecv() 62210296Ssam { 62310296Ssam 62426048Sminshall mflag = 0; 62526048Sminshall abrtflag = 0; 62626048Sminshall printf("\n"); 62726048Sminshall (void) fflush(stdout); 62810296Ssam longjmp(recvabort, 1); 62910296Ssam } 63010296Ssam 63111651Ssam recvrequest(cmd, local, remote, mode) 63211651Ssam char *cmd, *local, *remote, *mode; 63310296Ssam { 63435659Sbostic FILE *fout, *din = 0, *popen(); 63535659Sbostic int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); 63636935Skarels int abortrecv(), oldverbose, oldtype = 0, is_retr, tcrflag, nfnd; 637*36942Skarels char *buf, *bufp, *gunique(), msg; 63836940Skarels static int bufsize; 63936940Skarels long bytes = 0, hashbytes = HASHBYTES; 64026496Sminshall struct fd_set mask; 64111346Ssam register int c, d; 64210296Ssam struct timeval start, stop; 64336940Skarels struct stat st; 64436940Skarels extern char *malloc(); 64510296Ssam 64636935Skarels is_retr = strcmp(cmd, "RETR") == 0; 64736935Skarels if (proxy && is_retr) { 64826048Sminshall proxtrans(cmd, local, remote); 64926048Sminshall return; 65026048Sminshall } 65110296Ssam closefunc = NULL; 65226048Sminshall oldintr = NULL; 65326048Sminshall oldintp = NULL; 65436935Skarels tcrflag = !crflag && is_retr; 65526048Sminshall if (setjmp(recvabort)) { 65626048Sminshall while (cpend) { 65726048Sminshall (void) getreply(0); 65826048Sminshall } 65926048Sminshall if (data >= 0) { 66026048Sminshall (void) close(data); 66126048Sminshall data = -1; 66226048Sminshall } 66326448Slepreau if (oldintr) 66426048Sminshall (void) signal(SIGINT, oldintr); 66526048Sminshall code = -1; 66626048Sminshall return; 66726048Sminshall } 66810296Ssam oldintr = signal(SIGINT, abortrecv); 66926048Sminshall if (strcmp(local, "-") && *local != '|') { 67010296Ssam if (access(local, 2) < 0) { 67126048Sminshall char *dir = rindex(local, '/'); 67210296Ssam 67326048Sminshall if (errno != ENOENT && errno != EACCES) { 67410296Ssam perror(local); 67526048Sminshall (void) signal(SIGINT, oldintr); 67626048Sminshall code = -1; 67726048Sminshall return; 67810296Ssam } 67926048Sminshall if (dir != NULL) 68026048Sminshall *dir = 0; 68126048Sminshall d = access(dir ? local : ".", 2); 68226048Sminshall if (dir != NULL) 68326048Sminshall *dir = '/'; 68426048Sminshall if (d < 0) { 68526048Sminshall perror(local); 68626048Sminshall (void) signal(SIGINT, oldintr); 68726048Sminshall code = -1; 68826048Sminshall return; 68926048Sminshall } 69026048Sminshall if (!runique && errno == EACCES && 69136935Skarels chmod(local, 0600) < 0) { 69226048Sminshall perror(local); 69326048Sminshall (void) signal(SIGINT, oldintr); 69426048Sminshall code = -1; 69526048Sminshall return; 69626048Sminshall } 69726048Sminshall if (runique && errno == EACCES && 69826048Sminshall (local = gunique(local)) == NULL) { 69926048Sminshall (void) signal(SIGINT, oldintr); 70026048Sminshall code = -1; 70126048Sminshall return; 70226048Sminshall } 70310296Ssam } 70426048Sminshall else if (runique && (local = gunique(local)) == NULL) { 70526048Sminshall (void) signal(SIGINT, oldintr); 70626048Sminshall code = -1; 70726048Sminshall return; 70826048Sminshall } 70926048Sminshall } 71026048Sminshall if (initconn()) { 71126048Sminshall (void) signal(SIGINT, oldintr); 71226048Sminshall code = -1; 71326048Sminshall return; 71426048Sminshall } 71526448Slepreau if (setjmp(recvabort)) 71626048Sminshall goto abort; 71736935Skarels if (!is_retr) { 71836935Skarels if (type != TYPE_A) { 71936935Skarels oldtype = type; 72036935Skarels oldverbose = verbose; 72136935Skarels if (!debug) 72236935Skarels verbose = 0; 72336935Skarels setascii(); 72436935Skarels verbose = oldverbose; 72536935Skarels } 726*36942Skarels #ifdef RESTART 72736935Skarels } else if (restart_point) { 72836935Skarels if (command("REST %ld", (long) restart_point) != CONTINUE) 72936935Skarels return; 730*36942Skarels #endif 73126048Sminshall } 73210296Ssam if (remote) { 73326048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 73426048Sminshall (void) signal(SIGINT, oldintr); 73526048Sminshall if (oldtype) { 73626448Slepreau if (!debug) 73726048Sminshall verbose = 0; 73826048Sminshall switch (oldtype) { 73926048Sminshall case TYPE_I: 74026048Sminshall setbinary(); 74126048Sminshall break; 74226048Sminshall case TYPE_E: 74326048Sminshall setebcdic(); 74426048Sminshall break; 74526048Sminshall case TYPE_L: 74626048Sminshall settenex(); 74726048Sminshall break; 748*36942Skarels } 74926048Sminshall verbose = oldverbose; 75026048Sminshall } 75126048Sminshall return; 75226048Sminshall } 75326048Sminshall } else { 75426048Sminshall if (command("%s", cmd) != PRELIM) { 75526048Sminshall (void) signal(SIGINT, oldintr); 75626048Sminshall if (oldtype) { 75726448Slepreau if (!debug) 75826048Sminshall verbose = 0; 75926048Sminshall switch (oldtype) { 76026048Sminshall case TYPE_I: 76126048Sminshall setbinary(); 76226048Sminshall break; 76326048Sminshall case TYPE_E: 76426048Sminshall setebcdic(); 76526048Sminshall break; 76626048Sminshall case TYPE_L: 76726048Sminshall settenex(); 76826048Sminshall break; 769*36942Skarels } 77026048Sminshall verbose = oldverbose; 77126048Sminshall } 77226048Sminshall return; 77326048Sminshall } 77426048Sminshall } 77526048Sminshall din = dataconn("r"); 77626048Sminshall if (din == NULL) 77726048Sminshall goto abort; 77826448Slepreau if (strcmp(local, "-") == 0) 77910296Ssam fout = stdout; 78010296Ssam else if (*local == '|') { 78126048Sminshall oldintp = signal(SIGPIPE, SIG_IGN); 78235659Sbostic fout = popen(local + 1, "w"); 78326048Sminshall if (fout == NULL) { 78426048Sminshall perror(local+1); 78526048Sminshall goto abort; 78626048Sminshall } 78735659Sbostic closefunc = pclose; 78836940Skarels } else { 78911651Ssam fout = fopen(local, mode); 79026048Sminshall if (fout == NULL) { 79126048Sminshall perror(local); 79226048Sminshall goto abort; 79326048Sminshall } 79410296Ssam closefunc = fclose; 79510296Ssam } 79636940Skarels if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) 79736940Skarels st.st_blksize = BUFSIZ; 79836940Skarels if (st.st_blksize > bufsize) { 79936940Skarels if (buf) 80036940Skarels (void) free(buf); 80136940Skarels buf = malloc(st.st_blksize); 80236940Skarels if (buf == NULL) { 80336940Skarels perror("malloc"); 80436940Skarels goto abort; 80536940Skarels } 80636940Skarels bufsize = st.st_blksize; 80736940Skarels } 80826496Sminshall (void) gettimeofday(&start, (struct timezone *)0); 80911219Ssam switch (type) { 81011219Ssam 81111219Ssam case TYPE_I: 81211219Ssam case TYPE_L: 813*36942Skarels #ifdef RESTART 81436935Skarels if (restart_point && 81536935Skarels lseek(fileno(fout), (long) restart_point, L_SET) < 0) { 81636935Skarels perror(local); 81736935Skarels if (closefunc != NULL) 81836935Skarels (*closefunc)(fout); 81936935Skarels return; 82036935Skarels } 821*36942Skarels #endif 82211346Ssam errno = d = 0; 82336940Skarels while ((c = read(fileno(din), buf, bufsize)) > 0) { 824*36942Skarels if ((d = write(fileno(fout), bufp, c)) != c) 82511219Ssam break; 82611219Ssam bytes += c; 82711651Ssam if (hash) { 82836940Skarels while (bytes >= hashbytes) { 82936940Skarels (void) putchar('#'); 83036940Skarels hashbytes += HASHBYTES; 83136940Skarels } 83226496Sminshall (void) fflush(stdout); 83311651Ssam } 83411219Ssam } 83513213Ssam if (hash && bytes > 0) { 83636940Skarels if (bytes < HASHBYTES) 83736940Skarels (void) putchar('#'); 83826496Sminshall (void) putchar('\n'); 83926496Sminshall (void) fflush(stdout); 84011651Ssam } 84136935Skarels if (c < 0) { 84236935Skarels if (errno != EPIPE) 84336935Skarels perror("netin"); 84436935Skarels bytes = -1; 84536935Skarels } 846*36942Skarels if (d < c) { 847*36942Skarels if (d < 0) 848*36942Skarels perror(local); 849*36942Skarels else 850*36942Skarels fprintf(stderr, "%s: short write\n", local); 851*36942Skarels } 85211219Ssam break; 85311219Ssam 85411219Ssam case TYPE_A: 855*36942Skarels #ifdef RESTART 85636935Skarels if (restart_point) { 85736935Skarels register int i, n, c; 85836940Skarels 85936935Skarels if (fseek(fout, 0L, L_SET) < 0) 86036935Skarels goto done; 86136935Skarels n = restart_point; 86236935Skarels i = 0; 86336940Skarels while (i++ < n) { 86436935Skarels if ((c=getc(fout)) == EOF) 86536935Skarels goto done; 86636935Skarels if (c == '\n') 86736935Skarels i++; 868*36942Skarels } 86936935Skarels if (fseek(fout, 0L, L_INCR) < 0) { 87036935Skarels done: 87136935Skarels perror(local); 87236935Skarels if (closefunc != NULL) 87336935Skarels (*closefunc)(fout); 87436935Skarels return; 87536935Skarels } 87636935Skarels } 877*36942Skarels #endif 87811219Ssam while ((c = getc(din)) != EOF) { 87927749Sminshall while (c == '\r') { 88011651Ssam while (hash && (bytes >= hashbytes)) { 88126496Sminshall (void) putchar('#'); 88226496Sminshall (void) fflush(stdout); 88336940Skarels hashbytes += HASHBYTES; 88411651Ssam } 88510296Ssam bytes++; 88626048Sminshall if ((c = getc(din)) != '\n' || tcrflag) { 88736940Skarels if (ferror(fout)) 88836940Skarels goto break2; 88936940Skarels (void) putc('\r', fout); 890*36942Skarels if (c == '\0') { 891*36942Skarels bytes++; 89236940Skarels goto contin2; 893*36942Skarels } 894*36942Skarels if (c == EOF) 895*36942Skarels goto contin2; 89611219Ssam } 89711219Ssam } 89836940Skarels (void) putc(c, fout); 89911219Ssam bytes++; 90036940Skarels contin2: ; 90110296Ssam } 90236940Skarels break2: 90311651Ssam if (hash) { 90413213Ssam if (bytes < hashbytes) 90526496Sminshall (void) putchar('#'); 90626496Sminshall (void) putchar('\n'); 90726496Sminshall (void) fflush(stdout); 90811651Ssam } 90936940Skarels if (ferror(din)){ 91036935Skarels if (errno != EPIPE) 91136935Skarels perror ("netin"); 91236935Skarels bytes = -1; 91336935Skarels } 91436940Skarels if (ferror(fout)) 91511219Ssam perror (local); 91611219Ssam break; 91710296Ssam } 91826448Slepreau if (closefunc != NULL) 91926048Sminshall (*closefunc)(fout); 92026496Sminshall (void) signal(SIGINT, oldintr); 92126448Slepreau if (oldintp) 92226048Sminshall (void) signal(SIGPIPE, oldintp); 92326496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 92410296Ssam (void) fclose(din); 92526048Sminshall (void) getreply(0); 92636935Skarels if (bytes > 0 && is_retr) 92726048Sminshall ptransfer("received", bytes, &start, &stop, local, remote); 92826048Sminshall if (oldtype) { 92926448Slepreau if (!debug) 93026048Sminshall verbose = 0; 93126048Sminshall switch (oldtype) { 93226048Sminshall case TYPE_I: 93326048Sminshall setbinary(); 93426048Sminshall break; 93526048Sminshall case TYPE_E: 93626048Sminshall setebcdic(); 93726048Sminshall break; 93826048Sminshall case TYPE_L: 93926048Sminshall settenex(); 94026048Sminshall break; 94126048Sminshall } 94226048Sminshall verbose = oldverbose; 94326048Sminshall } 94426048Sminshall return; 94526048Sminshall abort: 94626048Sminshall 94727687Sminshall /* abort using RFC959 recommended IP,SYNC sequence */ 94826048Sminshall 94926496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 95026448Slepreau if (oldintp) 95126048Sminshall (void) signal(SIGPIPE, oldintr); 95226048Sminshall (void) signal(SIGINT,SIG_IGN); 95326048Sminshall if (oldtype) { 95426448Slepreau if (!debug) 95526048Sminshall verbose = 0; 95626048Sminshall switch (oldtype) { 95726048Sminshall case TYPE_I: 95826048Sminshall setbinary(); 95926048Sminshall break; 96026048Sminshall case TYPE_E: 96126048Sminshall setebcdic(); 96226048Sminshall break; 96326048Sminshall case TYPE_L: 96426048Sminshall settenex(); 96526048Sminshall break; 96626048Sminshall } 96726048Sminshall verbose = oldverbose; 96826048Sminshall } 96926048Sminshall if (!cpend) { 97026048Sminshall code = -1; 97126048Sminshall (void) signal(SIGINT,oldintr); 97226048Sminshall return; 97326048Sminshall } 97426048Sminshall 97527687Sminshall fprintf(cout,"%c%c",IAC,IP); 97627687Sminshall (void) fflush(cout); 97727687Sminshall msg = IAC; 97827687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */ 97927687Sminshall /* after urgent byte rather than before as now is protocol */ 98027687Sminshall if (send(fileno(cout),&msg,1,MSG_OOB) != 1) { 98127687Sminshall perror("abort"); 98226048Sminshall } 98327687Sminshall fprintf(cout,"%cABOR\r\n",DM); 98426048Sminshall (void) fflush(cout); 98527687Sminshall FD_ZERO(&mask); 98626496Sminshall FD_SET(fileno(cin), &mask); 98726496Sminshall if (din) { 98826496Sminshall FD_SET(fileno(din), &mask); 98926496Sminshall } 99027687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 99127687Sminshall if (nfnd < 0) { 99227687Sminshall perror("abort"); 99327687Sminshall } 99426048Sminshall code = -1; 99526048Sminshall lostpeer(); 99626048Sminshall } 99726496Sminshall if (din && FD_ISSET(fileno(din), &mask)) { 99836940Skarels while ((c = read(fileno(din), buf, bufsize)) > 0) 99926448Slepreau ; 100026496Sminshall } 100127687Sminshall if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */ 100226048Sminshall if (data >= 0) { 100326496Sminshall (void) close(data); 100426048Sminshall data = -1; 100526048Sminshall } 100625907Smckusick (void) getreply(0); 100725907Smckusick } 100826048Sminshall (void) getreply(0); 100926048Sminshall code = -1; 101026048Sminshall if (data >= 0) { 101126048Sminshall (void) close(data); 101226048Sminshall data = -1; 101326048Sminshall } 101426448Slepreau if (closefunc != NULL && fout != NULL) 101526048Sminshall (*closefunc)(fout); 101626448Slepreau if (din) 101726048Sminshall (void) fclose(din); 101835699Sbostic if (bytes > 0) 101926048Sminshall ptransfer("received", bytes, &start, &stop, local, remote); 102026048Sminshall (void) signal(SIGINT,oldintr); 102110296Ssam } 102210296Ssam 102310296Ssam /* 102410296Ssam * Need to start a listen on the data channel 102510296Ssam * before we send the command, otherwise the 102610296Ssam * server's connect may fail. 102710296Ssam */ 102833224Sbostic int sendport = -1; 102911651Ssam 103010296Ssam initconn() 103110296Ssam { 103210296Ssam register char *p, *a; 103326048Sminshall int result, len, tmpno = 0; 103426993Skarels int on = 1; 103510296Ssam 103611651Ssam noport: 103710296Ssam data_addr = myctladdr; 103811651Ssam if (sendport) 103911651Ssam data_addr.sin_port = 0; /* let system pick one */ 104011651Ssam if (data != -1) 104111651Ssam (void) close (data); 104218287Sralph data = socket(AF_INET, SOCK_STREAM, 0); 104310296Ssam if (data < 0) { 104410296Ssam perror("ftp: socket"); 104526448Slepreau if (tmpno) 104626048Sminshall sendport = 1; 104710296Ssam return (1); 104810296Ssam } 104912397Ssam if (!sendport) 105027687Sminshall if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { 105133224Sbostic perror("ftp: setsockopt (reuse address)"); 105212397Ssam goto bad; 105312397Ssam } 105426496Sminshall if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { 105510296Ssam perror("ftp: bind"); 105610296Ssam goto bad; 105710296Ssam } 105810296Ssam if (options & SO_DEBUG && 105927687Sminshall setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) 106010296Ssam perror("ftp: setsockopt (ignored)"); 106111627Ssam len = sizeof (data_addr); 106211627Ssam if (getsockname(data, (char *)&data_addr, &len) < 0) { 106311627Ssam perror("ftp: getsockname"); 106410296Ssam goto bad; 106510296Ssam } 106626448Slepreau if (listen(data, 1) < 0) 106710296Ssam perror("ftp: listen"); 106811651Ssam if (sendport) { 106911651Ssam a = (char *)&data_addr.sin_addr; 107011651Ssam p = (char *)&data_addr.sin_port; 107110296Ssam #define UC(b) (((int)b)&0xff) 107211651Ssam result = 107311651Ssam command("PORT %d,%d,%d,%d,%d,%d", 107411651Ssam UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 107511651Ssam UC(p[0]), UC(p[1])); 107611651Ssam if (result == ERROR && sendport == -1) { 107711651Ssam sendport = 0; 107826048Sminshall tmpno = 1; 107911651Ssam goto noport; 108011651Ssam } 108111651Ssam return (result != COMPLETE); 108211651Ssam } 108326448Slepreau if (tmpno) 108426048Sminshall sendport = 1; 108511651Ssam return (0); 108610296Ssam bad: 108710296Ssam (void) close(data), data = -1; 108826448Slepreau if (tmpno) 108926048Sminshall sendport = 1; 109010296Ssam return (1); 109110296Ssam } 109210296Ssam 109310296Ssam FILE * 109410296Ssam dataconn(mode) 109510296Ssam char *mode; 109610296Ssam { 109710296Ssam struct sockaddr_in from; 109810296Ssam int s, fromlen = sizeof (from); 109910296Ssam 110026496Sminshall s = accept(data, (struct sockaddr *) &from, &fromlen); 110110296Ssam if (s < 0) { 110210296Ssam perror("ftp: accept"); 110310296Ssam (void) close(data), data = -1; 110410296Ssam return (NULL); 110510296Ssam } 110610296Ssam (void) close(data); 110710296Ssam data = s; 110810296Ssam return (fdopen(data, mode)); 110910296Ssam } 111010296Ssam 111126048Sminshall ptransfer(direction, bytes, t0, t1, local, remote) 111226048Sminshall char *direction, *local, *remote; 111311651Ssam long bytes; 111410296Ssam struct timeval *t0, *t1; 111510296Ssam { 111610296Ssam struct timeval td; 111716437Sleres float s, bs; 111810296Ssam 111935699Sbostic if (verbose) { 112035699Sbostic tvsub(&td, t1, t0); 112135699Sbostic s = td.tv_sec + (td.tv_usec / 1000000.); 112210296Ssam #define nz(x) ((x) == 0 ? 1 : (x)) 112335699Sbostic bs = bytes / nz(s); 112435699Sbostic printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n", 112535699Sbostic bytes, direction, s, bs / 1024.); 112635699Sbostic } else { 112735699Sbostic if (local && *local != '-') 112835699Sbostic printf("local: %s ", local); 112935699Sbostic if (remote) 113035699Sbostic printf("remote: %s\n", remote); 113135699Sbostic } 113210296Ssam } 113310296Ssam 113426496Sminshall /*tvadd(tsum, t0) 113510296Ssam struct timeval *tsum, *t0; 113610296Ssam { 113710296Ssam 113810296Ssam tsum->tv_sec += t0->tv_sec; 113910296Ssam tsum->tv_usec += t0->tv_usec; 114010296Ssam if (tsum->tv_usec > 1000000) 114110296Ssam tsum->tv_sec++, tsum->tv_usec -= 1000000; 114226496Sminshall } */ 114310296Ssam 114410296Ssam tvsub(tdiff, t1, t0) 114510296Ssam struct timeval *tdiff, *t1, *t0; 114610296Ssam { 114710296Ssam 114810296Ssam tdiff->tv_sec = t1->tv_sec - t0->tv_sec; 114910296Ssam tdiff->tv_usec = t1->tv_usec - t0->tv_usec; 115010296Ssam if (tdiff->tv_usec < 0) 115110296Ssam tdiff->tv_sec--, tdiff->tv_usec += 1000000; 115210296Ssam } 115326048Sminshall 115426048Sminshall psabort() 115526048Sminshall { 115626048Sminshall extern int abrtflag; 115726048Sminshall 115826048Sminshall abrtflag++; 115926048Sminshall } 116026048Sminshall 116126048Sminshall pswitch(flag) 116226048Sminshall int flag; 116326048Sminshall { 116426048Sminshall extern int proxy, abrtflag; 116526048Sminshall int (*oldintr)(); 116626048Sminshall static struct comvars { 116726048Sminshall int connect; 116828469Skarels char name[MAXHOSTNAMELEN]; 116926048Sminshall struct sockaddr_in mctl; 117026048Sminshall struct sockaddr_in hctl; 117126048Sminshall FILE *in; 117226048Sminshall FILE *out; 117326048Sminshall int tpe; 117426048Sminshall int cpnd; 117526048Sminshall int sunqe; 117626048Sminshall int runqe; 117726048Sminshall int mcse; 117826048Sminshall int ntflg; 117926048Sminshall char nti[17]; 118026048Sminshall char nto[17]; 118126048Sminshall int mapflg; 118226048Sminshall char mi[MAXPATHLEN]; 118326048Sminshall char mo[MAXPATHLEN]; 118426048Sminshall } proxstruct, tmpstruct; 118526048Sminshall struct comvars *ip, *op; 118626048Sminshall 118726048Sminshall abrtflag = 0; 118826048Sminshall oldintr = signal(SIGINT, psabort); 118926048Sminshall if (flag) { 119026448Slepreau if (proxy) 119126048Sminshall return; 119226048Sminshall ip = &tmpstruct; 119326048Sminshall op = &proxstruct; 119426048Sminshall proxy++; 119526048Sminshall } 119626048Sminshall else { 119726448Slepreau if (!proxy) 119826048Sminshall return; 119926048Sminshall ip = &proxstruct; 120026048Sminshall op = &tmpstruct; 120126048Sminshall proxy = 0; 120226048Sminshall } 120326048Sminshall ip->connect = connected; 120426048Sminshall connected = op->connect; 120528469Skarels if (hostname) { 120628469Skarels (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1); 120728469Skarels ip->name[strlen(ip->name)] = '\0'; 120828469Skarels } else 120928469Skarels ip->name[0] = 0; 121026048Sminshall hostname = op->name; 121126048Sminshall ip->hctl = hisctladdr; 121226048Sminshall hisctladdr = op->hctl; 121326048Sminshall ip->mctl = myctladdr; 121426048Sminshall myctladdr = op->mctl; 121526048Sminshall ip->in = cin; 121626048Sminshall cin = op->in; 121726048Sminshall ip->out = cout; 121826048Sminshall cout = op->out; 121926048Sminshall ip->tpe = type; 122026048Sminshall type = op->tpe; 122126448Slepreau if (!type) 122226048Sminshall type = 1; 122326048Sminshall ip->cpnd = cpend; 122426048Sminshall cpend = op->cpnd; 122526048Sminshall ip->sunqe = sunique; 122626048Sminshall sunique = op->sunqe; 122726048Sminshall ip->runqe = runique; 122826048Sminshall runique = op->runqe; 122926048Sminshall ip->mcse = mcase; 123026048Sminshall mcase = op->mcse; 123126048Sminshall ip->ntflg = ntflag; 123226048Sminshall ntflag = op->ntflg; 123326496Sminshall (void) strncpy(ip->nti, ntin, 16); 123426048Sminshall (ip->nti)[strlen(ip->nti)] = '\0'; 123526496Sminshall (void) strcpy(ntin, op->nti); 123626496Sminshall (void) strncpy(ip->nto, ntout, 16); 123726048Sminshall (ip->nto)[strlen(ip->nto)] = '\0'; 123826496Sminshall (void) strcpy(ntout, op->nto); 123926048Sminshall ip->mapflg = mapflag; 124026048Sminshall mapflag = op->mapflg; 124126496Sminshall (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1); 124226048Sminshall (ip->mi)[strlen(ip->mi)] = '\0'; 124326496Sminshall (void) strcpy(mapin, op->mi); 124426496Sminshall (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1); 124526048Sminshall (ip->mo)[strlen(ip->mo)] = '\0'; 124626496Sminshall (void) strcpy(mapout, op->mo); 124726048Sminshall (void) signal(SIGINT, oldintr); 124826048Sminshall if (abrtflag) { 124926048Sminshall abrtflag = 0; 125026048Sminshall (*oldintr)(); 125126448Slepreau } 125226048Sminshall } 125326048Sminshall 125426048Sminshall jmp_buf ptabort; 125526048Sminshall int ptabflg; 125626048Sminshall 125726048Sminshall abortpt() 125826048Sminshall { 125926048Sminshall printf("\n"); 126026496Sminshall (void) fflush(stdout); 126126048Sminshall ptabflg++; 126226048Sminshall mflag = 0; 126326048Sminshall abrtflag = 0; 126426048Sminshall longjmp(ptabort, 1); 126526048Sminshall } 126626048Sminshall 126726048Sminshall proxtrans(cmd, local, remote) 126826048Sminshall char *cmd, *local, *remote; 126926048Sminshall { 127027687Sminshall int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd; 127126048Sminshall extern jmp_buf ptabort; 127226048Sminshall char *cmd2; 127326496Sminshall struct fd_set mask; 127426048Sminshall 127526448Slepreau if (strcmp(cmd, "RETR")) 127626048Sminshall cmd2 = "RETR"; 127726448Slepreau else 127826048Sminshall cmd2 = runique ? "STOU" : "STOR"; 127926048Sminshall if (command("PASV") != COMPLETE) { 128026048Sminshall printf("proxy server does not support third part transfers.\n"); 128126048Sminshall return; 128226048Sminshall } 128326048Sminshall tmptype = type; 128426048Sminshall pswitch(0); 128526048Sminshall if (!connected) { 128626048Sminshall printf("No primary connection\n"); 128726048Sminshall pswitch(1); 128826048Sminshall code = -1; 128926048Sminshall return; 129026048Sminshall } 129126048Sminshall if (type != tmptype) { 129226048Sminshall oldtype = type; 129326048Sminshall switch (tmptype) { 129426048Sminshall case TYPE_A: 129526048Sminshall setascii(); 129626048Sminshall break; 129726048Sminshall case TYPE_I: 129826048Sminshall setbinary(); 129926048Sminshall break; 130026048Sminshall case TYPE_E: 130126048Sminshall setebcdic(); 130226048Sminshall break; 130326048Sminshall case TYPE_L: 130426048Sminshall settenex(); 130526048Sminshall break; 130626048Sminshall } 130726048Sminshall } 130826048Sminshall if (command("PORT %s", pasv) != COMPLETE) { 130926048Sminshall switch (oldtype) { 131026048Sminshall case 0: 131126048Sminshall break; 131226048Sminshall case TYPE_A: 131326048Sminshall setascii(); 131426048Sminshall break; 131526048Sminshall case TYPE_I: 131626048Sminshall setbinary(); 131726048Sminshall break; 131826048Sminshall case TYPE_E: 131926048Sminshall setebcdic(); 132026048Sminshall break; 132126048Sminshall case TYPE_L: 132226048Sminshall settenex(); 132326048Sminshall break; 132426048Sminshall } 132526048Sminshall pswitch(1); 132626048Sminshall return; 132726048Sminshall } 132826448Slepreau if (setjmp(ptabort)) 132926048Sminshall goto abort; 133026048Sminshall oldintr = signal(SIGINT, abortpt); 133126048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 133226048Sminshall (void) signal(SIGINT, oldintr); 133326048Sminshall switch (oldtype) { 133426048Sminshall case 0: 133526048Sminshall break; 133626048Sminshall case TYPE_A: 133726048Sminshall setascii(); 133826048Sminshall break; 133926048Sminshall case TYPE_I: 134026048Sminshall setbinary(); 134126048Sminshall break; 134226048Sminshall case TYPE_E: 134326048Sminshall setebcdic(); 134426048Sminshall break; 134526048Sminshall case TYPE_L: 134626048Sminshall settenex(); 134726048Sminshall break; 134826048Sminshall } 134926048Sminshall pswitch(1); 135026048Sminshall return; 135126048Sminshall } 135226048Sminshall sleep(2); 135326048Sminshall pswitch(1); 135426048Sminshall secndflag++; 135526448Slepreau if (command("%s %s", cmd2, local) != PRELIM) 135626048Sminshall goto abort; 135726048Sminshall ptflag++; 135826048Sminshall (void) getreply(0); 135926048Sminshall pswitch(0); 136026048Sminshall (void) getreply(0); 136126048Sminshall (void) signal(SIGINT, oldintr); 136226048Sminshall switch (oldtype) { 136326048Sminshall case 0: 136426048Sminshall break; 136526048Sminshall case TYPE_A: 136626048Sminshall setascii(); 136726048Sminshall break; 136826048Sminshall case TYPE_I: 136926048Sminshall setbinary(); 137026048Sminshall break; 137126048Sminshall case TYPE_E: 137226048Sminshall setebcdic(); 137326048Sminshall break; 137426048Sminshall case TYPE_L: 137526048Sminshall settenex(); 137626048Sminshall break; 137726048Sminshall } 137826048Sminshall pswitch(1); 137926048Sminshall ptflag = 0; 138026048Sminshall printf("local: %s remote: %s\n", local, remote); 138126048Sminshall return; 138226048Sminshall abort: 138326048Sminshall (void) signal(SIGINT, SIG_IGN); 138426048Sminshall ptflag = 0; 138526448Slepreau if (strcmp(cmd, "RETR") && !proxy) 138626048Sminshall pswitch(1); 138726448Slepreau else if (!strcmp(cmd, "RETR") && proxy) 138826048Sminshall pswitch(0); 138926048Sminshall if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ 139026048Sminshall if (command("%s %s", cmd2, local) != PRELIM) { 139126048Sminshall pswitch(0); 139226048Sminshall switch (oldtype) { 139326048Sminshall case 0: 139426048Sminshall break; 139526048Sminshall case TYPE_A: 139626048Sminshall setascii(); 139726048Sminshall break; 139826048Sminshall case TYPE_I: 139926048Sminshall setbinary(); 140026048Sminshall break; 140126048Sminshall case TYPE_E: 140226048Sminshall setebcdic(); 140326048Sminshall break; 140426048Sminshall case TYPE_L: 140526048Sminshall settenex(); 140626048Sminshall break; 140726048Sminshall } 140827687Sminshall if (cpend) { 140926048Sminshall char msg[2]; 141026048Sminshall 141126048Sminshall fprintf(cout,"%c%c",IAC,IP); 141226048Sminshall (void) fflush(cout); 141326048Sminshall *msg = IAC; 141426048Sminshall *(msg+1) = DM; 141526448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 141626048Sminshall perror("abort"); 141726048Sminshall fprintf(cout,"ABOR\r\n"); 141826048Sminshall (void) fflush(cout); 141927687Sminshall FD_ZERO(&mask); 142026496Sminshall FD_SET(fileno(cin), &mask); 142127687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 142227687Sminshall if (nfnd < 0) { 142327687Sminshall perror("abort"); 142427687Sminshall } 142526448Slepreau if (ptabflg) 142626048Sminshall code = -1; 142726048Sminshall lostpeer(); 142826048Sminshall } 142926048Sminshall (void) getreply(0); 143026048Sminshall (void) getreply(0); 143126048Sminshall } 143226048Sminshall } 143326048Sminshall pswitch(1); 143426448Slepreau if (ptabflg) 143526048Sminshall code = -1; 143626048Sminshall (void) signal(SIGINT, oldintr); 143726048Sminshall return; 143826048Sminshall } 143927687Sminshall if (cpend) { 144026048Sminshall char msg[2]; 144126048Sminshall 144226048Sminshall fprintf(cout,"%c%c",IAC,IP); 144326048Sminshall (void) fflush(cout); 144426048Sminshall *msg = IAC; 144526048Sminshall *(msg+1) = DM; 144626448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 144726048Sminshall perror("abort"); 144826048Sminshall fprintf(cout,"ABOR\r\n"); 144926048Sminshall (void) fflush(cout); 145027687Sminshall FD_ZERO(&mask); 145126496Sminshall FD_SET(fileno(cin), &mask); 145227687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 145327687Sminshall if (nfnd < 0) { 145427687Sminshall perror("abort"); 145527687Sminshall } 145626448Slepreau if (ptabflg) 145726048Sminshall code = -1; 145826048Sminshall lostpeer(); 145926048Sminshall } 146026048Sminshall (void) getreply(0); 146126048Sminshall (void) getreply(0); 146226048Sminshall } 146326048Sminshall pswitch(!proxy); 146426048Sminshall if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ 146526048Sminshall if (command("%s %s", cmd2, local) != PRELIM) { 146626048Sminshall pswitch(0); 146726048Sminshall switch (oldtype) { 146826048Sminshall case 0: 146926048Sminshall break; 147026048Sminshall case TYPE_A: 147126048Sminshall setascii(); 147226048Sminshall break; 147326048Sminshall case TYPE_I: 147426048Sminshall setbinary(); 147526048Sminshall break; 147626048Sminshall case TYPE_E: 147726048Sminshall setebcdic(); 147826048Sminshall break; 147926048Sminshall case TYPE_L: 148026048Sminshall settenex(); 148126048Sminshall break; 148226048Sminshall } 148327687Sminshall if (cpend) { 148426048Sminshall char msg[2]; 148526048Sminshall 148626048Sminshall fprintf(cout,"%c%c",IAC,IP); 148726048Sminshall (void) fflush(cout); 148826048Sminshall *msg = IAC; 148926048Sminshall *(msg+1) = DM; 149026448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 149126048Sminshall perror("abort"); 149226048Sminshall fprintf(cout,"ABOR\r\n"); 149326048Sminshall (void) fflush(cout); 149427687Sminshall FD_ZERO(&mask); 149526496Sminshall FD_SET(fileno(cin), &mask); 149627687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 149727687Sminshall if (nfnd < 0) { 149827687Sminshall perror("abort"); 149927687Sminshall } 150026448Slepreau if (ptabflg) 150126048Sminshall code = -1; 150226048Sminshall lostpeer(); 150326048Sminshall } 150426048Sminshall (void) getreply(0); 150526048Sminshall (void) getreply(0); 150626048Sminshall } 150726048Sminshall pswitch(1); 150826448Slepreau if (ptabflg) 150926048Sminshall code = -1; 151026048Sminshall (void) signal(SIGINT, oldintr); 151126048Sminshall return; 151226048Sminshall } 151326048Sminshall } 151427687Sminshall if (cpend) { 151526048Sminshall char msg[2]; 151626048Sminshall 151726048Sminshall fprintf(cout,"%c%c",IAC,IP); 151826048Sminshall (void) fflush(cout); 151926048Sminshall *msg = IAC; 152026048Sminshall *(msg+1) = DM; 152126448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 152226048Sminshall perror("abort"); 152326048Sminshall fprintf(cout,"ABOR\r\n"); 152426048Sminshall (void) fflush(cout); 152527687Sminshall FD_ZERO(&mask); 152626496Sminshall FD_SET(fileno(cin), &mask); 152727687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 152827687Sminshall if (nfnd < 0) { 152927687Sminshall perror("abort"); 153027687Sminshall } 153126448Slepreau if (ptabflg) 153226048Sminshall code = -1; 153326048Sminshall lostpeer(); 153426048Sminshall } 153526048Sminshall (void) getreply(0); 153626048Sminshall (void) getreply(0); 153726048Sminshall } 153826048Sminshall pswitch(!proxy); 153926048Sminshall if (cpend) { 154027687Sminshall FD_ZERO(&mask); 154126496Sminshall FD_SET(fileno(cin), &mask); 154227687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 154327687Sminshall if (nfnd < 0) { 154427687Sminshall perror("abort"); 154527687Sminshall } 154626448Slepreau if (ptabflg) 154726048Sminshall code = -1; 154826048Sminshall lostpeer(); 154926048Sminshall } 155026048Sminshall (void) getreply(0); 155126048Sminshall (void) getreply(0); 155226048Sminshall } 155326448Slepreau if (proxy) 155426048Sminshall pswitch(0); 155526048Sminshall switch (oldtype) { 155626048Sminshall case 0: 155726048Sminshall break; 155826048Sminshall case TYPE_A: 155926048Sminshall setascii(); 156026048Sminshall break; 156126048Sminshall case TYPE_I: 156226048Sminshall setbinary(); 156326048Sminshall break; 156426048Sminshall case TYPE_E: 156526048Sminshall setebcdic(); 156626048Sminshall break; 156726048Sminshall case TYPE_L: 156826048Sminshall settenex(); 156926048Sminshall break; 157026048Sminshall } 157126048Sminshall pswitch(1); 157226448Slepreau if (ptabflg) 157326048Sminshall code = -1; 157426048Sminshall (void) signal(SIGINT, oldintr); 157526048Sminshall } 157626048Sminshall 157726048Sminshall reset() 157826048Sminshall { 157926496Sminshall struct fd_set mask; 158026496Sminshall int nfnd = 1; 158126048Sminshall 158227687Sminshall FD_ZERO(&mask); 158330946Scsvsj while (nfnd > 0) { 158426496Sminshall FD_SET(fileno(cin), &mask); 158527687Sminshall if ((nfnd = empty(&mask,0)) < 0) { 158626048Sminshall perror("reset"); 158726048Sminshall code = -1; 158826048Sminshall lostpeer(); 158926048Sminshall } 159027687Sminshall else if (nfnd) { 159126048Sminshall (void) getreply(0); 159226496Sminshall } 159326048Sminshall } 159426048Sminshall } 159526048Sminshall 159626048Sminshall char * 159726048Sminshall gunique(local) 159826048Sminshall char *local; 159926048Sminshall { 160026048Sminshall static char new[MAXPATHLEN]; 160126048Sminshall char *cp = rindex(local, '/'); 160226048Sminshall int d, count=0; 160326048Sminshall char ext = '1'; 160426048Sminshall 160526448Slepreau if (cp) 160626048Sminshall *cp = '\0'; 160726048Sminshall d = access(cp ? local : ".", 2); 160826448Slepreau if (cp) 160926048Sminshall *cp = '/'; 161026048Sminshall if (d < 0) { 161126048Sminshall perror(local); 161226048Sminshall return((char *) 0); 161326048Sminshall } 161426048Sminshall (void) strcpy(new, local); 161526048Sminshall cp = new + strlen(new); 161626048Sminshall *cp++ = '.'; 161726048Sminshall while (!d) { 161826048Sminshall if (++count == 100) { 161926048Sminshall printf("runique: can't find unique file name.\n"); 162026048Sminshall return((char *) 0); 162126048Sminshall } 162226048Sminshall *cp++ = ext; 162326048Sminshall *cp = '\0'; 162426448Slepreau if (ext == '9') 162526048Sminshall ext = '0'; 162626448Slepreau else 162726048Sminshall ext++; 162826448Slepreau if ((d = access(new, 0)) < 0) 162926048Sminshall break; 163026448Slepreau if (ext != '0') 163126048Sminshall cp--; 163226448Slepreau else if (*(cp - 2) == '.') 163326048Sminshall *(cp - 1) = '1'; 163426048Sminshall else { 163526048Sminshall *(cp - 2) = *(cp - 2) + 1; 163626048Sminshall cp--; 163726048Sminshall } 163826048Sminshall } 163926048Sminshall return(new); 164026048Sminshall } 1641