1 /* 2 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 5 /**************************************************************************** 6 Copyright (c) 1999,2000,2001 WU-FTPD Development Group. 7 All rights reserved. 8 9 Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994 10 The Regents of the University of California. 11 Portions Copyright (c) 1993, 1994 Washington University in Saint Louis. 12 Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc. 13 Portions Copyright (c) 1989 Massachusetts Institute of Technology. 14 Portions Copyright (c) 1998 Sendmail, Inc. 15 Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P. Allman. 16 Portions Copyright (c) 1997 by Stan Barber. 17 Portions Copyright (c) 1997 by Kent Landfield. 18 Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997 19 Free Software Foundation, Inc. 20 21 Use and distribution of this software and its source code are governed 22 by the terms and conditions of the WU-FTPD Software License ("LICENSE"). 23 24 If you did not receive a copy of the license, it may be obtained online 25 at http://www.wu-ftpd.org/license.html. 26 27 $Id: ftpcmd.y,v 1.27.2.2 2001/11/29 17:01:38 wuftpd Exp $ 28 29 ****************************************************************************/ 30 /* 31 * Grammar for FTP commands. 32 * See RFC 959. 33 */ 34 35 %{ 36 #include "config.h" 37 #include <sys/param.h> 38 #include <sys/types.h> 39 #include <sys/socket.h> 40 #include <sys/stat.h> 41 #include <netinet/in.h> 42 #include <arpa/inet.h> 43 #include <arpa/ftp.h> 44 #include <stdio.h> 45 #include <signal.h> 46 #include <errno.h> 47 #include <ctype.h> 48 #include <pwd.h> 49 #include <setjmp.h> 50 #ifdef HAVE_SYS_SYSLOG_H 51 #include <sys/syslog.h> 52 #endif 53 #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H)) 54 #include <syslog.h> 55 #endif 56 #include <time.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <limits.h> 60 #include <alloca.h> 61 #include "extensions.h" 62 #include "pathnames.h" 63 #include "proto.h" 64 65 #if defined(USE_TLS) || defined(USE_GSS) 66 static int pbsz_command_issued = 0; 67 char *cur_auth_type = NULL; 68 extern char *protnames[]; 69 #endif /* defined(USE_TLS) || defined(USE_GSS) */ 70 71 #if defined(USE_GSS) 72 #include "gssutil.h" 73 74 extern gss_info_t gss_info; 75 #endif /* defined(USE_GSS) */ 76 77 extern int dolreplies; 78 #ifndef INTERNAL_LS 79 extern char ls_long[]; 80 extern char ls_short[]; 81 #endif 82 extern struct SOCKSTORAGE data_dest; 83 extern struct SOCKSTORAGE his_addr; 84 extern int logged_in; 85 extern struct passwd *pw; 86 extern int anonymous; 87 extern int logging; 88 extern int log_commands; 89 extern int log_security; 90 extern int type; 91 extern int form; 92 extern int debug; 93 extern unsigned int timeout_idle; 94 extern unsigned int timeout_maxidle; 95 extern int pdata; 96 extern char hostname[], remotehost[], *remoteident; 97 extern char remoteaddr[]; 98 extern char chroot_path[]; 99 extern char guestpw[], authuser[]; /* added. _H */ 100 extern char proctitle[]; 101 extern char *globerr; 102 extern int usedefault; 103 extern int transflag; 104 extern char tmpline[]; 105 extern int data; 106 extern int errno; 107 extern char *home; 108 109 off_t restart_point; 110 int yyerrorcalled; 111 112 extern char *strunames[]; 113 extern char *typenames[]; 114 extern char *modenames[]; 115 extern char *formnames[]; 116 extern int restricted_user; /* global flag indicating if user is restricted to home directory */ 117 118 #ifdef TRANSFER_COUNT 119 extern off_t data_count_total; 120 extern off_t byte_count_total; 121 extern off_t byte_count_in; 122 extern int file_count_total; 123 extern int xfer_count_total; 124 #endif 125 126 extern int retrieve_is_data; 127 128 #ifdef VIRTUAL 129 extern int virtual_mode; 130 extern int virtual_ftpaccess; 131 extern char virtual_email[]; 132 #endif 133 134 #ifdef IGNORE_NOOP 135 static int alarm_running = 0; 136 #endif 137 138 static unsigned short cliport = 0; 139 static struct in_addr cliaddr; 140 static int cmd_type; 141 static int cmd_form; 142 static int cmd_bytesz; 143 char cbuf[16 * BUFSIZ]; 144 char *fromname; 145 146 #ifndef L_FORMAT /* Autoconf detects this... */ 147 #if (defined(BSD) && (BSD >= 199103)) && !defined(LONGOFF_T) 148 #define L_FORMAT "qd" 149 #else 150 #ifdef _AIX42 151 #define L_FORMAT "lld" 152 #else 153 #ifdef SOLARIS_2 154 #define L_FORMAT "ld" 155 #else 156 #define L_FORMAT "d" 157 #endif 158 #endif 159 #endif 160 #endif 161 162 #ifdef INET6 163 extern int epsv_all; 164 int lport_error; 165 #endif 166 167 /* Debian linux bison fix: moved this up, added forward decls */ 168 169 struct tab { 170 char *name; 171 short token; 172 short state; 173 short implemented; /* 1 if command is implemented */ 174 char *help; 175 }; 176 177 extern struct tab cmdtab[]; 178 extern struct tab sitetab[]; 179 180 static void toolong(int); 181 void help(struct tab *ctab, char *s); 182 struct tab *lookup(register struct tab *p, char *cmd); 183 int yylex(void); 184 185 static char *nullstr = "(null)"; 186 #define CHECKNULL(p) ((p) ? (p) : nullstr) 187 188 extern int pasv_allowed(const char *remoteaddr); 189 extern int port_allowed(const char *remoteaddr); 190 %} 191 192 %token 193 A B C E F I 194 L N P R S T 195 196 SP CRLF COMMA STRING NUMBER 197 198 USER PASS ACCT REIN QUIT PORT 199 PASV TYPE STRU MODE RETR STOR 200 APPE MLFL MAIL MSND MSOM MSAM 201 MRSQ MRCP ALLO REST RNFR RNTO 202 ABOR DELE CWD LIST NLST SITE 203 STAT HELP NOOP MKD RMD PWD 204 CDUP STOU SMNT SYST SIZE MDTM 205 EPRT EPSV LPRT LPSV 206 PROT PBSZ AUTH ADAT CCC 207 208 UMASK IDLE CHMOD GROUP GPASS NEWER 209 MINFO INDEX EXEC ALIAS CDPATH GROUPS 210 CHECKMETHOD CHECKSUM 211 212 LEXERR 213 214 %union { 215 char *String; 216 int Number; 217 } 218 219 %type <String> STRING password pathname pathstring username method 220 %type <Number> NUMBER byte_size check_login form_code 221 %type <Number> struct_code mode_code octal_number 222 %type <Number> prot_code 223 224 %start cmd_list 225 226 %% 227 228 cmd_list: /* empty */ 229 | cmd_list cmd 230 = { 231 if (fromname) { 232 free(fromname); 233 fromname = NULL; 234 } 235 restart_point = 0; 236 } 237 | cmd_list rcmd 238 ; 239 240 cmd: USER SP username CRLF 241 = { 242 user($3); 243 if (log_commands) 244 syslog(LOG_INFO, "USER %s", $3); 245 free($3); 246 } 247 | PASS SP password CRLF 248 = { 249 if (log_commands) 250 if (anonymous) 251 syslog(LOG_INFO, "PASS %s", $3); 252 else 253 syslog(LOG_INFO, "PASS password"); 254 255 pass($3); 256 free($3); 257 } 258 | PORT check_login SP host_port CRLF 259 = { 260 if (log_commands) 261 syslog(LOG_INFO, "PORT"); 262 /* H* port fix, part B: admonish the twit. 263 Also require login before PORT works */ 264 if ($2) { 265 #ifndef DISABLE_PORT 266 #ifdef INET6 267 if (epsv_all) { 268 reply(501, "PORT not allowed after EPSV ALL"); 269 goto prt_done; 270 } 271 #endif 272 if (((sock_cmp_inaddr(&his_addr, cliaddr) == 0) 273 || port_allowed(inet_ntoa(cliaddr))) 274 && (ntohs(cliport) >= IPPORT_RESERVED)) { 275 usedefault = 0; 276 if (pdata >= 0) { 277 (void) close(pdata); 278 pdata = -1; 279 } 280 SET_SOCK_FAMILY(data_dest, SOCK_FAMILY(his_addr)); 281 SET_SOCK_PORT(data_dest, cliport); 282 SET_SOCK_ADDR4(data_dest, cliaddr); 283 reply(200, "PORT command successful."); 284 } 285 else { 286 #endif /* DISABLE_PORT */ 287 reply(502, "Illegal PORT Command"); 288 prt_done: 289 usedefault = 1; 290 syslog(LOG_WARNING, "refused PORT %s,%d from %s", 291 inet_ntoa(cliaddr), ntohs(cliport), remoteident); 292 #ifndef DISABLE_PORT 293 } 294 #endif 295 } 296 } 297 | EPRT check_login SP STRING CRLF 298 = { 299 #ifdef INET6 300 if (log_commands) 301 syslog(LOG_INFO, "EPRT"); 302 if ($2 && $4 != NULL) { 303 #ifndef DISABLE_PORT 304 char d, fmt[32], addr[INET6_ADDRSTRLEN + 1]; 305 int proto; 306 unsigned short port; 307 308 if (epsv_all) { 309 reply(501, "EPRT not allowed after EPSV ALL"); 310 goto eprt_done; 311 } 312 d = *((char *)$4); 313 if ((d < 33) || (d > 126)) { 314 reply(501, "Bad delimiter '%c' (%d).", d, d); 315 goto eprt_done; 316 } 317 if (d == '%') 318 (void) snprintf(fmt, sizeof(fmt), 319 "%%%1$c%%d%%%1$c%%%2$d[^%%%1$c]%%%1$c%%hu%%%1$c", 320 d, INET6_ADDRSTRLEN); 321 else 322 (void) snprintf(fmt, sizeof(fmt), 323 "%1$c%%d%1$c%%%2$d[^%1$c]%1$c%%hu%1$c", 324 d, INET6_ADDRSTRLEN); 325 326 if (sscanf((const char *)$4, fmt, &proto, addr, &port) != 3) { 327 reply(501, "EPRT bad format."); 328 goto eprt_done; 329 } 330 port = htons(port); 331 332 switch (proto) { 333 case 1: 334 SET_SOCK_FAMILY(data_dest, AF_INET); 335 break; 336 case 2: 337 memset(&data_dest, 0, sizeof(struct sockaddr_in6)); 338 SET_SOCK_FAMILY(data_dest, AF_INET6); 339 break; 340 default: 341 reply(522, "Network protocol not supported, use (1,2)"); 342 goto eprt_done; 343 } 344 if (inet_pton(SOCK_FAMILY(data_dest), addr, SOCK_ADDR(data_dest)) 345 != 1) { 346 reply(501, "Bad address %s.", addr); 347 goto eprt_done; 348 } 349 350 if (((sock_cmp_addr(&his_addr, &data_dest) == 0) 351 || port_allowed(inet_stop(&data_dest))) 352 && (ntohs(port) >= IPPORT_RESERVED)) { 353 usedefault = 0; 354 if (pdata >= 0) { 355 (void) close(pdata); 356 pdata = -1; 357 } 358 SET_SOCK_PORT(data_dest, port); 359 SET_SOCK_SCOPE(data_dest, his_addr); 360 reply(200, "EPRT command successful."); 361 } 362 else { 363 #endif /* DISABLE_PORT */ 364 reply(502, "Illegal EPRT Command"); 365 eprt_done: 366 usedefault = 1; 367 syslog(LOG_WARNING, "refused EPRT %s from %s", 368 $4, remoteident); 369 #ifndef DISABLE_PORT 370 } 371 #endif 372 } 373 if ($4 != NULL) 374 free($4); 375 #endif /* INET6 */ 376 } 377 | LPRT check_login SP host_lport CRLF 378 = { 379 #ifdef INET6 380 if (log_commands) 381 syslog(LOG_INFO, "LPRT"); 382 if ($2) { 383 #ifndef DISABLE_PORT 384 if (lport_error) 385 goto lprt_done; 386 if (((sock_cmp_addr(&his_addr, &data_dest) == 0) 387 || port_allowed(inet_stop(&data_dest))) 388 && (SOCK_PORT(data_dest) >= IPPORT_RESERVED)) { 389 usedefault = 0; 390 if (pdata >= 0) { 391 (void) close(pdata); 392 pdata = -1; 393 } 394 SET_SOCK_SCOPE(data_dest, his_addr); 395 reply(200, "LPRT command successful."); 396 } 397 else { 398 #endif /* DISABLE_PORT */ 399 reply(502, "Illegal LPRT Command"); 400 lprt_done: 401 usedefault = 1; 402 syslog(LOG_WARNING, "refused LPRT from %s", remoteident); 403 #ifndef DISABLE_PORT 404 } 405 #endif 406 } 407 #endif /* INET6 */ 408 } 409 | PASV check_login CRLF 410 = { 411 /* Require login for PASV, too. This actually fixes a bug -- telnet to an 412 unfixed wu-ftpd and type PASV first off, and it crashes! */ 413 if (log_commands) 414 syslog(LOG_INFO, "PASV"); 415 if ($2) 416 #if (defined (DISABLE_PORT) || !defined (DISABLE_PASV)) 417 #ifdef INET6 418 if (epsv_all) 419 reply(501, "PASV not allowed after EPSV ALL"); 420 else 421 #endif 422 passive(TYPE_PASV, 0); 423 #else 424 reply(502, "Illegal PASV Command"); 425 #endif 426 } 427 | EPSV check_login CRLF 428 = { 429 #ifdef INET6 430 if (log_commands) 431 syslog(LOG_INFO, "EPSV"); 432 if ($2) 433 #if (defined (DISABLE_PORT) || !defined (DISABLE_PASV)) 434 passive(TYPE_EPSV, 0); 435 #else 436 reply(502, "Illegal EPSV Command"); 437 #endif 438 #endif /* INET6 */ 439 } 440 | EPSV check_login SP STRING CRLF 441 = { 442 #ifdef INET6 443 if (log_commands) 444 syslog(LOG_INFO, "EPSV"); 445 if ($2 && $4 != NULL) 446 #if (defined (DISABLE_PORT) || !defined (DISABLE_PASV)) 447 if (strcasecmp((const char *)$4, "ALL") == 0) { 448 epsv_all = 1; 449 reply(200, "EPSV ALL command successful."); 450 } 451 else { 452 int af; 453 char *endp; 454 455 af = strtoul((char *)$4, &endp, 0); 456 if (*endp) 457 reply(501, "'EPSV %s':" "command not understood.", $4); 458 else { 459 /* Not allowed to specify address family 0 */ 460 if (af == 0) 461 af = -1; 462 passive(TYPE_EPSV, af); 463 } 464 } 465 #else 466 reply(502, "Illegal EPSV Command"); 467 #endif 468 if ($4 != NULL) 469 free($4); 470 #endif /* INET6 */ 471 } 472 | LPSV check_login CRLF 473 = { 474 #ifdef INET6 475 if (log_commands) 476 syslog(LOG_INFO, "LPSV"); 477 if ($2) 478 #if (defined (DISABLE_PORT) || !defined (DISABLE_PASV)) 479 if (epsv_all) 480 reply(501, "LPSV not allowed after EPSV ALL"); 481 else 482 passive(TYPE_LPSV, 0); 483 #else 484 reply(502, "Illegal LPSV Command"); 485 #endif 486 #endif /* INET6 */ 487 } 488 | TYPE check_login SP type_code CRLF 489 = { 490 if (log_commands) 491 syslog(LOG_INFO, "TYPE %s", typenames[cmd_type]); 492 if ($2) 493 switch (cmd_type) { 494 495 case TYPE_A: 496 if (cmd_form == FORM_N) { 497 reply(200, "Type set to A."); 498 type = cmd_type; 499 form = cmd_form; 500 } 501 else 502 reply(504, "Form must be N."); 503 break; 504 505 case TYPE_E: 506 reply(504, "Type E not implemented."); 507 break; 508 509 case TYPE_I: 510 reply(200, "Type set to I."); 511 type = cmd_type; 512 break; 513 514 case TYPE_L: 515 #if NBBY == 8 516 if (cmd_bytesz == 8) { 517 reply(200, 518 "Type set to L (byte size 8)."); 519 type = cmd_type; 520 } 521 else 522 reply(504, "Byte size must be 8."); 523 #else /* NBBY == 8 */ 524 #error UNIMPLEMENTED for NBBY != 8 525 #endif /* NBBY == 8 */ 526 } 527 } 528 | STRU check_login SP struct_code CRLF 529 = { 530 if (log_commands) 531 syslog(LOG_INFO, "STRU %s", strunames[$4]); 532 if ($2) 533 switch ($4) { 534 535 case STRU_F: 536 reply(200, "STRU F ok."); 537 break; 538 539 default: 540 reply(504, "Unimplemented STRU type."); 541 } 542 } 543 | MODE check_login SP mode_code CRLF 544 = { 545 if (log_commands) 546 syslog(LOG_INFO, "MODE %s", modenames[$4]); 547 if ($2) 548 switch ($4) { 549 550 case MODE_S: 551 reply(200, "MODE S ok."); 552 break; 553 554 default: 555 reply(502, "Unimplemented MODE type."); 556 } 557 } 558 | ALLO check_login SP NUMBER CRLF 559 = { 560 if (log_commands) 561 syslog(LOG_INFO, "ALLO %d", $4); 562 if ($2) 563 reply(202, "ALLO command ignored."); 564 } 565 | ALLO check_login SP NUMBER SP R SP NUMBER CRLF 566 = { 567 if (log_commands) 568 syslog(LOG_INFO, "ALLO %d R %d", $4, $8); 569 if ($2) 570 reply(202, "ALLO command ignored."); 571 } 572 | RETR check_login SP pathname CRLF 573 = { 574 if (log_commands) 575 syslog(LOG_INFO, "RETR %s", CHECKNULL($4)); 576 if ($2 && $4 != NULL && !restrict_check($4)) { 577 retrieve_is_data = 1; 578 retrieve((char *) NULL, $4); 579 } 580 if ($4 != NULL) 581 free($4); 582 } 583 | STOR check_login SP pathname CRLF 584 = { 585 if (log_commands) 586 syslog(LOG_INFO, "STOR %s", CHECKNULL($4)); 587 if ($2 && $4 != NULL && !restrict_check($4)) 588 store($4, "w", 0); 589 if ($4 != NULL) 590 free($4); 591 } 592 | APPE check_login SP pathname CRLF 593 = { 594 if (log_commands) 595 syslog(LOG_INFO, "APPE %s", CHECKNULL($4)); 596 if ($2 && $4 != NULL && !restrict_check($4)) 597 store($4, "a", 0); 598 if ($4 != NULL) 599 free($4); 600 } 601 | NLST check_login CRLF 602 = { 603 if (log_commands) 604 syslog(LOG_INFO, "NLST"); 605 if ($2 && !restrict_check(".")) 606 send_file_list(""); 607 } 608 | NLST check_login SP STRING CRLF 609 = { 610 if (log_commands) 611 syslog(LOG_INFO, "NLST %s", $4); 612 if ($2 && $4 && !restrict_check($4)) 613 send_file_list($4); 614 if ($4 != NULL) 615 free($4); 616 } 617 | LIST check_login CRLF 618 = { 619 if (log_commands) 620 syslog(LOG_INFO, "LIST"); 621 if ($2 && !restrict_check(".")) { 622 retrieve_is_data = 0; 623 #ifndef INTERNAL_LS 624 if (anonymous && dolreplies) 625 retrieve(ls_long, ""); 626 else 627 retrieve(ls_short, ""); 628 #else 629 ls(NULL, 0); 630 #endif 631 } 632 } 633 | LIST check_login SP pathname CRLF 634 = { 635 if (log_commands) 636 syslog(LOG_INFO, "LIST %s", CHECKNULL($4)); 637 if ($2 && $4 != NULL && !restrict_list_check($4)) { 638 retrieve_is_data = 0; 639 #ifndef INTERNAL_LS 640 if (anonymous && dolreplies) 641 retrieve(ls_long, $4); 642 else 643 retrieve(ls_short, $4); 644 #else 645 ls($4, 0); 646 #endif 647 } 648 if ($4 != NULL) 649 free($4); 650 } 651 | STAT check_login SP pathname CRLF 652 = { 653 if (log_commands) 654 syslog(LOG_INFO, "STAT %s", CHECKNULL($4)); 655 if ($2 && $4 != NULL && !restrict_check($4)) 656 statfilecmd($4); 657 if ($4 != NULL) 658 free($4); 659 } 660 | STAT check_login CRLF 661 = { 662 if (log_commands) 663 syslog(LOG_INFO, "STAT"); 664 if ($2) 665 statcmd(); 666 } 667 | DELE check_login SP pathname CRLF 668 = { 669 if (log_commands) 670 syslog(LOG_INFO, "DELE %s", CHECKNULL($4)); 671 if ($2 && $4 != NULL && !restrict_check($4)) 672 delete($4); 673 if ($4 != NULL) 674 free($4); 675 } 676 | RNTO check_login SP pathname CRLF 677 = { 678 if (log_commands) 679 syslog(LOG_INFO, "RNTO %s", CHECKNULL($4)); 680 if ($2 && $4 && !restrict_check($4)) { 681 if (fromname) { 682 renamecmd(fromname, $4); 683 free(fromname); 684 fromname = NULL; 685 } 686 else { 687 reply(503, "Bad sequence of commands."); 688 } 689 } 690 if ($4) 691 free($4); 692 } 693 | ABOR check_login CRLF 694 = { 695 if (log_commands) 696 syslog(LOG_INFO, "ABOR"); 697 if ($2) 698 reply(225, "ABOR command successful."); 699 } 700 | CWD check_login CRLF 701 = { 702 if (log_commands) 703 syslog(LOG_INFO, "CWD"); 704 if ($2 && !restrict_check(home)) 705 cwd(home); 706 } 707 | CWD check_login SP pathname CRLF 708 = { 709 if (log_commands) 710 syslog(LOG_INFO, "CWD %s", CHECKNULL($4)); 711 if ($2 && $4 != NULL && !restrict_check($4)) 712 cwd($4); 713 if ($4 != NULL) 714 free($4); 715 } 716 | HELP check_login CRLF 717 = { 718 if (log_commands) 719 syslog(LOG_INFO, "HELP"); 720 if ($2) 721 help(cmdtab, (char *) NULL); 722 } 723 | HELP check_login SP STRING CRLF 724 = { 725 register char *cp = (char *) $4; 726 727 if (log_commands) 728 syslog(LOG_INFO, "HELP %s", $4); 729 if ($2) 730 if (strncasecmp(cp, "SITE", 4) == 0) { 731 cp = (char *) $4 + 4; 732 if (*cp == ' ') 733 cp++; 734 if (*cp) 735 help(sitetab, cp); 736 else 737 help(sitetab, (char *) NULL); 738 } 739 else 740 help(cmdtab, $4); 741 if ($4 != NULL) 742 free($4); 743 } 744 | NOOP check_login CRLF 745 = { 746 if (log_commands) 747 syslog(LOG_INFO, "NOOP"); 748 if ($2) 749 reply(200, "NOOP command successful."); 750 } 751 | MKD check_login SP pathname CRLF 752 = { 753 if (log_commands) 754 syslog(LOG_INFO, "MKD %s", CHECKNULL($4)); 755 if ($2 && $4 != NULL && !restrict_check($4)) 756 makedir($4); 757 if ($4 != NULL) 758 free($4); 759 } 760 | RMD check_login SP pathname CRLF 761 = { 762 if (log_commands) 763 syslog(LOG_INFO, "RMD %s", CHECKNULL($4)); 764 if ($2 && $4 != NULL && !restrict_check($4)) 765 removedir($4); 766 if ($4 != NULL) 767 free($4); 768 } 769 | PWD check_login CRLF 770 = { 771 if (log_commands) 772 syslog(LOG_INFO, "PWD"); 773 if ($2) 774 pwd(); 775 } 776 | CDUP check_login CRLF 777 = { 778 if (log_commands) 779 syslog(LOG_INFO, "CDUP"); 780 if ($2) 781 if (!test_restriction("..")) 782 cwd(".."); 783 else 784 ack("CWD"); 785 } 786 787 | SITE check_login SP HELP CRLF 788 = { 789 if (log_commands) 790 syslog(LOG_INFO, "SITE HELP"); 791 if ($2) 792 help(sitetab, (char *) NULL); 793 } 794 | SITE check_login SP HELP SP STRING CRLF 795 = { 796 if (log_commands) 797 syslog(LOG_INFO, "SITE HELP %s", $6); 798 if ($2) 799 help(sitetab, $6); 800 if ($6 != NULL) 801 free($6); 802 } 803 | SITE check_login SP UMASK CRLF 804 = { 805 mode_t oldmask; 806 807 if (log_commands) 808 syslog(LOG_INFO, "SITE UMASK"); 809 if ($2) { 810 oldmask = umask(0); 811 (void) umask(oldmask); 812 reply(200, "Current UMASK is %03o", oldmask); 813 } 814 } 815 | SITE check_login SP UMASK SP octal_number CRLF 816 = { 817 mode_t oldmask; 818 struct aclmember *entry = NULL; 819 int ok = 1; 820 821 if (log_commands) 822 syslog(LOG_INFO, "SITE UMASK %03o", $6); 823 if ($2) { 824 /* check for umask permission */ 825 while (getaclentry("umask", &entry) && ARG0 && ARG1 != NULL) { 826 if (type_match(ARG1)) 827 if (*ARG0 == 'n') 828 ok = 0; 829 } 830 if (ok && !restricted_user) { 831 if (($6 < 0) || ($6 > 0777)) { 832 reply(501, "Bad UMASK value"); 833 } 834 else { 835 oldmask = umask((mode_t) $6); 836 reply(200, "UMASK set to %03o (was %03o)", $6, oldmask); 837 } 838 } 839 else 840 reply(553, "Permission denied on server. (umask)"); 841 } 842 } 843 | SITE check_login SP CHMOD SP octal_number SP pathname CRLF 844 = { 845 struct aclmember *entry = NULL; 846 int ok = (anonymous ? 0 : 1); 847 848 if (log_commands) 849 syslog(LOG_INFO, "SITE CHMOD %03o %s", $6, CHECKNULL($8)); 850 if ($2 && $8) { 851 /* check for chmod permission */ 852 while (getaclentry("chmod", &entry) && ARG0 && ARG1 != NULL) { 853 if (type_match(ARG1)) 854 if (anonymous) { 855 if (*ARG0 == 'y') 856 ok = 1; 857 } 858 else if (*ARG0 == 'n') 859 ok = 0; 860 } 861 if (ok) { 862 #ifdef UNRESTRICTED_CHMOD 863 if (chmod($8, (mode_t) $6) < 0) 864 #else 865 if (($6 < 0) || ($6 > 0777)) 866 reply(501, 867 "CHMOD: Mode value must be between 0 and 0777"); 868 else if (chmod($8, (mode_t) $6) < 0) 869 #endif 870 perror_reply(550, $8); 871 else { 872 char path[MAXPATHLEN]; 873 874 wu_realpath($8, path, chroot_path); 875 876 if (log_security) 877 if (anonymous) { 878 syslog(LOG_NOTICE, "%s of %s changed permissions for %s", guestpw, remoteident, path); 879 } 880 else { 881 syslog(LOG_NOTICE, "%s of %s changed permissions for %s", pw->pw_name, 882 remoteident, path); 883 } 884 reply(200, "CHMOD command successful."); 885 } 886 } 887 else 888 reply(553, "Permission denied on server. (chmod)"); 889 } 890 if ($8 != NULL) 891 free($8); 892 } 893 | SITE check_login SP IDLE CRLF 894 = { 895 if (log_commands) 896 syslog(LOG_INFO, "SITE IDLE"); 897 if ($2) 898 reply(200, 899 "Current IDLE time limit is %d seconds; max %d", 900 timeout_idle, timeout_maxidle); 901 } 902 | SITE check_login SP IDLE SP NUMBER CRLF 903 = { 904 if (log_commands) 905 syslog(LOG_INFO, "SITE IDLE %d", $6); 906 if ($2) 907 if ($6 < 30 || $6 > timeout_maxidle) { 908 reply(501, 909 "Maximum IDLE time must be between 30 and %d seconds", 910 timeout_maxidle); 911 } 912 else { 913 timeout_idle = $6; 914 reply(200, "Maximum IDLE time set to %d seconds", timeout_idle); 915 } 916 } 917 | SITE check_login SP GROUP SP username CRLF 918 = { 919 #ifndef NO_PRIVATE 920 if (log_commands) 921 syslog(LOG_INFO, "SITE GROUP %s", $6); 922 if (!restricted_user && $2 && $6) 923 priv_group($6); 924 free($6); 925 #endif /* !NO_PRIVATE */ 926 } 927 | SITE check_login SP GPASS SP password CRLF 928 = { 929 #ifndef NO_PRIVATE 930 if (log_commands) 931 syslog(LOG_INFO, "SITE GPASS password"); 932 if (!restricted_user && $2 && $6) 933 priv_gpass($6); 934 free($6); 935 #endif /* !NO_PRIVATE */ 936 } 937 | SITE check_login SP GPASS CRLF 938 = { 939 #ifndef NO_PRIVATE 940 if (log_commands) 941 syslog(LOG_INFO, "SITE GPASS"); 942 if (!restricted_user && $2) 943 priv_gpass(NULL); 944 #endif /* !NO_PRIVATE */ 945 } 946 | SITE check_login SP NEWER SP STRING CRLF 947 = { 948 if (log_commands) 949 syslog(LOG_INFO, "SITE NEWER %s", $6); 950 #ifdef SITE_NEWER 951 if ($2 && $6 && !restrict_check(".")) 952 newer($6, ".", 0); 953 #else 954 reply(502, "Command no longer honored by this server"); 955 #endif 956 free($6); 957 } 958 | SITE check_login SP NEWER SP STRING SP pathname CRLF 959 = { 960 if (log_commands) 961 syslog(LOG_INFO, "SITE NEWER %s %s", $6, 962 CHECKNULL($8)); 963 #ifdef SITE_NEWER 964 if ($2 && $6 && $8 && !restrict_check($8)) 965 newer($6, $8, 0); 966 #else 967 reply(502, "Command no longer honored by this server"); 968 #endif 969 free($6); 970 if ($8) 971 free($8); 972 } 973 | SITE check_login SP MINFO SP STRING CRLF 974 = { 975 if (log_commands) 976 syslog(LOG_INFO, "SITE MINFO %s", $6); 977 #ifdef SITE_NEWER 978 if ($2 && $6 && !restrict_check(".")) 979 newer($6, ".", 1); 980 #else 981 reply(502, "Command no longer honored by this server"); 982 #endif 983 free($6); 984 } 985 | SITE check_login SP MINFO SP STRING SP pathname CRLF 986 = { 987 if (log_commands) 988 syslog(LOG_INFO, "SITE MINFO %s %s", $6, 989 CHECKNULL($8)); 990 #ifdef SITE_NEWER 991 if ($2 && $6 && $8 && !restrict_check($8)) 992 newer($6, $8, 1); 993 #else 994 reply(502, "Command no longer honored by this server"); 995 #endif 996 free($6); 997 if ($8) 998 free($8); 999 } 1000 | SITE check_login SP INDEX SP STRING CRLF 1001 = { 1002 /* this is just for backward compatibility since we 1003 * thought of INDEX before we thought of EXEC 1004 */ 1005 if (!restricted_user && $2 != 0 && $6 != NULL) { 1006 char buf[MAXPATHLEN]; 1007 if (strlen($6) + 7 <= sizeof(buf)) { 1008 (void) snprintf(buf, sizeof(buf), "index %s", (char *) $6); 1009 (void) site_exec(buf); 1010 } 1011 } 1012 if ($6 != NULL) 1013 free($6); 1014 } 1015 | SITE check_login SP EXEC SP STRING CRLF 1016 = { 1017 if (!restricted_user && $2 != 0 && $6 != NULL) { 1018 (void) site_exec((char *) $6); 1019 } 1020 if ($6 != NULL) 1021 free($6); 1022 } 1023 1024 | STOU check_login 1025 = { 1026 char *default_filename = "ftp"; 1027 if (log_commands) 1028 syslog(LOG_INFO, "STOU"); 1029 if ($2 && !restrict_check(default_filename)) 1030 store(default_filename, "w", 1); 1031 } 1032 | STOU check_login SP pathname CRLF 1033 = { 1034 if (log_commands) 1035 syslog(LOG_INFO, "STOU %s", CHECKNULL($4)); 1036 if ($2 && $4 && !restrict_check($4)) 1037 store($4, "w", 1); 1038 if ($4 != NULL) 1039 free($4); 1040 } 1041 | SYST check_login CRLF 1042 = { 1043 if (log_commands) 1044 syslog(LOG_INFO, "SYST"); 1045 if ($2) 1046 #ifdef BSD 1047 reply(215, "UNIX Type: L%d Version: BSD-%d", NBBY, BSD); 1048 #elif defined(SOLARIS_2) 1049 reply(215, "UNIX Type: L%d Version: SUNOS", NBBY); 1050 #elif defined(unix) || defined(__unix__) 1051 reply(215, "UNIX Type: L%d", NBBY); 1052 #else 1053 reply(215, "UNKNOWN Type: L%d", NBBY); 1054 #endif /* BSD */ 1055 } 1056 1057 /* 1058 * SIZE is not in RFC959, but Postel has blessed it and 1059 * it will be in the updated RFC. 1060 * 1061 * Return size of file in a format suitable for 1062 * using with RESTART (we just count bytes). 1063 */ 1064 | SIZE check_login SP pathname CRLF 1065 = { 1066 if (log_commands) 1067 syslog(LOG_INFO, "SIZE %s", CHECKNULL($4)); 1068 if ($2 && $4 && !restrict_check($4)) { 1069 sizecmd($4); 1070 } 1071 if ($4 != NULL) 1072 free($4); 1073 } 1074 1075 /* 1076 * MDTM is not in RFC959, but Postel has blessed it and 1077 * it will be in the updated RFC. 1078 * 1079 * Return modification time of file as an ISO 3307 1080 * style time. E.g. YYYYMMDDHHMMSS or YYYYMMDDHHMMSS.xxx 1081 * where xxx is the fractional second (of any precision, 1082 * not necessarily 3 digits) 1083 */ 1084 | MDTM check_login SP pathname CRLF 1085 = { 1086 if (log_commands) 1087 syslog(LOG_INFO, "MDTM %s", CHECKNULL($4)); 1088 if ($2 && $4 && !restrict_check($4)) { 1089 struct stat stbuf; 1090 1091 if (stat($4, &stbuf) < 0) 1092 perror_reply(550, $4); 1093 else if ((stbuf.st_mode & S_IFMT) != S_IFREG) { 1094 reply(550, "%s: not a plain file.", 1095 $4); 1096 } 1097 else { 1098 register struct tm *t; 1099 t = gmtime(&stbuf.st_mtime); 1100 reply(213, 1101 "%04d%02d%02d%02d%02d%02d", 1102 t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, 1103 t->tm_hour, t->tm_min, t->tm_sec); 1104 } 1105 } 1106 if ($4 != NULL) 1107 free($4); 1108 } 1109 | QUIT CRLF 1110 = { 1111 if (log_commands) 1112 syslog(LOG_INFO, "QUIT"); 1113 #ifdef TRANSFER_COUNT 1114 if (logged_in) { 1115 lreply(221, "You have transferred %" L_FORMAT " bytes in %d files.", data_count_total, file_count_total); 1116 lreply(221, "Total traffic for this session was %" L_FORMAT " bytes in %d transfers.", byte_count_total, xfer_count_total); 1117 lreply(221, "Thank you for using the FTP service on %s.", hostname); 1118 } 1119 #endif /* TRANSFER_COUNT */ 1120 reply(221, "Goodbye."); 1121 dologout(0); 1122 } 1123 | error CRLF 1124 = { 1125 yyerrok; 1126 } 1127 ; 1128 1129 rcmd: RNFR check_login SP pathname CRLF 1130 = { 1131 1132 if (log_commands) 1133 syslog(LOG_INFO, "RNFR %s", CHECKNULL($4)); 1134 if ($2) 1135 restart_point = 0; 1136 if (fromname) { 1137 free(fromname); 1138 fromname = NULL; 1139 } 1140 if ($2 && $4 && !restrict_check($4)) { 1141 fromname = renamefrom($4); 1142 } 1143 if (fromname == NULL && $4) 1144 free($4); 1145 } 1146 | REST check_login SP STRING CRLF 1147 = { 1148 if (log_commands) 1149 syslog(LOG_INFO, "REST %s", CHECKNULL($4)); 1150 if ($2 && $4 != NULL) { 1151 char *endp; 1152 1153 if (fromname) { 1154 free(fromname); 1155 fromname = NULL; 1156 } 1157 errno = 0; 1158 #if _FILE_OFFSET_BITS == 64 1159 restart_point = strtoll($4, &endp, 10); 1160 #else 1161 restart_point = strtol($4, &endp, 10); 1162 #endif 1163 if ((errno == 0) && (restart_point >= 0) && (*endp == '\0')) { 1164 reply(350, "Restarting at %" L_FORMAT 1165 ". Send STORE or RETRIEVE to initiate transfer.", 1166 restart_point); 1167 } 1168 else { 1169 restart_point = 0; 1170 reply(501, "Bad value for REST: %s", $4); 1171 } 1172 } 1173 if ($4 != NULL) 1174 free($4); 1175 } 1176 1177 | SITE check_login SP ALIAS CRLF 1178 = { 1179 if (log_commands) 1180 syslog(LOG_INFO, "SITE ALIAS"); 1181 if ($2) 1182 alias((char *) NULL); 1183 } 1184 | SITE check_login SP ALIAS SP STRING CRLF 1185 = { 1186 if (log_commands) 1187 syslog(LOG_INFO, "SITE ALIAS %s", $6); 1188 if ($2) 1189 alias($6); 1190 if ($6 != NULL) 1191 free($6); 1192 } 1193 | SITE check_login SP GROUPS CRLF 1194 = { 1195 if (log_commands) 1196 syslog(LOG_INFO, "SITE GROUPS"); 1197 if ($2) 1198 print_groups(); 1199 } 1200 | SITE check_login SP CDPATH CRLF 1201 = { 1202 if (log_commands) 1203 syslog(LOG_INFO, "SITE CDPATH"); 1204 if ($2) 1205 cdpath(); 1206 } 1207 | SITE check_login SP CHECKMETHOD SP method CRLF 1208 = { 1209 if (log_commands) 1210 syslog(LOG_INFO, "SITE CHECKMETHOD %s", CHECKNULL($6)); 1211 if (($2) && ($6 != NULL)) 1212 SetCheckMethod($6); 1213 if ($6 != NULL) 1214 free($6); 1215 } 1216 | SITE check_login SP CHECKMETHOD CRLF 1217 = { 1218 if (log_commands) 1219 syslog(LOG_INFO, "SITE CHECKMETHOD"); 1220 if ($2) 1221 ShowCheckMethod(); 1222 } 1223 | SITE check_login SP CHECKSUM SP pathname CRLF 1224 = { 1225 if (log_commands) 1226 syslog(LOG_INFO, "SITE CHECKSUM %s", CHECKNULL($6)); 1227 if (($2) && ($6 != NULL) && (!restrict_check($6))) 1228 CheckSum($6); 1229 if ($6 != NULL) 1230 free($6); 1231 } 1232 | SITE check_login SP CHECKSUM CRLF 1233 = { 1234 if (log_commands) 1235 syslog(LOG_INFO, "SITE CHECKSUM"); 1236 if ($2) 1237 CheckSumLastFile(); 1238 } 1239 | PBSZ SP STRING CRLF 1240 = { 1241 #if defined(USE_TLS) || defined(USE_GSS) 1242 if (log_commands) 1243 syslog(LOG_INFO, "PBSZ %s", $3); 1244 { 1245 int sz = 0; 1246 #if defined(USE_GSS) 1247 sz = gss_setpbsz((char *)$3); 1248 #else 1249 reply(200, "PBSZ=%d", sz); 1250 #endif /* defined(USE_GSS) */ 1251 pbsz_command_issued = 1; 1252 } 1253 #endif /* defined(USE_TLS) || defined(USE_GSS) */ 1254 if ($3 != NULL) 1255 free((char *)$3); 1256 } 1257 | AUTH SP STRING CRLF 1258 = { 1259 #if defined(USE_TLS) || defined(USE_GSS) 1260 register char *cp = (char *) $3; 1261 if (log_commands) 1262 syslog(LOG_INFO, "AUTH %s", $3); 1263 /* convert to UPPER case as per RFC 2228 */ 1264 while (*cp) { 1265 *cp = toupper(*cp); 1266 cp++; 1267 } 1268 #if defined(USE_GSS) 1269 if (!strcmp((char *) $3, "GSSAPI")) { 1270 if (cur_auth_type != NULL) { 1271 reply(534, "Authentication type already set to %s", 1272 cur_auth_type); 1273 syslog(LOG_ERR, "Rejecting duplicate AUTH command"); 1274 } else { 1275 cur_auth_type = strdup((char *)$3); 1276 reply(334, "Using AUTH type %s; ADAT must follow", 1277 cur_auth_type); 1278 } 1279 } else 1280 #endif /* defined(USE_GSS) */ 1281 { 1282 /* 1283 * Previous auth_type did not work, clear the string. 1284 */ 1285 if (cur_auth_type != NULL) { 1286 free(cur_auth_type); 1287 cur_auth_type = NULL; 1288 } 1289 reply(504,"AUTH %s not supported.", $3); 1290 } 1291 #endif /* !(defined(USE_TLS)) && !defined(USE_GSS) */ 1292 if ($3 != NULL) 1293 free((char *)$3); 1294 } 1295 | PROT SP prot_code CRLF 1296 = { 1297 #if defined(USE_TLS) || defined(USE_GSS) 1298 if (log_commands) 1299 syslog(LOG_INFO, "PROT %s", protnames[$3]); 1300 { 1301 if (!pbsz_command_issued) { 1302 reply(503, "PROT command not valid before PBSZ."); 1303 } else { 1304 switch ($3) { 1305 case PROT_P: 1306 reply(200, "PROT P ok."); 1307 #if defined(USE_GSS) 1308 gss_info.data_prot = PROT_P; 1309 #endif /* defined(USE_GSS) */ 1310 break; 1311 case PROT_C: 1312 reply(200, "PROT C ok."); 1313 #if defined(USE_GSS) 1314 gss_info.data_prot = PROT_C; 1315 #endif /* defined(USE_GSS) */ 1316 break; 1317 case PROT_E: 1318 reply(536, "PROT E unsupported"); 1319 break; 1320 case PROT_S: 1321 #if defined(USE_GSS) 1322 reply(200, "PROT S ok."); 1323 gss_info.data_prot = PROT_S; 1324 #endif /* defined(USE_GSS) */ 1325 break; 1326 default: 1327 reply(504, "Invalid PROT type."); 1328 } 1329 #if defined(USE_GSS) 1330 gss_adjust_buflen(); 1331 #endif /* defined(USE_GSS) */ 1332 } 1333 } 1334 #endif /* !(defined(USE_TLS) && !defined(USE_GSS)) */ 1335 } 1336 | ADAT SP STRING CRLF 1337 = { 1338 #if defined(USE_GSS) 1339 if (log_commands) 1340 syslog(LOG_INFO, "ADAT %s", $3); 1341 if (cur_auth_type == NULL || strcmp(cur_auth_type, "GSSAPI")) { 1342 reply(503, "Must identify AUTH GSSAPI before sending ADAT"); 1343 } else 1344 (void) gss_adat((char *)$3); 1345 #endif 1346 if ($3 != NULL) 1347 free((char *)$3); 1348 } 1349 | CCC CRLF 1350 = { 1351 #if defined(USE_GSS) 1352 if (log_commands) 1353 syslog(LOG_INFO, "CCC"); 1354 ccc(); 1355 #endif /* defined(USE_GSS) */ 1356 } 1357 ; 1358 1359 username: STRING 1360 ; 1361 1362 password: /* empty */ 1363 = { 1364 $$ = (char *) malloc(1); 1365 $$[0] = '\0'; 1366 } 1367 | STRING 1368 ; 1369 1370 byte_size: NUMBER 1371 ; 1372 1373 host_port: NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER 1374 = { 1375 register char *a, *p; 1376 1377 a = (char *) &cliaddr; 1378 a[0] = $1; 1379 a[1] = $3; 1380 a[2] = $5; 1381 a[3] = $7; 1382 p = (char *) &cliport; 1383 p[0] = $9; 1384 p[1] = $11; 1385 } 1386 ; 1387 1388 host_lport: NUMBER COMMA NUMBER COMMA 1389 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 1390 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 1391 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 1392 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 1393 NUMBER COMMA NUMBER COMMA NUMBER 1394 = { 1395 #ifdef INET6 1396 char *a, *p; 1397 struct sockaddr_in6 *data_dest_sin6; 1398 1399 lport_error = 0; 1400 if (epsv_all) { 1401 reply(501, "LPRT not allowed after EPSV ALL"); 1402 lport_error = 1; 1403 goto lport_done6; 1404 } 1405 if ($1 != 6) { 1406 reply(521, "Supported address families are (4, 6)"); 1407 lport_error = 1; 1408 goto lport_done6; 1409 } 1410 if (($3 != 16) || ($37 != 2)) { 1411 reply(501, "Bad length."); 1412 lport_error = 1; 1413 goto lport_done6; 1414 } 1415 memset(&data_dest, 0, sizeof(struct sockaddr_in6)); 1416 data_dest_sin6 = (struct sockaddr_in6 *) &data_dest; 1417 data_dest_sin6->sin6_family = AF_INET6; 1418 a = (char *)&data_dest_sin6->sin6_addr; 1419 a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11; 1420 a[4] = $13; a[5] = $15; a[6] = $17; a[7] = $19; 1421 a[8] = $21; a[9] = $23; a[10] = $25; a[11] = $27; 1422 a[12] = $29; a[13] = $31; a[14] = $33; a[15] = $35; 1423 p = (char *)&data_dest_sin6->sin6_port; 1424 p[0] = $39; p[1] = $41; 1425 lport_done6:; 1426 #endif /* INET6 */ 1427 } 1428 | NUMBER COMMA NUMBER COMMA 1429 NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA 1430 NUMBER COMMA NUMBER COMMA NUMBER 1431 = { 1432 #ifdef INET6 1433 char *a, *p; 1434 struct sockaddr_in *data_dest_sin; 1435 1436 lport_error = 0; 1437 if (epsv_all) { 1438 reply(501, "LPRT not allowed after EPSV ALL"); 1439 lport_error = 1; 1440 goto lport_done4; 1441 } 1442 if ($1 != 4) { 1443 reply(521, "Supported address families are (4, 6)"); 1444 lport_error = 1; 1445 goto lport_done4; 1446 } 1447 if (($3 != 4) || ($13 != 2)) { 1448 reply(501, "Bad length."); 1449 lport_error = 1; 1450 goto lport_done4; 1451 } 1452 data_dest_sin = (struct sockaddr_in *) &data_dest; 1453 data_dest_sin->sin_family = AF_INET; 1454 a = (char *)&data_dest_sin->sin_addr; 1455 a[0] = $5; a[1] = $7; a[2] = $9; a[3] = $11; 1456 p = (char *)&data_dest_sin->sin_port; 1457 p[0] = $15; p[1] = $17; 1458 lport_done4:; 1459 #endif /* INET6 */ 1460 } 1461 ; 1462 1463 form_code: N 1464 = { 1465 $$ = FORM_N; 1466 } 1467 | T 1468 = { 1469 $$ = FORM_T; 1470 } 1471 | C 1472 = { 1473 $$ = FORM_C; 1474 } 1475 ; 1476 1477 type_code: A 1478 = { 1479 cmd_type = TYPE_A; 1480 cmd_form = FORM_N; 1481 } 1482 | A SP form_code 1483 = { 1484 cmd_type = TYPE_A; 1485 cmd_form = $3; 1486 } 1487 | E 1488 = { 1489 cmd_type = TYPE_E; 1490 cmd_form = FORM_N; 1491 } 1492 | E SP form_code 1493 = { 1494 cmd_type = TYPE_E; 1495 cmd_form = $3; 1496 } 1497 | I 1498 = { 1499 cmd_type = TYPE_I; 1500 } 1501 | L 1502 = { 1503 cmd_type = TYPE_L; 1504 cmd_bytesz = NBBY; 1505 } 1506 | L SP byte_size 1507 = { 1508 cmd_type = TYPE_L; 1509 cmd_bytesz = $3; 1510 } 1511 /* this is for a bug in the BBN ftp */ 1512 | L byte_size 1513 = { 1514 cmd_type = TYPE_L; 1515 cmd_bytesz = $2; 1516 } 1517 ; 1518 1519 prot_code: C 1520 = { 1521 #if defined(USE_GSS) 1522 $$ = PROT_C; 1523 #endif 1524 } 1525 | P 1526 = { 1527 #if defined(USE_GSS) 1528 $$ = PROT_P; 1529 #endif 1530 } 1531 | S 1532 = { 1533 #if defined(USE_GSS) 1534 $$ = PROT_S; 1535 #endif 1536 } 1537 | E 1538 = { 1539 #if defined(USE_GSS) 1540 $$ = PROT_E; 1541 #endif 1542 } 1543 ; 1544 1545 struct_code: F 1546 = { 1547 $$ = STRU_F; 1548 } 1549 | R 1550 = { 1551 $$ = STRU_R; 1552 } 1553 | P 1554 = { 1555 $$ = STRU_P; 1556 } 1557 ; 1558 1559 mode_code: S 1560 = { 1561 $$ = MODE_S; 1562 } 1563 | B 1564 = { 1565 $$ = MODE_B; 1566 } 1567 | C 1568 = { 1569 $$ = MODE_C; 1570 } 1571 ; 1572 1573 pathname: pathstring 1574 = { 1575 /* 1576 * Problem: this production is used for all pathname 1577 * processing, but only gives a 550 error reply. 1578 * This is a valid reply in some cases but not in others. 1579 */ 1580 if (restricted_user && logged_in && $1 && strncmp($1, "/", 1) == 0) { 1581 /* 1582 * This remaps the root so it is appearently at the user's home 1583 * rather than the real root/chroot. 1584 */ 1585 size_t len = strlen($1) + 2; 1586 char **globlist; 1587 char *t = calloc(len, sizeof(char)); 1588 if (t == NULL) { 1589 errno = EAGAIN; 1590 perror_reply(550, $1); 1591 $$ = NULL; 1592 } 1593 else { 1594 t[0] = '~'; 1595 t[1] = '\0'; 1596 if (strncmp($1, "/../", 4) == 0) 1597 (void) strlcat(t, $1 + 3, len); 1598 else if (strcmp($1, "/..") != 0) 1599 (void) strlcat(t, $1, len); 1600 globlist = ftpglob(t, B_TRUE); 1601 if (globerr) { 1602 reply(550, "%s", globerr); 1603 $$ = NULL; 1604 if (globlist) { 1605 blkfree(globlist); 1606 free((char *) globlist); 1607 } 1608 } 1609 else if (globlist && *globlist) { 1610 $$ = *globlist; 1611 blkfree(&globlist[1]); 1612 free((char *) globlist); 1613 } 1614 else { 1615 if (globlist) { 1616 blkfree(globlist); 1617 free((char *) globlist); 1618 } 1619 errno = ENOENT; 1620 perror_reply(550, $1); 1621 $$ = NULL; 1622 } 1623 free(t); 1624 } 1625 free($1); 1626 } 1627 else if (logged_in && $1 && strncmp($1, "~", 1) == 0) { 1628 char **globlist; 1629 1630 globlist = ftpglob($1, B_TRUE); 1631 if (globerr) { 1632 reply(550, "%s", globerr); 1633 $$ = NULL; 1634 if (globlist) { 1635 blkfree(globlist); 1636 free((char *) globlist); 1637 } 1638 } 1639 else if (globlist && *globlist) { 1640 $$ = *globlist; 1641 blkfree(&globlist[1]); 1642 free((char *) globlist); 1643 } 1644 else { 1645 if (globlist) { 1646 blkfree(globlist); 1647 free((char *) globlist); 1648 } 1649 errno = ENOENT; 1650 perror_reply(550, $1); 1651 $$ = NULL; 1652 } 1653 free($1); 1654 } 1655 else 1656 $$ = $1; 1657 } 1658 ; 1659 1660 pathstring: STRING 1661 ; 1662 1663 method: STRING 1664 ; 1665 1666 octal_number: NUMBER 1667 = { 1668 register int ret, dec, multby, digit; 1669 1670 /* 1671 * Convert a number that was read as decimal number 1672 * to what it would be if it had been read as octal. 1673 */ 1674 dec = $1; 1675 multby = 1; 1676 ret = 0; 1677 while (dec) { 1678 digit = dec % 10; 1679 if (digit > 7) { 1680 ret = -1; 1681 break; 1682 } 1683 ret += digit * multby; 1684 multby *= 8; 1685 dec /= 10; 1686 } 1687 $$ = ret; 1688 } 1689 ; 1690 1691 check_login: /* empty */ 1692 = { 1693 if (logged_in) 1694 $$ = 1; 1695 else { 1696 if (log_commands) 1697 syslog(LOG_INFO, "cmd failure - not logged in"); 1698 reply(530, "Please login with USER and PASS."); 1699 $$ = 0; 1700 yyerrorcalled = 1; 1701 } 1702 } 1703 ; 1704 1705 %% 1706 1707 extern jmp_buf errcatch; 1708 1709 #define CMD 0 /* beginning of command */ 1710 #define ARGS 1 /* expect miscellaneous arguments */ 1711 #define STR1 2 /* expect SP followed by STRING */ 1712 #define STR2 3 /* expect STRING */ 1713 #define OSTR 4 /* optional SP then STRING */ 1714 #define ZSTR1 5 /* SP then optional STRING */ 1715 #define ZSTR2 6 /* optional STRING after SP */ 1716 #define SITECMD 7 /* SITE command */ 1717 #define NSTR 8 /* Number followed by a string */ 1718 #define STR3 9 /* expect STRING followed by optional SP then STRING */ 1719 1720 struct tab cmdtab[] = 1721 { /* In order defined in RFC 765 */ 1722 {"USER", USER, STR1, 1, "<sp> username"}, 1723 {"PASS", PASS, ZSTR1, 1, "<sp> password"}, 1724 {"ACCT", ACCT, STR1, 0, "(specify account)"}, 1725 {"SMNT", SMNT, ARGS, 0, "(structure mount)"}, 1726 {"REIN", REIN, ARGS, 0, "(reinitialize server state)"}, 1727 {"QUIT", QUIT, ARGS, 1, "(terminate service)",}, 1728 {"PORT", PORT, ARGS, 1, "<sp> h1, h2, h3, h4, p1, p2"}, 1729 {"PASV", PASV, ARGS, 1, "(set server in passive mode)"}, 1730 #ifdef INET6 1731 {"EPRT", EPRT, STR1, 1, "<sp> |af|addr|port|"}, 1732 {"EPSV", EPSV, OSTR, 1, "[<sp> af|ALL]"}, 1733 {"LPRT", LPRT, ARGS, 1, "<sp> af, hal, h1, h2, ..., pal, p1, p2, ..."}, 1734 {"LPSV", LPSV, ARGS, 1, "(set server in long passive mode)"}, 1735 #endif 1736 {"TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]"}, 1737 {"STRU", STRU, ARGS, 1, "(specify file structure)"}, 1738 {"MODE", MODE, ARGS, 1, "(specify transfer mode)"}, 1739 {"RETR", RETR, STR1, 1, "<sp> file-name"}, 1740 {"STOR", STOR, STR1, 1, "<sp> file-name"}, 1741 {"APPE", APPE, STR1, 1, "<sp> file-name"}, 1742 {"MLFL", MLFL, OSTR, 0, "(mail file)"}, 1743 {"MAIL", MAIL, OSTR, 0, "(mail to user)"}, 1744 {"MSND", MSND, OSTR, 0, "(mail send to terminal)"}, 1745 {"MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)"}, 1746 {"MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)"}, 1747 {"MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)"}, 1748 {"MRCP", MRCP, STR1, 0, "(mail recipient)"}, 1749 {"ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)"}, 1750 {"REST", REST, STR1, 1, "(restart command)"}, 1751 {"RNFR", RNFR, STR1, 1, "<sp> file-name"}, 1752 {"RNTO", RNTO, STR1, 1, "<sp> file-name"}, 1753 {"ABOR", ABOR, ARGS, 1, "(abort operation)"}, 1754 {"DELE", DELE, STR1, 1, "<sp> file-name"}, 1755 {"CWD", CWD, OSTR, 1, "[ <sp> directory-name ]"}, 1756 {"XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]"}, 1757 {"LIST", LIST, OSTR, 1, "[ <sp> path-name ]"}, 1758 {"NLST", NLST, OSTR, 1, "[ <sp> path-name ]"}, 1759 {"SITE", SITE, SITECMD, 1, "site-cmd [ <sp> arguments ]"}, 1760 {"SYST", SYST, ARGS, 1, "(get type of operating system)"}, 1761 {"STAT", STAT, OSTR, 1, "[ <sp> path-name ]"}, 1762 {"HELP", HELP, OSTR, 1, "[ <sp> <string> ]"}, 1763 {"NOOP", NOOP, ARGS, 1, ""}, 1764 {"MKD", MKD, STR1, 1, "<sp> path-name"}, 1765 {"XMKD", MKD, STR1, 1, "<sp> path-name"}, 1766 {"RMD", RMD, STR1, 1, "<sp> path-name"}, 1767 {"XRMD", RMD, STR1, 1, "<sp> path-name"}, 1768 {"PWD", PWD, ARGS, 1, "(return current directory)"}, 1769 {"XPWD", PWD, ARGS, 1, "(return current directory)"}, 1770 {"CDUP", CDUP, ARGS, 1, "(change to parent directory)"}, 1771 {"XCUP", CDUP, ARGS, 1, "(change to parent directory)"}, 1772 {"STOU", STOU, OSTR, 1, "[ <sp> file-name ]"}, 1773 {"SIZE", SIZE, OSTR, 1, "<sp> path-name"}, 1774 {"MDTM", MDTM, OSTR, 1, "<sp> path-name"}, 1775 #if defined(USE_TLS) || defined(USE_GSS) 1776 {"PROT", PROT, ARGS, 1, "<sp> protection-level"}, 1777 {"PBSZ", PBSZ, STR1, 1, "<sp> protection-buffer-size"}, 1778 {"AUTH", AUTH, STR1, 1, "<sp> authentication-mechanism"}, 1779 {"ADAT", ADAT, STR1, 1, "<sp> authentication-data"}, 1780 #if defined(USE_GSS) 1781 {"CCC", CCC, ARGS, 1, "(clear command channel)"}, 1782 #endif 1783 #endif /* defined(USE_TLS) || defined(USE_GSS) */ 1784 {NULL, 0, 0, 0, 0} 1785 }; 1786 1787 struct tab sitetab[] = 1788 { 1789 {"UMASK", UMASK, ARGS, 1, "[ <sp> umask ]"}, 1790 {"IDLE", IDLE, ARGS, 1, "[ <sp> maximum-idle-time ]"}, 1791 {"CHMOD", CHMOD, NSTR, 1, "<sp> mode <sp> file-name"}, 1792 {"HELP", HELP, OSTR, 1, "[ <sp> <string> ]"}, 1793 {"GROUP", GROUP, STR1, 1, "<sp> access-group"}, 1794 {"GPASS", GPASS, OSTR, 1, "<sp> access-password"}, 1795 {"NEWER", NEWER, STR3, 1, "<sp> YYYYMMDDHHMMSS [ <sp> path-name ]"}, 1796 {"MINFO", MINFO, STR3, 1, "<sp> YYYYMMDDHHMMSS [ <sp> path-name ]"}, 1797 {"INDEX", INDEX, STR1, 1, "<sp> pattern"}, 1798 {"EXEC", EXEC, STR1, 1, "<sp> command [ <sp> arguments ]"}, 1799 {"ALIAS", ALIAS, OSTR, 1, "[ <sp> alias ] "}, 1800 {"CDPATH", CDPATH, OSTR, 1, "[ <sp> ] "}, 1801 {"GROUPS", GROUPS, OSTR, 1, "[ <sp> ] "}, 1802 {"CHECKMETHOD", CHECKMETHOD, OSTR, 1, "[ <sp> crc|md5 ]"}, 1803 {"CHECKSUM", CHECKSUM, OSTR, 1, "[ <sp> file-name ]"}, 1804 {NULL, 0, 0, 0, 0} 1805 }; 1806 1807 struct tab *lookup(register struct tab *p, char *cmd) 1808 { 1809 for (; p->name != NULL; p++) 1810 if (strcmp(cmd, p->name) == 0) 1811 return (p); 1812 return (0); 1813 } 1814 1815 #include <arpa/telnet.h> 1816 1817 /* 1818 * getline - a hacked up version of fgets to ignore TELNET escape codes. 1819 */ 1820 char *wu_getline(char *s, int n, register FILE *iop) 1821 { 1822 register int c; 1823 register char *cs; 1824 char *passtxt = "PASS password\r\n"; 1825 1826 cs = s; 1827 /* tmpline may contain saved command from urgent mode interruption */ 1828 for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { 1829 *cs++ = tmpline[c]; 1830 if (tmpline[c] == '\n') { 1831 *cs++ = '\0'; 1832 if (debug) { 1833 if (strncasecmp(passtxt, s, 5) == 0) 1834 syslog(LOG_DEBUG, "command: %s", passtxt); 1835 else 1836 syslog(LOG_DEBUG, "command: %s", s); 1837 } 1838 tmpline[0] = '\0'; 1839 return (s); 1840 } 1841 if (c == 0) 1842 tmpline[0] = '\0'; 1843 } 1844 retry: 1845 while ((c = getc(iop)) != EOF) { 1846 #ifdef TRANSFER_COUNT 1847 byte_count_total++; 1848 byte_count_in++; 1849 #endif 1850 c &= 0377; 1851 if (c == IAC) { 1852 if ((c = getc(iop)) != EOF) { 1853 #ifdef TRANSFER_COUNT 1854 byte_count_total++; 1855 byte_count_in++; 1856 #endif 1857 c &= 0377; 1858 switch (c) { 1859 case WILL: 1860 case WONT: 1861 c = getc(iop); 1862 #ifdef TRANSFER_COUNT 1863 byte_count_total++; 1864 byte_count_in++; 1865 #endif 1866 printf("%c%c%c", IAC, DONT, 0377 & c); 1867 (void) fflush(stdout); 1868 continue; 1869 case DO: 1870 case DONT: 1871 c = getc(iop); 1872 #ifdef TRANSFER_COUNT 1873 byte_count_total++; 1874 byte_count_in++; 1875 #endif 1876 printf("%c%c%c", IAC, WONT, 0377 & c); 1877 (void) fflush(stdout); 1878 continue; 1879 case IAC: 1880 break; 1881 default: 1882 continue; /* ignore command */ 1883 } 1884 } 1885 } 1886 *cs++ = c; 1887 if (--n <= 0) { 1888 /* If command does not fit to buffer then discard the rest. */ 1889 while (c != '\n' && (c = getc(iop)) != EOF) 1890 ; 1891 reply(500, "Command too long"); 1892 break; 1893 } 1894 if (c == '\n') 1895 break; 1896 } 1897 1898 if (c == EOF && cs == s) { 1899 if (ferror(iop) && (errno == EINTR)) 1900 goto retry; 1901 return (NULL); 1902 } 1903 1904 *cs++ = '\0'; 1905 1906 #if defined(USE_GSS) 1907 if (IS_GSSAUTH(cur_auth_type) && 1908 (gss_info.authstate & GSS_ADAT_DONE) && 1909 gss_info.context != GSS_C_NO_CONTEXT) { 1910 s = sec_decode_command(s); 1911 } else if (IS_GSSAUTH(cur_auth_type) && 1912 (!strncmp(s, "ENC", 3) || !strncmp(s, "MIC", 3) || 1913 !strncmp(s, "CONF", 4)) && 1914 !(gss_info.authstate & GSS_ADAT_DONE)) { 1915 if (debug) 1916 syslog(LOG_DEBUG, "command: %s", s); 1917 reply(503, "Must perform authentication before sending protected commands"); 1918 *s = '\0'; 1919 return(s); 1920 } 1921 #endif /* USE_GSS */ 1922 if (debug) { 1923 if (strncasecmp(passtxt, s, 5) == 0) 1924 syslog(LOG_DEBUG, "command: %s", passtxt); 1925 else 1926 syslog(LOG_DEBUG, "command: %s", s); 1927 } 1928 return (s); 1929 } 1930 1931 static void toolong(int a) /* signal that caused this function to be called */ 1932 { 1933 time_t now; 1934 1935 reply(421, 1936 "Timeout (%d seconds): closing control connection.", timeout_idle); 1937 (void) time(&now); 1938 if (logging) { 1939 syslog(LOG_INFO, 1940 "User %s timed out after %d seconds at %.24s", 1941 (pw ? pw->pw_name : "unknown"), timeout_idle, ctime(&now)); 1942 } 1943 dologout(1); 1944 } 1945 1946 int yylex(void) 1947 { 1948 static int cpos, state; 1949 register char *cp, *cp2; 1950 register struct tab *p; 1951 int n; 1952 time_t now; 1953 char c = '\0'; 1954 extern time_t limit_time; 1955 extern time_t login_time; 1956 1957 for (;;) { 1958 switch (state) { 1959 1960 case CMD: 1961 yyerrorcalled = 0; 1962 1963 setproctitle("%s: IDLE", proctitle); 1964 1965 if (is_shutdown(!logged_in, 0) != 0) { 1966 reply(221, "Server shutting down. Goodbye."); 1967 dologout(0); 1968 } 1969 1970 time(&now); 1971 if ((limit_time > 0) && (((now - login_time) / 60) >= limit_time)) { 1972 reply(221, "Time limit reached. Goodbye."); 1973 dologout(0); 1974 } 1975 1976 #ifdef IGNORE_NOOP 1977 if (!alarm_running) { 1978 (void) signal(SIGALRM, toolong); 1979 (void) alarm((unsigned) timeout_idle); 1980 alarm_running = 1; 1981 } 1982 #else 1983 (void) signal(SIGALRM, toolong); 1984 (void) alarm((unsigned) timeout_idle); 1985 #endif 1986 if (wu_getline(cbuf, sizeof(cbuf) - 1, stdin) == NULL) { 1987 (void) alarm(0); 1988 reply(221, "You could at least say goodbye."); 1989 dologout(0); 1990 } 1991 #ifndef IGNORE_NOOP 1992 (void) alarm(0); 1993 #endif 1994 if ((cp = strchr(cbuf, '\r'))) { 1995 *cp++ = '\n'; 1996 *cp = '\0'; 1997 } 1998 if ((cp = strpbrk(cbuf, " \n"))) 1999 cpos = cp - cbuf; 2000 if (cpos == 0) 2001 cpos = 4; 2002 c = cbuf[cpos]; 2003 cbuf[cpos] = '\0'; 2004 upper(cbuf); 2005 #ifdef IGNORE_NOOP 2006 if (strncasecmp(cbuf, "NOOP", 4) != 0) { 2007 (void) alarm(0); 2008 alarm_running = 0; 2009 } 2010 #endif 2011 p = lookup(cmdtab, cbuf); 2012 cbuf[cpos] = c; 2013 if (strncasecmp(cbuf, "PASS", 4) != 0 && 2014 strncasecmp(cbuf, "SITE GPASS", 10) != 0) { 2015 if ((cp = strchr(cbuf, '\n'))) 2016 *cp = '\0'; 2017 setproctitle("%s: %s", proctitle, cbuf); 2018 if (cp) 2019 *cp = '\n'; 2020 } 2021 if (p != 0) { 2022 if (p->implemented == 0) { 2023 nack(p->name); 2024 longjmp(errcatch, 0); 2025 /* NOTREACHED */ 2026 } 2027 state = p->state; 2028 yylval.String = p->name; 2029 return (p->token); 2030 } 2031 break; 2032 2033 case SITECMD: 2034 if (cbuf[cpos] == ' ') { 2035 cpos++; 2036 return (SP); 2037 } 2038 cp = &cbuf[cpos]; 2039 if ((cp2 = strpbrk(cp, " \n"))) 2040 cpos = cp2 - cbuf; 2041 c = cbuf[cpos]; 2042 cbuf[cpos] = '\0'; 2043 upper(cp); 2044 p = lookup(sitetab, cp); 2045 cbuf[cpos] = c; 2046 if (p != 0) { 2047 #ifndef PARANOID /* what GOOD is SITE *, anyways?! _H */ 2048 if (p->implemented == 0) { 2049 #else 2050 if (1) { 2051 syslog(LOG_WARNING, "refused SITE %s %s from %s of %s", 2052 p->name, &cbuf[cpos], 2053 anonymous ? guestpw : authuser, remoteident); 2054 #endif /* PARANOID */ 2055 state = CMD; 2056 nack(p->name); 2057 longjmp(errcatch, 0); 2058 /* NOTREACHED */ 2059 } 2060 state = p->state; 2061 yylval.String = p->name; 2062 return (p->token); 2063 } 2064 state = CMD; 2065 break; 2066 2067 case OSTR: 2068 if (cbuf[cpos] == '\n') { 2069 state = CMD; 2070 return (CRLF); 2071 } 2072 /* FALLTHROUGH */ 2073 2074 case STR1: 2075 case ZSTR1: 2076 dostr1: 2077 if (cbuf[cpos] == ' ') { 2078 cpos++; 2079 if (state == OSTR) 2080 state = STR2; 2081 else 2082 ++state; 2083 return (SP); 2084 } 2085 break; 2086 2087 case ZSTR2: 2088 if (cbuf[cpos] == '\n') { 2089 state = CMD; 2090 return (CRLF); 2091 } 2092 /* FALLTHROUGH */ 2093 2094 case STR2: 2095 cp = &cbuf[cpos]; 2096 n = strlen(cp); 2097 cpos += n - 1; 2098 /* 2099 * Make sure the string is nonempty and \n terminated. 2100 */ 2101 if (n > 1 && cbuf[cpos] == '\n') { 2102 cbuf[cpos] = '\0'; 2103 yylval.String = copy(cp); 2104 cbuf[cpos] = '\n'; 2105 state = ARGS; 2106 return (STRING); 2107 } 2108 break; 2109 2110 case NSTR: 2111 if (cbuf[cpos] == ' ') { 2112 cpos++; 2113 return (SP); 2114 } 2115 if (isdigit(cbuf[cpos])) { 2116 cp = &cbuf[cpos]; 2117 while (isdigit(cbuf[++cpos])); 2118 c = cbuf[cpos]; 2119 cbuf[cpos] = '\0'; 2120 yylval.Number = atoi(cp); 2121 cbuf[cpos] = c; 2122 state = STR1; 2123 return (NUMBER); 2124 } 2125 state = STR1; 2126 goto dostr1; 2127 2128 case STR3: 2129 if (cbuf[cpos] == ' ') { 2130 cpos++; 2131 return (SP); 2132 } 2133 2134 cp = &cbuf[cpos]; 2135 cp2 = strpbrk(cp, " \n"); 2136 if (cp2 != NULL) { 2137 c = *cp2; 2138 *cp2 = '\0'; 2139 } 2140 n = strlen(cp); 2141 cpos += n; 2142 /* 2143 * Make sure the string is nonempty and SP terminated. 2144 */ 2145 if ((cp2 - cp) > 1) { 2146 yylval.String = copy(cp); 2147 cbuf[cpos] = c; 2148 state = OSTR; 2149 return (STRING); 2150 } 2151 break; 2152 2153 case ARGS: 2154 if (isdigit(cbuf[cpos])) { 2155 cp = &cbuf[cpos]; 2156 while (isdigit(cbuf[++cpos])); 2157 c = cbuf[cpos]; 2158 cbuf[cpos] = '\0'; 2159 yylval.Number = atoi(cp); 2160 cbuf[cpos] = c; 2161 return (NUMBER); 2162 } 2163 switch (cbuf[cpos++]) { 2164 2165 case '\n': 2166 state = CMD; 2167 return (CRLF); 2168 2169 case ' ': 2170 return (SP); 2171 2172 case ',': 2173 return (COMMA); 2174 2175 case 'A': 2176 case 'a': 2177 return (A); 2178 2179 case 'B': 2180 case 'b': 2181 return (B); 2182 2183 case 'C': 2184 case 'c': 2185 return (C); 2186 2187 case 'E': 2188 case 'e': 2189 return (E); 2190 2191 case 'F': 2192 case 'f': 2193 return (F); 2194 2195 case 'I': 2196 case 'i': 2197 return (I); 2198 2199 case 'L': 2200 case 'l': 2201 return (L); 2202 2203 case 'N': 2204 case 'n': 2205 return (N); 2206 2207 case 'P': 2208 case 'p': 2209 return (P); 2210 2211 case 'R': 2212 case 'r': 2213 return (R); 2214 2215 case 'S': 2216 case 's': 2217 return (S); 2218 2219 case 'T': 2220 case 't': 2221 return (T); 2222 2223 } 2224 break; 2225 2226 default: 2227 fatal("Unknown state in scanner."); 2228 } 2229 if (yyerrorcalled == 0) { 2230 if ((cp = strchr(cbuf, '\n')) != NULL) 2231 *cp = '\0'; 2232 if (logged_in) 2233 reply(500, "'%s': command not understood.", cbuf); 2234 else 2235 reply(530, "Please login with USER and PASS."); 2236 } 2237 state = CMD; 2238 longjmp(errcatch, 0); 2239 } 2240 } 2241 2242 void upper(char *s) 2243 { 2244 while (*s != '\0') { 2245 if (islower(*s)) 2246 *s = toupper(*s); 2247 s++; 2248 } 2249 } 2250 2251 char *copy(char *s) 2252 { 2253 char *p; 2254 2255 p = strdup(s); 2256 if (p == NULL) 2257 fatal("Ran out of memory."); 2258 return (p); 2259 } 2260 2261 void help(struct tab *ctab, char *s) 2262 { 2263 struct aclmember *entry = NULL; 2264 struct tab *c; 2265 size_t width, NCMDS; 2266 char *type; 2267 2268 if (ctab == sitetab) 2269 type = "SITE "; 2270 else 2271 type = ""; 2272 width = 0, NCMDS = 0; 2273 for (c = ctab; c->name != NULL; c++) { 2274 size_t len = strlen(c->name); 2275 2276 if (len > width) 2277 width = len; 2278 NCMDS++; 2279 } 2280 width = (width + 8) & ~7; 2281 if (s == 0) { 2282 register size_t i, j, w; 2283 size_t columns, lines; 2284 2285 lreply(214, "The following %scommands are recognized %s.", 2286 type, "(* =>'s unimplemented)"); 2287 columns = 76 / width; 2288 if (columns == 0) 2289 columns = 1; 2290 lines = (NCMDS + columns - 1) / columns; 2291 for (i = 0; i < lines; i++) { 2292 char line[BUFSIZ], *ptr = line; 2293 ptr += strlcpy(line, " ", sizeof(line)); 2294 for (j = 0; j < columns; j++) { 2295 c = ctab + j * lines + i; 2296 (void) snprintf(ptr, line + sizeof(line) - ptr, "%s%c", 2297 c->name, c->implemented ? ' ' : '*'); 2298 w = strlen(c->name) + 1; 2299 ptr += w; 2300 if (c + lines >= &ctab[NCMDS]) 2301 break; 2302 while (w < width) { 2303 *(ptr++) = ' '; 2304 w++; 2305 } 2306 } 2307 *ptr = '\0'; 2308 lreply(0, "%s", line); 2309 } 2310 (void) fflush(stdout); 2311 #ifdef VIRTUAL 2312 if (virtual_mode && !virtual_ftpaccess && virtual_email[0] != '\0') 2313 reply(214, "Direct comments to %s.", virtual_email); 2314 else 2315 #endif 2316 if ((getaclentry("email", &entry)) && ARG0) 2317 reply(214, "Direct comments to %s.", ARG0); 2318 else 2319 reply(214, "Direct comments to ftp-bugs@%s.", hostname); 2320 return; 2321 } 2322 upper(s); 2323 c = lookup(ctab, s); 2324 if (c == (struct tab *) NULL) { 2325 reply(502, "Unknown command %s.", s); 2326 return; 2327 } 2328 if (c->implemented) 2329 reply(214, "Syntax: %s%s %s", type, c->name, c->help); 2330 else 2331 reply(214, "%s%-*s\t%s; unimplemented.", type, width, 2332 c->name, c->help); 2333 } 2334 2335 void sizecmd(char *filename) 2336 { 2337 switch (type) { 2338 case TYPE_L: 2339 case TYPE_I:{ 2340 struct stat stbuf; 2341 if (stat(filename, &stbuf) < 0 || 2342 (stbuf.st_mode & S_IFMT) != S_IFREG) 2343 reply(550, "%s: not a plain file.", filename); 2344 else 2345 reply(213, "%" L_FORMAT, stbuf.st_size); 2346 break; 2347 } 2348 case TYPE_A:{ 2349 FILE *fin; 2350 register int c; 2351 register off_t count; 2352 struct stat stbuf; 2353 fin = fopen(filename, "r"); 2354 if (fin == NULL) { 2355 perror_reply(550, filename); 2356 return; 2357 } 2358 if (fstat(fileno(fin), &stbuf) < 0 || 2359 (stbuf.st_mode & S_IFMT) != S_IFREG) { 2360 reply(550, "%s: not a plain file.", filename); 2361 (void) fclose(fin); 2362 return; 2363 } 2364 2365 count = 0; 2366 while ((c = getc(fin)) != EOF) { 2367 if (c == '\n') /* will get expanded to \r\n */ 2368 count++; 2369 count++; 2370 } 2371 (void) fclose(fin); 2372 2373 reply(213, "%" L_FORMAT, count); 2374 break; 2375 } 2376 default: 2377 reply(504, "SIZE not implemented for Type %c.", "?AEIL"[type]); 2378 } 2379 } 2380 2381 void site_exec(char *cmd) 2382 { 2383 #ifdef PARANOID 2384 syslog(LOG_CRIT, "REFUSED SITE_EXEC (slipped through!!): %s", cmd); 2385 #else 2386 char buf[MAXPATHLEN]; 2387 char *sp = (char *) strchr(cmd, ' '), *slash, *t; 2388 FILE *cmdf; 2389 2390 2391 /* sanitize the command-string */ 2392 2393 if (sp == 0) { 2394 while ((slash = strchr(cmd, '/')) != 0) 2395 cmd = slash + 1; 2396 } 2397 else { 2398 while (sp && (slash = (char *) strchr(cmd, '/')) 2399 && (slash < sp)) 2400 cmd = slash + 1; 2401 } 2402 2403 for (t = cmd; *t && !isspace(*t); t++) { 2404 if (isupper(*t)) { 2405 *t = tolower(*t); 2406 } 2407 } 2408 2409 /* build the command */ 2410 if (strlen(_PATH_EXECPATH) + strlen(cmd) + 2 > sizeof(buf)) 2411 return; 2412 (void) snprintf(buf, sizeof(buf), "%s/%s", _PATH_EXECPATH, cmd); 2413 2414 cmdf = ftpd_popen(buf, "r", 0); 2415 if (!cmdf) { 2416 perror_reply(550, cmd); 2417 if (log_commands) 2418 syslog(LOG_INFO, "SITE EXEC (FAIL: %m): %s", cmd); 2419 } 2420 else { 2421 int lines = 0; 2422 int maxlines = 0; 2423 struct aclmember *entry = NULL; 2424 char class[BUFSIZ]; 2425 int maxfound = 0; 2426 int defmaxlines = 20; 2427 int which; 2428 2429 (void) acl_getclass(class); 2430 while ((getaclentry("site-exec-max-lines", &entry)) && ARG0) { 2431 if (ARG1) 2432 for (which = 1; (which < MAXARGS) && ARG[which]; which++) { 2433 if (!strcasecmp(ARG[which], class)) { 2434 maxlines = atoi(ARG0); 2435 maxfound = 1; 2436 } 2437 if (!strcmp(ARG[which], "*")) 2438 defmaxlines = atoi(ARG0); 2439 } 2440 else 2441 defmaxlines = atoi(ARG0); 2442 } 2443 if (!maxfound) 2444 maxlines = defmaxlines; 2445 lreply(200, "%s", cmd); 2446 while (fgets(buf, sizeof buf, cmdf)) { 2447 size_t len = strlen(buf); 2448 2449 if (len > 0 && buf[len - 1] == '\n') 2450 buf[--len] = '\0'; 2451 lreply(200, "%s", buf); 2452 if (maxlines <= 0) 2453 ++lines; 2454 else if (++lines >= maxlines) { 2455 lreply(200, "*** Truncated ***"); 2456 break; 2457 } 2458 } 2459 reply(200, " (end of '%s')", cmd); 2460 if (log_commands) 2461 syslog(LOG_INFO, "SITE EXEC (lines: %d): %s", lines, cmd); 2462 ftpd_pclose(cmdf); 2463 } 2464 #endif /* PARANOID */ 2465 } 2466 2467 void alias(char *s) 2468 { 2469 struct aclmember *entry = NULL; 2470 2471 if (s != (char *) NULL) { 2472 while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL) 2473 if (!strcmp(ARG0, s)) { 2474 reply(214, "%s is an alias for %s.", ARG0, ARG1); 2475 return; 2476 } 2477 reply(502, "Unknown alias %s.", s); 2478 return; 2479 } 2480 2481 lreply(214, "The following aliases are available."); 2482 2483 while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL) 2484 lreply(0, " %-8s %s", ARG0, ARG1); 2485 (void) fflush(stdout); 2486 2487 reply(214, ""); 2488 } 2489 2490 void cdpath(void) 2491 { 2492 struct aclmember *entry = NULL; 2493 2494 lreply(214, "The cdpath is:"); 2495 while (getaclentry("cdpath", &entry) && ARG0 != NULL) 2496 lreply(0, " %s", ARG0); 2497 (void) fflush(stdout); 2498 reply(214, ""); 2499 } 2500 2501 void print_groups(void) 2502 { 2503 gid_t *groups; 2504 int ngroups; 2505 int maxgrp; 2506 2507 maxgrp = getgroups(0, NULL); 2508 2509 groups = alloca(maxgrp * sizeof (gid_t)); 2510 2511 if ((ngroups = getgroups(maxgrp, groups)) < 0) { 2512 return; 2513 } 2514 2515 lreply(214, "Group membership is:"); 2516 ngroups--; 2517 2518 for (; ngroups >= 0; ngroups--) 2519 lreply(214, " %d", groups[ngroups]); 2520 2521 (void) fflush(stdout); 2522 reply(214, ""); 2523 }