1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2  */
3 
4 #include <string.h>
5 #include "login-common.h"
6 #include "ioloop.h"
7 #include "istream.h"
8 #include "ostream.h"
9 #include "str.h"
10 #include "str-sanitize.h"
11 #include "safe-memset.h"
12 #include "buffer.h"
13 #include "base64.h"
14 #include "dsasl-client.h"
15 
16 #include "client.h"
17 #include "client-authenticate.h"
18 
19 #include "managesieve-quote.h"
20 #include "managesieve-proxy.h"
21 #include "managesieve-parser.h"
22 
23 typedef enum {
24 	MANAGESIEVE_RESPONSE_NONE,
25 	MANAGESIEVE_RESPONSE_OK,
26 	MANAGESIEVE_RESPONSE_NO,
27 	MANAGESIEVE_RESPONSE_BYE
28 } managesieve_response_t;
29 
30 static const char *managesieve_proxy_state_names[MSIEVE_PROXY_STATE_COUNT] = {
31 	"none", "tls-start", "tls-ready", "xclient", "auth"
32 };
33 
proxy_write_xclient(struct managesieve_client * client,string_t * str)34 static void proxy_write_xclient
35 (struct managesieve_client *client, string_t *str)
36 {
37 	str_printfa(str,
38 		"XCLIENT ADDR=%s PORT=%u SESSION=%s TTL=%u\r\n",
39 		net_ip2addr(&client->common.ip),
40 		client->common.remote_port,
41 		client_get_session_id(&client->common),
42 		client->common.proxy_ttl - 1);
43 }
44 
proxy_write_auth_data(const unsigned char * data,unsigned int data_len,string_t * str)45 static void proxy_write_auth_data
46 (const unsigned char *data, unsigned int data_len,
47 	string_t *str)
48 {
49 	if (data_len == 0)
50 		str_append(str, "\"\"");
51 	else {
52 		string_t *data_str = t_str_new(128);
53 		base64_encode(data, data_len, data_str);
54 		managesieve_quote_append_string(str, str_c(data_str), FALSE);
55 	}
56 }
57 
proxy_write_auth(struct managesieve_client * client,string_t * str)58 static int proxy_write_auth
59 (struct managesieve_client *client, string_t *str)
60 {
61 	struct dsasl_client_settings sasl_set;
62 	const unsigned char *output;
63 	size_t len;
64 	const char *mech_name, *error;
65 
66 	i_assert(client->common.proxy_ttl > 1);
67 
68 	if ( !client->proxy_sasl ) {
69 		/* Prevent sending credentials to a server that has login disabled;
70 		   i.e., due to the lack of TLS */
71 		login_proxy_failed(client->common.login_proxy,
72 			login_proxy_get_event(client->common.login_proxy),
73 			LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG,
74 			"Server has disabled authentication (TLS required?)");
75 		return -1;
76 	}
77 
78 	if (client->common.proxy_mech == NULL)
79 		client->common.proxy_mech = &dsasl_client_mech_plain;
80 
81 	i_assert(client->common.proxy_sasl_client == NULL);
82 	i_zero(&sasl_set);
83 	sasl_set.authid = client->common.proxy_master_user != NULL ?
84 		client->common.proxy_master_user : client->common.proxy_user;
85 	sasl_set.authzid = client->common.proxy_user;
86 	sasl_set.password = client->common.proxy_password;
87 	client->common.proxy_sasl_client =
88 		dsasl_client_new(client->common.proxy_mech, &sasl_set);
89 	mech_name = dsasl_client_mech_get_name(client->common.proxy_mech);
90 
91 	str_append(str, "AUTHENTICATE ");
92 	managesieve_quote_append_string(str, mech_name, FALSE);
93 	if (dsasl_client_output(client->common.proxy_sasl_client,
94 				&output, &len, &error) < 0) {
95 		const char *reason = t_strdup_printf(
96 			"SASL mechanism %s init failed: %s",
97 			mech_name, error);
98 		login_proxy_failed(client->common.login_proxy,
99 			login_proxy_get_event(client->common.login_proxy),
100 			LOGIN_PROXY_FAILURE_TYPE_INTERNAL, reason);
101 		return -1;
102 	}
103 	if (len > 0) {
104 		str_append_c(str, ' ');
105 		proxy_write_auth_data(output, len, str);
106 	}
107 	str_append(str, "\r\n");
108 	return 0;
109 }
110 
proxy_input_auth_challenge(struct managesieve_client * client,const char * line,const char ** challenge_r)111 static int proxy_input_auth_challenge
112 (struct managesieve_client *client, const char *line,
113 	const char **challenge_r)
114 {
115 	struct istream *input;
116 	struct managesieve_parser *parser;
117  	const struct managesieve_arg *args;
118 	const char *challenge;
119 	bool fatal = FALSE;
120 	int ret;
121 
122 	i_assert(client->common.proxy_sasl_client != NULL);
123 	*challenge_r = NULL;
124 
125 	/* Build an input stream for the managesieve parser
126 	 *  FIXME: Ugly, see proxy_input_capability().
127 	 */
128 	line = t_strconcat(line, "\r\n", NULL);
129 	input = i_stream_create_from_data(line, strlen(line));
130 	parser = managesieve_parser_create(input, MAX_MANAGESIEVE_LINE);
131 	managesieve_parser_reset(parser);
132 
133 	(void)i_stream_read(input);
134 	ret = managesieve_parser_read_args(parser, 1, 0, &args);
135 
136 	if ( ret >= 0 ) {
137 		if ( ret > 0 && managesieve_arg_get_string(&args[0], &challenge) ) {
138 			*challenge_r = t_strdup(challenge);
139 		} else {
140 			const char *reason = t_strdup_printf(
141 				"Server sent invalid SASL challenge line: %s",
142 				str_sanitize(line,160));
143 			login_proxy_failed(client->common.login_proxy,
144 				login_proxy_get_event(client->common.login_proxy),
145 				LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
146 			fatal = TRUE;
147 		}
148 
149 	} else if ( ret == -2 ) {
150 		/* Parser needs more data (not possible on mem stream) */
151 		i_unreached();
152 
153 	} else {
154 		const char *error_str = managesieve_parser_get_error(parser, &fatal);
155 		error_str = (error_str != NULL ? error_str : "unknown (bug)" );
156 
157 		/* Do not accept faulty server */
158 		const char *reason = t_strdup_printf(
159 			"Protocol parse error(%d) int SASL challenge line: %s (line=`%s')",
160 			ret, error_str, line);
161 		login_proxy_failed(client->common.login_proxy,
162 			login_proxy_get_event(client->common.login_proxy),
163 			LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
164 		fatal = TRUE;
165 	}
166 
167 
168 	/* Cleanup parser */
169   managesieve_parser_destroy(&parser);
170 	i_stream_destroy(&input);
171 
172 	/* Time to exit if greeting was not accepted */
173 	if ( fatal ) return -1;
174 	return 0;
175 }
176 
proxy_write_auth_response(struct managesieve_client * client,const char * challenge,string_t * str)177 static int proxy_write_auth_response
178 (struct managesieve_client *client,
179 	const char *challenge, string_t *str)
180 {
181 	const unsigned char *data;
182 	size_t data_len;
183 	const char *error;
184 	int ret;
185 
186 	if (base64_decode(challenge, strlen(challenge), NULL, str) < 0) {
187 		login_proxy_failed(client->common.login_proxy,
188 			login_proxy_get_event(client->common.login_proxy),
189 			LOGIN_PROXY_FAILURE_TYPE_PROTOCOL,
190 			"Server sent invalid base64 data in AUTHENTICATE response");
191 		return -1;
192 	}
193 	ret = dsasl_client_input(client->common.proxy_sasl_client,
194 				 str_data(str), str_len(str), &error);
195 	if (ret == 0) {
196 		ret = dsasl_client_output(client->common.proxy_sasl_client,
197 					  &data, &data_len, &error);
198 	}
199 	if (ret < 0) {
200 		const char *reason = t_strdup_printf(
201 			"Server sent invalid authentication data: %s", error);
202 		login_proxy_failed(client->common.login_proxy,
203 			login_proxy_get_event(client->common.login_proxy),
204 			LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
205 		return -1;
206 	}
207 	i_assert(ret == 0);
208 
209 	str_truncate(str, 0);
210 	proxy_write_auth_data(data, data_len, str);
211 	str_append(str, "\r\n");
212 	return 0;
213 }
214 
proxy_read_response(const struct managesieve_arg * args)215 static managesieve_response_t proxy_read_response
216 (const struct managesieve_arg *args)
217 {
218 	const char *response;
219 
220 	if ( managesieve_arg_get_atom(&args[0], &response) ) {
221 		if ( strcasecmp(response, "OK") == 0 ) {
222 			/* Received OK response; greeting is finished */
223 			return MANAGESIEVE_RESPONSE_OK;
224 
225 		} else if ( strcasecmp(response, "NO") == 0 ) {
226 			/* Received OK response; greeting is finished */
227 			return MANAGESIEVE_RESPONSE_NO;
228 
229 		} else if ( strcasecmp(response, "BYE") == 0 ) {
230 			/* Received OK response; greeting is finished */
231 			return MANAGESIEVE_RESPONSE_BYE;
232 		}
233 	}
234 	return MANAGESIEVE_RESPONSE_NONE;
235 }
236 
proxy_input_capability(struct managesieve_client * client,const char * line,managesieve_response_t * resp_r)237 static int proxy_input_capability
238 (struct managesieve_client *client, const char *line,
239 	managesieve_response_t *resp_r)
240 {
241 	struct istream *input;
242 	struct managesieve_parser *parser;
243  	const struct managesieve_arg *args;
244 	const char *capability;
245 	int ret;
246 	bool fatal = FALSE;
247 
248 	*resp_r = MANAGESIEVE_RESPONSE_NONE;
249 
250 	/* Build an input stream for the managesieve parser
251 	 *  FIXME: It would be nice if the line-wise parsing could be
252 	 *    substituded by something similar to the command line interpreter.
253 	 *    However, the current login_proxy structure does not make streams
254 	 *    known until inside proxy_input handler.
255 	 */
256 	line = t_strconcat(line, "\r\n", NULL);
257 	input = i_stream_create_from_data(line, strlen(line));
258 	parser = managesieve_parser_create(input, MAX_MANAGESIEVE_LINE);
259 	managesieve_parser_reset(parser);
260 
261 	/* Parse input
262 	 *  FIXME: Theoretically the OK response could include a
263 	 *   response code which could be rejected by the parser.
264 	 */
265 	(void)i_stream_read(input);
266 	ret = managesieve_parser_read_args(parser, 2, 0, &args);
267 
268 	if ( ret == 0 ) {
269 		const char *reason = t_strdup_printf(
270 			"Remote returned with invalid capability/greeting line: %s",
271 			str_sanitize(line,160));
272 		login_proxy_failed(client->common.login_proxy,
273 			login_proxy_get_event(client->common.login_proxy),
274 			LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
275 		fatal = TRUE;
276 	} else if ( ret > 0 ) {
277 		if ( args[0].type == MANAGESIEVE_ARG_ATOM ) {
278 			*resp_r = proxy_read_response(args);
279 
280 			if ( *resp_r == MANAGESIEVE_RESPONSE_NONE ) {
281 				const char *reason = t_strdup_printf(
282 					"Remote sent invalid response: %s",
283 					str_sanitize(line,160));
284 				login_proxy_failed(client->common.login_proxy,
285 					login_proxy_get_event(client->common.login_proxy),
286 					LOGIN_PROXY_FAILURE_TYPE_PROTOCOL,
287 					reason);
288 
289 				fatal = TRUE;
290 			}
291 		} else if ( managesieve_arg_get_string(&args[0], &capability) ) {
292 			if ( strcasecmp(capability, "SASL") == 0 ) {
293 				const char *sasl_mechs;
294 
295 				/* Check whether the server supports the SASL mechanism
296 				 * we are going to use (currently only PLAIN supported).
297 				 */
298 				if ( ret == 2 && managesieve_arg_get_string(&args[1], &sasl_mechs) ) {
299 					const char *const *mechs = t_strsplit(sasl_mechs, " ");
300 
301 					if ( *mechs != NULL ) {
302 						/* At least one SASL mechanism is supported */
303 						client->proxy_sasl = TRUE;
304 					}
305 
306 				} else {
307 					login_proxy_failed(client->common.login_proxy,
308 						login_proxy_get_event(client->common.login_proxy),
309 						LOGIN_PROXY_FAILURE_TYPE_PROTOCOL,
310 						"Server returned erroneous SASL capability");
311 					fatal = TRUE;
312 				}
313 
314 			} else if ( strcasecmp(capability, "STARTTLS") == 0 ) {
315 				client->proxy_starttls = TRUE;
316 			} else if ( strcasecmp(capability, "XCLIENT") == 0 ) {
317 				client->proxy_xclient = TRUE;
318 			}
319 
320 		} else {
321 			/* Do not accept faulty server */
322 			const char *reason = t_strdup_printf(
323 				"Remote returned with invalid capability/greeting line: %s",
324 				str_sanitize(line,160));
325 			login_proxy_failed(client->common.login_proxy,
326 				login_proxy_get_event(client->common.login_proxy),
327 				LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
328 			fatal = TRUE;
329 		}
330 
331 	} else if ( ret == -2 ) {
332 		/* Parser needs more data (not possible on mem stream) */
333 		i_unreached();
334 
335 	} else {
336 		const char *error_str = managesieve_parser_get_error(parser, &fatal);
337 		error_str = (error_str != NULL ? error_str : "unknown (bug)" );
338 
339 		/* Do not accept faulty server */
340 		const char *reason = t_strdup_printf(
341 			"Protocol parse error(%d) in capability/greeting line: %s (line=`%s')",
342 			ret, error_str, line);
343 		login_proxy_failed(client->common.login_proxy,
344 			login_proxy_get_event(client->common.login_proxy),
345 			LOGIN_PROXY_FAILURE_TYPE_PROTOCOL, reason);
346 		fatal = TRUE;
347 	}
348 
349 	/* Cleanup parser */
350 	managesieve_parser_destroy(&parser);
351 	i_stream_destroy(&input);
352 
353 	/* Time to exit if greeting was not accepted */
354 	if ( fatal ) return -1;
355 
356 	/* Wait until greeting is received completely */
357 	if ( *resp_r == MANAGESIEVE_RESPONSE_NONE ) return 1;
358 
359 	return 0;
360 }
361 
362 static void
managesieve_proxy_parse_auth_reply(const char * line,const char ** reason_r,bool * trylater_r)363 managesieve_proxy_parse_auth_reply(const char *line,
364 				   const char **reason_r, bool *trylater_r)
365 {
366 	struct managesieve_parser *parser;
367 	const struct managesieve_arg *args;
368 	struct istream *input;
369 	const char *reason;
370 	int ret;
371 
372 	*trylater_r = FALSE;
373 
374 	if (strncasecmp(line, "NO ", 3) != 0) {
375 		*reason_r = line;
376 		return;
377 	}
378 	line += 3;
379 	*reason_r = line;
380 
381 	if (line[0] == '(') {
382 		/* Parse optional resp-code. FIXME: The current
383 		   managesieve-parser can't really handle this properly, so
384 		   we'll just assume that there aren't any strings with ')'
385 		   in them. */
386 		if (strncasecmp(line, "(TRYLATER) ", 11) == 0) {
387 			*trylater_r = TRUE;
388 			line += 11;
389 		} else {
390 			line = strstr(line, ") ");
391 			if (line == NULL)
392 				return;
393 			line += 2;
394 		}
395 	}
396 
397 	/* parse the string */
398 	input = i_stream_create_from_data(line, strlen(line));
399 	parser = managesieve_parser_create(input, (size_t)-1);
400 	(void)i_stream_read(input);
401 	ret = managesieve_parser_finish_line(parser, 0, 0, &args);
402 	if (ret == 1 && managesieve_arg_get_string(&args[0], &reason))
403 		*reason_r = t_strdup(reason);
404 	managesieve_parser_destroy(&parser);
405 }
406 
managesieve_proxy_parse_line(struct client * client,const char * line)407 int managesieve_proxy_parse_line(struct client *client, const char *line)
408 {
409 	struct managesieve_client *msieve_client =
410 		(struct managesieve_client *) client;
411 	struct ostream *output;
412 	enum login_proxy_ssl_flags ssl_flags;
413 	managesieve_response_t response = MANAGESIEVE_RESPONSE_NONE;
414 	string_t *command;
415 	int ret = 0;
416 
417 	i_assert(!client->destroyed);
418 
419 	output = login_proxy_get_ostream(client->login_proxy);
420 	switch ( msieve_client->proxy_state ) {
421 	case MSIEVE_PROXY_STATE_NONE:
422 		if ( (ret=proxy_input_capability
423 			(msieve_client, line, &response)) < 0 )
424 			return -1;
425 
426 		if ( ret == 0 ) {
427 			if ( response != MANAGESIEVE_RESPONSE_OK ) {
428 				login_proxy_failed(client->login_proxy,
429 					login_proxy_get_event(client->login_proxy),
430 					LOGIN_PROXY_FAILURE_TYPE_PROTOCOL,
431 					"Remote sent unexpected NO/BYE instead of capability response");
432 				return -1;
433 			}
434 
435 			command = t_str_new(128);
436 
437 			ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
438 			if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) {
439 				if ( !msieve_client->proxy_starttls ) {
440 					login_proxy_failed(client->login_proxy,
441 						login_proxy_get_event(client->login_proxy),
442 						LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG,
443 						"Remote doesn't support STARTTLS");
444 					return -1;
445 				}
446 
447 				str_append(command, "STARTTLS\r\n");
448 				msieve_client->proxy_state = MSIEVE_PROXY_STATE_TLS_START;
449 
450 			} else if (msieve_client->proxy_xclient) {
451 				proxy_write_xclient(msieve_client, command);
452 				msieve_client->proxy_state = MSIEVE_PROXY_STATE_XCLIENT;
453 
454 			} else {
455 				if ( proxy_write_auth(msieve_client, command) < 0 )
456 					return -1;
457 				msieve_client->proxy_state = MSIEVE_PROXY_STATE_AUTH;
458 			}
459 
460 			o_stream_nsend(output, str_data(command), str_len(command));
461 		}
462 		return 0;
463 
464 	case MSIEVE_PROXY_STATE_TLS_START:
465 		if ( strncasecmp(line, "OK", 2) == 0 &&
466 			( strlen(line) == 2 || line[2] == ' ' ) ) {
467 
468 			/* STARTTLS successful, begin TLS negotiation. */
469 			if ( login_proxy_starttls(client->login_proxy) < 0 )
470 				return -1;
471 
472 			msieve_client->proxy_sasl = FALSE;
473 			msieve_client->proxy_xclient = FALSE;
474 			msieve_client->proxy_state = MSIEVE_PROXY_STATE_TLS_READY;
475 			return 1;
476 		}
477 
478 		login_proxy_failed(client->login_proxy,
479 			login_proxy_get_event(client->login_proxy),
480 			LOGIN_PROXY_FAILURE_TYPE_REMOTE,
481 			"Remote refused STARTTLS command");
482 		return -1;
483 
484 	case MSIEVE_PROXY_STATE_TLS_READY:
485 		if ( (ret=proxy_input_capability(msieve_client, line, &response)) < 0 )
486 			return -1;
487 
488 		if ( ret == 0 ) {
489 			if ( response != MANAGESIEVE_RESPONSE_OK ) {
490 				/* STARTTLS failed */
491 				const char *reason = t_strdup_printf(
492 					"Remote STARTTLS failed: %s",
493 					str_sanitize(line, 160));
494 				login_proxy_failed(client->login_proxy,
495 					login_proxy_get_event(client->login_proxy),
496 					LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason);
497 				return -1;
498 			}
499 
500 			command = t_str_new(128);
501 			if ( msieve_client->proxy_xclient ) {
502 				proxy_write_xclient(msieve_client, command);
503 				msieve_client->proxy_state = MSIEVE_PROXY_STATE_XCLIENT;
504 
505 			} else {
506 				if ( proxy_write_auth(msieve_client, command) < 0 )
507 					return -1;
508 				msieve_client->proxy_state = MSIEVE_PROXY_STATE_AUTH;
509 			}
510 			o_stream_nsend(output, str_data(command), str_len(command));
511 		}
512 		return 0;
513 
514 	case MSIEVE_PROXY_STATE_XCLIENT:
515 		if ( strncasecmp(line, "OK", 2) == 0 &&
516 			( strlen(line) == 2 || line[2] == ' ' ) ) {
517 
518 			command = t_str_new(128);
519 			if ( proxy_write_auth(msieve_client, command) < 0 )
520 				return -1;
521 			o_stream_nsend(output, str_data(command), str_len(command));
522 			msieve_client->proxy_state = MSIEVE_PROXY_STATE_AUTH;
523 			return 0;
524 		}
525 
526 		const char *reason = t_strdup_printf(
527 			"Remote XCLIENT failed: %s",
528 			str_sanitize(line, 160));
529 		login_proxy_failed(client->login_proxy,
530 			login_proxy_get_event(client->login_proxy),
531 			LOGIN_PROXY_FAILURE_TYPE_REMOTE, reason);
532 		return -1;
533 
534 	case MSIEVE_PROXY_STATE_AUTH:
535 		/* Challenge? */
536 		if ( *line == '"' ) {
537 			const char *challenge;
538 
539 			if ( proxy_input_auth_challenge
540 				(msieve_client, line, &challenge) < 0 )
541 				return -1;
542 			command = t_str_new(128);
543 			if ( proxy_write_auth_response
544 				(msieve_client, challenge, command) < 0 )
545 				return -1;
546 			o_stream_nsend(output, str_data(command), str_len(command));
547 			return 0;
548 		}
549 
550 		/* Check login status */
551 		if ( strncasecmp(line, "OK", 2) == 0 &&
552 			(strlen(line) == 2 || line[2] == ' ') ) {
553 			string_t *str = t_str_new(128);
554 
555 			/* Login successful */
556 
557 			/* FIXME: some SASL mechanisms cause a capability response to be sent */
558 
559 			/* Send this line to client. */
560 			str_append(str, line );
561 			str_append(str, "\r\n");
562 			o_stream_nsend(client->output, str_data(str), str_len(str));
563 
564 			(void)client_skip_line(msieve_client);
565 			client_proxy_finish_destroy_client(client);
566 			return 1;
567 		}
568 
569 		/* Authentication failed */
570 		bool try_later;
571 		(void)managesieve_proxy_parse_auth_reply(line, &reason, &try_later);
572 
573 		/* Login failed. Send our own failure reply so client can't
574 		 * figure out if user exists or not just by looking at the
575 		 * reply string.
576 		 */
577 		enum login_proxy_failure_type failure_type;
578 		if (try_later)
579 			failure_type = LOGIN_PROXY_FAILURE_TYPE_AUTH_TEMPFAIL;
580 		else {
581 			failure_type = LOGIN_PROXY_FAILURE_TYPE_AUTH;
582 			client_send_no(client, AUTH_FAILED_MSG);
583 		}
584 
585 		login_proxy_failed(client->login_proxy,
586 			login_proxy_get_event(client->login_proxy),
587 			failure_type, reason);
588 		return -1;
589 
590 	default:
591 		/* Not supposed to happen */
592 		break;
593 	}
594 
595 	i_unreached();
596 	return -1;
597 }
598 
managesieve_proxy_reset(struct client * client)599 void managesieve_proxy_reset(struct client *client)
600 {
601 	struct managesieve_client *msieve_client =
602 		(struct managesieve_client *) client;
603 
604 	msieve_client->proxy_starttls = FALSE;
605 	msieve_client->proxy_sasl = FALSE;
606 	msieve_client->proxy_xclient = FALSE;
607 	msieve_client->proxy_state = MSIEVE_PROXY_STATE_NONE;
608 }
609 
610 static void
managesieve_proxy_send_failure_reply(struct client * client,enum login_proxy_failure_type type,const char * reason)611 managesieve_proxy_send_failure_reply(struct client *client,
612 				     enum login_proxy_failure_type type,
613 				     const char *reason)
614 {
615 	switch (type) {
616 	case LOGIN_PROXY_FAILURE_TYPE_CONNECT:
617 	case LOGIN_PROXY_FAILURE_TYPE_INTERNAL:
618 	case LOGIN_PROXY_FAILURE_TYPE_REMOTE:
619 	case LOGIN_PROXY_FAILURE_TYPE_PROTOCOL:
620 		client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_NO,
621 				       "TRYLATER", LOGIN_PROXY_FAILURE_MSG);
622 		break;
623 	case LOGIN_PROXY_FAILURE_TYPE_INTERNAL_CONFIG:
624 	case LOGIN_PROXY_FAILURE_TYPE_REMOTE_CONFIG:
625 		client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_NO,
626 				       NULL, LOGIN_PROXY_FAILURE_MSG);
627 		break;
628 	case LOGIN_PROXY_FAILURE_TYPE_AUTH_TEMPFAIL:
629 		client_send_reply_code(client, MANAGESIEVE_CMD_REPLY_NO,
630 				       "TRYLATER", reason);
631 		break;
632 	case LOGIN_PROXY_FAILURE_TYPE_AUTH:
633 		/* reply was already sent */
634 		break;
635 	}
636 }
637 
managesieve_proxy_failed(struct client * client,enum login_proxy_failure_type type,const char * reason,bool reconnecting)638 void managesieve_proxy_failed(struct client *client,
639 			      enum login_proxy_failure_type type,
640 			      const char *reason, bool reconnecting)
641 {
642 	if (!reconnecting)
643 		managesieve_proxy_send_failure_reply(client, type, reason);
644 	client_common_proxy_failed(client, type, reason, reconnecting);
645 }
646 
managesieve_proxy_get_state(struct client * client)647 const char *managesieve_proxy_get_state(struct client *client)
648 {
649 	struct managesieve_client *msieve_client =
650 		(struct managesieve_client *) client;
651 
652 	return managesieve_proxy_state_names[msieve_client->proxy_state];
653 }
654