diff --git a/install_update_dovecot-2.4.sh b/install_update_dovecot-2.4.sh index 7f8b6c9..7a03bd4 100755 --- a/install_update_dovecot-2.4.sh +++ b/install_update_dovecot-2.4.sh @@ -147,6 +147,449 @@ detect_os_1 () { } +replace_code_block() { + local block_name="$1" + local new_block="$2" + local file="$3" + + if [[ -z "$block_name" || -z "$new_block" || -z "$file" ]]; then + echo "Fehler: Parameter fehlen." + echo "Verwendung: replace_dovecot_block \"blockname\" \"neuer_block\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Fehler: Datei '$file' existiert nicht." + return 1 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v block_name="$block_name" -v new_block="$new_block" ' + function count_char(str, c) { + n = 0 + for (i = 1; i <= length(str); i++) { + if (substr(str, i, 1) == c) n++ + } + return n + } + + { + if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") { + in_block = 1 + brace_depth = count_char($0, "{") - count_char($0, "}") + print new_block + next + } + + if (in_block) { + brace_depth += count_char($0, "{") - count_char($0, "}") + if (brace_depth <= 0) { + in_block = 0 + } + next + } + + print + } + ' "$file" > "$tmp_file" + + mv "$tmp_file" "$file" + return 0 +} + +replace_or_append_code_block() { + local block_name="$1" + local new_block="$2" + local file="$3" + + if [[ -z "$block_name" || -z "$new_block" || -z "$file" ]]; then + echo "Fehler: Parameter fehlen." + echo "Verwendung: replace_dovecot_block \"blockname\" \"neuer_block\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Fehler: Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + local block_found=0 + + awk -v block_name="$block_name" -v new_block="$new_block" ' + function count_char(str, c) { + n = 0 + for (i = 1; i <= length(str); i++) { + if (substr(str, i, 1) == c) n++ + } + return n + } + + { + if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") { + in_block = 1 + brace_depth = count_char($0, "{") - count_char($0, "}") + print new_block + block_found = 1 + next + } + + if (in_block) { + brace_depth += count_char($0, "{") - count_char($0, "}") + if (brace_depth <= 0) { + in_block = 0 + } + next + } + + print + } + + END { + if (!block_found) { + print new_block > "/dev/stderr" + exit 3 + } + } + ' "$file" 1>"$tmp_file" 2>_new_block_to_append.tmp + + result=$? + + if [[ $result -eq 3 ]]; then + # Block nicht gefunden neuen Block anhängen + echo "" >> "$file" + cat _new_block_to_append.tmp >> "$file" + rm -f "$tmp_file" _new_block_to_append.tmp + echo "Block '$block_name' wurde nicht gefunden und deshalb am Ende der Datei angehängt." + return 0 + fi + + mv "$tmp_file" "$file" + rm -f _new_block_to_append.tmp + echo "Block '$block_name' wurde ersetzt." + return 0 +} + +delete_code_block() { + local block_name="$1" + local file="$2" + + if [[ -z "$block_name" || -z "$file" ]]; then + echo "Verwendung: delete_block \"blockname\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v block_name="$block_name" ' + function count_char(str, c) { + n = 0 + for (i = 1; i <= length(str); i++) { + if (substr(str, i, 1) == c) n++ + } + return n + } + + { + if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") { + in_block = 1 + brace_depth = count_char($0, "{") - count_char($0, "}") + next + } + + if (in_block) { + brace_depth += count_char($0, "{") - count_char($0, "}") + if (brace_depth <= 0) { + in_block = 0 + } + next + } + + print + } + ' "$file" > "$tmp_file" + + mv "$tmp_file" "$file" + echo "Block '$block_name' wurde gelöscht." + return 0 +} + +delete_code_block_with_comments() { + local block_name="$1" + local file="$2" + + if [[ -z "$block_name" || -z "$file" ]]; then + echo "Verwendung: delete_block_with_comments \"blockname\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v block_name="$block_name" ' + function count_char(str, c) { + n = 0 + for (i = 1; i <= length(str); i++) { + if (substr(str, i, 1) == c) n++ + } + return n + } + + { + lines[NR] = $0 + if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") { + # Rückwärts prüfen, ob vorherige Zeilen nur Kommentare oder leer sind + start = NR + for (i = NR - 1; i >= 1; i--) { + if (lines[i] ~ /^#|^\s*$/) { + start = i + } else { + break + } + } + + in_block = 1 + brace_depth = count_char($0, "{") - count_char($0, "}") + skip_until = NR + next + } + + if (in_block) { + brace_depth += count_char($0, "{") - count_char($0, "}") + if (brace_depth <= 0) { + in_block = 0 + for (i = start; i <= NR; i++) { + deleted[i] = 1 + } + } + next + } + } + + END { + for (i = 1; i <= NR; i++) { + if (!(i in deleted)) { + print lines[i] + } + } + } + ' "$file" > "$tmp_file" + + mv "$tmp_file" "$file" + echo "Block '$block_name' inkl. vorangehender Kommentare wurde gelöscht." + return 0 +} + +replace_variable() { + local var_name="$1" + local new_value="$2" + local file="$3" + + if [[ -z "$var_name" || -z "$new_value" || -z "$file" ]]; then + echo "Verwendung: replace_variable \"variablenname\" \"neuer_wert\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v var_name="$var_name" -v new_value="$new_value" ' + BEGIN { + replaced = 0 + } + + { + if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") { + # Ersetze gesamte Zeile durch normierte Form + print var_name " = " new_value + replaced = 1 + } else { + print + } + } + + END { + if (!replaced) { + print var_name " = " new_value > "/dev/stderr" + exit 3 + } + } + ' "$file" 1> "$tmp_file" 2> _missing_var.tmp + + result=$? + + if [[ $result -eq 3 ]]; then + # Variable nicht gefunden → neue hinzufügen + echo "" >> "$file" + cat _missing_var.tmp >> "$file" + echo "➕ Variable '$var_name' wurde neu ans Ende angehängt." + rm -f "$tmp_file" _missing_var.tmp + return 0 + fi + + mv "$tmp_file" "$file" + rm -f _missing_var.tmp + echo "Variable '$var_name' wurde ersetzt." + return 0 +} + +replace_or_append_variable() { + local var_name="$1" + local new_value="$2" + local file="$3" + + if [[ -z "$var_name" || -z "$new_value" || -z "$file" ]]; then + echo "Verwendung: replace_variable \"variablenname\" \"neuer_wert\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v var_name="$var_name" -v new_value="$new_value" ' + BEGIN { replaced = 0 } + + { + if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") { + print var_name " = " new_value + replaced = 1 + } else { + print + } + } + + END { + if (!replaced) { + printf("\n%s = %s\n", var_name, new_value) >> "/dev/stderr" + exit 3 + } + } + ' "$file" > "$tmp_file" 2> _var_append.tmp + + result=$? + + if [[ $result -eq 3 ]]; then + cat _var_append.tmp >> "$tmp_file" + echo "Variable '$var_name' wurde neu ans Ende angehängt." + else + echo "Variable '$var_name' wurde ersetzt." + fi + + mv "$tmp_file" "$file" + rm -f _var_append.tmp + + return 0 +} + + +delete_variable() { + local var_name="$1" + local file="$2" + + if [[ -z "$var_name" || -z "$file" ]]; then + echo "Verwendung: delete_variable_only \"variablenname\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v var_name="$var_name" ' + # match: key = val, key=val, key val + !($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") { + print + } + ' "$file" > "$tmp_file" + + mv "$tmp_file" "$file" + echo "Nur Variable '$var_name' wurde gelöscht (Kommentare erhalten)." + return 0 +} + +delete_variable_with_comments() { + local var_name="$1" + local file="$2" + + if [[ -z "$var_name" || -z "$file" ]]; then + echo "Verwendung: delete_variable_with_comments \"variablenname\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v var_name="$var_name" ' + { + lines[NR] = $0 + + if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^=[:alnum:]])") { + # Rückwärts: vorangehende Kommentarzeilen (ohne Leerzeile) + start = NR + for (i = NR - 1; i >= 1; i--) { + if (lines[i] ~ /^[[:space:]]*#/) { + start = i + } else if (lines[i] ~ /^[[:space:]]*$/) { + break + } else { + break + } + } + + for (i = start; i <= NR; i++) { + delete lines[i] + } + } + } + + END { + for (i = 1; i <= NR; i++) { + if (i in lines) { + print lines[i] + } + } + } + ' "$file" > "$tmp_file" + + mv "$tmp_file" "$file" + echo "Variable '$var_name' inkl. zugehöriger Kommentare wurde gelöscht." + return 0 +} + # - Support systemd ? @@ -165,6 +608,8 @@ else DEFAULT_MYSQL_CREDENTIALS="" fi +DEFAULT_SSL_CIPHER_LIST="ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305" + # - Detect OS - Set variable # - os_dist @@ -252,6 +697,8 @@ fi [[ -n "$server_key" ]] || server_key="${cert_base_dir}/mailserver.key" [[ -n "$dh_pem_file" ]] || dh_pem_file="${cert_base_dir}/dh_4096.pem" +[[ -n "$ssl_cipher_list" ]] || ssl_cipher_list="${DEFAULT_SSL_CIPHER_LIST}" + [[ -n "$imap_cert" ]] || imap_cert="${cert_base_dir}/mailserver.crt" [[ -n "$imap_key" ]] || imap_key="${cert_base_dir}/mailserver.key" @@ -306,7 +753,7 @@ _version_short="${_version%-*}" #clean_up 0 -# 'expire plugin'was rRemoved in version 2.3.14: This plugin is not needed. +# 'expire plugin'was removed in version 2.3.14: This plugin is not needed. # Use mailbox { autoexpunge } Mailbox settings instead. # if [[ $dovecot_major_version -gt 2 ]] \ @@ -491,13 +938,7 @@ INSTALL_UPDATE_ENVIRONMENT_FILE="${_src_base_dir}/conf/install_update_dovecot-2. cat < ${INSTALL_UPDATE_ENVIRONMENT_FILE} #!/usr/bin/env bash -EOF -echo "_version=\"${_version}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} - -echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} - -cat <> ${INSTALL_UPDATE_ENVIRONMENT_FILE} log_file="${log_file}" backup_date="${backup_date}" @@ -510,20 +951,28 @@ rc_skipped="${rc_skipped}" rc_wait="${rc_wait}" rc_not_yet_implemented="${rc_not_yet_implemented}" +EOF + +cat <<'EOF' >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} + + +# ------------- +# - Functions an Variable +# ------------- clean_up() { - if [[ -f "\$_backup_crontab_file" ]]; then + if [[ -f "$_backup_crontab_file" ]]; then - echononl "(Re)Install previously saved crontab from '\$_backup_crontab_file'.." + echononl "(Re)Install previously saved crontab from '$_backup_crontab_file'.." - crontab \$_backup_crontab_file >> \$log_file 2>&1 + crontab $_backup_crontab_file >> $log_file 2>&1 - if [[ \$? -eq 0 ]]; then - echo -e "\$rc_done" + if [[ $? -eq 0 ]]; then + echo -e "$rc_done" else - echo -e "\$rc_failed" - error "\$(cat \$log_file)" + echo -e "$rc_failed" + error "$(cat $log_file)" fi fi @@ -534,40 +983,41 @@ clean_up() { exit $1 } + echononl(){ - echo X\\c > /tmp/shprompt\$\$ - if [ \`wc -c /tmp/shprompt\$\$ | awk '{print \$1}'\` -eq 1 ]; then - echo -e "\$*\\c" 1>&2 + echo X\\c > /tmp/shprompt$$ + if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then + echo -e "$*\\c" 1>&2 else - echo -en "\$*" 1>&2 + echo -en "$*" 1>&2 fi - rm /tmp/shprompt\$\$ + rm /tmp/shprompt$$ } fatal(){ echo "" - echo -e "\t[ \033[31m\033[1mFatal\033[m ]: \033[37m\033[1m\$*\033[m" + echo -e "\t[ \033[31m\033[1mFatal\033[m ]: \033[37m\033[1m$*\033[m" echo "" echo -e "\t\033[31m\033[1m Skript wird abgebrochen\033[m\033[m\n" - rm -f \$log_file + rm -f $log_file clean_up 1 } error(){ echo "" - echo -e "\t[ \033[31m\033[1mError\033[m ]: \$*" + echo -e "\t[ \033[31m\033[1mError\033[m ]: $*" echo "" } warn(){ echo "" - echo -e "\t[ \033[33m\033[1mWarning\033[m ]: \$*" + echo -e "\t[ \033[33m\033[1mWarning\033[m ]: $*" echo "" } info(){ echo "" - echo -e "\t[ \033[32m\033[1mInfo\033[m ]: \$*" + echo -e "\t[ \033[32m\033[1mInfo\033[m ]: $*" echo "" } @@ -586,8 +1036,483 @@ echo_skipped() { echo -e "\033[71G[ \033[33m\033[1mskipped\033[m ]" } +detect_os_1 () { + + if $(which lsb_release > /dev/null 2>&1) ; then + + os_dist="$(lsb_release -i | awk '{print tolower($3)}')" + os_version="$(lsb_release -r | awk '{print tolower($2)}')" + os_codename="$(lsb_release -c | awk '{print tolower($2)}')" + + if [[ "$os_dist" = "debian" ]]; then + if $(echo "$os_version" | grep -q '\.') ; then + os_version=$(echo "$os_version" | cut --delimiter='.' -f1) + fi + fi + + elif [[ -e "/etc/os-release" ]]; then + + . /etc/os-release + + os_dist=$ID + os_version=${VERSION_ID} + + fi + + # remove whitespace from os_dist and os_version + os_dist="${os_dist// /}" + os_version="${os_version// /}" + +} + +replace_code_block() { + local block_name="$1" + local new_block="$2" + local file="$3" + + if [[ -z "$block_name" || -z "$new_block" || -z "$file" ]]; then + echo "Fehler: Parameter fehlen." + echo "Verwendung: replace_dovecot_block \"blockname\" \"neuer_block\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Fehler: Datei '$file' existiert nicht." + return 1 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v block_name="$block_name" -v new_block="$new_block" ' + function count_char(str, c) { + n = 0 + for (i = 1; i <= length(str); i++) { + if (substr(str, i, 1) == c) n++ + } + return n + } + + { + if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") { + in_block = 1 + brace_depth = count_char($0, "{") - count_char($0, "}") + print new_block + next + } + + if (in_block) { + brace_depth += count_char($0, "{") - count_char($0, "}") + if (brace_depth <= 0) { + in_block = 0 + } + next + } + + print + } + ' "$file" > "$tmp_file" + + mv "$tmp_file" "$file" + return 0 +} + +replace_or_append_code_block() { + local block_name="$1" + local new_block="$2" + local file="$3" + + if [[ -z "$block_name" || -z "$new_block" || -z "$file" ]]; then + echo "Fehler: Parameter fehlen." + echo "Verwendung: replace_dovecot_block \"blockname\" \"neuer_block\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Fehler: Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + local block_found=0 + + awk -v block_name="$block_name" -v new_block="$new_block" ' + function count_char(str, c) { + n = 0 + for (i = 1; i <= length(str); i++) { + if (substr(str, i, 1) == c) n++ + } + return n + } + + { + if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") { + in_block = 1 + brace_depth = count_char($0, "{") - count_char($0, "}") + print new_block + block_found = 1 + next + } + + if (in_block) { + brace_depth += count_char($0, "{") - count_char($0, "}") + if (brace_depth <= 0) { + in_block = 0 + } + next + } + + print + } + + END { + if (!block_found) { + print new_block > "/dev/stderr" + exit 3 + } + } + ' "$file" 1>"$tmp_file" 2>_new_block_to_append.tmp + + result=$? + + if [[ $result -eq 3 ]]; then + # Block nicht gefunden neuen Block anhängen + echo "" >> "$file" + cat _new_block_to_append.tmp >> "$file" + rm -f "$tmp_file" _new_block_to_append.tmp + echo "Block '$block_name' wurde nicht gefunden und deshalb am Ende der Datei angehängt." + return 0 + fi + + mv "$tmp_file" "$file" + rm -f _new_block_to_append.tmp + echo "Block '$block_name' wurde ersetzt." + return 0 +} + +delete_code_block() { + local block_name="$1" + local file="$2" + + if [[ -z "$block_name" || -z "$file" ]]; then + echo "Verwendung: delete_block \"blockname\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v block_name="$block_name" ' + function count_char(str, c) { + n = 0 + for (i = 1; i <= length(str); i++) { + if (substr(str, i, 1) == c) n++ + } + return n + } + + { + if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") { + in_block = 1 + brace_depth = count_char($0, "{") - count_char($0, "}") + next + } + + if (in_block) { + brace_depth += count_char($0, "{") - count_char($0, "}") + if (brace_depth <= 0) { + in_block = 0 + } + next + } + + print + } + ' "$file" > "$tmp_file" + + mv "$tmp_file" "$file" + echo "Block '$block_name' wurde gelöscht." + return 0 +} + +replace_variable() { + local var_name="$1" + local new_value="$2" + local file="$3" + + if [[ -z "$var_name" || -z "$new_value" || -z "$file" ]]; then + echo "Verwendung: replace_variable \"variablenname\" \"neuer_wert\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v var_name="$var_name" -v new_value="$new_value" ' + BEGIN { + replaced = 0 + } + + { + if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") { + # Ersetze gesamte Zeile durch normierte Form + print var_name " = " new_value + replaced = 1 + } else { + print + } + } + + END { + if (!replaced) { + print var_name " = " new_value > "/dev/stderr" + exit 3 + } + } + ' "$file" 1> "$tmp_file" 2> _missing_var.tmp + + result=$? + + if [[ $result -eq 3 ]]; then + # Variable nicht gefunden → neue hinzufügen + echo "" >> "$file" + cat _missing_var.tmp >> "$file" + echo "➕ Variable '$var_name' wurde neu ans Ende angehängt." + rm -f "$tmp_file" _missing_var.tmp + return 0 + fi + + mv "$tmp_file" "$file" + rm -f _missing_var.tmp + echo "Variable '$var_name' wurde ersetzt." + return 0 +} + +replace_or_append_variable() { + local var_name="$1" + local new_value="$2" + local file="$3" + + if [[ -z "$var_name" || -z "$new_value" || -z "$file" ]]; then + echo "Verwendung: replace_variable \"variablenname\" \"neuer_wert\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v var_name="$var_name" -v new_value="$new_value" ' + BEGIN { replaced = 0 } + + { + if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") { + print var_name " = " new_value + replaced = 1 + } else { + print + } + } + + END { + if (!replaced) { + printf("\n%s = %s\n", var_name, new_value) >> "/dev/stderr" + exit 3 + } + } + ' "$file" > "$tmp_file" 2> _var_append.tmp + + result=$? + + if [[ $result -eq 3 ]]; then + cat _var_append.tmp >> "$tmp_file" + echo "Variable '$var_name' wurde neu ans Ende angehängt." + else + echo "Variable '$var_name' wurde ersetzt." + fi + + mv "$tmp_file" "$file" + rm -f _var_append.tmp + + return 0 +} + +delete_variable() { + local var_name="$1" + local file="$2" + + if [[ -z "$var_name" || -z "$file" ]]; then + echo "Verwendung: delete_variable \"variablenname\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v var_name="$var_name" ' + # match: key = val, key=val, key val + !($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^[:alnum:]#])") { + print + } + ' "$file" > "$tmp_file" + + mv "$tmp_file" "$file" + echo "Nur Variable '$var_name' wurde gelöscht (Kommentare erhalten)." + return 0 +} + +delete_code_block_with_comments() { + local block_name="$1" + local file="$2" + + if [[ -z "$block_name" || -z "$file" ]]; then + echo "Verwendung: delete_block_with_comments \"blockname\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v block_name="$block_name" ' + function count_char(str, c) { + n = 0 + for (i = 1; i <= length(str); i++) { + if (substr(str, i, 1) == c) n++ + } + return n + } + + { + lines[NR] = $0 + if (!in_block && $0 ~ "^\\s*" block_name "\\s*\\{") { + # Rückwärts prüfen, ob vorherige Zeilen nur Kommentare oder leer sind + start = NR + for (i = NR - 1; i >= 1; i--) { + if (lines[i] ~ /^#|^\s*$/) { + start = i + } else { + break + } + } + + in_block = 1 + brace_depth = count_char($0, "{") - count_char($0, "}") + skip_until = NR + next + } + + if (in_block) { + brace_depth += count_char($0, "{") - count_char($0, "}") + if (brace_depth <= 0) { + in_block = 0 + for (i = start; i <= NR; i++) { + deleted[i] = 1 + } + } + next + } + } + + END { + for (i = 1; i <= NR; i++) { + if (!(i in deleted)) { + print lines[i] + } + } + } + ' "$file" > "$tmp_file" + + mv "$tmp_file" "$file" + echo "Block '$block_name' inkl. vorangehender Kommentare wurde gelöscht." + return 0 +} + +delete_variable_with_comments() { + local var_name="$1" + local file="$2" + + if [[ -z "$var_name" || -z "$file" ]]; then + echo "Verwendung: delete_variable_with_comments \"variablenname\" \"/pfad/zur/datei\"" + return 1 + fi + + if [[ ! -f "$file" ]]; then + echo "Datei '$file' existiert nicht." + return 2 + fi + + local tmp_file + tmp_file=$(mktemp) + + awk -v var_name="$var_name" ' + { + lines[NR] = $0 + + if ($0 ~ "^[[:space:]]*" var_name "[[:space:]]*(=|[^=[:alnum:]])") { + # Rückwärts: vorangehende Kommentarzeilen (ohne Leerzeile) + start = NR + for (i = NR - 1; i >= 1; i--) { + if (lines[i] ~ /^[[:space:]]*#/) { + start = i + } else if (lines[i] ~ /^[[:space:]]*$/) { + break + } else { + break + } + } + + for (i = start; i <= NR; i++) { + delete lines[i] + } + } + } + + END { + for (i = 1; i <= NR; i++) { + if (i in lines) { + print lines[i] + } + } + } + ' "$file" > "$tmp_file" + + mv "$tmp_file" "$file" + echo "Variable '$var_name' inkl. zugehöriger Kommentare wurde gelöscht." + return 0 +} + + EOF +echo "_version=\"${_version}\" # dovecot version" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} + +echo "" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} echo "dovecot_main_version=${dovecot_main_version}" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} echo "dovecot_major_version=${dovecot_major_version}" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} @@ -654,6 +1579,7 @@ if [[ $dovecot_major_version -ge 3 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -ge 3 ]] ); then echo "dh_pem_file=\"${dh_pem_file}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} fi +echo "ssl_cipher_list=\"${ssl_cipher_list}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} echo "imap_cert=\"${imap_cert}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} echo "imap_key=\"${imap_key}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} echo "pop_cert=\"${pop_cert}\"" >> ${INSTALL_UPDATE_ENVIRONMENT_FILE} @@ -1211,27 +2137,78 @@ fi blank_line -echononl " Create Configuration Directory 'etc/dovecot/conf.d'.." -if [[ ! -d "/usr/local/dovecot-${_version}/etc/dovecot/conf.d" ]] ; then - mkdir -p "/usr/local/dovecot-${_version}/etc/dovecot/conf.d" > $log_file 2>&1 - if [ "$?" = 0 ]; then - echo -e "$rc_done" - else - echo -e "$rc_failed" - error "$(cat $log_file)" - echononl " continue anyway [yes/no]: " - read OK - OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" - while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do - echononl "Wrong entry! - repeat [yes/no]: " +if [[ $dovecot_major_version -gt 2 ]] \ + || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then + echononl " Create Configuration Directory 'etc/dovecot/conf.d'.." + if [[ ! -d "/usr/local/dovecot-${_version}/etc/dovecot/conf.d" ]] ; then + mkdir -p "/usr/local/dovecot-${_version}/etc/dovecot/conf.d" > $log_file 2>&1 + if [ "$?" = 0 ]; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "$(cat $log_file)" + + echononl " continue anyway [yes/no]: " read OK - done - [[ $OK = "yes" ]] || fatal "Abbruch durch User" + OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" + while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do + echononl "Wrong entry! - repeat [yes/no]: " + read OK + done + [[ $OK = "yes" ]] || fatal "Abbruch durch User" + fi + else + echo -e "$rc_skipped" fi -else - echo -e "$rc_skipped" + + _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf" + echononl " Create empty file '$(basename "${_conf_file}")'.." + if [[ ! -f "${_conf_file}" ]] ; then + _failed=false + touch "${_conf_file}" > ${log_file} + if [ "$?" = 0 ]; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Creating empty file '${_conf_file}' failed!" + fi + else + echo -e "$rc_skipped" + fi + + _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf" + echononl " Create empty file '$(basename "${_conf_file}")'.." + if [[ ! -f "${_conf_file}" ]] ; then + _failed=false + touch "${_conf_file}" > ${log_file} + if [ "$?" = 0 ]; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Creating empty file '${_conf_file}' failed!" + fi + else + echo -e "$rc_skipped" + fi + + _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf" + echononl " Create empty file '$(basename "${_conf_file}")'.." + if [[ ! -f "${_conf_file}" ]] ; then + _failed=false + touch "${_conf_file}" > ${log_file} + if [ "$?" = 0 ]; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Creating empty file '${_conf_file}' failed!" + fi + else + echo -e "$rc_skipped" + fi + + blank_line fi @@ -1328,7 +2305,7 @@ blank_line ## - Copy example config files to the config directory ## - -echononl "Copy example config files to the config directory.." +echononl " Copy example config files to the config directory.." if [[ ${dovecot_major_version} -eq 2 ]] && [[ ${dovecot_minor_version} -lt 4 ]] ; then cp -r /usr/local/dovecot-${_version}/share/doc/dovecot/example-config/* \ /usr/local/dovecot-${_version}/etc/dovecot/ > /dev/null 2>&1 @@ -1343,7 +2320,7 @@ else fi -echononl "Backup main configuration file 'dovecot.conf'.." +echononl " Backup main configuration file 'dovecot.conf'.." if [[ -f "/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf" ]] ; then cp -a /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf \ /usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf.ORIG > /dev/null 2>&1 @@ -1405,6 +2382,19 @@ if [[ $dovecot_major_version -gt 2 ]] \ # - _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/dovecot.conf" + echononl " Delete block 'namespace inbox' in file '$(basename "${_conf_file}")'.." + if grep -qE '^\s*namespace\s+inbox\s*{' "${_conf_file}"; then + delete_code_block "namespace inbox" "${_conf_file}" + if [[ $? -gt 1 ]] ; then + echo -e "$rc_failed" + error "Deleting block 'namespace inbox' in file '$(basename "${_conf_file}")' failed!" + else + echo -e "$rc_done" + fi + else + echo -e "$rc_skipped" + fi + _protocols_block="protocols {\n imap = yes\n lmtp = yes\n pop3 = yes\n sieve = yes\n}" if [[ -n "$ipv6" ]]; then _listen="$ipv4 $ipv6" @@ -1962,23 +2952,485 @@ fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf # +_failed=false if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then - if [[ ! -f "/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf" ]] ; then - _failed=false - echononl " Create empty file '10-master.conf'.." - touch /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf > ${log_file} - if [ "$?" = 0 ]; then - echo -e "$rc_done" - else - echo -e "$rc_failed" - error "Creating empty file '/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf' failed!" - fi + _conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf" + + # edit /usr/local/dovecot/etc/dovecot/conf.d/10-master.conf + # + # default_process_limit = 1024 + # default_client_limit = 10240 + # + # default_vsz_limit = 512M + # + # !! Bemerkung !! + # + # Das Hochsetzen des default_client_limit Parameters auf einen Wert größer + # als 1024 geht nur dann wenn auch die Anzahl der zulässigen "open files" + # (default = 1024) geändert wird. + # + # + # Systemd System: + # =============== + # + # In der service datei (z.Bsp. /etc/systemd/system/multi-user.target.wants/dovecot.service) + # den Wert 'LimitNOFILE' hochsetzen: + # + # LimitNOFILE=32768 (must be greater or equal of 'default_client_limit') + # + # systemctl daemon-reload + # systemctl restart dovecot.service + # + # Im Falle von LX containern muss zusätzlich auf dem hostsystem + # in der datei '/etc/systemd/system.conf' der Wert für 'DefaultLimitNOFILE' + # hochgesetzt werden. + # + # System V systems: + # ================= + # Das Hochsetzen des default_client_limit Parameters auf einen Wert größer + # als 1024 geht nur dann wenn auch die Anzahl der zulässigen "open files" + # (default = 1024) geändert wird. Z.Bsp. in der Datei /etc/init.d/dovecot + # durch Einfügen der zeile: + # ulimit -n 32768 + # + # Linux VServer: + # put the following lines into /etc/security/limits.conf + # + # @staff hard nofile 32768 + # root hard nofile 32768 + # + # !! Mybe you have also create file /etc/vservers/*/ulimits/nofiles.hard + # with the same contents: + # + # @staff hard nofile 32768 + # @adm hard nofile 32768 + # root hard nofile 32768 + # + # see also http://linux-vserver.org/Ulimit_Nofiles + # + # + # service imap-login { + # inet_listener imap { + # address = $imap_listener_adresses + # } + # + # inet_listener imaps { + # address = $imaps_listener_adresses + # + # } + # + # process_min_avail = 16 + # } + # + # service pop3-login { + # inet_listener pop3 { + # address = $pop_listener_adresses + # + # } + # inet_listener pop3s { + # address = $pops_listener_adresses + # + # } + # } + # + # service submission-login { + # + # inet_listener submission { + # #port = 587 + # } + # + # inet_listener submissions { + # #port = 465 + # } + # } + # + # service lmtp { + # + # unix_listener /var/spool/postfix/private/dovecot-lmtp { + # user = postfix + # group = postfix + # mode = 0660 + # } + # + # # Create inet listener only if you can't use the above UNIX socket + # #inet_listener lmtp { + # # Avoid making LMTP visible for the entire internet + # #address = + # #port = + # #} + # } + # + # service imap { + # + # # tell imap to do post-login lookup using a socket called "imap-postlogin" + # executable = imap post-login + # + # # Most of the memory goes to mmap()ing files. You may need to increase this + # # limit if you have huge mailboxes. + # #vsz_limit = $default_vsz_limit + # + # # Max. number of IMAP processes (connections) + # #process_limit = 1024 + # } + # + # service pop3 { + # + # # tell imap to do post-login lookup using a socket called "imap-postlogin" + # executable = pop3 post-login + # + # # Max. number of POP3 processes (connections) + # #process_limit = 1024 + # } + # + # service submission { + # + # # Max. number of SMTP Submission processes (connections) + # #process_limit = 1024 + # } + # + # service auth { + # + # # Auth Listener (XMPP - Jabber) + # inet_listener { + # address = $xmpp_listener_addresses + # port = $xmpp_listener_port + # } + # + # unix_listener auth-userdb { + # mode = 0666 + # user = dovecot + # group = dovecot + # } + # + # unix_listener /var/spool/postfix/private/dovecot-auth { + # mode = 0666 + # user = postfix + # group = postfix + # } + # + # } + # + # service auth-worker { + # # Auth worker process is run as root by default, so that it can access + # # /etc/shadow. If this isn't necessary, the user should be changed to + # # $SET:default_internal_user. + # #user = root + # } + # + # service dict { + # # If dict proxy is used, mail processes should have access to its socket. + # # For example: mode=0660, group=vmail and global mail_access_groups=vmail + # unix_listener dict { + # #mode = 0600 + # #user = + # #group = + # } + # } + # + echononl " Adjusting file $(basename "${_conf_file}").." + :> "${_conf_file}" + + _param="default_process_limit" + _val=1024 + if grep -qE "^\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" >> "${log_file}" 2>&1 || _failed=true + else + cat <> "${_conf_file}" || _failed=true + +# Default value for parameter 'service_process_limit', if not overridden by service-specific configuration. +${_param} = ${_val} +EOF fi - echononl " Adjusting file 10-master.conf.." - echo -e "$rc_not_yet_implemented" + _param="default_client_limit" + _val=10240 + if grep -qE "^\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" >> "${log_file}" 2>&1 || _failed=true + else + cat <> "${_conf_file}" || _failed=true + +# Default value for service_client_limit, if not overridden by service-specific configuration. +${_param} = ${_val} +EOF + fi + + _param="default_vsz_limit" + _val="512 M" + if grep -qE "^\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" >> "${log_file}" 2>&1 || _failed=true + else + cat <> "${_conf_file}" || _failed=true + +# Default value for service_vsz_limit, if not overridden by service-specific configuration. +${_param} = ${_val} +EOF + fi + + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + if ${xmpp_listener} ; then + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + +# if grep -qE "^\s*service\s+auth\s*{" "${_conf_file}"; then +# replace_code_block "service auth" "${NEW_BLOCK}" "${_conf_file}" +# +# if [[ $? -gt 0 ]]; then +# _failed=true +# fi +# else +# echo -e "\n${NEW_BLOCK}" >> "${_conf_file}" +# fi + + if ! $_failed ; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Adjusting Adjusting file ${_conf_file} failed" + error "$(cat "${_conf_file}")" + + echo "" + echononl "continue anyway [yes/no]: " + read OK + OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" + while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do + echononl "Wrong entry! - repeat [yes/no]: " + read OK + done + [[ $OK = "yes" ]] || fatal "Interupted by user" + + fi else @@ -2082,7 +3534,6 @@ else ## - } ## - } ## - - _failed=false echononl " Adjusting file 10-master.conf.." perl -i.ORIG -n -p -e "s#^([ ]*)(unix_listener\ +auth-userdb.*)#\1\2\n\1 mode = 0666\n\1 user = dovecot\n\1 group = dovecot#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-master.conf || _failed=true @@ -2152,11 +3603,11 @@ fi ## - ## - openssl dhparam -out /etc/postfix/ssl/dh_4096.pem` ## - +echononl " Create SSL DH parameters '$dh_pem_file'.." if [[ $dovecot_major_version -ge 3 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -ge 3 ]] ); then if [[ ! -f "$dh_pem_file" ]] ; then - echononl " Create SSL DH parameters '$dh_pem_file'.." echo -en "$rc_wait" if [[ "$os_dist" = "debian" ]] && [[ $os_version -gt 11 ]] ; then openssl dhparam -out "$dh_pem_file" 4096 > /dev/null 2>&1 @@ -2169,19 +3620,135 @@ if [[ $dovecot_major_version -ge 3 ]] \ echo -e "$rc_failed" error "Creating DH parameter file '$dh_pem_file' failed." fi - fi + else + echo -e "$rc_skipped" + fi +else + echo -e "$rc_skipped" fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf # +_failed=false +_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf" + if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then - echononl " Adjusting file 10-ssl.conf.." - echo -e "$rc_not_yet_implemented" + # edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf + # + # ssl_server { + # + # ssl = required + # + # # Preferred permissions: root:root 0444 + # cert_file = $server_cert + # + # # Preferred permissions: root:root 0400 + # key_file = $server_key + # + # # Path to the Diffie-Hellman parameters file. This setting isn't needed if using only ECDSA certificates. + # # + # # You can generate a new parameters file by, for example, running + # # + # # openssl dhparam -out dh.pem 4096 + # # + # # on a machine with sufficient entropy (this may take some time). + # dh_file = $dh_pem_file + # + # # SSL ciphers to use + # ssl_cipher_list = ${ssl_cipher_list} + # + # + # # Whether to give preference to the server's cipher list over a client's list (server) + # # or vice versa (client) + # # + # # For TLSv1.3 server ciphers should not longer be preferred + # prefer_ciphers = client + # + # # The minimum SSL protocol version Dovecot accepts. + # # + # # This setting is used for both incoming and outgoing SSL connections. + # min_protocol = TLSv1.2 + # } + + echononl " Adjusting file $(basename "${_conf_file}").." + :> "${log_file}" + + read -r -d '' NEW_BLOCK <> "${log_file}" 2>&1 + if [[ $? -gt 0 ]]; then + _failed=true + fi + + _param="ssl_min_protocol" + _val="TLSv1.2" + if grep -qE "^\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" >> "${log_file}" 2>&1 || _failed=true + else + cat <> "${_conf_file}" || _failed=true + +# The minimum SSL protocol version Dovecot accepts. +# +# This setting is used for both incoming and outgoing SSL connections. +${_param} = ${_val} +EOF + fi + + if ! $_failed ; then + echo -e "$rc_done" + else + echo -e "$rc_failed" + error "Adjusting Adjusting file ${_conf_file} failed" + error "$(cat "${log_file}")" + + echo "" + echononl "continue anyway [yes/no]: " + read OK + OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" + while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do + echononl "Wrong entry! - repeat [yes/no]: " + read OK + done + [[ $OK = "yes" ]] || fatal "Interupted by user" + + fi else + ## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf ## - ## - ssl = required @@ -2196,7 +3763,7 @@ else ## - #ssl_protocols = !SSLv3 ## - ssl_min_protocol = TLSv1.2 ## - - ## - ssl_cipher_list = ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA + ## - ssl_cipher_list = ${ssl_cipher_list} ## - ## - ssl_prefer_server_ciphers = yes ## - @@ -2212,14 +3779,68 @@ else ## - # ssl_key = <$pop_key ## - #} ## - - _failed=false - echononl " Adjusting file 10-ssl.conf.." - perl -i.ORIG -n -p -e "s#^(\s*\#*\s*)(ssl\ ?=.*)#\#\1\2\nssl = required#" \ - /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true - perl -i -n -p -e "s#^([ ]*)(ssl_cert\ ?=.*)#\1\#\# \2\n\1ssl_cert = <$server_cert#g" \ - /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true - perl -i -n -p -e "s#^([ ]*)(ssl_key\ ?=.*)#\1\#\# \2\n\1ssl_key = <$server_key#g" \ - /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true + echononl " Backup file $(basename "${_conf_file}").." + + if [[ ! -f "${_conf_file}.ORIG" ]] ; then + cp -a "${_conf_file}" "${_conf_file}.ORIG" > ${log_file} 2>&1 + + if [[ $? -gt 0 ]] ; then + echo -e "$rc_failed" + error "$(cat $log_file)" + else + echo -e "$rc_done" + fi + else + echo -e "$rc_skipped" + fi + + :> "${log_file}" + + echononl " Adjusting file $(basename "${_conf_file}").." + + _param="ssl" + _val="required" + if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" || _failed=true + else + cat <> "${_conf_file}" || _failed=true + +# SSL/TLS support: yes, no, required. +${_param} = ${_val} +EOF + fi + + + _param="ssl_cert" + _val="<$server_cert" + if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" || _failed=true + else + cat <> "${_conf_file}" || _failed=true + +# PEM encoded X.509 SSL/TLS certificate and private key. They're opened before +# dropping root privileges, so keep the key file unreadable by anyone but +# root. Included doc/mkcert.sh can be used to easily generate self-signed +# certificate, just make sure to update the domains in dovecot-openssl.cnf +${_param} = ${_val} +EOF + fi + + + _param="ssl_key" + _val="<$server_key" + if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" || _failed=true + else + cat <> "${_conf_file}" || _failed=true + +${_param} = ${_val} +EOF + fi + if [[ $dovecot_major_version -ge 3 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -ge 3 ]] ); then @@ -2229,8 +3850,21 @@ else fi fi if [[ -f "$dh_pem_file" ]]; then - perl -i -n -p -e "s#^(\s*\#*)(ssl_dh\s*=.*)#\#\1\2\nssl_dh = <$dh_pem_file#g" \ - /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true + + _param="ssl_dh" + _val="<$dh_pem_file" + if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" || _failed=true + else + cat <> "${_conf_file}" || _failed=true +# SSL DH parameters +# Generate new params with \`openssl dhparam -out /etc/dovecot/dh.pem 4096\` +# Or migrate from old ssl-parameters.dat file with the command dovecot +# gives on startup when ssl_dh is unset. +${_param} = ${_val} +EOF + fi else _failed=true fi @@ -2239,8 +3873,20 @@ else /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true fi - perl -i -n -p -e "s#^([ ]*)\#?(ssl_min_protocol\ ?=.*)#\1\#\# \2\nssl_min_protocol = TLSv1.2#g" \ - /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true + _param="ssl_min_protocol" + _val="TLSv1.2" + if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" || _failed=true + else + cat <> "${_conf_file}" || _failed=true + +# The minimum SSL protocol version Dovecot accepts. +${_param} = ${_val} +EOF + fi + + echo "ssl_min_protocol: done" # - Replace only the first occurence of the match # - @@ -2249,18 +3895,58 @@ else # - # - perl -pi -e '$a=1 if(!$a && s/(width:).*;/$1 100%;/);' filename.css # - - perl -i -n -p -e '$a=1 if(!$a && s#^([ ]*)\#?(ssl_cipher_list\ ?=.*)#\1\#\# \2\nssl_cipher_list = ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA#);' \ + #perl -i -n -p -e "\$a=1 if(!\$a && s#^([ ]*)\#?(ssl_cipher_list\ ?=.*)#\1\#\# \2\nssl_cipher_list = ${ssl_cipher_list}#);" \ + # /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true + + perl -i -n -p -e "\$a=1 if(!\$a && s#^([ ]*)\#?(ssl_cipher_list\ ?=.*)#ssl_cipher_list = ${ssl_cipher_list}#);" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true + echo "ssl_cipher_list: done" + + + _param="ssl_min_protocol" + _val="TLSv1.2" + if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" || _failed=true + else + cat <> "${_conf_file}" || _failed=true + +# The minimum SSL protocol version Dovecot accepts. +${_param} = ${_val} +EOF + fi + + + _param="ssl_prefer_server_ciphers" + _val="no" + if grep -qE "^\s*#?\s*${_param}\s*=" "${_conf_file}"; then + perl -i -n -p -e "s#^(\s*)\#?\ ?(${_param}\ ?=.*)#${_param} = ${_val}#g" \ + "${_conf_file}" || _failed=true + else + cat <> "${_conf_file}" || _failed=true + +# Prefer the server's order of ciphers over client's. +${_param} = ${_val} +EOF + fi - perl -i -n -p -e "s#^([ ]*)\#?(ssl_prefer_server_ciphers\ ?=.*)#\1\#\# \2\nssl_prefer_server_ciphers = yes#g" \ - /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-ssl.conf || _failed=true if ! $_failed ; then echo -e "$rc_done" else echo -e "$rc_failed" - fatal "Adjusting file 10-ssl.conf failed" + error "Adjusting file 10-ssl.conf failed" + + echo "" + echononl "continue anyway [yes/no]: " + read OK + OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')" + while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do + echononl "Wrong entry! - repeat [yes/no]: " + read OK + done + [[ $OK = "yes" ]] || fatal "Interupted by user" fi fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf @@ -2268,10 +3954,35 @@ fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-ssl.conf # edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf # +_failed=false +_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf" if [[ $dovecot_major_version -gt 2 ]] \ || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then - echononl " Adjusting file 10-mail.conf.." + # edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf + # + # mail_home = /var/vmail/%{user | domain}/%{user | username} + # mail_driver = Maildir + # mail_path = ~/Maildir + # + # mail_uid = vmail + # mail_gid = vmail + # + # first_valid_uid = 5000 + # last_valid_uid = 5000 + # + # first_valid_gid = 5000 + # last_valid_gid = 5000 + # + # mail_temp_dir = /var/vmail/tmp + # + # auth_socket_path = /run/dovecot/auth-userdb + # + # mail_plugins = quota acl | mail_plugins = quota acl expire + # + # mailbox_list_index + # + echononl " Adjusting file '$(basename "${_conf_file}").." echo -e "$rc_not_yet_implemented" else @@ -2292,11 +4003,10 @@ else ## - last_valid_gid = 5000 ## - ## - auth_socket_path = /run/dovecot/auth-userdb - ## - mail_plugins = quota | mail_plugins = quota expire + ## - mail_plugins = quota acl | mail_plugins = quota acl expire ## - ## - mailbox_list_index = yes ## - - _failed=false echononl " Adjusting file 10-mail.conf" perl -i.ORIG -n -p -e "s#^([ ]*)\#?\ ?(mail_location\ +=.*)#\1\#\# \2\n\1mail_location = maildir:/var/vmail/%d/%n/Maildir#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true @@ -2318,11 +4028,11 @@ else /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true if $plugin_expire ; then - perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota expire#g" \ + perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota acl expire#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true else - perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota#g" \ + perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota acl#g" \ /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true fi @@ -3833,7 +5543,7 @@ echo echo -e "\033[1mConfigure quota support for dovecot\033[m" -## - take care quota plugins (quota,imap-quota) will +## - take care quota plugins (quota,imap_quota) will ## - be loaded: ## - ## - there are two quota related plugins: @@ -4650,32 +6360,46 @@ else echo -e "$rc_failed" fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/20-imap.conf failed" fi - - ## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf - ## - - ## - mail_plugins = quota expire acl - ## - - _failed=false - echononl " Add mail_plugin acl to 10-mail.conf" - - if $plugin_expire ; then - perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota expire acl#g" \ - /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true - else - perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota acl#g" \ - /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true - fi - - if ! $_failed ; then - echo -e "$rc_done" - else - echo -e "$rc_failed" - fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf failed" - fi - fi # edit /usr/local/dovecot/etc/dovecot/conf.d/20-imap.conf +## edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf +## +#_failed=false +#_conf_file="/usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf" +#if [[ $dovecot_major_version -gt 2 ]] \ +# || ( [[ $dovecot_major_version -eq 2 ]] && [[ $dovecot_minor_version -gt 3 ]] ); then +# +# echononl " Adjust the mail_plugins parameter in the $(basename "${_conf_file}") file.." +# echo -e "$rc_not_yet_implemented" +# +#else +# +# ## - edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf +# ## - +# ## - mail_plugins = quota expire acl +# ## - +# _failed=false +# echononl " Adjust the mail_plugins parameter in the $(basename "${_conf_file}") file.." +# +# if $plugin_expire ; then +# perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota expire acl#g" \ +# /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true +# else +# perl -i -n -p -e "s#^([ ]*)\#?\ ?(mail_plugins\ +=.*)#\1\#\# \2\n\1mail_plugins = quota acl#g" \ +# /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf || _failed=true +# fi +# +# if ! $_failed ; then +# echo -e "$rc_done" +# else +# echo -e "$rc_failed" +# fatal "Adjusting file /usr/local/dovecot-${_version}/etc/dovecot/conf.d/10-mail.conf failed" +# fi +# +#fi # edit /usr/local/dovecot/etc/dovecot/conf.d/10-mail.conf + + ## - !! Notice !! ## - There a two possibilities, configuring acl backend: ## - - flat file