From 2d0b101df7dc6ddc6660aae24e64e8ab452127db Mon Sep 17 00:00:00 2001 From: obrien Date: Sun, 2 Feb 2003 20:58:44 +0000 Subject: Import of LukeM's ftpd taken from the NetBSD CVS repo on 22-Jan-2003. This includes the DoS fix of rev 1.133 libexec/ftpd/ftpd.c. --- contrib/lukemftpd/src/cmds.c | 146 ++++++++++++++++++++++++++++++++++++++-- contrib/lukemftpd/src/ftpcmd.y | 6 +- contrib/lukemftpd/src/ftpd.c | 57 +++++++++------- contrib/lukemftpd/src/popen.c | 16 ++--- contrib/lukemftpd/src/version.h | 4 +- 5 files changed, 184 insertions(+), 45 deletions(-) (limited to 'contrib/lukemftpd') diff --git a/contrib/lukemftpd/src/cmds.c b/contrib/lukemftpd/src/cmds.c index 334078f..7a287ea 100644 --- a/contrib/lukemftpd/src/cmds.c +++ b/contrib/lukemftpd/src/cmds.c @@ -1,4 +1,4 @@ -/* $NetBSD: cmds.c,v 1.18 2002/10/12 08:35:16 darrenr Exp $ */ +/* $NetBSD: cmds.c,v 1.20 2003/01/08 18:07:31 manu Exp $ */ /* * Copyright (c) 1999-2001 The NetBSD Foundation, Inc. @@ -101,7 +101,7 @@ #include #ifndef lint -__RCSID("$NetBSD: cmds.c,v 1.18 2002/10/12 08:35:16 darrenr Exp $"); +__RCSID("$NetBSD: cmds.c,v 1.20 2003/01/08 18:07:31 manu Exp $"); #endif /* not lint */ #include @@ -171,6 +171,8 @@ struct ftpfact facttab[] = { #define FACTTABSIZE (sizeof(facttab) / sizeof(struct ftpfact)) +static char cached_path[MAXPATHLEN + 1] = "/"; +static void discover_path(char *, const char *); void cwd(const char *path) @@ -181,6 +183,9 @@ cwd(const char *path) else { show_chdir_messages(250); ack("CWD"); + if (getcwd(cached_path, MAXPATHLEN) == NULL) { + discover_path(cached_path, path); + } } } @@ -404,11 +409,15 @@ pwd(void) { char path[MAXPATHLEN]; - if (getcwd(path, sizeof(path) - 1) == NULL) - reply(550, "Can't get the current directory: %s.", - strerror(errno)); - else - replydirname(path, "is the current directory."); + if (getcwd(path, sizeof(path) - 1) == NULL) { + if (chdir(cached_path) < 0) { + reply(550, "Can't get the current directory: %s.", + strerror(errno)); + return; + } + (void)strlcpy(path, cached_path, MAXPATHLEN); + } + replydirname(path, "is the current directory."); } void @@ -844,3 +853,126 @@ replydirname(const char *name, const char *message) *p = '\0'; reply(257, "\"%s\" %s", npath, message); } + +static void +discover_path(last_path, new_path) + char *last_path; + const char *new_path; +{ + char tp[MAXPATHLEN + 1] = ""; + char tq[MAXPATHLEN + 1] = ""; + char *cp; + char *cq; + int sz1, sz2; + int nomorelink; + struct stat st1, st2; + + if (new_path[0] != '/') { + (void)strlcpy(tp, last_path, MAXPATHLEN); + (void)strlcat(tp, "/", MAXPATHLEN); + } + (void)strlcat(tp, new_path, MAXPATHLEN); + (void)strlcat(tp, "/", MAXPATHLEN); + + /* + * resolve symlinks. A symlink may introduce another symlink, so we + * loop trying to resolve symlinks until we don't find any of them. + */ + do { + /* Collapse any // into / */ + while ((cp = strstr(tp, "//")) != NULL) + (void)memmove(cp, cp + 1, strlen(cp) - 1 + 1); + + /* Collapse any /./ into / */ + while ((cp = strstr(tp, "/./")) != NULL) + (void)memmove(cp, cp + 2, strlen(cp) - 2 + 1); + + cp = tp; + nomorelink = 1; + + while ((cp = strstr(++cp, "/")) != NULL) { + sz1 = (u_long)cp - (u_long)tp; + if (sz1 > MAXPATHLEN) + goto bad; + *cp = 0; + sz2 = readlink(tp, tq, MAXPATHLEN); + *cp = '/'; + + /* If this is not a symlink, move to next / */ + if (sz2 <= 0) + continue; + + /* + * We found a symlink, so we will have to + * do one more pass to check there is no + * more symlink in the path + */ + nomorelink = 0; + + /* + * Null terminate the string and remove trailing / + */ + tq[sz2] = 0; + sz2 = strlen(tq); + if (tq[sz2 - 1] == '/') + tq[--sz2] = 0; + + /* + * Is this an absolute link or a relative link? + */ + if (tq[0] == '/') { + /* absolute link */ + if (strlen(cp) + sz2 > MAXPATHLEN) + goto bad; + memmove(tp + sz2, cp, strlen(cp) + 1); + memcpy(tp, tq, sz2); + } else { + /* relative link */ + for (cq = cp - 1; *cq != '/'; cq--); + if (strlen(tp) - ((u_long)cq - (u_long)cp) + + 1 + sz2 > MAXPATHLEN) + goto bad; + (void)memmove(cq + 1 + sz2, + cp, strlen(cp) + 1); + (void)memcpy(cq + 1, tq, sz2); + } + + /* + * start over, looking for new symlinks + */ + break; + } + } while (nomorelink == 0); + + /* Collapse any /foo/../ into /foo/ */ + while ((cp = strstr(tp, "/../")) != NULL) { + /* ^/../foo/ becomes ^/foo/ */ + if (cp == tp) { + (void)memmove(cp, cp + 3, + strlen(cp) - 3 + 1); + } else { + for (cq = cp - 1; *cq != '/'; cq--); + (void)memmove(cq, cp + 3, + strlen(cp) - 3 + 1); + } + } + + /* strip strailing / */ + if (strlen(tp) != 1) + tp[strlen(tp) - 1] = '\0'; + + /* check that the path is correct */ + stat(tp, &st1); + stat(".", &st2); + if ((st1.st_dev != st2.st_dev) || (st1.st_ino != st2.st_ino)) + goto bad; + + (void)strlcpy(last_path, tp, MAXPATHLEN); + return; + +bad: + (void)strlcat(last_path, "/", MAXPATHLEN); + (void)strlcat(last_path, new_path, MAXPATHLEN); + return; +} + diff --git a/contrib/lukemftpd/src/ftpcmd.y b/contrib/lukemftpd/src/ftpcmd.y index 1039d51..42a7131 100644 --- a/contrib/lukemftpd/src/ftpcmd.y +++ b/contrib/lukemftpd/src/ftpcmd.y @@ -1,4 +1,4 @@ -/* $NetBSD: ftpcmd.y,v 1.71 2002/10/12 08:35:17 darrenr Exp $ */ +/* $NetBSD: ftpcmd.y,v 1.73 2003/01/22 04:33:35 lukem Exp $ */ /*- * Copyright (c) 1997-2002 The NetBSD Foundation, Inc. @@ -83,7 +83,7 @@ #if 0 static char sccsid[] = "@(#)ftpcmd.y 8.3 (Berkeley) 4/6/94"; #else -__RCSID("$NetBSD: ftpcmd.y,v 1.71 2002/10/12 08:35:17 darrenr Exp $"); +__RCSID("$NetBSD: ftpcmd.y,v 1.73 2003/01/22 04:33:35 lukem Exp $"); #endif #endif /* not lint */ @@ -1222,7 +1222,7 @@ struct tab cmdtab[] = { { "SMNT", SMNT, ARGS, 0, "(structure mount)" }, { "QUIT", QUIT, NOARGS, 1, "(terminate service)" }, { "REIN", REIN, NOARGS, 0, "(reinitialize server state)" }, - { "PORT", PORT, ARGS, 1, " b0, b1, b2, b3, b4" }, + { "PORT", PORT, ARGS, 1, " b0, b1, b2, b3, b4, b5" }, { "LPRT", LPRT, ARGS, 1, " af, hal, h1, h2, h3,..., pal, p1, p2..." }, { "EPRT", EPRT, STR1, 1, " |af|addr|port|" }, { "PASV", PASV, NOARGS, 1, "(set server in passive mode)" }, diff --git a/contrib/lukemftpd/src/ftpd.c b/contrib/lukemftpd/src/ftpd.c index de19ccc..5f6cd24 100644 --- a/contrib/lukemftpd/src/ftpd.c +++ b/contrib/lukemftpd/src/ftpd.c @@ -1,4 +1,4 @@ -/* $NetBSD: ftpd.c,v 1.147 2002/11/29 14:40:00 lukem Exp $ */ +/* $NetBSD: ftpd.c,v 1.150 2003/01/22 04:46:08 lukem Exp $ */ /* * Copyright (c) 1997-2001 The NetBSD Foundation, Inc. @@ -109,7 +109,7 @@ __COPYRIGHT( #if 0 static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95"; #else -__RCSID("$NetBSD: ftpd.c,v 1.147 2002/11/29 14:40:00 lukem Exp $"); +__RCSID("$NetBSD: ftpd.c,v 1.150 2003/01/22 04:46:08 lukem Exp $"); #endif #endif /* not lint */ @@ -670,8 +670,7 @@ user(const char *name) } else pw = sgetpwnam(name); - if (logging) - strlcpy(curname, name, sizeof(curname)); + strlcpy(curname, name, sizeof(curname)); /* check user in /etc/ftpusers, and setup class */ permitted = checkuser(_PATH_FTPUSERS, curname, 1, 0, &class); @@ -1573,7 +1572,7 @@ dataconn(const char *name, off_t size, const char *fmode) { char sizebuf[32]; FILE *file; - int retry = 0, tos, keepalive; + int retry, tos, keepalive, conerrno; file_size = size; byte_count = 0; @@ -1627,30 +1626,38 @@ dataconn(const char *name, off_t size, const char *fmode) if (usedefault) data_dest = his_addr; usedefault = 1; - file = getdatasock(fmode); - if (file == NULL) { - char hbuf[NI_MAXHOST]; - char pbuf[NI_MAXSERV]; - - if (getnameinfo((struct sockaddr *)&data_source.si_su, - data_source.su_len, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), - NI_NUMERICHOST | NI_NUMERICSERV)) - strlcpy(hbuf, "?", sizeof(hbuf)); - reply(425, "Can't create data socket (%s,%s): %s.", - hbuf, pbuf, strerror(errno)); - return (NULL); - } - data = fileno(file); - while (connect(data, (struct sockaddr *)&data_dest.si_su, - data_dest.su_len) < 0) { - if (errno == EADDRINUSE && retry < swaitmax) { + retry = conerrno = 0; + do { + file = getdatasock(fmode); + if (file == NULL) { + char hbuf[NI_MAXHOST]; + char pbuf[NI_MAXSERV]; + + if (getnameinfo((struct sockaddr *)&data_source.si_su, + data_source.su_len, hbuf, sizeof(hbuf), pbuf, + sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) + strlcpy(hbuf, "?", sizeof(hbuf)); + reply(425, "Can't create data socket (%s,%s): %s.", + hbuf, pbuf, strerror(errno)); + return (NULL); + } + data = fileno(file); + conerrno = 0; + if (connect(data, (struct sockaddr *)&data_dest.si_su, + data_dest.su_len) == 0) + break; + conerrno = errno; + (void) fclose(file); + data = -1; + if (conerrno == EADDRINUSE) { sleep((unsigned) swaitint); retry += swaitint; - continue; + } else { + break; } + } while (retry <= swaitmax); + if (conerrno != 0) { perror_reply(425, "Can't build data connection"); - (void) fclose(file); - data = -1; return (NULL); } reply(150, "Opening %s mode data connection for '%s'%s.", diff --git a/contrib/lukemftpd/src/popen.c b/contrib/lukemftpd/src/popen.c index aaaebca..7a7c6c4 100644 --- a/contrib/lukemftpd/src/popen.c +++ b/contrib/lukemftpd/src/popen.c @@ -1,4 +1,4 @@ -/* $NetBSD: popen.c,v 1.26 2001/04/25 01:46:26 lukem Exp $ */ +/* $NetBSD: popen.c,v 1.28 2003/01/16 09:41:38 kleink Exp $ */ /*- * Copyright (c) 1999-2001 The NetBSD Foundation, Inc. @@ -78,7 +78,7 @@ #if 0 static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 4/6/94"; #else -__RCSID("$NetBSD: popen.c,v 1.26 2001/04/25 01:46:26 lukem Exp $"); +__RCSID("$NetBSD: popen.c,v 1.28 2003/01/16 09:41:38 kleink Exp $"); #endif #endif /* not lint */ @@ -229,7 +229,7 @@ ftpd_pclose(FILE *iop) { int fdes, status; pid_t pid; - sigset_t sigset, osigset; + sigset_t nsigset, osigset; /* * pclose returns -1 if stream is not associated with a @@ -238,11 +238,11 @@ ftpd_pclose(FILE *iop) if (pids == 0 || pids[fdes = fileno(iop)] == 0) return (-1); (void)fclose(iop); - sigemptyset(&sigset); - sigaddset(&sigset, SIGINT); - sigaddset(&sigset, SIGQUIT); - sigaddset(&sigset, SIGHUP); - sigprocmask(SIG_BLOCK, &sigset, &osigset); + sigemptyset(&nsigset); + sigaddset(&nsigset, SIGINT); + sigaddset(&nsigset, SIGQUIT); + sigaddset(&nsigset, SIGHUP); + sigprocmask(SIG_BLOCK, &nsigset, &osigset); while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR) continue; sigprocmask(SIG_SETMASK, &osigset, NULL); diff --git a/contrib/lukemftpd/src/version.h b/contrib/lukemftpd/src/version.h index 482a47a..4ffeb8a 100644 --- a/contrib/lukemftpd/src/version.h +++ b/contrib/lukemftpd/src/version.h @@ -1,4 +1,4 @@ -/* $NetBSD: version.h,v 1.48 2002/10/26 04:19:56 lukem Exp $ */ +/* $NetBSD: version.h,v 1.50 2003/01/22 04:46:08 lukem Exp $ */ /*- * Copyright (c) 1999-2002 The NetBSD Foundation, Inc. * All rights reserved. @@ -36,5 +36,5 @@ */ #ifndef FTPD_VERSION -#define FTPD_VERSION "NetBSD-ftpd 20021130" +#define FTPD_VERSION "NetBSD-ftpd 20030122" #endif -- cgit v1.1