1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #include "ftp_var.h" 41 #include <arpa/nameser.h> 42 #include <sys/types.h> 43 44 /* 45 * WRITE() returns: 46 * >0 no error 47 * -1 error, errorno is set 48 * -2 security error (secure_write() only) 49 */ 50 #define PUTC(x, y) secure_putc(x, y) 51 #define READ(x, y, z) secure_read(x, y, z) 52 #define WRITE(x, y, z) secure_write(x, y, z) 53 54 static struct sockaddr_in6 data_addr; 55 int data = -1; 56 static int abrtflag = 0; 57 static int ptflag = 0; 58 static jmp_buf sendabort; 59 static jmp_buf recvabort; 60 static jmp_buf ptabort; 61 static int ptabflg; 62 static boolean_t pasv_refused; 63 boolean_t eport_supported = B_TRUE; 64 /* 65 * For IPv6 addresses, EPSV will be the default (rather than EPRT/LPRT). 66 * The EPSV/ERPT ftp protocols are specified in RFC 2428. 67 * 68 * Perform EPSV if passivemode is set and ipv6rem is TRUE. 69 */ 70 static boolean_t ipv6rem; 71 int use_eprt = 0; /* Testing option that specifies EPRT by default */ 72 FILE *ctrl_in, *ctrl_out; 73 74 static void abortsend(int sig); 75 static void abortpt(int sig); 76 static void proxtrans(char *cmd, char *local, char *remote); 77 static void cmdabort(int sig); 78 static int empty(struct fd_set *mask, int sec, int nfds); 79 static void abortrecv(int sig); 80 static int initconn(void); 81 static FILE *dataconn(char *mode); 82 static void ptransfer(char *direction, off_t bytes, hrtime_t t0, 83 hrtime_t t1, char *local, char *remote); 84 static void psabort(int sig); 85 static char *gunique(char *local); 86 static const char *inet_ntop_native(int af, const void *src, char *dst, 87 size_t size); 88 static ssize_t timedread(int fd, void *buf, size_t maxlen, int timeout); 89 90 static int secure_command(char *); 91 static int decode_reply(uchar_t *, int, uchar_t *, int, boolean_t *); 92 93 static ssize_t bufcnt; /* number of bytes in buf[] */ 94 static char *bufp; /* next character in buf */ 95 static int buferr; /* last errno */ 96 static size_t bufsize; 97 98 static void fdio_setbuf(char *buffer, size_t bufsize); 99 static int fdio_fillbuf(int fd); 100 static int fdio_error(int fd); 101 #define fdio_getc(fd) (--bufcnt < 0 ? fdio_fillbuf((fd)) : \ 102 ((unsigned char)*bufp++)) 103 104 #define MAX(a, b) ((a) > (b) ? (a) : (b)) 105 #define NONZERO(x) ((x) == 0 ? 1 : (x)) 106 107 static void 108 fdio_setbuf(char *buffer, size_t maxsize) 109 { 110 buf = buffer; 111 bufp = buf; 112 bufcnt = 0; 113 buferr = 0; 114 bufsize = maxsize; 115 } 116 117 static int 118 fdio_fillbuf(int fd) 119 { 120 bufcnt = timedread(fd, buf, bufsize, timeout); 121 if (bufcnt < 0) 122 buferr = errno; 123 if (bufcnt <= 0) 124 return (EOF); 125 bufp = buf; 126 bufcnt--; 127 return ((unsigned char)*bufp++); 128 } 129 130 /* 131 * fdio_error - used on a file descriptor instead of ferror() 132 */ 133 134 /*ARGSUSED*/ 135 static int 136 fdio_error(int fd) 137 { 138 return (buferr); 139 } 140 141 /* 142 * timedread - read buffer (like "read"), but with timeout (in seconds) 143 */ 144 145 static ssize_t 146 timedread(int fd, void *buf, size_t size, int timeout) 147 { 148 struct fd_set mask; 149 struct timeval tv; 150 int err; 151 152 if (!timeout) 153 return (READ(fd, buf, size)); 154 155 tv.tv_sec = (time_t)timeout; 156 tv.tv_usec = 0; 157 158 FD_ZERO(&mask); 159 FD_SET(fd, &mask); 160 161 err = select(fd + 1, &mask, NULL, NULL, &tv); 162 if (err == 0) 163 errno = ETIMEDOUT; 164 if (err <= 0) 165 return (-1); 166 167 return (READ(fd, buf, size)); 168 } 169 170 171 char * 172 hookup(char *host, char *service) 173 { 174 struct addrinfo hints, *ai = NULL, *ai_head; 175 int s; 176 socklen_t len; 177 static char hostnamebuf[80]; 178 struct in6_addr ipv6addr; 179 char abuf[INET6_ADDRSTRLEN]; 180 int error_num; 181 int on = 1; 182 183 /* 184 * There appears to be a bug in getaddrinfo() where, if the 185 * ai_family is set to AF_INET6, and the host is a v4-only 186 * host, getaddrinfo() returns an error instead of returning 187 * an v4-mapped ipv6 address. Therefore the ai_family is 188 * set to AF_UNSPEC and any returned v4 addresses are 189 * explicitly mapped within ftp. 190 */ 191 bzero((char *)&remctladdr, sizeof (remctladdr)); 192 bzero((char *)&hints, sizeof (hints)); 193 hints.ai_flags = AI_CANONNAME; 194 hints.ai_family = AF_UNSPEC; 195 hints.ai_socktype = SOCK_STREAM; 196 197 error_num = getaddrinfo(host, service, &hints, &ai); 198 if (error_num != 0) { 199 if (error_num == EAI_AGAIN) { 200 (void) printf( 201 "%s: unknown host or invalid literal address " 202 "(try again later)\n", host); 203 } else { 204 (void) printf( 205 "%s: unknown host or invalid literal address\n", 206 host); 207 } 208 code = -1; 209 return ((char *)0); 210 } 211 ai_head = ai; 212 213 214 /* 215 * If ai_canonname is a IPv4-mapped IPv6 literal, we'll convert it to 216 * IPv4 literal address. 217 */ 218 if (ai->ai_canonname != NULL && 219 (inet_pton(AF_INET6, ai->ai_canonname, &ipv6addr) > 0) && 220 IN6_IS_ADDR_V4MAPPED(&ipv6addr)) { 221 struct in_addr src4; 222 hostnamebuf[0] = '\0'; 223 IN6_V4MAPPED_TO_INADDR(&ipv6addr, &src4); 224 (void) inet_ntop(AF_INET, &src4, hostnamebuf, 225 sizeof (hostnamebuf)); 226 227 /* 228 * It can even be the case that the "host" supplied by the user 229 * can be a IPv4-mapped IPv6 literal. So, let's fix that too. 230 */ 231 if ((inet_pton(AF_INET6, host, &ipv6addr) > 0) && 232 IN6_IS_ADDR_V4MAPPED(&ipv6addr) && 233 strlen(hostnamebuf) <= strlen(host)) { 234 (void) strlcpy(host, hostnamebuf, strlen(host) + 1); 235 } 236 } else { 237 reset_timer(); 238 (void) strlcpy(hostnamebuf, 239 (ai->ai_canonname ? ai->ai_canonname : host), 240 sizeof (hostnamebuf)); 241 } 242 243 hostname = hostnamebuf; 244 for (;;) { 245 int oerrno; 246 247 bcopy(ai->ai_addr, &remctladdr, ai->ai_addrlen); 248 if (ai->ai_addr->sa_family == AF_INET) { 249 IN6_INADDR_TO_V4MAPPED( 250 &(((struct sockaddr_in *)ai->ai_addr)->sin_addr), 251 &remctladdr.sin6_addr); 252 remctladdr.sin6_family = AF_INET6; 253 } 254 255 s = socket(AF_INET6, SOCK_STREAM, 0); 256 if (s < 0) { 257 perror("ftp: socket"); 258 code = -1; 259 freeaddrinfo(ai_head); 260 return (0); 261 } 262 if (timeout && setsockopt(s, IPPROTO_TCP, TCP_ABORT_THRESHOLD, 263 (char *)&timeoutms, sizeof (timeoutms)) < 0 && debug) 264 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)"); 265 reset_timer(); 266 267 error_num = connect(s, (struct sockaddr *)&remctladdr, 268 sizeof (remctladdr)); 269 oerrno = errno; 270 if (error_num >= 0) 271 break; 272 273 /* 274 * Maintain message behavior: only include the address in 275 * our error message if we have another one to try; if this 276 * is the last address on our list, just print the error. 277 */ 278 if (ai->ai_next != NULL) { 279 (void) fprintf(stderr, "ftp: connect to address %s: ", 280 inet_ntop_native(ai->ai_addr->sa_family, 281 (void *)ai->ai_addr, abuf, sizeof (abuf))); 282 errno = oerrno; 283 perror((char *)0); 284 } else { 285 perror("ftp: connect"); 286 code = -1; 287 freeaddrinfo(ai_head); 288 goto bad; 289 } 290 ai = ai->ai_next; 291 (void) fprintf(stdout, "Trying %s...\n", 292 inet_ntop_native(ai->ai_addr->sa_family, 293 (void *)ai->ai_addr, abuf, sizeof (abuf))); 294 (void) close(s); 295 296 } 297 298 /* Set ipv6rem to TRUE if control connection is a native IPv6 address */ 299 if (IN6_IS_ADDR_V4MAPPED(&remctladdr.sin6_addr)) 300 ipv6rem = B_FALSE; 301 else 302 ipv6rem = B_TRUE; 303 304 305 freeaddrinfo(ai_head); 306 ai = NULL; 307 308 /* 309 * Set passive mode flag on by default only if a native IPv6 address 310 * is being used -and- the use_eprt is not set. 311 */ 312 if (ipv6rem == B_TRUE && use_eprt == 0) 313 passivemode = 1; 314 315 len = sizeof (myctladdr); 316 if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) { 317 perror("ftp: getsockname"); 318 code = -1; 319 goto bad; 320 } 321 ctrl_in = fdopen(s, "r"); 322 ctrl_out = fdopen(s, "w"); 323 if (ctrl_in == NULL || ctrl_out == NULL) { 324 (void) fprintf(stderr, "ftp: fdopen failed.\n"); 325 if (ctrl_in) 326 (void) fclose(ctrl_in); 327 if (ctrl_out) 328 (void) fclose(ctrl_out); 329 code = -1; 330 goto bad; 331 } 332 if (verbose) 333 (void) printf("Connected to %s.\n", hostname); 334 if (getreply(0) > 2) { /* read startup message from server */ 335 if (ctrl_in) 336 (void) fclose(ctrl_in); 337 if (ctrl_out) 338 (void) fclose(ctrl_out); 339 ctrl_in = ctrl_out = NULL; 340 ctrl_in = ctrl_out = NULL; 341 code = -1; 342 goto bad; 343 } 344 if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char *)&on, 345 sizeof (on)) < 0 && debug) 346 perror("ftp: setsockopt (SO_OOBINLINE)"); 347 348 return (hostname); 349 bad: 350 (void) close(s); 351 return ((char *)0); 352 } 353 354 int 355 login(char *host) 356 { 357 char tmp[80]; 358 char *user, *pass, *acct; 359 int n, aflag = 0; 360 361 user = pass = acct = 0; 362 if (ruserpass(host, &user, &pass, &acct) < 0) { 363 disconnect(0, NULL); 364 code = -1; 365 return (0); 366 } 367 if (user == NULL) { 368 char *myname = getlogin(); 369 370 if (myname == NULL) { 371 struct passwd *pp = getpwuid(getuid()); 372 373 if (pp != NULL) 374 myname = pp->pw_name; 375 } 376 stop_timer(); 377 (void) printf("Name (%s:%s): ", host, 378 (myname == NULL) ? "" : myname); 379 *tmp = '\0'; 380 if (fgets(tmp, sizeof (tmp) - 1, stdin) != NULL) 381 tmp[strlen(tmp) - 1] = '\0'; 382 if (*tmp != '\0') 383 user = tmp; 384 else if (myname != NULL) 385 user = myname; 386 else 387 return (0); 388 } 389 n = command("USER %s", user); 390 if (n == CONTINUE) { 391 int oldclevel; 392 if (pass == NULL) 393 pass = mygetpass("Password:"); 394 oldclevel = clevel; 395 clevel = PROT_P; 396 n = command("PASS %s", pass); 397 /* level may have changed */ 398 if (clevel == PROT_P) 399 clevel = oldclevel; 400 } 401 if (n == CONTINUE) { 402 aflag++; 403 if (acct == NULL) 404 acct = mygetpass("Account:"); 405 n = command("ACCT %s", acct); 406 } 407 if (n != COMPLETE) { 408 (void) fprintf(stderr, "Login failed.\n"); 409 return (0); 410 } 411 if (!aflag && acct != NULL) 412 (void) command("ACCT %s", acct); 413 if (proxy) 414 return (1); 415 for (n = 0; n < macnum; ++n) { 416 if (strcmp("init", macros[n].mac_name) == 0) { 417 (void) strlcpy(line, "$init", sizeof (line)); 418 makeargv(); 419 domacro(margc, margv); 420 break; 421 } 422 } 423 return (1); 424 } 425 426 /*ARGSUSED*/ 427 static void 428 cmdabort(int sig) 429 { 430 (void) printf("\n"); 431 (void) fflush(stdout); 432 abrtflag++; 433 if (ptflag) 434 longjmp(ptabort, 1); 435 } 436 437 int 438 command(char *fmt, ...) 439 { 440 int r; 441 void (*oldintr)(); 442 va_list ap; 443 char command_buf[FTPBUFSIZ]; 444 445 va_start(ap, fmt); 446 abrtflag = 0; 447 if (debug) { 448 (void) printf("---> "); 449 if (strncmp("PASS ", fmt, 5) == 0) 450 (void) printf("PASS XXXX"); 451 else if (strncmp("ACCT ", fmt, 5) == 0) 452 (void) printf("ACCT XXXX"); 453 else 454 (void) vfprintf(stdout, fmt, ap); 455 (void) printf("\n"); 456 (void) fflush(stdout); 457 } 458 if (ctrl_out == NULL) { 459 perror("No control connection for command"); 460 code = -1; 461 return (0); 462 } 463 oldintr = signal(SIGINT, cmdabort); 464 (void) vsnprintf(command_buf, FTPBUFSIZ, fmt, ap); 465 va_end(ap); 466 467 again: if (secure_command(command_buf) == 0) 468 return (0); 469 470 cpend = 1; 471 r = getreply(strcmp(fmt, "QUIT") == 0); 472 473 if (r == 533 && clevel == PROT_P) { 474 (void) fprintf(stderr, "ENC command not supported at server; " 475 "retrying under MIC...\n"); 476 clevel = PROT_S; 477 goto again; 478 } 479 480 if (abrtflag && oldintr != SIG_IGN) 481 (*oldintr)(); 482 (void) signal(SIGINT, oldintr); 483 return (r); 484 } 485 486 /* Need to save reply reponse from server for use in EPSV mode */ 487 char reply_string[BUFSIZ]; 488 489 int 490 getreply(int expecteof) 491 { 492 /* 493 * 'code' is the 3 digit reply code, form xyz 494 * 'dig' counts the number of digits we are along in the code 495 * 'n' is the first digit of 'code' 496 * 4yz: resource unavailable 497 * 5yz: an error occurred, failure 498 * 6yz: protected reply (is_base64 == TRUE) 499 * 631 - base 64 encoded safe message 500 * 632 - base 64 encoded private message 501 * 633 - base 64 encoded confidential message 502 * 'c' is a wide char type, for international char sets 503 */ 504 wint_t c; 505 int i, n; 506 int dig; 507 int originalcode = 0, continuation = 0; 508 void (*oldintr)(); 509 int pflag = 0; 510 char *pt = pasv; 511 /* 512 * this is the input and output buffers needed for 513 * radix_encode() 514 */ 515 unsigned char ibuf[FTPBUFSIZ]; 516 unsigned char obuf[FTPBUFSIZ]; 517 boolean_t is_base64; 518 int len; 519 char *cp; 520 521 if (!ctrl_in) 522 return (0); 523 oldintr = signal(SIGINT, cmdabort); 524 525 ibuf[0] = '\0'; 526 527 if (reply_parse) 528 reply_ptr = reply_buf; 529 530 for (;;) { 531 obuf[0] = '\0'; 532 dig = n = code = 0; 533 i = is_base64 = 0; 534 cp = reply_string; 535 reset_timer(); /* once per line */ 536 537 while ((c = ibuf[0] ? 538 (wint_t)ibuf[i++] : fgetwc(ctrl_in)) != '\n') { 539 540 if (i >= FTPBUFSIZ) 541 break; 542 543 if (c == IAC) { /* handle telnet commands */ 544 switch (c = fgetwc(ctrl_in)) { 545 case WILL: 546 case WONT: 547 c = fgetwc(ctrl_in); 548 (void) fprintf(ctrl_out, "%c%c%wc", IAC, 549 WONT, c); 550 (void) fflush(ctrl_out); 551 break; 552 case DO: 553 case DONT: 554 c = fgetwc(ctrl_in); 555 (void) fprintf(ctrl_out, "%c%c%wc", IAC, 556 DONT, c); 557 (void) fflush(ctrl_out); 558 break; 559 default: 560 break; 561 } 562 continue; 563 } 564 dig++; 565 if (c == EOF) { 566 if (expecteof) { 567 (void) signal(SIGINT, oldintr); 568 code = 221; 569 return (0); 570 } 571 lostpeer(0); 572 if (verbose) { 573 (void) printf( 574 "421 Service not available, remote" 575 " server has closed connection\n"); 576 } else { 577 (void) printf("Lost connection\n"); 578 } 579 (void) fflush(stdout); 580 code = 421; 581 return (4); 582 } 583 if (n == 0) 584 n = c; 585 586 if (n == '6') 587 is_base64 = 1; 588 589 if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] && 590 (is_base64 || continuation)) { 591 /* start storing chars in obuf */ 592 if (c != '\r' && dig > 4) 593 obuf[i++] = (char)c; 594 } else { 595 if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] && 596 dig == 1 && verbose) 597 (void) printf("Unauthenticated reply " 598 "received from server:\n"); 599 if (reply_parse) 600 *reply_ptr++ = (char)c; 601 if (c != '\r' && (verbose > 0 || 602 (verbose > -1 && n == '5' && dig > 4))) { 603 if (proxflag && 604 (dig == 1 || dig == 5 && 605 verbose == 0)) 606 (void) printf("%s:", hostname); 607 (void) putwchar(c); 608 } 609 } /* endif auth_type && !ibuf[0] ... */ 610 611 if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] && 612 !is_base64) 613 continue; 614 615 /* we are still extracting the 3 digit code */ 616 if (dig < 4 && isascii(c) && isdigit(c)) 617 code = code * 10 + (c - '0'); 618 619 /* starting passive mode */ 620 if (!pflag && code == 227) 621 pflag = 1; 622 623 /* start to store characters, when dig > 4 */ 624 if (dig > 4 && pflag == 1 && isascii(c) && isdigit(c)) 625 pflag = 2; 626 if (pflag == 2) { 627 if (c != '\r' && c != ')') { 628 /* 629 * the mb array is to deal with 630 * the wchar_t 631 */ 632 char mb[MB_LEN_MAX]; 633 int avail; 634 635 /* 636 * space available in pasv[], accounting 637 * for trailing NULL 638 */ 639 avail = &pasv[sizeof (pasv)] - pt - 1; 640 641 len = wctomb(mb, c); 642 if (len <= 0 && avail > 0) { 643 *pt++ = (unsigned char)c; 644 } else if (len > 0 && avail >= len) { 645 bcopy(mb, pt, (size_t)len); 646 pt += len; 647 } else { 648 /* 649 * no room in pasv[]; 650 * close connection 651 */ 652 (void) printf("\nReply too long" 653 " - closing connection\n"); 654 lostpeer(0); 655 (void) fflush(stdout); 656 (void) signal(SIGINT, oldintr); 657 return (4); 658 } 659 } else { 660 *pt = '\0'; 661 pflag = 3; 662 } 663 } /* endif pflag == 2 */ 664 if (dig == 4 && c == '-' && !is_base64) { 665 if (continuation) 666 code = 0; 667 continuation++; 668 } 669 if (cp < &reply_string[sizeof (reply_string) - 1]) 670 *cp++ = c; 671 672 } /* end while */ 673 674 if ((auth_type != AUTHTYPE_NONE) && !ibuf[0] && !is_base64) 675 return (getreply(expecteof)); 676 677 ibuf[0] = obuf[i] = '\0'; 678 679 if (code && is_base64) { 680 boolean_t again = 0; 681 n = decode_reply(ibuf, sizeof (ibuf), obuf, n, &again); 682 if (again) 683 continue; 684 } else { 685 if (verbose > 0 || verbose > -1 && n == '5') { 686 (void) putwchar(c); 687 (void) fflush(stdout); 688 } 689 } 690 691 if (continuation && code != originalcode) { 692 ibuf[0] = obuf[i] = '\0'; 693 if (originalcode == 0) 694 originalcode = code; 695 continue; 696 } 697 *cp = '\0'; 698 if (n != '1') 699 cpend = 0; 700 (void) signal(SIGINT, oldintr); 701 if (code == 421 || originalcode == 421) 702 lostpeer(0); 703 if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) 704 (*oldintr)(); 705 706 if (reply_parse) { 707 *reply_ptr = '\0'; 708 if (reply_ptr = strstr(reply_buf, reply_parse)) { 709 reply_parse = reply_ptr + strlen(reply_parse); 710 if (reply_ptr = strpbrk(reply_parse, " \r")) 711 *reply_ptr = '\0'; 712 } else { 713 reply_parse = reply_ptr; 714 } 715 } 716 717 return (n - '0'); 718 } /* end for */ 719 } 720 721 static int 722 empty(struct fd_set *mask, int sec, int nfds) 723 { 724 struct timeval t; 725 726 reset_timer(); 727 t.tv_sec = (time_t)sec; 728 t.tv_usec = 0; 729 return (select(nfds, mask, NULL, NULL, &t)); 730 } 731 732 /*ARGSUSED*/ 733 static void 734 abortsend(int sig) 735 { 736 mflag = 0; 737 abrtflag = 0; 738 (void) printf("\nsend aborted\n"); 739 (void) fflush(stdout); 740 longjmp(sendabort, 1); 741 } 742 743 void 744 sendrequest(char *cmd, char *local, char *remote, int allowpipe) 745 { 746 FILE *fin, *dout = 0; 747 int (*closefunc)(); 748 void (*oldintr)(), (*oldintp)(); 749 off_t bytes = 0, hashbytes = HASHSIZ; 750 int c; 751 /* 752 * d >= 0 if there is no error 753 * -1 if there was a normal file i/o error 754 * -2 if there was a security error 755 */ 756 int d; 757 struct stat st; 758 hrtime_t start, stop; 759 char *dmode; 760 761 if (proxy) { 762 proxtrans(cmd, local, remote); 763 return; 764 } 765 closefunc = NULL; 766 oldintr = NULL; 767 oldintp = NULL; 768 dmode = "w"; 769 if (setjmp(sendabort)) { 770 while (cpend) { 771 (void) getreply(0); 772 } 773 if (data >= 0) { 774 (void) close(data); 775 data = -1; 776 } 777 if (oldintr) 778 (void) signal(SIGINT, oldintr); 779 if (oldintp) 780 (void) signal(SIGPIPE, oldintp); 781 code = -1; 782 restart_point = 0; 783 return; 784 } 785 oldintr = signal(SIGINT, abortsend); 786 if (strcmp(local, "-") == 0) 787 fin = stdin; 788 else if (allowpipe && *local == '|') { 789 oldintp = signal(SIGPIPE, SIG_IGN); 790 fin = mypopen(local + 1, "r"); 791 if (fin == NULL) { 792 perror(local + 1); 793 (void) signal(SIGINT, oldintr); 794 (void) signal(SIGPIPE, oldintp); 795 code = -1; 796 restart_point = 0; 797 return; 798 } 799 closefunc = mypclose; 800 } else { 801 fin = fopen(local, "r"); 802 if (fin == NULL) { 803 perror(local); 804 (void) signal(SIGINT, oldintr); 805 code = -1; 806 restart_point = 0; 807 return; 808 } 809 closefunc = fclose; 810 if (fstat(fileno(fin), &st) < 0 || 811 (st.st_mode&S_IFMT) != S_IFREG) { 812 (void) fprintf(stdout, 813 "%s: not a plain file.\n", local); 814 (void) signal(SIGINT, oldintr); 815 code = -1; 816 (void) fclose(fin); 817 restart_point = 0; 818 return; 819 } 820 } 821 if (initconn()) { 822 (void) signal(SIGINT, oldintr); 823 if (oldintp) 824 (void) signal(SIGPIPE, oldintp); 825 code = -1; 826 if (closefunc != NULL) 827 (*closefunc)(fin); 828 restart_point = 0; 829 return; 830 } 831 if (setjmp(sendabort)) 832 goto abort; 833 if ((restart_point > 0) && 834 (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { 835 if (fseeko(fin, restart_point, SEEK_SET) < 0) { 836 perror(local); 837 if (closefunc != NULL) 838 (*closefunc)(fin); 839 restart_point = 0; 840 return; 841 } 842 if (command("REST %lld", (longlong_t)restart_point) 843 != CONTINUE) { 844 if (closefunc != NULL) 845 (*closefunc)(fin); 846 restart_point = 0; 847 return; 848 } 849 dmode = "r+w"; 850 } 851 restart_point = 0; 852 if (remote) { 853 if (command("%s %s", cmd, remote) != PRELIM) { 854 (void) signal(SIGINT, oldintr); 855 if (oldintp) 856 (void) signal(SIGPIPE, oldintp); 857 if (closefunc != NULL) 858 (*closefunc)(fin); 859 if (data >= 0) { 860 (void) close(data); 861 data = -1; 862 } 863 return; 864 } 865 } else 866 if (command("%s", cmd) != PRELIM) { 867 (void) signal(SIGINT, oldintr); 868 if (oldintp) 869 (void) signal(SIGPIPE, oldintp); 870 if (closefunc != NULL) 871 (*closefunc)(fin); 872 if (data >= 0) { 873 (void) close(data); 874 data = -1; 875 } 876 return; 877 } 878 dout = dataconn(dmode); 879 if (dout == NULL) 880 goto abort; 881 stop_timer(); 882 oldintp = signal(SIGPIPE, SIG_IGN); 883 start = gethrtime(); 884 switch (type) { 885 886 case TYPE_I: 887 case TYPE_L: 888 errno = d = 0; 889 while ((c = read(fileno(fin), buf, FTPBUFSIZ)) > 0) { 890 if ((d = WRITE(fileno(dout), buf, c)) < 0) 891 break; 892 bytes += c; 893 if (hash) { 894 while (bytes >= hashbytes) { 895 (void) putchar('#'); 896 hashbytes += HASHSIZ; 897 } 898 (void) fflush(stdout); 899 } 900 } 901 if (hash && bytes > 0) { 902 if (bytes < hashbytes) 903 (void) putchar('#'); 904 (void) putchar('\n'); 905 (void) fflush(stdout); 906 } 907 if (c < 0) 908 perror(local); 909 910 if (d >= 0) 911 d = secure_flush(fileno(dout)); 912 913 if (d < 0) { 914 if ((d == -1) && (errno != EPIPE)) 915 perror("netout"); 916 bytes = -1; 917 } 918 break; 919 920 case TYPE_A: 921 while ((c = getc(fin)) != EOF) { 922 if (c == '\n') { 923 while (hash && (bytes >= hashbytes)) { 924 (void) putchar('#'); 925 (void) fflush(stdout); 926 hashbytes += HASHSIZ; 927 } 928 if (ferror(dout) || PUTC('\r', dout) < 0) 929 break; 930 bytes++; 931 } 932 933 if (PUTC(c, dout) < 0) 934 break; 935 bytes++; 936 #ifdef notdef 937 if (c == '\r') { 938 /* this violates rfc */ 939 (void) PUTC('\0', dout); 940 bytes++; 941 } 942 #endif 943 } 944 if (hash && bytes > 0) { 945 if (bytes < hashbytes) 946 (void) putchar('#'); 947 (void) putchar('\n'); 948 (void) fflush(stdout); 949 } 950 if (ferror(fin)) 951 perror(local); 952 953 d = ferror(dout) ? -1 : 0; 954 if (d == 0) 955 d = secure_flush(fileno(dout)); 956 957 if (d < 0) { 958 if ((d == -1) && (errno != EPIPE)) 959 perror("netout"); 960 bytes = -1; 961 } 962 break; 963 } 964 reset_timer(); 965 if (closefunc != NULL) 966 (*closefunc)(fin); 967 if (ctrl_in != NULL) { 968 int dfn = fileno(dout); 969 int nfds = fileno(ctrl_in); 970 fd_set mask; 971 972 /* 973 * There could be data not yet written to dout, 974 * in the stdio buffer; so, before a shutdown() 975 * on further sends, do fflush(dout) 976 */ 977 (void) fflush(dout); 978 979 /* sending over; shutdown sending on dfn */ 980 (void) shutdown(dfn, SHUT_WR); 981 FD_ZERO(&mask); 982 FD_SET(dfn, &mask); 983 FD_SET(nfds, &mask); 984 nfds = MAX(dfn, nfds); 985 986 /* 987 * Wait for remote end to either close data socket 988 * or ack that we've closed our end; it doesn't 989 * matter which happens first. 990 */ 991 (void) select(nfds + 1, &mask, NULL, NULL, NULL); 992 } 993 (void) fclose(dout); data = -1; 994 stop = gethrtime(); 995 (void) getreply(0); 996 (void) signal(SIGINT, oldintr); 997 if (oldintp) 998 (void) signal(SIGPIPE, oldintp); 999 1000 /* 1001 * Only print the transfer successful message if the code returned 1002 * from remote is 226 or 250. All other codes are error codes. 1003 */ 1004 if ((bytes > 0) && verbose && ((code == 226) || (code == 250))) 1005 ptransfer("sent", bytes, start, stop, local, remote); 1006 if (!ctrl_in) 1007 (void) printf("Lost connection\n"); 1008 return; 1009 abort: 1010 (void) signal(SIGINT, oldintr); 1011 if (oldintp) 1012 (void) signal(SIGPIPE, oldintp); 1013 if (!cpend) { 1014 code = -1; 1015 return; 1016 } 1017 if (data >= 0) { 1018 (void) close(data); 1019 data = -1; 1020 } 1021 if (dout) { 1022 (void) fclose(dout); 1023 data = -1; 1024 } 1025 (void) getreply(0); 1026 code = -1; 1027 if (closefunc != NULL && fin != NULL) 1028 (*closefunc)(fin); 1029 stop = gethrtime(); 1030 /* 1031 * Only print the transfer successful message if the code returned 1032 * from remote is 226 or 250. All other codes are error codes. 1033 */ 1034 if ((bytes > 0) && verbose && ((code == 226) || (code == 250))) 1035 ptransfer("sent", bytes, start, stop, local, remote); 1036 if (!ctrl_in) 1037 (void) printf("Lost connection\n"); 1038 restart_point = 0; 1039 } 1040 1041 /*ARGSUSED*/ 1042 static void 1043 abortrecv(int sig) 1044 { 1045 mflag = 0; 1046 abrtflag = 0; 1047 (void) printf("\n"); 1048 (void) fflush(stdout); 1049 longjmp(recvabort, 1); 1050 } 1051 1052 void 1053 recvrequest(char *cmd, char *local, char *remote, char *mode, int allowpipe) 1054 { 1055 FILE *fout, *din = 0; 1056 int (*closefunc)(); 1057 void (*oldintr)(), (*oldintp)(); 1058 int oldverbose, oldtype = 0, tcrflag, nfnd; 1059 char msg; 1060 off_t bytes = 0, hashbytes = HASHSIZ; 1061 struct fd_set mask; 1062 int c, d, n; 1063 hrtime_t start, stop; 1064 int errflg = 0; 1065 int infd; 1066 int nfds; 1067 int retrcmd; 1068 1069 retrcmd = (strcmp(cmd, "RETR") == 0); 1070 if (proxy && retrcmd) { 1071 proxtrans(cmd, local, remote); 1072 return; 1073 } 1074 closefunc = NULL; 1075 oldintr = NULL; 1076 oldintp = NULL; 1077 tcrflag = !crflag && retrcmd; 1078 if (setjmp(recvabort)) { 1079 while (cpend) { 1080 (void) getreply(0); 1081 } 1082 if (data >= 0) { 1083 (void) close(data); 1084 data = -1; 1085 } 1086 if (oldintr) 1087 (void) signal(SIGINT, oldintr); 1088 code = -1; 1089 return; 1090 } 1091 oldintr = signal(SIGINT, abortrecv); 1092 if (local != NULL && 1093 strcmp(local, "-") != 0 && 1094 (*local != '|' || !allowpipe)) { 1095 if (access(local, W_OK) < 0) { 1096 char *dir = rindex(local, '/'); 1097 int file_errno = errno; 1098 1099 if (file_errno != ENOENT && file_errno != EACCES) { 1100 perror(local); 1101 (void) signal(SIGINT, oldintr); 1102 code = -1; 1103 return; 1104 } 1105 if ((dir != NULL) && (dir != local)) 1106 *dir = 0; 1107 if (dir == local) 1108 d = access("/", W_OK); 1109 else 1110 d = access(dir ? local : ".", W_OK); 1111 if ((dir != NULL) && (dir != local)) 1112 *dir = '/'; 1113 if (d < 0) { 1114 perror(local); 1115 (void) signal(SIGINT, oldintr); 1116 code = -1; 1117 return; 1118 } 1119 if (!runique && file_errno == EACCES) { 1120 errno = file_errno; 1121 perror(local); 1122 (void) signal(SIGINT, oldintr); 1123 code = -1; 1124 return; 1125 } 1126 if (runique && file_errno == EACCES && 1127 (local = gunique(local)) == NULL) { 1128 (void) signal(SIGINT, oldintr); 1129 code = -1; 1130 return; 1131 } 1132 } else if (runique && (local = gunique(local)) == NULL) { 1133 (void) signal(SIGINT, oldintr); 1134 code = -1; 1135 return; 1136 } 1137 } 1138 if (initconn()) { 1139 (void) signal(SIGINT, oldintr); 1140 code = -1; 1141 return; 1142 } 1143 if (setjmp(recvabort)) 1144 goto abort; 1145 if (!retrcmd && type != TYPE_A) { 1146 oldtype = type; 1147 oldverbose = verbose; 1148 if (!debug) 1149 verbose = 0; 1150 setascii(0, NULL); 1151 verbose = oldverbose; 1152 } 1153 if ((restart_point > 0) && retrcmd && 1154 command("REST %lld", (longlong_t)restart_point) != CONTINUE) { 1155 return; 1156 } 1157 if (remote) { 1158 if (command("%s %s", cmd, remote) != PRELIM) { 1159 (void) signal(SIGINT, oldintr); 1160 if (oldtype) { 1161 if (!debug) 1162 verbose = 0; 1163 switch (oldtype) { 1164 case TYPE_I: 1165 setbinary(0, NULL); 1166 break; 1167 case TYPE_E: 1168 setebcdic(0, NULL); 1169 break; 1170 case TYPE_L: 1171 settenex(0, NULL); 1172 break; 1173 } 1174 verbose = oldverbose; 1175 } 1176 return; 1177 } 1178 } else { 1179 if (command("%s", cmd) != PRELIM) { 1180 (void) signal(SIGINT, oldintr); 1181 if (oldtype) { 1182 if (!debug) 1183 verbose = 0; 1184 switch (oldtype) { 1185 case TYPE_I: 1186 setbinary(0, NULL); 1187 break; 1188 case TYPE_E: 1189 setebcdic(0, NULL); 1190 break; 1191 case TYPE_L: 1192 settenex(0, NULL); 1193 break; 1194 } 1195 verbose = oldverbose; 1196 } 1197 return; 1198 } 1199 } 1200 din = dataconn("r"); 1201 if (din == NULL) 1202 goto abort; 1203 1204 if (local == NULL) { 1205 fout = tmp_nlst; 1206 } else if (strcmp(local, "-") == 0) { 1207 fout = stdout; 1208 } else if (allowpipe && *local == '|') { 1209 oldintp = signal(SIGPIPE, SIG_IGN); 1210 fout = mypopen(local + 1, "w"); 1211 if (fout == NULL) { 1212 perror(local+1); 1213 goto abort; 1214 } 1215 closefunc = mypclose; 1216 } else { 1217 fout = fopen(local, mode); 1218 if (fout == NULL) { 1219 perror(local); 1220 goto abort; 1221 } 1222 closefunc = fclose; 1223 } 1224 start = gethrtime(); 1225 stop_timer(); 1226 switch (type) { 1227 1228 case TYPE_I: 1229 case TYPE_L: 1230 if ((restart_point > 0) && retrcmd && 1231 lseek(fileno(fout), restart_point, SEEK_SET) < 0) { 1232 perror(local); 1233 goto abort; 1234 } 1235 errno = d = 0; 1236 infd = fileno(din); 1237 while ((c = timedread(infd, buf, FTPBUFSIZ, timeout)) > 0) { 1238 for (n = 0; n < c; n += d) { 1239 d = write(fileno(fout), &buf[n], c - n); 1240 if (d == -1) 1241 goto writeerr; 1242 } 1243 bytes += c; 1244 if (hash) { 1245 while (bytes >= hashbytes) { 1246 (void) putchar('#'); 1247 hashbytes += HASHSIZ; 1248 } 1249 (void) fflush(stdout); 1250 } 1251 } 1252 if (hash && bytes > 0) { 1253 if (bytes < hashbytes) 1254 (void) putchar('#'); 1255 (void) putchar('\n'); 1256 (void) fflush(stdout); 1257 } 1258 if (c < 0) { 1259 errflg = 1; 1260 perror("netin"); 1261 } 1262 if ((d < 0) || ((c == 0) && (fsync(fileno(fout)) == -1))) { 1263 writeerr: 1264 errflg = 1; 1265 perror(local); 1266 } 1267 break; 1268 1269 case TYPE_A: 1270 if ((restart_point > 0) && retrcmd) { 1271 int c; 1272 off_t i = 0; 1273 1274 if (fseek(fout, 0L, SEEK_SET) < 0) { 1275 perror(local); 1276 goto abort; 1277 } 1278 while (i++ < restart_point) { 1279 if ((c = getc(fout)) == EOF) { 1280 if (ferror(fout)) 1281 perror(local); 1282 else 1283 (void) fprintf(stderr, 1284 "%s: Unexpected end of " 1285 "file\n", local); 1286 goto abort; 1287 } 1288 if (c == '\n') 1289 i++; 1290 } 1291 if (fseeko(fout, 0L, SEEK_CUR) < 0) { 1292 perror(local); 1293 goto abort; 1294 } 1295 } 1296 fdio_setbuf(buf, FTPBUFSIZ); 1297 infd = fileno(din); 1298 while ((c = fdio_getc(infd)) != EOF) { 1299 while (c == '\r') { 1300 while (hash && (bytes >= hashbytes)) { 1301 (void) putchar('#'); 1302 (void) fflush(stdout); 1303 hashbytes += HASHSIZ; 1304 } 1305 bytes++; 1306 1307 if ((c = fdio_getc(infd)) != '\n' || tcrflag) { 1308 if (ferror(fout)) 1309 break; 1310 if (putc('\r', fout) == EOF) 1311 goto writer_ascii_err; 1312 } 1313 #ifdef notdef 1314 if (c == '\0') { 1315 bytes++; 1316 continue; 1317 } 1318 #endif 1319 if (c == EOF) 1320 goto endread; 1321 } 1322 if (putc(c, fout) == EOF) 1323 goto writer_ascii_err; 1324 bytes++; 1325 } 1326 endread: 1327 if (hash && bytes > 0) { 1328 if (bytes < hashbytes) 1329 (void) putchar('#'); 1330 (void) putchar('\n'); 1331 (void) fflush(stdout); 1332 } 1333 if (fdio_error(infd)) { 1334 errflg = 1; 1335 perror("netin"); 1336 } 1337 if ((fflush(fout) == EOF) || ferror(fout) || 1338 (fsync(fileno(fout)) == -1)) { 1339 writer_ascii_err: 1340 errflg = 1; 1341 perror(local); 1342 } 1343 break; 1344 } 1345 reset_timer(); 1346 if (closefunc != NULL) 1347 (*closefunc)(fout); 1348 (void) signal(SIGINT, oldintr); 1349 if (oldintp) 1350 (void) signal(SIGPIPE, oldintp); 1351 (void) fclose(din); data = -1; 1352 stop = gethrtime(); 1353 (void) getreply(0); 1354 if (bytes > 0 && verbose && !errflg) 1355 ptransfer("received", bytes, start, stop, local, remote); 1356 if (!ctrl_in) 1357 (void) printf("Lost connection\n"); 1358 if (oldtype) { 1359 if (!debug) 1360 verbose = 0; 1361 switch (oldtype) { 1362 case TYPE_I: 1363 setbinary(0, NULL); 1364 break; 1365 case TYPE_E: 1366 setebcdic(0, NULL); 1367 break; 1368 case TYPE_L: 1369 settenex(0, NULL); 1370 break; 1371 } 1372 verbose = oldverbose; 1373 } 1374 return; 1375 abort: 1376 1377 /* abort using RFC959 recommended IP, SYNC sequence */ 1378 1379 stop = gethrtime(); 1380 if (oldintp) 1381 (void) signal(SIGPIPE, oldintp); 1382 (void) signal(SIGINT, SIG_IGN); 1383 if (!cpend) { 1384 code = -1; 1385 (void) signal(SIGINT, oldintr); 1386 return; 1387 } 1388 1389 (void) fprintf(ctrl_out, "%c%c", IAC, IP); 1390 (void) fflush(ctrl_out); 1391 msg = (char)IAC; 1392 /* 1393 * send IAC in urgent mode instead of DM because UNIX places oob 1394 * mark after urgent byte rather than before as now is protocol 1395 */ 1396 if (send(fileno(ctrl_out), &msg, 1, MSG_OOB) != 1) { 1397 perror("abort"); 1398 } 1399 (void) fprintf(ctrl_out, "%cABOR\r\n", DM); 1400 (void) fflush(ctrl_out); 1401 nfds = fileno(ctrl_in) + 1; 1402 FD_ZERO(&mask); 1403 FD_SET(fileno(ctrl_in), &mask); 1404 if (din) { 1405 FD_SET(fileno(din), &mask); 1406 nfds = MAX(fileno(din) + 1, nfds); 1407 } 1408 if ((nfnd = empty(&mask, 10, nfds)) <= 0) { 1409 if (nfnd < 0) { 1410 perror("abort"); 1411 } 1412 code = -1; 1413 lostpeer(0); 1414 } 1415 if (din && FD_ISSET(fileno(din), &mask)) { 1416 do { 1417 reset_timer(); 1418 } while ((c = read(fileno(din), buf, FTPBUFSIZ)) > 0); 1419 } 1420 if ((c = getreply(0)) == ERROR && code == 552) { 1421 /* needed for nic style abort */ 1422 if (data >= 0) { 1423 (void) close(data); 1424 data = -1; 1425 } 1426 (void) getreply(0); 1427 } 1428 if (oldtype) { 1429 if (!debug) 1430 verbose = 0; 1431 switch (oldtype) { 1432 case TYPE_I: 1433 setbinary(0, NULL); 1434 break; 1435 case TYPE_E: 1436 setebcdic(0, NULL); 1437 break; 1438 case TYPE_L: 1439 settenex(0, NULL); 1440 break; 1441 } 1442 verbose = oldverbose; 1443 } 1444 (void) getreply(0); 1445 code = -1; 1446 if (data >= 0) { 1447 (void) close(data); 1448 data = -1; 1449 } 1450 if (closefunc != NULL && fout != NULL) 1451 (*closefunc)(fout); 1452 if (din) { 1453 (void) fclose(din); 1454 data = -1; 1455 } 1456 if (bytes > 0 && verbose) 1457 ptransfer("received", bytes, start, stop, local, remote); 1458 if (!ctrl_in) 1459 (void) printf("Lost connection\n"); 1460 (void) signal(SIGINT, oldintr); 1461 } 1462 1463 /* 1464 * Need to start a listen on the data channel 1465 * before we send the command, otherwise the 1466 * server's connect may fail. 1467 */ 1468 1469 static int 1470 initconn(void) 1471 { 1472 unsigned char *p, *a; 1473 int result, tmpno = 0; 1474 int on = 1; 1475 socklen_t len; 1476 int v4_addr; 1477 char *c, *c2, delm; 1478 in_port_t ports; 1479 1480 pasv_refused = B_FALSE; 1481 if (passivemode) { 1482 data = socket(AF_INET6, SOCK_STREAM, 0); 1483 if (data < 0) { 1484 perror("socket"); 1485 return (1); 1486 } 1487 if (timeout && setsockopt(data, IPPROTO_TCP, 1488 TCP_ABORT_THRESHOLD, (char *)&timeoutms, 1489 sizeof (timeoutms)) < 0 && debug) 1490 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)"); 1491 if ((options & SO_DEBUG) && 1492 setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, 1493 sizeof (on)) < 0) 1494 perror("setsockopt (ignored)"); 1495 /* 1496 * Use the system wide default send and receive buffer sizes 1497 * unless one has been specified. 1498 */ 1499 if (tcpwindowsize) { 1500 if (setsockopt(data, SOL_SOCKET, SO_SNDBUF, 1501 (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0) 1502 perror("ftp: setsockopt (SO_SNDBUF - ignored)"); 1503 if (setsockopt(data, SOL_SOCKET, SO_RCVBUF, 1504 (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0) 1505 perror("ftp: setsockopt (SO_RCVBUF - ignored)"); 1506 } 1507 1508 data_addr = remctladdr; 1509 1510 if (ipv6rem == B_TRUE) { 1511 if (command("EPSV") != COMPLETE) { 1512 (void) fprintf(stderr, 1513 "Passive mode refused. Try EPRT\n"); 1514 pasv_refused = B_TRUE; 1515 goto noport; 1516 } 1517 1518 /* 1519 * Get the data port from reply string from the 1520 * server. The format of the reply string is: 1521 * 229 Entering Extended Passive Mode (|||port|) 1522 * where | is the delimiter being used. 1523 */ 1524 c = strchr(reply_string, '('); 1525 c2 = strchr(reply_string, ')'); 1526 if (c == NULL || c2 == NULL) { 1527 (void) fprintf(stderr, "Extended passive mode" 1528 "parsing failure.\n"); 1529 goto bad; 1530 } 1531 *(c2 - 1) = '\0'; 1532 /* Delimiter is the next char in the reply string */ 1533 delm = *(++c); 1534 while (*c == delm) { 1535 if (!*(c++)) { 1536 (void) fprintf(stderr, 1537 "Extended passive mode" 1538 "parsing failure.\n"); 1539 goto bad; 1540 } 1541 } 1542 /* assign the port for data connection */ 1543 ports = (in_port_t)atoi(c); 1544 data_addr.sin6_port = htons(ports); 1545 } else { 1546 int a1, a2, a3, a4, p1, p2; 1547 1548 if (command("PASV") != COMPLETE) { 1549 (void) fprintf(stderr, 1550 "Passive mode refused. Try PORT\n"); 1551 pasv_refused = B_TRUE; 1552 goto noport; 1553 } 1554 1555 /* 1556 * Get the data port from reply string from the 1557 * server. The format of the reply string is: 1558 * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2) 1559 */ 1560 if (sscanf(pasv, "%d,%d,%d,%d,%d,%d", 1561 &a1, &a2, &a3, &a4, &p1, &p2) != 6) { 1562 (void) fprintf(stderr, 1563 "Passive mode parsing failure.\n"); 1564 goto bad; 1565 } 1566 /* 1567 * Set the supplied address and port in an 1568 * IPv4-mapped IPv6 address. 1569 */ 1570 a = (unsigned char *)&data_addr.sin6_addr + 1571 sizeof (struct in6_addr) - 1572 sizeof (struct in_addr); 1573 #define UC(b) ((b)&0xff) 1574 a[0] = UC(a1); 1575 a[1] = UC(a2); 1576 a[2] = UC(a3); 1577 a[3] = UC(a4); 1578 p = (unsigned char *)&data_addr.sin6_port; 1579 p[0] = UC(p1); 1580 p[1] = UC(p2); 1581 } 1582 1583 if (connect(data, (struct sockaddr *)&data_addr, 1584 sizeof (data_addr)) < 0) { 1585 perror("connect"); 1586 goto bad; 1587 } 1588 return (0); 1589 } 1590 1591 noport: 1592 data_addr = myctladdr; 1593 if (sendport) 1594 data_addr.sin6_port = 0; /* let system pick one */ 1595 1596 if (data != -1) 1597 (void) close(data); 1598 data = socket(AF_INET6, SOCK_STREAM, 0); 1599 if (data < 0) { 1600 perror("ftp: socket"); 1601 if (tmpno) 1602 sendport = 1; 1603 return (1); 1604 } 1605 if (!sendport) 1606 if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, 1607 (char *)&on, sizeof (on)) < 0) { 1608 perror("ftp: setsockopt (SO_REUSEADDR)"); 1609 goto bad; 1610 } 1611 if (bind(data, 1612 (struct sockaddr *)&data_addr, sizeof (data_addr)) < 0) { 1613 perror("ftp: bind"); 1614 goto bad; 1615 } 1616 if (timeout && setsockopt(data, IPPROTO_TCP, TCP_ABORT_THRESHOLD, 1617 (char *)&timeoutms, sizeof (timeoutms)) < 0 && debug) 1618 perror("ftp: setsockopt (TCP_ABORT_THRESHOLD)"); 1619 if (options & SO_DEBUG && 1620 setsockopt(data, SOL_SOCKET, SO_DEBUG, 1621 (char *)&on, sizeof (on)) < 0) 1622 perror("ftp: setsockopt (SO_DEBUG - ignored)"); 1623 /* 1624 * Use the system wide default send and receive buffer sizes unless 1625 * one has been specified. 1626 */ 1627 if (tcpwindowsize) { 1628 if (setsockopt(data, SOL_SOCKET, SO_SNDBUF, 1629 (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0) 1630 perror("ftp: setsockopt (SO_SNDBUF - ignored)"); 1631 if (setsockopt(data, SOL_SOCKET, SO_RCVBUF, 1632 (char *)&tcpwindowsize, sizeof (tcpwindowsize)) < 0) 1633 perror("ftp: setsockopt (SO_RCVBUF - ignored)"); 1634 } 1635 len = sizeof (data_addr); 1636 if (getsockname(data, (struct sockaddr *)&data_addr, &len) < 0) { 1637 perror("ftp: getsockname"); 1638 goto bad; 1639 } 1640 1641 v4_addr = IN6_IS_ADDR_V4MAPPED(&data_addr.sin6_addr); 1642 if (listen(data, 1) < 0) 1643 perror("ftp: listen"); 1644 1645 if (sendport) { 1646 a = (unsigned char *)&data_addr.sin6_addr; 1647 p = (unsigned char *)&data_addr.sin6_port; 1648 if (v4_addr) { 1649 result = 1650 command("PORT %d,%d,%d,%d,%d,%d", 1651 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), 1652 UC(p[0]), UC(p[1])); 1653 } else { 1654 char hname[INET6_ADDRSTRLEN]; 1655 1656 result = COMPLETE + 1; 1657 /* 1658 * if on previous try to server, it was 1659 * determined that the server doesn't support 1660 * EPRT, don't bother trying again. Just try 1661 * LPRT. 1662 */ 1663 if (eport_supported == B_TRUE) { 1664 if (inet_ntop(AF_INET6, &data_addr.sin6_addr, 1665 hname, sizeof (hname)) != NULL) { 1666 result = command("EPRT |%d|%s|%d|", 2, 1667 hname, htons(data_addr.sin6_port)); 1668 if (result != COMPLETE) 1669 eport_supported = B_FALSE; 1670 } 1671 } 1672 /* Try LPRT */ 1673 if (result != COMPLETE) { 1674 result = command( 1675 "LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d," 1676 "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", 1677 6, 16, 1678 UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), 1679 UC(a[4]), UC(a[5]), UC(a[6]), UC(a[7]), 1680 UC(a[8]), UC(a[9]), UC(a[10]), UC(a[11]), 1681 UC(a[12]), UC(a[13]), UC(a[14]), UC(a[15]), 1682 2, UC(p[0]), UC(p[1])); 1683 } 1684 } 1685 1686 if (result == ERROR && sendport == -1) { 1687 sendport = 0; 1688 tmpno = 1; 1689 goto noport; 1690 } 1691 return (result != COMPLETE); 1692 } 1693 if (tmpno) 1694 sendport = 1; 1695 return (0); 1696 bad: 1697 (void) close(data), data = -1; 1698 if (tmpno) 1699 sendport = 1; 1700 return (1); 1701 } 1702 1703 static FILE * 1704 dataconn(char *mode) 1705 { 1706 struct sockaddr_in6 from; 1707 int s; 1708 socklen_t fromlen = sizeof (from); 1709 1710 reset_timer(); 1711 if (passivemode && !pasv_refused) 1712 return (fdopen(data, mode)); 1713 1714 s = accept(data, (struct sockaddr *)&from, &fromlen); 1715 if (s < 0) { 1716 perror("ftp: accept"); 1717 (void) close(data), data = -1; 1718 return (NULL); 1719 } 1720 (void) close(data); 1721 data = s; 1722 return (fdopen(data, mode)); 1723 } 1724 1725 static void 1726 ptransfer(char *direction, off_t bytes, hrtime_t t0, 1727 hrtime_t t1, char *local, char *remote) 1728 { 1729 hrtime_t td; /* nanoseconds in a 64 bit int */ 1730 double s, bs; 1731 1732 td = t1 - t0; 1733 s = (double)td / 1000000000.0; /* seconds */ 1734 bs = (double)bytes / NONZERO(s); 1735 if (local && *local != '-') 1736 (void) printf("local: %s ", local); 1737 if (remote) 1738 (void) printf("remote: %s\n", remote); 1739 (void) printf("%lld bytes %s in %.2g seconds (%.2f Kbytes/s)\n", 1740 (longlong_t)bytes, direction, s, bs / 1024.0); 1741 } 1742 1743 /*ARGSUSED*/ 1744 static void 1745 psabort(int sig) 1746 { 1747 abrtflag++; 1748 } 1749 1750 void 1751 pswitch(int flag) 1752 { 1753 void (*oldintr)(); 1754 static struct comvars { 1755 int connect; 1756 char name[MAXHOSTNAMELEN]; 1757 struct sockaddr_in6 mctl; 1758 struct sockaddr_in6 hctl; 1759 FILE *in; 1760 FILE *out; 1761 int tpe; 1762 int cpnd; 1763 int sunqe; 1764 int runqe; 1765 int mcse; 1766 int ntflg; 1767 char nti[17]; 1768 char nto[17]; 1769 int mapflg; 1770 char mi[MAXPATHLEN]; 1771 char mo[MAXPATHLEN]; 1772 int authtype; 1773 int clvl; 1774 int dlvl; 1775 } proxstruct, tmpstruct; 1776 struct comvars *ip, *op; 1777 1778 abrtflag = 0; 1779 oldintr = signal(SIGINT, psabort); 1780 if (flag) { 1781 if (proxy) 1782 return; 1783 ip = &tmpstruct; 1784 op = &proxstruct; 1785 proxy++; 1786 } else { 1787 if (!proxy) 1788 return; 1789 ip = &proxstruct; 1790 op = &tmpstruct; 1791 proxy = 0; 1792 } 1793 ip->connect = connected; 1794 connected = op->connect; 1795 if (hostname) 1796 (void) strlcpy(ip->name, hostname, sizeof (ip->name)); 1797 else 1798 ip->name[0] = 0; 1799 hostname = op->name; 1800 ip->hctl = remctladdr; 1801 remctladdr = op->hctl; 1802 ip->mctl = myctladdr; 1803 myctladdr = op->mctl; 1804 ip->in = ctrl_in; 1805 ctrl_in = op->in; 1806 ip->out = ctrl_out; 1807 ctrl_out = op->out; 1808 ip->tpe = type; 1809 type = op->tpe; 1810 if (!type) 1811 type = 1; 1812 ip->cpnd = cpend; 1813 cpend = op->cpnd; 1814 ip->sunqe = sunique; 1815 sunique = op->sunqe; 1816 ip->runqe = runique; 1817 runique = op->runqe; 1818 ip->mcse = mcase; 1819 mcase = op->mcse; 1820 ip->ntflg = ntflag; 1821 ntflag = op->ntflg; 1822 (void) strlcpy(ip->nti, ntin, sizeof (ip->nti)); 1823 (void) strlcpy(ntin, op->nti, sizeof (ntin)); 1824 (void) strlcpy(ip->nto, ntout, sizeof (ip->nto)); 1825 (void) strlcpy(ntout, op->nto, sizeof (ntout)); 1826 ip->mapflg = mapflag; 1827 mapflag = op->mapflg; 1828 (void) strlcpy(ip->mi, mapin, sizeof (ip->mi)); 1829 (void) strlcpy(mapin, op->mi, sizeof (mapin)); 1830 (void) strlcpy(ip->mo, mapout, sizeof (ip->mo)); 1831 (void) strlcpy(mapout, op->mo, sizeof (mapout)); 1832 1833 ip->authtype = auth_type; 1834 auth_type = op->authtype; 1835 ip->clvl = clevel; 1836 clevel = op->clvl; 1837 ip->dlvl = dlevel; 1838 dlevel = op->dlvl; 1839 if (!clevel) 1840 clevel = PROT_C; 1841 if (!dlevel) 1842 dlevel = PROT_C; 1843 1844 (void) signal(SIGINT, oldintr); 1845 if (abrtflag) { 1846 abrtflag = 0; 1847 (*oldintr)(); 1848 } 1849 } 1850 1851 /*ARGSUSED*/ 1852 static void 1853 abortpt(int sig) 1854 { 1855 (void) printf("\n"); 1856 (void) fflush(stdout); 1857 ptabflg++; 1858 mflag = 0; 1859 abrtflag = 0; 1860 longjmp(ptabort, 1); 1861 } 1862 1863 static void 1864 proxtrans(char *cmd, char *local, char *remote) 1865 { 1866 void (*oldintr)(); 1867 int tmptype, oldtype = 0, secndflag = 0, nfnd; 1868 extern jmp_buf ptabort; 1869 char *cmd2; 1870 struct fd_set mask; 1871 int ipv4_addr = IN6_IS_ADDR_V4MAPPED(&remctladdr.sin6_addr); 1872 1873 if (strcmp(cmd, "RETR")) 1874 cmd2 = "RETR"; 1875 else 1876 cmd2 = runique ? "STOU" : "STOR"; 1877 if (command(ipv4_addr ? "PASV" : "EPSV") != COMPLETE) { 1878 (void) printf( 1879 "proxy server does not support third part transfers.\n"); 1880 return; 1881 } 1882 tmptype = type; 1883 pswitch(0); 1884 if (!connected) { 1885 (void) printf("No primary connection\n"); 1886 pswitch(1); 1887 code = -1; 1888 return; 1889 } 1890 if (type != tmptype) { 1891 oldtype = type; 1892 switch (tmptype) { 1893 case TYPE_A: 1894 setascii(0, NULL); 1895 break; 1896 case TYPE_I: 1897 setbinary(0, NULL); 1898 break; 1899 case TYPE_E: 1900 setebcdic(0, NULL); 1901 break; 1902 case TYPE_L: 1903 settenex(0, NULL); 1904 break; 1905 } 1906 } 1907 if (command(ipv4_addr ? "PORT %s" : "EPRT %s", pasv) != COMPLETE) { 1908 switch (oldtype) { 1909 case 0: 1910 break; 1911 case TYPE_A: 1912 setascii(0, NULL); 1913 break; 1914 case TYPE_I: 1915 setbinary(0, NULL); 1916 break; 1917 case TYPE_E: 1918 setebcdic(0, NULL); 1919 break; 1920 case TYPE_L: 1921 settenex(0, NULL); 1922 break; 1923 } 1924 pswitch(1); 1925 return; 1926 } 1927 if (setjmp(ptabort)) 1928 goto abort; 1929 oldintr = signal(SIGINT, (void (*)())abortpt); 1930 if (command("%s %s", cmd, remote) != PRELIM) { 1931 (void) signal(SIGINT, oldintr); 1932 switch (oldtype) { 1933 case 0: 1934 break; 1935 case TYPE_A: 1936 setascii(0, NULL); 1937 break; 1938 case TYPE_I: 1939 setbinary(0, NULL); 1940 break; 1941 case TYPE_E: 1942 setebcdic(0, NULL); 1943 break; 1944 case TYPE_L: 1945 settenex(0, NULL); 1946 break; 1947 } 1948 pswitch(1); 1949 return; 1950 } 1951 (void) sleep(2); 1952 pswitch(1); 1953 secndflag++; 1954 if (command("%s %s", cmd2, local) != PRELIM) 1955 goto abort; 1956 ptflag++; 1957 (void) getreply(0); 1958 pswitch(0); 1959 (void) getreply(0); 1960 (void) signal(SIGINT, oldintr); 1961 switch (oldtype) { 1962 case 0: 1963 break; 1964 case TYPE_A: 1965 setascii(0, NULL); 1966 break; 1967 case TYPE_I: 1968 setbinary(0, NULL); 1969 break; 1970 case TYPE_E: 1971 setebcdic(0, NULL); 1972 break; 1973 case TYPE_L: 1974 settenex(0, NULL); 1975 break; 1976 } 1977 pswitch(1); 1978 ptflag = 0; 1979 (void) printf("local: %s remote: %s\n", local, remote); 1980 return; 1981 abort: 1982 (void) signal(SIGINT, SIG_IGN); 1983 ptflag = 0; 1984 if (strcmp(cmd, "RETR") && !proxy) 1985 pswitch(1); 1986 else if ((strcmp(cmd, "RETR") == 0) && proxy) 1987 pswitch(0); 1988 if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ 1989 if (command("%s %s", cmd2, local) != PRELIM) { 1990 pswitch(0); 1991 switch (oldtype) { 1992 case 0: 1993 break; 1994 case TYPE_A: 1995 setascii(0, NULL); 1996 break; 1997 case TYPE_I: 1998 setbinary(0, NULL); 1999 break; 2000 case TYPE_E: 2001 setebcdic(0, NULL); 2002 break; 2003 case TYPE_L: 2004 settenex(0, NULL); 2005 break; 2006 } 2007 if (cpend) { 2008 char msg[2]; 2009 2010 (void) fprintf(ctrl_out, "%c%c", IAC, IP); 2011 (void) fflush(ctrl_out); 2012 *msg = (char)IAC; 2013 *(msg+1) = (char)DM; 2014 if (send(fileno(ctrl_out), msg, 2, MSG_OOB) 2015 != 2) 2016 perror("abort"); 2017 (void) fprintf(ctrl_out, "ABOR\r\n"); 2018 (void) fflush(ctrl_out); 2019 FD_ZERO(&mask); 2020 FD_SET(fileno(ctrl_in), &mask); 2021 if ((nfnd = empty(&mask, 10, 2022 fileno(ctrl_in) + 1)) <= 0) { 2023 if (nfnd < 0) { 2024 perror("abort"); 2025 } 2026 if (ptabflg) 2027 code = -1; 2028 lostpeer(0); 2029 } 2030 (void) getreply(0); 2031 (void) getreply(0); 2032 } 2033 } 2034 pswitch(1); 2035 if (ptabflg) 2036 code = -1; 2037 (void) signal(SIGINT, oldintr); 2038 return; 2039 } 2040 if (cpend) { 2041 char msg[2]; 2042 2043 (void) fprintf(ctrl_out, "%c%c", IAC, IP); 2044 (void) fflush(ctrl_out); 2045 *msg = (char)IAC; 2046 *(msg+1) = (char)DM; 2047 if (send(fileno(ctrl_out), msg, 2, MSG_OOB) != 2) 2048 perror("abort"); 2049 (void) fprintf(ctrl_out, "ABOR\r\n"); 2050 (void) fflush(ctrl_out); 2051 FD_ZERO(&mask); 2052 FD_SET(fileno(ctrl_in), &mask); 2053 if ((nfnd = empty(&mask, 10, fileno(ctrl_in) + 1)) <= 0) { 2054 if (nfnd < 0) { 2055 perror("abort"); 2056 } 2057 if (ptabflg) 2058 code = -1; 2059 lostpeer(0); 2060 } 2061 (void) getreply(0); 2062 (void) getreply(0); 2063 } 2064 pswitch(!proxy); 2065 if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ 2066 if (command("%s %s", cmd2, local) != PRELIM) { 2067 pswitch(0); 2068 switch (oldtype) { 2069 case 0: 2070 break; 2071 case TYPE_A: 2072 setascii(0, NULL); 2073 break; 2074 case TYPE_I: 2075 setbinary(0, NULL); 2076 break; 2077 case TYPE_E: 2078 setebcdic(0, NULL); 2079 break; 2080 case TYPE_L: 2081 settenex(0, NULL); 2082 break; 2083 } 2084 if (cpend) { 2085 char msg[2]; 2086 2087 (void) fprintf(ctrl_out, "%c%c", IAC, IP); 2088 (void) fflush(ctrl_out); 2089 *msg = (char)IAC; 2090 *(msg+1) = (char)DM; 2091 if (send(fileno(ctrl_out), msg, 2, MSG_OOB) 2092 != 2) 2093 perror("abort"); 2094 (void) fprintf(ctrl_out, "ABOR\r\n"); 2095 (void) fflush(ctrl_out); 2096 FD_ZERO(&mask); 2097 FD_SET(fileno(ctrl_in), &mask); 2098 if ((nfnd = empty(&mask, 10, 2099 fileno(ctrl_in) + 1)) <= 0) { 2100 if (nfnd < 0) { 2101 perror("abort"); 2102 } 2103 if (ptabflg) 2104 code = -1; 2105 lostpeer(0); 2106 } 2107 (void) getreply(0); 2108 (void) getreply(0); 2109 } 2110 pswitch(1); 2111 if (ptabflg) 2112 code = -1; 2113 (void) signal(SIGINT, oldintr); 2114 return; 2115 } 2116 } 2117 if (cpend) { 2118 char msg[2]; 2119 2120 (void) fprintf(ctrl_out, "%c%c", IAC, IP); 2121 (void) fflush(ctrl_out); 2122 *msg = (char)IAC; 2123 *(msg+1) = (char)DM; 2124 if (send(fileno(ctrl_out), msg, 2, MSG_OOB) != 2) 2125 perror("abort"); 2126 (void) fprintf(ctrl_out, "ABOR\r\n"); 2127 (void) fflush(ctrl_out); 2128 FD_ZERO(&mask); 2129 FD_SET(fileno(ctrl_in), &mask); 2130 if ((nfnd = empty(&mask, 10, fileno(ctrl_in) + 1)) <= 0) { 2131 if (nfnd < 0) { 2132 perror("abort"); 2133 } 2134 if (ptabflg) 2135 code = -1; 2136 lostpeer(0); 2137 } 2138 (void) getreply(0); 2139 (void) getreply(0); 2140 } 2141 pswitch(!proxy); 2142 if (cpend) { 2143 FD_ZERO(&mask); 2144 FD_SET(fileno(ctrl_in), &mask); 2145 if ((nfnd = empty(&mask, 10, fileno(ctrl_in) + 1)) <= 0) { 2146 if (nfnd < 0) { 2147 perror("abort"); 2148 } 2149 if (ptabflg) 2150 code = -1; 2151 lostpeer(0); 2152 } 2153 (void) getreply(0); 2154 (void) getreply(0); 2155 } 2156 if (proxy) 2157 pswitch(0); 2158 switch (oldtype) { 2159 case 0: 2160 break; 2161 case TYPE_A: 2162 setascii(0, NULL); 2163 break; 2164 case TYPE_I: 2165 setbinary(0, NULL); 2166 break; 2167 case TYPE_E: 2168 setebcdic(0, NULL); 2169 break; 2170 case TYPE_L: 2171 settenex(0, NULL); 2172 break; 2173 } 2174 pswitch(1); 2175 if (ptabflg) 2176 code = -1; 2177 (void) signal(SIGINT, oldintr); 2178 } 2179 2180 /*ARGSUSED*/ 2181 void 2182 reset(int argc, char *argv[]) 2183 { 2184 struct fd_set mask; 2185 int nfnd = 1; 2186 2187 FD_ZERO(&mask); 2188 while (nfnd > 0) { 2189 FD_SET(fileno(ctrl_in), &mask); 2190 if ((nfnd = empty(&mask, 0, fileno(ctrl_in) + 1)) < 0) { 2191 perror("reset"); 2192 code = -1; 2193 lostpeer(0); 2194 } else if (nfnd > 0) { 2195 (void) getreply(0); 2196 } 2197 } 2198 } 2199 2200 static char * 2201 gunique(char *local) 2202 { 2203 static char new[MAXPATHLEN]; 2204 char *cp = rindex(local, '/'); 2205 int d, count = 0; 2206 char ext = '1'; 2207 2208 if (cp) 2209 *cp = '\0'; 2210 d = access(cp ? local : ".", 2); 2211 if (cp) 2212 *cp = '/'; 2213 if (d < 0) { 2214 perror(local); 2215 return ((char *)0); 2216 } 2217 if (strlcpy(new, local, sizeof (new)) >= sizeof (new)) 2218 (void) printf("gunique: too long: local %s, %d, new %d\n", 2219 local, strlen(local), sizeof (new)); 2220 2221 cp = new + strlen(new); 2222 *cp++ = '.'; 2223 while (!d) { 2224 if (++count == 100) { 2225 (void) printf( 2226 "gunique: can't find unique file name.\n"); 2227 return (NULL); 2228 } 2229 *cp++ = ext; 2230 *cp = '\0'; 2231 if (ext == '9') 2232 ext = '0'; 2233 else 2234 ext++; 2235 if ((d = access(new, 0)) < 0) 2236 break; 2237 if (ext != '0') 2238 cp--; 2239 else if (*(cp - 2) == '.') 2240 *(cp - 1) = '1'; 2241 else { 2242 *(cp - 2) = *(cp - 2) + 1; 2243 cp--; 2244 } 2245 } 2246 return (new); 2247 } 2248 2249 /* 2250 * This is a wrap-around function for inet_ntop(). In case the af is AF_INET6 2251 * and the address pointed by src is a IPv4-mapped IPv6 address, it 2252 * returns printable IPv4 address, not IPv4-mapped IPv6 address. In other cases 2253 * it behaves just like inet_ntop(). 2254 */ 2255 const char * 2256 inet_ntop_native(int af, const void *src, char *dst, size_t size) 2257 { 2258 struct in_addr src4; 2259 const char *result; 2260 struct sockaddr_in *sin; 2261 struct sockaddr_in6 *sin6; 2262 2263 if (af == AF_INET6) { 2264 sin6 = (struct sockaddr_in6 *)src; 2265 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 2266 IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, &src4); 2267 result = inet_ntop(AF_INET, &src4, dst, size); 2268 } else { 2269 result = inet_ntop(AF_INET6, &sin6->sin6_addr, 2270 dst, size); 2271 } 2272 } else { 2273 sin = (struct sockaddr_in *)src; 2274 result = inet_ntop(af, &sin->sin_addr, dst, size); 2275 } 2276 2277 return (result); 2278 } 2279 2280 int 2281 secure_command(char *cmd) 2282 { 2283 unsigned char *in = NULL, *out = NULL; 2284 int length = 0; 2285 size_t inlen; 2286 2287 if ((auth_type != AUTHTYPE_NONE) && clevel != PROT_C) { 2288 gss_buffer_desc in_buf, out_buf; 2289 OM_uint32 maj_stat, min_stat; 2290 2291 /* secure_command (based on level) */ 2292 if (auth_type == AUTHTYPE_GSSAPI) { 2293 OM_uint32 expire_time; 2294 int conf_state; 2295 /* clevel = PROT_P; */ 2296 in_buf.value = cmd; 2297 in_buf.length = strlen(cmd) + 1; 2298 2299 maj_stat = gss_context_time(&min_stat, gcontext, 2300 &expire_time); 2301 if (GSS_ERROR(maj_stat)) { 2302 user_gss_error(maj_stat, min_stat, 2303 "gss context has expired"); 2304 fatal("Your gss credentials have expired. " 2305 "Good-bye!"); 2306 } 2307 maj_stat = gss_seal(&min_stat, gcontext, 2308 (clevel == PROT_P), /* private */ 2309 GSS_C_QOP_DEFAULT, 2310 &in_buf, &conf_state, 2311 &out_buf); 2312 if (maj_stat != GSS_S_COMPLETE) { 2313 /* generally need to deal */ 2314 user_gss_error(maj_stat, min_stat, 2315 (clevel == PROT_P) ? 2316 "gss_seal ENC didn't complete": 2317 "gss_seal MIC didn't complete"); 2318 } else if ((clevel == PROT_P) && !conf_state) { 2319 (void) fprintf(stderr, 2320 "GSSAPI didn't encrypt message"); 2321 out = out_buf.value; 2322 } else { 2323 if (debug) 2324 (void) fprintf(stderr, 2325 "sealed (%s) %d bytes\n", 2326 clevel == PROT_P ? "ENC" : "MIC", 2327 out_buf.length); 2328 2329 out = out_buf.value; 2330 } 2331 } 2332 /* Other auth types go here ... */ 2333 inlen = ((4 * out_buf.length) / 3) + 4; 2334 in = (uchar_t *)malloc(inlen); 2335 if (in == NULL) { 2336 gss_release_buffer(&min_stat, &out_buf); 2337 fatal("Memory error allocating space for response."); 2338 } 2339 length = out_buf.length; 2340 if (auth_error = radix_encode(out, in, inlen, &length, 0)) { 2341 (void) fprintf(stderr, 2342 "Couldn't base 64 encode command (%s)\n", 2343 radix_error(auth_error)); 2344 free(in); 2345 gss_release_buffer(&min_stat, &out_buf); 2346 return (0); 2347 } 2348 2349 (void) fprintf(ctrl_out, "%s %s", 2350 clevel == PROT_P ? "ENC" : "MIC", in); 2351 2352 free(in); 2353 gss_release_buffer(&min_stat, &out_buf); 2354 2355 if (debug) 2356 (void) fprintf(stderr, 2357 "secure_command(%s)\nencoding %d bytes %s %s\n", 2358 cmd, length, 2359 (clevel == PROT_P) ? "ENC" : "MIC", in); 2360 } else { 2361 /* 2362 * auth_type = AUTHTYPE_NONE or 2363 * command channel is not protected 2364 */ 2365 fputs(cmd, ctrl_out); 2366 } 2367 2368 (void) fprintf(ctrl_out, "\r\n"); 2369 (void) fflush(ctrl_out); 2370 return (1); 2371 } 2372 2373 unsigned int maxbuf; 2374 unsigned char *ucbuf; 2375 2376 void 2377 setpbsz(unsigned int size) 2378 { 2379 unsigned int actualbuf; 2380 int oldverbose; 2381 2382 if (ucbuf) 2383 (void) free(ucbuf); 2384 actualbuf = size; 2385 while ((ucbuf = (unsigned char *)malloc(actualbuf)) == NULL) { 2386 if (actualbuf) 2387 actualbuf >>= 2; 2388 else { 2389 perror("Error while trying to malloc PROT buffer:"); 2390 exit(1); 2391 } 2392 } 2393 oldverbose = verbose; 2394 verbose = 0; 2395 reply_parse = "PBSZ="; 2396 if (command("PBSZ %u", actualbuf) != COMPLETE) 2397 fatal("Cannot set PROT buffer size"); 2398 if (reply_parse) { 2399 if ((maxbuf = (unsigned int) atol(reply_parse)) > actualbuf) 2400 maxbuf = actualbuf; 2401 } else 2402 maxbuf = actualbuf; 2403 reply_parse = NULL; 2404 verbose = oldverbose; 2405 } 2406 2407 /* 2408 * Do the base 64 decoding of the raw input buffer, b64_buf. 2409 * Also do the verification and decryption, if required. 2410 * retval contains the current error code number 2411 * 2412 * returns: 2413 * (RFC 2228: error returns are 3 digit numbers of the form 5xy) 2414 * 5 if an error occurred 2415 */ 2416 static int 2417 decode_reply(uchar_t *plain_buf, int ilen, uchar_t *b64_buf, int retval, 2418 boolean_t *again) 2419 { 2420 int len; 2421 int safe = 0; 2422 2423 *again = 0; 2424 2425 if (!b64_buf[0]) /* if there is no string, no problem */ 2426 return (retval); 2427 2428 if ((auth_type == AUTHTYPE_NONE)) { 2429 (void) printf("Cannot decode reply:\n%d %s\n", code, b64_buf); 2430 return ('5'); 2431 } 2432 2433 switch (code) { 2434 2435 case 631: /* 'safe' */ 2436 safe = 1; 2437 break; 2438 2439 case 632: /* 'private' */ 2440 break; 2441 2442 case 633: /* 'confidential' */ 2443 break; 2444 2445 default: 2446 (void) printf("Unknown reply: %d %s\n", code, b64_buf); 2447 return ('5'); 2448 } 2449 2450 /* decode the base64 encoded message */ 2451 auth_error = radix_encode(b64_buf, plain_buf, ilen, &len, 1); 2452 2453 if (auth_error) { 2454 (void) printf("Can't base 64 decode reply %d (%s)\n\"%s\"\n", 2455 code, radix_error(auth_error), b64_buf); 2456 return ('5'); 2457 } 2458 2459 if (auth_type == AUTHTYPE_GSSAPI) { 2460 gss_buffer_desc xmit_buf, msg_buf; 2461 OM_uint32 maj_stat, min_stat; 2462 int conf_state = safe; 2463 xmit_buf.value = plain_buf; 2464 xmit_buf.length = len; 2465 2466 /* decrypt/verify the message */ 2467 maj_stat = gss_unseal(&min_stat, gcontext, 2468 &xmit_buf, &msg_buf, &conf_state, NULL); 2469 if (maj_stat != GSS_S_COMPLETE) { 2470 user_gss_error(maj_stat, min_stat, 2471 "failed unsealing reply"); 2472 return ('5'); 2473 } 2474 if (msg_buf.length < ilen - 2 - 1) { 2475 memcpy(plain_buf, msg_buf.value, msg_buf.length); 2476 strcpy((char *)&plain_buf[msg_buf.length], "\r\n"); 2477 gss_release_buffer(&min_stat, &msg_buf); 2478 *again = 1; 2479 } else { 2480 user_gss_error(maj_stat, min_stat, 2481 "reply was too long"); 2482 return ('5'); 2483 } 2484 } /* end if GSSAPI */ 2485 2486 /* Other auth types go here... */ 2487 2488 return (retval); 2489 } 2490