1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
6
#include "str-sanitize.h"
9
#include "safe-mkstemp.h"
14
#include "write-full.h"
17
#include "mail-user.h"
18
#include "imap-urlauth-fetch.h"
20
#include "imap-urlauth-connection.h"
22
enum imap_urlauth_state {
23
IMAP_URLAUTH_STATE_DISCONNECTED = 0,
24
IMAP_URLAUTH_STATE_AUTHENTICATING,
25
IMAP_URLAUTH_STATE_AUTHENTICATED,
26
IMAP_URLAUTH_STATE_SELECTING_TARGET,
27
IMAP_URLAUTH_STATE_UNSELECTING_TARGET,
28
IMAP_URLAUTH_STATE_READY,
29
IMAP_URLAUTH_STATE_REQUEST_PENDING,
30
IMAP_URLAUTH_STATE_REQUEST_WAIT,
33
struct imap_urlauth_request {
34
struct imap_urlauth_target *target;
35
struct imap_urlauth_request *prev, *next;
38
enum imap_urlauth_fetch_flags flags;
42
imap_urlauth_request_callback_t *callback;
45
unsigned int binary_has_nuls;
48
struct imap_urlauth_target {
49
struct imap_urlauth_target *prev, *next;
53
struct imap_urlauth_request *requests_head, *requests_tail;
56
struct imap_urlauth_connection {
59
char *path, *session_id;
60
struct mail_user *user;
63
struct istream *input;
64
struct ostream *output;
67
struct timeout *to_reconnect, *to_idle, *to_response;
68
time_t last_reconnect;
69
unsigned int reconnect_attempts;
70
unsigned int idle_timeout_msecs;
72
char *literal_temp_path;
74
buffer_t *literal_buf;
75
uoff_t literal_size, literal_bytes_left;
77
enum imap_urlauth_state state;
79
/* userid => target struct */
80
struct imap_urlauth_target *targets_head, *targets_tail;
82
unsigned int reading_literal:1;
85
#define IMAP_URLAUTH_RECONNECT_MIN_SECS 2
86
#define IMAP_URLAUTH_RECONNECT_MAX_ATTEMPTS 3
88
#define IMAP_URLAUTH_RESPONSE_TIMEOUT_MSECS 2*60*1000
90
#define IMAP_URLAUTH_HANDSHAKE "VERSION\timap-urlauth\t1\t0\n"
92
#define IMAP_URLAUTH_MAX_INLINE_LITERAL_SIZE (1024*32)
94
static void imap_urlauth_connection_disconnect
95
(struct imap_urlauth_connection *conn, const char *reason);
96
static void imap_urlauth_connection_abort
97
(struct imap_urlauth_connection *conn, const char *reason);
98
static void imap_urlauth_connection_reconnect
99
(struct imap_urlauth_connection *conn);
100
static void imap_urlauth_connection_idle_disconnect
101
(struct imap_urlauth_connection *conn);
102
static void imap_urlauth_connection_timeout_abort
103
(struct imap_urlauth_connection *conn);
104
static void imap_urlauth_connection_fail
105
(struct imap_urlauth_connection *conn);
107
struct imap_urlauth_connection *
108
imap_urlauth_connection_init(const char *path, struct mail_user *user,
109
const char *session_id,
110
unsigned int idle_timeout_msecs)
112
struct imap_urlauth_connection *conn;
114
conn = i_new(struct imap_urlauth_connection, 1);
116
conn->path = i_strdup(path);
117
if (session_id != NULL)
118
conn->session_id = i_strdup(session_id);
121
conn->literal_fd = -1;
122
conn->idle_timeout_msecs = idle_timeout_msecs;
126
void imap_urlauth_connection_deinit(struct imap_urlauth_connection **_conn)
128
struct imap_urlauth_connection *conn = *_conn;
132
imap_urlauth_connection_abort(conn, NULL);
135
if (conn->session_id != NULL)
136
i_free(conn->session_id);
138
i_assert(conn->to_idle == NULL);
139
i_assert(conn->to_reconnect == NULL);
140
i_assert(conn->to_response == NULL);
146
imap_urlauth_stop_response_timeout(struct imap_urlauth_connection *conn)
148
if (conn->to_response != NULL)
149
timeout_remove(&conn->to_response);
153
imap_urlauth_start_response_timeout(struct imap_urlauth_connection *conn)
155
imap_urlauth_stop_response_timeout(conn);
156
conn->to_response = timeout_add(IMAP_URLAUTH_RESPONSE_TIMEOUT_MSECS,
157
imap_urlauth_connection_timeout_abort, conn);
160
static struct imap_urlauth_target *
161
imap_urlauth_connection_get_target(struct imap_urlauth_connection *conn,
162
const char *target_user)
164
struct imap_urlauth_target *target = conn->targets_head;
166
while (target != NULL) {
167
if (strcmp(target->userid, target_user) == 0)
169
target = target->next;
172
target = i_new(struct imap_urlauth_target, 1);
173
target->userid = i_strdup(target_user);
174
DLLIST2_APPEND(&conn->targets_head, &conn->targets_tail, target);
179
imap_urlauth_target_free(struct imap_urlauth_connection *conn,
180
struct imap_urlauth_target *target)
182
DLLIST2_REMOVE(&conn->targets_head, &conn->targets_tail, target);
183
i_free(target->userid);
188
imap_urlauth_connection_select_target(struct imap_urlauth_connection *conn)
190
struct imap_urlauth_target *target = conn->targets_head;
193
if (target == NULL || conn->state != IMAP_URLAUTH_STATE_AUTHENTICATED)
196
if (conn->user->mail_debug)
197
i_debug("imap-urlauth: Selecting target user `%s'", target->userid);
199
conn->state = IMAP_URLAUTH_STATE_SELECTING_TARGET;
200
cmd = t_strdup_printf("USER\t%s\n", str_tabescape(target->userid));
201
if (o_stream_send_str(conn->output, cmd) < 0) {
202
i_warning("Error sending USER request to imap-urlauth server: %m");
203
imap_urlauth_connection_fail(conn);
206
imap_urlauth_start_response_timeout(conn);
210
imap_urlauth_connection_send_request(struct imap_urlauth_connection *conn)
212
struct imap_urlauth_request *urlreq;
215
if (conn->targets_head == NULL ||
216
(conn->targets_head->requests_head == NULL &&
217
conn->targets_head->next == NULL &&
218
conn->state == IMAP_URLAUTH_STATE_READY)) {
219
if (conn->user->mail_debug)
220
i_debug("imap-urlauth: No more requests pending; scheduling disconnect");
221
if (conn->to_idle != NULL)
222
timeout_remove(&conn->to_idle);
223
if (conn->idle_timeout_msecs > 0) {
224
conn->to_idle = timeout_add(conn->idle_timeout_msecs,
225
imap_urlauth_connection_idle_disconnect, conn);
230
if (conn->state == IMAP_URLAUTH_STATE_AUTHENTICATED) {
231
imap_urlauth_connection_select_target(conn);
235
if (conn->state != IMAP_URLAUTH_STATE_READY)
238
urlreq = conn->targets_head->requests_head;
239
if (urlreq == NULL) {
240
if (conn->targets_head->next == NULL)
243
conn->state = IMAP_URLAUTH_STATE_UNSELECTING_TARGET;
244
imap_urlauth_target_free(conn, conn->targets_head);
246
if (o_stream_send_str(conn->output, "END\n") < 0) {
247
i_warning("Error sending END request to imap-urlauth server: %m");
248
imap_urlauth_connection_fail(conn);
250
imap_urlauth_start_response_timeout(conn);
254
if (conn->user->mail_debug)
255
i_debug("imap-urlauth: Fetching URL `%s'", urlreq->url);
257
cmd = t_str_new(128);
258
str_append(cmd, "URL\t");
259
str_append_tabescaped(cmd, urlreq->url);
260
if ((urlreq->flags & IMAP_URLAUTH_FETCH_FLAG_BODYPARTSTRUCTURE) != 0)
261
str_append(cmd, "\tbpstruct");
262
if ((urlreq->flags & IMAP_URLAUTH_FETCH_FLAG_BINARY) != 0)
263
str_append(cmd, "\tbinary");
264
else if ((urlreq->flags & IMAP_URLAUTH_FETCH_FLAG_BODY) != 0)
265
str_append(cmd, "\tbody");
266
str_append_c(cmd, '\n');
268
conn->state = IMAP_URLAUTH_STATE_REQUEST_PENDING;
269
if (o_stream_send(conn->output, str_data(cmd), str_len(cmd)) < 0) {
270
i_warning("Error sending URL request to imap-urlauth server: %m");
271
imap_urlauth_connection_fail(conn);
274
imap_urlauth_start_response_timeout(conn);
277
struct imap_urlauth_request *
278
imap_urlauth_request_new(struct imap_urlauth_connection *conn,
279
const char *target_user, const char *url,
280
enum imap_urlauth_fetch_flags flags,
281
imap_urlauth_request_callback_t *callback,
284
struct imap_urlauth_request *urlreq;
285
struct imap_urlauth_target *target;
287
target = imap_urlauth_connection_get_target(conn, target_user);
289
urlreq = i_new(struct imap_urlauth_request, 1);
290
urlreq->url = i_strdup(url);
291
urlreq->flags = flags;
292
urlreq->target = target;
293
urlreq->callback = callback;
294
urlreq->context = context;
296
DLLIST2_APPEND(&target->requests_head, &target->requests_tail, urlreq);
298
if (conn->to_idle != NULL)
299
timeout_remove(&conn->to_idle);
301
if (conn->user->mail_debug) {
302
i_debug("imap-urlauth: Added request for URL `%s' from user `%s'",
306
imap_urlauth_connection_send_request(conn);
310
static void imap_urlauth_request_free(struct imap_urlauth_request *urlreq)
312
struct imap_urlauth_target *target = urlreq->target;
314
DLLIST2_REMOVE(&target->requests_head, &target->requests_tail, urlreq);
316
i_free(urlreq->bodypartstruct);
320
static void imap_urlauth_request_drop(struct imap_urlauth_connection *conn,
321
struct imap_urlauth_request *urlreq)
323
if ((conn->state == IMAP_URLAUTH_STATE_REQUEST_PENDING ||
324
conn->state == IMAP_URLAUTH_STATE_REQUEST_WAIT) &&
325
conn->targets_head != NULL &&
326
conn->targets_head->requests_head == urlreq) {
327
/* cannot just drop pending request without breaking
331
imap_urlauth_request_free(urlreq);
335
void imap_urlauth_request_abort(struct imap_urlauth_connection *conn,
336
struct imap_urlauth_request *urlreq)
338
imap_urlauth_request_callback_t *callback;
340
callback = urlreq->callback;
341
urlreq->callback = NULL;
342
if (callback != NULL) {
344
callback(NULL, urlreq->context);
348
imap_urlauth_request_drop(conn, urlreq);
352
imap_urlauth_request_fail(struct imap_urlauth_connection *conn,
353
struct imap_urlauth_request *urlreq,
356
struct imap_urlauth_fetch_reply reply;
357
imap_urlauth_request_callback_t *callback;
360
callback = urlreq->callback;
361
urlreq->callback = NULL;
362
if (callback != NULL) {
363
memset(&reply, 0, sizeof(reply));
364
reply.url = urlreq->url;
365
reply.flags = urlreq->flags;
366
reply.succeeded = FALSE;
370
ret = callback(&reply, urlreq->context);
374
imap_urlauth_request_drop(conn, urlreq);
377
/* Drop any related requests upon error */
378
imap_urlauth_request_abort_by_context(conn, urlreq->context);
382
imap_urlauth_connection_continue(conn);
386
imap_urlauth_target_abort(struct imap_urlauth_connection *conn,
387
struct imap_urlauth_target *target)
389
struct imap_urlauth_request *urlreq, *next;
391
urlreq = target->requests_head;
392
while (urlreq != NULL) {
394
imap_urlauth_request_abort(conn, urlreq);
398
imap_urlauth_target_free(conn, target);
402
imap_urlauth_target_fail(struct imap_urlauth_connection *conn,
403
struct imap_urlauth_target *target, const char *error)
405
struct imap_urlauth_request *urlreq, *next;
407
urlreq = target->requests_head;
408
while (urlreq != NULL) {
410
imap_urlauth_request_fail(conn, urlreq, error);
414
imap_urlauth_target_free(conn, target);
418
imap_urlauth_target_abort_by_context(struct imap_urlauth_connection *conn,
419
struct imap_urlauth_target *target,
422
struct imap_urlauth_request *urlreq, *next;
424
/* abort all matching requests */
425
urlreq = target->requests_head;
426
while (urlreq != NULL) {
428
if (urlreq->context == context)
429
imap_urlauth_request_abort(conn, urlreq);
433
if (target->requests_head == NULL)
434
imap_urlauth_target_free(conn, target);
438
imap_urlauth_connection_abort(struct imap_urlauth_connection *conn,
441
struct imap_urlauth_target *target, *next;
444
reason = "Aborting due to error";
445
imap_urlauth_connection_disconnect(conn, reason);
447
/* abort all requests */
448
target = conn->targets_head;
449
while (target != NULL) {
451
imap_urlauth_target_abort(conn, target);
456
void imap_urlauth_request_abort_by_context(struct imap_urlauth_connection *conn,
459
struct imap_urlauth_target *target, *next;
461
/* abort all matching requests */
462
target = conn->targets_head;
463
while (target != NULL) {
465
imap_urlauth_target_abort_by_context(conn, target, context);
470
static void imap_urlauth_connection_fail(struct imap_urlauth_connection *conn)
472
if (conn->reconnect_attempts > IMAP_URLAUTH_RECONNECT_MAX_ATTEMPTS) {
473
imap_urlauth_connection_abort(conn,
474
"Connection failed and connection attempts exhausted");
476
imap_urlauth_connection_reconnect(conn);
481
imap_urlauth_connection_create_temp_fd(struct imap_urlauth_connection *conn,
487
path = t_str_new(128);
488
mail_user_set_get_temp_prefix(path, conn->user->set);
489
fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
491
i_error("safe_mkstemp(%s) failed: %m", str_c(path));
495
/* we just want the fd, unlink it */
496
if (unlink(str_c(path)) < 0) {
497
/* shouldn't happen.. */
498
i_error("unlink(%s) failed: %m", str_c(path));
503
*path_r = str_c(path);
508
imap_urlauth_connection_read_literal_init(struct imap_urlauth_connection *conn,
513
i_assert(conn->literal_fd == -1 && conn->literal_buf == NULL);
515
if (size <= IMAP_URLAUTH_MAX_INLINE_LITERAL_SIZE) {
516
/* read the literal directly */
519
buffer_create_dynamic(default_pool, size);
522
/* read it into a file */
524
imap_urlauth_connection_create_temp_fd(conn, &path);
525
if (conn->literal_fd == -1)
527
conn->literal_temp_path = i_strdup(path);
530
conn->literal_size = size;
531
conn->literal_bytes_left = size;
532
conn->reading_literal = TRUE;
536
void imap_urlauth_connection_continue(struct imap_urlauth_connection *conn)
538
i_assert(conn->targets_head != NULL);
539
i_assert(conn->targets_head->requests_head != NULL);
541
if (conn->state != IMAP_URLAUTH_STATE_REQUEST_WAIT)
544
conn->state = IMAP_URLAUTH_STATE_READY;
545
imap_urlauth_request_free(conn->targets_head->requests_head);
547
imap_urlauth_connection_send_request(conn);
551
imap_urlauth_connection_read_literal_data(struct imap_urlauth_connection *conn)
553
const unsigned char *data;
557
data = i_stream_get_data(conn->input, &size);
558
if (size > conn->literal_bytes_left)
559
size = conn->literal_bytes_left;
561
/* write to buffer or file */
563
if (conn->literal_fd >= 0) {
564
if (write_full(conn->literal_fd, data, size) < 0) {
565
i_error("imap-urlauth: write(%s) failed: %m",
566
conn->literal_temp_path);
570
i_assert(conn->literal_buf != NULL);
571
buffer_append(conn->literal_buf, data, size);
573
i_stream_skip(conn->input, size);
574
conn->literal_bytes_left -= size;
577
/* exit if not finished */
578
if (conn->literal_bytes_left > 0)
582
data = i_stream_get_data(conn->input, &size);
587
if (data[0] != '\n') {
588
i_error("imap-urlauth: no LF at end of literal (found 0x%x)",
592
i_stream_skip(conn->input, 1);
596
static void literal_stream_destroy(buffer_t *buffer)
598
buffer_free(&buffer);
602
imap_urlauth_fetch_reply_set_literal_stream(struct imap_urlauth_connection *conn,
603
struct imap_urlauth_fetch_reply *reply)
605
const unsigned char *data;
609
if (conn->literal_fd != -1) {
610
reply->input = i_stream_create_fd(conn->literal_fd,
612
if (i_stream_get_size(reply->input, TRUE, &fd_size) < 1 ||
613
fd_size != conn->literal_size) {
614
i_stream_unref(&reply->input);
615
i_error("imap-urlauth: Failed to obtain proper size from literal stream");
616
imap_urlauth_connection_abort(conn,
617
"Failed during literal transfer");
621
data = buffer_get_data(conn->literal_buf, &size);
622
i_assert(size == conn->literal_size);
623
reply->input = i_stream_create_from_data(data, size);
624
i_stream_add_destroy_callback(reply->input,
625
literal_stream_destroy,
628
reply->size = conn->literal_size;
633
imap_urlauth_connection_read_literal(struct imap_urlauth_connection *conn)
635
struct imap_urlauth_request *urlreq = conn->targets_head->requests_head;
636
struct imap_urlauth_fetch_reply reply;
637
imap_urlauth_request_callback_t *callback;
640
i_assert(conn->reading_literal);
641
i_assert(urlreq != NULL);
643
if (conn->literal_size > 0) {
644
ret = imap_urlauth_connection_read_literal_data(conn);
648
i_assert(conn->literal_bytes_left == 0);
651
memset(&reply, 0, sizeof(reply));
652
reply.url = urlreq->url;
653
reply.flags = urlreq->flags;
654
reply.bodypartstruct = urlreq->bodypartstruct;
655
reply.binary_has_nuls = urlreq->binary_has_nuls;
657
if (conn->literal_size > 0) {
658
if (imap_urlauth_fetch_reply_set_literal_stream(conn, &reply) < 0)
661
reply.succeeded = TRUE;
664
callback = urlreq->callback;
665
urlreq->callback = NULL;
666
if (callback != NULL) T_BEGIN {
667
ret = callback(&reply, urlreq->context);
670
if (reply.input != NULL)
671
i_stream_unref(&reply.input);
674
/* Drop any related requests upon error */
675
imap_urlauth_request_abort_by_context(conn, urlreq->context);
678
conn->state = IMAP_URLAUTH_STATE_REQUEST_WAIT;
680
imap_urlauth_connection_continue(conn);
683
i_free_and_null(conn->literal_temp_path);
684
conn->literal_fd = -1;
685
conn->literal_buf = NULL;
686
conn->reading_literal = FALSE;
690
static int imap_urlauth_input_pending(struct imap_urlauth_connection *conn)
692
struct imap_urlauth_request *urlreq;
693
const char *response, *const *args, *bpstruct = NULL;
696
i_assert(conn->targets_head != NULL);
697
i_assert(conn->targets_head->requests_head != NULL);
698
urlreq = conn->targets_head->requests_head;
700
if (conn->reading_literal) {
701
/* Read pending literal; may callback */
702
return imap_urlauth_connection_read_literal(conn);
705
/* "OK"[<metadata-items>]"\t"<literal-size>"\n" or
706
"NO"["\terror="<error>]"\n" */
707
if ((response = i_stream_next_line(conn->input)) == NULL)
709
imap_urlauth_stop_response_timeout(conn);
711
args = t_strsplit_tabescaped(response);
712
if (args[0] == NULL) {
713
i_error("imap-urlauth: Empty URL response: %s",
714
str_sanitize(response, 80));
718
if (strcmp(args[0], "OK") != 0 || args[1] == NULL) {
719
if (strcmp(args[0], "NO") == 0) {
720
const char *param = args[1], *error = NULL;
723
strncasecmp(param, "error=", 6) == 0 &&
727
conn->state = IMAP_URLAUTH_STATE_REQUEST_WAIT;
728
imap_urlauth_request_fail(conn,
729
conn->targets_head->requests_head, error);
732
i_error("imap-urlauth: Unexpected URL response: %s",
733
str_sanitize(response, 80));
739
for (; args[1] != NULL; args++) {
740
const char *param = args[0];
742
if (strcasecmp(param, "hasnuls") == 0) {
743
urlreq->binary_has_nuls = TRUE;
744
} else if (strncasecmp(param, "bpstruct=", 9) == 0 &&
750
/* read literal size */
751
if (str_to_uoff(args[0], &literal_size) < 0) {
752
i_error("imap-urlauth: "
753
"Overflowing unsigned integer value for literal size: %s",
759
if (imap_urlauth_connection_read_literal_init(conn, literal_size) < 0)
762
urlreq->bodypartstruct = i_strdup(bpstruct);
763
return imap_urlauth_connection_read_literal(conn);
766
static int imap_urlauth_input_next(struct imap_urlauth_connection *conn)
768
const char *response;
771
switch (conn->state) {
772
case IMAP_URLAUTH_STATE_AUTHENTICATING:
773
case IMAP_URLAUTH_STATE_UNSELECTING_TARGET:
774
if ((response = i_stream_next_line(conn->input)) == NULL)
776
imap_urlauth_stop_response_timeout(conn);
778
if (strcasecmp(response, "OK") != 0) {
779
if (conn->state == IMAP_URLAUTH_STATE_AUTHENTICATING)
780
i_error("imap-urlauth: Failed to authenticate to service: "
781
"Got unexpected response: %s", str_sanitize(response, 80));
783
i_error("imap-urlauth: Failed to unselect target user: "
784
"Got unexpected response: %s", str_sanitize(response, 80));
785
imap_urlauth_connection_abort(conn, NULL);
789
if (conn->user->mail_debug) {
790
if (conn->state == IMAP_URLAUTH_STATE_AUTHENTICATING)
791
i_debug("imap-urlauth: Successfully authenticated to service");
793
i_debug("imap-urlauth: Successfully unselected target user");
796
conn->state = IMAP_URLAUTH_STATE_AUTHENTICATED;
797
imap_urlauth_connection_select_target(conn);
799
case IMAP_URLAUTH_STATE_SELECTING_TARGET:
800
if ((response = i_stream_next_line(conn->input)) == NULL)
802
imap_urlauth_stop_response_timeout(conn);
804
i_assert(conn->targets_head != NULL);
806
if (strcasecmp(response, "NO") == 0) {
807
if (conn->user->mail_debug) {
808
i_debug("imap-urlauth: Failed to select target user %s",
809
conn->targets_head->userid);
811
imap_urlauth_target_fail(conn, conn->targets_head, NULL);
813
conn->state = IMAP_URLAUTH_STATE_AUTHENTICATED;
814
imap_urlauth_connection_select_target(conn);
817
if (strcasecmp(response, "OK") != 0) {
818
i_error("imap-urlauth: Failed to select target user %s: "
819
"Got unexpected response: %s", conn->targets_head->userid,
820
str_sanitize(response, 80));
821
imap_urlauth_connection_abort(conn, NULL);
825
if (conn->user->mail_debug) {
826
i_debug("imap-urlauth: Successfully selected target user %s",
827
conn->targets_head->userid);
829
conn->state = IMAP_URLAUTH_STATE_READY;
830
imap_urlauth_connection_send_request(conn);
832
case IMAP_URLAUTH_STATE_AUTHENTICATED:
833
case IMAP_URLAUTH_STATE_READY:
834
case IMAP_URLAUTH_STATE_REQUEST_WAIT:
835
if ((response = i_stream_next_line(conn->input)) == NULL)
838
i_error("imap-urlauth: Received input while no requests were pending");
839
imap_urlauth_connection_abort(conn, NULL);
841
case IMAP_URLAUTH_STATE_REQUEST_PENDING:
842
if ((ret = imap_urlauth_input_pending(conn)) < 0)
843
imap_urlauth_connection_fail(conn);
845
case IMAP_URLAUTH_STATE_DISCONNECTED:
851
static void imap_urlauth_input(struct imap_urlauth_connection *conn)
855
i_assert(conn->state != IMAP_URLAUTH_STATE_DISCONNECTED);
857
if (conn->input->closed) {
859
i_error("imap-urlauth: Service disconnected unexpectedly");
860
imap_urlauth_connection_fail(conn);
864
switch (i_stream_read(conn->input)) {
867
i_error("imap-urlauth: Service disconnected unexpectedly");
868
imap_urlauth_connection_fail(conn);
871
/* input buffer full */
872
i_error("imap-urlauth: Service sent too large input");
873
imap_urlauth_connection_abort(conn, NULL);
877
while (!conn->input->closed) {
878
if ((ret = imap_urlauth_input_next(conn)) <= 0)
884
imap_urlauth_connection_do_connect(struct imap_urlauth_connection *conn)
889
if (conn->state != IMAP_URLAUTH_STATE_DISCONNECTED) {
890
imap_urlauth_connection_send_request(conn);
894
if (conn->user->auth_token == NULL) {
895
i_error("imap-urlauth: cannot authenticate because no auth token "
896
"is available for this session (standalone IMAP?).");
897
imap_urlauth_connection_abort(conn, NULL);
901
if (conn->user->mail_debug)
902
i_debug("imap-urlauth: Connecting to service at %s", conn->path);
904
i_assert(conn->fd == -1);
905
fd = net_connect_unix(conn->path);
907
i_error("imap-urlauth: net_connect_unix(%s) failed: %m",
909
imap_urlauth_connection_abort(conn, NULL);
913
if (conn->to_reconnect != NULL)
914
timeout_remove(&conn->to_reconnect);
917
conn->input = i_stream_create_fd(fd, (size_t)-1, FALSE);
918
conn->output = o_stream_create_fd(fd, (size_t)-1, FALSE);
919
conn->io = io_add(fd, IO_READ, imap_urlauth_input, conn);
920
conn->state = IMAP_URLAUTH_STATE_AUTHENTICATING;
922
str = t_str_new(128);
923
str_printfa(str, IMAP_URLAUTH_HANDSHAKE"AUTH\t%s\t", my_pid);
924
str_append_tabescaped(str, conn->user->username);
925
str_append_c(str, '\t');
926
if (conn->session_id != NULL)
927
str_append_tabescaped(str, conn->session_id);
928
str_append_c(str, '\t');
929
str_append_tabescaped(str, conn->user->auth_token);
930
str_append_c(str, '\n');
931
if (o_stream_send(conn->output, str_data(str), str_len(str)) < 0) {
932
i_warning("Error sending handshake to imap-urlauth server: %m");
933
imap_urlauth_connection_abort(conn, NULL);
937
imap_urlauth_start_response_timeout(conn);
941
int imap_urlauth_connection_connect(struct imap_urlauth_connection *conn)
943
conn->reconnect_attempts = 0;
945
if (conn->to_reconnect == NULL)
946
return imap_urlauth_connection_do_connect(conn);
950
static void imap_urlauth_connection_disconnect
951
(struct imap_urlauth_connection *conn, const char *reason)
953
conn->state = IMAP_URLAUTH_STATE_DISCONNECTED;
955
if (conn->fd != -1) {
956
if (conn->user->mail_debug) {
958
i_debug("imap-urlauth: Disconnecting from service");
960
i_debug("imap-urlauth: Disconnected: %s", reason);
963
io_remove(&conn->io);
964
i_stream_destroy(&conn->input);
965
o_stream_destroy(&conn->output);
966
net_disconnect(conn->fd);
969
conn->reading_literal = FALSE;
971
if (conn->literal_fd != -1) {
972
if (close(conn->literal_fd) < 0)
973
i_error("imap-urlauth: close(%s) failed: %m", conn->literal_temp_path);
975
i_free_and_null(conn->literal_temp_path);
976
conn->literal_fd = -1;
979
if (conn->literal_buf != NULL)
980
buffer_free(&conn->literal_buf);
981
if (conn->to_reconnect != NULL)
982
timeout_remove(&conn->to_reconnect);
983
if (conn->to_idle != NULL)
984
timeout_remove(&conn->to_idle);
985
imap_urlauth_stop_response_timeout(conn);
989
imap_urlauth_connection_do_reconnect(struct imap_urlauth_connection *conn)
991
if (conn->reconnect_attempts >= IMAP_URLAUTH_RECONNECT_MAX_ATTEMPTS) {
992
imap_urlauth_connection_abort(conn,
993
"Connection failed and connection attempts exhausted");
997
if (ioloop_time - conn->last_reconnect < IMAP_URLAUTH_RECONNECT_MIN_SECS) {
998
if (conn->user->mail_debug)
999
i_debug("imap-urlauth: Scheduling reconnect");
1000
if (conn->to_reconnect != NULL)
1001
timeout_remove(&conn->to_reconnect);
1002
conn->to_reconnect =
1003
timeout_add(IMAP_URLAUTH_RECONNECT_MIN_SECS*1000,
1004
imap_urlauth_connection_do_reconnect, conn);
1006
conn->reconnect_attempts++;
1007
conn->last_reconnect = ioloop_time;
1008
(void)imap_urlauth_connection_do_connect(conn);
1013
imap_urlauth_connection_reconnect(struct imap_urlauth_connection *conn)
1015
imap_urlauth_connection_disconnect(conn, NULL);
1017
/* don't reconnect if there are no requests */
1018
if (conn->targets_head == NULL)
1021
imap_urlauth_connection_do_reconnect(conn);
1025
imap_urlauth_connection_idle_disconnect(struct imap_urlauth_connection *conn)
1027
imap_urlauth_connection_disconnect(conn, "Idle timeout");
1031
imap_urlauth_connection_timeout_abort(struct imap_urlauth_connection *conn)
1033
imap_urlauth_connection_abort(conn, "Service is not responding");
1036
bool imap_urlauth_connection_is_connected(struct imap_urlauth_connection *conn)
1038
return conn->fd != -1 && conn->state != IMAP_URLAUTH_STATE_DISCONNECTED;