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