Back to index

courier  0.68.2
courieresmtpd.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      <stdio.h>
00010 #if    HAVE_UNISTD_H
00011 #include      <unistd.h>
00012 #endif
00013 #if    HAVE_FCNTL_H
00014 #include      <fcntl.h>
00015 #endif
00016 #include      <ctype.h>
00017 #include      <string.h>
00018 #include      <stdlib.h>
00019 #include      <sys/types.h>
00020 #include      <sys/uio.h>
00021 #include      <sys/time.h>
00022 #include      <signal.h>
00023 #include      <syslog.h>
00024 
00025 #if    HAVE_LOCALE_H
00026 #include      <locale.h>
00027 #endif
00028 
00029 #include      "courier.h"
00030 #include      "rw.h"
00031 #include      "comcargs.h"
00032 #include      "comsubmitclient.h"
00033 #include      "comreadtime.h"
00034 #include      "rfc822.h"
00035 #include      "waitlib/waitlib.h"
00036 #include      "esmtpiov.h"
00037 #include      "esmtpconfig.h"
00038 #include      "numlib/numlib.h"
00039 #include      "tcpd/spipe.h"
00040 #include      "tcpd/tlsclient.h"
00041 #include      <courierauth.h>
00042 #include      <courierauthsasl.h>
00043 
00044 
00045 static char helobuf[256];
00046 static char authuserbuf[256];
00047 static char tlsbuf[128+NUMBUFSIZE];
00048 static int extended;
00049 
00050 static unsigned long sizelimit;
00051 static int submit_started=0;
00052 static int hasexdata;
00053 static int hasverp;
00054 static int hasstarttls;
00055 
00056 static char *mailfroms=0;
00057 extern time_t iovread_timeout;
00058 extern time_t iovwrite_timeout;
00059 static char *input_line="";
00060 static void cancelsubmit();
00061 static time_t data_timeout;
00062 
00063 static const char *tcpremoteip, *tcpremotehost;
00064 
00065 #define       INIT_TEERGRUBE       8
00066 #define       MAX_TEERGRUBE 128
00067 
00068 static time_t teergrube=INIT_TEERGRUBE;
00069 
00070 extern const char *externalauth();
00071 
00072 static const char *truncate_ipv6(const char *tcp)
00073 {
00074        if (strncmp(tcp, "::ffff:", 7) == 0)
00075               tcp += 7;
00076        return tcp;
00077 }
00078 
00079 static const char *smtp_externalauth()
00080 {
00081        const char *p;
00082 
00083        if ((p=getenv("ESMTP_TLS")) && atoi(p))
00084               return externalauth();
00085 
00086        return NULL;
00087 }
00088 
00089 static void tarpit()
00090 {
00091        const char *p;
00092        if ((p=getenv("TARPIT")) && atoi(p))
00093        {
00094               sleep(teergrube);
00095               teergrube *= 2;
00096               if (teergrube > MAX_TEERGRUBE)
00097                      teergrube=MAX_TEERGRUBE;
00098        }
00099 }
00100 
00101 void iov_logerror(const char *q, const char *p)
00102 {
00103        const char *ident=getenv("TCPREMOTEINFO");
00104 
00105        if (strcmp(input_line, "QUIT") == 0)
00106               return;
00107        /* Do not log write errors for QUIT cmd -- broken clients */
00108 
00109        clog_msg_start_info();
00110        clog_msg_str("error,relay=");
00111        clog_msg_str(tcpremoteip);
00112        if (ident)
00113        {
00114               clog_msg_str(",ident=\"");
00115               clog_msg_str(ident);
00116               clog_msg_str("\"");
00117        }
00118        clog_msg_str(",msg=\"");
00119        if (q)
00120               clog_msg_str(q);
00121        clog_msg_str(p);
00122        clog_msg_str("\",cmd: ");
00123        clog_msg_str(input_line);
00124        clog_msg_send();
00125 }
00126 
00127 void addiovec_error(const char *p)
00128 {
00129        addiovec(p, strlen(p));
00130        addiovec("\r\n", 2);
00131 
00132        iov_logerror(NULL, p);
00133        iovflush();
00134 
00135        if (*p == '5')
00136               tarpit();
00137 }
00138 
00139 static void showbanner()
00140 {
00141 const char *banner=config_esmtpgreeting();
00142 const char *p;
00143 
00144        do
00145        {
00146               for (p=banner; *p; p++)
00147                      if (*p == '\n')      break;
00148               addiovec((*p && p[1] ? "220-":"220 "), 4);
00149               addiovec(banner, p-banner);
00150               addiovec("\r\n", 2);
00151               if (*p)       p++;
00152               banner=p;
00153        } while (*banner);
00154 }
00155 
00156 static void ehlo(const char *heloname, int hastls, int tls)
00157 {
00158 static const char e[]=
00159 COURIER_EXTENSIONS
00160 EHLO_VERP_EXTENSION
00161 EHLO_EXDATA_EXTENSION
00162 EHLO_SECURITY_EXTENSION
00163 "250-PIPELINING\r\n"
00164 "250-8BITMIME\r\n"
00165 "250-SIZE\r\n"
00166 "250 DSN\r\n";
00167 const char *me=config_me();
00168 const char *p, *q;
00169 
00170        if (helobuf[0] == 0) 
00171        {
00172               char *p;
00173 
00174               strncat(helobuf, heloname, sizeof(helobuf)-1);
00175 
00176               for (p=helobuf; *p; p++)
00177                      if (isspace((int)(unsigned char)*p) ||
00178                          (int)(unsigned char)*p < ' ')
00179                             *p='_';
00180        }
00181 
00182         putenv(strcat(strcpy(courier_malloc(sizeof("ESMTPHELO=") +
00183                                        strlen(helobuf)),
00184                           "ESMTPHELO="), helobuf));
00185 
00186        if (!extended)
00187        {
00188               addiovec("250 ", 4);
00189               addiovec(me, strlen(me));
00190               addiovec(" Ok.\r\n", 6);
00191               return;
00192        }
00193 
00194        addiovec("250-", 4);
00195        addiovec(me, strlen(me));
00196        addiovec(" Ok.\r\n", 6);
00197 
00198        if (tls && (p=getenv("ESMTPAUTH_TLS")) != 0 && *p)
00199               ;
00200        else
00201               p=getenv("ESMTPAUTH");
00202 
00203        if (!p)
00204               p="";
00205 
00206        q=smtp_externalauth() ? "EXTERNAL":"";
00207 
00208        if (*p || *q)
00209        {
00210               addiovec("250-AUTH ", 9);
00211               addiovec(p, strlen(p));
00212               if (*p && *q)
00213                      addiovec(" ", 1);
00214               addiovec(q, strlen(q));
00215               addiovec("\r\n", 2);
00216 #if 0
00217               /*
00218               ** Netscape.
00219               */
00220 
00221               addiovec("250-AUTH=", 9);
00222               addiovec(p, strlen(p));
00223               if (*p && *q)
00224                      addiovec(" ", 1);
00225               addiovec(q, strlen(q));
00226               addiovec(" X-NETSCAPE-HAS-BUGS\r\n", 22);
00227 #endif
00228        }
00229 
00230        if (hastls)
00231        {
00232               static const char starttls_msg[]=
00233                      "250-STARTTLS\r\n";
00234 
00235               addiovec(starttls_msg, sizeof(starttls_msg)-1);
00236        }
00237 
00238        addiovec(e, sizeof(e)-1);
00239 }
00240 
00241 extern char **environ;
00242 
00243 static void badfork()
00244 {
00245        addiovec_error("432 Service temporarily unavailable.");
00246 }
00247 
00248 static void expnvrfy(const char *line, const char *cmd)
00249 {
00250 struct rfc822t *t=rfc822t_alloc_new(line, NULL, NULL);
00251 struct rfc822a *a;
00252 char   *addr;
00253 char   *argv[5];
00254 int    rc;
00255 
00256        if (!t)       clog_msg_errno();
00257 
00258        a=rfc822a_alloc(t);
00259        if (!a)       clog_msg_errno();
00260 
00261        if (a->naddrs != 1 || a->addrs[0].tokens == 0)
00262        {
00263               addiovec_error("502 EXPN syntax error.");
00264               rfc822a_free(a);
00265               rfc822t_free(t);
00266               return;
00267        }
00268 
00269        addr=rfc822_getaddr(a, 0);
00270        rfc822a_free(a);
00271        rfc822t_free(t);
00272        if (!addr)    clog_msg_errno();
00273 
00274        argv[0]="submit";
00275        argv[1]=strcat(strcpy(courier_malloc(strlen(cmd)+strlen(addr)+1),
00276               cmd), addr);
00277        free(addr);
00278        argv[2]="local";     /* Use the LOCAL rewrite module */
00279        argv[3]="unknown; unknown";
00280        argv[4]=0;
00281        if (submit_fork(argv, environ, submit_print_stdout))
00282        {
00283               badfork();
00284               free(argv[1]);
00285               return;
00286        }
00287        free(argv[1]);
00288        fclose(submit_to);
00289        rc=submit_readrcprintcrlf();
00290        (void)submit_wait();
00291        if (rc == 0)
00292               teergrube=INIT_TEERGRUBE;
00293        fclose(fromsubmit);
00294 }
00295 
00296 static void startsubmit(int tls)
00297 {
00298        char   *argv[14];
00299        const char *ident;
00300        char   *identbuf=0;
00301        int    n, exid_ndx=0;
00302        const  char *host;
00303        char   *buf;
00304        char rfc3848_buf[32];
00305 
00306        if (submit_started)  return;
00307        if (helobuf[0] == '\0')     return;
00308 
00309        argv[0]="submit";
00310        argv[1]=getenv("RELAYCLIENT") ? "-src=authsmtp":"-src=smtp";
00311        n=2;
00312 
00313        if (authuserbuf[0])
00314        {
00315               char *p;
00316 
00317               static char authbuf[sizeof(authuserbuf)+sizeof("-auth=")];
00318 
00319               p=strchr(authuserbuf, ' ');
00320               if (p)
00321               {
00322                      strcat(strcpy(authbuf, "-auth="), p+1);
00323                      argv[n++]=authbuf;
00324               }
00325               exid_ndx=1;
00326        }
00327 
00328        strcpy(rfc3848_buf, "-rfc3848=");
00329 
00330        if (extended)
00331        {
00332               static char *exid[] =
00333                      {"ESMTP",
00334                       "ESMTPA",
00335                       "ESMTPS",
00336                       "ESMTPSA"};
00337 
00338               if (tls) exid_ndx += 2;
00339               strcat(rfc3848_buf, exid[exid_ndx]);
00340 
00341        }
00342        else
00343        {
00344               strcat(rfc3848_buf, "SMTP");
00345        }
00346        argv[n++]=rfc3848_buf;
00347 
00348        argv[n++]="esmtp";
00349 
00350        host=tcpremotehost;
00351 
00352        if (!host)    host="";
00353        argv[n]=buf=courier_malloc(strlen(host)+strlen(tcpremoteip)+strlen(
00354               helobuf)+sizeof("dns;  ( [])"));
00355 
00356        strcat(strcat(strcpy(buf, "dns; "), helobuf), " (");
00357        if (*host)
00358               strcat(strcat(buf, host), " ");
00359        strcat(strcat(strcat(buf, "["), tcpremoteip), "])");
00360 
00361        ++n;
00362 
00363        if ((ident=getenv("TCPREMOTEINFO")) == 0)
00364               ident="";
00365 
00366        if (*ident || authuserbuf[0] || tls)
00367        {
00368               argv[n]=identbuf=courier_malloc(sizeof("IDENT: , AUTH: , ")+
00369                                           strlen(tlsbuf)+
00370                                           strlen(ident)+
00371                                           strlen(authuserbuf));
00372               ++n;
00373               *identbuf=0;
00374               if (*ident)
00375                      strcat(strcat(identbuf, "IDENT: "), ident);
00376                 if (authuserbuf[0])
00377                 {
00378                         if (*identbuf)  strcat(identbuf, ", ");
00379                         strcat(strcat(identbuf, "AUTH: "), authuserbuf);
00380                      putenv(strcat(
00381                              strcpy(
00382                                courier_malloc(sizeof("SENDERAUTH=") +
00383                                             strlen(authuserbuf)),
00384                                "SENDERAUTH="), authuserbuf));
00385               }
00386 
00387               if (tls)
00388               {
00389                      if (*identbuf)       strcat(identbuf, ", ");
00390                      strcat(identbuf, tlsbuf);
00391               }
00392        }
00393 
00394        argv[n]=0;
00395 
00396        if (submit_fork(argv, environ, submit_print_stdout) == 0)
00397               submit_started=1;
00398 
00399        if (identbuf) free(identbuf);
00400        free(buf);
00401 }
00402 
00403 static void cancelsubmit()
00404 {
00405        if (submit_started)
00406        {
00407               fclose(submit_to);
00408               fclose(fromsubmit);
00409               (void)submit_wait();
00410               submit_started=0;
00411        }
00412 }
00413 
00414 static char *log_error_sender=0;
00415 static char *log_error_to=0;
00416 
00417 static void print_submit_log_fix(void);
00418 
00419 static void set_submit_error(const char *r, int rl)
00420 {
00421 char   *p;
00422 
00423        if (log_error_sender)       free(log_error_sender);
00424        if (log_error_to)    free(log_error_to);
00425 
00426        log_error_sender=0;
00427        if (mailfroms && (log_error_sender=strdup(mailfroms)) == 0)
00428               clog_msg_errno();
00429 
00430        log_error_to=0;
00431        if (r && rl)
00432        {
00433               if ((log_error_to=malloc(rl+1)) == 0)
00434                      clog_msg_errno();
00435               memcpy(log_error_to, r, rl);
00436               log_error_to[rl]=0;
00437        }
00438 
00439        if (log_error_sender && *log_error_sender)
00440               for (p=log_error_sender+1; p[1]; p++)
00441                      if (*p == '<' || *p == '>' || *p == ':')
00442                             *p=' ';
00443 
00444        if (log_error_to && *log_error_to)
00445               for (p=log_error_to+1; p[1]; p++)
00446                      if (*p == '<' || *p == '>' || *p == ':')
00447                             *p=' ';
00448 
00449        if (log_error_sender && *log_error_sender)
00450               submit_log_error_prefix(print_submit_log_fix);
00451        else
00452               submit_log_error_prefix(0);
00453 }
00454 
00455 static void print_submit_log_fix(void)
00456 {
00457 const char *p;
00458 
00459        clog_msg_str("error,relay=");
00460        clog_msg_str(tcpremoteip);
00461        if ((p=getenv("TCPREMOTEINFO")) != 0 && *p)
00462        {
00463        char   *q=strdup(p), *r;
00464 
00465               if (!q)       clog_msg_errno();
00466               for (r=q; *r; r++)
00467                      if (*r == ',' || *r == ':') *r=' ';
00468               clog_msg_str(",ident=");
00469               clog_msg_str(q);
00470               free(q);
00471        }
00472 
00473        if (log_error_sender)
00474        {
00475               clog_msg_str(",from=");
00476               clog_msg_str(log_error_sender);
00477        }
00478        if (log_error_to)
00479        {
00480               clog_msg_str(",to=");
00481               clog_msg_str(log_error_to);
00482        }
00483        clog_msg_str(": ");
00484 }
00485 
00486 /* Skip the E-mail address in the MAIL FROM:/RCPT TO: command */
00487 
00488 static const char *skipaddress(const char **ptr)
00489 {
00490 const char *p;
00491 int inquote=0;
00492 
00493        while ( **ptr && isspace((int)(unsigned char)**ptr) )
00494               ++*ptr;
00495 
00496        if (**ptr != '<')    return (0);
00497        p= ++*ptr;
00498 
00499        while (*p)
00500        {
00501               if (*p == '>' && !inquote)  return (p);
00502               if (*p == '"')       inquote ^= 1;
00503               if (*p == '\\' && p[1])     ++p;
00504               ++p;
00505        }
00506        return (0);
00507 }
00508 
00509 /**************************************************************************/
00510 
00511 /*                          MAIL FROM                                     */
00512 
00513 /**************************************************************************/
00514 
00515 static int domailfrom(const char *, const char *);
00516 
00517 static int mailfrom(const char *p)
00518 {
00519 const char *q=skipaddress(&p);
00520 
00521        set_submit_error(0, 0);
00522        if (q)
00523        {
00524               /* Save <address> in mailfroms */
00525 
00526               if (mailfroms)       free(mailfroms);
00527               mailfroms=courier_malloc(q-p+3);
00528               memcpy(mailfroms, p-1, q-p+2);
00529               mailfroms[q-p+2]=0;
00530               set_submit_error(0, 0);
00531               return (domailfrom(p, q));
00532        }
00533        addiovec_error("554 Syntax error - your mail software violates RFC 821.");
00534        return (-1);
00535 }
00536 
00537 static int domailfrom(const char *p, const char *q)
00538 {
00539 const char *r, *s;
00540 char   retformat=0;
00541 const char *envid=0;
00542 size_t envidlen=0;
00543 char   *buf;
00544 int    rc;
00545 
00546        hasexdata=0;
00547        hasverp=0;
00548        hasstarttls=0;
00549 
00550        for (r=q+1; *r; r++)
00551        {
00552               if (isspace((int)(unsigned char)*r))      continue;
00553               for (s=r; *s && !isspace((int)(unsigned char)*s); s++)
00554                      ;
00555               if (s - r == 4 &&
00556 #if HAVE_STRNCASECMP
00557                      strncasecmp(r, "VERP", 4)
00558 #else
00559                      strnicmp(r, "VERP", 4)
00560 #endif
00561                      == 0)
00562               {
00563                      hasverp=1;
00564               }
00565               else if (s - r == 17 &&
00566 #if HAVE_STRNCASECMP
00567                      strncasecmp(r, "SECURITY=STARTTLS", 17)
00568 #else
00569                      strnicmp(r, "SECURITY=STARTTLS", 17)
00570 #endif
00571                      == 0)
00572               {
00573                      hasstarttls=1;
00574               }
00575               else if (s - r == 6 &&
00576 #if HAVE_STRNCASECMP
00577                      strncasecmp(r, "EXDATA", 6)
00578 #else
00579                      strnicmp(r, "EXDATA", 6)
00580 #endif
00581                      == 0)
00582               {
00583                      hasexdata=1;
00584               }
00585               else if (s - r >= 4 &&
00586 #if HAVE_STRNCASECMP
00587                      strncasecmp(r, "RET=", 4)
00588 #else
00589                      strnicmp(r, "RET=", 4)
00590 #endif
00591                      == 0)
00592               {
00593                      switch (r[4]) {
00594                      case 'f':
00595                      case 'F':
00596                             retformat='F';
00597                             break;
00598                      case 'h':
00599                      case 'H':
00600                             retformat='H';
00601                             break;
00602                      }
00603               }
00604               else if (s - r >= 6 &&
00605 #if HAVE_STRNCASECMP
00606                      strncasecmp(r, "ENVID=", 6)
00607 #else
00608                      strnicmp(r, "ENVID=", 6)
00609 #endif
00610                      == 0)
00611               {
00612                      envid=r+6;
00613                      envidlen=s-envid;
00614               }
00615               else if (s - r >= 5 &&
00616 #if HAVE_STRNCASECMP
00617                      strncasecmp(r, "SIZE=", 5)
00618 #else
00619                      strnicmp(r, "SIZE=", 5)
00620 #endif
00621                      == 0)
00622               {
00623               unsigned long l=0, n;
00624 
00625                      for (r += 5; *r >= '0' && *r <= '9'; r++)
00626                      {
00627                             if ( (n=l * 10) < l ||
00628                                    (n += *r-'0') < l ||
00629                                    (sizelimit && n > sizelimit))
00630                             {
00631                                    addiovec_error("534 SIZE=Message too big.");
00632                                    return (-1);
00633                             }
00634                             l=n;
00635                      }
00636               }
00637               r= s-1;
00638        }
00639 
00640        buf=courier_malloc(q-p+envidlen+80);
00641        if (q > p)
00642               memcpy(buf, p, q-p);
00643        strcpy(buf + (q-p), "\t");
00644        if (retformat)
00645        {
00646        char b[2];
00647 
00648               b[0]=retformat;
00649               b[1]=0;
00650               strcat(buf, b);
00651        }
00652        if (hasverp)
00653               strcat(buf, "V");
00654 
00655        if (hasstarttls)
00656        {
00657               strcat(buf, "S{STARTTLS}");
00658        }
00659 
00660        if (envidlen)
00661        {
00662        char   *t;
00663 
00664               strcat(buf, "\t");
00665               t=buf+strlen(buf);
00666               memcpy(t, envid, envidlen);
00667               t[envidlen]=0;
00668        }
00669        submit_write_message(buf);
00670        free(buf);
00671        rc=submit_readrcprintcrlf();
00672        if (rc)
00673        {
00674               iovflush();
00675        }
00676        return (rc);
00677 }
00678 
00679 /**************************************************************************/
00680 
00681 /*                            RCPT TO                                     */
00682 
00683 /**************************************************************************/
00684 
00685 static int dorcptto(const char *, const char *);
00686 
00687 static int rcptto(const char *p)
00688 {
00689 const char *q=skipaddress(&p);
00690 
00691        if ( q )
00692        {
00693               set_submit_error(p-1, q-p+2);
00694               return (dorcptto(p, q));
00695        }
00696        addiovec_error("554 Syntax error - your mail software violates RFC 821.");
00697        return (-1);
00698 }
00699 
00700 static int dorcptto2(const char *p, const char *q);
00701 static int rcpttolocal(const char *p, const char *r, const char *q);
00702 
00703 static int dorcptto(const char *p, const char *q)
00704 {
00705        const char *r;
00706        const char *tcp=getenv("TCPLOCALIP");
00707 
00708        /* foo@[our.ip.address] -> foo@default */
00709 
00710        for (r=p; r != q; r++)
00711        {
00712               if (*r == '@' && r[1] == '[' && tcp)
00713               {
00714 
00715                      if (strncasecmp(r+2, tcp, strlen(tcp)) == 0 &&
00716                          strncasecmp(r+2+strlen(tcp), "]>", 2) == 0)
00717                      {
00718                             return rcpttolocal(p, r+1, q);
00719                      }
00720 
00721                      if (strncmp(tcp, "::ffff:", 7) == 0)
00722                      {
00723                             tcp += 7;
00724                             if (strncasecmp(r+2, tcp, strlen(tcp)) == 0 &&
00725                                 strncasecmp(r+2+strlen(tcp), "]>", 2) == 0)
00726                             {
00727                                    return rcpttolocal(p, r+1, q);
00728                             }
00729                      }
00730               }
00731        }
00732 
00733        return dorcptto2(p, q);
00734 }
00735 
00736 static int rcpttolocal(const char *p, const char *r, const char *q)
00737 {
00738        const char *d=config_defaultdomain();
00739        char *buf=courier_malloc(r-p + strlen(d)+strlen(q)+1);
00740        int rc;
00741 
00742        memcpy(buf, p, r-p);
00743        strcpy(buf+(r-p), d);
00744 
00745        p=buf+strlen(buf);
00746        strcat(buf, q);
00747 
00748        rc=dorcptto2(buf, p);
00749        free(buf);
00750        return rc;
00751 }
00752 
00753 static int dorcptto2(const char *p, const char *q)
00754 {
00755 int    notifyn=0,notifyf=0,notifys=0,notifyd=0;
00756 const char *orcpt=0;
00757 int    orcptlen=0;
00758 const char *r, *s;
00759 char   *t, *buf;
00760 const char *relayclient=getenv("RELAYCLIENT");
00761 int    relayclientl= relayclient ? strlen(relayclient):0;
00762 int    rc;
00763 
00764        for (r=q+1; *r; r++)
00765        {
00766               if (isspace((int)(unsigned char)*r))      continue;
00767               for (s=r; *s && !isspace((int)(unsigned char)*s); s++)
00768                      ;
00769               if (s - r > 7 &&
00770 #if HAVE_STRNCASECMP
00771                      strncasecmp(r, "NOTIFY=", 7)
00772 #else
00773                      strnicmp(r, "NOTIFY=", 7)
00774 #endif
00775                      == 0)
00776               {
00777                      r += 7;
00778                      while (r < s)
00779                      {
00780                             switch (toupper(*r)) {
00781                             case 'N':
00782                                    notifyn=1;
00783                                    break;
00784                             case 'S':
00785                                    notifys=1;
00786                                    break;
00787                             case 'D':
00788                                    notifyd=1;
00789                                    break;
00790                             case 'F':
00791                                    notifyf=1;
00792                                    break;
00793                             }
00794                             while (r < s)
00795                                    if (*r++ == ',')     break;
00796                      }
00797 
00798 
00799                      hasverp=1;
00800               }
00801               else if (s - r > 6 &&
00802 #if HAVE_STRNCASECMP
00803                      strncasecmp(r, "ORCPT=", 6)
00804 #else
00805                      strnicmp(r, "ORCPT=", 6)
00806 #endif
00807                      == 0)
00808               {
00809                      r += 6;
00810                      orcpt=r;
00811                      orcptlen=s-r;
00812               }
00813        }
00814 
00815        buf=courier_malloc(q-p + relayclientl + orcptlen + 10);
00816        memcpy(buf, p, q-p);
00817        t=buf + (q-p);
00818        if (relayclientl)
00819               memcpy(t, relayclient, relayclientl);
00820        t += relayclientl;
00821 
00822        *t++ = '\t';
00823        if (notifyn)
00824               *t++ = 'N';
00825        else
00826        {
00827               if (notifys)
00828                      *t++ = 'S';
00829               if (notifyf)
00830                      *t++ = 'F';
00831               if (notifyd)
00832                      *t++ = 'D';
00833        }
00834        *t++ = '\t';
00835        if (orcptlen)
00836               memcpy(t, orcpt, orcptlen);
00837        t[orcptlen]=0;
00838 
00839        submit_write_message(buf);
00840        free(buf);
00841        rc=submit_readrcprintcrlf();
00842        if (rc)
00843        {
00844               iovflush();
00845        }
00846        return (rc);
00847 }
00848 
00849 static void getmoredata(char *p, int *l)
00850 {
00851 time_t t;
00852 
00853        time(&t);
00854        t += data_timeout;
00855        if (iovwaitfordata(&t, 0) || (*l=read(0, p, *l)) <= 0)
00856        {
00857               submit_cancel();
00858               _exit(0);
00859        }
00860 }
00861 
00862 void data()
00863 {
00864 char   databuf[BUFSIZ];
00865 char *p;
00866 int l;
00867 int    rc;
00868 
00869        l=0;
00870        p=databuf;
00871        for (;;)
00872        {
00873               if (l == 0)
00874               {
00875                      p=databuf;
00876                      l=sizeof(databuf);
00877                      getmoredata(p, &l);
00878               }
00879 
00880               if ( *p == '.' )
00881               {
00882                      ++p; --l;
00883                      if (l == 0)
00884                      {
00885                             p=databuf;
00886                             l=sizeof(databuf);
00887                             getmoredata(p, &l);
00888                      }
00889                      if (*p == '\r')
00890                      {
00891                             ++p;
00892                             --l;
00893                             if (l == 0)
00894                             {
00895                                    p=databuf;
00896                                    l=sizeof(databuf);
00897                                    getmoredata(p, &l);
00898                             }
00899                             if (*p == '\n')
00900                             {
00901                                    ++p;
00902                                    --l;
00903                                    break;
00904                             }
00905                             putc('\r', submit_to);
00906                      }
00907               }
00908               for (;;)
00909               {
00910                      if (l == 0)
00911                      {
00912                             p=databuf;
00913                             l=sizeof(databuf);
00914                             getmoredata(p, &l);
00915                      }
00916                      if (*p == '\r')
00917                      {
00918                             ++p;
00919                             --l;
00920                             if (l == 0)
00921                             {
00922                                    p=databuf;
00923                                    l=sizeof(databuf);
00924                                    getmoredata(p, &l);
00925                             }
00926                             if (*p == '\n')      break;
00927                             putc('\r', submit_to);
00928                             continue;
00929                      }
00930                      putc(*p, submit_to);
00931                      ++p;
00932                      --l;
00933               }
00934               putc('\n', submit_to);
00935               ++p;
00936               --l;
00937        }
00938        fclose(submit_to);
00939        rc=submit_readrcprintcrlf();
00940        if (submit_wait() && rc == 0)
00941        {
00942               clog_msg_start_err();
00943               clog_msg_str("submit terminated with a non-zero exit code.");
00944               clog_msg_send();
00945               exit(0);
00946        }
00947 
00948        if (rc == 0)
00949               teergrube=INIT_TEERGRUBE;
00950        fclose(fromsubmit);
00951 }
00952 
00953 static int bofh(const char *bofh)
00954 {
00955 const char *p=getenv(bofh);
00956 
00957        if (p && *p == '1')  return (1);
00958        return (0);
00959 }
00960 
00961 static char *sasl_conv_func(const char *s, void *dummy)
00962 {
00963 char   *p;
00964 
00965        addiovec("334 ", 4);
00966        addiovec(s, strlen(s));
00967        addiovec("\r\n", 2);
00968        iovflush();
00969 
00970        p=iovreadline();
00971        if (!p)       exit(0);
00972        if ((p=strdup(p)) == 0)
00973        {
00974               perror("malloc");
00975               exit(0);
00976        }
00977        return (p);
00978 }
00979 
00980 static int auth_callback_func(struct authinfo *a, void *va)
00981 {
00982        char *p;
00983 
00984        strcpy(authuserbuf, "");
00985        strncat(authuserbuf, (const char *)va, 20);
00986        strcat(authuserbuf, " ");
00987        strncat(authuserbuf, a->address,
00988               sizeof(authuserbuf)-10-strlen(a->address));
00989 
00990        for (p=authuserbuf; *p; p++)
00991               if ((int)(unsigned char)*p < ' ' || *p >= 127)
00992                      *p=' ';
00993        return 0;
00994 }
00995 
00996 static char *rtrim(char *s)
00997 {
00998        char *end = s + strlen(s);
00999        while (s < end)
01000               if (isspace(*(unsigned char*)--end))
01001                      *end = 0;
01002               else
01003                      break;
01004        return s;
01005 }
01006 
01007 
01008 /*****************************************************************************
01009 
01010 courieresmtpd can be started in two situations:
01011 
01012 * No command line arguments: courier is not configured to support the ESMTP
01013   AUTH extension
01014 
01015 * Command line arguments are present: Courier is configured to support the
01016   ESMTP AUTH extension
01017 
01018 *****************************************************************************/
01019 
01020 int main(int argc, char **argv)
01021 {
01022 int    seenmailfrom;
01023 int    seenrcptto;
01024 char   *line;
01025 int    starttls=0;
01026 int    tls=0;
01027 int    tls_required=0;
01028 int    auth_required=0;
01029 int    authenticated=0;
01030 
01031 #if HAVE_SETLOCALE
01032        setlocale(LC_ALL, "C");
01033 #endif
01034        /*
01035        ** When called via -bs to sendmail, dump log to /dev/null via stderr,
01036        ** else record everything via syslog.
01037        */
01038 
01039        if (chdir(courierdir()))
01040               clog_msg_errno();
01041 
01042        if (fcntl(0, F_SETFL, O_NONBLOCK) ||
01043            fcntl(1, F_SETFL, O_NONBLOCK))
01044        {
01045               perror("fcntl");
01046               exit(1);
01047        }
01048 
01049        helobuf[0]=0;
01050        submit_set_teergrube(tarpit);
01051 
01052        if (strcmp(argv[0], "sendmail") == 0)
01053               clog_open_stderr("courieresmtpd");
01054               /* We are being called by the sendmail command line wrapper */
01055 
01056        else
01057        {
01058               const char *p=getenv("TCPLOCALIP");
01059 
01060               if (p)
01061                      p=truncate_ipv6(p);
01062 
01063               if (p && *p && config_has_vhost(p))
01064                      config_set_local_vhost(p);
01065 
01066               clog_open_syslog("courieresmtpd");
01067 
01068               if ((p=getenv("ESMTP_TLS")) && atoi(p))
01069               {
01070                      p=getenv("TLS_CONNECTED_PROTOCOL");
01071 
01072                      tls=1;
01073                      /* This is the smtps service, and we don't need to
01074                       * initialize the STARTTLS feature. */
01075 
01076                      if (p && *p)
01077                      {
01078                             strcpy(tlsbuf, "SSL: ");
01079                             strncat(tlsbuf, p, sizeof(tlsbuf)-6);
01080                      }
01081               }
01082               else
01083               {
01084                      if ((p=getenv("COURIERTLS")) != 0 && *p
01085                             && access(p, X_OK) == 0 &&
01086                             (p=getenv("TLS_CERTFILE")) != 0 && *p &&
01087                             access(p, R_OK) == 0)
01088                             starttls=1;
01089 
01090                      if ((p=getenv("ESMTP_TLS_REQUIRED")) && atoi(p))
01091                      {
01092                             tls_required=1;
01093                             if (!starttls)
01094                             {
01095                                    addiovec_error("440 TLS not available,  but"
01096                                           " it's required for this connection.");
01097                                    return (1);
01098                             }
01099                      }
01100               }
01101        }
01102 
01103 
01104        {
01105               const char *p=getenv("AUTH_REQUIRED");
01106 
01107               if (p)
01108                      auth_required=atoi(p);
01109        }
01110 
01111        iovread_timeout=config_time_esmtptimeout();
01112        iovwrite_timeout=data_timeout=config_time_esmtpdata();
01113 
01114        tcpremoteip=getenv("TCPREMOTEIP");
01115        tcpremotehost=getenv("TCPREMOTEHOST");
01116 
01117        if (!tcpremoteip)
01118        {
01119               fprintf(stderr, "%s: don't know your IP address, no dice.\n",
01120                      argv[0]);
01121               exit(1);
01122        }
01123 
01124        showbanner();
01125        iovflush();
01126 
01127        signal(SIGPIPE, SIG_IGN);
01128        /* Some house keeping, while waiting for a reply */
01129 
01130        if (rw_init_courier("esmtp"))      return (1);
01131 
01132        clog_msg_start_info();
01133        clog_msg_str("started,ip=[");
01134        clog_msg_str(tcpremoteip);
01135        clog_msg_str("]");
01136        clog_msg_send();
01137 
01138        seenmailfrom=0;
01139        seenrcptto=0;
01140        sizelimit=config_sizelimit();
01141 
01142        for (;;)
01143        {
01144        char   *p;
01145 
01146               input_line=line=iovreadline();
01147 
01148               /* Optionally log the esmtp dialog */
01149               if ((p=getenv("ESMTP_LOG_DIALOG")) && *p == '1')
01150               {
01151                      clog_msg_start_info();
01152                      clog_msg_str(input_line);
01153                      clog_msg_str("\n");
01154                      clog_msg_send();
01155               }
01156 
01157               for (p=line; *p && *p != ':'; p++)
01158               {
01159                      if (*p == ' ' && strncmp(line, "MAIL", 4) &&
01160                             strncmp(line, "RCPT", 4))
01161                             break;
01162 
01163                      *p=toupper(*p);
01164               }
01165 
01166               rtrim(line);
01167               if (strcmp(line, "QUIT") == 0)     break;
01168               if ((strncmp(line, "EHLO ", 5) == 0 ||
01169                      strncmp(line, "HELO ", 5) == 0) &&
01170                      line[5])
01171               {
01172                      extended=line[0] == 'E';
01173                      ehlo(line+5, starttls, tls);
01174                      iovflush();
01175                      cancelsubmit();
01176                      startsubmit(tls);
01177                      continue;
01178               }
01179 
01180               if (strcmp(line, "STARTTLS") == 0)
01181               {
01182               int    pipefd[2];
01183               struct couriertls_info cinfo;
01184               char   *argvec[4];
01185               char   buf1[NUMBUFSIZE+40];
01186               char   buf2[NUMBUFSIZE];
01187 
01188                       if (!starttls ||
01189                          ((p=getenv("TLS_DEBUG_FAIL_STARTTLS_HARD")) &&
01190                           *p == '1'))
01191                      {
01192                             addiovec_error("540 TLS not available.");
01193                             continue;
01194                      }
01195 
01196                       if ((p=getenv("TLS_DEBUG_FAIL_STARTTLS_SOFT")) &&
01197                          *p == '1')
01198                      {
01199                             addiovec_error("440 TLS not available.");
01200                             continue;
01201                      }
01202                      if (libmail_streampipe(pipefd))
01203                      {
01204                             addiovec_error("432 libmail_streampipe() failed.");
01205                             exit(1);
01206                      }
01207 
01208                      couriertls_init(&cinfo);
01209 
01210                      strcat(strcpy(buf1, "-localfd="),
01211                             libmail_str_size_t(pipefd[1], buf2));
01212 
01213                      argvec[0]=buf1;
01214                      argvec[1]="-tcpd";
01215                      argvec[2]="-server";
01216                      argvec[3]=NULL;
01217                      fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);
01218 
01219                      addiovec("220 Ok\r\n", 8);
01220                      iovflush();
01221                      iovreset();
01222 
01223                      if (couriertls_start(argvec, &cinfo))
01224                      {
01225                             close(pipefd[0]);
01226                             close(pipefd[1]);
01227                             syslog(LOG_MAIL|LOG_ERR,
01228                                    "courieresmtpd: STARTTLS failed: %s\n",
01229                                    cinfo.errmsg);
01230                             couriertls_destroy(&cinfo);
01231                             exit(1);
01232                      }
01233 
01234                      close(pipefd[1]);
01235                      strcpy(tlsbuf, "TLS: ");
01236                      strncat(tlsbuf, cinfo.version, 40);
01237                      if (cinfo.bits > 0)
01238                             strcat(strcat(strcat(tlsbuf, ","),
01239                                          libmail_str_size_t(cinfo.bits,
01240                                                   buf2)),
01241                                    "bits");
01242                      strncat(strcat(tlsbuf, ","), cinfo.cipher, 40);
01243 
01244                      couriertls_export_subject_environment(&cinfo);
01245                      couriertls_destroy(&cinfo);
01246 
01247                      tls=1;
01248                      starttls=0;
01249                      tls_required=0;
01250                      close(pipefd[1]);
01251                      close(0);
01252                      close(1);
01253                      if (dup(pipefd[0]) != 0 || dup(pipefd[0]) != 1)
01254                      {
01255                             perror("dup");
01256                             exit(1);
01257                      }
01258                      close(pipefd[0]);
01259                      cancelsubmit();
01260                      startsubmit(tls);    /* Mark */
01261 
01262                      setenv("ESMTP_TLS", "1", 1);
01263                      continue;
01264               }
01265 
01266               if (tls_required && strcmp(line, "RSET"))
01267               {
01268                      addiovec_error("400 STARTTLS is required first.");
01269                      continue;
01270               }
01271 
01272               if (strncmp(line, "AUTH ", 5) == 0 && mailfroms == 0
01273                      && authuserbuf[0] == 0)
01274               {
01275               char   *authmethod;
01276               char   *initreply;
01277               const char *q;
01278               char   *buf=strcpy(courier_malloc(strlen(line)+1), line);
01279               char   *authtype;
01280               char   *authdata;
01281               char    fakecmd[5];
01282 
01283                       strcpy(fakecmd, "AUTH");
01284 
01285                      starttls=0;
01286                      (void)strtok(buf, " \t\r\n");
01287                      authmethod=strtok(0, " \t\r\n");
01288                      initreply=strtok(0, " \t\r\n");
01289 
01290                      if (tls && (q=getenv("ESMTPAUTH_TLS")) != 0 && *q)
01291                             ;
01292                      else
01293                             q=getenv("ESMTPAUTH");
01294 
01295                      if (q == 0 || *q == 0)      authmethod=0;
01296 
01297                      if (authmethod == 0 || *authmethod == 0)
01298                      {
01299                             input_line=fakecmd;
01300                             addiovec_error("535 Authentication rejected");
01301                             free(buf);
01302                             continue;
01303                      }
01304 
01305                      if (initreply && *initreply)
01306                      {
01307                             if (strcmp(initreply, "=") == 0)
01308                                    initreply="";
01309                      }
01310                      else
01311                      {
01312                             initreply=0;
01313                      }
01314 
01315                      if (auth_sasl_ex(authmethod, initreply,
01316                                     smtp_externalauth(),
01317                                     sasl_conv_func,
01318                                     NULL,
01319                                     &authtype,
01320                                     &authdata) != AUTHSASL_OK)
01321                      {
01322                             /* TODO - better error messages */
01323 
01324                             strcpy(authuserbuf, "");
01325                      }
01326                      else
01327                      {
01328                             int rc=auth_generic("esmtp", authtype,
01329                                               authdata,
01330                                               auth_callback_func,
01331                                               authmethod);
01332 
01333                             free(authtype);
01334                             free(authdata);
01335 
01336                             if (rc)
01337                                    strcpy(authuserbuf, "");
01338                      }
01339 
01340                      if (authuserbuf[0] == 0)
01341                      {
01342                             input_line=fakecmd;
01343                             addiovec_error("535 Authentication failed.");
01344                             iovflush();
01345                      }
01346                      else
01347                      {
01348                      const char *rc;
01349                      char *p;
01350 
01351                             addiovec("235 Ok\r\n", 8);
01352                             iovflush();
01353                             cancelsubmit();
01354                             putenv("BLOCK=");
01355                             rc=getenv("AUTHRELAYCLIENT");
01356                             if (!rc)      rc="";
01357                             p=courier_malloc(sizeof("RELAYCLIENT=")+
01358                                    strlen(rc));
01359                             strcat(strcpy(p, "RELAYCLIENT="), rc);
01360                             putenv(p);
01361                             putenv("FAXRELAYCLIENT=");
01362                             startsubmit(tls);
01363                             authenticated=1;
01364                      }
01365                      free(buf);
01366                      continue;
01367               }
01368 
01369               if (auth_required && !authenticated && strcmp(line, "RSET"))
01370               {
01371                      addiovec_error("535 Authentication required.");
01372                      continue;
01373               }
01374 
01375               if (strncmp(line, "EXPN ", 5) == 0)
01376               {
01377                      starttls=0;
01378                      if (bofh("BOFHNOEXPN") == 0 && seenmailfrom == 0)
01379                      {
01380                             cancelsubmit();
01381                             expnvrfy(line+5, "-expn=");
01382                             startsubmit(tls);
01383                      }
01384                      else   addiovec_error("252 EXPN disabled");
01385                      continue;
01386               }
01387               if (strncmp(line, "VRFY ", 5) == 0)
01388               {
01389                      starttls=0;
01390                      if (bofh("BOFHNOVRFY") == 0 && seenmailfrom == 0)
01391                      {
01392                             cancelsubmit();
01393                             expnvrfy(line+5, "-vrfy=");
01394                             startsubmit(tls);
01395                      }
01396                      else   addiovec_error("252 VRFY disabled");
01397                      continue;
01398               }
01399               if (strcmp(line, "RSET") == 0)
01400               {
01401                      starttls=0;
01402                      addiovec("250 Ok\r\n", 8);
01403                      iovflush();
01404                      cancelsubmit();
01405                      startsubmit(tls);
01406                      seenmailfrom=0;
01407                      if (mailfroms)       free(mailfroms);
01408                      mailfroms=0;
01409                      set_submit_error(0, 0);
01410                      continue;
01411               }
01412               if (strncmp(line, "NOOP", 4) == 0)
01413               {
01414                      addiovec("250 Ok\r\n", 8);
01415                      iovflush();
01416                      continue;
01417               }
01418               if (strncmp(line, "MAIL", 4) == 0 && (p=strchr(line, ':')) != 0
01419                      && !seenmailfrom)
01420               {
01421                      starttls=0;
01422                      if (!helobuf[0])
01423                      {
01424                             addiovec_error("502 Polite people say HELO first");
01425                             continue;
01426                      }
01427                      if (!submit_started)
01428                      {
01429                             badfork();
01430                             continue;
01431                      }
01432                      if (mailfrom(p+1) == 0)
01433                      {
01434                             seenmailfrom=1;
01435                             seenrcptto=0;
01436                      }
01437                      else
01438                      {
01439                             cancelsubmit();
01440                             startsubmit(tls);
01441                      }
01442                      continue;
01443               }
01444 
01445               if (strncmp(line, "RCPT", 4) == 0 && (p=strchr(line, ':')) != 0
01446                             && seenmailfrom)
01447               {
01448                      if (rcptto(p+1) == 0)
01449                             seenrcptto=1;
01450                      continue;
01451               }
01452               if (strcmp(line, "DATA") == 0 && seenmailfrom && seenrcptto)
01453               {
01454                      set_submit_error(0, 0);
01455                      addiovec("354 Ok.\r\n", 9);
01456                      iovflush();
01457                      putc('\n', submit_to);
01458                      data();
01459                      seenmailfrom=0;
01460                      seenrcptto=0;
01461                      submit_started=0;
01462                      if (mailfroms)       free(mailfroms);
01463                      mailfroms=0;
01464                      startsubmit(tls);
01465                      continue;
01466               }
01467               addiovec_error("502 ESMTP command error");
01468        }
01469        addiovec("221 Bye.\r\n", 10);
01470        iovflush();
01471        return (0);
01472 }