bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2007-2018 Dovecot authors, see the included COPYING file */
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen#include "lib.h"
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen#include "str.h"
dfa2201c6ac8ddb2d2798dee15662cfe774e644eMartti Rannanjärvi#include "path-util.h"
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen#include "ipwd.h"
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen#include "restrict-access.h"
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen#include "eacces-error.h"
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen#include <sys/stat.h>
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen#include <unistd.h>
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainenstatic bool is_in_group(gid_t gid)
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen{
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen const gid_t *gids;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen unsigned int i, count;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen if (getegid() == gid)
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen return TRUE;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen gids = restrict_get_groups_list(&count);
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen for (i = 0; i < count; i++) {
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen if (gids[i] == gid)
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen return TRUE;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen }
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen return FALSE;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen}
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainenstatic void write_eacces_error(string_t *errmsg, const char *path, int mode)
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen{
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen char c;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen switch (mode) {
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen case R_OK:
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen c = 'r';
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen break;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen case W_OK:
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen c = 'w';
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen break;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen case X_OK:
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen c = 'x';
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen break;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen default:
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen i_unreached();
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen }
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen str_printfa(errmsg, " missing +%c perm: %s", c, path);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen}
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainenstatic int
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainentest_manual_access(const char *path, int access_mode, bool write_eacces,
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen string_t *errmsg)
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen{
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen const struct group *group;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen bool user_not_in_group = FALSE;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen struct stat st;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen int mode;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (stat(path, &st) < 0) {
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen str_printfa(errmsg, " stat(%s) failed: %m", path);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen return -1;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen }
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen switch (access_mode) {
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen case R_OK:
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen mode = 04;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen break;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen case W_OK:
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen mode = 02;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen break;
74ec4fe074dfc487e9a5b98ff237391c082eceb1Timo Sirainen case X_OK:
74ec4fe074dfc487e9a5b98ff237391c082eceb1Timo Sirainen mode = 01;
74ec4fe074dfc487e9a5b98ff237391c082eceb1Timo Sirainen break;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen default:
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen i_unreached();
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen }
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (st.st_uid == geteuid())
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen st.st_mode = (st.st_mode & 0700) >> 6;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen else if (is_in_group(st.st_gid))
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen st.st_mode = (st.st_mode & 0070) >> 3;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen else {
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if ((((st.st_mode & 0070) >> 3) & mode) != 0)
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen user_not_in_group = TRUE;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen st.st_mode = (st.st_mode & 0007);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen }
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if ((st.st_mode & mode) != 0)
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen return 0;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (write_eacces)
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen write_eacces_error(errmsg, path, access_mode);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (user_not_in_group) {
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 Sirainen dec2str(st.st_gid));
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen group = getgrgid(st.st_gid);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (group != NULL)
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen str_printfa(errmsg, "(%s)", group->gr_name);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen }
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen errno = EACCES;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen return -1;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen}
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainenstatic int test_access(const char *path, int access_mode, string_t *errmsg)
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen{
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen struct stat st;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen if (getuid() == geteuid()) {
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (access(path, access_mode) == 0)
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen return 0;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (errno == EACCES) {
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen write_eacces_error(errmsg, path, access_mode);
23bd9fccb78de27232c48c8b1d75ef2145d51dedTimo Sirainen if (test_manual_access(path, access_mode,
23bd9fccb78de27232c48c8b1d75ef2145d51dedTimo Sirainen FALSE, errmsg) == 0) {
4dfaf598d6f2539caaab7ff0dd51d24a20928db8Timo Sirainen str_append(errmsg, ", UNIX perms appear ok "
23bd9fccb78de27232c48c8b1d75ef2145d51dedTimo Sirainen "(ACL/MAC wrong?)");
23bd9fccb78de27232c48c8b1d75ef2145d51dedTimo Sirainen }
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen errno = EACCES;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen } else {
4dfaf598d6f2539caaab7ff0dd51d24a20928db8Timo Sirainen str_printfa(errmsg, ", access(%s, %d) failed: %m",
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen path, access_mode);
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen }
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen return -1;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen }
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen /* access() uses real uid, not effective uid.
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen we'll have to do these checks manually. */
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen switch (access_mode) {
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen case X_OK:
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen if (stat(t_strconcat(path, "/test", NULL), &st) == 0)
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen return 0;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen if (errno == ENOENT || errno == ENOTDIR)
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen return 0;
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (errno == EACCES)
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen write_eacces_error(errmsg, path, access_mode);
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen else
4dfaf598d6f2539caaab7ff0dd51d24a20928db8Timo Sirainen str_printfa(errmsg, ", stat(%s/test) failed: %m", path);
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen return -1;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen case R_OK:
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen case W_OK:
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen break;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen default:
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen i_unreached();
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen }
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen return test_manual_access(path, access_mode, TRUE, errmsg);
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen}
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainenstatic const char *
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Siraineneacces_error_get_full(const char *func, const char *path, bool creating)
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen{
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen const char *prev_path, *dir = NULL, *p;
7ca397e910d2b267bcfaecbcdf9b23523c639776Timo Sirainen const char *pw_name = NULL, *gr_name = NULL;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen struct passwd pw;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen struct group group;
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen string_t *errmsg;
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen struct stat st;
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen int orig_errno, ret, missing_mode = 0;
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen orig_errno = errno;
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen errmsg = t_str_new(256);
761c440316cc003817b3375b627287eceb6f6dceTimo Sirainen str_printfa(errmsg, "%s(%s)", func, path);
761c440316cc003817b3375b627287eceb6f6dceTimo Sirainen if (*path != '/') {
f0913bab58841032fa0ac719771f78bc3a4fd23eMartti Rannanjärvi const char *error;
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");
f0913bab58841032fa0ac719771f78bc3a4fd23eMartti Rannanjärvi } else {
761c440316cc003817b3375b627287eceb6f6dceTimo Sirainen str_printfa(errmsg, " in directory %s", dir);
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen path = t_strconcat(dir, "/", path, NULL);
0471a9dde7b4fb55779261460c973f85088b4b0cTimo Sirainen }
761c440316cc003817b3375b627287eceb6f6dceTimo Sirainen }
761c440316cc003817b3375b627287eceb6f6dceTimo Sirainen str_printfa(errmsg, " failed: Permission denied (euid=%s",
761c440316cc003817b3375b627287eceb6f6dceTimo Sirainen dec2str(geteuid()));
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen switch (i_getpwuid(geteuid(), &pw)) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen case -1:
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen str_append(errmsg, "(<getpwuid() error>)");
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen break;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen case 0:
f3ef6fdc790caf67352a07829bedb117bc56fb78Timo Sirainen str_append(errmsg, "(<unknown>)");
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen break;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen default:
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen pw_name = t_strdup(pw.pw_name);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen str_printfa(errmsg, "(%s)", pw_name);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen break;
7ca397e910d2b267bcfaecbcdf9b23523c639776Timo Sirainen }
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen str_printfa(errmsg, " egid=%s", dec2str(getegid()));
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen switch (i_getgrgid(getegid(), &group)) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen case -1:
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen str_append(errmsg, "(<getgrgid() error>)");
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen break;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen case 0:
f3ef6fdc790caf67352a07829bedb117bc56fb78Timo Sirainen str_append(errmsg, "(<unknown>)");
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen break;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen default:
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen gr_name = t_strdup(group.gr_name);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen str_printfa(errmsg, "(%s)", gr_name);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen break;
7ca397e910d2b267bcfaecbcdf9b23523c639776Timo Sirainen }
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen prev_path = path; ret = -1;
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen while (strcmp(prev_path, "/") != 0) {
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen if ((p = strrchr(prev_path, '/')) == NULL)
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen break;
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen dir = t_strdup_until(prev_path, p);
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen ret = stat(dir, &st);
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen if (ret == 0)
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen break;
882eb225340a9fae014c22b7ac4118f1580e2d60Timo Sirainen if (errno == EACCES && strcmp(dir, "/") != 0) {
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen /* see if we have access to parent directory */
882eb225340a9fae014c22b7ac4118f1580e2d60Timo Sirainen } else if (errno == ENOENT && creating &&
882eb225340a9fae014c22b7ac4118f1580e2d60Timo Sirainen strcmp(dir, "/") != 0) {
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen /* probably mkdir_parents() failed here, find the first
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen parent directory we couldn't create */
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen } else {
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen /* some other error, can't handle it */
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen str_printfa(errmsg, " stat(%s) failed: %m", dir);
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen break;
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen }
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen prev_path = dir;
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen }
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen if (ret == 0) {
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen /* dir is the first parent directory we can stat() */
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen if (test_access(dir, X_OK, errmsg) < 0) {
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (errno == EACCES)
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen missing_mode = 1;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen } else if (creating && test_access(dir, W_OK, errmsg) < 0) {
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (errno == EACCES)
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen missing_mode = 2;
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen } else if (prev_path == path &&
5e9a39da0a9aba60b50e2c1d401f102703431b73Timo Sirainen test_access(path, R_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
826d9b7a1dec011e4777b334af5f4dc4feebb64bTimo Sirainen it here.. */
93e742e81653922361ce61f38319bd53e9bcad91Timo Sirainen if (errno == EACCES)
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen missing_mode = 4;
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen } else {
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen str_append(errmsg, " UNIX perms appear ok "
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen "(ACL/MAC wrong?)");
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen }
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen }
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen if (ret < 0)
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen ;
a497e8b94b55e035a1ebd28cf1368a8869ddaa62Timo Sirainen else if (st.st_uid != geteuid()) {
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen if (pw_name != NULL && i_getpwuid(st.st_uid, &pw) > 0 &&
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen strcmp(pw.pw_name, pw_name) == 0) {
49dc101839b5f37a1a3c000421796f162e0017d9Timo Sirainen str_printfa(errmsg, ", conflicting dir uid=%s(%s)",
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen dec2str(st.st_uid), pw_name);
49dc101839b5f37a1a3c000421796f162e0017d9Timo Sirainen } else {
80b837ed54521cbd241110c2c6b58c02d187b818Timo Sirainen str_printfa(errmsg, ", dir owned by %s:%s mode=0%o",
80b837ed54521cbd241110c2c6b58c02d187b818Timo Sirainen dec2str(st.st_uid), dec2str(st.st_gid),
b38d0e738ef8be0c437106ba7967a4bdf8057d32Timo Sirainen (unsigned int)(st.st_mode & 0777));
7ca397e910d2b267bcfaecbcdf9b23523c639776Timo Sirainen }
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");
7ca397e910d2b267bcfaecbcdf9b23523c639776Timo Sirainen }
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen if (ret == 0 && gr_name != NULL && st.st_gid != getegid()) {
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen if (i_getgrgid(st.st_gid, &group) > 0 &&
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen strcmp(group.gr_name, gr_name) == 0) {
49dc101839b5f37a1a3c000421796f162e0017d9Timo Sirainen str_printfa(errmsg, ", conflicting dir gid=%s(%s)",
37c4359391810bc5bab0d2c72d7d25d8335b2858Timo Sirainen dec2str(st.st_gid), gr_name);
7ca397e910d2b267bcfaecbcdf9b23523c639776Timo Sirainen }
7ca397e910d2b267bcfaecbcdf9b23523c639776Timo Sirainen }
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen str_append_c(errmsg, ')');
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen errno = orig_errno;
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen return str_c(errmsg);
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen}
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainenconst char *eacces_error_get(const char *func, const char *path)
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen{
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen return eacces_error_get_full(func, path, FALSE);
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen}
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainenconst char *eacces_error_get_creating(const char *func, const char *path)
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen{
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen return eacces_error_get_full(func, path, TRUE);
5cdd1691e5185ecfe424f5de7b6f697813b88ba2Timo Sirainen}
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainenconst char *eperm_error_get_chgrp(const char *func, const char *path,
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen gid_t gid, const char *gid_origin)
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen{
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen string_t *errmsg;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen const struct group *group;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen int orig_errno = errno;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen errmsg = t_str_new(256);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
4a3e6e01ea368e9a90dc32abc40aea46fe93f926Timo Sirainen str_printfa(errmsg, "%s(%s, group=%s", func, path, dec2str(gid));
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen group = getgrgid(gid);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen if (group != NULL)
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen str_printfa(errmsg, "(%s)", group->gr_name);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen str_printfa(errmsg, ") failed: Operation not permitted (egid=%s",
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen dec2str(getegid()));
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen group = getgrgid(getegid());
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen if (group != NULL)
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen str_printfa(errmsg, "(%s)", group->gr_name);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen if (gid_origin != NULL)
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen str_printfa(errmsg, ", group based on %s", gid_origin);
0622f54c063d2dca88f6b95daa6822cb386068caTimo Sirainen str_append(errmsg, " - see http://wiki2.dovecot.org/Errors/ChgrpNoPerm)");
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen errno = orig_errno;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen return str_c(errmsg);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen}