Annotation of src/usr.bin/ftp/ftp.c, Revision 1.69
1.69 ! ray 1: /* $OpenBSD: ftp.c,v 1.68 2008/03/10 22:56:43 espie Exp $ */
1.22 millert 2: /* $NetBSD: ftp.c,v 1.27 1997/08/18 10:20:23 lukem Exp $ */
1.1 deraadt 3:
4: /*
1.34 itojun 5: * Copyright (C) 1997 and 1998 WIDE Project.
6: * 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. Neither the name of the project nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
1.1 deraadt 34: * Copyright (c) 1985, 1989, 1993, 1994
35: * The Regents of the University of California. All rights reserved.
36: *
37: * Redistribution and use in source and binary forms, with or without
38: * modification, are permitted provided that the following conditions
39: * are met:
40: * 1. Redistributions of source code must retain the above copyright
41: * notice, this list of conditions and the following disclaimer.
42: * 2. Redistributions in binary form must reproduce the above copyright
43: * notice, this list of conditions and the following disclaimer in the
44: * documentation and/or other materials provided with the distribution.
1.53 millert 45: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: */
61:
1.55 deraadt 62: #if !defined(lint) && !defined(SMALL)
1.69 ! ray 63: static const char rcsid[] = "$OpenBSD: ftp.c,v 1.68 2008/03/10 22:56:43 espie Exp $";
1.55 deraadt 64: #endif /* not lint and not SMALL */
1.1 deraadt 65:
1.10 millert 66: #include <sys/types.h>
1.1 deraadt 67: #include <sys/stat.h>
68: #include <sys/socket.h>
69:
70: #include <netinet/in.h>
71: #include <netinet/in_systm.h>
72: #include <netinet/ip.h>
73: #include <arpa/inet.h>
74: #include <arpa/ftp.h>
75: #include <arpa/telnet.h>
76:
77: #include <ctype.h>
78: #include <err.h>
79: #include <errno.h>
80: #include <netdb.h>
1.54 millert 81: #include <poll.h>
82: #include <stdarg.h>
1.1 deraadt 83: #include <stdio.h>
84: #include <stdlib.h>
85: #include <string.h>
86: #include <unistd.h>
1.12 millert 87: #include <utime.h>
1.1 deraadt 88:
89: #include "ftp_var.h"
90:
1.34 itojun 91: union sockunion {
92: struct sockinet {
93: u_char si_len;
94: u_char si_family;
95: u_short si_port;
96: } su_si;
97: struct sockaddr_in su_sin;
98: struct sockaddr_in6 su_sin6;
99: };
100: #define su_len su_si.si_len
101: #define su_family su_si.si_family
102: #define su_port su_si.si_port
103:
104: union sockunion myctladdr, hisctladdr, data_addr;
105:
1.1 deraadt 106: int data = -1;
107: int abrtflag = 0;
108: jmp_buf ptabort;
109: int ptabflg;
110: int ptflag = 0;
111: off_t restart_point = 0;
112:
113:
114: FILE *cin, *cout;
115:
116: char *
1.56 deraadt 117: hookup(char *host, char *port)
1.1 deraadt 118: {
1.57 deraadt 119: int s, tos, error;
1.10 millert 120: static char hostnamebuf[MAXHOSTNAMELEN];
1.34 itojun 121: struct addrinfo hints, *res, *res0;
1.51 itojun 122: char hbuf[NI_MAXHOST];
1.34 itojun 123: char *cause = "unknown";
1.57 deraadt 124: socklen_t namelen;
1.34 itojun 125:
1.36 itojun 126: epsv4bad = 0;
127:
1.34 itojun 128: memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
129: memset(&hints, 0, sizeof(hints));
130: hints.ai_flags = AI_CANONNAME;
1.45 deraadt 131: hints.ai_family = family;
1.34 itojun 132: hints.ai_socktype = SOCK_STREAM;
133: hints.ai_protocol = 0;
134: error = getaddrinfo(host, port, &hints, &res0);
1.35 deraadt 135: if (error == EAI_SERVICE) {
136: /*
137: * If the services file is corrupt/missing, fall back
138: * on our hard-coded defines.
139: */
140: char pbuf[NI_MAXSERV];
141:
142: pbuf[0] = '\0';
143: if (strcmp(port, "ftp") == 0)
144: snprintf(pbuf, sizeof(pbuf), "%d", FTP_PORT);
145: else if (strcmp(port, "ftpgate") == 0)
146: snprintf(pbuf, sizeof(pbuf), "%d", GATE_PORT);
147: else if (strcmp(port, "http") == 0)
148: snprintf(pbuf, sizeof(pbuf), "%d", HTTP_PORT);
1.63 deraadt 149: #ifndef SMALL
150: else if (strcmp(port, "https") == 0)
151: snprintf(pbuf, sizeof(pbuf), "%d", HTTPS_PORT);
152: #endif
1.35 deraadt 153: if (pbuf[0])
154: error = getaddrinfo(host, pbuf, &hints, &res0);
155: }
1.34 itojun 156: if (error) {
1.39 itojun 157: if (error == EAI_SERVICE)
158: warnx("%s: bad port number `%s'", host, port);
159: else
160: warnx("%s: %s", host, gai_strerror(error));
1.1 deraadt 161: code = -1;
162: return (0);
163: }
1.34 itojun 164:
165: if (res0->ai_canonname)
1.41 lebel 166: strlcpy(hostnamebuf, res0->ai_canonname, sizeof(hostnamebuf));
1.34 itojun 167: else
1.41 lebel 168: strlcpy(hostnamebuf, host, sizeof(hostnamebuf));
1.34 itojun 169: hostname = hostnamebuf;
170:
171: s = -1;
172: for (res = res0; res; res = res->ai_next) {
173: #if 0 /*old behavior*/
174: if (res != res0) /* not on the first address */
175: #else
176: if (res0->ai_next) /* if we have multiple possibilities */
177: #endif
178: {
1.50 itojun 179: if (getnameinfo(res->ai_addr, res->ai_addrlen,
180: hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
181: strlcpy(hbuf, "unknown", sizeof(hbuf));
1.34 itojun 182: fprintf(ttyout, "Trying %s...\n", hbuf);
183: }
184: s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
185: if (s < 0) {
186: cause = "socket";
1.27 deraadt 187: continue;
1.34 itojun 188: }
189: while ((error = connect(s, res->ai_addr, res->ai_addrlen)) < 0
190: && errno == EINTR) {
191: ;
192: }
193: if (error) {
194: /* this "if" clause is to prevent print warning twice */
195: if (res->ai_next) {
1.50 itojun 196: if (getnameinfo(res->ai_addr, res->ai_addrlen,
197: hbuf, sizeof(hbuf), NULL, 0,
198: NI_NUMERICHOST) != 0)
199: strlcpy(hbuf, "(unknown)",
200: sizeof(hbuf));
1.34 itojun 201: warn("connect to address %s", hbuf);
1.1 deraadt 202: }
1.34 itojun 203: cause = "connect";
1.60 moritz 204: error = errno;
1.34 itojun 205: close(s);
1.60 moritz 206: errno = error;
1.34 itojun 207: s = -1;
1.1 deraadt 208: continue;
209: }
1.34 itojun 210:
211: /* finally we got one */
212: break;
213: }
214: if (s < 0) {
1.38 millert 215: warn("%s", cause);
1.1 deraadt 216: code = -1;
1.34 itojun 217: freeaddrinfo(res0);
218: return 0;
1.1 deraadt 219: }
1.34 itojun 220: memcpy(&hisctladdr, res->ai_addr, res->ai_addrlen);
1.57 deraadt 221: namelen = res->ai_addrlen;
1.34 itojun 222: freeaddrinfo(res0);
223: res0 = res = NULL;
1.57 deraadt 224: if (getsockname(s, (struct sockaddr *)&myctladdr, &namelen) < 0) {
1.1 deraadt 225: warn("getsockname");
226: code = -1;
227: goto bad;
228: }
1.34 itojun 229: #if defined(IPPROTO_IP) && defined(IP_TOS)
230: if (hisctladdr.su_family == AF_INET) {
231: tos = IPTOS_LOWDELAY;
232: if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
233: warn("setsockopt TOS (ignored)");
234: }
1.1 deraadt 235: #endif
236: cin = fdopen(s, "r");
237: cout = fdopen(s, "w");
238: if (cin == NULL || cout == NULL) {
239: warnx("fdopen failed.");
240: if (cin)
1.11 millert 241: (void)fclose(cin);
1.1 deraadt 242: if (cout)
1.11 millert 243: (void)fclose(cout);
1.1 deraadt 244: code = -1;
245: goto bad;
246: }
247: if (verbose)
1.18 deraadt 248: fprintf(ttyout, "Connected to %s.\n", hostname);
1.1 deraadt 249: if (getreply(0) > 2) { /* read startup message from server */
250: if (cin)
1.11 millert 251: (void)fclose(cin);
1.1 deraadt 252: if (cout)
1.11 millert 253: (void)fclose(cout);
1.1 deraadt 254: code = -1;
255: goto bad;
256: }
257: #ifdef SO_OOBINLINE
258: {
259: int on = 1;
260:
261: if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
262: < 0 && debug) {
263: warn("setsockopt");
264: }
265: }
266: #endif /* SO_OOBINLINE */
267:
268: return (hostname);
269: bad:
1.11 millert 270: (void)close(s);
1.1 deraadt 271: return ((char *)0);
272: }
273:
1.57 deraadt 274: /* ARGSUSED */
1.1 deraadt 275: void
1.57 deraadt 276: cmdabort(int signo)
1.1 deraadt 277: {
278:
1.10 millert 279: alarmtimer(0);
1.18 deraadt 280: putc('\n', ttyout);
281: (void)fflush(ttyout);
1.1 deraadt 282: abrtflag++;
283: if (ptflag)
1.10 millert 284: longjmp(ptabort, 1);
1.1 deraadt 285: }
286:
287: /*VARARGS*/
288: int
1.13 millert 289: command(const char *fmt, ...)
1.1 deraadt 290: {
291: va_list ap;
292: int r;
293: sig_t oldintr;
294:
295: abrtflag = 0;
296: if (debug) {
1.18 deraadt 297: fputs("---> ", ttyout);
1.13 millert 298: va_start(ap, fmt);
1.1 deraadt 299: if (strncmp("PASS ", fmt, 5) == 0)
1.18 deraadt 300: fputs("PASS XXXX", ttyout);
1.10 millert 301: else if (strncmp("ACCT ", fmt, 5) == 0)
1.18 deraadt 302: fputs("ACCT XXXX", ttyout);
1.10 millert 303: else
1.28 millert 304: vfprintf(ttyout, fmt, ap);
1.1 deraadt 305: va_end(ap);
1.18 deraadt 306: putc('\n', ttyout);
307: (void)fflush(ttyout);
1.1 deraadt 308: }
309: if (cout == NULL) {
1.13 millert 310: warnx("No control connection for command.");
1.1 deraadt 311: code = -1;
312: return (0);
313: }
314: oldintr = signal(SIGINT, cmdabort);
1.13 millert 315: va_start(ap, fmt);
1.1 deraadt 316: vfprintf(cout, fmt, ap);
317: va_end(ap);
1.11 millert 318: fputs("\r\n", cout);
319: (void)fflush(cout);
1.1 deraadt 320: cpend = 1;
321: r = getreply(!strcmp(fmt, "QUIT"));
322: if (abrtflag && oldintr != SIG_IGN)
323: (*oldintr)(SIGINT);
1.11 millert 324: (void)signal(SIGINT, oldintr);
1.1 deraadt 325: return (r);
326: }
327:
1.68 espie 328: int keep_alive_timeout = 60; /* 0 -> no timeout */
1.67 espie 329:
330: static int full_noops_sent = 0;
331: static time_t last_timestamp = 0; /* 0 -> no measurement yet */
332: static char noop[] = "NOOP\r\n";
333: #define NOOP_LENGTH (sizeof noop - 1)
334: static int current_nop_pos = 0; /* 0 -> no noop started */
335:
336: /* to achieve keep alive, we send noop one byte at a time */
337: void
338: send_noop_char()
339: {
340: if (debug)
341: fprintf(ttyout, "---> %c\n", noop[current_nop_pos]);
342: fputc(noop[current_nop_pos++], cout);
343: (void)fflush(cout);
344: if (current_nop_pos >= NOOP_LENGTH) {
345: full_noops_sent++;
346: current_nop_pos = 0;
347: }
348: }
349:
350: void
351: may_reset_noop_timeout()
352: {
353: if (keep_alive_timeout != 0)
354: last_timestamp = time(NULL);
355: }
356:
357: void
358: may_receive_noop_ack()
359: {
360: int i;
361:
362: /* finish sending last incomplete noop */
363: if (current_nop_pos != 0) {
364: fputs(&(noop[current_nop_pos]), cout);
365: if (debug)
366: fprintf(ttyout, "---> %s\n", &(noop[current_nop_pos]));
367: (void)fflush(cout);
368: current_nop_pos = 0;
369: full_noops_sent++;
370: }
371: /* and get the replies */
372: for (i = 0; i < full_noops_sent; i++)
373: (void)getreply(0);
374:
375: full_noops_sent = 0;
376: }
377:
378: void
379: may_send_noop_char()
380: {
381: if (keep_alive_timeout != 0) {
382: if (last_timestamp != 0) {
383: time_t t = time(NULL);
384:
385: if (t - last_timestamp >= keep_alive_timeout) {
386: last_timestamp = t;
387: send_noop_char();
388: }
389: } else {
390: last_timestamp = time(NULL);
391: }
392: }
393: }
394:
1.10 millert 395: char reply_string[BUFSIZ]; /* first line of previous reply */
1.1 deraadt 396:
397: int
1.56 deraadt 398: getreply(int expecteof)
1.1 deraadt 399: {
1.10 millert 400: char current_line[BUFSIZ]; /* last line of previous reply */
1.64 ray 401: int c, n, lineno;
1.1 deraadt 402: int dig;
403: int originalcode = 0, continuation = 0;
404: sig_t oldintr;
405: int pflag = 0;
406: char *cp, *pt = pasv;
407:
1.25 weingart 408: memset(current_line, 0, sizeof(current_line));
1.1 deraadt 409: oldintr = signal(SIGINT, cmdabort);
1.64 ray 410: for (lineno = 0 ;; lineno++) {
1.1 deraadt 411: dig = n = code = 0;
1.10 millert 412: cp = current_line;
1.23 millert 413: while ((c = fgetc(cin)) != '\n') {
1.1 deraadt 414: if (c == IAC) { /* handle telnet commands */
1.23 millert 415: switch (c = fgetc(cin)) {
1.1 deraadt 416: case WILL:
417: case WONT:
1.23 millert 418: c = fgetc(cin);
1.1 deraadt 419: fprintf(cout, "%c%c%c", IAC, DONT, c);
1.11 millert 420: (void)fflush(cout);
1.1 deraadt 421: break;
422: case DO:
423: case DONT:
1.23 millert 424: c = fgetc(cin);
1.1 deraadt 425: fprintf(cout, "%c%c%c", IAC, WONT, c);
1.11 millert 426: (void)fflush(cout);
1.1 deraadt 427: break;
428: default:
429: break;
430: }
431: continue;
432: }
433: dig++;
434: if (c == EOF) {
435: if (expecteof) {
1.11 millert 436: (void)signal(SIGINT, oldintr);
1.1 deraadt 437: code = 221;
438: return (0);
439: }
440: lostpeer();
441: if (verbose) {
1.18 deraadt 442: fputs(
443: "421 Service not available, remote server has closed connection.\n", ttyout);
444: (void)fflush(ttyout);
1.1 deraadt 445: }
446: code = 421;
447: return (4);
448: }
1.10 millert 449: if (c != '\r' && (verbose > 0 ||
1.21 mickey 450: ((verbose > -1 && n == '5' && dig > 4)) &&
451: (((!n && c < '5') || (n && n < '5'))
452: || !retry_connect))) {
1.1 deraadt 453: if (proxflag &&
1.10 millert 454: (dig == 1 || (dig == 5 && verbose == 0)))
1.18 deraadt 455: fprintf(ttyout, "%s:", hostname);
456: (void)putc(c, ttyout);
1.1 deraadt 457: }
458: if (dig < 4 && isdigit(c))
459: code = code * 10 + (c - '0');
1.34 itojun 460: if (!pflag && (code == 227 || code == 228))
1.1 deraadt 461: pflag = 1;
1.34 itojun 462: else if (!pflag && code == 229)
463: pflag = 100;
1.1 deraadt 464: if (dig > 4 && pflag == 1 && isdigit(c))
465: pflag = 2;
466: if (pflag == 2) {
1.44 itojun 467: if (c != '\r' && c != ')') {
468: if (pt < &pasv[sizeof(pasv) - 1])
469: *pt++ = c;
470: } else {
1.1 deraadt 471: *pt = '\0';
472: pflag = 3;
473: }
474: }
1.34 itojun 475: if (pflag == 100 && c == '(')
476: pflag = 2;
1.1 deraadt 477: if (dig == 4 && c == '-') {
478: if (continuation)
479: code = 0;
480: continuation++;
481: }
1.10 millert 482: if (n == 0)
483: n = c;
484: if (cp < ¤t_line[sizeof(current_line) - 1])
1.1 deraadt 485: *cp++ = c;
486: }
1.11 millert 487: if (verbose > 0 || ((verbose > -1 && n == '5') &&
488: (n < '5' || !retry_connect))) {
1.18 deraadt 489: (void)putc(c, ttyout);
490: (void)fflush (ttyout);
1.1 deraadt 491: }
1.64 ray 492: if (lineno == 0) {
1.10 millert 493: size_t len = cp - current_line;
494:
495: if (len > sizeof(reply_string))
496: len = sizeof(reply_string);
497:
1.48 itojun 498: (void)strlcpy(reply_string, current_line, len);
1.10 millert 499: }
1.1 deraadt 500: if (continuation && code != originalcode) {
501: if (originalcode == 0)
502: originalcode = code;
503: continue;
504: }
505: *cp = '\0';
506: if (n != '1')
507: cpend = 0;
1.11 millert 508: (void)signal(SIGINT, oldintr);
1.1 deraadt 509: if (code == 421 || originalcode == 421)
510: lostpeer();
511: if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
512: (*oldintr)(SIGINT);
513: return (n - '0');
514: }
515: }
516:
517: jmp_buf sendabort;
518:
1.57 deraadt 519: /* ARGSUSED */
1.1 deraadt 520: void
1.57 deraadt 521: abortsend(int signo)
1.1 deraadt 522: {
523:
1.10 millert 524: alarmtimer(0);
1.1 deraadt 525: mflag = 0;
526: abrtflag = 0;
1.18 deraadt 527: fputs("\nsend aborted\nwaiting for remote to finish abort.\n", ttyout);
528: (void)fflush(ttyout);
1.1 deraadt 529: longjmp(sendabort, 1);
530: }
531:
532: void
1.56 deraadt 533: sendrequest(const char *cmd, const char *local, const char *remote,
534: int printnames)
1.1 deraadt 535: {
536: struct stat st;
537: int c, d;
1.40 millert 538: FILE * volatile fin, * volatile dout;
1.42 millert 539: int (* volatile closefunc)(FILE *);
1.40 millert 540: volatile sig_t oldinti, oldintr, oldintp;
1.20 millert 541: volatile off_t hashbytes;
1.40 millert 542: char * volatile lmode;
543: char buf[BUFSIZ], *bufp;
1.69 ! ray 544: int oprogress, serrno;
1.1 deraadt 545:
1.10 millert 546: hashbytes = mark;
547: direction = "sent";
1.20 millert 548: dout = NULL;
1.10 millert 549: bytes = 0;
550: filesize = -1;
1.13 millert 551: oprogress = progress;
1.1 deraadt 552: if (verbose && printnames) {
553: if (local && *local != '-')
1.18 deraadt 554: fprintf(ttyout, "local: %s ", local);
1.1 deraadt 555: if (remote)
1.18 deraadt 556: fprintf(ttyout, "remote: %s\n", remote);
1.1 deraadt 557: }
558: if (proxy) {
559: proxtrans(cmd, local, remote);
560: return;
561: }
562: if (curtype != type)
563: changetype(type, 0);
564: closefunc = NULL;
565: oldintr = NULL;
566: oldintp = NULL;
1.10 millert 567: oldinti = NULL;
1.1 deraadt 568: lmode = "w";
569: if (setjmp(sendabort)) {
570: while (cpend) {
1.11 millert 571: (void)getreply(0);
1.1 deraadt 572: }
573: if (data >= 0) {
1.11 millert 574: (void)close(data);
1.1 deraadt 575: data = -1;
576: }
577: if (oldintr)
1.11 millert 578: (void)signal(SIGINT, oldintr);
1.1 deraadt 579: if (oldintp)
1.11 millert 580: (void)signal(SIGPIPE, oldintp);
1.10 millert 581: if (oldinti)
1.11 millert 582: (void)signal(SIGINFO, oldinti);
1.13 millert 583: progress = oprogress;
1.1 deraadt 584: code = -1;
585: return;
586: }
587: oldintr = signal(SIGINT, abortsend);
1.10 millert 588: oldinti = signal(SIGINFO, psummary);
1.13 millert 589: if (strcmp(local, "-") == 0) {
1.1 deraadt 590: fin = stdin;
1.31 millert 591: if (progress == 1)
592: progress = 0;
1.13 millert 593: } else if (*local == '|') {
1.10 millert 594: oldintp = signal(SIGPIPE, SIG_IGN);
1.1 deraadt 595: fin = popen(local + 1, "r");
596: if (fin == NULL) {
597: warn("%s", local + 1);
1.11 millert 598: (void)signal(SIGINT, oldintr);
599: (void)signal(SIGPIPE, oldintp);
600: (void)signal(SIGINFO, oldinti);
1.1 deraadt 601: code = -1;
602: return;
603: }
1.31 millert 604: if (progress == 1)
605: progress = 0;
1.1 deraadt 606: closefunc = pclose;
607: } else {
608: fin = fopen(local, "r");
609: if (fin == NULL) {
610: warn("local: %s", local);
1.11 millert 611: (void)signal(SIGINT, oldintr);
612: (void)signal(SIGINFO, oldinti);
1.1 deraadt 613: code = -1;
614: return;
615: }
616: closefunc = fclose;
617: if (fstat(fileno(fin), &st) < 0 ||
1.14 millert 618: (st.st_mode & S_IFMT) != S_IFREG) {
1.18 deraadt 619: fprintf(ttyout, "%s: not a plain file.\n", local);
1.11 millert 620: (void)signal(SIGINT, oldintr);
621: (void)signal(SIGINFO, oldinti);
1.1 deraadt 622: fclose(fin);
623: code = -1;
624: return;
625: }
1.10 millert 626: filesize = st.st_size;
1.1 deraadt 627: }
628: if (initconn()) {
1.11 millert 629: (void)signal(SIGINT, oldintr);
630: (void)signal(SIGINFO, oldinti);
1.1 deraadt 631: if (oldintp)
1.11 millert 632: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 633: code = -1;
1.13 millert 634: progress = oprogress;
1.1 deraadt 635: if (closefunc != NULL)
636: (*closefunc)(fin);
637: return;
638: }
639: if (setjmp(sendabort))
640: goto abort;
641:
642: if (restart_point &&
643: (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
1.59 deraadt 644: int rc = -1;
1.1 deraadt 645:
646: switch (curtype) {
647: case TYPE_A:
1.58 sturm 648: rc = fseeko(fin, restart_point, SEEK_SET);
1.1 deraadt 649: break;
650: case TYPE_I:
651: case TYPE_L:
1.59 deraadt 652: if (lseek(fileno(fin), restart_point, SEEK_SET) != -1)
653: rc = 0;
1.1 deraadt 654: break;
655: }
1.59 deraadt 656: if (rc == -1) {
1.1 deraadt 657: warn("local: %s", local);
658: restart_point = 0;
1.13 millert 659: progress = oprogress;
1.1 deraadt 660: if (closefunc != NULL)
661: (*closefunc)(fin);
662: return;
663: }
1.58 sturm 664: if (command("REST %lld", (long long) restart_point)
1.1 deraadt 665: != CONTINUE) {
666: restart_point = 0;
1.13 millert 667: progress = oprogress;
1.1 deraadt 668: if (closefunc != NULL)
669: (*closefunc)(fin);
670: return;
671: }
672: restart_point = 0;
673: lmode = "r+w";
674: }
675: if (remote) {
676: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 677: (void)signal(SIGINT, oldintr);
678: (void)signal(SIGINFO, oldinti);
1.13 millert 679: progress = oprogress;
1.1 deraadt 680: if (oldintp)
1.11 millert 681: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 682: if (closefunc != NULL)
683: (*closefunc)(fin);
684: return;
685: }
686: } else
687: if (command("%s", cmd) != PRELIM) {
1.11 millert 688: (void)signal(SIGINT, oldintr);
689: (void)signal(SIGINFO, oldinti);
1.13 millert 690: progress = oprogress;
1.1 deraadt 691: if (oldintp)
1.11 millert 692: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 693: if (closefunc != NULL)
694: (*closefunc)(fin);
695: return;
696: }
697: dout = dataconn(lmode);
698: if (dout == NULL)
699: goto abort;
1.10 millert 700: progressmeter(-1);
1.67 espie 701: may_reset_noop_timeout();
1.1 deraadt 702: oldintp = signal(SIGPIPE, SIG_IGN);
703: switch (curtype) {
704:
705: case TYPE_I:
706: case TYPE_L:
1.69 ! ray 707: d = 0;
1.11 millert 708: while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
1.67 espie 709: may_send_noop_char();
1.1 deraadt 710: bytes += c;
711: for (bufp = buf; c > 0; c -= d, bufp += d)
1.20 millert 712: if ((d = write(fileno(dout), bufp, (size_t)c))
713: <= 0)
1.1 deraadt 714: break;
1.10 millert 715: if (hash && (!progress || filesize < 0) ) {
1.1 deraadt 716: while (bytes >= hashbytes) {
1.18 deraadt 717: (void)putc('#', ttyout);
1.7 kstailey 718: hashbytes += mark;
1.1 deraadt 719: }
1.18 deraadt 720: (void)fflush(ttyout);
1.1 deraadt 721: }
722: }
1.69 ! ray 723: if (c == -1 || d == -1)
! 724: serrno = errno;
1.10 millert 725: if (hash && (!progress || filesize < 0) && bytes > 0) {
1.7 kstailey 726: if (bytes < mark)
1.18 deraadt 727: (void)putc('#', ttyout);
728: (void)putc('\n', ttyout);
729: (void)fflush(ttyout);
1.1 deraadt 730: }
731: if (c < 0)
1.69 ! ray 732: warnx("local: %s: %s", local, strerror(serrno));
1.1 deraadt 733: if (d < 0) {
1.69 ! ray 734: if (serrno != EPIPE)
! 735: warnx("netout: %s", strerror(serrno));
1.1 deraadt 736: bytes = -1;
737: }
738: break;
739:
740: case TYPE_A:
1.23 millert 741: while ((c = fgetc(fin)) != EOF) {
1.67 espie 742: may_send_noop_char();
1.1 deraadt 743: if (c == '\n') {
1.10 millert 744: while (hash && (!progress || filesize < 0) &&
745: (bytes >= hashbytes)) {
1.18 deraadt 746: (void)putc('#', ttyout);
747: (void)fflush(ttyout);
1.7 kstailey 748: hashbytes += mark;
1.1 deraadt 749: }
750: if (ferror(dout))
751: break;
1.11 millert 752: (void)putc('\r', dout);
1.1 deraadt 753: bytes++;
754: }
1.11 millert 755: (void)putc(c, dout);
1.1 deraadt 756: bytes++;
1.10 millert 757: #if 0 /* this violates RFC */
758: if (c == '\r') {
759: (void)putc('\0', dout);
760: bytes++;
761: }
762: #endif
1.1 deraadt 763: }
1.69 ! ray 764: if (ferror(fin) || ferror(dout))
! 765: serrno = errno;
1.10 millert 766: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 767: if (bytes < hashbytes)
1.18 deraadt 768: (void)putc('#', ttyout);
769: (void)putc('\n', ttyout);
770: (void)fflush(ttyout);
1.1 deraadt 771: }
772: if (ferror(fin))
1.69 ! ray 773: warnx("local: %s: %s", local, strerror(serrno));
1.1 deraadt 774: if (ferror(dout)) {
775: if (errno != EPIPE)
1.69 ! ray 776: warnx("netout: %s", strerror(serrno));
1.1 deraadt 777: bytes = -1;
778: }
779: break;
780: }
1.10 millert 781: progressmeter(1);
1.13 millert 782: progress = oprogress;
1.1 deraadt 783: if (closefunc != NULL)
784: (*closefunc)(fin);
1.11 millert 785: (void)fclose(dout);
786: (void)getreply(0);
1.67 espie 787: may_receive_noop_ack();
1.11 millert 788: (void)signal(SIGINT, oldintr);
789: (void)signal(SIGINFO, oldinti);
1.1 deraadt 790: if (oldintp)
1.11 millert 791: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 792: if (bytes > 0)
1.10 millert 793: ptransfer(0);
1.1 deraadt 794: return;
795: abort:
1.11 millert 796: (void)signal(SIGINT, oldintr);
797: (void)signal(SIGINFO, oldinti);
1.13 millert 798: progress = oprogress;
1.1 deraadt 799: if (oldintp)
1.11 millert 800: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 801: if (!cpend) {
802: code = -1;
803: return;
804: }
805: if (data >= 0) {
1.11 millert 806: (void)close(data);
1.1 deraadt 807: data = -1;
808: }
809: if (dout)
1.11 millert 810: (void)fclose(dout);
811: (void)getreply(0);
1.1 deraadt 812: code = -1;
813: if (closefunc != NULL && fin != NULL)
814: (*closefunc)(fin);
815: if (bytes > 0)
1.10 millert 816: ptransfer(0);
1.1 deraadt 817: }
818:
819: jmp_buf recvabort;
820:
1.57 deraadt 821: /* ARGSUSED */
1.1 deraadt 822: void
1.57 deraadt 823: abortrecv(int signo)
1.1 deraadt 824: {
825:
1.10 millert 826: alarmtimer(0);
1.1 deraadt 827: mflag = 0;
828: abrtflag = 0;
1.18 deraadt 829: fputs("\nreceive aborted\nwaiting for remote to finish abort.\n", ttyout);
830: (void)fflush(ttyout);
1.1 deraadt 831: longjmp(recvabort, 1);
832: }
833:
834: void
1.56 deraadt 835: recvrequest(const char *cmd, const char * volatile local, const char *remote,
836: const char *lmode, int printnames, int ignorespecial)
1.1 deraadt 837: {
1.40 millert 838: FILE * volatile fout, * volatile din;
1.42 millert 839: int (* volatile closefunc)(FILE *);
1.40 millert 840: volatile sig_t oldinti, oldintr, oldintp;
1.69 ! ray 841: int c, d, serrno;
1.20 millert 842: volatile int is_retr, tcrflag, bare_lfs;
843: static size_t bufsize;
1.1 deraadt 844: static char *buf;
1.20 millert 845: volatile off_t hashbytes;
1.1 deraadt 846: struct stat st;
1.10 millert 847: time_t mtime;
1.13 millert 848: int oprogress;
1.16 millert 849: int opreserve;
1.1 deraadt 850:
1.20 millert 851: fout = NULL;
852: din = NULL;
853: oldinti = NULL;
1.10 millert 854: hashbytes = mark;
855: direction = "received";
856: bytes = 0;
1.20 millert 857: bare_lfs = 0;
1.10 millert 858: filesize = -1;
1.13 millert 859: oprogress = progress;
1.16 millert 860: opreserve = preserve;
1.1 deraadt 861: is_retr = strcmp(cmd, "RETR") == 0;
862: if (is_retr && verbose && printnames) {
1.22 millert 863: if (local && (ignorespecial || *local != '-'))
1.18 deraadt 864: fprintf(ttyout, "local: %s ", local);
1.1 deraadt 865: if (remote)
1.18 deraadt 866: fprintf(ttyout, "remote: %s\n", remote);
1.1 deraadt 867: }
868: if (proxy && is_retr) {
869: proxtrans(cmd, local, remote);
870: return;
871: }
872: closefunc = NULL;
873: oldintr = NULL;
874: oldintp = NULL;
875: tcrflag = !crflag && is_retr;
876: if (setjmp(recvabort)) {
877: while (cpend) {
1.11 millert 878: (void)getreply(0);
1.1 deraadt 879: }
880: if (data >= 0) {
1.11 millert 881: (void)close(data);
1.1 deraadt 882: data = -1;
883: }
884: if (oldintr)
1.11 millert 885: (void)signal(SIGINT, oldintr);
1.10 millert 886: if (oldinti)
1.11 millert 887: (void)signal(SIGINFO, oldinti);
1.15 millert 888: progress = oprogress;
1.16 millert 889: preserve = opreserve;
1.1 deraadt 890: code = -1;
891: return;
892: }
893: oldintr = signal(SIGINT, abortrecv);
1.10 millert 894: oldinti = signal(SIGINFO, psummary);
1.22 millert 895: if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
896: if (access(local, W_OK) < 0) {
1.69 ! ray 897: char *dir;
1.1 deraadt 898:
899: if (errno != ENOENT && errno != EACCES) {
900: warn("local: %s", local);
1.11 millert 901: (void)signal(SIGINT, oldintr);
902: (void)signal(SIGINFO, oldinti);
1.1 deraadt 903: code = -1;
904: return;
905: }
1.69 ! ray 906: dir = strrchr(local, '/');
1.1 deraadt 907: if (dir != NULL)
908: *dir = 0;
1.22 millert 909: d = access(dir == local ? "/" : dir ? local : ".", W_OK);
1.1 deraadt 910: if (dir != NULL)
911: *dir = '/';
912: if (d < 0) {
913: warn("local: %s", local);
1.11 millert 914: (void)signal(SIGINT, oldintr);
915: (void)signal(SIGINFO, oldinti);
1.1 deraadt 916: code = -1;
917: return;
918: }
919: if (!runique && errno == EACCES &&
1.20 millert 920: chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
1.1 deraadt 921: warn("local: %s", local);
1.11 millert 922: (void)signal(SIGINT, oldintr);
923: (void)signal(SIGINFO, oldinti);
1.1 deraadt 924: code = -1;
925: return;
926: }
927: if (runique && errno == EACCES &&
928: (local = gunique(local)) == NULL) {
1.11 millert 929: (void)signal(SIGINT, oldintr);
930: (void)signal(SIGINFO, oldinti);
1.1 deraadt 931: code = -1;
932: return;
933: }
934: }
935: else if (runique && (local = gunique(local)) == NULL) {
1.11 millert 936: (void)signal(SIGINT, oldintr);
937: (void)signal(SIGINFO, oldinti);
1.1 deraadt 938: code = -1;
939: return;
940: }
941: }
942: if (!is_retr) {
943: if (curtype != TYPE_A)
944: changetype(TYPE_A, 0);
1.10 millert 945: } else {
946: if (curtype != type)
947: changetype(type, 0);
948: filesize = remotesize(remote, 0);
949: }
1.1 deraadt 950: if (initconn()) {
1.11 millert 951: (void)signal(SIGINT, oldintr);
952: (void)signal(SIGINFO, oldinti);
1.1 deraadt 953: code = -1;
954: return;
955: }
956: if (setjmp(recvabort))
957: goto abort;
958: if (is_retr && restart_point &&
1.58 sturm 959: command("REST %lld", (long long) restart_point) != CONTINUE)
1.1 deraadt 960: return;
961: if (remote) {
962: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 963: (void)signal(SIGINT, oldintr);
964: (void)signal(SIGINFO, oldinti);
1.1 deraadt 965: return;
966: }
967: } else {
968: if (command("%s", cmd) != PRELIM) {
1.11 millert 969: (void)signal(SIGINT, oldintr);
970: (void)signal(SIGINFO, oldinti);
1.1 deraadt 971: return;
972: }
973: }
974: din = dataconn("r");
975: if (din == NULL)
976: goto abort;
1.22 millert 977: if (!ignorespecial && strcmp(local, "-") == 0) {
1.1 deraadt 978: fout = stdout;
1.16 millert 979: preserve = 0;
1.22 millert 980: } else if (!ignorespecial && *local == '|') {
1.1 deraadt 981: oldintp = signal(SIGPIPE, SIG_IGN);
982: fout = popen(local + 1, "w");
983: if (fout == NULL) {
984: warn("%s", local+1);
985: goto abort;
986: }
1.31 millert 987: if (progress == 1)
988: progress = 0;
1.16 millert 989: preserve = 0;
1.1 deraadt 990: closefunc = pclose;
991: } else {
992: fout = fopen(local, lmode);
993: if (fout == NULL) {
994: warn("local: %s", local);
995: goto abort;
996: }
997: closefunc = fclose;
998: }
999: if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
1000: st.st_blksize = BUFSIZ;
1001: if (st.st_blksize > bufsize) {
1.65 steven 1002: (void)free(buf);
1.1 deraadt 1003: buf = malloc((unsigned)st.st_blksize);
1004: if (buf == NULL) {
1005: warn("malloc");
1006: bufsize = 0;
1007: goto abort;
1008: }
1009: bufsize = st.st_blksize;
1010: }
1.14 millert 1011: if ((st.st_mode & S_IFMT) != S_IFREG) {
1.31 millert 1012: if (progress == 1)
1013: progress = 0;
1.13 millert 1014: preserve = 0;
1015: }
1.10 millert 1016: progressmeter(-1);
1.67 espie 1017: may_reset_noop_timeout();
1.1 deraadt 1018: switch (curtype) {
1019:
1020: case TYPE_I:
1021: case TYPE_L:
1022: if (restart_point &&
1023: lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1024: warn("local: %s", local);
1.13 millert 1025: progress = oprogress;
1.16 millert 1026: preserve = opreserve;
1.1 deraadt 1027: if (closefunc != NULL)
1028: (*closefunc)(fout);
1029: return;
1030: }
1031: errno = d = 0;
1032: while ((c = read(fileno(din), buf, bufsize)) > 0) {
1.57 deraadt 1033: ssize_t wr;
1.32 deraadt 1034: size_t rd = c;
1035:
1.67 espie 1036: may_send_noop_char();
1.32 deraadt 1037: d = 0;
1038: do {
1039: wr = write(fileno(fout), buf + d, rd);
1040: if (wr == -1 && errno == EPIPE)
1041: break;
1042: d += wr;
1043: rd -= wr;
1044: } while (d < c);
1045: if (rd != 0)
1.1 deraadt 1046: break;
1047: bytes += c;
1.10 millert 1048: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 1049: while (bytes >= hashbytes) {
1.18 deraadt 1050: (void)putc('#', ttyout);
1.7 kstailey 1051: hashbytes += mark;
1.1 deraadt 1052: }
1.18 deraadt 1053: (void)fflush(ttyout);
1.1 deraadt 1054: }
1055: }
1.69 ! ray 1056: if (c == -1 || d < c)
! 1057: serrno = errno;
1.10 millert 1058: if (hash && (!progress || filesize < 0) && bytes > 0) {
1.7 kstailey 1059: if (bytes < mark)
1.18 deraadt 1060: (void)putc('#', ttyout);
1061: (void)putc('\n', ttyout);
1062: (void)fflush(ttyout);
1.1 deraadt 1063: }
1064: if (c < 0) {
1.69 ! ray 1065: if (serrno != EPIPE)
! 1066: warnx("netin: %s", strerror(serrno));
1.1 deraadt 1067: bytes = -1;
1068: }
1069: if (d < c) {
1070: if (d < 0)
1.69 ! ray 1071: warnx("local: %s: %s", local, strerror(serrno));
1.1 deraadt 1072: else
1073: warnx("%s: short write", local);
1074: }
1075: break;
1076:
1077: case TYPE_A:
1078: if (restart_point) {
1079: int i, n, ch;
1080:
1081: if (fseek(fout, 0L, SEEK_SET) < 0)
1082: goto done;
1083: n = restart_point;
1084: for (i = 0; i++ < n;) {
1.69 ! ray 1085: if ((ch = fgetc(fout)) == EOF) {
! 1086: if (!ferror(fout))
! 1087: errno = 0;
1.1 deraadt 1088: goto done;
1.69 ! ray 1089: }
1.1 deraadt 1090: if (ch == '\n')
1091: i++;
1092: }
1093: if (fseek(fout, 0L, SEEK_CUR) < 0) {
1094: done:
1.69 ! ray 1095: if (errno)
! 1096: warn("local: %s", local);
! 1097: else
! 1098: warnx("local: %s", local);
1.13 millert 1099: progress = oprogress;
1.16 millert 1100: preserve = opreserve;
1.1 deraadt 1101: if (closefunc != NULL)
1102: (*closefunc)(fout);
1103: return;
1104: }
1105: }
1.23 millert 1106: while ((c = fgetc(din)) != EOF) {
1.67 espie 1107: may_send_noop_char();
1.1 deraadt 1108: if (c == '\n')
1109: bare_lfs++;
1110: while (c == '\r') {
1.10 millert 1111: while (hash && (!progress || filesize < 0) &&
1112: (bytes >= hashbytes)) {
1.18 deraadt 1113: (void)putc('#', ttyout);
1114: (void)fflush(ttyout);
1.7 kstailey 1115: hashbytes += mark;
1.1 deraadt 1116: }
1117: bytes++;
1.23 millert 1118: if ((c = fgetc(din)) != '\n' || tcrflag) {
1.1 deraadt 1119: if (ferror(fout))
1120: goto break2;
1.11 millert 1121: (void)putc('\r', fout);
1.1 deraadt 1122: if (c == '\0') {
1123: bytes++;
1124: goto contin2;
1125: }
1126: if (c == EOF)
1127: goto contin2;
1128: }
1129: }
1.11 millert 1130: (void)putc(c, fout);
1.1 deraadt 1131: bytes++;
1132: contin2: ;
1133: }
1134: break2:
1.69 ! ray 1135: if (ferror(din) || ferror(fout))
! 1136: serrno = errno;
1.1 deraadt 1137: if (bare_lfs) {
1.22 millert 1138: fprintf(ttyout,
1.13 millert 1139: "WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
1.22 millert 1140: fputs("File may not have transferred correctly.\n",
1141: ttyout);
1.1 deraadt 1142: }
1.10 millert 1143: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 1144: if (bytes < hashbytes)
1.18 deraadt 1145: (void)putc('#', ttyout);
1146: (void)putc('\n', ttyout);
1147: (void)fflush(ttyout);
1.1 deraadt 1148: }
1149: if (ferror(din)) {
1.69 ! ray 1150: if (serrno != EPIPE)
! 1151: warnx("netin: %s", strerror(serrno));
1.1 deraadt 1152: bytes = -1;
1153: }
1154: if (ferror(fout))
1.69 ! ray 1155: warnx("local: %s: %s", local, strerror(serrno));
1.1 deraadt 1156: break;
1157: }
1.10 millert 1158: progressmeter(1);
1.13 millert 1159: progress = oprogress;
1.16 millert 1160: preserve = opreserve;
1.1 deraadt 1161: if (closefunc != NULL)
1162: (*closefunc)(fout);
1.11 millert 1163: (void)signal(SIGINT, oldintr);
1164: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1165: if (oldintp)
1.11 millert 1166: (void)signal(SIGPIPE, oldintp);
1167: (void)fclose(din);
1168: (void)getreply(0);
1.67 espie 1169: may_receive_noop_ack();
1.10 millert 1170: if (bytes >= 0 && is_retr) {
1171: if (bytes > 0)
1172: ptransfer(0);
1173: if (preserve && (closefunc == fclose)) {
1174: mtime = remotemodtime(remote, 0);
1175: if (mtime != -1) {
1.12 millert 1176: struct utimbuf ut;
1177:
1178: ut.actime = time(NULL);
1179: ut.modtime = mtime;
1180: if (utime(local, &ut) == -1)
1.22 millert 1181: fprintf(ttyout,
1.13 millert 1182: "Can't change modification time on %s to %s",
1.11 millert 1183: local, asctime(localtime(&mtime)));
1.10 millert 1184: }
1185: }
1186: }
1.1 deraadt 1187: return;
1.13 millert 1188:
1.1 deraadt 1189: abort:
1190:
1.10 millert 1191: /* abort using RFC959 recommended IP,SYNC sequence */
1.1 deraadt 1192:
1.13 millert 1193: progress = oprogress;
1.16 millert 1194: preserve = opreserve;
1.1 deraadt 1195: if (oldintp)
1.11 millert 1196: (void)signal(SIGPIPE, oldintp);
1197: (void)signal(SIGINT, SIG_IGN);
1.1 deraadt 1198: if (!cpend) {
1199: code = -1;
1.11 millert 1200: (void)signal(SIGINT, oldintr);
1201: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1202: return;
1203: }
1204:
1205: abort_remote(din);
1206: code = -1;
1207: if (data >= 0) {
1.11 millert 1208: (void)close(data);
1.1 deraadt 1209: data = -1;
1210: }
1211: if (closefunc != NULL && fout != NULL)
1212: (*closefunc)(fout);
1213: if (din)
1.11 millert 1214: (void)fclose(din);
1.1 deraadt 1215: if (bytes > 0)
1.10 millert 1216: ptransfer(0);
1.11 millert 1217: (void)signal(SIGINT, oldintr);
1218: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1219: }
1220:
1221: /*
1222: * Need to start a listen on the data channel before we send the command,
1223: * otherwise the server's connect may fail.
1224: */
1225: int
1.56 deraadt 1226: initconn(void)
1.1 deraadt 1227: {
1228: char *p, *a;
1.57 deraadt 1229: int result = ERROR, tmpno = 0;
1.1 deraadt 1230: int on = 1;
1.34 itojun 1231: int error;
1232: u_int addr[16], port[2];
1233: u_int af, hal, pal;
1234: char *pasvcmd = NULL;
1.57 deraadt 1235: socklen_t namelen;
1.34 itojun 1236:
1237: if (myctladdr.su_family == AF_INET6
1238: && (IN6_IS_ADDR_LINKLOCAL(&myctladdr.su_sin6.sin6_addr)
1239: || IN6_IS_ADDR_SITELOCAL(&myctladdr.su_sin6.sin6_addr))) {
1240: warnx("use of scoped address can be troublesome");
1241: }
1.24 millert 1242: reinit:
1.1 deraadt 1243: if (passivemode) {
1.34 itojun 1244: data_addr = myctladdr;
1245: data = socket(data_addr.su_family, SOCK_STREAM, 0);
1.1 deraadt 1246: if (data < 0) {
1.10 millert 1247: warn("socket");
1248: return (1);
1.1 deraadt 1249: }
1250: if ((options & SO_DEBUG) &&
1251: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1.11 millert 1252: sizeof(on)) < 0)
1.10 millert 1253: warn("setsockopt (ignored)");
1.34 itojun 1254: switch (data_addr.su_family) {
1255: case AF_INET:
1.36 itojun 1256: if (epsv4 && !epsv4bad) {
1.66 beck 1257: int ov;
1258: /* shut this command up in case it fails */
1259: ov = verbose;
1260: verbose = -1;
1.36 itojun 1261: result = command(pasvcmd = "EPSV");
1.66 beck 1262: /*
1263: * now back to whatever verbosity we had before
1264: * and we can try PASV
1265: */
1266: verbose = ov;
1.36 itojun 1267: if (code / 10 == 22 && code != 229) {
1268: fputs(
1.34 itojun 1269: "wrong server: return code must be 229\n",
1.36 itojun 1270: ttyout);
1271: result = COMPLETE + 1;
1272: }
1273: if (result != COMPLETE) {
1274: epsv4bad = 1;
1275: if (debug) {
1276: fputs(
1277: "disabling epsv4 for this connection\n",
1278: ttyout);
1279: }
1280: }
1.34 itojun 1281: }
1282: if (result != COMPLETE)
1283: result = command(pasvcmd = "PASV");
1284: break;
1285: case AF_INET6:
1286: result = command(pasvcmd = "EPSV");
1287: if (code / 10 == 22 && code != 229) {
1288: fputs(
1289: "wrong server: return code must be 229\n",
1290: ttyout);
1291: result = COMPLETE + 1;
1292: }
1293: if (result != COMPLETE)
1294: result = command(pasvcmd = "LPSV");
1295: break;
1296: default:
1297: result = COMPLETE + 1;
1298: break;
1299: }
1300: if (result != COMPLETE) {
1.24 millert 1301: if (activefallback) {
1302: (void)close(data);
1303: data = -1;
1304: passivemode = 0;
1305: activefallback = 0;
1306: goto reinit;
1307: }
1.18 deraadt 1308: fputs("Passive mode refused.\n", ttyout);
1.1 deraadt 1309: goto bad;
1310: }
1311:
1.34 itojun 1312: #define pack2(var, off) \
1313: (((var[(off) + 0] & 0xff) << 8) | ((var[(off) + 1] & 0xff) << 0))
1314: #define pack4(var, off) \
1315: (((var[(off) + 0] & 0xff) << 24) | ((var[(off) + 1] & 0xff) << 16) | \
1316: ((var[(off) + 2] & 0xff) << 8) | ((var[(off) + 3] & 0xff) << 0))
1317:
1.1 deraadt 1318: /*
1.34 itojun 1319: * What we've got at this point is a string of comma separated
1320: * one-byte unsigned integer values, separated by commas.
1.1 deraadt 1321: */
1.38 millert 1322: if (!pasvcmd)
1323: goto bad;
1.34 itojun 1324: if (strcmp(pasvcmd, "PASV") == 0) {
1325: if (data_addr.su_family != AF_INET) {
1326: fputs(
1327: "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1328: error = 1;
1329: goto bad;
1330: }
1331: if (code / 10 == 22 && code != 227) {
1332: fputs("wrong server: return code must be 227\n",
1333: ttyout);
1334: error = 1;
1335: goto bad;
1336: }
1337: error = sscanf(pasv, "%u,%u,%u,%u,%u,%u",
1338: &addr[0], &addr[1], &addr[2], &addr[3],
1339: &port[0], &port[1]);
1340: if (error != 6) {
1341: fputs(
1342: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1343: error = 1;
1344: goto bad;
1345: }
1346: error = 0;
1347: memset(&data_addr, 0, sizeof(data_addr));
1348: data_addr.su_family = AF_INET;
1349: data_addr.su_len = sizeof(struct sockaddr_in);
1350: data_addr.su_sin.sin_addr.s_addr =
1351: htonl(pack4(addr, 0));
1352: data_addr.su_port = htons(pack2(port, 0));
1353: } else if (strcmp(pasvcmd, "LPSV") == 0) {
1354: if (code / 10 == 22 && code != 228) {
1355: fputs("wrong server: return code must be 228\n",
1356: ttyout);
1357: error = 1;
1358: goto bad;
1359: }
1360: switch (data_addr.su_family) {
1361: case AF_INET:
1362: error = sscanf(pasv,
1363: "%u,%u,%u,%u,%u,%u,%u,%u,%u",
1364: &af, &hal,
1365: &addr[0], &addr[1], &addr[2], &addr[3],
1366: &pal, &port[0], &port[1]);
1367: if (error != 9) {
1368: fputs(
1369: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1370: error = 1;
1371: goto bad;
1372: }
1373: if (af != 4 || hal != 4 || pal != 2) {
1374: fputs(
1375: "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1376: error = 1;
1377: goto bad;
1378: }
1.1 deraadt 1379:
1.34 itojun 1380: error = 0;
1381: memset(&data_addr, 0, sizeof(data_addr));
1382: data_addr.su_family = AF_INET;
1383: data_addr.su_len = sizeof(struct sockaddr_in);
1384: data_addr.su_sin.sin_addr.s_addr =
1385: htonl(pack4(addr, 0));
1386: data_addr.su_port = htons(pack2(port, 0));
1387: break;
1388: case AF_INET6:
1389: error = sscanf(pasv,
1390: "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
1391: &af, &hal,
1392: &addr[0], &addr[1], &addr[2], &addr[3],
1393: &addr[4], &addr[5], &addr[6], &addr[7],
1394: &addr[8], &addr[9], &addr[10],
1395: &addr[11], &addr[12], &addr[13],
1396: &addr[14], &addr[15],
1397: &pal, &port[0], &port[1]);
1398: if (error != 21) {
1399: fputs(
1.18 deraadt 1400: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1.34 itojun 1401: error = 1;
1402: goto bad;
1403: }
1404: if (af != 6 || hal != 16 || pal != 2) {
1405: fputs(
1406: "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1407: error = 1;
1408: goto bad;
1409: }
1410:
1411: error = 0;
1412: memset(&data_addr, 0, sizeof(data_addr));
1413: data_addr.su_family = AF_INET6;
1414: data_addr.su_len = sizeof(struct sockaddr_in6);
1415: {
1416: u_int32_t *p32;
1417: p32 = (u_int32_t *)&data_addr.su_sin6.sin6_addr;
1418: p32[0] = htonl(pack4(addr, 0));
1419: p32[1] = htonl(pack4(addr, 4));
1420: p32[2] = htonl(pack4(addr, 8));
1421: p32[3] = htonl(pack4(addr, 12));
1422: }
1423: data_addr.su_port = htons(pack2(port, 0));
1424: break;
1425: default:
1426: error = 1;
1427: }
1428: } else if (strcmp(pasvcmd, "EPSV") == 0) {
1429: char delim[4];
1430:
1431: port[0] = 0;
1432: if (code / 10 == 22 && code != 229) {
1433: fputs("wrong server: return code must be 229\n",
1434: ttyout);
1435: error = 1;
1436: goto bad;
1437: }
1438: if (sscanf(pasv, "%c%c%c%d%c", &delim[0],
1439: &delim[1], &delim[2], &port[1],
1440: &delim[3]) != 5) {
1441: fputs("parse error!\n", ttyout);
1442: error = 1;
1443: goto bad;
1444: }
1445: if (delim[0] != delim[1] || delim[0] != delim[2]
1446: || delim[0] != delim[3]) {
1447: fputs("parse error!\n", ttyout);
1448: error = 1;
1449: goto bad;
1450: }
1451: data_addr = hisctladdr;
1452: data_addr.su_port = htons(port[1]);
1453: } else
1.1 deraadt 1454: goto bad;
1455:
1.27 deraadt 1456: while (connect(data, (struct sockaddr *)&data_addr,
1.34 itojun 1457: data_addr.su_len) < 0) {
1.27 deraadt 1458: if (errno == EINTR)
1459: continue;
1.33 millert 1460: if (activefallback) {
1461: (void)close(data);
1462: data = -1;
1463: passivemode = 0;
1464: activefallback = 0;
1465: goto reinit;
1466: }
1.10 millert 1467: warn("connect");
1.1 deraadt 1468: goto bad;
1469: }
1.34 itojun 1470: #if defined(IPPROTO_IP) && defined(IP_TOS)
1471: if (data_addr.su_family == AF_INET) {
1472: on = IPTOS_THROUGHPUT;
1473: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1474: sizeof(int)) < 0)
1475: warn("setsockopt TOS (ignored)");
1476: }
1.1 deraadt 1477: #endif
1.10 millert 1478: return (0);
1.1 deraadt 1479: }
1480:
1481: noport:
1482: data_addr = myctladdr;
1483: if (sendport)
1.34 itojun 1484: data_addr.su_port = 0; /* let system pick one */
1.1 deraadt 1485: if (data != -1)
1.11 millert 1486: (void)close(data);
1.34 itojun 1487: data = socket(data_addr.su_family, SOCK_STREAM, 0);
1.1 deraadt 1488: if (data < 0) {
1489: warn("socket");
1490: if (tmpno)
1491: sendport = 1;
1492: return (1);
1493: }
1494: if (!sendport)
1.10 millert 1495: if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1.11 millert 1496: sizeof(on)) < 0) {
1.1 deraadt 1497: warn("setsockopt (reuse address)");
1498: goto bad;
1499: }
1.49 jakob 1500: switch (data_addr.su_family) {
1501: case AF_INET:
1502: on = IP_PORTRANGE_HIGH;
1503: if (setsockopt(data, IPPROTO_IP, IP_PORTRANGE,
1504: (char *)&on, sizeof(on)) < 0)
1505: warn("setsockopt IP_PORTRANGE (ignored)");
1506: break;
1507: case AF_INET6:
1508: on = IPV6_PORTRANGE_HIGH;
1509: if (setsockopt(data, IPPROTO_IPV6, IPV6_PORTRANGE,
1510: (char *)&on, sizeof(on)) < 0)
1511: warn("setsockopt IPV6_PORTRANGE (ignored)");
1512: break;
1513: }
1.34 itojun 1514: if (bind(data, (struct sockaddr *)&data_addr, data_addr.su_len) < 0) {
1.1 deraadt 1515: warn("bind");
1516: goto bad;
1517: }
1518: if (options & SO_DEBUG &&
1.10 millert 1519: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1.11 millert 1520: sizeof(on)) < 0)
1.1 deraadt 1521: warn("setsockopt (ignored)");
1.57 deraadt 1522: namelen = sizeof(data_addr);
1523: if (getsockname(data, (struct sockaddr *)&data_addr, &namelen) < 0) {
1.1 deraadt 1524: warn("getsockname");
1525: goto bad;
1526: }
1527: if (listen(data, 1) < 0)
1528: warn("listen");
1.34 itojun 1529:
1530: #define UC(b) (((int)b)&0xff)
1531:
1.1 deraadt 1532: if (sendport) {
1.47 itojun 1533: char hname[NI_MAXHOST], pbuf[NI_MAXSERV];
1.64 ray 1534: int af_tmp;
1.47 itojun 1535: union sockunion tmp;
1.34 itojun 1536:
1.47 itojun 1537: tmp = data_addr;
1538: switch (tmp.su_family) {
1.34 itojun 1539: case AF_INET:
1.36 itojun 1540: if (!epsv4 || epsv4bad) {
1541: result = COMPLETE +1;
1542: break;
1543: }
1544: /*FALLTHROUGH*/
1.34 itojun 1545: case AF_INET6:
1.47 itojun 1546: if (tmp.su_family == AF_INET6)
1547: tmp.su_sin6.sin6_scope_id = 0;
1.64 ray 1548: af_tmp = (tmp.su_family == AF_INET) ? 1 : 2;
1.47 itojun 1549: if (getnameinfo((struct sockaddr *)&tmp,
1550: tmp.su_len, hname, sizeof(hname),
1551: pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
1.34 itojun 1552: result = ERROR;
1553: } else {
1.47 itojun 1554: result = command("EPRT |%d|%s|%s|",
1.64 ray 1555: af_tmp, hname, pbuf);
1.36 itojun 1556: if (result != COMPLETE) {
1557: epsv4bad = 1;
1558: if (debug) {
1559: fputs(
1560: "disabling epsv4 for this connection\n",
1561: ttyout);
1562: }
1563: }
1.34 itojun 1564: }
1565: break;
1566: default:
1567: result = COMPLETE + 1;
1568: break;
1569: }
1570: if (result == COMPLETE)
1571: goto skip_port;
1572:
1573: switch (data_addr.su_family) {
1574: case AF_INET:
1575: a = (char *)&data_addr.su_sin.sin_addr;
1576: p = (char *)&data_addr.su_port;
1577: result = command("PORT %d,%d,%d,%d,%d,%d",
1578: UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1579: UC(p[0]), UC(p[1]));
1580: break;
1581: case AF_INET6:
1582: a = (char *)&data_addr.su_sin6.sin6_addr;
1583: p = (char *)&data_addr.su_port;
1584: result = command(
1585: "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1586: 6, 16,
1587: UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
1588: UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
1589: UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
1590: UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
1591: 2, UC(p[0]), UC(p[1]));
1592: break;
1593: default:
1594: result = COMPLETE + 1; /* xxx */
1595: }
1596: skip_port:
1597:
1.1 deraadt 1598: if (result == ERROR && sendport == -1) {
1599: sendport = 0;
1600: tmpno = 1;
1601: goto noport;
1602: }
1603: return (result != COMPLETE);
1604: }
1605: if (tmpno)
1606: sendport = 1;
1.34 itojun 1607: #if defined(IPPROTO_IP) && defined(IP_TOS)
1608: if (data_addr.su_family == AF_INET) {
1609: on = IPTOS_THROUGHPUT;
1610: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1611: sizeof(int)) < 0)
1612: warn("setsockopt TOS (ignored)");
1613: }
1.1 deraadt 1614: #endif
1615: return (0);
1616: bad:
1.11 millert 1617: (void)close(data), data = -1;
1.1 deraadt 1618: if (tmpno)
1619: sendport = 1;
1620: return (1);
1621: }
1622:
1623: FILE *
1.56 deraadt 1624: dataconn(const char *lmode)
1.1 deraadt 1625: {
1.34 itojun 1626: union sockunion from;
1.57 deraadt 1627: socklen_t fromlen = myctladdr.su_len;
1628: int s;
1.1 deraadt 1629:
1630: if (passivemode)
1631: return (fdopen(data, lmode));
1632:
1633: s = accept(data, (struct sockaddr *) &from, &fromlen);
1634: if (s < 0) {
1635: warn("accept");
1.11 millert 1636: (void)close(data), data = -1;
1.1 deraadt 1637: return (NULL);
1638: }
1.11 millert 1639: (void)close(data);
1.1 deraadt 1640: data = s;
1.34 itojun 1641: #if defined(IPPROTO_IP) && defined(IP_TOS)
1642: if (from.su_family == AF_INET) {
1643: int tos = IPTOS_THROUGHPUT;
1644: if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1645: sizeof(int)) < 0) {
1646: warn("setsockopt TOS (ignored)");
1647: }
1648: }
1.1 deraadt 1649: #endif
1650: return (fdopen(data, lmode));
1651: }
1652:
1.57 deraadt 1653: /* ARGSUSED */
1.1 deraadt 1654: void
1.57 deraadt 1655: psummary(int signo)
1.1 deraadt 1656: {
1.26 deraadt 1657: int save_errno = errno;
1.10 millert 1658:
1659: if (bytes > 0)
1660: ptransfer(1);
1.26 deraadt 1661: errno = save_errno;
1.1 deraadt 1662: }
1663:
1.57 deraadt 1664: /* ARGSUSED */
1.1 deraadt 1665: void
1.57 deraadt 1666: psabort(int signo)
1.1 deraadt 1667: {
1668:
1.10 millert 1669: alarmtimer(0);
1.1 deraadt 1670: abrtflag++;
1671: }
1672:
1673: void
1.56 deraadt 1674: pswitch(int flag)
1.1 deraadt 1675: {
1676: sig_t oldintr;
1677: static struct comvars {
1678: int connect;
1679: char name[MAXHOSTNAMELEN];
1.34 itojun 1680: union sockunion mctl;
1681: union sockunion hctl;
1.1 deraadt 1682: FILE *in;
1683: FILE *out;
1684: int tpe;
1685: int curtpe;
1686: int cpnd;
1687: int sunqe;
1688: int runqe;
1689: int mcse;
1690: int ntflg;
1691: char nti[17];
1692: char nto[17];
1693: int mapflg;
1694: char mi[MAXPATHLEN];
1695: char mo[MAXPATHLEN];
1696: } proxstruct, tmpstruct;
1697: struct comvars *ip, *op;
1698:
1699: abrtflag = 0;
1700: oldintr = signal(SIGINT, psabort);
1701: if (flag) {
1702: if (proxy)
1703: return;
1704: ip = &tmpstruct;
1705: op = &proxstruct;
1706: proxy++;
1707: } else {
1708: if (!proxy)
1709: return;
1710: ip = &proxstruct;
1711: op = &tmpstruct;
1712: proxy = 0;
1713: }
1714: ip->connect = connected;
1715: connected = op->connect;
1716: if (hostname) {
1.41 lebel 1717: (void)strlcpy(ip->name, hostname, sizeof(ip->name));
1.1 deraadt 1718: } else
1.11 millert 1719: ip->name[0] = '\0';
1.1 deraadt 1720: hostname = op->name;
1721: ip->hctl = hisctladdr;
1722: hisctladdr = op->hctl;
1723: ip->mctl = myctladdr;
1724: myctladdr = op->mctl;
1725: ip->in = cin;
1726: cin = op->in;
1727: ip->out = cout;
1728: cout = op->out;
1729: ip->tpe = type;
1730: type = op->tpe;
1731: ip->curtpe = curtype;
1732: curtype = op->curtpe;
1733: ip->cpnd = cpend;
1734: cpend = op->cpnd;
1735: ip->sunqe = sunique;
1736: sunique = op->sunqe;
1737: ip->runqe = runique;
1738: runique = op->runqe;
1739: ip->mcse = mcase;
1740: mcase = op->mcse;
1741: ip->ntflg = ntflag;
1742: ntflag = op->ntflg;
1.41 lebel 1743: (void)strlcpy(ip->nti, ntin, sizeof(ip->nti));
1.52 deraadt 1744: (void)strlcpy(ntin, op->nti, sizeof ntin);
1.41 lebel 1745: (void)strlcpy(ip->nto, ntout, sizeof(ip->nto));
1.52 deraadt 1746: (void)strlcpy(ntout, op->nto, sizeof ntout);
1.1 deraadt 1747: ip->mapflg = mapflag;
1748: mapflag = op->mapflg;
1.41 lebel 1749: (void)strlcpy(ip->mi, mapin, sizeof(ip->mi));
1.52 deraadt 1750: (void)strlcpy(mapin, op->mi, sizeof mapin);
1.41 lebel 1751: (void)strlcpy(ip->mo, mapout, sizeof(ip->mo));
1.52 deraadt 1752: (void)strlcpy(mapout, op->mo, sizeof mapout);
1.11 millert 1753: (void)signal(SIGINT, oldintr);
1.1 deraadt 1754: if (abrtflag) {
1755: abrtflag = 0;
1756: (*oldintr)(SIGINT);
1757: }
1758: }
1759:
1.57 deraadt 1760: /* ARGSUSED */
1.1 deraadt 1761: void
1.57 deraadt 1762: abortpt(int signo)
1.1 deraadt 1763: {
1764:
1.10 millert 1765: alarmtimer(0);
1.18 deraadt 1766: putc('\n', ttyout);
1767: (void)fflush(ttyout);
1.1 deraadt 1768: ptabflg++;
1769: mflag = 0;
1770: abrtflag = 0;
1771: longjmp(ptabort, 1);
1772: }
1773:
1774: void
1.56 deraadt 1775: proxtrans(const char *cmd, const char *local, const char *remote)
1.1 deraadt 1776: {
1.40 millert 1777: volatile sig_t oldintr;
1.20 millert 1778: int prox_type, nfnd;
1779: volatile int secndflag;
1.40 millert 1780: char * volatile cmd2;
1.54 millert 1781: struct pollfd pfd[1];
1.20 millert 1782:
1783: oldintr = NULL;
1784: secndflag = 0;
1.1 deraadt 1785: if (strcmp(cmd, "RETR"))
1786: cmd2 = "RETR";
1787: else
1788: cmd2 = runique ? "STOU" : "STOR";
1789: if ((prox_type = type) == 0) {
1790: if (unix_server && unix_proxy)
1791: prox_type = TYPE_I;
1792: else
1793: prox_type = TYPE_A;
1794: }
1795: if (curtype != prox_type)
1796: changetype(prox_type, 1);
1797: if (command("PASV") != COMPLETE) {
1.18 deraadt 1798: fputs("proxy server does not support third party transfers.\n",
1799: ttyout);
1.1 deraadt 1800: return;
1801: }
1802: pswitch(0);
1803: if (!connected) {
1.18 deraadt 1804: fputs("No primary connection.\n", ttyout);
1.1 deraadt 1805: pswitch(1);
1806: code = -1;
1807: return;
1808: }
1809: if (curtype != prox_type)
1810: changetype(prox_type, 1);
1811: if (command("PORT %s", pasv) != COMPLETE) {
1812: pswitch(1);
1813: return;
1814: }
1815: if (setjmp(ptabort))
1816: goto abort;
1817: oldintr = signal(SIGINT, abortpt);
1818: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 1819: (void)signal(SIGINT, oldintr);
1.1 deraadt 1820: pswitch(1);
1821: return;
1822: }
1823: sleep(2);
1824: pswitch(1);
1825: secndflag++;
1826: if (command("%s %s", cmd2, local) != PRELIM)
1827: goto abort;
1828: ptflag++;
1.11 millert 1829: (void)getreply(0);
1.1 deraadt 1830: pswitch(0);
1.11 millert 1831: (void)getreply(0);
1832: (void)signal(SIGINT, oldintr);
1.1 deraadt 1833: pswitch(1);
1834: ptflag = 0;
1.18 deraadt 1835: fprintf(ttyout, "local: %s remote: %s\n", local, remote);
1.1 deraadt 1836: return;
1837: abort:
1.11 millert 1838: (void)signal(SIGINT, SIG_IGN);
1.1 deraadt 1839: ptflag = 0;
1840: if (strcmp(cmd, "RETR") && !proxy)
1841: pswitch(1);
1842: else if (!strcmp(cmd, "RETR") && proxy)
1843: pswitch(0);
1844: if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1845: if (command("%s %s", cmd2, local) != PRELIM) {
1846: pswitch(0);
1847: if (cpend)
1.19 kstailey 1848: abort_remote(NULL);
1.1 deraadt 1849: }
1850: pswitch(1);
1851: if (ptabflg)
1852: code = -1;
1.11 millert 1853: (void)signal(SIGINT, oldintr);
1.1 deraadt 1854: return;
1855: }
1856: if (cpend)
1.19 kstailey 1857: abort_remote(NULL);
1.1 deraadt 1858: pswitch(!proxy);
1859: if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1860: if (command("%s %s", cmd2, local) != PRELIM) {
1861: pswitch(0);
1862: if (cpend)
1.19 kstailey 1863: abort_remote(NULL);
1.1 deraadt 1864: pswitch(1);
1865: if (ptabflg)
1866: code = -1;
1.11 millert 1867: (void)signal(SIGINT, oldintr);
1.1 deraadt 1868: return;
1869: }
1870: }
1871: if (cpend)
1.19 kstailey 1872: abort_remote(NULL);
1.1 deraadt 1873: pswitch(!proxy);
1874: if (cpend) {
1.54 millert 1875: pfd[0].fd = fileno(cin);
1876: pfd[0].events = POLLIN;
1877: if ((nfnd = poll(pfd, 1, 10 * 1000)) <= 0) {
1878: if (nfnd < 0)
1.1 deraadt 1879: warn("abort");
1880: if (ptabflg)
1881: code = -1;
1882: lostpeer();
1883: }
1.11 millert 1884: (void)getreply(0);
1885: (void)getreply(0);
1.1 deraadt 1886: }
1887: if (proxy)
1888: pswitch(0);
1889: pswitch(1);
1890: if (ptabflg)
1891: code = -1;
1.11 millert 1892: (void)signal(SIGINT, oldintr);
1.1 deraadt 1893: }
1894:
1.57 deraadt 1895: /* ARGSUSED */
1.1 deraadt 1896: void
1.56 deraadt 1897: reset(int argc, char *argv[])
1.1 deraadt 1898: {
1.54 millert 1899: struct pollfd pfd[1];
1.1 deraadt 1900: int nfnd = 1;
1901:
1.54 millert 1902: pfd[0].fd = fileno(cin);
1903: pfd[0].events = POLLIN;
1.1 deraadt 1904: while (nfnd > 0) {
1.54 millert 1905: if ((nfnd = poll(pfd, 1, 0)) < 0) {
1.1 deraadt 1906: warn("reset");
1907: code = -1;
1908: lostpeer();
1.54 millert 1909: } else if (nfnd) {
1.11 millert 1910: (void)getreply(0);
1.1 deraadt 1911: }
1912: }
1913: }
1914:
1915: char *
1.56 deraadt 1916: gunique(const char *local)
1.1 deraadt 1917: {
1918: static char new[MAXPATHLEN];
1919: char *cp = strrchr(local, '/');
1920: int d, count=0;
1921: char ext = '1';
1922:
1923: if (cp)
1924: *cp = '\0';
1.22 millert 1925: d = access(cp == local ? "/" : cp ? local : ".", W_OK);
1.1 deraadt 1926: if (cp)
1927: *cp = '/';
1928: if (d < 0) {
1929: warn("local: %s", local);
1930: return ((char *) 0);
1931: }
1.52 deraadt 1932: (void)strlcpy(new, local, sizeof new);
1.1 deraadt 1933: cp = new + strlen(new);
1934: *cp++ = '.';
1935: while (!d) {
1936: if (++count == 100) {
1.18 deraadt 1937: fputs("runique: can't find unique file name.\n", ttyout);
1.1 deraadt 1938: return ((char *) 0);
1939: }
1940: *cp++ = ext;
1941: *cp = '\0';
1942: if (ext == '9')
1943: ext = '0';
1944: else
1945: ext++;
1.22 millert 1946: if ((d = access(new, F_OK)) < 0)
1.1 deraadt 1947: break;
1948: if (ext != '0')
1949: cp--;
1950: else if (*(cp - 2) == '.')
1951: *(cp - 1) = '1';
1952: else {
1953: *(cp - 2) = *(cp - 2) + 1;
1954: cp--;
1955: }
1956: }
1957: return (new);
1958: }
1959:
1960: void
1.56 deraadt 1961: abort_remote(FILE *din)
1.1 deraadt 1962: {
1963: char buf[BUFSIZ];
1964: int nfnd;
1.54 millert 1965: struct pollfd pfd[2];
1.13 millert 1966:
1967: if (cout == NULL) {
1968: warnx("Lost control connection for abort.");
1969: if (ptabflg)
1970: code = -1;
1971: lostpeer();
1972: return;
1973: }
1.1 deraadt 1974:
1975: /*
1976: * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1977: * after urgent byte rather than before as is protocol now
1978: */
1.46 deraadt 1979: snprintf(buf, sizeof buf, "%c%c%c", IAC, IP, IAC);
1.1 deraadt 1980: if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1981: warn("abort");
1.10 millert 1982: fprintf(cout, "%cABOR\r\n", DM);
1.11 millert 1983: (void)fflush(cout);
1.54 millert 1984: pfd[0].fd = fileno(cin);
1985: pfd[0].events = POLLIN;
1986: nfnd = 1;
1.10 millert 1987: if (din) {
1.54 millert 1988: pfd[1].fd = fileno(din);
1989: pfd[1].events = POLLIN;
1990: nfnd++;
1.1 deraadt 1991: }
1.54 millert 1992: if ((nfnd = poll(pfd, nfnd, 10 * 1000)) <= 0) {
1993: if (nfnd < 0)
1.1 deraadt 1994: warn("abort");
1995: if (ptabflg)
1996: code = -1;
1997: lostpeer();
1998: }
1.54 millert 1999: if (din && (pfd[1].revents & POLLIN)) {
1.1 deraadt 2000: while (read(fileno(din), buf, BUFSIZ) > 0)
2001: /* LOOP */;
2002: }
2003: if (getreply(0) == ERROR && code == 552) {
2004: /* 552 needed for nic style abort */
1.11 millert 2005: (void)getreply(0);
1.1 deraadt 2006: }
1.11 millert 2007: (void)getreply(0);
1.1 deraadt 2008: }