/src/dovecot/src/lib-smtp/smtp-server-connection.c
Line | Count | Source |
1 | | /* Copyright (c) Dovecot authors, see top-level COPYING file */ |
2 | | |
3 | | #include "lib.h" |
4 | | #include "llist.h" |
5 | | #include "array.h" |
6 | | #include "str.h" |
7 | | #include "guid.h" |
8 | | #include "base64.h" |
9 | | #include "ioloop.h" |
10 | | #include "istream.h" |
11 | | #include "ostream.h" |
12 | | #include "iostream.h" |
13 | | #include "connection.h" |
14 | | #include "iostream-rawlog.h" |
15 | | #include "iostream-ssl.h" |
16 | | #include "settings.h" |
17 | | #include "master-service.h" |
18 | | #include "master-service-ssl.h" |
19 | | |
20 | | #include "smtp-syntax.h" |
21 | | #include "smtp-reply-parser.h" |
22 | | #include "smtp-command-parser.h" |
23 | | #include "smtp-server-private.h" |
24 | | #include "ssl-settings.h" |
25 | | |
26 | | const char *const smtp_server_state_names[] = { |
27 | | "GREETING", |
28 | | "XCLIENT", |
29 | | "HELO", |
30 | | "STARTTLS", |
31 | | "AUTH", |
32 | | "READY", |
33 | | "MAIL FROM", |
34 | | "RCPT TO", |
35 | | "DATA" |
36 | | }; |
37 | | |
38 | | /* |
39 | | * Connection |
40 | | */ |
41 | | |
42 | | static void smtp_server_connection_input(struct connection *_conn); |
43 | | static int smtp_server_connection_output(struct smtp_server_connection *conn); |
44 | | static void |
45 | | smtp_server_connection_disconnect(struct smtp_server_connection *conn, |
46 | | const char *reason) ATTR_NULL(2); |
47 | | |
48 | | static void |
49 | | smtp_server_connection_update_stats(struct smtp_server_connection *conn) |
50 | 6.06k | { |
51 | 6.06k | if (conn->conn.input != NULL) |
52 | 6.06k | conn->stats.input = conn->conn.input->v_offset; |
53 | 6.06k | if (conn->conn.output != NULL) |
54 | 6.06k | conn->stats.output = conn->conn.output->offset; |
55 | 6.06k | connection_update_counters(&conn->conn); |
56 | 6.06k | } |
57 | | |
58 | | const struct smtp_server_stats * |
59 | | smtp_server_connection_get_stats(struct smtp_server_connection *conn) |
60 | 0 | { |
61 | 0 | smtp_server_connection_update_stats(conn); |
62 | 0 | return &conn->stats; |
63 | 0 | } |
64 | | |
65 | | static bool |
66 | | smtp_server_connection_check_pipeline(struct smtp_server_connection *conn) |
67 | 160k | { |
68 | 160k | unsigned int pipeline = conn->command_queue_count; |
69 | 160k | struct smtp_server_command *cmd; |
70 | | |
71 | 160k | if (conn->command_queue_tail != NULL) { |
72 | 124k | i_assert(pipeline > 0); |
73 | 124k | if (conn->command_queue_tail->state == |
74 | 124k | SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY) |
75 | 2.88k | pipeline--; |
76 | 124k | } |
77 | | |
78 | 160k | if (pipeline >= conn->set.max_pipelined_commands) { |
79 | 3.84k | e_debug(conn->event, "Command pipeline is full " |
80 | 3.84k | "(pipelined commands %u > limit %u)", |
81 | 3.84k | pipeline, conn->set.max_pipelined_commands); |
82 | 3.84k | return FALSE; |
83 | 3.84k | } |
84 | | |
85 | 156k | cmd = conn->command_queue_head; |
86 | 749k | while (cmd != NULL) { |
87 | 609k | if (cmd->pipeline_blocked) |
88 | 16.7k | return FALSE; |
89 | 592k | cmd = cmd->next; |
90 | 592k | } |
91 | 140k | return TRUE; |
92 | 156k | } |
93 | | |
94 | | void smtp_server_connection_input_halt(struct smtp_server_connection *conn) |
95 | 82.1k | { |
96 | 82.1k | connection_input_halt(&conn->conn); |
97 | 82.1k | } |
98 | | |
99 | | void smtp_server_connection_input_resume(struct smtp_server_connection *conn) |
100 | 65.1k | { |
101 | 65.1k | struct smtp_server_command *cmd; |
102 | | |
103 | 65.1k | if (conn->conn.io == NULL) { |
104 | | /* Only resume when we actually can */ |
105 | 48.0k | if (conn->input_locked || conn->input_broken || |
106 | 40.9k | conn->disconnected) |
107 | 7.54k | return; |
108 | 40.4k | if (!smtp_server_connection_check_pipeline(conn)) { |
109 | 3.68k | i_assert(conn->command_queue_tail != NULL); |
110 | 3.68k | if (!conn->command_queue_tail->pipeline_blocked || |
111 | 3.10k | !smtp_server_connection_pending_command_data(conn)) |
112 | 3.68k | return; |
113 | 3.68k | } |
114 | | |
115 | | /* Is queued command still blocking input? */ |
116 | 36.7k | cmd = conn->command_queue_head; |
117 | 125k | while (cmd != NULL) { |
118 | 89.4k | if (cmd->input_locked) |
119 | 1.17k | return; |
120 | 88.2k | cmd = cmd->next; |
121 | 88.2k | } |
122 | | |
123 | | /* Restore input handler */ |
124 | 35.6k | connection_input_resume(&conn->conn); |
125 | 35.6k | } |
126 | | |
127 | 52.7k | if (conn->conn.io != NULL && |
128 | 52.7k | i_stream_have_bytes_left(conn->conn.input)) { |
129 | 52.3k | io_set_pending(conn->conn.io); |
130 | 52.3k | } |
131 | 52.7k | } |
132 | | |
133 | | void smtp_server_connection_input_lock(struct smtp_server_connection *conn) |
134 | 6.06k | { |
135 | 6.06k | conn->input_locked = TRUE; |
136 | 6.06k | smtp_server_connection_input_halt(conn); |
137 | 6.06k | } |
138 | | |
139 | | void smtp_server_connection_input_unlock(struct smtp_server_connection *conn) |
140 | 6.06k | { |
141 | 6.06k | conn->input_locked = FALSE; |
142 | 6.06k | smtp_server_connection_input_resume(conn); |
143 | 6.06k | } |
144 | | |
145 | | #undef smtp_server_connection_input_capture |
146 | | void smtp_server_connection_input_capture( |
147 | | struct smtp_server_connection *conn, |
148 | | smtp_server_input_callback_t *callback, void *context) |
149 | 10.5k | { |
150 | 10.5k | i_assert(!conn->input_broken && !conn->disconnected); |
151 | 10.5k | connection_input_halt(&conn->conn); |
152 | 10.5k | i_stream_set_input_pending(conn->conn.input, TRUE); |
153 | 10.5k | conn->conn.io = io_add_istream(conn->conn.input, *callback, context); |
154 | 10.5k | } |
155 | | |
156 | | static void |
157 | | smtp_server_connection_update_rawlog(struct smtp_server_connection *conn) |
158 | 6.06k | { |
159 | 6.06k | struct stat st; |
160 | | |
161 | 6.06k | if (conn->set.rawlog_dir == NULL) |
162 | 6.06k | return; |
163 | | |
164 | 0 | if (!conn->rawlog_checked) { |
165 | 0 | conn->rawlog_checked = TRUE; |
166 | 0 | if (stat(conn->set.rawlog_dir, &st) == 0) |
167 | 0 | conn->rawlog_enabled = TRUE; |
168 | 0 | } |
169 | 0 | if (conn->rawlog_enabled) { |
170 | | /* FIXME: we don't know the setting name here */ |
171 | 0 | iostream_rawlog_create(conn->event, "smtp server rawlog", |
172 | 0 | conn->set.rawlog_dir, |
173 | 0 | &conn->conn.input, &conn->conn.output); |
174 | 0 | } |
175 | 0 | } |
176 | | |
177 | | static void |
178 | | smtp_server_connection_streams_changed(struct smtp_server_connection *conn) |
179 | 0 | { |
180 | 0 | smtp_server_connection_update_rawlog(conn); |
181 | 0 | smtp_command_parser_set_stream(conn->smtp_parser, conn->conn.input); |
182 | |
|
183 | 0 | o_stream_set_flush_callback(conn->conn.output, |
184 | 0 | smtp_server_connection_output, conn); |
185 | 0 | o_stream_set_flush_pending(conn->conn.output, TRUE); |
186 | 0 | } |
187 | | |
188 | | void smtp_server_connection_set_streams(struct smtp_server_connection *conn, |
189 | | struct istream *input, |
190 | | struct ostream *output) |
191 | 0 | { |
192 | 0 | struct istream *old_input = conn->conn.input; |
193 | 0 | struct ostream *old_output = conn->conn.output; |
194 | |
|
195 | 0 | i_assert(conn->created_from_streams); |
196 | | |
197 | 0 | conn->conn.input = input; |
198 | 0 | i_stream_ref(conn->conn.input); |
199 | |
|
200 | 0 | conn->conn.output = output; |
201 | 0 | o_stream_ref(conn->conn.output); |
202 | 0 | o_stream_set_no_error_handling(conn->conn.output, TRUE); |
203 | |
|
204 | 0 | i_stream_unref(&old_input); |
205 | 0 | o_stream_unref(&old_output); |
206 | |
|
207 | 0 | smtp_server_connection_streams_changed(conn); |
208 | 0 | } |
209 | | |
210 | | void smtp_server_connection_set_ssl_streams(struct smtp_server_connection *conn, |
211 | | struct istream *input, |
212 | | struct ostream *output) |
213 | 0 | { |
214 | 0 | conn->ssl_secured = TRUE; |
215 | 0 | conn->set.capabilities &= ENUM_NEGATE(SMTP_CAPABILITY_STARTTLS); |
216 | |
|
217 | 0 | smtp_server_connection_set_streams(conn, input, output); |
218 | 0 | } |
219 | | |
220 | | static void |
221 | | smtp_server_connection_idle_timeout(struct smtp_server_connection *conn) |
222 | 0 | { |
223 | 0 | smtp_server_connection_terminate( |
224 | 0 | &conn, "4.4.2", "Disconnected for inactivity"); |
225 | 0 | } |
226 | | |
227 | | void smtp_server_connection_timeout_stop(struct smtp_server_connection *conn) |
228 | 111k | { |
229 | 111k | if (conn->to_idle != NULL) { |
230 | 37.5k | e_debug(conn->event, "Timeout stop"); |
231 | | |
232 | 37.5k | timeout_remove(&conn->to_idle); |
233 | 37.5k | } |
234 | 111k | } |
235 | | |
236 | | void smtp_server_connection_timeout_start(struct smtp_server_connection *conn) |
237 | 44.0k | { |
238 | 44.0k | if (conn->disconnected) |
239 | 764 | return; |
240 | | |
241 | 43.3k | if (conn->to_idle == NULL && |
242 | 37.5k | conn->set.max_client_idle_time_msecs > 0) { |
243 | 37.5k | e_debug(conn->event, "Timeout start"); |
244 | | |
245 | 37.5k | conn->to_idle = timeout_add( |
246 | 37.5k | conn->set.max_client_idle_time_msecs, |
247 | 37.5k | smtp_server_connection_idle_timeout, conn); |
248 | 37.5k | } |
249 | 43.3k | } |
250 | | |
251 | | void smtp_server_connection_timeout_reset(struct smtp_server_connection *conn) |
252 | 79.6k | { |
253 | 79.6k | if (conn->to_idle != NULL) |
254 | 55.8k | timeout_reset(conn->to_idle); |
255 | 79.6k | } |
256 | | |
257 | | static void |
258 | | smtp_server_connection_timeout_update(struct smtp_server_connection *conn) |
259 | 131k | { |
260 | 131k | struct smtp_server_command *cmd = conn->command_queue_head; |
261 | | |
262 | 131k | if (cmd == NULL) { |
263 | 33.2k | smtp_server_connection_timeout_start(conn); |
264 | 33.2k | return; |
265 | 33.2k | } |
266 | | |
267 | 98.2k | switch (cmd->state) { |
268 | 0 | case SMTP_SERVER_COMMAND_STATE_NEW: |
269 | 0 | smtp_server_connection_timeout_start(conn); |
270 | 0 | break; |
271 | 231 | case SMTP_SERVER_COMMAND_STATE_PROCESSING: |
272 | 231 | if (cmd->input_captured) { |
273 | | /* Command updates timeout internally */ |
274 | 231 | return; |
275 | 231 | } |
276 | 0 | smtp_server_connection_timeout_stop(conn); |
277 | 0 | break; |
278 | 852 | case SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY: |
279 | 98.0k | case SMTP_SERVER_COMMAND_STATE_READY_TO_REPLY: |
280 | 98.0k | smtp_server_connection_timeout_stop(conn); |
281 | 98.0k | break; |
282 | 0 | case SMTP_SERVER_COMMAND_STATE_FINISHED: |
283 | 0 | case SMTP_SERVER_COMMAND_STATE_ABORTED: |
284 | 0 | i_unreached(); |
285 | 98.2k | } |
286 | 98.2k | } |
287 | | |
288 | | static void smtp_server_connection_ready(struct smtp_server_connection *conn) |
289 | 6.06k | { |
290 | 6.06k | conn->raw_input = conn->conn.input; |
291 | 6.06k | conn->raw_output = conn->conn.output; |
292 | | |
293 | 6.06k | conn->connect_succeeded = TRUE; |
294 | | |
295 | 6.06k | smtp_server_connection_update_rawlog(conn); |
296 | | |
297 | 6.06k | conn->smtp_parser = smtp_command_parser_init(conn->conn.input, |
298 | 6.06k | &conn->set.command_limits); |
299 | 6.06k | o_stream_set_flush_callback(conn->conn.output, |
300 | 6.06k | smtp_server_connection_output, conn); |
301 | | |
302 | 6.06k | o_stream_cork(conn->conn.output); |
303 | 6.06k | if (conn->set.no_greeting) { |
304 | | /* Don't send greeting or login reply. */ |
305 | 6.06k | } else if (conn->authenticated) { |
306 | | /* RFC 4954, Section 4: |
307 | | Should the client successfully complete the exchange, the |
308 | | SMTP server issues a 235 reply. */ |
309 | 0 | smtp_server_connection_send_line( |
310 | 0 | conn, "235 2.7.0 Logged in."); |
311 | 6.06k | } else { |
312 | 6.06k | smtp_server_connection_send_line( |
313 | 6.06k | conn, "220 %s %s", conn->set.hostname, |
314 | 6.06k | conn->set.login_greeting); |
315 | 6.06k | } |
316 | 6.06k | if (!conn->corked) |
317 | 6.06k | o_stream_uncork(conn->conn.output); |
318 | 6.06k | } |
319 | | |
320 | | static void smtp_server_connection_destroy(struct connection *_conn) |
321 | 3.60k | { |
322 | 3.60k | struct smtp_server_connection *conn = |
323 | 3.60k | (struct smtp_server_connection *)_conn; |
324 | | |
325 | 3.60k | smtp_server_connection_disconnect(conn, NULL); |
326 | 3.60k | smtp_server_connection_unref(&conn); |
327 | 3.60k | } |
328 | | |
329 | | static bool |
330 | | smtp_server_connection_handle_command(struct smtp_server_connection *conn, |
331 | | const char *cmd_name, |
332 | | const char *cmd_params) |
333 | 97.9k | { |
334 | 97.9k | struct smtp_server_connection *tmp_conn = conn; |
335 | 97.9k | struct smtp_server_command *cmd; |
336 | 97.9k | bool finished; |
337 | | |
338 | 97.9k | cmd = smtp_server_command_new(tmp_conn, cmd_name); |
339 | | |
340 | 97.9k | smtp_server_command_ref(cmd); |
341 | | |
342 | 97.9k | smtp_server_connection_ref(tmp_conn); |
343 | 97.9k | smtp_server_command_execute(cmd, cmd_params); |
344 | 97.9k | if (!smtp_server_connection_unref(&tmp_conn)) { |
345 | | /* The command start callback managed to get this connection |
346 | | destroyed */ |
347 | 0 | smtp_server_command_unref(&cmd); |
348 | 0 | return FALSE; |
349 | 0 | } |
350 | | |
351 | 97.9k | if (conn->command_queue_head == cmd) |
352 | 21.6k | (void)smtp_server_command_next_to_reply(&cmd); |
353 | | |
354 | 97.9k | smtp_server_connection_timeout_update(conn); |
355 | | |
356 | 97.9k | finished = !cmd->input_locked; |
357 | 97.9k | return (!smtp_server_command_unref(&cmd) || finished); |
358 | 97.9k | } |
359 | | |
360 | | static int |
361 | | smtp_server_connection_sni_callback(const char *name, const char **error_r, |
362 | | void *context) |
363 | 0 | { |
364 | 0 | struct smtp_server_connection *conn = context; |
365 | 0 | struct ssl_iostream_context *ssl_ctx; |
366 | 0 | const struct ssl_settings *ssl_set; |
367 | 0 | const struct ssl_server_settings *ssl_server_set; |
368 | |
|
369 | 0 | event_add_str(conn->event, "local_name", name); |
370 | 0 | i_free(conn->local_name); |
371 | 0 | conn->local_name = i_strdup(name); |
372 | 0 | if (ssl_server_settings_get(conn->event, &ssl_set, &ssl_server_set, |
373 | 0 | error_r) < 0) |
374 | 0 | return -1; |
375 | 0 | if (conn->local_name != NULL && *conn->local_name != '\0') |
376 | 0 | conn->set.hostname = conn->local_name; |
377 | 0 | if (conn->callbacks->conn_tls_sni_callback != NULL && |
378 | 0 | conn->callbacks->conn_tls_sni_callback(conn->context, name, |
379 | 0 | error_r) < 0) { |
380 | 0 | settings_free(ssl_set); |
381 | 0 | settings_free(ssl_server_set); |
382 | 0 | return -1; |
383 | 0 | } |
384 | | |
385 | 0 | ssl_server_settings_to_iostream_set(ssl_set, ssl_server_set, |
386 | 0 | &conn->set.ssl); |
387 | |
|
388 | 0 | int ret; |
389 | 0 | if ((ret = ssl_iostream_server_context_cache_get(conn->set.ssl, &ssl_ctx, |
390 | 0 | error_r)) < 0) { |
391 | 0 | settings_free(ssl_set); |
392 | 0 | settings_free(ssl_server_set); |
393 | 0 | return -1; |
394 | 0 | } |
395 | 0 | settings_free(ssl_set); |
396 | 0 | settings_free(ssl_server_set); |
397 | 0 | if (ret == 1) { |
398 | 0 | const char *application_protocol = smtp_protocol_name(conn->set.protocol); |
399 | 0 | const char *const names[] = { |
400 | 0 | application_protocol, |
401 | 0 | NULL |
402 | 0 | }; |
403 | 0 | ssl_iostream_context_set_application_protocols(ssl_ctx, names); |
404 | 0 | } |
405 | 0 | ssl_iostream_change_context(conn->ssl_iostream, ssl_ctx); |
406 | 0 | ssl_iostream_context_unref(&ssl_ctx); |
407 | 0 | return 0; |
408 | 0 | } |
409 | | |
410 | | int smtp_server_connection_ssl_init(struct smtp_server_connection *conn) |
411 | 0 | { |
412 | 0 | struct ssl_iostream_context *ssl_ctx; |
413 | 0 | const char *error; |
414 | 0 | int ret; |
415 | |
|
416 | 0 | e_debug(conn->event, "Starting SSL handshake"); |
417 | |
|
418 | 0 | if (conn->raw_input != conn->conn.input) { |
419 | | /* Recreate rawlog after STARTTLS */ |
420 | 0 | i_stream_ref(conn->raw_input); |
421 | 0 | o_stream_ref(conn->raw_output); |
422 | 0 | i_stream_destroy(&conn->conn.input); |
423 | 0 | o_stream_destroy(&conn->conn.output); |
424 | 0 | conn->conn.input = conn->raw_input; |
425 | 0 | conn->conn.output = conn->raw_output; |
426 | 0 | } |
427 | |
|
428 | 0 | smtp_server_connection_input_halt(conn); |
429 | 0 | if (conn->set.ssl == NULL) { |
430 | 0 | const struct ssl_iostream_server_autocreate_parameters parameters = { |
431 | 0 | .event_parent = conn->event, |
432 | 0 | }; |
433 | 0 | ret = io_stream_autocreate_ssl_server(¶meters, |
434 | 0 | &conn->conn.input, &conn->conn.output, |
435 | 0 | &conn->ssl_iostream, &error); |
436 | 0 | } else if (ssl_iostream_server_context_cache_get(conn->set.ssl, |
437 | 0 | &ssl_ctx, &error) < 0) |
438 | 0 | ret = -1; |
439 | 0 | else { |
440 | 0 | ret = io_stream_create_ssl_server(ssl_ctx, conn->event, |
441 | 0 | &conn->conn.input, &conn->conn.output, |
442 | 0 | &conn->ssl_iostream, &error); |
443 | 0 | ssl_iostream_context_unref(&ssl_ctx); |
444 | 0 | } |
445 | 0 | if (ret < 0) { |
446 | 0 | e_error(conn->event, |
447 | 0 | "Couldn't initialize SSL server for %s: %s", |
448 | 0 | conn->conn.name, error); |
449 | 0 | return -1; |
450 | 0 | } |
451 | 0 | ssl_iostream_set_sni_callback( |
452 | 0 | conn->ssl_iostream, smtp_server_connection_sni_callback, conn); |
453 | 0 | smtp_server_connection_input_resume(conn); |
454 | |
|
455 | 0 | if (ssl_iostream_handshake(conn->ssl_iostream) < 0) { |
456 | 0 | e_error(conn->event, "SSL handshake failed: %s", |
457 | 0 | ssl_iostream_get_last_error(conn->ssl_iostream)); |
458 | 0 | return -1; |
459 | 0 | } |
460 | | |
461 | 0 | conn->ssl_secured = TRUE; |
462 | 0 | conn->set.capabilities &= ENUM_NEGATE(SMTP_CAPABILITY_STARTTLS); |
463 | |
|
464 | 0 | if (conn->connect_succeeded) |
465 | 0 | smtp_server_connection_streams_changed(conn); |
466 | 0 | else if (conn->ssl_start && |
467 | 0 | ssl_iostream_is_handshaked(conn->ssl_iostream)) |
468 | 0 | smtp_server_connection_ready(conn); |
469 | |
|
470 | 0 | return 0; |
471 | 0 | } |
472 | | |
473 | | static void |
474 | | smtp_server_connection_handle_input(struct smtp_server_connection *conn, |
475 | | bool pipeline_blocked) |
476 | 25.9k | { |
477 | 25.9k | struct smtp_server_command *pending_command; |
478 | 25.9k | enum smtp_command_parse_error error_code; |
479 | 25.9k | const char *cmd_name, *cmd_params, *error; |
480 | 25.9k | int ret; |
481 | | |
482 | | /* Check whether we are continuing a command */ |
483 | 25.9k | pending_command = NULL; |
484 | 25.9k | if (conn->command_queue_tail != NULL) { |
485 | 171 | pending_command = |
486 | 171 | ((conn->command_queue_tail->state == |
487 | 171 | SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY) ? |
488 | 171 | conn->command_queue_tail : NULL); |
489 | 171 | } |
490 | | |
491 | 25.9k | smtp_server_connection_timeout_reset(conn); |
492 | | |
493 | | /* Parse commands */ |
494 | 25.9k | ret = 1; |
495 | 40.5k | while (!conn->closing && !conn->input_locked && ret != 0) { |
496 | 117k | while ((ret = smtp_command_parse_next( |
497 | 117k | conn->smtp_parser, pipeline_blocked, |
498 | 117k | &cmd_name, &cmd_params, &error_code, &error)) > 0) { |
499 | | |
500 | 98.0k | if (pending_command != NULL) { |
501 | | /* Previous command is now fully read and ready |
502 | | to reply */ |
503 | 2.59k | smtp_server_command_ready_to_reply(pending_command); |
504 | 2.59k | pending_command = NULL; |
505 | 2.59k | } |
506 | | |
507 | 98.0k | if (pipeline_blocked) { |
508 | 63 | e_debug(conn->event, |
509 | 63 | "Discarded remaining data for previous command"); |
510 | 63 | break; |
511 | 63 | } |
512 | | |
513 | 98.0k | e_debug(conn->event, "Received new command: %s %s", |
514 | 97.9k | cmd_name, cmd_params); |
515 | | |
516 | 97.9k | conn->stats.command_count++; |
517 | | |
518 | | /* Handle command (cmd may be destroyed after this) */ |
519 | 97.9k | if (!smtp_server_connection_handle_command(conn, |
520 | 97.9k | cmd_name, cmd_params)) |
521 | 3.38k | return; |
522 | | |
523 | 94.6k | if (conn->disconnected) |
524 | 215 | return; |
525 | | /* Last command locked the input; stop trying to read |
526 | | more. */ |
527 | 94.3k | if (conn->input_locked) |
528 | 0 | break; |
529 | | /* Client indicated it will close after this command; |
530 | | stop trying to read more. */ |
531 | 94.3k | if (conn->closing) |
532 | 0 | break; |
533 | | |
534 | 94.3k | if (!smtp_server_connection_check_pipeline(conn)) |
535 | 16.8k | pipeline_blocked = TRUE; |
536 | 94.3k | if (pipeline_blocked && |
537 | 16.8k | !smtp_command_parser_pending_data(conn->smtp_parser)) { |
538 | 16.7k | smtp_server_connection_input_halt(conn); |
539 | 16.7k | return; |
540 | 16.7k | } |
541 | | |
542 | 77.6k | if (conn->command_queue_tail != NULL) { |
543 | 77.6k | pending_command = |
544 | 77.6k | ((conn->command_queue_tail->state == |
545 | 77.6k | SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY) ? |
546 | 77.6k | conn->command_queue_tail : NULL); |
547 | 77.6k | } |
548 | 77.6k | } |
549 | | |
550 | 19.9k | if (ret < 0 && conn->conn.input->eof) { |
551 | 5.15k | const char *error = |
552 | 5.15k | i_stream_get_disconnect_reason(conn->conn.input); |
553 | 5.15k | e_debug(conn->event, "Remote closed connection: %s", |
554 | 5.15k | error); |
555 | | |
556 | 5.15k | if (conn->command_queue_head == NULL || |
557 | 3.62k | conn->command_queue_head->state < |
558 | 3.62k | SMTP_SERVER_COMMAND_STATE_SUBMITTED_REPLY) { |
559 | | /* No pending commands or unfinished |
560 | | command; close */ |
561 | 1.53k | smtp_server_connection_close(&conn, error); |
562 | 3.62k | } else { |
563 | | /* A command is still processing; |
564 | | only drop input io for now */ |
565 | 3.62k | conn->input_broken = TRUE; |
566 | 3.62k | smtp_server_connection_input_halt(conn); |
567 | 3.62k | } |
568 | 5.15k | return; |
569 | 5.15k | } |
570 | | |
571 | 14.7k | if (ret < 0) { |
572 | 14.5k | struct smtp_server_command *cmd; |
573 | | |
574 | 14.5k | e_debug(conn->event, |
575 | 14.5k | "Client sent invalid command: %s", error); |
576 | | |
577 | 14.5k | switch (error_code) { |
578 | 0 | case SMTP_COMMAND_PARSE_ERROR_BROKEN_COMMAND: |
579 | 0 | conn->input_broken = TRUE; |
580 | | /* fall through */ |
581 | 14.0k | case SMTP_COMMAND_PARSE_ERROR_BAD_COMMAND: |
582 | 14.0k | cmd = smtp_server_command_new_invalid(conn); |
583 | 14.0k | smtp_server_command_fail( |
584 | 14.0k | cmd, 500, "5.5.2", |
585 | 14.0k | "Invalid command syntax"); |
586 | 14.0k | break; |
587 | 437 | case SMTP_COMMAND_PARSE_ERROR_LINE_TOO_LONG: |
588 | 437 | cmd = smtp_server_command_new_invalid(conn); |
589 | 437 | smtp_server_command_fail( |
590 | 437 | cmd, 500, "5.5.2", "Line too long"); |
591 | 437 | break; |
592 | 0 | case SMTP_COMMAND_PARSE_ERROR_DATA_TOO_LARGE: |
593 | | /* Command data size exceeds the absolute limit; |
594 | | i.e. beyond which we don't even want to skip |
595 | | data anymore. The command error is usually |
596 | | already submitted by the application and sent |
597 | | to the client. */ |
598 | 0 | smtp_server_connection_close(&conn, |
599 | 0 | "Command data size exceeds absolute limit"); |
600 | 0 | return; |
601 | 0 | case SMTP_COMMAND_PARSE_ERROR_BROKEN_STREAM: |
602 | 0 | smtp_server_connection_close(&conn, error); |
603 | 0 | return; |
604 | 0 | default: |
605 | 0 | i_unreached(); |
606 | 14.5k | } |
607 | 14.5k | } |
608 | | |
609 | 14.7k | if (conn->disconnected) |
610 | 112 | return; |
611 | 14.6k | if (conn->input_broken || conn->closing) { |
612 | 0 | smtp_server_connection_input_halt(conn); |
613 | 0 | return; |
614 | 0 | } |
615 | | |
616 | 14.6k | if (ret == 0 && pending_command != NULL && |
617 | 71 | !smtp_command_parser_pending_data(conn->smtp_parser)) { |
618 | | /* Previous command is now fully read and ready to |
619 | | reply */ |
620 | 19 | smtp_server_command_ready_to_reply(pending_command); |
621 | 19 | } |
622 | | |
623 | 14.6k | if (pipeline_blocked && |
624 | 74 | !smtp_command_parser_pending_data(conn->smtp_parser)) { |
625 | 63 | smtp_server_connection_input_halt(conn); |
626 | 63 | return; |
627 | 63 | } |
628 | 14.6k | } |
629 | 25.9k | } |
630 | | |
631 | | static void smtp_server_connection_input(struct connection *_conn) |
632 | 25.9k | { |
633 | 25.9k | struct smtp_server_connection *conn = |
634 | 25.9k | (struct smtp_server_connection *)_conn; |
635 | 25.9k | int ret; |
636 | | |
637 | 25.9k | i_assert(!conn->input_broken); |
638 | | |
639 | 25.9k | if (conn->handling_input) |
640 | 0 | return; |
641 | | |
642 | 25.9k | smtp_server_connection_timeout_reset(conn); |
643 | | |
644 | 25.9k | if (conn->ssl_start && conn->ssl_iostream == NULL) { |
645 | 0 | if (smtp_server_connection_ssl_init(conn) < 0) { |
646 | 0 | smtp_server_connection_close(&conn, |
647 | 0 | "SSL Initialization failed"); |
648 | 0 | return; |
649 | 0 | } |
650 | 0 | } |
651 | 25.9k | i_assert(!conn->halted); |
652 | | |
653 | | /* If connection is established over secure line, wait for TLS |
654 | | handshake to finish. */ |
655 | 25.9k | if (conn->ssl_iostream != NULL && |
656 | 0 | !ssl_iostream_is_handshaked(conn->ssl_iostream)) { |
657 | | /* Finish SSL negotiating by reading from input stream. */ |
658 | 0 | while ((ret = i_stream_read(conn->conn.input)) > 0 || |
659 | 0 | ret == -2) { |
660 | 0 | if (ssl_iostream_is_handshaked(conn->ssl_iostream)) |
661 | 0 | break; |
662 | 0 | } |
663 | 0 | if (ret == -1) { |
664 | 0 | int stream_errno = conn->conn.input->stream_errno; |
665 | | |
666 | | /* Failed somehow. */ |
667 | 0 | i_assert(ret != -2); |
668 | 0 | const char *error = t_strdup_printf( |
669 | 0 | "SSL handshaking with %s failed: " |
670 | 0 | "read(%s) failed: %s", |
671 | 0 | _conn->name, |
672 | 0 | i_stream_get_name(conn->conn.input), |
673 | 0 | (stream_errno != 0 ? |
674 | 0 | i_stream_get_error(conn->conn.input) : "EOF")); |
675 | 0 | e_error(conn->event, "%s", error); |
676 | 0 | smtp_server_connection_close(&conn, error); |
677 | 0 | return; |
678 | 0 | } |
679 | 0 | if (!ssl_iostream_is_handshaked(conn->ssl_iostream)) { |
680 | | /* Not finished. */ |
681 | 0 | i_assert(ret == 0); |
682 | 0 | return; |
683 | 0 | } |
684 | 0 | if (conn->halted) { |
685 | 0 | smtp_server_connection_input_lock(conn); |
686 | 0 | return; |
687 | 0 | } |
688 | 0 | } |
689 | | |
690 | 25.9k | if (!conn->connect_succeeded && |
691 | 0 | (conn->ssl_iostream == NULL || |
692 | 0 | ssl_iostream_is_handshaked(conn->ssl_iostream))) |
693 | 0 | smtp_server_connection_ready(conn); |
694 | | |
695 | 25.9k | bool pipeline_blocked = FALSE; |
696 | 25.9k | if (!smtp_server_connection_check_pipeline(conn)) { |
697 | | /* Check whether the last command in the queue is blocking the |
698 | | pipeline and whether it still has pending input data. In that |
699 | | case we read/discard that first to possibly unblock the |
700 | | pipeline. */ |
701 | 11 | if (conn->command_queue_tail == NULL || |
702 | 11 | !conn->command_queue_tail->pipeline_blocked || |
703 | 11 | !smtp_server_connection_pending_command_data(conn)) { |
704 | 11 | smtp_server_connection_input_halt(conn); |
705 | 11 | return; |
706 | 11 | } |
707 | 0 | pipeline_blocked = TRUE; |
708 | 0 | } |
709 | | |
710 | 25.9k | smtp_server_connection_ref(conn); |
711 | 25.9k | conn->handling_input = TRUE; |
712 | 25.9k | if (conn->callbacks != NULL && |
713 | 25.9k | conn->callbacks->conn_cmd_input_pre != NULL) |
714 | 0 | conn->callbacks->conn_cmd_input_pre(conn->context); |
715 | 25.9k | smtp_server_connection_handle_input(conn, pipeline_blocked); |
716 | 25.9k | if (conn->callbacks != NULL && |
717 | 25.9k | conn->callbacks->conn_cmd_input_post != NULL) |
718 | 0 | conn->callbacks->conn_cmd_input_post(conn->context); |
719 | 25.9k | conn->handling_input = FALSE; |
720 | | |
721 | | /* Handle output errors from immediate replies sent to client |
722 | | (normal replies are exclusively sent in output handler). */ |
723 | 25.9k | if (conn->conn.output != NULL && conn->conn.output->closed) |
724 | 1.86k | smtp_server_connection_handle_output_error(conn); |
725 | 25.9k | smtp_server_connection_unref(&conn); |
726 | 25.9k | } |
727 | | |
728 | | bool smtp_server_connection_pending_command_data( |
729 | | struct smtp_server_connection *conn) |
730 | 114k | { |
731 | 114k | if (conn->smtp_parser == NULL) |
732 | 0 | return FALSE; |
733 | 114k | return smtp_command_parser_pending_data(conn->smtp_parser); |
734 | 114k | } |
735 | | |
736 | | /* |
737 | | * Command reply handling |
738 | | */ |
739 | | |
740 | | void smtp_server_connection_handle_output_error( |
741 | | struct smtp_server_connection *conn) |
742 | 2.40k | { |
743 | 2.40k | smtp_server_connection_close(&conn, |
744 | 2.40k | o_stream_get_disconnect_reason(conn->conn.output)); |
745 | 2.40k | } |
746 | | |
747 | | static bool |
748 | | smtp_server_connection_next_reply(struct smtp_server_connection *conn) |
749 | 136k | { |
750 | 136k | struct smtp_server_command *cmd; |
751 | | |
752 | 136k | cmd = conn->command_queue_head; |
753 | 136k | if (cmd == NULL) { |
754 | | /* No commands pending */ |
755 | 26.4k | e_debug(conn->event, "No more commands pending"); |
756 | 26.4k | return FALSE; |
757 | 26.4k | } |
758 | | |
759 | 109k | return smtp_server_command_send_replies(cmd); |
760 | 136k | } |
761 | | |
762 | | void smtp_server_connection_cork(struct smtp_server_connection *conn) |
763 | 0 | { |
764 | 0 | conn->corked = TRUE; |
765 | 0 | if (conn->conn.output != NULL) |
766 | 0 | o_stream_cork(conn->conn.output); |
767 | 0 | } |
768 | | |
769 | | void smtp_server_connection_uncork(struct smtp_server_connection *conn) |
770 | 0 | { |
771 | 0 | conn->corked = FALSE; |
772 | 0 | if (!conn->conn.output->closed) { |
773 | 0 | if (o_stream_uncork_flush(conn->conn.output) < 0) { |
774 | 0 | smtp_server_connection_handle_output_error(conn); |
775 | 0 | return; |
776 | 0 | } |
777 | 0 | smtp_server_connection_trigger_output(conn); |
778 | 0 | } |
779 | 0 | } |
780 | | |
781 | | static void |
782 | | smtp_server_connection_send_replies(struct smtp_server_connection *conn) |
783 | 27.4k | { |
784 | | /* Send more replies until no more replies remain, the output |
785 | | blocks again, or the connection is closed */ |
786 | 136k | while (!conn->disconnected && smtp_server_connection_next_reply(conn)); |
787 | | |
788 | 27.4k | smtp_server_connection_timeout_update(conn); |
789 | | |
790 | | /* Accept more commands if possible */ |
791 | 27.4k | smtp_server_connection_input_resume(conn); |
792 | 27.4k | } |
793 | | |
794 | | int smtp_server_connection_flush(struct smtp_server_connection *conn) |
795 | 27.4k | { |
796 | 27.4k | struct ostream *output = conn->conn.output; |
797 | 27.4k | int ret; |
798 | | |
799 | 27.4k | if ((ret = o_stream_flush(output)) <= 0) { |
800 | 0 | if (ret < 0) |
801 | 0 | smtp_server_connection_handle_output_error(conn); |
802 | 0 | return ret; |
803 | 0 | } |
804 | 27.4k | return 1; |
805 | 27.4k | } |
806 | | |
807 | | static int smtp_server_connection_output(struct smtp_server_connection *conn) |
808 | 27.4k | { |
809 | 27.4k | int ret; |
810 | | |
811 | 27.4k | e_debug(conn->event, "Sending replies"); |
812 | | |
813 | 27.4k | smtp_server_connection_ref(conn); |
814 | 27.4k | o_stream_cork(conn->conn.output); |
815 | 27.4k | ret = smtp_server_connection_flush(conn); |
816 | 27.4k | if (ret > 0) { |
817 | 27.4k | smtp_server_connection_timeout_reset(conn); |
818 | 27.4k | smtp_server_connection_send_replies(conn); |
819 | 27.4k | } |
820 | 27.4k | if (ret >= 0 && !conn->corked && conn->conn.output != NULL) |
821 | 27.4k | ret = o_stream_uncork_flush(conn->conn.output); |
822 | 27.4k | if (conn->conn.output != NULL && conn->conn.output->closed) { |
823 | 549 | smtp_server_connection_handle_output_error(conn); |
824 | 549 | ret = -1; |
825 | 549 | } |
826 | 27.4k | smtp_server_connection_unref(&conn); |
827 | 27.4k | return ret; |
828 | 27.4k | } |
829 | | |
830 | | void smtp_server_connection_trigger_output(struct smtp_server_connection *conn) |
831 | 220k | { |
832 | 220k | if (conn->conn.output != NULL) { |
833 | 220k | e_debug(conn->event, "Trigger output"); |
834 | 220k | o_stream_set_flush_pending(conn->conn.output, TRUE); |
835 | 220k | } |
836 | 220k | } |
837 | | |
838 | | /* |
839 | | * |
840 | | */ |
841 | | |
842 | | static struct connection_settings smtp_server_connection_set = { |
843 | | .input_max_size = SIZE_MAX, |
844 | | .output_max_size = SIZE_MAX, |
845 | | .client = FALSE, |
846 | | .log_connection_id = TRUE, |
847 | | }; |
848 | | |
849 | | static const struct connection_vfuncs smtp_server_connection_vfuncs = { |
850 | | .destroy = smtp_server_connection_destroy, |
851 | | .input = smtp_server_connection_input, |
852 | | }; |
853 | | |
854 | | struct connection_list *smtp_server_connection_list_init(void) |
855 | 6.06k | { |
856 | 6.06k | return connection_list_init(&smtp_server_connection_set, |
857 | 6.06k | &smtp_server_connection_vfuncs); |
858 | 6.06k | } |
859 | | |
860 | | static struct event * |
861 | | smtp_server_connection_event_create(struct smtp_server *server, |
862 | | const struct smtp_server_settings *set) |
863 | 6.06k | { |
864 | 6.06k | struct event *conn_event; |
865 | | |
866 | 6.06k | if (set != NULL && set->event_parent != NULL) { |
867 | 0 | conn_event = event_create(set->event_parent); |
868 | 0 | smtp_server_event_init(server, conn_event); |
869 | 0 | } else |
870 | 6.06k | conn_event = event_create(server->event); |
871 | 6.06k | event_set_append_log_prefix(conn_event, t_strdup_printf( |
872 | 6.06k | "%s-server: ", smtp_protocol_name(server->set.protocol))); |
873 | 6.06k | event_set_forced_debug(conn_event, (set != NULL && set->debug)); |
874 | | |
875 | 6.06k | return conn_event; |
876 | 6.06k | } |
877 | | |
878 | | static void |
879 | | smtp_server_connection_update_event(struct smtp_server_connection *conn) |
880 | 6.06k | { |
881 | 6.06k | event_add_str(conn->event, "connection_id", conn->session_id); |
882 | 6.06k | event_add_str(conn->event, "session", conn->session_id); |
883 | 6.06k | } |
884 | | |
885 | | static void |
886 | | smtp_server_connection_init_session(struct smtp_server_connection *conn) |
887 | 6.06k | { |
888 | 6.06k | guid_128_t guid; |
889 | 6.06k | string_t *session_id; |
890 | | |
891 | 6.06k | session_id = t_str_new(30); |
892 | 6.06k | guid_128_generate(guid); |
893 | 6.06k | base64_encode(guid, sizeof(guid), session_id); |
894 | | |
895 | | /* drop trailing "==" */ |
896 | 6.06k | i_assert(str_c(session_id)[str_len(session_id)-2] == '='); |
897 | 6.06k | str_truncate(session_id, str_len(session_id)-2); |
898 | | |
899 | 6.06k | conn->session_id = i_strdup(str_c(session_id)); |
900 | 6.06k | } |
901 | | |
902 | | static struct smtp_server_connection * ATTR_NULL(5, 6) |
903 | | smtp_server_connection_alloc(struct smtp_server *server, |
904 | | const struct smtp_server_settings *set, |
905 | | int fd_in, int fd_out, |
906 | | const struct smtp_server_callbacks *callbacks, |
907 | | void *context) |
908 | 6.06k | { |
909 | 6.06k | struct smtp_server_connection *conn; |
910 | 6.06k | pool_t pool; |
911 | | |
912 | 6.06k | pool = pool_alloconly_create("smtp server", 2048); |
913 | 6.06k | conn = p_new(pool, struct smtp_server_connection, 1); |
914 | 6.06k | conn->pool = pool; |
915 | 6.06k | conn->refcount = 1; |
916 | 6.06k | conn->server = server; |
917 | 6.06k | conn->callbacks = callbacks; |
918 | 6.06k | conn->context = context; |
919 | | |
920 | | /* Merge settings with global server settings */ |
921 | 6.06k | conn->set = server->set; |
922 | 6.06k | if (set != NULL) { |
923 | 0 | conn->set.protocol = server->set.protocol; |
924 | 0 | if (set->rawlog_dir != NULL && *set->rawlog_dir != '\0') |
925 | 0 | conn->set.rawlog_dir = p_strdup(pool, set->rawlog_dir); |
926 | |
|
927 | 0 | if (set->ssl != NULL) { |
928 | 0 | conn->set.ssl = set->ssl; |
929 | 0 | pool_ref(conn->set.ssl->pool); |
930 | 0 | } |
931 | |
|
932 | 0 | if (set->hostname != NULL && *set->hostname != '\0') |
933 | 0 | conn->set.hostname = p_strdup(pool, set->hostname); |
934 | 0 | if (set->login_greeting != NULL && |
935 | 0 | *set->login_greeting != '\0') { |
936 | 0 | conn->set.login_greeting = |
937 | 0 | p_strdup(pool, set->login_greeting); |
938 | 0 | } |
939 | 0 | if (set->capabilities != 0) |
940 | 0 | conn->set.capabilities = set->capabilities; |
941 | 0 | conn->set.workarounds |= set->workarounds; |
942 | |
|
943 | 0 | if (set->max_client_idle_time_msecs > 0) { |
944 | 0 | conn->set.max_client_idle_time_msecs = |
945 | 0 | set->max_client_idle_time_msecs; |
946 | 0 | } |
947 | 0 | if (set->max_pipelined_commands > 0) { |
948 | 0 | conn->set.max_pipelined_commands = |
949 | 0 | set->max_pipelined_commands; |
950 | 0 | } |
951 | 0 | if (set->max_bad_commands > 0) { |
952 | 0 | conn->set.max_bad_commands = set->max_bad_commands; |
953 | 0 | } |
954 | 0 | conn->set.max_recipients = set->max_recipients; |
955 | 0 | i_assert(server->set.max_recipients != 0); |
956 | 0 | smtp_command_limits_merge(&conn->set.command_limits, |
957 | 0 | &set->command_limits); |
958 | |
|
959 | 0 | conn->set.max_message_size = set->max_message_size; |
960 | 0 | if (set->max_message_size == 0 || |
961 | 0 | set->max_message_size == UOFF_T_MAX) { |
962 | 0 | conn->set.command_limits.max_data_size = UOFF_T_MAX; |
963 | 0 | } else if (conn->set.command_limits.max_data_size != 0) { |
964 | | /* Explicit limit given */ |
965 | 0 | } else if (set->max_message_size > |
966 | 0 | (UOFF_T_MAX - SMTP_SERVER_DEFAULT_MAX_SIZE_EXCESS_LIMIT)) { |
967 | | /* Very high limit */ |
968 | 0 | conn->set.command_limits.max_data_size = UOFF_T_MAX; |
969 | 0 | } else { |
970 | | /* Absolute maximum before connection is closed in DATA |
971 | | command */ |
972 | 0 | conn->set.command_limits.max_data_size = |
973 | 0 | set->max_message_size + |
974 | 0 | SMTP_SERVER_DEFAULT_MAX_SIZE_EXCESS_LIMIT; |
975 | 0 | } |
976 | |
|
977 | 0 | if (set->mail_param_extensions != NULL) { |
978 | 0 | conn->set.mail_param_extensions = |
979 | 0 | p_strarray_dup(pool, set->mail_param_extensions); |
980 | 0 | } |
981 | 0 | if (set->rcpt_param_extensions != NULL) { |
982 | 0 | conn->set.rcpt_param_extensions = |
983 | 0 | p_strarray_dup(pool, set->rcpt_param_extensions); |
984 | 0 | } |
985 | 0 | if (set->xclient_extensions != NULL) { |
986 | 0 | conn->set.xclient_extensions = |
987 | 0 | p_strarray_dup(pool, set->xclient_extensions); |
988 | 0 | } |
989 | |
|
990 | 0 | if (set->socket_send_buffer_size > 0) { |
991 | 0 | conn->set.socket_send_buffer_size = |
992 | 0 | set->socket_send_buffer_size; |
993 | 0 | } |
994 | 0 | if (set->socket_recv_buffer_size > 0) { |
995 | 0 | conn->set.socket_recv_buffer_size = |
996 | 0 | set->socket_recv_buffer_size; |
997 | 0 | } |
998 | |
|
999 | 0 | conn->set.tls_required = |
1000 | 0 | conn->set.tls_required || set->tls_required; |
1001 | 0 | conn->set.auth_optional = |
1002 | 0 | conn->set.auth_optional || set->auth_optional; |
1003 | 0 | conn->set.mail_path_allow_broken = |
1004 | 0 | conn->set.mail_path_allow_broken || |
1005 | 0 | set->mail_path_allow_broken; |
1006 | 0 | conn->set.rcpt_domain_optional = |
1007 | 0 | conn->set.rcpt_domain_optional || |
1008 | 0 | set->rcpt_domain_optional; |
1009 | 0 | conn->set.no_greeting = |
1010 | 0 | conn->set.no_greeting || set->no_greeting; |
1011 | 0 | conn->set.debug = conn->set.debug || set->debug; |
1012 | 0 | } |
1013 | | |
1014 | 6.06k | if (set != NULL && set->mail_param_extensions != NULL) { |
1015 | 0 | const char *const *extp; |
1016 | |
|
1017 | 0 | p_array_init(&conn->mail_param_extensions, pool, |
1018 | 0 | str_array_length(set->mail_param_extensions) + 8); |
1019 | 0 | for (extp = set->mail_param_extensions; *extp != NULL; extp++) { |
1020 | 0 | const char *ext = p_strdup(pool, *extp); |
1021 | 0 | array_push_back(&conn->mail_param_extensions, &ext); |
1022 | 0 | } |
1023 | 0 | array_append_zero(&conn->mail_param_extensions); |
1024 | 0 | } |
1025 | 6.06k | if (set != NULL && set->rcpt_param_extensions != NULL) { |
1026 | 0 | const char *const *extp; |
1027 | |
|
1028 | 0 | p_array_init(&conn->rcpt_param_extensions, pool, |
1029 | 0 | str_array_length(set->rcpt_param_extensions) + 8); |
1030 | 0 | for (extp = set->rcpt_param_extensions; *extp != NULL; extp++) { |
1031 | 0 | const char *ext = p_strdup(pool, *extp); |
1032 | 0 | array_push_back(&conn->rcpt_param_extensions, &ext); |
1033 | 0 | } |
1034 | 0 | array_append_zero(&conn->rcpt_param_extensions); |
1035 | 0 | } |
1036 | | |
1037 | 6.06k | net_set_nonblock(fd_in, TRUE); |
1038 | 6.06k | if (fd_in != fd_out) |
1039 | 0 | net_set_nonblock(fd_out, TRUE); |
1040 | 6.06k | (void)net_set_tcp_nodelay(fd_out, TRUE); |
1041 | | |
1042 | 6.06k | set = &conn->set; |
1043 | 6.06k | if (set->socket_send_buffer_size > 0 && |
1044 | 0 | net_set_send_buffer_size(fd_out, |
1045 | 0 | set->socket_send_buffer_size) < 0) { |
1046 | 0 | e_error(conn->event, |
1047 | 0 | "net_set_send_buffer_size(%zu) failed: %m", |
1048 | 0 | set->socket_send_buffer_size); |
1049 | 0 | } |
1050 | 6.06k | if (set->socket_recv_buffer_size > 0 && |
1051 | 0 | net_set_recv_buffer_size(fd_in, |
1052 | 0 | set->socket_recv_buffer_size) < 0) { |
1053 | 0 | e_error(conn->event, |
1054 | 0 | "net_set_recv_buffer_size(%zu) failed: %m", |
1055 | 0 | set->socket_recv_buffer_size); |
1056 | 0 | } |
1057 | | |
1058 | 6.06k | smtp_server_connection_init_session(conn); |
1059 | | |
1060 | 6.06k | return conn; |
1061 | 6.06k | } |
1062 | | |
1063 | | static void smtp_server_connection_created(struct smtp_server_connection *conn) |
1064 | 6.06k | { |
1065 | 6.06k | conn->raw_input = conn->conn.input; |
1066 | 6.06k | conn->raw_output = conn->conn.output; |
1067 | | |
1068 | | /* Halt input until started */ |
1069 | 6.06k | smtp_server_connection_halt(conn); |
1070 | | |
1071 | 6.06k | e_debug(conn->event, "Connection created"); |
1072 | 6.06k | } |
1073 | | |
1074 | | struct smtp_server_connection * |
1075 | | smtp_server_connection_create( |
1076 | | struct smtp_server *server, int fd_in, int fd_out, |
1077 | | const struct ip_addr *local_ip, in_port_t local_port, |
1078 | | const struct ip_addr *remote_ip, in_port_t remote_port, |
1079 | | bool ssl_start, const struct smtp_server_settings *set, |
1080 | | const struct smtp_server_callbacks *callbacks, void *context) |
1081 | 6.06k | { |
1082 | 6.06k | struct smtp_server_connection *conn; |
1083 | 6.06k | struct event *conn_event; |
1084 | | |
1085 | 6.06k | conn = smtp_server_connection_alloc(server, set, fd_in, fd_out, |
1086 | 6.06k | callbacks, context); |
1087 | 6.06k | conn_event = smtp_server_connection_event_create(server, set); |
1088 | 6.06k | conn->conn.event_parent = conn_event; |
1089 | 6.06k | connection_init_server_ip(server->conn_list, &conn->conn, NULL, |
1090 | 6.06k | fd_in, fd_out, remote_ip, remote_port); |
1091 | 6.06k | if (local_ip != NULL && local_ip->family != 0) |
1092 | 0 | conn->conn.local_ip = *local_ip; |
1093 | 6.06k | conn->conn.local_port = local_port; |
1094 | 6.06k | conn->event = conn->conn.event; |
1095 | 6.06k | smtp_server_connection_update_event(conn); |
1096 | 6.06k | event_unref(&conn_event); |
1097 | | |
1098 | 6.06k | conn->ssl_start = ssl_start; |
1099 | 6.06k | if (ssl_start) |
1100 | 0 | conn->set.capabilities &= ENUM_NEGATE(SMTP_CAPABILITY_STARTTLS); |
1101 | | |
1102 | 6.06k | smtp_server_connection_created(conn); |
1103 | | |
1104 | 6.06k | return conn; |
1105 | 6.06k | } |
1106 | | |
1107 | | struct smtp_server_connection * |
1108 | | smtp_server_connection_create_from_streams( |
1109 | | struct smtp_server *server, |
1110 | | struct istream *input, struct ostream *output, |
1111 | | const struct ip_addr *local_ip, in_port_t local_port, |
1112 | | const struct ip_addr *remote_ip, in_port_t remote_port, |
1113 | | const struct smtp_server_settings *set, |
1114 | | const struct smtp_server_callbacks *callbacks, void *context) |
1115 | 0 | { |
1116 | 0 | struct smtp_server_connection *conn; |
1117 | 0 | struct event *conn_event; |
1118 | 0 | int fd_in, fd_out; |
1119 | |
|
1120 | 0 | fd_in = i_stream_get_fd(input); |
1121 | 0 | fd_out = o_stream_get_fd(output); |
1122 | 0 | i_assert(fd_in >= 0); |
1123 | 0 | i_assert(fd_out >= 0); |
1124 | | |
1125 | 0 | conn = smtp_server_connection_alloc(server, set, fd_in, fd_out, |
1126 | 0 | callbacks, context); |
1127 | 0 | if (local_ip != NULL && local_ip->family != 0) |
1128 | 0 | conn->conn.local_ip = *local_ip; |
1129 | 0 | conn->conn.local_port = local_port; |
1130 | 0 | if (remote_ip != NULL && remote_ip->family != 0) |
1131 | 0 | conn->conn.remote_ip = *remote_ip; |
1132 | 0 | if (remote_port != 0) |
1133 | 0 | conn->conn.remote_port = remote_port; |
1134 | 0 | conn_event = smtp_server_connection_event_create(server, set); |
1135 | 0 | conn->conn.event_parent = conn_event; |
1136 | 0 | connection_init_from_streams(server->conn_list, &conn->conn, NULL, |
1137 | 0 | input, output); |
1138 | 0 | conn->created_from_streams = TRUE; |
1139 | 0 | conn->event = conn->conn.event; |
1140 | 0 | smtp_server_connection_update_event(conn); |
1141 | 0 | event_unref(&conn_event); |
1142 | |
|
1143 | 0 | smtp_server_connection_created(conn); |
1144 | |
|
1145 | 0 | return conn; |
1146 | 0 | } |
1147 | | |
1148 | | void smtp_server_connection_ref(struct smtp_server_connection *conn) |
1149 | 275k | { |
1150 | 275k | conn->refcount++; |
1151 | 275k | } |
1152 | | |
1153 | | static const char * |
1154 | | smtp_server_connection_get_disconnect_reason( |
1155 | | struct smtp_server_connection *conn) |
1156 | 3.60k | { |
1157 | 3.60k | const char *err; |
1158 | | |
1159 | 3.60k | if (conn->ssl_iostream != NULL && |
1160 | 0 | !ssl_iostream_is_handshaked(conn->ssl_iostream)) { |
1161 | 0 | err = ssl_iostream_get_last_error(conn->ssl_iostream); |
1162 | 0 | if (err != NULL) { |
1163 | 0 | return t_strdup_printf( |
1164 | 0 | "TLS handshaking failed: %s", err); |
1165 | 0 | } |
1166 | 0 | } |
1167 | | |
1168 | 3.60k | return io_stream_get_disconnect_reason(conn->conn.input, |
1169 | 3.60k | conn->conn.output); |
1170 | 3.60k | } |
1171 | | |
1172 | | static void |
1173 | | smtp_server_connection_disconnect(struct smtp_server_connection *conn, |
1174 | | const char *reason) |
1175 | 12.1k | { |
1176 | 12.1k | struct smtp_server_command *cmd, *cmd_next; |
1177 | | |
1178 | 12.1k | if (conn->disconnected) |
1179 | 6.06k | return; |
1180 | 6.06k | conn->disconnected = TRUE; |
1181 | | |
1182 | 6.06k | if (reason == NULL) |
1183 | 3.60k | reason = smtp_server_connection_get_disconnect_reason(conn); |
1184 | 2.46k | else |
1185 | 2.46k | reason = t_str_oneline(reason); |
1186 | | |
1187 | 6.06k | cmd = conn->command_queue_head; |
1188 | 6.06k | if (cmd != NULL && cmd->reg != NULL) { |
1189 | | /* Unfinished command - include it in the reason string */ |
1190 | 981 | reason = t_strdup_printf("%s (unfinished %s command)", |
1191 | 981 | reason, cmd->reg->name); |
1192 | 981 | } |
1193 | 6.06k | if (!conn->set.no_state_in_reason) { |
1194 | 6.06k | reason = t_strdup_printf("%s (state=%s)", reason, |
1195 | 6.06k | smtp_server_state_names[conn->state.state]); |
1196 | 6.06k | } |
1197 | | |
1198 | 6.06k | e_debug(conn->event, "Disconnected: %s", reason); |
1199 | | |
1200 | | /* Preserve statistics */ |
1201 | 6.06k | smtp_server_connection_update_stats(conn); |
1202 | | |
1203 | | /* Drop transaction */ |
1204 | 6.06k | smtp_server_connection_reset_state(conn); |
1205 | | |
1206 | | /* Clear command queue */ |
1207 | 6.06k | cmd = conn->command_queue_head; |
1208 | 9.92k | while (cmd != NULL) { |
1209 | 3.86k | cmd_next = cmd->next; |
1210 | 3.86k | smtp_server_command_abort(&cmd); |
1211 | 3.86k | cmd = cmd_next; |
1212 | 3.86k | } |
1213 | | |
1214 | 6.06k | smtp_server_connection_timeout_stop(conn); |
1215 | 6.06k | if (conn->conn.output != NULL) |
1216 | 6.06k | o_stream_uncork(conn->conn.output); |
1217 | 6.06k | if (conn->smtp_parser != NULL) |
1218 | 6.06k | smtp_command_parser_deinit(&conn->smtp_parser); |
1219 | 6.06k | ssl_iostream_destroy(&conn->ssl_iostream); |
1220 | 6.06k | settings_free(conn->set.ssl); |
1221 | | |
1222 | 6.06k | if (conn->callbacks != NULL && |
1223 | 6.06k | conn->callbacks->conn_disconnect != NULL) { |
1224 | | /* The callback may close the fd, so remove IO before that */ |
1225 | 0 | io_remove(&conn->conn.io); |
1226 | 0 | conn->callbacks->conn_disconnect(conn->context, reason); |
1227 | 0 | } |
1228 | | |
1229 | 6.06k | if (!conn->created_from_streams) |
1230 | 6.06k | connection_disconnect(&conn->conn); |
1231 | 0 | else { |
1232 | 0 | conn->conn.fd_in = conn->conn.fd_out = -1; |
1233 | 0 | io_remove(&conn->conn.io); |
1234 | 0 | i_stream_unref(&conn->conn.input); |
1235 | 0 | o_stream_unref(&conn->conn.output); |
1236 | 0 | } |
1237 | 6.06k | } |
1238 | | |
1239 | | bool smtp_server_connection_unref(struct smtp_server_connection **_conn) |
1240 | 281k | { |
1241 | 281k | struct smtp_server_connection *conn = *_conn; |
1242 | | |
1243 | 281k | *_conn = NULL; |
1244 | | |
1245 | 281k | i_assert(conn->refcount > 0); |
1246 | 281k | if (--conn->refcount > 0) |
1247 | 275k | return TRUE; |
1248 | | |
1249 | 6.06k | smtp_server_connection_disconnect(conn, NULL); |
1250 | | |
1251 | 6.06k | e_debug(conn->event, "Connection destroy"); |
1252 | | |
1253 | 6.06k | connection_deinit(&conn->conn); |
1254 | | |
1255 | 6.06k | if (conn->callbacks != NULL && conn->callbacks->conn_free != NULL) |
1256 | 6.06k | conn->callbacks->conn_free(conn->context); |
1257 | | |
1258 | 6.06k | i_free(conn->proxy_helo); |
1259 | 6.06k | i_free(conn->helo_domain); |
1260 | 6.06k | i_free(conn->username); |
1261 | 6.06k | i_free(conn->session_id); |
1262 | 6.06k | i_free(conn->client_transport); |
1263 | 6.06k | i_free(conn->local_name); |
1264 | 6.06k | event_unref(&conn->next_trans_event); |
1265 | 6.06k | pool_unref(&conn->pool); |
1266 | 6.06k | return FALSE; |
1267 | 281k | } |
1268 | | |
1269 | | void smtp_server_connection_send_line(struct smtp_server_connection *conn, |
1270 | | const char *fmt, ...) |
1271 | 6.06k | { |
1272 | 6.06k | va_list args; |
1273 | | |
1274 | 6.06k | va_start(args, fmt); |
1275 | | |
1276 | 6.06k | T_BEGIN { |
1277 | 6.06k | string_t *str; |
1278 | | |
1279 | 6.06k | str = t_str_new(256); |
1280 | 6.06k | str_vprintfa(str, fmt, args); |
1281 | | |
1282 | 6.06k | e_debug(conn->event, "Sent: %s", str_c(str)); |
1283 | | |
1284 | 6.06k | str_append(str, "\r\n"); |
1285 | 6.06k | o_stream_nsend(conn->conn.output, str_data(str), str_len(str)); |
1286 | 6.06k | } T_END; |
1287 | 6.06k | va_end(args); |
1288 | 6.06k | } |
1289 | | |
1290 | | void smtp_server_connection_reply_lines(struct smtp_server_connection *conn, |
1291 | | unsigned int status, |
1292 | | const char *enh_code, |
1293 | | const char *const *text_lines) |
1294 | 258 | { |
1295 | 258 | struct smtp_reply reply; |
1296 | | |
1297 | 258 | i_zero(&reply); |
1298 | 258 | reply.status = status; |
1299 | 258 | reply.text_lines = text_lines; |
1300 | | |
1301 | 258 | if (!smtp_reply_parse_enhanced_code( |
1302 | 258 | enh_code, &reply.enhanced_code, NULL)) |
1303 | 0 | reply.enhanced_code = SMTP_REPLY_ENH_CODE(status / 100, 0, 0); |
1304 | | |
1305 | 258 | T_BEGIN { |
1306 | 258 | string_t *str; |
1307 | | |
1308 | 258 | e_debug(conn->event, "Sent: %s", smtp_reply_log(&reply)); |
1309 | | |
1310 | 258 | str = t_str_new(256); |
1311 | 258 | smtp_reply_write(str, &reply); |
1312 | 258 | o_stream_nsend(conn->conn.output, str_data(str), str_len(str)); |
1313 | 258 | } T_END; |
1314 | 258 | } |
1315 | | |
1316 | | void smtp_server_connection_reply_immediate( |
1317 | | struct smtp_server_connection *conn, |
1318 | | unsigned int status, const char *fmt, ...) |
1319 | 1.50k | { |
1320 | 1.50k | va_list args; |
1321 | | |
1322 | 1.50k | va_start(args, fmt); |
1323 | 1.50k | T_BEGIN { |
1324 | 1.50k | string_t *str; |
1325 | | |
1326 | 1.50k | str = t_str_new(256); |
1327 | 1.50k | str_printfa(str, "%03u ", status); |
1328 | 1.50k | str_vprintfa(str, fmt, args); |
1329 | | |
1330 | 1.50k | e_debug(conn->event, "Sent: %s", str_c(str)); |
1331 | | |
1332 | 1.50k | str_append(str, "\r\n"); |
1333 | 1.50k | o_stream_nsend(conn->conn.output, str_data(str), str_len(str)); |
1334 | 1.50k | } T_END; |
1335 | 1.50k | va_end(args); |
1336 | | |
1337 | | /* Send immediately */ |
1338 | 1.50k | if (o_stream_is_corked(conn->conn.output)) { |
1339 | 1.47k | o_stream_uncork(conn->conn.output); |
1340 | 1.47k | o_stream_cork(conn->conn.output); |
1341 | 1.47k | } |
1342 | 1.50k | } |
1343 | | |
1344 | | void smtp_server_connection_login(struct smtp_server_connection *conn, |
1345 | | const char *username, const char *helo, |
1346 | | const unsigned char *pdata, |
1347 | | unsigned int pdata_len, bool ssl_secured) |
1348 | 0 | { |
1349 | 0 | i_assert(!conn->started); |
1350 | | |
1351 | 0 | conn->set.capabilities &= ENUM_NEGATE(SMTP_CAPABILITY_STARTTLS); |
1352 | 0 | i_free(conn->username); |
1353 | 0 | conn->username = i_strdup(username); |
1354 | 0 | if (helo != NULL && *helo != '\0') { |
1355 | 0 | i_free(conn->helo_domain); |
1356 | 0 | conn->helo_domain = i_strdup(helo); |
1357 | 0 | conn->helo.domain = conn->helo_domain; |
1358 | 0 | conn->helo.domain_valid = TRUE; |
1359 | 0 | } |
1360 | 0 | conn->authenticated = TRUE; |
1361 | 0 | conn->ssl_secured = ssl_secured; |
1362 | |
|
1363 | 0 | if (pdata_len > 0) { |
1364 | 0 | if (!i_stream_add_data(conn->conn.input, pdata, pdata_len)) |
1365 | 0 | i_panic("Couldn't add client input to stream"); |
1366 | 0 | } |
1367 | 0 | } |
1368 | | |
1369 | | void smtp_server_connection_start_pending(struct smtp_server_connection *conn) |
1370 | 6.06k | { |
1371 | 6.06k | i_assert(!conn->started); |
1372 | 6.06k | conn->started = TRUE; |
1373 | | |
1374 | 6.06k | e_debug(conn->event, "Connection started"); |
1375 | | |
1376 | 6.06k | if (!conn->ssl_start) |
1377 | 6.06k | smtp_server_connection_ready(conn); |
1378 | 0 | else if (conn->ssl_iostream == NULL) |
1379 | 0 | smtp_server_connection_input_unlock(conn); |
1380 | 6.06k | } |
1381 | | |
1382 | | void smtp_server_connection_start(struct smtp_server_connection *conn) |
1383 | 6.06k | { |
1384 | 6.06k | smtp_server_connection_start_pending(conn); |
1385 | 6.06k | smtp_server_connection_resume(conn); |
1386 | 6.06k | } |
1387 | | |
1388 | | void smtp_server_connection_abort(struct smtp_server_connection **_conn, |
1389 | | unsigned int status, const char *enh_code, |
1390 | | const char *reason) |
1391 | 0 | { |
1392 | 0 | struct smtp_server_connection *conn = *_conn; |
1393 | 0 | const char **reason_lines; |
1394 | |
|
1395 | 0 | if (conn == NULL) |
1396 | 0 | return; |
1397 | 0 | *_conn = NULL; |
1398 | |
|
1399 | 0 | i_assert(!conn->started); |
1400 | 0 | conn->started = TRUE; |
1401 | |
|
1402 | 0 | if (conn->authenticated) { |
1403 | 0 | reason_lines = t_strsplit_spaces(reason, "\r\n"); |
1404 | 0 | smtp_server_connection_reply_lines( |
1405 | 0 | conn, status, enh_code, reason_lines); |
1406 | 0 | smtp_server_connection_terminate( |
1407 | 0 | &conn, "4.3.2", "Shutting down due to fatal error"); |
1408 | 0 | } else { |
1409 | 0 | smtp_server_connection_terminate(&conn, enh_code, reason); |
1410 | 0 | } |
1411 | 0 | } |
1412 | | |
1413 | | void smtp_server_connection_halt(struct smtp_server_connection *conn) |
1414 | 6.06k | { |
1415 | 6.06k | conn->halted = TRUE; |
1416 | 6.06k | smtp_server_connection_timeout_stop(conn); |
1417 | 6.06k | if (conn->ssl_start && |
1418 | 0 | (conn->ssl_iostream == NULL || |
1419 | 0 | !ssl_iostream_is_handshaked(conn->ssl_iostream))) |
1420 | 0 | return; |
1421 | | |
1422 | 6.06k | smtp_server_connection_input_lock(conn); |
1423 | 6.06k | } |
1424 | | |
1425 | | void smtp_server_connection_resume(struct smtp_server_connection *conn) |
1426 | 6.06k | { |
1427 | 6.06k | smtp_server_connection_input_unlock(conn); |
1428 | 6.06k | smtp_server_connection_timeout_update(conn); |
1429 | 6.06k | conn->halted = FALSE; |
1430 | 6.06k | } |
1431 | | |
1432 | | void smtp_server_connection_close(struct smtp_server_connection **_conn, |
1433 | | const char *reason) |
1434 | 4.87k | { |
1435 | 4.87k | struct smtp_server_connection *conn = *_conn; |
1436 | | |
1437 | 4.87k | *_conn = NULL; |
1438 | | |
1439 | 4.87k | if (conn->closed) |
1440 | 2.40k | return; |
1441 | 2.46k | conn->closed = TRUE; |
1442 | | |
1443 | 2.46k | smtp_server_connection_disconnect(conn, reason); |
1444 | 2.46k | smtp_server_connection_unref(&conn); |
1445 | 2.46k | } |
1446 | | |
1447 | | void smtp_server_connection_terminate(struct smtp_server_connection **_conn, |
1448 | | const char *enh_code, const char *reason) |
1449 | 258 | { |
1450 | 258 | smtp_server_connection_terminate_full(_conn, enh_code, reason, reason); |
1451 | 258 | } |
1452 | | |
1453 | | void smtp_server_connection_terminate_full( |
1454 | | struct smtp_server_connection **_conn, const char *enh_code, |
1455 | | const char *reply_reason, const char *log_reason) |
1456 | 258 | { |
1457 | 258 | struct smtp_server_connection *conn = *_conn; |
1458 | 258 | const char **reason_lines; |
1459 | | |
1460 | 258 | *_conn = NULL; |
1461 | | |
1462 | 258 | if (conn->closed) |
1463 | 0 | return; |
1464 | | |
1465 | 258 | i_assert(enh_code[0] == '4' && enh_code[1] == '.'); |
1466 | | |
1467 | 258 | T_BEGIN { |
1468 | | /* Add hostname prefix */ |
1469 | 258 | reason_lines = t_strsplit_spaces(reply_reason, "\r\n"); |
1470 | 258 | reason_lines[0] = t_strconcat(conn->set.hostname, " ", |
1471 | 258 | reason_lines[0], NULL); |
1472 | | |
1473 | 258 | smtp_server_connection_reply_lines(conn, 421, enh_code, |
1474 | 258 | reason_lines); |
1475 | | |
1476 | 258 | smtp_server_connection_close(&conn, log_reason); |
1477 | 258 | } T_END; |
1478 | 258 | } |
1479 | | |
1480 | | struct smtp_server_helo_data * |
1481 | | smtp_server_connection_get_helo_data(struct smtp_server_connection *conn) |
1482 | 0 | { |
1483 | 0 | return &conn->helo; |
1484 | 0 | } |
1485 | | |
1486 | | enum smtp_server_state |
1487 | | smtp_server_connection_get_state(struct smtp_server_connection *conn, |
1488 | | const char **args_r) |
1489 | 0 | { |
1490 | 0 | if (args_r != NULL) |
1491 | 0 | *args_r = conn->state.args; |
1492 | 0 | return conn->state.state; |
1493 | 0 | } |
1494 | | |
1495 | | void smtp_server_connection_set_state(struct smtp_server_connection *conn, |
1496 | | enum smtp_server_state state, |
1497 | | const char *args) |
1498 | 54.1k | { |
1499 | 54.1k | bool changed = FALSE; |
1500 | | |
1501 | 54.1k | if (conn->state.state != state) { |
1502 | 31.0k | conn->state.state = state; |
1503 | 31.0k | changed = TRUE; |
1504 | 31.0k | } |
1505 | 54.1k | if (null_strcmp(args, conn->state.args) != 0) { |
1506 | 13.2k | i_free(conn->state.args); |
1507 | 13.2k | conn->state.args = i_strdup(args); |
1508 | 13.2k | changed = TRUE; |
1509 | 13.2k | } |
1510 | | |
1511 | 54.1k | if (changed && conn->callbacks != NULL && |
1512 | 34.2k | conn->callbacks->conn_state_changed != NULL) |
1513 | 0 | conn->callbacks->conn_state_changed(conn->context, state, args); |
1514 | 54.1k | } |
1515 | | |
1516 | | const char * |
1517 | | smtp_server_connection_get_security_string(struct smtp_server_connection *conn) |
1518 | 0 | { |
1519 | 0 | if (conn->ssl_iostream == NULL) |
1520 | 0 | return NULL; |
1521 | 0 | return ssl_iostream_get_security_string(conn->ssl_iostream); |
1522 | 0 | } |
1523 | | |
1524 | | void smtp_server_connection_reset_state(struct smtp_server_connection *conn) |
1525 | 19.7k | { |
1526 | 19.7k | e_debug(conn->event, "Connection state reset"); |
1527 | | |
1528 | 19.7k | i_free(conn->state.args); |
1529 | | |
1530 | 19.7k | if (conn->state.trans != NULL) |
1531 | 4.40k | smtp_server_transaction_free(&conn->state.trans); |
1532 | | |
1533 | | /* RFC 3030, Section 2: |
1534 | | The RSET command, when issued after the first BDAT and before the |
1535 | | BDAT LAST, clears all segments sent during that transaction and |
1536 | | resets the session. |
1537 | | */ |
1538 | 19.7k | i_stream_destroy(&conn->state.data_input); |
1539 | 19.7k | i_stream_destroy(&conn->state.data_chain_input); |
1540 | 19.7k | conn->state.data_chain = NULL; |
1541 | | |
1542 | | /* Reset state */ |
1543 | 19.7k | i_zero(&conn->state); |
1544 | 19.7k | smtp_server_connection_set_state(conn, SMTP_SERVER_STATE_READY, NULL); |
1545 | 19.7k | } |
1546 | | |
1547 | | void smtp_server_connection_clear(struct smtp_server_connection *conn) |
1548 | 0 | { |
1549 | 0 | e_debug(conn->event, "Connection clear"); |
1550 | |
|
1551 | 0 | i_free(conn->helo_domain); |
1552 | 0 | i_zero(&conn->helo); |
1553 | 0 | smtp_server_connection_reset_state(conn); |
1554 | 0 | } |
1555 | | |
1556 | | void smtp_server_connection_set_capabilities( |
1557 | | struct smtp_server_connection *conn, enum smtp_capability capabilities) |
1558 | 0 | { |
1559 | 0 | conn->set.capabilities = capabilities; |
1560 | 0 | } |
1561 | | |
1562 | | void smtp_server_connection_set_greeting(struct smtp_server_connection *conn, |
1563 | | const char *greeting) |
1564 | 0 | { |
1565 | 0 | conn->set.login_greeting = p_strdup(conn->pool, greeting); |
1566 | 0 | } |
1567 | | |
1568 | | void smtp_server_connection_add_extra_capability( |
1569 | | struct smtp_server_connection *conn, |
1570 | | const struct smtp_capability_extra *cap) |
1571 | 0 | { |
1572 | 0 | const struct smtp_capability_extra *cap_idx; |
1573 | 0 | struct smtp_capability_extra cap_new; |
1574 | 0 | unsigned int insert_idx; |
1575 | 0 | pool_t pool = conn->pool; |
1576 | | |
1577 | | /* Avoid committing protocol errors */ |
1578 | 0 | i_assert(smtp_ehlo_keyword_is_valid(cap->name)); |
1579 | 0 | i_assert(smtp_ehlo_params_are_valid(cap->params)); |
1580 | | |
1581 | | /* Cannot override standard capabilities */ |
1582 | 0 | i_assert(smtp_capability_find_by_name(cap->name) |
1583 | 0 | == SMTP_CAPABILITY_NONE); |
1584 | | |
1585 | 0 | if (!array_is_created(&conn->extra_capabilities)) |
1586 | 0 | p_array_init(&conn->extra_capabilities, pool, 4); |
1587 | | |
1588 | | /* Keep array sorted */ |
1589 | 0 | insert_idx = array_count(&conn->extra_capabilities); |
1590 | 0 | array_foreach(&conn->extra_capabilities, cap_idx) { |
1591 | 0 | int cmp = strcasecmp(cap_idx->name, cap->name); |
1592 | | |
1593 | | /* Prohibit duplicates */ |
1594 | 0 | i_assert(cmp != 0); |
1595 | | |
1596 | 0 | if (cmp > 0) { |
1597 | 0 | insert_idx = array_foreach_idx( |
1598 | 0 | &conn->extra_capabilities, cap_idx); |
1599 | 0 | break; |
1600 | 0 | } |
1601 | 0 | } |
1602 | | |
1603 | 0 | i_zero(&cap_new); |
1604 | 0 | cap_new.name = p_strdup(pool, cap->name); |
1605 | 0 | if (cap->params != NULL) |
1606 | 0 | cap_new.params = p_strarray_dup(pool, cap->params); |
1607 | |
|
1608 | 0 | array_insert(&conn->extra_capabilities, insert_idx, &cap_new, 1); |
1609 | 0 | } |
1610 | | |
1611 | | void *smtp_server_connection_get_context(struct smtp_server_connection *conn) |
1612 | 0 | { |
1613 | 0 | return conn->context; |
1614 | 0 | } |
1615 | | |
1616 | | bool smtp_server_connection_is_ssl_secured(struct smtp_server_connection *conn) |
1617 | 0 | { |
1618 | 0 | return conn->ssl_secured; |
1619 | 0 | } |
1620 | | |
1621 | | bool smtp_server_connection_is_trusted(struct smtp_server_connection *conn) |
1622 | 6.67k | { |
1623 | 6.67k | if (conn->callbacks == NULL || conn->callbacks->conn_is_trusted == NULL) |
1624 | 6.67k | return FALSE; |
1625 | 0 | return conn->callbacks->conn_is_trusted(conn->context); |
1626 | 6.67k | } |
1627 | | |
1628 | | bool smtp_server_connection_is_started(struct smtp_server_connection *conn) |
1629 | 0 | { |
1630 | 0 | return conn->started; |
1631 | 0 | } |
1632 | | |
1633 | | enum smtp_protocol |
1634 | | smtp_server_connection_get_protocol(struct smtp_server_connection *conn) |
1635 | 0 | { |
1636 | 0 | return conn->set.protocol; |
1637 | 0 | } |
1638 | | |
1639 | | const char * |
1640 | | smtp_server_connection_get_protocol_name(struct smtp_server_connection *conn) |
1641 | 0 | { |
1642 | 0 | string_t *pname = t_str_new(16); |
1643 | |
|
1644 | 0 | switch (conn->set.protocol) { |
1645 | 0 | case SMTP_PROTOCOL_SMTP: |
1646 | 0 | if (conn->helo.old_smtp) |
1647 | 0 | str_append(pname, "SMTP"); |
1648 | 0 | else |
1649 | 0 | str_append(pname, "ESMTP"); |
1650 | 0 | break; |
1651 | 0 | case SMTP_PROTOCOL_LMTP: |
1652 | 0 | str_append(pname, "LMTP"); |
1653 | 0 | break; |
1654 | 0 | default: |
1655 | 0 | i_unreached(); |
1656 | 0 | } |
1657 | 0 | if (conn->ssl_secured) |
1658 | 0 | str_append_c(pname, 'S'); |
1659 | 0 | if (conn->authenticated) |
1660 | 0 | str_append_c(pname, 'A'); |
1661 | 0 | return str_c(pname); |
1662 | 0 | } |
1663 | | |
1664 | | struct smtp_server_transaction * |
1665 | | smtp_server_connection_get_transaction(struct smtp_server_connection *conn) |
1666 | 0 | { |
1667 | 0 | return conn->state.trans; |
1668 | 0 | } |
1669 | | |
1670 | | const char * |
1671 | | smtp_server_connection_get_transaction_id(struct smtp_server_connection *conn) |
1672 | 0 | { |
1673 | 0 | if (conn->state.trans == NULL) |
1674 | 0 | return NULL; |
1675 | 0 | return conn->state.trans->id; |
1676 | 0 | } |
1677 | | |
1678 | | void smtp_server_connection_get_proxy_data(struct smtp_server_connection *conn, |
1679 | | struct smtp_proxy_data *proxy_data) |
1680 | 0 | { |
1681 | 0 | i_zero(proxy_data); |
1682 | 0 | proxy_data->source_ip = conn->conn.remote_ip; |
1683 | 0 | proxy_data->source_port = conn->conn.remote_port; |
1684 | 0 | proxy_data->dest_ip = conn->conn.local_ip; |
1685 | 0 | proxy_data->dest_port = conn->conn.local_port; |
1686 | 0 | if (conn->proxy_helo != NULL) |
1687 | 0 | proxy_data->helo = conn->proxy_helo; |
1688 | 0 | else if (conn->helo.domain_valid) |
1689 | 0 | proxy_data->helo = conn->helo.domain; |
1690 | 0 | proxy_data->login = conn->username; |
1691 | 0 | proxy_data->session = conn->session_id; |
1692 | 0 | proxy_data->client_transport = conn->client_transport; |
1693 | 0 | proxy_data->local_name = conn->local_name; |
1694 | |
|
1695 | 0 | if (conn->proxy_proto != SMTP_PROXY_PROTOCOL_UNKNOWN) |
1696 | 0 | proxy_data->proto = conn->proxy_proto; |
1697 | 0 | else if (conn->set.protocol == SMTP_PROTOCOL_LMTP) |
1698 | 0 | proxy_data->proto = SMTP_PROXY_PROTOCOL_LMTP; |
1699 | 0 | else if (conn->helo.old_smtp) |
1700 | 0 | proxy_data->proto = SMTP_PROXY_PROTOCOL_SMTP; |
1701 | 0 | else |
1702 | 0 | proxy_data->proto = SMTP_PROXY_PROTOCOL_ESMTP; |
1703 | |
|
1704 | 0 | proxy_data->ttl_plus_1 = conn->proxy_ttl_plus_1; |
1705 | 0 | proxy_data->timeout_secs = conn->proxy_timeout_secs; |
1706 | 0 | } |
1707 | | |
1708 | | void smtp_server_connection_set_proxy_data( |
1709 | | struct smtp_server_connection *conn, |
1710 | | const struct smtp_proxy_data *proxy_data) |
1711 | 0 | { |
1712 | 0 | if (proxy_data->source_ip.family != 0) |
1713 | 0 | conn->conn.remote_ip = proxy_data->source_ip; |
1714 | 0 | if (proxy_data->source_port != 0) |
1715 | 0 | conn->conn.remote_port = proxy_data->source_port; |
1716 | 0 | if (proxy_data->helo != NULL) { |
1717 | 0 | i_free(conn->helo_domain); |
1718 | 0 | conn->helo_domain = i_strdup(proxy_data->helo); |
1719 | 0 | conn->helo.domain = conn->helo_domain; |
1720 | 0 | conn->helo.domain_valid = TRUE; |
1721 | 0 | if (conn->helo.domain_valid) { |
1722 | 0 | i_free(conn->proxy_helo); |
1723 | 0 | conn->proxy_helo = i_strdup(proxy_data->helo); |
1724 | 0 | } |
1725 | 0 | } |
1726 | 0 | if (proxy_data->login != NULL) { |
1727 | 0 | i_free(conn->username); |
1728 | 0 | conn->username = i_strdup(proxy_data->login); |
1729 | 0 | } |
1730 | 0 | if (proxy_data->proto != SMTP_PROXY_PROTOCOL_UNKNOWN) |
1731 | 0 | conn->proxy_proto = proxy_data->proto; |
1732 | 0 | if (proxy_data->session != NULL && |
1733 | 0 | strcmp(proxy_data->session, conn->session_id) != 0) { |
1734 | 0 | e_debug(conn->event, "Updated session ID from %s to %s", |
1735 | 0 | conn->session_id, proxy_data->session); |
1736 | 0 | i_free(conn->session_id); |
1737 | 0 | conn->session_id = i_strdup(proxy_data->session); |
1738 | 0 | } |
1739 | 0 | if (proxy_data->client_transport != NULL) { |
1740 | 0 | i_free(conn->client_transport); |
1741 | 0 | conn->client_transport = i_strdup(proxy_data->client_transport); |
1742 | 0 | } |
1743 | 0 | if (proxy_data->local_name != NULL) { |
1744 | 0 | i_free(conn->local_name); |
1745 | 0 | conn->local_name = i_strdup(proxy_data->local_name); |
1746 | 0 | } |
1747 | 0 | if (proxy_data->ttl_plus_1 > 0) |
1748 | 0 | conn->proxy_ttl_plus_1 = proxy_data->ttl_plus_1; |
1749 | 0 | if (conn->proxy_timeout_secs > 0) |
1750 | 0 | conn->proxy_timeout_secs = proxy_data->timeout_secs; |
1751 | |
|
1752 | 0 | connection_update_properties(&conn->conn); |
1753 | 0 | smtp_server_connection_update_event(conn); |
1754 | |
|
1755 | 0 | if (conn->callbacks != NULL && |
1756 | 0 | conn->callbacks->conn_proxy_data_updated != NULL) { |
1757 | 0 | struct smtp_proxy_data full_data; |
1758 | |
|
1759 | 0 | smtp_server_connection_get_proxy_data(conn, &full_data); |
1760 | |
|
1761 | 0 | conn->callbacks-> |
1762 | 0 | conn_proxy_data_updated(conn->context, &full_data); |
1763 | 0 | } |
1764 | 0 | } |
1765 | | |
1766 | | void smtp_server_connection_register_mail_param( |
1767 | | struct smtp_server_connection *conn, const char *param) |
1768 | 0 | { |
1769 | 0 | param = p_strdup(conn->pool, param); |
1770 | |
|
1771 | 0 | if (!array_is_created(&conn->mail_param_extensions)) { |
1772 | 0 | p_array_init(&conn->mail_param_extensions, conn->pool, 8); |
1773 | 0 | array_push_back(&conn->mail_param_extensions, ¶m); |
1774 | 0 | } else { |
1775 | 0 | unsigned int count = array_count(&conn->mail_param_extensions); |
1776 | |
|
1777 | 0 | i_assert(count > 0); |
1778 | 0 | array_idx_set(&conn->mail_param_extensions, |
1779 | 0 | count - 1, ¶m); |
1780 | 0 | } |
1781 | 0 | array_append_zero(&conn->mail_param_extensions); |
1782 | 0 | } |
1783 | | |
1784 | | void smtp_server_connection_register_rcpt_param( |
1785 | | struct smtp_server_connection *conn, const char *param) |
1786 | 0 | { |
1787 | 0 | param = p_strdup(conn->pool, param); |
1788 | |
|
1789 | 0 | if (!array_is_created(&conn->rcpt_param_extensions)) { |
1790 | 0 | p_array_init(&conn->rcpt_param_extensions, conn->pool, 8); |
1791 | 0 | array_push_back(&conn->rcpt_param_extensions, ¶m); |
1792 | 0 | } else { |
1793 | 0 | unsigned int count = array_count(&conn->rcpt_param_extensions); |
1794 | |
|
1795 | 0 | i_assert(count > 0); |
1796 | 0 | array_idx_set(&conn->rcpt_param_extensions, |
1797 | 0 | count - 1, ¶m); |
1798 | 0 | } |
1799 | 0 | array_append_zero(&conn->rcpt_param_extensions); |
1800 | 0 | } |
1801 | | |
1802 | | void smtp_server_connection_switch_ioloop(struct smtp_server_connection *conn) |
1803 | 0 | { |
1804 | 0 | if (conn->to_idle != NULL) |
1805 | 0 | conn->to_idle = io_loop_move_timeout(&conn->to_idle); |
1806 | 0 | connection_switch_ioloop(&conn->conn); |
1807 | 0 | } |
1808 | | |
1809 | | struct event_reason * |
1810 | | smtp_server_connection_reason_begin(struct smtp_server_connection *conn, |
1811 | | const char *name) |
1812 | 23.8k | { |
1813 | 23.8k | if (conn->set.reason_code_module == NULL) |
1814 | 23.8k | return NULL; |
1815 | 0 | const char *reason_code = |
1816 | 0 | event_reason_code(conn->set.reason_code_module, name); |
1817 | 0 | return event_reason_begin(reason_code); |
1818 | 23.8k | } |
1819 | | |
1820 | | const char * |
1821 | | smtp_server_connection_get_server_name(struct smtp_server_connection *conn) |
1822 | 0 | { |
1823 | 0 | if (conn->ssl_iostream == NULL) |
1824 | 0 | return NULL; |
1825 | 0 | return ssl_iostream_get_server_name(conn->ssl_iostream); |
1826 | 0 | } |