Back to index

courier  0.68.2
esmtpclient.c
Go to the documentation of this file.
00001 /*
00002 ** Copyright 1998 - 2012 Double Precision, Inc.
00003 ** See COPYING for distribution information.
00004 */
00005 
00006 #if    HAVE_CONFIG_H
00007 #include      "config.h"
00008 #endif
00009 #include      "soxwrap/soxwrap.h"
00010 #include      "soxwrap/sconnect.h"
00011 #include      "courier.h"
00012 #include      "smtproutes.h"
00013 #include      "localstatedir.h"
00014 #include      "moduledel.h"
00015 #include      "comctlfile.h"
00016 #include      "comreadtime.h"
00017 #include      "comqueuename.h"
00018 #include      "maxlongsize.h"
00019 #include      "comverp.h"
00020 #include      "rfc1035/rfc1035.h"
00021 #include      "rfc1035/rfc1035mxlist.h"
00022 #include      "rfc822.h"
00023 #include      "rfc2045/rfc2045.h"
00024 #include      "numlib/numlib.h"
00025 #include      "tcpd/spipe.h"
00026 #include      "tcpd/tlsclient.h"
00027 #include      <courierauthsaslclient.h>
00028 
00029 #define       mybuf_readfunc       sox_read
00030 #include      "mybuf.h"
00031 #include      "rw.h"
00032 #include      "esmtpconfig.h"
00033 
00034 #include      <sys/types.h>
00035 #include      <sys/uio.h>
00036 #include      <sys/socket.h>
00037 #include      <sys/time.h>
00038 #include      <sys/wait.h>
00039 #if    HAVE_NETINET_TCP_H
00040 #include      <netinet/tcp.h>
00041 #endif
00042 #if    HAVE_UTIME
00043 #include      <utime.h>
00044 #endif
00045 
00046 
00047 #include      <ctype.h>
00048 #include      <string.h>
00049 #if HAVE_SYS_STAT_H
00050 #include      <sys/stat.h>
00051 #endif
00052 #if HAVE_FCNTL_H
00053 #include      <fcntl.h>
00054 #endif
00055 
00056 #if TIME_WITH_SYS_TIME
00057 #include      <sys/time.h>
00058 #include      <time.h>
00059 #else
00060 #if HAVE_SYS_TIME_H
00061 #include      <sys/time.h>
00062 #else
00063 #include      <time.h>
00064 #endif
00065 #endif
00066 #if HAVE_UNISTD_H
00067 #include      <unistd.h>
00068 #endif
00069 #include      <stdio.h>
00070 #include      <stdlib.h>
00071 #include      <signal.h>
00072 #include      <errno.h>
00073 
00074 static time_t esmtpkeepaliveping;
00075 static time_t connect_timeout;
00076 static time_t cmd_timeout;
00077 static time_t helo_timeout;
00078 static time_t quit_timeout;
00079 static time_t data_timeout;
00080 
00081 #ifdef TCP_CORK
00082 
00083 static int esmtp_cork;
00084 static int corked;
00085 
00086 #define       cork(n) \
00087        {\
00088        int flag=(n);\
00089 \
00090               if (esmtp_cork && sockfd >= 0 && corked != flag) \
00091               { \
00092                      setsockopt(sockfd, SOL_TCP, TCP_CORK, &flag, \
00093                                                  sizeof(flag));\
00094               } \
00095               corked=flag;\
00096        }
00097 #else
00098 #define       cork(n)
00099 #endif
00100 
00101 static time_t net_timeout;
00102        /*
00103        ** If all MXs are unreachable, wait until this tick before attempting
00104        ** any new connections.
00105        */
00106 static int net_error;
00107 
00108 static void sendesmtp(struct moduledel *, struct ctlfile *);
00109 static const char *readline();
00110 static int sockfd;
00111 static void quit();
00112 static int dowritestr(const char *);
00113 static int writeflush();
00114 static void sock_timeout(unsigned);
00115 
00116 #define       ISFINALLINE(p)       ( isdigit((int)(unsigned char)p[0]) && \
00117                      isdigit((int)(unsigned char)p[1]) && \
00118                      isdigit((int)(unsigned char)p[2]) \
00119                             && p[3] == ' ')
00120 
00121 extern struct rw_list *esmtp_rw_install(const struct rw_install_info *);
00122 extern int isloopback(const char *);
00123 
00124 static void (*rewrite_func)(struct rw_info *, void (*)(struct rw_info *));
00125 
00126 void rfc2045_error(const char *p)
00127 {
00128        clog_msg_start_err();
00129        clog_msg_str(p);
00130        clog_msg_send();
00131        _exit(1);
00132 }
00133 
00134 static void setconfig()
00135 {
00136        esmtpkeepaliveping=config_time_esmtpkeepaliveping();
00137        cmd_timeout=config_time_esmtptimeout();
00138        connect_timeout=config_time_esmtpconnect();
00139        cmd_timeout=config_time_esmtptimeout();
00140        helo_timeout=config_time_esmtphelo();
00141        data_timeout=config_time_esmtpdata();
00142        quit_timeout=config_time_esmtpquit();
00143 }
00144 
00145 /* We get here as a new child process of the courieresmtp driver */
00146 
00147 void esmtpchild(unsigned childnum)
00148 {
00149 struct moduledel *del;
00150 struct ctlfile       ctf;
00151 unsigned long mypid=(unsigned long)getpid();
00152 
00153        signal(SIGPIPE, SIG_IGN);
00154        srand(time(NULL));
00155        rw_init_courier("esmtp");
00156        rewrite_func=rw_search_transport("esmtp")->rw_ptr->rewrite;
00157 
00158        if (chdir(courierdir()))
00159               clog_msg_errno();
00160        sockfd= -1;
00161 
00162        setconfig();
00163 
00164        net_timeout=0;
00165 
00166 #ifdef TCP_CORK
00167 
00168        {
00169        const char *p=getenv("ESMTP_CORK");
00170 
00171               esmtp_cork=p ? atoi(p):0;
00172               corked=0;
00173        }
00174 
00175 #endif
00176 
00177        /* Retrieve delivery request until courieresmtp closes the pipe */
00178 
00179        while ((del=module_getdel()) != 0)
00180        {
00181        fd_set fdr;
00182        struct timeval       tv;
00183        const char *p;
00184 
00185 #if 0
00186               clog_msg_start_info();
00187               clog_msg_str("Process ");
00188               clog_msg_uint(getpid());
00189               clog_msg_str(" ready to be grabbed.");
00190               clog_msg_send();
00191               sleep(60);
00192 #endif
00193 
00194               /*
00195               ** Open the message control file, send the message, close
00196               ** the control file, we're done.
00197               */
00198 
00199               if (ctlfile_openi(del->inum, &ctf, 0) == 0)
00200               {
00201                      int changed_vhosts=ctlfile_setvhost(&ctf);
00202 
00203                      if (changed_vhosts)
00204                      {
00205                             quit();
00206                             setconfig();
00207                      }
00208 
00209                      sendesmtp(del, &ctf);
00210                      ctlfile_close(&ctf);
00211               }
00212               {
00213               char   pidbuf[NUMBUFSIZE];
00214 
00215                      printf("%u %s\n", childnum, libmail_str_pid_t(mypid, pidbuf));
00216                      fflush(stdout);
00217               }
00218 
00219               /*
00220               ** While waiting for the next message, push a RSET every
00221               ** so-so seconds
00222               */
00223 
00224               while (esmtpkeepaliveping && sockfd >= 0)
00225               {
00226                      FD_ZERO(&fdr);
00227                      FD_SET(0, &fdr);
00228                      tv.tv_sec=esmtpkeepaliveping;
00229                      tv.tv_usec=0;
00230 
00231                      if ( sox_select(1, &fdr, 0, 0, &tv) > 0)
00232                             break;
00233                      sock_timeout(data_timeout);
00234                      if (dowritestr("RSET\r\n") || writeflush())
00235                             break;
00236 
00237                      while ( (p=readline()) != 0 && !ISFINALLINE(p))
00238                             ;
00239 
00240                      if (p == 0)
00241                      {
00242                             quit();
00243                             break;
00244                      }
00245               }
00246        }
00247        if (sockfd >= 0)
00248               quit();
00249 }
00250 
00251 static RFC1035_ADDR sockfdaddr;
00252 static char *sockfdaddrname=0;
00253 static char *auth_key=0;
00254 static struct mybuf sockbuf;
00255 static char writebuf[BUFSIZ];
00256 static char *writebufptr;
00257 static unsigned writebufleft;
00258 static time_t timeout_time;
00259 static char socklinebuf[sizeof(sockbuf.buffer)+1];
00260 static unsigned socklinesize;
00261 static char *host;
00262 static char *authsasllist=0;
00263 static int is_secure_connection=0;
00264 static int smtproutes_flags=0;
00265 
00266 static int hasdsn, haspipelining, has8bitmime, hasverp, hassize, hasexdata,
00267        hascourier, hasstarttls, hassecurity_starttls;
00268 
00269 static void hard_error(struct moduledel *, struct ctlfile *, const char *);
00270 static void soft_error(struct moduledel *, struct ctlfile *, const char *);
00271 static void connect_error(struct moduledel *, struct ctlfile *);
00272 
00273 static int hello(struct moduledel *, struct ctlfile *);
00274 static int starttls(struct moduledel *, struct ctlfile *, const char *);
00275 static int authclient(struct moduledel *, struct ctlfile *, const char *);
00276 
00277 static int rset(struct moduledel *, struct ctlfile *);
00278 static int smtpreply(const char *, struct moduledel *, struct ctlfile *, int);
00279 static int dowrite(const char *, unsigned);
00280 static void push(struct moduledel *, struct ctlfile *);
00281 
00282 static const char *want_security(struct ctlfile *ctf)
00283 {
00284        const char *sec;
00285 
00286        if (smtproutes_flags & ROUTE_NOSECURITY)
00287               return (0);
00288 
00289        if (smtproutes_flags & ROUTE_STARTTLS)
00290               return ("STARTTLS");
00291 
00292        sec=ctlfile_security(ctf);
00293 
00294        if (!sec)
00295               return (0);
00296        if (strcmp(sec, "STARTTLS") == 0)
00297               return (sec);
00298        return (0);
00299 }
00300 
00301 static int get_sourceaddr(int af,
00302                        const RFC1035_ADDR *dest_addr,
00303                        RFC1035_NETADDR *addrbuf,
00304                        const struct sockaddr **addrptr, int *addrptrlen)
00305 {
00306        int rc;
00307        RFC1035_ADDR in;
00308        const char *vhost=config_get_local_vhost();
00309        char vhost_ip_buf[100];
00310        const char *buf=getenv(
00311 #if RFC1035_IPV6
00312 
00313                             !IN6_IS_ADDR_V4MAPPED(dest_addr)
00314                             ? "SOURCE_ADDRESS_IPV6":
00315 #endif
00316                             "SOURCE_ADDRESS");
00317 
00318        char *source=config_localfilename(
00319 #if RFC1035_IPV6
00320 
00321                                      !IN6_IS_ADDR_V4MAPPED(dest_addr)
00322                                      ? "ip6out":
00323 #endif
00324                                      "ipout");
00325        FILE *fp;
00326        fp=fopen(source, "r");
00327        free(source);
00328 
00329        if (fp)
00330        {
00331               char *p;
00332 
00333               /*
00334               ** If ip[6]out.xxxx exists, read the IP address from it.
00335               */
00336               vhost_ip_buf[0]=0;
00337               if (fgets(vhost_ip_buf, sizeof(vhost_ip_buf), fp) == NULL)
00338                      vhost_ip_buf[0]=0;
00339               fclose(fp);
00340 
00341               p=strchr(vhost_ip_buf, '\n');
00342               if (p) *p=0;
00343 
00344               /*
00345               ** If the file is empty, use the vhost IP address itself.
00346               */
00347               if (vhost_ip_buf[0])
00348                      buf=vhost_ip_buf;
00349               else if (vhost && *vhost)
00350                      buf=vhost;
00351        }
00352 
00353        if (buf && strcmp(buf, "0")) {
00354               rc = rfc1035_aton(buf, &in);
00355               if (rc != 0)
00356                      return rc;
00357        } else
00358               in = RFC1035_ADDRANY;
00359 
00360        rc = rfc1035_mkaddress(af, addrbuf, &in, htons(0),
00361                      addrptr, addrptrlen);
00362        if (rc != 0)
00363               return rc;
00364 
00365        return 0;
00366 }
00367 
00368 static int backscatter(const char *src)
00369 {
00370        char buf[1024];
00371        const char *env;
00372        char *p;
00373 
00374        buf[0]=0;
00375 
00376        env=getenv("ESMTP_BLOCKBACKSCATTER");
00377 
00378        strncat(buf, env ? env:"", 1000);
00379 
00380        for (p=buf; (p=strtok(p, ",")); p=NULL)
00381        {
00382               if (strcmp(p, src) == 0)
00383                      return 1;
00384        }
00385        return 0;
00386 }
00387 
00388 /* Attempt to deliver a message */
00389 
00390 static void sendesmtp(struct moduledel *del, struct ctlfile *ctf)
00391 {
00392        char *smtproute;
00393        int cn;
00394 
00395        if (!host)
00396               host=strcpy(courier_malloc(strlen(del->host)+1), del->host);
00397 
00398        /* Sanity check */
00399 
00400        if (strcmp(host, del->host))
00401        {
00402               clog_msg_start_err();
00403               clog_msg_str("Internal failure in courieresmtp - daemon mixup.");
00404               clog_msg_send();
00405               _exit(1);
00406        }
00407 
00408        /* If we're connected, send a RSET to make sure the socket is working */
00409 
00410        if (sockfd >= 0)
00411        {
00412               sock_timeout(helo_timeout);
00413               if (dowritestr("RSET\r\n") == 0 && writeflush() == 0)
00414               {
00415                      if (smtpreply("RSET", del, ctf, -1))
00416                      {
00417                             quit();
00418                             return;
00419                      }
00420               }
00421        }
00422 
00423        if (sockfd < 0 && net_timeout)
00424        {
00425        time_t t;
00426 
00427               time (&t);
00428               if (t < net_timeout)
00429               {
00430                      errno=net_error;
00431                      if (!errno)   errno=ENETDOWN;
00432                      connect_error(del, ctf);
00433                      return;
00434               }
00435               net_timeout=0;
00436        }
00437 
00438        if ((cn=ctlfile_searchfirst(ctf, COMCTLFILE_MSGSOURCE)) >= 0 &&
00439            backscatter(ctf->lines[cn]+1))
00440        {
00441               int i;
00442 
00443               for (i=0; i<del->nreceipients; i++)
00444               {
00445                      ctlfile_append_connectioninfo(ctf,
00446                                                 (unsigned)
00447                                                 atol(del->receipients
00448                                                     [i*2]),
00449                                                 COMCTLFILE_DELINFO_REPLYTYPE,
00450                                                 "smtp");
00451 
00452                      ctlfile_append_connectioninfo(ctf,
00453                                                 (unsigned)
00454                                                 atol(del->receipients
00455                                                     [i*2]),
00456                                                 COMCTLFILE_DELINFO_REPLY,
00457                                                 "250 Backscatter bounce dropped.");
00458 
00459                      ctlfile_append_reply(ctf,
00460                                         (unsigned)atol( del->receipients[i*2]),
00461                                         "delivered: backscatter bounce dropped",
00462                                         COMCTLFILE_DELSUCCESS_NOLOG,
00463                                         (hasdsn ? "":" r"));
00464               }
00465               return;
00466        }
00467 
00468        /*
00469        ** If the message wants a secured connection, and the current
00470        ** connection has not been secured, close it, so it can be reopened.
00471        */
00472 
00473        smtproute=smtproutes(host, &smtproutes_flags);
00474 
00475        if (sockfd >= 0 && want_security(ctf) && !is_secure_connection)
00476               quit();
00477 
00478        if (sockfd < 0)      /* First time, connect to a server */
00479        {
00480               struct rfc1035_mxlist *mxlist, *p, *q;
00481               int static_route= smtproute != NULL;
00482               struct rfc1035_res res;
00483               int rc;
00484 
00485               errno=0;      /* Detect network failures */
00486 
00487               if (auth_key)
00488                      free(auth_key);
00489 
00490               auth_key=strdup(smtproute ? smtproute:host);
00491 
00492               if (!auth_key)
00493                      clog_msg_errno();
00494 
00495               rfc1035_init_resolv(&res);
00496 
00497               rc=rfc1035_mxlist_create_x(&res,
00498                                       auth_key,
00499                                       RFC1035_MX_AFALLBACK |
00500                                       RFC1035_MX_IGNORESOFTERR,
00501                                       &mxlist);
00502               rfc1035_destroy_resolv(&res);
00503 
00504               switch (rc)   {
00505               case RFC1035_MX_OK:
00506                      break;
00507               case RFC1035_MX_HARDERR:
00508                      if (smtproute)       free(smtproute);
00509                      hard_error(del, ctf, "No such domain.");
00510                      return;
00511               case RFC1035_MX_BADDNS:
00512                      if (smtproute)       free(smtproute);
00513                      hard_error(del, ctf,
00514                             "This domain's DNS violates RFC 1035.");
00515                      return;
00516               default:
00517                      if (smtproute)       free(smtproute);
00518                      soft_error(del, ctf, "DNS lookup failed.");
00519 
00520                      if (errno)
00521                      {
00522                             net_error=errno;
00523                             time (&net_timeout);
00524                             net_timeout += config_time_esmtpdelay();
00525                      }
00526                      return;
00527               }
00528               if (smtproute)       free(smtproute);
00529 
00530               /* Check for broken MX records - BOFH */
00531 
00532               q=0;   /* Also see if I'm in the MX list */
00533 
00534               for (p=mxlist; p; p=p->next)
00535               {
00536               RFC1035_ADDR    addr;
00537               char    buf[RFC1035_NTOABUFSIZE];
00538 
00539                      if (rfc1035_sockaddrip(&p->address,
00540                                    sizeof(p->address), &addr))
00541                             continue;
00542 
00543                      rfc1035_ntoa(&addr, buf);
00544                      if (strcmp(buf, p->hostname) == 0)
00545                      {
00546                             hard_error(del, ctf,
00547                                    "This domain's DNS violates RFC 1035.");
00548                             rfc1035_mxlist_free(mxlist);
00549                             return;
00550                      }
00551               
00552                      if (!q && !static_route &&
00553                          (config_islocal(p->hostname, 0)
00554                           || isloopback(buf)))
00555                             q=p;
00556               }
00557 
00558               if (q && q->priority == mxlist->priority)
00559               {
00560                      hard_error(del, ctf, "configuration error: mail loops back to myself (MX problem).");
00561                      rfc1035_mxlist_free(mxlist);
00562                      return;
00563               }
00564 
00565               /* Ok, try each MX server until we get through */
00566 
00567               for (p=mxlist; p; p=p->next)
00568               {
00569               RFC1035_ADDR addr;
00570               int    port;
00571               int    af;
00572               RFC1035_NETADDR addrbuf, saddrbuf;
00573               const struct sockaddr *addrptr, *saddrptr;
00574               int    addrptrlen, saddrptrlen;
00575 
00576                      if (q && q->priority == p->priority)
00577                             break;
00578                      /*
00579                      ** We're a backup MX for this domain, ignore MXs
00580                      ** with same, or higher, priority than us
00581                      */
00582 
00583                      if (rfc1035_sockaddrip(&p->address,
00584                             sizeof(p->address), &addr) ||
00585                             rfc1035_sockaddrport(&p->address,
00586                             sizeof(p->address), &port))
00587                             continue;
00588  
00589                      sockfdaddr=addr;
00590                      if (sockfdaddrname)  free(sockfdaddrname);
00591                      sockfdaddrname=strcpy(
00592                             courier_malloc(strlen(p->hostname)+1),
00593                             p->hostname); /* Save this for later */
00594 
00595                      is_secure_connection=0;
00596                      if ((sockfd=rfc1035_mksocket(SOCK_STREAM, 0, &af))
00597                                    >= 0 &&
00598                          rfc1035_mkaddress(af, &addrbuf, &addr, port,
00599                                          &addrptr, &addrptrlen) == 0 &&
00600                          get_sourceaddr(af, &addr, &saddrbuf, &saddrptr,
00601                                       &saddrptrlen) == 0 &&
00602                          rfc1035_bindsource(sockfd, saddrptr,
00603                                           saddrptrlen) == 0 &&
00604                          s_connect(sockfd, addrptr, addrptrlen,
00605                                   connect_timeout) == 0)
00606                      {
00607                             /*
00608                             ** If we're connected, make sure EHLO or HELO
00609                             ** is cool, before blessing the connection.
00610                             */
00611 
00612                      int    rc=hello(del, ctf);
00613 
00614                             if (rc == 0)
00615                             {
00616                                    if (hasstarttls && starttls(del, ctf,
00617                                           p->hostname))
00618                                    {
00619                                           sox_close(sockfd);
00620                                           return;
00621                                    }
00622                                    if (authclient(del, ctf, auth_key))
00623                                    {
00624                                           sox_close(sockfd);
00625                                           return;
00626                                    }
00627                                    break;
00628                             }
00629                             quit();       /* We don't want to talk to him */
00630                             if (rc < 0)
00631                                    return;       /* HELO failed, perm error */
00632                      }
00633                      if (sockfd >= 0)
00634                             sox_close(sockfd);
00635                      sockfd= -1;
00636 
00637 #if 0
00638                      if (p->next && p->priority == p->next->priority &&
00639                             strcmp(p->hostname, p->next->hostname) == 0)
00640                      {
00641                             continue; /* Another IP address for same MX */
00642                      }
00643 
00644                      /* Skip other MX records with the same priority */
00645                      while (p->next && p->priority == p->next->priority)
00646                             p=p->next;
00647 #endif
00648               }
00649 
00650               rfc1035_mxlist_free(mxlist);
00651               if (sockfd < 0)      /* Couldn't find an active server */
00652               {
00653                      net_error=errno;
00654                      connect_error(del, ctf);
00655                      time (&net_timeout);
00656                      net_timeout += config_time_esmtpdelay();
00657                      return;
00658               }
00659        }
00660        else
00661        {
00662               if (smtproute)
00663                      free(smtproute);
00664        }
00665 
00666        /*
00667        ** Ok, we now have a connection.  We want to call push() to deliver
00668        ** this message, but if the VERP flag is set but the remote server
00669        ** does not grok VERPs, we need to do a song-n-dance routine.
00670        */
00671 
00672        if (hasverp || ctlfile_searchfirst(ctf, COMCTLFILE_VERP) < 0)
00673        {
00674               push(del, ctf);      /* ... but not this time */
00675               return;
00676        }
00677 
00678        /*
00679        ** Ok, so what we do is to call push() individually for each
00680        ** recipient, manually munging the return address each time, and
00681        ** fudging the delivery record setting it for that one recipient
00682        ** only.
00683        */
00684 
00685        {
00686        unsigned i;
00687        unsigned real_recip=del->nreceipients;
00688 
00689               del->nreceipients=1;
00690               for (i=0; i<real_recip; i++, del->receipients += 2)
00691               {
00692               char   *verp_sender;
00693 
00694                      if (i && sockfd >= 0)       /* Call RSET in between */
00695                      {
00696                             if (rset(del, ctf))
00697                             {
00698                                    quit();
00699                                    continue;
00700                             }
00701                      }
00702                      if (sockfd < 0)
00703                      {
00704                             connect_error(del, ctf);
00705                             continue;
00706                      }
00707 
00708                      verp_sender=verp_getsender(ctf, del->receipients[1]);
00709 
00710                      del->sender=verp_sender;
00711                      push(del, ctf);
00712                      free(verp_sender);
00713               }
00714        }
00715 }
00716 
00717 /* Record a permanent failure for one, or all, recipients */
00718 
00719 static void hard_error1(struct moduledel *del, struct ctlfile *ctf,
00720               const char *msg, int n)
00721 {
00722 unsigned        i;
00723 
00724        if (n >= 0)
00725               ctlfile_append_reply(ctf,
00726                      (unsigned)atol(del->receipients[n*2]), msg,
00727                      COMCTLFILE_DELFAIL, 0);
00728        else for (i=0; i<del->nreceipients; i++)
00729               ctlfile_append_reply(ctf,
00730                      (unsigned)atol(del->receipients[i*2]), msg,
00731                      COMCTLFILE_DELFAIL, 0);
00732 }
00733 
00734 static void hard_error(struct moduledel *del, struct ctlfile *ctf,
00735               const char *msg)
00736 {
00737        hard_error1(del, ctf, msg, -1);
00738 }
00739 
00740 /* Record a temporary failure for one, or all, the recipients */
00741 
00742 static void soft_error1(struct moduledel *del, struct ctlfile *ctf,
00743        const char *msg, int n)
00744 {
00745 unsigned        i;
00746 
00747        if (n >= 0)
00748               ctlfile_append_reply(ctf,
00749                      (unsigned)atol(del->receipients[n*2]), msg,
00750                      COMCTLFILE_DELDEFERRED, 0);
00751        else for (i=0; i<del->nreceipients; i++)
00752               ctlfile_append_reply(ctf,
00753                      (unsigned)atol(del->receipients[i*2]), msg,
00754                      COMCTLFILE_DELDEFERRED, 0);
00755 }
00756 
00757 static void soft_error(struct moduledel *del, struct ctlfile *ctf,
00758        const char *msg)
00759 {
00760        soft_error1(del, ctf, msg, -1);
00761 }
00762 
00763 static void connection_closed(struct moduledel *del, struct ctlfile *ctf)
00764 {
00765        soft_error(del, ctf, "Connection unexpectedly closed by remote host.");
00766 }
00767 
00768 /* Record an SMTP error for all the recipients */
00769 
00770 static void smtp_error(struct moduledel *del, struct ctlfile *ctf,
00771                      const char *msg, int errcode)
00772 {
00773        if (!msg)
00774        {
00775               connect_error(del, ctf);
00776               return;
00777        }
00778 
00779        if (errcode == 0)
00780               errcode= *msg;
00781 
00782        if (errcode == '5')
00783               hard_error1(del, ctf, msg, -1);
00784        else
00785               soft_error1(del, ctf, msg, -1);
00786 }
00787 
00788 
00789 /* Record our peer in the message's control file, for error messages */
00790 
00791 static void sockipname(char *buf)
00792 {
00793        rfc1035_ntoa( &sockfdaddr, buf);
00794 
00795 #if    RFC1035_IPV6
00796 
00797        if (IN6_IS_ADDR_V4MAPPED(&sockfdaddr))
00798        {
00799        char   *p, *q;
00800 
00801               if ((p=strrchr(buf, ':')) != 0)
00802               {
00803                      ++p;
00804                      q=buf;
00805                      while ( (*q++ = *p++ ) )
00806                             ;
00807               }
00808        }
00809 #endif
00810 }
00811 
00812 static void talking2(struct moduledel *del, struct ctlfile *ctf, int n)
00813 {
00814 char   buf[RFC1035_NTOABUFSIZE];
00815 unsigned i;
00816 char   *p;
00817 
00818        sockipname(buf);
00819        p=courier_malloc(strlen(sockfdaddrname)+strlen(buf)+
00820               sizeof(" []"));
00821        strcat(strcat(strcat(strcpy(p, sockfdaddrname), " ["),
00822               buf), "]");
00823 
00824        if (n >= 0)
00825               ctlfile_append_connectioninfo(ctf,
00826                      (unsigned)atol(del->receipients[n*2]),
00827                      COMCTLFILE_DELINFO_PEER, p);
00828        else for (i=0; i<del->nreceipients; i++)
00829               ctlfile_append_connectioninfo(ctf,
00830                      (unsigned)atol(del->receipients[i*2]),
00831                      COMCTLFILE_DELINFO_PEER, p);
00832        free(p);
00833 }
00834 
00835 static void talking(struct moduledel *del, struct ctlfile *ctf)
00836 {
00837        talking2(del, ctf, -1);
00838 }
00839 
00840 /* TCP/IP error */
00841 
00842 static void connect_error1(struct moduledel *del, struct ctlfile *ctf, int n)
00843 {
00844 #if    HAVE_STRERROR
00845 
00846        if (errno)
00847               soft_error1(del, ctf, errno == ECONNRESET
00848                          ? "Network connection shut down by the remote mail server"
00849                          : strerror(errno), n);
00850        else
00851 #endif
00852               soft_error1(del, ctf, "Connection closed by remote host.", n);
00853 }
00854 
00855 static void connect_error(struct moduledel *del, struct ctlfile *ctf)
00856 {
00857        connect_error1(del, ctf, -1);
00858 }
00859 
00860 /* Log reply received */
00861 
00862 static void smtp_msg(struct moduledel *del, struct ctlfile *ctf)
00863 {
00864 unsigned      i;
00865 
00866        for (i=0; i<del->nreceipients; i++)
00867               ctlfile_append_connectioninfo(ctf,
00868                      (unsigned)atol(del->receipients[i*2]),
00869                      COMCTLFILE_DELINFO_REPLYTYPE, "smtp");
00870 }
00871 
00872 static void reply(struct moduledel *del, struct ctlfile *ctf, const char *msg)
00873 {
00874 unsigned        i;
00875 
00876        for (i=0; i<del->nreceipients; i++)
00877               ctlfile_append_connectioninfo(ctf,
00878                      (unsigned)atol(del->receipients[i*2]),
00879                      COMCTLFILE_DELINFO_REPLY, msg);
00880 }
00881 
00882 /* Log the command sent to remote server */
00883 
00884 static void sent(struct moduledel *del, struct ctlfile *ctf, const char *msg)
00885 {
00886 unsigned        i;
00887 
00888        for (i=0; i<del->nreceipients; i++)
00889               ctlfile_append_connectioninfo(ctf,
00890                      (unsigned)atol(del->receipients[i*2]),
00891                             COMCTLFILE_DELINFO_SENT, msg);
00892 }
00893 
00894 /***************************************************************************
00895 
00896   Socket stuff.  All socket operations have a timeout which is set separately,
00897   then we wait for the socket to be ready for reading or writing, then
00898   closing the socket if the timeout expires before the socket is ready.
00899 
00900 ***************************************************************************/
00901 
00902 /* Set the timeout */
00903 
00904 static void sock_timeout(unsigned nsecs)
00905 {
00906        time(&timeout_time);
00907        timeout_time += nsecs;
00908 }
00909 
00910 /* Wait for either a response, or availability for write, until we time out */
00911 
00912 static void wait_rw(int *waitr, int *waitw)
00913 {
00914 fd_set fdr, fdw;
00915 struct timeval       tv;
00916 time_t current_time;
00917 
00918        time( & current_time );
00919        if (waitr)    *waitr=0;
00920        if (waitw)    *waitw=0;
00921 
00922        if (current_time >= timeout_time || sockfd < 0)
00923        {
00924               errno=ETIMEDOUT;
00925               if (sockfd >= 0)
00926                      sox_close(sockfd);
00927               sockfd= -1;
00928               return;
00929        }
00930 
00931        FD_ZERO(&fdr);
00932        FD_ZERO(&fdw);
00933 
00934        if (waitr)
00935               FD_SET(sockbuf.fd, &fdr);
00936 
00937        if (waitw)
00938               FD_SET(sockbuf.fd, &fdw);
00939 
00940        tv.tv_sec= timeout_time - current_time;
00941        tv.tv_usec=0;
00942 
00943        if ( sox_select(sockbuf.fd+1, &fdr, &fdw, 0, &tv) > 0)
00944        {
00945               if (waitw && FD_ISSET(sockbuf.fd, &fdw))
00946                      *waitw=1;
00947               if (waitr && FD_ISSET(sockbuf.fd, &fdr))
00948                      *waitr=1;
00949               return;
00950        }
00951 
00952        errno=ETIMEDOUT;
00953        sox_close(sockfd);
00954        sockfd= -1;
00955 }
00956 
00957 static int wait_read()
00958 {
00959 int    flag;
00960 
00961        wait_rw(&flag, 0);
00962        return (flag ? 0:-1);
00963 }
00964 
00965 static int wait_write()
00966 {
00967 int    flag;
00968 
00969        wait_rw(0, &flag);
00970        return (flag ? 0:-1);
00971 }
00972 
00973 static void swallow(unsigned);
00974 static void burp(const char *, unsigned);
00975 
00976 /* Receive a CRLF-terminated reply from the remote server */
00977 
00978 static const char *readline()
00979 {
00980 int    c;
00981 char   cc;
00982 char   *p;
00983 unsigned cnt, i;
00984 
00985        socklinesize=0;
00986        if (sockfd < 0)      return (0);
00987        for (;;)
00988        {
00989               p=mybuf_ptr( &sockbuf );
00990               cnt=mybuf_ptrleft( &sockbuf );
00991               if (cnt == 0)
00992               {
00993                      if (wait_read())     return (0);
00994 
00995                      /* Check for unexpected shutdown */
00996 
00997                      if ((c=mybuf_get( &sockbuf )) < 0)
00998                      {
00999                             sox_close(sockfd);
01000                             sockfd= -1;
01001                             errno=ECONNRESET;
01002                             return (0);
01003                      }
01004                      p = --mybuf_ptr( &sockbuf );
01005                      cnt = ++mybuf_ptrleft( &sockbuf );
01006               }
01007               for (i=0; i<cnt; i++)
01008                      if (p[i] == '\r')
01009                             break;
01010 
01011               if (i < cnt)
01012               {
01013                      swallow(i);
01014                      (void)mybuf_get( &sockbuf );       /* Skip the CR */
01015 
01016                      for (;;)      /* Skip continuous CRs */
01017                      {
01018                             if (mybuf_ptrleft( &sockbuf ) == 0 &&
01019                                    wait_read())  return (0);
01020 
01021                             if ((c=mybuf_get( &sockbuf )) != '\r')
01022                                    break;
01023                             burp("\r", 1);
01024                      }
01025 
01026                      if (c < 0)
01027                      {
01028                             sox_close(sockfd);
01029                             sockfd= -1;
01030                             return (0);
01031                      }
01032                      if (c == '\n')       break; /* Seen CRLF */
01033                      cc=c;
01034                      burp(&cc, 1);
01035                      continue;
01036               }
01037               swallow(i);
01038        }
01039 
01040        socklinebuf[socklinesize]=0;
01041        return (socklinebuf);
01042 }
01043 
01044 /* Flush out anything that's waiting to be written out */
01045 
01046 static void doflush()
01047 {
01048 int    n;
01049 int    i;
01050 
01051        if (wait_write())
01052        {
01053               if (sockfd >= 0)
01054                      sox_close(sockfd);
01055               sockfd= -1;
01056               return;
01057        }
01058        if ((n=sox_write(sockfd, writebuf, writebufptr-writebuf)) <= 0)
01059        {
01060               if (sockfd >= 0)
01061                      sox_close(sockfd);
01062               sockfd= -1;
01063               return;
01064        }
01065 
01066        for (i=n; writebuf+i < writebufptr; i++)
01067               writebuf[i-n]=writebuf[i];
01068        writebufptr -= n;
01069        writebufleft += n;
01070 }
01071 
01072 /* Write various stuff to the socket */
01073 
01074 static int dowrite(const char *p, unsigned l)
01075 {
01076        while (l)
01077        {
01078        int n;
01079 
01080               if (sockfd < 0)      return (-1);
01081 
01082               if (writebufleft == 0)
01083               {
01084                      doflush();
01085                      continue;
01086               }
01087               if (writebufleft < l)
01088                      n=writebufleft;
01089               else
01090                      n=l;
01091 
01092               memcpy(writebufptr, p, n);
01093               p += n;
01094               l -= n;
01095               writebufptr += n;
01096               writebufleft -= n;
01097        }
01098        return (0);
01099 }
01100 
01101 static int dowritestr(const char *p)
01102 {
01103        return (dowrite(p, strlen(p)));
01104 }
01105 
01106 static int writeflush()
01107 {
01108        while (writebufptr > writebuf && sockfd >= 0)
01109               doflush();
01110        if (sockfd < 0)      return (-1);
01111        return (0);
01112 }
01113 
01114 /* Copy stuff read from socket into the line buffer */
01115 
01116 static void swallow(unsigned l)
01117 {
01118        burp(mybuf_ptr( &sockbuf ), l);
01119 
01120        mybuf_ptr( &sockbuf ) += l;
01121        mybuf_ptrleft( &sockbuf ) -= l;
01122 }
01123 
01124 /* Replies are collected into a fixed length line buffer. */
01125 
01126 static void burp(const char *p, unsigned n)
01127 {
01128        if (n > sizeof(socklinebuf)-1-socklinesize)
01129               n=sizeof(socklinebuf)-1-socklinesize;
01130        memcpy(socklinebuf+socklinesize, p, n);
01131        socklinesize += n;
01132 }
01133 
01134 /*
01135        Try EHLO then HELO, and see what the other server says.
01136 */
01137 
01138 static RFC1035_ADDR laddr;
01139 
01140 static int hello2(struct moduledel *, struct ctlfile *, int);
01141 
01142 static int hello(struct moduledel *del, struct ctlfile *ctf)
01143 {
01144        const char *p;
01145        RFC1035_NETADDR lsin;
01146        socklen_t i;
01147 
01148        i=sizeof(lsin);
01149        if (sox_getsockname(sockfd, (struct sockaddr *)&lsin, &i) ||
01150            rfc1035_sockaddrip(&lsin, i, &laddr))
01151        {
01152               soft_error1(del, ctf, "Cannot obtain local socket IP address.",
01153                          -1);
01154               return -1;
01155        }
01156 
01157        mybuf_init(&sockbuf, sockfd);
01158        writebufptr=writebuf;
01159        writebufleft=sizeof(writebuf);
01160        sock_timeout(helo_timeout);
01161        if ((p=readline()) == 0)    /* Wait for server first */
01162               return (1);
01163 
01164        if (*p == '5')       /* Hard error */
01165        {
01166               talking(del, ctf);
01167               smtp_msg(del, ctf);
01168               while (!ISFINALLINE(p))     /* Skip multiline replies */
01169               {
01170                      reply(del, ctf, p);
01171                      if ((p=readline()) == 0)
01172                             return (1);
01173                             /* Caller will report the error */
01174               }
01175               hard_error(del, ctf, p);
01176               return (-1);
01177        }
01178 
01179        if (*p != '1' && *p != '2' && *p != '3')  /* Soft error */
01180        {
01181               for (;;)
01182               {
01183                      if (ISFINALLINE(p))
01184                             break;
01185 
01186                      if ((p=readline()) == 0)
01187                      {
01188                             talking(del, ctf);
01189                             return (1);
01190                      }
01191               }
01192               quit();
01193               return (-1);  /*
01194                             ** Let caller handle this as a hard error,
01195                             ** so that it does not try the next MX.
01196                             */
01197        }
01198 
01199        /* Skip multiline good response. */
01200 
01201        while (!ISFINALLINE(p))
01202        {
01203               if ((p=readline()) == 0)
01204               {
01205                      talking(del, ctf);
01206                      return (1);
01207               }
01208        }
01209 
01210        return (hello2(del, ctf, 0));
01211 }
01212 
01213        /* Try an EHLO */
01214 
01215 static int hello2(struct moduledel *del, struct ctlfile *ctf, int using_tls)
01216 {
01217        const  char *p;
01218        char   hellobuf[512];
01219        char buf[RFC1035_MAXNAMESIZE+128];
01220 
01221        haspipelining=hasdsn=has8bitmime=hasverp=hassize=hasexdata=hascourier=
01222        hasstarttls=hassecurity_starttls=0;
01223        if (authsasllist)    free(authsasllist);
01224        authsasllist=0;
01225 
01226        p=config_esmtphelo();
01227 
01228        /*
01229        ** If the remote host is "*", use reverse DNS from the local IP addr.
01230        */
01231 
01232        if (strcmp(p, "*") == 0)
01233        {
01234               struct rfc1035_res res;
01235               int rc;
01236 
01237               rfc1035_init_resolv(&res);
01238 
01239               p=buf;
01240               rc=rfc1035_ptr(&res, &laddr, buf);
01241 
01242               rfc1035_destroy_resolv(&res);
01243 
01244               if (rc != 0)
01245               {
01246                      char *q;
01247 
01248                      rfc1035_ntoa(&laddr, buf+1);
01249 
01250                      q=buf+1;
01251 
01252                      if (strncmp(q, "::ffff:", 7) == 0)
01253                             q += 7;
01254                      *--q='[';
01255                      strcat(q, "]");
01256                      p=q;
01257               }
01258        }
01259 
01260        strcpy(hellobuf, "EHLO ");
01261        strncat(hellobuf, p, sizeof(hellobuf)-10);
01262        strcat(hellobuf, "\r\n");
01263 
01264        if (dowritestr(hellobuf) || writeflush())
01265        {
01266               talking(del, ctf);
01267               return (1);
01268        }
01269 
01270        if ((p=readline()) == 0)
01271        {
01272               talking(del, ctf);
01273               return (1);
01274        }
01275 
01276        if (*p == '5')       /* Hard error, let's try a HELO */
01277        {
01278               while (!ISFINALLINE(p))     /* Skip multiline error */
01279               {
01280                      if ((p=readline()) == 0)
01281                      {
01282                             talking(del, ctf);
01283                             return (1);
01284                      }
01285               }
01286               hellobuf[0]='H';
01287               hellobuf[1]='E';
01288 
01289               sock_timeout(helo_timeout);
01290               if (dowritestr(hellobuf) || writeflush())
01291               {
01292                      talking(del, ctf);
01293                      return (1);
01294               }
01295 
01296               if ((p=readline()) == 0)
01297               {
01298                      talking(del, ctf);
01299                      return (1);
01300               }
01301        }
01302 
01303        if (*p != '1' && *p != '2' && *p != '3') /* Some kind of an error */
01304        {
01305               talking(del, ctf);
01306               sent(del, ctf, hellobuf);
01307               smtp_msg(del, ctf);
01308               while (!ISFINALLINE(p))
01309               {
01310                      reply(del, ctf, p);
01311                      if ((p=readline()) == 0)
01312                             return (1);
01313               }
01314               smtp_error(del, ctf, p, 0);
01315               quit();
01316               return (-1);  /*
01317                             ** Let the caller consider this a hard error,
01318                             ** so that it doesn't try the next MX.
01319                             */
01320        }
01321 
01322        /*
01323        ** If we're here after a HELO, just eat it up, otherwise, we want to
01324        ** parse available ESMTP keywords.
01325        */
01326 
01327        if (hellobuf[0] == 'H')
01328        {
01329               while (!ISFINALLINE(p))
01330               {
01331                      if ((p=readline()) == 0)
01332                      {
01333                             talking(del, ctf);
01334                             return (1);
01335                      }
01336               }
01337               return (0);
01338        }
01339 
01340        if (!ISFINALLINE(p))
01341        {
01342 /*
01343 **     Read remaining lines, parse the keywords.
01344 */
01345               do
01346               {
01347               const char *q;
01348               unsigned l;
01349 
01350                      if ((p=readline()) == 0)
01351                      {
01352                             talking(del, ctf);
01353                             return (1);
01354                      }
01355 
01356                      if (!isdigit((int)(unsigned char)p[0]) ||
01357                             !isdigit((int)(unsigned char)p[1]) ||
01358                             !isdigit((int)(unsigned char)p[2]) ||
01359                             (p[3] != ' ' && p[3] != '-'))
01360                      {
01361                             continue;
01362                      }
01363                      q=p+4;
01364                      for (l=0; q[l] && q[l] != ' '; l++)
01365                      {
01366                             if (l >= sizeof(hellobuf)-1)       break;
01367                             hellobuf[l]=toupper(q[l]);
01368                      }
01369                      hellobuf[l]=0;
01370 
01371                      if (strcmp(hellobuf, "PIPELINING") == 0)
01372                             haspipelining=1;
01373                      if (strcmp(hellobuf, "DSN") == 0)
01374                             hasdsn=1;
01375                      if (strcmp(hellobuf, "8BITMIME") == 0)
01376                             has8bitmime=1;
01377                      if (strcmp(hellobuf, "SIZE") == 0)
01378                             hassize=1;
01379                      if (strcmp(hellobuf, "STARTTLS") == 0 && !(smtproutes_flags & ROUTE_NOSECURITY))
01380                             hasstarttls=1;
01381 
01382                      if (strcmp(hellobuf, "AUTH") == 0
01383                             || strncmp(hellobuf, "AUTH=", 5) == 0)
01384                      {
01385                      const char *p=q+4;
01386 
01387                             if (isspace((int)(unsigned char)*p)||*p == '=')
01388                             {
01389                             char   *s;
01390                             unsigned      l=(authsasllist ?
01391                                    strlen(authsasllist)+1: 0)+strlen(p)+1;
01392 
01393                                    if (l > 10000)       continue;
01394                                                  /* Script kiddies... */
01395                                    ++p;
01396                                    s=courier_malloc(l);
01397                                    *s=0;
01398                                    if (authsasllist)
01399                                           strcat(strcpy(s, authsasllist),
01400                                                  " ");
01401                                    strcat(s, p);
01402                                    if (authsasllist)
01403                                           free(authsasllist);
01404                                    authsasllist=s;
01405                             }
01406                      }
01407 
01408 
01409 #define       KEYWORD(x)    (strcmp(hellobuf, x) == 0)
01410 #define KEYWORDARG(x)       (strncmp(hellobuf, x, sizeof(x)-1) == 0)
01411 
01412                      if (IS_EXDATA_KEYWORD)
01413                             hasexdata=1;
01414 
01415                      if (IS_VERP_KEYWORD)
01416                      {
01417                             char *p=strchr(hellobuf, '=');
01418 
01419                             if (p)
01420                             {
01421                                    for (++p; (p=strtok(p, ",")) != 0; p=0)
01422                                           if (strcasecmp(p, "Courier")
01423                                               == 0)
01424                                                  hasverp=1;
01425                             }
01426                      }
01427 
01428                      if (IS_COURIER_EXTENSIONS)
01429                             hascourier=1;
01430 
01431                      if (IS_SECURITY_KEYWORD)
01432                      {
01433                             char *p=strchr(hellobuf, '=');
01434 
01435                             if (p)
01436                             {
01437                                    for (++p; (p=strtok(p, ",")) != 0; p=0)
01438                                           if (strcmp(p, "STARTTLS") == 0 && !(smtproutes_flags & ROUTE_NOSECURITY))
01439                                                  hassecurity_starttls=1;
01440                             }
01441                      }
01442               } while (!ISFINALLINE(p));
01443 
01444               if (!hascourier) /* No courier extensions, no EXDATA or VERP */
01445                      hasexdata=hasverp=hassecurity_starttls=0;
01446        }
01447 
01448        if (hasstarttls)
01449        {
01450               const char *q=getenv("COURIERTLS");
01451               struct stat stat_buf;
01452 
01453               if (!q || stat(q, &stat_buf))
01454                      hasstarttls=0;
01455        }
01456 
01457        if ((p=want_security(ctf)) != 0)
01458        {
01459               if ( strcmp(p, "STARTTLS") == 0)
01460               {
01461                      if ((hasstarttls || using_tls) && hassecurity_starttls)
01462                             return (0);
01463               }
01464 
01465               talking(del, ctf);
01466               sent(del, ctf, "SECURITY=STARTTLS REQUESTED FOR THIS MESSAGE");
01467               smtp_msg(del, ctf);
01468               smtp_error(del, ctf,
01469                         "500 Unable to set minimum security level.", 0);
01470               quit();
01471               return (-1);
01472        }
01473 
01474        if (hasstarttls)
01475        {
01476               const char *p=getenv("ESMTP_USE_STARTTLS");
01477 
01478               if (!p || !atoi(p))
01479                      hasstarttls=0;
01480        }
01481 
01482        if (getenv("COURIER_ESMTP_DEBUG_NO8BITMIME"))
01483               has8bitmime=0;
01484        return (0);
01485 }
01486 
01487 static void report_broken_starttls(const char *reply)
01488 {
01489        const char *cmd=getenv("TLS_ERROR_REPORT");
01490        const char *shell;
01491 
01492        char   buf[RFC1035_NTOABUFSIZE];
01493        pid_t p;
01494 
01495        if (!cmd || !*cmd)
01496               return;
01497 
01498        p=fork();
01499 
01500        if (p < 0)
01501        {
01502               clog_msg_start_err();
01503               clog_msg_str("fork() failed");
01504               clog_msg_send();
01505               return;
01506        }
01507 
01508        if (p > 0)
01509        {
01510               wait(NULL); /* Better be this child */
01511               return;
01512        }
01513 
01514        close(sockfd);
01515 
01516        p=fork();
01517 
01518        if (p)
01519               _exit(0);
01520 
01521        sockipname(buf);
01522 
01523        setenv("ERROR_HOST", sockfdaddrname ? sockfdaddrname:"", 1);
01524        setenv("ERROR_IP", buf, 1);
01525        setenv("ERROR_CODE", "STARTTLS", 1);
01526        setenv("ERROR_TEXT", reply, 1);
01527 
01528        shell=getenv("SHELL");
01529 
01530        if (!shell || !*shell)
01531               shell="/bin/sh";
01532 
01533        execl(shell, shell, "-c", cmd, NULL);
01534        _exit(1);
01535 }
01536 
01537 static int starttls(struct moduledel *del, struct ctlfile *ctf,
01538        const char *hostname)
01539 {
01540        const char *p;
01541        int    pipefd[2];
01542        int rc;
01543        const char *sec;
01544        struct couriertls_info cinfo;
01545        char   *verify_domain=0;
01546        char   localfd_buf[NUMBUFSIZE+30];
01547        char   remotefd_buf[NUMBUFSIZE+30];
01548        char   miscbuf[NUMBUFSIZE];
01549 
01550        static char *trustcert_buf=0;
01551        static char *origcert_buf=0;
01552 
01553        char *argvec[10];
01554 
01555        int restore_origcert=0;
01556        int n;
01557 
01558        const char *tls_error_handle=getenv("TLS_ERROR_HANDLE");
01559 
01560        if (!tls_error_handle)
01561               tls_error_handle="";
01562 
01563        if (libmail_streampipe(pipefd))
01564        {
01565               perror("libmail_streampipe");
01566               return (-1);
01567        }
01568 
01569        if (dowritestr("STARTTLS\r\n") || writeflush() ||
01570               (p=readline()) == 0)
01571        {
01572               talking(del, ctf);
01573               connect_error(del, ctf);
01574               close(pipefd[0]);
01575               close(pipefd[1]);
01576 
01577               report_broken_starttls("(none)");
01578 
01579               return (1);
01580        }
01581 
01582        if (*p != '1' && *p != '2' && *p != '3')
01583        {
01584               talking(del, ctf);
01585               sent(del, ctf, "STARTTLS");
01586               smtp_msg(del, ctf);
01587               close(pipefd[0]);
01588               close(pipefd[1]);
01589 
01590               report_broken_starttls(p);
01591 
01592               while (!ISFINALLINE(p))
01593               {
01594                      reply(del, ctf, p);
01595                      if ((p=readline()) == 0)
01596                             break;
01597               }
01598 
01599               if (*tls_error_handle == 'i')
01600                      return 0;
01601 
01602               smtp_error(del, ctf, p, *tls_error_handle == 's' ? '4':0);
01603               return (-1);
01604        }
01605 
01606        sec=want_security(ctf);
01607 
01608        couriertls_init(&cinfo);
01609 
01610        /*
01611        ** Make sure that our side of the pipe is closed when couriertls
01612        ** is execed by the child process.
01613        */
01614 
01615        fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);
01616 
01617        strcat(strcpy(localfd_buf, "-localfd="),
01618               libmail_str_size_t(pipefd[1], miscbuf));
01619        strcat(strcpy(remotefd_buf, "-remotefd="),
01620               libmail_str_size_t(sockfd, miscbuf));
01621 
01622        p=getenv("ESMTP_TLS_VERIFY_DOMAIN");
01623 
01624        if (sec != 0)
01625        {
01626               char *q, *r;
01627 
01628               /*
01629               ** Replace TLS_TRUSTCERTS with TLS_TRUSTSECURITYCERTS,
01630               ** until couriertls is execed.
01631               */
01632 
01633               q=getenv("TLS_TRUSTCERTS");
01634 
01635               r=courier_malloc(strlen(q ? q:"")+40);
01636               strcat(strcpy(r, "TLS_TRUSTCERTS="), q ? q:"");
01637 
01638               if (origcert_buf)
01639                      free(origcert_buf);
01640               origcert_buf=r;
01641               restore_origcert=1;
01642 
01643               p=getenv("TLS_TRUSTSECURITYCERTS");
01644               if (!p || !*p)
01645               {
01646                      static const char fail[]=
01647                             "500 Unable to set minimum security"
01648                             " level.\n";
01649 
01650                      talking(del, ctf);
01651                      sent(del, ctf, "STARTTLS");
01652                      smtp_msg(del, ctf);
01653                      smtp_error(del, ctf, fail, 0);
01654                      sox_close(sockfd);
01655                      sockfd= -1;
01656                      close(pipefd[0]);
01657                      close(pipefd[1]);
01658                      return (-1);
01659               }
01660 
01661               q=courier_malloc(strlen(p)+40);
01662 
01663               strcat(strcpy(q, "TLS_TRUSTCERTS="), p);
01664               putenv(q);
01665               p="1";
01666 
01667               if (trustcert_buf)
01668                      free(trustcert_buf);
01669               trustcert_buf=q;
01670        }
01671 
01672        if (p && atoi(p))
01673        {
01674               verify_domain=courier_malloc(sizeof("-verify=")
01675                                         +strlen(hostname));
01676               strcat(strcpy(verify_domain, "-verify="), hostname);
01677        }
01678 
01679 
01680        n=0;
01681 
01682        argvec[n++]=localfd_buf;
01683        argvec[n++]=remotefd_buf;
01684        if (verify_domain)
01685        {
01686               argvec[n++]=verify_domain;
01687        }
01688        argvec[n]=0;
01689 
01690        n=couriertls_start(argvec, &cinfo);
01691 
01692        if (restore_origcert)
01693               putenv(origcert_buf);
01694        if (verify_domain)
01695               free(verify_domain);
01696 
01697        close(sockfd);
01698        sockfd=pipefd[0];
01699        close(pipefd[1]);
01700 
01701        if (!n && fcntl(sockfd, F_SETFL, O_NONBLOCK))
01702        {
01703               perror("fcntl");
01704               n= -1;
01705               strcpy(cinfo.errmsg, "fcntl() failed");
01706        }
01707 
01708        if (n)
01709        {
01710               char tmperrbuf[sizeof(cinfo.errmsg)+10];
01711 
01712               talking(del, ctf);
01713               sent(del, ctf, "STARTTLS");
01714 
01715               smtp_msg(del, ctf);
01716               strcat(strcpy(tmperrbuf,
01717                            *tls_error_handle == 's' ? "400 ":"500 "),
01718                      cinfo.errmsg);
01719               smtp_error(del, ctf, tmperrbuf, 0);
01720               sox_close(sockfd);
01721               sockfd= -1;
01722               couriertls_destroy(&cinfo);
01723               return (-1);
01724        }
01725        couriertls_destroy(&cinfo);
01726 
01727        /* Reset the socket buffer structure given the new filedescriptor */
01728 
01729        mybuf_init(&sockbuf, sockfd);
01730        writebufptr=writebuf;
01731        writebufleft=sizeof(writebuf);
01732 
01733        /* Ask again for an EHLO, because the capabilities may differ now */
01734 
01735        rc=hello2(del, ctf, 1);
01736 
01737        if (rc > 0)
01738               connection_closed(del, ctf);       /* Make sure to log it */
01739        else
01740               is_secure_connection= sec != 0;
01741        return (rc);
01742 
01743 }
01744 /*
01745 ** Send a QUIT, and shut down the connection
01746 */
01747 
01748 static void quit()
01749 {
01750 const char *p;
01751 
01752        if (sockfd < 0)      return;
01753 
01754        sock_timeout(quit_timeout);
01755        if (dowritestr("QUIT\r\n") || writeflush())      return;
01756 
01757        while ((p=readline()) != 0 && !ISFINALLINE(p))
01758               ;
01759        if (sockfd >= 0)
01760               sox_close(sockfd);
01761        sockfd= -1;
01762 }
01763 
01764 /* Parse a reply to a SMTP command that applies to all recipients */
01765 
01766 static int smtpreply(const char *cmd,
01767        struct moduledel *del, struct ctlfile *ctf, int istalking)
01768 {
01769 const char *p;
01770 unsigned line_num;
01771 
01772        if ((p=readline()) == 0)
01773        {
01774               if (istalking < 0)   return (0);
01775 
01776               if (!istalking)
01777                      talking(del, ctf);
01778               connect_error(del, ctf);
01779               quit();
01780               return (-1);
01781        }
01782 
01783        line_num=0;
01784 
01785        switch (SMTPREPLY_TYPE(p))  {
01786        case COMCTLFILE_DELDEFERRED:
01787        case COMCTLFILE_DELFAIL:
01788 
01789               if (!istalking || istalking < 0)
01790                      talking(del, ctf);
01791               sent(del, ctf, cmd);
01792               smtp_msg(del, ctf);
01793               while (!ISFINALLINE(p))
01794               {
01795                      if (line_num < 10)   /* We record up to 10 lines
01796                                           ** of the reply in our log
01797                                           ** files.
01798                                           */
01799                      {
01800                             reply(del, ctf, p);
01801                             ++line_num;
01802                      }
01803                      if ((p=readline()) == 0)
01804                      {
01805                             connect_error(del, ctf);
01806                             quit();
01807                             return (-1);
01808                      }
01809               }
01810               smtp_error(del, ctf, p, 0);
01811               return (-1);
01812        }
01813 
01814        while (!ISFINALLINE(p))
01815        {
01816               if ((p=readline()) == 0)
01817               {
01818                      if (!istalking || istalking < 0)
01819                             talking(del, ctf);
01820                      connect_error(del, ctf);
01821                      quit();
01822                      return (-1);
01823               }
01824        }
01825        return (0);
01826 }
01827 
01828 /* Send an SMTP command that applies to all recipients, then wait for a reply */
01829 
01830 static int smtpcommand(const char *cmd,
01831        struct moduledel *del, struct ctlfile *ctf, int istalking)
01832 {
01833        if (dowritestr(cmd) || writeflush())
01834        {
01835               if (!istalking)
01836                      talking(del, ctf);
01837               connect_error(del, ctf);
01838               quit();
01839               return (-1);
01840        }
01841        return (smtpreply(cmd, del, ctf, istalking));
01842 }
01843 
01844 
01845 static int rset(struct moduledel *del, struct ctlfile *ctf)
01846 {
01847        sock_timeout(helo_timeout);
01848        return (smtpcommand("RSET\r\n", del, ctf, 0));
01849 }
01850 
01851 static void pushdsn(struct moduledel *, struct ctlfile *);
01852 
01853 /*
01854 **     We now resolved issues with VERP support.  Resolve issues with
01855 **     DSNs.  The next function to call is pushdsn.  The following issue
01856 **     is resolved here: sending a message to a server that does not
01857 **     support DSNs.  In this situation what we want to do is to send
01858 **     all recipients with a NOTIFY=NEVER in a transaction where MAIL FROM
01859 **     is <>.  Everyone else is sent in a separate transaction.
01860 **
01861 **     If this is not applicable (the remote server supports DSNs), we
01862 **     simply call pushdsn() to continue with the delivery attempt.
01863 **     Otherwise we call pushdsn() twice.
01864 */
01865 
01866 static void push(struct moduledel *del, struct ctlfile *ctf)
01867 {
01868 unsigned      i;
01869 char   **real_receipients;
01870 const char    *real_sender;
01871 int    pass;
01872 unsigned real_nreceipients;
01873 
01874        real_sender=del->sender;
01875        real_receipients=del->receipients;
01876        real_nreceipients=del->nreceipients;
01877 
01878        if (real_nreceipients == 0) return;
01879 
01880        /* If the sender is <> already, I don't care */
01881 
01882        if (hasdsn || real_sender == 0 || *real_sender == '\0')
01883        {
01884               pushdsn(del, ctf);
01885               return;
01886        }
01887 
01888        /*
01889        ** If the remote MTA does not support DSNs, and we have some
01890        ** receipients with NOTIFY=NEVER, what we do is set the MAIL FROM:
01891        ** for those recipients to <>.  We call pushdsn twice, once for
01892        ** receipients with NOTIFY=NEVER, and once more for ones without
01893        ** NOTIFY=NEVER.
01894        */
01895 
01896        del->receipients=(char **)courier_malloc(
01897                      sizeof(char *)*2*del->nreceipients);
01898 
01899        for (pass=0; pass<2; pass++)
01900        {
01901               if (pass)     del->sender="";
01902               del->nreceipients=0;
01903 
01904               for (i=0; i<real_nreceipients; i++)
01905               {
01906               const char *dsnptr=ctf->dsnreceipients[
01907                      atol(real_receipients[i*2])];
01908 
01909                      if (dsnptr && strchr(dsnptr, 'N'))
01910                      {
01911                             if (pass == 0)       continue;
01912                      }
01913                      else
01914                      {
01915                             if (pass == 1)       continue;
01916                      }
01917                      del->receipients[del->nreceipients*2]=
01918                             real_receipients[i*2];
01919                      del->receipients[del->nreceipients*2+1]=
01920                             real_receipients[i*2+1];
01921                      ++del->nreceipients;
01922               }
01923               if (del->nreceipients == 0) continue;
01924               pushdsn(del, ctf);
01925        }
01926        free(del->receipients);
01927        del->receipients=real_receipients;
01928        del->nreceipients=real_nreceipients;
01929        del->sender=real_sender;
01930 }
01931 
01932 /*
01933 ** Construct the MAIL FROM: command, taking into account ESMTP capabilities
01934 ** of the remote server.
01935 */
01936 
01937 static char *mailfrom(struct moduledel *del, struct ctlfile *ctf,
01938        int messagefd, int is8bitmsg)
01939 {
01940 char   *bodyverb="", *verpverb="", *retverb="";
01941 char   *oenvidverb="", *sizeverb="";
01942 const char *seclevel="";
01943 char   *mailfromcmd;
01944 int    n;
01945 struct stat stat_buf;
01946 const char *sec=want_security(ctf);
01947 
01948 static const char seclevel_starttls[]=" SECURITY=STARTTLS";
01949 
01950        if (has8bitmime)     /* ESMTP 8BITMIME capability */
01951               bodyverb= is8bitmsg ? " BODY=8BITMIME":" BODY=7BIT";
01952 
01953        if (hasverp && ctlfile_searchfirst(ctf, COMCTLFILE_VERP) >= 0)
01954               verpverb=" VERP";    /* ESMTP VERP capability */
01955 
01956        /* ESMTP DSN capability */
01957        if (hasdsn && (n=ctlfile_searchfirst(ctf, COMCTLFILE_DSNFORMAT)) >= 0)
01958               retverb=strchr(ctf->lines[n]+1, 'F') ? " RET=FULL":
01959                      strchr(ctf->lines[n]+1, 'H') ? " RET=HDRS":"";
01960        if (hasdsn && (n=ctlfile_searchfirst(ctf, COMCTLFILE_ENVID)) >= 0 &&
01961                      ctf->lines[n][1])
01962        {
01963               oenvidverb=courier_malloc(sizeof(" ENVID=")+
01964                      strlen(ctf->lines[n]+1));
01965               strcat(strcpy(oenvidverb, " ENVID="), ctf->lines[n]+1);
01966        }
01967 
01968        /* ESMTP SIZE capability */
01969 
01970        if (fstat(messagefd, &stat_buf) == 0)
01971        {
01972               ctf->msgsize=stat_buf.st_size;
01973 
01974               if (hassize)
01975               {
01976                      off_t s=stat_buf.st_size;
01977                      char   buf[MAXLONGSIZE+1];
01978 
01979                      s= s/75 * 77+256;    /* Size estimate */
01980                      if (!has8bitmime && is8bitmsg)
01981                             s=s/70 * 100;
01982                      sprintf(buf, "%lu", (unsigned long)s);
01983                      sizeverb=courier_malloc(sizeof(" SIZE=")+strlen(buf));
01984                      strcat(strcpy(sizeverb, " SIZE="), buf);
01985               }
01986        }
01987 
01988        /* SECURITY extension */
01989 
01990        if (sec && strcmp(sec, "STARTTLS") == 0)
01991               seclevel=seclevel_starttls;
01992 
01993        mailfromcmd=courier_malloc(sizeof("MAIL FROM:<>\r\n")+
01994                                strlen(del->sender)+
01995                                strlen(bodyverb)+
01996                                strlen(verpverb)+
01997                                strlen(retverb)+
01998                                strlen(oenvidverb)+
01999                                strlen(sizeverb)+
02000                                strlen(seclevel));
02001 
02002        strcat(strcat(strcat(strcat(strcat(
02003               strcat(strcat(strcat(strcat(strcpy(
02004                                              mailfromcmd, "MAIL FROM:<"),
02005                                        del->sender),
02006                                  ">"),
02007                            bodyverb),
02008                      verpverb),
02009               retverb),
02010                                 oenvidverb),
02011                           sizeverb),
02012                     seclevel),
02013               "\r\n");
02014 
02015        if (*oenvidverb)     free(oenvidverb);
02016        if (*sizeverb)              free(sizeverb);
02017        return (mailfromcmd);
02018 }
02019 
02020 /*
02021 ** Construct the RCPT TO command along the same lines.
02022 */
02023 
02024 static char *rcptcmd(struct moduledel *del,
02025        struct ctlfile *ctf, unsigned rcptnum)
02026 {
02027 char notify[sizeof(" NOTIFY=SUCCESS,FAILURE,DELAY")];
02028 char *orcpt="";
02029 const char *p;
02030 char   *q;
02031 unsigned n=atol(del->receipients[rcptnum*2]);
02032 
02033        notify[0]=0;
02034        if ((p=ctf->dsnreceipients[n]) != 0 && *p && hasdsn)
02035        {
02036        int s=0,f=0,d=0,n=0;
02037 
02038               while (*p)
02039                      switch (*p++) {
02040                      case 'N':
02041                             n=1;
02042                             break;
02043                      case 'D':
02044                             d=1;
02045                             break;
02046                      case 'F':
02047                             f=1;
02048                             break;
02049                      case 'S':
02050                             s=1;
02051                             break;
02052                      }
02053               if (n)
02054                      strcpy(notify, " NOTIFY=NEVER");
02055               else
02056               {
02057                      p=" NOTIFY=";
02058                      if (s)
02059                      {
02060                             strcat(strcat(notify, p), "SUCCESS");
02061                             p=",";
02062                      }
02063                      if (f)
02064                      {
02065                             strcat(strcat(notify, p), "FAILURE");
02066                             p=",";
02067                      }
02068                      if (d)
02069                             strcat(strcat(notify, p), "DELAY");
02070               }
02071        }
02072 
02073        if ((p=ctf->oreceipients[n]) != 0 && *p && hasdsn)
02074        {
02075               orcpt=courier_malloc(sizeof(" ORCPT=")+strlen(p));
02076               strcat(strcpy(orcpt, " ORCPT="), p);
02077        }
02078 
02079        p=del->receipients[rcptnum*2+1];
02080 
02081        q=courier_malloc(sizeof("RCPT TO:<>\r\n")+strlen(p)+strlen(notify)+
02082               strlen(orcpt));
02083 
02084        strcat(strcat(strcat(strcat(strcat(strcpy(q,
02085               "RCPT TO:<"),
02086               p),
02087               ">"),
02088               notify),
02089               orcpt),
02090               "\r\n");
02091        if (*orcpt)   free(orcpt);
02092        return (q);
02093 }
02094 
02095 /***************************************************************************/
02096 /*                             RCPT TO                                     */
02097 /***************************************************************************/
02098 
02099 /*
02100 ** do_pipeline_rcpt handles a pipeline RCPT TO command set.  That is, all
02101 ** the RCPT TOs are written at once, and we read the reply from the server
02102 ** in parallel.
02103 **
02104 ** If the remote server does not support PIPELINING, a tiny hack in the
02105 ** write logic arranges for non-pipelined RCPT TO command set.
02106 **
02107 ** ( DATA is also pipelined! )
02108 */
02109 
02110 static const char *readpipelinercpt( struct iovec **, unsigned *);
02111 
02112 static int parsedatareply(struct moduledel *, struct ctlfile *,
02113        int *, struct iovec **, unsigned *, int);
02114 
02115 static int do_pipeline_rcpt(struct moduledel *del,
02116        struct ctlfile *ctf,
02117        int *rcptok)
02118 {
02119 char   **cmdarray;
02120 struct iovec *iov;
02121 struct iovec *       iovw;
02122 unsigned      niovw;
02123 
02124 unsigned i;
02125 const char *p;
02126 
02127 int    rc=0;
02128 
02129        /* Construct all the RCPT TOs we'll issue. */
02130 
02131        cmdarray=(char **)courier_malloc(sizeof(char *)*
02132               (del->nreceipients+1));     /* 1 extra PTR for the DATA */
02133        iov=(struct iovec *)courier_malloc(sizeof(struct iovec)*
02134               (del->nreceipients+1));
02135 
02136        /* Allocate cmdarray[], also set up iovecs to point to each cmd */
02137 
02138        for (i=0; i <= del->nreceipients; i++)
02139        {
02140               cmdarray[i]= i < del->nreceipients ?  rcptcmd(del, ctf, i):
02141                             strcpy(courier_malloc(sizeof("DATA\r\n")),
02142                                           "DATA\r\n");
02143               iov[i].iov_base=(caddr_t)cmdarray[i];
02144               iov[i].iov_len=strlen(cmdarray[i]);
02145        }
02146 
02147        iovw=iov;
02148        niovw= i;
02149 
02150        if (haspipelining)   /* One timeout */
02151               sock_timeout(cmd_timeout);
02152 
02153        /* Read replies for the RCPT TO commands */
02154 
02155        for (i=0; i<del->nreceipients; i++)
02156        {
02157        char   err_code=0;
02158        unsigned line_num=0;
02159 
02160               /* If server can't do pipelining, just set niovw to one!!! */
02161 
02162               if (!haspipelining)
02163               {
02164                      iovw=iov+i;
02165                      niovw=1;
02166                      sock_timeout(cmd_timeout);
02167               }
02168 
02169               do
02170               {
02171                      if ((p=readpipelinercpt( &iovw, &niovw)) == 0)
02172                             break;
02173 
02174                      if (line_num == 0)
02175                             err_code= *p;
02176 
02177                      if ( SMTPREPLY_TYPE(&err_code) ==
02178                             COMCTLFILE_DELSUCCESS)
02179                             continue;
02180 
02181                      if (line_num >= 10)  continue;
02182                      /* Ignore SMTP replies longer than 10 lines */
02183 
02184                      if (line_num == 0)
02185                      {
02186                             ctlfile_append_connectioninfo(ctf,
02187                                    (unsigned)atol(del->receipients[i*2]),
02188                                    COMCTLFILE_DELINFO_SENT,
02189                                    cmdarray[i]);
02190                             ctlfile_append_connectioninfo(ctf,
02191                                    (unsigned)atol(del->receipients[i*2]),
02192                                    COMCTLFILE_DELINFO_REPLYTYPE,
02193                                    "smtp");
02194                      }
02195                      ctlfile_append_connectioninfo(ctf,
02196                             (unsigned)atol(del->receipients[i*2]),
02197                                    COMCTLFILE_DELINFO_REPLY, p);
02198               } while (!ISFINALLINE(p));
02199 
02200               if (!p)
02201               {
02202                      while (i < del->nreceipients)
02203                             rcptok[i++]=1;
02204                      break;
02205               }
02206 
02207               if ( SMTPREPLY_TYPE(&err_code) == COMCTLFILE_DELSUCCESS)
02208               {
02209                      rcptok[i]=1;  /* This recipient was accepted */
02210                      continue;
02211               }
02212 
02213               /* Failed.  Report it */
02214 
02215               rcptok[i]=0;
02216 
02217               if (SMTPREPLY_TYPE(&err_code) == COMCTLFILE_DELFAIL)
02218                      hard_error1(del, ctf, 0, i);
02219               else
02220                      soft_error1(del, ctf, 0, i);
02221        }
02222 
02223 /* ------------------- Read the reply to the DATA ----------------- */
02224 
02225        if (sockfd >= 0)
02226        {
02227               if (!haspipelining)  /* DATA hasn't been sent yet */
02228               {
02229                      for (i=0; i<del->nreceipients; i++)
02230                             if (rcptok[i])       break;
02231 
02232                      if (i >= del->nreceipients) return (-1);
02233                                    /* All RCPT TOs failed */
02234 
02235                      iovw=iov+del->nreceipients;
02236                      niovw=1;
02237                      sock_timeout(cmd_timeout);
02238               }
02239               rc=parsedatareply(del, ctf, rcptok, &iovw, &niovw, 0);
02240                      /* One more reply */
02241        }
02242 
02243        if (sockfd < 0)
02244        {
02245               for (i=0; i<del->nreceipients; i++)
02246               {
02247                      if (!rcptok[i])      continue;
02248                      connect_error1(del, ctf, i);
02249               }
02250               rc= -1;
02251        }
02252 
02253        for (i=0; i<del->nreceipients; i++)
02254               free(cmdarray[i]);
02255        free(cmdarray);
02256        free(iov);
02257        return (rc);
02258 }
02259 
02260 /* Sigh... When SOCKSv5 supports writev, I'll be happy... */
02261 
02262 static int my_writev(int fd, const struct iovec *vector, size_t count)
02263 {
02264 char   buf[BUFSIZ];
02265 size_t i=0;
02266 
02267        while (count)
02268        {
02269               if (vector->iov_len > sizeof(buf)-i)      break;
02270 
02271               memcpy(buf+i, vector->iov_base, vector->iov_len);
02272               i += vector->iov_len;
02273               ++vector;
02274               --count;
02275        }
02276        if (i)
02277               return (sox_write(fd, buf, i));
02278 
02279        return (sox_write(fd, vector->iov_base, vector->iov_len));
02280 }
02281 
02282 /* Read an SMTP reply line in pipeline mode */
02283 
02284 static const char *readpipelinercpt(
02285               struct iovec **iovw, /* Write pipeline */
02286               unsigned *niovw)
02287 {
02288 int    read_flag, write_flag, *writeptr;
02289 
02290        if (sockfd < 0)      return (0);
02291 
02292        if (mybuf_more(&sockbuf))
02293               return (readline()); /* We have the reply buffered */
02294 
02295        do
02296        {
02297               write_flag=0;
02298               writeptr= &write_flag;
02299               if (iovw == 0 || niovw == 0 || *niovw == 0)
02300                      writeptr=0;
02301 
02302               wait_rw(&read_flag, writeptr);
02303 
02304               if (write_flag)      /* We can squeeze something out now */
02305               {
02306               int    n=my_writev(sockfd, *iovw, *niovw);
02307 
02308                      if (n < 0)
02309                      {
02310                             sox_close(sockfd);
02311                             sockfd=-1;
02312                             return (0);
02313                      }
02314 
02315                      /* Update iovecs to reflect # bytes written */
02316 
02317                      while (n)
02318                      {
02319                             if (n < (*iovw)->iov_len)
02320                             {
02321                                    (*iovw)->iov_base=(caddr_t)
02322                                           ( (char *)(*iovw)->iov_base+n);
02323                                    (*iovw)->iov_len -= n;
02324                                    break;
02325                             }
02326                             n -= (*iovw)->iov_len;
02327                             ++*iovw;
02328                             --*niovw;
02329                      }
02330               }
02331        } while (!read_flag && sockfd >= 0);
02332 
02333        return (readline());
02334 }
02335 
02336 /***************************************************************************/
02337 /*                               DATA                                      */
02338 /***************************************************************************/
02339 
02340 /*
02341 ** Parse the reply to the DATA command.
02342 ** This is called to parse both the first reply (isfinal=0), and the
02343 ** second reply after the message has been sent (isfinal=1).
02344 **
02345 ** When isfinal=0, if this is called as part of pipelined commands,
02346 ** iovw/niovw must be initialized appropriately, otherwise they must be null.
02347 */
02348 
02349 static int parseexdatareply(const char *, struct moduledel *, struct ctlfile *,
02350        int *);
02351 
02352 static char *logsuccessto()
02353 {
02354 char   buf[RFC1035_NTOABUFSIZE];
02355 char   *p;
02356 
02357        sockipname(buf);
02358        p=courier_malloc(sizeof("delivered:  []")+
02359               (sockfdaddrname ?
02360                      strlen(sockfdaddrname):0)+strlen(buf));
02361 
02362        strcpy(p, "delivered: ");
02363        if (sockfdaddrname && *sockfdaddrname)
02364               strcat(strcat(p, sockfdaddrname), " ");
02365        strcat(p, "[");
02366        strcat(p, buf);
02367        strcat(p, "]");
02368        return (p);
02369 }
02370 
02371 static int parsedatareply(struct moduledel *del, struct ctlfile *ctf,
02372        int *rcptok, struct iovec **iovw, unsigned *niovw, int isfinal)
02373 {
02374 const char *p;
02375 unsigned line_num=0;
02376 unsigned i;
02377 
02378        p=readpipelinercpt(iovw, niovw);
02379 
02380        if (!p)       return (-1);
02381 
02382        if (SMTPREPLY_TYPE(p) == COMCTLFILE_DELSUCCESS)
02383        {
02384               /*
02385               ** DATA went through.  What we do depends on whether this is
02386               ** the first or the last DATA.
02387               */
02388 
02389               for (;;)
02390               {
02391                      if (isfinal && line_num < 10)
02392                      {
02393                             /* We want to record the final DATA reply in
02394                             ** the log.
02395                             */
02396 
02397                             for (i=0; i<del->nreceipients; i++)
02398                             {
02399                                    if (!rcptok[i])      continue;
02400 
02401                                    if (line_num == 0)
02402                                           ctlfile_append_connectioninfo(
02403                                                  ctf,
02404                                           (unsigned)atol(
02405                                                  del->receipients[i*2]),
02406                                           COMCTLFILE_DELINFO_REPLYTYPE,
02407                                           "smtp");
02408 
02409                                    ctlfile_append_connectioninfo(ctf,
02410                                           (unsigned)atol(
02411                                                  del->receipients[i*2]),
02412                                           COMCTLFILE_DELINFO_REPLY, p);
02413                             }
02414                             ++line_num;
02415                      }
02416                      if (ISFINALLINE(p))  break;
02417                      if ((p=readline()) == 0)
02418                             return (-1);
02419               }
02420 
02421               if (isfinal)
02422               {
02423               char   *p=logsuccessto();
02424 
02425                      /*
02426                      ** Final reply - record a success for recipients that
02427                      ** haven't previously failed (in RCPT TO).
02428                      */
02429 
02430                      for (i=0; i<del->nreceipients; i++)
02431                      {
02432                             if (!rcptok[i])      continue;
02433 
02434                             ctlfile_append_reply(ctf,
02435                                    (unsigned)atol(del->receipients[i*2]),
02436                                    p, COMCTLFILE_DELSUCCESS_NOLOG,
02437                                    (hasdsn ? "":" r"));
02438                      }
02439                      free(p);
02440               }
02441               else
02442               {
02443                      /* Good response to the first DATA */
02444 
02445                      for (i=0; i<del->nreceipients; i++)
02446                             if (rcptok[i]) break;
02447 
02448                      if (i >= del->nreceipients)
02449                             /* Stupid server wants message with no
02450                             ** receipients
02451                             */
02452                      {
02453                             sock_timeout(data_timeout);
02454                             if (dowritestr(".\r\n") || writeflush())
02455                                    return (-1);
02456                             do
02457                             {
02458                                    p=readline();
02459                                    if (!p)       return (-1);
02460                             } while (!ISFINALLINE(p));
02461                             return (-1);
02462                      }
02463               }
02464               return (0);
02465        }
02466 
02467        /* DATA error */
02468 
02469        if (hasexdata && isfinal && *p == '5' && p[1] == '5'  && p[2] == '8')
02470               return (parseexdatareply(p, del, ctf, rcptok));
02471               /* Special logic for EXDATA extended replies */
02472 
02473        /* Fail the recipients that haven't been failed already */
02474 
02475        for (i=0; i<del->nreceipients; i++)
02476        {
02477               if (!rcptok[i])      continue;
02478               ctlfile_append_connectioninfo(ctf,
02479                      (unsigned)atol(del->receipients[i*2]),
02480                      COMCTLFILE_DELINFO_SENT, "DATA");
02481 
02482               ctlfile_append_connectioninfo(ctf,
02483                      (unsigned)atol(del->receipients[i*2]),
02484                      COMCTLFILE_DELINFO_REPLYTYPE, "smtp");
02485        }
02486 
02487        for (;;)
02488        {
02489               if (line_num < 10)
02490               {
02491                      for (i=0; i<del->nreceipients; i++)
02492                      {
02493                             if (!rcptok[i])      continue;
02494 
02495                             ctlfile_append_connectioninfo(ctf,
02496                                    (unsigned)atol(
02497                                           del->receipients[i*2]),
02498                                    COMCTLFILE_DELINFO_REPLY, p);
02499                      }
02500                      ++line_num;
02501               }
02502               if (ISFINALLINE(p))
02503               {
02504                      for (i=0; i<del->nreceipients; i++)
02505                      {
02506                             if (!rcptok[i])      continue;
02507 
02508                             if (SMTPREPLY_TYPE(p) == COMCTLFILE_DELFAIL)
02509                                    hard_error1(del, ctf, "", i);
02510                             else
02511                                    soft_error1(del, ctf, "", i);
02512                             rcptok[i]=0;
02513                      }
02514                      break;
02515               }
02516               if ((p=readline()) == 0)
02517                      return (-1);
02518        }
02519        return (-1);
02520 }
02521 
02522 /*
02523 ** Parse EXDATA 558 reply.
02524 **
02525 ** See draft-varshavchik-exdata-smtpext.txt for more information.
02526 */
02527 
02528 static int parseexdatareply(const char *p,
02529        struct moduledel *del, struct ctlfile *ctf, int *rcptok)
02530 {
02531 unsigned i;
02532 char err_code=0;
02533 unsigned line_num=0;
02534 
02535        for (i=0; i<del->nreceipients; i++)
02536               if (rcptok[i])       break;
02537 
02538        /* i is the next recipient that's getting an extended reply */
02539 
02540        for (;;p=readline())
02541        {
02542               if (!p)       return (-1);
02543 
02544               if (!isdigit((int)(unsigned char)*p) ||
02545                      !isdigit((int)(unsigned char)p[1]) ||
02546                      !isdigit((int)(unsigned char)p[2]) || !p[3])
02547                      continue;
02548 
02549               if (line_num == 0)
02550                      err_code=p[4];
02551 
02552               if (i >= del->nreceipients) /* Bad extended reply */
02553               {
02554                      if (ISFINALLINE(p))  break;
02555                      continue;
02556               }
02557 
02558               if (line_num == 0 &&
02559                      SMTPREPLY_TYPE(&err_code) != COMCTLFILE_DELSUCCESS)
02560               {
02561                      ctlfile_append_connectioninfo( ctf,
02562                             (unsigned)atol(del->receipients[i*2]),
02563                             COMCTLFILE_DELINFO_SENT, "DATA");
02564               }
02565 
02566               if (line_num == 0)
02567                      ctlfile_append_connectioninfo( ctf,
02568                             (unsigned)atol(del->receipients[i*2]),
02569                             COMCTLFILE_DELINFO_REPLYTYPE, "smtp");
02570 
02571 
02572               if (line_num < 10)
02573               {
02574                      ctlfile_append_connectioninfo(ctf,
02575                             (unsigned)atol(del->receipients[i*2]),
02576                             COMCTLFILE_DELINFO_REPLY, p+4);
02577                      ++line_num;
02578               }
02579 
02580               if (ISFINALLINE((p+4)))
02581               {
02582                      switch (SMTPREPLY_TYPE( &err_code))       {
02583                      case COMCTLFILE_DELFAIL:
02584                             hard_error1(del, ctf, "", i);
02585                             rcptok[i]=0;
02586                             break;
02587                      case COMCTLFILE_DELSUCCESS:
02588                             {
02589                             char   *p=logsuccessto();
02590 
02591                             ctlfile_append_reply(ctf,
02592                                    (unsigned)atol( del->receipients[i*2]),
02593                                    p, COMCTLFILE_DELSUCCESS_NOLOG,
02594                                    (hasdsn ? "":" r"));
02595 
02596                                    free(p);
02597                             }
02598                             break;
02599                      default:
02600                             soft_error1(del, ctf, "", i);
02601                             rcptok[i]=0;
02602                             break;
02603                      }
02604 
02605                      /* Find next recipient that gets an extended reply */
02606 
02607                      while (i < del->nreceipients &&
02608                             !rcptok[++i])
02609                             ;
02610                      line_num=0;
02611               }
02612               if (ISFINALLINE(p))  break;
02613        }
02614 
02615        while (i < del->nreceipients)
02616               if (rcptok[++i])
02617               {
02618                      hard_error1(del, ctf,
02619                             "Invalid 558 response from server.", i);
02620                      rcptok[i]=0;
02621               }
02622 
02623        return (0);
02624 }
02625 
02626 static void call_rewrite_func(struct rw_info *p, void (*f)(struct rw_info *),
02627               void *arg)
02628 {
02629        (*rewrite_func)(p, f);
02630 }
02631 
02632 /* Write out .\r\n, then wait for the DATA reply */
02633 
02634 static int data_wait(struct moduledel *del, struct ctlfile *ctf, int *rcptok)
02635 {
02636        sock_timeout(data_timeout);
02637        if (dowrite(".\r\n", 3) || writeflush())  return (-1);
02638 
02639        cork(0);
02640 
02641        (void)parsedatareply(del, ctf, rcptok, 0, 0, 1);
02642 
02643        if (sockfd < 0)      return (-1);
02644        return (0);
02645 }
02646 
02647 static void parserfc(int fd, struct rfc2045 *rfcp)
02648 {
02649 char   buf[8192];
02650 int    n;
02651 
02652        while ((n=sox_read(fd, buf, sizeof(buf))) > 0)
02653               rfc2045_parse(rfcp, buf, n);
02654 }
02655 
02656 /*
02657 ** Ok, everything above is collected into a nice, tight, package.
02658 */
02659 
02660 struct rw_for_esmtp {
02661 
02662        /* State flags for converting msg to ESMTP format */
02663 
02664        int    is_sol;
02665 
02666        unsigned byte_counter;
02667        } ;
02668 
02669 static int convert_to_crlf(const char *, unsigned, void *);
02670 
02671 static void pushdsn(struct moduledel *del, struct ctlfile *ctf)
02672 {
02673 unsigned i;
02674 int    *rcptok;
02675 int    fd;
02676 char   *mailfroms;
02677 struct rfc2045 *rfcp=0;
02678 int    is8bitmsg;
02679 
02680        if ((fd=open(qmsgsdatname(del->inum), O_RDONLY)) < 0)
02681        {
02682               connect_error1(del, ctf, -1);
02683               return;
02684        }
02685 
02686        is8bitmsg=ctlfile_searchfirst(ctf, COMCTLFILE_8BIT) >= 0;
02687        if ((mailfroms=mailfrom(del, ctf, fd, is8bitmsg)) == 0)
02688        {
02689               sox_close(fd);
02690               return;
02691        }
02692 
02693        talking(del, ctf);
02694        sock_timeout(cmd_timeout);
02695 
02696        if (dowritestr(mailfroms) || writeflush())
02697        {
02698               sox_close(fd);
02699               free(mailfroms);
02700               connect_error(del, ctf);
02701               quit();
02702               return;
02703        }
02704 
02705        /*
02706        ** While waiting for MAIL FROM to come back, check if the message
02707        ** needs to be converted to quoted-printable.
02708        */
02709 
02710        if (!has8bitmime && is8bitmsg)
02711        {
02712               rfcp=rfc2045_alloc_ac();
02713               if (!rfcp)    clog_msg_errno();
02714               parserfc(fd, rfcp);
02715 
02716               rfc2045_ac_check(rfcp, RFC2045_RW_7BIT);
02717        }
02718 
02719        if (smtpreply(mailfroms, del, ctf, 1))    /* MAIL FROM rejected */
02720        {
02721               if (rfcp)     rfc2045_free(rfcp);
02722               sox_close(fd);
02723 
02724               free(mailfroms);
02725               return;
02726        }
02727        free(mailfroms);
02728 
02729        rcptok=courier_malloc(sizeof(int)*(del->nreceipients+1));
02730 
02731        if ( do_pipeline_rcpt(del, ctf, rcptok) )
02732        {
02733               if (rfcp)     rfc2045_free(rfcp);
02734               free(rcptok);
02735               sox_close(fd);
02736               return;
02737        }
02738 
02739        {
02740        struct rw_for_esmtp rfe;
02741 
02742               rfe.is_sol=1;
02743               rfe.byte_counter=0;
02744 
02745               cork(1);
02746 
02747               if ((rfcp ?
02748                      rw_rewrite_msg_7bit(fd, rfcp,
02749                             &convert_to_crlf,
02750                             &call_rewrite_func,
02751                             &rfe):
02752                      rw_rewrite_msg(fd,
02753                             &convert_to_crlf,
02754                             &call_rewrite_func,
02755                             &rfe))
02756                      || data_wait(del, ctf, rcptok))
02757                      for (i=0; i<del->nreceipients; i++)
02758                             if (rcptok[i])
02759                                    connect_error1(del, ctf, i);
02760               free(rcptok);
02761               sox_close(fd);
02762               cork(0);
02763        }
02764        if (rfcp)     rfc2045_free(rfcp);
02765 }
02766 
02767 
02768 static int escape_dots(const char *, unsigned,
02769        struct rw_for_esmtp *);
02770 
02771 static int convert_to_crlf(const char *msg, unsigned l, void *voidp)
02772 {
02773 unsigned i, j;
02774 int    rc;
02775 
02776        for (i=j=0; i < l; i++)
02777        {
02778               if (msg[i] != '\n')
02779                      continue;
02780               if ((rc=escape_dots(msg+j, i-j,
02781                      (struct rw_for_esmtp *)voidp)) != 0 ||
02782                      (rc=escape_dots("\r", 1,
02783                             (struct rw_for_esmtp *)voidp)) != 0)
02784                      return (rc);
02785               j=i;
02786        }
02787        return (escape_dots(msg+j, i-j, (struct rw_for_esmtp *)voidp));
02788 }
02789 
02790 static int escape_dots(const char *msg, unsigned l, struct rw_for_esmtp *ptr)
02791 {
02792 unsigned i, j;
02793 int    rc;
02794 
02795        if ( (ptr->byte_counter += l) >= BUFSIZ)
02796               ptr->byte_counter=0;
02797 
02798        if (ptr->byte_counter == 0)
02799               sock_timeout(data_timeout);
02800 
02801        for (i=j=0; i<l; i++)
02802        {
02803               if (ptr->is_sol && msg[i] == '.')
02804               {
02805                      if ((rc=dowrite(msg+j, i-j)) != 0 ||
02806                             (rc=dowrite(".", 1)) != 0)
02807                             return (rc);
02808                      j=i;
02809               }
02810               ptr->is_sol= msg[i] == '\n' ? 1:0;
02811        }
02812 
02813        return (dowrite(msg+j, i-j));
02814 }
02815 
02816 /****************************************************************************/
02817 /* Authenticated ESMTP client                                               */
02818 /****************************************************************************/
02819 
02820 static const char *start_esmtpauth(const char *, const char *, void *);
02821 static const char *esmtpauth(const char *, void *);
02822 static int final_esmtpauth(const char *, void *);
02823 static int plain_esmtpauth(const char *, const char *, void *);
02824 
02825 struct esmtpauthinfo {
02826        struct moduledel *del;
02827        struct ctlfile *ctf;
02828        int error_sent;
02829        } ;
02830 
02831 static int authclient(struct moduledel *del, struct ctlfile *ctf,
02832                     const char *auth_key)
02833 {
02834 FILE   *configfile;
02835 char   uidpwbuf[256];
02836 char   *q;
02837 const char *p;
02838 struct authsaslclientinfo info;
02839 struct esmtpauthinfo xinfo;
02840 int    rc;
02841 
02842        q=config_localfilename("esmtpauthclient");
02843        configfile=fopen( q, "r");
02844        free(q);
02845 
02846        if (!configfile)     return (0);
02847 
02848        xinfo.del=del;
02849        xinfo.ctf=ctf;
02850        xinfo.error_sent=0;
02851 
02852        for (;;)
02853        {
02854               if (fgets(uidpwbuf, sizeof(uidpwbuf), configfile) == 0)
02855               {
02856                      fclose(configfile);
02857                      return (0);
02858               }
02859               q=strtok(uidpwbuf, " \t\r\n");
02860 
02861               if (!sockfdaddrname || !q)  continue;
02862 
02863 #if    HAVE_STRCASECMP
02864               if (strcasecmp(q, auth_key) == 0)
02865                      break;
02866 #else
02867               if (stricmp(q, auth_key) == 0)
02868                      break;
02869 #endif
02870        }
02871        fclose(configfile);
02872        memset(&info, 0, sizeof(info));
02873        info.userid=strtok(0, " \t\r\n");
02874        info.password=strtok(0, " \t\r\n");
02875 
02876        info.sasl_funcs=authsasllist;
02877 
02878        info.start_conv_func= &start_esmtpauth;
02879        info.conv_func= &esmtpauth;
02880        info.final_conv_func= &final_esmtpauth;
02881        info.plain_conv_func= &plain_esmtpauth;
02882        info.conv_func_arg= &xinfo;
02883 
02884        rc=auth_sasl_client(&info);
02885        if (rc == AUTHSASL_NOMETHODS)
02886        {
02887               talking(del, ctf);
02888               hard_error(del, ctf,
02889                      "Compatible SASL authentication not available.");
02890               return (-1);
02891        }
02892 
02893        if (rc && !xinfo.error_sent)
02894        {
02895               talking(del, ctf);
02896               soft_error(del, ctf, "Temporary SASL authentication error.");
02897        }
02898 
02899        if (rc)
02900               return (-1);
02901 
02902        if ((p=readline()) == 0)
02903        {
02904               talking(del, ctf);
02905               connect_error(del, ctf);
02906               return (-1);
02907        }
02908 
02909        if (*p != '1' && *p != '2' && *p != '3') /* Some kind of an error */
02910        {
02911               talking(del, ctf);
02912               sent(del, ctf, "AUTH");
02913               smtp_msg(del, ctf);
02914               while (!ISFINALLINE(p))
02915               {
02916                      reply(del, ctf, p);
02917                      if ((p=readline()) == 0)
02918                      {
02919                             connection_closed(del, ctf);
02920                             return (-1);
02921                      }
02922               }
02923               smtp_error(del, ctf, p, 0);
02924               quit();
02925               return (-1);
02926        }
02927 
02928        return (0);
02929 }
02930 
02931 static const char *getresp(struct esmtpauthinfo *x)
02932 {
02933 const char *p=readline();
02934 
02935        if (p && *p == '3')
02936        {
02937               do
02938               {
02939                      ++p;
02940               } while ( isdigit((int)(unsigned char)*p));
02941 
02942               do
02943               {
02944                      ++p;
02945               } while ( isspace((int)(unsigned char)*p));
02946               return (p);
02947        }
02948        x->error_sent=1;
02949        talking(x->del, x->ctf);
02950        sent(x->del, x->ctf, "AUTH");
02951        smtp_msg(x->del, x->ctf);
02952 
02953        if (!p)
02954        {
02955               connection_closed(x->del, x->ctf);
02956               return (0);
02957        }
02958 
02959        while (!ISFINALLINE(p))
02960        {
02961               reply(x->del, x->ctf, p);
02962               if ((p=readline()) == 0)
02963               {
02964                      connection_closed(x->del, x->ctf);
02965                      return (0);
02966               }
02967        }
02968        smtp_error(x->del, x->ctf, p, 0);
02969        return (0);
02970 }
02971 
02972 static const char *start_esmtpauth(const char *method, const char *arg,
02973        void *voidp)
02974 {
02975        if (arg && !*arg)
02976               arg="=";
02977 
02978        if (dowritestr("AUTH ") || dowritestr(method) ||
02979                      (arg && (dowritestr(" ") || dowritestr(arg))) ||
02980                      dowritestr("\r\n") ||
02981               writeflush())
02982               return (0);
02983 
02984        return (getresp((struct esmtpauthinfo *)voidp));
02985 }
02986 
02987 static const char *esmtpauth(const char *msg, void *voidp)
02988 {
02989        if (dowritestr(msg) || dowritestr("\r\n") || writeflush())
02990               return (0);
02991        return (getresp((struct esmtpauthinfo *)voidp));
02992 }
02993 
02994 static int final_esmtpauth(const char *msg, void *voidp)
02995 {
02996        if (dowritestr(msg) || dowritestr("\r\n") || writeflush())
02997               return (AUTHSASL_CANCELLED);
02998        return (0);
02999 }
03000 
03001 static int plain_esmtpauth(const char *method, const char *arg,
03002        void *voidp)
03003 {
03004        if (arg && !*arg)
03005               arg="=";
03006 
03007        if (dowritestr("AUTH ") || dowritestr(method) ||
03008                      (arg && (dowritestr(" ") || dowritestr(arg))) ||
03009                      dowritestr("\r\n") ||
03010               writeflush())
03011               return (AUTHSASL_CANCELLED);
03012 
03013        return (0);
03014 }