]> git.wh0rd.org Git - nano.git/commitdiff
Okay, now abort if the symlink isn't owned by the user, and some mode fixes
authorChris Allegretta <chrisa@asty.org>
Sat, 2 Dec 2000 21:13:50 +0000 (21:13 +0000)
committerChris Allegretta <chrisa@asty.org>
Sat, 2 Dec 2000 21:13:50 +0000 (21:13 +0000)
git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@364 35c25a1d-7b9e-4130-9fde-d3aeb78583b8

ChangeLog
files.c

index 651b2ffda33547f4b6ec2c0823d22fd62da3addc..570b1b5113569ca21b962349aab0fa07b222de18 100644 (file)
--- 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 3fd29143bc8c23aaafaf37babe3f0004727bf0b7..9798521a3f0e88bd0234697b2b62a1ec53eb704c 100644 (file)
--- 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) {