mail-error.c revision 7b85f7d35b2192bdff734d7d2891630bc30b2518
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen#include "lib.h"
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen#include "str.h"
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen#include "mail-error.h"
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen#include <sys/stat.h>
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen#include <unistd.h>
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen#include <pwd.h>
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen#include <grp.h>
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenbool mail_error_from_errno(enum mail_error *error_r,
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen const char **error_string_r)
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen{
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen if (ENOACCESS(errno)) {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen *error_r = MAIL_ERROR_PERM;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen *error_string_r = MAIL_ERRSTR_NO_PERMISSION;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen } else if (ENOSPACE(errno)) {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen *error_r = MAIL_ERROR_NOSPACE;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen *error_string_r = MAIL_ERRSTR_NO_SPACE;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen } else if (ENOTFOUND(errno)) {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen *error_r = MAIL_ERROR_NOTFOUND;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen *error_string_r = errno != ELOOP ? "Not found" :
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen "Directory structure is broken";
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen } else {
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen return FALSE;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen }
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen return TRUE;
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen}
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainenstatic const char *
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainenmail_error_eacces_msg_full(const char *func, const char *path, bool creating)
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen{
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen const char *prev_path = path, *dir = "/", *p;
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen const struct passwd *pw;
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen const struct group *group;
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen string_t *errmsg;
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen struct stat st;
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen int ret = -1;
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen errmsg = t_str_new(256);
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen str_printfa(errmsg, "%s(%s) failed: Permission denied (euid=%s",
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen func, path, dec2str(geteuid()));
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen pw = getpwuid(geteuid());
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen if (pw != NULL)
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen str_printfa(errmsg, "(%s)", pw->pw_name);
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen str_printfa(errmsg, " egid=%s", dec2str(getegid()));
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen group = getgrgid(getegid());
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen if (group != NULL)
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen str_printfa(errmsg, "(%s)", group->gr_name);
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen while ((p = strrchr(prev_path, '/')) != NULL) {
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen dir = t_strdup_until(prev_path, p);
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen ret = stat(dir, &st);
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen if (ret == 0)
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen break;
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen if (errno == EACCES) {
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen /* see if we have access to parent directory */
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen } else if (errno == ENOENT && creating) {
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen /* probably mkdir_parents() failed here, find the first
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen parent directory we couldn't create */
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen } else {
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen /* some other error, can't handle it */
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen str_printfa(errmsg, " stat(%s) failed: %m", dir);
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen break;
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen }
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen prev_path = dir;
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen dir = "/";
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen }
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen if (ret == 0) {
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen /* dir is the first parent directory we can stat() */
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen if (access(dir, X_OK) < 0) {
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen if (errno == EACCES)
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen str_printfa(errmsg, " missing +x perm: %s", dir);
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen else
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen str_printfa(errmsg, " access(%s, x) failed: %m", dir);
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen } else if (prev_path == path && access(path, R_OK) < 0) {
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen if (errno == EACCES)
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen str_printfa(errmsg, " missing +r perm: %s", path);
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen else
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen str_printfa(errmsg, " access(%s, r) failed: %m", path);
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen } else if (creating && access(dir, W_OK) < 0) {
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen if (errno == EACCES)
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen str_printfa(errmsg, " missing +w perm: %s", dir);
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen else
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen str_printfa(errmsg, " access(%s, w) failed: %m", dir);
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen } else
c6421c8849017f4db934db1fa075d786bcb794c9Timo Sirainen str_printfa(errmsg, " UNIX perms seem ok, ACL problem?");
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen }
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen str_append_c(errmsg, ')');
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen return str_c(errmsg);
9e9f0cf3cc3ce546e8a433990c92dd9be6665df6Timo Sirainen}
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainenconst char *mail_error_eacces_msg(const char *func, const char *path)
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen{
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen return mail_error_eacces_msg_full(func, path, FALSE);
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen}
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainenconst char *mail_error_create_eacces_msg(const char *func, const char *path)
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen{
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen return mail_error_eacces_msg_full(func, path, TRUE);
7b85f7d35b2192bdff734d7d2891630bc30b2518Timo Sirainen}