NeoMutt  2020-06-26-89-g172cd3
Teaching an old dog new tricks
DOXYGEN
sasl.c File Reference

SASL authentication support. More...

#include "config.h"
#include <stddef.h>
#include <errno.h>
#include <netdb.h>
#include <sasl/sasl.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "mutt/lib.h"
#include "gui/lib.h"
#include "mutt.h"
#include "sasl.h"
#include "lib.h"
#include "options.h"
+ Include dependency graph for sasl.c:

Go to the source code of this file.

Data Structures

struct  SaslSockData
 SASL authentication API. More...
 

Macros

#define MUTT_SASL_MAXBUF   65536
 
#define IP_PORT_BUFLEN   1024
 

Functions

static int getnameinfo_err (int ret)
 Convert a getaddrinfo() error code into an SASL error code. More...
 
static int iptostring (const struct sockaddr *addr, socklen_t addrlen, char *out, unsigned int outlen)
 Convert IP Address to string. More...
 
static int mutt_sasl_cb_log (void *context, int priority, const char *message)
 callback to log SASL messages More...
 
static int mutt_sasl_start (void)
 Initialise SASL library. More...
 
static int mutt_sasl_cb_authname (void *context, int id, const char **result, unsigned int *len)
 callback to retrieve authname or user from ConnAccount More...
 
static int mutt_sasl_cb_pass (sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
 SASL callback function to get password. More...
 
static sasl_callback_t * mutt_sasl_get_callbacks (struct ConnAccount *cac)
 Get the SASL callback functions. More...
 
static int mutt_sasl_conn_open (struct Connection *conn)
 empty wrapper for underlying open function - Implements Connection::open() More...
 
static int mutt_sasl_conn_close (struct Connection *conn)
 close SASL connection - Implements Connection::close() More...
 
static int mutt_sasl_conn_read (struct Connection *conn, char *buf, size_t count)
 Read data from an SASL connection - Implements Connection::read() More...
 
static int mutt_sasl_conn_write (struct Connection *conn, const char *buf, size_t count)
 Write to an SASL connection - Implements Connection::write() More...
 
static int mutt_sasl_conn_poll (struct Connection *conn, time_t wait_secs)
 Check an SASL connection for data - Implements Connection::poll() More...
 
int mutt_sasl_client_new (struct Connection *conn, sasl_conn_t **saslconn)
 Wrapper for sasl_client_new() More...
 
int mutt_sasl_interact (sasl_interact_t *interaction)
 Perform an SASL interaction with the user. More...
 
void mutt_sasl_setup_conn (struct Connection *conn, sasl_conn_t *saslconn)
 Set up an SASL connection. More...
 
void mutt_sasl_done (void)
 Invoke when processing is complete. More...
 

Variables

static sasl_callback_t MuttSaslCallbacks [5]
 
static sasl_secret_t * secret_ptr = NULL
 

Detailed Description

SASL authentication support.

Authors
  • Brendan Cully

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file sasl.c.

Macro Definition Documentation

◆ MUTT_SASL_MAXBUF

#define MUTT_SASL_MAXBUF   65536

Definition at line 102 of file sasl.c.

◆ IP_PORT_BUFLEN

#define IP_PORT_BUFLEN   1024

Definition at line 104 of file sasl.c.

Function Documentation

◆ getnameinfo_err()

static int getnameinfo_err ( int  ret)
static

Convert a getaddrinfo() error code into an SASL error code.

Parameters
retgetaddrinfo() error code, e.g. EAI_AGAIN
Return values
numSASL error code, e.g. SASL_FAIL

Definition at line 115 of file sasl.c.

116 {
117  int err;
118  mutt_debug(LL_DEBUG1, "getnameinfo: ");
119  switch (ret)
120  {
121  case EAI_AGAIN:
123  "The name could not be resolved at this time. Future "
124  "attempts may succeed\n");
125  err = SASL_TRYAGAIN;
126  break;
127  case EAI_BADFLAGS:
128  mutt_debug(LL_DEBUG1, "The flags had an invalid value\n");
129  err = SASL_BADPARAM;
130  break;
131  case EAI_FAIL:
132  mutt_debug(LL_DEBUG1, "A non-recoverable error occurred\n");
133  err = SASL_FAIL;
134  break;
135  case EAI_FAMILY:
137  "The address family was not recognized or the address "
138  "length was invalid for the specified family\n");
139  err = SASL_BADPROT;
140  break;
141  case EAI_MEMORY:
142  mutt_debug(LL_DEBUG1, "There was a memory allocation failure\n");
143  err = SASL_NOMEM;
144  break;
145  case EAI_NONAME:
147  "The name does not resolve for the supplied parameters. "
148  "NI_NAMEREQD is set and the host's name can't be located, "
149  "or both nodename and servname were null.\n");
150  err = SASL_FAIL; /* no real equivalent */
151  break;
152  case EAI_SYSTEM:
154  "A system error occurred. The error code can be found in "
155  "errno(%d,%s))\n",
156  errno, strerror(errno));
157  err = SASL_FAIL; /* no real equivalent */
158  break;
159  default:
160  mutt_debug(LL_DEBUG1, "Unknown error %d\n", ret);
161  err = SASL_FAIL; /* no real equivalent */
162  break;
163  }
164  return err;
165 }
Log at debug level 1.
Definition: logging.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the caller graph for this function:

◆ iptostring()

static int iptostring ( const struct sockaddr *  addr,
socklen_t  addrlen,
char *  out,
unsigned int  outlen 
)
static

Convert IP Address to string.

Parameters
addrIP address
addrlenSize of addr struct
outBuffer for result
outlenLength of buffer
Return values
numSASL error code, e.g. SASL_BADPARAM

utility function, copied from sasl2 sample code

Definition at line 177 of file sasl.c.

179 {
180  char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
181  int ret;
182 
183  if (!addr || !out)
184  return SASL_BADPARAM;
185 
186  ret = getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
187  NI_NUMERICHOST |
188 #ifdef NI_WITHSCOPEID
189  NI_WITHSCOPEID |
190 #endif
191  NI_NUMERICSERV);
192  if (ret != 0)
193  return getnameinfo_err(ret);
194 
195  if (outlen < strlen(hbuf) + strlen(pbuf) + 2)
196  return SASL_BUFOVER;
197 
198  snprintf(out, outlen, "%s;%s", hbuf, pbuf);
199 
200  return SASL_OK;
201 }
static int getnameinfo_err(int ret)
Convert a getaddrinfo() error code into an SASL error code.
Definition: sasl.c:115
static unsigned char * pbuf
Cache PGP data packet.
Definition: pgppacket.c:38
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sasl_cb_log()

static int mutt_sasl_cb_log ( void *  context,
int  priority,
const char *  message 
)
static

callback to log SASL messages

Parameters
contextSupplied context, always NULL
priorityDebug level
messageMessage
Return values
numSASL_OK, always

Definition at line 210 of file sasl.c.

211 {
212  if (priority == SASL_LOG_NONE)
213  return SASL_OK;
214 
215  int mutt_priority = 0;
216  switch (priority)
217  {
218  case SASL_LOG_TRACE:
219  case SASL_LOG_PASS:
220  mutt_priority = 5;
221  break;
222  case SASL_LOG_DEBUG:
223  case SASL_LOG_NOTE:
224  mutt_priority = 3;
225  break;
226  case SASL_LOG_FAIL:
227  case SASL_LOG_WARN:
228  mutt_priority = 2;
229  break;
230  case SASL_LOG_ERR:
231  mutt_priority = 1;
232  break;
233  default:
234  mutt_debug(LL_DEBUG1, "SASL unknown log priority: %s\n", message);
235  return SASL_OK;
236  }
237  mutt_debug(mutt_priority, "SASL: %s\n", message);
238  return SASL_OK;
239 }
Log at debug level 1.
Definition: logging.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the caller graph for this function:

◆ mutt_sasl_start()

static int mutt_sasl_start ( void  )
static

Initialise SASL library.

Return values
numSASL error code, e.g. SASL_OK

Call before doing an SASL exchange - initialises library (if necessary).

Definition at line 247 of file sasl.c.

248 {
249  static bool sasl_init = false;
250 
251  static sasl_callback_t callbacks[2];
252  int rc;
253 
254  if (sasl_init)
255  return SASL_OK;
256 
257  /* set up default logging callback */
258  callbacks[0].id = SASL_CB_LOG;
259  callbacks[0].proc = (int (*)(void)) mutt_sasl_cb_log;
260  callbacks[0].context = NULL;
261 
262  callbacks[1].id = SASL_CB_LIST_END;
263  callbacks[1].proc = NULL;
264  callbacks[1].context = NULL;
265 
266  rc = sasl_client_init(callbacks);
267 
268  if (rc != SASL_OK)
269  {
270  mutt_debug(LL_DEBUG1, "libsasl initialisation failed\n");
271  return SASL_FAIL;
272  }
273 
274  sasl_init = true;
275 
276  return SASL_OK;
277 }
Log at debug level 1.
Definition: logging.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static int mutt_sasl_cb_log(void *context, int priority, const char *message)
callback to log SASL messages
Definition: sasl.c:210
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sasl_cb_authname()

static int mutt_sasl_cb_authname ( void *  context,
int  id,
const char **  result,
unsigned int *  len 
)
static

callback to retrieve authname or user from ConnAccount

Parameters
[in]contextConnAccount
[in]idField to get. SASL_CB_USER or SASL_CB_AUTHNAME
[out]resultResulting string
[out]lenLength of result
Return values
numSASL error code, e.g. SASL_FAIL

Definition at line 287 of file sasl.c.

288 {
289  if (!result)
290  return SASL_FAIL;
291 
292  struct ConnAccount *cac = context;
293 
294  *result = NULL;
295  if (len)
296  *len = 0;
297 
298  if (!cac)
299  return SASL_BADPARAM;
300 
301  mutt_debug(LL_DEBUG2, "getting %s for %s:%u\n",
302  (id == SASL_CB_AUTHNAME) ? "authname" : "user", cac->host, cac->port);
303 
304  if (id == SASL_CB_AUTHNAME)
305  {
306  if (mutt_account_getlogin(cac) < 0)
307  return SASL_FAIL;
308  *result = cac->login;
309  }
310  else
311  {
312  if (mutt_account_getuser(cac) < 0)
313  return SASL_FAIL;
314  *result = cac->user;
315  }
316 
317  if (len)
318  *len = strlen(*result);
319 
320  return SASL_OK;
321 }
char login[128]
Login name.
Definition: connaccount.h:54
int mutt_account_getuser(struct ConnAccount *cac)
Retrieve username into ConnAccount, if necessary.
Definition: connaccount.c:48
char user[128]
Username.
Definition: connaccount.h:55
char host[128]
Server to login to.
Definition: connaccount.h:53
Log at debug level 2.
Definition: logging.h:41
unsigned short port
Port to connect to.
Definition: connaccount.h:57
int mutt_account_getlogin(struct ConnAccount *cac)
Retrieve login info into ConnAccount, if necessary.
Definition: connaccount.c:81
Login details for a remote server.
Definition: connaccount.h:51
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sasl_cb_pass()

static int mutt_sasl_cb_pass ( sasl_conn_t *  conn,
void *  context,
int  id,
sasl_secret_t **  psecret 
)
static

SASL callback function to get password.

Parameters
[in]connConnection to a server
[in]contextConnAccount
[in]idSASL_CB_PASS
[out]psecretSASL secret
Return values
numSASL error code, e.g SASL_FAIL

Definition at line 331 of file sasl.c.

332 {
333  struct ConnAccount *cac = context;
334  int len;
335 
336  if (!cac || !psecret)
337  return SASL_BADPARAM;
338 
339  mutt_debug(LL_DEBUG2, "getting password for %s@%s:%u\n", cac->login, cac->host, cac->port);
340 
341  if (mutt_account_getpass(cac) < 0)
342  return SASL_FAIL;
343 
344  len = strlen(cac->pass);
345 
346  mutt_mem_realloc(&secret_ptr, sizeof(sasl_secret_t) + len);
347  memcpy((char *) secret_ptr->data, cac->pass, (size_t) len);
348  secret_ptr->len = len;
349  *psecret = secret_ptr;
350 
351  return SASL_OK;
352 }
char login[128]
Login name.
Definition: connaccount.h:54
char host[128]
Server to login to.
Definition: connaccount.h:53
Log at debug level 2.
Definition: logging.h:41
char pass[256]
Password.
Definition: connaccount.h:56
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:114
unsigned short port
Port to connect to.
Definition: connaccount.h:57
static sasl_secret_t * secret_ptr
Definition: sasl.c:108
Login details for a remote server.
Definition: connaccount.h:51
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int mutt_account_getpass(struct ConnAccount *cac)
Fetch password into ConnAccount, if necessary.
Definition: connaccount.c:111
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sasl_get_callbacks()

static sasl_callback_t* mutt_sasl_get_callbacks ( struct ConnAccount cac)
static

Get the SASL callback functions.

Parameters
cacConnAccount to associate with callbacks
Return values
ptrArray of callback functions

Definition at line 359 of file sasl.c.

360 {
361  sasl_callback_t *callback = MuttSaslCallbacks;
362 
363  callback->id = SASL_CB_USER;
364  callback->proc = (int (*)(void)) mutt_sasl_cb_authname;
365  callback->context = cac;
366  callback++;
367 
368  callback->id = SASL_CB_AUTHNAME;
369  callback->proc = (int (*)(void)) mutt_sasl_cb_authname;
370  callback->context = cac;
371  callback++;
372 
373  callback->id = SASL_CB_PASS;
374  callback->proc = (int (*)(void)) mutt_sasl_cb_pass;
375  callback->context = cac;
376  callback++;
377 
378  callback->id = SASL_CB_GETREALM;
379  callback->proc = NULL;
380  callback->context = NULL;
381  callback++;
382 
383  callback->id = SASL_CB_LIST_END;
384  callback->proc = NULL;
385  callback->context = NULL;
386 
387  return MuttSaslCallbacks;
388 }
static int mutt_sasl_cb_pass(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret)
SASL callback function to get password.
Definition: sasl.c:331
static int mutt_sasl_cb_authname(void *context, int id, const char **result, unsigned int *len)
callback to retrieve authname or user from ConnAccount
Definition: sasl.c:287
static sasl_callback_t MuttSaslCallbacks[5]
Definition: sasl.c:106
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sasl_conn_open()

static int mutt_sasl_conn_open ( struct Connection conn)
static

empty wrapper for underlying open function - Implements Connection::open()

We don't know in advance that a connection will use SASL, so we replace conn's methods with sasl methods when authentication is successful, using mutt_sasl_setup_conn

Definition at line 397 of file sasl.c.

398 {
399  struct SaslSockData *sasldata = conn->sockdata;
400  conn->sockdata = sasldata->sockdata;
401  int rc = sasldata->open(conn);
402  conn->sockdata = sasldata;
403 
404  return rc;
405 }
int(* open)(struct Connection *conn)
Open a socket Connection - Implements Connection::open()
Definition: sasl.c:76
SASL authentication API.
Definition: sasl.c:60
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
void * sockdata
Underlying socket data.
Definition: sasl.c:71
+ Here is the caller graph for this function:

◆ mutt_sasl_conn_close()

static int mutt_sasl_conn_close ( struct Connection conn)
static

close SASL connection - Implements Connection::close()

Calls underlying close function and disposes of the sasl_conn_t object, then restores connection to pre-sasl state

Definition at line 413 of file sasl.c.

414 {
415  struct SaslSockData *sasldata = conn->sockdata;
416 
417  /* restore connection's underlying methods */
418  conn->sockdata = sasldata->sockdata;
419  conn->open = sasldata->open;
420  conn->read = sasldata->read;
421  conn->write = sasldata->write;
422  conn->poll = sasldata->poll;
423  conn->close = sasldata->close;
424 
425  /* release sasl resources */
426  sasl_dispose(&sasldata->saslconn);
427  FREE(&sasldata);
428 
429  /* call underlying close */
430  int rc = conn->close(conn);
431 
432  return rc;
433 }
int(* open)(struct Connection *conn)
Open a socket Connection - Implements Connection::open()
Definition: sasl.c:76
int(* read)(struct Connection *conn, char *buf, size_t count)
Read from a socket Connection.
Definition: connection.h:72
SASL authentication API.
Definition: sasl.c:60
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
sasl_conn_t * saslconn
Definition: sasl.c:62
void * sockdata
Underlying socket data.
Definition: sasl.c:71
int(* open)(struct Connection *conn)
Note about ssf: in actuality, NeoMutt uses this as a boolean to determine if the connection is "secur...
Definition: connection.h:62
int(* close)(struct Connection *conn)
Close a socket Connection.
Definition: connection.h:100
int(* close)(struct Connection *conn)
Close a socket Connection - Implements Connection::close()
Definition: sasl.c:96
int(* poll)(struct Connection *conn, time_t wait_secs)
Check whether a socket read would block.
Definition: connection.h:92
int(* write)(struct Connection *conn, const char *buf, size_t count)
Write to a socket Connection.
Definition: connection.h:82
int(* poll)(struct Connection *conn, time_t wait_secs)
Check whether a socket read would block - Implements Connection::poll()
Definition: sasl.c:91
#define FREE(x)
Definition: memory.h:40
int(* read)(struct Connection *conn, char *buf, size_t count)
Read from a socket Connection - Implements Connection::read()
Definition: sasl.c:81
int(* write)(struct Connection *conn, const char *buf, size_t count)
Write to a socket Connection - Implements Connection::write()
Definition: sasl.c:86
+ Here is the caller graph for this function:

◆ mutt_sasl_conn_read()

static int mutt_sasl_conn_read ( struct Connection conn,
char *  buf,
size_t  count 
)
static

Read data from an SASL connection - Implements Connection::read()

Definition at line 438 of file sasl.c.

439 {
440  int rc;
441  unsigned int olen;
442 
443  struct SaslSockData *sasldata = conn->sockdata;
444 
445  /* if we still have data in our read buffer, copy it into buf */
446  if (sasldata->blen > sasldata->bpos)
447  {
448  olen = ((sasldata->blen - sasldata->bpos) > count) ?
449  count :
450  sasldata->blen - sasldata->bpos;
451 
452  memcpy(buf, sasldata->buf + sasldata->bpos, olen);
453  sasldata->bpos += olen;
454 
455  return olen;
456  }
457 
458  conn->sockdata = sasldata->sockdata;
459 
460  sasldata->bpos = 0;
461  sasldata->blen = 0;
462 
463  /* and decode the result, if necessary */
464  if (*sasldata->ssf != 0)
465  {
466  do
467  {
468  /* call the underlying read function to fill the buffer */
469  rc = sasldata->read(conn, buf, count);
470  if (rc <= 0)
471  goto out;
472 
473  rc = sasl_decode(sasldata->saslconn, buf, rc, &sasldata->buf, &sasldata->blen);
474  if (rc != SASL_OK)
475  {
476  mutt_debug(LL_DEBUG1, "SASL decode failed: %s\n", sasl_errstring(rc, NULL, NULL));
477  goto out;
478  }
479  } while (sasldata->blen == 0);
480 
481  olen = ((sasldata->blen - sasldata->bpos) > count) ?
482  count :
483  sasldata->blen - sasldata->bpos;
484 
485  memcpy(buf, sasldata->buf, olen);
486  sasldata->bpos += olen;
487 
488  rc = olen;
489  }
490  else
491  rc = sasldata->read(conn, buf, count);
492 
493 out:
494  conn->sockdata = sasldata;
495 
496  return rc;
497 }
SASL authentication API.
Definition: sasl.c:60
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
sasl_conn_t * saslconn
Definition: sasl.c:62
unsigned int bpos
Definition: sasl.c:69
void * sockdata
Underlying socket data.
Definition: sasl.c:71
unsigned int blen
Definition: sasl.c:68
const sasl_ssf_t * ssf
Definition: sasl.c:63
Log at debug level 1.
Definition: logging.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int(* read)(struct Connection *conn, char *buf, size_t count)
Read from a socket Connection - Implements Connection::read()
Definition: sasl.c:81
const char * buf
Definition: sasl.c:67
+ Here is the caller graph for this function:

◆ mutt_sasl_conn_write()

static int mutt_sasl_conn_write ( struct Connection conn,
const char *  buf,
size_t  count 
)
static

Write to an SASL connection - Implements Connection::write()

Definition at line 502 of file sasl.c.

503 {
504  int rc;
505  const char *pbuf = NULL;
506  unsigned int olen, plen;
507 
508  struct SaslSockData *sasldata = conn->sockdata;
509  conn->sockdata = sasldata->sockdata;
510 
511  /* encode data, if necessary */
512  if (*sasldata->ssf != 0)
513  {
514  /* handle data larger than MAXOUTBUF */
515  do
516  {
517  olen = (count > *sasldata->pbufsize) ? *sasldata->pbufsize : count;
518 
519  rc = sasl_encode(sasldata->saslconn, buf, olen, &pbuf, &plen);
520  if (rc != SASL_OK)
521  {
522  mutt_debug(LL_DEBUG1, "SASL encoding failed: %s\n", sasl_errstring(rc, NULL, NULL));
523  goto fail;
524  }
525 
526  rc = sasldata->write(conn, pbuf, plen);
527  if (rc != plen)
528  goto fail;
529 
530  count -= olen;
531  buf += olen;
532  } while (count > *sasldata->pbufsize);
533  }
534  else
535  {
536  /* just write using the underlying socket function */
537  rc = sasldata->write(conn, buf, count);
538  }
539 
540  conn->sockdata = sasldata;
541 
542  return rc;
543 
544 fail:
545  conn->sockdata = sasldata;
546  return -1;
547 }
static size_t plen
Length of cached packet.
Definition: pgppacket.c:39
SASL authentication API.
Definition: sasl.c:60
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
sasl_conn_t * saslconn
Definition: sasl.c:62
void * sockdata
Underlying socket data.
Definition: sasl.c:71
const sasl_ssf_t * ssf
Definition: sasl.c:63
Log at debug level 1.
Definition: logging.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
const char * buf
Definition: sasl.c:67
const unsigned int * pbufsize
Definition: sasl.c:64
int(* write)(struct Connection *conn, const char *buf, size_t count)
Write to a socket Connection - Implements Connection::write()
Definition: sasl.c:86
static unsigned char * pbuf
Cache PGP data packet.
Definition: pgppacket.c:38
+ Here is the caller graph for this function:

◆ mutt_sasl_conn_poll()

static int mutt_sasl_conn_poll ( struct Connection conn,
time_t  wait_secs 
)
static

Check an SASL connection for data - Implements Connection::poll()

Definition at line 552 of file sasl.c.

553 {
554  struct SaslSockData *sasldata = conn->sockdata;
555  int rc;
556 
557  conn->sockdata = sasldata->sockdata;
558  rc = sasldata->poll(conn, wait_secs);
559  conn->sockdata = sasldata;
560 
561  return rc;
562 }
SASL authentication API.
Definition: sasl.c:60
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
void * sockdata
Underlying socket data.
Definition: sasl.c:71
int(* poll)(struct Connection *conn, time_t wait_secs)
Check whether a socket read would block - Implements Connection::poll()
Definition: sasl.c:91
+ Here is the caller graph for this function:

◆ mutt_sasl_client_new()

int mutt_sasl_client_new ( struct Connection conn,
sasl_conn_t **  saslconn 
)

Wrapper for sasl_client_new()

Parameters
[in]connConnection to a server
[out]saslconnSASL connection
Return values
0Success
-1Error

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().

Definition at line 574 of file sasl.c.

575 {
576  sasl_security_properties_t secprops;
577  struct sockaddr_storage local, remote;
578  socklen_t size;
579  char iplocalport[IP_PORT_BUFLEN], ipremoteport[IP_PORT_BUFLEN];
580  char *plp = NULL;
581  char *prp = NULL;
582  int rc;
583 
584  if (mutt_sasl_start() != SASL_OK)
585  return -1;
586 
587  if (!conn->account.service)
588  {
589  mutt_error(_("Unknown SASL profile"));
590  return -1;
591  }
592 
593  size = sizeof(local);
594  if (getsockname(conn->fd, (struct sockaddr *) &local, &size) == 0)
595  {
596  if (iptostring((struct sockaddr *) &local, size, iplocalport, IP_PORT_BUFLEN) == SASL_OK)
597  plp = iplocalport;
598  else
599  mutt_debug(LL_DEBUG2, "SASL failed to parse local IP address\n");
600  }
601  else
602  mutt_debug(LL_DEBUG2, "SASL failed to get local IP address\n");
603 
604  size = sizeof(remote);
605  if (getpeername(conn->fd, (struct sockaddr *) &remote, &size) == 0)
606  {
607  if (iptostring((struct sockaddr *) &remote, size, ipremoteport, IP_PORT_BUFLEN) == SASL_OK)
608  prp = ipremoteport;
609  else
610  mutt_debug(LL_DEBUG2, "SASL failed to parse remote IP address\n");
611  }
612  else
613  mutt_debug(LL_DEBUG2, "SASL failed to get remote IP address\n");
614 
615  mutt_debug(LL_DEBUG2, "SASL local ip: %s, remote ip:%s\n", NONULL(plp), NONULL(prp));
616 
617  rc = sasl_client_new(conn->account.service, conn->account.host, plp, prp,
618  mutt_sasl_get_callbacks(&conn->account), 0, saslconn);
619 
620  if (rc != SASL_OK)
621  {
622  mutt_error(_("Error allocating SASL connection"));
623  return -1;
624  }
625 
626  memset(&secprops, 0, sizeof(secprops));
627  /* Work around a casting bug in the SASL krb4 module */
628  secprops.max_ssf = 0x7fff;
629  secprops.maxbufsize = MUTT_SASL_MAXBUF;
630  if (sasl_setprop(*saslconn, SASL_SEC_PROPS, &secprops) != SASL_OK)
631  {
632  mutt_error(_("Error setting SASL security properties"));
633  sasl_dispose(saslconn);
634  return -1;
635  }
636 
637  if (conn->ssf != 0)
638  {
639  /* I'm not sure this actually has an effect, at least with SASLv2 */
640  mutt_debug(LL_DEBUG2, "External SSF: %d\n", conn->ssf);
641  if (sasl_setprop(*saslconn, SASL_SSF_EXTERNAL, &conn->ssf) != SASL_OK)
642  {
643  mutt_error(_("Error setting SASL external security strength"));
644  sasl_dispose(saslconn);
645  return -1;
646  }
647  }
648  if (conn->account.user[0])
649  {
650  mutt_debug(LL_DEBUG2, "External authentication name: %s\n", conn->account.user);
651  if (sasl_setprop(*saslconn, SASL_AUTH_EXTERNAL, conn->account.user) != SASL_OK)
652  {
653  mutt_error(_("Error setting SASL external user name"));
654  sasl_dispose(saslconn);
655  return -1;
656  }
657  }
658 
659  return 0;
660 }
#define MUTT_SASL_MAXBUF
Definition: sasl.c:102
#define NONULL(x)
Definition: string2.h:37
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:36
unsigned int ssf
Security strength factor, in bits (see below)
Definition: connection.h:37
char user[128]
Username.
Definition: connaccount.h:55
static int mutt_sasl_start(void)
Initialise SASL library.
Definition: sasl.c:247
#define _(a)
Definition: message.h:28
char host[128]
Server to login to.
Definition: connaccount.h:53
Log at debug level 2.
Definition: logging.h:41
#define IP_PORT_BUFLEN
Definition: sasl.c:104
int fd
Socket file descriptor.
Definition: connection.h:40
static int iptostring(const struct sockaddr *addr, socklen_t addrlen, char *out, unsigned int outlen)
Convert IP Address to string.
Definition: sasl.c:177
const char * service
Name of the service, e.g. "imap".
Definition: connaccount.h:60
#define mutt_error(...)
Definition: logging.h:84
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
static sasl_callback_t * mutt_sasl_get_callbacks(struct ConnAccount *cac)
Get the SASL callback functions.
Definition: sasl.c:359
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sasl_interact()

int mutt_sasl_interact ( sasl_interact_t *  interaction)

Perform an SASL interaction with the user.

Parameters
interactionDetails of interaction
Return values
numSASL error code: SASL_OK or SASL_FAIL

An example interaction might be asking the user for a password.

Definition at line 669 of file sasl.c.

670 {
671  char prompt[128];
672  char resp[128];
673 
674  while (interaction->id != SASL_CB_LIST_END)
675  {
676  mutt_debug(LL_DEBUG2, "filling in SASL interaction %ld\n", interaction->id);
677 
678  snprintf(prompt, sizeof(prompt), "%s: ", interaction->prompt);
679  resp[0] = '\0';
680  if (OptNoCurses || mutt_get_field(prompt, resp, sizeof(resp), MUTT_COMP_NO_FLAGS))
681  return SASL_FAIL;
682 
683  interaction->len = mutt_str_len(resp) + 1;
684  char *result = mutt_mem_malloc(interaction->len);
685  memcpy(result, resp, interaction->len);
686  interaction->result = result;
687 
688  interaction++;
689  }
690 
691  return SASL_OK;
692 }
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:48
#define mutt_get_field(field, buf, buflen, complete)
Definition: curs_lib.h:91
Log at debug level 2.
Definition: logging.h:41
#define MUTT_COMP_NO_FLAGS
No flags are set.
Definition: mutt.h:56
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:636
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sasl_setup_conn()

void mutt_sasl_setup_conn ( struct Connection conn,
sasl_conn_t *  saslconn 
)

Set up an SASL connection.

Parameters
connConnection to a server
saslconnSASL connection

Replace connection methods, sockdata with SASL wrappers, for protection layers. Also get ssf, as a fastpath for the read/write methods.

Definition at line 702 of file sasl.c.

703 {
704  struct SaslSockData *sasldata = mutt_mem_malloc(sizeof(struct SaslSockData));
705  /* work around sasl_getprop aliasing issues */
706  const void *tmp = NULL;
707 
708  sasldata->saslconn = saslconn;
709  /* get ssf so we know whether we have to (en|de)code read/write */
710  sasl_getprop(saslconn, SASL_SSF, &tmp);
711  sasldata->ssf = tmp;
712  mutt_debug(LL_DEBUG3, "SASL protection strength: %u\n", *sasldata->ssf);
713  /* Add SASL SSF to transport SSF */
714  conn->ssf += *sasldata->ssf;
715  sasl_getprop(saslconn, SASL_MAXOUTBUF, &tmp);
716  sasldata->pbufsize = tmp;
717  mutt_debug(LL_DEBUG3, "SASL protection buffer size: %u\n", *sasldata->pbufsize);
718 
719  /* clear input buffer */
720  sasldata->buf = NULL;
721  sasldata->bpos = 0;
722  sasldata->blen = 0;
723 
724  /* preserve old functions */
725  sasldata->sockdata = conn->sockdata;
726  sasldata->open = conn->open;
727  sasldata->read = conn->read;
728  sasldata->write = conn->write;
729  sasldata->poll = conn->poll;
730  sasldata->close = conn->close;
731 
732  /* and set up new functions */
733  conn->sockdata = sasldata;
734  conn->open = mutt_sasl_conn_open;
735  conn->read = mutt_sasl_conn_read;
736  conn->write = mutt_sasl_conn_write;
737  conn->poll = mutt_sasl_conn_poll;
738  conn->close = mutt_sasl_conn_close;
739 }
int(* open)(struct Connection *conn)
Open a socket Connection - Implements Connection::open()
Definition: sasl.c:76
unsigned int ssf
Security strength factor, in bits (see below)
Definition: connection.h:37
int(* read)(struct Connection *conn, char *buf, size_t count)
Read from a socket Connection.
Definition: connection.h:72
SASL authentication API.
Definition: sasl.c:60
void * sockdata
Backend-specific socket data.
Definition: connection.h:42
sasl_conn_t * saslconn
Definition: sasl.c:62
unsigned int bpos
Definition: sasl.c:69
void * sockdata
Underlying socket data.
Definition: sasl.c:71
int(* open)(struct Connection *conn)
Note about ssf: in actuality, NeoMutt uses this as a boolean to determine if the connection is "secur...
Definition: connection.h:62
static int mutt_sasl_conn_poll(struct Connection *conn, time_t wait_secs)
Check an SASL connection for data - Implements Connection::poll()
Definition: sasl.c:552
unsigned int blen
Definition: sasl.c:68
int(* close)(struct Connection *conn)
Close a socket Connection.
Definition: connection.h:100
const sasl_ssf_t * ssf
Definition: sasl.c:63
static int mutt_sasl_conn_close(struct Connection *conn)
close SASL connection - Implements Connection::close()
Definition: sasl.c:413
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:90
static int mutt_sasl_conn_write(struct Connection *conn, const char *buf, size_t count)
Write to an SASL connection - Implements Connection::write()
Definition: sasl.c:502
static int mutt_sasl_conn_open(struct Connection *conn)
empty wrapper for underlying open function - Implements Connection::open()
Definition: sasl.c:397
int(* close)(struct Connection *conn)
Close a socket Connection - Implements Connection::close()
Definition: sasl.c:96
int(* poll)(struct Connection *conn, time_t wait_secs)
Check whether a socket read would block.
Definition: connection.h:92
int(* write)(struct Connection *conn, const char *buf, size_t count)
Write to a socket Connection.
Definition: connection.h:82
int(* poll)(struct Connection *conn, time_t wait_secs)
Check whether a socket read would block - Implements Connection::poll()
Definition: sasl.c:91
static int mutt_sasl_conn_read(struct Connection *conn, char *buf, size_t count)
Read data from an SASL connection - Implements Connection::read()
Definition: sasl.c:438
#define mutt_debug(LEVEL,...)
Definition: logging.h:81
int(* read)(struct Connection *conn, char *buf, size_t count)
Read from a socket Connection - Implements Connection::read()
Definition: sasl.c:81
const char * buf
Definition: sasl.c:67
const unsigned int * pbufsize
Definition: sasl.c:64
int(* write)(struct Connection *conn, const char *buf, size_t count)
Write to a socket Connection - Implements Connection::write()
Definition: sasl.c:86
Log at debug level 3.
Definition: logging.h:42
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sasl_done()

void mutt_sasl_done ( void  )

Invoke when processing is complete.

This is a cleanup function, used to free all memory used by the library. Invoke when processing is complete.

Definition at line 747 of file sasl.c.

748 {
749 #ifdef HAVE_SASL_CLIENT_DONE
750  /* As we never use the server-side, the silently ignore the return value */
751  sasl_client_done();
752 #else
753  sasl_done();
754 #endif
755 }
+ Here is the caller graph for this function:

Variable Documentation

◆ MuttSaslCallbacks

sasl_callback_t MuttSaslCallbacks[5]
static

Definition at line 106 of file sasl.c.

◆ secret_ptr

sasl_secret_t* secret_ptr = NULL
static

Definition at line 108 of file sasl.c.