X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/edc33b5f1aca3f17ee8ca0b93689e6d14009df54..93a6fce2ebf117f490d7ee11f066f75280d32386:/src/src/auths/cyrus_sasl.c diff --git a/src/src/auths/cyrus_sasl.c b/src/src/auths/cyrus_sasl.c index e61625e28..ef13db9e7 100644 --- a/src/src/auths/cyrus_sasl.c +++ b/src/src/auths/cyrus_sasl.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2009 */ +/* Copyright (c) University of Cambridge 1995 - 2012 */ /* See the file NOTICE for conditions of use and distribution. */ /* This code was originally contributed by Matthew Byng-Maddick */ @@ -25,7 +25,9 @@ in a dummy argument to stop even pickier compilers complaining about infinite loops. */ #ifndef AUTH_CYRUS_SASL -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 @@ -95,10 +97,11 @@ auth_cyrus_sasl_init(auth_instance *ablock) { auth_cyrus_sasl_options_block *ob = (auth_cyrus_sasl_options_block *)(ablock->options_block); -uschar *list, *listptr, *buffer; +const uschar *list, *listptr, *buffer; int rc, i; unsigned int len; uschar *rs_point, *expanded_hostname; +char *realm_expanded; sasl_conn_t *conn; sasl_callback_t cbs[]={ @@ -115,6 +118,15 @@ if (expanded_hostname == NULL) "couldn't expand server_hostname [%s]: %s", ablock->name, ob->server_hostname, expand_string_message); +realm_expanded=NULL; +if (ob->server_realm != NULL) { + realm_expanded = CS expand_string(ob->server_realm); + if (realm_expanded == NULL) + log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " + "couldn't expand server_realm [%s]: %s", + ablock->name, ob->server_realm, expand_string_message); +} + /* we're going to initialise the library to check that there is an * authenticator of type whatever mechanism we're using */ @@ -129,12 +141,12 @@ if( rc != SASL_OK ) "couldn't initialise Cyrus SASL library.", ablock->name); rc=sasl_server_new(CS ob->server_service, CS expanded_hostname, - CS ob->server_realm, NULL, NULL, NULL, 0, &conn); + realm_expanded, NULL, NULL, NULL, 0, &conn); if( rc != SASL_OK ) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "couldn't initialise Cyrus SASL server connection.", ablock->name); -rc=sasl_listmech(conn, NULL, "", ":", "", (const char **)(&list), &len, &i); +rc=sasl_listmech(conn, NULL, "", ":", "", (const char **)&list, &len, &i); if( rc != SASL_OK ) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator: " "couldn't get Cyrus SASL mechanism list.", ablock->name); @@ -144,7 +156,7 @@ listptr=list; HDEBUG(D_auth) { debug_printf("Initialised Cyrus SASL service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n", - ob->server_service, expanded_hostname, ob->server_realm); + ob->server_service, expanded_hostname, realm_expanded); debug_printf("Cyrus SASL knows mechanisms: %s\n", list); } @@ -194,7 +206,8 @@ uschar *output, *out2, *input, *clear, *hname; uschar *debug = NULL; /* Stops compiler complaining */ sasl_callback_t cbs[]={{SASL_CB_LIST_END, NULL, NULL}}; sasl_conn_t *conn; -int rc, firsttime=1, clen, negotiated_ssf; +char *realm_expanded; +int rc, i, firsttime=1, clen, *negotiated_ssf_ptr=NULL, negotiated_ssf; unsigned int inlen, outlen; input=data; @@ -203,7 +216,11 @@ inlen=Ustrlen(data); HDEBUG(D_auth) debug=string_copy(data); hname=expand_string(ob->server_hostname); -if(hname == NULL) +realm_expanded=NULL; +if (hname && ob->server_realm) + realm_expanded= CS expand_string(ob->server_realm); +if((hname == NULL) || + ((realm_expanded == NULL) && (ob->server_realm != NULL))) { auth_defer_msg = expand_string_message; return DEFER; @@ -227,12 +244,12 @@ if (rc != SASL_OK) return DEFER; } -rc=sasl_server_new(CS ob->server_service, CS hname, CS ob->server_realm, NULL, +rc=sasl_server_new(CS ob->server_service, CS hname, realm_expanded, NULL, NULL, NULL, 0, &conn); HDEBUG(D_auth) debug_printf("Initialised Cyrus SASL server connection; service=\"%s\" fqdn=\"%s\" realm=\"%s\"\n", - ob->server_service, hname, ob->server_realm); + ob->server_service, hname, realm_expanded); if( rc != SASL_OK ) { @@ -241,23 +258,81 @@ if( rc != SASL_OK ) return DEFER; } -if (tls_cipher) +if (tls_in.cipher) { - rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, &tls_bits); + rc = sasl_setprop(conn, SASL_SSF_EXTERNAL, (sasl_ssf_t *) &tls_in.bits); if (rc != SASL_OK) { HDEBUG(D_auth) debug_printf("Cyrus SASL EXTERNAL SSF set %d failed: %s\n", - tls_bits, sasl_errstring(rc, NULL, NULL)); + tls_in.bits, sasl_errstring(rc, NULL, NULL)); auth_defer_msg = US"couldn't set Cyrus SASL EXTERNAL SSF"; sasl_done(); return DEFER; } else - HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_bits); + HDEBUG(D_auth) debug_printf("Cyrus SASL set EXTERNAL SSF to %d\n", tls_in.bits); } else HDEBUG(D_auth) debug_printf("Cyrus SASL: no TLS, no EXTERNAL SSF set\n"); +/* So sasl_setprop() documents non-shorted IPv6 addresses which is incredibly +annoying; looking at cyrus-imapd-2.3.x source, the IP address is constructed +with their iptostring() function, which just wraps +getnameinfo(..., NI_NUMERICHOST|NI_NUMERICSERV), which is equivalent to the +inet_ntop which we wrap in our host_ntoa() function. + +So the docs are too strict and we shouldn't worry about :: contractions. */ + +/* Set properties for remote and local host-ip;port */ +for (i=0; i < 2; ++i) + { + struct sockaddr_storage ss; + int (*query)(int, struct sockaddr *, socklen_t *); + int propnum, port; + const uschar *label; + uschar *address, *address_port; + const char *s_err; + socklen_t sslen; + + if (i) + { + query = &getpeername; + propnum = SASL_IPREMOTEPORT; + label = CUS"peer"; + } + else + { + query = &getsockname; + propnum = SASL_IPLOCALPORT; + label = CUS"local"; + } + + sslen = sizeof(ss); + rc = query(fileno(smtp_in), (struct sockaddr *) &ss, &sslen); + if (rc < 0) + { + HDEBUG(D_auth) + debug_printf("Failed to get %s address information: %s\n", + label, strerror(errno)); + break; + } + + address = host_ntoa(-1, &ss, NULL, &port); + address_port = string_sprintf("%s;%d", address, port); + + rc = sasl_setprop(conn, propnum, address_port); + if (rc != SASL_OK) + { + s_err = sasl_errdetail(conn); + HDEBUG(D_auth) + debug_printf("Failed to set %s SASL property: [%d] %s\n", + label, rc, s_err ? s_err : ""); + break; + } + HDEBUG(D_auth) debug_printf("Cyrus SASL set %s hostport to: %s\n", + label, address_port); + } + rc=SASL_CONTINUE; while(rc==SASL_CONTINUE) @@ -377,7 +452,7 @@ while(rc==SASL_CONTINUE) debug_printf("Cyrus SASL %s authentication succeeded for %s\n", ob->server_mech, auth_vars[0]); - rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf)); + rc = sasl_getprop(conn, SASL_SSF, (const void **)(&negotiated_ssf_ptr)); if (rc != SASL_OK) { HDEBUG(D_auth) @@ -390,6 +465,7 @@ while(rc==SASL_CONTINUE) sasl_done(); return FAIL; } + negotiated_ssf = *negotiated_ssf_ptr; HDEBUG(D_auth) debug_printf("Cyrus SASL %s negotiated SSF: %d\n", ob->server_mech, negotiated_ssf); if (negotiated_ssf > 0)