/* -*- LPC -*- */
/*
* $Id: valid_write.c,v 1.10 2003/04/19 01:36:14 pinkfish Exp $
*/
/*
* This controls the write permisions for everything in the mud.
* It defaults to 0 if all else fails.
* Any permisions can be overridden by the global permision giving/
* changeing code.
*
* The master.c's in the domain and wizard dirs will be checked if
* any access is done to them. This is a very flexible system,
* but perhaps a little hard for some people to use.
*/
//#define DEBUG
#define WRITE_FILE_STATS 1
private nosave mapping write_stats;
int valid_write(string path, mixed euid, string func) {
mapping perms;
string tmp;
string *bits, rcspath;
string prev;
if (path && (path[<2..] == ",v")) {
/* No matter what, never allow direct manipulation of RCS files
* from the mudlib. If there is a problem, someone can fix it
* with the shell account.
*/
return 0;
}
if (func == "remove_file" && path[0..13] == "/save/players/") {
// Log this for now.
if (objectp(euid)) {
log_file("/d/admin/log/DELETE_PLAYER", "Deleting " +
path + " by " + file_name(previous_object()) +
"->" + call_stack(2)[0] + "\n");
} else {
log_file("/d/admin/log/DELETE_PLAYER", "Deleting " +
path + " by " + euid + " (" + file_name(previous_object()) +
"->" + call_stack(2)[0] + ")\n");
}
}
if (euid == master())
return 1;
if (path[0] != '/')
path = "/" + path;
#ifdef WRITE_FILE_STATS
// Add some statistics collection.
if(!write_stats)
write_stats = ([ ]);
if(previous_object()) {
prev = base_name(previous_object());
if(!write_stats[prev])
write_stats[prev] = ([ path : 1 ]);
else
write_stats[prev][path] += 1;
}
#endif
bits = explode(path, "/");
// Added by Ceres to do locking of files for RCS
// The checks are as follows:
// If they have an EUID and
// the file exists and
// it's not rcsout trying to do the job (that would be bad :) and
// it's not the ftp daemon and
// its not a .o file (they aren't in RCS so don't bother checking) and
// its not a log, save or player file (don't bother checking for these either
// then lets go check the RCS directory and see if it's in there.
if(euid &&
(file_size(path) > 0) &&
(!previous_object() ||
file_name(previous_object()) != "/secure/cmds/creator/rcso_ut") &&
(!objectp(euid) || file_name(euid) != "/secure/ftpd") &&
path[<2..] != ".o" &&
(bits[0] != "log" && bits[0] != "save" && bits[0] != "players") ) {
// Figure out the RCS filename and check if it exists.
if(sizeof(bits) > 2) {
rcspath = "/" + implode(bits[0..sizeof(bits)-2], "/") + "/RCS/";
} else if(sizeof(bits) == 2) {
rcspath = "/" + bits[0] + "/RCS/";
} else
rcspath = "/";
rcspath += bits[sizeof(bits)-1] + ",v";
if(file_size(rcspath) > 0) {
#ifdef DEBUG
if(stringp(euid))
tell_object(find_player("ceres"), sprintf("Checking perms: %s [%s](string)\n", rcspath, euid ));
else if(objectp(euid))
tell_object(find_player("ceres"), sprintf("Checking perms: %s [%s](object)\n", rcspath, file_name(euid )));
else
tell_object(find_player("ceres"), sprintf("Checking perms: %s [%O](unknown)\n", rcspath, euid ));
#endif
tmp = read_file(rcspath, 4, 1);
if(tmp == "locks\n") { // we've found a lock
string lockname ;
tmp = read_file(rcspath, 5, 1);
sscanf(tmp, "\t%s:", lockname);
if((objectp(euid) && euid->query_name() != lockname) ||
(stringp(euid) && euid != lockname)) {
int i, ok;
object *stack;
// Ok, so the euid doesn't match. Now we have to check the previous
// object just in case.
stack = previous_object(-1);
i = sizeof(stack);
while(--i) {
if(geteuid(stack[i]) == lockname) {
ok = 1;
}
}
if(!ok) {
// locked by someone else or no lock exists -- DENIED
#ifdef DEBUG
if(objectp(euid))
tell_object(find_player("ceres"), sprintf("Write denied to %O or %O Locked by %s\n", euid, previous_object(-1), lockname));
else
tell_object(find_player("ceres"), sprintf("Write denied to %s or %O Locked by %s\n", euid, previous_object(-1), lockname));
#endif
return 0;
} else {
#ifdef DEBUG
tell_object(find_player("ceres"), "Write allowed to "+geteuid(stack[i])+" Locked by:"+lockname +" on file "+path+"\n");
#endif
}
} else {
// continue with normal security checks.
#ifdef DEBUG
if(objectp(euid))
tell_object(find_player("ceres"), sprintf("Write allowed by %O Locked by %s\n", euid, lockname));
else
tell_object(find_player("ceres"), sprintf("Write allowed by %s Locked by %s\n", euid, lockname));
#endif
}
} else {
#ifdef DEBUG
tell_object(find_player("ceres"), "No locks found\n");
#endif
return 0;
}
}
}
// end of code added by Ceres
perms = permission_match_path(permissions, path);
return check_permission(euid, func, path, perms, WRITE_MASK);
} /* valid_write() */
mapping query_write_stats() { return copy(write_stats); }
void reset() {
write_stats = ([ ]);
read_stats = ([ ]);
}