]> git.pld-linux.org Git - packages/cryptsetup-luks.git/blob - cryptsetup-luks-initramfs-root-hook
- package python binding (as python-pycryptsetup)
[packages/cryptsetup-luks.git] / cryptsetup-luks-initramfs-root-hook
1 #!/bin/sh
2
3 PREREQ=""
4
5 prereqs()
6 {
7         echo "$PREREQ"
8 }
9
10 case $1 in
11 prereqs)
12         prereqs
13         exit 0
14         ;;
15 esac
16
17 . /usr/share/initramfs-tools/hook-functions
18
19 get_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
35 get_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
114 node_is_in_crypttab() {
115         local node
116         node="$1"
117
118         grep -q ^$node /etc/crypttab
119         return $?
120 }
121
122 get_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
154 get_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
256 get_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
282 canonical_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
309 add_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
388 add_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
443 setup="no"
444 rootdev=""
445 resumedevs=""
446
447 # Find the root and resume device(s)
448 if [ -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)
454 fi
455
456 # Load the config opts and modules for each device
457 for 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
467 done
468
469 # With large initramfs, we always add a basic subset of modules
470 if [ "$MODULES" != "dep" ]; then
471         for mod in aes sha256 cbc; do
472                 add_crypto_modules $mod
473         done
474 fi
475
476 # See if we need to add the basic components
477 if [ "$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
485 fi
486
487 exit 0
This page took 0.14862 seconds and 3 git commands to generate.