summaryrefslogtreecommitdiff
path: root/open_sesame.sh
blob: 631c87dd5378725e898468afa05ec68b9dc0b0b4 (plain)
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
#!/bin/bash
#
#   open_sesame.sh -- semi-automated luksOpen of encrypted RAID clusters
#
#   Copyright (C) 2018-2019 Andrew Marchetta
#
#   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, either version 3 of the License, or
#   (at your option) any later version.
#
#   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 <https://www.gnu.org/licenses/>.

# Do not proceed unless user is root.
verify_rootuser() {
    if [[ $EUID -ne 0 ]]; then
        printf "You must be root to run this script.\n" >&2
        return 1
    fi
    return 0
}

# Do not proceed unless cryptsetup exists on the system
locate_cryptsetup() {
    which cryptsetup 2>&1 >/dev/null
    err=$?
    if [[ $err -ne 0 ]]; then
        printf 'Could not locate cryptsetup.\n' >&2
        printf '%s requires the cryptsetup binary to work.\n' "$0" >&2
        return 1
    fi
    return 0
}

# Define a central configuration for the script.
set_config() {
    # Define the UUIDs of the RAID members for later identification. Be sure to
    # replace the defaults with the UUIDs of your own devices! Naturally, you
    # should include an entry for each device in your RAID cluster, which may be
    # more than the two placeholder devices listed here.
    declare -g -a raid_members=(
        "12345678-9abc-def0-1234-56789abcdef0"
        "fedcba98-7654-3210-0f1e-2c3b4a596877"
    )

    # Define the mountpoint for the RAID volume, assumed to be in fstab. Be sure to
    # change to change the default value if your system does not use it!
    declare -g raid_mountpoint="/mnt"
    declare -g mount_delay=2
}

# Attempt to open the provided LUKS member.
luks_openmember() {
    if [[ -z "$1" ]]; then
        printf "You must pass this function a single argument (others ignored)." >&2
        return 1
    fi

    if [[ -L "$(find "/dev/disk/by-id/dm-uuid-CRYPT-LUKS1-${raid_thismember//\-}-"* 2>/dev/null)" ]]; then
        printf "LUKS device %s already opened; skipping.\n" "$raid_thismember"
    else
        printf 'Attempting to open %s.\n' "$raid_thismember"
        printf 'Supply your passphrase when prompted.\n'
        cryptsetup luksOpen UUID="$raid_thismember" dev_"${raid_thismember}"
        err=$?
        if [[ $err -ne 0 ]]; then
            printf 'ERROR: cryptsetup reported error code %u\n' "$err" >&2
            printf 'Check passphrase and make sure %s is a valid LUKS device.\n' "$raid_thismember" >&2
            return 1
        fi
    fi

    return 0
}

# Attempt to luksOpen all listed devices.
raid_tryopenall() {
    declare openfailure=0
    for raid_thismember in "${raid_members[@]}"; do
        if luks_openmember "$raid_thismember"; then
            printf 'Successfully opened %s.\n' "$raid_thismember"
        else
            printf 'Failed to open %s.\n' "$raid_thismember" >&2
            openfailure=1
        fi
    done

    return $openfailure
}

# With both drives opened, it is now acceptable to attempt mounting the volume.
raid_trymount() {
    echo "Waiting $mount_delay seconds before attempting mount..."
    sleep $mount_delay
    mount "$raid_mountpoint"
    err=$?
    if [[ $err -ne 0 ]]; then
        printf 'ERROR: mount reported error code %u\n' "$err" >&2
        printf 'Ensure presence of /etc/fstab entry for %s\n' "$raid_mountpoint" >&2
        return 1
    fi

    return 0
}

# Main routine.
verify_rootuser     || exit 1
locate_cryptsetup   || exit 1
set_config          || exit 1

declare ret=0
if raid_tryopenall; then
    if raid_trymount; then
        :
    else
        printf "Not proceeding due to fatal error.\n" >&2
        ret=1
    fi
else
    printf "Not proceeding due to fatal error.\n" >&2
    ret=1
fi

exit $ret