--- Makefile.am | 4 - lib/file.c | 7 ++- mbox.c | 5 ++ mh.c | 8 +++ mutt.h | 3 + opennfs.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sendlib.c | 4 + 7 files changed, 150 insertions(+), 3 deletions(-) --- Makefile.am +++ Makefile.am 2017-09-11 11:47:43.214350183 +0000 @@ -52,7 +52,7 @@ mutt_SOURCES = account.c addrbook.c addr handler.c hdrline.c header.h headers.c help.c history.c hook.c \ init.c keymap.c list.h main.c mbox.c mbyte.c mbtable.h \ menu.c mh.c muttlib.c mutt_idna.c mutt_sasl_plain.c mutt_socket.c \ - mutt_tunnel.c mx.c newsrc.c nntp.c options.h pager.c parameter.c parameter.h \ + mutt_tunnel.c mx.c newsrc.c nntp.c opennfs.c options.h pager.c parameter.c parameter.h \ parse.c pattern.c pattern.h pop.c pop_auth.c pop_lib.c postpone.c \ query.c recvattach.c recvcmd.c rfc1524.c rfc2047.c rfc2231.c rfc3676.c \ rfc822.c safe_asprintf.c score.c send.c sendlib.c sidebar.c signal.c \ @@ -96,7 +96,7 @@ EXTRA_DIST = account.h attach.h bcache.h EXTRA_SCRIPTS = -pgpring_SOURCES = pgppubring.c +pgpring_SOURCES = opennfs.c pgppubring.c pgpring_LDADD = $(LIBOBJS) $(NCRYPT_LIBS) $(INTLLIBS) $(LIBMUTT) pgpring_DEPENDENCIES = $(LIBOBJS) $(NCRYPT_DEPS) $(INTLDEPS) $(LIBMUTTDEPS) --- lib/file.c +++ lib/file.c 2017-09-11 11:45:32.960743565 +0000 @@ -71,6 +71,7 @@ #include "debug.h" #include "memory.h" #include "message.h" +#include "mutt.h" #include "string2.h" /* these characters must be escaped in regular expressions */ @@ -502,6 +503,10 @@ int safe_open(const char *path, int flag struct stat osb, nsb; int fd; +#if defined(__linux__) + if ((fd = opennfs (path, flags, 0600)) < 0) + return fd; +#else if (flags & O_EXCL) { char safe_file[_POSIX_PATH_MAX]; @@ -526,7 +531,7 @@ int safe_open(const char *path, int flag fd = open(path, flags & ~O_EXCL, 0600); if (fd < 0) return fd; - +#endif /* make sure the file is not symlink */ if ((lstat(path, &osb) < 0 || fstat(fd, &nsb) < 0) || !compare_stat(&osb, &nsb)) { --- mbox.c +++ mbox.c 2017-09-11 11:40:15.902567799 +0000 @@ -1075,8 +1075,13 @@ static int mbox_sync_mailbox(struct Cont /* Create a temporary file to write the new version of the mailbox in. */ mutt_mktemp(tempfile, sizeof(tempfile)); +#if defined(__linux__) + if ((i = opennfs(tempfile, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1 || + (fp = fdopen(i, "w")) == NULL) +#else if ((i = open(tempfile, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1 || (fp = fdopen(i, "w")) == NULL) +#endif { if (-1 != i) { --- mh.c +++ mh.c 2017-09-11 11:49:25.892463230 +0000 @@ -383,7 +383,11 @@ static int mh_mkstemp(struct Context *de { snprintf(path, _POSIX_PATH_MAX, "%s/.mutt-%s-%d-%" PRIu64, dest->path, NONULL(ShortHostname), (int) getpid(), mutt_rand64()); +#if defined(__linux__) + if ((fd = opennfs(path, O_WRONLY | O_EXCL | O_CREAT, 0666)) == -1) +#else if ((fd = open(path, O_WRONLY | O_EXCL | O_CREAT, 0666)) == -1) +#endif { if (errno != EEXIST) { @@ -1518,7 +1522,11 @@ static int maildir_open_new_message(stru mutt_debug(2, "maildir_open_new_message (): Trying %s.\n", path); +#if defined(__linux__) + if ((fd = opennfs(path, O_WRONLY | O_EXCL | O_CREAT, 0666)) == -1) +#else if ((fd = open(path, O_WRONLY | O_EXCL | O_CREAT, 0666)) == -1) +#endif { if (errno != EEXIST) { --- mutt.h +++ mutt.h 2017-09-11 11:50:18.979487541 +0000 @@ -367,4 +367,7 @@ extern char *debugfile_cmdline; extern int debuglevel_cmdline; #endif +#if defined(__linux__) +extern int opennfs(const char *, int, int); +#endif #endif /* _MUTT_H */ --- opennfs.c +++ opennfs.c 2017-09-11 11:40:15.906567726 +0000 @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef NFS_SUPER_MAGIC +# define NFS_SUPER_MAGIC 0x6969 +#endif + +int opennfs(const char *path, int flags, int mode) +{ + char tmplock[NFS_MAXPATHLEN+1], sysname[256]; + char *slash, *ptr, *dir, *base, *clear = (char*)0; + struct stat ps, ts; + struct statfs fs; + ssize_t len; + int ret; + + if ((flags & (O_WRONLY|O_RDWR)) == 0) + goto safe; + + if ((flags & (O_EXCL|O_CREAT)) != (O_EXCL|O_CREAT)) + goto safe; + +#if defined(O_NOFOLLOW) + flags |= O_NOFOLLOW; +#endif + + ret = -1; + if ((clear = strdup(path)) == (char*)0) + goto err; + dir = dirname(clear); + + if ((ret = (statfs(dir, &fs))) < 0) + goto err; + + if (fs.f_type != NFS_SUPER_MAGIC) + goto safe; + + if ((ret = gethostname(sysname, sizeof(sysname))) < 0) + goto err; + + ret = -1; + ptr = &tmplock[0]; + if (((len = snprintf(ptr, NFS_MAXPATHLEN, "%s/.%s-XXXXXX", dir, sysname)) < 0) || (len >= NFS_MAXPATHLEN)) + goto err; + ptr += len; + slash = ptr; + + free(clear); + clear = (char*)0; + + if (mkdtemp(tmplock) == (char*)0) + goto err; + + ret = -1; + if ((clear = strdup(path)) == (char*)0) + goto rmd; + base = basename(clear); + + ret = -1; + if (((len = snprintf(ptr, NFS_MAXPATHLEN - len, "/%s", base)) < 0) || (len >= (NFS_MAXPATHLEN - len))) + goto rmd; + + free(clear); + clear = (char*)0; + + if ((ret = open(tmplock, flags, mode)) < 0) + goto rmd; + + errno = 0; + do { + len = write(ret, "0", 2); + } while ((len < 0) && (errno == EINTR)); + close(ret); + + ret = -1; + errno = EBADF; + if (len != 2) + goto unl; + + errno = 0; + if ((ret = lstat(tmplock, &ts)) < 0) + goto unl; + + if (((ret = link(tmplock, path)) < 0) && (errno == EEXIST)) + goto unl; + + if ((ret = lstat(path, &ps)) < 0) + goto unl; + + ret = -1; + errno = EEXIST; + if (ps.st_nlink != 2) + goto unl; + if ((ps.st_rdev != ts.st_rdev) || (ps.st_ino != ts.st_ino)) + goto unl; + + errno = 0; + flags |= O_TRUNC; + flags &= ~(O_EXCL|O_CREAT); + ret = open(path, flags, mode); +unl: + unlink(tmplock); +rmd: + *slash = '\0'; + rmdir(tmplock); +err: + if (clear) free(clear); + return ret; +safe: + if (clear) free(clear); + return open(path, flags, mode); +} --- sendlib.c +++ sendlib.c 2017-09-11 11:40:15.906567726 +0000 @@ -2354,7 +2354,11 @@ static int send_msg(const char *path, ch if (SendmailWait >= 0 && tempfile && *tempfile) { /* *tempfile will be opened as stdout */ +#if defined(__linux__) + if (opennfs(*tempfile, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0600) < 0) +#else if (open(*tempfile, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0600) < 0) +#endif _exit(S_ERR); /* redirect stderr to *tempfile too */ if (dup(1) < 0)