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 160PSC_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 223void 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 279const 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