Annotation of src/usr.bin/ftp/ftp.c, Revision 1.20
1.20 ! millert 1: /* $OpenBSD: ftp.c,v 1.19 1997/06/17 20:40:40 kstailey Exp $ */
! 2: /* $NetBSD: ftp.c,v 1.26 1997/07/20 09:45:53 lukem Exp $ */
1.1 deraadt 3:
4: /*
5: * Copyright (c) 1985, 1989, 1993, 1994
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
37: #ifndef lint
38: #if 0
39: static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
40: #else
1.20 ! millert 41: static char rcsid[] = "$OpenBSD: ftp.c,v 1.19 1997/06/17 20:40:40 kstailey Exp $";
1.1 deraadt 42: #endif
43: #endif /* not lint */
44:
1.10 millert 45: #include <sys/types.h>
1.1 deraadt 46: #include <sys/stat.h>
47: #include <sys/socket.h>
48:
49: #include <netinet/in.h>
50: #include <netinet/in_systm.h>
51: #include <netinet/ip.h>
52: #include <arpa/inet.h>
53: #include <arpa/ftp.h>
54: #include <arpa/telnet.h>
55:
56: #include <ctype.h>
57: #include <err.h>
58: #include <errno.h>
59: #include <netdb.h>
60: #include <stdio.h>
61: #include <stdlib.h>
62: #include <string.h>
63: #include <unistd.h>
1.12 millert 64: #include <utime.h>
1.13 millert 65: #ifdef __STDC__
66: #include <stdarg.h>
67: #else
1.1 deraadt 68: #include <varargs.h>
1.13 millert 69: #endif
1.1 deraadt 70:
71: #include "ftp_var.h"
72:
73: struct sockaddr_in hisctladdr;
74: struct sockaddr_in data_addr;
75: int data = -1;
76: int abrtflag = 0;
77: jmp_buf ptabort;
78: int ptabflg;
79: int ptflag = 0;
80: struct sockaddr_in myctladdr;
81: off_t restart_point = 0;
82:
83:
84: FILE *cin, *cout;
85:
86: char *
87: hookup(host, port)
1.10 millert 88: const char *host;
1.20 ! millert 89: in_port_t port;
1.1 deraadt 90: {
1.20 ! millert 91: struct hostent *hp = NULL;
1.1 deraadt 92: int s, len, tos;
1.10 millert 93: static char hostnamebuf[MAXHOSTNAMELEN];
1.1 deraadt 94:
1.12 millert 95: memset((void *)&hisctladdr, 0, sizeof(hisctladdr));
1.1 deraadt 96: if (inet_aton(host, &hisctladdr.sin_addr) != 0) {
97: hisctladdr.sin_family = AF_INET;
1.11 millert 98: (void)strncpy(hostnamebuf, host, sizeof(hostnamebuf) - 1);
99: hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
1.1 deraadt 100: } else {
101: hp = gethostbyname(host);
102: if (hp == NULL) {
103: warnx("%s: %s", host, hstrerror(h_errno));
104: code = -1;
105: return ((char *) 0);
106: }
107: hisctladdr.sin_family = hp->h_addrtype;
1.20 ! millert 108: memcpy(&hisctladdr.sin_addr, hp->h_addr_list[0],
! 109: (size_t)hp->h_length);
1.11 millert 110: (void)strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf) - 1);
111: hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
1.1 deraadt 112: }
113: hostname = hostnamebuf;
114: s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
115: if (s < 0) {
116: warn("socket");
117: code = -1;
118: return (0);
119: }
120: hisctladdr.sin_port = port;
1.10 millert 121: while (connect(s, (struct sockaddr *)&hisctladdr,
1.11 millert 122: sizeof(hisctladdr)) < 0) {
1.1 deraadt 123: if (hp && hp->h_addr_list[1]) {
124: int oerrno = errno;
125: char *ia;
126:
127: ia = inet_ntoa(hisctladdr.sin_addr);
128: errno = oerrno;
129: warn("connect to address %s", ia);
130: hp->h_addr_list++;
1.11 millert 131: memcpy(&hisctladdr.sin_addr, hp->h_addr_list[0],
1.20 ! millert 132: (size_t)hp->h_length);
1.18 deraadt 133: fprintf(ttyout, "Trying %s...\n", inet_ntoa(hisctladdr.sin_addr));
1.11 millert 134: (void)close(s);
1.1 deraadt 135: s = socket(hisctladdr.sin_family, SOCK_STREAM, 0);
136: if (s < 0) {
137: warn("socket");
138: code = -1;
139: return (0);
140: }
141: continue;
142: }
143: warn("connect");
144: code = -1;
145: goto bad;
146: }
1.11 millert 147: len = sizeof(myctladdr);
1.1 deraadt 148: if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
149: warn("getsockname");
150: code = -1;
151: goto bad;
152: }
153: #ifdef IP_TOS
154: tos = IPTOS_LOWDELAY;
155: if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
156: warn("setsockopt TOS (ignored)");
157: #endif
158: cin = fdopen(s, "r");
159: cout = fdopen(s, "w");
160: if (cin == NULL || cout == NULL) {
161: warnx("fdopen failed.");
162: if (cin)
1.11 millert 163: (void)fclose(cin);
1.1 deraadt 164: if (cout)
1.11 millert 165: (void)fclose(cout);
1.1 deraadt 166: code = -1;
167: goto bad;
168: }
169: if (verbose)
1.18 deraadt 170: fprintf(ttyout, "Connected to %s.\n", hostname);
1.1 deraadt 171: if (getreply(0) > 2) { /* read startup message from server */
172: if (cin)
1.11 millert 173: (void)fclose(cin);
1.1 deraadt 174: if (cout)
1.11 millert 175: (void)fclose(cout);
1.1 deraadt 176: code = -1;
177: goto bad;
178: }
179: #ifdef SO_OOBINLINE
180: {
181: int on = 1;
182:
183: if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
184: < 0 && debug) {
185: warn("setsockopt");
186: }
187: }
188: #endif /* SO_OOBINLINE */
189:
190: return (hostname);
191: bad:
1.11 millert 192: (void)close(s);
1.1 deraadt 193: return ((char *)0);
194: }
195:
196: void
1.12 millert 197: cmdabort(notused)
198: int notused;
1.1 deraadt 199: {
200:
1.10 millert 201: alarmtimer(0);
1.18 deraadt 202: putc('\n', ttyout);
203: (void)fflush(ttyout);
1.1 deraadt 204: abrtflag++;
205: if (ptflag)
1.10 millert 206: longjmp(ptabort, 1);
1.1 deraadt 207: }
208:
209: /*VARARGS*/
210: int
1.13 millert 211: #ifdef __STDC__
212: command(const char *fmt, ...)
213: #else
1.1 deraadt 214: command(va_alist)
1.13 millert 215: va_dcl
216: #endif
1.1 deraadt 217: {
218: va_list ap;
219: int r;
220: sig_t oldintr;
1.13 millert 221: #ifndef __STDC__
222: const char *fmt;
223: #endif
1.1 deraadt 224:
225: abrtflag = 0;
226: if (debug) {
1.18 deraadt 227: fputs("---> ", ttyout);
1.13 millert 228: #ifdef __STDC__
229: va_start(ap, fmt);
230: #else
1.1 deraadt 231: va_start(ap);
1.13 millert 232: fmt = va_arg(ap, const char *);
233: #endif
1.1 deraadt 234: if (strncmp("PASS ", fmt, 5) == 0)
1.18 deraadt 235: fputs("PASS XXXX", ttyout);
1.10 millert 236: else if (strncmp("ACCT ", fmt, 5) == 0)
1.18 deraadt 237: fputs("ACCT XXXX", ttyout);
1.10 millert 238: else
1.11 millert 239: vprintf(fmt, ap);
1.1 deraadt 240: va_end(ap);
1.18 deraadt 241: putc('\n', ttyout);
242: (void)fflush(ttyout);
1.1 deraadt 243: }
244: if (cout == NULL) {
1.13 millert 245: warnx("No control connection for command.");
1.1 deraadt 246: code = -1;
247: return (0);
248: }
249: oldintr = signal(SIGINT, cmdabort);
1.13 millert 250: #ifdef __STDC__
251: va_start(ap, fmt);
252: #else
1.1 deraadt 253: va_start(ap);
254: fmt = va_arg(ap, char *);
1.13 millert 255: #endif
1.1 deraadt 256: vfprintf(cout, fmt, ap);
257: va_end(ap);
1.11 millert 258: fputs("\r\n", cout);
259: (void)fflush(cout);
1.1 deraadt 260: cpend = 1;
261: r = getreply(!strcmp(fmt, "QUIT"));
262: if (abrtflag && oldintr != SIG_IGN)
263: (*oldintr)(SIGINT);
1.11 millert 264: (void)signal(SIGINT, oldintr);
1.1 deraadt 265: return (r);
266: }
267:
1.10 millert 268: char reply_string[BUFSIZ]; /* first line of previous reply */
1.1 deraadt 269:
270: int
271: getreply(expecteof)
272: int expecteof;
273: {
1.10 millert 274: char current_line[BUFSIZ]; /* last line of previous reply */
275: int c, n, line;
1.1 deraadt 276: int dig;
277: int originalcode = 0, continuation = 0;
278: sig_t oldintr;
279: int pflag = 0;
280: char *cp, *pt = pasv;
281:
282: oldintr = signal(SIGINT, cmdabort);
1.10 millert 283: for (line = 0 ;; line++) {
1.1 deraadt 284: dig = n = code = 0;
1.10 millert 285: cp = current_line;
1.1 deraadt 286: while ((c = getc(cin)) != '\n') {
287: if (c == IAC) { /* handle telnet commands */
288: switch (c = getc(cin)) {
289: case WILL:
290: case WONT:
291: c = getc(cin);
292: fprintf(cout, "%c%c%c", IAC, DONT, c);
1.11 millert 293: (void)fflush(cout);
1.1 deraadt 294: break;
295: case DO:
296: case DONT:
297: c = getc(cin);
298: fprintf(cout, "%c%c%c", IAC, WONT, c);
1.11 millert 299: (void)fflush(cout);
1.1 deraadt 300: break;
301: default:
302: break;
303: }
304: continue;
305: }
306: dig++;
307: if (c == EOF) {
308: if (expecteof) {
1.11 millert 309: (void)signal(SIGINT, oldintr);
1.1 deraadt 310: code = 221;
311: return (0);
312: }
313: lostpeer();
314: if (verbose) {
1.18 deraadt 315: fputs(
316: "421 Service not available, remote server has closed connection.\n", ttyout);
317: (void)fflush(ttyout);
1.1 deraadt 318: }
319: code = 421;
320: return (4);
321: }
1.10 millert 322: if (c != '\r' && (verbose > 0 ||
1.11 millert 323: (verbose > -1 && n == '5' && dig > 4)) &&
324: (n < '5' || !retry_connect)) {
1.1 deraadt 325: if (proxflag &&
1.10 millert 326: (dig == 1 || (dig == 5 && verbose == 0)))
1.18 deraadt 327: fprintf(ttyout, "%s:", hostname);
328: (void)putc(c, ttyout);
1.1 deraadt 329: }
330: if (dig < 4 && isdigit(c))
331: code = code * 10 + (c - '0');
332: if (!pflag && code == 227)
333: pflag = 1;
334: if (dig > 4 && pflag == 1 && isdigit(c))
335: pflag = 2;
336: if (pflag == 2) {
337: if (c != '\r' && c != ')')
338: *pt++ = c;
339: else {
340: *pt = '\0';
341: pflag = 3;
342: }
343: }
344: if (dig == 4 && c == '-') {
345: if (continuation)
346: code = 0;
347: continuation++;
348: }
1.10 millert 349: if (n == 0)
350: n = c;
351: if (cp < ¤t_line[sizeof(current_line) - 1])
1.1 deraadt 352: *cp++ = c;
353: }
1.11 millert 354: if (verbose > 0 || ((verbose > -1 && n == '5') &&
355: (n < '5' || !retry_connect))) {
1.18 deraadt 356: (void)putc(c, ttyout);
357: (void)fflush (ttyout);
1.1 deraadt 358: }
1.10 millert 359: if (line == 0) {
360: size_t len = cp - current_line;
361:
362: if (len > sizeof(reply_string))
363: len = sizeof(reply_string);
364:
1.11 millert 365: (void)strncpy(reply_string, current_line, len);
1.10 millert 366: reply_string[len] = '\0';
367: }
1.1 deraadt 368: if (continuation && code != originalcode) {
369: if (originalcode == 0)
370: originalcode = code;
371: continue;
372: }
373: *cp = '\0';
374: if (n != '1')
375: cpend = 0;
1.11 millert 376: (void)signal(SIGINT, oldintr);
1.1 deraadt 377: if (code == 421 || originalcode == 421)
378: lostpeer();
379: if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
380: (*oldintr)(SIGINT);
381: return (n - '0');
382: }
383: }
384:
385: int
386: empty(mask, sec)
387: struct fd_set *mask;
388: int sec;
389: {
390: struct timeval t;
391:
392: t.tv_sec = (long) sec;
393: t.tv_usec = 0;
394: return (select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
395: }
396:
397: jmp_buf sendabort;
398:
399: void
1.12 millert 400: abortsend(notused)
401: int notused;
1.1 deraadt 402: {
403:
1.10 millert 404: alarmtimer(0);
1.1 deraadt 405: mflag = 0;
406: abrtflag = 0;
1.18 deraadt 407: fputs("\nsend aborted\nwaiting for remote to finish abort.\n", ttyout);
408: (void)fflush(ttyout);
1.1 deraadt 409: longjmp(sendabort, 1);
410: }
411:
412: void
413: sendrequest(cmd, local, remote, printnames)
1.10 millert 414: const char *cmd, *local, *remote;
1.1 deraadt 415: int printnames;
416: {
417: struct stat st;
418: int c, d;
1.20 ! millert 419: FILE *fin, *dout;
1.1 deraadt 420: int (*closefunc) __P((FILE *));
1.10 millert 421: sig_t oldinti, oldintr, oldintp;
1.20 ! millert 422: volatile off_t hashbytes;
1.1 deraadt 423: char *lmode, buf[BUFSIZ], *bufp;
1.13 millert 424: int oprogress;
1.1 deraadt 425:
1.20 ! millert 426: #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
! 427: (void)&fin;
! 428: (void)&dout;
! 429: (void)&closefunc;
! 430: (void)&oldinti;
! 431: (void)&oldintr;
! 432: (void)&oldintp;
! 433: (void)&lmode;
! 434: #endif
! 435:
1.10 millert 436: hashbytes = mark;
437: direction = "sent";
1.20 ! millert 438: dout = NULL;
1.10 millert 439: bytes = 0;
440: filesize = -1;
1.13 millert 441: oprogress = progress;
1.1 deraadt 442: if (verbose && printnames) {
443: if (local && *local != '-')
1.18 deraadt 444: fprintf(ttyout, "local: %s ", local);
1.1 deraadt 445: if (remote)
1.18 deraadt 446: fprintf(ttyout, "remote: %s\n", remote);
1.1 deraadt 447: }
448: if (proxy) {
449: proxtrans(cmd, local, remote);
450: return;
451: }
452: if (curtype != type)
453: changetype(type, 0);
454: closefunc = NULL;
455: oldintr = NULL;
456: oldintp = NULL;
1.10 millert 457: oldinti = NULL;
1.1 deraadt 458: lmode = "w";
459: if (setjmp(sendabort)) {
460: while (cpend) {
1.11 millert 461: (void)getreply(0);
1.1 deraadt 462: }
463: if (data >= 0) {
1.11 millert 464: (void)close(data);
1.1 deraadt 465: data = -1;
466: }
467: if (oldintr)
1.11 millert 468: (void)signal(SIGINT, oldintr);
1.1 deraadt 469: if (oldintp)
1.11 millert 470: (void)signal(SIGPIPE, oldintp);
1.10 millert 471: if (oldinti)
1.11 millert 472: (void)signal(SIGINFO, oldinti);
1.13 millert 473: progress = oprogress;
1.1 deraadt 474: code = -1;
475: return;
476: }
477: oldintr = signal(SIGINT, abortsend);
1.10 millert 478: oldinti = signal(SIGINFO, psummary);
1.13 millert 479: if (strcmp(local, "-") == 0) {
1.1 deraadt 480: fin = stdin;
1.13 millert 481: progress = 0;
482: } else if (*local == '|') {
1.10 millert 483: oldintp = signal(SIGPIPE, SIG_IGN);
1.1 deraadt 484: fin = popen(local + 1, "r");
485: if (fin == NULL) {
486: warn("%s", local + 1);
1.11 millert 487: (void)signal(SIGINT, oldintr);
488: (void)signal(SIGPIPE, oldintp);
489: (void)signal(SIGINFO, oldinti);
1.1 deraadt 490: code = -1;
491: return;
492: }
1.13 millert 493: progress = 0;
1.1 deraadt 494: closefunc = pclose;
495: } else {
496: fin = fopen(local, "r");
497: if (fin == NULL) {
498: warn("local: %s", local);
1.11 millert 499: (void)signal(SIGINT, oldintr);
500: (void)signal(SIGINFO, oldinti);
1.1 deraadt 501: code = -1;
502: return;
503: }
504: closefunc = fclose;
505: if (fstat(fileno(fin), &st) < 0 ||
1.14 millert 506: (st.st_mode & S_IFMT) != S_IFREG) {
1.18 deraadt 507: fprintf(ttyout, "%s: not a plain file.\n", local);
1.11 millert 508: (void)signal(SIGINT, oldintr);
509: (void)signal(SIGINFO, oldinti);
1.1 deraadt 510: fclose(fin);
511: code = -1;
512: return;
513: }
1.10 millert 514: filesize = st.st_size;
1.1 deraadt 515: }
516: if (initconn()) {
1.11 millert 517: (void)signal(SIGINT, oldintr);
518: (void)signal(SIGINFO, oldinti);
1.1 deraadt 519: if (oldintp)
1.11 millert 520: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 521: code = -1;
1.13 millert 522: progress = oprogress;
1.1 deraadt 523: if (closefunc != NULL)
524: (*closefunc)(fin);
525: return;
526: }
527: if (setjmp(sendabort))
528: goto abort;
529:
530: if (restart_point &&
531: (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
532: int rc;
533:
1.10 millert 534: rc = -1;
1.1 deraadt 535: switch (curtype) {
536: case TYPE_A:
537: rc = fseek(fin, (long) restart_point, SEEK_SET);
538: break;
539: case TYPE_I:
540: case TYPE_L:
541: rc = lseek(fileno(fin), restart_point, SEEK_SET);
542: break;
543: }
544: if (rc < 0) {
545: warn("local: %s", local);
546: restart_point = 0;
1.13 millert 547: progress = oprogress;
1.1 deraadt 548: if (closefunc != NULL)
549: (*closefunc)(fin);
550: return;
551: }
552: if (command("REST %ld", (long) restart_point)
553: != CONTINUE) {
554: restart_point = 0;
1.13 millert 555: progress = oprogress;
1.1 deraadt 556: if (closefunc != NULL)
557: (*closefunc)(fin);
558: return;
559: }
560: restart_point = 0;
561: lmode = "r+w";
562: }
563: if (remote) {
564: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 565: (void)signal(SIGINT, oldintr);
566: (void)signal(SIGINFO, oldinti);
1.13 millert 567: progress = oprogress;
1.1 deraadt 568: if (oldintp)
1.11 millert 569: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 570: if (closefunc != NULL)
571: (*closefunc)(fin);
572: return;
573: }
574: } else
575: if (command("%s", cmd) != PRELIM) {
1.11 millert 576: (void)signal(SIGINT, oldintr);
577: (void)signal(SIGINFO, oldinti);
1.13 millert 578: progress = oprogress;
1.1 deraadt 579: if (oldintp)
1.11 millert 580: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 581: if (closefunc != NULL)
582: (*closefunc)(fin);
583: return;
584: }
585: dout = dataconn(lmode);
586: if (dout == NULL)
587: goto abort;
1.10 millert 588: progressmeter(-1);
1.1 deraadt 589: oldintp = signal(SIGPIPE, SIG_IGN);
590: switch (curtype) {
591:
592: case TYPE_I:
593: case TYPE_L:
594: errno = d = 0;
1.11 millert 595: while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
1.1 deraadt 596: bytes += c;
597: for (bufp = buf; c > 0; c -= d, bufp += d)
1.20 ! millert 598: if ((d = write(fileno(dout), bufp, (size_t)c))
! 599: <= 0)
1.1 deraadt 600: break;
1.10 millert 601: if (hash && (!progress || filesize < 0) ) {
1.1 deraadt 602: while (bytes >= hashbytes) {
1.18 deraadt 603: (void)putc('#', ttyout);
1.7 kstailey 604: hashbytes += mark;
1.1 deraadt 605: }
1.18 deraadt 606: (void)fflush(ttyout);
1.1 deraadt 607: }
608: }
1.10 millert 609: if (hash && (!progress || filesize < 0) && bytes > 0) {
1.7 kstailey 610: if (bytes < mark)
1.18 deraadt 611: (void)putc('#', ttyout);
612: (void)putc('\n', ttyout);
613: (void)fflush(ttyout);
1.1 deraadt 614: }
615: if (c < 0)
616: warn("local: %s", local);
617: if (d < 0) {
1.10 millert 618: if (errno != EPIPE)
1.1 deraadt 619: warn("netout");
620: bytes = -1;
621: }
622: break;
623:
624: case TYPE_A:
625: while ((c = getc(fin)) != EOF) {
626: if (c == '\n') {
1.10 millert 627: while (hash && (!progress || filesize < 0) &&
628: (bytes >= hashbytes)) {
1.18 deraadt 629: (void)putc('#', ttyout);
630: (void)fflush(ttyout);
1.7 kstailey 631: hashbytes += mark;
1.1 deraadt 632: }
633: if (ferror(dout))
634: break;
1.11 millert 635: (void)putc('\r', dout);
1.1 deraadt 636: bytes++;
637: }
1.11 millert 638: (void)putc(c, dout);
1.1 deraadt 639: bytes++;
1.10 millert 640: #if 0 /* this violates RFC */
641: if (c == '\r') {
642: (void)putc('\0', dout);
643: bytes++;
644: }
645: #endif
1.1 deraadt 646: }
1.10 millert 647: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 648: if (bytes < hashbytes)
1.18 deraadt 649: (void)putc('#', ttyout);
650: (void)putc('\n', ttyout);
651: (void)fflush(ttyout);
1.1 deraadt 652: }
653: if (ferror(fin))
654: warn("local: %s", local);
655: if (ferror(dout)) {
656: if (errno != EPIPE)
657: warn("netout");
658: bytes = -1;
659: }
660: break;
661: }
1.10 millert 662: progressmeter(1);
1.13 millert 663: progress = oprogress;
1.1 deraadt 664: if (closefunc != NULL)
665: (*closefunc)(fin);
1.11 millert 666: (void)fclose(dout);
667: (void)getreply(0);
668: (void)signal(SIGINT, oldintr);
669: (void)signal(SIGINFO, oldinti);
1.1 deraadt 670: if (oldintp)
1.11 millert 671: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 672: if (bytes > 0)
1.10 millert 673: ptransfer(0);
1.1 deraadt 674: return;
675: abort:
1.11 millert 676: (void)signal(SIGINT, oldintr);
677: (void)signal(SIGINFO, oldinti);
1.13 millert 678: progress = oprogress;
1.1 deraadt 679: if (oldintp)
1.11 millert 680: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 681: if (!cpend) {
682: code = -1;
683: return;
684: }
685: if (data >= 0) {
1.11 millert 686: (void)close(data);
1.1 deraadt 687: data = -1;
688: }
689: if (dout)
1.11 millert 690: (void)fclose(dout);
691: (void)getreply(0);
1.1 deraadt 692: code = -1;
693: if (closefunc != NULL && fin != NULL)
694: (*closefunc)(fin);
695: if (bytes > 0)
1.10 millert 696: ptransfer(0);
1.1 deraadt 697: }
698:
699: jmp_buf recvabort;
700:
701: void
1.12 millert 702: abortrecv(notused)
703: int notused;
1.1 deraadt 704: {
705:
1.10 millert 706: alarmtimer(0);
1.1 deraadt 707: mflag = 0;
708: abrtflag = 0;
1.18 deraadt 709: fputs("\nreceive aborted\nwaiting for remote to finish abort.\n", ttyout);
710: (void)fflush(ttyout);
1.1 deraadt 711: longjmp(recvabort, 1);
712: }
713:
714: void
715: recvrequest(cmd, local, remote, lmode, printnames)
1.10 millert 716: const char *cmd, *local, *remote, *lmode;
1.1 deraadt 717: int printnames;
718: {
1.20 ! millert 719: FILE *fout, *din;
1.1 deraadt 720: int (*closefunc) __P((FILE *));
1.10 millert 721: sig_t oldinti, oldintr, oldintp;
1.20 ! millert 722: int c, d;
! 723: volatile int is_retr, tcrflag, bare_lfs;
! 724: static size_t bufsize;
1.1 deraadt 725: static char *buf;
1.20 ! millert 726: volatile off_t hashbytes;
1.1 deraadt 727: struct stat st;
1.10 millert 728: time_t mtime;
1.13 millert 729: int oprogress;
1.16 millert 730: int opreserve;
1.1 deraadt 731:
1.20 ! millert 732: #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
! 733: (void)&local;
! 734: (void)&fout;
! 735: (void)&din;
! 736: (void)&closefunc;
! 737: (void)&oldinti;
! 738: (void)&oldintr;
! 739: (void)&oldintp;
! 740: #endif
! 741:
! 742: fout = NULL;
! 743: din = NULL;
! 744: oldinti = NULL;
1.10 millert 745: hashbytes = mark;
746: direction = "received";
747: bytes = 0;
1.20 ! millert 748: bare_lfs = 0;
1.10 millert 749: filesize = -1;
1.13 millert 750: oprogress = progress;
1.16 millert 751: opreserve = preserve;
1.1 deraadt 752: is_retr = strcmp(cmd, "RETR") == 0;
753: if (is_retr && verbose && printnames) {
754: if (local && *local != '-')
1.18 deraadt 755: fprintf(ttyout, "local: %s ", local);
1.1 deraadt 756: if (remote)
1.18 deraadt 757: fprintf(ttyout, "remote: %s\n", remote);
1.1 deraadt 758: }
759: if (proxy && is_retr) {
760: proxtrans(cmd, local, remote);
761: return;
762: }
763: closefunc = NULL;
764: oldintr = NULL;
765: oldintp = NULL;
766: tcrflag = !crflag && is_retr;
767: if (setjmp(recvabort)) {
768: while (cpend) {
1.11 millert 769: (void)getreply(0);
1.1 deraadt 770: }
771: if (data >= 0) {
1.11 millert 772: (void)close(data);
1.1 deraadt 773: data = -1;
774: }
775: if (oldintr)
1.11 millert 776: (void)signal(SIGINT, oldintr);
1.10 millert 777: if (oldinti)
1.11 millert 778: (void)signal(SIGINFO, oldinti);
1.15 millert 779: progress = oprogress;
1.16 millert 780: preserve = opreserve;
1.1 deraadt 781: code = -1;
782: return;
783: }
784: oldintr = signal(SIGINT, abortrecv);
1.10 millert 785: oldinti = signal(SIGINFO, psummary);
1.1 deraadt 786: if (strcmp(local, "-") && *local != '|') {
787: if (access(local, 2) < 0) {
788: char *dir = strrchr(local, '/');
789:
790: if (errno != ENOENT && errno != EACCES) {
791: warn("local: %s", local);
1.11 millert 792: (void)signal(SIGINT, oldintr);
793: (void)signal(SIGINFO, oldinti);
1.1 deraadt 794: code = -1;
795: return;
796: }
797: if (dir != NULL)
798: *dir = 0;
1.10 millert 799: d = access(dir == local ? "/" : dir ? local : ".", 2);
1.1 deraadt 800: if (dir != NULL)
801: *dir = '/';
802: if (d < 0) {
803: warn("local: %s", local);
1.11 millert 804: (void)signal(SIGINT, oldintr);
805: (void)signal(SIGINFO, oldinti);
1.1 deraadt 806: code = -1;
807: return;
808: }
809: if (!runique && errno == EACCES &&
1.20 ! millert 810: chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
1.1 deraadt 811: warn("local: %s", local);
1.11 millert 812: (void)signal(SIGINT, oldintr);
813: (void)signal(SIGINFO, oldinti);
1.1 deraadt 814: code = -1;
815: return;
816: }
817: if (runique && errno == EACCES &&
818: (local = gunique(local)) == NULL) {
1.11 millert 819: (void)signal(SIGINT, oldintr);
820: (void)signal(SIGINFO, oldinti);
1.1 deraadt 821: code = -1;
822: return;
823: }
824: }
825: else if (runique && (local = gunique(local)) == NULL) {
1.11 millert 826: (void)signal(SIGINT, oldintr);
827: (void)signal(SIGINFO, oldinti);
1.1 deraadt 828: code = -1;
829: return;
830: }
831: }
832: if (!is_retr) {
833: if (curtype != TYPE_A)
834: changetype(TYPE_A, 0);
1.10 millert 835: } else {
836: if (curtype != type)
837: changetype(type, 0);
838: filesize = remotesize(remote, 0);
839: }
1.1 deraadt 840: if (initconn()) {
1.11 millert 841: (void)signal(SIGINT, oldintr);
842: (void)signal(SIGINFO, oldinti);
1.1 deraadt 843: code = -1;
844: return;
845: }
846: if (setjmp(recvabort))
847: goto abort;
848: if (is_retr && restart_point &&
849: command("REST %ld", (long) restart_point) != CONTINUE)
850: return;
851: if (remote) {
852: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 853: (void)signal(SIGINT, oldintr);
854: (void)signal(SIGINFO, oldinti);
1.1 deraadt 855: return;
856: }
857: } else {
858: if (command("%s", cmd) != PRELIM) {
1.11 millert 859: (void)signal(SIGINT, oldintr);
860: (void)signal(SIGINFO, oldinti);
1.1 deraadt 861: return;
862: }
863: }
864: din = dataconn("r");
865: if (din == NULL)
866: goto abort;
1.13 millert 867: if (strcmp(local, "-") == 0) {
1.1 deraadt 868: fout = stdout;
1.13 millert 869: progress = 0;
1.16 millert 870: preserve = 0;
1.13 millert 871: } else if (*local == '|') {
1.1 deraadt 872: oldintp = signal(SIGPIPE, SIG_IGN);
873: fout = popen(local + 1, "w");
874: if (fout == NULL) {
875: warn("%s", local+1);
876: goto abort;
877: }
1.13 millert 878: progress = 0;
1.16 millert 879: preserve = 0;
1.1 deraadt 880: closefunc = pclose;
881: } else {
882: fout = fopen(local, lmode);
883: if (fout == NULL) {
884: warn("local: %s", local);
885: goto abort;
886: }
887: closefunc = fclose;
888: }
889: if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
890: st.st_blksize = BUFSIZ;
891: if (st.st_blksize > bufsize) {
892: if (buf)
1.11 millert 893: (void)free(buf);
1.1 deraadt 894: buf = malloc((unsigned)st.st_blksize);
895: if (buf == NULL) {
896: warn("malloc");
897: bufsize = 0;
898: goto abort;
899: }
900: bufsize = st.st_blksize;
901: }
1.14 millert 902: if ((st.st_mode & S_IFMT) != S_IFREG) {
1.13 millert 903: progress = 0;
904: preserve = 0;
905: }
1.10 millert 906: progressmeter(-1);
1.1 deraadt 907: switch (curtype) {
908:
909: case TYPE_I:
910: case TYPE_L:
911: if (restart_point &&
912: lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
913: warn("local: %s", local);
1.13 millert 914: progress = oprogress;
1.16 millert 915: preserve = opreserve;
1.1 deraadt 916: if (closefunc != NULL)
917: (*closefunc)(fout);
918: return;
919: }
920: errno = d = 0;
921: while ((c = read(fileno(din), buf, bufsize)) > 0) {
1.20 ! millert 922: if ((d = write(fileno(fout), buf, (size_t)c)) != c)
1.1 deraadt 923: break;
924: bytes += c;
1.10 millert 925: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 926: while (bytes >= hashbytes) {
1.18 deraadt 927: (void)putc('#', ttyout);
1.7 kstailey 928: hashbytes += mark;
1.1 deraadt 929: }
1.18 deraadt 930: (void)fflush(ttyout);
1.1 deraadt 931: }
932: }
1.10 millert 933: if (hash && (!progress || filesize < 0) && bytes > 0) {
1.7 kstailey 934: if (bytes < mark)
1.18 deraadt 935: (void)putc('#', ttyout);
936: (void)putc('\n', ttyout);
937: (void)fflush(ttyout);
1.1 deraadt 938: }
939: if (c < 0) {
940: if (errno != EPIPE)
941: warn("netin");
942: bytes = -1;
943: }
944: if (d < c) {
945: if (d < 0)
946: warn("local: %s", local);
947: else
948: warnx("%s: short write", local);
949: }
950: break;
951:
952: case TYPE_A:
953: if (restart_point) {
954: int i, n, ch;
955:
956: if (fseek(fout, 0L, SEEK_SET) < 0)
957: goto done;
958: n = restart_point;
959: for (i = 0; i++ < n;) {
960: if ((ch = getc(fout)) == EOF)
961: goto done;
962: if (ch == '\n')
963: i++;
964: }
965: if (fseek(fout, 0L, SEEK_CUR) < 0) {
966: done:
967: warn("local: %s", local);
1.13 millert 968: progress = oprogress;
1.16 millert 969: preserve = opreserve;
1.1 deraadt 970: if (closefunc != NULL)
971: (*closefunc)(fout);
972: return;
973: }
974: }
975: while ((c = getc(din)) != EOF) {
976: if (c == '\n')
977: bare_lfs++;
978: while (c == '\r') {
1.10 millert 979: while (hash && (!progress || filesize < 0) &&
980: (bytes >= hashbytes)) {
1.18 deraadt 981: (void)putc('#', ttyout);
982: (void)fflush(ttyout);
1.7 kstailey 983: hashbytes += mark;
1.1 deraadt 984: }
985: bytes++;
986: if ((c = getc(din)) != '\n' || tcrflag) {
987: if (ferror(fout))
988: goto break2;
1.11 millert 989: (void)putc('\r', fout);
1.1 deraadt 990: if (c == '\0') {
991: bytes++;
992: goto contin2;
993: }
994: if (c == EOF)
995: goto contin2;
996: }
997: }
1.11 millert 998: (void)putc(c, fout);
1.1 deraadt 999: bytes++;
1000: contin2: ;
1001: }
1002: break2:
1003: if (bare_lfs) {
1.13 millert 1004: printf(
1005: "WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
1.18 deraadt 1006: fputs("File may not have transferred correctly.\n", ttyout);
1.1 deraadt 1007: }
1.10 millert 1008: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 1009: if (bytes < hashbytes)
1.18 deraadt 1010: (void)putc('#', ttyout);
1011: (void)putc('\n', ttyout);
1012: (void)fflush(ttyout);
1.1 deraadt 1013: }
1014: if (ferror(din)) {
1015: if (errno != EPIPE)
1016: warn("netin");
1017: bytes = -1;
1018: }
1019: if (ferror(fout))
1020: warn("local: %s", local);
1021: break;
1022: }
1.10 millert 1023: progressmeter(1);
1.13 millert 1024: progress = oprogress;
1.16 millert 1025: preserve = opreserve;
1.1 deraadt 1026: if (closefunc != NULL)
1027: (*closefunc)(fout);
1.11 millert 1028: (void)signal(SIGINT, oldintr);
1029: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1030: if (oldintp)
1.11 millert 1031: (void)signal(SIGPIPE, oldintp);
1032: (void)fclose(din);
1033: (void)getreply(0);
1.10 millert 1034: if (bytes >= 0 && is_retr) {
1035: if (bytes > 0)
1036: ptransfer(0);
1037: if (preserve && (closefunc == fclose)) {
1038: mtime = remotemodtime(remote, 0);
1039: if (mtime != -1) {
1.12 millert 1040: struct utimbuf ut;
1041:
1042: ut.actime = time(NULL);
1043: ut.modtime = mtime;
1044: if (utime(local, &ut) == -1)
1.13 millert 1045: printf(
1046: "Can't change modification time on %s to %s",
1.11 millert 1047: local, asctime(localtime(&mtime)));
1.10 millert 1048: }
1049: }
1050: }
1.1 deraadt 1051: return;
1.13 millert 1052:
1.1 deraadt 1053: abort:
1054:
1.10 millert 1055: /* abort using RFC959 recommended IP,SYNC sequence */
1.1 deraadt 1056:
1.13 millert 1057: progress = oprogress;
1.16 millert 1058: preserve = opreserve;
1.1 deraadt 1059: if (oldintp)
1.11 millert 1060: (void)signal(SIGPIPE, oldintp);
1061: (void)signal(SIGINT, SIG_IGN);
1.1 deraadt 1062: if (!cpend) {
1063: code = -1;
1.11 millert 1064: (void)signal(SIGINT, oldintr);
1065: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1066: return;
1067: }
1068:
1069: abort_remote(din);
1070: code = -1;
1071: if (data >= 0) {
1.11 millert 1072: (void)close(data);
1.1 deraadt 1073: data = -1;
1074: }
1075: if (closefunc != NULL && fout != NULL)
1076: (*closefunc)(fout);
1077: if (din)
1.11 millert 1078: (void)fclose(din);
1.1 deraadt 1079: if (bytes > 0)
1.10 millert 1080: ptransfer(0);
1.11 millert 1081: (void)signal(SIGINT, oldintr);
1082: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1083: }
1084:
1085: /*
1086: * Need to start a listen on the data channel before we send the command,
1087: * otherwise the server's connect may fail.
1088: */
1089: int
1090: initconn()
1091: {
1092: char *p, *a;
1093: int result, len, tmpno = 0;
1094: int on = 1;
1095: int a0, a1, a2, a3, p0, p1;
1096:
1097: if (passivemode) {
1098: data = socket(AF_INET, SOCK_STREAM, 0);
1099: if (data < 0) {
1.10 millert 1100: warn("socket");
1101: return (1);
1.1 deraadt 1102: }
1103: if ((options & SO_DEBUG) &&
1104: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1.11 millert 1105: sizeof(on)) < 0)
1.10 millert 1106: warn("setsockopt (ignored)");
1.1 deraadt 1107: if (command("PASV") != COMPLETE) {
1.18 deraadt 1108: fputs("Passive mode refused.\n", ttyout);
1.1 deraadt 1109: goto bad;
1110: }
1111:
1112: /*
1113: * What we've got at this point is a string of comma
1114: * separated one-byte unsigned integer values.
1115: * The first four are the an IP address. The fifth is
1116: * the MSB of the port number, the sixth is the LSB.
1117: * From that we'll prepare a sockaddr_in.
1118: */
1119:
1.10 millert 1120: if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
1.1 deraadt 1121: &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
1.18 deraadt 1122: fputs(
1123: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1.1 deraadt 1124: goto bad;
1125: }
1126:
1.10 millert 1127: memset(&data_addr, 0, sizeof(data_addr));
1.1 deraadt 1128: data_addr.sin_family = AF_INET;
1129: a = (char *)&data_addr.sin_addr.s_addr;
1130: a[0] = a0 & 0xff;
1131: a[1] = a1 & 0xff;
1132: a[2] = a2 & 0xff;
1133: a[3] = a3 & 0xff;
1134: p = (char *)&data_addr.sin_port;
1135: p[0] = p0 & 0xff;
1136: p[1] = p1 & 0xff;
1137:
1138: if (connect(data, (struct sockaddr *)&data_addr,
1139: sizeof(data_addr)) < 0) {
1.10 millert 1140: warn("connect");
1.1 deraadt 1141: goto bad;
1142: }
1143: #ifdef IP_TOS
1144: on = IPTOS_THROUGHPUT;
1145: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1146: sizeof(int)) < 0)
1.10 millert 1147: warn("setsockopt TOS (ignored)");
1.1 deraadt 1148: #endif
1.10 millert 1149: return (0);
1.1 deraadt 1150: }
1151:
1152: noport:
1153: data_addr = myctladdr;
1154: if (sendport)
1.10 millert 1155: data_addr.sin_port = 0; /* let system pick one */
1.1 deraadt 1156: if (data != -1)
1.11 millert 1157: (void)close(data);
1.1 deraadt 1158: data = socket(AF_INET, SOCK_STREAM, 0);
1159: if (data < 0) {
1160: warn("socket");
1161: if (tmpno)
1162: sendport = 1;
1163: return (1);
1164: }
1165: if (!sendport)
1.10 millert 1166: if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1.11 millert 1167: sizeof(on)) < 0) {
1.1 deraadt 1168: warn("setsockopt (reuse address)");
1169: goto bad;
1170: }
1.11 millert 1171: if (bind(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0) {
1.1 deraadt 1172: warn("bind");
1173: goto bad;
1174: }
1175: if (options & SO_DEBUG &&
1.10 millert 1176: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1.11 millert 1177: sizeof(on)) < 0)
1.1 deraadt 1178: warn("setsockopt (ignored)");
1.11 millert 1179: len = sizeof(data_addr);
1.1 deraadt 1180: if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1181: warn("getsockname");
1182: goto bad;
1183: }
1184: if (listen(data, 1) < 0)
1185: warn("listen");
1186: if (sendport) {
1187: a = (char *)&data_addr.sin_addr;
1188: p = (char *)&data_addr.sin_port;
1189: #define UC(b) (((int)b)&0xff)
1190: result =
1191: command("PORT %d,%d,%d,%d,%d,%d",
1192: UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1193: UC(p[0]), UC(p[1]));
1194: if (result == ERROR && sendport == -1) {
1195: sendport = 0;
1196: tmpno = 1;
1197: goto noport;
1198: }
1199: return (result != COMPLETE);
1200: }
1201: if (tmpno)
1202: sendport = 1;
1203: #ifdef IP_TOS
1204: on = IPTOS_THROUGHPUT;
1205: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1206: warn("setsockopt TOS (ignored)");
1207: #endif
1208: return (0);
1209: bad:
1.11 millert 1210: (void)close(data), data = -1;
1.1 deraadt 1211: if (tmpno)
1212: sendport = 1;
1213: return (1);
1214: }
1215:
1216: FILE *
1217: dataconn(lmode)
1.10 millert 1218: const char *lmode;
1.1 deraadt 1219: {
1220: struct sockaddr_in from;
1.13 millert 1221: int s, fromlen, tos;
1222:
1223: fromlen = sizeof(from);
1.1 deraadt 1224:
1225: if (passivemode)
1226: return (fdopen(data, lmode));
1227:
1228: s = accept(data, (struct sockaddr *) &from, &fromlen);
1229: if (s < 0) {
1230: warn("accept");
1.11 millert 1231: (void)close(data), data = -1;
1.1 deraadt 1232: return (NULL);
1233: }
1.11 millert 1234: (void)close(data);
1.1 deraadt 1235: data = s;
1236: #ifdef IP_TOS
1237: tos = IPTOS_THROUGHPUT;
1238: if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1239: warn("setsockopt TOS (ignored)");
1240: #endif
1241: return (fdopen(data, lmode));
1242: }
1243:
1244: void
1.10 millert 1245: psummary(notused)
1246: int notused;
1.1 deraadt 1247: {
1.10 millert 1248:
1249: if (bytes > 0)
1250: ptransfer(1);
1.1 deraadt 1251: }
1252:
1253: void
1.12 millert 1254: psabort(notused)
1255: int notused;
1.1 deraadt 1256: {
1257:
1.10 millert 1258: alarmtimer(0);
1.1 deraadt 1259: abrtflag++;
1260: }
1261:
1262: void
1263: pswitch(flag)
1264: int flag;
1265: {
1266: sig_t oldintr;
1267: static struct comvars {
1268: int connect;
1269: char name[MAXHOSTNAMELEN];
1270: struct sockaddr_in mctl;
1271: struct sockaddr_in hctl;
1272: FILE *in;
1273: FILE *out;
1274: int tpe;
1275: int curtpe;
1276: int cpnd;
1277: int sunqe;
1278: int runqe;
1279: int mcse;
1280: int ntflg;
1281: char nti[17];
1282: char nto[17];
1283: int mapflg;
1284: char mi[MAXPATHLEN];
1285: char mo[MAXPATHLEN];
1286: } proxstruct, tmpstruct;
1287: struct comvars *ip, *op;
1288:
1289: abrtflag = 0;
1290: oldintr = signal(SIGINT, psabort);
1291: if (flag) {
1292: if (proxy)
1293: return;
1294: ip = &tmpstruct;
1295: op = &proxstruct;
1296: proxy++;
1297: } else {
1298: if (!proxy)
1299: return;
1300: ip = &proxstruct;
1301: op = &tmpstruct;
1302: proxy = 0;
1303: }
1304: ip->connect = connected;
1305: connected = op->connect;
1306: if (hostname) {
1.11 millert 1307: (void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1308: ip->name[sizeof(ip->name) - 1] = '\0';
1.1 deraadt 1309: } else
1.11 millert 1310: ip->name[0] = '\0';
1.1 deraadt 1311: hostname = op->name;
1312: ip->hctl = hisctladdr;
1313: hisctladdr = op->hctl;
1314: ip->mctl = myctladdr;
1315: myctladdr = op->mctl;
1316: ip->in = cin;
1317: cin = op->in;
1318: ip->out = cout;
1319: cout = op->out;
1320: ip->tpe = type;
1321: type = op->tpe;
1322: ip->curtpe = curtype;
1323: curtype = op->curtpe;
1324: ip->cpnd = cpend;
1325: cpend = op->cpnd;
1326: ip->sunqe = sunique;
1327: sunique = op->sunqe;
1328: ip->runqe = runique;
1329: runique = op->runqe;
1330: ip->mcse = mcase;
1331: mcase = op->mcse;
1332: ip->ntflg = ntflag;
1333: ntflag = op->ntflg;
1.11 millert 1334: (void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1335: (ip->nti)[sizeof(ip->nti) - 1] = '\0';
1336: (void)strcpy(ntin, op->nti);
1337: (void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1338: (ip->nto)[sizeof(ip->nto) - 1] = '\0';
1339: (void)strcpy(ntout, op->nto);
1.1 deraadt 1340: ip->mapflg = mapflag;
1341: mapflag = op->mapflg;
1.11 millert 1342: (void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1343: (ip->mi)[sizeof(ip->mi) - 1] = '\0';
1344: (void)strcpy(mapin, op->mi);
1345: (void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1346: (ip->mo)[sizeof(ip->mo) - 1] = '\0';
1347: (void)strcpy(mapout, op->mo);
1348: (void)signal(SIGINT, oldintr);
1.1 deraadt 1349: if (abrtflag) {
1350: abrtflag = 0;
1351: (*oldintr)(SIGINT);
1352: }
1353: }
1354:
1355: void
1.12 millert 1356: abortpt(notused)
1357: int notused;
1.1 deraadt 1358: {
1359:
1.10 millert 1360: alarmtimer(0);
1.18 deraadt 1361: putc('\n', ttyout);
1362: (void)fflush(ttyout);
1.1 deraadt 1363: ptabflg++;
1364: mflag = 0;
1365: abrtflag = 0;
1366: longjmp(ptabort, 1);
1367: }
1368:
1369: void
1370: proxtrans(cmd, local, remote)
1.10 millert 1371: const char *cmd, *local, *remote;
1.1 deraadt 1372: {
1373: sig_t oldintr;
1.20 ! millert 1374: int prox_type, nfnd;
! 1375: volatile int secndflag;
1.1 deraadt 1376: char *cmd2;
1377: struct fd_set mask;
1378:
1.20 ! millert 1379: #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
! 1380: (void)&oldintr;
! 1381: (void)&cmd2;
! 1382: #endif
! 1383:
! 1384: oldintr = NULL;
! 1385: secndflag = 0;
1.1 deraadt 1386: if (strcmp(cmd, "RETR"))
1387: cmd2 = "RETR";
1388: else
1389: cmd2 = runique ? "STOU" : "STOR";
1390: if ((prox_type = type) == 0) {
1391: if (unix_server && unix_proxy)
1392: prox_type = TYPE_I;
1393: else
1394: prox_type = TYPE_A;
1395: }
1396: if (curtype != prox_type)
1397: changetype(prox_type, 1);
1398: if (command("PASV") != COMPLETE) {
1.18 deraadt 1399: fputs("proxy server does not support third party transfers.\n",
1400: ttyout);
1.1 deraadt 1401: return;
1402: }
1403: pswitch(0);
1404: if (!connected) {
1.18 deraadt 1405: fputs("No primary connection.\n", ttyout);
1.1 deraadt 1406: pswitch(1);
1407: code = -1;
1408: return;
1409: }
1410: if (curtype != prox_type)
1411: changetype(prox_type, 1);
1412: if (command("PORT %s", pasv) != COMPLETE) {
1413: pswitch(1);
1414: return;
1415: }
1416: if (setjmp(ptabort))
1417: goto abort;
1418: oldintr = signal(SIGINT, abortpt);
1419: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 1420: (void)signal(SIGINT, oldintr);
1.1 deraadt 1421: pswitch(1);
1422: return;
1423: }
1424: sleep(2);
1425: pswitch(1);
1426: secndflag++;
1427: if (command("%s %s", cmd2, local) != PRELIM)
1428: goto abort;
1429: ptflag++;
1.11 millert 1430: (void)getreply(0);
1.1 deraadt 1431: pswitch(0);
1.11 millert 1432: (void)getreply(0);
1433: (void)signal(SIGINT, oldintr);
1.1 deraadt 1434: pswitch(1);
1435: ptflag = 0;
1.18 deraadt 1436: fprintf(ttyout, "local: %s remote: %s\n", local, remote);
1.1 deraadt 1437: return;
1438: abort:
1.11 millert 1439: (void)signal(SIGINT, SIG_IGN);
1.1 deraadt 1440: ptflag = 0;
1441: if (strcmp(cmd, "RETR") && !proxy)
1442: pswitch(1);
1443: else if (!strcmp(cmd, "RETR") && proxy)
1444: pswitch(0);
1445: if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1446: if (command("%s %s", cmd2, local) != PRELIM) {
1447: pswitch(0);
1448: if (cpend)
1.19 kstailey 1449: abort_remote(NULL);
1.1 deraadt 1450: }
1451: pswitch(1);
1452: if (ptabflg)
1453: code = -1;
1.11 millert 1454: (void)signal(SIGINT, oldintr);
1.1 deraadt 1455: return;
1456: }
1457: if (cpend)
1.19 kstailey 1458: abort_remote(NULL);
1.1 deraadt 1459: pswitch(!proxy);
1460: if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1461: if (command("%s %s", cmd2, local) != PRELIM) {
1462: pswitch(0);
1463: if (cpend)
1.19 kstailey 1464: abort_remote(NULL);
1.1 deraadt 1465: pswitch(1);
1466: if (ptabflg)
1467: code = -1;
1.11 millert 1468: (void)signal(SIGINT, oldintr);
1.1 deraadt 1469: return;
1470: }
1471: }
1472: if (cpend)
1.19 kstailey 1473: abort_remote(NULL);
1.1 deraadt 1474: pswitch(!proxy);
1475: if (cpend) {
1476: FD_ZERO(&mask);
1477: FD_SET(fileno(cin), &mask);
1478: if ((nfnd = empty(&mask, 10)) <= 0) {
1479: if (nfnd < 0) {
1480: warn("abort");
1481: }
1482: if (ptabflg)
1483: code = -1;
1484: lostpeer();
1485: }
1.11 millert 1486: (void)getreply(0);
1487: (void)getreply(0);
1.1 deraadt 1488: }
1489: if (proxy)
1490: pswitch(0);
1491: pswitch(1);
1492: if (ptabflg)
1493: code = -1;
1.11 millert 1494: (void)signal(SIGINT, oldintr);
1.1 deraadt 1495: }
1496:
1497: void
1498: reset(argc, argv)
1499: int argc;
1500: char *argv[];
1501: {
1502: struct fd_set mask;
1503: int nfnd = 1;
1504:
1505: FD_ZERO(&mask);
1506: while (nfnd > 0) {
1507: FD_SET(fileno(cin), &mask);
1.10 millert 1508: if ((nfnd = empty(&mask, 0)) < 0) {
1.1 deraadt 1509: warn("reset");
1510: code = -1;
1511: lostpeer();
1512: }
1513: else if (nfnd) {
1.11 millert 1514: (void)getreply(0);
1.1 deraadt 1515: }
1516: }
1517: }
1518:
1519: char *
1520: gunique(local)
1.10 millert 1521: const char *local;
1.1 deraadt 1522: {
1523: static char new[MAXPATHLEN];
1524: char *cp = strrchr(local, '/');
1525: int d, count=0;
1526: char ext = '1';
1527:
1528: if (cp)
1529: *cp = '\0';
1.10 millert 1530: d = access(cp == local ? "/" : cp ? local : ".", 2);
1.1 deraadt 1531: if (cp)
1532: *cp = '/';
1533: if (d < 0) {
1534: warn("local: %s", local);
1535: return ((char *) 0);
1536: }
1.11 millert 1537: (void)strcpy(new, local);
1.1 deraadt 1538: cp = new + strlen(new);
1539: *cp++ = '.';
1540: while (!d) {
1541: if (++count == 100) {
1.18 deraadt 1542: fputs("runique: can't find unique file name.\n", ttyout);
1.1 deraadt 1543: return ((char *) 0);
1544: }
1545: *cp++ = ext;
1546: *cp = '\0';
1547: if (ext == '9')
1548: ext = '0';
1549: else
1550: ext++;
1551: if ((d = access(new, 0)) < 0)
1552: break;
1553: if (ext != '0')
1554: cp--;
1555: else if (*(cp - 2) == '.')
1556: *(cp - 1) = '1';
1557: else {
1558: *(cp - 2) = *(cp - 2) + 1;
1559: cp--;
1560: }
1561: }
1562: return (new);
1563: }
1564:
1565: void
1566: abort_remote(din)
1567: FILE *din;
1568: {
1569: char buf[BUFSIZ];
1570: int nfnd;
1571: struct fd_set mask;
1.13 millert 1572:
1573: if (cout == NULL) {
1574: warnx("Lost control connection for abort.");
1575: if (ptabflg)
1576: code = -1;
1577: lostpeer();
1578: return;
1579: }
1.1 deraadt 1580:
1581: /*
1582: * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1583: * after urgent byte rather than before as is protocol now
1584: */
1585: sprintf(buf, "%c%c%c", IAC, IP, IAC);
1586: if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1587: warn("abort");
1.10 millert 1588: fprintf(cout, "%cABOR\r\n", DM);
1.11 millert 1589: (void)fflush(cout);
1.1 deraadt 1590: FD_ZERO(&mask);
1591: FD_SET(fileno(cin), &mask);
1.10 millert 1592: if (din) {
1.1 deraadt 1593: FD_SET(fileno(din), &mask);
1594: }
1595: if ((nfnd = empty(&mask, 10)) <= 0) {
1596: if (nfnd < 0) {
1597: warn("abort");
1598: }
1599: if (ptabflg)
1600: code = -1;
1601: lostpeer();
1602: }
1603: if (din && FD_ISSET(fileno(din), &mask)) {
1604: while (read(fileno(din), buf, BUFSIZ) > 0)
1605: /* LOOP */;
1606: }
1607: if (getreply(0) == ERROR && code == 552) {
1608: /* 552 needed for nic style abort */
1.11 millert 1609: (void)getreply(0);
1.1 deraadt 1610: }
1.11 millert 1611: (void)getreply(0);
1.1 deraadt 1612: }