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