-
Notifications
You must be signed in to change notification settings - Fork 5
/
filter
279 lines (239 loc) · 9.89 KB
/
filter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# Exim filter
# Special variables in this file:
# n0/$3 is the counter in the local part prefix, if any.
# n1 idenifies the control command type, or is 0 if not one.
# n2 is the remaining deliveries counter (from the db if present, else the prefix)
# $1 is the alias's prefix ID.
# $3 (on second capture) is the actual control command extracted from the subject.
# This match also captures the alias's prefix in $1, and the counter
# in $3. $local_part retains the alias stem.
if $local_part_prefix does not match "^([^.]+)[.](([0-9]{1,5})[.])?\\$"
then
testprint "not a disposable mail candidate, skipping"
finish
endif
# Sanitize the email counter into a number in n0, which indicates the default remaining
# counter to use if this is the first email seen to this alias. If there was no counter
# $3 will be ''.
# After this we don't need $3
if "$3" is ""
then
# Use the default_remaining config (-1 -> no limit; modify this to change the default remaining)
add "${lookup sqlite{ \
select default_remaining from stem_configs \
where stem = '${quote_sqlite:$local_part}'} \
{$value}{0}}" to n0
testprint "No email infix counter, using configured default_remaining counter $n0"
else
# Use the number from the email
add $3 to n0
testprint "Using email infix counter $n0"
endif
testprint "got a disposable mail candidate infixed with \
${if >{${strlen:$3}}{0}{$n0}{no}} deliveries remaining"
# Is $local_part an existing alias, i.e. does $local_part match a defined alias?
# This match also captures the alias, if known, in $2, whilst preserving $1
# in a somewhat nasty way forced upon us by exim's lack of
# proper variables.
if "${lookup sqlite{ \
select coalesce(group_concat(recipients, ','), '') from aliases \
where stem = '${quote_sqlite:$local_part}'} \
{$1 $value}{}}" does not match "(.*) (.*[[:graph:]].*)"
then
testprint "not a known alias '$local_part', skipping"
finish
endif
testprint "got a known alias '$local_part' for '$2' prefix '$1'"
# Set the logfile for this message
# (Use of per-alias logfiles has been dropped as this is hard since Exim added tainting checks)
logfile DISP_ALIASES_LOGDIR/combined.log
# Is it a control message sent by an authorised user on a safe
# connection? Capture the command in $3, but preserve $1 and
# $2. Use n1 to preserve the conclusion
if "$1 $2 $h_subject" matches "^([^ ]+) ([^ ]+) *[!] *([^ ]+)"
then
testprint "subject might be a control message: '$h_subject:'"
if ($sender_host_address is "" and $authenticated_id is "root")
or "${lookup sqlite{ \
select count(*) from authorised \
where stem = '${quote_sqlite:$local_part}' \
and id = '${quote_sqlite:$authenticated_id}' \
and driver = '${quote_sqlite:$sender_host_authenticated}'}\
{$value}{0}}" is above 0
then
testprint "source looks authenticated, id: '$authenticated_id' host: '$sender_host_address' auth driver: '$sender_host_authenticated'"
# Identify the command, set n1 accordingly
if $3 is "on"
then
add 1 to n1
elif $3 is "off"
then
add 2 to n1
elif "${if match{$3}{[^0-9]}{nonnumeric}{numeric}}" is "numeric"
then
add 3 to n1
elif $3 is "report"
then
testprint "This is a report command on '$1.$local_part'"
logwrite "$tod_log\t$local_part_prefix$local_part\treport\t$sender_address\t$return_path\t$h_subject"
seen mail subject "Disposable mail report for *.$local_part@$domain"
text "${lookup sqlite{ \
select prefix, remaining, delivered, rejected from counters \
where stem = '${quote_sqlite:$local_part}' \
order by prefix} \
{All *.$local_part alias deliveries remaining:\n\
\n$value\n\n\
Note, a count of -1 means all mail will be delivered.} \
{No prefixes defined for '$local_part' yet.}}\n"
finish
else # unknown
testprint "unknown command: '$h_subject:'"
logwrite "$tod_log\t$local_part_prefix$local_part\tinvalid-command\t$sender_address\t$return_path\t$h_subject"
seen mail subject "unknown command"
text "Unknown command:\n[$h_subject:]"
finish
endif
else
testprint "source doesn't look authenticated, id: '$authenticated_id' host: '$sender_host_address' auth driver: '$sender_host_authenticated'"
endif
endif
# Get the remaining deliveries counter for this prefix (without any
# number part) in $n2. This should be an integer, or NULL (if this
# prefix is a new one). It may be negative, indicating the alias is
# permanently enabled, zero if it is disabled, or positive, if it is
# limited. We use the failure clause to map NULL into a default taken
# from the email, which is handled above and should be guaranteed a
# positive integer or zero. Note this needs to be done before we
# insert a record.
add "${lookup sqlite{ \
select remaining from counters \
where prefix = '${quote_sqlite:$1}' \
and stem = '${quote_sqlite:$local_part}'} \
{$value}{$n0}}" to n2
# Following queries need to update-or-insert a counter. Upsert-style
# operations in sqlite are complicated to achieve, so we ensure the
# appropriate counter record exists, meaning we can subsequently just
# do simple updates.
# Condition is for side-effects only.
if $acl_m_disposable_aliases_delivering is not ""
and "${lookup sqlite{ \
insert or rollback into counters \
(prefix, stem) values \
('${quote_sqlite:$1}', \
'${quote_sqlite:$local_part}')} \
{1}{1}}" is "0"
then
endif
# Now handle each remaining case of n1
if $n1 is 0
then
testprint "Not a valid control message"
# Perform the counter setting/incrementing logic, then exit
testprint "$n2 remaining deliveries"
# Insert the remaining deliveries counter back into the database,
# after decrementing if it is positive and not zero.
# We use a trick with the min/max functions to get that condition.
# remaining delta max(remaining, 0) min(max(remaining, 0), 1)
# -n 0 0 0
# 0 0 0 0
# n -1 n 1
if $acl_m_disposable_aliases_delivering is not ""
and "${lookup sqlite{ \
update counters set \
remaining = $n2 - min(max($n2, 0), 1) \
where prefix = '${quote_sqlite:$1}' \
and stem = '${quote_sqlite:$local_part}'} \
{1}{1}}" is "0"
then
endif
# If the counter was not zero, deliver the message, else deny it
if $n2 is not 0
then
testprint "deliver to '$2': remaining=$n2"
logwrite "$tod_log\t$local_part_prefix$local_part\tremaining=$n2\t$sender_address\t$return_path\t$h_subject"
# Increment stats. Condition is for side-effects only.
if $acl_m_disposable_aliases_delivering is not ""
and "${lookup sqlite{ \
update counters set delivered = delivered + 1 \
where prefix='${quote_sqlite:$1}' \
and stem='${quote_sqlite:$local_part}'}\
{1}{1}}" is "0"
then
endif
# Extract up to 10 email addresses, delimited by commas, from $2
# Currently I don't know of a way to do an arbitrary number.
seen deliver ${extract{1}{,}{$2}{$value}}
if "${extract{2}{,}{$2}{$value}{,}}" is "," then finish endif
seen deliver ${extract{2}{,}{$2}{$value}}
if "${extract{3}{,}{$2}{$value}{,}}" is "," then finish endif
seen deliver ${extract{3}{,}{$2}{$value}}
if "${extract{4}{,}{$2}{$value}{,}}" is "," then finish endif
seen deliver ${extract{4}{,}{$2}{$value}}
if "${extract{5}{,}{$2}{$value}{,}}" is "," then finish endif
seen deliver ${extract{5}{,}{$2}{$value}}
if "${extract{6}{,}{$2}{$value}{,}}" is "," then finish endif
seen deliver ${extract{6}{,}{$2}{$value}}
if "${extract{7}{,}{$2}{$value}{,}}" is "," then finish endif
seen deliver ${extract{7}{,}{$2}{$value}}
if "${extract{8}{,}{$2}{$value}{,}}" is "," then finish endif
seen deliver ${extract{8}{,}{$2}{$value}}
if "${extract{9}{,}{$2}{$value}{,}}" is "," then finish endif
seen deliver ${extract{9}{,}{$2}{$value}}
if "${extract{10}{,}{$2}{$value}{,}}" is "," then finish endif
seen deliver ${extract{10}{,}{$2}{$value}}
finish
else
testprint "no more mail permitted to $1.$local_part: remaining=$n2"
logwrite "$tod_log\t$local_part_prefix$local_part\trejected\t$sender_address\t$return_path\t$h_subject"
# Increment stats. Condition is for side-effects only.
if $acl_m_disposable_aliases_delivering is not ""
and "${lookup sqlite{ \
update counters set rejected = rejected + 1 \
where prefix='${quote_sqlite:$1}' \
and stem='${quote_sqlite:$local_part}'}\
{1}{1}}" is "0"
then
endif
finish
endif
elif $n1 is 1
then
testprint "enable prefix '$1'"
logwrite "$tod_log\t$local_part_prefix$local_part\tenabled\t$sender_address\t$return_path\t$h_subject"
seen mail
subject "Enabled disposable mail alias $1.$local_part@domain"
text "${if def:acl_m_disposable_aliases_delivering{${lookup sqlite{ \
update counters set \
remaining = -1 \
where prefix = '${quote_sqlite:$1}' \
and stem = '${quote_sqlite:$local_part}'} \
{}{}}}{}} \
Enabled $1.$local_part@$domain."
finish
elif $n1 is 2
then
testprint "disable prefix '$1'"
logwrite "$tod_log\t$local_part_prefix$local_part\tdisabled\t$sender_address\t$return_path\t$h_subject"
seen mail subject "Disabled disposable mail alias $1.$local_part@$domain"
text "${if def:acl_m_disposable_aliases_delivering{${lookup sqlite{ \
update counters set \
remaining = 0 \
where prefix = '${quote_sqlite:$1}' \
and stem = '${quote_sqlite:$local_part}'} \
{}{}}}{}} \
Disabled $1.$local_part@$domain."
finish
elif $n1 is 3
then
testprint "allow $3 more to prefix '$1'"
logwrite "$tod_log\t$local_part_prefix$local_part\tset=$3\t$sender_address\t$return_path\t$h_subject"
seen mail subject "Allow $3 more deliveries to $1.$local_part@$domain"
text "${if def:acl_m_disposable_aliases_delivering{${lookup sqlite{ \
update counters set \
remaining = $3 \
where prefix = '${quote_sqlite:$1}' \
and stem = '${quote_sqlite:$local_part}'} \
{}{}}}{}} \
Allow $3 more deliveries to $1.$local_part@$domain."
finish
endif