From: Timo Sirainen Date: Wed, 24 Jul 2019 11:42:21 +0000 (+0300) Subject: lib-storage: Add support for "validated attributes" X-Git-Tag: 2.3.9~347 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c46ae2baa354c41b7615456b751f74acf015f82c;p=thirdparty%2Fdovecot%2Fcore.git lib-storage: Add support for "validated attributes" If an attribute is marked with MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED, it's assumed to be "validated". This means that it has a set() callback that validates the value, which at minimum means that its size isn't excessively large. MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED can be used with set/get/iterate to allow access only to these validated attributes. Trying to access non-validated attributes will result in error. --- diff --git a/src/lib-storage/index/index-attribute.c b/src/lib-storage/index/index-attribute.c index aed651f04e..15feb5503e 100644 --- a/src/lib-storage/index/index-attribute.c +++ b/src/lib-storage/index/index-attribute.c @@ -88,6 +88,14 @@ index_storage_get_dict(struct mailbox *box, enum mail_attribute_type type_flags, struct dict_settings set; const char *error; + if ((type_flags & MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED) != 0) { + /* IMAP METADATA support isn't enabled, so don't allow using + mail_attribute_dict. */ + mail_storage_set_error(storage, MAIL_ERROR_NOTPOSSIBLE, + "Generic mailbox attributes not enabled"); + return -1; + } + if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) return -1; *mailbox_prefix_r = guid_128_to_string(metadata.guid); @@ -177,8 +185,11 @@ index_storage_attribute_get_dict_trans(struct mailbox_transaction_context *t, } i_assert(dtransp != NULL); - if (*dtransp != NULL) { - /* transaction already created */ + if (*dtransp != NULL && + (type_flags & MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED) == 0) { + /* Transaction already created. Even if it was, don't use it + if _FLAG_VALIDATED is being used. It'll be handled below by + returning failure. */ if (mailbox_get_metadata(t->box, MAILBOX_METADATA_GUID, &metadata) < 0) return -1; @@ -189,6 +200,7 @@ index_storage_attribute_get_dict_trans(struct mailbox_transaction_context *t, if (index_storage_get_dict(t->box, type_flags, &dict, mailbox_prefix_r) < 0) return -1; + i_assert(*dtransp == NULL); *dtransp = *dtrans_r = dict_transaction_begin(dict); return 0; } diff --git a/src/lib-storage/mailbox-attribute.c b/src/lib-storage/mailbox-attribute.c index 51455b8851..bb52376cf5 100644 --- a/src/lib-storage/mailbox-attribute.c +++ b/src/lib-storage/mailbox-attribute.c @@ -47,6 +47,13 @@ void mailbox_attribute_register_internal( struct mailbox_attribute_internal ireg; unsigned int insert_idx; + /* Validated attributes must have a set() callback that validates the + provided values. Also read-only _RANK_AUTHORITY attributes don't + need validation. */ + i_assert((iattr->flags & MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED) == 0 || + iattr->set != NULL || + iattr->rank == MAIL_ATTRIBUTE_INTERNAL_RANK_AUTHORITY); + (void)array_bsearch_insert_pos(&mailbox_internal_attributes, iattr, mailbox_attribute_internal_cmp, &insert_idx); @@ -88,8 +95,8 @@ void mailbox_attribute_unregister_internals( } static const struct mailbox_attribute_internal * -mailbox_internal_attribute_get(enum mail_attribute_type type_flags, - const char *key) +mailbox_internal_attribute_get_int(enum mail_attribute_type type_flags, + const char *key) { const struct mailbox_attribute_internal *iattr; struct mailbox_attribute_internal dreg; @@ -121,6 +128,22 @@ mailbox_internal_attribute_get(enum mail_attribute_type type_flags, } } +static const struct mailbox_attribute_internal * +mailbox_internal_attribute_get(enum mail_attribute_type type_flags, + const char *key) +{ + const struct mailbox_attribute_internal *iattr; + + iattr = mailbox_internal_attribute_get_int(type_flags, key); + if ((type_flags & MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED) != 0 && + iattr != NULL && + (iattr->flags & MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED) == 0) { + /* only validated attributes can be accessed */ + iattr = NULL; + } + return iattr; +} + static void mailbox_internal_attributes_get(enum mail_attribute_type type_flags, const char *prefix, bool have_dict, ARRAY_TYPE(const_string) *attrs) @@ -151,6 +174,10 @@ mailbox_internal_attributes_get(enum mail_attribute_type type_flags, if (regs[i].type != dreg.type) return; + if ((type_flags & MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED) != 0 && + (regs[i].flags & MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED) == 0) + continue; + if (plen > 0) { if (strncmp(key, bare_prefix, plen) != 0) return; @@ -214,6 +241,8 @@ mailbox_attribute_set_common(struct mailbox_transaction_context *t, default: i_unreached(); } + /* the value was validated. */ + type_flags &= ~MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED; } ret = t->box->v.attribute_set(t, type_flags, key, value); @@ -290,6 +319,12 @@ mailbox_attribute_get_common(struct mailbox *box, if (iattr != NULL) { switch (iattr->rank) { case MAIL_ATTRIBUTE_INTERNAL_RANK_OVERRIDE: + /* we already checked that this attribute has + validated-flag */ + type_flags &= ~MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED; + + if (iattr->get == NULL) + break; if ((ret = iattr->get(box, key, value_r)) != 0) { if (ret < 0) return -1; diff --git a/src/lib-storage/mailbox-attribute.h b/src/lib-storage/mailbox-attribute.h index 76428dd185..093158a7f9 100644 --- a/src/lib-storage/mailbox-attribute.h +++ b/src/lib-storage/mailbox-attribute.h @@ -183,6 +183,9 @@ enum mail_attribute_type { MAIL_ATTRIBUTE_TYPE_SHARED }; #define MAIL_ATTRIBUTE_TYPE_MASK 0x0f +/* Allow accessing only attributes with + MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED. */ +#define MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED 0x80 enum mail_attribute_value_flags { MAIL_ATTRIBUTE_VALUE_FLAG_READONLY = 0x01, @@ -234,7 +237,11 @@ enum mail_attribute_internal_rank { enum mail_attribute_internal_flags { /* Apply this attribute to the given key and its children. */ - MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN = 0x01 + MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN = 0x01, + /* This attribute can be set/get even without generic METADATA support. + These attributes don't count towards any quotas either, so the set() + callback should validate that the value isn't excessively large. */ + MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED = 0x02, }; struct mailbox_attribute_internal {