Postfix3.3.1
postscreen_tests.c
[詳解]
1 /*++
2 /* NAME
3 /* postscreen_tests 3
4 /* SUMMARY
5 /* postscreen tests timestamp/flag bulk support
6 /* SYNOPSIS
7 /* #include <postscreen.h>
8 /*
9 /* void PSC_INIT_TESTS(state)
10 /* PSC_STATE *state;
11 /*
12 /* void psc_new_tests(state)
13 /* PSC_STATE *state;
14 /*
15 /* void psc_parse_tests(state, stamp_text, time_value)
16 /* PSC_STATE *state;
17 /* const char *stamp_text;
18 /* time_t time_value;
19 /*
20 /* void psc_todo_tests(state, time_value)
21 /* PSC_STATE *state;
22 /* const char *stamp_text;
23 /* time_t time_value;
24 /*
25 /* char *psc_print_tests(buffer, state)
26 /* VSTRING *buffer;
27 /* PSC_STATE *state;
28 /*
29 /* char *psc_print_grey_key(buffer, client, helo, sender, rcpt)
30 /* VSTRING *buffer;
31 /* const char *client;
32 /* const char *helo;
33 /* const char *sender;
34 /* const char *rcpt;
35 /*
36 /* const char *psc_test_name(tindx)
37 /* int tindx;
38 /* DESCRIPTION
39 /* The functions in this module overwrite the per-test expiration
40 /* time stamps and all flags bits. Some functions are implemented
41 /* as unsafe macros, meaning they evaluate one or more arguments
42 /* multiple times.
43 /*
44 /* PSC_INIT_TESTS() is an unsafe macro that sets the per-test
45 /* expiration time stamps to PSC_TIME_STAMP_INVALID, and that
46 /* zeroes all the flags bits. These values are not meant to
47 /* be stored into the postscreen(8) cache.
48 /*
49 /* PSC_INIT_TEST_FLAGS_ONLY() zeroes all the flag bits. It
50 /* should be used when the time stamps are already initialized.
51 /*
52 /* psc_new_tests() sets all test expiration time stamps to
53 /* PSC_TIME_STAMP_NEW, and invokes psc_todo_tests().
54 /*
55 /* psc_parse_tests() parses a cache file record and invokes
56 /* psc_todo_tests().
57 /*
58 /* psc_todo_tests() overwrites all per-session flag bits, and
59 /* populates the flags based on test expiration time stamp
60 /* information. Tests are considered "expired" when they
61 /* would be expired at the specified time value. Only enabled
62 /* tests are flagged as "expired"; the object is flagged as
63 /* "new" if some enabled tests have "new" time stamps.
64 /*
65 /* psc_print_tests() creates a cache file record for the
66 /* specified flags and per-test expiration time stamps.
67 /* This may modify the time stamps for disabled tests.
68 /*
69 /* psc_print_grey_key() prints a greylist lookup key.
70 /*
71 /* psc_test_name() returns the name for the specified text
72 /* index.
73 /* LICENSE
74 /* .ad
75 /* .fi
76 /* The Secure Mailer license must be distributed with this software.
77 /* AUTHOR(S)
78 /* Wietse Venema
79 /* IBM T.J. Watson Research
80 /* P.O. Box 704
81 /* Yorktown Heights, NY 10598, USA
82 /*
83 /* Wietse Venema
84 /* Google, Inc.
85 /* 111 8th Avenue
86 /* New York, NY 10011, USA
87 /*--*/
88 
89 /* System library. */
90 
91 #include <sys_defs.h>
92 #include <stdio.h> /* sscanf */
93 #include <stdlib.h> /* strtoul */
94 
95 /* Utility library. */
96 
97 #include <msg.h>
98 #include <name_code.h>
99 
100 /* Global library. */
101 
102 #include <mail_params.h>
103 
104 /* Application-specific. */
105 
106 #include <postscreen.h>
107 
108  /*
109  * Kludge to detect if some test is enabled.
110  */
111 #define PSC_PREGR_TEST_ENABLE() (*var_psc_pregr_banner != 0)
112 #define PSC_DNSBL_TEST_ENABLE() (*var_psc_dnsbl_sites != 0)
113 
114  /*
115  * Format of a persistent cache entry (which is almost but not quite the
116  * same as the in-memory representation).
117  *
118  * Each cache entry has one time stamp for each test.
119  *
120  * - A time stamp of PSC_TIME_STAMP_INVALID must never appear in the cache. It
121  * is reserved for in-memory objects that are still being initialized.
122  *
123  * - A time stamp of PSC_TIME_STAMP_NEW indicates that the test never passed.
124  * Postscreen will log the client with "pass new" when it passes the final
125  * test.
126  *
127  * - A time stamp of PSC_TIME_STAMP_DISABLED indicates that the test never
128  * passed, and that the test was disabled when the cache entry was written.
129  *
130  * - Otherwise, the test was passed, and the time stamp indicates when that
131  * test result expires.
132  *
133  * A cache entry is expired when the time stamps of all passed tests are
134  * expired.
135  */
136 
137 /* psc_new_tests - initialize new test results from scratch */
138 
140 {
141  time_t *expire_time = state->client_info->expire_time;
142 
143  /*
144  * Give all tests a PSC_TIME_STAMP_NEW time stamp, so that we can later
145  * recognize cache entries that haven't passed all enabled tests. When we
146  * write a cache entry to the database, any new-but-disabled tests will
147  * get a PSC_TIME_STAMP_DISABLED time stamp.
148  */
149  expire_time[PSC_TINDX_PREGR] = PSC_TIME_STAMP_NEW;
150  expire_time[PSC_TINDX_DNSBL] = PSC_TIME_STAMP_NEW;
151  expire_time[PSC_TINDX_PIPEL] = PSC_TIME_STAMP_NEW;
152  expire_time[PSC_TINDX_NSMTP] = PSC_TIME_STAMP_NEW;
153  expire_time[PSC_TINDX_BARLF] = PSC_TIME_STAMP_NEW;
154 
155  /*
156  * Determine what tests need to be completed.
157  */
159 }
160 
161 /* psc_parse_tests - parse test results from cache */
162 
164  const char *stamp_str,
165  time_t time_value)
166 {
167  const char *start = stamp_str;
168  char *cp;
169  time_t *time_stamps = state->client_info->expire_time;
170  time_t *sp;
171 
172  /*
173  * Parse the cache entry, and allow for older postscreen versions that
174  * implemented fewer tests. We pretend that the newer tests were disabled
175  * at the time that the cache entry was written.
176  */
177  for (sp = time_stamps; sp < time_stamps + PSC_TINDX_COUNT; sp++) {
178  *sp = strtoul(start, &cp, 10);
179  if (*start == 0 || (*cp != '\0' && *cp != ';') || errno == ERANGE)
181  if (msg_verbose)
182  msg_info("%s -> %lu", start, (unsigned long) *sp);
183  if (*cp == ';')
184  start = cp + 1;
185  else
186  start = cp;
187  }
188 
189  /*
190  * Determine what tests need to be completed.
191  */
192  psc_todo_tests(state, time_value);
193 }
194 
195 /* psc_todo_tests - determine what tests to perform */
196 
197 void psc_todo_tests(PSC_STATE *state, time_t time_value)
198 {
199  time_t *expire_time = state->client_info->expire_time;
200  time_t *sp;
201 
202  /*
203  * Reset all per-session flags.
204  */
205  state->flags = 0;
206 
207  /*
208  * Flag the tests as "new" when the cache entry has fields for all
209  * enabled tests, but the remote SMTP client has not yet passed all those
210  * tests.
211  */
212  for (sp = expire_time; sp < expire_time + PSC_TINDX_COUNT; sp++) {
213  if (*sp == PSC_TIME_STAMP_NEW)
214  state->flags |= PSC_STATE_FLAG_NEW;
215  }
216 
217  /*
218  * Don't flag disabled tests as "todo", because there would be no way to
219  * make those bits go away.
220  */
221  if (PSC_PREGR_TEST_ENABLE() && time_value > expire_time[PSC_TINDX_PREGR])
223  if (PSC_DNSBL_TEST_ENABLE() && time_value > expire_time[PSC_TINDX_DNSBL])
225  if (var_psc_pipel_enable && time_value > expire_time[PSC_TINDX_PIPEL])
227  if (var_psc_nsmtp_enable && time_value > expire_time[PSC_TINDX_NSMTP])
229  if (var_psc_barlf_enable && time_value > expire_time[PSC_TINDX_BARLF])
231 
232  /*
233  * If any test has expired, proactively refresh tests that will expire
234  * soon. This can increase the occurrence of client-visible delays, but
235  * avoids questions about why a client can pass some test and then fail
236  * within seconds. The proactive refresh time is really a surrogate for
237  * the user's curiosity level, and therefore hard to choose optimally.
238  */
239 #ifdef VAR_PSC_REFRESH_TIME
240  if ((state->flags & PSC_STATE_MASK_ANY_TODO) != 0
241  && var_psc_refresh_time > 0) {
242  time_t refresh_time = time_value + var_psc_refresh_time;
243 
244  if (PSC_PREGR_TEST_ENABLE() && refresh_time > expire_time[PSC_TINDX_PREGR])
246  if (PSC_DNSBL_TEST_ENABLE() && refresh_time > expire_time[PSC_TINDX_DNSBL])
248  if (var_psc_pipel_enable && refresh_time > expire_time[PSC_TINDX_PIPEL])
250  if (var_psc_nsmtp_enable && refresh_time > expire_time[PSC_TINDX_NSMTP])
252  if (var_psc_barlf_enable && refresh_time > expire_time[PSC_TINDX_BARLF])
254  }
255 #endif
256 
257  /*
258  * Gratuitously make postscreen logging more useful by turning on all
259  * enabled pre-handshake tests when any pre-handshake test is turned on.
260  *
261  * XXX Don't enable PREGREET gratuitously before the test expires. With a
262  * short TTL for DNSBL whitelisting, turning on PREGREET would force a
263  * full postscreen_greet_wait too frequently.
264  */
265 #if 0
266  if (state->flags & PSC_STATE_MASK_EARLY_TODO) {
267  if (PSC_PREGR_TEST_ENABLE())
269  if (PSC_DNSBL_TEST_ENABLE())
271  }
272 #endif
273 }
274 
275 /* psc_print_tests - print postscreen cache record */
276 
277 char *psc_print_tests(VSTRING *buf, PSC_STATE *state)
278 {
279  const char *myname = "psc_print_tests";
280  time_t *expire_time = state->client_info->expire_time;
281 
282  /*
283  * Sanity check.
284  */
285  if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) == 0)
286  msg_panic("%s: attempt to save a no-update record", myname);
287 
288  /*
289  * Give disabled tests a dummy time stamp so that we don't log a client
290  * with "pass new" when some disabled test becomes enabled at some later
291  * time.
292  */
293  if (PSC_PREGR_TEST_ENABLE() == 0 && expire_time[PSC_TINDX_PREGR] == PSC_TIME_STAMP_NEW)
295  if (PSC_DNSBL_TEST_ENABLE() == 0 && expire_time[PSC_TINDX_DNSBL] == PSC_TIME_STAMP_NEW)
297  if (var_psc_pipel_enable == 0 && expire_time[PSC_TINDX_PIPEL] == PSC_TIME_STAMP_NEW)
299  if (var_psc_nsmtp_enable == 0 && expire_time[PSC_TINDX_NSMTP] == PSC_TIME_STAMP_NEW)
301  if (var_psc_barlf_enable == 0 && expire_time[PSC_TINDX_BARLF] == PSC_TIME_STAMP_NEW)
303 
304  vstring_sprintf(buf, "%lu;%lu;%lu;%lu;%lu",
305  (unsigned long) expire_time[PSC_TINDX_PREGR],
306  (unsigned long) expire_time[PSC_TINDX_DNSBL],
307  (unsigned long) expire_time[PSC_TINDX_PIPEL],
308  (unsigned long) expire_time[PSC_TINDX_NSMTP],
309  (unsigned long) expire_time[PSC_TINDX_BARLF]);
310  return (STR(buf));
311 }
312 
313 /* psc_print_grey_key - print postscreen cache record */
314 
315 char *psc_print_grey_key(VSTRING *buf, const char *client,
316  const char *helo, const char *sender,
317  const char *rcpt)
318 {
319  return (STR(vstring_sprintf(buf, "%s/%s/%s/%s",
320  client, helo, sender, rcpt)));
321 }
322 
323 /* psc_test_name - map test index to symbolic name */
324 
325 const char *psc_test_name(int tindx)
326 {
327  const char *myname = "psc_test_name";
328  const NAME_CODE test_name_map[] = {
334  0, -1,
335  };
336  const char *result;
337 
338  if ((result = str_name_code(test_name_map, tindx)) == 0)
339  msg_panic("%s: bad index %d", myname, tindx);
340  return (result);
341 }
int msg_verbose
Definition: msg.c:177
PSC_CLIENT_INFO * client_info
Definition: postscreen.h:83
#define PSC_TINDX_COUNT
Definition: postscreen.h:47
#define PSC_STATE_FLAG_NEW
Definition: postscreen.h:115
#define PSC_TNAME_PIPEL
Definition: postscreen.h:51
#define PSC_STATE_FLAG_DNSBL_TODO
Definition: postscreen.h:193
#define PSC_STATE_FLAG_NSMTP_TODO
Definition: postscreen.h:203
time_t expire_time[PSC_TINDX_COUNT]
Definition: postscreen.h:63
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define PSC_TNAME_BARLF
Definition: postscreen.h:53
#define PSC_PREGR_TEST_ENABLE()
#define PSC_TIME_STAMP_DISABLED
Definition: postscreen.h:106
int flags
Definition: postscreen.h:70
#define PSC_DNSBL_TEST_ENABLE()
const char * psc_test_name(int tindx)
void psc_parse_tests(PSC_STATE *state, const char *stamp_str, time_t time_value)
bool var_psc_barlf_enable
Definition: postscreen.c:501
#define PSC_STATE_MASK_ANY_TODO
Definition: postscreen.h:277
bool var_psc_pipel_enable
Definition: postscreen.c:493
#define PSC_TINDX_PREGR
Definition: postscreen.h:42
#define PSC_TINDX_BARLF
Definition: postscreen.h:46
const char * str_name_code(const NAME_CODE *table, int code)
Definition: name_code.c:83
#define STR(x)
Definition: anvil.c:518
#define PSC_STATE_MASK_ANY_UPDATE
Definition: postscreen.h:283
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
#define PSC_STATE_MASK_EARLY_TODO
Definition: postscreen.h:249
bool var_psc_nsmtp_enable
Definition: postscreen.c:497
#define PSC_TIME_STAMP_NEW
Definition: postscreen.h:105
#define PSC_TINDX_PIPEL
Definition: postscreen.h:44
#define PSC_TNAME_DNSBL
Definition: postscreen.h:50
char * psc_print_grey_key(VSTRING *buf, const char *client, const char *helo, const char *sender, const char *rcpt)
#define PSC_STATE_FLAG_PIPEL_TODO
Definition: postscreen.h:198
#define PSC_TNAME_NSMTP
Definition: postscreen.h:52
char * psc_print_tests(VSTRING *buf, PSC_STATE *state)
#define PSC_TINDX_DNSBL
Definition: postscreen.h:43
#define PSC_STATE_FLAG_BARLF_TODO
Definition: postscreen.h:208
#define PSC_TNAME_PREGR
Definition: postscreen.h:49
#define PSC_STATE_FLAG_PREGR_TODO
Definition: postscreen.h:188
void psc_new_tests(PSC_STATE *state)
#define PSC_TINDX_NSMTP
Definition: postscreen.h:45
void psc_todo_tests(PSC_STATE *state, time_t time_value)
void msg_info(const char *fmt,...)
Definition: msg.c:199