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