-- Copyright (C) 1981, 1984, 1985 by Xerox Corporation. All rights reserved. -- LocalName.mesa - R-Name of this registration or mail server -- HGM, 15-Sep-85 4:24:11 -- Randy Gobbel 19-May-81 22:32:55 -- -- Andrew Birrell 17-Mar-81 15:06:46 -- DIRECTORY Ascii, BodyDefs USING [maxRNameLength, RName], Heap USING [systemMDSZone, systemZone], HeapDefs USING [ HeapEndRead, HeapEndWrite, HeapStartRead, HeapStartWrite, HeapReadData, HeapReadRName, HeapWriteData, HeapWriteRName, HeapWriteString, ReaderHandle, WriterHandle], IODefs, LocalNameDefs USING [], LocateDefs USING [FindLocalServer, FindRegServer, FoundServerInfo], NameInfoDefs USING [Authenticate, GetConnect, NameType], ObjectDirDefs USING [Enumerate, FreeObject, noObject, ObjectNumber, UseObject], ProtocolDefs, PupDefs USING [ AppendPupAddress, GetPupAddress, PupAddress, PupNameTrouble, PupSocketID], String USING [AppendString, EquivalentString, WordsForString]; LocalName: MONITOR [initHeap: BOOLEAN] LOCKS info USING info: LONG POINTER TO NameInfo IMPORTS Heap, HeapDefs, IODefs, LocateDefs, NameInfoDefs, ObjectDirDefs, ProtocolDefs, PupDefs, String EXPORTS LocalNameDefs = BEGIN OPEN IODefs; NameInfo: TYPE = MONITORED RECORD [ name: BodyDefs.RName ← NIL, password: LONG STRING ← NIL, key: ProtocolDefs.Password, known: BOOLEAN ← FALSE]; MSInfo: LONG POINTER TO NameInfo ← Heap.systemZone.NEW[NameInfo]; RSInfo: LONG POINTER TO NameInfo ← Heap.systemZone.NEW[NameInfo]; ReadMSName: PUBLIC PROCEDURE RETURNS [name: BodyDefs.RName, password: LONG STRING, key: ProtocolDefs.Password] = {[name, password, key] ← ReadName[MSInfo]}; ReadRSName: PUBLIC PROCEDURE RETURNS [name: BodyDefs.RName, password: LONG STRING, key: ProtocolDefs.Password] = {[name, password, key] ← ReadName[RSInfo]}; ReadName: PROC [info: LONG POINTER TO NameInfo] RETURNS [name: BodyDefs.RName, password: LONG STRING, key: ProtocolDefs.Password] = BEGIN IF PossiblyFindName[info] THEN CheckConnect[info] --this call must be outside the monitor-- ; RETURN[info.name, info.password, info.key] END; PossiblyFindName: ENTRY PROC [info: LONG POINTER TO NameInfo] RETURNS [first: BOOLEAN] = { first ← NOT info.known; IF first THEN FindName[info]}; BadHeapNameObject: SIGNAL = CODE; FindName: INTERNAL PROC [info: LONG POINTER TO NameInfo] = BEGIN which: {mail, reg} = IF info = MSInfo THEN mail ELSE reg; changed: BOOLEAN ← FALSE; oldObj: ObjectDirDefs.ObjectNumber ← ObjectDirDefs.noObject; text: STRING = IF which = reg THEN "R-Server"L ELSE "M-Server"L; FindObject: PROCEDURE [obj: ObjectDirDefs.ObjectNumber] RETURNS [BOOLEAN] = BEGIN reader: HeapDefs.ReaderHandle = HeapDefs.HeapStartRead[obj]; Read: PROCEDURE [to: LONG POINTER, amount: CARDINAL] = BEGIN used: CARDINAL; [, used] ← HeapDefs.HeapReadData[reader, [to, amount]]; IF used # amount THEN BEGIN SIGNAL BadHeapNameObject[]; info.known ← FALSE END; END; temp: STRING = [0]; info.known ← TRUE; [] ← HeapDefs.HeapReadRName[reader, info.name]; Read[temp, String.WordsForString[0]]; IF temp.length > info.password.maxlength THEN BEGIN SIGNAL BadHeapNameObject[]; info.known ← FALSE END; info.password.length ← temp.length; Read[ @(info.password.text), String.WordsForString[info.password.length] - String.WordsForString[0]]; Read[@(info.key), SIZE[ProtocolDefs.Password]]; HeapDefs.HeapEndRead[reader]; IF info.known THEN { ObjectDirDefs.UseObject[oldObj ← obj]; RETURN[TRUE] -- terminate -- } ELSE RETURN[FALSE] --keep going-- END; AskOthers: INTERNAL PROCEDURE = BEGIN info.name.length ← 0; WriteLine["Consulting registration servers ... "L]; SELECT LocateDefs.FindLocalServer[ IF which = reg THEN "GV.GV"L ELSE "MailDrop.MS"L, info.name] FROM allDown => WriteLine["all down"L]; notFound => WriteLine["no local name found"L]; found => info.known ← TRUE; ENDCASE => ERROR; IF NOT info.known THEN BEGIN ConfirmSystem[]; String.AppendString[info.name, "Anon.GV"L]; info.known ← TRUE; END; WriteString["My "L]; WriteString[text]; WriteString[" name appears to be "L]; WriteLine[info.name]; WriteString["If you are certain the name is correct, type my password: "L]; info.key ← ReadPassword[info.password]; WriteLine[""L]; changed ← TRUE; END; info.name ← Heap.systemMDSZone.NEW[StringBody[BodyDefs.maxRNameLength]]; info.password ← Heap.systemZone.NEW[StringBody[32]]; [] ← ObjectDirDefs.Enumerate[ IF which = reg THEN RSname ELSE MSname, FindObject]; IF NOT info.known THEN BEGIN WriteString["No "]; WriteString[text]; WriteLine[" name is recorded in the heap"L]; IF NOT initHeap THEN ConfirmSystem[] END ELSE BEGIN WriteString[text]; WriteString[" name recorded in the heap is "L]; WriteLine[info.name]; END; DO UNTIL info.known DO AskOthers[]; ENDLOOP; SELECT NameInfoDefs.Authenticate[info.name, info.password] FROM individual => EXIT; notFound, group => BEGIN WriteString[text]; WriteLine[" name is not valid"L]; ConfirmSystem[]; info.known ← FALSE; END; allDown => BEGIN WriteString["No authentication server available"L]; ConfirmSystem[]; EXIT END; badPwd => BEGIN WriteString["My password is incorrect; please re-type it: "L]; info.key ← ReadPassword[info.password]; WriteLine[""L]; changed ← TRUE; END; ENDCASE => ERROR; ENDLOOP; IF changed THEN BEGIN -- create the heap object -- writer: HeapDefs.WriterHandle = HeapDefs.HeapStartWrite[ IF which = reg THEN RSname ELSE MSname]; Keep: PROCEDURE [obj: ObjectDirDefs.ObjectNumber] = BEGIN ObjectDirDefs.UseObject[obj]; END; HeapDefs.HeapWriteRName[writer, info.name]; HeapDefs.HeapWriteString[writer, info.password]; HeapDefs.HeapWriteData[writer, [@(info.key), SIZE[ProtocolDefs.Password]]]; HeapDefs.HeapEndWrite[writer, Keep]; IF oldObj # ObjectDirDefs.noObject THEN ObjectDirDefs.FreeObject[oldObj]; END; END; system: BOOLEAN ← FALSE; ConfirmSystem: PROCEDURE = BEGIN -- In principle, we should keep only a one-way function of the -- system password in this source (e.g. [0,0,0,0] encrypted with the -- system password), and then check for equality with what the user -- types. In practice, the system password is only there to prevent -- idiots messing up the system in some error cases (when the idiot -- has physical access to the computer), so proper security isn't -- worth the trouble. sysPwd: STRING = "Botrytis"L; hisAttempt: STRING = [32]; IF system THEN BEGIN WriteString["Continue? [confirm] "L]; UNTIL SELECT IODefs.ReadChar[] FROM Ascii.CR, 'y, 'Y => TRUE, ENDCASE => FALSE DO NULL ENDLOOP; WriteLine["yes"L]; END ELSE DO WriteLine["*****"L]; WriteLine["***** Something horrible has happened."L]; WriteLine["***** You should probably consult a Wizard."L]; WriteLine["*****"L]; WriteString["Type the system password to continue: "L]; [] ← ReadPassword[hisAttempt]; IF String.EquivalentString[hisAttempt, sysPwd] THEN { system ← TRUE; WriteLine[" ... ok"L]; EXIT} ELSE WriteLine[" ... incorrect"L]; ENDLOOP; END; ReadPassword: PROCEDURE [pwd: LONG STRING] RETURNS [key: ProtocolDefs.Password] = BEGIN pwd.length ← 0; DO BEGIN c: CHARACTER = IODefs.ReadChar[]; SELECT c FROM Ascii.SP, Ascii.TAB, Ascii.CR, Ascii.ESC => EXIT; Ascii.BS, Ascii.ControlA => IF pwd.length > 0 THEN BEGIN pwd.length ← pwd.length - 1; WriteChar[Ascii.BS]; END; ENDCASE => IF pwd.length < pwd.maxlength THEN BEGIN pwd[pwd.length] ← c; pwd.length ← pwd.length + 1; WriteChar['*]; END; END; ENDLOOP; RETURN[ProtocolDefs.MakeKey[pwd]] END; FindConnect: PROCEDURE [ name: BodyDefs.RName, addr: POINTER TO PupDefs.PupAddress] RETURNS [BOOLEAN] = BEGIN connect: ProtocolDefs.Connect = [ProtocolDefs.maxConnectLength]; info: NameInfoDefs.NameType = NameInfoDefs.GetConnect[name, connect]; SELECT info FROM individual => PupDefs.GetPupAddress[ addr, connect ! PupDefs.PupNameTrouble => GOTO couldnt]; ENDCASE => GOTO couldnt; RETURN[TRUE]; EXITS couldnt => RETURN[FALSE]; END; SetConnectLocal: PROCEDURE [ name: BodyDefs.RName, key: ProtocolDefs.Password, socket: PupDefs.PupSocketID] RETURNS [BOOLEAN] = BEGIN info: LocateDefs.FoundServerInfo; str: ProtocolDefs.Handle ← NIL; Action: PROCEDURE [serverAddr: PupDefs.PupAddress] RETURNS [BOOLEAN] = BEGIN ENABLE ProtocolDefs.Failed => GOTO no; serverAddr.socket ← ProtocolDefs.RegServerEnquirySocket; str ← ProtocolDefs.CreateStream[serverAddr]; RETURN[TRUE]; EXITS no => RETURN[FALSE] END; info ← LocateDefs.FindRegServer[name, Action]; IF str = NIL THEN GOTO couldnt; BEGIN ENABLE ProtocolDefs.Failed => GOTO badAnswer; rc: ProtocolDefs.ReturnCode; myAddr: PupDefs.PupAddress; connect: ProtocolDefs.Connect = [ProtocolDefs.maxConnectLength]; PupDefs.GetPupAddress[@myAddr, "ME"L]; myAddr.socket ← socket; PupDefs.AppendPupAddress[connect, myAddr]; ProtocolDefs.SendRSOperation[str, IdentifyCaller]; ProtocolDefs.SendRName[str, name]; ProtocolDefs.SendPassword[str: str, pw: key, key: [0, 0, 0, 0]]; ProtocolDefs.SendNow[str]; rc ← ProtocolDefs.ReceiveRC[str]; IF rc.code # done THEN GOTO badAnswer; ProtocolDefs.SendRSOperation[str, ChangeConnect]; ProtocolDefs.SendRName[str, name]; ProtocolDefs.SendConnect[str, connect]; ProtocolDefs.SendNow[str]; rc ← ProtocolDefs.ReceiveRC[str]; IF rc.code # done THEN GOTO badAnswer; EXITS badAnswer => BEGIN ProtocolDefs.DestroyStream[str]; GOTO couldnt END; END; ProtocolDefs.DestroyStream[str]; RETURN[TRUE]; EXITS couldnt => RETURN[FALSE]; END; CheckConnect: PROC [info: LONG POINTER TO NameInfo] = BEGIN which: {mail, reg} = IF info = MSInfo THEN mail ELSE reg; name: LONG STRING = ReadName[info].name; key: ProtocolDefs.Password = ReadName[info].key; foundAddr: PupDefs.PupAddress; IF NOT FindConnect[name, @foundAddr] OR NOT ProtocolDefs.IsLocal[foundAddr] OR (foundAddr.socket # (IF which = reg THEN ProtocolDefs.RegServerPollingSocket ELSE ProtocolDefs.mailServerPollingSocket)) THEN BEGIN WriteString["Re-setting my "L]; WriteString[IF which = mail THEN "M-Server"L ELSE "R-Server"L]; WriteString[" connect-site ... "L]; IF SetConnectLocal[ name, key, IF which = reg THEN ProtocolDefs.RegServerPollingSocket ELSE ProtocolDefs.mailServerPollingSocket] THEN WriteLine["done"L] ELSE BEGIN WriteLine["couldn't"L]; ConfirmSystem[]; END; END; END; END.