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