lima-1.0b5/
lima-1.0b5/driver/
lima-1.0b5/driver/ChangeLog.old/
lima-1.0b5/driver/Win32/
lima-1.0b5/driver/compat/
lima-1.0b5/driver/include/
lima-1.0b5/driver/testsuite/
lima-1.0b5/driver/testsuite/clone/
lima-1.0b5/driver/testsuite/command/
lima-1.0b5/driver/testsuite/data/
lima-1.0b5/driver/testsuite/etc/
lima-1.0b5/driver/testsuite/include/
lima-1.0b5/driver/testsuite/inherit/
lima-1.0b5/driver/testsuite/inherit/master/
lima-1.0b5/driver/testsuite/log/
lima-1.0b5/driver/testsuite/single/
lima-1.0b5/driver/testsuite/single/tests/compiler/
lima-1.0b5/driver/testsuite/single/tests/efuns/
lima-1.0b5/driver/testsuite/single/tests/operators/
lima-1.0b5/driver/testsuite/u/
lima-1.0b5/driver/tmp/
lima-1.0b5/etc/
lima-1.0b5/lib/WWW/help/
lima-1.0b5/lib/cmds/
lima-1.0b5/lib/cmds/create/
lima-1.0b5/lib/cmds/player/attic/
lima-1.0b5/lib/contrib/bboard/
lima-1.0b5/lib/contrib/boards/
lima-1.0b5/lib/contrib/marriage/
lima-1.0b5/lib/contrib/roommaker/
lima-1.0b5/lib/contrib/transient_effect/
lima-1.0b5/lib/daemons/channel/
lima-1.0b5/lib/daemons/imud/
lima-1.0b5/lib/data/
lima-1.0b5/lib/data/config/
lima-1.0b5/lib/data/links/
lima-1.0b5/lib/data/news/
lima-1.0b5/lib/data/players/
lima-1.0b5/lib/data/secure/
lima-1.0b5/lib/domains/
lima-1.0b5/lib/domains/std/2.4.5/maze1/
lima-1.0b5/lib/domains/std/2.4.5/npc/
lima-1.0b5/lib/domains/std/2.4.5/post_dir/
lima-1.0b5/lib/domains/std/2.4.5/sub/
lima-1.0b5/lib/domains/std/camera/
lima-1.0b5/lib/domains/std/config/
lima-1.0b5/lib/domains/std/cult/
lima-1.0b5/lib/domains/std/effects/
lima-1.0b5/lib/domains/std/misc/
lima-1.0b5/lib/domains/std/monsters/
lima-1.0b5/lib/domains/std/recorder/
lima-1.0b5/lib/domains/std/rooms/
lima-1.0b5/lib/domains/std/rooms/beach/
lima-1.0b5/lib/domains/std/rooms/labyrinth/
lima-1.0b5/lib/domains/std/school/
lima-1.0b5/lib/domains/std/school/O/
lima-1.0b5/lib/domains/std/spells/
lima-1.0b5/lib/domains/std/spells/stock-mage/
lima-1.0b5/lib/domains/std/spells/stock-priest/
lima-1.0b5/lib/help/
lima-1.0b5/lib/help/admin/
lima-1.0b5/lib/help/hints/General_Questions/
lima-1.0b5/lib/help/hints/Pirate_Quest/
lima-1.0b5/lib/help/player/
lima-1.0b5/lib/help/player/bin/
lima-1.0b5/lib/help/player/quests/
lima-1.0b5/lib/help/wizard/
lima-1.0b5/lib/help/wizard/coding/guilds/
lima-1.0b5/lib/help/wizard/coding/rooms/
lima-1.0b5/lib/help/wizard/lib/daemons/
lima-1.0b5/lib/help/wizard/lib/lfun/
lima-1.0b5/lib/help/wizard/lib/std/
lima-1.0b5/lib/help/wizard/mudos_doc/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/interactive/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/concepts/
lima-1.0b5/lib/help/wizard/mudos_doc/driver/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/arrays/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/buffers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/compile/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/filesystem/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/floats/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/functions/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/general/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mappings/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mixed/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/numbers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/constructs/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/types/
lima-1.0b5/lib/include/driver/
lima-1.0b5/lib/log/
lima-1.0b5/lib/obj/admtool/
lima-1.0b5/lib/obj/admtool/internal/
lima-1.0b5/lib/obj/admtool/mudinfo/
lima-1.0b5/lib/obj/admtool/secure/
lima-1.0b5/lib/obj/secure/
lima-1.0b5/lib/obj/secure/cmd/
lima-1.0b5/lib/obj/secure/mailers/
lima-1.0b5/lib/obj/secure/shell/
lima-1.0b5/lib/obj/secure/shell/classes/
lima-1.0b5/lib/obj/tasktool/
lima-1.0b5/lib/obj/tasktool/internal/
lima-1.0b5/lib/open/
lima-1.0b5/lib/secure/
lima-1.0b5/lib/secure/cgi/
lima-1.0b5/lib/secure/modules/
lima-1.0b5/lib/secure/simul_efun/
lima-1.0b5/lib/std/adversary/
lima-1.0b5/lib/std/adversary/advancement/
lima-1.0b5/lib/std/adversary/armor/
lima-1.0b5/lib/std/adversary/blows/
lima-1.0b5/lib/std/adversary/death/
lima-1.0b5/lib/std/adversary/formula/
lima-1.0b5/lib/std/adversary/health/
lima-1.0b5/lib/std/adversary/pulse/
lima-1.0b5/lib/std/adversary/wield/
lima-1.0b5/lib/std/classes/event_info/
lima-1.0b5/lib/std/container/
lima-1.0b5/lib/std/living/
lima-1.0b5/lib/std/modules/contrib/
lima-1.0b5/lib/std/patterns/
lima-1.0b5/lib/std/race/
lima-1.0b5/lib/std/race/restricted/
lima-1.0b5/lib/std/room/
lima-1.0b5/lib/tmp/
lima-1.0b5/lib/trans/
lima-1.0b5/lib/trans/admincmds/
lima-1.0b5/lib/trans/obj/
lima-1.0b5/lib/wiz/
/* Do not remove the headers from this file! see /USAGE for more info. */

// NOTE:
// Despite the length of this code, the only outside calls made
// are from call_unguarded(). call_other()s to other object will
// be extremely dangerous since they imply an unguarded() call.

#include <mudlib.h>
#include <security.h>

inherit M_ACCESS;

#define ERR_PRIV	"insufficient privilege"
#define ERR_NODOMAIN    "accessing non-existing domain"
#define ERR_NOWIZ       "referring to non-existing wizard"
#define ERR_BADARG	"illegal or unusable parameter"
#define ERR_HAZARD	"hazardous setting of privileges"

private mapping privileges; // mapping containing all privileges
                            // values are arrays of parents and children
private mapping read_access; // maps directory -> protection level
private mapping write_access; // dto.
private mapping wizards; // mapping containing all wizards and their level
private mapping domains; // maps domains -> mappings of members/lords
                         //                 (valued 2 for lords, 1 for members)
private mapping domainlists; // wizard -> domains

int
valid_name( string s )
{
    // replace valid chars by '*', and compare to a string of all '*'s
    return
	map(s, (: ($1 < 'a' || $1 > 'z') ? ' ' : '*' :))
	== map(s, (: '*' :)) && s!="";
}

private void save_data()
{
  unguarded(1, (: save_object, ACCESS_SAVE :));
  unguarded(1, (: save_object, ACCESS_SAVE_BAK :));
}

private void syslog(string text)
{
  unguarded(1, (: write_file, ACCESS_LOG,
    (this_user() ? this_user()->query_userid()
                        : "<Server>") + ": " + text + "\n" :) );
}

void create()
{
  if( clonep(this_object()) )
    return;
  set_privilege(1);
  // The following call is handled specially in the master.
  // Using unguarded() is impossible, since variables are not yet
  // initialized.
 if (!restore_object(ACCESS_SAVE))
  {
    if (eval_cost() < 1000) // *sigh*
      for (;;);
    privileges = ([ ]);
    read_access = allocate_mapping(1);
    write_access = allocate_mapping(1);
    domains = ([ ]);
    domainlists = ([ ]);
    wizards = ([ ]);
    save_data();
    return;
  }
  if (!sizeof(read_access))
    read_access = ([]);
  if (!sizeof(write_access))
    write_access = ([]);
}

int query_allow_shadow() { return 0; }

// The following function HAS to be private. Otherwise somebody
// might gain write access to the server's datastructures.
private mixed *walk_path(string file,int write)
{
  string *path;
  mixed *result;
  mixed *tmp;
  mapping node,subnode;
  int i;
  path = explode(file,"/")-({"","."});
  if (!sizeof(path))
    return 0;
  if (member_array("..",path)>=0)
    return 0;
  result = allocate(sizeof(path));
  node = write ? write_access : read_access;
  result[0] = !!write;
  for (i=1;i<sizeof(result);i++)
  {
    if (undefinedp(tmp = node[path[i-1]]))
    {
      result[i]=-1;
      break;
    } else {
      result[i] = tmp[0];
      subnode = tmp[1];
    }
    if (!subnode)
      break;
    if (!sizeof(subnode))
    {
      tmp[1] = 0;
      break;
    }
    node = subnode;
  }
  if (i == sizeof(result))
    --i;
  return ({ result, path[0..<2], i });
}

nomask mixed query_protection(mixed file,int write)
{
  mixed *desc;
  int i;
  if (objectp(file))
    file = file_name(file);
  desc = walk_path(file,write);
  if (!desc)
    return !!write; // root directory
  i = desc[2];
  desc = desc[0];
  while (desc[i]==-1)
    --i;
  return desc[i];
}

nomask varargs int check_privilege(mixed priv,int ignore);
nomask int higher_privilege(mixed a,mixed b);
nomask int valid_privilege(mixed priv);

nomask string set_protection(string file,int write,mixed prot)
{
  mixed *desc;
  int i,j;
  mixed *priv;
  string *path;
  mapping node,subnode;
  desc = walk_path(file+"/foo",write);
  if (sizeof(desc[1])>6)
    return ERR_BADARG;
  if (prot != -1 && !valid_privilege(prot))
    return "invalid privilege identifier";
  if (!desc)
    return "trying to change root directory's privilege";
  priv = desc[0];
  i = desc[2];
  while (priv[i]==-1)
    i--;
  if (i)
  {
    j = i-1;
    while (priv[j]==-1)
      j--;
  }
  else
    j = i;
  if (priv[i]==prot)
    return "directory already has this effective protection level";
  if (write && !check_privilege(priv[sizeof(desc[1])==i ? j : i]))
    return ERR_PRIV;
  if (!write && !check_privilege(1)) // Only staff can make read restrictions
    return ERR_PRIV;
  if (eval_cost()<1000)
    for (;;);
  if (prot != -1)
  {
    if (write && higher_privilege(prot,priv[i]))
      return ERR_HAZARD;
    if (!write && higher_privilege(priv[i],prot))
      return ERR_HAZARD;
    node = write ? write_access : read_access;
    path = desc[1];
    for (i=0; i<sizeof(path)-1; i++)
    {
      if (undefinedp(node[path[i]]))
        node[path[i]] = ({ -1, subnode = allocate_mapping(1) });
      else if (!(subnode = node[path[i]][1]))
	node[path[i]][1] = subnode = allocate_mapping(1);
      node = subnode;
    }
    node[path[<1]]=({ prot, 0});
    save_data();
    return 0;
  }
  else
  {
    if (desc[2]!=sizeof(desc[1]))
      return "directory not linked to a privilege level";
    node = write ? write_access : read_access;
    path = desc[1];
    for (i=0; i<sizeof(path)-1; i++)
      node = node[path[i]][1];
    map_delete(node,path[<1]);
    save_data();
    return 0;
  }
}

private int valid_domain_name(string name)
{
	return sizeof(regexp( ({ name }), "^[-a-z_]*$"));
}

nomask varargs string create_domain(string domain)
{
  if (!check_privilege(1)) // Only staff members can create domains
    return ERR_PRIV;
  if (eval_cost()<1000)
    for (;;);
  if (!valid_domain_name(domain))
    return "invalid domain name";
  domain = lower_case(domain);
  if (domains[domain])
    return "domain already exists";
  domains[domain] = ([ ]);
  privileges[capitalize(domain)] = ([ "":({}),":":({}) ]);
  save_data();
  syslog("Created domain " + domain);
  return 0;
}

nomask string delete_domain(string domain)
{
  string *members;
  int i;
  if (!check_privilege(1)) // Only staff members can delete domains
    return ERR_PRIV;
  if (eval_cost()<10000)
    for (;;);
  if (!domains[domain])
    return ERR_NODOMAIN;
  members = keys(domains[domain]);
  for (i=0; i<sizeof(members); i++)
  {
    mapping m;
    m = domainlists[members[i]];
    map_delete(m,domain);
  }
  map_delete(domains,domain);
  save_data();
  syslog("Deleted domain " + domain);
  return 0;
}

nomask string add_domain_member(string domain,string member,int lord)
{
  if (!domains[domain])
    return ERR_NODOMAIN;
  if (!wizards[member])
    return ERR_NOWIZ;
  if (!check_privilege(capitalize(domain)))
    return ERR_PRIV;
  if (eval_cost()<1000)
    for (;;); // This is getting boring...
  domains[domain][member] = (lord ? 2 : 1);
  if (domainlists[member])
    domainlists[member] += ([ domain : 1 ]);
  else
    domainlists[member] = ([ domain : 1 ]);
  save_data();
  if (lord)
    syslog("Made " + member + " lord of " + domain);
  else
    syslog("Made " + member + " member of " + domain);
  return 0;
}

nomask string remove_domain_member(string domain,string member)
{
  if (!domains[domain])
    return ERR_NODOMAIN;
  if (!domains[domain][member])
    return ERR_NOWIZ;
  if (!check_privilege(capitalize(domain)))
    return ERR_PRIV;
  if (eval_cost()<1000)
    for (;;);
  map_delete(domains[domain],member);
  map_delete(domainlists[member],domain);
  save_data();
  syslog("Removed " + member +" from domain " + domain);
  return 0;
}

nomask string create_wizard(string wizard)
{
  if (!valid_name(wizard))
    return "invalid character name";
  if (wizards[wizard])
    return "this character is already recorded as a wizard";
  if (!check_privilege(1))
    return ERR_PRIV;
  if (eval_cost()<1000)
    for (;;);
  wizards[wizard] = 1;
  privileges[wizard] = ([ "":({}),":":({}) ]);
  save_data();
  syslog("Created wizard " + wizard);
  return 0;
}

nomask string delete_wizard(string wizard)
{
  mixed d;
  if (!wizards[wizard])
    return ERR_NOWIZ;
  if (!check_privilege(1))
    return ERR_PRIV;
  if (eval_cost()<10000)
    for (;;);
  map_delete(wizards,wizard);
  map_delete(privileges,wizard);
  d = domainlists[wizard];
  if (d)
  {
    int i;
    d = keys(d);
    for (i=0; i<sizeof(d); i++)
      map_delete(domains[d[i]],wizard);
  }
  map_delete(domainlists,wizard);
  save_data();
  syslog("Deleted wizard " + wizard);
  return 0;
}

private string get_priv_owner(string priv)
{
  int n;
  if (!stringp(priv))
    return 0;
  n = member_array(':',priv);
  if (n >=0)
    priv = priv[0..n-1];
  if (!privileges[priv])
    return 0;
  return priv;
}

nomask string define_privilege(string priv)
{
  string owner;
  owner = get_priv_owner(priv);
  if (!owner)
  {
    if (priv[0]!='@' || member_array(':',priv)>=0)
      return "invalid privilege identifier";
    if (!check_privilege(1))
      return ERR_PRIV;
    if (eval_cost()<1000)
      for (;;);
    privileges[priv] = ([ "": ({ }), ":": ({ }) ]);
    save_data();
    return 0;
  }
  if (!check_privilege(owner))
    return ERR_PRIV;
  if (eval_cost()<1000)
    for (;;);
  priv = priv[strlen(owner)..];
  if (privileges[owner][priv])
    return "attempt to redefine privilege";
  privileges[owner][priv] = ({ });
  save_data();
  return 0;
}

nomask string undefine_privilege(string priv)
{
  mixed owner;
  owner = get_priv_owner(priv);
  if (!owner)
    return "invalid privilege identifier";
  if (strlen(owner)+1 >= strlen(priv))
  {
    if (!check_privilege(1))
      return ERR_PRIV;
  }
  else
  {
    if (!check_privilege(owner))
      return ERR_PRIV;
  }
  if (eval_cost()<1000)
    for (;;);
  if (owner == priv)
    map_delete(privileges,priv);
  else
  {
    mapping list;
    list = privileges[owner];
    if (!list[priv[strlen(owner)..]])
      return "invalid privilege identifier";
    map_delete(list,priv[strlen(owner)..]);
  }
  save_data();
  return 0;
}

nomask string * query_privilege_owners()
{
    return keys(privileges);
}

nomask mapping query_privilege_list(string priv)
{
  mapping list,result;
  string *subs;
  int i;

  if (!(list = privileges[priv]))
    return 0;
  result = ([ ]);
  subs = keys(list);
  for (i=0; i<sizeof(subs); i++)
    result[priv+subs[i]] = list[subs[i]][0..];
  return result;
}

nomask mapping query_access_tree(string path,int write)
{
  mapping result;
  string *p;
  int i;
  mixed *tmp;
  
  p = explode(path,"/")-({"","."});
  if (write)
    result = write_access;
  else
    result = read_access;
  if (!sizeof(p))
    return copy(result);
  for (i=0;i<sizeof(p)-1 && sizeof(result);i++)
    result = result[p[i]] ? result[p[i]][1] : 0;
  if (sizeof(result) && !undefinedp(tmp = result[p[<1]]))
      return ([ p[<1] : ({ tmp[0] == -1 ? query_protection(path+"/foo",write):tmp[0], copy(tmp[1])}) ]);
  else
    return ([ p[<1] : ({ query_protection(path+"/foo",write), 0}) ]);
}

nomask string extend_access(string priv,string add)
{
  string owner;
  owner = get_priv_owner(priv);
  if (!owner || !privileges[owner] || !privileges[owner][priv[strlen(owner)..]])
    return "invalid privilege identifier";
  if (!stringp(add) || !valid_privilege(add))
    return "invalid privilege identifier";
  if (owner == priv)
  {
    if (!check_privilege(1))
      return ERR_PRIV;
  }
  else
  {
    if (!check_privilege(owner))
      return ERR_PRIV;
  }
  if (eval_cost()<1000)
    for (;;);
  priv = priv[strlen(owner)..];
  privileges[owner][priv] -= ({ add });
  privileges[owner][priv] += ({ add });
  save_data();
  return 0;
}

nomask string restrict_access(string priv,string remove)
{
  string owner;
  owner = get_priv_owner(priv);
  if (!owner || !privileges[owner] || !privileges[owner][priv[strlen(owner)..]])
    return "invalid privilege identifier";
  if (owner == priv)
  {
    if (!check_privilege(1))
      return ERR_PRIV;
  }
  else
  {
    if (!check_privilege(owner))
      return ERR_PRIV;
  }
  if (eval_cost()<1000)
    for (;;);
  priv = priv[strlen(owner)..];
  if (member_array(remove,privileges[owner][priv])<0)
    return "invalid privilege identifier";
  privileges[owner][priv] -= ({ remove });
  save_data();
  return 0;
}

nomask int query_is_wizard(string name)
{
  return wizards[name];
}

nomask int query_is_domain(string name)
{
  return !!domains[name];
}

nomask string *query_domain_members(string domain)
{
  mapping members;
  members = domains[domain];
  return members && keys(members);
}

nomask string *query_domain_lords(string domain)
{
  mapping members;
  string *list;
  int i;
  members = domains[domain];
  if (!members)
    return 0;
  list = keys(members);
  for (i=0; i<sizeof(list); i++)
    if (members[list[i]]<2)
      list[i] = 0;
  return list - ({ 0 });
}

nomask varargs string *query_domains(string wizard)
{
  mapping d;
  if (!wizard)
    return keys(domains);
  if (!wizards[wizard])
    return 0;
  d = domainlists[wizard];
  return d ? keys(d) : ({ });
}

nomask int valid_privilege(mixed p)
{
  int n;
  mapping list;
  if (intp(p))
    return p==0 || p==1;
  n = member_array(':',p);
  if (n<0)
    n = strlen(p);
  if (list = privileges[p[0..n-1]])
    return !undefinedp(list[p[n..]]);
}

// returns 1 if a >= b
nomask int higher_privilege(mixed a,mixed b)
{
  // This is THE central routine of the security system.
  // It determines the security hierarchy.
  int m,n;
  if (!valid_privilege(a) || !valid_privilege(b))
    error("Invalid privilege: "+a+", "+b+"\n");
  if (a==b)
    return 1;
  if (intp(a))
  {
    if (a)
      return 1;
    return 0;
  }
  else if (intp(b))
  {
    if (!b)
      return 1;
    return 0;
  }
  m = member_array(':',a);
  if (m<0)
    m = strlen(a);
  n = member_array(':',b);
  if (n<0)
    n = strlen(b);
  a = ({ a[0..m-1], a[m..] });
  b = ({ b[0..n-1], b[n..] });
  if (a[0]==b[0] && strlen(a[1])<strlen(b[1]) && b[1][0..strlen(a[1])-1]==a[1])
    return 1;
  switch (b[0][0])
  {
    case 'A'..'Z':
      if (strlen(a[1])==0 && domains[lower_case(b[0])])
      {
	/* if b is "Foo" then a must be a lord; if b is "Foo:" or "Foo:xxx"
	   then a must be a member */
        if (domains[lower_case(b[0])][a[0]] > !strlen(b[1]))
          return 1;

	/* fallthru to check privs */
      }
  }
  return member_array(a[0] + a[1], privileges[b[0]][b[1]]) != -1;
}

nomask mixed reduced_privilege(mixed priv,mixed max)
{
  if (higher_privilege(max,priv))
    return priv;
  return max;
}

nomask mixed call_unguarded(function code,mixed *handle)
{
  if (function_exists("verify_privilege_granted",previous_object())!=M_ACCESS)
    {
      syslog("Secvio: faked call in " + file_name(previous_object()));
      return 0; // faked call
    }
  if (!previous_object()->verify_privilege_granted(handle))
    {
      syslog("Secvio: handle incorrect in " + file_name(previous_object()));
      return 0; // faked, too
    }
  return evaluate(code);
}

nomask varargs int check_privilege(mixed prot,int ignore)
{
  object *stack;
  int stacksize;
  int i;
  object ob,next;
  object next2;

  if (!prot)
    return 1;
  stacksize = (sizeof(stack = all_previous_objects()));
  for (i=ignore; i<stacksize; i++)
  {
    ob = stack[i];
    next = (i < stacksize - 1 ? stack[i+1] : 0);
    next2 = (i < stacksize - 2 ? stack[i+2] : 0);
    if (!ob)
      {
	syslog("Secvio: object destructed in call stack\n" + 
	       implode(map_array(stack, (: $1 ? file_name($1) : "0" :)), ", "));
	return 0;
      }

    if (next == this_object()) // This call is unguarded
    {
      next = next2;
      if (next!=ob && next != this_object())
	{
	  syslog(sprintf("Secvio: %O used fptr bound to %O", ob, next));
	  return 0; // The object defining the fptr did not call it.
	}
      if (!next && prot)
	{
	  syslog("Secvio: ob destructed in call stack\n" +
		 implode(map_array(stack, (: file_name :)), ", "));
	  return 0; // This object has been destructed.
	}
      if (function_exists("query_unguarded_privilege",next)!=M_ACCESS)
	{
	  syslog("Secvio: faked query_unguarded_privilege in " + 
		 file_name(next));
	  return 0; // faked
	}
      if (!higher_privilege(next->query_unguarded_privilege(),prot))
	{
	  syslog(sprintf("Secvio: %O has priv %O, asked for %O",
			 next, next->query_unguarded_privilege(), prot));
	  return 0; // insufficient privilege
	}
      if (!higher_privilege(query_protection(next,1),prot))
	{
	  syslog(sprintf("Secvio: %O has prot %O, asked for %O",
			 next, query_protection(next, 1), prot));
	  return 0; // privilege higher than maximum allowed value
	}
      return 1;
    }
    if ( ob == master() ) continue;
    if ( file_name(ob) == SIMUL_OB ) continue;

    if (function_exists("query_privilege",ob)!=M_ACCESS)
    {
      string temp,temp2;
      if (sscanf(file_name(ob),"/wiz/%s/%s",temp,temp2)==2)
      {
	  return higher_privilege(temp+":",prot);
      }
      if (sscanf(file_name(ob),"/domains/%s/%s",temp,temp2)==2)
      {
	  return higher_privilege(capitalize(temp)+":",prot);
      }
      return 0;
    }
    if (!higher_privilege(ob->query_privilege(),prot))
      return 0;
  }
  ob = this_user();
  if (!ob)
    {
      syslog("Secvio: Missing user\n" + call_trace()[0..<2]);
      return 0;
    }
  if (function_exists("query_privilege",ob)!=M_ACCESS)
    {
      syslog(sprintf("Secvio: %O faked query_privilege", ob));
      return 0;
    }
  if (!higher_privilege(ob->query_privilege(),prot))
    {
      syslog(sprintf("Secvio: %O has priv %O, asked for %O",
		     ob, ob->query_privilege(), prot));
      return 0;
    }
  return 1;
}