CONCEPT
  Security

LAST UPDATE
  Mateese, 14-Jul-1996  02:30 MET

DESCRIPTION
  Security in microMud is based on permissions and protections, both values
  in the range from "!0" (lowest level) to "!1" (highest level), with lots
  of interim values.
  Every item (objects, actions, files) has a certain protection, which is
  on necessity compared with the permission of the active object. If the
  object's permission is higher or equal to the protection, the action may
  continue, else it fails. The order of the permissions is defined
  separately for each pair of permissions - there is not necessarily an
  overall order.
  The permission values of an object are stored as its uid and euid.
  The exception are players for whose the euid is the players 'real name'
  instead.

  However, the actual or 'effective' permission of an object is not
  determined by the objects intrinsic permission alone, but instead
  the lowest common denominator of the whole object call chain is chosen.
  Objects may liberately shorten this backtrace by demanding an 'unguarded'
  action, in this case the objects maximum permission are used as the
  base for the computation instead of that of the interactive user.

  This system is basically the same system Reimer 'Macbeth' Behrens
  suggested to the LPMud community Summer 1993, though it was developed
  independantly. The implementation microMud uses features just static
  permission-protection relationships - it is not possible to add
  permissions during runtime without changes to the servicing objects.

  microMud organizes the permissions into groups, with the group name being
  the permission value. By definition, each group name starts with '!' as
  first character.
  Some groups are subdivided horizontally with separate names for each
  horizontal division. In such cases the full permission value would be
  "<group>:<division>". More ':<division>` may be appended as well.
  The permission of an object are stored as its (e)uid, with exception of
  player objects (see below). The uid always shows the objects
  maximum permission, the euid the current permission to use (for now, micro
  keeps the current permission at the maximum).

  Currently these permissions are implemented:

    !1             : root, the topmost permission
    !private:<name>: Private data for user <name>
    !admin         : Mud administrators
    !arch          : Arch object, Domainlords.
    !member:<name> : Domain <name> member permissions
    !lord:<name>   : Domain <name> lord permissions
    !wizard:<name> : Wizard <name>
    !player:<name> : Player <name>
    !0             : bottom, the lowest permission

  A problem are the actual users, because for example a wizard may be lord
  in one domain, member in another, thus having two different permissions
  depending on the action to occur.
  Therefore, the permission stored as the users euid is just the <name>,
  which is internally evaluated as approbiate. When unguarded, the uid
  takes effect.
  A pleasant side effect is that the euid reflects the 'real' name of the
  object,

  Domainlords receive a special treatment, as their tasks are as global
  as those of archwizards. Though their 'true', stored clearance is that of
  a normal wizard, the game internally gives them archwizard permissions.

  The order of the permissions is in general this:

                            !1
                             |
                  ---------------------------------------
                 /                                       \
              !admin                                      |
                 |\                                       |
                 | -------------------
                 |                    \                   |
              !arch               !lord:<name>            |
                 |\                    |                  |
                 | ->------->-------->-+           !private:<name>
                 |                     |                  |
           !wizard:<name>              |                  |
                 |                !member:<name>          |
           !player:<name>              |                  |
                 \                     |                  /
                  ----------------------------------------
                             |
                            !0


  Learners (apprentice wizards) are not able to snoop non-players
  anonymously.

  Similar, the access to files of !private:<name> protection is allowed
  just with !(wizard,learner, player):<name> permission, where the <name>
  must match.

  Permissions and protections are derived from the filenames, in a way that
  the permissions/protections of a directory apply to all subfiles and
  -directories, if not specified otherwise.
  The permissions and protections are divided into: read protection, write
  protection, and object permission.
  The implemented structure is (with the '!' omitted for readability):

  /                  : r: 0;              w: arch;           o: 0
  +-adm              : r: 0;              w: admin;          o: 1
  +-b                : r: 0;              w: admin;          o: admin
  +-bin              : r: 0;              w: admin;          o: 1
  +-d                : r: 0;              w: arch;           o: 0
  | `-<dname>        : r: 0;              w: lord:<dname>;   o: lord:<dname>
  |   +-base         : r: 0;              w: member:<dname>; o: lord:<dname>
  |   `-<wizard>     : r: 0;              w: member:<dname>; o: lord:<dname>
  +-doc              : r: 0;              w: arch;           o: 0
  +-g                : r: 0;              w: arch;           o: arch
  +-i                : r: 0;              w: arch;           o: 0
  | `-sys            : r: 0;              w: admin;          o: 0
  +-log              : r: 0;              w: 0;              o: 0
  | `-adm            : r: 0;              w: arch;           o: 0
  +-save             : r: 0;              w: arch;           o: 0
  +-save             : r: 0;              w: arch;           o: 0
  | `-mail           : r: 0:              w: admin;          o: 0
  |   `-<n>          : r: 0:              w: admin;          o: 0
  |     `-<name>.o   : r: private:<name>; w: admin;          o: 0
  +-secure           : r: 0;              w: 1;              o: 1
  | `-save           : r: 0;              w: admin;          o: 0
  |   `-<n>          : r: 0;              w: admin;          o: 0
  |     `-<name>.o   : r: wizard:<name>;  w: admin;          o: 0
  +-std              : r: 0;              w: admin;          o: admin
  `-w                : r: 0;              w: arch;           o: 0
    `-<name>         : r: 0;              w: wizard:<name>;  o: wizard:<name>
      `-secure       : r: wizard:<name>;  w: wizard:<name>;  o: wizard:<name>


  The ID strings are defined as such:

    ROOTID     "!1"
    ADMINID    "!admin"
    ARCHID     "!arch"
    LORDID     "!lord"
    MEMBERID   "!member"
    WIZARDID   "!wizard"
    PLAYERID   "!player"
    PRIVATEID  "!private"
    BOTTOMID   "!0"

  The security is implemented in these simulated efuns:

    nomask string prot2domain (string prot)
      Return the name of the domain if the given protection concerns
      domain matters.
        prot: the protection to analyze
      Result:
        The name of the concerned domain, or 0.

   nomask string get_permission (object obj, void|string domain)
     Get the permission of an object.
       obj   : the object
       domain: the name of the domain if the permission is sought
               in respect to a domain, or 0 else.
     Result:
       The permission of the object.
       Normally this is the euid of the object (BOTTOMID if obj is 0).
       However, if the object is 'unguarded' the object's uid is returned
       as permission.
       Alternatively, if the object is or was interactive, the permission
       as returned by SECUREINFO->Permission() is returned.

   nomask string *get_protection (string file, void|object|string user)
     Get the protections for a file.
       file : the filename to analyze
       user: The name to use with relative filenames.
             It may also be an ID-permission, or 0.
     Result is an array with the three protections of <file>:
       [0]: the read protection
       [1]: the write protection
       [2]: the basic object permissions

   nomask int cmp_perm (string perm1, string perm2)
     Compare the two permissions/protections <perm1> and <perm2>.
     Result:
       = -2: the two perms are not compareable
       = -1: perm1 < perm2
       =  0: perm1 = perm2
       =  1: perm1 > perm2

   nomask string eff_perm (void|string domain, void|int|object skip)
     Evaluate the current effective permission.
       domain: the domainname if domain topics are concerned
       skip  : if integer, the 'n'th object to start the scan with
               else the object itself.
     Result:
       The evaluated permission.
     The function scans back through the call stack and evaluates the lowest
     common denomitor of all permissions.

   nomask int check_permission ( string|object prot
                               , void|int|object skip)
     Check the given protection against the effective permissions.
       prot: the protection to check against.
             If it is an object, the object's permissions is used.
       skip: if integer, the 'n'th object to start the scan with
             else the object itself.
     Result:
       != 0 if the action is allowed.

   mixed unguarded ( closure code , mixed arg1, mixed arg2
                                  , mixed arg3, mixed arg4
                   )
     Execute a closure unguarded (i.e. using the this_object()s full
     permissions).
       code   : the closure to execute.
       arg1..4: optional arguments to pass to the closure.
     Result:
       The result from the closure call.
    The code is executed within a catch(). If an error occurs, it is
    re-thrown.

   string username (object ob)  [MACRO]
     The current protection of <ob>, which for interactive players
     is the username.
     This is just geteuid(ob).


SEE ALSO
  levels(basics)
