1 /* $NetBSD: postscreen_state.c,v 1.4 2022/10/08 16:12:48 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* postscreen_state 3
6 /* SUMMARY
7 /* postscreen session state and queue length management
8 /* SYNOPSIS
9 /* #include <postscreen.h>
10 /*
11 /* PSC_STATE *psc_new_session_state(stream, client_addr, client_port,
12 /* server_addr, server_port)
13 /* VSTREAM *stream;
14 /* const char *client_addr;
15 /* const char *client_port;
16 /* const char *server_addr;
17 /* const char *server_port;
18 /*
19 /* void psc_free_session_state(state)
20 /* PSC_STATE *state;
21 /*
22 /* char *psc_print_state_flags(flags, context)
23 /* int flags;
24 /* const char *context;
25 /*
26 /* void PSC_ADD_SERVER_STATE(state, server_fd)
27 /* PSC_STATE *state;
28 /* int server_fd;
29 /*
30 /* void PSC_DEL_SERVER_STATE(state)
31 /* PSC_STATE *state;
32 /*
33 /* void PSC_DEL_CLIENT_STATE(state)
34 /* PSC_STATE *state;
35 /*
36 /* void PSC_DROP_SESSION_STATE(state, final_reply)
37 /* PSC_STATE *state;
38 /* const char *final_reply;
39 /*
40 /* void PSC_ENFORCE_SESSION_STATE(state, rcpt_reply)
41 /* PSC_STATE *state;
42 /* const char *rcpt_reply;
43 /*
44 /* void PSC_PASS_SESSION_STATE(state, testname, pass_flag)
45 /* PSC_STATE *state;
46 /* const char *testname;
47 /* int pass_flag;
48 /*
49 /* void PSC_FAIL_SESSION_STATE(state, fail_flag)
50 /* PSC_STATE *state;
51 /* int fail_flag;
52 /*
53 /* void PSC_UNFAIL_SESSION_STATE(state, fail_flag)
54 /* PSC_STATE *state;
55 /* int fail_flag;
56 /* DESCRIPTION
57 /* This module maintains per-client session state, and two
58 /* global file descriptor counters:
59 /* .IP psc_check_queue_length
60 /* The total number of remote SMTP client sockets.
61 /* .IP psc_post_queue_length
62 /* The total number of server file descriptors that are currently
63 /* in use for client file descriptor passing. This number
64 /* equals the number of client file descriptors in transit.
65 /* .PP
66 /* psc_new_session_state() creates a new session state object
67 /* for the specified client stream, and increments the
68 /* psc_check_queue_length counter. The flags and per-test time
69 /* stamps are initialized with PSC_INIT_TESTS(), or for concurrent
70 /* sessions, with PSC_INIT_TEST_FLAGS_ONLY(). The addr and
71 /* port arguments are null-terminated strings with the remote
72 /* SMTP client endpoint. The _reply members are set to
73 /* polite "try again" SMTP replies. The protocol member is set
74 /* to "SMTP".
75 /*
76 /* The psc_stress variable is set to non-zero when
77 /* psc_check_queue_length passes over a high-water mark.
78 /*
79 /* psc_free_session_state() destroys the specified session state
80 /* object, closes the applicable I/O channels, and decrements
81 /* the applicable file descriptor counters: psc_check_queue_length
82 /* and psc_post_queue_length.
83 /*
84 /* The psc_stress variable is reset to zero when psc_check_queue_length
85 /* passes under a low-water mark.
86 /*
87 /* psc_print_state_flags() converts per-session flags into
88 /* human-readable form. The context is for error reporting.
89 /* The result is overwritten upon each call.
90 /*
91 /* PSC_ADD_SERVER_STATE() updates the specified session state
92 /* object with the specified server file descriptor, and
93 /* increments the global psc_post_queue_length file descriptor
94 /* counter.
95 /*
96 /* PSC_DEL_SERVER_STATE() closes the specified session state
97 /* object's server file descriptor, and decrements the global
98 /* psc_post_queue_length file descriptor counter.
99 /*
100 /* PSC_DEL_CLIENT_STATE() updates the specified session state
101 /* object, closes the client stream, and decrements the global
102 /* psc_check_queue_length file descriptor counter.
103 /*
104 /* PSC_DROP_SESSION_STATE() updates the specified session state
105 /* object and closes the client stream after sending the
106 /* specified SMTP reply.
107 /*
108 /* PSC_ENFORCE_SESSION_STATE() updates the specified session
109 /* state object. It arranges that the built-in SMTP engine
110 /* logs sender/recipient information and rejects all RCPT TO
111 /* commands with the specified SMTP reply.
112 /*
113 /* PSC_PASS_SESSION_STATE() sets the specified "pass" flag.
114 /* The testname is used for debug logging.
115 /*
116 /* PSC_FAIL_SESSION_STATE() sets the specified "fail" flag.
117 /*
118 /* PSC_UNFAIL_SESSION_STATE() unsets the specified "fail" flag.
119 /* LICENSE
120 /* .ad
121 /* .fi
122 /* The Secure Mailer license must be distributed with this software.
123 /* AUTHOR(S)
124 /* Wietse Venema
125 /* IBM T.J. Watson Research
126 /* P.O. Box 704
127 /* Yorktown Heights, NY 10598, USA
128 /*
129 /* Wietse Venema
130 /* Google, Inc.
131 /* 111 8th Avenue
132 /* New York, NY 10011, USA
133 /*--*/
134
135 /* System library. */
136
137 #include <sys_defs.h>
138
139 /* Utility library. */
140
141 #include <msg.h>
142 #include <mymalloc.h>
143 #include <name_mask.h>
144 #include <htable.h>
145
146 /* Global library. */
147
148 #include <mail_proto.h>
149
150 /* Master server protocols. */
151
152 #include <mail_server.h>
153
154 /* Application-specific. */
155
156 #include <postscreen.h>
157
158 /* psc_new_session_state - fill in connection state for event processing */
159
psc_new_session_state(VSTREAM * stream,const char * client_addr,const char * client_port,const char * server_addr,const char * server_port)160 PSC_STATE *psc_new_session_state(VSTREAM *stream,
161 const char *client_addr,
162 const char *client_port,
163 const char *server_addr,
164 const char *server_port)
165 {
166 PSC_STATE *state;
167
168 state = (PSC_STATE *) mymalloc(sizeof(*state));
169 if ((state->smtp_client_stream = stream) != 0)
170 psc_check_queue_length++;
171 state->smtp_server_fd = (-1);
172 state->smtp_client_addr = mystrdup(client_addr);
173 state->smtp_client_port = mystrdup(client_port);
174 state->smtp_server_addr = mystrdup(server_addr);
175 state->smtp_server_port = mystrdup(server_port);
176 state->send_buf = vstring_alloc(100);
177 state->test_name = "TEST NAME HERE";
178 state->dnsbl_reply = 0;
179 state->final_reply = "421 4.3.2 Service currently unavailable\r\n";
180 state->rcpt_reply = "450 4.3.2 Service currently unavailable\r\n";
181 state->command_count = 0;
182 state->protocol = MAIL_PROTO_SMTP;
183 state->helo_name = 0;
184 state->sender = 0;
185 state->cmd_buffer = 0;
186 state->read_state = 0;
187 state->ehlo_discard_mask = 0; /* XXX Should be ~0 */
188 state->expand_buf = 0;
189 state->where = PSC_SMTPD_CMD_CONNECT;
190
191 /*
192 * Update the stress level.
193 */
194 if (psc_stress == 0
195 && psc_check_queue_length >= psc_hiwat_check_queue_length) {
196 psc_stress = 1;
197 msg_info("entering STRESS mode with %d connections",
198 psc_check_queue_length);
199 }
200
201 /*
202 * Update the per-client session count.
203 */
204 if ((state->client_info = (PSC_CLIENT_INFO *)
205 htable_find(psc_client_concurrency, client_addr)) == 0) {
206 state->client_info = (PSC_CLIENT_INFO *)
207 mymalloc(sizeof(state->client_info[0]));
208 (void) htable_enter(psc_client_concurrency, client_addr,
209 (void *) state->client_info);
210 PSC_INIT_TESTS(state);
211 state->client_info->concurrency = 1;
212 state->client_info->pass_new_count = 0;
213 } else {
214 PSC_INIT_TEST_FLAGS_ONLY(state);
215 state->client_info->concurrency += 1;
216 }
217
218 return (state);
219 }
220
221 /* psc_free_session_state - destroy connection state including connections */
222
psc_free_session_state(PSC_STATE * state)223 void psc_free_session_state(PSC_STATE *state)
224 {
225 const char *myname = "psc_free_session_state";
226 HTABLE_INFO *ht;
227
228 /*
229 * Update the per-client session count.
230 */
231 if ((ht = htable_locate(psc_client_concurrency,
232 state->smtp_client_addr)) == 0)
233 msg_panic("%s: unknown client address: %s",
234 myname, state->smtp_client_addr);
235 if (--(state->client_info->concurrency) == 0)
236 htable_delete(psc_client_concurrency, state->smtp_client_addr, myfree);
237
238 if (state->smtp_client_stream != 0) {
239 PSC_DEL_CLIENT_STATE(state);
240 }
241 if (state->smtp_server_fd >= 0) {
242 PSC_DEL_SERVER_STATE(state);
243 }
244 if (state->send_buf != 0)
245 state->send_buf = vstring_free(state->send_buf);
246 myfree(state->smtp_client_addr);
247 myfree(state->smtp_client_port);
248 myfree(state->smtp_server_addr);
249 myfree(state->smtp_server_port);
250 if (state->dnsbl_reply)
251 vstring_free(state->dnsbl_reply);
252 if (state->helo_name)
253 myfree(state->helo_name);
254 if (state->sender)
255 myfree(state->sender);
256 if (state->cmd_buffer)
257 vstring_free(state->cmd_buffer);
258 if (state->expand_buf)
259 vstring_free(state->expand_buf);
260 myfree((void *) state);
261
262 if (psc_check_queue_length < 0 || psc_post_queue_length < 0)
263 msg_panic("bad queue length: check_queue=%d, post_queue=%d",
264 psc_check_queue_length, psc_post_queue_length);
265
266 /*
267 * Update the stress level.
268 */
269 if (psc_stress != 0
270 && psc_check_queue_length <= psc_lowat_check_queue_length) {
271 psc_stress = 0;
272 msg_info("leaving STRESS mode with %d connections",
273 psc_check_queue_length);
274 }
275 }
276
277 /* psc_print_state_flags - format state flags */
278
psc_print_state_flags(int flags,const char * context)279 const char *psc_print_state_flags(int flags, const char *context)
280 {
281 static const NAME_MASK flags_mask[] = {
282 "NOFORWARD", PSC_STATE_FLAG_NOFORWARD,
283 "USING_TLS", PSC_STATE_FLAG_USING_TLS,
284 "NEW", PSC_STATE_FLAG_NEW,
285 "DNLIST_FAIL", PSC_STATE_FLAG_DNLIST_FAIL,
286 "HANGUP", PSC_STATE_FLAG_HANGUP,
287 /* unused */
288 "ALLIST_FAIL", PSC_STATE_FLAG_ALLIST_FAIL,
289
290 "PREGR_FAIL", PSC_STATE_FLAG_PREGR_FAIL,
291 "PREGR_PASS", PSC_STATE_FLAG_PREGR_PASS,
292 "PREGR_TODO", PSC_STATE_FLAG_PREGR_TODO,
293 "PREGR_DONE", PSC_STATE_FLAG_PREGR_DONE,
294
295 "DNSBL_FAIL", PSC_STATE_FLAG_DNSBL_FAIL,
296 "DNSBL_PASS", PSC_STATE_FLAG_DNSBL_PASS,
297 "DNSBL_TODO", PSC_STATE_FLAG_DNSBL_TODO,
298 "DNSBL_DONE", PSC_STATE_FLAG_DNSBL_DONE,
299
300 "PIPEL_FAIL", PSC_STATE_FLAG_PIPEL_FAIL,
301 "PIPEL_PASS", PSC_STATE_FLAG_PIPEL_PASS,
302 "PIPEL_TODO", PSC_STATE_FLAG_PIPEL_TODO,
303 "PIPEL_SKIP", PSC_STATE_FLAG_PIPEL_SKIP,
304
305 "NSMTP_FAIL", PSC_STATE_FLAG_NSMTP_FAIL,
306 "NSMTP_PASS", PSC_STATE_FLAG_NSMTP_PASS,
307 "NSMTP_TODO", PSC_STATE_FLAG_NSMTP_TODO,
308 "NSMTP_SKIP", PSC_STATE_FLAG_NSMTP_SKIP,
309
310 "BARLF_FAIL", PSC_STATE_FLAG_BARLF_FAIL,
311 "BARLF_PASS", PSC_STATE_FLAG_BARLF_PASS,
312 "BARLF_TODO", PSC_STATE_FLAG_BARLF_TODO,
313 "BARLF_SKIP", PSC_STATE_FLAG_BARLF_SKIP,
314 0,
315 };
316
317 return (str_name_mask_opt((VSTRING *) 0, context, flags_mask, flags,
318 NAME_MASK_PIPE | NAME_MASK_NUMBER));
319 }
320