bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen for (i = 0; i < count; i++) {
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainenstatic void write_eacces_error(string_t *errmsg, const char *path, int mode)
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen str_printfa(errmsg, " missing +%c perm: %s", c, path);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainentest_manual_access(const char *path, int access_mode, bool write_eacces,
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen str_printfa(errmsg, " stat(%s) failed: %m", path);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen write_eacces_error(errmsg, path, access_mode);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen /* group would have had enough permissions,
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen but we don't belong to the group */
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen str_printfa(errmsg, ", we're not in group %s",
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainenstatic int test_access(const char *path, int access_mode, string_t *errmsg)
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen write_eacces_error(errmsg, path, access_mode);
23bd9fccb78de27232c48c8b1d75ef2145d51dedTimo Sirainen "(ACL/MAC wrong?)");
4dfaf598d6f2539caaab7ff0dd51d24a20928db8Timo Sirainen str_printfa(errmsg, ", access(%s, %d) failed: %m",
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen /* access() uses real uid, not effective uid.
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen we'll have to do these checks manually. */
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen if (stat(t_strconcat(path, "/test", NULL), &st) == 0)
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen write_eacces_error(errmsg, path, access_mode);
4dfaf598d6f2539caaab7ff0dd51d24a20928db8Timo Sirainen str_printfa(errmsg, ", stat(%s/test) failed: %m", path);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen return test_manual_access(path, access_mode, TRUE, errmsg);
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainenstatic const char *
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Siraineneacces_error_get_full(const char *func, const char *path, bool creating)
f0913bab58841032fa0ac719771f78bc3a4fd23eMartti Rannanjärvi if (t_get_working_dir(&dir, &error) < 0) {
f0913bab58841032fa0ac719771f78bc3a4fd23eMartti Rannanjärvi i_error("eacces_error_get_full: %s", error);
f0913bab58841032fa0ac719771f78bc3a4fd23eMartti Rannanjärvi str_printfa(errmsg, " in an unknown directory");
761c440316cc003817b3375b627287eceb6f6dceTimo Sirainen str_printfa(errmsg, " failed: Permission denied (euid=%s",
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen str_printfa(errmsg, " egid=%s", dec2str(getegid()));
882eb225340a9fae014c22b7ac4118f1580e2d60Timo Sirainen if (errno == EACCES && strcmp(dir, "/") != 0) {
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen /* see if we have access to parent directory */
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen /* probably mkdir_parents() failed here, find the first
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen parent directory we couldn't create */
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen /* some other error, can't handle it */
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen str_printfa(errmsg, " stat(%s) failed: %m", dir);
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen /* dir is the first parent directory we can stat() */
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen } else if (creating && test_access(dir, W_OK, errmsg) < 0) {
826d9b7a1dec011e4777b334af5f4dc4feebb64bTimo Sirainen } else if (!creating && test_access(path, W_OK, errmsg) < 0) {
826d9b7a1dec011e4777b334af5f4dc4feebb64bTimo Sirainen /* this produces a wrong error if the operation didn't
826d9b7a1dec011e4777b334af5f4dc4feebb64bTimo Sirainen actually need write permissions, but we don't know
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen "(ACL/MAC wrong?)");
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen if (pw_name != NULL && i_getpwuid(st.st_uid, &pw) > 0 &&
49dc101839b5f37a1a3c000421796f162e0017d9Timo Sirainen str_printfa(errmsg, ", conflicting dir uid=%s(%s)",
80b837ed54521cbd241110c2c6b58c02d187b818Timo Sirainen str_printfa(errmsg, ", dir owned by %s:%s mode=0%o",
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen } else if (missing_mode != 0 &&
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen (((st.st_mode & 0700) >> 6) & missing_mode) == 0) {
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen str_append(errmsg, ", dir owner missing perms");
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen if (ret == 0 && gr_name != NULL && st.st_gid != getegid()) {
49dc101839b5f37a1a3c000421796f162e0017d9Timo Sirainen str_printfa(errmsg, ", conflicting dir gid=%s(%s)",
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainenconst char *eacces_error_get(const char *func, const char *path)
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen return eacces_error_get_full(func, path, FALSE);
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainenconst char *eacces_error_get_creating(const char *func, const char *path)
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen return eacces_error_get_full(func, path, TRUE);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainenconst char *eperm_error_get_chgrp(const char *func, const char *path,
4a3e6e01ea368e9a90dc32abc40aea46fe93f926Timo Sirainen str_printfa(errmsg, "%s(%s, group=%s", func, path, dec2str(gid));
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen str_printfa(errmsg, ") failed: Operation not permitted (egid=%s",
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen str_printfa(errmsg, ", group based on %s", gid_origin);