123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- if [ "${0#/usr/share/initramfs-tools/hooks/}" != "$0" ] ||
- [ "${0#/etc/initramfs-tools/hooks/}" != "$0" ]; then
- # called from an initramfs-tools hook script
- TABFILE="$DESTDIR/cryptroot/crypttab"
- elif [ "${0#/scripts/}" != "$0" ]; then
- # called at initramfs stage from a boot script
- TABFILE="/cryptroot/crypttab"
- else
- TABFILE="${TABFILE-/etc/crypttab}"
- fi
- export DM_DEFAULT_NAME_MANGLING_MODE=hex # for dmsetup(8)
- # Logging helpers. Send the argument list to plymouth(1), or fold it
- # and print it to the standard error.
- cryptsetup_message() {
- local IFS=' '
- if [ "${0#/scripts/}" != "$0" ] && [ -x /bin/plymouth ] && plymouth --ping; then
- plymouth message --text="cryptsetup: $*"
- elif [ ${#*} -lt 70 ]; then
- echo "cryptsetup: $*" >&2
- else
- # use busybox's fold(1) and sed(1) at initramfs stage
- echo "cryptsetup: $*" | fold -s | sed '1! s/^/ /' >&2
- fi
- return 0
- }
- # crypttab_parse_options([--export], [--quiet], [--missing-path={ignore|warn|fail}])
- # Parse $_CRYPTTAB_OPTIONS, a comma-separated option string from the
- # crypttab(5) 4th column, and sets corresponding variables
- # CRYPTTAB_OPTION_<option>=<value> (which are added to the environment
- # if --export is set). If --path-exists isn't set to "ignore" (the
- # default), then options taking a file name, such as header=<path>,
- # need to point to an existing path, otherwise a warning is printed;
- # and an error is raised if the value is set to "fail".
- # For error and warning messages, CRYPTTAB_NAME, (resp. CRYPTTAB_KEY)
- # should be set to the (unmangled) mapped device name (resp. key
- # file).
- # Return 1 on parsing error, 0 otherwise (incl. if unknown options
- # were encountered).
- crypttab_parse_options() {
- local quiet="n" export="n" missing_path="ignore"
- while [ $# -gt 0 ]; do
- case "$1" in
- --quiet) quiet="y";;
- --export) export="y";;
- --missing-path=*) missing_path="${1#--missing-path=}";;
- *) cryptsetup_message "WARNING: crypttab_parse_options(): unknown option $1"
- esac
- shift
- done
- local IFS=',' x OPTION VALUE
- unset -v CRYPTTAB_OPTION_cipher \
- CRYPTTAB_OPTION_size \
- CRYPTTAB_OPTION_sector_size \
- CRYPTTAB_OPTION_hash \
- CRYPTTAB_OPTION_offset \
- CRYPTTAB_OPTION_skip \
- CRYPTTAB_OPTION_verify \
- CRYPTTAB_OPTION_readonly \
- CRYPTTAB_OPTION_discard \
- CRYPTTAB_OPTION_plain \
- CRYPTTAB_OPTION_luks \
- CRYPTTAB_OPTION_tcrypt \
- CRYPTTAB_OPTION_veracrypt \
- CRYPTTAB_OPTION_swap \
- CRYPTTAB_OPTION_tmp \
- CRYPTTAB_OPTION_check \
- CRYPTTAB_OPTION_checkargs \
- CRYPTTAB_OPTION_tries \
- CRYPTTAB_OPTION_initramfs \
- CRYPTTAB_OPTION_noearly \
- CRYPTTAB_OPTION_noauto \
- CRYPTTAB_OPTION_loud \
- CRYPTTAB_OPTION_quiet \
- CRYPTTAB_OPTION_keyscript \
- CRYPTTAB_OPTION_keyslot \
- CRYPTTAB_OPTION_header \
- CRYPTTAB_OPTION_tcrypthidden
- # use $_CRYPTTAB_OPTIONS not $CRYPTTAB_OPTIONS as options values may
- # contain '\054' which is decoded to ',' in the latter
- for x in $_CRYPTTAB_OPTIONS; do
- OPTION="${x%%=*}"
- VALUE="${x#*=}"
- if [ "$x" = "$OPTION" ]; then
- unset -v VALUE
- else
- VALUE="$(printf '%b' "$VALUE")"
- fi
- if ! crypttab_validate_option; then
- if [ "$quiet" = "n" ]; then
- cryptsetup_message "ERROR: $CRYPTTAB_NAME: invalid value for '${x%%=*}' option, skipping"
- fi
- return 1
- elif [ -z "${OPTION+x}" ]; then
- continue
- fi
- if [ "$export" = "y" ]; then
- export "CRYPTTAB_OPTION_$OPTION"="${VALUE-yes}"
- else
- eval "CRYPTTAB_OPTION_$OPTION"='${VALUE-yes}'
- fi
- done
- IFS=" "
- if [ "$quiet" = "n" ] &&
- [ -z "${CRYPTTAB_OPTION_luks+x}" ] && [ -n "${CRYPTTAB_OPTION_header+x}" ]; then
- cryptsetup_message "WARNING: Option 'luks' missing in crypttab for target $CRYPTTAB_NAME." \
- "Headers are only supported for LUKS devices."
- fi
- if [ -z "${CRYPTTAB_OPTION_luks+x}" ] && [ -z "${CRYPTTAB_OPTION_tcrypt+x}" ]; then
- # the compiled-in default for these are subject to change
- options='cipher size'
- if [ -n "${CRYPTTAB_OPTION_keyscript+x}" ] || [ "$CRYPTTAB_KEY" = "none" ]; then
- options="$options hash" # --hash is being ignored in plain mode with keyfile specified
- fi
- for o in $options; do
- if [ "$quiet" = "n" ] && eval [ -z "\${CRYPTTAB_OPTION_$o+x}" ]; then
- cryptsetup_message "WARNING: Option '$o' missing in crypttab for plain dm-crypt" \
- "mapping $CRYPTTAB_NAME. Please read /usr/share/doc/cryptsetup-initramfs/README.initramfs.gz and" \
- "add the correct '$o' option to your crypttab(5)."
- fi
- done
- fi
- }
- # crypttab_validate_option()
- # Validate $OPTION=$VALUE (or flag $OPTION if VALUE is unset). return
- # 1 on error, unsets OPTION for unknown or useless options.
- crypttab_validate_option() {
- # option aliases
- case "$OPTION" in
- read-only) OPTION="readonly";;
- key-slot) OPTION="keyslot";;
- tcrypt-hidden) OPTION="tcrypthidden";;
- tcrypt-veracrypt) OPTION="veracrypt";;
- esac
- # sanitize the option name so CRYPTTAB_OPTION_$OPTION is a valid variable name
- local o="$OPTION"
- case "$o" in
- keyfile-offset) OPTION="keyfile_offset";;
- keyfile-size) OPTION="keyfile_size";;
- sector-size) OPTION="sector_size";;
- esac
- case "$o" in
- # value must be a non-empty string
- cipher|hash)
- [ -n "${VALUE:+x}" ] || return 1
- ;;
- # value must be a non-empty string, and an existing path if --missing-path is set
- header)
- [ -n "${VALUE:+x}" ] || return 1
- if [ "$missing_path" != "ignore" ]; then
- if [ ! -e "$VALUE" ]; then
- cryptsetup_message "WARNING: $CRYPTTAB_NAME: $VALUE does not exist";
- [ "$missing_path" = "warn" ] || return 1
- fi
- fi
- ;;
- # numeric options >0
- size|keyfile-size|sector-size)
- if ! printf '%s' "${VALUE-}" | grep -Exq "0*[1-9][0-9]*"; then
- return 1
- fi
- ;;
- # numeric options >=0
- offset|skip|tries|keyslot|keyfile-offset)
- if ! printf '%s' "${VALUE-}" | grep -Exq "[0-9]+"; then
- return 1
- fi
- ;;
- tmp)
- if [ -z "${VALUE+x}" ]; then
- VALUE="ext4" # 'tmp flag'
- elif [ -z "$VALUE" ]; then
- return 1
- fi
- ;;
- check)
- if [ -z "${VALUE+x}" ]; then
- if [ -n "${CRYPTDISKS_CHECK-}" ]; then
- VALUE="$CRYPTDISKS_CHECK"
- else
- unset -v OPTION
- return 0
- fi
- fi
- if [ -x "/lib/cryptsetup/checks/$VALUE" ] && [ -f "/lib/cryptsetup/checks/$VALUE" ]; then
- VALUE="/lib/cryptsetup/checks/$VALUE"
- elif [ ! -x "$VALUE" ] || [ ! -f "$VALUE" ]; then
- return 1
- fi
- ;;
- checkargs)
- [ -n "${VALUE+x}" ] || return 1 # must have a value (possibly empty)
- ;;
- keyscript)
- [ -n "${VALUE:+x}" ] || return 1 # must have a value
- if [ "${VALUE#/}" = "$VALUE" ]; then
- VALUE="/lib/cryptsetup/scripts/$VALUE"
- fi
- if [ ! -x "$VALUE" ] || [ ! -f "$VALUE" ]; then
- return 1
- fi
- ;;
- # and now the flags
- verify) ;;
- loud) ;;
- quiet) ;;
- initramfs) ;;
- noearly) ;;
- noauto) ;;
- readonly) ;;
- discard) ;;
- plain) ;;
- luks) ;;
- swap) ;;
- tcrypt) ;;
- veracrypt) ;;
- tcrypthidden) ;;
- *)
- if [ "${quiet:-n}" = "n" ]; then
- cryptsetup_message "WARNING: $CRYPTTAB_NAME: ignoring unknown option '$o'";
- fi
- unset -v OPTION
- ;;
- esac
- }
- # crypttab_resolve_source()
- # Resolve the CRYPTTAB_SOURCE variable, containing value of the second
- # field of a crypttab(5)-like file.
- # On error (non-existing source), CRYPTTAB_SOURCE is not changed and 1
- # is returned.
- crypttab_resolve_source() {
- # return immediately if source is a regular file
- [ ! -f "$CRYPTTAB_SOURCE" ] || return 0
- # otherwise resolve the block device specification
- local dev="$CRYPTTAB_SOURCE"
- dev="$(resolve_device_spec "$dev")" && CRYPTTAB_SOURCE="$dev" || return 1
- }
- # run_keyscript($keyscriptarg, $tried_count)
- # exec()'ute `$CRYPTTAB_OPTION_keyscript $keyscriptarg`.
- # If $CRYPTTAB_OPTION_keyscript is unset or null and $keyscriptarg is
- # "none" (meaning the passphrase is to be read interactively from the
- # console), use `/lib/cryptsetup/askpass` as keyscript with a suitable
- # prompt message.
- # Since the shell process is replaced with the $CRYPTTAB_OPTION_keyscript
- # program, run_keyscript() must be used on the left-hand side of a
- # pipe, or similar.
- run_keyscript() {
- local keyscriptarg="$1" CRYPTTAB_TRIED="$2" keyscript;
- export CRYPTTAB_NAME CRYPTTAB_SOURCE CRYPTTAB_OPTIONS
- export CRYPTTAB_TRIED
- if [ -n "${CRYPTTAB_OPTION_keyscript+x}" ] && \
- [ "$CRYPTTAB_OPTION_keyscript" != "/lib/cryptsetup/askpass" ]; then
- # 'keyscript' option is present: export its argument as
- # $CRYPTTAB_KEY
- export CRYPTTAB_KEY="$keyscriptarg"
- keyscript="$CRYPTTAB_OPTION_keyscript"
- elif [ "$keyscriptarg" = none ]; then
- # don't export the prompt message as CRYPTTAB_KEY
- keyscript="/lib/cryptsetup/askpass"
- keyscriptarg="Please unlock disk $CRYPTTAB_NAME: "
- fi
- exec "$keyscript" "$keyscriptarg"
- }
- # get_crypt_type()
- # Set CRYPTTAB_TYPE to the mapping type, depending on its
- # $CRYPTTAB_OPTION_<option> values
- get_crypt_type() {
- if [ "${CRYPTTAB_OPTION_tcrypt-}" = "yes" ]; then
- CRYPTTAB_TYPE="tcrypt"
- elif [ "${CRYPTTAB_OPTION_plain-}" = "yes" ]; then
- CRYPTTAB_TYPE="plain"
- elif [ "${CRYPTTAB_OPTION_luks-}" = "yes" ] ||
- /sbin/cryptsetup isLuks -- "${CRYPTTAB_OPTION_header-$CRYPTTAB_SOURCE}"; then
- CRYPTTAB_TYPE="luks"
- else
- # assume plain dm-crypt device by default
- CRYPTTAB_TYPE="plain"
- fi
- }
- # unlock_mapping([$keyfile])
- # Run cryptsetup(8) with suitable options and arguments to unlock
- # $CRYPTTAB_SOURCE and setup dm-crypt managed device-mapper mapping
- # $CRYPTTAB_NAME.
- unlock_mapping() {
- local keyfile="${1:--}"
- if [ "$CRYPTTAB_TYPE" = "luks" ] || [ "$CRYPTTAB_TYPE" = "tcrypt" ]; then
- # ignored for LUKS and TCRYPT devices
- unset -v CRYPTTAB_OPTION_cipher \
- CRYPTTAB_OPTION_size \
- CRYPTTAB_OPTION_hash \
- CRYPTTAB_OPTION_offset \
- CRYPTTAB_OPTION_skip
- fi
- if [ "$CRYPTTAB_TYPE" = "plain" ] || [ "$CRYPTTAB_TYPE" = "tcrypt" ]; then
- unset -v CRYPTTAB_OPTION_keyfile_size
- fi
- if [ "$CRYPTTAB_TYPE" = "tcrypt" ]; then
- # ignored for TCRYPT devices
- unset -v CRYPTTAB_OPTION_keyfile_offset
- else
- # ignored for non-TCRYPT devices
- unset -v CRYPTTAB_OPTION_veracrypt CRYPTTAB_OPTION_tcrypthidden
- fi
- if [ "$CRYPTTAB_TYPE" != "luks" ]; then
- # ignored for non-LUKS devices
- unset -v CRYPTTAB_OPTION_keyslot
- fi
- /sbin/cryptsetup -T1 \
- ${CRYPTTAB_OPTION_header:+--header="$CRYPTTAB_OPTION_header"} \
- ${CRYPTTAB_OPTION_cipher:+--cipher="$CRYPTTAB_OPTION_cipher"} \
- ${CRYPTTAB_OPTION_size:+--key-size="$CRYPTTAB_OPTION_size"} \
- ${CRYPTTAB_OPTION_sector_size:+--sector-size="$CRYPTTAB_OPTION_sector_size"} \
- ${CRYPTTAB_OPTION_hash:+--hash="$CRYPTTAB_OPTION_hash"} \
- ${CRYPTTAB_OPTION_offset:+--offset="$CRYPTTAB_OPTION_offset"} \
- ${CRYPTTAB_OPTION_skip:+--skip="$CRYPTTAB_OPTION_skip"} \
- ${CRYPTTAB_OPTION_verify:+--verify-passphrase} \
- ${CRYPTTAB_OPTION_readonly:+--readonly} \
- ${CRYPTTAB_OPTION_discard:+--allow-discards} \
- ${CRYPTTAB_OPTION_veracrypt:+--veracrypt} \
- ${CRYPTTAB_OPTION_keyslot:+--key-slot="$CRYPTTAB_OPTION_keyslot"} \
- ${CRYPTTAB_OPTION_tcrypthidden:+--tcrypt-hidden} \
- ${CRYPTTAB_OPTION_keyfile_size:+--keyfile-size="$CRYPTTAB_OPTION_keyfile_size"} \
- ${CRYPTTAB_OPTION_keyfile_offset:+--keyfile-offset="$CRYPTTAB_OPTION_keyfile_offset"} \
- --type="$CRYPTTAB_TYPE" --key-file="$keyfile" \
- open -- "$CRYPTTAB_SOURCE" "$CRYPTTAB_NAME"
- }
- # crypttab_key_check()
- # Sanity checks for keyfile $CRYPTTAB_KEY. CRYPTTAB_NAME and
- # CRYPTTAB_OPTION_<option> must be set appropriately.
- crypttab_key_check() {
- if [ ! -f "$CRYPTTAB_KEY" ] && [ ! -b "$CRYPTTAB_KEY" ] && [ ! -c "$CRYPTTAB_KEY" ] ; then
- cryptsetup_message "WARNING: $CRYPTTAB_NAME: keyfile '$CRYPTTAB_KEY' not found"
- return 0
- fi
- if [ "$CRYPTTAB_KEY" = "/dev/random" ] || [ "$CRYPTTAB_KEY" = "/dev/urandom" ]; then
- if [ -n "${CRYPTTAB_OPTION_luks+x}" ] || [ -n "${CRYPTTAB_OPTION_tcrypt+x}" ]; then
- cryptsetup_message "WARNING: $CRYPTTAB_NAME: has random data as key"
- return 1
- else
- return 0
- fi
- fi
- local mode="$(stat -L -c"%04a" -- "$CRYPTTAB_KEY")"
- if [ $(stat -L -c"%u" -- "$CRYPTTAB_KEY") -ne 0 ] || [ "${mode%00}" = "$mode" ]; then
- cryptsetup_message "WARNING: $CRYPTTAB_NAME: key file $CRYPTTAB_KEY has" \
- "insecure ownership, see /usr/share/doc/cryptsetup/README.Debian.gz."
- fi
- }
- # resolve_device_spec($spec)
- # Resolve LABEL=<label>, UUID=<uuid>, PARTUUID=<partuuid> and
- # PARTLABEL=<partlabel> to a block special device. If $spec is
- # already a (link to a block special device) then it is echoed as is.
- # Return 1 if $spec doesn't correspond to a block special device.
- resolve_device_spec() {
- local spec="$1"
- case "$spec" in
- UUID=*|LABEL=*|PARTUUID=*|PARTLABEL=*)
- # don't use /dev/disk/by-label/... to avoid gessing udev mangling
- spec="$(blkid -l -t "$spec" -o device)" || spec=
- ;;
- esac
- [ -b "$spec" ] && printf '%s\n' "$spec" || return 1
- }
- # dm_blkdevname($name)
- # Print the mapped device name, or return 1 if the the device doesn't exist.
- dm_blkdevname() {
- local name="$1" dev
- # /dev/mapper/$name isn't reliable due to udev mangling
- if dev="$(dmsetup info -c --noheadings -o blkdevname -- "$name" 2>/dev/null)" &&
- [ -n "$dev" ] && [ -b "/dev/$dev" ]; then
- echo "/dev/$dev"
- return 0
- else
- return 1
- fi
- }
- # crypttab_find_entry([--quiet], $target)
- # Search in the crypttab(5) for the given $target, and sets the
- # variables CRYPTTAB_NAME, CRYPTTAB_SOURCE, CRYPTTAB_KEY and
- # CRYPTTAB_OPTIONS accordingly. (In addition _CRYPTTAB_NAME,
- # _CRYPTTAB_SOURCE, _CRYPTTAB_KEY and _CRYPTTAB_OPTIONS are set to the
- # unmangled values before decoding the escape sequence.) If there are
- # duplicates then only the first match is considered.
- # Return 0 if a match is found, and 1 otherwise.
- crypttab_find_entry() {
- local target="$1" quiet="n" IFS
- if [ "$target" = "--quiet" ] && [ $# -eq 2 ]; then
- quiet="y"
- target="$2"
- fi
- if [ -f "$TABFILE" ]; then
- while IFS=" " read -r _CRYPTTAB_NAME _CRYPTTAB_SOURCE _CRYPTTAB_KEY _CRYPTTAB_OPTIONS; do
- if [ "${_CRYPTTAB_NAME#\#}" != "$_CRYPTTAB_NAME" ] || [ -z "$_CRYPTTAB_NAME" ]; then
- # ignore comments and empty lines
- continue
- fi
- # unmangle names
- CRYPTTAB_NAME="$(printf '%b' "$_CRYPTTAB_NAME")"
- if [ -z "$_CRYPTTAB_SOURCE" ] || [ -z "$_CRYPTTAB_KEY" ] || [ -z "$_CRYPTTAB_OPTIONS" ]; then
- cryptsetup_message "WARNING: '$CRYPTTAB_NAME' is missing some arguments, see crypttab(5)"
- continue
- elif [ "$CRYPTTAB_NAME" = "$target" ]; then
- CRYPTTAB_SOURCE="$( printf '%b' "$_CRYPTTAB_SOURCE" )"
- CRYPTTAB_KEY="$( printf '%b' "$_CRYPTTAB_KEY" )"
- CRYPTTAB_OPTIONS="$(printf '%b' "$_CRYPTTAB_OPTIONS")"
- return 0
- fi
- done <"$TABFILE"
- fi
- if [ "$quiet" = "n" ]; then
- cryptsetup_message "WARNING: target '$target' not found in $TABFILE"
- fi
- return 1
- }
- # crypttab_foreach_entry($callback)
- # Iterate through the crypttab(5) and run the given $callback for each
- # entry found. Variables CRYPTTAB_NAME, CRYPTTAB_SOURCE, CRYPTTAB_KEY
- # and CRYPTTAB_OPTIONS are set accordingly and available to the
- # $callback. (In addition _CRYPTTAB_NAME, _CRYPTTAB_SOURCE,
- # _CRYPTTAB_KEY and _CRYPTTAB_OPTIONS are set to the unmangled values
- # before decoding the escape sequence.)
- # Return 0 if a match is found, and 1 otherwise.
- crypttab_foreach_entry() {
- local callback="$1" IFS
- local _CRYPTTAB_NAME _CRYPTTAB_SOURCE _CRYPTTAB_KEY _CRYPTTAB_OPTIONS \
- CRYPTTAB_NAME CRYPTTAB_SOURCE CRYPTTAB_KEY CRYPTTAB_OPTIONS
- [ -f "$TABFILE" ] || return
- while IFS=" " read -r _CRYPTTAB_NAME _CRYPTTAB_SOURCE _CRYPTTAB_KEY _CRYPTTAB_OPTIONS <&9; do
- if [ "${_CRYPTTAB_NAME#\#}" != "$_CRYPTTAB_NAME" ] || [ -z "$_CRYPTTAB_NAME" ]; then
- # ignore comments and empty lines
- continue
- fi
- # unmangle names
- CRYPTTAB_NAME="$( printf '%b' "$_CRYPTTAB_NAME" )"
- CRYPTTAB_SOURCE="$( printf '%b' "$_CRYPTTAB_SOURCE" )"
- CRYPTTAB_KEY="$( printf '%b' "$_CRYPTTAB_KEY" )"
- CRYPTTAB_OPTIONS="$(printf '%b' "$_CRYPTTAB_OPTIONS")"
- if [ -z "$CRYPTTAB_SOURCE" ] || [ -z "$CRYPTTAB_KEY" ] || [ -z "$CRYPTTAB_OPTIONS" ]; then
- cryptsetup_message "WARNING: '$CRYPTTAB_NAME' is missing some arguments, see crypttab(5)"
- continue
- fi
- "$callback" 9<&-
- done 9<"$TABFILE"
- }
- # vim: set filetype=sh :
|