From abe6016909259942e4406e3f1ad00457ed92ad7b Mon Sep 17 00:00:00 2001 From: simon Date: Wed, 7 Jan 2009 20:17:55 +0000 Subject: Prevent cross-site forgery attacks on lukemftpd(8) due to splitting long commands into multiple requests. [09:01] Fix incorrect OpenSSL checks for malformed signatures due to invalid check of return value from EVP_VerifyFinal(), DSA_verify, and DSA_do_verify. [09:02] Security: FreeBSD-SA-09:01.lukemftpd Security: FreeBSD-SA-09:02.openssl Obtained from: NetBSD [SA-09:01] Obtained from: OpenSSL Project [SA-09:02] Approved by: so (simon) --- contrib/lukemftpd/src/extern.h | 2 +- contrib/lukemftpd/src/ftpcmd.y | 39 +++++++++++++++++++++++++++++++-------- contrib/lukemftpd/src/ftpd.c | 10 ++++++++-- 3 files changed, 40 insertions(+), 11 deletions(-) (limited to 'contrib/lukemftpd') diff --git a/contrib/lukemftpd/src/extern.h b/contrib/lukemftpd/src/extern.h index 2d02106..771fbb8 100644 --- a/contrib/lukemftpd/src/extern.h +++ b/contrib/lukemftpd/src/extern.h @@ -139,7 +139,7 @@ void feat(void); void format_path(char *, const char *); int ftpd_pclose(FILE *); FILE *ftpd_popen(char *[], const char *, int); -char *getline(char *, int, FILE *); +int getline(char *, int, FILE *); void init_curclass(void); void logxfer(const char *, off_t, const char *, const char *, const struct timeval *, const char *); diff --git a/contrib/lukemftpd/src/ftpcmd.y b/contrib/lukemftpd/src/ftpcmd.y index 804a26b..3f3e950 100644 --- a/contrib/lukemftpd/src/ftpcmd.y +++ b/contrib/lukemftpd/src/ftpcmd.y @@ -1363,8 +1363,12 @@ lookup(struct tab *p, const char *cmd) /* * getline - a hacked up version of fgets to ignore TELNET escape codes. + * `s' is the buffer to read into. + * `n' is the 1 less than the size of the buffer, to allow trailing NUL + * `iop' is the FILE to read from. + * Returns 0 on success, -1 on EOF, -2 if the command was too long. */ -char * +int getline(char *s, int n, FILE *iop) { int c; @@ -1379,7 +1383,7 @@ getline(char *s, int n, FILE *iop) if (ftpd_debug) syslog(LOG_DEBUG, "command: %s", s); tmpline[0] = '\0'; - return(s); + return(0); } if (c == 0) tmpline[0] = '\0'; @@ -1418,11 +1422,25 @@ getline(char *s, int n, FILE *iop) } } *cs++ = c; - if (--n <= 0 || c == '\n') + if (--n <= 0) { + /* + * If command doesn't fit into buffer, discard the + * rest of the command and indicate truncation. + * This prevents the command to be split up into + * multiple commands. + */ + if (ftpd_debug) + syslog(LOG_DEBUG, + "command too long, last char: %d", c); + while (c != '\n' && (c = getc(iop)) != EOF) + continue; + return (-2); + } + if (c == '\n') break; } if (c == EOF && cs == s) - return (NULL); + return (-1); *cs++ = '\0'; if (ftpd_debug) { if ((curclass.type != CLASS_GUEST && @@ -1444,7 +1462,7 @@ getline(char *s, int n, FILE *iop) syslog(LOG_DEBUG, "command: %.*s", len, s); } } - return (s); + return (0); } void @@ -1458,15 +1476,20 @@ ftp_handle_line(char *cp) void ftp_loop(void) { + int ret; while (1) { (void) alarm(curclass.timeout); - if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { + ret = getline(cbuf, sizeof(cbuf)-1, stdin); + (void) alarm(0); + if (ret == -1) { reply(221, "You could at least say goodbye."); dologout(0); + } else if (ret == -2) { + reply(500, "Command too long."); + } else { + ftp_handle_line(cbuf); } - (void) alarm(0); - ftp_handle_line(cbuf); } /*NOTREACHED*/ } diff --git a/contrib/lukemftpd/src/ftpd.c b/contrib/lukemftpd/src/ftpd.c index 50a8854..afdd517 100644 --- a/contrib/lukemftpd/src/ftpd.c +++ b/contrib/lukemftpd/src/ftpd.c @@ -1,4 +1,4 @@ -/* $NetBSD: ftpd.c,v 1.176 2006/05/09 20:18:06 mrg Exp $ */ +/* $NetBSD: ftpd.c,v 1.187 2008/09/13 03:30:35 lukem Exp $ */ /* * Copyright (c) 1997-2004 The NetBSD Foundation, Inc. @@ -2896,6 +2896,7 @@ static int handleoobcmd() { char *cp; + int ret; if (!urgflag) return (0); @@ -2904,9 +2905,14 @@ handleoobcmd() if (!transflag) return (0); cp = tmpline; - if (getline(cp, sizeof(tmpline), stdin) == NULL) { + ret = getline(cp, sizeof(tmpline)-1, stdin); + if (ret == -1) { reply(221, "You could at least say goodbye."); dologout(0); + } else if (ret == -2) { + /* Ignore truncated command */ + /* XXX: abort xfer with "500 command too long", & return 1 ? */ + return 0; } /* * Manually parse OOB commands, because we can't -- cgit v1.1