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