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