functions 8.04 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/sh
# Shell functions for most initialization scripts

die() {
	echo >&2 "$*";
	exit 1;
}

warn() {
	echo >&2 "$*";
}

recovery() {
	echo >&2 "!!!!! $*"

	# Remove any temporary secret files that might be hanging around
	# but recreate the directory so that new tools can use it.
18
	shred -n 10 -z -u /tmp/secret/* 2> /dev/null
19
20
	rm -rf /tmp/secret
	mkdir -p /tmp/secret
21
22
23
24

	# ensure /tmp/config exists for recovery scripts that depend on it
	touch /tmp/config

25
26
27
	if [ "$CONFIG_TPM" = y ]; then
		tpm extend -ix 4 -ic recovery
	fi
28

29
30
31
32
33
34
35
36
37
38
39
40
41
	while [ true ]
	do
		echo >&2 "!!!!! Starting recovery shell"
		sleep 1

		if [ -x /bin/setsid ]; then
			/bin/setsid -c /bin/ash
		else
			/bin/ash
		fi
		# clear screen
		printf "\033c"
	done
42
43
}

44
45
46
47
pause_recovery() {
	read -p 'Hit enter to proceed to recovery shell:'
	recovery $*
}
48
49

pcrs() {
50
	head -8 /sys/class/tpm/tpm0/pcrs
51
}
52
53
54

confirm_totp()
{
55
	prompt="$1"
56
	last_half=X
57
	unset totp_confirm
58
59
60
61
62
63
64

	while true; do

		# update the TOTP code every thirty seconds
		date=`date "+%Y-%m-%d %H:%M:%S"`
		seconds=`date "+%s"`
		half=`expr \( $seconds % 60 \) / 30`
65
		if [ "$CONFIG_TPM" != y ]; then
66
67
			TOTP="NO TPM"
		elif [ "$half" != "$last_half" ]; then
68
69
70
71
72
73
74
75
76
77
78
79
			last_half=$half;
			TOTP=`unseal-totp` \
			|| recovery "TOTP code generation failed"
		fi

		echo -n "$date $TOTP: "

		# read the first character, non-blocking
		read \
			-t 1 \
			-n 1 \
			-s \
80
			-p "$prompt" \
81
82
83
84
85
86
87
88
89
90
			totp_confirm \
		&& break

		# nothing typed, redraw the line
		echo -ne '\r'
	done

	# clean up with a newline
	echo
}
91

92
enable_usb()
93
{
94
95
96
97
98
99
100
101
102
103
104
105
106
	if [ "$CONFIG_LINUX_USB_COMPANION_CONTROLLER" = y ]; then
		if ! lsmod | grep -q uhci_hcd; then
			insmod /lib/modules/uhci-hcd.ko \
			|| die "uhci_hcd: module load failed"
		fi
		if ! lsmod | grep -q ohci_hcd; then
			insmod /lib/modules/ohci-hcd.ko \
			|| die "ohci_hcd: module load failed"
		fi
		if ! lsmod | grep -q ohci_pci; then
			insmod /lib/modules/ohci-pci.ko \
			|| die "ohci_pci: module load failed"
		fi
107
	fi
108
109
110
111
112
113
114
115
116
117
	if ! lsmod | grep -q ehci_hcd; then
		insmod /lib/modules/ehci-hcd.ko \
		|| die "ehci_hcd: module load failed"
	fi
	if ! lsmod | grep -q ehci_pci; then
		insmod /lib/modules/ehci-pci.ko \
		|| die "ehci_pci: module load failed"
	fi
	if ! lsmod | grep -q xhci_hcd; then
		insmod /lib/modules/xhci-hcd.ko \
118
		|| die "xhci_hcd: module load failed"
119
120
121
	fi
	if ! lsmod | grep -q xhci_pci; then
		insmod /lib/modules/xhci-pci.ko \
122
		|| die "xhci_pci: module load failed"
123
124
		sleep 2
	fi
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
}

confirm_gpg_card()
{
	read \
		-n 1 \
		-p "Please confirm that your GPG card is inserted [Y/n]: " \
		card_confirm
	echo

	if [ "$card_confirm" != "y" \
		-a "$card_confirm" != "Y" \
		-a -n "$card_confirm" ] \
	; then
		die "gpg card not confirmed"
	fi

	# setup the USB so we can reach the GPG card
	enable_usb
144

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
	echo -e "\nVerifying presence of GPG card...\n"
	# ensure we don't exit without retrying
	errexit=$(set -o | grep errexit | awk '{print $2}')
	set +e
	gpg --card-status > /dev/null
	if [ $? -ne 0 ]; then
	  # prompt for reinsertion and try a second time
	  read -n1 -r -p \
	      "Can't access GPG key; remove and reinsert, then press Enter to retry. " \
	      ignored
	  # restore prev errexit state
	  if [ "$errexit" = "on" ]; then
	    set -e
	  fi
	  # retry card status
	  gpg --card-status > /dev/null \
	  	|| die "gpg card read failed"
	fi
	# restore prev errexit state
	if [ "$errexit" = "on" ]; then
	  set -e
	fi
167
}
168
169
170
171


check_tpm_counter()
{
Kyle Rankin's avatar
Kyle Rankin committed
172
  LABEL=${2:-3135106223}
173
174
175
176
177
	# if the /boot.hashes file already exists, read the TPM counter ID
	# from it.
	if [ -r "$1" ]; then
		TPM_COUNTER=`grep counter- "$1" | cut -d- -f2`
	else
Kyle Rankin's avatar
Kyle Rankin committed
178
		warn "$1 does not exist; creating new TPM counter"
179
180
181
182
183
		read -s -p "TPM Owner password: " tpm_password
		echo
		tpm counter_create \
			-pwdo "$tpm_password" \
			-pwdc '' \
184
			-la $LABEL \
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
		| tee /tmp/counter \
		|| die "Unable to create TPM counter"
		TPM_COUNTER=`cut -d: -f1 < /tmp/counter`
	fi

	if [ -z "$TPM_COUNTER" ]; then
		die "$1: TPM Counter not found?"
	fi
}

read_tpm_counter()
{
	tpm counter_read -ix "$1" | tee "/tmp/counter-$1" \
	|| die "Counter read failed"
}

increment_tpm_counter()
{
	tpm counter_increment -ix "$1" -pwdc '' \
		| tee /tmp/counter-$1 \
	|| die "Counter increment failed"
}

check_config() {
	if [ ! -d /tmp/kexec ]; then
		mkdir /tmp/kexec \
		|| die 'Failed to make kexec tmp dir'
	else
		rm -rf /tmp/kexec/* \
		|| die 'Failed to empty kexec tmp dir'
	fi

	if [ ! -r $1/kexec.sig ]; then
		return
	fi

	if [ `find $1/kexec*.txt | wc -l` -eq 0 ]; then
		return
	fi

225
226
227
228
	if [ "$2" != "force" ]; then
		if ! sha256sum `find $1/kexec*.txt` | gpgv $1/kexec.sig - ; then
			die 'Invalid signature on kexec boot params'
		fi
229
230
231
232
233
234
	fi

	echo "+++ Found verified kexec boot params"
	cp $1/kexec*.txt /tmp/kexec \
	|| die "Failed to copy kexec boot params to tmp"
}
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250

preserve_rom() {
	new_rom="$1"
	old_files=`cbfs -t 50 -l 2>/dev/null | grep "^heads/"`

	for old_file in `echo $old_files`; do
		new_file=`cbfs -o $1 -l | grep -x $old_file`
		if [ -z "$new_file" ]; then
			echo "+++ Adding $old_file to $1"
			cbfs -t 50 -r $old_file >/tmp/rom.$$ \
			|| die "Failed to read cbfs file from ROM"
			cbfs -o $1 -a $old_file -f /tmp/rom.$$ \
			|| die "Failed to write cbfs file to new ROM file"
		fi
	done
}
251
replace_config() {
252
253
254
	CONFIG_FILE=$1
	CONFIG_OPTION=$2
	NEW_SETTING=$3
255

256
	touch $CONFIG_FILE
257
# first pull out the existing option from the global config and place in a tmp file
258
259
	awk "gsub(\"^export ${CONFIG_OPTION}=.*\",\"export ${CONFIG_OPTION}=\\\"${NEW_SETTING}\\\"\")" /tmp/config > ${CONFIG_FILE}.tmp
	awk "gsub(\"^${CONFIG_OPTION}=.*\",\"${CONFIG_OPTION}=\\\"${NEW_SETTING}\\\"\")" /tmp/config >> ${CONFIG_FILE}.tmp
260
261

# then copy any remaining settings from the existing config file, minus the option you changed
262
	grep -v "^export ${CONFIG_OPTION}=" ${CONFIG_FILE} | grep -v "^${CONFIG_OPTION}=" >> ${CONFIG_FILE}.tmp || true
263
  sort ${CONFIG_FILE}.tmp | uniq > ${CONFIG_FILE}
264
	rm -f ${CONFIG_FILE}.tmp
265
266
}
combine_configs() {
267
	cat /etc/config* > /tmp/config
268
}
269

270
271
272
273
274
275
276
277
278
279
280
281
282
# Generate secret value using first 20 chars of ROM SHA256 hash
secret_from_rom_hash() {
	local ROM_IMAGE="/tmp/coreboot-notpm.rom"

	echo -e "\nTPM not detected; measuring ROM directly\n" 1>&2
	# use a previously-copied image if it exists
	if [ -f ${ROM_IMAGE} ]; then
		sha256sum ${ROM_IMAGE} | cut -f1 -d ' ' | cut -c 1-20 | tr -d '\n'
	else
		flash.sh -s ${ROM_IMAGE} | cut -c 1-20 | tr -d '\n'
	fi
}

283
284
285
286
287
288
289
290
291
update_checksums()
{
	# clear screen
	printf "\033c"
	# ensure /boot mounted
	if ! grep -q /boot /proc/mounts ; then
		mount -o ro /boot \
		|| recovery "Unable to mount /boot"
	fi
292

293
	# remount RW
294
	mount -o rw,remount /boot
295
296
297
298

	# sign and auto-roll config counter
	extparam=
	if [ "$CONFIG_TPM" = "y" ]; then
299
		extparam=-r
300
	fi
301
	if ! kexec-sign-config -p /boot -u $extparam ; then
302
303
304
	  echo "Failed to sign default config; press Enter to continue."
	  read
	fi
305
306
307
308

	# switch back to ro mode
	mount -o ro,remount /boot
}
309
310
311
312
313
314

# detect and set /boot device
# mount /boot if successful
detect_boot_device()
{
	# unmount /boot to be safe
315
	cd / && umount /boot 2>/dev/null
316
317
318

	# check $CONFIG_BOOT_DEV if set/valid
	if [ -e "$CONFIG_BOOT_DEV" ]; then
319
320
321
322
323
		if mount -o ro $CONFIG_BOOT_DEV /boot >/dev/null 2>&1; then
			if ls -d /boot/grub* >/dev/null 2>&1; then
				# CONFIG_BOOT_DEV is valid device and contains an installed OS
				return 0
			fi
324
325
326
327
		fi
	fi

	# generate list of possible boot devices
328
	fdisk -l | grep "Disk /dev/" | cut -f2 -d " " | cut -f1 -d ":" > /tmp/disklist
329

330
331
332
333
	# filter out extraneous options
	> /tmp/boot_device_list
	for i in `cat /tmp/disklist`; do
		# remove block device from list if numeric partitions exist, since not bootable
334
		DEV_NUM_PARTITIONS=$((`ls -1 $i* | wc -l`-1))
335
336
337
338
339
340
		if [ ${DEV_NUM_PARTITIONS} -eq 0 ]; then
			echo $i >> /tmp/boot_device_list
		else
			ls $i* | tail -${DEV_NUM_PARTITIONS} >> /tmp/boot_device_list
		fi
	done
341

342
343
344
	# iterate thru possible options and check for grub dir
	for i in `cat /tmp/boot_device_list`; do
		umount /boot 2>/dev/null
345
346
347
348
349
		if mount -o ro $i /boot >/dev/null 2>&1; then
			if ls -d /boot/grub* >/dev/null 2>&1; then
				CONFIG_BOOT_DEV="$i"
				return 0
			fi
350
351
352
353
354
355
356
357
		fi
	done

	# no valid boot device found
	echo "Unable to locate /boot files on any mounted disk"
	umount /boot 2>/dev/null
	return 1
}