Back to index

courier  0.68.2
Defines | Functions
sendmail.c File Reference
#include "courier.h"
#include "rw.h"
#include "rfc822.h"
#include "comsubmitclient.h"
#include "maxlongsize.h"
#include "numlib/numlib.h"
#include "sbindir.h"
#include <pwd.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>

Go to the source code of this file.

Defines

#define EX_NOUSER   67
#define EX_TEMPFAIL   75
#define EX_NOPERM   77

Functions

void esmtpd ()
static struct passwd * mypwd ()
static const char * env (const char *envname)
static char * rewrite_env_sender (const char *from)
static char * rewrite_from (const char *, const char *, const char *, const char *)
static struct rfc822ttokenize_name (const char *name)
static char * get_gecos ()
static void rewrite_headers (const char *From)
static void exit_submit (int errcode)
int main (int argc, char **argv)

Define Documentation

#define EX_NOPERM   77

Definition at line 24 of file sendmail.c.

#define EX_NOUSER   67

Definition at line 22 of file sendmail.c.

#define EX_TEMPFAIL   75

Definition at line 23 of file sendmail.c.


Function Documentation

static const char* env ( const char *  envname) [static]

Definition at line 55 of file sendmail.c.

{
const char *p=getenv(envname);

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

Here is the caller graph for this function:

void esmtpd ( )

Definition at line 49 of file sendmail-esmtpd-wrapper.c.

{
uid_t orig_uid=getuid();
char   ubuf[NUMBUFSIZE];
char   remoteinfobuf[NUMBUFSIZE+30];
char   *environ[6];
char   *argv[2];
int    pipefd[2];
pid_t  pid;

       sprintf(remoteinfobuf, "TCPREMOTEINFO=uid %s",
              libmail_str_uid_t(orig_uid, ubuf));

       if (pipe(pipefd) < 0)
       {
              perror("pipe");
              exit(EX_TEMPFAIL);
       }

       if (chdir(courierdir()) < 0)
       {
              perror("chdir");
              exit(EX_TEMPFAIL);
       }

       pid=fork();
       if (pid < 0)
       {
              perror("fork");
              exit(EX_TEMPFAIL);
       }
       if (pid == 0)
       {
              dup2(pipefd[1], 1);
              close(pipefd[0]);
              close(pipefd[1]);
              execl(BINDIR "/addcr", "addcr", (char *)0);
              perror("exec");
              exit(EX_TEMPFAIL);
       }
       dup2(pipefd[0], 0);
       close(pipefd[0]);
       close(pipefd[1]);
       close(2); open("/dev/null", O_WRONLY); /* Pine temper tantrum */

       environ[0]="TCPREMOTEIP=127.0.0.1";
       environ[1]="TCPREMOTEHOST=localhost";
       environ[2]=remoteinfobuf;
       environ[3]="RELAYCLIENT=";
       environ[4]="FAXRELAYCLIENT=";
       environ[5]=0;
       argv[0]="sendmail";
       argv[1]=0;
       execve(SBINDIR "/courieresmtpd", argv, environ);
       perror("exec");
       exit(EX_TEMPFAIL);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void exit_submit ( int  errcode) [static]

Definition at line 346 of file sendmail.c.

{
       if (errcode == -5)
              exit(EX_NOUSER);

       exit(EX_TEMPFAIL);
}

Here is the caller graph for this function:

static char* get_gecos ( ) [static]

Definition at line 110 of file sendmail.c.

{
struct passwd *pw=mypwd();
char   *p, *q;

       if (!pw || !pw->pw_gecos)   return (0);

       p=strcpy(courier_malloc(strlen(pw->pw_gecos)+1), pw->pw_gecos);

       if ((q=strchr(p, ',')) != 0)       *q=0;
       return (p);
}

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 354 of file sendmail.c.

{
const char *from=0;
const char *From=0;
const char *ret=0, *dsn=0, *security=0, *envid=0;
int    argn, argp;
int    errflag=0;
int    c;
char   *args[6];
char   *envs[7];
int    envp;
int    tostdout=0;
char   frombuf[NUMBUFSIZE+30];
int    doverp=0;
int    bcconly=0;
char   ubuf[NUMBUFSIZE];
char   *uucprmail=0;
char   *s;
char   ret_buf[2], security_buf[40];
int     submit_errcode;

       /*
       ** Immediately drop uid, force GID to MAILGID
       ** The reason we can't just setgid ourselves to MAILGID is because
       ** that only sets the effective uid.  We need to also set both
       ** real and effective GIDs, otherwise maildrop filtering will fail,
       ** because the real gid won't be trusted.
       */
       setgid(MAILGID);
       setuid(getuid());
       signal(SIGCHLD, SIG_DFL);
       signal(SIGPIPE, SIG_IGN);
       argn=1;

       putenv("AUTHMODULES="); /* See module.local/local.c */

       putenv("LANG=en_US");
       putenv("CHARSET=iso-8859-1");
       putenv("MM_CHARSET=iso-8859-1");

#if HAVE_SETLOCALE
       setlocale(LC_ALL, "C");
#endif

       /* Only uucp can run rmail (this better be installed setgid) */

       if ((s=strrchr(argv[0], '/')) != 0)       ++s;
       else   s=argv[0];
       if (strcmp(s, "rmail") == 0)
       {
       struct passwd *p=mypwd();
       char   *uu_machine, *uu_user;

              if (!p || strcmp(p->pw_name, "uucp"))
              {
                     fprintf(stderr, "rmail: permission denied.\n");
                     exit(EX_NOPERM);
              }

              uu_machine=getenv("UU_MACHINE");
              uu_user=getenv("UU_USER");

              if (!uu_machine || !uu_user)
              {
                     fprintf(stderr,
                            "rmail: UU_MACHINE!UU_USER required.\n");
                     exit(EX_NOPERM);
              }
              uucprmail=malloc(strlen(uu_machine)+strlen(uu_user)+2);
              if (!uucprmail)
              {
                     perror("malloc");
                     exit(EX_TEMPFAIL);
              }
              strcat(strcat(strcpy(uucprmail, uu_machine), "!"), uu_user);
       }

       while (argn < argc)
       {
       const char *arg;
       int    c;

              if (argv[argn][0] != '-')   break;

              if (strcmp(argv[argn], "-") == 0)
              {
                     ++argn;
                     break;
              }

              if (uucprmail && strncmp(argv[argn], "-f", 2)

              /*
              ** Ok, obviously no UUCP version will give me the following
              ** options, must I can hope, can't I?
              */
                     && strcmp(argv[argn], "-verp")
                     && strncmp(argv[argn], "-N", 2)
                     && strncmp(argv[argn], "-R", 2)
                     && strncmp(argv[argn], "-V", 2)

                     /* Ignore the ignorable */

                     && strncmp(argv[argn], "-o", 2)
                     && strncmp(argv[argn], "-t", 2)

                     )
              {
                     fprintf(stderr, "rmail: invalid option %s\n",
                            argv[argn]);
                     exit(EX_NOPERM);
              }

              if (strcmp(argv[argn], "-verp") == 0)
              {
                     doverp=1;
                     ++argn;
                     continue;
              }

              if (strcmp(argv[argn], "-bcc") == 0)
              {
                     bcconly=1;
                     ++argn;
                     continue;
              }

              if (strcmp(argv[argn], "-bs") == 0)
              {
                     esmtpd();
              }
              switch (c=argv[argn][1])    {
              case 'o':
              case 'f':
              case 'F':
              case 'R':
              case 'N':
              case 'S':
              case 'V':
                     break;
              case 'n':
                     tostdout=1;
                     ++argn;
                     continue;
              default:
                     ++argn;
                     continue;
              }
              arg=argv[argn]+2;
              if (!*arg && argn+1 < argc)
                     arg=argv[++argn];
              ++argn;

              if (c == 'f')
                     from=arg;
              else if (c == 'F')
                     From=arg;
              else if (c == 'N')
                     dsn=arg;
              else if (c == 'S')
              {
                     char *q;

                     if (strcasecmp(arg, "NONE") &&
                         strcasecmp(arg, "STARTTLS"))
                     {
                            fprintf(stderr, "sendmail: invalid option"
                                   " -S %s\n",
                                   arg);
                            exit(EX_NOPERM);
                     }
                     strcpy(security_buf, arg);

                     for (q=security_buf; *q; q++)
                            *q=toupper((int)(unsigned char)*q);

                     security=security_buf;
              }
              else if (c == 'R')
              {
                     ret_buf[0]= toupper((int)(unsigned char)*arg);
                     ret_buf[1]= 0;
                     ret=ret_buf;
              }
              else if (c == 'V')
                     envid=arg;
       }

       sprintf(frombuf, "uid %s", libmail_str_uid_t(getuid(), ubuf));
       argp=0;
       args[argp++]="submit";
       if (bcconly)
              args[argp++]="-bcc";

       if (uucprmail)
       {
              if (argn >= argc)
              {
                     fprintf(stderr, "rmail: missing recipients\n");
                     exit(EX_NOPERM);
              }

              args[argp++]="uucp";
              s=malloc(sizeof("unknown; uucp ()")+strlen(uucprmail));
              if (!s)
              {
                     perror("malloc");
                     exit(EX_TEMPFAIL);
              }
              strcat(strcat(strcpy(s, "unknown; uucp ("), uucprmail), ")");
              args[argp++]=s;
       }
       else
       {
              args[argp++]="local";
              args[argp++]="dns; localhost (localhost [127.0.0.1])";
              args[argp++]=frombuf;
       }
       args[argp++]=0;
       envp=0;

       clog_open_stderr("sendmail");
       if (ret || security || doverp)
       {
              envs[envp]=strcat(strcat(strcpy(courier_malloc(strlen(ret ?
                     ret:"")+strlen(security ? security:"") + 30),
                                          "DSNRET="), (ret ? ret:"")),
                              (doverp ? "V":""));
              if (security)
                     strcat(strcat(strcat(envs[envp], "S{"),
                                  security), "}");

              ++envp;
       }

       if (dsn)
       {
              envs[envp]=strcat(strcpy(courier_malloc(strlen(dsn)+11),
                     "DSNNOTIFY="), dsn);
              ++envp;
       }
       if (envid)
       {
              envs[envp]=strcat(strcpy(courier_malloc(strlen(envid)+10),
                     "DSNENVID="), envid);
              ++envp;
       }
       envs[envp++]="TCPREMOTEHOST=localhost";
       envs[envp++]="TCPREMOTEIP=127.0.0.1";

       if (!uucprmail)
              envs[envp++]=strcat(strcpy(courier_malloc(strlen(frombuf)+
                            sizeof("TCPREMOTEINFO=")),
                            "TCPREMOTEINFO="), frombuf);
       envs[envp]=0;

       if (!tostdout && submit_fork(args, envs, submit_print_stdout))
       {
              fprintf(stderr, "sendmail: Service temporarily unavailable.\n");
              exit(EX_TEMPFAIL);
       }

       if (tostdout)
              submit_to=stdout;
       else
       {
              if (uucprmail)
              {
                     submit_write_message(from ? from:"");
              }
              else
              {
              char   *p;

                     p=rewrite_env_sender(from);
                     submit_write_message(p);
                     free(p);
              }
              if ((submit_errcode=submit_readrcprinterr()) != 0)
              {
                     exit_submit(submit_errcode);
              }
       }

       while (!tostdout && argn < argc)
       {
              submit_write_message(argv[argn]);
              if ((errflag=submit_readrcprinterr()) != 0)
              {
                     fprintf(stderr, "%s: invalid address.\n", argv[argn]);
              }
              ++argn;
       }
       if (errflag)  exit_submit(errflag);
       if (!tostdout)
              putc('\n', submit_to);

       if (!uucprmail)
              rewrite_headers(From);

       while ((c=getchar()) != EOF)
       {
              putc(c, submit_to);
       }
       fflush(submit_to);
       signal(SIGINT, SIG_IGN);
       signal(SIGTERM, SIG_IGN);
       signal(SIGHUP, SIG_IGN);

       errflag=0;
       if (ferror(submit_to) || (!tostdout && (
              fclose(submit_to) ||
              (errflag=submit_readrcprinterr()) || submit_wait()))
              )
       {
              fprintf(stderr, "sendmail: Unable to submit message.\n");
              if (errflag)
                     exit_submit(errflag);
              exit(EX_TEMPFAIL);
       }
       exit(0);
}

Here is the call graph for this function:

static struct passwd* mypwd ( ) [static, read]

Definition at line 41 of file sendmail.c.

{
static struct passwd *pwd=0;
int    first_pwd=1;

       if (first_pwd)
       {
              first_pwd=0;
              pwd=getpwuid(getuid());
       }

       return (pwd);
}

Here is the caller graph for this function:

static char* rewrite_env_sender ( const char *  from) [static]

Definition at line 63 of file sendmail.c.

{
const char *host;

       if (!from)
       {
              if ((from=env("MAILSUSER")) == 0 &&
                     (from=env("MAILUSER")) == 0 &&
                     (from=env("LOGNAME")) == 0 &&
                     (from=env("USER")) == 0)
              {
              struct passwd *pw=mypwd();

                     from=pw ? pw->pw_name:"nobody";
              }

              if ((host=env("MAILSHOST")) != 0 ||
                     (host=env("MAILHOST")) != 0)
              {
              char   *p=courier_malloc(strlen(from)+strlen(host)+2);

                     return (strcat(strcat(strcpy(p, from), "@"), host));
              }
       }
       return (strcpy(courier_malloc(strlen(from)+1), from));
}

Here is the call graph for this function:

Here is the caller graph for this function:

static char * rewrite_from ( const char *  oldfrom,
const char *  newuser,
const char *  newhost,
const char *  newname 
) [static]

Definition at line 214 of file sendmail.c.

{
struct rfc822t *rfct;
struct rfc822a *rfca;
struct rfc822t *usert, *hostt, *namet;
struct rfc822token attoken, **tp;
char   *p;
const char *q;
char   *gecosname=0;

       if (!oldfrom)
       {
       char   *p=courier_malloc(
                     (newuser ? strlen(newuser):0)+
                     (newhost ? strlen(newhost):0)+4);
              strcpy(p, "<");
              if (newuser)  strcat(p, newuser);
              if (newuser && newhost)
                     strcat(strcat(p, "@"), newhost);
              strcat(p, ">");
              if (newname)
              {
              char *q, *r;

                     namet=tokenize_name(newname);
                     q=rfc822_gettok(namet->tokens);
                     rfc822t_free(namet);
                     r=courier_malloc(strlen(p)+strlen(q)+2);
                     strcat(strcat(strcpy(r, q), " "), p);
                     free(p);
                     p=r;
                     free(q);
              }
              return (p);
       }

       if ((rfct=rfc822t_alloc_new(oldfrom, NULL, NULL)) == 0 ||
              (rfca=rfc822a_alloc(rfct)) == 0)
       {
              clog_msg_errno();
              return(0);
       }

       if ((q=env("MAILNAME")) || (q=env("NAME")))
              newname=q;

       if (!newname && rfca->naddrs == 0)
              newname=gecosname=get_gecos();

       if ((rfca->naddrs == 0 || rfca->addrs[0].tokens == 0) && newuser == 0)
       {
       struct passwd *pw=mypwd();

              if (pw)       newuser=pw->pw_name;
       }

       namet=newname ? tokenize_name(newname):0;
       usert=newuser ? rw_rewrite_tokenize(newuser):0;
       hostt=newhost ? rw_rewrite_tokenize(newhost):0;

       if (rfca->naddrs == 0 || rfca->addrs[0].tokens == 0)
       {
       struct rfc822addr a;
       struct rfc822a       fakea;

              if (hostt)
              {
              struct rfc822token *t;

                     attoken.token='@';
                     attoken.next=hostt->tokens;
                     attoken.ptr=0;
                     attoken.len=0;

                     for (t=usert->tokens; t->next; t=t->next)
                            ;
                     t->next=&attoken;
              }
              fakea.naddrs=1;
              fakea.addrs= &a;

              if (!namet)   namet=tokenize_name("");
              if (!usert)   usert=rw_rewrite_tokenize("");
              a.name=namet->tokens;
              a.tokens=usert->tokens;
              p=rfc822_getaddrs(&fakea);
       }
       else
       {
       struct rfc822token *t, *u;

              rfca->naddrs=1;
              if (usert)
              {
                     for (t=rfca->addrs[0].tokens; t; t=t->next)
                            if (t->token == '@') break;
                     
                     for (u=usert->tokens; u->next; u=u->next)
                            ;
                     u->next=t;
                     rfca->addrs[0].tokens=usert->tokens;;
              }

              if (hostt && rfca->addrs[0].tokens)
              {
                     for (tp= &rfca->addrs[0].tokens; *tp;
                            tp= &(*tp)->next)
                            if ( (*tp)->token == '@')   break;
                     *tp=&attoken;
                     attoken.token='@';
                     attoken.next=hostt->tokens;
                     attoken.ptr=0;
                     attoken.len=0;
              }
              if (namet)
                     rfca->addrs[0].name=namet->tokens;

              p=rfc822_getaddrs(rfca);
       }

       if (!p)       clog_msg_errno();

       if (usert)    rfc822t_free(usert);
       if (hostt)    rfc822t_free(hostt);
       if (namet)    rfc822t_free(namet);
       rfc822t_free(rfct);
       rfc822a_free(rfca);
       if (gecosname)       free(gecosname);
       return (p);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void rewrite_headers ( const char *  From) [static]

Definition at line 123 of file sendmail.c.

{
int    seen_from=0;
char   headerbuf[5000];
int    c, i;
const char *mailuser, *mailuser2, *mailhost;
char   *p;
char   *pfrom=From ? strcpy(courier_malloc(strlen(From)+1), From):0;

       if ((mailuser=env("MAILUSER")) == 0 &&
              (mailuser=env("LOGNAME")) == 0)
              mailuser=env("USER");
       mailuser2=env("MAILUSER");
       mailhost=env("MAILHOST");

       while (fgets(headerbuf, sizeof(headerbuf), stdin))
       {
       char   *p=strchr(headerbuf, '\n');

              if (p)
              {
                     *p=0;
                     if (p == headerbuf || strcmp(headerbuf, "\r") == 0)
                            break;
              }

#if HAVE_STRNCASECMP
              if (strncasecmp(headerbuf, "from:", 5))
#else
              if (strnicmp(headerbuf, "from:", 5))
#endif
              {
                     fprintf(submit_to, "%s", headerbuf);
                     if (!p)
                            while ((c=getchar()) != EOF && c != '\n')
                                   putc(c, submit_to);
                     putc('\n', submit_to);
                     continue;
              }
              if (!p)
                     while ((c=getchar()) != EOF && c != '\n')
                            ;      /* I don't care */
              if (seen_from)       continue;     /* Screwit */
              seen_from=1;

              i=strlen(headerbuf);
              for (;;)
              {
                     c=getchar();
                     if (c != EOF) ungetc(c, stdin);
                     if (c == EOF || c == '\r' || c == '\n')   break;
                     if (!isspace((int)(unsigned char)c))      break;
                     while ((c=getchar()) != EOF && c != '\n')
                     {
                            if (i < sizeof(headerbuf)-1)
                                   headerbuf[i++]=c;
                     }
                     headerbuf[i]=0;
              }

              p=rewrite_from(headerbuf+5, mailuser2, mailhost, pfrom);
              fprintf(submit_to, "From: %s\n", p);
              free(p);
       }
       if (!seen_from)
       {
              if (!mailuser)
              {
              struct passwd *pw=mypwd();

                     mailuser=pw ? pw->pw_name:"nobody";
              }

              if (!pfrom)
              {
                     if ( !(From=env("MAILNAME")) && !(From=env("NAME")))
                     {
                            pfrom=get_gecos();
                     }
                     else   pfrom=strcpy(courier_malloc(strlen(From)+1),
                                        From);
              }

              p=rewrite_from(NULL, mailuser, mailhost, pfrom);
              fprintf(submit_to, "From: %s\n", p);
              free(p);
       }
       putc('\n', submit_to);
       if (pfrom)    free(pfrom);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static struct rfc822t* tokenize_name ( const char *  name) [static, read]

Definition at line 93 of file sendmail.c.

{
struct rfc822t *p=rw_rewrite_tokenize(name);
struct rfc822token *t;

       for (t=p->tokens; t; t=t->next)
              if (t->token) break;
       if (t == 0)   return (p);   /* Only atoms */
       if (p->tokens == 0)  return (p);

       p->tokens->token='"';
       p->tokens->next=0;
       p->tokens->ptr=name;
       p->tokens->len=strlen(name);
       return (p);
}

Here is the call graph for this function:

Here is the caller graph for this function: