if (Ustat(filename, &statbuf) >= 0 && statbuf.st_uid != exim_uid)
{
DEBUG(D_hints_lookup) debug_printf_indent("ensuring %s is owned by exim\n", filename);
- if (Uchown(filename, exim_uid, exim_gid))
+ if (exim_chown(filename, exim_uid, exim_gid))
DEBUG(D_hints_lookup) debug_printf_indent("failed setting %s to owned by exim\n", filename);
}
}
#ifndef O_CLOEXEC
(void)fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
#endif
- if (fchown(fd, exim_uid, exim_gid) < 0)
+ if (exim_fchown(fd, exim_uid, exim_gid, filename) < 0)
{
*error = US"chown";
return -1;
MSGLOG_DIRECTORY_MODE, TRUE);
}
-*error = US"create";
+*error = US"create or open";
return -1;
}
that the mode is correct - the group setting doesn't always seem to get
set automatically. */
- if( fchown(journal_fd, exim_uid, exim_gid)
+ if( exim_fchown(journal_fd, exim_uid, exim_gid, fname)
|| fchmod(journal_fd, SPOOL_MODE)
#ifndef O_CLOEXEC
|| fcntl(journal_fd, F_SETFD, fcntl(journal_fd, F_GETFD) | FD_CLOEXEC)
/* Set the ownership if necessary. */
- if (use_chown && Uchown(path, exim_uid, exim_gid))
+ if (use_chown && exim_chown(path, exim_uid, exim_gid))
{ p = US"set owner on"; goto bad; }
/* It appears that any mode bits greater than 0777 are ignored by
}
-
-
/*************************************************
* Ensure stdin, stdout, and stderr exist *
*************************************************/
exit(EXIT_FAILURE);
}
+/* exim_chown_failure() called from exim_chown()/exim_fchown() on failure
+of chown()/fchown(). See src/functions.h for more explanation */
+int
+exim_chown_failure(int fd, const uschar *name, uid_t owner, gid_t group)
+{
+#if 1
+log_write(0, LOG_MAIN|LOG_PANIC,
+ __FILE__ ":%d: chown(%s, %d:%d) failed (%s)."
+ " Please contact the authors and refer to https://bugs.exim.org/show_bug.cgi?id=2391",
+ __LINE__, name?name:US"<unknown>", owner, group, strerror(errno));
+#else
+/* I leave this here, commented, in case the "bug"(?) comes up again.
+ It is not an Exim bug, but we can provide a workaround.
+ See Bug 2391
+ HS 2019-04-18 */
+
+int saved_errno = errno; /* from the preceeding chown call */
+struct stat buf;
+
+if (0 == (fd < 0 ? stat(name, &buf) : fstat(fd, &buf)))
+{
+ if (buf.st_uid == owner && buf.st_gid == group) return 0;
+ log_write(0, LOG_MAIN|LOG_PANIC, "Wrong ownership on %s", name);
+}
+else log_write(0, LOG_MAIN|LOG_PANIC, "Stat failed on %s: %s", name, strerror(errno));
+
+errno = saved_errno;
+return -1;
+#endif
+}
/*************************************************
to avoid having a lot of tiddly little headers with only a couple of lines in
them. However, some functions that are used (or not used) by utility programs
are in in fact in separate headers. */
+#ifndef _FUNCTIONS_H_
+#define _FUNCTIONS_H_
#ifdef EXIM_PERL
extern uschar *event_raise(uschar *, const uschar *, uschar *);
extern void msg_event_raise(const uschar *, const address_item *);
#endif
+
+extern int exim_chown_failure(int, const uschar*, uid_t, gid_t);
+inline int exim_chown(const uschar*, uid_t, gid_t);
+inline int exim_fchown(int, uid_t, gid_t, const uschar*);
extern const uschar * exim_errstr(int);
extern void exim_exit(int, const uschar *);
extern void exim_nullstd(void);
extern BOOL write_chunk(transport_ctx *, uschar *, int);
extern ssize_t write_to_fd_buf(int, const uschar *, size_t);
+/* exim_chown - in some NFSv4 setups *seemes* to be an issue with
+ chown(<exim-uid>, <exim-gid>).
+
+ Probably because the idmapping is broken, misconfigured or set up in
+ an unusal way. (see Bug 2931). As I'm not sure, if this was a single
+ case of misconfiguration, or if there are more such broken systems
+ out, I try to impose as least impact as possible and for now just write
+ a panic log entry pointing to the bug report. You're encouraged to
+ contact the developers, if you experience this issue.
+
+ fd the file descriptor (or -1 if not valid)
+ name the file name for error messages or for file operations,
+ if fd is < 0
+ owner the owner
+ group the group
+
+ returns 0 on success, -1 on failure */
+
+inline int
+exim_fchown(int fd, uid_t owner, gid_t group, const uschar *name)
+{
+return (0 == fchown(fd, owner, group))
+ ? 0 : exim_chown_failure(fd, name, owner, group);
+}
+
+inline int
+exim_chown(const uschar *name, uid_t owner, gid_t group)
+{
+return (0 == chown(name, owner, group))
+ ? 0 : exim_chown_failure(-1, name, owner, group);
+}
+
+#endif /* _FUNCTIONS_H_ */
/* vi: aw
*/
#define Uatol(s) atol(CCS(s))
#define Uchdir(s) chdir(CCS(s))
#define Uchmod(s,n) chmod(CCS(s),n)
-#define Uchown(s,n,m) chown(CCS(s),n,m)
#define Ufgets(b,n,f) fgets(CS(b),n,f)
#define Ufopen(s,t) fopen(CCS(s),CCS(t))
#define Ulink(s,t) link(CCS(s),CCS(t))
/* Make sure the file's group is the Exim gid, and double-check the mode
because the group setting doesn't always get set automatically. */
-if (fchown(data_fd, exim_uid, exim_gid))
+if (0 != exim_fchown(data_fd, exim_uid, exim_gid, spool_name))
log_write(0, LOG_MAIN|LOG_PANIC_DIE,
"Failed setting ownership on spool file %s: %s",
spool_name, strerror(errno));
{
int fd;
uschar * m_name = spool_fname(US"msglog", message_subdir, message_id, US"");
-
+
if ( (fd = Uopen(m_name, O_WRONLY|O_APPEND|O_CREAT, SPOOL_MODE)) < 0
&& errno == ENOENT
)
if (f.deliver_freeze) log_write(0, LOG_MAIN, "frozen by %s", frozen_by);
if (f.queue_only_policy) log_write(L_delay_delivery, LOG_MAIN,
"no immediate delivery: queued%s%s by %s",
- *queue_name ? " in " : "", *queue_name ? CS queue_name : "",
+ *queue_name ? " in " : "", *queue_name ? CS queue_name : "",
queued_by);
}
f.receive_call_bombout = FALSE;
automatically. */
if (fd >= 0)
- if (fchown(fd, exim_uid, exim_gid) || fchmod(fd, SPOOL_MODE))
+ if (exim_fchown(fd, exim_uid, exim_gid, temp_name) || fchmod(fd, SPOOL_MODE))
{
DEBUG(D_any) debug_printf("failed setting perms on %s\n", temp_name);
(void) close(fd); fd = -1;
temp_fn = string_copy(US"%s.XXXXXXX");
if ((fd = mkstemp(CS temp_fn)) < 0) /* modifies temp_fn */
return tls_error_sys(US"Unable to open temp file", errno, NULL, errstr);
- (void)fchown(fd, exim_uid, exim_gid); /* Probably not necessary */
+ (void)exim_chown(temp_fn, exim_uid, exim_gid); /* Probably not necessary */
/* GnuTLS overshoots!
* If we ask for 2236, we might get 2237 or more.
/* We have successfully created and opened the file. Ensure that the group
and the mode are correct. */
- if(Uchown(filename, uid, gid) || Uchmod(filename, mode))
+ if(exim_chown(filename, uid, gid) || Uchmod(filename, mode))
{
addr->basic_errno = errno;
addr->message = string_sprintf("while setting perms on mailbox %s",
/* Why are these here? Put in because they are present in the non-maildir
directory case above. */
- if(Uchown(filename, uid, gid) || Uchmod(filename, mode))
+ if(exim_chown(filename, uid, gid) || Uchmod(filename, mode))
{
addr->basic_errno = errno;
addr->message = string_sprintf("while setting perms on maildir %s",
/* Why are these here? Put in because they are present in the non-maildir
directory case above. */
- if(Uchown(filename, uid, gid) || Uchmod(filename, mode))
+ if(exim_chown(filename, uid, gid) || Uchmod(filename, mode))
{
addr->basic_errno = errno;
addr->message = string_sprintf("while setting perms on file %s",
Uunlink(filename);
return FALSE;
}
- if(Uchown(dataname, uid, gid) || Uchmod(dataname, mode))
+ if(exim_chown(dataname, uid, gid) || Uchmod(dataname, mode))
{
addr->basic_errno = errno;
addr->message = string_sprintf("while setting perms on file %s",
/* In all cases of writing to a new file, ensure that the file which is
going to be renamed has the correct ownership and mode. */
- if(Uchown(filename, uid, gid) || Uchmod(filename, mode))
+ if(exim_chown(filename, uid, gid) || Uchmod(filename, mode))
{
addr->basic_errno = errno;
addr->message = string_sprintf("while setting perms on file %s",