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
master
Chris Allegretta 2000-12-02 21:13:50 +00:00
parent 3ea0a8f1d6
commit f7ee9e6996
2 changed files with 26 additions and 20 deletions

View File

@ -23,7 +23,8 @@ CVS code -
- files.c: - files.c:
write_file() write_file()
- Unsetting modified on temp files bug fixed (Rocco Corsi). - 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() do_insertfile()
- Added call to real_name_from tilde, oops. Added check for - Added call to real_name_from tilde, oops. Added check for
DISABLE_TABCOMP. DISABLE_TABCOMP.

43
files.c
View File

@ -301,7 +301,7 @@ int write_file(char *name, int tmp)
long size, lineswritten = 0; long size, lineswritten = 0;
char buf[PATH_MAX + 1]; char buf[PATH_MAX + 1];
filestruct *fileptr; filestruct *fileptr;
int fd, mask = 0; int fd, mask = 0, realexists;
struct stat st; struct stat st;
static char *realname = NULL; static char *realname = NULL;
@ -321,16 +321,20 @@ int write_file(char *name, int tmp)
realname = mallocstrcpy(realname, name); realname = mallocstrcpy(realname, name);
#endif #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 /* 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 set. If so then don't do the delete and recreate code which would
cause unexpected behavior */ cause unexpected behavior */
lstat(realname, &st); lstat(realname, &st);
/* New case: if it's a symlink and tmp is set, abort. It could be /* New case: if it's a symlink and tmp is set AND the user does not
a symlink attack */ own the symlink, abort. It could be a symlink attack */
if (tmp && S_ISLNK(st.st_mode)) if (tmp && S_ISLNK(st.st_mode) && getuid() != st.st_uid)
return -1; 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. */ /* Open the file and truncate it. Trust the symlink. */
if ((fd = open(realname, O_WRONLY | O_CREAT | O_TRUNC, 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 (!ISSET(FOLLOW_SYMLINKS) || tmp) {
if (stat(realname, &st) == -1) { if (realexists == -1) {
/* Use default umask as file permisions if file is a new file. */ /* Use default umask as file permisions if file is a new file. */
mask = umask(0); mask = umask(0);
umask(mask); umask(mask);
@ -426,7 +430,7 @@ int write_file(char *name, int tmp)
} else { } else {
/* Use permissions from file we are overwriting. */ /* Use permissions from file we are overwriting. */
mask = st.st_mode; mask = st.st_mode;
if (unlink(realname) == -1) { if (!tmp && unlink(realname) == -1) {
if (errno != ENOENT) { if (errno != ENOENT) {
statusbar(_("Could not open %s for writing: %s"), statusbar(_("Could not open %s for writing: %s"),
realname, strerror(errno)); realname, strerror(errno));
@ -436,23 +440,24 @@ int write_file(char *name, int tmp)
} }
} }
if (link(buf, realname) != -1) if (!tmp) {
unlink(buf); if (link(buf, realname) != -1)
else if (errno != EPERM) { unlink(buf);
statusbar(_("Could not open %s for writing: %s"), else if (errno != EPERM) {
statusbar(_("Could not open %s for writing: %s"),
name, strerror(errno)); name, strerror(errno));
unlink(buf); unlink(buf);
return -1; return -1;
} else if (rename(buf, realname) == -1) { /* Try a rename?? */ } else if (rename(buf, realname) == -1) { /* Try a rename?? */
statusbar(_("Could not open %s for writing: %s"), statusbar(_("Could not open %s for writing: %s"),
realname, strerror(errno)); realname, strerror(errno));
unlink(buf); unlink(buf);
return -1; return -1;
}
} }
if (chmod(realname, mask) == -1) { if (chmod(realname, mask) == -1)
statusbar(_("Could not set permissions %o on %s: %s"), statusbar(_("Could not set permissions %o on %s: %s"),
mask, realname, strerror(errno)); mask, realname, strerror(errno));
}
} }
if (!tmp) { if (!tmp) {