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