#!/usr/bin/env bash ## -------------------------------------- ## - ## - Add mailboxes read from a flat file ## - ## -------------------------------------- script_dir="$(dirname $(realpath $0))" log_dir="${script_dir}/log" conf_dir="${script_dir}/conf" file_dir="${script_dir}/files" conf_file="${conf_dir}/postfix_add_mailboxes.conf" tmp_err_msg="$(mktemp)" ## --- Default Settings ## --- DEFAULT_db_type="pgsql" DEFAULT_db_name="postfix" DEFAULT_quota="536870912" DEFAULT_dovecot_enc_method="SHA512-CRYPT" DEFAULT_in_file="${file_dir}/mailboxes_new.lst" DEFAULT_log_file="${script_dir}/log/postfix_add_mailboxes.log" ## --- some functions ## --- clean_up() { # Perform program exit housekeeping rm -f $tmp_err_msg exit $1 } echononl(){ echo X\\c > /tmp/shprompt$$ if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then echo -e -n "$*\\c" 1>&2 else echo -e -n "$*" 1>&2 fi rm /tmp/shprompt$$ } fatal(){ echo "" echo -e "[ \033[31m\033[1mError\033[m ]: $*" echo "" echo -e " \033[31m\033[1mInstalllation is canceled\033[m\033[m" echo "" clean_up 1 } warn (){ echo "" echo -e "\t[ \033[33m\033[1mWarning\033[m ]: $*" echo "" } info (){ echo "" echo -e "\t[ \033[33m\033[1mInfo\033[m ]: $*" echo "" } ok (){ echo "" echo -e "\t[ \033[36m\033[1mOk\033[m ]: $*" echo "" } error(){ echo "" echo -e "\t[ \033[31m\033[1mFehler\033[m ]: $*" echo "" } echo_ok() { echo -e "\033[75G[ \033[32mok\033[m ]" } echo_failed(){ echo -e "\033[75G[ \033[1;31mfailed\033[m ]" } echo_skipped() { echo -e "\033[75G[ \033[33m\033[1mskipped\033[m ]" } ## - remove leading/trailling whitespaces ## - trim() { local var="$*" var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters echo -n "$var" } ## --- ## --- END: functions date_suffix="`date +%Y%m%d-%H%M`" echo "" echo "" echononl " Loading default Configuration values from $(basename ${conf_file}).." if [[ ! -f "$conf_file" ]]; then echo_skipped else source "${conf_file}" > /dev/null 2>&1 if [[ $? -eq 0 ]]; then echo_ok else echo_failed fi fi [[ -n "$db_type" ]] || db_type="$DEFAULT_db_type" if [[ "$db_type" != "pgsql" ]] && [[ "$db_type" != "mysql" ]]; then fatal "Unknown Database Type '$db_type' for Password Database (Parameter db_type)" fi if [[ "$db_type" = "mysql" ]]; then if [[ -z "$mysql_credential_args" ]]; then if [[ -f "/etc/mysql/debian.cnf" ]]; then mysql_credential_args="--defaults-file=/etc/mysql/debian.cnf" elif [[ -f "/usr/local/mysql/sys-maint.cnf" ]] ; then mysql_credential_args="--defaults-file=/usr/local/mysql/sys-maint.cnf" else fatal "No credentials for access to MySQL is given!" fi fi fi [[ -n "$db_name" ]] || db_name="$DEFAULT_db_name" [[ -n "$quota" ]] || quota="$DEFAULT_quota" [[ -n "$in_file" ]] || in_file="$DEFAULT_in_file" [[ -n "$log_file" ]] || log_file="$DEFAULT_log_file" [[ -n "$dovecot_enc_method" ]] || dovecot_enc_method="$DEFAULT_dovecot_enc_method" if [[ ! -f "$in_file" ]];then fatal "File containing the email/password pairs '$in_file' does not exist !!" fi echo "" echo "" echo -e "\033[32mSettings for script \033[37m\033[1msent_userinfo_postfix.sh\033[m" echo "" echo " File containing the new mailboxes and passwords.......: $in_file" echo "" echo " Passsword scheme used for encryption..................: $dovecot_enc_method" echo " Mailbox quota to set for each new mailbox.............: $quota ($(echo "scale=2; $quota / 1024 /1024" | bc) MB)" echo "" if [[ "$db_type" = "pgsql" ]] ; then echo " Type of postfix databae...............................: PostgreSQL ($db_type)" echo " Database name for the postfix DB......................: $db_name" elif [[ "$db_type" = "mysql" ]] ; then echo " Type of postfix databae...............................: MySQL ($db_type)" echo " Database name for the postfix DB......................: $db_name" echo " MySQL credential args.................................: $mysql_credential_args" fi if [[ "$db_type" = "mysql" ]] ; then echo " Type of postfix databae...............................: MySQL ($db_type)" fi echo "" OK= while [ "$OK" != "yes" -o "$OK" != "no" ] ; do echononl "\033[1mParameters ok? [yes/no]:\033[m " read OK ## - To lower case OK=${OK,,} if [ "X$OK" = "X" ]; then echo -e "\n\t\033[33m\033[1mAn entry is required!\033[m\n" OK="" continue fi if [ "$OK" != "yes" -o "$OK" != "no" ] ; then break fi echo -e "\n\t\033[33m\033[1mWrong entry!\033[m\n" done [[ $OK = "yes" ]] || fatal "Repeat execution with different parameters." echo "" echononl " Create log directory '$(dirname "$log_file")'.." if [[ ! -d "$(dirname "$log_file")" ]] ; then mkdir "$(dirname "$log_file")" if [[ $? -eq 0 ]]; then echo_ok else echo_failed fi else echo_skipped fi echo ## - ## - Logfile ## - echononl " Backup existing log file.." if [ -f "$log_file" ]; then mv "$log_file" "${log_file}.${date_suffix}" if [ "$?" = "0" ]; then echo_ok else echo_failed fi else echo_skipped fi echononl " Create log file $log_file.." touch $log_file if [ "$?" = "0" ]; then echo_ok else echo_failed fi echo "" curdir=`pwd` cd /tmp while read email passwd ; do ## - get rid of empty lines [[ -z "$email" ]] && continue ## - get rid of comment lines [[ $email =~ ^[[:space:]]*# ]] && continue ## - remove leading/trailling whitespaces ## - email=`trim "$email"` password=`trim $passwd` ## - regex tha email addresses must matc ## - #regex_email="^[a-z0-9!#\$%&'*+/=?^_\`{|}~-]+(\.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$" regex_email="^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$" if [[ ! $email =~ $regex_email ]]; then error "email: give e-mail address ($email) is NOT VALID" echo "[ FAILED ]: The given e-mail address \"${user}@$domain\" is not VALID" >> $log_file continue fi ## - splitt in name and domain part ## - read user domain <<<$(IFS="@" ; echo $email) echo echo -e " \033[37m\033[1mHandling E-Mail addess ${user}@${domain}..\033[m" ## - check if domain is already configured ## - if [[ "$db_type" = "pgsql" ]] ; then domain_exists=`su postgres -c"psql $db_name -At -c\"SELECT 1 FROM domain WHERE domain = '$domain'\""` elif [[ "$db_type" = "mysql" ]] ; then domain_exists="$(mysql "$mysql_credential_args" "$db_name" \ -N -s -e"SELECT 1 FROM domain WHERE domain = '$domain'")" else fatal "Database type '$db_type' is not supported." fi if [[ "X$domain_exists" = "X" ]] ; then warn "Domain $domain is not configured as maildomain." echo "[ FAILED ]: Cannot create e-mail address \"${user}@$domain\"" >> $log_file echo " Domain $domain is not configured as maildomain." >> $log_file continue fi if [[ "$user" = "abuse" ]]; then warn "E-mail address $email is not supported" echo "[ FAILED ]: Cannot create e-mail address \"${user}@$domain\"" >> $log_file echo " E-mail address $email is not supported." >> $log_file continue elif [[ "$user" = "postmaster" ]];then warn "E-mail address $email is not supported" echo "[ FAILED ]: Cannot create e-mail address \"${user}@$domain\"" >> $log_file echo " E-mail address $email is not supported." >> $log_file continue fi ## - If password is not given, then take a default ## - if [[ -z "$passwd" ]]; then if [[ -z "$_passwd" ]]; then password_accepted=false while ! $password_accepted ; do passwd=`tr -cd '[:alnum:]#_\!\%/=@-' < /dev/urandom | tr '0' 'O' | fold -w12 | head -n1` regex="[#_\!\%/=@-]" [[ $passwd =~ $regex ]] || continue regex="[123456789].*[123456789]" [[ $passwd =~ $regex ]] || continue password_accepted=true done else passwd=$_passwd fi fi if [[ "$db_type" = "pgsql" ]] ; then mb_exists=`su postgres -c"psql $db_name -At -c\"SELECT 1 FROM mailbox WHERE username = '${user}@$domain'\""` elif [[ "$db_type" = "mysql" ]] ; then mb_exists="$(mysql "$mysql_credential_args" "$db_name" \ -N -s -e"SELECT 1 FROM mailbox WHERE username = '${user}@$domain'")" else fatal "Database type '$db_type' is not supported." fi if [[ "X$mb_exists" == "X1" ]] ; then warn "A Mailbox ${user}@$domain already exists." echo "[ FAILED ]: Cannot create e-mail address \"${user}@$domain\"" >> $log_file echo " A Mailbox ${user}@$domain already exists." >> $log_file continue fi if [[ "$db_type" = "pgsql" ]] ; then alias_exists=`su postgres -c"psql $db_name -At -c\"SELECT 1 FROM alias WHERE address = '${user}@$domain'\""` elif [[ "$db_type" = "mysql" ]] ; then alias_exists="$(mysql "$mysql_credential_args" "$db_name" \ -N -s -e"SELECT 1 FROM alias WHERE address = '${user}@$domain'")" else fatal "Database type '$db_type' is not supported." fi if [[ "X$alias_exists" == "X1" ]] ; then warn "A Forwarding Address ${user}@$domain already exists." echo "[ FAILED ]: Cannot create e-mail address \"${user}@$domain\"" >> $log_file echo " A Forwarding Address ${user}@$domain already exists." >> $log_file continue fi echononl " Create entry in table \"mailbox\".." if [[ "$db_type" = "pgsql" ]] ; then if [[ "$dovecot_enc_method" = "PLAIN" ]]; then sudo -u postgres psql $db_name -c "\ SET client_encoding to 'UTF8'; \ INSERT INTO mailbox (username,password,name,maildir,local_part,quota,domain,created,modified,active) \ VALUES ('${user}@$domain', '$passwd','','${domain}/${user}/','$user','$quota','$domain',NOW(),NOW(),'t')" \ > $tmp_err_msg 2>&1 else sudo -u postgres psql $db_name -c "\ SET client_encoding to 'UTF8'; \ INSERT INTO mailbox (username,password,name,maildir,local_part,quota,domain,created,modified,active) \ VALUES ('${user}@$domain', '$(doveadm pw -s "$dovecot_enc_method" -p "$passwd")','','${domain}/${user}/','$user','$quota','$domain',NOW(),NOW(),'t')" \ > $tmp_err_msg 2>&1 fi elif [[ "$db_type" = "mysql" ]] ; then if [[ "$dovecot_enc_method" = "PLAIN" ]]; then $(mysql "$mysql_credential_args" "$db_name" -N -s -e" SET NAMES utf8; INSERT INTO mailbox (username,password,name,maildir,local_part,quota,domain,created,modified,active) VALUES ('${user}@$domain', '$passwd','','${domain}/${user}/','$user','$quota','$domain',NOW(),NOW(),1)" \ > $tmp_err_msg 2>&1) else $(mysql "$mysql_credential_args" "$db_name" -N -s -e" SET NAMES utf8; INSERT INTO mailbox (username,password,name,maildir,local_part,quota,domain,created,modified,active) VALUES ('${user}@$domain', '$(doveadm pw -s "$dovecot_enc_method" -p "$passwd")','','${domain}/${user}/','$user','$quota','$domain',NOW(),NOW(),1)" \ > $tmp_err_msg 2>&1) fi else fatal "Database type '$db_type' is not supported." fi if [ "$?" = "0" ]; then echo_ok else echo_failed error "$(cat "$tmp_err_msg")" echo "[ FAILED ]: Cannot create e-mail address \"${user}@$domain\"" >> $log_file continue fi echononl " Create entry in table \"alias\".." if [[ "$db_type" = "pgsql" ]] ; then sudo -u postgres psql $db_name -c "\ SET client_encoding to 'UTF8'; \ INSERT INTO alias (address,goto,domain,created,modified) \ VALUES ('${user}@$domain','${user}@$domain','$domain',NOW(),NOW())" > $tmp_err_msg 2>&1 elif [[ "$db_type" = "mysql" ]] ; then $(mysql "$mysql_credential_args" "$db_name" -N -s -e" SET NAMES utf8; INSERT INTO alias (address,goto,domain,created,modified) VALUES ('${user}@$domain','${user}@$domain','$domain',NOW(),NOW())" \ > $tmp_err_msg 2>&1) else fatal "Database type '$db_type' is not supported." fi if [ "$?" = "0" ]; then echo_ok echo -e " email: ${user}@$domain" echo -e " password: $passwd" echo "[ OK ]: e-mail: ${user}@$domain -- password: $passwd" >> $log_file else echo_failed echo "[ FAILED ]: Cannot create e-mail address \"${user}@$domain\"" >> $log_file echo " Note: Entry in table \"alias\" was done; Take care, to" >> $log_file echo " remove that Entry." >> $log_file fi # - Test imap connection on the new mailbox using curl # - # - Note: turn off history expansion (set +H), to prevent the shell from # - interpreting sign "!" # - set +H echononl " Test imap connection to mailbox '${user}@$domain'.." curl --url "imap://127.0.0.1" --user "${user}@$domain:${passwd}" > $tmp_err_msg 2>&1 if [[ $? -ne 0 ]]; then echo_failed error "Testing an imap connection failed\n\t $(cat "$tmp_err_msg")" echo "[ FAILED ]: Testing an imap connection failed!" else echo_ok fi set -H done < $in_file echo "" echo "" echononl "\tMove file '$in_file'.." mv "$in_file" "${in_file}.ADDED.$(date +%Y-%m-%d)" if [[ $? -eq 0 ]]; then echo_ok else echo_failed fi echo echo -e "See \033[37m\033[1m$log_file\033[m to see the results again." echo "" cd $pwd clean_up 0