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