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