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