1 #ifndef MAILBOX_ATTRIBUTE_H 2 #define MAILBOX_ATTRIBUTE_H 3 4 /* 5 * Attribute Handling in Dovecot 6 * ============================= 7 * 8 * What IMAP & doveadm users see gets translated into one of several things 9 * depending on if we're operating on a mailbox or on server metadata ("" 10 * mailbox in IMAP parlance). Consider these examples: 11 * 12 * /private/foo 13 * /shared/foo 14 * 15 * Here "foo" can be any RFC defined attribute name, or a vendor-prefixed 16 * non-standard name. (Our vendor prefix is "vendor/vendor.dovecot".) 17 * 18 * In all cases, the "/private" and "/shared" user visible prefixes get 19 * replaced by priv/<GUID> and shared/<GUID>, respectively. (Here, <GUID> 20 * is the GUID of the mailbox with which the attribute is associated.) This 21 * way, attributes for all mailboxes can be stored in a single dict. For 22 * example, the above examples would map to: 23 * 24 * priv/<GUID>/foo 25 * shared/<GUID>/foo 26 * 27 * More concrete examples: 28 * 29 * /private/comment 30 * /private/vendor/vendor.dovecot/abc 31 * 32 * turn into: 33 * 34 * priv/<GUID>/comment 35 * priv/<GUID>/vendor/vendor.dovecot/abc 36 * 37 * Server attributes, that is attributes not associated with a mailbox, are 38 * stored in the INBOX mailbox with a special prefix - 39 * vendor/vendor.dovecot/pvt/server. For example, the server attribute 40 * /private/comment gets mapped to: 41 * 42 * priv/<INBOX GUID>/vendor/vendor.dovecot/pvt/server/comment 43 * 44 * This means that if we set a /private/comment server attribute as well as 45 * /private/comment INBOX mailbox attribute, we'll see the following paths 46 * used in the dict: 47 * 48 * priv/<INBOX GUID>/comment <- mailbox attr 49 * priv/<INBOX GUID>/vendor/vendor.dovecot/pvt/server/comment <- server attr 50 * 51 * The case of vendor specific server attributes is a bit confusing, but 52 * consistent. For example, this server attribute: 53 * 54 * /private/vendor/vendor.dovecot/abc 55 * 56 * It will get mapped to: 57 * 58 * priv/<INBOX GUID>/vendor/vendor.dovecot/pvt/server/vendor/vendor.dovecot/abc 59 * | | | | 60 * \----- server attr prefix -----/ \-- server attr name ---/ 61 * 62 * 63 * Internal Attributes 64 * ------------------- 65 * 66 * The final aspect of attribute handling in Dovecot are the so called 67 * "internal attributes". 68 * 69 * The easiest way to explain internal attributes is to summarize attributes 70 * in general. Attributes are just <key,value> pairs that are stored in a 71 * dict. The key is mangled according to the above rules before passed to 72 * the dict code. That is, the key already encodes whether the attribute is 73 * private or shared, the GUID of the mailbox (or of INBOX for server 74 * attributes), etc. There is no processing of the value. It is stored and 75 * returned to clients verbatim. 76 * 77 * Internal attributes, on the other hand, are special cased attributes. 78 * That is, the code contains a list of specific attribute names and how to 79 * handle them. Each internal attribute is defined by a struct 80 * mailbox_attribute_internal. It contains the pre-parsed name of the 81 * attribute (type, key, and flags), and how to handle getting and setting 82 * of the attribute (rank, get, and set). 83 * 84 * The values for these attributes may come from two places - from the 85 * attributes dict, or from the get function pointer. Which source to use 86 * is identified by the rank (MAIL_ATTRIBUTE_INTERNAL_RANK_*). 87 * 88 * 89 * Access 90 * ------ 91 * 92 * In general, a user (IMAP or doveadm) can access all attributes for a 93 * mailbox. The one exception are attributes under: 94 * 95 * /private/vendor/vendor.dovecot/pvt 96 * /shared/vendor/vendor.dovecot/pvt 97 * 98 * Which as you may recall map to: 99 * 100 * priv/<GUID>/vendor/vendor.dovecot/pvt 101 * shared/<GUID>/vendor/vendor.dovecot/pvt 102 * 103 * These are deemed internal to Dovecot, and therefore of no concern to the 104 * user. 105 * 106 * Server attributes have a similar restriction. That is, attributes 107 * beginning with the following are not accessible: 108 * 109 * /private/vendor/vendor.dovecot/pvt 110 * /shared/vendor/vendor.dovecot/pvt 111 * 112 * However since server attributes are stored under the INBOX mailbox, these 113 * paths map to: 114 * 115 * priv/<INBOX GUID>/vendor/vendor.dovecot/pvt/server/vendor/vendor.dovecot/pvt 116 * shared/<INBOX GUID>/vendor/vendor.dovecot/pvt/server/vendor/vendor.dovecot/pvt 117 * 118 * As a result, the code performs access checks via the 119 * MAILBOX_ATTRIBUTE_KEY_IS_USER_ACCESSIBLE() macro to make sure that the 120 * user is allowed access to the attribute. 121 * 122 * 123 * Nicknames 124 * --------- 125 * 126 * Since every path stored in the dict begins with priv/<GUID> or 127 * shared/<GUID>, these prefixes are often omitted. This also matches the 128 * internal implementation where the priv/ or shared/ prefix is specified 129 * using an enum, and only the path after the GUID is handled as a string. 130 * For example: 131 * 132 * priv/<GUID>/vendor/vendor.dovecot/pvt/server/foo 133 * 134 * would be referred to as: 135 * 136 * vendor/vendor.dovecot/pvt/server/foo 137 * 138 * Since some of the generated paths are very long, developers often use a 139 * shorthand to refer to some of these paths. For example, 140 * 141 * pvt/server/pvt 142 * 143 * is really: 144 * 145 * vendor/vendor.dovecot/pvt/server/vendor/vendor.dovecot/pvt 146 * 147 * Which when fully specified with a type and INBOX's GUID would turn into 148 * one of the following: 149 * 150 * priv/<GUID>/vendor/vendor.dovecot/pvt/server/vendor/vendor.dovecot/pvt 151 * shared/<GUID>/vendor/vendor.dovecot/pvt/server/vendor/vendor.dovecot/pvt 152 */ 153 154 struct mailbox; 155 struct mailbox_transaction_context; 156 157 /* RFC 5464 specifies that this is vendor/<vendor-token>/. The registered 158 vendor-tokens always begin with "vendor." so there's some redundancy.. */ 159 #define MAILBOX_ATTRIBUTE_PREFIX_DOVECOT "vendor/vendor.dovecot/" 160 /* Prefix used for attributes reserved for Dovecot's internal use. Normal 161 users cannot access these in any way. */ 162 #define MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT \ 163 MAILBOX_ATTRIBUTE_PREFIX_DOVECOT"pvt/" 164 /* Server attributes are currently stored in INBOX under this private prefix. 165 They're under the pvt/ prefix so they won't be listed as regular INBOX 166 attributes, but unlike other pvt/ attributes it's actually possible to 167 access these attributes as regular users. 168 169 If INBOX is deleted, attributes under this prefix are preserved. */ 170 #define MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER \ 171 MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT"server/" 172 173 /* User can get/set all non-pvt/ attributes and also pvt/server/ 174 (but not pvt/server/pvt/) attributes. */ 175 #define MAILBOX_ATTRIBUTE_KEY_IS_USER_ACCESSIBLE(key) \ 176 (!str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT) || \ 177 (str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER) && \ 178 strncmp(key, MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT, \ 179 strlen(MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT)) != 0)) 180 181 enum mail_attribute_type { 182 MAIL_ATTRIBUTE_TYPE_PRIVATE, 183 MAIL_ATTRIBUTE_TYPE_SHARED 184 }; 185 #define MAIL_ATTRIBUTE_TYPE_MASK 0x0f 186 /* Allow accessing only attributes with 187 MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED. */ 188 #define MAIL_ATTRIBUTE_TYPE_FLAG_VALIDATED 0x80 189 190 enum mail_attribute_value_flags { 191 MAIL_ATTRIBUTE_VALUE_FLAG_READONLY = 0x01, 192 MAIL_ATTRIBUTE_VALUE_FLAG_INT_STREAMS = 0x02 193 }; 194 195 struct mail_attribute_value { 196 /* mailbox_attribute_set() can set either value or value_stream. 197 mailbox_attribute_get() returns only values, but 198 mailbox_attribute_get_stream() may return either value or 199 value_stream. The caller must unreference the returned streams. */ 200 const char *value; 201 struct istream *value_stream; 202 203 /* Last time the attribute was changed (0 = unknown). This may be 204 returned even for values that don't exist anymore. */ 205 time_t last_change; 206 207 enum mail_attribute_value_flags flags; 208 }; 209 210 /* 211 * Internal attribute 212 */ 213 214 enum mail_attribute_internal_rank { 215 /* The internal attribute serves only as a source for a default value 216 when the normal mailbox attribute storage has no entry for this 217 attribute. Otherwise it is ignored. The `set' function is called 218 only as a notification, not with the intention to store the value. 219 The value is always assigned to the normal mailbox attribute storage. 220 */ 221 MAIL_ATTRIBUTE_INTERNAL_RANK_DEFAULT = 0, 222 /* The internal attribute serves as the main source of the attribute 223 value. If the `get' function returns 0, the normal mailbox attribute 224 storage is attempted to obtain the value. The `set' function is 225 called only as a notification, not with the intention to store the 226 value. The value is assigned to the normal mailbox attribute storage. 227 */ 228 MAIL_ATTRIBUTE_INTERNAL_RANK_OVERRIDE, 229 /* The value for the internal attribute is never read from the normal 230 mailbox attribute storage. If the `set' function is NULL, the 231 attribute is read-only. If it is not NULL it is used to assign the 232 attribute value; it is not assigned to the normal mailbox attribute 233 storage. 234 */ 235 MAIL_ATTRIBUTE_INTERNAL_RANK_AUTHORITY 236 }; 237 238 enum mail_attribute_internal_flags { 239 /* Apply this attribute to the given key and its children. */ 240 MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN = 0x01, 241 /* This attribute can be set/get even without generic METADATA support. 242 These attributes don't count towards any quotas either, so the set() 243 callback should validate that the value isn't excessively large. */ 244 MAIL_ATTRIBUTE_INTERNAL_FLAG_VALIDATED = 0x02, 245 }; 246 247 struct mailbox_attribute_internal { 248 enum mail_attribute_type type; 249 const char *key; /* relative to the GUID, e.g., "comment" */ 250 enum mail_attribute_internal_rank rank; 251 enum mail_attribute_internal_flags flags; 252 253 /* Get the value of this internal attribute */ 254 int (*get)(struct mailbox *box, const char *key, 255 struct mail_attribute_value *value_r); 256 /* Set the value of this internal attribute */ 257 int (*set)(struct mailbox_transaction_context *t, const char *key, 258 const struct mail_attribute_value *value); 259 /* If non-NULL, the function is responsible for iterating the 260 attribute. Typically this would be used for attributes with 261 MAIL_ATTRIBUTE_INTERNAL_FLAG_CHILDREN to get the children 262 iterated. If key_prefix is "", all keys should be returned. 263 Otherwise only the keys beginning with key_prefix should be 264 returned. The key_prefix is already relative to the 265 mailbox_attribute_internal.key. */ 266 int (*iter)(struct mailbox *box, const char *key_prefix, 267 pool_t pool, ARRAY_TYPE(const_string) *keys); 268 }; 269 270 void mailbox_attribute_register_internal( 271 const struct mailbox_attribute_internal *iattr); 272 void mailbox_attribute_register_internals( 273 const struct mailbox_attribute_internal *iattrs, unsigned int count); 274 275 void mailbox_attribute_unregister_internal( 276 const struct mailbox_attribute_internal *iattr); 277 void mailbox_attribute_unregister_internals( 278 const struct mailbox_attribute_internal *iattrs, unsigned int count); 279 280 /* 281 * Attribute API 282 */ 283 284 /* Set mailbox attribute key to value. The key should be compatible with 285 IMAP METADATA, so for Dovecot-specific keys use 286 MAILBOX_ATTRIBUTE_PREFIX_DOVECOT. */ 287 int mailbox_attribute_set(struct mailbox_transaction_context *t, 288 enum mail_attribute_type type_flags, const char *key, 289 const struct mail_attribute_value *value); 290 /* Delete mailbox attribute key. This is just a wrapper to 291 mailbox_attribute_set() with value->value=NULL. */ 292 int mailbox_attribute_unset(struct mailbox_transaction_context *t, 293 enum mail_attribute_type type_flags, const char *key); 294 /* Returns value for mailbox attribute key. Returns 1 if value was returned, 295 0 if value wasn't found (set to NULL), -1 if error */ 296 int mailbox_attribute_get(struct mailbox *box, 297 enum mail_attribute_type type_flags, const char *key, 298 struct mail_attribute_value *value_r); 299 /* Same as mailbox_attribute_get(), but the returned value may be either an 300 input stream or a string. */ 301 int mailbox_attribute_get_stream(struct mailbox *box, 302 enum mail_attribute_type type_flags, 303 const char *key, 304 struct mail_attribute_value *value_r); 305 306 /* Iterate through mailbox attributes of the given type. The prefix can be used 307 to restrict what attributes are returned. */ 308 struct mailbox_attribute_iter * 309 mailbox_attribute_iter_init(struct mailbox *box, 310 enum mail_attribute_type type_flags, 311 const char *prefix); 312 /* Returns the attribute key or NULL if there are no more attributes. */ 313 const char *mailbox_attribute_iter_next(struct mailbox_attribute_iter *iter); 314 int mailbox_attribute_iter_deinit(struct mailbox_attribute_iter **iter); 315 316 #endif 317