1 /* Copyright (c) 2010-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "array.h"
5 #include "base64.h"
6 #include "ioloop.h"
7 #include "net.h"
8 #include "istream.h"
9 #include "istream-multiplex.h"
10 #include "ostream.h"
11 #include "ostream-dot.h"
12 #include "str.h"
13 #include "strescape.h"
14 #include "iostream-ssl.h"
15 #include "master-service.h"
16 #include "master-service-settings.h"
17 #include "settings-parser.h"
18 #include "doveadm.h"
19 #include "doveadm-print.h"
20 #include "doveadm-util.h"
21 #include "doveadm-server.h"
22 #include "doveadm-settings.h"
23 #include "server-connection.h"
24 
25 #include <sysexits.h>
26 #include <unistd.h>
27 
28 #define DOVEADM_LOG_CHANNEL_ID 'L'
29 
30 #define MAX_INBUF_SIZE (1024*32)
31 
32 enum server_reply_state {
33 	SERVER_REPLY_STATE_DONE = 0,
34 	SERVER_REPLY_STATE_PRINT,
35 	SERVER_REPLY_STATE_RET
36 };
37 
38 struct server_connection {
39 	struct doveadm_server *server;
40 
41 	pool_t pool;
42 	struct doveadm_settings *set;
43 
44 	int fd;
45 	unsigned int minor;
46 
47 	struct io *io;
48 	struct io *io_log;
49 	struct istream *input;
50 	struct istream *log_input;
51 	struct ostream *output;
52 	struct ssl_iostream *ssl_iostream;
53 
54 	struct istream *cmd_input;
55 	struct ostream *cmd_output;
56 	const char *delayed_cmd;
57 	server_cmd_callback_t *callback;
58 	void *context;
59 
60 	enum server_reply_state state;
61 
62 	bool version_received:1;
63 	bool authenticate_sent:1;
64 	bool authenticated:1;
65 	bool streaming:1;
66 	bool ssl_done:1;
67 };
68 
69 static struct server_connection *printing_conn = NULL;
70 static ARRAY(struct doveadm_server *) print_pending_servers = ARRAY_INIT;
71 
72 static void server_connection_input(struct server_connection *conn);
73 static bool server_connection_input_one(struct server_connection *conn);
74 static int server_connection_init_ssl(struct server_connection *conn,
75 				      const char **error_r);
76 
server_set_print_pending(struct doveadm_server * server)77 static void server_set_print_pending(struct doveadm_server *server)
78 {
79 	struct doveadm_server *pending_server;
80 
81 	if (!array_is_created(&print_pending_servers))
82 		i_array_init(&print_pending_servers, 16);
83 	array_foreach_elem(&print_pending_servers, pending_server) {
84 		if (pending_server == server)
85 			return;
86 	}
87 	array_push_back(&print_pending_servers, &server);
88 }
89 
server_print_connection_released(struct doveadm_server * server)90 static void server_print_connection_released(struct doveadm_server *server)
91 {
92 	struct server_connection *const *conns;
93 	unsigned int i, count;
94 
95 	conns = array_get(&server->connections, &count);
96 	for (i = 0; i < count; i++) {
97 		if (conns[i]->io != NULL)
98 			continue;
99 
100 		conns[i]->io = io_add(conns[i]->fd, IO_READ,
101 				      server_connection_input, conns[i]);
102 		io_set_pending(conns[i]->io);
103 	}
104 }
105 
print_connection_released(void)106 static void print_connection_released(void)
107 {
108 	struct doveadm_server *server;
109 
110 	printing_conn = NULL;
111 	if (!array_is_created(&print_pending_servers))
112 		return;
113 
114 	array_foreach_elem(&print_pending_servers, server)
115 		server_print_connection_released(server);
116 	array_free(&print_pending_servers);
117 }
118 
server_connection_send_cmd_input_more(struct server_connection * conn)119 static int server_connection_send_cmd_input_more(struct server_connection *conn)
120 {
121 	enum ostream_send_istream_result res;
122 	int ret = -1;
123 
124 	/* ostream-dot writes only up to max buffer size, so keep it non-zero */
125 	o_stream_set_max_buffer_size(conn->cmd_output, IO_BLOCK_SIZE);
126 	res = o_stream_send_istream(conn->cmd_output, conn->cmd_input);
127 	o_stream_set_max_buffer_size(conn->cmd_output, SIZE_MAX);
128 
129 	switch (res) {
130 	case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
131 		break;
132 	case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
133 		return 1;
134 	case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
135 		return 0;
136 	case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
137 		i_error("read(%s) failed: %s",
138 			i_stream_get_name(conn->cmd_input),
139 			i_stream_get_error(conn->cmd_input));
140 		break;
141 	case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
142 		i_error("write(%s) failed: %s",
143 			o_stream_get_name(conn->cmd_output),
144 			o_stream_get_error(conn->cmd_output));
145 		break;
146 	}
147 	if (res == OSTREAM_SEND_ISTREAM_RESULT_FINISHED) {
148 		if ((ret = o_stream_finish(conn->cmd_output)) == 0)
149 			return 0;
150 		else if (ret < 0) {
151 			i_error("write(%s) failed: %s",
152 				o_stream_get_name(conn->cmd_output),
153 				o_stream_get_error(conn->cmd_output));
154 		}
155 	}
156 
157 	i_stream_destroy(&conn->cmd_input);
158 	o_stream_destroy(&conn->cmd_output);
159 	return ret;
160 }
161 
server_connection_send_cmd_input(struct server_connection * conn)162 static void server_connection_send_cmd_input(struct server_connection *conn)
163 {
164 	if (conn->cmd_input == NULL)
165 		return;
166 
167 	conn->cmd_output = o_stream_create_dot(conn->output, TRUE);
168 	(void)server_connection_send_cmd_input_more(conn);
169 }
170 
server_connection_output(struct server_connection * conn)171 static int server_connection_output(struct server_connection *conn)
172 {
173 	int ret;
174 
175 	ret = o_stream_flush(conn->output);
176 	if (ret > 0 && conn->cmd_input != NULL && conn->delayed_cmd == NULL)
177 		ret = server_connection_send_cmd_input_more(conn);
178 	if (ret < 0)
179 		server_connection_destroy(&conn);
180 	return ret;
181 }
182 
183 static void
server_connection_callback(struct server_connection * conn,int exit_code,const char * error)184 server_connection_callback(struct server_connection *conn,
185 			   int exit_code, const char *error)
186 {
187 	server_cmd_callback_t *callback = conn->callback;
188 
189 	conn->callback = NULL;
190 	callback(exit_code, error, conn->context);
191 }
192 
stream_data(string_t * str,const unsigned char * data,size_t size)193 static void stream_data(string_t *str, const unsigned char *data, size_t size)
194 {
195 	str_truncate(str, 0);
196 	str_append_tabunescaped(str, data, size);
197 	doveadm_print_stream(str->data, str->used);
198 }
199 
server_flush_field(struct server_connection * conn,string_t * str,const unsigned char * data,size_t size)200 static void server_flush_field(struct server_connection *conn, string_t *str,
201 			       const unsigned char *data, size_t size)
202 {
203 	if (conn->streaming) {
204 		conn->streaming = FALSE;
205 		if (size > 0)
206 			stream_data(str, data, size);
207 		doveadm_print_stream("", 0);
208 	} else {
209 		str_truncate(str, 0);
210 		str_append_tabunescaped(str, data, size);
211 		doveadm_print(str_c(str));
212 	}
213 }
214 
215 static void
server_handle_input(struct server_connection * conn,const unsigned char * data,size_t size)216 server_handle_input(struct server_connection *conn,
217 		    const unsigned char *data, size_t size)
218 {
219 	string_t *str;
220 	size_t i, start;
221 
222 	if (printing_conn == conn) {
223 		/* continue printing */
224 	} else if (printing_conn == NULL) {
225 		printing_conn = conn;
226 	} else {
227 		/* someone else is printing. don't continue until it
228 		   goes away */
229 		server_set_print_pending(conn->server);
230 		io_remove(&conn->io);
231 		return;
232 	}
233 
234 	if (data[size-1] == '\001') {
235 		/* last character is an escape */
236 		size--;
237 	}
238 
239 	str = t_str_new(128);
240 	for (i = start = 0; i < size; i++) {
241 		if (data[i] == '\n') {
242 			if (i != start) {
243 				i_error("doveadm server sent broken print input");
244 				server_connection_destroy(&conn);
245 				return;
246 			}
247 			conn->state = SERVER_REPLY_STATE_RET;
248 			i_stream_skip(conn->input, i + 1);
249 
250 			print_connection_released();
251 			return;
252 		}
253 		if (data[i] == '\t') {
254 			server_flush_field(conn, str, data + start, i - start);
255 			start = i + 1;
256 		}
257 	}
258 	if (start != size) {
259 		conn->streaming = TRUE;
260 		stream_data(str, data + start, size - start);
261 	}
262 	i_stream_skip(conn->input, size);
263 }
264 
server_connection_authenticated(struct server_connection * conn)265 static void server_connection_authenticated(struct server_connection *conn)
266 {
267 	conn->authenticated = TRUE;
268 	if (conn->delayed_cmd != NULL) {
269 		o_stream_nsend_str(conn->output, conn->delayed_cmd);
270 		conn->delayed_cmd = NULL;
271 		server_connection_send_cmd_input(conn);
272 	}
273 }
274 
275 static int
server_connection_authenticate(struct server_connection * conn)276 server_connection_authenticate(struct server_connection *conn)
277 {
278 	string_t *plain = t_str_new(128);
279 	string_t *cmd = t_str_new(128);
280 
281 	if (*conn->set->doveadm_password == '\0') {
282 		i_error("doveadm_password not set, "
283 			"can't authenticate to remote server");
284 		return -1;
285 	}
286 
287 	str_append_c(plain, '\0');
288 	str_append(plain, conn->set->doveadm_username);
289 	str_append_c(plain, '\0');
290 	str_append(plain, conn->set->doveadm_password);
291 
292 	str_append(cmd, "PLAIN\t");
293 	base64_encode(plain->data, plain->used, cmd);
294 	str_append_c(cmd, '\n');
295 
296 	o_stream_nsend(conn->output, cmd->data, cmd->used);
297 	conn->authenticate_sent = TRUE;
298 	return 0;
299 }
300 
server_log_disconnect_error(struct server_connection * conn)301 static void server_log_disconnect_error(struct server_connection *conn)
302 {
303 	const char *error;
304 
305 	error = conn->ssl_iostream == NULL ? NULL :
306 		ssl_iostream_get_last_error(conn->ssl_iostream);
307 	if (error == NULL) {
308 		error = conn->input->stream_errno == 0 ? "EOF" :
309 			strerror(conn->input->stream_errno);
310 	}
311 	i_error("doveadm server disconnected before handshake: %s", error);
312 }
313 
server_connection_print_log(struct server_connection * conn)314 static void server_connection_print_log(struct server_connection *conn)
315 {
316 	const char *line;
317 	struct failure_context ctx;
318 	i_zero(&ctx);
319 
320 	while((line = i_stream_read_next_line(conn->log_input))!=NULL) {
321 		/* skip empty lines */
322 		if (*line == '\0') continue;
323 
324 		if (!doveadm_log_type_from_char(line[0], &ctx.type))
325 			i_warning("Doveadm server sent invalid log type 0x%02x",
326 				  line[0]);
327 		line++;
328 		i_log_type(&ctx, "remote(%s): %s", conn->server->name, line);
329 	}
330 }
331 
server_connection_start_multiplex(struct server_connection * conn)332 static void server_connection_start_multiplex(struct server_connection *conn)
333 {
334 	struct istream *is = conn->input;
335 	conn->input = i_stream_create_multiplex(is, MAX_INBUF_SIZE);
336 	i_stream_unref(&is);
337 	io_remove(&conn->io);
338 	conn->io = io_add_istream(conn->input, server_connection_input, conn);
339 	conn->log_input = i_stream_multiplex_add_channel(conn->input, DOVEADM_LOG_CHANNEL_ID);
340 	conn->io_log = io_add_istream(conn->log_input, server_connection_print_log, conn);
341 	i_stream_set_return_partial_line(conn->log_input, TRUE);
342 }
343 
server_connection_input(struct server_connection * conn)344 static void server_connection_input(struct server_connection *conn)
345 {
346 	const char *line;
347 	const char *error;
348 
349 	if (i_stream_read(conn->input) < 0) {
350 		/* disconnected */
351 		server_log_disconnect_error(conn);
352 		server_connection_destroy(&conn);
353 		return;
354 	}
355 
356 	while (!conn->authenticated) {
357 		if ((line = i_stream_next_line(conn->input)) == NULL) {
358 			if (conn->input->eof) {
359 				/* we'll also get here if the line is too long */
360 				server_log_disconnect_error(conn);
361 				server_connection_destroy(&conn);
362 			}
363 			return;
364 		}
365 		/* Allow VERSION before or after the "+" or "-" line,
366 		   because v2.2.33 sent the version after and newer
367 		   versions send before. */
368 		if (!conn->version_received &&
369 		    str_begins(line, "VERSION\t")) {
370 			if (!version_string_verify_full(line, "doveadm-client",
371 							DOVEADM_SERVER_PROTOCOL_VERSION_MAJOR,
372 							&conn->minor)) {
373 				i_error("doveadm server not compatible with this client"
374 					"(mixed old and new binaries?)");
375 				server_connection_destroy(&conn);
376 				return;
377 			}
378 			conn->version_received = TRUE;
379 		} else if (strcmp(line, "+") == 0) {
380 			if (conn->minor > 0)
381 				server_connection_start_multiplex(conn);
382 			server_connection_authenticated(conn);
383 		} else if (strcmp(line, "-") == 0) {
384 			if (conn->authenticate_sent) {
385 				i_error("doveadm authentication failed (%s)",
386 					line+1);
387 				server_connection_destroy(&conn);
388 				return;
389 			}
390 			if (!conn->ssl_done &&
391 			    (conn->server->ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) {
392 				io_remove(&conn->io);
393 				if (conn->minor < 2) {
394 					i_error("doveadm STARTTLS failed: Server does not support it");
395 					server_connection_destroy(&conn);
396 					return;
397 				}
398 				/* send STARTTLS */
399 				o_stream_nsend_str(conn->output, "STARTTLS\n");
400 				if (server_connection_init_ssl(conn, &error) < 0) {
401 					i_error("doveadm STARTTLS failed: %s", error);
402 					server_connection_destroy(&conn);
403 					return;
404 				}
405 				conn->ssl_done = TRUE;
406 				conn->io = io_add_istream(conn->input, server_connection_input, conn);
407 			}
408 			if (server_connection_authenticate(conn) < 0) {
409 				server_connection_destroy(&conn);
410 				return;
411 			}
412 		} else {
413 			i_error("doveadm server sent invalid handshake: %s",
414 				line);
415 			server_connection_destroy(&conn);
416 			return;
417 		}
418 	}
419 
420 	while (server_connection_input_one(conn)) ;
421 }
422 
server_connection_input_one(struct server_connection * conn)423 static bool server_connection_input_one(struct server_connection *conn)
424 {
425 	const unsigned char *data;
426 	size_t size;
427 	const char *line;
428 	int exit_code;
429 
430 	/* check logs - NOTE: must be before i_stream_get_data() since checking
431 	   for logs may add data to our channel. */
432 	if (conn->log_input != NULL)
433 		(void)server_connection_print_log(conn);
434 
435 	data = i_stream_get_data(conn->input, &size);
436 	if (size == 0)
437 		return FALSE;
438 
439 	switch (conn->state) {
440 	case SERVER_REPLY_STATE_DONE:
441 		i_error("doveadm server sent unexpected input");
442 		server_connection_destroy(&conn);
443 		return FALSE;
444 	case SERVER_REPLY_STATE_PRINT:
445 		server_handle_input(conn, data, size);
446 		if (conn->state != SERVER_REPLY_STATE_RET)
447 			return FALSE;
448 		/* fall through */
449 	case SERVER_REPLY_STATE_RET:
450 		line = i_stream_next_line(conn->input);
451 		if (line == NULL)
452 			return FALSE;
453 		if (line[0] == '+')
454 			server_connection_callback(conn, 0, "");
455 		else if (line[0] == '-') {
456 			line++;
457 			exit_code = doveadm_str_to_exit_code(line);
458 			if (exit_code == DOVEADM_EX_UNKNOWN &&
459 			    str_to_int(line, &exit_code) < 0) {
460 				/* old doveadm-server */
461 				exit_code = EX_TEMPFAIL;
462 			}
463 			server_connection_callback(conn, exit_code, line);
464 		} else {
465 			i_error("doveadm server sent broken input "
466 				"(expected cmd reply): %s", line);
467 			server_connection_destroy(&conn);
468 			return FALSE;
469 		}
470 		if (conn->callback == NULL) {
471 			/* we're finished, close the connection */
472 			server_connection_destroy(&conn);
473 			return FALSE;
474 		}
475 		return TRUE;
476 	}
477 	i_unreached();
478 }
479 
server_connection_read_settings(struct server_connection * conn,const char ** error_r)480 static int server_connection_read_settings(struct server_connection *conn,
481 					   const char **error_r)
482 {
483 	const struct setting_parser_info *set_roots[] = {
484 		&doveadm_setting_parser_info,
485 		NULL
486 	};
487 	struct master_service_settings_input input;
488 	struct master_service_settings_output output;
489 	const char *error;
490 	in_port_t port;
491 	void *set;
492 
493 	i_zero(&input);
494 	input.roots = set_roots;
495 	input.service = "doveadm";
496 
497 	(void)net_getsockname(conn->fd, &input.local_ip, &port);
498 	(void)net_getpeername(conn->fd, &input.remote_ip, &port);
499 
500 	if (master_service_settings_read(master_service, &input,
501 					 &output, &error) < 0) {
502 		*error_r = t_strdup_printf(
503 			"Error reading configuration: %s", error);
504 		return -1;
505 	}
506 	set = master_service_settings_get_others(master_service)[0];
507 	conn->set = settings_dup(&doveadm_setting_parser_info, set, conn->pool);
508 	return 0;
509 }
510 
server_connection_init_ssl(struct server_connection * conn,const char ** error_r)511 static int server_connection_init_ssl(struct server_connection *conn,
512 				      const char **error_r)
513 {
514 	struct ssl_iostream_settings ssl_set;
515 	const char *error;
516 
517 	if (conn->server->ssl_flags == 0)
518 		return 0;
519 
520 	doveadm_get_ssl_settings(&ssl_set, pool_datastack_create());
521 
522 	if ((conn->server->ssl_flags & PROXY_SSL_FLAG_ANY_CERT) != 0)
523 		ssl_set.allow_invalid_cert = TRUE;
524 	if (ssl_set.allow_invalid_cert)
525 		ssl_set.verbose_invalid_cert = TRUE;
526 
527 	if (conn->server->ssl_ctx == NULL &&
528 	    ssl_iostream_client_context_cache_get(&ssl_set,
529 						  &conn->server->ssl_ctx,
530 						  &error) < 0) {
531 		*error_r = t_strdup_printf(
532 			"Couldn't initialize SSL client: %s", error);
533 		return -1;
534 	}
535 
536 	if (io_stream_create_ssl_client(conn->server->ssl_ctx,
537 					conn->server->hostname, &ssl_set,
538 					&conn->input, &conn->output,
539 					&conn->ssl_iostream, &error) < 0) {
540 		*error_r = t_strdup_printf(
541 			"Couldn't initialize SSL client: %s", error);
542 		return -1;
543 	}
544 	if (ssl_iostream_handshake(conn->ssl_iostream) < 0) {
545 		*error_r = t_strdup_printf(
546 			"SSL handshake failed: %s",
547 			ssl_iostream_get_last_error(conn->ssl_iostream));
548 		return -1;
549 	}
550 	return 0;
551 }
552 
server_connection_create(struct doveadm_server * server,struct server_connection ** conn_r,const char ** error_r)553 int server_connection_create(struct doveadm_server *server,
554 			     struct server_connection **conn_r,
555 			     const char **error_r)
556 {
557 	const char *target;
558 	struct server_connection *conn;
559 	pool_t pool;
560 
561 	pool = pool_alloconly_create("doveadm server connection", 1024*16);
562 	conn = p_new(pool, struct server_connection, 1);
563 	conn->pool = pool;
564 	conn->server = server;
565 	if (server->ip.family != 0) {
566 		(void)net_ipport2str(&server->ip, server->port, &target);
567 	} else {
568 		target = server->name;
569 	}
570 	conn->fd = doveadm_connect_with_default_port(target,
571 						     doveadm_settings->doveadm_port);
572 	net_set_nonblock(conn->fd, TRUE);
573 	conn->input = i_stream_create_fd(conn->fd, MAX_INBUF_SIZE);
574 	conn->output = o_stream_create_fd(conn->fd, SIZE_MAX);
575 	o_stream_set_flush_callback(conn->output, server_connection_output, conn);
576 	o_stream_set_no_error_handling(conn->output, TRUE);
577 
578 	i_stream_set_name(conn->input, server->name);
579 	o_stream_set_name(conn->output, server->name);
580 
581 	array_push_back(&conn->server->connections, &conn);
582 
583 	if (server_connection_read_settings(conn, error_r) < 0 ||
584 	    ((server->ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0 &&
585 	     server_connection_init_ssl(conn, error_r) < 0)) {
586 		server_connection_destroy(&conn);
587 		return -1;
588 	}
589 	conn->io = io_add_istream(conn->input, server_connection_input, conn);
590 
591 	conn->state = SERVER_REPLY_STATE_DONE;
592 	o_stream_nsend_str(conn->output, DOVEADM_SERVER_PROTOCOL_VERSION_LINE"\n");
593 
594 	*conn_r = conn;
595 	return 0;
596 }
597 
server_connection_destroy(struct server_connection ** _conn)598 void server_connection_destroy(struct server_connection **_conn)
599 {
600 	struct server_connection *conn = *_conn;
601 	struct server_connection *const *conns;
602 	const char *error;
603 	unsigned int i, count;
604 
605 	*_conn = NULL;
606 
607 	conns = array_get(&conn->server->connections, &count);
608 	for (i = 0; i < count; i++) {
609 		if (conns[i] == conn) {
610 			array_delete(&conn->server->connections, i, 1);
611 			break;
612 		}
613 	}
614 
615 	if (conn->callback != NULL) {
616 		error = conn->ssl_iostream == NULL ? NULL :
617 			ssl_iostream_get_last_error(conn->ssl_iostream);
618 		if (error == NULL) {
619 			error = conn->input->stream_errno == 0 ? "EOF" :
620 				strerror(conn->input->stream_errno);
621 		}
622 		server_connection_callback(conn, SERVER_EXIT_CODE_DISCONNECTED,
623 					   error);
624 	}
625 	if (printing_conn == conn)
626 		print_connection_released();
627 
628 	i_stream_destroy(&conn->input);
629 	o_stream_destroy(&conn->output);
630 	i_stream_destroy(&conn->cmd_input);
631 	/* close cmd_output after its parent, so the "." isn't sent */
632 	o_stream_destroy(&conn->cmd_output);
633 	ssl_iostream_destroy(&conn->ssl_iostream);
634 	io_remove(&conn->io_log);
635 	/* make sure all logs got consumed */
636 	if (conn->log_input != NULL)
637 		server_connection_print_log(conn);
638 	i_stream_unref(&conn->log_input);
639 	io_remove(&conn->io);
640 	i_close_fd(&conn->fd);
641 	pool_unref(&conn->pool);
642 }
643 
644 struct doveadm_server *
server_connection_get_server(struct server_connection * conn)645 server_connection_get_server(struct server_connection *conn)
646 {
647 	return conn->server;
648 }
649 
server_connection_cmd(struct server_connection * conn,const char * line,struct istream * cmd_input,server_cmd_callback_t * callback,void * context)650 void server_connection_cmd(struct server_connection *conn, const char *line,
651 			   struct istream *cmd_input,
652 			   server_cmd_callback_t *callback, void *context)
653 {
654 	i_assert(conn->delayed_cmd == NULL);
655 
656 	conn->state = SERVER_REPLY_STATE_PRINT;
657 	if (cmd_input != NULL) {
658 		i_assert(conn->cmd_input == NULL);
659 		i_stream_ref(cmd_input);
660 		conn->cmd_input = cmd_input;
661 	}
662 	if (!conn->authenticated)
663 		conn->delayed_cmd = p_strdup(conn->pool, line);
664 	else {
665 		o_stream_nsend_str(conn->output, line);
666 		server_connection_send_cmd_input(conn);
667 	}
668 	conn->callback = callback;
669 	conn->context = context;
670 }
671 
server_connection_is_idle(struct server_connection * conn)672 bool server_connection_is_idle(struct server_connection *conn)
673 {
674 	return conn->callback == NULL;
675 }
676 
server_connection_extract(struct server_connection * conn,struct istream ** istream_r,struct ostream ** ostream_r,struct ssl_iostream ** ssl_iostream_r)677 void server_connection_extract(struct server_connection *conn,
678 			       struct istream **istream_r,
679 			       struct ostream **ostream_r,
680 			       struct ssl_iostream **ssl_iostream_r)
681 {
682 	*istream_r = conn->input;
683 	*ostream_r = conn->output;
684 	*ssl_iostream_r = conn->ssl_iostream;
685 
686 	conn->input = NULL;
687 	conn->output = NULL;
688 	conn->ssl_iostream = NULL;
689 	io_remove(&conn->io);
690 	conn->fd = -1;
691 }
692