/* /adm/obj/master.c * from Nightmare 3.3 * the master object, responsible for security * created by Descartes of Borg 940910 * error handling by Beek@The Idea Exchange 941004 */ #include <config.h> #include <rooms.h> #include <cfg.h> #include <lib.h> #include <objects.h> #include <privs.h> #include <dirs.h> #include <save.h> #include <daemons.h> #include <commands.h> #include "master.h" private static object Unguarded; private static string PlayerName; private static object NewPlayer; private static mapping Groups, ReadAccess, WriteAccess; void create() { Unguarded = 0; NewPlayer = 0; PlayerName = 0; new_read(); new_write(); new_groups(); } void new_read() { mapping tmp; tmp = ([]); load_access(CFG_READ, tmp); ReadAccess = tmp; } void new_write() { mapping tmp; tmp = ([]); load_access(CFG_WRITE, tmp); WriteAccess = tmp; } void new_groups() { mapping tmp; tmp = ([]); load_access(CFG_GROUPS, tmp); Groups = tmp; } private static void load_access(string cfg, mapping ref) { string *lines; string file, fl, ac; int i, maxi; if(!(file = read_file(cfg))) error("Failed to find config file: "+cfg); maxi = sizeof(lines = explode(file, "\n")); for(i=0; i<maxi; i++) { if(!lines[i] || lines[i] == "" || lines[i][0] == '#') continue; if(sscanf(lines[i], "(%s) %s", fl, ac) != 2) error("Error in loading config file "+cfg+" at line "+ (i+1)); ref[fl] = explode(ac, ":"); } } void flag(string str) { string file, arg; int i, x; if(previous_object()) return; if(sscanf(str, "for %d", x) == 1) { for(i=0; i<x; i++) {} return; } if(sscanf(str, "call %s %s", file, arg)) { write("Got "+(string)call_other(file, arg)+" back.\n"); return; } write("Master: unknown flag.\n"); } string *epilog(int x) { string *lines, *files; string content; int i; if(!(content = read_file(CFG_PRELOAD))) return ({}); i = sizeof(lines = explode(content, "\n")); files = ({}); while(i--) { if(!lines[i] || lines[i] == "" || lines[i][0] == '#') continue; files += ({ lines[i] }); } return files; } string privs_file(string file) { string nom = 0; int ext; file = "/" + file; #ifdef PLAYERS if( !strsrch(file, DIR_PLAYERS) ) sscanf(file, DIR_PLAYERS "/%*s/%s", nom); else #endif if( !strsrch(file, DIR_CRES) ) sscanf(file, DIR_CRES "/%*s/%s", nom); if( nom ) { if( file == DIR_CRES + "/" + nom[0..0] +"/"+ nom) { string *grps; string str; int i; str = nom; i = sizeof(grps = keys(Groups)); while(i--) if(member_array(nom, Groups[grps[i]]) != -1) str = str + ":" + grps[i]; //tc("privs_file("+file+"): "+str): return str; } #ifdef PLAYERS else if(file == DIR_PLAYERS+"/" + nom[0..0] + "/" + nom){ //tc("privs_file("+file+"): "+nom): return nom; } #endif else{ //tc("privs_file("+file+"): 0"); return 0; } } return file_privs(file); } void preload(string str) { string err; int t; if( !file_exists(str + ".c") ) return; t = time(); write("Preloading: " + str + "..."); if( err = catch(call_other(str, "???")) ) write("\nGot error "+err+" when loading "+str+".\n"); else { t = time() - t; write("("+(t/60)+"."+(t%60)+")\n"); } } int valid_write(string file, object ob, string fun) { string *ok; if( ob == master() ) return 1; if( file[0] != '/' ) file = "/"+file; ok = match_path(WriteAccess, file); return check_access(ob, fun, file, ok, "write"); return 0; } int valid_read(string file, object ob, string fun) { string *ok; if( ob == master() ) return 1; if( file[0] != '/' ) file = "/"+file; ok = match_path(ReadAccess, file); return check_access(ob, fun, file, ok, "read"); } int valid_apply(string *ok) { return check_access(previous_object(1),0,previous_object(0), ok, "apply"); } int check_access(object ob, string fun, mixed file, string *ok, string oper) { object *stack; string *privs; string priv; int i; //tc("check_access("+identify(ob)+", "+identify(fun)+", "+ //identify(file)+", "+identify(ok)+", "+identify(oper)+ //")"); if( objectp(file) ) file = base_name(file); if( ok && sizeof(ok) && ok[0] == "all" ) return 1; if( Unguarded == ob ) { string tmp; #ifdef PLAYERS if( (tmp = base_name(ob)) == LIB_PLAYER || tmp == LIB_CREATOR) { #else if( (tmp = base_name(ob)) == LIB_CREATOR ) { #endif if( !PlayerName ) i = sizeof(stack = ({ob})+previous_object(-1)); #ifdef PLAYERS else if( file == DIR_PLAYERS+"/"+PlayerName[0..0]+"/"+ PlayerName + __SAVE_EXTENSION__ ) return 1; #endif else if( file == DIR_CRES+"/"+PlayerName[0..0]+"/"+ PlayerName + __SAVE_EXTENSION__ ) return 1; else i = sizeof(stack = ({ ob })); } else if( tmp + __SAVE_EXTENSION__ == file ) return 1; else i = sizeof(stack = ({ ob })); } else if(Unguarded && base_name(ob) == SEFUN) { if(Unguarded == previous_object(1)) stack = ({ previous_object(1) }); else stack = ({ ob }) + previous_object(-1); } else i = sizeof(stack = previous_object(-1) + ({ ob })); while(i--) { if(!stack[i] || stack[i] == this_object()) continue; if(file_name(stack[i]) == SEFUN) continue; if(!(priv = query_privs(stack[i]))){ //tc("query_privs("+identify(stack[i])+") failed."); return 0; } if(!ok && oper == "read") continue; privs = explode(priv, ":"); if(member_array(PRIV_SECURE, privs) != -1) continue; if(member_array(file_privs(file), privs) != -1) continue; if(!ok && oper == "write") { if(userp(stack[i]) && check_user(stack[i], fun, file, oper)) continue; else { //tc("check_user("+identify(stack[i])+", "+ //identify(fun)+", "+identify(file)+ //","+identify(oper)+") failed."); return 0; } } if(sizeof(privs & ok)) continue; if(userp(stack[i]) && check_user(stack[i], fun, file, oper)) continue; if(userp(stack[i]) && check_domain(stack[i], fun, file,oper)) continue; return 0; } return 1; } nomask static int check_user(object ob, string fun, string file, string oper) { string nom, achar; int x; #ifdef SUB_REALMS if( sscanf(file, REALMS_DIRS "/%s/%s/%*s", achar, nom) != 2 ) return 0; #else if( !sscanf(file, REALMS_DIRS "/%s/%*s", nom) ) return 0; #endif nom = user_path(nom)+"adm/access"; if(file_size(nom+".c") < 0) return 0; catch(x = (int)call_other(nom, "check_access", ob, fun, file, oper)); return x; } nomask static int check_domain(object ob, string fun, string file, string o) { string nom; int x; if(!sscanf(file, DOMAINS_DIRS+"/%s/%*s", nom)) return 0; nom = DOMAINS_DIRS+"/"+nom+"/adm/access"; if(file_size(nom+".c") < 0) return 0; catch(x = (int)call_other(nom, "check_access", ob, fun, file, o)); return x; } object connect() { object ob; string err; if(err=catch(ob = clone_object(OB_LOGIN))) { write("It looks like someone is working on the user object.\n"); write(err); destruct(ob); } return ob; } object compile_object(string str) { string nom, tmp, where, which, achar; object ob; #ifdef SUB_REALMS if( sscanf(str, REALMS_DIRS "/%s/%s/%*s", achar, nom) == 2 ) #else if(sscanf(str, REALMS_DIRS+"/%s/%*s", nom)) #endif tmp = sprintf("%svirtual/server", user_path(nom)); else if(sscanf(str, DOMAINS_DIRS+"/%s/%*s", nom)) tmp = sprintf("%s/%s/virtual/server", DOMAINS_DIRS, nom); #ifdef PLAYERS else if(sscanf(str, DIR_PLAYERS+"/%*s/%s", nom)) { if(!NewPlayer) return 0; if((string)NewPlayer->GetKeyName() != nom) return 0; PlayerName = nom; ob = new(LIB_PLAYER); if(file_size(str+__SAVE_EXTENSION__) > 0) ob->restore_player(nom); else if(file_size(DIR_PLAYERS) != -2) mkdir(DIR_PLAYERS); else if(file_size(DIR_PLAYERS+"/"+nom[0..0]) != -2) mkdir(DIR_PLAYERS+"/"+nom[0..0]); ob->SetKeyName(nom); PlayerName = 0; return ob; } #endif else if( sscanf(str, DIR_CRES+"/%*s/%s", nom) ) { if(!NewPlayer) return 0; if((string)NewPlayer->GetKeyName() != nom) return 0; PlayerName = nom; ob = new(LIB_CREATOR); if(file_size(str+__SAVE_EXTENSION__) > 0) ob->restore_player(nom); else if(file_size(DIR_CRES) != -2) mkdir(DIR_CRES); else if(file_size(DIR_CRES "/" + nom[0..0]) != -2) mkdir(DIR_CRES "/" + nom[0..0]); ob->SetKeyName(nom); PlayerName = 0; return ob; } if(file_size(tmp+",c") < 0) { if(sscanf(str, "%s.%s", where, which) != 2) return 0; #ifdef SUB_REALMS if( sscanf(str, REALMS_DIRS "/%s/%s/%*s", achar, nom) == 2 ) #else if(sscanf(str, REALMS_DIRS+"/%s/%*s", nom)) #endif tmp = sprintf("%svirtual/%s_server", user_path(nom), which); else if(sscanf(str, DOMAINS_DIRS+"/%s/%*s", nom)) tmp = sprintf("%s/%s/virtual/%s_server", DOMAINS_DIRS, nom, which); if(file_size(tmp+".c") < 0) return 0; else return (object)call_other(tmp, "compile_object", where); } return (object)call_other(tmp, "compile_object", str); } static void crash(string err) { write_file(DIR_LOGS "/crashes", mud_name() + " crashed " + ctime(time()) + " with error " + err+".\n"); message("system", "Reality implosion!!! Everyone duck!!!", users()); message("system", "You are being forced to quit.", users()); users()->cmdQuit(); } int valid_bind(object binder, object old_owner, object new_owner) { if( member_array(PRIV_SECURE, explode(query_privs(new_owner), ":")) != -1) return 0; if( binder == master() ) return 1; if( member_array(PRIV_SECURE, explode(query_privs(binder), ":")) != -1 ) return 1; return 0; } int valid_hide(object who) { string priv; if(!objectp(who)) return 0; if(environment(who) && hiddenp(environment(who))) return 1; if(!(priv = query_privs(who))) return 0; else return (member_array(PRIV_SECURE, explode(priv, ":")) != -1); } int valid_override(string file, string nom) { return (file[0..6] == "/secure"); } int valid_shadow(object ob) { return (!virtualp(ob) && !strsrch(file_name(ob), DIR_SHADOWS)); } int valid_object(object ob) { string file; file = file_name(ob); if( !strsrch(file, DIR_TMP) ) return 0; else if( !strsrch(file, DIR_FTP) ) return 0; else if( !strsrch(file, DIR_LOGS) ) return 0; else return 1; } int valid_socket(object ob, string fun, mixed *info) { object *obs; string tmp; int i; i = sizeof(obs = previous_object(-1)); while(i--) { if( !obs[i] ) continue; if( userp(obs[i]) ) continue; if( !(tmp = query_privs(obs[i])) ) return 0; if( !sizeof(explode(tmp, ":") & ({ PRIV_SECURE, PRIV_MUDLIB, PRIV_GENERAL, PRIV_CMDS })) ) return 0; } return 1; } mixed apply_unguarded(function f) { object previous_unguarded; string base, err, tmp; mixed val; if(base_name(previous_object(0)) != SEFUN) { error("Illegal unguarded apply."); return 0; } previous_unguarded = Unguarded; Unguarded = previous_object(1); err = catch(val = (mixed)(*f)()); Unguarded = previous_unguarded; if(err) error(err); return val; } string error_handler(mapping mp, int caught) { string ret, file; ret = "---\n" + standard_trace(mp); if( caught ) write_file(file = "/log/catch", ret); else write_file(file = "/log/runtime", ret); if( this_player(1) ) { if( find_object(SEFUN) && creatorp(this_player(1)) ) { message("error", mp["error"] + "Trace written to " + file, this_player(1)); this_player(1)->SetLastError(mp); } } return 0; } void log_error(string file, string msg) { string nom, home, tmp, achar; if( this_player(1) ) { if( find_object(SEFUN) && creatorp(this_player(1)) ) message("error", msg, this_player(1)); } if( file[0] != '/' ) file = "/"+file; #ifdef SUB_REALMS if( sscanf(file, REALMS_DIRS "/%s/%s/%s", achar, nom, tmp) != 3 && #else if( sscanf(file, REALMS_DIRS+"/%s/%s", nom, tmp) != 2 && #endif sscanf(file, DOMAINS_DIRS+"/%s/%s", nom, tmp) != 2 ) sscanf(file, "/%s/%s", nom, tmp); if( !nom ) nom = "log"; catch(write_file(DIR_ERROR_LOGS "/" + nom, msg)); } varargs string standard_trace(mapping mp, int flag) { string obj, ret; mapping *trace; int i,n; ret = mp["error"] + "Object: " + trace_line(mp["object"], mp["program"], mp["file"], mp["line"]); ret += "\n"; trace = mp["trace"]; n = sizeof(trace); for (i=0; i<n; i++) { if( flag ) ret += sprintf("#%d: ", i); ret += sprintf("'%s' at %s", trace[i]["function"], trace_line(trace[i]["object"], trace[i]["program"], trace[i]["file"], trace[i]["line"])); } return ret; } string trace_line(object obj, string prog, string file, int line) { string ret; string objfn = obj ? file_name(obj) : "<none>"; ret = objfn; if( different(objfn, prog) ) ret += sprintf(" (%s)", prog); if( file != prog ) ret += sprintf(" at %s:%d\n", file, line); else ret += sprintf(" at line %d\n", line); return ret; } int different(string fn, string pr) { int tmp; sscanf(fn, "%s#%d", fn, tmp); fn += ".c"; return (fn != pr) && (fn != ("/" + pr)); } void master_log_file(string file, string msg) { if(file_name(previous_object()) != SEFUN) return; if(file_size(file) > MAX_LOG_SIZE) rename(file, file+".old"); write_file(file, msg); } string make_path_absolute(string file) { return absolute_path((string)this_player()->query_cwd(), file); } int player_exists(string nom) { string str; if( !nom ) return 0; str = DIR_PLAYERS "/" + nom[0..0] + "/" + nom + __SAVE_EXTENSION__; if( file_size(str) > -1 ) return 1; str = DIR_CRES "/" + nom[0..0] + "/" + nom + __SAVE_EXTENSION__; return (file_size(str) > -1); } string domain_file(string str) { string nom, tmp; if(str[0] != '/') str = "/"+str; if(sscanf(str, DOMAINS_DIRS+"/%s/%s", nom, tmp) == 2) return nom; return 0; } string author_file(string str) { string nom, tmp, achar; if(str[0] != '/') str = "/"+str; #ifdef SUB_REALMS if( sscanf(str, REALMS_DIRS "/%s/%s/%s", achar, nom, tmp) == 3 ) return nom; #else if(sscanf(str, REALMS_DIRS+"/%s/%s", nom, tmp) == 2) return nom; #endif return 0; } static int slow_shutdown() { write_file(DIR_LOGS "/audit", "Armageddon loaded by master: "+ctime(time())+".\n"); EVENTS_D->eventRebootMud(2); return 1; } int save_ed_setup(object who, int code) { string file; if(!intp(code)) return 0; rm(file = user_path((string)who->GetKeyName())+".edrc"); return write_file(file, code+""); } int retrieve_ed_setup(object who) { string file; int x; file = user_path((string)who->GetKeyName())+".edrc"; if(!file_exists(file)) return 0; return to_int(read_file(file)); } string get_save_file_name(string file) { string str; str = (string)this_player()->GetKeyName(); if(file_size(user_path(str)) == -2) return user_path(str)+"dead.edit"; else return DIR_TMP+"/"+str+".dead.edit"; } int is_locked() { return MUD_IS_LOCKED; } string *parse_command_id_list() { return ({ "one", "thing" }); } string *parse_command_plural_id_list() { return ({ "ones", "things","them"}); } string *parse_command_adjectiv_id_list() { return ({ "the", "an", "a" }); } string *parse_command_prepos_list() { return ({ "in", "with", "without", "into", "for", "on", "under", "from", "between", "at", "to", "over", "near" }); } string parse_command_all_word() { return "all"; } void create_save() { string str; if(!stringp(str = (string)previous_object()->GetKeyName())) return; #ifdef PLAYERS if(file_size(DIR_PLAYERS+"/"+str[0..0]) == -2) return; if(str[0] < 'a' || str[0] > 'z') return; mkdir(DIR_PLAYERS+"/"+str[0..0]); #else if( file_size(DIR_CRES "/" + str[0..0]) == -2) return; if( str[0] < 'a' || str[0] > 'z' ) return; mkdir(DIR_CRES "/" + str[0..0]); #endif } object player_object(string nom) { object ob; string err, tmp; int old_limit; tmp = base_name(ob = previous_object()); if( tmp != CMD_ENCRE && tmp != CMD_DECRE && tmp != OB_LOGIN ) return 0; old_limit = max_eval_cost(); set_eval_limit(1000000000); NewPlayer = ob; #ifdef PLAYERS if(file_size(DIR_CRES + "/" + nom[0..0]+ "/" +nom+__SAVE_EXTENSION__) > -1) #endif err = catch(ob = load_object(DIR_CRES+"/"+nom[0..0]+"/"+nom)); #ifdef PLAYERS else err = catch(ob = load_object(DIR_PLAYERS+"/"+nom[0..0]+"/"+nom)); #endif NewPlayer = 0; set_eval_limit(old_limit); if(err) error(err); return ob; } string player_save_file(string nom) { string tmp; tmp = DIR_CRES + "/" + nom[0..0] + "/" + nom; #ifdef PLAYERS if( file_size(tmp + __SAVE_EXTENSION__) > -1 ) return tmp; else return DIR_PLAYERS + "/" + nom[0..0] + "/" + nom; #else return tmp; #endif } string *query_group(string grp) { return copy(Groups[grp]); } mapping query_groups() { return copy(Groups); } int valid_save_binary() { return 1; }