📄 ftpcmd.y
字号:
/**************************************************************************** Copyright (c) 1999,2000,2001 WU-FTPD Development Group. All rights reserved. Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994 The Regents of the University of California. Portions Copyright (c) 1993, 1994 Washington University in Saint Louis. Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc. Portions Copyright (c) 1989 Massachusetts Institute of Technology. Portions Copyright (c) 1998 Sendmail, Inc. Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P. Allman. Portions Copyright (c) 1997 by Stan Barber. Portions Copyright (c) 1997 by Kent Landfield. Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. Use and distribution of this software and its source code are governed by the terms and conditions of the WU-FTPD Software License ("LICENSE"). If you did not receive a copy of the license, it may be obtained online at http://www.wu-ftpd.org/license.html. $Id: ftpcmd.y,v 1.27.2.2 2001/11/29 17:01:38 wuftpd Exp $ ****************************************************************************/ /* * Grammar for FTP commands. * See RFC 959. */%{#include "config.h"#include <sys/param.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/stat.h>#include <netinet/in.h>#include <arpa/inet.h>#include "../support/ftp.h"#include <stdio.h>#include <signal.h>#include <errno.h>#include <ctype.h>#include <pwd.h>#include <setjmp.h>#ifdef HAVE_SYS_SYSLOG_H#include <sys/syslog.h>#endif#if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))#include <syslog.h>#endif#include <time.h>#include <stdlib.h>#include <string.h>#include <limits.h>#include "extensions.h"#include "pathnames.h"#include "proto.h"extern int dolreplies;#ifndef INTERNAL_LSextern char ls_long[50];extern char ls_short[50];#endifextern struct sockaddr_in data_dest;extern struct sockaddr_in his_addr; /* added. _H */extern int logged_in;extern struct passwd *pw;extern int anonymous;extern int logging;extern int log_commands;extern int log_security;extern int type;extern int form;extern int debug;extern unsigned int timeout_idle;extern unsigned int timeout_maxidle;extern int pdata;extern char hostname[], remotehost[], *remoteident;extern char remoteaddr[];extern char chroot_path[];extern char guestpw[], authuser[]; /* added. _H */extern char proctitle[];extern char *globerr;extern int usedefault;extern int transflag;extern char tmpline[];extern int data;extern int errno;extern char *home;off_t restart_point;int yyerrorcalled;extern char *strunames[];extern char *typenames[];extern char *modenames[];extern char *formnames[];extern int restricted_user; /* global flag indicating if user is restricted to home directory */#ifdef TRANSFER_COUNTextern int data_count_total;extern int data_count_in;extern int data_count_out;extern int byte_count_total;extern int byte_count_in;extern int byte_count_out;extern int file_count_total;extern int file_count_in;extern int file_count_out;extern int xfer_count_total;extern int xfer_count_in;extern int xfer_count_out;#endifextern int retrieve_is_data;#ifdef VIRTUALextern int virtual_mode;extern int virtual_ftpaccess;extern char virtual_email[];#endif#ifdef IGNORE_NOOPstatic int alarm_running = 0;#endifstatic unsigned short cliport = 0;static struct in_addr cliaddr;static int cmd_type;static int cmd_form;static int cmd_bytesz;char cbuf[512];char *fromname;/* Debian linux bison fix: moved this up, added forward decls */struct tab { char *name; short token; short state; short implemented; /* 1 if command is implemented */ char *help;};extern struct tab cmdtab[];extern struct tab sitetab[];static void toolong(int);void help(struct tab *ctab, char *s);struct tab *lookup(register struct tab *p, char *cmd);int yylex(void);static char *nullstr = "(null)";#define CHECKNULL(p) ((p) ? (p) : nullstr)extern int pasv_allowed(const char *remoteaddr);extern int port_allowed(const char *remoteaddr);%}%token A B C E F I L N P R S T SP CRLF COMMA STRING NUMBER USER PASS ACCT REIN QUIT PORT PASV TYPE STRU MODE RETR STOR APPE MLFL MAIL MSND MSOM MSAM MRSQ MRCP ALLO REST RNFR RNTO ABOR DELE CWD LIST NLST SITE STAT HELP NOOP MKD RMD PWD CDUP STOU SMNT SYST SIZE MDTM UMASK IDLE CHMOD GROUP GPASS NEWER MINFO INDEX EXEC ALIAS CDPATH GROUPS CHECKMETHOD CHECKSUM LEXERR%union { char *String; int Number;}%type <String> STRING password pathname pathstring username method%type <Number> NUMBER byte_size check_login form_code %type <Number> struct_code mode_code octal_number%start cmd_list%%cmd_list: /* empty */ | cmd_list cmd = { fromname = (char *) NULL; restart_point = 0; } | cmd_list rcmd ;cmd: USER SP username CRLF = { user($3); if (log_commands) syslog(LOG_INFO, "USER %s", $3); free($3); } | PASS SP password CRLF = { if (log_commands) if (anonymous) syslog(LOG_INFO, "PASS %s", $3); else syslog(LOG_INFO, "PASS password"); pass($3); free($3); } | PORT check_login SP host_port CRLF = { if (log_commands) syslog(LOG_INFO, "PORT");/* H* port fix, part B: admonish the twit. Also require login before PORT works */ if ($2) {#ifndef DISABLE_PORT if (((cliaddr.s_addr == his_addr.sin_addr.s_addr) || (port_allowed(inet_ntoa(cliaddr)))) && (ntohs(cliport) > 1023)) { usedefault = 0; if (pdata >= 0) { (void) close(pdata); pdata = -1; } data_dest.sin_family = AF_INET; data_dest.sin_addr = cliaddr; data_dest.sin_port = cliport; reply(200, "PORT command successful."); } else {#endif memset(&data_dest, 0, sizeof(data_dest)); syslog(LOG_WARNING, "refused PORT %s,%d from %s", inet_ntoa(cliaddr), ntohs(cliport), remoteident); reply(500, "Illegal PORT Command");#ifndef DISABLE_PORT }#endif } } | PASV check_login CRLF = {/* Require login for PASV, too. This actually fixes a bug -- telnet to an unfixed wu-ftpd and type PASV first off, and it crashes! */ if (log_commands) syslog(LOG_INFO, "PASV"); if ($2)#if (defined (DISABLE_PORT) || !defined (DISABLE_PASV)) passive();#else reply(425, "Cannot open passive connection");#endif } | TYPE check_login SP type_code CRLF = { if (log_commands) syslog(LOG_INFO, "TYPE %s", typenames[cmd_type]); if ($2) switch (cmd_type) { case TYPE_A: if (cmd_form == FORM_N) { reply(200, "Type set to A."); type = cmd_type; form = cmd_form; } else reply(504, "Form must be N."); break; case TYPE_E: reply(504, "Type E not implemented."); break; case TYPE_I: reply(200, "Type set to I."); type = cmd_type; break; case TYPE_L:#if NBBY == 8 if (cmd_bytesz == 8) { reply(200, "Type set to L (byte size 8)."); type = cmd_type; } else reply(504, "Byte size must be 8.");#else /* NBBY == 8 */#error UNIMPLEMENTED for NBBY != 8#endif /* NBBY == 8 */ } } | STRU check_login SP struct_code CRLF = { if (log_commands) syslog(LOG_INFO, "STRU %s", strunames[$4]); if ($2) switch ($4) { case STRU_F: reply(200, "STRU F ok."); break; default: reply(504, "Unimplemented STRU type."); } } | MODE check_login SP mode_code CRLF = { if (log_commands) syslog(LOG_INFO, "MODE %s", modenames[$4]); if ($2) switch ($4) { case MODE_S: reply(200, "MODE S ok."); break; default: reply(502, "Unimplemented MODE type."); } } | ALLO check_login SP NUMBER CRLF = { if (log_commands) syslog(LOG_INFO, "ALLO %d", $4); if ($2) reply(202, "ALLO command ignored."); } | ALLO check_login SP NUMBER SP R SP NUMBER CRLF = { if (log_commands) syslog(LOG_INFO, "ALLO %d R %d", $4, $8); if ($2) reply(202, "ALLO command ignored."); } | RETR check_login SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "RETR %s", CHECKNULL($4)); if ($2 && $4 != NULL && !restrict_check($4)) { retrieve_is_data = 1; retrieve((char *) NULL, $4); } if ($4 != NULL) free($4); } | STOR check_login SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "STOR %s", CHECKNULL($4)); if ($2 && $4 != NULL && !restrict_check($4)) store($4, "w", 0); if ($4 != NULL) free($4); } | APPE check_login SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "APPE %s", CHECKNULL($4)); if ($2 && $4 != NULL && !restrict_check($4)) store($4, "a", 0); if ($4 != NULL) free($4); } | NLST check_login CRLF = { if (log_commands) syslog(LOG_INFO, "NLST"); if ($2 && !restrict_check(".")) send_file_list(""); } | NLST check_login SP STRING CRLF = { if (log_commands) syslog(LOG_INFO, "NLST %s", $4); if ($2 && $4 && !restrict_check($4)) send_file_list($4); if ($4 != NULL) free($4); } | LIST check_login CRLF = { if (log_commands) syslog(LOG_INFO, "LIST"); if ($2 && !restrict_check(".")) { retrieve_is_data = 0;#ifndef INTERNAL_LS if (anonymous && dolreplies) retrieve(ls_long, ""); else retrieve(ls_short, "");#else ls(NULL, 0);#endif } } | LIST check_login SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "LIST %s", CHECKNULL($4)); if ($2 && $4 != NULL && !restrict_list_check($4)) { retrieve_is_data = 0;#ifndef INTERNAL_LS if (anonymous && dolreplies) retrieve(ls_long, $4); else retrieve(ls_short, $4);#else ls($4, 0);#endif } if ($4 != NULL) free($4); } | STAT check_login SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "STAT %s", CHECKNULL($4)); if ($2 && $4 != NULL && !restrict_check($4)) statfilecmd($4); if ($4 != NULL) free($4); } | STAT check_login CRLF = { if (log_commands) syslog(LOG_INFO, "STAT"); if ($2) statcmd(); } | DELE check_login SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "DELE %s", CHECKNULL($4)); if ($2 && $4 != NULL && !restrict_check($4)) delete($4); if ($4 != NULL) free($4); } | RNTO check_login SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "RNTO %s", CHECKNULL($4)); if ($2 && $4 && !restrict_check($4)) { if (fromname) { renamecmd(fromname, $4); free(fromname); fromname = (char *) NULL; } else { reply(503, "Bad sequence of commands."); } } if ($4) free($4); } | ABOR check_login CRLF = { if (log_commands) syslog(LOG_INFO, "ABOR"); if ($2) reply(225, "ABOR command successful."); } | CWD check_login CRLF = { if (log_commands) syslog(LOG_INFO, "CWD"); if ($2 && !restrict_check(home)) cwd(home); } | CWD check_login SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "CWD %s", CHECKNULL($4)); if ($2 && $4 != NULL && !restrict_check($4)) cwd($4); if ($4 != NULL) free($4); } | HELP check_login CRLF = { if (log_commands) syslog(LOG_INFO, "HELP"); if ($2) help(cmdtab, (char *) NULL); } | HELP check_login SP STRING CRLF = { register char *cp = (char *) $4; if (log_commands) syslog(LOG_INFO, "HELP %s", $4); if ($2) if (strncasecmp(cp, "SITE", 4) == 0) { cp = (char *) $4 + 4; if (*cp == ' ') cp++; if (*cp) help(sitetab, cp); else help(sitetab, (char *) NULL); } else help(cmdtab, $4); if ($4 != NULL) free($4); } | NOOP check_login CRLF = { if (log_commands) syslog(LOG_INFO, "NOOP"); if ($2) reply(200, "NOOP command successful."); } | MKD check_login SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "MKD %s", CHECKNULL($4)); if ($2 && $4 != NULL && !restrict_check($4)) makedir($4); if ($4 != NULL) free($4); } | RMD check_login SP pathname CRLF = { if (log_commands) syslog(LOG_INFO, "RMD %s", CHECKNULL($4)); if ($2 && $4 != NULL && !restrict_check($4)) removedir($4); if ($4 != NULL) free($4); } | PWD check_login CRLF = { if (log_commands) syslog(LOG_INFO, "PWD"); if ($2) pwd(); } | CDUP check_login CRLF = { if (log_commands) syslog(LOG_INFO, "CDUP"); if ($2) if (!test_restriction("..")) cwd(".."); else ack("CWD"); } | SITE check_login SP HELP CRLF = { if (log_commands) syslog(LOG_INFO, "SITE HELP"); if ($2) help(sitetab, (char *) NULL); } | SITE check_login SP HELP SP STRING CRLF = { if (log_commands) syslog(LOG_INFO, "SITE HELP %s", $6); if ($2) help(sitetab, $6); if ($6 != NULL) free($6); } | SITE check_login SP UMASK CRLF = { mode_t oldmask; if (log_commands) syslog(LOG_INFO, "SITE UMASK"); if ($2) { oldmask = umask(0); (void) umask(oldmask); reply(200, "Current UMASK is %03o", oldmask); } } | SITE check_login SP UMASK SP octal_number CRLF = { mode_t oldmask; struct aclmember *entry = NULL; int ok = 1; if (log_commands) syslog(LOG_INFO, "SITE UMASK %03o", $6); if ($2) { /* check for umask permission */ while (getaclentry("umask", &entry) && ARG0 && ARG1 != NULL) { if (type_match(ARG1)) if (*ARG0 == 'n') ok = 0; } if (ok && !restricted_user) { if (($6 < 0) || ($6 > 0777)) { reply(501, "Bad UMASK value"); } else { oldmask = umask((mode_t) $6); reply(200, "UMASK set to %03o (was %03o)", $6, oldmask); } } else reply(553, "Permission denied on server. (umask)"); } } | SITE check_login SP CHMOD SP octal_number SP pathname CRLF = { struct aclmember *entry = NULL; int ok = (anonymous ? 0 : 1); if (log_commands) syslog(LOG_INFO, "SITE CHMOD %03o %s", $6, CHECKNULL($8)); if ($2 && $8) { /* check for chmod permission */ while (getaclentry("chmod", &entry) && ARG0 && ARG1 != NULL) { if (type_match(ARG1)) if (anonymous) { if (*ARG0 == 'y') ok = 1; } else if (*ARG0 == 'n') ok = 0; } if (ok) {#ifdef UNRESTRICTED_CHMOD if (chmod($8, (mode_t) $6) < 0)#else if (($6 < 0) || ($6 > 0777)) reply(501, "CHMOD: Mode value must be between 0 and 0777"); else if (chmod($8, (mode_t) $6) < 0)#endif perror_reply(550, $8); else { char path[MAXPATHLEN]; wu_realpath($8, path, chroot_path); if (log_security) if (anonymous) { syslog(LOG_NOTICE, "%s of %s changed permissions for %s", guestpw, remoteident, path); } else { syslog(LOG_NOTICE, "%s of %s changed permissions for %s", pw->pw_name, remoteident, path); } reply(200, "CHMOD command successful."); } } else reply(553, "Permission denied on server. (chmod)"); } if ($8 != NULL) free($8); } | SITE check_login SP IDLE CRLF = {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -