1329167Simp--
2344220Skevans-- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3344220Skevans--
4329167Simp-- Copyright (c) 2015 Pedro Souza <pedrosouza@freebsd.org>
5344220Skevans-- Copyright (C) 2018 Kyle Evans <kevans@FreeBSD.org>
6329167Simp-- All rights reserved.
7329167Simp--
8329167Simp-- Redistribution and use in source and binary forms, with or without
9329167Simp-- modification, are permitted provided that the following conditions
10329167Simp-- are met:
11329167Simp-- 1. Redistributions of source code must retain the above copyright
12329167Simp--    notice, this list of conditions and the following disclaimer.
13329167Simp-- 2. Redistributions in binary form must reproduce the above copyright
14329167Simp--    notice, this list of conditions and the following disclaimer in the
15329167Simp--    documentation and/or other materials provided with the distribution.
16329167Simp--
17329167Simp-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18329167Simp-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19329167Simp-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20329167Simp-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21329167Simp-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22329167Simp-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23329167Simp-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24329167Simp-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25329167Simp-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26329167Simp-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27329167Simp-- SUCH DAMAGE.
28329167Simp--
29329167Simp-- $FreeBSD: stable/11/stand/lua/password.lua 345882 2019-04-04 17:29:43Z kevans $
30329167Simp--
31329167Simp
32344220Skevanslocal core = require("core")
33344220Skevanslocal screen = require("screen")
34329167Simp
35344220Skevanslocal password = {}
36329167Simp
37344220Skevanslocal INCORRECT_PASSWORD = "loader: incorrect password"
38344220Skevans-- Asterisks as a password mask
39344220Skevanslocal show_password_mask = false
40344220Skevanslocal twiddle_chars = {"/", "-", "\\", "|"}
41345882Skevanslocal screen_setup = false
42329167Simp
43345882Skevanslocal function setup_screen()
44345882Skevans	screen.clear()
45345882Skevans	screen.defcursor()
46345882Skevans	screen_setup = true
47345882Skevansend
48345882Skevans
49344220Skevans-- Module exports
50344220Skevansfunction password.read(prompt_length)
51344220Skevans	local str = ""
52344220Skevans	local twiddle_pos = 1
53344220Skevans
54344220Skevans	local function draw_twiddle()
55344220Skevans		printc(twiddle_chars[twiddle_pos])
56344220Skevans		-- Reset cursor to just after the password prompt
57344220Skevans		screen.setcursor(prompt_length + 2, screen.default_y)
58344220Skevans		twiddle_pos = (twiddle_pos % #twiddle_chars) + 1
59344220Skevans	end
60344220Skevans
61344220Skevans	-- Space between the prompt and any on-screen feedback
62344220Skevans	printc(" ")
63344220Skevans	while true do
64344220Skevans		local ch = io.getchar()
65344220Skevans		if ch == core.KEY_ENTER then
66344220Skevans			break
67329167Simp		end
68344220Skevans		if ch == core.KEY_BACKSPACE or ch == core.KEY_DELETE then
69344220Skevans			if #str > 0 then
70344220Skevans				if show_password_mask then
71344220Skevans					printc("\008 \008")
72344220Skevans				else
73344220Skevans					draw_twiddle()
74344220Skevans				end
75344220Skevans				str = str:sub(1, #str - 1)
76329167Simp			end
77329167Simp		else
78344220Skevans			if show_password_mask then
79344220Skevans				printc("*")
80344220Skevans			else
81344220Skevans				draw_twiddle()
82344220Skevans			end
83344220Skevans			str = str .. string.char(ch)
84329167Simp		end
85344220Skevans	end
86344220Skevans	return str
87329167Simpend
88329167Simp
89329167Simpfunction password.check()
90344220Skevans	-- pwd is optionally supplied if we want to check it
91344220Skevans	local function doPrompt(prompt, pwd)
92344220Skevans		local attempts = 1
93344220Skevans
94344220Skevans		local function clear_incorrect_text_prompt()
95344220Skevans			printc("\r" .. string.rep(" ", #INCORRECT_PASSWORD))
96329167Simp		end
97344220Skevans
98345882Skevans		if not screen_setup then
99345882Skevans			setup_screen()
100345882Skevans		end
101345882Skevans
102329167Simp		while true do
103344220Skevans			if attempts > 1 then
104344220Skevans				clear_incorrect_text_prompt()
105329167Simp			end
106344220Skevans			screen.defcursor()
107344220Skevans			printc(prompt)
108344220Skevans			local read_pwd = password.read(#prompt)
109344220Skevans			if pwd == nil or pwd == read_pwd then
110344220Skevans				-- Clear the prompt + twiddle
111344220Skevans				printc(string.rep(" ", #prompt + 5))
112344220Skevans				return read_pwd
113344220Skevans			end
114344220Skevans			printc("\n" .. INCORRECT_PASSWORD)
115344220Skevans			attempts = attempts + 1
116344220Skevans			loader.delay(3*1000*1000)
117329167Simp		end
118329167Simp	end
119344220Skevans	local function compare(prompt, pwd)
120344220Skevans		if pwd == nil then
121344220Skevans			return
122344220Skevans		end
123344220Skevans		doPrompt(prompt, pwd)
124344220Skevans	end
125329167Simp
126344220Skevans	local boot_pwd = loader.getenv("bootlock_password")
127344220Skevans	compare("Bootlock password:", boot_pwd)
128329167Simp
129344220Skevans	local geli_prompt = loader.getenv("geom_eli_passphrase_prompt")
130344220Skevans	if geli_prompt ~= nil and geli_prompt:lower() == "yes" then
131344220Skevans		local passphrase = doPrompt("GELI Passphrase:")
132344220Skevans		loader.setenv("kern.geom.eli.passphrase", passphrase)
133329167Simp	end
134344220Skevans
135344220Skevans	local pwd = loader.getenv("password")
136344220Skevans	if pwd ~= nil then
137344220Skevans		core.autoboot()
138345882Skevans		-- The autoboot sequence was interrupted, so we'll need to
139345882Skevans		-- prompt for a password.  Put the screen back into a known
140345882Skevans		-- good state, otherwise we're drawing back a couple lines
141345882Skevans		-- in the middle of other text.
142345882Skevans		setup_screen()
143344220Skevans	end
144344220Skevans	compare("Loader password:", pwd)
145329167Simpend
146329167Simp
147329167Simpreturn password
148