melville/
melville/cmds/
melville/cmds/admin/
melville/data/
melville/data/mail/
melville/data/player/
melville/data/system/
melville/data/user/
melville/doc/functions/
melville/doc/help/
melville/inherit/
melville/log/
melville/obj/
melville/system/auto/
melville/system/player/
melville/system/user/
melville/users/
melville/users/mobydick/
melville/world/
/*
   overrides.c
   Functions in the auto object that override kfuns, usually to add
   security on file-writing operations or other sensitive kfuns.
   These functions all need to be nomask so that they cannot be
   bypassed.
   Begun by Mobydick, 5-24-94.
*/

#include <config.h>
#include <options.h>
#include <type.h>

nomask int valid_write (string file) ;
nomask int valid_read (string file) ;

static nomask void write (string str) ;
static nomask object get_object (string name) ;

private static string creator ;        /* will be set in security.c */
private static string privileges ;     /* ditto */

/*
   save_object() checks for permissions to save. Users and players may
   save to the appropriate data file. Any object can save to a file
   which has the same name as the object but ends in .dat instead of .c.
   The mailer can save to /data/mail/foo.dat if its creator is foo, not
   otherwise. The mail daemon can save to /data/mail/foo.dat for any
   value of foo.
   Other save attempts are not permitted.
   Returns 1 if the save was permitted, 0 if not.
*/


static nomask int save_object (string file) {

    string s1,s2 ;
    string obname, prefix ;
    int clonenum ;

/* Separate the file name and the clone number. */
    sscanf (object_name(this_object()),"%s#%d",obname,clonenum) ;
    if (!obname) obname = object_name(this_object()) ;
/* Users can save to /data/user. */
    if (obname==USER) {
	if (sscanf(file,USER_SAVE_DIR+"%s.dat",prefix)==1 && prefix==creator) {
	    ::save_object(file) ;
	    return 1 ;
        }
        return 0 ;
    }
/* Players can save to /data/player. */
    if (obname==PLAYER) {
	if (sscanf(file,PLAYER_SAVE_DIR+"%s.dat",prefix)==1 && prefix==creator){
	    ::save_object(file) ;
	    return 1 ;
        }
        return 0 ;
    }
/* The mailer can save to /data/mail/foo.dat if foo is its creator. */
   if (obname==MAILER && file==MAIL_DIR+creator+MAIL_EXT) {
       ::save_object(file) ;
       return 1 ;
   }
/* The mailer daemon can always save. */
   if (obname==MAIL_D) {
       ::save_object(file) ;
       return 1 ;
   }
/* Any object can save to the a file with the same name as that object
   but ending with .dat instead of .c. */
    if (sscanf(file,"%s.dat",s1)==1 && s1==obname) {
	::save_object(file) ;
        return 1 ;
    }
/* For now, no other saves allowed. */
    return 0 ;
}

/* restore_object() checks to make sure you have read permission to any
   file you restore from. This is necessary to safeguard mail. */

static nomask int restore_object (string file) {
    if (!valid_read(file)) return 0 ;
    ::restore_object(file) ;
    return 1 ;
}

/* destruct_object() overrides the destruct efun. An object may only destroy
   itself.
*/

static nomask void destruct_object (object obj) {

    object env ;

    if (obj!=this_object()) return ;
/* If we have an environment, depart therefrom. */
/* having a problem, somehow, with this_object() being zero in the
   middle of an update. Can't find it, so let's just trap for it. */
    if (!this_object()) return ;
    env=this_object()->query_environment() ;
    if (env) env->release_object(this_object()) ;
    ::destruct_object(this_object()) ;
    return ;
}

/* write_file() calls valid_write() in the previous object to make
   sure the write attempt is legal.  */

static nomask varargs int write_file (string file, string str, int offset) {
    if (!valid_write(file)) return 0 ;
    return ::write_file(file,str,offset) ;
}

/* read_file() calls valid_read() in the previous object to make
   sure the write attempt is legal.  */

static nomask varargs string read_file (string file, int offset, int size) {
    if (!valid_read(file)) return 0 ;
    return ::read_file(file,offset,size) ;
}

/* remove_file calls valid_write() to check permission.  */

static nomask int remove_file (string file) {
    if (!valid_write(file)) return 0 ;
    return ::remove_file(file) ;
}

/* So does remove_dir. */

static nomask int remove_dir (string directory) {
    if (!valid_write(directory)) return 0 ;
    return ::remove_dir(directory) ;
}

/* What a coincidence! make_dir does too! */

static nomask int make_dir (string directory) {
    if (!valid_write(directory)) return 0 ;
    return ::make_dir(directory) ;
}

/* To no one's surprise, so does rename_file. */

static nomask int rename_file (string old, string new) {
    if (!valid_write(old)) return 0 ;
    if (!valid_write(new)) return 0 ;
    return ::rename_file(old,new) ;
}

/* This masks the clone_object kfun for backward compatibility, so
   that you can send files as well as objects if you want. */

static nomask object clone_object (mixed master) {
    if (typeof(master)==T_STRING) {
        master = get_object(master) ;
    }
    return ::clone_object(master) ;
}

/* This is here to impose limits on resource usage. A call_out
   can start a function call in any object, so the auto.c object
   needs to have an rlimits() call that will be invoked in every
   object when a call_out is made. The idea is to override the
   call_out kfun, redirecting the call_out to a limit_call_out
   function that imposes the rlimits() and then sends control
   to the originally called function.
   I thank harte@xs4all.nl (Erwin Harte) for this idea.

static nomask varargs int call_out (string func, int delay, mixed args) {
write ("func is "+func+" and delay is "+delay+"\n") ;
    return ::call_out("limit_call_out", delay, func, args) ;
}

static nomask varargs int limit_call_out(string func, mixed args) {
    get_object("/system/player#12")->catch_tell("lick me, "+func+"!\n") ;
    rlimits (MAX_DEPTH; MAX_TICKS) {
        return call_other(this_object(), func, args);
    }
}
*/