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