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