From 28df4fd48a82c97d8f6c6a1ad1228561994b545b Mon Sep 17 00:00:00 2001 From: Nathan Dushman Date: Tue, 12 Nov 2002 08:20:08 +0000 Subject: [PATCH] Hi - this is a patch against mutt-1.4 to use version 2 of the Cyrus SASL library; all changes are ifdef'd so as not to break SASLv1 support. This includes a patch to configure.in to allow the choice between v1 and v2, but someone with a better understanding of autoconf should double-check it. --- configure.in | 66 +++++++++++++++++++++++++++++++ imap/auth_gss.c | 2 +- imap/auth_sasl.c | 25 ++++++++++++ main.c | 5 +++ mutt_sasl.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++- mutt_sasl.h | 8 ++++ 6 files changed, 204 insertions(+), 2 deletions(-) diff --git a/configure.in b/configure.in index 31510e30..fd9115cd 100644 --- a/configure.in +++ b/configure.in @@ -611,6 +611,72 @@ AC_ARG_WITH(sasl, [ --with-sasl[=PFX] Use Cyrus SASL library for POP/I ]) AM_CONDITIONAL(USE_SASL, test x$need_sasl = xyes) +AC_ARG_WITH(sasl2, [ --with-sasl2[=PFX] Use Cyrus SASL library version 2 for POP/IMAP authentication], + [ + if test "$need_socket" != "yes" + then + AC_MSG_ERROR([SASL support is only useful with POP or IMAP support]) + fi + + if test "$with_sasl2" != "no" + then + if test "$with_sasl2" != "yes" + then + CPPFLAGS="$CPPFLAGS -I$with_sasl2/include" + LDFLAGS="$LDFLAGS -L$with_sasl2/lib" + fi + + saved_LIBS="$LIBS" + + AC_CHECK_LIB(sasl2, sasl_client_init,, + AC_MSG_ERROR([could not find libsasl]),) + + MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS mutt_sasl.o" + MUTTLIBS="$MUTTLIBS -lsasl2" + LIBS="$saved_LIBS" + AC_DEFINE(USE_SASL,1, + [ Define if want to use the Cyrus SASL library for POP/IMAP authentication. ]) + AC_DEFINE(USE_SASL2,1, + [ Define if want to use version 2 of the Cyrus SASL library. ]) + need_sasl=yes + need_md5=no + fi + ]) +AM_CONDITIONAL(USE_SASL, test x$need_sasl = xyes) + +AC_ARG_WITH(sasl2, [ --with-sasl2[=PFX] Use Cyrus SASL library version 2 for POP/IMAP authentication], + [ + if test "$need_socket" != "yes" + then + AC_MSG_ERROR([SASL support is only useful with POP or IMAP support]) + fi + + if test "$with_sasl2" != "no" + then + if test "$with_sasl2" != "yes" + then + CPPFLAGS="$CPPFLAGS -I$with_sasl2/include" + LDFLAGS="$LDFLAGS -L$with_sasl2/lib" + fi + + saved_LIBS="$LIBS" + + AC_CHECK_LIB(sasl2, sasl_client_init,, + AC_MSG_ERROR([could not find libsasl]),) + + MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS mutt_sasl.o" + MUTTLIBS="$MUTTLIBS -lsasl2" + LIBS="$saved_LIBS" + AC_DEFINE(USE_SASL,1, + [ Define if want to use the Cyrus SASL library for POP/IMAP authentication. ]) + AC_DEFINE(USE_SASL2,1, + [ Define if want to use version 2 of the Cyrus SASL library. ]) + need_sasl=yes + need_md5=no + fi + ]) +AM_CONDITIONAL(USE_SASL, test x$need_sasl = xyes) + if test "$need_md5" = "yes" then MUTT_LIB_OBJECTS="$MUTT_LIB_OBJECTS md5c.o" diff --git a/imap/auth_gss.c b/imap/auth_gss.c index 1a7491e8..a6a29086 100644 --- a/imap/auth_gss.c +++ b/imap/auth_gss.c @@ -28,7 +28,7 @@ #include #ifdef HAVE_HEIMDAL -# include +# include # define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE #else # include diff --git a/imap/auth_sasl.c b/imap/auth_sasl.c index c8e656ed..4bfaab42 100644 --- a/imap/auth_sasl.c +++ b/imap/auth_sasl.c @@ -23,8 +23,13 @@ #include "imap_private.h" #include "auth.h" +#ifdef USE_SASL2 +#include +#include +#else #include #include +#endif /* imap_auth_sasl: Default authenticator if available. */ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method) @@ -34,7 +39,11 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method) int rc, irc; char buf[LONG_STRING]; const char* mech; +#ifdef USE_SASL2 + const char *pc = NULL; +#else char* pc = NULL; +#endif unsigned int len, olen; unsigned char client_start; @@ -63,15 +72,25 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method) if (mutt_bit_isset (idata->capabilities, AUTH_ANON) && (!idata->conn->account.user[0] || !ascii_strncmp (idata->conn->account.user, "anonymous", 9))) +#ifdef USE_SASL2 + rc = sasl_client_start (saslconn, "AUTH=ANONYMOUS", NULL, &pc, &olen, + &mech); +#else rc = sasl_client_start (saslconn, "AUTH=ANONYMOUS", NULL, NULL, &pc, &olen, &mech); +#endif } if (rc != SASL_OK && rc != SASL_CONTINUE) do { +#ifdef USE_SASL2 + rc = sasl_client_start (saslconn, method, &interaction, + &pc, &olen, &mech); +#else rc = sasl_client_start (saslconn, method, NULL, &interaction, &pc, &olen, &mech); +#endif if (rc == SASL_INTERACT) mutt_sasl_interact (interaction); } @@ -108,7 +127,11 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method) if (irc == IMAP_CMD_RESPOND) { +#ifdef USE_SASL2 + if (sasl_decode64 (idata->cmd.buf+2, strlen (idata->cmd.buf+2), buf, LONG_STRING-1, +#else if (sasl_decode64 (idata->cmd.buf+2, strlen (idata->cmd.buf+2), buf, +#endif &len) != SASL_OK) { dprint (1, (debugfile, "imap_auth_sasl: error base64-decoding server response.\n")); @@ -140,7 +163,9 @@ imap_auth_res_t imap_auth_sasl (IMAP_DATA* idata, const char* method) /* sasl_client_st(art|ep) allocate pc with malloc, expect me to * free it */ +#ifndef USE_SASL2 FREE (&pc); +#endif } if (olen || rc == SASL_CONTINUE) diff --git a/main.c b/main.c index 7a7c2476..d2091a00 100644 --- a/main.c +++ b/main.c @@ -232,6 +232,11 @@ static void show_version (void) "+USE_SASL " #else "-USE_SASL " +#endif +#ifdef USE_SASL2 + "+USE_SASL2 " +#else + "-USE_SASL2 " #endif "\n" diff --git a/mutt_sasl.c b/mutt_sasl.c index 4d6d7fe6..350cc307 100644 --- a/mutt_sasl.c +++ b/mutt_sasl.c @@ -23,7 +23,12 @@ #include "mutt_sasl.h" #include "mutt_socket.h" +#ifdef USE_SASL2 +#include +#include +#else #include +#endif #include #include @@ -32,6 +37,10 @@ * a protection buffer. */ #define M_SASL_MAXBUF 65536 +#ifdef USE_SASL2 +#define IP_PORT_BUFLEN 1024 +#endif + static sasl_callback_t mutt_sasl_callbacks[5]; static int mutt_sasl_start (void); @@ -50,6 +59,26 @@ static int mutt_sasl_conn_read (CONNECTION* conn, char* buf, size_t len); static int mutt_sasl_conn_write (CONNECTION* conn, const char* buf, size_t count); +#ifdef USE_SASL2 +/* utility function, stolen from sasl2 sample code */ +static int iptostring(const struct sockaddr *addr, socklen_t addrlen, + char *out, unsigned outlen) { + char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; + + if(!addr || !out) return SASL_BADPARAM; + + getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), + NI_NUMERICHOST | NI_WITHSCOPEID | NI_NUMERICSERV); + + if(outlen < strlen(hbuf) + strlen(pbuf) + 2) + return SASL_BUFOVER; + + snprintf(out, outlen, "%s;%s", hbuf, pbuf); + + return SASL_OK; +} +#endif + /* mutt_sasl_start: called before doing a SASL exchange - initialises library * (if neccessary). */ int mutt_sasl_start (void) @@ -93,7 +122,13 @@ int mutt_sasl_start (void) int mutt_sasl_client_new (CONNECTION* conn, sasl_conn_t** saslconn) { sasl_security_properties_t secprops; +#ifdef USE_SASL2 + struct sockaddr local, remote; + socklen_t size; + char iplocalport[IP_PORT_BUFLEN], ipremoteport[IP_PORT_BUFLEN]; +#else sasl_external_properties_t extprops; +#endif const char* service; int rc; @@ -112,10 +147,40 @@ int mutt_sasl_client_new (CONNECTION* conn, sasl_conn_t** saslconn) dprint (1, (debugfile, "mutt_sasl_client_new: account type unset\n")); return -1; } + +#ifdef USE_SASL2 + size = sizeof (local); + if (getsockname (conn->fd, &local, &size)){ + dprint (1, (debugfile, "mutt_sasl_client_new: getsockname for local failed\n")); + return -1; + } + else + if (iptostring(&local, size, iplocalport, IP_PORT_BUFLEN) != SASL_OK){ + dprint (1, (debugfile, "mutt_sasl_client_new: iptostring for local failed\n")); + return -1; + } + size = sizeof (remote); + if (getpeername (conn->fd, &remote, &size)){ + dprint (1, (debugfile, "mutt_sasl_client_new: getsockname for remote failed\n")); + return -1; + } + else + if (iptostring(&remote, size, ipremoteport, IP_PORT_BUFLEN) != SASL_OK){ + dprint (1, (debugfile, "mutt_sasl_client_new: iptostring for remote failed\n")); + return -1; + } + +dprint(1,(debugfile, "local ip: %s, remote ip:%s\n", iplocalport, ipremoteport)); + + rc = sasl_client_new (service, conn->account.host, iplocalport, ipremoteport, + mutt_sasl_get_callbacks (&conn->account), 0, saslconn); + +#else rc = sasl_client_new (service, conn->account.host, mutt_sasl_get_callbacks (&conn->account), SASL_SECURITY_LAYER, saslconn); - +#endif + if (rc != SASL_OK) { dprint (1, (debugfile, @@ -127,6 +192,7 @@ int mutt_sasl_client_new (CONNECTION* conn, sasl_conn_t** saslconn) /* Do we need to fail if this fails? I would assume having these unset * would just disable KRB4. Who wrote this code? I'm not sure how this * interacts with the NSS code either, since that mucks with the fd. */ +#ifndef USE_SASL2 /* with SASLv2 this all happens in sasl_client_new */ { struct sockaddr_in local, remote; socklen_t size; @@ -157,6 +223,7 @@ int mutt_sasl_client_new (CONNECTION* conn, sasl_conn_t** saslconn) } #endif } +#endif /* set security properties. We use NOPLAINTEXT globally, since we can * just fall back to LOGIN in the IMAP case anyway. If that doesn't @@ -181,14 +248,27 @@ int mutt_sasl_client_new (CONNECTION* conn, sasl_conn_t** saslconn) #if defined(USE_SSL) && !defined(USE_NSS) if (conn->account.flags & M_ACCT_SSL) { +#ifdef USE_SASL2 /* I'm not sure this actually has an effect, at least with SASLv2 */ + dprint (2, (debugfile, "External SSF: %d\n", conn->ssf)); + if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &(conn->ssf)) != SASL_OK) +#else memset (&extprops, 0, sizeof (extprops)); extprops.ssf = conn->ssf; dprint (2, (debugfile, "External SSF: %d\n", extprops.ssf)); if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &extprops) != SASL_OK) +#endif { dprint (1, (debugfile, "mutt_sasl_client_new: Error setting external properties\n")); return -1; } +#ifdef USE_SASL2 + dprint (2, (debugfile, "External authentication name: %s\n","NULL")); + if (sasl_setprop (*saslconn, SASL_AUTH_EXTERNAL, NULL) != SASL_OK) + { + dprint (1, (debugfile, "mutt_sasl_client_new: Error setting external properties\n")); + return -1; + } +#endif } #endif @@ -274,11 +354,19 @@ void mutt_sasl_setup_conn (CONNECTION* conn, sasl_conn_t* saslconn) sasldata->saslconn = saslconn; /* get ssf so we know whether we have to (en|de)code read/write */ +#ifdef USE_SASL2 + sasl_getprop (saslconn, SASL_SSF, (const void**) &sasldata->ssf); +#else sasl_getprop (saslconn, SASL_SSF, (void**) &sasldata->ssf); +#endif dprint (3, (debugfile, "SASL protection strength: %u\n", *sasldata->ssf)); /* Add SASL SSF to transport SSF */ conn->ssf += *sasldata->ssf; +#ifdef USE_SASL2 + sasl_getprop (saslconn, SASL_MAXOUTBUF, (const void**) &sasldata->pbufsize); +#else sasl_getprop (saslconn, SASL_MAXOUTBUF, (void**) &sasldata->pbufsize); +#endif dprint (3, (debugfile, "SASL protection buffer size: %u\n", *sasldata->pbufsize)); /* clear input buffer */ @@ -398,7 +486,9 @@ static int mutt_sasl_conn_close (CONNECTION* conn) /* release sasl resources */ sasl_dispose (&sasldata->saslconn); +#ifndef USE_SASL2 FREE (&sasldata->buf); +#endif FREE (&sasldata); /* call underlying close */ @@ -430,7 +520,9 @@ static int mutt_sasl_conn_read (CONNECTION* conn, char* buf, size_t len) conn->sockdata = sasldata->sockdata; +#ifndef USE_SASL2 FREE (&sasldata->buf); +#endif sasldata->bpos = 0; sasldata->blen = 0; @@ -478,7 +570,11 @@ static int mutt_sasl_conn_write (CONNECTION* conn, const char* buf, SASL_DATA* sasldata; int rc; +#ifdef USE_SASL2 + const char *pbuf; +#else char* pbuf; +#endif unsigned int olen, plen; sasldata = (SASL_DATA*) conn->sockdata; @@ -501,7 +597,9 @@ static int mutt_sasl_conn_write (CONNECTION* conn, const char* buf, } rc = (sasldata->write) (conn, pbuf, plen); +#ifndef USE_SASL2 FREE (&pbuf); +#endif if (rc != plen) goto fail; diff --git a/mutt_sasl.h b/mutt_sasl.h index 2e7e4739..eaba032f 100644 --- a/mutt_sasl.h +++ b/mutt_sasl.h @@ -21,7 +21,11 @@ #ifndef _MUTT_SASL_H_ #define _MUTT_SASL_H_ 1 +#ifdef USE_SASL2 +#include +#else #include +#endif #include "mutt_socket.h" @@ -37,7 +41,11 @@ typedef struct const unsigned int* pbufsize; /* read buffer */ +#ifdef USE_SASL2 + const char *buf; +#else char* buf; +#endif unsigned int blen; unsigned int bpos; -- 2.40.0