-- Registration Server - Functions determining permissions of users.

-- [Juniper]<Grapevine>MS>Acl.mesa

-- 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: STRING, b: 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.