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