dmcrypt.initd 8.9 KB

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