;	title	'PASSWORD.ASM'
;	page	60
;
;
;		PASSWORD.ASM			Version 1.0
;	 By Bo McCormick       8/6/81
;
; This is a program that adds password protection
; to programs. Format:
;
; PASSWORD name_of_file
;
; Then answer the prompt with the password to be
; applied to the program:
;
; Password : enter password here
;
; If everything goes well, the program will be saved to disk.
; If not, a message is printed and control is passed
; to the CCP.
;
; The good part of this is, when you type in the program
; program name next time, instead of running the program
; right away, the program asks you for the password. If you
; reply with something other than the original password, the
; program doesn't run, and it returns to the ccp.
;
;
;EQUATES
mesout:	equ	9		;BDOS functions
incon:	equ	10
open:	equ	15
close:	equ	16
delete:	equ	19
read:	equ	20
write:	equ	21
setdma:	equ	26
;
cr	equ	0dh		;ascii values
lf	equ	0ah
eos	equ	'$'
;
boot	equ	0		;0 for standard CP/M
				;4200H for ALT. CP/M;
bdos	equ	boot+5
fcb	equ	boot+5ch
defbuf	equ	boot+80h
tpa	equ	boot+100h
stack	equ	tpa
;
	org	tpa

;
;
start:	lxi	h,0		;save stack pointer
	dad	sp		;put stack in hl
	shld	old$stack-offset	;save it
	lxi	sp,stack	;get new stack
;
; stack saved so program can return to CCP without
; intervening warm start.
;
	lda	fcb+9		;get first char of extension
	cpi	' '		;if ' ' then change to .COM
	jz	no$type
	cpi	'C'		;If there is an extension,
	jnz	not$right	;make sure it's .COM
	lda	fcb+10		;check second letter
	cpi	'O'		
	jnz	not$right
	lda	fcb+11
	cpi	'M'		;last letter
	jz	is$com		;if it is a COM, then cont.
not$right:
	call	end$mes		;it's not a com file, so tell
;
	db	cr,lf,'Must be a command (.COM) file'
	db	cr,lf,eos
;
end$mes:
	pop	d		;get address of message
	mvi	c,mesout	;PRINT STRING command
	call	bdos		;print error message
;
finish:	lhld	old$stack-offset ;get old stack
	sphl			;put it in HL
	ret			;return to CP/M
;
no$type	mvi	a,'C'		;if there was space, change
	sta	fcb+9		;to COM
	mvi	a,'O'
	sta	fcb+10
	mvi	a,'M'
	sta	fcb+11
;
is$com	mvi	a,0		;zero record count
	sta	fcb+32
	mvi	c,open		;OPEN file command
	lxi	d,fcb		;load address of FCB in DE
	call	bdos		;Open file
	inr	a		;successful?
	jnz	open$ok		;if so, then continue
	call	end$mes		;if not, then tell
;
	db	cr,lf,'Cannot open file',cr,lf,eos
;
open$ok	lxi	d,buffer-offset	;point to where program goes
r$loop:	mvi	c,setdma	;SET DMA command
	push	d		;save it
	call	bdos		;and tell CP/M
	lxi	d,fcb		;point to FCB
	mvi	c,read		;READ sector command
	call	bdos		;do it
	pop	d		;get DMA address back
	ana	a		;EOF?
	jnz	done$read	;if so, then ask for password
	lxi	h,80h		;length of sector
	dad	d		;bump DMA
	xchg			;put new address in DE
	jmp	r$loop		;and read some more
;
done$read:
	xchg			;dma ==> hl
	shld	end$prog-offset	;save last address
gpasag	call	get$pas		;print password message
;
pas$mes	db	'Password: ',eos
;
get$pas	pop	d		;get address of message
	mvi	c,mesout	;PRINT STRING function
	call	bdos		;print it
	lxi	d,defbuf	;point to default buffer
	mvi	a,8		;tell CP/M max chars
	stax	d		;put it there
	mvi	c,incon		;READ LINE command
	call	bdos		;do it
	lxi	h,defbuf+1	;point to length
	lxi	d,password-offset	;point to storage
	lda	defbuf+1	;get length
	ana	a		;set flags
	jz	gpasag		;if 0 then ask again
	inr	a		;plus 1 for length byte
	mov	b,a		;put length in B
mploop	mov	a,m		;get char
	stax	d		;save it
	inx	h		;increment pointer
	inx	d		;  "          "
	dcr	b		;decrement length
	jnz	mploop		;if not zero, then next char
	xra	a		;zero a
	sta	fcb+12		;zero bytes in FCB
	sta	fcb+14
	sta	fcb+32
	mvi	c,open		;OPEN file command
	lxi	d,fcb		;point to FCB
	call	bdos		;open the file
	lxi	d,n$start	;point to new program start
;
	push	d
w$loop1	pop	d		;get DMA
	push	d		;put it back on stack
	mvi	c,setdma	;SET DMA command
	call	bdos		;tell CP/M
	lxi	d,fcb		;point to FCB
	mvi	c,write		;WRITE SECTOR command
	call	bdos		;do it
	pop	h		;get DMA address from stack
	lxi	d,80h		;length of sector
	dad	d		;HL has new DMA
	push	h		;put it on stack
	mov	a,h		;this is to get 2's complement
	cma			;of address. We are subtracting
	mov	d,a		;the current address from the
	mov	a,l		;high address. If the high byte
	cma			;<1 , we are done
	mov	e,a		;
	inx	d		;Now 2's comp. of address in DE
	lhld	end$prog-offset	;get ending address
	dad	d		;Subtract (add 2's comp)
	mov	a,h		;get high byte
	inr	a		;is it FF (-1)?		
	ana	a		;set flags
	jnz	w$loop1		;if not, write another sector
;
	mvi	c,close		;That's it. Close the file
	lxi	d,fcb		;point to FCB
	call	bdos		;do it
	jmp	finish		;goto finish
;
;
n$start:
offset	equ	100h-n$start
;
;	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;	%% WARNING -                                        %%
;	%% From now on, all labels are in                   %%
;	%% the form:                                        %%
;	%%      LABEL   EQU  $+OFFSET                       %%
;	%%  This is to allow the program to run at100H      %%
;	%% when it is saved by the earlier portion.         %%
;	%%  ALL new labels added MUST be in the form        %%
;	%% LABEL   EQU  $+OFFSET for this program to work   %%
;	%% properly.                                        %%
;	%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;
;This is portion of the program is placed at the beginning
;of the program to be PASSWORDed. When it is executed, it will
;ask for a password. If the password is incorrect, the program
;warm starts. If the password is correct, the program is moved
;to the TPA and executed.
;
	lxi	h,0		;save stack pointer
	dad	sp		;stack is in HL
	shld	old$stack	;save it
	lxi	sp,stack	;get new stack
	call	ot$pw		;print password message
;
	db	cr,lf,'Password :'
	db	eos
;
ot$pw	equ	$+offset
	pop	d		;get address of message
	mvi	c,mesout	;PRINT STRING command
	call	bdos		;print it
	lxi	d,newbuf	;point to input buffer
	mvi	c,incon		;READ LINE command
	call	bdos		;read it
;
	lxi	h,password	;point to actual password
	lxi	d,newbuf+1	;point to user's input
	mov	b,m		;get length
;
c$lp	equ	$+offset
	ldax	d		;get char
	cmp	m		;are they the same?
	jnz	boot		;if not, restart
	inx	h		;point to next characters
	inx	d		;  "    "  "        "
	dcr	b		;decrement length
	jnz	c$lp		;if not done, then loop
;
; Now we move a segment of code to a part of the default
; buffer. This segment moves the actual program down to the
; TPA
;
	lxi	h,n$mv		;point to code
	lxi	d,defbuf+20h	;point to new postion
	mvi	b,n$m$len	;length
;
move	equ	$+offset
	mov	a,m		;get byte
	stax	d		;save it
	inx	d		;point to next addresses
	inx	h		;  "   "    "      "
	dcr	b		;decrement length
	jnz	move		;if not done, loop
	jmp	defbuf+20h	;go to segment
;
n$mv	equ	$+offset	;segment that gets moved
	lhld	old$stack	;get stack pointer
	push	h		;save it on stack
	lxi	h,buffer	;get start of actual program
	mov	a,h		;We have to compute the length
	cma			;and because X-Y equals
	mov	d,a		;X + Two's complent(Y), we have
	mov	a,l		;to find the 2's comp. of the
	cma			;first address
	mov	e,a		;
	inx	d		;Y is in DE
	lhld	end$prog	;get last address
	dad	d		;subtract (add 2's comp)
	mov	b,h		;put length in BC
	mov	c,l		; "    "     "  "
	lxi	d,tpa		;point to TPA
	lxi	h,buffer	;point to first address
n$m$lp	equ	defbuf+20h+$+offset-n$mv
	mov	a,m		;get byte
	stax	d		;save byte
	inx	h		;increment address
	inx	d		;    "        "
	dcx	b		;decrement length
	mov	a,b		;check for zero left
	ora	c		;Are we done?
	jnz	n$m$lp		;if not, loop some more
	pop	h		;get stack from stack
	sphl			;put stack in SP
	jmp	tpa		;run program
;
n$m$len	equ	$+offset-n$mv	;length of segment
;
;
password	equ	$+offset ;password storage
	db	0,'         '
;
newbuf	equ	$+offset	;Users input buffer
	db	10H,0,'                '
;
old$stack	equ	$+offset ;place for stack
	ds	2
;
end$prog	equ	$+offset ;place for address
	ds	2
;
buffer	equ	$+offset	;where actual program goes
	end
