acl-api.c revision 7cb128dc4cae2a03a742f63ba7afee23c78e3af0
/* Copyright (c) 2006-2015 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;
};
static const struct acl_letter_map acl_letter_map[] = {
{ '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 -1;
}
{
}
struct acl_object_list_iter *
{
struct acl_object_list_iter *iter;
/* we may have the object cached, but we don't have all the
rights read into memory */
}
return iter;
}
struct acl_rights *rights_r)
{
const struct acl_rights *rights;
return 0;
return 1;
}
{
}
struct acl_mailbox_list_context *
{
}
const char **name_r)
{
}
void
{
}
{
}
{
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();
}
}
{
}
static bool is_standard_right(const char *name)
{
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;
}
{
}
}
{
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;
}
{
struct acl_rights *rights;
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;
}
}
}
}
{
char c2[2];
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)
{
const char *const *old_rights = *rightsp;
const char *const *new_rights = NULL;
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;
}
}
{
struct acl_rights_update ru;
}
{
struct acl_rights_update ru;
enum acl_modify_mode add_mode;
unsigned int i, count;
bool first_global = TRUE;
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 */
}
}
}
{
struct acl_rights rights;
}
{
else
vname = "";
}