From 26c41874cf6019c3e39f0ed630b2a07a92b2635f Mon Sep 17 00:00:00 2001 From: Josef 'Jeff' Sipek Date: Tue, 13 Sep 2016 07:50:04 -0400 Subject: [PATCH] doveadm: allow access to server attributes via empty mailbox name --- src/doveadm/doveadm-mail-mailbox-metadata.c | 93 +++++++++++++++++---- src/doveadm/doveadm-mail.c | 4 + src/doveadm/doveadm-mail.h | 3 + 3 files changed, 86 insertions(+), 14 deletions(-) diff --git a/src/doveadm/doveadm-mail-mailbox-metadata.c b/src/doveadm/doveadm-mail-mailbox-metadata.c index aadb230028..f284af6563 100644 --- a/src/doveadm/doveadm-mail-mailbox-metadata.c +++ b/src/doveadm/doveadm-mail-mailbox-metadata.c @@ -24,10 +24,33 @@ cmd_mailbox_metadata_set_run(struct doveadm_mail_cmd_context *_ctx, struct mail_namespace *ns; struct mailbox *box; struct mailbox_transaction_context *trans; + bool empty_mailbox_name; + const char *key; int ret; - ns = mail_namespace_find(user->namespaces, ctx->mailbox); - box = mailbox_alloc(ns->list, ctx->mailbox, 0); + empty_mailbox_name = (ctx->mailbox[0] == '\0'); + + if (empty_mailbox_name) { + if (!_ctx->allow_empty_mailbox_name) { + i_error("Failed to set attribute: %s", + "mailbox name cannot be empty"); + _ctx->exit_code = EX_USAGE; + return -1; + } + + /* server attribute */ + ns = mail_namespace_find_inbox(user->namespaces); + box = mailbox_alloc(ns->list, "INBOX", 0); + + key = t_strconcat(MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER, + ctx->key); + } else { + /* mailbox attributes */ + ns = mail_namespace_find(user->namespaces, ctx->mailbox); + box = mailbox_alloc(ns->list, ctx->mailbox, 0); + + key = ctx->key; + } if (mailbox_open(box) < 0) { i_error("Failed to open mailbox: %s", @@ -36,11 +59,12 @@ cmd_mailbox_metadata_set_run(struct doveadm_mail_cmd_context *_ctx, mailbox_free(&box); return -1; } - trans = mailbox_transaction_begin(box, 0); + trans = mailbox_transaction_begin(box, empty_mailbox_name ? + MAILBOX_TRANSACTION_FLAG_EXTERNAL : 0); ret = ctx->value.value == NULL ? - mailbox_attribute_unset(trans, ctx->key_type, ctx->key) : - mailbox_attribute_set(trans, ctx->key_type, ctx->key, &ctx->value); + mailbox_attribute_unset(trans, ctx->key_type, key) : + mailbox_attribute_set(trans, ctx->key_type, key, &ctx->value); if (ret < 0) { i_error("Failed to set attribute: %s", mailbox_get_last_error(box, NULL)); @@ -141,10 +165,30 @@ cmd_mailbox_metadata_get_run(struct doveadm_mail_cmd_context *_ctx, struct mail_namespace *ns; struct mailbox *box; struct mail_attribute_value value; + const char *key; int ret; - ns = mail_namespace_find(user->namespaces, ctx->mailbox); - box = mailbox_alloc(ns->list, ctx->mailbox, 0); + if (ctx->mailbox[0] == '\0') { + if (!_ctx->allow_empty_mailbox_name) { + i_error("Failed to get attribute: %s", + "mailbox name cannot be empty"); + _ctx->exit_code = EX_USAGE; + return -1; + } + + /* server attribute */ + ns = mail_namespace_find_inbox(user->namespaces); + box = mailbox_alloc(ns->list, "INBOX", 0); + + key = t_strconcat(MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER, + ctx->key); + } else { + /* mailbox attribute */ + ns = mail_namespace_find(user->namespaces, ctx->mailbox); + box = mailbox_alloc(ns->list, ctx->mailbox, 0); + + key = ctx->key; + } if (mailbox_open(box) < 0) { i_error("Failed to open mailbox: %s", @@ -154,7 +198,7 @@ cmd_mailbox_metadata_get_run(struct doveadm_mail_cmd_context *_ctx, return -1; } - ret = mailbox_attribute_get_stream(box, ctx->key_type, ctx->key, &value); + ret = mailbox_attribute_get_stream(box, ctx->key_type, key, &value); if (ret < 0) { i_error("Failed to get attribute: %s", mailbox_get_last_error(box, NULL)); @@ -229,8 +273,25 @@ cmd_mailbox_metadata_list_run(struct doveadm_mail_cmd_context *_ctx, struct mailbox *box; int ret = 0; - ns = mail_namespace_find(user->namespaces, ctx->mailbox); - box = mailbox_alloc(ns->list, ctx->mailbox, 0); + if (ctx->mailbox[0] == '\0') { + if (!_ctx->allow_empty_mailbox_name) { + i_error("Failed to list attributes: %s", + "mailbox name cannot be empty"); + _ctx->exit_code = EX_USAGE; + return -1; + } + + /* server attribute */ + ns = mail_namespace_find_inbox(user->namespaces); + box = mailbox_alloc(ns->list, "INBOX", 0); + + ctx->key = t_strconcat(MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER, + ctx->key); + } else { + /* mailbox attribute */ + ns = mail_namespace_find(user->namespaces, ctx->mailbox); + box = mailbox_alloc(ns->list, ctx->mailbox, 0); + } if (mailbox_open(box) < 0) { i_error("Failed to open mailbox: %s", @@ -287,9 +348,10 @@ static struct doveadm_mail_cmd_context *cmd_mailbox_metadata_list_alloc(void) struct doveadm_cmd_ver2 doveadm_cmd_mailbox_metadata_set_ver2 = { .name = "mailbox metadata set", .mail_cmd = cmd_mailbox_metadata_set_alloc, - .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX" ", + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"[-s] ", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('s', "allow-empty-mailbox-name", CMD_PARAM_BOOL, 0) DOVEADM_CMD_PARAM('\0', "mailbox", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "value", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) @@ -299,9 +361,10 @@ DOVEADM_CMD_PARAMS_END struct doveadm_cmd_ver2 doveadm_cmd_mailbox_metadata_unset_ver2 = { .name = "mailbox metadata unset", .mail_cmd = cmd_mailbox_metadata_unset_alloc, - .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX" ", + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"[-s] ", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('s', "allow-empty-mailbox-name", CMD_PARAM_BOOL, 0) DOVEADM_CMD_PARAM('\0', "mailbox", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END @@ -310,9 +373,10 @@ DOVEADM_CMD_PARAMS_END struct doveadm_cmd_ver2 doveadm_cmd_mailbox_metadata_get_ver2 = { .name = "mailbox metadata get", .mail_cmd = cmd_mailbox_metadata_get_alloc, - .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX" ", + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"[-s] ", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('s', "allow-empty-mailbox-name", CMD_PARAM_BOOL, 0) DOVEADM_CMD_PARAM('\0', "mailbox", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END @@ -321,9 +385,10 @@ DOVEADM_CMD_PARAMS_END struct doveadm_cmd_ver2 doveadm_cmd_mailbox_metadata_list_ver2 = { .name = "mailbox metadata list", .mail_cmd = cmd_mailbox_metadata_list_alloc, - .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX" []", + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"[-s] []", DOVEADM_CMD_PARAMS_START DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('s', "allow-empty-mailbox-name", CMD_PARAM_BOOL, 0) DOVEADM_CMD_PARAM('\0', "mailbox", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAM('\0', "key-prefix", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) DOVEADM_CMD_PARAMS_END diff --git a/src/doveadm/doveadm-mail.c b/src/doveadm/doveadm-mail.c index 6785b3c73b..03c8e65eca 100644 --- a/src/doveadm/doveadm-mail.c +++ b/src/doveadm/doveadm-mail.c @@ -1012,6 +1012,10 @@ doveadm_cmd_ver2_to_mail_cmd_wrapper(struct doveadm_cmd_context *cctx) } mctx->cmd_input = arg->value.v_istream; i_stream_ref(mctx->cmd_input); + } else if (strcmp(arg->name, "allow-empty-mailbox-name") == 0) { + /* allow an empty mailbox name - to access server + attributes */ + mctx->allow_empty_mailbox_name = arg->value.v_bool; /* Keep all named special parameters above this line */ diff --git a/src/doveadm/doveadm-mail.h b/src/doveadm/doveadm-mail.h index b115ff661e..60db54555f 100644 --- a/src/doveadm/doveadm-mail.h +++ b/src/doveadm/doveadm-mail.h @@ -101,6 +101,9 @@ struct doveadm_mail_cmd_context { bool add_username_header:1; /* Running from CLI doveadm (not doveadm-server) */ bool cli:1; + + /* Allow empty mailbox name - to allow access to server attributes */ + bool allow_empty_mailbox_name:1; }; struct doveadm_mail_cmd {