Coverage Report

Created: 2026-06-15 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-sasl/sasl-server-request.c
Line
Count
Source
1
/* Copyright (c) 2023 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "str-sanitize.h"
5
#include "buffer.h"
6
7
#include "sasl-server-private.h"
8
9
/*
10
 * Public API
11
 */
12
13
void sasl_server_request_create(struct sasl_server_req_ctx *rctx,
14
        const struct sasl_server_mech *mech,
15
        const char *protocol,
16
        struct event *event_parent)
17
7.86k
{
18
7.86k
  struct sasl_server_instance *sinst = mech->sinst;
19
7.86k
  struct sasl_server *server = sinst->server;
20
7.86k
  struct sasl_server_request *req;
21
7.86k
  pool_t pool;
22
23
7.86k
  i_assert(mech->def != NULL);
24
7.86k
  i_assert(mech->def->funcs != NULL);
25
26
7.86k
  i_zero(rctx);
27
28
7.86k
  pool = pool_alloconly_create(
29
7.86k
    MEMPOOL_GROWING"sasl_server_request", 2048);
30
7.86k
  req = p_new(pool, struct sasl_server_request, 1);
31
7.86k
  req->pool = pool;
32
7.86k
  req->refcount = 1;
33
7.86k
  req->sinst = sinst;
34
7.86k
  req->rctx = rctx;
35
36
7.86k
  sinst->requests++;
37
7.86k
  server->requests++;
38
39
7.86k
  if (event_parent == NULL) {
40
7.86k
    req->event = event_create(sinst->event);
41
7.86k
    event_drop_parent_log_prefixes(req->event, 1);
42
7.86k
  } else {
43
0
    req->event = event_create(event_parent);
44
0
    event_add_category(req->event, &event_category_sasl_server);
45
0
  }
46
7.86k
  event_set_append_log_prefix(req->event,
47
7.86k
    t_strdup_printf("sasl(%s): ", t_str_lcase(mech->def->name)));
48
49
7.86k
  struct sasl_server_mech_request *mreq;
50
51
7.86k
  if (mech->def->funcs->auth_new != NULL)
52
7.24k
    mreq = mech->def->funcs->auth_new(mech, pool);
53
615
  else
54
615
    mreq = p_new(pool, struct sasl_server_mech_request, 1);
55
7.86k
  mreq->pool = pool;
56
7.86k
  mreq->req = req;
57
7.86k
  mreq->set = &sinst->set;
58
7.86k
  mreq->mech = mech;
59
7.86k
  mreq->event = req->event;
60
7.86k
  mreq->protocol = p_strdup(pool, protocol);
61
62
7.86k
  req->mech = mreq;
63
7.86k
  rctx->mech = mech;
64
7.86k
  rctx->mech_name = mech->def->name;
65
7.86k
  rctx->request = req;
66
67
7.86k
  e_debug(req->event, "Request create");
68
7.86k
}
69
70
void sasl_server_mech_request_ref(struct sasl_server_mech_request *mreq)
71
16.9k
{
72
16.9k
  i_assert(mreq->req->refcount > 0);
73
16.9k
  mreq->req->refcount++;
74
16.9k
}
75
76
void sasl_server_mech_request_unref(struct sasl_server_mech_request **_mreq)
77
24.8k
{
78
24.8k
  struct sasl_server_mech_request *mreq = *_mreq;
79
80
24.8k
  *_mreq = NULL;
81
24.8k
  if (mreq == NULL)
82
0
    return;
83
84
24.8k
  struct sasl_server_request *req = mreq->req;
85
86
24.8k
  i_assert(req->refcount > 0);
87
24.8k
  if (--req->refcount > 0)
88
16.9k
    return;
89
90
7.86k
  struct sasl_server_instance *sinst = req->sinst;
91
7.86k
  struct sasl_server *server = sinst->server;
92
7.86k
  const struct sasl_server_request_funcs *funcs = server->funcs;
93
94
7.86k
  i_assert(sinst->requests > 0);
95
7.86k
  sinst->requests--;
96
7.86k
  i_assert(server->requests > 0);
97
7.86k
  server->requests--;
98
99
7.86k
  if (funcs->request_free != NULL && req->rctx != NULL)
100
0
    funcs->request_free(req->rctx);
101
7.86k
  if (mreq->mech->def->funcs->auth_free != NULL)
102
4.38k
    mreq->mech->def->funcs->auth_free(mreq);
103
104
7.86k
  e_debug(req->event, "Request destroy");
105
106
7.86k
  if (req->rctx != NULL)
107
0
    i_zero(req->rctx);
108
7.86k
  event_unref(&req->event);
109
7.86k
  pool_unref(&req->pool);
110
7.86k
}
111
112
void sasl_server_request_ref(struct sasl_server_req_ctx *rctx)
113
0
{
114
0
  sasl_server_mech_request_ref(rctx->request->mech);
115
0
}
116
117
void sasl_server_request_unref(struct sasl_server_req_ctx *rctx)
118
7.86k
{
119
7.86k
  struct sasl_server_request *req = rctx->request;
120
121
7.86k
  i_zero(rctx);
122
7.86k
  if (req == NULL)
123
0
    return;
124
125
7.86k
  struct sasl_server_mech_request *mreq = req->mech;
126
127
7.86k
  sasl_server_mech_request_unref(&mreq);
128
7.86k
}
129
130
void sasl_server_request_destroy(struct sasl_server_req_ctx *rctx)
131
7.86k
{
132
7.86k
  struct sasl_server_request *req = rctx->request;
133
134
7.86k
  if (req == NULL) {
135
0
    i_zero(rctx);
136
0
    return;
137
0
  }
138
139
7.86k
  req->rctx = NULL;
140
7.86k
  sasl_server_request_unref(rctx);
141
7.86k
}
142
143
static bool
144
sasl_server_request_fail_on_size(struct sasl_server_request *req,
145
         size_t data_size)
146
16.8k
{
147
16.8k
  if (data_size > (size_t)SASL_MAX_MESSAGE_SIZE) {
148
    /* We should normally never get here, because the limit enforced
149
       by the auth service is smaller.
150
     */
151
296
    e_debug(req->event, "Excessive response size (> %d)",
152
296
      SASL_MAX_MESSAGE_SIZE);
153
296
    sasl_server_request_failure(req->mech);
154
296
    return TRUE;
155
296
  }
156
16.5k
  return FALSE;
157
16.8k
}
158
159
static bool
160
sasl_server_request_fail_on_nuls(struct sasl_server_request *req,
161
         const unsigned char *data, size_t data_size)
162
16.5k
{
163
16.5k
  const struct sasl_server_mech *mech = req->mech->mech;
164
165
16.5k
  if ((mech->def->flags & SASL_MECH_SEC_ALLOW_NULS) != 0)
166
6.21k
    return FALSE;
167
10.3k
  if (memchr(data, '\0', data_size) != NULL) {
168
39
    e_debug(req->event, "Unexpected NUL in auth data");
169
39
    sasl_server_request_failure(req->mech);
170
39
    return TRUE;
171
39
  }
172
10.3k
  return FALSE;
173
10.3k
}
174
175
void sasl_server_request_initial(struct sasl_server_req_ctx *rctx,
176
         const unsigned char *data, size_t data_size)
177
7.86k
{
178
7.86k
  struct sasl_server_request *req = rctx->request;
179
7.86k
  struct sasl_server_mech_request *mreq = req->mech;
180
7.86k
  const struct sasl_server_mech *mech = mreq->mech;
181
182
7.86k
  i_assert(data != NULL || data_size == 0);
183
184
7.86k
  if (data == NULL) {
185
7.03k
    e_debug(req->event,
186
7.03k
      "Started interaction without initial response");
187
7.03k
  } else {
188
828
    e_debug(req->event,
189
828
      "Started interaction with initial response (size=%zu)",
190
828
      data_size);
191
828
  }
192
193
7.86k
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_NEW);
194
7.86k
  req->state = SASL_SERVER_REQUEST_STATE_SERVER;
195
196
7.86k
  if (sasl_server_request_fail_on_size(req, data_size))
197
81
    return;
198
7.78k
  if (sasl_server_request_fail_on_nuls(req, data, data_size))
199
10
    return;
200
201
7.77k
  sasl_server_mech_request_ref(mreq);
202
7.77k
  i_assert(mech->def->funcs->auth_initial != NULL);
203
7.77k
  mech->def->funcs->auth_initial(mreq, data, data_size);
204
7.77k
  sasl_server_mech_request_unref(&mreq);
205
7.77k
}
206
207
void sasl_server_request_input(struct sasl_server_req_ctx *rctx,
208
             const unsigned char *data, size_t data_size)
209
9.03k
{
210
9.03k
  struct sasl_server_request *req = rctx->request;
211
9.03k
  struct sasl_server_mech_request *mreq = req->mech;
212
9.03k
  const struct sasl_server_mech *mech = mreq->mech;
213
214
9.03k
  i_assert(data != NULL || data_size == 0);
215
216
9.03k
  e_debug(req->event,
217
9.03k
    "Client continued interaction with response (size=%zu)",
218
9.03k
    data_size);
219
220
9.03k
  if (req->state == SASL_SERVER_REQUEST_STATE_FINISHED &&
221
0
      req->finished_with_data) {
222
0
    req->state = SASL_SERVER_REQUEST_STATE_SERVER;
223
0
    if (!req->failed)
224
0
      sasl_server_request_success(mreq, "", 0);
225
0
    else
226
0
      sasl_server_request_failure(mreq);
227
0
    return;
228
0
  }
229
9.03k
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_CLIENT);
230
9.03k
  i_assert(!req->finished_with_data);
231
9.03k
  req->state = SASL_SERVER_REQUEST_STATE_SERVER;
232
233
9.03k
  if (sasl_server_request_fail_on_size(req, data_size))
234
215
    return;
235
8.81k
  if (sasl_server_request_fail_on_nuls(req, data, data_size))
236
29
    return;
237
238
8.78k
  sasl_server_mech_request_ref(mreq);
239
8.78k
  i_assert(mech->def->funcs->auth_continue != NULL);
240
8.78k
  mech->def->funcs->auth_continue(mreq, data, data_size);
241
8.78k
  sasl_server_mech_request_unref(&mreq);
242
8.78k
}
243
244
bool sasl_server_request_has_failed(const struct sasl_server_req_ctx *rctx)
245
0
{
246
0
  return rctx->request->failed;
247
0
}
248
249
void sasl_server_request_test_set_authid(struct sasl_server_req_ctx *rctx,
250
           const char *authid)
251
0
{
252
0
  struct sasl_server_request *req = rctx->request;
253
254
0
  req->mech->authid = p_strdup(req->mech->pool, authid);
255
0
}
256
257
/*
258
 * Mechanism API
259
 */
260
261
bool sasl_server_request_set_authid(struct sasl_server_mech_request *mreq,
262
            enum sasl_server_authid_type authid_type,
263
            const char *authid)
264
5.88k
{
265
5.88k
  struct sasl_server_request *req = mreq->req;
266
5.88k
  struct sasl_server *server = req->sinst->server;
267
5.88k
  const struct sasl_server_request_funcs *funcs = server->funcs;
268
269
5.88k
  if (strlen(authid) > (size_t)SASL_MAX_AUTHID_SIZE) {
270
126
    e_debug(req->event, "Failed to set authid: "
271
126
      "Maximum length exceeded (> %d)", SASL_MAX_AUTHID_SIZE);
272
126
    req->failed = TRUE;
273
126
    return FALSE;
274
126
  }
275
276
5.76k
  mreq->authid = p_strdup(req->pool, authid);
277
278
5.76k
  i_assert(req->rctx != NULL);
279
5.76k
  i_assert(funcs->request_set_authid != NULL);
280
5.76k
  if (!funcs->request_set_authid(req->rctx, authid_type, authid)) {
281
2
    e_debug(req->event, "Failed to set authid '%s'",
282
2
      str_sanitize(authid, 256));
283
2
    req->failed = TRUE;
284
2
    return FALSE;
285
2
  }
286
287
5.76k
  e_debug(req->event, "Set authid '%s'", str_sanitize(authid, 256));
288
5.76k
  return TRUE;
289
5.76k
}
290
291
bool sasl_server_request_set_authzid(struct sasl_server_mech_request *mreq,
292
             const char *authzid)
293
1.81k
{
294
1.81k
  struct sasl_server_request *req = mreq->req;
295
1.81k
  struct sasl_server *server = req->sinst->server;
296
1.81k
  const struct sasl_server_request_funcs *funcs = server->funcs;
297
298
1.81k
  if (strlen(authzid) > (size_t)SASL_MAX_AUTHID_SIZE) {
299
26
    e_debug(req->event, "Failed to set authzid: "
300
26
      "Maximum length exceeded (> %d)", SASL_MAX_AUTHID_SIZE);
301
26
    req->failed = TRUE;
302
26
    return FALSE;
303
26
  }
304
305
1.81k
  i_assert(req->rctx != NULL);
306
1.79k
  i_assert(funcs->request_set_authzid != NULL);
307
1.79k
  if (!funcs->request_set_authzid(req->rctx, authzid)) {
308
2
    e_debug(req->event, "Failed to set authzid '%s'",
309
2
      str_sanitize(authzid, 256));
310
2
    req->failed = TRUE;
311
2
    return FALSE;
312
2
  }
313
314
1.79k
  e_debug(req->event, "Set authzid '%s'", str_sanitize(authzid, 256));
315
1.78k
  return TRUE;
316
1.79k
}
317
318
void sasl_server_request_set_realm(struct sasl_server_mech_request *mreq,
319
           const char *realm)
320
77
{
321
77
  struct sasl_server_request *req = mreq->req;
322
77
  struct sasl_server *server = req->sinst->server;
323
77
  const struct sasl_server_request_funcs *funcs = server->funcs;
324
325
77
  i_assert(mreq->realm == NULL);
326
77
  mreq->realm = p_strdup(req->pool, realm);
327
328
77
  i_assert(req->rctx != NULL);
329
77
  i_assert(funcs->request_set_realm != NULL);
330
77
  funcs->request_set_realm(req->rctx, realm);
331
332
77
  e_debug(req->event, "Set realm '%s'", str_sanitize(realm, 256));
333
77
}
334
335
bool sasl_server_request_get_extra_field(struct sasl_server_mech_request *mreq,
336
           const char *name,
337
           const char **field_r)
338
0
{
339
0
  struct sasl_server_request *req = mreq->req;
340
0
  struct sasl_server *server = req->sinst->server;
341
0
  const struct sasl_server_request_funcs *funcs = server->funcs;
342
343
0
  i_assert(req->rctx != NULL);
344
0
  if (funcs->request_get_extra_field == NULL) {
345
0
    *field_r = NULL;
346
0
    return FALSE;
347
0
  }
348
0
  return funcs->request_get_extra_field(req->rctx, name, field_r);
349
0
}
350
351
void sasl_server_request_start_channel_binding(
352
  struct sasl_server_mech_request *mreq, const char *type)
353
506
{
354
506
  struct sasl_server_request *req = mreq->req;
355
506
  struct sasl_server *server = req->sinst->server;
356
506
  const struct sasl_server_request_funcs *funcs = server->funcs;
357
358
506
  e_debug(req->event, "Request channel binding '%s'",
359
506
    str_sanitize(type, 64));
360
361
506
  i_assert(req->rctx != NULL);
362
506
  i_assert(funcs->request_start_channel_binding != NULL);
363
506
  funcs->request_start_channel_binding(req->rctx, type);
364
506
}
365
366
int sasl_server_request_accept_channel_binding(
367
  struct sasl_server_mech_request *mreq, buffer_t **data_r)
368
362
{
369
362
  struct sasl_server_request *req = mreq->req;
370
362
  struct sasl_server *server = req->sinst->server;
371
362
  const struct sasl_server_request_funcs *funcs = server->funcs;
372
362
  int ret;
373
374
362
  i_assert(req->rctx != NULL);
375
362
  i_assert(funcs->request_accept_channel_binding != NULL);
376
362
  ret = funcs->request_accept_channel_binding(req->rctx, data_r);
377
362
  if (ret < 0) {
378
0
    e_debug(req->event, "Failed to obtain channel binding data");
379
0
    return -1;
380
0
  }
381
382
362
  e_debug(req->event, "Obtained channel binding data (size=%zu)",
383
362
    (*data_r)->used);
384
362
  return 0;
385
362
}
386
387
void sasl_server_request_output(struct sasl_server_mech_request *mreq,
388
        const void *data, size_t data_size)
389
10.4k
{
390
10.4k
  struct sasl_server_request *req = mreq->req;
391
10.4k
  struct sasl_server *server = req->sinst->server;
392
10.4k
  const struct sasl_server_request_funcs *funcs = server->funcs;
393
394
10.4k
  i_assert(req->rctx != NULL);
395
396
10.4k
  i_assert(!req->failed);
397
10.4k
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_NEW ||
398
10.4k
     req->state == SASL_SERVER_REQUEST_STATE_SERVER ||
399
10.4k
     req->state == SASL_SERVER_REQUEST_STATE_PASSDB);
400
10.4k
  req->state = SASL_SERVER_REQUEST_STATE_CLIENT;
401
10.4k
  req->sequence++;
402
403
10.4k
  e_debug(req->event,
404
10.4k
    "Server continued interaction with challenge (size=%zu)",
405
10.4k
    data_size);
406
407
10.4k
  const struct sasl_server_output output = {
408
10.4k
    .status = SASL_SERVER_OUTPUT_CONTINUE,
409
10.4k
    .data = data,
410
10.4k
    .data_size = data_size,
411
10.4k
  };
412
10.4k
  i_assert(funcs->request_output != NULL);
413
10.4k
  funcs->request_output(req->rctx, &output);
414
10.4k
}
415
416
void sasl_server_request_success(struct sasl_server_mech_request *mreq,
417
         const void *data, size_t data_size)
418
1.35k
{
419
1.35k
  struct sasl_server_request *req = mreq->req;
420
1.35k
  struct sasl_server *server = req->sinst->server;
421
1.35k
  const struct sasl_server_request_funcs *funcs = server->funcs;
422
423
1.35k
  i_assert(req->rctx != NULL);
424
425
1.35k
  i_assert(!req->failed);
426
1.35k
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_NEW ||
427
1.35k
     req->state == SASL_SERVER_REQUEST_STATE_SERVER ||
428
1.35k
     req->state == SASL_SERVER_REQUEST_STATE_PASSDB);
429
1.35k
  req->state = SASL_SERVER_REQUEST_STATE_FINISHED;
430
1.35k
  req->sequence++;
431
1.35k
  if (data_size > 0) {
432
913
    e_debug(req->event,
433
913
      "Interaction succeeded with final data (size=%zu)",
434
913
      data_size);
435
913
    i_assert(!req->finished_with_data);
436
913
    req->finished_with_data = TRUE;
437
913
  } else {
438
444
    e_debug(req->event, "Interaction succeeded");
439
444
  }
440
441
1.35k
  const struct sasl_server_output output = {
442
1.35k
    .status = SASL_SERVER_OUTPUT_SUCCESS,
443
1.35k
    .data = data,
444
1.35k
    .data_size = data_size,
445
1.35k
  };
446
1.35k
  i_assert(funcs->request_output != NULL);
447
1.35k
  funcs->request_output(req->rctx, &output);
448
1.35k
}
449
450
static void
451
sasl_server_request_failure_common(struct sasl_server_mech_request *mreq,
452
           enum sasl_server_output_status status,
453
           const void *data, size_t data_size)
454
5.08k
{
455
5.08k
  struct sasl_server_request *req = mreq->req;
456
5.08k
  struct sasl_server *server = req->sinst->server;
457
5.08k
  const struct sasl_server_request_funcs *funcs = server->funcs;
458
459
5.08k
  i_assert(req->rctx != NULL);
460
461
5.08k
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_NEW ||
462
5.08k
     req->state == SASL_SERVER_REQUEST_STATE_SERVER ||
463
5.08k
     req->state == SASL_SERVER_REQUEST_STATE_PASSDB);
464
5.08k
  req->state = SASL_SERVER_REQUEST_STATE_FINISHED;
465
5.08k
  req->sequence++;
466
5.08k
  req->failed = TRUE;
467
5.08k
  if (data_size > 0) {
468
684
    i_assert(status != SASL_SERVER_OUTPUT_INTERNAL_FAILURE);
469
684
    i_assert(status != SASL_SERVER_OUTPUT_PASSWORD_MISMATCH);
470
684
    i_assert(!req->finished_with_data);
471
684
    req->finished_with_data = TRUE;
472
684
    e_debug(req->event,
473
684
      "Interaction failed with final data (size=%zu)",
474
684
      data_size);
475
4.39k
  } else if (status == SASL_SERVER_OUTPUT_PASSWORD_MISMATCH) {
476
553
    e_debug(req->event, "Interaction failed: Password mismatch");
477
3.84k
  } else if (status == SASL_SERVER_OUTPUT_INTERNAL_FAILURE) {
478
0
    e_debug(req->event, "Interaction failed (internal failure)");
479
3.84k
  } else {
480
3.84k
    e_debug(req->event, "Interaction failed");
481
3.84k
  }
482
483
5.08k
  const struct sasl_server_output output = {
484
5.08k
    .status = status,
485
5.08k
    .data = data,
486
5.08k
    .data_size = data_size,
487
5.08k
  };
488
5.08k
  i_assert(funcs->request_output != NULL);
489
5.08k
  funcs->request_output(req->rctx, &output);
490
5.08k
}
491
492
void sasl_server_request_failure_with_reply(
493
  struct sasl_server_mech_request *mreq,
494
  const void *data, size_t data_size)
495
684
{
496
684
  sasl_server_request_failure_common(mreq, SASL_SERVER_OUTPUT_FAILURE,
497
684
             data, data_size);
498
684
}
499
500
void sasl_server_request_failure(struct sasl_server_mech_request *mreq)
501
3.84k
{
502
3.84k
  sasl_server_request_failure_common(mreq, SASL_SERVER_OUTPUT_FAILURE,
503
3.84k
             "", 0);
504
3.84k
}
505
506
void sasl_server_request_password_mismatch(
507
  struct sasl_server_mech_request *mreq)
508
553
{
509
553
  sasl_server_request_failure_common(
510
553
    mreq, SASL_SERVER_OUTPUT_PASSWORD_MISMATCH, "", 0);
511
553
}
512
513
void sasl_server_request_internal_failure(
514
  struct sasl_server_mech_request *mreq)
515
0
{
516
0
  sasl_server_request_failure_common(
517
0
    mreq, SASL_SERVER_OUTPUT_INTERNAL_FAILURE, "", 0);
518
0
}
519
520
static const char *
521
sasl_passdb_result_to_string(enum sasl_passdb_result_status status)
522
0
{
523
0
  switch (status) {
524
0
  case SASL_PASSDB_RESULT_INTERNAL_FAILURE:
525
0
    return "internal-failure";
526
0
  case SASL_PASSDB_RESULT_SCHEME_NOT_AVAILABLE:
527
0
    return "scheme-not-available";
528
0
  case SASL_PASSDB_RESULT_USER_UNKNOWN:
529
0
    return "user-unknown";
530
0
  case SASL_PASSDB_RESULT_USER_DISABLED:
531
0
    return "scheme-disabled";
532
0
  case SASL_PASSDB_RESULT_PASS_EXPIRED:
533
0
    return "pass-expired";
534
0
  case SASL_PASSDB_RESULT_PASSWORD_MISMATCH:
535
0
    return "password-mismatch";
536
0
  case SASL_PASSDB_RESULT_OK:
537
0
    return "ok";
538
0
  }
539
0
  i_unreached();
540
0
}
541
542
static void
543
verify_plain_callback(struct sasl_server_req_ctx *rctx,
544
          const struct sasl_passdb_result *result)
545
578
{
546
578
  struct sasl_server_request *req = rctx->request;
547
548
578
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_PASSDB);
549
578
  req->state = SASL_SERVER_REQUEST_STATE_SERVER;
550
578
  if (result->status == SASL_PASSDB_RESULT_INTERNAL_FAILURE)
551
0
    req->failed = TRUE;
552
553
578
  e_debug(req->event, "Finished plain passdb verification (status=%s)",
554
578
    sasl_passdb_result_to_string(result->status));
555
556
578
  i_assert(req->passdb_type == SASL_SERVER_PASSDB_TYPE_VERIFY_PLAIN);
557
578
  req->passdb_callback(req->mech, result);
558
578
}
559
560
void sasl_server_request_verify_plain(
561
  struct sasl_server_mech_request *mreq, const char *password,
562
  sasl_server_mech_passdb_callback_t *callback)
563
578
{
564
578
  struct sasl_server_request *req = mreq->req;
565
578
  struct sasl_server *server = req->sinst->server;
566
578
  const struct sasl_server_request_funcs *funcs = server->funcs;
567
568
578
  i_assert(req->rctx != NULL);
569
570
578
  i_assert(!req->failed);
571
578
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_NEW ||
572
578
     req->state == SASL_SERVER_REQUEST_STATE_SERVER);
573
578
  req->state = SASL_SERVER_REQUEST_STATE_PASSDB;
574
575
578
  e_debug(req->event, "Performing plain passdb verification");
576
577
578
  req->passdb_type = SASL_SERVER_PASSDB_TYPE_VERIFY_PLAIN;
578
578
  req->passdb_callback = callback;
579
580
578
  i_assert(funcs->request_verify_plain != NULL);
581
578
  funcs->request_verify_plain(req->rctx, password,
582
578
            verify_plain_callback);
583
578
}
584
585
static void
586
lookup_credentials_callback(struct sasl_server_req_ctx *rctx,
587
          const struct sasl_passdb_result *result)
588
4.74k
{
589
4.74k
  struct sasl_server_request *req = rctx->request;
590
591
4.74k
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_PASSDB);
592
4.74k
  req->state = SASL_SERVER_REQUEST_STATE_SERVER;
593
4.74k
  if (result->status == SASL_PASSDB_RESULT_INTERNAL_FAILURE)
594
0
    req->failed = TRUE;
595
596
4.74k
  e_debug(req->event, "Finished passdb credentials lookup (status=%s)",
597
4.74k
    sasl_passdb_result_to_string(result->status));
598
599
4.74k
  i_assert(req->passdb_type ==
600
4.74k
     SASL_SERVER_PASSDB_TYPE_LOOKUP_CREDENTIALS);
601
4.74k
  req->passdb_callback(req->mech, result);
602
4.74k
}
603
604
void sasl_server_request_lookup_credentials(
605
  struct sasl_server_mech_request *mreq, const char *scheme,
606
  sasl_server_mech_passdb_callback_t *callback)
607
4.74k
{
608
4.74k
  struct sasl_server_request *req = mreq->req;
609
4.74k
  struct sasl_server *server = req->sinst->server;
610
4.74k
  const struct sasl_server_request_funcs *funcs = server->funcs;
611
612
4.74k
  i_assert(req->rctx != NULL);
613
614
4.74k
  i_assert(!req->failed);
615
4.74k
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_NEW ||
616
4.74k
     req->state == SASL_SERVER_REQUEST_STATE_SERVER);
617
4.74k
  req->state = SASL_SERVER_REQUEST_STATE_PASSDB;
618
619
4.74k
  e_debug(req->event, "Performing passdb credentials lookup (scheme=%s)",
620
4.74k
    scheme);
621
622
4.74k
  req->passdb_type = SASL_SERVER_PASSDB_TYPE_LOOKUP_CREDENTIALS;
623
4.74k
  req->passdb_callback = callback;
624
625
4.74k
  i_assert(funcs->request_lookup_credentials != NULL);
626
4.74k
  funcs->request_lookup_credentials(req->rctx, scheme,
627
4.74k
            lookup_credentials_callback);
628
4.74k
}
629
630
static void
631
set_credentials_callback(struct sasl_server_req_ctx *rctx,
632
       const struct sasl_passdb_result *result)
633
195
{
634
195
  struct sasl_server_request *req = rctx->request;
635
636
195
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_PASSDB);
637
195
  req->state = SASL_SERVER_REQUEST_STATE_SERVER;
638
195
  if (result->status == SASL_PASSDB_RESULT_INTERNAL_FAILURE)
639
0
    req->failed = TRUE;
640
641
195
  e_debug(req->event, "Finished updating passdb credentials (status=%s)",
642
195
    sasl_passdb_result_to_string(result->status));
643
644
195
  i_assert(req->passdb_type == SASL_SERVER_PASSDB_TYPE_SET_CREDENTIALS);
645
195
  req->passdb_callback(req->mech, result);
646
195
}
647
648
void sasl_server_request_set_credentials(
649
  struct sasl_server_mech_request *mreq,
650
  const char *scheme, const char *data,
651
  sasl_server_mech_passdb_callback_t *callback)
652
195
{
653
195
  struct sasl_server_request *req = mreq->req;
654
195
  struct sasl_server *server = req->sinst->server;
655
195
  const struct sasl_server_request_funcs *funcs = server->funcs;
656
657
195
  i_assert(req->rctx != NULL);
658
659
195
  i_assert(!req->failed);
660
195
  i_assert(req->state == SASL_SERVER_REQUEST_STATE_NEW ||
661
195
     req->state == SASL_SERVER_REQUEST_STATE_SERVER);
662
195
  req->state = SASL_SERVER_REQUEST_STATE_PASSDB;
663
664
195
  e_debug(req->event, "Updating passdb credentials (scheme=%s)",
665
195
    scheme);
666
667
195
  req->passdb_type = SASL_SERVER_PASSDB_TYPE_SET_CREDENTIALS;
668
195
  req->passdb_callback = callback;
669
670
195
  i_assert(funcs->request_set_credentials != NULL);
671
195
  funcs->request_set_credentials(req->rctx, scheme, data,
672
195
               set_credentials_callback);
673
195
}
674
675
struct sasl_server_mech_request *
676
sasl_server_request_get_mech_request(struct sasl_server_req_ctx *rctx)
677
216
{
678
216
  return rctx->request->mech;
679
216
}
680
681
struct sasl_server_req_ctx *
682
sasl_server_request_get_req_ctx(struct sasl_server_mech_request *mreq)
683
216
{
684
216
  i_assert(mreq->req->rctx != NULL);
685
216
  return mreq->req->rctx;
686
216
}