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