Subject: Re: Permissions system of moo

From: [email-masked]
Date: Wed, 24 Feb 1993 07:02:00 -0800

Pavel responds to me:

>> This works around the server requirements, yet it still makes players own 
>> things themselves.  And rather than creating a communal owner for groups 
>> of objects, it's the groups of objects having -sets- of owners.  We've 
>> found this to be terribly useful as we work on several large 
>> collaborative projects.

> The question is with whose permissions a group-owned verb operates.  

The method we used to determine this is as follows:

If I set the code on the verb, and I am non-wizardly, the verb's ownership
is changed to me.  Thus, on a shared object, any number of verbs may be
owned by any number of players, all of whose verbs run with their own 
permissions.  (There are a few more tricks in the works, but this is the most 
basic rule, preventing me from usurping your power just because we share an 
object.)

> I certainly don't want any verbs that I own with a group of others to run 
> with *my* permissions.  By symmetry, that verb couldn't be owned by *any* 
> of the members of the group, so who is there to own it?  In my system, the
> corporation owns it, so the verb can only read and modify the things that 
> the corporation can read or modify, which seems just right to me.

Yes, except that it seems somewhat artificial to me.  (I am, admittedly, 
stuck in the `only players may own stuff' mindset.)

>> While I think this sounds like a neat idea, I'm not sure what real use it 
>> would be.  The -easiest- way to handle this, it seems, is through multiple 
>> ownership, simply put, and this is quite doable in-DB.  It seems that more 
>> and more complications would be added if we had to keep track of the 
>> `mode' or `corporation' a player's acting in/for at any given time.

> Fortunately, the only operations you need to know this for is
> verb/property/object creation.  Editing the code for verbs or the values of
> properties does not require a `mode', since you can just check for 
> membership in the corporation.  I don't know about other folks, but I tend 
> to do my creations in fairly large clumps, so it might work out fine to 
> simply `time out' my decision about what corporation I'm representing.  
> Also, one could default on verbs and properties to the owner of the object.

Perhaps. I still tend towards thinking that it's a simple thing to do in-DB, 
if we work on the assumption that no programmer will write a verb which can 
be used against him.

Seth / Blackbriar

---

From: Roger Crew <[email-masked]>
Date: Wed, 24 Feb 1993 16:16:22 -0800

>   You are your own corporation. 

clearly.  What I meant was having the default corporation where one's
verbs and objects are normally created be a "safe" corporation that is
*distinct* from the player corporation.  In general, one would be a
member of many corporations; the player corporation should be the most
protected of all since anyone who breaks into it gets into all of the
others.  Thus, it should (according to the Paranoid point of view I'm
espousing) NEVER be the default for creating new verbs.

E.g., I may, in the course of experimenting, create a verb with an
unprotected eval().  Having this be in a corporation limits the damage
this can do to me, i.e., my player.  (wow ...the word "corporation" in
this context is *really* appropriate...).

I'm mainly thinking about the situation where Rog has many hundreds of
verbs, any of which could be a security hole (granted it wouldn't be
completely earthshattering, but they *could* read my mail).  If I had
it to do over, I'd have about 20 corporations just for my own stuff,
and have very few verbs actually owned by Rog, in which case we could
even do away with ur-Rog since Rog could then safely be a wizard.  
I guess, in practice, Rog *is* my default safe corporation.

Except, of course, that we might not even need explicit wizards
anymore.  There would just be spheres of influence, each controlled by
a separate corporation (MailCorp, EditCorp, HelpCorp, QuotaCorp,
TopologyCorp, RPGCorp,...).  A "wizard" would merely be someone with
membership in all of them, though if one seriously believes in checks
and balances, *no one* would have membership on more than some specified 
fraction of the important ones --- ... there's your government mechanism...

Well, ok, there would need to be real wizard bits for maintaining the 
underpinnings (e.g., the code that allows QuotaCorp to control who can 
create things), but one assumes that there's a right way to do it so 
that there won't be very much code involved.

--
Roger Crew
Internet:   [email-masked]
LambdaMOO:  Rog

---

From: [email-masked]
Date: Thu, 25 Feb 1993 04:15:00 -0800

> I see no harm in making corporations .players, except that players()
> would get longer and contain objects that were not children of
> $player.

I -do- see some problems with this plan.  If you allow a non-$player
to be is_player(), then more than likely that object will not have a
.ownership_quota property and can create objects to its hearts desire.
And even if you -do- make the requirement that a corporation be created
as a $player, then there's nothing to stop this pseudoplayer from saying
to itself, `Hey, I don't log in anyway' and chparent()ing to some other
class and being able to create away.

For this reason, I think multiple ownership between players is the best
way to handle these things.

Seth / Blackbriar

---

From: [email-masked] (A VAX's nightmare)
Date: Thu, 25 Feb 1993 12:24:19 -0800

> class and being able to create away.

Um, Seth, from what I gather, the whole point of allowing corporations is
so that non-players can own verbs. Therefore they don't HAVE to have a
player flag. Thus eliminating the problem you stated.

Of course, I could also be out of my mind and have the whole idea of
corporations wrong too.... :)

-Wayne/Sadric

---

From: [email-masked]
Date: Thu, 25 Feb 1993 10:05:00 -0800

Wayne / Sadric:

> Um, Seth, from what I gather, the whole point of allowing corporations 
> is so that non-players can own verbs. Therefore they don't HAVE to have 
> a player flag. Thus eliminating the problem you stated.

I see... I admit, though, that I'm not entirely clear on why non-players
have to own verbs.  yduJ alluded to a problem before, but it wasn't one
I'd seen previously.

I'm gonna spout off on what I think the Right Way to do group 
projects is (aside from having a shared character to hack with).  
Actually, I was asked to send some more details about our corified 
multiple ownership on OpalMOO.  It all revolves around a hacker-owned !c 
property on $root_class -- .owners, defaulting to {}.

The main verbs in the DB permitted to directly change this property
are $ownership_utils:add_owner and $ownership_utils:delete_owner. The
only other verb which is permitted to change this property is the all-
important $ownership_utils:controls verb, which reads as follows (it,
like the two previously-mentioned verbs, is Hacker-owned):

  $ownership_utils:controls this none this rx
   1:  "$ownership_utils:controls(who, what)";
   2:  "is WHO allowed to hack on WHAT?";
   3:  "YES if WHO is WHAT's owner.";
   4:  "YES if WHO is a wizard.";
   5:  "YES if WHO is one of WHAT's shared owners listed in the .owners prop";
   6:  "NO otherwise.";
   7:  "This verb also maintains the purity of .owners by ensuring that it is
  never clear and only contains living players.";
   8:  "Because of the twisted way in which !d verbs blindly march forward
  through errors, this verb -will- properly handle objects which do not have
  .owners properties (assuming that the correct answer in that case is `Yes if
  you're a wizard or you own it').";
   9:  who = args[1];
  10:  what = args[2];
  11:  if (is_clear_property(what, "owners"))
  12:    "there's a fukd-up :initialize SOMEWHERE";
  13:    what.owners = {};
  14:    return 0;
  15:  endif
  16:  for dude in (what.owners)
  17:    if (!valid(dude) || !is_player(dude))
  18:      what.owners = setremove(what.owners, dude);
  19:    endif
  20:  endfor
  21:  if (who.wizard || who == what.owner || who in what.owners)
  22:    return 1;
  23:  else
  24:    return 0;
  25:  endif
  26:  "Last modified Mon Feb  8 23:53:32 1993 EST by BabyBriar (#2).";

The $ownership_utils:controls() check is essentially the same as
the older $perm_utils:controls() check, except that it takes into
account the extra possible owners and it also handles the special
cases needed to maintain security.  This verb is called to determine
whether a player is permitted to, say, add a verb to any given object.

Here is the code called when someone wants to add a verb to an object:

  $ownership_utils:add_verb this none this rx Wizard
   1:  "add_verb() -- see help on the builtin for more information";
   2:  who = caller_perms();
   3:  what = args[1];
   4:  info = args[2];
   5:  vargs = args[3];
   6:  if (!$ownership_utils:controls(who, what) && !what.w)
   7:    "caller_perms() is not allowed to hack on the object in question";
   8:    return E_PERM;
   9:  elseif (!$perm_utils:controls(who, info[1]))
  10:    "caller_perms() is not permitted to add a verb with the specified
  owner.";
  11:    return E_PERM;
  12:  else
  13:    "we now know that the caller's perms control the object (by multiple
  inheritance) or the object is writable, and we know that the caller's perms
  control the prospective verb owner (by more traditional means)";
  14:    return add_verb(@args);
  15:  endif

(Yes, I know it's not the best-written code in the world, but it works.)
Essentially, this allows a player to add a verb to any object e controls
(or any writable object, for that matter).  (The reason I include this
example is because I will refer to it later on.)

With these sort of controls in place, it's easy to add similar verbs for
the other relevant builtins (add_property, verb_args, etc.).  There are
a few tricks that need to be handled, though:

  1. How do we handle shared verbs?
  2. How do we handle shared properties?
  3. How do we handle shared PLAYERS?
     (this last one has special promise)

There are a few ways we looked at to handle shared verbs.  One of them
was to stick with the old server-style method of setting verb code,
and only allowing someone to set code on a verb e owns eirself.  This
was shot down primarily because it was clunky and didn't let people
collaborate so well.

Another method was to let any owner of a shared object set the code on
any verb on that object.  This got shot down -real- fast because nobody
liked the idea that by sharing an object, people could make tasks run
with their own permissions.

The last method, the one we settled on, was to have the verb ownership
change when the code is changed.  Here is the code we're using:

  $ownership_utils:set_verb_code this none this rx Wizard
   1:  who = caller_perms();
   2:  where = args[1];
   3:  what = args[2];
   4:  code = args[3];
   5:  while ((last = code[length(code)]) && length(last) >= 15 &&
  last[1..15] == "\"Last Modified ")
   6:    code = code[1..length(code) - 1];
   7:  endwhile
   8:  args[3] = {@code, tostr("\"Last modified ", ctime(), " by ", 
  who.name, " (", who, ").\";")};
   9:  if ($ownership_utils:controls(who, where) && !who.wizard)
  10:    "the player controls the object in question AND IS NOT WIZARDLY";
  11:    info = verb_info(where, what);
  12:    if (typeof(info) == ERR)
  13:      "most likely, verb not exists";
  14:      return info;
  15:    endif
  16:    info[1] = who;
  17:    set_verb_info(where, what, info);
  18:  endif
  19:  set_task_perms(who);
  20:  return set_verb_code(@args);
  21:  "Last modified Mon Feb 15 23:04:40 1993 EST by BabyBriar (#2).";

This code changes the owner to the new editor, if that editor is non-
wizardly.  This has been found to be a quite suitable arrangement.

Handling properties proved to be a different animal, so we needed to
introduce two new `builtins' -- property_value and set_property_value.
Essentially, the only added functionality they offered was that a !c
property defined on a shared object could be used (set, read, etc.) by
any of the owners of that object, even when that property is being
accessed on a descendant.  As an example:

  $ownership_utils:property_value this none this rx Wizard
   1:  "$ownership_utils:property_value( object , property-name ) => value |
  E_PERM | E_PROPNF";
   2:  who = caller_perms();
   3:  where = args[1];
   4:  what = args[2];
   5:  if (typeof(where) != OBJ)
   6:    return E_INVARG;
   7:  elseif (!valid(where))
   8:    return E_INVARG;
   9:  elseif (typeof(what) != STR)
  10:    return E_INVARG;
  11:  endif
  12:  info = property_info(where, what);
  13:  if (typeof(info) == ERR)
  14:    return info;
  15:  endif
  16:  if (index(info[2], "r") || $perm_utils:controls(who, info[1]))
  17:    return where.(what);
  18:  endif
  19:  "now for the TRICKY part. The property is not readable by our caller's
  permissions. Is it defined on an object which the caller controls?";
  20:  home = $ownership_utils:property_definition(where, what);
  21:  if ($ownership_utils:controls(who, home) && !index(info[2], "c"))
  22:    return where.(what);
  23:  endif
  24:  "last shot -- is there anything I missed?";
  25:  set_task_perms(who);
  26:  return where.(what);

The last question is one we're not yet facing on OpalMOO, but one I
intend to introduce soon.  What if the object being shared is not
merely an object, but in fact a -player- object?

What I intend to do soon is eliminate the $perm_utils checks and
use $ownership_utils totally.  What this will mean, essentially,
is that we will have a situation like the following:

  Munchkin and Xiombarg are working on some hellish projects
  together, and they trust each other a lot.  So Xiombarg,
  being the more trusting of the two, adds Munchkin as an
  owner to HERSELF -- so that, essentially, Xiombarg is a
  player object with two owners.

  Munchkin is now able to execute the previously-unavailable
  commands:
    @verb foo:bar this none this rxd Xiombarg
    @property foo.baz {} "r" Xiombarg
  ... and, thus, create verbs and properties owned by Xiombarg,
  by virtue of his being an owner of hers.  (Eek, I realize I've
  painted this in a horribly sexist way.  Let's assume that at
  this point in the text Xiombarg morphs into Xiombargs, so they're
  plural now.)

  Similarly, although this isn't supported by the above code,
  Munchkin will be able to set the code on Xiombargs-owned verbs,
  and essentially do anything except actually log in as the
  Xiombargs (because this still doesn't allow access to the password).

(Because of this upcoming development, $ownership_utils:add_owner
does not allow an owner to be added to a wizardly object.)

We're going through the database and changing most of the core verbs
to use these multiple ownership utilities.  So far, we've had very few
bugs (although some people griped about the verb timestamping).  I think 
that this method allows for simpler handling of shared projects.

Seth / Blackbriar