acl-backend-vfile.c revision f988345bc29ef022ae73f96b3ec841d39c46d30a
/* Copyright (c) 2006-2017 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>
#define ACL_VFILE_DEFAULT_CACHE_SECS 30
static struct acl_backend *acl_backend_vfile_alloc(void)
{
struct acl_backend_vfile *backend;
}
static int
{
struct acl_backend_vfile *backend =
(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 =
(struct acl_backend_vfile *)_backend;
}
}
static const char *
{
struct mail_storage *storage;
enum mailbox_list_path_type type;
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 =
(struct acl_backend_vfile *)_backend;
struct acl_object_vfile *aclobj;
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 =
(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)
{
struct acl_rights rights;
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 int
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)
{
struct acl_backend_vfile *backend =
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;
}
}
{
struct acl_backend_vfile_validity *validity;
return -1;
else
*mtime_r = 0;
return 0;
}
{
struct acl_backend_vfile *backend =
struct acl_backend_vfile_validity *old_validity;
struct acl_backend_vfile_validity validity;
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;
}
{
struct acl_backend_vfile_validity *old_validity;
*last_changed_r = 0;
if (old_validity == NULL) {
return -1;
if (old_validity == NULL)
return 0;
}
return 0;
}
struct acl_backend_vfuncs acl_backend_vfile = {
};