	.title	SSXTLOCK
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;	Program:	SSXTLOCK
;	Author:		Lynn Tedder
;	Date Written:	04/22/91
;	Synopsis:	This program will accept a password from the terminal
;			and verify it against what is in the SYSUAF.  If a
;			retry limit is exceded, the process will either be
;			logged off, or the calling image will be run down
;
;	INPUTS:	None                                                        
;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

	.library	/sys$library:lib.mlb/
	.library	/sys$library:starlet.mlb/
	.link		/sys$system:sys.stb/

	$iodef		;Define Section Table Entry offsets for I/O
	$qiodef		;Define Section Table Entry offsets for QIO masks
	$ssdef		;Define Section Table Entry offsets for System Services
	$trmdef		;Define Section Table Entry offsets for Terminal masks
	$ttdef		;Define Section Table Entry offsets for TT masks
	$prvdef		;Define Section Table Entry offsets for priv masks

	.macro	check	?l
	cmpl	#ss$_normal,r0
	beql	l
	pushl	r0
	calls	#1,g^lib$stop
l:
	.endm	check

username_descriptor:
username_length:
	.word	12
	.word
	.address	username
username:
	.ascii	/            /

terminator_mask:			;Define the QIO Read terminator mask
first_terminator_longword:		;The first longword must be 0
	.long	0
second_terminator_longword:		;The second longword allows only
	.long	8192			;<RET> as a terminator

control_mask:				;Will contain lib$m_cli_ctrly to
	.long	0			;disallow the use of <CONTROL-Y>
old_control_mask:			;Longword to contain the saved
	.long	0			;control character mask

spaces:	.ascii	/                                /

master_pid:
	.long
master_pid_len:
	.word
getjpi_iosb:				;IOSB of GETJPI call
	.long
getjpi_rest_iosb:
	.long

getjpi_item_list:			;GETJPI item list to return the
					;username and the master pid
	.word		12		;Length of returned item
	.word		jpi$_username	;Item code to return the USERNAME
	.address	username	;Address of return buffer
	.address	username_length	;Length written to return buffer

	.word		4		;Length of returned item
	.word		jpi$_master_pid	;Item code to return the master pid
	.address	master_pid	;Address of return buffer
	.address	master_pid_len	;Length written to return buffer
	.long	0			;Item List ending Longword

getuai_item_list:			;GETUAI item list 
	.word		1		;Length of returned item
	.word		uai$_encrypt	;Item code to return the algorithm
	.address	algorithm	;Address of return buffer
	.address	algorithm_length;Length written to return buffer

	.word		2		;Length of returned item
	.word		uai$_salt	;Item code to return the password salt
	.address	password_seed	;Address of return buffer
	.address	seed_length	;Length written to return buffer

	.word		8		;Length of returned item
	.word		uai$_pwd	;Item code to return the hashed password
	.address	hashed_password	;Address of return buffer
	.address	password_length	;Length written to return buffer

	.word		4		;Length of returned item
	.word		uai$_uic	;Item code to return the hUIC
	.address	longword_uic	;Address of return buffer
	.address	uic_length	;Length written to return buffer
	.long	0			;Item List ending Longword

getsyi_iosb:				;I/O Status block for GETSYI call
	.long
	.long
getsyi_item_list:			;GETSYI item list to return the Breakin Limit
	.word		1		;Length of returned item
	.word		syi$_lgi_brk_lim;Item code to return the breakin limit
	.address	max_loop_counter;Address of return buffer
	.address	algorithm_length;Length written to return buffer
	.long	0

max_loop_counter:			;Storage for LGI_BRK_LIM
	.long

loop_counter:
	.long	0

algorithm:
	.byte
algorithm_length:
	.word
password_seed:
	.word
seed_length:
	.word
hashed_password:
	.quad
password_length:
	.word

longword_uic:
	.long
uic_length:
	.word
control_string:
	.ascid	/!%U/

new_hashed_password:
	.quad

tt_chan:
	.blkw	1

tt_descriptor:
	.ascid	/SYS$INPUT:/

password_prompt:
	.ascii	/Password:   /
password_prompt_length:
	.long	10
second_password_prompt:
	.ascii	<cr><lf>/Password: /

pass_buffer_length:
	.word	32
entered_password_descriptor:
entered_password_length:
	.word	0
	.word
	.address	entered_password
entered_password:
	.blkb	32

read_qio_iosb:				;I/O Status block for the QIO
	.word
read_qio_length:			;Length of entered data
	.word
read_qio_terminator:			;Terminator used
	.word
read_qio_terminator_length:		;Length of Terminator
	.word

read_qio_function:			;Convert input to upcase, do not echo,
					;and purge the type ahead buffer
	.word	io$_readprompt!io$m_cvtlow!io$m_noecho!io$m_purge

invalid_message:
	.ascii	/INVALID/

lf = 10				;Line Feed
cr = 13				;Carriage Return

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
;                                                                              ;
;Code start                                                                    ;
;                                                                              ;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;

	.entry	ssxtlock,^m<r2,r3,r4,r5,r6,r7,r8,r9>

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
;                                                                              ;
;Disable <CNTRL-Y> processing                                                  ;
;                                                                              ;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;

	bisl2	#lib$m_cli_ctrly,control_mask	;Mask out <CTRL-Y>

	pushal	old_control_mask		;Save current Control Mask
	pushal	control_mask
	calls	#2,g^lib$disable_ctrl		;Disable <CTRL-Y>
	check

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
;                                                                              ;
;Call $GETJPI to get a username.                                               ;
;                                                                              ;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;

20$:
	pushl	#0				;No AST Params
	pushl	#0				;No AST Procedure
	pushaq	getjpi_iosb			;IO Status Block
	pushal	getjpi_item_list		;Item List
	pushl	#0				;No Process Name - this process
	pushl	#0				;No PID - use this process
	pushl	#0				;No Event flag to set
	calls	#7,g^sys$getjpiw		;Go get the current username
	check					;Everything OK with the call?
	movl	getjpi_iosb,r0			;Now, lets check the IOSB
	check					;Hope we're OK

30$:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                                              ;
;Get the Password algorithm, the hashed password, and the seed from the UAF.   ;
;                                                                              ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	pushl	#0				;Null Argument
	pushl	#0				;Null Argument
	pushl	#0				;Null Argument
	pushal	getuai_item_list		;Item List
	pushal	username_descriptor		;Username
	pushl	#0				;Null Argument
	pushl	#0				;Null Argument
	calls	#7,g^sys$getuai
	check

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                                              ;
;Get the SYSGEN parameter LGI_BRK_LIM to see how many chances to give to get   ;
;the password right.                                                           ;
;                                                                              ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	pushl	#0				;No AST Parameter
	pushl	#0				;No AST Routine address
	pushal	getsyi_iosb			;I/O Status Block
	pushal	getsyi_item_list		;Item List
	pushl	#0				;Use this Node, no Node name
	pushl	#0				;Use this node, no CSID
	pushl	#0				;No Event flag, do it Sync-ly
	calls	#7,g^sys$getsyiw
	check

	movl	getsyi_iosb,r0			;Check the status in IOSB
	check

	$assign_s	devnam=tt_descriptor,-	;Assign I/O Channel to Terminal
			chan=tt_chan
	check
	movl	#0,loop_counter			;Initialize the Loop Counter

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                                              ;
;Get the Password from the user.  Wait until they enter it                     ;
;                                                                              ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

qio_call:

	addl	#1,loop_counter			;Increment the loop counter

	pushl	password_prompt_length		;Get the length of the prompt
	pushal	password_prompt			;Get the address of the prompt
	pushal	terminator_mask			;Get the terminator mask
	pushl	#0				;No p3
	pushl	pass_buffer_length		;Get the password buffer length
	pushal	entered_password		;Get the password buffer
	pushl	#0				;No AST parameter
	pushl	#0				;No AST
	pushaq	read_qio_iosb			;Read I/O Status Block
	pushl	read_qio_function		;Function = upcase,purge,noecho,
						;Read with prompt
	pushl	tt_chan				;Terminal Channel
	pushl	#0				;No Event Flag
	calls	#12,g^sys$qiow			;Check success of the call

	blbs	r0,40$
	ret
40$:
	movl	read_qio_iosb,r0		;Check the status in IOSB
	blbs	r0,check_control_y
	ret

check_control_y:

	cmpw	#ss$_controly,read_qio_iosb	;Check to see if they hit <CTRL-Y>
	beql	control_c_y			;They did!

check_control_c:

	cmpw	#ss$_controlc,read_qio_iosb	;Check to see if they hit <CTRL-C>
	bneq	got_a_password			;They did not


control_c_y:

	subl2	#1,loop_counter			;They did.  Subtract 1 from loop
						;counter
	brw	bad_password			;Go to BAD_PASSWORD

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
;                                                                              ;
;We have a password entered.  We need to hash it and then compare it to what   ;
;we got from the UAF.
;                                                                              ;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;

got_a_password:

	movw	read_qio_length,entered_password_length
						;Get the number of characters
	pushaq	new_hashed_password		;Destination
	pushal	username_descriptor		;Username
	pushl	password_seed			;Password Salt
	pushl	algorithm			;Name of the algorithm
	pushal	entered_password_descriptor	;Password entered at the prompt
	calls	#5,g^sys$hash_password		;Hash it
	check

	movaq	new_hashed_password,r7		;Get address of new hash
	movaq	hashed_password,r8		;Get address of old hash
	cmpl	(r7)+,(r8)+			;Compare them and auto increment
						;the address for the second
						;longword.
	bneq	bad_password			;They didn't match
	cmpl	(r7),(r8)			;Compare the second longword
	bneq	bad_password			;They didn't match

	brw	finished			;They matched!

;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;
;                                                                              ;
;The password entered did not match what was stored.  Compare the loop counter ;
;to the masimum number of tries.  If we excede this number, log them out.      ;
;                                                                              ;
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^;

bad_password:

	cmpl	max_loop_counter,loop_counter	;Exceded maximum # of tries?
	bleq	go_away				;Yes we have
	movc3	#12,second_password_prompt,password_prompt
						;Move in the second prompt. 
						;This has CR and LF in it.
	movw	#12,password_prompt_length	;Change to the new length
	brw	qio_call			;Go back and prompt them

go_away:

	$dassgn_s	chan=tt_chan		;Deassign the terminal channel
	check

	$delprc_s	pidadr=master_pid	;If not, delete the process
	$exit_s					;else, run down the image
	
finished:

	$dassgn_s	chan=tt_chan		;Deassigh the terminal channel
	check

	pushal	control_mask			;Restore the original control
	pushal	old_control_mask		;mask.
	calls	#2,g^lib$enable_ctrl		;Set it now.
	check

	movl	#1,r0
	ret					;Let's go home!
	.end	ssxtlock
