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