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