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