]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
mbox: Give better error messages if dotlocking fails.
authorTimo Sirainen <tss@iki.fi>
Thu, 26 Feb 2009 18:54:30 +0000 (13:54 -0500)
committerTimo Sirainen <tss@iki.fi>
Thu, 26 Feb 2009 18:54:30 +0000 (13:54 -0500)
--HG--
branch : HEAD

src/lib-storage/index/mbox/mbox-lock.c

index 1e8084497dfb410c0b5c0eaefd4427d7d91d0047..972df6ac9a6b2e763d00a66e7ddb2a776f3c2a43 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "eacces-error.h"
 #include "restrict-access.h"
 #include "nfs-workarounds.h"
 #include "mail-index-private.h"
@@ -14,6 +15,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <grp.h>
 
 #ifdef HAVE_FLOCK
 #  include <sys/file.h>
@@ -260,7 +262,7 @@ static int mbox_dotlock_privileged_op(struct mbox_mailbox *mbox,
                                      enum mbox_dotlock_op op)
 {
        const char *dir, *fname;
-       int ret = -1, orig_dir_fd;
+       int ret = -1, orig_dir_fd, orig_errno;
 
        orig_dir_fd = open(".", O_RDONLY);
        if (orig_dir_fd == -1) {
@@ -310,23 +312,42 @@ static int mbox_dotlock_privileged_op(struct mbox_mailbox *mbox,
                ret = file_dotlock_create(set, fname, 0, &mbox->mbox_dotlock);
                if (ret > 0)
                        mbox->mbox_used_privileges = TRUE;
+               else if (ret < 0 && errno == EACCES) {
+                       const char *errmsg =
+                               eacces_error_get_creating("file_dotlock_create",
+                                                         fname);
+                       mail_storage_set_critical(&mbox->storage->storage,
+                                                 "%s", errmsg);
+               } else {
+                       mbox_set_syscall_error(mbox, "file_dotlock_create()");
+               }
                break;
        case MBOX_DOTLOCK_OP_UNLOCK:
                /* we're now privileged - avoid doing as much as possible */
                ret = file_dotlock_delete(&mbox->mbox_dotlock);
+               if (ret < 0)
+                       mbox_set_syscall_error(mbox, "file_dotlock_delete()");
                mbox->mbox_used_privileges = FALSE;
                break;
        case MBOX_DOTLOCK_OP_TOUCH:
                if (!file_dotlock_is_locked(mbox->mbox_dotlock)) {
-                       file_dotlock_delete(&mbox->mbox_dotlock);
+                       if (file_dotlock_delete(&mbox->mbox_dotlock) < 0) {
+                               mbox_set_syscall_error(mbox,
+                                                      "file_dotlock_delete()");
+                       }
                        mbox->mbox_used_privileges = TRUE;
                        ret = -1;
                } else {
                        ret = file_dotlock_touch(mbox->mbox_dotlock);
+                       if (ret < 0) {
+                               mbox_set_syscall_error(mbox,
+                                                      "file_dotlock_touch()");
+                       }
                }
                break;
        }
 
+       orig_errno = errno;
        restrict_access_drop_priv_gid();
 
        if (fchdir(orig_dir_fd) < 0) {
@@ -334,9 +355,35 @@ static int mbox_dotlock_privileged_op(struct mbox_mailbox *mbox,
                        "fchdir() failed: %m");
        }
        (void)close(orig_dir_fd);
+       errno = orig_errno;
        return ret;
 }
 
+static void
+mbox_dotlock_log_eacces_error(struct mbox_mailbox *mbox, const char *path)
+{
+       const char *dir, *errmsg;
+       struct stat st;
+       const struct group *group;
+       int orig_errno = errno;
+
+       errmsg = eacces_error_get_creating("file_dotlock_create", path);
+       dir = strrchr(path, '/');
+       dir = dir == NULL ? "." : t_strdup_until(path, dir);
+       if (stat(dir, &st) == 0 &&
+           (st.st_mode & 02) == 0 && /* not world-writable */
+           (st.st_mode & 020) != 0) { /* group-writable */
+               group = getgrgid(st.st_gid);
+               mail_storage_set_critical(&mbox->storage->storage,
+                       "%s (set mail_privileged_group=%s)", errmsg,
+                       group == NULL ? dec2str(st.st_gid) : group->gr_name);
+       } else {
+               mail_storage_set_critical(&mbox->storage->storage,
+                       "%s (nonstandard permissions in %s)", errmsg, path);
+       }
+       errno = orig_errno;
+}
+
 static int
 mbox_lock_dotlock_int(struct mbox_lock_context *ctx, int lock_type, bool try)
 {
@@ -348,18 +395,17 @@ mbox_lock_dotlock_int(struct mbox_lock_context *ctx, int lock_type, bool try)
                if (!mbox->mbox_dotlocked)
                        return 1;
 
-               if (!mbox->mbox_used_privileges)
-                       ret = file_dotlock_delete(&mbox->mbox_dotlock);
-               else {
+               if (!mbox->mbox_used_privileges) {
+                       if (file_dotlock_delete(&mbox->mbox_dotlock) <= 0) {
+                               mbox_set_syscall_error(mbox,
+                                                      "file_dotlock_delete()");
+                       }
+               } else {
                        ctx->using_privileges = TRUE;
-                       ret = mbox_dotlock_privileged_op(mbox, NULL,
-                                                       MBOX_DOTLOCK_OP_UNLOCK);
+                       (void)mbox_dotlock_privileged_op(mbox, NULL,
+                                                        MBOX_DOTLOCK_OP_UNLOCK);
                        ctx->using_privileges = FALSE;
                }
-               if (ret <= 0) {
-                       mbox_set_syscall_error(mbox, "file_dotlock_delete()");
-                       ret = -1;
-               }
                 mbox->mbox_dotlocked = FALSE;
                return 1;
        }
@@ -380,18 +426,21 @@ mbox_lock_dotlock_int(struct mbox_lock_context *ctx, int lock_type, bool try)
        set.context = ctx;
 
        ret = file_dotlock_create(&set, mbox->path, 0, &mbox->mbox_dotlock);
-       if (ret < 0 && errno == EACCES && restrict_access_have_priv_gid() &&
-           mbox->mbox_privileged_locking) {
+       if (ret >= 0) {
+               /* success / timeout */
+       } else if (errno == EACCES && restrict_access_have_priv_gid() &&
+                  mbox->mbox_privileged_locking) {
                /* try again, this time with extra privileges */
                ret = mbox_dotlock_privileged_op(mbox, &set,
                                                 MBOX_DOTLOCK_OP_LOCK);
-       }
+       } else if (errno == EACCES)
+               mbox_dotlock_log_eacces_error(mbox, mbox->path);
+       else
+               mbox_set_syscall_error(mbox, "file_dotlock_create()");
 
        if (ret < 0) {
                if ((ENOSPACE(errno) || errno == EACCES) && try)
                        return 1;
-
-               mbox_set_syscall_error(mbox, "file_lock_dotlock()");
                return -1;
        }
        if (ret == 0) {