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