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