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