AutoBounce the automatic mail bouncer
Pete Shipley
shipley at e260-4g.berkeley.edu
Sat Feb 25 16:57:06 AEST 1989
Here it is, a automatic mail bouncer, the local postmater has asked
me to stop using this. So I am posting it to the world....
Pete Shipley:
email: shipley at berkeley.edu Flames: cimarron at postgres.berkeley.edu
uunet!lurnix!shipley or ucbvax!shipley or pyramid!hippo!{ root peter }
Spelling corections: /dev/null Quote: "Anger is an energy"
-=-=-=-=- cut here -=-=-=-=-
#! /bin/sh
mkdir Autobounce
cd Autobounce
echo x - Makefile
cat >Makefile <<'!E!O!F!'
DEST = .
EXTHDRS = /usr/include/ctype.h \
/usr/include/machine/param.h \
/usr/include/machine/param.h \
/usr/include/netdb.h \
/usr/include/netinet/in.h \
/usr/include/pwd.h \
/usr/include/signal.h \
/usr/include/stdio.h \
/usr/include/sys/fcntl.h \
/usr/include/sys/file.h \
/usr/include/sys/ioctl.h \
/usr/include/sys/param.h \
/usr/include/sys/socket.h \
/usr/include/sys/sysmacros.h \
/usr/include/sys/time.h \
/usr/include/sys/ttychars.h \
/usr/include/sys/ttydev.h \
/usr/include/sys/types.h \
/usr/include/time.h
HDRS =
# STRNCASECMP define if strcasecmp() does not exist (eg: non 4.3 systems)
#
CFLAGS = -g -pipe -I. -DSTRNCASECMP #-DDEBUG
LDFLAGS = $(CFLAGS)
LIBS =
LINKER = $(CC)
MAKEFILE = Makefile
OBJS = mbounce.o
PRINT = psgrind
PROGRAM = autobounce
SRCS = mbounce.c
all: $(PROGRAM) manpage
$(PROGRAM): $(OBJS)
$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
clean:; @rm -f $(OBJS) autobounce.man tags
depend:; @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)
index:; @ctags -wx $(HDRS) $(SRCS)
manpage: autobounce.1
tbl autobounce.1 | nroff -man > autobounce.man
install: $(PROGRAM)
@echo Installing $(PROGRAM) in $(DEST)
@install -s $(PROGRAM) $(DEST)
print:; @$(PRINT) $(HDRS) $(SRCS)
program: $(PROGRAM)
lint:; lint $(SRCS)
tags: $(HDRS) $(SRCS)
ctags -tw $(HDRS) $(SRCS)
update: $(DEST)/$(PROGRAM)
$(DEST)/$(PROGRAM): $(SRCS) $(LIBS) $(HDRS) $(EXTHDRS)
@make -f $(MAKEFILE) DEST=$(DEST) install
###
!E!O!F!
echo x - autobounce.1
cat >autobounce.1 <<'!E!O!F!'
.TH MAN 1 "24 Feb 1989"
.SH NAME
autobounce \- bounced mail impersonator
.SH SYNOPSIS
.B man
.RB "[\|" \-b "\|]"
.RB "[\|" \-d "\|]"
.RB "[\|" \-o "\|]"
.RB "[\|" \-f \0\fIfile\fP "\|]"
.RB "[\|" \-h \0\fImailerhost\fP "\|]"
.SH DESCRIPTION
.I autobounce
can be used to forge bounced mail messages.
It is normally used by placing in one's \*Q.forward\*U file
so it can be used to reject unwanted mail.
It can also be use to form the command line to previously received
bounce mail.
.SH OPTIONS
.PP
.TP
.B \-b
Force the sending of a forged bounce. (even is user does not appear
in the \*Q.shitlist\*U config file).
.TP
.B -d
turn on debugging infomation.
.TP
.B \-o
Send output to stdout instead of the smtp port of the mailerhost.
.TP
.B \-f
Take input from specified file instead of stdin.
.TP
.B \-h
specify the host to deliver the bounced mail to.
.SH USAGE
Autobounce is normally run from within your .forward file.
To run create a
.I \&.forward
file in your home directory containing a line of the form:
.IP
\e\fIname\fP, "|/the/full/path/to/autobounce"
.LP
where
.I name
is your login name.
.SH SHITLIST FILE FORMAT
The default file \*Q$HOST/.shitlist\*U has the following format:
.sp 1
.ti 0.5i
bounce user \fI%_chance_of_bounce\fP \fInumber_of_bounces\fP
.LP
Where: user if the user name you wish to bounce.
%_chance_of_bounce is a optional percent chance of bouncing the letter
(default is 100%).
number_of_bounces if the number of copies to send (default is one).
.LP
Other options that can be set in the .shitlist file
are the mailerhost and debug.
Mailerhost sets the system to connect and send the forged mail to.
Debug activates the debugging option.
.LP
Here is an example default file:
.in +0.5i
.na
.nf
bounce nory 100 40
bounce muir 10 100
bounce andy 50
bounce leo
mailerhost jade.berkeley.edu
.fi
.ad
.in -0.5i
.LP
.SH FILES
.TP
.I $HOST/.shitlist
default config file.
.SH "SEE ALSO"
vacation(1), RFC788, RFC821.
.SH BUGS
Lots. The reason list for the bounce looks fishy.
This badly written manpage.
!E!O!F!
echo x - mbounce.c
cat >mbounce.c <<'!E!O!F!'
#include <sys/param.h>
#include <sys/file.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <stdio.h>
#include <pwd.h>
#include <ctype.h>
/* mail data string to be feed to mailer */
static char header_string[] = "\
helo: %s\n\
mail from: %s<%s>\n\
rcpt to: %s<%s>\n\
data\n\
Subject: Returned mail: User unknown\n\
\n\
----- Transcript of session follows -----\n\
>>> RCPT To:<%s>\n\
<<< 550 <%s>... User unknown\n\
550 %s... User unknown\n\n\
----- Unsent message follows -----\n";
/* max taken from mail header configs */
#ifndef MAXLINE
#define MAXLINE 500
#endif
/* other random definitions */
#ifndef FALSE
#define FALSE 0
#endif FALSE
#ifndef TRUE
#define TRUE 1
#endif TRUE
/* this make coding more fun */
#ifndef EVER
#define EVER ;;
#endif EVER
/* thsi is a fun one */
#ifdef DEBUG
#define exit(X) abort(X);
#endif DEBUG
#ifndef ToLower
#define ToLower(X) (isupper(X) != 0 ? tolower(X) : X)
#endif ToLower
#ifndef StrMake
#define StrMake(X) strcpy( malloc((unsigned) strlen(X)+1), X)
#endif StrMake
/* linked list struct def */
typedef struct _Shitlist {
char name[MAXLINE];
int chance;
int count;
struct _Shitlist *next;
} Shitlist;
/* the struct is to hold the information on the current victim */
typedef struct user {
char to[MAXLINE];
char from[MAXLINE];
char cc[MAXLINE];
char id[MAXLINE];
char subject[MAXLINE];
char name[16];
u_int count;
} mailer;
/* Guess */
typedef char Boolean;
Shitlist *start_shit;
Boolean debug;
Boolean bounceall;
char *mailerhost = "localhost.berkeley.edu";
char *homedir;
#ifdef STRNCASECMP
Boolean strncasecmp();
#else
int strncasecmp();
#endif STRNCASECMP
static mailer *readheaders();
static Boolean checkbounce(),
nsearch();
static void sendmessage(),
logbounce(),
ReadDefaults(),
copycont();
static Shitlist *CreateLink();
static short servtoport();
static long hosttoaddr();
int getuid();
char *strcpy(),
*malloc(),
*tempnam(),
*index(),
*sprintf(),
*getenv(),
*strcat(),
*rindex();
/* here is where is all begins */
/* ARGUSED */
main(ac, av)
int ac;
char **av;
{
register int ch;
char *tempfile;
mailer *header;
FILE *tempfd, *infile;
Boolean use_stdout = FALSE;
extern int optind;
extern char *optarg;
extern int errno;
extern Boolean debug;
extern char *homedir;
extern Boolean bounceall;
/* init a few vars */
errno = 0;
infile = (FILE *) NULL;
debug = FALSE;
bounceall = FALSE;
/* load in the default file */
ReadDefaults();
#ifdef DEBUG
/* So core files can be found */
(void) chdir(homedir);
#endif DEBUG
/* Parse the arguments */
while((ch = getopt(ac, av, "dh:?obf:")) != EOF)
switch( (char) ch) {
case 'h': /* define new mailer host */
mailerhost = optarg;
break;
case 'd': /* activate debuging */
debug = TRUE;
break;
case 'b': /* force the bounce */
bounceall = TRUE;
break;
case 'f': /* take input from following file */
infile = fopen(optarg, "r");
if(infile == (FILE *) NULL) {
perror(optarg);
exit(1);
}
break;
case 'o': /* send output to stdout */
use_stdout = TRUE;
break;
case '?':
default:
(void) fprintf(stderr,
"Usage: %s [-o] [-f file] [-h hostname] [-b] [-d]\n",
av[0]);
(void) fputs(
"-o\tUse stdout instead of connecting to malerhost\n",
stderr);
(void) fputs("-f file\tuse file for input [stdin default]\n",
stderr);
(void) fputs(
"-h hostname\thost to connect and send mail to\n", stderr);
(void) fputs(
"-b\tforce bounce even if user does not appear in configurtion file\n",
stderr);
exit(1);
}
/* get a unique temp file name */
tempfile = tempnam((char *) NULL, "mboun");
if(debug)
(void) fprintf(stderr, "tempfile = '%s'\n", tempfile);
/* open a temporary file */
tempfd = fopen(tempfile, "w+");
if(tempfd == (FILE *) NULL) {
perror(tempfile);
exit(1);
}
/* free unneeded memory */
(void) free(tempfile);
/* unlink the tempory file to make it really temporary */
if(unlink(tempfile) == -1)
perror("unlink");
/* copy the incoming letter into the temp file */
if(infile) {
copycont(infile, tempfd);
(void) fclose(infile);
} else
copycont(stdin, tempfd);
/* parse the mail header */
header = readheaders(tempfd);
/* if bounce is not being forced, test for it */
if(!bounceall)
bounceall = checkbounce(header);
/* here we send it off */
if(bounceall)
for( ch = header->count; ch > 0; ch--)
/* Transmit the message */
sendmessage(header, tempfd, use_stdout);
/* bye bye */
exit(0);
}
/* this function checks to see it show bounce the letter */
static Boolean
checkbounce(hdata)
mailer *hdata;
{
Shitlist *current;
Boolean send;
/* set current to start of linked list */
current = start_shit;
/* don't bounce authors mail */
if (nsearch("shipley", hdata->from)) {
return(FALSE);
}
/* loop untill end of list or victem is found */
for (EVER) {
Shitlist *prev;
/* check for match */
if (nsearch(current->name, hdata->from)) {
send = TRUE;
hdata->count = current->count;
break;
}
/* look for end of list */
if(current->next == NULL)
break;
/* free unused date */
prev = current;
current = current->next;
if(!debug)
(void) free((char *) prev);
}
/* check if random bounce */
if(send && current->chance) {
(void) srand(getpid());
if( current->chance < (rand()%100) )
send = FALSE;
}
/* log the bouncing */
if(send)
logbounce(hdata);
/* and go home */
return(send);
}
/* the function sends the mail */
static void
sendmessage(hdata, datafd, use_stdout)
mailer *hdata;
FILE *datafd;
Boolean use_stdout;
{
char hostn[MAXLINE];
char from_addr[MAXLINE];
struct servent *sp;
FILE *fout;
/* get our hostname */
(void) gethostname(hostn, MAXLINE);
/* if we are not using stdout set up a connection */
if(!use_stdout) {
int sock;
struct sockaddr_in server;
struct hostent *hp, *gethostbyname();
/* Create socket */
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
/* Connect socket using name specified by command line. */
server.sin_family = AF_INET;
hp = gethostbyname(mailerhost);
if (hp == 0) {
(void) fprintf(stderr, "%s: unknown host\n", mailerhost);
exit(2);
}
/* get ugly */
bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
sp = getservbyname("smtp", "tcp");
server.sin_port = sp->s_port;
if(server.sin_port == htons(0)) {
(void) fputs("Unknown service: smtp\n", stderr);
exit(1);
}
/* test connection */
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
perror("connecting stream socket");
exit(1);
}
/* turn file des. into FILE* */
fout = fdopen(sock, "w");
} else
fout = stdout;
/* assemble maler header */
(void) sprintf(from_addr, "%s@%s", "MAILER-DAEMON", hostn);
/* check if we have to me verbose about life */
if(debug) {
(void) fprintf(stderr,
"From = '%s'\nTo = '%s'\nCc = '%s'\nsubject = '%s'\nId = '%s'\n",
hdata->from, hdata->to, hdata->cc, hdata->subject, hdata->id);
(void) fprintf(stderr, "hostname = '%s'\n", hostn);
(void) fflush(stderr);
}
/* start Xmiting */
(void) fprintf(fout, header_string,
hostn,
from_addr, from_addr,
hdata->from, hdata->from,
hdata->to,
hdata->to,
hdata->to);
/* start at the begining of the letter */
rewind(datafd);
/* copy the leter to output */
copycont(datafd, fout);
/* say good buy to the mailer [or stdout] */
(void) fputs("\n\n.\nquit\n", fout);
/* close the socket */
if (!use_stdout)
(void) fclose(fout);
/* bye bye*/
return;
}
/* the function parces the mailer header */
static mailer *
readheaders(in)
FILE *in;
{
register char *p;
int n;
char buf[MAXLINE];
mailer *mdata;
extern int errno;
/* allocate and init return data */
mdata = (mailer *)malloc(sizeof(mailer));
bzero((char *)mdata, sizeof(mailer));
/* init buffer since local Vars are not automaticly nulled */
bzero(buf, MAXLINE);
/* rewind the temp file so we can read the full contance */
(void) rewind(in);
if(errno) {
if(debug)
perror("rewind");
exit(1);
}
while (fgets(buf, sizeof(buf), in) && *buf != '\n') {
switch(*buf) {
case 'F': /* "From " */
if (!strncmp(buf, "From:", 5)) {
(void)strcpy(mdata->from, &buf[6]);
if( (n = strlen(mdata->from)) != 0)
mdata->from[n-1] = NULL;
}
break;
case 'C': /* "Cc:" */
if (!strncmp(buf, "Cc:", 3))
(void)strcpy(mdata->cc, &buf[4]);
if( (n = strlen(mdata->cc)) != 0)
mdata->cc[n-1] = NULL;
break;
case 'S': /* "Subject:" */
if (!strncmp(buf, "Subject:", 8))
(void)strcpy(mdata->subject, &buf[9]);
if( (n = strlen(mdata->subject)) != 0)
mdata->subject[n-1] = NULL;
break;
case 'T': /* "To:" */
if (!strncmp(buf, "To:", 3)) {
(void)strcpy(mdata->to, &buf[4]);
if( (p = index(mdata->to, ',')) != NULL)
*p = NULL;
else
if( (n = strlen(mdata->to)) != 0)
mdata->to[n-1] = NULL;
}
break;
case 'M': /* "Message-Id:" */
if (!strncmp(buf, "Message-Id:", 10))
(void)strcpy(mdata->id, &buf[11]);
if( (n = strlen(mdata->id)) != 0)
mdata->id[n-1] = NULL;
break;
}
}
/* set bounce count to 1 [may be reset in checkbounce] */
mdata->count = 1;
/* done here so return */
return mdata;
}
/* search a string for a substring. */
static Boolean
nsearch(name, string)
register char *name;
register char *string;
{
register int i;
for (i = strlen(name); *string; ++string)
if (*string == *name && !strncasecmp(name, string, i))
return(TRUE);
return(FALSE);
}
/* copy one FILE* into another FILE* */
static void
copycont(from, to)
FILE *from, *to;
{
register n;
char buf[BUFSIZ];
extern int errno;
extern Boolean debug;
/* reset error flag so we can test it later */
errno = 0;
/* loop untill out of data */
while(n = fread(buf, sizeof(char), BUFSIZ, from))
if(fwrite(buf, sizeof(char), n, to) != n) {
if(debug)
(void) perror("copycont");
}
/*
*if there is an error and debuging info is requested
* call perror & continue
*/
if(errno != 0 && debug)
(void) perror("Copycont");
return;
}
/* log bounce if log file exists */
static void
logbounce(hdata)
mailer *hdata;
{
char tbuf[MAXPATHLEN];
FILE *logfd;
extern char *homedir;
extern Boolean debug;
/* build path to log file */
(void) strcpy(tbuf, homedir);
(void) strcat(tbuf, "/.bouncelog");
/* open logfile */
logfd = fopen(tbuf, "a+");
/* test if we opened log file */
if(logfd == (FILE *) NULL) {
/* test if we report failer */
if(debug) perror(tbuf);
/* bye again */
return;
}
/* write log entery */
(void) fprintf(logfd,
"From = '%s'\nTo = '%s'\nCc = '%s'\nsubject = '%s'\nId = '%s'\ncount =%d\n",
hdata->from, hdata->to, hdata->cc, hdata->subject, hdata->id,
hdata->count);
/* close log file */
(void) fclose(logfd);
return;
}
/* create a link section */
static Shitlist *
CreateLink()
{
register Shitlist *newlink;
/* allocate mem for the new link */
newlink = (Shitlist *) malloc( sizeof(Shitlist) );
/* clean out the newly alloced memory */
bzero((char *) newlink, sizeof(Shitlist) );
/* return our new creation */
return(newlink);
}
/* read in our defaults file*/
static void
ReadDefaults()
{
char buf[BUFSIZ];
FILE *bfd;
int uid = getuid();
struct passwd *pw;
Shitlist *current;
extern char *homedir;
extern Boolean debug;
extern Boolean bounceall;
/* get teh passwd entery of user [needed for home directory] */
pw = getpwuid(uid);
/* test to see it we get what we want */
if(pw == (struct passwd *) NULL) {
(void) fprintf(stderr, "Can't get home directory for %d\n", uid);
exit(1);
} else
(void) strcpy(buf, pw->pw_dir);
/* copy the path to home directory into a safe place */
homedir = StrMake(pw->pw_dir);
/* build path to defuat file */
(void) strcat(buf, "/.shitlist");
/* be loud if necceary */
if(debug)
(void) fprintf(stderr, "<bounce> buf = '%s'\n", buf);
/* open the default file */
bfd = fopen(buf, "r");
/* check if we cant open default file */
if(bfd == (FILE *) NULL) {
if(debug)
perror(buf);
return;
}
/* start the list */
current = start_shit = CreateLink();
/* assemble the list */
while ( fgets(buf, BUFSIZ, bfd) != NULL)
switch(*buf) {
case 'd': /* "mailerhost" */
case 'D': /* "Mailerhost" */
if (!strncasecmp(buf, "debug", 5))
debug = TRUE;
break;
case 'm': /* "mailerhost" */
case 'M': /* "Mailerhost" */
if (!strncasecmp(buf, "mailerhost", 10)) {
char *tp;
/* skip the while space */
if( (tp = index(buf, ' ')) == NULL)
break;
else
tp++;
if(*tp != NULL) {
mailerhost = StrMake(tp);
mailerhost[strlen(mailerhost) -1] = '\0';
}
}
if(debug)
(void) fprintf(stderr, "mailerhost = '%s'\n",
mailerhost);
break;
case 'b': /* "bounce" */
case 'B': /* "Bounce" */
if(bounceall)
break;
if (!strncasecmp(buf, "bounce", 6)) {
char *tp;
if( (tp = index(buf, ' ')) == NULL)
break;
else
tp++;
if(*tp == NULL)
break;
if (nsearch("!any", tp)) {
bounceall = TRUE;
break;
}
/* Check if the is the first link */
if(current->name[0] != '\0') {
current->next = CreateLink();
current = current->next;
}
(void) sscanf(tp, "%s %d %d",
current->name, ¤t->chance, ¤t->count);
if(current->count == 0) {
current->count = 1;
}
if(debug)
(void) fprintf(stderr,
"buf = '%s'\tchance = %d\tcount = %d\n",
current->name, current->chance, current->count);
}
}
/* be neet and clean */
(void) fclose(bfd);
/* go home */
return;
}
#ifdef STRNCASECMP
Boolean
strncasecmp(s1, s2, n)
char *s1, *s2;
register int n;
{
register u_char *r1 = (u_char *)s1;
register u_char *r2 = (u_char *)s2;
while (--n >= 0 && ToLower(*s1) == ToLower(*s2)) {
*s2++;
if (*s1++ == '\0')
return(FALSE);
}
return (n<0 ? 0 : *s1 - *--s2);
}
#endif STRNCASECMP
/* END OF TEXT */
!E!O!F!
echo x - sample.shitlist
cat >sample.shitlist <<'!E!O!F!'
bounce phr 50 2
bounce stephan 100 40
bounce c60a-4fl 33 2
bounce adamj 20
bounce muir 25
bounce hans 75 1
bounce andy
bounce cimarron 20 1
bounce shipley 50 2
bounce psb 30 1
mailerhost widow.berkeley.edu
!E!O!F!
cd ..
Pete Shipley:
email: shipley at berkeley.edu Flames: cimarron at postgres.berkeley.edu
uunet!lurnix!shipley or ucbvax!shipley or pyramid!hippo!{ root peter }
Spelling corections: /dev/null Quote: "Anger is an energy"
More information about the Alt.sources
mailing list