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