ftp.c revision 1.62 1 /* $NetBSD: ftp.c,v 1.62 1999/09/21 13:17:22 lukem Exp $ */
2
3 /*
4 * Copyright (C) 1997 and 1998 WIDE Project.
5 * 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. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1985, 1989, 1993, 1994
34 * The Regents of the University of California. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 */
64
65 #include <sys/cdefs.h>
66 #ifndef lint
67 #if 0
68 static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
69 #else
70 __RCSID("$NetBSD: ftp.c,v 1.62 1999/09/21 13:17:22 lukem Exp $");
71 #endif
72 #endif /* not lint */
73
74 #include <sys/types.h>
75 #include <sys/stat.h>
76 #include <sys/socket.h>
77 #include <sys/time.h>
78
79 #include <netinet/in.h>
80 #include <netinet/in_systm.h>
81 #include <netinet/ip.h>
82 #include <arpa/inet.h>
83 #include <arpa/ftp.h>
84 #include <arpa/telnet.h>
85
86 #include <ctype.h>
87 #include <err.h>
88 #include <errno.h>
89 #include <netdb.h>
90 #include <signal.h>
91 #include <stdio.h>
92 #include <stdlib.h>
93 #include <string.h>
94 #include <time.h>
95 #include <unistd.h>
96 #ifdef __STDC__
97 #include <stdarg.h>
98 #else
99 #include <varargs.h>
100 #endif
101 #ifndef __USE_SELECT
102 #include <poll.h>
103 #endif
104
105 #include "ftp_var.h"
106
107 extern int h_errno;
108
109 int data = -1;
110 int abrtflag = 0;
111 jmp_buf ptabort;
112 int ptabflg;
113 int ptflag = 0;
114 off_t restart_point = 0;
115
116 static int empty __P((FILE *, FILE *, int));
117
118 union sockunion {
119 struct sockinet {
120 #ifdef BSD4_4
121 u_char si_len;
122 u_char si_family;
123 #else
124 u_short si_family;
125 #endif
126 u_short si_port;
127 #ifndef BSD4_4
128 u_char si_pad[
129 #ifdef INET6
130 sizeof(struct sockaddr_in6)
131 #else
132 sizeof(struct sockaddr_in)
133 #endif
134 - sizeof(u_int)];
135 u_char si_len;
136 #endif
137 } su_si;
138 struct sockaddr_in su_sin;
139 #ifdef INET6
140 struct sockaddr_in6 su_sin6;
141 #endif
142 };
143
144 #define su_len su_si.si_len
145 #define su_family su_si.si_family
146 #define su_port su_si.si_port
147
148 union sockunion myctladdr, hisctladdr, data_addr;
149
150 FILE *cin, *cout;
151
152 char *
153 hookup(host, port)
154 char *host;
155 char *port;
156 {
157 int s = -1, len, error;
158 #ifdef NI_NUMERICHOST
159 struct addrinfo hints, *res, *res0;
160 char hbuf[MAXHOSTNAMELEN];
161 #else
162 struct hostent *hp = NULL;
163 struct servent *sp = NULL;
164 char **ptr;
165 struct sockaddr_in sin;
166 #endif
167 static char hostnamebuf[MAXHOSTNAMELEN];
168 char *cause = "unknown";
169 int family;
170
171 #ifdef NI_NUMERICHOST
172 memset((char *)&hisctladdr, 0, sizeof (hisctladdr));
173 memset(&hints, 0, sizeof(hints));
174 hints.ai_flags = AI_CANONNAME;
175 hints.ai_family = AF_UNSPEC;
176 hints.ai_socktype = SOCK_STREAM;
177 hints.ai_protocol = 0;
178 error = getaddrinfo(host, port, &hints, &res0);
179 if (error) {
180 warnx(gai_strerror(error));
181 code = -1;
182 return (0);
183 }
184
185 if (res0->ai_canonname)
186 strncpy(hostnamebuf, res0->ai_canonname, sizeof(hostnamebuf));
187 else
188 strncpy(hostnamebuf, host, sizeof(hostnamebuf));
189 hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
190 hostname = hostnamebuf;
191
192 for (res = res0; res; res = res->ai_next) {
193 #if 0 /*old behavior*/
194 if (res != res0) /* not on the first address */
195 #else
196 if (res0->ai_next) /* if we have multiple possibilities */
197 #endif
198 {
199 getnameinfo(res->ai_addr, res->ai_addrlen,
200 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
201 fprintf(ttyout, "Trying %s...\n", hbuf);
202 }
203 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
204 if (s < 0) {
205 cause = "socket";
206 continue;
207 }
208 while ((error = xconnect(s, res->ai_addr, res->ai_addrlen)) < 0
209 && errno == EINTR) {
210 ;
211 }
212 if (error) {
213 /* this "if" clause is to prevent print warning twice */
214 if (res->ai_next) {
215 getnameinfo(res->ai_addr, res->ai_addrlen,
216 hbuf, sizeof(hbuf), NULL, 0,
217 NI_NUMERICHOST);
218 warn("connect to address %s", hbuf);
219 }
220 cause = "connect";
221 close(s);
222 s = -1;
223 continue;
224 }
225
226 /* finally we got one */
227 break;
228 }
229 if (s < 0) {
230 warn(cause);
231 code = -1;
232 freeaddrinfo(res0);
233 return 0;
234 }
235 memcpy(&hisctladdr, res->ai_addr, res->ai_addrlen);
236 len = res->ai_addrlen;
237 freeaddrinfo(res0);
238 res0 = res = NULL;
239 family = hisctladdr.su_family;
240 #else
241 memset(&sin, 0, sizeof(sin));
242 sin.sin_family = AF_INET;
243 if ((hp = gethostbyname(host)) == NULL) {
244 warnx("%s: %s", host, hstrerror(h_errno));
245 code = -1;
246 return 0;
247 }
248
249 if ((sp = getservbyname(port, "tcp")) == NULL) {
250 sin.sin_port = htons(21);
251 }
252 else
253 sin.sin_port = sp->s_port;
254
255 strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
256 hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
257 hostname = hostnamebuf;
258
259 if (hp->h_length > sizeof(sin.sin_addr))
260 hp->h_length = sizeof(sin.sin_addr);
261
262 for (ptr = hp->h_addr_list; *ptr; ptr++) {
263 memcpy(&sin.sin_addr, *ptr, (size_t)hp->h_length);
264 if (hp->h_addr_list[1])
265 fprintf(ttyout, "Trying %s...\n",
266 inet_ntoa(sin.sin_addr));
267 s = socket(AF_INET, SOCK_STREAM, 0);
268 if (s < 0) {
269 cause = "socket";
270 continue;
271 }
272 while ((error = xconnect(s, (struct sockaddr *)&sin,
273 sizeof(sin))) < 0 && errno == EINTR) {
274 ;
275 }
276 if (error) {
277 /* this "if" clause is to prevent print warning twice */
278 if (hp->h_addr_list[1]) {
279 warn("connect to address %s",
280 inet_ntoa(sin.sin_addr));
281 }
282 cause = "connect";
283 close(s);
284 s = -1;
285 continue;
286 }
287
288 /* finally we got one */
289 break;
290 }
291 if (s < 0) {
292 warn(cause);
293 code = -1;
294 return 0;
295 }
296 memcpy(&hisctladdr, &sin, sizeof(sin));
297 len = sizeof(sin);
298 if (hisctladdr.su_len == 0)
299 hisctladdr.su_len = len;
300 family = AF_INET;
301 #endif
302
303 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
304 warn("getsockname");
305 code = -1;
306 goto bad;
307 }
308 if (myctladdr.su_len == 0)
309 myctladdr.su_len = len;
310
311 #if defined(IPPROTO_IP) && defined(IP_TOS)
312 if (family == AF_INET) {
313 int tos = IPTOS_LOWDELAY;
314 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
315 sizeof(int)) < 0)
316 warn("setsockopt TOS (ignored)");
317 }
318 #endif
319 cin = fdopen(s, "r");
320 cout = fdopen(s, "w");
321 if (cin == NULL || cout == NULL) {
322 warnx("fdopen failed.");
323 if (cin)
324 (void)fclose(cin);
325 if (cout)
326 (void)fclose(cout);
327 code = -1;
328 goto bad;
329 }
330 if (verbose)
331 fprintf(ttyout, "Connected to %s.\n", hostname);
332 if (getreply(0) > 2) { /* read startup message from server */
333 if (cin)
334 (void)fclose(cin);
335 if (cout)
336 (void)fclose(cout);
337 code = -1;
338 goto bad;
339 }
340 #ifdef SO_OOBINLINE
341 {
342 int on = 1;
343
344 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on))
345 < 0 && debug) {
346 warn("setsockopt");
347 }
348 }
349 #endif /* SO_OOBINLINE */
350
351 return (hostname);
352 bad:
353 (void)close(s);
354 return (NULL);
355 }
356
357 void
358 cmdabort(notused)
359 int notused;
360 {
361
362 alarmtimer(0);
363 putc('\n', ttyout);
364 abrtflag++;
365 if (ptflag)
366 longjmp(ptabort, 1);
367 }
368
369 /*VARARGS*/
370 int
371 #ifdef __STDC__
372 command(const char *fmt, ...)
373 #else
374 command(va_alist)
375 va_dcl
376 #endif
377 {
378 va_list ap;
379 int r;
380 sig_t oldintr;
381 #ifndef __STDC__
382 const char *fmt;
383 #endif
384
385 abrtflag = 0;
386 if (debug) {
387 fputs("---> ", ttyout);
388 #ifdef __STDC__
389 va_start(ap, fmt);
390 #else
391 va_start(ap);
392 fmt = va_arg(ap, const char *);
393 #endif
394 if (strncmp("PASS ", fmt, 5) == 0)
395 fputs("PASS XXXX", ttyout);
396 else if (strncmp("ACCT ", fmt, 5) == 0)
397 fputs("ACCT XXXX", ttyout);
398 else
399 vfprintf(ttyout, fmt, ap);
400 va_end(ap);
401 putc('\n', ttyout);
402 }
403 if (cout == NULL) {
404 warnx("No control connection for command.");
405 code = -1;
406 return (0);
407 }
408 oldintr = signal(SIGINT, cmdabort);
409 #ifdef __STDC__
410 va_start(ap, fmt);
411 #else
412 va_start(ap);
413 fmt = va_arg(ap, char *);
414 #endif
415 vfprintf(cout, fmt, ap);
416 va_end(ap);
417 fputs("\r\n", cout);
418 (void)fflush(cout);
419 cpend = 1;
420 r = getreply(!strcmp(fmt, "QUIT"));
421 if (abrtflag && oldintr != SIG_IGN)
422 (*oldintr)(SIGINT);
423 (void)signal(SIGINT, oldintr);
424 return (r);
425 }
426
427 char reply_string[BUFSIZ]; /* first line of previous reply */
428
429 int
430 getreply(expecteof)
431 int expecteof;
432 {
433 char current_line[BUFSIZ]; /* last line of previous reply */
434 int c, n, line;
435 int dig;
436 int originalcode = 0, continuation = 0;
437 sig_t oldintr;
438 int pflag = 0;
439 char *cp, *pt = pasv;
440
441 oldintr = signal(SIGINT, cmdabort);
442 for (line = 0 ;; line++) {
443 dig = n = code = 0;
444 cp = current_line;
445 while ((c = getc(cin)) != '\n') {
446 if (c == IAC) { /* handle telnet commands */
447 switch (c = getc(cin)) {
448 case WILL:
449 case WONT:
450 c = getc(cin);
451 fprintf(cout, "%c%c%c", IAC, DONT, c);
452 (void)fflush(cout);
453 break;
454 case DO:
455 case DONT:
456 c = getc(cin);
457 fprintf(cout, "%c%c%c", IAC, WONT, c);
458 (void)fflush(cout);
459 break;
460 default:
461 break;
462 }
463 continue;
464 }
465 dig++;
466 if (c == EOF) {
467 if (expecteof) {
468 (void)signal(SIGINT, oldintr);
469 code = 221;
470 return (0);
471 }
472 lostpeer();
473 if (verbose) {
474 fputs(
475 "421 Service not available, remote server has closed connection.\n",
476 ttyout);
477 }
478 code = 421;
479 return (4);
480 }
481 if (c != '\r' && (verbose > 0 ||
482 ((verbose > -1 && n == '5' && dig > 4) &&
483 (((!n && c < '5') || (n && n < '5'))
484 || !retry_connect)))) {
485 if (proxflag &&
486 (dig == 1 || (dig == 5 && verbose == 0)))
487 fprintf(ttyout, "%s:", hostname);
488 (void)putc(c, ttyout);
489 }
490 if (dig < 4 && isdigit(c))
491 code = code * 10 + (c - '0');
492 if (!pflag && (code == 227 || code == 228))
493 pflag = 1;
494 else if (!pflag && code == 229)
495 pflag = 100;
496 if (dig > 4 && pflag == 1 && isdigit(c))
497 pflag = 2;
498 if (pflag == 2) {
499 if (c != '\r' && c != ')')
500 *pt++ = c;
501 else {
502 *pt = '\0';
503 pflag = 3;
504 }
505 }
506 if (pflag == 100 && c == '(')
507 pflag = 2;
508 if (dig == 4 && c == '-') {
509 if (continuation)
510 code = 0;
511 continuation++;
512 }
513 if (n == 0)
514 n = c;
515 if (cp < ¤t_line[sizeof(current_line) - 1])
516 *cp++ = c;
517 }
518 if (verbose > 0 || ((verbose > -1 && n == '5') &&
519 (n < '5' || !retry_connect))) {
520 (void)putc(c, ttyout);
521 (void)fflush (ttyout);
522 }
523 if (line == 0) {
524 size_t len = cp - current_line;
525
526 if (len > sizeof(reply_string))
527 len = sizeof(reply_string);
528
529 (void)strncpy(reply_string, current_line, len);
530 reply_string[len] = '\0';
531 }
532 if (continuation && code != originalcode) {
533 if (originalcode == 0)
534 originalcode = code;
535 continue;
536 }
537 *cp = '\0';
538 if (n != '1')
539 cpend = 0;
540 (void)signal(SIGINT, oldintr);
541 if (code == 421 || originalcode == 421)
542 lostpeer();
543 if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN)
544 (*oldintr)(SIGINT);
545 return (n - '0');
546 }
547 }
548
549 static int
550 empty(cin, din, sec)
551 FILE *cin;
552 FILE *din;
553 int sec;
554 {
555 int nr;
556 int nfd = 0;
557
558 #ifdef __USE_SELECT
559 struct timeval t;
560 fd_set rmask;
561
562 FD_ZERO(&cin);
563 if (cin) {
564 if (nfd < fileno(cin))
565 nfd = fileno(cin);
566 FD_SET(fileno(cin), &rmask);
567 }
568 if (din) {
569 if (nfd < fileno(din))
570 nfd = fileno(din);
571 FD_SET(fileno(din), &rmask);
572 }
573
574 t.tv_sec = (long) sec;
575 t.tv_usec = 0;
576 if ((nr = select(nfd, &rmask, NULL, NULL, &t)) <= 0)
577 return nr;
578
579 nr = 0;
580 if (cin)
581 nr |= FD_ISSET(fileno(cin), &rmask) ? 1 : 0;
582 if (din)
583 nr |= FD_ISSET(fileno(din), &rmask) ? 2 : 0;
584
585 #else
586 struct pollfd pfd[2];
587
588 if (cin) {
589 pfd[nfd].fd = fileno(cin);
590 pfd[nfd++].events = POLLIN;
591 }
592
593 if (din) {
594 pfd[nfd].fd = fileno(din);
595 pfd[nfd++].events = POLLIN;
596 }
597
598 if ((nr = poll(pfd, nfd, sec * 1000)) <= 0)
599 return nr;
600
601 nr = 0;
602 nfd = 0;
603 if (cin)
604 nr |= (pfd[nfd++].revents & POLLIN) ? 1 : 0;
605 if (din)
606 nr |= (pfd[nfd++].revents & POLLIN) ? 2 : 0;
607 #endif
608 return nr;
609 }
610
611 jmp_buf sendabort;
612
613 void
614 abortsend(notused)
615 int notused;
616 {
617
618 alarmtimer(0);
619 mflag = 0;
620 abrtflag = 0;
621 fputs("\nsend aborted\nwaiting for remote to finish abort.\n", ttyout);
622 longjmp(sendabort, 1);
623 }
624
625 void
626 sendrequest(cmd, local, remote, printnames)
627 const char *cmd, *local, *remote;
628 int printnames;
629 {
630 struct stat st;
631 int c, d;
632 FILE *fin, *dout;
633 int (*closefunc) __P((FILE *));
634 sig_t oldinti, oldintr, oldintp;
635 volatile off_t hashbytes;
636 char *lmode, buf[BUFSIZ], *bufp;
637 int oprogress;
638
639 #ifdef __GNUC__ /* to shut up gcc warnings */
640 (void)&fin;
641 (void)&dout;
642 (void)&closefunc;
643 (void)&oldinti;
644 (void)&oldintr;
645 (void)&oldintp;
646 (void)&lmode;
647 #endif
648
649 hashbytes = mark;
650 direction = "sent";
651 dout = NULL;
652 bytes = 0;
653 filesize = -1;
654 oprogress = progress;
655 if (verbose && printnames) {
656 if (local && *local != '-')
657 fprintf(ttyout, "local: %s ", local);
658 if (remote)
659 fprintf(ttyout, "remote: %s\n", remote);
660 }
661 if (proxy) {
662 proxtrans(cmd, local, remote);
663 return;
664 }
665 if (curtype != type)
666 changetype(type, 0);
667 closefunc = NULL;
668 oldintr = NULL;
669 oldintp = NULL;
670 oldinti = NULL;
671 lmode = "w";
672 if (setjmp(sendabort)) {
673 while (cpend) {
674 (void)getreply(0);
675 }
676 if (data >= 0) {
677 (void)close(data);
678 data = -1;
679 }
680 if (oldintr)
681 (void)signal(SIGINT, oldintr);
682 if (oldintp)
683 (void)signal(SIGPIPE, oldintp);
684 if (oldinti)
685 (void)xsignal(SIGINFO, oldinti);
686 code = -1;
687 goto cleanupsend;
688 }
689 oldintr = signal(SIGINT, abortsend);
690 oldinti = xsignal(SIGINFO, psummary);
691 if (strcmp(local, "-") == 0) {
692 fin = stdin;
693 progress = 0;
694 } else if (*local == '|') {
695 oldintp = signal(SIGPIPE, SIG_IGN);
696 fin = popen(local + 1, "r");
697 if (fin == NULL) {
698 warn("%s", local + 1);
699 (void)signal(SIGINT, oldintr);
700 (void)signal(SIGPIPE, oldintp);
701 (void)xsignal(SIGINFO, oldinti);
702 code = -1;
703 goto cleanupsend;
704 }
705 progress = 0;
706 closefunc = pclose;
707 } else {
708 fin = fopen(local, "r");
709 if (fin == NULL) {
710 warn("local: %s", local);
711 (void)signal(SIGINT, oldintr);
712 (void)xsignal(SIGINFO, oldinti);
713 code = -1;
714 goto cleanupsend;
715 }
716 closefunc = fclose;
717 if (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode)) {
718 fprintf(ttyout, "%s: not a plain file.\n", local);
719 (void)signal(SIGINT, oldintr);
720 (void)xsignal(SIGINFO, oldinti);
721 fclose(fin);
722 code = -1;
723 goto cleanupsend;
724 }
725 filesize = st.st_size;
726 }
727 if (initconn()) {
728 (void)signal(SIGINT, oldintr);
729 (void)xsignal(SIGINFO, oldinti);
730 if (oldintp)
731 (void)signal(SIGPIPE, oldintp);
732 code = -1;
733 if (closefunc != NULL)
734 (*closefunc)(fin);
735 goto cleanupsend;
736 }
737 if (setjmp(sendabort))
738 goto abort;
739
740 if (restart_point &&
741 (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) {
742 int rc;
743
744 rc = -1;
745 switch (curtype) {
746 case TYPE_A:
747 rc = fseek(fin, (long) restart_point, SEEK_SET);
748 break;
749 case TYPE_I:
750 case TYPE_L:
751 rc = lseek(fileno(fin), restart_point, SEEK_SET);
752 break;
753 }
754 if (rc < 0) {
755 warn("local: %s", local);
756 if (closefunc != NULL)
757 (*closefunc)(fin);
758 goto cleanupsend;
759 }
760 #ifndef NO_QUAD
761 if (command("REST %qd", (long long) restart_point) !=
762 #else
763 if (command("REST %ld", (long) restart_point) !=
764 #endif
765 CONTINUE) {
766 if (closefunc != NULL)
767 (*closefunc)(fin);
768 goto cleanupsend;
769 }
770 lmode = "r+w";
771 }
772 if (remote) {
773 if (command("%s %s", cmd, remote) != PRELIM) {
774 (void)signal(SIGINT, oldintr);
775 (void)xsignal(SIGINFO, oldinti);
776 if (oldintp)
777 (void)signal(SIGPIPE, oldintp);
778 if (closefunc != NULL)
779 (*closefunc)(fin);
780 goto cleanupsend;
781 }
782 } else
783 if (command("%s", cmd) != PRELIM) {
784 (void)signal(SIGINT, oldintr);
785 (void)xsignal(SIGINFO, oldinti);
786 if (oldintp)
787 (void)signal(SIGPIPE, oldintp);
788 if (closefunc != NULL)
789 (*closefunc)(fin);
790 goto cleanupsend;
791 }
792 dout = dataconn(lmode);
793 if (dout == NULL)
794 goto abort;
795 progressmeter(-1);
796 oldintp = signal(SIGPIPE, SIG_IGN);
797 switch (curtype) {
798
799 case TYPE_I:
800 case TYPE_L:
801 while (1) {
802 struct timeval then, now, td;
803 off_t bufrem, bufsize;
804
805 bufsize = sizeof(buf);
806 if (rate_put)
807 (void)gettimeofday(&then, NULL);
808 errno = c = d = 0;
809 bufrem = rate_put ? rate_put : bufsize;
810 while (bufrem > 0) {
811 if ((c = read(fileno(fin), buf,
812 MIN(bufsize, bufrem))) <= 0)
813 goto senddone;
814 bytes += c;
815 bufrem -= c;
816 for (bufp = buf; c > 0; c -= d, bufp += d)
817 if ((d = write(fileno(dout), bufp, c))
818 <= 0)
819 break;
820 if (d < 0)
821 goto senddone;
822 if (hash && (!progress || filesize < 0) ) {
823 while (bytes >= hashbytes) {
824 (void)putc('#', ttyout);
825 hashbytes += mark;
826 }
827 (void)fflush(ttyout);
828 }
829 }
830 if (rate_put) {
831 while (1) {
832 (void)gettimeofday(&now, NULL);
833 timersub(&now, &then, &td);
834 if (td.tv_sec > 0)
835 break;
836 usleep(1000000 - td.tv_usec);
837 }
838 }
839 }
840 senddone:
841 if (hash && (!progress || filesize < 0) && bytes > 0) {
842 if (bytes < mark)
843 (void)putc('#', ttyout);
844 (void)putc('\n', ttyout);
845 }
846 if (c < 0)
847 warn("local: %s", local);
848 if (d < 0) {
849 if (errno != EPIPE)
850 warn("netout");
851 bytes = -1;
852 }
853 break;
854
855 case TYPE_A:
856 while ((c = getc(fin)) != EOF) {
857 if (c == '\n') {
858 while (hash && (!progress || filesize < 0) &&
859 (bytes >= hashbytes)) {
860 (void)putc('#', ttyout);
861 (void)fflush(ttyout);
862 hashbytes += mark;
863 }
864 if (ferror(dout))
865 break;
866 (void)putc('\r', dout);
867 bytes++;
868 }
869 (void)putc(c, dout);
870 bytes++;
871 #if 0 /* this violates RFC */
872 if (c == '\r') {
873 (void)putc('\0', dout);
874 bytes++;
875 }
876 #endif
877 }
878 if (hash && (!progress || filesize < 0)) {
879 if (bytes < hashbytes)
880 (void)putc('#', ttyout);
881 (void)putc('\n', ttyout);
882 }
883 if (ferror(fin))
884 warn("local: %s", local);
885 if (ferror(dout)) {
886 if (errno != EPIPE)
887 warn("netout");
888 bytes = -1;
889 }
890 break;
891 }
892 progressmeter(1);
893 if (closefunc != NULL)
894 (*closefunc)(fin);
895 (void)fclose(dout);
896 (void)getreply(0);
897 (void)signal(SIGINT, oldintr);
898 (void)xsignal(SIGINFO, oldinti);
899 if (oldintp)
900 (void)signal(SIGPIPE, oldintp);
901 if (bytes > 0)
902 ptransfer(0);
903 goto cleanupsend;
904 abort:
905 (void)signal(SIGINT, oldintr);
906 (void)xsignal(SIGINFO, oldinti);
907 if (oldintp)
908 (void)signal(SIGPIPE, oldintp);
909 if (!cpend) {
910 code = -1;
911 return;
912 }
913 if (data >= 0) {
914 (void)close(data);
915 data = -1;
916 }
917 if (dout)
918 (void)fclose(dout);
919 (void)getreply(0);
920 code = -1;
921 if (closefunc != NULL && fin != NULL)
922 (*closefunc)(fin);
923 if (bytes > 0)
924 ptransfer(0);
925 cleanupsend:
926 progress = oprogress;
927 restart_point = 0;
928 }
929
930 jmp_buf recvabort;
931
932 void
933 abortrecv(notused)
934 int notused;
935 {
936
937 alarmtimer(0);
938 mflag = 0;
939 abrtflag = 0;
940 fputs("\nreceive aborted\nwaiting for remote to finish abort.\n",
941 ttyout);
942 longjmp(recvabort, 1);
943 }
944
945 void
946 recvrequest(cmd, local, remote, lmode, printnames, ignorespecial)
947 const char *cmd, *local, *remote, *lmode;
948 int printnames, ignorespecial;
949 {
950 FILE *fout, *din;
951 int (*closefunc) __P((FILE *));
952 sig_t oldinti, oldintr, oldintp;
953 int c, d;
954 volatile int is_retr, tcrflag, bare_lfs;
955 static size_t bufsize;
956 static char *buf;
957 volatile off_t hashbytes;
958 struct stat st;
959 time_t mtime;
960 struct timeval tval[2];
961 int oprogress;
962 int opreserve;
963
964 #ifdef __GNUC__ /* to shut up gcc warnings */
965 (void)&local;
966 (void)&fout;
967 (void)&din;
968 (void)&closefunc;
969 (void)&oldinti;
970 (void)&oldintr;
971 (void)&oldintp;
972 #endif
973
974 fout = NULL;
975 din = NULL;
976 oldinti = NULL;
977 hashbytes = mark;
978 direction = "received";
979 bytes = 0;
980 bare_lfs = 0;
981 filesize = -1;
982 oprogress = progress;
983 opreserve = preserve;
984 is_retr = (strcmp(cmd, "RETR") == 0);
985 if (is_retr && verbose && printnames) {
986 if (local && (ignorespecial || *local != '-'))
987 fprintf(ttyout, "local: %s ", local);
988 if (remote)
989 fprintf(ttyout, "remote: %s\n", remote);
990 }
991 if (proxy && is_retr) {
992 proxtrans(cmd, local, remote);
993 return;
994 }
995 closefunc = NULL;
996 oldintr = NULL;
997 oldintp = NULL;
998 tcrflag = !crflag && is_retr;
999 if (setjmp(recvabort)) {
1000 while (cpend) {
1001 (void)getreply(0);
1002 }
1003 if (data >= 0) {
1004 (void)close(data);
1005 data = -1;
1006 }
1007 if (oldintr)
1008 (void)signal(SIGINT, oldintr);
1009 if (oldinti)
1010 (void)xsignal(SIGINFO, oldinti);
1011 progress = oprogress;
1012 preserve = opreserve;
1013 code = -1;
1014 return;
1015 }
1016 oldintr = signal(SIGINT, abortrecv);
1017 oldinti = xsignal(SIGINFO, psummary);
1018 if (ignorespecial || (strcmp(local, "-") && *local != '|')) {
1019 if (access(local, W_OK) < 0) {
1020 char *dir = strrchr(local, '/');
1021
1022 if (errno != ENOENT && errno != EACCES) {
1023 warn("local: %s", local);
1024 (void)signal(SIGINT, oldintr);
1025 (void)xsignal(SIGINFO, oldinti);
1026 code = -1;
1027 return;
1028 }
1029 if (dir != NULL)
1030 *dir = 0;
1031 d = access(dir == local ? "/" :
1032 dir ? local : ".", W_OK);
1033 if (dir != NULL)
1034 *dir = '/';
1035 if (d < 0) {
1036 warn("local: %s", local);
1037 (void)signal(SIGINT, oldintr);
1038 (void)xsignal(SIGINFO, oldinti);
1039 code = -1;
1040 return;
1041 }
1042 if (!runique && errno == EACCES &&
1043 chmod(local, (S_IRUSR|S_IWUSR)) < 0) {
1044 warn("local: %s", local);
1045 (void)signal(SIGINT, oldintr);
1046 (void)xsignal(SIGINFO, oldinti);
1047 code = -1;
1048 return;
1049 }
1050 if (runique && errno == EACCES &&
1051 (local = gunique(local)) == NULL) {
1052 (void)signal(SIGINT, oldintr);
1053 (void)xsignal(SIGINFO, oldinti);
1054 code = -1;
1055 return;
1056 }
1057 }
1058 else if (runique && (local = gunique(local)) == NULL) {
1059 (void)signal(SIGINT, oldintr);
1060 (void)xsignal(SIGINFO, oldinti);
1061 code = -1;
1062 return;
1063 }
1064 }
1065 if (!is_retr) {
1066 if (curtype != TYPE_A)
1067 changetype(TYPE_A, 0);
1068 } else {
1069 if (curtype != type)
1070 changetype(type, 0);
1071 filesize = remotesize(remote, 0);
1072 }
1073 if (initconn()) {
1074 (void)signal(SIGINT, oldintr);
1075 (void)xsignal(SIGINFO, oldinti);
1076 code = -1;
1077 return;
1078 }
1079 if (setjmp(recvabort))
1080 goto abort;
1081 if (is_retr && restart_point &&
1082 #ifndef NO_QUAD
1083 command("REST %qd", (long long) restart_point) != CONTINUE)
1084 #else
1085 command("REST %ld", (long) restart_point) != CONTINUE)
1086 #endif
1087 return;
1088 if (remote) {
1089 if (command("%s %s", cmd, remote) != PRELIM) {
1090 (void)signal(SIGINT, oldintr);
1091 (void)xsignal(SIGINFO, oldinti);
1092 return;
1093 }
1094 } else {
1095 if (command("%s", cmd) != PRELIM) {
1096 (void)signal(SIGINT, oldintr);
1097 (void)xsignal(SIGINFO, oldinti);
1098 return;
1099 }
1100 }
1101 din = dataconn("r");
1102 if (din == NULL)
1103 goto abort;
1104 if (!ignorespecial && strcmp(local, "-") == 0) {
1105 fout = stdout;
1106 progress = 0;
1107 preserve = 0;
1108 } else if (!ignorespecial && *local == '|') {
1109 oldintp = signal(SIGPIPE, SIG_IGN);
1110 fout = popen(local + 1, "w");
1111 if (fout == NULL) {
1112 warn("%s", local+1);
1113 goto abort;
1114 }
1115 progress = 0;
1116 preserve = 0;
1117 closefunc = pclose;
1118 } else {
1119 fout = fopen(local, lmode);
1120 if (fout == NULL) {
1121 warn("local: %s", local);
1122 goto abort;
1123 }
1124 closefunc = fclose;
1125 }
1126
1127 /*
1128 * XXX: look at punting and just using sndbuf_* for
1129 * the buffer size, since st.st_blksize ~= 512
1130 * and BUFSIZ ~= 4K
1131 */
1132 if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0)
1133 st.st_blksize = BUFSIZ;
1134 if (st.st_blksize > bufsize) {
1135 if (buf)
1136 (void)free(buf);
1137 bufsize = st.st_blksize;
1138 buf = xmalloc(bufsize);
1139 }
1140 if (!S_ISREG(st.st_mode)) {
1141 progress = 0;
1142 preserve = 0;
1143 }
1144 progressmeter(-1);
1145 switch (curtype) {
1146
1147 case TYPE_I:
1148 case TYPE_L:
1149 if (is_retr && restart_point &&
1150 lseek(fileno(fout), restart_point, SEEK_SET) < 0) {
1151 warn("local: %s", local);
1152 progress = oprogress;
1153 preserve = opreserve;
1154 if (closefunc != NULL)
1155 (*closefunc)(fout);
1156 return;
1157 }
1158 while (1) {
1159 struct timeval then, now, td;
1160 off_t bufrem;
1161
1162 if (rate_get)
1163 (void)gettimeofday(&then, NULL);
1164 errno = c = d = 0;
1165 bufrem = rate_get ? rate_get : bufsize;
1166 while (bufrem > 0) {
1167 if ((c = read(fileno(din), buf,
1168 MIN(bufsize, bufrem))) <= 0)
1169 goto recvdone;
1170 bytes += c;
1171 bufrem -=c;
1172 if ((d = write(fileno(fout), buf, c)) != c)
1173 goto recvdone;
1174 if (hash && (!progress || filesize < 0)) {
1175 while (bytes >= hashbytes) {
1176 (void)putc('#', ttyout);
1177 hashbytes += mark;
1178 }
1179 (void)fflush(ttyout);
1180 }
1181 }
1182 if (rate_get) {
1183 while (1) {
1184 (void)gettimeofday(&now, NULL);
1185 timersub(&now, &then, &td);
1186 if (td.tv_sec > 0)
1187 break;
1188 usleep(1000000 - td.tv_usec);
1189 }
1190 }
1191 }
1192 recvdone:
1193 if (hash && (!progress || filesize < 0) && bytes > 0) {
1194 if (bytes < mark)
1195 (void)putc('#', ttyout);
1196 (void)putc('\n', ttyout);
1197 }
1198 if (c < 0) {
1199 if (errno != EPIPE)
1200 warn("netin");
1201 bytes = -1;
1202 }
1203 if (d < c) {
1204 if (d < 0)
1205 warn("local: %s", local);
1206 else
1207 warnx("%s: short write", local);
1208 }
1209 break;
1210
1211 case TYPE_A:
1212 if (is_retr && restart_point) {
1213 int ch;
1214 long i, n;
1215
1216 if (fseek(fout, 0L, SEEK_SET) < 0)
1217 goto done;
1218 n = (long)restart_point;
1219 for (i = 0; i++ < n;) {
1220 if ((ch = getc(fout)) == EOF)
1221 goto done;
1222 if (ch == '\n')
1223 i++;
1224 }
1225 if (fseek(fout, 0L, SEEK_CUR) < 0) {
1226 done:
1227 warn("local: %s", local);
1228 progress = oprogress;
1229 preserve = opreserve;
1230 if (closefunc != NULL)
1231 (*closefunc)(fout);
1232 return;
1233 }
1234 }
1235 while ((c = getc(din)) != EOF) {
1236 if (c == '\n')
1237 bare_lfs++;
1238 while (c == '\r') {
1239 while (hash && (!progress || filesize < 0) &&
1240 (bytes >= hashbytes)) {
1241 (void)putc('#', ttyout);
1242 (void)fflush(ttyout);
1243 hashbytes += mark;
1244 }
1245 bytes++;
1246 if ((c = getc(din)) != '\n' || tcrflag) {
1247 if (ferror(fout))
1248 goto break2;
1249 (void)putc('\r', fout);
1250 if (c == '\0') {
1251 bytes++;
1252 goto contin2;
1253 }
1254 if (c == EOF)
1255 goto contin2;
1256 }
1257 }
1258 (void)putc(c, fout);
1259 bytes++;
1260 contin2: ;
1261 }
1262 break2:
1263 if (hash && (!progress || filesize < 0)) {
1264 if (bytes < hashbytes)
1265 (void)putc('#', ttyout);
1266 (void)putc('\n', ttyout);
1267 }
1268 if (ferror(din)) {
1269 if (errno != EPIPE)
1270 warn("netin");
1271 bytes = -1;
1272 }
1273 if (ferror(fout))
1274 warn("local: %s", local);
1275 break;
1276 }
1277 progressmeter(1);
1278 if (closefunc != NULL)
1279 (*closefunc)(fout);
1280 (void)signal(SIGINT, oldintr);
1281 (void)xsignal(SIGINFO, oldinti);
1282 if (oldintp)
1283 (void)signal(SIGPIPE, oldintp);
1284 (void)fclose(din);
1285 (void)getreply(0);
1286 if (bare_lfs) {
1287 fprintf(ttyout,
1288 "WARNING! %d bare linefeeds received in ASCII mode.\n",
1289 bare_lfs);
1290 fputs("File may not have transferred correctly.\n", ttyout);
1291 }
1292 if (bytes >= 0 && is_retr) {
1293 if (bytes > 0)
1294 ptransfer(0);
1295 if (preserve && (closefunc == fclose)) {
1296 mtime = remotemodtime(remote, 0);
1297 if (mtime != -1) {
1298 (void)gettimeofday(&tval[0], NULL);
1299 tval[1].tv_sec = mtime;
1300 tval[1].tv_usec = 0;
1301 if (utimes(local, tval) == -1) {
1302 fprintf(ttyout,
1303 "Can't change modification time on %s to %s",
1304 local, asctime(localtime(&mtime)));
1305 }
1306 }
1307 }
1308 }
1309 progress = oprogress;
1310 preserve = opreserve;
1311 return;
1312
1313 abort:
1314
1315 /* abort using RFC 959 recommended IP,SYNC sequence */
1316
1317 progress = oprogress;
1318 preserve = opreserve;
1319 if (oldintp)
1320 (void)signal(SIGPIPE, oldintp);
1321 (void)signal(SIGINT, SIG_IGN);
1322 if (!cpend) {
1323 code = -1;
1324 (void)signal(SIGINT, oldintr);
1325 (void)xsignal(SIGINFO, oldinti);
1326 return;
1327 }
1328
1329 abort_remote(din);
1330 code = -1;
1331 if (data >= 0) {
1332 (void)close(data);
1333 data = -1;
1334 }
1335 if (closefunc != NULL && fout != NULL)
1336 (*closefunc)(fout);
1337 if (din)
1338 (void)fclose(din);
1339 if (bytes > 0)
1340 ptransfer(0);
1341 (void)signal(SIGINT, oldintr);
1342 (void)xsignal(SIGINFO, oldinti);
1343 }
1344
1345 /*
1346 * Need to start a listen on the data channel before we send the command,
1347 * otherwise the server's connect may fail.
1348 */
1349 int
1350 initconn()
1351 {
1352 char *p, *a;
1353 int result, len, tmpno = 0;
1354 int on = 1;
1355 int error;
1356 u_int addr[16], port[2];
1357 u_int af, hal, pal;
1358 char *pasvcmd = NULL;
1359
1360 #ifdef INET6
1361 if (myctladdr.su_family == AF_INET6
1362 && (IN6_IS_ADDR_LINKLOCAL(&myctladdr.su_sin6.sin6_addr)
1363 || IN6_IS_ADDR_SITELOCAL(&myctladdr.su_sin6.sin6_addr))) {
1364 warnx("use of scoped address can be troublesome");
1365 }
1366 #endif
1367 reinit:
1368 if (passivemode) {
1369 data_addr = myctladdr;
1370 data = socket(data_addr.su_family, SOCK_STREAM, 0);
1371 if (data < 0) {
1372 warn("socket");
1373 return (1);
1374 }
1375 if ((options & SO_DEBUG) &&
1376 setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1377 sizeof(on)) < 0)
1378 warn("setsockopt (ignored)");
1379 result = COMPLETE + 1;
1380 switch (data_addr.su_family) {
1381 case AF_INET:
1382 if (epsv4) {
1383 result = command(pasvcmd = "EPSV");
1384 /*
1385 * this code is to be friendly with broken
1386 * BSDI ftpd
1387 */
1388 if (code / 10 == 22 && code != 229) {
1389 fputs(
1390 "wrong server: return code must be 229\n",
1391 ttyout);
1392 result = COMPLETE + 1;
1393 }
1394 }
1395 if (result != COMPLETE)
1396 result = command(pasvcmd = "PASV");
1397 break;
1398 #ifdef INET6
1399 case AF_INET6:
1400 result = command(pasvcmd = "EPSV");
1401 /* this code is to be friendly with broken BSDI ftpd */
1402 if (code / 10 == 22 && code != 229) {
1403 fputs(
1404 "wrong server: return code must be 229\n",
1405 ttyout);
1406 result = COMPLETE + 1;
1407 }
1408 if (result != COMPLETE)
1409 result = command(pasvcmd = "LPSV");
1410 break;
1411 #endif
1412 default:
1413 result = COMPLETE + 1;
1414 break;
1415 }
1416 if (result != COMPLETE) {
1417 if (activefallback) {
1418 (void)close(data);
1419 data = -1;
1420 passivemode = 0;
1421 activefallback = 0;
1422 goto reinit;
1423 }
1424 fputs("Passive mode refused.\n", ttyout);
1425 goto bad;
1426 }
1427
1428 #define pack2(var, off) \
1429 (((var[(off) + 0] & 0xff) << 8) | ((var[(off) + 1] & 0xff) << 0))
1430 #define pack4(var, off) \
1431 (((var[(off) + 0] & 0xff) << 24) | ((var[(off) + 1] & 0xff) << 16) | \
1432 ((var[(off) + 2] & 0xff) << 8) | ((var[(off) + 3] & 0xff) << 0))
1433
1434 /*
1435 * What we've got at this point is a string of comma separated
1436 * one-byte unsigned integer values, separated by commas.
1437 */
1438 if (strcmp(pasvcmd, "PASV") == 0) {
1439 if (data_addr.su_family != AF_INET) {
1440 fputs(
1441 "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1442 error = 1;
1443 goto bad;
1444 }
1445 if (code / 10 == 22 && code != 227) {
1446 fputs("wrong server: return code must be 227\n",
1447 ttyout);
1448 error = 1;
1449 goto bad;
1450 }
1451 error = sscanf(pasv, "%u,%u,%u,%u,%u,%u",
1452 &addr[0], &addr[1], &addr[2], &addr[3],
1453 &port[0], &port[1]);
1454 if (error != 6) {
1455 fputs(
1456 "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1457 error = 1;
1458 goto bad;
1459 }
1460 error = 0;
1461 memset(&data_addr, 0, sizeof(data_addr));
1462 data_addr.su_family = AF_INET;
1463 data_addr.su_len = sizeof(struct sockaddr_in);
1464 data_addr.su_sin.sin_addr.s_addr =
1465 htonl(pack4(addr, 0));
1466 data_addr.su_port = htons(pack2(port, 0));
1467 } else if (strcmp(pasvcmd, "LPSV") == 0) {
1468 if (code / 10 == 22 && code != 228) {
1469 fputs("wrong server: return code must be 228\n",
1470 ttyout);
1471 error = 1;
1472 goto bad;
1473 }
1474 switch (data_addr.su_family) {
1475 case AF_INET:
1476 error = sscanf(pasv,
1477 "%u,%u,%u,%u,%u,%u,%u,%u,%u",
1478 &af, &hal,
1479 &addr[0], &addr[1], &addr[2], &addr[3],
1480 &pal, &port[0], &port[1]);
1481 if (error != 9) {
1482 fputs(
1483 "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1484 error = 1;
1485 goto bad;
1486 }
1487 if (af != 4 || hal != 4 || pal != 2) {
1488 fputs(
1489 "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1490 error = 1;
1491 goto bad;
1492 }
1493
1494 error = 0;
1495 memset(&data_addr, 0, sizeof(data_addr));
1496 data_addr.su_family = AF_INET;
1497 data_addr.su_len = sizeof(struct sockaddr_in);
1498 data_addr.su_sin.sin_addr.s_addr =
1499 htonl(pack4(addr, 0));
1500 data_addr.su_port = htons(pack2(port, 0));
1501 break;
1502 #ifdef INET6
1503 case AF_INET6:
1504 error = sscanf(pasv,
1505 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u",
1506 &af, &hal,
1507 &addr[0], &addr[1], &addr[2], &addr[3],
1508 &addr[4], &addr[5], &addr[6], &addr[7],
1509 &addr[8], &addr[9], &addr[10],
1510 &addr[11], &addr[12], &addr[13],
1511 &addr[14], &addr[15],
1512 &pal, &port[0], &port[1]);
1513 if (error != 21) {
1514 fputs(
1515 "Passive mode address scan failure. Shouldn't happen!\n", ttyout);
1516 error = 1;
1517 goto bad;
1518 }
1519 if (af != 6 || hal != 16 || pal != 2) {
1520 fputs(
1521 "Passive mode AF mismatch. Shouldn't happen!\n", ttyout);
1522 error = 1;
1523 goto bad;
1524 }
1525
1526 error = 0;
1527 memset(&data_addr, 0, sizeof(data_addr));
1528 data_addr.su_family = AF_INET6;
1529 data_addr.su_len = sizeof(struct sockaddr_in6);
1530 {
1531 u_int32_t *p32;
1532 p32 = (u_int32_t *)&data_addr.su_sin6.sin6_addr;
1533 p32[0] = htonl(pack4(addr, 0));
1534 p32[1] = htonl(pack4(addr, 4));
1535 p32[2] = htonl(pack4(addr, 8));
1536 p32[3] = htonl(pack4(addr, 12));
1537 }
1538 data_addr.su_port = htons(pack2(port, 0));
1539 break;
1540 #endif
1541 default:
1542 error = 1;
1543 }
1544 } else if (strcmp(pasvcmd, "EPSV") == 0) {
1545 char delim[4];
1546
1547 port[0] = 0;
1548 if (code / 10 == 22 && code != 229) {
1549 fputs("wrong server: return code must be 229\n",
1550 ttyout);
1551 error = 1;
1552 goto bad;
1553 }
1554 if (sscanf(pasv, "%c%c%c%d%c", &delim[0],
1555 &delim[1], &delim[2], &port[1],
1556 &delim[3]) != 5) {
1557 fputs("parse error!\n", ttyout);
1558 error = 1;
1559 goto bad;
1560 }
1561 if (delim[0] != delim[1] || delim[0] != delim[2]
1562 || delim[0] != delim[3]) {
1563 fputs("parse error!\n", ttyout);
1564 error = 1;
1565 goto bad;
1566 }
1567 data_addr = hisctladdr;
1568 data_addr.su_port = htons(port[1]);
1569 } else
1570 goto bad;
1571
1572 while (xconnect(data, (struct sockaddr *)&data_addr,
1573 data_addr.su_len) < 0) {
1574 if (errno == EINTR)
1575 continue;
1576 if (activefallback) {
1577 (void)close(data);
1578 data = -1;
1579 passivemode = 0;
1580 activefallback = 0;
1581 goto reinit;
1582 }
1583 warn("connect");
1584 goto bad;
1585 }
1586 #if defined(IPPROTO_IP) && defined(IP_TOS)
1587 if (data_addr.su_family == AF_INET) {
1588 on = IPTOS_THROUGHPUT;
1589 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1590 sizeof(int)) < 0)
1591 warn("setsockopt TOS (ignored)");
1592 }
1593 #endif
1594 return (0);
1595 }
1596
1597 noport:
1598 data_addr = myctladdr;
1599 if (sendport)
1600 data_addr.su_port = 0; /* let system pick one */
1601 if (data != -1)
1602 (void)close(data);
1603 data = socket(data_addr.su_family, SOCK_STREAM, 0);
1604 if (data < 0) {
1605 warn("socket");
1606 if (tmpno)
1607 sendport = 1;
1608 return (1);
1609 }
1610 if (!sendport)
1611 if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
1612 sizeof(on)) < 0) {
1613 warn("setsockopt (reuse address)");
1614 goto bad;
1615 }
1616 if (bind(data, (struct sockaddr *)&data_addr, data_addr.su_len) < 0) {
1617 warn("bind");
1618 goto bad;
1619 }
1620 if (options & SO_DEBUG &&
1621 setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
1622 sizeof(on)) < 0)
1623 warn("setsockopt (ignored)");
1624 len = sizeof(data_addr);
1625 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) {
1626 warn("getsockname");
1627 goto bad;
1628 }
1629 if (xlisten(data, 1) < 0)
1630 warn("listen");
1631
1632 #define UC(b) (((int)b)&0xff)
1633
1634 if (sendport) {
1635 #ifdef INET6
1636 char hname[INET6_ADDRSTRLEN];
1637 int af;
1638 #endif
1639
1640 switch (data_addr.su_family) {
1641 case AF_INET:
1642 if (!epsv4) {
1643 result = COMPLETE + 1;
1644 break;
1645 }
1646 /* FALLTHROUGH */
1647 #ifdef INET6
1648 case AF_INET6:
1649 af = (data_addr.su_family == AF_INET) ? 1 : 2;
1650 if (getnameinfo((struct sockaddr *)&data_addr,
1651 data_addr.su_len, hname, sizeof(hname),
1652 NULL, 0, NI_NUMERICHOST)) {
1653 result = ERROR;
1654 } else {
1655 result = command("EPRT |%d|%s|%d|",
1656 af, hname, ntohs(data_addr.su_port));
1657 }
1658 break;
1659 #endif
1660 default:
1661 result = COMPLETE + 1;
1662 break;
1663 }
1664 if (result == COMPLETE)
1665 goto skip_port;
1666
1667 switch (data_addr.su_family) {
1668 case AF_INET:
1669 a = (char *)&data_addr.su_sin.sin_addr;
1670 p = (char *)&data_addr.su_port;
1671 result = command("PORT %d,%d,%d,%d,%d,%d",
1672 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
1673 UC(p[0]), UC(p[1]));
1674 break;
1675 #ifdef INET6
1676 case AF_INET6:
1677 a = (char *)&data_addr.su_sin6.sin6_addr;
1678 p = (char *)&data_addr.su_port;
1679 result = command(
1680 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
1681 6, 16,
1682 UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
1683 UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
1684 UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
1685 UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
1686 2, UC(p[0]), UC(p[1]));
1687 break;
1688 #endif
1689 default:
1690 result = COMPLETE + 1; /* xxx */
1691 }
1692 skip_port:
1693
1694 if (result == ERROR && sendport == -1) {
1695 sendport = 0;
1696 tmpno = 1;
1697 goto noport;
1698 }
1699 return (result != COMPLETE);
1700 }
1701 if (tmpno)
1702 sendport = 1;
1703 #if defined(IPPROTO_IP) && defined(IP_TOS)
1704 if (data_addr.su_family == AF_INET) {
1705 on = IPTOS_THROUGHPUT;
1706 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
1707 sizeof(int)) < 0)
1708 warn("setsockopt TOS (ignored)");
1709 }
1710 #endif
1711 return (0);
1712 bad:
1713 (void)close(data), data = -1;
1714 if (tmpno)
1715 sendport = 1;
1716 return (1);
1717 }
1718
1719 FILE *
1720 dataconn(lmode)
1721 const char *lmode;
1722 {
1723 union sockunion from;
1724 int s, fromlen = myctladdr.su_len;
1725
1726 if (passivemode)
1727 return (fdopen(data, lmode));
1728
1729 s = accept(data, (struct sockaddr *) &from, &fromlen);
1730 if (s < 0) {
1731 warn("accept");
1732 (void)close(data), data = -1;
1733 return (NULL);
1734 }
1735 (void)close(data);
1736 data = s;
1737 #if defined(IPPROTO_IP) && defined(IP_TOS)
1738 if (from.su_family == AF_INET) {
1739 int tos = IPTOS_THROUGHPUT;
1740 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos,
1741 sizeof(int)) < 0) {
1742 warn("setsockopt TOS (ignored)");
1743 }
1744 }
1745 #endif
1746 return (fdopen(data, lmode));
1747 }
1748
1749 void
1750 psummary(notused)
1751 int notused;
1752 {
1753 int oerrno;
1754
1755 oerrno = errno;
1756 if (bytes > 0)
1757 ptransfer(1);
1758 errno = oerrno;
1759 }
1760
1761 void
1762 psabort(notused)
1763 int notused;
1764 {
1765
1766 alarmtimer(0);
1767 abrtflag++;
1768 }
1769
1770 void
1771 pswitch(flag)
1772 int flag;
1773 {
1774 sig_t oldintr;
1775 static struct comvars {
1776 int connect;
1777 char name[MAXHOSTNAMELEN];
1778 union sockunion mctl;
1779 union sockunion hctl;
1780 FILE *in;
1781 FILE *out;
1782 int tpe;
1783 int curtpe;
1784 int cpnd;
1785 int sunqe;
1786 int runqe;
1787 int mcse;
1788 int ntflg;
1789 char nti[17];
1790 char nto[17];
1791 int mapflg;
1792 char mi[MAXPATHLEN];
1793 char mo[MAXPATHLEN];
1794 } proxstruct, tmpstruct;
1795 struct comvars *ip, *op;
1796
1797 abrtflag = 0;
1798 oldintr = signal(SIGINT, psabort);
1799 if (flag) {
1800 if (proxy)
1801 return;
1802 ip = &tmpstruct;
1803 op = &proxstruct;
1804 proxy++;
1805 } else {
1806 if (!proxy)
1807 return;
1808 ip = &proxstruct;
1809 op = &tmpstruct;
1810 proxy = 0;
1811 }
1812 ip->connect = connected;
1813 connected = op->connect;
1814 if (hostname) {
1815 (void)strncpy(ip->name, hostname, sizeof(ip->name) - 1);
1816 ip->name[sizeof(ip->name) - 1] = '\0';
1817 } else
1818 ip->name[0] = '\0';
1819 hostname = op->name;
1820 ip->hctl = hisctladdr;
1821 hisctladdr = op->hctl;
1822 ip->mctl = myctladdr;
1823 myctladdr = op->mctl;
1824 ip->in = cin;
1825 cin = op->in;
1826 ip->out = cout;
1827 cout = op->out;
1828 ip->tpe = type;
1829 type = op->tpe;
1830 ip->curtpe = curtype;
1831 curtype = op->curtpe;
1832 ip->cpnd = cpend;
1833 cpend = op->cpnd;
1834 ip->sunqe = sunique;
1835 sunique = op->sunqe;
1836 ip->runqe = runique;
1837 runique = op->runqe;
1838 ip->mcse = mcase;
1839 mcase = op->mcse;
1840 ip->ntflg = ntflag;
1841 ntflag = op->ntflg;
1842 (void)strncpy(ip->nti, ntin, sizeof(ip->nti) - 1);
1843 (ip->nti)[sizeof(ip->nti) - 1] = '\0';
1844 (void)strcpy(ntin, op->nti);
1845 (void)strncpy(ip->nto, ntout, sizeof(ip->nto) - 1);
1846 (ip->nto)[sizeof(ip->nto) - 1] = '\0';
1847 (void)strcpy(ntout, op->nto);
1848 ip->mapflg = mapflag;
1849 mapflag = op->mapflg;
1850 (void)strncpy(ip->mi, mapin, sizeof(ip->mi) - 1);
1851 (ip->mi)[sizeof(ip->mi) - 1] = '\0';
1852 (void)strcpy(mapin, op->mi);
1853 (void)strncpy(ip->mo, mapout, sizeof(ip->mo) - 1);
1854 (ip->mo)[sizeof(ip->mo) - 1] = '\0';
1855 (void)strcpy(mapout, op->mo);
1856 (void)signal(SIGINT, oldintr);
1857 if (abrtflag) {
1858 abrtflag = 0;
1859 (*oldintr)(SIGINT);
1860 }
1861 }
1862
1863 void
1864 abortpt(notused)
1865 int notused;
1866 {
1867
1868 alarmtimer(0);
1869 putc('\n', ttyout);
1870 ptabflg++;
1871 mflag = 0;
1872 abrtflag = 0;
1873 longjmp(ptabort, 1);
1874 }
1875
1876 void
1877 proxtrans(cmd, local, remote)
1878 const char *cmd, *local, *remote;
1879 {
1880 sig_t oldintr;
1881 int prox_type, nfnd;
1882 volatile int secndflag;
1883 char *cmd2;
1884
1885 #ifdef __GNUC__ /* to shut up gcc warnings */
1886 (void)&oldintr;
1887 (void)&cmd2;
1888 #endif
1889
1890 oldintr = NULL;
1891 secndflag = 0;
1892 if (strcmp(cmd, "RETR"))
1893 cmd2 = "RETR";
1894 else
1895 cmd2 = runique ? "STOU" : "STOR";
1896 if ((prox_type = type) == 0) {
1897 if (unix_server && unix_proxy)
1898 prox_type = TYPE_I;
1899 else
1900 prox_type = TYPE_A;
1901 }
1902 if (curtype != prox_type)
1903 changetype(prox_type, 1);
1904 if (command("PASV") != COMPLETE) {
1905 fputs("proxy server does not support third party transfers.\n",
1906 ttyout);
1907 return;
1908 }
1909 pswitch(0);
1910 if (!connected) {
1911 fputs("No primary connection.\n", ttyout);
1912 pswitch(1);
1913 code = -1;
1914 return;
1915 }
1916 if (curtype != prox_type)
1917 changetype(prox_type, 1);
1918 if (command("PORT %s", pasv) != COMPLETE) {
1919 pswitch(1);
1920 return;
1921 }
1922 if (setjmp(ptabort))
1923 goto abort;
1924 oldintr = signal(SIGINT, abortpt);
1925 if ((restart_point &&
1926 #ifndef NO_QUAD
1927 (command("REST %qd", (long long) restart_point) != CONTINUE)
1928 #else
1929 (command("REST %ld", (long) restart_point) != CONTINUE)
1930 #endif
1931 ) || (command("%s %s", cmd, remote) != PRELIM)) {
1932 (void)signal(SIGINT, oldintr);
1933 pswitch(1);
1934 return;
1935 }
1936 sleep(2);
1937 pswitch(1);
1938 secndflag++;
1939 if ((restart_point &&
1940 #ifndef NO_QUAD
1941 (command("REST %qd", (long long) restart_point) != CONTINUE)
1942 #else
1943 (command("REST %ld", (long) restart_point) != CONTINUE)
1944 #endif
1945 ) || (command("%s %s", cmd2, local) != PRELIM))
1946 goto abort;
1947 ptflag++;
1948 (void)getreply(0);
1949 pswitch(0);
1950 (void)getreply(0);
1951 (void)signal(SIGINT, oldintr);
1952 pswitch(1);
1953 ptflag = 0;
1954 fprintf(ttyout, "local: %s remote: %s\n", local, remote);
1955 return;
1956 abort:
1957 (void)signal(SIGINT, SIG_IGN);
1958 ptflag = 0;
1959 if (strcmp(cmd, "RETR") && !proxy)
1960 pswitch(1);
1961 else if (!strcmp(cmd, "RETR") && proxy)
1962 pswitch(0);
1963 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */
1964 if (command("%s %s", cmd2, local) != PRELIM) {
1965 pswitch(0);
1966 if (cpend)
1967 abort_remote(NULL);
1968 }
1969 pswitch(1);
1970 if (ptabflg)
1971 code = -1;
1972 (void)signal(SIGINT, oldintr);
1973 return;
1974 }
1975 if (cpend)
1976 abort_remote(NULL);
1977 pswitch(!proxy);
1978 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */
1979 if (command("%s %s", cmd2, local) != PRELIM) {
1980 pswitch(0);
1981 if (cpend)
1982 abort_remote(NULL);
1983 pswitch(1);
1984 if (ptabflg)
1985 code = -1;
1986 (void)signal(SIGINT, oldintr);
1987 return;
1988 }
1989 }
1990 if (cpend)
1991 abort_remote(NULL);
1992 pswitch(!proxy);
1993 if (cpend) {
1994 if ((nfnd = empty(cin, NULL, 10)) <= 0) {
1995 if (nfnd < 0) {
1996 warn("abort");
1997 }
1998 if (ptabflg)
1999 code = -1;
2000 lostpeer();
2001 }
2002 (void)getreply(0);
2003 (void)getreply(0);
2004 }
2005 if (proxy)
2006 pswitch(0);
2007 pswitch(1);
2008 if (ptabflg)
2009 code = -1;
2010 (void)signal(SIGINT, oldintr);
2011 }
2012
2013 void
2014 reset(argc, argv)
2015 int argc;
2016 char *argv[];
2017 {
2018 int nfnd = 1;
2019
2020 while (nfnd > 0) {
2021 if ((nfnd = empty(cin, NULL, 0)) < 0) {
2022 warn("reset");
2023 code = -1;
2024 lostpeer();
2025 }
2026 else if (nfnd) {
2027 (void)getreply(0);
2028 }
2029 }
2030 }
2031
2032 char *
2033 gunique(local)
2034 const char *local;
2035 {
2036 static char new[MAXPATHLEN];
2037 char *cp = strrchr(local, '/');
2038 int d, count=0;
2039 char ext = '1';
2040
2041 if (cp)
2042 *cp = '\0';
2043 d = access(cp == local ? "/" : cp ? local : ".", W_OK);
2044 if (cp)
2045 *cp = '/';
2046 if (d < 0) {
2047 warn("local: %s", local);
2048 return (NULL);
2049 }
2050 (void)strcpy(new, local);
2051 cp = new + strlen(new);
2052 *cp++ = '.';
2053 while (!d) {
2054 if (++count == 100) {
2055 fputs("runique: can't find unique file name.\n",
2056 ttyout);
2057 return (NULL);
2058 }
2059 *cp++ = ext;
2060 *cp = '\0';
2061 if (ext == '9')
2062 ext = '0';
2063 else
2064 ext++;
2065 if ((d = access(new, F_OK)) < 0)
2066 break;
2067 if (ext != '0')
2068 cp--;
2069 else if (*(cp - 2) == '.')
2070 *(cp - 1) = '1';
2071 else {
2072 *(cp - 2) = *(cp - 2) + 1;
2073 cp--;
2074 }
2075 }
2076 return (new);
2077 }
2078
2079 void
2080 abort_remote(din)
2081 FILE *din;
2082 {
2083 char buf[BUFSIZ];
2084 int nfnd;
2085
2086 if (cout == NULL) {
2087 warnx("Lost control connection for abort.");
2088 if (ptabflg)
2089 code = -1;
2090 lostpeer();
2091 return;
2092 }
2093 /*
2094 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark
2095 * after urgent byte rather than before as is protocol now
2096 */
2097 snprintf(buf, sizeof(buf), "%c%c%c", IAC, IP, IAC);
2098 if (send(fileno(cout), buf, 3, MSG_OOB) != 3)
2099 warn("abort");
2100 fprintf(cout, "%cABOR\r\n", DM);
2101 (void)fflush(cout);
2102 if ((nfnd = empty(cin, din, 10)) <= 0) {
2103 if (nfnd < 0) {
2104 warn("abort");
2105 }
2106 if (ptabflg)
2107 code = -1;
2108 lostpeer();
2109 }
2110 if (din && (nfnd & 2)) {
2111 while (read(fileno(din), buf, BUFSIZ) > 0)
2112 continue;
2113 }
2114 if (getreply(0) == ERROR && code == 552) {
2115 /* 552 needed for nic style abort */
2116 (void)getreply(0);
2117 }
2118 (void)getreply(0);
2119 }
2120