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