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