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