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*36944Skarels static char sccsid[] = "@(#)ftp.c 5.25 (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*36944Skarels off_t restart_point = 0; 5110296Ssam 5210296Ssam FILE *cin, *cout; 5310296Ssam FILE *dataconn(); 5410296Ssam 5525904Skarels char * 5610296Ssam hookup(host, port) 5710296Ssam char *host; 5810296Ssam int port; 5910296Ssam { 6025904Skarels register struct hostent *hp = 0; 6127687Sminshall int s,len; 6225904Skarels static char hostnamebuf[80]; 6310296Ssam 6410296Ssam bzero((char *)&hisctladdr, sizeof (hisctladdr)); 6525904Skarels hisctladdr.sin_addr.s_addr = inet_addr(host); 6625904Skarels if (hisctladdr.sin_addr.s_addr != -1) { 6725904Skarels hisctladdr.sin_family = AF_INET; 6836940Skarels (void) strncpy(hostnamebuf, host, sizeof(hostnamebuf)); 6936940Skarels } else { 7025100Sbloom hp = gethostbyname(host); 7125904Skarels if (hp == NULL) { 7235792Sbostic fprintf(stderr, "ftp: %s: ", host); 7335792Sbostic herror((char *)NULL); 7426048Sminshall code = -1; 7526048Sminshall return((char *) 0); 7625904Skarels } 7725904Skarels hisctladdr.sin_family = hp->h_addrtype; 7825904Skarels bcopy(hp->h_addr_list[0], 7925904Skarels (caddr_t)&hisctladdr.sin_addr, hp->h_length); 8036940Skarels (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf)); 8110296Ssam } 8225904Skarels hostname = hostnamebuf; 8325904Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 8410296Ssam if (s < 0) { 8510296Ssam perror("ftp: socket"); 8626048Sminshall code = -1; 8710296Ssam return (0); 8810296Ssam } 8910296Ssam hisctladdr.sin_port = port; 9026496Sminshall while (connect(s, &hisctladdr, sizeof (hisctladdr)) < 0) { 9125904Skarels if (hp && hp->h_addr_list[1]) { 9225904Skarels int oerrno = errno; 9325904Skarels 9425904Skarels fprintf(stderr, "ftp: connect to address %s: ", 9525904Skarels inet_ntoa(hisctladdr.sin_addr)); 9625904Skarels errno = oerrno; 9726496Sminshall perror((char *) 0); 9825904Skarels hp->h_addr_list++; 9925904Skarels bcopy(hp->h_addr_list[0], 10026048Sminshall (caddr_t)&hisctladdr.sin_addr, hp->h_length); 10126496Sminshall fprintf(stdout, "Trying %s...\n", 10225904Skarels inet_ntoa(hisctladdr.sin_addr)); 10326813Skarels (void) close(s); 10426813Skarels s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); 10526813Skarels if (s < 0) { 10626813Skarels perror("ftp: socket"); 10726813Skarels code = -1; 10826813Skarels return (0); 10926813Skarels } 11025904Skarels continue; 11125904Skarels } 11210296Ssam perror("ftp: connect"); 11326048Sminshall code = -1; 11410296Ssam goto bad; 11510296Ssam } 11611627Ssam len = sizeof (myctladdr); 11711627Ssam if (getsockname(s, (char *)&myctladdr, &len) < 0) { 11811627Ssam perror("ftp: getsockname"); 11926048Sminshall code = -1; 12010296Ssam goto bad; 12110296Ssam } 12210296Ssam cin = fdopen(s, "r"); 12310296Ssam cout = fdopen(s, "w"); 12411219Ssam if (cin == NULL || cout == NULL) { 12510296Ssam fprintf(stderr, "ftp: fdopen failed.\n"); 12610296Ssam if (cin) 12726496Sminshall (void) fclose(cin); 12810296Ssam if (cout) 12926496Sminshall (void) fclose(cout); 13026048Sminshall code = -1; 13110296Ssam goto bad; 13210296Ssam } 13310296Ssam if (verbose) 13426067Sminshall printf("Connected to %s.\n", hostname); 13527687Sminshall if (getreply(0) > 2) { /* read startup message from server */ 13626048Sminshall if (cin) 13726496Sminshall (void) fclose(cin); 13826048Sminshall if (cout) 13926496Sminshall (void) fclose(cout); 14026048Sminshall code = -1; 14126048Sminshall goto bad; 14226048Sminshall } 14327687Sminshall #ifdef SO_OOBINLINE 14427687Sminshall { 14527687Sminshall int on = 1; 14626048Sminshall 14727687Sminshall if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, &on, sizeof(on)) 14827687Sminshall < 0 && debug) { 14927687Sminshall perror("ftp: setsockopt"); 15027687Sminshall } 15127687Sminshall } 15227687Sminshall #endif SO_OOBINLINE 15326048Sminshall 15425904Skarels return (hostname); 15510296Ssam bad: 15626496Sminshall (void) close(s); 15725904Skarels return ((char *)0); 15810296Ssam } 15910296Ssam 16025904Skarels login(host) 16125904Skarels char *host; 16210296Ssam { 16326048Sminshall char tmp[80]; 16435659Sbostic char *user, *pass, *acct, *getlogin(), *getpass(); 16526048Sminshall int n, aflag = 0; 16610296Ssam 16726048Sminshall user = pass = acct = 0; 16826048Sminshall if (ruserpass(host, &user, &pass, &acct) < 0) { 16926048Sminshall code = -1; 17026048Sminshall return(0); 17126048Sminshall } 17226048Sminshall if (user == NULL) { 17326048Sminshall char *myname = getlogin(); 17426048Sminshall 17526048Sminshall if (myname == NULL) { 17626048Sminshall struct passwd *pp = getpwuid(getuid()); 17726048Sminshall 17826448Slepreau if (pp != NULL) 17926048Sminshall myname = pp->pw_name; 18026048Sminshall } 18126048Sminshall printf("Name (%s:%s): ", host, myname); 18226048Sminshall (void) fgets(tmp, sizeof(tmp) - 1, stdin); 18326048Sminshall tmp[strlen(tmp) - 1] = '\0'; 18426448Slepreau if (*tmp == '\0') 18526048Sminshall user = myname; 18626448Slepreau else 18726048Sminshall user = tmp; 18826048Sminshall } 18910296Ssam n = command("USER %s", user); 19026048Sminshall if (n == CONTINUE) { 19126448Slepreau if (pass == NULL) 19235659Sbostic pass = getpass("Password:"); 19310296Ssam n = command("PASS %s", pass); 19426048Sminshall } 19510296Ssam if (n == CONTINUE) { 19626048Sminshall aflag++; 19735659Sbostic acct = getpass("Account:"); 19810296Ssam n = command("ACCT %s", acct); 19910296Ssam } 20010296Ssam if (n != COMPLETE) { 20110296Ssam fprintf(stderr, "Login failed.\n"); 20210296Ssam return (0); 20310296Ssam } 20426448Slepreau if (!aflag && acct != NULL) 20526048Sminshall (void) command("ACCT %s", acct); 20626448Slepreau if (proxy) 20726048Sminshall return(1); 20826048Sminshall for (n = 0; n < macnum; ++n) { 20926048Sminshall if (!strcmp("init", macros[n].mac_name)) { 21026496Sminshall (void) strcpy(line, "$init"); 21126048Sminshall makeargv(); 21226048Sminshall domacro(margc, margv); 21326048Sminshall break; 21426048Sminshall } 21526048Sminshall } 21610296Ssam return (1); 21710296Ssam } 21810296Ssam 21926048Sminshall cmdabort() 22026048Sminshall { 22126048Sminshall extern jmp_buf ptabort; 22226048Sminshall 22326048Sminshall printf("\n"); 22426048Sminshall (void) fflush(stdout); 22526048Sminshall abrtflag++; 22626448Slepreau if (ptflag) 22726048Sminshall longjmp(ptabort,1); 22826048Sminshall } 22926048Sminshall 23026496Sminshall /*VARARGS1*/ 23110296Ssam command(fmt, args) 23210296Ssam char *fmt; 23310296Ssam { 23426048Sminshall int r, (*oldintr)(), cmdabort(); 23510296Ssam 23626048Sminshall abrtflag = 0; 23710296Ssam if (debug) { 23810296Ssam printf("---> "); 23910296Ssam _doprnt(fmt, &args, stdout); 24010296Ssam printf("\n"); 24110296Ssam (void) fflush(stdout); 24210296Ssam } 24311219Ssam if (cout == NULL) { 24411219Ssam perror ("No control connection for command"); 24526048Sminshall code = -1; 24611219Ssam return (0); 24711219Ssam } 24826048Sminshall oldintr = signal(SIGINT,cmdabort); 24910296Ssam _doprnt(fmt, &args, cout); 25010296Ssam fprintf(cout, "\r\n"); 25110296Ssam (void) fflush(cout); 25226048Sminshall cpend = 1; 25326048Sminshall r = getreply(!strcmp(fmt, "QUIT")); 25426448Slepreau if (abrtflag && oldintr != SIG_IGN) 25526048Sminshall (*oldintr)(); 25626048Sminshall (void) signal(SIGINT, oldintr); 25726048Sminshall return(r); 25810296Ssam } 25910296Ssam 26036935Skarels char reply_string[BUFSIZ]; 26136935Skarels 26210296Ssam #include <ctype.h> 26310296Ssam 26410296Ssam getreply(expecteof) 26510296Ssam int expecteof; 26610296Ssam { 26711219Ssam register int c, n; 26826048Sminshall register int dig; 26936935Skarels register char *cp; 27026048Sminshall int originalcode = 0, continuation = 0, (*oldintr)(), cmdabort(); 27126048Sminshall int pflag = 0; 27226048Sminshall char *pt = pasv; 27310296Ssam 27436935Skarels cp = reply_string; 27526048Sminshall oldintr = signal(SIGINT,cmdabort); 27610296Ssam for (;;) { 27710296Ssam dig = n = code = 0; 27810296Ssam while ((c = getc(cin)) != '\n') { 27927687Sminshall if (c == IAC) { /* handle telnet commands */ 28027687Sminshall switch (c = getc(cin)) { 28127687Sminshall case WILL: 28227687Sminshall case WONT: 28327687Sminshall c = getc(cin); 28436940Skarels fprintf(cout, "%c%c%c",IAC,DONT,c); 28527687Sminshall (void) fflush(cout); 28627687Sminshall break; 28727687Sminshall case DO: 28827687Sminshall case DONT: 28927687Sminshall c = getc(cin); 29036940Skarels fprintf(cout, "%c%c%c",IAC,WONT,c); 29127687Sminshall (void) fflush(cout); 29227687Sminshall break; 29327687Sminshall default: 29427687Sminshall break; 29527687Sminshall } 29627687Sminshall continue; 29727687Sminshall } 29810296Ssam dig++; 29910296Ssam if (c == EOF) { 30026048Sminshall if (expecteof) { 30126048Sminshall (void) signal(SIGINT,oldintr); 30226048Sminshall code = 221; 30310296Ssam return (0); 30426048Sminshall } 30510296Ssam lostpeer(); 30626048Sminshall if (verbose) { 30726048Sminshall printf("421 Service not available, remote server has closed connection\n"); 30826048Sminshall (void) fflush(stdout); 30926048Sminshall } 31033772Scsvsj code = 421; 31133772Scsvsj return(4); 31210296Ssam } 31326048Sminshall if (c != '\r' && (verbose > 0 || 31426048Sminshall (verbose > -1 && n == '5' && dig > 4))) { 31526448Slepreau if (proxflag && 31626448Slepreau (dig == 1 || dig == 5 && verbose == 0)) 31726048Sminshall printf("%s:",hostname); 31826496Sminshall (void) putchar(c); 31926048Sminshall } 32010296Ssam if (dig < 4 && isdigit(c)) 32110296Ssam code = code * 10 + (c - '0'); 32226448Slepreau if (!pflag && code == 227) 32326048Sminshall pflag = 1; 32426448Slepreau if (dig > 4 && pflag == 1 && isdigit(c)) 32526048Sminshall pflag = 2; 32626048Sminshall if (pflag == 2) { 32726448Slepreau if (c != '\r' && c != ')') 32826048Sminshall *pt++ = c; 32926048Sminshall else { 33026048Sminshall *pt = '\0'; 33126048Sminshall pflag = 3; 33226048Sminshall } 33326048Sminshall } 33426048Sminshall if (dig == 4 && c == '-') { 33526448Slepreau if (continuation) 33626048Sminshall code = 0; 33710296Ssam continuation++; 33826048Sminshall } 33910296Ssam if (n == 0) 34010296Ssam n = c; 34136935Skarels *cp++ = c; 34210296Ssam } 34326048Sminshall if (verbose > 0 || verbose > -1 && n == '5') { 34426496Sminshall (void) putchar(c); 34511346Ssam (void) fflush (stdout); 34611346Ssam } 34710296Ssam if (continuation && code != originalcode) { 34810296Ssam if (originalcode == 0) 34910296Ssam originalcode = code; 35010296Ssam continue; 35110296Ssam } 35236935Skarels *cp = '\0'; 35326448Slepreau if (n != '1') 35426048Sminshall cpend = 0; 35526048Sminshall (void) signal(SIGINT,oldintr); 35626448Slepreau if (code == 421 || originalcode == 421) 35726048Sminshall lostpeer(); 35826448Slepreau if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) 35926048Sminshall (*oldintr)(); 36025907Smckusick return (n - '0'); 36110296Ssam } 36210296Ssam } 36310296Ssam 36426048Sminshall empty(mask, sec) 36527687Sminshall struct fd_set *mask; 36626048Sminshall int sec; 36726048Sminshall { 36826048Sminshall struct timeval t; 36926048Sminshall 37026048Sminshall t.tv_sec = (long) sec; 37126048Sminshall t.tv_usec = 0; 37227687Sminshall return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t)); 37326048Sminshall } 37426048Sminshall 37510296Ssam jmp_buf sendabort; 37610296Ssam 37710296Ssam abortsend() 37810296Ssam { 37910296Ssam 38026048Sminshall mflag = 0; 38126048Sminshall abrtflag = 0; 38226048Sminshall printf("\nsend aborted\n"); 38326048Sminshall (void) fflush(stdout); 38410296Ssam longjmp(sendabort, 1); 38510296Ssam } 38610296Ssam 38736940Skarels #define HASHBYTES 1024 38836940Skarels 38910296Ssam sendrequest(cmd, local, remote) 39010296Ssam char *cmd, *local, *remote; 39110296Ssam { 39235659Sbostic FILE *fin, *dout = 0, *popen(); 39335659Sbostic int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); 39426048Sminshall int abortsend(); 39536942Skarels char buf[BUFSIZ], *bufp; 39636940Skarels long bytes = 0, hashbytes = HASHBYTES; 39711346Ssam register int c, d; 39810296Ssam struct stat st; 39910296Ssam struct timeval start, stop; 40036935Skarels char *mode; 40110296Ssam 40226048Sminshall if (proxy) { 40326048Sminshall proxtrans(cmd, local, remote); 40426048Sminshall return; 40526048Sminshall } 40610296Ssam closefunc = NULL; 40726048Sminshall oldintr = NULL; 40826048Sminshall oldintp = NULL; 40936935Skarels mode = "w"; 41026048Sminshall if (setjmp(sendabort)) { 41126048Sminshall while (cpend) { 41226048Sminshall (void) getreply(0); 41326048Sminshall } 41426048Sminshall if (data >= 0) { 41526048Sminshall (void) close(data); 41626048Sminshall data = -1; 41726048Sminshall } 41826448Slepreau if (oldintr) 41926048Sminshall (void) signal(SIGINT,oldintr); 42026448Slepreau if (oldintp) 42126048Sminshall (void) signal(SIGPIPE,oldintp); 42226048Sminshall code = -1; 42326048Sminshall return; 42426048Sminshall } 42510296Ssam oldintr = signal(SIGINT, abortsend); 42610296Ssam if (strcmp(local, "-") == 0) 42710296Ssam fin = stdin; 42810296Ssam else if (*local == '|') { 42926048Sminshall oldintp = signal(SIGPIPE,SIG_IGN); 43035659Sbostic fin = popen(local + 1, "r"); 43110296Ssam if (fin == NULL) { 43226048Sminshall perror(local + 1); 43326048Sminshall (void) signal(SIGINT, oldintr); 43426048Sminshall (void) signal(SIGPIPE, oldintp); 43526048Sminshall code = -1; 43626048Sminshall return; 43710296Ssam } 43835659Sbostic closefunc = pclose; 43910296Ssam } else { 44010296Ssam fin = fopen(local, "r"); 44110296Ssam if (fin == NULL) { 44210296Ssam perror(local); 44326048Sminshall (void) signal(SIGINT, oldintr); 44426048Sminshall code = -1; 44526048Sminshall return; 44610296Ssam } 44710296Ssam closefunc = fclose; 44810296Ssam if (fstat(fileno(fin), &st) < 0 || 44910296Ssam (st.st_mode&S_IFMT) != S_IFREG) { 45026496Sminshall fprintf(stdout, "%s: not a plain file.\n", local); 45126048Sminshall (void) signal(SIGINT, oldintr); 45236935Skarels fclose(fin); 45326048Sminshall code = -1; 45426048Sminshall return; 45510296Ssam } 45610296Ssam } 45726048Sminshall if (initconn()) { 45826048Sminshall (void) signal(SIGINT, oldintr); 45926448Slepreau if (oldintp) 46026048Sminshall (void) signal(SIGPIPE, oldintp); 46126048Sminshall code = -1; 46236935Skarels if (closefunc != NULL) 46336935Skarels (*closefunc)(fin); 46426048Sminshall return; 46526048Sminshall } 46626448Slepreau if (setjmp(sendabort)) 46726048Sminshall goto abort; 46836935Skarels 469*36944Skarels if (restart_point && 470*36944Skarels (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { 471*36944Skarels if (fseek(fin, (long) restart_point, 0) < 0) { 472*36944Skarels perror(local); 473*36944Skarels restart_point = 0; 474*36944Skarels if (closefunc != NULL) 475*36944Skarels (*closefunc)(fin); 476*36944Skarels return; 477*36944Skarels } 478*36944Skarels if (command("REST %ld", (long) restart_point) 479*36944Skarels != CONTINUE) { 480*36944Skarels restart_point = 0; 481*36944Skarels if (closefunc != NULL) 482*36944Skarels (*closefunc)(fin); 483*36944Skarels return; 484*36944Skarels } 485*36944Skarels restart_point = 0; 486*36944Skarels mode = "r+w"; 487*36944Skarels } 48810296Ssam if (remote) { 48926048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 49026048Sminshall (void) signal(SIGINT, oldintr); 49126448Slepreau if (oldintp) 49226048Sminshall (void) signal(SIGPIPE, oldintp); 49336935Skarels if (closefunc != NULL) 49436935Skarels (*closefunc)(fin); 49526048Sminshall return; 49626048Sminshall } 49710296Ssam } else 49826048Sminshall if (command("%s", cmd) != PRELIM) { 49926048Sminshall (void) signal(SIGINT, oldintr); 50026448Slepreau if (oldintp) 50126048Sminshall (void) signal(SIGPIPE, oldintp); 50236935Skarels if (closefunc != NULL) 50336935Skarels (*closefunc)(fin); 50426048Sminshall return; 50526048Sminshall } 50636935Skarels dout = dataconn(mode); 50726448Slepreau if (dout == NULL) 50826048Sminshall goto abort; 50926496Sminshall (void) gettimeofday(&start, (struct timezone *)0); 51036935Skarels oldintp = signal(SIGPIPE, SIG_IGN); 51111219Ssam switch (type) { 51211219Ssam 51311219Ssam case TYPE_I: 51411219Ssam case TYPE_L: 51511346Ssam errno = d = 0; 51636942Skarels while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) { 51711219Ssam bytes += c; 51836942Skarels for (bufp = buf; c > 0; c -= d, bufp += d) 51936942Skarels if ((d = write(fileno(dout), bufp, c)) <= 0) 52036942Skarels break; 52111651Ssam if (hash) { 52236940Skarels while (bytes >= hashbytes) { 52336940Skarels (void) putchar('#'); 52436940Skarels hashbytes += HASHBYTES; 52536940Skarels } 52626496Sminshall (void) fflush(stdout); 52711651Ssam } 52811219Ssam } 52913213Ssam if (hash && bytes > 0) { 53036940Skarels if (bytes < HASHBYTES) 53136940Skarels (void) putchar('#'); 53226496Sminshall (void) putchar('\n'); 53326496Sminshall (void) fflush(stdout); 53411651Ssam } 53511219Ssam if (c < 0) 53611219Ssam perror(local); 53736942Skarels if (d <= 0) { 53836942Skarels if (d == 0) 53936942Skarels fprintf(stderr, "netout: write returned 0?\n"); 54036942Skarels else if (errno != EPIPE) 54136935Skarels perror("netout"); 54236935Skarels bytes = -1; 54336935Skarels } 54411219Ssam break; 54511219Ssam 54611219Ssam case TYPE_A: 54711219Ssam while ((c = getc(fin)) != EOF) { 54811219Ssam if (c == '\n') { 54911651Ssam while (hash && (bytes >= hashbytes)) { 55026496Sminshall (void) putchar('#'); 55126496Sminshall (void) fflush(stdout); 55236940Skarels hashbytes += HASHBYTES; 55311651Ssam } 55411219Ssam if (ferror(dout)) 55511219Ssam break; 55626496Sminshall (void) putc('\r', dout); 55711219Ssam bytes++; 55811219Ssam } 55926496Sminshall (void) putc(c, dout); 56011219Ssam bytes++; 56126048Sminshall /* if (c == '\r') { */ 56226496Sminshall /* (void) putc('\0', dout); /* this violates rfc */ 56326048Sminshall /* bytes++; */ 56426048Sminshall /* } */ 56511219Ssam } 56611651Ssam if (hash) { 56713213Ssam if (bytes < hashbytes) 56826496Sminshall (void) putchar('#'); 56926496Sminshall (void) putchar('\n'); 57026496Sminshall (void) fflush(stdout); 57111651Ssam } 57211219Ssam if (ferror(fin)) 57311219Ssam perror(local); 57436935Skarels if (ferror(dout)) { 57536935Skarels if (errno != EPIPE) 57636935Skarels perror("netout"); 57736935Skarels bytes = -1; 57836935Skarels } 57911219Ssam break; 58010296Ssam } 58126496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 58210296Ssam if (closefunc != NULL) 58326048Sminshall (*closefunc)(fin); 58410296Ssam (void) fclose(dout); 58526048Sminshall (void) getreply(0); 58626048Sminshall (void) signal(SIGINT, oldintr); 58736935Skarels if (oldintp) 58836935Skarels (void) signal(SIGPIPE, oldintp); 58935699Sbostic if (bytes > 0) 59026048Sminshall ptransfer("sent", bytes, &start, &stop, local, remote); 59110296Ssam return; 59226048Sminshall abort: 59326496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 59426048Sminshall (void) signal(SIGINT, oldintr); 59526448Slepreau if (oldintp) 59626048Sminshall (void) signal(SIGPIPE, oldintp); 59726048Sminshall if (!cpend) { 59826048Sminshall code = -1; 59926048Sminshall return; 60026048Sminshall } 60126048Sminshall if (data >= 0) { 60226048Sminshall (void) close(data); 60326048Sminshall data = -1; 60426048Sminshall } 60526448Slepreau if (dout) 60626048Sminshall (void) fclose(dout); 60726048Sminshall (void) getreply(0); 60826048Sminshall code = -1; 60910296Ssam if (closefunc != NULL && fin != NULL) 61026048Sminshall (*closefunc)(fin); 61135699Sbostic if (bytes > 0) 61226048Sminshall ptransfer("sent", bytes, &start, &stop, local, remote); 61310296Ssam } 61410296Ssam 61510296Ssam jmp_buf recvabort; 61610296Ssam 61710296Ssam abortrecv() 61810296Ssam { 61910296Ssam 62026048Sminshall mflag = 0; 62126048Sminshall abrtflag = 0; 62226048Sminshall printf("\n"); 62326048Sminshall (void) fflush(stdout); 62410296Ssam longjmp(recvabort, 1); 62510296Ssam } 62610296Ssam 62711651Ssam recvrequest(cmd, local, remote, mode) 62811651Ssam char *cmd, *local, *remote, *mode; 62910296Ssam { 63035659Sbostic FILE *fout, *din = 0, *popen(); 63135659Sbostic int (*closefunc)(), pclose(), fclose(), (*oldintr)(), (*oldintp)(); 63236935Skarels int abortrecv(), oldverbose, oldtype = 0, is_retr, tcrflag, nfnd; 633*36944Skarels char *bufp, *gunique(), msg; 634*36944Skarels static char *buf; 63536940Skarels static int bufsize; 63636940Skarels long bytes = 0, hashbytes = HASHBYTES; 63726496Sminshall struct fd_set mask; 63811346Ssam register int c, d; 63910296Ssam struct timeval start, stop; 64036940Skarels struct stat st; 64136940Skarels extern char *malloc(); 64210296Ssam 64336935Skarels is_retr = strcmp(cmd, "RETR") == 0; 64436935Skarels if (proxy && is_retr) { 64526048Sminshall proxtrans(cmd, local, remote); 64626048Sminshall return; 64726048Sminshall } 64810296Ssam closefunc = NULL; 64926048Sminshall oldintr = NULL; 65026048Sminshall oldintp = NULL; 65136935Skarels tcrflag = !crflag && is_retr; 65226048Sminshall if (setjmp(recvabort)) { 65326048Sminshall while (cpend) { 65426048Sminshall (void) getreply(0); 65526048Sminshall } 65626048Sminshall if (data >= 0) { 65726048Sminshall (void) close(data); 65826048Sminshall data = -1; 65926048Sminshall } 66026448Slepreau if (oldintr) 66126048Sminshall (void) signal(SIGINT, oldintr); 66226048Sminshall code = -1; 66326048Sminshall return; 66426048Sminshall } 66510296Ssam oldintr = signal(SIGINT, abortrecv); 66626048Sminshall if (strcmp(local, "-") && *local != '|') { 66710296Ssam if (access(local, 2) < 0) { 66826048Sminshall char *dir = rindex(local, '/'); 66910296Ssam 67026048Sminshall if (errno != ENOENT && errno != EACCES) { 67110296Ssam perror(local); 67226048Sminshall (void) signal(SIGINT, oldintr); 67326048Sminshall code = -1; 67426048Sminshall return; 67510296Ssam } 67626048Sminshall if (dir != NULL) 67726048Sminshall *dir = 0; 67826048Sminshall d = access(dir ? local : ".", 2); 67926048Sminshall if (dir != NULL) 68026048Sminshall *dir = '/'; 68126048Sminshall if (d < 0) { 68226048Sminshall perror(local); 68326048Sminshall (void) signal(SIGINT, oldintr); 68426048Sminshall code = -1; 68526048Sminshall return; 68626048Sminshall } 68726048Sminshall if (!runique && errno == EACCES && 68836935Skarels chmod(local, 0600) < 0) { 68926048Sminshall perror(local); 69026048Sminshall (void) signal(SIGINT, oldintr); 69126048Sminshall code = -1; 69226048Sminshall return; 69326048Sminshall } 69426048Sminshall if (runique && errno == EACCES && 69526048Sminshall (local = gunique(local)) == NULL) { 69626048Sminshall (void) signal(SIGINT, oldintr); 69726048Sminshall code = -1; 69826048Sminshall return; 69926048Sminshall } 70010296Ssam } 70126048Sminshall else if (runique && (local = gunique(local)) == NULL) { 70226048Sminshall (void) signal(SIGINT, oldintr); 70326048Sminshall code = -1; 70426048Sminshall return; 70526048Sminshall } 70626048Sminshall } 70726048Sminshall if (initconn()) { 70826048Sminshall (void) signal(SIGINT, oldintr); 70926048Sminshall code = -1; 71026048Sminshall return; 71126048Sminshall } 71226448Slepreau if (setjmp(recvabort)) 71326048Sminshall goto abort; 71436935Skarels if (!is_retr) { 71536935Skarels if (type != TYPE_A) { 71636935Skarels oldtype = type; 71736935Skarels oldverbose = verbose; 71836935Skarels if (!debug) 71936935Skarels verbose = 0; 72036935Skarels setascii(); 72136935Skarels verbose = oldverbose; 72236935Skarels } 723*36944Skarels } else if (restart_point) { 724*36944Skarels if (command("REST %ld", (long) restart_point) != CONTINUE) 725*36944Skarels return; 72626048Sminshall } 72710296Ssam if (remote) { 72826048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 72926048Sminshall (void) signal(SIGINT, oldintr); 73026048Sminshall if (oldtype) { 73126448Slepreau if (!debug) 73226048Sminshall verbose = 0; 73326048Sminshall switch (oldtype) { 73426048Sminshall case TYPE_I: 73526048Sminshall setbinary(); 73626048Sminshall break; 73726048Sminshall case TYPE_E: 73826048Sminshall setebcdic(); 73926048Sminshall break; 74026048Sminshall case TYPE_L: 74126048Sminshall settenex(); 74226048Sminshall break; 74336942Skarels } 74426048Sminshall verbose = oldverbose; 74526048Sminshall } 74626048Sminshall return; 74726048Sminshall } 74826048Sminshall } else { 74926048Sminshall if (command("%s", cmd) != PRELIM) { 75026048Sminshall (void) signal(SIGINT, oldintr); 75126048Sminshall if (oldtype) { 75226448Slepreau if (!debug) 75326048Sminshall verbose = 0; 75426048Sminshall switch (oldtype) { 75526048Sminshall case TYPE_I: 75626048Sminshall setbinary(); 75726048Sminshall break; 75826048Sminshall case TYPE_E: 75926048Sminshall setebcdic(); 76026048Sminshall break; 76126048Sminshall case TYPE_L: 76226048Sminshall settenex(); 76326048Sminshall break; 76436942Skarels } 76526048Sminshall verbose = oldverbose; 76626048Sminshall } 76726048Sminshall return; 76826048Sminshall } 76926048Sminshall } 77026048Sminshall din = dataconn("r"); 77126048Sminshall if (din == NULL) 77226048Sminshall goto abort; 77326448Slepreau if (strcmp(local, "-") == 0) 77410296Ssam fout = stdout; 77510296Ssam else if (*local == '|') { 77626048Sminshall oldintp = signal(SIGPIPE, SIG_IGN); 77735659Sbostic fout = popen(local + 1, "w"); 77826048Sminshall if (fout == NULL) { 77926048Sminshall perror(local+1); 78026048Sminshall goto abort; 78126048Sminshall } 78235659Sbostic closefunc = pclose; 78336940Skarels } else { 78411651Ssam fout = fopen(local, mode); 78526048Sminshall if (fout == NULL) { 78626048Sminshall perror(local); 78726048Sminshall goto abort; 78826048Sminshall } 78910296Ssam closefunc = fclose; 79010296Ssam } 79136940Skarels if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) 79236940Skarels st.st_blksize = BUFSIZ; 79336940Skarels if (st.st_blksize > bufsize) { 79436940Skarels if (buf) 79536940Skarels (void) free(buf); 79636940Skarels buf = malloc(st.st_blksize); 79736940Skarels if (buf == NULL) { 79836940Skarels perror("malloc"); 799*36944Skarels bufsize = 0; 80036940Skarels goto abort; 80136940Skarels } 80236940Skarels bufsize = st.st_blksize; 80336940Skarels } 80426496Sminshall (void) gettimeofday(&start, (struct timezone *)0); 80511219Ssam switch (type) { 80611219Ssam 80711219Ssam case TYPE_I: 80811219Ssam case TYPE_L: 809*36944Skarels if (restart_point && 810*36944Skarels lseek(fileno(fout), (long) restart_point, L_SET) < 0) { 811*36944Skarels perror(local); 812*36944Skarels if (closefunc != NULL) 813*36944Skarels (*closefunc)(fout); 814*36944Skarels return; 815*36944Skarels } 81611346Ssam errno = d = 0; 81736940Skarels while ((c = read(fileno(din), buf, bufsize)) > 0) { 818*36944Skarels if ((d = write(fileno(fout), buf, c)) != c) 81911219Ssam break; 82011219Ssam bytes += c; 82111651Ssam if (hash) { 82236940Skarels while (bytes >= hashbytes) { 82336940Skarels (void) putchar('#'); 82436940Skarels hashbytes += HASHBYTES; 82536940Skarels } 82626496Sminshall (void) fflush(stdout); 82711651Ssam } 82811219Ssam } 82913213Ssam if (hash && bytes > 0) { 83036940Skarels if (bytes < HASHBYTES) 83136940Skarels (void) putchar('#'); 83226496Sminshall (void) putchar('\n'); 83326496Sminshall (void) fflush(stdout); 83411651Ssam } 83536935Skarels if (c < 0) { 83636935Skarels if (errno != EPIPE) 83736935Skarels perror("netin"); 83836935Skarels bytes = -1; 83936935Skarels } 84036942Skarels if (d < c) { 84136942Skarels if (d < 0) 84236942Skarels perror(local); 84336942Skarels else 84436942Skarels fprintf(stderr, "%s: short write\n", local); 84536942Skarels } 84611219Ssam break; 84711219Ssam 84811219Ssam case TYPE_A: 849*36944Skarels if (restart_point) { 850*36944Skarels register int i, n, c; 851*36944Skarels 852*36944Skarels if (fseek(fout, 0L, L_SET) < 0) 853*36944Skarels goto done; 854*36944Skarels n = restart_point; 855*36944Skarels i = 0; 856*36944Skarels while (i++ < n) { 857*36944Skarels if ((c=getc(fout)) == EOF) 858*36944Skarels goto done; 859*36944Skarels if (c == '\n') 860*36944Skarels i++; 861*36944Skarels } 862*36944Skarels if (fseek(fout, 0L, L_INCR) < 0) { 863*36944Skarels done: 864*36944Skarels perror(local); 865*36944Skarels if (closefunc != NULL) 866*36944Skarels (*closefunc)(fout); 867*36944Skarels return; 868*36944Skarels } 869*36944Skarels } 87011219Ssam while ((c = getc(din)) != EOF) { 87127749Sminshall while (c == '\r') { 87211651Ssam while (hash && (bytes >= hashbytes)) { 87326496Sminshall (void) putchar('#'); 87426496Sminshall (void) fflush(stdout); 87536940Skarels hashbytes += HASHBYTES; 87611651Ssam } 87710296Ssam bytes++; 87826048Sminshall if ((c = getc(din)) != '\n' || tcrflag) { 87936940Skarels if (ferror(fout)) 88036940Skarels goto break2; 88136940Skarels (void) putc('\r', fout); 88236942Skarels if (c == '\0') { 88336942Skarels bytes++; 88436940Skarels goto contin2; 88536942Skarels } 88636942Skarels if (c == EOF) 88736942Skarels goto contin2; 88811219Ssam } 88911219Ssam } 89036940Skarels (void) putc(c, fout); 89111219Ssam bytes++; 89236940Skarels contin2: ; 89310296Ssam } 89436940Skarels break2: 89511651Ssam if (hash) { 89613213Ssam if (bytes < hashbytes) 89726496Sminshall (void) putchar('#'); 89826496Sminshall (void) putchar('\n'); 89926496Sminshall (void) fflush(stdout); 90011651Ssam } 901*36944Skarels if (ferror(din)) { 90236935Skarels if (errno != EPIPE) 903*36944Skarels perror("netin"); 90436935Skarels bytes = -1; 90536935Skarels } 90636940Skarels if (ferror(fout)) 907*36944Skarels perror(local); 90811219Ssam break; 90910296Ssam } 91026448Slepreau if (closefunc != NULL) 91126048Sminshall (*closefunc)(fout); 91226496Sminshall (void) signal(SIGINT, oldintr); 91326448Slepreau if (oldintp) 91426048Sminshall (void) signal(SIGPIPE, oldintp); 91526496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 91610296Ssam (void) fclose(din); 91726048Sminshall (void) getreply(0); 91836935Skarels if (bytes > 0 && is_retr) 91926048Sminshall ptransfer("received", bytes, &start, &stop, local, remote); 92026048Sminshall if (oldtype) { 92126448Slepreau if (!debug) 92226048Sminshall verbose = 0; 92326048Sminshall switch (oldtype) { 92426048Sminshall case TYPE_I: 92526048Sminshall setbinary(); 92626048Sminshall break; 92726048Sminshall case TYPE_E: 92826048Sminshall setebcdic(); 92926048Sminshall break; 93026048Sminshall case TYPE_L: 93126048Sminshall settenex(); 93226048Sminshall break; 93326048Sminshall } 93426048Sminshall verbose = oldverbose; 93526048Sminshall } 93626048Sminshall return; 93726048Sminshall abort: 93826048Sminshall 93927687Sminshall /* abort using RFC959 recommended IP,SYNC sequence */ 94026048Sminshall 94126496Sminshall (void) gettimeofday(&stop, (struct timezone *)0); 94226448Slepreau if (oldintp) 94326048Sminshall (void) signal(SIGPIPE, oldintr); 94426048Sminshall (void) signal(SIGINT,SIG_IGN); 94526048Sminshall if (oldtype) { 94626448Slepreau if (!debug) 94726048Sminshall verbose = 0; 94826048Sminshall switch (oldtype) { 94926048Sminshall case TYPE_I: 95026048Sminshall setbinary(); 95126048Sminshall break; 95226048Sminshall case TYPE_E: 95326048Sminshall setebcdic(); 95426048Sminshall break; 95526048Sminshall case TYPE_L: 95626048Sminshall settenex(); 95726048Sminshall break; 95826048Sminshall } 95926048Sminshall verbose = oldverbose; 96026048Sminshall } 96126048Sminshall if (!cpend) { 96226048Sminshall code = -1; 96326048Sminshall (void) signal(SIGINT,oldintr); 96426048Sminshall return; 96526048Sminshall } 96626048Sminshall 96727687Sminshall fprintf(cout,"%c%c",IAC,IP); 96827687Sminshall (void) fflush(cout); 96927687Sminshall msg = IAC; 97027687Sminshall /* send IAC in urgent mode instead of DM because UNIX places oob mark */ 97127687Sminshall /* after urgent byte rather than before as now is protocol */ 97227687Sminshall if (send(fileno(cout),&msg,1,MSG_OOB) != 1) { 97327687Sminshall perror("abort"); 97426048Sminshall } 97527687Sminshall fprintf(cout,"%cABOR\r\n",DM); 97626048Sminshall (void) fflush(cout); 97727687Sminshall FD_ZERO(&mask); 97826496Sminshall FD_SET(fileno(cin), &mask); 97926496Sminshall if (din) { 98026496Sminshall FD_SET(fileno(din), &mask); 98126496Sminshall } 98227687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 98327687Sminshall if (nfnd < 0) { 98427687Sminshall perror("abort"); 98527687Sminshall } 98626048Sminshall code = -1; 98726048Sminshall lostpeer(); 98826048Sminshall } 98926496Sminshall if (din && FD_ISSET(fileno(din), &mask)) { 99036940Skarels while ((c = read(fileno(din), buf, bufsize)) > 0) 99126448Slepreau ; 99226496Sminshall } 99327687Sminshall if ((c = getreply(0)) == ERROR && code == 552) { /* needed for nic style abort */ 99426048Sminshall if (data >= 0) { 99526496Sminshall (void) close(data); 99626048Sminshall data = -1; 99726048Sminshall } 99825907Smckusick (void) getreply(0); 99925907Smckusick } 100026048Sminshall (void) getreply(0); 100126048Sminshall code = -1; 100226048Sminshall if (data >= 0) { 100326048Sminshall (void) close(data); 100426048Sminshall data = -1; 100526048Sminshall } 100626448Slepreau if (closefunc != NULL && fout != NULL) 100726048Sminshall (*closefunc)(fout); 100826448Slepreau if (din) 100926048Sminshall (void) fclose(din); 101035699Sbostic if (bytes > 0) 101126048Sminshall ptransfer("received", bytes, &start, &stop, local, remote); 101226048Sminshall (void) signal(SIGINT,oldintr); 101310296Ssam } 101410296Ssam 101510296Ssam /* 101610296Ssam * Need to start a listen on the data channel 101710296Ssam * before we send the command, otherwise the 101810296Ssam * server's connect may fail. 101910296Ssam */ 102033224Sbostic int sendport = -1; 102111651Ssam 102210296Ssam initconn() 102310296Ssam { 102410296Ssam register char *p, *a; 102526048Sminshall int result, len, tmpno = 0; 102626993Skarels int on = 1; 102710296Ssam 102811651Ssam noport: 102910296Ssam data_addr = myctladdr; 103011651Ssam if (sendport) 103111651Ssam data_addr.sin_port = 0; /* let system pick one */ 103211651Ssam if (data != -1) 103311651Ssam (void) close (data); 103418287Sralph data = socket(AF_INET, SOCK_STREAM, 0); 103510296Ssam if (data < 0) { 103610296Ssam perror("ftp: socket"); 103726448Slepreau if (tmpno) 103826048Sminshall sendport = 1; 103910296Ssam return (1); 104010296Ssam } 104112397Ssam if (!sendport) 104227687Sminshall if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { 104333224Sbostic perror("ftp: setsockopt (reuse address)"); 104412397Ssam goto bad; 104512397Ssam } 104626496Sminshall if (bind(data, (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { 104710296Ssam perror("ftp: bind"); 104810296Ssam goto bad; 104910296Ssam } 105010296Ssam if (options & SO_DEBUG && 105127687Sminshall setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) 105210296Ssam perror("ftp: setsockopt (ignored)"); 105311627Ssam len = sizeof (data_addr); 105411627Ssam if (getsockname(data, (char *)&data_addr, &len) < 0) { 105511627Ssam perror("ftp: getsockname"); 105610296Ssam goto bad; 105710296Ssam } 105826448Slepreau if (listen(data, 1) < 0) 105910296Ssam perror("ftp: listen"); 106011651Ssam if (sendport) { 106111651Ssam a = (char *)&data_addr.sin_addr; 106211651Ssam p = (char *)&data_addr.sin_port; 106310296Ssam #define UC(b) (((int)b)&0xff) 106411651Ssam result = 106511651Ssam command("PORT %d,%d,%d,%d,%d,%d", 106611651Ssam UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 106711651Ssam UC(p[0]), UC(p[1])); 106811651Ssam if (result == ERROR && sendport == -1) { 106911651Ssam sendport = 0; 107026048Sminshall tmpno = 1; 107111651Ssam goto noport; 107211651Ssam } 107311651Ssam return (result != COMPLETE); 107411651Ssam } 107526448Slepreau if (tmpno) 107626048Sminshall sendport = 1; 107711651Ssam return (0); 107810296Ssam bad: 107910296Ssam (void) close(data), data = -1; 108026448Slepreau if (tmpno) 108126048Sminshall sendport = 1; 108210296Ssam return (1); 108310296Ssam } 108410296Ssam 108510296Ssam FILE * 108610296Ssam dataconn(mode) 108710296Ssam char *mode; 108810296Ssam { 108910296Ssam struct sockaddr_in from; 109010296Ssam int s, fromlen = sizeof (from); 109110296Ssam 109226496Sminshall s = accept(data, (struct sockaddr *) &from, &fromlen); 109310296Ssam if (s < 0) { 109410296Ssam perror("ftp: accept"); 109510296Ssam (void) close(data), data = -1; 109610296Ssam return (NULL); 109710296Ssam } 109810296Ssam (void) close(data); 109910296Ssam data = s; 110010296Ssam return (fdopen(data, mode)); 110110296Ssam } 110210296Ssam 110326048Sminshall ptransfer(direction, bytes, t0, t1, local, remote) 110426048Sminshall char *direction, *local, *remote; 110511651Ssam long bytes; 110610296Ssam struct timeval *t0, *t1; 110710296Ssam { 110810296Ssam struct timeval td; 110916437Sleres float s, bs; 111010296Ssam 111135699Sbostic if (verbose) { 111235699Sbostic tvsub(&td, t1, t0); 111335699Sbostic s = td.tv_sec + (td.tv_usec / 1000000.); 111410296Ssam #define nz(x) ((x) == 0 ? 1 : (x)) 111535699Sbostic bs = bytes / nz(s); 111635699Sbostic printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n", 111735699Sbostic bytes, direction, s, bs / 1024.); 111835699Sbostic } else { 111935699Sbostic if (local && *local != '-') 112035699Sbostic printf("local: %s ", local); 112135699Sbostic if (remote) 112235699Sbostic printf("remote: %s\n", remote); 112335699Sbostic } 112410296Ssam } 112510296Ssam 112626496Sminshall /*tvadd(tsum, t0) 112710296Ssam struct timeval *tsum, *t0; 112810296Ssam { 112910296Ssam 113010296Ssam tsum->tv_sec += t0->tv_sec; 113110296Ssam tsum->tv_usec += t0->tv_usec; 113210296Ssam if (tsum->tv_usec > 1000000) 113310296Ssam tsum->tv_sec++, tsum->tv_usec -= 1000000; 113426496Sminshall } */ 113510296Ssam 113610296Ssam tvsub(tdiff, t1, t0) 113710296Ssam struct timeval *tdiff, *t1, *t0; 113810296Ssam { 113910296Ssam 114010296Ssam tdiff->tv_sec = t1->tv_sec - t0->tv_sec; 114110296Ssam tdiff->tv_usec = t1->tv_usec - t0->tv_usec; 114210296Ssam if (tdiff->tv_usec < 0) 114310296Ssam tdiff->tv_sec--, tdiff->tv_usec += 1000000; 114410296Ssam } 114526048Sminshall 114626048Sminshall psabort() 114726048Sminshall { 114826048Sminshall extern int abrtflag; 114926048Sminshall 115026048Sminshall abrtflag++; 115126048Sminshall } 115226048Sminshall 115326048Sminshall pswitch(flag) 115426048Sminshall int flag; 115526048Sminshall { 115626048Sminshall extern int proxy, abrtflag; 115726048Sminshall int (*oldintr)(); 115826048Sminshall static struct comvars { 115926048Sminshall int connect; 116028469Skarels char name[MAXHOSTNAMELEN]; 116126048Sminshall struct sockaddr_in mctl; 116226048Sminshall struct sockaddr_in hctl; 116326048Sminshall FILE *in; 116426048Sminshall FILE *out; 116526048Sminshall int tpe; 116626048Sminshall int cpnd; 116726048Sminshall int sunqe; 116826048Sminshall int runqe; 116926048Sminshall int mcse; 117026048Sminshall int ntflg; 117126048Sminshall char nti[17]; 117226048Sminshall char nto[17]; 117326048Sminshall int mapflg; 117426048Sminshall char mi[MAXPATHLEN]; 117526048Sminshall char mo[MAXPATHLEN]; 117626048Sminshall } proxstruct, tmpstruct; 117726048Sminshall struct comvars *ip, *op; 117826048Sminshall 117926048Sminshall abrtflag = 0; 118026048Sminshall oldintr = signal(SIGINT, psabort); 118126048Sminshall if (flag) { 118226448Slepreau if (proxy) 118326048Sminshall return; 118426048Sminshall ip = &tmpstruct; 118526048Sminshall op = &proxstruct; 118626048Sminshall proxy++; 118726048Sminshall } 118826048Sminshall else { 118926448Slepreau if (!proxy) 119026048Sminshall return; 119126048Sminshall ip = &proxstruct; 119226048Sminshall op = &tmpstruct; 119326048Sminshall proxy = 0; 119426048Sminshall } 119526048Sminshall ip->connect = connected; 119626048Sminshall connected = op->connect; 119728469Skarels if (hostname) { 119828469Skarels (void) strncpy(ip->name, hostname, sizeof(ip->name) - 1); 119928469Skarels ip->name[strlen(ip->name)] = '\0'; 120028469Skarels } else 120128469Skarels ip->name[0] = 0; 120226048Sminshall hostname = op->name; 120326048Sminshall ip->hctl = hisctladdr; 120426048Sminshall hisctladdr = op->hctl; 120526048Sminshall ip->mctl = myctladdr; 120626048Sminshall myctladdr = op->mctl; 120726048Sminshall ip->in = cin; 120826048Sminshall cin = op->in; 120926048Sminshall ip->out = cout; 121026048Sminshall cout = op->out; 121126048Sminshall ip->tpe = type; 121226048Sminshall type = op->tpe; 121326448Slepreau if (!type) 121426048Sminshall type = 1; 121526048Sminshall ip->cpnd = cpend; 121626048Sminshall cpend = op->cpnd; 121726048Sminshall ip->sunqe = sunique; 121826048Sminshall sunique = op->sunqe; 121926048Sminshall ip->runqe = runique; 122026048Sminshall runique = op->runqe; 122126048Sminshall ip->mcse = mcase; 122226048Sminshall mcase = op->mcse; 122326048Sminshall ip->ntflg = ntflag; 122426048Sminshall ntflag = op->ntflg; 122526496Sminshall (void) strncpy(ip->nti, ntin, 16); 122626048Sminshall (ip->nti)[strlen(ip->nti)] = '\0'; 122726496Sminshall (void) strcpy(ntin, op->nti); 122826496Sminshall (void) strncpy(ip->nto, ntout, 16); 122926048Sminshall (ip->nto)[strlen(ip->nto)] = '\0'; 123026496Sminshall (void) strcpy(ntout, op->nto); 123126048Sminshall ip->mapflg = mapflag; 123226048Sminshall mapflag = op->mapflg; 123326496Sminshall (void) strncpy(ip->mi, mapin, MAXPATHLEN - 1); 123426048Sminshall (ip->mi)[strlen(ip->mi)] = '\0'; 123526496Sminshall (void) strcpy(mapin, op->mi); 123626496Sminshall (void) strncpy(ip->mo, mapout, MAXPATHLEN - 1); 123726048Sminshall (ip->mo)[strlen(ip->mo)] = '\0'; 123826496Sminshall (void) strcpy(mapout, op->mo); 123926048Sminshall (void) signal(SIGINT, oldintr); 124026048Sminshall if (abrtflag) { 124126048Sminshall abrtflag = 0; 124226048Sminshall (*oldintr)(); 124326448Slepreau } 124426048Sminshall } 124526048Sminshall 124626048Sminshall jmp_buf ptabort; 124726048Sminshall int ptabflg; 124826048Sminshall 124926048Sminshall abortpt() 125026048Sminshall { 125126048Sminshall printf("\n"); 125226496Sminshall (void) fflush(stdout); 125326048Sminshall ptabflg++; 125426048Sminshall mflag = 0; 125526048Sminshall abrtflag = 0; 125626048Sminshall longjmp(ptabort, 1); 125726048Sminshall } 125826048Sminshall 125926048Sminshall proxtrans(cmd, local, remote) 126026048Sminshall char *cmd, *local, *remote; 126126048Sminshall { 126227687Sminshall int (*oldintr)(), abortpt(), tmptype, oldtype = 0, secndflag = 0, nfnd; 126326048Sminshall extern jmp_buf ptabort; 126426048Sminshall char *cmd2; 126526496Sminshall struct fd_set mask; 126626048Sminshall 126726448Slepreau if (strcmp(cmd, "RETR")) 126826048Sminshall cmd2 = "RETR"; 126926448Slepreau else 127026048Sminshall cmd2 = runique ? "STOU" : "STOR"; 127126048Sminshall if (command("PASV") != COMPLETE) { 127226048Sminshall printf("proxy server does not support third part transfers.\n"); 127326048Sminshall return; 127426048Sminshall } 127526048Sminshall tmptype = type; 127626048Sminshall pswitch(0); 127726048Sminshall if (!connected) { 127826048Sminshall printf("No primary connection\n"); 127926048Sminshall pswitch(1); 128026048Sminshall code = -1; 128126048Sminshall return; 128226048Sminshall } 128326048Sminshall if (type != tmptype) { 128426048Sminshall oldtype = type; 128526048Sminshall switch (tmptype) { 128626048Sminshall case TYPE_A: 128726048Sminshall setascii(); 128826048Sminshall break; 128926048Sminshall case TYPE_I: 129026048Sminshall setbinary(); 129126048Sminshall break; 129226048Sminshall case TYPE_E: 129326048Sminshall setebcdic(); 129426048Sminshall break; 129526048Sminshall case TYPE_L: 129626048Sminshall settenex(); 129726048Sminshall break; 129826048Sminshall } 129926048Sminshall } 130026048Sminshall if (command("PORT %s", pasv) != COMPLETE) { 130126048Sminshall switch (oldtype) { 130226048Sminshall case 0: 130326048Sminshall break; 130426048Sminshall case TYPE_A: 130526048Sminshall setascii(); 130626048Sminshall break; 130726048Sminshall case TYPE_I: 130826048Sminshall setbinary(); 130926048Sminshall break; 131026048Sminshall case TYPE_E: 131126048Sminshall setebcdic(); 131226048Sminshall break; 131326048Sminshall case TYPE_L: 131426048Sminshall settenex(); 131526048Sminshall break; 131626048Sminshall } 131726048Sminshall pswitch(1); 131826048Sminshall return; 131926048Sminshall } 132026448Slepreau if (setjmp(ptabort)) 132126048Sminshall goto abort; 132226048Sminshall oldintr = signal(SIGINT, abortpt); 132326048Sminshall if (command("%s %s", cmd, remote) != PRELIM) { 132426048Sminshall (void) signal(SIGINT, oldintr); 132526048Sminshall switch (oldtype) { 132626048Sminshall case 0: 132726048Sminshall break; 132826048Sminshall case TYPE_A: 132926048Sminshall setascii(); 133026048Sminshall break; 133126048Sminshall case TYPE_I: 133226048Sminshall setbinary(); 133326048Sminshall break; 133426048Sminshall case TYPE_E: 133526048Sminshall setebcdic(); 133626048Sminshall break; 133726048Sminshall case TYPE_L: 133826048Sminshall settenex(); 133926048Sminshall break; 134026048Sminshall } 134126048Sminshall pswitch(1); 134226048Sminshall return; 134326048Sminshall } 134426048Sminshall sleep(2); 134526048Sminshall pswitch(1); 134626048Sminshall secndflag++; 134726448Slepreau if (command("%s %s", cmd2, local) != PRELIM) 134826048Sminshall goto abort; 134926048Sminshall ptflag++; 135026048Sminshall (void) getreply(0); 135126048Sminshall pswitch(0); 135226048Sminshall (void) getreply(0); 135326048Sminshall (void) signal(SIGINT, oldintr); 135426048Sminshall switch (oldtype) { 135526048Sminshall case 0: 135626048Sminshall break; 135726048Sminshall case TYPE_A: 135826048Sminshall setascii(); 135926048Sminshall break; 136026048Sminshall case TYPE_I: 136126048Sminshall setbinary(); 136226048Sminshall break; 136326048Sminshall case TYPE_E: 136426048Sminshall setebcdic(); 136526048Sminshall break; 136626048Sminshall case TYPE_L: 136726048Sminshall settenex(); 136826048Sminshall break; 136926048Sminshall } 137026048Sminshall pswitch(1); 137126048Sminshall ptflag = 0; 137226048Sminshall printf("local: %s remote: %s\n", local, remote); 137326048Sminshall return; 137426048Sminshall abort: 137526048Sminshall (void) signal(SIGINT, SIG_IGN); 137626048Sminshall ptflag = 0; 137726448Slepreau if (strcmp(cmd, "RETR") && !proxy) 137826048Sminshall pswitch(1); 137926448Slepreau else if (!strcmp(cmd, "RETR") && proxy) 138026048Sminshall pswitch(0); 138126048Sminshall if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ 138226048Sminshall if (command("%s %s", cmd2, local) != PRELIM) { 138326048Sminshall pswitch(0); 138426048Sminshall switch (oldtype) { 138526048Sminshall case 0: 138626048Sminshall break; 138726048Sminshall case TYPE_A: 138826048Sminshall setascii(); 138926048Sminshall break; 139026048Sminshall case TYPE_I: 139126048Sminshall setbinary(); 139226048Sminshall break; 139326048Sminshall case TYPE_E: 139426048Sminshall setebcdic(); 139526048Sminshall break; 139626048Sminshall case TYPE_L: 139726048Sminshall settenex(); 139826048Sminshall break; 139926048Sminshall } 140027687Sminshall if (cpend) { 140126048Sminshall char msg[2]; 140226048Sminshall 140326048Sminshall fprintf(cout,"%c%c",IAC,IP); 140426048Sminshall (void) fflush(cout); 140526048Sminshall *msg = IAC; 140626048Sminshall *(msg+1) = DM; 140726448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 140826048Sminshall perror("abort"); 140926048Sminshall fprintf(cout,"ABOR\r\n"); 141026048Sminshall (void) fflush(cout); 141127687Sminshall FD_ZERO(&mask); 141226496Sminshall FD_SET(fileno(cin), &mask); 141327687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 141427687Sminshall if (nfnd < 0) { 141527687Sminshall perror("abort"); 141627687Sminshall } 141726448Slepreau if (ptabflg) 141826048Sminshall code = -1; 141926048Sminshall lostpeer(); 142026048Sminshall } 142126048Sminshall (void) getreply(0); 142226048Sminshall (void) getreply(0); 142326048Sminshall } 142426048Sminshall } 142526048Sminshall pswitch(1); 142626448Slepreau if (ptabflg) 142726048Sminshall code = -1; 142826048Sminshall (void) signal(SIGINT, oldintr); 142926048Sminshall return; 143026048Sminshall } 143127687Sminshall if (cpend) { 143226048Sminshall char msg[2]; 143326048Sminshall 143426048Sminshall fprintf(cout,"%c%c",IAC,IP); 143526048Sminshall (void) fflush(cout); 143626048Sminshall *msg = IAC; 143726048Sminshall *(msg+1) = DM; 143826448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 143926048Sminshall perror("abort"); 144026048Sminshall fprintf(cout,"ABOR\r\n"); 144126048Sminshall (void) fflush(cout); 144227687Sminshall FD_ZERO(&mask); 144326496Sminshall FD_SET(fileno(cin), &mask); 144427687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 144527687Sminshall if (nfnd < 0) { 144627687Sminshall perror("abort"); 144727687Sminshall } 144826448Slepreau if (ptabflg) 144926048Sminshall code = -1; 145026048Sminshall lostpeer(); 145126048Sminshall } 145226048Sminshall (void) getreply(0); 145326048Sminshall (void) getreply(0); 145426048Sminshall } 145526048Sminshall pswitch(!proxy); 145626048Sminshall if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ 145726048Sminshall if (command("%s %s", cmd2, local) != PRELIM) { 145826048Sminshall pswitch(0); 145926048Sminshall switch (oldtype) { 146026048Sminshall case 0: 146126048Sminshall break; 146226048Sminshall case TYPE_A: 146326048Sminshall setascii(); 146426048Sminshall break; 146526048Sminshall case TYPE_I: 146626048Sminshall setbinary(); 146726048Sminshall break; 146826048Sminshall case TYPE_E: 146926048Sminshall setebcdic(); 147026048Sminshall break; 147126048Sminshall case TYPE_L: 147226048Sminshall settenex(); 147326048Sminshall break; 147426048Sminshall } 147527687Sminshall if (cpend) { 147626048Sminshall char msg[2]; 147726048Sminshall 147826048Sminshall fprintf(cout,"%c%c",IAC,IP); 147926048Sminshall (void) fflush(cout); 148026048Sminshall *msg = IAC; 148126048Sminshall *(msg+1) = DM; 148226448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 148326048Sminshall perror("abort"); 148426048Sminshall fprintf(cout,"ABOR\r\n"); 148526048Sminshall (void) fflush(cout); 148627687Sminshall FD_ZERO(&mask); 148726496Sminshall FD_SET(fileno(cin), &mask); 148827687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 148927687Sminshall if (nfnd < 0) { 149027687Sminshall perror("abort"); 149127687Sminshall } 149226448Slepreau if (ptabflg) 149326048Sminshall code = -1; 149426048Sminshall lostpeer(); 149526048Sminshall } 149626048Sminshall (void) getreply(0); 149726048Sminshall (void) getreply(0); 149826048Sminshall } 149926048Sminshall pswitch(1); 150026448Slepreau if (ptabflg) 150126048Sminshall code = -1; 150226048Sminshall (void) signal(SIGINT, oldintr); 150326048Sminshall return; 150426048Sminshall } 150526048Sminshall } 150627687Sminshall if (cpend) { 150726048Sminshall char msg[2]; 150826048Sminshall 150926048Sminshall fprintf(cout,"%c%c",IAC,IP); 151026048Sminshall (void) fflush(cout); 151126048Sminshall *msg = IAC; 151226048Sminshall *(msg+1) = DM; 151326448Slepreau if (send(fileno(cout),msg,2,MSG_OOB) != 2) 151426048Sminshall perror("abort"); 151526048Sminshall fprintf(cout,"ABOR\r\n"); 151626048Sminshall (void) fflush(cout); 151727687Sminshall FD_ZERO(&mask); 151826496Sminshall FD_SET(fileno(cin), &mask); 151927687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 152027687Sminshall if (nfnd < 0) { 152127687Sminshall perror("abort"); 152227687Sminshall } 152326448Slepreau if (ptabflg) 152426048Sminshall code = -1; 152526048Sminshall lostpeer(); 152626048Sminshall } 152726048Sminshall (void) getreply(0); 152826048Sminshall (void) getreply(0); 152926048Sminshall } 153026048Sminshall pswitch(!proxy); 153126048Sminshall if (cpend) { 153227687Sminshall FD_ZERO(&mask); 153326496Sminshall FD_SET(fileno(cin), &mask); 153427687Sminshall if ((nfnd = empty(&mask,10)) <= 0) { 153527687Sminshall if (nfnd < 0) { 153627687Sminshall perror("abort"); 153727687Sminshall } 153826448Slepreau if (ptabflg) 153926048Sminshall code = -1; 154026048Sminshall lostpeer(); 154126048Sminshall } 154226048Sminshall (void) getreply(0); 154326048Sminshall (void) getreply(0); 154426048Sminshall } 154526448Slepreau if (proxy) 154626048Sminshall pswitch(0); 154726048Sminshall switch (oldtype) { 154826048Sminshall case 0: 154926048Sminshall break; 155026048Sminshall case TYPE_A: 155126048Sminshall setascii(); 155226048Sminshall break; 155326048Sminshall case TYPE_I: 155426048Sminshall setbinary(); 155526048Sminshall break; 155626048Sminshall case TYPE_E: 155726048Sminshall setebcdic(); 155826048Sminshall break; 155926048Sminshall case TYPE_L: 156026048Sminshall settenex(); 156126048Sminshall break; 156226048Sminshall } 156326048Sminshall pswitch(1); 156426448Slepreau if (ptabflg) 156526048Sminshall code = -1; 156626048Sminshall (void) signal(SIGINT, oldintr); 156726048Sminshall } 156826048Sminshall 156926048Sminshall reset() 157026048Sminshall { 157126496Sminshall struct fd_set mask; 157226496Sminshall int nfnd = 1; 157326048Sminshall 157427687Sminshall FD_ZERO(&mask); 157530946Scsvsj while (nfnd > 0) { 157626496Sminshall FD_SET(fileno(cin), &mask); 157727687Sminshall if ((nfnd = empty(&mask,0)) < 0) { 157826048Sminshall perror("reset"); 157926048Sminshall code = -1; 158026048Sminshall lostpeer(); 158126048Sminshall } 158227687Sminshall else if (nfnd) { 158326048Sminshall (void) getreply(0); 158426496Sminshall } 158526048Sminshall } 158626048Sminshall } 158726048Sminshall 158826048Sminshall char * 158926048Sminshall gunique(local) 159026048Sminshall char *local; 159126048Sminshall { 159226048Sminshall static char new[MAXPATHLEN]; 159326048Sminshall char *cp = rindex(local, '/'); 159426048Sminshall int d, count=0; 159526048Sminshall char ext = '1'; 159626048Sminshall 159726448Slepreau if (cp) 159826048Sminshall *cp = '\0'; 159926048Sminshall d = access(cp ? local : ".", 2); 160026448Slepreau if (cp) 160126048Sminshall *cp = '/'; 160226048Sminshall if (d < 0) { 160326048Sminshall perror(local); 160426048Sminshall return((char *) 0); 160526048Sminshall } 160626048Sminshall (void) strcpy(new, local); 160726048Sminshall cp = new + strlen(new); 160826048Sminshall *cp++ = '.'; 160926048Sminshall while (!d) { 161026048Sminshall if (++count == 100) { 161126048Sminshall printf("runique: can't find unique file name.\n"); 161226048Sminshall return((char *) 0); 161326048Sminshall } 161426048Sminshall *cp++ = ext; 161526048Sminshall *cp = '\0'; 161626448Slepreau if (ext == '9') 161726048Sminshall ext = '0'; 161826448Slepreau else 161926048Sminshall ext++; 162026448Slepreau if ((d = access(new, 0)) < 0) 162126048Sminshall break; 162226448Slepreau if (ext != '0') 162326048Sminshall cp--; 162426448Slepreau else if (*(cp - 2) == '.') 162526048Sminshall *(cp - 1) = '1'; 162626048Sminshall else { 162726048Sminshall *(cp - 2) = *(cp - 2) + 1; 162826048Sminshall cp--; 162926048Sminshall } 163026048Sminshall } 163126048Sminshall return(new); 163226048Sminshall } 1633