dovecot-2.2: acl: Added ACL checks for attributes. Added ACL <->...
dovecot at dovecot.org
dovecot at dovecot.org
Thu Mar 14 15:41:49 EET 2013
details: http://hg.dovecot.org/dovecot-2.2/rev/3ba8fa6d3cc2
changeset: 16026:3ba8fa6d3cc2
user: Timo Sirainen <tss at iki.fi>
date: Thu Mar 14 15:41:39 2013 +0200
description:
acl: Added ACL checks for attributes. Added ACL <-> mailbox attribute mapping.
The ACL checks will be useful once IMAP METADATA extension is finished. The
mapping is used by dsync to sync ACLs via generic attribute syncing.
diffstat:
src/plugins/acl/Makefile.am | 1 +
src/plugins/acl/acl-api-private.h | 5 +
src/plugins/acl/acl-api.c | 100 ++++++++++++++
src/plugins/acl/acl-api.h | 9 +
src/plugins/acl/acl-attributes.c | 234 +++++++++++++++++++++++++++++++++
src/plugins/acl/acl-backend-vfile.c | 22 +++
src/plugins/acl/acl-mailbox.c | 60 +++++++-
src/plugins/acl/acl-plugin.h | 8 +
src/plugins/acl/acl-storage.h | 19 ++
src/plugins/acl/doveadm-acl.c | 121 +++-------------
src/plugins/imap-acl/imap-acl-plugin.c | 29 +++-
11 files changed, 499 insertions(+), 109 deletions(-)
diffs (truncated from 820 to 300 lines):
diff -r c6082de4bf5b -r 3ba8fa6d3cc2 src/plugins/acl/Makefile.am
--- a/src/plugins/acl/Makefile.am Thu Mar 14 15:41:09 2013 +0200
+++ b/src/plugins/acl/Makefile.am Thu Mar 14 15:41:39 2013 +0200
@@ -18,6 +18,7 @@
lib01_acl_plugin_la_SOURCES = \
acl-api.c \
+ acl-attributes.c \
acl-backend.c \
acl-backend-vfile.c \
acl-backend-vfile-acllist.c \
diff -r c6082de4bf5b -r 3ba8fa6d3cc2 src/plugins/acl/acl-api-private.h
--- a/src/plugins/acl/acl-api-private.h Thu Mar 14 15:41:09 2013 +0200
+++ b/src/plugins/acl/acl-api-private.h Thu Mar 14 15:41:39 2013 +0200
@@ -32,6 +32,7 @@
int (*object_refresh_cache)(struct acl_object *aclobj);
int (*object_update)(struct acl_object *aclobj,
const struct acl_rights_update *update);
+ int (*last_changed)(struct acl_object *aclobj, time_t *last_changed_r);
struct acl_object_list_iter *
(*object_list_init)(struct acl_object *aclobj);
@@ -86,5 +87,9 @@
bool acl_rights_has_nonowner_lookup_changes(const struct acl_rights *rights);
int acl_identifier_parse(const char *line, struct acl_rights *rights);
+int acl_rights_update_import(struct acl_rights_update *update,
+ const char *id, const char *const *rights,
+ const char **error_r);
+const char *acl_rights_export(const struct acl_rights *rights);
#endif
diff -r c6082de4bf5b -r 3ba8fa6d3cc2 src/plugins/acl/acl-api.c
--- a/src/plugins/acl/acl-api.c Thu Mar 14 15:41:09 2013 +0200
+++ b/src/plugins/acl/acl-api.c Thu Mar 14 15:41:39 2013 +0200
@@ -1,6 +1,7 @@
/* Copyright (c) 2006-2013 Dovecot authors, see the included COPYING file */
#include "lib.h"
+#include "array.h"
#include "str.h"
#include "hash.h"
#include "mail-user.h"
@@ -122,6 +123,11 @@
pool_datastack_create());
}
+int acl_object_last_changed(struct acl_object *aclobj, time_t *last_changed_r)
+{
+ return aclobj->backend->v.last_changed(aclobj, last_changed_r);
+}
+
int acl_object_update(struct acl_object *aclobj,
const struct acl_rights_update *update)
{
@@ -205,6 +211,100 @@
}
}
+const char *acl_rights_get_id(const struct acl_rights *right)
+{
+ string_t *str = t_str_new(32);
+
+ acl_rights_write_id(str, right);
+ return str_c(str);
+}
+
+static bool is_standard_right(const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; all_mailbox_rights[i] != NULL; i++) {
+ if (strcmp(all_mailbox_rights[i], name) == 0)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int acl_rights_update_import(struct acl_rights_update *update,
+ const char *id, const char *const *rights,
+ const char **error_r)
+{
+ ARRAY_TYPE(const_string) dest_rights, dest_neg_rights, *dest;
+ unsigned int i, j;
+
+ if (acl_identifier_parse(id, &update->rights) < 0) {
+ *error_r = t_strdup_printf("Invalid ID: %s", id);
+ return -1;
+ }
+ if (rights == NULL) {
+ update->modify_mode = ACL_MODIFY_MODE_CLEAR;
+ update->neg_modify_mode = ACL_MODIFY_MODE_CLEAR;
+ return 0;
+ }
+
+ t_array_init(&dest_rights, 8);
+ t_array_init(&dest_neg_rights, 8);
+ for (i = 0; rights[i] != NULL; i++) {
+ const char *right = rights[i];
+
+ if (right[0] != '-')
+ dest = &dest_rights;
+ else {
+ right++;
+ dest = &dest_neg_rights;
+ }
+ if (strcmp(right, "all") != 0) {
+ if (*right == ':') {
+ /* non-standard right */
+ right++;
+ array_append(dest, &right, 1);
+ } else if (is_standard_right(right)) {
+ array_append(dest, &right, 1);
+ } else {
+ *error_r = t_strdup_printf("Invalid right '%s'",
+ right);
+ return -1;
+ }
+ } else {
+ for (j = 0; all_mailbox_rights[j] != NULL; j++)
+ array_append(dest, &all_mailbox_rights[j], 1);
+ }
+ }
+ if (array_count(&dest_rights) > 0) {
+ array_append_zero(&dest_rights);
+ update->rights.rights = array_idx(&dest_rights, 0);
+ } else if (update->modify_mode == ACL_MODIFY_MODE_REPLACE) {
+ update->modify_mode = ACL_MODIFY_MODE_CLEAR;
+ }
+ if (array_count(&dest_neg_rights) > 0) {
+ array_append_zero(&dest_neg_rights);
+ update->rights.neg_rights = array_idx(&dest_neg_rights, 0);
+ } else if (update->neg_modify_mode == ACL_MODIFY_MODE_REPLACE) {
+ update->neg_modify_mode = ACL_MODIFY_MODE_CLEAR;
+ }
+ return 0;
+}
+
+const char *acl_rights_export(const struct acl_rights *rights)
+{
+ string_t *str = t_str_new(128);
+
+ if (rights->rights != NULL)
+ str_append(str, t_strarray_join(rights->rights, " "));
+ if (rights->neg_rights != NULL) {
+ if (str_len(str) > 0)
+ str_append_c(str, ' ');
+ str_append_c(str, '-');
+ str_append(str, t_strarray_join(rights->neg_rights, " -"));
+ }
+ return str_c(str);
+}
+
bool acl_rights_has_nonowner_lookup_changes(const struct acl_rights *rights)
{
const char *const *p;
diff -r c6082de4bf5b -r 3ba8fa6d3cc2 src/plugins/acl/acl-api.h
--- a/src/plugins/acl/acl-api.h Thu Mar 14 15:41:09 2013 +0200
+++ b/src/plugins/acl/acl-api.h Thu Mar 14 15:41:39 2013 +0200
@@ -30,6 +30,9 @@
/* Allow changing ACL state in this mailbox */
#define MAIL_ACL_ADMIN "admin"
+#define MAILBOX_ATTRIBUTE_PREFIX_ACL \
+ MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT"acl/"
+
/* ACL identifiers in override order */
enum acl_id_type {
/* Anyone's rights, including anonymous's.
@@ -138,6 +141,9 @@
const char *const **rights_r);
/* Returns the default rights for the object. */
const char *const *acl_object_get_default_rights(struct acl_object *aclobj);
+/* Returns timestamp of when the ACLs were last changed for this object,
+ or 0 = never. */
+int acl_object_last_changed(struct acl_object *aclobj, time_t *last_changed_r);
/* Update ACL of given object. */
int acl_object_update(struct acl_object *aclobj,
@@ -149,4 +155,7 @@
struct acl_rights *rights_r);
void acl_object_list_deinit(struct acl_object_list_iter **iter);
+/* Returns the canonical ID for the right. */
+const char *acl_rights_get_id(const struct acl_rights *right);
+
#endif
diff -r c6082de4bf5b -r 3ba8fa6d3cc2 src/plugins/acl/acl-attributes.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/acl/acl-attributes.c Thu Mar 14 15:41:39 2013 +0200
@@ -0,0 +1,234 @@
+/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str.h"
+#include "mail-storage-private.h"
+#include "acl-api-private.h"
+#include "acl-plugin.h"
+#include "acl-storage.h"
+
+struct acl_mailbox_attribute_iter {
+ struct mailbox_attribute_iter iter;
+ struct mailbox_attribute_iter *super;
+
+ struct acl_object_list_iter *acl_iter;
+ string_t *acl_name;
+
+ bool failed;
+};
+
+static int acl_attribute_update_acl(struct mailbox_transaction_context *t,
+ const char *key, const char *value)
+{
+ const char *id, *const *rights, *error;
+ struct acl_rights_update update;
+
+ /* for now allow only admin (=dsync) to update ACLs this way.
+ if this check is removed, it should be replaced by a setting, since
+ some admins may still have configured Dovecot using dovecot-acl
+ files directly that they don't want users to update. and in any case
+ ACL_STORAGE_RIGHT_ADMIN must be checked then. */
+ if (!t->box->storage->user->admin) {
+ mail_storage_set_error(t->box->storage, MAIL_ERROR_PERM,
+ MAIL_ERRSTR_NO_PERMISSION);
+ return -1;
+ }
+
+ memset(&update, 0, sizeof(update));
+ update.modify_mode = ACL_MODIFY_MODE_REPLACE;
+ update.neg_modify_mode = ACL_MODIFY_MODE_REPLACE;
+ id = key + strlen(MAILBOX_ATTRIBUTE_PREFIX_ACL);
+ rights = value == NULL ? NULL : t_strsplit(value, " ");
+ if (acl_rights_update_import(&update, id, rights, &error) < 0) {
+ mail_storage_set_error(t->box->storage, MAIL_ERROR_PARAMS, error);
+ return -1;
+ }
+ /* FIXME: this should actually be done only at commit().. */
+ return acl_mailbox_update_acl(t, &update);
+}
+
+static int acl_attribute_get_acl(struct mailbox *box, const char *key,
+ struct mail_attribute_value *value_r)
+{
+ struct acl_object *aclobj = acl_mailbox_get_aclobj(box);
+ struct acl_object_list_iter *iter;
+ struct acl_rights rights, wanted_rights;
+ const char *id;
+ int ret;
+
+ memset(value_r, 0, sizeof(*value_r));
+
+ if (!box->storage->user->admin) {
+ mail_storage_set_error(box->storage, MAIL_ERROR_PERM,
+ MAIL_ERRSTR_NO_PERMISSION);
+ return -1;
+ }
+ /* set last_change for all ACL objects, even if they don't exist
+ (because they could have been removed by the last change, and dsync
+ can use this information) */
+ (void)acl_object_last_changed(aclobj, &value_r->last_change);
+
+ memset(&wanted_rights, 0, sizeof(wanted_rights));
+ id = key + strlen(MAILBOX_ATTRIBUTE_PREFIX_ACL);
+ if (acl_identifier_parse(id, &wanted_rights) < 0) {
+ mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
+ t_strdup_printf("Invalid ID: %s", id));
+ return -1;
+ }
+
+ iter = acl_object_list_init(aclobj);
+ while ((ret = acl_object_list_next(iter, &rights)) > 0) {
+ if (!rights.global &&
+ rights.id_type == wanted_rights.id_type &&
+ null_strcmp(rights.identifier, wanted_rights.identifier) == 0) {
+ value_r->value = acl_rights_export(&rights);
+ break;
+ }
+ }
+ if (ret < 0)
+ mail_storage_set_internal_error(box->storage);
+ acl_object_list_deinit(&iter);
+ return ret;
+}
+
+static int acl_have_attribute_rights(struct mailbox *box)
+{
+ int ret;
+
+ /* RFC 5464:
+
+ When the ACL extension [RFC4314] is present, users can only set and
+ retrieve private or shared mailbox annotations on a mailbox on which
+ they have the "l" right and any one of the "r", "s", "w", "i", or "p"
+ rights.
+ */
+ ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_LOOKUP);
+ if (ret <= 0) {
+ if (ret < 0)
+ return -1;
+ mail_storage_set_error(box->storage, MAIL_ERROR_NOTFOUND,
More information about the dovecot-cvs
mailing list