DIRECTORY Ascii USING [Lower], BasicTime USING [GetClockPulses], Convert USING [CardFromRope, Error], RefText USING [New, TrustTextAsRope], Rope USING [Equal, FromRefText, ROPE, ToRefText], SunAuthUnix USING [Groups, GroupsObject], SunRPC USING [CloseReader, CloseWriter, Error, GetCard32, GetRope, Handle, OpenReader, OpenWriter, PutCard32, PutRope], SunRPCAuth USING [AuthenticateProc, CheckReplyVerifierProc, Conversation, ConversationObject, Error, GetCredentialsAndNextVerifierProc, InitiateProc, NoShortcutProc, nullFlavor, Procs, ProcsObject, Register, shortFlavor, SweepProc, TerminateProc, unixFlavor], SunYPAgent USING [Error, First, Handle, Match, Next, ObtainHandle, ReleaseHandle, TextSeq, TokenizeUsingSeparator], ThisMachine USING [Name] ; SunAuthUnixImpl: CEDAR MONITOR LOCKS lock USING lock: Lock IMPORTS Ascii, BasicTime, Convert, RefText, Rope, SunRPC, SunRPCAuth, SunYPAgent, ThisMachine EXPORTS SunAuthUnix ~ { ROPE: TYPE ~ Rope.ROPE; Conversation: TYPE ~ SunRPCAuth.Conversation; ConversationObject: TYPE ~ SunRPCAuth.ConversationObject; Lock: TYPE ~ REF LockObject; LockObject: TYPE ~ MONITORED RECORD []; initialTTL: CARDINAL _ 3600; passwordMapName: ROPE _ "passwd.byname"; groupMapName: ROPE _ "group.byname"; passwordPos: CARDINAL ~ 1; uidPos: CARDINAL ~ 2; gidPos: CARDINAL ~ 3; grpNamePos: CARDINAL ~ 0; grpNumPos: CARDINAL ~ 2; grpMembersPos: CARDINAL ~ 3; maxGroups: CARDINAL ~ 9; -- the 0th slot is filled with gid from passwd file, leaving 9 maxCredentialsBytes: CARDINAL _ 350; maxUnixNameLen: CARDINAL _ 8; ConversationData: TYPE ~ REF ConversationDataObject; ConversationDataObject: TYPE ~ RECORD [ next: ConversationData, conversation: Conversation, ttl: CARDINAL _ initialTTL, name, password: ROPE, credentials: REF TEXT, shortCredentials: REF TEXT ]; conversationDataCache: ConversationData _ NIL; conversationCacheLock: Lock _ NEW[LockObject]; GetConversationFromCache: ENTRY PROC [name, password: ROPE, lock: Lock _ conversationCacheLock] RETURNS [c: Conversation] ~ { p, prev: ConversationData; p _ conversationDataCache; WHILE p # NIL DO IF Rope.Equal[p.name, name] AND Rope.Equal[p.password, password] THEN EXIT; prev _ p; p _ p.next; ENDLOOP; IF p = NIL THEN RETURN [NIL]; IF prev = NIL THEN conversationDataCache _ p.next ELSE prev.next _ p.next; RETURN [p.conversation]; }; PutConversationIntoCache: ENTRY PROC [c: Conversation, lock: Lock _ conversationCacheLock] ~ { cD: ConversationData ~ NARROW[c.conversationData]; cD.next _ conversationDataCache; conversationDataCache _ cD; }; Sweep: SunRPCAuth.SweepProc -- [registrationData, secondsSinceLastSweep] -- ~ { SweepInner[secondsSinceLastSweep]; }; SweepInner: ENTRY PROC [secs: CARD, lock: Lock _ conversationCacheLock] ~ { p, prev: ConversationData; p _ conversationDataCache; WHILE p # NIL DO IF p.ttl > secs THEN { p.ttl _ p.ttl - secs; prev _ p; } ELSE { IF prev = NIL THEN conversationDataCache _ p.next ELSE prev.next _ p.next; }; p _ p.next; ENDLOOP; }; UnixPasswordMatches: PROC [uid: CARD, name, password, encryptedPassword: ROPE] RETURNS [matches: BOOL] ~ { RETURN [TRUE]; }; FixNameForUnix: PUBLIC PROC [name: ROPE] RETURNS [fixedName: ROPE] ~ { buffer: REF TEXT _ Rope.ToRefText[name]; i: CARDINAL _ 0; len: CARDINAL _ MIN[buffer.length, maxUnixNameLen]; DO c: CHAR; IF (i >= len) OR ((c _ buffer[i]) = '.) THEN EXIT; buffer[i] _ Ascii.Lower[c]; i _ i + 1; ENDLOOP; buffer.length _ i; fixedName _ Rope.FromRefText[buffer]; }; nullVerifier: REF TEXT _ RefText.New[0]; stamp: CARD _ BasicTime.GetClockPulses[]; stampLock: Lock _ NEW[LockObject]; GetStamp: PROC [lock: Lock _ stampLock] RETURNS [CARD] ~ { RETURN [stamp _ stamp + 1]; }; Groups: TYPE ~ REF GroupsObject; GroupsObject: TYPE ~ RECORD [ nGroups: CARDINAL _ 0, groups: ARRAY [0..maxGroups) OF CARD ]; GetGroupsWithGivenMember: PROC [h: SunYPAgent.Handle, name: ROPE] RETURNS [g: Groups] ~ { g _ NEW[GroupsObject]; { ENABLE SunYPAgent.Error, Convert.Error => GOTO GiveUp; keyBefore: ROPE; val: REF TEXT; [keyBefore, val] _ SunYPAgent.First[h, groupMapName]; DO seq: SunYPAgent.TextSeq; gid: CARD; seq _ SunYPAgent.TokenizeUsingSeparator[val, ':]; IF seq.length <= grpNumPos THEN GOTO GiveUp; gid _ Convert.CardFromRope[RefText.TrustTextAsRope[seq.refText[grpNumPos]]]; IF seq.length <= grpMembersPos THEN GOTO GiveUp; seq _ SunYPAgent.TokenizeUsingSeparator[seq.refText[grpMembersPos], ',]; FOR i: CARDINAL IN [0 .. seq.length) DO IF Rope.Equal[RefText.TrustTextAsRope[seq.refText[i]], name, TRUE] THEN { g.groups[g.nGroups] _ gid; g.nGroups _ g.nGroups + 1; EXIT; }; ENDLOOP; IF g.nGroups >= maxGroups THEN EXIT; [keyBefore, val] _ SunYPAgent.Next[h, groupMapName, keyBefore]; ENDLOOP; EXITS GiveUp => NULL; }; }; GetConversationByContactingYPServer: PROC [name, password: ROPE] RETURNS [c: Conversation] ~ { credentials, val: REF TEXT; seq: SunYPAgent.TextSeq; uid, gid: CARD; h: SunYPAgent.Handle; hW: SunRPC.Handle; errorCode: ATOM _ NIL; { ENABLE { SunYPAgent.Error => { errorCode _ (SELECT code FROM $noYP, $domainNotFound, $timeout => $timeout, $keyNotFound => $wrongUserPassword, ENDCASE => $protocol); GOTO Cant; }; Convert.Error => { errorCode _ $protocol; GOTO Cant; }; }; h _ SunYPAgent.ObtainHandle[]; val _ SunYPAgent.Match[h, passwordMapName, name]; seq _ SunYPAgent.TokenizeUsingSeparator[val, ':]; IF seq.length <= gidPos THEN { errorCode _ $protocol; GOTO Cant }; uid _ Convert.CardFromRope[RefText.TrustTextAsRope[seq.refText[uidPos]]]; gid _ Convert.CardFromRope[RefText.TrustTextAsRope[seq.refText[gidPos]]]; IF NOT UnixPasswordMatches[uid, name, password, RefText.TrustTextAsRope[seq.refText[passwordPos]]] THEN { errorCode _ $wrongUserPassword; GOTO Cant }; hW _ SunRPC.OpenWriter[maxCredentialsBytes]; SunRPC.PutCard32[hW, GetStamp[]]; SunRPC.PutRope[hW, ThisMachine.Name[--$Arpa--]]; -- Have to fix ThisMachineImpl! SunRPC.PutCard32[hW, uid]; SunRPC.PutCard32[hW, gid]; { g: Groups _ GetGroupsWithGivenMember[h, name]; SunRPC.PutCard32[hW, g.nGroups + 1]; SunRPC.PutCard32[hW, gid]; FOR i: CARDINAL IN [0 .. g.nGroups) DO SunRPC.PutCard32[hW, g.groups[i]]; ENDLOOP; }; credentials _ SunRPC.CloseWriter[hW]; hW _ NIL; EXITS Cant => NULL; }; IF h # NIL THEN { SunYPAgent.ReleaseHandle[h]; h _ NIL }; IF hW # NIL THEN { [] _ SunRPC.CloseWriter[hW]; hW _ NIL }; IF errorCode # NIL THEN ERROR SunRPCAuth.Error[errorCode]; c _ NEW[ConversationObject _ [SunRPCAuth.unixFlavor, myProcs, NIL]]; c.conversationData _ NEW[ConversationDataObject _ [conversation~c, name~name, password~password, credentials~credentials]]; }; Initiate: SunRPCAuth.InitiateProc -- [flavor, myName, myPassword, hisName, registrationData] RETURNS [c] -- ~ { IF flavor # SunRPCAuth.unixFlavor THEN ERROR; c _ GetConversationFromCache[myName, myPassword]; IF c = NIL THEN c _ GetConversationByContactingYPServer[myName, myPassword]; }; Authenticate: SunRPCAuth.AuthenticateProc -- [cFlavor, credentials, vFlavor, verifier, registrationData] RETURNS [result, replyFlavor, replyVerifier, c] -- ~ { replyFlavor _ SunRPCAuth.nullFlavor; replyVerifier _ nullVerifier; IF cFlavor # SunRPCAuth.unixFlavor THEN ERROR; IF vFlavor # SunRPCAuth.nullFlavor THEN { result _ wrongVerifier; RETURN }; c _ NEW[ConversationObject _ [SunRPCAuth.unixFlavor, myProcs, NIL]]; c.conversationData _ NEW[ConversationDataObject _ [credentials~credentials]]; result _ ok; }; ExtractConversationDetails: PUBLIC PROC [c: Conversation] RETURNS [machineName: ROPE, uid, gid: CARD, groups: SunAuthUnix.Groups] ~ { cD: ConversationData _ NARROW[c.conversationData]; hR: SunRPC.Handle _ SunRPC.OpenReader[cD.credentials]; { ENABLE { SunRPC.Error => { ERROR SunRPCAuth.Error[$badCredentials] }; UNWIND => { SunRPC.CloseReader[hR] }; }; numIDs: CARDINAL; [] _ SunRPC.GetCard32[hR]; -- stamp machineName _ SunRPC.GetRope[hR]; -- machineName uid _ SunRPC.GetCard32[hR]; gid _ SunRPC.GetCard32[hR]; numIDs _ SunRPC.GetCard32[hR]; groups _ NEW[SunAuthUnix.GroupsObject[numIDs]]; FOR i: CARDINAL IN [0 .. numIDs) DO groups.group[i] _ SunRPC.GetCard32[hR]; ENDLOOP; }; SunRPC.CloseReader[hR]; }; GetCredentialsAndNextVerifier: SunRPCAuth.GetCredentialsAndNextVerifierProc -- [c] RETURNS [cFlavor, credentials, vFlavor, verifier] -- ~ { cD: ConversationData ~ NARROW[c.conversationData]; IF cD.shortCredentials # NIL THEN RETURN [SunRPCAuth.shortFlavor, cD.shortCredentials, SunRPCAuth.nullFlavor, nullVerifier]; RETURN [SunRPCAuth.unixFlavor, cD.credentials, SunRPCAuth.nullFlavor, nullVerifier]; }; CheckReplyVerifier: SunRPCAuth.CheckReplyVerifierProc -- [c, flavor, verifier] RETURNS [result: SunRPCAuth.AuthenticateResult] -- ~ { IF flavor = SunRPCAuth.nullFlavor THEN RETURN [ok]; IF flavor = SunRPCAuth.shortFlavor THEN { cD: ConversationData ~ NARROW[c.conversationData]; cD.shortCredentials _ verifier; RETURN [ok]; }; RETURN [wrongVerifier]; }; NoShortcut: SunRPCAuth.NoShortcutProc -- [c] RETURNS [wasShortcut] -- ~ { cD: ConversationData ~ NARROW[c.conversationData]; wasShortcut _ (cD.shortCredentials # NIL); cD.shortCredentials _ NIL; }; Terminate: SunRPCAuth.TerminateProc -- [c] -- ~ { cD: ConversationData ~ NARROW[c.conversationData]; cD.shortCredentials _ NIL; PutConversationIntoCache[c]; }; myProcs: SunRPCAuth.Procs _ NEW[SunRPCAuth.ProcsObject _ [GetCredentialsAndNextVerifier, CheckReplyVerifier, NoShortcut, Terminate]]; SunRPCAuth.Register[SunRPCAuth.unixFlavor, Initiate, Authenticate, Sweep, NIL]; }... ΈSunAuthUnixImpl.mesa Demers, October 12, 1987 10:42:31 am PDT Types Parameters Conversation Cache Unix Utilities YP Client Note gid (from passwd line) is put into credentials twice. I don't know why this should be necessary, but the Sun code does it ... Registered Procedures This is grossly inefficient, but Cedar servers shouldn't use Unix-flavor authentication anyway, since it's so awful ... Client Procs Object Initialization Κ b˜codešœ™K™(K˜—šΟk ˜ Kšœœ ˜Kšœ œ˜!Kšœœ˜$Kšœœ˜%Kšœœœ ˜1Kšœ œ˜)Kšœœk˜wKšœ œσ˜ƒKšœ œc˜sKšœ œ˜K˜K˜—šΟnœœ˜Kšœœ ˜KšœV˜]Kšœ ˜K˜head™Kšœœœ˜K˜Kšœœ˜-Kšœœ!˜9K˜Kšœœœ ˜Kšœ œ œœ˜'—™ Kšœ œ˜K˜Kšœœ˜(Kšœœ˜$K˜Kšœ œ˜Kšœœ˜Kšœœ˜K˜Kšœ œ˜Kšœ œ˜Kšœœ˜Kšœ œΟc>˜WK˜Kšœœ˜$Kšœœ˜—™Kšœœœ˜4šœœœ˜'Kšœ˜K˜Kšœ œ ˜Kšœœ˜Kšœ œ˜Kšœœ˜K˜K˜—Kšœ*œ˜.šœœ ˜.K˜—š žœœœœ&œ˜}K˜Kšœ˜šœœ˜Kšœœ"œœ˜LK˜Kšœ˜—Kš œœœœœ˜Kšœœœ œ˜JKšœ˜K˜K˜—šžœœœ:˜^Kšœœ˜2Kšœ ˜ Kšœ˜K˜K˜—šžœŸ/œ˜OK˜"K˜K˜—šž œœœœ)˜KK˜Kšœ˜šœœ˜šœ ˜šœ˜K˜K˜ K˜—šœ˜Kšœœœ œ˜JK˜——K˜ Kšœ˜—J˜——™š žœœœ%œœ œ˜jKšœœ˜K˜K˜—š žœœœœœ œ˜FKšœœœ˜(Kšœœ˜Kšœœœ ˜3š˜Kšœœ˜Kšœ œœœ˜2K˜K˜ Kšœ˜—K˜K˜%K˜—K™—™ Kšœœœ˜(K˜Kšœœ˜)Kšœœ ˜"K˜šžœœœœ˜:Kšœ˜Kšœ˜—K˜Kšœœœ˜ šœœœ˜Kšœ œ˜Kšœœœ˜$K˜K˜—šžœœœœ˜YKšœœ˜šœœ$œ˜8Kšœ œ˜Kšœœœ˜K˜5š˜K˜Kšœœ˜ K˜1Kšœœœ˜,KšœL˜LKšœœœ˜0KšœH˜Hšœœœ˜'šœ;œœ˜IKšœ˜K˜Kšœ˜K˜—Kšœ˜—Kšœœœ˜$K˜?Kšœ˜—š˜Kšœ œ˜—K˜—K˜K˜—šž#œœœœ˜^Kšœœœ˜K˜Kšœ œ˜K˜K˜Kšœ œœ˜šœ˜šœ˜šœ˜šœ œ˜K˜-K˜#Kšœ˜—Kšœ˜ K˜—šœ˜Kšœ˜Kšœ˜ Kšœ˜—K˜—Kšœ˜K˜1K˜1Kšœœœ˜BK˜IK˜IKšœœ]œ#œ˜–K˜K˜,K˜!Kšœ$Ÿ œŸ˜PK˜K˜šœ0˜0K™ƒKšœ$˜$Kšœ˜šœœœ˜&Kšœ"˜"Kšœ˜—K˜—Kšœ,œ˜0š˜Kšœœ˜ —K˜—Kšœœœ$œ˜9Kšœœœ&œ˜