Annotation of src/usr.bin/ftp/ftp.c, Revision 1.15
1.15 ! millert 1: /* $OpenBSD: ftp.c,v 1.14 1997/03/14 05:40:20 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.15 ! millert 41: static char rcsid[] = "$OpenBSD: ftp.c,v 1.14 1997/03/14 05:40:20 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.15 ! millert 846: progress = oprogress;
1.1 deraadt 847: code = -1;
848: return;
849: }
850: oldintr = signal(SIGINT, abortrecv);
1.10 millert 851: oldinti = signal(SIGINFO, psummary);
1.1 deraadt 852: if (strcmp(local, "-") && *local != '|') {
853: if (access(local, 2) < 0) {
854: char *dir = strrchr(local, '/');
855:
856: if (errno != ENOENT && errno != EACCES) {
857: warn("local: %s", local);
1.11 millert 858: (void)signal(SIGINT, oldintr);
859: (void)signal(SIGINFO, oldinti);
1.1 deraadt 860: code = -1;
861: return;
862: }
863: if (dir != NULL)
864: *dir = 0;
1.10 millert 865: d = access(dir == local ? "/" : dir ? local : ".", 2);
1.1 deraadt 866: if (dir != NULL)
867: *dir = '/';
868: if (d < 0) {
869: warn("local: %s", local);
1.11 millert 870: (void)signal(SIGINT, oldintr);
871: (void)signal(SIGINFO, oldinti);
1.1 deraadt 872: code = -1;
873: return;
874: }
875: if (!runique && errno == EACCES &&
876: chmod(local, 0600) < 0) {
877: warn("local: %s", local);
1.11 millert 878: (void)signal(SIGINT, oldintr);
879: (void)signal(SIGINFO, oldinti);
1.1 deraadt 880: code = -1;
881: return;
882: }
883: if (runique && errno == EACCES &&
884: (local = gunique(local)) == NULL) {
1.11 millert 885: (void)signal(SIGINT, oldintr);
886: (void)signal(SIGINFO, oldinti);
1.1 deraadt 887: code = -1;
888: return;
889: }
890: }
891: else if (runique && (local = gunique(local)) == NULL) {
1.11 millert 892: (void)signal(SIGINT, oldintr);
893: (void)signal(SIGINFO, oldinti);
1.1 deraadt 894: code = -1;
895: return;
896: }
897: }
898: if (!is_retr) {
899: if (curtype != TYPE_A)
900: changetype(TYPE_A, 0);
1.10 millert 901: } else {
902: if (curtype != type)
903: changetype(type, 0);
904: filesize = remotesize(remote, 0);
905: }
1.1 deraadt 906: if (initconn()) {
1.11 millert 907: (void)signal(SIGINT, oldintr);
908: (void)signal(SIGINFO, oldinti);
1.1 deraadt 909: code = -1;
910: return;
911: }
912: if (setjmp(recvabort))
913: goto abort;
914: if (is_retr && restart_point &&
915: command("REST %ld", (long) restart_point) != CONTINUE)
916: return;
917: if (remote) {
918: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 919: (void)signal(SIGINT, oldintr);
920: (void)signal(SIGINFO, oldinti);
1.1 deraadt 921: return;
922: }
923: } else {
924: if (command("%s", cmd) != PRELIM) {
1.11 millert 925: (void)signal(SIGINT, oldintr);
926: (void)signal(SIGINFO, oldinti);
1.1 deraadt 927: return;
928: }
929: }
930: din = dataconn("r");
931: if (din == NULL)
932: goto abort;
1.13 millert 933: if (strcmp(local, "-") == 0) {
1.1 deraadt 934: fout = stdout;
1.13 millert 935: progress = 0;
936: } else if (*local == '|') {
1.1 deraadt 937: oldintp = signal(SIGPIPE, SIG_IGN);
938: fout = popen(local + 1, "w");
939: if (fout == NULL) {
940: warn("%s", local+1);
941: goto abort;
942: }
1.13 millert 943: progress = 0;
1.1 deraadt 944: closefunc = pclose;
945: } else {
946: fout = fopen(local, lmode);
947: if (fout == NULL) {
948: warn("local: %s", local);
949: goto abort;
950: }
951: closefunc = fclose;
952: }
953: if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
954: st.st_blksize = BUFSIZ;
955: if (st.st_blksize > bufsize) {
956: if (buf)
1.11 millert 957: (void)free(buf);
1.1 deraadt 958: buf = malloc((unsigned)st.st_blksize);
959: if (buf == NULL) {
960: warn("malloc");
961: bufsize = 0;
962: goto abort;
963: }
964: bufsize = st.st_blksize;
965: }
1.14 millert 966: if ((st.st_mode & S_IFMT) != S_IFREG) {
1.13 millert 967: progress = 0;
968: preserve = 0;
969: }
1.10 millert 970: progressmeter(-1);
1.1 deraadt 971: switch (curtype) {
972:
973: case TYPE_I:
974: case TYPE_L:
975: if (restart_point &&
976: lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
977: warn("local: %s", local);
1.13 millert 978: progress = oprogress;
1.1 deraadt 979: if (closefunc != NULL)
980: (*closefunc)(fout);
981: return;
982: }
983: errno = d = 0;
984: while ((c = read(fileno(din), buf, bufsize)) > 0) {
985: if ((d = write(fileno(fout), buf, c)) != c)
986: break;
987: bytes += c;
1.10 millert 988: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 989: while (bytes >= hashbytes) {
1.11 millert 990: (void)putchar('#');
1.7 kstailey 991: hashbytes += mark;
1.1 deraadt 992: }
1.11 millert 993: (void)fflush(stdout);
1.1 deraadt 994: }
995: }
1.10 millert 996: if (hash && (!progress || filesize < 0) && bytes > 0) {
1.7 kstailey 997: if (bytes < mark)
1.11 millert 998: (void)putchar('#');
999: (void)putchar('\n');
1000: (void)fflush(stdout);
1.1 deraadt 1001: }
1002: if (c < 0) {
1003: if (errno != EPIPE)
1004: warn("netin");
1005: bytes = -1;
1006: }
1007: if (d < c) {
1008: if (d < 0)
1009: warn("local: %s", local);
1010: else
1011: warnx("%s: short write", local);
1012: }
1013: break;
1014:
1015: case TYPE_A:
1016: if (restart_point) {
1017: int i, n, ch;
1018:
1019: if (fseek(fout, 0L, SEEK_SET) < 0)
1020: goto done;
1021: n = restart_point;
1022: for (i = 0; i++ < n;) {
1023: if ((ch = getc(fout)) == EOF)
1024: goto done;
1025: if (ch == '\n')
1026: i++;
1027: }
1028: if (fseek(fout, 0L, SEEK_CUR) < 0) {
1029: done:
1030: warn("local: %s", local);
1.13 millert 1031: progress = oprogress;
1.1 deraadt 1032: if (closefunc != NULL)
1033: (*closefunc)(fout);
1034: return;
1035: }
1036: }
1037: while ((c = getc(din)) != EOF) {
1038: if (c == '\n')
1039: bare_lfs++;
1040: while (c == '\r') {
1.10 millert 1041: while (hash && (!progress || filesize < 0) &&
1042: (bytes >= hashbytes)) {
1.11 millert 1043: (void)putchar('#');
1044: (void)fflush(stdout);
1.7 kstailey 1045: hashbytes += mark;
1.1 deraadt 1046: }
1047: bytes++;
1048: if ((c = getc(din)) != '\n' || tcrflag) {
1049: if (ferror(fout))
1050: goto break2;
1.11 millert 1051: (void)putc('\r', fout);
1.1 deraadt 1052: if (c == '\0') {
1053: bytes++;
1054: goto contin2;
1055: }
1056: if (c == EOF)
1057: goto contin2;
1058: }
1059: }
1.11 millert 1060: (void)putc(c, fout);
1.1 deraadt 1061: bytes++;
1062: contin2: ;
1063: }
1064: break2:
1065: if (bare_lfs) {
1.13 millert 1066: printf(
1067: "WARNING! %d bare linefeeds received in ASCII mode.\n", bare_lfs);
1.11 millert 1068: puts("File may not have transferred correctly.");
1.1 deraadt 1069: }
1.10 millert 1070: if (hash && (!progress || filesize < 0)) {
1.1 deraadt 1071: if (bytes < hashbytes)
1.11 millert 1072: (void)putchar('#');
1073: (void)putchar('\n');
1074: (void)fflush(stdout);
1.1 deraadt 1075: }
1076: if (ferror(din)) {
1077: if (errno != EPIPE)
1078: warn("netin");
1079: bytes = -1;
1080: }
1081: if (ferror(fout))
1082: warn("local: %s", local);
1083: break;
1084: }
1.10 millert 1085: progressmeter(1);
1.13 millert 1086: progress = oprogress;
1.1 deraadt 1087: if (closefunc != NULL)
1088: (*closefunc)(fout);
1.11 millert 1089: (void)signal(SIGINT, oldintr);
1090: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1091: if (oldintp)
1.11 millert 1092: (void)signal(SIGPIPE, oldintp);
1093: (void)fclose(din);
1094: (void)getreply(0);
1.10 millert 1095: if (bytes >= 0 && is_retr) {
1096: if (bytes > 0)
1097: ptransfer(0);
1098: if (preserve && (closefunc == fclose)) {
1099: mtime = remotemodtime(remote, 0);
1100: if (mtime != -1) {
1.12 millert 1101: struct utimbuf ut;
1102:
1103: ut.actime = time(NULL);
1104: ut.modtime = mtime;
1105: if (utime(local, &ut) == -1)
1.13 millert 1106: printf(
1107: "Can't change modification time on %s to %s",
1.11 millert 1108: local, asctime(localtime(&mtime)));
1.10 millert 1109: }
1110: }
1111: }
1.1 deraadt 1112: return;
1.13 millert 1113:
1.1 deraadt 1114: abort:
1115:
1.10 millert 1116: /* abort using RFC959 recommended IP,SYNC sequence */
1.1 deraadt 1117:
1.13 millert 1118: progress = oprogress;
1.1 deraadt 1119: if (oldintp)
1.11 millert 1120: (void)signal(SIGPIPE, oldintp);
1121: (void)signal(SIGINT, SIG_IGN);
1.1 deraadt 1122: if (!cpend) {
1123: code = -1;
1.11 millert 1124: (void)signal(SIGINT, oldintr);
1125: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1126: return;
1127: }
1128:
1129: abort_remote(din);
1130: code = -1;
1131: if (data >= 0) {
1.11 millert 1132: (void)close(data);
1.1 deraadt 1133: data = -1;
1134: }
1135: if (closefunc != NULL && fout != NULL)
1136: (*closefunc)(fout);
1137: if (din)
1.11 millert 1138: (void)fclose(din);
1.1 deraadt 1139: if (bytes > 0)
1.10 millert 1140: ptransfer(0);
1.11 millert 1141: (void)signal(SIGINT, oldintr);
1142: (void)signal(SIGINFO, oldinti);
1.1 deraadt 1143: }
1144:
1145: /*
1146: * Need to start a listen on the data channel before we send the command,
1147: * otherwise the server's connect may fail.
1148: */
1149: int
1150: initconn()
1151: {
1152: char *p, *a;
1153: int result, len, tmpno = 0;
1154: int on = 1;
1155: int a0, a1, a2, a3, p0, p1;
1156:
1157: if (passivemode) {
1158: data = socket(AF_INET, SOCK_STREAM, 0);
1159: if (data < 0) {
1.10 millert 1160: warn("socket");
1161: return (1);
1.1 deraadt 1162: }
1163: if ((options & SO_DEBUG) &&
1164: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1.11 millert 1165: sizeof(on)) < 0)
1.10 millert 1166: warn("setsockopt (ignored)");
1.1 deraadt 1167: if (command("PASV") != COMPLETE) {
1.11 millert 1168: puts("Passive mode refused.");
1.1 deraadt 1169: goto bad;
1170: }
1171:
1172: /*
1173: * What we've got at this point is a string of comma
1174: * separated one-byte unsigned integer values.
1175: * The first four are the an IP address. The fifth is
1176: * the MSB of the port number, the sixth is the LSB.
1177: * From that we'll prepare a sockaddr_in.
1178: */
1179:
1.10 millert 1180: if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
1.1 deraadt 1181: &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
1.13 millert 1182: puts(
1183: "Passive mode address scan failure. Shouldn't happen!");
1.1 deraadt 1184: goto bad;
1185: }
1186:
1.10 millert 1187: memset(&data_addr, 0, sizeof(data_addr));
1.1 deraadt 1188: data_addr.sin_family = AF_INET;
1189: a = (char *)&data_addr.sin_addr.s_addr;
1190: a[0] = a0 & 0xff;
1191: a[1] = a1 & 0xff;
1192: a[2] = a2 & 0xff;
1193: a[3] = a3 & 0xff;
1194: p = (char *)&data_addr.sin_port;
1195: p[0] = p0 & 0xff;
1196: p[1] = p1 & 0xff;
1197:
1198: if (connect(data, (struct sockaddr *)&data_addr,
1199: sizeof(data_addr)) < 0) {
1.10 millert 1200: warn("connect");
1.1 deraadt 1201: goto bad;
1202: }
1203: #ifdef IP_TOS
1204: on = IPTOS_THROUGHPUT;
1205: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1206: sizeof(int)) < 0)
1.10 millert 1207: warn("setsockopt TOS (ignored)");
1.1 deraadt 1208: #endif
1.10 millert 1209: return (0);
1.1 deraadt 1210: }
1211:
1212: noport:
1213: data_addr = myctladdr;
1214: if (sendport)
1.10 millert 1215: data_addr.sin_port = 0; /* let system pick one */
1.1 deraadt 1216: if (data != -1)
1.11 millert 1217: (void)close(data);
1.1 deraadt 1218: data = socket(AF_INET, SOCK_STREAM, 0);
1219: if (data < 0) {
1220: warn("socket");
1221: if (tmpno)
1222: sendport = 1;
1223: return (1);
1224: }
1225: if (!sendport)
1.10 millert 1226: if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1.11 millert 1227: sizeof(on)) < 0) {
1.1 deraadt 1228: warn("setsockopt (reuse address)");
1229: goto bad;
1230: }
1.11 millert 1231: if (bind(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0) {
1.1 deraadt 1232: warn("bind");
1233: goto bad;
1234: }
1235: if (options & SO_DEBUG &&
1.10 millert 1236: setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1.11 millert 1237: sizeof(on)) < 0)
1.1 deraadt 1238: warn("setsockopt (ignored)");
1.11 millert 1239: len = sizeof(data_addr);
1.1 deraadt 1240: if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1241: warn("getsockname");
1242: goto bad;
1243: }
1244: if (listen(data, 1) < 0)
1245: warn("listen");
1246: if (sendport) {
1247: a = (char *)&data_addr.sin_addr;
1248: p = (char *)&data_addr.sin_port;
1249: #define UC(b) (((int)b)&0xff)
1250: result =
1251: command("PORT %d,%d,%d,%d,%d,%d",
1252: UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1253: UC(p[0]), UC(p[1]));
1254: if (result == ERROR && sendport == -1) {
1255: sendport = 0;
1256: tmpno = 1;
1257: goto noport;
1258: }
1259: return (result != COMPLETE);
1260: }
1261: if (tmpno)
1262: sendport = 1;
1263: #ifdef IP_TOS
1264: on = IPTOS_THROUGHPUT;
1265: if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
1266: warn("setsockopt TOS (ignored)");
1267: #endif
1268: return (0);
1269: bad:
1.11 millert 1270: (void)close(data), data = -1;
1.1 deraadt 1271: if (tmpno)
1272: sendport = 1;
1273: return (1);
1274: }
1275:
1276: FILE *
1277: dataconn(lmode)
1.10 millert 1278: const char *lmode;
1.1 deraadt 1279: {
1280: struct sockaddr_in from;
1.13 millert 1281: int s, fromlen, tos;
1282:
1283: fromlen = sizeof(from);
1.1 deraadt 1284:
1285: if (passivemode)
1286: return (fdopen(data, lmode));
1287:
1288: s = accept(data, (struct sockaddr *) &from, &fromlen);
1289: if (s < 0) {
1290: warn("accept");
1.11 millert 1291: (void)close(data), data = -1;
1.1 deraadt 1292: return (NULL);
1293: }
1.11 millert 1294: (void)close(data);
1.1 deraadt 1295: data = s;
1296: #ifdef IP_TOS
1297: tos = IPTOS_THROUGHPUT;
1298: if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
1299: warn("setsockopt TOS (ignored)");
1300: #endif
1301: return (fdopen(data, lmode));
1302: }
1303:
1304: void
1.10 millert 1305: psummary(notused)
1306: int notused;
1.1 deraadt 1307: {
1.10 millert 1308:
1309: if (bytes > 0)
1310: ptransfer(1);
1.1 deraadt 1311: }
1312:
1313: void
1.12 millert 1314: psabort(notused)
1315: int notused;
1.1 deraadt 1316: {
1317:
1.10 millert 1318: alarmtimer(0);
1.1 deraadt 1319: abrtflag++;
1320: }
1321:
1322: void
1323: pswitch(flag)
1324: int flag;
1325: {
1326: sig_t oldintr;
1327: static struct comvars {
1328: int connect;
1329: char name[MAXHOSTNAMELEN];
1330: struct sockaddr_in mctl;
1331: struct sockaddr_in hctl;
1332: FILE *in;
1333: FILE *out;
1334: int tpe;
1335: int curtpe;
1336: int cpnd;
1337: int sunqe;
1338: int runqe;
1339: int mcse;
1340: int ntflg;
1341: char nti[17];
1342: char nto[17];
1343: int mapflg;
1344: char mi[MAXPATHLEN];
1345: char mo[MAXPATHLEN];
1346: } proxstruct, tmpstruct;
1347: struct comvars *ip, *op;
1348:
1349: abrtflag = 0;
1350: oldintr = signal(SIGINT, psabort);
1351: if (flag) {
1352: if (proxy)
1353: return;
1354: ip = &tmpstruct;
1355: op = &proxstruct;
1356: proxy++;
1357: } else {
1358: if (!proxy)
1359: return;
1360: ip = &proxstruct;
1361: op = &tmpstruct;
1362: proxy = 0;
1363: }
1364: ip->connect = connected;
1365: connected = op->connect;
1366: if (hostname) {
1.11 millert 1367: (void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1368: ip->name[sizeof(ip->name) - 1] = '\0';
1.1 deraadt 1369: } else
1.11 millert 1370: ip->name[0] = '\0';
1.1 deraadt 1371: hostname = op->name;
1372: ip->hctl = hisctladdr;
1373: hisctladdr = op->hctl;
1374: ip->mctl = myctladdr;
1375: myctladdr = op->mctl;
1376: ip->in = cin;
1377: cin = op->in;
1378: ip->out = cout;
1379: cout = op->out;
1380: ip->tpe = type;
1381: type = op->tpe;
1382: ip->curtpe = curtype;
1383: curtype = op->curtpe;
1384: ip->cpnd = cpend;
1385: cpend = op->cpnd;
1386: ip->sunqe = sunique;
1387: sunique = op->sunqe;
1388: ip->runqe = runique;
1389: runique = op->runqe;
1390: ip->mcse = mcase;
1391: mcase = op->mcse;
1392: ip->ntflg = ntflag;
1393: ntflag = op->ntflg;
1.11 millert 1394: (void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1395: (ip->nti)[sizeof(ip->nti) - 1] = '\0';
1396: (void)strcpy(ntin, op->nti);
1397: (void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1398: (ip->nto)[sizeof(ip->nto) - 1] = '\0';
1399: (void)strcpy(ntout, op->nto);
1.1 deraadt 1400: ip->mapflg = mapflag;
1401: mapflag = op->mapflg;
1.11 millert 1402: (void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1403: (ip->mi)[sizeof(ip->mi) - 1] = '\0';
1404: (void)strcpy(mapin, op->mi);
1405: (void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1406: (ip->mo)[sizeof(ip->mo) - 1] = '\0';
1407: (void)strcpy(mapout, op->mo);
1408: (void)signal(SIGINT, oldintr);
1.1 deraadt 1409: if (abrtflag) {
1410: abrtflag = 0;
1411: (*oldintr)(SIGINT);
1412: }
1413: }
1414:
1415: void
1.12 millert 1416: abortpt(notused)
1417: int notused;
1.1 deraadt 1418: {
1419:
1.10 millert 1420: alarmtimer(0);
1.11 millert 1421: putchar('\n');
1422: (void)fflush(stdout);
1.1 deraadt 1423: ptabflg++;
1424: mflag = 0;
1425: abrtflag = 0;
1426: longjmp(ptabort, 1);
1427: }
1428:
1429: void
1430: proxtrans(cmd, local, remote)
1.10 millert 1431: const char *cmd, *local, *remote;
1.1 deraadt 1432: {
1433: sig_t oldintr;
1434: int secndflag = 0, prox_type, nfnd;
1435: char *cmd2;
1436: struct fd_set mask;
1437:
1438: if (strcmp(cmd, "RETR"))
1439: cmd2 = "RETR";
1440: else
1441: cmd2 = runique ? "STOU" : "STOR";
1442: if ((prox_type = type) == 0) {
1443: if (unix_server && unix_proxy)
1444: prox_type = TYPE_I;
1445: else
1446: prox_type = TYPE_A;
1447: }
1448: if (curtype != prox_type)
1449: changetype(prox_type, 1);
1450: if (command("PASV") != COMPLETE) {
1.11 millert 1451: puts("proxy server does not support third party transfers.");
1.1 deraadt 1452: return;
1453: }
1454: pswitch(0);
1455: if (!connected) {
1.13 millert 1456: puts("No primary connection.");
1.1 deraadt 1457: pswitch(1);
1458: code = -1;
1459: return;
1460: }
1461: if (curtype != prox_type)
1462: changetype(prox_type, 1);
1463: if (command("PORT %s", pasv) != COMPLETE) {
1464: pswitch(1);
1465: return;
1466: }
1467: if (setjmp(ptabort))
1468: goto abort;
1469: oldintr = signal(SIGINT, abortpt);
1470: if (command("%s %s", cmd, remote) != PRELIM) {
1.11 millert 1471: (void)signal(SIGINT, oldintr);
1.1 deraadt 1472: pswitch(1);
1473: return;
1474: }
1475: sleep(2);
1476: pswitch(1);
1477: secndflag++;
1478: if (command("%s %s", cmd2, local) != PRELIM)
1479: goto abort;
1480: ptflag++;
1.11 millert 1481: (void)getreply(0);
1.1 deraadt 1482: pswitch(0);
1.11 millert 1483: (void)getreply(0);
1484: (void)signal(SIGINT, oldintr);
1.1 deraadt 1485: pswitch(1);
1486: ptflag = 0;
1487: printf("local: %s remote: %s\n", local, remote);
1488: return;
1489: abort:
1.11 millert 1490: (void)signal(SIGINT, SIG_IGN);
1.1 deraadt 1491: ptflag = 0;
1492: if (strcmp(cmd, "RETR") && !proxy)
1493: pswitch(1);
1494: else if (!strcmp(cmd, "RETR") && proxy)
1495: pswitch(0);
1496: if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1497: if (command("%s %s", cmd2, local) != PRELIM) {
1498: pswitch(0);
1499: if (cpend)
1500: abort_remote((FILE *) NULL);
1501: }
1502: pswitch(1);
1503: if (ptabflg)
1504: code = -1;
1.11 millert 1505: (void)signal(SIGINT, oldintr);
1.1 deraadt 1506: return;
1507: }
1508: if (cpend)
1509: abort_remote((FILE *) NULL);
1510: pswitch(!proxy);
1511: if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1512: if (command("%s %s", cmd2, local) != PRELIM) {
1513: pswitch(0);
1514: if (cpend)
1515: abort_remote((FILE *) NULL);
1516: pswitch(1);
1517: if (ptabflg)
1518: code = -1;
1.11 millert 1519: (void)signal(SIGINT, oldintr);
1.1 deraadt 1520: return;
1521: }
1522: }
1523: if (cpend)
1524: abort_remote((FILE *) NULL);
1525: pswitch(!proxy);
1526: if (cpend) {
1527: FD_ZERO(&mask);
1528: FD_SET(fileno(cin), &mask);
1529: if ((nfnd = empty(&mask, 10)) <= 0) {
1530: if (nfnd < 0) {
1531: warn("abort");
1532: }
1533: if (ptabflg)
1534: code = -1;
1535: lostpeer();
1536: }
1.11 millert 1537: (void)getreply(0);
1538: (void)getreply(0);
1.1 deraadt 1539: }
1540: if (proxy)
1541: pswitch(0);
1542: pswitch(1);
1543: if (ptabflg)
1544: code = -1;
1.11 millert 1545: (void)signal(SIGINT, oldintr);
1.1 deraadt 1546: }
1547:
1548: void
1549: reset(argc, argv)
1550: int argc;
1551: char *argv[];
1552: {
1553: struct fd_set mask;
1554: int nfnd = 1;
1555:
1556: FD_ZERO(&mask);
1557: while (nfnd > 0) {
1558: FD_SET(fileno(cin), &mask);
1.10 millert 1559: if ((nfnd = empty(&mask, 0)) < 0) {
1.1 deraadt 1560: warn("reset");
1561: code = -1;
1562: lostpeer();
1563: }
1564: else if (nfnd) {
1.11 millert 1565: (void)getreply(0);
1.1 deraadt 1566: }
1567: }
1568: }
1569:
1570: char *
1571: gunique(local)
1.10 millert 1572: const char *local;
1.1 deraadt 1573: {
1574: static char new[MAXPATHLEN];
1575: char *cp = strrchr(local, '/');
1576: int d, count=0;
1577: char ext = '1';
1578:
1579: if (cp)
1580: *cp = '\0';
1.10 millert 1581: d = access(cp == local ? "/" : cp ? local : ".", 2);
1.1 deraadt 1582: if (cp)
1583: *cp = '/';
1584: if (d < 0) {
1585: warn("local: %s", local);
1586: return ((char *) 0);
1587: }
1.11 millert 1588: (void)strcpy(new, local);
1.1 deraadt 1589: cp = new + strlen(new);
1590: *cp++ = '.';
1591: while (!d) {
1592: if (++count == 100) {
1.11 millert 1593: puts("runique: can't find unique file name.");
1.1 deraadt 1594: return ((char *) 0);
1595: }
1596: *cp++ = ext;
1597: *cp = '\0';
1598: if (ext == '9')
1599: ext = '0';
1600: else
1601: ext++;
1602: if ((d = access(new, 0)) < 0)
1603: break;
1604: if (ext != '0')
1605: cp--;
1606: else if (*(cp - 2) == '.')
1607: *(cp - 1) = '1';
1608: else {
1609: *(cp - 2) = *(cp - 2) + 1;
1610: cp--;
1611: }
1612: }
1613: return (new);
1614: }
1615:
1616: void
1617: abort_remote(din)
1618: FILE *din;
1619: {
1620: char buf[BUFSIZ];
1621: int nfnd;
1622: struct fd_set mask;
1.13 millert 1623:
1624: if (cout == NULL) {
1625: warnx("Lost control connection for abort.");
1626: if (ptabflg)
1627: code = -1;
1628: lostpeer();
1629: return;
1630: }
1.1 deraadt 1631:
1632: /*
1633: * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
1634: * after urgent byte rather than before as is protocol now
1635: */
1636: sprintf(buf, "%c%c%c", IAC, IP, IAC);
1637: if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
1638: warn("abort");
1.10 millert 1639: fprintf(cout, "%cABOR\r\n", DM);
1.11 millert 1640: (void)fflush(cout);
1.1 deraadt 1641: FD_ZERO(&mask);
1642: FD_SET(fileno(cin), &mask);
1.10 millert 1643: if (din) {
1.1 deraadt 1644: FD_SET(fileno(din), &mask);
1645: }
1646: if ((nfnd = empty(&mask, 10)) <= 0) {
1647: if (nfnd < 0) {
1648: warn("abort");
1649: }
1650: if (ptabflg)
1651: code = -1;
1652: lostpeer();
1653: }
1654: if (din && FD_ISSET(fileno(din), &mask)) {
1655: while (read(fileno(din), buf, BUFSIZ) > 0)
1656: /* LOOP */;
1657: }
1658: if (getreply(0) == ERROR && code == 552) {
1659: /* 552 needed for nic style abort */
1.11 millert 1660: (void)getreply(0);
1.1 deraadt 1661: }
1.11 millert 1662: (void)getreply(0);
1.1 deraadt 1663: }