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