403 lines
10 KiB
Bash
Executable File
403 lines
10 KiB
Bash
Executable File
#!/bin/sh
|
||
|
||
set -u
|
||
|
||
# Display usage
|
||
usage ()
|
||
{
|
||
local - progname
|
||
progname=$1
|
||
echo "Usage :"
|
||
echo
|
||
echo "$progname emailaccount [emailalias]"
|
||
echo "$progname -h | --help"
|
||
echo
|
||
echo "Fist form add an email account named emailaccount if it doesn't already exist"
|
||
echo "and create an alias named emailalias for this email account if specified"
|
||
echo
|
||
echo "Second and third form print this help"
|
||
}
|
||
|
||
# Test an email is valid and exit if it isn't
|
||
test_email ()
|
||
{
|
||
local -
|
||
user=$(echo "$1" | cut -d '@' -f 1)
|
||
if [ -z "$user" ]
|
||
then
|
||
echo "Missing user in email account"
|
||
exit 1
|
||
fi
|
||
domain=$(echo "$1" | cut -d '@' -f 2)
|
||
if echo "$domain" | grep -E -v "^([[:alnum:]]+\.)+[[:alnum:]]+$" > /dev/null
|
||
then
|
||
echo "Invalid domain for email account"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
ask_user_default_no ()
|
||
{
|
||
local - answer
|
||
answer="unset"
|
||
echo -n "$1 [y/N] "
|
||
while [ -n "$answer" -a "$answer" != "y" -a "$answer" != "Y" -a "$answer" != "n" -a "$answer" != "N" ]
|
||
do
|
||
read answer
|
||
if [ -z "$answer" -o "$answer" = "n" -o "$answer" = "N" ]
|
||
then
|
||
return 1
|
||
fi
|
||
if [ "$answer" = "y" -o "$answer" = "Y" ]
|
||
then
|
||
break
|
||
fi
|
||
echo -n "$2 [y/N] "
|
||
done
|
||
return 0
|
||
}
|
||
|
||
# Test number of argument is correct and their value are correct also
|
||
test_args ()
|
||
{
|
||
local - user domain first_ask next_ask
|
||
if [ \( $# -ge 1 -a "$1" = "-h" -a $# -gt 1 \) -o $# -gt 2 ]
|
||
then
|
||
echo "Too many arguments"
|
||
exit 1
|
||
fi
|
||
if [ $# -eq 0 -o "$1" = "-h" -o "$1" = "-help" ]
|
||
then
|
||
usage $(basename $0)
|
||
exit 0
|
||
else
|
||
# Test email arguments
|
||
test_email "$1"
|
||
emailuser="$user"
|
||
emaildomain="$domain"
|
||
if [ $# -eq 2 ]
|
||
then
|
||
test_email "$2"
|
||
aliasuser="$user"
|
||
aliasdomain="$domain"
|
||
if [ "$emaildomain" != "$aliasdomain" ]
|
||
then
|
||
echo "Domain of the alias must be identical to the domain of the email account"
|
||
exit 1
|
||
fi
|
||
fi
|
||
fi
|
||
first_ask="Be aware that you'll need to restart cyrus twice and postfix once. Are you ready ?"
|
||
next_ask="Incorrect answer. Are you ready to restart cyrus and postfix ?"
|
||
ask_user_default_no "$first_ask" "$next_ask"
|
||
if [ $? -eq 1 ]
|
||
then
|
||
echo "Ok, exiting_"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# Are we root ?
|
||
must_sudo ()
|
||
{
|
||
uid="$(id -u)"
|
||
[ ! $uid -eq 0 ]
|
||
return $?
|
||
}
|
||
|
||
# This function try to become root with sudo and execute this script
|
||
# NB: This function doesn't return
|
||
try_sudo ()
|
||
{
|
||
local - ret
|
||
echo "You aren't root. Trying to use sudo to become root…"
|
||
sudo $0 "$@"
|
||
ret=$?
|
||
if [ ! $ret -eq 0 ]
|
||
then
|
||
echo "You must be root or being able to become root by sudo without password to create an email account or add an email alias"
|
||
fi
|
||
exit $ret
|
||
}
|
||
|
||
# Test cyrus password is ok
|
||
test_cyrus_admin ()
|
||
{
|
||
local -
|
||
cyruser=$(grep -E "^[[:space:]]*admins:" /etc/imapd.conf | cut -d ':' -f 2- | sed -r "s/[[:alnum:]]+@[[:alnum:].]+//g" | tr -d ' ')
|
||
cyrpwd=$(cat /root/cyrus_main_admin_password)
|
||
testsaslauthd -u $cyruser -p $cyrpwd > /dev/null || { echo "Password for main cyrus admin has changed but has not been modified in /root/" && exit 1 ; }
|
||
}
|
||
|
||
# Save cyrus state and make it cyradm ready, that is save and change
|
||
# allowplaintext and virtdomain and make it listen on localhost:imap
|
||
# instead of *:imap
|
||
save_cyrus_state_and_become_cyradm_ready ()
|
||
{
|
||
local -
|
||
sed -r -i "s/^(.*cmd=\"imapd.* listen=\")(imap\".*)$/\1localhost:\2/" /etc/cyrus.conf
|
||
sed -r -i "s/^([[:space:]]*allowplaintext:.*)$/#\1\nallowplaintext: 1/" /etc/imapd.conf
|
||
sed -r -i "s/^([[:space:]]*virtdomains:.*)$/#\1\nvirtdomains: userid/" /etc/imapd.conf
|
||
invoke-rc.d cyrus2.2 restart
|
||
if [ ! $? -eq 0 ]
|
||
then
|
||
echo "Restarting cyrus failed. The requested action coudn't be performed."
|
||
echo "Look at the logs and restart Cyrus manually."
|
||
return 1
|
||
fi
|
||
return 0
|
||
}
|
||
|
||
# Ask a password to the user and create the entry in sasldb database
|
||
ask_and_create_password ()
|
||
{
|
||
local - newemailpassword
|
||
emailpassword=""
|
||
newemailpassword="different"
|
||
while [ "$emailpassword" != "$newemailpassword" ]
|
||
do
|
||
emailpassword=""
|
||
echo "What password do you want for your email account ?"
|
||
while [ -z "$emailpassword" ]
|
||
do
|
||
echo -n "Password : "
|
||
read emailpassword
|
||
done
|
||
newemailpassword=""
|
||
echo "Re-enter your password to ensure you type it in correctly"
|
||
while [ -z "$newemailpassword" ]
|
||
do
|
||
echo -n "Password (bis) : "
|
||
read newemailpassword
|
||
done
|
||
if [ "$emailpassword" != "$newemailpassword" ]
|
||
then
|
||
echo "Password don't match"
|
||
fi
|
||
done
|
||
echo "$emailpassword" | saslpasswd2 -p -u "$emaildomain" "$emailuser"
|
||
}
|
||
|
||
# Check if a password already exist in the sasldb database.
|
||
# Then ask a password to the user and create the entry in sasldb
|
||
# database if password doesn't exist are user want to change it
|
||
create_sasldb_password ()
|
||
{
|
||
local - first_ask next_ask
|
||
sasldblistusers2 | grep "$emailuser@$emaildomain" > /dev/null
|
||
if [ $? -eq 0 ]
|
||
then
|
||
first_ask="There is already a password for this user, do you want to change it ?"
|
||
next_ask="Do you want to change the existing password for your email account ?"
|
||
ask_user_default_no "$first_ask" "$next_ask"
|
||
if [ $? -eq 0 ]
|
||
then
|
||
ask_and_create_password
|
||
else
|
||
emailpassword="has remained unchanged"
|
||
fi
|
||
else
|
||
ask_and_create_password
|
||
fi
|
||
}
|
||
|
||
# Add the domain of the email account to the list of virtual domain
|
||
# in cyrus and postfix if necessary
|
||
update_virtual_domains ()
|
||
{
|
||
local -
|
||
grep "defaultdomain:" /etc/imapd.conf | grep "$emaildomain" > /dev/null
|
||
if [ ! $? -eq 0 ]
|
||
then
|
||
grep "loginrealms:" /etc/imapd.conf | grep "$emaildomain" > /dev/null
|
||
if [ ! $? -eq 0 ]
|
||
then
|
||
sed -r -i "s/^([[:space:]]*loginrealms): ?(.*)$/\1: $emaildomain \2/" /etc/imapd.conf
|
||
fi
|
||
fi
|
||
grep "mydomain[[:space:]]*=" /etc/postfix/main.cf | grep "$emaildomain" > /dev/null
|
||
if [ ! $? -eq 0 ]
|
||
then
|
||
grep "virtual_mailbox_domains[[:space:]]*=" /etc/postfix/main.cf | grep "$emaildomain" /dev/null
|
||
if [ ! $? -eq 0 ]
|
||
then
|
||
sed -r -i "s/^([[:space:]]*virtual_mailbox_domains[[:space:]]*)= ?(.*)$/\1= $emaildomain \2/" /etc/postfix/main.cf
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# Print the first parameter and then the second parameter at a distance
|
||
# of $3 tabs
|
||
echo_with_tabs ()
|
||
{
|
||
local - nbchars nbtabs
|
||
nbchars=$(echo "$1" | wc -m)
|
||
nbtabs=$(($3-nbchars/8))
|
||
[ $nbtabs -lt 1 ] && nbtabs=1
|
||
echo -n "$1"
|
||
for i in $(seq $nbtabs)
|
||
do
|
||
echo -n "\t"
|
||
done
|
||
echo "$2"
|
||
}
|
||
|
||
# Add requested email to postfix virtual_mailbox_maps
|
||
update_postfix_email_account ()
|
||
{
|
||
local -
|
||
grep "^[[:space:]]*$emailuser@$emaildomain" /etc/postfix/vmailbox > /dev/null
|
||
if [ ! $? -eq 0 ]
|
||
then
|
||
echo_with_tabs "$emailuser@$emaildomain" "whatever" 4 >> /etc/postfix/vmailbox
|
||
fi
|
||
if [ ! $# -eq 0 ]
|
||
then
|
||
grep "^[[:space:]]*$aliasuser@$aliasdomain" /etc/postfix/vmailbox > /dev/null
|
||
if [ ! $? -eq 0 ]
|
||
then
|
||
echo_with_tabs "$aliasuser@$aliasdomain" "whatever" 4 >> /etc/postfix/vmailbox
|
||
fi
|
||
fi
|
||
postmap /etc/postfix/vmailbox
|
||
}
|
||
|
||
# Add requested alias to postfix virtual_alias_maps
|
||
update_email_aliases ()
|
||
{
|
||
local -
|
||
grep "$aliasuser@$aliasdomain[[:space:]]+$emailuser@$emaildomain" /etc/postfix/virtual > /dev/null
|
||
if [ ! $? -eq 0 ]
|
||
then
|
||
echo_with_tabs "$aliasuser@$aliasdomain" "$emailuser@$emaildomain" 4 >> /etc/postfix/virtual
|
||
fi
|
||
postmap /etc/postfix/virtual
|
||
}
|
||
|
||
display_infos ()
|
||
{
|
||
local - imap imaps imapret imapsret security
|
||
set +u
|
||
grep "defaultdomain:" /etc/imapd.conf | grep "$emaildomain" > /dev/null
|
||
if [ $? -eq 0 ]
|
||
then
|
||
echo "Your email login is $emailuser and your password $emailpassword"
|
||
else
|
||
echo "Your email login is $emailuser@$emaildomain and your password $emailpassword"
|
||
fi
|
||
echo -n "supported mechanism for imap authentification are : "
|
||
sed -r -n "{s/sasl_mech_list: *(.*)$/\1/;t success;T;: success;p}" /etc/imapd.conf
|
||
echo -n "The imap server listen on port "
|
||
imap=$(grep -E "^[^#]+cmd=\"imapd[^#]+listen=\"imap\"" /etc/cyrus.conf)
|
||
imapret=$?
|
||
if [ $imapret -eq 0 ]
|
||
then
|
||
security=$(echo "$imap" | sed -r -n "{s/^.*cmd=\".* -s.*$/(SSL\/TLS)/;t success;T;: success;p}")
|
||
if [ -z "$security" ]
|
||
then
|
||
security="(STARTTLS)"
|
||
fi
|
||
echo -n "143 ($security)"
|
||
fi
|
||
imaps=$(grep -E "^[^#]+cmd=\"imapd[^#]+listen=\"imaps\"" /etc/cyrus.conf)
|
||
imapsret=$?
|
||
if [ $imapsret -eq 0 ]
|
||
then
|
||
security=$(echo "$imaps" | sed -r -n "{s/^.*cmd=\".* -s.*$/(SSL\/TLS)/;t success;T;: success;p}")
|
||
if [ -z "$security" ]
|
||
then
|
||
security="(STARTTLS)"
|
||
fi
|
||
if [ $imapret -eq 0 ]
|
||
then
|
||
echo -n " and on port "
|
||
fi
|
||
echo -n "993 ($security)"
|
||
fi
|
||
echo
|
||
}
|
||
|
||
# Restore cyrus state as it was before making it cyradm ready, that is
|
||
# restore allowplaintext, virtdomain and make it listen on *:imap
|
||
# instead of localhost:imap
|
||
restore_cyrus_state ()
|
||
{
|
||
local -
|
||
sed -r -i "s/^(.*cmd=\"imapd.* listen=\")localhost:(imap\".*)$/\1\2/" /etc/cyrus.conf
|
||
# Ok let's explain that sed line
|
||
# First you must understand that for each line all the commands inside
|
||
# the {} block and separated by ; are executed
|
||
# When the allowplaintext commented line is found, the # is removed by
|
||
# a s/pattern/replacement/ command. Then, as this substitution is
|
||
# successful, we jump at success which copy the substituted line in
|
||
# the hold space, get the next line in the pattern space and replace
|
||
# it by the substituted line. We've just deleted the next line. Then,
|
||
# we print the line in the pattern space. If from the beginning we
|
||
# have a non allowplaintext line, then T makes us jump to fail and
|
||
# print the line in the pattern space (that is the current line)
|
||
sed -r -n -i "{s/^#([[:space:]]*allowplaintext:.*)$/\1/;t success;T fail;: success;h;n;g;: fail;p}" /etc/imapd.conf
|
||
# Same as for allowplaintext above
|
||
sed -r -n -i "{s/^#([[:space:]]*virtdomains:.*)$/\1/;t success;T fail;: success;h;n;g;: fail;p}" /etc/imapd.conf
|
||
invoke-rc.d --quiet cyrus2.2 restart
|
||
if [ ! $? -eq 0 ]
|
||
then
|
||
echo "Restarting cyrus failed"
|
||
exit 1
|
||
fi
|
||
invoke-rc.d --quiet postfix reload
|
||
if [ ! $? -eq 0 ]
|
||
then
|
||
echo "Reloading postfix failed"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# Create the mailbox
|
||
create_mail_account ()
|
||
{
|
||
local - nblines
|
||
nblines=$(echo "listmailbox user.$emailuser@$emaildomain" | cyradm --user $cyruser --auth login --pass $cyrpwd localhost | wc -l)
|
||
if [ $nblines -eq 0 ]
|
||
then
|
||
echo "Mailbox for $emailuser@$emaildomain doesn't exist, creating it…"
|
||
echo "createmailbox user.$emailuser@$emaildomain" | cyradm --user $cyruser --auth login --pass $cyrpwd localhost
|
||
fi
|
||
|
||
}
|
||
|
||
main ()
|
||
{
|
||
ret=0
|
||
# This test should be useless if rights on this file are corrects
|
||
# (that is 770 for root:gt owner)
|
||
test_args "$@"
|
||
if must_sudo
|
||
then
|
||
try_sudo "$@"
|
||
fi
|
||
test_cyrus_admin
|
||
save_cyrus_state_and_become_cyradm_ready
|
||
if [ $? -eq 0 ]
|
||
then
|
||
create_sasldb_password
|
||
update_virtual_domains
|
||
aliasuser="${aliasuser:-""}"
|
||
if [ -n "$aliasuser" ]
|
||
then
|
||
update_postfix_email_account 1
|
||
update_email_aliases
|
||
else
|
||
update_postfix_email_account
|
||
fi
|
||
create_mail_account
|
||
display_infos
|
||
else
|
||
ret=1
|
||
fi
|
||
restore_cyrus_state
|
||
return $ret
|
||
}
|
||
|
||
main "$@"
|
||
exit $?
|