pax_global_header00006660000000000000000000000064133647162550014526gustar00rootroot0000000000000052 comment=5df2b95c30fc963bc76291de487b5654e558baf9 yubikey-luks-master/000077500000000000000000000000001336471625500150205ustar00rootroot00000000000000yubikey-luks-master/.gitignore000066400000000000000000000000131336471625500170020ustar00rootroot00000000000000/DEBUILD/ yubikey-luks-master/Makefile000066400000000000000000000020021336471625500164520ustar00rootroot00000000000000info: @echo "builddeb [NO_SIGN=1] - build deb package for Ubuntu LTS [NO_SIGN disables signing]" @echo "clean - clean build directory DEBUILD" @echo "ppa-dev - upload to ppa launchpad. Development" @echo "ppa - upload to ppa launchpad. Stable" VERSION=0.5.1 SRC_DIR = yubikey_luks.orig debianize: rm -fr DEBUILD mkdir -p DEBUILD/${SRC_DIR} cp -r * DEBUILD/${SRC_DIR} || true (cd DEBUILD; tar -zcf yubikey-luks_${VERSION}.orig.tar.gz --exclude=${SRC_DIR}/debian ${SRC_DIR}) builddeb: make debianize ifndef NO_SIGN (cd DEBUILD/${SRC_DIR}; debuild) else (cd DEBUILD/${SRC_DIR}; debuild -uc -us) endif ppa-dev: make debianize (cd DEBUILD/${SRC_DIR}; debuild -S) # Upload to launchpad: dput ppa:privacyidea/privacyidea-dev DEBUILD/yubikey-luks_${VERSION}-?_source.changes ppa: make debianize (cd DEBUILD/${SRC_DIR}; debuild -S) # Upload to launchpad: dput ppa:privacyidea/privacyidea DEBUILD/yubikey-luks_${VERSION}-?_source.changes clean: rm -fr DEBUILD yubikey-luks-master/README.md000066400000000000000000000067161336471625500163110ustar00rootroot00000000000000Yubikey for LUKS ================ This package is inspired and based on https://github.com/tfheen/ykfde. This enables you to use the yubikey as 2FA for LUKS. The Password you enter is used as challenge for the yubikey The keyscript allows to boot the machine with either the password and the Yubikey or with a normal password from any key slot. luksSuspend/luksResume integration is inspired and based on https://github.com/zhongfu/ubuntu-luks-suspend Initialize Yubikey ------------------ Initialize the Yubikey for challenge response in slot 2 ykpersonalize -2 -ochal-resp -ochal-hmac -ohmac-lt64 -oserial-api-visible Install package --------------- Build the package (without signing it): make builddeb NO_SIGN=1 Install the package: dpkg -i DEBUILD/yubikey-luks_0.*-1_all.deb Assign a Yubikey to an LUKS slot -------------------------------- You can now assign the Yubikey to a slot using the tool yubikey-luks-enroll Technically this is done by writing the response to your password (1st factor knowledge) created by the Yubikey (2nd factor possession) to a key slot. Admitted - If the attacker was able to phish this response which looks like this: bd438575f4e8df965c80363f8aa6fe1debbe9ea9 it can be used as normal password. If you set CONCATENATE=1 option in the file /etc/ykluks.cfg then both your password and Yubikey response will be bundled together and written to key slot: passwordbd438575f4e8df965c80363f8aa6fe1debbe9ea9 If you set HASH=1 option in the file /etc/ykluks.cfg then your password will be hashed with sha256 algorithm before using as challenge for yubikey: printf password | sha256sum | awk '{print $1}' 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 Changing the welcome text ------------------------- If you want to change the welcome text a.k.a. the passphrase prompt you can edit the file /etc/ykluks.cfg. After changing this file, you need to run update-initramfs -u so that the changes get transferred to the initramfs. Enable yubikey-luks initramfs module ------------------------- In order to use yubikey-luks for unlocking LUKS encrypted volume at boot you must append keyscript=/usr/share/yubikey-luks/ykluks-keyscript to the /etc/crypttab file. Example: cryptroot /dev/sda none luks,keyscript=/usr/share/yubikey-luks/ykluks-keyscript After changing this file, you need to run update-initramfs -u so that the changes get transferred to the initramfs. Alternatively you may add keyscript=/sbin/ykluks-keyscript to your boot cmdline in cryptoptions. Example: cryptoptions=target=cryptroot,source=/dev/sda,keyscript=/sbin/ykluks-keyscript Enable yubikey-luks-suspend module ------------------------------------ You can enable yubikey-luks-suspend module which allows for automatically locking encrypted LUKS containers and wiping keys from memory on suspend and unlocking them on resume by using luksSuspend, luksResume commands. systemctl enable yubikey-luks-suspend.service Open LUKS container protected with yubikey-luks ------------------------------------ You can open LUKS container protected with yubikey-luks on running system yubikey-luks-open Manage several Yubikeys and Machines ------------------------------------ It is possible to manage several Yubikeys and machines. You need to use privacyIDEA to manage the Yubikeys and the privacyIDEA admin client to push the Yubikey responses to the LUKS slots. See https://github.com/privacyidea/privacyideaadm and https://github.com/privacyidea/privacyidea yubikey-luks-master/debian/000077500000000000000000000000001336471625500162425ustar00rootroot00000000000000yubikey-luks-master/debian/changelog000066400000000000000000000036061336471625500201210ustar00rootroot00000000000000yubikey-luks (0.5.1-1) trusty; urgency=low * Avoid writing temp password to disk -- Cornelius Kölbel Sun, 26 Nov 2017 09:22:00 +0200 yubikey-luks (0.5-1) trusty; urgency=low * Concatenate challenge + response * Add option for hashing password with sha256 * Make script compatible with non-root encrypted volume * Avoid writing temp password to disk -- Cornelius Kölbel Mon, 13 Nov 2017 20:22:00 +0200 yubikey-luks (0.4.1-1) trusty; urgency=low * Make the passphrase welcome text configurable in /etc/ykluks.cfg -- Cornelius Kölbel Mon, 15 Mar 2017 12:49:00 +0200 yubikey-luks (0.4-1) trusty; urgency=low * Fix typo in program name * Add man page -- Cornelius Kölbel Tue, 01 Dec 2015 12:49:00 +0200 yubikey-luks (0.3.3-1) trusty; urgency=low * added option, to clear the slot, so that an empty slot will also work -- Cornelius Kölbel Tue, 22 Jul 2014 21:46:00 +0200 yubikey-luks (0.3.2-1) trusty; urgency=low * added parameters for slot and partition. -- Cornelius Kölbel Tue, 22 Jul 2014 21:20:00 +0200 yubikey-luks (0.3.1-1) trusty; urgency=low * added deb dependency -- Cornelius Kölbel Wed, 16 Jul 2014 18:29:00 +0200 yubikey-luks (0.3-1) trusty; urgency=low * added debian build and upload to ppa -- Cornelius Kölbel Wed, 16 Jul 2014 17:54:00 +0200 yubikey-luks (0.2-1) unstable; urgency=low * Fixed if-error that avoided the usage of plain password -- Cornelius Kölbel Thu, 13 Mar 2014 22:40:00 +0100 yubikey-luks (0.1-1) unstable; urgency=low * Initial release. -- Cornelius Kölbel Thu, 06 Mar 2014 12:22:00 +0100 yubikey-luks-master/debian/compat000066400000000000000000000000031336471625500174410ustar00rootroot0000000000000011 yubikey-luks-master/debian/control000066400000000000000000000016701336471625500176510ustar00rootroot00000000000000Source: yubikey-luks Section: admin Priority: optional Maintainer: Cornelius Kölbel Build-Depends: debhelper (>= 11), dh-exec Standards-Version: 4.1.4 Homepage: https://github.com/cornelinux/yubikey-luks Package: yubikey-luks Architecture: all Depends: cryptsetup, initramfs-tools, yubikey-personalization (>= 1.5), udisks2, expect, ${misc:Depends} Description: YubiKey two factor authentication for LUKS disks With this extension to the initramfs-tools, you can unlock a LUKS encrypted disk using your YubiKey as a second factor. . The challenge-response mechanism of the YubiKey is used to generate a response based on a PIN/password you have to enter. . Only the combination of the correct password and the matching YubiKey will generate a response, that is a valid passphrase of the LUKS disk. Alternatively you can use any other LUKS passphrase when the YubiKey is not present. . Requires Yubikey 2.2 or newer. yubikey-luks-master/debian/copyright000066400000000000000000000024231336471625500201760ustar00rootroot00000000000000 Copyright 2014 Cornelius Kölel All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. yubikey-luks-master/debian/rules000077500000000000000000000024751336471625500173320ustar00rootroot00000000000000#! /usr/bin/make -f %: dh $@ override_dh_auto_build: # nothing to build override_dh_installsystemd: dh_installsystemd -pyubikey-luks \ --no-enable --no-start --no-restart-after-upgrade --no-stop-on-upgrade \ yubikey-luks-suspend.service override_dh_install: dh_install install -D -o root -g root -m755 hook debian/yubikey-luks/usr/share/initramfs-tools/hooks/yubikey-luks install -D -o root -g root -m755 key-script debian/yubikey-luks/usr/share/yubikey-luks/ykluks-keyscript install -D -o root -g root -m755 yubikey-luks-open debian/yubikey-luks/usr/bin/yubikey-luks-open install -D -o root -g root -m755 yubikey-luks-enroll debian/yubikey-luks/usr/bin/yubikey-luks-enroll install -D -o root -g root -m644 yubikey-luks-enroll.1 debian/yubikey-luks/usr/man/man1/yubikey-luks-enroll.1 install -D -o root -g root -m644 README.md debian/yubikey-luks/usr/share/doc/yubikey-luks/README.md install -D -o root -g root -m644 ykluks.cfg debian/yubikey-luks/etc/ykluks.cfg install -D -o root -g root -m755 yubikey-luks-suspend debian/yubikey-luks/usr/lib/yubikey-luks/yubikey-luks-suspend install -D -o root -g root -m755 initramfs-suspend debian/yubikey-luks/usr/lib/yubikey-luks/initramfs-suspend install -D -o root -g root -m644 yubikey-luks-suspend.service debian/yubikey-luks/lib/systemd/system/yubikey-luks-suspend.service yubikey-luks-master/debian/yubikey-luks.postinst000066400000000000000000000004521336471625500225050ustar00rootroot00000000000000#! /bin/sh set -e case "$1" in configure) if [ -x /usr/sbin/update-initramfs ]; then echo update-initramfs -u fi ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac #DEBHELPER# yubikey-luks-master/hook000077500000000000000000000007411336471625500157100ustar00rootroot00000000000000#!/bin/sh set -e PREREQ="cryptroot" prereqs() { echo "$PREREQ" } case $1 in prereqs) prereqs exit 0 ;; esac . /usr/share/initramfs-tools/hook-functions copy_exec /usr/bin/ykchalresp copy_exec /usr/bin/ykinfo copy_exec /usr/bin/sha256sum cp /usr/share/yubikey-luks/ykluks-keyscript "${DESTDIR}/sbin/ykluks-keyscript" cp /etc/ykluks.cfg "${DESTDIR}/etc/ykluks.cfg" cp -pnL /usr/lib/yubikey-luks/initramfs-suspend "${DESTDIR}/suspend" chmod 755 "${DESTDIR}/suspend" exit 0 yubikey-luks-master/initramfs-suspend000066400000000000000000000030771336471625500204250ustar00rootroot00000000000000#!/bin/sh # Copyright 2013 Vianney le Clément de Saint-Marcq # Copyright 2017 Zhongfu Li # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with This program. If not, see http://www.gnu.org/licenses/. cryptname="${1}" # Start udev from initramfs /lib/systemd/systemd-udevd --daemon --resolve-names=never # Sync one more time, just in case sync # Suspend root device [ -z "${cryptname}" ] || cryptsetup luksSuspend "${cryptname}" # Suspend the system echo mem > /sys/power/state # Resume root device . /etc/ykluks.cfg [ -z "${cryptname}" ] || while true; do P1=$(/lib/cryptsetup/askpass "$WELCOME_TEXT") if [ "$HASH" = "1" ]; then P1=$(printf %s "$P1" | sha256sum | awk '{print $1}') fi R="$(ykchalresp -2 "$P1" 2>/dev/null || true)" if [ "$CONCATENATE" = "1" ]; then printf %s "$P1$R" | cryptsetup luksResume "${cryptname}" 2>&1; else printf %s "$R" | cryptsetup luksResume "${cryptname}" 2>&1; fi [ $? -le 1 ] && break sleep 2 done # Stop udev from initramfs, as the real daemon from rootfs will be restarted udevadm control --exit yubikey-luks-master/key-script000077500000000000000000000025321336471625500170420ustar00rootroot00000000000000#! /bin/sh # # This is /sbin/ykluks-keyscript, which gets called when unlocking the disk # . /etc/ykluks.cfg if [ -z "$WELCOME_TEXT" ]; then WELCOME_TEXT="Please insert yubikey and press enter or enter a valid passphrase" fi message() { if [ -x /bin/plymouth ] && plymouth --ping; then plymouth message --text="$*" else echo "$@" >&2 fi return 0 } check_yubikey_present="$(ykinfo -q -2)" # source for log_*_msg() functions, see LP: #272301 if [ -e /scripts/functions ] ; then . /scripts/functions else . /usr/share/initramfs-tools/scripts/functions fi if [ -z "$cryptkeyscript" ]; then cryptkey="Unlocking the disk $cryptsource ($crypttarget)\\nEnter passphrase: " if [ -x /bin/plymouth ] && plymouth --ping; then cryptkeyscript="plymouth ask-for-password --prompt" cryptkey=$(printf '%s' "$cryptkey") else cryptkeyscript="/lib/cryptsetup/askpass" fi fi PW="$($cryptkeyscript "$WELCOME_TEXT")" if [ "$check_yubikey_present" = "1" ]; then message "Accessing yubikey..." if [ "$HASH" = "1" ]; then PW=$(printf %s "$PW" | sha256sum | awk '{print $1}') fi R="$(ykchalresp -2 "$PW" 2>/dev/null || true)" message "Retrieved the response from the Yubikey" if [ "$CONCATENATE" = "1" ]; then printf '%s' "$PW$R" else printf '%s' "$R" fi else printf '%s' "$PW" fi exit 0 yubikey-luks-master/ykluks.cfg000066400000000000000000000005251336471625500170250ustar00rootroot00000000000000# If you change this file, you need to run # update-initramfs -u WELCOME_TEXT="Please insert yubikey and press enter or enter a valid passphrase" # Set to "1" if you want both your password and Yubikey response be bundled together and writtent to key slot. CONCATENATE=0 # Set to "1" if you want to hash your password with sha256. HASH=0 yubikey-luks-master/yubikey-luks-enroll000077500000000000000000000046551336471625500207060ustar00rootroot00000000000000#!/bin/sh SLOT=7 DISK="/dev/sda3" CLEAR_SLOT=0 DBG=0 set -e . /etc/ykluks.cfg if [ "$(id -u)" -ne 0 ]; then echo "You must be root." 1>&2 exit 1 fi while getopts ":s:d:hcv" opt; do case $opt in s) SLOT=$OPTARG echo "setting slot to $OPTARG." ;; d) DISK=$OPTARG echo "setting disk to $OPTARG." ;; c) CLEAR_SLOT=1 echo "clearing slot" ;; v) DBG=1 echo "debugging enabled" ;; h) echo echo " -d : set the partition" echo " -s : set the slot" echo " -c : clear the slot prior to writing" echo " -v : show input/output in cleartext" echo exit 1 ;; \?) echo "Invalid option: -$OPTARG" >&2 ;; esac done echo "This script will utilize slot $SLOT on drive $DISK. If this is not what you intended, exit now!" if [ "$CLEAR_SLOT" = "1" ]; then echo "Killing LUKS slot $SLOT" cryptsetup luksKillSlot "$DISK" "$SLOT" fi echo "Adding yubikey to initrd" while true ; do if lsusb | grep -iq 'yubico'; then break; fi printf "Please insert a yubikey and press enter." read -r _ <&1 done P1=$(/lib/cryptsetup/askpass "Please enter the yubikey challenge password. This is the password that will only work while your yubikey is installed in your computer:") if [ "$DBG" = "1" ]; then echo "Password: $P1"; fi P2=$(/lib/cryptsetup/askpass "Please enter the yubikey challenge password again:") if [ "$DBG" = "1" ]; then echo "Password: $P2"; fi if [ "$P1" != "$P2" ]; then echo "Passwords do not match" exit 1 fi if [ "$HASH" = "1" ]; then P1=$(printf %s "$P1" | sha256sum | awk '{print $1}') if [ "$DBG" = "1" ]; then echo "Password hash: $P1"; fi fi R="$(ykchalresp -2 "$P1" 2>/dev/null || true)" if [ "$DBG" = "1" ]; then echo "Yubikey response: $R"; fi if [ -z "$R" ]; then echo "Yubikey not available or timed out waiting for button press" exit 1 fi OLD=$(/lib/cryptsetup/askpass "Please provide an existing passphrase. This is NOT the passphrase you just entered, this is the passphrase that you currently use to unlock your LUKS encrypted drive:") if [ "$DBG" = "1" ]; then echo "Old passphrase: $OLD"; fi if [ "$CONCATENATE" = "1" ]; then printf '%s\n' "$OLD" "$P1$R" "$P1$R" | cryptsetup --key-slot="$SLOT" luksAddKey "$DISK" 2>&1; if [ "$DBG" = "1" ]; then echo "LUKS key: $P1$R"; fi else printf '%s\n' "$OLD" "$R" "$R" | cryptsetup --key-slot="$SLOT" luksAddKey "$DISK" 2>&1; if [ "$DBG" = "1" ]; then echo "LUKS key: $R"; fi fi exit 0 yubikey-luks-master/yubikey-luks-enroll.1000066400000000000000000000040311336471625500210260ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" (C) Copyright 2015 Markus Frosch .\" .\" Cornelius Kölbel .\" Add the prerequisites .TH YUBIKEY-LUKS-ENROLL 1 "2015-12-01" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME yubikey-luks-enroll - enroll your yubikey for usage with LUKS .SH SYNOPSIS .B yubikey-luks-enroll .RI "[ \-s 3 ] [ \-d /dev/sda6 ] [ \-c ]" .SH DESCRIPTION With this tool you can take a YubiKey with challenge-response enabled on slot 2 to add a LUKS / cryptsetup key slot. Your chosen PIN or password, plus your YubiKey can generate a response that is added as a key to the cryptsetup disk. On the next boot you can insert your YubiKey into a USB slot, enter your password, to unlock the disk. Alternatively you can enter any other passphrase that is valid for that disk. .SH OPTIONS The following options change the behavior of the tool. .TP .B \-h Show summary of options. .TP .B \-s The LUKS slot to save the passphrase to. (default: 7) .TP .B \-c Clear the chosen LUKS slot at first. .TP .B \-d The disk device to work with (default: /dev/sda3) .SH PREREQUISITES Before adding the Yubikey to the LUKS slot, you need to initialize your Yubikey. You can do so using the privacyIDEA management system or simply by using the command line. The following command will create a key for challenges response in Yubikey slot 2: ykpersonalize -2 -ochal-resp -ochal-hmac -ohmac-lt64 -oserial-api-visible After this, you can use yubikey-luks-enroll to assign this Yubikey to an LUKS slot. .SH SEE ALSO .BR cryptsetup (1), .BR ykpersonalize (1), .BR ykchalresp (1). yubikey-luks-master/yubikey-luks-open000066400000000000000000000051341336471625500203420ustar00rootroot00000000000000#!/bin/sh DISK="/dev/sda3" NAME="yubikey-luks" DBG=0 set -e . /etc/ykluks.cfg while getopts ":d:n:hv" opt; do case $opt in d) DISK=$OPTARG echo "setting disk to $OPTARG." ;; n) NAME=$OPTARG echo "setting name to $OPTARG." ;; v) DBG=1 echo "debugging enabled" ;; h) echo echo " -d : select existing partition" echo " -n : set the new container name" echo " -v : show input/output in cleartext" echo exit 1 ;; \?) echo "Invalid option: -$OPTARG" >&2 ;; esac done echo "This script will try opening $NAME LUKS container on drive $DISK . If this is not what you intended, exit now!" while true ; do if lsusb | grep -iq 'yubico'; then break; fi printf "Please insert a yubikey and press enter." read -r _ <&1 done P1=$(/lib/cryptsetup/askpass "Enter password created with yubikey-luks-enroll:") if [ "$DBG" = "1" ]; then echo "Password: $P1"; fi if [ "$HASH" = "1" ]; then P1=$(printf %s "$P1" | sha256sum | awk '{print $1}') if [ "$DBG" = "1" ]; then echo "Password hash: $P1"; fi fi R="$(ykchalresp -2 "$P1" 2>/dev/null || true)" if [ "$DBG" = "1" ]; then echo "Yubikey response: $R"; fi if [ -z "$R" ]; then echo "Yubikey not available or timed out waiting for button press" exit 1 fi _passphrase='' if [ "$CONCATENATE" = "1" ]; then _passphrase=$(printf '%s' "$P1$R") else _passphrase=$(printf '%s' "$R") fi if [ "$DBG" = "1" ]; then echo "LUKS key: ${_passphrase}"; fi if [ "$(id -u)" -eq 0 ]; then printf %s "${_passphrase}" | cryptsetup luksOpen "$DISK" "$NAME" 2>&1; else # c-style escapes are not available in sh, so instead of doing symply # $'\n' we have to put a newline in a variable, see: # https://github.com/koalaman/shellcheck/wiki/SC2039 _n="$(printf '%b_' '\n')" _n="${_n%_}" # reading a HEREDOC to a variable in a POSIX-compliant shell, see: # https://unix.stackexchange.com/a/340907/162158 # basically, the while loop reads the HEREDOC line-by-line (IFS set to # newline) and concatenates everything in a variable and adds a newline. expect_script='' OLDIFS="$IFS" while IFS="${_n}" read -r line; do expect_script="$expect_script$line${_n}" done < # Copyright 2017 Zhongfu Li # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with This program. If not, see http://www.gnu.org/licenses/. set -e -u trap 'echo "Press ENTER to continue."; read dummy' ERR trap cleanup EXIT ################################################################################ ## Parameters and helper functions INITRAMFS_DIR=/run/initramfs SYSTEM_SLEEP_PATH=/lib/systemd/system-sleep BIND_PATHS="/sys /proc /dev /run" REMOUNT=0 # Retrieve cryptdevice name from /proc/mounts -- kinda hacky CRYPTNAME="$(grep -E "^/dev/mapper/[a-zA-Z0-9_\-]+ / " /proc/mounts | sed -r "s|^/dev/mapper/([a-zA-Z0-9_\-]+).*|\1|")" # run_dir DIR ARGS... # Run all executable scripts in directory DIR with arguments ARGS run_dir() { local dir="$1" shift find "${dir}" -type f -executable -exec "{}" "$@" ";" } # Remount root fs with barrier mount_barrier() { if ((REMOUNT)); then mount -o remount,barrier "/dev/mapper/$CRYPTNAME" REMOUNT=0 fi } # Unmount bind mounts umount_bind() { local p for p in ${BIND_PATHS}; do mountpoint -q "${INITRAMFS_DIR}${p}" && umount "${INITRAMFS_DIR}${p}" done } # Unmount (and remove) extracted initramfs # umount -l (lazy) because sometimes, it takes a while before everything stops # using the ramdisk. umount_initramfs() { mountpoint -q "${INITRAMFS_DIR}" && umount -l "${INITRAMFS_DIR}" } cleanup() { mount_barrier ((BIND_MOUNTED)) && umount_bind umount_initramfs } cryptdevice_mount_options() { local mt mt="$(grep "^/dev/mapper/${1} " /proc/mounts | cut -d ' ' -f 3,4 | head -n 1)" local fs fs="$(cut -d ' ' -f 1 <<< "${mt}")" local opt opt="$(cut -d ' ' -f 2 <<< "${mt}")" if [[ "${fs}" == "ext4" || "${fs}" == "btrfs" ]]; then echo "${opt}" fi } ################################################################################ ## Main script # We'll mount ramfs on /run/initramfs, then extract initramfs there # Unmount /run/initramfs in case something failed previously mountpoint -q "${INITRAMFS_DIR}" && umount "${INITRAMFS_DIR}" [ -d "${INITRAMFS_DIR}" ] || mkdir "${INITRAMFS_DIR}" mount -t ramfs ramfs /run/initramfs INITRAMFS="/boot/initrd.img-$(uname -r)" [ -e "${INITRAMFS}" ] || exec /lib/systemd/systemd-sleep suspend cd "${INITRAMFS_DIR}" (cpio --quiet -id; zcat | cpio --quiet -id) < "${INITRAMFS}" chown -R root:root "${INITRAMFS_DIR}" chmod -R go-w "${INITRAMFS_DIR}" # In case we're still missing the suspend script. # (Perhaps the user didn't regenerate initramfs, or we picked the wrong file?) [ -e "${INITRAMFS_DIR}/suspend" ] || exec /lib/systemd/systemd-sleep suspend # Prepare chroot # For some reason, $BIND_PATHS aren't in ${INITRAMFS_DIR} # No worries, we'll just create them if they don't exist BIND_MOUNTED=1 for p in ${BIND_PATHS}; do [ -d "${INITRAMFS_DIR}${p}" ] || mkdir "${INITRAMFS_DIR}${p}" mount -o bind "${p}" "${INITRAMFS_DIR}${p}" done # Run pre-suspend scripts run_dir "${SYSTEM_SLEEP_PATH}" pre suspend # Stop udev service and prevent it from being autostarted. # Otherwise, luksResume will hang waiting for udev, which is itself waiting # for I/O on the root device. systemctl stop systemd-udevd-control.socket systemctl stop systemd-udevd-kernel.socket systemctl stop systemd-udevd.service # Stop systemd-journald and prevent it from being autostarted. # It seems to block suspend with file I/O systemctl stop systemd-journald-audit.socket systemctl stop systemd-journald-dev-log.socket systemctl stop systemd-journald.socket systemctl stop systemd-journald.service # Journalled ext4 filesystems in kernel versions 3.11+ will block suspend # if mounted with `barrier=1`, which is the default. Temporarily remount with # `barrier=0` if this is true of the crypt fs. MOUNT_OPTS="$(cryptdevice_mount_options "$CRYPTNAME")" if [[ "$MOUNT_OPTS" ]] && ! [[ "$MOUNT_OPTS" == *nobarrier* || "$MOUNT_OPTS" == *barrier=0* ]]; then REMOUNT=1 mount -o remount,nobarrier "/dev/mapper/$CRYPTNAME" fi # Synchronize filesystems before luksSuspend sync # Hand over execution to script inside initramfs cd "${INITRAMFS_DIR}" chroot . /suspend "$CRYPTNAME" # Restore original mount options if necessary mount_barrier # Restart systemd-journald systemctl start systemd-journald.socket systemctl start systemd-journald-dev-log.socket systemctl start systemd-journald-audit.socket systemctl start systemd-journald.service # Restart udev systemctl start systemd-udevd-control.socket systemctl start systemd-udevd-kernel.socket systemctl start systemd-udevd.service # Run post-suspend scripts run_dir "${SYSTEM_SLEEP_PATH}" post suspend # Unlock user sessions loginctl unlock-sessions yubikey-luks-master/yubikey-luks-suspend.service000066400000000000000000000011661336471625500225220ustar00rootroot00000000000000# This file has been adapted from systemd. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. [Unit] Description=Suspend Crypto on Standby (WARNING: THIS IS HIGHLY EXPERIMENTAL) Documentation=man:systemd-suspend.service(8) DefaultDependencies=no Requires=sleep.target After=sleep.target [Service] Type=oneshot ExecStart=/bin/openvt -ws /usr/lib/yubikey-luks/yubikey-luks-suspend [Install] Alias=systemd-suspend.service