📄 ftpd.c
字号:
#include <config.h>#define DEFINE_GLOBALS#include "messages.h"#include "ftpd_p.h"#include "ipv4stack.h"#include "dynamic.h"#include "ftpwho-update.h"#include "ftpwho-read.h"#include "globals.h"#include "caps.h"#if defined(WITH_UPLOAD_SCRIPT)# include "upload-pipe.h"#endif#ifdef WITH_ALTLOG# include "altlog.h"#endif#ifdef QUOTAS# include "quotas.h"#endif#ifdef WITH_DIRALIASES# include "diraliases.h"#endif#include "ftpd.h"#include "bsd-glob.h"#include "getloadavg.h"#ifdef WITH_PRIVSEP# include "privsep.h"#endif#ifdef WITH_TLS# include "tls.h"#endif#ifdef WITH_DMALLOC# include <dmalloc.h>#endif#ifndef HAVE_SYS_FSUID_Hvoid disablesignals(void){ sigset_t sigs; sigfillset(&sigs); if (sigprocmask(SIG_BLOCK, &sigs, &old_sigmask) < 0) { _EXIT(EXIT_FAILURE); }}static void enablesignals(void){ if (sigprocmask(SIG_SETMASK, &old_sigmask, NULL) < 0) { _EXIT(EXIT_FAILURE); }}void usleep2(const unsigned long microsec){ disablesignals(); usleep(microsec); enablesignals();}#endifint safe_write(const int fd, const void *buf_, size_t count){ ssize_t written; register const char *buf = (const char *) buf_; while (count > (size_t) 0U) { for (;;) { if ((written = write(fd, buf, count)) <= (ssize_t) 0) { if (errno == EAGAIN) { sleep(1); } else if (errno != EINTR) { return -1; } continue; } break; } buf += written; count -= written; } return 0;}static void overlapcpy(register char *d, register const char *s){ while (*s != 0) { *d++ = *s++; } *d = 0;}static void safe_fd_set(const int fd, fd_set * const fds){ if (fd == -1) { return; } FD_SET(fd, fds); }static int safe_fd_isset(const int fd, const fd_set * const fds){ if (fd == -1) { return 0; } return FD_ISSET(fd, fds);}void simplify(char *subdir){ char *a; if (subdir == NULL || *subdir == 0) { return; } while ((a = strstr(subdir, "//")) != NULL) { overlapcpy(a, a + 1); } while ((a = strstr(subdir, "/./")) != NULL) { overlapcpy(a, a + 2); } while (strncmp(subdir, "../", 3) == 0) { subdir += 3; } a = strstr(subdir, "/../"); if (a != NULL) { if (a == subdir) { while (strncmp(subdir, "/../", 4) == 0) { overlapcpy(subdir, subdir + 3); } a = strstr(subdir, "/../"); } while (a != NULL) { char *nextcomponent = a + 4; if (a != subdir && *a == '/') { a--; } while (a != subdir && *a != '/') { a--; } if (*a == '/') { a++; } overlapcpy(a, nextcomponent); a = strstr(subdir, "/../"); } } a = subdir; if (*a == '.') { a++; if (*a == 0) { return; } if (*a == '/') { while (*a == '/') { a++; } overlapcpy(subdir, a); } }}int checkprintable(register const char *s){ register int ret = 0; register unsigned char c; while ((c = (unsigned char) *s) != 0U) { if (ISCTRLCODE(c)) { ret--; break; } s++; } return ret; }void die(const int err, const int priority, const char * const format, ...){ va_list va; char line[MAX_SYSLOG_LINE]; va_start(va, format);#ifndef HAVE_SYS_FSUID_H disablesignals();#endif vsnprintf(line, sizeof line, format, va); printf("%d %s\r\n", err, line); fflush(stdout); logfile(priority, "%s", line); va_end(va); _EXIT(-priority - 1);}void die_mem(void){ die(421, LOG_ERR, MSG_OUT_OF_MEMORY);}static RETSIGTYPE sigurg(int sig){ int olderrno; int readen; unsigned char fodder; (void) sig; if (xferfd == -1) { return; } olderrno = errno; closedata();#ifndef HAVE_SYS_FSUID_H disablesignals();#endif addreply_noformat(426, MSG_ABORTED); doreply(); do { if ((readen = read(0, &fodder, (size_t) 1U)) < (ssize_t) 0 && errno == EINTR) { continue; } } while (readen > (ssize_t) 0 && fodder != '\n'); addreply_noformat(226, MSG_ABORTED); doreply();#ifndef HAVE_SYS_FSUID_H enablesignals();#endif errno = olderrno;}static RETSIGTYPE sigalarm(int sig){ (void) sig;#ifndef HAVE_SYS_FSUID_H disablesignals();#endif die(421, LOG_INFO, MSG_TIMEOUT);}#ifndef NO_STANDALONEstatic RETSIGTYPE sigchild(int sig){ const int olderrno = errno; pid_t pid; (void) sig;#ifdef HAVE_WAITPID while ((pid = waitpid((pid_t) -1, NULL, WNOHANG)) > (pid_t) 0) { if (nb_children > 0U) { nb_children--; }# ifdef FTPWHO ftpwho_unlinksbfile(pid);# endif iptrack_delete_pid(pid); }#else while ((pid = wait3(NULL, WNOHANG, NULL)) > (pid_t) 0) { if (nb_children > 0U) { nb_children--; }# ifdef FTPWHO ftpwho_unlinksbfile(pid);# endif iptrack_delete_pid(pid); }#endif errno = olderrno;}#endifstatic RETSIGTYPE sigterm_client(int sig){ (void) sig; #ifndef HAVE_SYS_FSUID_H disablesignals();#endif _EXIT(EXIT_SUCCESS);}#ifndef NO_STANDALONEstatic RETSIGTYPE sigterm(int sig){ const int olderrno = errno; (void) sig; stop_server = 1; if (listenfd != -1) { shutdown(listenfd, 2); (void) close(listenfd); } errno = olderrno;}static void set_cloexec_flag(const int fd){ fcntl(fd, F_SETFD, FD_CLOEXEC);}#endifstatic void clearargs(int argc, char **argv){#ifndef NO_PROCNAME_CHANGE# if defined(__linux__) && !defined(HAVE_SETPROCTITLE) int i; for (i = 0; environ[i] != NULL; i++); argv0 = argv; if (i > 0) { argv_lth = environ[i-1] + strlen(environ[i-1]) - argv0[0]; } else { argv_lth = argv0[argc-1] + strlen(argv0[argc-1]) - argv0[0]; } if (environ != NULL) { char **new_environ; unsigned int env_nb = 0U; while (environ[env_nb] != NULL) { env_nb++; } if ((new_environ = malloc((1U + env_nb) * sizeof (char *))) == NULL) { abort(); } new_environ[env_nb] = NULL; while (env_nb > 0U) { env_nb--; /* Can any bad thing happen if strdup() ever fails? */ new_environ[env_nb] = strdup(environ[env_nb]); } environ = new_environ; }# else (void) argc; (void) argv;# endif#endif}void setprogname(const char * const title){#ifndef NO_PROCNAME_CHANGE# ifdef HAVE_SETPROCTITLE setproctitle("-%s", title);# elif defined(__linux__) if (argv0 != NULL) { memset(argv0[0], 0, argv_lth); strncpy(argv0[0], title, argv_lth - 2); argv0[1] = NULL; }# elif defined(__hpux__) union pstun pst; pst.pst_command = title; pstat(PSTAT_SETCMD, pst, strlen(title), 0, 0);# endif#endif (void) title;}/* Check whether an address is valid, return 1 if ok, 0 otherwise. * Unfortunately, multicasting with the FTP protocol is impossible, * you have to use things like MTP instead. So prohibit multicast. */static int checkvalidaddr(const struct sockaddr_storage * const addr){ if (addr == NULL) { return 0; } if (STORAGE_FAMILY(*addr) == AF_INET6) { if (IN6_IS_ADDR_MULTICAST(&STORAGE_SIN_ADDR6_NF(*addr)) || IN6_IS_ADDR_UNSPECIFIED(&STORAGE_SIN_ADDR6_NF(*addr))) { return 0; } return 1; } else if (STORAGE_FAMILY(*addr) == AF_INET) { if (ntohl(STORAGE_SIN_ADDR(*addr)) == INADDR_ANY || ntohl(STORAGE_SIN_ADDR(*addr)) == INADDR_NONE || ntohl(STORAGE_SIN_ADDR(*addr)) == INADDR_BROADCAST || IN_MULTICAST(ntohl(STORAGE_SIN_ADDR(*addr))) || IN_BADCLASS(ntohl(STORAGE_SIN_ADDR(*addr)))) { return 0; } return 1; } return 0;}/* Convert a 4-in-6 address in pure IPv4 */static void fourinsix(struct sockaddr_storage *v6){ struct sockaddr_storage v4; if (v6ready == 0 || STORAGE_FAMILY(*v6) != AF_INET6 || IN6_IS_ADDR_V4MAPPED(&STORAGE_SIN_ADDR6_NF(*v6)) == 0) { return; } memset(&v4, 0, sizeof v4); STORAGE_FAMILY(v4) = AF_INET; memcpy(&STORAGE_SIN_ADDR(v4), (unsigned char *) &STORAGE_SIN_ADDR6(*v6) + 12, sizeof STORAGE_SIN_ADDR(v4)); STORAGE_PORT(v4) = STORAGE_PORT6(*v6); SET_STORAGE_LEN(v4, sizeof(struct sockaddr_in)); *v6 = v4;}/* Return 0 if s1 == s2 , 1 if s1 != s2 , -1 if error */static int addrcmp(const struct sockaddr_storage * const s1, const struct sockaddr_storage * const s2){ if (STORAGE_FAMILY(*s1) == AF_INET6) { if (STORAGE_FAMILY(*s2) != AF_INET6) { return 1; } if (IN6_ARE_ADDR_EQUAL(&STORAGE_SIN_ADDR6_NF(*s1), &STORAGE_SIN_ADDR6_NF(*s2))) { return 0; } else { return 1; } } else if (STORAGE_FAMILY(*s1) == AF_INET) { if (STORAGE_FAMILY(*s2) != AF_INET) { return 1; } if (STORAGE_SIN_ADDR(*s1) == STORAGE_SIN_ADDR(*s2)) { return 0; } else { return 1; } } return -1;}static int generic_aton(const char *src, struct sockaddr_storage *a){ if (inet_pton(AF_INET6, src, &STORAGE_SIN_ADDR6(*a)) > 0) { STORAGE_FAMILY(*a) = AF_INET6; return 0; } if (inet_pton(AF_INET, src, &STORAGE_SIN_ADDR(*a)) > 0) { STORAGE_FAMILY(*a) = AF_INET; return 0; } memset(a, 0, sizeof *a); return -1;}void logfile(const int crit, const char *format, ...){#ifdef NON_ROOT_FTP (void) crit; (void) format;#else const char *urgency; va_list va; char line[MAX_SYSLOG_LINE]; if (no_syslog != 0) { return; } va_start(va, format); vsnprintf(line, sizeof line, format, va); switch (crit) { case LOG_INFO: urgency = "[INFO] "; break; case LOG_WARNING: urgency = "[WARNING] "; break; case LOG_ERR: urgency = "[ERROR] "; break; case LOG_NOTICE: urgency = "[NOTICE] "; break; case LOG_DEBUG: urgency = "[DEBUG] "; break; default: urgency = ""; }# ifdef SAVE_DESCRIPTORS openlog("pure-ftpd", log_pid, syslog_facility);# endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -