-
Notifications
You must be signed in to change notification settings - Fork 3
/
plugin-counters.c
134 lines (124 loc) · 3.34 KB
/
plugin-counters.c
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
#include "mailfront.h"
static RESPONSE(too_long, 552, "5.2.3 Sorry, that message exceeds the maximum message length.");
static RESPONSE(hops, 554, "5.6.0 This message is looping, too many hops.");
static RESPONSE(manyrcpt, 550, "5.5.3 Too many recipients");
static unsigned rcpt_count = 0;
static unsigned long data_bytes; /* Total number of data bytes */
static unsigned count_rec; /* Count of the Received: headers */
static unsigned count_dt; /* Count of the Delivered-To: headers */
static int in_header; /* True until a blank line is seen */
static unsigned linepos; /* The number of bytes since the last LF */
static int in_rec; /* True if we might be seeing Received: */
static int in_dt; /* True if we might be seeing Delivered-To: */
static unsigned long minenv(const char* sname, const char* name)
{
unsigned long u;
unsigned long value = session_getenvu(name);
u = 0;
if (value > 0)
if (!session_hasnum(sname, &u)
|| u > value) {
session_setnum(sname, value);
return value;
}
return u;
}
static const response* init(void)
{
/* This MUST be done in the init section to make sure the SMTP
* greeting displays the current value. */
minenv("maxdatabytes", "DATABYTES");
return 0;
}
static const response* reset(void)
{
rcpt_count = 0;
return 0;
}
static const response* sender(str* r)
{
/* This MUST be done as a sender match to make sure SMTP "MAIL FROM"
* commands with a SIZE parameter can be rejected properly. */
minenv("maxdatabytes", "DATABYTES");
minenv("maxrcpts", "MAXRCPTS");
(void)r;
return 0;
}
static const response* recipient(str* r)
{
unsigned long maxrcpts = minenv("maxrcpts", "MAXRCPTS");
minenv("maxdatabytes", "DATABYTES");
++rcpt_count;
if (maxrcpts > 0 && rcpt_count > maxrcpts)
return &resp_manyrcpt;
return 0;
(void)r;
}
static const response* start(void)
{
unsigned long maxhops;
minenv("maxdatabytes", "DATABYTES");
if ((maxhops = session_getenvu("MAXHOPS")) == 0)
maxhops = 100;
session_setnum("maxhops", maxhops);
data_bytes = 0;
count_rec = 0;
count_dt = 0;
in_header = 1;
linepos = 0;
in_rec = 1;
in_dt = 1;
return 0;
}
static const response* block(const char* bytes, unsigned long len)
{
unsigned i;
const char* p;
const unsigned long maxdatabytes = session_getnum("maxdatabytes", ~0UL);
const unsigned long maxhops = session_getnum("maxhops", 100);
data_bytes += len;
if (maxdatabytes > 0 && data_bytes > maxdatabytes)
return &resp_too_long;
for (i = 0, p = bytes; in_header && i < len; ++i, ++p) {
char ch = *p;
if (ch == LF) {
if (linepos == 0) in_header = 0;
linepos = 0;
in_rec = in_dt = in_header;
}
else {
if (in_header && linepos < 13) {
if (in_rec) {
if (ch != "received:"[linepos] &&
ch != "RECEIVED:"[linepos])
in_rec = 0;
else if (linepos >= 8) {
in_dt = in_rec = 0;
if (++count_rec > maxhops)
return &resp_hops;
}
}
if (in_dt) {
if (ch != "delivered-to:"[linepos] &&
ch != "DELIVERED-TO:"[linepos])
in_dt = 0;
else if (linepos >= 12) {
in_dt = in_rec = 0;
if (++count_dt > maxhops)
return &resp_hops;
}
}
++linepos;
}
}
}
return 0;
}
struct plugin plugin = {
.init = init,
.reset = reset,
.sender = sender,
.recipient = recipient,
.data_start = start,
.data_block = block,
};