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