diff options
author | Micah <micah@leap.se> | 2016-05-10 14:48:26 -0400 |
---|---|---|
committer | Micah <micah@leap.se> | 2016-05-10 14:48:26 -0400 |
commit | 86c85582065c391aa13c0b9b397dfd1aa2e2ac7b (patch) | |
tree | 7c027409a517d862864bf3650f4a8a66f615162d /puppet/modules/site_postfix | |
parent | 70b1c648b94e6c007b9241a4661f33881e74485f (diff) | |
parent | 66b4c6b5ec6fe2f242020845fe92715ae2cdcc1e (diff) |
Merge tag '0.8.0'
Release 0.8.0
Diffstat (limited to 'puppet/modules/site_postfix')
13 files changed, 287 insertions, 71 deletions
diff --git a/puppet/modules/site_postfix/files/checks/received_anon b/puppet/modules/site_postfix/files/checks/received_anon index 2822973e..9de25e63 100644 --- a/puppet/modules/site_postfix/files/checks/received_anon +++ b/puppet/modules/site_postfix/files/checks/received_anon @@ -1,2 +1,2 @@ -/^Received: from (.* \([-._[:alnum:]]+ \[[.[:digit:]]{7,15}\]\))([[:space:]]+).*(\(using [.[:alnum:]]+ with cipher [-A-Z0-9]+ \([0-9]+\/[0-9]+ bits\)\))[[:space:]]+\(Client CN "([[:alnum:]]+)", Issuer "[[:print:]]+" \(verified OK\)\)[[:space:]]+by ([.[:alnum:]]+) \(([^)]+)\) with (E?SMTPS?A?) id ([A-F[:digit:]]+).*/ +/^Received: from (.* \([-._[:alnum:]]+ \[[.[:digit:]]{7,15}\]\))([[:space:]]+).*(\(using [.[:alnum:]]+ with cipher [-A-Z0-9]+ \([0-9]+\/[0-9]+ bits\)\))[[:space:]]+\(Client CN "([-._@[:alnum:]]+)", Issuer "[[:print:]]+" \(verified OK\)\)[[:space:]]+by ([.[:alnum:]]+) \(([^)]+)\) with (E?SMTPS?A?) id ([A-F[:digit:]]+).*/ REPLACE Received: from [127.0.0.1] (localhost [127.0.0.1])${2}${3}${2}(Authenticated sender: $4)${2}with $7 id $8 diff --git a/puppet/modules/site_postfix/manifests/mx.pp b/puppet/modules/site_postfix/manifests/mx.pp index 49692d24..c269946b 100644 --- a/puppet/modules/site_postfix/manifests/mx.pp +++ b/puppet/modules/site_postfix/manifests/mx.pp @@ -7,10 +7,12 @@ class site_postfix::mx { $domain = $domain_hash['full_suffix'] $host_domain = $domain_hash['full'] $cert_name = hiera('name') - $mynetworks = join(hiera('mynetworks'), ' ') + $mynetworks = join(hiera('mynetworks', ''), ' ') + $rbls = suffix(prefix(hiera('rbls', []), 'reject_rbl_client '), ',') - $root_mail_recipient = hiera('contacts') - $postfix_smtp_listen = 'all' + $root_mail_recipient = hiera('contacts') + $postfix_smtp_listen = 'all' + $postfix_use_postscreen = 'yes' include site_config::x509::cert include site_config::x509::key @@ -20,20 +22,41 @@ class site_postfix::mx { postfix::config { 'mynetworks': value => "127.0.0.0/8 [::1]/128 [fe80::]/64 ${mynetworks}"; + # Note: mydestination should not include @domain, because this is + # used in virtual alias maps. 'mydestination': - value => "\$myorigin, localhost, localhost.\$mydomain, ${domain}"; + value => "\$myorigin, localhost, localhost.\$mydomain"; 'myhostname': value => $host_domain; 'mailbox_size_limit': value => '0'; 'home_mailbox': - value => 'Maildir/'; + value => ''; + 'virtual_mailbox_domains': + value => 'deliver.local'; + 'virtual_mailbox_base': + value => '/var/mail/leap-mx'; + 'virtual_mailbox_maps': + value => 'static:Maildir/'; + # Note: virtual-aliases map will take precedence over leap-mx + # lookup (tcp:localhost) 'virtual_alias_maps': - value => 'tcp:localhost:4242'; + value => 'hash:/etc/postfix/virtual-aliases tcp:localhost:4242'; 'luser_relay': - value => 'vmail'; - 'smtpd_tls_received_header': - value => 'yes'; + value => ''; + # uid and gid are set to an arbitrary hard-coded value here, this + # must match the 'leap-mx' user/group + 'virtual_uid_maps': + value => 'static:42424'; + 'virtual_gid_maps': + value => 'static:42424'; + # the two following configs are needed for matching user's client cert + # fingerprints to enable relaying (#3634). Satellites do not have + # these configured. + 'smtpd_tls_fingerprint_digest': + value => 'sha1'; + 'relay_clientcerts': + value => 'tcp:localhost:2424'; # Note: we are setting this here, instead of in site_postfix::mx::smtp_tls # because the satellites need to have a different value 'smtp_tls_security_level': @@ -44,40 +67,86 @@ class site_postfix::mx { # alias map 'local_recipient_maps': value => '$alias_maps'; + # setup clamav and opendkim on smtpd + 'smtpd_milters': + value => 'unix:/run/clamav/milter.ctl,inet:localhost:8891'; + # setup opendkim for smtp (non-smtpd) outgoing mail + 'non_smtpd_milters': + value => 'inet:localhost:8891'; + 'milter_default_action': + value => 'accept'; + # Make sure that the right values are set, these could be set to different + # things on install, depending on preseed or debconf options + # selected (see #7478) + 'relay_transport': + value => 'relay'; + 'default_transport': + value => 'smtp'; + 'mailbox_command': + value => ''; + 'header_checks': + value => ''; + 'postscreen_access_list': + value => 'permit_mynetworks'; + 'postscreen_greet_action': + value => 'enforce'; } - include site_postfix::mx::smtpd_checks - include site_postfix::mx::checks - include site_postfix::mx::smtp_tls - include site_postfix::mx::smtpd_tls - include site_postfix::mx::reserved_aliases + # Make sure that the cleanup serivce is not chrooted, otherwise it cannot + # access the opendkim milter socket (#8020) + exec { 'unset_cleanup_chroot': + command => '/usr/sbin/postconf -F "cleanup/unix/chroot=n"', + onlyif => '/usr/sbin/postconf -h -F "cleanup/unix/chroot" | egrep -q ^n', + notify => Service['postfix'], + require => File['/etc/postfix/master.cf'] + } + + include ::site_postfix::mx::smtpd_checks + include ::site_postfix::mx::checks + include ::site_postfix::mx::smtp_tls + include ::site_postfix::mx::smtpd_tls + include ::site_postfix::mx::static_aliases + include ::site_postfix::mx::rewrite_openpgp_header + include ::site_postfix::mx::received_anon + include ::clamav + include ::opendkim + include ::postfwd # greater verbosity for debugging, take out for production #include site_postfix::debug - user { 'vmail': - ensure => present, - comment => 'Leap Mailspool', - home => '/var/mail/vmail', - shell => '/bin/false', - managehome => true, + case $::operatingsystemrelease { + /^7.*/: { + $smtpd_relay_restrictions='' + } + default: { + $smtpd_relay_restrictions=" -o smtpd_relay_restrictions=\$smtps_relay_restrictions\n" + } } + $mastercf_tail = " +smtps inet n - - - - smtpd + -o smtpd_tls_wrappermode=yes + -o smtpd_tls_security_level=encrypt + -o tls_preempt_cipherlist=yes +${smtpd_relay_restrictions} -o smtpd_recipient_restrictions=\$smtps_recipient_restrictions + -o smtpd_helo_restrictions=\$smtps_helo_restrictions + -o smtpd_client_restrictions= + -o cleanup_service_name=clean_smtps +clean_smtps unix n - n - 0 cleanup + -o header_checks=pcre:/etc/postfix/checks/rewrite_openpgp_headers,pcre:/etc/postfix/checks/received_anon" + class { 'postfix': preseed => true, root_mail_recipient => $root_mail_recipient, smtp_listen => 'all', - mastercf_tail => - "smtps inet n - - - - smtpd - -o smtpd_tls_wrappermode=yes - -o smtpd_tls_security_level=encrypt - -o smtpd_recipient_restrictions=\$smtps_recipient_restrictions - -o smtpd_helo_restrictions=\$smtps_helo_restrictions", + mastercf_tail => $mastercf_tail, + use_postscreen => 'yes', require => [ Class['Site_config::X509::Key'], Class['Site_config::X509::Cert'], Class['Site_config::X509::Client_ca::Key'], Class['Site_config::X509::Client_ca::Ca'], - User['vmail'] ] + User['leap-mx'] ] } } diff --git a/puppet/modules/site_postfix/manifests/mx/checks.pp b/puppet/modules/site_postfix/manifests/mx/checks.pp index 5d75a5e5..f406ad34 100644 --- a/puppet/modules/site_postfix/manifests/mx/checks.pp +++ b/puppet/modules/site_postfix/manifests/mx/checks.pp @@ -20,22 +20,4 @@ class site_postfix::mx::checks { refreshonly => true, subscribe => File['/etc/postfix/checks/helo_checks']; } - - # Anonymize the user's home IP from the email headers (Feature #3866) - package { 'postfix-pcre': ensure => installed, require => Package['postfix'] } - - file { '/etc/postfix/checks/received_anon': - source => 'puppet:///modules/site_postfix/checks/received_anon', - mode => '0644', - owner => root, - group => root, - notify => Service['postfix'] - } - - postfix::config { - 'header_checks': - value => 'pcre:/etc/postfix/checks/received_anon', - require => File['/etc/postfix/checks/received_anon']; - } - } diff --git a/puppet/modules/site_postfix/manifests/mx/received_anon.pp b/puppet/modules/site_postfix/manifests/mx/received_anon.pp new file mode 100644 index 00000000..51ba3faa --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/received_anon.pp @@ -0,0 +1,13 @@ +# Anonymize the user's home IP from the email headers (Feature #3866) +class site_postfix::mx::received_anon { + + package { 'postfix-pcre': ensure => installed, require => Package['postfix'] } + + file { '/etc/postfix/checks/received_anon': + source => 'puppet:///modules/site_postfix/checks/received_anon', + mode => '0644', + owner => root, + group => root, + notify => Service['postfix'] + } +} diff --git a/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp b/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp deleted file mode 100644 index 83e27376..00000000 --- a/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp +++ /dev/null @@ -1,15 +0,0 @@ -# Defines which mail addresses shouldn't be available and where they should fwd -class site_postfix::mx::reserved_aliases { - - postfix::mailalias { - [ 'abuse', 'admin', 'arin-admin', 'administrator', 'bin', 'cron', - 'certmaster', 'domainadmin', 'games', 'ftp', 'hostmaster', 'lp', - 'maildrop', 'mysql', 'news', 'nobody', 'noc', 'postmaster', 'postgresql', - 'security', 'ssladmin', 'sys', 'usenet', 'uucp', 'webmaster', 'www', - 'www-data', - ]: - ensure => present, - recipient => 'root' - } - -} diff --git a/puppet/modules/site_postfix/manifests/mx/rewrite_openpgp_header.pp b/puppet/modules/site_postfix/manifests/mx/rewrite_openpgp_header.pp new file mode 100644 index 00000000..71f945b8 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/rewrite_openpgp_header.pp @@ -0,0 +1,11 @@ +class site_postfix::mx::rewrite_openpgp_header { + $mx = hiera('mx') + $correct_domain = $mx['key_lookup_domain'] + + file { '/etc/postfix/checks/rewrite_openpgp_headers': + content => template('site_postfix/checks/rewrite_openpgp_headers.erb'), + mode => '0644', + owner => root, + group => root; + } +} diff --git a/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp b/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp index d56f6b54..c93c3ba2 100644 --- a/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp +++ b/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp @@ -1,11 +1,16 @@ +# configure smtp tls class site_postfix::mx::smtp_tls { include site_config::x509::ca include x509::variables + $cert_name = hiera('name') $ca_path = "${x509::variables::local_CAs}/${site_config::params::ca_name}.crt" $cert_path = "${x509::variables::certs}/${site_config::params::cert_name}.crt" $key_path = "${x509::variables::keys}/${site_config::params::cert_name}.key" + include site_config::x509::cert + include site_config::x509::key + # smtp TLS postfix::config { 'smtp_use_tls': value => 'yes'; @@ -20,9 +25,19 @@ class site_postfix::mx::smtp_tls { 'smtp_tls_fingerprint_digest': value => 'sha1'; 'smtp_tls_session_cache_database': - value => 'btree:${data_directory}/smtp_cache'; + value => "btree:\${data_directory}/smtp_cache"; # see issue #4011 'smtp_tls_protocols': value => '!SSLv2, !SSLv3'; + 'smtp_tls_mandatory_protocols': + value => '!SSLv2, !SSLv3'; + 'tls_ssl_options': + value => 'NO_COMPRESSION'; + # We can switch between the different postfix internal list of ciphers by + # using smtpd_tls_ciphers. For server-to-server connections we leave this + # at its default because of opportunistic encryption combined with many mail + # servers only support outdated protocols and ciphers and if we are too + # strict with required ciphers, then connections *will* fall-back to + # plain-text. Bad ciphers are still better than plain text transmission. } } diff --git a/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp b/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp index 0ec40277..291d7ee4 100644 --- a/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp +++ b/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp @@ -1,3 +1,5 @@ +# smtpd checks for incoming mail on smtp port 25 and +# mail sent via the bitmask client using smtps port 465 class site_postfix::mx::smtpd_checks { postfix::config { @@ -6,7 +8,7 @@ class site_postfix::mx::smtpd_checks { 'checks_dir': value => '$config_directory/checks'; 'smtpd_client_restrictions': - value => 'permit_mynetworks,permit'; + value => "permit_mynetworks,${site_postfix::mx::rbls},permit"; 'smtpd_data_restrictions': value => 'permit_mynetworks, reject_unauth_pipelining, permit'; 'smtpd_delay_reject': @@ -15,13 +17,16 @@ class site_postfix::mx::smtpd_checks { value => 'permit_mynetworks, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, check_helo_access hash:$checks_dir/helo_checks, permit'; 'smtpd_recipient_restrictions': value => 'reject_unknown_recipient_domain, permit_mynetworks, check_recipient_access tcp:localhost:2244, reject_unauth_destination, permit'; - # We should change from permit_tls_all_clientcerts to permit_tls_clientcerts - # with a lookup on $relay_clientcerts! Right now we are listing the only - # valid CA that client certificates can use in the $smtp_tls_CAfile parameter - # but we cannot cut off a certificate that should no longer be used unless - # we use permit_tls_clientcerts with the $relay_clientcerts lookup + + # permit_tls_clientcerts will lookup client cert fingerprints from the tcp + # lookup on port 2424 (based on what is configured in relay_clientcerts + # paramter, see site_postfix::mx postfix::config resource) to determine + # if a client is allowed to relay mail through us. This enables us to + # disable a user by removing their valid client cert (#3634) 'smtps_recipient_restrictions': - value => 'permit_tls_all_clientcerts, check_recipient_access tcp:localhost:2244, reject_unauth_destination, permit'; + value => 'permit_tls_clientcerts, check_recipient_access tcp:localhost:2244, reject_unauth_destination, permit'; + 'smtps_relay_restrictions': + value => 'permit_mynetworks, permit_tls_clientcerts, defer_unauth_destination'; 'smtps_helo_restrictions': value => 'permit_mynetworks, check_helo_access hash:$checks_dir/helo_checks, permit'; 'smtpd_sender_restrictions': diff --git a/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp b/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp index 0809c75f..66297f55 100644 --- a/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp +++ b/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp @@ -1,3 +1,4 @@ +# configure smtpd tls class site_postfix::mx::smtpd_tls { include x509::variables @@ -12,12 +13,25 @@ class site_postfix::mx::smtpd_tls { 'smtpd_tls_cert_file': value => $cert_path; 'smtpd_tls_key_file': value => $key_path; 'smtpd_tls_ask_ccert': value => 'yes'; + 'smtpd_tls_received_header': + value => 'yes'; 'smtpd_tls_security_level': value => 'may'; 'smtpd_tls_eecdh_grade': value => 'ultra'; 'smtpd_tls_session_cache_database': - value => 'btree:${data_directory}/smtpd_scache'; + value => "btree:\${data_directory}/smtpd_scache"; + # see issue #4011 + 'smtpd_tls_mandatory_protocols': + value => '!SSLv2, !SSLv3'; + 'smtpd_tls_protocols': + value => '!SSLv2, !SSLv3'; + # For connections to MUAs, TLS is mandatory and the ciphersuite is modified. + # MX and SMTP client configuration + 'smtpd_tls_mandatory_ciphers': + value => 'high'; + 'tls_high_cipherlist': + value => '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:!3DES:!RC4:!MD5:!PSK!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; } # Setup DH parameters diff --git a/puppet/modules/site_postfix/manifests/mx/static_aliases.pp b/puppet/modules/site_postfix/manifests/mx/static_aliases.pp new file mode 100644 index 00000000..9cd7ca02 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/static_aliases.pp @@ -0,0 +1,88 @@ +# +# Defines static, hard coded aliases that are not in the database. +# These aliases take precedence over the database aliases. +# +# There are three classes of reserved names: +# +# (1) forbidden_usernames: +# Some usernames are forbidden and cannot be registered. +# this is defined in node property webapp.forbidden_usernames +# This is enforced by the webapp. +# +# (2) public aliases: +# Some aliases for root, and are publicly exposed so that anyone +# can deliver mail to them. For example, postmaster. +# These are implemented in the virtual alias map, which takes +# precedence over the local alias map. +# +# (3) local aliases: +# Some aliases are only available locally: mail can be delivered +# to the alias if the mail originates from the local host, or is +# hostname qualified, but otherwise it will be rejected. +# These are implemented in the local alias map. +# +# The alias for local 'root' is defined elsewhere. In this file, we +# define the virtual 'root@domain' (which can be overwritten by +# defining an entry for root in node property mx.aliases). +# + +class site_postfix::mx::static_aliases { + + $mx = hiera('mx') + $root_recipients = hiera('contacts') + + # + # LOCAL ALIASES + # + + # NOTE: if you remove one of these, they will still appear in the + # /etc/aliases file + $local_aliases = [ + 'admin', 'administrator', 'bin', 'cron', 'games', 'ftp', 'lp', 'maildrop', + 'mysql', 'news', 'nobody', 'noc', 'postgresql', 'ssladmin', 'sys', + 'usenet', 'uucp', 'www', 'www-data', 'leap-mx' + ] + + postfix::mailalias { + $local_aliases: + ensure => present, + recipient => 'root' + } + + # + # PUBLIC ALIASES + # + + $public_aliases = $mx['aliases'] + + $default_public_aliases = { + 'root' => $root_recipients, + 'abuse' => 'postmaster', + 'arin-admin' => 'root', + 'certmaster' => 'hostmaster', + 'domainadmin' => 'hostmaster', + 'hostmaster' => 'root', + 'mailer-daemon' => 'postmaster', + 'postmaster' => 'root', + 'security' => 'root', + 'webmaster' => 'hostmaster', + } + + $aliases = merge($default_public_aliases, $public_aliases) + + exec { 'postmap_virtual_aliases': + command => '/usr/sbin/postmap /etc/postfix/virtual-aliases', + refreshonly => true, + user => root, + group => root, + require => Package['postfix'], + subscribe => File['/etc/postfix/virtual-aliases'] + } + file { '/etc/postfix/virtual-aliases': + content => template('site_postfix/virtual-aliases.erb'), + owner => root, + group => root, + mode => '0600', + require => Package['postfix'] + } +} diff --git a/puppet/modules/site_postfix/templates/checks/helo_access.erb b/puppet/modules/site_postfix/templates/checks/helo_access.erb index bef3c11d..bac2c45a 100644 --- a/puppet/modules/site_postfix/templates/checks/helo_access.erb +++ b/puppet/modules/site_postfix/templates/checks/helo_access.erb @@ -18,4 +18,4 @@ # Reject anybody that HELO's as being in our own domain(s) # anyone who identifies themselves as us is a virus/spammer -<%= domain %> 554 You are not in domain <%= domain %> +<%= @domain %> 554 You are not in domain <%= @domain %> diff --git a/puppet/modules/site_postfix/templates/checks/rewrite_openpgp_headers.erb b/puppet/modules/site_postfix/templates/checks/rewrite_openpgp_headers.erb new file mode 100644 index 00000000..7af14f7d --- /dev/null +++ b/puppet/modules/site_postfix/templates/checks/rewrite_openpgp_headers.erb @@ -0,0 +1,13 @@ +# THIS FILE IS MANAGED BY PUPPET +# +# This will replace the OpenPGP header that the client adds, because it is +# sometimes incorrect (due to the client not always knowing what the proper URL +# is for the webapp). +# e.g. This will rewrite this header: +# OpenPGP: id=4C0E01CD50E2F653; url="https://leap.se/key/elijah"; preference="signencrypt +# with this replacement: +# OpenPGP: id=4C0E01CD50E2F653; url="https://user.leap.se/key/elijah"; preference="signencrypt +# +# Note: whitespace in the pattern is represented by [[:space:]] to avoid these warnings from postmap: +# "record is in "key: value" format; is this an alias file?" and "duplicate entry" +/^(OpenPGP:[[:space:]]id=[[:alnum:]]+;[[:space:]]url="https:\/\/)<%= @domain %>(\/key\/[[:alpha:]]+";.*)/i REPLACE ${1}<%= @correct_domain %>${2} diff --git a/puppet/modules/site_postfix/templates/virtual-aliases.erb b/puppet/modules/site_postfix/templates/virtual-aliases.erb new file mode 100644 index 00000000..8373de97 --- /dev/null +++ b/puppet/modules/site_postfix/templates/virtual-aliases.erb @@ -0,0 +1,21 @@ +# +# This file is managed by puppet. +# +# These virtual aliases take precedence over all other aliases. +# + +# +# enable these virtual domains: +# +<%= @domain %> enabled +<%- @aliases.keys.map {|addr| addr.split('@')[1] }.compact.sort.uniq.each do |virt_domain| -%> +<%= virt_domain %> enabled +<%- end %> + +# +# virtual aliases: +# +<%- @aliases.keys.sort.each do |from| -%> +<%- full_address = from =~ /@/ ? from : from + "@" + @domain -%> +<%= full_address %> <%= [@aliases[from]].flatten.map{|a| a =~ /@/ ? a : a + "@" + @domain}.join(', ') %> +<%- end -%> |