[comp.sources.misc] v03i019: Sendmail replacement for smail sites

jv@mh.nl.UUCP (Johan Vromans) (05/16/88)

comp.sources.misc: Volume 3, Issue 19
Submitted-By: "Johan Vromans" <jv@mh.nl.UUCP>
Archive-Name: sm-smtp

Lots of people asked me for this, so here it is ...

This is a merger of Ian's standalone talker and MIT's talker.
Peter Honeyman hacked on it to make it work correctly on the Arpanet.

Adapted by Johan Vromans <jv@mh.nl>, May 1988

 - simplified code

 - adapted to System V (Most notably: HP-UX)

 - added better host/domain name handling & setup

 - added time-routine (from smail)

 - added "config.h" for local settings, and moved common includes and
   portability code to "smtp.h"

 - produces a "smtpd" to be used under inetd, "sa-smtpd" (standalone) and
   "smtp" interface program.

#---------------- cut here ----------------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Makefile
#	README
#	cmds.h
#	config.h
#	converse.c
#	dconverse.c
#	misc.c
#	miscerrs.h
#	mx.c
#	netio.c
#	smtp.8
#	smtp.c
#	smtp.h
#	smtpd.c
#	sysexits.h
#	syslog.h
#	MANIFEST
# This archive created: Mon May 16 17:16:19 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'Makefile'" '(800 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#!/bin/make
X
XCFLAGS	= -O
XLIBS	= -lBSD -lbsdipc -lsyslog	# HP-UX
X#LIBS	=				# BSD
X
Xall:	smtp smtpd
X
XSTD	= netio.o misc.o
X
Xsmtp:	smtp.o converse.o $(STD)
X	$(CC) $(CFLAGS) -o smtp smtp.o converse.o $(STD) $(LIBS)
X
Xsmtpd:	smtpd.o dconverse.o $(STD)
X	$(CC) $(CFLAGS) -o smtpd smtpd.o dconverse.o $(STD) $(LIBS)
X
Xsa-smtpd:	sa-smtpd.o dconverse.o $(STD)
X	$(CC) $(CFLAGS) -o sa-smtpd sa-smtpd.o dconverse.o $(STD) $(LIBS)
X
Xsmptd.o sa-smtpd.o smtp.o $(STD) converse.o: smtp.h
X
Xsmtp.h:	config.h miscerrs.h
X	-touch smtp.h
X
Xsmtpd.o:	smtpd.c
X	$(CC) -c $(CFLAGS) -DINETD smtpd.c
X
Xsa-smtpd.o:	smtpd.c
X	$(CC) -c $(CFLAGS) -UINETD smtpd.c
X	mv smtpd.o sa-smtpd.o
X
Xclean:
X	rm -f smtp smtpd sa-smtpd *.o
X
Xlint:
X	lint smtp.c netio.c converse.c
X	lint smtpd.c netio.c dconverse.c
X	lint -DINETD smtpd.c netio.c dconverse.c
X
SHAR_EOF
if test 800 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 800 characters)'
fi
fi
echo shar: "extracting 'README'" '(2322 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XThis is a merger of Ian's standalone talker and MIT's talker.
XPeter Honeyman hacked on it to make it work correctly on the Arpanet.
X
XAdapted by Johan Vromans <jv@mh.nl>, May 1988
X
X - simplified code
X
X - adapted to System V (Most notably: HP-UX)
X
X - added better host/domain name handling & setup
X
X - added time-routine (from smail)
X
X - added "config.h" for local settings, and moved common includes and
X   portability code to "smtp.h"
X
X - produces a "smtpd" to be used under inetd, "sa-smtpd" (standalone) and
X   "smtp" interface program.
X
XDisclaimers: it works for me. I didn't test "sa-smtpd", nor tried it under
XBerkeley Unix. However, the code originated from BSD, and I tried to keep
Xsystem dependent things intact.
XI did not look at the "mx" program which is also included.
X
XHow I use it
X------------
XI use a mail system based on smail 2.5.
X
XMy user agents can be Elm, mail or mailx, and pass the message to smail for
Xaliasing and routing. Smail hands the message to either a localmail program
X(for local delivery: user mailboxes, programs or files) or a remotemail
Xprogram (for remote delivery: uucp or smtp).
X
XIn the routing database, all hosts I can connect to are considered
X"UUCP"-hosts, and delivery is passed to a shell script. In this script,
Xhosts are looked-up in the file /etc/hosts.smtp (with the names of TCP/IP
Xhosts which speak smtp) and - if found - delivery is passed to the smtp
Xprogram. 
X
XOtherwise delivery is passed to uux as usual.
X
XOn the input side, smtp mail is caught by the smtpd program, and passed to
Xsmail for further processing.
X
XWhy I don't use sendmail
X------------------------
XUsing sendmail has a few drawbacks:
X
X - it is hard to configure and difficult to maintain
X
X - lots of the functionality of sendmail is also in smail. Who is aliasing,
X   who is routing, who is bouncing?
X
X - I cannot prevent sendmail from rewriting message headers
X
X - when something goes wrong, sendmail will try to do sensible things
X   which bypass the rest of the mail system
X
XSmail does everything I want, except for the SMTP delivery. Well - the
Xprograms included do just that.
X
XAnd last but not least: it is more easy to maintain a few small, well
Xdocumented and easy to understand programs than one big hard to understand/
Xconfigure/maintain program. 
X
XMay 1988, Johan Vromans, Multihouse Research
SHAR_EOF
if test 2322 -ne "`wc -c < 'README'`"
then
	echo shar: "error transmitting 'README'" '(should have been 2322 characters)'
fi
fi
echo shar: "extracting 'cmds.h'" '(1024 characters)'
if test -f 'cmds.h'
then
	echo shar: "will not over-write existing file 'cmds.h'"
else
sed 's/^X//' << \SHAR_EOF > 'cmds.h'
X#ifndef lint
Xstatic char *cmds_sccsid = "@(#)cmds.h	1.5 87/04/06";
X#endif lint
X/* cmds.h */
X
X/*  Copyright 1984 by the Massachusetts Institute of Technology  */
X/*  See permission and disclaimer notice in file "notice.h"  */
X
X/* EMACS_MODES: c !fill */
X
X/*
X * smtp command strings and associated codes.  Note that the command code
X * MUST be equal to the index of the command in the table.
X */
X
X
Xstruct	cmdtab	{
X	char	*c_name;		/* command name */
X	int	c_len;			/* command length */
X} cmdtab[] = {
X#define	NONE		0		/* no such command */
X	{ "", 0, },
X#define	HELO		1
X	{ "HELO", 4, },
X#define	MAIL		2
X	{ "MAIL FROM:", 10 },
X#define	RCPT		3
X	{ "RCPT TO:", 8, },
X#define	DATA		4
X	{ "DATA", 4, },
X#define	QUIT		5
X	{ "QUIT", 4, },
X#define	RSET		6
X	{ "RSET", 4, },
X#define	NOOP		7
X	{ "NOOP", 4, },
X#define VRFY		8
X	{ "VRFY", 4, },
X/* sendmail compatibility */
X#define ONEX		9
X	{ "ONEX", 4, },
X#define VERB		10
X	{ "VERB", 4, },
X
X	{ 0, 0, }			/* end of table marker */
X};
X 
X#define toupper(c)	(islower(c) ? ((c) - ('a' - 'A')) : (c))
SHAR_EOF
if test 1024 -ne "`wc -c < 'cmds.h'`"
then
	echo shar: "error transmitting 'cmds.h'" '(should have been 1024 characters)'
fi
fi
echo shar: "extracting 'config.h'" '(1280 characters)'
if test -f 'config.h'
then
	echo shar: "will not over-write existing file 'config.h'"
else
sed 's/^X//' << \SHAR_EOF > 'config.h'
X/* config.h for smtp package */
X
X/*
X * define either BSD or SYSV.
X */
X#define SYSV			/* SystemV with TCP/IP */
X/* # define BSD			/* Berkeley 4.[23] */
X
X/*
X * If set, HOSTDOMAIN overrides HOSTNAME and MYDOM.
X */
X/* #define HOSTDOMAIN	"mhres.mh.nl" */
X
X/*
X * If not set, HOSTNAME will be fetched using uname (SYSV) or gethostname (BSD)
X */
X/* #define HOSTNAME	"mhres" */
X
X/*
X * If set, MYDOM will be appended to the host name.
X */
X#define MYDOM		".mh.nl"
X
X/*
X * Define server to use. Defaults to "smtp".
X */
X/* #define SERVNAME	"tsmtp" */
X
X/*
X * Define SYSLOG when the syslog rotuine can be used. For SYSV, it will
X * use a PD syslog package.
X */
X#define SYSLOG
X
X/*
X * Define this if you want a log of mail transactions. See the code in
X * smtpd.c.
X */
X#define SIMPLELOG
X
X/*
X * The mailer used to send the mail.
X */
X#define MAILER	"/bin/smail"
X
X/*
X * Define HOOTING for printout of transaction (needed for "Transaction
X * of session")
X * Used by "netio" in "smtp"
X */
X#define HOOTING
X
X/*
X * Define NOSYSEXITS iy you don't have <sysexits.h> (or "sysexits.h" on SYSV.
X */
X
X/* define NOSYSEXITS */
X
X/*
X * Define this if your signal(2) takes a void function as its second arg.
X * Otherwise leave it empty
X */
X
X/* define TYPESIG	((void)(*)())	*/
X#ifndef TYPESIG
X# define TYPESIG
X#endif
X
SHAR_EOF
if test 1280 -ne "`wc -c < 'config.h'`"
then
	echo shar: "error transmitting 'config.h'" '(should have been 1280 characters)'
fi
fi
echo shar: "extracting 'converse.c'" '(4950 characters)'
if test -f 'converse.c'
then
	echo shar: "will not over-write existing file 'converse.c'"
else
sed 's/^X//' << \SHAR_EOF > 'converse.c'
X/*
X * Do the necessary commands for a smtp transfer.  Start by waiting for the
X * connection to open, then send HELO, MAIL, RCPT, and DATA.  Check the
X * reply codes and give up if needed.
X * 
X * This code modified from the MIT UNIX TCP implementation:
X * Copyright 1984 Massachusetts Institute of Technology
X * 
X * Permission to use, copy, modify, and distribute this file
X * for any purpose and without fee is hereby granted, provided
X * that this copyright and permission notice appear on all copies
X * and supporting documentation, the name of M.I.T. not be used
X * in advertising or publicity pertaining to distribution of the
X * program without specific prior permission, and notice be given
X * in supporting documentation that copying and distribution is
X * by permission of M.I.T.  M.I.T. makes no representations about
X * the suitability of this software for any purpose.  It is provided
X * "as is" without express or implied warranty.
X */
X
X#include "smtp.h"
X#include <signal.h>
X
X#define	MAXTIME		(60 * 5)		/* way too long - die */
X
Xint success, termcode;
X
Xint gethostname();
Xextern int death();
Xchar *strcat(), *strcpy();
Xextern char hostname[], hostdomain[];
X
Xconverse(from, rcpt, sfi, sfo, mlfd)
Xchar	*from;				/* from address */
Xchar	*rcpt;				/* to address */
XFILE	*sfi;				/* smtp input */
XFILE	*sfo;				/* smtp output */
XFILE	*mlfd;				/* mail file descriptor */
X{
X	extern expect();
X	extern char *sendhost;
X	char buf[MAXSTR];
X	char host[64];
X
X	(void) signal(SIGALRM, TYPESIG death);
X	(void) alarm(MAXTIME);		/* make sure we eventually go away */
X
X	expect(220, sfi, sfo);			/* expect a service ready msg */
X/*	(void) gethostname(host, sizeof host); */
X
X	if (sendhost == NULL)
X		(void) sprintf(buf, "HELO %s.%s\n", hostdomain);
X	else
X		(void) sprintf(buf, "HELO %s\n", sendhost);
X	tputs(buf, sfo);
X	expect(250, sfi, sfo);			/* expect an OK */
X
X	(void) strcpy(buf, "MAIL FROM:<");
X	(void) strcat(buf, from);
X	(void) strcat(buf, ">\n");
X	tputs(buf, sfo);
X	expect(250, sfi, sfo);			/* expect OK */
X
X	(void) strcpy(buf, "RCPT TO:<");
X	(void) strcat(buf, rcpt);
X	(void) strcat(buf, ">\n");
X	tputs(buf, sfo);
X	expect(250, sfi, sfo);			/* expect OK */
X
X	tputs("DATA\n", sfo);
X	expect(354, sfi, sfo);
X	do_data(mlfd, sfo);
X	expect(250, sfi, sfo);			/* hope data is OK */
X	success = TRUE;
X
X	tputs("QUIT\n", sfo);
X	/*expect(221, sfi, sfo);*/	/* who cares? */
X}
X
X
X/*
X * Send the data from the specified mail file out on the current smtp
X * connection.  Do the appropriate netascii conversion and starting '.'
X * padding.  Send the <CRLF>.<CRLF> at completion.
X */
Xdo_data(fd, sfo)
Xregister FILE	*fd;			/* mail file descriptor */
XFILE *sfo;				/* smtp files */
X{
X	register int c;		/* current character */
X	int nlseen = FALSE;		/* newline */
X	extern int debug;
X
X	if (debug)
X		(void) printf("in do_data\n");
X	while ((c = getc(fd)) != EOF) {
X		if (nlseen) {
X			nlseen = FALSE;
X			if (c == '.')
X				(void) putc('.', sfo);
X		}
X		if (c == '\n') {
X			(void) putc('\r', sfo);
X			nlseen = TRUE;
X		}
X		(void) putc(c, sfo);
X#ifdef what_the_fuck_is_all_this_about
X		if (c == '\r')
X			(void) putc('\0', sfo);
X#endif
X	}
X	if (!nlseen) {
X		(void) putc('\r', sfo);
X		(void) putc('\n', sfo);
X	}
X#ifdef this_is_bullshit_too
X	(void) putc('\n', sfo);	/* TODO: why is this line needed? */
X#endif
X	(void) putc('.', sfo);
X	(void) putc('\r', sfo);
X	(void) putc('\n', sfo);
X	(void) fflush(sfo);
X	if (ferror(sfo)) {
X		perror("write error in smtp");
X		bomb(E_IOERR);
X	}
X	if (debug)
X		(void) printf("leaving do_data\n");
X}
X
X
X/*
X * Expect a reply message with the specified code.  If the specified code
X * is received return TRUE; otherwise print the error message out on the
X * standard output and give up.  Note that the reply can be a multiline
X * message.
X */
Xexpect(code, sfi, sfo)
Xint	code;
XFILE	*sfi, *sfo;
X{
X	int retcd;
X	char cmdbuf[MAXSTR], termbuf[MAXSTR];
X	extern int debug;
X
X	if (debug)
X		(void) fprintf(stderr, "expect %d ", code);
X	for (;;) {			/* get whole reply */
X		if (tgets(cmdbuf, sizeof cmdbuf, sfi) > 0) {	/* get input line */
X			if (cmdbuf[3] == '-') /* continuation line? */
X				continue;
X						/* no, last line */
X			if (sscanf(cmdbuf, "%d", &retcd) !=1 ){
X				(void) fprintf(stderr,
X					"non-numeric command reply!\n");
X				bomb(E_IOERR);
X			}
X			if (retcd == code) {
X				if (debug)
X					(void) fprintf(stderr," got it\n");
X				return;
X			}
X			else {
X				if (debug)
X					(void) fprintf(stderr,
X						" FAIL (got %d)\n", retcd);
X				/* return the error line */
X				(void) strcpy(termbuf, cmdbuf);
X				tputs ("QUIT\n", sfo);
X				break;
X			}
X		} 
X		else if (success)
X			(void) strcpy(termbuf, "250 OK\n");
X		else {
X			(void) perror("smtp");
X			bomb(451);
X		}
X	}
X	termcode = !success;			/* error return */
X	if (debug)
X		(void) fprintf(stderr, " FALLOUT\n");
X	bomb(retcd);		/* map smtp errors to mailsys errors */
X}
X
X/* Maximum time to live elapsed.  Die right now. */
Xdeath()
X{
X	(void) fprintf(stderr, "Max transfer length timeout.\n");
X	(void) exit(1);
X}
SHAR_EOF
if test 4950 -ne "`wc -c < 'converse.c'`"
then
	echo shar: "error transmitting 'converse.c'" '(should have been 4950 characters)'
fi
fi
echo shar: "extracting 'dconverse.c'" '(12608 characters)'
if test -f 'dconverse.c'
then
	echo shar: "will not over-write existing file 'dconverse.c'"
else
sed 's/^X//' << \SHAR_EOF > 'dconverse.c'
X#ifndef lint
Xstatic char *sccsid = "@(#)converse.c	1.8 87/05/14";
X#endif lint
X/*  Copyright 1984 Massachusetts Institute of Technology
X
XPermission to use, copy, modify, and distribute this program
Xfor any purpose and without fee is hereby granted, provided
Xthat this copyright and permission notice appear on all copies
Xand supporting documentation, the name of M.I.T. not be used
Xin advertising or publicity pertaining to distribution of the
Xprogram without specific prior permission, and notice be given
Xin supporting documentation that copying and distribution is
Xby permission of M.I.T.  M.I.T. makes no representations about
Xthe suitability of this software for any purpose.  It is pro-
Xvided "as is" without express or implied warranty.		*/
X
X/*
X * smtpd - World's most trivial SMTP server.  Only accepts the MAIL, FROM,
X * RCPT, and DATA commands.  Generates a date file for the mail
X * daemon and kicks the mail daemon off.
X */
X
X#include "smtp.h"
X
X#ifdef BSD
X#include <sgtty.h>
X#endif
X/* #include <ioctl.h> */
X#include <signal.h>
X#include <sys/uio.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X
X#include "cmds.h"
X
X/* tunable constants */
X
X#define SECONDS		1
X#define MINUTES		60
X#define HOURS		(60 * MINUTES)
X
X#define	SHORTTIME	(5 * MINUTES)	/* enough time for easy stuff */
X#define	LONGTIME	(2 * HOURS)	/* max time, DATA to `.' */
X
X#define	DATAMODE	0660		/* mode for data file */
X
X#ifdef MAILER
Xchar *sigmaild = MAILER;
X#else
Xchar *sigmaild = "/bin/rmail";
X#endif
X
Xtypedef long in_name;			/* internet host address */
X
Xint	buflen;				/* size of string in cmd buffer */
X
Xstatic char rcptlist[MAXSTR];		/* recipient list */
Xstatic char *rcptlast;			/* end of rcptlist */
X
XFILE	*datafd;			/* data file descriptor */
X
Xchar	dataname[NAMSIZ];		/* data file name */
X
Xtypedef int event;
X
Xextern int death();
Xextern int alarmtr();
X
Xextern char *strcpy();
Xextern char *index();
Xextern char *rindex();
Xextern char *strcpy(), *strcat();
X
Xextern char hostdomain[];
Xextern char hostname[];
Xextern char arpanows[];
X
X#ifdef SIMPLELOG
X#include <sys/file.h>
Xstatic char mailfrom[MAXSTR], rcptto[MAXSTR];
X#endif
X
X/*
X * This is the routine which processes incoming smtp commands from the
X * user.  It goes to sleep awaiting network input.  When a complete
X * command is received, the tcp receiver task awakens us to process it.
X * Currently only the commands listed in the command table are accepted.
X * This routine never returns.
X */
X/* ARGSUSED from */
Xconverse(fi, fo, from)
XFILE *fi, *fo;
Xstruct sockaddr_in *from;
X{
X	char greeting[MAXSTR];
X
X	(void) chdir("/tmp");		/* put temp files somewhere sensible */
X	(void) signal(SIGALRM, TYPESIG alarmtr);
X	(void) alarm(SHORTTIME);		/* make sure we eventually go away */
X	setdates ();
X	(void) sprintf(greeting, "220 %s SMTP server ready at %s\n",
X		hostdomain, arpanows);
X	(void) tputs(greeting, fo);
X	do_helo(fi, fo);		/* wait for the hello */
X	for (;;) {			/* until QUIT */
X		do_mail(fi, fo);	/* wait for the mail command */
X		while (do_rcpt(fi, fo))	/* do all the recipients */
X			;
X		(void) alarm(LONGTIME);
X		do_data(fi, fo);	/* do the data */
X	}
X}
X
X/*
X * Wait for the user to send the HELO command.  Punt out if he sends
X * QUIT or RSET.
X */
Xdo_helo(fi, fo)
XFILE *fi, *fo;
X{
X	char	cmdbuf[MAXSTR];
X	char	greeting[MAXSTR];
X
X	for (;;) {		/* until HELO, QUIT, or RSET */
X		buflen = tgets(cmdbuf, sizeof cmdbuf, fi);	/* wait for command */
X		switch (cmdparse(cmdbuf, buflen)) {
X		case QUIT:
X		case RSET:
X			quit(fi, fo);
X		case NOOP:
X			(void) tputs("250 OK\n", fo);
X			continue;
X		case HELO:
X			(void) sprintf(greeting, "250 %s Pleased to meet you\n", hostname);
X			(void) tputs(greeting, fo);
X			return;
X		case NONE:
X			bitch(cmdbuf, fo);
X			continue;
X		default:
X			(void) tputs("503 Expecting HELO\n", fo);
X			continue;
X		}
X	}
X}
X
X/*
X * Wait for the user to send the MAIL command.  Punt out if he sends
X * QUIT or RSET.
X */
Xdo_mail(fi, fo)
XFILE *fi, *fo;
X{
X	char	cmdbuf[MAXSTR];
X
X	for (;;) {		/* until MAIL, QUIT, or RSET */
X		buflen = tgets(cmdbuf, sizeof cmdbuf, fi);	/* wait for command */
X		switch (cmdparse(cmdbuf, buflen)) {
X		case QUIT:
X		case RSET:
X			quit(fi, fo);
X		case NOOP:
X			(void) tputs("250 OK\n", fo);
X			continue;
X		case MAIL:
X#ifdef SIMPLELOG
X			strcpy(mailfrom, cmdbuf);
X#endif
X			(void) tputs("250 OK\n", fo);
X			return;
X		case NONE:
X			bitch(cmdbuf, fo);
X			continue;
X		default:
X			(void) tputs("503 Expecting MAIL\n", fo);
X			continue;
X		}
X	}
X}
X
X/*
X * Wait for the user to send the RCPT command.  Punt out if he sends
X * QUIT or RSET.  Returns TRUE if a RCPT command was received, FALSE
X * if a DATA command was received.
X */
Xdo_rcpt(fi, fo)
XFILE *fi, *fo;
X{
X	char	cmdbuf[MAXSTR];
X
X	for (;;) {		/* until RCPT, DATA, QUIT, or RSET */
X		buflen = tgets(cmdbuf, sizeof cmdbuf, fi);	/* wait for command */
X		switch (cmdparse(cmdbuf, buflen)) {
X		case QUIT:
X		case RSET:
X			quit(fi, fo);
X		case NOOP:
X			(void) tputs("250 OK\n", fo);
X			continue;
X		case RCPT:
X#ifdef SIMPLELOG
X			strcat(rcptto, cmdbuf);
X#endif
X			if (!parse_rcpt(cmdbuf, buflen)) {
X				(void) tputs("501 Syntax error in recipient name\n", fo);
X				continue;
X			}
X			(void) tputs("250 OK\n", fo);
X			return(TRUE);
X		case DATA:
X			if (*rcptlist == 0) {
X				(void) tputs("503 Expecting RCPT\n", fo);
X				continue;
X			}
X			if (!init_xfr()) {	/* set up data file */
X				(void) tputs("451 Can't initialize transfer\n", fo);
X				death(E_CANTOPEN);
X			}
X			(void) tputs("354 Start mail input; end with <CRLF>.<CRLF>\n", fo);
X			return(FALSE);
X		case NONE:
X			bitch(cmdbuf, fo);
X			continue;
X		default:
X			(void) tputs("503 Expecting RCPT or DATA\n", fo);
X			continue;
X		}
X	}
X}
X
Xdo_data(fi, fo)
XFILE *fi, *fo;
X{
X	char cmd[MAXSTR];
X	register char *buf = cmd;
X	int sysret;
X
X	setdates ();
X	fprintf (datafd, "Received: by %s with SMTP; %s\n",
X		hostdomain, arpanows);
X	for (;;) {
X		if (tgets(buf, sizeof cmd, fi) < 0)
X			death(E_IOERR);
X		if (*buf == '.') {
X			buf++;	/* hidden dot */
X			if (*buf == '\n')
X				break;
X		}
X		(void) fputs(buf, datafd);
X	}
X
X	(void) fclose(datafd);
X
X	/* run mailer with rcptlist as args and message as input */
X	/* TODO: check system status to see if OK */
X	(void) sprintf(cmd, "%s %s <%s", sigmaild, rcptlist, dataname);
X	sysret = system(cmd);
X	if (sysret == 0)
X		(void) tputs("250 OK\n", fo);
X	else
X		(void) tputs("554 Transaction failed\n", fo);
X
X#ifdef SIMPLELOG
X	simplelog(abs(sysret));
X#endif
X
X	/* shouldn't leave it around, but ... */
X	if (sysret == 0)
X		(void) unlink(dataname);	/* remove temporaries */
X
X	*dataname = *rcptlist = *rcptto = 0;
X	rcptlast = 0;
X}
X
X/*
X * Create the data file for the transfer.  Get unique
X * names and create the files.
X */
Xinit_xfr()
X{
X	int	dfd;			/* file desc. for data file */
X
X	(void) tmpnam(dataname);
X	
X	if ((dfd = creat(dataname, DATAMODE)) < 0)
X		return FALSE;
X	datafd = fdopen(dfd, "w");	/* make stdio descriptor */
X	if (datafd == NULL)
X		return FALSE;
X
X	
X	return TRUE;
X}
X
X/*
X * Give up on the transfer.  Unlink the data file (if any),
X * close the tcp connection, and exit.
X */
Xquit(fi, fo)
XFILE *fi, *fo;
X{
X	char greeting[MAXSTR];
X
X	(void) sprintf(greeting, "221 %s Terminating\n", hostname);
X	(void) tputs(greeting, fo);
X	(void) fclose(fi);
X	(void) fclose(fo);
X	exit(0);
X}
X
X/*
X * Parse the command part off the specified buffer.  Return the index
X * of the command in the command table(or 0 if the command is not
X * recognized).
X * The commands and indices accepted are listed in the include file
X * "cmds.h".
X */
Xcmdparse(buf, len)
Xchar *buf;
Xint len;
X{
X	register char *cmdp, *bufp;	/* command, buffer ptrs. */
X	register struct	cmdtab	*ct;	/* cmd table ptr */
X	register int i;			/* index in cmd table */
X	int	clen;			/* length of this command */
X	
X	for (ct = &cmdtab[1], i = 1; ct->c_name != NULL; ct++, i++) {
X		clen = ct->c_len;
X		if (len < clen)		/* buffer shorter than command? */
X			continue;
X		/* case-insensitive matching of command names */
X		for (cmdp = ct->c_name, bufp = buf;
X		     clen > 0 && *cmdp == toupper(*bufp);
X		     cmdp++, bufp++, clen--)
X			;
X		if (clen == 0) {		/* success */
X			/* sendmail compatibility */
X			if (i == ONEX || i == VERB)
X				i = NOOP;
X			return i;
X		}
X	}
X	return 0;
X}
X
Xstatic	char	*to;			/* ptr. into request buffer */
X
X/*
X * Parse the recipient spec in the buffer.  Start by stripping the
X * command off the front of the buffer.  Then call canon() to convert
X * the recpient name into a format acceptable to the mailer daemon
X * (ie. the original multiple-at-sign format).
X * Returns TRUE if parsed successfully, FALSE otherwise.
X */
X/* ARGSUSED len */
Xparse_rcpt(buf, len)
Xchar *buf;				/* command buffer */
Xint len;				/* size of buffer string */
X{
X	register char *from;		/* ptr to recipient name */
X	char *end;
X	
X	from = &buf[cmdtab[RCPT].c_len];
X	while (*from == ' ' || *from == '\t')
X		from++;
X	if (*from == '<') {
X		end = index(from++, '>');
X		if (end == 0) {
X			(void) printf("no > at end of string\n");
X			return FALSE;
X		}
X		*end = 0;
X	}
X	if (rcptlast) {
X		rcptlast += strlen(rcptlast);
X		*rcptlast++ = ' ';
X	} else
X		rcptlast = rcptlist;
X	/* NB: we use the canonical name even if `bad' */
X	if (canon(from, rcptlast))	/* canonicalize */
X#ifdef DEBUG
X		(void) printf("parsed ok: %s\n", rcptlast);
X	else
X		(void) printf("parsed bad: %s\n", rcptlast);
X#endif
X	;
X	return TRUE;
X}
X
X/*
X * Canonicalize the smtp-style path pointed to by from into the buffer
X * pointed to by the external static variable to.  The result will be
X * a string containing the multiple-at-sign form, as desired by the
X * mailer daemon.  Also removes the '\' escape characters.
X * The procedure follwed is recursive: this routine is recursively
X * called for each "@host" in the from string.
X * Returns TRUE if successful, or FALSE if the format of the recipient
X * name is bad.
X */
Xrcanon(from)
Xregister char	*from;			/* start of string to canonicalize */
X{
X	register char	*end;		/* end of this part of path */
X	register int	escseen;	/* escape character seen */
X	int	atseen;			/* '@' seen in mailbox */
X	
X	escseen = atseen = FALSE;
X	if (*from == '@') {		/* host name; find end */
X		for (end = from; *end != '\0'; end++) {
X			if (escseen)
X				escseen = FALSE;
X			else if (*end == '\\') /* escape? */
X				escseen = TRUE;
X			else if (*end == ',' || *end == ':')
X				break;
X		}
X		if (*end == '\0' || !rcanon(end+1)) { /* bad format? */
X#ifdef PICKY /*{*/
X			(void) printf("no mailbox found\n");
X			return FALSE;
X		} else
X#else
X		}
X#endif				/* PICKY */
X		{
X			escseen = FALSE;
X			for (*from = '%'; from < end; from++) { /* copy into to buffer */
X				if (escseen)
X					escseen = FALSE;
X				else if (*from == '\\') {
X					escseen = TRUE;
X					continue;
X				}
X				*to++ = *from;
X			}
X			*to = '\0';
X			return TRUE;
X		}
X	} else {
X		for (; *from; from++) {	/* copy mailbox */
X			if (escseen)
X				escseen = FALSE;
X			else if (*from == '\\') {
X				escseen = TRUE;
X				continue;
X			} else if (*from == '@') { /* end of username? */
X				(void) printf("found @ in mailbox\n");
X				*from = '%';
X				atseen = TRUE;
X			}
X			*to++ = *from;
X		}
X		*to = 0;
X		return atseen;
X	}
X}
X
X/* Time to live elapsed or io error. */
Xdeath(weapon)
X{
X#ifdef SIMPLELOG
X	simplelog(weapon);
X#endif
X	(void) printf("Time to die.\n");
X	/*(void) unlink(dataname);*/
X	exit(1);
X}
X
Xalarmtr()
X{
X	death(E_TEMPFAIL);
X}
X
Xcanon(in, out)
Xchar	*in, *out;
X{
X	char *at;
X
X	to = out;
X	if (funnychars(in) || !rcanon(in) || (at = rindex(out, '%')) == 0)
X		return(FALSE);
X	*at = '@';
X	return TRUE;
X}
X
Xfunnychars(str)
Xregister char *str;
X{
X
X	for (;;)
X		switch(*str++) {
X		case '^':
X		case '&':
X		case '>':
X		case '<':
X		case '`':
X		case '|':
X		case ';':
X		case '\'':
X			return TRUE;
X
X		case 0:
X			return FALSE;
X		}
X}
X
X#ifdef SIMPLELOG
Xsimplelog(retcode)
X{
X	char buf[1024], *bptr, *status;
X	int fd;
X	time_t t;
X	extern char *ctime();
X	extern time_t time();
X
X	t = time(&t);
X	switch (retcode) {
X	case E_CANTOPEN:
X		status = "OPEN FAILED";
X		break;
X	case E_IOERR:
X		status = "IO ERROR";
X		break;
X	case E_TEMPFAIL:
X		status = "TIMED OUT";
X		break;
X	case 0:
X		status = "OK";
X		break;
X	default:
X		status = "DELIVERY FAILURE";
X		break;
X	}
X	if (*mailfrom == 0)
X		strcpy(mailfrom, "UNKNOWN");
X	if (*rcptto == 0)
X		strcpy(rcptto, "UNKNOWN");
X	(void) sprintf(buf, "%s %s %s %s", mailfrom, rcptto, status, ctime(&t));
X	for (bptr = buf; *bptr; bptr++)
X		if (*bptr == '\n' || *bptr == '\r')
X			*bptr = ' ';
X	strcat(bptr, "\n");
X	if ((fd = open("/tmp/smtpd.log", O_WRONLY|O_APPEND)) >= 0) {
X		(void) write(fd, buf, strlen(buf));
X		(void) close(fd);
X	}
X}
X#endif
X
Xbitch(buf, fo)
Xchar *buf;
XFILE *fo;
X{
X	char gripe[MAXSTR], *nlptr;
X
X	if ((nlptr = index(buf, '\n')) != 0)
X		*nlptr = 0;
X	(void) sprintf(gripe, "502 %s ... Not recognized\n", buf);
X	(void) tputs(gripe, fo);
X}
SHAR_EOF
if test 12608 -ne "`wc -c < 'dconverse.c'`"
then
	echo shar: "error transmitting 'dconverse.c'" '(should have been 12608 characters)'
fi
fi
echo shar: "extracting 'misc.c'" '(4018 characters)'
if test -f 'misc.c'
then
	echo shar: "will not over-write existing file 'misc.c'"
else
sed 's/^X//' << \SHAR_EOF > 'misc.c'
X
X/*
X**  Miscellaneous support functions for smtp (borrowed from smail)
X*/
X
X# include	"smtp.h"
X#ifdef BSD
X# include	<sys/timeb.h>
X#endif
X#ifdef SYSV
X# include	<sys/utsname.h>
X#endif
X
Xchar hostdomain[256];
Xchar hostname[256];
X
Xextern struct tm *localtime();
X
Xstruct tm *gmt, *loc;		/* GMT and local time structure	*/
Xtime_t now;			/* current system time		*/
Xchar nows[50];			/* time in ctime format		*/
Xchar arpanows[50];		/* time in arpa format		*/
X
Xsetdates()
X{
X	time_t time();
X	struct tm *gmtime();
X	char *ctime(), *arpadate();
X
X	(void) time(&now);
X	(void) strcpy(nows, ctime(&now));
X	gmt = gmtime(&now);
X	loc = localtime(&now);
X	(void) strcpy(arpanows, arpadate(nows));
X}
X
X/*
X**  Note: This routine was taken from sendmail
X**
X**  ARPADATE -- Create date in ARPANET format
X**
X**	Parameters:
X**		ud -- unix style date string.  if NULL, one is created.
X**
X**	Returns:
X**		pointer to an ARPANET date field
X**
X**	Side Effects:
X**		none
X**
X**	WARNING:
X**		date is stored in a local buffer -- subsequent
X**		calls will overwrite.
X**
X**	Bugs:
X**		Timezone is computed from local time, rather than
X**		from whereever (and whenever) the message was sent.
X**		To do better is very hard.
X**
X**		Some sites are now inserting the timezone into the
X**		local date.  This routine should figure out what
X**		the format is and work appropriately.
X*/
X
Xchar *
Xarpadate(ud)
X	register char *ud;
X{
X	register char *p;
X	register char *q;
X	static char b[40];
X	extern char *ctime();
X	register int i;
X#ifndef BSD
X	extern char *tzname[];
X	extern long timezone;
X	char dspace[40];
X	time_t t, time();
X	int dst;			/* dst active */
X	long tz;
X#else
X	/* V7 and 4BSD */
X	struct timeb t;
X	extern struct timeb *ftime();
X	extern char *timezone();
X#endif
X
X	/*
X	**  Get current time.
X	**	This will be used if a null argument is passed and
X	**	to resolve the timezone.
X	*/
X
X#ifndef BSD
X	(void) time(&t);
X	if (ud == NULL)
X		ud = ctime(&t);
X#else
X	/* V7 or 4BSD */
X	ftime(&t);
X	if (ud == NULL)
X		ud = ctime(&t.time);
X#endif
X
X	/*
X	**  Crack the UNIX date line in a singularly unoriginal way.
X	*/
X
X	q = b;
X
X	p = &ud[0];		/* Mon */
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = ',';
X	*q++ = ' ';
X
X	p = &ud[8];		/* 16 */
X	if (*p == ' ')
X		p++;
X	else
X		*q++ = *p++;
X	*q++ = *p++;
X	*q++ = ' ';
X
X	p = &ud[4];		/* Sep */
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = ' ';
X
X	p = &ud[22];		/* 1979 */
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = ' ';
X
X	p = &ud[11];		/* 01:03:52 */
X	for (i = 8; i > 0; i--)
X		*q++ = *p++;
X
X				/* -PST or -PDT */
X#ifndef BSD
X	dst = localtime(&t)->tm_isdst;
X	tz = timezone - (dst ? 3600 : 0);
X	p = tzname[dst];
X#else
X	p = timezone(t.timezone, localtime(&t.time)->tm_isdst);
X	if (p[3] != '\0')
X	{
X		/* hours from GMT */
X		p += 3;
X		*q++ = *p++;
X		if (p[1] == ':')
X			*q++ = '0';
X		else
X			*q++ = *p++;
X		*q++ = *p++;
X		p++;		/* skip ``:'' */
X		*q++ = *p++;
X		*q++ = *p++;
X	}
X	else
X#endif
X	{
X		*q++ = ' ';
X		while (*p) *q++ = *p++;
X	}
X#ifndef BSD
X	if (tz != 0) {
X		(void) sprintf (q, " (%c%02d%02d)", 
X			((tz > 0) ? '-' : '+'),
X			abs(tz/3600),
X			abs(tz%3600)/60);
X		q += strlen (q);
X	}
X#endif
X
X	*q = '\0';
X	return (b);
X}
X
X/*
X**
X**  getmynames(): what is my host name and host domain?
X**
X**  Hostname set by -h, failing that by #define HOSTNAME, failing
X**  that by gethostname() or uname().
X**  
X**  Hostdomain set by -h, failing that by #define HOSTDOMAIN,
X**  failing that as hostname.MYDOM, or as just hostname.
X**
X**  See defs.h for the inside story.
X**
X*/
X
Xgetmynames()
X{
X#ifdef HOSTNAME
X	if (!*hostname)
X		(void) strcpy(hostname, HOSTNAME);
X#endif
X#ifdef BSD
X	if (!*hostname)
X		gethostname(hostname, SMLBUF - 1);
X#endif
X#ifdef SYSV
X	if (!*hostname) {
X		struct utsname site;
X
X		if (uname(&site) == 0)
X			(void) strcpy(hostname, site.nodename);
X	}
X#endif
X	if (!*hostname)
X		return -1;
X#ifdef HOSTDOMAIN
X	if (!*hostdomain)
X		(void) strcpy(hostdomain, HOSTDOMAIN);
X#endif
X#ifdef MYDOM
X	if (!*hostdomain)
X		(void) strcat(strcpy(hostdomain, hostname), MYDOM);
X#endif
X	if (!*hostdomain)
X		(void) strcpy(hostdomain, hostname);
X
X	return 1;
X}
SHAR_EOF
if test 4018 -ne "`wc -c < 'misc.c'`"
then
	echo shar: "error transmitting 'misc.c'" '(should have been 4018 characters)'
fi
fi
echo shar: "extracting 'miscerrs.h'" '(197 characters)'
if test -f 'miscerrs.h'
then
	echo shar: "will not over-write existing file 'miscerrs.h'"
else
sed 's/^X//' << \SHAR_EOF > 'miscerrs.h'
X/* these error numbers are local to the smtp programs, used by bomb() */
X#define	E_USAGE		-1
X#define E_NOHOST	-2
X#define	E_CANTOPEN	-3
X#define E_OSFILE	-4
X#define E_IOERR		-5
X#define E_TEMPFAIL	-6
SHAR_EOF
if test 197 -ne "`wc -c < 'miscerrs.h'`"
then
	echo shar: "error transmitting 'miscerrs.h'" '(should have been 197 characters)'
fi
fi
echo shar: "extracting 'mx.c'" '(5751 characters)'
if test -f 'mx.c'
then
	echo shar: "will not over-write existing file 'mx.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mx.c'
X#include <stdio.h>
X#include <netdb.h>
X#include <sysexits.h>
X#include <sys/errno.h>
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <arpa/nameser.h>
X#include "miscerrs.h"
X
X/* imports */
Xextern int errno, h_errno;
Xextern char *malloc(), *strcpy(), *inet_ntoa();
X
X/* exports */
Xint mxconnect();
X
X/* private */
X#define MAXMXLIST 10
Xstatic struct mxitem {
X	char *host;
X	u_short pref;
X	u_char localflag;
X} MXlist[MAXMXLIST + 1];
Xstatic char *strsave();
Xstatic int buildmxlist();
Xstatic void mxsave(), mxinsert(), mxlocal();
Xstatic struct hostent *getmxhost();
X
X#ifdef MXMAIN
X
X#define bomb return
X
Xmain(argc, argv)
X	char **argv;
X{	int fd;
X	char buf[BUFSIZ], *crlf, *index();
X	struct mxitem *mxp;
X
X	for (;;) {
X		printf("domain: ");
X		if (argc > 1)
X			strcpy(buf, argv[1]);
X		else if (gets(buf) == 0)
X			break;
X		if ((fd = mxconnect(buf)) >= 0)
X			if (read(fd, buf, 512) > 0) {
X				if ((crlf = index(buf, '\r')) != 0)
X					strcpy(crlf, "\n");
X				puts(buf);
X			} else
X				perror("read");
X		close(fd);
X		if (argc > 1)
X			break;
X		for (mxp = MXlist; mxp < MXlist + MAXMXLIST + 1; mxp++)
X			mxp->host = 0;
X	}
X	return 0;
X}
X#endif
X
Xmxconnect(host)
X	char *host;
X{	int s, lport, mxfatal;
X	char **addr, errbuf[256];
X	struct hostent *hp;
X	struct servent *sp;
X	struct sockaddr_in sin;
X	struct mxitem *mxp;
X
X	mxfatal = buildmxlist(host);
X	if (MXlist[0].host == 0)
X		MXlist[0].host = host;
X	if ((sp = getservbyname ("smtp", "tcp")) == NULL) {
X		(void)fprintf(stderr,"unknown service TCP/smtp\n");
X		bomb(E_OSFILE);
X	}
X	(void) setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *) 0, 0);
X
X	/* slop in the loop -- i hate the socket dance */
X	for (mxp = MXlist; mxp->host; mxp++) {
X		if ((s = rresvport(&lport)) < 0) {
X			perror("rresvport");
X			bomb(E_CANTOPEN);
X		}
X		if ((hp = getmxhost(mxp->host)) == 0) {
X			(void) close(s);
X			if (mxfatal)
X				bomb(E_NOHOST);
X			continue;
X		}
X		bzero((char *)&sin, sizeof(sin));
X		sin.sin_port = sp->s_port;
X		sin.sin_family = hp->h_addrtype;
X		for (addr = hp->h_addr_list; *addr; addr++) {
X			bcopy(*addr, (char *) &sin.sin_addr, hp->h_length);
X			if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
X				sprintf(errbuf, "%s [%s]", mxp->host, inet_ntoa(sin.sin_addr));
X				perror(errbuf);
X				continue;
X			}
X			return s;
X		}
X		close(s);
X	}
X
X	bomb(E_TEMPFAIL);
X}
X
X/* return 1 for fatal MX error (authoritative NXDOMAIN), 0 o.w. */
Xstatic int
Xbuildmxlist(host)
X	char *host;
X{	register HEADER *hp;
X	register char *cp;
X	register int n;
X	char q[PACKETSZ], a[PACKETSZ];	/* query, answer */
X	char *eom, *bp;
X	int buflen, ancount, qdcount;
X	char hostbuf[BUFSIZ+1];
X	u_short preference, reclen;
X
X	if ((n = res_mkquery(QUERY, host, C_IN, T_MX, (char *) 0, 0, (struct rrec *) 0, q, sizeof(q))) < 0)
X		return 0;
X	n = res_send(q, n, a, sizeof(a));
X	if (n < 0)
X		return 0;
X	eom = a + n;
X	hp = (HEADER *) a;
X	ancount = ntohs(hp->ancount);
X	qdcount = ntohs(hp->qdcount);
X	if (hp->rcode != NOERROR || ancount == 0)
X		return hp->rcode == NXDOMAIN && hp->aa;
X	bp = hostbuf;
X	buflen = sizeof(hostbuf);
X	cp = a + sizeof(HEADER);
X	while (--qdcount >= 0)
X		cp += dn_skip(cp) + QFIXEDSZ;
X	/* TODO: if type is CNAME, reissue query */
X	while (--ancount >= 0 && cp < eom) {
X		cp += dn_skip(cp)	/* name */
X		    + sizeof(u_short)	/* type */	
X		    + sizeof(u_short)	/* class */
X		    + sizeof(u_long);	/* ttl (see rfc973) */
X		reclen = _getshort(cp);
X		cp += sizeof(u_short);
X		preference = _getshort(cp);
X		if ((n = dn_expand(a, eom, cp + sizeof(u_short), bp, buflen)) < 0)
X			break;
X		mxsave(bp, preference);
X		cp += reclen;
X	}
X	mxlocal();
X	return 0;
X}
X
X/* NOT TODO: issue WKS query.  (just try to connect.) */
X
Xstatic void
Xmxsave(host, pref)
X	char *host;
X	u_short pref;
X{	struct mxitem *mxp;
X	int localflag;
X	static char thishost[64];
X
X	if (*thishost == 0)
X		gethostname(thishost, sizeof(thishost));
X
X	if (MXlist[MAXMXLIST].host)
X		return;				/* full */
X
X	localflag = (strcmp(thishost, host) == 0);
X
X	/* insertion sort */
X	for (mxp = MXlist; mxp < MXlist + MAXMXLIST; mxp++) {
X		if (mxp->host == 0) {
X			mxinsert(mxp, host, pref, localflag);
X			return;
X		}
X		if (pref < mxp->pref) {
X			mxinsert(mxp, host, pref, localflag);
X			return;
X		}
X		if (pref == mxp->pref) {
X			if (mxp->localflag)
X				return;
X			if (localflag) {
X				mxp->host = strsave(host);
X				mxp->pref = pref;
X				mxp->localflag = localflag;
X				(++mxp)->host = 0;
X				return;
X			}
X			mxinsert(mxp, host, pref, localflag);
X			return;
X		}
X	}
X}
X
Xstatic void
Xmxinsert(mxlistp, host, pref, localflag)
X	struct mxitem *mxlistp;
X	char *host;
X	u_short pref;
X{	register struct mxitem *mxp;
X
X	for (mxp = MXlist + MAXMXLIST - 1; mxp > mxlistp; --mxp)
X		*mxp = mxp[-1];
X	mxp->host = strsave(host);
X	mxp->pref = pref;
X	mxp->localflag = localflag;
X}
X
Xstatic char *
Xstrsave(str)
X	register char *str;
X{	register char *rval;
X
X	if ((rval = malloc(strlen(str) + 1)) == 0) {
X		perror("malloc");
X		bomb(-EX_SOFTWARE);
X	}
X	strcpy(rval, str);
X	return rval;
X}
X
Xstatic void
Xmxlocal()
X{	register struct mxitem *mxp;
X
X	if (MXlist[0].host == 0)
X		return;
X
X	for (mxp = MXlist; mxp->host; mxp++) {
X		if (mxp->localflag) {
X			mxp->host = 0;
X			break;
X		}
X	}
X}
X
Xstatic struct hostent *
Xgetmxhost(host)
X	char *host;
X{	struct hostent *hp, *gethostbyname();
X
X	if ((hp = gethostbyname(host)) != 0)
X		return hp;
X
X	switch(h_errno) {
X
X	case HOST_NOT_FOUND:
X		(void) fprintf(stderr, "unknown host (%s).\n", host);
X		break;
X
X	case TRY_AGAIN:
X		(void) fprintf(stderr, "name server not responding (%s).\n", host);
X		break;
X
X	case NO_RECOVERY:
X		(void) fprintf(stderr, "name server error (%s).\n", host);
X		break;
X		
X	case NO_ADDRESS:
X		(void) fprintf(stderr, "no IP address (%s).\n", host);
X		break;
X	
X	default:
X		(void) fprintf(stderr, "unknown resolver error (%s).\n", host);
X		break;
X	}
X	return 0;
X}
SHAR_EOF
if test 5751 -ne "`wc -c < 'mx.c'`"
then
	echo shar: "error transmitting 'mx.c'" '(should have been 5751 characters)'
fi
fi
echo shar: "extracting 'netio.c'" '(1442 characters)'
if test -f 'netio.c'
then
	echo shar: "will not over-write existing file 'netio.c'"
else
sed 's/^X//' << \SHAR_EOF > 'netio.c'
X#ifndef lint
Xstatic char *sccsid = "@(#)netio.c	1.7 87/07/31";
X#endif lint
X
X#include "smtp.h"
X#include <setjmp.h>
X
X#ifdef NOBOMB
X#define bomb exit
X#endif
X
Xchar *strcpy(), *strncat();
X
Xint hooting = 0;		/* true if not server */
X
Xint
Xtgets(line, size, fi)		/* fgets from TCP */
Xchar *line;
Xint size;
XFILE *fi;
X{
X	register char *cr;
X
X	*line = 0;
X	if (fgets(line, size, fi) == NULL)
X		return -1;
X	if (ferror(fi)) {
X		perror("error reading from smtp");
X		bomb(E_IOERR);
X	}
X
X	/* convert \r\n -> \n */
X	cr = line + strlen(line) - 2;
X	if (cr >= line && *cr == '\r' && *(cr+1) == '\n') {	/* CRLF there? */
X		*cr++ = '\n';
X		*cr = 0;
X	} else				/* no CRLF present */
X		cr += 2;		/* point at NUL byte */
X
X#ifdef HOOTING
X	if (hooting) (void) printf("<<< %s", line);
X#endif
X	if (feof(fi)) {
X		perror("read eof from smtp");
X		bomb(E_IOERR);
X	}
X	return cr - line;
X}
X
Xint
Xtputs(line, fo)			/* fputs to TCP */
Xchar *line;
XFILE *fo;
X{
X	char buf[MAXSTR];
X	register char *nl;
X	extern int debug;
X
X	(void) strcpy(buf, line);
X#ifdef HOOTING
X	if (hooting) (void) printf(">>> %s", buf);
X#endif
X	/* replace terminating \n by \r\n */
X	nl = buf + strlen(buf) - 1;		/* presumably \n */
X	if (nl >= buf && *nl=='\n') {		/* if it is ... */
X		*nl++ = '\r';
X		*nl++ = '\n';
X		*nl = 0;
X	} else
X		printf("unterminated line: <%s>\n", buf);
X
X	(void) fputs(buf, fo);
X	(void) fflush(fo);
X	if (ferror(fo)) {
X		(void) perror("error writing to smtp");
X		bomb(E_IOERR);
X	}
X	return 0;
X}
SHAR_EOF
if test 1442 -ne "`wc -c < 'netio.c'`"
then
	echo shar: "error transmitting 'netio.c'" '(should have been 1442 characters)'
fi
fi
echo shar: "extracting 'smtp.8'" '(4836 characters)'
if test -f 'smtp.8'
then
	echo shar: "will not over-write existing file 'smtp.8'"
else
sed 's/^X//' << \SHAR_EOF > 'smtp.8'
X.TH SMTP 8 local "Public Domain"
X.DA "4 May 1987"
X.SH NAME
Xsmtp, smtpd, in.smtpd \- SMTP talker and listeners
X.br
Xsmtpqer, runsmtpq, smtpq \- SMTP enqueuing, queue running and listing
X.br
Xcleansmtpq, returnsmtpmail \- SMTP queue cleaning and mail returning
X.SH SYNOPSIS
X.B /usr/lib/mail/smtp
X[
X.B \-h
Xhelohost
X]
Xtargethost sender recipient
X.br
X.B "cd /usr/spool/smtpq; /usr/lib/mail/smtpd"
X.br
X.B "cd /usr/spool/smtpq; /usr/etc/in.smtpd"
X.RB sourcehost . sourceport
X.br
X.B /usr/lib/mail/smtpqer
X[
X.B \-h
Xhelohost
X]
Xtargethost sender recipient
X.br
X.B /usr/lib/mail/runsmtpq
X.br
X.B /usr/lib/mail/smtpq
X.br
X.B /usr/lib/mail/cleansmtpq
X.br
X.B /usr/lib/mail/returnsmtpmail
X*.sh ...
X.SH DESCRIPTION
XThese routines provide a minimal stand-alone \s-2SMTP\s0 service.
XIt consists of small programs that can be used with a central mail router like
X.I upas,
Xa system of your own construction,
Xor
X.IR sendmail .
X.PP
X.I smtp
Xsends the mail message on its standard input to
X.I targethost
Xwhich in turn will deliver the message to
X.I recipient
Xas being from
X.IR sender .
X.I smtp
Xcan be used with
X.I sendmail
Xinstead of the latter's built-in \s-2IPC\s0 mailer.
XHere is a mailer definition we have used;
Xyour mileage will vary:
X.PP
X.nf
X.B
XMether, P=/usr/lib/mail/smtp, F=SsDFuCX, S=11, R=21, A=smtp $h $g $u
X.fi
X.PP
XEvery SMTP talker identifies itself in the
X``host.domain''
Xpart of the \s-2SMTP\s0 \s-2HELO\s0 message.
XNormally
X.I smtp
Xuses the
X.IR gethostname (2)
Xcall to get the hostname,
Xand the compiled-in DOMAINNAME,
Xto identify itself.
XThe
X.B \-h
Xoption allows you to override both values with one string,
Xi.e.,
X.BR \-h erewhon.peter.edu.
XIf you are using 
X.I sendmail ,
Xthen
X.B \-h
Xshould be added to the Mether definition with ``-h$j''
X(but this has not yet been tested).
XIn
X.IR upas ,
Xa typical rule is
X.PP
X.nf
X.B
X^([^!]+)\e.(mil|gov|edu|com|uk|org|net)!(.+)$ | "smtpqer -h \fIdom.ain\fP \e1.\e2 \es \e3"
X.fi
X.PP
X.I smtpd
Xis a 4.2BSD (or later) network daemon:
Xit listens on the SMTP port
X(TCP port 25 usually)
Xfor an SMTP talker,
Xreceives a mail message from it
Xand hands the message to
X.I cmail
X(or equivalent other mail system).
X.I in.smtpd
Xis a similar 4.3BSD (or later)
X.I inetd
Xdaemon:
Xit expects an SMTP connection on file descriptor zero (0)
Xand the
X.I sourcehost
Xand
X.I sourceport
Xas its argument
X.RI ( sourcehost
Xin hexademical;
X.I sourceport
Xin decimal).
X.PP
X.I smtpqer
Xqueues its standard input
Xand shell commands to invoke
X.I smtp
Xwith
X.IR smtpqer 's
Xstandard input and arguments,
Xand to remove the queued files if
X.I smtp
Xis successful.
XIt then runs
X.IR runsmtpq .
X.PP
X.I runsmtpq
Xlocks the SMTP queue,
Xexecutes all the shell command files in the SMTP queue,
Xand unlocks the SMTP queue.
X.I runsmtpq
Xis stolen outright from the SM paper in the proceedings
Xof the Portland Usenix conference.
X.PP
X.I smtpq
Xshows the contents of the SMTP queue.
X.PP
X.I cleansmtpq
Xreturns to sender mail which has been in the SMTP queue
Xfor more than three days and removes it from the queue.
X.PP
X.I returnsmtpmail
Xtakes the names of ``envelope'' shell files,
Xreturns the messages therein
Xand removes the messages from the SMTP queue.
X.SH FILES
X.BR /usr/spool/smtpq "	the SMTP queue"
X.br
X.IB queue /*.sh
X\&	envelopes
X.br
X.IB queue /*.msg
X\&	message contents
X.br
X.IB queue /*.errs
X\&	errors from running
X.I smtp
X.br
X.BR temp.* "	incoming messages, created in"
X.IR smtpd 's
Xcurrent directory
X.SH "SEE ALSO"
XRFC 821 \- Simple Mail Transfer Protocol, ARPA Internet, NIC, SRI
X.SH DIAGNOSTICS
XBy default,
Xthe talker program exits with the return codes defined in
X.I <sysexits.h>
Xfor
X.IR sendmail .
XTo disable this,
Xcompile with -DNOSYSEXITS;
Xit will exit with code 1 for all errors.
X.SH HISTORY
XThe SMTP talker (client) was written by Ian Darwin in 1985,
Xas a simple telnet-like program
Xthat just talked from stdin to a remote SMTP.
XIn late 1986,
Xit was built into a full talker
Xwith some functions stolen
Xfrom the public domain MIT UNIX TCP/IP implementation.
X.PP
XThe SMTP listener (daemon) was synthesised by Geoff Collyer
Xby smashing together an old
X.I nicname
Xdaemon written by Ian with more public-domain SMTP code from MIT.
X.PP
X.I smtpqer
Xand
X.I smtpq
Xwere written by Geoff Collyer.
X.IR runsmtpq ,
X.I cleansmtpq
Xand
X.I returnsmtpmail
Xwere stolen from the SM Portland Usenix paper
Xand adapted by Geoff Collyer.
XPeter Honeyman installed it under
X.I upas
Xon the Internet and fixed a lot of bugs.
XSome remain.
X.SH BUGS
XThe SMTP implementation is minimal,
Xand could stand some fleshing out.
X.PP
X.I smtp
Xand
X.I smtpqer
Xcould profitably handle multiple recipients on the same machine,
Xbut dealing with bad recipients would be tricky.
X.PP
X.I smtpd
Xand
X.I in.smtpd
Xcreate files named
X.I temp.*
Xin their current directories,
Xso they should be run in the SMTP queue directory.
X.PP
X.I smtp
Xand
X.I smtpd
Xlimit connect time to 30 minutes,
Xwhich can be optimistic.
SHAR_EOF
if test 4836 -ne "`wc -c < 'smtp.8'`"
then
	echo shar: "error transmitting 'smtp.8'" '(should have been 4836 characters)'
fi
fi
echo shar: "extracting 'smtp.c'" '(4985 characters)'
if test -f 'smtp.c'
then
	echo shar: "will not over-write existing file 'smtp.c'"
else
sed 's/^X//' << \SHAR_EOF > 'smtp.c'
X/*
X * smtp -- client, send mail to remote smtp server
X * Set up for 4.2BSD networking system.
X * Adapted for System V by jv@mh.nl.
X * TODO:
X *	better mapping of error numbers.
X *	allow multiple recipients (maybe)
X * 	send stuff from cmds.h instead of hard-coded here
X */
X
X#define	USAGE "usage: %s [-h helohost] targethost sender recipient\n"
X
X#include "smtp.h"
X#include <sys/uio.h>		/* needed for socket.h */
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X
X
X#ifndef SERVNAME
X#define SERVNAME "smtp"			/* service we wanna talk to */
X#endif
X
Xchar *progname;
Xint debug = 0;
Xextern char hostname[];
Xextern char hostdomain[];
Xchar *sendhost = hostdomain;
XFILE *sfi, *sfo;
Xchar *host = "None";
Xchar *strcat(), *strcpy();
Xstatic char *makedomain();
X
X#ifdef HOOTING
Xextern int hooting;	/* in netio */
X#endif
X
X/*
X * main - parse arguments and handle options
X */
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	register int c;
X	int errflg = 0;
X	extern int optind;
X	extern char *optarg;
X	char *sender, *recip;
X
X	progname = argv[0];
X	getmynames ();
X
X	while ((c = getopt(argc, argv, "dh:")) != EOF)
X		switch (c) {
X		case 'd':
X			++debug;
X			break;
X		case 'h':		/* alternate sending host */
X			sendhost = optarg;
X			break;
X		case '?':
X		default:
X			errflg++;
X			break;
X		}
X	if (errflg || (argc - optind) < 3) {
X		(void) fprintf(stderr, USAGE, progname);
X		bomb(E_USAGE);
X	}
X	host = argv[optind++];
X	sender = makedomain(argv[optind++], sendhost);
X	recip  = makedomain(argv[optind++], host);
X
X	setup();		/* open connection */
X
X
X#ifdef HOOTING
X	hooting = 1;
X#endif
X	/* hold the conversation */
X
X	converse(sender, recip, sfi, sfo, stdin);
X	(void) sleep(5);	/* drain? */
X
X	if (sfo!=NULL)
X		(void) fclose(sfo);
X	if (sfi!=NULL)
X		(void) fclose(sfi);
X
X	return 0;
X}
X
X/*
X * setup -- setup tcp/ip connection to/from server
X */
Xsetup()
X{
X	struct hostent *hp;
X	struct servent *sp;
X	struct sockaddr_in sin;
X	int s;
X	extern int errno;
X
X	(void) bzero((char *)&sin, sizeof(sin));
X
X	if ((hp = gethostbyname(host)) == (struct hostent *) NULL) {
X		(void) fprintf(stderr, "unknown host (%s).\n", host);
X		bomb(E_NOHOST);
X	}
X
X	(void) bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
X
X	if ((sp = getservbyname (SERVNAME, "tcp")) == NULL) {
X		(void)fprintf(stderr,"unknown service TCP/%s\n", SERVNAME);
X		bomb(E_OSFILE);
X	}
X	sin.sin_port = sp->s_port;
X	sin.sin_family = hp->h_addrtype;
X
X	if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
X		perror("setup - socket");
X		bomb(E_CANTOPEN);
X	}
X
X	if (connect(s, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
X		perror("setup - connect");
X		/*
X		 * check for conditions that (we think) are temporary;
X		 * try them later; bomb utterly on all others.
X		 */
X		if (errno == ETIMEDOUT || errno == ECONNREFUSED || 
X			errno == EHOSTDOWN || errno == EHOSTUNREACH)
X			bomb(E_TEMPFAIL);
X		else
X			bomb(E_CANTOPEN);
X	}
X
X	if (((sfi = fdopen(s, "r")) == (FILE *) NULL) ||
X	    ((sfo = fdopen(s, "w")) == (FILE *) NULL)) {
X		perror("setup - fdopen");
X		bomb(E_CANTOPEN);
X	}
X/*	setbuf(sfi, (char *) 0);*/
X}
X
X/*
X * bomb(code) - exit program, map smtp error code into mailsystem code
X * Codes with E_ are defined in miscerrs.h.
X * Codes with EX_ are from <sysexits.h>
X * Lines with FOO are placeholders until we decrypt more appropriate codes.
X */
Xbomb(code)
Xint code;
X{
X	if (sfi != NULL)
X		(void) fclose(sfi);
X	if (sfo != NULL)
X		(void) fclose(sfo);
X
X#ifdef	EX_OK
X	switch(code) {
X	case 451:			/* host not responding */
X		code = EX_UNAVAILABLE;	/* service unavailable */
X		break;
X	case 550:
X		code = EX_NOUSER;	/* addressee unknown */
X		break;
X	case 501:			/* syntax error in address */
X	case 554:			/* */
X		code = EX_DATAERR;	/* data format error */
X		break;
X	case E_IOERR:
X		code = EX_IOERR;	/* input/output error */
X		break;
X	case E_NOHOST:
X		code = EX_NOHOST;	/* host name unknown */
X		break;
X	case E_OSFILE:			/* no "smtp" -> /etc/services f'd */
X		code = EX_OSFILE;	/* critical OS file missing */
X		break;
X	case E_USAGE:
X		code = EX_USAGE;	/* command line usage error */
X		break;
X	case E_TEMPFAIL:
X		code = EX_TEMPFAIL;	/* temp failure; user can retry */
X		break;
X#if 0
X	case FOO:
X		code = EX_OSERR;	/* system error (e.g., can't fork) */
X		break;
X	case FOO:
X		code = EX_NOINPUT;	/* cannot open input */
X		break;
X	case FOO:
X		code = EX_CANTCREAT;	/* can't create (user) output file */
X		break;
X	case FOO:
X		code = EX_PROTOCOL;	/* remote error in protocol */
X		break;
X	case FOO:
X		code = EX_NOPERM;	/* permission denied */
X		break;
X#endif	/* NOTDEF */
X	default:			/* can't happen? */
X		code = EX_SOFTWARE;	/* internal software error */
X		break;
X	}
X
X#else	/* has no sysexits */
X	code = 1;
X#endif
X
X	(void) exit (code);
X}
X
Xstatic char *
Xmakedomain(addr, domain)
Xchar *addr, *domain;
X{
X	char *rval;
X	extern char *index(), *malloc();
X
X	if (index(addr, '@') != 0)
X		return addr;
X
X	if ((rval = malloc(strlen(addr) + strlen(domain) + 2)) == 0)
X#ifdef EX_SOFTWARE
X		bomb(EX_SOFTWARE);	/* can't happen! */
X#else
X		bomb (3);
X#endif
X	sprintf(rval, "%s@%s", addr, domain);
X	return rval;
X}
SHAR_EOF
if test 4985 -ne "`wc -c < 'smtp.c'`"
then
	echo shar: "error transmitting 'smtp.c'" '(should have been 4985 characters)'
fi
fi
echo shar: "extracting 'smtp.h'" '(1022 characters)'
if test -f 'smtp.h'
then
	echo shar: "will not over-write existing file 'smtp.h'"
else
sed 's/^X//' << \SHAR_EOF > 'smtp.h'
X/* smtp.h */
X
X#include "config.h"
X
X/* smtp constants and the like */
X
X/* tunable constants */
X#define MAXSTR 10240			/* maximum string length */
X#define NAMSIZ MAXSTR			/* max file name length */
X
X/* standard includes and portability */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <errno.h>
X#include "miscerrs.h"
X
X#ifdef BSD
X#include <strings.h>
X#include <sys/time.h>
X#include <sys/wait.h>
Xextern char *sprintf();
X# ifndef NOSYSEXITS
X#  include <sysexits.h>
X# endif
X#endif
X
X#ifdef SYSV
X#include <string.h>
X#include <time.h>
X#include <fcntl.h>
X#define	index		strchr
X#define	rindex		strrchr
X#define	bcopy(a,b,n)	memcpy(b,a,n)
X#define	bzero(a,n)	memset(a,'\0',n)
X#define	SIGCHLD		SIGCLD
Xextern int sprintf();
X# ifndef NOSYSEXITS
X#  include "sysexits.h"
X# endif
X#endif
X
X#ifndef EX_SOFTWARE
X# define EX_SOFTWARE	70	/* internal software error */
X#endif
X
X#ifdef SYSLOG
X# ifdef SYSV
X#  include "syslog.h"
X# else
X#  include <syslog.h>
X# endif
X#endif
X
X#ifndef TRUE
X# define TRUE	1
X# define FALSE	0
X#endif
SHAR_EOF
if test 1022 -ne "`wc -c < 'smtp.h'`"
then
	echo shar: "error transmitting 'smtp.h'" '(should have been 1022 characters)'
fi
fi
echo shar: "extracting 'smtpd.c'" '(5297 characters)'
if test -f 'smtpd.c'
then
	echo shar: "will not over-write existing file 'smtpd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'smtpd.c'
X#ifndef lint
Xstatic char *sccsid = "@(#)smtpd.c	1.7 87/07/31";
X#endif lint
X/*
X * smtpd - SMTP listener: receives SMTP mail & invokes cmail.
X *	SMTP is either Simple Mail Transfer Protocol or
X *	Sado-Masochistic Torture Procedure.
X */
X
X#include "smtp.h"
X#include <signal.h>
X#include <netdb.h>
X#include <sys/uio.h>
X#include <sys/socket.h>
X#ifdef BSD
X#include <sgtty.h>
X#include <sys/wait.h>
X#endif
X#include <sys/resource.h>	/* for wait3(2) */
X#include <netinet/in.h>
X
X/* forward declarations */
XFILE	*popen();
X
X#ifdef INETD
X#ifdef BSD
Xint	reapchild();
X#endif
X#endif
X
Xextern	char **environ;
Xextern	int errno, sys_nerr;
Xextern	char *sys_errlist[];
X
X#ifndef SERVNAME
X#define SERVNAME "smtp"
X#endif				/* SERVNAME */
Xstruct sockaddr_in sin = { AF_INET };
Xstruct sockaddr_in from;
X
Xint debug;
Xchar *progname;
Xchar logm[MAXSTR];
X
X/*
X * main - parse arguments and handle options
X */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int c;
X	int errflg = 0;
X	extern int optind;
X	extern char *optarg;
X
X	progname = argv[0];
X	getmynames ();
X
X	while ((c = getopt(argc, argv, "d")) != EOF)
X		switch (c) {
X		case 'd':
X			++debug;
X			break;
X		case '?':
X		default:
X			errflg++;
X			break;
X		}
X	if (errflg) {
X		logit(LOG_CRIT, "Usage: %s [-d]\n", progname);
X		exit(2);
X	}
X
X	if (optind >= argc)
X		process();
X#ifdef INETD
X	else if (optind == argc - 1) {		/* one argument */
X		if (sscanf(argv[optind], "%lx.%hd", &from.sin_addr.s_addr,
X		    &from.sin_port) != 2) {
X			logit(LOG_CRIT,
X				"in.smtpd: bad arg from inetd: %s\n",
X				argv[optind]);
X			exit(2);
X		}
X		from.sin_family = AF_INET;
X		from.sin_addr.s_addr = htonl(from.sin_addr.s_addr);
X		from.sin_port = htons(from.sin_port);
X		process();
X	}
X#endif				/* INETD */
X	else {
X		logit(LOG_CRIT, "%s: too many args\n", progname);
X		exit(2);
X	}
X
X	return 0;
X}
X
X/*
X * process - process input file
X */
Xprocess()
X{
X#ifndef INETD
X	int s, pid;
X#endif		/* INETD */
X	struct servent *sp;
X
X	sp = getservbyname(SERVNAME, "tcp");
X	if (sp == 0) {
X		logit(LOG_CRIT, "tcp/%s: unknown service\n", SERVNAME);
X		exit(1);
X	}
X	sin.sin_port = sp->s_port;
X
X#ifdef INETD
X	/* connection on fd 0 from inetd */
X	doit(0, &from);
X	/* NOTREACHED */
X	exit(0);
X#else					/* INETD */
X#ifndef DEBUG
X	if (fork())			/* run in the background */
X		exit(0);
X	for (s = 0; s < 10; s++)	/* close most file descriptors */
X		(void) close(s);
X	(void) open("/dev/null", 0);	/* reopen them on harmless streams */
X	(void) dup2(0, 1);
X	(void) dup2(0, 2);
X	{ int tt = open("/dev/tty", 2);	/* leave current process group */
X	  if (tt > 0) {
X#ifdef TIOCNOTTY
X		(void) ioctl(tt, TIOCNOTTY, (char *)0);
X#endif
X		(void) close(tt);
X	  }
X	}
X#endif					/* DEBUG */
X	/* create internet socket s; retry 5 times at 5 s. intervals if no luck */
X	while ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
X		static int nlog = 0;
X
X		if (nlog++ <= 5)
X			logit(LOG_CRIT, "socket", "");
X		sleep(5);
X	}
X	/* set socket options, notably keepalive */
X	if (debug) {
X		int debugval = 1;
X
X		if (setsockopt(s, SOL_SOCKET, SO_DEBUG,
X		    (char *)&debugval, sizeof(int)) < 0)
X			logit(LOG_CRIT, "setsockopt (SO_DEBUG)", "");
X	}
X	if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)0, 0) < 0)
X		logit(LOG_CRIT, "setsockopt (SO_KEEPALIVE)", "");
X	/* bind socket to SERVNAME (SMTP) port; retry as above on failure */
X	while (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
X		static int nlog = 0;
X
X		if (nlog++ <= 5)
X			logit(LOG_CRIT, "bind", "");
X		sleep(5);
X	}
X
X#ifdef BSD
X	(void) signal(SIGCHLD, TYPESIG reapchild);
X#else
X	(void) signal(SIGCHLD, SIG_IGN);	/* SystemV takes care ... */
X#endif
X
X	/* listen with 10 input buffers on socket (?) */
X	if (listen(s, 10) == -1)
X		logit(LOG_CRIT, "listen", "");
X	for (;;) {
X		int conn, fromlen = sizeof from;
X
X		/* get a connection on fd conn; stores src host addr in from */
X		conn = accept(s, (struct sockaddr *)&from, &fromlen);
X		if (conn < 0) {
X			static int nlog = 0;
X
X			if (errno == EINTR)
X				continue;
X			if (++nlog <= 5)
X				logit(LOG_CRIT, "accept", "");
X			sleep(1);
X			continue;
X		}
X		/* fork a child for this connection */
X		if ((pid = fork()) < 0)
X			logit(LOG_CRIT, "can't fork!!", "");
X		else if (pid == 0) {
X			(void) signal(SIGCHLD, SIG_DFL);
X			doit(conn, &from);	/* listen to SMTP dialogue */
X			/* NOTREACHED */
X			exit(0);
X		}
X		(void) close(conn);
X	}
X	/*NOTREACHED*/
X#endif			/* INETD */
X}
X
X#ifndef INETD
X#ifdef BSD
Xreapchild()
X{
X	union wait status;
X
X	/* gross hack! */
X	while (wait3(&status, WNOHANG, (struct rusage *)0) > 0);
X
X}
X#endif				/* BSD */
X#endif			/* INETD */
X
X/*
X * handle some input.  never returns.
X */
Xdoit(f, fromaddr)
Xint f;
Xstruct sockaddr_in *fromaddr;		/* internet addr of sending host */
X{
X	FILE *fi, *fo;
X
X	if ((fi = fdopen(f, "r")) == NULL)
X		logit(LOG_CRIT, "fdopen of socket for input", "");
X	if ((fo = fdopen(f, "w")) == NULL)
X		logit(LOG_CRIT, "fdopen of socket for output", "");
X
X	converse(fi, fo, fromaddr);
X	/* NOTREACHED */
X	return 0;
X}
X
X#ifndef NOBOMB
Xbomb(err)
Xint err;
X{
X	death(err);
X}
X#endif
X
Xlogit (sev, fmt, str)
Xint sev;
Xchar *fmt, *str;
X{
X#ifdef SYSLOG
X	(void) sprintf(logm, "%s: %s", progname, fmt);
X	(void) syslog(sev, logm, (str == "" && errno <= sys_nerr)?
X		sys_errlist[errno]: str);
X#else
X	(void) sprintf(logm, "%s: %s", progname, fmt);
X	(void) fprintf(stderr, logm, (str == "" && errno <= sys_nerr)?
X		sys_errlist[errno]: str);
X#endif
X}
SHAR_EOF
if test 5297 -ne "`wc -c < 'smtpd.c'`"
then
	echo shar: "error transmitting 'smtpd.c'" '(should have been 5297 characters)'
fi
fi
echo shar: "extracting 'sysexits.h'" '(3662 characters)'
if test -f 'sysexits.h'
then
	echo shar: "will not over-write existing file 'sysexits.h'"
else
sed 's/^X//' << \SHAR_EOF > 'sysexits.h'
X/*
X**  SYSEXITS.H -- Exit status codes for system programs.
X**
X**	This include file attempts to categorize possible error
X**	exit statuses for system programs, notably delivermail
X**	and the Berkeley network.
X**
X**	Error numbers begin at EX__BASE to reduce the possibility of
X**	clashing with other exit statuses that random programs may
X**	already return.  The meaning of the codes is approximately
X**	as follows:
X**
X**	EX_USAGE -- The command was used incorrectly, e.g., with
X**		the wrong number of arguments, a bad flag, a bad
X**		syntax in a parameter, or whatever.
X**	EX_DATAERR -- The input data was incorrect in some way.
X**		This should only be used for user's data & not
X**		system files.
X**	EX_NOINPUT -- An input file (not a system file) did not
X**		exist or was not readable.  This could also include
X**		errors like "No message" to a mailer (if it cared
X**		to catch it).
X**	EX_NOUSER -- The user specified did not exist.  This might
X**		be used for mail addresses or remote logins.
X**	EX_NOHOST -- The host specified did not exist.  This is used
X**		in mail addresses or network requests.
X**	EX_UNAVAILABLE -- A service is unavailable.  This can occur
X**		if a support program or file does not exist.  This
X**		can also be used as a catchall message when something
X**		you wanted to do doesn't work, but you don't know
X**		why.
X**	EX_SOFTWARE -- An internal software error has been detected.
X**		This should be limited to non-operating system related
X**		errors as possible.
X**	EX_OSERR -- An operating system error has been detected.
X**		This is intended to be used for such things as "cannot
X**		fork", "cannot create pipe", or the like.  It includes
X**		things like getuid returning a user that does not
X**		exist in the passwd file.
X**	EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
X**		etc.) does not exist, cannot be opened, or has some
X**		sort of error (e.g., syntax error).
X**	EX_CANTCREAT -- A (user specified) output file cannot be
X**		created.
X**	EX_IOERR -- An error occurred while doing I/O on some file.
X**	EX_TEMPFAIL -- temporary failure, indicating something that
X**		is not really an error.  In sendmail, this means
X**		that a mailer (e.g.) could not create a connection,
X**		and the request should be reattempted later.
X**	EX_PROTOCOL -- the remote system returned something that
X**		was "not possible" during a protocol exchange.
X**	EX_NOPERM -- You did not have sufficient permission to
X**		perform the operation.  This is not intended for
X**		file system problems, which should use NOINPUT or
X**		CANTCREAT, but rather for higher level permissions.
X**		For example, kre uses this to restrict who students
X**		can send mail to.
X**
X**	Maintained by Eric Allman (eric@berkeley, ucbvax!eric) --
X**		please mail changes to me.
X**
X**	@(#)sysexits.h	1.2	86/05/09	ACE (c)
X*/
X
X# define EX_OK		0	/* successful termination */
X
X# define EX__BASE	64	/* base value for error messages */
X
X# define EX_USAGE	64	/* command line usage error */
X# define EX_DATAERR	65	/* data format error */
X# define EX_NOINPUT	66	/* cannot open input */
X# define EX_NOUSER	67	/* addressee unknown */
X# define EX_NOHOST	68	/* host name unknown */
X# define EX_UNAVAILABLE	69	/* service unavailable */
X# define EX_SOFTWARE	70	/* internal software error */
X# define EX_OSERR	71	/* system error (e.g., can't fork) */
X# define EX_OSFILE	72	/* critical OS file missing */
X# define EX_CANTCREAT	73	/* can't create (user) output file */
X# define EX_IOERR	74	/* input/output error */
X# define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
X# define EX_PROTOCOL	76	/* remote error in protocol */
X# define EX_NOPERM	77	/* permission denied */
SHAR_EOF
if test 3662 -ne "`wc -c < 'sysexits.h'`"
then
	echo shar: "error transmitting 'sysexits.h'" '(should have been 3662 characters)'
fi
fi
echo shar: "extracting 'syslog.h'" '(24 characters)'
if test -f 'syslog.h'
then
	echo shar: "will not over-write existing file 'syslog.h'"
else
sed 's/^X//' << \SHAR_EOF > 'syslog.h'
X#include <sys/syslog.h>
SHAR_EOF
if test 24 -ne "`wc -c < 'syslog.h'`"
then
	echo shar: "error transmitting 'syslog.h'" '(should have been 24 characters)'
fi
fi
echo shar: "extracting 'MANIFEST'" '(144 characters)'
if test -f 'MANIFEST'
then
	echo shar: "will not over-write existing file 'MANIFEST'"
else
sed 's/^X//' << \SHAR_EOF > 'MANIFEST'
XMakefile
XREADME
Xcmds.h
Xconfig.h
Xconverse.c
Xdconverse.c
Xmisc.c
Xmiscerrs.h
Xmx.c
Xnetio.c
Xsmtp.8
Xsmtp.c
Xsmtp.h
Xsmtpd.c
Xsysexits.h
Xsyslog.h
XMANIFEST
SHAR_EOF
if test 144 -ne "`wc -c < 'MANIFEST'`"
then
	echo shar: "error transmitting 'MANIFEST'" '(should have been 144 characters)'
fi
fi
exit 0
#	End of shell archive

-- 
postmaster on node mhres (currently: Johan Vromans)