Annotation of src/usr.bin/ftp/ftp.c, Revision 1.39
1.39 ! itojun 1: /* $OpenBSD: ftp.c,v 1.38 2000/06/30 16:00:14 millert Exp $ */
1.22 millert 2: /* $NetBSD: ftp.c,v 1.27 1997/08/18 10:20:23 lukem Exp $ */
1.1 deraadt 3:
4: /*
1.34 itojun 5: * Copyright (C) 1997 and 1998 WIDE Project.
6: * All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the project nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
19: *
20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
1.1 deraadt 34: * Copyright (c) 1985, 1989, 1993, 1994
35: * The Regents of the University of California. All rights reserved.
36: *
37: * Redistribution and use in source and binary forms, with or without
38: * modification, are permitted provided that the following conditions
39: * are met:
40: * 1. Redistributions of source code must retain the above copyright
41: * notice, this list of conditions and the following disclaimer.
42: * 2. Redistributions in binary form must reproduce the above copyright
43: * notice, this list of conditions and the following disclaimer in the
44: * documentation and/or other materials provided with the distribution.
45: * 3. All advertising materials mentioning features or use of this software
46: * must display the following acknowledgement:
47: * This product includes software developed by the University of
48: * California, Berkeley and its contributors.
49: * 4. Neither the name of the University nor the names of its contributors
50: * may be used to endorse or promote products derived from this software
51: * without specific prior written permission.
52: *
53: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63: * SUCH DAMAGE.
64: */
65:
66: #ifndef lint
67: #if 0
68: static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
69: #else
1.39 ! itojun 70: static char rcsid[] = "$OpenBSD: ftp.c,v 1.38 2000/06/30 16:00:14 millert 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.20 millert 510: FILE *fin, *dout;
1.1 deraadt 511: int (*closefunc) __P((FILE *));
1.10 millert 512: sig_t oldinti, oldintr, oldintp;
1.20 millert 513: volatile off_t hashbytes;
1.1 deraadt 514: char *lmode, buf[BUFSIZ], *bufp;
1.13 millert 515: int oprogress;
1.1 deraadt 516:
1.20 millert 517: #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
518: (void)&fin;
519: (void)&dout;
520: (void)&closefunc;
521: (void)&oldinti;
522: (void)&oldintr;
523: (void)&oldintp;
524: (void)&lmode;
525: #endif
526:
1.10 millert 527: hashbytes = mark;
528: direction = "sent";
1.20 millert 529: dout = NULL;
1.10 millert 530: bytes = 0;
531: filesize = -1;
1.13 millert 532: oprogress = progress;
1.1 deraadt 533: if (verbose && printnames) {
534: if (local && *local != '-')
1.18 deraadt 535: fprintf(ttyout, "local: %s ", local);
1.1 deraadt 536: if (remote)
1.18 deraadt 537: fprintf(ttyout, "remote: %s\n", remote);
1.1 deraadt 538: }
539: if (proxy) {
540: proxtrans(cmd, local, remote);
541: return;
542: }
543: if (curtype != type)
544: changetype(type, 0);
545: closefunc = NULL;
546: oldintr = NULL;
547: oldintp = NULL;
1.10 millert 548: oldinti = NULL;
1.1 deraadt 549: lmode = "w";
550: if (setjmp(sendabort)) {
551: while (cpend) {
1.11 millert 552: (void)getreply(0);
1.1 deraadt 553: }
554: if (data >= 0) {
1.11 millert 555: (void)close(data);
1.1 deraadt 556: data = -1;
557: }
558: if (oldintr)
1.11 millert 559: (void)signal(SIGINT, oldintr);
1.1 deraadt 560: if (oldintp)
1.11 millert 561: (void)signal(SIGPIPE, oldintp);
1.10 millert 562: if (oldinti)
1.11 millert 563: (void)signal(SIGINFO, oldinti);
1.13 millert 564: progress = oprogress;
1.1 deraadt 565: code = -1;
566: return;
567: }
568: oldintr = signal(SIGINT, abortsend);
1.10 millert 569: oldinti = signal(SIGINFO, psummary);
1.13 millert 570: if (strcmp(local, "-") == 0) {
1.1 deraadt 571: fin = stdin;
1.31 millert 572: if (progress == 1)
573: progress = 0;
1.13 millert 574: } else if (*local == '|') {
1.10 millert 575: oldintp = signal(SIGPIPE, SIG_IGN);
1.1 deraadt 576: fin = popen(local + 1, "r");
577: if (fin == NULL) {
578: warn("%s", local + 1);
1.11 millert 579: (void)signal(SIGINT, oldintr);
580: (void)signal(SIGPIPE, oldintp);
581: (void)signal(SIGINFO, oldinti);
1.1 deraadt 582: code = -1;
583: return;
584: }
1.31 millert 585: if (progress == 1)
586: progress = 0;
1.1 deraadt 587: closefunc = pclose;
588: } else {
589: fin = fopen(local, "r");
590: if (fin == NULL) {
591: warn("local: %s", local);
1.11 millert 592: (void)signal(SIGINT, oldintr);
593: (void)signal(SIGINFO, oldinti);
1.1 deraadt 594: code = -1;
595: return;
596: }
597: closefunc = fclose;
598: if (fstat(fileno(fin), &st) < 0 ||
1.14 millert 599: (st.st_mode & S_IFMT) != S_IFREG) {
1.18 deraadt 600: fprintf(ttyout, "%s: not a plain file.\n", local);
1.11 millert 601: (void)signal(SIGINT, oldintr);
602: (void)signal(SIGINFO, oldinti);
1.1 deraadt 603: fclose(fin);
604: code = -1;
605: return;
606: }
1.10 millert 607: filesize = st.st_size;
1.1 deraadt 608: }
609: if (initconn()) {
1.11 millert 610: (void)signal(SIGINT, oldintr);
611: (void)signal(SIGINFO, oldinti);
1.1 deraadt 612: if (oldintp)
1.11 millert 613: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 614: code = -1;
1.13 millert 615: progress = oprogress;
1.1 deraadt 616: if (closefunc != NULL)
617: (*closefunc)(fin);
618: return;
619: }
620: if (setjmp(sendabort))
621: goto abort;
622:
623: if (restart_point &&
624: (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
625: int rc;
626:
1.10 millert 627: rc = -1;
1.1 deraadt 628: switch (curtype) {
629: case TYPE_A:
630: rc = fseek(fin, (long) restart_point, SEEK_SET);
631: break;
632: case TYPE_I:
633: case TYPE_L:
634: rc = lseek(fileno(fin), restart_point, SEEK_SET);
635: break;
636: }
637: if (rc < 0) {
638: warn("local: %s", local);
639: restart_point = 0;
1.13 millert 640: progress = oprogress;
1.1 deraadt 641: if (closefunc != NULL)
642: (*closefunc)(fin);
643: return;
644: }
645: if (command("REST %ld", (long) restart_point)
646: != CONTINUE) {
647: restart_point = 0;
1.13 millert 648: progress = oprogress;
1.1 deraadt 649: if (closefunc != NULL)
650: (*closefunc)(fin);
651: return;
652: }
653: restart_point = 0;
654: lmode = "r+w";
655: }
656: if (remote) {
657: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 658: (void)signal(SIGINT, oldintr);
659: (void)signal(SIGINFO, oldinti);
1.13 millert 660: progress = oprogress;
1.1 deraadt 661: if (oldintp)
1.11 millert 662: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 663: if (closefunc != NULL)
664: (*closefunc)(fin);
665: return;
666: }
667: } else
668: if (command("%s", cmd) != PRELIM) {
1.11 millert 669: (void)signal(SIGINT, oldintr);
670: (void)signal(SIGINFO, oldinti);
1.13 millert 671: progress = oprogress;
1.1 deraadt 672: if (oldintp)
1.11 millert 673: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 674: if (closefunc != NULL)
675: (*closefunc)(fin);
676: return;
677: }
678: dout = dataconn(lmode);
679: if (dout == NULL)
680: goto abort;
1.10 millert 681: progressmeter(-1);
1.1 deraadt 682: oldintp = signal(SIGPIPE, SIG_IGN);
683: switch (curtype) {
684:
685: case TYPE_I:
686: case TYPE_L:
687: errno = d = 0;
1.11 millert 688: while ((c = read(fileno(fin), buf, sizeof(buf))) > 0) {
1.1 deraadt 689: bytes += c;
690: for (bufp = buf; c > 0; c -= d, bufp += d)
1.20 millert 691: if ((d = write(fileno(dout), bufp, (size_t)c))
692: <= 0)
1.1 deraadt 693: break;
1.10 millert 694: if (hash && (!progress || filesize < 0) ) {
1.1 deraadt 695: while (bytes >= hashbytes) {
1.18 deraadt 696: (void)putc('#', ttyout);
1.7 kstailey 697: hashbytes += mark;
1.1 deraadt 698: }
1.18 deraadt 699: (void)fflush(ttyout);
1.1 deraadt 700: }
701: }
1.10 millert 702: if (hash && (!progress || filesize < 0) && bytes > 0) {
1.7 kstailey 703: if (bytes < mark)
1.18 deraadt 704: (void)putc('#', ttyout);
705: (void)putc('\n', ttyout);
706: (void)fflush(ttyout);
1.1 deraadt 707: }
708: if (c < 0)
709: warn("local: %s", local);
710: if (d < 0) {
1.10 millert 711: if (errno != EPIPE)
1.1 deraadt 712: warn("netout");
713: bytes = -1;
714: }
715: break;
716:
717: case TYPE_A:
1.23 millert 718: while ((c = fgetc(fin)) != EOF) {
1.1 deraadt 719: if (c == '\n') {
1.10 millert 720: while (hash && (!progress || filesize < 0) &&
721: (bytes >= hashbytes)) {
1.18 deraadt 722: (void)putc('#', ttyout);
723: (void)fflush(ttyout);
1.7 kstailey 724: hashbytes += mark;
1.1 deraadt 725: }
726: if (ferror(dout))
727: break;
1.11 millert 728: (void)putc('\r', dout);
1.1 deraadt 729: bytes++;
730: }
1.11 millert 731: (void)putc(c, dout);
1.1 deraadt 732: bytes++;
1.10 millert 733: #if 0 /* this violates RFC */
734: if (c == '\r') {
735: (void)putc('\0', dout);
736: bytes++;
737: }
738: #endif
1.1 deraadt 739: }
1.10 millert 740: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 741: if (bytes < hashbytes)
1.18 deraadt 742: (void)putc('#', ttyout);
743: (void)putc('\n', ttyout);
744: (void)fflush(ttyout);
1.1 deraadt 745: }
746: if (ferror(fin))
747: warn("local: %s", local);
748: if (ferror(dout)) {
749: if (errno != EPIPE)
750: warn("netout");
751: bytes = -1;
752: }
753: break;
754: }
1.10 millert 755: progressmeter(1);
1.13 millert 756: progress = oprogress;
1.1 deraadt 757: if (closefunc != NULL)
758: (*closefunc)(fin);
1.11 millert 759: (void)fclose(dout);
760: (void)getreply(0);
761: (void)signal(SIGINT, oldintr);
762: (void)signal(SIGINFO, oldinti);
1.1 deraadt 763: if (oldintp)
1.11 millert 764: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 765: if (bytes > 0)
1.10 millert 766: ptransfer(0);
1.1 deraadt 767: return;
768: abort:
1.11 millert 769: (void)signal(SIGINT, oldintr);
770: (void)signal(SIGINFO, oldinti);
1.13 millert 771: progress = oprogress;
1.1 deraadt 772: if (oldintp)
1.11 millert 773: (void)signal(SIGPIPE, oldintp);
1.1 deraadt 774: if (!cpend) {
775: code = -1;
776: return;
777: }
778: if (data >= 0) {
1.11 millert 779: (void)close(data);
1.1 deraadt 780: data = -1;
781: }
782: if (dout)
1.11 millert 783: (void)fclose(dout);
784: (void)getreply(0);
1.1 deraadt 785: code = -1;
786: if (closefunc != NULL && fin != NULL)
787: (*closefunc)(fin);
788: if (bytes > 0)
1.10 millert 789: ptransfer(0);
1.1 deraadt 790: }
791:
792: jmp_buf recvabort;
793:
794: void
1.12 millert 795: abortrecv(notused)
796: int notused;
1.1 deraadt 797: {
798:
1.10 millert 799: alarmtimer(0);
1.1 deraadt 800: mflag = 0;
801: abrtflag = 0;
1.18 deraadt 802: fputs("\nreceive aborted\nwaiting for remote to finish abort.\n", ttyout);
803: (void)fflush(ttyout);
1.1 deraadt 804: longjmp(recvabort, 1);
805: }
806:
807: void
1.22 millert 808: recvrequest(cmd, local, remote, lmode, printnames, ignorespecial)
1.10 millert 809: const char *cmd, *local, *remote, *lmode;
1.22 millert 810: int printnames, ignorespecial;
1.1 deraadt 811: {
1.20 millert 812: FILE *fout, *din;
1.1 deraadt 813: int (*closefunc) __P((FILE *));
1.10 millert 814: sig_t oldinti, oldintr, oldintp;
1.20 millert 815: int c, d;
816: volatile int is_retr, tcrflag, bare_lfs;
817: static size_t bufsize;
1.1 deraadt 818: static char *buf;
1.20 millert 819: volatile off_t hashbytes;
1.1 deraadt 820: struct stat st;
1.10 millert 821: time_t mtime;
1.13 millert 822: int oprogress;
1.16 millert 823: int opreserve;
1.1 deraadt 824:
1.20 millert 825: #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
826: (void)&local;
827: (void)&fout;
828: (void)&din;
829: (void)&closefunc;
830: (void)&oldinti;
831: (void)&oldintr;
832: (void)&oldintp;
833: #endif
834:
835: fout = NULL;
836: din = NULL;
837: oldinti = NULL;
1.10 millert 838: hashbytes = mark;
839: direction = "received";
840: bytes = 0;
1.20 millert 841: bare_lfs = 0;
1.10 millert 842: filesize = -1;
1.13 millert 843: oprogress = progress;
1.16 millert 844: opreserve = preserve;
1.1 deraadt 845: is_retr = strcmp(cmd, "RETR") == 0;
846: if (is_retr && verbose && printnames) {
1.22 millert 847: if (local && (ignorespecial || *local != '-'))
1.18 deraadt 848: fprintf(ttyout, "local: %s ", local);
1.1 deraadt 849: if (remote)
1.18 deraadt 850: fprintf(ttyout, "remote: %s\n", remote);
1.1 deraadt 851: }
852: if (proxy && is_retr) {
853: proxtrans(cmd, local, remote);
854: return;
855: }
856: closefunc = NULL;
857: oldintr = NULL;
858: oldintp = NULL;
859: tcrflag = !crflag && is_retr;
860: if (setjmp(recvabort)) {
861: while (cpend) {
1.11 millert 862: (void)getreply(0);
1.1 deraadt 863: }
864: if (data >= 0) {
1.11 millert 865: (void)close(data);
1.1 deraadt 866: data = -1;
867: }
868: if (oldintr)
1.11 millert 869: (void)signal(SIGINT, oldintr);
1.10 millert 870: if (oldinti)
1.11 millert 871: (void)signal(SIGINFO, oldinti);
1.15 millert 872: progress = oprogress;
1.16 millert 873: preserve = opreserve;
1.1 deraadt 874: code = -1;
875: return;
876: }
877: oldintr = signal(SIGINT, abortrecv);
1.10 millert 878: oldinti = signal(SIGINFO, psummary);
1.22 millert 879: if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
880: if (access(local, W_OK) < 0) {
1.1 deraadt 881: char *dir = strrchr(local, '/');
882:
883: if (errno != ENOENT && errno != EACCES) {
884: warn("local: %s", local);
1.11 millert 885: (void)signal(SIGINT, oldintr);
886: (void)signal(SIGINFO, oldinti);
1.1 deraadt 887: code = -1;
888: return;
889: }
890: if (dir != NULL)
891: *dir = 0;
1.22 millert 892: d = access(dir == local ? "/" : dir ? local : ".", W_OK);
1.1 deraadt 893: if (dir != NULL)
894: *dir = '/';
895: if (d < 0) {
896: warn("local: %s", local);
1.11 millert 897: (void)signal(SIGINT, oldintr);
898: (void)signal(SIGINFO, oldinti);
1.1 deraadt 899: code = -1;
900: return;
901: }
902: if (!runique && errno == EACCES &&
1.20 millert 903: chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
1.1 deraadt 904: warn("local: %s", local);
1.11 millert 905: (void)signal(SIGINT, oldintr);
906: (void)signal(SIGINFO, oldinti);
1.1 deraadt 907: code = -1;
908: return;
909: }
910: if (runique && errno == EACCES &&
911: (local = gunique(local)) == NULL) {
1.11 millert 912: (void)signal(SIGINT, oldintr);
913: (void)signal(SIGINFO, oldinti);
1.1 deraadt 914: code = -1;
915: return;
916: }
917: }
918: else if (runique && (local = gunique(local)) == NULL) {
1.11 millert 919: (void)signal(SIGINT, oldintr);
920: (void)signal(SIGINFO, oldinti);
1.1 deraadt 921: code = -1;
922: return;
923: }
924: }
925: if (!is_retr) {
926: if (curtype != TYPE_A)
927: changetype(TYPE_A, 0);
1.10 millert 928: } else {
929: if (curtype != type)
930: changetype(type, 0);
931: filesize = remotesize(remote, 0);
932: }
1.1 deraadt 933: if (initconn()) {
1.11 millert 934: (void)signal(SIGINT, oldintr);
935: (void)signal(SIGINFO, oldinti);
1.1 deraadt 936: code = -1;
937: return;
938: }
939: if (setjmp(recvabort))
940: goto abort;
941: if (is_retr && restart_point &&
942: command("REST %ld", (long) restart_point) != CONTINUE)
943: return;
944: if (remote) {
945: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 946: (void)signal(SIGINT, oldintr);
947: (void)signal(SIGINFO, oldinti);
1.1 deraadt 948: return;
949: }
950: } else {
951: if (command("%s", cmd) != PRELIM) {
1.11 millert 952: (void)signal(SIGINT, oldintr);
953: (void)signal(SIGINFO, oldinti);
1.1 deraadt 954: return;
955: }
956: }
957: din = dataconn("r");
958: if (din == NULL)
959: goto abort;
1.22 millert 960: if (!ignorespecial && strcmp(local, "-") == 0) {
1.1 deraadt 961: fout = stdout;
1.16 millert 962: preserve = 0;
1.22 millert 963: } else if (!ignorespecial && *local == '|') {
1.1 deraadt 964: oldintp = signal(SIGPIPE, SIG_IGN);
965: fout = popen(local + 1, "w");
966: if (fout == NULL) {
967: warn("%s", local+1);
968: goto abort;
969: }
1.31 millert 970: if (progress == 1)
971: progress = 0;
1.16 millert 972: preserve = 0;
1.1 deraadt 973: closefunc = pclose;
974: } else {
975: fout = fopen(local, lmode);
976: if (fout == NULL) {
977: warn("local: %s", local);
978: goto abort;
979: }
980: closefunc = fclose;
981: }
982: if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
983: st.st_blksize = BUFSIZ;
984: if (st.st_blksize > bufsize) {
985: if (buf)
1.11 millert 986: (void)free(buf);
1.1 deraadt 987: buf = malloc((unsigned)st.st_blksize);
988: if (buf == NULL) {
989: warn("malloc");
990: bufsize = 0;
991: goto abort;
992: }
993: bufsize = st.st_blksize;
994: }
1.14 millert 995: if ((st.st_mode & S_IFMT) != S_IFREG) {
1.31 millert 996: if (progress == 1)
997: progress = 0;
1.13 millert 998: preserve = 0;
999: }
1.10 millert 1000: progressmeter(-1);
1.1 deraadt 1001: switch (curtype) {
1002:
1003: case TYPE_I:
1004: case TYPE_L:
1005: if (restart_point &&
1006: lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1007: warn("local: %s", local);
1.13 millert 1008: progress = oprogress;
1.16 millert 1009: preserve = opreserve;
1.1 deraadt 1010: if (closefunc != NULL)
1011: (*closefunc)(fout);
1012: return;
1013: }
1014: errno = d = 0;
1015: while ((c = read(fileno(din), buf, bufsize)) > 0) {
1.32 deraadt 1016: size_t wr;
1017: size_t rd = c;
1018:
1019: d = 0;
1020: do {
1021: wr = write(fileno(fout), buf + d, rd);
1022: if (wr == -1 && errno == EPIPE)
1023: break;
1024: d += wr;
1025: rd -= wr;
1026: } while (d < c);
1027: if (rd != 0)
1.1 deraadt 1028: break;
1029: bytes += c;
1.10 millert 1030: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 1031: while (bytes >= hashbytes) {
1.18 deraadt 1032: (void)putc('#', ttyout);
1.7 kstailey 1033: hashbytes += mark;
1.1 deraadt 1034: }
1.18 deraadt 1035: (void)fflush(ttyout);
1.1 deraadt 1036: }
1037: }
1.10 millert 1038: if (hash && (!progress || filesize < 0) && bytes > 0) {
1.7 kstailey 1039: if (bytes < mark)
1.18 deraadt 1040: (void)putc('#', ttyout);
1041: (void)putc('\n', ttyout);
1042: (void)fflush(ttyout);
1.1 deraadt 1043: }
1044: if (c < 0) {
1045: if (errno != EPIPE)
1046: warn("netin");
1047: bytes = -1;
1048: }
1049: if (d < c) {
1050: if (d < 0)
1051: warn("local: %s", local);
1052: else
1053: warnx("%s: short write", local);
1054: }
1055: break;
1056:
1057: case TYPE_A:
1058: if (restart_point) {
1059: int i, n, ch;
1060:
1061: if (fseek(fout, 0L, SEEK_SET) < 0)
1062: goto done;
1063: n = restart_point;
1064: for (i = 0; i++ < n;) {
1.23 millert 1065: if ((ch = fgetc(fout)) == EOF)
1.1 deraadt 1066: goto done;
1067: if (ch == '\n')
1068: i++;
1069: }
1070: if (fseek(fout, 0L, SEEK_CUR) < 0) {
1071: done:
1072: warn("local: %s", local);
1.13 millert 1073: progress = oprogress;
1.16 millert 1074: preserve = opreserve;
1.1 deraadt 1075: if (closefunc != NULL)
1076: (*closefunc)(fout);
1077: return;
1078: }
1079: }
1.23 millert 1080: while ((c = fgetc(din)) != EOF) {
1.1 deraadt 1081: if (c == '\n')
1082: bare_lfs++;
1083: while (c == '\r') {
1.10 millert 1084: while (hash && (!progress || filesize < 0) &&
1085: (bytes >= hashbytes)) {
1.18 deraadt 1086: (void)putc('#', ttyout);
1087: (void)fflush(ttyout);
1.7 kstailey 1088: hashbytes += mark;
1.1 deraadt 1089: }
1090: bytes++;
1.23 millert 1091: if ((c = fgetc(din)) != '\n' || tcrflag) {
1.1 deraadt 1092: if (ferror(fout))
1093: goto break2;
1.11 millert 1094: (void)putc('\r', fout);
1.1 deraadt 1095: if (c == '\0') {
1096: bytes++;
1097: goto contin2;
1098: }
1099: if (c == EOF)
1100: goto contin2;
1101: }
1102: }
1.11 millert 1103: (void)putc(c, fout);
1.1 deraadt 1104: bytes++;
1105: contin2: ;
1106: }
1107: break2:
1108: if (bare_lfs) {
1.22 millert 1109: fprintf(ttyout,
1.13 millert 1110: "WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
1.22 millert 1111: fputs("File may not have transferred correctly.\n",
1112: ttyout);
1.1 deraadt 1113: }
1.10 millert 1114: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 1115: if (bytes < hashbytes)
1.18 deraadt 1116: (void)putc('#', ttyout);
1117: (void)putc('\n', ttyout);
1118: (void)fflush(ttyout);
1.1 deraadt 1119: }
1120: if (ferror(din)) {
1121: if (errno != EPIPE)
1122: warn("netin");
1123: bytes = -1;
1124: }
1125: if (ferror(fout))
1126: warn("local: %s", local);
1127: break;
1128: }
1.10 millert 1129: progressmeter(1);
1.13 millert 1130: progress = oprogress;
1.16 millert 1131: preserve = opreserve;
1.1 deraadt 1132: if (closefunc != NULL)
1133: (*closefunc)(fout);
1.11 millert 1134: (void)signal(SIGINT, oldintr);
1135: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1136: if (oldintp)
1.11 millert 1137: (void)signal(SIGPIPE, oldintp);
1138: (void)fclose(din);
1139: (void)getreply(0);
1.10 millert 1140: if (bytes >= 0 && is_retr) {
1141: if (bytes > 0)
1142: ptransfer(0);
1143: if (preserve && (closefunc == fclose)) {
1144: mtime = remotemodtime(remote, 0);
1145: if (mtime != -1) {
1.12 millert 1146: struct utimbuf ut;
1147:
1148: ut.actime = time(NULL);
1149: ut.modtime = mtime;
1150: if (utime(local, &ut) == -1)
1.22 millert 1151: fprintf(ttyout,
1.13 millert 1152: "Can't change modification time on %s to %s",
1.11 millert 1153: local, asctime(localtime(&mtime)));
1.10 millert 1154: }
1155: }
1156: }
1.1 deraadt 1157: return;
1.13 millert 1158:
1.1 deraadt 1159: abort:
1160:
1.10 millert 1161: /* abort using RFC959 recommended IP,SYNC sequence */
1.1 deraadt 1162:
1.13 millert 1163: progress = oprogress;
1.16 millert 1164: preserve = opreserve;
1.1 deraadt 1165: if (oldintp)
1.11 millert 1166: (void)signal(SIGPIPE, oldintp);
1167: (void)signal(SIGINT, SIG_IGN);
1.1 deraadt 1168: if (!cpend) {
1169: code = -1;
1.11 millert 1170: (void)signal(SIGINT, oldintr);
1171: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1172: return;
1173: }
1174:
1175: abort_remote(din);
1176: code = -1;
1177: if (data >= 0) {
1.11 millert 1178: (void)close(data);
1.1 deraadt 1179: data = -1;
1180: }
1181: if (closefunc != NULL && fout != NULL)
1182: (*closefunc)(fout);
1183: if (din)
1.11 millert 1184: (void)fclose(din);
1.1 deraadt 1185: if (bytes > 0)
1.10 millert 1186: ptransfer(0);
1.11 millert 1187: (void)signal(SIGINT, oldintr);
1188: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1189: }
1190:
1191: /*
1192: * Need to start a listen on the data channel before we send the command,
1193: * otherwise the server's connect may fail.
1194: */
1195: int
1196: initconn()
1197: {
1198: char *p, *a;
1.37 fgsch 1199: int result = ERROR, len, tmpno = 0;
1.1 deraadt 1200: int on = 1;
1.34 itojun 1201: int error;
1202: u_int addr[16], port[2];
1203: u_int af, hal, pal;
1204: char *pasvcmd = NULL;
1205:
1206: if (myctladdr.su_family == AF_INET6
1207: && (IN6_IS_ADDR_LINKLOCAL(&myctladdr.su_sin6.sin6_addr)
1208: || IN6_IS_ADDR_SITELOCAL(&myctladdr.su_sin6.sin6_addr))) {
1209: warnx("use of scoped address can be troublesome");
1210: }
1.24 millert 1211: reinit:
1.1 deraadt 1212: if (passivemode) {
1.34 itojun 1213: data_addr = myctladdr;
1214: data = socket(data_addr.su_family, SOCK_STREAM, 0);
1.1 deraadt 1215: if (data < 0) {
1.10 millert 1216: warn("socket");
1217: return (1);
1.1 deraadt 1218: }
1219: if ((options & SO_DEBUG) &&
1220: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1.11 millert 1221: sizeof(on)) < 0)
1.10 millert 1222: warn("setsockopt (ignored)");
1.34 itojun 1223: switch (data_addr.su_family) {
1224: case AF_INET:
1.36 itojun 1225: if (epsv4 && !epsv4bad) {
1226: result = command(pasvcmd = "EPSV");
1227: if (code / 10 == 22 && code != 229) {
1228: fputs(
1.34 itojun 1229: "wrong server: return code must be 229\n",
1.36 itojun 1230: ttyout);
1231: result = COMPLETE + 1;
1232: }
1233: if (result != COMPLETE) {
1234: epsv4bad = 1;
1235: if (debug) {
1236: fputs(
1237: "disabling epsv4 for this connection\n",
1238: ttyout);
1239: }
1240: }
1.34 itojun 1241: }
1242: if (result != COMPLETE)
1243: result = command(pasvcmd = "PASV");
1244: break;
1245: case AF_INET6:
1246: result = command(pasvcmd = "EPSV");
1247: if (code / 10 == 22 && code != 229) {
1248: fputs(
1249: "wrong server: return code must be 229\n",
1250: ttyout);
1251: result = COMPLETE + 1;
1252: }
1253: if (result != COMPLETE)
1254: result = command(pasvcmd = "LPSV");
1255: break;
1256: default:
1257: result = COMPLETE + 1;
1258: break;
1259: }
1260: if (result != COMPLETE) {
1.24 millert 1261: if (activefallback) {
1262: (void)close(data);
1263: data = -1;
1264: passivemode = 0;
1265: activefallback = 0;
1266: goto reinit;
1267: }
1.18 deraadt 1268: fputs("Passive mode refused.\n", ttyout);
1.1 deraadt 1269: goto bad;
1270: }
1271:
1.34 itojun 1272: #define pack2(var, off) \
1273: (((var[(off) + 0] & 0xff) << 8) | ((var[(off) + 1] & 0xff) << 0))
1274: #define pack4(var, off) \
1275: (((var[(off) + 0] & 0xff) << 24) | ((var[(off) + 1] & 0xff) << 16) | \
1276: ((var[(off) + 2] & 0xff) << 8) | ((var[(off) + 3] & 0xff) << 0))
1277:
1.1 deraadt 1278: /*
1.34 itojun 1279: * What we've got at this point is a string of comma separated
1280: * one-byte unsigned integer values, separated by commas.
1.1 deraadt 1281: */
1.38 millert 1282: if (!pasvcmd)
1283: goto bad;
1.34 itojun 1284: if (strcmp(pasvcmd, "PASV") == 0) {
1285: if (data_addr.su_family != AF_INET) {
1286: fputs(
1287: "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1288: error = 1;
1289: goto bad;
1290: }
1291: if (code / 10 == 22 && code != 227) {
1292: fputs("wrong server: return code must be 227\n",
1293: ttyout);
1294: error = 1;
1295: goto bad;
1296: }
1297: error = sscanf(pasv, "%u,%u,%u,%u,%u,%u",
1298: &addr[0], &addr[1], &addr[2], &addr[3],
1299: &port[0], &port[1]);
1300: if (error != 6) {
1301: fputs(
1302: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1303: error = 1;
1304: goto bad;
1305: }
1306: error = 0;
1307: memset(&data_addr, 0, sizeof(data_addr));
1308: data_addr.su_family = AF_INET;
1309: data_addr.su_len = sizeof(struct sockaddr_in);
1310: data_addr.su_sin.sin_addr.s_addr =
1311: htonl(pack4(addr, 0));
1312: data_addr.su_port = htons(pack2(port, 0));
1313: } else if (strcmp(pasvcmd, "LPSV") == 0) {
1314: if (code / 10 == 22 && code != 228) {
1315: fputs("wrong server: return code must be 228\n",
1316: ttyout);
1317: error = 1;
1318: goto bad;
1319: }
1320: switch (data_addr.su_family) {
1321: case AF_INET:
1322: error = sscanf(pasv,
1323: "%u,%u,%u,%u,%u,%u,%u,%u,%u",
1324: &af, &hal,
1325: &addr[0], &addr[1], &addr[2], &addr[3],
1326: &pal, &port[0], &port[1]);
1327: if (error != 9) {
1328: fputs(
1329: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1330: error = 1;
1331: goto bad;
1332: }
1333: if (af != 4 || hal != 4 || pal != 2) {
1334: fputs(
1335: "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1336: error = 1;
1337: goto bad;
1338: }
1.1 deraadt 1339:
1.34 itojun 1340: error = 0;
1341: memset(&data_addr, 0, sizeof(data_addr));
1342: data_addr.su_family = AF_INET;
1343: data_addr.su_len = sizeof(struct sockaddr_in);
1344: data_addr.su_sin.sin_addr.s_addr =
1345: htonl(pack4(addr, 0));
1346: data_addr.su_port = htons(pack2(port, 0));
1347: break;
1348: case AF_INET6:
1349: error = sscanf(pasv,
1350: "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
1351: &af, &hal,
1352: &addr[0], &addr[1], &addr[2], &addr[3],
1353: &addr[4], &addr[5], &addr[6], &addr[7],
1354: &addr[8], &addr[9], &addr[10],
1355: &addr[11], &addr[12], &addr[13],
1356: &addr[14], &addr[15],
1357: &pal, &port[0], &port[1]);
1358: if (error != 21) {
1359: fputs(
1.18 deraadt 1360: "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1.34 itojun 1361: error = 1;
1362: goto bad;
1363: }
1364: if (af != 6 || hal != 16 || pal != 2) {
1365: fputs(
1366: "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1367: error = 1;
1368: goto bad;
1369: }
1370:
1371: error = 0;
1372: memset(&data_addr, 0, sizeof(data_addr));
1373: data_addr.su_family = AF_INET6;
1374: data_addr.su_len = sizeof(struct sockaddr_in6);
1375: {
1376: u_int32_t *p32;
1377: p32 = (u_int32_t *)&data_addr.su_sin6.sin6_addr;
1378: p32[0] = htonl(pack4(addr, 0));
1379: p32[1] = htonl(pack4(addr, 4));
1380: p32[2] = htonl(pack4(addr, 8));
1381: p32[3] = htonl(pack4(addr, 12));
1382: }
1383: data_addr.su_port = htons(pack2(port, 0));
1384: break;
1385: default:
1386: error = 1;
1387: }
1388: } else if (strcmp(pasvcmd, "EPSV") == 0) {
1389: char delim[4];
1390:
1391: port[0] = 0;
1392: if (code / 10 == 22 && code != 229) {
1393: fputs("wrong server: return code must be 229\n",
1394: ttyout);
1395: error = 1;
1396: goto bad;
1397: }
1398: if (sscanf(pasv, "%c%c%c%d%c", &delim[0],
1399: &delim[1], &delim[2], &port[1],
1400: &delim[3]) != 5) {
1401: fputs("parse error!\n", ttyout);
1402: error = 1;
1403: goto bad;
1404: }
1405: if (delim[0] != delim[1] || delim[0] != delim[2]
1406: || delim[0] != delim[3]) {
1407: fputs("parse error!\n", ttyout);
1408: error = 1;
1409: goto bad;
1410: }
1411: data_addr = hisctladdr;
1412: data_addr.su_port = htons(port[1]);
1413: } else
1.1 deraadt 1414: goto bad;
1415:
1.27 deraadt 1416: while (connect(data, (struct sockaddr *)&data_addr,
1.34 itojun 1417: data_addr.su_len) < 0) {
1.27 deraadt 1418: if (errno == EINTR)
1419: continue;
1.33 millert 1420: if (activefallback) {
1421: (void)close(data);
1422: data = -1;
1423: passivemode = 0;
1424: activefallback = 0;
1425: goto reinit;
1426: }
1.10 millert 1427: warn("connect");
1.1 deraadt 1428: goto bad;
1429: }
1.34 itojun 1430: #if defined(IPPROTO_IP) && defined(IP_TOS)
1431: if (data_addr.su_family == AF_INET) {
1432: on = IPTOS_THROUGHPUT;
1433: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1434: sizeof(int)) < 0)
1435: warn("setsockopt TOS (ignored)");
1436: }
1.1 deraadt 1437: #endif
1.10 millert 1438: return (0);
1.1 deraadt 1439: }
1440:
1441: noport:
1442: data_addr = myctladdr;
1443: if (sendport)
1.34 itojun 1444: data_addr.su_port = 0; /* let system pick one */
1.1 deraadt 1445: if (data != -1)
1.11 millert 1446: (void)close(data);
1.34 itojun 1447: data = socket(data_addr.su_family, SOCK_STREAM, 0);
1.1 deraadt 1448: if (data < 0) {
1449: warn("socket");
1450: if (tmpno)
1451: sendport = 1;
1452: return (1);
1453: }
1454: if (!sendport)
1.10 millert 1455: if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1.11 millert 1456: sizeof(on)) < 0) {
1.1 deraadt 1457: warn("setsockopt (reuse address)");
1458: goto bad;
1459: }
1.34 itojun 1460: if (bind(data, (struct sockaddr *)&data_addr, data_addr.su_len) < 0) {
1.1 deraadt 1461: warn("bind");
1462: goto bad;
1463: }
1464: if (options & SO_DEBUG &&
1.10 millert 1465: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1.11 millert 1466: sizeof(on)) < 0)
1.1 deraadt 1467: warn("setsockopt (ignored)");
1.11 millert 1468: len = sizeof(data_addr);
1.1 deraadt 1469: if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1470: warn("getsockname");
1471: goto bad;
1472: }
1473: if (listen(data, 1) < 0)
1474: warn("listen");
1.34 itojun 1475:
1476: #define UC(b) (((int)b)&0xff)
1477:
1.1 deraadt 1478: if (sendport) {
1.34 itojun 1479: char hname[INET6_ADDRSTRLEN];
1480: int af;
1481:
1482: switch (data_addr.su_family) {
1483: case AF_INET:
1.36 itojun 1484: if (!epsv4 || epsv4bad) {
1485: result = COMPLETE +1;
1486: break;
1487: }
1488: /*FALLTHROUGH*/
1.34 itojun 1489: case AF_INET6:
1490: af = (data_addr.su_family == AF_INET) ? 1 : 2;
1491: if (getnameinfo((struct sockaddr *)&data_addr,
1492: data_addr.su_len, hname, sizeof(hname),
1493: NULL, 0, NI_NUMERICHOST)) {
1494: result = ERROR;
1495: } else {
1496: result = command("EPRT |%d|%s|%d|",
1497: af, hname, ntohs(data_addr.su_port));
1.36 itojun 1498: if (result != COMPLETE) {
1499: epsv4bad = 1;
1500: if (debug) {
1501: fputs(
1502: "disabling epsv4 for this connection\n",
1503: ttyout);
1504: }
1505: }
1.34 itojun 1506: }
1507: break;
1508: default:
1509: result = COMPLETE + 1;
1510: break;
1511: }
1512: if (result == COMPLETE)
1513: goto skip_port;
1514:
1515: switch (data_addr.su_family) {
1516: case AF_INET:
1517: a = (char *)&data_addr.su_sin.sin_addr;
1518: p = (char *)&data_addr.su_port;
1519: result = command("PORT %d,%d,%d,%d,%d,%d",
1520: UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1521: UC(p[0]), UC(p[1]));
1522: break;
1523: case AF_INET6:
1524: a = (char *)&data_addr.su_sin6.sin6_addr;
1525: p = (char *)&data_addr.su_port;
1526: result = command(
1527: "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1528: 6, 16,
1529: UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
1530: UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
1531: UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
1532: UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
1533: 2, UC(p[0]), UC(p[1]));
1534: break;
1535: default:
1536: result = COMPLETE + 1; /* xxx */
1537: }
1538: skip_port:
1539:
1.1 deraadt 1540: if (result == ERROR && sendport == -1) {
1541: sendport = 0;
1542: tmpno = 1;
1543: goto noport;
1544: }
1545: return (result != COMPLETE);
1546: }
1547: if (tmpno)
1548: sendport = 1;
1.34 itojun 1549: #if defined(IPPROTO_IP) && defined(IP_TOS)
1550: if (data_addr.su_family == AF_INET) {
1551: on = IPTOS_THROUGHPUT;
1552: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1553: sizeof(int)) < 0)
1554: warn("setsockopt TOS (ignored)");
1555: }
1.1 deraadt 1556: #endif
1557: return (0);
1558: bad:
1.11 millert 1559: (void)close(data), data = -1;
1.1 deraadt 1560: if (tmpno)
1561: sendport = 1;
1562: return (1);
1563: }
1564:
1565: FILE *
1566: dataconn(lmode)
1.10 millert 1567: const char *lmode;
1.1 deraadt 1568: {
1.34 itojun 1569: union sockunion from;
1570: int s, fromlen = myctladdr.su_len;
1.1 deraadt 1571:
1572: if (passivemode)
1573: return (fdopen(data, lmode));
1574:
1575: s = accept(data, (struct sockaddr *) &from, &fromlen);
1576: if (s < 0) {
1577: warn("accept");
1.11 millert 1578: (void)close(data), data = -1;
1.1 deraadt 1579: return (NULL);
1580: }
1.11 millert 1581: (void)close(data);
1.1 deraadt 1582: data = s;
1.34 itojun 1583: #if defined(IPPROTO_IP) && defined(IP_TOS)
1584: if (from.su_family == AF_INET) {
1585: int tos = IPTOS_THROUGHPUT;
1586: if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1587: sizeof(int)) < 0) {
1588: warn("setsockopt TOS (ignored)");
1589: }
1590: }
1.1 deraadt 1591: #endif
1592: return (fdopen(data, lmode));
1593: }
1594:
1595: void
1.10 millert 1596: psummary(notused)
1597: int notused;
1.1 deraadt 1598: {
1.26 deraadt 1599: int save_errno = errno;
1.10 millert 1600:
1601: if (bytes > 0)
1602: ptransfer(1);
1.26 deraadt 1603: errno = save_errno;
1.1 deraadt 1604: }
1605:
1606: void
1.12 millert 1607: psabort(notused)
1608: int notused;
1.1 deraadt 1609: {
1610:
1.10 millert 1611: alarmtimer(0);
1.1 deraadt 1612: abrtflag++;
1613: }
1614:
1615: void
1616: pswitch(flag)
1617: int flag;
1618: {
1619: sig_t oldintr;
1620: static struct comvars {
1621: int connect;
1622: char name[MAXHOSTNAMELEN];
1.34 itojun 1623: union sockunion mctl;
1624: union sockunion hctl;
1.1 deraadt 1625: FILE *in;
1626: FILE *out;
1627: int tpe;
1628: int curtpe;
1629: int cpnd;
1630: int sunqe;
1631: int runqe;
1632: int mcse;
1633: int ntflg;
1634: char nti[17];
1635: char nto[17];
1636: int mapflg;
1637: char mi[MAXPATHLEN];
1638: char mo[MAXPATHLEN];
1639: } proxstruct, tmpstruct;
1640: struct comvars *ip, *op;
1641:
1642: abrtflag = 0;
1643: oldintr = signal(SIGINT, psabort);
1644: if (flag) {
1645: if (proxy)
1646: return;
1647: ip = &tmpstruct;
1648: op = &proxstruct;
1649: proxy++;
1650: } else {
1651: if (!proxy)
1652: return;
1653: ip = &proxstruct;
1654: op = &tmpstruct;
1655: proxy = 0;
1656: }
1657: ip->connect = connected;
1658: connected = op->connect;
1659: if (hostname) {
1.11 millert 1660: (void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1661: ip->name[sizeof(ip->name) - 1] = '\0';
1.1 deraadt 1662: } else
1.11 millert 1663: ip->name[0] = '\0';
1.1 deraadt 1664: hostname = op->name;
1665: ip->hctl = hisctladdr;
1666: hisctladdr = op->hctl;
1667: ip->mctl = myctladdr;
1668: myctladdr = op->mctl;
1669: ip->in = cin;
1670: cin = op->in;
1671: ip->out = cout;
1672: cout = op->out;
1673: ip->tpe = type;
1674: type = op->tpe;
1675: ip->curtpe = curtype;
1676: curtype = op->curtpe;
1677: ip->cpnd = cpend;
1678: cpend = op->cpnd;
1679: ip->sunqe = sunique;
1680: sunique = op->sunqe;
1681: ip->runqe = runique;
1682: runique = op->runqe;
1683: ip->mcse = mcase;
1684: mcase = op->mcse;
1685: ip->ntflg = ntflag;
1686: ntflag = op->ntflg;
1.11 millert 1687: (void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1688: (ip->nti)[sizeof(ip->nti) - 1] = '\0';
1689: (void)strcpy(ntin, op->nti);
1690: (void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1691: (ip->nto)[sizeof(ip->nto) - 1] = '\0';
1692: (void)strcpy(ntout, op->nto);
1.1 deraadt 1693: ip->mapflg = mapflag;
1694: mapflag = op->mapflg;
1.11 millert 1695: (void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1696: (ip->mi)[sizeof(ip->mi) - 1] = '\0';
1697: (void)strcpy(mapin, op->mi);
1698: (void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1699: (ip->mo)[sizeof(ip->mo) - 1] = '\0';
1700: (void)strcpy(mapout, op->mo);
1701: (void)signal(SIGINT, oldintr);
1.1 deraadt 1702: if (abrtflag) {
1703: abrtflag = 0;
1704: (*oldintr)(SIGINT);
1705: }
1706: }
1707:
1708: void
1.12 millert 1709: abortpt(notused)
1710: int notused;
1.1 deraadt 1711: {
1712:
1.10 millert 1713: alarmtimer(0);
1.18 deraadt 1714: putc('\n', ttyout);
1715: (void)fflush(ttyout);
1.1 deraadt 1716: ptabflg++;
1717: mflag = 0;
1718: abrtflag = 0;
1719: longjmp(ptabort, 1);
1720: }
1721:
1722: void
1723: proxtrans(cmd, local, remote)
1.10 millert 1724: const char *cmd, *local, *remote;
1.1 deraadt 1725: {
1726: sig_t oldintr;
1.20 millert 1727: int prox_type, nfnd;
1728: volatile int secndflag;
1.1 deraadt 1729: char *cmd2;
1.29 art 1730: fd_set mask;
1.1 deraadt 1731:
1.20 millert 1732: #ifdef __GNUC__ /* XXX: to shut up gcc warnings */
1733: (void)&oldintr;
1734: (void)&cmd2;
1735: #endif
1736:
1737: oldintr = NULL;
1738: secndflag = 0;
1.1 deraadt 1739: if (strcmp(cmd, "RETR"))
1740: cmd2 = "RETR";
1741: else
1742: cmd2 = runique ? "STOU" : "STOR";
1743: if ((prox_type = type) == 0) {
1744: if (unix_server && unix_proxy)
1745: prox_type = TYPE_I;
1746: else
1747: prox_type = TYPE_A;
1748: }
1749: if (curtype != prox_type)
1750: changetype(prox_type, 1);
1751: if (command("PASV") != COMPLETE) {
1.18 deraadt 1752: fputs("proxy server does not support third party transfers.\n",
1753: ttyout);
1.1 deraadt 1754: return;
1755: }
1756: pswitch(0);
1757: if (!connected) {
1.18 deraadt 1758: fputs("No primary connection.\n", ttyout);
1.1 deraadt 1759: pswitch(1);
1760: code = -1;
1761: return;
1762: }
1763: if (curtype != prox_type)
1764: changetype(prox_type, 1);
1765: if (command("PORT %s", pasv) != COMPLETE) {
1766: pswitch(1);
1767: return;
1768: }
1769: if (setjmp(ptabort))
1770: goto abort;
1771: oldintr = signal(SIGINT, abortpt);
1772: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 1773: (void)signal(SIGINT, oldintr);
1.1 deraadt 1774: pswitch(1);
1775: return;
1776: }
1777: sleep(2);
1778: pswitch(1);
1779: secndflag++;
1780: if (command("%s %s", cmd2, local) != PRELIM)
1781: goto abort;
1782: ptflag++;
1.11 millert 1783: (void)getreply(0);
1.1 deraadt 1784: pswitch(0);
1.11 millert 1785: (void)getreply(0);
1786: (void)signal(SIGINT, oldintr);
1.1 deraadt 1787: pswitch(1);
1788: ptflag = 0;
1.18 deraadt 1789: fprintf(ttyout, "local: %s remote: %s\n", local, remote);
1.1 deraadt 1790: return;
1791: abort:
1.11 millert 1792: (void)signal(SIGINT, SIG_IGN);
1.1 deraadt 1793: ptflag = 0;
1794: if (strcmp(cmd, "RETR") && !proxy)
1795: pswitch(1);
1796: else if (!strcmp(cmd, "RETR") && proxy)
1797: pswitch(0);
1798: if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1799: if (command("%s %s", cmd2, local) != PRELIM) {
1800: pswitch(0);
1801: if (cpend)
1.19 kstailey 1802: abort_remote(NULL);
1.1 deraadt 1803: }
1804: pswitch(1);
1805: if (ptabflg)
1806: code = -1;
1.11 millert 1807: (void)signal(SIGINT, oldintr);
1.1 deraadt 1808: return;
1809: }
1810: if (cpend)
1.19 kstailey 1811: abort_remote(NULL);
1.1 deraadt 1812: pswitch(!proxy);
1813: if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1814: if (command("%s %s", cmd2, local) != PRELIM) {
1815: pswitch(0);
1816: if (cpend)
1.19 kstailey 1817: abort_remote(NULL);
1.1 deraadt 1818: pswitch(1);
1819: if (ptabflg)
1820: code = -1;
1.11 millert 1821: (void)signal(SIGINT, oldintr);
1.1 deraadt 1822: return;
1823: }
1824: }
1825: if (cpend)
1.19 kstailey 1826: abort_remote(NULL);
1.1 deraadt 1827: pswitch(!proxy);
1828: if (cpend) {
1829: FD_ZERO(&mask);
1830: FD_SET(fileno(cin), &mask);
1831: if ((nfnd = empty(&mask, 10)) <= 0) {
1832: if (nfnd < 0) {
1833: warn("abort");
1834: }
1835: if (ptabflg)
1836: code = -1;
1837: lostpeer();
1838: }
1.11 millert 1839: (void)getreply(0);
1840: (void)getreply(0);
1.1 deraadt 1841: }
1842: if (proxy)
1843: pswitch(0);
1844: pswitch(1);
1845: if (ptabflg)
1846: code = -1;
1.11 millert 1847: (void)signal(SIGINT, oldintr);
1.1 deraadt 1848: }
1849:
1850: void
1851: reset(argc, argv)
1852: int argc;
1853: char *argv[];
1854: {
1.29 art 1855: fd_set mask;
1.1 deraadt 1856: int nfnd = 1;
1857:
1858: FD_ZERO(&mask);
1859: while (nfnd > 0) {
1860: FD_SET(fileno(cin), &mask);
1.10 millert 1861: if ((nfnd = empty(&mask, 0)) < 0) {
1.1 deraadt 1862: warn("reset");
1863: code = -1;
1864: lostpeer();
1865: }
1866: else if (nfnd) {
1.11 millert 1867: (void)getreply(0);
1.1 deraadt 1868: }
1869: }
1870: }
1871:
1872: char *
1873: gunique(local)
1.10 millert 1874: const char *local;
1.1 deraadt 1875: {
1876: static char new[MAXPATHLEN];
1877: char *cp = strrchr(local, '/');
1878: int d, count=0;
1879: char ext = '1';
1880:
1881: if (cp)
1882: *cp = '\0';
1.22 millert 1883: d = access(cp == local ? "/" : cp ? local : ".", W_OK);
1.1 deraadt 1884: if (cp)
1885: *cp = '/';
1886: if (d < 0) {
1887: warn("local: %s", local);
1888: return ((char *) 0);
1889: }
1.11 millert 1890: (void)strcpy(new, local);
1.1 deraadt 1891: cp = new + strlen(new);
1892: *cp++ = '.';
1893: while (!d) {
1894: if (++count == 100) {
1.18 deraadt 1895: fputs("runique: can't find unique file name.\n", ttyout);
1.1 deraadt 1896: return ((char *) 0);
1897: }
1898: *cp++ = ext;
1899: *cp = '\0';
1900: if (ext == '9')
1901: ext = '0';
1902: else
1903: ext++;
1.22 millert 1904: if ((d = access(new, F_OK)) < 0)
1.1 deraadt 1905: break;
1906: if (ext != '0')
1907: cp--;
1908: else if (*(cp - 2) == '.')
1909: *(cp - 1) = '1';
1910: else {
1911: *(cp - 2) = *(cp - 2) + 1;
1912: cp--;
1913: }
1914: }
1915: return (new);
1916: }
1917:
1918: void
1919: abort_remote(din)
1920: FILE *din;
1921: {
1922: char buf[BUFSIZ];
1923: int nfnd;
1.29 art 1924: fd_set mask;
1.13 millert 1925:
1926: if (cout == NULL) {
1927: warnx("Lost control connection for abort.");
1928: if (ptabflg)
1929: code = -1;
1930: lostpeer();
1931: return;
1932: }
1.1 deraadt 1933:
1934: /*
1935: * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1936: * after urgent byte rather than before as is protocol now
1937: */
1938: sprintf(buf, "%c%c%c", IAC, IP, IAC);
1939: if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1940: warn("abort");
1.10 millert 1941: fprintf(cout, "%cABOR\r\n", DM);
1.11 millert 1942: (void)fflush(cout);
1.1 deraadt 1943: FD_ZERO(&mask);
1944: FD_SET(fileno(cin), &mask);
1.10 millert 1945: if (din) {
1.1 deraadt 1946: FD_SET(fileno(din), &mask);
1947: }
1948: if ((nfnd = empty(&mask, 10)) <= 0) {
1949: if (nfnd < 0) {
1950: warn("abort");
1951: }
1952: if (ptabflg)
1953: code = -1;
1954: lostpeer();
1955: }
1956: if (din && FD_ISSET(fileno(din), &mask)) {
1957: while (read(fileno(din), buf, BUFSIZ) > 0)
1958: /* LOOP */;
1959: }
1960: if (getreply(0) == ERROR && code == 552) {
1961: /* 552 needed for nic style abort */
1.11 millert 1962: (void)getreply(0);
1.1 deraadt 1963: }
1.11 millert 1964: (void)getreply(0);
1.1 deraadt 1965: }