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