<> <> <> DIRECTORY Agent USING [ Authentication, AuthenticationRecord, Authenticator, AuthenticatorLayout, Frob, FrobRecord, Principal ], AgentRpcControl USING [ ExportInterface, InterfaceName ], Commander USING [ CommandProc, Register ], DESFace USING [ Block, Blocks, CBCCheckEncrypt, CorrectParity, EncryptBlock, GetRandomKey, Key, nullKey ], IO, NamesGV USING [ AttributeSeq, GVGetAttribute, GVGetAttributeSeq, GVIsAuthenticated ], PupDefs USING [ GetPupAddress, PupAddress ], PupTypes USING [ PupHostID, PupNetID ], Rope USING [ Concat, Equal, Length, Flatten, ROPE ], RPC USING [ EncryptionKey, ExportFailed, matchAllVersions, ShortROPE, VersionRange ], RPCPkt USING [ Machine ], RPCInternalExtras USING [ CopyPrincipal ], UserProfile USING [ Token ], VoiceUtils USING [ CurrentPasskey, InstanceFromNetAddress, Report, Problem ] ; AgentImpl: CEDAR PROGRAM IMPORTS AgentRpcControl, Commander, DESFace, IO, NamesGV, PupDefs, Rope, RPC, RPCInternalExtras, UserProfile, VoiceUtils EXPORTS Agent = { OPEN IO; <> blockSize: NAT = SIZE[DESFace.Block]; larkRegistry: Rope.ROPE _ ".Lark"; agentExported: BOOL _ FALSE; defaultServerInstance: Rope.ROPE _ UserProfile.Token[key: "ThrushServerInstance", default: "Morley.Lark"]; Authenticate: PUBLIC PROC [ nonceId: LONG INTEGER, a, b: Agent.Principal ] RETURNS [ an: Agent.Frob, ar: Agent.Frob ] = TRUSTED { ka, kb: DESFace.Key _ DESFace.nullKey -- !!! --; kx, ky, ck: DESFace.Key; aLen: NAT=a.Length[]; bLen: NAT=b.Length[]; authenticator: Agent.Authenticator; authentication: Agent.Authentication; nBlks: NAT _ DESBlocks[SIZE[Agent.AuthenticatorLayout[aLen]]]; IF a=NIL OR b=NIL OR aLen=0 OR bLen=0 THEN { VoiceUtils.Problem["Authenticate: Null arguments", $System]; RETURN[NIL, NIL]; }; ar _ NEW[Agent.FrobRecord[nBlks*blockSize]]; authenticator _ LOOPHOLE[@ar[0]]; a _ a.Flatten[]; b _ b.Flatten[]; DESFace.CorrectParity[@ka]; DESFace.CorrectParity[@kb]; kx _ DESFace.GetRandomKey[]; ky _ DESFace.GetRandomKey[]; ck _ DESFace.GetRandomKey[]; -- Build and encrypt Authenticator -- DESFace.EncryptBlock[key: kb, from: Blk[LONG[@ky]], to: Blk[@authenticator.ky ]]; DESFace.EncryptBlock[key: kb, from: Blk[LONG[@ck]], to: Blk[@authenticator.ck ]]; authenticator.time _ 0; RPCInternalExtras.CopyPrincipal[from: a, to: @(authenticator.a)]; DESFace.CBCCheckEncrypt[key: ky, nBlks: nBlks-2, from: Blks[@authenticator.ck], to: Blks[@authenticator.ck], seed: [0,0,0,0] ]; <> DESFace.CBCCheckEncrypt[key: kx, nBlks: nBlks, from: Blks[@authenticator.ky], to: Blks[@authenticator.ky], seed: [0,0,0,0] ]; <> nBlks _ DESBlocks[SIZE[Agent.AuthenticationRecord[bLen]]]; an _ NEW[Agent.FrobRecord[nBlks*blockSize]]; authentication _ LOOPHOLE[@an[0]]; authentication.nonceId _ nonceId; DESFace.EncryptBlock[key: ka, from: Blk[LONG[@kx]],to: Blk[@authentication.kx] ]; DESFace.EncryptBlock[key: ka, from: Blk[LONG[@ck]], to: Blk[@authentication.ck ]]; RPCInternalExtras.CopyPrincipal[from: b, to: @authentication.b]; DESFace.CBCCheckEncrypt[key: kx, nBlks: nBlks-2, from: Blks[@authentication.ck], to: Blks[@authentication.ck], seed: [0,0,0,0] ]; VoiceUtils.Report[IO.PutFR["Authenticate[%s, to; %s]", rope[a], rope[b]], $System]; }; DESBlocks: PROC[len: NAT] RETURNS [nBlks: NAT] = { RETURN [ (len + blockSize - 1) / blockSize ]; }; Blk: PROC[p: LONG POINTER] RETURNS [LONG POINTER TO DESFace.Block] = TRUSTED INLINE { RETURN [LOOPHOLE[p]]; }; Blks: PROC[p: LONG POINTER] RETURNS [DESFace.Blocks] = TRUSTED INLINE { RETURN [LOOPHOLE[p]]; }; <> Vitae: PUBLIC PROC[ clientMachine: RPCPkt.Machine, range: RPC.VersionRange_RPC.matchAllVersions, interfaceType: RPC.ShortROPE ] RETURNS [ serverMachine: RPCPkt.Machine_[[0],[0]], clientRname: Agent.Principal, clientInstance: RPC.ShortROPE_NIL, serverInstance: RPC.ShortROPE_NIL ] = TRUSTED { <> serverMachineRope: RPC.ShortROPE; clientMachineRName: RPC.ShortROPE; pa: PupDefs.PupAddress; interfaceSeq: NamesGV.AttributeSeq; comment: Rope.ROPE _ NIL; clientInstance _ VoiceUtils.InstanceFromNetAddress[clientMachine, "0"]; clientMachineRName _ VoiceUtils.InstanceFromNetAddress[clientMachine, larkRegistry]; SELECT NamesGV.GVIsAuthenticated[clientMachineRName] FROM bogus, nonexistent, unknown => comment _ "RName is unknown or invalid. "; authentic, perhaps => { clientRname _ NamesGV.GVGetAttribute[clientMachineRName, $owner, NIL]; interfaceSeq _ NamesGV.GVGetAttributeSeq[clientMachineRName, $interface]; <> IF interfaceSeq#NIL THEN { IF ~interfaceType.Equal[interfaceSeq[0].attributeValue, FALSE] THEN comment _ comment.Concat[IO.PutFR["GV interface type is %s. ", rope[interfaceSeq[0].attributeValue]]]; serverInstance _ interfaceSeq[1].attributeValue; }; IF serverInstance=NIL THEN serverInstance _ defaultServerInstance; serverMachineRope _ NamesGV.GVGetAttribute[ serverInstance, $connect, NIL ]; IF serverMachineRope#NIL THEN { pa _ PupDefs.GetPupAddress[[0,0], serverMachineRope]; serverMachine _ [net: pa.net, host: pa.host]; } ELSE comment _ comment.Concat["Instance has not been exported. "]; }; ENDCASE=>ERROR; VoiceUtils.Report[ IO.PutFR["Vitae[lark: %b, type: %s] -> [ rName: %s, client: %s, server: %s]", card[clientMachine.host], rope[interfaceType], rope[clientRname], rope[clientInstance], rope[serverInstance]], $System]; IF comment#NIL THEN VoiceUtils.Report[IO.PutFR[" (%s)", rope[comment]], $System]; }; <> AgentInit: Commander.CommandProc = { ENABLE RPC.ExportFailed => { VoiceUtils.Problem["Agent export failed", $System]; GOTO Failed; }; myName: AgentRpcControl.InterfaceName = [ type: "Agent.Lark", instance: UserProfile.Token[key: "AgentInstance", default: "Michaelson.Lark"]]; serverPassword: RPC.EncryptionKey = VoiceUtils.CurrentPasskey[UserProfile.Token[ key: "AgentPassword", default: "MFLFLX"]]; IF agentExported THEN RETURN; AgentRpcControl.ExportInterface[ interfaceName: myName, user: myName.instance, password: serverPassword]; VoiceUtils.Report[IO.PutFR["Agent exported as %s", rope[myName.instance]], $System]; agentExported _ TRUE; EXITS Failed => NULL; }; Commander.Register["Agent", AgentInit, "Export Registration/Authentication Agent"]; }.