/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "strescape.h"
#include "hash.h"
#include "mail-user.h"
#include "mailbox-list.h"
#include "acl-global-file.h"
#include "acl-cache.h"
#include "acl-api-private.h"
struct acl_letter_map {
char letter;
const char *name;
};
{ 'l', MAIL_ACL_LOOKUP },
{ 'r', MAIL_ACL_READ },
{ 'w', MAIL_ACL_WRITE },
{ 's', MAIL_ACL_WRITE_SEEN },
{ 't', MAIL_ACL_WRITE_DELETED },
{ 'i', MAIL_ACL_INSERT },
{ 'p', MAIL_ACL_POST },
{ 'e', MAIL_ACL_EXPUNGE },
{ 'k', MAIL_ACL_CREATE },
{ 'x', MAIL_ACL_DELETE },
{ 'a', MAIL_ACL_ADMIN },
{ '\0', NULL }
};
const char *name)
{
}
const char *child_name)
{
}
{
}
{
unsigned int read_idx;
return -1;
return -1;
}
return 1;
/* when dsync is running on a shared mailbox, it must be able
to do everything inside it. however, dsync shouldn't touch
mailboxes where user doesn't have any read access, because
that could make them readable on the replica. */
return 1;
}
return 0;
}
const char *const *
{
const char *const *names;
count = 0;
else {
continue;
/* @UNSAFE */
}
}
}
/* @UNSAFE */
return rights;
}
const char *const **rights_r)
{
return -1;
return -1;
}
return 0;
}
const char *const **rights_r)
{
int ret;
if (pool->datastack_pool)
T_BEGIN {
} T_END;
return ret;
}
{
}
{
}
const struct acl_rights_update *update)
{
}
{
}
struct acl_rights *rights_r)
{
return FALSE;
}
{
}
struct acl_object_list_iter *
{
unsigned int i;
/* we may have the object cached, but we don't have all the
rights read into memory */
}
} else
return iter;
}
struct acl_rights *rights_r)
{
return FALSE;
return FALSE;
return TRUE;
}
{
int ret = 0;
ret = -1;
ret = 0;
else
ret = 1;
return ret;
}
struct acl_mailbox_list_context *
{
}
const char **name_r)
{
}
{
}
{
}
{
case ACL_ID_ANYONE:
break;
case ACL_ID_AUTHENTICATED:
break;
case ACL_ID_OWNER:
break;
case ACL_ID_USER:
break;
case ACL_ID_GROUP:
break;
case ACL_ID_GROUP_OVERRIDE:
break;
case ACL_ID_TYPE_COUNT:
i_unreached();
}
}
{
}
{
unsigned int i;
for (i = 0; all_mailbox_rights[i] != NULL; i++) {
return TRUE;
}
return FALSE;
}
const char **error_r)
{
unsigned int i, j;
return -1;
}
return 0;
}
if (right[0] != '-')
dest = &dest_rights;
else {
right++;
dest = &dest_neg_rights;
}
if (*right == ':') {
/* non-standard right */
right++;
} else if (is_standard_right(right)) {
} else {
right);
return -1;
}
} else {
for (j = 0; all_mailbox_rights[j] != NULL; j++)
}
}
if (array_count(&dest_rights) > 0) {
}
if (array_count(&dest_neg_rights) > 0) {
}
return 0;
}
{
}
}
{
/* <id> [<imap acls>] [:<named acls>] */
if (*line == '"') {
line++;
*error_r = "Invalid quoted ID";
return -1;
}
if (line[0] == ' ')
line++;
} else {
line = "";
else
}
if (*id_str != '-')
else {
id_str++;
}
return -1;
}
return 0;
}
{
}
{
int ret;
/* globals have higher priority than locals */
}
if (ret != 0)
return ret;
}
{
return;
/* merge identical identifiers */
/* add i's rights to dest and delete i */
} else {
if (++dest != i)
}
}
}
{
const char *const *p;
/* ignore owner rights */
return FALSE;
}
return FALSE;
if (strcmp(*p, MAIL_ACL_LOOKUP) == 0)
return TRUE;
}
return FALSE;
}
{
strlen(ACL_ID_NAME_USER_PREFIX)) == 0) {
strlen(ACL_ID_NAME_GROUP_PREFIX)) == 0) {
strlen(ACL_ID_NAME_GROUP_OVERRIDE_PREFIX)) == 0) {
} else {
return -1;
}
return 0;
}
static const char *const *
bool dup_strings)
{
/* sort the rights first so we can easily drop duplicates */
/* @UNSAFE */
if (count > 0) {
}
if (dup_strings) {
for (i = 0; i < dest; i++)
}
}
return ret;
}
const char *const *
{
const char *const *names;
unsigned int i;
/* parse IMAP ACL list */
acl++;
break;
}
return NULL;
}
acl++;
}
if (*acl != '\0') {
/* parse our own extended ACLs */
if (*acl != ':') {
*error_r = "Missing ':' prefix in ACL extensions";
return NULL;
}
}
}
}
{
unsigned int i, j, pos;
/* use letters if possible */
pos++;
break;
}
}
/* fallback to full name */
}
}
c2[0] = ':';
}
}
const char *const *src, bool dup_strings)
{
unsigned int i;
}
}
}
const char *const **rightsp,
const char *const *modify_rights,
enum acl_modify_mode modify_mode)
{
unsigned int i, j;
/* nothing to do here */
return FALSE;
}
switch (modify_mode) {
case ACL_MODIFY_MODE_REMOVE:
/* nothing to do */
return FALSE;
}
for (i = 0; old_rights[i] != NULL; i++) {
for (j = 0; modify_rights[j] != NULL; j++) {
break;
}
if (modify_rights[j] == NULL)
}
new_rights = &null;
break;
case ACL_MODIFY_MODE_ADD:
break;
case ACL_MODIFY_MODE_REPLACE:
new_rights = &null;
break;
case ACL_MODIFY_MODE_CLEAR:
/* ACL didn't exist before either */
return FALSE;
}
return TRUE;
}
*rightsp = new_rights;
if (old_rights == NULL)
return new_rights[0] != NULL;
/* see if anything changed */
return TRUE;
}
}
{
}
{
unsigned int i, count;
return;
/* Rights are sorted by their 1) locals first, globals next,
2) acl_id_type. We'll apply only the rights matching ourself.
replace all of the existing ACLs. Basically this means that if
user belongs to multiple matching groups or group-overrides, their
ACLs are merged. In all other situations the ACLs are replaced
(because there aren't duplicate rights entries and a user can't
match multiple usernames). */
i = 0;
else {
/* we're the owner. skip over all rights entries until we
reach ACL_ID_OWNER or higher, or alternatively when we
reach a global ACL (even ACL_ID_ANYONE overrides owner's
rights if it's global) */
for (i = 0; i < count; i++) {
break;
}
/* now continue applying the rest of the rights,
if there are any */
}
for (; i < count; i++) {
continue;
if (prev_match == NULL ||
/* replace old ACLs */
} else {
/* merging to existing ACLs */
}
prev_match = &rights[i];
/* If [neg_]rights is NULL it needs to be ignored.
The easiest way to do that is to just mark it with
REMOVE mode */
/* first global: reset negative ACLs so local ACLs
can't mess things up via them */
}
}
}
{
}
{
else
vname = "";
}