X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/44bbabb570db6e700a31469a0faf2ac27bf3bfe0..f8c0a35cdf7181196ceda8e10ab38757c80b3e80:/src/src/auths/gsasl_exim.c diff --git a/src/src/auths/gsasl_exim.c b/src/src/auths/gsasl_exim.c index e88bd2578..87be9b5e1 100644 --- a/src/src/auths/gsasl_exim.c +++ b/src/src/auths/gsasl_exim.c @@ -5,7 +5,9 @@ /* Copyright (c) University of Cambridge 1995 - 2012 */ /* See the file NOTICE for conditions of use and distribution. */ -/* Copyright (c) Twitter Inc 2012 */ +/* Copyright (c) Twitter Inc 2012 + Author: Phil Pennock */ +/* Copyright (c) Phil Pennock 2012 */ /* Interface to GNU SASL library for generic authentication. */ @@ -27,7 +29,9 @@ sense in all contexts. For some, we can do checks at init time. #ifndef AUTH_GSASL /* dummy function to satisfy compilers when we link in an "empty" file. */ -static void dummy(int x) { dummy(x-1); } +static void dummy(int x); +static void dummy2(int x) { dummy(x-1); } +static void dummy(int x) { dummy2(x-1); } #else #include @@ -146,14 +150,22 @@ auth_gsasl_init(auth_instance *ablock) ablock->name, ob->server_mech); if ((ablock->server_condition == NULL) && - (strcmpic(ob->server_mech, US"EXTERNAL") || - strcmpic(ob->server_mech, US"ANONYMOUS") || - strcmpic(ob->server_mech, US"PLAIN") || - strcmpic(ob->server_mech, US"LOGIN"))) + (streqic(ob->server_mech, US"EXTERNAL") || + streqic(ob->server_mech, US"ANONYMOUS") || + streqic(ob->server_mech, US"PLAIN") || + streqic(ob->server_mech, US"LOGIN"))) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "Need server_condition for %s mechanism", ablock->name, ob->server_mech); + /* This does *not* scale to new SASL mechanisms. Need a better way to ask + which properties will be needed. */ + if ((ob->server_realm == NULL) && + streqic(ob->server_mech, US"DIGEST-MD5")) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " + "Need server_realm for %s mechanism", + ablock->name, ob->server_mech); + /* At present, for mechanisms we don't panic on absence of server_condition; need to figure out the most generically correct approach to deciding when it's critical and when it isn't. Eg, for simple validation (PLAIN mechanism, @@ -176,8 +188,9 @@ main_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop) struct callback_exim_state *cb_state = (struct callback_exim_state *)gsasl_session_hook_get(sctx); - HDEBUG(D_auth) debug_printf("Callback entered, prop=%d (loop prop=%d)\n", - prop, callback_loop); + HDEBUG(D_auth) + debug_printf("GNU SASL Callback entered, prop=%d (loop prop=%d)\n", + prop, callback_loop); if (cb_state == NULL) { HDEBUG(D_auth) debug_printf(" not from our server/client processing.\n"); @@ -305,7 +318,9 @@ auth_gsasl_server(auth_instance *ablock, uschar *initial_data) switch (rc) { case GSASL_OK: - goto STOP_INTERACTION; + if (!to_send) + goto STOP_INTERACTION; + break; case GSASL_NEEDS_MORE: break; @@ -337,8 +352,16 @@ auth_gsasl_server(auth_instance *ablock, uschar *initial_data) goto STOP_INTERACTION; } - exim_error = - auth_get_no64_data((uschar **)&received, (uschar *)to_send); + if ((rc == GSASL_NEEDS_MORE) || + (to_send && *to_send)) + exim_error = + auth_get_no64_data((uschar **)&received, (uschar *)to_send); + + if (to_send) { + free(to_send); + to_send = NULL; + } + if (exim_error) break; /* handles * cancelled check */ @@ -412,11 +435,11 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta switch (prop) { case GSASL_VALIDATE_SIMPLE: /* GSASL_AUTHID, GSASL_AUTHZID, and GSASL_PASSWORD */ - propval = (uschar *) gsasl_property_get(sctx, GSASL_AUTHID); + propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHID); auth_vars[0] = expand_nstring[1] = propval ? propval : US""; - propval = (uschar *) gsasl_property_get(sctx, GSASL_AUTHZID); + propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID); auth_vars[1] = expand_nstring[2] = propval ? propval : US""; - propval = (uschar *) gsasl_property_get(sctx, GSASL_PASSWORD); + propval = (uschar *) gsasl_property_fast(sctx, GSASL_PASSWORD); auth_vars[2] = expand_nstring[3] = propval ? propval : US""; expand_nmax = 3; for (i = 1; i <= 3; ++i) @@ -432,7 +455,7 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta cbrc = GSASL_AUTHENTICATION_ERROR; break; } - propval = (uschar *) gsasl_property_get(sctx, GSASL_AUTHZID); + propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID); /* We always set $auth1, even if only to empty string. */ auth_vars[0] = expand_nstring[1] = propval ? propval : US""; expand_nlength[1] = Ustrlen(expand_nstring[1]); @@ -449,7 +472,7 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta cbrc = GSASL_AUTHENTICATION_ERROR; break; } - propval = (uschar *) gsasl_property_get(sctx, GSASL_ANONYMOUS_TOKEN); + propval = (uschar *) gsasl_property_fast(sctx, GSASL_ANONYMOUS_TOKEN); /* We always set $auth1, even if only to empty string. */ auth_vars[0] = expand_nstring[1] = propval ? propval : US""; expand_nlength[1] = Ustrlen(expand_nstring[1]); @@ -461,10 +484,18 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta break; case GSASL_VALIDATE_GSSAPI: - /* GSASL_AUTHZID and GSASL_GSSAPI_DISPLAY_NAME */ - propval = (uschar *) gsasl_property_get(sctx, GSASL_AUTHZID); + /* GSASL_AUTHZID and GSASL_GSSAPI_DISPLAY_NAME + The display-name is authenticated as part of GSS, the authzid is claimed + by the SASL integration after authentication; protected against tampering + (if the SASL mechanism supports that, which Kerberos does) but is + unverified, same as normal for other mechanisms. + + First coding, we had these values swapped, but for consistency and prior + to the first release of Exim with this authenticator, they've been + switched to match the ordering of GSASL_VALIDATE_SIMPLE. */ + propval = (uschar *) gsasl_property_fast(sctx, GSASL_GSSAPI_DISPLAY_NAME); auth_vars[0] = expand_nstring[1] = propval ? propval : US""; - propval = (uschar *) gsasl_property_get(sctx, GSASL_GSSAPI_DISPLAY_NAME); + propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID); auth_vars[1] = expand_nstring[2] = propval ? propval : US""; expand_nmax = 2; for (i = 1; i <= 2; ++i) @@ -491,16 +522,17 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta tmps = CS expand_string(ob->server_scram_salt); gsasl_property_set(sctx, GSASL_SCRAM_SALT, tmps); } - /* Asking for GSASL_AUTHZID will probably call back into us. + /* Asking for GSASL_AUTHZID calls back into us if we use + gsasl_property_get(), thus the use of gsasl_property_fast(). Do we really want to hardcode limits per mechanism? What happens when a new mechanism is added to the library. It *shouldn't* result in us needing to add more glue, since avoiding that is a large part of the point of SASL. */ - propval = (uschar *) gsasl_property_get(sctx, GSASL_AUTHID); + propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHID); auth_vars[0] = expand_nstring[1] = propval ? propval : US""; - propval = (uschar *) gsasl_property_get(sctx, GSASL_AUTHZID); + propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID); auth_vars[1] = expand_nstring[2] = propval ? propval : US""; - propval = (uschar *) gsasl_property_get(sctx, GSASL_REALM); + propval = (uschar *) gsasl_property_fast(sctx, GSASL_REALM); auth_vars[2] = expand_nstring[3] = propval ? propval : US""; expand_nmax = 3; for (i = 1; i <= 3; ++i)