"Fossies" - the Fresh Open Source Software Archive

Member "msmtp-1.8.5/src/smtp.c" (12 Jul 2019, 56286 Bytes) of package /linux/privat/msmtp-1.8.5.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 latest Fossies "Diffs" side-by-side code changes report: 1.8.4_vs_1.8.5.

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