From f7ee9e69968df62bb0c683a901641a8d9f11618c Mon Sep 17 00:00:00 2001 From: Chris Allegretta Date: Sat, 2 Dec 2000 21:13:50 +0000 Subject: [PATCH] Okay, now abort if the symlink isn't owned by the user, and some mode fixes git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@364 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- ChangeLog | 3 ++- files.c | 43 ++++++++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 651b2ffd..570b1b51 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,7 +23,8 @@ CVS code - - files.c: write_file() - Unsetting modified on temp files bug fixed (Rocco Corsi). - - Okay, if tmp == 1 and the file is a symlink, we return -1. + - Okay, if tmp == 1 and the file is a symlink the user doesn't + own, we return -1. do_insertfile() - Added call to real_name_from tilde, oops. Added check for DISABLE_TABCOMP. diff --git a/files.c b/files.c index 3fd29143..9798521a 100644 --- a/files.c +++ b/files.c @@ -301,7 +301,7 @@ int write_file(char *name, int tmp) long size, lineswritten = 0; char buf[PATH_MAX + 1]; filestruct *fileptr; - int fd, mask = 0; + int fd, mask = 0, realexists; struct stat st; static char *realname = NULL; @@ -321,16 +321,20 @@ int write_file(char *name, int tmp) realname = mallocstrcpy(realname, name); #endif + + /* Save the state of file at the end of the symlink */ + realexists = stat(realname, &st); + /* Check to see if the file is a regular file and FOLLOW_SYMLINKS is set. If so then don't do the delete and recreate code which would cause unexpected behavior */ lstat(realname, &st); - /* New case: if it's a symlink and tmp is set, abort. It could be - a symlink attack */ - if (tmp && S_ISLNK(st.st_mode)) + /* New case: if it's a symlink and tmp is set AND the user does not + own the symlink, abort. It could be a symlink attack */ + if (tmp && S_ISLNK(st.st_mode) && getuid() != st.st_uid) return -1; - else if (!tmp && (ISSET(FOLLOW_SYMLINKS) || !S_ISLNK(st.st_mode))) { + else if (ISSET(FOLLOW_SYMLINKS) || !S_ISLNK(st.st_mode)) { /* Open the file and truncate it. Trust the symlink. */ if ((fd = open(realname, O_WRONLY | O_CREAT | O_TRUNC, @@ -413,7 +417,7 @@ int write_file(char *name, int tmp) } if (!ISSET(FOLLOW_SYMLINKS) || tmp) { - if (stat(realname, &st) == -1) { + if (realexists == -1) { /* Use default umask as file permisions if file is a new file. */ mask = umask(0); umask(mask); @@ -426,7 +430,7 @@ int write_file(char *name, int tmp) } else { /* Use permissions from file we are overwriting. */ mask = st.st_mode; - if (unlink(realname) == -1) { + if (!tmp && unlink(realname) == -1) { if (errno != ENOENT) { statusbar(_("Could not open %s for writing: %s"), realname, strerror(errno)); @@ -436,23 +440,24 @@ int write_file(char *name, int tmp) } } - if (link(buf, realname) != -1) - unlink(buf); - else if (errno != EPERM) { - statusbar(_("Could not open %s for writing: %s"), + if (!tmp) { + if (link(buf, realname) != -1) + unlink(buf); + else if (errno != EPERM) { + statusbar(_("Could not open %s for writing: %s"), name, strerror(errno)); - unlink(buf); - return -1; - } else if (rename(buf, realname) == -1) { /* Try a rename?? */ - statusbar(_("Could not open %s for writing: %s"), + unlink(buf); + return -1; + } else if (rename(buf, realname) == -1) { /* Try a rename?? */ + statusbar(_("Could not open %s for writing: %s"), realname, strerror(errno)); - unlink(buf); - return -1; + unlink(buf); + return -1; + } } - if (chmod(realname, mask) == -1) { + if (chmod(realname, mask) == -1) statusbar(_("Could not set permissions %o on %s: %s"), mask, realname, strerror(errno)); - } } if (!tmp) { -- 2.39.5