;	.TITLE scli - Main Security CLI
;	.IDENT /1.17/

.REM |
*+	scli - Main Security CLI

	File:scli.mac
	Version: 1.17
	Author:
	Last Edit: 14-JUN-1985 14:47:43 
	Last Update: 3-Oct-1985 09:05:46 
		     modify for G.Lab

	This is the root module for SCLI. It contains initialization,
	and main-line code. 
*-
|
	.sbttl CONDITIONALS

;;debug = 0		; define for debug code
;;bkdoor = 0		; define to include back door code
	.list meb
	.enable lc


	.LIBRARY /LB:[1,1]GLMAC.MLB/
	.mcall push,pop,call,return

	.sbttl DPBS

	.psect dpbs d,lcl,con
.rem |
	This psect contains the static dpbs for this module.
	These are possibly skeletal -- required info is filled
	in at run-time, and the directives are executed by a 
	DIR$ call. 
|
	.MCALL	GCCI$,RPOI$,SCLI$,EXIT$S,QIOW$,ALUN$,DIR$

GCCI:	GCCI$	CMDBUF,CBLEN,IBUF,IBLEN,0,GC.CST
	; note: the definitions for two gcci bits were left out of RSX!?
	; the one needed is defined here, from the documentation in EXEC REF.
	gc.cnl = 1		; null command line

RPOI:	RPOI$	SHI
SCLI:  	SCLI$	MCR
CLUN:	alun$ 2,CO			; assign LUN 2 to console

	.even
	.SBTTL LOCAL DATA

	.psect ldat,d,lcl,con
;
; use this psect for scratch storage - it is not guaranteed to be saved
; across calls to the module
;
log1:	.word 0		; reserve some variables for logging
log2:	.word 0		; ...
log3:	.word 0		; ...

;
; get the global definitions
;
	.include /sclidat.mac/

	.psect data,d,gbl,con
;
; use this psect for module-specific data which must be retained across
; calls to the module
;

;
; BUFFER AREAS
;
CMDBUF:	.BLKB	255.+G.CCBF	;length = header plus command in bytes
				;  big enough for M-PLUS command lines
CBLEN=.-CMDBUF			;calculate length
	.EVEN
 
IBUF:	.BLKB	G.CCCA+2	;long enough to contain all information
IBLEN=.-IBUF			;calculate length
	.EVEN
 
	.if df bkdoor
pound:	.word 	0		; for testing use - back-door exit
	.endc
rplptr:	.word	0		; pointer to reply string
msptr:	.word	0		; general msg pointer
pass:	.word	0		; flag we will give tt to mcr
nodmp:	.word	0		; flag we will NOT dump raw command

; some strings....

	.even
	.sbttl SCLI Main 


	.PSECT
; code goes in the blank psect

INIT:
	dir$ 	#CLUN		; assign console lun
	bcc	100$		; br if no errors
	mov	$dsw, log1	; save dsw
	mov	#1, log2	; num params
	mov	#5, log3	; error number
	dolog	9.,<log3,log2,log1>
100$:	
	; clear out user-id from tt-table. This shows the init code
	; that we are really starting from scratch.
	mov	#tttbl, r0	; point to tt table
150$:	clr	tt.uid(r0)	; clear user-id
	clr	tt.tot(r0)	; clear total foo-count
	clr	tt.foo(r0)	; and current foo-count
	add	#ttsiz, r0	; point to next record
	tst	(r0)		; off end?
	bne	150$		; no - loop

	clr	flags		; init flags
	
START:	DIR$	#GCCI		;GET A COMMAND FROM SYSTEM
	bcc	50$		; br if no error
	; directive errors here are simply not tolerated!
	mov	#1, r0
	mov	$dsw, r1
	iot			; crash and burn

50$:
;
; IF THE GCCI$ DIRECTIVE HAD THE GC.CST OPTION SPECIFIED, WE MAY HAVE
; JUST BEEN UNSTOPPED, SO WE HAVE TO GET THE COMMAND.
;
	CMP	#IS.CLR,$DSW	;WERE WE JUST UNSTOPPED?
	BEQ	START		;IF EQ YES
	MOV	#CMDBUF,R0	;POINT TO COMMAND BUFFER
	TST	(R0)		;IS THIS A SYSTEM MESSAGE?
	bne	100$		; no -br
	.globl domsg
	call 	DOMSG		; process system messages
	br	start		; and loop
;
; AT THIS POINT, THE CLI HAS A COMMAND TO BE PROCESSED. THE CODE FROM
; THE "START:" LABEL TO HERE SHOULD BE FAIRLY COMMON AMONG ALL CLIS.

100$:
	; just loop on null command lines, mostly to allow
	; autobaud dial-up
	bitb	#gc.cnl, g.ccfl(r0)	; null command line
	bne	start			; yes - loop

	.if df bkdoor
; for testing, if command terminator is <ESC>, remember this fact,
; and set to MCR regardless of SCLI actions - this is a back-door
; and must be removed for production use!
	clr	pound		; not escape command
	cmpb	#33, g.cctc(r0)	; back-door key?
	bne	200$		; nope
	inc	pound		; open back door
	.endc
200$:
	clr	rplptr		; init to no reply
	clr	pass		; init to no-pass	
	clr	nodmp		; will let verbose dump command (for now)
	movb	g.ccct(r0), r1	; get command length
	add	#g.ccbf, r0	; point to command text
	.globl lookup
	call	lookup		; get index into command table
	mov	#cmdbuf, r0	; point back to gcci buffer
	mov	#cmdtbl, ctptr	; construct pointer to command record
	mov	r2, r3		; want single-register multiply
	asr	r3		; make byte offset into record number
	mul	#cmdsiz, r3	; construct offset
	cmp	r3, #maxcmd	; index within limits
	bhi	250$		; index too high - use zero (illegal)
	add	r3, ctptr	; ctptr now points to record in cmdtbl	
	mov	ctptr,r3	; check for message type record
	cmp	#ac.mes, cm.act(r3)	; is this valid only for messages?
	bhi	250$			; not a message, br
	mov	#cmdbuf, ctptr	; is a message, so make illegal command
	inc	nodmp		; but don't allow dump of it

250$:	mov	#tttbl, r4	; point to beginning of tt-table
	movb	g.ccun(r0), ttnum	; save tt number for logging
300$:	cmpb	g.ccun(r0), (r4)	; tt match?
	beq	400$		; yes - br
	add	#ttsiz, r4	; point to next record
	tst	(r4)		; off end?
	bne	300$		; no - loop
; the command came from an 'unknown' tt??!!!???
;
; do something nasty to the guy who went SET /CLI=TI:SCLI
;
	dolog	11.,<ttnum>	; log unknown terminal
	jmp	start		; for now, just ignore

400$:	mov	r4, ttptr	; save pointer to tt record

; with the preliminaries accomplished, see what we should do, and
; do it
; note:  
;	r5 -> garbage
;	r4 -> tt-table record
; 	r3 =  garbage
;	r2 =  garbage
;	r1 =  buffer length
;	r0 -> GCCI buffer
;

	bit	#fl.mbl, tt.flg(r4)	; tt in mumble mode?
	beq	1000$			; no - br
;
; tt is in mumble-mode. issue garbage reply regardless of command,
;    and count input commands during mumble-mode
;
	inc	tt.foo(r4)	; increment foo-count
	mov	#rpl0, rplptr	; set 'random' reply
	br	2000$		; join common code

1000$:
	; here, tt is not now in mumble-mode
	;   is command a password?
	mov	ctptr, r5		; point into command table
	mov	cm.rpl(r5), rplptr	; set reply pointer
	cmp	#ac.pas, cm.act(r5)	; let him in?
	bne	1200$			; no - br
	inc	pass			; remember to let him in
	inc	nodmp			; don't dump passwords!
	mov	cm.id(r5), log1		; point to user-id for later logging
	clr	tt.foo(r4)		; zero invalid count
	clr	tt.tot(r4)		; and total invalid
	mov	cm.id(r5), tt.uid(r4)	; remember user id
	br	2000$			; join commmon code	

1200$:
	;
	; here, tt not now in mumble-mode, but invalid reply
	;  count invalid attempts, and kick into mumble mode
	;  if try limit exceeded
	;
	inc	tt.foo(r4)	; increment foo-count
	cmp	tt.foo(r4), #maxfoo	; over the limit?
	blo	2000$			; no - br
	.globl	mblon
	call mblon	; start mumble-mode
	; go issue 'illegal command' message
	br	2010$
	
2000$:	
	; if verbose mode set, and nodump clear, un-encrypt
	; the text, and dump it in an 'illegal command' message
	bit	#gf.vrb, flags		; verbose mode?
	beq	2040$			; no - br
2010$:	tst	nodmp			; dump suppressed for this command?
	bne	2040$			; yes - br
	; 
	; since we carefully encrypted the input, we must reverse
	; the process now in order to dump the plain text out.
	;
	push	<r0>			; save a reg
	add	#g.ccbf, r0		; point to command text
	mov	r0, log1		; save pointer for logging
	.globl	crypt
	call	crypt			; un-encrypt the command text	
	add	r1, r0			; point past end
	clrb	(r0)			; make asciz
	pop	<r0>			; restore cmdbuf pointer
	dolog	10.,<ttnum,log1>	; log the illegal attempt

2040$:
	; issue the reply, set to mcr (if pass), then loop
	tst	rplptr			; check for null reply
	bne	2050$			; not null - br
	mov	#rpl0, rplptr		; set 'random' reply

2050$:	call	type,r5,<rplptr,0> 	; type out message at rplptr

	.if df bkdoor
	tst	pound			; back-door open?
	bne	2100$			; yes, go thru
	.endc
	tst	pass			; set to MCR?
	beq	3000$			; no - br
	
2100$:	; set cli to MCR via SCLI directive
	dolog	1,<log1,ttnum>		; log the 'login'
	bic	#fl.pro, tt.flg(r4)	; set not protected
	mov	#scli, r4		; point to dpb
	mov	g.ccdv(r0), s.cidv(r4)	; stuff device name
	movb	g.ccun(r0), s.ciun(r4)	; and unit number
	clrb	s.ciun+1(r4)		; make sure hi byte zero
	dir$	#scli			; switch cli's
	bcc	3000$			; ok - br
	jmp	ferr1			; fatal error

3000$:	jmp	start

ferr1:	mov	#1, r0
	mov	$dsw, r1
	br	ferr
ferr:	iot			; crash and burn

	.end INIT

