2.4.3-dmcrypt.rc 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. #!/sbin/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. after dev-settle
  8. if grep -qs ^swap= "${conf_file}" ; then
  9. before swap
  10. fi
  11. }
  12. # We support multiple dmcrypt instances based on $SVCNAME
  13. conf_file="/etc/conf.d/${SVCNAME}"
  14. # Get splash helpers if available.
  15. if [ -e /sbin/splash-functions.sh ] ; then
  16. . /sbin/splash-functions.sh
  17. fi
  18. # Setup mappings for an individual target/swap
  19. # Note: This relies on variables localized in the main body below.
  20. dm_crypt_execute() {
  21. local dev ret mode foo source_dev
  22. if [ -z "${target}" -a -z "${swap}" ] ; then
  23. return
  24. fi
  25. # Set up default values.
  26. : ${dmcrypt_key_timeout:=1}
  27. : ${dmcrypt_max_timeout:=300}
  28. : ${dmcrypt_retries:=5}
  29. : ${wait:=5}
  30. # Handle automatic look up of the source path.
  31. if [ -z "${source}" -a -n "${loop_file}" ] ; then
  32. source=$(losetup --show -f "${loop_file}")
  33. fi
  34. case ${source} in
  35. *=*)
  36. i=0
  37. while [ ${i} -lt ${wait} ]; do
  38. if source_dev="$(blkid -l -t "${source}" -o device)"; then
  39. source="${source_dev}"
  40. break
  41. fi
  42. : $((i += 1))
  43. einfo "waiting for source \"${source}\" for ${target}..."
  44. sleep 1
  45. done
  46. ;;
  47. esac
  48. if [ -z "${source}" ] || [ ! -e "${source}" ] ; then
  49. ewarn "source \"${source}\" for ${target} missing, skipping..."
  50. return
  51. fi
  52. if [ -n "${header}" ] ; then
  53. header_opt="--header=${header}"
  54. i=0
  55. while [ ! -e "${header}" ] && [ ${i} -lt ${wait} ] ; do
  56. : $((i += 1))
  57. einfo "Waiting for header ${header} to appear for ${target} ${i}/${dmcrypt_max_timeout} ..."
  58. sleep 1
  59. done
  60. if [ ${i} -gt ${wait} ] || [ ${i} -eq ${wait} ] ; then
  61. ewarn "Waited ${i} times for header file ${header}. Aborting ${target}."
  62. return
  63. fi
  64. else
  65. header_opt=""
  66. fi
  67. if [ -n "${target}" ] ; then
  68. # let user set options, otherwise leave empty
  69. : ${options:=' '}
  70. elif [ -n "${swap}" ] ; then
  71. if cryptsetup ${header_opt} isLuks ${source} 2>/dev/null ; then
  72. ewarn "The swap you have defined is a LUKS partition. Aborting crypt-swap setup."
  73. return
  74. fi
  75. target=${swap}
  76. # swap contents do not need to be preserved between boots, luks not required.
  77. # suspend2 users should have initramfs's init handling their swap partition either way.
  78. : ${options:='-c aes -h sha1 -d /dev/urandom'}
  79. : ${pre_mount:='mkswap ${dev}'}
  80. fi
  81. if [ -n "${loop_file}" ] ; then
  82. dev="/dev/mapper/${target}"
  83. ebegin " Setting up loop device ${source}"
  84. losetup ${source} ${loop_file}
  85. fi
  86. # cryptsetup:
  87. # open <device> <name> # <device> is $source
  88. # create <name> <device> # <name> is $target
  89. local arg1="create" arg2="${target}" arg3="${source}"
  90. if cryptsetup ${header_opt} isLuks ${source} 2>/dev/null ; then
  91. arg1="open"
  92. arg2="${source}"
  93. arg3="${target}"
  94. fi
  95. # Older versions reported:
  96. # ${target} is active:
  97. # Newer versions report:
  98. # ${target} is active[ and is in use.]
  99. if cryptsetup ${header_opt} status ${target} | grep -E -q ' is active' ; then
  100. einfo "dm-crypt mapping ${target} is already configured"
  101. return
  102. fi
  103. splash svc_input_begin ${SVCNAME} >/dev/null 2>&1
  104. # Handle keys
  105. if [ -n "${key}" ] ; then
  106. read_abort() {
  107. # some colors
  108. local ans savetty resettty
  109. [ -z "${NORMAL}" ] && eval $(eval_ecolors)
  110. einfon " $1? (${WARN}yes${NORMAL}/${GOOD}No${NORMAL}) "
  111. shift
  112. # This is ugly as s**t. But POSIX doesn't provide `read -t`, so
  113. # we end up having to implement our own crap with stty/etc...
  114. savetty=$(stty -g)
  115. resettty='stty ${savetty}; trap - EXIT HUP INT TERM'
  116. trap 'eval "${resettty}"' EXIT HUP INT TERM
  117. stty -icanon
  118. stty min 0 time "$(( $2 * 10 ))"
  119. ans=$(dd count=1 bs=1 2>/dev/null) || ans=''
  120. eval "${resettty}"
  121. if [ -z "${ans}" ] ; then
  122. printf '\r'
  123. else
  124. echo
  125. fi
  126. case ${ans} in
  127. [yY]) return 0;;
  128. *) return 1;;
  129. esac
  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: ${header_opt} ${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 ${header_opt} --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 app-crypt/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 ${header_opt} ${options} -d ${key} ${arg1} ${arg2} ${arg3}
  213. ret=$?
  214. eend ${ret} "failure running cryptsetup"
  215. else
  216. cryptsetup ${header_opt} ${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. if [ ${ret} -ne 0 ] ; then
  227. cryptfs_status=1
  228. else
  229. if [ -n "${pre_mount}" ] ; then
  230. dev="/dev/mapper/${target}"
  231. eval ebegin \"" pre_mount: ${pre_mount}"\"
  232. eval "${pre_mount}" > /dev/null
  233. ewend $? || cryptfs_status=1
  234. fi
  235. fi
  236. }
  237. # Lookup optional bootparams
  238. get_bootparam_val() {
  239. # We're given something like:
  240. # foo=bar=cow
  241. # Return the "bar=cow" part.
  242. case $1 in
  243. *=*)
  244. echo "${1#*=}"
  245. ;;
  246. esac
  247. }
  248. start() {
  249. local print_header=true cryptfs_status=0
  250. local gpg_options key loop_file target targetline options pre_mount post_mount source swap remdev
  251. local x
  252. for x in $(cat /proc/cmdline) ; do
  253. case "${x}" in
  254. key_timeout=*)
  255. dmcrypt_key_timeout=$(get_bootparam_val "${x}")
  256. ;;
  257. esac
  258. done
  259. while read targetline <&3 ; do
  260. case ${targetline} in
  261. # skip comments and blank lines
  262. ""|"#"*) continue ;;
  263. # skip service-specific openrc configs #377927
  264. rc_*) continue ;;
  265. esac
  266. ${print_header} && ebegin "Setting up dm-crypt mappings"
  267. print_header=false
  268. # check for the start of a new target/swap
  269. case ${targetline} in
  270. target=*|swap=*)
  271. # If we have a target queued up, then execute it
  272. dm_crypt_execute
  273. # Prepare for the next target/swap by resetting variables
  274. unset gpg_options key loop_file target options pre_mount post_mount source swap remdev wait header header_opt
  275. ;;
  276. gpg_options=*|remdev=*|key=*|loop_file=*|options=*|pre_mount=*|post_mount=*|wait=*|source=*|header=*)
  277. if [ -z "${target}${swap}" ] ; then
  278. ewarn "Ignoring setting outside target/swap section: ${targetline}"
  279. continue
  280. fi
  281. ;;
  282. dmcrypt_*=*)
  283. # ignore global options
  284. continue
  285. ;;
  286. *)
  287. ewarn "Skipping invalid line in ${conf_file}: ${targetline}"
  288. ;;
  289. esac
  290. # Queue this setting for the next call to dm_crypt_execute
  291. eval "${targetline}"
  292. done 3< ${conf_file}
  293. # If we have a target queued up, then execute it
  294. dm_crypt_execute
  295. ewend ${cryptfs_status} "Failed to setup dm-crypt devices"
  296. }
  297. stop() {
  298. local line print_header
  299. # Break down all mappings
  300. print_header=true
  301. grep -E "^(target|swap)=" ${conf_file} | \
  302. while read line ; do
  303. ${print_header} && einfo "Removing dm-crypt mappings"
  304. print_header=false
  305. target= swap=
  306. eval ${line}
  307. [ -n "${swap}" ] && target=${swap}
  308. if [ -z "${target}" ] ; then
  309. ewarn "invalid line in ${conf_file}: ${line}"
  310. continue
  311. fi
  312. ebegin " ${target}"
  313. cryptsetup ${header_opt} remove ${target}
  314. eend $?
  315. done
  316. # Break down loop devices
  317. print_header=true
  318. grep '^source=./dev/loop' ${conf_file} | \
  319. while read line ; do
  320. ${print_header} && einfo "Detaching dm-crypt loop devices"
  321. print_header=false
  322. source=
  323. eval ${line}
  324. ebegin " ${source}"
  325. losetup -d "${source}"
  326. eend $?
  327. done
  328. return 0
  329. }