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