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