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