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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 #pragma ident "%Z%%M% %I% %E% SMI" 40 41 42 /* 43 * FTP User Program -- Command Routines. 44 */ 45 #define FTP_NAMES 46 #include "ftp_var.h" 47 48 FILE *tmp_nlst = NULL; /* tmp file; holds NLST results for mget, etc */ 49 50 static char *mname; 51 static jmp_buf jabort; 52 static jmp_buf abortprox; 53 54 static char *remglob(char *argv[], int doswitch); 55 static char *onoff(int bool); 56 static int confirm(char *cmd, char *file); 57 static int globulize(char **cpp); 58 static void proxabort(int sig); 59 static void mabort(int sig); 60 static char *dotrans(char *name); 61 static char *domap(char *name); 62 static void getit(int argc, char *argv[], int restartit, char *mode); 63 64 static char *getlevel(int); 65 66 /* Prompt for command argument, add to buffer with space separator */ 67 static int 68 prompt_for_arg(char *buffer, int buffer_size, char *prompt) 69 { 70 if (strlen(buffer) > buffer_size - 2) { 71 (void) printf("Line too long\n"); 72 return (-1); 73 } 74 strcat(buffer, " "); 75 stop_timer(); 76 (void) printf("(%s) ", prompt); 77 if (fgets(buffer + strlen(buffer), buffer_size - strlen(buffer), stdin) 78 == NULL) { 79 reset_timer(); 80 return (-1); 81 } 82 83 /* Flush what didn't fit in the buffer */ 84 if (buffer[strlen(buffer)-1] != '\n') { 85 while (fgetc(stdin) != '\n' && !ferror(stdin) && !feof(stdin)) 86 ; 87 (void) printf("Line too long\n"); 88 reset_timer(); 89 return (-1); 90 } else 91 buffer[strlen(buffer)-1] = 0; 92 93 reset_timer(); 94 return (0); 95 } 96 97 98 /* 99 * Connect to peer server and 100 * auto-login, if possible. 101 */ 102 void 103 setpeer(int argc, char *argv[]) 104 { 105 char *host; 106 107 if (connected) { 108 (void) printf("Already connected to %s, use close first.\n", 109 hostname); 110 code = -1; 111 return; 112 } 113 if (argc < 2) { 114 if (prompt_for_arg(line, sizeof (line), "to") == -1) { 115 code = -1; 116 return; 117 } 118 makeargv(); 119 argc = margc; 120 argv = margv; 121 } 122 if (argc > 3 || argc < 2) { 123 (void) printf("usage: %s host-name [port]\n", argv[0]); 124 code = -1; 125 return; 126 } 127 strcpy(typename, "ascii"); 128 host = hookup(argv[1], (argc > 2 ? argv[2] : "ftp")); 129 if (host) { 130 int overbose; 131 extern char reply_string[]; 132 133 connected = 1; 134 /* 135 * Set up defaults for FTP. 136 */ 137 clevel = dlevel = PROT_C; 138 if (autoauth) { 139 if (do_auth() && autoencrypt) { 140 clevel = PROT_P; 141 setpbsz(1<<20); 142 if (command("PROT P") == COMPLETE) 143 dlevel = PROT_P; 144 else { 145 (void) fprintf(stderr, 146 "%s: couldn't enable encryption\n", 147 argv[0]); 148 /* unable to encrypt command channel, too! */ 149 dlevel = clevel = PROT_C; 150 } 151 } 152 if ((auth_type != AUTHTYPE_NONE) && (clevel == PROT_C)) 153 clevel = PROT_S; 154 } 155 156 if (autologin) 157 (void) login(argv[1]); 158 /* if skipsyst is enabled, then don't send SYST command */ 159 if (skipsyst) 160 return; 161 162 overbose = verbose; 163 if (debug == 0) 164 verbose = -1; 165 if (command("SYST") == COMPLETE && overbose) { 166 char *cp, c; 167 168 cp = index(reply_string+4, ' '); 169 if (cp == NULL) 170 cp = index(reply_string+4, '\r'); 171 if (cp) { 172 if (cp[-1] == '.') 173 cp--; 174 c = *cp; 175 *cp = '\0'; 176 } 177 178 (void) printf("Remote system type is %s.\n", 179 reply_string+4); 180 if (cp) 181 *cp = c; 182 } 183 if (strncmp(reply_string, "215 UNIX Type: L8", 17) == 0) { 184 setbinary(0, NULL); 185 if (overbose) 186 (void) printf( 187 "Using %s mode to transfer files.\n", 188 typename); 189 } else if (overbose && 190 strncmp(reply_string, "215 TOPS20", 10) == 0) { 191 (void) printf( 192 "Remember to set tenex mode when transfering " 193 "binary files from this machine.\n"); 194 } 195 verbose = overbose; 196 } 197 } 198 199 static struct types { 200 char *t_name; 201 char *t_mode; 202 int t_type; 203 char *t_arg; 204 } types[] = { 205 { "ascii", "A", TYPE_A, 0 }, 206 { "binary", "I", TYPE_I, 0 }, 207 { "image", "I", TYPE_I, 0 }, 208 { "ebcdic", "E", TYPE_E, 0 }, 209 { "tenex", "L", TYPE_L, bytename }, 210 0 211 }; 212 213 /* 214 * Set transfer type. 215 */ 216 void 217 settype(int argc, char *argv[]) 218 { 219 struct types *p; 220 int comret; 221 222 if (argc > 2) { 223 char *sep; 224 225 (void) printf("usage: %s [", argv[0]); 226 sep = " "; 227 for (p = types; p->t_name; p++) { 228 (void) printf("%s%s", sep, p->t_name); 229 if (*sep == ' ') 230 sep = " | "; 231 } 232 (void) printf(" ]\n"); 233 code = -1; 234 return; 235 } 236 if (argc < 2) { 237 (void) printf("Using %s mode to transfer files.\n", typename); 238 code = 0; 239 return; 240 } 241 for (p = types; p->t_name; p++) 242 if (strcmp(argv[1], p->t_name) == 0) 243 break; 244 if (p->t_name == 0) { 245 (void) printf("%s: unknown mode\n", argv[1]); 246 code = -1; 247 return; 248 } 249 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 250 comret = command("TYPE %s %s", p->t_mode, p->t_arg); 251 else 252 comret = command("TYPE %s", p->t_mode); 253 if (comret == COMPLETE) { 254 (void) strcpy(typename, p->t_name); 255 type = p->t_type; 256 } 257 } 258 259 /* 260 * Set binary transfer type. 261 */ 262 /*ARGSUSED*/ 263 void 264 setbinary(int argc, char *argv[]) 265 { 266 call(settype, "type", "binary", 0); 267 } 268 269 /* 270 * Set ascii transfer type. 271 */ 272 /*ARGSUSED*/ 273 void 274 setascii(int argc, char *argv[]) 275 { 276 call(settype, "type", "ascii", 0); 277 } 278 279 /* 280 * Set tenex transfer type. 281 */ 282 /*ARGSUSED*/ 283 void 284 settenex(int argc, char *argv[]) 285 { 286 call(settype, "type", "tenex", 0); 287 } 288 289 /* 290 * Set ebcdic transfer type. 291 */ 292 /*ARGSUSED*/ 293 void 294 setebcdic(int argc, char *argv[]) 295 { 296 call(settype, "type", "ebcdic", 0); 297 } 298 299 /* 300 * Set file transfer mode. 301 */ 302 /*ARGSUSED*/ 303 void 304 setmode(int argc, char *argv[]) 305 { 306 (void) printf("We only support %s mode, sorry.\n", modename); 307 code = -1; 308 } 309 310 /* 311 * Set file transfer format. 312 */ 313 /*ARGSUSED*/ 314 void 315 setform(int argc, char *argv[]) 316 { 317 (void) printf("We only support %s format, sorry.\n", formname); 318 code = -1; 319 } 320 321 /* 322 * Set file transfer structure. 323 */ 324 /*ARGSUSED*/ 325 void 326 setstruct(int argc, char *argv[]) 327 { 328 329 (void) printf("We only support %s structure, sorry.\n", structname); 330 code = -1; 331 } 332 333 /* 334 * Send a single file. 335 */ 336 void 337 put(int argc, char *argv[]) 338 { 339 char *cmd; 340 int loc = 0; 341 char *oldargv1; 342 343 if (argc == 2) { 344 argc++; 345 argv[2] = argv[1]; 346 loc++; 347 } 348 if (argc < 2) { 349 if (prompt_for_arg(line, sizeof (line), "local-file") == -1) { 350 code = -1; 351 return; 352 } 353 makeargv(); 354 argc = margc; 355 argv = margv; 356 } 357 if (argc < 2) { 358 usage: 359 (void) printf("usage: %s local-file remote-file\n", argv[0]); 360 code = -1; 361 return; 362 } 363 if (argc < 3) { 364 if (prompt_for_arg(line, sizeof (line), "remote-file") == -1) { 365 code = -1; 366 return; 367 } 368 makeargv(); 369 argc = margc; 370 argv = margv; 371 } 372 if (argc < 3) 373 goto usage; 374 oldargv1 = argv[1]; 375 if (!globulize(&argv[1])) { 376 code = -1; 377 return; 378 } 379 /* 380 * If "globulize" modifies argv[1], and argv[2] is a copy of 381 * the old argv[1], make it a copy of the new argv[1]. 382 */ 383 if (argv[1] != oldargv1 && argv[2] == oldargv1) { 384 argv[2] = argv[1]; 385 } 386 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); 387 if (loc && ntflag) { 388 argv[2] = dotrans(argv[2]); 389 } 390 if (loc && mapflag) { 391 argv[2] = domap(argv[2]); 392 } 393 sendrequest(cmd, argv[1], argv[2], 1); 394 } 395 396 /*ARGSUSED*/ 397 static void 398 mabort(int sig) 399 { 400 int ointer; 401 402 (void) printf("\n"); 403 (void) fflush(stdout); 404 if (mflag && fromatty) { 405 ointer = interactive; 406 interactive = 1; 407 if (confirm("Continue with", mname)) { 408 interactive = ointer; 409 longjmp(jabort, 0); 410 } 411 interactive = ointer; 412 } 413 mflag = 0; 414 longjmp(jabort, 0); 415 } 416 417 /* 418 * Send multiple files. 419 */ 420 void 421 mput(int argc, char *argv[]) 422 { 423 int i; 424 int ointer; 425 void (*oldintr)(); 426 char *tp; 427 int len; 428 429 if (argc < 2) { 430 if (prompt_for_arg(line, sizeof (line), "local-files") == -1) { 431 code = -1; 432 return; 433 } 434 makeargv(); 435 argc = margc; 436 argv = margv; 437 } 438 if (argc < 2) { 439 (void) printf("usage: %s local-files\n", argv[0]); 440 code = -1; 441 return; 442 } 443 mname = argv[0]; 444 mflag = 1; 445 oldintr = signal(SIGINT, mabort); 446 (void) setjmp(jabort); 447 if (proxy) { 448 char *cp, *tp2, tmpbuf[MAXPATHLEN]; 449 450 while ((cp = remglob(argv, 0)) != NULL) { 451 if (*cp == 0) { 452 mflag = 0; 453 continue; 454 } 455 if (mflag && confirm(argv[0], cp)) { 456 tp = cp; 457 if (mcase) { 458 while (*tp) { 459 if ((len = 460 mblen(tp, MB_CUR_MAX)) <= 0) 461 len = 1; 462 if (islower(*tp)) 463 break; 464 tp += len; 465 } 466 if (!*tp) { 467 tp = cp; 468 tp2 = tmpbuf; 469 while (*tp) { 470 if ((len = mblen(tp, 471 MB_CUR_MAX)) <= 0) 472 len = 1; 473 memcpy(tp2, tp, len); 474 if (isupper(*tp2)) { 475 *tp2 = 'a' + 476 *tp2 - 'A'; 477 } 478 tp += len; 479 tp2 += len; 480 } 481 *tp2 = 0; 482 tp = tmpbuf; 483 } 484 } 485 if (ntflag) { 486 tp = dotrans(tp); 487 } 488 if (mapflag) { 489 tp = domap(tp); 490 } 491 sendrequest((sunique) ? "STOU" : "STOR", 492 cp, tp, 0); 493 if (!mflag && fromatty) { 494 ointer = interactive; 495 interactive = 1; 496 if (confirm("Continue with", "mput")) { 497 mflag++; 498 } 499 interactive = ointer; 500 } 501 } 502 } 503 (void) signal(SIGINT, oldintr); 504 mflag = 0; 505 return; 506 } 507 for (i = 1; i < argc; i++) { 508 char **cpp, **gargs; 509 510 if (!doglob) { 511 if (mflag && confirm(argv[0], argv[i])) { 512 tp = (ntflag) ? dotrans(argv[i]) : argv[i]; 513 tp = (mapflag) ? domap(tp) : tp; 514 sendrequest((sunique) ? "STOU" : "STOR", 515 argv[i], tp, 1); 516 if (!mflag && fromatty) { 517 ointer = interactive; 518 interactive = 1; 519 if (confirm("Continue with", "mput")) { 520 mflag++; 521 } 522 interactive = ointer; 523 } 524 } 525 continue; 526 } 527 gargs = glob(argv[i]); 528 if (globerr != NULL) { 529 (void) printf("%s\n", globerr); 530 if (gargs) 531 blkfree(gargs); 532 continue; 533 } 534 for (cpp = gargs; cpp && *cpp != NULL; cpp++) { 535 if (mflag && confirm(argv[0], *cpp)) { 536 tp = (ntflag) ? dotrans(*cpp) : *cpp; 537 tp = (mapflag) ? domap(tp) : tp; 538 sendrequest((sunique) ? "STOU" : "STOR", 539 *cpp, tp, 0); 540 if (!mflag && fromatty) { 541 ointer = interactive; 542 interactive = 1; 543 if (confirm("Continue with", "mput")) { 544 mflag++; 545 } 546 interactive = ointer; 547 } 548 } 549 } 550 if (gargs != NULL) 551 blkfree(gargs); 552 } 553 (void) signal(SIGINT, oldintr); 554 mflag = 0; 555 } 556 557 /* 558 * Restart transfer at a specific offset. 559 */ 560 void 561 restart(int argc, char *argv[]) 562 { 563 off_t orestart_point = restart_point; 564 565 if (argc > 2) { 566 (void) printf("usage: %s [marker]\n", argv[0]); 567 code = -1; 568 return; 569 } 570 if (argc == 2) { 571 longlong_t rp; 572 char *endp; 573 574 errno = 0; 575 rp = strtoll(argv[1], &endp, 10); 576 if (errno || rp < 0 || *endp != '\0') 577 (void) printf("%s: Invalid offset `%s'\n", 578 argv[0], argv[1]); 579 else 580 restart_point = rp; 581 } 582 if (restart_point == 0) { 583 if (orestart_point == 0) 584 (void) printf("No restart marker defined\n"); 585 else 586 (void) printf("Restart marker cleared\n"); 587 } else 588 (void) printf( 589 "Restarting at %lld for next get, put or append\n", 590 (longlong_t)restart_point); 591 } 592 593 void 594 reget(int argc, char *argv[]) 595 { 596 getit(argc, argv, 1, "r+w"); 597 } 598 599 void 600 get(int argc, char *argv[]) 601 { 602 getit(argc, argv, 0, restart_point ? "r+w" : "w"); 603 } 604 605 /* 606 * Receive one file. 607 */ 608 static void 609 getit(int argc, char *argv[], int restartit, char *mode) 610 { 611 int loc = 0; 612 int len; 613 int allowpipe = 1; 614 615 if (argc == 2) { 616 argc++; 617 argv[2] = argv[1]; 618 /* Only permit !file if two arguments. */ 619 allowpipe = 0; 620 loc++; 621 } 622 if (argc < 2) { 623 if (prompt_for_arg(line, sizeof (line), "remote-file") == -1) { 624 code = -1; 625 return; 626 } 627 makeargv(); 628 argc = margc; 629 argv = margv; 630 } 631 if (argc < 2) { 632 usage: 633 (void) printf("usage: %s remote-file [ local-file ]\n", 634 argv[0]); 635 code = -1; 636 return; 637 } 638 if (argc < 3) { 639 if (prompt_for_arg(line, sizeof (line), "local-file") == -1) { 640 code = -1; 641 return; 642 } 643 makeargv(); 644 argc = margc; 645 argv = margv; 646 } 647 if (argc < 3) 648 goto usage; 649 if (!globulize(&argv[2])) { 650 code = -1; 651 return; 652 } 653 if (loc && mcase) { 654 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN]; 655 656 while (*tp) { 657 if ((len = mblen(tp, MB_CUR_MAX)) <= 0) 658 len = 1; 659 if (islower(*tp)) 660 break; 661 tp += len; 662 } 663 if (!*tp) { 664 tp = argv[2]; 665 tp2 = tmpbuf; 666 while (*tp) { 667 if ((len = mblen(tp, MB_CUR_MAX)) <= 0) 668 len = 1; 669 memcpy(tp2, tp, len); 670 if (isupper(*tp2)) 671 *tp2 = 'a' + *tp2 - 'A'; 672 tp += len; 673 tp2 += len; 674 } 675 *tp2 = 0; 676 argv[2] = tmpbuf; 677 } 678 } 679 if (loc && ntflag) { 680 argv[2] = dotrans(argv[2]); 681 } 682 if (loc && mapflag) { 683 argv[2] = domap(argv[2]); 684 } 685 if (restartit) { 686 struct stat stbuf; 687 688 if (stat(argv[2], &stbuf) < 0) { 689 perror(argv[2]); 690 code = -1; 691 return; 692 } 693 restart_point = stbuf.st_size; 694 } 695 recvrequest("RETR", argv[2], argv[1], mode, allowpipe); 696 restart_point = 0; 697 } 698 699 /* 700 * Get multiple files. 701 */ 702 void 703 mget(int argc, char *argv[]) 704 { 705 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN]; 706 int ointer; 707 void (*oldintr)(); 708 int need_convert; 709 int len; 710 711 if (argc < 2) { 712 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) { 713 code = -1; 714 return; 715 } 716 makeargv(); 717 argc = margc; 718 argv = margv; 719 } 720 if (argc < 2) { 721 (void) printf("usage: %s remote-files\n", argv[0]); 722 code = -1; 723 return; 724 } 725 mname = argv[0]; 726 mflag = 1; 727 oldintr = signal(SIGINT, mabort); 728 (void) setjmp(jabort); 729 while ((cp = remglob(argv, proxy)) != NULL) { 730 if (*cp == '\0') { 731 mflag = 0; 732 continue; 733 } 734 if (mflag && confirm(argv[0], cp)) { 735 strcpy(tmpbuf, cp); 736 tp = tmpbuf; 737 need_convert = 1; 738 if (mcase) { 739 tp2 = tp; 740 while (*tp2 && need_convert) { 741 /* Need any case convert? */ 742 if (islower(*tp2)) 743 need_convert = 0; 744 if ((len = mblen(tp2, MB_CUR_MAX)) <= 0) 745 len = 1; 746 tp2 += len; 747 } 748 tp2 = tp; 749 while (need_convert && *tp2) { 750 /* Convert to lower case */ 751 if (isupper(*tp2)) 752 *tp2 = tolower(*tp2); 753 if ((len = mblen(tp2, MB_CUR_MAX)) <= 0) 754 len = 1; 755 tp2 += len; 756 } 757 } 758 759 if (ntflag) { 760 tp = dotrans(tp); 761 } 762 if (mapflag) { 763 tp = domap(tp); 764 } 765 recvrequest("RETR", tp, cp, "w", 0); 766 restart_point = 0; 767 if (!mflag && fromatty) { 768 ointer = interactive; 769 interactive = 1; 770 if (confirm("Continue with", "mget")) { 771 mflag++; 772 } 773 interactive = ointer; 774 } 775 } 776 } 777 (void) signal(SIGINT, oldintr); 778 mflag = 0; 779 } 780 781 static char * 782 remglob(char *argv[], int doswitch) 783 { 784 static char buf[MAXPATHLEN]; 785 static char **args; 786 int oldverbose, oldhash; 787 char *cp; 788 789 if (!mflag) { 790 if (!doglob) { 791 args = NULL; 792 } else { 793 if (tmp_nlst != NULL) { 794 (void) fclose(tmp_nlst); 795 tmp_nlst = NULL; 796 } 797 } 798 return (NULL); 799 } 800 if (!doglob) { 801 if (args == NULL) 802 args = argv; 803 if ((cp = *++args) == NULL) 804 args = NULL; 805 return (cp); 806 } 807 if (tmp_nlst == NULL) { 808 if ((tmp_nlst = tmpfile()) == NULL) { 809 (void) printf("%s\n", strerror(errno)); 810 return (NULL); 811 } 812 oldverbose = verbose, verbose = 0; 813 oldhash = hash, hash = 0; 814 if (doswitch) { 815 pswitch(!proxy); 816 } 817 for (; *++argv != NULL; ) 818 recvrequest("NLST", NULL, *argv, "", 0); 819 rewind(tmp_nlst); 820 if (doswitch) { 821 pswitch(!proxy); 822 } 823 verbose = oldverbose; hash = oldhash; 824 } 825 reset_timer(); 826 if (fgets(buf, sizeof (buf), tmp_nlst) == NULL) { 827 (void) fclose(tmp_nlst), tmp_nlst = NULL; 828 return (NULL); 829 } 830 if ((cp = index(buf, '\n')) != NULL) 831 *cp = '\0'; 832 return (buf); 833 } 834 835 static char * 836 onoff(int bool) 837 { 838 return (bool ? "on" : "off"); 839 } 840 841 /* 842 * Show status. 843 */ 844 /*ARGSUSED*/ 845 void 846 status(int argc, char *argv[]) 847 { 848 int i; 849 char *levelp; 850 851 if (connected) 852 (void) printf("Connected to %s.\n", hostname); 853 else 854 (void) printf("Not connected.\n"); 855 if (!proxy) { 856 pswitch(1); 857 if (connected) { 858 (void) printf("Connected for proxy commands to %s.\n", 859 hostname); 860 } else { 861 (void) printf("No proxy connection.\n"); 862 } 863 pswitch(0); 864 } 865 866 if (auth_type != AUTHTYPE_NONE) 867 (void) printf("Authentication type: %s\n", 868 GSS_AUTHTYPE_NAME(auth_type)); 869 else 870 (void) printf("Not authenticated.\n"); 871 (void) printf("Mechanism: %s\n", mechstr); 872 (void) printf("Autoauth: %s; Autologin: %s\n", 873 onoff(autoauth), onoff(autologin)); 874 levelp = getlevel(clevel); 875 (void) printf("Control Channel Protection Level: %s\n", 876 levelp ? levelp : "<unknown>"); 877 levelp = getlevel(dlevel); 878 (void) printf("Data Channel Protection Level: %s\n", 879 levelp ? levelp : "<unknown>"); 880 881 (void) printf("Passive mode: %s.\n", onoff(passivemode)); 882 (void) printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 883 modename, typename, formname, structname); 884 (void) printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 885 onoff(verbose), onoff(bell), onoff(interactive), 886 onoff(doglob)); 887 (void) printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), 888 onoff(runique)); 889 (void) printf("Case: %s; CR stripping: %s\n", 890 onoff(mcase), onoff(crflag)); 891 if (ntflag) { 892 (void) printf("Ntrans: (in) %s (out) %s\n", ntin, ntout); 893 } else { 894 (void) printf("Ntrans: off\n"); 895 } 896 if (mapflag) { 897 (void) printf("Nmap: (in) %s (out) %s\n", mapin, mapout); 898 } else { 899 (void) printf("Nmap: off\n"); 900 } 901 (void) printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 902 onoff(hash), onoff(sendport)); 903 if (macnum > 0) { 904 (void) printf("Macros:\n"); 905 for (i = 0; i < macnum; i++) { 906 (void) printf("\t%s\n", macros[i].mac_name); 907 } 908 } 909 code = 0; 910 } 911 912 /* 913 * Set beep on cmd completed mode. 914 */ 915 /*ARGSUSED*/ 916 void 917 setbell(int argc, char *argv[]) 918 { 919 bell = !bell; 920 (void) printf("Bell mode %s.\n", onoff(bell)); 921 code = bell; 922 } 923 924 /* 925 * Turn on packet tracing. 926 */ 927 /*ARGSUSED*/ 928 void 929 settrace(int argc, char *argv[]) 930 { 931 trace = !trace; 932 (void) printf("Packet tracing %s.\n", onoff(trace)); 933 code = trace; 934 } 935 936 /* 937 * Toggle hash mark printing during transfers. 938 */ 939 /*ARGSUSED*/ 940 void 941 sethash(int argc, char *argv[]) 942 { 943 hash = !hash; 944 (void) printf("Hash mark printing %s", onoff(hash)); 945 code = hash; 946 if (hash) 947 (void) printf(" (%d bytes/hash mark)", HASHSIZ); 948 (void) printf(".\n"); 949 } 950 951 /* 952 * Turn on printing of server echo's. 953 */ 954 /*ARGSUSED*/ 955 void 956 setverbose(int argc, char *argv[]) 957 { 958 verbose = !verbose; 959 (void) printf("Verbose mode %s.\n", onoff(verbose)); 960 code = verbose; 961 } 962 963 /* 964 * Toggle PORT cmd use before each data connection. 965 */ 966 /*ARGSUSED*/ 967 void 968 setport(int argc, char *argv[]) 969 { 970 sendport = !sendport; 971 (void) printf("Use of PORT cmds %s.\n", onoff(sendport)); 972 code = sendport; 973 } 974 975 /* 976 * Turn on interactive prompting 977 * during mget, mput, and mdelete. 978 */ 979 /*ARGSUSED*/ 980 void 981 setprompt(int argc, char *argv[]) 982 { 983 interactive = !interactive; 984 (void) printf("Interactive mode %s.\n", onoff(interactive)); 985 code = interactive; 986 } 987 988 /* 989 * Toggle metacharacter interpretation 990 * on local file names. 991 */ 992 /*ARGSUSED*/ 993 void 994 setglob(int argc, char *argv[]) 995 { 996 doglob = !doglob; 997 (void) printf("Globbing %s.\n", onoff(doglob)); 998 code = doglob; 999 } 1000 1001 /* 1002 * Set debugging mode on/off and/or 1003 * set level of debugging. 1004 */ 1005 void 1006 setdebug(int argc, char *argv[]) 1007 { 1008 int val; 1009 1010 if (argc > 1) { 1011 val = atoi(argv[1]); 1012 if (val < 0) { 1013 (void) printf("%s: bad debugging value.\n", argv[1]); 1014 code = -1; 1015 return; 1016 } 1017 } else 1018 val = !debug; 1019 debug = val; 1020 if (debug) 1021 options |= SO_DEBUG; 1022 else 1023 options &= ~SO_DEBUG; 1024 (void) printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 1025 code = debug > 0; 1026 } 1027 1028 /* 1029 * Set current working directory 1030 * on remote machine. 1031 */ 1032 void 1033 cd(int argc, char *argv[]) 1034 { 1035 if (argc < 2) { 1036 if (prompt_for_arg(line, sizeof (line), "remote-directory") < 1037 0) { 1038 code = -1; 1039 return; 1040 } 1041 makeargv(); 1042 argc = margc; 1043 argv = margv; 1044 } 1045 if (argc < 2) { 1046 (void) printf("usage: %s remote-directory\n", argv[0]); 1047 code = -1; 1048 return; 1049 } 1050 (void) command("CWD %s", argv[1]); 1051 } 1052 1053 /* 1054 * Set current working directory 1055 * on local machine. 1056 */ 1057 void 1058 lcd(int argc, char *argv[]) 1059 { 1060 char buf[MAXPATHLEN], *bufptr; 1061 1062 if (argc < 2) 1063 argc++, argv[1] = home; 1064 if (argc != 2) { 1065 (void) printf("usage: %s local-directory\n", argv[0]); 1066 code = -1; 1067 return; 1068 } 1069 if (!globulize(&argv[1])) { 1070 code = -1; 1071 return; 1072 } 1073 if (chdir(argv[1]) < 0) { 1074 perror(argv[1]); 1075 code = -1; 1076 return; 1077 } 1078 bufptr = getcwd(buf, MAXPATHLEN); 1079 /* 1080 * Even though chdir may succeed, getcwd may fail if a component 1081 * of the pwd is unreadable. In this case, print the argument to 1082 * chdir as the resultant directory, since we know it succeeded above. 1083 */ 1084 (void) printf("Local directory now %s\n", (bufptr ? bufptr : argv[1])); 1085 code = 0; 1086 } 1087 1088 /* 1089 * Delete a single file. 1090 */ 1091 void 1092 delete(int argc, char *argv[]) 1093 { 1094 1095 if (argc < 2) { 1096 if (prompt_for_arg(line, sizeof (line), "remote-file") < 0) { 1097 code = -1; 1098 return; 1099 } 1100 makeargv(); 1101 argc = margc; 1102 argv = margv; 1103 } 1104 if (argc < 2) { 1105 (void) printf("usage: %s remote-file\n", argv[0]); 1106 code = -1; 1107 return; 1108 } 1109 (void) command("DELE %s", argv[1]); 1110 } 1111 1112 /* 1113 * Delete multiple files. 1114 */ 1115 void 1116 mdelete(int argc, char *argv[]) 1117 { 1118 char *cp; 1119 int ointer; 1120 void (*oldintr)(); 1121 1122 if (argc < 2) { 1123 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) { 1124 code = -1; 1125 return; 1126 } 1127 makeargv(); 1128 argc = margc; 1129 argv = margv; 1130 } 1131 if (argc < 2) { 1132 (void) printf("usage: %s remote-files\n", argv[0]); 1133 code = -1; 1134 return; 1135 } 1136 mname = argv[0]; 1137 mflag = 1; 1138 oldintr = signal(SIGINT, mabort); 1139 (void) setjmp(jabort); 1140 while ((cp = remglob(argv, 0)) != NULL) { 1141 if (*cp == '\0') { 1142 mflag = 0; 1143 continue; 1144 } 1145 if (mflag && confirm(argv[0], cp)) { 1146 (void) command("DELE %s", cp); 1147 if (!mflag && fromatty) { 1148 ointer = interactive; 1149 interactive = 1; 1150 if (confirm("Continue with", "mdelete")) { 1151 mflag++; 1152 } 1153 interactive = ointer; 1154 } 1155 } 1156 } 1157 (void) signal(SIGINT, oldintr); 1158 mflag = 0; 1159 } 1160 1161 /* 1162 * Rename a remote file. 1163 */ 1164 void 1165 renamefile(int argc, char *argv[]) 1166 { 1167 1168 if (argc < 2) { 1169 if (prompt_for_arg(line, sizeof (line), "from-name") < 0) { 1170 code = -1; 1171 return; 1172 } 1173 makeargv(); 1174 argc = margc; 1175 argv = margv; 1176 } 1177 if (argc < 2) { 1178 usage: 1179 (void) printf("%s from-name to-name\n", argv[0]); 1180 code = -1; 1181 return; 1182 } 1183 if (argc < 3) { 1184 if (prompt_for_arg(line, sizeof (line), "to-name") < 0) { 1185 code = -1; 1186 return; 1187 } 1188 makeargv(); 1189 argc = margc; 1190 argv = margv; 1191 } 1192 if (argc < 3) 1193 goto usage; 1194 if (command("RNFR %s", argv[1]) == CONTINUE) 1195 (void) command("RNTO %s", argv[2]); 1196 } 1197 1198 /* 1199 * Get a directory listing 1200 * of remote files. 1201 */ 1202 void 1203 ls(int argc, char *argv[]) 1204 { 1205 char *cmd; 1206 1207 if (argc < 2) 1208 argc++, argv[1] = NULL; 1209 if (argc < 3) 1210 argc++, argv[2] = "-"; 1211 if (argc > 3) { 1212 (void) printf("usage: %s remote-directory local-file\n", 1213 argv[0]); 1214 code = -1; 1215 return; 1216 } 1217 if (ls_invokes_NLST) { 1218 cmd = ((argv[0][0] == 'l' || argv[0][0] == 'n') ? 1219 "NLST" : "LIST"); 1220 } else { 1221 cmd = ((argv[0][0] == 'n') ? "NLST" : "LIST"); 1222 } 1223 if (strcmp(argv[2], "-") && !globulize(&argv[2])) { 1224 code = -1; 1225 return; 1226 } 1227 recvrequest(cmd, argv[2], argv[1], "w", 1); 1228 } 1229 1230 /* 1231 * Get a directory listing 1232 * of multiple remote files. 1233 */ 1234 void 1235 mls(int argc, char *argv[]) 1236 { 1237 char *cmd, mode[1], *dest; 1238 int ointer, i; 1239 void (*oldintr)(); 1240 1241 if (argc < 2) { 1242 if (prompt_for_arg(line, sizeof (line), "remote-files") < 0) { 1243 code = -1; 1244 return; 1245 } 1246 makeargv(); 1247 argc = margc; 1248 argv = margv; 1249 } 1250 if (argc < 3) { 1251 if (prompt_for_arg(line, sizeof (line), "local-file") < 0) { 1252 code = -1; 1253 return; 1254 } 1255 makeargv(); 1256 argc = margc; 1257 argv = margv; 1258 } 1259 if (argc < 3) { 1260 (void) printf("usage: %s remote-files local-file\n", argv[0]); 1261 code = -1; 1262 return; 1263 } 1264 dest = argv[argc - 1]; 1265 argv[argc - 1] = NULL; 1266 if (strcmp(dest, "-") && *dest != '|') 1267 if (!globulize(&dest) || 1268 !confirm("output to local-file:", dest)) { 1269 code = -1; 1270 return; 1271 } 1272 cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 1273 mname = argv[0]; 1274 mflag = 1; 1275 oldintr = signal(SIGINT, mabort); 1276 (void) setjmp(jabort); 1277 for (i = 1; mflag && i < argc-1; ++i) { 1278 *mode = (i == 1) ? 'w' : 'a'; 1279 recvrequest(cmd, dest, argv[i], mode, 1); 1280 if (!mflag && fromatty) { 1281 ointer = interactive; 1282 interactive = 1; 1283 if (confirm("Continue with", argv[0])) { 1284 mflag ++; 1285 } 1286 interactive = ointer; 1287 } 1288 } 1289 (void) signal(SIGINT, oldintr); 1290 mflag = 0; 1291 } 1292 1293 /* 1294 * Do a shell escape 1295 */ 1296 /*ARGSUSED*/ 1297 void 1298 shell(int argc, char *argv[]) 1299 { 1300 pid_t pid; 1301 void (*old1)(), (*old2)(); 1302 char *shellstring, *namep; 1303 int status; 1304 1305 stop_timer(); 1306 old1 = signal(SIGINT, SIG_IGN); 1307 old2 = signal(SIGQUIT, SIG_IGN); 1308 if ((pid = fork()) == 0) { 1309 closefrom(STDERR_FILENO + 1); 1310 (void) signal(SIGINT, SIG_DFL); 1311 (void) signal(SIGQUIT, SIG_DFL); 1312 shellstring = getenv("SHELL"); 1313 if (shellstring == NULL) 1314 shellstring = "/bin/sh"; 1315 namep = rindex(shellstring, '/'); 1316 if (namep == NULL) 1317 namep = shellstring; 1318 if (argc > 1) { 1319 if (debug) { 1320 (void) printf("%s -c %s\n", shellstring, 1321 altarg); 1322 (void) fflush(stdout); 1323 } 1324 execl(shellstring, namep, "-c", altarg, (char *)0); 1325 } else { 1326 if (debug) { 1327 (void) printf("%s\n", shellstring); 1328 (void) fflush(stdout); 1329 } 1330 execl(shellstring, namep, (char *)0); 1331 } 1332 perror(shellstring); 1333 code = -1; 1334 exit(1); 1335 } 1336 if (pid > 0) 1337 while (wait(&status) != pid) 1338 ; 1339 (void) signal(SIGINT, old1); 1340 (void) signal(SIGQUIT, old2); 1341 reset_timer(); 1342 if (pid == (pid_t)-1) { 1343 perror("Try again later"); 1344 code = -1; 1345 } else { 1346 code = 0; 1347 } 1348 } 1349 1350 /* 1351 * Send new user information (re-login) 1352 */ 1353 void 1354 user(int argc, char *argv[]) 1355 { 1356 char acct[80]; 1357 int n, aflag = 0; 1358 1359 if (argc < 2) { 1360 if (prompt_for_arg(line, sizeof (line), "username") < 0) { 1361 code = -1; 1362 return; 1363 } 1364 makeargv(); 1365 argc = margc; 1366 argv = margv; 1367 } 1368 if (argc > 4) { 1369 (void) printf("usage: %s username [password] [account]\n", 1370 argv[0]); 1371 code = -1; 1372 return; 1373 } 1374 if (argv[1] == 0) { 1375 (void) printf("access for user (nil) denied\n"); 1376 code = -1; 1377 return; 1378 } 1379 n = command("USER %s", argv[1]); 1380 if (n == CONTINUE) { 1381 int oldclevel; 1382 if (argc < 3) 1383 argv[2] = mygetpass("Password: "), argc++; 1384 if ((oldclevel = clevel) == PROT_S) 1385 clevel = PROT_P; 1386 n = command("PASS %s", argv[2]); 1387 /* level may have changed */ 1388 if (clevel == PROT_P) 1389 clevel = oldclevel; 1390 } 1391 if (n == CONTINUE) { 1392 if (argc < 4) { 1393 (void) printf("Account: "); (void) fflush(stdout); 1394 stop_timer(); 1395 (void) fgets(acct, sizeof (acct) - 1, stdin); 1396 reset_timer(); 1397 acct[strlen(acct) - 1] = '\0'; 1398 argv[3] = acct; argc++; 1399 } 1400 n = command("ACCT %s", argv[3]); 1401 aflag++; 1402 } 1403 if (n != COMPLETE) { 1404 (void) fprintf(stdout, "Login failed.\n"); 1405 return; 1406 } 1407 if (!aflag && argc == 4) { 1408 (void) command("ACCT %s", argv[3]); 1409 } 1410 } 1411 1412 /* 1413 * Print working directory. 1414 */ 1415 /*ARGSUSED*/ 1416 void 1417 pwd(int argc, char *argv[]) 1418 { 1419 (void) command("PWD"); 1420 } 1421 1422 /* 1423 * Make a directory. 1424 */ 1425 void 1426 makedir(int argc, char *argv[]) 1427 { 1428 if (argc < 2) { 1429 if (prompt_for_arg(line, sizeof (line), "directory-name") < 1430 0) { 1431 code = -1; 1432 return; 1433 } 1434 makeargv(); 1435 argc = margc; 1436 argv = margv; 1437 } 1438 if (argc < 2) { 1439 (void) printf("usage: %s directory-name\n", argv[0]); 1440 code = -1; 1441 return; 1442 } 1443 (void) command("MKD %s", argv[1]); 1444 } 1445 1446 /* 1447 * Remove a directory. 1448 */ 1449 void 1450 removedir(int argc, char *argv[]) 1451 { 1452 if (argc < 2) { 1453 if (prompt_for_arg(line, sizeof (line), "directory-name") < 1454 0) { 1455 code = -1; 1456 return; 1457 } 1458 makeargv(); 1459 argc = margc; 1460 argv = margv; 1461 } 1462 if (argc < 2) { 1463 (void) printf("usage: %s directory-name\n", argv[0]); 1464 code = -1; 1465 return; 1466 } 1467 (void) command("RMD %s", argv[1]); 1468 } 1469 1470 /* 1471 * Send a line, verbatim, to the remote machine. 1472 */ 1473 void 1474 quote(int argc, char *argv[]) 1475 { 1476 int i, n, len; 1477 char buf[FTPBUFSIZ]; 1478 1479 if (argc < 2) { 1480 if (prompt_for_arg(line, sizeof (line), 1481 "command line to send") == -1) { 1482 code = -1; 1483 return; 1484 } 1485 makeargv(); 1486 argc = margc; 1487 argv = margv; 1488 } 1489 if (argc < 2) { 1490 (void) printf("usage: %s line-to-send\n", argv[0]); 1491 code = -1; 1492 return; 1493 } 1494 len = snprintf(buf, sizeof (buf), "%s", argv[1]); 1495 if (len >= 0 && len < sizeof (buf) - 1) { 1496 for (i = 2; i < argc; i++) { 1497 n = snprintf(&buf[len], sizeof (buf) - len, " %s", 1498 argv[i]); 1499 if (n < 0 || n >= sizeof (buf) - len) 1500 break; 1501 len += n; 1502 } 1503 } 1504 if (command("%s", buf) == PRELIM) { 1505 while (getreply(0) == PRELIM) 1506 ; 1507 } 1508 } 1509 1510 /* 1511 * Send a line, verbatim, to the remote machine as a SITE command. 1512 */ 1513 void 1514 site(int argc, char *argv[]) 1515 { 1516 int i, n, len; 1517 char buf[FTPBUFSIZ]; 1518 1519 if (argc < 2) { 1520 if (prompt_for_arg(line, sizeof (line), 1521 "arguments to SITE command") == -1) { 1522 code = -1; 1523 return; 1524 } 1525 makeargv(); 1526 argc = margc; 1527 argv = margv; 1528 } 1529 if (argc < 2) { 1530 (void) printf("usage: %s arg1 [arg2] ...\n", argv[0]); 1531 code = -1; 1532 return; 1533 } 1534 len = snprintf(buf, sizeof (buf), "%s", argv[1]); 1535 if (len >= 0 && len < sizeof (buf) - 1) { 1536 for (i = 2; i < argc; i++) { 1537 n = snprintf(&buf[len], sizeof (buf) - len, " %s", 1538 argv[i]); 1539 if (n < 0 || n >= sizeof (buf) - len) 1540 break; 1541 len += n; 1542 } 1543 } 1544 if (command("SITE %s", buf) == PRELIM) { 1545 while (getreply(0) == PRELIM) 1546 ; 1547 } 1548 } 1549 1550 /* 1551 * Ask the other side for help. 1552 */ 1553 void 1554 rmthelp(int argc, char *argv[]) 1555 { 1556 int oldverbose = verbose; 1557 1558 verbose = 1; 1559 (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 1560 verbose = oldverbose; 1561 } 1562 1563 /* 1564 * Terminate session and exit. 1565 */ 1566 /*ARGSUSED*/ 1567 void 1568 quit(int argc, char *argv[]) 1569 { 1570 if (connected) 1571 disconnect(0, NULL); 1572 pswitch(1); 1573 if (connected) { 1574 disconnect(0, NULL); 1575 } 1576 exit(0); 1577 } 1578 1579 /* 1580 * Terminate session, but don't exit. 1581 */ 1582 /*ARGSUSED*/ 1583 void 1584 disconnect(int argc, char *argv[]) 1585 { 1586 extern FILE *ctrl_in, *ctrl_out; 1587 extern int data; 1588 1589 if (!connected) 1590 return; 1591 (void) command("QUIT"); 1592 if (ctrl_in) { 1593 reset_timer(); 1594 (void) fclose(ctrl_in); 1595 } 1596 if (ctrl_out) { 1597 reset_timer(); 1598 (void) fclose(ctrl_out); 1599 } 1600 ctrl_out = ctrl_in = NULL; 1601 connected = 0; 1602 data = -1; 1603 if (!proxy) { 1604 macnum = 0; 1605 } 1606 1607 auth_type = AUTHTYPE_NONE; 1608 clevel = dlevel = PROT_C; 1609 goteof = 0; 1610 } 1611 1612 static int 1613 confirm(char *cmd, char *file) 1614 { 1615 char line[FTPBUFSIZ]; 1616 1617 if (!interactive) 1618 return (1); 1619 stop_timer(); 1620 (void) printf("%s %s? ", cmd, file); 1621 (void) fflush(stdout); 1622 *line = '\0'; 1623 (void) fgets(line, sizeof (line), stdin); 1624 reset_timer(); 1625 return (*line != 'n' && *line != 'N'); 1626 } 1627 1628 void 1629 fatal(char *msg) 1630 { 1631 (void) fprintf(stderr, "ftp: %s\n", msg); 1632 exit(1); 1633 } 1634 1635 /* 1636 * Glob a local file name specification with 1637 * the expectation of a single return value. 1638 * Can't control multiple values being expanded 1639 * from the expression, we return only the first. 1640 */ 1641 static int 1642 globulize(char **cpp) 1643 { 1644 char **globbed; 1645 1646 if (!doglob) 1647 return (1); 1648 globbed = glob(*cpp); 1649 if (globbed != NULL && *globbed == NULL && globerr == NULL) 1650 globerr = "No match"; 1651 if (globerr != NULL) { 1652 (void) printf("%s: %s\n", *cpp, globerr); 1653 if (globbed) 1654 blkfree(globbed); 1655 return (0); 1656 } 1657 if (globbed) { 1658 *cpp = strdup(*globbed); 1659 blkfree(globbed); 1660 if (!*cpp) 1661 return (0); 1662 } 1663 return (1); 1664 } 1665 1666 void 1667 account(int argc, char *argv[]) 1668 { 1669 char acct[50], *ap; 1670 1671 if (argc > 1) { 1672 ++argv; 1673 --argc; 1674 (void) strncpy(acct, *argv, 49); 1675 acct[49] = '\0'; 1676 while (argc > 1) { 1677 --argc; 1678 ++argv; 1679 (void) strncat(acct, *argv, 49 - strlen(acct)); 1680 } 1681 ap = acct; 1682 } else { 1683 ap = mygetpass("Account:"); 1684 } 1685 (void) command("ACCT %s", ap); 1686 } 1687 1688 /*ARGSUSED*/ 1689 static void 1690 proxabort(int sig) 1691 { 1692 extern int proxy; 1693 1694 if (!proxy) { 1695 pswitch(1); 1696 } 1697 if (connected) { 1698 proxflag = 1; 1699 } else { 1700 proxflag = 0; 1701 } 1702 pswitch(0); 1703 longjmp(abortprox, 1); 1704 } 1705 1706 void 1707 doproxy(int argc, char *argv[]) 1708 { 1709 void (*oldintr)(); 1710 struct cmd *c; 1711 1712 if (argc < 2) { 1713 if (prompt_for_arg(line, sizeof (line), "command") == -1) { 1714 code = -1; 1715 return; 1716 } 1717 makeargv(); 1718 argc = margc; 1719 argv = margv; 1720 } 1721 if (argc < 2) { 1722 (void) printf("usage: %s command\n", argv[0]); 1723 code = -1; 1724 return; 1725 } 1726 c = getcmd(argv[1]); 1727 if (c == (struct cmd *)-1) { 1728 (void) printf("?Ambiguous command\n"); 1729 (void) fflush(stdout); 1730 code = -1; 1731 return; 1732 } 1733 if (c == 0) { 1734 (void) printf("?Invalid command\n"); 1735 (void) fflush(stdout); 1736 code = -1; 1737 return; 1738 } 1739 if (!c->c_proxy) { 1740 (void) printf("?Invalid proxy command\n"); 1741 (void) fflush(stdout); 1742 code = -1; 1743 return; 1744 } 1745 if (setjmp(abortprox)) { 1746 code = -1; 1747 return; 1748 } 1749 oldintr = signal(SIGINT, (void (*)())proxabort); 1750 pswitch(1); 1751 if (c->c_conn && !connected) { 1752 (void) printf("Not connected\n"); 1753 (void) fflush(stdout); 1754 pswitch(0); 1755 (void) signal(SIGINT, oldintr); 1756 code = -1; 1757 return; 1758 } 1759 (*c->c_handler)(argc-1, argv+1); 1760 if (connected) { 1761 proxflag = 1; 1762 } else { 1763 proxflag = 0; 1764 } 1765 pswitch(0); 1766 (void) signal(SIGINT, oldintr); 1767 } 1768 1769 /*ARGSUSED*/ 1770 void 1771 setcase(int argc, char *argv[]) 1772 { 1773 mcase = !mcase; 1774 (void) printf("Case mapping %s.\n", onoff(mcase)); 1775 code = mcase; 1776 } 1777 1778 /*ARGSUSED*/ 1779 void 1780 setcr(int argc, char *argv[]) 1781 { 1782 crflag = !crflag; 1783 (void) printf("Carriage Return stripping %s.\n", onoff(crflag)); 1784 code = crflag; 1785 } 1786 1787 void 1788 setntrans(int argc, char *argv[]) 1789 { 1790 if (argc == 1) { 1791 ntflag = 0; 1792 (void) printf("Ntrans off.\n"); 1793 code = ntflag; 1794 return; 1795 } 1796 ntflag++; 1797 code = ntflag; 1798 (void) strncpy(ntin, argv[1], 16); 1799 ntin[16] = '\0'; 1800 if (argc == 2) { 1801 ntout[0] = '\0'; 1802 return; 1803 } 1804 (void) strncpy(ntout, argv[2], 16); 1805 ntout[16] = '\0'; 1806 } 1807 1808 static char * 1809 dotrans(char *name) 1810 { 1811 static char new[MAXPATHLEN]; 1812 char *cp1, *cp2 = new; 1813 int i, ostop, found; 1814 1815 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) 1816 ; 1817 for (cp1 = name; *cp1; cp1++) { 1818 found = 0; 1819 for (i = 0; *(ntin + i) && i < 16; i++) { 1820 if (*cp1 == *(ntin + i)) { 1821 found++; 1822 if (i < ostop) { 1823 *cp2++ = *(ntout + i); 1824 } 1825 break; 1826 } 1827 } 1828 if (!found) { 1829 *cp2++ = *cp1; 1830 } 1831 } 1832 *cp2 = '\0'; 1833 return (new); 1834 } 1835 1836 void 1837 setnmap(int argc, char *argv[]) 1838 { 1839 char *cp; 1840 1841 if (argc == 1) { 1842 mapflag = 0; 1843 (void) printf("Nmap off.\n"); 1844 code = mapflag; 1845 return; 1846 } 1847 if (argc < 3) { 1848 if (prompt_for_arg(line, sizeof (line), "mapout") == -1) { 1849 code = -1; 1850 return; 1851 } 1852 makeargv(); 1853 argc = margc; 1854 argv = margv; 1855 } 1856 if (argc < 3) { 1857 (void) printf("Usage: %s [mapin mapout]\n", argv[0]); 1858 code = -1; 1859 return; 1860 } 1861 mapflag = 1; 1862 code = 1; 1863 cp = index(altarg, ' '); 1864 if (proxy) { 1865 while (*++cp == ' ') 1866 /* NULL */; 1867 altarg = cp; 1868 cp = index(altarg, ' '); 1869 } 1870 *cp = '\0'; 1871 (void) strncpy(mapin, altarg, MAXPATHLEN - 1); 1872 while (*++cp == ' ') 1873 /* NULL */; 1874 (void) strncpy(mapout, cp, MAXPATHLEN - 1); 1875 } 1876 1877 static char * 1878 domap(char *name) 1879 { 1880 static char new[MAXPATHLEN]; 1881 char *cp1 = name, *cp2 = mapin; 1882 char *tp[9], *te[9]; 1883 int i, toks[9], toknum, match = 1; 1884 wchar_t wc1, wc2; 1885 int len1, len2; 1886 1887 for (i = 0; i < 9; ++i) { 1888 toks[i] = 0; 1889 } 1890 while (match && *cp1 && *cp2) { 1891 if ((len1 = mbtowc(&wc1, cp1, MB_CUR_MAX)) <= 0) { 1892 wc1 = (unsigned char)*cp1; 1893 len1 = 1; 1894 } 1895 cp1 += len1; 1896 if ((len2 = mbtowc(&wc2, cp2, MB_CUR_MAX)) <= 0) { 1897 wc2 = (unsigned char)*cp2; 1898 len2 = 1; 1899 } 1900 cp2 += len2; 1901 1902 switch (wc2) { 1903 case '\\': 1904 if ((len2 = mbtowc(&wc2, cp2, MB_CUR_MAX)) <= 0) { 1905 wc2 = (unsigned char)*cp2; 1906 len2 = 1; 1907 } 1908 cp2 += len2; 1909 if (wc2 != wc1) 1910 match = 0; 1911 break; 1912 1913 case '$': 1914 if (*cp2 >= '1' && *cp2 <= '9') { 1915 if ((len2 = 1916 mbtowc(&wc2, cp2 + 1, MB_CUR_MAX)) <= 0) { 1917 wc2 = (unsigned char)*(cp2 + 1); 1918 len2 = 1; 1919 } 1920 if (wc1 != wc2) { 1921 toks[toknum = *cp2 - '1']++; 1922 tp[toknum] = cp1 - len1; 1923 while (*cp1) { 1924 if ((len1 = mbtowc(&wc1, 1925 cp1, MB_CUR_MAX)) <= 0) { 1926 wc1 = 1927 (unsigned char)*cp1; 1928 len1 = 1; 1929 } 1930 cp1 += len1; 1931 if (wc2 == wc1) 1932 break; 1933 } 1934 if (*cp1 == 0 && wc2 != wc1) 1935 te[toknum] = cp1; 1936 else 1937 te[toknum] = cp1 - len1; 1938 } 1939 cp2++; /* Consume the digit */ 1940 if (wc2) 1941 cp2 += len2; /* Consume wide char */ 1942 break; 1943 } 1944 /* intentional drop through */ 1945 default: 1946 if (wc2 != wc1) 1947 match = 0; 1948 break; 1949 } 1950 } 1951 1952 cp1 = new; 1953 *cp1 = '\0'; 1954 cp2 = mapout; 1955 while (*cp2) { 1956 match = 0; 1957 switch (*cp2) { 1958 case '\\': 1959 cp2++; 1960 if (*cp2) { 1961 if ((len2 = mblen(cp2, MB_CUR_MAX)) <= 0) 1962 len2 = 1; 1963 memcpy(cp1, cp2, len2); 1964 cp1 += len2; 1965 cp2 += len2; 1966 } 1967 break; 1968 1969 case '[': 1970 LOOP: 1971 cp2++; 1972 if (*cp2 == '$' && isdigit(*(cp2+1))) { 1973 if (*++cp2 == '0') { 1974 char *cp3 = name; 1975 1976 while (*cp3) { 1977 *cp1++ = *cp3++; 1978 } 1979 match = 1; 1980 } else if (toks[toknum = *cp2 - '1']) { 1981 char *cp3 = tp[toknum]; 1982 1983 while (cp3 != te[toknum]) { 1984 *cp1++ = *cp3++; 1985 } 1986 match = 1; 1987 } 1988 } else { 1989 while (*cp2 && *cp2 != ',' && *cp2 != ']') { 1990 if (*cp2 == '\\') { 1991 cp2++; 1992 continue; 1993 } 1994 1995 if (*cp2 == '$' && isdigit(*(cp2+1))) { 1996 if (*++cp2 == '0') { 1997 char *cp3 = name; 1998 1999 while (*cp3) 2000 *cp1++ = *cp3++; 2001 continue; 2002 } 2003 if (toks[toknum = *cp2 - '1']) { 2004 char *cp3 = tp[toknum]; 2005 2006 while (cp3 != 2007 te[toknum]) 2008 *cp1++ = *cp3++; 2009 } 2010 continue; 2011 } 2012 if (*cp2) { 2013 if ((len2 = 2014 mblen(cp2, MB_CUR_MAX)) <= 2015 0) { 2016 len2 = 1; 2017 } 2018 memcpy(cp1, cp2, len2); 2019 cp1 += len2; 2020 cp2 += len2; 2021 } 2022 } 2023 if (!*cp2) { 2024 (void) printf( 2025 "nmap: unbalanced brackets\n"); 2026 return (name); 2027 } 2028 match = 1; 2029 } 2030 if (match) { 2031 while (*cp2 && *cp2 != ']') { 2032 if (*cp2 == '\\' && *(cp2 + 1)) { 2033 cp2++; 2034 } 2035 if ((len2 = mblen(cp2, MB_CUR_MAX)) <= 2036 0) 2037 len2 = 1; 2038 cp2 += len2; 2039 } 2040 if (!*cp2) { 2041 (void) printf( 2042 "nmap: unbalanced brackets\n"); 2043 return (name); 2044 } 2045 cp2++; 2046 break; 2047 } 2048 switch (*++cp2) { 2049 case ',': 2050 goto LOOP; 2051 case ']': 2052 break; 2053 default: 2054 cp2--; 2055 goto LOOP; 2056 } 2057 cp2++; 2058 break; 2059 case '$': 2060 if (isdigit(*(cp2 + 1))) { 2061 if (*++cp2 == '0') { 2062 char *cp3 = name; 2063 2064 while (*cp3) { 2065 *cp1++ = *cp3++; 2066 } 2067 } else if (toks[toknum = *cp2 - '1']) { 2068 char *cp3 = tp[toknum]; 2069 2070 while (cp3 != te[toknum]) { 2071 *cp1++ = *cp3++; 2072 } 2073 } 2074 cp2++; 2075 break; 2076 } 2077 /* intentional drop through */ 2078 default: 2079 if ((len2 = mblen(cp2, MB_CUR_MAX)) <= 0) 2080 len2 = 1; 2081 memcpy(cp1, cp2, len2); 2082 cp1 += len2; 2083 cp2 += len2; 2084 break; 2085 } 2086 } 2087 *cp1 = '\0'; 2088 if (!*new) { 2089 return (name); 2090 } 2091 return (new); 2092 } 2093 2094 /*ARGSUSED*/ 2095 void 2096 setsunique(int argc, char *argv[]) 2097 { 2098 sunique = !sunique; 2099 (void) printf("Store unique %s.\n", onoff(sunique)); 2100 code = sunique; 2101 } 2102 2103 /*ARGSUSED*/ 2104 void 2105 setrunique(int argc, char *argv[]) 2106 { 2107 runique = !runique; 2108 (void) printf("Receive unique %s.\n", onoff(runique)); 2109 code = runique; 2110 } 2111 2112 /*ARGSUSED*/ 2113 void 2114 setpassive(int argc, char *argv[]) 2115 { 2116 passivemode = !passivemode; 2117 (void) printf("Passive mode %s.\n", onoff(passivemode)); 2118 code = passivemode; 2119 } 2120 2121 void 2122 settcpwindow(int argc, char *argv[]) 2123 { 2124 int owindowsize = tcpwindowsize; 2125 2126 if (argc > 2) { 2127 (void) printf("usage: %s [size]\n", argv[0]); 2128 code = -1; 2129 return; 2130 } 2131 if (argc == 2) { 2132 int window; 2133 char *endp; 2134 2135 errno = 0; 2136 window = (int)strtol(argv[1], &endp, 10); 2137 if (errno || window < 0 || *endp != '\0') 2138 (void) printf("%s: Invalid size `%s'\n", 2139 argv[0], argv[1]); 2140 else 2141 tcpwindowsize = window; 2142 } 2143 if (tcpwindowsize == 0) { 2144 if (owindowsize == 0) 2145 (void) printf("No TCP window size defined\n"); 2146 else 2147 (void) printf("TCP window size cleared\n"); 2148 } else 2149 (void) printf("TCP window size is set to %d\n", tcpwindowsize); 2150 } 2151 2152 /* change directory to parent directory */ 2153 /*ARGSUSED*/ 2154 void 2155 cdup(int argc, char *argv[]) 2156 { 2157 (void) command("CDUP"); 2158 } 2159 2160 void 2161 macdef(int argc, char *argv[]) 2162 { 2163 char *tmp; 2164 int c; 2165 2166 if (macnum == 16) { 2167 (void) printf("Limit of 16 macros have already been defined\n"); 2168 code = -1; 2169 return; 2170 } 2171 if (argc < 2) { 2172 if (prompt_for_arg(line, sizeof (line), "macro name") == -1) { 2173 code = -1; 2174 return; 2175 } 2176 makeargv(); 2177 argc = margc; 2178 argv = margv; 2179 } 2180 if (argc != 2) { 2181 (void) printf("Usage: %s macro_name\n", argv[0]); 2182 code = -1; 2183 return; 2184 } 2185 if (interactive) { 2186 (void) printf("Enter macro line by line, terminating " 2187 "it with a null line\n"); 2188 } 2189 (void) strncpy(macros[macnum].mac_name, argv[1], 8); 2190 if (macnum == 0) { 2191 macros[macnum].mac_start = macbuf; 2192 } else { 2193 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 2194 } 2195 tmp = macros[macnum].mac_start; 2196 while (tmp != macbuf+4096) { 2197 if ((c = getchar()) == EOF) { 2198 (void) printf("macdef:end of file encountered\n"); 2199 code = -1; 2200 return; 2201 } 2202 if ((*tmp = c) == '\n') { 2203 if (tmp == macros[macnum].mac_start) { 2204 macros[macnum++].mac_end = tmp; 2205 code = 0; 2206 return; 2207 } 2208 if (*(tmp-1) == '\0') { 2209 macros[macnum++].mac_end = tmp - 1; 2210 code = 0; 2211 return; 2212 } 2213 *tmp = '\0'; 2214 } 2215 tmp++; 2216 } 2217 for (;;) { 2218 while ((c = getchar()) != '\n' && c != EOF) 2219 /* NULL */; 2220 if (c == EOF || getchar() == '\n') { 2221 (void) printf( 2222 "Macro not defined - 4k buffer exceeded\n"); 2223 code = -1; 2224 return; 2225 } 2226 } 2227 } 2228 2229 /* 2230 * The p_name strings are for the getlevel and setlevel commands. 2231 * The name strings for printing are in the arpa/ftp.h file in the 2232 * protnames[] array of strings. 2233 */ 2234 static struct levels { 2235 char *p_name; 2236 char *p_mode; 2237 int p_level; 2238 } levels[] = { 2239 { "clear", "C", PROT_C }, 2240 { "safe", "S", PROT_S }, 2241 { "private", "P", PROT_P }, 2242 NULL 2243 }; 2244 2245 /* 2246 * Return a pointer to a string which is the readable version of the 2247 * protection level, or NULL if the input level is not found. 2248 */ 2249 static char * 2250 getlevel(int level) 2251 { 2252 struct levels *p; 2253 2254 for (p = levels; (p != NULL) && (p->p_level != level); p++) 2255 ; 2256 return (p ? p->p_name : NULL); 2257 } 2258 2259 static char *plevel[] = { 2260 "protect", 2261 "", 2262 NULL 2263 }; 2264 2265 /* 2266 * Set control channel protection level. 2267 */ 2268 void 2269 setclevel(int argc, char *argv[]) 2270 { 2271 struct levels *p; 2272 char *levelp; 2273 int comret; 2274 2275 if (argc > 2) { 2276 char *sep; 2277 2278 (void) printf("usage: %s [", argv[0]); 2279 sep = " "; 2280 for (p = levels; p->p_name; p++) { 2281 (void) printf("%s%s", sep, p->p_name); 2282 if (*sep == ' ') 2283 sep = " | "; 2284 } 2285 (void) printf(" ]\n"); 2286 code = -1; 2287 return; 2288 } 2289 if (argc < 2) { 2290 levelp = getlevel(clevel); 2291 (void) printf("Using %s protection level for commands.\n", 2292 levelp ? levelp : "<unknown>"); 2293 code = 0; 2294 return; 2295 } 2296 for (p = levels; (p != NULL) && (p->p_name); p++) 2297 if (strcmp(argv[1], p->p_name) == 0) 2298 break; 2299 if (p->p_name == 0) { 2300 (void) printf("%s: unknown protection level\n", argv[1]); 2301 code = -1; 2302 return; 2303 } 2304 if (auth_type == AUTHTYPE_NONE) { 2305 if (strcmp(p->p_name, "clear")) 2306 (void) printf("Cannot set protection level to %s\n", 2307 argv[1]); 2308 return; 2309 } 2310 if (strcmp(p->p_name, "clear") == 0) { 2311 comret = command("CCC"); 2312 if (comret == COMPLETE) 2313 clevel = PROT_C; 2314 return; 2315 } 2316 clevel = p->p_level; 2317 (void) printf("Control channel protection level set to %s.\n", 2318 p->p_name); 2319 } 2320 2321 /* 2322 * Set data channel protection level. 2323 */ 2324 void 2325 setdlevel(int argc, char *argv[]) 2326 { 2327 struct levels *p; 2328 int comret; 2329 2330 if (argc != 2) { 2331 char *sep; 2332 2333 (void) printf("usage: %s [", argv[0]); 2334 sep = " "; 2335 for (p = levels; p->p_name; p++) { 2336 (void) printf("%s%s", sep, p->p_name); 2337 if (*sep == ' ') 2338 sep = " | "; 2339 } 2340 (void) printf(" ]\n"); 2341 code = -1; 2342 return; 2343 } 2344 for (p = levels; p->p_name; p++) 2345 if (strcmp(argv[1], p->p_name) == 0) 2346 break; 2347 if (p->p_name == 0) { 2348 (void) printf("%s: unknown protection level\n", argv[1]); 2349 code = -1; 2350 return; 2351 } 2352 if (auth_type == AUTHTYPE_NONE) { 2353 if (strcmp(p->p_name, "clear")) 2354 (void) printf("Cannot set protection level to %s\n", 2355 argv[1]); 2356 return; 2357 } 2358 /* Start with a PBSZ of 1 meg */ 2359 if (p->p_level != PROT_C) 2360 setpbsz(1<<20); 2361 comret = command("PROT %s", p->p_mode); 2362 if (comret == COMPLETE) 2363 dlevel = p->p_level; 2364 } 2365 2366 /* 2367 * Set clear command protection level. 2368 */ 2369 /* VARARGS */ 2370 void 2371 ccc(int argc, char *argv[]) 2372 { 2373 plevel[1] = "clear"; 2374 setclevel(2, plevel); 2375 } 2376 2377 /* 2378 * Set clear data protection level. 2379 */ 2380 /* VARARGS */ 2381 void 2382 setclear(int argc, char *argv[]) 2383 { 2384 plevel[1] = "clear"; 2385 setdlevel(2, plevel); 2386 } 2387 2388 /* 2389 * Set safe data protection level. 2390 */ 2391 /* VARARGS */ 2392 void 2393 setsafe(int argc, char *argv[]) 2394 { 2395 plevel[1] = "safe"; 2396 setdlevel(2, plevel); 2397 } 2398 2399 /* 2400 * Set private data protection level. 2401 */ 2402 /* VARARGS */ 2403 void 2404 setprivate(int argc, char *argv[]) 2405 { 2406 plevel[1] = "private"; 2407 setdlevel(2, plevel); 2408 } 2409 2410 /* 2411 * Set mechanism type 2412 */ 2413 void 2414 setmech(int argc, char *argv[]) 2415 { 2416 char tempmech[MECH_SZ]; 2417 2418 if (argc < 2) { 2419 if (prompt_for_arg(line, sizeof (line), "mech-type") == -1) { 2420 code = -1; 2421 return; 2422 } 2423 makeargv(); 2424 argc = margc; 2425 argv = margv; 2426 } 2427 2428 if (argc != 2) { 2429 (void) printf("usage: %s [ mechanism type ]\n", argv[0]); 2430 code = -1; 2431 return; 2432 } 2433 2434 if ((strlcpy(tempmech, argv[1], MECH_SZ) >= MECH_SZ) || 2435 __gss_mech_to_oid(tempmech, (gss_OID*)&mechoid) != 2436 GSS_S_COMPLETE) { 2437 (void) printf("%s: %s: not a valid security mechanism\n", 2438 argv[0], tempmech); 2439 code = -1; 2440 return; 2441 } else { 2442 (void) strlcpy(mechstr, tempmech, MECH_SZ); 2443 (void) printf("Using %s mechanism type\n", mechstr); 2444 code = 0; 2445 return; 2446 } 2447 } 2448