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