freedombone/src/freedombone-base-email

1480 lines
57 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
#
# .---. . .
# | | |
# |--- .--. .-. .-. .-.| .-. .--.--. |.-. .-. .--. .-.
# | | (.-' (.-' ( | ( )| | | | )( )| | (.-'
# ' ' --' --' -' - -' ' ' -' -' -' ' - --'
#
# Freedom in the Cloud
#
# Email functions
#
# License
# =======
#
# Copyright (C) 2014-2018 Bob Mottram <bob@freedombone.net>
#
# This program is free software: you can redistribute it and/or modify
# it 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.
#
# 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# the default email address
MY_EMAIL_ADDRESS=$MY_USERNAME@$DEFAULT_DOMAIN_NAME
# If you want to run a public mailing list specify its name here.
# There should be no spaces in the name
PUBLIC_MAILING_LIST=
# Optional different domain name for the public mailing list
PUBLIC_MAILING_LIST_DOMAIN_NAME=
# Directory where the public mailing list data is stored
PUBLIC_MAILING_LIST_DIRECTORY="/var/spool/mlmmj"
# If you want to run an encrypted mailing list specify its name here.
# There should be no spaces in the name
PRIVATE_MAILING_LIST=
GPG_KEYSERVER="hkp://keys.gnupg.net"
# whether to encrypt all incoming email with your public key
GPG_ENCRYPT_STORED_EMAIL="yes"
# optionally you can provide your exported GPG key pair here
# Note that the private key file will be deleted after use
# If these are unspecified then a new GPG key will be created
MY_GPG_PUBLIC_KEY=
MY_GPG_PRIVATE_KEY=
# optionally specify your public key ID
MY_GPG_PUBLIC_KEY_ID=
EXIM_ONION_REPO="https://github.com/petterreinholdtsen/exim4-smtorp"
# automatic archiving of email
CLEANUP_MAILDIR_REPO="https://github.com/bashrc/cleanup-maildir"
CLEANUP_MAILDIR_COMMIT='33241d2e3861f901ba17f5c77ada007e1ec06a86'
# email encryption at rest
GPGIT_REPO="https://gitlab.com/mikecardwell/gpgit"
GPGIT_COMMIT='583dc76119f19420f8a33f606744faa7c8922738'
# refresh gpg keys every few hours
REFRESH_GPG_KEYS_HOURS=2
function email_create_template {
if [ ! -d /etc/skel/log ]; then
mkdir -m 700 /etc/skel/log
fi
if [ ! -d /etc/skel/Maildir ]; then
mkdir -m 700 /etc/skel/.mutt
mkdir -m 700 /etc/skel/Maildir
mkdir -m 700 /etc/skel/Maildir/new
mkdir -m 700 /etc/skel/Maildir/cur
mkdir -m 700 /etc/skel/Maildir/Sent
mkdir -m 700 /etc/skel/Maildir/Sent/tmp
mkdir -m 700 /etc/skel/Maildir/Sent/cur
mkdir -m 700 /etc/skel/Maildir/Sent/new
mkdir -m 700 /etc/skel/Maildir/.learn-spam
mkdir -m 700 /etc/skel/Maildir/.learn-spam/cur
mkdir -m 700 /etc/skel/Maildir/.learn-spam/new
mkdir -m 700 /etc/skel/Maildir/.learn-spam/tmp
mkdir -m 700 /etc/skel/Maildir/.learn-ham
mkdir -m 700 /etc/skel/Maildir/.learn-ham/cur
mkdir -m 700 /etc/skel/Maildir/.learn-ham/new
mkdir -m 700 /etc/skel/Maildir/.learn-ham/tmp
ln -s /etc/skel/Maildir/.learn-spam /etc/skel/Maildir/spam
ln -s /etc/skel/Maildir/.learn-ham /etc/skel/Maildir/ham
fi
if [ ! -d "/home/$MY_USERNAME/Maildir" ]; then
mkdir -m 700 "/home/$MY_USERNAME/.mutt"
mkdir -m 700 "/home/$MY_USERNAME/Maildir"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/cur"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/tmp"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/new"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/Sent"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/Sent/cur"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/Sent/tmp"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/Sent/new"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/.learn-spam"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/.learn-spam/cur"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/.learn-spam/new"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/.learn-spam/tmp"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/.learn-ham"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/.learn-ham/cur"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/.learn-ham/new"
mkdir -m 700 "/home/$MY_USERNAME/Maildir/.learn-ham/tmp"
ln -s "/home/$MY_USERNAME/Maildir/.learn-spam" "/home/$MY_USERNAME/Maildir/spam"
ln -s "/home/$MY_USERNAME/Maildir/.learn-ham" "/home/$MY_USERNAME/Maildir/ham"
chown -R "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/Maildir"
fi
}
function configure_email_onion {
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
if [[ "$SYSTEM_TYPE" == "mesh"* ]]; then
return
fi
if ! grep -q "hidden_service_email" /etc/tor/torrc; then
{ echo 'HiddenServiceDir /var/lib/tor/hidden_service_email/';
echo 'HiddenServicePort 25 127.0.0.1:25';
echo 'HiddenServicePort 587 127.0.0.1:587';
echo 'HiddenServicePort 465 127.0.0.1:465'; } >> /etc/tor/torrc
fi
function_check onion_update
onion_update
function_check wait_for_onion_service
wait_for_onion_service email
if [ ! -f /var/lib/tor/hidden_service_email/hostname ]; then
echo $"email onion site hostname not found"
systemctl restart tor
exit 782352
fi
onion_address=$(cat /var/lib/tor/hidden_service_email/hostname)
set_completion_param "email onion domain" "${onion_address}"
add_email_hostname "$onion_address"
mark_completed "${FUNCNAME[0]}"
}
function check_email_address_exists {
read_config_param ONION_ONLY
read_config_param MY_USERNAME
read_config_param DEFAULT_DOMAIN_NAME
read_config_param MY_EMAIL_ADDRESS
read_config_param DH_KEYLENGTH
if [ ! "$MY_USERNAME" ]; then
echo $'No username for email installation'
exit 73672
fi
if [ ! "$DEFAULT_DOMAIN_NAME" ]; then
echo $'No default domain name for email installation'
exit 57634
fi
my_email="$MY_EMAIL_ADDRESS"
if [ ${#my_email} -lt 3 ]; then
MY_EMAIL_ADDRESS="${MY_USERNAME}@${DEFAULT_DOMAIN_NAME}"
write_config_param "MY_EMAIL_ADDRESS" "$MY_EMAIL_ADDRESS"
fi
}
function backup_email {
echo ''
}
function configure_firewall_for_email {
if [[ "$INSTALLED_WITHIN_DOCKER" == "yes" ]]; then
# docker does its own firewalling
return
fi
if [[ "$ONION_ONLY" != "no" ]]; then
return
fi
firewall_add Email 25 tcp
firewall_add Email 587 tcp
firewall_add Email 465 tcp
firewall_add Imap 993 tcp
}
function encrypt_incoming_email {
# encrypts incoming mail using your GPG public key
# so even if an attacker gains access to the data at rest they still need
# to know your GPG key password to be able to read anything
if [ ! -d /etc/exim4 ]; then
return
fi
# update to the next commit
function_check set_repo_commit
set_repo_commit "$INSTALL_DIR/gpgit" "gpgit commit" "$GPGIT_COMMIT" "$GPGIT_REPO"
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
if [[ "$GPG_ENCRYPT_STORED_EMAIL" != "yes" ]]; then
return
fi
if [ ! -f /usr/bin/gpgit.pl ]; then
apt-get -yq install git libmail-gnupg-perl
cd "$INSTALL_DIR" || exit 246824624
function_check git_clone
git_clone "$GPGIT_REPO" "$INSTALL_DIR/gpgit"
cd "$INSTALL_DIR/gpgit" || exit 7246725474
git checkout "$GPGIT_COMMIT" -b "$GPGIT_COMMIT"
set_completion_param "gpgit commit" "$GPGIT_COMMIT"
cp gpgit.pl /usr/bin
fi
# add a procmail rule
if ! grep -q "/usr/bin/gpgit.pl" "/home/$MY_USERNAME/.procmailrc"; then
{ echo '';
echo ':0 f';
echo "| /usr/bin/gpgit.pl --encrypt-mode prefer-inline --inline-flatten $MY_EMAIL_ADDRESS"; } >> "/home/$MY_USERNAME/.procmailrc"
chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.procmailrc"
{ echo '';
echo ':0 f';
echo -n "| /usr/bin/gpgit.pl --encrypt-mode prefer-inline --inline-flatten \$USER@";
echo "$DEFAULT_DOMAIN_NAME"; } >> /etc/skel/.procmailrc
fi
mark_completed "${FUNCNAME[0]}"
}
function encrypt_outgoing_email {
# encrypts outgoing mail using your GPG public key
# so even if an attacker gains access to the data at rest they still need
# to know your GPG key password to be able to read sent mail
if [ ! -d /etc/exim4 ]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
if [[ "$GPG_ENCRYPT_STORED_EMAIL" != "yes" ]]; then
return
fi
if [ ! -d "/home/$MY_USERNAME/.gnupg" ]; then
return
fi
if [ ! -f "/home/$MY_USERNAME/.muttrc" ]; then
return
fi
# obtain your public key ID
if [ ! "$MY_GPG_PUBLIC_KEY_ID" ]; then
MY_GPG_PUBLIC_KEY_ID=$(gpg_pubkey_from_email "$MY_USERNAME" "$MY_EMAIL_ADDRESS")
if [ ! "$MY_GPG_PUBLIC_KEY_ID" ]; then
return
fi
if [ ${#MY_GPG_PUBLIC_KEY_ID} -lt 4 ]; then
return
fi
fi
if ! grep -q "pgp_encrypt_only_command" "/home/$MY_USERNAME/.muttrc"; then
{ echo '';
echo $'# Encrypt items in the Sent folder';
echo "set pgp_encrypt_only_command=\"/usr/lib/mutt/pgpewrap gpg --batch --quiet --no-verbose --output - --encrypt --textmode --armor --trust-model always --encrypt-to $MY_GPG_PUBLIC_KEY_ID -- -r %r -- %f\""; } >> "/home/$MY_USERNAME/.muttrc"
else
sed -i "s|set pgp_encrypt_only_command.*|set pgp_encrypt_only_command=\"/usr/lib/mutt/pgpewrap gpg --batch --quiet --no-verbose --output - --encrypt --textmode --armor --trust-model always --encrypt-to $MY_GPG_PUBLIC_KEY_ID -- -r %r -- %f\"|g" "/home/$MY_USERNAME/.muttrc"
fi
if ! grep -q "pgp_encrypt_sign_command" "/home/$MY_USERNAME/.muttrc"; then
echo "set pgp_encrypt_sign_command=\"/usr/lib/mutt/pgpewrap gpg %?p?--passphrase-fd 0? --batch --quiet --no-verbose --textmode --output - --encrypt --sign %?a?-u %a? --armor --trust-model always --encrypt-to $MY_GPG_PUBLIC_KEY_ID -- -r %r -- %f\"" >> "/home/$MY_USERNAME/.muttrc"
else
sed -i "s|set pgp_encrypt_sign_command.*|set pgp_encrypt_sign_command=\"/usr/lib/mutt/pgpewrap gpg %?p?--passphrase-fd 0? --batch --quiet --no-verbose --textmode --output - --encrypt --sign %?a?-u %a? --armor --trust-model always --encrypt-to $MY_GPG_PUBLIC_KEY_ID -- -r %r -- %f\"|g" "/home/$MY_USERNAME/.muttrc"
fi
mark_completed "${FUNCNAME[0]}"
}
function encrypt_all_email {
if [ ! -d /etc/exim4 ]; then
return
fi
if [[ "$GPG_ENCRYPT_STORED_EMAIL" != "yes" ]]; then
return
fi
if [ -f "/usr/local/bin/${PROJECT_NAME}-encrypt-mail" ]; then
if [ ! -f /usr/bin/encmaildir ]; then
cp "/usr/local/bin/${PROJECT_NAME}-encrypt-mail" /usr/bin/encmaildir
else
HASH1=$(sha256sum "/usr/local/bin/${PROJECT_NAME}-encrypt-mail" | awk -F ' ' '{print $1}')
HASH2=$(sha256sum /usr/bin/encmaildir | awk -F ' ' '{print $1}')
if [[ "$HASH1" != "$HASH2" ]]; then
cp "/usr/local/bin/${PROJECT_NAME}-encrypt-mail" /usr/bin/encmaildir
fi
fi
else
if [ ! -f /usr/bin/encmaildir ]; then
cp "/usr/bin/${PROJECT_NAME}-encrypt-mail" /usr/bin/encmaildir
else
HASH1=$(sha256sum "/usr/bin/${PROJECT_NAME}-encrypt-mail" | awk -F ' ' '{print $1}')
HASH2=$(sha256sum /usr/bin/encmaildir | awk -F ' ' '{print $1}')
if [[ "$HASH1" != "$HASH2" ]]; then
cp "/usr/bin/${PROJECT_NAME}-encrypt-mail" /usr/bin/encmaildir
fi
fi
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
if [ ! -f "/home/$MY_USERNAME/README" ]; then
touch "/home/$MY_USERNAME/README"
fi
if ! grep -q $"If you have imported legacy email which is not encrypted" "/home/$MY_USERNAME/README"; then
{ echo '';
echo '';
echo $'# Encrypting legacy email';
echo $'If you have imported legacy email which is not encrypted';
echo $'then it can be encrypted with the command:';
echo '';
echo ' encmaildir';
echo '';
echo $'But be warned that depending upon how much email you have';
echo $'this could take a seriously LONG time on the Beaglebone';
echo $'and may be better done on a faster machine.'; } >> "/home/$MY_USERNAME/README"
chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/README"
chmod 600 "/home/$MY_USERNAME/README"
fi
mark_completed "${FUNCNAME[0]}"
}
function email_client {
if [ ! -d /etc/exim4 ]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
apt-get -yq install lynx abook urlview mutt
if [ ! -f /etc/Muttrc ]; then
echo $"ERROR: Mutt does not appear to have installed. $CHECK_MESSAGE"
exit 49
fi
if [ ! -d "/home/$MY_USERNAME/.mutt" ]; then
mkdir "/home/$MY_USERNAME/.mutt"
fi
echo "text/html; lynx -dump -width=78 -nolist %s | sed s/^ //; copiousoutput; needsterminal; nametemplate=%s.html" > "/home/$MY_USERNAME/.mutt/mailcap"
cp "/home/$MY_USERNAME/.mutt/mailcap" /etc/skel/.mutt
chown -R "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.mutt"
chown -R root:root /etc/skel/.mutt
{ echo 'set mbox_type=Maildir';
echo 'set folder="~/Maildir"';
echo 'set mask="!^\\.[^.]"';
echo 'set mbox="~/Maildir"';
echo 'set record="+Sent"';
echo 'set postponed="+Drafts"';
echo 'set trash="+Trash"';
echo 'set spoolfile="~/Maildir"';
echo 'auto_view text/x-vcard text/html text/enriched';
echo 'set header_cache="+.cache"';
echo 'set markers=no';
echo '';
echo '# ctrl-u to view long URLs';
echo 'macro pager \cu <pipe-entry>"urlview"<enter> "Follow links with urlview"';
echo '';
echo 'macro index S "<tag-prefix><decode-save>=.learn-spam<enter>" "move to learn-spam"';
echo 'macro pager S "<decode-save>=.learn-spam<enter>" "move to learn-spam"';
echo 'macro index H "<tag-prefix><decode-copy>=.learn-ham<enter>" "copy to learn-ham"';
echo 'macro pager H "<decode-copy>=.learn-ham<enter>" "copy to learn-ham"';
echo '';
echo '# set up the sidebar';
echo 'set sidebar_width=22';
echo 'set sidebar_visible=yes';
echo '';
echo 'set rfc2047_parameters';
echo '';
echo '# Show inbox and sent items';
echo 'mailboxes = =admin =Sent =maybe-spam =spam';
echo '';
echo '# Alter these colours as needed for maximum bling';
echo 'color sidebar_new yellow default';
echo 'color normal white default';
echo 'color hdrdefault brightcyan default';
echo 'color signature green default';
echo 'color attachment brightyellow default';
echo 'color quoted green default';
echo 'color quoted1 white default';
echo 'color tilde blue default';
echo '';
echo '# ctrl-n, ctrl-p to select next, prev folder';
echo '# ctrl-o to open selected folder';
echo 'bind index \Cp sidebar-prev';
echo 'bind index \Cn sidebar-next';
echo 'bind index \Co sidebar-open';
echo 'bind pager \Cp sidebar-prev';
echo 'bind pager \Cn sidebar-next';
echo 'bind pager \Co sidebar-open';
echo '';
echo '# ctrl-b toggles sidebar visibility';
echo "macro index,pager \\Cb '<enter-command>toggle sidebar_visible<enter><redraw-screen>' 'toggle sidebar'";
echo '';
echo '# esc-m Mark new messages as read';
echo 'macro index <esc>m "T~N<enter>;WNT~O<enter>;WO\CT~T<enter>" "mark all messages read"';
echo '';
echo '# Collapsing threads';
echo 'macro index [ "<collapse-thread>" "collapse/uncollapse thread"';
echo 'macro index ] "<collapse-all>" "collapse/uncollapse all threads"';
echo '';
echo '# threads containing new messages';
echo 'uncolor index "~(~N)"';
echo 'color index brightblue default "~(~N)"';
echo '';
echo '# new messages themselves';
echo 'uncolor index "~N"';
echo 'color index brightyellow default "~N"';
echo '';
echo '# GPG/PGP integration';
echo '# this set the number of seconds to keep in memory the passphrase used to encrypt/sign';
echo 'set pgp_timeout=1800';
echo '';
echo '# automatically sign and encrypt with PGP/MIME';
echo 'set pgp_autosign # autosign all outgoing mails';
echo 'set pgp_autoencrypt # Try to encrypt automatically';
echo 'set pgp_replyencrypt # autocrypt replies to crypted';
echo 'set pgp_replysign # autosign replies to signed';
echo 'set pgp_auto_decode=yes # decode attachments';
echo 'set fcc_clear=no # Keep encrypted copy of sent encrypted mail';
echo 'unset smime_is_default';
echo '';
echo 'set alias_file=~/.mutt-alias';
echo 'source ~/.mutt-alias';
echo 'set query_command= "abook --mutt-query \"%s\""';
echo 'macro index,pager A "<pipe-message>abook --add-email-quiet<return>" "add the sender address to abook"';
echo '';
echo '# Optional relay of SMTP via ISP';
echo '#set smtp_url="smtps://username:password@isp_mail_domain:465/"'; } > /etc/Muttrc
# For viewing long URLs
echo 'REGEXP (((http|https|ftp|gopher)|mailto)[.:][^ >"\t]*|www\.[-a-z0-9.]+)[^ .,;\t>">\):]' > "/home/$MY_USERNAME/.urlview"
echo 'COMMAND lynx -dump -width=78 -nolist %s' >> "/home/$MY_USERNAME/.urlview"
cp -f /etc/Muttrc "/home/$MY_USERNAME/.muttrc"
cp -f /etc/Muttrc /etc/skel/.muttrc
cp -f "/home/$MY_USERNAME/.urlview" /etc/skel/.urlview
touch "/home/$MY_USERNAME/.mutt-alias"
cp "/home/$MY_USERNAME/.mutt-alias" /etc/skel/.mutt-alias
chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.muttrc"
chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.mutt-alias"
# default user on generic images
if [ -d "/home/${GENERIC_IMAGE_USERNAME}" ]; then
cp -f /etc/Muttrc "/home/${GENERIC_IMAGE_USERNAME}/.muttrc"
chown "${GENERIC_IMAGE_USERNAME}":"${GENERIC_IMAGE_USERNAME}" "/home/${GENERIC_IMAGE_USERNAME}/.muttrc"
touch "/home/${GENERIC_IMAGE_USERNAME}/.mutt-alias"
chown "${GENERIC_IMAGE_USERNAME}":"${GENERIC_IMAGE_USERNAME}" "/home/${GENERIC_IMAGE_USERNAME}/.mutt-alias"
fi
mark_completed "${FUNCNAME[0]}"
}
function email_archiving {
if [ ! -d /etc/exim4 ]; then
return
fi
# ensure that the mail archive script is up to date
if [ -f "/usr/local/bin/${PROJECT_NAME}-archive-mail" ]; then
if [ ! -f /etc/cron.daily/archivemail ]; then
cp "/usr/local/bin/${PROJECT_NAME}-archive-mail" /etc/cron.daily/archivemail
chmod +x /etc/cron.daily/archivemail
else
HASH1=$(sha256sum "/usr/local/bin/${PROJECT_NAME}-archive-mail" | awk -F ' ' '{print $1}')
HASH2=$(sha256sum /etc/cron.daily/archivemail | awk -F ' ' '{print $1}')
if [[ "$HASH1" != "$HASH2" ]]; then
cp "/usr/local/bin/${PROJECT_NAME}-archive-mail" /etc/cron.daily/archivemail
chmod +x /etc/cron.daily/archivemail
fi
fi
else
if [ -f "/usr/bin/${PROJECT_NAME}-archive-mail" ]; then
if [ ! -f /etc/cron.daily/archivemail ]; then
cp "/usr/bin/${PROJECT_NAME}-archive-mail" /etc/cron.daily/archivemail
chmod +x /etc/cron.daily/archivemail
else
HASH1=$(sha256sum "/usr/local/bin/${PROJECT_NAME}-archive-mail" | awk -F ' ' '{print $1}')
HASH2=$(sha256sum /etc/cron.daily/archivemail | awk -F ' ' '{print $1}')
if [[ "$HASH1" != "$HASH2" ]]; then
cp "/usr/local/bin/${PROJECT_NAME}-archive-mail" /etc/cron.daily/archivemail
chmod +x /etc/cron.daily/archivemail
fi
fi
else
echo "/usr/bin/${PROJECT_NAME}-archive-mail was not found. ${PROJECT_NAME} might not have fully installed."
exit 62379
fi
fi
# update to the next commit
function_check set_repo_commit
set_repo_commit "$INSTALL_DIR/cleanup-maildir" "cleanup-maildir commit" "$CLEANUP_MAILDIR_COMMIT" "$CLEANUP_MAILDIR_REPO"
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
if [ ! -d "$INSTALL_DIR" ]; then
mkdir "$INSTALL_DIR"
fi
cd "$INSTALL_DIR" || exit 246824245242
function_check git_clone
git_clone "$CLEANUP_MAILDIR_REPO" "$INSTALL_DIR/cleanup-maildir"
cd "$INSTALL_DIR/cleanup-maildir" || exit 6887242572
git checkout $CLEANUP_MAILDIR_COMMIT -b $CLEANUP_MAILDIR_COMMIT
set_completion_param "cleanup-maildir commit" "$CLEANUP_MAILDIR_COMMIT"
if [ ! -f /usr/bin/cleanup-maildir ]; then
cp "$INSTALL_DIR/cleanup-maildir/cleanup-maildir" /usr/bin
else
HASH1=$(sha256sum "$INSTALL_DIR/cleanup-maildir/cleanup-maildir" | awk -F ' ' '{print $1}')
HASH2=$(sha256sum /usr/bin/cleanup-maildir | awk -F ' ' '{print $1}')
if [[ "$HASH1" != "$HASH2" ]]; then
cp "$INSTALL_DIR/cleanup-maildir/cleanup-maildir" /usr/bin
fi
fi
mark_completed "${FUNCNAME[0]}"
}
# Ensure that the from field is correct when sending email from Mutt
function email_from_address {
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
if [ ! -f "/home/$MY_USERNAME/.muttrc" ]; then
return
fi
if grep -q "set from=" "/home/$MY_USERNAME/.muttrc"; then
sed -i "s|set from=.*|set from='$MY_NAME <$MY_EMAIL_ADDRESS>'|g" "/home/$MY_USERNAME/.muttrc"
else
echo "set from='$MY_NAME <$MY_EMAIL_ADDRESS>'" >> "/home/$MY_USERNAME/.muttrc"
fi
mark_completed "${FUNCNAME[0]}"
}
function create_public_mailing_list {
if [ ! -d /etc/exim4 ]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
if [ ! "$PUBLIC_MAILING_LIST" ]; then
return
fi
# does the mailing list have a separate domain name?
if [ ! "$PUBLIC_MAILING_LIST_DOMAIN_NAME" ]; then
PUBLIC_MAILING_LIST_DOMAIN_NAME="$DEFAULT_DOMAIN_NAME"
fi
PUBLIC_MAILING_LIST_USER="mlmmj"
apt-get -yq install mlmmj
adduser --system "$PUBLIC_MAILING_LIST_USER"
addgroup "$PUBLIC_MAILING_LIST_USER"
adduser "$PUBLIC_MAILING_LIST_USER" "$PUBLIC_MAILING_LIST_USER"
echo ''
echo $"Creating the $PUBLIC_MAILING_LIST mailing list"
echo ''
# create the list
mlmmj-make-ml -a -L "$PUBLIC_MAILING_LIST" -c "$PUBLIC_MAILING_LIST_USER"
{ echo 'SYSTEM_ALIASES_PIPE_TRANSPORT = address_pipe';
echo "SYSTEM_ALIASES_USER = $PUBLIC_MAILING_LIST_USER";
echo "SYSTEM_ALIASES_GROUP = $PUBLIC_MAILING_LIST_USER"; } > /etc/exim4/conf.d/main/000_localmacros
# router
{ echo 'mlmmj_router:';
echo " debug_print = \"R: mlmmj_router for \$local_part@\$domain\"";
echo ' driver = accept';
echo ' domains = +mlmmj_domains';
echo " #require_files = MLMMJ_HOME/\${lc::\$local_part}";
echo ' # Use this instead, if you dont want to give Exim rx rights to mlmmj spool.';
echo ' # Exim will then spawn a new process running under the UID of "mlmmj".';
echo " require_files = mlmmj:MLMMJ_HOME/\${lc::\$local_part}";
echo ' local_part_suffix = +*';
echo ' local_part_suffix_optional';
echo ' headers_remove = Delivered-To';
echo " headers_add = Delivered-To: \$local_part\$local_part_suffix@\$domain";
echo ' transport = mlmmj_transport'; } > /etc/exim4/conf.d/router/750_exim4-config_mlmmj
# transport
{ echo 'mlmmj_transport:';
echo " debug_print = \"T: mlmmj_transport for \$local_part@\$domain\"";
echo ' driver = pipe';
echo ' return_path_add';
echo ' user = mlmmj';
echo ' group = mlmmj';
echo ' home_directory = MLMMJ_HOME';
echo ' current_directory = MLMMJ_HOME';
echo " command = /usr/bin/mlmmj-receive -F -L MLMMJ_HOME/\${lc:\$local_part}"; } > /etc/exim4/conf.d/transport/40_exim4-config_mlmmj
if ! grep -q "MLMMJ_HOME=/var/spool/mlmmj" /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs; then
sed -i '/MAIN CONFIGURATION SETTINGS/a\MLMMJ_HOME=/var/spool/mlmmj' /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs
fi
if ! grep -q "domainlist mlmmj_domains =" /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs; then
sed -i "/MLMMJ_HOME/a\\domainlist mlmmj_domains = $PUBLIC_MAILING_LIST_DOMAIN_NAME" /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs
fi
if ! grep -q "delay_warning_condition =" /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs; then
sed -i "/domainlist mlmmj_domains =/a\\delay_warning_condition = \${if match_domain{\$domain}{+mlmmj_domains}{no}{yes}}" /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs
fi
if ! grep -q ": +mlmmj_domains" /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs; then
sed -i 's/domainlist relay_to_domains = MAIN_RELAY_TO_DOMAINS/domainlist relay_to_domains = MAIN_RELAY_TO_DOMAINS : +mlmmj_domains/g' /etc/exim4/conf.d/main/01_exim4-config_listmacrosdefs
fi
if ! grep -q "! +mlmmj_domains" /etc/exim4/conf.d/router/200_exim4-config_primary; then
sed -i 's/domains = ! +local_domains/domains = ! +mlmmj_domains : ! +local_domains/g' /etc/exim4/conf.d/router/200_exim4-config_primary
fi
update-exim4.conf.template -r
update-exim4.conf
systemctl restart exim4
if ! grep -q $"$PUBLIC_MAILING_LIST mailing list" "/home/$MY_USERNAME/README"; then
{ echo '';
echo '';
echo $"$PUBLIC_MAILING_LIST mailing list";
echo '=================================';
echo $"To subscribe to the $PUBLIC_MAILING_LIST mailing list send a";
echo $"cleartext email to $PUBLIC_MAILING_LIST+subscribe@$DEFAULT_DOMAIN_NAME"; } >> "/home/$MY_USERNAME/README"
chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/README"
chmod 600 "/home/$MY_USERNAME/README"
fi
"${PROJECT_NAME}-addlist" -u "$MY_USERNAME" -l "$PUBLIC_MAILING_LIST" -s "$PUBLIC_MAILING_LIST"
mark_completed "${FUNCNAME[0]}"
}
function split_gpg_key_into_fragments {
# split the gpg key into fragments if social key management is enabled
if [[ "$ENABLE_SOCIAL_KEY_MANAGEMENT" == "yes" ]]; then
if [ "$IMAGE_PASSWORD_FILE" ]; then
if [ -f "$IMAGE_PASSWORD_FILE" ]; then
"${PROJECT_NAME}-splitkey" -u "$MY_USERNAME" -e "$MY_EMAIL_ADDRESS" --fullname "$MY_NAME" --passwordfile "$IMAGE_PASSWORD_FILE"
return
fi
fi
echo 'Splitting GPG key. You may need to enter your passphrase.'
"${PROJECT_NAME}-splitkey" -u "$MY_USERNAME" -e "$MY_EMAIL_ADDRESS" --fullname "$MY_NAME"
if [ ! -d "/home/$MY_USERNAME/.gnupg_fragments" ]; then
echo 'Yhe GPG key could not be split'
exit 86548
fi
fi
}
function import_email {
if [ ! -d /etc/exim4 ]; then
return
fi
EMAIL_COMPLETE_MSG=$"
*** ${PROJECT_NAME} mailbox installation is complete ***
Now on your internet router forward ports
25, 587, 465, 993 and 2222 to the ${PROJECT_NAME}
"
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
if [[ "$SYSTEM_TYPE" == "mail"* ]]; then
function_check backup_to_friends_servers
backup_to_friends_servers
function_check install_tripwire
install_tripwire
function_check split_gpg_key_into_fragments
split_gpg_key_into_fragments
clear
echo ''
echo "$EMAIL_COMPLETE_MSG"
if [ -d "$USB_MOUNT" ]; then
umount "$USB_MOUNT"
rm -rf "$USB_MOUNT"
echo $' You can now remove the USB drive'
fi
exit 0
fi
return
fi
mark_completed "${FUNCNAME[0]}"
if [[ "$SYSTEM_TYPE" == "mail"* ]]; then
function_check backup_to_friends_servers
backup_to_friends_servers
function_check install_tripwire
install_tripwire
function_check split_gpg_key_into_fragments
split_gpg_key_into_fragments
# unmount any attached usb drive
clear
echo ''
echo "$EMAIL_COMPLETE_MSG"
echo ''
if [ -d "$USB_MOUNT" ]; then
umount "$USB_MOUNT"
rm -rf "$USB_MOUNT"
echo $' You can now remove the USB drive'
fi
exit 0
fi
}
function remove_email {
echo ''
}
function install_email_basic {
apt-get -yq remove postfix
apt-get -yq install exim4 sasl2-bin swaks libnet-ssleay-perl procmail
if [ ! -d /etc/exim4 ]; then
echo $"ERROR: Exim does not appear to have installed. $CHECK_MESSAGE"
exit 48
fi
# configure for Maildir format
sed -i 's/MAIL_DIR/#MAIL_DIR/g' /etc/login.defs
sed -i 's|#MAIL_FILE.*|MAIL_FILE Maildir/|g' /etc/login.defs
if ! grep -q "export MAIL" /etc/profile; then
echo 'export MAIL=~/Maildir' >> /etc/profile
fi
sed -i 's|pam_mail.so standard|pam_mail.so dir=~/Maildir standard|g' /etc/pam.d/login
sed -i 's|pam_mail.so standard noenv|pam_mail.so dir=~/Maildir standard|g' /etc/pam.d/sshd
sed -i 's|pam_mail.so nopen|pam_mail.so dir=~/Maildir nopen|g' /etc/pam.d/su
{ echo "dc_eximconfig_configtype='internet'";
echo "dc_other_hostnames='${DEFAULT_DOMAIN_NAME};mail.${DEFAULT_DOMAIN_NAME}'";
echo "dc_local_interfaces=''";
echo "dc_readhost=''";
echo "dc_relay_domains=''";
echo "dc_minimaldns='false'"; } > /etc/exim4/update-exim4.conf.conf
IPv4_address=$(get_ipv4_address)
IPv4_address_base=$(echo "$IPv4_address" | awk -F '.' '{print $1"."$2"."$3}')
RELAY_NETS="${IPv4_address_base}.0/24"
if [ "$LOCAL_NETWORK_STATIC_IP_ADDRESS" ]; then
RELAY_NETS=$(awk "$LOCAL_NETWORK_STATIC_IP_ADDRESS" -F '.' '{print $1 "." $2 "." $3 ".0/24"}')
fi
{ echo "dc_relay_nets='$RELAY_NETS'";
echo "dc_smarthost=''";
echo "CFILEMODE='644'";
echo "dc_use_split_config='false'";
echo "dc_hide_mailname=''";
echo "dc_mailname_in_oh='true'";
echo "dc_localdelivery='maildir_home'";
echo "dc_main_log_selector=-all"; } >> /etc/exim4/update-exim4.conf.conf
echo "chunking_advertise_hosts =" > /etc/exim4/conf.d/main/04_exim4-config_chunking
update-exim4.conf
sed -i "s/START=no/START=yes/g" /etc/default/saslauthd
systemctl start saslauthd
email_install_tls
adduser "$MY_USERNAME" sasl
addgroup Debian-exim sasl
systemctl restart exim4
email_create_template
if [ -f /usr/sbin/exim ]; then
chmod u+s /usr/sbin/exim
fi
if [ -f /usr/sbin/exim4 ]; then
chmod u+s /usr/sbin/exim4
fi
function_check configure_firewall_for_email
configure_firewall_for_email
dpkg-reconfigure --frontend noninteractive exim4-config
systemctl restart exim4
}
function email_change_relay {
curr_ip_address="$1"
email_relay_base=$(echo "$curr_ip_address" | awk -F '.' '{print $1"."$2"."$3}')
RELAY_NETS="${email_relay_base}.0/24"
sed -i "s|dc_relay_nets=.*|dc_relay_nets='$RELAY_NETS'|g" /etc/exim4/update-exim4.conf.conf
dpkg-reconfigure --frontend noninteractive exim4-config
}
function create_procmail {
if [ ! -d /etc/exim4 ]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
if [ ! -f "/home/$MY_USERNAME/.procmailrc" ]; then
{ echo "MAILDIR=\$HOME/Maildir";
echo "DEFAULT=\$MAILDIR/";
echo "LOGFILE=\$HOME/log/procmail.log";
echo 'LOGABSTRACT=all';
echo '';
echo '# Test for an empty or missing subject line';
echo "SUBJ_=\$(formail -xSubject: \\";
echo " | expand | sed -e 's/^[ ]*//g' -e 's/[ ]*\$//g')";
echo ':0';
echo ' * SUBJ_ ?? ^^^^';
echo '/dev/null';
echo '';
echo $"# Tripwire reports which have no violations don't need to be logged";
echo ':0 BD:'; } > "/home/$MY_USERNAME/.procmailrc"
TRIPWIRE_VIOLATIONS_STR=$'Total violations found: 0'
{ echo " * .*$TRIPWIRE_VIOLATIONS_STR";
echo '/dev/null';
echo ''; } >> "/home/$MY_USERNAME/.procmailrc"
chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.procmailrc"
fi
mkdir -p "/home/$MY_USERNAME/Maildir/admin/new"
mkdir -p "/home/$MY_USERNAME/Maildir/admin/cur"
chown -R "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/Maildir/admin"
if [ ! -f /etc/skel/.procmailrc ]; then
cp "/home/$MY_USERNAME/.procmailrc" /etc/skel/.procmailrc
chown root:root /etc/skel/.procmailrc
fi
if [ -f /usr/bin/procmail ]; then
chmod 6755 /usr/bin/procmail
fi
mark_completed "${FUNCNAME[0]}"
}
function handle_admin_emails {
# keep emails for root in a separate folder
if [ -d "/home/$MY_USERNAME/Maildir/admin" ]; then
return
fi
"${PROJECT_NAME}-addemail" -u "$MY_USERNAME" -e "root@$DEFAULT_DOMAIN_NAME" -g admin --public no
}
function spam_filtering {
if [ ! -d /etc/exim4 ]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
apt-get -yq install exim4-daemon-heavy
apt-get -yq install spamassassin
if [ ! -f /etc/default/spamassassin ]; then
echo 'Spamassassin was not installed'
exit 72570
fi
sa-update -v
sed -i 's/ENABLED=0/ENABLED=1/g' /etc/default/spamassassin
sed -i 's/# spamd_address = 127.0.0.1 783/spamd_address = 127.0.0.1 783/g' /etc/exim4/exim4.conf.template
# This configuration is based on https://wiki.debian.org/DebianSpamAssassin
sed -i 's/local_parts = postmaster/local_parts = postmaster:abuse/g' /etc/exim4/conf.d/acl/30_exim4-config_check_rcpt
sed -i '/domains = +local_domains : +relay_to_domains/a\ set acl_m0 = rfcnames' /etc/exim4/conf.d/acl/30_exim4-config_check_rcpt
sed -i "s/accept/accept condition = \${if eq{\$acl_m0}{rfcnames} {1}{0}}/g" /etc/exim4/conf.d/acl/40_exim4-config_check_data
{ echo "warn message = X-Spam-Score: \$spam_score (\$spam_bar)";
echo ' spam = nobody:true';
echo 'warn message = X-Spam-Flag: YES';
echo ' spam = nobody';
echo "warn message = X-Spam-Report: \$spam_report";
echo ' spam = nobody';
echo '# reject spam at high scores (> 12)';
echo "deny message = This message scored \$spam_score spam points.";
echo ' spam = nobody:true';
echo " condition = \${if >{\$spam_score_int}{120}{1}{0}}"; } >> /etc/exim4/conf.d/acl/40_exim4-config_check_data
# procmail configuration
{ echo '# get spamassassin to check emails';
echo ':0fw: .spamassassin.lock';
echo ' * < 256000';
echo '| spamc';
echo '# strong spam are discarded';
echo ':0';
echo ' * ^X-Spam-Level: \*\*\*\*\*\*';
echo '/dev/null';
echo '# weak spam are kept just in case - clear this out every now and then';
echo ':0';
echo ' * ^X-Spam-Level: \*\*\*\*\*';
echo 'maybe-spam/';
echo '# otherwise, marginal spam goes here for revision';
echo ':0';
echo ' * ^X-Spam-Level: \*\*';
echo 'spam/'; } >> "/home/$MY_USERNAME/.procmailrc"
chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.procmailrc"
{ echo '# get spamassassin to check emails';
echo ':0fw: .spamassassin.lock';
echo ' * < 256000';
echo '| spamc';
echo '# strong spam are discarded';
echo ':0';
echo ' * ^X-Spam-Level: \*\*\*\*\*\*';
echo '/dev/null';
echo '# weak spam are kept just in case - clear this out every now and then';
echo ':0';
echo ' * ^X-Spam-Level: \*\*\*\*\*';
echo 'maybe-spam/';
echo '# otherwise, marginal spam goes here for revision';
echo ':0';
echo ' * ^X-Spam-Level: \*\*';
echo 'spam/'; } >> /etc/skel/.procmailrc
# filtering scripts
{ echo '#!/bin/bash';
echo 'for d in /home/*/ ; do';
echo " USERNAME=\$(echo \"\$d\" | awk -F '/' '{print \$3}')";
echo " if [[ \$USERNAME != \"git\" && $USERNAME != \"go\" && \$USERNAME != \"gogs\" && \$USERNAME != \"sync\" && \$USERNAME != \"tahoelafs\" ]]; then";
echo " MAILDIR=/home/\$USERNAME/Maildir/.learn-spam";
echo " if [ ! -d \"\$MAILDIR\" ]; then";
echo ' exit';
echo ' fi';
echo " for f in \$(ls \$MAILDIR/cur)";
echo ' do';
echo " spamc -L spam < \"\$MAILDIR/cur/\$f\" > /dev/null";
echo " rm \"\$MAILDIR/cur/\$f\"";
echo ' done';
echo " for f in \$(ls \$MAILDIR/new)";
echo ' do';
echo " spamc -L spam < \"\$MAILDIR/new/\$f\" > /dev/null";
echo " rm \"\$MAILDIR/new/\$f\"";
echo ' done';
echo ' fi';
echo 'done';
echo 'exit 0'; } > /usr/bin/filterspam
{ echo '#!/bin/bash';
echo 'for d in /home/*/ ; do';
echo " USERNAME=\$(echo \"\$d\" | awk -F '/' '{print \$3}')";
echo " if [[ \$USERNAME != \"git\" && \$USERNAME != \"go\" && \$USERNAME != \"gogs\" && \$USERNAME != \"sync\" && \$USERNAME != \"tahoelafs\" ]]; then";
echo " MAILDIR=/home/\$USERNAME/Maildir/.learn-ham";
echo " if [ ! -d \"\$MAILDIR\" ]; then";
echo ' exit';
echo ' fi';
echo " for f in \$(ls \$MAILDIR/cur)";
echo ' do';
echo " spamc -L ham < \"\$MAILDIR/cur/\$f\" > /dev/null";
echo " rm \"\$MAILDIR/cur/\$f\"";
echo ' done';
echo " for f in \$(ls \$MAILDIR/new)";
echo ' do';
echo " spamc -L ham < \"\$MAILDIR/new/\$f\" > /dev/null";
echo " rm \"\$MAILDIR/new/\$f\"";
echo ' done';
echo ' fi';
echo 'done';
echo 'exit 0'; } > /usr/bin/filterham
function_check cron_add_mins
cron_add_mins 3 '/usr/bin/timeout 120 /usr/bin/filterspam'
cron_add_mins 3 '/usr/bin/timeout 120 /usr/bin/filterham'
chmod 655 /usr/bin/filterspam /usr/bin/filterham
sed -i 's/# use_bayes 1/use_bayes 1/g' /etc/mail/spamassassin/local.cf
sed -i 's/# bayes_auto_learn 1/bayes_auto_learn 1/g' /etc/mail/spamassassin/local.cf
# user preferences
if [ ! -d "/home/$MY_USERNAME/.spamassassin" ]; then
mkdir "/home/$MY_USERNAME/.spamassassin"
{ echo $'# How many points before a mail is considered spam.';
echo '# required_score 5';
echo '';
echo $'# Whitelist and blacklist addresses are now file-glob-style patterns, so';
echo $'# "friend@somewhere.com", "*@isp.com", or "*.domain.net" will all work.';
echo '# whitelist_from someone@somewhere.com';
echo '';
echo $'# Add your own customised scores for some tests below. The default scores are';
echo $'# read from the installed spamassassin rules files, but you can override them';
echo $'# here. To see the list of tests and their default scores, go to';
echo '# http://spamassassin.apache.org/tests.html .';
echo '#';
echo '# score SYMBOLIC_TEST_NAME n.nn';
echo '';
echo $'# Speakers of Asian languages, like Chinese, Japanese and Korean, will almost';
echo $'# definitely want to uncomment the following lines. They will switch off some';
echo $'# rules that detect 8-bit characters, which commonly trigger on mails using CJK';
echo $'# character sets, or that assume a western-style charset is in use. ';
echo '# ';
echo '# score HTML_COMMENT_8BITS 0';
echo '# score UPPERCASE_25_50 0';
echo '# score UPPERCASE_50_75 0';
echo '# score UPPERCASE_75_100 0';
echo '# score OBSCURED_EMAIL 0';
echo '';
echo $'# Speakers of any language that uses non-English, accented characters may wish';
echo $'# to uncomment the following lines. They turn off rules that fire on';
echo $'# misformatted messages generated by common mail apps in contravention of the';
echo $'# email RFCs.';
echo '';
echo '# score SUBJ_ILLEGAL_CHARS 0'; } > "/home/$MY_USERNAME/.spamassassin/user_prefs"
fi
# this must be accessible by root
chown -R "$MY_USERNAME":root "/home/$MY_USERNAME/.spamassassin"
# script to keep spamassassin running
# There is a systemd script from the debian package, but it doesn't restart on failure
# and also doesn't ensure start after networking is up. If that is eventually fixed
# then this script and the cron job which runs it can be removed.
script_name=/usr/bin/run-spamassassin
{ echo '#!/bin/bash';
echo "current_state=\$(systemctl status spamassassin)";
echo "if [[ \"\$current_state\" != *\"(running)\"* ]]; then";
echo ' systemctl restart spamassassin';
echo 'fi';
echo 'exit 0'; } > $script_name
chmod +x $script_name
systemctl start spamassassin
systemctl restart exim4
systemctl restart cron
function_check cron_add_mins
cron_add_mins 10 "$script_name 2> /dev/null"
mark_completed "${FUNCNAME[0]}"
}
function configure_imap {
if [ ! -d /etc/exim4 ]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
apt-get -yq install dovecot-imapd
if [ ! -d /etc/dovecot ]; then
echo $"ERROR: Dovecot does not appear to have installed. $CHECK_MESSAGE"
exit 48
fi
if [[ "$(cert_exists dovecot)" == "0" ]]; then
"${PROJECT_NAME}-addcert" -h dovecot --dhkey "$DH_KEYLENGTH"
check_certificates dovecot
fi
chmod 600 /etc/shadow
chmod 600 /etc/gshadow
groupadd default
usermod -g default dovecot
chmod 0000 /etc/shadow
chmod 0000 /etc/gshadow
chown root:default /etc/ssl/certs/dovecot.*
chown root:default /etc/ssl/private/dovecot.*
chown root:default "/etc/ssl/certs/${DEFAULT_DOMAIN_NAME}.*"
chown root:default "/etc/ssl/private/${DEFAULT_DOMAIN_NAME}.*"
if [ ! -f /etc/dovecot/conf.d/10-ssl.conf ]; then
echo $'Unable to find /etc/dovecot/conf.d/10-ssl.conf'
exit 83629
fi
sed -i 's|#ssl =.*|ssl = no|g' /etc/dovecot/conf.d/10-ssl.conf
sed -i 's|ssl =.*|ssl = no|g' /etc/dovecot/conf.d/10-ssl.conf
sed -i "s|#ssl_cert =.*|ssl_cert = </etc/ssl/certs/dovecot.crt|g" /etc/dovecot/conf.d/10-ssl.conf
sed -i "s|ssl_cert =.*|ssl_cert = </etc/ssl/certs/dovecot.crt|g" /etc/dovecot/conf.d/10-ssl.conf
sed -i "s|#ssl_key =.*|ssl_key = </etc/ssl/private/dovecot.key|g" /etc/dovecot/conf.d/10-ssl.conf
sed -i "s|ssl_key =.*|ssl_key = </etc/ssl/private/dovecot.key|g" /etc/dovecot/conf.d/10-ssl.conf
sed -i "s|#ssl_dh_parameters_length.*|ssl_dh_parameters_length = ${DH_KEYLENGTH}|g" /etc/dovecot/conf.d/10-ssl.conf
sed -i 's/#ssl_prefer_server_ciphers.*/ssl_prefer_server_ciphers = yes/g' /etc/dovecot/conf.d/10-ssl.conf
sed -i "s|#ssl_protocols =.*|ssl_protocols = '$SSL_PROTOCOLS'|g" /etc/dovecot/conf.d/10-ssl.conf
sed -i "s|ssl_protocols =.*|ssl_protocols = '$SSL_PROTOCOLS'|g" /etc/dovecot/conf.d/10-ssl.conf
echo "ssl_cipher_list = '$SSL_CIPHERS'" >> /etc/dovecot/conf.d/10-ssl.conf
if [ ! -f /etc/dovecot/conf.d/10-master.conf ]; then
echo $'Unable to find /etc/dovecot/conf.d/10-master.conf'
exit 49259
fi
sed -i 's/#process_limit =.*/process_limit = 100/g' /etc/dovecot/conf.d/10-master.conf
if [ ! -f /etc/dovecot/conf.d/10-logging.conf ]; then
echo $'Unable to find /etc/dovecot/conf.d/10-logging.conf'
exit 48936
fi
sed -i 's/#auth_verbose.*/auth_verbose = yes/g' /etc/dovecot/conf.d/10-logging.conf
if [ ! -f /etc/dovecot/dovecot.conf ]; then
echo $'Unable to find /etc/dovecot/dovecot.conf'
exit 43890
fi
sed -i 's/#listen =.*/listen = */g' /etc/dovecot/dovecot.conf
if [ ! -f /etc/dovecot/conf.d/10-auth.conf ]; then
echo $'Unable to find /etc/dovecot/conf.d/10-auth.conf'
exit 843256
fi
sed -i 's/#disable_plaintext_auth =.*/disable_plaintext_auth = no/g' /etc/dovecot/conf.d/10-auth.conf
sed -i 's/auth_mechanisms =.*/auth_mechanisms = plain login/g' /etc/dovecot/conf.d/10-auth.conf
if [ ! -f /etc/dovecot/conf.d/10-mail.conf ]; then
echo $'Unable to find /etc/dovecot/conf.d/10-mail.conf'
exit 42036
fi
sed -i 's|mail_location =.*|mail_location = maildir:~/Maildir:LAYOUT=fs|g' /etc/dovecot/conf.d/10-mail.conf
# This long notify interval makes the system more suited for use with
# battery powered mobile devices
sed -i 's|#imap_idle_notify_interval =.*|imap_idle_notify_interval = 29|g' /etc/dovecot/conf.d/20-imap.conf
if [ -f /var/lib/dovecot/ssl-parameters.dat ]; then
rm /var/lib/dovecot/ssl-parameters.dat
fi
if [ -f /etc/systemd/system/sockets.target.wants/dovecot.socket ]; then
rm /etc/systemd/system/sockets.target.wants/dovecot.socket
fi
# Separate logging, otherwise syslog is used
if ! grep -q "# logging" /etc/dovecot/dovecot.conf; then
{ echo '';
echo '# logging';
echo 'log_path = /var/log/dovecot.log';
echo 'info_log_path = /var/log/dovecot-info.log';
echo 'debug_log_path = /var/log/dovecot-debug.log'; } >> /etc/dovecot/dovecot.conf
fi
systemctl restart dovecot
mark_completed "${FUNCNAME[0]}"
}
function configure_imap_client_certs {
if [ ! -d /etc/exim4 ]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
# http://strange.systems/certificate-based-auth-with-dovecot-sendmail/
sed -i 's|#default_process_limit =.*|default_process_limit = 100|g' /etc/dovecot/conf.d/10-master.conf
sed -i 's/disable_plaintext_auth =.*/disable_plaintext_auth = yes/g' /etc/dovecot/conf.d/10-auth.conf
sed -i 's|#auth_ssl_require_client_cert =.*|auth_ssl_require_client_cert = yes|g' /etc/dovecot/conf.d/10-auth.conf
sed -i 's|#auth_ssl_username_from_cert =.*|auth_ssl_username_from_cert = yes|g' /etc/dovecot/conf.d/10-auth.conf
sed -i "s|#ssl_ca =.*|ssl_ca = /etc/ssl/certs/ca-$DEFAULT_DOMAIN_NAME.crt|g" /etc/dovecot/conf.d/10-ssl.conf
sed -i 's|#ssl_cert_username_field =.*|ssl_cert_username_field = commonName|g' /etc/dovecot/conf.d/10-ssl.conf
sed -i 's|#ssl_verify_client_cert =.*|ssl_verify_client_cert = yes|g' /etc/dovecot/conf.d/10-ssl.conf
if ! grep -q "passdb {" /etc/dovecot/conf.d/10-auth.conf; then
{ echo '';
echo 'passdb {';
echo ' driver = passwd-file';
echo ' args = /etc/dovecot/passwd-file';
echo ' deny = no';
echo ' master = no';
echo ' pass = no';
echo '}'; } >> /etc/dovecot/conf.d/10-auth.conf
fi
if [[ "$ONION_ONLY" == "no" ]]; then
# make a CA cert
if [ ! -f "/etc/ssl/private/ca-$DEFAULT_DOMAIN_NAME.key" ]; then
if [[ "$LETSENCRYPT_ENABLED" != "yes" ]]; then
"${PROJECT_NAME}-addcert" -h "$DEFAULT_DOMAIN_NAME" --ca "" --dhkey "$DH_KEYLENGTH"
else
"${PROJECT_NAME}-addcert" -e "$DEFAULT_DOMAIN_NAME" -s "$LETSENCRYPT_SERVER" --ca "" --dhkey "$DH_KEYLENGTH" --email "$MY_EMAIL_ADDRESS"
fi
fi
fi
# CA configuration
{ echo '[ ca ]';
echo "default_ca = dovecot-ca";
echo '';
echo '[ crl_ext ]';
echo 'authorityKeyIdentifier=keyid:always';
echo '';
echo '[ dovecot-ca ]';
echo 'new_certs_dir = .';
echo 'unique_subject = no';
echo "certificate = /etc/ssl/certs/ca-$DEFAULT_DOMAIN_NAME.crt";
echo 'database = ssldb';
echo "private_key = /etc/ssl/private/ca-$DEFAULT_DOMAIN_NAME.key";
echo 'serial = sslserial';
echo 'default_days = 3650';
echo 'default_md = sha256';
echo 'default_bits = 2048';
echo 'policy = dovecot-ca_policy';
echo 'x509_extensions = dovecot-ca_extensions';
echo '';
echo '[ dovecot-ca_policy ]';
echo 'commonName = supplied';
echo 'stateOrProvinceName = supplied';
echo 'countryName = supplied';
echo 'emailAddress = optional';
echo 'organizationName = supplied';
echo 'organizationalUnitName = optional';
echo '';
echo '[ dovecot-ca_extensions ]';
echo 'basicConstraints = CA:false';
echo 'subjectKeyIdentifier = hash';
echo 'authorityKeyIdentifier = keyid:always';
echo 'keyUsage = digitalSignature,keyEncipherment';
echo 'extendedKeyUsage = clientAuth'; } > /etc/ssl/dovecot-ca.cnf
if [ -f /etc/ssl/ssldb ]; then
rm /etc/ssl/ssldb
fi
if [ -f /etc/ssl/sslserial ]; then
rm /etc/ssl/sslserial
fi
touch /etc/ssl/ssldb
echo 0001 > /etc/ssl/sslserial
#${PROJECT_NAME}-clientcert -u $MY_USERNAME
systemctl restart dovecot
mark_completed "${FUNCNAME[0]}"
}
function create_gpg_subkey {
# Note: currently not used
if [ ! -d /etc/exim4 ]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
apt-get -yq install gnupg
GPG_KEY_USAGE=$1
if [[ "$GPG_KEY_USAGE" != "sign" && "$GPG_KEY_USAGE" != "auth" && "$GPG_KEY_USAGE" != "encrypt" ]]; then
echo $"Unknown subkey usage: $GPG_KEY_USAGE"
echo $'Available types: sign|auth|encrypt'
exit 14783
fi
KEYGRIP=$(gpg --fingerprint --fingerprint "$MY_EMAIL_ADDRESS" | grep fingerprint | tail -1 | cut -d= -f2 | sed -e 's/ //g')
# Generate a GPG subkey
{ echo 'Key-Type: eddsa';
echo 'Key-Curve: Ed25519';
echo "Key-Grip: $KEYGRIP";
echo 'Subkey-Type: eddsa';
echo "subkey-Usage: $GPG_KEY_USAGE";
echo "Name-Real: $MY_NAME";
echo "Name-Email: $MY_EMAIL_ADDRESS";
echo "Name-Comment: $GPG_KEY_USAGE";
echo 'Expire-Date: 0';
echo "Passphrase: $PROJECT_NAME"; } > "/home/$MY_USERNAME/gpg-genkey.conf"
chown "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/gpg-genkey.conf"
su -m root -c "gpg --homedir /home/$MY_USERNAME/.gnupg --batch --full-gen-key /home/$MY_USERNAME/gpg-genkey.conf" - "$MY_USERNAME"
chown -R "$MY_USERNAME":"$MY_USERNAME" "/home/$MY_USERNAME/.gnupg"
shred -zu "/home/$MY_USERNAME/gpg-genkey.conf"
# shellcheck disable=SC2034
MY_GPG_SUBKEY_ID=$(gpg_pubkey_from_email "$MY_USERNAME" "$MY_EMAIL_ADDRESS")
mark_completed "${FUNCNAME[0]}"
}
function gpg_key_exists {
key_owner_username="$1"
key_search_text="$2"
if [[ $key_owner_username != "root" ]]; then
KEY_EXISTS=$(su -c "gpg --list-keys \"${key_search_text}\"" - "$key_owner_username")
else
KEY_EXISTS=$(gpg --list-keys "${key_search_text}")
fi
if [ ! "$KEY_EXISTS" ]; then
echo "no"
return
fi
if [[ "$KEY_EXISTS" == *"error"* ]]; then
echo "no"
return
fi
echo "yes"
}
function configure_gpg {
if [ ! -d /etc/exim4 ]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
apt-get -yq install gnupg dirmngr
printf '%%Assuan%%\nsocket=/dev/shm/S.dirmngr\n' > ~/.gnupg/S.dirmngr
check_email_address_exists
gpg_dir="/home/$MY_USERNAME/.gnupg"
# if gpg keys directory was previously imported from usb
if [ -d "$gpg_dir" ]; then
echo $'GPG directory exists'
else
echo $"GPG directory $gpg_dir was not found"
fi
if [ -d "$gpg_dir" ]; then
echo $'GPG keys were imported'
sed -i "s|keyserver hkp://keys.gnupg.net|keyserver $GPG_KEYSERVER|g" "$gpg_dir/gpg.conf"
MY_GPG_PUBLIC_KEY_ID=$(gpg_pubkey_from_email "$MY_USERNAME" "$MY_EMAIL_ADDRESS")
if [ ${#MY_GPG_PUBLIC_KEY_ID} -lt 4 ]; then
echo $'GPG public key ID could not be obtained'
else
if [[ "$MY_GPG_PUBLIC_KEY_ID" == *'error'* ]]; then
echo $"Can't locate gpg key"
else
chown -R "$MY_USERNAME":"$MY_USERNAME" "$gpg_dir"
chmod 700 "$gpg_dir"
chmod 600 "$gpg_dir/*"
printf '%%Assuan%%\nsocket=/dev/shm/S.dirmngr\n' > "/home/$MY_USERNAME/.gnupg/S.dirmngr"
if [ -d "/home/$MY_USERNAME/.gnupg/crls.d" ]; then
chmod +x "/home/$MY_USERNAME/.gnupg/crls.d"
fi
mark_completed "${FUNCNAME[0]}"
return
fi
fi
fi
if [ ! -d "$gpg_dir" ]; then
mkdir "$gpg_dir"
echo "keyserver $GPG_KEYSERVER" >> "$gpg_dir/gpg.conf"
echo 'keyserver-options auto-key-retrieve' >> "$gpg_dir/gpg.conf"
fi
sed -i "s|keyserver hkp://keys.gnupg.net|keyserver $GPG_KEYSERVER|g" "$gpg_dir/gpg.conf"
gpg_agent_setup root
gpg_agent_setup "$MY_USERNAME"
if ! grep -q "# default preferences" "$gpg_dir/gpg.conf"; then
{ echo '';
echo '# default preferences';
echo 'personal-digest-preferences SHA256';
echo 'cert-digest-algo SHA256';
echo 'default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed'; } >> "$gpg_dir/gpg.conf"
fi
chown -R "$MY_USERNAME":"$MY_USERNAME" "$gpg_dir"
chmod 700 "$gpg_dir"
chmod 600 "$gpg_dir/*"
printf '%%Assuan%%\nsocket=/dev/shm/S.dirmngr\n' > "$gpg_dir/S.dirmngr"
if [ -d "$gpg_dir/crls.d" ]; then
chmod +x "$gpg_dir/crls.d"
fi
if [[ "$MY_GPG_PUBLIC_KEY" && "$MY_GPG_PRIVATE_KEY" ]]; then
echo $'Importing GPG keys from file'
echo $"Public key: $MY_GPG_PUBLIC_KEY"
echo $"Private key: $MY_GPG_PRIVATE_KEY"
# use your existing GPG keys which were exported
if [ ! -f $MY_GPG_PUBLIC_KEY ]; then
echo $"GPG public key file $MY_GPG_PUBLIC_KEY was not found"
exit 2483
fi
if [ ! -f $MY_GPG_PRIVATE_KEY ]; then
echo $"GPG private key file $MY_GPG_PRIVATE_KEY was not found"
exit 5383
fi
gpg_import_public_key "$MY_USERNAME" "$MY_GPG_PUBLIC_KEY"
gpg_import_private_key "$MY_USERNAME" "$MY_GPG_PRIVATE_KEY"
KEY_EXISTS=$(gpg_key_exists "$MY_USERNAME" "$MY_EMAIL_ADDRESS")
if [[ $KEY_EXISTS == "no" ]]; then
echo $"The GPG key for $MY_EMAIL_ADDRESS could not be imported"
exit 13821
fi
# for security ensure that the private key file doesn't linger around
shred -zu $MY_GPG_PRIVATE_KEY
MY_GPG_PUBLIC_KEY_ID=$(gpg_pubkey_from_email "$MY_USERNAME" "$MY_EMAIL_ADDRESS")
if [ ${#MY_GPG_PUBLIC_KEY_ID} -lt 4 ]; then
echo $'GPG public key ID could not be obtained'
fi
else
# Generate a GPG key
if [ -f "$IMAGE_PASSWORD_FILE" ]; then
gpg_create_key "$MY_USERNAME" "$(printf "%s" "$(cat "$IMAGE_PASSWORD_FILE")")"
else
gpg_create_key "$MY_USERNAME" "$PROJECT_NAME"
fi
MY_GPG_PUBLIC_KEY_ID=$(gpg_pubkey_from_email "$MY_USERNAME" "$MY_EMAIL_ADDRESS")
MY_GPG_PUBLIC_KEY=/tmp/public_key.gpg
gpg_export_public_key "$MY_USERNAME" "$MY_GPG_PUBLIC_KEY_ID" "$MY_GPG_PUBLIC_KEY"
fi
if [ ! -d /root/.gnupg ]; then
cp -r "/home/$MY_USERNAME/.gnupg" /root/
chmod 700 /root/.gnupg
chmod 600 /root/.gnupg/*
printf '%%Assuan%%\nsocket=/dev/shm/S.dirmngr\n' > /root/.gnupg/S.dirmngr
if [ -d /root/.gnupg/crls.d ]; then
chmod +x /root/.gnupg/crls.d
fi
fi
mark_completed "${FUNCNAME[0]}"
}
function refresh_gpg_keys {
REFRESH_GPG_KEYS_SCRIPT=/tmp/update-gpg-keys
{ echo '#!/bin/bash';
echo "if [ -f /usr/local/bin/${PROJECT_NAME}-sec ]; then";
echo " /usr/bin/timeout 600 /usr/local/bin/${PROJECT_NAME}-sec --refresh yes";
echo 'else';
echo " /usr/bin/timeout 600 /usr/bin/${PROJECT_NAME}-sec --refresh yes";
echo 'fi';
echo 'exit 0'; } > "$REFRESH_GPG_KEYS_SCRIPT"
chmod +x "$REFRESH_GPG_KEYS_SCRIPT"
if [ ! -f /usr/bin/update-gpg-keys ]; then
cp "$REFRESH_GPG_KEYS_SCRIPT" /usr/bin/update-gpg-keys
else
HASH1=$(sha256sum "$REFRESH_GPG_KEYS_SCRIPT" | awk -F ' ' '{print $1}')
HASH2=$(sha256sum /usr/bin/update-gpg-keys | awk -F ' ' '{print $1}')
if [[ "$HASH1" != "$HASH2" ]]; then
cp $REFRESH_GPG_KEYS_SCRIPT /usr/bin/update-gpg-keys
fi
rm $REFRESH_GPG_KEYS_SCRIPT
fi
REFRESH_GPG_KEYS_SCRIPT=/usr/bin/update-gpg-keys
if grep -q "${PROJECT_NAME}-sec" /etc/crontab; then
sed -i "/${PROJECT_NAME}-sec /d" /etc/crontab
fi
if ! grep -q "$REFRESH_GPG_KEYS_SCRIPT" /etc/crontab; then
GPG_REFRESH_TIME=$(( RANDOM % 60 ))
echo "$GPG_REFRESH_TIME */$REFRESH_GPG_KEYS_HOURS * * * root cronic $REFRESH_GPG_KEYS_SCRIPT" >> /etc/crontab
systemctl restart cron
else
if ! grep "root cronic $REFRESH_GPG_KEYS_SCRIPT" /etc/crontab; then
sed -i "s|root $REFRESH_GPG_KEYS_SCRIPT.*|root cronic $REFRESH_GPG_KEYS_SCRIPT|g" /etc/crontab
fi
fi
}
function install_email {
if [[ $SYSTEM_TYPE == "mesh"* ]]; then
return
fi
if [[ $(is_completed "${FUNCNAME[0]}") == "1" ]]; then
return
fi
check_email_address_exists
install_email_basic
configure_email_onion
mark_completed "${FUNCNAME[0]}"
}
# NOTE: deliberately no exit 0