/*
Copyright (C) 2004 IC & S dbmail@ic-s.nl
Copyright (c) 2005-2006 NFG Net Facilities Group BV support@nfg.nl
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "dbmail.h"
#define NR_ACL_FLAGS 9
static const char *acl_right_strings[] = {
"lookup_flag",
"read_flag",
"seen_flag",
"write_flag",
"insert_flag",
"post_flag",
"create_flag",
"delete_flag",
"administer_flag"
};
static const char acl_right_chars[] = "lrswipcda";
//{'l','r','s','w','i','p','c','d','a'};
/* local functions */
static ACLRight_t acl_get_right_from_char(char right_char);
static int acl_change_rights(u64_t userid, u64_t mboxid,
const char *rightsstring, int set);
static int acl_replace_rights(u64_t userid, u64_t mboxid,
const char *rightsstring);
static int acl_set_one_right(u64_t userid, u64_t mboxid,
ACLRight_t right, int set);
static int acl_get_rightsstring_identifier(char *identifier, u64_t mboxid,
/*@out@*/ char *rightsstring);
static int acl_get_rightsstring(u64_t userid, u64_t mboxid,
/*@out@*/ char *rightsstring);
int acl_has_right(mailbox_t *mailbox, u64_t userid, ACLRight_t right)
{
u64_t anyone_userid;
int test;
switch(right) {
case ACL_RIGHT_SEEN:
case ACL_RIGHT_WRITE:
case ACL_RIGHT_INSERT:
case ACL_RIGHT_POST:
case ACL_RIGHT_CREATE:
case ACL_RIGHT_DELETE:
case ACL_RIGHT_ADMINISTER:
if (mailbox_is_writable(mailbox->uid))
return FALSE;
break;
/* ignore the rest */
default:
break;
}
const char *right_flag = acl_right_strings[right];
/* first try if the user has the right */
if ((test = db_acl_has_right(mailbox, userid, right_flag)))
return TRUE;
/* else check the 'anyone' user */
test = auth_user_exists(DBMAIL_ACL_ANYONE_USER, &anyone_userid);
if (test == DM_EQUERY)
return DM_EQUERY;
if (test)
return db_acl_has_right(mailbox, anyone_userid, right_flag);
return FALSE;
}
int acl_set_rights(u64_t userid, u64_t mboxid, const char *rightsstring)
{
if (rightsstring[0] == '-')
return acl_change_rights(userid, mboxid, rightsstring, 0);
if (rightsstring[0] == '+')
return acl_change_rights(userid, mboxid, rightsstring, 1);
return acl_replace_rights(userid, mboxid, rightsstring);
}
ACLRight_t acl_get_right_from_char(char right_char)
{
switch (right_char) {
case 'l':
return ACL_RIGHT_LOOKUP;
case 'r':
return ACL_RIGHT_READ;
case 's':
return ACL_RIGHT_SEEN;
case 'w':
return ACL_RIGHT_WRITE;
case 'i':
return ACL_RIGHT_INSERT;
case 'p':
return ACL_RIGHT_POST;
case 'c':
return ACL_RIGHT_CREATE;
case 'd':
return ACL_RIGHT_DELETE;
case 'a':
return ACL_RIGHT_ADMINISTER;
default:
trace(TRACE_ERROR,
"%s,%s: error wrong acl character. This "
"error should have been caught earlier!", __FILE__,
__func__);
return ACL_RIGHT_NONE;
}
}
int
acl_change_rights(u64_t userid, u64_t mboxid, const char *rightsstring,
int set)
{
size_t i;
char rightchar;
for (i = 1; i < strlen(rightsstring); i++) {
rightchar = rightsstring[i];
if (acl_set_one_right(userid, mboxid,
acl_get_right_from_char(rightchar),
set) < 0)
return -1;
}
return 1;
}
int
acl_replace_rights(u64_t userid, u64_t mboxid, const char *rightsstring)
{
unsigned i;
int set;
trace(TRACE_DEBUG, "%s,%s: replacing rights for user [%llu], "
"mailbox [%llu] to %s", __FILE__, __func__,
userid, mboxid, rightsstring);
for (i = ACL_RIGHT_LOOKUP; i < ACL_RIGHT_NONE; i++) {
if (strchr(rightsstring, (int) acl_right_chars[i]))
set = 1;
else
set = 0;
if (db_acl_set_right
(userid, mboxid, acl_right_strings[i], set) < 0) {
trace(TRACE_ERROR, "%s, %s: error replacing ACL",
__FILE__, __func__);
return -1;
}
}
return 1;
}
int
acl_set_one_right(u64_t userid, u64_t mboxid, ACLRight_t right, int set)
{
return db_acl_set_right(userid, mboxid, acl_right_strings[right],
set);
}
/*
int acl_delete_acl(u64_t userid, u64_t mboxid)
{
return db_acl_delete_acl(userid, mboxid);
}
*/
char *acl_get_acl(u64_t mboxid)
{
u64_t userid;
char *username;
size_t acl_string_size = 0;
size_t acl_strlen;
char *acl_string; /* return string */
char *identifier; /* one identifier */
char rightsstring[NR_ACL_FLAGS + 1];
int result;
struct dm_list identifier_list;
struct element *identifier_elm;
unsigned nr_identifiers = 0;
result = db_acl_get_identifier(mboxid, &identifier_list);
if (result < 0) {
trace(TRACE_ERROR, "%s,%s: error when getting identifier "
"list for mailbox [%llu].", __FILE__, __func__,
mboxid);
dm_list_free(&identifier_list.start);
return NULL;
}
/* add the current user to the list if this user is the owner
* of the mailbox
*/
if (db_get_mailbox_owner(mboxid, &userid) < 0) {
trace(TRACE_ERROR, "%s,%s: error querying ownership of "
"mailbox", __FILE__, __func__);
dm_list_free(&identifier_list.start);
return NULL;
}
if ((username = auth_get_userid(userid)) == NULL) {
trace(TRACE_ERROR, "%s,%s: error getting username for "
"user [%llu]", __FILE__, __func__, userid);
dm_list_free(&identifier_list.start);
return NULL;
}
if (dm_list_nodeadd(&identifier_list, username, strlen(username) + 1) == NULL) {
trace(TRACE_ERROR, "%s,%s: error adding username to list",
__FILE__, __func__);
dm_list_free(&identifier_list.start);
dm_free(username);
return NULL;
}
dm_free(username);
trace(TRACE_DEBUG, "%s,%s: before looping identifiers!", __FILE__, __func__);
identifier_elm = dm_list_getstart(&identifier_list);
while (identifier_elm) {
nr_identifiers++;
acl_string_size += strlen((char *) identifier_elm->data) + NR_ACL_FLAGS + 2;
identifier_elm = identifier_elm->nextnode;
}
trace(TRACE_DEBUG, "%s,%s: acl_string size = %zd", __FILE__, __func__, acl_string_size);
if (! (acl_string = g_new0(char, acl_string_size + 1))) {
dm_list_free(&identifier_list.start);
trace(TRACE_FATAL, "%s,%s: error allocating memory",
__FILE__, __func__);
return NULL;
}
identifier_elm = dm_list_getstart(&identifier_list);
while (identifier_elm) {
identifier = (char *) identifier_elm->data;
if (acl_get_rightsstring_identifier(identifier, mboxid, rightsstring) < 0) {
dm_list_free(&identifier_list.start);
dm_free(acl_string);
return NULL;
}
trace(TRACE_DEBUG, "%s,%s: %s", __FILE__, __func__, rightsstring);
if (strlen(rightsstring) > 0) {
acl_strlen = strlen(acl_string);
(void) snprintf(&acl_string[acl_strlen], acl_string_size - acl_strlen, "%s %s ", identifier, rightsstring);
}
identifier_elm = identifier_elm->nextnode;
}
dm_list_free(&identifier_list.start);
return g_strstrip(acl_string);
}
char *acl_listrights(u64_t userid, u64_t mboxid)
{
int result;
if ((result = db_user_is_mailbox_owner(userid, mboxid)) < 0) {
trace(TRACE_ERROR, "%s,%s: error checking if user "
"is owner of a mailbox", __FILE__, __func__);
return NULL;
}
if (result == 0) {
/* user is not owner. User will never be granted any right
by default, but may be granted any right by setting the
right ACL */
return g_strdup("\"\" l r s w i p c d a");
}
/* user is owner, User will always be granted all rights */
return g_strdup(acl_right_chars);
}
char *acl_myrights(u64_t userid, u64_t mboxid)
{
char *rightsstring;
if (! (rightsstring = g_new0(char, NR_ACL_FLAGS + 1))) {
trace(TRACE_ERROR, "%s,%s: error allocating memory for "
"rightsstring", __FILE__, __func__);
return NULL;
}
if (acl_get_rightsstring(userid, mboxid, rightsstring) < 0) {
trace(TRACE_ERROR, "%s,%s: error getting rightsstring.",
__FILE__, __func__);
dm_free(rightsstring);
return NULL;
}
return rightsstring;
}
int acl_get_rightsstring_identifier(char *identifier, u64_t mboxid, char *rightsstring)
{
u64_t userid;
assert(rightsstring);
memset(rightsstring, '\0', NR_ACL_FLAGS + 1);
if (auth_user_exists(identifier, &userid) < 0) {
trace(TRACE_ERROR, "%s,%s: error finding user id for "
"user with name [%s]", __FILE__, __func__,
identifier);
return -1;
}
return acl_get_rightsstring(userid, mboxid, rightsstring);
}
int acl_get_rightsstring(u64_t userid, u64_t mboxid, char *rightsstring)
{
int result;
u64_t owner_idnr;
mailbox_t mailbox;
struct ACLMap map;
assert(rightsstring);
memset(rightsstring, '\0', NR_ACL_FLAGS + 1);
if ((result = db_get_mailbox_owner(mboxid, &owner_idnr)) <= 0)
return result;
if (owner_idnr == userid) {
trace(TRACE_DEBUG, "%s, %s: mailbox [%llu] is owned by user [%llu], giving all rights",
__FILE__, __func__, mboxid, userid);
g_strlcat(rightsstring, acl_right_chars, NR_ACL_FLAGS+1);
return 1;
}
memset(&mailbox, '\0', sizeof(mailbox_t));
memset(&map, '\0', sizeof(struct ACLMap));
mailbox.uid = mboxid;
mailbox.owner_idnr = owner_idnr;
if ((result = db_acl_get_acl_map(&mailbox, userid, &map)) == DM_EQUERY)
return result;
if (map.lookup_flag)
g_strlcat(rightsstring,"l", NR_ACL_FLAGS+1);
if (map.read_flag)
g_strlcat(rightsstring,"r", NR_ACL_FLAGS+1);
if (map.seen_flag)
g_strlcat(rightsstring,"s", NR_ACL_FLAGS+1);
if (map.write_flag)
g_strlcat(rightsstring,"w", NR_ACL_FLAGS+1);
if (map.insert_flag)
g_strlcat(rightsstring,"i", NR_ACL_FLAGS+1);
if (map.post_flag)
g_strlcat(rightsstring,"p", NR_ACL_FLAGS+1);
if (map.create_flag)
g_strlcat(rightsstring,"c", NR_ACL_FLAGS+1);
if (map.delete_flag)
g_strlcat(rightsstring,"d", NR_ACL_FLAGS+1);
if (map.administer_flag)
g_strlcat(rightsstring,"a", NR_ACL_FLAGS+1);
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1