1 /* 2 * Copyright (c) 1985, 1988, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)ftpcmd.y 8.3 (Berkeley) 4/6/94 34 */ 35 36 /* 37 * Grammar for FTP commands. 38 * See RFC 959. 39 */ 40 41 %{ 42 43 #ifndef lint 44 #if 0 45 static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94"; 46 #endif 47 static const char rcsid[] = 48 "$FreeBSD$"; 49 #endif /* not lint */ 50 51 #include <sys/param.h> 52 #include <sys/socket.h> 53 #include <sys/stat.h> 54 55 #include <netinet/in.h> 56 #include <arpa/ftp.h> 57 58 #include <ctype.h> 59 #include <errno.h> 60 #include <glob.h> 61 #include <libutil.h> 62 #include <limits.h> 63 #include <md5.h> 64 #include <netdb.h> 65 #include <pwd.h> 66 #include <signal.h> 67 #include <stdio.h> 68 #include <stdlib.h> 69 #include <string.h> 70 #include <syslog.h> 71 #include <time.h> 72 #include <unistd.h> 73 74 #include "extern.h" 75 #include "pathnames.h" 76 77 extern union sockunion data_dest, his_addr; 78 extern int hostinfo; 79 extern int logged_in; 80 extern struct passwd *pw; 81 extern int guest; 82 extern char *homedir; 83 extern int paranoid; 84 extern int logging; 85 extern int type; 86 extern int form; 87 extern int ftpdebug; 88 extern int timeout; 89 extern int maxtimeout; 90 extern int pdata; 91 extern char *hostname; 92 extern char proctitle[]; 93 extern int usedefault; 94 extern char tmpline[]; 95 extern int readonly; 96 extern int noepsv; 97 extern int noretr; 98 extern int noguestretr; 99 extern char *typenames[]; /* defined in <arpa/ftp.h> included from ftpd.c */ 100 101 off_t restart_point; 102 103 static int cmd_type; 104 static int cmd_form; 105 static int cmd_bytesz; 106 static int state; 107 char cbuf[512]; 108 char *fromname = (char *) 0; 109 110 extern int epsvall; 111 112 %} 113 114 %union { 115 struct { 116 off_t o; 117 int i; 118 } u; 119 char *s; 120 } 121 122 %token 123 A B C E F I 124 L N P R S T 125 ALL 126 127 SP CRLF COMMA 128 129 USER PASS ACCT REIN QUIT PORT 130 PASV TYPE STRU MODE RETR STOR 131 APPE MLFL MAIL MSND MSOM MSAM 132 MRSQ MRCP ALLO REST RNFR RNTO 133 ABOR DELE CWD LIST NLST SITE 134 STAT HELP NOOP MKD RMD PWD 135 CDUP STOU SMNT SYST SIZE MDTM 136 LPRT LPSV EPRT EPSV 137 138 UMASK IDLE CHMOD MDFIVE 139 140 LEXERR NOTIMPL 141 142 %token <s> STRING 143 %token <u> NUMBER 144 145 %type <u.i> check_login octal_number byte_size 146 %type <u.i> check_login_ro check_login_epsv 147 %type <u.i> struct_code mode_code type_code form_code 148 %type <s> pathstring pathname password username 149 %type <s> ALL NOTIMPL 150 151 %start cmd_list 152 153 %% 154 155 cmd_list 156 : /* empty */ 157 | cmd_list cmd 158 { 159 if (fromname) 160 free(fromname); 161 fromname = (char *) 0; 162 restart_point = (off_t) 0; 163 } 164 | cmd_list rcmd 165 ; 166 167 cmd 168 : USER SP username CRLF 169 { 170 user($3); 171 free($3); 172 } 173 | PASS SP password CRLF 174 { 175 pass($3); 176 free($3); 177 } 178 | PASS CRLF 179 { 180 pass(""); 181 } 182 | PORT check_login SP host_port CRLF 183 { 184 if (epsvall) { 185 reply(501, "no PORT allowed after EPSV ALL"); 186 goto port_done; 187 } 188 if (!$2) 189 goto port_done; 190 if (port_check("PORT") == 1) 191 goto port_done; 192 #ifdef INET6 193 if ((his_addr.su_family != AF_INET6 || 194 !IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) { 195 /* shoud never happen */ 196 usedefault = 1; 197 reply(500, "Invalid address rejected."); 198 goto port_done; 199 } 200 port_check_v6("pcmd"); 201 #endif 202 port_done: 203 42; /* Life, the universe and everything! */ 204 } 205 | LPRT check_login SP host_long_port CRLF 206 { 207 if (epsvall) { 208 reply(501, "no LPRT allowed after EPSV ALL"); 209 goto lprt_done; 210 } 211 if (!$2) 212 goto lprt_done; 213 if (port_check("LPRT") == 1) 214 goto lprt_done; 215 #ifdef INET6 216 if (his_addr.su_family != AF_INET6) { 217 usedefault = 1; 218 reply(500, "Invalid address rejected."); 219 goto lprt_done; 220 } 221 if (port_check_v6("LPRT") == 1) 222 goto lprt_done; 223 #endif 224 lprt_done: 225 42; /* Life, the universe and everything! */ 226 } 227 | EPRT check_login SP STRING CRLF 228 { 229 char delim; 230 char *tmp = NULL; 231 char *p, *q; 232 char *result[3]; 233 struct addrinfo hints; 234 struct addrinfo *res; 235 int i; 236 237 if (epsvall) { 238 reply(501, "no EPRT allowed after EPSV ALL"); 239 goto eprt_done; 240 } 241 if (!$2) 242 goto eprt_done; 243 244 memset(&data_dest, 0, sizeof(data_dest)); 245 tmp = strdup($4); 246 if (ftpdebug) 247 syslog(LOG_DEBUG, "%s", tmp); 248 if (!tmp) { 249 fatalerror("not enough core"); 250 /*NOTREACHED*/ 251 } 252 p = tmp; 253 delim = p[0]; 254 p++; 255 memset(result, 0, sizeof(result)); 256 for (i = 0; i < 3; i++) { 257 q = strchr(p, delim); 258 if (!q || *q != delim) { 259 parsefail: 260 reply(500, 261 "Invalid argument, rejected."); 262 if (tmp) 263 free(tmp); 264 usedefault = 1; 265 goto eprt_done; 266 } 267 *q++ = '\0'; 268 result[i] = p; 269 if (ftpdebug) 270 syslog(LOG_DEBUG, "%d: %s", i, p); 271 p = q; 272 } 273 274 /* some more sanity check */ 275 p = result[0]; 276 while (*p) { 277 if (!isdigit(*p)) 278 goto parsefail; 279 p++; 280 } 281 p = result[2]; 282 while (*p) { 283 if (!isdigit(*p)) 284 goto parsefail; 285 p++; 286 } 287 288 /* grab address */ 289 memset(&hints, 0, sizeof(hints)); 290 if (atoi(result[0]) == 1) 291 hints.ai_family = PF_INET; 292 #ifdef INET6 293 else if (atoi(result[0]) == 2) 294 hints.ai_family = PF_INET6; 295 #endif 296 else 297 hints.ai_family = PF_UNSPEC; /*XXX*/ 298 hints.ai_socktype = SOCK_STREAM; 299 i = getaddrinfo(result[1], result[2], &hints, &res); 300 if (i) 301 goto parsefail; 302 memcpy(&data_dest, res->ai_addr, res->ai_addrlen); 303 #ifdef INET6 304 if (his_addr.su_family == AF_INET6 305 && data_dest.su_family == AF_INET6) { 306 /* XXX more sanity checks! */ 307 data_dest.su_sin6.sin6_scope_id = 308 his_addr.su_sin6.sin6_scope_id; 309 } 310 #endif 311 free(tmp); 312 tmp = NULL; 313 314 if (port_check("EPRT") == 1) 315 goto eprt_done; 316 #ifdef INET6 317 if (his_addr.su_family != AF_INET6) { 318 usedefault = 1; 319 reply(500, "Invalid address rejected."); 320 goto eprt_done; 321 } 322 if (port_check_v6("EPRT") == 1) 323 goto eprt_done; 324 #endif 325 eprt_done: 326 free($4); 327 } 328 | PASV check_login CRLF 329 { 330 if (epsvall) 331 reply(501, "no PASV allowed after EPSV ALL"); 332 else if ($2) 333 passive(); 334 } 335 | LPSV check_login CRLF 336 { 337 if (epsvall) 338 reply(501, "no LPSV allowed after EPSV ALL"); 339 else if ($2) 340 long_passive("LPSV", PF_UNSPEC); 341 } 342 | EPSV check_login_epsv SP NUMBER CRLF 343 { 344 if ($2) { 345 int pf; 346 switch ($4.i) { 347 case 1: 348 pf = PF_INET; 349 break; 350 #ifdef INET6 351 case 2: 352 pf = PF_INET6; 353 break; 354 #endif 355 default: 356 pf = -1; /*junk value*/ 357 break; 358 } 359 long_passive("EPSV", pf); 360 } 361 } 362 | EPSV check_login_epsv SP ALL CRLF 363 { 364 if ($2) { 365 reply(200, 366 "EPSV ALL command successful."); 367 epsvall++; 368 } 369 } 370 | EPSV check_login_epsv CRLF 371 { 372 if ($2) 373 long_passive("EPSV", PF_UNSPEC); 374 } 375 | TYPE check_login SP type_code CRLF 376 { 377 if ($2) { 378 switch (cmd_type) { 379 380 case TYPE_A: 381 if (cmd_form == FORM_N) { 382 reply(200, "Type set to A."); 383 type = cmd_type; 384 form = cmd_form; 385 } else 386 reply(504, "Form must be N."); 387 break; 388 389 case TYPE_E: 390 reply(504, "Type E not implemented."); 391 break; 392 393 case TYPE_I: 394 reply(200, "Type set to I."); 395 type = cmd_type; 396 break; 397 398 case TYPE_L: 399 #if CHAR_BIT == 8 400 if (cmd_bytesz == 8) { 401 reply(200, 402 "Type set to L (byte size 8)."); 403 type = cmd_type; 404 } else 405 reply(504, "Byte size must be 8."); 406 #else /* CHAR_BIT == 8 */ 407 UNIMPLEMENTED for CHAR_BIT != 8 408 #endif /* CHAR_BIT == 8 */ 409 } 410 } 411 } 412 | STRU check_login SP struct_code CRLF 413 { 414 if ($2) { 415 switch ($4) { 416 417 case STRU_F: 418 reply(200, "STRU F ok."); 419 break; 420 421 default: 422 reply(504, "Unimplemented STRU type."); 423 } 424 } 425 } 426 | MODE check_login SP mode_code CRLF 427 { 428 if ($2) { 429 switch ($4) { 430 431 case MODE_S: 432 reply(200, "MODE S ok."); 433 break; 434 435 default: 436 reply(502, "Unimplemented MODE type."); 437 } 438 } 439 } 440 | ALLO check_login SP NUMBER CRLF 441 { 442 if ($2) { 443 reply(202, "ALLO command ignored."); 444 } 445 } 446 | ALLO check_login SP NUMBER SP R SP NUMBER CRLF 447 { 448 if ($2) { 449 reply(202, "ALLO command ignored."); 450 } 451 } 452 | RETR check_login SP pathname CRLF 453 { 454 if (noretr || (guest && noguestretr)) 455 reply(500, "RETR command is disabled"); 456 else if ($2 && $4 != NULL) 457 retrieve((char *) 0, $4); 458 459 if ($4 != NULL) 460 free($4); 461 } 462 | STOR check_login_ro SP pathname CRLF 463 { 464 if ($2 && $4 != NULL) 465 store($4, "w", 0); 466 if ($4 != NULL) 467 free($4); 468 } 469 | APPE check_login_ro SP pathname CRLF 470 { 471 if ($2 && $4 != NULL) 472 store($4, "a", 0); 473 if ($4 != NULL) 474 free($4); 475 } 476 | NLST check_login CRLF 477 { 478 if ($2) 479 send_file_list("."); 480 } 481 | NLST check_login SP pathstring CRLF 482 { 483 if ($2) 484 send_file_list($4); 485 free($4); 486 } 487 | LIST check_login CRLF 488 { 489 if ($2) 490 retrieve(_PATH_LS " -lgA", ""); 491 } 492 | LIST check_login SP pathstring CRLF 493 { 494 if ($2) 495 retrieve(_PATH_LS " -lgA %s", $4); 496 free($4); 497 } 498 | STAT check_login SP pathname CRLF 499 { 500 if ($2 && $4 != NULL) 501 statfilecmd($4); 502 if ($4 != NULL) 503 free($4); 504 } 505 | STAT check_login CRLF 506 { 507 if ($2) { 508 statcmd(); 509 } 510 } 511 | DELE check_login_ro SP pathname CRLF 512 { 513 if ($2 && $4 != NULL) 514 delete($4); 515 if ($4 != NULL) 516 free($4); 517 } 518 | RNTO check_login_ro SP pathname CRLF 519 { 520 if ($2 && $4 != NULL) { 521 if (fromname) { 522 renamecmd(fromname, $4); 523 free(fromname); 524 fromname = (char *) 0; 525 } else { 526 reply(503, "Bad sequence of commands."); 527 } 528 } 529 if ($4 != NULL) 530 free($4); 531 } 532 | ABOR check_login CRLF 533 { 534 if ($2) 535 reply(225, "ABOR command successful."); 536 } 537 | CWD check_login CRLF 538 { 539 if ($2) { 540 cwd(homedir); 541 } 542 } 543 | CWD check_login SP pathname CRLF 544 { 545 if ($2 && $4 != NULL) 546 cwd($4); 547 if ($4 != NULL) 548 free($4); 549 } 550 | HELP CRLF 551 { 552 help(cmdtab, (char *) 0); 553 } 554 | HELP SP STRING CRLF 555 { 556 char *cp = $3; 557 558 if (strncasecmp(cp, "SITE", 4) == 0) { 559 cp = $3 + 4; 560 if (*cp == ' ') 561 cp++; 562 if (*cp) 563 help(sitetab, cp); 564 else 565 help(sitetab, (char *) 0); 566 } else 567 help(cmdtab, $3); 568 free($3); 569 } 570 | NOOP CRLF 571 { 572 reply(200, "NOOP command successful."); 573 } 574 | MKD check_login_ro SP pathname CRLF 575 { 576 if ($2 && $4 != NULL) 577 makedir($4); 578 if ($4 != NULL) 579 free($4); 580 } 581 | RMD check_login_ro SP pathname CRLF 582 { 583 if ($2 && $4 != NULL) 584 removedir($4); 585 if ($4 != NULL) 586 free($4); 587 } 588 | PWD check_login CRLF 589 { 590 if ($2) 591 pwd(); 592 } 593 | CDUP check_login CRLF 594 { 595 if ($2) 596 cwd(".."); 597 } 598 | SITE SP HELP CRLF 599 { 600 help(sitetab, (char *) 0); 601 } 602 | SITE SP HELP SP STRING CRLF 603 { 604 help(sitetab, $5); 605 free($5); 606 } 607 | SITE SP MDFIVE check_login SP pathname CRLF 608 { 609 char p[64], *q; 610 611 if ($4 && $6) { 612 q = MD5File($6, p); 613 if (q != NULL) 614 reply(200, "MD5(%s) = %s", $6, p); 615 else 616 perror_reply(550, $6); 617 } 618 if ($6) 619 free($6); 620 } 621 | SITE SP UMASK check_login CRLF 622 { 623 int oldmask; 624 625 if ($4) { 626 oldmask = umask(0); 627 (void) umask(oldmask); 628 reply(200, "Current UMASK is %03o", oldmask); 629 } 630 } 631 | SITE SP UMASK check_login SP octal_number CRLF 632 { 633 int oldmask; 634 635 if ($4) { 636 if (($6 == -1) || ($6 > 0777)) { 637 reply(501, "Bad UMASK value"); 638 } else { 639 oldmask = umask($6); 640 reply(200, 641 "UMASK set to %03o (was %03o)", 642 $6, oldmask); 643 } 644 } 645 } 646 | SITE SP CHMOD check_login_ro SP octal_number SP pathname CRLF 647 { 648 if ($4 && ($8 != NULL)) { 649 if (($6 == -1 ) || ($6 > 0777)) 650 reply(501, "Bad mode value"); 651 else if (chmod($8, $6) < 0) 652 perror_reply(550, $8); 653 else 654 reply(200, "CHMOD command successful."); 655 } 656 if ($8 != NULL) 657 free($8); 658 } 659 | SITE SP check_login IDLE CRLF 660 { 661 if ($3) 662 reply(200, 663 "Current IDLE time limit is %d seconds; max %d", 664 timeout, maxtimeout); 665 } 666 | SITE SP check_login IDLE SP NUMBER CRLF 667 { 668 if ($3) { 669 if ($6.i < 30 || $6.i > maxtimeout) { 670 reply(501, 671 "Maximum IDLE time must be between 30 and %d seconds", 672 maxtimeout); 673 } else { 674 timeout = $6.i; 675 (void) alarm((unsigned) timeout); 676 reply(200, 677 "Maximum IDLE time set to %d seconds", 678 timeout); 679 } 680 } 681 } 682 | STOU check_login_ro SP pathname CRLF 683 { 684 if ($2 && $4 != NULL) 685 store($4, "w", 1); 686 if ($4 != NULL) 687 free($4); 688 } 689 | SYST check_login CRLF 690 { 691 if ($2) { 692 if (hostinfo) 693 #ifdef BSD 694 reply(215, "UNIX Type: L%d Version: BSD-%d", 695 CHAR_BIT, BSD); 696 #else /* BSD */ 697 reply(215, "UNIX Type: L%d", CHAR_BIT); 698 #endif /* BSD */ 699 else 700 reply(215, "UNKNOWN Type: L%d", CHAR_BIT); 701 } 702 } 703 704 /* 705 * SIZE is not in RFC959, but Postel has blessed it and 706 * it will be in the updated RFC. 707 * 708 * Return size of file in a format suitable for 709 * using with RESTART (we just count bytes). 710 */ 711 | SIZE check_login SP pathname CRLF 712 { 713 if ($2 && $4 != NULL) 714 sizecmd($4); 715 if ($4 != NULL) 716 free($4); 717 } 718 719 /* 720 * MDTM is not in RFC959, but Postel has blessed it and 721 * it will be in the updated RFC. 722 * 723 * Return modification time of file as an ISO 3307 724 * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx 725 * where xxx is the fractional second (of any precision, 726 * not necessarily 3 digits) 727 */ 728 | MDTM check_login SP pathname CRLF 729 { 730 if ($2 && $4 != NULL) { 731 struct stat stbuf; 732 if (stat($4, &stbuf) < 0) 733 reply(550, "%s: %s", 734 $4, strerror(errno)); 735 else if (!S_ISREG(stbuf.st_mode)) { 736 reply(550, "%s: not a plain file.", $4); 737 } else { 738 struct tm *t; 739 t = gmtime(&stbuf.st_mtime); 740 reply(213, 741 "%04d%02d%02d%02d%02d%02d", 742 1900 + t->tm_year, 743 t->tm_mon+1, t->tm_mday, 744 t->tm_hour, t->tm_min, t->tm_sec); 745 } 746 } 747 if ($4 != NULL) 748 free($4); 749 } 750 | QUIT CRLF 751 { 752 reply(221, "Goodbye."); 753 dologout(0); 754 } 755 | NOTIMPL 756 { 757 nack($1); 758 } 759 | error 760 { 761 yyclearin; /* discard lookahead data */ 762 yyerrok; /* clear error condition */ 763 state = CMD; /* reset lexer state */ 764 } 765 ; 766 rcmd 767 : RNFR check_login_ro SP pathname CRLF 768 { 769 restart_point = (off_t) 0; 770 if ($2 && $4) { 771 if (fromname) 772 free(fromname); 773 fromname = (char *) 0; 774 if (renamefrom($4)) 775 fromname = $4; 776 else 777 free($4); 778 } else if ($4) { 779 free($4); 780 } 781 } 782 | REST check_login SP NUMBER CRLF 783 { 784 if ($2) { 785 if (fromname) 786 free(fromname); 787 fromname = (char *) 0; 788 restart_point = $4.o; 789 reply(350, "Restarting at %llu. %s", 790 restart_point, 791 "Send STORE or RETRIEVE to initiate transfer."); 792 } 793 } 794 ; 795 796 username 797 : STRING 798 ; 799 800 password 801 : /* empty */ 802 { 803 $$ = (char *)calloc(1, sizeof(char)); 804 } 805 | STRING 806 ; 807 808 byte_size 809 : NUMBER 810 { 811 $$ = $1.i; 812 } 813 ; 814 815 host_port 816 : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 817 NUMBER COMMA NUMBER 818 { 819 char *a, *p; 820 821 data_dest.su_len = sizeof(struct sockaddr_in); 822 data_dest.su_family = AF_INET; 823 p = (char *)&data_dest.su_sin.sin_port; 824 p[0] = $9.i; p[1] = $11.i; 825 a = (char *)&data_dest.su_sin.sin_addr; 826 a[0] = $1.i; a[1] = $3.i; a[2] = $5.i; a[3] = $7.i; 827 } 828 ; 829 830 host_long_port 831 : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 832 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 833 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 834 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 835 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 836 NUMBER 837 { 838 char *a, *p; 839 840 memset(&data_dest, 0, sizeof(data_dest)); 841 data_dest.su_len = sizeof(struct sockaddr_in6); 842 data_dest.su_family = AF_INET6; 843 p = (char *)&data_dest.su_port; 844 p[0] = $39.i; p[1] = $41.i; 845 a = (char *)&data_dest.su_sin6.sin6_addr; 846 a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 847 a[4] = $13.i; a[5] = $15.i; a[6] = $17.i; a[7] = $19.i; 848 a[8] = $21.i; a[9] = $23.i; a[10] = $25.i; a[11] = $27.i; 849 a[12] = $29.i; a[13] = $31.i; a[14] = $33.i; a[15] = $35.i; 850 if (his_addr.su_family == AF_INET6) { 851 /* XXX more sanity checks! */ 852 data_dest.su_sin6.sin6_scope_id = 853 his_addr.su_sin6.sin6_scope_id; 854 } 855 if ($1.i != 6 || $3.i != 16 || $37.i != 2) 856 memset(&data_dest, 0, sizeof(data_dest)); 857 } 858 | NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 859 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 860 NUMBER 861 { 862 char *a, *p; 863 864 memset(&data_dest, 0, sizeof(data_dest)); 865 data_dest.su_sin.sin_len = sizeof(struct sockaddr_in); 866 data_dest.su_family = AF_INET; 867 p = (char *)&data_dest.su_port; 868 p[0] = $15.i; p[1] = $17.i; 869 a = (char *)&data_dest.su_sin.sin_addr; 870 a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 871 if ($1.i != 4 || $3.i != 4 || $13.i != 2) 872 memset(&data_dest, 0, sizeof(data_dest)); 873 } 874 ; 875 876 form_code 877 : N 878 { 879 $$ = FORM_N; 880 } 881 | T 882 { 883 $$ = FORM_T; 884 } 885 | C 886 { 887 $$ = FORM_C; 888 } 889 ; 890 891 type_code 892 : A 893 { 894 cmd_type = TYPE_A; 895 cmd_form = FORM_N; 896 } 897 | A SP form_code 898 { 899 cmd_type = TYPE_A; 900 cmd_form = $3; 901 } 902 | E 903 { 904 cmd_type = TYPE_E; 905 cmd_form = FORM_N; 906 } 907 | E SP form_code 908 { 909 cmd_type = TYPE_E; 910 cmd_form = $3; 911 } 912 | I 913 { 914 cmd_type = TYPE_I; 915 } 916 | L 917 { 918 cmd_type = TYPE_L; 919 cmd_bytesz = CHAR_BIT; 920 } 921 | L SP byte_size 922 { 923 cmd_type = TYPE_L; 924 cmd_bytesz = $3; 925 } 926 /* this is for a bug in the BBN ftp */ 927 | L byte_size 928 { 929 cmd_type = TYPE_L; 930 cmd_bytesz = $2; 931 } 932 ; 933 934 struct_code 935 : F 936 { 937 $$ = STRU_F; 938 } 939 | R 940 { 941 $$ = STRU_R; 942 } 943 | P 944 { 945 $$ = STRU_P; 946 } 947 ; 948 949 mode_code 950 : S 951 { 952 $$ = MODE_S; 953 } 954 | B 955 { 956 $$ = MODE_B; 957 } 958 | C 959 { 960 $$ = MODE_C; 961 } 962 ; 963 964 pathname 965 : pathstring 966 { 967 if (logged_in && $1) { 968 char *p; 969 970 /* 971 * Expand ~user manually since glob(3) 972 * will return the unexpanded pathname 973 * if the corresponding file/directory 974 * doesn't exist yet. Using sole glob(3) 975 * would break natural commands like 976 * MKD ~user/newdir 977 * or 978 * RNTO ~/newfile 979 */ 980 if ((p = exptilde($1)) != NULL) { 981 $$ = expglob(p); 982 free(p); 983 } else 984 $$ = NULL; 985 free($1); 986 } else 987 $$ = $1; 988 } 989 ; 990 991 pathstring 992 : STRING 993 ; 994 995 octal_number 996 : NUMBER 997 { 998 int ret, dec, multby, digit; 999 1000 /* 1001 * Convert a number that was read as decimal number 1002 * to what it would be if it had been read as octal. 1003 */ 1004 dec = $1.i; 1005 multby = 1; 1006 ret = 0; 1007 while (dec) { 1008 digit = dec%10; 1009 if (digit > 7) { 1010 ret = -1; 1011 break; 1012 } 1013 ret += digit * multby; 1014 multby *= 8; 1015 dec /= 10; 1016 } 1017 $$ = ret; 1018 } 1019 ; 1020 1021 1022 check_login 1023 : /* empty */ 1024 { 1025 $$ = check_login1(); 1026 } 1027 ; 1028 1029 check_login_epsv 1030 : /* empty */ 1031 { 1032 if (noepsv) { 1033 reply(500, "EPSV command disabled"); 1034 $$ = 0; 1035 } 1036 else 1037 $$ = check_login1(); 1038 } 1039 ; 1040 1041 check_login_ro 1042 : /* empty */ 1043 { 1044 if (readonly) { 1045 reply(550, "Permission denied."); 1046 $$ = 0; 1047 } 1048 else 1049 $$ = check_login1(); 1050 } 1051 ; 1052 1053 %% 1054 1055 #define CMD 0 /* beginning of command */ 1056 #define ARGS 1 /* expect miscellaneous arguments */ 1057 #define STR1 2 /* expect SP followed by STRING */ 1058 #define STR2 3 /* expect STRING */ 1059 #define OSTR 4 /* optional SP then STRING */ 1060 #define ZSTR1 5 /* optional SP then optional STRING */ 1061 #define ZSTR2 6 /* optional STRING after SP */ 1062 #define SITECMD 7 /* SITE command */ 1063 #define NSTR 8 /* Number followed by a string */ 1064 1065 #define MAXGLOBARGS 1000 1066 1067 #define MAXASIZE 10240 /* Deny ASCII SIZE on files larger than that */ 1068 1069 struct tab { 1070 char *name; 1071 short token; 1072 short state; 1073 short implemented; /* 1 if command is implemented */ 1074 char *help; 1075 }; 1076 1077 struct tab cmdtab[] = { /* In order defined in RFC 765 */ 1078 { "USER", USER, STR1, 1, "<sp> username" }, 1079 { "PASS", PASS, ZSTR1, 1, "[<sp> [password]]" }, 1080 { "ACCT", ACCT, STR1, 0, "(specify account)" }, 1081 { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, 1082 { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, 1083 { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, 1084 { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4, b5" }, 1085 { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." }, 1086 { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" }, 1087 { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, 1088 { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, 1089 { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" }, 1090 { "TYPE", TYPE, ARGS, 1, "<sp> { A | E | I | L }" }, 1091 { "STRU", STRU, ARGS, 1, "(specify file structure)" }, 1092 { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, 1093 { "RETR", RETR, STR1, 1, "<sp> file-name" }, 1094 { "STOR", STOR, STR1, 1, "<sp> file-name" }, 1095 { "APPE", APPE, STR1, 1, "<sp> file-name" }, 1096 { "MLFL", MLFL, OSTR, 0, "(mail file)" }, 1097 { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, 1098 { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, 1099 { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, 1100 { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, 1101 { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, 1102 { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, 1103 { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, 1104 { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, 1105 { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, 1106 { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, 1107 { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, 1108 { "DELE", DELE, STR1, 1, "<sp> file-name" }, 1109 { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1110 { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1111 { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, 1112 { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, 1113 { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, 1114 { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, 1115 { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, 1116 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1117 { "NOOP", NOOP, ARGS, 1, "" }, 1118 { "MKD", MKD, STR1, 1, "<sp> path-name" }, 1119 { "XMKD", MKD, STR1, 1, "<sp> path-name" }, 1120 { "RMD", RMD, STR1, 1, "<sp> path-name" }, 1121 { "XRMD", RMD, STR1, 1, "<sp> path-name" }, 1122 { "PWD", PWD, ARGS, 1, "(return current directory)" }, 1123 { "XPWD", PWD, ARGS, 1, "(return current directory)" }, 1124 { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1125 { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1126 { "STOU", STOU, STR1, 1, "<sp> file-name" }, 1127 { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, 1128 { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, 1129 { NULL, 0, 0, 0, 0 } 1130 }; 1131 1132 struct tab sitetab[] = { 1133 { "MD5", MDFIVE, STR1, 1, "[ <sp> file-name ]" }, 1134 { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, 1135 { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, 1136 { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, 1137 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1138 { NULL, 0, 0, 0, 0 } 1139 }; 1140 1141 static char *copy(char *); 1142 static char *expglob(char *); 1143 static char *exptilde(char *); 1144 static void help(struct tab *, char *); 1145 static struct tab * 1146 lookup(struct tab *, char *); 1147 static int port_check(const char *); 1148 static int port_check_v6(const char *); 1149 static void sizecmd(char *); 1150 static void toolong(int); 1151 static void v4map_data_dest(void); 1152 static int yylex(void); 1153 1154 static struct tab * 1155 lookup(struct tab *p, char *cmd) 1156 { 1157 1158 for (; p->name != NULL; p++) 1159 if (strcmp(cmd, p->name) == 0) 1160 return (p); 1161 return (0); 1162 } 1163 1164 #include <arpa/telnet.h> 1165 1166 /* 1167 * getline - a hacked up version of fgets to ignore TELNET escape codes. 1168 */ 1169 char * 1170 getline(char *s, int n, FILE *iop) 1171 { 1172 int c; 1173 register char *cs; 1174 sigset_t sset, osset; 1175 1176 cs = s; 1177 /* tmpline may contain saved command from urgent mode interruption */ 1178 for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 1179 *cs++ = tmpline[c]; 1180 if (tmpline[c] == '\n') { 1181 *cs++ = '\0'; 1182 if (ftpdebug) 1183 syslog(LOG_DEBUG, "command: %s", s); 1184 tmpline[0] = '\0'; 1185 return(s); 1186 } 1187 if (c == 0) 1188 tmpline[0] = '\0'; 1189 } 1190 /* SIGURG would interrupt stdio if not blocked during the read loop */ 1191 sigemptyset(&sset); 1192 sigaddset(&sset, SIGURG); 1193 sigprocmask(SIG_BLOCK, &sset, &osset); 1194 while ((c = getc(iop)) != EOF) { 1195 c &= 0377; 1196 if (c == IAC) { 1197 if ((c = getc(iop)) == EOF) 1198 goto got_eof; 1199 c &= 0377; 1200 switch (c) { 1201 case WILL: 1202 case WONT: 1203 if ((c = getc(iop)) == EOF) 1204 goto got_eof; 1205 printf("%c%c%c", IAC, DONT, 0377&c); 1206 (void) fflush(stdout); 1207 continue; 1208 case DO: 1209 case DONT: 1210 if ((c = getc(iop)) == EOF) 1211 goto got_eof; 1212 printf("%c%c%c", IAC, WONT, 0377&c); 1213 (void) fflush(stdout); 1214 continue; 1215 case IAC: 1216 break; 1217 default: 1218 continue; /* ignore command */ 1219 } 1220 } 1221 *cs++ = c; 1222 if (--n <= 0 || c == '\n') 1223 break; 1224 } 1225 got_eof: 1226 sigprocmask(SIG_SETMASK, &osset, NULL); 1227 if (c == EOF && cs == s) 1228 return (NULL); 1229 *cs++ = '\0'; 1230 if (ftpdebug) { 1231 if (!guest && strncasecmp("pass ", s, 5) == 0) { 1232 /* Don't syslog passwords */ 1233 syslog(LOG_DEBUG, "command: %.5s ???", s); 1234 } else { 1235 register char *cp; 1236 register int len; 1237 1238 /* Don't syslog trailing CR-LF */ 1239 len = strlen(s); 1240 cp = s + len - 1; 1241 while (cp >= s && (*cp == '\n' || *cp == '\r')) { 1242 --cp; 1243 --len; 1244 } 1245 syslog(LOG_DEBUG, "command: %.*s", len, s); 1246 } 1247 } 1248 return (s); 1249 } 1250 1251 static void 1252 toolong(int signo) 1253 { 1254 1255 reply(421, 1256 "Timeout (%d seconds): closing control connection.", timeout); 1257 if (logging) 1258 syslog(LOG_INFO, "User %s timed out after %d seconds", 1259 (pw ? pw -> pw_name : "unknown"), timeout); 1260 dologout(1); 1261 } 1262 1263 static int 1264 yylex(void) 1265 { 1266 static int cpos; 1267 char *cp, *cp2; 1268 struct tab *p; 1269 int n; 1270 char c; 1271 1272 for (;;) { 1273 switch (state) { 1274 1275 case CMD: 1276 (void) signal(SIGALRM, toolong); 1277 (void) alarm((unsigned) timeout); 1278 if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { 1279 reply(221, "You could at least say goodbye."); 1280 dologout(0); 1281 } 1282 (void) alarm(0); 1283 #ifdef SETPROCTITLE 1284 if (strncasecmp(cbuf, "PASS", 4) != 0) 1285 setproctitle("%s: %s", proctitle, cbuf); 1286 #endif /* SETPROCTITLE */ 1287 if ((cp = strchr(cbuf, '\r'))) { 1288 *cp++ = '\n'; 1289 *cp = '\0'; 1290 } 1291 if ((cp = strpbrk(cbuf, " \n"))) 1292 cpos = cp - cbuf; 1293 if (cpos == 0) 1294 cpos = 4; 1295 c = cbuf[cpos]; 1296 cbuf[cpos] = '\0'; 1297 upper(cbuf); 1298 p = lookup(cmdtab, cbuf); 1299 cbuf[cpos] = c; 1300 if (p != 0) { 1301 yylval.s = p->name; 1302 if (!p->implemented) 1303 return (NOTIMPL); /* state remains CMD */ 1304 state = p->state; 1305 return (p->token); 1306 } 1307 break; 1308 1309 case SITECMD: 1310 if (cbuf[cpos] == ' ') { 1311 cpos++; 1312 return (SP); 1313 } 1314 cp = &cbuf[cpos]; 1315 if ((cp2 = strpbrk(cp, " \n"))) 1316 cpos = cp2 - cbuf; 1317 c = cbuf[cpos]; 1318 cbuf[cpos] = '\0'; 1319 upper(cp); 1320 p = lookup(sitetab, cp); 1321 cbuf[cpos] = c; 1322 if (guest == 0 && p != 0) { 1323 yylval.s = p->name; 1324 if (!p->implemented) { 1325 state = CMD; 1326 return (NOTIMPL); 1327 } 1328 state = p->state; 1329 return (p->token); 1330 } 1331 state = CMD; 1332 break; 1333 1334 case ZSTR1: 1335 case OSTR: 1336 if (cbuf[cpos] == '\n') { 1337 state = CMD; 1338 return (CRLF); 1339 } 1340 /* FALLTHROUGH */ 1341 1342 case STR1: 1343 dostr1: 1344 if (cbuf[cpos] == ' ') { 1345 cpos++; 1346 state = state == OSTR ? STR2 : state+1; 1347 return (SP); 1348 } 1349 break; 1350 1351 case ZSTR2: 1352 if (cbuf[cpos] == '\n') { 1353 state = CMD; 1354 return (CRLF); 1355 } 1356 /* FALLTHROUGH */ 1357 1358 case STR2: 1359 cp = &cbuf[cpos]; 1360 n = strlen(cp); 1361 cpos += n - 1; 1362 /* 1363 * Make sure the string is nonempty and \n terminated. 1364 */ 1365 if (n > 1 && cbuf[cpos] == '\n') { 1366 cbuf[cpos] = '\0'; 1367 yylval.s = copy(cp); 1368 cbuf[cpos] = '\n'; 1369 state = ARGS; 1370 return (STRING); 1371 } 1372 break; 1373 1374 case NSTR: 1375 if (cbuf[cpos] == ' ') { 1376 cpos++; 1377 return (SP); 1378 } 1379 if (isdigit(cbuf[cpos])) { 1380 cp = &cbuf[cpos]; 1381 while (isdigit(cbuf[++cpos])) 1382 ; 1383 c = cbuf[cpos]; 1384 cbuf[cpos] = '\0'; 1385 yylval.u.i = atoi(cp); 1386 cbuf[cpos] = c; 1387 state = STR1; 1388 return (NUMBER); 1389 } 1390 state = STR1; 1391 goto dostr1; 1392 1393 case ARGS: 1394 if (isdigit(cbuf[cpos])) { 1395 cp = &cbuf[cpos]; 1396 while (isdigit(cbuf[++cpos])) 1397 ; 1398 c = cbuf[cpos]; 1399 cbuf[cpos] = '\0'; 1400 yylval.u.i = atoi(cp); 1401 yylval.u.o = strtoull(cp, (char **)NULL, 10); 1402 cbuf[cpos] = c; 1403 return (NUMBER); 1404 } 1405 if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0 1406 && !isalnum(cbuf[cpos + 3])) { 1407 cpos += 3; 1408 return ALL; 1409 } 1410 switch (cbuf[cpos++]) { 1411 1412 case '\n': 1413 state = CMD; 1414 return (CRLF); 1415 1416 case ' ': 1417 return (SP); 1418 1419 case ',': 1420 return (COMMA); 1421 1422 case 'A': 1423 case 'a': 1424 return (A); 1425 1426 case 'B': 1427 case 'b': 1428 return (B); 1429 1430 case 'C': 1431 case 'c': 1432 return (C); 1433 1434 case 'E': 1435 case 'e': 1436 return (E); 1437 1438 case 'F': 1439 case 'f': 1440 return (F); 1441 1442 case 'I': 1443 case 'i': 1444 return (I); 1445 1446 case 'L': 1447 case 'l': 1448 return (L); 1449 1450 case 'N': 1451 case 'n': 1452 return (N); 1453 1454 case 'P': 1455 case 'p': 1456 return (P); 1457 1458 case 'R': 1459 case 'r': 1460 return (R); 1461 1462 case 'S': 1463 case 's': 1464 return (S); 1465 1466 case 'T': 1467 case 't': 1468 return (T); 1469 1470 } 1471 break; 1472 1473 default: 1474 fatalerror("Unknown state in scanner."); 1475 } 1476 state = CMD; 1477 return (LEXERR); 1478 } 1479 } 1480 1481 void 1482 upper(char *s) 1483 { 1484 while (*s != '\0') { 1485 if (islower(*s)) 1486 *s = toupper(*s); 1487 s++; 1488 } 1489 } 1490 1491 static char * 1492 copy(char *s) 1493 { 1494 char *p; 1495 1496 p = malloc((unsigned) strlen(s) + 1); 1497 if (p == NULL) 1498 fatalerror("Ran out of memory."); 1499 (void) strcpy(p, s); 1500 return (p); 1501 } 1502 1503 static void 1504 help(struct tab *ctab, char *s) 1505 { 1506 struct tab *c; 1507 int width, NCMDS; 1508 char *type; 1509 1510 if (ctab == sitetab) 1511 type = "SITE "; 1512 else 1513 type = ""; 1514 width = 0, NCMDS = 0; 1515 for (c = ctab; c->name != NULL; c++) { 1516 int len = strlen(c->name); 1517 1518 if (len > width) 1519 width = len; 1520 NCMDS++; 1521 } 1522 width = (width + 8) &~ 7; 1523 if (s == 0) { 1524 int i, j, w; 1525 int columns, lines; 1526 1527 lreply(214, "The following %scommands are recognized %s.", 1528 type, "(* =>'s unimplemented)"); 1529 columns = 76 / width; 1530 if (columns == 0) 1531 columns = 1; 1532 lines = (NCMDS + columns - 1) / columns; 1533 for (i = 0; i < lines; i++) { 1534 printf(" "); 1535 for (j = 0; j < columns; j++) { 1536 c = ctab + j * lines + i; 1537 printf("%s%c", c->name, 1538 c->implemented ? ' ' : '*'); 1539 if (c + lines >= &ctab[NCMDS]) 1540 break; 1541 w = strlen(c->name) + 1; 1542 while (w < width) { 1543 putchar(' '); 1544 w++; 1545 } 1546 } 1547 printf("\r\n"); 1548 } 1549 (void) fflush(stdout); 1550 if (hostinfo) 1551 reply(214, "Direct comments to ftp-bugs@%s.", hostname); 1552 else 1553 reply(214, "End."); 1554 return; 1555 } 1556 upper(s); 1557 c = lookup(ctab, s); 1558 if (c == (struct tab *)0) { 1559 reply(502, "Unknown command %s.", s); 1560 return; 1561 } 1562 if (c->implemented) 1563 reply(214, "Syntax: %s%s %s", type, c->name, c->help); 1564 else 1565 reply(214, "%s%-*s\t%s; unimplemented.", type, width, 1566 c->name, c->help); 1567 } 1568 1569 static void 1570 sizecmd(char *filename) 1571 { 1572 switch (type) { 1573 case TYPE_L: 1574 case TYPE_I: { 1575 struct stat stbuf; 1576 if (stat(filename, &stbuf) < 0) 1577 perror_reply(550, filename); 1578 else if (!S_ISREG(stbuf.st_mode)) 1579 reply(550, "%s: not a plain file.", filename); 1580 else 1581 reply(213, "%qu", stbuf.st_size); 1582 break; } 1583 case TYPE_A: { 1584 FILE *fin; 1585 int c; 1586 off_t count; 1587 struct stat stbuf; 1588 fin = fopen(filename, "r"); 1589 if (fin == NULL) { 1590 perror_reply(550, filename); 1591 return; 1592 } 1593 if (fstat(fileno(fin), &stbuf) < 0) { 1594 perror_reply(550, filename); 1595 (void) fclose(fin); 1596 return; 1597 } else if (!S_ISREG(stbuf.st_mode)) { 1598 reply(550, "%s: not a plain file.", filename); 1599 (void) fclose(fin); 1600 return; 1601 } else if (stbuf.st_size > MAXASIZE) { 1602 reply(550, "%s: too large for type A SIZE.", filename); 1603 (void) fclose(fin); 1604 return; 1605 } 1606 1607 count = 0; 1608 while((c=getc(fin)) != EOF) { 1609 if (c == '\n') /* will get expanded to \r\n */ 1610 count++; 1611 count++; 1612 } 1613 (void) fclose(fin); 1614 1615 reply(213, "%qd", count); 1616 break; } 1617 default: 1618 reply(504, "SIZE not implemented for type %s.", 1619 typenames[type]); 1620 } 1621 } 1622 1623 /* Return 1, if port check is done. Return 0, if not yet. */ 1624 static int 1625 port_check(const char *pcmd) 1626 { 1627 if (his_addr.su_family == AF_INET) { 1628 if (data_dest.su_family != AF_INET) { 1629 usedefault = 1; 1630 reply(500, "Invalid address rejected."); 1631 return 1; 1632 } 1633 if (paranoid && 1634 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1635 memcmp(&data_dest.su_sin.sin_addr, 1636 &his_addr.su_sin.sin_addr, 1637 sizeof(data_dest.su_sin.sin_addr)))) { 1638 usedefault = 1; 1639 reply(500, "Illegal PORT range rejected."); 1640 } else { 1641 usedefault = 0; 1642 if (pdata >= 0) { 1643 (void) close(pdata); 1644 pdata = -1; 1645 } 1646 reply(200, "%s command successful.", pcmd); 1647 } 1648 return 1; 1649 } 1650 return 0; 1651 } 1652 1653 static int 1654 check_login1(void) 1655 { 1656 if (logged_in) 1657 return 1; 1658 else { 1659 reply(530, "Please login with USER and PASS."); 1660 return 0; 1661 } 1662 } 1663 1664 /* 1665 * Replace leading "~user" in a pathname by the user's login directory. 1666 * Returned string will be in a freshly malloced buffer unless it's NULL. 1667 */ 1668 static char * 1669 exptilde(char *s) 1670 { 1671 char *p, *q; 1672 char *path, *user; 1673 struct passwd *ppw; 1674 1675 if ((p = strdup(s)) == NULL) 1676 return (NULL); 1677 if (*p != '~') 1678 return (p); 1679 1680 user = p + 1; /* skip tilde */ 1681 if ((path = strchr(p, '/')) != NULL) 1682 *(path++) = '\0'; /* separate ~user from the rest of path */ 1683 if (*user == '\0') /* no user specified, use the current user */ 1684 user = pw->pw_name; 1685 /* read passwd even for the current user since we may be chrooted */ 1686 if ((ppw = getpwnam(user)) != NULL) { 1687 /* user found, substitute login directory for ~user */ 1688 if (path) 1689 asprintf(&q, "%s/%s", ppw->pw_dir, path); 1690 else 1691 q = strdup(ppw->pw_dir); 1692 free(p); 1693 p = q; 1694 } else { 1695 /* user not found, undo the damage */ 1696 if (path) 1697 path[-1] = '/'; 1698 } 1699 return (p); 1700 } 1701 1702 /* 1703 * Expand glob(3) patterns possibly present in a pathname. 1704 * Avoid expanding to a pathname including '\r' or '\n' in order to 1705 * not disrupt the FTP protocol. 1706 * The expansion found must be unique. 1707 * Return the result as a malloced string, or NULL if an error occured. 1708 * 1709 * Problem: this production is used for all pathname 1710 * processing, but only gives a 550 error reply. 1711 * This is a valid reply in some cases but not in others. 1712 */ 1713 static char * 1714 expglob(char *s) 1715 { 1716 char *p, **pp, *rval; 1717 int flags = GLOB_BRACE | GLOB_NOCHECK; 1718 int n; 1719 glob_t gl; 1720 1721 memset(&gl, 0, sizeof(gl)); 1722 flags |= GLOB_LIMIT; 1723 gl.gl_matchc = MAXGLOBARGS; 1724 if (glob(s, flags, NULL, &gl) == 0 && gl.gl_pathc != 0) { 1725 for (pp = gl.gl_pathv, p = NULL, n = 0; *pp; pp++) 1726 if (*(*pp + strcspn(*pp, "\r\n")) == '\0') { 1727 p = *pp; 1728 n++; 1729 } 1730 if (n == 0) 1731 rval = strdup(s); 1732 else if (n == 1) 1733 rval = strdup(p); 1734 else { 1735 reply(550, "ambiguous"); 1736 rval = NULL; 1737 } 1738 } else { 1739 reply(550, "wildcard expansion error"); 1740 rval = NULL; 1741 } 1742 globfree(&gl); 1743 return (rval); 1744 } 1745 1746 #ifdef INET6 1747 /* Return 1, if port check is done. Return 0, if not yet. */ 1748 static int 1749 port_check_v6(const char *pcmd) 1750 { 1751 if (his_addr.su_family == AF_INET6) { 1752 if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) 1753 /* Convert data_dest into v4 mapped sockaddr.*/ 1754 v4map_data_dest(); 1755 if (data_dest.su_family != AF_INET6) { 1756 usedefault = 1; 1757 reply(500, "Invalid address rejected."); 1758 return 1; 1759 } 1760 if (paranoid && 1761 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1762 memcmp(&data_dest.su_sin6.sin6_addr, 1763 &his_addr.su_sin6.sin6_addr, 1764 sizeof(data_dest.su_sin6.sin6_addr)))) { 1765 usedefault = 1; 1766 reply(500, "Illegal PORT range rejected."); 1767 } else { 1768 usedefault = 0; 1769 if (pdata >= 0) { 1770 (void) close(pdata); 1771 pdata = -1; 1772 } 1773 reply(200, "%s command successful.", pcmd); 1774 } 1775 return 1; 1776 } 1777 return 0; 1778 } 1779 1780 static void 1781 v4map_data_dest(void) 1782 { 1783 struct in_addr savedaddr; 1784 int savedport; 1785 1786 if (data_dest.su_family != AF_INET) { 1787 usedefault = 1; 1788 reply(500, "Invalid address rejected."); 1789 return; 1790 } 1791 1792 savedaddr = data_dest.su_sin.sin_addr; 1793 savedport = data_dest.su_port; 1794 1795 memset(&data_dest, 0, sizeof(data_dest)); 1796 data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6); 1797 data_dest.su_sin6.sin6_family = AF_INET6; 1798 data_dest.su_sin6.sin6_port = savedport; 1799 memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2); 1800 memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12], 1801 (caddr_t)&savedaddr, sizeof(savedaddr)); 1802 } 1803 #endif 1804