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