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 */