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