bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "lib.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "ioloop.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "array.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "istream.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "nfs-workarounds.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "mail-storage-private.h"
4c158400b046fefefce0194603951a6587f51867Timo Sirainen#include "acl-global-file.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include "acl-cache.h"
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen#include "acl-backend-vfile.h"
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include <fcntl.h>
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include <unistd.h>
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#include <sys/stat.h>
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen#define ACL_ESTALE_RETRY_COUNT NFS_ESTALE_RETRY_COUNT
ccd4a548556a72a74a8183fa46cdd616dceae456Timo Sirainen#define ACL_VFILE_DEFAULT_CACHE_SECS 30
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainenstatic struct acl_backend *acl_backend_vfile_alloc(void)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_backend_vfile *backend;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen pool_t pool;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen pool = pool_alloconly_create("ACL backend", 512);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen backend = p_new(pool, struct acl_backend_vfile, 1);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen backend->backend.pool = pool;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return &backend->backend;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainenstatic int
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainenacl_backend_vfile_init(struct acl_backend *_backend, const char *data)
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen{
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen struct acl_backend_vfile *backend =
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen (struct acl_backend_vfile *)_backend;
4c158400b046fefefce0194603951a6587f51867Timo Sirainen struct stat st;
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen const char *const *tmp;
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen tmp = t_strsplit(data, ":");
4c158400b046fefefce0194603951a6587f51867Timo Sirainen backend->global_path = p_strdup_empty(_backend->pool, *tmp);
7dc2c953377fdf3f98e392c2eb7c9caa3dfc5d4fTimo Sirainen backend->cache_secs = ACL_VFILE_DEFAULT_CACHE_SECS;
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen
9fa54323c1382c969190ec46eb1c7ca783aec9b9Timo Sirainen if (*tmp != NULL)
9fa54323c1382c969190ec46eb1c7ca783aec9b9Timo Sirainen tmp++;
9fa54323c1382c969190ec46eb1c7ca783aec9b9Timo Sirainen for (; *tmp != NULL; tmp++) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (strncmp(*tmp, "cache_secs=", 11) == 0) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (str_to_uint(*tmp + 11, &backend->cache_secs) < 0) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen i_error("acl vfile: Invalid cache_secs value: %s",
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen *tmp + 11);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen return -1;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen }
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen } else {
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen i_error("acl vfile: Unknown parameter: %s", *tmp);
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen return -1;
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen }
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen }
4c158400b046fefefce0194603951a6587f51867Timo Sirainen if (backend->global_path != NULL) {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen if (stat(backend->global_path, &st) < 0) {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen if (errno != ENOENT) {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen i_error("acl vfile: stat(%s) failed: %m",
4c158400b046fefefce0194603951a6587f51867Timo Sirainen backend->global_path);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen return -1;
4c158400b046fefefce0194603951a6587f51867Timo Sirainen }
4c158400b046fefefce0194603951a6587f51867Timo Sirainen } else if (!S_ISDIR(st.st_mode)) {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen _backend->global_file =
e2e6f40d58b85041ca77338026a17d6708f324efTimo Sirainen acl_global_file_init(backend->global_path, backend->cache_secs,
e2e6f40d58b85041ca77338026a17d6708f324efTimo Sirainen _backend->debug);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen }
4c158400b046fefefce0194603951a6587f51867Timo Sirainen }
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen if (_backend->debug) {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen if (backend->global_path == NULL)
4c158400b046fefefce0194603951a6587f51867Timo Sirainen i_debug("acl vfile: Global ACLs disabled");
4c158400b046fefefce0194603951a6587f51867Timo Sirainen else if (_backend->global_file != NULL) {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen i_debug("acl vfile: Global ACL file: %s",
4c158400b046fefefce0194603951a6587f51867Timo Sirainen backend->global_path);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen } else {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen i_debug("acl vfile: Global ACL legacy directory: %s",
4c158400b046fefefce0194603951a6587f51867Timo Sirainen backend->global_path);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen }
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen }
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen _backend->cache =
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen acl_cache_init(_backend,
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen sizeof(struct acl_backend_vfile_validity));
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen return 0;
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen}
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainenstatic void acl_backend_vfile_deinit(struct acl_backend *_backend)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainen struct acl_backend_vfile *backend =
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainen (struct acl_backend_vfile *)_backend;
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainen
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainen if (backend->acllist_pool != NULL) {
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainen array_free(&backend->acllist);
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainen pool_unref(&backend->acllist_pool);
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainen }
4c158400b046fefefce0194603951a6587f51867Timo Sirainen if (_backend->global_file != NULL)
4c158400b046fefefce0194603951a6587f51867Timo Sirainen acl_global_file_deinit(&_backend->global_file);
395ad9a760c494a2106fada1392c5432a1629de6Timo Sirainen pool_unref(&backend->backend.pool);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainenstatic const char *
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainenacl_backend_vfile_get_local_dir(struct acl_backend *backend,
4c158400b046fefefce0194603951a6587f51867Timo Sirainen const char *name, const char *vname)
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen{
1cfa65c0b9df2508b084774d349af58b5c6c1941Timo Sirainen struct mail_namespace *ns = mailbox_list_get_namespace(backend->list);
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen struct mailbox_list *list = ns->list;
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen struct mail_storage *storage;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen enum mailbox_list_path_type type;
4c158400b046fefefce0194603951a6587f51867Timo Sirainen const char *dir, *inbox;
375848bde4272b83b43865698f88c1b75f39162dTimo Sirainen
375848bde4272b83b43865698f88c1b75f39162dTimo Sirainen if (*name == '\0')
375848bde4272b83b43865698f88c1b75f39162dTimo Sirainen name = NULL;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
5714c480bb705939ef33de2ec7e8fb501809aa49Timo Sirainen if (backend->globals_only)
5714c480bb705939ef33de2ec7e8fb501809aa49Timo Sirainen return NULL;
5714c480bb705939ef33de2ec7e8fb501809aa49Timo Sirainen
8d9540a4536e294e69beb3d1f5b378eb06ba8bdaTimo Sirainen /* ACL files are very important. try to keep them among the main
8d9540a4536e294e69beb3d1f5b378eb06ba8bdaTimo Sirainen mail files. that's not possible though with a) if the mailbox is
8d9540a4536e294e69beb3d1f5b378eb06ba8bdaTimo Sirainen a file or b) if the mailbox path doesn't point to filesystem. */
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen if (mailbox_list_get_storage(&list, vname, &storage) < 0)
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen return NULL;
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen i_assert(list == ns->list);
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen type = mail_storage_is_mailbox_file(storage) ||
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen (storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NO_ROOT) != 0 ?
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen MAILBOX_LIST_PATH_TYPE_CONTROL : MAILBOX_LIST_PATH_TYPE_MAILBOX;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (name == NULL) {
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen if (!mailbox_list_get_root_path(list, type, &dir))
4c158400b046fefefce0194603951a6587f51867Timo Sirainen return NULL;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen } else {
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen if (mailbox_list_get_path(list, name, type, &dir) <= 0)
375848bde4272b83b43865698f88c1b75f39162dTimo Sirainen return NULL;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen }
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* verify that the directory isn't same as INBOX's directory.
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen this is mainly for Maildir. */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (name == NULL &&
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen mailbox_list_get_path(list, "INBOX",
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX, &inbox) > 0 &&
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen strcmp(inbox, dir) == 0) {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen /* can't have default ACLs with this setup */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return NULL;
375848bde4272b83b43865698f88c1b75f39162dTimo Sirainen }
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen return dir;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen}
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic struct acl_object *
e7ca5f820d6a1a8fe549a2966ac707a60e055ef4Timo Sirainenacl_backend_vfile_object_init(struct acl_backend *_backend,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const char *name)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_backend_vfile *backend =
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen (struct acl_backend_vfile *)_backend;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_object_vfile *aclobj;
4c158400b046fefefce0194603951a6587f51867Timo Sirainen const char *dir, *vname, *error;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen aclobj = i_new(struct acl_object_vfile, 1);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen aclobj->aclobj.backend = _backend;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen aclobj->aclobj.name = i_strdup(name);
f35410e3121ced145c4d76da08be866a305b08ccTimo Sirainen
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen T_BEGIN {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen if (*name == '\0' ||
4c158400b046fefefce0194603951a6587f51867Timo Sirainen mailbox_list_is_valid_name(_backend->list, name, &error)) {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen vname = *name == '\0' ? "" :
4c158400b046fefefce0194603951a6587f51867Timo Sirainen mailbox_list_get_vname(_backend->list, name);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen
4c158400b046fefefce0194603951a6587f51867Timo Sirainen dir = acl_backend_vfile_get_local_dir(_backend, name, vname);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen aclobj->local_path = dir == NULL ? NULL :
4c158400b046fefefce0194603951a6587f51867Timo Sirainen i_strconcat(dir, "/"ACL_FILENAME, NULL);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen if (backend->global_path != NULL &&
4c158400b046fefefce0194603951a6587f51867Timo Sirainen _backend->global_file == NULL) {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen aclobj->global_path =
f87daf83d4fc2db884e071475a21c54be9307689Timo Sirainen i_strconcat(backend->global_path, "/", vname, NULL);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen }
4c158400b046fefefce0194603951a6587f51867Timo Sirainen } else {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen /* Invalid mailbox name, just use the default
4c158400b046fefefce0194603951a6587f51867Timo Sirainen global ACL files */
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen }
949fa97a4ab5c62e4db73c3973e35ae3b73a2b23Timo Sirainen } T_END;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return &aclobj->aclobj;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainenstatic const char *
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenget_parent_mailbox(struct acl_backend *backend, const char *name)
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen{
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen const char *p;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
6a764a456e4d0789e9cc0b6a95b72001737e819aTimo Sirainen p = strrchr(name, mailbox_list_get_hierarchy_sep(backend->list));
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen return p == NULL ? NULL : t_strdup_until(name, p);
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen}
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainenstatic int
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainenacl_backend_vfile_exists(struct acl_backend_vfile *backend, const char *path,
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen struct acl_vfile_validity *validity)
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen{
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen struct stat st;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen if (validity->last_check + (time_t)backend->cache_secs > ioloop_time) {
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen /* use the cached value */
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen return validity->last_mtime != ACL_VFILE_VALIDITY_MTIME_NOTFOUND ? 1 : 0;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen }
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen validity->last_check = ioloop_time;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen if (stat(path, &st) < 0) {
72f0ed440e0ad7046d5f1ae14450a197ff5365a9Timo Sirainen if (errno == ENOENT || errno == ENOTDIR) {
71966291d5f91a87394ad2e321250e1d02670a84Timo Sirainen validity->last_mtime = ACL_VFILE_VALIDITY_MTIME_NOTFOUND;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen return 0;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen }
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen if (errno == EACCES) {
71966291d5f91a87394ad2e321250e1d02670a84Timo Sirainen validity->last_mtime = ACL_VFILE_VALIDITY_MTIME_NOACCESS;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen return 1;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen }
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen i_error("stat(%s) failed: %m", path);
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen return -1;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen }
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen validity->last_mtime = st.st_mtime;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen validity->last_size = st.st_size;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen return 1;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen}
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainenstatic bool
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenacl_backend_vfile_has_acl(struct acl_backend *_backend, const char *name)
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen{
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen struct acl_backend_vfile *backend =
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen (struct acl_backend_vfile *)_backend;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen struct acl_backend_vfile_validity *old_validity, new_validity;
4c158400b046fefefce0194603951a6587f51867Timo Sirainen const char *path, *local_path, *global_path, *dir, *vname = "";
4c158400b046fefefce0194603951a6587f51867Timo Sirainen const char *error;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen int ret;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen old_validity = acl_cache_get_validity(_backend->cache, name);
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen if (old_validity != NULL)
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen new_validity = *old_validity;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen else
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&new_validity);
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen /* See if the mailbox exists. If we wanted recursive lookups we could
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen skip this, but at least for now we assume that if an existing
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen mailbox has no ACL it's equivalent to default ACLs. */
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_list_get_path(_backend->list, name,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX, &path) <= 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen ret = -1;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen else {
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen ret = acl_backend_vfile_exists(backend, path,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen &new_validity.mailbox_validity);
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen }
4c158400b046fefefce0194603951a6587f51867Timo Sirainen
375848bde4272b83b43865698f88c1b75f39162dTimo Sirainen if (ret == 0 &&
4c158400b046fefefce0194603951a6587f51867Timo Sirainen (*name == '\0' ||
4c158400b046fefefce0194603951a6587f51867Timo Sirainen mailbox_list_is_valid_name(_backend->list, name, &error))) {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen vname = *name == '\0' ? "" :
4c158400b046fefefce0194603951a6587f51867Timo Sirainen mailbox_list_get_vname(_backend->list, name);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen dir = acl_backend_vfile_get_local_dir(_backend, name, vname);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen if (dir != NULL) {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen local_path = t_strconcat(dir, "/", name, NULL);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen ret = acl_backend_vfile_exists(backend, local_path,
4c158400b046fefefce0194603951a6587f51867Timo Sirainen &new_validity.local_validity);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen }
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen }
4c158400b046fefefce0194603951a6587f51867Timo Sirainen
4c158400b046fefefce0194603951a6587f51867Timo Sirainen if (ret == 0 && backend->global_path != NULL) {
22e74047a660ee770427920d755d9cda564c2babTimo Sirainen if (_backend->global_file != NULL) {
22e74047a660ee770427920d755d9cda564c2babTimo Sirainen ret = acl_global_file_refresh(_backend->global_file);
22e74047a660ee770427920d755d9cda564c2babTimo Sirainen if (ret == 0 && acl_global_file_have_any(_backend->global_file, vname))
22e74047a660ee770427920d755d9cda564c2babTimo Sirainen ret = 1;
22e74047a660ee770427920d755d9cda564c2babTimo Sirainen } else {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen global_path = t_strconcat(backend->global_path, "/", name, NULL);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen ret = acl_backend_vfile_exists(backend, global_path,
4c158400b046fefefce0194603951a6587f51867Timo Sirainen &new_validity.global_validity);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen }
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen }
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen acl_cache_set_validity(_backend->cache, name, &new_validity);
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen return ret > 0;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen}
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainenstatic struct acl_object *
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainenacl_backend_vfile_object_init_parent(struct acl_backend *backend,
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen const char *child_name)
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen{
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen const char *parent;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen /* stop at the first parent that
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen a) has global ACL file
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen b) has local ACL file
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen c) exists */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen while ((parent = get_parent_mailbox(backend, child_name)) != NULL) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (acl_backend_vfile_has_acl(backend, parent))
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen break;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen child_name = parent;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen }
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen if (parent == NULL) {
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen /* use the root */
515d649c1802beb48433b90125518c00d0a1fbb4Timo Sirainen parent = acl_backend_get_default_object(backend)->name;
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return acl_backend_vfile_object_init(backend, parent);
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen}
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic void acl_backend_vfile_object_deinit(struct acl_object *_aclobj)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_object_vfile *aclobj = (struct acl_object_vfile *)_aclobj;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen i_free(aclobj->local_path);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen i_free(aclobj->global_path);
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen if (array_is_created(&aclobj->aclobj.rights))
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen array_free(&aclobj->aclobj.rights);
c69a177207ed18d0f0210347430a60957136bd6cJosef 'Jeff' Sipek pool_unref(&aclobj->aclobj.rights_pool);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen i_free(aclobj->aclobj.name);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen i_free(aclobj);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic int
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainenacl_backend_vfile_read(struct acl_object *aclobj, bool global, const char *path,
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen struct acl_vfile_validity *validity, bool try_retry,
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen bool *is_dir_r)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct istream *input;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct stat st;
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen struct acl_rights rights;
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen const char *line, *error;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int linenum;
ec238b744181bc41796d84d8e0ef5a23bca73bf2Timo Sirainen int fd, ret = 0;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen *is_dir_r = FALSE;
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen fd = nfs_safe_open(path, O_RDONLY);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (fd == -1) {
72f0ed440e0ad7046d5f1ae14450a197ff5365a9Timo Sirainen if (errno == ENOENT || errno == ENOTDIR) {
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen if (aclobj->backend->debug)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("acl vfile: file %s not found", path);
71966291d5f91a87394ad2e321250e1d02670a84Timo Sirainen validity->last_mtime = ACL_VFILE_VALIDITY_MTIME_NOTFOUND;
730aee6c3bb2e4f2125bcdb02be4d01c4082a8e9Timo Sirainen } else if (errno == EACCES) {
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen if (aclobj->backend->debug)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("acl vfile: no access to file %s",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk path);
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen acl_object_remove_all_access(aclobj);
71966291d5f91a87394ad2e321250e1d02670a84Timo Sirainen validity->last_mtime = ACL_VFILE_VALIDITY_MTIME_NOACCESS;
730aee6c3bb2e4f2125bcdb02be4d01c4082a8e9Timo Sirainen } else {
730aee6c3bb2e4f2125bcdb02be4d01c4082a8e9Timo Sirainen i_error("open(%s) failed: %m", path);
730aee6c3bb2e4f2125bcdb02be4d01c4082a8e9Timo Sirainen return -1;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
730aee6c3bb2e4f2125bcdb02be4d01c4082a8e9Timo Sirainen
730aee6c3bb2e4f2125bcdb02be4d01c4082a8e9Timo Sirainen validity->last_size = 0;
730aee6c3bb2e4f2125bcdb02be4d01c4082a8e9Timo Sirainen validity->last_read_time = ioloop_time;
730aee6c3bb2e4f2125bcdb02be4d01c4082a8e9Timo Sirainen return 1;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen if (fstat(fd, &st) < 0) {
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen if (errno == ESTALE && try_retry) {
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen return 0;
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen }
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen
e7ca5f820d6a1a8fe549a2966ac707a60e055ef4Timo Sirainen i_error("fstat(%s) failed: %m", path);
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen return -1;
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen }
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen if (S_ISDIR(st.st_mode)) {
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen /* we opened a directory. */
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen *is_dir_r = TRUE;
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen return 0;
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen }
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen if (aclobj->backend->debug)
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("acl vfile: reading file %s", path);
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen
e93184a9055c2530366dfe617e07199603c399ddMartti Rannanjärvi input = i_stream_create_fd(fd, (size_t)-1);
d4854db53e9c141db3d02821ed857bea101b1cc2Timo Sirainen i_stream_set_return_partial_line(input, TRUE);
bf04396da8310add0275b337263da21cb5d3ce1bTimo Sirainen linenum = 0;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen while ((line = i_stream_read_next_line(input)) != NULL) {
bf04396da8310add0275b337263da21cb5d3ce1bTimo Sirainen linenum++;
bf04396da8310add0275b337263da21cb5d3ce1bTimo Sirainen if (line[0] == '\0' || line[0] == '#')
bf04396da8310add0275b337263da21cb5d3ce1bTimo Sirainen continue;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen T_BEGIN {
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen ret = acl_rights_parse_line(line, aclobj->rights_pool,
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen &rights, &error);
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen rights.global = global;
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen if (ret < 0) {
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen i_error("ACL file %s line %u: %s",
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen path, linenum, error);
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen } else {
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen array_append(&aclobj->rights, &rights, 1);
15f43b172d2c626aa03c921979c49821a55c7e5eTimo Sirainen }
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen } T_END;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (ret < 0)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
ec238b744181bc41796d84d8e0ef5a23bca73bf2Timo Sirainen if (ret < 0) {
ec238b744181bc41796d84d8e0ef5a23bca73bf2Timo Sirainen /* parsing failure */
ec238b744181bc41796d84d8e0ef5a23bca73bf2Timo Sirainen } else if (input->stream_errno != 0) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (input->stream_errno == ESTALE && try_retry)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ret = 0;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen else {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ret = -1;
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen i_error("read(%s) failed: %s", path,
0f3d4fbcf88e2ffd674893aed8cc1288fe17d290Timo Sirainen i_stream_get_error(input));
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
ec238b744181bc41796d84d8e0ef5a23bca73bf2Timo Sirainen } else {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (fstat(fd, &st) < 0) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (errno == ESTALE && try_retry)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ret = 0;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen else {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen ret = -1;
ec238b744181bc41796d84d8e0ef5a23bca73bf2Timo Sirainen i_error("fstat(%s) failed: %m", path);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen } else {
ec238b744181bc41796d84d8e0ef5a23bca73bf2Timo Sirainen ret = 1;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen validity->last_read_time = ioloop_time;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen validity->last_mtime = st.st_mtime;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen validity->last_size = st.st_size;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen i_stream_unref(&input);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (close(fd) < 0) {
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (errno == ESTALE && try_retry)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return 0;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
e7ca5f820d6a1a8fe549a2966ac707a60e055ef4Timo Sirainen i_error("close(%s) failed: %m", path);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return -1;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return ret;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic int
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainenacl_backend_vfile_read_with_retry(struct acl_object *aclobj,
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen bool global, const char *path,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen struct acl_vfile_validity *validity)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen unsigned int i;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen int ret;
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen bool is_dir;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
a1b472db72081f8a27edf69497fd20d173789111Timo Sirainen if (path == NULL)
a1b472db72081f8a27edf69497fd20d173789111Timo Sirainen return 0;
a1b472db72081f8a27edf69497fd20d173789111Timo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen for (i = 0;; i++) {
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen ret = acl_backend_vfile_read(aclobj, global, path, validity,
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen i < ACL_ESTALE_RETRY_COUNT,
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen &is_dir);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (ret != 0)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen break;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen if (is_dir) {
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen /* opened a directory. use dir/.DEFAULT instead */
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen path = t_strconcat(path, "/.DEFAULT", NULL);
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen } else {
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen /* ESTALE - try again */
96182e7a3a64a967c0a1d718024c2063f77d371fTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return ret <= 0 ? -1 : 0;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
f2de2be0e3453cdfa1d9eebd4d4361720ab60affTimo Sirainenstatic bool
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainenacl_vfile_validity_has_changed(struct acl_backend_vfile *backend,
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen const struct acl_vfile_validity *validity,
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen const struct stat *st)
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen{
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen if (st->st_mtime == validity->last_mtime &&
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen st->st_size == validity->last_size) {
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen /* same timestamp, but if it was modified within the
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen same second we want to refresh it again later (but
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen do it only after a couple of seconds so we don't
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen keep re-reading it all the time within those
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen seconds) */
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen time_t cache_secs = backend->cache_secs;
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen if (validity->last_read_time != 0 &&
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen (st->st_mtime < validity->last_read_time - cache_secs ||
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen ioloop_time - validity->last_read_time <= cache_secs))
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen return FALSE;
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen }
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen return TRUE;
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen}
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic int
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainenacl_backend_vfile_refresh(struct acl_object *aclobj, const char *path,
e50c1eb31159d8ccc116d8fb487a5e231d2033a1Timo Sirainen struct acl_vfile_validity *validity)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen struct acl_backend_vfile *backend =
9e808b253bf5c20878fedfb44e4f2273db31da7cTimo Sirainen (struct acl_backend_vfile *)aclobj->backend;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct stat st;
bd2b326267f9fcaeee8455c581394eabcf377759Timo Sirainen int ret;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen if (validity == NULL)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return 1;
e50c1eb31159d8ccc116d8fb487a5e231d2033a1Timo Sirainen if (path == NULL ||
ff4bb2dfb5714eeb0408d3bb862de1646351d097Timo Sirainen validity->last_check + (time_t)backend->cache_secs > ioloop_time)
a1b472db72081f8a27edf69497fd20d173789111Timo Sirainen return 0;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
e50c1eb31159d8ccc116d8fb487a5e231d2033a1Timo Sirainen validity->last_check = ioloop_time;
bd2b326267f9fcaeee8455c581394eabcf377759Timo Sirainen ret = stat(path, &st);
bd2b326267f9fcaeee8455c581394eabcf377759Timo Sirainen if (ret == 0 && S_ISDIR(st.st_mode)) {
bd2b326267f9fcaeee8455c581394eabcf377759Timo Sirainen /* it's a directory. use dir/.DEFAULT instead */
bd2b326267f9fcaeee8455c581394eabcf377759Timo Sirainen path = t_strconcat(path, "/.DEFAULT", NULL);
bd2b326267f9fcaeee8455c581394eabcf377759Timo Sirainen ret = stat(path, &st);
bd2b326267f9fcaeee8455c581394eabcf377759Timo Sirainen }
bd2b326267f9fcaeee8455c581394eabcf377759Timo Sirainen
bd2b326267f9fcaeee8455c581394eabcf377759Timo Sirainen if (ret < 0) {
72f0ed440e0ad7046d5f1ae14450a197ff5365a9Timo Sirainen if (errno == ENOENT || errno == ENOTDIR) {
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen /* if the file used to exist, we have to re-read it */
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen return validity->last_mtime != ACL_VFILE_VALIDITY_MTIME_NOTFOUND ? 1 : 0;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen }
8c0e314c57b91253c8b2c3491e162967bd3a2cd3Timo Sirainen if (errno == EACCES)
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen return validity->last_mtime != ACL_VFILE_VALIDITY_MTIME_NOACCESS ? 1 : 0;
e7ca5f820d6a1a8fe549a2966ac707a60e055ef4Timo Sirainen i_error("stat(%s) failed: %m", path);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return -1;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen }
f988345bc29ef022ae73f96b3ec841d39c46d30aTimo Sirainen return acl_vfile_validity_has_changed(backend, validity, &st) ? 1 : 0;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainenint acl_backend_vfile_object_get_mtime(struct acl_object *aclobj,
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen time_t *mtime_r)
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen{
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen struct acl_backend_vfile_validity *validity;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen validity = acl_cache_get_validity(aclobj->backend->cache, aclobj->name);
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen if (validity == NULL)
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen return -1;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen if (validity->local_validity.last_mtime != 0)
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen *mtime_r = validity->local_validity.last_mtime;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen else if (validity->global_validity.last_mtime != 0)
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen *mtime_r = validity->global_validity.last_mtime;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen else
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen *mtime_r = 0;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen return 0;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen}
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainenstatic int
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainenacl_backend_global_file_refresh(struct acl_object *_aclobj,
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen struct acl_vfile_validity *validity)
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen{
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen struct acl_backend_vfile *backend =
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen (struct acl_backend_vfile *)_aclobj->backend;
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen struct stat st;
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen if (acl_global_file_refresh(_aclobj->backend->global_file) < 0)
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen return -1;
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen acl_global_file_last_stat(_aclobj->backend->global_file, &st);
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen if (validity == NULL)
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen return 1;
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen return acl_vfile_validity_has_changed(backend, validity, &st) ? 1 : 0;
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen}
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstatic int acl_backend_vfile_object_refresh_cache(struct acl_object *_aclobj)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen{
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen struct acl_object_vfile *aclobj = (struct acl_object_vfile *)_aclobj;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen struct acl_backend_vfile *backend =
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen (struct acl_backend_vfile *)_aclobj->backend;
e50c1eb31159d8ccc116d8fb487a5e231d2033a1Timo Sirainen struct acl_backend_vfile_validity *old_validity;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen struct acl_backend_vfile_validity validity;
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen time_t mtime;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen int ret;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen old_validity = acl_cache_get_validity(_aclobj->backend->cache,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen _aclobj->name);
4c158400b046fefefce0194603951a6587f51867Timo Sirainen ret = _aclobj->backend->global_file != NULL ?
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen acl_backend_global_file_refresh(_aclobj, old_validity == NULL ? NULL :
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen &old_validity->global_validity) :
4c158400b046fefefce0194603951a6587f51867Timo Sirainen acl_backend_vfile_refresh(_aclobj, aclobj->global_path,
4c158400b046fefefce0194603951a6587f51867Timo Sirainen old_validity == NULL ? NULL :
4c158400b046fefefce0194603951a6587f51867Timo Sirainen &old_validity->global_validity);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen if (ret == 0) {
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen ret = acl_backend_vfile_refresh(_aclobj, aclobj->local_path,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen old_validity == NULL ? NULL :
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen &old_validity->local_validity);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen }
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen if (ret <= 0)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return ret;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen /* either global or local ACLs changed, need to re-read both */
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen if (!array_is_created(&_aclobj->rights)) {
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen _aclobj->rights_pool =
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen pool_alloconly_create("acl rights", 256);
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen i_array_init(&_aclobj->rights, 16);
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen } else {
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen array_clear(&_aclobj->rights);
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen p_clear(_aclobj->rights_pool);
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen }
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&validity);
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen if (_aclobj->backend->global_file != NULL) {
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen struct stat st;
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen
4c158400b046fefefce0194603951a6587f51867Timo Sirainen acl_object_add_global_acls(_aclobj);
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen acl_global_file_last_stat(_aclobj->backend->global_file, &st);
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen validity.global_validity.last_read_time = ioloop_time;
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen validity.global_validity.last_mtime = st.st_mtime;
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen validity.global_validity.last_size = st.st_size;
af134287071b6d8a9e12c3f11a50fe9ad824d89aTimo Sirainen } else {
4c158400b046fefefce0194603951a6587f51867Timo Sirainen if (acl_backend_vfile_read_with_retry(_aclobj, TRUE, aclobj->global_path,
4c158400b046fefefce0194603951a6587f51867Timo Sirainen &validity.global_validity) < 0)
4c158400b046fefefce0194603951a6587f51867Timo Sirainen return -1;
4c158400b046fefefce0194603951a6587f51867Timo Sirainen }
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen if (acl_backend_vfile_read_with_retry(_aclobj, FALSE, aclobj->local_path,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen &validity.local_validity) < 0)
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return -1;
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen acl_rights_sort(_aclobj);
0d7b2e0750386fe1646a17d83a803d1d5eb3d3a0Timo Sirainen /* update cache only after we've successfully read everything */
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen acl_object_rebuild_cache(_aclobj);
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen acl_cache_set_validity(_aclobj->backend->cache,
08a0b7b0d0444875001847ef2b1b7b76122620abTimo Sirainen _aclobj->name, &validity);
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen if (acl_backend_vfile_object_get_mtime(_aclobj, &mtime) == 0)
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen acl_backend_vfile_acllist_verify(backend, _aclobj->name, mtime);
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen return 0;
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen}
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainenstatic int acl_backend_vfile_object_last_changed(struct acl_object *_aclobj,
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen time_t *last_changed_r)
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen{
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen struct acl_backend_vfile_validity *old_validity;
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen *last_changed_r = 0;
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen old_validity = acl_cache_get_validity(_aclobj->backend->cache,
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen _aclobj->name);
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen if (old_validity == NULL) {
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen if (acl_backend_vfile_object_refresh_cache(_aclobj) < 0)
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen return -1;
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen old_validity = acl_cache_get_validity(_aclobj->backend->cache,
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen _aclobj->name);
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen if (old_validity == NULL)
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen return 0;
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen }
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen *last_changed_r = old_validity->local_validity.last_mtime;
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen return 0;
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen}
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainenstruct acl_backend_vfuncs acl_backend_vfile = {
3809b9691c46926aa54968ac8e418d04361e1efaTimo Sirainen acl_backend_vfile_alloc,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_backend_vfile_init,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_backend_vfile_deinit,
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen acl_backend_vfile_nonowner_iter_init,
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen acl_backend_vfile_nonowner_iter_next,
2f122b4db3f0d4eeb59ff9d306e54b2009d72cf9Timo Sirainen acl_backend_vfile_nonowner_iter_deinit,
579e70631b8474d20fd3829f477c62950e5f9635Timo Sirainen acl_backend_vfile_nonowner_lookups_rebuild,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_backend_vfile_object_init,
da9f6acdcb303d0fe5160b669668aedf39c8f45aTimo Sirainen acl_backend_vfile_object_init_parent,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_backend_vfile_object_deinit,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_backend_vfile_object_refresh_cache,
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen acl_backend_vfile_object_update,
eb4d4f557fa75aa2a47639e9deb75a21f44eb42aTimo Sirainen acl_backend_vfile_object_last_changed,
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen acl_default_object_list_init,
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen acl_default_object_list_next,
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen acl_default_object_list_deinit
7fb70daba4e571eab5b64f496d20b9e37e31141bTimo Sirainen};