]> git.proxmox.com Git - pmg-api.git/blame - src/PMG/RuleCache.pm
api: acme: add eab parameters
[pmg-api.git] / src / PMG / RuleCache.pm
CommitLineData
c881fe35
DM
1package PMG::RuleCache;
2
3use strict;
4use warnings;
5use DBI;
c881fe35
DM
6
7use PVE::SafeSyslog;
8
9use PMG::Utils;
10use PMG::RuleDB;
11use Digest::SHA;
12
13my $ocache_size = 1023;
14
15sub new {
16 my ($type, $ruledb) = @_;
17
18 my $self;
19
20 $self->{ruledb} = $ruledb;
21 $self->{ocache} = ();
22
23 bless $self, $type;
24
25 my $rules = ();
26
27 my $dbh = $ruledb->{dbh};
28
29 my $sha1 = Digest::SHA->new;
30
31 eval {
32 $dbh->begin_work;
33
34 # read a consistent snapshot
35 $dbh->do("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
36
37 my $sth = $dbh->prepare(
38 "SELECT ID, Name, Priority, Active, Direction FROM Rule " .
39 "where Active > 0 " .
f6b69037 40 "ORDER BY Priority DESC, ID DESC");
c881fe35
DM
41
42 $sth->execute();
43
44 while (my $ref = $sth->fetchrow_hashref()) {
45 my $ruleid = $ref->{id};
46 my $rule = PMG::RuleDB::Rule->new(
47 $ref->{name}, $ref->{priority}, $ref->{active},
48 $ref->{direction});
49
50 $rule->{id} = $ruleid;
51 push @$rules, $rule;
52
c9bb8609
DM
53 $sha1->add(join(',', $ref->{id}, $ref->{name}, $ref->{priority}, $ref->{active},
54 $ref->{direction}) . "|");
c881fe35
DM
55
56 my ($from, $to, $when, $what, $action);
57
58 my $sth1 = $dbh->prepare(
59 "SELECT Objectgroup_ID, Grouptype FROM RuleGroup " .
60 "where RuleGroup.Rule_ID = '$ruleid' " .
61 "ORDER BY Grouptype, Objectgroup_ID");
62
63 $sth1->execute();
64 while (my $ref1 = $sth1->fetchrow_hashref()) {
65 my $gtype = $ref1->{grouptype};
66 my $groupid = $ref1->{objectgroup_id};
67
68 # emtyp groups differ from non-existent groups!
69
70 if ($gtype == 0) { #from
71 $from = [] if !defined ($from);
72 } elsif ($gtype == 1) { # to
73 $to = [] if !defined ($to);
74 } elsif ($gtype == 2) { # when
75 $when = [] if !defined ($when);
76 } elsif ($gtype == 3) { # what
77 $what = [] if !defined ($what);
78 } elsif ($gtype == 4) { # action
79 $action = [] if !defined ($action);
80 }
81
82 my $sth2 = $dbh->prepare(
83 "SELECT ID FROM Object where Objectgroup_ID = '$groupid' " .
84 "ORDER BY ID");
85 $sth2->execute();
86 while (my $ref2 = $sth2->fetchrow_hashref()) {
87 my $objid = $ref2->{'id'};
88 my $obj = $self->_get_object($objid);
89
90 $sha1->add (join (',', $objid, $gtype, $groupid) . "|");
91 $sha1->add ($obj->{digest}, "|");
92
93 if ($gtype == 0) { #from
94 push @$from, $obj;
95 } elsif ($gtype == 1) { # to
96 push @$to, $obj;
97 } elsif ($gtype == 2) { # when
98 push @$when, $obj;
99 } elsif ($gtype == 3) { # what
100 push @$what, $obj;
5e809f47
DC
101 if ($obj->otype == PMG::RuleDB::ArchiveFilter->otype ||
102 $obj->otype == PMG::RuleDB::MatchArchiveFilename->otype)
103 {
c881fe35
DM
104 if ($rule->{direction} == 0) {
105 $self->{archivefilter_in} = 1;
106 } elsif ($rule->{direction} == 1) {
107 $self->{archivefilter_out} = 1;
108 } else {
109 $self->{archivefilter_in} = 1;
110 $self->{archivefilter_out} = 1;
111 }
112 }
113 } elsif ($gtype == 4) { # action
114 push @$action, $obj;
115 $self->{"$ruleid:final"} = 1 if $obj->final();
116 }
117 }
118 $sth2->finish();
119 }
120
121 $sth1->finish();
122
123 $self->{"$ruleid:from"} = $from;
124 $self->{"$ruleid:to"} = $to;
125 $self->{"$ruleid:when"} = $when;
126 $self->{"$ruleid:what"} = $what;
127 $self->{"$ruleid:action"} = $action;
128 }
129
130 # Cache Greylist Exclusion
131 $sth = $dbh->prepare(
132 "SELECT object.id FROM object, objectgroup " .
133 "WHERE class = 'greylist' AND " .
134 "objectgroup.id = object.objectgroup_id " .
135 "ORDER BY object.id");
136
137 $sth->execute();
138 my $grey_excl_sender = ();
139 my $grey_excl_receiver = ();
140 while (my $ref2 = $sth->fetchrow_hashref()) {
141 my $obj = $self->_get_object ($ref2->{'id'});
142
143 if ($obj->receivertest()) {
144 push @$grey_excl_receiver, $obj;
145 } else {
146 push @$grey_excl_sender, $obj;
147 }
c9bb8609 148 $sha1->add ($ref2->{'id'}, "|");
c881fe35
DM
149 $sha1->add ($obj->{digest}, "|");
150 }
151
152 $self->{"greylist:sender"} = $grey_excl_sender;
153 $self->{"greylist:receiver"} = $grey_excl_receiver;
154
155 $sth->finish();
156 };
157 my $err = $@;
158
159 $dbh->rollback; # end transaction
160
b902c0b8 161 syslog ('err', "unable to load rulecache : $err") if $err;
c881fe35
DM
162
163 $self->{rules} = $rules;
164
165 $self->{digest} = $sha1->hexdigest;
166
167 return $self;
168}
169
170sub final {
171 my ($self, $ruleid) = @_;
172
9ef3f143 173 defined($ruleid) || die "undefined rule id: ERROR";
c881fe35
DM
174
175 return $self->{"$ruleid:final"};
176}
177
178sub rules {
179 my ($self) = @_;
180
181 $self->{rules};
182}
183
184sub _get_object {
185 my ($self, $objid) = @_;
186
187 my $cid = $objid % $ocache_size;
188
189 my $obj = $self->{ocache}[$cid];
190
191 if (!defined ($obj) || $obj->{id} != $objid) {
192 $obj = $self->{ruledb}->load_object($objid);
193 $self->{ocache}[$cid] = $obj;
194 }
195
9ef3f143 196 $obj || die "unable to get object $objid: ERROR";
c881fe35
DM
197
198 return $obj;
199}
200
201sub get_actions {
202 my ($self, $ruleid) = @_;
203
9ef3f143 204 defined($ruleid) || die "undefined rule id: ERROR";
c881fe35
DM
205
206 return $self->{"$ruleid:action"};
207}
208
209sub greylist_match {
210 my ($self, $addr, $ip) = @_;
211
212 my $grey = $self->{"greylist:sender"};
213
214 foreach my $obj (@$grey) {
215 if ($obj->who_match ($addr, $ip)) {
216 return 1;
217 }
218 }
219
220 return 0;
221}
222
223sub greylist_match_receiver {
224 my ($self, $addr) = @_;
225
226 my $grey = $self->{"greylist:receiver"};
227
228 foreach my $obj (@$grey) {
229 if ($obj->who_match($addr)) {
230 return 1;
231 }
232 }
233
234 return 0;
235}
236
237sub from_match {
238 my ($self, $ruleid, $addr, $ip, $ldap) = @_;
239
240 my $from = $self->{"$ruleid:from"};
241
242 return 1 if !defined ($from);
243
61954d8d 244 # postfix prefixes ipv6 addresses with IPv6:
a34b95db 245 if (defined($ip) && $ip =~ /^IPv6:(.*)/) {
61954d8d
DC
246 $ip = $1;
247 }
248
c881fe35
DM
249 foreach my $obj (@$from) {
250 return 1 if $obj->who_match($addr, $ip, $ldap);
251 }
252
253 return 0;
254}
255
256sub to_match {
257 my ($self, $ruleid, $addr, $ldap) = @_;
258
259 my $to = $self->{"$ruleid:to"};
260
261 return 1 if !defined ($to);
262
263 foreach my $obj (@$to) {
264 return 1 if $obj->who_match($addr, undef, $ldap);
265 }
266
267 return 0;
268}
269
270sub when_match {
271 my ($self, $ruleid, $time) = @_;
272
273 my $when = $self->{"$ruleid:when"};
274
275 return 1 if !defined ($when);
276
277 foreach my $obj (@$when) {
278 return 1 if $obj->when_match($time);
279 }
280
281 return 0;
282}
283
284sub what_match {
285 my ($self, $ruleid, $queue, $element, $msginfo, $dbh) = @_;
286
287 my $what = $self->{"$ruleid:what"};
288
289 my $res;
290
291 # $res->{marks} is used by mark specific actions like remove-attachments
292 # $res->{$target}->{marks} is only used in apply_rules() to exclude some
293 # targets (spam blacklist and whitelist)
294
295 if (!defined ($what)) {
296 # match all targets
297 foreach my $target (@{$msginfo->{targets}}) {
298 $res->{$target}->{marks} = [];
299 }
300
301 $res->{marks} = [];
302 return $res;
303 }
304
305 my $marks;
306
307 foreach my $obj (@$what) {
308 if (!$obj->can('what_match_targets')) {
309 if (my $match = $obj->what_match($queue, $element, $msginfo, $dbh)) {
310 push @$marks, @$match;
311 }
312 }
313 }
314
315 foreach my $target (@{$msginfo->{targets}}) {
316 $res->{$target}->{marks} = $marks;
317 $res->{marks} = $marks;
318 }
319
320 foreach my $obj (@$what) {
321 if ($obj->can ("what_match_targets")) {
322 my $target_info;
323 if ($target_info = $obj->what_match_targets($queue, $element, $msginfo, $dbh)) {
324 foreach my $k (keys %$target_info) {
325 my $cmarks = $target_info->{$k}->{marks}; # make a copy
326 $res->{$k} = $target_info->{$k};
327 push @{$res->{$k}->{marks}}, @$cmarks if $cmarks;
328 }
329 }
330 }
331 }
332
333 return $res;
334}
335
3361;