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