NeoMutt  2018-07-16 +1360-3df4a2
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
 
#define SMTP_CAP_NO_FLAGS   0
 No flags are set. More...
 
#define SMTP_CAP_STARTTLS   (1 << 0)
 Server supports STARTTLS command. More...
 
#define SMTP_CAP_AUTH   (1 << 1)
 Server supports AUTH command. More...
 
#define SMTP_CAP_DSN   (1 << 2)
 Server supports Delivery Status Notification. More...
 
#define SMTP_CAP_EIGHTBITMIME   (1 << 3)
 Server supports 8-bit MIME content. More...
 
#define SMTP_CAP_SMTPUTF8   (1 << 4)
 Server accepts UTF-8 strings. More...
 
#define SMTP_CAP_ALL   ((1 << 5) - 1)
 

Typedefs

typedef uint8_t SmtpCapFlags
 typedef SmtpCapFlags - 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 * C_SmtpAuthenticators
 Config: (smtp) List of allowed authentication methods. More...
 
static char * AuthMechs = NULL
 
static SmtpCapFlags Capabilities
 

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.

#define SMTP_CAP_NO_FLAGS   0

No flags are set.

Definition at line 79 of file smtp.c.

#define SMTP_CAP_STARTTLS   (1 << 0)

Server supports STARTTLS command.

Definition at line 80 of file smtp.c.

#define SMTP_CAP_AUTH   (1 << 1)

Server supports AUTH command.

Definition at line 81 of file smtp.c.

#define SMTP_CAP_DSN   (1 << 2)

Server supports Delivery Status Notification.

Definition at line 82 of file smtp.c.

#define SMTP_CAP_EIGHTBITMIME   (1 << 3)

Server supports 8-bit MIME content.

Definition at line 83 of file smtp.c.

#define SMTP_CAP_SMTPUTF8   (1 << 4)

Server accepts UTF-8 strings.

Definition at line 84 of file smtp.c.

#define SMTP_CAP_ALL   ((1 << 5) - 1)

Definition at line 86 of file smtp.c.

Typedef Documentation

typedef uint8_t SmtpCapFlags

typedef SmtpCapFlags - SMTP server capabilities

Flags, e.g. SMTP_CAP_STARTTLS

Definition at line 78 of file smtp.c.

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 99 of file smtp.c.

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

+ 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 120 of file smtp.c.

121 {
122  int n;
123  char buf[1024];
124 
125  do
126  {
127  n = mutt_socket_readln(buf, sizeof(buf), conn);
128  if (n < 4)
129  {
130  /* read error, or no response code */
131  return SMTP_ERR_READ;
132  }
133  const char *s = buf + 4; /* Skip the response code and the space/dash */
134  size_t plen;
135 
136  if (mutt_str_startswith(s, "8BITMIME", CASE_IGNORE))
138  else if ((plen = mutt_str_startswith(s, "AUTH ", CASE_IGNORE)))
139  {
141  FREE(&AuthMechs);
142  AuthMechs = mutt_str_strdup(s + plen);
143  }
144  else if (mutt_str_startswith(s, "DSN", CASE_IGNORE))
146  else if (mutt_str_startswith(s, "STARTTLS", CASE_IGNORE))
148  else if (mutt_str_startswith(s, "SMTPUTF8", CASE_IGNORE))
150 
151  if (!valid_smtp_code(buf, n, &n))
152  return SMTP_ERR_CODE;
153 
154  } while (buf[3] == '-');
155 
156  if (smtp_success(n) || (n == SMTP_CONTINUE))
157  return 0;
158 
159  mutt_error(_("SMTP session failed: %s"), buf);
160  return -1;
161 }
#define SMTP_CAP_STARTTLS
Server supports STARTTLS command.
Definition: smtp.c:80
static size_t plen
Length of cached packet.
Definition: pgppacket.c:38
#define SMTP_CAP_SMTPUTF8
Server accepts UTF-8 strings.
Definition: smtp.c:84
#define _(a)
Definition: message.h:28
static SmtpCapFlags Capabilities
Definition: smtp.c:90
Ignore case when comparing strings.
Definition: string2.h:67
#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:165
#define mutt_socket_readln(buf, buflen, conn)
Definition: mutt_socket.h:37
#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:99
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:383
#define mutt_error(...)
Definition: logging.h:88
#define SMTP_CONTINUE
Definition: smtp.c:61
#define SMTP_CAP_EIGHTBITMIME
Server supports 8-bit MIME content.
Definition: smtp.c:83
#define FREE(x)
Definition: memory.h:40
#define SMTP_CAP_AUTH
Server supports AUTH command.
Definition: smtp.c:81
static char * AuthMechs
Definition: smtp.c:89
#define SMTP_CAP_DSN
Server supports Delivery Status Notification.
Definition: smtp.c:82

+ 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 170 of file smtp.c.

171 {
172  char buf[1024];
173  int rc;
174 
175  while (a)
176  {
177  /* weed out group mailboxes, since those are for display only */
178  if (!a->mailbox || a->group)
179  {
180  a = a->next;
181  continue;
182  }
184  snprintf(buf, sizeof(buf), "RCPT TO:<%s> NOTIFY=%s\r\n", a->mailbox, C_DsnNotify);
185  else
186  snprintf(buf, sizeof(buf), "RCPT TO:<%s>\r\n", a->mailbox);
187  if (mutt_socket_send(conn, buf) == -1)
188  return SMTP_ERR_WRITE;
189  rc = smtp_get_resp(conn);
190  if (rc != 0)
191  return rc;
192  a = a->next;
193  }
194 
195  return 0;
196 }
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:38
char * mailbox
mailbox and host address
Definition: address.h:35
static SmtpCapFlags Capabilities
Definition: smtp.c:90
#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:120
bool group
group mailbox?
Definition: address.h:36
WHERE char * C_DsnNotify
Config: Request notification for message delivery or delay.
Definition: globals.h:110
#define SMTP_CAP_DSN
Server supports Delivery Status Notification.
Definition: smtp.c:82
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 205 of file smtp.c.

206 {
207  char buf[1024];
208  struct Progress progress;
209  struct stat st;
210  int rc, term = 0;
211  size_t buflen = 0;
212 
213  FILE *fp = fopen(msgfile, "r");
214  if (!fp)
215  {
216  mutt_error(_("SMTP session failed: unable to open %s"), msgfile);
217  return -1;
218  }
219  stat(msgfile, &st);
220  unlink(msgfile);
221  mutt_progress_init(&progress, _("Sending message..."), MUTT_PROGRESS_SIZE,
222  C_NetInc, st.st_size);
223 
224  snprintf(buf, sizeof(buf), "DATA\r\n");
225  if (mutt_socket_send(conn, buf) == -1)
226  {
227  mutt_file_fclose(&fp);
228  return SMTP_ERR_WRITE;
229  }
230  rc = smtp_get_resp(conn);
231  if (rc != 0)
232  {
233  mutt_file_fclose(&fp);
234  return rc;
235  }
236 
237  while (fgets(buf, sizeof(buf) - 1, fp))
238  {
239  buflen = mutt_str_strlen(buf);
240  term = buflen && buf[buflen - 1] == '\n';
241  if (term && ((buflen == 1) || (buf[buflen - 2] != '\r')))
242  snprintf(buf + buflen - 1, sizeof(buf) - buflen + 1, "\r\n");
243  if (buf[0] == '.')
244  {
245  if (mutt_socket_send_d(conn, ".", MUTT_SOCK_LOG_FULL) == -1)
246  {
247  mutt_file_fclose(&fp);
248  return SMTP_ERR_WRITE;
249  }
250  }
251  if (mutt_socket_send_d(conn, buf, MUTT_SOCK_LOG_FULL) == -1)
252  {
253  mutt_file_fclose(&fp);
254  return SMTP_ERR_WRITE;
255  }
256  mutt_progress_update(&progress, ftell(fp), -1);
257  }
258  if (!term && buflen && (mutt_socket_send_d(conn, "\r\n", MUTT_SOCK_LOG_FULL) == -1))
259  {
260  mutt_file_fclose(&fp);
261  return SMTP_ERR_WRITE;
262  }
263  mutt_file_fclose(&fp);
264 
265  /* terminate the message body */
266  if (mutt_socket_send(conn, ".\r\n") == -1)
267  return SMTP_ERR_WRITE;
268 
269  rc = smtp_get_resp(conn);
270  if (rc != 0)
271  return rc;
272 
273  return 0;
274 }
#define MUTT_PROGRESS_SIZE
traffic-based progress
Definition: progress.h:32
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:38
int mutt_file_fclose(FILE **fp)
Close a FILE handle (and NULL the pointer)
Definition: file.c:149
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
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:662
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:32
A progress bar.
Definition: progress.h:38
#define mutt_socket_send_d(conn, buf, dbg)
Definition: mutt_socket.h:39
#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:120
#define mutt_error(...)
Definition: logging.h:88
WHERE short C_NetInc
Config: (socket) Update the progress bar after this many KB sent/received (0 to disable) ...
Definition: globals.h:131

+ 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 281 of file smtp.c.

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

+ 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 301 of file smtp.c.

302 {
303  while (a)
304  {
305  if (a->mailbox && !a->group && address_uses_unicode(a->mailbox))
306  return true;
307  a = a->next;
308  }
309  return false;
310 }
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:281
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 318 of file smtp.c.

319 {
320  account->flags = 0;
321  account->port = 0;
322  account->type = MUTT_ACCT_TYPE_SMTP;
323 
324  struct Url *url = url_parse(C_SmtpUrl);
325  if (!url || ((url->scheme != U_SMTP) && (url->scheme != U_SMTPS)) ||
326  !url->host || (mutt_account_fromurl(account, url) < 0))
327  {
328  url_free(&url);
329  mutt_error(_("Invalid SMTP URL: %s"), C_SmtpUrl);
330  return -1;
331  }
332 
333  if (url->scheme == U_SMTPS)
334  account->flags |= MUTT_ACCT_SSL;
335 
336  if (!account->port)
337  {
338  if (account->flags & MUTT_ACCT_SSL)
339  account->port = SMTPS_PORT;
340  else
341  {
342  static unsigned short SmtpPort = 0;
343  if (!SmtpPort)
344  {
345  struct servent *service = getservbyname("smtp", "tcp");
346  if (service)
347  SmtpPort = ntohs(service->s_port);
348  else
349  SmtpPort = SMTP_PORT;
350  mutt_debug(LL_DEBUG3, "Using default SMTP port %d\n", SmtpPort);
351  }
352  account->port = SmtpPort;
353  }
354  }
355 
356  url_free(&url);
357  return 0;
358 }
struct Url url
Definition: url.c:45
WHERE char * C_SmtpUrl
Config: (smtp) Url of the SMTP server.
Definition: globals.h:148
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:289
#define SMTP_PORT
Definition: smtp.c:67
unsigned short port
Definition: connaccount.h:37
Url is smtps://.
Definition: url.h:43
unsigned char type
Connection type, e.g. MUTT_ACCT_TYPE_IMAP.
Definition: connaccount.h:38
char * host
Definition: url.h:72
#define mutt_error(...)
Definition: logging.h:88
Url is smtp://.
Definition: url.h:42
#define MUTT_ACCT_SSL
Account uses SSL/TLS.
Definition: mutt_account.h:64
Smtp Account.
Definition: mutt_account.h:54
#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
Log at debug level 3.
Definition: logging.h:58
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:39

+ 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 367 of file smtp.c.

368 {
369  char buf[1024];
370  const char *fqdn = NULL;
371 
372  Capabilities = 0;
373 
374  if (!esmtp)
375  {
376  /* if TLS or AUTH are requested, use EHLO */
377  if (conn->account.flags & MUTT_ACCT_USER)
378  esmtp = true;
379 #ifdef USE_SSL
380  if (C_SslForceTls || (C_SslStarttls != MUTT_NO))
381  esmtp = true;
382 #endif
383  }
384 
385  fqdn = mutt_fqdn(false);
386  if (!fqdn)
387  fqdn = NONULL(ShortHostname);
388 
389  snprintf(buf, sizeof(buf), "%s %s\r\n", esmtp ? "EHLO" : "HELO", fqdn);
390  /* XXX there should probably be a wrapper in mutt_socket.c that
391  * repeatedly calls conn->write until all data is sent. This
392  * currently doesn't check for a short write. */
393  if (mutt_socket_send(conn, buf) == -1)
394  return SMTP_ERR_WRITE;
395  return smtp_get_resp(conn);
396 }
#define NONULL(x)
Definition: string2.h:36
struct ConnAccount account
Definition: connection.h:36
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:38
WHERE bool C_SslForceTls
Config: (ssl) Require TLS encryption for all connections.
Definition: globals.h:240
static SmtpCapFlags Capabilities
Definition: smtp.c:90
#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:120
const char * mutt_fqdn(bool may_hide_host)
Get the Fully-Qualified Domain Name.
Definition: sendlib.c:2432
WHERE char * ShortHostname
Short version of the hostname.
Definition: globals.h:49
WHERE unsigned char C_SslStarttls
Config: (ssl) Use STARTTLS on servers advertising the capability.
Definition: globals.h:195
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:39
#define MUTT_ACCT_USER
User field has been set.
Definition: mutt_account.h:61

+ 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 406 of file smtp.c.

407 {
408  sasl_conn_t *saslconn = NULL;
409  sasl_interact_t *interaction = NULL;
410  const char *mech = NULL;
411  const char *data = NULL;
412  unsigned int len;
413  char *buf = NULL;
414  size_t bufsize = 0;
415  int rc, saslrc;
416 
417  if (mutt_sasl_client_new(conn, &saslconn) < 0)
418  return SMTP_AUTH_FAIL;
419 
420  do
421  {
422  rc = sasl_client_start(saslconn, mechlist, &interaction, &data, &len, &mech);
423  if (rc == SASL_INTERACT)
424  mutt_sasl_interact(interaction);
425  } while (rc == SASL_INTERACT);
426 
427  if ((rc != SASL_OK) && (rc != SASL_CONTINUE))
428  {
429  mutt_debug(LL_DEBUG2, "%s unavailable\n", mech);
430  sasl_dispose(&saslconn);
431  return SMTP_AUTH_UNAVAIL;
432  }
433 
434  if (!OptNoCurses)
435  mutt_message(_("Authenticating (%s)..."), mech);
436 
437  bufsize = MAX((len * 2), 1024);
438  buf = mutt_mem_malloc(bufsize);
439 
440  snprintf(buf, bufsize, "AUTH %s", mech);
441  if (len)
442  {
443  mutt_str_strcat(buf, bufsize, " ");
444  if (sasl_encode64(data, len, buf + mutt_str_strlen(buf),
445  bufsize - mutt_str_strlen(buf), &len) != SASL_OK)
446  {
447  mutt_debug(LL_DEBUG1, "#1 error base64-encoding client response.\n");
448  goto fail;
449  }
450  }
451  mutt_str_strcat(buf, bufsize, "\r\n");
452 
453  do
454  {
455  if (mutt_socket_send(conn, buf) < 0)
456  goto fail;
457  rc = mutt_socket_readln_d(buf, bufsize, conn, MUTT_SOCK_LOG_FULL);
458  if (rc < 0)
459  goto fail;
460  if (!valid_smtp_code(buf, rc, &rc))
461  goto fail;
462 
463  if (rc != SMTP_READY)
464  break;
465 
466  if (sasl_decode64(buf + 4, strlen(buf + 4), buf, bufsize - 1, &len) != SASL_OK)
467  {
468  mutt_debug(LL_DEBUG1, "error base64-decoding server response.\n");
469  goto fail;
470  }
471 
472  do
473  {
474  saslrc = sasl_client_step(saslconn, buf, len, &interaction, &data, &len);
475  if (saslrc == SASL_INTERACT)
476  mutt_sasl_interact(interaction);
477  } while (saslrc == SASL_INTERACT);
478 
479  if (len)
480  {
481  if ((len * 2) > bufsize)
482  {
483  bufsize = len * 2;
484  mutt_mem_realloc(&buf, bufsize);
485  }
486  if (sasl_encode64(data, len, buf, bufsize, &len) != SASL_OK)
487  {
488  mutt_debug(LL_DEBUG1, "#2 error base64-encoding client response.\n");
489  goto fail;
490  }
491  }
492  mutt_str_strfcpy(buf + len, "\r\n", bufsize - len);
493  } while (rc == SMTP_READY && saslrc != SASL_FAIL);
494 
495  if (smtp_success(rc))
496  {
497  mutt_sasl_setup_conn(conn, saslconn);
498  FREE(&buf);
499  return SMTP_AUTH_SUCCESS;
500  }
501 
502 fail:
503  sasl_dispose(&saslconn);
504  FREE(&buf);
505  return SMTP_AUTH_FAIL;
506 }
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:38
#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:532
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:675
size_t mutt_str_strlen(const char *a)
Calculate the length of a string, safely.
Definition: string.c:662
#define MUTT_SOCK_LOG_FULL
Definition: mutt_socket.h:32
#define MAX(a, b)
Definition: memory.h:30
Log at debug level 2.
Definition: logging.h:57
void mutt_mem_realloc(void *ptr, size_t size)
Resize a block of memory on the heap.
Definition: memory.c:124
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:741
#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:401
#define SMTP_AUTH_UNAVAIL
Definition: smtp.c:71
Log at debug level 1.
Definition: logging.h:56
static bool valid_smtp_code(char *buf, size_t buflen, int *n)
Is the is a valid SMTP return code?
Definition: smtp.c:99
#define FREE(x)
Definition: memory.h:40
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition: socket.c:242
#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:643

+ 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 514 of file smtp.c.

515 {
516  mutt_message(_("Authenticating (OAUTHBEARER)..."));
517 
518  /* We get the access token from the smtp_oauth_refresh_command */
519  char *oauthbearer = mutt_account_getoauthbearer(&conn->account);
520  if (!oauthbearer)
521  return SMTP_AUTH_FAIL;
522 
523  size_t ilen = strlen(oauthbearer) + 30;
524  char *ibuf = mutt_mem_malloc(ilen);
525  snprintf(ibuf, ilen, "AUTH OAUTHBEARER %s\r\n", oauthbearer);
526 
527  int rc = mutt_socket_send(conn, ibuf);
528  FREE(&oauthbearer);
529  FREE(&ibuf);
530 
531  if (rc == -1)
532  return SMTP_AUTH_FAIL;
533  if (smtp_get_resp(conn) != 0)
534  return SMTP_AUTH_FAIL;
535 
536  return SMTP_AUTH_SUCCESS;
537 }
struct ConnAccount account
Definition: connection.h:36
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:38
#define mutt_message(...)
Definition: logging.h:87
#define _(a)
Definition: message.h:28
#define SMTP_AUTH_SUCCESS
Definition: smtp.c:70
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:120
#define FREE(x)
Definition: memory.h:40
#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 545 of file smtp.c.

546 {
547  char buf[1024];
548 
549  /* Get username and password. Bail out of any cannot be retrieved. */
550  if ((mutt_account_getuser(&conn->account) < 0) ||
551  (mutt_account_getpass(&conn->account) < 0))
552  {
553  goto error;
554  }
555 
556  /* Build the initial client response. */
557  size_t len = mutt_sasl_plain_msg(buf, sizeof(buf), "AUTH PLAIN", conn->account.user,
558  conn->account.user, conn->account.pass);
559 
560  /* Terminate as per SMTP protocol. Bail out if there's no room left. */
561  if (snprintf(buf + len, sizeof(buf) - len, "\r\n") != 2)
562  {
563  goto error;
564  }
565 
566  /* Send request, receive response (with a check for OK code). */
567  if ((mutt_socket_send(conn, buf) < 0) || smtp_get_resp(conn))
568  {
569  goto error;
570  }
571 
572  /* If we got here, auth was successful. */
573  return 0;
574 
575 error:
576  mutt_error(_("SASL authentication failed"));
577  return -1;
578 }
struct ConnAccount account
Definition: connection.h:36
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:38
char user[128]
Definition: connaccount.h:33
#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
char pass[256]
Definition: connaccount.h:35
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:120
#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 586 of file smtp.c.

587 {
588  int r = SMTP_AUTH_UNAVAIL;
589 
591  {
592  char *methods = mutt_str_strdup(C_SmtpAuthenticators);
593  char *method = NULL;
594  char *delim = NULL;
595 
596  for (method = methods; method; method = delim)
597  {
598  delim = strchr(method, ':');
599  if (delim)
600  *delim++ = '\0';
601  if (!method[0])
602  continue;
603 
604  mutt_debug(LL_DEBUG2, "Trying method %s\n", method);
605 
606  if (strcmp(method, "oauthbearer") == 0)
607  {
608  r = smtp_auth_oauth(conn);
609  }
610  else if (strcmp(method, "plain") == 0)
611  {
612  r = smtp_auth_plain(conn);
613  }
614  else
615  {
616 #ifdef USE_SASL
617  r = smtp_auth_sasl(conn, method);
618 #else
619  mutt_error(_("SMTP authentication method %s requires SASL"), method);
620  continue;
621 #endif
622  }
623 
624  if ((r == SMTP_AUTH_FAIL) && delim)
625  {
626  mutt_error(_("%s authentication failed, trying next method"), method);
627  }
628  else if (r != SMTP_AUTH_UNAVAIL)
629  break;
630  }
631 
632  FREE(&methods);
633  }
634  else
635  {
636 #ifdef USE_SASL
637  r = smtp_auth_sasl(conn, AuthMechs);
638 #else
639  mutt_error(_("SMTP authentication requires SASL"));
640  r = SMTP_AUTH_UNAVAIL;
641 #endif
642  }
643 
644  if (r != SMTP_AUTH_SUCCESS)
646 
647  if (r == SMTP_AUTH_FAIL)
648  {
649  mutt_error(_("SASL authentication failed"));
650  }
651  else if (r == SMTP_AUTH_UNAVAIL)
652  {
653  mutt_error(_("No authenticators available"));
654  }
655 
656  return (r == SMTP_AUTH_SUCCESS) ? 0 : -1;
657 }
static int smtp_auth_plain(struct Connection *conn)
Authenticate using plain text.
Definition: smtp.c:545
struct ConnAccount account
Definition: connection.h:36
#define _(a)
Definition: message.h:28
#define SMTP_AUTH_SUCCESS
Definition: smtp.c:70
Log at debug level 2.
Definition: logging.h:57
#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:406
char * mutt_str_strdup(const char *str)
Copy a string, safely.
Definition: string.c:383
#define mutt_error(...)
Definition: logging.h:88
char * C_SmtpAuthenticators
Config: (smtp) List of allowed authentication methods.
Definition: smtp.c:57
#define FREE(x)
Definition: memory.h:40
#define mutt_debug(LEVEL,...)
Definition: logging.h:85
static char * AuthMechs
Definition: smtp.c:89
#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:514
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 666 of file smtp.c.

667 {
668  int rc;
669 
670  if (mutt_socket_open(conn))
671  return -1;
672 
673  /* get greeting string */
674  rc = smtp_get_resp(conn);
675  if (rc != 0)
676  return rc;
677 
678  rc = smtp_helo(conn, esmtp);
679  if (rc != 0)
680  return rc;
681 
682 #ifdef USE_SSL
683  enum QuadOption ans = MUTT_NO;
684  if (conn->ssf)
685  ans = MUTT_NO;
686  else if (C_SslForceTls)
687  ans = MUTT_YES;
688  else if ((Capabilities & SMTP_CAP_STARTTLS) &&
690  _("Secure connection with TLS?"))) == MUTT_ABORT))
691  {
692  return -1;
693  }
694 
695  if (ans == MUTT_YES)
696  {
697  if (mutt_socket_send(conn, "STARTTLS\r\n") < 0)
698  return SMTP_ERR_WRITE;
699  rc = smtp_get_resp(conn);
700  if (rc != 0)
701  return rc;
702 
703  if (mutt_ssl_starttls(conn))
704  {
705  mutt_error(_("Could not negotiate TLS connection"));
706  return -1;
707  }
708 
709  /* re-EHLO to get authentication mechanisms */
710  rc = smtp_helo(conn, esmtp);
711  if (rc != 0)
712  return rc;
713  }
714 #endif
715 
716  if (conn->account.flags & MUTT_ACCT_USER)
717  {
718  if (!(Capabilities & SMTP_CAP_AUTH))
719  {
720  mutt_error(_("SMTP server does not support authentication"));
721  return -1;
722  }
723 
724  return smtp_auth(conn);
725  }
726 
727  return 0;
728 }
static int smtp_helo(struct Connection *conn, bool esmtp)
Say hello to an SMTP Server.
Definition: smtp.c:367
struct ConnAccount account
Definition: connection.h:36
#define mutt_socket_send(conn, buf)
Definition: mutt_socket.h:38
unsigned int ssf
security strength factor, in bits
Definition: connection.h:37
#define SMTP_CAP_STARTTLS
Server supports STARTTLS command.
Definition: smtp.c:80
User aborted the question (with Ctrl-G)
Definition: quad.h:37
enum QuadOption query_quadoption(enum QuadOption opt, const char *prompt)
Ask the user a quad-question.
Definition: init.c:3369
User answered &#39;Yes&#39;, or assume &#39;Yes&#39;.
Definition: quad.h:39
#define _(a)
Definition: message.h:28
WHERE bool C_SslForceTls
Config: (ssl) Require TLS encryption for all connections.
Definition: globals.h:240
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
Definition: socket.c:74
static int smtp_auth(struct Connection *conn)
Authenticate to an SMTP server.
Definition: smtp.c:586
static SmtpCapFlags Capabilities
Definition: smtp.c:90
#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:1419
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:120
#define mutt_error(...)
Definition: logging.h:88
#define SMTP_CAP_AUTH
Server supports AUTH command.
Definition: smtp.c:81
QuadOption
Possible values for a quad-option.
Definition: quad.h:35
WHERE unsigned char C_SslStarttls
Config: (ssl) Use STARTTLS on servers advertising the capability.
Definition: globals.h:195
MuttAccountFlags flags
Which fields are initialised, e.g. MUTT_ACCT_USER.
Definition: connaccount.h:39
#define MUTT_ACCT_USER
User field has been set.
Definition: mutt_account.h:61

+ 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 741 of file smtp.c.

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

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Variable Documentation

char* C_SmtpAuthenticators

Config: (smtp) List of allowed authentication methods.

Definition at line 57 of file smtp.c.

char* AuthMechs = NULL
static

Definition at line 89 of file smtp.c.

SmtpCapFlags Capabilities
static

Definition at line 90 of file smtp.c.