]> git.pld-linux.org Git - packages/cryptsetup-luks.git/blame - cryptsetup-luks-initramfs-root-hook
- package python binding (as python-pycryptsetup)
[packages/cryptsetup-luks.git] / cryptsetup-luks-initramfs-root-hook
CommitLineData
b32f9594
JR
1#!/bin/sh
2
3PREREQ=""
4
5prereqs()
6{
7 echo "$PREREQ"
8}
9
10case $1 in
11prereqs)
12 prereqs
13 exit 0
14 ;;
15esac
16
17. /usr/share/initramfs-tools/hook-functions
18
19get_root_device() {
20 local device mount type options dump pass
21
22 if [ ! -r /etc/fstab ]; then
23 return 1
24 fi
25
26 grep '^[^#]' /etc/fstab | \
27 while read device mount type options dump pass; do
28 if [ "$mount" = "/" ]; then
29 echo "$device"
30 return
31 fi
32 done
33}
34
35get_resume_devices() {
36 local device opt count dupe candidates devices
37 candidates=""
38
39 # First, get a list of potential resume devices
40
41 # uswsusp
42 if [ -e /etc/uswsusp.conf ]; then
43 device=$(sed -rn 's/^resume device[[:space:]]*[:=][[:space:]]*// p' /etc/uswsusp.conf)
44 if [ -n "$device" ]; then
45 candidates="$candidates $device"
46 fi
47 fi
48
49 # uswsusp - again...
50 if [ -e /etc/suspend.conf ]; then
51 device=$(sed -rn 's/^resume device[[:space:]]*[:=][[:space:]]*// p' /etc/suspend.conf)
52 if [ -n "$device" ]; then
53 candidates="$candidates $device"
54 fi
55 fi
56
57 # regular swsusp
58 for opt in $(cat /proc/cmdline); do
59 case $opt in
60 resume=*)
61 device="${opt#resume=}"
62 candidates="$candidates $device"
63 ;;
64 esac
65 done
66
67 # initramfs-tools
68 if [ -e /etc/initramfs-tools/conf.d/resume ]; then
69 device=$(sed -rn 's/^RESUME[[:space:]]*=[[:space:]]*// p' /etc/initramfs-tools/conf.d/resume)
70 if [ -n "$device" ]; then
71 candidates="$candidates $device"
72 fi
73 fi
74
75 # Now check the sanity of all candidates
76 devices=""
77 count=0
78 for device in $candidates; do
79 # Weed out clever defaults
80 if [ "$device" = "<path_to_resume_device_file>" ]; then
81 continue
82 fi
83
84 # Weed out duplicates
85 dupe=0
86 for opt in $devices; do
87 if [ "$device" = "$opt" ]; then
88 dupe=1
89 fi
90 done
91 if [ $dupe -eq 1 ]; then
92 continue
93 fi
94
95 # This device seems ok
96 devices="$devices $device"
97 count=$(( $count + 1 ))
98 done
99
100 if [ $count -gt 1 ]; then
101 echo "cryptsetup: WARNING: found more than one resume device candidate:" >&2
102 for device in $devices; do
103 echo " $device" >&2
104 done
105 fi
106
107 if [ $count -gt 0 ]; then
108 echo $devices
109 fi
110
111 return 0
112}
113
114node_is_in_crypttab() {
115 local node
116 node="$1"
117
118 grep -q ^$node /etc/crypttab
119 return $?
120}
121
122get_lvm_deps() {
123 local node deps maj min depnode
124 node="$1"
125
126 if [ -z $node ]; then
127 echo "cryptsetup: WARNING: get_lvm_deps - invalid arguments" >&2
128 return 1
129 fi
130
131 if ! deps=$(dmsetup deps "$node" 2> /dev/null | sed 's/[^:]*: *//;s/[ (]//g;s/)/ /g'); then
132 echo "cryptsetup: WARNING: failed to find deps for $node" >&2
133 return 1
134 fi
135
136 # We should now have a list of major,minor pairs, e.g. "3,2 3,3"
137 for dep in $deps; do
138 maj=${dep%,*}
139 min=${dep#*,}
140 depnode=$(dmsetup ls | sed -n "s/\\([^ ]*\\) *($maj, $min)/\\1/p" | sed -e "s/[ \t]*$//")
141 if [ -z "$depnode" ]; then
142 continue
143 fi
144 if [ "$(dmsetup table "$depnode" 2> /dev/null | cut -d' ' -f3)" != "crypt" ]; then
145 get_lvm_deps "$depnode"
146 continue
147 fi
148 echo "$depnode"
149 done
150
151 return 0
152}
153
154get_device_opts() {
155 local target source link extraopts rootopts opt
156 target="$1"
157 extraopts="$2"
158 KEYSCRIPT=""
159 OPTIONS=""
160
161 if [ -z "$target" ]; then
162 echo "cryptsetup: WARNING: get_device_opts - invalid arguments" >&2
163 return 1
164 fi
165
166 opt=$( grep ^$target /etc/crypttab | head -1 | sed 's/[[:space:]]\+/ /g' )
167 source=$( echo $opt | cut -d " " -f2 )
168 key=$( echo $opt | cut -d " " -f3 )
169 rootopts=$( echo $opt | cut -d " " -f4- )
170
171 if [ -z "$opt" ] || [ -z "$source" ] || [ -z "$key" ] || [ -z "$rootopts" ]; then
172 echo "cryptsetup: WARNING: invalid line in /etc/crypttab - $opt" >&2
173 return 1
174 fi
175
176 # Sanity checks for $source
177 if [ -h "$source" ]; then
178 link=$(readlink -nqe "$source")
179 if [ -z "$link" ]; then
180 echo "cryptsetup: WARNING: $source is a dangling symlink" >&2
181 return 1
182 fi
183
184 if [ "$link" != "${link#/dev/mapper/}" ]; then
185 echo "cryptsetup: NOTE: using $link instead of $source for $target" >&2
186 source="$link"
187 fi
188 fi
189
190 # Sanity checks for $key
191 if [ "$key" = "/dev/random" ] || [ "$key" = "/dev/urandom" ]; then
192 echo "cryptsetup: WARNING: target $target has a random key, skipped" >&2
193 return 1
194 fi
195
196 if [ -n "$extraopts" ]; then
197 rootopts="$extraopts,$rootopts"
198 fi
199
200 # We have all the basic options, let's go trough them
201 OPTIONS="target=$target,source=$source,key=$key"
202 local IFS=", "
203 unset HASH_FOUND
204 unset LUKS_FOUND
205 for opt in $rootopts; do
206 case $opt in
207 cipher=*)
208 OPTIONS="$OPTIONS,$opt"
209 ;;
210 hash=*)
211 OPTIONS="$OPTIONS,$opt"
212 HASH_FOUND=1
213 ;;
214 size=*)
215 OPTIONS="$OPTIONS,$opt"
216 ;;
217 lvm=*)
218 OPTIONS="$OPTIONS,$opt"
219 ;;
220 keyscript=*)
221 opt=${opt#keyscript=}
222 if [ ! -x "/lib/cryptsetup/scripts/$opt" ] && [ ! -x "$opt" ]; then
223 echo "cryptsetup: WARNING: target $target has an invalid keyscript, skipped" >&2
224 return 1
225 fi
226 KEYSCRIPT="$opt"
227 OPTIONS="$OPTIONS,keyscript=/keyscripts/$(basename "$opt")"
228 ;;
229 tries=*)
230 OPTIONS="$OPTIONS,$opt"
231 ;;
232 luks)
233 LUKS_FOUND=1
234 ;;
235 *)
236 # Presumably a non-supported option
237 ;;
238 esac
239 done
240
241 # Warn for missing hash option, unless we have a LUKS partition
242 if [ -z "$HASH_FOUND" ] && [ -z "$LUKS_FOUND" ]; then
243 echo "WARNING: Option hash missing in crypttab for target $target, assuming ripemd160." >&2
244 echo " If this is wrong, this initramfs image will not boot." >&2
245 echo " Please read /usr/share/doc/cryptsetup/README.initramfs.gz and add" >&2
246 echo " the correct hash option to your /etc/crypttab." >&2
247 fi
248
249 # If keyscript is set, the "key" is just an argument to the script
250 if [ "$key" != "none" ] && [ -z "$KEYSCRIPT" ]; then
251 echo "cryptsetup: WARNING: target $target uses a key file, skipped" >&2
252 return 1
253 fi
254}
255
256get_device_modules() {
257 local node value cipher blockcipher ivhash
258 node="$1"
259
260 # Check the ciphers used by the active root mapping
261 value=$(dmsetup table "$node" | cut -d " " -f4)
262 cipher=$(echo "$value" | cut -d ":" -f1 | cut -d "-" -f1)
263 blockcipher=$(echo "$value" | cut -d ":" -f1 | cut -d "-" -f2)
264 ivhash=$(echo "$value" | cut -d ":" -s -f2)
265
266 if [ -n "$cipher" ]; then
267 echo "$cipher"
268 else
269 return 1
270 fi
271
272 if [ -n "$blockcipher" ] && [ "$blockcipher" != "plain" ]; then
273 echo "$blockcipher"
274 fi
275
276 if [ -n "$ivhash" ] && [ "$ivhash" != "plain" ]; then
277 echo "$ivhash"
278 fi
279 return 0
280}
281
282canonical_device() {
283 local dev altdev
284 dev="$1"
285
286 altdev="${dev#LABEL=}"
287 if [ "$altdev" != "$dev" ]; then
288 dev="/dev/disk/by-label/$altdev"
289 fi
290
291 altdev="${dev#UUID=}"
292 if [ "$altdev" != "$dev" ]; then
293 dev="/dev/disk/by-uuid/$altdev"
294 fi
295
296 if [ -h "$dev" ]; then
297 dev=$(readlink -e "$dev")
298 fi
299
300 altdev="${dev#/dev/mapper/}"
301 if [ "$altdev" != "$dev" ]; then
302 echo "$altdev"
303 return 0
304 fi
305
306 return 1
307}
308
309add_device() {
310 local node nodes opts lastopts i count
311 nodes="$1"
312 opts="" # Applied to all nodes
313 lastopts="" # Applied to last node
314
315 if [ -z "$nodes" ]; then
316 return 0
317 fi
318
319 # Check that it is a node under /dev/mapper/
320 nodes=$(canonical_device "$nodes") || return 0
321
322 # Can we find this node in crypttab
323 if ! node_is_in_crypttab "$nodes"; then
324 # dm node but not in crypttab, is it a lvm device backed by dm-crypt nodes?
325 lvmnodes=$(get_lvm_deps "$nodes") || return 1
326
327 # not backed by any dm-crypt nodes; stop here
328 if [ -z "$lvmnodes" ]; then
329 return 0
330 fi
331
332 # It is a lvm device!
333 lastopts="lvm=$nodes"
334 nodes="$lvmnodes"
335 fi
336
337 # Prepare to setup each node
338 count=$(echo "$nodes" | wc -w)
339 i=1
340 for node in $nodes; do
341 # Prepare the additional options
342 if [ $i -eq $count ]; then
343 if [ -z "$opts" ]; then
344 opts="$lastopts"
345 else
346 opts="$opts,$lastopts"
347 fi
348 fi
349
350 # Get crypttab root options
351 if ! get_device_opts "$node" "$opts"; then
352 continue
353 fi
354 echo "$OPTIONS" >> "$DESTDIR/conf/conf.d/cryptroot"
355
356 # If we have a keyscript, make sure it is included
357 if [ -n "$KEYSCRIPT" ]; then
358 if [ ! -d "$DESTDIR/keyscripts" ]; then
359 mkdir "$DESTDIR/keyscripts"
360 fi
361
362 if [ -e "/lib/cryptsetup/scripts/$KEYSCRIPT" ]; then
363 copy_exec "/lib/cryptsetup/scripts/$KEYSCRIPT" /keyscripts
364 elif [ -e "$KEYSCRIPT" ]; then
365 copy_exec "$KEYSCRIPT" /keyscripts
366 else
367 echo "cryptsetup: WARNING: failed to find keyscript $KEYSCRIPT" >&2
368 continue
369 fi
370 fi
371
372 # Calculate needed modules
373 modules=$(get_device_modules $node | sort | uniq)
374 if [ -z "$modules" ]; then
375 echo "cryptsetup: WARNING: failed to determine cipher modules to load for $node" >&2
376 continue
377 fi
378 echo dm_mod
379 echo dm_crypt
380 echo "$modules"
381
382 i=$(( $i + 1 ))
383 done
384
385 return 0
386}
387
388add_crypto_modules() {
389 local mod file altmod found genericfound
390 mod="$1"
391 found=""
392 genericfound=""
393
394 if [ -z "$mod" ]; then
395 return 1
396 fi
397
398 # We have several potential sources of modules (in order of preference):
399 #
400 # a) /lib/modules/$VERSION/kernel/arch/$ARCH/crypto/$mod-$specific.ko
401 # b) /lib/modules/$VERSION/kernel/crypto/$mod_generic.ko
402 # c) /lib/modules/$VERSION/kernel/crypto/$mod.ko
403 #
404 # and (currently ignored):
405 #
406 # d) /lib/modules/$VERSION/kernel/drivers/crypto/$specific-$mod.ko
407
408 for file in $(find "$MODULESDIR/kernel/arch/" -name "$mod-*.ko"); do
409 altmod="${file##*/}"
410 altmod="${altmod%.ko}"
411 manual_add_modules "$altmod"
412 found="yes"
413 done
414
415 for file in $(find "$MODULESDIR/kernel/crypto/" -name "${mod}_generic.ko"); do
416 altmod="${file##*/}"
417 altmod="${altmod%.ko}"
418 manual_add_modules "$altmod"
419 found="yes"
420 genericfound="yes"
421 done
422
423 if [ -z "$genericfound" ]; then
424 for file in $(find "$MODULESDIR/kernel/crypto/" -name "${mod}.ko"); do
425 altmod="${file##*/}"
426 altmod="${altmod%.ko}"
427 manual_add_modules "$altmod"
428 found="yes"
429 done
430 fi
431
432 if [ -z "$found" ]; then
433 return 1
434 fi
435
436 return 0
437}
438
439#
440# Begin real processing
441#
442
443setup="no"
444rootdev=""
445resumedevs=""
446
447# Find the root and resume device(s)
448if [ -r /etc/crypttab ]; then
449 rootdev=$(get_root_device)
450 if [ -z "$rootdev" ]; then
451 echo "cryptsetup: WARNING: could not determine root device from /etc/fstab" >&2
452 fi
453 resumedevs=$(get_resume_devices)
454fi
455
456# Load the config opts and modules for each device
457for dev in $rootdev $resumedevs; do
458 if ! modules=$(add_device "$dev"); then
459 echo "cryptsetup: FAILURE: could not determine configuration for $dev" >&2
460 continue
461 fi
462
463 setup="yes"
464 for mod in $modules; do
465 add_crypto_modules $mod
466 done
467done
468
469# With large initramfs, we always add a basic subset of modules
470if [ "$MODULES" != "dep" ]; then
471 for mod in aes sha256 cbc; do
472 add_crypto_modules $mod
473 done
474fi
475
476# See if we need to add the basic components
477if [ "$MODULES" != "dep" ] || [ "$setup" = "yes" ]; then
478 for mod in dm_mod dm_crypt; do
479 manual_add_modules $mod
480 done
481
482 copy_exec /sbin/cryptsetup
483 copy_exec /sbin/dmsetup
484# copy_exec /lib/cryptsetup/askpass
485fi
486
487exit 0
This page took 0.291555 seconds and 4 git commands to generate.