Home | History | Annotate | Line # | Download | only in postscreen
      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 
    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 
    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 
    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