/* -*- LPC -*- */
/*
* $Id: permission.c,v 1.12 2003/03/21 02:25:20 ceres Exp $
*/
int add_senior( string word ) {
if ( !sizeof( filter( previous_object( -1 ), (: interactive( $1 ) :) ) ) ) {
user_event( "inform", this_player()->query_name() +
" illegally attempted to call add_senior( "+ word +
" )", "cheat" );
unguarded((: write_file, "/log/CHEAT", ctime( time() ) +
": illegal attempt to call add_senior( "+ word +
" ).\n"+ back_trace() :));
return 0;
}
if ( PLAYER_HANDLER->test_user( word ) &&
query_leader( previous_object(-1) ) ) {
write_file( "/log/PROMOTIONS", ctime( time() ) +": "+ word +
" was promoted to Senior by "+ geteuid( this_interactive() ) +
"\n" );
if ( ( positions[ word ] != TRUSTEE ) &&
( positions[ word ] != DIRECTOR ) )
positions[ word ] = SENIOR;
save_object( "/secure/master" );
return 1;
}
return 0;
} /* add_senior() */
int remove_senior(string str) {
if (!sizeof(filter(previous_object(-1), (: interactive($1) :)))) {
user_event( "inform", this_player()->query_cap_name()+
" illegally attempted to call remove_senior("+str+")",
"cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call remove_senior("+str+").\nBacktrace: "+
back_trace() :));
return 0;
}
if (query_leader(previous_object(-1)) &&
positions[str] == SENIOR) {
write_file("/log/DEMOTIONS", ctime(time())+": "+str+
" was demoted from Senior by "+geteuid(this_interactive())+
"\n");
map_delete(positions, str);
save_object("/secure/master");
return 1;
}
return 0;
} /* remove_senior() */
int add_director(string str) {
if (!sizeof(filter(previous_object(-1), (: interactive($1) :)))) {
user_event( "inform", this_player()->query_cap_name()+
" illegally attempted to call add_director("+str+")",
"cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+
": Illegal attempt to call add_director("+str+
").\nBacktrace: "+ back_trace() :));
return 0;
}
if (PLAYER_HANDLER->test_user(str) &&
query_trustee(previous_object(-1))) {
write_file("/log/PROMOTIONS", ctime(time())+": "+str+
" was promoted to Leader by "+ geteuid(this_interactive())+
"\n");
if (positions[str] != TRUSTEE)
positions[str] = DIRECTOR;
save_object("/secure/master");
return 1;
}
return 0;
}
int remove_director(string str) {
if (!sizeof(filter(previous_object(-1), (: interactive($1) :)))) {
user_event( "inform", this_player()->query_cap_name()+
" illegally attempted to call remove_director("+str+")",
"cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+
": Illegal attempt to call remove_director("+str+
").\nBacktrace: "+ back_trace() :));
return 0;
}
if (query_trustee(previous_object(-1)) &&
positions[str] == DIRECTOR) {
write_file("/log/DEMOTIONS", ctime(time())+": "+str+
" was demoted from Leader by "+geteuid(this_interactive())+
"\n");
map_delete(positions, str);
save_object("/secure/master");
return 1;
}
return 0;
}
int add_trustee(string str) {
if (!sizeof(filter(previous_object(-1), (: interactive($1) :)))) {
user_event( "inform", this_player()->query_cap_name()+
" illegally attempted to call add_tristee("+str+")",
"cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call add_trustee("+str+").\nBacktrace: "+
back_trace() :));
return 0;
}
if (PLAYER_HANDLER->test_user(str) &&
query_trustee(previous_object(-1))) {
write_file("/log/PROMOTIONS", ctime(time())+": "+str+
" was promoted to Administrator by "+
geteuid(this_interactive())+"\n");
positions[str] = TRUSTEE;
save_object("/secure/master");
return 1;
}
return 0;
}
int remove_trustee(string str) {
if (!sizeof(filter(previous_object(-1), (: interactive($1) :)))) {
user_event( "inform", this_player()->query_cap_name()+
" illegally attempted to call remove_trustee("+str+")",
"cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call remove_trustee("+str+").\nBacktrace: "+
back_trace() :));
return 0;
}
if (query_trustee(previous_object(-1)) &&
positions[str] == TRUSTEE) {
write_file("/log/DEMOTIONS", ctime(time())+": "+str+
" was demoted from Administrator by "+
geteuid(this_interactive())+"\n");
map_delete(positions, str);
save_object("/secure/master");
return 1;
}
return 0;
}
varargs mixed creator_file(string path, int author);
nomask protected int check_domain(mixed ob, string func, string path, int mask) {
object master_ob;
string master, domain, *bits = explode(path, "/") - ({ "", "." });
int ret;
if (sizeof(bits) < 2)
return (mask & READ_MASK);
domain = bits[1];
if (objectp(ob))
ob = geteuid(ob);
/* Is it the domain itself? */
if (ob == creator_file(path))
return 1;
/* Check the domain master object, if any. */
master = "/d/" + domain + "/master";
if (!(master_ob = find_object(master)) && checked_master[master]) {
return (mask & READ_MASK);
}
if (!master_ob && !checked_master[master] &&
catch(master_ob = load_object(master))) {
checked_master[master] = 1;
}
if (master_ob) {
ret = master_ob->check_permission(ob, bits, mask);
if (ret == -1) {
/* This means the path was locked. We deny access. */
return 0;
}
/* Senior Creators have access to the domains, except when explicitly
locked. */
if ((sizeof(bits) > 2) && (bits[2] != "master.c") &&
(bits[2] != "master.o") && (bits[2] != "master") && query_senior(ob)) {
return 1;
}
return (ret || (mask & READ_MASK?master_ob->valid_read(bits, ob, func):
master_ob->valid_write(bits, ob, func)));
}
return (mask & READ_MASK);
}
nomask protected int check_creator(mixed ob, string func, string path, int mask) {
string master, creator, *bits = explode(path, "/") - ({ "", "." });
object master_ob;
if (sizeof(bits) < 2)
return (mask & READ_MASK);
creator = bits[1];
if (objectp(ob))
ob = geteuid(ob);
/* Creators are not allowed to give out write perms to their dirs using
the granting system, they should write their own master object if
they want to do this. */
/* Err, why this? Why not use the standard system?
* - pf
*/
if (mask & GRANT_MASK) {
if (ob == creator) {
return 1;
} else {
return 0;
}
}
/* The mbox file is private. Only the owner can read it. */
if ((mask & READ_MASK) && sizeof(bits) >= 3 && bits[2] == "mbox" &&
file_size(sprintf("/w/%s/mbox", bits[1])) != -2)
return ob == bits[1];
/* Reading is allowed in creator dirs, and writing is allowed if it's
the owner doing it. */
if ((mask & READ_MASK) || (ob == creator_file(path)))
return 1;
/* Check the master object, if any. */
master = "/w/" + creator + "/master";
if (!(master_ob = find_object(master)) && checked_master[master])
return 0;
if (!master_ob && !checked_master[master] &&
catch(master_ob = load_object(master)))
checked_master[master] = 1;
if (master_ob)
return (master_ob->check_permission(ob, bits, mask) ||
master_ob->valid_write(bits, ob, func));
return 0;
}
/* Permision handling stuff. Originally coded by who knows who.
This now uses a system based on the previous_object() stack.
Coded by Turrican, based on code in the Nightmare mudlib.
- First working version on 7-10-96
- Hacked some more on 4-4-97 */
private int check_permission(mixed ob, string func, string path,
mapping perms, int mask) {
string tmp, euid;
int i;
mixed *stack;
if (perms && sizeof(perms) && !undefinedp(perms["all"]) &&
(perms["all"] & mask))
return 1;
if(path[0..21] == "/save/boards/lordboard" &&
base_name(ob) != "/obj/handlers/board_handler") {
catch(log_file("/d/admin/log/LORDBOARD",
"%s: ob %s player %s prev %s\n",
ctime(time())[4..18], base_name(ob),
this_player()->query_name(),
base_name(previous_object())));
}
if (unguarded_ob == ob) {
if ((tmp = base_name(ob)) == "/global/player" ||
tmp == "/global/playtester" ||
tmp == "/global/creator" ||
tmp == "/global/lord") {
if((path == "/save/players/"+ob->query_name()[0..0]+"/"+ob->query_name())
||
(path == "/save/players/"+ob->query_name()[0..0]+"/"+ob->query_name()+
".o") ||
(path == "/save/players/"+ob->query_name()[0..0]+"/"+ob->query_name()+
".o.gz") ||
(path == "/save/ramdisk/players/"+ob->query_name()[0..0]+"/"+ob->query_name()) ||
(path == "/save/ramdisk/players/"+ob->query_name()[0..0]+"/"+ob->query_name()+
".o") ||
(path == "/save/ramdisk/players/"+ob->query_name()[0..0]+"/"+ob->query_name()+
".o.gz"))
return 1;
else i = sizeof(stack = ({ ob }) + previous_object(-1));
} else if (tmp == path)
return 1;
else
i = sizeof(stack = ({ ob }));
} else if (unguarded_ob && base_name(ob) == "/secure/simul_efun") {
if (unguarded_ob == previous_object(1))
i = sizeof(stack = ({ previous_object(1) }));
else
i = sizeof(stack = ({ ob }) + previous_object(-1));
} else if (unguarded_ob) {
/* Okay, unguarded object is not the calling object. We only check
the call stack as far back as the position of the unguarded
object. */
stack = previous_object(-1);
for (i = 0; i < sizeof(stack) && stack[i] != unguarded_ob; i++)
;
i = sizeof(stack = ({ ob }) + stack[0..i]);
} else
i = sizeof(stack = ({ ob}) + previous_object(-1));
// tell_object(find_player("turrican"),
// sprintf("stack = %O, perms = %O, unguarded_ob = %O, func = %s\n",
// stack, perms, unguarded_ob, func));
while (i--) {
if (!stack[i])
return 0;
if (stack[i] == this_object())
continue;
if (objectp(stack[i])) {
if (file_name(stack[i]) == "/secure/simul_efun")
continue;
if (!(euid = geteuid(stack[i])))
return 0;
} else
euid = stack[i];
if (euid == get_root_uid())
continue;
if (query_director(euid) && (mask & READ_MASK))
continue;
if (query_trustee(euid))
continue;
if (perms) {
if (!undefinedp(perms[euid]) && (perms[euid] & mask))
continue;
/* If the path is explicitly locked, and the lock isn't overridden
by other pemissions, we deny access. */
if (!undefinedp(perms["all"]) && (perms["all"] & LOCK_MASK))
return 0;
}
/* Is this a creator directory? */
if (path[0..2] == "/w/") {
if (check_creator(stack[i], func, path, mask))
continue;
} else if(path[0..2] == "/d/") {
/* It's a domain directory. */
if (check_domain(stack[i], func, path, mask))
continue;
} else {
/* The rest of the mudlib defaults to reading allowed, unless
paths are explitcitly locked, which is handled above. */
return (mask & READ_MASK);
}
return 0;
}
return 1;
} /* check_permission() */
mixed permission_match_path(mapping m, string path) {
string p, *bits;
int i, size;
mapping found = ([]);
if (!sizeof(m)) {
return 0;
}
bits = explode(path, "/") - ({ "", "." });
p = "";
if (!undefinedp(m["/"])) {
found += m["/"];
}
size = sizeof(bits);
for (i = 0; i <= size; i++) {
if (!undefinedp(m[p])) {
mapping old = copy(found);
if (sizeof((found += m[p])) != (sizeof(old) + sizeof(m[p]))) {
string euid;
int mask;
found = old;
foreach (euid, mask in m[p]) {
if (!undefinedp(found[euid]))
found[euid] |= mask;
else
found[euid] = mask;
}
}
}
if (i < size)
p = p + "/" + bits[i];
}
if (sizeof(found)) {
return found;
} else {
return 0;
}
} /* permission_match_path() */
int valid_grant(object euid, string path, int mask) {
string domain, master, director;
int result;
object master_ob;
if (path[0] != '/')
path = "/" + path;
result = check_permission(euid, 0, path,
permission_match_path(permissions, path),
GRANT_MASK);
if (!result || (mask & (READ_MASK|WRITE_MASK)))
return result;
if (sscanf(path, "/d/%s/%*s", domain) != 2 &&
sscanf(path, "/d/%s", domain) != 1)
return 0;
master = "/d/" + domain + "/master";
if (!(master_ob = find_object(master)) && checked_master[master])
return 0;
if (!master_ob && !checked_master[master] &&
catch(master_ob = load_object(master))) {
checked_master[master] = 1;
return 0;
}
director = master->query_director();
if(!director)
director = master->query_lord();
return (query_director(previous_object(-1) + ({ euid })) &&
(member_array(director, map(previous_object(-1),
(: geteuid($1) :))) != -1));
}
mapping query_permissions() {
string *doms, master;
int i;
mapping blue, tmp;
object master_ob;
doms = get_dir("/d/");
doms -= ({ "lost+found" });
blue = ([ ]);
for (i=0;i<sizeof(doms);i++) {
master = "/d/"+doms[i]+"/master";
if (!(master_ob = find_object(master)) && checked_master[master])
continue;
if (!master_ob && !checked_master[master] &&
catch(master_ob = load_object(master))) {
checked_master[master] = 1;
continue;
}
tmp = (mapping)master_ob->query_access();
if (mapp(tmp))
blue += tmp;
}
return permissions + blue;
} /* query_permissions() */
protected int add_permission(string euid, string path, int mask) {
string *bits, master;
object master_ob;
if (path[0..2] == "/d/") {
/* A domain... */
bits = explode(path, "/");
if (sizeof(bits) >= 2) {
master = "/d/"+bits[1]+"/master";
if (!(master_ob = find_object(master)) && checked_master[master])
return 0;
if (!master_ob && !checked_master[master] &&
catch(master_ob = load_object(master))) {
checked_master[master] = 1;
return notify_fail("Failed to load master file.\n");
}
if ((mask & LOCK_MASK) &&
!sizeof(filter(previous_object(-1),
(: $(master_ob)->query_lord() == geteuid($1) :))))
return notify_fail("You are not the leader of $C$" + bits[1] +
".\n");
return (int)master_ob->add_permission(euid, path, mask);
}
}
if (!permissions[path]) {
permissions[path] = ([ euid : mask ]);
} else {
permissions[path][euid] |= mask;
}
unguarded((: save_object, "/secure/master" :));
return 1;
} /* add_permission() */
int add_read_permission(string euid, string path) {
if ( base_name(previous_object()) != "/d/admin/room/access_control" &&
base_name(previous_object()) != "/cmds/creator/perm_it") {
user_event( "inform", this_interactive()->query_cap_name()+
" illegally attempted to call add_read_permission("+euid+", "+
path+")", "cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call add_read_permission("+euid+", "+path+").\nBacktrace: "+
back_trace() :));
return 0;
}
if (add_permission(euid, path, READ_MASK)) {
write("Added read permision for "+euid+" to "+path+".\n");
return 1;
}
return 0;
} /* add_read_permission() */
int add_write_permission(string euid, string path) {
if ( base_name(previous_object()) != "/d/admin/room/access_control" &&
base_name(previous_object()) != "/cmds/creator/perm_it") {
user_event( "inform", this_player(1)->query_cap_name()+
" illegally attempted to call add_write_permission("+euid+", "+
path+")", "cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call add_write_permission("+euid+", "+path+").\n"
"Backtrace: "+ back_trace() :));
return 0;
}
if (add_permission(euid, path, WRITE_MASK)) {
write("Added write permision for "+euid+" to "+path+".\n");
return 1;
}
return 0;
} /* add_write_permission() */
int add_grant_permission(string euid, string path) {
if ( base_name(previous_object()) != "/d/admin/room/access_control" &&
base_name(previous_object()) != "/cmds/creator/perm_it") {
user_event( "inform", this_player(1)->query_cap_name()+
" illegally attempted to call add_grant_permission("+euid+", "+
path+")", "cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call add_grant_permission("+euid+", "+path+").\n"
"Backtrace: "+ back_trace() :));
return 0;
}
if (add_permission(euid, path, GRANT_MASK)) {
write("Added grant permision for "+euid+" to "+path+".\n");
return 1;
}
return 0;
} /* add_grant_permission() */
int lock_path(string path) {
if ( base_name(previous_object()) != "/d/admin/room/access_control" &&
base_name(previous_object()) != "/cmds/creator/perm_it") {
user_event("inform", this_player(1)->query_cap_name()+
" illegally attempted to call lock_path("+path+")", "cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call lock_path("+path+").\nBacktrace: "+ back_trace() :));
return 0;
}
if (add_permission("all", path, LOCK_MASK)) {
write("Restricted access for all to "+path+".\n");
return 1;
}
return 0;
} /* lock_path() */
protected int remove_permission(string euid, string path, int mask) {
string *bits, master;
object master_ob;
if (path[0..2] == "/d/") {
/* A domain... */
bits = explode(path, "/");
if (sizeof(bits) >= 2) {
master = "/d/"+bits[1]+"/master";
if (!(master_ob = find_object(master)) && checked_master[master])
return 0;
if (!master_ob && !checked_master[master] &&
catch(master_ob = load_object(master))) {
checked_master[master] = 1;
return notify_fail("Failed to load master file.\n");
}
if ((mask & LOCK_MASK) &&
!sizeof(filter(previous_object(-1),
(: $(master_ob)->query_lord() == geteuid($1) :))))
return notify_fail("You are not the lord of $C$" + bits[1] + ".\n");
return (int)master_ob->remove_permission(euid, path, mask);
}
}
if (!permissions[path] || !permissions[path][euid]) {
notify_fail("The euid \""+euid+"\" does not have any permissions to "
"remove in "+path+".\n");
return 0;
}
permissions[path][euid] &= ~mask;
if (!permissions[path][euid]) {
if (m_sizeof(permissions[path]) == 1) {
map_delete(permissions, path);
} else {
map_delete(permissions[path], euid);
}
}
unguarded((: save_object, "/secure/master" :));
return 1;
} /* remove_permission() */
int remove_read_permission(string euid, string path) {
if ( base_name(previous_object()) != "/d/admin/room/access_control" &&
base_name(previous_object()) != "/cmds/creator/perm_it") {
user_event( "inform", this_player(1)->query_cap_name()+
" illegally attempted to call remove_read_permission("+euid+
", "+path+")", "cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call remove_read_permission("+euid+", "+path+").\n"
"Backtrace: "+ back_trace() :));
return 0;
}
if (remove_permission(euid, path, READ_MASK)) {
write("Removed read permision for "+euid+" to "+path+".\n");
return 1;
}
return 0;
} /* remove_read_permission() */
int remove_write_permission(string euid, string path) {
if ( base_name(previous_object()) != "/d/admin/room/access_control" &&
base_name(previous_object()) != "/cmds/creator/perm_it") {
user_event( "inform", this_player(1)->query_cap_name()+
" illegally attempted to call remove_write_permission("+euid+
", "+path+")", "cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call remove_write_permission("+euid+", "+path+").\n"
"Backtrace: "+ back_trace() :));
return 0;
}
if (remove_permission(euid, path, WRITE_MASK)) {
write("Removed write permision for "+euid+" to "+path+".\n");
return 1;
}
return 0;
} /* remove_write_permission() */
int remove_grant_permission(string euid, string path) {
if ( base_name(previous_object()) != "/d/admin/room/access_control" &&
base_name(previous_object()) != "/cmds/creator/perm_it") {
user_event( "inform", this_player(1)->query_cap_name()+
" illegally attempted to call remove_grant_permission("+euid+
", "+path+")", "cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call remove_grant_permission("+euid+", "+path+").\n"
"Backtrace: "+ back_trace() :));
return 0;
}
if (remove_permission(euid, path, GRANT_MASK)) {
write("Removed grant permision for "+euid+" to "+path+".\n");
return 1;
}
return 0;
} /* remove_grant_permission() */
int unlock_path(string path) {
if ( base_name(previous_object()) != "/d/admin/room/access_control" &&
base_name(previous_object()) != "/cmds/creator/perm_it") {
user_event("inform", this_player(1)->query_cap_name()+
" illegally attempted to call unlock_path("+path+")", "cheat");
unguarded((: write_file, "/log/CHEAT", ctime(time())+": Illegal attempt "
"to call unlock_path("+path+").\nBacktrace: "+ back_trace() :));
return 0;
}
if (remove_permission("all", path, LOCK_MASK)) {
write("Removed access restrictions for all to "+path+".\n");
return 1;
}
return 0;
} /* unlock_path() */