GSASL: provide $autnN for scram option expansions
[exim.git] / src / src / auths / gsasl_exim.c
1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
4
5 /* Copyright (c) The Exim Maintainers 2019 */
6 /* Copyright (c) University of Cambridge 1995 - 2018 */
7 /* See the file NOTICE for conditions of use and distribution. */
8
9 /* Copyright (c) Twitter Inc 2012
10 Author: Phil Pennock <pdp@exim.org> */
11 /* Copyright (c) Phil Pennock 2012 */
12
13 /* Interface to GNU SASL library for generic authentication. */
14
15 /* Trade-offs:
16
17 GNU SASL does not provide authentication data itself, so we have to expose
18 that decision to configuration. For some mechanisms, we need to act much
19 like plaintext. For others, we only need to be able to provide some
20 evaluated data on demand. There's no abstracted way (ie, without hardcoding
21 knowledge of authenticators here) to know which need what properties; we
22 can't query a session or the library for "we will need these for mechanism X".
23
24 So: we always require server_condition, even if sometimes it will just be
25 set as "yes". We do provide a number of other hooks, which might not make
26 sense in all contexts. For some, we can do checks at init time.
27 */
28
29 #include "../exim.h"
30 #define CHANNELBIND_HACK
31
32 #ifndef AUTH_GSASL
33 /* dummy function to satisfy compilers when we link in an "empty" file. */
34 static void dummy(int x);
35 static void dummy2(int x) { dummy(x-1); }
36 static void dummy(int x) { dummy2(x-1); }
37 #else
38
39 #include <gsasl.h>
40 #include "gsasl_exim.h"
41
42
43 #if GSASL_VERSION_MINOR >= 9
44 # define EXIM_GSASL_HAVE_SCRAM_SHA_256
45 #endif
46
47
48 /* Authenticator-specific options. */
49 /* I did have server_*_condition options for various mechanisms, but since
50 we only ever handle one mechanism at a time, I didn't see the point in keeping
51 that. In case someone sees a point, I've left the condition_check() API
52 alone. */
53 optionlist auth_gsasl_options[] = {
54 { "client_authz", opt_stringptr,
55 (void *)(offsetof(auth_gsasl_options_block, client_authz)) },
56 { "client_channelbinding", opt_bool,
57 (void *)(offsetof(auth_gsasl_options_block, client_channelbinding)) },
58 { "client_password", opt_stringptr,
59 (void *)(offsetof(auth_gsasl_options_block, client_password)) },
60 { "client_username", opt_stringptr,
61 (void *)(offsetof(auth_gsasl_options_block, client_username)) },
62
63 { "server_channelbinding", opt_bool,
64 (void *)(offsetof(auth_gsasl_options_block, server_channelbinding)) },
65 { "server_hostname", opt_stringptr,
66 (void *)(offsetof(auth_gsasl_options_block, server_hostname)) },
67 { "server_mech", opt_stringptr,
68 (void *)(offsetof(auth_gsasl_options_block, server_mech)) },
69 { "server_password", opt_stringptr,
70 (void *)(offsetof(auth_gsasl_options_block, server_password)) },
71 { "server_realm", opt_stringptr,
72 (void *)(offsetof(auth_gsasl_options_block, server_realm)) },
73 { "server_scram_iter", opt_stringptr,
74 (void *)(offsetof(auth_gsasl_options_block, server_scram_iter)) },
75 { "server_scram_salt", opt_stringptr,
76 (void *)(offsetof(auth_gsasl_options_block, server_scram_salt)) },
77 { "server_service", opt_stringptr,
78 (void *)(offsetof(auth_gsasl_options_block, server_service)) }
79 };
80 /* GSASL_SCRAM_SALTED_PASSWORD documented only for client, so not implementing
81 hooks to avoid cleartext passwords in the Exim server. */
82
83 int auth_gsasl_options_count =
84 sizeof(auth_gsasl_options)/sizeof(optionlist);
85
86 /* Defaults for the authenticator-specific options. */
87 auth_gsasl_options_block auth_gsasl_option_defaults = {
88 .server_service = US"smtp",
89 .server_hostname = US"$primary_hostname",
90 .server_scram_iter = US"4096",
91 /* all others zero/null */
92 };
93
94
95 #ifdef MACRO_PREDEF
96
97 /* Dummy values */
98 void auth_gsasl_init(auth_instance *ablock) {}
99 int auth_gsasl_server(auth_instance *ablock, uschar *data) {return 0;}
100 int auth_gsasl_client(auth_instance *ablock, void * sx,
101 int timeout, uschar *buffer, int buffsize) {return 0;}
102 void auth_gsasl_version_report(FILE *f) {}
103
104 void
105 auth_gsasl_macros(void)
106 {
107 # ifdef EXIM_GSASL_HAVE_SCRAM_SHA_256
108 builtin_macro_create(US"_HAVE_AUTH_GSASL_SCRAM_SHA_256");
109 # endif
110 }
111
112 #else /*!MACRO_PREDEF*/
113
114
115
116 /* "Globals" for managing the gsasl interface. */
117
118 static Gsasl *gsasl_ctx = NULL;
119 static int
120 main_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop);
121 static int
122 server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_instance *ablock);
123 static int
124 client_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_instance *ablock);
125
126 static BOOL sasl_error_should_defer = FALSE;
127 static Gsasl_property callback_loop = 0;
128 static BOOL checked_server_condition = FALSE;
129
130 enum { CURRENTLY_SERVER = 1, CURRENTLY_CLIENT = 2 };
131
132 struct callback_exim_state {
133 auth_instance *ablock;
134 int currently;
135 };
136
137
138 /*************************************************
139 * Initialization entry point *
140 *************************************************/
141
142 /* Called for each instance, after its options have been read, to
143 enable consistency checks to be done, or anything else that needs
144 to be set up. */
145
146 void
147 auth_gsasl_init(auth_instance *ablock)
148 {
149 static char * once = NULL;
150 int rc;
151 auth_gsasl_options_block *ob =
152 (auth_gsasl_options_block *)(ablock->options_block);
153
154 /* As per existing Cyrus glue, use the authenticator's public name as
155 the default for the mechanism name; we don't handle multiple mechanisms
156 in one authenticator, but the same driver can be used multiple times. */
157
158 if (!ob->server_mech)
159 ob->server_mech = string_copy(ablock->public_name);
160
161 /* Can get multiple session contexts from one library context, so just
162 initialise the once. */
163
164 if (!gsasl_ctx)
165 {
166 if ((rc = gsasl_init(&gsasl_ctx)) != GSASL_OK)
167 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
168 "couldn't initialise GNU SASL library: %s (%s)",
169 ablock->name, gsasl_strerror_name(rc), gsasl_strerror(rc));
170
171 gsasl_callback_set(gsasl_ctx, main_callback);
172 }
173
174 /* We don't need this except to log it for debugging. */
175
176 HDEBUG(D_auth) if (!once)
177 {
178 if ((rc = gsasl_server_mechlist(gsasl_ctx, &once)) != GSASL_OK)
179 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
180 "failed to retrieve list of mechanisms: %s (%s)",
181 ablock->name, gsasl_strerror_name(rc), gsasl_strerror(rc));
182
183 debug_printf("GNU SASL supports: %s\n", once);
184 }
185
186 if (!gsasl_client_support_p(gsasl_ctx, CCS ob->server_mech))
187 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
188 "GNU SASL does not support mechanism \"%s\"",
189 ablock->name, ob->server_mech);
190
191 ablock->server = TRUE;
192
193 if ( !ablock->server_condition
194 && ( streqic(ob->server_mech, US"EXTERNAL")
195 || streqic(ob->server_mech, US"ANONYMOUS")
196 || streqic(ob->server_mech, US"PLAIN")
197 || streqic(ob->server_mech, US"LOGIN")
198 ) )
199 {
200 ablock->server = FALSE;
201 HDEBUG(D_auth) debug_printf("%s authenticator: "
202 "Need server_condition for %s mechanism\n",
203 ablock->name, ob->server_mech);
204 }
205
206 /* This does *not* scale to new SASL mechanisms. Need a better way to ask
207 which properties will be needed. */
208
209 if ( !ob->server_realm
210 && streqic(ob->server_mech, US"DIGEST-MD5"))
211 {
212 ablock->server = FALSE;
213 HDEBUG(D_auth) debug_printf("%s authenticator: "
214 "Need server_realm for %s mechanism\n",
215 ablock->name, ob->server_mech);
216 }
217
218 /* At present, for mechanisms we don't panic on absence of server_condition;
219 need to figure out the most generically correct approach to deciding when
220 it's critical and when it isn't. Eg, for simple validation (PLAIN mechanism,
221 etc) it clearly is critical.
222 */
223
224 ablock->client = ob->client_username && ob->client_password;
225 }
226
227
228 /* GNU SASL uses one top-level callback, registered at library level.
229 We dispatch to client and server functions instead. */
230
231 static int
232 main_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
233 {
234 int rc = 0;
235 struct callback_exim_state *cb_state =
236 (struct callback_exim_state *)gsasl_session_hook_get(sctx);
237
238 if (!cb_state)
239 {
240 HDEBUG(D_auth) debug_printf("gsasl callback (%d) not from our server/client processing\n", prop);
241 #ifdef CHANNELBIND_HACK
242 if (prop == GSASL_CB_TLS_UNIQUE)
243 {
244 uschar * s;
245 if ((s = gsasl_callback_hook_get(ctx)))
246 {
247 HDEBUG(D_auth) debug_printf("GSASL_CB_TLS_UNIQUE from ctx hook\n");
248 gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CS s);
249 }
250 else
251 {
252 HDEBUG(D_auth) debug_printf("GSASL_CB_TLS_UNIQUE! dummy for now\n");
253 gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, "");
254 }
255 return GSASL_OK;
256 }
257 #endif
258 return GSASL_NO_CALLBACK;
259 }
260
261 HDEBUG(D_auth)
262 debug_printf("GNU SASL Callback entered, prop=%d (loop prop=%d)\n",
263 prop, callback_loop);
264
265 if (callback_loop > 0)
266 {
267 /* Most likely is that we were asked for property FOO, and to
268 expand the string we asked for property BAR to put into an auth
269 variable, but property BAR is not supplied for this mechanism. */
270 HDEBUG(D_auth)
271 debug_printf("Loop, asked for property %d while handling property %d\n",
272 prop, callback_loop);
273 return GSASL_NO_CALLBACK;
274 }
275 callback_loop = prop;
276
277 if (cb_state->currently == CURRENTLY_CLIENT)
278 rc = client_callback(ctx, sctx, prop, cb_state->ablock);
279 else if (cb_state->currently == CURRENTLY_SERVER)
280 rc = server_callback(ctx, sctx, prop, cb_state->ablock);
281 else
282 log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
283 "unhandled callback state, bug in Exim", cb_state->ablock->name);
284 /* NOTREACHED */
285
286 callback_loop = 0;
287 return rc;
288 }
289
290
291 /*************************************************
292 * Server entry point *
293 *************************************************/
294
295 /* For interface, see auths/README */
296
297 int
298 auth_gsasl_server(auth_instance *ablock, uschar *initial_data)
299 {
300 char *tmps;
301 char *to_send, *received;
302 Gsasl_session *sctx = NULL;
303 auth_gsasl_options_block *ob =
304 (auth_gsasl_options_block *)(ablock->options_block);
305 struct callback_exim_state cb_state;
306 int rc, auth_result, exim_error, exim_error_override;
307
308 HDEBUG(D_auth)
309 debug_printf("GNU SASL: initialising session for %s, mechanism %s\n",
310 ablock->name, ob->server_mech);
311
312 #ifndef DISABLE_TLS
313 if (tls_in.channelbinding && ob->server_channelbinding)
314 {
315 # ifdef EXPERIMENTAL_TLS_RESUME
316 if (!tls_in.ext_master_secret && tls_in.resumption == RESUME_USED)
317 { /* per RFC 7677 section 4 */
318 HDEBUG(D_auth) debug_printf(
319 "channel binding not usable on resumed TLS without extended-master-secret");
320 return FAIL;
321 }
322 # endif
323 # ifdef CHANNELBIND_HACK
324 /* This is a gross hack to get around the library a) requiring that
325 c-b was already set, at the _start() call, and b) caching a b64'd
326 version of the binding then which it never updates. */
327
328 gsasl_callback_hook_set(gsasl_ctx, tls_in.channelbinding);
329 # endif
330 }
331 #endif
332
333 if ((rc = gsasl_server_start(gsasl_ctx, CCS ob->server_mech, &sctx)) != GSASL_OK)
334 {
335 auth_defer_msg = string_sprintf("GNU SASL: session start failure: %s (%s)",
336 gsasl_strerror_name(rc), gsasl_strerror(rc));
337 HDEBUG(D_auth) debug_printf("%s\n", auth_defer_msg);
338 return DEFER;
339 }
340 /* Hereafter: gsasl_finish(sctx) please */
341
342 cb_state.ablock = ablock;
343 cb_state.currently = CURRENTLY_SERVER;
344 gsasl_session_hook_set(sctx, &cb_state);
345
346 tmps = CS expand_string(ob->server_service);
347 gsasl_property_set(sctx, GSASL_SERVICE, tmps);
348 tmps = CS expand_string(ob->server_hostname);
349 gsasl_property_set(sctx, GSASL_HOSTNAME, tmps);
350 if (ob->server_realm)
351 {
352 tmps = CS expand_string(ob->server_realm);
353 if (tmps && *tmps)
354 gsasl_property_set(sctx, GSASL_REALM, tmps);
355 }
356 /* We don't support protection layers. */
357 gsasl_property_set(sctx, GSASL_QOPS, "qop-auth");
358
359 #ifndef DISABLE_TLS
360 if (tls_in.channelbinding)
361 {
362 /* Some auth mechanisms can ensure that both sides are talking withing the
363 same security context; for TLS, this means that even if a bad certificate
364 has been accepted, they remain MitM-proof because both sides must be within
365 the same negotiated session; if someone is terminating one session and
366 proxying data on within a second, authentication will fail.
367
368 We might not have this available, depending upon TLS implementation,
369 ciphersuite, phase of moon ...
370
371 If we do, it results in extra SASL mechanisms being available; here,
372 Exim's one-mechanism-per-authenticator potentially causes problems.
373 It depends upon how GNU SASL will implement the PLUS variants of GS2
374 and whether it automatically mandates a switch to the bound PLUS
375 if the data is available. Since default-on, despite being more secure,
376 would then result in mechanism name changes on a library update, we
377 have little choice but to default it off and let the admin choose to
378 enable it. *sigh*
379 */
380 if (ob->server_channelbinding)
381 {
382 HDEBUG(D_auth) debug_printf("Auth %s: Enabling channel-binding\n",
383 ablock->name);
384 # ifndef CHANNELBIND_HACK
385 gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CCS tls_in.channelbinding);
386 # endif
387 }
388 else
389 HDEBUG(D_auth)
390 debug_printf("Auth %s: Not enabling channel-binding (data available)\n",
391 ablock->name);
392 }
393 else
394 HDEBUG(D_auth)
395 debug_printf("Auth %s: no channel-binding data available\n",
396 ablock->name);
397 #endif
398
399 checked_server_condition = FALSE;
400
401 received = CS initial_data;
402 to_send = NULL;
403 exim_error = exim_error_override = OK;
404
405 do {
406 switch (rc = gsasl_step64(sctx, received, &to_send))
407 {
408 case GSASL_OK:
409 if (!to_send)
410 goto STOP_INTERACTION;
411 break;
412
413 case GSASL_NEEDS_MORE:
414 break;
415
416 case GSASL_AUTHENTICATION_ERROR:
417 case GSASL_INTEGRITY_ERROR:
418 case GSASL_NO_AUTHID:
419 case GSASL_NO_ANONYMOUS_TOKEN:
420 case GSASL_NO_AUTHZID:
421 case GSASL_NO_PASSWORD:
422 case GSASL_NO_PASSCODE:
423 case GSASL_NO_PIN:
424 case GSASL_BASE64_ERROR:
425 HDEBUG(D_auth) debug_printf("GNU SASL permanent error: %s (%s)\n",
426 gsasl_strerror_name(rc), gsasl_strerror(rc));
427 log_write(0, LOG_REJECT, "%s authenticator (%s):\n "
428 "GNU SASL permanent failure: %s (%s)",
429 ablock->name, ob->server_mech,
430 gsasl_strerror_name(rc), gsasl_strerror(rc));
431 if (rc == GSASL_BASE64_ERROR)
432 exim_error_override = BAD64;
433 goto STOP_INTERACTION;
434
435 default:
436 auth_defer_msg = string_sprintf("GNU SASL temporary error: %s (%s)",
437 gsasl_strerror_name(rc), gsasl_strerror(rc));
438 HDEBUG(D_auth) debug_printf("%s\n", auth_defer_msg);
439 exim_error_override = DEFER;
440 goto STOP_INTERACTION;
441 }
442
443 if ((rc == GSASL_NEEDS_MORE) || (to_send && *to_send))
444 exim_error = auth_get_no64_data(USS &received, US to_send);
445
446 if (to_send)
447 {
448 free(to_send);
449 to_send = NULL;
450 }
451
452 if (exim_error)
453 break; /* handles * cancelled check */
454
455 } while (rc == GSASL_NEEDS_MORE);
456
457 STOP_INTERACTION:
458 auth_result = rc;
459
460 gsasl_finish(sctx);
461
462 /* Can return: OK DEFER FAIL CANCELLED BAD64 UNEXPECTED */
463
464 if (exim_error != OK)
465 return exim_error;
466
467 if (auth_result != GSASL_OK)
468 {
469 HDEBUG(D_auth) debug_printf("authentication returned %s (%s)\n",
470 gsasl_strerror_name(auth_result), gsasl_strerror(auth_result));
471 if (exim_error_override != OK)
472 return exim_error_override; /* might be DEFER */
473 if (sasl_error_should_defer) /* overriding auth failure SASL error */
474 return DEFER;
475 return FAIL;
476 }
477
478 /* Auth succeeded, check server_condition unless already done in callback */
479 return checked_server_condition ? OK : auth_check_serv_cond(ablock);
480 }
481
482
483 /* returns the GSASL status of expanding the Exim string given */
484 static int
485 condition_check(auth_instance *ablock, uschar *label, uschar *condition_string)
486 {
487 int exim_rc = auth_check_some_cond(ablock, label, condition_string, FAIL);
488 switch (exim_rc)
489 {
490 case OK: return GSASL_OK;
491 case DEFER: sasl_error_should_defer = TRUE;
492 return GSASL_AUTHENTICATION_ERROR;
493 case FAIL: return GSASL_AUTHENTICATION_ERROR;
494 default: log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: "
495 "Unhandled return from checking %s: %d",
496 ablock->name, label, exim_rc);
497 }
498
499 /* NOTREACHED */
500 return GSASL_AUTHENTICATION_ERROR;
501 }
502
503
504 static void
505 set_exim_authvar_from_prop(Gsasl_session * sctx, Gsasl_property prop)
506 {
507 uschar * propval = US gsasl_property_fast(sctx, prop);
508 int i = expand_nmax, j = i + 1;
509 propval = propval ? string_copy(propval) : US"";
510 auth_vars[i] = expand_nstring[j] = propval;
511 expand_nlength[j] = Ustrlen(propval);
512 expand_nmax = j;
513 }
514
515 static void
516 set_exim_authvars_from_a_az_r_props(Gsasl_session * sctx)
517 {
518 if (expand_nmax > 0 ) return;
519
520 /* Asking for GSASL_AUTHZID calls back into us if we use
521 gsasl_property_get(), thus the use of gsasl_property_fast().
522 Do we really want to hardcode limits per mechanism? What happens when
523 a new mechanism is added to the library. It *shouldn't* result in us
524 needing to add more glue, since avoiding that is a large part of the
525 point of SASL. */
526
527 set_exim_authvar_from_prop(sctx, GSASL_AUTHID);
528 set_exim_authvar_from_prop(sctx, GSASL_AUTHZID);
529 set_exim_authvar_from_prop(sctx, GSASL_REALM);
530 }
531
532
533 static int
534 server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop,
535 auth_instance *ablock)
536 {
537 char *tmps;
538 uschar *propval;
539 int cbrc = GSASL_NO_CALLBACK;
540 auth_gsasl_options_block *ob =
541 (auth_gsasl_options_block *)(ablock->options_block);
542
543 HDEBUG(D_auth)
544 debug_printf("GNU SASL callback %d for %s/%s as server\n",
545 prop, ablock->name, ablock->public_name);
546
547 for (int i = 0; i < AUTH_VARS; i++) auth_vars[i] = NULL;
548 expand_nmax = 0;
549
550 switch (prop)
551 {
552 case GSASL_VALIDATE_SIMPLE:
553 HDEBUG(D_auth) debug_printf(" VALIDATE_SIMPLE\n");
554 /* GSASL_AUTHID, GSASL_AUTHZID, and GSASL_PASSWORD */
555 set_exim_authvar_from_prop(sctx, GSASL_AUTHID);
556 set_exim_authvar_from_prop(sctx, GSASL_AUTHZID);
557 set_exim_authvar_from_prop(sctx, GSASL_PASSWORD);
558
559 cbrc = condition_check(ablock, US"server_condition", ablock->server_condition);
560 checked_server_condition = TRUE;
561 break;
562
563 case GSASL_VALIDATE_EXTERNAL:
564 HDEBUG(D_auth) debug_printf(" VALIDATE_EXTERNAL\n");
565 if (!ablock->server_condition)
566 {
567 HDEBUG(D_auth) debug_printf("No server_condition supplied, to validate EXTERNAL\n");
568 cbrc = GSASL_AUTHENTICATION_ERROR;
569 break;
570 }
571 set_exim_authvar_from_prop(sctx, GSASL_AUTHZID);
572
573 cbrc = condition_check(ablock,
574 US"server_condition (EXTERNAL)", ablock->server_condition);
575 checked_server_condition = TRUE;
576 break;
577
578 case GSASL_VALIDATE_ANONYMOUS:
579 HDEBUG(D_auth) debug_printf(" VALIDATE_ANONYMOUS\n");
580 if (!ablock->server_condition)
581 {
582 HDEBUG(D_auth) debug_printf("No server_condition supplied, to validate ANONYMOUS\n");
583 cbrc = GSASL_AUTHENTICATION_ERROR;
584 break;
585 }
586 set_exim_authvar_from_prop(sctx, GSASL_ANONYMOUS_TOKEN);
587
588 cbrc = condition_check(ablock,
589 US"server_condition (ANONYMOUS)", ablock->server_condition);
590 checked_server_condition = TRUE;
591 break;
592
593 case GSASL_VALIDATE_GSSAPI:
594 HDEBUG(D_auth) debug_printf(" VALIDATE_GSSAPI\n");
595 /* GSASL_AUTHZID and GSASL_GSSAPI_DISPLAY_NAME
596 The display-name is authenticated as part of GSS, the authzid is claimed
597 by the SASL integration after authentication; protected against tampering
598 (if the SASL mechanism supports that, which Kerberos does) but is
599 unverified, same as normal for other mechanisms.
600 First coding, we had these values swapped, but for consistency and prior
601 to the first release of Exim with this authenticator, they've been
602 switched to match the ordering of GSASL_VALIDATE_SIMPLE. */
603
604 set_exim_authvar_from_prop(sctx, GSASL_GSSAPI_DISPLAY_NAME);
605 set_exim_authvar_from_prop(sctx, GSASL_AUTHZID);
606
607 /* In this one case, it perhaps makes sense to default back open?
608 But for consistency, let's just mandate server_condition here too. */
609
610 cbrc = condition_check(ablock,
611 US"server_condition (GSSAPI family)", ablock->server_condition);
612 checked_server_condition = TRUE;
613 break;
614
615 case GSASL_SCRAM_ITER:
616 HDEBUG(D_auth) debug_printf(" SCRAM_ITER\n");
617 if (ob->server_scram_iter)
618 {
619 set_exim_authvars_from_a_az_r_props(sctx);
620 tmps = CS expand_string(ob->server_scram_iter);
621 HDEBUG(D_auth) debug_printf(" '%s'\n", tmps);
622 gsasl_property_set(sctx, GSASL_SCRAM_ITER, tmps);
623 cbrc = GSASL_OK;
624 }
625 else
626 HDEBUG(D_auth) debug_printf(" option not set\n");
627 break;
628
629 case GSASL_SCRAM_SALT:
630 HDEBUG(D_auth) debug_printf(" SCRAM_SALT\n");
631 if (ob->server_scram_salt)
632 {
633 set_exim_authvars_from_a_az_r_props(sctx);
634 tmps = CS expand_string(ob->server_scram_salt);
635 HDEBUG(D_auth) debug_printf(" '%s'\n", tmps);
636 if (*tmps)
637 gsasl_property_set(sctx, GSASL_SCRAM_SALT, tmps);
638 cbrc = GSASL_OK;
639 }
640 else
641 HDEBUG(D_auth) debug_printf(" option not set\n");
642 break;
643
644 case GSASL_PASSWORD:
645 HDEBUG(D_auth) debug_printf(" PASSWORD\n");
646 /* SCRAM-SHA-1: GSASL_AUTHID, GSASL_AUTHZID and GSASL_REALM
647 DIGEST-MD5: GSASL_AUTHID, GSASL_AUTHZID and GSASL_REALM
648 CRAM-MD5: GSASL_AUTHID
649 PLAIN: GSASL_AUTHID and GSASL_AUTHZID
650 LOGIN: GSASL_AUTHID
651 */
652 set_exim_authvars_from_a_az_r_props(sctx);
653
654 if (!ob->server_password)
655 {
656 HDEBUG(D_auth) debug_printf("option not set\n");
657 break;
658 }
659 if (!(tmps = CS expand_string(ob->server_password)))
660 {
661 sasl_error_should_defer = !f.expand_string_forcedfail;
662 HDEBUG(D_auth) debug_printf("server_password expansion failed, so "
663 "can't tell GNU SASL library the password for %s\n", auth_vars[0]);
664 return GSASL_AUTHENTICATION_ERROR;
665 }
666 HDEBUG(D_auth) debug_printf(" set\n");
667 gsasl_property_set(sctx, GSASL_PASSWORD, tmps);
668
669 /* This is inadequate; don't think Exim's store stacks are geared
670 for memory wiping, so expanding strings will leave stuff laying around.
671 But no need to compound the problem, so get rid of the one we can. */
672
673 memset(tmps, '\0', strlen(tmps));
674 cbrc = GSASL_OK;
675 break;
676
677 default:
678 HDEBUG(D_auth) debug_printf(" Unrecognised callback: %d\n", prop);
679 cbrc = GSASL_NO_CALLBACK;
680 }
681
682 HDEBUG(D_auth) debug_printf("Returning %s (%s)\n",
683 gsasl_strerror_name(cbrc), gsasl_strerror(cbrc));
684
685 return cbrc;
686 }
687
688
689 /******************************************************************************/
690
691 #define PROP_OPTIONAL BIT(0)
692
693 static BOOL
694 client_prop(Gsasl_session * sctx, Gsasl_property propnum, uschar * val,
695 const uschar * why, unsigned flags, uschar * buffer, int buffsize)
696 {
697 uschar * s;
698 int rc;
699
700 if (flags & PROP_OPTIONAL && !val) return TRUE;
701 if (!(s = expand_string(val)) || !(flags & PROP_OPTIONAL) && !*s)
702 {
703 string_format(buffer, buffsize, "%s", expand_string_message);
704 return FALSE;
705 }
706 if (*s) gsasl_property_set(sctx, propnum, CS s);
707 return TRUE;
708 }
709
710 /*************************************************
711 * Client entry point *
712 *************************************************/
713
714 /* For interface, see auths/README */
715
716 int
717 auth_gsasl_client(
718 auth_instance *ablock, /* authenticator block */
719 void * sx, /* connection */
720 int timeout, /* command timeout */
721 uschar *buffer, /* buffer for reading response */
722 int buffsize) /* size of buffer */
723 {
724 auth_gsasl_options_block *ob =
725 (auth_gsasl_options_block *)(ablock->options_block);
726 Gsasl_session * sctx = NULL;
727 struct callback_exim_state cb_state;
728 uschar * s;
729 BOOL initial = TRUE;
730 int rc, yield = FAIL;
731
732 HDEBUG(D_auth)
733 debug_printf("GNU SASL: initialising session for %s, mechanism %s\n",
734 ablock->name, ob->server_mech);
735
736 *buffer = 0;
737
738 #ifndef DISABLE_TLS
739 if (tls_out.channelbinding && ob->client_channelbinding)
740 {
741 # ifdef EXPERIMENTAL_TLS_RESUME
742 if (!tls_out.ext_master_secret && tls_out.resumption == RESUME_USED)
743 { /* per RFC 7677 section 4 */
744 string_format(buffer, buffsize, "%s",
745 "channel binding not usable on resumed TLS without extended-master-secret");
746 return FAIL;
747 }
748 # endif
749 # ifdef CHANNELBIND_HACK
750 /* This is a gross hack to get around the library a) requiring that
751 c-b was already set, at the _start() call, and b) caching a b64'd
752 version of the binding then which it never updates. */
753
754 gsasl_callback_hook_set(gsasl_ctx, tls_out.channelbinding);
755 # endif
756 }
757 #endif
758
759 if ((rc = gsasl_client_start(gsasl_ctx, CCS ob->server_mech, &sctx)) != GSASL_OK)
760 {
761 string_format(buffer, buffsize, "GNU SASL: session start failure: %s (%s)",
762 gsasl_strerror_name(rc), gsasl_strerror(rc));
763 HDEBUG(D_auth) debug_printf("%s\n", buffer);
764 return ERROR;
765 }
766
767 cb_state.ablock = ablock;
768 cb_state.currently = CURRENTLY_CLIENT;
769 gsasl_session_hook_set(sctx, &cb_state);
770
771 /* Set properties */
772
773 if ( !client_prop(sctx, GSASL_PASSWORD, ob->client_password, US"password",
774 0, buffer, buffsize)
775 || !client_prop(sctx, GSASL_AUTHID, ob->client_username, US"username",
776 0, buffer, buffsize)
777 || !client_prop(sctx, GSASL_AUTHZID, ob->client_authz, US"authz",
778 PROP_OPTIONAL, buffer, buffsize)
779 )
780 return ERROR;
781
782 #ifndef DISABLE_TLS
783 if (tls_out.channelbinding)
784 if (ob->client_channelbinding)
785 {
786 HDEBUG(D_auth) debug_printf("Auth %s: Enabling channel-binding\n",
787 ablock->name);
788 # ifndef CHANNELBIND_HACK
789 gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CCS tls_out.channelbinding);
790 # endif
791 }
792 else
793 HDEBUG(D_auth)
794 debug_printf("Auth %s: Not enabling channel-binding (data available)\n",
795 ablock->name);
796 #endif
797
798 /* Run the SASL conversation with the server */
799
800 for(s = NULL; ;)
801 {
802 uschar * outstr;
803 BOOL fail;
804
805 rc = gsasl_step64(sctx, CS s, CSS &outstr);
806
807 fail = initial
808 ? smtp_write_command(sx, SCMD_FLUSH,
809 outstr ? "AUTH %s %s\r\n" : "AUTH %s\r\n",
810 ablock->public_name, outstr) <= 0
811 : outstr
812 ? smtp_write_command(sx, SCMD_FLUSH, "%s\r\n", outstr) <= 0
813 : FALSE;
814 if (outstr && *outstr) free(outstr);
815 if (fail)
816 {
817 yield = FAIL_SEND;
818 goto done;
819 }
820 initial = FALSE;
821
822 if (rc != GSASL_NEEDS_MORE)
823 {
824 if (rc != GSASL_OK)
825 {
826 string_format(buffer, buffsize, "gsasl: %s", gsasl_strerror(rc));
827 break;
828 }
829
830 /* expecting a final 2xx from the server, accepting the AUTH */
831
832 if (smtp_read_response(sx, buffer, buffsize, '2', timeout))
833 yield = OK;
834 break; /* from SASL sequence loop */
835 }
836
837 /* 2xx or 3xx response is acceptable. If 2xx, no further input */
838
839 if (!smtp_read_response(sx, buffer, buffsize, '3', timeout))
840 if (errno == 0 && buffer[0] == '2')
841 buffer[4] = '\0';
842 else
843 {
844 yield = FAIL;
845 goto done;
846 }
847 s = buffer + 4;
848 }
849
850 done:
851 gsasl_finish(sctx);
852 return yield;
853 }
854
855 static int
856 client_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_instance *ablock)
857 {
858 HDEBUG(D_auth) debug_printf("GNU SASL callback %d for %s/%s as client\n",
859 prop, ablock->name, ablock->public_name);
860 switch (prop)
861 {
862 case GSASL_AUTHZID:
863 HDEBUG(D_auth) debug_printf(" inquired for AUTHZID; not providing one\n");
864 break;
865 case GSASL_SCRAM_SALTED_PASSWORD:
866 HDEBUG(D_auth)
867 debug_printf(" inquired for SCRAM_SALTED_PASSWORD; not providing one\n");
868 break;
869 case GSASL_CB_TLS_UNIQUE:
870 HDEBUG(D_auth)
871 debug_printf(" inquired for CB_TLS_UNIQUE, filling in\n");
872 gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE, CCS tls_out.channelbinding);
873 break;
874 }
875 return GSASL_NO_CALLBACK;
876 }
877
878 /*************************************************
879 * Diagnostic API *
880 *************************************************/
881
882 void
883 auth_gsasl_version_report(FILE *f)
884 {
885 const char *runtime;
886 runtime = gsasl_check_version(NULL);
887 fprintf(f, "Library version: GNU SASL: Compile: %s\n"
888 " Runtime: %s\n",
889 GSASL_VERSION, runtime);
890 }
891
892
893
894 /* Dummy */
895 void auth_gsasl_macros(void) {}
896
897 #endif /*!MACRO_PREDEF*/
898 #endif /* AUTH_GSASL */
899
900 /* End of gsasl_exim.c */