blob: 35cd79012858531a4b6ed1a7af6d78d1d28159f0 [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001#!/bin/bash
2
3trap "postfix stop" EXIT
4
5[[ ! -d /opt/postfix/conf/sql/ ]] && mkdir -p /opt/postfix/conf/sql/
6
7# Wait for MySQL to warm-up
8while ! mysqladmin status --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
9 echo "Waiting for database to come up..."
10 sleep 2
11done
12
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020013until dig +short mailcow.email > /dev/null; do
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010014 echo "Waiting for DNS..."
15 sleep 1
16done
17
18cat <<EOF > /etc/aliases
19# Autogenerated by mailcow
20null: /dev/null
21watchdog: /dev/null
22ham: "|/usr/local/bin/rspamd-pipe-ham"
23spam: "|/usr/local/bin/rspamd-pipe-spam"
24EOF
25newaliases;
26
27# create sni configuration
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020028if [[ "${SKIP_LETS_ENCRYPT}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
29 echo -n "" > /opt/postfix/conf/sni.map
30else
31 echo -n "" > /opt/postfix/conf/sni.map;
32 for cert_dir in /etc/ssl/mail/*/ ; do
33 if [[ ! -f ${cert_dir}domains ]] || [[ ! -f ${cert_dir}cert.pem ]] || [[ ! -f ${cert_dir}key.pem ]]; then
34 continue;
35 fi
36 IFS=" " read -r -a domains <<< "$(cat "${cert_dir}domains")"
37 for domain in "${domains[@]}"; do
38 echo -n "${domain} ${cert_dir}key.pem ${cert_dir}cert.pem" >> /opt/postfix/conf/sni.map;
39 echo "" >> /opt/postfix/conf/sni.map;
40 done
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010041 done
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020042fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010043postmap -F hash:/opt/postfix/conf/sni.map;
44
45cat <<EOF > /opt/postfix/conf/sql/mysql_relay_ne.cf
46# Autogenerated by mailcow
47user = ${DBUSER}
48password = ${DBPASS}
49hosts = unix:/var/run/mysqld/mysqld.sock
50dbname = ${DBNAME}
51query = SELECT IF(EXISTS(SELECT address, domain FROM alias
52 WHERE address = '%s'
53 AND domain IN (
54 SELECT domain FROM domain
55 WHERE backupmx = '1'
56 AND relay_all_recipients = '1'
57 AND relay_unknown_only = '1')
58
59 ), 'lmtp:inet:dovecot:24', NULL) AS 'transport'
60EOF
61
62cat <<EOF > /opt/postfix/conf/sql/mysql_relay_recipient_maps.cf
63# Autogenerated by mailcow
64user = ${DBUSER}
65password = ${DBPASS}
66hosts = unix:/var/run/mysqld/mysqld.sock
67dbname = ${DBNAME}
68query = SELECT DISTINCT
69 CASE WHEN '%d' IN (
70 SELECT domain FROM domain
71 WHERE relay_all_recipients=1
72 AND domain='%d'
73 AND backupmx=1
74 )
75 THEN '%s' ELSE (
76 SELECT goto FROM alias WHERE address='%s' AND active='1'
77 )
78 END AS result;
79EOF
80
81cat <<EOF > /opt/postfix/conf/sql/mysql_tls_policy_override_maps.cf
82# Autogenerated by mailcow
83user = ${DBUSER}
84password = ${DBPASS}
85hosts = unix:/var/run/mysqld/mysqld.sock
86dbname = ${DBNAME}
87query = SELECT CONCAT(policy, ' ', parameters) AS tls_policy FROM tls_policy_override WHERE active = '1' AND dest = '%s'
88EOF
89
90cat <<EOF > /opt/postfix/conf/sql/mysql_tls_enforce_in_policy.cf
91# Autogenerated by mailcow
92user = ${DBUSER}
93password = ${DBPASS}
94hosts = unix:/var/run/mysqld/mysqld.sock
95dbname = ${DBNAME}
96query = SELECT IF(EXISTS(
97 SELECT 'TLS_ACTIVE' FROM alias
98 LEFT OUTER JOIN mailbox ON mailbox.username = alias.goto
99 WHERE (address='%s'
100 OR address IN (
101 SELECT CONCAT('%u', '@', target_domain) FROM alias_domain
102 WHERE alias_domain='%d'
103 )
104 ) AND JSON_UNQUOTE(JSON_VALUE(attributes, '$.tls_enforce_in')) = '1' AND mailbox.active = '1'
105 ), 'reject_plaintext_session', NULL) AS 'tls_enforce_in';
106EOF
107
108cat <<EOF > /opt/postfix/conf/sql/mysql_sender_dependent_default_transport_maps.cf
109# Autogenerated by mailcow
110user = ${DBUSER}
111password = ${DBPASS}
112hosts = unix:/var/run/mysqld/mysqld.sock
113dbname = ${DBNAME}
114query = SELECT GROUP_CONCAT(transport SEPARATOR '') AS transport_maps
115 FROM (
116 SELECT IF(EXISTS(SELECT 'smtp_type' FROM alias
117 LEFT OUTER JOIN mailbox ON mailbox.username = alias.goto
118 WHERE (address = '%s'
119 OR address IN (
120 SELECT CONCAT('%u', '@', target_domain) FROM alias_domain
121 WHERE alias_domain = '%d'
122 )
123 )
124 AND JSON_UNQUOTE(JSON_VALUE(attributes, '$.tls_enforce_out')) = '1'
125 AND mailbox.active = '1'
126 ), 'smtp_enforced_tls:', 'smtp:') AS 'transport'
127 UNION ALL
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200128 SELECT COALESCE(
129 (SELECT hostname FROM relayhosts
130 LEFT OUTER JOIN mailbox ON JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.relayhost')) = relayhosts.id
131 WHERE relayhosts.active = '1'
132 AND (
133 mailbox.username IN (SELECT alias.goto from alias
134 JOIN mailbox ON mailbox.username = alias.goto
135 WHERE alias.active = '1'
136 AND alias.address = '%s'
137 AND alias.address NOT LIKE '@%%'
138 )
139 )
140 ),
141 (SELECT hostname FROM relayhosts
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100142 LEFT OUTER JOIN domain ON domain.relayhost = relayhosts.id
143 WHERE relayhosts.active = '1'
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200144 AND (domain.domain = '%d'
145 OR domain.domain IN (
146 SELECT target_domain FROM alias_domain
147 WHERE alias_domain = '%d'
148 )
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100149 )
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200150 )
151 )
152 ) AS transport_view;
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100153EOF
154
155cat <<EOF > /opt/postfix/conf/sql/mysql_transport_maps.cf
156# Autogenerated by mailcow
157user = ${DBUSER}
158password = ${DBPASS}
159hosts = unix:/var/run/mysqld/mysqld.sock
160dbname = ${DBNAME}
161query = SELECT CONCAT('smtp_via_transport_maps:', nexthop) AS transport FROM transports
162 WHERE active = '1'
163 AND destination = '%s';
164EOF
165
166cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_resource_maps.cf
167# Autogenerated by mailcow
168user = ${DBUSER}
169password = ${DBPASS}
170hosts = unix:/var/run/mysqld/mysqld.sock
171dbname = ${DBNAME}
172query = SELECT 'null@localhost' FROM mailbox
173 WHERE kind REGEXP 'location|thing|group' AND username = '%s';
174EOF
175
176cat <<EOF > /opt/postfix/conf/sql/mysql_sasl_passwd_maps_sender_dependent.cf
177# Autogenerated by mailcow
178user = ${DBUSER}
179password = ${DBPASS}
180hosts = unix:/var/run/mysqld/mysqld.sock
181dbname = ${DBNAME}
182query = SELECT CONCAT_WS(':', username, password) AS auth_data FROM relayhosts
183 WHERE id IN (
184 SELECT relayhost FROM domain
185 WHERE CONCAT('@', domain) = '%s'
186 OR domain IN (
187 SELECT target_domain FROM alias_domain WHERE CONCAT('@', alias_domain) = '%s'
188 )
189 )
190 AND active = '1'
191 AND username != '';
192EOF
193
194cat <<EOF > /opt/postfix/conf/sql/mysql_sasl_passwd_maps_transport_maps.cf
195# Autogenerated by mailcow
196user = ${DBUSER}
197password = ${DBPASS}
198hosts = unix:/var/run/mysqld/mysqld.sock
199dbname = ${DBNAME}
200query = SELECT CONCAT_WS(':', username, password) AS auth_data FROM transports
201 WHERE nexthop = '%s'
202 AND active = '1'
203 AND username != ''
204 LIMIT 1;
205EOF
206
207cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_domain_maps.cf
208# Autogenerated by mailcow
209user = ${DBUSER}
210password = ${DBPASS}
211hosts = unix:/var/run/mysqld/mysqld.sock
212dbname = ${DBNAME}
213query = SELECT username FROM mailbox, alias_domain
214 WHERE alias_domain.alias_domain = '%d'
215 AND mailbox.username = CONCAT('%u', '@', alias_domain.target_domain)
216 AND (mailbox.active = '1' OR mailbox.active = '2')
217 AND alias_domain.active='1'
218EOF
219
220cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_maps.cf
221# Autogenerated by mailcow
222user = ${DBUSER}
223password = ${DBPASS}
224hosts = unix:/var/run/mysqld/mysqld.sock
225dbname = ${DBNAME}
226query = SELECT goto FROM alias
227 WHERE address='%s'
228 AND (active='1' OR active='2');
229EOF
230
231cat <<EOF > /opt/postfix/conf/sql/mysql_recipient_bcc_maps.cf
232# Autogenerated by mailcow
233user = ${DBUSER}
234password = ${DBPASS}
235hosts = unix:/var/run/mysqld/mysqld.sock
236dbname = ${DBNAME}
237query = SELECT bcc_dest FROM bcc_maps
238 WHERE local_dest='%s'
239 AND type='rcpt'
240 AND active='1';
241EOF
242
243cat <<EOF > /opt/postfix/conf/sql/mysql_sender_bcc_maps.cf
244# Autogenerated by mailcow
245user = ${DBUSER}
246password = ${DBPASS}
247hosts = unix:/var/run/mysqld/mysqld.sock
248dbname = ${DBNAME}
249query = SELECT bcc_dest FROM bcc_maps
250 WHERE local_dest='%s'
251 AND type='sender'
252 AND active='1';
253EOF
254
255cat <<EOF > /opt/postfix/conf/sql/mysql_recipient_canonical_maps.cf
256# Autogenerated by mailcow
257user = ${DBUSER}
258password = ${DBPASS}
259hosts = unix:/var/run/mysqld/mysqld.sock
260dbname = ${DBNAME}
261query = SELECT new_dest FROM recipient_maps
262 WHERE old_dest='%s'
263 AND active='1';
264EOF
265
266cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_domains_maps.cf
267# Autogenerated by mailcow
268user = ${DBUSER}
269password = ${DBPASS}
270hosts = unix:/var/run/mysqld/mysqld.sock
271dbname = ${DBNAME}
272query = SELECT alias_domain from alias_domain WHERE alias_domain='%s' AND active='1'
273 UNION
274 SELECT domain FROM domain
275 WHERE domain='%s'
276 AND active = '1'
277 AND backupmx = '0'
278EOF
279
280cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_mailbox_maps.cf
281# Autogenerated by mailcow
282user = ${DBUSER}
283password = ${DBPASS}
284hosts = unix:/var/run/mysqld/mysqld.sock
285dbname = ${DBNAME}
286query = SELECT CONCAT(JSON_UNQUOTE(JSON_VALUE(attributes, '$.mailbox_format')), mailbox_path_prefix, '%d/%u/') FROM mailbox WHERE username='%s' AND (active = '1' OR active = '2')
287EOF
288
289cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_relay_domain_maps.cf
290# Autogenerated by mailcow
291user = ${DBUSER}
292password = ${DBPASS}
293hosts = unix:/var/run/mysqld/mysqld.sock
294dbname = ${DBNAME}
295query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '1' AND active = '1'
296EOF
297
298cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_sender_acl.cf
299# Autogenerated by mailcow
300user = ${DBUSER}
301password = ${DBPASS}
302hosts = unix:/var/run/mysqld/mysqld.sock
303dbname = ${DBNAME}
304# First select queries domain and alias_domain to determine if domains are active.
305query = SELECT goto FROM alias
306 WHERE address='%s'
307 AND active='1'
308 AND (domain IN
309 (SELECT domain FROM domain
310 WHERE domain='%d'
311 AND active='1')
312 OR domain in (
313 SELECT alias_domain FROM alias_domain
314 WHERE alias_domain='%d'
315 AND active='1'
316 )
317 )
318 UNION
319 SELECT logged_in_as FROM sender_acl
320 WHERE send_as='@%d'
321 OR send_as='%s'
322 OR send_as='*'
323 OR send_as IN (
324 SELECT CONCAT('@',target_domain) FROM alias_domain
325 WHERE alias_domain = '%d')
326 OR send_as IN (
327 SELECT CONCAT('%u','@',target_domain) FROM alias_domain
328 WHERE alias_domain = '%d')
329 AND logged_in_as NOT IN (
330 SELECT goto FROM alias
331 WHERE address='%s')
332 UNION
333 SELECT username FROM mailbox, alias_domain
334 WHERE alias_domain.alias_domain = '%d'
335 AND mailbox.username = CONCAT('%u','@',alias_domain.target_domain)
336 AND (mailbox.active = '1' OR mailbox.active ='2')
337 AND alias_domain.active='1'
338EOF
339
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200340# MX based routing
341cat <<EOF > /opt/postfix/conf/sql/mysql_mbr_access_maps.cf
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100342# Autogenerated by mailcow
343user = ${DBUSER}
344password = ${DBPASS}
345hosts = unix:/var/run/mysqld/mysqld.sock
346dbname = ${DBNAME}
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200347query = SELECT CONCAT('FILTER smtp_via_transport_maps:', nexthop) as transport FROM transports
348 WHERE '%s' REGEXP destination
349 AND active='1'
350 AND is_mx_based='1';
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100351EOF
352
353cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_spamalias_maps.cf
354# Autogenerated by mailcow
355user = ${DBUSER}
356password = ${DBPASS}
357hosts = unix:/var/run/mysqld/mysqld.sock
358dbname = ${DBNAME}
359query = SELECT goto FROM spamalias
360 WHERE address='%s'
361 AND validity >= UNIX_TIMESTAMP()
362EOF
363
364sed -i '/User overrides/q' /opt/postfix/conf/main.cf
365echo >> /opt/postfix/conf/main.cf
366touch /opt/postfix/conf/extra.cf
367sed -i '/myhostname/d' /opt/postfix/conf/extra.cf
368echo -e "myhostname = ${MAILCOW_HOSTNAME}\n$(cat /opt/postfix/conf/extra.cf)" > /opt/postfix/conf/extra.cf
369
370cat /opt/postfix/conf/extra.cf >> /opt/postfix/conf/main.cf
371
372if [ ! -f /opt/postfix/conf/custom_transport.pcre ]; then
373 echo "Creating dummy custom_transport.pcre"
374 touch /opt/postfix/conf/custom_transport.pcre
375fi
376
377if [[ ! -f /opt/postfix/conf/custom_postscreen_whitelist.cidr ]]; then
378 echo "Creating dummy custom_postscreen_whitelist.cidr"
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200379 cat <<EOF > /opt/postfix/conf/custom_postscreen_whitelist.cidr
380# Autogenerated by mailcow
381# Rules are evaluated in the order as specified.
382# Blacklist 192.168.* except 192.168.0.1.
383# 192.168.0.1 permit
384# 192.168.0.0/16 reject
385EOF
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100386fi
387
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100388# Fix Postfix permissions
389chown -R root:postfix /opt/postfix/conf/sql/ /opt/postfix/conf/custom_transport.pcre
390chmod 640 /opt/postfix/conf/sql/*.cf /opt/postfix/conf/custom_transport.pcre
391chgrp -R postdrop /var/spool/postfix/public
392chgrp -R postdrop /var/spool/postfix/maildrop
393postfix set-permissions
394
395# Check Postfix configuration
396postconf -c /opt/postfix/conf > /dev/null
397
398if [[ $? != 0 ]]; then
399 echo "Postfix configuration error, refusing to start."
400 exit 1
401else
402 postfix -c /opt/postfix/conf start
403 sleep 126144000
404fi