mirror of
https://github.com/mail-in-a-box/mailinabox.git
synced 2025-04-04 00:17:06 +00:00
186 lines
5.2 KiB
Bash
Executable File
186 lines
5.2 KiB
Bash
Executable File
#!/bin/bash
|
|
#####
|
|
##### This file is part of Mail-in-a-Box-LDAP which is released under the
|
|
##### terms of the GNU Affero General Public License as published by the
|
|
##### Free Software Foundation, either version 3 of the License, or (at
|
|
##### your option) any later version. See file LICENSE or go to
|
|
##### https://github.com/downtownallday/mailinabox-ldap for full license
|
|
##### details.
|
|
#####
|
|
|
|
|
|
usage() {
|
|
echo ""
|
|
echo "Restore a Mail-In-A-Box or Cloud-In-A-Box user-data directory from a local backup"
|
|
echo ""
|
|
echo "usage: $0 <storage-user> <path-to-encrypted-dir> <path-to-secret-key.txt> [path-to-restore-to]"
|
|
echo " storage-user:"
|
|
echo " the user account that owns the miab files. eg 'user-data'"
|
|
echo " path-to-encrypted-dir:"
|
|
echo " a directory containing a copy of duplicity files to restore. These were in"
|
|
echo " /home/user-data/backup/encrypted on the system."
|
|
echo ""
|
|
echo " path-secret-key.txt:"
|
|
echo " a copy of the encryption key file 'secret-key.txt' that was kept in"
|
|
echo " /home/user-data/backup/secret-key.txt."
|
|
echo ""
|
|
echo " path-to-restore-to:"
|
|
echo " the directory where the restored files are placed. the default location is"
|
|
echo " /home/<storage-user>. FILES IN THIS DIRECTORY WILL BE REPLACED. IF THIS IS A MOUNT POINT ENTER A SUBDIRECTORY OF THE MOUNT POINT THEN MANUALLY MOVE THE FILES BACK ONE LEVEL BECAUSE DUPLICITY AUTOMATICALLY UNMOUNTS IT!"
|
|
echo ""
|
|
echo "If you're using encryption-at-rest, make sure it's mounted before restoring"
|
|
echo "eg: run ehdd/mount.sh"
|
|
echo ""
|
|
exit 1
|
|
}
|
|
|
|
if [ $# -lt 3 ]; then
|
|
usage
|
|
fi
|
|
|
|
if [ $EUID -ne 0 ]; then
|
|
echo "Must be run as root" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
storage_user="$1"
|
|
backup_files_dir="$(realpath "$2")"
|
|
secret_key_file="$3"
|
|
restore_to_dir="$(realpath "${4:-/home/$storage_user}")"
|
|
|
|
|
|
PASSPHRASE="$(cat "$secret_key_file")"
|
|
if [ $? -ne 0 ]; then
|
|
echo "unable to access $secret_key_file" 1>&2
|
|
exit 1
|
|
fi
|
|
export PASSPHRASE
|
|
|
|
if [ ! -d "$backup_files_dir" ]; then
|
|
echo "Does not exist or not a directory: $backup_files_dir" 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "Shutting down services"
|
|
ehdd/shutdown.sh --no-umount || exit 1
|
|
|
|
if [ ! -x /usr/bin/duplicity ]; then
|
|
echo "Installing duplicity"
|
|
tmpf=$(mktemp)
|
|
apt-get install -y duplicity &> "$tmpf"
|
|
if [ $? -ne 0 ]; then
|
|
echo "Failed: " 1>&2
|
|
cat "$tmpf" 1>&2
|
|
rm -f "$tmpf"
|
|
exit 1
|
|
fi
|
|
rm -f "$tmpf"
|
|
fi
|
|
|
|
# Ensure users and groups are created so that duplicity properly
|
|
# restores permissions.
|
|
#
|
|
# system_users format:
|
|
# user:group:comment:homedir:shell
|
|
#
|
|
# if the user name and group of `system_users` are identical, the
|
|
# group is created, otherwise the group must already exist (see
|
|
# system_groups below, which are created before users)
|
|
|
|
if [ -e "setup/ldap.sh" ]; then
|
|
# Mail-In-A-Box
|
|
system_users=(
|
|
"openldap:openldap:OpenLDAP Server Account:/var/lib/ldap:/bin/false"
|
|
"opendkim:opendkim::/run/opendkim:/usr/sbin/nologin"
|
|
"spampd:spampd::/nonexistent:/usr/sbin/nologin"
|
|
"www-data:www-data:www-data:/var/www:/usr/sbin/nologin"
|
|
"postgrey:postgrey::/var/lib/postgrey:/usr/sbin/nologin"
|
|
)
|
|
else
|
|
# Cloud-In-A-Box
|
|
system_users=(
|
|
"mysql:mysql:MySQL Server:/nonexistent:/bin/false"
|
|
"www-data:www-data:www-data:/var/www:/usr/sbin/nologin"
|
|
)
|
|
fi
|
|
|
|
system_groups=(
|
|
"ssl-cert"
|
|
)
|
|
|
|
# add system groups
|
|
idx=0
|
|
while [ $idx -lt ${#system_groups[*]} ]; do
|
|
group="${system_groups[$idx]}"
|
|
groupadd -fr "$group"
|
|
let idx+=1
|
|
done
|
|
|
|
# add system users
|
|
idx=0
|
|
while [ $idx -lt ${#system_users[*]} ]; do
|
|
user=$(awk -F: '{print $1}' <<<"${system_users[$idx]}")
|
|
group=$(awk -F: '{print $2}' <<<"${system_users[$idx]}")
|
|
comment=$(awk -F: '{print $3}' <<<"${system_users[$idx]}")
|
|
homedir=$(awk -F: '{print $4}' <<<"${system_users[$idx]}")
|
|
shellpath=$(awk -F: '{print $5}' <<<"${system_users[$idx]}")
|
|
|
|
if ! id "$user" >/dev/null 2>&1; then
|
|
opts="-g $group"
|
|
if [ "$group" = "$user" ]; then
|
|
opts="-U"
|
|
fi
|
|
echo "Add user $user"
|
|
useradd --shell "$shellpath" -r -M $opts -c "$comment" -d "$homedir" "$user"
|
|
fi
|
|
let idx+=1
|
|
done
|
|
|
|
# add regular user STORAGE_USER
|
|
if ! id "$storage_user" >/dev/null 2>&1; then
|
|
# ensure the storage user exists
|
|
echo "Add user $storage_user"
|
|
useradd -m $storage_user
|
|
chmod o+x /home/$storage_user
|
|
fi
|
|
|
|
echo "Restoring with duplicity"
|
|
opts=""
|
|
if [ -e "$restore_to_dir" ]; then
|
|
opts="--force"
|
|
fi
|
|
duplicity restore $opts "file://$backup_files_dir" "$restore_to_dir" 2>&1 | (
|
|
code=0
|
|
while read line; do
|
|
echo "$line"
|
|
case "$line" in
|
|
Error\ * )
|
|
code=1
|
|
;;
|
|
esac
|
|
done; exit $code)
|
|
|
|
codes="${PIPESTATUS[0]}${PIPESTATUS[1]}"
|
|
[ "$codes" -ne "00" ] && exit 1
|
|
|
|
|
|
#
|
|
# check that filesystem uid's/gid's mapped to actual users/groups
|
|
#
|
|
files_with_nouser="$(find "$restore_to_dir" -nouser)"
|
|
files_with_nogroup="$(find "$restore_to_dir" -nogroup)"
|
|
if [ "${files_with_nouser}${files_with_nogroup}" != "" ]; then
|
|
echo ""
|
|
echo "WARNING: some restored file/directory ownerships are unmatched"
|
|
echo "They are:"
|
|
(find "$restore_to_dir" -nouser; find "$restore_to_dir" -nogroup) | sort | uniq
|
|
fi
|
|
|
|
|
|
echo ""
|
|
echo "Restore successful"
|
|
echo ""
|
|
|
|
exit 0
|
|
|