bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
cc287b822b175619a853686b738ba673e370117bTimo Sirainenstatic int acl_backend_vfile_update_begin(struct acl_object_vfile *aclobj,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen i_error("Can't update acl object '%s': No local acl file path",
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* first lock the ACL file */
cc287b822b175619a853686b738ba673e370117bTimo Sirainen mailbox_list_get_permissions(_aclobj->backend->list,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen fd = file_dotlock_open_group(&dotlock_set, aclobj->local_path, 0,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen i_error("file_dotlock_open(%s) failed: %m", aclobj->local_path);
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* locked successfully, re-read the existing file to make sure we
cc287b822b175619a853686b738ba673e370117bTimo Sirainen don't lose any changes. */
cc287b822b175619a853686b738ba673e370117bTimo Sirainen acl_cache_flush(_aclobj->backend->cache, _aclobj->name);
cc287b822b175619a853686b738ba673e370117bTimo Sirainen if (_aclobj->backend->v.object_refresh_cache(_aclobj) < 0) {
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainenvfile_object_modify_right(struct acl_object *aclobj, unsigned int idx,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen right = array_idx_modifiable(&aclobj->rights, idx);
cc287b822b175619a853686b738ba673e370117bTimo Sirainen c1 = acl_right_names_modify(aclobj->rights_pool, &right->rights,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen c2 = acl_right_names_modify(aclobj->rights_pool, &right->neg_rights,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen if (right->rights == NULL && right->neg_rights == NULL) {
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* this identifier no longer exists */
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainenvfile_object_add_right(struct acl_object *aclobj, unsigned int idx,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen if (update->modify_mode == ACL_MODIFY_MODE_REMOVE &&
cc287b822b175619a853686b738ba673e370117bTimo Sirainen update->neg_modify_mode == ACL_MODIFY_MODE_REMOVE) {
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* nothing to do */
cc287b822b175619a853686b738ba673e370117bTimo Sirainen right.identifier = p_strdup(aclobj->rights_pool,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen c1 = acl_right_names_modify(aclobj->rights_pool, &right.rights,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen c2 = acl_right_names_modify(aclobj->rights_pool, &right.neg_rights,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen array_insert(&aclobj->rights, idx, &right, 1);
cc287b822b175619a853686b738ba673e370117bTimo Sirainenvfile_write_right(string_t *dest, const struct acl_rights *right,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen const char *const *rights = neg ? right->neg_rights : right->rights;
cc287b822b175619a853686b738ba673e370117bTimo Sirainen if (strchr(str_c(dest), ' ') != NULL) T_BEGIN {
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* need to escape it */
cc287b822b175619a853686b738ba673e370117bTimo Sirainen const char *escaped = t_strdup(str_escape(str_c(dest)));
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainenacl_backend_vfile_update_write(struct acl_object *aclobj,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen output = o_stream_create_fd_file(fd, 0, FALSE);
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* rights are sorted with globals at the end, so we can stop at the
cc287b822b175619a853686b738ba673e370117bTimo Sirainen first global */
cc287b822b175619a853686b738ba673e370117bTimo Sirainen for (i = 0; i < count && !rights[i].global; i++) {
cc287b822b175619a853686b738ba673e370117bTimo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
cc287b822b175619a853686b738ba673e370117bTimo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* we really don't want to lose ACL files' contents, so fsync() always
cc287b822b175619a853686b738ba673e370117bTimo Sirainen before renaming */
cc287b822b175619a853686b738ba673e370117bTimo Sirainenstatic void acl_backend_vfile_update_cache(struct acl_object *_aclobj, int fd)
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* we'll just recalculate or fail it later */
cc287b822b175619a853686b738ba673e370117bTimo Sirainen acl_cache_flush(_aclobj->backend->cache, _aclobj->name);
cc287b822b175619a853686b738ba673e370117bTimo Sirainen validity = acl_cache_get_validity(_aclobj->backend->cache,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen validity->local_validity.last_read_time = ioloop_time;
cc287b822b175619a853686b738ba673e370117bTimo Sirainen validity->local_validity.last_mtime = st.st_mtime;
cc287b822b175619a853686b738ba673e370117bTimo Sirainen validity->local_validity.last_size = st.st_size;
cc287b822b175619a853686b738ba673e370117bTimo Sirainenint acl_backend_vfile_object_update(struct acl_object *_aclobj,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen unsigned int i;
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* global ACLs can't be updated here */
cc287b822b175619a853686b738ba673e370117bTimo Sirainen fd = acl_backend_vfile_update_begin(aclobj, &dotlock);
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen if (!array_bsearch_insert_pos(&_aclobj->rights, &update->rights,
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen changed = vfile_object_add_right(_aclobj, i, update);
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen changed = vfile_object_modify_right(_aclobj, i, update);
cc287b822b175619a853686b738ba673e370117bTimo Sirainen validity = acl_cache_get_validity(_aclobj->backend->cache,
cc287b822b175619a853686b738ba673e370117bTimo Sirainen orig_mtime = validity->local_validity.last_mtime;
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* ACLs were really changed, write the new ones */
086c52e4bcdc950e47ee331e1e07c9c10982a670Timo Sirainen if (acl_backend_vfile_update_write(_aclobj, fd, path) < 0) {
cc287b822b175619a853686b738ba673e370117bTimo Sirainen acl_cache_flush(_aclobj->backend->cache, _aclobj->name);
cc287b822b175619a853686b738ba673e370117bTimo Sirainen if (orig_mtime < update->last_change && update->last_change != 0) {
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* set mtime to last_change, if it's higher than the file's
cc287b822b175619a853686b738ba673e370117bTimo Sirainen original mtime. if original mtime is higher, then we're
cc287b822b175619a853686b738ba673e370117bTimo Sirainen merging some changes and it's better for the mtime to get
cc287b822b175619a853686b738ba673e370117bTimo Sirainen acl_cache_flush(_aclobj->backend->cache, _aclobj->name);
cc287b822b175619a853686b738ba673e370117bTimo Sirainen /* make sure dovecot-acl-list gets updated if we changed any
cc287b822b175619a853686b738ba673e370117bTimo Sirainen lookup rights. */
cc287b822b175619a853686b738ba673e370117bTimo Sirainen if (acl_rights_has_nonowner_lookup_changes(&update->rights) ||
cc287b822b175619a853686b738ba673e370117bTimo Sirainen update->modify_mode == ACL_MODIFY_MODE_REPLACE ||