Viewing file:
sendmail.c (12.62 KB) -rw-rw-rw-Select action/file-type:

(
+) |

(
+) |

(
+) |
Code (
+) |
Session (
+) |

(
+) |
SDB (
+) |

(
+) |

(
+) |

(
+) |

(
+) |

(
+) |
/*
** Copyright 1998 - 2004 Double Precision, Inc.
** See COPYING for distribution information.
**
*/
#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>
#if HAVE_SYSEXITS_H
#include <sysexits.h>
#else
#define EX_NOUSER 67
#define EX_TEMPFAIL 75
#define EX_NOPERM 77
#endif
#if HAVE_LOCALE_H
#include <locale.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
extern void esmtpd();
static struct passwd *mypwd()
{
static struct passwd *pwd=0;
int first_pwd=1;
if (first_pwd)
{
first_pwd=0;
pwd=getpwuid(getuid());
}
return (pwd);
}
static const char *env(const char *envname)
{
const char *p=getenv(envname);
if (p && !*p) p=0;
return (p);
}
static char *rewrite_env_sender(const char *from)
{
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));
}
static char *rewrite_from(const char *, const char *, const char *,
const char *);
static struct rfc822t *tokenize_name(const char *name)
{
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);
}
static char *get_gecos()
{
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);
}
static void rewrite_headers(const char *From)
{
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);
}
static char *rewrite_from(const char *oldfrom, const char *newuser,
const char *newhost, const char *newname)
{
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);
}
static void exit_submit(int errcode)
{
if (errcode == -5)
exit(EX_NOUSER);
exit(EX_TEMPFAIL);
}
int main(int argc, char **argv)
{
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);
}