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