]> git.pld-linux.org Git - projects/geninitrd.git/blob - mod-luks.sh
Support discard/allow-discard cryptsetup LUKS option. Replace deprecated luksOpen...
[projects/geninitrd.git] / mod-luks.sh
1 #!/bin/sh
2 # geninitrd mod: cryptsetup luks
3 USE_LUKS=${USE_LUKS:-yes}
4
5 # true if root device is crypted with cryptsetup luks
6 # and we should init cryptsetup luks at boot
7 have_luks=no
8
9 # device to use for name for cryptsetup luks
10 LUKSNAME=""
11
12 # setup geninitrd module
13 # @access       public
14 setup_mod_luks() {
15         cryptsetup=$(find_tool $initrd_dir/cryptsetup /sbin/cryptsetup-initrd)
16
17         if [ ! -x /sbin/cryptsetup ] || [ ! -x "$cryptsetup" ]; then
18                 USE_LUKS=no
19         fi
20 }
21
22 # return true if node is cryptsetup luks encrypted
23 # @param        string $node device node to be examined
24 # @access       public
25 is_luks() {
26         local node="$1"
27
28         # luks not wanted
29         if is_no "$USE_LUKS"; then
30                 return 1
31         fi
32
33         local dev dm_name=${node#/dev/mapper/}
34         if [ "$node" = "$dm_name" ]; then
35                 verbose "is_luks: $node is not device mapper name"
36                 return 1
37         fi
38
39         dev=$(awk -vdm_name="$dm_name" '$1 == dm_name { print $2 }' /etc/crypttab)
40         if [ "$dev" ]; then
41                 /sbin/cryptsetup isLuks $dev
42                 rc=$?
43         else
44                 rc=1
45         fi
46
47         if [ $rc = 0 ]; then
48                 verbose "is_luks: $node is cryptsetup luks"
49         else
50                 verbose "is_luks: $node is not cryptsetup luks"
51         fi
52         return $rc
53 }
54
55 # find modules for $devpath
56 # @param        $devpath        device to be examined
57 # @access       public
58 find_modules_luks() {
59         local devpath="$1"
60         local dev=""
61
62         LUKSNAME=${devpath#/dev/mapper/}
63
64         find_module "dm-crypt"
65
66         # TODO: autodetect
67         find_module "aes"
68         find_module "cbc"
69
70         # recurse
71         dev=$(awk -vLUKSNAME="$LUKSNAME" '$1 == LUKSNAME { print $2 }' /etc/crypttab)
72         if [ -n "$dev" ]; then
73                 find_modules_for_devpath $dev
74                 have_luks=yes
75         else
76                 die "Cannot find '$LUKSNAME' in /etc/crypttab"
77         fi
78 }
79
80
81 # generate initrd fragment for cryptsetup luks init
82 # @access       public
83 initrd_gen_luks() {
84         if ! is_yes "$have_luks"; then
85                 return
86         fi
87
88         inst_d /bin
89         inst_exec $cryptsetup /bin/cryptsetup
90
91         mount_dev
92         mount_sys
93         initrd_gen_devices
94         # TODO: 'udevadm settle' is called by lukssetup, is udev optional?
95
96         verbose "luks: process /etc/crypttab $LUKSNAME"
97         luks_crypttab $LUKSNAME
98 }
99
100
101 # PRIVATE METHODS
102 key_is_random() {
103         [ "$1" = "/dev/urandom" -o "$1" = "/dev/hw_random" -o "$1" = "/dev/random" ]
104 }
105
106 # produce cryptsetup from $name from /etc/crypttab
107 luks_crypttab() {
108         local LUKSNAME="$1"
109
110         # copy from /etc/rc.d/init.d/cryptsetup
111         local dst src key opt mode owner
112
113         while read dst src key opt; do
114                 [ "$dst" != "$LUKSNAME" ] && continue
115
116                 if [ -n "$key" -a "x$key" != "xnone" ]; then
117                         if test -e "$key" ; then
118                                 mode=$(LC_ALL=C ls -l "$key" | cut -c 5-10)
119                                 owner=$(LC_ALL=C ls -l $key | awk '{ print $3 }')
120                                 if [ "$mode" != "------" ] && ! key_is_random "$key"; then
121                                         die "INSECURE MODE FOR $key"
122                                 fi
123                                 if [ "$owner" != root ]; then
124                                         die "INSECURE OWNER FOR $key"
125                                 fi
126                         else
127                                 die "Key file for $dst not found"
128                         fi
129                 else
130                         key=""
131                 fi
132
133                 if /sbin/cryptsetup isLuks "$src" 2>/dev/null; then
134                         if key_is_random "$key"; then
135                                 die "$dst: LUKS requires non-random key, skipping"
136                         fi
137                         if [ "$key" ]; then
138                                 keyfile=/etc/.$dst.key
139                                 inst $key $keyfile
140                         fi
141
142                         crypttab_opt=""
143                         old_IFS="$IFS"
144                         IFS=","
145                         for option in $opt; do
146                                 case "$option" in
147                                         discard|allow-discards)
148                                                 crypttab_opt="$crypttab_opt --allow-discards"
149                                                 ;;
150                                         *)
151                                                 warn "$dst: option \'$opt\' is invalid for LUKS partitions, ignored"
152                                                 ;;
153                                 esac
154                         done
155                         IFS="$old_IFS"
156
157                         verbose "+ cryptsetup ${keyfile:+-d $keyfile} open --type luks $crypttab_opt '$src' '$dst'"
158                         add_linuxrc <<-EOF
159                         debugshell
160
161                         cryptsetup_opt=""
162                         if [ "\$DEBUGINITRD" ]; then
163                                 cryptsetup_opt="--debug"
164                         fi
165                         # cryptsetup can be called twice and in case on crypt on lvm only second
166                         # will succeed because there will be no src device in first cryptsetup call
167                         # this can be called multiple times, before lvm and after lvm.
168                         luksdev='$src'
169                         if [ \${luksdev##/dev/disk/by-uuid/} != \${luksdev} ]; then
170                                 src_uuid=\${luksdev##/dev/disk/by-uuid/}
171                                 while read x y z name; do
172                                         found_uuid=\$(cryptsetup \$cryptsetup_opt luksUUID /dev/\${name} 2>/dev/null)
173                                         if [ "\$found_uuid" = "\$src_uuid" ]; then
174                                                 luksdev=/dev/\$name
175                                                 break
176                                         fi
177                                 done < /proc/partitions
178                         fi
179
180                         if [ -e "\$luksdev" ]; then
181                                 crypt_status=\$(cryptsetup \$cryptsetup_opt status '$dst')
182                                 if [ "\${crypt_status%%is inactive.}" != "\$crypt_status" ]; then
183                                         # is inactive
184                                         cryptsetup \$cryptsetup_opt ${keyfile:+-d $keyfile} open --type luks $crypttab_opt "\$luksdev" '$dst' <&1
185                                 fi
186                         fi
187
188                         debugshell
189                         EOF
190                 else
191                         die "$dst: only LUKS encryption supported"
192                 fi
193         done < /etc/crypttab
194 }
This page took 0.6909 seconds and 4 git commands to generate.