-- UserCredentialsUnsafe.mesa
-- last edited by Levin on October 21, 1982 2:44 pm

DIRECTORY
  NameInfoDefs: TYPE USING [Outcome];

UserCredentialsUnsafe: DEFINITIONS =

BEGIN

-- This interface manages the credentials (Grapevine RName and password) of the human sitting at the terminal.  It provides facilities for authentication of the individual and protection of the contents of the local disk against unauthorized access.

-- The individual must supply his credentials once per power-on of his machine.  The credentials are retained by the system across world-swaps, rollbacks, and boots.  The credentials are discarded only under the following circumstances:  (1) the user leaves the Pilot world entirely (e.g., by returning to the Alto world), (2) the machine is powered off, (3) the user deliberately instructs the system to forget his credentials (e.g., by pressing the Idle button).  These events delimit sessions, at least from the standpoint of credentials lifetime.  Once the credentials have been discarded, the system will normally require that they be supplied and authenticated before any access to the disk is permitted.

State: TYPE = MACHINE DEPENDENT {noCredentials(0), name(1), nameHint(2), nameAndPassword(3)};
-- The credentials are stored on disk in a private location accessible only through this interface.  The information stored there may be in one of the forms indicated by "State".  "noCredentials" means that the disk area has never been initialized or that it holds credentials in an obsolete format from a previous, incompatible Cedar release.  "name" means that the user's name is stored on the disk and that Login (see below) will accept only the named individual.  Furthermore, the password supplied at Login time must be acceptable to Grapevine.  (If Grapevine is unavailable, the password must match the last password for this individual that Grapevine acknowledged as correct.)  "nameHint" means that any individual registered with Grapevine may successfully log in, but the system retains the credentials of the individual who did so most recently on this machine.  "nameAndPassword" is functionally similar to "name" except that both name and password are stored on the disk in unencrypted form and that Login will prompt for credentials only if Grapevine rejects the ones stored on disk.

GetCredentialsState: PROC RETURNS [State];
-- This procedure returns the present state of the credentials stored on disk.

ChangeCredentialsState: PROC [new: State] RETURNS [old: State];
-- This procedure permits the form of the credentials stored on the disk to be changed.  If "new" is other than State[noCredentials], the name and/or password stored on the disk will be obtained from GetUserCredentials (see below), which may not produce the same values as are on the disk at the time ChangeCredentialsState is called.

GetProc: TYPE = PROC RETURNS [CHAR];
PutProc: TYPE = PROC [CHAR];

LoginOptions: TYPE = RECORD[
  confirmCredentialsOverwrite: BOOL ← FALSE,
  -- 'confirmCredentialsOverwrite' is interrogated by Login only if it finds missing or obsolete credentials information on the disk. If 'confirmCredentialsOverwrite' is TRUE, Login will give the user the opportunity to retain the disk state untouched.  Otherwise, Login will force the state to be either 'name' or 'nameHint'; the user chooses which.
  prohibitDiskProtection: BOOL ← FALSE,
  -- 'prohibitDiskProtection', if TRUE, will cause Login not to offer the user the opportunity to set the disk credentials state to 'name'.
  ignoreDiskEntirely: BOOL ← FALSE,
  -- 'ignoreDiskEntirely', if TRUE, causes Login to bypass any attempt to access or rewrite the disk credentials ('confirmCredentialsOverwrite' is therefore ignored in this case).
  alwaysPrompt: BOOL ← FALSE,
  -- 'alwaysPrompt', if TRUE, forces Login to prompt for credentials, even if the user was already satisfactorily logged in.
  reserved: [0..7777B] ← 0];

defaultOptions: LoginOptions = [];

Login: PROC [
  startInteraction: PROC RETURNS [GetProc, PutProc], endInteraction: PROC,
  options: LoginOptions ← defaultOptions];
-- The detailed behavior of this procedure depends on the present state of the private disk area used to store credentials (see description of "State", above).  Login is prepared to find the credentials area in any of the four states.  If the initial state is "noCredentials", Login will prompt for a Grapevine RName and password, which it then presents to Grapevine for authentication.  (The details of the prompting are described below.)  Once a valid set of credentials is supplied, Login asks if the desired final state is "name" or "nameHint" and rewrites the credentials area accordingly.  (See description of LoginOptions for an exception to this behavior.)  If the initial state is "nameHint", Login prompts as for "noCredentials", then rewrites the credentials area in State[nameHint] using the name and password supplied.  If the initial state is "name", Login prompts for the password only, obtaining the user name from the disk.  This combination of name and password must be acceptable to Grapevine.  Finally, if the initial state is "nameAndPassword", Login obtains both name and password from the disk and presents them to Grapevine.  If they are rejected as invalid, Login acts as though the initial state were "name". At the completion of Login, the successfully authenticated credentials are passed to SetUserCredentials (see below).
-- Note 1:  When Login is invoked, it first invokes GetUserCredentials.  If it finds name.length = 0 or if options.alwaysPrompt is TRUE, it behaves exactly as just described.  If, however, it finds name.length > 0, Login bypasses all of the above processing and returns without inspecting the disk credentials area.  Thus, once credentials have been established using SetUserCredentials, they remain in effect until discarded by one of the circumstances described earlier.  It is intended that the initial call of SetUserCredentials occur implicitly as a result of a successful Login, and that the credentials thus established remain in effect until explicitly changed by a call of SetUserCredentials or until explicitly discarded.  If every Pilot-based environment sharing the disk on this machine calls Login before it permits the user access to any information stored on the disk, a strong guarantee of disk privacy can be made (assuming State[name]).
-- Note 2:  If Login needs to interact with the user, it first calls "startInteraction" to obtain two procedures for character I/O.  These procedures have semantics identical to TTY.GetChar and TTY.PutChar (i.e., GetChar never echos, PutChar is expected to handle Ascii.BS intelligently).  When interaction has completed, Login calls "endInteraction", enabling the initial supplier to clean up.  Login never retains the character I/O procedures across calls.  "endInteraction" is called if and only if "startInteraction" is.

GetUserCredentials: PROC [name, password: LONG STRING];
-- This procedure fills in the current values of the user name and password.  If Login has not yet succeeded, name.length = password.length = 0.  The same values will be returned in all Pilot environments on this machine, independent of boot, rollback, or world-swap.  These credentials will remain in effect until the next call of SetUserCredentials.  If either parameter is NIL, no attempt will be made to return the corresponding value.  If a parameter is non-NIL and has insufficient space (maxlength is too small), String.StringBoundsFault will be raised.

SetUserCredentials: PROC [name, password: LONG STRING];
-- This procedure changes the values of the user name and password.  No attempt is made to validate these credentials with Grapevine.  Subsequent invocations of GetUserCredentials will return these values, even after a boot, rollback, or world-swap.  These credentials will remain in effect until the next call of SetUserCredentials.

Authenticate: PROC RETURNS [NameInfoDefs.Outcome];
-- This procedure uses the current credentials and passes them through to Grapevine for authentication.  It is here largely for convenience, since the unsafe GrapevineUser interfaces presently accept only short STRINGs and this interface traffics in LONG STRINGs.

END.