Mercurial > dnsbl
comparison src/context.cpp @ 192:8f4a9a37d4d9
delay autowhitelisting to avoid out of office reply bots
author | carl |
---|---|
date | Sun, 11 Nov 2007 12:49:25 -0800 |
parents | 7a722f482bfb |
children | 797299e9fffc |
comparison
equal
deleted
inserted
replaced
191:2a67d31099c3 | 192:8f4a9a37d4d9 |
---|---|
65 char *token_white; | 65 char *token_white; |
66 char *token_yes; | 66 char *token_yes; |
67 | 67 |
68 char *token_myhostname; | 68 char *token_myhostname; |
69 #ifndef HOST_NAME_MAX | 69 #ifndef HOST_NAME_MAX |
70 #define HOST_NAME_MAX 255 | 70 #define HOST_NAME_MAX 255 |
71 #endif | 71 #endif |
72 char myhostname[HOST_NAME_MAX+1]; | 72 char myhostname[HOST_NAME_MAX+1]; |
73 | 73 |
74 pthread_mutex_t verifier_mutex; // protect the verifier map | 74 pthread_mutex_t verifier_mutex; // protect the verifier map |
75 verify_map verifiers; | 75 verify_map verifiers; |
76 | 76 |
77 pthread_mutex_t whitelister_mutex; // protect the whitelisters map | 77 pthread_mutex_t whitelister_mutex; // protect the whitelisters map |
78 whitelister_map whitelisters; | 78 whitelister_map whitelisters; |
79 | 79 |
80 string_set all_strings; // owns all the strings, only modified by the config loader thread | 80 string_set all_strings; // owns all the strings, only modified by the config loader thread |
81 const int maxlen = 1000; // used for snprintf buffers | 81 const int maxlen = 1000; // used for snprintf buffers |
82 const int maxsmtp_age = 60;// smtp verify sockets older than this are ancient | 82 const int maxsmtp_age = 60;// smtp verify sockets older than this are ancient |
83 const int maxauto_age = 600;// auto whitelister delay before flushing to file | 83 const int maxauto_age = 600;// auto whitelister delay before flushing to file |
84 extern int NULL_SOCKET; | 84 extern int NULL_SOCKET; |
85 const time_t ERROR_SMTP_SOCKET_TIME = 600; // number of seconds between attempts to open a socket to an smtp server | 85 const time_t ERROR_SMTP_SOCKET_TIME = 600; // number of seconds between attempts to open a socket to an smtp server |
86 | 86 |
87 | 87 |
88 int SMTP::writer() { | 88 int SMTP::writer() { |
89 #ifdef VERIFY_DEBUG | 89 #ifdef VERIFY_DEBUG |
90 log("writer() sees buffer with %s", buffer); | 90 log("writer() sees buffer with %s", buffer); |
91 log("writer() sees error %d", (int)error); | 91 log("writer() sees error %d", (int)error); |
92 #endif | 92 #endif |
93 int rs = 0; | 93 int rs = 0; |
94 if (!error) { | 94 if (!error) { |
95 int len = strlen(buffer); | 95 int len = strlen(buffer); |
96 while (rs < len) { | 96 while (rs < len) { |
97 int ws = write(fd, buffer+rs, len-rs); | 97 int ws = write(fd, buffer+rs, len-rs); |
98 if (ws > 0) { | 98 if (ws > 0) { |
99 rs += ws; | 99 rs += ws; |
100 } | 100 } |
101 else { | 101 else { |
102 // peer closed the socket! | 102 // peer closed the socket! |
103 rs = 0; | 103 rs = 0; |
104 error = true; | 104 error = true; |
105 break; | 105 break; |
106 } | 106 } |
107 } | 107 } |
108 } | 108 } |
109 return rs; | 109 return rs; |
110 } | 110 } |
111 | 111 |
112 | 112 |
113 int SMTP::reader() { | 113 int SMTP::reader() { |
114 // read some bytes terminated by lf or end of buffer. | 114 // read some bytes terminated by lf or end of buffer. |
115 // we may have a multi line response or part thereof in the buffer. | 115 // we may have a multi line response or part thereof in the buffer. |
116 #ifdef VERIFY_DEBUG | 116 #ifdef VERIFY_DEBUG |
117 log("reader() sees error %d", (int)error); | 117 log("reader() sees error %d", (int)error); |
118 #endif | 118 #endif |
119 if (error) return 0; | 119 if (error) return 0; |
120 int len = maxlen-1; // room for null terminator | 120 int len = maxlen-1; // room for null terminator |
121 while (pending < len) { | 121 while (pending < len) { |
122 int ws = read(fd, buffer+pending, len-pending); | 122 int ws = read(fd, buffer+pending, len-pending); |
123 if (ws > 0) { | 123 if (ws > 0) { |
124 pending += ws; | 124 pending += ws; |
125 if (buffer[pending-1] == '\n') break; | 125 if (buffer[pending-1] == '\n') break; |
126 } | 126 } |
127 else { | 127 else { |
128 // peer closed the socket! | 128 // peer closed the socket! |
129 pending = 0; | 129 pending = 0; |
130 error = true; | 130 error = true; |
131 break; | 131 break; |
132 } | 132 } |
133 } | 133 } |
134 buffer[pending] = '\0'; | 134 buffer[pending] = '\0'; |
135 #ifdef VERIFY_DEBUG | 135 #ifdef VERIFY_DEBUG |
136 log("reader() sees buffer with %s", buffer); | 136 log("reader() sees buffer with %s", buffer); |
137 #endif | 137 #endif |
138 return pending; | 138 return pending; |
139 } | 139 } |
140 | 140 |
141 | 141 |
142 int SMTP::read_line() { | 142 int SMTP::read_line() { |
143 char *lf = strchr(buffer, '\n'); | 143 char *lf = strchr(buffer, '\n'); |
144 if (!lf) { | 144 if (!lf) { |
145 reader(); // get a lf | 145 reader(); // get a lf |
146 lf = strchr(buffer, '\n'); | 146 lf = strchr(buffer, '\n'); |
147 if (!lf) lf = buffer + pending - 1; | 147 if (!lf) lf = buffer + pending - 1; |
148 } | 148 } |
149 return (lf-buffer)+1; // number of bytes in this line | 149 return (lf-buffer)+1; // number of bytes in this line |
150 } | 150 } |
151 | 151 |
152 | 152 |
153 void SMTP::flush_line(int r) { | 153 void SMTP::flush_line(int r) { |
154 if (pending > r) memmove(buffer, buffer+r, pending-r); | 154 if (pending > r) memmove(buffer, buffer+r, pending-r); |
155 pending -= r; | 155 pending -= r; |
156 } | 156 } |
157 | 157 |
158 | 158 |
159 int SMTP::read_response() { | 159 int SMTP::read_response() { |
160 pending = 0; | 160 pending = 0; |
161 buffer[pending] = '\0'; | 161 buffer[pending] = '\0'; |
162 while (true) { | 162 while (true) { |
163 int r = read_line(); | 163 int r = read_line(); |
164 #ifdef VERIFY_DEBUG | 164 #ifdef VERIFY_DEBUG |
165 log("read_response() sees line with %s", buffer); | 165 log("read_response() sees line with %s", buffer); |
166 log("read_response() sees line length %d", r); | 166 log("read_response() sees line length %d", r); |
167 #endif | 167 #endif |
168 if (r == 0) return 0; // failed to read any bytes | 168 if (r == 0) return 0; // failed to read any bytes |
169 if ((r > 4) && (buffer[3] == '-')) { | 169 if ((r > 4) && (buffer[3] == '-')) { |
170 flush_line(r); | 170 flush_line(r); |
171 continue; | 171 continue; |
172 } | 172 } |
173 return atoi(buffer); | 173 return atoi(buffer); |
174 } | 174 } |
175 return 0; | 175 return 0; |
176 } | 176 } |
177 | 177 |
178 | 178 |
179 int SMTP::cmd(char *c) { | 179 int SMTP::cmd(char *c) { |
180 if (c) { | 180 if (c) { |
181 init(); | 181 init(); |
182 append(c); | 182 append(c); |
183 } | 183 } |
184 append("\r\n"); | 184 append("\r\n"); |
185 writer(); | 185 writer(); |
186 return read_response(); | 186 return read_response(); |
187 } | 187 } |
188 | 188 |
189 | 189 |
190 int SMTP::helo() { | 190 int SMTP::helo() { |
191 if (read_response() != 220) return 0; | 191 if (read_response() != 220) return 0; |
192 init(); | 192 init(); |
193 append("HELO "); | 193 append("HELO "); |
194 append(token_myhostname); | 194 append(token_myhostname); |
195 return cmd(NULL); | 195 return cmd(NULL); |
196 } | 196 } |
197 | 197 |
198 | 198 |
199 int SMTP::rset() { | 199 int SMTP::rset() { |
200 int rc = cmd("RSET"); | 200 int rc = cmd("RSET"); |
201 efrom[0] = '\0'; | 201 efrom[0] = '\0'; |
202 return rc; | 202 return rc; |
203 } | 203 } |
204 | 204 |
205 | 205 |
206 int SMTP::from(char *f) { | 206 int SMTP::from(char *f) { |
207 // the mail from address was originally passed in from sendmail enclosed in | 207 // the mail from address was originally passed in from sendmail enclosed in |
208 // <>. to_lower_string() removed the <> and converted the rest to lowercase, | 208 // <>. to_lower_string() removed the <> and converted the rest to lowercase, |
209 // except in the case of an empty return path, which was left as the two | 209 // except in the case of an empty return path, which was left as the two |
210 // character string <>. | 210 // character string <>. |
211 if (strncmp(efrom, f, maxlen)) { | 211 if (strncmp(efrom, f, maxlen)) { |
212 rset(); | 212 rset(); |
213 strncpy(efrom, f, maxlen); | 213 strncpy(efrom, f, maxlen); |
214 init(); | 214 init(); |
215 append("MAIL FROM:<"); | 215 append("MAIL FROM:<"); |
216 if (*f != '<') append(f); | 216 if (*f != '<') append(f); |
217 append(">"); | 217 append(">"); |
218 return cmd(NULL); | 218 return cmd(NULL); |
219 } | 219 } |
220 return 250; // pretend it worked | 220 return 250; // pretend it worked |
221 } | 221 } |
222 | 222 |
223 | 223 |
224 int SMTP::rcpt(char *t) { | 224 int SMTP::rcpt(char *t) { |
225 init(); | 225 init(); |
226 append("RCPT TO:<"); | 226 append("RCPT TO:<"); |
227 append(t); | 227 append(t); |
228 append(">"); | 228 append(">"); |
229 return cmd(NULL); | 229 return cmd(NULL); |
230 } | 230 } |
231 | 231 |
232 | 232 |
233 int SMTP::quit() { | 233 int SMTP::quit() { |
234 return cmd("QUIT"); | 234 return cmd("QUIT"); |
235 } | 235 } |
236 | 236 |
237 | 237 |
238 void SMTP::closefd() { | 238 void SMTP::closefd() { |
239 shutdown(fd, SHUT_RDWR); | 239 shutdown(fd, SHUT_RDWR); |
240 close(fd); | 240 close(fd); |
241 } | 241 } |
242 | 242 |
243 | 243 |
244 #ifdef VERIFY_DEBUG | 244 #ifdef VERIFY_DEBUG |
245 void SMTP::log(char *m, int v) { | 245 void SMTP::log(char *m, int v) { |
246 char buf[maxlen]; | 246 char buf[maxlen]; |
247 snprintf(buf, maxlen, m, v); | 247 snprintf(buf, maxlen, m, v); |
248 my_syslog(buf); | 248 my_syslog(buf); |
249 } | 249 } |
250 | 250 |
251 | 251 |
252 void SMTP::log(char *m, char *v) { | 252 void SMTP::log(char *m, char *v) { |
253 char buf[maxlen]; | 253 char buf[maxlen]; |
254 snprintf(buf, maxlen, m, v); | 254 snprintf(buf, maxlen, m, v); |
255 my_syslog(buf); | 255 my_syslog(buf); |
256 } | 256 } |
257 #endif | 257 #endif |
258 | 258 |
259 | 259 |
260 //////////////////////////////////////////////// | 260 //////////////////////////////////////////////// |
261 // smtp verifier so backup mx machines can see the valid users | 261 // smtp verifier so backup mx machines can see the valid users |
262 // | 262 // |
263 VERIFY::VERIFY(char *h) { | 263 VERIFY::VERIFY(char *h) { |
264 host = h; | 264 host = h; |
265 last_err = 0; | 265 last_err = 0; |
266 pthread_mutex_init(&mutex, 0); | 266 pthread_mutex_init(&mutex, 0); |
267 } | 267 } |
268 | 268 |
269 | 269 |
270 void VERIFY::closer() { | 270 void VERIFY::closer() { |
271 bool ok = true; | 271 bool ok = true; |
272 while (ok) { | 272 while (ok) { |
273 SMTP *conn = NULL; | 273 SMTP *conn = NULL; |
274 pthread_mutex_lock(&mutex); | 274 pthread_mutex_lock(&mutex); |
275 if (connections.empty()) { | 275 if (connections.empty()) { |
276 ok = false; | 276 ok = false; |
277 } | 277 } |
278 else { | 278 else { |
279 conn = connections.front(); | 279 conn = connections.front(); |
280 time_t now = time(NULL); | 280 time_t now = time(NULL); |
281 if ((now - conn->get_stamp()) > maxsmtp_age) { | 281 if ((now - conn->get_stamp()) > maxsmtp_age) { |
282 // this connection is ancient, remove it | 282 // this connection is ancient, remove it |
283 connections.pop_front(); | 283 connections.pop_front(); |
284 } | 284 } |
285 else { | 285 else { |
286 ok = false; | 286 ok = false; |
287 conn = NULL; | 287 conn = NULL; |
288 } | 288 } |
289 } | 289 } |
290 pthread_mutex_unlock(&mutex); | 290 pthread_mutex_unlock(&mutex); |
291 // avoid doing this work inside the mutex lock | 291 // avoid doing this work inside the mutex lock |
292 if (conn) { | 292 if (conn) { |
293 #ifdef VERIFY_DEBUG | 293 #ifdef VERIFY_DEBUG |
294 conn->log("closer() closes ancient %d", conn->get_fd()); | 294 conn->log("closer() closes ancient %d", conn->get_fd()); |
295 #endif | 295 #endif |
296 delete conn; | 296 delete conn; |
297 } | 297 } |
298 } | 298 } |
299 } | 299 } |
300 | 300 |
301 | 301 |
302 SMTP* VERIFY::get_connection() { | 302 SMTP* VERIFY::get_connection() { |
303 SMTP *conn = NULL; | 303 SMTP *conn = NULL; |
304 pthread_mutex_lock(&mutex); | 304 pthread_mutex_lock(&mutex); |
305 if (!connections.empty()) { | 305 if (!connections.empty()) { |
306 conn = connections.front(); | 306 conn = connections.front(); |
307 connections.pop_front(); | 307 connections.pop_front(); |
308 #ifdef VERIFY_DEBUG | 308 #ifdef VERIFY_DEBUG |
309 conn->log("get_connection() %d from cache", conn->get_fd()); | 309 conn->log("get_connection() %d from cache", conn->get_fd()); |
310 #endif | 310 #endif |
311 } | 311 } |
312 pthread_mutex_unlock(&mutex); | 312 pthread_mutex_unlock(&mutex); |
313 if (conn) return conn; | 313 if (conn) return conn; |
314 int sock = NULL_SOCKET; | 314 int sock = NULL_SOCKET; |
315 if ((time(NULL) - last_err) > ERROR_SMTP_SOCKET_TIME) { | 315 if ((time(NULL) - last_err) > ERROR_SMTP_SOCKET_TIME) { |
316 // nothing recent, maybe this time it will work | 316 // nothing recent, maybe this time it will work |
317 hostent *h = gethostbyname(host); | 317 hostent *h = gethostbyname(host); |
318 if (h) { | 318 if (h) { |
319 sockaddr_in server; | 319 sockaddr_in server; |
320 server.sin_family = h->h_addrtype; | 320 server.sin_family = h->h_addrtype; |
321 server.sin_port = htons(25); | 321 server.sin_port = htons(25); |
322 memcpy(&server.sin_addr, h->h_addr_list[0], h->h_length); | 322 memcpy(&server.sin_addr, h->h_addr_list[0], h->h_length); |
323 sock = socket(PF_INET, SOCK_STREAM, 0); | 323 sock = socket(PF_INET, SOCK_STREAM, 0); |
324 if (sock != NULL_SOCKET) { | 324 if (sock != NULL_SOCKET) { |
325 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0); | 325 bool rc = (connect(sock, (sockaddr *)&server, sizeof(server)) == 0); |
326 if (!rc) { | 326 if (!rc) { |
327 shutdown(sock, SHUT_RDWR); | 327 shutdown(sock, SHUT_RDWR); |
328 close(sock); | 328 close(sock); |
329 sock = NULL_SOCKET; | 329 sock = NULL_SOCKET; |
330 last_err = time(NULL); | 330 last_err = time(NULL); |
331 } | 331 } |
332 } | 332 } |
333 else last_err = time(NULL); | 333 else last_err = time(NULL); |
334 } | 334 } |
335 else last_err = time(NULL); | 335 else last_err = time(NULL); |
336 } | 336 } |
337 if (sock != NULL_SOCKET) { | 337 if (sock != NULL_SOCKET) { |
338 conn = new SMTP(sock); | 338 conn = new SMTP(sock); |
339 #ifdef VERIFY_DEBUG | 339 #ifdef VERIFY_DEBUG |
340 conn->log("get_connection() %d new socket", conn->get_fd()); | 340 conn->log("get_connection() %d new socket", conn->get_fd()); |
341 #endif | 341 #endif |
342 if (conn->helo() == 250) return conn; | 342 if (conn->helo() == 250) return conn; |
343 delete conn; | 343 delete conn; |
344 } | 344 } |
345 return NULL; | 345 return NULL; |
346 } | 346 } |
347 | 347 |
348 | 348 |
349 void VERIFY::put_connection(SMTP *conn) { | 349 void VERIFY::put_connection(SMTP *conn) { |
350 if (conn->err()) { | 350 if (conn->err()) { |
351 #ifdef VERIFY_DEBUG | 351 #ifdef VERIFY_DEBUG |
352 conn->log("put_socket() %d with error, close it", conn->get_fd()); | 352 conn->log("put_socket() %d with error, close it", conn->get_fd()); |
353 #endif | 353 #endif |
354 delete conn; | 354 delete conn; |
355 last_err = time(NULL); | 355 last_err = time(NULL); |
356 } | 356 } |
357 else { | 357 else { |
358 #ifdef VERIFY_DEBUG | 358 #ifdef VERIFY_DEBUG |
359 conn->log("put_socket() %d", conn->get_fd()); | 359 conn->log("put_socket() %d", conn->get_fd()); |
360 #endif | 360 #endif |
361 conn->now(); | 361 conn->now(); |
362 pthread_mutex_lock(&mutex); | 362 pthread_mutex_lock(&mutex); |
363 connections.push_back(conn); | 363 connections.push_back(conn); |
364 pthread_mutex_unlock(&mutex); | 364 pthread_mutex_unlock(&mutex); |
365 } | 365 } |
366 } | 366 } |
367 | 367 |
368 | 368 |
369 bool VERIFY::ok(char *from, char *to) { | 369 bool VERIFY::ok(char *from, char *to) { |
370 if (host == token_myhostname) return true; | 370 if (host == token_myhostname) return true; |
371 SMTP *conn = get_connection(); | 371 SMTP *conn = get_connection(); |
372 if (!conn) return true; // cannot verify right now, we have socket errors | 372 if (!conn) return true; // cannot verify right now, we have socket errors |
373 int rc; | 373 int rc; |
374 rc = conn->from(from); | 374 rc = conn->from(from); |
375 #ifdef VERIFY_DEBUG | 375 #ifdef VERIFY_DEBUG |
376 conn->log("verify::ok() from sees %d", rc); | 376 conn->log("verify::ok() from sees %d", rc); |
377 #endif | 377 #endif |
378 if (rc != 250) { | 378 if (rc != 250) { |
379 conn->rset(); | 379 conn->rset(); |
380 put_connection(conn); | 380 put_connection(conn); |
381 return (rc >= 500) ? false : true; | 381 return (rc >= 500) ? false : true; |
382 } | 382 } |
383 rc = conn->rcpt(to); | 383 rc = conn->rcpt(to); |
384 #ifdef VERIFY_DEBUG | 384 #ifdef VERIFY_DEBUG |
385 conn->log("verify::ok() rcpt sees %d", rc); | 385 conn->log("verify::ok() rcpt sees %d", rc); |
386 #endif | 386 #endif |
387 put_connection(conn); | 387 put_connection(conn); |
388 return (rc >= 500) ? false : true; | 388 return (rc >= 500) ? false : true; |
389 } | 389 } |
390 | 390 |
391 | 391 |
392 //////////////////////////////////////////////// | 392 //////////////////////////////////////////////// |
393 // setup a new smtp verify host | 393 // setup a new smtp verify host |
394 // | 394 // |
395 VERIFYP add_verify_host(char *host); | 395 VERIFYP add_verify_host(char *host); |
396 VERIFYP add_verify_host(char *host) { | 396 VERIFYP add_verify_host(char *host) { |
397 VERIFYP rc = NULL; | 397 VERIFYP rc = NULL; |
398 pthread_mutex_lock(&verifier_mutex); | 398 pthread_mutex_lock(&verifier_mutex); |
399 verify_map::iterator i = verifiers.find(host); | 399 verify_map::iterator i = verifiers.find(host); |
400 if (i == verifiers.end()) { | 400 if (i == verifiers.end()) { |
401 rc = new VERIFY(host); | 401 rc = new VERIFY(host); |
402 verifiers[host] = rc; | 402 verifiers[host] = rc; |
403 } | 403 } |
404 else rc = (*i).second; | 404 else rc = (*i).second; |
405 pthread_mutex_unlock(&verifier_mutex); | 405 pthread_mutex_unlock(&verifier_mutex); |
406 return rc; | 406 return rc; |
407 } | 407 } |
408 | 408 |
409 | 409 |
410 //////////////////////////////////////////////// | 410 //////////////////////////////////////////////// |
411 // thread to check for verify hosts with old sockets that we can close | 411 // thread to check for verify hosts with old sockets that we can close |
412 // | 412 // |
413 void* verify_closer(void *arg) { | 413 void* verify_closer(void *arg) { |
414 while (true) { | 414 while (true) { |
415 sleep(maxsmtp_age); | 415 sleep(maxsmtp_age); |
416 pthread_mutex_lock(&verifier_mutex); | 416 pthread_mutex_lock(&verifier_mutex); |
417 for (verify_map::iterator i=verifiers.begin(); i!=verifiers.end(); i++) { | 417 for (verify_map::iterator i=verifiers.begin(); i!=verifiers.end(); i++) { |
418 VERIFYP v = (*i).second; | 418 VERIFYP v = (*i).second; |
419 v->closer(); | 419 v->closer(); |
420 } | 420 } |
421 pthread_mutex_unlock(&verifier_mutex); | 421 pthread_mutex_unlock(&verifier_mutex); |
422 } | 422 } |
423 return NULL; | 423 return NULL; |
424 } | 424 } |
425 | 425 |
426 | 426 |
427 //////////////////////////////////////////////// | 427 //////////////////////////////////////////////// |
428 // automatic whitelister | 428 // automatic whitelister |
429 // | 429 // |
430 WHITELISTER::WHITELISTER(char *f, int d) { | 430 WHITELISTER::WHITELISTER(char *f, int d) { |
431 fn = f; | 431 fn = f; |
432 days = d; | 432 days = d; |
433 pthread_mutex_init(&mutex, 0); | 433 pthread_mutex_init(&mutex, 0); |
434 need = false; | 434 need = false; |
435 loaded = time(NULL); | 435 loaded = time(NULL); |
436 merge(); | 436 merge(); |
437 } | 437 } |
438 | 438 |
439 | 439 |
440 void WHITELISTER::merge() { | 440 void WHITELISTER::merge() { |
441 time_t now = time(NULL); | 441 time_t now = time(NULL); |
442 ifstream ifs; | 442 ifstream ifs; |
443 ifs.open(fn); | 443 ifs.open(fn); |
444 if (!ifs.fail()) { | 444 if (!ifs.fail()) { |
445 const int maxlen = 1000; | 445 const int maxlen = 1000; |
446 char buf[maxlen]; | 446 char buf[maxlen]; |
447 while (ifs.getline(buf, maxlen)) { | 447 while (ifs.getline(buf, maxlen)) { |
448 char *p = strchr(buf, ' '); | 448 char *p = strchr(buf, ' '); |
449 if (p) { | 449 if (p) { |
450 *p = '\0'; | 450 *p = '\0'; |
451 char *who = strdup(buf); | 451 char *who = strdup(buf); |
452 time_t when = atoi(p+1); | 452 time_t when = atoi(p+1); |
453 if ((when == 0) || (when > now)) when = now; | 453 if ((when == 0) || (when > now)) when = now; |
454 autowhite_sent::iterator i = rcpts.find(who); | 454 autowhite_sent::iterator i = rcpts.find(who); |
455 if (i == rcpts.end()) { | 455 if (i == rcpts.end()) { |
456 rcpts[who] = when; | 456 rcpts[who] = when; |
457 } | 457 } |
458 else { | 458 else { |
459 time_t wh = (*i).second; | 459 time_t wh = (*i).second; |
460 if ((when == 1) || (when > wh)) (*i).second = when; | 460 if ((when == 1) || (when > wh)) (*i).second = when; |
461 free(who); | 461 free(who); |
462 } | 462 } |
463 } | 463 } |
464 } | 464 } |
465 } | 465 } |
466 ifs.close(); | 466 ifs.close(); |
467 } | 467 } |
468 | 468 |
469 | 469 |
470 void WHITELISTER::writer() { | 470 void WHITELISTER::writer() { |
471 pthread_mutex_lock(&mutex); | 471 pthread_mutex_lock(&mutex); |
472 time_t limit = time(NULL) - days*86400; | 472 time_t limit = time(NULL) - days*86400; |
473 | 473 |
474 // check for manually modified autowhitelist file | 474 // check for manually modified autowhitelist file |
475 struct stat st; | 475 struct stat st; |
476 if (stat(fn, &st)) need = true; // file has disappeared | 476 if (stat(fn, &st)) need = true; // file has disappeared |
477 else if (st.st_mtime > loaded) { | 477 else if (st.st_mtime > loaded) { |
478 // file has been manually updated, merge new entries | 478 // file has been manually updated, merge new entries |
479 merge(); | 479 merge(); |
480 need = true; | 480 need = true; |
481 } | 481 } |
482 | 482 |
483 // purge old entries | 483 // purge old entries |
484 for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end();) { | 484 for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end();) { |
485 time_t when = (*i).second; | 485 time_t when = (*i).second; |
486 if (when < limit) { | 486 if (when < limit) { |
487 char *who = (*i).first; | 487 char *who = (*i).first; |
488 free(who); | 488 free(who); |
489 autowhite_sent::iterator j = i; | 489 autowhite_sent::iterator j = i; |
490 j++; | 490 j++; |
491 rcpts.erase(i); | 491 rcpts.erase(i); |
492 i = j; | 492 i = j; |
493 need = true; | 493 need = true; |
494 } | 494 } |
495 else i++; | 495 else i++; |
496 } | 496 } |
497 | 497 |
498 if (need) { | 498 if (need) { |
499 // dump the file | 499 // dump the file |
500 ofstream ofs; | 500 ofstream ofs; |
501 ofs.open(fn); | 501 ofs.open(fn); |
502 if (!ofs.fail()) { | 502 if (!ofs.fail()) { |
503 for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end(); i++) { | 503 for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end(); i++) { |
504 char *who = (*i).first; | 504 char *who = (*i).first; |
505 int when = (*i).second; | 505 int when = (*i).second; |
506 if (!strchr(who, ' ')) { | 506 if (!strchr(who, ' ')) { |
507 ofs << who << " " << when << endl; | 507 ofs << who << " " << when << endl; |
508 } | 508 } |
509 } | 509 } |
510 } | 510 } |
511 ofs.close(); | 511 ofs.close(); |
512 need = false; | 512 need = false; |
513 loaded = time(NULL); // update load time | 513 loaded = time(NULL); // update load time |
514 } | 514 } |
515 pthread_mutex_unlock(&mutex); | 515 pthread_mutex_unlock(&mutex); |
516 } | 516 } |
517 | 517 |
518 | 518 |
519 void WHITELISTER::sent(char *to) { | 519 void WHITELISTER::sent(char *to) { |
520 // we take ownership of the string | 520 // we take ownership of the string |
521 pthread_mutex_lock(&mutex); | 521 pthread_mutex_lock(&mutex); |
522 need = true; | 522 need = true; |
523 autowhite_sent::iterator i = rcpts.find(to); | 523 autowhite_sent::iterator i = rcpts.find(to); |
524 if (i == rcpts.end()) { | 524 if (i == rcpts.end()) { |
525 rcpts[to] = time(NULL); | 525 rcpts[to] = time(NULL); |
526 } | 526 } |
527 else { | 527 else { |
528 (*i).second = time(NULL); | 528 (*i).second = time(NULL); |
529 free(to); | 529 free(to); |
530 } | 530 } |
531 pthread_mutex_unlock(&mutex); | 531 pthread_mutex_unlock(&mutex); |
532 } | 532 } |
533 | 533 |
534 | 534 |
535 bool WHITELISTER::is_white(char *from) { | 535 bool WHITELISTER::is_white(char *from) { |
536 pthread_mutex_lock(&mutex); | 536 pthread_mutex_lock(&mutex); |
537 autowhite_sent::iterator i = rcpts.find(from); | 537 autowhite_sent::iterator i = rcpts.find(from); |
538 bool rc = (i != rcpts.end()); | 538 bool rc = (i != rcpts.end()); |
539 pthread_mutex_unlock(&mutex); | 539 pthread_mutex_unlock(&mutex); |
540 return rc; | 540 return rc; |
541 } | 541 } |
542 | 542 |
543 | 543 |
544 //////////////////////////////////////////////// | 544 //////////////////////////////////////////////// |
545 // setup a new auto whitelister file | 545 // setup a new auto whitelister file |
546 // | 546 // |
547 WHITELISTERP add_whitelister_file(char *fn, int days); | 547 WHITELISTERP add_whitelister_file(char *fn, int days); |
548 WHITELISTERP add_whitelister_file(char *fn, int days) { | 548 WHITELISTERP add_whitelister_file(char *fn, int days) { |
549 WHITELISTERP rc = NULL; | 549 WHITELISTERP rc = NULL; |
550 pthread_mutex_lock(&whitelister_mutex); | 550 pthread_mutex_lock(&whitelister_mutex); |
551 whitelister_map::iterator i = whitelisters.find(fn); | 551 whitelister_map::iterator i = whitelisters.find(fn); |
552 if (i == whitelisters.end()) { | 552 if (i == whitelisters.end()) { |
553 rc = new WHITELISTER(fn, days); | 553 rc = new WHITELISTER(fn, days); |
554 whitelisters[fn] = rc; | 554 whitelisters[fn] = rc; |
555 } | 555 } |
556 else { | 556 else { |
557 rc = (*i).second; | 557 rc = (*i).second; |
558 rc->set_days(days); | 558 rc->set_days(days); |
559 } | 559 } |
560 pthread_mutex_unlock(&whitelister_mutex); | 560 pthread_mutex_unlock(&whitelister_mutex); |
561 return rc; | 561 return rc; |
562 } | 562 } |
563 | 563 |
564 | 564 |
565 //////////////////////////////////////////////// | 565 //////////////////////////////////////////////// |
566 // thread to check for whitelister hosts with old sockets that we can close | 566 // thread to check for whitelister hosts with old sockets that we can close |
567 // | 567 // |
568 void* whitelister_writer(void *arg) { | 568 void* whitelister_writer(void *arg) { |
569 while (true) { | 569 while (true) { |
570 sleep(maxauto_age); | 570 sleep(maxauto_age); |
571 pthread_mutex_lock(&whitelister_mutex); | 571 pthread_mutex_lock(&whitelister_mutex); |
572 for (whitelister_map::iterator i=whitelisters.begin(); i!=whitelisters.end(); i++) { | 572 for (whitelister_map::iterator i=whitelisters.begin(); i!=whitelisters.end(); i++) { |
573 WHITELISTERP v = (*i).second; | 573 WHITELISTERP v = (*i).second; |
574 v->writer(); | 574 v->writer(); |
575 } | 575 } |
576 pthread_mutex_unlock(&whitelister_mutex); | 576 pthread_mutex_unlock(&whitelister_mutex); |
577 } | 577 } |
578 return NULL; | 578 return NULL; |
579 } | |
580 | |
581 | |
582 DELAYWHITE::DELAYWHITE(char *loto_, WHITELISTERP w_, CONTEXTP con_) { | |
583 loto = loto_; | |
584 w = w_; | |
585 con = con_; | |
579 } | 586 } |
580 | 587 |
581 | 588 |
582 DNSBL::DNSBL(char *n, char *s, char *m) { | 589 DNSBL::DNSBL(char *n, char *s, char *m) { |
583 name = n; | 590 name = n; |
584 suffix = s; | 591 suffix = s; |
585 message = m; | 592 message = m; |
586 } | 593 } |
587 | 594 |
588 | 595 |
589 bool DNSBL::operator==(const DNSBL &rhs) { | 596 bool DNSBL::operator==(const DNSBL &rhs) { |
590 return (strcmp(name, rhs.name) == 0) && | 597 return (strcmp(name, rhs.name) == 0) && |
591 (strcmp(suffix, rhs.suffix) == 0) && | 598 (strcmp(suffix, rhs.suffix) == 0) && |
592 (strcmp(message, rhs.message) == 0); | 599 (strcmp(message, rhs.message) == 0); |
593 } | 600 } |
594 | 601 |
595 | 602 |
596 CONFIG::CONFIG() { | 603 CONFIG::CONFIG() { |
597 reference_count = 0; | 604 reference_count = 0; |
598 generation = 0; | 605 generation = 0; |
599 load_time = 0; | 606 load_time = 0; |
600 default_context = NULL; | 607 default_context = NULL; |
601 } | 608 } |
602 | 609 |
603 | 610 |
604 CONFIG::~CONFIG() { | 611 CONFIG::~CONFIG() { |
605 if (debug_syslog) { | 612 if (debug_syslog) { |
606 char buf[maxlen]; | 613 char buf[maxlen]; |
607 snprintf(buf, sizeof(buf), "freeing memory for old configuration generation %d", generation); | 614 snprintf(buf, sizeof(buf), "freeing memory for old configuration generation %d", generation); |
608 my_syslog(buf); | 615 my_syslog(buf); |
609 } | 616 } |
610 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { | 617 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { |
611 CONTEXT *c = *i; | 618 CONTEXT *c = *i; |
612 delete c; | 619 delete c; |
613 } | 620 } |
614 } | 621 } |
615 | 622 |
616 | 623 |
617 void CONFIG::add_context(CONTEXTP con) { | 624 void CONFIG::add_context(CONTEXTP con) { |
618 contexts.push_back(con); | 625 contexts.push_back(con); |
619 if (!default_context && !con->get_parent()) { | 626 if (!default_context && !con->get_parent()) { |
620 // first global context | 627 // first global context |
621 default_context = con; | 628 default_context = con; |
622 } | 629 } |
623 } | 630 } |
624 | 631 |
625 | 632 |
626 void CONFIG::add_to(char *to, CONTEXTP con) { | 633 void CONFIG::add_to(char *to, CONTEXTP con) { |
627 context_map::iterator i = env_to.find(to); | 634 context_map::iterator i = env_to.find(to); |
628 if (i != env_to.end()) { | 635 if (i != env_to.end()) { |
629 CONTEXTP c = (*i).second; | 636 CONTEXTP c = (*i).second; |
630 if ((c != con) && (c != con->get_parent())) { | 637 if ((c != con) && (c != con->get_parent())) { |
631 if (debug_syslog) { | 638 if (debug_syslog) { |
632 char oldname[maxlen]; | 639 char oldname[maxlen]; |
633 char newname[maxlen]; | 640 char newname[maxlen]; |
634 char *oldn = c->get_full_name(oldname, maxlen); | 641 char *oldn = c->get_full_name(oldname, maxlen); |
635 char *newn = con->get_full_name(newname, maxlen); | 642 char *newn = con->get_full_name(newname, maxlen); |
636 char buf[maxlen*3]; | 643 char buf[maxlen*3]; |
637 snprintf(buf, maxlen*3, "both %s and %s claim envelope to %s, the second one wins", oldn, newn, to); | 644 snprintf(buf, maxlen*3, "both %s and %s claim envelope to %s, the second one wins", oldn, newn, to); |
638 my_syslog(buf); | 645 my_syslog(buf); |
639 } | 646 } |
640 } | 647 } |
641 } | 648 } |
642 env_to[to] = con; | 649 env_to[to] = con; |
643 } | 650 } |
644 | 651 |
645 | 652 |
646 CONTEXTP CONFIG::find_context(char *to) { | 653 CONTEXTP CONFIG::find_context(char *to) { |
647 context_map::iterator i = env_to.find(to); | 654 context_map::iterator i = env_to.find(to); |
648 if (i != env_to.end()) return (*i).second; // found user@domain key | 655 if (i != env_to.end()) return (*i).second; // found user@domain key |
649 char *x = strchr(to, '@'); | 656 char *x = strchr(to, '@'); |
650 if (x) { | 657 if (x) { |
651 x++; | 658 x++; |
652 i = env_to.find(x); | 659 i = env_to.find(x); |
653 if (i != env_to.end()) return (*i).second; // found domain key | 660 if (i != env_to.end()) return (*i).second; // found domain key |
654 char y = *x; | 661 char y = *x; |
655 *x = '\0'; | 662 *x = '\0'; |
656 i = env_to.find(to); | 663 i = env_to.find(to); |
657 *x = y; | 664 *x = y; |
658 if (i != env_to.end()) return (*i).second; // found user@ key | 665 if (i != env_to.end()) return (*i).second; // found user@ key |
659 } | 666 } |
660 return default_context; | 667 return default_context; |
661 } | 668 } |
662 | 669 |
663 | 670 |
664 void CONFIG::dump() { | 671 void CONFIG::dump() { |
665 bool spamass = false; | 672 bool spamass = false; |
666 if (default_context) default_context->dump(true, spamass); | 673 if (default_context) default_context->dump(true, spamass); |
667 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { | 674 for (context_list::iterator i=contexts.begin(); i!=contexts.end(); i++) { |
668 CONTEXTP c = *i; | 675 CONTEXTP c = *i; |
669 CONTEXTP p = c->get_parent(); | 676 CONTEXTP p = c->get_parent(); |
670 if (!p && (c != default_context)) c->dump(false, spamass); | 677 if (!p && (c != default_context)) c->dump(false, spamass); |
671 } | 678 } |
672 char buf[maxlen]; | 679 char buf[maxlen]; |
673 for (context_map::iterator i=env_to.begin(); i!=env_to.end(); i++) { | 680 for (context_map::iterator i=env_to.begin(); i!=env_to.end(); i++) { |
674 char *to = (*i).first; | 681 char *to = (*i).first; |
675 CONTEXTP con = (*i).second; | 682 CONTEXTP con = (*i).second; |
676 printf("// envelope to %s \t-> context %s \n", to, con->get_full_name(buf,maxlen)); | 683 printf("// envelope to %s \t-> context %s \n", to, con->get_full_name(buf,maxlen)); |
677 } | 684 } |
678 if (spamass && (spamc == spamc_empty)) { | 685 if (spamass && (spamc == spamc_empty)) { |
679 printf("// *** warning - spamassassin filtering requested, but spamc not found by autoconf.\n"); | 686 printf("// *** warning - spamassassin filtering requested, but spamc not found by autoconf.\n"); |
680 } | 687 } |
681 } | 688 } |
682 | 689 |
683 | 690 |
684 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) { | 691 CONTEXT::CONTEXT(CONTEXTP parent_, char *name_) { |
685 parent = parent_; | 692 parent = parent_; |
686 name = name_; | 693 name = name_; |
687 verify_host = NULL; | 694 verify_host = NULL; |
688 verifier = NULL; | 695 verifier = NULL; |
689 generic_regx = NULL; | 696 generic_regx = NULL; |
690 generic_message = NULL; | 697 generic_message = NULL; |
691 autowhite_file = NULL; | 698 autowhite_file = NULL; |
692 whitelister = NULL; | 699 whitelister = NULL; |
693 env_from_default = (parent) ? token_inherit : token_unknown; | 700 env_from_default = (parent) ? token_inherit : token_unknown; |
694 content_filtering = (parent) ? parent->content_filtering : false; | 701 content_filtering = (parent) ? parent->content_filtering : false; |
695 content_suffix = NULL; | 702 content_suffix = NULL; |
696 content_message = NULL; | 703 content_message = NULL; |
697 uribl_suffix = NULL; | 704 uribl_suffix = NULL; |
698 uribl_message = NULL; | 705 uribl_message = NULL; |
699 host_limit = (parent) ? parent->host_limit : 0; | 706 host_limit = (parent) ? parent->host_limit : 0; |
700 host_limit_message = NULL; | 707 host_limit_message = NULL; |
701 host_random = (parent) ? parent->host_random : false; | 708 host_random = (parent) ? parent->host_random : false; |
702 tag_limit = (parent) ? parent->tag_limit : 0; | 709 tag_limit = (parent) ? parent->tag_limit : 0; |
703 tag_limit_message = NULL; | 710 tag_limit_message = NULL; |
704 spamassassin_limit = (parent) ? parent->spamassassin_limit : 0; | 711 spamassassin_limit = (parent) ? parent->spamassassin_limit : 0; |
705 require_match = (parent) ? parent->require_match : false; | 712 require_match = (parent) ? parent->require_match : false; |
706 dcc_greylist = (parent) ? parent->dcc_greylist : false; | 713 dcc_greylist = (parent) ? parent->dcc_greylist : false; |
707 dcc_bulk_threshold = (parent) ? parent->dcc_bulk_threshold : 0; | 714 dcc_bulk_threshold = (parent) ? parent->dcc_bulk_threshold : 0; |
708 default_rcpt_rate = INT_MAX; | 715 default_rcpt_rate = INT_MAX; |
709 } | 716 } |
710 | 717 |
711 | 718 |
712 CONTEXT::~CONTEXT() { | 719 CONTEXT::~CONTEXT() { |
713 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) { | 720 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) { |
714 DNSBLP d = (*i).second; | 721 DNSBLP d = (*i).second; |
715 // delete the underlying DNSBL objects. | 722 // delete the underlying DNSBL objects. |
716 delete d; | 723 delete d; |
717 } | 724 } |
718 if (generic_regx) regfree(&generic_pattern); | 725 if (generic_regx) regfree(&generic_pattern); |
719 } | 726 } |
720 | 727 |
721 | 728 |
722 bool CONTEXT::is_parent(CONTEXTP p) { | 729 bool CONTEXT::is_parent(CONTEXTP p) { |
723 if (p == parent) return true; | 730 if (p == parent) return true; |
724 if (!parent) return false; | 731 if (!parent) return false; |
725 return parent->is_parent(p); | 732 return parent->is_parent(p); |
726 } | 733 } |
727 | 734 |
728 | 735 |
729 char *CONTEXT::get_full_name(char *buffer, int size) { | 736 char *CONTEXT::get_full_name(char *buffer, int size) { |
730 if (!parent) return name; | 737 if (!parent) return name; |
731 char buf[maxlen]; | 738 char buf[maxlen]; |
732 snprintf(buffer, size, "%s.%s", parent->get_full_name(buf, maxlen), name); | 739 snprintf(buffer, size, "%s.%s", parent->get_full_name(buf, maxlen), name); |
733 return buffer; | 740 return buffer; |
734 } | 741 } |
735 | 742 |
736 | 743 |
737 bool CONTEXT::set_generic(char *regx, char *msg) | 744 bool CONTEXT::set_generic(char *regx, char *msg) |
738 { | 745 { |
739 int rc = 0; | 746 int rc = 0; |
740 if (generic_regx) regfree(&generic_pattern); | 747 if (generic_regx) regfree(&generic_pattern); |
741 generic_regx = regx; | 748 generic_regx = regx; |
742 generic_message = msg; | 749 generic_message = msg; |
743 if (generic_regx) { | 750 if (generic_regx) { |
744 rc = regcomp(&generic_pattern, regx, REG_NOSUB | REG_ICASE | REG_EXTENDED); | 751 rc = regcomp(&generic_pattern, regx, REG_NOSUB | REG_ICASE | REG_EXTENDED); |
745 } | 752 } |
746 return rc; // true iff bad pattern | 753 return rc; // true iff bad pattern |
747 } | 754 } |
748 | 755 |
749 | 756 |
750 char *CONTEXT::generic_match(char *client) | 757 char *CONTEXT::generic_match(char *client) |
751 { | 758 { |
752 if (parent && !generic_regx) return parent->generic_match(client); | 759 if (parent && !generic_regx) return parent->generic_match(client); |
753 if (!generic_regx) return NULL; | 760 if (!generic_regx) return NULL; |
754 if (0 == regexec(&generic_pattern, client, 0, NULL, 0)) { | 761 if (0 == regexec(&generic_pattern, client, 0, NULL, 0)) { |
755 return generic_message; | 762 return generic_message; |
756 } | 763 } |
757 return NULL; | 764 return NULL; |
758 } | 765 } |
759 | 766 |
760 | 767 |
761 bool CONTEXT::cover_env_to(char *to) { | 768 bool CONTEXT::cover_env_to(char *to) { |
762 char buffer[maxlen]; | 769 char buffer[maxlen]; |
763 char *x = strchr(to, '@'); | 770 char *x = strchr(to, '@'); |
764 if (x) x++; | 771 if (x) x++; |
765 else x = to; | 772 else x = to; |
766 if (*x == '\0') return true; // always allow covering addresses with no domain name, eg abuse@ | 773 if (*x == '\0') return true; // always allow covering addresses with no domain name, eg abuse@ |
767 if (!parent && env_to.empty()) return true; // empty env_to at global level covers everything | 774 if (!parent && env_to.empty()) return true; // empty env_to at global level covers everything |
768 string_set::iterator i = env_to.find(x); | 775 string_set::iterator i = env_to.find(x); |
769 if (i != env_to.end()) return true; // we cover the entire domain | 776 if (i != env_to.end()) return true; // we cover the entire domain |
770 if (x != to) { | 777 if (x != to) { |
771 i = env_to.find(to); | 778 i = env_to.find(to); |
772 if (i != env_to.end()) return true; // we cover the specific email address | 779 if (i != env_to.end()) return true; // we cover the specific email address |
773 } | 780 } |
774 return false; | 781 return false; |
775 } | 782 } |
776 | 783 |
777 | 784 |
778 VERIFYP CONTEXT::find_verify(char *to) { | 785 VERIFYP CONTEXT::find_verify(char *to) { |
779 if (verifier && (verify_host != token_myhostname) && cover_env_to(to)) | 786 if (verifier && (verify_host != token_myhostname) && cover_env_to(to)) |
780 return verifier; | 787 return verifier; |
781 else if (parent) | 788 else if (parent) |
782 return parent->find_verify(to); | 789 return parent->find_verify(to); |
783 else | 790 else |
784 return NULL; | 791 return NULL; |
785 } | 792 } |
786 | 793 |
787 | 794 |
788 WHITELISTERP CONTEXT::find_autowhite(char *from, char *to) { | 795 WHITELISTERP CONTEXT::find_autowhite(char *from, char *to) { |
789 if (whitelister && cover_env_to(to) && !cover_env_to(from)) | 796 if (whitelister && cover_env_to(to) && !cover_env_to(from)) |
790 return whitelister; | 797 return whitelister; |
791 else if (parent) | 798 else if (parent) |
792 return parent->find_autowhite(from, to); | 799 return parent->find_autowhite(from, to); |
793 else | 800 else |
794 return NULL; | 801 return NULL; |
795 } | 802 } |
796 | 803 |
797 | 804 |
798 int CONTEXT::find_rate(char *user) { | 805 int CONTEXT::find_rate(char *user) { |
799 if (rcpt_per_hour.empty()) return default_rcpt_rate; | 806 if (rcpt_per_hour.empty()) return default_rcpt_rate; |
800 rcpt_rates::iterator i = rcpt_per_hour.find(user); | 807 rcpt_rates::iterator i = rcpt_per_hour.find(user); |
801 return (i == rcpt_per_hour.end()) ? default_rcpt_rate : (*i).second; | 808 return (i == rcpt_per_hour.end()) ? default_rcpt_rate : (*i).second; |
802 } | 809 } |
803 | 810 |
804 | 811 |
805 char *CONTEXT::find_from(char *from, bool update_white) { | 812 char *CONTEXT::find_from(char *from, bool update_white) { |
806 if (whitelister && whitelister->is_white(from)) { | 813 if (whitelister && whitelister->is_white(from)) { |
807 if (update_white) { | 814 if (update_white) { |
808 // update senders timestamp to extend the whitelisting period | 815 // update senders timestamp to extend the whitelisting period |
809 if (debug_syslog > 1) { | 816 if (debug_syslog > 1) { |
810 char buf[maxlen]; | 817 char buf[maxlen]; |
811 char msg[maxlen]; | 818 char msg[maxlen]; |
812 snprintf(msg, sizeof(msg), "extend whitelist reply from <%s> in context %s", from, get_full_name(buf,maxlen)); | 819 snprintf(msg, sizeof(msg), "extend whitelist reply from <%s> in context %s", from, get_full_name(buf,maxlen)); |
813 my_syslog(msg); | 820 my_syslog(msg); |
814 } | 821 } |
815 whitelister->sent(strdup(from)); | 822 whitelister->sent(strdup(from)); |
816 } | 823 } |
817 return token_white; | 824 return token_white; |
818 } | 825 } |
819 char *rc = env_from_default; | 826 char *rc = env_from_default; |
820 string_map::iterator i = env_from.find(from); | 827 string_map::iterator i = env_from.find(from); |
821 if (i != env_from.end()) rc = (*i).second; // found user@domain key | 828 if (i != env_from.end()) rc = (*i).second; // found user@domain key |
822 else { | 829 else { |
823 char *x = strchr(from, '@'); | 830 char *x = strchr(from, '@'); |
824 if (x) { | 831 if (x) { |
825 x++; | 832 x++; |
826 i = env_from.find(x); | 833 i = env_from.find(x); |
827 if (i != env_from.end()) rc = (*i).second; // found domain key | 834 if (i != env_from.end()) rc = (*i).second; // found domain key |
828 else { | 835 else { |
829 char y = *x; | 836 char y = *x; |
830 *x = '\0'; | 837 *x = '\0'; |
831 i = env_from.find(from); | 838 i = env_from.find(from); |
832 *x = y; | 839 *x = y; |
833 if (i != env_from.end()) rc = (*i).second; // found user@ key | 840 if (i != env_from.end()) rc = (*i).second; // found user@ key |
834 } | 841 } |
835 } | 842 } |
836 } | 843 } |
837 if ((rc == token_inherit) && parent) return parent->find_from(from); | 844 if ((rc == token_inherit) && parent) return parent->find_from(from); |
838 return (rc == token_inherit) ? token_unknown : rc; | 845 return (rc == token_inherit) ? token_unknown : rc; |
839 } | 846 } |
840 | 847 |
841 | 848 |
842 CONTEXTP CONTEXT::find_context(char *from) { | 849 CONTEXTP CONTEXT::find_context(char *from) { |
843 context_map::iterator i = env_from_context.find(from); | 850 context_map::iterator i = env_from_context.find(from); |
844 if (i != env_from_context.end()) return (*i).second; // found user@domain key | 851 if (i != env_from_context.end()) return (*i).second; // found user@domain key |
845 char *x = strchr(from, '@'); | 852 char *x = strchr(from, '@'); |
846 if (x) { | 853 if (x) { |
847 x++; | 854 x++; |
848 i = env_from_context.find(x); | 855 i = env_from_context.find(x); |
849 if (i != env_from_context.end()) return (*i).second; // found domain key | 856 if (i != env_from_context.end()) return (*i).second; // found domain key |
850 char y = *x; | 857 char y = *x; |
851 *x = '\0'; | 858 *x = '\0'; |
852 i = env_from_context.find(from); | 859 i = env_from_context.find(from); |
853 *x = y; | 860 *x = y; |
854 if (i != env_from_context.end()) return (*i).second; // found user@ key | 861 if (i != env_from_context.end()) return (*i).second; // found user@ key |
855 } | 862 } |
856 return this; | 863 return this; |
857 } | 864 } |
858 | 865 |
859 | 866 |
860 CONTEXTP CONTEXT::find_from_context_name(char *name) { | 867 CONTEXTP CONTEXT::find_from_context_name(char *name) { |
861 context_map::iterator i = children.find(name); | 868 context_map::iterator i = children.find(name); |
862 if (i != children.end()) return (*i).second; | 869 if (i != children.end()) return (*i).second; |
863 return NULL; | 870 return NULL; |
864 } | 871 } |
865 | 872 |
866 | 873 |
867 DNSBLP CONTEXT::find_dnsbl(char *name) { | 874 DNSBLP CONTEXT::find_dnsbl(char *name) { |
868 dnsblp_map::iterator i = dnsbl_names.find(name); | 875 dnsblp_map::iterator i = dnsbl_names.find(name); |
869 if (i != dnsbl_names.end()) return (*i).second; | 876 if (i != dnsbl_names.end()) return (*i).second; |
870 if (parent) return parent->find_dnsbl(name); | 877 if (parent) return parent->find_dnsbl(name); |
871 return NULL; | 878 return NULL; |
872 } | 879 } |
873 | 880 |
874 | 881 |
875 char* CONTEXT::get_content_suffix() { | 882 char* CONTEXT::get_content_suffix() { |
876 if (!content_suffix && parent) return parent->get_content_suffix(); | 883 if (!content_suffix && parent) return parent->get_content_suffix(); |
877 return content_suffix; | 884 return content_suffix; |
878 } | 885 } |
879 | 886 |
880 | 887 |
881 char* CONTEXT::get_uribl_suffix() { | 888 char* CONTEXT::get_uribl_suffix() { |
882 if (!uribl_suffix && parent) return parent->get_uribl_suffix(); | 889 if (!uribl_suffix && parent) return parent->get_uribl_suffix(); |
883 return uribl_suffix; | 890 return uribl_suffix; |
884 } | 891 } |
885 | 892 |
886 | 893 |
887 char* CONTEXT::get_content_message() { | 894 char* CONTEXT::get_content_message() { |
888 if (!content_message && parent) return parent->get_content_message(); | 895 if (!content_message && parent) return parent->get_content_message(); |
889 return content_message; | 896 return content_message; |
890 } | 897 } |
891 | 898 |
892 | 899 |
893 char* CONTEXT::get_uribl_message() { | 900 char* CONTEXT::get_uribl_message() { |
894 if (!uribl_message && parent) return parent->get_uribl_message(); | 901 if (!uribl_message && parent) return parent->get_uribl_message(); |
895 return uribl_message; | 902 return uribl_message; |
896 } | 903 } |
897 | 904 |
898 | 905 |
899 string_set& CONTEXT::get_content_host_ignore() { | 906 string_set& CONTEXT::get_content_host_ignore() { |
900 if (content_host_ignore.empty() && parent) return parent->get_content_host_ignore(); | 907 if (content_host_ignore.empty() && parent) return parent->get_content_host_ignore(); |
901 return content_host_ignore; | 908 return content_host_ignore; |
902 } | 909 } |
903 | 910 |
904 | 911 |
905 string_set& CONTEXT::get_content_cctlds() { | 912 string_set& CONTEXT::get_content_cctlds() { |
906 if (content_cctlds.empty() && parent) return parent->get_content_cctlds(); | 913 if (content_cctlds.empty() && parent) return parent->get_content_cctlds(); |
907 return content_cctlds; | 914 return content_cctlds; |
908 } | 915 } |
909 | 916 |
910 string_set& CONTEXT::get_content_tlds() { | 917 string_set& CONTEXT::get_content_tlds() { |
911 if (content_tlds.empty() && parent) return parent->get_content_tlds(); | 918 if (content_tlds.empty() && parent) return parent->get_content_tlds(); |
912 return content_tlds; | 919 return content_tlds; |
913 } | 920 } |
914 | 921 |
915 | 922 |
916 string_set& CONTEXT::get_html_tags() { | 923 string_set& CONTEXT::get_html_tags() { |
917 if (html_tags.empty() && parent) return parent->get_html_tags(); | 924 if (html_tags.empty() && parent) return parent->get_html_tags(); |
918 return html_tags; | 925 return html_tags; |
919 } | 926 } |
920 | 927 |
921 | 928 |
922 dnsblp_list& CONTEXT::get_dnsbl_list() { | 929 dnsblp_list& CONTEXT::get_dnsbl_list() { |
923 if (dnsbl_list.empty() && parent) return parent->get_dnsbl_list(); | 930 if (dnsbl_list.empty() && parent) return parent->get_dnsbl_list(); |
924 return dnsbl_list; | 931 return dnsbl_list; |
925 } | 932 } |
926 | 933 |
927 | 934 |
928 bool CONTEXT::acceptable_content(recorder &memory, int score, int bulk, string& msg) { | 935 bool CONTEXT::acceptable_content(recorder &memory, int score, int bulk, string& msg) { |
929 if (spamassassin_limit && (score > spamassassin_limit)) { | 936 if (spamassassin_limit && (score > spamassassin_limit)) { |
930 char buf[maxlen]; | 937 char buf[maxlen]; |
931 snprintf(buf, sizeof(buf), "Mail rejected - spam assassin score %d", score); | 938 snprintf(buf, sizeof(buf), "Mail rejected - spam assassin score %d", score); |
932 msg = string(buf); | 939 msg = string(buf); |
933 return false; | 940 return false; |
934 } | 941 } |
935 if (dcc_bulk_threshold && (bulk > dcc_bulk_threshold)) { | 942 if (dcc_bulk_threshold && (bulk > dcc_bulk_threshold)) { |
936 char buf[maxlen]; | 943 char buf[maxlen]; |
937 snprintf(buf, sizeof(buf), "Mail rejected - dcc score %d", bulk); | 944 snprintf(buf, sizeof(buf), "Mail rejected - dcc score %d", bulk); |
938 msg = string(buf); | 945 msg = string(buf); |
939 return false; | 946 return false; |
940 } | 947 } |
941 if (memory.excessive_bad_tags(tag_limit)) { | 948 if (memory.excessive_bad_tags(tag_limit)) { |
942 msg = string(tag_limit_message); | 949 msg = string(tag_limit_message); |
943 return false; | 950 return false; |
944 } | 951 } |
945 if (!host_random && memory.excessive_hosts(host_limit)) { | 952 if (!host_random && memory.excessive_hosts(host_limit)) { |
946 msg = string(host_limit_message); | 953 msg = string(host_limit_message); |
947 return false; | 954 return false; |
948 } | 955 } |
949 return true; | 956 return true; |
950 } | 957 } |
951 | 958 |
952 | 959 |
953 void CONTEXT::dump(bool isdefault, bool &spamass, int level) { | 960 void CONTEXT::dump(bool isdefault, bool &spamass, int level) { |
954 char indent[maxlen]; | 961 char indent[maxlen]; |
955 int i = min(maxlen-1, level*4); | 962 int i = min(maxlen-1, level*4); |
956 memset(indent, ' ', i); | 963 memset(indent, ' ', i); |
957 indent[i] = '\0'; | 964 indent[i] = '\0'; |
958 char buf[maxlen]; | 965 char buf[maxlen]; |
959 char *fullname = get_full_name(buf,maxlen); | 966 char *fullname = get_full_name(buf,maxlen); |
960 printf("%s context %s { \t// %s\n", indent, name, fullname); | 967 printf("%s context %s { \t// %s\n", indent, name, fullname); |
961 | 968 |
962 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) { | 969 for (dnsblp_map::iterator i=dnsbl_names.begin(); i!=dnsbl_names.end(); i++) { |
963 char *n = (*i).first; | 970 char *n = (*i).first; |
964 DNSBL &d = *(*i).second; | 971 DNSBL &d = *(*i).second; |
965 printf("%s dnsbl %s %s \"%s\"; \n", indent, n, d.suffix, d.message); | 972 printf("%s dnsbl %s %s \"%s\"; \n", indent, n, d.suffix, d.message); |
966 } | 973 } |
967 | 974 |
968 dnsblp_list dl = get_dnsbl_list(); | 975 dnsblp_list dl = get_dnsbl_list(); |
969 if (!dl.empty()) { | 976 if (!dl.empty()) { |
970 printf("%s dnsbl_list", indent); | 977 printf("%s dnsbl_list", indent); |
971 for (dnsblp_list::iterator i=dl.begin(); i!=dl.end(); i++) { | 978 for (dnsblp_list::iterator i=dl.begin(); i!=dl.end(); i++) { |
972 DNSBL &d = *(*i); | 979 DNSBL &d = *(*i); |
973 printf(" %s", d.name); | 980 printf(" %s", d.name); |
974 } | 981 } |
975 printf("; \n"); | 982 printf("; \n"); |
976 } | 983 } |
977 | 984 |
978 if (content_filtering) { | 985 if (content_filtering) { |
979 printf("%s content on { \n", indent, env_from_default); | 986 printf("%s content on { \n", indent, env_from_default); |
980 if (content_suffix) { | 987 if (content_suffix) { |
981 printf("%s filter %s \"%s\"; \n", indent, content_suffix, content_message); | 988 printf("%s filter %s \"%s\"; \n", indent, content_suffix, content_message); |
982 } | 989 } |
983 if (uribl_suffix) { | 990 if (uribl_suffix) { |
984 printf("%s uribl %s \"%s\"; \n", indent, uribl_suffix, uribl_message); | 991 printf("%s uribl %s \"%s\"; \n", indent, uribl_suffix, uribl_message); |
985 } | 992 } |
986 if (!content_host_ignore.empty()) { | 993 if (!content_host_ignore.empty()) { |
987 printf("%s ignore { \n", indent); | 994 printf("%s ignore { \n", indent); |
988 for (string_set::iterator i=content_host_ignore.begin(); i!=content_host_ignore.end(); i++) { | 995 for (string_set::iterator i=content_host_ignore.begin(); i!=content_host_ignore.end(); i++) { |
989 printf("%s %s; \n", indent, *i); | 996 printf("%s %s; \n", indent, *i); |
990 } | 997 } |
991 printf("%s }; \n", indent); | 998 printf("%s }; \n", indent); |
992 } | 999 } |
993 if (!content_cctlds.empty()) { | 1000 if (!content_cctlds.empty()) { |
994 printf("%s cctld { \n", indent); | 1001 printf("%s cctld { \n", indent); |
995 printf("%s ", indent); | 1002 printf("%s ", indent); |
996 for (string_set::iterator i=content_cctlds.begin(); i!=content_cctlds.end(); i++) { | 1003 for (string_set::iterator i=content_cctlds.begin(); i!=content_cctlds.end(); i++) { |
997 printf("%s; ", *i); | 1004 printf("%s; ", *i); |
998 } | 1005 } |
999 printf("\n%s }; \n", indent); | 1006 printf("\n%s }; \n", indent); |
1000 } | 1007 } |
1001 if (!content_tlds.empty()) { | 1008 if (!content_tlds.empty()) { |
1002 printf("%s tld { \n", indent); | 1009 printf("%s tld { \n", indent); |
1003 printf("%s ", indent); | 1010 printf("%s ", indent); |
1004 for (string_set::iterator i=content_tlds.begin(); i!=content_tlds.end(); i++) { | 1011 for (string_set::iterator i=content_tlds.begin(); i!=content_tlds.end(); i++) { |
1005 printf("%s; ", *i); | 1012 printf("%s; ", *i); |
1006 } | 1013 } |
1007 printf("\n%s }; \n", indent); | 1014 printf("\n%s }; \n", indent); |
1008 } | 1015 } |
1009 if (!html_tags.empty()) { | 1016 if (!html_tags.empty()) { |
1010 printf("%s html_tags { \n", indent); | 1017 printf("%s html_tags { \n", indent); |
1011 printf("%s ", indent); | 1018 printf("%s ", indent); |
1012 for (string_set::iterator i=html_tags.begin(); i!=html_tags.end(); i++) { | 1019 for (string_set::iterator i=html_tags.begin(); i!=html_tags.end(); i++) { |
1013 printf("%s; ", *i); | 1020 printf("%s; ", *i); |
1014 } | 1021 } |
1015 printf("\n%s }; \n", indent); | 1022 printf("\n%s }; \n", indent); |
1016 } | 1023 } |
1017 if (host_limit_message) { | 1024 if (host_limit_message) { |
1018 printf("%s host_limit on %d \"%s\"; \n", indent, host_limit, host_limit_message); | 1025 printf("%s host_limit on %d \"%s\"; \n", indent, host_limit, host_limit_message); |
1019 } | 1026 } |
1020 else if (host_random) { | 1027 else if (host_random) { |
1021 printf("%s host_limit soft %d; \n", indent, host_limit); | 1028 printf("%s host_limit soft %d; \n", indent, host_limit); |
1022 } | 1029 } |
1023 else { | 1030 else { |
1024 printf("%s host_limit off; \n", indent); | 1031 printf("%s host_limit off; \n", indent); |
1025 } | 1032 } |
1026 if (tag_limit_message) { | 1033 if (tag_limit_message) { |
1027 printf("%s html_limit on %d \"%s\"; \n", indent, tag_limit, tag_limit_message); | 1034 printf("%s html_limit on %d \"%s\"; \n", indent, tag_limit, tag_limit_message); |
1028 } | 1035 } |
1029 else { | 1036 else { |
1030 printf("%s html_limit off; \n", indent); | 1037 printf("%s html_limit off; \n", indent); |
1031 } | 1038 } |
1032 printf("%s spamassassin %d; \n", indent, spamassassin_limit); | 1039 printf("%s spamassassin %d; \n", indent, spamassassin_limit); |
1033 printf("%s require_match %s; \n", indent, (require_match) ? "yes" : "no"); | 1040 printf("%s require_match %s; \n", indent, (require_match) ? "yes" : "no"); |
1034 printf("%s dcc_greylist %s; \n", indent, (dcc_greylist) ? "yes" : "no"); | 1041 printf("%s dcc_greylist %s; \n", indent, (dcc_greylist) ? "yes" : "no"); |
1035 if (dcc_bulk_threshold == 0) printf("%s dcc_bulk_threshold off; \n", indent); | 1042 if (dcc_bulk_threshold == 0) printf("%s dcc_bulk_threshold off; \n", indent); |
1036 else if (dcc_bulk_threshold >= dccbulk) printf("%s dcc_bulk_threshold many; \n", indent); | 1043 else if (dcc_bulk_threshold >= dccbulk) printf("%s dcc_bulk_threshold many; \n", indent); |
1037 else printf("%s dcc_bulk_threshold %d; \n", indent, dcc_bulk_threshold); | 1044 else printf("%s dcc_bulk_threshold %d; \n", indent, dcc_bulk_threshold); |
1038 printf("%s }; \n", indent); | 1045 printf("%s }; \n", indent); |
1039 spamass |= (spamassassin_limit != 0); | 1046 spamass |= (spamassassin_limit != 0); |
1040 } | 1047 } |
1041 else { | 1048 else { |
1042 printf("%s content off {}; \n", indent, env_from_default); | 1049 printf("%s content off {}; \n", indent, env_from_default); |
1043 } | 1050 } |
1044 | 1051 |
1045 printf("%s env_to { \t// %s\n", indent, fullname); | 1052 printf("%s env_to { \t// %s\n", indent, fullname); |
1046 for (string_set::iterator i=env_to.begin(); i!=env_to.end(); i++) { | 1053 for (string_set::iterator i=env_to.begin(); i!=env_to.end(); i++) { |
1047 printf("%s %s; \n", indent, *i); | 1054 printf("%s %s; \n", indent, *i); |
1048 } | 1055 } |
1049 printf("%s }; \n", indent); | 1056 printf("%s }; \n", indent); |
1050 | 1057 |
1051 if (verify_host) { | 1058 if (verify_host) { |
1052 printf("%s verify %s; \n", indent, verify_host); | 1059 printf("%s verify %s; \n", indent, verify_host); |
1053 } | 1060 } |
1054 | 1061 |
1055 if (generic_regx) { | 1062 if (generic_regx) { |
1056 printf("%s generic \"%s\" \n", indent, generic_regx); | 1063 printf("%s generic \"%s\" \n", indent, generic_regx); |
1057 printf("%s \"%s\"; \n", indent, generic_message); | 1064 printf("%s \"%s\"; \n", indent, generic_message); |
1058 } | 1065 } |
1059 | 1066 |
1060 if (autowhite_file && whitelister) { | 1067 if (autowhite_file && whitelister) { |
1061 printf("%s autowhite %d %s; \n", indent, whitelister->get_days(), autowhite_file); | 1068 printf("%s autowhite %d %s; \n", indent, whitelister->get_days(), autowhite_file); |
1062 } | 1069 } |
1063 | 1070 |
1064 for (context_map::iterator i=children.begin(); i!=children.end(); i++) { | 1071 for (context_map::iterator i=children.begin(); i!=children.end(); i++) { |
1065 CONTEXTP c = (*i).second; | 1072 CONTEXTP c = (*i).second; |
1066 c->dump(false, spamass, level+1); | 1073 c->dump(false, spamass, level+1); |
1067 } | 1074 } |
1068 | 1075 |
1069 printf("%s env_from %s { \t// %s\n", indent, env_from_default, fullname); | 1076 printf("%s env_from %s { \t// %s\n", indent, env_from_default, fullname); |
1070 if (!env_from.empty()) { | 1077 if (!env_from.empty()) { |
1071 printf("%s // white/black/unknown \n", indent); | 1078 printf("%s // white/black/unknown \n", indent); |
1072 for (string_map::iterator i=env_from.begin(); i!=env_from.end(); i++) { | 1079 for (string_map::iterator i=env_from.begin(); i!=env_from.end(); i++) { |
1073 char *f = (*i).first; | 1080 char *f = (*i).first; |
1074 char *t = (*i).second; | 1081 char *t = (*i).second; |
1075 printf("%s %s \t%s; \n", indent, f, t); | 1082 printf("%s %s \t%s; \n", indent, f, t); |
1076 } | 1083 } |
1077 } | 1084 } |
1078 if (!env_from_context.empty()) { | 1085 if (!env_from_context.empty()) { |
1079 printf("%s // child contexts \n", indent); | 1086 printf("%s // child contexts \n", indent); |
1080 for (context_map::iterator j=env_from_context.begin(); j!=env_from_context.end(); j++) { | 1087 for (context_map::iterator j=env_from_context.begin(); j!=env_from_context.end(); j++) { |
1081 char *f = (*j).first; | 1088 char *f = (*j).first; |
1082 CONTEXTP t = (*j).second; | 1089 CONTEXTP t = (*j).second; |
1083 printf("%s %s \t%s; \n", indent, f, t->name); | 1090 printf("%s %s \t%s; \n", indent, f, t->name); |
1084 } | 1091 } |
1085 } | 1092 } |
1086 printf("%s }; \n", indent); | 1093 printf("%s }; \n", indent); |
1087 | 1094 |
1088 if (isdefault) { | 1095 if (isdefault) { |
1089 printf("%s rate_limit %d { \n", indent, default_rcpt_rate); | 1096 printf("%s rate_limit %d { \n", indent, default_rcpt_rate); |
1090 for (rcpt_rates::iterator j=rcpt_per_hour.begin(); j!=rcpt_per_hour.end(); j++) { | 1097 for (rcpt_rates::iterator j=rcpt_per_hour.begin(); j!=rcpt_per_hour.end(); j++) { |
1091 char *u = (*j).first; | 1098 char *u = (*j).first; |
1092 int l = (*j).second; | 1099 int l = (*j).second; |
1093 printf("%s \"%s\" \t%d; \n", indent, u, l); | 1100 printf("%s \"%s\" \t%d; \n", indent, u, l); |
1094 } | 1101 } |
1095 printf("%s }; \n", indent); | 1102 printf("%s }; \n", indent); |
1096 } | 1103 } |
1097 | 1104 |
1098 printf("%s }; \n", indent); | 1105 printf("%s }; \n", indent); |
1099 } | 1106 } |
1100 | 1107 |
1101 | 1108 |
1102 //////////////////////////////////////////////// | 1109 //////////////////////////////////////////////// |
1103 // helper to discard the strings held by a string_set | 1110 // helper to discard the strings held by a string_set |
1104 // | 1111 // |
1105 void discard(string_set &s) { | 1112 void discard(string_set &s) { |
1106 for (string_set::iterator i=s.begin(); i!=s.end(); i++) { | 1113 for (string_set::iterator i=s.begin(); i!=s.end(); i++) { |
1107 free(*i); | 1114 free(*i); |
1108 } | 1115 } |
1109 s.clear(); | 1116 s.clear(); |
1110 } | 1117 } |
1111 | 1118 |
1112 | 1119 |
1113 //////////////////////////////////////////////// | 1120 //////////////////////////////////////////////// |
1114 // helper to register a string in a string set | 1121 // helper to register a string in a string set |
1115 // | 1122 // |
1116 char* register_string(string_set &s, char *name) { | 1123 char* register_string(string_set &s, char *name) { |
1117 string_set::iterator i = s.find(name); | 1124 string_set::iterator i = s.find(name); |
1118 if (i != s.end()) return *i; | 1125 if (i != s.end()) return *i; |
1119 char *x = strdup(name); | 1126 char *x = strdup(name); |
1120 s.insert(x); | 1127 s.insert(x); |
1121 return x; | 1128 return x; |
1122 } | 1129 } |
1123 | 1130 |
1124 | 1131 |
1125 //////////////////////////////////////////////// | 1132 //////////////////////////////////////////////// |
1126 // register a global string | 1133 // register a global string |
1127 // | 1134 // |
1128 char* register_string(char *name) { | 1135 char* register_string(char *name) { |
1129 return register_string(all_strings, name); | 1136 return register_string(all_strings, name); |
1130 } | 1137 } |
1131 | 1138 |
1132 | 1139 |
1133 //////////////////////////////////////////////// | 1140 //////////////////////////////////////////////// |
1134 // clear all global strings, helper for valgrind checking | 1141 // clear all global strings, helper for valgrind checking |
1135 // | 1142 // |
1136 void clear_strings() { | 1143 void clear_strings() { |
1137 discard(all_strings); | 1144 discard(all_strings); |
1138 } | 1145 } |
1139 | 1146 |
1140 | 1147 |
1141 //////////////////////////////////////////////// | 1148 //////////////////////////////////////////////// |
1142 // | 1149 // |
1143 bool tsa(TOKEN &tok, char *token); | 1150 bool tsa(TOKEN &tok, char *token); |
1144 bool tsa(TOKEN &tok, char *token) { | 1151 bool tsa(TOKEN &tok, char *token) { |
1145 char *have = tok.next(); | 1152 char *have = tok.next(); |
1146 if (have == token) return true; | 1153 if (have == token) return true; |
1147 tok.token_error(token, have); | 1154 tok.token_error(token, have); |
1148 return false; | 1155 return false; |
1149 } | 1156 } |
1150 | 1157 |
1151 | 1158 |
1152 //////////////////////////////////////////////// | 1159 //////////////////////////////////////////////// |
1153 // | 1160 // |
1154 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1161 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
1155 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1162 bool parse_dnsbl(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
1156 char *name = tok.next(); | 1163 char *name = tok.next(); |
1157 char *suf = tok.next(); | 1164 char *suf = tok.next(); |
1158 char *msg = tok.next(); | 1165 char *msg = tok.next(); |
1159 if (!tsa(tok, token_semi)) return false; | 1166 if (!tsa(tok, token_semi)) return false; |
1160 DNSBLP dnsnew = new DNSBL(name, suf, msg); | 1167 DNSBLP dnsnew = new DNSBL(name, suf, msg); |
1161 DNSBLP dnsold = me.find_dnsbl(name); | 1168 DNSBLP dnsold = me.find_dnsbl(name); |
1162 if (dnsold && (*dnsold == *dnsnew)) { | 1169 if (dnsold && (*dnsold == *dnsnew)) { |
1163 // duplicate redefinition, ignore it | 1170 // duplicate redefinition, ignore it |
1164 delete dnsnew; | 1171 delete dnsnew; |
1165 return true; | 1172 return true; |
1166 } | 1173 } |
1167 me.add_dnsbl(name, dnsnew); | 1174 me.add_dnsbl(name, dnsnew); |
1168 return true; | 1175 return true; |
1169 } | 1176 } |
1170 | 1177 |
1171 | 1178 |
1172 //////////////////////////////////////////////// | 1179 //////////////////////////////////////////////// |
1173 // | 1180 // |
1174 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1181 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
1175 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1182 bool parse_dnsbll(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
1176 while (true) { | 1183 while (true) { |
1177 char *have = tok.next(); | 1184 char *have = tok.next(); |
1178 if (!have) break; | 1185 if (!have) break; |
1179 if (have == token_semi) break; | 1186 if (have == token_semi) break; |
1180 DNSBLP dns = me.find_dnsbl(have); | 1187 DNSBLP dns = me.find_dnsbl(have); |
1181 if (dns) { | 1188 if (dns) { |
1182 me.add_dnsbl(dns); | 1189 me.add_dnsbl(dns); |
1183 } | 1190 } |
1184 else { | 1191 else { |
1185 tok.token_error("dnsbl name", have); | 1192 tok.token_error("dnsbl name", have); |
1186 return false; | 1193 return false; |
1187 } | 1194 } |
1188 } | 1195 } |
1189 return true; | 1196 return true; |
1190 } | 1197 } |
1191 | 1198 |
1192 | 1199 |
1193 //////////////////////////////////////////////// | 1200 //////////////////////////////////////////////// |
1194 // | 1201 // |
1195 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1202 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
1196 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1203 bool parse_content(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
1197 char *setting = tok.next(); | 1204 char *setting = tok.next(); |
1198 if (setting == token_on) { | 1205 if (setting == token_on) { |
1199 me.set_content_filtering(true); | 1206 me.set_content_filtering(true); |
1200 } | 1207 } |
1201 else if (setting == token_off) { | 1208 else if (setting == token_off) { |
1202 me.set_content_filtering(false); | 1209 me.set_content_filtering(false); |
1203 } | 1210 } |
1204 else { | 1211 else { |
1205 tok.token_error("on/off", setting); | 1212 tok.token_error("on/off", setting); |
1206 return false; | 1213 return false; |
1207 } | 1214 } |
1208 if (!tsa(tok, token_lbrace)) return false; | 1215 if (!tsa(tok, token_lbrace)) return false; |
1209 while (true) { | 1216 while (true) { |
1210 char *have = tok.next(); | 1217 char *have = tok.next(); |
1211 if (!have) break; | 1218 if (!have) break; |
1212 if (have == token_filter) { | 1219 if (have == token_filter) { |
1213 char *suffix = tok.next(); | 1220 char *suffix = tok.next(); |
1214 char *messag = tok.next(); | 1221 char *messag = tok.next(); |
1215 me.set_content_suffix(suffix); | 1222 me.set_content_suffix(suffix); |
1216 me.set_content_message(messag); | 1223 me.set_content_message(messag); |
1217 if (!tsa(tok, token_semi)) return false; | 1224 if (!tsa(tok, token_semi)) return false; |
1218 } | 1225 } |
1219 else if (have == token_uribl) { | 1226 else if (have == token_uribl) { |
1220 char *suffix = tok.next(); | 1227 char *suffix = tok.next(); |
1221 char *messag = tok.next(); | 1228 char *messag = tok.next(); |
1222 me.set_uribl_suffix(suffix); | 1229 me.set_uribl_suffix(suffix); |
1223 me.set_uribl_message(messag); | 1230 me.set_uribl_message(messag); |
1224 if (!tsa(tok, token_semi)) return false; | 1231 if (!tsa(tok, token_semi)) return false; |
1225 } | 1232 } |
1226 else if (have == token_ignore) { | 1233 else if (have == token_ignore) { |
1227 if (!tsa(tok, token_lbrace)) return false; | 1234 if (!tsa(tok, token_lbrace)) return false; |
1228 while (true) { | 1235 while (true) { |
1229 if (!have) break; | 1236 if (!have) break; |
1230 char *have = tok.next(); | 1237 char *have = tok.next(); |
1231 if (have == token_rbrace) break; // done | 1238 if (have == token_rbrace) break; // done |
1232 me.add_ignore(have); | 1239 me.add_ignore(have); |
1233 } | 1240 } |
1234 if (!tsa(tok, token_semi)) return false; | 1241 if (!tsa(tok, token_semi)) return false; |
1235 } | 1242 } |
1236 else if (have == token_tld) { | 1243 else if (have == token_tld) { |
1237 if (!tsa(tok, token_lbrace)) return false; | 1244 if (!tsa(tok, token_lbrace)) return false; |
1238 while (true) { | 1245 while (true) { |
1239 char *have = tok.next(); | 1246 char *have = tok.next(); |
1240 if (!have) break; | 1247 if (!have) break; |
1241 if (have == token_rbrace) break; // done | 1248 if (have == token_rbrace) break; // done |
1242 me.add_tld(have); | 1249 me.add_tld(have); |
1243 } | 1250 } |
1244 if (!tsa(tok, token_semi)) return false; | 1251 if (!tsa(tok, token_semi)) return false; |
1245 } | 1252 } |
1246 else if (have == token_cctld) { | 1253 else if (have == token_cctld) { |
1247 if (!tsa(tok, token_lbrace)) return false; | 1254 if (!tsa(tok, token_lbrace)) return false; |
1248 while (true) { | 1255 while (true) { |
1249 char *have = tok.next(); | 1256 char *have = tok.next(); |
1250 if (!have) break; | 1257 if (!have) break; |
1251 if (have == token_rbrace) break; // done | 1258 if (have == token_rbrace) break; // done |
1252 me.add_cctld(have); | 1259 me.add_cctld(have); |
1253 } | 1260 } |
1254 if (!tsa(tok, token_semi)) return false; | 1261 if (!tsa(tok, token_semi)) return false; |
1255 } | 1262 } |
1256 else if (have == token_html_tags) { | 1263 else if (have == token_html_tags) { |
1257 if (!tsa(tok, token_lbrace)) return false; | 1264 if (!tsa(tok, token_lbrace)) return false; |
1258 while (true) { | 1265 while (true) { |
1259 char *have = tok.next(); | 1266 char *have = tok.next(); |
1260 if (!have) break; | 1267 if (!have) break; |
1261 if (have == token_rbrace) { | 1268 if (have == token_rbrace) { |
1262 break; // done | 1269 break; // done |
1263 } | 1270 } |
1264 else { | 1271 else { |
1265 me.add_tag(have); // base version | 1272 me.add_tag(have); // base version |
1266 char buf[200]; | 1273 char buf[200]; |
1267 snprintf(buf, sizeof(buf), "/%s", have); | 1274 snprintf(buf, sizeof(buf), "/%s", have); |
1268 me.add_tag(register_string(buf)); // leading / | 1275 me.add_tag(register_string(buf)); // leading / |
1269 snprintf(buf, sizeof(buf), "%s/", have); | 1276 snprintf(buf, sizeof(buf), "%s/", have); |
1270 me.add_tag(register_string(buf)); // trailing / | 1277 me.add_tag(register_string(buf)); // trailing / |
1271 } | 1278 } |
1272 } | 1279 } |
1273 if (!tsa(tok, token_semi)) return false; | 1280 if (!tsa(tok, token_semi)) return false; |
1274 } | 1281 } |
1275 else if (have == token_html_limit) { | 1282 else if (have == token_html_limit) { |
1276 have = tok.next(); | 1283 have = tok.next(); |
1277 if (have == token_on) { | 1284 if (have == token_on) { |
1278 me.set_tag_limit(tok.nextint()); | 1285 me.set_tag_limit(tok.nextint()); |
1279 me.set_tag_message(tok.next()); | 1286 me.set_tag_message(tok.next()); |
1280 } | 1287 } |
1281 else if (have == token_off) { | 1288 else if (have == token_off) { |
1282 me.set_tag_limit(0); | 1289 me.set_tag_limit(0); |
1283 me.set_tag_message(NULL); | 1290 me.set_tag_message(NULL); |
1284 } | 1291 } |
1285 else { | 1292 else { |
1286 tok.token_error("on/off", have); | 1293 tok.token_error("on/off", have); |
1287 return false; | 1294 return false; |
1288 } | 1295 } |
1289 if (!tsa(tok, token_semi)) return false; | 1296 if (!tsa(tok, token_semi)) return false; |
1290 } | 1297 } |
1291 else if (have == token_host_limit) { | 1298 else if (have == token_host_limit) { |
1292 have = tok.next(); | 1299 have = tok.next(); |
1293 if (have == token_on) { | 1300 if (have == token_on) { |
1294 me.set_host_limit(tok.nextint()); | 1301 me.set_host_limit(tok.nextint()); |
1295 me.set_host_message(tok.next()); | 1302 me.set_host_message(tok.next()); |
1296 me.set_host_random(false); | 1303 me.set_host_random(false); |
1297 } | 1304 } |
1298 else if (have == token_off) { | 1305 else if (have == token_off) { |
1299 me.set_host_limit(0); | 1306 me.set_host_limit(0); |
1300 me.set_host_message(NULL); | 1307 me.set_host_message(NULL); |
1301 me.set_host_random(false); | 1308 me.set_host_random(false); |
1302 } | 1309 } |
1303 else if (have == token_soft) { | 1310 else if (have == token_soft) { |
1304 me.set_host_limit(tok.nextint()); | 1311 me.set_host_limit(tok.nextint()); |
1305 me.set_host_message(NULL); | 1312 me.set_host_message(NULL); |
1306 me.set_host_random(true); | 1313 me.set_host_random(true); |
1307 } | 1314 } |
1308 else { | 1315 else { |
1309 tok.token_error("on/off/soft", have); | 1316 tok.token_error("on/off/soft", have); |
1310 return false; | 1317 return false; |
1311 } | 1318 } |
1312 if (!tsa(tok, token_semi)) return false; | 1319 if (!tsa(tok, token_semi)) return false; |
1313 } | 1320 } |
1314 else if (have == token_spamassassin) { | 1321 else if (have == token_spamassassin) { |
1315 me.set_spamassassin_limit(tok.nextint()); | 1322 me.set_spamassassin_limit(tok.nextint()); |
1316 if (!tsa(tok, token_semi)) return false; | 1323 if (!tsa(tok, token_semi)) return false; |
1317 } | 1324 } |
1318 else if (have == token_require) { | 1325 else if (have == token_require) { |
1319 have = tok.next(); | 1326 have = tok.next(); |
1320 if (have == token_yes) me.set_require(true); | 1327 if (have == token_yes) me.set_require(true); |
1321 else if (have == token_no) me.set_require(false); | 1328 else if (have == token_no) me.set_require(false); |
1322 else { | 1329 else { |
1323 tok.token_error("yes/no", have); | 1330 tok.token_error("yes/no", have); |
1324 return false; | 1331 return false; |
1325 } | 1332 } |
1326 if (!tsa(tok, token_semi)) return false; | 1333 if (!tsa(tok, token_semi)) return false; |
1327 } | 1334 } |
1328 else if (have == token_dccgrey) { | 1335 else if (have == token_dccgrey) { |
1329 have = tok.next(); | 1336 have = tok.next(); |
1330 if (have == token_yes) me.set_grey(true); | 1337 if (have == token_yes) me.set_grey(true); |
1331 else if (have == token_no) me.set_grey(false); | 1338 else if (have == token_no) me.set_grey(false); |
1332 else { | 1339 else { |
1333 tok.token_error("yes/no", have); | 1340 tok.token_error("yes/no", have); |
1334 return false; | 1341 return false; |
1335 } | 1342 } |
1336 if (!tsa(tok, token_semi)) return false; | 1343 if (!tsa(tok, token_semi)) return false; |
1337 } | 1344 } |
1338 else if (have == token_dccbulk) { | 1345 else if (have == token_dccbulk) { |
1339 have = tok.next(); | 1346 have = tok.next(); |
1340 if (have == token_off) me.set_bulk(0); | 1347 if (have == token_off) me.set_bulk(0); |
1341 else if (have == token_many) me.set_bulk(dccbulk); | 1348 else if (have == token_many) me.set_bulk(dccbulk); |
1342 else { | 1349 else { |
1343 char *e; | 1350 char *e; |
1344 long i = strtol(have, &e, 10); | 1351 long i = strtol(have, &e, 10); |
1345 if (*e != '\0') { | 1352 if (*e != '\0') { |
1346 tok.token_error("integer", have); | 1353 tok.token_error("integer", have); |
1347 return false; | 1354 return false; |
1348 } | 1355 } |
1349 me.set_bulk((int)i); | 1356 me.set_bulk((int)i); |
1350 } | 1357 } |
1351 if (!tsa(tok, token_semi)) return false; | 1358 if (!tsa(tok, token_semi)) return false; |
1352 } | 1359 } |
1353 else if (have == token_rbrace) { | 1360 else if (have == token_rbrace) { |
1354 break; // done | 1361 break; // done |
1355 } | 1362 } |
1356 else { | 1363 else { |
1357 tok.token_error("content keyword", have); | 1364 tok.token_error("content keyword", have); |
1358 return false; | 1365 return false; |
1359 } | 1366 } |
1360 } | 1367 } |
1361 return tsa(tok, token_semi); | 1368 return tsa(tok, token_semi); |
1362 } | 1369 } |
1363 | 1370 |
1364 | 1371 |
1365 //////////////////////////////////////////////// | 1372 //////////////////////////////////////////////// |
1366 // | 1373 // |
1367 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1374 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
1368 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1375 bool parse_envto(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
1369 if (!tsa(tok, token_lbrace)) return false; | 1376 if (!tsa(tok, token_lbrace)) return false; |
1370 while (true) { | 1377 while (true) { |
1371 char *have = tok.next(); | 1378 char *have = tok.next(); |
1372 if (!have) break; | 1379 if (!have) break; |
1373 if (have == token_rbrace) break; | 1380 if (have == token_rbrace) break; |
1374 if (have == token_semi) { | 1381 if (have == token_semi) { |
1375 // optional separators | 1382 // optional separators |
1376 } | 1383 } |
1377 else if (have == token_dccto) { | 1384 else if (have == token_dccto) { |
1378 char *flavor = tok.next(); | 1385 char *flavor = tok.next(); |
1379 if (!tsa(tok, token_lbrace)) return false; | 1386 if (!tsa(tok, token_lbrace)) return false; |
1380 bool keeping = false; | 1387 bool keeping = false; |
1381 while (true) { | 1388 while (true) { |
1382 char *have = tok.next(); | 1389 char *have = tok.next(); |
1383 if (!have) break; | 1390 if (!have) break; |
1384 if (have == token_rbrace) break; | 1391 if (have == token_rbrace) break; |
1385 if (have == flavor) { | 1392 if (have == flavor) { |
1386 keeping = true; | 1393 keeping = true; |
1387 continue; | 1394 continue; |
1388 } | 1395 } |
1389 else if ((have == token_ok) || (have == token_ok2) || (have == token_many)) { | 1396 else if ((have == token_ok) || (have == token_ok2) || (have == token_many)) { |
1390 keeping = false; | 1397 keeping = false; |
1391 continue; | 1398 continue; |
1392 } | 1399 } |
1393 if (have == token_envto) { | 1400 if (have == token_envto) { |
1394 have = tok.next(); | 1401 have = tok.next(); |
1395 if (keeping) { | 1402 if (keeping) { |
1396 if (me.allow_env_to(have)) { | 1403 if (me.allow_env_to(have)) { |
1397 me.add_to(have); | 1404 me.add_to(have); |
1398 dc.add_to(have, &me); | 1405 dc.add_to(have, &me); |
1399 } | 1406 } |
1400 } | 1407 } |
1401 } | 1408 } |
1402 //else if (have == token_substitute) { | 1409 //else if (have == token_substitute) { |
1403 // if (tok.next() == token_mailhost) { | 1410 // if (tok.next() == token_mailhost) { |
1404 // have = tok.next(); | 1411 // have = tok.next(); |
1405 // if (keeping) { | 1412 // if (keeping) { |
1406 // if (me.allow_env_to(have)) { | 1413 // if (me.allow_env_to(have)) { |
1407 // me.add_to(have); | 1414 // me.add_to(have); |
1408 // dc.add_to(have, &me); | 1415 // dc.add_to(have, &me); |
1409 // } | 1416 // } |
1410 // } | 1417 // } |
1411 // } | 1418 // } |
1412 //} | 1419 //} |
1413 tok.skipeol(); | 1420 tok.skipeol(); |
1414 } | 1421 } |
1415 } | 1422 } |
1416 else if (me.allow_env_to(have)) { | 1423 else if (me.allow_env_to(have)) { |
1417 me.add_to(have); | 1424 me.add_to(have); |
1418 dc.add_to(have, &me); | 1425 dc.add_to(have, &me); |
1419 } | 1426 } |
1420 else { | 1427 else { |
1421 tok.token_error("user@ or user@domain.tld or domain.tld where domain.tld allowed by parent context", have); | 1428 tok.token_error("user@ or user@domain.tld or domain.tld where domain.tld allowed by parent context", have); |
1422 return false; | 1429 return false; |
1423 } | 1430 } |
1424 } | 1431 } |
1425 return tsa(tok, token_semi); | 1432 return tsa(tok, token_semi); |
1426 } | 1433 } |
1427 | 1434 |
1428 | 1435 |
1429 //////////////////////////////////////////////// | 1436 //////////////////////////////////////////////// |
1430 // | 1437 // |
1431 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1438 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
1432 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1439 bool parse_verify(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
1433 char *host = tok.next(); | 1440 char *host = tok.next(); |
1434 if (!tsa(tok, token_semi)) return false; | 1441 if (!tsa(tok, token_semi)) return false; |
1435 me.set_verify(host); | 1442 me.set_verify(host); |
1436 me.set_verifier(add_verify_host(host)); | 1443 me.set_verifier(add_verify_host(host)); |
1437 return true; | 1444 return true; |
1438 } | 1445 } |
1439 | 1446 |
1440 | 1447 |
1441 //////////////////////////////////////////////// | 1448 //////////////////////////////////////////////// |
1442 // | 1449 // |
1443 bool parse_generic(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1450 bool parse_generic(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
1444 bool parse_generic(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1451 bool parse_generic(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
1445 char *regx = tok.next(); | 1452 char *regx = tok.next(); |
1446 char *msg = tok.next(); | 1453 char *msg = tok.next(); |
1447 if (!tsa(tok, token_semi)) return false; | 1454 if (!tsa(tok, token_semi)) return false; |
1448 if (me.set_generic(regx, msg)) { | 1455 if (me.set_generic(regx, msg)) { |
1449 tok.token_error("invalid regular expression %s", regx, regx); | 1456 tok.token_error("invalid regular expression %s", regx, regx); |
1450 return false; | 1457 return false; |
1451 } | 1458 } |
1452 return true; | 1459 return true; |
1453 } | 1460 } |
1454 | 1461 |
1455 | 1462 |
1456 //////////////////////////////////////////////// | 1463 //////////////////////////////////////////////// |
1457 // | 1464 // |
1458 bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1465 bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
1459 bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1466 bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
1460 int days = tok.nextint(); | 1467 int days = tok.nextint(); |
1461 char *fn = tok.next(); | 1468 char *fn = tok.next(); |
1462 if (!tsa(tok, token_semi)) return false; | 1469 if (!tsa(tok, token_semi)) return false; |
1463 me.set_autowhite(fn); | 1470 me.set_autowhite(fn); |
1464 me.set_whitelister(add_whitelister_file(fn, days)); | 1471 me.set_whitelister(add_whitelister_file(fn, days)); |
1465 return true; | 1472 return true; |
1466 } | 1473 } |
1467 | 1474 |
1468 | 1475 |
1469 //////////////////////////////////////////////// | 1476 //////////////////////////////////////////////// |
1470 // | 1477 // |
1471 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1478 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
1472 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1479 bool parse_envfrom(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
1473 char *st = tok.next(); | 1480 char *st = tok.next(); |
1474 if ((st == token_black) || (st == token_white) || (st == token_unknown) || (st == token_inherit)) { | 1481 if ((st == token_black) || (st == token_white) || (st == token_unknown) || (st == token_inherit)) { |
1475 me.set_from_default(st); | 1482 me.set_from_default(st); |
1476 } | 1483 } |
1477 else { | 1484 else { |
1478 tok.push(st); | 1485 tok.push(st); |
1479 } | 1486 } |
1480 if (!tsa(tok, token_lbrace)) return false; | 1487 if (!tsa(tok, token_lbrace)) return false; |
1481 while (true) { | 1488 while (true) { |
1482 char *have = tok.next(); | 1489 char *have = tok.next(); |
1483 if (!have) break; | 1490 if (!have) break; |
1484 if (have == token_rbrace) break; | 1491 if (have == token_rbrace) break; |
1485 if (have == token_semi) { | 1492 if (have == token_semi) { |
1486 // optional separators | 1493 // optional separators |
1487 } | 1494 } |
1488 else if (have == token_dccfrom) { | 1495 else if (have == token_dccfrom) { |
1489 if (!tsa(tok, token_lbrace)) return false; | 1496 if (!tsa(tok, token_lbrace)) return false; |
1490 bool keeping = false; | 1497 bool keeping = false; |
1491 bool many = false; | 1498 bool many = false; |
1492 while (true) { | 1499 while (true) { |
1493 char *have = tok.next(); | 1500 char *have = tok.next(); |
1494 if (!have) break; | 1501 if (!have) break; |
1495 if (have == token_rbrace) break; | 1502 if (have == token_rbrace) break; |
1496 if (have == token_ok) { | 1503 if (have == token_ok) { |
1497 keeping = true; | 1504 keeping = true; |
1498 many = false; | 1505 many = false; |
1499 continue; | 1506 continue; |
1500 } | 1507 } |
1501 else if (have == token_many) { | 1508 else if (have == token_many) { |
1502 keeping = true; | 1509 keeping = true; |
1503 many = true; | 1510 many = true; |
1504 continue; | 1511 continue; |
1505 } | 1512 } |
1506 else if (have == token_ok2) { | 1513 else if (have == token_ok2) { |
1507 keeping = false; | 1514 keeping = false; |
1508 continue; | 1515 continue; |
1509 } | 1516 } |
1510 if (have == token_envfrom) { | 1517 if (have == token_envfrom) { |
1511 have = tok.next(); | 1518 have = tok.next(); |
1512 if (keeping) { | 1519 if (keeping) { |
1513 me.add_from(have, (many) ? token_black : token_white); | 1520 me.add_from(have, (many) ? token_black : token_white); |
1514 } | 1521 } |
1515 } | 1522 } |
1516 else if (have == token_substitute) { | 1523 else if (have == token_substitute) { |
1517 if (tok.next() == token_mailhost) { | 1524 if (tok.next() == token_mailhost) { |
1518 have = tok.next(); | 1525 have = tok.next(); |
1519 me.add_from(have, (many) ? token_black : token_white); | 1526 me.add_from(have, (many) ? token_black : token_white); |
1520 } | 1527 } |
1521 } | 1528 } |
1522 tok.skipeol(); | 1529 tok.skipeol(); |
1523 } | 1530 } |
1524 } | 1531 } |
1525 else { | 1532 else { |
1526 // may be a valid email address or domain name | 1533 // may be a valid email address or domain name |
1527 char *st = tok.next(); | 1534 char *st = tok.next(); |
1528 if ((st == token_white) || (st == token_black) || (st == token_unknown) || (st == token_inherit)) { | 1535 if ((st == token_white) || (st == token_black) || (st == token_unknown) || (st == token_inherit)) { |
1529 me.add_from(have, st); | 1536 me.add_from(have, st); |
1530 } | 1537 } |
1531 else { | 1538 else { |
1532 CONTEXTP con = me.find_from_context_name(st); | 1539 CONTEXTP con = me.find_from_context_name(st); |
1533 if (con) { | 1540 if (con) { |
1534 me.add_from_context(have, con); | 1541 me.add_from_context(have, con); |
1535 } | 1542 } |
1536 else { | 1543 else { |
1537 tok.token_error("white/black/unknown/inherit or child context name", st); | 1544 tok.token_error("white/black/unknown/inherit or child context name", st); |
1538 return false; | 1545 return false; |
1539 } | 1546 } |
1540 } | 1547 } |
1541 } | 1548 } |
1542 } | 1549 } |
1543 return tsa(tok, token_semi); | 1550 return tsa(tok, token_semi); |
1544 } | 1551 } |
1545 | 1552 |
1546 | 1553 |
1547 //////////////////////////////////////////////// | 1554 //////////////////////////////////////////////// |
1548 // | 1555 // |
1549 bool parse_rate(TOKEN &tok, CONFIG &dc, CONTEXT &me); | 1556 bool parse_rate(TOKEN &tok, CONFIG &dc, CONTEXT &me); |
1550 bool parse_rate(TOKEN &tok, CONFIG &dc, CONTEXT &me) { | 1557 bool parse_rate(TOKEN &tok, CONFIG &dc, CONTEXT &me) { |
1551 char *def = tok.next(); | 1558 char *def = tok.next(); |
1552 tok.push(def); | 1559 tok.push(def); |
1553 if (def != token_lbrace) me.set_default_rate(tok.nextint()); | 1560 if (def != token_lbrace) me.set_default_rate(tok.nextint()); |
1554 if (!tsa(tok, token_lbrace)) return false; | 1561 if (!tsa(tok, token_lbrace)) return false; |
1555 while (true) { | 1562 while (true) { |
1556 char *have = tok.next(); | 1563 char *have = tok.next(); |
1557 if (!have) break; | 1564 if (!have) break; |
1558 if (have == token_rbrace) break; | 1565 if (have == token_rbrace) break; |
1559 if (have == token_semi) { | 1566 if (have == token_semi) { |
1560 // optional separators | 1567 // optional separators |
1561 } | 1568 } |
1562 else { | 1569 else { |
1563 me.add_rate(have, tok.nextint()); | 1570 me.add_rate(have, tok.nextint()); |
1564 } | 1571 } |
1565 } | 1572 } |
1566 return tsa(tok, token_semi); | 1573 return tsa(tok, token_semi); |
1567 } | 1574 } |
1568 | 1575 |
1569 | 1576 |
1570 //////////////////////////////////////////////// | 1577 //////////////////////////////////////////////// |
1571 // | 1578 // |
1572 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent); | 1579 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent); |
1573 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent) { | 1580 bool parse_context(TOKEN &tok, CONFIG &dc, CONTEXTP parent) { |
1574 char *name = tok.next(); | 1581 char *name = tok.next(); |
1575 if (!tsa(tok, token_lbrace)) return false; | 1582 if (!tsa(tok, token_lbrace)) return false; |
1576 CONTEXTP con = new CONTEXT(parent, name); | 1583 CONTEXTP con = new CONTEXT(parent, name); |
1577 | 1584 |
1578 while (true) { | 1585 while (true) { |
1579 char *have = tok.next(); | 1586 char *have = tok.next(); |
1580 if (!have) break; | 1587 if (!have) break; |
1581 if (have == token_rbrace) break; // done | 1588 if (have == token_rbrace) break; // done |
1582 if (have == token_dnsbl) { | 1589 if (have == token_dnsbl) { |
1583 if (!parse_dnsbl(tok, dc, *con)) return false; | 1590 if (!parse_dnsbl(tok, dc, *con)) return false; |
1584 } | 1591 } |
1585 else if (have == token_dnsbll) { | 1592 else if (have == token_dnsbll) { |
1586 if (!parse_dnsbll(tok, dc, *con)) return false; | 1593 if (!parse_dnsbll(tok, dc, *con)) return false; |
1587 } | 1594 } |
1588 else if (have == token_content) { | 1595 else if (have == token_content) { |
1589 if (!parse_content(tok, dc, *con)) return false; | 1596 if (!parse_content(tok, dc, *con)) return false; |
1590 } | 1597 } |
1591 else if (have == token_envto) { | 1598 else if (have == token_envto) { |
1592 if (!parse_envto(tok, dc, *con)) return false; | 1599 if (!parse_envto(tok, dc, *con)) return false; |
1593 } | 1600 } |
1594 else if (have == token_verify) { | 1601 else if (have == token_verify) { |
1595 if (!parse_verify(tok, dc, *con)) return false; | 1602 if (!parse_verify(tok, dc, *con)) return false; |
1596 } | 1603 } |
1597 else if (have == token_generic) { | 1604 else if (have == token_generic) { |
1598 if (!parse_generic(tok, dc, *con)) return false; | 1605 if (!parse_generic(tok, dc, *con)) return false; |
1599 } | 1606 } |
1600 else if (have == token_autowhite) { | 1607 else if (have == token_autowhite) { |
1601 if (!parse_autowhite(tok, dc, *con)) return false; | 1608 if (!parse_autowhite(tok, dc, *con)) return false; |
1602 } | 1609 } |
1603 else if (have == token_envfrom) { | 1610 else if (have == token_envfrom) { |
1604 if (!parse_envfrom(tok, dc, *con)) return false; | 1611 if (!parse_envfrom(tok, dc, *con)) return false; |
1605 } | 1612 } |
1606 else if (have == token_rate) { | 1613 else if (have == token_rate) { |
1607 if (parent || dc.default_context) tok.token_error("rate limit ignored in non default context"); | 1614 if (parent || dc.default_context) tok.token_error("rate limit ignored in non default context"); |
1608 if (!parse_rate(tok, dc, *con)) return false; | 1615 if (!parse_rate(tok, dc, *con)) return false; |
1609 } | 1616 } |
1610 else if (have == token_context) { | 1617 else if (have == token_context) { |
1611 if (!parse_context(tok, dc, con)) return false; | 1618 if (!parse_context(tok, dc, con)) return false; |
1612 } | 1619 } |
1613 else { | 1620 else { |
1614 tok.token_error("context keyword", have); | 1621 tok.token_error("context keyword", have); |
1615 return false; | 1622 return false; |
1616 } | 1623 } |
1617 } | 1624 } |
1618 | 1625 |
1619 if (!tsa(tok, token_semi)) { | 1626 if (!tsa(tok, token_semi)) { |
1620 delete con; | 1627 delete con; |
1621 return false; | 1628 return false; |
1622 } | 1629 } |
1623 dc.add_context(con); | 1630 dc.add_context(con); |
1624 if (parent) parent->add_context(con); | 1631 if (parent) parent->add_context(con); |
1625 return true; | 1632 return true; |
1626 } | 1633 } |
1627 | 1634 |
1628 | 1635 |
1629 //////////////////////////////////////////////// | 1636 //////////////////////////////////////////////// |
1630 // parse a config file | 1637 // parse a config file |
1631 // | 1638 // |
1632 bool load_conf(CONFIG &dc, char *fn) { | 1639 bool load_conf(CONFIG &dc, char *fn) { |
1633 int count = 0; | 1640 int count = 0; |
1634 TOKEN tok(fn, &dc.config_files); | 1641 TOKEN tok(fn, &dc.config_files); |
1635 while (true) { | 1642 while (true) { |
1636 char *have = tok.next(); | 1643 char *have = tok.next(); |
1637 if (!have) break; | 1644 if (!have) break; |
1638 if (have == token_context) { | 1645 if (have == token_context) { |
1639 if (!parse_context(tok, dc, NULL)) { | 1646 if (!parse_context(tok, dc, NULL)) { |
1640 tok.token_error("load_conf() failed to parse context"); | 1647 tok.token_error("load_conf() failed to parse context"); |
1641 return false; | 1648 return false; |
1642 } | 1649 } |
1643 else count++; | 1650 else count++; |
1644 } | 1651 } |
1645 else { | 1652 else { |
1646 tok.token_error(token_context, have); | 1653 tok.token_error(token_context, have); |
1647 return false; | 1654 return false; |
1648 } | 1655 } |
1649 } | 1656 } |
1650 tok.token_error("load_conf() found %d contexts in %s", count, fn); | 1657 tok.token_error("load_conf() found %d contexts in %s", count, fn); |
1651 return (dc.default_context) ? true : false; | 1658 return (dc.default_context) ? true : false; |
1652 } | 1659 } |
1653 | 1660 |
1654 | 1661 |
1655 //////////////////////////////////////////////// | 1662 //////////////////////////////////////////////// |
1656 // init the tokens | 1663 // init the tokens |
1657 // | 1664 // |
1658 void token_init() { | 1665 void token_init() { |
1659 token_autowhite = register_string("autowhite"); | 1666 token_autowhite = register_string("autowhite"); |
1660 token_black = register_string("black"); | 1667 token_black = register_string("black"); |
1661 token_cctld = register_string("cctld"); | 1668 token_cctld = register_string("cctld"); |
1662 token_content = register_string("content"); | 1669 token_content = register_string("content"); |
1663 token_context = register_string("context"); | 1670 token_context = register_string("context"); |
1664 token_dccbulk = register_string("dcc_bulk_threshold"); | 1671 token_dccbulk = register_string("dcc_bulk_threshold"); |
1665 token_dccfrom = register_string("dcc_from"); | 1672 token_dccfrom = register_string("dcc_from"); |
1666 token_dccgrey = register_string("dcc_greylist"); | 1673 token_dccgrey = register_string("dcc_greylist"); |
1667 token_dccto = register_string("dcc_to"); | 1674 token_dccto = register_string("dcc_to"); |
1668 token_default = register_string("default"); | 1675 token_default = register_string("default"); |
1669 token_dnsbl = register_string("dnsbl"); | 1676 token_dnsbl = register_string("dnsbl"); |
1670 token_dnsbll = register_string("dnsbl_list"); | 1677 token_dnsbll = register_string("dnsbl_list"); |
1671 token_envfrom = register_string("env_from"); | 1678 token_envfrom = register_string("env_from"); |
1672 token_envto = register_string("env_to"); | 1679 token_envto = register_string("env_to"); |
1673 token_filter = register_string("filter"); | 1680 token_filter = register_string("filter"); |
1674 token_generic = register_string("generic"); | 1681 token_generic = register_string("generic"); |
1675 token_host_limit = register_string("host_limit"); | 1682 token_host_limit = register_string("host_limit"); |
1676 token_html_limit = register_string("html_limit"); | 1683 token_html_limit = register_string("html_limit"); |
1677 token_html_tags = register_string("html_tags"); | 1684 token_html_tags = register_string("html_tags"); |
1678 token_ignore = register_string("ignore"); | 1685 token_ignore = register_string("ignore"); |
1679 token_include = register_string("include"); | 1686 token_include = register_string("include"); |
1680 token_inherit = register_string("inherit"); | 1687 token_inherit = register_string("inherit"); |
1681 token_lbrace = register_string("{"); | 1688 token_lbrace = register_string("{"); |
1682 token_mailhost = register_string("mail_host"); | 1689 token_mailhost = register_string("mail_host"); |
1683 token_many = register_string("many"); | 1690 token_many = register_string("many"); |
1684 token_no = register_string("no"); | 1691 token_no = register_string("no"); |
1685 token_off = register_string("off"); | 1692 token_off = register_string("off"); |
1686 token_ok = register_string("ok"); | 1693 token_ok = register_string("ok"); |
1687 token_ok2 = register_string("ok2"); | 1694 token_ok2 = register_string("ok2"); |
1688 token_on = register_string("on"); | 1695 token_on = register_string("on"); |
1689 token_rate = register_string("rate_limit"); | 1696 token_rate = register_string("rate_limit"); |
1690 token_rbrace = register_string("}"); | 1697 token_rbrace = register_string("}"); |
1691 token_require = register_string("require_match"); | 1698 token_require = register_string("require_match"); |
1692 token_semi = register_string(";"); | 1699 token_semi = register_string(";"); |
1693 token_soft = register_string("soft"); | 1700 token_soft = register_string("soft"); |
1694 token_spamassassin = register_string("spamassassin"); | 1701 token_spamassassin = register_string("spamassassin"); |
1695 token_substitute = register_string("substitute"); | 1702 token_substitute = register_string("substitute"); |
1696 token_tld = register_string("tld"); | 1703 token_tld = register_string("tld"); |
1697 token_unknown = register_string("unknown"); | 1704 token_unknown = register_string("unknown"); |
1698 token_uribl = register_string("uribl"); | 1705 token_uribl = register_string("uribl"); |
1699 token_verify = register_string("verify"); | 1706 token_verify = register_string("verify"); |
1700 token_white = register_string("white"); | 1707 token_white = register_string("white"); |
1701 token_yes = register_string("yes"); | 1708 token_yes = register_string("yes"); |
1702 | 1709 |
1703 if (gethostname(myhostname, HOST_NAME_MAX+1) != 0) { | 1710 if (gethostname(myhostname, HOST_NAME_MAX+1) != 0) { |
1704 strncpy(myhostname, "localhost", HOST_NAME_MAX+1); | 1711 strncpy(myhostname, "localhost", HOST_NAME_MAX+1); |
1705 } | 1712 } |
1706 myhostname[HOST_NAME_MAX] = '\0'; // ensure null termination | 1713 myhostname[HOST_NAME_MAX] = '\0'; // ensure null termination |
1707 token_myhostname = register_string(myhostname); | 1714 token_myhostname = register_string(myhostname); |
1708 } | 1715 } |