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