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