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