/* // File : /std/priv.c // Purpose : This is an access checking system that is inherited by // both generic objects and file security mechanisms. // 92-05-31 : Buddha wrote it // 94-03-26 : Pallando added delete_access() */ #include <uid.h> #include <priv.h> private mapping perms; static nomask int check_access(mixed what); nomask int set_access(mixed what, int new_access); nomask int delete_access(string entry); // debugging stuff void debug(string str) { #ifdef DEBUG write(str + "\n"); #endif } // start with something pretty basic. void init_access() { if(!mapp(perms)) perms = ([ ]); } // O.K., this one returns an integer value based on the security level // in question, as defined in priv.h. It gets called by valid_write() and // valid_read(), and is passed a string such as "obj/equip/sword.c". // it will return the access for the item, or if that is unavailable, the // access for the node of the tree that it's on. static nomask int check_access(string tmp) { int i; string *parts; debug("Passed to check_access: " + tmp); init_access(); debug("past init_access()"); // okay, first check for a direct match. This will be a lot of // cases for variables, less for files. if (perms[tmp]) return perms[tmp]; // there was no match, so let's split this string up into segments. // If there is only one element in the resulting array, then we // know it's been passed already. parts = explode(tmp, "/"); // question, what to do here? For file security, it probably // means they are trying to write to /, but for variables it sounds // like they are adding a new one.... one is harmless, the other isn't. // for now, I'll assume that there is another way to lock the root // directory... it may be necessary to add a "/" entry. // This is my solution, but I suspect there's a better way where // I won't have to do this for all objects. if (sizeof(parts) == 1) { debug("Only one level depth to resolve"); if (file_name(this_object()) == "adm/newaccess") return MASTER_ONLY; else return PUBLIC; } // okay, let's look for the closest match we can find for this, // starting with things most similar and working towards root. for (i=sizeof(parts)-1;i>=0;i--) { tmp = implode(parts[0..i], "/"); debug("debug: checking for an entry for " + tmp); if(perms[tmp]) { debug("Matched " + implode(parts, "/") + " with " + tmp); return perms[tmp]; } } debug("No match, returning PUBLIC status."); return PUBLIC; } // This function will take either an access string or an array that // constitutes a path through a variable tree, and set the access for // the variable or tree segment specified. nomask int set_access(string entry, int new_access) { string eff_user; int curr_access; // first, get the identity of who is trying to change the access. if (!previous_object()) eff_user = geteuid(); else eff_user = geteuid(previous_object()); #ifdef DEBUG write(eff_user + " is trying to change access " + entry + " to " + new_access + " for " + file_name(this_object()) + "\n"); #endif // Only two euid can generally change the permissions on things. // the owner, because it makes sense, and Root, just because. if (eff_user != geteuid(this_object()) && eff_user != ROOT_UID) return 0; // now get it's protection level. // then, switch through the various types of protection. curr_access = check_access(entry); if(!intp(curr_access)) curr_access = 0; switch(curr_access) { case PUBLIC: case READ_ONLY: case OWNER_ONLY: perms[entry] = new_access; return 1; break; case LOCKED: case PRIVATE: return 0; break; case MASTER_ONLY: if (eff_user == ROOT_UID) { perms[entry] = new_access; return 1; } return 0; break; default: // the item isn't even in priv.h - probably an error perms[entry] = new_access; return 1; break; } } // delete() uses delete_access(entry) rather than set_access(entry,0) because // that is The Right Thing (tm) to do. nomask int delete_access(string entry) { string eff_user; eff_user = ( previous_object() ? geteuid( previous_object() ) : geteuid() ); if( eff_user != geteuid() && eff_user != ROOT_UID ) return 0; // Fail. map_delete( perms, entry ); } // Now, we do something that's purpose may look familiar to some of you // valid_write() and valid_read() get passed the string that represents // what is being accessed, and is also passed the object doing the action. // This way, we can ensure that nothing happens that shouldn't. // the string passed will look like a file name already, i.e. it will nomask int valid_write(string what, object act_ob) { string eff_user; int security; if (!what) return 0 ; /* a hack-o by mobydick to fix a crash */ if (!act_ob) act_ob = previous_object(); // who is this? ourself? if (!act_ob) act_ob = this_player(); if (!act_ob) { log_file("odd_errors", "no act_ob, /std/priv.c line 149"); return 0; } eff_user = geteuid(act_ob); security = check_access(what); debug("check_access ok, security level " + security + " returned."); // Okay, let's check the access situation before going further. if(!intp(security)) security = 0; switch (security) { case PUBLIC : return 1; break; case READ_ONLY : case OWNER_ONLY : if (eff_user != geteuid() && eff_user != ROOT_UID) return 0; break; case MASTER_ONLY : case LOCKED : case PRIVATE : if (eff_user != ROOT_UID) return 0; break; default : debug("default case reached."); return 0; break; } // anything that makes it to this point should be ok, right? return 1; } nomask int valid_read(string what, object act_ob) { string eff_user; int security; if (!act_ob) return 0; eff_user = geteuid(act_ob); security = check_access(what); debug("check_access ok, security level " + security + " returned."); // Okay, let's check the access situation before going further. if(!intp(security)) security = 0; switch (security) { case PUBLIC : case READ_ONLY : case MASTER_ONLY : case LOCKED : return 1; break; case OWNER_ONLY : case PRIVATE : if (eff_user != geteuid() && eff_user != ROOT_UID) return 0; break; default : debug("default case reached."); return 0; break; } // anything that makes it to this point should be ok, right? return 1; } // This function just checks with the access system and returns the // present permissions set on an attribute. int query_permission(string prop) { return check_access(prop); }