commit f7ee9e69968df62bb0c683a901641a8d9f11618c
parent 3ea0a8f1d6c45640d481729b25f1a54386762c09
Author: Chris Allegretta <chrisa@asty.org>
Date: Sat, 2 Dec 2000 21:13:50 +0000
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
Diffstat:
2 files changed, 26 insertions(+), 20 deletions(-)
diff --git 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
@@ -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) {