104char cbuf[512]; 105char *fromname = (char *) 0; 106 107extern int epsvall; 108 109%} 110 111%union { 112 int i; 113 char *s; 114} 115 116%token 117 A B C E F I 118 L N P R S T 119 ALL 120 121 SP CRLF COMMA 122 123 USER PASS ACCT REIN QUIT PORT 124 PASV TYPE STRU MODE RETR STOR 125 APPE MLFL MAIL MSND MSOM MSAM 126 MRSQ MRCP ALLO REST RNFR RNTO 127 ABOR DELE CWD LIST NLST SITE 128 STAT HELP NOOP MKD RMD PWD 129 CDUP STOU SMNT SYST SIZE MDTM 130 LPRT LPSV EPRT EPSV 131 132 UMASK IDLE CHMOD MDFIVE 133 134 LEXERR 135 136%token <s> STRING 137%token <i> NUMBER 138 139%type <i> check_login octal_number byte_size 140%type <i> check_login_ro octal_number byte_size 141%type <i> check_login_epsv octal_number byte_size 142%type <i> struct_code mode_code type_code form_code 143%type <s> pathstring pathname password username 144%type <s> ALL 145 146%start cmd_list 147 148%% 149 150cmd_list 151 : /* empty */ 152 | cmd_list cmd 153 { 154 if (fromname) 155 free(fromname); 156 fromname = (char *) 0; 157 restart_point = (off_t) 0; 158 } 159 | cmd_list rcmd 160 ; 161 162cmd 163 : USER SP username CRLF 164 { 165 user($3); 166 free($3); 167 } 168 | PASS SP password CRLF 169 { 170 pass($3); 171 free($3); 172 } 173 | PASS CRLF 174 { 175 pass(""); 176 } 177 | PORT check_login SP host_port CRLF 178 { 179 if (epsvall) { 180 reply(501, "no PORT allowed after EPSV ALL"); 181 goto port_done; 182 } 183 if (!$2) 184 goto port_done; 185 if (port_check("PORT") == 1) 186 goto port_done; 187#ifdef INET6 188 if ((his_addr.su_family != AF_INET6 || 189 !IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) { 190 /* shoud never happen */ 191 usedefault = 1; 192 reply(500, "Invalid address rejected."); 193 goto port_done; 194 } 195 port_check_v6("pcmd"); 196#endif 197 port_done: 198 } 199 | LPRT check_login SP host_long_port CRLF 200 { 201 if (epsvall) { 202 reply(501, "no LPRT allowed after EPSV ALL"); 203 goto lprt_done; 204 } 205 if (!$2) 206 goto lprt_done; 207 if (port_check("LPRT") == 1) 208 goto lprt_done; 209#ifdef INET6 210 if (his_addr.su_family != AF_INET6) { 211 usedefault = 1; 212 reply(500, "Invalid address rejected."); 213 goto lprt_done; 214 } 215 if (port_check_v6("LPRT") == 1) 216 goto lprt_done; 217#endif 218 lprt_done: 219 } 220 | EPRT check_login SP STRING CRLF 221 { 222 char delim; 223 char *tmp = NULL; 224 char *p, *q; 225 char *result[3]; 226 struct addrinfo hints; 227 struct addrinfo *res; 228 int i; 229 230 if (epsvall) { 231 reply(501, "no EPRT allowed after EPSV ALL"); 232 goto eprt_done; 233 } 234 if (!$2) 235 goto eprt_done; 236 237 memset(&data_dest, 0, sizeof(data_dest)); 238 tmp = strdup($4); 239 if (ftpdebug) 240 syslog(LOG_DEBUG, "%s", tmp); 241 if (!tmp) { 242 fatalerror("not enough core"); 243 /*NOTREACHED*/ 244 } 245 p = tmp; 246 delim = p[0]; 247 p++; 248 memset(result, 0, sizeof(result)); 249 for (i = 0; i < 3; i++) { 250 q = strchr(p, delim); 251 if (!q || *q != delim) { 252 parsefail: 253 reply(500, 254 "Invalid argument, rejected."); 255 if (tmp) 256 free(tmp); 257 usedefault = 1; 258 goto eprt_done; 259 } 260 *q++ = '\0'; 261 result[i] = p; 262 if (ftpdebug) 263 syslog(LOG_DEBUG, "%d: %s", i, p); 264 p = q; 265 } 266 267 /* some more sanity check */ 268 p = result[0]; 269 while (*p) { 270 if (!isdigit(*p)) 271 goto parsefail; 272 p++; 273 } 274 p = result[2]; 275 while (*p) { 276 if (!isdigit(*p)) 277 goto parsefail; 278 p++; 279 } 280 281 /* grab address */ 282 memset(&hints, 0, sizeof(hints)); 283 if (atoi(result[0]) == 1) 284 hints.ai_family = PF_INET; 285#ifdef INET6 286 else if (atoi(result[0]) == 2) 287 hints.ai_family = PF_INET6; 288#endif 289 else 290 hints.ai_family = PF_UNSPEC; /*XXX*/ 291 hints.ai_socktype = SOCK_STREAM; 292 i = getaddrinfo(result[1], result[2], &hints, &res); 293 if (i) 294 goto parsefail; 295 memcpy(&data_dest, res->ai_addr, res->ai_addrlen); 296#ifdef INET6 297 if (his_addr.su_family == AF_INET6 298 && data_dest.su_family == AF_INET6) { 299 /* XXX more sanity checks! */ 300 data_dest.su_sin6.sin6_scope_id = 301 his_addr.su_sin6.sin6_scope_id; 302 } 303#endif 304 free(tmp); 305 tmp = NULL; 306 307 if (port_check("EPRT") == 1) 308 goto eprt_done; 309#ifdef INET6 310 if (his_addr.su_family != AF_INET6) { 311 usedefault = 1; 312 reply(500, "Invalid address rejected."); 313 goto eprt_done; 314 } 315 if (port_check_v6("EPRT") == 1) 316 goto eprt_done; 317#endif 318 eprt_done: 319 free($4); 320 } 321 | PASV check_login CRLF 322 { 323 if (epsvall) 324 reply(501, "no PASV allowed after EPSV ALL"); 325 else if ($2) 326 passive(); 327 } 328 | LPSV check_login CRLF 329 { 330 if (epsvall) 331 reply(501, "no LPSV allowed after EPSV ALL"); 332 else if ($2) 333 long_passive("LPSV", PF_UNSPEC); 334 } 335 | EPSV check_login_epsv SP NUMBER CRLF 336 { 337 if ($2) { 338 int pf; 339 switch ($4) { 340 case 1: 341 pf = PF_INET; 342 break; 343#ifdef INET6 344 case 2: 345 pf = PF_INET6; 346 break; 347#endif 348 default: 349 pf = -1; /*junk value*/ 350 break; 351 } 352 long_passive("EPSV", pf); 353 } 354 } 355 | EPSV check_login_epsv SP ALL CRLF 356 { 357 if ($2) { 358 reply(200, 359 "EPSV ALL command successful."); 360 epsvall++; 361 } 362 } 363 | EPSV check_login_epsv CRLF 364 { 365 if ($2) 366 long_passive("EPSV", PF_UNSPEC); 367 } 368 | TYPE check_login SP type_code CRLF 369 { 370 if ($2) { 371 switch (cmd_type) { 372 373 case TYPE_A: 374 if (cmd_form == FORM_N) { 375 reply(200, "Type set to A."); 376 type = cmd_type; 377 form = cmd_form; 378 } else 379 reply(504, "Form must be N."); 380 break; 381 382 case TYPE_E: 383 reply(504, "Type E not implemented."); 384 break; 385 386 case TYPE_I: 387 reply(200, "Type set to I."); 388 type = cmd_type; 389 break; 390 391 case TYPE_L: 392#if NBBY == 8 393 if (cmd_bytesz == 8) { 394 reply(200, 395 "Type set to L (byte size 8)."); 396 type = cmd_type; 397 } else 398 reply(504, "Byte size must be 8."); 399#else /* NBBY == 8 */ 400 UNIMPLEMENTED for NBBY != 8 401#endif /* NBBY == 8 */ 402 } 403 } 404 } 405 | STRU check_login SP struct_code CRLF 406 { 407 if ($2) { 408 switch ($4) { 409 410 case STRU_F: 411 reply(200, "STRU F ok."); 412 break; 413 414 default: 415 reply(504, "Unimplemented STRU type."); 416 } 417 } 418 } 419 | MODE check_login SP mode_code CRLF 420 { 421 if ($2) { 422 switch ($4) { 423 424 case MODE_S: 425 reply(200, "MODE S ok."); 426 break; 427 428 default: 429 reply(502, "Unimplemented MODE type."); 430 } 431 } 432 } 433 | ALLO check_login SP NUMBER CRLF 434 { 435 if ($2) { 436 reply(202, "ALLO command ignored."); 437 } 438 } 439 | ALLO check_login SP NUMBER SP R SP NUMBER CRLF 440 { 441 if ($2) { 442 reply(202, "ALLO command ignored."); 443 } 444 } 445 | RETR check_login SP pathname CRLF 446 { 447 if (noretr || (guest && noguestretr)) 448 reply(500, "RETR command is disabled"); 449 else if ($2 && $4 != NULL) 450 retrieve((char *) 0, $4); 451 452 if ($4 != NULL) 453 free($4); 454 } 455 | STOR check_login_ro SP pathname CRLF 456 { 457 if ($2 && $4 != NULL) 458 store($4, "w", 0); 459 if ($4 != NULL) 460 free($4); 461 } 462 | APPE check_login_ro SP pathname CRLF 463 { 464 if ($2 && $4 != NULL) 465 store($4, "a", 0); 466 if ($4 != NULL) 467 free($4); 468 } 469 | NLST check_login CRLF 470 { 471 if ($2) 472 send_file_list("."); 473 } 474 | NLST check_login SP STRING CRLF 475 { 476 if ($2 && $4 != NULL) 477 send_file_list($4); 478 if ($4 != NULL) 479 free($4); 480 } 481 | LIST check_login CRLF 482 { 483 if ($2) 484 retrieve("/bin/ls -lgA", ""); 485 } 486 | LIST check_login SP pathstring CRLF 487 { 488 if ($2 && $4 != NULL) 489 retrieve("/bin/ls -lgA %s", $4); 490 if ($4 != NULL) 491 free($4); 492 } 493 | STAT check_login SP pathname CRLF 494 { 495 if ($2 && $4 != NULL) 496 statfilecmd($4); 497 if ($4 != NULL) 498 free($4); 499 } 500 | STAT check_login CRLF 501 { 502 if ($2) { 503 statcmd(); 504 } 505 } 506 | DELE check_login_ro SP pathname CRLF 507 { 508 if ($2 && $4 != NULL) 509 delete($4); 510 if ($4 != NULL) 511 free($4); 512 } 513 | RNTO check_login_ro SP pathname CRLF 514 { 515 if ($2) { 516 if (fromname) { 517 renamecmd(fromname, $4); 518 free(fromname); 519 fromname = (char *) 0; 520 } else { 521 reply(503, "Bad sequence of commands."); 522 } 523 } 524 free($4); 525 } 526 | ABOR check_login CRLF 527 { 528 if ($2) 529 reply(225, "ABOR command successful."); 530 } 531 | CWD check_login CRLF 532 { 533 if ($2) { 534 if (guest) 535 cwd("/"); 536 else 537 cwd(pw->pw_dir); 538 } 539 } 540 | CWD check_login SP pathname CRLF 541 { 542 if ($2 && $4 != NULL) 543 cwd($4); 544 if ($4 != NULL) 545 free($4); 546 } 547 | HELP CRLF 548 { 549 help(cmdtab, (char *) 0); 550 } 551 | HELP SP STRING CRLF 552 { 553 char *cp = $3; 554 555 if (strncasecmp(cp, "SITE", 4) == 0) { 556 cp = $3 + 4; 557 if (*cp == ' ') 558 cp++; 559 if (*cp) 560 help(sitetab, cp); 561 else 562 help(sitetab, (char *) 0); 563 } else 564 help(cmdtab, $3); 565 free($3); 566 } 567 | NOOP CRLF 568 { 569 reply(200, "NOOP command successful."); 570 } 571 | MKD check_login_ro SP pathname CRLF 572 { 573 if ($2 && $4 != NULL) 574 makedir($4); 575 if ($4 != NULL) 576 free($4); 577 } 578 | RMD check_login_ro SP pathname CRLF 579 { 580 if ($2 && $4 != NULL) 581 removedir($4); 582 if ($4 != NULL) 583 free($4); 584 } 585 | PWD check_login CRLF 586 { 587 if ($2) 588 pwd(); 589 } 590 | CDUP check_login CRLF 591 { 592 if ($2) 593 cwd(".."); 594 } 595 | SITE SP HELP CRLF 596 { 597 help(sitetab, (char *) 0); 598 } 599 | SITE SP HELP SP STRING CRLF 600 { 601 help(sitetab, $5); 602 free($5); 603 } 604 | SITE SP MDFIVE check_login SP pathname CRLF 605 { 606 char p[64], *q; 607 608 if ($4) { 609 q = MD5File($6, p); 610 if (q != NULL) 611 reply(200, "MD5(%s) = %s", $6, p); 612 else 613 perror_reply(550, $6); 614 } 615 if ($6) 616 free($6); 617 } 618 | SITE SP UMASK check_login CRLF 619 { 620 int oldmask; 621 622 if ($4) { 623 oldmask = umask(0); 624 (void) umask(oldmask); 625 reply(200, "Current UMASK is %03o", oldmask); 626 } 627 } 628 | SITE SP UMASK check_login SP octal_number CRLF 629 { 630 int oldmask; 631 632 if ($4) { 633 if (($6 == -1) || ($6 > 0777)) { 634 reply(501, "Bad UMASK value"); 635 } else { 636 oldmask = umask($6); 637 reply(200, 638 "UMASK set to %03o (was %03o)", 639 $6, oldmask); 640 } 641 } 642 } 643 | SITE SP CHMOD check_login_ro SP octal_number SP pathname CRLF 644 { 645 if ($4 && ($8 != NULL)) { 646 if ($6 > 0777) 647 reply(501, 648 "CHMOD: Mode value must be between 0 and 0777"); 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 < 30 || $6 > maxtimeout) { 668 reply(501, 669 "Maximum IDLE time must be between 30 and %d seconds", 670 maxtimeout); 671 } else { 672 timeout = $6; 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 }
| 104char cbuf[512]; 105char *fromname = (char *) 0; 106 107extern int epsvall; 108 109%} 110 111%union { 112 int i; 113 char *s; 114} 115 116%token 117 A B C E F I 118 L N P R S T 119 ALL 120 121 SP CRLF COMMA 122 123 USER PASS ACCT REIN QUIT PORT 124 PASV TYPE STRU MODE RETR STOR 125 APPE MLFL MAIL MSND MSOM MSAM 126 MRSQ MRCP ALLO REST RNFR RNTO 127 ABOR DELE CWD LIST NLST SITE 128 STAT HELP NOOP MKD RMD PWD 129 CDUP STOU SMNT SYST SIZE MDTM 130 LPRT LPSV EPRT EPSV 131 132 UMASK IDLE CHMOD MDFIVE 133 134 LEXERR 135 136%token <s> STRING 137%token <i> NUMBER 138 139%type <i> check_login octal_number byte_size 140%type <i> check_login_ro octal_number byte_size 141%type <i> check_login_epsv octal_number byte_size 142%type <i> struct_code mode_code type_code form_code 143%type <s> pathstring pathname password username 144%type <s> ALL 145 146%start cmd_list 147 148%% 149 150cmd_list 151 : /* empty */ 152 | cmd_list cmd 153 { 154 if (fromname) 155 free(fromname); 156 fromname = (char *) 0; 157 restart_point = (off_t) 0; 158 } 159 | cmd_list rcmd 160 ; 161 162cmd 163 : USER SP username CRLF 164 { 165 user($3); 166 free($3); 167 } 168 | PASS SP password CRLF 169 { 170 pass($3); 171 free($3); 172 } 173 | PASS CRLF 174 { 175 pass(""); 176 } 177 | PORT check_login SP host_port CRLF 178 { 179 if (epsvall) { 180 reply(501, "no PORT allowed after EPSV ALL"); 181 goto port_done; 182 } 183 if (!$2) 184 goto port_done; 185 if (port_check("PORT") == 1) 186 goto port_done; 187#ifdef INET6 188 if ((his_addr.su_family != AF_INET6 || 189 !IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr))) { 190 /* shoud never happen */ 191 usedefault = 1; 192 reply(500, "Invalid address rejected."); 193 goto port_done; 194 } 195 port_check_v6("pcmd"); 196#endif 197 port_done: 198 } 199 | LPRT check_login SP host_long_port CRLF 200 { 201 if (epsvall) { 202 reply(501, "no LPRT allowed after EPSV ALL"); 203 goto lprt_done; 204 } 205 if (!$2) 206 goto lprt_done; 207 if (port_check("LPRT") == 1) 208 goto lprt_done; 209#ifdef INET6 210 if (his_addr.su_family != AF_INET6) { 211 usedefault = 1; 212 reply(500, "Invalid address rejected."); 213 goto lprt_done; 214 } 215 if (port_check_v6("LPRT") == 1) 216 goto lprt_done; 217#endif 218 lprt_done: 219 } 220 | EPRT check_login SP STRING CRLF 221 { 222 char delim; 223 char *tmp = NULL; 224 char *p, *q; 225 char *result[3]; 226 struct addrinfo hints; 227 struct addrinfo *res; 228 int i; 229 230 if (epsvall) { 231 reply(501, "no EPRT allowed after EPSV ALL"); 232 goto eprt_done; 233 } 234 if (!$2) 235 goto eprt_done; 236 237 memset(&data_dest, 0, sizeof(data_dest)); 238 tmp = strdup($4); 239 if (ftpdebug) 240 syslog(LOG_DEBUG, "%s", tmp); 241 if (!tmp) { 242 fatalerror("not enough core"); 243 /*NOTREACHED*/ 244 } 245 p = tmp; 246 delim = p[0]; 247 p++; 248 memset(result, 0, sizeof(result)); 249 for (i = 0; i < 3; i++) { 250 q = strchr(p, delim); 251 if (!q || *q != delim) { 252 parsefail: 253 reply(500, 254 "Invalid argument, rejected."); 255 if (tmp) 256 free(tmp); 257 usedefault = 1; 258 goto eprt_done; 259 } 260 *q++ = '\0'; 261 result[i] = p; 262 if (ftpdebug) 263 syslog(LOG_DEBUG, "%d: %s", i, p); 264 p = q; 265 } 266 267 /* some more sanity check */ 268 p = result[0]; 269 while (*p) { 270 if (!isdigit(*p)) 271 goto parsefail; 272 p++; 273 } 274 p = result[2]; 275 while (*p) { 276 if (!isdigit(*p)) 277 goto parsefail; 278 p++; 279 } 280 281 /* grab address */ 282 memset(&hints, 0, sizeof(hints)); 283 if (atoi(result[0]) == 1) 284 hints.ai_family = PF_INET; 285#ifdef INET6 286 else if (atoi(result[0]) == 2) 287 hints.ai_family = PF_INET6; 288#endif 289 else 290 hints.ai_family = PF_UNSPEC; /*XXX*/ 291 hints.ai_socktype = SOCK_STREAM; 292 i = getaddrinfo(result[1], result[2], &hints, &res); 293 if (i) 294 goto parsefail; 295 memcpy(&data_dest, res->ai_addr, res->ai_addrlen); 296#ifdef INET6 297 if (his_addr.su_family == AF_INET6 298 && data_dest.su_family == AF_INET6) { 299 /* XXX more sanity checks! */ 300 data_dest.su_sin6.sin6_scope_id = 301 his_addr.su_sin6.sin6_scope_id; 302 } 303#endif 304 free(tmp); 305 tmp = NULL; 306 307 if (port_check("EPRT") == 1) 308 goto eprt_done; 309#ifdef INET6 310 if (his_addr.su_family != AF_INET6) { 311 usedefault = 1; 312 reply(500, "Invalid address rejected."); 313 goto eprt_done; 314 } 315 if (port_check_v6("EPRT") == 1) 316 goto eprt_done; 317#endif 318 eprt_done: 319 free($4); 320 } 321 | PASV check_login CRLF 322 { 323 if (epsvall) 324 reply(501, "no PASV allowed after EPSV ALL"); 325 else if ($2) 326 passive(); 327 } 328 | LPSV check_login CRLF 329 { 330 if (epsvall) 331 reply(501, "no LPSV allowed after EPSV ALL"); 332 else if ($2) 333 long_passive("LPSV", PF_UNSPEC); 334 } 335 | EPSV check_login_epsv SP NUMBER CRLF 336 { 337 if ($2) { 338 int pf; 339 switch ($4) { 340 case 1: 341 pf = PF_INET; 342 break; 343#ifdef INET6 344 case 2: 345 pf = PF_INET6; 346 break; 347#endif 348 default: 349 pf = -1; /*junk value*/ 350 break; 351 } 352 long_passive("EPSV", pf); 353 } 354 } 355 | EPSV check_login_epsv SP ALL CRLF 356 { 357 if ($2) { 358 reply(200, 359 "EPSV ALL command successful."); 360 epsvall++; 361 } 362 } 363 | EPSV check_login_epsv CRLF 364 { 365 if ($2) 366 long_passive("EPSV", PF_UNSPEC); 367 } 368 | TYPE check_login SP type_code CRLF 369 { 370 if ($2) { 371 switch (cmd_type) { 372 373 case TYPE_A: 374 if (cmd_form == FORM_N) { 375 reply(200, "Type set to A."); 376 type = cmd_type; 377 form = cmd_form; 378 } else 379 reply(504, "Form must be N."); 380 break; 381 382 case TYPE_E: 383 reply(504, "Type E not implemented."); 384 break; 385 386 case TYPE_I: 387 reply(200, "Type set to I."); 388 type = cmd_type; 389 break; 390 391 case TYPE_L: 392#if NBBY == 8 393 if (cmd_bytesz == 8) { 394 reply(200, 395 "Type set to L (byte size 8)."); 396 type = cmd_type; 397 } else 398 reply(504, "Byte size must be 8."); 399#else /* NBBY == 8 */ 400 UNIMPLEMENTED for NBBY != 8 401#endif /* NBBY == 8 */ 402 } 403 } 404 } 405 | STRU check_login SP struct_code CRLF 406 { 407 if ($2) { 408 switch ($4) { 409 410 case STRU_F: 411 reply(200, "STRU F ok."); 412 break; 413 414 default: 415 reply(504, "Unimplemented STRU type."); 416 } 417 } 418 } 419 | MODE check_login SP mode_code CRLF 420 { 421 if ($2) { 422 switch ($4) { 423 424 case MODE_S: 425 reply(200, "MODE S ok."); 426 break; 427 428 default: 429 reply(502, "Unimplemented MODE type."); 430 } 431 } 432 } 433 | ALLO check_login SP NUMBER CRLF 434 { 435 if ($2) { 436 reply(202, "ALLO command ignored."); 437 } 438 } 439 | ALLO check_login SP NUMBER SP R SP NUMBER CRLF 440 { 441 if ($2) { 442 reply(202, "ALLO command ignored."); 443 } 444 } 445 | RETR check_login SP pathname CRLF 446 { 447 if (noretr || (guest && noguestretr)) 448 reply(500, "RETR command is disabled"); 449 else if ($2 && $4 != NULL) 450 retrieve((char *) 0, $4); 451 452 if ($4 != NULL) 453 free($4); 454 } 455 | STOR check_login_ro SP pathname CRLF 456 { 457 if ($2 && $4 != NULL) 458 store($4, "w", 0); 459 if ($4 != NULL) 460 free($4); 461 } 462 | APPE check_login_ro SP pathname CRLF 463 { 464 if ($2 && $4 != NULL) 465 store($4, "a", 0); 466 if ($4 != NULL) 467 free($4); 468 } 469 | NLST check_login CRLF 470 { 471 if ($2) 472 send_file_list("."); 473 } 474 | NLST check_login SP STRING CRLF 475 { 476 if ($2 && $4 != NULL) 477 send_file_list($4); 478 if ($4 != NULL) 479 free($4); 480 } 481 | LIST check_login CRLF 482 { 483 if ($2) 484 retrieve("/bin/ls -lgA", ""); 485 } 486 | LIST check_login SP pathstring CRLF 487 { 488 if ($2 && $4 != NULL) 489 retrieve("/bin/ls -lgA %s", $4); 490 if ($4 != NULL) 491 free($4); 492 } 493 | STAT check_login SP pathname CRLF 494 { 495 if ($2 && $4 != NULL) 496 statfilecmd($4); 497 if ($4 != NULL) 498 free($4); 499 } 500 | STAT check_login CRLF 501 { 502 if ($2) { 503 statcmd(); 504 } 505 } 506 | DELE check_login_ro SP pathname CRLF 507 { 508 if ($2 && $4 != NULL) 509 delete($4); 510 if ($4 != NULL) 511 free($4); 512 } 513 | RNTO check_login_ro SP pathname CRLF 514 { 515 if ($2) { 516 if (fromname) { 517 renamecmd(fromname, $4); 518 free(fromname); 519 fromname = (char *) 0; 520 } else { 521 reply(503, "Bad sequence of commands."); 522 } 523 } 524 free($4); 525 } 526 | ABOR check_login CRLF 527 { 528 if ($2) 529 reply(225, "ABOR command successful."); 530 } 531 | CWD check_login CRLF 532 { 533 if ($2) { 534 if (guest) 535 cwd("/"); 536 else 537 cwd(pw->pw_dir); 538 } 539 } 540 | CWD check_login SP pathname CRLF 541 { 542 if ($2 && $4 != NULL) 543 cwd($4); 544 if ($4 != NULL) 545 free($4); 546 } 547 | HELP CRLF 548 { 549 help(cmdtab, (char *) 0); 550 } 551 | HELP SP STRING CRLF 552 { 553 char *cp = $3; 554 555 if (strncasecmp(cp, "SITE", 4) == 0) { 556 cp = $3 + 4; 557 if (*cp == ' ') 558 cp++; 559 if (*cp) 560 help(sitetab, cp); 561 else 562 help(sitetab, (char *) 0); 563 } else 564 help(cmdtab, $3); 565 free($3); 566 } 567 | NOOP CRLF 568 { 569 reply(200, "NOOP command successful."); 570 } 571 | MKD check_login_ro SP pathname CRLF 572 { 573 if ($2 && $4 != NULL) 574 makedir($4); 575 if ($4 != NULL) 576 free($4); 577 } 578 | RMD check_login_ro SP pathname CRLF 579 { 580 if ($2 && $4 != NULL) 581 removedir($4); 582 if ($4 != NULL) 583 free($4); 584 } 585 | PWD check_login CRLF 586 { 587 if ($2) 588 pwd(); 589 } 590 | CDUP check_login CRLF 591 { 592 if ($2) 593 cwd(".."); 594 } 595 | SITE SP HELP CRLF 596 { 597 help(sitetab, (char *) 0); 598 } 599 | SITE SP HELP SP STRING CRLF 600 { 601 help(sitetab, $5); 602 free($5); 603 } 604 | SITE SP MDFIVE check_login SP pathname CRLF 605 { 606 char p[64], *q; 607 608 if ($4) { 609 q = MD5File($6, p); 610 if (q != NULL) 611 reply(200, "MD5(%s) = %s", $6, p); 612 else 613 perror_reply(550, $6); 614 } 615 if ($6) 616 free($6); 617 } 618 | SITE SP UMASK check_login CRLF 619 { 620 int oldmask; 621 622 if ($4) { 623 oldmask = umask(0); 624 (void) umask(oldmask); 625 reply(200, "Current UMASK is %03o", oldmask); 626 } 627 } 628 | SITE SP UMASK check_login SP octal_number CRLF 629 { 630 int oldmask; 631 632 if ($4) { 633 if (($6 == -1) || ($6 > 0777)) { 634 reply(501, "Bad UMASK value"); 635 } else { 636 oldmask = umask($6); 637 reply(200, 638 "UMASK set to %03o (was %03o)", 639 $6, oldmask); 640 } 641 } 642 } 643 | SITE SP CHMOD check_login_ro SP octal_number SP pathname CRLF 644 { 645 if ($4 && ($8 != NULL)) { 646 if ($6 > 0777) 647 reply(501, 648 "CHMOD: Mode value must be between 0 and 0777"); 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 < 30 || $6 > maxtimeout) { 668 reply(501, 669 "Maximum IDLE time must be between 30 and %d seconds", 670 maxtimeout); 671 } else { 672 timeout = $6; 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 }
|
1052#define CMD 0 /* beginning of command */ 1053#define ARGS 1 /* expect miscellaneous arguments */ 1054#define STR1 2 /* expect SP followed by STRING */ 1055#define STR2 3 /* expect STRING */ 1056#define OSTR 4 /* optional SP then STRING */ 1057#define ZSTR1 5 /* optional SP then optional STRING */ 1058#define ZSTR2 6 /* optional STRING after SP */ 1059#define SITECMD 7 /* SITE command */ 1060#define NSTR 8 /* Number followed by a string */ 1061 1062#define MAXGLOBARGS 1000 1063 1064struct tab { 1065 char *name; 1066 short token; 1067 short state; 1068 short implemented; /* 1 if command is implemented */ 1069 char *help; 1070}; 1071 1072struct tab cmdtab[] = { /* In order defined in RFC 765 */ 1073 { "USER", USER, STR1, 1, "<sp> username" }, 1074 { "PASS", PASS, ZSTR1, 1, "[<sp> [password]]" }, 1075 { "ACCT", ACCT, STR1, 0, "(specify account)" }, 1076 { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, 1077 { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, 1078 { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, 1079 { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" }, 1080 { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." }, 1081 { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" }, 1082 { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, 1083 { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, 1084 { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" }, 1085 { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" }, 1086 { "STRU", STRU, ARGS, 1, "(specify file structure)" }, 1087 { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, 1088 { "RETR", RETR, STR1, 1, "<sp> file-name" }, 1089 { "STOR", STOR, STR1, 1, "<sp> file-name" }, 1090 { "APPE", APPE, STR1, 1, "<sp> file-name" }, 1091 { "MLFL", MLFL, OSTR, 0, "(mail file)" }, 1092 { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, 1093 { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, 1094 { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, 1095 { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, 1096 { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, 1097 { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, 1098 { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, 1099 { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, 1100 { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, 1101 { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, 1102 { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, 1103 { "DELE", DELE, STR1, 1, "<sp> file-name" }, 1104 { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1105 { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1106 { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, 1107 { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, 1108 { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, 1109 { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, 1110 { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, 1111 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1112 { "NOOP", NOOP, ARGS, 1, "" }, 1113 { "MKD", MKD, STR1, 1, "<sp> path-name" }, 1114 { "XMKD", MKD, STR1, 1, "<sp> path-name" }, 1115 { "RMD", RMD, STR1, 1, "<sp> path-name" }, 1116 { "XRMD", RMD, STR1, 1, "<sp> path-name" }, 1117 { "PWD", PWD, ARGS, 1, "(return current directory)" }, 1118 { "XPWD", PWD, ARGS, 1, "(return current directory)" }, 1119 { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1120 { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1121 { "STOU", STOU, STR1, 1, "<sp> file-name" }, 1122 { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, 1123 { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, 1124 { NULL, 0, 0, 0, 0 } 1125}; 1126 1127struct tab sitetab[] = { 1128 { "MD5", MDFIVE, STR1, 1, "[ <sp> file-name ]" }, 1129 { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, 1130 { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, 1131 { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, 1132 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1133 { NULL, 0, 0, 0, 0 } 1134}; 1135 1136static char *copy __P((char *)); 1137static void help __P((struct tab *, char *)); 1138static struct tab * 1139 lookup __P((struct tab *, char *)); 1140static int port_check __P((const char *)); 1141static int port_check_v6 __P((const char *)); 1142static void sizecmd __P((char *)); 1143static void toolong __P((int)); 1144static void v4map_data_dest __P((void)); 1145static int yylex __P((void)); 1146 1147static struct tab * 1148lookup(p, cmd) 1149 struct tab *p; 1150 char *cmd; 1151{ 1152 1153 for (; p->name != NULL; p++) 1154 if (strcmp(cmd, p->name) == 0) 1155 return (p); 1156 return (0); 1157} 1158 1159#include <arpa/telnet.h> 1160 1161/* 1162 * getline - a hacked up version of fgets to ignore TELNET escape codes. 1163 */ 1164char * 1165getline(s, n, iop) 1166 char *s; 1167 int n; 1168 FILE *iop; 1169{ 1170 int c; 1171 register char *cs; 1172 1173 cs = s; 1174/* tmpline may contain saved command from urgent mode interruption */ 1175 for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 1176 *cs++ = tmpline[c]; 1177 if (tmpline[c] == '\n') { 1178 *cs++ = '\0'; 1179 if (ftpdebug) 1180 syslog(LOG_DEBUG, "command: %s", s); 1181 tmpline[0] = '\0'; 1182 return(s); 1183 } 1184 if (c == 0) 1185 tmpline[0] = '\0'; 1186 } 1187 while ((c = getc(iop)) != EOF) { 1188 c &= 0377; 1189 if (c == IAC) { 1190 if ((c = getc(iop)) != EOF) { 1191 c &= 0377; 1192 switch (c) { 1193 case WILL: 1194 case WONT: 1195 c = getc(iop); 1196 printf("%c%c%c", IAC, DONT, 0377&c); 1197 (void) fflush(stdout); 1198 continue; 1199 case DO: 1200 case DONT: 1201 c = getc(iop); 1202 printf("%c%c%c", IAC, WONT, 0377&c); 1203 (void) fflush(stdout); 1204 continue; 1205 case IAC: 1206 break; 1207 default: 1208 continue; /* ignore command */ 1209 } 1210 } 1211 } 1212 *cs++ = c; 1213 if (--n <= 0 || c == '\n') 1214 break; 1215 } 1216 if (c == EOF && cs == s) 1217 return (NULL); 1218 *cs++ = '\0'; 1219 if (ftpdebug) { 1220 if (!guest && strncasecmp("pass ", s, 5) == 0) { 1221 /* Don't syslog passwords */ 1222 syslog(LOG_DEBUG, "command: %.5s ???", s); 1223 } else { 1224 register char *cp; 1225 register int len; 1226 1227 /* Don't syslog trailing CR-LF */ 1228 len = strlen(s); 1229 cp = s + len - 1; 1230 while (cp >= s && (*cp == '\n' || *cp == '\r')) { 1231 --cp; 1232 --len; 1233 } 1234 syslog(LOG_DEBUG, "command: %.*s", len, s); 1235 } 1236 } 1237 return (s); 1238} 1239 1240static void 1241toolong(signo) 1242 int signo; 1243{ 1244 1245 reply(421, 1246 "Timeout (%d seconds): closing control connection.", timeout); 1247 if (logging) 1248 syslog(LOG_INFO, "User %s timed out after %d seconds", 1249 (pw ? pw -> pw_name : "unknown"), timeout); 1250 dologout(1); 1251} 1252 1253static int 1254yylex() 1255{
| 1052#define CMD 0 /* beginning of command */ 1053#define ARGS 1 /* expect miscellaneous arguments */ 1054#define STR1 2 /* expect SP followed by STRING */ 1055#define STR2 3 /* expect STRING */ 1056#define OSTR 4 /* optional SP then STRING */ 1057#define ZSTR1 5 /* optional SP then optional STRING */ 1058#define ZSTR2 6 /* optional STRING after SP */ 1059#define SITECMD 7 /* SITE command */ 1060#define NSTR 8 /* Number followed by a string */ 1061 1062#define MAXGLOBARGS 1000 1063 1064struct tab { 1065 char *name; 1066 short token; 1067 short state; 1068 short implemented; /* 1 if command is implemented */ 1069 char *help; 1070}; 1071 1072struct tab cmdtab[] = { /* In order defined in RFC 765 */ 1073 { "USER", USER, STR1, 1, "<sp> username" }, 1074 { "PASS", PASS, ZSTR1, 1, "[<sp> [password]]" }, 1075 { "ACCT", ACCT, STR1, 0, "(specify account)" }, 1076 { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, 1077 { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, 1078 { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, 1079 { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" }, 1080 { "LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, h3,..., pal, p1, p2..." }, 1081 { "EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|" }, 1082 { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, 1083 { "LPSV", LPSV, ARGS, 1, "(set server in passive mode)" }, 1084 { "EPSV", EPSV, ARGS, 1, "[<sp> af|ALL]" }, 1085 { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" }, 1086 { "STRU", STRU, ARGS, 1, "(specify file structure)" }, 1087 { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, 1088 { "RETR", RETR, STR1, 1, "<sp> file-name" }, 1089 { "STOR", STOR, STR1, 1, "<sp> file-name" }, 1090 { "APPE", APPE, STR1, 1, "<sp> file-name" }, 1091 { "MLFL", MLFL, OSTR, 0, "(mail file)" }, 1092 { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, 1093 { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, 1094 { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, 1095 { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, 1096 { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, 1097 { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, 1098 { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, 1099 { "REST", REST, ARGS, 1, "<sp> offset (restart command)" }, 1100 { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, 1101 { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, 1102 { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, 1103 { "DELE", DELE, STR1, 1, "<sp> file-name" }, 1104 { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1105 { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, 1106 { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, 1107 { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, 1108 { "SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]" }, 1109 { "SYST", SYST, ARGS, 1, "(get type of operating system)" }, 1110 { "STAT", STAT, OSTR, 1, "[ <sp> path-name ]" }, 1111 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1112 { "NOOP", NOOP, ARGS, 1, "" }, 1113 { "MKD", MKD, STR1, 1, "<sp> path-name" }, 1114 { "XMKD", MKD, STR1, 1, "<sp> path-name" }, 1115 { "RMD", RMD, STR1, 1, "<sp> path-name" }, 1116 { "XRMD", RMD, STR1, 1, "<sp> path-name" }, 1117 { "PWD", PWD, ARGS, 1, "(return current directory)" }, 1118 { "XPWD", PWD, ARGS, 1, "(return current directory)" }, 1119 { "CDUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1120 { "XCUP", CDUP, ARGS, 1, "(change to parent directory)" }, 1121 { "STOU", STOU, STR1, 1, "<sp> file-name" }, 1122 { "SIZE", SIZE, OSTR, 1, "<sp> path-name" }, 1123 { "MDTM", MDTM, OSTR, 1, "<sp> path-name" }, 1124 { NULL, 0, 0, 0, 0 } 1125}; 1126 1127struct tab sitetab[] = { 1128 { "MD5", MDFIVE, STR1, 1, "[ <sp> file-name ]" }, 1129 { "UMASK", UMASK, ARGS, 1, "[ <sp> umask ]" }, 1130 { "IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]" }, 1131 { "CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name" }, 1132 { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, 1133 { NULL, 0, 0, 0, 0 } 1134}; 1135 1136static char *copy __P((char *)); 1137static void help __P((struct tab *, char *)); 1138static struct tab * 1139 lookup __P((struct tab *, char *)); 1140static int port_check __P((const char *)); 1141static int port_check_v6 __P((const char *)); 1142static void sizecmd __P((char *)); 1143static void toolong __P((int)); 1144static void v4map_data_dest __P((void)); 1145static int yylex __P((void)); 1146 1147static struct tab * 1148lookup(p, cmd) 1149 struct tab *p; 1150 char *cmd; 1151{ 1152 1153 for (; p->name != NULL; p++) 1154 if (strcmp(cmd, p->name) == 0) 1155 return (p); 1156 return (0); 1157} 1158 1159#include <arpa/telnet.h> 1160 1161/* 1162 * getline - a hacked up version of fgets to ignore TELNET escape codes. 1163 */ 1164char * 1165getline(s, n, iop) 1166 char *s; 1167 int n; 1168 FILE *iop; 1169{ 1170 int c; 1171 register char *cs; 1172 1173 cs = s; 1174/* tmpline may contain saved command from urgent mode interruption */ 1175 for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 1176 *cs++ = tmpline[c]; 1177 if (tmpline[c] == '\n') { 1178 *cs++ = '\0'; 1179 if (ftpdebug) 1180 syslog(LOG_DEBUG, "command: %s", s); 1181 tmpline[0] = '\0'; 1182 return(s); 1183 } 1184 if (c == 0) 1185 tmpline[0] = '\0'; 1186 } 1187 while ((c = getc(iop)) != EOF) { 1188 c &= 0377; 1189 if (c == IAC) { 1190 if ((c = getc(iop)) != EOF) { 1191 c &= 0377; 1192 switch (c) { 1193 case WILL: 1194 case WONT: 1195 c = getc(iop); 1196 printf("%c%c%c", IAC, DONT, 0377&c); 1197 (void) fflush(stdout); 1198 continue; 1199 case DO: 1200 case DONT: 1201 c = getc(iop); 1202 printf("%c%c%c", IAC, WONT, 0377&c); 1203 (void) fflush(stdout); 1204 continue; 1205 case IAC: 1206 break; 1207 default: 1208 continue; /* ignore command */ 1209 } 1210 } 1211 } 1212 *cs++ = c; 1213 if (--n <= 0 || c == '\n') 1214 break; 1215 } 1216 if (c == EOF && cs == s) 1217 return (NULL); 1218 *cs++ = '\0'; 1219 if (ftpdebug) { 1220 if (!guest && strncasecmp("pass ", s, 5) == 0) { 1221 /* Don't syslog passwords */ 1222 syslog(LOG_DEBUG, "command: %.5s ???", s); 1223 } else { 1224 register char *cp; 1225 register int len; 1226 1227 /* Don't syslog trailing CR-LF */ 1228 len = strlen(s); 1229 cp = s + len - 1; 1230 while (cp >= s && (*cp == '\n' || *cp == '\r')) { 1231 --cp; 1232 --len; 1233 } 1234 syslog(LOG_DEBUG, "command: %.*s", len, s); 1235 } 1236 } 1237 return (s); 1238} 1239 1240static void 1241toolong(signo) 1242 int signo; 1243{ 1244 1245 reply(421, 1246 "Timeout (%d seconds): closing control connection.", timeout); 1247 if (logging) 1248 syslog(LOG_INFO, "User %s timed out after %d seconds", 1249 (pw ? pw -> pw_name : "unknown"), timeout); 1250 dologout(1); 1251} 1252 1253static int 1254yylex() 1255{
|
1473 } 1474} 1475 1476void 1477upper(s) 1478 char *s; 1479{ 1480 while (*s != '\0') { 1481 if (islower(*s)) 1482 *s = toupper(*s); 1483 s++; 1484 } 1485} 1486 1487static char * 1488copy(s) 1489 char *s; 1490{ 1491 char *p; 1492 1493 p = malloc((unsigned) strlen(s) + 1); 1494 if (p == NULL) 1495 fatalerror("Ran out of memory."); 1496 (void) strcpy(p, s); 1497 return (p); 1498} 1499 1500static void 1501help(ctab, s) 1502 struct tab *ctab; 1503 char *s; 1504{ 1505 struct tab *c; 1506 int width, NCMDS; 1507 char *type; 1508 1509 if (ctab == sitetab) 1510 type = "SITE "; 1511 else 1512 type = ""; 1513 width = 0, NCMDS = 0; 1514 for (c = ctab; c->name != NULL; c++) { 1515 int len = strlen(c->name); 1516 1517 if (len > width) 1518 width = len; 1519 NCMDS++; 1520 } 1521 width = (width + 8) &~ 7; 1522 if (s == 0) { 1523 int i, j, w; 1524 int columns, lines; 1525 1526 lreply(214, "The following %scommands are recognized %s.", 1527 type, "(* =>'s unimplemented)"); 1528 columns = 76 / width; 1529 if (columns == 0) 1530 columns = 1; 1531 lines = (NCMDS + columns - 1) / columns; 1532 for (i = 0; i < lines; i++) { 1533 printf(" "); 1534 for (j = 0; j < columns; j++) { 1535 c = ctab + j * lines + i; 1536 printf("%s%c", c->name, 1537 c->implemented ? ' ' : '*'); 1538 if (c + lines >= &ctab[NCMDS]) 1539 break; 1540 w = strlen(c->name) + 1; 1541 while (w < width) { 1542 putchar(' '); 1543 w++; 1544 } 1545 } 1546 printf("\r\n"); 1547 } 1548 (void) fflush(stdout); 1549 reply(214, "Direct comments to ftp-bugs@%s.", hostname); 1550 return; 1551 } 1552 upper(s); 1553 c = lookup(ctab, s); 1554 if (c == (struct tab *)0) { 1555 reply(502, "Unknown command %s.", s); 1556 return; 1557 } 1558 if (c->implemented) 1559 reply(214, "Syntax: %s%s %s", type, c->name, c->help); 1560 else 1561 reply(214, "%s%-*s\t%s; unimplemented.", type, width, 1562 c->name, c->help); 1563} 1564 1565static void 1566sizecmd(filename) 1567 char *filename; 1568{ 1569 switch (type) { 1570 case TYPE_L: 1571 case TYPE_I: { 1572 struct stat stbuf; 1573 if (stat(filename, &stbuf) < 0) 1574 perror_reply(550, filename); 1575 else if (!S_ISREG(stbuf.st_mode)) 1576 reply(550, "%s: not a plain file.", filename); 1577 else 1578 reply(213, "%qu", stbuf.st_size); 1579 break; } 1580 case TYPE_A: { 1581 FILE *fin; 1582 int c; 1583 off_t count; 1584 struct stat stbuf; 1585 fin = fopen(filename, "r"); 1586 if (fin == NULL) { 1587 perror_reply(550, filename); 1588 return; 1589 } 1590 if (fstat(fileno(fin), &stbuf) < 0) { 1591 perror_reply(550, filename); 1592 (void) fclose(fin); 1593 return; 1594 } else if (!S_ISREG(stbuf.st_mode)) { 1595 reply(550, "%s: not a plain file.", filename); 1596 (void) fclose(fin); 1597 return; 1598 } 1599 1600 count = 0; 1601 while((c=getc(fin)) != EOF) { 1602 if (c == '\n') /* will get expanded to \r\n */ 1603 count++; 1604 count++; 1605 } 1606 (void) fclose(fin); 1607 1608 reply(213, "%qd", count); 1609 break; } 1610 default: 1611 reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); 1612 } 1613} 1614 1615/* Return 1, if port check is done. Return 0, if not yet. */ 1616static int 1617port_check(pcmd) 1618 const char *pcmd; 1619{ 1620 if (his_addr.su_family == AF_INET) { 1621 if (data_dest.su_family != AF_INET) { 1622 usedefault = 1; 1623 reply(500, "Invalid address rejected."); 1624 return 1; 1625 } 1626 if (paranoid && 1627 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1628 memcmp(&data_dest.su_sin.sin_addr, 1629 &his_addr.su_sin.sin_addr, 1630 sizeof(data_dest.su_sin.sin_addr)))) { 1631 usedefault = 1; 1632 reply(500, "Illegal PORT range rejected."); 1633 } else { 1634 usedefault = 0; 1635 if (pdata >= 0) { 1636 (void) close(pdata); 1637 pdata = -1; 1638 } 1639 reply(200, "%s command successful.", pcmd); 1640 } 1641 return 1; 1642 } 1643 return 0; 1644} 1645 1646static int 1647check_login1() 1648{ 1649 if (logged_in) 1650 return 1; 1651 else { 1652 reply(530, "Please login with USER and PASS."); 1653 return 0; 1654 } 1655} 1656 1657#ifdef INET6 1658/* Return 1, if port check is done. Return 0, if not yet. */ 1659static int 1660port_check_v6(pcmd) 1661 const char *pcmd; 1662{ 1663 if (his_addr.su_family == AF_INET6) { 1664 if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) 1665 /* Convert data_dest into v4 mapped sockaddr.*/ 1666 v4map_data_dest(); 1667 if (data_dest.su_family != AF_INET6) { 1668 usedefault = 1; 1669 reply(500, "Invalid address rejected."); 1670 return 1; 1671 } 1672 if (paranoid && 1673 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1674 memcmp(&data_dest.su_sin6.sin6_addr, 1675 &his_addr.su_sin6.sin6_addr, 1676 sizeof(data_dest.su_sin6.sin6_addr)))) { 1677 usedefault = 1; 1678 reply(500, "Illegal PORT range rejected."); 1679 } else { 1680 usedefault = 0; 1681 if (pdata >= 0) { 1682 (void) close(pdata); 1683 pdata = -1; 1684 } 1685 reply(200, "%s command successful.", pcmd); 1686 } 1687 return 1; 1688 } 1689 return 0; 1690} 1691 1692static void 1693v4map_data_dest() 1694{ 1695 struct in_addr savedaddr; 1696 int savedport; 1697 1698 if (data_dest.su_family != AF_INET) { 1699 usedefault = 1; 1700 reply(500, "Invalid address rejected."); 1701 return; 1702 } 1703 1704 savedaddr = data_dest.su_sin.sin_addr; 1705 savedport = data_dest.su_port; 1706 1707 memset(&data_dest, 0, sizeof(data_dest)); 1708 data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6); 1709 data_dest.su_sin6.sin6_family = AF_INET6; 1710 data_dest.su_sin6.sin6_port = savedport; 1711 memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2); 1712 memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12], 1713 (caddr_t)&savedaddr, sizeof(savedaddr)); 1714} 1715#endif
| 1470 } 1471} 1472 1473void 1474upper(s) 1475 char *s; 1476{ 1477 while (*s != '\0') { 1478 if (islower(*s)) 1479 *s = toupper(*s); 1480 s++; 1481 } 1482} 1483 1484static char * 1485copy(s) 1486 char *s; 1487{ 1488 char *p; 1489 1490 p = malloc((unsigned) strlen(s) + 1); 1491 if (p == NULL) 1492 fatalerror("Ran out of memory."); 1493 (void) strcpy(p, s); 1494 return (p); 1495} 1496 1497static void 1498help(ctab, s) 1499 struct tab *ctab; 1500 char *s; 1501{ 1502 struct tab *c; 1503 int width, NCMDS; 1504 char *type; 1505 1506 if (ctab == sitetab) 1507 type = "SITE "; 1508 else 1509 type = ""; 1510 width = 0, NCMDS = 0; 1511 for (c = ctab; c->name != NULL; c++) { 1512 int len = strlen(c->name); 1513 1514 if (len > width) 1515 width = len; 1516 NCMDS++; 1517 } 1518 width = (width + 8) &~ 7; 1519 if (s == 0) { 1520 int i, j, w; 1521 int columns, lines; 1522 1523 lreply(214, "The following %scommands are recognized %s.", 1524 type, "(* =>'s unimplemented)"); 1525 columns = 76 / width; 1526 if (columns == 0) 1527 columns = 1; 1528 lines = (NCMDS + columns - 1) / columns; 1529 for (i = 0; i < lines; i++) { 1530 printf(" "); 1531 for (j = 0; j < columns; j++) { 1532 c = ctab + j * lines + i; 1533 printf("%s%c", c->name, 1534 c->implemented ? ' ' : '*'); 1535 if (c + lines >= &ctab[NCMDS]) 1536 break; 1537 w = strlen(c->name) + 1; 1538 while (w < width) { 1539 putchar(' '); 1540 w++; 1541 } 1542 } 1543 printf("\r\n"); 1544 } 1545 (void) fflush(stdout); 1546 reply(214, "Direct comments to ftp-bugs@%s.", hostname); 1547 return; 1548 } 1549 upper(s); 1550 c = lookup(ctab, s); 1551 if (c == (struct tab *)0) { 1552 reply(502, "Unknown command %s.", s); 1553 return; 1554 } 1555 if (c->implemented) 1556 reply(214, "Syntax: %s%s %s", type, c->name, c->help); 1557 else 1558 reply(214, "%s%-*s\t%s; unimplemented.", type, width, 1559 c->name, c->help); 1560} 1561 1562static void 1563sizecmd(filename) 1564 char *filename; 1565{ 1566 switch (type) { 1567 case TYPE_L: 1568 case TYPE_I: { 1569 struct stat stbuf; 1570 if (stat(filename, &stbuf) < 0) 1571 perror_reply(550, filename); 1572 else if (!S_ISREG(stbuf.st_mode)) 1573 reply(550, "%s: not a plain file.", filename); 1574 else 1575 reply(213, "%qu", stbuf.st_size); 1576 break; } 1577 case TYPE_A: { 1578 FILE *fin; 1579 int c; 1580 off_t count; 1581 struct stat stbuf; 1582 fin = fopen(filename, "r"); 1583 if (fin == NULL) { 1584 perror_reply(550, filename); 1585 return; 1586 } 1587 if (fstat(fileno(fin), &stbuf) < 0) { 1588 perror_reply(550, filename); 1589 (void) fclose(fin); 1590 return; 1591 } else if (!S_ISREG(stbuf.st_mode)) { 1592 reply(550, "%s: not a plain file.", filename); 1593 (void) fclose(fin); 1594 return; 1595 } 1596 1597 count = 0; 1598 while((c=getc(fin)) != EOF) { 1599 if (c == '\n') /* will get expanded to \r\n */ 1600 count++; 1601 count++; 1602 } 1603 (void) fclose(fin); 1604 1605 reply(213, "%qd", count); 1606 break; } 1607 default: 1608 reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); 1609 } 1610} 1611 1612/* Return 1, if port check is done. Return 0, if not yet. */ 1613static int 1614port_check(pcmd) 1615 const char *pcmd; 1616{ 1617 if (his_addr.su_family == AF_INET) { 1618 if (data_dest.su_family != AF_INET) { 1619 usedefault = 1; 1620 reply(500, "Invalid address rejected."); 1621 return 1; 1622 } 1623 if (paranoid && 1624 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1625 memcmp(&data_dest.su_sin.sin_addr, 1626 &his_addr.su_sin.sin_addr, 1627 sizeof(data_dest.su_sin.sin_addr)))) { 1628 usedefault = 1; 1629 reply(500, "Illegal PORT range rejected."); 1630 } else { 1631 usedefault = 0; 1632 if (pdata >= 0) { 1633 (void) close(pdata); 1634 pdata = -1; 1635 } 1636 reply(200, "%s command successful.", pcmd); 1637 } 1638 return 1; 1639 } 1640 return 0; 1641} 1642 1643static int 1644check_login1() 1645{ 1646 if (logged_in) 1647 return 1; 1648 else { 1649 reply(530, "Please login with USER and PASS."); 1650 return 0; 1651 } 1652} 1653 1654#ifdef INET6 1655/* Return 1, if port check is done. Return 0, if not yet. */ 1656static int 1657port_check_v6(pcmd) 1658 const char *pcmd; 1659{ 1660 if (his_addr.su_family == AF_INET6) { 1661 if (IN6_IS_ADDR_V4MAPPED(&his_addr.su_sin6.sin6_addr)) 1662 /* Convert data_dest into v4 mapped sockaddr.*/ 1663 v4map_data_dest(); 1664 if (data_dest.su_family != AF_INET6) { 1665 usedefault = 1; 1666 reply(500, "Invalid address rejected."); 1667 return 1; 1668 } 1669 if (paranoid && 1670 ((ntohs(data_dest.su_port) < IPPORT_RESERVED) || 1671 memcmp(&data_dest.su_sin6.sin6_addr, 1672 &his_addr.su_sin6.sin6_addr, 1673 sizeof(data_dest.su_sin6.sin6_addr)))) { 1674 usedefault = 1; 1675 reply(500, "Illegal PORT range rejected."); 1676 } else { 1677 usedefault = 0; 1678 if (pdata >= 0) { 1679 (void) close(pdata); 1680 pdata = -1; 1681 } 1682 reply(200, "%s command successful.", pcmd); 1683 } 1684 return 1; 1685 } 1686 return 0; 1687} 1688 1689static void 1690v4map_data_dest() 1691{ 1692 struct in_addr savedaddr; 1693 int savedport; 1694 1695 if (data_dest.su_family != AF_INET) { 1696 usedefault = 1; 1697 reply(500, "Invalid address rejected."); 1698 return; 1699 } 1700 1701 savedaddr = data_dest.su_sin.sin_addr; 1702 savedport = data_dest.su_port; 1703 1704 memset(&data_dest, 0, sizeof(data_dest)); 1705 data_dest.su_sin6.sin6_len = sizeof(struct sockaddr_in6); 1706 data_dest.su_sin6.sin6_family = AF_INET6; 1707 data_dest.su_sin6.sin6_port = savedport; 1708 memset((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[10], 0xff, 2); 1709 memcpy((caddr_t)&data_dest.su_sin6.sin6_addr.s6_addr[12], 1710 (caddr_t)&savedaddr, sizeof(savedaddr)); 1711} 1712#endif
|