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