-- Transport Mechanism - R-Name of this registration or mail server --
-- [Juniper]<DMS>MS>LocalName.mesa
-- Randy Gobbel 19-May-81 22:32:55 --
-- Andrew Birrell 17-Mar-81 15:06:46 --
DIRECTORY
Ascii,
BodyDefs USING[ maxRNameLength, RName ],
HeapDefs USING[ HeapEndRead, HeapEndWrite, HeapStartRead,
HeapStartWrite, HeapReadData, HeapReadRName,
HeapWriteData, HeapWriteRName,
HeapWriteString, ReaderHandle,
WriterHandle ],
IODefs,
LocalNameDefs --EXPORT only--,
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 ],
Storage USING[ String ],
String USING[ AppendString, EquivalentString, WordsForString];
LocalName: MONITOR[ initHeap: BOOLEAN ]
LOCKS info USING info: POINTER TO NameInfo
IMPORTS HeapDefs, IODefs, LocateDefs, NameInfoDefs,
ObjectDirDefs, ProtocolDefs, PupDefs, Storage, String
EXPORTS LocalNameDefs =
BEGIN
OPEN IODefs;
NameInfo: TYPE = MONITORED RECORD[ name: BodyDefs.RName,
password: STRING,
key: ProtocolDefs.Password,
known: BOOLEAN ];
MSInfo: NameInfo ← [ name: NIL,
password: NIL,
key:,
known: FALSE ];
RSInfo: NameInfo ← [ name: NIL,
password: NIL,
key:,
known: FALSE ];
ReadMSName: PUBLIC PROCEDURE RETURNS[ name: BodyDefs.RName,
password: STRING,
key: ProtocolDefs.Password ] =
{ [name, password, key] ← ReadName[@MSInfo] };
ReadRSName: PUBLIC PROCEDURE RETURNS[ name: BodyDefs.RName,
password: STRING,
key: ProtocolDefs.Password ] =
{ [name, password, key] ← ReadName[@RSInfo] };
ReadName: PROC[info: POINTER TO NameInfo]
RETURNS[name: BodyDefs.RName,
password: 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: POINTER TO NameInfo]
RETURNS[first: BOOLEAN] = INLINE
{ first ← NOT info.known; IF first THEN FindName[info] };
BadHeapNameObject: SIGNAL = CODE;
FindName: INTERNAL PROC[info: 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: 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 ← Storage.String[BodyDefs.maxRNameLength];
info.password ← Storage.String[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 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: 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: POINTER TO NameInfo] =
BEGIN
which: {mail, reg} = IF info=@MSInfo THEN mail ELSE reg;
name: 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.