\ Copyright (c) 2006-2015 Devin Teske \ All rights reserved. \ \ Redistribution and use in source and binary forms, with or without \ modification, are permitted provided that the following conditions \ are met: \ 1. Redistributions of source code must retain the above copyright \ notice, this list of conditions and the following disclaimer. \ 2. Redistributions in binary form must reproduce the above copyright \ notice, this list of conditions and the following disclaimer in the \ documentation and/or other materials provided with the distribution. \ \ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND \ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE \ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \ SUCH DAMAGE. \ \ $FreeBSD: head/sys/boot/forth/check-password.4th 281616 2015-04-16 20:53:15Z dteske $ marker task-check-password.4th include /boot/screen.4th vocabulary password-processing only forth also password-processing definitions 13 constant enter_key \ The decimal ASCII value for Enter key 8 constant bs_key \ The decimal ASCII value for Backspace key 21 constant ctrl_u \ The decimal ASCII value for Ctrl-U sequence 255 constant readmax \ Maximum number of characters for the password variable read-tick \ Twiddle position (used by read) variable read-start \ Starting X offset (column)(used by read) create readval readmax allot \ input obtained (up to readmax characters) variable readlen \ input length \ This function blocks program flow (loops forever) until a key is pressed. \ The key that was pressed is added to the top of the stack in the form of its \ decimal ASCII representation. Note: the stack cannot be empty when this \ function starts or an underflow exception will occur. Simplest way to prevent \ this is to pass 0 as a stack parameter (ie. `0 sgetkey'). This function is \ called by the read function. You need not call it directly. NOTE: arrow keys \ show as 0 on the stack \ : sgetkey ( -- ) begin \ Loop forever key? if \ Was a key pressed? (see loader(8)) drop \ Remove stack-cruft key \ Get the key that was pressed \ Check key pressed (see loader(8)) and input limit dup 0<> if ( and ) readlen @ readmax < if \ Spin the twiddle and then exit this function read-tick @ dup 1+ 4 mod read-tick ! 2 spaces dup 0 = if ( 1 ) ." /" else dup 1 = if ( 2 ) ." -" else dup 2 = if ( 3 ) ." \" else dup 3 = if ( 4 ) ." |" else 1 spaces then then then then drop read-start @ 25 at-xy exit then then \ Always allow Backspace, Enter, and Ctrl-U dup bs_key = if exit then dup enter_key = if exit then dup ctrl_u = if exit then then 50 ms \ Sleep for 50 milliseconds (see loader(8)) again ; : cfill ( c c-addr/u -- ) begin dup 0> while -rot 2dup c! 1+ rot 1- repeat 2drop drop ; : read-reset ( -- ) 0 readlen ! 0 readval readmax cfill ; : read ( c-addr/u -- ) \ Expects string prompt as stack input 0 25 at-xy \ Move the cursor to the bottom-left dup 1+ read-start ! \ Store X offset after the prompt 0 readlen ! \ Initialize the read length type \ Print the prompt begin \ Loop forever 0 sgetkey \ Block here, waiting for a key to be pressed \ We are not going to echo the password to the screen (for \ security reasons). If Enter is pressed, we process the \ password, otherwise augment the key to a string. dup enter_key = if drop \ Clean up stack cruft 3 spaces \ Erase the twiddle 10 emit \ Echo new line exit else dup ctrl_u = if 3 spaces read-start @ 25 at-xy \ Erase the twiddle 0 readlen ! \ Reset input to NULL else dup bs_key = if readlen @ 1 - dup readlen ! \ Decrement input length dup 0< if drop 0 dup readlen ! then \ Don't go negative 0= if 3 spaces read-start @ 25 at-xy then \ Twiddle else dup \ Store the character \ NB: sgetkey prevents overflow by way of blocking \ at readmax except for Backspace or Enter readlen @ 1+ dup readlen ! 1- readval + c! then then then drop \ last key pressed again \ Enter was not pressed; repeat ; only forth definitions also password-processing : check-password ( -- ) \ Do not allow the user to proceed beyond this point if a boot-lock \ password has been set (preventing even boot from proceeding) s" bootlock_password" getenv dup -1 <> if dup readmax > if drop readmax then begin s" Boot Password: " read ( prompt -- ) 2dup readval readlen @ compare 0<> while 3000 ms ." loader: incorrect password" 10 emit repeat 2drop read-reset else drop then \ Prompt for GEOM ELI (geli(8)) passphrase if enabled s" geom_eli_passphrase_prompt" getenv dup -1 <> if s" YES" compare-insensitive 0= if s" GELI Passphrase: " read ( prompt -- ) readval readlen @ s" kern.geom.eli.passphrase" setenv read-reset then else drop then \ Exit if a password was not set s" password" getenv -1 = if exit else drop then \ We should prevent the user from visiting the menu or dropping to the \ interactive loader(8) prompt, but still allow the machine to boot... 0 autoboot \ Only reached if autoboot fails for any reason (including if/when \ the user aborts/escapes the countdown sequence leading to boot). s" password" getenv dup readmax > if drop readmax then begin s" Password: " read ( prompt -- ) 2dup readval readlen @ compare 0= if \ Correct password? 2drop read-reset exit then 3000 ms ." loader: incorrect password" 10 emit again ; only forth definitions