|
|
researchv8 Dan Cross
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <pwd.h>
#include <sys/stat.h>
#include <time.h>
#include <sys/timeb.h>
#include "letter.h"
#include "mail.h"
#include "string.h"
/* configuration */
#define DEAD "dead.letter"
#define MAILMODE (~0644) /* mode of created mail */
#define MAXFORWARD 32
#define MAXHOP 5
/* imports */
extern char *basename();
extern int (*signal())();
extern char *getsysname();
extern char *stringin();
extern char *getarg();
extern char *getenv();
extern char *mailpath();
extern char *upaspath();
extern void lock();
extern void unlock();
extern int rewrite();
extern int getrules();
extern long getunix();
extern void putunix();
extern void putrfunix();
extern FILE *popen();
extern char *getlogin();
extern char *asctime();
extern struct tm *localtime();
extern char *timezone();
/* exported */
char *thissys; /* name of this system */
char *network = "uucp"; /* name of network mail is coming from */
int onatty;
int rmail; /* true if not executed as 'mail' */
/* global to this module */
#define LETTERNAME 0
#define DEVTTY NOFILE-1
static int error;
static char *myname; /* name of this program */
/* predeclared */
static void saveletter();
static int saveonint(), done();
static int send();
static int append_to_file();
static int pipe_to_cmd();
static long getfrom();
extern void
sendmail(ac, av)
int ac;
char *av[];
{
int chkfl; /* check forward list */
int ind=1;
int (*rc)();
char sender[ADDRSIZE];
char date[DATESIZE];
long bodyoffset;
letter *lp;
/* avoid hanging dk lines (HACK!!!!!!!!) */
close(DEVTTY);
myname = basename(av[0]);
rmail = chkfl = strcmp(myname, "mail") != 0;
onatty = isatty(0);
thissys = getsysname();
/* make temporary */
rc = signal(SIGINT, done);
inittmp();
/* get network (default uucp) */
if (av[1][0] == '-' && av[1][1] == 'N') {
if (av[1][2] == '\0') {
network = av[2];
ind++;
} else {
network = &(av[1][2]);
}
ind++;
}
/* read letter */
(void)signal(SIGINT, saveonint);
lp = lopen(LETTERNAME, "w");
copyto(stdin, lp, onatty, 1);
if (ltell(lp) == 0L)
done();
/* send */
if (!error) {
(void)getrules();
lp = lopen(LETTERNAME, "r");
bodyoffset = getfrom(lp, sender, date);
(void)signal(SIGINT, rc);
for (; ind<ac; ind++) {
letseek(lp, bodyoffset);
error += send(lp, sender, date, av[ind], chkfl, 0);
}
}
if (error && onatty)
saveletter(lp);
(void)done();
}
/* come here on interrupt while reading in letter */
static int
saveonint() {
(void)signal(SIGINT, saveonint);
error++;
}
/* come here to finish up */
static int
done() {
unlock();
releasetmp();
exit(error);
}
/* save the letter in dead.letter */
static void
saveletter(lp)
letter *lp;
{
FILE *malf;
char where[PATHSIZE];
char *home = getenv("HOME");
(void)setgid(getgid());
(void)setuid(getuid());
if (home != NULL) {
strcpy(where, home);
strcat(where, "/");
} else
*where = '\0';
strcat(where, DEAD);
malf = fopen(where, "w");
if (malf == NULL) {
fprintf(stderr, "mail: cannot open %s\n", where);
return;
}
letseek(lp, (long)0);
copyfrom(lp, malf);
fclose(malf);
printf("Mail saved in %s\n", where);
}
/*
* Send a letter. Return 0 if all went well.
*/
static int
send(lp, sender, date, rcvr, chkfl, hop)
letter *lp;
char *sender, *date, *rcvr;
int chkfl;
int hop;
{
int rv, notinfl;
char dest[ADDRSIZE], rest[ADDRSIZE], cmd[CMDSIZE], format[32], sysname[64];
if ((notinfl = rewrite(rcvr, sender, chkfl, cmd)) < 0) {
fprintf(stderr, "mail: can't understand address %s\n", dest);
return 1;
}
if (cmd[0]=='\0')
rv = append_to_file(lp, sender, date, rcvr, chkfl, hop);
else
rv = pipe_to_cmd(lp, sender, date, rcvr, cmd,
chkfl && notinfl);
return rv;
}
/*
* Put mail into a mail file in the standard place.
*/
static int
append_to_file(lp, sender, date, rcvr, chkfl, hop)
letter *lp;
char *sender, *date, *rcvr;
int hop;
{
register mask;
struct passwd *pw, *getpwnam();
struct stat stbuf;
char file[PATHSIZE];
char sendto[CMDSIZE];
int exists;
FILE *malf;
char *p;
int i;
if (strcmp(rcvr, "-") == 0)
return(1);
if (strchr(rcvr, '/') != NULL) {
fprintf(stderr, "mail: illegal name %s\n", rcvr);
return(0);
}
strcpy(file, mailpath(rcvr));
switch (delivery_status(file, sendto) & MFTYPE) {
case MF_NORMAL:
/* normal message */
break;
case MF_FORWARD:
/* look for possible forwarding loop */
for (i = 0, p = sender-1; p != NULL; p = strchr(p+1, '!'))
if (strncmp(thissys, p+1, strlen(thissys))==0)
i++;
if (i > MAXHOP) {
logsend(rcvr, sender, date, "remote-mail-loop-err");
fprintf(stderr, "mail: remote mail loop\n");
break;
}
/* forward message */
return forward_to(lp, rcvr, sender, date, sendto, hop);
case MF_PIPE:
/* pipe to a command */
(void)stat(file, &stbuf);
return pipe_to(lp, rcvr, sender, date, sendto, stbuf.st_uid,
stbuf.st_gid);
}
exists = stat(file, &stbuf);
if ((pw = getpwnam(rcvr)) == NULL) {
if (exists < 0) {
if (chkfl) {
refuse(lp,sender, date, rcvr, "addressee unknown.");
return(0);
}
fprintf(stderr, "mail: can't send to %s\n", rcvr);
return 1;
}
} else {
stbuf.st_uid = pw->pw_uid;
stbuf.st_gid = pw->pw_gid;
}
mask = umask(MAILMODE);
lock(file);
malf = fopen(file, "a");
umask(mask);
if (malf == NULL) {
fprintf(stderr, "mail: cannot append to %s\n", file);
logsend(rcvr, sender, date, "append-err");
return 1;
}
if (exists < 0)
chown(file, stbuf.st_uid, stbuf.st_gid);
fprintf(malf, "%s%s %s\n", FROM, sender, date);
copyfrom(lp, malf);
fputs("\n", malf);
fclose(malf);
unlock();
logsend(rcvr, sender, date, "delivered");
notify(rcvr, sender); /* let him know it right away! */
return 0;
}
/*
* Pipe the mail into a command. This is either for remote
* mail or specially handled mail. Remote mail is distinguished
* by a non-null string as the destination.
*/
static int
pipe_to_cmd(lp, sender, date, rcvr, cmd, chkfl)
letter *lp;
char *sender, *date, *rcvr, *cmd;
int chkfl;
{
FILE *fp;
char errbuf[CMDSIZE];
char reason[2*CMDSIZE];
long pos, status;
/* check forwarding (what anti-social crap!) */
if (chkfl) {
if (rewrite(sender, "", chkfl, (char *)NULL) != 0) {
refuse(lp, sender, date, rcvr,
"forwarding to this system disallowed.");
return(0);
}
}
/* do it */
if ((fp=popen(cmd, getuid(), getgid())) == NULL) {
fprintf(stderr, "mail: can't pipe to network mailer\n");
exit(1);
}
pos = ltell(lp);
putrfunix(sender, date, thissys, fp);
copyfrom(lp, fp);
status = pclose(fp, errbuf, CMDSIZE);
if (status==0) {
logsend(rcvr, sender, date, "remote");
return 0;
} else {
logsend(rcvr, sender, date, "remote-err");
logsend("", cmd, "", "remote-err");
sprintf(reason, "\"%s\"\nwas unable to send your mail. It returned the status 0x%x.\nStderr was:\n%s",
cmd, status, errbuf);
(void)letseek(lp, pos);
refuse(lp, sender, date, rcvr, reason);
return 0;
}
}
/* return to sender, address unknown, no such number, no such phone... */
refuse(lp, sender, date, rcvr, reason)
letter *lp;
char *sender, *date, *rcvr, *reason;
{
FILE *pf;
char cbuf[CMDSIZE];
sprintf(cbuf, "PATH=/bin:/usr/bin mail %s", sender);
if ((pf = popen(cbuf, getuid(), getgid())) == NULL)
return;
fprintf(pf, "Mail to %s failed. %s\nMessage was:\n", rcvr, reason);
fprintf(pf, "%s%s %s\n", FROM, sender, date);
copyfrom(lp, pf);
pclose(pf, 0, 0);
logsend(rcvr, sender, date, "refused");
}
/* forward mail to a list of people */
forward_to(lp, rcvr, sender, date, list, hop)
letter *lp;
char *rcvr, *sender, *date, *list;
int hop;
{
char dest[ADDRSIZE];
char *p;
int rv=0;
if (hop > MAXFORWARD) {
fprintf(stderr, "mail: forwarding loop!!\n");
logsend(rcvr, sender, date, "forward-loop-err");
return 1;
}
for (p = list; (p = getarg(dest, p)) != NULL; ) {
(void)letseek(lp, (long)0);
rv += send(lp, sender, date, dest, 0, ++hop);
}
return rv;
}
#define SU 0 /* super-duper user uid */
/* change uid to the receiver and perform the command */
pipe_to(lp, rcvr, sender, date, cmd, uid, gid)
letter *lp;
char *rcvr, *sender, *date, *cmd;
{
FILE *fp;
int i;
/* do it */
if ((fp=popen(cmd, uid, gid)) == NULL) {
fprintf(stderr, "mail: can't pipe to network mailer\n");
return 1;
}
putunix(sender, date, fp);
copyfrom(lp, fp);
if ((i=pclose(fp, 0, 0))==0) {
logsend(rcvr, sender, date, "pipe_to");
return 0;
} else {
logsend(rcvr, sender, date, "pipe_to_err");
logsend("", cmd, "", "pipe_to_err");
fprintf(stderr, "mail: Pipe to \"%s\" returns error status %d\n",
cmd, i);
return 1;
}
}
/* default sender */
static void
defaultsender(sender, date)
char *sender; /* filled by defaultsender */
char *date; /* filled by defaultsender */
{
char *tp, *dp;
struct timeb timbuf;
struct tm *bp;
long thetime;
(void)strcpy(sender, getlogin());
ftime(&timbuf);
thetime = timbuf.time;
bp = localtime(&thetime);
dp = asctime(bp);
tp = timezone(timbuf.timezone, bp->tm_isdst);
sprintf(date, "%.16s %.3s %.4s", dp, tp, dp+20);
}
/* Get/parse a unix header. */
static long
getfrom(lp, sender, date)
letter *lp;
char *sender, *date;
{
char line[FROMLINESIZE];
long n=0;
defaultsender(sender, date);
initgetunix();
while (lgets(line, sizeof(line), lp) != NULL) {
if (getunix(line, sender, date) == 0)
break;
n = ltell(lp);
}
return n;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.