check-password.4th revision 339697
1\ Copyright (c) 2006-2015 Devin Teske <dteske@FreeBSD.org>
2\ All rights reserved.
3\ 
4\ Redistribution and use in source and binary forms, with or without
5\ modification, are permitted provided that the following conditions
6\ are met:
7\ 1. Redistributions of source code must retain the above copyright
8\    notice, this list of conditions and the following disclaimer.
9\ 2. Redistributions in binary form must reproduce the above copyright
10\    notice, this list of conditions and the following disclaimer in the
11\    documentation and/or other materials provided with the distribution.
12\ 
13\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16\ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23\ SUCH DAMAGE.
24\ 
25\ $FreeBSD: stable/11/stand/forth/check-password.4th 339697 2018-10-24 23:17:17Z dteske $
26
27marker task-check-password.4th
28
29include /boot/screen.4th
30
31vocabulary password-processing
32only forth also password-processing definitions
33
3413  constant enter_key       \ The decimal ASCII value for Enter key
358   constant bs_key          \ The decimal ASCII value for Backspace key
3621  constant ctrl_u          \ The decimal ASCII value for Ctrl-U sequence
37255 constant readmax         \ Maximum number of characters for the password
38
39variable read-tick           \ Twiddle position (used by read)
40variable read-start          \ Starting X offset (column)(used by read)
41
42create readval readmax allot \ input obtained (up to readmax characters)
43variable readlen             \ input length
44
45\ This function blocks program flow (loops forever) until a key is pressed.
46\ The key that was pressed is added to the top of the stack in the form of its
47\ decimal ASCII representation. Note: the stack cannot be empty when this
48\ function starts or an underflow exception will occur. Simplest way to prevent
49\ this is to pass 0 as a stack parameter (ie. `0 sgetkey'). This function is
50\ called by the read function. You need not call it directly. NOTE: arrow keys
51\ show as 0 on the stack
52\ 
53: sgetkey ( -- )
54
55	begin \ Loop forever
56		key? if \ Was a key pressed? (see loader(8))
57			drop \ Remove stack-cruft
58			key  \ Get the key that was pressed
59
60			\ Check key pressed (see loader(8)) and input limit
61			dup 0<> if ( and ) readlen @ readmax < if
62				\ Spin the twiddle and then exit this function
63				read-tick @ dup 1+ 4 mod read-tick !
64				2 spaces
65				dup 0 = if ( 1 ) ." /" else
66				dup 1 = if ( 2 ) ." -" else
67				dup 2 = if ( 3 ) ." \" else
68				dup 3 = if ( 4 ) ." |" else
69					1 spaces
70				then then then then drop
71				read-start @ 25 at-xy
72				exit
73			then then
74
75			\ Always allow Backspace, Enter, and Ctrl-U
76			dup bs_key = if exit then
77			dup enter_key = if exit then
78			dup ctrl_u = if exit then
79		then
80		50 ms \ Sleep for 50 milliseconds (see loader(8))
81	again
82;
83
84: cfill ( c c-addr/u -- )
85	begin dup 0> while
86		-rot 2dup c! 1+ rot 1-
87	repeat 2drop drop
88;
89
90: read-reset ( -- )
91	0 readlen !
92	0 readval readmax cfill
93;
94
95: read ( c-addr/u -- ) \ Expects string prompt as stack input
96
97	0 25 at-xy           \ Move the cursor to the bottom-left
98	dup 1+ read-start !  \ Store X offset after the prompt
99	0 readlen !          \ Initialize the read length
100	type                 \ Print the prompt
101
102	begin \ Loop forever
103
104		0 sgetkey \ Block here, waiting for a key to be pressed
105
106		\ We are not going to echo the password to the screen (for
107		\ security reasons). If Enter is pressed, we process the
108		\ password, otherwise augment the key to a string.
109
110		dup enter_key = if
111			drop     \ Clean up stack cruft
112			3 spaces \ Erase the twiddle
113			10 emit  \ Echo new line
114			exit
115		else dup ctrl_u = if
116			3 spaces read-start @ 25 at-xy \ Erase the twiddle
117			0 readlen ! \ Reset input to NULL
118		else dup bs_key = if
119			readlen @ 1 - dup readlen ! \ Decrement input length
120			dup 0< if drop 0 dup readlen ! then \ Don't go negative
121			0= if 3 spaces read-start @ 25 at-xy then \ Twiddle
122		else dup \ Store the character
123			\ NB: sgetkey prevents overflow by way of blocking
124			\     at readmax except for Backspace or Enter
125			readlen @ 1+ dup readlen ! 1- readval + c!
126		then then then
127
128		drop \ last key pressed
129	again \ Enter was not pressed; repeat
130;
131
132only forth definitions also password-processing also support-functions
133
134: check-password ( -- )
135
136	\ Do not allow the user to proceed beyond this point if a boot-lock
137	\ password has been set (preventing even boot from proceeding)
138	s" bootlock_password" getenv dup -1 <> if
139		dup readmax > if drop readmax then
140		begin
141			s" Boot Password: " read ( prompt -- )
142			2dup readval readlen @ compare 0<>
143		while
144			3000 ms ." loader: incorrect password" 10 emit
145		repeat
146		2drop read-reset
147	else drop then
148
149	\ Prompt for GEOM ELI (geli(8)) passphrase if enabled
150	s" geom_eli_passphrase_prompt" getenv dup -1 <> if
151		s" YES" compare-insensitive 0= if
152			s" GELI Passphrase: " read ( prompt -- )
153			readval readlen @ s" kern.geom.eli.passphrase" setenv
154			read-reset
155		then
156	else drop then
157
158	\ Exit if a password was not set
159	s" password" getenv -1 = if exit else drop then
160
161	\ We should prevent the user from visiting the menu or dropping to the
162	\ interactive loader(8) prompt, but still allow the machine to boot...
163
164	any_conf_read? if load_kernel load_modules then
165	0 autoboot
166
167	\ Only reached if autoboot fails for any reason (including if/when
168	\ the user aborts/escapes the countdown sequence leading to boot).
169
170	s" password" getenv dup readmax > if drop readmax then
171	begin
172		s" Password: " read ( prompt -- )
173		2dup readval readlen @ compare 0= if \ Correct password?
174			2drop read-reset exit
175		then
176		3000 ms ." loader: incorrect password" 10 emit
177	again
178;
179
180only forth definitions
181