psyced/world/net/library/sandbox.c

327 lines
8.1 KiB
C

// vim:foldmethod=marker:syntax=lpc:noexpandtab
// $Id: sandbox.c,v 1.16 2008/02/06 12:16:16 lynx Exp $
#include <net.h>
#include <sandbox.h>
#if __EFUN_DEFINED__(shutdown)
MASK(shutdown, "SHUTDOWN")
#endif
#if __EFUN_DEFINED__(add_action)
MASK(add_action, "ADD_ACTION")
#endif
#if __EFUN_DEFINED__(break_point)
MASK(break_point, "BREAK_POINT")
#endif
#if __EFUN_DEFINED__(call_direct)
MASK(call_direct, "CALL_DIRECT")
#endif
#if __EFUN_DEFINED__(call_direct_resolved)
MASK(call_direct_resolved, "CALL_DIRECT_RESOLVED")
#endif
#if __EFUN_DEFINED__(call_resolved)
MASK(call_resolved, "CALL_RESOLVED")
#endif
#if __EFUN_DEFINED__(swap)
MASK(swap, "SWAP")
#endif
#if __EFUN_DEFINED__(debug_info)
MASK(debug_info, "DEBUG_INFO")
#endif
#if __EFUN_DEFINED__(command)
MASK(command, "COMMAND")
#endif
#if __EFUN_DEFINED__(command_stack)
MASK(command_stack, "COMMAND_STACK")
#endif
#if __EFUN_DEFINED__(command_stack_depth)
MASK(command_stack_depth, "COMMAND_STACK_DEPTH")
#endif
#if __EFUN_DEFINED__(convert_charset)
MASK(convert_charset, "CONVERT_CHARSET")
#endif
#if __EFUN_DEFINED__(debug_message) && DEBUG < 1
MASK(debug_message, "DEBUG_MESSAGE")
#endif
#if __EFUN_DEFINED__(disable_commands)
MASK(disable_commands, "DISABLE_COMMANDS")
#endif
#if __EFUN_DEFINED__(enable_commands)
MASK(enable_commands, "ENABLE_COMMANDS")
#endif
#if __EFUN_DEFINED__(function_exists)
MASK(function_exists, "FUNCTION_EXISTS")
#endif
#if __EFUN_DEFINED__(functionlist)
MASK(functionlist, "FUNCTIONLIST")
#endif
#if __EFUN_DEFINED__(garbage_collection)
MASK(garbage_collection, "GARBAGECOLLECTION")
#endif
#if __EFUN_DEFINED__(get_dir) // caught by valid_read?
MASK(get_dir, "GETDIR")
#endif
#if __EFUN_DEFINED__(include_list)
MASK(include_list, "INCLUDE_LIST")
#endif
#if __EFUN_DEFINED__(inherit_list)
MASK(inherit_list, "INHERIT_LIST")
#endif
#if __EFUN_DEFINED__(input_to_info)
MASK(input_to_info, "INPUT_TO_INFO")
#endif
#if __EFUN_DEFINED__(last_instructions)
MASK(last_instructions, "LAST_INSTRUCTIONS")
#endif
#if __EFUN_DEFINED__(load_object)
MASK(load_object, "LOAD_OBJECT")
#endif
#if __EFUN_DEFINED__(mkdir) // caught by valid_write?
MASK(mkdir, "MKDIR")
#endif
#if __EFUN_DEFINED__(move_object)
MASK(move_object, "MOVE_OBJECT")
#endif
#if __EFUN_DEFINED__(object_info)
MASK(object_info, "OBJECT_INFO")
#endif
#if __EFUN_DEFINED__(process_string)
MASK(process_string, "PROCESS_STRING")
#endif
#if __EFUN_DEFINED__(query_ip_name)
MASK(query_ip_name, "QUERY_IP_NAME")
#endif
#if __EFUN_DEFINED__(query_ip_number)
MASK(query_ip_number, "QUERY_IP_NUMBER")
#endif
#if __EFUN_DEFINED__(query_load_average)
MASK(query_load_average, "QUERY_LOAD_AVERAGE")
#endif
#if __EFUN_DEFINED__(query_shadowing)
MASK(query_shadowing, "QUERY_SHADOWING")
#endif
#if __EFUN_DEFINED__(remove_action)
MASK(remove_action, "REMOVE_ACTION")
#endif
#if __EFUN_DEFINED__(remove_input_to)
MASK(remove_input_to, "REMOVE_INPUT_TO")
#endif
#if __EFUN_DEFINED__(remove_interactive)
MASK(remove_interactive, "REMOVE_INTERACTIVE")
#endif
#if __EFUN_DEFINED__(rename) // seems to be caught by valid_(read|write), but
// i have to check that
MASK(rename, "RENAME")
#endif
#if __EFUN_DEFINED__(rm) // caught by valid_write?
MASK(rm, "RM")
#endif
#if __EFUN_DEFINED__(rmdir) // caught by valid_write?
MASK(rmdir, "RMDIR")
#endif
#if __EFUN_DEFINED__(rusage)
MASK(rusage, "RUSAGE")
#endif
#if __EFUN_DEFINED__(say)
MASK(say, "SAY")
#endif
#if __EFUN_DEFINED__(set_environment)
MASK(set_environment, "SET_ENVIRONMENT")
#endif
#if __EFUN_DEFINED__(set_is_wizard)
MASK(set_is_wizard, "SET_IS_WIZARD")
#endif
#if __EFUN_DEFINED__(set_modify_command)
MASK(set_modify_command, "SET_MODIFY_COMMAND")
#endif
#if __EFUN_DEFINED__(set_prompt)
MASK(set_prompt, "SET_PROMPT")
#endif
#if __EFUN_DEFINED__(swap)
MASK(swap, "SWAP")
#endif
#if __EFUN_DEFINED__(tell_object)
MASK(tell_object, "TELL_OBJECT")
#endif
#if __EFUN_DEFINED__(tell_room)
MASK(tell_room, "TELL_ROOM")
#endif
#if __EFUN_DEFINED__(tls_deinit_connection)
MASK(tls_deinit_connection, "TLS_DEINIT_CONNECTION")
#endif
#if __EFUN_DEFINED__(tls_init_connection)
MASK(tls_init_connection, "TLS_INIT_CONNECTION")
#endif
#if __EFUN_DEFINED__(tls_query_connection_info)
MASK(tls_query_connection_info, "TLS_QUERY_CONNECTION_INFO")
#endif
#if __EFUN_DEFINED__(tls_query_connection_state)
MASK(tls_query_connection_state, "TLS_QUERY_CONNECTION_STATE")
#endif
#if __EFUN_DEFINED__(transfer)
//MASK(transfer, "TRANSFER")
// avoid deprecation warning, and as nobody uses it:
nomask void transfer() {}
#endif
#if __EFUN_DEFINED__(unshadow)
MASK(unshadow, "UNSHADOW")
#endif
#if __EFUN_DEFINED__(users)
MASK(users, "USERS")
#endif
#if __EFUN_DEFINED__(variable_list)
MASK(variable_list, "VARIABLE_LIST")
#endif
#if __EFUN_DEFINED__(wizlist_info)
MASK(wizlist_info, "WIZLIST_INFO")
#endif
nomask mixed call_other(mixed obj, string func, varargs mixed * b) {
P4(("call_other(%O, %O, %O)\n", obj, func, b));
if (extern_call()) {
mixed euid = geteuid(previous_object());
if (stringp(euid) && euid[0] != '/') {
string s;
object o;
s = stringp(obj) ? obj : object_name(obj);
o = objectp(obj) ? obj : find_object(obj);
#ifndef __COMPAT_MODE__
if (s[0] == '/') s = s[1..];
#endif
if (euid[0] == '@') { // yes, this check is overdone, but only for
// now. i think we can use exactly this
// structure for allowed call_others into
// daemons. says tobij.
// <lynX> yes, checking the identity of daemons is much
// easier. some of them we already have stored in library
// vars, others have static object names, so they can be put
// into a switch or mapping. it's only doing so for "any"
// user object, which gets too messy. it is architecturally
// much cleaner to let sendmsg() decide which msg is legal
// (which it has to do anyway) so we don't need yet another
// security scheme in here with this wild guessing for user
// objects. in fact two redundant security approaches also
// unnecessarily raise the chances of being flawed. so let's
// allow as few -> operations as possible for sandbox mode.
//
// great idea. library_object()->sendmsg() _is_
// a -> operation, in case you forgot we're doing that (in
// entity.c).
//
// if we rename the library-sendmsg to something reachable
// without a call_other, anyways, sendmsg() will be an extra
// function call if it just redirects the msg to
// target->msg().
// in fact, it might be same complexity as calling target->msg
// directly, as call_other is overloaded and an lfun doing
// ... virtually the same thing for the discussed type of
// call.
//
// the if here isn't even more complex than in sendmsg, it'll
// be of equal or less complexity, plus, normal objects
// (and, if we want to allow ->qName for everybody anywhere,
// normal call_others (well, qName)
// don't run deep into this check.
//
// so, after all, the only argument is "evil! code!
// 'duplication'!", which i prefer over (for users who do
// their own rooms etc) incomprehensible
// #ifndef SADNBOX
// target->msg
// #else
// sendmsg(target, ...)
// #endif
// mess in files.
//
// additionally, my sandbox-philosophy is to keep things
// maximum equal in usage with and without SANDBOX,
// so i'll do it this way.
unless (o == previous_object() || o == ME) {
int i;
if ((i = index(s, '#')) == -1) i = strlen(s) - 1;
unless (func == "qName") switch (s[..i]) {
case "net/person#":
case "net/user#":
//if (func == "qName" || func == "msg") break;
if (func == "msg") break;
default:
if (sscanf(s[..i], "net/%~s/user#")
&& func == "msg") break;
raise_error(sprintf("INVALID %O "
"call_other(%O, %O, %O)\n",
euid, obj, func, b));
}
}
} else {
raise_error(sprintf("INVALID %O call_other(%O, %O, %O)\n",
euid, obj, func, b));
}
} else unless (euid) {
raise_error(sprintf("INVALID euid-0 (%O) call_other(%O, %O, %O)\n",
previous_object(), obj, func, b));
}
set_this_object(previous_object());
}
return efun::call_other(obj, func, b...);
}