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 STRING CRLF 479 { 480 if ($2 && $4 != NULL) 481 send_file_list($4); 482 if ($4 != NULL) 483 free($4); 484 } 485 | LIST check_login CRLF 486 { 487 if ($2) 488 retrieve("/bin/ls -lgA", ""); 489 } 490 | LIST check_login SP pathstring CRLF 491 { 492 if ($2 && $4 != NULL) 493 retrieve("/bin/ls -lgA %s", $4); 494 if ($4 != NULL) 495 free($4); 496 } 497 | STAT check_login SP pathname CRLF 498 { 499 if ($2 && $4 != NULL) 500 statfilecmd($4); 501 if ($4 != NULL) 502 free($4); 503 } 504 | STAT check_login CRLF 505 { 506 if ($2) { 507 statcmd(); 508 } 509 } 510 | DELE check_login_ro SP pathname CRLF 511 { 512 if ($2 && $4 != NULL) 513 delete($4); 514 if ($4 != NULL) 515 free($4); 516 } 517 | RNTO check_login_ro SP pathname CRLF 518 { 519 if ($2) { 520 if (fromname) { 521 renamecmd(fromname, $4); 522 free(fromname); 523 fromname = (char *) 0; 524 } else { 525 reply(503, "Bad sequence of commands."); 526 } 527 } 528 free($4); 529 } 530 | ABOR check_login CRLF 531 { 532 if ($2) 533 reply(225, "ABOR command successful."); 534 } 535 | CWD check_login CRLF 536 { 537 if ($2) { 538 if (guest) 539 cwd("/"); 540 else 541 cwd(pw->pw_dir); 542 } 543 } 544 | CWD check_login SP pathname CRLF 545 { 546 if ($2 && $4 != NULL) 547 cwd($4); 548 if ($4 != NULL) 549 free($4); 550 } 551 | HELP CRLF 552 { 553 help(cmdtab, (char *) 0); 554 } 555 | HELP SP STRING CRLF 556 { 557 char *cp = $3; 558 559 if (strncasecmp(cp, "SITE", 4) == 0) { 560 cp = $3 + 4; 561 if (*cp == ' ') 562 cp++; 563 if (*cp) 564 help(sitetab, cp); 565 else 566 help(sitetab, (char *) 0); 567 } else 568 help(cmdtab, $3); 569 free($3); 570 } 571 | NOOP CRLF 572 { 573 reply(200, "NOOP command successful."); 574 } 575 | MKD check_login_ro SP pathname CRLF 576 { 577 if ($2 && $4 != NULL) 578 makedir($4); 579 if ($4 != NULL) 580 free($4); 581 } 582 | RMD check_login_ro SP pathname CRLF 583 { 584 if ($2 && $4 != NULL) 585 removedir($4); 586 if ($4 != NULL) 587 free($4); 588 } 589 | PWD check_login CRLF 590 { 591 if ($2) 592 pwd(); 593 } 594 | CDUP check_login CRLF 595 { 596 if ($2) 597 cwd(".."); 598 } 599 | SITE SP HELP CRLF 600 { 601 help(sitetab, (char *) 0); 602 } 603 | SITE SP HELP SP STRING CRLF 604 { 605 help(sitetab, $5); 606 free($5); 607 } 608 | SITE SP MDFIVE check_login SP pathname CRLF 609 { 610 char p[64], *q; 611 612 if ($4) { 613 q = MD5File($6, p); 614 if (q != NULL) 615 reply(200, "MD5(%s) = %s", $6, p); 616 else 617 perror_reply(550, $6); 618 } 619 if ($6) 620 free($6); 621 } 622 | SITE SP UMASK check_login CRLF 623 { 624 int oldmask; 625 626 if ($4) { 627 oldmask = umask(0); 628 (void) umask(oldmask); 629 reply(200, "Current UMASK is %03o", oldmask); 630 } 631 } 632 | SITE SP UMASK check_login SP octal_number CRLF 633 { 634 int oldmask; 635 636 if ($4) { 637 if (($6 == -1) || ($6 > 0777)) { 638 reply(501, "Bad UMASK value"); 639 } else { 640 oldmask = umask($6); 641 reply(200, 642 "UMASK set to %03o (was %03o)", 643 $6, oldmask); 644 } 645 } 646 } 647 | SITE SP CHMOD check_login_ro SP octal_number SP pathname CRLF 648 { 649 if ($4 && ($8 != NULL)) { 650 if ($6 > 0777) 651 reply(501, 652 "CHMOD: Mode value must be between 0 and 0777"); 653 else if (chmod($8, $6) < 0) 654 perror_reply(550, $8); 655 else 656 reply(200, "CHMOD command successful."); 657 } 658 if ($8 != NULL) 659 free($8); 660 } 661 | SITE SP check_login IDLE CRLF 662 { 663 if ($3) 664 reply(200, 665 "Current IDLE time limit is %d seconds; max %d", 666 timeout, maxtimeout); 667 } 668 | SITE SP check_login IDLE SP NUMBER CRLF 669 { 670 if ($3) { 671 if ($6.i < 30 || $6.i > maxtimeout) { 672 reply(501, 673 "Maximum IDLE time must be between 30 and %d seconds", 674 maxtimeout); 675 } else { 676 timeout = $6.i; 677 (void) alarm((unsigned) timeout); 678 reply(200, 679 "Maximum IDLE time set to %d seconds", 680 timeout); 681 } 682 } 683 } 684 | STOU check_login_ro SP pathname CRLF 685 { 686 if ($2 && $4 != NULL) 687 store($4, "w", 1); 688 if ($4 != NULL) 689 free($4); 690 } 691 | SYST check_login CRLF 692 { 693 if ($2) 694 #ifdef unix 695 #ifdef BSD 696 reply(215, "UNIX Type: L%d Version: BSD-%d", 697 NBBY, BSD); 698 #else /* BSD */ 699 reply(215, "UNIX Type: L%d", NBBY); 700 #endif /* BSD */ 701 #else /* unix */ 702 reply(215, "UNKNOWN Type: L%d", NBBY); 703 #endif /* unix */ 704 } 705 706 /* 707 * SIZE is not in RFC959, but Postel has blessed it and 708 * it will be in the updated RFC. 709 * 710 * Return size of file in a format suitable for 711 * using with RESTART (we just count bytes). 712 */ 713 | SIZE check_login SP pathname CRLF 714 { 715 if ($2 && $4 != NULL) 716 sizecmd($4); 717 if ($4 != NULL) 718 free($4); 719 } 720 721 /* 722 * MDTM is not in RFC959, but Postel has blessed it and 723 * it will be in the updated RFC. 724 * 725 * Return modification time of file as an ISO 3307 726 * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx 727 * where xxx is the fractional second (of any precision, 728 * not necessarily 3 digits) 729 */ 730 | MDTM check_login SP pathname CRLF 731 { 732 if ($2 && $4 != NULL) { 733 struct stat stbuf; 734 if (stat($4, &stbuf) < 0) 735 reply(550, "%s: %s", 736 $4, strerror(errno)); 737 else if (!S_ISREG(stbuf.st_mode)) { 738 reply(550, "%s: not a plain file.", $4); 739 } else { 740 struct tm *t; 741 t = gmtime(&stbuf.st_mtime); 742 reply(213, 743 "%04d%02d%02d%02d%02d%02d", 744 1900 + t->tm_year, 745 t->tm_mon+1, t->tm_mday, 746 t->tm_hour, t->tm_min, t->tm_sec); 747 } 748 } 749 if ($4 != NULL) 750 free($4); 751 } 752 | QUIT CRLF 753 { 754 reply(221, "Goodbye."); 755 dologout(0); 756 } 757 | error 758 { 759 yyclearin; /* discard lookahead data */ 760 yyerrok; /* clear error condition */ 761 state = 0; /* reset lexer state */ 762 } 763 ; 764 rcmd 765 : RNFR check_login_ro SP pathname CRLF 766 { 767 restart_point = (off_t) 0; 768 if ($2 && $4) { 769 if (fromname) 770 free(fromname); 771 fromname = (char *) 0; 772 if (renamefrom($4)) 773 fromname = $4; 774 else 775 free($4); 776 } else if ($4) { 777 free($4); 778 } 779 } 780 | REST check_login SP NUMBER CRLF 781 { 782 if ($2) { 783 if (fromname) 784 free(fromname); 785 fromname = (char *) 0; 786 restart_point = $4.o; 787 reply(350, "Restarting at %llu. %s", 788 restart_point, 789 "Send STORE or RETRIEVE to initiate transfer."); 790 } 791 } 792 ; 793 794 username 795 : STRING 796 ; 797 798 password 799 : /* empty */ 800 { 801 $$ = (char *)calloc(1, sizeof(char)); 802 } 803 | STRING 804 ; 805 806 byte_size 807 : NUMBER 808 { 809 $$ = $1.i; 810 } 811 ; 812 813 host_port 814 : NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 815 NUMBER COMMA NUMBER 816 { 817 char *a, *p; 818 819 data_dest.su_len = sizeof(struct sockaddr_in); 820 data_dest.su_family = AF_INET; 821 p = (char *)&data_dest.su_sin.sin_port; 822 p[0] = $9.i; p[1] = $11.i; 823 a = (char *)&data_dest.su_sin.sin_addr; 824 a[0] = $1.i; a[1] = $3.i; a[2] = $5.i; a[3] = $7.i; 825 } 826 ; 827 828 host_long_port 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 COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 833 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 834 NUMBER 835 { 836 char *a, *p; 837 838 memset(&data_dest, 0, sizeof(data_dest)); 839 data_dest.su_len = sizeof(struct sockaddr_in6); 840 data_dest.su_family = AF_INET6; 841 p = (char *)&data_dest.su_port; 842 p[0] = $39.i; p[1] = $41.i; 843 a = (char *)&data_dest.su_sin6.sin6_addr; 844 a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 845 a[4] = $13.i; a[5] = $15.i; a[6] = $17.i; a[7] = $19.i; 846 a[8] = $21.i; a[9] = $23.i; a[10] = $25.i; a[11] = $27.i; 847 a[12] = $29.i; a[13] = $31.i; a[14] = $33.i; a[15] = $35.i; 848 if (his_addr.su_family == AF_INET6) { 849 /* XXX more sanity checks! */ 850 data_dest.su_sin6.sin6_scope_id = 851 his_addr.su_sin6.sin6_scope_id; 852 } 853 if ($1.i != 6 || $3.i != 16 || $37.i != 2) 854 memset(&data_dest, 0, sizeof(data_dest)); 855 } 856 | NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 857 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 858 NUMBER 859 { 860 char *a, *p; 861 862 memset(&data_dest, 0, sizeof(data_dest)); 863 data_dest.su_sin.sin_len = sizeof(struct sockaddr_in); 864 data_dest.su_family = AF_INET; 865 p = (char *)&data_dest.su_port; 866 p[0] = $15.i; p[1] = $17.i; 867 a = (char *)&data_dest.su_sin.sin_addr; 868 a[0] = $5.i; a[1] = $7.i; a[2] = $9.i; a[3] = $11.i; 869 if ($1.i != 4 || $3.i != 4 || $13.i != 2) 870 memset(&data_dest, 0, sizeof(data_dest)); 871 } 872 ; 873 874 form_code 875 : N 876 { 877 $$ = FORM_N; 878 } 879 | T 880 { 881 $$ = FORM_T; 882 } 883 | C 884 { 885 $$ = FORM_C; 886 } 887 ; 888 889 type_code 890 : A 891 { 892 cmd_type = TYPE_A; 893 cmd_form = FORM_N; 894 } 895 | A SP form_code 896 { 897 cmd_type = TYPE_A; 898 cmd_form = $3; 899 } 900 | E 901 { 902 cmd_type = TYPE_E; 903 cmd_form = FORM_N; 904 } 905 | E SP form_code 906 { 907 cmd_type = TYPE_E; 908 cmd_form = $3; 909 } 910 | I 911 { 912 cmd_type = TYPE_I; 913 } 914 | L 915 { 916 cmd_type = TYPE_L; 917 cmd_bytesz = NBBY; 918 } 919 | L SP byte_size 920 { 921 cmd_type = TYPE_L; 922 cmd_bytesz = $3; 923 } 924 /* this is for a bug in the BBN ftp */ 925 | L byte_size 926 { 927 cmd_type = TYPE_L; 928 cmd_bytesz = $2; 929 } 930 ; 931 932 struct_code 933 : F 934 { 935 $$ = STRU_F; 936 } 937 | R 938 { 939 $$ = STRU_R; 940 } 941 | P 942 { 943 $$ = STRU_P; 944 } 945 ; 946 947 mode_code 948 : S 949 { 950 $$ = MODE_S; 951 } 952 | B 953 { 954 $$ = MODE_B; 955 } 956 | C 957 { 958 $$ = MODE_C; 959 } 960 ; 961 962 pathname 963 : pathstring 964 { 965 /* 966 * Problem: this production is used for all pathname 967 * processing, but only gives a 550 error reply. 968 * This is a valid reply in some cases but not in others. 969 */ 970 if (logged_in && $1) { 971 glob_t gl; 972 int flags = 973 GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 974 975 memset(&gl, 0, sizeof(gl)); 976 flags |= GLOB_MAXPATH; 977 gl.gl_matchc = MAXGLOBARGS; 978 if (glob($1, flags, NULL, &gl) || 979 gl.gl_pathc == 0) { 980 reply(550, "not found"); 981 $$ = NULL; 982 } else if (gl.gl_pathc > 1) { 983 reply(550, "ambiguous"); 984 $$ = NULL; 985 } else { 986 $$ = strdup(gl.gl_pathv[0]); 987 } 988 globfree(&gl); 989 free($1); 990 } else 991 $$ = $1; 992 } 993 ; 994 995 pathstring 996 : STRING 997 ; 998 999 octal_number 1000 : NUMBER 1001 { 1002 int ret, dec, multby, digit; 1003 1004 /* 1005 * Convert a number that was read as decimal number 1006 * to what it would be if it had been read as octal. 1007 */ 1008 dec = $1.i; 1009 multby = 1; 1010 ret = 0; 1011 while (dec) { 1012 digit = dec%10; 1013 if (digit > 7) { 1014 ret = -1; 1015 break; 1016 } 1017 ret += digit * multby; 1018 multby *= 8; 1019 dec /= 10; 1020 } 1021 $$ = ret; 1022 } 1023 ; 1024 1025 1026 check_login 1027 : /* empty */ 1028 { 1029 $$ = check_login1(); 1030 } 1031 ; 1032 1033 check_login_epsv 1034 : /* empty */ 1035 { 1036 if (noepsv) { 1037 reply(500, "EPSV command disabled"); 1038 $$ = 0; 1039 } 1040 else 1041 $$ = check_login1(); 1042 } 1043 ; 1044 1045 check_login_ro 1046 : /* empty */ 1047 { 1048 if (readonly) { 1049 reply(550, "Permission denied."); 1050 $$ = 0; 1051 } 1052 else 1053 $$ = check_login1(); 1054 } 1055 ; 1056 1057 %% 1058 1059 #define CMD 0 /* beginning of command */ 1060 #define ARGS 1 /* expect miscellaneous arguments */ 1061 #define STR1 2 /* expect SP followed by STRING */ 1062 #define STR2 3 /* expect STRING */ 1063 #define OSTR 4 /* optional SP then STRING */ 1064 #define ZSTR1 5 /* optional SP then optional STRING */ 1065 #define ZSTR2 6 /* optional STRING after SP */ 1066 #define SITECMD 7 /* SITE command */ 1067 #define NSTR 8 /* Number followed by a string */ 1068 1069 #define MAXGLOBARGS 1000 1070 1071 #define MAXASIZE 10240 /* Deny ASCII SIZE on files larger than that */ 1072 1073 struct tab { 1074 char *name; 1075 short token; 1076 short state; 1077 short implemented; /* 1 if command is implemented */ 1078 char *help; 1079 }; 1080 1081 struct tab cmdtab[] = { /* In order defined in RFC 765 */ 1082 { "USER", USER, STR1, 1, "<sp> username" }, 1083 { "PASS", PASS, ZSTR1, 1, "[<sp> [password]]" }, 1084 { "ACCT", ACCT, STR1, 0, "(specify account)" }, 1085 { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, 1086 { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, 1087 { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, 1088 { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" }, 1089 { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." }, 1090 { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" }, 1091 { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, 1092 { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, 1093 { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" }, 1094 { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" }, 1095 { "STRU", STRU, ARGS, 1, "(specify file structure)" }, 1096 { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, 1097 { "RETR", RETR, STR1, 1, "<sp> file-name" }, 1098 { "STOR", STOR, STR1, 1, "<sp> file-name" }, 1099 { "APPE", APPE, STR1, 1, "<sp> file-name" }, 1100 { "MLFL", MLFL, OSTR, 0, "(mail file)" }, 1101 { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, 1102 { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, 1103 { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, 1104 { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, 1105 { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, 1106 { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, 1107 { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, 1108 { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, 1109 { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, 1110 { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, 1111 { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, 1112 { "DELE", DELE, STR1, 1, "<sp> file-name" }, 1113 { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1114 { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1115 { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, 1116 { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, 1117 { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, 1118 { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, 1119 { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, 1120 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1121 { "NOOP", NOOP, ARGS, 1, "" }, 1122 { "MKD", MKD, STR1, 1, "<sp> path-name" }, 1123 { "XMKD", MKD, STR1, 1, "<sp> path-name" }, 1124 { "RMD", RMD, STR1, 1, "<sp> path-name" }, 1125 { "XRMD", RMD, STR1, 1, "<sp> path-name" }, 1126 { "PWD", PWD, ARGS, 1, "(return current directory)" }, 1127 { "XPWD", PWD, ARGS, 1, "(return current directory)" }, 1128 { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1129 { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1130 { "STOU", STOU, STR1, 1, "<sp> file-name" }, 1131 { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, 1132 { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, 1133 { NULL, 0, 0, 0, 0 } 1134 }; 1135 1136 struct tab sitetab[] = { 1137 { "MD5", MDFIVE, STR1, 1, "[ <sp> file-name ]" }, 1138 { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, 1139 { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, 1140 { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, 1141 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1142 { NULL, 0, 0, 0, 0 } 1143 }; 1144 1145 static char *copy(char *); 1146 static void help(struct tab *, char *); 1147 static struct tab * 1148 lookup(struct tab *, char *); 1149 static int port_check(const char *); 1150 static int port_check_v6(const char *); 1151 static void sizecmd(char *); 1152 static void toolong(int); 1153 static void v4map_data_dest(void); 1154 static int yylex(void); 1155 1156 static struct tab * 1157 lookup(struct tab *p, char *cmd) 1158 { 1159 1160 for (; p->name != NULL; p++) 1161 if (strcmp(cmd, p->name) == 0) 1162 return (p); 1163 return (0); 1164 } 1165 1166 #include <arpa/telnet.h> 1167 1168 /* 1169 * getline - a hacked up version of fgets to ignore TELNET escape codes. 1170 */ 1171 char * 1172 getline(char *s, int n, FILE *iop) 1173 { 1174 int c; 1175 register char *cs; 1176 1177 cs = s; 1178 /* tmpline may contain saved command from urgent mode interruption */ 1179 for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 1180 *cs++ = tmpline[c]; 1181 if (tmpline[c] == '\n') { 1182 *cs++ = '\0'; 1183 if (ftpdebug) 1184 syslog(LOG_DEBUG, "command: %s", s); 1185 tmpline[0] = '\0'; 1186 return(s); 1187 } 1188 if (c == 0) 1189 tmpline[0] = '\0'; 1190 } 1191 while ((c = getc(iop)) != EOF) { 1192 c &= 0377; 1193 if (c == IAC) { 1194 if ((c = getc(iop)) != EOF) { 1195 c &= 0377; 1196 switch (c) { 1197 case WILL: 1198 case WONT: 1199 c = getc(iop); 1200 printf("%c%c%c", IAC, DONT, 0377&c); 1201 (void) fflush(stdout); 1202 continue; 1203 case DO: 1204 case DONT: 1205 c = getc(iop); 1206 printf("%c%c%c", IAC, WONT, 0377&c); 1207 (void) fflush(stdout); 1208 continue; 1209 case IAC: 1210 break; 1211 default: 1212 continue; /* ignore command */ 1213 } 1214 } 1215 } 1216 *cs++ = c; 1217 if (--n <= 0 || c == '\n') 1218 break; 1219 } 1220 if (c == EOF && cs == s) 1221 return (NULL); 1222 *cs++ = '\0'; 1223 if (ftpdebug) { 1224 if (!guest && strncasecmp("pass ", s, 5) == 0) { 1225 /* Don't syslog passwords */ 1226 syslog(LOG_DEBUG, "command: %.5s ???", s); 1227 } else { 1228 register char *cp; 1229 register int len; 1230 1231 /* Don't syslog trailing CR-LF */ 1232 len = strlen(s); 1233 cp = s + len - 1; 1234 while (cp >= s && (*cp == '\n' || *cp == '\r')) { 1235 --cp; 1236 --len; 1237 } 1238 syslog(LOG_DEBUG, "command: %.*s", len, s); 1239 } 1240 } 1241 return (s); 1242 } 1243 1244 static void 1245 toolong(int signo) 1246 { 1247 1248 reply(421, 1249 "Timeout (%d seconds): closing control connection.", timeout); 1250 if (logging) 1251 syslog(LOG_INFO, "User %s timed out after %d seconds", 1252 (pw ? pw -> pw_name : "unknown"), timeout); 1253 dologout(1); 1254 } 1255 1256 static int 1257 yylex(void) 1258 { 1259 static int cpos; 1260 char *cp, *cp2; 1261 struct tab *p; 1262 int n; 1263 char c; 1264 1265 for (;;) { 1266 switch (state) { 1267 1268 case CMD: 1269 (void) signal(SIGALRM, toolong); 1270 (void) alarm((unsigned) timeout); 1271 if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { 1272 reply(221, "You could at least say goodbye."); 1273 dologout(0); 1274 } 1275 (void) alarm(0); 1276 #ifdef SETPROCTITLE 1277 if (strncasecmp(cbuf, "PASS", 4) != 0) 1278 setproctitle("%s: %s", proctitle, cbuf); 1279 #endif /* SETPROCTITLE */ 1280 if ((cp = strchr(cbuf, '\r'))) { 1281 *cp++ = '\n'; 1282 *cp = '\0'; 1283 } 1284 if ((cp = strpbrk(cbuf, " \n"))) 1285 cpos = cp - cbuf; 1286 if (cpos == 0) 1287 cpos = 4; 1288 c = cbuf[cpos]; 1289 cbuf[cpos] = '\0'; 1290 upper(cbuf); 1291 p = lookup(cmdtab, cbuf); 1292 cbuf[cpos] = c; 1293 if (p != 0) { 1294 if (p->implemented == 0) { 1295 nack(p->name); 1296 return (LEXERR); 1297 } 1298 state = p->state; 1299 yylval.s = p->name; 1300 return (p->token); 1301 } 1302 break; 1303 1304 case SITECMD: 1305 if (cbuf[cpos] == ' ') { 1306 cpos++; 1307 return (SP); 1308 } 1309 cp = &cbuf[cpos]; 1310 if ((cp2 = strpbrk(cp, " \n"))) 1311 cpos = cp2 - cbuf; 1312 c = cbuf[cpos]; 1313 cbuf[cpos] = '\0'; 1314 upper(cp); 1315 p = lookup(sitetab, cp); 1316 cbuf[cpos] = c; 1317 if (guest == 0 && p != 0) { 1318 if (p->implemented == 0) { 1319 state = CMD; 1320 nack(p->name); 1321 return (LEXERR); 1322 } 1323 state = p->state; 1324 yylval.s = p->name; 1325 return (p->token); 1326 } 1327 state = CMD; 1328 break; 1329 1330 case ZSTR1: 1331 case OSTR: 1332 if (cbuf[cpos] == '\n') { 1333 state = CMD; 1334 return (CRLF); 1335 } 1336 /* FALLTHROUGH */ 1337 1338 case STR1: 1339 dostr1: 1340 if (cbuf[cpos] == ' ') { 1341 cpos++; 1342 state = state == OSTR ? STR2 : state+1; 1343 return (SP); 1344 } 1345 break; 1346 1347 case ZSTR2: 1348 if (cbuf[cpos] == '\n') { 1349 state = CMD; 1350 return (CRLF); 1351 } 1352 /* FALLTHROUGH */ 1353 1354 case STR2: 1355 cp = &cbuf[cpos]; 1356 n = strlen(cp); 1357 cpos += n - 1; 1358 /* 1359 * Make sure the string is nonempty and \n terminated. 1360 */ 1361 if (n > 1 && cbuf[cpos] == '\n') { 1362 cbuf[cpos] = '\0'; 1363 yylval.s = copy(cp); 1364 cbuf[cpos] = '\n'; 1365 state = ARGS; 1366 return (STRING); 1367 } 1368 break; 1369 1370 case NSTR: 1371 if (cbuf[cpos] == ' ') { 1372 cpos++; 1373 return (SP); 1374 } 1375 if (isdigit(cbuf[cpos])) { 1376 cp = &cbuf[cpos]; 1377 while (isdigit(cbuf[++cpos])) 1378 ; 1379 c = cbuf[cpos]; 1380 cbuf[cpos] = '\0'; 1381 yylval.u.i = atoi(cp); 1382 cbuf[cpos] = c; 1383 state = STR1; 1384 return (NUMBER); 1385 } 1386 state = STR1; 1387 goto dostr1; 1388 1389 case ARGS: 1390 if (isdigit(cbuf[cpos])) { 1391 cp = &cbuf[cpos]; 1392 while (isdigit(cbuf[++cpos])) 1393 ; 1394 c = cbuf[cpos]; 1395 cbuf[cpos] = '\0'; 1396 yylval.u.i = atoi(cp); 1397 yylval.u.o = strtoull(cp, (char **)NULL, 10); 1398 cbuf[cpos] = c; 1399 return (NUMBER); 1400 } 1401 if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0 1402 && !isalnum(cbuf[cpos + 3])) { 1403 cpos += 3; 1404 return ALL; 1405 } 1406 switch (cbuf[cpos++]) { 1407 1408 case '\n': 1409 state = CMD; 1410 return (CRLF); 1411 1412 case ' ': 1413 return (SP); 1414 1415 case ',': 1416 return (COMMA); 1417 1418 case 'A': 1419 case 'a': 1420 return (A); 1421 1422 case 'B': 1423 case 'b': 1424 return (B); 1425 1426 case 'C': 1427 case 'c': 1428 return (C); 1429 1430 case 'E': 1431 case 'e': 1432 return (E); 1433 1434 case 'F': 1435 case 'f': 1436 return (F); 1437 1438 case 'I': 1439 case 'i': 1440 return (I); 1441 1442 case 'L': 1443 case 'l': 1444 return (L); 1445 1446 case 'N': 1447 case 'n': 1448 return (N); 1449 1450 case 'P': 1451 case 'p': 1452 return (P); 1453 1454 case 'R': 1455 case 'r': 1456 return (R); 1457 1458 case 'S': 1459 case 's': 1460 return (S); 1461 1462 case 'T': 1463 case 't': 1464 return (T); 1465 1466 } 1467 break; 1468 1469 default: 1470 fatalerror("Unknown state in scanner."); 1471 } 1472 state = CMD; 1473 return (LEXERR); 1474 } 1475 } 1476 1477 void 1478 upper(char *s) 1479 { 1480 while (*s != '\0') { 1481 if (islower(*s)) 1482 *s = toupper(*s); 1483 s++; 1484 } 1485 } 1486 1487 static char * 1488 copy(char *s) 1489 { 1490 char *p; 1491 1492 p = malloc((unsigned) strlen(s) + 1); 1493 if (p == NULL) 1494 fatalerror("Ran out of memory."); 1495 (void) strcpy(p, s); 1496 return (p); 1497 } 1498 1499 static void 1500 help(struct tab *ctab, char *s) 1501 { 1502 struct tab *c; 1503 int width, NCMDS; 1504 char *type; 1505 1506 if (ctab == sitetab) 1507 type = "SITE "; 1508 else 1509 type = ""; 1510 width = 0, NCMDS = 0; 1511 for (c = ctab; c->name != NULL; c++) { 1512 int len = strlen(c->name); 1513 1514 if (len > width) 1515 width = len; 1516 NCMDS++; 1517 } 1518 width = (width + 8) &~ 7; 1519 if (s == 0) { 1520 int i, j, w; 1521 int columns, lines; 1522 1523 lreply(214, "The following %scommands are recognized %s.", 1524 type, "(* =>'s unimplemented)"); 1525 columns = 76 / width; 1526 if (columns == 0) 1527 columns = 1; 1528 lines = (NCMDS + columns - 1) / columns; 1529 for (i = 0; i < lines; i++) { 1530 printf(" "); 1531 for (j = 0; j < columns; j++) { 1532 c = ctab + j * lines + i; 1533 printf("%s%c", c->name, 1534 c->implemented ? ' ' : '*'); 1535 if (c + lines >= &ctab[NCMDS]) 1536 break; 1537 w = strlen(c->name) + 1; 1538 while (w < width) { 1539 putchar(' '); 1540 w++; 1541 } 1542 } 1543 printf("\r\n"); 1544 } 1545 (void) fflush(stdout); 1546 reply(214, "Direct comments to ftp-bugs@%s.", hostname); 1547 return; 1548 } 1549 upper(s); 1550 c = lookup(ctab, s); 1551 if (c == (struct tab *)0) { 1552 reply(502, "Unknown command %s.", s); 1553 return; 1554 } 1555 if (c->implemented) 1556 reply(214, "Syntax: %s%s %s", type, c->name, c->help); 1557 else 1558 reply(214, "%s%-*s\t%s; unimplemented.", type, width, 1559 c->name, c->help); 1560 } 1561 1562 static void 1563 sizecmd(char *filename) 1564 { 1565 switch (type) { 1566 case TYPE_L: 1567 case TYPE_I: { 1568 struct stat stbuf; 1569 if (stat(filename, &stbuf) < 0) 1570 perror_reply(550, filename); 1571 else if (!S_ISREG(stbuf.st_mode)) 1572 reply(550, "%s: not a plain file.", filename); 1573 else 1574 reply(213, "%qu", stbuf.st_size); 1575 break; } 1576 case TYPE_A: { 1577 FILE *fin; 1578 int c; 1579 off_t count; 1580 struct stat stbuf; 1581 fin = fopen(filename, "r"); 1582 if (fin == NULL) { 1583 perror_reply(550, filename); 1584 return; 1585 } 1586 if (fstat(fileno(fin), &stbuf) < 0) { 1587 perror_reply(550, filename); 1588 (void) fclose(fin); 1589 return; 1590 } else if (!S_ISREG(stbuf.st_mode)) { 1591 reply(550, "%s: not a plain file.", filename); 1592 (void) fclose(fin); 1593 return; 1594 } else if (stbuf.st_size > MAXASIZE) { 1595 reply(550, "%s: too large for type A SIZE.", filename); 1596 (void) fclose(fin); 1597 return; 1598 } 1599 1600 count = 0; 1601 while((c=getc(fin)) != EOF) { 1602 if (c == '\n') /* will get expanded to \r\n */ 1603 count++; 1604 count++; 1605 } 1606 (void) fclose(fin); 1607 1608 reply(213, "%qd", count); 1609 break; } 1610 default: 1611 reply(504, "SIZE not implemented for type %s.", 1612 typenames[type]); 1613 } 1614 } 1615 1616 /* Return 1, if port check is done. Return 0, if not yet. */ 1617 static int 1618 port_check(const char *pcmd) 1619 { 1620 if (his_addr.su_family == AF_INET) { 1621 if (data_dest.su_family != AF_INET) { 1622 usedefault = 1; 1623 reply(500, "Invalid address rejected."); 1624 return 1; 1625 } 1626 if (paranoid && 1627 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1628 memcmp(&data_dest.su_sin.sin_addr, 1629 &his_addr.su_sin.sin_addr, 1630 sizeof(data_dest.su_sin.sin_addr)))) { 1631 usedefault = 1; 1632 reply(500, "Illegal PORT range rejected."); 1633 } else { 1634 usedefault = 0; 1635 if (pdata >= 0) { 1636 (void) close(pdata); 1637 pdata = -1; 1638 } 1639 reply(200, "%s command successful.", pcmd); 1640 } 1641 return 1; 1642 } 1643 return 0; 1644 } 1645 1646 static int 1647 check_login1(void) 1648 { 1649 if (logged_in) 1650 return 1; 1651 else { 1652 reply(530, "Please login with USER and PASS."); 1653 return 0; 1654 } 1655 } 1656 1657 #ifdef INET6 1658 /* Return 1, if port check is done. Return 0, if not yet. */ 1659 static int 1660 port_check_v6(const char *pcmd) 1661 { 1662 if (his_addr.su_family == AF_INET6) { 1663 if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) 1664 /* Convert data_dest into v4 mapped sockaddr.*/ 1665 v4map_data_dest(); 1666 if (data_dest.su_family != AF_INET6) { 1667 usedefault = 1; 1668 reply(500, "Invalid address rejected."); 1669 return 1; 1670 } 1671 if (paranoid && 1672 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1673 memcmp(&data_dest.su_sin6.sin6_addr, 1674 &his_addr.su_sin6.sin6_addr, 1675 sizeof(data_dest.su_sin6.sin6_addr)))) { 1676 usedefault = 1; 1677 reply(500, "Illegal PORT range rejected."); 1678 } else { 1679 usedefault = 0; 1680 if (pdata >= 0) { 1681 (void) close(pdata); 1682 pdata = -1; 1683 } 1684 reply(200, "%s command successful.", pcmd); 1685 } 1686 return 1; 1687 } 1688 return 0; 1689 } 1690 1691 static void 1692 v4map_data_dest(void) 1693 { 1694 struct in_addr savedaddr; 1695 int savedport; 1696 1697 if (data_dest.su_family != AF_INET) { 1698 usedefault = 1; 1699 reply(500, "Invalid address rejected."); 1700 return; 1701 } 1702 1703 savedaddr = data_dest.su_sin.sin_addr; 1704 savedport = data_dest.su_port; 1705 1706 memset(&data_dest, 0, sizeof(data_dest)); 1707 data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6); 1708 data_dest.su_sin6.sin6_family = AF_INET6; 1709 data_dest.su_sin6.sin6_port = savedport; 1710 memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2); 1711 memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12], 1712 (caddr_t)&savedaddr, sizeof(savedaddr)); 1713 } 1714 #endif 1715