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