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