[1,100]SCLI.PDL -- Program Descriptor Language for Security CLI Author: Jim Bostwick 24-JAN-1985 13:27:45 History: Randy Baldwin 7-FEB-1985 09:44:29 Adding more info. JMB 20-FEB-1985 Added MACRO subroutine headers, variable name mapping. All MACRO stuff is surrounded by ;*+ ... ;*- pairs. Last Edit: 15-MAY-1985 09:49:11 This file contains a pseudocode program description of the security CLI system. This design approach is for the author experimental. It is modeled after Pascal, somewhat loosely. PDL: PDL (alias piddle) is a pseudocode language intended for design application. Modeled loosely after Pascal, PDL replaces traditional flowcharting, data dictionaries (for non-DB intensive applications) and in general streamlines the design process. PDL adheres to Pascal in the following ways: * All Pascal keywords are recognized, including the := assignment construct. * Indentation is used to indicate statement nesting. PDL does not adhere to Pascal in the following: * Unlike Pascal, PDL is strictly top-down (more or less reverse of Pascal). However, Variables and data are still declared at beginning in conformance with top-down rules. * Variables, tests, etc. may be English phrases. * Typing is not enforced - it is encouraged. * Intermediate variables are not required -- "REPEAT check-record UNTIL no-more-records" is perfectly legal. PROGRAM SCLI -- Command line interpreter for Dial-in security. { Description: SCLI is a CLI which is (by various means) made the active CLI for all non-logged-on Dial-up terminals. (Although intended for dial-up terminals, SCLI may be installed on local terminals as well. ) SCLI enforces an additional layer of access protection on those terminals under its control. Potential users of the system must first deal with and satisfy SCLI before being allowed to enter the normal RSX logon procedure. Note that users must posess access information (passwords) for BOTH SCLI and RSX (Hello) in order to gain access to the system. SCLI also detects and counteracts most attempts to break through itself. It does this by entering a 'mumble mode' upon detection of breakin attempts. Finally, SCLI maintains a private log of legal log-in's and illegal attempts. Information in the log does NOT reflect SCLI's internal mechanism, making the log of very limited use in attempting to circumvent SCLI. } DATABASE This section covers the database used by SCLI. Note that intermediate variables, loop counters, and the like are not defined herein. We only attempt to present the required data structures in a pseudocode format. { note on vectors: SCLI can be built to protect any number of terminals. For each protected terminal, an entry will exist in several vectors. These are defined below in terms of constant Num_tts. } CONST Num_tts = xxx; { number of tts protected } TYPE tt_rec = RECORD { one of these per protected tt } tt_num: integer; { tt: number of this tt } foo_count: integer; { count of invalid commands received } mumble_efn: integer; { efn number used for this tt } mumble_mode: boolean; { true if tt in mumble mode } end; cmd_rec = RECORD { one of these per known command, plus one catchall } rpl_ptr:^string; { reply string} id_ptr:^string; action:integer; { 1 = let into mcr for this command } end; VAR command_table: array[num_commands] of command_record; tt_table: array[num_tts] of tt_rec; cmdrec: comman_record; {@MARK@} {------------------------- Begin_mumble -------------------------} { Begin-mumble initiates mumble-mode. In this mode, messages are somewhat different, but most importantly, all keys are illegal. That is, no input whatsoever will cause a fall-through to MCR. Mumble-mode may only be teminated by expiration of the mumble timer, or by aborting SCLI. } BEGIN {Begin_mumble} with tt_table[tt] do begin mumble_mode := true; MRKT(mumble_time,mumble_efn,mumble_AST); {set timer} cont_mumble := false; {flag to show activity during mumble time } end; log(mumble_initiated, tt) end; {------------------------- end_mumble -------------------------} { End-mumble terminates mumble-mode processing. SCLI will now accept valid passwords as commands to fall-through to MCR. } BEGIN with tt_table[tt] do begin mumble_mode := false; foo_count := 0; end END; {------------------------- Mumble_AST ---------------------------} { Mumble-AST is the AST entry point for the mumble-timer. If cont-mumble is true, the mumble timer is restarted, and we remain in mumble mode. IF cont-mumble is false, we call end-mumble, restoring normal operations. NOTE WELL: the efn associated with the MRKT is on top of the stack. It must be removed, and is our link with which tt this AST is for. } BEGIN {mumble_AST } get efn from top-of-stack; find tt_table entryt with this efn-- gives tt; with tt_table[tt] do begin IF cont_mumble THEN BEGIN MRKT(mumble_time,mumble_efn,mumble_AST) cont_mumble := false END ELSE end_mumble(tt) end END; {------------------------- TYPE ---------------------------------} Procedure Type({in} ptr:^string; {in} length:integer); { This procedure prints an ascii or asciz string on LUN 6 (normally the users ti: ). If length=0 on input, asciz is assumed, and TYPE calls SLEN to determine the length of the string (null terminated). } {------------------------- Encrypt ------------------------------} { Encrypt takes the command line returned by GCCI, locates it's real length (less trailing whitespace), and encrypts it in place (via a call to CRYPT). CALLS: CRYPT } Local data: length: word; {number of words to crypt } BEGIN { Encrypt } find end of command_line length := length of command line {in bytes} call CRYPT(cmd_ptr,length); END; { Encrypt } {------------------------- LOG ----------------------------------} { The LOG function is used to send SYSTEM SERVICE MESSAGES to the LB:[1,6]LOG.ERR file. These messages allow a knowledgable person to monitor SCLI's activity. } CONST INIT = 'Initialized' ENABLE = 'Enabled' DISABLE = 'Disabled' ATTEMPT = 'Elimination Attemted' ALL_ELIM = 'System Elimination' LINKED = 'Dev xxxx linked' RELEASE = 'Terminal xxxx released' PRIV_ELIM = 'Priveleged Elimination' MUMBLE = 'Invalid detected' UP_ERROR = 'Restart error' WHO = 'SCLI: ' BEGIN buffer := who; buffer := buffer + message_type IF tt: available THEN buffer := buffer + tt_name SEND_SYSTEM_MESSAGE; { via smsg directive } END {------------------------- Look_Up_Command ----------------------} Procedure Look_up_Command({inout}command:string; {out}cmdidx:integer); { The function of this procedure is to take the input command and search the command table for a match. It will return the index into command table. If the command is not found in the table, the index will be zero. } BEGIN x := 0; encrypt(command); REPEAT IF table[x] = crypt_command THEN BEGIN match = true; END ELSE x := suc(x); UNTIL (x > max_table_entries) OR (match); cmdidx = x END; {------------------------- Reestablish_CLI ----------------------} Procedure Reestablish_CLI; { This procedure will reestablish the SCLI for a tt in the event of it's elimination via a CLI /ELIM=cliname command. This prevents a user from simply eliminating the CLI in an attempt to bypass it. It works because SCLI receives a message informing it of the elmination attempt. NOTE: if this wont' work, just leave terminal slaved. } BEGIN spawn(MCR, UPCLI); { task to bring up the CLI again } { UPCLI is MCR command needed to setup cli } IF not success then LOG(up_error) END {------------------------- Do_Sys_Message -----------------------} Procedure Do-Sys-Message({in}cmdptr:^command-line); { This procedure will take a system message and process it. Most cases simply log the action and others will act on the message. See System Management guide chapter 11 for system message definitions. } BEGIN CASE Sys_Message of Init/Enable, Init/Disable: (LOG,SCLI_initialized) Enable: (LOG, SCLI_enabled) Disable: (LOG, SCLI_disabled) Eliminate: BEGIN (LOG, SCLI_elim_attempt) (Reestablish_SCLI) END Eliminate_All: (LOG, SCLI_eliminate) Terminal_Linked: (LOG, SCLI_linked, terminal) Terminal_Released: (LOG, SCLI_release, terminal) Special: {user initiated cli message} BEGIN CASE Special of Eliminate: (LOG, SCLI_priv_elim) END {case} END {case} END { do_sys_message } {------------------------- Main SCLI ----------------------------} BEGIN { SCLI } Init; { initialize CLI } Repeat Reply-ptr := NIL; GCCI(command_line) { obtain command line} IF system_message THEN Do_Sys_message(sys_message) { system message sent to cli } ELSE IF command_line THEN BEGIN Look_up_command({in}command; {out} cmdidx); cmdptr := command_table[cmdidx]; ttptr := tt_table[tt] { tt in GCCI info buffer } if mumble_mode[tt] then BEGIN increment ttptr^.foo-count; ttptr^.cont_mumble := true; reply-ptr := random-reply END else if cmdptr^.pass then BEGIN log(logged-on,tt); reply-ptr := cmdrec.reply; set_cli_mcr; ttptr^.foo-cnt := 0 END else BEGIN increment ttptr^.foo-count; if ttptr^.foo-count > max-foo then begin-mumble; IF cmdrec.reply <> NIL THEN reply-ptr := cmdrec.reply ELSE reply-ptr := random-reply END; if reply-ptr <> NIL then type(reply-ptr); END; UNTIL true; {repeat forever} STOP {system will unstop} END.