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 NOTIMPL 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 NOTIMPL 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 CHAR_BIT == 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 /* CHAR_BIT == 8 */ 404 UNIMPLEMENTED for CHAR_BIT != 8 405 #endif /* CHAR_BIT == 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 CHAR_BIT, BSD); 696 #else /* BSD */ 697 reply(215, "UNIX Type: L%d", CHAR_BIT); 698 #endif /* BSD */ 699 #else /* unix */ 700 reply(215, "UNKNOWN Type: L%d", CHAR_BIT); 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 | 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 /* 968 * Problem: this production is used for all pathname 969 * processing, but only gives a 550 error reply. 970 * This is a valid reply in some cases but not in others. 971 */ 972 if (logged_in && $1) { 973 glob_t gl; 974 int flags = 975 GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 976 977 memset(&gl, 0, sizeof(gl)); 978 flags |= GLOB_MAXPATH; 979 gl.gl_matchc = MAXGLOBARGS; 980 if (glob($1, flags, NULL, &gl) || 981 gl.gl_pathc == 0) { 982 reply(550, "wildcard expansion error"); 983 $$ = NULL; 984 } else if (gl.gl_pathc > 1) { 985 reply(550, "ambiguous"); 986 $$ = NULL; 987 } else { 988 $$ = strdup(gl.gl_pathv[0]); 989 } 990 globfree(&gl); 991 free($1); 992 } else 993 $$ = $1; 994 } 995 ; 996 997 pathstring 998 : STRING 999 ; 1000 1001 octal_number 1002 : NUMBER 1003 { 1004 int ret, dec, multby, digit; 1005 1006 /* 1007 * Convert a number that was read as decimal number 1008 * to what it would be if it had been read as octal. 1009 */ 1010 dec = $1.i; 1011 multby = 1; 1012 ret = 0; 1013 while (dec) { 1014 digit = dec%10; 1015 if (digit > 7) { 1016 ret = -1; 1017 break; 1018 } 1019 ret += digit * multby; 1020 multby *= 8; 1021 dec /= 10; 1022 } 1023 $$ = ret; 1024 } 1025 ; 1026 1027 1028 check_login 1029 : /* empty */ 1030 { 1031 $$ = check_login1(); 1032 } 1033 ; 1034 1035 check_login_epsv 1036 : /* empty */ 1037 { 1038 if (noepsv) { 1039 reply(500, "EPSV command disabled"); 1040 $$ = 0; 1041 } 1042 else 1043 $$ = check_login1(); 1044 } 1045 ; 1046 1047 check_login_ro 1048 : /* empty */ 1049 { 1050 if (readonly) { 1051 reply(550, "Permission denied."); 1052 $$ = 0; 1053 } 1054 else 1055 $$ = check_login1(); 1056 } 1057 ; 1058 1059 %% 1060 1061 #define CMD 0 /* beginning of command */ 1062 #define ARGS 1 /* expect miscellaneous arguments */ 1063 #define STR1 2 /* expect SP followed by STRING */ 1064 #define STR2 3 /* expect STRING */ 1065 #define OSTR 4 /* optional SP then STRING */ 1066 #define ZSTR1 5 /* optional SP then optional STRING */ 1067 #define ZSTR2 6 /* optional STRING after SP */ 1068 #define SITECMD 7 /* SITE command */ 1069 #define NSTR 8 /* Number followed by a string */ 1070 1071 #define MAXGLOBARGS 1000 1072 1073 #define MAXASIZE 10240 /* Deny ASCII SIZE on files larger than that */ 1074 1075 struct tab { 1076 char *name; 1077 short token; 1078 short state; 1079 short implemented; /* 1 if command is implemented */ 1080 char *help; 1081 }; 1082 1083 struct tab cmdtab[] = { /* In order defined in RFC 765 */ 1084 { "USER", USER, STR1, 1, "<sp> username" }, 1085 { "PASS", PASS, ZSTR1, 1, "[<sp> [password]]" }, 1086 { "ACCT", ACCT, STR1, 0, "(specify account)" }, 1087 { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, 1088 { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, 1089 { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, 1090 { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4, b5" }, 1091 { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." }, 1092 { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" }, 1093 { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, 1094 { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, 1095 { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" }, 1096 { "TYPE", TYPE, ARGS, 1, "<sp> { A | E | I | L }" }, 1097 { "STRU", STRU, ARGS, 1, "(specify file structure)" }, 1098 { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, 1099 { "RETR", RETR, STR1, 1, "<sp> file-name" }, 1100 { "STOR", STOR, STR1, 1, "<sp> file-name" }, 1101 { "APPE", APPE, STR1, 1, "<sp> file-name" }, 1102 { "MLFL", MLFL, OSTR, 0, "(mail file)" }, 1103 { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, 1104 { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, 1105 { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, 1106 { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, 1107 { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, 1108 { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, 1109 { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, 1110 { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, 1111 { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, 1112 { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, 1113 { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, 1114 { "DELE", DELE, STR1, 1, "<sp> file-name" }, 1115 { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1116 { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1117 { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, 1118 { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, 1119 { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, 1120 { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, 1121 { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, 1122 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1123 { "NOOP", NOOP, ARGS, 1, "" }, 1124 { "MKD", MKD, STR1, 1, "<sp> path-name" }, 1125 { "XMKD", MKD, STR1, 1, "<sp> path-name" }, 1126 { "RMD", RMD, STR1, 1, "<sp> path-name" }, 1127 { "XRMD", RMD, STR1, 1, "<sp> path-name" }, 1128 { "PWD", PWD, ARGS, 1, "(return current directory)" }, 1129 { "XPWD", PWD, ARGS, 1, "(return current directory)" }, 1130 { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1131 { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1132 { "STOU", STOU, STR1, 1, "<sp> file-name" }, 1133 { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, 1134 { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, 1135 { NULL, 0, 0, 0, 0 } 1136 }; 1137 1138 struct tab sitetab[] = { 1139 { "MD5", MDFIVE, STR1, 1, "[ <sp> file-name ]" }, 1140 { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, 1141 { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, 1142 { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, 1143 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1144 { NULL, 0, 0, 0, 0 } 1145 }; 1146 1147 static char *copy(char *); 1148 static void help(struct tab *, char *); 1149 static struct tab * 1150 lookup(struct tab *, char *); 1151 static int port_check(const char *); 1152 static int port_check_v6(const char *); 1153 static void sizecmd(char *); 1154 static void toolong(int); 1155 static void v4map_data_dest(void); 1156 static int yylex(void); 1157 1158 static struct tab * 1159 lookup(struct tab *p, char *cmd) 1160 { 1161 1162 for (; p->name != NULL; p++) 1163 if (strcmp(cmd, p->name) == 0) 1164 return (p); 1165 return (0); 1166 } 1167 1168 #include <arpa/telnet.h> 1169 1170 /* 1171 * getline - a hacked up version of fgets to ignore TELNET escape codes. 1172 */ 1173 char * 1174 getline(char *s, int n, FILE *iop) 1175 { 1176 int c; 1177 register char *cs; 1178 1179 cs = s; 1180 /* tmpline may contain saved command from urgent mode interruption */ 1181 for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 1182 *cs++ = tmpline[c]; 1183 if (tmpline[c] == '\n') { 1184 *cs++ = '\0'; 1185 if (ftpdebug) 1186 syslog(LOG_DEBUG, "command: %s", s); 1187 tmpline[0] = '\0'; 1188 return(s); 1189 } 1190 if (c == 0) 1191 tmpline[0] = '\0'; 1192 } 1193 while ((c = getc(iop)) != EOF) { 1194 c &= 0377; 1195 if (c == IAC) { 1196 if ((c = getc(iop)) != EOF) { 1197 c &= 0377; 1198 switch (c) { 1199 case WILL: 1200 case WONT: 1201 c = getc(iop); 1202 printf("%c%c%c", IAC, DONT, 0377&c); 1203 (void) fflush(stdout); 1204 continue; 1205 case DO: 1206 case DONT: 1207 c = getc(iop); 1208 printf("%c%c%c", IAC, WONT, 0377&c); 1209 (void) fflush(stdout); 1210 continue; 1211 case IAC: 1212 break; 1213 default: 1214 continue; /* ignore command */ 1215 } 1216 } 1217 } 1218 *cs++ = c; 1219 if (--n <= 0 || c == '\n') 1220 break; 1221 } 1222 if (c == EOF && cs == s) 1223 return (NULL); 1224 *cs++ = '\0'; 1225 if (ftpdebug) { 1226 if (!guest && strncasecmp("pass ", s, 5) == 0) { 1227 /* Don't syslog passwords */ 1228 syslog(LOG_DEBUG, "command: %.5s ???", s); 1229 } else { 1230 register char *cp; 1231 register int len; 1232 1233 /* Don't syslog trailing CR-LF */ 1234 len = strlen(s); 1235 cp = s + len - 1; 1236 while (cp >= s && (*cp == '\n' || *cp == '\r')) { 1237 --cp; 1238 --len; 1239 } 1240 syslog(LOG_DEBUG, "command: %.*s", len, s); 1241 } 1242 } 1243 return (s); 1244 } 1245 1246 static void 1247 toolong(int signo) 1248 { 1249 1250 reply(421, 1251 "Timeout (%d seconds): closing control connection.", timeout); 1252 if (logging) 1253 syslog(LOG_INFO, "User %s timed out after %d seconds", 1254 (pw ? pw -> pw_name : "unknown"), timeout); 1255 dologout(1); 1256 } 1257 1258 static int 1259 yylex(void) 1260 { 1261 static int cpos; 1262 char *cp, *cp2; 1263 struct tab *p; 1264 int n; 1265 char c; 1266 1267 for (;;) { 1268 switch (state) { 1269 1270 case CMD: 1271 (void) signal(SIGALRM, toolong); 1272 (void) alarm((unsigned) timeout); 1273 if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { 1274 reply(221, "You could at least say goodbye."); 1275 dologout(0); 1276 } 1277 (void) alarm(0); 1278 #ifdef SETPROCTITLE 1279 if (strncasecmp(cbuf, "PASS", 4) != 0) 1280 setproctitle("%s: %s", proctitle, cbuf); 1281 #endif /* SETPROCTITLE */ 1282 if ((cp = strchr(cbuf, '\r'))) { 1283 *cp++ = '\n'; 1284 *cp = '\0'; 1285 } 1286 if ((cp = strpbrk(cbuf, " \n"))) 1287 cpos = cp - cbuf; 1288 if (cpos == 0) 1289 cpos = 4; 1290 c = cbuf[cpos]; 1291 cbuf[cpos] = '\0'; 1292 upper(cbuf); 1293 p = lookup(cmdtab, cbuf); 1294 cbuf[cpos] = c; 1295 if (p != 0) { 1296 yylval.s = p->name; 1297 if (!p->implemented) 1298 return (NOTIMPL); /* state remains CMD */ 1299 state = p->state; 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 yylval.s = p->name; 1319 if (!p->implemented) { 1320 state = CMD; 1321 return (NOTIMPL); 1322 } 1323 state = p->state; 1324 return (p->token); 1325 } 1326 state = CMD; 1327 break; 1328 1329 case ZSTR1: 1330 case OSTR: 1331 if (cbuf[cpos] == '\n') { 1332 state = CMD; 1333 return (CRLF); 1334 } 1335 /* FALLTHROUGH */ 1336 1337 case STR1: 1338 dostr1: 1339 if (cbuf[cpos] == ' ') { 1340 cpos++; 1341 state = state == OSTR ? STR2 : state+1; 1342 return (SP); 1343 } 1344 break; 1345 1346 case ZSTR2: 1347 if (cbuf[cpos] == '\n') { 1348 state = CMD; 1349 return (CRLF); 1350 } 1351 /* FALLTHROUGH */ 1352 1353 case STR2: 1354 cp = &cbuf[cpos]; 1355 n = strlen(cp); 1356 cpos += n - 1; 1357 /* 1358 * Make sure the string is nonempty and \n terminated. 1359 */ 1360 if (n > 1 && cbuf[cpos] == '\n') { 1361 cbuf[cpos] = '\0'; 1362 yylval.s = copy(cp); 1363 cbuf[cpos] = '\n'; 1364 state = ARGS; 1365 return (STRING); 1366 } 1367 break; 1368 1369 case NSTR: 1370 if (cbuf[cpos] == ' ') { 1371 cpos++; 1372 return (SP); 1373 } 1374 if (isdigit(cbuf[cpos])) { 1375 cp = &cbuf[cpos]; 1376 while (isdigit(cbuf[++cpos])) 1377 ; 1378 c = cbuf[cpos]; 1379 cbuf[cpos] = '\0'; 1380 yylval.u.i = atoi(cp); 1381 cbuf[cpos] = c; 1382 state = STR1; 1383 return (NUMBER); 1384 } 1385 state = STR1; 1386 goto dostr1; 1387 1388 case ARGS: 1389 if (isdigit(cbuf[cpos])) { 1390 cp = &cbuf[cpos]; 1391 while (isdigit(cbuf[++cpos])) 1392 ; 1393 c = cbuf[cpos]; 1394 cbuf[cpos] = '\0'; 1395 yylval.u.i = atoi(cp); 1396 yylval.u.o = strtoull(cp, (char **)NULL, 10); 1397 cbuf[cpos] = c; 1398 return (NUMBER); 1399 } 1400 if (strncasecmp(&cbuf[cpos], "ALL", 3) == 0 1401 && !isalnum(cbuf[cpos + 3])) { 1402 cpos += 3; 1403 return ALL; 1404 } 1405 switch (cbuf[cpos++]) { 1406 1407 case '\n': 1408 state = CMD; 1409 return (CRLF); 1410 1411 case ' ': 1412 return (SP); 1413 1414 case ',': 1415 return (COMMA); 1416 1417 case 'A': 1418 case 'a': 1419 return (A); 1420 1421 case 'B': 1422 case 'b': 1423 return (B); 1424 1425 case 'C': 1426 case 'c': 1427 return (C); 1428 1429 case 'E': 1430 case 'e': 1431 return (E); 1432 1433 case 'F': 1434 case 'f': 1435 return (F); 1436 1437 case 'I': 1438 case 'i': 1439 return (I); 1440 1441 case 'L': 1442 case 'l': 1443 return (L); 1444 1445 case 'N': 1446 case 'n': 1447 return (N); 1448 1449 case 'P': 1450 case 'p': 1451 return (P); 1452 1453 case 'R': 1454 case 'r': 1455 return (R); 1456 1457 case 'S': 1458 case 's': 1459 return (S); 1460 1461 case 'T': 1462 case 't': 1463 return (T); 1464 1465 } 1466 break; 1467 1468 default: 1469 fatalerror("Unknown state in scanner."); 1470 } 1471 state = CMD; 1472 return (LEXERR); 1473 } 1474 } 1475 1476 void 1477 upper(char *s) 1478 { 1479 while (*s != '\0') { 1480 if (islower(*s)) 1481 *s = toupper(*s); 1482 s++; 1483 } 1484 } 1485 1486 static char * 1487 copy(char *s) 1488 { 1489 char *p; 1490 1491 p = malloc((unsigned) strlen(s) + 1); 1492 if (p == NULL) 1493 fatalerror("Ran out of memory."); 1494 (void) strcpy(p, s); 1495 return (p); 1496 } 1497 1498 static void 1499 help(struct tab *ctab, char *s) 1500 { 1501 struct tab *c; 1502 int width, NCMDS; 1503 char *type; 1504 1505 if (ctab == sitetab) 1506 type = "SITE "; 1507 else 1508 type = ""; 1509 width = 0, NCMDS = 0; 1510 for (c = ctab; c->name != NULL; c++) { 1511 int len = strlen(c->name); 1512 1513 if (len > width) 1514 width = len; 1515 NCMDS++; 1516 } 1517 width = (width + 8) &~ 7; 1518 if (s == 0) { 1519 int i, j, w; 1520 int columns, lines; 1521 1522 lreply(214, "The following %scommands are recognized %s.", 1523 type, "(* =>'s unimplemented)"); 1524 columns = 76 / width; 1525 if (columns == 0) 1526 columns = 1; 1527 lines = (NCMDS + columns - 1) / columns; 1528 for (i = 0; i < lines; i++) { 1529 printf(" "); 1530 for (j = 0; j < columns; j++) { 1531 c = ctab + j * lines + i; 1532 printf("%s%c", c->name, 1533 c->implemented ? ' ' : '*'); 1534 if (c + lines >= &ctab[NCMDS]) 1535 break; 1536 w = strlen(c->name) + 1; 1537 while (w < width) { 1538 putchar(' '); 1539 w++; 1540 } 1541 } 1542 printf("\r\n"); 1543 } 1544 (void) fflush(stdout); 1545 reply(214, "Direct comments to ftp-bugs@%s.", hostname); 1546 return; 1547 } 1548 upper(s); 1549 c = lookup(ctab, s); 1550 if (c == (struct tab *)0) { 1551 reply(502, "Unknown command %s.", s); 1552 return; 1553 } 1554 if (c->implemented) 1555 reply(214, "Syntax: %s%s %s", type, c->name, c->help); 1556 else 1557 reply(214, "%s%-*s\t%s; unimplemented.", type, width, 1558 c->name, c->help); 1559 } 1560 1561 static void 1562 sizecmd(char *filename) 1563 { 1564 switch (type) { 1565 case TYPE_L: 1566 case TYPE_I: { 1567 struct stat stbuf; 1568 if (stat(filename, &stbuf) < 0) 1569 perror_reply(550, filename); 1570 else if (!S_ISREG(stbuf.st_mode)) 1571 reply(550, "%s: not a plain file.", filename); 1572 else 1573 reply(213, "%qu", stbuf.st_size); 1574 break; } 1575 case TYPE_A: { 1576 FILE *fin; 1577 int c; 1578 off_t count; 1579 struct stat stbuf; 1580 fin = fopen(filename, "r"); 1581 if (fin == NULL) { 1582 perror_reply(550, filename); 1583 return; 1584 } 1585 if (fstat(fileno(fin), &stbuf) < 0) { 1586 perror_reply(550, filename); 1587 (void) fclose(fin); 1588 return; 1589 } else if (!S_ISREG(stbuf.st_mode)) { 1590 reply(550, "%s: not a plain file.", filename); 1591 (void) fclose(fin); 1592 return; 1593 } else if (stbuf.st_size > MAXASIZE) { 1594 reply(550, "%s: too large for type A SIZE.", filename); 1595 (void) fclose(fin); 1596 return; 1597 } 1598 1599 count = 0; 1600 while((c=getc(fin)) != EOF) { 1601 if (c == '\n') /* will get expanded to \r\n */ 1602 count++; 1603 count++; 1604 } 1605 (void) fclose(fin); 1606 1607 reply(213, "%qd", count); 1608 break; } 1609 default: 1610 reply(504, "SIZE not implemented for type %s.", 1611 typenames[type]); 1612 } 1613 } 1614 1615 /* Return 1, if port check is done. Return 0, if not yet. */ 1616 static int 1617 port_check(const char *pcmd) 1618 { 1619 if (his_addr.su_family == AF_INET) { 1620 if (data_dest.su_family != AF_INET) { 1621 usedefault = 1; 1622 reply(500, "Invalid address rejected."); 1623 return 1; 1624 } 1625 if (paranoid && 1626 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1627 memcmp(&data_dest.su_sin.sin_addr, 1628 &his_addr.su_sin.sin_addr, 1629 sizeof(data_dest.su_sin.sin_addr)))) { 1630 usedefault = 1; 1631 reply(500, "Illegal PORT range rejected."); 1632 } else { 1633 usedefault = 0; 1634 if (pdata >= 0) { 1635 (void) close(pdata); 1636 pdata = -1; 1637 } 1638 reply(200, "%s command successful.", pcmd); 1639 } 1640 return 1; 1641 } 1642 return 0; 1643 } 1644 1645 static int 1646 check_login1(void) 1647 { 1648 if (logged_in) 1649 return 1; 1650 else { 1651 reply(530, "Please login with USER and PASS."); 1652 return 0; 1653 } 1654 } 1655 1656 #ifdef INET6 1657 /* Return 1, if port check is done. Return 0, if not yet. */ 1658 static int 1659 port_check_v6(const char *pcmd) 1660 { 1661 if (his_addr.su_family == AF_INET6) { 1662 if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) 1663 /* Convert data_dest into v4 mapped sockaddr.*/ 1664 v4map_data_dest(); 1665 if (data_dest.su_family != AF_INET6) { 1666 usedefault = 1; 1667 reply(500, "Invalid address rejected."); 1668 return 1; 1669 } 1670 if (paranoid && 1671 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1672 memcmp(&data_dest.su_sin6.sin6_addr, 1673 &his_addr.su_sin6.sin6_addr, 1674 sizeof(data_dest.su_sin6.sin6_addr)))) { 1675 usedefault = 1; 1676 reply(500, "Illegal PORT range rejected."); 1677 } else { 1678 usedefault = 0; 1679 if (pdata >= 0) { 1680 (void) close(pdata); 1681 pdata = -1; 1682 } 1683 reply(200, "%s command successful.", pcmd); 1684 } 1685 return 1; 1686 } 1687 return 0; 1688 } 1689 1690 static void 1691 v4map_data_dest(void) 1692 { 1693 struct in_addr savedaddr; 1694 int savedport; 1695 1696 if (data_dest.su_family != AF_INET) { 1697 usedefault = 1; 1698 reply(500, "Invalid address rejected."); 1699 return; 1700 } 1701 1702 savedaddr = data_dest.su_sin.sin_addr; 1703 savedport = data_dest.su_port; 1704 1705 memset(&data_dest, 0, sizeof(data_dest)); 1706 data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6); 1707 data_dest.su_sin6.sin6_family = AF_INET6; 1708 data_dest.su_sin6.sin6_port = savedport; 1709 memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2); 1710 memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12], 1711 (caddr_t)&savedaddr, sizeof(savedaddr)); 1712 } 1713 #endif 1714