1 /* $NetBSD: ftp.c,v 1.98 2000/06/05 09:22:53 lukem 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.98 2000/06/05 09:22:53 lukem 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(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(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(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 1502 /* 1503 * What we've got at this point is a string of comma separated 1504 * one-byte unsigned integer values, separated by commas. 1505 */ 1506 if (strcmp(pasvcmd, "PASV") == 0) { 1507 if (data_addr.su_family != AF_INET) { 1508 fputs( 1509 "Passive mode AF mismatch. Shouldn't happen!\n", ttyout); 1510 error = 1; 1511 goto bad; 1512 } 1513 if (code / 10 == 22 && code != 227) { 1514 fputs("wrong server: return code must be 227\n", 1515 ttyout); 1516 error = 1; 1517 goto bad; 1518 } 1519 error = sscanf(pasv, "%u,%u,%u,%u,%u,%u", 1520 &addr[0], &addr[1], &addr[2], &addr[3], 1521 &port[0], &port[1]); 1522 if (error != 6) { 1523 fputs( 1524 "Passive mode address scan failure. Shouldn't happen!\n", ttyout); 1525 error = 1; 1526 goto bad; 1527 } 1528 error = 0; 1529 memset(&data_addr, 0, sizeof(data_addr)); 1530 data_addr.su_family = AF_INET; 1531 data_addr.su_len = sizeof(struct sockaddr_in); 1532 data_addr.su_sin.sin_addr.s_addr = 1533 htonl(pack4(addr, 0)); 1534 data_addr.su_port = htons(pack2(port, 0)); 1535 } else if (strcmp(pasvcmd, "LPSV") == 0) { 1536 if (code / 10 == 22 && code != 228) { 1537 fputs("wrong server: return code must be 228\n", 1538 ttyout); 1539 error = 1; 1540 goto bad; 1541 } 1542 switch (data_addr.su_family) { 1543 case AF_INET: 1544 error = sscanf(pasv, 1545 "%u,%u,%u,%u,%u,%u,%u,%u,%u", 1546 &af, &hal, 1547 &addr[0], &addr[1], &addr[2], &addr[3], 1548 &pal, &port[0], &port[1]); 1549 if (error != 9) { 1550 fputs( 1551 "Passive mode address scan failure. Shouldn't happen!\n", ttyout); 1552 error = 1; 1553 goto bad; 1554 } 1555 if (af != 4 || hal != 4 || pal != 2) { 1556 fputs( 1557 "Passive mode AF mismatch. Shouldn't happen!\n", ttyout); 1558 error = 1; 1559 goto bad; 1560 } 1561 1562 error = 0; 1563 memset(&data_addr, 0, sizeof(data_addr)); 1564 data_addr.su_family = AF_INET; 1565 data_addr.su_len = sizeof(struct sockaddr_in); 1566 data_addr.su_sin.sin_addr.s_addr = 1567 htonl(pack4(addr, 0)); 1568 data_addr.su_port = htons(pack2(port, 0)); 1569 break; 1570 #ifdef INET6 1571 case AF_INET6: 1572 error = sscanf(pasv, 1573 "%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u,%u", 1574 &af, &hal, 1575 &addr[0], &addr[1], &addr[2], &addr[3], 1576 &addr[4], &addr[5], &addr[6], &addr[7], 1577 &addr[8], &addr[9], &addr[10], 1578 &addr[11], &addr[12], &addr[13], 1579 &addr[14], &addr[15], 1580 &pal, &port[0], &port[1]); 1581 if (error != 21) { 1582 fputs( 1583 "Passive mode address scan failure. Shouldn't happen!\n", ttyout); 1584 error = 1; 1585 goto bad; 1586 } 1587 if (af != 6 || hal != 16 || pal != 2) { 1588 fputs( 1589 "Passive mode AF mismatch. Shouldn't happen!\n", ttyout); 1590 error = 1; 1591 goto bad; 1592 } 1593 1594 error = 0; 1595 memset(&data_addr, 0, sizeof(data_addr)); 1596 data_addr.su_family = AF_INET6; 1597 data_addr.su_len = sizeof(struct sockaddr_in6); 1598 { 1599 u_int32_t *p32; 1600 p32 = (u_int32_t *)&data_addr.su_sin6.sin6_addr; 1601 p32[0] = htonl(pack4(addr, 0)); 1602 p32[1] = htonl(pack4(addr, 4)); 1603 p32[2] = htonl(pack4(addr, 8)); 1604 p32[3] = htonl(pack4(addr, 12)); 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 #define UC(b) (((int)b)&0xff) 1703 1704 if (sendport) { 1705 #ifdef INET6 1706 char hname[INET6_ADDRSTRLEN]; 1707 int af; 1708 #endif 1709 1710 switch (data_addr.su_family) { 1711 case AF_INET: 1712 if (!epsv4 || epsv4bad) { 1713 result = COMPLETE + 1; 1714 break; 1715 } 1716 /* FALLTHROUGH */ 1717 #ifdef INET6 1718 case AF_INET6: 1719 af = (data_addr.su_family == AF_INET) ? 1 : 2; 1720 if (getnameinfo((struct sockaddr *)&data_addr, 1721 data_addr.su_len, hname, sizeof(hname), 1722 NULL, 0, NI_NUMERICHOST)) { 1723 result = ERROR; 1724 } else { 1725 result = command("EPRT |%d|%s|%d|", af, hname, 1726 ntohs(data_addr.su_port)); 1727 if (!connected) 1728 return (1); 1729 if (result != COMPLETE) { 1730 epsv4bad = 1; 1731 if (debug) 1732 fputs( 1733 "disabling epsv4 for this connection\n", 1734 ttyout); 1735 } 1736 } 1737 break; 1738 #endif 1739 default: 1740 result = COMPLETE + 1; 1741 break; 1742 } 1743 if (result == COMPLETE) 1744 goto skip_port; 1745 1746 switch (data_addr.su_family) { 1747 case AF_INET: 1748 a = (char *)&data_addr.su_sin.sin_addr; 1749 p = (char *)&data_addr.su_port; 1750 result = command("PORT %d,%d,%d,%d,%d,%d", 1751 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 1752 UC(p[0]), UC(p[1])); 1753 break; 1754 #ifdef INET6 1755 case AF_INET6: 1756 a = (char *)&data_addr.su_sin6.sin6_addr; 1757 p = (char *)&data_addr.su_port; 1758 result = command( 1759 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", 1760 6, 16, 1761 UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]), 1762 UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]), 1763 UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]), 1764 UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]), 1765 2, UC(p[0]), UC(p[1])); 1766 break; 1767 #endif 1768 default: 1769 result = COMPLETE + 1; /* xxx */ 1770 } 1771 if (!connected) 1772 return (1); 1773 skip_port: 1774 1775 if (result == ERROR && sendport == -1) { 1776 sendport = 0; 1777 tmpno = 1; 1778 goto noport; 1779 } 1780 return (result != COMPLETE); 1781 } 1782 if (tmpno) 1783 sendport = 1; 1784 #ifdef IPTOS_THROUGHPUT 1785 if (data_addr.su_family == AF_INET) { 1786 on = IPTOS_THROUGHPUT; 1787 if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, 1788 sizeof(int)) < 0) 1789 warn("setsockopt TOS (ignored)"); 1790 } 1791 #endif 1792 return (0); 1793 bad: 1794 (void)close(data), data = -1; 1795 if (tmpno) 1796 sendport = 1; 1797 return (1); 1798 } 1799 1800 FILE * 1801 dataconn(const char *lmode) 1802 { 1803 union sockunion from; 1804 int s, fromlen = myctladdr.su_len; 1805 1806 if (passivemode) 1807 return (fdopen(data, lmode)); 1808 1809 s = accept(data, (struct sockaddr *) &from, &fromlen); 1810 if (s < 0) { 1811 warn("accept"); 1812 (void)close(data), data = -1; 1813 return (NULL); 1814 } 1815 (void)close(data); 1816 data = s; 1817 #ifdef IPTOS_THROUGHPUT 1818 if (from.su_family == AF_INET) { 1819 int tos = IPTOS_THROUGHPUT; 1820 if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, 1821 sizeof(int)) < 0) { 1822 warn("setsockopt TOS (ignored)"); 1823 } 1824 } 1825 #endif 1826 return (fdopen(data, lmode)); 1827 } 1828 1829 void 1830 psabort(int notused) 1831 { 1832 int oerrno = errno; 1833 1834 alarmtimer(0); 1835 abrtflag++; 1836 errno = oerrno; 1837 } 1838 1839 void 1840 pswitch(int flag) 1841 { 1842 sigfunc oldintr; 1843 static struct comvars { 1844 int connect; 1845 char name[MAXHOSTNAMELEN]; 1846 union sockunion mctl; 1847 union sockunion hctl; 1848 FILE *in; 1849 FILE *out; 1850 int tpe; 1851 int curtpe; 1852 int cpnd; 1853 int sunqe; 1854 int runqe; 1855 int mcse; 1856 int ntflg; 1857 char nti[17]; 1858 char nto[17]; 1859 int mapflg; 1860 char mi[MAXPATHLEN]; 1861 char mo[MAXPATHLEN]; 1862 } proxstruct, tmpstruct; 1863 struct comvars *ip, *op; 1864 1865 abrtflag = 0; 1866 oldintr = xsignal(SIGINT, psabort); 1867 if (flag) { 1868 if (proxy) 1869 return; 1870 ip = &tmpstruct; 1871 op = &proxstruct; 1872 proxy++; 1873 } else { 1874 if (!proxy) 1875 return; 1876 ip = &proxstruct; 1877 op = &tmpstruct; 1878 proxy = 0; 1879 } 1880 ip->connect = connected; 1881 connected = op->connect; 1882 if (hostname) 1883 (void)strlcpy(ip->name, hostname, sizeof(ip->name)); 1884 else 1885 ip->name[0] = '\0'; 1886 hostname = op->name; 1887 ip->hctl = hisctladdr; 1888 hisctladdr = op->hctl; 1889 ip->mctl = myctladdr; 1890 myctladdr = op->mctl; 1891 ip->in = cin; 1892 cin = op->in; 1893 ip->out = cout; 1894 cout = op->out; 1895 ip->tpe = type; 1896 type = op->tpe; 1897 ip->curtpe = curtype; 1898 curtype = op->curtpe; 1899 ip->cpnd = cpend; 1900 cpend = op->cpnd; 1901 ip->sunqe = sunique; 1902 sunique = op->sunqe; 1903 ip->runqe = runique; 1904 runique = op->runqe; 1905 ip->mcse = mcase; 1906 mcase = op->mcse; 1907 ip->ntflg = ntflag; 1908 ntflag = op->ntflg; 1909 (void)strlcpy(ip->nti, ntin, sizeof(ip->nti)); 1910 (void)strlcpy(ntin, op->nti, sizeof(ntin)); 1911 (void)strlcpy(ip->nto, ntout, sizeof(ip->nto)); 1912 (void)strlcpy(ntout, op->nto, sizeof(ntout)); 1913 ip->mapflg = mapflag; 1914 mapflag = op->mapflg; 1915 (void)strlcpy(ip->mi, mapin, sizeof(ip->mi)); 1916 (void)strlcpy(mapin, op->mi, sizeof(mapin)); 1917 (void)strlcpy(ip->mo, mapout, sizeof(ip->mo)); 1918 (void)strlcpy(mapout, op->mo, sizeof(mapout)); 1919 (void)xsignal(SIGINT, oldintr); 1920 if (abrtflag) { 1921 abrtflag = 0; 1922 (*oldintr)(SIGINT); 1923 } 1924 } 1925 1926 void 1927 abortpt(int notused) 1928 { 1929 1930 alarmtimer(0); 1931 if (fromatty) 1932 write(fileno(ttyout), "\n", 1); 1933 ptabflg++; 1934 mflag = 0; 1935 abrtflag = 0; 1936 siglongjmp(ptabort, 1); 1937 } 1938 1939 void 1940 proxtrans(const char *cmd, const char *local, const char *remote) 1941 { 1942 sigfunc oldintr; 1943 int prox_type, nfnd; 1944 volatile int secndflag; 1945 char *cmd2; 1946 1947 #ifdef __GNUC__ /* to shut up gcc warnings */ 1948 (void)&oldintr; 1949 (void)&cmd2; 1950 #endif 1951 1952 oldintr = NULL; 1953 secndflag = 0; 1954 if (strcmp(cmd, "RETR")) 1955 cmd2 = "RETR"; 1956 else 1957 cmd2 = runique ? "STOU" : "STOR"; 1958 if ((prox_type = type) == 0) { 1959 if (unix_server && unix_proxy) 1960 prox_type = TYPE_I; 1961 else 1962 prox_type = TYPE_A; 1963 } 1964 if (curtype != prox_type) 1965 changetype(prox_type, 1); 1966 if (command("PASV") != COMPLETE) { 1967 fputs("proxy server does not support third party transfers.\n", 1968 ttyout); 1969 return; 1970 } 1971 pswitch(0); 1972 if (!connected) { 1973 fputs("No primary connection.\n", ttyout); 1974 pswitch(1); 1975 code = -1; 1976 return; 1977 } 1978 if (curtype != prox_type) 1979 changetype(prox_type, 1); 1980 if (command("PORT %s", pasv) != COMPLETE) { 1981 pswitch(1); 1982 return; 1983 } 1984 if (sigsetjmp(ptabort, 1)) 1985 goto abort; 1986 oldintr = xsignal(SIGINT, abortpt); 1987 if ((restart_point && 1988 #ifndef NO_QUAD 1989 (command("REST %lld", (long long) restart_point) != CONTINUE) 1990 #else 1991 (command("REST %ld", (long) restart_point) != CONTINUE) 1992 #endif 1993 ) || (command("%s %s", cmd, remote) != PRELIM)) { 1994 (void)xsignal(SIGINT, oldintr); 1995 pswitch(1); 1996 return; 1997 } 1998 sleep(2); 1999 pswitch(1); 2000 secndflag++; 2001 if ((restart_point && 2002 #ifndef NO_QUAD 2003 (command("REST %lld", (long long) restart_point) != CONTINUE) 2004 #else 2005 (command("REST %ld", (long) restart_point) != CONTINUE) 2006 #endif 2007 ) || (command("%s %s", cmd2, local) != PRELIM)) 2008 goto abort; 2009 ptflag++; 2010 (void)getreply(0); 2011 pswitch(0); 2012 (void)getreply(0); 2013 (void)xsignal(SIGINT, oldintr); 2014 pswitch(1); 2015 ptflag = 0; 2016 fprintf(ttyout, "local: %s remote: %s\n", local, remote); 2017 return; 2018 abort: 2019 if (sigsetjmp(xferabort, 1)) { 2020 (void)xsignal(SIGINT, oldintr); 2021 return; 2022 } 2023 (void)xsignal(SIGINT, abort_squared); 2024 ptflag = 0; 2025 if (strcmp(cmd, "RETR") && !proxy) 2026 pswitch(1); 2027 else if (!strcmp(cmd, "RETR") && proxy) 2028 pswitch(0); 2029 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ 2030 if (command("%s %s", cmd2, local) != PRELIM) { 2031 pswitch(0); 2032 if (cpend) 2033 abort_remote(NULL); 2034 } 2035 pswitch(1); 2036 if (ptabflg) 2037 code = -1; 2038 (void)xsignal(SIGINT, oldintr); 2039 return; 2040 } 2041 if (cpend) 2042 abort_remote(NULL); 2043 pswitch(!proxy); 2044 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ 2045 if (command("%s %s", cmd2, local) != PRELIM) { 2046 pswitch(0); 2047 if (cpend) 2048 abort_remote(NULL); 2049 pswitch(1); 2050 if (ptabflg) 2051 code = -1; 2052 (void)xsignal(SIGINT, oldintr); 2053 return; 2054 } 2055 } 2056 if (cpend) 2057 abort_remote(NULL); 2058 pswitch(!proxy); 2059 if (cpend) { 2060 if ((nfnd = empty(cin, NULL, 10)) <= 0) { 2061 if (nfnd < 0) 2062 warn("abort"); 2063 if (ptabflg) 2064 code = -1; 2065 lostpeer(0); 2066 } 2067 (void)getreply(0); 2068 (void)getreply(0); 2069 } 2070 if (proxy) 2071 pswitch(0); 2072 pswitch(1); 2073 if (ptabflg) 2074 code = -1; 2075 (void)xsignal(SIGINT, oldintr); 2076 } 2077 2078 void 2079 reset(int argc, char *argv[]) 2080 { 2081 int nfnd = 1; 2082 2083 if (argc == 0 && argv != NULL) { 2084 fprintf(ttyout, "usage: %s\n", argv[0]); 2085 code = -1; 2086 return; 2087 } 2088 while (nfnd > 0) { 2089 if ((nfnd = empty(cin, NULL, 0)) < 0) { 2090 warn("reset"); 2091 code = -1; 2092 lostpeer(0); 2093 } else if (nfnd) 2094 (void)getreply(0); 2095 } 2096 } 2097 2098 char * 2099 gunique(const char *local) 2100 { 2101 static char new[MAXPATHLEN]; 2102 char *cp = strrchr(local, '/'); 2103 int d, count=0, len; 2104 char ext = '1'; 2105 2106 if (cp) 2107 *cp = '\0'; 2108 d = access(cp == local ? "/" : cp ? local : ".", W_OK); 2109 if (cp) 2110 *cp = '/'; 2111 if (d < 0) { 2112 warn("local: %s", local); 2113 return (NULL); 2114 } 2115 len = strlcpy(new, local, sizeof(new)); 2116 cp = &new[len]; 2117 *cp++ = '.'; 2118 while (!d) { 2119 if (++count == 100) { 2120 fputs("runique: can't find unique file name.\n", 2121 ttyout); 2122 return (NULL); 2123 } 2124 *cp++ = ext; 2125 *cp = '\0'; 2126 if (ext == '9') 2127 ext = '0'; 2128 else 2129 ext++; 2130 if ((d = access(new, F_OK)) < 0) 2131 break; 2132 if (ext != '0') 2133 cp--; 2134 else if (*(cp - 2) == '.') 2135 *(cp - 1) = '1'; 2136 else { 2137 *(cp - 2) = *(cp - 2) + 1; 2138 cp--; 2139 } 2140 } 2141 return (new); 2142 } 2143 2144 /* 2145 * abort_squared -- 2146 * aborts abort_remote(). lostpeer() is called because if the user is 2147 * too impatient to wait or there's another problem then ftp really 2148 * needs to get back to a known state. 2149 */ 2150 void 2151 abort_squared(int dummy) 2152 { 2153 char msgbuf[100]; 2154 int len; 2155 2156 alarmtimer(0); 2157 len = strlcpy(msgbuf, "\nremote abort aborted; closing connection.\n", 2158 sizeof(msgbuf)); 2159 write(fileno(ttyout), msgbuf, len); 2160 lostpeer(0); 2161 siglongjmp(xferabort, 1); 2162 } 2163 2164 void 2165 abort_remote(FILE *din) 2166 { 2167 char buf[BUFSIZ]; 2168 int nfnd; 2169 2170 if (cout == NULL) { 2171 warnx("Lost control connection for abort."); 2172 if (ptabflg) 2173 code = -1; 2174 lostpeer(0); 2175 return; 2176 } 2177 /* 2178 * send IAC in urgent mode instead of DM because 4.3BSD places oob mark 2179 * after urgent byte rather than before as is protocol now 2180 */ 2181 buf[0] = IAC; 2182 buf[1] = IP; 2183 buf[2] = IAC; 2184 if (send(fileno(cout), buf, 3, MSG_OOB) != 3) 2185 warn("abort"); 2186 fprintf(cout, "%cABOR\r\n", DM); 2187 (void)fflush(cout); 2188 if ((nfnd = empty(cin, din, 10)) <= 0) { 2189 if (nfnd < 0) 2190 warn("abort"); 2191 if (ptabflg) 2192 code = -1; 2193 lostpeer(0); 2194 } 2195 if (din && (nfnd & 2)) { 2196 while (read(fileno(din), buf, BUFSIZ) > 0) 2197 continue; 2198 } 2199 if (getreply(0) == ERROR && code == 552) { 2200 /* 552 needed for nic style abort */ 2201 (void)getreply(0); 2202 } 2203 (void)getreply(0); 2204 } 2205 2206 void 2207 ai_unmapped(struct addrinfo *ai) 2208 { 2209 #ifdef INET6 2210 struct sockaddr_in6 *sin6; 2211 struct sockaddr_in sin; 2212 2213 if (ai->ai_family != AF_INET6) 2214 return; 2215 if (ai->ai_addrlen != sizeof(struct sockaddr_in6) || 2216 sizeof(sin) > ai->ai_addrlen) 2217 return; 2218 sin6 = (struct sockaddr_in6 *)ai->ai_addr; 2219 if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) 2220 return; 2221 2222 memset(&sin, 0, sizeof(sin)); 2223 sin.sin_family = AF_INET; 2224 sin.sin_len = sizeof(struct sockaddr_in); 2225 memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12], 2226 sizeof(sin.sin_addr)); 2227 sin.sin_port = sin6->sin6_port; 2228 2229 ai->ai_family = AF_INET; 2230 memcpy(ai->ai_addr, &sin, sin.sin_len); 2231 ai->ai_addrlen = sin.sin_len; 2232 #endif 2233 } 2234