summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2005-10-12 06:50:43 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2005-10-12 06:50:43 +0000
commit65195695f7749bcb0061ad81b0f68daccbc53243 (patch)
tree72346cbe46a1be6816aafdfb02a97f35e37f7d6f /usr.bin
parent7417ea743b8d22bdc39685adfd3857d9f56e9d74 (diff)
Fix mget directory traversal vulnerability. From NetBSD. CAN-2002-1345.
ok millert@ deraadt@, prodding by david@
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/ftp/cmds.c18
-rw-r--r--usr.bin/ftp/extern.h3
-rw-r--r--usr.bin/ftp/util.c38
3 files changed, 52 insertions, 7 deletions
diff --git a/usr.bin/ftp/cmds.c b/usr.bin/ftp/cmds.c
index f316f3cdc9a..eda879e1f2c 100644
--- a/usr.bin/ftp/cmds.c
+++ b/usr.bin/ftp/cmds.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmds.c,v 1.48 2004/09/16 04:39:16 deraadt Exp $ */
+/* $OpenBSD: cmds.c,v 1.49 2005/10/12 06:50:42 otto Exp $ */
/* $NetBSD: cmds.c,v 1.27 1997/08/18 10:20:15 lukem Exp $ */
/*
@@ -60,7 +60,7 @@
*/
#if !defined(lint) && !defined(SMALL)
-static char rcsid[] = "$OpenBSD: cmds.c,v 1.48 2004/09/16 04:39:16 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: cmds.c,v 1.49 2005/10/12 06:50:42 otto Exp $";
#endif /* not lint and not SMALL */
/*
@@ -565,7 +565,7 @@ mget(int argc, char *argv[])
{
sig_t oldintr;
int ch, ointer;
- char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
+ char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN], localcwd[MAXPATHLEN];
if (argc < 2 && !another(&argc, &argv, "remote-files")) {
fprintf(ttyout, "usage: %s remote-files\n", argv[0]);
@@ -574,6 +574,9 @@ mget(int argc, char *argv[])
}
mname = argv[0];
mflag = 1;
+ if (getcwd(localcwd, sizeof(localcwd)) == NULL)
+ err(1, "can't get cwd");
+
oldintr = signal(SIGINT, mabort);
(void)setjmp(jabort);
while ((cp = remglob(argv, proxy, NULL)) != NULL) {
@@ -581,7 +584,14 @@ mget(int argc, char *argv[])
mflag = 0;
continue;
}
- if (mflag && confirm(argv[0], cp)) {
+ if (!mflag)
+ continue;
+ if (!fileindir(cp, localcwd)) {
+ fprintf(ttyout, "Skipping non-relative filename `%s'\n",
+ cp);
+ continue;
+ }
+ if (confirm(argv[0], cp)) {
tp = cp;
if (mcase) {
for (tp2 = tmpbuf; (ch = *tp++) != 0; )
diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h
index 416113948f0..d12b7c4ba58 100644
--- a/usr.bin/ftp/extern.h
+++ b/usr.bin/ftp/extern.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: extern.h,v 1.27 2004/09/16 04:39:16 deraadt Exp $ */
+/* $OpenBSD: extern.h,v 1.28 2005/10/12 06:50:42 otto Exp $ */
/* $NetBSD: extern.h,v 1.17 1997/08/18 10:20:19 lukem Exp $ */
/*
@@ -93,6 +93,7 @@ char *domap(char *);
void doproxy(int, char **);
char *dotrans(char *);
int foregroundproc(void);
+int fileindir(const char *, const char *);
void get(int, char **);
struct cmd *getcmd(const char *);
int getit(int, char **, int, const char *);
diff --git a/usr.bin/ftp/util.c b/usr.bin/ftp/util.c
index 131bfca5acc..c8a419dbd85 100644
--- a/usr.bin/ftp/util.c
+++ b/usr.bin/ftp/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.40 2005/04/11 15:16:50 deraadt Exp $ */
+/* $OpenBSD: util.c,v 1.41 2005/10/12 06:50:42 otto Exp $ */
/* $NetBSD: util.c,v 1.12 1997/08/18 10:20:27 lukem Exp $ */
/*-
@@ -71,7 +71,7 @@
*/
#if !defined(lint) && !defined(SMALL)
-static char rcsid[] = "$OpenBSD: util.c,v 1.40 2005/04/11 15:16:50 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: util.c,v 1.41 2005/10/12 06:50:42 otto Exp $";
#endif /* not lint and not SMALL */
/*
@@ -85,6 +85,7 @@ static char rcsid[] = "$OpenBSD: util.c,v 1.40 2005/04/11 15:16:50 deraadt Exp $
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
#include <limits.h>
#include <glob.h>
#include <pwd.h>
@@ -631,6 +632,39 @@ remotemodtime(const char *file, int noisy)
}
/*
+ * Ensure file is in or under dir.
+ * Returns 1 if so, 0 if not (or an error occurred).
+ */
+int
+fileindir(const char *file, const char *dir)
+{
+ char parentdirbuf[MAXPATHLEN], *parentdir;
+ char realdir[MAXPATHLEN];
+ size_t dirlen;
+
+ /* determine parent directory of file */
+ (void)strlcpy(parentdirbuf, file, sizeof(parentdirbuf));
+ parentdir = dirname(parentdirbuf);
+ if (strcmp(parentdir, ".") == 0)
+ return 1; /* current directory is ok */
+
+ /* find the directory */
+ if (realpath(parentdir, realdir) == NULL) {
+ warn("Unable to determine real path of `%s'", parentdir);
+ return 0;
+ }
+ if (realdir[0] != '/') /* relative result is ok */
+ return 1;
+
+ dirlen = strlen(dir);
+ if (strncmp(realdir, dir, dirlen) == 0 &&
+ (realdir[dirlen] == '/' || realdir[dirlen] == '\0'))
+ return 1;
+ return 0;
+}
+
+
+/*
* Returns true if this is the controlling/foreground process, else false.
*/
int