Back to index

courier  0.68.2
Defines | Functions | Variables
courieresmtpd.c File Reference
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <signal.h>
#include <syslog.h>
#include "courier.h"
#include "rw.h"
#include "comcargs.h"
#include "comsubmitclient.h"
#include "comreadtime.h"
#include "rfc822.h"
#include "waitlib/waitlib.h"
#include "esmtpiov.h"
#include "esmtpconfig.h"
#include "numlib/numlib.h"
#include "tcpd/spipe.h"
#include "tcpd/tlsclient.h"
#include <courierauth.h>
#include <courierauthsasl.h>

Go to the source code of this file.

Defines

#define INIT_TEERGRUBE   8
#define MAX_TEERGRUBE   128

Functions

static void cancelsubmit ()
const char * externalauth ()
static const char * truncate_ipv6 (const char *tcp)
static const char * smtp_externalauth ()
static void tarpit ()
void iov_logerror (const char *q, const char *p)
void addiovec_error (const char *p)
static void showbanner ()
static void ehlo (const char *heloname, int hastls, int tls)
static void badfork ()
static void expnvrfy (const char *line, const char *cmd)
static void startsubmit (int tls)
static void print_submit_log_fix (void)
static void set_submit_error (const char *r, int rl)
static const char * skipaddress (const char **ptr)
static int domailfrom (const char *, const char *)
static int mailfrom (const char *p)
static int dorcptto (const char *, const char *)
static int rcptto (const char *p)
static int dorcptto2 (const char *p, const char *q)
static int rcpttolocal (const char *p, const char *r, const char *q)
static void getmoredata (char *p, int *l)
void data ()
static int bofh (const char *bofh)
static char * sasl_conv_func (const char *s, void *dummy)
static int auth_callback_func (struct authinfo *a, void *va)
static char * rtrim (char *s)
int main (int argc, char **argv)

Variables

static char helobuf [256]
static char authuserbuf [256]
static char tlsbuf [128+NUMBUFSIZE]
static int extended
static unsigned long sizelimit
static int submit_started = 0
static int hasexdata
static int hasverp
static int hasstarttls
static char * mailfroms = 0
time_t iovread_timeout
time_t iovwrite_timeout
static char * input_line = ""
static time_t data_timeout
static const char * tcpremoteip
static const char * tcpremotehost
static time_t teergrube = INIT_TEERGRUBE
char ** environ
static char * log_error_sender = 0
static char * log_error_to = 0

Define Documentation

#define INIT_TEERGRUBE   8

Definition at line 65 of file courieresmtpd.c.

#define MAX_TEERGRUBE   128

Definition at line 66 of file courieresmtpd.c.


Function Documentation

void addiovec_error ( const char *  p)

Definition at line 127 of file courieresmtpd.c.

{
       addiovec(p, strlen(p));
       addiovec("\r\n", 2);

       iov_logerror(NULL, p);
       iovflush();

       if (*p == '5')
              tarpit();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int auth_callback_func ( struct authinfo *  a,
void *  va 
) [static]

Definition at line 980 of file courieresmtpd.c.

{
       char *p;

       strcpy(authuserbuf, "");
       strncat(authuserbuf, (const char *)va, 20);
       strcat(authuserbuf, " ");
       strncat(authuserbuf, a->address,
              sizeof(authuserbuf)-10-strlen(a->address));

       for (p=authuserbuf; *p; p++)
              if ((int)(unsigned char)*p < ' ' || *p >= 127)
                     *p=' ';
       return 0;
}

Here is the caller graph for this function:

static void badfork ( ) [static]

Definition at line 243 of file courieresmtpd.c.

{
       addiovec_error("432 Service temporarily unavailable.");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int bofh ( const char *  bofh) [static]

Definition at line 953 of file courieresmtpd.c.

{
const char *p=getenv(bofh);

       if (p && *p == '1')  return (1);
       return (0);
}

Here is the caller graph for this function:

static void cancelsubmit ( ) [static]

Definition at line 403 of file courieresmtpd.c.

{
       if (submit_started)
       {
              fclose(submit_to);
              fclose(fromsubmit);
              (void)submit_wait();
              submit_started=0;
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void data ( )

Definition at line 862 of file courieresmtpd.c.

{
char   databuf[BUFSIZ];
char *p;
int l;
int    rc;

       l=0;
       p=databuf;
       for (;;)
       {
              if (l == 0)
              {
                     p=databuf;
                     l=sizeof(databuf);
                     getmoredata(p, &l);
              }

              if ( *p == '.' )
              {
                     ++p; --l;
                     if (l == 0)
                     {
                            p=databuf;
                            l=sizeof(databuf);
                            getmoredata(p, &l);
                     }
                     if (*p == '\r')
                     {
                            ++p;
                            --l;
                            if (l == 0)
                            {
                                   p=databuf;
                                   l=sizeof(databuf);
                                   getmoredata(p, &l);
                            }
                            if (*p == '\n')
                            {
                                   ++p;
                                   --l;
                                   break;
                            }
                            putc('\r', submit_to);
                     }
              }
              for (;;)
              {
                     if (l == 0)
                     {
                            p=databuf;
                            l=sizeof(databuf);
                            getmoredata(p, &l);
                     }
                     if (*p == '\r')
                     {
                            ++p;
                            --l;
                            if (l == 0)
                            {
                                   p=databuf;
                                   l=sizeof(databuf);
                                   getmoredata(p, &l);
                            }
                            if (*p == '\n')      break;
                            putc('\r', submit_to);
                            continue;
                     }
                     putc(*p, submit_to);
                     ++p;
                     --l;
              }
              putc('\n', submit_to);
              ++p;
              --l;
       }
       fclose(submit_to);
       rc=submit_readrcprintcrlf();
       if (submit_wait() && rc == 0)
       {
              clog_msg_start_err();
              clog_msg_str("submit terminated with a non-zero exit code.");
              clog_msg_send();
              exit(0);
       }

       if (rc == 0)
              teergrube=INIT_TEERGRUBE;
       fclose(fromsubmit);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int domailfrom ( const char *  p,
const char *  q 
) [static]

Definition at line 537 of file courieresmtpd.c.

{
const char *r, *s;
char   retformat=0;
const char *envid=0;
size_t envidlen=0;
char   *buf;
int    rc;

       hasexdata=0;
       hasverp=0;
       hasstarttls=0;

       for (r=q+1; *r; r++)
       {
              if (isspace((int)(unsigned char)*r))      continue;
              for (s=r; *s && !isspace((int)(unsigned char)*s); s++)
                     ;
              if (s - r == 4 &&
#if HAVE_STRNCASECMP
                     strncasecmp(r, "VERP", 4)
#else
                     strnicmp(r, "VERP", 4)
#endif
                     == 0)
              {
                     hasverp=1;
              }
              else if (s - r == 17 &&
#if HAVE_STRNCASECMP
                     strncasecmp(r, "SECURITY=STARTTLS", 17)
#else
                     strnicmp(r, "SECURITY=STARTTLS", 17)
#endif
                     == 0)
              {
                     hasstarttls=1;
              }
              else if (s - r == 6 &&
#if HAVE_STRNCASECMP
                     strncasecmp(r, "EXDATA", 6)
#else
                     strnicmp(r, "EXDATA", 6)
#endif
                     == 0)
              {
                     hasexdata=1;
              }
              else if (s - r >= 4 &&
#if HAVE_STRNCASECMP
                     strncasecmp(r, "RET=", 4)
#else
                     strnicmp(r, "RET=", 4)
#endif
                     == 0)
              {
                     switch (r[4]) {
                     case 'f':
                     case 'F':
                            retformat='F';
                            break;
                     case 'h':
                     case 'H':
                            retformat='H';
                            break;
                     }
              }
              else if (s - r >= 6 &&
#if HAVE_STRNCASECMP
                     strncasecmp(r, "ENVID=", 6)
#else
                     strnicmp(r, "ENVID=", 6)
#endif
                     == 0)
              {
                     envid=r+6;
                     envidlen=s-envid;
              }
              else if (s - r >= 5 &&
#if HAVE_STRNCASECMP
                     strncasecmp(r, "SIZE=", 5)
#else
                     strnicmp(r, "SIZE=", 5)
#endif
                     == 0)
              {
              unsigned long l=0, n;

                     for (r += 5; *r >= '0' && *r <= '9'; r++)
                     {
                            if ( (n=l * 10) < l ||
                                   (n += *r-'0') < l ||
                                   (sizelimit && n > sizelimit))
                            {
                                   addiovec_error("534 SIZE=Message too big.");
                                   return (-1);
                            }
                            l=n;
                     }
              }
              r= s-1;
       }

       buf=courier_malloc(q-p+envidlen+80);
       if (q > p)
              memcpy(buf, p, q-p);
       strcpy(buf + (q-p), "\t");
       if (retformat)
       {
       char b[2];

              b[0]=retformat;
              b[1]=0;
              strcat(buf, b);
       }
       if (hasverp)
              strcat(buf, "V");

       if (hasstarttls)
       {
              strcat(buf, "S{STARTTLS}");
       }

       if (envidlen)
       {
       char   *t;

              strcat(buf, "\t");
              t=buf+strlen(buf);
              memcpy(t, envid, envidlen);
              t[envidlen]=0;
       }
       submit_write_message(buf);
       free(buf);
       rc=submit_readrcprintcrlf();
       if (rc)
       {
              iovflush();
       }
       return (rc);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dorcptto ( const char *  p,
const char *  q 
) [static]

Definition at line 703 of file courieresmtpd.c.

{
       const char *r;
       const char *tcp=getenv("TCPLOCALIP");

       /* foo@[our.ip.address] -> foo@default */

       for (r=p; r != q; r++)
       {
              if (*r == '@' && r[1] == '[' && tcp)
              {

                     if (strncasecmp(r+2, tcp, strlen(tcp)) == 0 &&
                         strncasecmp(r+2+strlen(tcp), "]>", 2) == 0)
                     {
                            return rcpttolocal(p, r+1, q);
                     }

                     if (strncmp(tcp, "::ffff:", 7) == 0)
                     {
                            tcp += 7;
                            if (strncasecmp(r+2, tcp, strlen(tcp)) == 0 &&
                                strncasecmp(r+2+strlen(tcp), "]>", 2) == 0)
                            {
                                   return rcpttolocal(p, r+1, q);
                            }
                     }
              }
       }

       return dorcptto2(p, q);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int dorcptto2 ( const char *  p,
const char *  q 
) [static]

Definition at line 753 of file courieresmtpd.c.

{
int    notifyn=0,notifyf=0,notifys=0,notifyd=0;
const char *orcpt=0;
int    orcptlen=0;
const char *r, *s;
char   *t, *buf;
const char *relayclient=getenv("RELAYCLIENT");
int    relayclientl= relayclient ? strlen(relayclient):0;
int    rc;

       for (r=q+1; *r; r++)
       {
              if (isspace((int)(unsigned char)*r))      continue;
              for (s=r; *s && !isspace((int)(unsigned char)*s); s++)
                     ;
              if (s - r > 7 &&
#if HAVE_STRNCASECMP
                     strncasecmp(r, "NOTIFY=", 7)
#else
                     strnicmp(r, "NOTIFY=", 7)
#endif
                     == 0)
              {
                     r += 7;
                     while (r < s)
                     {
                            switch (toupper(*r)) {
                            case 'N':
                                   notifyn=1;
                                   break;
                            case 'S':
                                   notifys=1;
                                   break;
                            case 'D':
                                   notifyd=1;
                                   break;
                            case 'F':
                                   notifyf=1;
                                   break;
                            }
                            while (r < s)
                                   if (*r++ == ',')     break;
                     }


                     hasverp=1;
              }
              else if (s - r > 6 &&
#if HAVE_STRNCASECMP
                     strncasecmp(r, "ORCPT=", 6)
#else
                     strnicmp(r, "ORCPT=", 6)
#endif
                     == 0)
              {
                     r += 6;
                     orcpt=r;
                     orcptlen=s-r;
              }
       }

       buf=courier_malloc(q-p + relayclientl + orcptlen + 10);
       memcpy(buf, p, q-p);
       t=buf + (q-p);
       if (relayclientl)
              memcpy(t, relayclient, relayclientl);
       t += relayclientl;

       *t++ = '\t';
       if (notifyn)
              *t++ = 'N';
       else
       {
              if (notifys)
                     *t++ = 'S';
              if (notifyf)
                     *t++ = 'F';
              if (notifyd)
                     *t++ = 'D';
       }
       *t++ = '\t';
       if (orcptlen)
              memcpy(t, orcpt, orcptlen);
       t[orcptlen]=0;

       submit_write_message(buf);
       free(buf);
       rc=submit_readrcprintcrlf();
       if (rc)
       {
              iovflush();
       }
       return (rc);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void ehlo ( const char *  heloname,
int  hastls,
int  tls 
) [static]

Definition at line 156 of file courieresmtpd.c.

{
static const char e[]=
COURIER_EXTENSIONS
EHLO_VERP_EXTENSION
EHLO_EXDATA_EXTENSION
EHLO_SECURITY_EXTENSION
"250-PIPELINING\r\n"
"250-8BITMIME\r\n"
"250-SIZE\r\n"
"250 DSN\r\n";
const char *me=config_me();
const char *p, *q;

       if (helobuf[0] == 0) 
       {
              char *p;

              strncat(helobuf, heloname, sizeof(helobuf)-1);

              for (p=helobuf; *p; p++)
                     if (isspace((int)(unsigned char)*p) ||
                         (int)(unsigned char)*p < ' ')
                            *p='_';
       }

        putenv(strcat(strcpy(courier_malloc(sizeof("ESMTPHELO=") +
                                       strlen(helobuf)),
                          "ESMTPHELO="), helobuf));

       if (!extended)
       {
              addiovec("250 ", 4);
              addiovec(me, strlen(me));
              addiovec(" Ok.\r\n", 6);
              return;
       }

       addiovec("250-", 4);
       addiovec(me, strlen(me));
       addiovec(" Ok.\r\n", 6);

       if (tls && (p=getenv("ESMTPAUTH_TLS")) != 0 && *p)
              ;
       else
              p=getenv("ESMTPAUTH");

       if (!p)
              p="";

       q=smtp_externalauth() ? "EXTERNAL":"";

       if (*p || *q)
       {
              addiovec("250-AUTH ", 9);
              addiovec(p, strlen(p));
              if (*p && *q)
                     addiovec(" ", 1);
              addiovec(q, strlen(q));
              addiovec("\r\n", 2);
#if 0
              /*
              ** Netscape.
              */

              addiovec("250-AUTH=", 9);
              addiovec(p, strlen(p));
              if (*p && *q)
                     addiovec(" ", 1);
              addiovec(q, strlen(q));
              addiovec(" X-NETSCAPE-HAS-BUGS\r\n", 22);
#endif
       }

       if (hastls)
       {
              static const char starttls_msg[]=
                     "250-STARTTLS\r\n";

              addiovec(starttls_msg, sizeof(starttls_msg)-1);
       }

       addiovec(e, sizeof(e)-1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void expnvrfy ( const char *  line,
const char *  cmd 
) [static]

Definition at line 248 of file courieresmtpd.c.

{
struct rfc822t *t=rfc822t_alloc_new(line, NULL, NULL);
struct rfc822a *a;
char   *addr;
char   *argv[5];
int    rc;

       if (!t)       clog_msg_errno();

       a=rfc822a_alloc(t);
       if (!a)       clog_msg_errno();

       if (a->naddrs != 1 || a->addrs[0].tokens == 0)
       {
              addiovec_error("502 EXPN syntax error.");
              rfc822a_free(a);
              rfc822t_free(t);
              return;
       }

       addr=rfc822_getaddr(a, 0);
       rfc822a_free(a);
       rfc822t_free(t);
       if (!addr)    clog_msg_errno();

       argv[0]="submit";
       argv[1]=strcat(strcpy(courier_malloc(strlen(cmd)+strlen(addr)+1),
              cmd), addr);
       free(addr);
       argv[2]="local";     /* Use the LOCAL rewrite module */
       argv[3]="unknown; unknown";
       argv[4]=0;
       if (submit_fork(argv, environ, submit_print_stdout))
       {
              badfork();
              free(argv[1]);
              return;
       }
       free(argv[1]);
       fclose(submit_to);
       rc=submit_readrcprintcrlf();
       (void)submit_wait();
       if (rc == 0)
              teergrube=INIT_TEERGRUBE;
       fclose(fromsubmit);
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* externalauth ( )

Definition at line 16 of file externalauth.c.

{
       const char *p=getenv("TLS_EXTERNAL");
       char *q, *r;

       if (!p || !*p)
              return NULL;

       if ((q=malloc(strlen(p)+20)) == NULL)
              return NULL;

       strcat(strcpy(q, "TLS_SUBJECT_"), p);

       for (r=q; *r; r++)
              if (*r >= 'a' && *r <= 'z')
                     *r -= 'a' - 'A';

       p=getenv(q);
       free(q);

       if (p && *p)
              return p;
       return 0;
}

Here is the caller graph for this function:

static void getmoredata ( char *  p,
int *  l 
) [static]

Definition at line 849 of file courieresmtpd.c.

{
time_t t;

       time(&t);
       t += data_timeout;
       if (iovwaitfordata(&t, 0) || (*l=read(0, p, *l)) <= 0)
       {
              submit_cancel();
              _exit(0);
       }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void iov_logerror ( const char *  q,
const char *  p 
)

Definition at line 101 of file courieresmtpd.c.

{
       const char *ident=getenv("TCPREMOTEINFO");

       if (strcmp(input_line, "QUIT") == 0)
              return;
       /* Do not log write errors for QUIT cmd -- broken clients */

       clog_msg_start_info();
       clog_msg_str("error,relay=");
       clog_msg_str(tcpremoteip);
       if (ident)
       {
              clog_msg_str(",ident=\"");
              clog_msg_str(ident);
              clog_msg_str("\"");
       }
       clog_msg_str(",msg=\"");
       if (q)
              clog_msg_str(q);
       clog_msg_str(p);
       clog_msg_str("\",cmd: ");
       clog_msg_str(input_line);
       clog_msg_send();
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int mailfrom ( const char *  p) [static]

Definition at line 517 of file courieresmtpd.c.

{
const char *q=skipaddress(&p);

       set_submit_error(0, 0);
       if (q)
       {
              /* Save <address> in mailfroms */

              if (mailfroms)       free(mailfroms);
              mailfroms=courier_malloc(q-p+3);
              memcpy(mailfroms, p-1, q-p+2);
              mailfroms[q-p+2]=0;
              set_submit_error(0, 0);
              return (domailfrom(p, q));
       }
       addiovec_error("554 Syntax error - your mail software violates RFC 821.");
       return (-1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int main ( int  argc,
char **  argv 
)

Definition at line 1020 of file courieresmtpd.c.

{
int    seenmailfrom;
int    seenrcptto;
char   *line;
int    starttls=0;
int    tls=0;
int    tls_required=0;
int    auth_required=0;
int    authenticated=0;

#if HAVE_SETLOCALE
       setlocale(LC_ALL, "C");
#endif
       /*
       ** When called via -bs to sendmail, dump log to /dev/null via stderr,
       ** else record everything via syslog.
       */

       if (chdir(courierdir()))
              clog_msg_errno();

       if (fcntl(0, F_SETFL, O_NONBLOCK) ||
           fcntl(1, F_SETFL, O_NONBLOCK))
       {
              perror("fcntl");
              exit(1);
       }

       helobuf[0]=0;
       submit_set_teergrube(tarpit);

       if (strcmp(argv[0], "sendmail") == 0)
              clog_open_stderr("courieresmtpd");
              /* We are being called by the sendmail command line wrapper */

       else
       {
              const char *p=getenv("TCPLOCALIP");

              if (p)
                     p=truncate_ipv6(p);

              if (p && *p && config_has_vhost(p))
                     config_set_local_vhost(p);

              clog_open_syslog("courieresmtpd");

              if ((p=getenv("ESMTP_TLS")) && atoi(p))
              {
                     p=getenv("TLS_CONNECTED_PROTOCOL");

                     tls=1;
                     /* This is the smtps service, and we don't need to
                      * initialize the STARTTLS feature. */

                     if (p && *p)
                     {
                            strcpy(tlsbuf, "SSL: ");
                            strncat(tlsbuf, p, sizeof(tlsbuf)-6);
                     }
              }
              else
              {
                     if ((p=getenv("COURIERTLS")) != 0 && *p
                            && access(p, X_OK) == 0 &&
                            (p=getenv("TLS_CERTFILE")) != 0 && *p &&
                            access(p, R_OK) == 0)
                            starttls=1;

                     if ((p=getenv("ESMTP_TLS_REQUIRED")) && atoi(p))
                     {
                            tls_required=1;
                            if (!starttls)
                            {
                                   addiovec_error("440 TLS not available,  but"
                                          " it's required for this connection.");
                                   return (1);
                            }
                     }
              }
       }


       {
              const char *p=getenv("AUTH_REQUIRED");

              if (p)
                     auth_required=atoi(p);
       }

       iovread_timeout=config_time_esmtptimeout();
       iovwrite_timeout=data_timeout=config_time_esmtpdata();

       tcpremoteip=getenv("TCPREMOTEIP");
       tcpremotehost=getenv("TCPREMOTEHOST");

       if (!tcpremoteip)
       {
              fprintf(stderr, "%s: don't know your IP address, no dice.\n",
                     argv[0]);
              exit(1);
       }

       showbanner();
       iovflush();

       signal(SIGPIPE, SIG_IGN);
       /* Some house keeping, while waiting for a reply */

       if (rw_init_courier("esmtp"))      return (1);

       clog_msg_start_info();
       clog_msg_str("started,ip=[");
       clog_msg_str(tcpremoteip);
       clog_msg_str("]");
       clog_msg_send();

       seenmailfrom=0;
       seenrcptto=0;
       sizelimit=config_sizelimit();

       for (;;)
       {
       char   *p;

              input_line=line=iovreadline();

              /* Optionally log the esmtp dialog */
              if ((p=getenv("ESMTP_LOG_DIALOG")) && *p == '1')
              {
                     clog_msg_start_info();
                     clog_msg_str(input_line);
                     clog_msg_str("\n");
                     clog_msg_send();
              }

              for (p=line; *p && *p != ':'; p++)
              {
                     if (*p == ' ' && strncmp(line, "MAIL", 4) &&
                            strncmp(line, "RCPT", 4))
                            break;

                     *p=toupper(*p);
              }

              rtrim(line);
              if (strcmp(line, "QUIT") == 0)     break;
              if ((strncmp(line, "EHLO ", 5) == 0 ||
                     strncmp(line, "HELO ", 5) == 0) &&
                     line[5])
              {
                     extended=line[0] == 'E';
                     ehlo(line+5, starttls, tls);
                     iovflush();
                     cancelsubmit();
                     startsubmit(tls);
                     continue;
              }

              if (strcmp(line, "STARTTLS") == 0)
              {
              int    pipefd[2];
              struct couriertls_info cinfo;
              char   *argvec[4];
              char   buf1[NUMBUFSIZE+40];
              char   buf2[NUMBUFSIZE];

                      if (!starttls ||
                         ((p=getenv("TLS_DEBUG_FAIL_STARTTLS_HARD")) &&
                          *p == '1'))
                     {
                            addiovec_error("540 TLS not available.");
                            continue;
                     }

                      if ((p=getenv("TLS_DEBUG_FAIL_STARTTLS_SOFT")) &&
                         *p == '1')
                     {
                            addiovec_error("440 TLS not available.");
                            continue;
                     }
                     if (libmail_streampipe(pipefd))
                     {
                            addiovec_error("432 libmail_streampipe() failed.");
                            exit(1);
                     }

                     couriertls_init(&cinfo);

                     strcat(strcpy(buf1, "-localfd="),
                            libmail_str_size_t(pipefd[1], buf2));

                     argvec[0]=buf1;
                     argvec[1]="-tcpd";
                     argvec[2]="-server";
                     argvec[3]=NULL;
                     fcntl(pipefd[0], F_SETFD, FD_CLOEXEC);

                     addiovec("220 Ok\r\n", 8);
                     iovflush();
                     iovreset();

                     if (couriertls_start(argvec, &cinfo))
                     {
                            close(pipefd[0]);
                            close(pipefd[1]);
                            syslog(LOG_MAIL|LOG_ERR,
                                   "courieresmtpd: STARTTLS failed: %s\n",
                                   cinfo.errmsg);
                            couriertls_destroy(&cinfo);
                            exit(1);
                     }

                     close(pipefd[1]);
                     strcpy(tlsbuf, "TLS: ");
                     strncat(tlsbuf, cinfo.version, 40);
                     if (cinfo.bits > 0)
                            strcat(strcat(strcat(tlsbuf, ","),
                                         libmail_str_size_t(cinfo.bits,
                                                  buf2)),
                                   "bits");
                     strncat(strcat(tlsbuf, ","), cinfo.cipher, 40);

                     couriertls_export_subject_environment(&cinfo);
                     couriertls_destroy(&cinfo);

                     tls=1;
                     starttls=0;
                     tls_required=0;
                     close(pipefd[1]);
                     close(0);
                     close(1);
                     if (dup(pipefd[0]) != 0 || dup(pipefd[0]) != 1)
                     {
                            perror("dup");
                            exit(1);
                     }
                     close(pipefd[0]);
                     cancelsubmit();
                     startsubmit(tls);    /* Mark */

                     setenv("ESMTP_TLS", "1", 1);
                     continue;
              }

              if (tls_required && strcmp(line, "RSET"))
              {
                     addiovec_error("400 STARTTLS is required first.");
                     continue;
              }

              if (strncmp(line, "AUTH ", 5) == 0 && mailfroms == 0
                     && authuserbuf[0] == 0)
              {
              char   *authmethod;
              char   *initreply;
              const char *q;
              char   *buf=strcpy(courier_malloc(strlen(line)+1), line);
              char   *authtype;
              char   *authdata;
              char    fakecmd[5];

                      strcpy(fakecmd, "AUTH");

                     starttls=0;
                     (void)strtok(buf, " \t\r\n");
                     authmethod=strtok(0, " \t\r\n");
                     initreply=strtok(0, " \t\r\n");

                     if (tls && (q=getenv("ESMTPAUTH_TLS")) != 0 && *q)
                            ;
                     else
                            q=getenv("ESMTPAUTH");

                     if (q == 0 || *q == 0)      authmethod=0;

                     if (authmethod == 0 || *authmethod == 0)
                     {
                            input_line=fakecmd;
                            addiovec_error("535 Authentication rejected");
                            free(buf);
                            continue;
                     }

                     if (initreply && *initreply)
                     {
                            if (strcmp(initreply, "=") == 0)
                                   initreply="";
                     }
                     else
                     {
                            initreply=0;
                     }

                     if (auth_sasl_ex(authmethod, initreply,
                                    smtp_externalauth(),
                                    sasl_conv_func,
                                    NULL,
                                    &authtype,
                                    &authdata) != AUTHSASL_OK)
                     {
                            /* TODO - better error messages */

                            strcpy(authuserbuf, "");
                     }
                     else
                     {
                            int rc=auth_generic("esmtp", authtype,
                                              authdata,
                                              auth_callback_func,
                                              authmethod);

                            free(authtype);
                            free(authdata);

                            if (rc)
                                   strcpy(authuserbuf, "");
                     }

                     if (authuserbuf[0] == 0)
                     {
                            input_line=fakecmd;
                            addiovec_error("535 Authentication failed.");
                            iovflush();
                     }
                     else
                     {
                     const char *rc;
                     char *p;

                            addiovec("235 Ok\r\n", 8);
                            iovflush();
                            cancelsubmit();
                            putenv("BLOCK=");
                            rc=getenv("AUTHRELAYCLIENT");
                            if (!rc)      rc="";
                            p=courier_malloc(sizeof("RELAYCLIENT=")+
                                   strlen(rc));
                            strcat(strcpy(p, "RELAYCLIENT="), rc);
                            putenv(p);
                            putenv("FAXRELAYCLIENT=");
                            startsubmit(tls);
                            authenticated=1;
                     }
                     free(buf);
                     continue;
              }

              if (auth_required && !authenticated && strcmp(line, "RSET"))
              {
                     addiovec_error("535 Authentication required.");
                     continue;
              }

              if (strncmp(line, "EXPN ", 5) == 0)
              {
                     starttls=0;
                     if (bofh("BOFHNOEXPN") == 0 && seenmailfrom == 0)
                     {
                            cancelsubmit();
                            expnvrfy(line+5, "-expn=");
                            startsubmit(tls);
                     }
                     else   addiovec_error("252 EXPN disabled");
                     continue;
              }
              if (strncmp(line, "VRFY ", 5) == 0)
              {
                     starttls=0;
                     if (bofh("BOFHNOVRFY") == 0 && seenmailfrom == 0)
                     {
                            cancelsubmit();
                            expnvrfy(line+5, "-vrfy=");
                            startsubmit(tls);
                     }
                     else   addiovec_error("252 VRFY disabled");
                     continue;
              }
              if (strcmp(line, "RSET") == 0)
              {
                     starttls=0;
                     addiovec("250 Ok\r\n", 8);
                     iovflush();
                     cancelsubmit();
                     startsubmit(tls);
                     seenmailfrom=0;
                     if (mailfroms)       free(mailfroms);
                     mailfroms=0;
                     set_submit_error(0, 0);
                     continue;
              }
              if (strncmp(line, "NOOP", 4) == 0)
              {
                     addiovec("250 Ok\r\n", 8);
                     iovflush();
                     continue;
              }
              if (strncmp(line, "MAIL", 4) == 0 && (p=strchr(line, ':')) != 0
                     && !seenmailfrom)
              {
                     starttls=0;
                     if (!helobuf[0])
                     {
                            addiovec_error("502 Polite people say HELO first");
                            continue;
                     }
                     if (!submit_started)
                     {
                            badfork();
                            continue;
                     }
                     if (mailfrom(p+1) == 0)
                     {
                            seenmailfrom=1;
                            seenrcptto=0;
                     }
                     else
                     {
                            cancelsubmit();
                            startsubmit(tls);
                     }
                     continue;
              }

              if (strncmp(line, "RCPT", 4) == 0 && (p=strchr(line, ':')) != 0
                            && seenmailfrom)
              {
                     if (rcptto(p+1) == 0)
                            seenrcptto=1;
                     continue;
              }
              if (strcmp(line, "DATA") == 0 && seenmailfrom && seenrcptto)
              {
                     set_submit_error(0, 0);
                     addiovec("354 Ok.\r\n", 9);
                     iovflush();
                     putc('\n', submit_to);
                     data();
                     seenmailfrom=0;
                     seenrcptto=0;
                     submit_started=0;
                     if (mailfroms)       free(mailfroms);
                     mailfroms=0;
                     startsubmit(tls);
                     continue;
              }
              addiovec_error("502 ESMTP command error");
       }
       addiovec("221 Bye.\r\n", 10);
       iovflush();
       return (0);
}
static void print_submit_log_fix ( void  ) [static]

Definition at line 455 of file courieresmtpd.c.

{
const char *p;

       clog_msg_str("error,relay=");
       clog_msg_str(tcpremoteip);
       if ((p=getenv("TCPREMOTEINFO")) != 0 && *p)
       {
       char   *q=strdup(p), *r;

              if (!q)       clog_msg_errno();
              for (r=q; *r; r++)
                     if (*r == ',' || *r == ':') *r=' ';
              clog_msg_str(",ident=");
              clog_msg_str(q);
              free(q);
       }

       if (log_error_sender)
       {
              clog_msg_str(",from=");
              clog_msg_str(log_error_sender);
       }
       if (log_error_to)
       {
              clog_msg_str(",to=");
              clog_msg_str(log_error_to);
       }
       clog_msg_str(": ");
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int rcptto ( const char *  p) [static]

Definition at line 687 of file courieresmtpd.c.

{
const char *q=skipaddress(&p);

       if ( q )
       {
              set_submit_error(p-1, q-p+2);
              return (dorcptto(p, q));
       }
       addiovec_error("554 Syntax error - your mail software violates RFC 821.");
       return (-1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int rcpttolocal ( const char *  p,
const char *  r,
const char *  q 
) [static]

Definition at line 736 of file courieresmtpd.c.

{
       const char *d=config_defaultdomain();
       char *buf=courier_malloc(r-p + strlen(d)+strlen(q)+1);
       int rc;

       memcpy(buf, p, r-p);
       strcpy(buf+(r-p), d);

       p=buf+strlen(buf);
       strcat(buf, q);

       rc=dorcptto2(buf, p);
       free(buf);
       return rc;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char* rtrim ( char *  s) [static]

Definition at line 996 of file courieresmtpd.c.

{
       char *end = s + strlen(s);
       while (s < end)
              if (isspace(*(unsigned char*)--end))
                     *end = 0;
              else
                     break;
       return s;
}

Here is the caller graph for this function:

static char* sasl_conv_func ( const char *  s,
void *  dummy 
) [static]

Definition at line 961 of file courieresmtpd.c.

{
char   *p;

       addiovec("334 ", 4);
       addiovec(s, strlen(s));
       addiovec("\r\n", 2);
       iovflush();

       p=iovreadline();
       if (!p)       exit(0);
       if ((p=strdup(p)) == 0)
       {
              perror("malloc");
              exit(0);
       }
       return (p);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void set_submit_error ( const char *  r,
int  rl 
) [static]

Definition at line 419 of file courieresmtpd.c.

{
char   *p;

       if (log_error_sender)       free(log_error_sender);
       if (log_error_to)    free(log_error_to);

       log_error_sender=0;
       if (mailfroms && (log_error_sender=strdup(mailfroms)) == 0)
              clog_msg_errno();

       log_error_to=0;
       if (r && rl)
       {
              if ((log_error_to=malloc(rl+1)) == 0)
                     clog_msg_errno();
              memcpy(log_error_to, r, rl);
              log_error_to[rl]=0;
       }

       if (log_error_sender && *log_error_sender)
              for (p=log_error_sender+1; p[1]; p++)
                     if (*p == '<' || *p == '>' || *p == ':')
                            *p=' ';

       if (log_error_to && *log_error_to)
              for (p=log_error_to+1; p[1]; p++)
                     if (*p == '<' || *p == '>' || *p == ':')
                            *p=' ';

       if (log_error_sender && *log_error_sender)
              submit_log_error_prefix(print_submit_log_fix);
       else
              submit_log_error_prefix(0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void showbanner ( ) [static]

Definition at line 139 of file courieresmtpd.c.

{
const char *banner=config_esmtpgreeting();
const char *p;

       do
       {
              for (p=banner; *p; p++)
                     if (*p == '\n')      break;
              addiovec((*p && p[1] ? "220-":"220 "), 4);
              addiovec(banner, p-banner);
              addiovec("\r\n", 2);
              if (*p)       p++;
              banner=p;
       } while (*banner);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static const char* skipaddress ( const char **  ptr) [static]

Definition at line 488 of file courieresmtpd.c.

{
const char *p;
int inquote=0;

       while ( **ptr && isspace((int)(unsigned char)**ptr) )
              ++*ptr;

       if (**ptr != '<')    return (0);
       p= ++*ptr;

       while (*p)
       {
              if (*p == '>' && !inquote)  return (p);
              if (*p == '"')       inquote ^= 1;
              if (*p == '\\' && p[1])     ++p;
              ++p;
       }
       return (0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static const char* smtp_externalauth ( ) [static]

Definition at line 79 of file courieresmtpd.c.

{
       const char *p;

       if ((p=getenv("ESMTP_TLS")) && atoi(p))
              return externalauth();

       return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void startsubmit ( int  tls) [static]

Definition at line 296 of file courieresmtpd.c.

{
       char   *argv[14];
       const char *ident;
       char   *identbuf=0;
       int    n, exid_ndx=0;
       const  char *host;
       char   *buf;
       char rfc3848_buf[32];

       if (submit_started)  return;
       if (helobuf[0] == '\0')     return;

       argv[0]="submit";
       argv[1]=getenv("RELAYCLIENT") ? "-src=authsmtp":"-src=smtp";
       n=2;

       if (authuserbuf[0])
       {
              char *p;

              static char authbuf[sizeof(authuserbuf)+sizeof("-auth=")];

              p=strchr(authuserbuf, ' ');
              if (p)
              {
                     strcat(strcpy(authbuf, "-auth="), p+1);
                     argv[n++]=authbuf;
              }
              exid_ndx=1;
       }

       strcpy(rfc3848_buf, "-rfc3848=");

       if (extended)
       {
              static char *exid[] =
                     {"ESMTP",
                      "ESMTPA",
                      "ESMTPS",
                      "ESMTPSA"};

              if (tls) exid_ndx += 2;
              strcat(rfc3848_buf, exid[exid_ndx]);

       }
       else
       {
              strcat(rfc3848_buf, "SMTP");
       }
       argv[n++]=rfc3848_buf;

       argv[n++]="esmtp";

       host=tcpremotehost;

       if (!host)    host="";
       argv[n]=buf=courier_malloc(strlen(host)+strlen(tcpremoteip)+strlen(
              helobuf)+sizeof("dns;  ( [])"));

       strcat(strcat(strcpy(buf, "dns; "), helobuf), " (");
       if (*host)
              strcat(strcat(buf, host), " ");
       strcat(strcat(strcat(buf, "["), tcpremoteip), "])");

       ++n;

       if ((ident=getenv("TCPREMOTEINFO")) == 0)
              ident="";

       if (*ident || authuserbuf[0] || tls)
       {
              argv[n]=identbuf=courier_malloc(sizeof("IDENT: , AUTH: , ")+
                                          strlen(tlsbuf)+
                                          strlen(ident)+
                                          strlen(authuserbuf));
              ++n;
              *identbuf=0;
              if (*ident)
                     strcat(strcat(identbuf, "IDENT: "), ident);
                if (authuserbuf[0])
                {
                        if (*identbuf)  strcat(identbuf, ", ");
                        strcat(strcat(identbuf, "AUTH: "), authuserbuf);
                     putenv(strcat(
                             strcpy(
                               courier_malloc(sizeof("SENDERAUTH=") +
                                            strlen(authuserbuf)),
                               "SENDERAUTH="), authuserbuf));
              }

              if (tls)
              {
                     if (*identbuf)       strcat(identbuf, ", ");
                     strcat(identbuf, tlsbuf);
              }
       }

       argv[n]=0;

       if (submit_fork(argv, environ, submit_print_stdout) == 0)
              submit_started=1;

       if (identbuf) free(identbuf);
       free(buf);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void tarpit ( ) [static]

Definition at line 89 of file courieresmtpd.c.

{
       const char *p;
       if ((p=getenv("TARPIT")) && atoi(p))
       {
              sleep(teergrube);
              teergrube *= 2;
              if (teergrube > MAX_TEERGRUBE)
                     teergrube=MAX_TEERGRUBE;
       }
}

Here is the caller graph for this function:

static const char* truncate_ipv6 ( const char *  tcp) [static]

Definition at line 72 of file courieresmtpd.c.

{
       if (strncmp(tcp, "::ffff:", 7) == 0)
              tcp += 7;
       return tcp;
}

Here is the caller graph for this function:


Variable Documentation

char authuserbuf[256] [static]

Definition at line 46 of file courieresmtpd.c.

time_t data_timeout [static]

Definition at line 61 of file courieresmtpd.c.

char** environ
int extended [static]

Definition at line 48 of file courieresmtpd.c.

int hasexdata [static]

Definition at line 52 of file courieresmtpd.c.

int hasstarttls [static]

Definition at line 54 of file courieresmtpd.c.

int hasverp [static]

Definition at line 53 of file courieresmtpd.c.

char helobuf[256] [static]

Definition at line 45 of file courieresmtpd.c.

char* input_line = "" [static]

Definition at line 59 of file courieresmtpd.c.

Definition at line 27 of file esmtpiov.c.

Definition at line 28 of file esmtpiov.c.

char* log_error_sender = 0 [static]

Definition at line 414 of file courieresmtpd.c.

char* log_error_to = 0 [static]

Definition at line 415 of file courieresmtpd.c.

char* mailfroms = 0 [static]

Definition at line 56 of file courieresmtpd.c.

unsigned long sizelimit [static]

Definition at line 50 of file courieresmtpd.c.

int submit_started = 0 [static]

Definition at line 51 of file courieresmtpd.c.

const char * tcpremotehost [static]

Definition at line 63 of file courieresmtpd.c.

const char* tcpremoteip [static]

Definition at line 63 of file courieresmtpd.c.

time_t teergrube = INIT_TEERGRUBE [static]

Definition at line 68 of file courieresmtpd.c.

char tlsbuf[128+NUMBUFSIZE] [static]

Definition at line 47 of file courieresmtpd.c.