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