"Fossies" - the Fresh Open Source Software Archive

Member "msmtp-1.8.17/src/smtp.c" (26 Dec 2020, 61778 Bytes) of package /linux/privat/msmtp-1.8.17.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "smtp.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.8.14_vs_1.8.15.

    1 /*
    2  * smtp.c
    3  *
    4  * This file is part of msmtp, an SMTP client.
    5  *
    6  * Copyright (C) 2000, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
    7  * 2014, 2016, 2018, 2019, 2020
    8  * Martin Lambers <marlam@marlam.de>
    9  *
   10  *   This program is free software; you can redistribute it and/or modify
   11  *   it under the terms of the GNU General Public License as published by
   12  *   the Free Software Foundation; either version 3 of the License, or
   13  *   (at your option) any later version.
   14  *
   15  *   This program is distributed in the hope that it will be useful,
   16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18  *   GNU General Public License for more details.
   19  *
   20  *   You should have received a copy of the GNU General Public License
   21  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
   22  */
   23 
   24 #ifdef HAVE_CONFIG_H
   25 # include "config.h"
   26 #endif
   27 
   28 #include <stdio.h>
   29 #include <stdlib.h>
   30 #include <limits.h>
   31 #include <stdarg.h>
   32 #include <string.h>
   33 #include <strings.h>
   34 #include <ctype.h>
   35 #include <errno.h>
   36 
   37 #ifdef HAVE_LIBGSASL
   38 # include <gsasl.h>
   39 #else
   40 # include "md5-apps.h"
   41 #endif
   42 #include "base64.h"
   43 
   44 #include "gettext.h"
   45 #define _(string) gettext(string)
   46 
   47 #include "xalloc.h"
   48 #include "list.h"
   49 #include "readbuf.h"
   50 #include "tools.h"
   51 #include "net.h"
   52 #include "smtp.h"
   53 #include "stream.h"
   54 #ifdef HAVE_TLS
   55 #include "mtls.h"
   56 #endif /* HAVE_TLS */
   57 
   58 
   59 /* This defines the maximum number of lines in a multiline server reply.
   60  * This limit exists to prevent an extremely long reply from eating
   61  * all the memory.
   62  * The longest server reply we have to expect is the repsonse to the EHLO
   63  * command. We should have enough lines for every SMTP extension known today
   64  * plus more lines for future extensions.
   65  */
   66 #define SMTP_MAXLINES 50
   67 
   68 /* This defines the length of the *input* buffer for SMTP messages.
   69  * According to RFC 2821, SMTP commands and SMTP messages may contain
   70  * at most 512 characters including CRLF, thus the *minimum* size is
   71  * 512 characters.
   72  */
   73 #define SMTP_BUFSIZE 1024
   74 
   75 /* This defines the length of the *output* buffer for SMTP commands, without
   76  * CRLF. According to RFC 2821, SMTP commands may contain at most 512
   77  * characters including CRLF, thus the maximum size should be 510 characters.
   78  * But this is not sufficient for some authentication mechanisms, notably
   79  * GSSAPI, so this value must be higher.
   80  */
   81 #define SMTP_MAXCMDLEN 4094
   82 
   83 /* The maximum length of the SMTP command pipeline (the maximum number of
   84  * commands that are sent at once, before starting to read the replies). This
   85  * number should be large enough to keep the benefits of pipelining (saved round
   86  * trips), and small enough to avoid problems (exceeding the TCP window size).
   87  * A value of 1 disables pipelining.
   88  */
   89 #define SMTP_PIPELINE_LIMIT 100
   90 
   91 /* This is the buffer length for copying the mail to the SMTP server.
   92  * According to RFC 2822, a line in a mail can contain at most 998
   93  * characters + CRLF. Plus one character for '\0' = 1001 characters.
   94  * All lines should fit in a buffer of this size.
   95  * However, this length is not a limit; smtp_send_mail() will accept
   96  * arbitrary long lines.
   97  */
   98 #define MAIL_BUFSIZE 1024
   99 
  100 
  101 /*
  102  * smtp_new()
  103  *
  104  * see smtp.h
  105  */
  106 
  107 smtp_server_t smtp_new(FILE *debug, int protocol)
  108 {
  109     smtp_server_t srv;
  110 
  111     srv.fd = -1;
  112 #ifdef HAVE_TLS
  113     mtls_clear(&srv.mtls);
  114 #endif /* HAVE_TLS */
  115     readbuf_init(&(srv.readbuf));
  116     srv.protocol = protocol;
  117     srv.cap.flags = 0;
  118     srv.cap.size = 0;
  119     srv.debug = debug;
  120     return srv;
  121 }
  122 
  123 
  124 /*
  125  * smtp_connect()
  126  *
  127  * see smtp.h
  128  */
  129 
  130 int smtp_connect(smtp_server_t *srv,
  131         const char *socketname,
  132         const char *proxy_host, int proxy_port,
  133         const char *host, int port, const char *source_ip, int timeout,
  134         char **server_canonical_name, char **server_address,
  135         char **errstr)
  136 {
  137     return net_open_socket(socketname, proxy_host, proxy_port, host, port,
  138             source_ip, timeout, &srv->fd,
  139             server_canonical_name, server_address, errstr);
  140 }
  141 
  142 
  143 /*
  144  * smtp_get_msg()
  145  *
  146  * This function gets a message from the SMTP server 'srv'.
  147  * In case of success, 'msg' will contain a pointer to a newly created list,
  148  * and each member of this list will contain one line of the message as an
  149  * allocated string. The list will contain at least one line. Each line will
  150  * be at least 4 characters long: The three digit status code plus a ' ' or '-'.
  151  * Each line will be at most SMTP_BUFSIZE characters long, including '\0'.
  152  * The return code will be EOK.
  153  * In case of failure, 'msg' will be NULL, and one of the following error codes
  154  * will be returned: SMTP_EIO, SMTP_EPROTO
  155  */
  156 
  157 int smtp_get_msg(smtp_server_t *srv, list_t **msg, char **errstr)
  158 {
  159     list_t *l;
  160     list_t *lp;
  161     char line[SMTP_BUFSIZE];
  162     int counter;
  163     size_t len;
  164 
  165     *msg = NULL;
  166     l = list_new();
  167     lp = l;
  168 
  169     counter = 0;
  170     do
  171     {
  172 #ifdef HAVE_TLS
  173         if (mtls_is_active(&srv->mtls))
  174         {
  175             if (mtls_gets(&srv->mtls, &(srv->readbuf),
  176                         line, SMTP_BUFSIZE, &len, errstr) != TLS_EOK)
  177             {
  178                 list_xfree(l, free);
  179                 return SMTP_EIO;
  180             }
  181         }
  182         else
  183         {
  184 #endif /* HAVE_TLS */
  185             if (net_gets(srv->fd, &(srv->readbuf),
  186                         line, SMTP_BUFSIZE, &len, errstr) != NET_EOK)
  187             {
  188                 list_xfree(l, free);
  189                 return SMTP_EIO;
  190             }
  191 #ifdef HAVE_TLS
  192         }
  193 #endif /* HAVE_TLS */
  194         if (len < 4
  195                 || !(isdigit((unsigned char)line[0])
  196                     && isdigit((unsigned char)line[1])
  197                     && isdigit((unsigned char)line[2])
  198                     && (line[3] == ' ' || line[3] == '-'))
  199                 || line[len - 1] != '\n')
  200         {
  201             list_xfree(l, free);
  202             /* The string is not necessarily a reply (it may be the initial OK
  203              * message), but this is the term used in the RFCs.
  204              * An empty reply is a special case of an invalid reply - this
  205              * differentiation may help the user. */
  206             if (counter == 0 && len == 0)
  207             {
  208                 *errstr = xasprintf(_("the server sent an empty reply"));
  209             }
  210             else
  211             {
  212                 *errstr = xasprintf(_("the server sent an invalid reply"));
  213             }
  214             return SMTP_EPROTO;
  215         }
  216         if (srv->debug)
  217         {
  218             fputs("<-- ", srv->debug);
  219             fwrite(line, sizeof(char), len, srv->debug);
  220         }
  221         /* kill CRLF */
  222         line[--len] = '\0';
  223         if (line[len - 1] == '\r')
  224         {
  225             line[--len] = '\0';
  226         }
  227         list_insert(lp, xstrdup(line));
  228         counter++;
  229         lp = lp->next;
  230     }
  231     while (line[3] == '-' && counter <= SMTP_MAXLINES);
  232 
  233     if (counter > SMTP_MAXLINES)
  234     {
  235         list_xfree(l, free);
  236         *errstr = xasprintf(_("Rejecting server reply that is longer "
  237                     "than %d lines. Increase SMTP_MAXLINES."), SMTP_MAXLINES);
  238         return SMTP_EPROTO;
  239     }
  240 
  241     *msg = l;
  242     return SMTP_EOK;
  243 }
  244 
  245 
  246 /*
  247  * smtp_msg_status()
  248  *
  249  * see smtp.h
  250  */
  251 
  252 int smtp_msg_status(list_t *msg)
  253 {
  254     /* we know that *msg is valid; there's no need to check for errors */
  255     return atoi(msg->next->data);
  256 }
  257 
  258 
  259 /*
  260  * smtp_put()
  261  *
  262  * This function writes 'len' characters from 's' to the SMTP server 'srv'.
  263  * Used error codes: SMTP_EIO
  264  */
  265 
  266 int smtp_put(smtp_server_t *srv, const char *s, size_t len, char **errstr)
  267 {
  268     int e = 0;
  269 
  270 #ifdef HAVE_TLS
  271     if (mtls_is_active(&srv->mtls))
  272     {
  273         e = (mtls_puts(&srv->mtls, s, len, errstr) != TLS_EOK);
  274     }
  275     else
  276     {
  277 #endif /* HAVE_TLS */
  278         e = (net_puts(srv->fd, s, len, errstr) != NET_EOK);
  279 #ifdef HAVE_TLS
  280     }
  281 #endif /* HAVE_TLS */
  282     if (e)
  283     {
  284         return SMTP_EIO;
  285     }
  286     if (srv->debug)
  287     {
  288         fputs("--> ", srv->debug);
  289         fwrite(s, sizeof(char), len, srv->debug);
  290     }
  291 
  292     return SMTP_EOK;
  293 }
  294 
  295 
  296 /*
  297  * smtp_send_cmd()
  298  *
  299  * This function writes a string to the SMTP server 'srv'. The string may not
  300  * be longer than SMTP_MAXCMDLEN characters (see above). TCP CRLF ('\r\n') will
  301  * be appended to the string. Use this function to send SMTP commands (not mail
  302  * data) to the SMTP server.
  303  * Used error codes: SMTP_EIO, SMTP_EINVAL
  304  */
  305 
  306 /* make gcc print format warnings for this function */
  307 #ifdef __GNUC__
  308 int smtp_send_cmd(smtp_server_t *srv, char **errstr, const char *format, ...)
  309     __attribute__ ((format (printf, 3, 4)));
  310 #endif
  311 
  312 int smtp_send_cmd(smtp_server_t *srv, char **errstr, const char *format, ...)
  313 {
  314     char line[SMTP_MAXCMDLEN + 3];
  315     int count;
  316     va_list args;
  317 
  318     va_start(args, format);
  319     count = vsnprintf(line, SMTP_MAXCMDLEN + 1, format, args);
  320     va_end(args);
  321     if (count >= SMTP_MAXCMDLEN + 1)
  322     {
  323         *errstr = xasprintf(_("Cannot send command because it is "
  324                 "longer than %d characters. Increase SMTP_MAXCMDLEN."),
  325                 SMTP_MAXCMDLEN);
  326         return SMTP_EINVAL;
  327     }
  328     line[count++] = '\r';
  329     line[count++] = '\n';
  330     line[count] = '\0';
  331     return smtp_put(srv, line, (size_t)count, errstr);
  332 }
  333 
  334 
  335 /*
  336  * smtp_get_greeting()
  337  *
  338  * see smtp.h
  339  */
  340 
  341 int smtp_get_greeting(smtp_server_t *srv, list_t **errmsg, char **buf,
  342         char **errstr)
  343 {
  344     int e;
  345     list_t *msg;
  346 
  347     *errmsg = NULL;
  348     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  349     {
  350         return e;
  351     }
  352     if (smtp_msg_status(msg) != 220)
  353     {
  354         *errmsg = msg;
  355         *errstr = xasprintf(_("cannot get initial OK message from server"));
  356         return SMTP_EPROTO;
  357     }
  358     if (buf)
  359     {
  360         *buf = xmalloc(
  361                 (strlen((char *)msg->next->data + 4) + 1) * sizeof(char));
  362         strcpy(*buf, (char *)(msg->next->data) + 4);
  363     }
  364     list_xfree(msg, free);
  365 
  366     return SMTP_EOK;
  367 }
  368 
  369 
  370 /*
  371  * smtp_init()
  372  *
  373  * see smtp.h
  374  */
  375 
  376 int smtp_init(smtp_server_t *srv, const char *ehlo_domain, list_t **errmsg,
  377         char **errstr)
  378 {
  379     int e;
  380     list_t *ehlo_response;
  381     list_t *lp;
  382     char *s;
  383     char *p;
  384     size_t len;
  385     int i;
  386 
  387     srv->cap.flags = 0;
  388 
  389     *errmsg = NULL;
  390     if (srv->protocol == SMTP_PROTO_SMTP)
  391     {
  392         if ((e = smtp_send_cmd(srv, errstr, "EHLO %s", ehlo_domain))
  393                 != SMTP_EOK)
  394         {
  395             return e;
  396         }
  397         if ((e = smtp_get_msg(srv, &ehlo_response, errstr)) != SMTP_EOK)
  398         {
  399             return e;
  400         }
  401         if (smtp_msg_status(ehlo_response) != 250)
  402         {
  403             /* fall back to HELO, for very old SMTP servers */
  404             list_xfree(ehlo_response, free);
  405             if ((e = smtp_send_cmd(srv, errstr, "HELO %s", ehlo_domain))
  406                     != SMTP_EOK)
  407             {
  408                 return e;
  409             }
  410             if ((e = smtp_get_msg(srv, &ehlo_response, errstr)) != SMTP_EOK)
  411             {
  412                 return e;
  413             }
  414             if (smtp_msg_status(ehlo_response) != 250)
  415             {
  416                 *errmsg = ehlo_response;
  417                 *errstr = xasprintf(_("SMTP server does not accept "
  418                             "EHLO or HELO commands"));
  419                 return SMTP_EPROTO;
  420             }
  421             list_xfree(ehlo_response, free);
  422             /* srv->cap.flags is 0 */
  423             return SMTP_EOK;
  424         }
  425     }
  426     else /* protocol is LMTP */
  427     {
  428         if ((e = smtp_send_cmd(srv, errstr, "LHLO %s", ehlo_domain))
  429                 != SMTP_EOK)
  430         {
  431             return e;
  432         }
  433         if ((e = smtp_get_msg(srv, &ehlo_response, errstr)) != SMTP_EOK)
  434         {
  435             return e;
  436         }
  437         if (smtp_msg_status(ehlo_response) != 250)
  438         {
  439             *errmsg = ehlo_response;
  440             *errstr = xasprintf(_("command %s failed"), "LHLO");
  441             return SMTP_EPROTO;
  442         }
  443     }
  444 
  445     lp = ehlo_response;
  446     while (!list_is_empty(lp))
  447     {
  448         lp = lp->next;
  449         s = lp->data;
  450         len = strlen(s);
  451         /* we know that len is >= 4 */
  452         /* make line uppercase */
  453         for (i = 4; (size_t)i < len; i++)
  454         {
  455             s[i] = toupper((unsigned char)s[i]);
  456         }
  457         /* search capabilities */
  458         if (strncmp(s + 4, "STARTTLS", 8) == 0)
  459         {
  460             srv->cap.flags |= SMTP_CAP_STARTTLS;
  461         }
  462         else if (strncmp(s + 4, "DSN", 3) == 0)
  463         {
  464             srv->cap.flags |= SMTP_CAP_DSN;
  465         }
  466         else if (strncmp(s + 4, "PIPELINING", 10) == 0)
  467         {
  468             srv->cap.flags |= SMTP_CAP_PIPELINING;
  469         }
  470         else if (strncmp(s + 4, "SIZE", 4) == 0)
  471         {
  472             /* If there's no number after the SIZE keyword, the server does not
  473              * tell us about a maximum message size. Treat that as if the SIZE
  474              * keyword was not seen. Also treat invalid numbers the same way.
  475              * The value 0 means there is no maximum.
  476              * See RFC 1653. */
  477             errno = 0;
  478             srv->cap.size = strtol(s + 8, &p, 10);
  479             if (!(*(s + 8) == '\0' || *p != '\0' || srv->cap.size < 0
  480                     || (srv->cap.size == LONG_MAX && errno == ERANGE)))
  481             {
  482                 srv->cap.flags |= SMTP_CAP_SIZE;
  483             }
  484         }
  485         /* Accept "AUTH " as well as "AUTH=". There are still some broken
  486          * servers that use "AUTH=". */
  487         else if (strncmp(s + 4, "AUTH", 4) == 0
  488                 && (*(s + 8) == ' ' || *(s + 8) == '='))
  489         {
  490             srv->cap.flags |= SMTP_CAP_AUTH;
  491             if (strstr(s + 9, "PLAIN"))
  492             {
  493                 srv->cap.flags |= SMTP_CAP_AUTH_PLAIN;
  494             }
  495             if (strstr(s + 9, "CRAM-MD5"))
  496             {
  497                 srv->cap.flags |= SMTP_CAP_AUTH_CRAM_MD5;
  498             }
  499             if (strstr(s + 9, "DIGEST-MD5"))
  500             {
  501                 srv->cap.flags |= SMTP_CAP_AUTH_DIGEST_MD5;
  502             }
  503             if (strstr(s + 9, "SCRAM-SHA-1"))
  504             {
  505                 srv->cap.flags |= SMTP_CAP_AUTH_SCRAM_SHA_1;
  506             }
  507             if (strstr(s + 9, "SCRAM-SHA-256"))
  508             {
  509                 srv->cap.flags |= SMTP_CAP_AUTH_SCRAM_SHA_256;
  510             }
  511             if (strstr(s + 9, "GSSAPI"))
  512             {
  513                 srv->cap.flags |= SMTP_CAP_AUTH_GSSAPI;
  514             }
  515             if (strstr(s + 9, "EXTERNAL"))
  516             {
  517                 srv->cap.flags |= SMTP_CAP_AUTH_EXTERNAL;
  518             }
  519             if (strstr(s + 9, "LOGIN"))
  520             {
  521                 srv->cap.flags |= SMTP_CAP_AUTH_LOGIN;
  522             }
  523             if (strstr(s + 9, "NTLM"))
  524             {
  525                 srv->cap.flags |= SMTP_CAP_AUTH_NTLM;
  526             }
  527             if (strstr(s + 9, "OAUTHBEARER"))
  528             {
  529                 srv->cap.flags |= SMTP_CAP_AUTH_OAUTHBEARER;
  530             }
  531             if (strstr(s + 9, "XOAUTH2"))
  532             {
  533                 srv->cap.flags |= SMTP_CAP_AUTH_XOAUTH2;
  534             }
  535         }
  536         else if (strncmp(s + 4, "ETRN", 4) == 0)
  537         {
  538             srv->cap.flags |= SMTP_CAP_ETRN;
  539         }
  540     }
  541 
  542     list_xfree(ehlo_response, free);
  543     return SMTP_EOK;
  544 }
  545 
  546 
  547 /*
  548  * smtp_tls_init()
  549  *
  550  * see smtp.h
  551  */
  552 
  553 #ifdef HAVE_TLS
  554 int smtp_tls_init(smtp_server_t *srv,
  555         const char *tls_key_file, const char *tls_cert_file, const char *pin,
  556         const char *tls_trust_file, const char *tls_crl_file,
  557         const unsigned char *tls_sha256_fingerprint,
  558         const unsigned char *tls_sha1_fingerprint,
  559         const unsigned char *tls_md5_fingerprint,
  560         int min_dh_prime_bits,
  561         const char *priorities,
  562         const char *hostname,
  563         int no_certcheck,
  564         char **errstr)
  565 {
  566     return mtls_init(&srv->mtls, tls_key_file, tls_cert_file, pin,
  567             tls_trust_file, tls_crl_file,
  568             tls_sha256_fingerprint, tls_sha1_fingerprint, tls_md5_fingerprint,
  569             min_dh_prime_bits, priorities, hostname, no_certcheck, errstr);
  570 }
  571 #endif /* HAVE_TLS */
  572 
  573 
  574 /*
  575  * smtp_tls_starttls()
  576  *
  577  * see smtp.h
  578  */
  579 
  580 #ifdef HAVE_TLS
  581 int smtp_tls_starttls(smtp_server_t *srv, list_t **error_msg, char **errstr)
  582 {
  583     int e;
  584     list_t *msg;
  585 
  586     *error_msg = NULL;
  587     if ((e = smtp_send_cmd(srv, errstr, "STARTTLS")) != SMTP_EOK)
  588     {
  589         return e;
  590     }
  591     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  592     {
  593         return e;
  594     }
  595     if (smtp_msg_status(msg) != 220)
  596     {
  597         *error_msg = msg;
  598         *errstr = xasprintf(_("command %s failed"), "STARTTLS");
  599         return SMTP_EPROTO;
  600     }
  601     if (!readbuf_is_empty(&(srv->readbuf)))
  602     {
  603         *errstr = xasprintf(_("command %s failed"), "STARTTLS");
  604         return SMTP_EPROTO;
  605     }
  606     list_xfree(msg, free);
  607     return SMTP_EOK;
  608 }
  609 #endif /* HAVE_TLS */
  610 
  611 
  612 /*
  613  * smtp_tls()
  614  *
  615  * see smtp.h
  616  */
  617 
  618 #ifdef HAVE_TLS
  619 int smtp_tls(smtp_server_t *srv,
  620         mtls_cert_info_t *tci, char **mtls_parameter_description, char **errstr)
  621 {
  622     return mtls_start(&srv->mtls, srv->fd, tci,
  623             mtls_parameter_description, errstr);
  624 }
  625 #endif /* HAVE_TLS */
  626 
  627 
  628 /*
  629  * smtp_auth_plain()
  630  *
  631  * Do SMTP authentication via AUTH PLAIN.
  632  * The SMTP server must support SMTP_CAP_AUTH_PLAIN
  633  * Used error codes: SMTP_EIO, SMTP_EPROTO, SMTP_EAUTHFAIL, SMTP_EINVAL
  634  */
  635 
  636 #ifndef HAVE_LIBGSASL
  637 int smtp_auth_plain(smtp_server_t *srv, const char *user, const char *password,
  638         list_t **error_msg, char **errstr)
  639 {
  640     char *s;
  641     char *b64;
  642     size_t u_len;
  643     size_t p_len;
  644     size_t b64_len;
  645     list_t *msg;
  646     int e;
  647     int status;
  648 
  649     *error_msg = NULL;
  650     u_len = strlen(user);
  651     p_len = strlen(password);
  652     s = xmalloc((u_len + p_len + 3) * sizeof(char));
  653     s[0] = '\0';
  654     strcpy(s + 1, user);
  655     strcpy(s + u_len + 2, password);
  656     b64_len = BASE64_LENGTH(u_len + p_len + 2);
  657     b64 = xmalloc(b64_len + 1);
  658     base64_encode(s, u_len + p_len + 2, b64, b64_len + 1);
  659     free(s);
  660 
  661     if ((e = smtp_send_cmd(srv, errstr, "AUTH PLAIN %s", b64)) != SMTP_EOK)
  662     {
  663         free(b64);
  664         return e;
  665     }
  666     free(b64);
  667     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  668     {
  669         return e;
  670     }
  671     if ((status = smtp_msg_status(msg)) != 235)
  672     {
  673         *error_msg = msg;
  674         if (status == 504)
  675         {
  676             *errstr = xasprintf(_("command %s failed"), "AUTH PLAIN");
  677             return SMTP_EPROTO;
  678         }
  679         else
  680         {
  681             *errstr = xasprintf(_("authentication failed (method %s)"),
  682                     "PLAIN");
  683             return SMTP_EAUTHFAIL;
  684         }
  685     }
  686     list_xfree(msg, free);
  687 
  688     return SMTP_EOK;
  689 }
  690 #endif /* !HAVE_LIBGSASL */
  691 
  692 
  693 /*
  694  * smtp_auth_login()
  695  *
  696  * Do SMTP authentication via AUTH LOGIN.
  697  * The SMTP server must support SMTP_CAP_AUTH_LOGIN
  698  * Used error codes: SMTP_EIO, SMTP_EPROTO, SMTP_EAUTHFAIL, SMTP_EINVAL
  699  */
  700 
  701 #ifndef HAVE_LIBGSASL
  702 int smtp_auth_login(smtp_server_t *srv, const char *user, const char *password,
  703         list_t **error_msg, char **errstr)
  704 {
  705     int e;
  706     list_t *msg;
  707     char *b64;
  708     size_t b64_len;
  709     size_t u_len;
  710     size_t p_len;
  711 
  712     *error_msg = NULL;
  713     if ((e = smtp_send_cmd(srv, errstr, "AUTH LOGIN")) != SMTP_EOK)
  714     {
  715         return e;
  716     }
  717     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  718     {
  719         return e;
  720     }
  721     if (smtp_msg_status(msg) != 334)
  722     {
  723         *error_msg = msg;
  724         *errstr = xasprintf(_("command %s failed"), "AUTH LOGIN");
  725         return SMTP_EPROTO;
  726     }
  727     list_xfree(msg, free);
  728     u_len = strlen(user);
  729     b64_len = BASE64_LENGTH(u_len);
  730     b64 = xmalloc(b64_len + 1);
  731     base64_encode(user, u_len, b64, b64_len + 1);
  732     if ((e = smtp_send_cmd(srv, errstr, "%s", b64)) != SMTP_EOK)
  733     {
  734         free(b64);
  735         return e;
  736     }
  737     free(b64);
  738     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  739     {
  740         return e;
  741     }
  742     if (smtp_msg_status(msg) != 334)
  743     {
  744         *error_msg = msg;
  745         *errstr = xasprintf(_("authentication failed (method %s)"), "LOGIN");
  746         return SMTP_EAUTHFAIL;
  747     }
  748     list_xfree(msg, free);
  749     p_len = strlen(password);
  750     b64_len = BASE64_LENGTH(p_len);
  751     b64 = xmalloc(b64_len + 1);
  752     base64_encode(password, p_len, b64, b64_len + 1);
  753     if ((e = smtp_send_cmd(srv, errstr, "%s", b64)) != SMTP_EOK)
  754     {
  755         free(b64);
  756         return e;
  757     }
  758     free(b64);
  759     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  760     {
  761         return e;
  762     }
  763     if (smtp_msg_status(msg) != 235)
  764     {
  765         *error_msg = msg;
  766         *errstr = xasprintf(_("authentication failed (method %s)"), "LOGIN");
  767         return SMTP_EAUTHFAIL;
  768     }
  769     list_xfree(msg, free);
  770 
  771     return SMTP_EOK;
  772 }
  773 #endif /* !HAVE_LIBGSASL */
  774 
  775 
  776 /*
  777  * smtp_auth_cram_md5()
  778  *
  779  * Do SMTP authentication via AUTH CRAM-MD5.
  780  * The SMTP server must support SMTP_CAP_AUTH_CRAM_MD5
  781  * Used error codes: SMTP_EIO, SMTP_EPROTO, SMTP_EAUTHFAIL, SMTP_EINVAL
  782  */
  783 
  784 #ifndef HAVE_LIBGSASL
  785 int smtp_auth_cram_md5(smtp_server_t *srv, const char *user,
  786         const char *password,
  787         list_t **error_msg, char **errstr)
  788 {
  789     unsigned char digest[16];
  790     char hex[] = "0123456789abcdef";
  791     char *challenge;
  792     size_t challenge_len;
  793     char *b64;
  794     size_t b64_len;
  795     char *buf;
  796     char *p;
  797     size_t len;
  798     int i;
  799     list_t *msg;
  800     int e;
  801 
  802     *error_msg = NULL;
  803     if ((e = smtp_send_cmd(srv, errstr, "AUTH CRAM-MD5")) != SMTP_EOK)
  804     {
  805         return e;
  806     }
  807     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  808     {
  809         return e;
  810     }
  811     if (smtp_msg_status(msg) != 334)
  812     {
  813         *error_msg = msg;
  814         *errstr = xasprintf(_("command %s failed"), "AUTH CRAM-MD5");
  815         return SMTP_EPROTO;
  816     }
  817     /* we know the line is at least 4 characters long */
  818     challenge = (char *)(msg->next->data) + 4;
  819     challenge_len = strlen(challenge);
  820     len = 3 * (challenge_len / 4) + 2;
  821     b64 = xmalloc(len);
  822     if (!base64_decode(challenge, challenge_len, b64, &len))
  823     {
  824         list_xfree(msg, free);
  825         *errstr = xasprintf(_("authentication method CRAM-MD5: "
  826                     "server sent invalid challenge"));
  827         return SMTP_EPROTO;
  828     }
  829     list_xfree(msg, free);
  830     md5_hmac(password, strlen(password), b64, len, digest);
  831     free(b64);
  832 
  833     /* construct username + ' ' + digest_in_hex */
  834     len = strlen(user);
  835     buf = xmalloc((len + 1 + 32 + 1) * sizeof(char));
  836     strcpy(buf, user);
  837     p = buf + len;
  838     *p++ = ' ';
  839     for (i = 0; i < 16; i++)
  840     {
  841         p[2 * i] = hex[(digest[i] & 0xf0) >> 4];
  842         p[2 * i + 1] = hex[digest[i] & 0x0f];
  843     }
  844     p[32] = '\0';
  845 
  846     b64_len = BASE64_LENGTH(len + 33);
  847     b64 = xmalloc(b64_len + 1);
  848     base64_encode(buf, len + 33, b64, b64_len + 1);
  849     free(buf);
  850     if ((e = smtp_send_cmd(srv, errstr, "%s", b64)) != SMTP_EOK)
  851     {
  852         free(b64);
  853         return e;
  854     }
  855     free(b64);
  856     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  857     {
  858         return e;
  859     }
  860     if (smtp_msg_status(msg) != 235)
  861     {
  862         *error_msg = msg;
  863         *errstr = xasprintf(_("authentication failed (method %s)"), "CRAM-MD5");
  864         return SMTP_EAUTHFAIL;
  865     }
  866     list_xfree(msg, free);
  867 
  868     return SMTP_EOK;
  869 }
  870 #endif /* !HAVE_LIBGSASL */
  871 
  872 
  873 /*
  874  * smtp_auth_external()
  875  *
  876  * Do SMTP authentication via AUTH EXTERNAL.
  877  * This means the actual authentication is done via TLS; we just send the user
  878  * name to ther server.
  879  * The SMTP server must support SMTP_CAP_AUTH_EXTERNAL
  880  * Used error codes: SMTP_EIO, SMTP_EPROTO, SMTP_EAUTHFAIL, SMTP_EINVAL
  881  */
  882 
  883 #ifndef HAVE_LIBGSASL
  884 int smtp_auth_external(smtp_server_t *srv, const char *user,
  885         list_t **error_msg, char **errstr)
  886 {
  887     size_t u_len;
  888     size_t b64_len;
  889     char *b64;
  890     list_t *msg;
  891     int e;
  892 
  893     *error_msg = NULL;
  894     if ((e = smtp_send_cmd(srv, errstr, "AUTH EXTERNAL")) != SMTP_EOK)
  895     {
  896         return e;
  897     }
  898     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  899     {
  900         return e;
  901     }
  902     if (smtp_msg_status(msg) != 334)
  903     {
  904         *error_msg = msg;
  905         *errstr = xasprintf(_("command %s failed"), "AUTH EXTERNAL");
  906         return SMTP_EPROTO;
  907     }
  908     list_xfree(msg, free);
  909     u_len = strlen(user);
  910     b64_len = BASE64_LENGTH(u_len);
  911     b64 = xmalloc(b64_len + 1);
  912     base64_encode(user, u_len, b64, b64_len + 1);
  913     if ((e = smtp_send_cmd(srv, errstr, "%s", b64)) != SMTP_EOK)
  914     {
  915         free(b64);
  916         return e;
  917     }
  918     free(b64);
  919     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  920     {
  921         return e;
  922     }
  923     if (smtp_msg_status(msg) != 235)
  924     {
  925         *error_msg = msg;
  926         *errstr = xasprintf(_("authentication failed (method %s)"), "EXTERNAL");
  927         return SMTP_EAUTHFAIL;
  928     }
  929     list_xfree(msg, free);
  930 
  931     return SMTP_EOK;
  932 }
  933 #endif /* !HAVE_LIBGSASL */
  934 
  935 
  936 /*
  937  * smtp_auth_oauthbearer()
  938  *
  939  * Do SMTP authentication via AUTH OAUTHBEARER.
  940  * The SMTP server must support SMTP_CAP_AUTH_OAUTHBEARER
  941  * Used error codes: SMTP_EIO, SMTP_EAUTHFAIL, SMTP_EINVAL
  942  */
  943 
  944 int smtp_auth_oauthbearer(smtp_server_t *srv,
  945         const char *hostname, unsigned short port,
  946         const char *user, const char *token,
  947         list_t **error_msg, char **errstr)
  948 {
  949     list_t *msg;
  950     char *oauth;
  951     size_t oa_len;
  952     char *b64;
  953     size_t b64_len;
  954     int e;
  955     int status;
  956 
  957     *error_msg = NULL;
  958 
  959     oa_len = 4 + /* "n,a=" */
  960              strlen(user) +
  961              7 + /* ",^Ahost=" */
  962              strlen(hostname) +
  963              6 + 5 + /* "^Aport=" + up to 5 digits */
  964              13 + /* "^Aauth=Bearer " */
  965              strlen(token) +
  966              2 /* "^A^A" */;
  967     oauth = xmalloc(oa_len + 1);
  968     oa_len = snprintf(oauth, oa_len + 1,
  969                       "n,a=%s,\001host=%s\001port=%d\001auth=Bearer %s\001\001",
  970                       user, hostname, port, token);
  971     b64_len = BASE64_LENGTH(oa_len) + 1;
  972     b64 = xmalloc(b64_len);
  973     base64_encode(oauth, oa_len, b64, b64_len);
  974     e = smtp_send_cmd(srv, errstr, "AUTH OAUTHBEARER %s", b64);
  975     free(oauth);
  976     free(b64);
  977     if (e != SMTP_EOK)
  978     {
  979         return e;
  980     }
  981     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  982     {
  983         return e;
  984     }
  985     if ((status = smtp_msg_status(msg)) != 235)
  986     {
  987         if (status == 334)
  988         {
  989             list_xfree(msg, free);
  990             if ((e = smtp_send_cmd(srv, errstr, "")) != SMTP_EOK)
  991             {
  992                 return e;
  993             }
  994             if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
  995             {
  996                 return e;
  997             }
  998         }
  999         *error_msg = msg;
 1000         *errstr = xasprintf(_("authentication failed (method %s)"), "OAUTHBEARER");
 1001         return SMTP_EAUTHFAIL;
 1002     }
 1003     list_xfree(msg, free);
 1004 
 1005     return SMTP_EOK;
 1006 }
 1007 
 1008 
 1009 /*
 1010  * smtp_auth_xoauth2()
 1011  *
 1012  * Do SMTP authentication via AUTH XOAUTH2.
 1013  * The SMTP server must support SMTP_CAP_AUTH_XOAUTH2
 1014  * Used error codes: SMTP_EIO, SMTP_EAUTHFAIL, SMTP_EINVAL
 1015  */
 1016 
 1017 int smtp_auth_xoauth2(smtp_server_t *srv,
 1018         const char *user, const char *token,
 1019         list_t **error_msg, char **errstr)
 1020 {
 1021     list_t *msg;
 1022     char *oauth;
 1023     size_t oa_len;
 1024     char *b64;
 1025     size_t b64_len;
 1026     int e;
 1027     int status;
 1028 
 1029     *error_msg = NULL;
 1030 
 1031     oa_len = 5 + /* "user=" */
 1032              strlen(user) +
 1033              13 + /* "^Aauth=Bearer " */
 1034              strlen(token) +
 1035              2 /* "^A^A" */;
 1036     oauth = xmalloc(oa_len + 1);
 1037     oa_len = snprintf(oauth, oa_len + 1,
 1038             "user=%s\001auth=Bearer %s\001\001", user, token);
 1039     b64_len = BASE64_LENGTH(oa_len) + 1;
 1040     b64 = xmalloc(b64_len);
 1041     base64_encode(oauth, oa_len, b64, b64_len);
 1042     e = smtp_send_cmd(srv, errstr, "AUTH XOAUTH2 %s", b64);
 1043     free(oauth);
 1044     free(b64);
 1045     if (e != SMTP_EOK)
 1046     {
 1047         return e;
 1048     }
 1049     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 1050     {
 1051         return e;
 1052     }
 1053     if ((status = smtp_msg_status(msg)) != 235)
 1054     {
 1055         if (status == 334)
 1056         {
 1057             list_xfree(msg, free);
 1058             if ((e = smtp_send_cmd(srv, errstr, "")) != SMTP_EOK)
 1059             {
 1060                 return e;
 1061             }
 1062             if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 1063             {
 1064                 return e;
 1065             }
 1066         }
 1067         *error_msg = msg;
 1068         *errstr = xasprintf(_("authentication failed (method %s)"), "XOAUTH2");
 1069         return SMTP_EAUTHFAIL;
 1070     }
 1071     list_xfree(msg, free);
 1072 
 1073     return SMTP_EOK;
 1074 }
 1075 
 1076 
 1077 /*
 1078  * smtp_server_supports_authmech()
 1079  *
 1080  * see smtp.h
 1081  */
 1082 
 1083 int smtp_server_supports_authmech(smtp_server_t *srv, const char *mech)
 1084 {
 1085     return (((srv->cap.flags & SMTP_CAP_AUTH_PLAIN)
 1086                 && strcmp(mech, "PLAIN") == 0)
 1087             || ((srv->cap.flags & SMTP_CAP_AUTH_CRAM_MD5)
 1088                 && strcmp(mech, "CRAM-MD5") == 0)
 1089             || ((srv->cap.flags & SMTP_CAP_AUTH_DIGEST_MD5)
 1090                 && strcmp(mech, "DIGEST-MD5") == 0)
 1091             || ((srv->cap.flags & SMTP_CAP_AUTH_SCRAM_SHA_1)
 1092                 && strcmp(mech, "SCRAM-SHA-1") == 0)
 1093             || ((srv->cap.flags & SMTP_CAP_AUTH_SCRAM_SHA_256)
 1094                 && strcmp(mech, "SCRAM-SHA-256") == 0)
 1095             || ((srv->cap.flags & SMTP_CAP_AUTH_EXTERNAL)
 1096                 && strcmp(mech, "EXTERNAL") == 0)
 1097             || ((srv->cap.flags & SMTP_CAP_AUTH_GSSAPI)
 1098                 && strcmp(mech, "GSSAPI") == 0)
 1099             || ((srv->cap.flags & SMTP_CAP_AUTH_LOGIN)
 1100                 && strcmp(mech, "LOGIN") == 0)
 1101             || ((srv->cap.flags & SMTP_CAP_AUTH_NTLM)
 1102                 && strcmp(mech, "NTLM") == 0)
 1103             || ((srv->cap.flags & SMTP_CAP_AUTH_OAUTHBEARER)
 1104                 && strcmp(mech, "OAUTHBEARER") == 0)
 1105             || ((srv->cap.flags & SMTP_CAP_AUTH_XOAUTH2)
 1106                 && strcmp(mech, "XOAUTH2") == 0));
 1107 }
 1108 
 1109 
 1110 /*
 1111  * smtp_client_supports_authmech()
 1112  *
 1113  * see smtp.h
 1114  */
 1115 
 1116 int smtp_client_supports_authmech(const char *mech)
 1117 {
 1118 #ifdef HAVE_LIBGSASL
 1119 
 1120     int supported = 0;
 1121     Gsasl *ctx;
 1122 
 1123     if (strcmp(mech, "OAUTHBEARER") == 0 || strcmp(mech, "XOAUTH2") == 0)
 1124     {
 1125         supported = 1;
 1126     }
 1127     else
 1128     {
 1129         if (gsasl_init(&ctx) != GSASL_OK)
 1130         {
 1131             return 0;
 1132         }
 1133         supported = gsasl_client_support_p(ctx, mech);
 1134         gsasl_done(ctx);
 1135     }
 1136     return supported;
 1137 
 1138 #else /* not HAVE_LIBGSASL */
 1139 
 1140     return (strcmp(mech, "CRAM-MD5") == 0
 1141             || strcmp(mech, "PLAIN") == 0
 1142             || strcmp(mech, "EXTERNAL") == 0
 1143             || strcmp(mech, "LOGIN") == 0
 1144             || strcmp(mech, "OAUTHBEARER") == 0
 1145             || strcmp(mech, "XOAUTH2") == 0);
 1146 
 1147 #endif /* not HAVE_LIBGSASL */
 1148 }
 1149 
 1150 
 1151 /*
 1152  * smtp_auth()
 1153  *
 1154  * see smtp.h
 1155  */
 1156 
 1157 int smtp_auth(smtp_server_t *srv,
 1158         const char *hostname,
 1159         unsigned short port,
 1160         const char *user,
 1161         const char *password,
 1162         const char *ntlmdomain,
 1163         const char *auth_mech,
 1164         char *(*password_callback)(const char *hostname, const char *user),
 1165         list_t **error_msg,
 1166         char **errstr)
 1167 {
 1168 #ifdef HAVE_LIBGSASL
 1169     int e;
 1170     list_t *msg;
 1171     Gsasl *ctx;
 1172     Gsasl_session *sctx;
 1173     char *input;
 1174     char inbuf[SMTP_BUFSIZE];
 1175     char *outbuf;
 1176     int error_code;
 1177     int auth_plain_special;
 1178     char *callback_password = NULL;
 1179 
 1180 
 1181     *error_msg = NULL;
 1182     if (strcmp(auth_mech, "") != 0
 1183             && !smtp_server_supports_authmech(srv, auth_mech))
 1184     {
 1185         *errstr = xasprintf(
 1186                 _("the server does not support authentication method %s"),
 1187                 auth_mech);
 1188         return SMTP_EUNAVAIL;
 1189     }
 1190     if ((error_code = gsasl_init(&ctx)) != GSASL_OK)
 1191     {
 1192         *errstr = xasprintf(_("GNU SASL: %s"), gsasl_strerror(error_code));
 1193         return SMTP_ELIBFAILED;
 1194     }
 1195     if (strcmp(auth_mech, "") != 0 && !smtp_client_supports_authmech(auth_mech))
 1196     {
 1197         gsasl_done(ctx);
 1198         *errstr = xasprintf(
 1199                 _("GNU SASL: authentication method %s not supported"),
 1200                 auth_mech);
 1201         return SMTP_ELIBFAILED;
 1202     }
 1203     if (strcmp(auth_mech, "") == 0)
 1204     {
 1205         /* Choose "best" authentication mechanism. */
 1206         /* TODO: use gsasl_client_suggest_mechanism()? */
 1207 #ifdef HAVE_TLS
 1208         if (mtls_is_active(&srv->mtls))
 1209         {
 1210             if (gsasl_client_support_p(ctx, "PLAIN")
 1211                     && (srv->cap.flags & SMTP_CAP_AUTH_PLAIN))
 1212             {
 1213                 auth_mech = "PLAIN";
 1214             }
 1215             else if (gsasl_client_support_p(ctx, "SCRAM-SHA-256")
 1216                     && (srv->cap.flags & SMTP_CAP_AUTH_SCRAM_SHA_256))
 1217             {
 1218                 auth_mech = "SCRAM-SHA-256";
 1219             }
 1220             else if (gsasl_client_support_p(ctx, "SCRAM-SHA-1")
 1221                     && (srv->cap.flags & SMTP_CAP_AUTH_SCRAM_SHA_1))
 1222             {
 1223                 auth_mech = "SCRAM-SHA-1";
 1224             }
 1225             else if (gsasl_client_support_p(ctx, "CRAM-MD5")
 1226                     && (srv->cap.flags & SMTP_CAP_AUTH_CRAM_MD5))
 1227             {
 1228                 auth_mech = "CRAM-MD5";
 1229             }
 1230             else if (gsasl_client_support_p(ctx, "DIGEST-MD5")
 1231                     && (srv->cap.flags & SMTP_CAP_AUTH_DIGEST_MD5))
 1232             {
 1233                 auth_mech = "DIGEST-MD5";
 1234             }
 1235             else if (gsasl_client_support_p(ctx, "LOGIN")
 1236                     && (srv->cap.flags & SMTP_CAP_AUTH_LOGIN))
 1237             {
 1238                 auth_mech = "LOGIN";
 1239             }
 1240             else if (gsasl_client_support_p(ctx, "NTLM")
 1241                     && (srv->cap.flags & SMTP_CAP_AUTH_NTLM))
 1242             {
 1243                 auth_mech = "NTLM";
 1244             }
 1245         }
 1246         else
 1247 #endif /* HAVE_TLS */
 1248         {
 1249             if (gsasl_client_support_p(ctx, "SCRAM-SHA-256")
 1250                     && (srv->cap.flags & SMTP_CAP_AUTH_SCRAM_SHA_256))
 1251             {
 1252                 auth_mech = "SCRAM-SHA-256";
 1253             }
 1254         else if (gsasl_client_support_p(ctx, "SCRAM-SHA-1")
 1255                     && (srv->cap.flags & SMTP_CAP_AUTH_SCRAM_SHA_1))
 1256             {
 1257                 auth_mech = "SCRAM-SHA-1";
 1258             }
 1259         }
 1260     }
 1261     if (strcmp(auth_mech, "") == 0)
 1262     {
 1263         gsasl_done(ctx);
 1264 #ifdef HAVE_TLS
 1265         if (!mtls_is_active(&srv->mtls))
 1266         {
 1267 #endif /* HAVE_TLS */
 1268             *errstr = xasprintf(_("cannot use a secure authentication method"));
 1269 #ifdef HAVE_TLS
 1270         }
 1271         else
 1272         {
 1273             *errstr = xasprintf(
 1274                     _("cannot find a usable authentication method"));
 1275         }
 1276 #endif /* not HAVE_TLS */
 1277         return SMTP_EUNAVAIL;
 1278     }
 1279 
 1280     /* Check availability of required authentication data */
 1281     if (strcmp(auth_mech, "EXTERNAL") != 0)
 1282     {
 1283         /* All authentication schemes need a user name */
 1284         if (!user)
 1285         {
 1286             gsasl_done(ctx);
 1287             *errstr = xasprintf(_("authentication method %s needs a user name"),
 1288                     auth_mech);
 1289             return SMTP_EUNAVAIL;
 1290         }
 1291         /* SCRAM-SHA-256, SCRAM-SHA-1, DIGEST-MD5, CRAM-MD5, PLAIN, LOGIN, NTLM, OAUTHBEARER, XOAUTH2
 1292          * all need a password */
 1293         if (strcmp(auth_mech, "GSSAPI") != 0 && !password)
 1294         {
 1295             if (!password_callback
 1296                     || !(callback_password = password_callback(hostname, user)))
 1297             {
 1298                 gsasl_done(ctx);
 1299                 *errstr = xasprintf(
 1300                         _("authentication method %s needs a password"),
 1301                         auth_mech);
 1302                 return SMTP_EUNAVAIL;
 1303             }
 1304             password = callback_password;
 1305         }
 1306     }
 1307 
 1308     /* OAUTHBEARER and XOAUTH2 are built-in, all other methods are provided by GNU SASL */
 1309     if (strcmp(auth_mech, "OAUTHBEARER") == 0)
 1310     {
 1311         gsasl_done(ctx);
 1312         e = smtp_auth_oauthbearer(srv, hostname, port, user, password,
 1313                                   error_msg, errstr);
 1314         free(callback_password);
 1315         return e;
 1316     }
 1317     else if (strcmp(auth_mech, "XOAUTH2") == 0)
 1318     {
 1319         gsasl_done(ctx);
 1320         e = smtp_auth_xoauth2(srv, user, password, error_msg, errstr);
 1321         free(callback_password);
 1322         return e;
 1323     }
 1324     else if ((error_code = gsasl_client_start(ctx, auth_mech, &sctx)) != GSASL_OK)
 1325     {
 1326         gsasl_done(ctx);
 1327         *errstr = xasprintf(_("GNU SASL: %s"), gsasl_strerror(error_code));
 1328         return SMTP_ELIBFAILED;
 1329     }
 1330 
 1331     /* Set the authentication properties */
 1332     if (user)
 1333     {
 1334         gsasl_property_set(sctx, GSASL_AUTHID, user);
 1335         /* GSASL_AUTHZID must not be set for DIGEST-MD5, because otherwise
 1336          * authentication may fail (tested with postfix). Set it only for
 1337          * EXTERNAL. */
 1338         if (strcmp(auth_mech, "EXTERNAL") == 0)
 1339         {
 1340             gsasl_property_set(sctx, GSASL_AUTHZID, user);
 1341         }
 1342     }
 1343     if (password)
 1344     {
 1345         gsasl_property_set(sctx, GSASL_PASSWORD, password);
 1346     }
 1347     free(callback_password);
 1348     /* For DIGEST-MD5 and GSSAPI */
 1349     gsasl_property_set(sctx, GSASL_SERVICE, "smtp");
 1350     if (hostname)
 1351     {
 1352         gsasl_property_set(sctx, GSASL_HOSTNAME, hostname);
 1353     }
 1354     /* For NTLM. Postfix does not care, MS IIS needs an arbitrary non-empty
 1355      * string. */
 1356     if (ntlmdomain)
 1357     {
 1358         gsasl_property_set(sctx, GSASL_REALM, ntlmdomain);
 1359     }
 1360 
 1361     /* Bigg authentication loop */
 1362     input = NULL;
 1363     do
 1364     {
 1365         error_code = gsasl_step64(sctx, input, &outbuf);
 1366         if (error_code != GSASL_OK && error_code != GSASL_NEEDS_MORE)
 1367         {
 1368             gsasl_finish(sctx);
 1369             gsasl_done(ctx);
 1370             *errstr = xasprintf(_("GNU SASL: %s"), gsasl_strerror(error_code));
 1371             return SMTP_ELIBFAILED;
 1372         }
 1373         if (!input)
 1374         {
 1375             if (strcmp(auth_mech, "PLAIN") == 0 && outbuf[0])
 1376             {
 1377                 /* AUTH PLAIN needs special treatment because it needs to send
 1378                  * the authentication data together with the AUTH PLAIN command.
 1379                  * At least smtp.web.de requires this, and I happen to use this
 1380                  * server :) */
 1381                 auth_plain_special = 1;
 1382                 if ((e = smtp_send_cmd(srv, errstr,
 1383                                 "AUTH PLAIN %s", outbuf)) != SMTP_EOK)
 1384                 {
 1385                     gsasl_finish(sctx);
 1386                     gsasl_done(ctx);
 1387                     free(outbuf);
 1388                     return e;
 1389                 }
 1390             }
 1391             else
 1392             {
 1393                 auth_plain_special = 0;
 1394                 if ((e = smtp_send_cmd(srv, errstr,
 1395                                 "AUTH %s", auth_mech)) != SMTP_EOK)
 1396                 {
 1397                     gsasl_finish(sctx);
 1398                     gsasl_done(ctx);
 1399                     free(outbuf);
 1400                     return e;
 1401                 }
 1402             }
 1403             if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 1404             {
 1405                 gsasl_finish(sctx);
 1406                 gsasl_done(ctx);
 1407                 free(outbuf);
 1408                 return e;
 1409             }
 1410             if (smtp_msg_status(msg) != 334 && smtp_msg_status(msg) != 235)
 1411             {
 1412                 *error_msg = msg;
 1413                 gsasl_finish(sctx);
 1414                 gsasl_done(ctx);
 1415                 free(outbuf);
 1416                 *errstr = xasprintf(_("authentication failed (method %s)"),
 1417                         auth_mech);
 1418                 return SMTP_EAUTHFAIL;
 1419             }
 1420             /* msg->next->data cannot be longer than SMTP_BUFSIZE-1 */
 1421             strcpy(inbuf, msg->next->data);
 1422             list_xfree(msg, free);
 1423             input = inbuf + 4;
 1424             if (auth_plain_special)
 1425             {
 1426                 free(outbuf);
 1427                 continue;
 1428             }
 1429         }
 1430         /* Some methods (at least CRAM-MD5) must not send an empty outbuf,
 1431          * while others (SCRAM-SHA-1, GSSAPI) must. Confirmed
 1432          * with mpop on 2011-01-17 with one POP3 server and the methods CRAM-MD5
 1433          * and SCRAM-SHA-1. */
 1434         if (outbuf[0]
 1435                 || strcmp(auth_mech, "SCRAM-SHA-256") == 0
 1436                 || strcmp(auth_mech, "SCRAM-SHA-1") == 0
 1437                 || strcmp(auth_mech, "GSSAPI") == 0)
 1438         {
 1439             if ((e = smtp_send_cmd(srv, errstr, "%s", outbuf)) != SMTP_EOK)
 1440             {
 1441                 gsasl_finish(sctx);
 1442                 gsasl_done(ctx);
 1443                 free(outbuf);
 1444                 return e;
 1445             }
 1446             if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 1447             {
 1448                 gsasl_finish(sctx);
 1449                 gsasl_done(ctx);
 1450                 free(outbuf);
 1451                 return e;
 1452             }
 1453             if (smtp_msg_status(msg) != 334 && smtp_msg_status(msg) != 235)
 1454             {
 1455                 *error_msg = msg;
 1456                 gsasl_finish(sctx);
 1457                 gsasl_done(ctx);
 1458                 free(outbuf);
 1459                 *errstr = xasprintf(_("authentication failed (method %s)"),
 1460                         auth_mech);
 1461                 return SMTP_EAUTHFAIL;
 1462             }
 1463             /* msg->next->data cannot be longer than SMTP_BUFSIZE-1 */
 1464             strcpy(inbuf, msg->next->data);
 1465             list_xfree(msg, free);
 1466             input = inbuf + 4;
 1467         }
 1468         free(outbuf);
 1469     }
 1470     while (error_code == GSASL_NEEDS_MORE);
 1471     if (error_code != GSASL_OK)
 1472     {
 1473         gsasl_finish(sctx);
 1474         gsasl_done(ctx);
 1475         *errstr = xasprintf(_("authentication failed: %s (method %s)"),
 1476                 gsasl_strerror(error_code), auth_mech);
 1477         return SMTP_EAUTHFAIL;
 1478     }
 1479     gsasl_finish(sctx);
 1480     gsasl_done(ctx);
 1481     /* For DIGEST-MD5, we need to send an empty answer to the last 334
 1482      * response before we get 235. */
 1483     if (strcmp(auth_mech, "DIGEST-MD5") == 0 && strncmp(inbuf, "235 ", 4) != 0)
 1484     {
 1485         if ((e = smtp_send_cmd(srv, errstr, "")) != SMTP_EOK)
 1486         {
 1487             return e;
 1488         }
 1489         if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 1490         {
 1491             return e;
 1492         }
 1493         if (smtp_msg_status(msg) != 235)
 1494         {
 1495             *error_msg = msg;
 1496             *errstr = xasprintf(_("authentication failed (method %s)"),
 1497                     auth_mech);
 1498             return SMTP_EAUTHFAIL;
 1499         }
 1500         list_xfree(msg, free);
 1501     }
 1502     return SMTP_EOK;
 1503 
 1504 #else /* not HAVE_LIBGSASL */
 1505 
 1506     (void)ntlmdomain;
 1507 
 1508     char *callback_password = NULL;
 1509     int e;
 1510 
 1511 
 1512     *error_msg = NULL;
 1513     if (strcmp(auth_mech, "") != 0
 1514             && !smtp_server_supports_authmech(srv, auth_mech))
 1515     {
 1516         *errstr = xasprintf(
 1517                 _("the server does not support authentication method %s"),
 1518                 auth_mech);
 1519         return SMTP_EUNAVAIL;
 1520     }
 1521     if (strcmp(auth_mech, "") == 0)
 1522     {
 1523         /* Choose "best" authentication mechanism. */
 1524 #ifdef HAVE_TLS
 1525         if (mtls_is_active(&srv->mtls))
 1526         {
 1527             if (srv->cap.flags & SMTP_CAP_AUTH_PLAIN)
 1528             {
 1529                 auth_mech = "PLAIN";
 1530             }
 1531             else if (srv->cap.flags & SMTP_CAP_AUTH_CRAM_MD5)
 1532             {
 1533                 auth_mech = "CRAM-MD5";
 1534             }
 1535             else if (srv->cap.flags & SMTP_CAP_AUTH_LOGIN)
 1536             {
 1537                 auth_mech = "LOGIN";
 1538             }
 1539         }
 1540 #endif /* HAVE_TLS */
 1541     }
 1542     if (strcmp(auth_mech, "") == 0)
 1543     {
 1544 #ifdef HAVE_TLS
 1545         if (!mtls_is_active(&srv->mtls))
 1546         {
 1547 #endif /* HAVE_TLS */
 1548             *errstr = xasprintf(_("cannot use a secure authentication method"));
 1549 #ifdef HAVE_TLS
 1550         }
 1551         else
 1552         {
 1553             *errstr = xasprintf(
 1554                     _("cannot find a usable authentication method"));
 1555         }
 1556 #endif /* not HAVE_TLS */
 1557         return SMTP_EUNAVAIL;
 1558     }
 1559 
 1560     if (strcmp(auth_mech, "EXTERNAL") != 0)
 1561     {
 1562         /* CRAMD-MD5, PLAIN, LOGIN, OAUTHBEARER all need a user name and a
 1563          * password */
 1564         if (!user)
 1565         {
 1566             *errstr = xasprintf(_("authentication method %s needs a user name"),
 1567                     auth_mech);
 1568             return SMTP_EUNAVAIL;
 1569         }
 1570         if (!password)
 1571         {
 1572             if (!password_callback
 1573                     || !(callback_password = password_callback(hostname, user)))
 1574             {
 1575                 *errstr = xasprintf(
 1576                         _("authentication method %s needs a password"),
 1577                         auth_mech);
 1578                 return SMTP_EUNAVAIL;
 1579             }
 1580             password = callback_password;
 1581         }
 1582     }
 1583 
 1584     if (strcmp(auth_mech, "CRAM-MD5") == 0)
 1585     {
 1586         e = smtp_auth_cram_md5(srv, user, password, error_msg, errstr);
 1587     }
 1588     else if (strcmp(auth_mech, "PLAIN") == 0)
 1589     {
 1590         e = smtp_auth_plain(srv, user, password, error_msg, errstr);
 1591     }
 1592     else if (strcmp(auth_mech, "EXTERNAL") == 0)
 1593     {
 1594         e = smtp_auth_external(srv, user ? user : "", error_msg, errstr);
 1595     }
 1596     else if (strcmp(auth_mech, "LOGIN") == 0)
 1597     {
 1598         e = smtp_auth_login(srv, user, password, error_msg, errstr);
 1599     }
 1600     else if (strcmp(auth_mech, "OAUTHBEARER") == 0)
 1601     {
 1602         e = smtp_auth_oauthbearer(srv, hostname, port, user, password,
 1603                                   error_msg, errstr);
 1604     }
 1605     else if (strcmp(auth_mech, "XOAUTH2") == 0)
 1606     {
 1607         e = smtp_auth_xoauth2(srv, user, password, error_msg, errstr);
 1608     }
 1609     else
 1610     {
 1611         *errstr = xasprintf(_("authentication method %s not supported"),
 1612                 auth_mech);
 1613         e = SMTP_ELIBFAILED;
 1614     }
 1615     free(callback_password);
 1616     return e;
 1617 
 1618 #endif /* not HAVE_LIBGSASL */
 1619 }
 1620 
 1621 
 1622 /*
 1623  * smtp_send_envelope()
 1624  *
 1625  * see smtp.h
 1626  */
 1627 
 1628 int smtp_send_envelope(smtp_server_t *srv,
 1629         const char *envelope_from,
 1630         list_t *recipients,
 1631         const char *dsn_notify,
 1632         const char *dsn_return,
 1633         list_t **error_msg,
 1634         char **errstr)
 1635 {
 1636     int e;
 1637     list_t *msg;
 1638     int mailfrom_cmd_was_sent = 0;
 1639     int mailfrom_reply_was_rcvd = 0;
 1640     list_t *rcpt_send = recipients;
 1641     list_t *rcpt_recv = recipients;
 1642     int data_cmd_was_sent = 0;
 1643     int data_reply_was_rcvd = 0;
 1644     int pipeline_limit = 1;
 1645     int piped_commands = 0;
 1646     int status;
 1647 
 1648 
 1649     *error_msg = NULL;
 1650     if (srv->cap.flags & SMTP_CAP_PIPELINING)
 1651     {
 1652         pipeline_limit = SMTP_PIPELINE_LIMIT;
 1653     }
 1654 
 1655     /* Send the MAIL FROM, RCPT TO and DATA commands using pipelining. The
 1656      * number of pipelined commands will never be greater than pipeline_limit
 1657      * to avoid problems with the TCP window size (exceeding it can lead to
 1658      * deadlocks). pipeline_limit == 1 disables pipelining. */
 1659     while (!data_reply_was_rcvd)
 1660     {
 1661         while (!data_cmd_was_sent && piped_commands < pipeline_limit)
 1662         {
 1663             /* send */
 1664             if (!mailfrom_cmd_was_sent)
 1665             {
 1666                 if (dsn_return)
 1667                 {
 1668                     e = smtp_send_cmd(srv, errstr, "MAIL FROM:<%s> RET=%s",
 1669                             strcasecmp(envelope_from, "MAILER-DAEMON") == 0
 1670                             ? "" : envelope_from, dsn_return);
 1671                 }
 1672                 else
 1673                 {
 1674                     e = smtp_send_cmd(srv, errstr, "MAIL FROM:<%s>",
 1675                             strcasecmp(envelope_from, "MAILER-DAEMON") == 0
 1676                             ? "" : envelope_from);
 1677                 }
 1678                 if (e != SMTP_EOK)
 1679                 {
 1680                     return e;
 1681                 }
 1682                 mailfrom_cmd_was_sent = 1;
 1683             }
 1684             else if (!list_is_empty(rcpt_send))
 1685             {
 1686                 rcpt_send = rcpt_send->next;
 1687                 if (dsn_notify)
 1688                 {
 1689                     e = smtp_send_cmd(srv, errstr, "RCPT TO:<%s> NOTIFY=%s",
 1690                             (char *)(rcpt_send->data), dsn_notify);
 1691                 }
 1692                 else
 1693                 {
 1694                     e = smtp_send_cmd(srv, errstr, "RCPT TO:<%s>",
 1695                             (char *)(rcpt_send->data));
 1696                 }
 1697                 if (e != SMTP_EOK)
 1698                 {
 1699                     return e;
 1700                 }
 1701             }
 1702             else
 1703             {
 1704                 if ((e = smtp_send_cmd(srv, errstr, "DATA")) != SMTP_EOK)
 1705                 {
 1706                     return e;
 1707                 }
 1708                 data_cmd_was_sent = 1;
 1709             }
 1710             piped_commands++;
 1711         }
 1712         while (piped_commands > 0)
 1713         {
 1714             /* receive */
 1715             if (!mailfrom_reply_was_rcvd)
 1716             {
 1717                 if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 1718                 {
 1719                     return e;
 1720                 }
 1721                 status = smtp_msg_status(msg);
 1722                 if (status != 250)
 1723                 {
 1724                     *error_msg = msg;
 1725                     *errstr = xasprintf(_("envelope from address %s not "
 1726                                 "accepted by the server"), envelope_from);
 1727                     return (status >= 400 && status <= 499
 1728                             ? SMTP_EUNAVAIL : SMTP_EINVAL);
 1729                 }
 1730                 list_xfree(msg, free);
 1731                 mailfrom_reply_was_rcvd = 1;
 1732             }
 1733             else if (!list_is_empty(rcpt_recv))
 1734             {
 1735                 rcpt_recv = rcpt_recv->next;
 1736                 if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 1737                 {
 1738                     return e;
 1739                 }
 1740                 status = smtp_msg_status(msg);
 1741                 if (status != 250 && status != 251)
 1742                 {
 1743                     *error_msg = msg;
 1744                     *errstr = xasprintf(_("recipient address %s not "
 1745                                 "accepted by the server"),
 1746                             (char *)(rcpt_recv->data));
 1747                     return (status >= 400 && status <= 499
 1748                             ? SMTP_EUNAVAIL : SMTP_EINVAL);
 1749                 }
 1750                 list_xfree(msg, free);
 1751             }
 1752             else
 1753             {
 1754                 if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 1755                 {
 1756                     return e;
 1757                 }
 1758                 status = smtp_msg_status(msg);
 1759                 if (smtp_msg_status(msg) != 354)
 1760                 {
 1761                     *error_msg = msg;
 1762                     *errstr = xasprintf(
 1763                             _("the server does not accept mail data"));
 1764                     return (status >= 400 && status <= 499
 1765                             ? SMTP_EUNAVAIL : SMTP_EINVAL);
 1766                 }
 1767                 list_xfree(msg, free);
 1768                 data_reply_was_rcvd = 1;
 1769             }
 1770             piped_commands--;
 1771         }
 1772     }
 1773 
 1774     return SMTP_EOK;
 1775 }
 1776 
 1777 
 1778 /*
 1779  * smtp_send_mail()
 1780  *
 1781  * see smtp.h
 1782  */
 1783 
 1784 int smtp_send_mail(smtp_server_t *srv, FILE *mailf,
 1785         int keep_from, int keep_to, int keep_cc, int keep_bcc,
 1786         long *mailsize, char **errstr)
 1787 {
 1788     char bigbuffer[MAIL_BUFSIZE + 3];   /* buffer + leading dot + ending CRLF */
 1789     char *buffer;
 1790     size_t len;
 1791     char *send_buf;
 1792     size_t send_len;
 1793     int in_header;
 1794     int in_from;
 1795     int in_to;
 1796     int in_cc;
 1797     int in_bcc;
 1798     int line_starts;
 1799     int line_continues;
 1800     int e;
 1801 
 1802     bigbuffer[0] = '.';
 1803     buffer = bigbuffer + 1;
 1804     in_header = 1;
 1805     in_from = 0;
 1806     in_to = 0;
 1807     in_cc = 0;
 1808     in_bcc = 0;
 1809     line_continues = 0;
 1810     e = SMTP_EOK;
 1811     for (;;)
 1812     {
 1813         if (stream_gets(mailf, buffer, MAIL_BUFSIZE, &len, errstr)
 1814                 != STREAM_EOK)
 1815         {
 1816             return SMTP_EIO;
 1817         }
 1818         if (len == 0)
 1819         {
 1820             break;
 1821         }
 1822         line_starts = !line_continues;
 1823         if (len > 0 && buffer[len - 1] == '\n')
 1824         {
 1825             /* first case: we have a line end */
 1826             buffer[--len] = '\0';
 1827             if (len > 0 && buffer[len - 1] == '\r')
 1828             {
 1829                 buffer[--len] = '\0';
 1830             }
 1831             line_continues = 0;
 1832         }
 1833         else if (len == MAIL_BUFSIZE - 1)
 1834         {
 1835             /* second case: the line continues */
 1836             if (buffer[len - 1] == '\r')
 1837             {
 1838                 /* We have CRLF that is divided by the buffer boundary. Since CR
 1839                  * may not appear alone in a mail according to RFC2822, we
 1840                  * know that the next buffer will be "\n\0", so it's safe to
 1841                  * just delete the CR. */
 1842                 buffer[--len] = '\0';
 1843             }
 1844             line_continues = 1;
 1845         }
 1846         else
 1847         {
 1848             /* third case: this is the last line, and it lacks a newline
 1849              * character */
 1850             line_continues = 0;
 1851         }
 1852         if (line_starts && in_header && buffer[0] == '\0')
 1853         {
 1854             in_header = 0;
 1855         }
 1856         if (in_header)
 1857         {
 1858             if (line_starts)
 1859             {
 1860                 if (!keep_from && strncasecmp(buffer, "From:", 5) == 0)
 1861                 {
 1862                     in_from = 1;
 1863                     /* remove header by ignoring this line */
 1864                     continue;
 1865                 }
 1866                 else if (!keep_from && in_from)
 1867                 {
 1868                     /* continued header lines begin with "horizontal
 1869                      * whitespace" (RFC 2822, section 2.2.3) */
 1870                     if (buffer[0] == '\t' || buffer[0] == ' ')
 1871                     {
 1872                         /* remove header by ignoring this line */
 1873                         continue;
 1874                     }
 1875                     else
 1876                     {
 1877                         in_from = 0;
 1878                     }
 1879                 }
 1880                 if (!keep_to && strncasecmp(buffer, "To:", 3) == 0)
 1881                 {
 1882                     in_to = 1;
 1883                     /* remove header by ignoring this line */
 1884                     continue;
 1885                 }
 1886                 else if (!keep_to && in_to)
 1887                 {
 1888                     /* continued header lines begin with "horizontal
 1889                      * whitespace" (RFC 2822, section 2.2.3) */
 1890                     if (buffer[0] == '\t' || buffer[0] == ' ')
 1891                     {
 1892                         /* remove header by ignoring this line */
 1893                         continue;
 1894                     }
 1895                     else
 1896                     {
 1897                         in_to = 0;
 1898                     }
 1899                 }
 1900                 if (!keep_cc && strncasecmp(buffer, "Cc:", 3) == 0)
 1901                 {
 1902                     in_cc = 1;
 1903                     /* remove header by ignoring this line */
 1904                     continue;
 1905                 }
 1906                 else if (!keep_cc && in_cc)
 1907                 {
 1908                     /* continued header lines begin with "horizontal
 1909                      * whitespace" (RFC 2822, section 2.2.3) */
 1910                     if (buffer[0] == '\t' || buffer[0] == ' ')
 1911                     {
 1912                         /* remove header by ignoring this line */
 1913                         continue;
 1914                     }
 1915                     else
 1916                     {
 1917                         in_cc = 0;
 1918                     }
 1919                 }
 1920                 if (!keep_bcc && strncasecmp(buffer, "Bcc:", 4) == 0)
 1921                 {
 1922                     in_bcc = 1;
 1923                     /* remove header by ignoring this line */
 1924                     continue;
 1925                 }
 1926                 else if (!keep_bcc && in_bcc)
 1927                 {
 1928                     /* continued header lines begin with "horizontal
 1929                      * whitespace" (RFC 2822, section 2.2.3) */
 1930                     if (buffer[0] == '\t' || buffer[0] == ' ')
 1931                     {
 1932                         /* remove header by ignoring this line */
 1933                         continue;
 1934                     }
 1935                     else
 1936                     {
 1937                         in_bcc = 0;
 1938                     }
 1939                 }
 1940             }
 1941             else
 1942             {
 1943                 if ((!keep_from && in_from) || (!keep_to && in_to)
 1944                         || (!keep_cc && in_cc) || (!keep_bcc && in_bcc))
 1945                 {
 1946                     /* remove header by ignoring this line */
 1947                     continue;
 1948                 }
 1949             }
 1950         }
 1951         send_buf = buffer;
 1952         send_len = len;
 1953         if (line_starts && buffer[0] == '.')
 1954         {
 1955             /* Quote the leading dot with another dot */
 1956             send_buf = bigbuffer;
 1957             send_len = len + 1;
 1958         }
 1959         if (!line_continues)
 1960         {
 1961             /* Append CRLF */
 1962             buffer[len] = '\r';
 1963             buffer[len + 1] = '\n';
 1964             buffer[len + 2] = '\0';
 1965             send_len += 2;
 1966         }
 1967         /* Update mailsize. Do not count a quote dot. Count CRLF as one
 1968          * character. */
 1969         *mailsize += (long)len + (line_continues ? 0 : 1);
 1970         if ((e = smtp_put(srv, send_buf, send_len, errstr)) != SMTP_EOK)
 1971         {
 1972             return e;
 1973         }
 1974     }
 1975 
 1976     return SMTP_EOK;
 1977 }
 1978 
 1979 
 1980 /*
 1981  * smtp_end_mail()
 1982  *
 1983  * see smtp.h
 1984  */
 1985 
 1986 int smtp_end_mail(smtp_server_t *srv, list_t **error_msg, char **errstr)
 1987 {
 1988     int e;
 1989     list_t *msg;
 1990 
 1991     *error_msg = NULL;
 1992     if ((e = smtp_send_cmd(srv, errstr, ".")) != SMTP_EOK)
 1993     {
 1994         return e;
 1995     }
 1996     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 1997     {
 1998         return e;
 1999     }
 2000     *error_msg = msg;
 2001     if (smtp_msg_status(msg) != 250)
 2002     {
 2003         *errstr = xasprintf(_("the server did not accept the mail"));
 2004         return SMTP_EUNAVAIL;
 2005     }
 2006     else
 2007     {
 2008         return SMTP_EOK;
 2009     }
 2010 }
 2011 
 2012 
 2013 /*
 2014  * smtp_end_mail_lmtp()
 2015  *
 2016  * see smtp.h
 2017  *
 2018  */
 2019 
 2020 void _smtp_free_list_of_lists(void *l)
 2021 {
 2022     list_xfree((list_t *)l, free);
 2023 }
 2024 
 2025 int smtp_end_mail_lmtp(smtp_server_t *srv,
 2026         list_t *recipients,
 2027         list_t **errstrs,
 2028         list_t **error_msgs,
 2029         char **errstr)
 2030 {
 2031     int e;
 2032     list_t *msg;
 2033     list_t *lp_recipients;
 2034     list_t *lp_errstrs;
 2035     list_t *lp_error_msgs;
 2036     int all_recipients_accepted;
 2037     char *tmp;
 2038 
 2039 
 2040     if ((e = smtp_send_cmd(srv, errstr, ".")) != SMTP_EOK)
 2041     {
 2042         *errstrs = NULL;
 2043         *error_msgs = NULL;
 2044         return e;
 2045     }
 2046 
 2047     *errstrs = list_new();
 2048     *error_msgs = list_new();
 2049     lp_errstrs = *errstrs;
 2050     lp_error_msgs = *error_msgs;
 2051     lp_recipients = recipients;
 2052     all_recipients_accepted = 1;
 2053     while (!list_is_empty(lp_recipients))
 2054     {
 2055         lp_recipients = lp_recipients->next;
 2056         if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 2057         {
 2058             list_xfree(*errstrs, free);
 2059             *errstrs = NULL;
 2060             list_xfree(*error_msgs, _smtp_free_list_of_lists);
 2061             *error_msgs = NULL;
 2062             return e;
 2063         }
 2064         if (smtp_msg_status(msg) != 250)
 2065         {
 2066             all_recipients_accepted = 0;
 2067             tmp = xasprintf(_("the server refuses to send the mail to %s"),
 2068                     (char *)(lp_recipients->data));
 2069             list_insert(lp_errstrs, tmp);
 2070             list_insert(lp_error_msgs, msg);
 2071         }
 2072         else
 2073         {
 2074             list_xfree(msg, free);
 2075             list_insert(lp_errstrs, NULL);
 2076             list_insert(lp_error_msgs, NULL);
 2077         }
 2078         lp_errstrs = lp_errstrs->next;
 2079         lp_error_msgs = lp_error_msgs->next;
 2080     }
 2081 
 2082     if (all_recipients_accepted)
 2083     {
 2084         /* we can use list_free() here since all list entries are just NULL */
 2085         list_free(*errstrs);
 2086         *errstrs = NULL;
 2087         list_free(*error_msgs);
 2088         *error_msgs = NULL;
 2089         return SMTP_EOK;
 2090     }
 2091     else
 2092     {
 2093         return SMTP_EUNAVAIL;
 2094     }
 2095 }
 2096 
 2097 
 2098 /*
 2099  * smtp_etrn()
 2100  *
 2101  * see smtp.h
 2102  */
 2103 
 2104 int smtp_etrn(smtp_server_t *srv, const char *etrn_argument,
 2105         list_t **error_msg, char **errstr)
 2106 {
 2107     int e;
 2108     list_t *msg;
 2109 
 2110     *error_msg = NULL;
 2111     if ((e = smtp_send_cmd(srv, errstr, "ETRN %s", etrn_argument)) != SMTP_EOK)
 2112     {
 2113         return e;
 2114     }
 2115     if ((e = smtp_get_msg(srv, &msg, errstr)) != SMTP_EOK)
 2116     {
 2117         return e;
 2118     }
 2119     switch (smtp_msg_status(msg))
 2120     {
 2121         case 250: /* OK, queuing for node <x> started */
 2122         case 251: /* OK, no messages waiting for node <x> */
 2123         case 252: /* OK, pending messages for node <x> started */
 2124         case 253: /* OK, <n> pending messages for node <x> started */
 2125             break;
 2126 
 2127         case 458: /* Unable to queue messages for node <x> */
 2128         case 459: /* Node <x> not allowed: <reason> */
 2129             *error_msg = msg;
 2130             *errstr = xasprintf(
 2131                     _("the server is unable to fulfill the request"));
 2132             return SMTP_EUNAVAIL;
 2133             break;
 2134 
 2135         case 500: /* Syntax Error */
 2136         case 501: /* 501 Syntax Error in Parameters */
 2137             *error_msg = msg;
 2138             *errstr = xasprintf(
 2139                     _("invalid argument for Remote Message Queue Starting"));
 2140             return SMTP_EINVAL;
 2141             break;
 2142 
 2143         default:
 2144             *error_msg = msg;
 2145             *errstr = xasprintf(_("command %s failed"), "ETRN");
 2146             return SMTP_EPROTO;
 2147             break;
 2148     }
 2149     list_xfree(msg, free);
 2150 
 2151     return SMTP_EOK;
 2152 }
 2153 
 2154 
 2155 /*
 2156  * smtp_quit()
 2157  *
 2158  * see smtp.h
 2159  */
 2160 
 2161 int smtp_quit(smtp_server_t *srv, char **errstr)
 2162 {
 2163     int e;
 2164     list_t *msg = NULL;
 2165 
 2166     if ((e = smtp_send_cmd(srv, errstr, "QUIT")) == SMTP_EOK)
 2167     {
 2168         e = smtp_get_msg(srv, &msg, errstr);
 2169     }
 2170     if (msg)
 2171     {
 2172         list_xfree(msg, free);
 2173     }
 2174     return e;
 2175 }
 2176 
 2177 
 2178 /*
 2179  * smtp_close()
 2180  *
 2181  * see smtp.h
 2182  */
 2183 
 2184 void smtp_close(smtp_server_t *srv)
 2185 {
 2186 #ifdef HAVE_TLS
 2187     if (mtls_is_active(&srv->mtls))
 2188     {
 2189         mtls_close(&srv->mtls);
 2190     }
 2191 #endif /* HAVE_TLS */
 2192     net_close_socket(srv->fd);
 2193 }
 2194 
 2195 
 2196 /*
 2197  * smtp_exitcode()
 2198  *
 2199  * see smtp.h
 2200  */
 2201 
 2202 int smtp_exitcode(int smtp_error_code)
 2203 {
 2204     switch (smtp_error_code)
 2205     {
 2206         case SMTP_EIO:
 2207             return EX_IOERR;
 2208         case SMTP_EPROTO:
 2209             return EX_PROTOCOL;
 2210         case SMTP_EINVAL:
 2211             return EX_DATAERR;
 2212         case SMTP_EAUTHFAIL:
 2213             return EX_NOPERM;
 2214         case SMTP_EINSECURE:
 2215         case SMTP_EUNAVAIL:
 2216             return EX_UNAVAILABLE;
 2217         case SMTP_ELIBFAILED:
 2218         default:
 2219             return EX_SOFTWARE;
 2220     }
 2221 }