external next up previous contents index
Next: 11.3 Error handling Up: 11.2 Security Previous: 11.2 Security

Writing Secure Verbs (by EricM)

   

Acknowledgment: This text is a formatted version of a message posted to ??? on BioMOO by:

                             Copyright 1995 Eric Mercer
                             last updated 7/11/95
                             EricM @ BioMOO, Diversity University, others....
                             mercer@caltech.edu

Additional documentation:

Check out the MOO programmer's manuel, e.g. the callers function.

What verbs need permissions checking?

Any verb that either

  1. alters the state of the object in a way that only a limited number of people should be able to do, or
  2. provides information that only a limited number of people should have access to.

What are the main considerations in choosing a format for your security?

The main considerations are 1) is the verb +x, and 2) can the verb be called from the command line (ie. does it have args other than this none this). Note that these are not linked and you can have +x command line verbs, for instance.

What is the general structure of a permissions test?

Verbs should start with a few lines of comments (describing what they do, etc.) followed by:

     if (perms_test_fails)
        return failure_report;
     endif
     ....->rest of verb
where "failure_report" should be 'E_PERM' for +x this none this verbs, and 'player:tell("Sorry, you don't have permission to do that.")' for -x command line verb). For +x command line verbs, add the player:tell line before returning E_PERM.

Replace "perms_test_fails" with one of the constructs given later in this note.

What are valid calls to +x, this none this verbs?

I think the following list is complete. I've also given an example of a typical "perms_test_fails" line for each, but note that you'll often want to use some combination or hybrid.

1. Calls from other verbs on the object itself.
     type:object-based security
     example: if (caller!=this)
2. Wiz-permed calls
     type: permissions-based security
     example: if (!$perm_utils:controls(caller_perms(), this))  <-preferred
              if (!caller_perms().wizard)  <- less flexible
3. Calls from verbs owned by the same programmer
     type: perms-based security
     example: if (caller_perms() != $code_utils:verb_perms())
     note: Gives a lot of power to the programmer, but sometimes useful.
           Note that we DON'T use the object number of the programmer,
           because this will be different if someone ports the object.
4. Calls from verbs owned by the object owner
     type:perms-based security
     example: if (caller_perms() != this.owner)
     note: rarely useful, and not at all useful on generic objects
5. Calls from objects owned by the programmer
     type: object-based security
     example: if (caller.owner != $code_utils:verb_perms())
     note: only useful in some special cases
6. Calls from "permitted" objects (generally stored as a list on a property)
     type: object-based security
     example: if (!(caller in this.permitted_callers))
     note: useful only in some specialized circumstances

What is the most useful test for -x command line verbs?

  if (!$perm_utils:controls(player,this))
This allows the object owner, additional owners, or wizards access to the verb.

Why is it unacceptable to test "player" for security on +x verbs?

I'll give an example. Loro the lazy wizard writes a +x verb that can recycle any object and tests permissions with "if (!$perm_utils:controls(player,this))" at the verb's beginning. Semli the sneaky programmer builds an object and adds a "tell" verb to it (ie. a verb that gets called any time someone in the same room speaks). The "tell" verb calls Loro's +x verb and tells it to recycle all of Loro's objects. Semli puts the object in Loro's room...and Loro gets a nasty surprise after connecting. Neato eh! Note that "player" will be the person speaking (Loro in this case), because "player" is set to whoever initiates the action, and can only be changed by wiz-permed verbs. Generally, it stays the same from the task's start to it's finish. Now, if Loro had tested caller_perms(), then Semli's call would have been caught as one that did not have permission to be recycling objects. Got it?

What's the most secure test for +x non-command line verbs?

  if (caller != this)

When in doubt, use this one. It's the least flexible but the most secure.

How do I do permissions-based security for a +x command line verb?

The problem here is that you can't test caller_perms() on a command line verb, since the perms will be #-1. Note that this isn't a problem for object-based security, since "caller" for a command line verb will be the same as "player." To test security on a +x command line verb, replace "player" in a construct like:

     if (!$perm_utils:controls(player,this))
with an expression that will handle both command line and verb calls:
     if (!$perm_utils:controls( (valid(caller_perms())?caller_perms()|player) ,this))
Note that if caller_perms is #-1, then "player" is used, otherwise caller_perms is used.

Why are +x verbs called using pass() a special case?

One of the great things about MOO code is that the object-oriented nature lets you "cover" verbs by adding verbs of the same name on child objects. These can handle special cases, but otherwise simply pass(@args) down to the verb on the parent object instead. The problem is that if you use only perms-based security, this call (a legitimate one) will fail. Let's say you are testing with

     if (!$perm_utils:controls(caller_perms(),this))

which is generally very reasonable. If someone makes a new generic as a child of your verb, then caller_perms() will be that person, who is unlikely to "control" the object. The solution is to use a combination object-based and perms-based test such as:

if ( (caller==this) || !$perm_utils:controls(caller_perms(),this) )

What sort of combination security tests are reasonable?

Here's an example for us to dissect:

if ( (caller!=this) && !$perm_utils:controls(cp=caller_perms(),this)
      && (cp!=$code_utils:verb_perms()))

What's going on here? First, there's a test to see if caller!=this. That gives access to calls from other verbs on the same object and to calls via pass(). Then we check with $perm_utils:controls, which gives access to the object's owner, any additional owners, and to wizards. Finally, we test if the caller_perms are the same as the perms of the verb running (ie. the calling verb was written by us). This allows us to design objects that interact with each other. Note that this is a special circumstance, but one that's not terribly uncommon (eg. a class of objects and a feature object that interacts with them).


next up previous contents index external
Next: 11.3 Error handling Up: 11.2 Security Previous: 11.2 Security

Daniel K. Schneider
Thu Apr 17 12:43:52 MET DST 1997