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