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