# Production release 1.8.0 of the LambdaMOO server

Christopher Unkel (cunkel@us.itd.umich.edu)
Mon, 11 Mar 1996 22:23:09 PST

- Messages sorted by:[ date ][ thread ][ subject ][ author ]

    On Mon, 11 Mar 1996, Roger Crew wrote:

    [Changelog quotation snipped.]

    > If you must do something like this I would MUCH prefer the following:
    >
    >  -- If a built-in function FOO has been made wiz-only (by defining
    >     $server_options.protect_FOO with a true value), and a call is made
    > to that
    >     function from ANY VERB NOT DEFINED ON #0,
    >                   === ----------------------
    >     the server first checks to see if the verb #0:bf_FOO exists.
    >     If so, it calls it (REGARDLESS OF THE PERMISSIONS OF THE CALLING
    > VERB).
    >     If not, E_PERM is raised if the calling verb is nonwizardly
    >       (i.e., same behavior as before if #0:bf_FOO doesn't exist).

    Problem with this:  $server_options.protect_FOO doesn't mean what it's
    supposed to any more.  .protect_FOO is supposed to mean that foo() is
    wiz-restricted.  Now it means that *nobody* can call foo(), except from
    #0.  This seems to me to be a much more serious illogicality than the
    current system (not to mention backwards-compatibility).

    Under your proposal, if you want a built-in to be wizard-restricted (or
    have one currently that is this way), you have to write #0:bf_FOO:

    if (caller_perms().wizard)
      FOO(@args);
    endif

    Given that this is the most likely case of wanting to modify the behavior
    of a built-in, it seems silly to force this code to be written over and over.

    > The problem with the previous version is if I'm looking at some random
    > verb in the db and I see a call `create(...)', given that #0:bf_create
    > could do completely arbitrary things, I have NO IDEA what this call is
    > going to do unless I know the wizardliness of the verb.

    You have no idea what any code is going to do unless you know what
    permissions it's going to run under, including whether they are wiz perms
    (or programmer perms, and the individual player.) You never have and you
    never will.  The permissions of a verb determine what everything will do:
    what verb calls do, whether property assignments work, what built-ins will
    allow you to do, etc.

    Furthermore, what you suggest doesn't improve things.  If the problem is
    that you don't know what #0:bf_FOO does, then making the change you
    suggest just means that instead of having no idea what the call is going
    to do unless you know the wizardliness of the verb, you have no idea what
    the call is going to do EVEN IF you know the wizardliness of the verb.
    Nothing gained.  (#0:bf_FOO is likely to be readable or have a
    description in any case, I'd think, especially since the point of it is
    to modify the behavior for non-wizards.  Omitting a description of how
    #0:bf_FOO() differs from the built-in foo() is just sloppy coding, not a
    problem with this scheme.)

    > An underlying principle here should be:
    >
    >   A verb should have the same semantics regardless of its permissions.
    >
    > By semantics, I mean the sequence of actions it attempts to perform on
    > the db, property-writes and verb calls in particular.  The only
    > difference that should be made by changing the ownership of a verb to be
    > wizardly/nonwizardly is that in the nonwizard case there is the
    > possibility of it bombing out somewhere in this sequence of actions with
    > E_PERM.  In particular, a builtin function should not engage in an
    > entirely different sequence of actions if the verb is/isn't wizardly.  I
    > realize that

    This has some merit.  It does make things more complicated if functions do
    different things (more than just permission errors) based on who calls
    them.  The flexibility of it, however, allows enough useful things that
    it seems worth it to me.  This is especially true because of who it makes
    life more complicated for: wizards.  Ordinary programmers have to deal
    with one case: what it does for non-wizzes.  They have to know what the
    built-in does, and that it may be protected or redirected to a wrapped
    version.  Only wizards need to keep track of different cases: what it
    does under their own permissions, what it does under
    set_task_perms(whoever).  Wizards are going to need to know what's going
    on in any case (they either need to know when the built-in is going to do
    what, or when to call another verb.)

    Supporting example: $server_options.protect_create is set true because
    programmers are calling raw create() instead of requesting an object from
    the recycler, resulting in skyrocketing max_object() and gobs of recycled
    objects just sitting around.  #0:bf_foo is written to call the recycler's
    create; problem solved.

    However, there needs to be some way to call the built-in create, because:
    (1) Sometimes a fresh object is really desired, for example when creating
    new players, and
    (2) The recycler's create is going to need to call it if there are no
    recycled objects available.

    I'll quote out of order here.  You propose:

    > Note that if you want to have a raw version of a given callable from
    > arbitrary wizard code on other objects, my proposal still allows you to
    > define such a version on #0.  The difference is that it will now be
    > apparent from examination of said code which version of the builtin was
    > intended.  E.g., `$create(...)' is always the raw version while
    > `create(...)' is always #0:bf_create.

    I don't think that the clarity advantage is so great.  If I'm a wizard I
    ought to be able to keep track of what create() does for me.  If we do it
    your way, in order to wizard-protect a built-in, I've got to
    (1) set $server_options.protect_FOO to 1
    (2) write #0:foo with permisson check that calls built-in foo()
    (3) change all wizard-owned calls to FOO with calls to $FOO.
    whereas the way it is now all I need to do is (1).

    I'd guess that the existing method is ever so slightly more efficient as
    well.

    > (1)  There does exist one builtin function (queued_tasks()) that behaves
    > slightly differently depending on whether it is wizard-called or not.
    > This is a mistake from prehistory that has thus far been confined to
    > this one function.

    I don't see why this is a mistake.  To me this seems like a very logical
    and easy to remember way to make a function behave: called by a
    non-wizard, it applies only to the caller, but called by a wizard it
    applies to everyone.  This seems like an example of how this flexibility
    is useful.

    > (2)  Yes, it is possible to write verbs that explicitly depend on
    > caller_perms().  I maintain that it is bad style to use caller_perms()
    > for anything other than a permission check, i.e., to raise(E_PERM) or
    > return some appropriate failure value if caller_perms() aren't right,
    > otherwise continue.  I'll grant that one can't force people to use good
    > style, but if even the builtin functions don't behave this way, this
    > removes any possibility of getting the rest of the db to behave this
    > way.

    Using caller_perms() to make a verb behave differently (and for that
    matter, the similar but insecure player and caller) is a rather useful
    technique.  It permits interesting variation in the behavior of an object
    or verb based on who's using it.  Does it make things slightly more
    complicated?  Yes.  Is it worth it?  Yes.

      --Chris                           cunkel@engin.umich.edu
        ResComp Network Support Technician, Bursley Hall
        "Invisibility is in the eye of the beholder."
        Home Page: http://www-personal.engin.umich.edu/~cunkel/