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