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