/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "istream.h"
#include "nfs-workarounds.h"
#include "mail-storage-private.h"
#include "acl-global-file.h"
#include "acl-cache.h"
#include "acl-backend-vfile.h"
#include <fcntl.h>
#include <unistd.h>
{
}
static int
{
(struct acl_backend_vfile *)_backend;
const char *const *tmp;
tmp++;
i_error("acl vfile: Invalid cache_secs value: %s",
*tmp + 11);
return -1;
}
} else {
return -1;
}
}
i_error("acl vfile: stat(%s) failed: %m",
return -1;
}
}
}
i_debug("acl vfile: Global ACLs disabled");
i_debug("acl vfile: Global ACL file: %s",
} else {
i_debug("acl vfile: Global ACL legacy directory: %s",
}
}
sizeof(struct acl_backend_vfile_validity));
return 0;
}
{
(struct acl_backend_vfile *)_backend;
}
}
static const char *
{
if (*name == '\0')
if (backend->globals_only)
return NULL;
/* ACL files are very important. try to keep them among the main
mail files. that's not possible though with a) if the mailbox is
a file or b) if the mailbox path doesn't point to filesystem. */
return NULL;
return NULL;
} else {
return NULL;
}
/* verify that the directory isn't same as INBOX's directory.
this is mainly for Maildir. */
MAILBOX_LIST_PATH_TYPE_MAILBOX, &inbox) > 0 &&
/* can't have default ACLs with this setup */
return NULL;
}
return dir;
}
static struct acl_object *
const char *name)
{
(struct acl_backend_vfile *)_backend;
T_BEGIN {
if (*name == '\0' ||
}
} else {
/* Invalid mailbox name, just use the default
global ACL files */
}
} T_END;
}
static const char *
{
const char *p;
}
static int
struct acl_vfile_validity *validity)
{
/* use the cached value */
}
return 0;
}
return 1;
}
return -1;
}
return 1;
}
static bool
{
(struct acl_backend_vfile *)_backend;
const char *error;
int ret;
if (old_validity != NULL)
else
/* See if the mailbox exists. If we wanted recursive lookups we could
skip this, but at least for now we assume that if an existing
mailbox has no ACL it's equivalent to default ACLs. */
MAILBOX_LIST_PATH_TYPE_MAILBOX, &path) <= 0)
ret = -1;
else {
}
if (ret == 0 &&
(*name == '\0' ||
}
}
ret = 1;
} else {
}
}
return ret > 0;
}
static struct acl_object *
const char *child_name)
{
const char *parent;
/* stop at the first parent that
a) has global ACL file
b) has local ACL file
c) exists */
break;
child_name = parent;
}
/* use the root */
}
}
{
}
static int
bool *is_dir_r)
{
unsigned int linenum;
if (fd == -1) {
i_debug("acl vfile: no access to file %s",
path);
} else {
return -1;
}
return 1;
}
i_close_fd(&fd);
return 0;
}
i_close_fd(&fd);
return -1;
}
/* we opened a directory. */
i_close_fd(&fd);
return 0;
}
linenum = 0;
linenum++;
continue;
T_BEGIN {
if (ret < 0) {
i_error("ACL file %s line %u: %s",
} else {
}
} T_END;
if (ret < 0)
break;
}
if (ret < 0) {
/* parsing failure */
} else if (input->stream_errno != 0) {
ret = 0;
else {
ret = -1;
}
} else {
ret = 0;
else {
ret = -1;
}
} else {
ret = 1;
}
}
return 0;
return -1;
}
return ret;
}
static int
struct acl_vfile_validity *validity)
{
unsigned int i;
int ret;
bool is_dir;
return 0;
for (i = 0;; i++) {
&is_dir);
if (ret != 0)
break;
if (is_dir) {
/* opened a directory. use dir/.DEFAULT instead */
} else {
/* ESTALE - try again */
}
}
return ret <= 0 ? -1 : 0;
}
static bool
const struct acl_vfile_validity *validity,
{
/* same timestamp, but if it was modified within the
same second we want to refresh it again later (but
do it only after a couple of seconds so we don't
keep re-reading it all the time within those
seconds) */
if (validity->last_read_time != 0 &&
return FALSE;
}
return TRUE;
}
static int
struct acl_vfile_validity *validity)
{
int ret;
return 1;
return 0;
/* it's a directory. use dir/.DEFAULT instead */
}
if (ret < 0) {
/* if the file used to exist, we have to re-read it */
}
return -1;
}
}
{
return -1;
else
*mtime_r = 0;
return 0;
}
static int
struct acl_vfile_validity *validity)
{
return -1;
return 1;
}
{
int ret;
if (ret == 0) {
}
if (ret <= 0)
return ret;
/* either global or local ACLs changed, need to re-read both */
} else {
}
} else {
&validity.global_validity) < 0)
return -1;
}
&validity.local_validity) < 0)
return -1;
/* update cache only after we've successfully read everything */
return 0;
}
{
*last_changed_r = 0;
if (old_validity == NULL) {
return -1;
if (old_validity == NULL)
return 0;
}
return 0;
}
};