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 76 extern union sockunion data_dest, his_addr; 77 extern int logged_in; 78 extern struct passwd *pw; 79 extern int guest; 80 extern int paranoid; 81 extern int logging; 82 extern int type; 83 extern int form; 84 extern int ftpdebug; 85 extern int timeout; 86 extern int maxtimeout; 87 extern int pdata; 88 extern char *hostname; 89 extern char remotehost[]; 90 extern char proctitle[]; 91 extern int usedefault; 92 extern int transflag; 93 extern char tmpline[]; 94 extern int readonly; 95 extern int noepsv; 96 extern int noretr; 97 extern int noguestretr; 98 extern char *typenames[]; /* defined in <arpa/ftp.h> included from ftpd.c */ 99 100 off_t restart_point; 101 102 static int cmd_type; 103 static int cmd_form; 104 static int cmd_bytesz; 105 static int state; 106 char cbuf[512]; 107 char *fromname = (char *) 0; 108 109 extern int epsvall; 110 111 %} 112 113 %union { 114 struct { 115 off_t o; 116 int i; 117 } u; 118 char *s; 119 } 120 121 %token 122 A B C E F I 123 L N P R S T 124 ALL 125 126 SP CRLF COMMA 127 128 USER PASS ACCT REIN QUIT PORT 129 PASV TYPE STRU MODE RETR STOR 130 APPE MLFL MAIL MSND MSOM MSAM 131 MRSQ MRCP ALLO REST RNFR RNTO 132 ABOR DELE CWD LIST NLST SITE 133 STAT HELP NOOP MKD RMD PWD 134 CDUP STOU SMNT SYST SIZE MDTM 135 LPRT LPSV EPRT EPSV 136 137 UMASK IDLE CHMOD MDFIVE 138 139 LEXERR 140 141 %token <s> STRING 142 %token <u> NUMBER 143 144 %type <u.i> check_login octal_number byte_size 145 %type <u.i> check_login_ro check_login_epsv 146 %type <u.i> struct_code mode_code type_code form_code 147 %type <s> pathstring pathname password username 148 %type <s> ALL 149 150 %start cmd_list 151 152 %% 153 154 cmd_list 155 : /* empty */ 156 | cmd_list cmd 157 { 158 if (fromname) 159 free(fromname); 160 fromname = (char *) 0; 161 restart_point = (off_t) 0; 162 } 163 | cmd_list rcmd 164 ; 165 166 cmd 167 : USER SP username CRLF 168 { 169 user($3); 170 free($3); 171 } 172 | PASS SP password CRLF 173 { 174 pass($3); 175 free($3); 176 } 177 | PASS CRLF 178 { 179 pass(""); 180 } 181 | PORT check_login SP host_port CRLF 182 { 183 if (epsvall) { 184 reply(501, "no PORT allowed after EPSV ALL"); 185 goto port_done; 186 } 187 if (!$2) 188 goto port_done; 189 if (port_check("PORT") == 1) 190 goto port_done; 191 #ifdef INET6 192 if ((his_addr.su_family != AF_INET6 || 193 !IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) { 194 /* shoud never happen */ 195 usedefault = 1; 196 reply(500, "Invalid address rejected."); 197 goto port_done; 198 } 199 port_check_v6("pcmd"); 200 #endif 201 port_done: 202 } 203 | LPRT check_login SP host_long_port CRLF 204 { 205 if (epsvall) { 206 reply(501, "no LPRT allowed after EPSV ALL"); 207 goto lprt_done; 208 } 209 if (!$2) 210 goto lprt_done; 211 if (port_check("LPRT") == 1) 212 goto lprt_done; 213 #ifdef INET6 214 if (his_addr.su_family != AF_INET6) { 215 usedefault = 1; 216 reply(500, "Invalid address rejected."); 217 goto lprt_done; 218 } 219 if (port_check_v6("LPRT") == 1) 220 goto lprt_done; 221 #endif 222 lprt_done: 223 } 224 | EPRT check_login SP STRING CRLF 225 { 226 char delim; 227 char *tmp = NULL; 228 char *p, *q; 229 char *result[3]; 230 struct addrinfo hints; 231 struct addrinfo *res; 232 int i; 233 234 if (epsvall) { 235 reply(501, "no EPRT allowed after EPSV ALL"); 236 goto eprt_done; 237 } 238 if (!$2) 239 goto eprt_done; 240 241 memset(&data_dest, 0, sizeof(data_dest)); 242 tmp = strdup($4); 243 if (ftpdebug) 244 syslog(LOG_DEBUG, "%s", tmp); 245 if (!tmp) { 246 fatalerror("not enough core"); 247 /*NOTREACHED*/ 248 } 249 p = tmp; 250 delim = p[0]; 251 p++; 252 memset(result, 0, sizeof(result)); 253 for (i = 0; i < 3; i++) { 254 q = strchr(p, delim); 255 if (!q || *q != delim) { 256 parsefail: 257 reply(500, 258 "Invalid argument, rejected."); 259 if (tmp) 260 free(tmp); 261 usedefault = 1; 262 goto eprt_done; 263 } 264 *q++ = '\0'; 265 result[i] = p; 266 if (ftpdebug) 267 syslog(LOG_DEBUG, "%d: %s", i, p); 268 p = q; 269 } 270 271 /* some more sanity check */ 272 p = result[0]; 273 while (*p) { 274 if (!isdigit(*p)) 275 goto parsefail; 276 p++; 277 } 278 p = result[2]; 279 while (*p) { 280 if (!isdigit(*p)) 281 goto parsefail; 282 p++; 283 } 284 285 /* grab address */ 286 memset(&hints, 0, sizeof(hints)); 287 if (atoi(result[0]) == 1) 288 hints.ai_family = PF_INET; 289 #ifdef INET6 290 else if (atoi(result[0]) == 2) 291 hints.ai_family = PF_INET6; 292 #endif 293 else 294 hints.ai_family = PF_UNSPEC; /*XXX*/ 295 hints.ai_socktype = SOCK_STREAM; 296 i = getaddrinfo(result[1], result[2], &hints, &res); 297 if (i) 298 goto parsefail; 299 memcpy(&data_dest, res->ai_addr, res->ai_addrlen); 300 #ifdef INET6 301 if (his_addr.su_family == AF_INET6 302 && data_dest.su_family == AF_INET6) { 303 /* XXX more sanity checks! */ 304 data_dest.su_sin6.sin6_scope_id = 305 his_addr.su_sin6.sin6_scope_id; 306 } 307 #endif 308 free(tmp); 309 tmp = NULL; 310 311 if (port_check("EPRT") == 1) 312 goto eprt_done; 313 #ifdef INET6 314 if (his_addr.su_family != AF_INET6) { 315 usedefault = 1; 316 reply(500, "Invalid address rejected."); 317 goto eprt_done; 318 } 319 if (port_check_v6("EPRT") == 1) 320 goto eprt_done; 321 #endif 322 eprt_done: 323 free($4); 324 } 325 | PASV check_login CRLF 326 { 327 if (epsvall) 328 reply(501, "no PASV allowed after EPSV ALL"); 329 else if ($2) 330 passive(); 331 } 332 | LPSV check_login CRLF 333 { 334 if (epsvall) 335 reply(501, "no LPSV allowed after EPSV ALL"); 336 else if ($2) 337 long_passive("LPSV", PF_UNSPEC); 338 } 339 | EPSV check_login_epsv SP NUMBER CRLF 340 { 341 if ($2) { 342 int pf; 343 switch ($4.i) { 344 case 1: 345 pf = PF_INET; 346 break; 347 #ifdef INET6 348 case 2: 349 pf = PF_INET6; 350 break; 351 #endif 352 default: 353 pf = -1; /*junk value*/ 354 break; 355 } 356 long_passive("EPSV", pf); 357 } 358 } 359 | EPSV check_login_epsv SP ALL CRLF 360 { 361 if ($2) { 362 reply(200, 363 "EPSV ALL command successful."); 364 epsvall++; 365 } 366 } 367 | EPSV check_login_epsv CRLF 368 { 369 if ($2) 370 long_passive("EPSV", PF_UNSPEC); 371 } 372 | TYPE check_login SP type_code CRLF 373 { 374 if ($2) { 375 switch (cmd_type) { 376 377 case TYPE_A: 378 if (cmd_form == FORM_N) { 379 reply(200, "Type set to A."); 380 type = cmd_type; 381 form = cmd_form; 382 } else 383 reply(504, "Form must be N."); 384 break; 385 386 case TYPE_E: 387 reply(504, "Type E not implemented."); 388 break; 389 390 case TYPE_I: 391 reply(200, "Type set to I."); 392 type = cmd_type; 393 break; 394 395 case TYPE_L: 396 #if NBBY == 8 397 if (cmd_bytesz == 8) { 398 reply(200, 399 "Type set to L (byte size 8)."); 400 type = cmd_type; 401 } else 402 reply(504, "Byte size must be 8."); 403 #else /* NBBY == 8 */ 404 UNIMPLEMENTED for NBBY != 8 405 #endif /* NBBY == 8 */ 406 } 407 } 408 } 409 | STRU check_login SP struct_code CRLF 410 { 411 if ($2) { 412 switch ($4) { 413 414 case STRU_F: 415 reply(200, "STRU F ok."); 416 break; 417 418 default: 419 reply(504, "Unimplemented STRU type."); 420 } 421 } 422 } 423 | MODE check_login SP mode_code CRLF 424 { 425 if ($2) { 426 switch ($4) { 427 428 case MODE_S: 429 reply(200, "MODE S ok."); 430 break; 431 432 default: 433 reply(502, "Unimplemented MODE type."); 434 } 435 } 436 } 437 | ALLO check_login SP NUMBER CRLF 438 { 439 if ($2) { 440 reply(202, "ALLO command ignored."); 441 } 442 } 443 | ALLO check_login SP NUMBER SP R SP NUMBER CRLF 444 { 445 if ($2) { 446 reply(202, "ALLO command ignored."); 447 } 448 } 449 | RETR check_login SP pathname CRLF 450 { 451 if (noretr || (guest && noguestretr)) 452 reply(500, "RETR command is disabled"); 453 else if ($2 && $4 != NULL) 454 retrieve((char *) 0, $4); 455 456 if ($4 != NULL) 457 free($4); 458 } 459 | STOR check_login_ro SP pathname CRLF 460 { 461 if ($2 && $4 != NULL) 462 store($4, "w", 0); 463 if ($4 != NULL) 464 free($4); 465 } 466 | APPE check_login_ro SP pathname CRLF 467 { 468 if ($2 && $4 != NULL) 469 store($4, "a", 0); 470 if ($4 != NULL) 471 free($4); 472 } 473 | NLST check_login CRLF 474 { 475 if ($2) 476 send_file_list("."); 477 } 478 | NLST check_login SP pathstring CRLF 479 { 480 if ($2) 481 send_file_list($4); 482 free($4); 483 } 484 | LIST check_login CRLF 485 { 486 if ($2) 487 retrieve("/bin/ls -lgA", ""); 488 } 489 | LIST check_login SP pathstring CRLF 490 { 491 if ($2) 492 retrieve("/bin/ls -lgA %s", $4); 493 free($4); 494 } 495 | STAT check_login SP pathname CRLF 496 { 497 if ($2 && $4 != NULL) 498 statfilecmd($4); 499 if ($4 != NULL) 500 free($4); 501 } 502 | STAT check_login CRLF 503 { 504 if ($2) { 505 statcmd(); 506 } 507 } 508 | DELE check_login_ro SP pathname CRLF 509 { 510 if ($2 && $4 != NULL) 511 delete($4); 512 if ($4 != NULL) 513 free($4); 514 } 515 | RNTO check_login_ro SP pathname CRLF 516 { 517 if ($2 && $4 != NULL) { 518 if (fromname) { 519 renamecmd(fromname, $4); 520 free(fromname); 521 fromname = (char *) 0; 522 } else { 523 reply(503, "Bad sequence of commands."); 524 } 525 } 526 if ($4 != NULL) 527 free($4); 528 } 529 | ABOR check_login CRLF 530 { 531 if ($2) 532 reply(225, "ABOR command successful."); 533 } 534 | CWD check_login CRLF 535 { 536 if ($2) { 537 if (guest) 538 cwd("/"); 539 else 540 cwd(pw->pw_dir); 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 #ifdef unix 693 #ifdef BSD 694 reply(215, "UNIX Type: L%d Version: BSD-%d", 695 NBBY, BSD); 696 #else /* BSD */ 697 reply(215, "UNIX Type: L%d", NBBY); 698 #endif /* BSD */ 699 #else /* unix */ 700 reply(215, "UNKNOWN Type: L%d", NBBY); 701 #endif /* unix */ 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 | error 756 { 757 yyclearin; /* discard lookahead data */ 758 yyerrok; /* clear error condition */ 759 state = 0; /* reset lexer state */ 760 } 761 ; 762 rcmd 763 : RNFR check_login_ro SP pathname CRLF 764 { 765 restart_point = (off_t) 0; 766 if ($2 && $4) { 767 if (fromname) 768 free(fromname); 769 fromname = (char *) 0; 770 if (renamefrom($4)) 771 fromname = $4; 772 else 773 free($4); 774 } else if ($4) { 775 free($4); 776 } 777 } 778 | REST check_login SP NUMBER CRLF 779 { 780 if ($2) { 781 if (fromname) 782 free(fromname); 783 fromname = (char *) 0; 784 restart_point = $4.o; 785 reply(350, "Restarting at %llu. %s", 786 restart_point, 787 "Send STORE or RETRIEVE to initiate transfer."); 788 } 789 } 790 ; 791 792 username 793 : STRING 794 ; 795 796 password 797 : /* empty */ 798 { 799 $$ = (char *)calloc(1, sizeof(char)); 800 } 801 | STRING 802 ; 803 804 byte_size 805 : NUMBER 806 { 807 $$ = $1.i; 808 } 809 ; 810 811 host_port 812 : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 813 NUMBER COMMA NUMBER 814 { 815 char *a, *p; 816 817 data_dest.su_len = sizeof(struct sockaddr_in); 818 data_dest.su_family = AF_INET; 819 p = (char *)&data_dest.su_sin.sin_port; 820 p[0] = $9.i; p[1] = $11.i; 821 a = (char *)&data_dest.su_sin.sin_addr; 822 a[0] = $1.i; a[1] = $3.i; a[2] = $5.i; a[3] = $7.i; 823 } 824 ; 825 826 host_long_port 827 : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 828 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 829 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 830 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 831 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 832 NUMBER 833 { 834 char *a, *p; 835 836 memset(&data_dest, 0, sizeof(data_dest)); 837 data_dest.su_len = sizeof(struct sockaddr_in6); 838 data_dest.su_family = AF_INET6; 839 p = (char *)&data_dest.su_port; 840 p[0] = $39.i; p[1] = $41.i; 841 a = (char *)&data_dest.su_sin6.sin6_addr; 842 a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 843 a[4] = $13.i; a[5] = $15.i; a[6] = $17.i; a[7] = $19.i; 844 a[8] = $21.i; a[9] = $23.i; a[10] = $25.i; a[11] = $27.i; 845 a[12] = $29.i; a[13] = $31.i; a[14] = $33.i; a[15] = $35.i; 846 if (his_addr.su_family == AF_INET6) { 847 /* XXX more sanity checks! */ 848 data_dest.su_sin6.sin6_scope_id = 849 his_addr.su_sin6.sin6_scope_id; 850 } 851 if ($1.i != 6 || $3.i != 16 || $37.i != 2) 852 memset(&data_dest, 0, sizeof(data_dest)); 853 } 854 | NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 855 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 856 NUMBER 857 { 858 char *a, *p; 859 860 memset(&data_dest, 0, sizeof(data_dest)); 861 data_dest.su_sin.sin_len = sizeof(struct sockaddr_in); 862 data_dest.su_family = AF_INET; 863 p = (char *)&data_dest.su_port; 864 p[0] = $15.i; p[1] = $17.i; 865 a = (char *)&data_dest.su_sin.sin_addr; 866 a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 867 if ($1.i != 4 || $3.i != 4 || $13.i != 2) 868 memset(&data_dest, 0, sizeof(data_dest)); 869 } 870 ; 871 872 form_code 873 : N 874 { 875 $$ = FORM_N; 876 } 877 | T 878 { 879 $$ = FORM_T; 880 } 881 | C 882 { 883 $$ = FORM_C; 884 } 885 ; 886 887 type_code 888 : A 889 { 890 cmd_type = TYPE_A; 891 cmd_form = FORM_N; 892 } 893 | A SP form_code 894 { 895 cmd_type = TYPE_A; 896 cmd_form = $3; 897 } 898 | E 899 { 900 cmd_type = TYPE_E; 901 cmd_form = FORM_N; 902 } 903 | E SP form_code 904 { 905 cmd_type = TYPE_E; 906 cmd_form = $3; 907 } 908 | I 909 { 910 cmd_type = TYPE_I; 911 } 912 | L 913 { 914 cmd_type = TYPE_L; 915 cmd_bytesz = NBBY; 916 } 917 | L SP byte_size 918 { 919 cmd_type = TYPE_L; 920 cmd_bytesz = $3; 921 } 922 /* this is for a bug in the BBN ftp */ 923 | L byte_size 924 { 925 cmd_type = TYPE_L; 926 cmd_bytesz = $2; 927 } 928 ; 929 930 struct_code 931 : F 932 { 933 $$ = STRU_F; 934 } 935 | R 936 { 937 $$ = STRU_R; 938 } 939 | P 940 { 941 $$ = STRU_P; 942 } 943 ; 944 945 mode_code 946 : S 947 { 948 $$ = MODE_S; 949 } 950 | B 951 { 952 $$ = MODE_B; 953 } 954 | C 955 { 956 $$ = MODE_C; 957 } 958 ; 959 960 pathname 961 : pathstring 962 { 963 /* 964 * Problem: this production is used for all pathname 965 * processing, but only gives a 550 error reply. 966 * This is a valid reply in some cases but not in others. 967 */ 968 if (logged_in && $1) { 969 glob_t gl; 970 int flags = 971 GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 972 973 memset(&gl, 0, sizeof(gl)); 974 flags |= GLOB_MAXPATH; 975 gl.gl_matchc = MAXGLOBARGS; 976 if (glob($1, flags, NULL, &gl) || 977 gl.gl_pathc == 0) { 978 reply(550, "wildcard expansion error"); 979 $$ = NULL; 980 } else if (gl.gl_pathc > 1) { 981 reply(550, "ambiguous"); 982 $$ = NULL; 983 } else { 984 $$ = strdup(gl.gl_pathv[0]); 985 } 986 globfree(&gl); 987 free($1); 988 } else 989 $$ = $1; 990 } 991 ; 992 993 pathstring 994 : STRING 995 ; 996 997 octal_number 998 : NUMBER 999 { 1000 int ret, dec, multby, digit; 1001 1002 /* 1003 * Convert a number that was read as decimal number 1004 * to what it would be if it had been read as octal. 1005 */ 1006 dec = $1.i; 1007 multby = 1; 1008 ret = 0; 1009 while (dec) { 1010 digit = dec%10; 1011 if (digit > 7) { 1012 ret = -1; 1013 break; 1014 } 1015 ret += digit * multby; 1016 multby *= 8; 1017 dec /= 10; 1018 } 1019 $$ = ret; 1020 } 1021 ; 1022 1023 1024 check_login 1025 : /* empty */ 1026 { 1027 $$ = check_login1(); 1028 } 1029 ; 1030 1031 check_login_epsv 1032 : /* empty */ 1033 { 1034 if (noepsv) { 1035 reply(500, "EPSV command disabled"); 1036 $$ = 0; 1037 } 1038 else 1039 $$ = check_login1(); 1040 } 1041 ; 1042 1043 check_login_ro 1044 : /* empty */ 1045 { 1046 if (readonly) { 1047 reply(550, "Permission denied."); 1048 $$ = 0; 1049 } 1050 else 1051 $$ = check_login1(); 1052 } 1053 ; 1054 1055 %% 1056 1057 #define CMD 0 /* beginning of command */ 1058 #define ARGS 1 /* expect miscellaneous arguments */ 1059 #define STR1 2 /* expect SP followed by STRING */ 1060 #define STR2 3 /* expect STRING */ 1061 #define OSTR 4 /* optional SP then STRING */ 1062 #define ZSTR1 5 /* optional SP then optional STRING */ 1063 #define ZSTR2 6 /* optional STRING after SP */ 1064 #define SITECMD 7 /* SITE command */ 1065 #define NSTR 8 /* Number followed by a string */ 1066 1067 #define MAXGLOBARGS 1000 1068 1069 #define MAXASIZE 10240 /* Deny ASCII SIZE on files larger than that */ 1070 1071 struct tab { 1072 char *name; 1073 short token; 1074 short state; 1075 short implemented; /* 1 if command is implemented */ 1076 char *help; 1077 }; 1078 1079 struct tab cmdtab[] = { /* In order defined in RFC 765 */ 1080 { "USER", USER, STR1, 1, "<sp> username" }, 1081 { "PASS", PASS, ZSTR1, 1, "[<sp> [password]]" }, 1082 { "ACCT", ACCT, STR1, 0, "(specify account)" }, 1083 { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, 1084 { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, 1085 { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, 1086 { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4, b5" }, 1087 { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." }, 1088 { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" }, 1089 { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, 1090 { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, 1091 { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" }, 1092 { "TYPE", TYPE, ARGS, 1, "<sp> { A | E | I | L }" }, 1093 { "STRU", STRU, ARGS, 1, "(specify file structure)" }, 1094 { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, 1095 { "RETR", RETR, STR1, 1, "<sp> file-name" }, 1096 { "STOR", STOR, STR1, 1, "<sp> file-name" }, 1097 { "APPE", APPE, STR1, 1, "<sp> file-name" }, 1098 { "MLFL", MLFL, OSTR, 0, "(mail file)" }, 1099 { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, 1100 { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, 1101 { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, 1102 { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, 1103 { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, 1104 { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, 1105 { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, 1106 { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, 1107 { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, 1108 { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, 1109 { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, 1110 { "DELE", DELE, STR1, 1, "<sp> file-name" }, 1111 { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1112 { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1113 { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, 1114 { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, 1115 { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, 1116 { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, 1117 { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, 1118 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1119 { "NOOP", NOOP, ARGS, 1, "" }, 1120 { "MKD", MKD, STR1, 1, "<sp> path-name" }, 1121 { "XMKD", MKD, STR1, 1, "<sp> path-name" }, 1122 { "RMD", RMD, STR1, 1, "<sp> path-name" }, 1123 { "XRMD", RMD, STR1, 1, "<sp> path-name" }, 1124 { "PWD", PWD, ARGS, 1, "(return current directory)" }, 1125 { "XPWD", PWD, ARGS, 1, "(return current directory)" }, 1126 { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1127 { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1128 { "STOU", STOU, STR1, 1, "<sp> file-name" }, 1129 { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, 1130 { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, 1131 { NULL, 0, 0, 0, 0 } 1132 }; 1133 1134 struct tab sitetab[] = { 1135 { "MD5", MDFIVE, STR1, 1, "[ <sp> file-name ]" }, 1136 { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, 1137 { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, 1138 { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, 1139 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1140 { NULL, 0, 0, 0, 0 } 1141 }; 1142 1143 static char *copy(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 1175 cs = s; 1176 /* tmpline may contain saved command from urgent mode interruption */ 1177 for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 1178 *cs++ = tmpline[c]; 1179 if (tmpline[c] == '\n') { 1180 *cs++ = '\0'; 1181 if (ftpdebug) 1182 syslog(LOG_DEBUG, "command: %s", s); 1183 tmpline[0] = '\0'; 1184 return(s); 1185 } 1186 if (c == 0) 1187 tmpline[0] = '\0'; 1188 } 1189 while ((c = getc(iop)) != EOF) { 1190 c &= 0377; 1191 if (c == IAC) { 1192 if ((c = getc(iop)) != EOF) { 1193 c &= 0377; 1194 switch (c) { 1195 case WILL: 1196 case WONT: 1197 c = getc(iop); 1198 printf("%c%c%c", IAC, DONT, 0377&c); 1199 (void) fflush(stdout); 1200 continue; 1201 case DO: 1202 case DONT: 1203 c = getc(iop); 1204 printf("%c%c%c", IAC, WONT, 0377&c); 1205 (void) fflush(stdout); 1206 continue; 1207 case IAC: 1208 break; 1209 default: 1210 continue; /* ignore command */ 1211 } 1212 } 1213 } 1214 *cs++ = c; 1215 if (--n <= 0 || c == '\n') 1216 break; 1217 } 1218 if (c == EOF && cs == s) 1219 return (NULL); 1220 *cs++ = '\0'; 1221 if (ftpdebug) { 1222 if (!guest && strncasecmp("pass ", s, 5) == 0) { 1223 /* Don't syslog passwords */ 1224 syslog(LOG_DEBUG, "command: %.5s ???", s); 1225 } else { 1226 register char *cp; 1227 register int len; 1228 1229 /* Don't syslog trailing CR-LF */ 1230 len = strlen(s); 1231 cp = s + len - 1; 1232 while (cp >= s && (*cp == '\n' || *cp == '\r')) { 1233 --cp; 1234 --len; 1235 } 1236 syslog(LOG_DEBUG, "command: %.*s", len, s); 1237 } 1238 } 1239 return (s); 1240 } 1241 1242 static void 1243 toolong(int signo) 1244 { 1245 1246 reply(421, 1247 "Timeout (%d seconds): closing control connection.", timeout); 1248 if (logging) 1249 syslog(LOG_INFO, "User %s timed out after %d seconds", 1250 (pw ? pw -> pw_name : "unknown"), timeout); 1251 dologout(1); 1252 } 1253 1254 static int 1255 yylex(void) 1256 { 1257 static int cpos; 1258 char *cp, *cp2; 1259 struct tab *p; 1260 int n; 1261 char c; 1262 1263 for (;;) { 1264 switch (state) { 1265 1266 case CMD: 1267 (void) signal(SIGALRM, toolong); 1268 (void) alarm((unsigned) timeout); 1269 if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { 1270 reply(221, "You could at least say goodbye."); 1271 dologout(0); 1272 } 1273 (void) alarm(0); 1274 #ifdef SETPROCTITLE 1275 if (strncasecmp(cbuf, "PASS", 4) != 0) 1276 setproctitle("%s: %s", proctitle, cbuf); 1277 #endif /* SETPROCTITLE */ 1278 if ((cp = strchr(cbuf, '\r'))) { 1279 *cp++ = '\n'; 1280 *cp = '\0'; 1281 } 1282 if ((cp = strpbrk(cbuf, " \n"))) 1283 cpos = cp - cbuf; 1284 if (cpos == 0) 1285 cpos = 4; 1286 c = cbuf[cpos]; 1287 cbuf[cpos] = '\0'; 1288 upper(cbuf); 1289 p = lookup(cmdtab, cbuf); 1290 cbuf[cpos] = c; 1291 if (p != 0) { 1292 if (p->implemented == 0) { 1293 nack(p->name); 1294 return (LEXERR); 1295 } 1296 state = p->state; 1297 yylval.s = p->name; 1298 return (p->token); 1299 } 1300 break; 1301 1302 case SITECMD: 1303 if (cbuf[cpos] == ' ') { 1304 cpos++; 1305 return (SP); 1306 } 1307 cp = &cbuf[cpos]; 1308 if ((cp2 = strpbrk(cp, " \n"))) 1309 cpos = cp2 - cbuf; 1310 c = cbuf[cpos]; 1311 cbuf[cpos] = '\0'; 1312 upper(cp); 1313 p = lookup(sitetab, cp); 1314 cbuf[cpos] = c; 1315 if (guest == 0 && p != 0) { 1316 if (p->implemented == 0) { 1317 state = CMD; 1318 nack(p->name); 1319 return (LEXERR); 1320 } 1321 state = p->state; 1322 yylval.s = p->name; 1323 return (p->token); 1324 } 1325 state = CMD; 1326 break; 1327 1328 case ZSTR1: 1329 case OSTR: 1330 if (cbuf[cpos] == '\n') { 1331 state = CMD; 1332 return (CRLF); 1333 } 1334 /* FALLTHROUGH */ 1335 1336 case STR1: 1337 dostr1: 1338 if (cbuf[cpos] == ' ') { 1339 cpos++; 1340 state = state == OSTR ? STR2 : state+1; 1341 return (SP); 1342 } 1343 break; 1344 1345 case ZSTR2: 1346 if (cbuf[cpos] == '\n') { 1347 state = CMD; 1348 return (CRLF); 1349 } 1350 /* FALLTHROUGH */ 1351 1352 case STR2: 1353 cp = &cbuf[cpos]; 1354 n = strlen(cp); 1355 cpos += n - 1; 1356 /* 1357 * Make sure the string is nonempty and \n terminated. 1358 */ 1359 if (n > 1 && cbuf[cpos] == '\n') { 1360 cbuf[cpos] = '\0'; 1361 yylval.s = copy(cp); 1362 cbuf[cpos] = '\n'; 1363 state = ARGS; 1364 return (STRING); 1365 } 1366 break; 1367 1368 case NSTR: 1369 if (cbuf[cpos] == ' ') { 1370 cpos++; 1371 return (SP); 1372 } 1373 if (isdigit(cbuf[cpos])) { 1374 cp = &cbuf[cpos]; 1375 while (isdigit(cbuf[++cpos])) 1376 ; 1377 c = cbuf[cpos]; 1378 cbuf[cpos] = '\0'; 1379 yylval.u.i = atoi(cp); 1380 cbuf[cpos] = c; 1381 state = STR1; 1382 return (NUMBER); 1383 } 1384 state = STR1; 1385 goto dostr1; 1386 1387 case ARGS: 1388 if (isdigit(cbuf[cpos])) { 1389 cp = &cbuf[cpos]; 1390 while (isdigit(cbuf[++cpos])) 1391 ; 1392 c = cbuf[cpos]; 1393 cbuf[cpos] = '\0'; 1394 yylval.u.i = atoi(cp); 1395 yylval.u.o = strtoull(cp, (char **)NULL, 10); 1396 cbuf[cpos] = c; 1397 return (NUMBER); 1398 } 1399 if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0 1400 && !isalnum(cbuf[cpos + 3])) { 1401 cpos += 3; 1402 return ALL; 1403 } 1404 switch (cbuf[cpos++]) { 1405 1406 case '\n': 1407 state = CMD; 1408 return (CRLF); 1409 1410 case ' ': 1411 return (SP); 1412 1413 case ',': 1414 return (COMMA); 1415 1416 case 'A': 1417 case 'a': 1418 return (A); 1419 1420 case 'B': 1421 case 'b': 1422 return (B); 1423 1424 case 'C': 1425 case 'c': 1426 return (C); 1427 1428 case 'E': 1429 case 'e': 1430 return (E); 1431 1432 case 'F': 1433 case 'f': 1434 return (F); 1435 1436 case 'I': 1437 case 'i': 1438 return (I); 1439 1440 case 'L': 1441 case 'l': 1442 return (L); 1443 1444 case 'N': 1445 case 'n': 1446 return (N); 1447 1448 case 'P': 1449 case 'p': 1450 return (P); 1451 1452 case 'R': 1453 case 'r': 1454 return (R); 1455 1456 case 'S': 1457 case 's': 1458 return (S); 1459 1460 case 'T': 1461 case 't': 1462 return (T); 1463 1464 } 1465 break; 1466 1467 default: 1468 fatalerror("Unknown state in scanner."); 1469 } 1470 state = CMD; 1471 return (LEXERR); 1472 } 1473 } 1474 1475 void 1476 upper(char *s) 1477 { 1478 while (*s != '\0') { 1479 if (islower(*s)) 1480 *s = toupper(*s); 1481 s++; 1482 } 1483 } 1484 1485 static char * 1486 copy(char *s) 1487 { 1488 char *p; 1489 1490 p = malloc((unsigned) strlen(s) + 1); 1491 if (p == NULL) 1492 fatalerror("Ran out of memory."); 1493 (void) strcpy(p, s); 1494 return (p); 1495 } 1496 1497 static void 1498 help(struct tab *ctab, char *s) 1499 { 1500 struct tab *c; 1501 int width, NCMDS; 1502 char *type; 1503 1504 if (ctab == sitetab) 1505 type = "SITE "; 1506 else 1507 type = ""; 1508 width = 0, NCMDS = 0; 1509 for (c = ctab; c->name != NULL; c++) { 1510 int len = strlen(c->name); 1511 1512 if (len > width) 1513 width = len; 1514 NCMDS++; 1515 } 1516 width = (width + 8) &~ 7; 1517 if (s == 0) { 1518 int i, j, w; 1519 int columns, lines; 1520 1521 lreply(214, "The following %scommands are recognized %s.", 1522 type, "(* =>'s unimplemented)"); 1523 columns = 76 / width; 1524 if (columns == 0) 1525 columns = 1; 1526 lines = (NCMDS + columns - 1) / columns; 1527 for (i = 0; i < lines; i++) { 1528 printf(" "); 1529 for (j = 0; j < columns; j++) { 1530 c = ctab + j * lines + i; 1531 printf("%s%c", c->name, 1532 c->implemented ? ' ' : '*'); 1533 if (c + lines >= &ctab[NCMDS]) 1534 break; 1535 w = strlen(c->name) + 1; 1536 while (w < width) { 1537 putchar(' '); 1538 w++; 1539 } 1540 } 1541 printf("\r\n"); 1542 } 1543 (void) fflush(stdout); 1544 reply(214, "Direct comments to ftp-bugs@%s.", hostname); 1545 return; 1546 } 1547 upper(s); 1548 c = lookup(ctab, s); 1549 if (c == (struct tab *)0) { 1550 reply(502, "Unknown command %s.", s); 1551 return; 1552 } 1553 if (c->implemented) 1554 reply(214, "Syntax: %s%s %s", type, c->name, c->help); 1555 else 1556 reply(214, "%s%-*s\t%s; unimplemented.", type, width, 1557 c->name, c->help); 1558 } 1559 1560 static void 1561 sizecmd(char *filename) 1562 { 1563 switch (type) { 1564 case TYPE_L: 1565 case TYPE_I: { 1566 struct stat stbuf; 1567 if (stat(filename, &stbuf) < 0) 1568 perror_reply(550, filename); 1569 else if (!S_ISREG(stbuf.st_mode)) 1570 reply(550, "%s: not a plain file.", filename); 1571 else 1572 reply(213, "%qu", stbuf.st_size); 1573 break; } 1574 case TYPE_A: { 1575 FILE *fin; 1576 int c; 1577 off_t count; 1578 struct stat stbuf; 1579 fin = fopen(filename, "r"); 1580 if (fin == NULL) { 1581 perror_reply(550, filename); 1582 return; 1583 } 1584 if (fstat(fileno(fin), &stbuf) < 0) { 1585 perror_reply(550, filename); 1586 (void) fclose(fin); 1587 return; 1588 } else if (!S_ISREG(stbuf.st_mode)) { 1589 reply(550, "%s: not a plain file.", filename); 1590 (void) fclose(fin); 1591 return; 1592 } else if (stbuf.st_size > MAXASIZE) { 1593 reply(550, "%s: too large for type A SIZE.", filename); 1594 (void) fclose(fin); 1595 return; 1596 } 1597 1598 count = 0; 1599 while((c=getc(fin)) != EOF) { 1600 if (c == '\n') /* will get expanded to \r\n */ 1601 count++; 1602 count++; 1603 } 1604 (void) fclose(fin); 1605 1606 reply(213, "%qd", count); 1607 break; } 1608 default: 1609 reply(504, "SIZE not implemented for type %s.", 1610 typenames[type]); 1611 } 1612 } 1613 1614 /* Return 1, if port check is done. Return 0, if not yet. */ 1615 static int 1616 port_check(const char *pcmd) 1617 { 1618 if (his_addr.su_family == AF_INET) { 1619 if (data_dest.su_family != AF_INET) { 1620 usedefault = 1; 1621 reply(500, "Invalid address rejected."); 1622 return 1; 1623 } 1624 if (paranoid && 1625 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1626 memcmp(&data_dest.su_sin.sin_addr, 1627 &his_addr.su_sin.sin_addr, 1628 sizeof(data_dest.su_sin.sin_addr)))) { 1629 usedefault = 1; 1630 reply(500, "Illegal PORT range rejected."); 1631 } else { 1632 usedefault = 0; 1633 if (pdata >= 0) { 1634 (void) close(pdata); 1635 pdata = -1; 1636 } 1637 reply(200, "%s command successful.", pcmd); 1638 } 1639 return 1; 1640 } 1641 return 0; 1642 } 1643 1644 static int 1645 check_login1(void) 1646 { 1647 if (logged_in) 1648 return 1; 1649 else { 1650 reply(530, "Please login with USER and PASS."); 1651 return 0; 1652 } 1653 } 1654 1655 #ifdef INET6 1656 /* Return 1, if port check is done. Return 0, if not yet. */ 1657 static int 1658 port_check_v6(const char *pcmd) 1659 { 1660 if (his_addr.su_family == AF_INET6) { 1661 if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) 1662 /* Convert data_dest into v4 mapped sockaddr.*/ 1663 v4map_data_dest(); 1664 if (data_dest.su_family != AF_INET6) { 1665 usedefault = 1; 1666 reply(500, "Invalid address rejected."); 1667 return 1; 1668 } 1669 if (paranoid && 1670 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1671 memcmp(&data_dest.su_sin6.sin6_addr, 1672 &his_addr.su_sin6.sin6_addr, 1673 sizeof(data_dest.su_sin6.sin6_addr)))) { 1674 usedefault = 1; 1675 reply(500, "Illegal PORT range rejected."); 1676 } else { 1677 usedefault = 0; 1678 if (pdata >= 0) { 1679 (void) close(pdata); 1680 pdata = -1; 1681 } 1682 reply(200, "%s command successful.", pcmd); 1683 } 1684 return 1; 1685 } 1686 return 0; 1687 } 1688 1689 static void 1690 v4map_data_dest(void) 1691 { 1692 struct in_addr savedaddr; 1693 int savedport; 1694 1695 if (data_dest.su_family != AF_INET) { 1696 usedefault = 1; 1697 reply(500, "Invalid address rejected."); 1698 return; 1699 } 1700 1701 savedaddr = data_dest.su_sin.sin_addr; 1702 savedport = data_dest.su_port; 1703 1704 memset(&data_dest, 0, sizeof(data_dest)); 1705 data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6); 1706 data_dest.su_sin6.sin6_family = AF_INET6; 1707 data_dest.su_sin6.sin6_port = savedport; 1708 memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2); 1709 memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12], 1710 (caddr_t)&savedaddr, sizeof(savedaddr)); 1711 } 1712 #endif 1713