#include "account.h"
#include "mutt_sasl.h"
-static int getnameinfo_err (int ret)
-{
- int err;
-
- switch (ret) {
- case EAI_AGAIN:
- err = SASL_TRYAGAIN;
- break;
- case EAI_BADFLAGS:
- err = SASL_BADPARAM;
- break;
- case EAI_FAIL:
- err = SASL_FAIL;
- break;
- case EAI_FAMILY:
- err = SASL_BADPROT;
- break;
- case EAI_MEMORY:
- err = SASL_NOMEM;
- break;
- case EAI_NONAME:
- err = SASL_FAIL; /* no real equivalent */
- break;
- case EAI_SYSTEM:
- err = SASL_FAIL; /* no real equivalent */
- break;
- default:
- err = SASL_FAIL; /* no real equivalent */
- break;
- }
- return err;
-}
-
/* 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. */
static sasl_callback_t mutt_sasl_callbacks[5];
-static int mutt_sasl_start (void);
-
/* callbacks */
static int mutt_sasl_cb_authname (void *context, int id, const char **result,
unsigned int *len);
static int mutt_sasl_conn_write (CONNECTION * conn, const char *buf,
ssize_t count);
-/* 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 (outlen < m_strlen(hbuf) + m_strlen(pbuf) + 2)
- return SASL_BUFOVER;
-
- snprintf (out, outlen, "%s;%s", hbuf, pbuf);
-
- return SASL_OK;
-}
+ if (getnameinfo((struct sockaddr*)addr, sizeof(*addr),
+ hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV))
+ return SASL_FAIL;
-/* mutt_sasl_cb_log: callback to log SASL messages */
-static int mutt_sasl_cb_log (void *context, int priority, const char *message)
-{
- return SASL_OK;
+ snprintf(out, outlen, "%s;%s", hbuf, pbuf);
+ return SASL_OK;
}
/* mutt_sasl_start: called before doing a SASL exchange - initialises library
* (if necessary). */
-int mutt_sasl_start (void)
+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;
+ static int sasl_init = 0;
- callbacks[1].id = SASL_CB_LIST_END;
- callbacks[1].proc = NULL;
- callbacks[1].context = NULL;
+ if (sasl_init)
+ return SASL_OK;
- rc = sasl_client_init (callbacks);
+ if (sasl_client_init(NULL) != SASL_OK)
+ return SASL_FAIL;
- if (rc != 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;
+ sasl_callback_t *callback;
- struct sockaddr_storage local, remote;
- socklen_t size;
- char iplocalport[IP_PORT_BUFLEN], ipremoteport[IP_PORT_BUFLEN];
- const char *service;
- int rc;
+ callback = mutt_sasl_callbacks;
- if (mutt_sasl_start () != SASL_OK)
- return -1;
+ callback->id = SASL_CB_USER;
+ callback->proc = mutt_sasl_cb_authname;
+ callback->context = account;
+ callback++;
- switch (conn->account.type) {
- case M_ACCT_TYPE_IMAP:
- service = "imap";
- break;
- case M_ACCT_TYPE_POP:
- service = "pop";
- break;
- default:
- return -1;
- }
+ callback->id = SASL_CB_AUTHNAME;
+ callback->proc = mutt_sasl_cb_authname;
+ callback->context = account;
+ callback++;
- size = sizeof (local);
- if (getsockname (conn->fd, (struct sockaddr *) &local, &size)) {
- return -1;
- }
- else
- if (iptostring((struct sockaddr *)&local, size, iplocalport,
- IP_PORT_BUFLEN) != SASL_OK) {
- return -1;
- }
+ callback->id = SASL_CB_PASS;
+ callback->proc = mutt_sasl_cb_pass;
+ callback->context = account;
+ callback++;
- size = sizeof (remote);
- if (getpeername (conn->fd, (struct sockaddr *) &remote, &size)) {
- return -1;
- }
- else
- if (iptostring
- ((struct sockaddr *) &remote, size, ipremoteport,
- IP_PORT_BUFLEN) != SASL_OK) {
- return -1;
- }
+ callback->id = SASL_CB_GETREALM;
+ callback->proc = NULL;
+ callback->context = NULL;
+ callback++;
- rc = sasl_client_new(service, conn->account.host, iplocalport, ipremoteport,
- mutt_sasl_get_callbacks(&conn->account), 0, saslconn);
+ callback->id = SASL_CB_LIST_END;
+ callback->proc = NULL;
+ callback->context = NULL;
- if (rc != SASL_OK) {
- 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?
- */
- {
- 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[IP_PORT_BUFLEN], ipremoteport[IP_PORT_BUFLEN];
+ 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) {
- 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) {
- return -1;
+ default:
+ return -1;
}
-#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 */
- 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;
- }
- if (conn->ssf) {
- if (sasl_setprop (*saslconn, SASL_SSF_EXTERNAL, &(conn->ssf)) != SASL_OK)
+ size = sizeof(local);
+ if (getsockname(conn->fd, (struct sockaddr *) &local, &size)
+ || iptostring(&local, iplocalport, IP_PORT_BUFLEN) != SASL_OK)
{
- return -1;
- }
- if (sasl_setprop (*saslconn, SASL_AUTH_EXTERNAL, conn->account.user) !=
- SASL_OK) {
- return -1;
+ return -1;
}
- }
- 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, IP_PORT_BUFLEN) != 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) {
- 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++;
- }
+ char prompt[SHORT_STRING];
+ char resp[SHORT_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 = 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;
+ 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;
}
void mutt_sasl_done (void) {
- sasl_done ();
+ 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;
-
- 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 = m_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, void *context, int id,
+ sasl_secret_t **psecret)
{
- ACCOUNT *account = (ACCOUNT *) context;
- int len;
+ ACCOUNT *account = (ACCOUNT *) context;
+ int len;
- if (!account || !psecret)
- return SASL_BADPARAM;
+ if (!account || !psecret)
+ return SASL_BADPARAM;
- if (mutt_account_getpass (account))
- return SASL_FAIL;
+ if (mutt_account_getpass (account))
+ return SASL_FAIL;
- len = m_strlen(account->pass);
+ len = m_strlen(account->pass);
- *psecret = xmalloc(sizeof(sasl_secret_t) + len);
- (*psecret)->len = len;
- strcpy ((char*) (*psecret)->data, account->pass); /* __STRCPY_CHECKED__ */
+ *psecret = xmalloc(sizeof(sasl_secret_t) + len);
+ (*psecret)->len = len;
+ strcpy((char*)(*psecret)->data, account->pass);
- 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);
- p_delete(&sasldata->buf);
- p_delete(&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, ssize_t len)
{
- SASL_DATA *sasldata;
- int rc;
+ SASL_DATA *sasldata;
+ int rc;
- unsigned int olen;
+ unsigned int olen;
- sasldata = (SASL_DATA *) conn->sockdata;
+ 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;
+ /* 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;
+ memcpy (buf, sasldata->buf + sasldata->bpos, olen);
+ sasldata->bpos += olen;
- return olen;
- }
+ return olen;
+ }
- conn->sockdata = sasldata->sockdata;
+ conn->sockdata = sasldata->sockdata;
- p_delete(&sasldata->buf);
- sasldata->bpos = 0;
- sasldata->blen = 0;
+ 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;
+ /* 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) {
- goto out;
- }
- }
- while (!sasldata->blen);
+ rc = sasl_decode(sasldata->saslconn, buf, rc,
+ (const char **)&sasldata->buf, &sasldata->blen);
+ if (rc != SASL_OK) {
+ goto out;
+ }
+ }
+ while (!sasldata->blen);
- olen = (sasldata->blen - sasldata->bpos > len) ? len :
- sasldata->blen - sasldata->bpos;
+ olen = (sasldata->blen - sasldata->bpos > len) ? len :
+ sasldata->blen - sasldata->bpos;
- memcpy (buf, sasldata->buf, olen);
- sasldata->bpos += olen;
+ memcpy (buf, sasldata->buf, olen);
+ sasldata->bpos += olen;
- rc = olen;
- }
- else
- rc = (sasldata->msasl_read) (conn, buf, len);
+ 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,
- ssize_t len)
+static int
+mutt_sasl_conn_write(CONNECTION * conn, const char *buf, ssize_t len)
{
- SASL_DATA *sasldata;
- int rc;
-
- const 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, &pbuf, &plen);
- if (rc != SASL_OK) {
- goto fail;
- }
-
- rc = (sasldata->msasl_write) (conn, pbuf, plen);
- p_delete(&pbuf);
- 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;
+ }
+
+ rc = (sasldata->msasl_write)(conn, pbuf, plen);
+ p_delete(&pbuf);
+ if (rc != 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;
}