blob: e734a9ab36dfbca3203e7c6e658f971b3ab7abe5 [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 (
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100184 SELECT COALESCE(
185 (SELECT id FROM relayhosts
186 LEFT OUTER JOIN domain ON domain.relayhost = relayhosts.id
187 WHERE relayhosts.active = '1'
188 AND (domain.domain = '%d'
189 OR domain.domain IN (
190 SELECT target_domain FROM alias_domain
191 WHERE alias_domain = '%d'
192 )
193 )
194 ),
195 (SELECT id FROM relayhosts
196 LEFT OUTER JOIN mailbox ON JSON_UNQUOTE(JSON_VALUE(mailbox.attributes, '$.relayhost')) = relayhosts.id
197 WHERE relayhosts.active = '1'
198 AND (
199 mailbox.username IN (
200 SELECT alias.goto from alias
201 JOIN mailbox ON mailbox.username = alias.goto
202 WHERE alias.active = '1'
203 AND alias.address = '%s'
204 AND alias.address NOT LIKE '@%%'
205 )
206 )
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100207 )
Matthias Andreas Benkard12a57352021-12-28 18:02:04 +0100208 )
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100209 )
210 AND active = '1'
211 AND username != '';
212EOF
213
214cat <<EOF > /opt/postfix/conf/sql/mysql_sasl_passwd_maps_transport_maps.cf
215# Autogenerated by mailcow
216user = ${DBUSER}
217password = ${DBPASS}
218hosts = unix:/var/run/mysqld/mysqld.sock
219dbname = ${DBNAME}
220query = SELECT CONCAT_WS(':', username, password) AS auth_data FROM transports
221 WHERE nexthop = '%s'
222 AND active = '1'
223 AND username != ''
224 LIMIT 1;
225EOF
226
227cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_domain_maps.cf
228# Autogenerated by mailcow
229user = ${DBUSER}
230password = ${DBPASS}
231hosts = unix:/var/run/mysqld/mysqld.sock
232dbname = ${DBNAME}
233query = SELECT username FROM mailbox, alias_domain
234 WHERE alias_domain.alias_domain = '%d'
235 AND mailbox.username = CONCAT('%u', '@', alias_domain.target_domain)
236 AND (mailbox.active = '1' OR mailbox.active = '2')
237 AND alias_domain.active='1'
238EOF
239
240cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_maps.cf
241# Autogenerated by mailcow
242user = ${DBUSER}
243password = ${DBPASS}
244hosts = unix:/var/run/mysqld/mysqld.sock
245dbname = ${DBNAME}
246query = SELECT goto FROM alias
247 WHERE address='%s'
248 AND (active='1' OR active='2');
249EOF
250
251cat <<EOF > /opt/postfix/conf/sql/mysql_recipient_bcc_maps.cf
252# Autogenerated by mailcow
253user = ${DBUSER}
254password = ${DBPASS}
255hosts = unix:/var/run/mysqld/mysqld.sock
256dbname = ${DBNAME}
257query = SELECT bcc_dest FROM bcc_maps
258 WHERE local_dest='%s'
259 AND type='rcpt'
260 AND active='1';
261EOF
262
263cat <<EOF > /opt/postfix/conf/sql/mysql_sender_bcc_maps.cf
264# Autogenerated by mailcow
265user = ${DBUSER}
266password = ${DBPASS}
267hosts = unix:/var/run/mysqld/mysqld.sock
268dbname = ${DBNAME}
269query = SELECT bcc_dest FROM bcc_maps
270 WHERE local_dest='%s'
271 AND type='sender'
272 AND active='1';
273EOF
274
275cat <<EOF > /opt/postfix/conf/sql/mysql_recipient_canonical_maps.cf
276# Autogenerated by mailcow
277user = ${DBUSER}
278password = ${DBPASS}
279hosts = unix:/var/run/mysqld/mysqld.sock
280dbname = ${DBNAME}
281query = SELECT new_dest FROM recipient_maps
282 WHERE old_dest='%s'
283 AND active='1';
284EOF
285
286cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_domains_maps.cf
287# Autogenerated by mailcow
288user = ${DBUSER}
289password = ${DBPASS}
290hosts = unix:/var/run/mysqld/mysqld.sock
291dbname = ${DBNAME}
292query = SELECT alias_domain from alias_domain WHERE alias_domain='%s' AND active='1'
293 UNION
294 SELECT domain FROM domain
295 WHERE domain='%s'
296 AND active = '1'
297 AND backupmx = '0'
298EOF
299
300cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_mailbox_maps.cf
301# Autogenerated by mailcow
302user = ${DBUSER}
303password = ${DBPASS}
304hosts = unix:/var/run/mysqld/mysqld.sock
305dbname = ${DBNAME}
306query = 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')
307EOF
308
309cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_relay_domain_maps.cf
310# Autogenerated by mailcow
311user = ${DBUSER}
312password = ${DBPASS}
313hosts = unix:/var/run/mysqld/mysqld.sock
314dbname = ${DBNAME}
315query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '1' AND active = '1'
316EOF
317
318cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_sender_acl.cf
319# Autogenerated by mailcow
320user = ${DBUSER}
321password = ${DBPASS}
322hosts = unix:/var/run/mysqld/mysqld.sock
323dbname = ${DBNAME}
324# First select queries domain and alias_domain to determine if domains are active.
325query = SELECT goto FROM alias
326 WHERE address='%s'
327 AND active='1'
328 AND (domain IN
329 (SELECT domain FROM domain
330 WHERE domain='%d'
331 AND active='1')
332 OR domain in (
333 SELECT alias_domain FROM alias_domain
334 WHERE alias_domain='%d'
335 AND active='1'
336 )
337 )
338 UNION
339 SELECT logged_in_as FROM sender_acl
340 WHERE send_as='@%d'
341 OR send_as='%s'
342 OR send_as='*'
343 OR send_as IN (
344 SELECT CONCAT('@',target_domain) FROM alias_domain
345 WHERE alias_domain = '%d')
346 OR send_as IN (
347 SELECT CONCAT('%u','@',target_domain) FROM alias_domain
348 WHERE alias_domain = '%d')
349 AND logged_in_as NOT IN (
350 SELECT goto FROM alias
351 WHERE address='%s')
352 UNION
353 SELECT username FROM mailbox, alias_domain
354 WHERE alias_domain.alias_domain = '%d'
355 AND mailbox.username = CONCAT('%u','@',alias_domain.target_domain)
356 AND (mailbox.active = '1' OR mailbox.active ='2')
357 AND alias_domain.active='1'
358EOF
359
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200360# MX based routing
361cat <<EOF > /opt/postfix/conf/sql/mysql_mbr_access_maps.cf
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100362# Autogenerated by mailcow
363user = ${DBUSER}
364password = ${DBPASS}
365hosts = unix:/var/run/mysqld/mysqld.sock
366dbname = ${DBNAME}
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200367query = SELECT CONCAT('FILTER smtp_via_transport_maps:', nexthop) as transport FROM transports
368 WHERE '%s' REGEXP destination
369 AND active='1'
370 AND is_mx_based='1';
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100371EOF
372
373cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_spamalias_maps.cf
374# Autogenerated by mailcow
375user = ${DBUSER}
376password = ${DBPASS}
377hosts = unix:/var/run/mysqld/mysqld.sock
378dbname = ${DBNAME}
379query = SELECT goto FROM spamalias
380 WHERE address='%s'
381 AND validity >= UNIX_TIMESTAMP()
382EOF
383
384sed -i '/User overrides/q' /opt/postfix/conf/main.cf
385echo >> /opt/postfix/conf/main.cf
386touch /opt/postfix/conf/extra.cf
387sed -i '/myhostname/d' /opt/postfix/conf/extra.cf
388echo -e "myhostname = ${MAILCOW_HOSTNAME}\n$(cat /opt/postfix/conf/extra.cf)" > /opt/postfix/conf/extra.cf
389
390cat /opt/postfix/conf/extra.cf >> /opt/postfix/conf/main.cf
391
392if [ ! -f /opt/postfix/conf/custom_transport.pcre ]; then
393 echo "Creating dummy custom_transport.pcre"
394 touch /opt/postfix/conf/custom_transport.pcre
395fi
396
397if [[ ! -f /opt/postfix/conf/custom_postscreen_whitelist.cidr ]]; then
398 echo "Creating dummy custom_postscreen_whitelist.cidr"
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200399 cat <<EOF > /opt/postfix/conf/custom_postscreen_whitelist.cidr
400# Autogenerated by mailcow
401# Rules are evaluated in the order as specified.
402# Blacklist 192.168.* except 192.168.0.1.
403# 192.168.0.1 permit
404# 192.168.0.0/16 reject
405EOF
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100406fi
407
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100408# Fix Postfix permissions
409chown -R root:postfix /opt/postfix/conf/sql/ /opt/postfix/conf/custom_transport.pcre
410chmod 640 /opt/postfix/conf/sql/*.cf /opt/postfix/conf/custom_transport.pcre
411chgrp -R postdrop /var/spool/postfix/public
412chgrp -R postdrop /var/spool/postfix/maildrop
413postfix set-permissions
414
415# Check Postfix configuration
416postconf -c /opt/postfix/conf > /dev/null
417
418if [[ $? != 0 ]]; then
419 echo "Postfix configuration error, refusing to start."
420 exit 1
421else
422 postfix -c /opt/postfix/conf start
423 sleep 126144000
424fi