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