projects/aports·blob master · refs

358 lines · 9.2 KiB

1#!/sbin/openrc-run
2# Copyright 1999-2015 Gentoo Foundation
3# Distributed under the terms of the GNU General Public License v2
4
5depend() {
6 before checkfs fsck
7
8 if grep -qs ^swap= "${conf_file}" ; then
9 before swap
10 fi
11}
12
13# We support multiple dmcrypt instances based on $SVCNAME
14conf_file="/etc/conf.d/${SVCNAME}"
15
16# Get splash helpers if available.
17if [ -e /sbin/splash-functions.sh ] ; then
18 . /sbin/splash-functions.sh
19fi
20
21# Setup mappings for an individual target/swap
22# Note: This relies on variables localized in the main body below.
23dm_crypt_execute() {
24 local dev ret mode foo
25
26 if [ -z "${target}" -a -z "${swap}" ] ; then
27 return
28 fi
29
30 # Set up default values.
31 : ${dmcrypt_key_timeout:=1}
32 : ${dmcrypt_max_timeout:=300}
33 : ${dmcrypt_retries:=5}
34
35 # Handle automatic look up of the source path.
36 if [ -z "${source}" -a -n "${loop_file}" ] ; then
37 source=$(losetup --show -f "${loop_file}")
38 fi
39 case ${source} in
40 *=*)
41 source="$(findfs ${source})"
42 ;;
43 esac
44 if [ -z "${source}" ] || [ ! -e "${source}" ] ; then
45 ewarn "source \"${source}\" for ${target} missing, skipping..."
46 return
47 fi
48
49 if [ -n "${target}" ] ; then
50 # let user set options, otherwise leave empty
51 : ${options:=' '}
52 elif [ -n "${swap}" ] ; then
53 if cryptsetup isLuks ${source} 2>/dev/null ; then
54 ewarn "The swap you have defined is a LUKS partition. Aborting crypt-swap setup."
55 return
56 fi
57 target=${swap}
58 # swap contents do not need to be preserved between boots, luks not required.
59 # suspend2 users should have initramfs's init handling their swap partition either way.
60 : ${options:='-s 256 -c aes -d /dev/urandom'}
61 : ${pre_mount:='mkswap ${dev}'}
62 fi
63
64 if [ -n "${loop_file}" ] ; then
65 dev="/dev/mapper/${target}"
66 ebegin " Setting up loop device ${source}"
67 losetup ${source} ${loop_file}
68 fi
69
70 # cryptsetup:
71 # open <device> <name> # <device> is $source
72 # create <name> <device> # <name> is $target
73 local arg1="create" arg2="${target}" arg3="${source}"
74 if cryptsetup isLuks ${source} 2>/dev/null ; then
75 arg1="open"
76 arg2="${source}"
77 arg3="${target}"
78 fi
79 # This hack works around the lack of isLuks equivalents for alternative types
80 # Required feature request: https://gitlab.com/cryptsetup/cryptsetup/-/issues/824
81 # tcrypt can't work this way since tcryptDump requires a password
82 if cryptsetup bitlkDump ${source} >/dev/null 2>&1 ; then
83 arg1="open --type bitlk"
84 arg2="${source}"
85 arg3="${target}"
86 fi
87 if cryptsetup fvault2Dump ${source} >/dev/null 2>&1 ; then
88 arg1="open --type fvault2"
89 arg2="${source}"
90 arg3="${target}"
91 fi
92
93 # Older versions reported:
94 # ${target} is active:
95 # Newer versions report:
96 # ${target} is active[ and is in use.]
97 if cryptsetup status ${target} | grep -qE ' is active' ; then
98 einfo "dm-crypt mapping ${target} is already configured"
99 return
100 fi
101 splash svc_input_begin ${SVCNAME} >/dev/null 2>&1
102
103 # Handle keys
104 if [ -n "${key}" ] ; then
105 read_abort() {
106 # some colors
107 local ans savetty resettty
108 [ -z "${NORMAL}" ] && eval $(eval_ecolors)
109 einfon " $1? (${WARN}yes${NORMAL}/${GOOD}No${NORMAL}) "
110 shift
111 # This is ugly as s**t. But POSIX doesn't provide `read -t`, so
112 # we end up having to implement our own crap with stty/etc...
113 savetty=$(stty -g)
114 resettty='stty ${savetty}; trap - EXIT HUP INT TERM'
115 trap 'eval "${resettty}"' EXIT HUP INT TERM
116 stty -icanon
117 stty min 0 time "$(( $2 * 10 ))"
118 ans=$(dd count=1 bs=1 2>/dev/null) || ans=''
119 eval "${resettty}"
120 if [ -z "${ans}" ] ; then
121 printf '\r'
122 else
123 echo
124 fi
125 case ${ans} in
126 [yY]) return 0;;
127 *) return 1;;
128 esac
129 }
130
131 # Notes: sed not used to avoid case where /usr partition is encrypted.
132 mode=${key##*:} && ( [ "${mode}" = "${key}" ] || [ -z "${mode}" ] ) && mode=reg
133 key=${key%:*}
134 case "${mode}" in
135 gpg|reg)
136 # handle key on removable device
137 if [ -n "${remdev}" ] ; then
138 # temp directory to mount removable device
139 local mntrem="${RC_SVCDIR}/dm-crypt-remdev.$$"
140 if [ ! -d "${mntrem}" ] ; then
141 if ! mkdir -p "${mntrem}" ; then
142 ewarn "${source} will not be decrypted ..."
143 einfo "Reason: Unable to create temporary mount point '${mntrem}'"
144 return
145 fi
146 fi
147 i=0
148 einfo "Please insert removable device for ${target}"
149 while [ ${i} -lt ${dmcrypt_max_timeout} ] ; do
150 foo=""
151 if mount -n -o ro "${remdev}" "${mntrem}" 2>/dev/null >/dev/null ; then
152 # keyfile exists?
153 if [ ! -e "${mntrem}${key}" ] ; then
154 umount -n "${mntrem}"
155 rmdir "${mntrem}"
156 einfo "Cannot find ${key} on removable media."
157 read_abort "Abort" ${dmcrypt_key_timeout} && return
158 else
159 key="${mntrem}${key}"
160 break
161 fi
162 else
163 [ -e "${remdev}" ] \
164 && foo="mount failed" \
165 || foo="mount source not found"
166 fi
167 : $((i += 1))
168 read_abort "Stop waiting after $i attempts (${foo})" -t 1 && return
169 done
170 else # keyfile ! on removable device
171 if [ ! -e "${key}" ] ; then
172 ewarn "${source} will not be decrypted ..."
173 einfo "Reason: keyfile ${key} does not exist."
174 return
175 fi
176 fi
177 ;;
178 *)
179 ewarn "${source} will not be decrypted ..."
180 einfo "Reason: mode ${mode} is invalid."
181 return
182 ;;
183 esac
184 else
185 mode=none
186 fi
187 ebegin " ${target} using: ${options} ${arg1} ${arg2} ${arg3}"
188 if [ "${mode}" = "gpg" ] ; then
189 : ${gpg_options:='-q -d'}
190 # gpg available ?
191 if command -v gpg >/dev/null ; then
192 i=0
193 while [ ${i} -lt ${dmcrypt_retries} ] ; do
194 # paranoid, don't store key in a variable, pipe it so it stays very little in ram unprotected.
195 # save stdin stdout stderr "values"
196 timeout ${dmcrypt_max_timeout} gpg ${gpg_options} ${key} 2>/dev/null | \
197 cryptsetup --key-file - ${options} ${arg1} ${arg2} ${arg3}
198 ret=$?
199 # The timeout command exits 124 when it times out.
200 [ ${ret} -eq 0 -o ${ret} -eq 124 ] && break
201 : $(( i += 1 ))
202 done
203 eend ${ret} "failure running cryptsetup"
204 else
205 ewarn "${source} will not be decrypted ..."
206 einfo "Reason: cannot find gpg application."
207 einfo "You have to install gnupg first."
208 einfo "If you have /usr on its own partition, try copying gpg to /bin ."
209 fi
210 else
211 if [ "${mode}" = "reg" ] ; then
212 cryptsetup ${options} -d ${key} ${arg1} ${arg2} ${arg3}
213 ret=$?
214 eend ${ret} "failure running cryptsetup"
215 else
216 cryptsetup ${options} ${arg1} ${arg2} ${arg3}
217 ret=$?
218 eend ${ret} "failure running cryptsetup"
219 fi
220 fi
221 if [ -d "${mntrem}" ] ; then
222 umount -n ${mntrem} 2>/dev/null >/dev/null
223 rmdir ${mntrem} 2>/dev/null >/dev/null
224 fi
225 splash svc_input_end ${SVCNAME} >/dev/null 2>&1
226
227 if [ ${ret} -ne 0 ] ; then
228 cryptfs_status=1
229 else
230 if [ -n "${pre_mount}" ] ; then
231 dev="/dev/mapper/${target}"
232 eval ebegin \"" pre_mount: ${pre_mount}"\"
233 eval "${pre_mount}" > /dev/null
234 ewend $? || cryptfs_status=1
235 fi
236 if [ -n "${post_mount}" ] ; then
237 dev="/dev/mapper/${target}"
238 eval ebegin \"" post_mount: ${post_mount}"\"
239 eval "${post_mount}" > /dev/null
240 ewend $? || cryptfs_status=1
241 fi
242 fi
243}
244
245# Lookup optional bootparams
246get_bootparam_val() {
247 # We're given something like:
248 # foo=bar=cow
249 # Return the "bar=cow" part.
250 case $1 in
251 *=*)
252 echo "${1#*=}"
253 ;;
254 esac
255}
256
257start() {
258 local header=true cryptfs_status=0
259 local gpg_options key loop_file target targetline options pre_mount post_mount source swap remdev
260
261 local x
262 for x in $(cat /proc/cmdline) ; do
263 case "${x}" in
264 key_timeout=*)
265 dmcrypt_key_timeout=$(get_bootparam_val "${x}")
266 ;;
267 esac
268 done
269
270 while read targetline <&3 ; do
271 case ${targetline} in
272 # skip comments and blank lines
273 ""|"#"*) continue ;;
274 # skip service-specific openrc configs #377927
275 rc_*) continue ;;
276 esac
277
278 ${header} && ebegin "Setting up dm-crypt mappings"
279 header=false
280
281 # check for the start of a new target/swap
282 case ${targetline} in
283 target=*|swap=*)
284 # If we have a target queued up, then execute it
285 dm_crypt_execute
286
287 # Prepare for the next target/swap by resetting variables
288 unset gpg_options key loop_file target options pre_mount post_mount source swap remdev
289 ;;
290
291 gpg_options=*|remdev=*|key=*|loop_file=*|options=*|pre_mount=*|post_mount=*|source=*)
292 if [ -z "${target}${swap}" ] ; then
293 ewarn "Ignoring setting outside target/swap section: ${targetline}"
294 continue
295 fi
296 ;;
297
298 dmcrypt_*=*)
299 # ignore global options
300 continue
301 ;;
302
303 *)
304 ewarn "Skipping invalid line in ${conf_file}: ${targetline}"
305 ;;
306 esac
307
308 # Queue this setting for the next call to dm_crypt_execute
309 eval "${targetline}"
310 done 3< ${conf_file}
311
312 # If we have a target queued up, then execute it
313 dm_crypt_execute
314
315 ewend ${cryptfs_status} "Failed to setup dm-crypt devices"
316}
317
318stop() {
319 local line header
320
321 # Break down all mappings
322 header=true
323 grep -E "^(target|swap)=" ${conf_file} | \
324 while read line ; do
325 ${header} && einfo "Removing dm-crypt mappings"
326 header=false
327
328 target= swap=
329 eval ${line}
330
331 [ -n "${swap}" ] && target=${swap}
332 if [ -z "${target}" ] ; then
333 ewarn "invalid line in ${conf_file}: ${line}"
334 continue
335 fi
336
337 ebegin " ${target}"
338 cryptsetup remove ${target}
339 eend $?
340 done
341
342 # Break down loop devices
343 header=true
344 grep '^source=./dev/loop' ${conf_file} | \
345 while read line ; do
346 ${header} && einfo "Detaching dm-crypt loop devices"
347 header=false
348
349 source=
350 eval ${line}
351
352 ebegin " ${source}"
353 losetup -d "${source}"
354 eend $?
355 done
356
357 return 0
358}