-- Copyright (C) 1981, 1982, 1984, 1985  by Xerox Corporation. All rights reserved. 
-- Acl.mesa, Registration Server - Functions determining permissions of users.

-- HGM, 15-Sep-85  3:43:02
-- Randy Gobbel		19-May-81 13:14:59
-- Andrew Birrell	 4-Jan-82 17:01:56

DIRECTORY
  AclDefs USING [Permission],
  BodyDefs USING [RName],
  ProtocolDefs USING [RSOperation],
  RegServerDefs USING [IsInList],
  String USING [EquivalentString, EquivalentSubStrings, SubStringDescriptor];

Acl: PROGRAM IMPORTS RegServerDefs, String EXPORTS AclDefs =

  BEGIN

  EndsWith: PROC [s: LONG STRING, b: LONG STRING] RETURNS [BOOLEAN] = INLINE
    BEGIN
    pattern: String.SubStringDescriptor ← [b, 0, b.length];
    target: String.SubStringDescriptor ← [s, s.length - b.length, b.length];
    RETURN[
      s.length >= b.length AND String.EquivalentSubStrings[@pattern, @target]]
    END;

  CanOperate: PUBLIC PROCEDURE [
    op: ProtocolDefs.RSOperation, entry, caller: BodyDefs.RName]
    RETURNS [perm: AclDefs.Permission] =
    BEGIN
    Permission: PROCEDURE [where: {it, itsRegistry}, who: {owner, friend}]
      RETURNS [perm: AclDefs.Permission] =
      BEGIN
      -- [it, friend] and [it,owner] default to [itsRegistry,friend]
      -- [itsRegistry,friend] defaults to [itsRegistry,owner]
      IF caller = NIL OR caller.length = 0 THEN RETURN[no];
      perm ←
        SELECT RegServerDefs.IsInList[
        entry, caller, closure, IF where = it THEN self ELSE registry,
        IF who = owner THEN owners ELSE friends].membership FROM
          yes => yes,
          badList => yes --it will fail later, with better message-- ,
          no =>
            IF where = itsRegistry THEN
            IF who = owner THEN no ELSE Permission[itsRegistry, owner]
            ELSE Permission[itsRegistry, friend],
          ENDCASE => ERROR;
      END;


    perm ←
      SELECT op FROM

        -- Enquiries --
        Expand, ReadMembers, ReadOwners, ReadFriends, ReadEntry, CheckStamp,
          ReadConnect, ReadRemark, Authenticate, IdentifyCaller, IsMemberDirect,
          IsOwnerDirect, IsFriendDirect, IsMemberClosure, IsOwnerClosure,
          IsFriendClosure, IsInList => yes,

        -- Creation, Mailbox-sites --
        CreateIndividual, DeleteIndividual, CreateGroup, DeleteGroup, NewName,
          AddMailBox, DeleteMailBox => Permission[itsRegistry, owner],

        -- Ops on Individuals --
        ChangePassword, ChangeConnect =>
          IF String.EquivalentString[entry, caller] THEN yes
          ELSE Permission[itsRegistry, friend],

        AddForward, DeleteForward => Permission[itsRegistry, friend],

        -- Ops on Groups --
        ChangeRemark, AddMember, DeleteMember, AddListOfMembers =>
          IF EndsWith[entry, ".gv"L] THEN  -- protect "reg.gv" groups --
          Permission[itsRegistry, friend] ELSE Permission[it, owner],

        AddSelf, DeleteSelf =>
          IF EndsWith[entry, ".gv"L] THEN  -- protect "reg.gv" groups --
          IF caller # NIL AND EndsWith[caller, ".gv"L] THEN yes  -- caller is R-Server --
          ELSE Permission[itsRegistry, friend] ELSE Permission[it, friend],

        AddOwner, DeleteOwner, AddFriend, DeleteFriend => Permission[it, owner],

        ENDCASE => no;
    END;

  END.