summaryrefslogtreecommitdiffstats
path: root/src/postscreen/postscreen.h
blob: 69a5e17503dc644ae27d828670b3c7178780cb53 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
/*++
/* NAME
/*	postscreen 3h
/* SUMMARY
/*	postscreen internal interfaces
/* SYNOPSIS
/*	#include <postscreen.h>
/* DESCRIPTION
/* .nf

 /*
  * System library.
  */

 /*
  * Utility library.
  */
#include <dict_cache.h>
#include <vstream.h>
#include <vstring.h>
#include <events.h>
#include <htable.h>
#include <myaddrinfo.h>

 /*
  * Global library.
  */
#include <addr_match_list.h>
#include <string_list.h>
#include <maps.h>
#include <server_acl.h>

 /*
  * Preliminary stuff, to be fixed.
  */
#define PSC_READ_BUF_SIZE	1024

 /*
  * Numeric indices and symbolic names for tests whose time stamps and status
  * flags can be accessed by numeric index.
  */
#define PSC_TINDX_PREGR	0		/* pregreet */
#define PSC_TINDX_DNSBL	1		/* dnsbl */
#define PSC_TINDX_PIPEL	2		/* pipelining */
#define PSC_TINDX_NSMTP	3		/* non-smtp command */
#define PSC_TINDX_BARLF	4		/* bare newline */
#define PSC_TINDX_COUNT	5		/* number of tests */

#define PSC_TNAME_PREGR	"pregreet"
#define PSC_TNAME_DNSBL	"dnsbl"
#define PSC_TNAME_PIPEL	"pipelining"
#define PSC_TNAME_NSMTP	"non-smtp command"
#define PSC_TNAME_BARLF	"bare newline"

#define PSC_TINDX_BYTNAME(tname) (PSC_TINDX_ ## tname)

 /*
  * Per-client shared state.
  */
typedef struct {
    int     concurrency;		/* per-client */
    int     pass_new_count;		/* per-client */
    time_t  expire_time[PSC_TINDX_COUNT];	/* per-test expiration */
} PSC_CLIENT_INFO;

 /*
  * Per-session state.
  */
typedef struct {
    int     flags;			/* see below */
    /* Socket state. */
    VSTREAM *smtp_client_stream;	/* remote SMTP client */
    int     smtp_server_fd;		/* real SMTP server */
    char   *smtp_client_addr;		/* client address */
    char   *smtp_client_port;		/* client port */
    char   *smtp_server_addr;		/* server address */
    char   *smtp_server_port;		/* server port */
    const char *final_reply;		/* cause for hanging up */
    VSTRING *send_buf;			/* pending output */
    /* Test context. */
    struct timeval start_time;		/* start of current test */
    const char *test_name;		/* name of current test */
    PSC_CLIENT_INFO *client_info;	/* shared client state */
    VSTRING *dnsbl_reply;		/* dnsbl reject text */
    int     dnsbl_score;		/* saved DNSBL score */
    int     dnsbl_ttl;			/* saved DNSBL TTL */
    const char *dnsbl_name;		/* DNSBL name with largest weight */
    int     dnsbl_index;		/* dnsbl request index */
    const char *rcpt_reply;		/* how to reject recipients */
    int     command_count;		/* error + junk command count */
    const char *protocol;		/* SMTP or ESMTP */
    char   *helo_name;			/* SMTP helo/ehlo */
    char   *sender;			/* MAIL FROM */
    VSTRING *cmd_buffer;		/* command read buffer */
    int     read_state;			/* command read state machine */
    /* smtpd(8) compatibility */
    int     ehlo_discard_mask;		/* EHLO filter */
    VSTRING *expand_buf;		/* macro expansion */
    const char *where;			/* SMTP protocol state */
} PSC_STATE;

 /*
  * Special expiration time values.
  */
#define PSC_TIME_STAMP_NEW		(0)	/* test was never passed */
#define PSC_TIME_STAMP_DISABLED		(1)	/* never passed but disabled */
#define PSC_TIME_STAMP_INVALID		(-1)	/* must not be cached */

 /*
  * Status flags.
  */
#define PSC_STATE_FLAG_NOFORWARD	(1<<0)	/* don't forward this session */
#define PSC_STATE_FLAG_USING_TLS	(1<<1)	/* using the TLS proxy */
#define PSC_STATE_FLAG_UNUSED2		(1<<2)	/* use me! */
#define PSC_STATE_FLAG_NEW		(1<<3)	/* some test was never passed */
#define PSC_STATE_FLAG_DNLIST_FAIL	(1<<4)	/* denylisted */
#define PSC_STATE_FLAG_HANGUP		(1<<5)	/* NOT a test failure */
#define PSC_STATE_FLAG_SMTPD_X21	(1<<6)	/* hang up after command */
#define PSC_STATE_FLAG_ALLIST_FAIL	(1<<7)	/* do not allowlist */
#define PSC_STATE_FLAG_TEST_BASE	(8)	/* start of indexable flags */

 /*
  * Tests whose flags and expiration time can be accessed by numerical index.
  * 
  * Important: every MUMBLE_TODO flag must have a MUMBLE_PASS flag, such that
  * MUMBLE_PASS == PSC_STATE_FLAGS_TODO_TO_PASS(MUMBLE_TODO).
  * 
  * MUMBLE_TODO flags must not be cleared once raised. The _TODO_TO_PASS and
  * _TODO_TO_DONE macros depend on this to decide that a group of tests is
  * passed or completed.
  * 
  * MUMBLE_DONE flags are used for "early" tests that have final results.
  * 
  * MUMBLE_SKIP flags are used for "deep" tests where the client messed up.
  * These flags look like MUMBLE_DONE but they are different. Deep tests can
  * tentatively pass, but can still fail later in a session. The "ignore"
  * action introduces an additional complication. MUMBLE_PASS indicates
  * either that a deep test passed tentatively, or that the test failed but
  * the result was ignored. MUMBLE_FAIL, on the other hand, is always final.
  * We use MUMBLE_SKIP to indicate that a decision was either "fail" or
  * forced "pass".
  * 
  * The difference between DONE and SKIP is in the beholder's eye. These flags
  * share the same bit.
  */
#define PSC_STATE_FLAGS_TODO_TO_PASS(todo_flags) ((todo_flags) >> 1)
#define PSC_STATE_FLAGS_TODO_TO_DONE(todo_flags) ((todo_flags) << 1)

#define PSC_STATE_FLAG_SHIFT_FAIL	(0)	/* failed test */
#define PSC_STATE_FLAG_SHIFT_PASS	(1)	/* passed test */
#define PSC_STATE_FLAG_SHIFT_TODO	(2)	/* expired test */
#define PSC_STATE_FLAG_SHIFT_DONE	(3)	/* decision is final */
#define PSC_STATE_FLAG_SHIFT_SKIP	(3)	/* action is already logged */
#define PSC_STATE_FLAG_SHIFT_STRIDE	(4)	/* nr of flags per test */

#define PSC_STATE_FLAG_SHIFT_BYFNAME(fname) (PSC_STATE_FLAG_SHIFT_ ## fname)

 /*
  * Indexable per-test flags. These are used for DNS allowlisting multiple
  * tests, without needing per-test ad-hoc code.
  */
#define PSC_STATE_FLAG_BYTINDX_FNAME(tindx, fname) \
	(1U << (PSC_STATE_FLAG_TEST_BASE \
	    + PSC_STATE_FLAG_SHIFT_STRIDE * (tindx) \
	    + PSC_STATE_FLAG_SHIFT_BYFNAME(fname)))

#define PSC_STATE_FLAG_BYTINDX_FAIL(tindx) \
	PSC_STATE_FLAG_BYTINDX_FNAME((tindx), FAIL)
#define PSC_STATE_FLAG_BYTINDX_PASS(tindx) \
	PSC_STATE_FLAG_BYTINDX_FNAME((tindx), PASS)
#define PSC_STATE_FLAG_BYTINDX_TODO(tindx) \
	PSC_STATE_FLAG_BYTINDX_FNAME((tindx), TODO)
#define PSC_STATE_FLAG_BYTINDX_DONE(tindx) \
	PSC_STATE_FLAG_BYTINDX_FNAME((tindx), DONE)
#define PSC_STATE_FLAG_BYTINDX_SKIP(tindx) \
	PSC_STATE_FLAG_BYTINDX_FNAME((tindx), SKIP)

 /*
  * Flags with distinct names. These are used in the per-test ad-hoc code.
  */
#define PSC_STATE_FLAG_BYTNAME_FNAME(tname, fname) \
	(1U << (PSC_STATE_FLAG_TEST_BASE \
	    + PSC_STATE_FLAG_SHIFT_STRIDE * PSC_TINDX_BYTNAME(tname) \
	    + PSC_STATE_FLAG_SHIFT_BYFNAME(fname)))

#define PSC_STATE_FLAG_PREGR_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, FAIL)
#define PSC_STATE_FLAG_PREGR_PASS PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, PASS)
#define PSC_STATE_FLAG_PREGR_TODO PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, TODO)
#define PSC_STATE_FLAG_PREGR_DONE PSC_STATE_FLAG_BYTNAME_FNAME(PREGR, DONE)

#define PSC_STATE_FLAG_DNSBL_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, FAIL)
#define PSC_STATE_FLAG_DNSBL_PASS PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, PASS)
#define PSC_STATE_FLAG_DNSBL_TODO PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, TODO)
#define PSC_STATE_FLAG_DNSBL_DONE PSC_STATE_FLAG_BYTNAME_FNAME(DNSBL, DONE)

#define PSC_STATE_FLAG_PIPEL_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, FAIL)
#define PSC_STATE_FLAG_PIPEL_PASS PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, PASS)
#define PSC_STATE_FLAG_PIPEL_TODO PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, TODO)
#define PSC_STATE_FLAG_PIPEL_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(PIPEL, SKIP)

#define PSC_STATE_FLAG_NSMTP_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, FAIL)
#define PSC_STATE_FLAG_NSMTP_PASS PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, PASS)
#define PSC_STATE_FLAG_NSMTP_TODO PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, TODO)
#define PSC_STATE_FLAG_NSMTP_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(NSMTP, SKIP)

#define PSC_STATE_FLAG_BARLF_FAIL PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, FAIL)
#define PSC_STATE_FLAG_BARLF_PASS PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, PASS)
#define PSC_STATE_FLAG_BARLF_TODO PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, TODO)
#define PSC_STATE_FLAG_BARLF_SKIP PSC_STATE_FLAG_BYTNAME_FNAME(BARLF, SKIP)

 /*
  * Aggregates for individual tests.
  */
#define PSC_STATE_MASK_PREGR_TODO_FAIL \
	(PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_PREGR_FAIL)
#define PSC_STATE_MASK_DNSBL_TODO_FAIL \
	(PSC_STATE_FLAG_DNSBL_TODO | PSC_STATE_FLAG_DNSBL_FAIL)
#define PSC_STATE_MASK_PIPEL_TODO_FAIL \
	(PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_PIPEL_FAIL)
#define PSC_STATE_MASK_NSMTP_TODO_FAIL \
	(PSC_STATE_FLAG_NSMTP_TODO | PSC_STATE_FLAG_NSMTP_FAIL)
#define PSC_STATE_MASK_BARLF_TODO_FAIL \
	(PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_FAIL)

#define PSC_STATE_MASK_PREGR_TODO_DONE \
	(PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_PREGR_DONE)
#define PSC_STATE_MASK_PIPEL_TODO_SKIP \
	(PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_PIPEL_SKIP)
#define PSC_STATE_MASK_NSMTP_TODO_SKIP \
	(PSC_STATE_FLAG_NSMTP_TODO | PSC_STATE_FLAG_NSMTP_SKIP)
#define PSC_STATE_MASK_BARLF_TODO_SKIP \
	(PSC_STATE_FLAG_BARLF_TODO | PSC_STATE_FLAG_BARLF_SKIP)

#define PSC_STATE_MASK_PREGR_FAIL_DONE \
	(PSC_STATE_FLAG_PREGR_FAIL | PSC_STATE_FLAG_PREGR_DONE)

#define PSC_STATE_MASK_PIPEL_TODO_PASS_FAIL \
	(PSC_STATE_MASK_PIPEL_TODO_FAIL | PSC_STATE_FLAG_PIPEL_PASS)
#define PSC_STATE_MASK_NSMTP_TODO_PASS_FAIL \
	(PSC_STATE_MASK_NSMTP_TODO_FAIL | PSC_STATE_FLAG_NSMTP_PASS)
#define PSC_STATE_MASK_BARLF_TODO_PASS_FAIL \
	(PSC_STATE_MASK_BARLF_TODO_FAIL | PSC_STATE_FLAG_BARLF_PASS)

 /*
  * Separate aggregates for early tests and deep tests.
  */
#define PSC_STATE_MASK_EARLY_DONE \
	(PSC_STATE_FLAG_PREGR_DONE | PSC_STATE_FLAG_DNSBL_DONE)
#define PSC_STATE_MASK_EARLY_TODO \
	(PSC_STATE_FLAG_PREGR_TODO | PSC_STATE_FLAG_DNSBL_TODO)
#define PSC_STATE_MASK_EARLY_PASS \
	(PSC_STATE_FLAG_PREGR_PASS | PSC_STATE_FLAG_DNSBL_PASS)
#define PSC_STATE_MASK_EARLY_FAIL \
	(PSC_STATE_FLAG_PREGR_FAIL | PSC_STATE_FLAG_DNSBL_FAIL)

#define PSC_STATE_MASK_SMTPD_TODO \
	(PSC_STATE_FLAG_PIPEL_TODO | PSC_STATE_FLAG_NSMTP_TODO | \
	PSC_STATE_FLAG_BARLF_TODO)
#define PSC_STATE_MASK_SMTPD_PASS \
	(PSC_STATE_FLAG_PIPEL_PASS | PSC_STATE_FLAG_NSMTP_PASS | \
	PSC_STATE_FLAG_BARLF_PASS)
#define PSC_STATE_MASK_SMTPD_FAIL \
	(PSC_STATE_FLAG_PIPEL_FAIL | PSC_STATE_FLAG_NSMTP_FAIL | \
	PSC_STATE_FLAG_BARLF_FAIL)

 /*
  * Super-aggregates for all tests combined.
  */
#define PSC_STATE_MASK_ANY_FAIL \
	(PSC_STATE_FLAG_DNLIST_FAIL | \
	PSC_STATE_MASK_EARLY_FAIL | PSC_STATE_MASK_SMTPD_FAIL | \
	PSC_STATE_FLAG_ALLIST_FAIL)

#define PSC_STATE_MASK_ANY_PASS \
	(PSC_STATE_MASK_EARLY_PASS | PSC_STATE_MASK_SMTPD_PASS)

#define PSC_STATE_MASK_ANY_TODO \
	(PSC_STATE_MASK_EARLY_TODO | PSC_STATE_MASK_SMTPD_TODO)

#define PSC_STATE_MASK_ANY_TODO_FAIL \
	(PSC_STATE_MASK_ANY_TODO | PSC_STATE_MASK_ANY_FAIL)

#define PSC_STATE_MASK_ANY_UPDATE \
	(PSC_STATE_MASK_ANY_PASS)

 /*
  * Meta-commands for state->where that reflect the initial command processor
  * state and commands that aren't implemented.
  */
#define PSC_SMTPD_CMD_CONNECT		"CONNECT"
#define PSC_SMTPD_CMD_UNIMPL		"UNIMPLEMENTED"

 /*
  * See log_adhoc.c for discussion.
  */
typedef struct {
    int     dt_sec;			/* make sure it's signed */
    int     dt_usec;			/* make sure it's signed */
} DELTA_TIME;

#define PSC_CALC_DELTA(x, y, z) \
    do { \
	(x).dt_sec = (y).tv_sec - (z).tv_sec; \
	(x).dt_usec = (y).tv_usec - (z).tv_usec; \
	while ((x).dt_usec < 0) { \
	    (x).dt_usec += 1000000; \
	    (x).dt_sec -= 1; \
	} \
	while ((x).dt_usec >= 1000000) { \
	    (x).dt_usec -= 1000000; \
	    (x).dt_sec += 1; \
	} \
	if ((x).dt_sec < 0) \
	    (x).dt_sec = (x).dt_usec = 0; \
    } while (0)

#define SIG_DIGS        2

 /*
  * Event management.
  */

/* PSC_READ_EVENT_REQUEST - prepare for transition to next state */

#define PSC_READ_EVENT_REQUEST(fd, action, context, timeout) do { \
	if (msg_verbose > 1) \
	    msg_info("%s: read-request fd=%d", myname, (fd)); \
	event_enable_read((fd), (action), (context)); \
	event_request_timer((action), (context), (timeout)); \
    } while (0)

#define PSC_READ_EVENT_REQUEST2(fd, read_act, time_act, context, timeout) do { \
	if (msg_verbose > 1) \
	    msg_info("%s: read-request fd=%d", myname, (fd)); \
	event_enable_read((fd), (read_act), (context)); \
	event_request_timer((time_act), (context), (timeout)); \
    } while (0)

/* PSC_CLEAR_EVENT_REQUEST - complete state transition */

#define PSC_CLEAR_EVENT_REQUEST(fd, time_act, context) do { \
	if (msg_verbose > 1) \
	    msg_info("%s: clear-request fd=%d", myname, (fd)); \
	event_disable_readwrite(fd); \
	event_cancel_timer((time_act), (context)); \
    } while (0)

 /*
  * Failure enforcement policies.
  */
#define PSC_NAME_ACT_DROP	"drop"
#define PSC_NAME_ACT_ENFORCE	"enforce"
#define PSC_NAME_ACT_IGNORE	"ignore"
#define PSC_NAME_ACT_CONT	"continue"

#define PSC_ACT_DROP		1
#define PSC_ACT_ENFORCE		2
#define PSC_ACT_IGNORE		3

 /*
  * Global variables.
  */
extern int psc_check_queue_length;	/* connections being checked */
extern int psc_post_queue_length;	/* being sent to real SMTPD */
extern DICT_CACHE *psc_cache_map;	/* cache table handle */
extern VSTRING *psc_temp;		/* scratchpad */
extern char *psc_smtpd_service_name;	/* path to real SMTPD */
extern int psc_pregr_action;		/* PSC_ACT_DROP etc. */
extern int psc_dnsbl_action;		/* PSC_ACT_DROP etc. */
extern int psc_pipel_action;		/* PSC_ACT_DROP etc. */
extern int psc_nsmtp_action;		/* PSC_ACT_DROP etc. */
extern int psc_barlf_action;		/* PSC_ACT_DROP etc. */
extern int psc_min_ttl;			/* Update with new tests! */
extern STRING_LIST *psc_forbid_cmds;	/* CONNECT GET POST */
extern int psc_stress_greet_wait;	/* stressed greet wait */
extern int psc_normal_greet_wait;	/* stressed greet wait */
extern int psc_stress_cmd_time_limit;	/* stressed command limit */
extern int psc_normal_cmd_time_limit;	/* normal command time limit */
extern int psc_stress;			/* stress level */
extern int psc_lowat_check_queue_length;/* stress low-water mark */
extern int psc_hiwat_check_queue_length;/* stress high-water mark */
extern DICT *psc_dnsbl_reply;		/* DNSBL name mapper */
extern HTABLE *psc_client_concurrency;	/* per-client concurrency */

#define PSC_EFF_GREET_WAIT \
	(psc_stress ? psc_stress_greet_wait : psc_normal_greet_wait)
#define PSC_EFF_CMD_TIME_LIMIT \
	(psc_stress ? psc_stress_cmd_time_limit : psc_normal_cmd_time_limit)

 /*
  * String plumbing macros.
  */
#define PSC_STRING_UPDATE(str, text) do { \
	if (str) myfree(str); \
	(str) = ((text) ? mystrdup(text) : 0); \
    } while (0)

#define PSC_STRING_RESET(str) do { \
	if (str) { \
	    myfree(str); \
	    (str) = 0; \
	} \
    } while (0)

 /*
  * SLMs.
  */
#define STR(x)  vstring_str(x)
#define LEN(x)  VSTRING_LEN(x)

 /*
  * postscreen_state.c
  */
#define PSC_CLIENT_ADDR_PORT(state) \
	(state)->smtp_client_addr, (state)->smtp_client_port

#define PSC_PASS_SESSION_STATE(state, what, bits) do { \
	if (msg_verbose) \
	    msg_info("PASS %s [%s]:%s", (what), PSC_CLIENT_ADDR_PORT(state)); \
	(state)->flags |= (bits); \
    } while (0)
#define PSC_FAIL_SESSION_STATE(state, bits) do { \
	if (msg_verbose) \
	    msg_info("FAIL [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
	(state)->flags |= (bits); \
    } while (0)
#define PSC_SKIP_SESSION_STATE(state, what, bits) do { \
	if (msg_verbose) \
	    msg_info("SKIP %s [%s]:%s", (what), PSC_CLIENT_ADDR_PORT(state)); \
	(state)->flags |= (bits); \
    } while (0)
#define PSC_DROP_SESSION_STATE(state, reply) do { \
	if (msg_verbose) \
	    msg_info("DROP [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
	(state)->flags |= PSC_STATE_FLAG_NOFORWARD; \
	(state)->final_reply = (reply); \
	psc_conclude(state); \
    } while (0)
#define PSC_ENFORCE_SESSION_STATE(state, reply) do { \
	if (msg_verbose) \
	    msg_info("ENFORCE [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
	(state)->rcpt_reply = (reply); \
	(state)->flags |= PSC_STATE_FLAG_NOFORWARD; \
    } while (0)
#define PSC_UNPASS_SESSION_STATE(state, bits) do { \
	if (msg_verbose) \
	    msg_info("UNPASS [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
	(state)->flags &= ~(bits); \
    } while (0)
#define PSC_UNFAIL_SESSION_STATE(state, bits) do { \
	if (msg_verbose) \
	    msg_info("UNFAIL [%s]:%s", PSC_CLIENT_ADDR_PORT(state)); \
	(state)->flags &= ~(bits); \
    } while (0)
#define PSC_ADD_SERVER_STATE(state, fd) do { \
	(state)->smtp_server_fd = (fd); \
	psc_post_queue_length++; \
    } while (0)
#define PSC_DEL_SERVER_STATE(state) do { \
	close((state)->smtp_server_fd); \
	(state)->smtp_server_fd = (-1); \
	psc_post_queue_length--; \
    } while (0)
#define PSC_DEL_CLIENT_STATE(state) do { \
	event_server_disconnect((state)->smtp_client_stream); \
	(state)->smtp_client_stream = 0; \
	psc_check_queue_length--; \
    } while (0)
extern PSC_STATE *psc_new_session_state(VSTREAM *, const char *, const char *, const char *, const char *);
extern void psc_free_session_state(PSC_STATE *);
extern const char *psc_print_state_flags(int, const char *);

 /*
  * postscreen_dict.c
  */
extern int psc_addr_match_list_match(ADDR_MATCH_LIST *, const char *);
extern const char *psc_cache_lookup(DICT_CACHE *, const char *);
extern void psc_cache_update(DICT_CACHE *, const char *, const char *);
const char *psc_dict_get(DICT *, const char *);
const char *psc_maps_find(MAPS *, const char *, int);

 /*
  * postscreen_dnsbl.c
  */
extern void psc_dnsbl_init(void);
extern int psc_dnsbl_retrieve(const char *, const char **, int, int *);
extern int psc_dnsbl_request(const char *, void (*) (int, void *), void *);

 /*
  * postscreen_tests.c
  */
#define PSC_INIT_TESTS(dst) do { \
	time_t *_it_stamp_p; \
	(dst)->flags = 0; \
	for (_it_stamp_p = (dst)->client_info->expire_time; \
	    _it_stamp_p < (dst)->client_info->expire_time + PSC_TINDX_COUNT; \
	    _it_stamp_p++) \
	    *_it_stamp_p = PSC_TIME_STAMP_INVALID; \
    } while (0)
#define PSC_INIT_TEST_FLAGS_ONLY(dst) do { \
	(dst)->flags = 0; \
    } while (0)
#define PSC_BEGIN_TESTS(state, name) do { \
	(state)->test_name = (name); \
	GETTIMEOFDAY(&(state)->start_time); \
    } while (0)
extern void psc_new_tests(PSC_STATE *);
extern void psc_parse_tests(PSC_STATE *, const char *, time_t);
extern void psc_todo_tests(PSC_STATE *, time_t);
extern char *psc_print_tests(VSTRING *, PSC_STATE *);
extern char *psc_print_grey_key(VSTRING *, const char *, const char *,
				        const char *, const char *);
extern const char *psc_test_name(int);

#define PSC_MIN(x, y) ((x) < (y) ? (x) : (y))
#define PSC_MAX(x, y) ((x) > (y) ? (x) : (y))

 /*
  * postscreen_early.c
  */
extern void psc_early_tests(PSC_STATE *);
extern void psc_early_init(void);

 /*
  * postscreen_smtpd.c
  */
extern void psc_smtpd_tests(PSC_STATE *);
extern void psc_smtpd_init(void);
extern void psc_smtpd_pre_jail_init(void);

#define PSC_SMTPD_X21(state, reply) do { \
	(state)->flags |= PSC_STATE_FLAG_SMTPD_X21; \
	(state)->final_reply = (reply); \
	psc_smtpd_tests(state); \
    } while (0)

 /*
  * postscreen_misc.c
  */
extern char *psc_format_delta_time(VSTRING *, struct timeval, DELTA_TIME *);
extern void psc_conclude(PSC_STATE *);
extern void psc_hangup_event(PSC_STATE *);

 /*
  * postscreen_send.c
  */
#define PSC_SEND_REPLY psc_send_reply	/* legacy macro */
extern void pcs_send_pre_jail_init(void);
extern int psc_send_reply(PSC_STATE *, const char *);
extern void psc_send_socket(PSC_STATE *);

 /*
  * postscreen_starttls.c
  */
extern void psc_starttls_open(PSC_STATE *, EVENT_NOTIFY_FN);

 /*
  * postscreen_expand.c
  */
extern VSTRING *psc_expand_filter;
extern void psc_expand_init(void);
extern const char *psc_expand_lookup(const char *, int, void *);

 /*
  * postscreen_endpt.c
  */
typedef void (*PSC_ENDPT_LOOKUP_FN) (int, VSTREAM *,
			             MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *,
			            MAI_HOSTADDR_STR *, MAI_SERVPORT_STR *);
extern void psc_endpt_lookup(VSTREAM *, PSC_ENDPT_LOOKUP_FN);
extern void psc_endpt_local_lookup(VSTREAM *, PSC_ENDPT_LOOKUP_FN);

 /*
  * postscreen_access emulation.
  */
#define PSC_ACL_ACT_ALLOWLIST	SERVER_ACL_ACT_PERMIT
#define PSC_ACL_ACT_DUNNO	SERVER_ACL_ACT_DUNNO
#define PSC_ACL_ACT_DENYLIST	SERVER_ACL_ACT_REJECT
#define PSC_ACL_ACT_ERROR	SERVER_ACL_ACT_ERROR

#define psc_acl_pre_jail_init	server_acl_pre_jail_init
#define psc_acl_parse		server_acl_parse
#define psc_acl_eval(s,a,p)	server_acl_eval((s)->smtp_client_addr, (a), (p))

/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*
/*	Wietse Venema
/*	Google, Inc.
/*	111 8th Avenue
/*	New York, NY 10011, USA
/*--*/