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