# include <kernel/kernel.h>
# include <kernel/access.h>
# include <type.h>
mapping uaccess; /* user access */
mapping gaccess; /* read access under /usr for everyone */
/*
* NAME: create()
* DESCRIPTION: initialize the access daemon
*/
static void create()
{
uaccess = ([ ]);
gaccess = ([ ]);
catch {
restore_object(ACCESSDATA);
}
}
/*
* NAME: filter_from_file()
* DESCRIPTION: filter access from a file
*/
private mapping filter_from_file(mapping access, string file)
{
if (file == "/") {
return access;
}
return access[file .. file] +
(access[file + "/" .. file + "0"] - ({ file + "0" }));
}
/*
* NAME: filter_to_file()
* DESCRIPTION: filter access to a file
*/
private mapping filter_to_file(mapping access, string file)
{
mapping result;
string *path;
int i, sz, type;
if (file == "/") {
/* special case */
return ([ "/" : access["/"] ]);
}
result = ([ ]);
path = explode(file, "/");
file = "";
for (i = 0, sz = sizeof(path); i < sz; i++) {
file += "/" + path[i];
result[file] = access[file];
}
return result;
}
/*
* NAME: access()
* DESCRIPTION: check access
*/
int access(string user, string file, int type)
{
if (KERNEL()) {
string dir, str, *path;
mixed access;
int i, sz;
sscanf(file, USR + "/%s/%s/", dir, str);
if (type == READ_ACCESS && (!dir || gaccess[dir] || str == "open") &&
sscanf(file, "/kernel/data/%*s") == 0) {
/*
* read access outside /usr, in /usr/foo/open and in selected
* other directories in /usr
*/
return TRUE;
}
if (user == dir ||
(user && sscanf(user, USR + "/%s/", str) != 0 && str == dir)) {
/*
* full access to own/owner directory
*/
return TRUE;
}
if (user == "admin") {
/*
* admin always has access (hardcoded)
*/
return TRUE;
}
/*
* check special access
*/
access = uaccess[user];
if (typeof(access) == T_MAPPING) {
if (access["/"] && access["/"] >= type) {
return TRUE;
}
path = explode(file, "/");
file = "";
for (i = 0, sz = sizeof(path) - 1; i < sz; i++) {
file += "/" + path[i];
if (access[file] && access[file] >= type) {
return TRUE;
}
}
}
}
return FALSE;
}
/*
* NAME: add_user()
* DESCRIPTION: add a new user
*/
void add_user(string user)
{
if (previous_program() == API_ACCESS && !uaccess[user]) {
rlimits (-1; -1) {
uaccess[user] = TRUE;
# ifndef SYS_PERSISTENT
save_object(ACCESSDATA);
# endif
}
}
}
/*
* NAME: remove_user()
* DESCRIPTION: remove a user
*/
void remove_user(string user)
{
if (previous_program() == API_ACCESS) {
if (uaccess[user]) {
rlimits (-1; -1) {
string *users;
mixed *values, access;
int i;
uaccess[user] = nil;
users = map_indices(uaccess);
values = map_values(uaccess);
user = USR + "/" + user;
for (i = sizeof(values); --i >= 0; ) {
access = values[i];
if (typeof(access) == T_MAPPING) {
access = filter_from_file(access, user);
if (map_sizeof(access) != 0) {
uaccess[users[i]] -= map_indices(access);
}
}
}
# ifndef SYS_PERSISTENT
save_object(ACCESSDATA);
# endif
}
}
}
}
/*
* NAME: query_users()
* DESCRIPTION: return list of users
*/
string *query_users()
{
if (KERNEL()) {
return map_indices(uaccess);
}
}
/*
* NAME: set_access()
* DESCRIPTION: set access
*/
void set_access(string user, string file, int type)
{
if (previous_program() == API_ACCESS) {
mixed access, *indices;
int i;
access = uaccess[user];
if (!access) {
error("No such user");
}
rlimits (-1; -1) {
if (type != 0) {
/*
* add access
*/
if (access(user, file + "/", type)) {
return; /* access already exists */
}
if (typeof(access) != T_MAPPING) {
/* first special access for this user */
uaccess[user] = ([ file : type ]);
} else {
/* remove existing lesser access */
indices = map_indices(filter_from_file(access, file));
for (i = sizeof(indices); --i >= 0; ) {
if (access[indices[i]] <= type) {
access[indices[i]] = nil;
}
}
/* set access */
access[file] = (type != 0) ? type : nil;
}
} else if (typeof(access) == T_MAPPING) {
/*
* remove access
*/
if (!access[file]) {
/* remove all subdir access */
indices = map_indices(filter_from_file(access, file));
for (i = sizeof(indices); --i >= 0; ) {
access[indices[i]] = nil;
}
} else {
/* remove specific access */
access[file] = nil;
}
if (map_sizeof(access) == 0) {
uaccess[user] = TRUE;
}
}
# ifndef SYS_PERSISTENT
save_object(ACCESSDATA);
# endif
}
}
}
/*
* NAME: query_user_access()
* DESCRIPTION: get all access for a user
*/
mapping query_user_access(string user)
{
if (previous_program() == API_ACCESS) {
mixed access;
access = uaccess[user];
return (typeof(access) == T_MAPPING) ? access[..] : ([ ]);
}
}
/*
* NAME: query_file_access()
* DESCRIPTION: get all access to a file
*/
mapping query_file_access(string file)
{
if (previous_program() == API_ACCESS) {
mapping result;
mixed *values, access;
string *users;
int i, sz;
result = ([ ]);
users = map_indices(uaccess);
values = map_values(uaccess);
for (i = 0, sz = sizeof(values); i < sz; i++) {
access = values[i];
if (typeof(access) == T_MAPPING) {
access = filter_to_file(access, file);
if (map_sizeof(access) != 0) {
result[users[i]] = access;
}
}
}
return result;
}
}
/*
* NAME: set_global_access()
* DESCRIPTION: set global read access for a directory
*/
void set_global_access(string dir, int flag)
{
if (previous_program() == API_ACCESS) {
rlimits (-1; -1) {
gaccess[dir] = (flag != 0) ? flag : nil;
# ifndef SYS_PERSISTENT
save_object(ACCESSDATA);
# endif
}
}
}
/*
* NAME: query_global_access()
* DESCRIPTION: return the directories under /usr where everyone has read
* access
*/
string *query_global_access()
{
if (previous_program() == API_ACCESS) {
return map_indices(gaccess);
}
}