imap-acl-plugin.c revision 23fdad6c7e2581921f511e24cd9371c9eaebcef9
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2008-2009 Dovecot authors, see the included COPYING file */
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen#define ERROR_NOT_ADMIN "["IMAP_RESP_CODE_NOPERM"] " \
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "You lack administrator privileges on this mailbox."
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen (MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic const struct imap_acl_letter_map imap_acl_letter_map[] = {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenconst char *imap_acl_plugin_version = PACKAGE_VERSION;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainenstatic void (*next_hook_client_created)(struct client **client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic struct mailbox *
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenacl_mailbox_open_as_admin(struct client_command_context *cmd, const char *name)
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen if (ACL_USER_CONTEXT(cmd->client->user) == NULL) {
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen client_send_command_error(cmd, "ACLs disabled.");
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen ns = client_find_namespace(cmd, &name, CLIENT_VERIFY_MAILBOX_NONE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* Force opening the mailbox so that we can give a nicer error message
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if mailbox isn't selectable but is listable. */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen box = mailbox_alloc(ns->list, name, NULL, ACL_MAILBOX_FLAGS |
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_ADMIN);
4376643cd2c7110e752c09f838f2c4eee6ed8ac6Timo Sirainen /* not an administrator. */
4376643cd2c7110e752c09f838f2c4eee6ed8ac6Timo Sirainen if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_LOOKUP) <= 0) {
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen client_send_tagline(cmd, "NO "ERROR_NOT_ADMIN);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic const struct imap_acl_letter_map *
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int i;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (i = 0; imap_acl_letter_map[i].name != NULL; i++) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strcmp(imap_acl_letter_map[i].name, name) == 0)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenimap_acl_write_rights_list(string_t *dest, const char *const *rights)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* write only letters */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenimap_acl_write_right(string_t *dest, string_t *tmp,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *const *rights = neg ? right->neg_rights : right->rights;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(tmp, IMAP_ACL_GROUP_OVERRIDE_PREFIX);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen imap_quote_append(dest, str_data(tmp), str_len(tmp), FALSE);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainenimap_acl_write_aclobj(string_t *dest, struct acl_backend *backend,
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen struct acl_object *aclobj, bool convert_owner,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen bool owner, seen_owner = FALSE, seen_positive_owner = FALSE;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen username = acl_backend_get_acl_username(backend);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen while ((ret = acl_object_list_next(iter, &rights)) > 0) {
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen acl_backend_user_name_equals(backend, rights.identifier))
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* oops, we have both owner and user=myself.
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen can't do the conversion, so try again. */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen imap_acl_write_right(dest, tmp, &rights, FALSE);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen imap_acl_write_right(dest, tmp, &rights, TRUE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!seen_positive_owner && username != NULL && add_default) {
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen /* no positive owner rights returned, write default ACLs */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen rights.rights = acl_object_get_default_rights(aclobj);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen imap_acl_write_right(dest, tmp, &rights, FALSE);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenstatic bool cmd_getacl(struct client_command_context *cmd)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!client_read_string_args(cmd, 1, &mailbox))
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen box = acl_mailbox_open_as_admin(cmd, mailbox);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen imap_quote_append_string(str, mailbox, FALSE);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen backend = acl_mailbox_list_get_backend(ns->list);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen client_send_tagline(cmd, "OK Getacl completed.");
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen client_send_tagline(cmd, "NO "MAIL_ERRSTR_CRITICAL_MSG);
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainenstatic bool cmd_myrights(struct client_command_context *cmd)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const char *const *rights;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (!client_read_string_args(cmd, 1, &mailbox))
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen if (ACL_USER_CONTEXT(cmd->client->user) == NULL) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen client_send_command_error(cmd, "ACLs disabled.");
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ns = client_find_namespace(cmd, &real_mailbox,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen box = mailbox_alloc(ns->list, real_mailbox, NULL,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ACL_MAILBOX_FLAGS | MAILBOX_FLAG_IGNORE_ACLS);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (acl_object_get_my_rights(acl_mailbox_get_aclobj(box),
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen client_send_tagline(cmd, "NO "MAIL_ERRSTR_CRITICAL_MSG);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* Post right alone doesn't give permissions to see if the mailbox
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen exists or not. Only mail deliveries care about that. */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen (strcmp(*rights, MAIL_ACL_POST) == 0 && rights[1] == NULL)) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen MAIL_ERRSTR_MAILBOX_NOT_FOUND, real_mailbox));
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen imap_quote_append_string(str, mailbox, FALSE);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen client_send_tagline(cmd, "OK Myrights completed.");
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic bool cmd_listrights(struct client_command_context *cmd)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (!client_read_string_args(cmd, 2, &mailbox, &identifier))
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen box = acl_mailbox_open_as_admin(cmd, mailbox);
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen imap_quote_append_string(str, mailbox, FALSE);
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen imap_quote_append_string(str, identifier, FALSE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, "\"\" l r w s t p i e k x a c d");
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen client_send_tagline(cmd, "OK Listrights completed.");
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainenimap_acl_letters_parse(const char *letters, const char *const **rights_r,
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen const char **error_r)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen static const char *acl_t = MAIL_ACL_WRITE_DELETED;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen unsigned int i;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (i = 0; imap_acl_letter_map[i].name != NULL; i++) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (imap_acl_letter_map[i].letter == *letters) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* Handling of obsolete rights as virtual
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen rights according to RFC 4314 */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenstatic bool acl_anyone_allow(struct mail_user *user)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *env;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen env = mail_user_plugin_getenv(user, "acl_anyone");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return env != NULL && strcmp(env, "allow") == 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenimap_acl_identifier_parse(struct client_command_context *cmd,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *error_r = t_strdup_printf("Global ACLs can't be modified: %s",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (check_anyone && !acl_anyone_allow(user)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *error_r = "'anyone' identifier is disallowed";
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen } else if (strcmp(id, IMAP_ACL_AUTHENTICATED) == 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (check_anyone && !acl_anyone_allow(user)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *error_r = "'authenticated' identifier is disallowed";
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen rights->identifier = id + strlen(IMAP_ACL_GROUP_PREFIX);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen } else if (strncmp(id, IMAP_ACL_GROUP_OVERRIDE_PREFIX,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen strlen(IMAP_ACL_GROUP_OVERRIDE_PREFIX)) == 0) {
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenstatic void imap_acl_update_ensure_keep_admins(struct acl_rights_update *update)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen static const char *acl_admin = MAIL_ACL_ADMIN;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *const *rights = update->rights.rights;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen unsigned int i;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* skip over the ADMIN removal and add the rest */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* add the missing ADMIN right */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen update->rights.rights = array_idx(&new_rights, 0);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic bool cmd_setacl(struct client_command_context *cmd)
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen const char *mailbox, *identifier, *rights, *error;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!client_read_string_args(cmd, 3, &mailbox, &identifier, &rights))
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen client_send_command_error(cmd, "Invalid arguments.");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (imap_acl_identifier_parse(cmd, identifier, &update.rights,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (imap_acl_letters_parse(rights, &update.rights.rights, &error) < 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen box = acl_mailbox_open_as_admin(cmd, mailbox);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen backend = acl_mailbox_list_get_backend(ns->list);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ns->type == NAMESPACE_PUBLIC && r->id_type == ACL_ID_OWNER) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_send_tagline(cmd, "NO Public namespaces have no owner");
return TRUE;
if (negative) {
return TRUE;
return FALSE;
return TRUE;
identifier++;
return TRUE;
return TRUE;
return TRUE;
void imap_acl_plugin_init(void)
void imap_acl_plugin_deinit(void)