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