1 /* $OpenBSD: small.c,v 1.1 2009/05/05 19:35:30 martynas Exp $ */ 2 /* $NetBSD: cmds.c,v 1.27 1997/08/18 10:20:15 lukem Exp $ */ 3 4 /* 5 * Copyright (C) 1997 and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1985, 1989, 1993, 1994 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 */ 61 62 /* 63 * FTP User Program -- Command Routines. 64 */ 65 #include <sys/types.h> 66 #include <sys/socket.h> 67 #include <sys/stat.h> 68 #include <sys/wait.h> 69 #include <arpa/ftp.h> 70 71 #include <ctype.h> 72 #include <err.h> 73 #include <fnmatch.h> 74 #include <glob.h> 75 #include <netdb.h> 76 #include <stdio.h> 77 #include <stdlib.h> 78 #include <string.h> 79 #include <unistd.h> 80 81 #include "ftp_var.h" 82 #include "pathnames.h" 83 #include "small.h" 84 85 jmp_buf jabort; 86 char *mname; 87 char *home = "/"; 88 89 struct types { 90 char *t_name; 91 char *t_mode; 92 int t_type; 93 char *t_arg; 94 } types[] = { 95 { "ascii", "A", TYPE_A, 0 }, 96 { "binary", "I", TYPE_I, 0 }, 97 { "image", "I", TYPE_I, 0 }, 98 { "ebcdic", "E", TYPE_E, 0 }, 99 { "tenex", "L", TYPE_L, bytename }, 100 { NULL } 101 }; 102 103 /* 104 * Set transfer type. 105 */ 106 void 107 settype(int argc, char *argv[]) 108 { 109 struct types *p; 110 int comret; 111 112 if (argc > 2) { 113 char *sep; 114 115 fprintf(ttyout, "usage: %s [", argv[0]); 116 sep = ""; 117 for (p = types; p->t_name; p++) { 118 fprintf(ttyout, "%s%s", sep, p->t_name); 119 sep = " | "; 120 } 121 fputs("]\n", ttyout); 122 code = -1; 123 return; 124 } 125 if (argc < 2) { 126 fprintf(ttyout, "Using %s mode to transfer files.\n", typename); 127 code = 0; 128 return; 129 } 130 for (p = types; p->t_name; p++) 131 if (strcmp(argv[1], p->t_name) == 0) 132 break; 133 if (p->t_name == 0) { 134 fprintf(ttyout, "%s: unknown mode.\n", argv[1]); 135 code = -1; 136 return; 137 } 138 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 139 comret = command("TYPE %s %s", p->t_mode, p->t_arg); 140 else 141 comret = command("TYPE %s", p->t_mode); 142 if (comret == COMPLETE) { 143 (void)strlcpy(typename, p->t_name, sizeof typename); 144 curtype = type = p->t_type; 145 } 146 } 147 148 /* 149 * Internal form of settype; changes current type in use with server 150 * without changing our notion of the type for data transfers. 151 * Used to change to and from ascii for listings. 152 */ 153 void 154 changetype(int newtype, int show) 155 { 156 struct types *p; 157 int comret, oldverbose = verbose; 158 159 if (newtype == 0) 160 newtype = TYPE_I; 161 if (newtype == curtype) 162 return; 163 if ( 164 #ifndef SMALL 165 !debug && 166 #endif /* !SMALL */ 167 show == 0) 168 verbose = 0; 169 for (p = types; p->t_name; p++) 170 if (newtype == p->t_type) 171 break; 172 if (p->t_name == 0) { 173 warnx("internal error: unknown type %d.", newtype); 174 return; 175 } 176 if (newtype == TYPE_L && bytename[0] != '\0') 177 comret = command("TYPE %s %s", p->t_mode, bytename); 178 else 179 comret = command("TYPE %s", p->t_mode); 180 if (comret == COMPLETE) 181 curtype = newtype; 182 verbose = oldverbose; 183 } 184 185 char *stype[] = { 186 "type", 187 "", 188 0 189 }; 190 191 /* 192 * Set binary transfer type. 193 */ 194 /*ARGSUSED*/ 195 void 196 setbinary(int argc, char *argv[]) 197 { 198 199 stype[1] = "binary"; 200 settype(2, stype); 201 } 202 203 void 204 get(int argc, char *argv[]) 205 { 206 207 (void)getit(argc, argv, 0, restart_point ? "a+w" : "w" ); 208 } 209 210 /* 211 * Receive one file. 212 */ 213 int 214 getit(int argc, char *argv[], int restartit, const char *mode) 215 { 216 int loc = 0; 217 int rval = 0; 218 char *oldargv1, *oldargv2, *globargv2; 219 220 if (argc == 2) { 221 argc++; 222 argv[2] = argv[1]; 223 loc++; 224 } 225 #ifndef SMALL 226 if (argc < 2 && !another(&argc, &argv, "remote-file")) 227 goto usage; 228 if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) { 229 usage: 230 fprintf(ttyout, "usage: %s remote-file [local-file]\n", 231 argv[0]); 232 code = -1; 233 return (0); 234 } 235 #endif /* !SMALL */ 236 oldargv1 = argv[1]; 237 oldargv2 = argv[2]; 238 if (!globulize(&argv[2])) { 239 code = -1; 240 return (0); 241 } 242 globargv2 = argv[2]; 243 if (loc && mcase) { 244 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN]; 245 246 while (*tp && !islower(*tp)) { 247 tp++; 248 } 249 if (!*tp) { 250 tp = argv[2]; 251 tp2 = tmpbuf; 252 while ((*tp2 = *tp) != '\0') { 253 if (isupper(*tp2)) { 254 *tp2 = tolower(*tp2); 255 } 256 tp++; 257 tp2++; 258 } 259 argv[2] = tmpbuf; 260 } 261 } 262 if (loc && ntflag) 263 argv[2] = dotrans(argv[2]); 264 if (loc && mapflag) 265 argv[2] = domap(argv[2]); 266 #ifndef SMALL 267 if (restartit) { 268 struct stat stbuf; 269 int ret; 270 271 ret = stat(argv[2], &stbuf); 272 if (restartit == 1) { 273 restart_point = (ret < 0) ? 0 : stbuf.st_size; 274 } else { 275 if (ret == 0) { 276 time_t mtime; 277 278 mtime = remotemodtime(argv[1], 0); 279 if (mtime == -1) 280 goto freegetit; 281 if (stbuf.st_mtime >= mtime) { 282 rval = 1; 283 goto freegetit; 284 } 285 } 286 } 287 } 288 #endif /* !SMALL */ 289 290 recvrequest("RETR", argv[2], argv[1], mode, 291 argv[1] != oldargv1 || argv[2] != oldargv2 || !interactive, loc); 292 restart_point = 0; 293 freegetit: 294 if (oldargv2 != globargv2) /* free up after globulize() */ 295 free(globargv2); 296 return (rval); 297 } 298 299 /* XXX - Signal race. */ 300 /* ARGSUSED */ 301 void 302 mabort(int signo) 303 { 304 alarmtimer(0); 305 putc('\n', ttyout); 306 (void)fflush(ttyout); 307 #ifndef SMALL 308 if (mflag && fromatty) 309 if (confirm(mname, NULL)) 310 longjmp(jabort, 1); 311 #endif /* !SMALL */ 312 mflag = 0; 313 longjmp(jabort, 1); 314 } 315 316 /* 317 * Get multiple files. 318 */ 319 void 320 mget(int argc, char *argv[]) 321 { 322 extern int optind, optreset; 323 sig_t oldintr; 324 int ch, xargc = 2; 325 char *cp, localcwd[MAXPATHLEN], *xargv[] = { argv[0], NULL, NULL }; 326 static int restartit = 0; 327 #ifndef SMALL 328 extern char *optarg; 329 const char *errstr; 330 int i = 1; 331 char type = 0, *dummyargv[] = { argv[0], ".", NULL }; 332 FILE *ftemp = NULL; 333 static int depth = 0, max_depth = 0; 334 335 optind = optreset = 1; 336 337 if (depth) 338 depth++; 339 340 while ((ch = getopt(argc, argv, "cd:nr")) != -1) { 341 switch(ch) { 342 case 'c': 343 restartit = 1; 344 break; 345 case 'd': 346 max_depth = strtonum(optarg, 0, INT_MAX, &errstr); 347 if (errstr != NULL) { 348 fprintf(ttyout, "bad depth value, %s: %s\n", 349 errstr, optarg); 350 code = -1; 351 return; 352 } 353 break; 354 case 'n': 355 restartit = -1; 356 break; 357 case 'r': 358 depth = 1; 359 break; 360 default: 361 goto usage; 362 } 363 } 364 365 if (argc - optind < 1 && !another(&argc, &argv, "remote-files")) { 366 usage: 367 fprintf(ttyout, "usage: %s [-cnr] [-d depth] remote-files\n", 368 argv[0]); 369 code = -1; 370 return; 371 } 372 373 argv[optind - 1] = argv[0]; 374 argc -= optind - 1; 375 argv += optind - 1; 376 #endif /* !SMALL */ 377 378 mname = argv[0]; 379 mflag = 1; 380 if (getcwd(localcwd, sizeof(localcwd)) == NULL) 381 err(1, "can't get cwd"); 382 383 oldintr = signal(SIGINT, mabort); 384 (void)setjmp(jabort); 385 while ((cp = 386 #ifdef SMALL 387 remglob(argv, proxy, NULL)) != NULL 388 ) { 389 #else /* SMALL */ 390 depth ? remglob2(dummyargv, proxy, NULL, &ftemp, &type) : 391 remglob(argv, proxy, NULL)) != NULL 392 || (mflag && depth && ++i < argc) 393 ) { 394 if (cp == NULL) 395 continue; 396 #endif /* SMALL */ 397 if (*cp == '\0') { 398 mflag = 0; 399 continue; 400 } 401 if (!mflag) 402 continue; 403 #ifndef SMALL 404 if (depth && fnmatch(argv[i], cp, FNM_PATHNAME) != 0) 405 continue; 406 #endif /* !SMALL */ 407 if (!fileindir(cp, localcwd)) { 408 fprintf(ttyout, "Skipping non-relative filename `%s'\n", 409 cp); 410 continue; 411 } 412 #ifndef SMALL 413 if (type == 'd' && depth == max_depth) 414 continue; 415 if (!confirm(argv[0], cp)) 416 continue; 417 if (type == 'd') { 418 mkdir(cp, 0755); 419 if (chdir(cp) != 0) { 420 warn("local: %s", cp); 421 continue; 422 } 423 424 xargv[1] = cp; 425 cd(xargc, xargv); 426 if (dirchange != 1) 427 goto out; 428 429 xargv[1] = "*"; 430 mget(xargc, xargv); 431 432 xargv[1] = ".."; 433 cd(xargc, xargv); 434 if (dirchange != 1) { 435 mflag = 0; 436 goto out; 437 } 438 439 out: 440 if (chdir("..") != 0) { 441 warn("local: %s", cp); 442 mflag = 0; 443 } 444 continue; 445 } 446 if (type == 's') 447 /* Currently ignored. */ 448 continue; 449 #endif /* !SMALL */ 450 xargv[1] = cp; 451 (void)getit(xargc, xargv, restartit, 452 (restartit == 1 || restart_point) ? "a+w" : "w"); 453 #ifndef SMALL 454 if (!mflag && fromatty) { 455 if (confirm(argv[0], NULL)) 456 mflag = 1; 457 } 458 #endif /* !SMALL */ 459 } 460 (void)signal(SIGINT, oldintr); 461 #ifndef SMALL 462 if (depth) 463 depth--; 464 if (depth == 0 || mflag == 0) 465 depth = max_depth = mflag = restartit = 0; 466 #else /* !SMALL */ 467 mflag = 0; 468 #endif /* !SMALL */ 469 } 470 471 /* 472 * Set current working directory on remote machine. 473 */ 474 void 475 cd(int argc, char *argv[]) 476 { 477 int r; 478 479 #ifndef SMALL 480 if ((argc < 2 && !another(&argc, &argv, "remote-directory")) || 481 argc > 2) { 482 fprintf(ttyout, "usage: %s remote-directory\n", argv[0]); 483 code = -1; 484 return; 485 } 486 #endif /* !SMALL */ 487 r = command("CWD %s", argv[1]); 488 if (r == ERROR && code == 500) { 489 if (verbose) 490 fputs("CWD command not recognized, trying XCWD.\n", ttyout); 491 r = command("XCWD %s", argv[1]); 492 } 493 if (r == ERROR && code == 550) { 494 dirchange = 0; 495 return; 496 } 497 if (r == COMPLETE) 498 dirchange = 1; 499 } 500 501 /* 502 * Terminate session, but don't exit. 503 */ 504 /* ARGSUSED */ 505 void 506 disconnect(int argc, char *argv[]) 507 { 508 509 if (!connected) 510 return; 511 (void)command("QUIT"); 512 if (cout) { 513 (void)fclose(cout); 514 } 515 cout = NULL; 516 connected = 0; 517 data = -1; 518 #ifndef SMALL 519 if (!proxy) { 520 macnum = 0; 521 } 522 #endif /* !SMALL */ 523 } 524 525 char * 526 dotrans(char *name) 527 { 528 static char new[MAXPATHLEN]; 529 char *cp1, *cp2 = new; 530 int i, ostop, found; 531 532 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) 533 continue; 534 for (cp1 = name; *cp1; cp1++) { 535 found = 0; 536 for (i = 0; *(ntin + i) && i < 16; i++) { 537 if (*cp1 == *(ntin + i)) { 538 found++; 539 if (i < ostop) { 540 *cp2++ = *(ntout + i); 541 } 542 break; 543 } 544 } 545 if (!found) { 546 *cp2++ = *cp1; 547 } 548 } 549 *cp2 = '\0'; 550 return (new); 551 } 552 553 char * 554 domap(char *name) 555 { 556 static char new[MAXPATHLEN]; 557 char *cp1 = name, *cp2 = mapin; 558 char *tp[9], *te[9]; 559 int i, toks[9], toknum = 0, match = 1; 560 561 for (i=0; i < 9; ++i) { 562 toks[i] = 0; 563 } 564 while (match && *cp1 && *cp2) { 565 switch (*cp2) { 566 case '\\': 567 if (*++cp2 != *cp1) { 568 match = 0; 569 } 570 break; 571 case '$': 572 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 573 if (*cp1 != *(++cp2+1)) { 574 toks[toknum = *cp2 - '1']++; 575 tp[toknum] = cp1; 576 while (*++cp1 && *(cp2+1) 577 != *cp1); 578 te[toknum] = cp1; 579 } 580 cp2++; 581 break; 582 } 583 /* FALLTHROUGH */ 584 default: 585 if (*cp2 != *cp1) { 586 match = 0; 587 } 588 break; 589 } 590 if (match && *cp1) { 591 cp1++; 592 } 593 if (match && *cp2) { 594 cp2++; 595 } 596 } 597 if (!match && *cp1) /* last token mismatch */ 598 { 599 toks[toknum] = 0; 600 } 601 cp1 = new; 602 *cp1 = '\0'; 603 cp2 = mapout; 604 while (*cp2) { 605 match = 0; 606 switch (*cp2) { 607 case '\\': 608 if (*(cp2 + 1)) { 609 *cp1++ = *++cp2; 610 } 611 break; 612 case '[': 613 LOOP: 614 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 615 if (*++cp2 == '0') { 616 char *cp3 = name; 617 618 while (*cp3) { 619 *cp1++ = *cp3++; 620 } 621 match = 1; 622 } 623 else if (toks[toknum = *cp2 - '1']) { 624 char *cp3 = tp[toknum]; 625 626 while (cp3 != te[toknum]) { 627 *cp1++ = *cp3++; 628 } 629 match = 1; 630 } 631 } 632 else { 633 while (*cp2 && *cp2 != ',' && 634 *cp2 != ']') { 635 if (*cp2 == '\\') { 636 cp2++; 637 } 638 else if (*cp2 == '$' && 639 isdigit(*(cp2+1))) { 640 if (*++cp2 == '0') { 641 char *cp3 = name; 642 643 while (*cp3) { 644 *cp1++ = *cp3++; 645 } 646 } 647 else if (toks[toknum = 648 *cp2 - '1']) { 649 char *cp3=tp[toknum]; 650 651 while (cp3 != 652 te[toknum]) { 653 *cp1++ = *cp3++; 654 } 655 } 656 } 657 else if (*cp2) { 658 *cp1++ = *cp2++; 659 } 660 } 661 if (!*cp2) { 662 fputs( 663 "nmap: unbalanced brackets.\n", ttyout); 664 return (name); 665 } 666 match = 1; 667 cp2--; 668 } 669 if (match) { 670 while (*++cp2 && *cp2 != ']') { 671 if (*cp2 == '\\' && *(cp2 + 1)) { 672 cp2++; 673 } 674 } 675 if (!*cp2) { 676 fputs( 677 "nmap: unbalanced brackets.\n", ttyout); 678 return (name); 679 } 680 break; 681 } 682 switch (*++cp2) { 683 case ',': 684 goto LOOP; 685 case ']': 686 break; 687 default: 688 cp2--; 689 goto LOOP; 690 } 691 break; 692 case '$': 693 if (isdigit(*(cp2 + 1))) { 694 if (*++cp2 == '0') { 695 char *cp3 = name; 696 697 while (*cp3) { 698 *cp1++ = *cp3++; 699 } 700 } 701 else if (toks[toknum = *cp2 - '1']) { 702 char *cp3 = tp[toknum]; 703 704 while (cp3 != te[toknum]) { 705 *cp1++ = *cp3++; 706 } 707 } 708 break; 709 } 710 /* FALLTHROUGH */ 711 default: 712 *cp1++ = *cp2; 713 break; 714 } 715 cp2++; 716 } 717 *cp1 = '\0'; 718 if (!*new) { 719 return (name); 720 } 721 return (new); 722 } 723 724