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