/*************************************************************************/ /* security.c v2.08 moved from player/wizard to separate object Revised August '95. Angel. */ #include <mudlib.h> #include <master.cfg> #include <player.cfg> #include <security.h> #include <levels.h> #if !defined(AMYLAAR) #define this_interactive() this_player(1) #endif /************************************************************************/ /* some function specs */ /* void remove_current_edit(string file); */ /************************************************************************/ /* 3.2 allows two people to edit same file simultaneously!! * here is a hack to stop that */ string *current_edit; /* list of files currently edited */ /* string *query_current_edit() { return current_edit; } */ status add_current_edit(string file) { string name; int i; name = capitalize((string)this_player()->query_name(1)); if(!current_edit) current_edit = ({}); if((i=member_array(file, current_edit)) != -1) { write("Warning: "+ file +" is being edited by "+ current_edit[i+1] +".\n"); return 0; /* return 0, if you want to stop editing all together */ } current_edit += ({ file, name, }); return 1; } void remove_current_edit_name (string name) { int i; if(!current_edit) current_edit = ({}); if((i = member_array(name, current_edit)) == -1) return; current_edit = current_edit[0..(i-2)] + current_edit[(i+1)..(sizeof(current_edit)-1)]; } void remove_current_edit_file (string file) { int i; if(!current_edit) current_edit = ({}); if((i = member_array(file, current_edit)) == -1) return; current_edit = current_edit[0..(i-1)] + current_edit[(i+2)..(sizeof(current_edit)-1)]; } /* master object(s) have full write access - defined in security.h */ nomask status valid_master_object(object ob) { int i; string file; file = file_name(ob); #ifdef MASTER_OBJECTS for(i = sizeof(MASTER_OBJECTS); i--; ) { if(file == MASTER_OBJECTS[i]) return 1; } #endif #ifdef MASTER_DIRECTORIES for(i = sizeof(MASTER_DIRECTORIES); i--; ) { if(sscanf("/"+ file, MASTER_DIRECTORIES[i], file) == 1) return 1; } #endif return 0; } /* path is a 'master' file */ static status master_path(string path) { int i; #ifdef MASTER_OBJECTS for(i = sizeof(MASTER_OBJECTS); i--; ) { if(path == "/"+ MASTER_OBJECTS[i] +".c") return 1; } #endif #ifdef MASTER_DIRECTORIES for(i = sizeof(MASTER_DIRECTORIES); i--; ) { if(sscanf(path, MASTER_DIRECTORIES[i], path) == 1) return 1; } #endif return 0; } /* player object(s) - defined in security.h */ nomask status restricted_path_object(object ob) { int i, n; string file; file = file_name(ob); if(!file) return 0; #ifdef RESTRICTED_PATH_OBJECTS for(i = sizeof(RESTRICTED_PATH_OBJECTS); i--; ) { if(sscanf(file, RESTRICTED_PATH_OBJECTS[i] +"#%d", n) == 1) return 1; } #endif return 0; } /* * certain paths are marked as restricted, to hold the integrity * of objects */ static status restricted_path(string file) { string *path; int i; path = RESTRICTED_PATHS; #ifdef MASTER_DIR path += MASTER_DIR; #endif /* MASTER_DIR */ for(i = sizeof(path); i--; ) { if(sscanf(file, path[i], file)) return 1; } return 0; } static void fail(string str) { if(this_player()->query_security_level() > SEC0) { write(str +"\n"); } } /****************************************************************************/ /* validate file writes */ nomask mixed valid_write(string path, object caller, string call_fun) { string domain, who, file; int i; string name; int security_level; status restricted_access, restricted_caller; restricted_caller = restricted_path_object(caller); if(this_interactive()) { name = (string)this_interactive()->query_real_name(); security_level = (int)this_interactive()->query_security_level(); } #if 1 else if(this_player() && restricted_path_object(this_player())) { name = (restricted_caller) ? (string)this_player()->query_real_name() : creator(caller); security_level = SEC0; restricted_access = 1; } else if(stringp(creator(caller))) { name = creator(caller); security_level = SEC0; restricted_access = 1; } #endif if(!path || path[0] != '/' || !caller) return 0; /* master object(s) have full write access */ if(valid_master_object(caller)) { return extract(path,1); } /* test if (unknown) object is trying to write to main lib */ if(restricted_path(path)) { if(restricted_access && restricted_caller) { if(call_fun != "save_object" || sscanf(path,"/usr/%s",file) != 1) { fail("Cannot use Restricted Access for a restricted path."); return 0; } } else if(!restricted_caller) { fail(file_name(caller) +" cannot access a Restricted Path."); return 0; } } if(master_path(path) && security_level < MASTER_SECURITY) { fail("Need Master Security Level: "+ MASTER_SECURITY); return 0; } /* allow 'name' full write access to their directories */ /* weakness - name yourself a restricted path */ if(name) { if((sscanf(path,"%s/"+ name +"/%s", who, file) == 2 || sscanf(path,"%s/"+ name +".%s", who, file) == 2) && sscanf(path,"/usr/%s", file) != 1) { if(!restricted_access /* using this_interactive() */ || creator(caller) == name /* or using your own object */ || restricted_path_object(caller)) { /* or using valid object */ return extract(path,1); } } } /* make validations for specific efuns */ switch(call_fun) { case "save_object": #if defined(MAIL_DIR) && defined(MAILER) if(sscanf(path,"/"+ MAIL_DIR +"%s", file)) { /* only mailer here */ file = file_name(caller); sscanf(file,"%s#%d",file,i); #ifdef INTERMUD if(file == "secure/UDP_CMD_DIR/mail") return extract(path,1); #endif /* INTERMUD */ if (file == MAILER) return extract(path,1); fail("Illegal Mailer Object."); return 0; } #endif /* MAILER */ return extract(path,1); break; case "ed_start": if(!restricted_caller) { fail("Illegal object using ed()"); return 0; } /* remove_current_edit(path); */ break; case "mkdir": if(!restricted_caller) { fail("Illegal Object using mkdir()"); return 0; } /* Domain, promote stuff */ /* Necassary to make sure Access objects are automatically made! */ if(sscanf(path,DOMAIN_DIR +"%s",domain) == 1) { if(sscanf(domain,"%s/%s",domain,file) != 2) { write("Use 'domain' command to make a New Domain.\n"); return 0; /* only create_wizard() fn can add domain creators */ } if(sscanf(path,DOMAIN_DIR +"%s/w/%s",domain,file) == 2) { if(sscanf(file,"%s/%s",who,file) != 2) { write("Use 'domain' command to add a New Creator Directory.\n"); return 0; /* only create_wizard() fn can add domain creators */ } } } if(sscanf(path,WIZARD_DIR +"%s", file) == 1) { if(sscanf(file,"%s/%s",who,file) != 2) { write("Use 'promote' command to add a New Creator Directory.\n"); return 0; /* only create_wizard() fn can add creators */ } } break; case "write_file": if(sscanf(path,"/log/%s",file)) { return extract(path,1); } case "cindent": case "rmdir": case "do_rename": case "remove_file": case "write_bytes": break; } switch(security_level) { case SEC9: case SEC8: return extract(path,1); case SEC7: if(sscanf(path, WIZARD_DIR +"%s/private/%s", who, file) == 2 || sscanf(path, "/inherit/base/%s", file) == 1 || sscanf(path, SHADOW_DIR, file) == 1) { break; } if(sscanf(path, WIZARD_DIR +"%s/%s", who, file) == 2 || sscanf(path, DOMAIN_DIR +"%s/w/%s/%s", domain, who, file) == 3 #ifndef 312MASTER /* /obj, /room save_object() -> /usr */ || sscanf(path, "/obj/%s", file) == 1 #endif || sscanf(path, "/function/%s", file) == 1 || sscanf(path, "/inherit/%s", file) == 1 || sscanf(path, "/objects/%s", file) == 1) { return extract(path,1); } case SEC6: if(sscanf(path, "/doc/helpdir/%s", file) == 1) { return extract(path,1); } case SEC5: #ifndef 312MASTER /* /room, /obj can save_object() -> /usr */ if(sscanf(path, "/room/post/%s", file) == 1) { break; } if(sscanf(path, "/room/%s", file) == 1) { return extract(path,1); } #endif case SEC4: if(sscanf(path, "/bin/%s", who) == 1 || sscanf(path, "/skills/%s", file) == 1) { return extract(path,1); } case SEC3: case SEC2: case SEC1: case SEC0: break; default: write("Error: Unknown Security Level.\n"); } #ifdef SC if(path == SOUL_FUNC_FILE) { if(member_array(name, SC) != -1) { return extract(path,1); } } #endif /* SC */ /* Open Write Files */ if(sscanf(path, "%s/open/%s", who, file) == 2 || sscanf(path, "/ideas/%s", file) == 1) { return extract(path,1); } if(sscanf(path, WIZARD_DIR +"%s/%s", who, file) == 2 && sscanf(path, "%s/private/%s", who, file) != 2) { if(file != "access.c") { if(call_other(WIZARD_DIR+who+"/access","valid_write",path,name)) { return extract(path,1); } } } if(sscanf(path, DOMAIN_DIR +"%s", file) == 1) { if(file != "access.c") { if(call_other(DOMAIN_DIR +"/access", "valid_write",path,name)) { return extract(path,1); } } } return 0; } /**********************************************************************/ /* validate file reads */ nomask mixed valid_read(string path, object caller, string call_fun) { string domain, who, file; string name; int security_level; mixed *error; status restricted_caller; int i; restricted_caller = restricted_path_object(caller); if(this_interactive()) { name = (string)this_interactive()->query_real_name(); security_level = (int)this_interactive()->query_security_level(); } #if 1 else if(this_player() && restricted_path_object(this_player())) { name = (string)this_player()->query_real_name(); security_level = SEC0; } else if(stringp(creator(caller))) { name = creator(caller); security_level = SEC0; } #endif #if 0 /* amylaar can use this, but mudlib handles it better */ if(!path) { if(call_fun == "ed_start") { error = get_error_file((string)this_player()->query_real_name()); if(!error || error[3]) { write("No error.\n"); return 0; } write(extract(error[0],1)+" line "+error[1]+": "+error[2]+"\n"); return error[0]; } return 0; } #else if(!path) return 0; #endif /* AMYLAAR */ if(path[0] != '/' || !caller) return 0; if(valid_master_object(caller)) { return extract(path,1); } switch(call_fun) { case "restore_object": #if defined(MAIL_DIR) && defined(MAILER) if(sscanf(path,MAIL_DIR +"%s",file)) { file = file_name(caller); sscanf(file,"%s#%d",file,i); #ifdef INTERMUD if(file == "secure/UDP_CMD_DIR/mail") return 1; #endif if(file != MAILER) { fail("Illegal Mailer Object"); return 0; } } #endif /* MAILER */ return 1; break; case "file_size": return extract(path,1); break; case "tail": case "cat": case "read_bytes": case "read_file": if(member_array(path, OPEN_FILES) != -1) { return extract(path,1); } break; case "ed_start": if(!restricted_caller) { fail("Illegal Object using ed()"); return 0; } /* if(!add_current_edit(path)) return 0; /* someone is already editing */ break; #ifdef MUDOS_DR case "stat": case "load_time": #endif case "file_time": case "get_dir": if(restricted_caller) { return extract(path,1); } break; case "do_rename": case "print_file": break; } #if 0 if ((file = valid_write(path, caller, 0))) { return file; } #endif if(name) { if((sscanf(path,"%s/"+ name +"/%s", who, file) == 2 || sscanf(path,"%s/"+ name +".%s", who, file) == 2 || sscanf(path,"%s/"+name,file) == 1) && sscanf(path,"/usr/%s", file) != 1) { return extract(path,1); } } if(member_array(path, OPEN_FILES) != -1) { return extract(path,1); } #ifdef QC if(sscanf(path, "%s/private/%s", who, file) != 2) { if(member_array(name,QC) != -1) { return extract(path,1); } } #endif /* QC */ switch(security_level) { case SEC9: case SEC8: return extract(path,1); case SEC7: case SEC6: if(sscanf(path, "%s/private/%s", who, file) == 2 || sscanf(path, "/room/post/%s", file) == 1) { break; } return extract(path,1); case SEC5: case SEC4: case SEC3: if(sscanf(path, "/room/post/%s", file) == 1 || sscanf(path, "%s/private/%s", who, file) == 2) { break; } if(sscanf(path, "/inherit/%s", file) == 1 || sscanf(path, "/obj/%s", file) == 1 || sscanf(path, "/function/%s", file) == 1 || sscanf(path, "/inherit/%s", file) == 1 || sscanf(path, "/objects/%s", file) == 1 || sscanf(path, "/doc/%s", file) == 1 || sscanf(path, "/room/%s", file) == 1 || sscanf(path, "/bin/%s", who) == 1 || sscanf(path, "/skills/%s", file) == 1) { return extract(path,1); } case SEC2: case SEC1: if(sscanf(path, "/room/post/%s", file) == 1 || sscanf(path, "%s/private/%s", who, file) == 2) { break; } if (sscanf(path, "/ideas/%s", file) == 1 || sscanf(path, "/doc/%s", file) == 1 || sscanf(path, "/log/%s", file) == 1 || sscanf(path, "/info/%s", file) == 1 || sscanf(path, "/inherit/%s", file) ==1 || sscanf(path, "/room/%s", file) == 1 || sscanf(path, "/manuals/%s", file) == 1 || sscanf(path, "/objects/%s", file) == 1) { return extract(path,1); } case SEC0: if(sscanf(path, "/room/post/%s", file) == 1 || sscanf(path, "%s/private/%s", who, file) == 2) { break; } if (sscanf(path, "%s/open/%s", who, file) == 2 || sscanf(path, "/manuals/%s", file) == 1 || sscanf(path, "/help/%s", file) == 1 || sscanf(path, "/info/%s", file) == 1 || sscanf(path, "/news/%s", file) == 1 || sscanf(path, "%s.dat", file) == 1) { return extract(path,1); } break; default: write("Error: Unknown Security Level.\n"); } if(sscanf(path, WIZARD_DIR +"%s/%s", who, file) == 2) { if(call_other(WIZARD_DIR+who+"/access","valid_read",path,name)) { return extract(path,1); } } if(sscanf(path, DOMAIN_DIR +"%s", file) == 1) { if(call_other(DOMAIN_DIR +"/access", "valid_read",path,name)) { return extract(path,1); } } return 0; }