1294Seric # include <signal.h>
24123Seric # include <errno.h>
33310Seric # include "sendmail.h"
4294Seric # ifdef LOG
52774Seric # include <syslog.h>
6294Seric # endif LOG
7294Seric 
8*4194Seric static char SccsId[] = "@(#)deliver.c	3.26	08/21/81";
9405Seric 
10294Seric /*
11294Seric **  DELIVER -- Deliver a message to a particular address.
12294Seric **
13294Seric **	Parameters:
14294Seric **		to -- the address to deliver the message to.
15294Seric **		editfcn -- if non-NULL, we want to call this function
16294Seric **			to output the letter (instead of just out-
17294Seric **			putting it raw).
18294Seric **
19294Seric **	Returns:
20294Seric **		zero -- successfully delivered.
21294Seric **		else -- some failure, see ExitStat for more info.
22294Seric **
23294Seric **	Side Effects:
24294Seric **		The standard input is passed off to someone.
25294Seric */
26294Seric 
27294Seric deliver(to, editfcn)
282968Seric 	ADDRESS *to;
29294Seric 	int (*editfcn)();
30294Seric {
31294Seric 	char *host;
32294Seric 	char *user;
33294Seric 	char **pvp;
343233Seric 	register char **mvp;
353233Seric 	register char *p;
363233Seric 	register struct mailer *m;
37294Seric 	register int i;
382898Seric 	extern putmessage();
392968Seric 	extern bool checkcompat();
403233Seric 	char *pv[MAXPV+1];
413233Seric 	char tobuf[MAXLINE];
423233Seric 	char buf[MAXNAME];
433233Seric 	bool firstone;
44294Seric 
453233Seric 	if (bitset(QDONTSEND, to->q_flags))
463233Seric 		return (0);
47294Seric 
48294Seric # ifdef DEBUG
49294Seric 	if (Debug)
503233Seric 		printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",
513233Seric 			to->q_mailer, to->q_host, to->q_user);
52294Seric # endif DEBUG
53294Seric 
54294Seric 	/*
553233Seric 	**  Do initial argv setup.
563233Seric 	**	Insert the mailer name.  Notice that $x expansion is
573233Seric 	**	NOT done on the mailer name.  Then, if the mailer has
583233Seric 	**	a picky -f flag, we insert it as appropriate.  This
593233Seric 	**	code does not check for 'pv' overflow; this places a
603233Seric 	**	manifest lower limit of 4 for MAXPV.
612968Seric 	*/
622968Seric 
633233Seric 	m = Mailer[to->q_mailer];
643233Seric 	host = to->q_host;
653233Seric 	define('g', m->m_from);		/* translated from address */
663233Seric 	define('h', host);		/* to host */
673233Seric 	Errors = 0;
683233Seric 	errno = 0;
693233Seric 	pvp = pv;
703233Seric 	*pvp++ = m->m_argv[0];
712968Seric 
723233Seric 	/* insert -f or -r flag as appropriate */
733233Seric 	if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag)
743233Seric 	{
753233Seric 		if (bitset(M_FOPT, m->m_flags))
763233Seric 			*pvp++ = "-f";
773233Seric 		else
783233Seric 			*pvp++ = "-r";
794082Seric 		(void) expand("$g", buf, &buf[sizeof buf - 1]);
803233Seric 		*pvp++ = newstr(buf);
813233Seric 	}
82294Seric 
83294Seric 	/*
843233Seric 	**  Append the other fixed parts of the argv.  These run
853233Seric 	**  up to the first entry containing "$u".  There can only
863233Seric 	**  be one of these, and there are only a few more slots
873233Seric 	**  in the pv after it.
88294Seric 	*/
89294Seric 
903233Seric 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
91294Seric 	{
923233Seric 		while ((p = index(p, '$')) != NULL)
933233Seric 			if (*++p == 'u')
943233Seric 				break;
953233Seric 		if (p != NULL)
963233Seric 			break;
973233Seric 
983233Seric 		/* this entry is safe -- go ahead and process it */
994082Seric 		(void) expand(*mvp, buf, &buf[sizeof buf - 1]);
1003233Seric 		*pvp++ = newstr(buf);
1013233Seric 		if (pvp >= &pv[MAXPV - 3])
1023233Seric 		{
1033233Seric 			syserr("Too many parameters to %s before $u", pv[0]);
1043233Seric 			return (-1);
1053233Seric 		}
106294Seric 	}
1073233Seric 	if (*mvp == NULL)
1083233Seric 		syserr("No $u in mailer argv for %s", pv[0]);
109294Seric 
110294Seric 	/*
1113233Seric 	**  At this point *mvp points to the argument with $u.  We
1123233Seric 	**  run through our address list and append all the addresses
1133233Seric 	**  we can.  If we run out of space, do not fret!  We can
1143233Seric 	**  always send another copy later.
115294Seric 	*/
116294Seric 
1173233Seric 	tobuf[0] = '\0';
1183233Seric 	firstone = TRUE;
1193233Seric 	To = tobuf;
1203233Seric 	for (; to != NULL; to = to->q_next)
121294Seric 	{
1223233Seric 		/* avoid sending multiple recipients to dumb mailers */
1233233Seric 		if (!firstone && !bitset(M_MUSER, m->m_flags))
1243233Seric 			break;
1253233Seric 
1263233Seric 		/* if already sent or not for this host, don't send */
1273233Seric 		if (bitset(QDONTSEND, to->q_flags) || strcmp(to->q_host, host) != 0)
1283233Seric 			continue;
1293233Seric 		user = to->q_user;
1303233Seric 		To = to->q_paddr;
1313233Seric 		to->q_flags |= QDONTSEND;
1323233Seric 		firstone = FALSE;
1333233Seric 
1343233Seric # ifdef DEBUG
1353233Seric 		if (Debug)
1363233Seric 			printf("   send to `%s'\n", user);
1373233Seric # endif DEBUG
1383233Seric 
1393233Seric 		/*
1403233Seric 		**  Check to see that these people are allowed to
1413233Seric 		**  talk to each other.
1423233Seric 		*/
1433233Seric 
1443233Seric 		if (!checkcompat(to))
145294Seric 		{
1463233Seric 			giveresponse(EX_UNAVAILABLE, TRUE, m);
1473233Seric 			continue;
148294Seric 		}
1493233Seric 
1503233Seric 		/*
1514099Seric 		**  Strip quote bits from names if the mailer is dumb
1524099Seric 		**	about them.
1533233Seric 		*/
1543233Seric 
1553233Seric 		if (bitset(M_STRIPQ, m->m_flags))
156294Seric 		{
1574099Seric 			stripquotes(user, TRUE);
1584099Seric 			stripquotes(host, TRUE);
1593233Seric 		}
1604099Seric 		else
1614099Seric 		{
1624099Seric 			stripquotes(user, FALSE);
1634099Seric 			stripquotes(host, FALSE);
1644099Seric 		}
1653233Seric 
1663233Seric 		/*
1674161Seric 		**  If an error message has already been given, don't
1684161Seric 		**	bother to send to this address.
1694161Seric 		**
1704161Seric 		**	>>>>>>>>>> This clause assumes that the local mailer
1714161Seric 		**	>> NOTE >> cannot do any further aliasing; that
1724161Seric 		**	>>>>>>>>>> function is subsumed by sendmail.
1734161Seric 		*/
1744161Seric 
1754161Seric 		if (bitset(QBADADDR, to->q_flags))
1764161Seric 			continue;
1774161Seric 
1784161Seric 		/*
1793233Seric 		**  See if this user name is "special".
1803233Seric 		**	If the user name has a slash in it, assume that this
1813233Seric 		**	is a file -- send it off without further ado.
1823233Seric 		**	Note that this means that editfcn's will not
1833233Seric 		**	be applied to the message.  Also note that
1843233Seric 		**	this type of addresses is not processed along
1853233Seric 		**	with the others, so we fudge on the To person.
1863233Seric 		*/
1873233Seric 
188*4194Seric 		if (m == Mailer[MN_LOCAL])
1893233Seric 		{
190294Seric 			if (index(user, '/') != NULL)
191294Seric 			{
192294Seric 				i = mailfile(user);
193294Seric 				giveresponse(i, TRUE, m);
1943233Seric 				continue;
195294Seric 			}
196294Seric 		}
1973233Seric 
1983233Seric 		/* create list of users for error messages */
1993233Seric 		if (tobuf[0] != '\0')
2004082Seric 			(void) strcat(tobuf, ",");
2014082Seric 		(void) strcat(tobuf, to->q_paddr);
2023233Seric 		define('u', user);		/* to user */
2034078Seric 		define('z', to->q_home);	/* user's home */
2043233Seric 
2053233Seric 		/* expand out this user */
2064082Seric 		(void) expand(user, buf, &buf[sizeof buf - 1]);
2073233Seric 		*pvp++ = newstr(buf);
2083233Seric 		if (pvp >= &pv[MAXPV - 2])
2093233Seric 		{
2103233Seric 			/* allow some space for trailing parms */
2113233Seric 			break;
2123233Seric 		}
213294Seric 	}
214294Seric 
2154067Seric 	/* see if any addresses still exist */
2164067Seric 	if (tobuf[0] == '\0')
2174067Seric 		return (0);
2184067Seric 
2193233Seric 	/* print out messages as full list */
2203233Seric 	To = tobuf;
2213233Seric 
222294Seric 	/*
2233233Seric 	**  Fill out any parameters after the $u parameter.
224294Seric 	*/
225294Seric 
2263233Seric 	while (*++mvp != NULL)
227294Seric 	{
2284082Seric 		(void) expand(*mvp, buf, &buf[sizeof buf - 1]);
2293233Seric 		*pvp++ = newstr(buf);
2303233Seric 		if (pvp >= &pv[MAXPV])
2313233Seric 			syserr("deliver: pv overflow after $u for %s", pv[0]);
232294Seric 	}
2333233Seric 	*pvp++ = NULL;
234294Seric 
235294Seric 	/*
236294Seric 	**  Call the mailer.
2372898Seric 	**	The argument vector gets built, pipes
238294Seric 	**	are created as necessary, and we fork & exec as
2392898Seric 	**	appropriate.
2404078Seric 	**
2414078Seric 	**	Notice the tacky hack to handle private mailers.
242294Seric 	*/
243294Seric 
2443233Seric 	if (editfcn == NULL)
2453233Seric 		editfcn = putmessage;
2463233Seric 	i = sendoff(m, pv, editfcn);
2473233Seric 
2483233Seric 	return (i);
2493233Seric }
2503233Seric /*
2513233Seric **  SENDOFF -- send off call to mailer & collect response.
2523233Seric **
2533233Seric **	Parameters:
2543233Seric **		m -- mailer descriptor.
2553233Seric **		pvp -- parameter vector to send to it.
2563233Seric **		editfcn -- function to pipe it through.
2573233Seric **
2583233Seric **	Returns:
2593233Seric **		exit status of mailer.
2603233Seric **
2613233Seric **	Side Effects:
2623233Seric **		none.
2633233Seric */
2643233Seric 
2654052Seric #define NFORKTRIES	5
2664052Seric 
2673233Seric sendoff(m, pvp, editfcn)
2683233Seric 	struct mailer *m;
2693233Seric 	char **pvp;
2703233Seric 	int (*editfcn)();
2713233Seric {
2723233Seric 	auto int st;
2733233Seric 	register int i;
2743233Seric 	int pid;
2753233Seric 	int pvect[2];
2763233Seric 	FILE *mfile;
2773233Seric 	extern putmessage();
2783233Seric 	extern FILE *fdopen();
2793233Seric 
2803233Seric # ifdef DEBUG
2813233Seric 	if (Debug)
282294Seric 	{
2833233Seric 		printf("Sendoff:\n");
2843233Seric 		printav(pvp);
285294Seric 	}
2863233Seric # endif DEBUG
2873233Seric 
2882898Seric 	/* create a pipe to shove the mail through */
2892898Seric 	if (pipe(pvect) < 0)
290294Seric 	{
291294Seric 		syserr("pipe");
292294Seric 		return (-1);
293294Seric 	}
2944052Seric 	for (i = NFORKTRIES; i-- > 0; )
2954052Seric 	{
2961504Smark # ifdef VFORK
2974052Seric 		pid = vfork();
2981504Smark # else
2994052Seric 		pid = fork();
3001504Smark # endif
3014052Seric 		if (pid >= 0)
3024052Seric 			break;
3034082Seric 		sleep((unsigned) NFORKTRIES - i);
3044052Seric 	}
305294Seric 	if (pid < 0)
306294Seric 	{
307294Seric 		syserr("Cannot fork");
3084082Seric 		(void) close(pvect[0]);
3094082Seric 		(void) close(pvect[1]);
310294Seric 		return (-1);
311294Seric 	}
312294Seric 	else if (pid == 0)
313294Seric 	{
314294Seric 		/* child -- set up input & exec mailer */
3151621Seric 		/* make diagnostic output be standard output */
3164082Seric 		(void) close(2);
3174082Seric 		(void) dup(1);
3184082Seric 		(void) signal(SIGINT, SIG_IGN);
3194082Seric 		(void) close(0);
3202898Seric 		if (dup(pvect[0]) < 0)
321294Seric 		{
3222898Seric 			syserr("Cannot dup to zero!");
3232898Seric 			_exit(EX_OSERR);
324294Seric 		}
3254082Seric 		(void) close(pvect[0]);
3264082Seric 		(void) close(pvect[1]);
3272968Seric 		if (!bitset(M_RESTR, m->m_flags))
3284082Seric 			(void) setuid(getuid());
3292774Seric # ifndef VFORK
3302774Seric 		/*
3312774Seric 		**  We have to be careful with vfork - we can't mung up the
3322774Seric 		**  memory but we don't want the mailer to inherit any extra
3332774Seric 		**  open files.  Chances are the mailer won't
3342774Seric 		**  care about an extra file, but then again you never know.
3352774Seric 		**  Actually, we would like to close(fileno(pwf)), but it's
3362774Seric 		**  declared static so we can't.  But if we fclose(pwf), which
3372774Seric 		**  is what endpwent does, it closes it in the parent too and
3382774Seric 		**  the next getpwnam will be slower.  If you have a weird
3392774Seric 		**  mailer that chokes on the extra file you should do the
3402774Seric 		**  endpwent().
3412774Seric 		**
3422774Seric 		**  Similar comments apply to log.  However, openlog is
3432774Seric 		**  clever enough to set the FIOCLEX mode on the file,
3442774Seric 		**  so it will be closed automatically on the exec.
3452774Seric 		*/
3462774Seric 
3472774Seric 		endpwent();
348294Seric # ifdef LOG
3492089Seric 		closelog();
350294Seric # endif LOG
3512774Seric # endif VFORK
352294Seric 		execv(m->m_mailer, pvp);
353294Seric 		/* syserr fails because log is closed */
354294Seric 		/* syserr("Cannot exec %s", m->m_mailer); */
3552343Seric 		printf("Cannot exec %s\n", m->m_mailer);
3564082Seric 		(void) fflush(stdout);
3571619Seric 		_exit(EX_UNAVAILABLE);
358294Seric 	}
359294Seric 
3602898Seric 	/* write out message to mailer */
3614082Seric 	(void) close(pvect[0]);
3624123Seric 	(void) signal(SIGPIPE, SIG_IGN);
3632898Seric 	mfile = fdopen(pvect[1], "w");
3642898Seric 	if (editfcn == NULL)
3652898Seric 		editfcn = putmessage;
3662898Seric 	(*editfcn)(mfile, m);
3674082Seric 	(void) fclose(mfile);
368294Seric 
369294Seric 	/*
370294Seric 	**  Wait for child to die and report status.
371294Seric 	**	We should never get fatal errors (e.g., segmentation
372294Seric 	**	violation), so we report those specially.  For other
373294Seric 	**	errors, we choose a status message (into statmsg),
374294Seric 	**	and if it represents an error, we print it.
375294Seric 	*/
376294Seric 
377294Seric 	while ((i = wait(&st)) > 0 && i != pid)
378294Seric 		continue;
379294Seric 	if (i < 0)
380294Seric 	{
381294Seric 		syserr("wait");
382294Seric 		return (-1);
383294Seric 	}
384294Seric 	if ((st & 0377) != 0)
385294Seric 	{
386294Seric 		syserr("%s: stat %o", pvp[0], st);
3871597Seric 		ExitStat = EX_UNAVAILABLE;
388294Seric 		return (-1);
389294Seric 	}
390294Seric 	i = (st >> 8) & 0377;
3912343Seric 	giveresponse(i, TRUE, m);
392294Seric 	return (i);
393294Seric }
394294Seric /*
395294Seric **  GIVERESPONSE -- Interpret an error response from a mailer
396294Seric **
397294Seric **	Parameters:
398294Seric **		stat -- the status code from the mailer (high byte
399294Seric **			only; core dumps must have been taken care of
400294Seric **			already).
401294Seric **		force -- if set, force an error message output, even
402294Seric **			if the mailer seems to like to print its own
403294Seric **			messages.
404294Seric **		m -- the mailer descriptor for this mailer.
405294Seric **
406294Seric **	Returns:
4074082Seric **		none.
408294Seric **
409294Seric **	Side Effects:
4101518Seric **		Errors may be incremented.
411294Seric **		ExitStat may be set.
412294Seric **
413294Seric **	Called By:
414294Seric **		deliver
415294Seric */
416294Seric 
417294Seric giveresponse(stat, force, m)
418294Seric 	int stat;
419294Seric 	int force;
420294Seric 	register struct mailer *m;
421294Seric {
422294Seric 	register char *statmsg;
423294Seric 	extern char *SysExMsg[];
424294Seric 	register int i;
425294Seric 	extern int N_SysEx;
4261624Seric 	extern long MsgSize;
4271624Seric 	char buf[30];
428294Seric 
429294Seric 	i = stat - EX__BASE;
430294Seric 	if (i < 0 || i > N_SysEx)
431294Seric 		statmsg = NULL;
432294Seric 	else
433294Seric 		statmsg = SysExMsg[i];
434294Seric 	if (stat == 0)
4354065Seric 	{
436*4194Seric 		if (bitset(M_LOCAL, m->m_flags))
4374161Seric 			statmsg = "delivered";
4384161Seric 		else
4394161Seric 			statmsg = "queued";
4404065Seric 		if (Verbose)
4414166Seric 			message(Arpa_Info, statmsg);
4424065Seric 	}
443294Seric 	else
444294Seric 	{
4451518Seric 		Errors++;
446294Seric 		if (statmsg == NULL && m->m_badstat != 0)
447294Seric 		{
448294Seric 			stat = m->m_badstat;
449294Seric 			i = stat - EX__BASE;
450294Seric # ifdef DEBUG
451294Seric 			if (i < 0 || i >= N_SysEx)
452294Seric 				syserr("Bad m_badstat %d", stat);
453294Seric 			else
454294Seric # endif DEBUG
455294Seric 			statmsg = SysExMsg[i];
456294Seric 		}
457294Seric 		if (statmsg == NULL)
458294Seric 			usrerr("unknown mailer response %d", stat);
4594065Seric 		else if (force || !bitset(M_QUIET, m->m_flags) || Verbose)
460294Seric 			usrerr("%s", statmsg);
461294Seric 	}
462294Seric 
463294Seric 	/*
464294Seric 	**  Final cleanup.
465294Seric 	**	Log a record of the transaction.  Compute the new
466294Seric 	**	ExitStat -- if we already had an error, stick with
467294Seric 	**	that.
468294Seric 	*/
469294Seric 
4701624Seric 	if (statmsg == NULL)
4711624Seric 	{
4724082Seric 		(void) sprintf(buf, "error %d", stat);
4731624Seric 		statmsg = buf;
4741624Seric 	}
4751624Seric 
476294Seric # ifdef LOG
4772774Seric 	syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg);
478294Seric # endif LOG
4791389Seric 	setstat(stat);
480294Seric }
481294Seric /*
4822898Seric **  PUTMESSAGE -- output a message to the final mailer.
483294Seric **
4842898Seric **	This routine takes care of recreating the header from the
4852898Seric **	in-core copy, etc.
486294Seric **
487294Seric **	Parameters:
4882898Seric **		fp -- file to output onto.
4892898Seric **		m -- a mailer descriptor.
490294Seric **
491294Seric **	Returns:
4922898Seric **		none.
493294Seric **
494294Seric **	Side Effects:
4952898Seric **		The message is written onto fp.
496294Seric */
497294Seric 
4982898Seric putmessage(fp, m)
4992898Seric 	FILE *fp;
5002898Seric 	struct mailer *m;
501294Seric {
5022898Seric 	char buf[BUFSIZ];
5032898Seric 	register int i;
5042898Seric 	HDR *h;
5051828Seric 	register char *p;
5062898Seric 	extern char *arpadate();
5072898Seric 	bool anyheader = FALSE;
5083044Seric 	extern char *capitalize();
509294Seric 
5103186Seric 	/* output "From" line unless supressed */
5113186Seric 	if (!bitset(M_NHDR, m->m_flags))
5123186Seric 		fprintf(fp, "%s\n", FromLine);
5133186Seric 
5143385Seric 	/* output all header lines */
5152898Seric 	for (h = Header; h != NULL; h = h->h_link)
5161828Seric 	{
5173389Seric 		if (bitset(H_DELETE, h->h_flags))
5183385Seric 			continue;
5193389Seric 		if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags))
5203389Seric 			continue;
5213385Seric 		if (bitset(H_DEFAULT, h->h_flags))
5223385Seric 		{
5234082Seric 			(void) expand(h->h_value, buf, &buf[sizeof buf]);
5243385Seric 			p = buf;
5253385Seric 		}
5262898Seric 		else
5273385Seric 			p = h->h_value;
5283389Seric 		if (*p == '\0')
5293389Seric 			continue;
5303385Seric 		fprintf(fp, "%s: %s\n", capitalize(h->h_field), p);
5312898Seric 		h->h_flags |= H_USED;
5322898Seric 		anyheader = TRUE;
5332898Seric 	}
5342898Seric 
5352898Seric 	if (anyheader)
5362898Seric 		fprintf(fp, "\n");
5372898Seric 
5382898Seric 	/* output the body of the message */
5394181Seric 	rewind(TempFile);
5404181Seric 	while (!ferror(fp) && (i = fread(buf, 1, BUFSIZ, TempFile)) > 0)
5414082Seric 		(void) fwrite(buf, 1, i, fp);
5422898Seric 
5434123Seric 	if (ferror(fp) && errno != EPIPE)
544294Seric 	{
5452898Seric 		syserr("putmessage: write error");
546294Seric 		setstat(EX_IOERR);
547294Seric 	}
5484123Seric 	errno = 0;
549294Seric }
550294Seric /*
551294Seric **  MAILFILE -- Send a message to a file.
552294Seric **
553294Seric **	Parameters:
554294Seric **		filename -- the name of the file to send to.
555294Seric **
556294Seric **	Returns:
557294Seric **		The exit code associated with the operation.
558294Seric **
559294Seric **	Side Effects:
560294Seric **		none.
561294Seric **
562294Seric **	Called By:
563294Seric **		deliver
564294Seric */
565294Seric 
566294Seric mailfile(filename)
567294Seric 	char *filename;
568294Seric {
569294Seric 	register FILE *f;
570294Seric 
571294Seric 	f = fopen(filename, "a");
572294Seric 	if (f == NULL)
573294Seric 		return (EX_CANTCREAT);
5744067Seric 
5753186Seric 	putmessage(f, Mailer[1]);
576294Seric 	fputs("\n", f);
5774082Seric 	(void) fclose(f);
578294Seric 	return (EX_OK);
579294Seric }
580