summaryrefslogtreecommitdiffstats
path: root/source/a/cryptsetup/rc.luks
blob: 9e85ceadeeddf8f56a617909efab70ebec797818 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/bin/bash
# Open any volumes created by cryptsetup.
#
# Some notes on /etc/crypttab in Slackware:
# Only LUKS formatted volumes are supported (except for swap)
# crypttab follows the following format:
# <luks_name> <device> <password> <options>
#
# <luks_name>:  This is the name of your LUKS volume.
# For example:  crypt-home
#
# <device>:  This is the device containing your LUKS volume.
# For example:  /dev/sda2
#
# <password>:  This is either the volume password in plain text, or the name of
# a key file.  Use 'none' to interactively enter password on boot.
#
# <options>:  Comma-separated list of options.  Note that there must be a
# password field for any options to be picked up (use a password of 'none' to
# get a password prompt at boot).  The following options are supported:
#
# discard -- this will cause --allow-discards to be passed to the cryptsetup
# program while opening the LUKS volume.
#
# ro -- this will cause --readonly to be passed to the cryptsetup program while
# opening the LUKS volume.
#
# swap -- this option cannot be used with other options.  The device given will
# be formatted as a new encrypted volume with a random key on boot, and used as
# swap.
#
# keyscript=<path/to/script> -- get the password from the named script's stdout.
# The only parameter sent to script is the <password> field, but the script can
# ignore it.
#

luks_start() {
  if [ -f /etc/crypttab -a -x /sbin/cryptsetup ]; then
    # First, check for device-mapper support.
    if ! grep -wq device-mapper /proc/devices ; then
      # If device-mapper exists as a module, try to load it.
      # Try to load a device-mapper kernel module:
      /sbin/modprobe -q dm-mod
    fi
    # NOTE: we only support LUKS formatted volumes (except for swap)!
    # The input for this loop comes from after the "done" below, so that we can
    # use fd3 and keep stdin functional for password entry or in case a keyscript
    # requires it:
    while read line <&3; do
      eval LUKSARRAY=( $line )
      LUKS="${LUKSARRAY[0]}"
      DEV="${LUKSARRAY[1]}"
      PASS="${LUKSARRAY[2]}"
      OPTS="${LUKSARRAY[3]}"
      KEYSCRIPT="$(echo $OPTS | sed -n 's/.*keyscript=\([^,]*\).*/\1/p')"
      LUKSOPTS=""
      if echo $OPTS | grep -wq ro ; then LUKSOPTS="${LUKSOPTS} --readonly" ; fi
      if echo $OPTS | grep -wq discard ; then LUKSOPTS="${LUKSOPTS} --allow-discards" ; fi
      # Skip LUKS volumes that were already unlocked (in the initrd):
      /sbin/cryptsetup status $LUKS 2>/dev/null | head -n 1 | grep -q "is active" && continue
      if /sbin/cryptsetup isLuks $DEV 2>/dev/null ; then
        if [ -z "${LUKSOPTS}" ]; then
          echo "Unlocking LUKS encrypted volume '${LUKS}' on device '$DEV':"
        else
          echo "Unlocking LUKS encrypted volume '${LUKS}' on device '$DEV' with options '${LUKSOPTS}':"
        fi
        if [ -x "${KEYSCRIPT}" ]; then
  	# A password was outputted by a script
  	${KEYSCRIPT} "${PASS}" | /sbin/cryptsetup ${LUKSOPTS} luksOpen $DEV $LUKS
  	echo
        elif [ -n "${PASS}" -a "${PASS}" != "none" ]; then
          if [ -f "${PASS}" ]; then
            # A password was given a key-file filename
            /sbin/cryptsetup ${LUKSOPTS} --key-file=${PASS} luksOpen $DEV $LUKS
          else
            # A password was provided in plain text
            echo "${PASS}" | /sbin/cryptsetup ${LUKSOPTS} luksOpen $DEV $LUKS
          fi
        else
          # No password was given, or a password of 'none' was given
          /sbin/cryptsetup ${LUKSOPTS} luksOpen $DEV $LUKS
        fi
      elif echo $OPTS | grep -wq swap ; then
        # If any of the volumes is to be used as encrypted swap,
        # then encrypt it using a random key and run mkswap:
        echo "Creating encrypted swap volume '${LUKS}' on device '$DEV':"
        /sbin/cryptsetup --batch-mode --cipher=aes --key-file=/dev/urandom --key-size=256 create $LUKS $DEV
        mkswap /dev/mapper/$LUKS
      fi
    done 3< <(grep -vE '^(#|$)' /etc/crypttab)
  fi
}

luks_stop() {
  # Close any volumes opened by cryptsetup:
  if [ -f /etc/crypttab -a -x /sbin/cryptsetup ]; then
    cat /etc/crypttab | grep -v "^#" | grep -v "^$" | while read line; do
      # NOTE: we only support LUKS formatted volumes (except for swap)!
      LUKS=$(echo $line | tr '\t' ' ' | tr -s ' ' | cut -f1 -d' ')
      DEV=$(echo $line | tr '\t' ' ' | tr -s ' ' | cut -f2 -d' ')
      OPTS=$(echo $line | tr '\t' ' ' | tr -s ' ' | cut -f4 -d' ')
      if /sbin/cryptsetup isLuks $DEV 2>/dev/null ; then
        echo "Locking LUKS crypt volume '${LUKS}':"
        /sbin/cryptsetup luksClose ${LUKS}
      elif echo $OPTS | grep -wq swap ; then
        # If any of the volumes was used as encrypted swap,
        # then run mkswap on the underlying device -
        # in case other Linux installations on this computer should use it:
        echo "Erasing encrypted swap '${LUKS}' and restoring normal swap on ${DEV}:"
        /sbin/cryptsetup remove ${LUKS}
        mkswap $DEV
      fi
    done
  fi
}

luks_status() {
  if [ -f /etc/crypttab -a -x /sbin/cryptsetup ]; then
    RET=0
    while read line; do
      # NOTE: we only support LUKS formatted volumes (except for swap)!
      LUKS=$(echo $line | tr '\t' ' ' | tr -s ' ' | cut -f1 -d' ')
      cryptsetup status $LUKS | grep 'active'
      STATUS="${PIPESTATUS[0]}"
      if [ "$STATUS" != "0" ]; then
         RET=1
      fi
    done < <(grep -vE '^(#|$)' /etc/crypttab)
    return $RET
  fi
}

case $1 in
  'start')
    luks_start
    ;;
  'stop')
    luks_stop
    ;;
  'status')
    luks_status
    ;;
  *)
    echo "Usage $0 start|stop|status"
    ;;
esac