imap-acl-plugin.c revision 04870054863757edf048c81dcce3c5e7dec453cd
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#include "common.h"
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#include "str.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "imap-quote.h"
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#include "imap-resp-code.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "commands.h"
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#include "mail-storage.h"
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#include "mail-namespace.h"
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#include "acl-api.h"
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen#include "acl-storage.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include "imap-acl-plugin.h"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#include <stdlib.h>
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#define ERROR_NOT_ADMIN "["IMAP_RESP_CODE_ACL"] " \
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen "You lack administrator privileges on this mailbox."
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#define ACL_MAILBOX_OPEN_FLAGS \
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen (MAILBOX_OPEN_READONLY | MAILBOX_OPEN_FAST | MAILBOX_OPEN_KEEP_RECENT)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#define IMAP_ACL_ANYONE "anyone"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#define IMAP_ACL_AUTHENTICATED "authenticated"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#define IMAP_ACL_OWNER "owner"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#define IMAP_ACL_GROUP_PREFIX "$"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#define IMAP_ACL_GROUP_OVERRIDE_PREFIX "!$"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen#define IMAP_ACL_GLOBAL_PREFIX "#"
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstruct imap_acl_letter_map {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen char letter;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen const char *name;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen};
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic const struct imap_acl_letter_map imap_acl_letter_map[] = {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { 'l', MAIL_ACL_LOOKUP },
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { 'r', MAIL_ACL_READ },
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { 'w', MAIL_ACL_WRITE },
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { 's', MAIL_ACL_WRITE_SEEN },
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { 't', MAIL_ACL_WRITE_DELETED },
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { 'i', MAIL_ACL_INSERT },
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { 'p', MAIL_ACL_POST },
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { 'e', MAIL_ACL_EXPUNGE },
52de839a8249bff5eace53dc1401b28baa0c124bTimo Sirainen { 'k', MAIL_ACL_CREATE },
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { 'x', MAIL_ACL_DELETE },
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { 'a', MAIL_ACL_ADMIN },
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen { '\0', NULL }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen};
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic bool acl_anyone_allow = FALSE;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstatic struct mailbox *
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenacl_mailbox_open_as_admin(struct client_command_context *cmd, const char *name)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct mail_storage *storage;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct mailbox *box;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen int ret;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen storage = client_find_storage(cmd, &name);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (storage == NULL)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return NULL;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen /* Force opening the mailbox so that we can give a nicer error message
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if mailbox isn't selectable but is listable. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen box = mailbox_open(storage, name, NULL, ACL_MAILBOX_OPEN_FLAGS |
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen MAILBOX_OPEN_IGNORE_ACLS);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen if (box == NULL) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client_send_storage_error(cmd, storage);
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen return NULL;
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_ADMIN);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (ret > 0)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen return box;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen /* not an administrator. */
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen if (acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_LOOKUP) <= 0) {
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen client_send_tagline(cmd, t_strdup_printf(
c59b9c273b41f7bcf51f6803110b67813879ff05Timo Sirainen "NO ["IMAP_RESP_CODE_NONEXISTENT"] "
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen MAIL_ERRSTR_MAILBOX_NOT_FOUND, name));
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen } else {
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen client_send_tagline(cmd, "NO "ERROR_NOT_ADMIN);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen }
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen mailbox_close(&box);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen return NULL;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen}
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainenstatic const struct imap_acl_letter_map *
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainenimap_acl_letter_map_find(const char *name)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen{
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen unsigned int i;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen for (i = 0; imap_acl_letter_map[i].name != NULL; i++) {
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (strcmp(imap_acl_letter_map[i].name, name) == 0)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen return &imap_acl_letter_map[i];
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen }
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen return NULL;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen}
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainenstatic void
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainenimap_acl_write_rights_list(string_t *dest, const char *const *rights)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen{
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen const struct imap_acl_letter_map *map;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen unsigned int i;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen bool append_c = FALSE, append_d = FALSE;
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen for (i = 0; rights[i] != NULL; i++) {
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen /* write only letters */
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen map = imap_acl_letter_map_find(rights[i]);
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen if (map != NULL) {
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen str_append_c(dest, map->letter);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (map->letter == 'k' || map->letter == 'x')
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen append_c = TRUE;
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen if (map->letter == 't' || map->letter == 'e')
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen append_d = TRUE;
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen }
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen }
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (append_c)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen str_append_c(dest, 'c');
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (append_d)
2c50ccaa9adb7df8cb49a240909fce732da57bedTimo Sirainen str_append_c(dest, 'd');
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainen}
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainen
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainenstatic void
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainenimap_acl_write_right(string_t *dest, string_t *tmp,
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainen const struct acl_rights *right, bool neg)
e3e5ca6aec3efe6ef7419f411d934a5350f06df9Timo Sirainen{
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen const char *const *rights = neg ? right->neg_rights : right->rights;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
2a77044395c864cc791cecd34b03002094f4973bTimo Sirainen if (neg) str_append_c(dest,'-');
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
2c50ccaa9adb7df8cb49a240909fce732da57bedTimo Sirainen str_truncate(tmp, 0);
2c50ccaa9adb7df8cb49a240909fce732da57bedTimo Sirainen if (right->global)
2c50ccaa9adb7df8cb49a240909fce732da57bedTimo Sirainen str_append(tmp, IMAP_ACL_GLOBAL_PREFIX);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen switch (right->id_type) {
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen case ACL_ID_ANYONE:
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str_append(tmp, IMAP_ACL_ANYONE);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen case ACL_ID_AUTHENTICATED:
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen str_append(tmp, IMAP_ACL_AUTHENTICATED);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen case ACL_ID_OWNER:
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str_append(tmp, IMAP_ACL_OWNER);
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen break;
9fd6f70ed6d4733ae5eabd49822bda280393e403Timo Sirainen case ACL_ID_USER:
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen str_append(tmp, right->identifier);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen break;
1554bed8d2b4e4286c10f7d6bcf716b246bd5bafTimo Sirainen case ACL_ID_GROUP:
1554bed8d2b4e4286c10f7d6bcf716b246bd5bafTimo Sirainen str_append(tmp, IMAP_ACL_GROUP_PREFIX);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen str_append(tmp, right->identifier);
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen break;
7631f16156aca373004953fe6b01a7f343fb47e0Timo Sirainen case ACL_ID_GROUP_OVERRIDE:
2c50ccaa9adb7df8cb49a240909fce732da57bedTimo Sirainen str_append(tmp, IMAP_ACL_GROUP_OVERRIDE_PREFIX);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen str_append(tmp, right->identifier);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen break;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen case ACL_ID_TYPE_COUNT:
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen i_unreached();
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen }
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen imap_quote_append(dest, str_data(tmp), str_len(tmp), FALSE);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen str_append_c(dest, ' ');
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen imap_acl_write_rights_list(dest, rights);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen}
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainenstatic int imap_acl_write_aclobj(string_t *dest, struct acl_object *aclobj)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen{
90e39174d397567c101dbf694761371af3682928Timo Sirainen struct acl_object_list_iter *iter;
99695d99930b35c2bac85d52e976b44cf8485d83Timo Sirainen struct acl_rights rights;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen string_t *tmp;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen int ret;
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen tmp = t_str_new(128);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen iter = acl_object_list_init(aclobj);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen while ((ret = acl_object_list_next(iter, &rights)) > 0) {
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen str_append_c(dest, ' ');
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (rights.rights != NULL)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen imap_acl_write_right(dest, tmp, &rights, FALSE);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen if (rights.neg_rights != NULL)
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen imap_acl_write_right(dest, tmp, &rights, TRUE);
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen }
e8762c2b4914db7997fa9eb644a91586952d1876Timo Sirainen acl_object_list_deinit(&iter);
return ret;
}
static bool cmd_getacl(struct client_command_context *cmd)
{
struct mailbox *box;
const char *mailbox;
string_t *str;
unsigned int len;
int ret;
if (!client_read_string_args(cmd, 1, &mailbox)) {
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, "* 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.");
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.");
return TRUE;
}
static int
imap_acl_letters_parse(const char *letters, const char *const **rights_r,
const char **error_r)
{
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) {
*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' || *rights == '\0') {
client_send_command_error(cmd, "Invalid arguments.");
return TRUE;
}
memset(&update, 0, sizeof(update));
if (*identifier == '-') {
negative = TRUE;
identifier++;
}
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;
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 (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)
{
command_unregister("GETACL");
command_unregister("MYRIGHTS");
command_unregister("SETACL");
command_unregister("DELETEACL");
command_unregister("LISTRIGHTS");
}