Annotation of src/usr.bin/ftp/ftp.c, Revision 1.26
1.26 ! deraadt 1: /* $OpenBSD: ftp.c,v 1.25 1998/02/10 02:13:10 weingart Exp $ */
1.22 millert 2: /* $NetBSD: ftp.c,v 1.27 1997/08/18 10:20:23 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.26 ! deraadt 41: static char rcsid[] = "$OpenBSD: ftp.c,v 1.25 1998/02/10 02:13:10 weingart 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:
1.25 weingart 282: memset(current_line, 0, sizeof(current_line));
1.1 deraadt 283: oldintr = signal(SIGINT, cmdabort);
1.10 millert 284: for (line = 0 ;; line++) {
1.1 deraadt 285: dig = n = code = 0;
1.10 millert 286: cp = current_line;
1.23 millert 287: while ((c = fgetc(cin)) != '\n') {
1.1 deraadt 288: if (c == IAC) { /* handle telnet commands */
1.23 millert 289: switch (c = fgetc(cin)) {
1.1 deraadt 290: case WILL:
291: case WONT:
1.23 millert 292: c = fgetc(cin);
1.1 deraadt 293: fprintf(cout, "%c%c%c", IAC, DONT, c);
1.11 millert 294: (void)fflush(cout);
1.1 deraadt 295: break;
296: case DO:
297: case DONT:
1.23 millert 298: c = fgetc(cin);
1.1 deraadt 299: fprintf(cout, "%c%c%c", IAC, WONT, c);
1.11 millert 300: (void)fflush(cout);
1.1 deraadt 301: break;
302: default:
303: break;
304: }
305: continue;
306: }
307: dig++;
308: if (c == EOF) {
309: if (expecteof) {
1.11 millert 310: (void)signal(SIGINT, oldintr);
1.1 deraadt 311: code = 221;
312: return (0);
313: }
314: lostpeer();
315: if (verbose) {
1.18 deraadt 316: fputs(
317: "421 Service not available, remote server has closed connection.\n", ttyout);
318: (void)fflush(ttyout);
1.1 deraadt 319: }
320: code = 421;
321: return (4);
322: }
1.10 millert 323: if (c != '\r' && (verbose > 0 ||
1.21 mickey 324: ((verbose > -1 && n == '5' && dig > 4)) &&
325: (((!n && c < '5') || (n && n < '5'))
326: || !retry_connect))) {
1.1 deraadt 327: if (proxflag &&
1.10 millert 328: (dig == 1 || (dig == 5 && verbose == 0)))
1.18 deraadt 329: fprintf(ttyout, "%s:", hostname);
330: (void)putc(c, ttyout);
1.1 deraadt 331: }
332: if (dig < 4 && isdigit(c))
333: code = code * 10 + (c - '0');
334: if (!pflag && code == 227)
335: pflag = 1;
336: if (dig > 4 && pflag == 1 && isdigit(c))
337: pflag = 2;
338: if (pflag == 2) {
339: if (c != '\r' && c != ')')
340: *pt++ = c;
341: else {
342: *pt = '\0';
343: pflag = 3;
344: }
345: }
346: if (dig == 4 && c == '-') {
347: if (continuation)
348: code = 0;
349: continuation++;
350: }
1.10 millert 351: if (n == 0)
352: n = c;
353: if (cp < ¤t_line[sizeof(current_line) - 1])
1.1 deraadt 354: *cp++ = c;
355: }
1.11 millert 356: if (verbose > 0 || ((verbose > -1 && n == '5') &&
357: (n < '5' || !retry_connect))) {
1.18 deraadt 358: (void)putc(c, ttyout);
359: (void)fflush (ttyout);
1.1 deraadt 360: }
1.10 millert 361: if (line == 0) {
362: size_t len = cp - current_line;
363:
364: if (len > sizeof(reply_string))
365: len = sizeof(reply_string);
366:
1.11 millert 367: (void)strncpy(reply_string, current_line, len);
1.10 millert 368: reply_string[len] = '\0';
369: }
1.1 deraadt 370: if (continuation && code != originalcode) {
371: if (originalcode == 0)
372: originalcode = code;
373: continue;
374: }
375: *cp = '\0';
376: if (n != '1')
377: cpend = 0;
1.11 millert 378: (void)signal(SIGINT, oldintr);
1.1 deraadt 379: if (code == 421 || originalcode == 421)
380: lostpeer();
381: if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
382: (*oldintr)(SIGINT);
383: return (n - '0');
384: }
385: }
386:
387: int
388: empty(mask, sec)
389: struct fd_set *mask;
390: int sec;
391: {
392: struct timeval t;
393:
394: t.tv_sec = (long) sec;
395: t.tv_usec = 0;
396: return (select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t));
397: }
398:
399: jmp_buf sendabort;
400:
401: void
1.12 millert 402: abortsend(notused)
403: int notused;
1.1 deraadt 404: {
405:
1.10 millert 406: alarmtimer(0);
1.1 deraadt 407: mflag = 0;
408: abrtflag = 0;
1.18 deraadt 409: fputs("\nsend aborted\nwaiting for remote to finish abort.\n", ttyout);
410: (void)fflush(ttyout);
1.1 deraadt 411: longjmp(sendabort, 1);
412: }
413:
414: void
415: sendrequest(cmd, local, remote, printnames)
1.10 millert 416: const char *cmd, *local, *remote;
1.1 deraadt 417: int printnames;
418: {
419: struct stat st;
420: int c, d;
1.20 millert 421: FILE *fin, *dout;
1.1 deraadt 422: int (*closefunc) __P((FILE *));
1.10 millert 423: sig_t oldinti, oldintr, oldintp;
1.20 millert 424: volatile off_t hashbytes;
1.1 deraadt 425: char *lmode, buf[BUFSIZ], *bufp;
1.13 millert 426: int oprogress;
1.1 deraadt 427:
1.20 millert 428: #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
429: (void)&fin;
430: (void)&dout;
431: (void)&closefunc;
432: (void)&oldinti;
433: (void)&oldintr;
434: (void)&oldintp;
435: (void)&lmode;
436: #endif
437:
1.10 millert 438: hashbytes = mark;
439: direction = "sent";
1.20 millert 440: dout = NULL;
1.10 millert 441: bytes = 0;
442: filesize = -1;
1.13 millert 443: oprogress = progress;
1.1 deraadt 444: if (verbose && printnames) {
445: if (local && *local != '-')
1.18 deraadt 446: fprintf(ttyout, "local: %s ", local);
1.1 deraadt 447: if (remote)
1.18 deraadt 448: fprintf(ttyout, "remote: %s\n", remote);
1.1 deraadt 449: }
450: if (proxy) {
451: proxtrans(cmd, local, remote);
452: return;
453: }
454: if (curtype != type)
455: changetype(type, 0);
456: closefunc = NULL;
457: oldintr = NULL;
458: oldintp = NULL;
1.10 millert 459: oldinti = NULL;
1.1 deraadt 460: lmode = "w";
461: if (setjmp(sendabort)) {
462: while (cpend) {
1.11 millert 463: (void)getreply(0);
1.1 deraadt 464: }
465: if (data >= 0) {
1.11 millert 466: (void)close(data);
1.1 deraadt 467: data = -1;
468: }
469: if (oldintr)
1.11 millert 470: (void)signal(SIGINT, oldintr);
1.1 deraadt 471: if (oldintp)
1.11 millert 472: (void)signal(SIGPIPE, oldintp);
1.10 millert 473: if (oldinti)
1.11 millert 474: (void)signal(SIGINFO, oldinti);
1.13 millert 475: progress = oprogress;
1.1 deraadt 476: code = -1;
477: return;
478: }
479: oldintr = signal(SIGINT, abortsend);
1.10 millert 480: oldinti = signal(SIGINFO, psummary);
1.13 millert 481: if (strcmp(local, "-") == 0) {
1.1 deraadt 482: fin = stdin;
1.13 millert 483: progress = 0;
484: } else if (*local == '|') {
1.10 millert 485: oldintp = signal(SIGPIPE, SIG_IGN);
1.1 deraadt 486: fin = popen(local + 1, "r");
487: if (fin == NULL) {
488: warn("%s", local + 1);
1.11 millert 489: (void)signal(SIGINT, oldintr);
490: (void)signal(SIGPIPE, oldintp);
491: (void)signal(SIGINFO, oldinti);
1.1 deraadt 492: code = -1;
493: return;
494: }
1.13 millert 495: progress = 0;
1.1 deraadt 496: closefunc = pclose;
497: } else {
498: fin = fopen(local, "r");
499: if (fin == NULL) {
500: warn("local: %s", local);
1.11 millert 501: (void)signal(SIGINT, oldintr);
502: (void)signal(SIGINFO, oldinti);
1.1 deraadt 503: code = -1;
504: return;
505: }
506: closefunc = fclose;
507: if (fstat(fileno(fin), &st) < 0 ||
1.14 millert 508: (st.st_mode & S_IFMT) != S_IFREG) {
1.18 deraadt 509: fprintf(ttyout, "%s: not a plain file.\n", local);
1.11 millert 510: (void)signal(SIGINT, oldintr);
511: (void)signal(SIGINFO, oldinti);
1.1 deraadt 512: fclose(fin);
513: code = -1;
514: return;
515: }
1.10 millert 516: filesize = st.st_size;
1.1 deraadt 517: }
518: if (initconn()) {
1.11 millert 519: (void)signal(SIGINT, oldintr);
520: (void)signal(SIGINFO, oldinti);
1.1 deraadt 521: if (oldintp)
1.11 millert 522: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 523: code = -1;
1.13 millert 524: progress = oprogress;
1.1 deraadt 525: if (closefunc != NULL)
526: (*closefunc)(fin);
527: return;
528: }
529: if (setjmp(sendabort))
530: goto abort;
531:
532: if (restart_point &&
533: (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
534: int rc;
535:
1.10 millert 536: rc = -1;
1.1 deraadt 537: switch (curtype) {
538: case TYPE_A:
539: rc = fseek(fin, (long) restart_point, SEEK_SET);
540: break;
541: case TYPE_I:
542: case TYPE_L:
543: rc = lseek(fileno(fin), restart_point, SEEK_SET);
544: break;
545: }
546: if (rc < 0) {
547: warn("local: %s", local);
548: restart_point = 0;
1.13 millert 549: progress = oprogress;
1.1 deraadt 550: if (closefunc != NULL)
551: (*closefunc)(fin);
552: return;
553: }
554: if (command("REST %ld", (long) restart_point)
555: != CONTINUE) {
556: restart_point = 0;
1.13 millert 557: progress = oprogress;
1.1 deraadt 558: if (closefunc != NULL)
559: (*closefunc)(fin);
560: return;
561: }
562: restart_point = 0;
563: lmode = "r+w";
564: }
565: if (remote) {
566: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 567: (void)signal(SIGINT, oldintr);
568: (void)signal(SIGINFO, oldinti);
1.13 millert 569: progress = oprogress;
1.1 deraadt 570: if (oldintp)
1.11 millert 571: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 572: if (closefunc != NULL)
573: (*closefunc)(fin);
574: return;
575: }
576: } else
577: if (command("%s", cmd) != PRELIM) {
1.11 millert 578: (void)signal(SIGINT, oldintr);
579: (void)signal(SIGINFO, oldinti);
1.13 millert 580: progress = oprogress;
1.1 deraadt 581: if (oldintp)
1.11 millert 582: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 583: if (closefunc != NULL)
584: (*closefunc)(fin);
585: return;
586: }
587: dout = dataconn(lmode);
588: if (dout == NULL)
589: goto abort;
1.10 millert 590: progressmeter(-1);
1.1 deraadt 591: oldintp = signal(SIGPIPE, SIG_IGN);
592: switch (curtype) {
593:
594: case TYPE_I:
595: case TYPE_L:
596: errno = d = 0;
1.11 millert 597: while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
1.1 deraadt 598: bytes += c;
599: for (bufp = buf; c > 0; c -= d, bufp += d)
1.20 millert 600: if ((d = write(fileno(dout), bufp, (size_t)c))
601: <= 0)
1.1 deraadt 602: break;
1.10 millert 603: if (hash && (!progress || filesize < 0) ) {
1.1 deraadt 604: while (bytes >= hashbytes) {
1.18 deraadt 605: (void)putc('#', ttyout);
1.7 kstailey 606: hashbytes += mark;
1.1 deraadt 607: }
1.18 deraadt 608: (void)fflush(ttyout);
1.1 deraadt 609: }
610: }
1.10 millert 611: if (hash && (!progress || filesize < 0) && bytes > 0) {
1.7 kstailey 612: if (bytes < mark)
1.18 deraadt 613: (void)putc('#', ttyout);
614: (void)putc('\n', ttyout);
615: (void)fflush(ttyout);
1.1 deraadt 616: }
617: if (c < 0)
618: warn("local: %s", local);
619: if (d < 0) {
1.10 millert 620: if (errno != EPIPE)
1.1 deraadt 621: warn("netout");
622: bytes = -1;
623: }
624: break;
625:
626: case TYPE_A:
1.23 millert 627: while ((c = fgetc(fin)) != EOF) {
1.1 deraadt 628: if (c == '\n') {
1.10 millert 629: while (hash && (!progress || filesize < 0) &&
630: (bytes >= hashbytes)) {
1.18 deraadt 631: (void)putc('#', ttyout);
632: (void)fflush(ttyout);
1.7 kstailey 633: hashbytes += mark;
1.1 deraadt 634: }
635: if (ferror(dout))
636: break;
1.11 millert 637: (void)putc('\r', dout);
1.1 deraadt 638: bytes++;
639: }
1.11 millert 640: (void)putc(c, dout);
1.1 deraadt 641: bytes++;
1.10 millert 642: #if 0 /* this violates RFC */
643: if (c == '\r') {
644: (void)putc('\0', dout);
645: bytes++;
646: }
647: #endif
1.1 deraadt 648: }
1.10 millert 649: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 650: if (bytes < hashbytes)
1.18 deraadt 651: (void)putc('#', ttyout);
652: (void)putc('\n', ttyout);
653: (void)fflush(ttyout);
1.1 deraadt 654: }
655: if (ferror(fin))
656: warn("local: %s", local);
657: if (ferror(dout)) {
658: if (errno != EPIPE)
659: warn("netout");
660: bytes = -1;
661: }
662: break;
663: }
1.10 millert 664: progressmeter(1);
1.13 millert 665: progress = oprogress;
1.1 deraadt 666: if (closefunc != NULL)
667: (*closefunc)(fin);
1.11 millert 668: (void)fclose(dout);
669: (void)getreply(0);
670: (void)signal(SIGINT, oldintr);
671: (void)signal(SIGINFO, oldinti);
1.1 deraadt 672: if (oldintp)
1.11 millert 673: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 674: if (bytes > 0)
1.10 millert 675: ptransfer(0);
1.1 deraadt 676: return;
677: abort:
1.11 millert 678: (void)signal(SIGINT, oldintr);
679: (void)signal(SIGINFO, oldinti);
1.13 millert 680: progress = oprogress;
1.1 deraadt 681: if (oldintp)
1.11 millert 682: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 683: if (!cpend) {
684: code = -1;
685: return;
686: }
687: if (data >= 0) {
1.11 millert 688: (void)close(data);
1.1 deraadt 689: data = -1;
690: }
691: if (dout)
1.11 millert 692: (void)fclose(dout);
693: (void)getreply(0);
1.1 deraadt 694: code = -1;
695: if (closefunc != NULL && fin != NULL)
696: (*closefunc)(fin);
697: if (bytes > 0)
1.10 millert 698: ptransfer(0);
1.1 deraadt 699: }
700:
701: jmp_buf recvabort;
702:
703: void
1.12 millert 704: abortrecv(notused)
705: int notused;
1.1 deraadt 706: {
707:
1.10 millert 708: alarmtimer(0);
1.1 deraadt 709: mflag = 0;
710: abrtflag = 0;
1.18 deraadt 711: fputs("\nreceive aborted\nwaiting for remote to finish abort.\n", ttyout);
712: (void)fflush(ttyout);
1.1 deraadt 713: longjmp(recvabort, 1);
714: }
715:
716: void
1.22 millert 717: recvrequest(cmd, local, remote, lmode, printnames, ignorespecial)
1.10 millert 718: const char *cmd, *local, *remote, *lmode;
1.22 millert 719: int printnames, ignorespecial;
1.1 deraadt 720: {
1.20 millert 721: FILE *fout, *din;
1.1 deraadt 722: int (*closefunc) __P((FILE *));
1.10 millert 723: sig_t oldinti, oldintr, oldintp;
1.20 millert 724: int c, d;
725: volatile int is_retr, tcrflag, bare_lfs;
726: static size_t bufsize;
1.1 deraadt 727: static char *buf;
1.20 millert 728: volatile off_t hashbytes;
1.1 deraadt 729: struct stat st;
1.10 millert 730: time_t mtime;
1.13 millert 731: int oprogress;
1.16 millert 732: int opreserve;
1.1 deraadt 733:
1.20 millert 734: #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
735: (void)&local;
736: (void)&fout;
737: (void)&din;
738: (void)&closefunc;
739: (void)&oldinti;
740: (void)&oldintr;
741: (void)&oldintp;
742: #endif
743:
744: fout = NULL;
745: din = NULL;
746: oldinti = NULL;
1.10 millert 747: hashbytes = mark;
748: direction = "received";
749: bytes = 0;
1.20 millert 750: bare_lfs = 0;
1.10 millert 751: filesize = -1;
1.13 millert 752: oprogress = progress;
1.16 millert 753: opreserve = preserve;
1.1 deraadt 754: is_retr = strcmp(cmd, "RETR") == 0;
755: if (is_retr && verbose && printnames) {
1.22 millert 756: if (local && (ignorespecial || *local != '-'))
1.18 deraadt 757: fprintf(ttyout, "local: %s ", local);
1.1 deraadt 758: if (remote)
1.18 deraadt 759: fprintf(ttyout, "remote: %s\n", remote);
1.1 deraadt 760: }
761: if (proxy && is_retr) {
762: proxtrans(cmd, local, remote);
763: return;
764: }
765: closefunc = NULL;
766: oldintr = NULL;
767: oldintp = NULL;
768: tcrflag = !crflag && is_retr;
769: if (setjmp(recvabort)) {
770: while (cpend) {
1.11 millert 771: (void)getreply(0);
1.1 deraadt 772: }
773: if (data >= 0) {
1.11 millert 774: (void)close(data);
1.1 deraadt 775: data = -1;
776: }
777: if (oldintr)
1.11 millert 778: (void)signal(SIGINT, oldintr);
1.10 millert 779: if (oldinti)
1.11 millert 780: (void)signal(SIGINFO, oldinti);
1.15 millert 781: progress = oprogress;
1.16 millert 782: preserve = opreserve;
1.1 deraadt 783: code = -1;
784: return;
785: }
786: oldintr = signal(SIGINT, abortrecv);
1.10 millert 787: oldinti = signal(SIGINFO, psummary);
1.22 millert 788: if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
789: if (access(local, W_OK) < 0) {
1.1 deraadt 790: char *dir = strrchr(local, '/');
791:
792: if (errno != ENOENT && errno != EACCES) {
793: warn("local: %s", local);
1.11 millert 794: (void)signal(SIGINT, oldintr);
795: (void)signal(SIGINFO, oldinti);
1.1 deraadt 796: code = -1;
797: return;
798: }
799: if (dir != NULL)
800: *dir = 0;
1.22 millert 801: d = access(dir == local ? "/" : dir ? local : ".", W_OK);
1.1 deraadt 802: if (dir != NULL)
803: *dir = '/';
804: if (d < 0) {
805: warn("local: %s", local);
1.11 millert 806: (void)signal(SIGINT, oldintr);
807: (void)signal(SIGINFO, oldinti);
1.1 deraadt 808: code = -1;
809: return;
810: }
811: if (!runique && errno == EACCES &&
1.20 millert 812: chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
1.1 deraadt 813: warn("local: %s", local);
1.11 millert 814: (void)signal(SIGINT, oldintr);
815: (void)signal(SIGINFO, oldinti);
1.1 deraadt 816: code = -1;
817: return;
818: }
819: if (runique && errno == EACCES &&
820: (local = gunique(local)) == NULL) {
1.11 millert 821: (void)signal(SIGINT, oldintr);
822: (void)signal(SIGINFO, oldinti);
1.1 deraadt 823: code = -1;
824: return;
825: }
826: }
827: else if (runique && (local = gunique(local)) == NULL) {
1.11 millert 828: (void)signal(SIGINT, oldintr);
829: (void)signal(SIGINFO, oldinti);
1.1 deraadt 830: code = -1;
831: return;
832: }
833: }
834: if (!is_retr) {
835: if (curtype != TYPE_A)
836: changetype(TYPE_A, 0);
1.10 millert 837: } else {
838: if (curtype != type)
839: changetype(type, 0);
840: filesize = remotesize(remote, 0);
841: }
1.1 deraadt 842: if (initconn()) {
1.11 millert 843: (void)signal(SIGINT, oldintr);
844: (void)signal(SIGINFO, oldinti);
1.1 deraadt 845: code = -1;
846: return;
847: }
848: if (setjmp(recvabort))
849: goto abort;
850: if (is_retr && restart_point &&
851: command("REST %ld", (long) restart_point) != CONTINUE)
852: return;
853: if (remote) {
854: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 855: (void)signal(SIGINT, oldintr);
856: (void)signal(SIGINFO, oldinti);
1.1 deraadt 857: return;
858: }
859: } else {
860: if (command("%s", cmd) != PRELIM) {
1.11 millert 861: (void)signal(SIGINT, oldintr);
862: (void)signal(SIGINFO, oldinti);
1.1 deraadt 863: return;
864: }
865: }
866: din = dataconn("r");
867: if (din == NULL)
868: goto abort;
1.22 millert 869: if (!ignorespecial && strcmp(local, "-") == 0) {
1.1 deraadt 870: fout = stdout;
1.13 millert 871: progress = 0;
1.16 millert 872: preserve = 0;
1.22 millert 873: } else if (!ignorespecial && *local == '|') {
1.1 deraadt 874: oldintp = signal(SIGPIPE, SIG_IGN);
875: fout = popen(local + 1, "w");
876: if (fout == NULL) {
877: warn("%s", local+1);
878: goto abort;
879: }
1.13 millert 880: progress = 0;
1.16 millert 881: preserve = 0;
1.1 deraadt 882: closefunc = pclose;
883: } else {
884: fout = fopen(local, lmode);
885: if (fout == NULL) {
886: warn("local: %s", local);
887: goto abort;
888: }
889: closefunc = fclose;
890: }
891: if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
892: st.st_blksize = BUFSIZ;
893: if (st.st_blksize > bufsize) {
894: if (buf)
1.11 millert 895: (void)free(buf);
1.1 deraadt 896: buf = malloc((unsigned)st.st_blksize);
897: if (buf == NULL) {
898: warn("malloc");
899: bufsize = 0;
900: goto abort;
901: }
902: bufsize = st.st_blksize;
903: }
1.14 millert 904: if ((st.st_mode & S_IFMT) != S_IFREG) {
1.13 millert 905: progress = 0;
906: preserve = 0;
907: }
1.10 millert 908: progressmeter(-1);
1.1 deraadt 909: switch (curtype) {
910:
911: case TYPE_I:
912: case TYPE_L:
913: if (restart_point &&
914: lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
915: warn("local: %s", local);
1.13 millert 916: progress = oprogress;
1.16 millert 917: preserve = opreserve;
1.1 deraadt 918: if (closefunc != NULL)
919: (*closefunc)(fout);
920: return;
921: }
922: errno = d = 0;
923: while ((c = read(fileno(din), buf, bufsize)) > 0) {
1.20 millert 924: if ((d = write(fileno(fout), buf, (size_t)c)) != c)
1.1 deraadt 925: break;
926: bytes += c;
1.10 millert 927: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 928: while (bytes >= hashbytes) {
1.18 deraadt 929: (void)putc('#', ttyout);
1.7 kstailey 930: hashbytes += mark;
1.1 deraadt 931: }
1.18 deraadt 932: (void)fflush(ttyout);
1.1 deraadt 933: }
934: }
1.10 millert 935: if (hash && (!progress || filesize < 0) && bytes > 0) {
1.7 kstailey 936: if (bytes < mark)
1.18 deraadt 937: (void)putc('#', ttyout);
938: (void)putc('\n', ttyout);
939: (void)fflush(ttyout);
1.1 deraadt 940: }
941: if (c < 0) {
942: if (errno != EPIPE)
943: warn("netin");
944: bytes = -1;
945: }
946: if (d < c) {
947: if (d < 0)
948: warn("local: %s", local);
949: else
950: warnx("%s: short write", local);
951: }
952: break;
953:
954: case TYPE_A:
955: if (restart_point) {
956: int i, n, ch;
957:
958: if (fseek(fout, 0L, SEEK_SET) < 0)
959: goto done;
960: n = restart_point;
961: for (i = 0; i++ < n;) {
1.23 millert 962: if ((ch = fgetc(fout)) == EOF)
1.1 deraadt 963: goto done;
964: if (ch == '\n')
965: i++;
966: }
967: if (fseek(fout, 0L, SEEK_CUR) < 0) {
968: done:
969: warn("local: %s", local);
1.13 millert 970: progress = oprogress;
1.16 millert 971: preserve = opreserve;
1.1 deraadt 972: if (closefunc != NULL)
973: (*closefunc)(fout);
974: return;
975: }
976: }
1.23 millert 977: while ((c = fgetc(din)) != EOF) {
1.1 deraadt 978: if (c == '\n')
979: bare_lfs++;
980: while (c == '\r') {
1.10 millert 981: while (hash && (!progress || filesize < 0) &&
982: (bytes >= hashbytes)) {
1.18 deraadt 983: (void)putc('#', ttyout);
984: (void)fflush(ttyout);
1.7 kstailey 985: hashbytes += mark;
1.1 deraadt 986: }
987: bytes++;
1.23 millert 988: if ((c = fgetc(din)) != '\n' || tcrflag) {
1.1 deraadt 989: if (ferror(fout))
990: goto break2;
1.11 millert 991: (void)putc('\r', fout);
1.1 deraadt 992: if (c == '\0') {
993: bytes++;
994: goto contin2;
995: }
996: if (c == EOF)
997: goto contin2;
998: }
999: }
1.11 millert 1000: (void)putc(c, fout);
1.1 deraadt 1001: bytes++;
1002: contin2: ;
1003: }
1004: break2:
1005: if (bare_lfs) {
1.22 millert 1006: fprintf(ttyout,
1.13 millert 1007: "WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
1.22 millert 1008: fputs("File may not have transferred correctly.\n",
1009: ttyout);
1.1 deraadt 1010: }
1.10 millert 1011: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 1012: if (bytes < hashbytes)
1.18 deraadt 1013: (void)putc('#', ttyout);
1014: (void)putc('\n', ttyout);
1015: (void)fflush(ttyout);
1.1 deraadt 1016: }
1017: if (ferror(din)) {
1018: if (errno != EPIPE)
1019: warn("netin");
1020: bytes = -1;
1021: }
1022: if (ferror(fout))
1023: warn("local: %s", local);
1024: break;
1025: }
1.10 millert 1026: progressmeter(1);
1.13 millert 1027: progress = oprogress;
1.16 millert 1028: preserve = opreserve;
1.1 deraadt 1029: if (closefunc != NULL)
1030: (*closefunc)(fout);
1.11 millert 1031: (void)signal(SIGINT, oldintr);
1032: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1033: if (oldintp)
1.11 millert 1034: (void)signal(SIGPIPE, oldintp);
1035: (void)fclose(din);
1036: (void)getreply(0);
1.10 millert 1037: if (bytes >= 0 && is_retr) {
1038: if (bytes > 0)
1039: ptransfer(0);
1040: if (preserve && (closefunc == fclose)) {
1041: mtime = remotemodtime(remote, 0);
1042: if (mtime != -1) {
1.12 millert 1043: struct utimbuf ut;
1044:
1045: ut.actime = time(NULL);
1046: ut.modtime = mtime;
1047: if (utime(local, &ut) == -1)
1.22 millert 1048: fprintf(ttyout,
1.13 millert 1049: "Can't change modification time on %s to %s",
1.11 millert 1050: local, asctime(localtime(&mtime)));
1.10 millert 1051: }
1052: }
1053: }
1.1 deraadt 1054: return;
1.13 millert 1055:
1.1 deraadt 1056: abort:
1057:
1.10 millert 1058: /* abort using RFC959 recommended IP,SYNC sequence */
1.1 deraadt 1059:
1.13 millert 1060: progress = oprogress;
1.16 millert 1061: preserve = opreserve;
1.1 deraadt 1062: if (oldintp)
1.11 millert 1063: (void)signal(SIGPIPE, oldintp);
1064: (void)signal(SIGINT, SIG_IGN);
1.1 deraadt 1065: if (!cpend) {
1066: code = -1;
1.11 millert 1067: (void)signal(SIGINT, oldintr);
1068: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1069: return;
1070: }
1071:
1072: abort_remote(din);
1073: code = -1;
1074: if (data >= 0) {
1.11 millert 1075: (void)close(data);
1.1 deraadt 1076: data = -1;
1077: }
1078: if (closefunc != NULL && fout != NULL)
1079: (*closefunc)(fout);
1080: if (din)
1.11 millert 1081: (void)fclose(din);
1.1 deraadt 1082: if (bytes > 0)
1.10 millert 1083: ptransfer(0);
1.11 millert 1084: (void)signal(SIGINT, oldintr);
1085: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1086: }
1087:
1088: /*
1089: * Need to start a listen on the data channel before we send the command,
1090: * otherwise the server's connect may fail.
1091: */
1092: int
1093: initconn()
1094: {
1095: char *p, *a;
1096: int result, len, tmpno = 0;
1097: int on = 1;
1098: int a0, a1, a2, a3, p0, p1;
1099:
1.24 millert 1100: reinit:
1.1 deraadt 1101: if (passivemode) {
1102: data = socket(AF_INET, SOCK_STREAM, 0);
1103: if (data < 0) {
1.10 millert 1104: warn("socket");
1105: return (1);
1.1 deraadt 1106: }
1107: if ((options & SO_DEBUG) &&
1108: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1.11 millert 1109: sizeof(on)) < 0)
1.10 millert 1110: warn("setsockopt (ignored)");
1.1 deraadt 1111: if (command("PASV") != COMPLETE) {
1.24 millert 1112: if (activefallback) {
1113: (void)close(data);
1114: data = -1;
1115: passivemode = 0;
1116: activefallback = 0;
1117: goto reinit;
1118: }
1.18 deraadt 1119: fputs("Passive mode refused.\n", ttyout);
1.1 deraadt 1120: goto bad;
1121: }
1122:
1123: /*
1124: * What we've got at this point is a string of comma
1125: * separated one-byte unsigned integer values.
1126: * The first four are the an IP address. The fifth is
1127: * the MSB of the port number, the sixth is the LSB.
1128: * From that we'll prepare a sockaddr_in.
1129: */
1130:
1.10 millert 1131: if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
1.1 deraadt 1132: &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
1.18 deraadt 1133: fputs(
1134: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1.1 deraadt 1135: goto bad;
1136: }
1137:
1.10 millert 1138: memset(&data_addr, 0, sizeof(data_addr));
1.1 deraadt 1139: data_addr.sin_family = AF_INET;
1140: a = (char *)&data_addr.sin_addr.s_addr;
1141: a[0] = a0 & 0xff;
1142: a[1] = a1 & 0xff;
1143: a[2] = a2 & 0xff;
1144: a[3] = a3 & 0xff;
1145: p = (char *)&data_addr.sin_port;
1146: p[0] = p0 & 0xff;
1147: p[1] = p1 & 0xff;
1148:
1149: if (connect(data, (struct sockaddr *)&data_addr,
1150: sizeof(data_addr)) < 0) {
1.10 millert 1151: warn("connect");
1.1 deraadt 1152: goto bad;
1153: }
1154: #ifdef IP_TOS
1155: on = IPTOS_THROUGHPUT;
1156: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1157: sizeof(int)) < 0)
1.10 millert 1158: warn("setsockopt TOS (ignored)");
1.1 deraadt 1159: #endif
1.10 millert 1160: return (0);
1.1 deraadt 1161: }
1162:
1163: noport:
1164: data_addr = myctladdr;
1165: if (sendport)
1.10 millert 1166: data_addr.sin_port = 0; /* let system pick one */
1.1 deraadt 1167: if (data != -1)
1.11 millert 1168: (void)close(data);
1.1 deraadt 1169: data = socket(AF_INET, SOCK_STREAM, 0);
1170: if (data < 0) {
1171: warn("socket");
1172: if (tmpno)
1173: sendport = 1;
1174: return (1);
1175: }
1176: if (!sendport)
1.10 millert 1177: if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1.11 millert 1178: sizeof(on)) < 0) {
1.1 deraadt 1179: warn("setsockopt (reuse address)");
1180: goto bad;
1181: }
1.11 millert 1182: if (bind(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0) {
1.1 deraadt 1183: warn("bind");
1184: goto bad;
1185: }
1186: if (options & SO_DEBUG &&
1.10 millert 1187: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1.11 millert 1188: sizeof(on)) < 0)
1.1 deraadt 1189: warn("setsockopt (ignored)");
1.11 millert 1190: len = sizeof(data_addr);
1.1 deraadt 1191: if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1192: warn("getsockname");
1193: goto bad;
1194: }
1195: if (listen(data, 1) < 0)
1196: warn("listen");
1197: if (sendport) {
1198: a = (char *)&data_addr.sin_addr;
1199: p = (char *)&data_addr.sin_port;
1200: #define UC(b) (((int)b)&0xff)
1201: result =
1202: command("PORT %d,%d,%d,%d,%d,%d",
1203: UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1204: UC(p[0]), UC(p[1]));
1205: if (result == ERROR && sendport == -1) {
1206: sendport = 0;
1207: tmpno = 1;
1208: goto noport;
1209: }
1210: return (result != COMPLETE);
1211: }
1212: if (tmpno)
1213: sendport = 1;
1214: #ifdef IP_TOS
1215: on = IPTOS_THROUGHPUT;
1216: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1217: warn("setsockopt TOS (ignored)");
1218: #endif
1219: return (0);
1220: bad:
1.11 millert 1221: (void)close(data), data = -1;
1.1 deraadt 1222: if (tmpno)
1223: sendport = 1;
1224: return (1);
1225: }
1226:
1227: FILE *
1228: dataconn(lmode)
1.10 millert 1229: const char *lmode;
1.1 deraadt 1230: {
1231: struct sockaddr_in from;
1.13 millert 1232: int s, fromlen, tos;
1233:
1234: fromlen = sizeof(from);
1.1 deraadt 1235:
1236: if (passivemode)
1237: return (fdopen(data, lmode));
1238:
1239: s = accept(data, (struct sockaddr *) &from, &fromlen);
1240: if (s < 0) {
1241: warn("accept");
1.11 millert 1242: (void)close(data), data = -1;
1.1 deraadt 1243: return (NULL);
1244: }
1.11 millert 1245: (void)close(data);
1.1 deraadt 1246: data = s;
1247: #ifdef IP_TOS
1248: tos = IPTOS_THROUGHPUT;
1249: if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1250: warn("setsockopt TOS (ignored)");
1251: #endif
1252: return (fdopen(data, lmode));
1253: }
1254:
1255: void
1.10 millert 1256: psummary(notused)
1257: int notused;
1.1 deraadt 1258: {
1.26 ! deraadt 1259: int save_errno = errno;
1.10 millert 1260:
1261: if (bytes > 0)
1262: ptransfer(1);
1.26 ! deraadt 1263: errno = save_errno;
1.1 deraadt 1264: }
1265:
1266: void
1.12 millert 1267: psabort(notused)
1268: int notused;
1.1 deraadt 1269: {
1270:
1.10 millert 1271: alarmtimer(0);
1.1 deraadt 1272: abrtflag++;
1273: }
1274:
1275: void
1276: pswitch(flag)
1277: int flag;
1278: {
1279: sig_t oldintr;
1280: static struct comvars {
1281: int connect;
1282: char name[MAXHOSTNAMELEN];
1283: struct sockaddr_in mctl;
1284: struct sockaddr_in hctl;
1285: FILE *in;
1286: FILE *out;
1287: int tpe;
1288: int curtpe;
1289: int cpnd;
1290: int sunqe;
1291: int runqe;
1292: int mcse;
1293: int ntflg;
1294: char nti[17];
1295: char nto[17];
1296: int mapflg;
1297: char mi[MAXPATHLEN];
1298: char mo[MAXPATHLEN];
1299: } proxstruct, tmpstruct;
1300: struct comvars *ip, *op;
1301:
1302: abrtflag = 0;
1303: oldintr = signal(SIGINT, psabort);
1304: if (flag) {
1305: if (proxy)
1306: return;
1307: ip = &tmpstruct;
1308: op = &proxstruct;
1309: proxy++;
1310: } else {
1311: if (!proxy)
1312: return;
1313: ip = &proxstruct;
1314: op = &tmpstruct;
1315: proxy = 0;
1316: }
1317: ip->connect = connected;
1318: connected = op->connect;
1319: if (hostname) {
1.11 millert 1320: (void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1321: ip->name[sizeof(ip->name) - 1] = '\0';
1.1 deraadt 1322: } else
1.11 millert 1323: ip->name[0] = '\0';
1.1 deraadt 1324: hostname = op->name;
1325: ip->hctl = hisctladdr;
1326: hisctladdr = op->hctl;
1327: ip->mctl = myctladdr;
1328: myctladdr = op->mctl;
1329: ip->in = cin;
1330: cin = op->in;
1331: ip->out = cout;
1332: cout = op->out;
1333: ip->tpe = type;
1334: type = op->tpe;
1335: ip->curtpe = curtype;
1336: curtype = op->curtpe;
1337: ip->cpnd = cpend;
1338: cpend = op->cpnd;
1339: ip->sunqe = sunique;
1340: sunique = op->sunqe;
1341: ip->runqe = runique;
1342: runique = op->runqe;
1343: ip->mcse = mcase;
1344: mcase = op->mcse;
1345: ip->ntflg = ntflag;
1346: ntflag = op->ntflg;
1.11 millert 1347: (void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1348: (ip->nti)[sizeof(ip->nti) - 1] = '\0';
1349: (void)strcpy(ntin, op->nti);
1350: (void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1351: (ip->nto)[sizeof(ip->nto) - 1] = '\0';
1352: (void)strcpy(ntout, op->nto);
1.1 deraadt 1353: ip->mapflg = mapflag;
1354: mapflag = op->mapflg;
1.11 millert 1355: (void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1356: (ip->mi)[sizeof(ip->mi) - 1] = '\0';
1357: (void)strcpy(mapin, op->mi);
1358: (void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1359: (ip->mo)[sizeof(ip->mo) - 1] = '\0';
1360: (void)strcpy(mapout, op->mo);
1361: (void)signal(SIGINT, oldintr);
1.1 deraadt 1362: if (abrtflag) {
1363: abrtflag = 0;
1364: (*oldintr)(SIGINT);
1365: }
1366: }
1367:
1368: void
1.12 millert 1369: abortpt(notused)
1370: int notused;
1.1 deraadt 1371: {
1372:
1.10 millert 1373: alarmtimer(0);
1.18 deraadt 1374: putc('\n', ttyout);
1375: (void)fflush(ttyout);
1.1 deraadt 1376: ptabflg++;
1377: mflag = 0;
1378: abrtflag = 0;
1379: longjmp(ptabort, 1);
1380: }
1381:
1382: void
1383: proxtrans(cmd, local, remote)
1.10 millert 1384: const char *cmd, *local, *remote;
1.1 deraadt 1385: {
1386: sig_t oldintr;
1.20 millert 1387: int prox_type, nfnd;
1388: volatile int secndflag;
1.1 deraadt 1389: char *cmd2;
1390: struct fd_set mask;
1391:
1.20 millert 1392: #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
1393: (void)&oldintr;
1394: (void)&cmd2;
1395: #endif
1396:
1397: oldintr = NULL;
1398: secndflag = 0;
1.1 deraadt 1399: if (strcmp(cmd, "RETR"))
1400: cmd2 = "RETR";
1401: else
1402: cmd2 = runique ? "STOU" : "STOR";
1403: if ((prox_type = type) == 0) {
1404: if (unix_server && unix_proxy)
1405: prox_type = TYPE_I;
1406: else
1407: prox_type = TYPE_A;
1408: }
1409: if (curtype != prox_type)
1410: changetype(prox_type, 1);
1411: if (command("PASV") != COMPLETE) {
1.18 deraadt 1412: fputs("proxy server does not support third party transfers.\n",
1413: ttyout);
1.1 deraadt 1414: return;
1415: }
1416: pswitch(0);
1417: if (!connected) {
1.18 deraadt 1418: fputs("No primary connection.\n", ttyout);
1.1 deraadt 1419: pswitch(1);
1420: code = -1;
1421: return;
1422: }
1423: if (curtype != prox_type)
1424: changetype(prox_type, 1);
1425: if (command("PORT %s", pasv) != COMPLETE) {
1426: pswitch(1);
1427: return;
1428: }
1429: if (setjmp(ptabort))
1430: goto abort;
1431: oldintr = signal(SIGINT, abortpt);
1432: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 1433: (void)signal(SIGINT, oldintr);
1.1 deraadt 1434: pswitch(1);
1435: return;
1436: }
1437: sleep(2);
1438: pswitch(1);
1439: secndflag++;
1440: if (command("%s %s", cmd2, local) != PRELIM)
1441: goto abort;
1442: ptflag++;
1.11 millert 1443: (void)getreply(0);
1.1 deraadt 1444: pswitch(0);
1.11 millert 1445: (void)getreply(0);
1446: (void)signal(SIGINT, oldintr);
1.1 deraadt 1447: pswitch(1);
1448: ptflag = 0;
1.18 deraadt 1449: fprintf(ttyout, "local: %s remote: %s\n", local, remote);
1.1 deraadt 1450: return;
1451: abort:
1.11 millert 1452: (void)signal(SIGINT, SIG_IGN);
1.1 deraadt 1453: ptflag = 0;
1454: if (strcmp(cmd, "RETR") && !proxy)
1455: pswitch(1);
1456: else if (!strcmp(cmd, "RETR") && proxy)
1457: pswitch(0);
1458: if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1459: if (command("%s %s", cmd2, local) != PRELIM) {
1460: pswitch(0);
1461: if (cpend)
1.19 kstailey 1462: abort_remote(NULL);
1.1 deraadt 1463: }
1464: pswitch(1);
1465: if (ptabflg)
1466: code = -1;
1.11 millert 1467: (void)signal(SIGINT, oldintr);
1.1 deraadt 1468: return;
1469: }
1470: if (cpend)
1.19 kstailey 1471: abort_remote(NULL);
1.1 deraadt 1472: pswitch(!proxy);
1473: if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1474: if (command("%s %s", cmd2, local) != PRELIM) {
1475: pswitch(0);
1476: if (cpend)
1.19 kstailey 1477: abort_remote(NULL);
1.1 deraadt 1478: pswitch(1);
1479: if (ptabflg)
1480: code = -1;
1.11 millert 1481: (void)signal(SIGINT, oldintr);
1.1 deraadt 1482: return;
1483: }
1484: }
1485: if (cpend)
1.19 kstailey 1486: abort_remote(NULL);
1.1 deraadt 1487: pswitch(!proxy);
1488: if (cpend) {
1489: FD_ZERO(&mask);
1490: FD_SET(fileno(cin), &mask);
1491: if ((nfnd = empty(&mask, 10)) <= 0) {
1492: if (nfnd < 0) {
1493: warn("abort");
1494: }
1495: if (ptabflg)
1496: code = -1;
1497: lostpeer();
1498: }
1.11 millert 1499: (void)getreply(0);
1500: (void)getreply(0);
1.1 deraadt 1501: }
1502: if (proxy)
1503: pswitch(0);
1504: pswitch(1);
1505: if (ptabflg)
1506: code = -1;
1.11 millert 1507: (void)signal(SIGINT, oldintr);
1.1 deraadt 1508: }
1509:
1510: void
1511: reset(argc, argv)
1512: int argc;
1513: char *argv[];
1514: {
1515: struct fd_set mask;
1516: int nfnd = 1;
1517:
1518: FD_ZERO(&mask);
1519: while (nfnd > 0) {
1520: FD_SET(fileno(cin), &mask);
1.10 millert 1521: if ((nfnd = empty(&mask, 0)) < 0) {
1.1 deraadt 1522: warn("reset");
1523: code = -1;
1524: lostpeer();
1525: }
1526: else if (nfnd) {
1.11 millert 1527: (void)getreply(0);
1.1 deraadt 1528: }
1529: }
1530: }
1531:
1532: char *
1533: gunique(local)
1.10 millert 1534: const char *local;
1.1 deraadt 1535: {
1536: static char new[MAXPATHLEN];
1537: char *cp = strrchr(local, '/');
1538: int d, count=0;
1539: char ext = '1';
1540:
1541: if (cp)
1542: *cp = '\0';
1.22 millert 1543: d = access(cp == local ? "/" : cp ? local : ".", W_OK);
1.1 deraadt 1544: if (cp)
1545: *cp = '/';
1546: if (d < 0) {
1547: warn("local: %s", local);
1548: return ((char *) 0);
1549: }
1.11 millert 1550: (void)strcpy(new, local);
1.1 deraadt 1551: cp = new + strlen(new);
1552: *cp++ = '.';
1553: while (!d) {
1554: if (++count == 100) {
1.18 deraadt 1555: fputs("runique: can't find unique file name.\n", ttyout);
1.1 deraadt 1556: return ((char *) 0);
1557: }
1558: *cp++ = ext;
1559: *cp = '\0';
1560: if (ext == '9')
1561: ext = '0';
1562: else
1563: ext++;
1.22 millert 1564: if ((d = access(new, F_OK)) < 0)
1.1 deraadt 1565: break;
1566: if (ext != '0')
1567: cp--;
1568: else if (*(cp - 2) == '.')
1569: *(cp - 1) = '1';
1570: else {
1571: *(cp - 2) = *(cp - 2) + 1;
1572: cp--;
1573: }
1574: }
1575: return (new);
1576: }
1577:
1578: void
1579: abort_remote(din)
1580: FILE *din;
1581: {
1582: char buf[BUFSIZ];
1583: int nfnd;
1584: struct fd_set mask;
1.13 millert 1585:
1586: if (cout == NULL) {
1587: warnx("Lost control connection for abort.");
1588: if (ptabflg)
1589: code = -1;
1590: lostpeer();
1591: return;
1592: }
1.1 deraadt 1593:
1594: /*
1595: * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1596: * after urgent byte rather than before as is protocol now
1597: */
1598: sprintf(buf, "%c%c%c", IAC, IP, IAC);
1599: if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1600: warn("abort");
1.10 millert 1601: fprintf(cout, "%cABOR\r\n", DM);
1.11 millert 1602: (void)fflush(cout);
1.1 deraadt 1603: FD_ZERO(&mask);
1604: FD_SET(fileno(cin), &mask);
1.10 millert 1605: if (din) {
1.1 deraadt 1606: FD_SET(fileno(din), &mask);
1607: }
1608: if ((nfnd = empty(&mask, 10)) <= 0) {
1609: if (nfnd < 0) {
1610: warn("abort");
1611: }
1612: if (ptabflg)
1613: code = -1;
1614: lostpeer();
1615: }
1616: if (din && FD_ISSET(fileno(din), &mask)) {
1617: while (read(fileno(din), buf, BUFSIZ) > 0)
1618: /* LOOP */;
1619: }
1620: if (getreply(0) == ERROR && code == 552) {
1621: /* 552 needed for nic style abort */
1.11 millert 1622: (void)getreply(0);
1.1 deraadt 1623: }
1.11 millert 1624: (void)getreply(0);
1.1 deraadt 1625: }