📄 ftp_parser.c
字号:
#include <config.h>#include "ftpd.h"#include "dynamic.h"#include "ftpwho-update.h"#include "globals.h"#include "messages.h"#ifdef WITH_DIRALIASES# include "diraliases.h"#endif#ifdef WITH_TLS# include "tls.h"#endif#ifdef WITH_DMALLOC# include <dmalloc.h>#endifstatic void antiidle(void){ if (noopidle == (time_t) -1) { noopidle = time(NULL); } else { if ((time(NULL) - noopidle) > (time_t) idletime_noop) { die(421, LOG_INFO, MSG_TIMEOUT_NOOP, (unsigned long) idletime_noop); } } }/* * Introduce a random delay, to avoid guessing existing user names by * mesuring delay. It's especially true when LDAP is used. * No need to call usleep2() because we are root at this point. */static void randomdelay(void){ usleep(rand() % 15000UL); /* dummy... no need for arc4 */}/* * Simple but fast command-line reader. We break the FTP protocol here, * because we deny access to files with strange characters in their name. * Now, I seriously doubt that clients should be allowed to upload files * with carriage returns, bells, cursor moves and other fancy stuff in the * names. It can indirectly lead to security flaws with scripts, it's * annoying for the sysadmin, it can be a client error, it can bring unexpected * results on some filesystems, etc. So control chars are replaced by "_". * Better be safe than 100% RFC crap compliant but unsafe. If you really want * RFC compliance, define RFC_CONFORMANT_PARSER. But I will hate you. * * RFC_CONFORMANT_LINES is another thing that clients should implement * properly (and it's trivial to do) : lines must be ended with \r\n . * Guess what ? * Some broken clients are just sending \n ... Grrrrrrrrrrrr !!!!!!!!!!!!!!! * * -Frank. */int sfgets(void){ fd_set rs; struct timeval tv; ssize_t readen; signed char seen_r = 0; static size_t scanned; static size_t readend; if (scanned > (size_t) 0U) { /* support pipelining */ readend -= scanned; memmove(cmd, cmd + scanned, readend); /* safe */ scanned = (size_t) 0U; } tv.tv_sec = idletime; tv.tv_usec = 0; FD_ZERO(&rs); while (scanned < cmdsize) { if (scanned >= readend) { /* nothing left in the buffer */ FD_SET(0, &rs); while (select(1, &rs, NULL, NULL, &tv) <= 0 && errno == EINTR); if (FD_ISSET(0, &rs) == 0) { return -1; } if (readend >= cmdsize) { break; }#ifdef WITH_TLS if (tls_cnx != NULL) { while ((readen = SSL_read (tls_cnx, cmd + readend, cmdsize - readend)) < (ssize_t) 0 && errno == EINTR); } else#endif { while ((readen = read(0, cmd + readend, cmdsize - readend)) < (ssize_t) 0 && errno == EINTR); } if (readen <= (ssize_t) 0) { return -2; } readend += readen; if (readend > cmdsize) { return -2; } }#ifdef RFC_CONFORMANT_LINES if (seen_r != 0) {#endif if (cmd[scanned] == '\n') {#ifndef RFC_CONFORMANT_LINES if (seen_r != 0) {#endif cmd[scanned - 1U] = 0;#ifndef RFC_CONFORMANT_LINES } else { cmd[scanned] = 0; }#endif if (++scanned >= readend) { /* non-pipelined command */ scanned = readend = (size_t) 0U; } return 0; } seen_r = 0;#ifdef RFC_CONFORMANT_LINES }#endif if (ISCTRLCODE(cmd[scanned])) { if (cmd[scanned] == '\r') { seen_r = 1; }#ifdef RFC_CONFORMANT_PARSER /* disabled by default, intentionnaly */ else if (cmd[scanned] == 0) { cmd[scanned] = '\n'; }#else /* replace control chars with _ */ cmd[scanned] = '_'; #endif } scanned++; } die(421, LOG_WARNING, MSG_LINE_TOO_LONG); /* don't remove this */ return 0; /* to please GCC */}/* Replace extra spaces before and after a string with '_' */#ifdef MINIMAL# define revealextraspc(X) (X)#elsestatic char *revealextraspc(char * const s_){ register unsigned char *s = (unsigned char *) s_; register unsigned char *sn; if (s == NULL) { return s_; } simplify(s_); while (*s != 0U && isspace(*s)) { *s++ = '_'; } if (*s == 0U) { return s_; } sn = s; do { sn++; } while (*sn != 0U); do { sn--; if (!isspace(*sn)) { break; } *sn = '_'; } while (sn != s); return s_;}#endifvoid parser(void){ char *arg;#ifndef MINIMAL char *sitearg;#endif size_t n; for (;;) { xferfd = -1; if (state_needs_update != 0) { state_needs_update = 0; setprogname("pure-ftpd (IDLE)");#ifdef FTPWHO if (shm_data_cur != NULL) { ftpwho_lock(); shm_data_cur->state = FTPWHO_STATE_IDLE; *shm_data_cur->filename = 0; ftpwho_unlock(); }#endif } doreply(); alarm(idletime * 2); switch (sfgets()) { case -1:#ifdef BORING_MODE die(421, LOG_INFO, MSG_TIMEOUT);#else die(421, LOG_INFO, MSG_TIMEOUT_PARSER);#endif case -2: return; }#ifdef DEBUG if (debug != 0) { addreply(0, "%s", cmd); }#endif n = (size_t) 0U; while ((isalpha((unsigned char) cmd[n]) || cmd[n] == '@') && n < cmdsize) { cmd[n] = (char) tolower((unsigned char) cmd[n]); n++; } if (n >= cmdsize) { /* overparanoid, it should never happen */ die(421, LOG_WARNING, MSG_LINE_TOO_LONG); } if (n == (size_t) 0U) { nop: addreply_noformat(500, "?"); continue; }#ifdef SKIP_COMMAND_TRAILING_SPACES while (isspace((unsigned char) cmd[n]) && n < cmdsize) { cmd[n++] = 0; } arg = cmd + n; while (cmd[n] != 0 && n < cmdsize) { n++; } n--; while (isspace((unsigned char) cmd[n])) { cmd[n--] = 0; }#else if (cmd[n] == 0) { arg = cmd + n; } else if (isspace((unsigned char) cmd[n])) { cmd[n] = 0; arg = cmd + n + 1; } else { goto nop; }#endif if (logging != 0) {#ifdef DEBUG logfile(LOG_DEBUG, MSG_DEBUG_COMMAND " [%s] [%s]", cmd, arg);#else logfile(LOG_DEBUG, MSG_DEBUG_COMMAND " [%s] [%s]", cmd, strcmp(cmd, "pass") ? arg : "<*>");#endif } /* * antiidle() is called with dummy commands, usually used by clients * who are wanting extra idle time. We give them some, but not too much. * When we jump to wayout, the idle timer is not zeroed. It means that * we didn't issue an 'active' command like RETR. */ #ifndef MINIMAL if (!strcmp(cmd, "noop") || !strcmp(cmd, "allo")) { antiidle(); donoop(); goto wayout; }#endif if (!strcmp(cmd, "user")) {#ifdef WITH_TLS if (enforce_tls_auth > 1 && tls_cnx == NULL) { die(421, LOG_WARNING, MSG_TLS_NEEDED); }#endif douser(arg); } else if (!strcmp(cmd, "acct")) { addreply(202, MSG_WHOAREYOU); } else if (!strcmp(cmd, "pass")) { if (guest == 0) { randomdelay(); } dopass(arg); } else if (!strcmp(cmd, "quit")) { addreply(221, MSG_GOODBYE, (unsigned long long) ((uploaded + 1023ULL) / 1024ULL), (unsigned long long) ((downloaded + 1023ULL) / 1024ULL)); return; } else if (!strcmp(cmd, "syst")) { antiidle(); addreply_noformat(215, "UNIX Type: L8"); goto wayout;#ifdef WITH_TLS } else if (enforce_tls_auth > 0 && !strcmp(cmd, "auth") && !strcasecmp(arg, "tls")) { addreply_noformat(234, "AUTH TLS OK."); doreply(); if (tls_cnx == NULL) { (void) tls_init_new_session();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -