blob: ce5e6f4534336cc9c9e71c6c8614462e8080df73 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
|
#
# This file is for inclusion with
# . /lib/cryptsetup/cryptdisks-functions
# and should not be executed directly.
PATH="/usr/sbin:/usr/bin:/sbin:/bin"
CRYPTDISKS_ENABLE="Yes"
#set -x
# Sanity check #1
[ -x /sbin/cryptsetup ] || exit 0
. /lib/lsb/init-functions
. /lib/cryptsetup/functions
if [ -r /etc/default/cryptdisks ]; then
. /etc/default/cryptdisks
fi
MOUNT="$CRYPTDISKS_MOUNT"
# do_start()
# Unlock all devices in the crypttab(5)
do_start() {
[ -s "$TABFILE" ] || return 0
# Create locking directory before invoking cryptsetup(8) to avoid warnings
mkdir -pm0700 /run/cryptsetup
modprobe -qb dm-mod || true
modprobe -qb dm-crypt || true
dmsetup mknodes >/dev/null 2>&1 || true
if [ "$INITSTATE" != "init" ]; then
log_action_begin_msg "Starting $INITSTATE crypto disks"
fi
mount_fs
crypttab_foreach_entry _do_start_callback
umount_fs
log_action_end_msg 0
}
_do_start_callback() {
setup_mapping || log_action_end_msg $?
}
# mount_fs()
# Premounts file systems
mount_fs() {
local point
MOUNTED=""
for point in $MOUNT; do
if mount "$point" >/dev/null; then
MOUNTED="$MOUNTED $point"
fi
done
}
# Postunmounts file systems
umount_fs() {
local point
for point in $MOUNTED; do
umount "$point" >/dev/null
done
}
# setup_mapping()
# Set up a crypttab(5) mapping defined by $CRYPTTAB_NAME,
# $CRYPTTAB_SOURCE, $CRYPTTAB_KEY, $CRYPTTAB_OPTIONS.
setup_mapping() {
if dm_blkdevname "$CRYPTTAB_NAME" >/dev/null; then
device_msg "running"
return 0
fi
local loud="${DEFAULT_LOUD:-}"
crypttab_parse_options --export --missing-path=fail || return 1
if [ -n "${CRYPTTAB_OPTION_quiet+x}" ]; then
loud="no"
elif [ -n "${CRYPTTAB_OPTION_loud+x}" ]; then
loud="yes"
fi
if [ -z "${FORCE_START-}" ]; then
if [ "$INITSTATE" = "early" -a -n "${CRYPTTAB_OPTION_noearly+x}" ] ||
[ "$INITSTATE" != "manual" -a -n "${CRYPTTAB_OPTION_noauto+x}" ]; then
device_msg "ignored"
return 0
fi
fi
if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ] && [ "$CRYPTTAB_KEY" != "none" ]; then
if ! crypttab_key_check; then
device_msg "invalid key"
return 1
fi
CRYPTTAB_OPTION_tries=1
fi
if ! crypttab_resolve_source; then
if [ "$loud" = "yes" ]; then
device_msg "skipped, device $CRYPTTAB_SOURCE does not exist"
fi
return 1
fi
device_msg "starting"
local offset_bytes=""
if [ -n "${CRYPTTAB_OPTION_offset+x}" ] && [ ${#CRYPTTAB_OPTION_offset} -le 7 ] && [ $CRYPTTAB_OPTION_offset -lt 4194304 ]; then
# silently ignore large offset values which might cause the multiplication to overflow...
offset_bytes=$((CRYPTTAB_OPTION_offset * 512))
fi
local out tmpdev
if [ "$CRYPTTAB_TYPE" != "luks" ] && [ "$CRYPTTAB_TYPE" != "bitlk" ]; then
# fail if the device has a filesystem and the disk encryption format doesn't
# verify the key digest (unlike LUKS); unless it's swap, otherwise people can't
# easily convert an existing plainttext swap partition to an encrypted one
if ! out="$(/lib/cryptsetup/checks/un_blkid "$CRYPTTAB_SOURCE" "" ${CRYPTTAB_OPTION_offset+"$offset_bytes"} 2>/dev/null)" &&
! /lib/cryptsetup/checks/blkid "$CRYPTTAB_SOURCE" swap ${CRYPTTAB_OPTION_offset+"$offset_bytes"} >/dev/null; then
log_warning_msg "$CRYPTTAB_NAME: the precheck for '$CRYPTTAB_SOURCE' failed: $out"
return 1
fi
fi
local count=0 maxtries="${CRYPTTAB_OPTION_tries:-3}" fstype rv
local target="$CRYPTTAB_NAME"
CRYPTTAB_NAME="${CRYPTTAB_NAME}_unformatted" # XXX potential conflict
while [ $maxtries -le 0 ] || [ $count -lt $maxtries ]; do
if [ -z "${CRYPTTAB_OPTION_keyscript+x}" ] && [ "$CRYPTTAB_KEY" != "none" ]; then
# unlock via keyfile
unlock_mapping "$CRYPTTAB_KEY"
else
# unlock interactively or via keyscript
CRYPTTAB_NAME="$target" run_keyscript "$count" | unlock_mapping
fi
rv=$?
count=$(( $count + 1 ))
if [ $rv -ne 0 ] || ! tmpdev="$(dm_blkdevname "$CRYPTTAB_NAME")"; then
continue
fi
if [ -n "${CRYPTTAB_OPTION_check+x}" ] && \
! "$CRYPTTAB_OPTION_check" "$tmpdev" ${CRYPTTAB_OPTION_checkargs+"$CRYPTTAB_OPTION_checkargs"}; then
log_warning_msg "$target: the check for '$CRYPTTAB_NAME' failed"
cryptsetup remove -- "$CRYPTTAB_NAME"
continue
fi
if [ "${CRYPTTAB_OPTION_swap+x}" ]; then
if out="$(/lib/cryptsetup/checks/un_blkid "$tmpdev" "" ${CRYPTTAB_OPTION_offset+"$offset_bytes"} 2>/dev/null)" ||
/lib/cryptsetup/checks/blkid "$tmpdev" swap ${CRYPTTAB_OPTION_offset+"$offset_bytes"} >/dev/null 2>&1; then
mkswap "$tmpdev" >/dev/null 2>&1
else
log_warning_msg "$target: the check for '$CRYPTTAB_NAME' failed. $CRYPTTAB_NAME contains data: $out"
cryptsetup remove -- "$CRYPTTAB_NAME"
return 1
fi
elif [ "${CRYPTTAB_OPTION_tmp+x}" ]; then
local tmpdir="$(mktemp --tmpdir="/run/cryptsetup" --directory)" rv=0
if ! mkfs -t "$CRYPTTAB_OPTION_tmp" -q "$tmpdev" >/dev/null 2>&1 ||
! mount -t "$CRYPTTAB_OPTION_tmp" "$tmpdev" "$tmpdir" ||
! chmod 1777 "$tmpdir"; then
rv=1
fi
umount "$tmpdir" || true
rmdir "$tmpdir" || true
[ $rv -eq 0 ] || return $rv
fi
if command -v udevadm >/dev/null 2>&1; then
udevadm settle
fi
dmsetup rename -- "$CRYPTTAB_NAME" "$target"
device_msg "$target" "started"
return 0
done
device_msg "$target" "failed"
return 1
}
# Removes all mappings in crypttab, except the ones holding the root
# file system or /usr
do_stop() {
local devno_rootfs devno_usr
dmsetup mknodes
log_action_begin_msg "Stopping $INITSTATE crypto disks"
devno_rootfs="$(get_mnt_devno /)" || devno_rootfs=""
devno_usr="$(get_mnt_devno /usr)" || devno_usr=""
crypttab_foreach_entry _do_stop_callback
log_action_end_msg 0
}
_do_stop_callback() {
local skip="n" devno rv=0
# traverse the device tree for each crypttab(5) entry and mark / and
# /usr holders as skipped. that's suboptimal but we can't use
# mapped device names as they might contain any character other than
# NUL. shouldn't be much overhead anyway as the device tree is
# likely not that long
foreach_cryptdev _do_stop_skipped $devno_rootfs $devno_usr
[ "$skip" = "n" ] || return $rv
if devno="$(dmsetup info -c --noheadings -o devno -- "$CRYPTTAB_NAME" 2>/dev/null)" && [ -n "$devno" ]; then
foreach_cryptdev --reverse _do_stop_remove "$devno" || rv=$? # try to remove slave devices first
fi
return $rv
}
_do_stop_skipped() {
if [ "$1" = "$CRYPTTAB_NAME" ]; then
skip="y"
fi
}
_do_stop_remove() {
local name="$1" i rv=0
for i in 1 2 4 8 16 32; do
remove_mapping "$name" 3<&- && break || rv=$?
if [ $rv -eq 1 ] || [ $rv -eq 2 -a $i -gt 16 ]; then
log_action_end_msg $rv
break
fi
log_action_cont_msg "$name busy..."
sleep $i
done
}
# device_msg([$name], $message)
# Convenience function to handle $VERBOSE
device_msg() {
local name message
if [ $# -eq 1 ]; then
name="$CRYPTTAB_NAME"
message="$1"
else
name="$1"
message="$2"
fi
if [ "$VERBOSE" != "no" ]; then
log_action_cont_msg "$name ($message)"
fi
}
# remove_mapping($target)
# Remove mapping $target
remove_mapping() {
local CRYPTTAB_NAME="$1"
if ! dm_blkdevname "$CRYPTTAB_NAME" >/dev/null; then
device_msg "stopped"
return 0
fi
if [ "$(dmsetup info --noheadings -c -o subsystem -- "$CRYPTTAB_NAME")" != "CRYPT" ]; then
device_msg "error"
return 1
fi
local opencount="$(dmsetup info -c --noheadings -o open -- "$CRYPTTAB_NAME" 2>/dev/null || true)"
if [ -z "$opencount" ]; then
device_msg "error"
return 1
elif [ "$opencount" != "0" ]; then
device_msg "busy"
if [ "$INITSTATE" = "early" ] || [ "$INITSTATE" = "manual" ]; then
return 1
elif [ "$INITSTATE" = "remaining" ]; then
return 2
fi
return 0
fi
if cryptsetup remove -- "$CRYPTTAB_NAME"; then
device_msg "stopping"
return 0
else
device_msg "error"
return 1
fi
}
# vim: set filetype=sh :
|