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