NeoMutt  2018-07-16 +952-a2da0a
Teaching an old dog new tricks
DOXYGEN
smtp.c File Reference

Send email to an SMTP server. More...

#include "config.h"
#include <netdb.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mutt/mutt.h"
#include "config/lib.h"
#include "email/lib.h"
#include "conn/conn.h"
#include "mutt.h"
#include "globals.h"
#include "mutt_account.h"
#include "mutt_socket.h"
#include "options.h"
#include "progress.h"
#include "sendlib.h"
#include <sasl/sasl.h>
#include <sasl/saslutil.h>
+ Include dependency graph for smtp.c:

Go to the source code of this file.

Macros

#define smtp_success(x)   ((x) / 100 == 2)
 
#define SMTP_READY   334
 
#define SMTP_CONTINUE   354
 
#define SMTP_ERR_READ   -2
 
#define SMTP_ERR_WRITE   -3
 
#define SMTP_ERR_CODE   -4
 
#define SMTP_PORT   25
 
#define SMTPS_PORT   465
 
#define SMTP_AUTH_SUCCESS   0
 
#define SMTP_AUTH_UNAVAIL   1
 
#define SMTP_AUTH_FAIL   -1
 

Enumerations

enum  SmtpCapability {
  SMTP_CAP_STARTTLS, SMTP_CAP_AUTH, SMTP_CAP_DSN, SMTP_CAP_EIGHTBITMIME,
  SMTP_CAP_SMTPUTF8, SMTP_CAP_MAX
}
 SMTP server capabilities. More...
 

Functions

static bool valid_smtp_code (char *buf, size_t buflen, int *n)
 Is the is a valid SMTP return code? More...
 
static int smtp_get_resp (struct Connection *conn)
 Read a command response from the SMTP server. More...
 
static int smtp_rcpt_to (struct Connection *conn, const struct Address *a)
 Set the recipient to an Address. More...
 
static int smtp_data (struct Connection *conn, const char *msgfile)
 Send data to an SMTP server. More...
 
static bool address_uses_unicode (const char *a)
 Do any addresses use Unicode. More...
 
static bool addresses_use_unicode (const struct Address *a)
 Do any of a list of addresses use Unicode. More...
 
static int smtp_fill_account (struct ConnAccount *account)
 Create ConnAccount object from SMTP Url. More...
 
static int smtp_helo (struct Connection *conn, bool esmtp)
 Say hello to an SMTP Server. More...
 
static int smtp_auth_sasl (struct Connection *conn, const char *mechlist)
 Authenticate using SASL. More...
 
static int smtp_auth_oauth (struct Connection *conn)
 Authenticate an SMTP connection using OAUTHBEARER. More...
 
static int smtp_auth_plain (struct Connection *conn)
 Authenticate using plain text. More...
 
static int smtp_auth (struct Connection *conn)
 Authenticate to an SMTP server. More...
 
static int smtp_open (struct Connection *conn, bool esmtp)
 Open an SMTP Connection. More...
 
int mutt_smtp_send (const struct Address *from, const struct Address *to, const struct Address *cc, const struct Address *bcc, const char *msgfile, bool eightbit)
 Send a message using SMTP. More...
 

Variables

char * SmtpAuthenticators
 Config: (smtp) List of allowed authentication methods. More...
 
static char * AuthMechs = NULL
 
static unsigned char Capabilities [(SMTP_CAP_MAX+7)/8]
 

Detailed Description

Send email to an SMTP server.

Authors
  • Michael R. Elkins
  • 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 smtp.c.

Macro Definition Documentation

#define smtp_success (   x)    ((x) / 100 == 2)

Definition at line 59 of file smtp.c.

#define SMTP_READY   334

Definition at line 60 of file smtp.c.

#define SMTP_CONTINUE   354

Definition at line 61 of file smtp.c.

#define SMTP_ERR_READ   -2

Definition at line 63 of file smtp.c.

#define SMTP_ERR_WRITE   -3

Definition at line 64 of file smtp.c.

#define SMTP_ERR_CODE   -4

Definition at line 65 of file smtp.c.

#define SMTP_PORT   25

Definition at line 67 of file smtp.c.

#define SMTPS_PORT   465

Definition at line 68 of file smtp.c.

#define SMTP_AUTH_SUCCESS   0

Definition at line 70 of file smtp.c.

#define SMTP_AUTH_UNAVAIL   1

Definition at line 71 of file smtp.c.

#define SMTP_AUTH_FAIL   -1

Definition at line 72 of file smtp.c.

Enumeration Type Documentation

SMTP server capabilities.

Enumerator
SMTP_CAP_STARTTLS 

Server supports STARTTLS command.

SMTP_CAP_AUTH 

Server supports AUTH command.

SMTP_CAP_DSN 

Server supports Delivery Status Notification.

SMTP_CAP_EIGHTBITMIME 

Server supports 8-bit MIME content.

SMTP_CAP_SMTPUTF8 

Server accepts UTF-8 strings.

SMTP_CAP_MAX 

Definition at line 77 of file smtp.c.

78 {
81  SMTP_CAP_DSN,
85 };
Server supports STARTTLS command.
Definition: smtp.c:79
Server supports 8-bit MIME content.
Definition: smtp.c:82
Server accepts UTF-8 strings.
Definition: smtp.c:83
Server supports AUTH command.
Definition: smtp.c:80
Server supports Delivery Status Notification.
Definition: smtp.c:81

Function Documentation

static bool valid_smtp_code ( char *  buf,
size_t  buflen,
int *  n 
)
static

Is the is a valid SMTP return code?

Parameters
[in]bufString to check
[in]buflenLength of string
[out]nNumeric value of code
Return values
trueValid number

Definition at line 97 of file smtp.c.

98 {
99  char code[4];
100 
101  if (buflen < 4)
102  return false;
103  code[0] = buf[0];
104  code[1] = buf[1];
105  code[2] = buf[2];
106  code[3] = 0;
107  if (mutt_str_atoi(code, n) < 0)
108  return false;
109  return true;
110 }
int mutt_str_atoi(const char *str, int *dst)
Convert ASCII string to an integer.
Definition: string.c:262

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int smtp_get_resp ( struct Connection conn)
static

Read a command response from the SMTP server.

Parameters
connSMTP connection
Return values
0Success (2xx code) or continue (354 code)
-1Write error, or any other response code

Definition at line 118 of file smtp.c.

119 {
120  int n;
121  char buf[1024];
122 
123  do
124  {
125  n = mutt_socket_readln(buf, sizeof(buf), conn);
126  if (n < 4)
127  {
128  /* read error, or no response code */
129  return SMTP_ERR_READ;
130  }
131  const char *s = buf + 4; /* Skip the response code and the space/dash */
132  size_t plen;
133 
134  if (mutt_str_startswith(s, "8BITMIME", CASE_IGNORE))
136  else if ((plen = mutt_str_startswith(s, "AUTH ", CASE_IGNORE)))
137  {
139  FREE(&AuthMechs);
140  AuthMechs = mutt_str_strdup(s + plen);
141  }
142  else if (mutt_str_startswith(s, "DSN", CASE_IGNORE))
144  else if (mutt_str_startswith(s, "STARTTLS", CASE_IGNORE))
146  else if (mutt_str_startswith(s, "SMTPUTF8", CASE_IGNORE))
148 
149  if (!valid_smtp_code(buf, n, &n))
150  return SMTP_ERR_CODE;
151 
152  } while (buf[3] == '-');
153 
154  if (smtp_success(n) || n == SMTP_CONTINUE)
155  return 0;
156 
157  mutt_error(_("SMTP session failed: %s"), buf);
158  return -1;
159 }
Server supports STARTTLS command.
Definition: smtp.c:79
static size_t plen
Length of cached packet.
Definition: pgppacket.c:38
Server supports 8-bit MIME content.
Definition: smtp.c:82
#define _(a)
Definition: message.h:28
Server accepts UTF-8 strings.
Definition: smtp.c:83
static unsigned char Capabilities[(SMTP_CAP_MAX+7)/8]
Definition: smtp.c:88
#define mutt_socket_readln(A, B, C)
Definition: mutt_socket.h:37
Ignore case when comparing strings.
Definition: string2.h:70
#define SMTP_ERR_READ
Definition: smtp.c:63
#define smtp_success(x)
Definition: smtp.c:59
size_t mutt_str_startswith(const char *str, const char *prefix, enum CaseSensitivity cs)
Check whether a string starts with a prefix.
Definition: string.c:166
#define SMTP_ERR_CODE
Definition: smtp.c:65
static bool valid_smtp_code(char *buf, size_t buflen, int *n)
Is the is a valid SMTP return code?
Definition: smtp.c:97
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:384
#define mutt_error(...)
Definition: logging.h:88
#define SMTP_CONTINUE
Definition: smtp.c:61
#define FREE(x)
Definition: memory.h:46
static char * AuthMechs
Definition: smtp.c:87
Server supports AUTH command.
Definition: smtp.c:80
Server supports Delivery Status Notification.
Definition: smtp.c:81
#define mutt_bit_set(v, n)
Definition: memory.h:36

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int smtp_rcpt_to ( struct Connection conn,
const struct Address a 
)
static

Set the recipient to an Address.

Parameters
connServer Connection
aAddress to use
Return values
0Success
<0Error, e.g. SMTP_ERR_WRITE

Definition at line 168 of file smtp.c.

169 {
170  char buf[1024];
171  int r;
172 
173  while (a)
174  {
175  /* weed out group mailboxes, since those are for display only */
176  if (!a->mailbox || a->group)
177  {
178  a = a->next;
179  continue;
180  }
182  snprintf(buf, sizeof(buf), "RCPT TO:<%s> NOTIFY=%s\r\n", a->mailbox, DsnNotify);
183  else
184  snprintf(buf, sizeof(buf), "RCPT TO:<%s>\r\n", a->mailbox);
185  if (mutt_socket_send(conn, buf) == -1)
186  return SMTP_ERR_WRITE;
187  r = smtp_get_resp(conn);
188  if (r != 0)
189  return r;
190  a = a->next;
191  }
192 
193  return 0;
194 }
#define mutt_bit_isset(v, n)
Definition: memory.h:39
char * mailbox
mailbox and host address
Definition: address.h:35
#define mutt_socket_send(conn, buffer)
Definition: mutt_socket.h:38
WHERE char * DsnNotify
Config: Request notification for message delivery or delay.
Definition: globals.h:108
static unsigned char Capabilities[(SMTP_CAP_MAX+7)/8]
Definition: smtp.c:88
#define SMTP_ERR_WRITE
Definition: smtp.c:64
static int smtp_get_resp(struct Connection *conn)
Read a command response from the SMTP server.
Definition: smtp.c:118
bool group
group mailbox?
Definition: address.h:36
Server supports Delivery Status Notification.
Definition: smtp.c:81
struct Address * next
Definition: address.h:39

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int smtp_data ( struct Connection conn,
const char *  msgfile 
)
static

Send data to an SMTP server.

Parameters
connSMTP Connection
msgfileFilename containing data
Return values
0Success
<0Error, e.g. SMTP_ERR_WRITE

Definition at line 203 of file smtp.c.

204 {
205  char buf[1024];
206  struct Progress progress;
207  struct stat st;
208  int r, term = 0;
209  size_t buflen = 0;
210 
211  FILE *fp = fopen(msgfile, "r");
212  if (!fp)
213  {
214  mutt_error(_("SMTP session failed: unable to open %s"), msgfile);
215  return -1;
216  }
217  stat(msgfile, &st);
218  unlink(msgfile);
219  mutt_progress_init(&progress, _("Sending message..."), MUTT_PROGRESS_SIZE,
220  NetInc, st.st_size);
221 
222  snprintf(buf, sizeof(buf), "DATA\r\n");
223  if (mutt_socket_send(conn, buf) == -1)
224  {
225  mutt_file_fclose(&fp);
226  return SMTP_ERR_WRITE;
227  }
228  r = smtp_get_resp(conn);
229  if (r != 0)
230  {
231  mutt_file_fclose(&fp);
232  return r;
233  }
234 
235  while (fgets(buf, sizeof(buf) - 1, fp))
236  {
237  buflen = mutt_str_strlen(buf);
238  term = buflen && buf[buflen - 1] == '\n';
239  if (term && (buflen == 1 || buf[buflen - 2] != '\r'))
240  snprintf(buf + buflen - 1, sizeof(buf) - buflen + 1, "\r\n");
241  if (buf[0] == '.')
242  {
243  if (mutt_socket_send_d(conn, ".", MUTT_SOCK_LOG_FULL) == -1)
244  {
245  mutt_file_fclose(&fp);
246  return SMTP_ERR_WRITE;
247  }
248  }
249  if (mutt_socket_send_d(conn, buf, MUTT_SOCK_LOG_FULL) == -1)
250  {
251  mutt_file_fclose(&fp);
252  return SMTP_ERR_WRITE;
253  }
254  mutt_progress_update(&progress, ftell(fp), -1);
255  }
256  if (!term && buflen && mutt_socket_send_d(conn, "\r\n", MUTT_SOCK_LOG_FULL) == -1)
257  {
258  mutt_file_fclose(&fp);
259  return SMTP_ERR_WRITE;
260  }
261  mutt_file_fclose(&fp);
262 
263  /* terminate the message body */
264  if (mutt_socket_send(conn, ".\r\n") == -1)
265  return SMTP_ERR_WRITE;
266 
267  r = smtp_get_resp(conn);
268  if (r != 0)
269  return r;
270 
271  return 0;
272 }
#define MUTT_PROGRESS_SIZE
traffic-based progress
Definition: progress.h:32
#define mutt_socket_send_d(conn, buffer, level)
Definition: mutt_socket.h:39
void mutt_progress_update(struct Progress *progress, long pos, int percent)
Update the state of the progress bar.
Definition: progress.c:170
void mutt_progress_init(struct Progress *progress, const char *msg, unsigned short flags, unsigned short inc, size_t size)
Set up a progress bar.
Definition: progress.c:113
#define _(a)
Definition: message.h:28
WHERE short NetInc
Config: (socket) Update the progress bar after this many KB sent/received (0 to disable) ...
Definition: globals.h:128
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:663
#define mutt_socket_send(conn, buffer)
Definition: mutt_socket.h:38
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:32
A progress bar.
Definition: progress.h:38
#define SMTP_ERR_WRITE
Definition: smtp.c:64
static int smtp_get_resp(struct Connection *conn)
Read a command response from the SMTP server.
Definition: smtp.c:118
int mutt_file_fclose(FILE **f)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
#define mutt_error(...)
Definition: logging.h:88

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static bool address_uses_unicode ( const char *  a)
static

Do any addresses use Unicode.

Parameters
aAddress list to check
Return values
trueif any of the string of addresses use 8-bit characters

Definition at line 279 of file smtp.c.

280 {
281  if (!a)
282  return false;
283 
284  while (*a)
285  {
286  if ((unsigned char) *a & (1 << 7))
287  return true;
288  a++;
289  }
290 
291  return false;
292 }

+ Here is the caller graph for this function:

static bool addresses_use_unicode ( const struct Address a)
static

Do any of a list of addresses use Unicode.

Parameters
aAddress list to check
Return values
trueif any use 8-bit characters

Definition at line 299 of file smtp.c.

300 {
301  while (a)
302  {
303  if (a->mailbox && !a->group && address_uses_unicode(a->mailbox))
304  return true;
305  a = a->next;
306  }
307  return false;
308 }
char * mailbox
mailbox and host address
Definition: address.h:35
static bool address_uses_unicode(const char *a)
Do any addresses use Unicode.
Definition: smtp.c:279
bool group
group mailbox?
Definition: address.h:36
struct Address * next
Definition: address.h:39

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int smtp_fill_account ( struct ConnAccount account)
static

Create ConnAccount object from SMTP Url.

Parameters
accountConnAccount to populate
Return values
0Success
-1Error

Definition at line 316 of file smtp.c.

317 {
318  account->flags = 0;
319  account->port = 0;
320  account->type = MUTT_ACCT_TYPE_SMTP;
321 
322  struct Url *url = url_parse(SmtpUrl);
323  if (!url || (url->scheme != U_SMTP && url->scheme != U_SMTPS) || !url->host ||
324  mutt_account_fromurl(account, url) < 0)
325  {
326  url_free(&url);
327  mutt_error(_("Invalid SMTP URL: %s"), SmtpUrl);
328  return -1;
329  }
330 
331  if (url->scheme == U_SMTPS)
332  account->flags |= MUTT_ACCT_SSL;
333 
334  if (!account->port)
335  {
336  if (account->flags & MUTT_ACCT_SSL)
337  account->port = SMTPS_PORT;
338  else
339  {
340  static unsigned short SmtpPort = 0;
341  if (!SmtpPort)
342  {
343  struct servent *service = getservbyname("smtp", "tcp");
344  if (service)
345  SmtpPort = ntohs(service->s_port);
346  else
347  SmtpPort = SMTP_PORT;
348  mutt_debug(3, "Using default SMTP port %d\n", SmtpPort);
349  }
350  account->port = SmtpPort;
351  }
352  }
353 
354  url_free(&url);
355  return 0;
356 }
struct Url url
Definition: url.c:45
A parsed URL proto://user:password@host:port/path?a=1&b=2
Definition: url.h:67
enum UrlScheme scheme
Definition: url.h:69
struct Url * url_parse(const char *src)
Fill in Url.
Definition: url.c:162
#define _(a)
Definition: message.h:28
void url_free(struct Url **u)
Free the contents of a URL.
Definition: url.c:290
#define SMTP_PORT
Definition: smtp.c:67
unsigned short port
Definition: connaccount.h:35
Url is smtps://.
Definition: url.h:43
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition: connaccount.h:36
char * host
Definition: url.h:72
unsigned char flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:37
WHERE char * SmtpUrl
Config: (smtp) Url of the SMTP server.
Definition: globals.h:145
#define mutt_error(...)
Definition: logging.h:88
Url is smtp://.
Definition: url.h:42
#define MUTT_ACCT_SSL
Definition: mutt_account.h:60
Smtp Account.
Definition: mutt_account.h:51
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
#define SMTPS_PORT
Definition: smtp.c:68
int mutt_account_fromurl(struct ConnAccount *account, const struct Url *url)
Fill ConnAccount with information from url.
Definition: mutt_account.c:108

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int smtp_helo ( struct Connection conn,
bool  esmtp 
)
static

Say hello to an SMTP Server.

Parameters
connSMTP Connection
esmtpIf true, use ESMTP
Return values
0Success
<0Error, e.g. SMTP_ERR_WRITE

Definition at line 365 of file smtp.c.

366 {
367  char buf[LONG_STRING];
368  const char *fqdn = NULL;
369 
370  memset(Capabilities, 0, sizeof(Capabilities));
371 
372  if (!esmtp)
373  {
374  /* if TLS or AUTH are requested, use EHLO */
375  if (conn->account.flags & MUTT_ACCT_USER)
376  esmtp = true;
377 #ifdef USE_SSL
378  if (SslForceTls || SslStarttls != MUTT_NO)
379  esmtp = true;
380 #endif
381  }
382 
383  fqdn = mutt_fqdn(false);
384  if (!fqdn)
385  fqdn = NONULL(ShortHostname);
386 
387  snprintf(buf, sizeof(buf), "%s %s\r\n", esmtp ? "EHLO" : "HELO", fqdn);
388  /* XXX there should probably be a wrapper in mutt_socket.c that
389  * repeatedly calls conn->write until all data is sent. This
390  * currently doesn't check for a short write.
391  */
392  if (mutt_socket_send(conn, buf) == -1)
393  return SMTP_ERR_WRITE;
394  return smtp_get_resp(conn);
395 }
#define NONULL(x)
Definition: string2.h:39
struct ConnAccount account
Definition: connection.h:37
#define mutt_socket_send(conn, buffer)
Definition: mutt_socket.h:38
#define LONG_STRING
Definition: string2.h:36
WHERE bool SslForceTls
Config: (ssl) Require TLS encryption for all connections.
Definition: globals.h:236
static unsigned char Capabilities[(SMTP_CAP_MAX+7)/8]
Definition: smtp.c:88
#define SMTP_ERR_WRITE
Definition: smtp.c:64
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
static int smtp_get_resp(struct Connection *conn)
Read a command response from the SMTP server.
Definition: smtp.c:118
unsigned char flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:37
const char * mutt_fqdn(bool may_hide_host)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:2425
WHERE unsigned char SslStarttls
Config: (ssl) Use STARTTLS on servers advertising the capability.
Definition: globals.h:192
WHERE char * ShortHostname
Short version of the hostname.
Definition: globals.h:48
#define MUTT_ACCT_USER
Definition: mutt_account.h:57

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int smtp_auth_sasl ( struct Connection conn,
const char *  mechlist 
)
static

Authenticate using SASL.

Parameters
connSMTP Connection
mechlistList of mechanisms to use
Return values
0Success
<0Error, e.g. SMTP_AUTH_FAIL

Definition at line 405 of file smtp.c.

406 {
407  sasl_conn_t *saslconn = NULL;
408  sasl_interact_t *interaction = NULL;
409  const char *mech = NULL;
410  const char *data = NULL;
411  unsigned int len;
412  char *buf = NULL;
413  size_t bufsize = 0;
414  int rc, saslrc;
415 
416  if (mutt_sasl_client_new(conn, &saslconn) < 0)
417  return SMTP_AUTH_FAIL;
418 
419  do
420  {
421  rc = sasl_client_start(saslconn, mechlist, &interaction, &data, &len, &mech);
422  if (rc == SASL_INTERACT)
423  mutt_sasl_interact(interaction);
424  } while (rc == SASL_INTERACT);
425 
426  if (rc != SASL_OK && rc != SASL_CONTINUE)
427  {
428  mutt_debug(2, "%s unavailable\n", mech);
429  sasl_dispose(&saslconn);
430  return SMTP_AUTH_UNAVAIL;
431  }
432 
433  if (!OptNoCurses)
434  mutt_message(_("Authenticating (%s)..."), mech);
435 
436  bufsize = ((len * 2) > LONG_STRING) ? (len * 2) : LONG_STRING;
437  buf = mutt_mem_malloc(bufsize);
438 
439  snprintf(buf, bufsize, "AUTH %s", mech);
440  if (len)
441  {
442  mutt_str_strcat(buf, bufsize, " ");
443  if (sasl_encode64(data, len, buf + mutt_str_strlen(buf),
444  bufsize - mutt_str_strlen(buf), &len) != SASL_OK)
445  {
446  mutt_debug(1, "#1 error base64-encoding client response.\n");
447  goto fail;
448  }
449  }
450  mutt_str_strcat(buf, bufsize, "\r\n");
451 
452  do
453  {
454  if (mutt_socket_send(conn, buf) < 0)
455  goto fail;
456  rc = mutt_socket_readln(buf, bufsize, conn);
457  if (rc < 0)
458  goto fail;
459  if (!valid_smtp_code(buf, rc, &rc))
460  goto fail;
461 
462  if (rc != SMTP_READY)
463  break;
464 
465  if (sasl_decode64(buf + 4, strlen(buf + 4), buf, bufsize - 1, &len) != SASL_OK)
466  {
467  mutt_debug(1, "error base64-decoding server response.\n");
468  goto fail;
469  }
470 
471  do
472  {
473  saslrc = sasl_client_step(saslconn, buf, len, &interaction, &data, &len);
474  if (saslrc == SASL_INTERACT)
475  mutt_sasl_interact(interaction);
476  } while (saslrc == SASL_INTERACT);
477 
478  if (len)
479  {
480  if ((len * 2) > bufsize)
481  {
482  bufsize = len * 2;
483  mutt_mem_realloc(&buf, bufsize);
484  }
485  if (sasl_encode64(data, len, buf, bufsize, &len) != SASL_OK)
486  {
487  mutt_debug(1, "#2 error base64-encoding client response.\n");
488  goto fail;
489  }
490  }
491  mutt_str_strfcpy(buf + len, "\r\n", bufsize - len);
492  } while (rc == SMTP_READY && saslrc != SASL_FAIL);
493 
494  if (smtp_success(rc))
495  {
496  mutt_sasl_setup_conn(conn, saslconn);
497  FREE(&buf);
498  return SMTP_AUTH_SUCCESS;
499  }
500 
501 fail:
502  sasl_dispose(&saslconn);
503  FREE(&buf);
504  return SMTP_AUTH_FAIL;
505 }
#define mutt_message(...)
Definition: logging.h:87
#define _(a)
Definition: message.h:28
int mutt_sasl_client_new(struct Connection *conn, sasl_conn_t **saslconn)
wrapper for sasl_client_new
Definition: sasl.c:504
WHERE bool OptNoCurses
(pseudo) when sending in batch mode
Definition: options.h:45
#define SMTP_AUTH_SUCCESS
Definition: smtp.c:70
void mutt_sasl_setup_conn(struct Connection *conn, sasl_conn_t *saslconn)
Set up an SASL connection.
Definition: sasl.c:647
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:663
#define mutt_socket_send(conn, buffer)
Definition: mutt_socket.h:38
#define LONG_STRING
Definition: string2.h:36
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:124
#define mutt_socket_readln(A, B, C)
Definition: mutt_socket.h:37
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:99
size_t mutt_str_strfcpy(char *dest, const char *src, size_t dsize)
Copy a string into a buffer (guaranteeing NUL-termination)
Definition: string.c:742
#define SMTP_READY
Definition: smtp.c:60
#define smtp_success(x)
Definition: smtp.c:59
char * mutt_str_strcat(char *buf, size_t buflen, const char *s)
Concatenate two strings.
Definition: string.c:402
#define SMTP_AUTH_UNAVAIL
Definition: smtp.c:71
static bool valid_smtp_code(char *buf, size_t buflen, int *n)
Is the is a valid SMTP return code?
Definition: smtp.c:97
#define FREE(x)
Definition: memory.h:46
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
#define SMTP_AUTH_FAIL
Definition: smtp.c:72
int mutt_sasl_interact(sasl_interact_t *interaction)
Perform an SASL interaction with the user.
Definition: sasl.c:615

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int smtp_auth_oauth ( struct Connection conn)
static

Authenticate an SMTP connection using OAUTHBEARER.

Parameters
connConnection info
Return values
numResult, e.g. SMTP_AUTH_SUCCESS

Definition at line 513 of file smtp.c.

514 {
515  mutt_message(_("Authenticating (OAUTHBEARER)..."));
516 
517  /* We get the access token from the smtp_oauth_refresh_command */
518  char *oauthbearer = mutt_account_getoauthbearer(&conn->account);
519  if (!oauthbearer)
520  return SMTP_AUTH_FAIL;
521 
522  size_t ilen = strlen(oauthbearer) + 30;
523  char *ibuf = mutt_mem_malloc(ilen);
524  snprintf(ibuf, ilen, "AUTH OAUTHBEARER %s\r\n", oauthbearer);
525 
526  int rc = mutt_socket_send(conn, ibuf);
527  FREE(&oauthbearer);
528  FREE(&ibuf);
529 
530  if (rc == -1)
531  return SMTP_AUTH_FAIL;
532  if (smtp_get_resp(conn) != 0)
533  return SMTP_AUTH_FAIL;
534 
535  return SMTP_AUTH_SUCCESS;
536 }
struct ConnAccount account
Definition: connection.h:37
#define mutt_message(...)
Definition: logging.h:87
#define _(a)
Definition: message.h:28
#define SMTP_AUTH_SUCCESS
Definition: smtp.c:70
#define mutt_socket_send(conn, buffer)
Definition: mutt_socket.h:38
char * mutt_account_getoauthbearer(struct ConnAccount *account)
Get an OAUTHBEARER token.
Definition: mutt_account.c:347
void * mutt_mem_malloc(size_t size)
Allocate memory on the heap.
Definition: memory.c:99
static int smtp_get_resp(struct Connection *conn)
Read a command response from the SMTP server.
Definition: smtp.c:118
#define FREE(x)
Definition: memory.h:46
#define SMTP_AUTH_FAIL
Definition: smtp.c:72

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int smtp_auth_plain ( struct Connection conn)
static

Authenticate using plain text.

Parameters
connSMTP Connection
Return values
0Success
<0Error, e.g. SMTP_AUTH_FAIL

Definition at line 544 of file smtp.c.

545 {
546  char buf[LONG_STRING];
547 
548  /* Get username and password. Bail out of any cannot be retrieved. */
549  if ((mutt_account_getuser(&conn->account) < 0) ||
550  (mutt_account_getpass(&conn->account) < 0))
551  {
552  goto error;
553  }
554 
555  /* Build the initial client response. */
556  size_t len = mutt_sasl_plain_msg(buf, sizeof(buf), "AUTH PLAIN", conn->account.user,
557  conn->account.user, conn->account.pass);
558 
559  /* Terminate as per SMTP protocol. Bail out if there's no room left. */
560  if (snprintf(buf + len, sizeof(buf) - len, "\r\n") != 2)
561  {
562  goto error;
563  }
564 
565  /* Send request, receive response (with a check for OK code). */
566  if ((mutt_socket_send(conn, buf) < 0) || smtp_get_resp(conn))
567  {
568  goto error;
569  }
570 
571  /* If we got here, auth was successful. */
572  return 0;
573 
574 error:
575  mutt_error(_("SASL authentication failed"));
576  return -1;
577 }
struct ConnAccount account
Definition: connection.h:37
char user[128]
Definition: connaccount.h:31
#define _(a)
Definition: message.h:28
size_t mutt_sasl_plain_msg(char *buf, size_t buflen, const char *cmd, const char *authz, const char *user, const char *pass)
Construct a base64 encoded SASL PLAIN message.
Definition: sasl_plain.c:54
#define mutt_socket_send(conn, buffer)
Definition: mutt_socket.h:38
#define LONG_STRING
Definition: string2.h:36
char pass[256]
Definition: connaccount.h:33
int mutt_account_getpass(struct ConnAccount *account)
Fetch password into ConnAccount, if necessary.
Definition: mutt_account.c:288
int mutt_account_getuser(struct ConnAccount *account)
Retrieve username into ConnAccount, if necessary.
Definition: mutt_account.c:207
static int smtp_get_resp(struct Connection *conn)
Read a command response from the SMTP server.
Definition: smtp.c:118
#define mutt_error(...)
Definition: logging.h:88

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int smtp_auth ( struct Connection conn)
static

Authenticate to an SMTP server.

Parameters
connSMTP Connection
Return values
0Success
<0Error, e.g. SMTP_AUTH_FAIL

Definition at line 585 of file smtp.c.

586 {
587  int r = SMTP_AUTH_UNAVAIL;
588 
590  {
591  char *methods = mutt_str_strdup(SmtpAuthenticators);
592  char *method = NULL;
593  char *delim = NULL;
594 
595  for (method = methods; method; method = delim)
596  {
597  delim = strchr(method, ':');
598  if (delim)
599  *delim++ = '\0';
600  if (!method[0])
601  continue;
602 
603  mutt_debug(2, "Trying method %s\n", method);
604 
605  if (strcmp(method, "oauthbearer") == 0)
606  {
607  r = smtp_auth_oauth(conn);
608  }
609  else if (strcmp(method, "plain") == 0)
610  {
611  r = smtp_auth_plain(conn);
612  }
613  else
614  {
615 #ifdef USE_SASL
616  r = smtp_auth_sasl(conn, method);
617 #else
618  mutt_error(_("SMTP authentication method %s requires SASL"), method);
619  continue;
620 #endif
621  }
622 
623  if (r == SMTP_AUTH_FAIL && delim)
624  {
625  mutt_error(_("%s authentication failed, trying next method"), method);
626  }
627  else if (r != SMTP_AUTH_UNAVAIL)
628  break;
629  }
630 
631  FREE(&methods);
632  }
633  else
634  {
635 #ifdef USE_SASL
636  r = smtp_auth_sasl(conn, AuthMechs);
637 #else
638  mutt_error(_("SMTP authentication requires SASL"));
639  r = SMTP_AUTH_UNAVAIL;
640 #endif
641  }
642 
643  if (r != SMTP_AUTH_SUCCESS)
645 
646  if (r == SMTP_AUTH_FAIL)
647  {
648  mutt_error(_("SASL authentication failed"));
649  }
650  else if (r == SMTP_AUTH_UNAVAIL)
651  {
652  mutt_error(_("No authenticators available"));
653  }
654 
655  return (r == SMTP_AUTH_SUCCESS) ? 0 : -1;
656 }
static int smtp_auth_plain(struct Connection *conn)
Authenticate using plain text.
Definition: smtp.c:544
struct ConnAccount account
Definition: connection.h:37
#define _(a)
Definition: message.h:28
#define SMTP_AUTH_SUCCESS
Definition: smtp.c:70
#define SMTP_AUTH_UNAVAIL
Definition: smtp.c:71
static int smtp_auth_sasl(struct Connection *conn, const char *mechlist)
Authenticate using SASL.
Definition: smtp.c:405
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:384
#define mutt_error(...)
Definition: logging.h:88
char * SmtpAuthenticators
Config: (smtp) List of allowed authentication methods.
Definition: smtp.c:57
#define FREE(x)
Definition: memory.h:46
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
static char * AuthMechs
Definition: smtp.c:87
#define SMTP_AUTH_FAIL
Definition: smtp.c:72
static int smtp_auth_oauth(struct Connection *conn)
Authenticate an SMTP connection using OAUTHBEARER.
Definition: smtp.c:513
void mutt_account_unsetpass(struct ConnAccount *account)
Unset ConnAccount&#39;s password.
Definition: mutt_account.c:331

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

static int smtp_open ( struct Connection conn,
bool  esmtp 
)
static

Open an SMTP Connection.

Parameters
connSMTP Connection
esmtpIf true, use ESMTP
Return values
0Success
-1Error

Definition at line 665 of file smtp.c.

666 {
667  int rc;
668 
669  if (mutt_socket_open(conn))
670  return -1;
671 
672  /* get greeting string */
673  rc = smtp_get_resp(conn);
674  if (rc != 0)
675  return rc;
676 
677  rc = smtp_helo(conn, esmtp);
678  if (rc != 0)
679  return rc;
680 
681 #ifdef USE_SSL
682  if (conn->ssf)
683  rc = MUTT_NO;
684  else if (SslForceTls)
685  rc = MUTT_YES;
688  _("Secure connection with TLS?"))) == MUTT_ABORT)
689  {
690  return rc;
691  }
692 
693  if (rc == MUTT_YES)
694  {
695  if (mutt_socket_send(conn, "STARTTLS\r\n") < 0)
696  return SMTP_ERR_WRITE;
697  rc = smtp_get_resp(conn);
698  if (rc != 0)
699  return rc;
700 
701  if (mutt_ssl_starttls(conn))
702  {
703  mutt_error(_("Could not negotiate TLS connection"));
704  return -1;
705  }
706 
707  /* re-EHLO to get authentication mechanisms */
708  rc = smtp_helo(conn, esmtp);
709  if (rc != 0)
710  return rc;
711  }
712 #endif
713 
714  if (conn->account.flags & MUTT_ACCT_USER)
715  {
717  {
718  mutt_error(_("SMTP server does not support authentication"));
719  return -1;
720  }
721 
722  return smtp_auth(conn);
723  }
724 
725  return 0;
726 }
#define mutt_bit_isset(v, n)
Definition: memory.h:39
static int smtp_helo(struct Connection *conn, bool esmtp)
Say hello to an SMTP Server.
Definition: smtp.c:365
struct ConnAccount account
Definition: connection.h:37
unsigned int ssf
security strength factor, in bits
Definition: connection.h:38
Server supports STARTTLS command.
Definition: smtp.c:79
User aborted the question (with Ctrl-G)
Definition: quad.h:37
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
#define _(a)
Definition: message.h:28
#define mutt_socket_send(conn, buffer)
Definition: mutt_socket.h:38
WHERE bool SslForceTls
Config: (ssl) Require TLS encryption for all connections.
Definition: globals.h:236
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
Definition: socket.c:86
static int smtp_auth(struct Connection *conn)
Authenticate to an SMTP server.
Definition: smtp.c:585
static unsigned char Capabilities[(SMTP_CAP_MAX+7)/8]
Definition: smtp.c:88
#define SMTP_ERR_WRITE
Definition: smtp.c:64
int mutt_ssl_starttls(struct Connection *conn)
Negotiate TLS over an already opened connection.
Definition: ssl.c:1405
User answered &#39;No&#39;, or assume &#39;No&#39;.
Definition: quad.h:38
int query_quadoption(int opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:3227
static int smtp_get_resp(struct Connection *conn)
Read a command response from the SMTP server.
Definition: smtp.c:118
unsigned char flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:37
WHERE unsigned char SslStarttls
Config: (ssl) Use STARTTLS on servers advertising the capability.
Definition: globals.h:192
#define mutt_error(...)
Definition: logging.h:88
Server supports AUTH command.
Definition: smtp.c:80
#define MUTT_ACCT_USER
Definition: mutt_account.h:57

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int mutt_smtp_send ( const struct Address from,
const struct Address to,
const struct Address cc,
const struct Address bcc,
const char *  msgfile,
bool  eightbit 
)

Send a message using SMTP.

Parameters
fromFrom Address
toTo Address
ccCc Address
bccBcc Address
msgfileMessage to send to the server
eightbitIf true, try for an 8-bit friendly connection
Return values
0Success
-1Error

Definition at line 739 of file smtp.c.

742 {
743  struct Connection *conn = NULL;
744  struct ConnAccount account;
745  const char *envfrom = NULL;
746  char buf[1024];
747  int rc = -1;
748 
749  /* it might be better to synthesize an envelope from from user and host
750  * but this condition is most likely arrived at accidentally */
752  envfrom = EnvelopeFromAddress->mailbox;
753  else if (from)
754  envfrom = from->mailbox;
755  else
756  {
757  mutt_error(_("No from address given"));
758  return -1;
759  }
760 
761  if (smtp_fill_account(&account) < 0)
762  return rc;
763 
764  conn = mutt_conn_find(NULL, &account);
765  if (!conn)
766  return -1;
767 
768  do
769  {
770  /* send our greeting */
771  rc = smtp_open(conn, eightbit);
772  if (rc != 0)
773  break;
774  FREE(&AuthMechs);
775 
776  /* send the sender's address */
777  int len = snprintf(buf, sizeof(buf), "MAIL FROM:<%s>", envfrom);
779  {
780  mutt_str_strncat(buf, sizeof(buf), " BODY=8BITMIME", 15);
781  len += 14;
782  }
784  len += snprintf(buf + len, sizeof(buf) - len, " RET=%s", DsnReturn);
786  (address_uses_unicode(envfrom) || addresses_use_unicode(to) ||
788  {
789  snprintf(buf + len, sizeof(buf) - len, " SMTPUTF8");
790  }
791  mutt_str_strncat(buf, sizeof(buf), "\r\n", 3);
792  if (mutt_socket_send(conn, buf) == -1)
793  {
794  rc = SMTP_ERR_WRITE;
795  break;
796  }
797  rc = smtp_get_resp(conn);
798  if (rc != 0)
799  break;
800 
801  /* send the recipient list */
802  if ((rc = smtp_rcpt_to(conn, to)) || (rc = smtp_rcpt_to(conn, cc)) ||
803  (rc = smtp_rcpt_to(conn, bcc)))
804  {
805  break;
806  }
807 
808  /* send the message data */
809  rc = smtp_data(conn, msgfile);
810  if (rc != 0)
811  break;
812 
813  mutt_socket_send(conn, "QUIT\r\n");
814 
815  rc = 0;
816  } while (false);
817 
818  if (conn)
819  mutt_socket_close(conn);
820 
821  if (rc == SMTP_ERR_READ)
822  mutt_error(_("SMTP session failed: read error"));
823  else if (rc == SMTP_ERR_WRITE)
824  mutt_error(_("SMTP session failed: write error"));
825  else if (rc == SMTP_ERR_CODE)
826  mutt_error(_("Invalid server response"));
827 
828  return rc;
829 }
WHERE struct Address * EnvelopeFromAddress
Config: Manually set the sender for outgoing messages.
Definition: globals.h:99
#define mutt_bit_isset(v, n)
Definition: memory.h:39
Server supports 8-bit MIME content.
Definition: smtp.c:82
An open network connection (socket)
Definition: connection.h:35
#define _(a)
Definition: message.h:28
char * mailbox
mailbox and host address
Definition: address.h:35
#define mutt_socket_send(conn, buffer)
Definition: mutt_socket.h:38
char * mutt_str_strncat(char *d, size_t l, const char *s, size_t sl)
Concatenate two strings.
Definition: string.c:431
static int smtp_open(struct Connection *conn, bool esmtp)
Open an SMTP Connection.
Definition: smtp.c:665
Server accepts UTF-8 strings.
Definition: smtp.c:83
static int smtp_rcpt_to(struct Connection *conn, const struct Address *a)
Set the recipient to an Address.
Definition: smtp.c:168
static unsigned char Capabilities[(SMTP_CAP_MAX+7)/8]
Definition: smtp.c:88
#define SMTP_ERR_WRITE
Definition: smtp.c:64
static bool address_uses_unicode(const char *a)
Do any addresses use Unicode.
Definition: smtp.c:279
static int smtp_get_resp(struct Connection *conn)
Read a command response from the SMTP server.
Definition: smtp.c:118
#define SMTP_ERR_READ
Definition: smtp.c:63
Login details for a remote server.
Definition: connaccount.h:29
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:107
#define SMTP_ERR_CODE
Definition: smtp.c:65
static int smtp_fill_account(struct ConnAccount *account)
Create ConnAccount object from SMTP Url.
Definition: smtp.c:316
#define mutt_error(...)
Definition: logging.h:88
#define FREE(x)
Definition: memory.h:46
static char * AuthMechs
Definition: smtp.c:87
WHERE char * DsnReturn
Config: What to send as a notification of message delivery or delay.
Definition: globals.h:109
static int smtp_data(struct Connection *conn, const char *msgfile)
Send data to an SMTP server.
Definition: smtp.c:203
Server supports Delivery Status Notification.
Definition: smtp.c:81
static bool addresses_use_unicode(const struct Address *a)
Do any of a list of addresses use Unicode.
Definition: smtp.c:299
struct Connection * mutt_conn_find(const struct Connection *start, const struct ConnAccount *account)
Find a connection from a list.
Definition: mutt_socket.c:85

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

char* SmtpAuthenticators

Config: (smtp) List of allowed authentication methods.

Definition at line 57 of file smtp.c.

char* AuthMechs = NULL
static

Definition at line 87 of file smtp.c.

unsigned char Capabilities[(SMTP_CAP_MAX+7)/8]
static

Definition at line 88 of file smtp.c.