/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "imap-match.h"
#include "mailbox-tree.h"
#include "mail-namespace.h"
#include "mailbox-list-iter-private.h"
#include "acl-api-private.h"
#include "acl-cache.h"
#include "acl-shared-storage.h"
#include "acl-plugin.h"
struct acl_mailbox_list_iterate_context {
char sep;
};
};
{
}
bool parent, unsigned int acl_storage_right_idx,
bool *can_see_r)
{
if (ret2 < 0)
ret = -1;
}
if (ret < 0)
return ret;
}
static void
{
const unsigned int *idxp;
const char *name;
return;
/* mailboxes in public namespace should all be listable to
someone. we don't benefit from fast listing. */
return;
}
/* if this namespace's default rights contain LOOKUP, we'll need to
go through all mailboxes in any case. */
return;
/* no LOOKUP right by default, we can optimize this */
i_zero(&update_ctx);
&name)) {
T_BEGIN {
const char *vname =
} T_END;
}
else
}
static struct mailbox_list_iterate_context *
const char *const *patterns,
enum mailbox_list_iter_flags flags)
{
int ret;
/* before listing anything add namespaces for all users
who may have visible mailboxes */
if (ret < 0)
return ctx;
}
static struct mailbox_list_iterate_context *
const char *const *patterns,
enum mailbox_list_iter_flags flags)
{
const char *p;
unsigned int i;
/* non-private namespace with subscriptions=yes. this could be
a site-global subscriptions file, so hide subscriptions for
mailboxes the user doesn't see. */
}
/* see if all patterns have only a single '*' and it's at the end.
we can use it to do some optimizations. */
break;
}
}
/* Try to avoid reading ACLs from all mailboxes by getting a smaller
list of mailboxes that have even potential to be visible. If we
couldn't get such a list, we'll go through all mailboxes. */
T_BEGIN {
} T_END;
return _ctx;
}
static const struct mailbox_info *
{
/* if we've a list of mailboxes with LOOKUP rights, skip the
mailboxes not in the list (since we know they can't be
visible to us). */
break;
i_debug("acl: Mailbox not in dovecot-acl-list: %s",
}
}
return info;
}
static const char *
const char *vname)
{
const char *name;
/* name ends with separator. this can happen if doing e.g.
LIST "" foo/% and it lists "foo/". */
}
return name;
}
static bool
{
const char *child;
/* If all patterns (with '.' separator) are in "name*", "name.*" or
"%.*" style format, simple_star_glob=TRUE and we can easily test
return ctx->simple_star_glob &&
}
static bool
bool only_nonpatterns, bool subscribed)
{
const char *prefix;
/* do we have child mailboxes with LOOKUP right that don't match
the list pattern? */
/* we have a list of mailboxes with LOOKUP rights. before
starting the slow list iteration, check check first
if there even are any children with LOOKUP rights. */
return FALSE;
}
/* if mailbox name has '*' characters in it, they'll conflict with the
LIST wildcard. replace then with '%' and verify later that all
results have the correct prefix. */
else {
}
}
(!subscribed ? 0 :
if (only_nonpatterns &&
/* at least one child matches also the original list
patterns. we don't need to show this mailbox. */
break;
}
}
(void)mailbox_list_iter_deinit(&iter);
return ret;
}
static int
{
const char *acl_name;
int ret;
/* skip ACL checks. */
return 1;
}
/* don't waste time doing an ACL check. we're going to list
all subscriptions anyway. */
return 1;
}
NULL);
if (ret != 0) {
/* don't waste time checking if there are visible
children, but also don't return incorrect flags */
}
return ret;
}
/* no permission to see this mailbox */
/* we're listing subscribed mailboxes. this one or its child
is subscribed, so we'll need to list it. but since we don't
have LOOKUP right, we'll need to show it as nonexistent. */
if (ctx->hide_nonlistable_subscriptions) {
/* global subscriptions file. hide this entry if there
are no visible subscribed children or if we're going
to list the subscribed children anyway. */
return 0;
if (iter_is_listing_all_children(_ctx) ||
return 0;
/* e.g. LSUB "" % with visible subscribed children */
}
return 1;
}
if (!iter_is_listing_all_children(_ctx) &&
/* no child mailboxes match the list pattern(s), but mailbox
has visible children. we'll need to show this as
non-existent. */
return 1;
}
return 0;
}
static int
{
unsigned int i, count;
int ret;
return 0;
/* skip ACL checks. */
return 0;
}
for (i = 0; i < count; ) {
const char *acl_name =
NULL);
if (ret < 0)
return -1;
if (ret > 0)
i++;
else {
/* no list right - remove the whole autobox */
}
}
return 0;
}
static const struct mailbox_info *
{
int ret;
if (!ctx->autocreate_acls_checked) {
if (acl_mailbox_list_iter_check_autocreate_acls(_ctx) < 0) {
return NULL;
}
}
T_BEGIN {
} T_END;
if (ret > 0)
break;
if (ret < 0) {
return NULL;
}
/* skip to next one */
i_debug("acl: No lookup right to mailbox: %s",
}
}
}
static int
{
ret = -1;
return ret;
}
{
}
{
}
struct acl_backend *backend)
{
unsigned int i;
for (i = 0; i < ACL_STORAGE_RIGHT_COUNT; i++) {
ctx->acl_storage_right_idx[i] =
}
}
{
/* not necessarily, but safer to do this for now. */
i_fatal("mail_full_filesystem_access=yes is "
"incompatible with ACLs");
}
}
{
return;
if (current_username == NULL)
else
/* We don't care about the username for non-private mailboxes.
It's used only when checking if we're the mailbox owner. We never
/* we need to know the storage when initializing backend */
i_fatal("ACL backend initialization failed");
}
{
/* ACLs disabled for this user */
/* no ACL checks for internal namespaces (lda, shared) */
/* this namespace is empty. don't attempt to lookup ACLs,
because they're not going to work anyway and we could
crash doing it. */
} else {
}
}