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