/* common SASL helper routines */
-#if HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include <lib-lib/lib-lib.h>
-#include "mutt.h"
-#include "account.h"
-#include "mutt_sasl.h"
-#include "mutt_socket.h"
-
-#include "lib/mem.h"
-#include "lib/debug.h"
-
-#ifdef USE_SASL2
-#include <errno.h>
#include <netdb.h>
#include <sasl/sasl.h>
-#else
-#include <sasl.h>
-#endif
#include <sys/socket.h>
#include <netinet/in.h>
-#ifdef USE_SASL2
-static int getnameinfo_err (int ret)
-{
- int err;
-
- switch (ret) {
- case EAI_AGAIN:
- debug_print (1, ("The name could not be resolved at this time. Future attempts may succeed.\n"));
- err = SASL_TRYAGAIN;
- break;
- case EAI_BADFLAGS:
- debug_print (1, ("The flags had an invalid value.\n"));
- err = SASL_BADPARAM;
- break;
- case EAI_FAIL:
- debug_print (1, ("A non-recoverable error occurred.\n"));
- err = SASL_FAIL;
- break;
- case EAI_FAMILY:
- debug_print (1, ("The address family was not recognized or the address length was invalid for the specified family.\n"));
- err = SASL_BADPROT;
- break;
- case EAI_MEMORY:
- debug_print (1, ("There was a memory allocation failure.\n"));
- err = SASL_NOMEM;
- break;
- case EAI_NONAME:
- debug_print (1, ("The name does not resolve for the supplied parameters. NI_NAMEREQD is set and the host's name cannot be located, or both nodename and servname were null.\n"));
- err = SASL_FAIL; /* no real equivalent */
- break;
- case EAI_SYSTEM:
- debug_print (1, ("A system error occurred. The error code can be found in errno(%d,%s)).\n",
- errno, strerror (errno)));
- err = SASL_FAIL; /* no real equivalent */
- break;
- default:
- debug_print (1, ("Unknown error %d\n", ret));
- err = SASL_FAIL; /* no real equivalent */
- break;
- }
- return err;
-}
-#endif
+#include <lib-ui/lib-ui.h>
+#include <lib-sys/mutt_socket.h>
+
+#include "mutt.h"
+#include "account.h"
+#include "mutt_sasl.h"
/* arbitrary. SASL will probably use a smaller buffer anyway. OTOH it's
* been a while since I've had access to an SASL server which negotiated
* a protection buffer. */
#define M_SASL_MAXBUF 65536
-#ifdef USE_SASL2
-#define IP_PORT_BUFLEN 1024
-#endif
+typedef struct {
+ sasl_conn_t *saslconn;
+ const sasl_ssf_t *ssf;
+ const unsigned int *pbufsize;
-static sasl_callback_t mutt_sasl_callbacks[5];
+ /* read buffer */
+ char *buf;
+ unsigned blen;
+ unsigned int bpos;
-static int mutt_sasl_start (void);
+ /* underlying socket data */
+ void *sockdata;
+ int (*msasl_open) (CONNECTION * conn);
+ int (*msasl_close) (CONNECTION * conn);
+ int (*msasl_read) (CONNECTION * conn, char *buf, ssize_t len);
+ int (*msasl_write) (CONNECTION * conn, const char *buf, ssize_t count);
+} SASL_DATA;
+
+static sasl_callback_t mutt_sasl_callbacks[5];
/* callbacks */
-static int mutt_sasl_cb_log (void *context, int priority,
- const char *message);
static int mutt_sasl_cb_authname (void *context, int id, const char **result,
unsigned int *len);
static int mutt_sasl_cb_pass (sasl_conn_t * conn, void *context, int id,
/* socket wrappers for a SASL security layer */
static int mutt_sasl_conn_open (CONNECTION * conn);
static int mutt_sasl_conn_close (CONNECTION * conn);
-static int mutt_sasl_conn_read (CONNECTION * conn, char *buf, size_t len);
+static int mutt_sasl_conn_read (CONNECTION * conn, char *buf, ssize_t len);
static int mutt_sasl_conn_write (CONNECTION * conn, const char *buf,
- size_t count);
+ ssize_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)
+static int
+iptostring(const struct sockaddr_storage *addr, char *out, unsigned outlen)
{
- char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
- int ret;
-
- if (!addr || !out)
- return SASL_BADPARAM;
+ char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
- ret = getnameinfo (addr, addrlen, hbuf, sizeof (hbuf), pbuf, sizeof (pbuf),
- NI_NUMERICHOST |
-#ifdef NI_WITHSCOPEID
- NI_WITHSCOPEID |
-#endif
- NI_NUMERICSERV);
- if (ret)
- return getnameinfo_err (ret);
+ if (getnameinfo((struct sockaddr*)addr, sizeof(*addr),
+ hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ return SASL_FAIL;
- if (outlen < safe_strlen (hbuf) + safe_strlen (pbuf) + 2)
- return SASL_BUFOVER;
-
- snprintf (out, outlen, "%s;%s", hbuf, pbuf);
-
- return SASL_OK;
+ 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)
+ * (if necessary). */
+static int mutt_sasl_start (void)
{
- static unsigned char sasl_init = 0;
-
- static sasl_callback_t callbacks[2];
- int rc;
-
- if (sasl_init)
- return SASL_OK;
-
- /* set up default logging callback */
- callbacks[0].id = SASL_CB_LOG;
- callbacks[0].proc = mutt_sasl_cb_log;
- callbacks[0].context = NULL;
-
- callbacks[1].id = SASL_CB_LIST_END;
- callbacks[1].proc = NULL;
- callbacks[1].context = NULL;
+ static int sasl_init = 0;
- rc = sasl_client_init (callbacks);
+ if (sasl_init)
+ return SASL_OK;
- if (rc != SASL_OK) {
- debug_print (1, ("libsasl initialisation failed.\n"));
- return SASL_FAIL;
- }
+ if (sasl_client_init(NULL) != SASL_OK)
+ return SASL_FAIL;
- sasl_init = 1;
+ sasl_init = 1;
- return SASL_OK;
+ return SASL_OK;
}
-/* mutt_sasl_client_new: wrapper for sasl_client_new which also sets various
- * security properties. If this turns out to be fine for POP too we can
- * probably stop exporting mutt_sasl_get_callbacks(). */
-int mutt_sasl_client_new (CONNECTION * conn, sasl_conn_t ** saslconn)
+static sasl_callback_t *mutt_sasl_get_callbacks (ACCOUNT * account)
{
- sasl_security_properties_t secprops;
-
-#ifdef USE_SASL2
- struct sockaddr_storage 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;
-
- if (mutt_sasl_start () != SASL_OK)
- return -1;
+ sasl_callback_t *callback;
- switch (conn->account.type) {
- case M_ACCT_TYPE_IMAP:
- service = "imap";
- break;
- case M_ACCT_TYPE_POP:
- service = "pop";
- break;
- default:
- debug_print (1, ("account type unset\n"));
- return -1;
- }
+ callback = mutt_sasl_callbacks;
-#ifdef USE_SASL2
- size = sizeof (local);
- if (getsockname (conn->fd, (struct sockaddr *) &local, &size)) {
- debug_print (1, ("getsockname for local failed\n"));
- return -1;
- }
- else
- if (iptostring
- ((struct sockaddr *) &local, size, iplocalport,
- IP_PORT_BUFLEN) != SASL_OK) {
- debug_print (1, ("iptostring for local failed\n"));
- return -1;
- }
+ callback->id = SASL_CB_USER;
+ callback->proc = mutt_sasl_cb_authname;
+ callback->context = account;
+ callback++;
- size = sizeof (remote);
- if (getpeername (conn->fd, (struct sockaddr *) &remote, &size)) {
- debug_print (1, ("getsockname for remote failed\n"));
- return -1;
- }
- else
- if (iptostring
- ((struct sockaddr *) &remote, size, ipremoteport,
- IP_PORT_BUFLEN) != SASL_OK) {
- debug_print (1, ("iptostring for remote failed\n"));
- return -1;
- }
+ callback->id = SASL_CB_AUTHNAME;
+ callback->proc = mutt_sasl_cb_authname;
+ callback->context = account;
+ callback++;
- debug_print (1, ("local ip: %s, remote ip:%s\n", iplocalport, ipremoteport));
+ callback->id = SASL_CB_PASS;
+ callback->proc = mutt_sasl_cb_pass;
+ callback->context = account;
+ callback++;
- rc =
- sasl_client_new (service, conn->account.host, iplocalport, ipremoteport,
- mutt_sasl_get_callbacks (&conn->account), 0, saslconn);
+ callback->id = SASL_CB_GETREALM;
+ callback->proc = NULL;
+ callback->context = NULL;
+ callback++;
-#else
- rc = sasl_client_new (service, conn->account.host,
- mutt_sasl_get_callbacks (&conn->account),
- SASL_SECURITY_LAYER, saslconn);
-#endif
+ callback->id = SASL_CB_LIST_END;
+ callback->proc = NULL;
+ callback->context = NULL;
- if (rc != SASL_OK) {
- debug_print (1, ("Error allocating SASL connection\n"));
- return -1;
- }
-
- /*** set sasl IP properties, necessary for use with krb4 ***/
- /* 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;
+ return mutt_sasl_callbacks;
+}
+
+int mutt_sasl_client_new (CONNECTION * conn, sasl_conn_t ** saslconn)
+{
+ sasl_security_properties_t secprops;
+
+ struct sockaddr_storage local, remote;
socklen_t size;
+ char iplocalport[STRING], ipremoteport[STRING];
+ const char *service;
+ int rc;
- size = sizeof (local);
- if (getsockname (conn->fd, (struct sockaddr *) &local, &size))
- return -1;
+ if (mutt_sasl_start() != SASL_OK)
+ return -1;
- size = sizeof (remote);
- if (getpeername (conn->fd, (struct sockaddr *) &remote, &size))
- return -1;
+ switch (conn->account.type) {
+ case M_ACCT_TYPE_IMAP:
+ service = "imap";
+ break;
-#ifdef SASL_IP_LOCAL
- if (sasl_setprop (*saslconn, SASL_IP_LOCAL, &local) != SASL_OK) {
- debug_print (1, ("Error setting local IP address\n"));
- return -1;
- }
-#endif
+ case M_ACCT_TYPE_POP:
+ service = "pop";
+ break;
-#ifdef SASL_IP_REMOTE
- if (sasl_setprop (*saslconn, SASL_IP_REMOTE, &remote) != SASL_OK) {
- debug_print (1, ("Error setting remote IP address\n"));
- return -1;
+ default:
+ return -1;
}
-#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
- * work for POP, we can make it a flag or move this code into
- * imap/auth_sasl.c */
- memset (&secprops, 0, sizeof (secprops));
- /* Work around a casting bug in the SASL krb4 module */
- secprops.max_ssf = 0x7fff;
- secprops.maxbufsize = M_SASL_MAXBUF;
- secprops.security_flags |= SASL_SEC_NOPLAINTEXT;
- if (sasl_setprop (*saslconn, SASL_SEC_PROPS, &secprops) != SASL_OK) {
- debug_print (1, ("Error setting security properties\n"));
- return -1;
- }
-
- /* we currently don't have an SSF finder for NSS (I don't know the API).
- * If someone does it'd probably be trivial to write mutt_nss_get_ssf().
- * I have a feeling more SSL code could be shared between those two files,
- * but I haven't looked into it yet, since I still don't know the APIs. */
-#if (defined(USE_SSL) || defined(USE_GNUTLS) && !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 */
- debug_print (2, ("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;
- debug_print (2, ("External SSF: %d\n", extprops.ssf));
- if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &extprops) != SASL_OK)
-#endif
+
+ size = sizeof(local);
+ if (getsockname(conn->fd, (struct sockaddr *) &local, &size)
+ || iptostring(&local, iplocalport, STRING) != SASL_OK)
{
- debug_print (1, ("Error setting external properties\n"));
- return -1;
+ return -1;
}
-#ifdef USE_SASL2
- debug_print (2, ("External authentication name: %s\n", conn->account.user));
- if (sasl_setprop (*saslconn, SASL_AUTH_EXTERNAL, conn->account.user) !=
- SASL_OK) {
- debug_print (1, ("Error setting external properties\n"));
- return -1;
- }
-#endif
- }
-#endif
-
- return 0;
-}
-
-sasl_callback_t *mutt_sasl_get_callbacks (ACCOUNT * account)
-{
- sasl_callback_t *callback;
- callback = mutt_sasl_callbacks;
-
- callback->id = SASL_CB_USER;
- callback->proc = mutt_sasl_cb_authname;
- callback->context = account;
- callback++;
+ size = sizeof(remote);
+ if (getpeername(conn->fd, (struct sockaddr *) &remote, &size)
+ || iptostring(&remote, ipremoteport, STRING) != SASL_OK)
+ {
+ return -1;
+ }
- callback->id = SASL_CB_AUTHNAME;
- callback->proc = mutt_sasl_cb_authname;
- callback->context = account;
- callback++;
+ rc = sasl_client_new(service, conn->account.host, iplocalport,
+ ipremoteport,
+ mutt_sasl_get_callbacks(&conn->account), 0, saslconn);
- callback->id = SASL_CB_PASS;
- callback->proc = mutt_sasl_cb_pass;
- callback->context = account;
- callback++;
+ if (rc != SASL_OK) {
+ return -1;
+ }
- callback->id = SASL_CB_GETREALM;
- callback->proc = NULL;
- callback->context = NULL;
- callback++;
+ /* set security properties. We use NOPLAINTEXT globally, since we can
+ * just fall back to LOGIN in the IMAP case anyway. If that doesn't
+ * work for POP, we can make it a flag or move this code into
+ * imap/auth_sasl.c */
+ p_clear(&secprops, 1);
+ /* Work around a casting bug in the SASL krb4 module */
+ secprops.max_ssf = 0x7fff;
+ secprops.maxbufsize = M_SASL_MAXBUF;
+ secprops.security_flags |= SASL_SEC_NOPLAINTEXT;
+ if (sasl_setprop (*saslconn, SASL_SEC_PROPS, &secprops) != SASL_OK) {
+ return -1;
+ }
- callback->id = SASL_CB_LIST_END;
- callback->proc = NULL;
- callback->context = NULL;
+ if (conn->ssf) {
+ if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &(conn->ssf)) != SASL_OK)
+ {
+ return -1;
+ }
+ if (sasl_setprop (*saslconn, SASL_AUTH_EXTERNAL, conn->account.user) !=
+ SASL_OK) {
+ return -1;
+ }
+ }
- return mutt_sasl_callbacks;
+ return 0;
}
int mutt_sasl_interact (sasl_interact_t * interaction)
{
- char prompt[SHORT_STRING];
- char resp[SHORT_STRING];
-
- while (interaction->id != SASL_CB_LIST_END) {
- debug_print (2, ("filling in SASL interaction %ld.\n", interaction->id));
-
- snprintf (prompt, sizeof (prompt), "%s: ", interaction->prompt);
- resp[0] = '\0';
- if (mutt_get_field (prompt, resp, sizeof (resp), 0))
- return SASL_FAIL;
-
- interaction->len = safe_strlen (resp) + 1;
- interaction->result = safe_malloc (interaction->len);
- memcpy (interaction->result, resp, interaction->len);
-
- interaction++;
- }
+ char prompt[STRING];
+ char resp[STRING];
+
+ while (interaction->id != SASL_CB_LIST_END) {
+ snprintf (prompt, sizeof (prompt), "%s: ", interaction->prompt);
+ resp[0] = '\0';
+ if (mutt_get_field (prompt, resp, sizeof (resp), 0))
+ return SASL_FAIL;
+
+ interaction->len = m_strlen(resp) + 1;
+ interaction->result = p_dupstr(resp, interaction->len - 1);
+ interaction++;
+ }
- return SASL_OK;
+ return SASL_OK;
}
/* SASL can stack a protection layer on top of an existing connection.
* for the read/write methods. */
void mutt_sasl_setup_conn (CONNECTION * conn, sasl_conn_t * saslconn)
{
- SASL_DATA *sasldata = (SASL_DATA *) safe_malloc (sizeof (SASL_DATA));
-
- 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
- debug_print (3, ("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
- debug_print (3, ("SASL protection buffer size: %u\n", *sasldata->pbufsize));
-
- /* clear input buffer */
- sasldata->buf = NULL;
- sasldata->bpos = 0;
- sasldata->blen = 0;
-
- /* preserve old functions */
- sasldata->sockdata = conn->sockdata;
- sasldata->msasl_open = conn->conn_open;
- sasldata->msasl_close = conn->conn_close;
- sasldata->msasl_read = conn->conn_read;
- sasldata->msasl_write = conn->conn_write;
-
- /* and set up new functions */
- conn->sockdata = sasldata;
- conn->conn_open = mutt_sasl_conn_open;
- conn->conn_close = mutt_sasl_conn_close;
- conn->conn_read = mutt_sasl_conn_read;
- conn->conn_write = mutt_sasl_conn_write;
+ SASL_DATA *sasldata = p_new(SASL_DATA, 1);
+
+ sasldata->saslconn = saslconn;
+ /* get ssf so we know whether we have to (en|de)code read/write */
+ sasl_getprop (saslconn, SASL_SSF, (const void **)(void *)&sasldata->ssf);
+
+ /* Add SASL SSF to transport SSF */
+ conn->ssf += *sasldata->ssf;
+ sasl_getprop (saslconn, SASL_MAXOUTBUF,
+ (const void **)(void *)&sasldata->pbufsize);
+
+ /* clear input buffer */
+ sasldata->buf = NULL;
+ sasldata->bpos = 0;
+ sasldata->blen = 0;
+
+ /* preserve old functions */
+ sasldata->sockdata = conn->sockdata;
+ sasldata->msasl_open = conn->conn_open;
+ sasldata->msasl_close = conn->conn_close;
+ sasldata->msasl_read = conn->conn_read;
+ sasldata->msasl_write = conn->conn_write;
+
+ /* and set up new functions */
+ conn->sockdata = sasldata;
+ conn->conn_open = mutt_sasl_conn_open;
+ conn->conn_close = mutt_sasl_conn_close;
+ conn->conn_read = mutt_sasl_conn_read;
+ conn->conn_write = mutt_sasl_conn_write;
}
-/* mutt_sasl_cb_log: callback to log SASL messages */
-static int mutt_sasl_cb_log (void *context, int priority, const char *message)
-{
- debug_print (priority, ("SASL: %s\n", message));
-
- return SASL_OK;
+void mutt_sasl_shutdown(void) {
+ sasl_done();
}
/* mutt_sasl_cb_authname: callback to retrieve authname or user from ACCOUNT */
static int mutt_sasl_cb_authname (void *context, int id, const char **result,
unsigned *len)
{
- ACCOUNT *account = (ACCOUNT *) context;
-
- *result = NULL;
- if (len)
- *len = 0;
-
- if (!account)
- return SASL_BADPARAM;
-
- debug_print (2, ("getting %s for %s:%u\n",
- id == SASL_CB_AUTHNAME ? "authname" : "user",
- account->host, account->port));
-
- if (id == SASL_CB_AUTHNAME) {
- if (mutt_account_getlogin (account))
- return SASL_FAIL;
- *result = account->login;
- } else {
- if (mutt_account_getuser (account))
- return SASL_FAIL;
- *result = account->user;
- }
+ ACCOUNT *account = (ACCOUNT *) context;
+
+ *result = NULL;
+ if (len)
+ *len = 0;
+
+ if (!account)
+ return SASL_BADPARAM;
+
+ if (id == SASL_CB_AUTHNAME) {
+ if (mutt_account_getlogin (account))
+ return SASL_FAIL;
+ *result = account->login;
+ } else {
+ if (mutt_account_getuser (account))
+ return SASL_FAIL;
+ *result = account->user;
+ }
- if (len)
- *len = safe_strlen (*result);
+ if (len)
+ *len = m_strlen(*result);
- return SASL_OK;
+ return SASL_OK;
}
-static int mutt_sasl_cb_pass (sasl_conn_t * conn, void *context, int id,
- sasl_secret_t ** psecret)
+static int mutt_sasl_cb_pass(sasl_conn_t *conn __attribute__ ((unused)),
+ void *context, int id __attribute__ ((unused)),
+ sasl_secret_t **psecret)
{
- ACCOUNT *account = (ACCOUNT *) context;
- int len;
-
- if (!account || !psecret)
- return SASL_BADPARAM;
+ ACCOUNT *account = (ACCOUNT *) context;
+ int len;
- debug_print (2, ("getting password for %s@%s:%u\n",
- account->login, account->host, account->port));
+ if (!account || !psecret)
+ return SASL_BADPARAM;
- if (mutt_account_getpass (account))
- return SASL_FAIL;
+ if (mutt_account_getpass (account))
+ return SASL_FAIL;
- len = safe_strlen (account->pass);
+ len = m_strlen(account->pass);
- *psecret = (sasl_secret_t *) safe_malloc (sizeof (sasl_secret_t) + len);
- (*psecret)->len = len;
- strcpy ((*psecret)->data, account->pass); /* __STRCPY_CHECKED__ */
+ *psecret = xmalloc(sizeof(sasl_secret_t) + len);
+ (*psecret)->len = len;
+ memcpy((char*)(*psecret)->data, account->pass, len);
- return SASL_OK;
+ return SASL_OK;
}
/* mutt_sasl_conn_open: empty wrapper for underlying open function. We
* is successful, using mutt_sasl_setup_conn */
static int mutt_sasl_conn_open (CONNECTION * conn)
{
- SASL_DATA *sasldata;
- int rc;
+ SASL_DATA *sasldata;
+ int rc;
- sasldata = (SASL_DATA *) conn->sockdata;
- conn->sockdata = sasldata->sockdata;
- rc = (sasldata->msasl_open) (conn);
- conn->sockdata = sasldata;
+ sasldata = (SASL_DATA *) conn->sockdata;
+ conn->sockdata = sasldata->sockdata;
+ rc = (sasldata->msasl_open) (conn);
+ conn->sockdata = sasldata;
- return rc;
+ return rc;
}
/* mutt_sasl_conn_close: calls underlying close function and disposes of
* the sasl_conn_t object, then restores connection to pre-sasl state */
-static int mutt_sasl_conn_close (CONNECTION * conn)
+static int mutt_sasl_conn_close(CONNECTION * conn)
{
- SASL_DATA *sasldata;
- int rc;
+ SASL_DATA *sasldata;
+ int rc;
- sasldata = (SASL_DATA *) conn->sockdata;
+ sasldata = (SASL_DATA *) conn->sockdata;
- /* restore connection's underlying methods */
- conn->sockdata = sasldata->sockdata;
- conn->conn_open = sasldata->msasl_open;
- conn->conn_close = sasldata->msasl_close;
- conn->conn_read = sasldata->msasl_read;
- conn->conn_write = sasldata->msasl_write;
+ /* restore connection's underlying methods */
+ conn->sockdata = sasldata->sockdata;
+ conn->conn_open = sasldata->msasl_open;
+ conn->conn_close = sasldata->msasl_close;
+ conn->conn_read = sasldata->msasl_read;
+ conn->conn_write = sasldata->msasl_write;
- /* release sasl resources */
- sasl_dispose (&sasldata->saslconn);
-#ifndef USE_SASL2
- FREE (&sasldata->buf);
-#endif
- FREE (&sasldata);
+ /* release sasl resources */
+ sasl_dispose (&sasldata->saslconn);
+ p_delete(&sasldata->buf);
+ p_delete(&sasldata);
- /* call underlying close */
- rc = (conn->conn_close) (conn);
+ /* call underlying close */
+ rc = (conn->conn_close) (conn);
- return rc;
+ return rc;
}
-static int mutt_sasl_conn_read (CONNECTION * conn, char *buf, size_t len)
+static int mutt_sasl_conn_read (CONNECTION * conn, char *buf, ssize_t len)
{
- SASL_DATA *sasldata;
- int rc;
-
- unsigned int olen;
-
- sasldata = (SASL_DATA *) conn->sockdata;
-
- /* if we still have data in our read buffer, copy it into buf */
- if (sasldata->blen > sasldata->bpos) {
- olen = (sasldata->blen - sasldata->bpos > len) ? len :
- sasldata->blen - sasldata->bpos;
-
- memcpy (buf, sasldata->buf + sasldata->bpos, olen);
- sasldata->bpos += olen;
-
- return olen;
- }
-
- conn->sockdata = sasldata->sockdata;
-
-#ifndef USE_SASL2
- FREE (&sasldata->buf);
-#endif
- sasldata->bpos = 0;
- sasldata->blen = 0;
-
- /* and decode the result, if necessary */
- if (*sasldata->ssf) {
- do {
- /* call the underlying read function to fill the buffer */
- rc = (sasldata->msasl_read) (conn, buf, len);
- if (rc <= 0)
- goto out;
-
- rc = sasl_decode (sasldata->saslconn, buf, rc, &sasldata->buf,
- &sasldata->blen);
- if (rc != SASL_OK) {
- debug_print (1, ("SASL decode failed: %s\n",
- sasl_errstring (rc, NULL, NULL)));
- goto out;
- }
+ SASL_DATA *sasldata;
+ int rc;
+
+ unsigned int olen;
+
+ sasldata = (SASL_DATA *) conn->sockdata;
+
+ /* if we still have data in our read buffer, copy it into buf */
+ if (sasldata->blen > sasldata->bpos) {
+ olen = (sasldata->blen - sasldata->bpos > len) ? len :
+ sasldata->blen - sasldata->bpos;
+
+ memcpy (buf, sasldata->buf + sasldata->bpos, olen);
+ sasldata->bpos += olen;
+
+ return olen;
}
- while (!sasldata->blen);
- olen = (sasldata->blen - sasldata->bpos > len) ? len :
- sasldata->blen - sasldata->bpos;
+ conn->sockdata = sasldata->sockdata;
+
+ p_delete(&sasldata->buf);
+ sasldata->bpos = 0;
+ sasldata->blen = 0;
+
+ /* and decode the result, if necessary */
+ if (*sasldata->ssf) {
+ do {
+ /* call the underlying read function to fill the buffer */
+ rc = (sasldata->msasl_read) (conn, buf, len);
+ if (rc <= 0)
+ goto out;
- memcpy (buf, sasldata->buf, olen);
- sasldata->bpos += olen;
+ rc = sasl_decode(sasldata->saslconn, buf, rc,
+ (const char **)&sasldata->buf, &sasldata->blen);
+ if (rc != SASL_OK) {
+ goto out;
+ }
+ }
+ while (!sasldata->blen);
- rc = olen;
- }
- else
- rc = (sasldata->msasl_read) (conn, buf, len);
+ olen = (sasldata->blen - sasldata->bpos > len) ? len :
+ sasldata->blen - sasldata->bpos;
+
+ memcpy (buf, sasldata->buf, olen);
+ sasldata->bpos += olen;
+
+ rc = olen;
+ }
+ else
+ rc = (sasldata->msasl_read) (conn, buf, len);
out:
- conn->sockdata = sasldata;
+ conn->sockdata = sasldata;
- return rc;
+ return rc;
}
-static int mutt_sasl_conn_write (CONNECTION * conn, const char *buf,
- size_t len)
+static int
+mutt_sasl_conn_write(CONNECTION * conn, const char *buf, ssize_t len)
{
- SASL_DATA *sasldata;
- int rc;
-
-#ifdef USE_SASL2
- const char *pbuf;
-#else
- char *pbuf;
-#endif
- unsigned int olen, plen;
-
- sasldata = (SASL_DATA *) conn->sockdata;
- conn->sockdata = sasldata->sockdata;
-
- /* encode data, if necessary */
- if (*sasldata->ssf) {
- /* handle data larger than MAXOUTBUF */
- do {
- olen = (len > *sasldata->pbufsize) ? *sasldata->pbufsize : len;
-
- rc = sasl_encode (sasldata->saslconn, buf, olen, &pbuf, &plen);
- if (rc != SASL_OK) {
- debug_print (1, ("SASL encoding failed: %s\n",
- sasl_errstring (rc, NULL, NULL)));
- goto fail;
- }
-
- rc = (sasldata->msasl_write) (conn, pbuf, plen);
-#ifndef USE_SASL2
- FREE (&pbuf);
-#endif
- if (rc != plen)
- goto fail;
-
- len -= olen;
- buf += olen;
+ SASL_DATA *sasldata;
+ int rc;
+
+ char *pbuf;
+ unsigned int olen, plen;
+
+ sasldata = (SASL_DATA *) conn->sockdata;
+ conn->sockdata = sasldata->sockdata;
+
+ /* encode data, if necessary */
+ if (*sasldata->ssf) {
+ /* handle data larger than MAXOUTBUF */
+ do {
+ olen = (len > *sasldata->pbufsize) ? *sasldata->pbufsize : len;
+
+ rc = sasl_encode(sasldata->saslconn, buf, olen,
+ (const char **)&pbuf, &plen);
+ if (rc != SASL_OK) {
+ goto fail;
+ }
+
+ plen -= (sasldata->msasl_write)(conn, pbuf, plen);
+ p_delete(&pbuf);
+ if (plen)
+ goto fail;
+
+ len -= olen;
+ buf += olen;
+ } while (len > *sasldata->pbufsize);
+ } else {
+ /* just write using the underlying socket function */
+ rc = (sasldata->msasl_write) (conn, buf, len);
}
- while (len > *sasldata->pbufsize);
- }
- else
- /* just write using the underlying socket function */
- rc = (sasldata->msasl_write) (conn, buf, len);
- conn->sockdata = sasldata;
+ conn->sockdata = sasldata;
- return rc;
+ return rc;
fail:
- conn->sockdata = sasldata;
- return -1;
+ conn->sockdata = sasldata;
+ return -1;
}