NeoMutt  2020-11-20
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

bool sasl_auth_validator (const char *authenticator)
 Validate an auth method against Cyrus SASL methods. More...
 
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 const char *const sasl_authenticators []
 Authenticaion methods supported by Cyrus SASL. More...
 
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 114 of file sasl.c.

◆ IP_PORT_BUFLEN

#define IP_PORT_BUFLEN   1024

Definition at line 116 of file sasl.c.

Function Documentation

◆ sasl_auth_validator()

bool sasl_auth_validator ( const char *  authenticator)

Validate an auth method against Cyrus SASL methods.

Parameters
authenticatorName of the authenticator to validate
Return values
boolTrue if argument matches an accepted auth method

Definition at line 127 of file sasl.c.

128 {
129  for (size_t i = 0; i < mutt_array_size(sasl_authenticators); i++)
130  {
131  const char *auth = sasl_authenticators[i];
132  if (mutt_istr_equal(auth, authenticator))
133  return true;
134  }
135 
136  return false;
137 }
#define mutt_array_size(x)
Definition: memory.h:33
bool mutt_istr_equal(const char *a, const char *b)
Compare two strings, ignoring case.
Definition: string.c:883
static const char *const sasl_authenticators[]
Authenticaion methods supported by Cyrus SASL.
Definition: sasl.c:102
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ 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 144 of file sasl.c.

145 {
146  int err;
147  mutt_debug(LL_DEBUG1, "getnameinfo: ");
148  switch (ret)
149  {
150  case EAI_AGAIN:
152  "The name could not be resolved at this time. Future "
153  "attempts may succeed\n");
154  err = SASL_TRYAGAIN;
155  break;
156  case EAI_BADFLAGS:
157  mutt_debug(LL_DEBUG1, "The flags had an invalid value\n");
158  err = SASL_BADPARAM;
159  break;
160  case EAI_FAIL:
161  mutt_debug(LL_DEBUG1, "A non-recoverable error occurred\n");
162  err = SASL_FAIL;
163  break;
164  case EAI_FAMILY:
166  "The address family was not recognized or the address "
167  "length was invalid for the specified family\n");
168  err = SASL_BADPROT;
169  break;
170  case EAI_MEMORY:
171  mutt_debug(LL_DEBUG1, "There was a memory allocation failure\n");
172  err = SASL_NOMEM;
173  break;
174  case EAI_NONAME:
176  "The name does not resolve for the supplied parameters. "
177  "NI_NAMEREQD is set and the host's name can't be located, "
178  "or both nodename and servname were null.\n");
179  err = SASL_FAIL; /* no real equivalent */
180  break;
181  case EAI_SYSTEM:
183  "A system error occurred. The error code can be found in "
184  "errno(%d,%s))\n",
185  errno, strerror(errno));
186  err = SASL_FAIL; /* no real equivalent */
187  break;
188  default:
189  mutt_debug(LL_DEBUG1, "Unknown error %d\n", ret);
190  err = SASL_FAIL; /* no real equivalent */
191  break;
192  }
193  return err;
194 }
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 206 of file sasl.c.

208 {
209  char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
210  int ret;
211 
212  if (!addr || !out)
213  return SASL_BADPARAM;
214 
215  ret = getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
216  NI_NUMERICHOST |
217 #ifdef NI_WITHSCOPEID
218  NI_WITHSCOPEID |
219 #endif
220  NI_NUMERICSERV);
221  if (ret != 0)
222  return getnameinfo_err(ret);
223 
224  if (outlen < strlen(hbuf) + strlen(pbuf) + 2)
225  return SASL_BUFOVER;
226 
227  snprintf(out, outlen, "%s;%s", hbuf, pbuf);
228 
229  return SASL_OK;
230 }
static int getnameinfo_err(int ret)
Convert a getaddrinfo() error code into an SASL error code.
Definition: sasl.c:144
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 239 of file sasl.c.

240 {
241  if (priority == SASL_LOG_NONE)
242  return SASL_OK;
243 
244  int mutt_priority = 0;
245  switch (priority)
246  {
247  case SASL_LOG_TRACE:
248  case SASL_LOG_PASS:
249  mutt_priority = 5;
250  break;
251  case SASL_LOG_DEBUG:
252  case SASL_LOG_NOTE:
253  mutt_priority = 3;
254  break;
255  case SASL_LOG_FAIL:
256  case SASL_LOG_WARN:
257  mutt_priority = 2;
258  break;
259  case SASL_LOG_ERR:
260  mutt_priority = 1;
261  break;
262  default:
263  mutt_debug(LL_DEBUG1, "SASL unknown log priority: %s\n", message);
264  return SASL_OK;
265  }
266  mutt_debug(mutt_priority, "SASL: %s\n", message);
267  return SASL_OK;
268 }
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 276 of file sasl.c.

277 {
278  static bool sasl_init = false;
279 
280  static sasl_callback_t callbacks[2];
281  int rc;
282 
283  if (sasl_init)
284  return SASL_OK;
285 
286  /* set up default logging callback */
287  callbacks[0].id = SASL_CB_LOG;
288  callbacks[0].proc = (int (*)(void)) mutt_sasl_cb_log;
289  callbacks[0].context = NULL;
290 
291  callbacks[1].id = SASL_CB_LIST_END;
292  callbacks[1].proc = NULL;
293  callbacks[1].context = NULL;
294 
295  rc = sasl_client_init(callbacks);
296 
297  if (rc != SASL_OK)
298  {
299  mutt_debug(LL_DEBUG1, "libsasl initialisation failed\n");
300  return SASL_FAIL;
301  }
302 
303  sasl_init = true;
304 
305  return SASL_OK;
306 }
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:239
+ 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 316 of file sasl.c.

317 {
318  if (!result)
319  return SASL_FAIL;
320 
321  struct ConnAccount *cac = context;
322 
323  *result = NULL;
324  if (len)
325  *len = 0;
326 
327  if (!cac)
328  return SASL_BADPARAM;
329 
330  mutt_debug(LL_DEBUG2, "getting %s for %s:%u\n",
331  (id == SASL_CB_AUTHNAME) ? "authname" : "user", cac->host, cac->port);
332 
333  if (id == SASL_CB_AUTHNAME)
334  {
335  if (mutt_account_getlogin(cac) < 0)
336  return SASL_FAIL;
337  *result = cac->login;
338  }
339  else
340  {
341  if (mutt_account_getuser(cac) < 0)
342  return SASL_FAIL;
343  *result = cac->user;
344  }
345 
346  if (len)
347  *len = strlen(*result);
348 
349  return SASL_OK;
350 }
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 360 of file sasl.c.

361 {
362  struct ConnAccount *cac = context;
363  int len;
364 
365  if (!cac || !psecret)
366  return SASL_BADPARAM;
367 
368  mutt_debug(LL_DEBUG2, "getting password for %s@%s:%u\n", cac->login, cac->host, cac->port);
369 
370  if (mutt_account_getpass(cac) < 0)
371  return SASL_FAIL;
372 
373  len = strlen(cac->pass);
374 
375  mutt_mem_realloc(&secret_ptr, sizeof(sasl_secret_t) + len);
376  memcpy((char *) secret_ptr->data, cac->pass, (size_t) len);
377  secret_ptr->len = len;
378  *psecret = secret_ptr;
379 
380  return SASL_OK;
381 }
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:120
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 388 of file sasl.c.

389 {
390  sasl_callback_t *callback = MuttSaslCallbacks;
391 
392  callback->id = SASL_CB_USER;
393  callback->proc = (int (*)(void)) mutt_sasl_cb_authname;
394  callback->context = cac;
395  callback++;
396 
397  callback->id = SASL_CB_AUTHNAME;
398  callback->proc = (int (*)(void)) mutt_sasl_cb_authname;
399  callback->context = cac;
400  callback++;
401 
402  callback->id = SASL_CB_PASS;
403  callback->proc = (int (*)(void)) mutt_sasl_cb_pass;
404  callback->context = cac;
405  callback++;
406 
407  callback->id = SASL_CB_GETREALM;
408  callback->proc = NULL;
409  callback->context = NULL;
410  callback++;
411 
412  callback->id = SASL_CB_LIST_END;
413  callback->proc = NULL;
414  callback->context = NULL;
415 
416  return MuttSaslCallbacks;
417 }
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:360
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:316
static sasl_callback_t MuttSaslCallbacks[5]
Definition: sasl.c:118
+ 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 426 of file sasl.c.

427 {
428  struct SaslSockData *sasldata = conn->sockdata;
429  conn->sockdata = sasldata->sockdata;
430  int rc = sasldata->open(conn);
431  conn->sockdata = sasldata;
432 
433  return rc;
434 }
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 442 of file sasl.c.

443 {
444  struct SaslSockData *sasldata = conn->sockdata;
445 
446  /* restore connection's underlying methods */
447  conn->sockdata = sasldata->sockdata;
448  conn->open = sasldata->open;
449  conn->read = sasldata->read;
450  conn->write = sasldata->write;
451  conn->poll = sasldata->poll;
452  conn->close = sasldata->close;
453 
454  /* release sasl resources */
455  sasl_dispose(&sasldata->saslconn);
456  FREE(&sasldata);
457 
458  /* call underlying close */
459  int rc = conn->close(conn);
460 
461  return rc;
462 }
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 467 of file sasl.c.

468 {
469  int rc;
470  unsigned int olen;
471 
472  struct SaslSockData *sasldata = conn->sockdata;
473 
474  /* if we still have data in our read buffer, copy it into buf */
475  if (sasldata->blen > sasldata->bpos)
476  {
477  olen = ((sasldata->blen - sasldata->bpos) > count) ?
478  count :
479  sasldata->blen - sasldata->bpos;
480 
481  memcpy(buf, sasldata->buf + sasldata->bpos, olen);
482  sasldata->bpos += olen;
483 
484  return olen;
485  }
486 
487  conn->sockdata = sasldata->sockdata;
488 
489  sasldata->bpos = 0;
490  sasldata->blen = 0;
491 
492  /* and decode the result, if necessary */
493  if (*sasldata->ssf != 0)
494  {
495  do
496  {
497  /* call the underlying read function to fill the buffer */
498  rc = sasldata->read(conn, buf, count);
499  if (rc <= 0)
500  goto out;
501 
502  rc = sasl_decode(sasldata->saslconn, buf, rc, &sasldata->buf, &sasldata->blen);
503  if (rc != SASL_OK)
504  {
505  mutt_debug(LL_DEBUG1, "SASL decode failed: %s\n", sasl_errstring(rc, NULL, NULL));
506  goto out;
507  }
508  } while (sasldata->blen == 0);
509 
510  olen = ((sasldata->blen - sasldata->bpos) > count) ?
511  count :
512  sasldata->blen - sasldata->bpos;
513 
514  memcpy(buf, sasldata->buf, olen);
515  sasldata->bpos += olen;
516 
517  rc = olen;
518  }
519  else
520  rc = sasldata->read(conn, buf, count);
521 
522 out:
523  conn->sockdata = sasldata;
524 
525  return rc;
526 }
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 531 of file sasl.c.

532 {
533  int rc;
534  const char *pbuf = NULL;
535  unsigned int olen, plen;
536 
537  struct SaslSockData *sasldata = conn->sockdata;
538  conn->sockdata = sasldata->sockdata;
539 
540  /* encode data, if necessary */
541  if (*sasldata->ssf != 0)
542  {
543  /* handle data larger than MAXOUTBUF */
544  do
545  {
546  olen = (count > *sasldata->pbufsize) ? *sasldata->pbufsize : count;
547 
548  rc = sasl_encode(sasldata->saslconn, buf, olen, &pbuf, &plen);
549  if (rc != SASL_OK)
550  {
551  mutt_debug(LL_DEBUG1, "SASL encoding failed: %s\n", sasl_errstring(rc, NULL, NULL));
552  goto fail;
553  }
554 
555  rc = sasldata->write(conn, pbuf, plen);
556  if (rc != plen)
557  goto fail;
558 
559  count -= olen;
560  buf += olen;
561  } while (count > *sasldata->pbufsize);
562  }
563  else
564  {
565  /* just write using the underlying socket function */
566  rc = sasldata->write(conn, buf, count);
567  }
568 
569  conn->sockdata = sasldata;
570 
571  return rc;
572 
573 fail:
574  conn->sockdata = sasldata;
575  return -1;
576 }
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 581 of file sasl.c.

582 {
583  struct SaslSockData *sasldata = conn->sockdata;
584  int rc;
585 
586  conn->sockdata = sasldata->sockdata;
587  rc = sasldata->poll(conn, wait_secs);
588  conn->sockdata = sasldata;
589 
590  return rc;
591 }
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 603 of file sasl.c.

604 {
605  sasl_security_properties_t secprops;
606  struct sockaddr_storage local, remote;
607  socklen_t size;
608  char iplocalport[IP_PORT_BUFLEN], ipremoteport[IP_PORT_BUFLEN];
609  char *plp = NULL;
610  char *prp = NULL;
611  int rc;
612 
613  if (mutt_sasl_start() != SASL_OK)
614  return -1;
615 
616  if (!conn->account.service)
617  {
618  mutt_error(_("Unknown SASL profile"));
619  return -1;
620  }
621 
622  size = sizeof(local);
623  if (getsockname(conn->fd, (struct sockaddr *) &local, &size) == 0)
624  {
625  if (iptostring((struct sockaddr *) &local, size, iplocalport, IP_PORT_BUFLEN) == SASL_OK)
626  plp = iplocalport;
627  else
628  mutt_debug(LL_DEBUG2, "SASL failed to parse local IP address\n");
629  }
630  else
631  mutt_debug(LL_DEBUG2, "SASL failed to get local IP address\n");
632 
633  size = sizeof(remote);
634  if (getpeername(conn->fd, (struct sockaddr *) &remote, &size) == 0)
635  {
636  if (iptostring((struct sockaddr *) &remote, size, ipremoteport, IP_PORT_BUFLEN) == SASL_OK)
637  prp = ipremoteport;
638  else
639  mutt_debug(LL_DEBUG2, "SASL failed to parse remote IP address\n");
640  }
641  else
642  mutt_debug(LL_DEBUG2, "SASL failed to get remote IP address\n");
643 
644  mutt_debug(LL_DEBUG2, "SASL local ip: %s, remote ip:%s\n", NONULL(plp), NONULL(prp));
645 
646  rc = sasl_client_new(conn->account.service, conn->account.host, plp, prp,
647  mutt_sasl_get_callbacks(&conn->account), 0, saslconn);
648 
649  if (rc != SASL_OK)
650  {
651  mutt_error(_("Error allocating SASL connection"));
652  return -1;
653  }
654 
655  memset(&secprops, 0, sizeof(secprops));
656  /* Work around a casting bug in the SASL krb4 module */
657  secprops.max_ssf = 0x7fff;
658  secprops.maxbufsize = MUTT_SASL_MAXBUF;
659  if (sasl_setprop(*saslconn, SASL_SEC_PROPS, &secprops) != SASL_OK)
660  {
661  mutt_error(_("Error setting SASL security properties"));
662  sasl_dispose(saslconn);
663  return -1;
664  }
665 
666  if (conn->ssf != 0)
667  {
668  /* I'm not sure this actually has an effect, at least with SASLv2 */
669  mutt_debug(LL_DEBUG2, "External SSF: %d\n", conn->ssf);
670  if (sasl_setprop(*saslconn, SASL_SSF_EXTERNAL, &conn->ssf) != SASL_OK)
671  {
672  mutt_error(_("Error setting SASL external security strength"));
673  sasl_dispose(saslconn);
674  return -1;
675  }
676  }
677  if (conn->account.user[0])
678  {
679  mutt_debug(LL_DEBUG2, "External authentication name: %s\n", conn->account.user);
680  if (sasl_setprop(*saslconn, SASL_AUTH_EXTERNAL, conn->account.user) != SASL_OK)
681  {
682  mutt_error(_("Error setting SASL external user name"));
683  sasl_dispose(saslconn);
684  return -1;
685  }
686  }
687 
688  return 0;
689 }
#define MUTT_SASL_MAXBUF
Definition: sasl.c:114
#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:276
#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:116
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:206
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:388
+ 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 698 of file sasl.c.

699 {
700  char prompt[128];
701  char resp[128];
702 
703  while (interaction->id != SASL_CB_LIST_END)
704  {
705  mutt_debug(LL_DEBUG2, "filling in SASL interaction %ld\n", interaction->id);
706 
707  snprintf(prompt, sizeof(prompt), "%s: ", interaction->prompt);
708  resp[0] = '\0';
709  if (OptNoCurses || mutt_get_field(prompt, resp, sizeof(resp), MUTT_COMP_NO_FLAGS))
710  return SASL_FAIL;
711 
712  interaction->len = mutt_str_len(resp) + 1;
713  char *result = mutt_mem_malloc(interaction->len);
714  memcpy(result, resp, interaction->len);
715  interaction->result = result;
716 
717  interaction++;
718  }
719 
720  return SASL_OK;
721 }
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:631
#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 731 of file sasl.c.

732 {
733  struct SaslSockData *sasldata = mutt_mem_malloc(sizeof(struct SaslSockData));
734  /* work around sasl_getprop aliasing issues */
735  const void *tmp = NULL;
736 
737  sasldata->saslconn = saslconn;
738  /* get ssf so we know whether we have to (en|de)code read/write */
739  sasl_getprop(saslconn, SASL_SSF, &tmp);
740  sasldata->ssf = tmp;
741  mutt_debug(LL_DEBUG3, "SASL protection strength: %u\n", *sasldata->ssf);
742  /* Add SASL SSF to transport SSF */
743  conn->ssf += *sasldata->ssf;
744  sasl_getprop(saslconn, SASL_MAXOUTBUF, &tmp);
745  sasldata->pbufsize = tmp;
746  mutt_debug(LL_DEBUG3, "SASL protection buffer size: %u\n", *sasldata->pbufsize);
747 
748  /* clear input buffer */
749  sasldata->buf = NULL;
750  sasldata->bpos = 0;
751  sasldata->blen = 0;
752 
753  /* preserve old functions */
754  sasldata->sockdata = conn->sockdata;
755  sasldata->open = conn->open;
756  sasldata->read = conn->read;
757  sasldata->write = conn->write;
758  sasldata->poll = conn->poll;
759  sasldata->close = conn->close;
760 
761  /* and set up new functions */
762  conn->sockdata = sasldata;
763  conn->open = mutt_sasl_conn_open;
764  conn->read = mutt_sasl_conn_read;
765  conn->write = mutt_sasl_conn_write;
766  conn->poll = mutt_sasl_conn_poll;
767  conn->close = mutt_sasl_conn_close;
768 }
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:581
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:442
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:531
static int mutt_sasl_conn_open(struct Connection *conn)
empty wrapper for underlying open function - Implements Connection::open()
Definition: sasl.c:426
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:467
#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 776 of file sasl.c.

777 {
778 #ifdef HAVE_SASL_CLIENT_DONE
779  /* As we never use the server-side, the silently ignore the return value */
780  sasl_client_done();
781 #else
782  sasl_done();
783 #endif
784 }
+ Here is the caller graph for this function:

Variable Documentation

◆ sasl_authenticators

const char* const sasl_authenticators[]
static
Initial value:
= {
"ANONYMOUS", "CRAM-MD5", "DIGEST-MD5", "EXTERNAL",
"GS2-IAKERB", "GS2-KRB5", "GSS-SPNEGO", "GSSAPI",
"LOGIN", "NTLM", "OTP-MD4", "OTP-MD5",
"OTP-SHA1", "PASSDSS-3DES-1", "PLAIN", "SCRAM-SHA-1",
"SCRAM-SHA-224", "SCRAM-SHA-256", "SCRAM-SHA-384", "SCRAM-SHA-512",
"SRP",
}

Authenticaion methods supported by Cyrus SASL.

Definition at line 102 of file sasl.c.

◆ MuttSaslCallbacks

sasl_callback_t MuttSaslCallbacks[5]
static

Definition at line 118 of file sasl.c.

◆ secret_ptr

sasl_secret_t* secret_ptr = NULL
static

Definition at line 120 of file sasl.c.