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