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