imap-acl-plugin.c revision e5b723864630e40c9028808ef417dd3d6fbf495b
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2008-2009 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "common.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "str.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "imap-quote.h"
9c6a09aa16095ff72837799a37e0e3b3e93bb3d8Timo Sirainen#include "imap-resp-code.h"
31a9637b38d37451b649c86301b2c12e53a7810eTimo Sirainen#include "commands.h"
9c6a09aa16095ff72837799a37e0e3b3e93bb3d8Timo Sirainen#include "mail-storage.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "mail-namespace.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "acl-api.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "acl-storage.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "imap-acl-plugin.h"
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen#include <stdlib.h>
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen#define ERROR_NOT_ADMIN "["IMAP_RESP_CODE_NOPERM"] " \
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen "You lack administrator privileges on this mailbox."
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen#define ACL_MAILBOX_OPEN_FLAGS \
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen (MAILBOX_OPEN_READONLY | MAILBOX_OPEN_FAST | MAILBOX_OPEN_KEEP_RECENT)
1f9d1bedae25d86f26c239055c5487499dfeeb58Timo Sirainen
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen#define IMAP_ACL_ANYONE "anyone"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#define IMAP_ACL_AUTHENTICATED "authenticated"
f37ecd72aad9b806aae83f71bacafdce32146945Timo Sirainen#define IMAP_ACL_OWNER "owner"
f37ecd72aad9b806aae83f71bacafdce32146945Timo Sirainen#define IMAP_ACL_GROUP_PREFIX "$"
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen#define IMAP_ACL_GROUP_OVERRIDE_PREFIX "!$"
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen#define IMAP_ACL_GLOBAL_PREFIX "#"
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainenstruct imap_acl_letter_map {
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen char letter;
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen const char *name;
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen};
8b5c520883aa37bb55646286d375fdbae294d710Timo Sirainen
8b5c520883aa37bb55646286d375fdbae294d710Timo Sirainenstatic const struct imap_acl_letter_map imap_acl_letter_map[] = {
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen { 'l', MAIL_ACL_LOOKUP },
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen { 'r', MAIL_ACL_READ },
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen { 'w', MAIL_ACL_WRITE },
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen { 's', MAIL_ACL_WRITE_SEEN },
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen { 't', MAIL_ACL_WRITE_DELETED },
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen { 'i', MAIL_ACL_INSERT },
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen { 'p', MAIL_ACL_POST },
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen { 'e', MAIL_ACL_EXPUNGE },
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen { 'k', MAIL_ACL_CREATE },
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen { 'x', MAIL_ACL_DELETE },
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen { 'a', MAIL_ACL_ADMIN },
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen { '\0', NULL }
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen};
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenconst char *imap_acl_plugin_version = PACKAGE_VERSION;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainenstatic bool acl_anyone_allow = FALSE;
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch
009217abb57a24a4076092e8e4e165545747839eStephan Boschstatic struct mailbox *
72f21884c0bb9bb26edad63623427ac2120901eaStephan Boschacl_mailbox_open_as_admin(struct client_command_context *cmd, const char *name)
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen{
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch struct mail_storage *storage;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch struct mailbox *box;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen int ret;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen storage = client_find_storage(cmd, &name);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (storage == NULL)
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen return NULL;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen /* Force opening the mailbox so that we can give a nicer error message
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen if mailbox isn't selectable but is listable. */
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen box = mailbox_open(&storage, name, NULL, ACL_MAILBOX_OPEN_FLAGS |
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen MAILBOX_OPEN_IGNORE_ACLS);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen if (box == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_send_storage_error(cmd, storage);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_ADMIN);
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen if (ret > 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return box;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* not an administrator. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_LOOKUP) <= 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_tagline(cmd, t_strdup_printf(
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "NO ["IMAP_RESP_CODE_NONEXISTENT"] "
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen MAIL_ERRSTR_MAILBOX_NOT_FOUND, name));
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen } else {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen client_send_tagline(cmd, "NO "ERROR_NOT_ADMIN);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen }
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen mailbox_close(&box);
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen return NULL;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic const struct imap_acl_letter_map *
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenimap_acl_letter_map_find(const char *name)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen unsigned int i;
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen for (i = 0; imap_acl_letter_map[i].name != NULL; i++) {
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen if (strcmp(imap_acl_letter_map[i].name, name) == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return &imap_acl_letter_map[i];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen return NULL;
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen}
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenimap_acl_write_rights_list(string_t *dest, const char *const *rights)
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen{
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen const struct imap_acl_letter_map *map;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i;
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen bool append_c = FALSE, append_d = FALSE;
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen for (i = 0; rights[i] != NULL; i++) {
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen /* write only letters */
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen map = imap_acl_letter_map_find(rights[i]);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (map != NULL) {
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen str_append_c(dest, map->letter);
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen if (map->letter == 'k' || map->letter == 'x')
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen append_c = TRUE;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen if (map->letter == 't' || map->letter == 'e')
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen append_d = TRUE;
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen }
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen }
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen if (append_c)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen str_append_c(dest, 'c');
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (append_d)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen str_append_c(dest, 'd');
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen}
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainenstatic void
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenimap_acl_write_right(string_t *dest, string_t *tmp,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct acl_rights *right, bool neg)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *const *rights = neg ? right->neg_rights : right->rights;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen str_truncate(tmp, 0);
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen if (neg) str_append_c(tmp,'-');
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen if (right->global)
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen str_append(tmp, IMAP_ACL_GLOBAL_PREFIX);
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen switch (right->id_type) {
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen case ACL_ID_ANYONE:
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen str_append(tmp, IMAP_ACL_ANYONE);
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen break;
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen case ACL_ID_AUTHENTICATED:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(tmp, IMAP_ACL_AUTHENTICATED);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case ACL_ID_OWNER:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(tmp, IMAP_ACL_OWNER);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case ACL_ID_USER:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(tmp, right->identifier);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case ACL_ID_GROUP:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen str_append(tmp, IMAP_ACL_GROUP_PREFIX);
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen str_append(tmp, right->identifier);
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen break;
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen case ACL_ID_GROUP_OVERRIDE:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_append(tmp, IMAP_ACL_GROUP_OVERRIDE_PREFIX);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_append(tmp, right->identifier);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case ACL_ID_TYPE_COUNT:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_unreached();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen imap_quote_append(dest, str_data(tmp), str_len(tmp), FALSE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_append_c(dest, ' ');
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen imap_acl_write_rights_list(dest, rights);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic int imap_acl_write_aclobj(string_t *dest, struct acl_object *aclobj)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct acl_object_list_iter *iter;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen struct acl_rights rights;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen string_t *tmp;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen int ret;
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen tmp = t_str_new(128);
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen iter = acl_object_list_init(aclobj);
03baa1c4c51f7b08fb285e82b528fcb00ac09ebfTimo Sirainen while ((ret = acl_object_list_next(iter, &rights)) > 0) {
03baa1c4c51f7b08fb285e82b528fcb00ac09ebfTimo Sirainen if (rights.rights != NULL) {
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen str_append_c(dest, ' ');
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen imap_acl_write_right(dest, tmp, &rights, FALSE);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (rights.neg_rights != NULL) {
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen str_append_c(dest, ' ');
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen imap_acl_write_right(dest, tmp, &rights, TRUE);
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen }
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen }
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen acl_object_list_deinit(&iter);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool cmd_getacl(struct client_command_context *cmd)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mailbox *box;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen const char *mailbox;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen string_t *str;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen unsigned int len;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen int ret;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen if (!client_read_string_args(cmd, 1, &mailbox)) {
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen client_send_command_error(cmd, "Invalid arguments.");
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen return TRUE;
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen }
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen box = acl_mailbox_open_as_admin(cmd, mailbox);
if (box == NULL)
return TRUE;
str = t_str_new(128);
str_append(str, "* ACL ");
imap_quote_append_string(str, mailbox, FALSE);
len = str_len(str);
ret = imap_acl_write_aclobj(str, acl_mailbox_get_aclobj(box));
if (ret == 0) {
client_send_line(cmd->client, str_c(str));
client_send_tagline(cmd, "OK Getacl completed.");
} else {
client_send_tagline(cmd, "NO "MAIL_ERRSTR_CRITICAL_MSG);
}
mailbox_close(&box);
return TRUE;
}
static bool cmd_myrights(struct client_command_context *cmd)
{
struct mail_storage *storage;
struct mailbox *box;
const char *mailbox, *real_mailbox;
const char *const *rights;
string_t *str;
if (!client_read_string_args(cmd, 1, &mailbox)) {
client_send_command_error(cmd, "Invalid arguments.");
return TRUE;
}
real_mailbox = mailbox;
storage = client_find_storage(cmd, &real_mailbox);
if (storage == NULL)
return TRUE;
box = mailbox_open(&storage, real_mailbox, NULL,
ACL_MAILBOX_OPEN_FLAGS | MAILBOX_OPEN_IGNORE_ACLS);
if (box == NULL) {
client_send_storage_error(cmd, storage);
return TRUE;
}
if (acl_object_get_my_rights(acl_mailbox_get_aclobj(box),
pool_datastack_create(), &rights) < 0) {
client_send_tagline(cmd, "NO "MAIL_ERRSTR_CRITICAL_MSG);
mailbox_close(&box);
return TRUE;
}
/* Post right alone doesn't give permissions to see if the mailbox
exists or not. Only mail deliveries care about that. */
if (*rights == NULL ||
(strcmp(*rights, MAIL_ACL_POST) == 0 && rights[1] == NULL)) {
client_send_tagline(cmd, t_strdup_printf(
"NO ["IMAP_RESP_CODE_NONEXISTENT"] "
MAIL_ERRSTR_MAILBOX_NOT_FOUND, real_mailbox));
mailbox_close(&box);
return TRUE;
}
str = t_str_new(128);
str_append(str, "* MYRIGHTS ");
imap_quote_append_string(str, mailbox, FALSE);
str_append_c(str,' ');
imap_acl_write_rights_list(str, rights);
client_send_line(cmd->client, str_c(str));
client_send_tagline(cmd, "OK Myrights completed.");
mailbox_close(&box);
return TRUE;
}
static bool cmd_listrights(struct client_command_context *cmd)
{
struct mailbox *box;
const char *mailbox, *identifier;
string_t *str;
if (!client_read_string_args(cmd, 2, &mailbox, &identifier)) {
client_send_command_error(cmd, "Invalid arguments.");
return TRUE;
}
box = acl_mailbox_open_as_admin(cmd, mailbox);
if (box == NULL)
return TRUE;
str = t_str_new(128);
str_append(str, "* LISTRIGHTS ");
imap_quote_append_string(str, mailbox, FALSE);
str_append_c(str, ' ');
imap_quote_append_string(str, identifier, FALSE);
str_append_c(str, ' ');
str_append(str, "\"\" l r w s t p i e k x a c d");
client_send_line(cmd->client, str_c(str));
client_send_tagline(cmd, "OK Listrights completed.");
mailbox_close(&box);
return TRUE;
}
static int
imap_acl_letters_parse(const char *letters, const char *const **rights_r,
const char **error_r)
{
static const char *acl_k = MAIL_ACL_CREATE;
static const char *acl_x = MAIL_ACL_DELETE;
static const char *acl_e = MAIL_ACL_EXPUNGE;
static const char *acl_t = MAIL_ACL_WRITE_DELETED;
ARRAY_TYPE(const_string) rights;
unsigned int i;
t_array_init(&rights, 64);
for (; *letters != '\0'; letters++) {
for (i = 0; imap_acl_letter_map[i].name != NULL; i++) {
if (imap_acl_letter_map[i].letter == *letters) {
array_append(&rights,
&imap_acl_letter_map[i].name, 1);
break;
}
}
if (imap_acl_letter_map[i].name == NULL) {
/* Handling of obsolete rights as virtual
rights according to RFC 4314 */
switch (*letters) {
case 'c':
array_append(&rights, &acl_k, 1);
array_append(&rights, &acl_x, 1);
break;
case 'd':
array_append(&rights, &acl_e, 1);
array_append(&rights, &acl_t, 1);
break;
default:
*error_r = t_strdup_printf(
"Invalid ACL right: %c", *letters);
return -1;
}
}
}
(void)array_append_space(&rights);
*rights_r = array_idx(&rights, 0);
return 0;
}
static int
imap_acl_identifier_parse(const char *id, struct acl_rights *rights,
bool check_anyone, const char **error_r)
{
if (strncmp(id, IMAP_ACL_GLOBAL_PREFIX,
strlen(IMAP_ACL_GLOBAL_PREFIX)) == 0) {
*error_r = t_strdup_printf("Global ACLs can't be modified: %s",
id);
return -1;
}
if (strcmp(id, IMAP_ACL_ANYONE) == 0) {
if (!acl_anyone_allow && check_anyone) {
*error_r = "'anyone' identifier is disallowed";
return -1;
}
rights->id_type = ACL_ID_ANYONE;
} else if (strcmp(id, IMAP_ACL_AUTHENTICATED) == 0) {
if (!acl_anyone_allow && check_anyone) {
*error_r = "'authenticated' identifier is disallowed";
return -1;
}
rights->id_type = ACL_ID_AUTHENTICATED;
} else if (strcmp(id, IMAP_ACL_OWNER) == 0)
rights->id_type = ACL_ID_OWNER;
else if (strncmp(id, IMAP_ACL_GROUP_PREFIX,
strlen(IMAP_ACL_GROUP_PREFIX)) == 0) {
rights->id_type = ACL_ID_GROUP;
rights->identifier = id + strlen(IMAP_ACL_GROUP_PREFIX);
} else if (strncmp(id, IMAP_ACL_GROUP_OVERRIDE_PREFIX,
strlen(IMAP_ACL_GROUP_OVERRIDE_PREFIX)) == 0) {
rights->id_type = ACL_ID_GROUP_OVERRIDE;
rights->identifier = id +
strlen(IMAP_ACL_GROUP_OVERRIDE_PREFIX);
} else {
rights->id_type = ACL_ID_USER;
rights->identifier = id;
}
return 0;
}
static bool cmd_setacl(struct client_command_context *cmd)
{
struct mailbox *box;
struct acl_rights_update update;
const char *mailbox, *identifier, *rights, *error;
bool negative = FALSE;
if (!client_read_string_args(cmd, 3, &mailbox, &identifier, &rights) ||
*identifier == '\0') {
client_send_command_error(cmd, "Invalid arguments.");
return TRUE;
}
memset(&update, 0, sizeof(update));
if (*identifier == '-') {
negative = TRUE;
identifier++;
}
switch (*rights) {
case '-':
update.modify_mode = ACL_MODIFY_MODE_REMOVE;
rights++;
break;
case '+':
update.modify_mode = ACL_MODIFY_MODE_ADD;
rights++;
break;
default:
update.modify_mode = ACL_MODIFY_MODE_REPLACE;
break;
}
if (imap_acl_identifier_parse(identifier, &update.rights,
TRUE, &error) < 0) {
client_send_command_error(cmd, error);
return TRUE;
}
if (imap_acl_letters_parse(rights, &update.rights.rights, &error) < 0) {
client_send_command_error(cmd, error);
return TRUE;
}
box = acl_mailbox_open_as_admin(cmd, mailbox);
if (box == NULL)
return TRUE;
if (update.rights.rights[0] == NULL) {
if (negative) {
update.modify_mode = 0;
update.rights.rights = NULL;
update.neg_modify_mode = ACL_MODIFY_MODE_CLEAR;
update.rights.neg_rights = NULL;
} else {
update.modify_mode = ACL_MODIFY_MODE_CLEAR;
update.rights.rights = NULL;
update.neg_modify_mode = 0;
update.rights.neg_rights = NULL;
}
} else if (negative) {
update.neg_modify_mode = update.modify_mode;
update.modify_mode = ACL_MODIFY_MODE_REMOVE;
update.rights.neg_rights = update.rights.rights;
update.rights.rights = NULL;
}
if (acl_object_update(acl_mailbox_get_aclobj(box), &update) < 0)
client_send_tagline(cmd, "NO "MAIL_ERRSTR_CRITICAL_MSG);
else
client_send_tagline(cmd, "OK Setacl complete.");
mailbox_close(&box);
return TRUE;
}
static bool cmd_deleteacl(struct client_command_context *cmd)
{
struct mailbox *box;
struct acl_rights_update update;
const char *mailbox, *identifier, *error;
if (!client_read_string_args(cmd, 2, &mailbox, &identifier) ||
*identifier == '\0') {
client_send_command_error(cmd, "Invalid arguments.");
return TRUE;
}
memset(&update, 0, sizeof(update));
if (*identifier != '-')
update.modify_mode = ACL_MODIFY_MODE_CLEAR;
else {
update.neg_modify_mode = ACL_MODIFY_MODE_CLEAR;
identifier++;
}
if (imap_acl_identifier_parse(identifier, &update.rights,
FALSE, &error) < 0) {
client_send_command_error(cmd, error);
return TRUE;
}
box = acl_mailbox_open_as_admin(cmd, mailbox);
if (box == NULL)
return TRUE;
if (acl_object_update(acl_mailbox_get_aclobj(box), &update) < 0)
client_send_tagline(cmd, "NO "MAIL_ERRSTR_CRITICAL_MSG);
else
client_send_tagline(cmd, "OK Deleteacl complete.");
mailbox_close(&box);
return TRUE;
}
void imap_acl_plugin_init(void)
{
const char *env;
if (getenv("ACL") == NULL)
return;
env = getenv("ACL_ANYONE");
if (env != NULL)
acl_anyone_allow = strcmp(env, "allow") == 0;
str_append(capability_string, " ACL RIGHTS=texk");
command_register("LISTRIGHTS", cmd_listrights, 0);
command_register("GETACL", cmd_getacl, 0);
command_register("MYRIGHTS", cmd_myrights, 0);
command_register("SETACL", cmd_setacl, 0);
command_register("DELETEACL", cmd_deleteacl, 0);
}
void imap_acl_plugin_deinit(void)
{
if (getenv("ACL") == NULL)
return;
command_unregister("GETACL");
command_unregister("MYRIGHTS");
command_unregister("SETACL");
command_unregister("DELETEACL");
command_unregister("LISTRIGHTS");
}