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