14227346bSdist /*
20942ea6aSbostic  * Copyright (c) 1983 Eric P. Allman
3e70a7521Sbostic  * Copyright (c) 1988 Regents of the University of California.
4e70a7521Sbostic  * All rights reserved.
5e70a7521Sbostic  *
6e70a7521Sbostic  * Redistribution and use in source and binary forms are permitted
70942ea6aSbostic  * provided that the above copyright notice and this paragraph are
80942ea6aSbostic  * duplicated in all such forms and that any documentation,
90942ea6aSbostic  * advertising materials, and other materials related to such
100942ea6aSbostic  * distribution and use acknowledge that the software was developed
110942ea6aSbostic  * by the University of California, Berkeley.  The name of the
120942ea6aSbostic  * University may not be used to endorse or promote products derived
130942ea6aSbostic  * from this software without specific prior written permission.
140942ea6aSbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
150942ea6aSbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
160942ea6aSbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
174227346bSdist  */
184227346bSdist 
194227346bSdist #ifndef lint
20*8f9146b0Srick static char sccsid[] = "@(#)deliver.c	5.29 (Berkeley) 04/16/90";
21e70a7521Sbostic #endif /* not lint */
224227346bSdist 
23911693bfSbostic #include <sendmail.h>
24911693bfSbostic #include <sys/signal.h>
25c77d1c25Seric #include <sys/stat.h>
26f28da541Smiriam #include <netdb.h>
27fccb3f7aSbostic #include <fcntl.h>
28911693bfSbostic #include <errno.h>
29134746fbSeric #ifdef NAMED_BIND
30912a731aSbostic #include <arpa/nameser.h>
31912a731aSbostic #include <resolv.h>
32134746fbSeric #endif
3325a99e2eSeric 
3425a99e2eSeric /*
3513bbc08cSeric **  DELIVER -- Deliver a message to a list of addresses.
3613bbc08cSeric **
3713bbc08cSeric **	This routine delivers to everyone on the same host as the
3813bbc08cSeric **	user on the head of the list.  It is clever about mailers
3913bbc08cSeric **	that don't handle multiple users.  It is NOT guaranteed
4013bbc08cSeric **	that it will deliver to all these addresses however -- so
4113bbc08cSeric **	deliver should be called once for each address on the
4213bbc08cSeric **	list.
4325a99e2eSeric **
4425a99e2eSeric **	Parameters:
45588cad61Seric **		e -- the envelope to deliver.
46c77d1c25Seric **		firstto -- head of the address list to deliver to.
4725a99e2eSeric **
4825a99e2eSeric **	Returns:
4925a99e2eSeric **		zero -- successfully delivered.
5025a99e2eSeric **		else -- some failure, see ExitStat for more info.
5125a99e2eSeric **
5225a99e2eSeric **	Side Effects:
5325a99e2eSeric **		The standard input is passed off to someone.
5425a99e2eSeric */
5525a99e2eSeric 
56588cad61Seric deliver(e, firstto)
57588cad61Seric 	register ENVELOPE *e;
58c77d1c25Seric 	ADDRESS *firstto;
5925a99e2eSeric {
6078442df3Seric 	char *host;			/* host being sent to */
6178442df3Seric 	char *user;			/* user being sent to */
6225a99e2eSeric 	char **pvp;
635dfc646bSeric 	register char **mvp;
6425a99e2eSeric 	register char *p;
65588cad61Seric 	register MAILER *m;		/* mailer for this recipient */
666259796dSeric 	ADDRESS *ctladdr;
67c77d1c25Seric 	register ADDRESS *to = firstto;
68c579ef51Seric 	bool clever = FALSE;		/* running user smtp to this mailer */
69772e6e50Seric 	ADDRESS *tochain = NULL;	/* chain of users in this mailer call */
70911693bfSbostic 	int rcode;		/* response code */
71ee6bf8dfSeric 	char *pv[MAXPV+1];
72ee6bf8dfSeric 	char tobuf[MAXLINE-50];		/* text line of to people */
73ee6bf8dfSeric 	char buf[MAXNAME];
74ee6bf8dfSeric 	char tfrombuf[MAXNAME];		/* translated from person */
75ee6bf8dfSeric 	extern bool checkcompat();
76ee6bf8dfSeric 	extern ADDRESS *getctladdr();
77ee6bf8dfSeric 	extern char *remotename();
7825a99e2eSeric 
7935490626Seric 	errno = 0;
80da2935e1Seric 	if (bitset(QDONTSEND, to->q_flags))
815dfc646bSeric 		return (0);
8225a99e2eSeric 
83134746fbSeric #ifdef NAMED_BIND
84912a731aSbostic 	/* unless interactive, try twice, over a minute */
85912a731aSbostic 	if (OpMode == MD_DAEMON || OpMode == MD_SMTP) {
86912a731aSbostic 		_res.retrans = 30;
87912a731aSbostic 		_res.retry = 2;
88912a731aSbostic 	}
89d4bd8f0eSbostic #endif
90912a731aSbostic 
9151552439Seric 	m = to->q_mailer;
9251552439Seric 	host = to->q_host;
9351552439Seric 
946ef48975Seric 	if (tTd(10, 1))
955dfc646bSeric 		printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n",
9651552439Seric 			m->m_mno, host, to->q_user);
97f3dbc832Seric 
98f3dbc832Seric 	/*
99f3dbc832Seric 	**  If this mailer is expensive, and if we don't want to make
100f3dbc832Seric 	**  connections now, just mark these addresses and return.
101f3dbc832Seric 	**	This is useful if we want to batch connections to
102f3dbc832Seric 	**	reduce load.  This will cause the messages to be
103f3dbc832Seric 	**	queued up, and a daemon will come along to send the
104f3dbc832Seric 	**	messages later.
105f3dbc832Seric 	**		This should be on a per-mailer basis.
106f3dbc832Seric 	*/
107f3dbc832Seric 
10857fc6f17Seric 	if (NoConnect && !QueueRun && bitnset(M_EXPENSIVE, m->m_flags) &&
109317680d6Seric 	    !Verbose)
110f3dbc832Seric 	{
111f3dbc832Seric 		for (; to != NULL; to = to->q_next)
112f4560e80Seric 		{
113f4560e80Seric 			if (bitset(QDONTSEND, to->q_flags) || to->q_mailer != m)
114f4560e80Seric 				continue;
115f3dbc832Seric 			to->q_flags |= QQUEUEUP|QDONTSEND;
116588cad61Seric 			e->e_to = to->q_paddr;
117eb238f8cSeric 			message(Arpa_Info, "queued");
118eb238f8cSeric 			if (LogLevel > 4)
119eb238f8cSeric 				logdelivery("queued");
120f4560e80Seric 		}
121588cad61Seric 		e->e_to = NULL;
122f3dbc832Seric 		return (0);
123f3dbc832Seric 	}
124f3dbc832Seric 
12525a99e2eSeric 	/*
1265dfc646bSeric 	**  Do initial argv setup.
1275dfc646bSeric 	**	Insert the mailer name.  Notice that $x expansion is
1285dfc646bSeric 	**	NOT done on the mailer name.  Then, if the mailer has
1295dfc646bSeric 	**	a picky -f flag, we insert it as appropriate.  This
1305dfc646bSeric 	**	code does not check for 'pv' overflow; this places a
1315dfc646bSeric 	**	manifest lower limit of 4 for MAXPV.
1323bea8136Seric 	**		The from address rewrite is expected to make
1333bea8136Seric 	**		the address relative to the other end.
1345dfc646bSeric 	*/
1355dfc646bSeric 
13678442df3Seric 	/* rewrite from address, using rewriting rules */
1379b6c17a6Seric 	expand("\001f", buf, &buf[sizeof buf - 1], e);
138ee6bf8dfSeric 	(void) strcpy(tfrombuf, remotename(buf, m, TRUE, TRUE));
13978442df3Seric 
140588cad61Seric 	define('g', tfrombuf, e);		/* translated sender address */
141588cad61Seric 	define('h', host, e);			/* to host */
1425dfc646bSeric 	Errors = 0;
1435dfc646bSeric 	pvp = pv;
1445dfc646bSeric 	*pvp++ = m->m_argv[0];
1455dfc646bSeric 
1465dfc646bSeric 	/* insert -f or -r flag as appropriate */
14757fc6f17Seric 	if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags)))
1485dfc646bSeric 	{
14957fc6f17Seric 		if (bitnset(M_FOPT, m->m_flags))
1505dfc646bSeric 			*pvp++ = "-f";
1515dfc646bSeric 		else
1525dfc646bSeric 			*pvp++ = "-r";
1539b6c17a6Seric 		expand("\001g", buf, &buf[sizeof buf - 1], e);
1545dfc646bSeric 		*pvp++ = newstr(buf);
1555dfc646bSeric 	}
1565dfc646bSeric 
1575dfc646bSeric 	/*
1585dfc646bSeric 	**  Append the other fixed parts of the argv.  These run
1595dfc646bSeric 	**  up to the first entry containing "$u".  There can only
1605dfc646bSeric 	**  be one of these, and there are only a few more slots
1615dfc646bSeric 	**  in the pv after it.
1625dfc646bSeric 	*/
1635dfc646bSeric 
1645dfc646bSeric 	for (mvp = m->m_argv; (p = *++mvp) != NULL; )
1655dfc646bSeric 	{
1669b6c17a6Seric 		while ((p = index(p, '\001')) != NULL)
1675dfc646bSeric 			if (*++p == 'u')
1685dfc646bSeric 				break;
1695dfc646bSeric 		if (p != NULL)
1705dfc646bSeric 			break;
1715dfc646bSeric 
1725dfc646bSeric 		/* this entry is safe -- go ahead and process it */
173588cad61Seric 		expand(*mvp, buf, &buf[sizeof buf - 1], e);
1745dfc646bSeric 		*pvp++ = newstr(buf);
1755dfc646bSeric 		if (pvp >= &pv[MAXPV - 3])
1765dfc646bSeric 		{
1775dfc646bSeric 			syserr("Too many parameters to %s before $u", pv[0]);
1785dfc646bSeric 			return (-1);
1795dfc646bSeric 		}
1805dfc646bSeric 	}
181c579ef51Seric 
18233db8731Seric 	/*
18333db8731Seric 	**  If we have no substitution for the user name in the argument
18433db8731Seric 	**  list, we know that we must supply the names otherwise -- and
18533db8731Seric 	**  SMTP is the answer!!
18633db8731Seric 	*/
18733db8731Seric 
1885dfc646bSeric 	if (*mvp == NULL)
189c579ef51Seric 	{
190c579ef51Seric 		/* running SMTP */
1912c7e1b8dSeric # ifdef SMTP
192c579ef51Seric 		clever = TRUE;
193c579ef51Seric 		*pvp = NULL;
1942c7e1b8dSeric # else SMTP
19533db8731Seric 		/* oops!  we don't implement SMTP */
1962c7e1b8dSeric 		syserr("SMTP style mailer");
1972c7e1b8dSeric 		return (EX_SOFTWARE);
1982c7e1b8dSeric # endif SMTP
199c579ef51Seric 	}
2005dfc646bSeric 
2015dfc646bSeric 	/*
2025dfc646bSeric 	**  At this point *mvp points to the argument with $u.  We
2035dfc646bSeric 	**  run through our address list and append all the addresses
2045dfc646bSeric 	**  we can.  If we run out of space, do not fret!  We can
2055dfc646bSeric 	**  always send another copy later.
2065dfc646bSeric 	*/
2075dfc646bSeric 
2085dfc646bSeric 	tobuf[0] = '\0';
209588cad61Seric 	e->e_to = tobuf;
2106259796dSeric 	ctladdr = NULL;
2115dfc646bSeric 	for (; to != NULL; to = to->q_next)
2125dfc646bSeric 	{
2135dfc646bSeric 		/* avoid sending multiple recipients to dumb mailers */
21457fc6f17Seric 		if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags))
2155dfc646bSeric 			break;
2165dfc646bSeric 
2175dfc646bSeric 		/* if already sent or not for this host, don't send */
218da2935e1Seric 		if (bitset(QDONTSEND, to->q_flags) ||
219da2935e1Seric 		    strcmp(to->q_host, host) != 0 ||
220da2935e1Seric 		    to->q_mailer != firstto->q_mailer)
2215dfc646bSeric 			continue;
2226259796dSeric 
2234b22ea87Seric 		/* avoid overflowing tobuf */
224588cad61Seric 		if (sizeof tobuf - (strlen(to->q_paddr) + strlen(tobuf) + 2) < 0)
2254b22ea87Seric 			break;
2264b22ea87Seric 
2276ef48975Seric 		if (tTd(10, 1))
228772e6e50Seric 		{
229772e6e50Seric 			printf("\nsend to ");
230772e6e50Seric 			printaddr(to, FALSE);
231772e6e50Seric 		}
232772e6e50Seric 
2336259796dSeric 		/* compute effective uid/gid when sending */
2347da1035fSeric 		if (to->q_mailer == ProgMailer)
2356259796dSeric 			ctladdr = getctladdr(to);
2366259796dSeric 
2375dfc646bSeric 		user = to->q_user;
238588cad61Seric 		e->e_to = to->q_paddr;
2395dfc646bSeric 		to->q_flags |= QDONTSEND;
2405dfc646bSeric 
2415dfc646bSeric 		/*
2425dfc646bSeric 		**  Check to see that these people are allowed to
2435dfc646bSeric 		**  talk to each other.
2442a6e0786Seric 		*/
2452a6e0786Seric 
24669582d2fSeric 		if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize)
24769582d2fSeric 		{
24869582d2fSeric 			NoReturn = TRUE;
249672bec4aSeric 			usrerr("Message is too large; %ld bytes max", m->m_maxsize);
25069582d2fSeric 			giveresponse(EX_UNAVAILABLE, m, e);
25169582d2fSeric 			continue;
25269582d2fSeric 		}
2532a6e0786Seric 		if (!checkcompat(to))
2545dfc646bSeric 		{
255198d9be0Seric 			giveresponse(EX_UNAVAILABLE, m, e);
2565dfc646bSeric 			continue;
2575dfc646bSeric 		}
2582a6e0786Seric 
2592a6e0786Seric 		/*
2609ec9501bSeric 		**  Strip quote bits from names if the mailer is dumb
2619ec9501bSeric 		**	about them.
26225a99e2eSeric 		*/
26325a99e2eSeric 
26457fc6f17Seric 		if (bitnset(M_STRIPQ, m->m_flags))
26525a99e2eSeric 		{
2669ec9501bSeric 			stripquotes(user, TRUE);
2679ec9501bSeric 			stripquotes(host, TRUE);
2689ec9501bSeric 		}
2699ec9501bSeric 		else
2709ec9501bSeric 		{
2719ec9501bSeric 			stripquotes(user, FALSE);
2729ec9501bSeric 			stripquotes(host, FALSE);
27325a99e2eSeric 		}
27425a99e2eSeric 
275cdb828c5Seric 		/* hack attack -- delivermail compatibility */
276cdb828c5Seric 		if (m == ProgMailer && *user == '|')
277cdb828c5Seric 			user++;
278cdb828c5Seric 
27925a99e2eSeric 		/*
2803efaed6eSeric 		**  If an error message has already been given, don't
2813efaed6eSeric 		**	bother to send to this address.
2823efaed6eSeric 		**
2833efaed6eSeric 		**	>>>>>>>>>> This clause assumes that the local mailer
2843efaed6eSeric 		**	>> NOTE >> cannot do any further aliasing; that
2853efaed6eSeric 		**	>>>>>>>>>> function is subsumed by sendmail.
2863efaed6eSeric 		*/
2873efaed6eSeric 
2886cae517dSeric 		if (bitset(QBADADDR|QQUEUEUP, to->q_flags))
2893efaed6eSeric 			continue;
2903efaed6eSeric 
291f2fec898Seric 		/* save statistics.... */
292588cad61Seric 		markstats(e, to);
293f2fec898Seric 
2943efaed6eSeric 		/*
29525a99e2eSeric 		**  See if this user name is "special".
29625a99e2eSeric 		**	If the user name has a slash in it, assume that this
29751552439Seric 		**	is a file -- send it off without further ado.  Note
29851552439Seric 		**	that this type of addresses is not processed along
29951552439Seric 		**	with the others, so we fudge on the To person.
30025a99e2eSeric 		*/
30125a99e2eSeric 
3027da1035fSeric 		if (m == LocalMailer)
30325a99e2eSeric 		{
304a49f24c0Seric 			if (user[0] == '/')
30525a99e2eSeric 			{
3065826d9d3Seric 				rcode = mailfile(user, getctladdr(to));
307198d9be0Seric 				giveresponse(rcode, m, e);
3085dfc646bSeric 				continue;
30925a99e2eSeric 			}
31025a99e2eSeric 		}
31125a99e2eSeric 
31213bbc08cSeric 		/*
31313bbc08cSeric 		**  Address is verified -- add this user to mailer
31413bbc08cSeric 		**  argv, and add it to the print list of recipients.
31513bbc08cSeric 		*/
31613bbc08cSeric 
317508daeccSeric 		/* link together the chain of recipients */
318508daeccSeric 		to->q_tchain = tochain;
319508daeccSeric 		tochain = to;
320508daeccSeric 
3215dfc646bSeric 		/* create list of users for error messages */
322db8841e9Seric 		(void) strcat(tobuf, ",");
323db8841e9Seric 		(void) strcat(tobuf, to->q_paddr);
324588cad61Seric 		define('u', user, e);		/* to user */
325588cad61Seric 		define('z', to->q_home, e);	/* user's home */
3265dfc646bSeric 
327c579ef51Seric 		/*
328508daeccSeric 		**  Expand out this user into argument list.
329c579ef51Seric 		*/
330c579ef51Seric 
331508daeccSeric 		if (!clever)
332c579ef51Seric 		{
333588cad61Seric 			expand(*mvp, buf, &buf[sizeof buf - 1], e);
3345dfc646bSeric 			*pvp++ = newstr(buf);
3355dfc646bSeric 			if (pvp >= &pv[MAXPV - 2])
3365dfc646bSeric 			{
3375dfc646bSeric 				/* allow some space for trailing parms */
3385dfc646bSeric 				break;
3395dfc646bSeric 			}
3405dfc646bSeric 		}
341c579ef51Seric 	}
3425dfc646bSeric 
343145b49b1Seric 	/* see if any addresses still exist */
344145b49b1Seric 	if (tobuf[0] == '\0')
345c579ef51Seric 	{
346588cad61Seric 		define('g', (char *) NULL, e);
347145b49b1Seric 		return (0);
348c579ef51Seric 	}
349145b49b1Seric 
3505dfc646bSeric 	/* print out messages as full list */
35163780dbdSeric 	e->e_to = tobuf + 1;
3525dfc646bSeric 
3535dfc646bSeric 	/*
3545dfc646bSeric 	**  Fill out any parameters after the $u parameter.
3555dfc646bSeric 	*/
3565dfc646bSeric 
357c579ef51Seric 	while (!clever && *++mvp != NULL)
3585dfc646bSeric 	{
359588cad61Seric 		expand(*mvp, buf, &buf[sizeof buf - 1], e);
3605dfc646bSeric 		*pvp++ = newstr(buf);
3615dfc646bSeric 		if (pvp >= &pv[MAXPV])
3625dfc646bSeric 			syserr("deliver: pv overflow after $u for %s", pv[0]);
3635dfc646bSeric 	}
3645dfc646bSeric 	*pvp++ = NULL;
3655dfc646bSeric 
36625a99e2eSeric 	/*
36725a99e2eSeric 	**  Call the mailer.
3686328bdf7Seric 	**	The argument vector gets built, pipes
36925a99e2eSeric 	**	are created as necessary, and we fork & exec as
3706328bdf7Seric 	**	appropriate.
371c579ef51Seric 	**	If we are running SMTP, we just need to clean up.
37225a99e2eSeric 	*/
37325a99e2eSeric 
3746259796dSeric 	if (ctladdr == NULL)
375588cad61Seric 		ctladdr = &e->e_from;
376134746fbSeric #ifdef NAMED_BIND
377912a731aSbostic 	_res.options &= ~(RES_DEFNAMES | RES_DNSRCH);		/* XXX */
378134746fbSeric #endif
3792c7e1b8dSeric #ifdef SMTP
380134746fbSeric 	if (clever)
381134746fbSeric 	{
382911693bfSbostic 		rcode = EX_OK;
383134746fbSeric #ifdef NAMED_BIND
3840877bd4eSbostic 		if (host[0] && host[0] != '[')
385134746fbSeric 		{
3860877bd4eSbostic 			expand("\001w", buf, &buf[sizeof(buf) - 1], e);
387134746fbSeric 			Nmx = getmxrr(host, MxHosts, buf, &rcode);
388134746fbSeric 		}
389134746fbSeric 		else
390134746fbSeric #endif
391134746fbSeric 		{
39260bcc2d9Sbostic 			Nmx = 1;
39360bcc2d9Sbostic 			MxHosts[0] = host;
394134746fbSeric 		}
395134746fbSeric 		if (Nmx >= 0)
396134746fbSeric 		{
397912a731aSbostic 			message(Arpa_Info, "Connecting to %s (%s)...",
398912a731aSbostic 			    MxHosts[0], m->m_name);
399912a731aSbostic 			if ((rcode = smtpinit(m, pv)) == EX_OK) {
400ded0d3daSkarels 				register char *t = tobuf;
401ded0d3daSkarels 				register int i;
402ded0d3daSkarels 
403588cad61Seric 				/* send the recipient list */
40463780dbdSeric 				tobuf[0] = '\0';
405911693bfSbostic 				for (to = tochain; to; to = to->q_tchain) {
40663780dbdSeric 					e->e_to = to->q_paddr;
407912a731aSbostic 					if ((i = smtprcpt(to, m)) != EX_OK) {
40883b7ddc9Seric 						markfailure(e, to, i);
409198d9be0Seric 						giveresponse(i, m, e);
41063780dbdSeric 					}
411911693bfSbostic 					else {
412911693bfSbostic 						*t++ = ',';
413911693bfSbostic 						for (p = to->q_paddr; *p; *t++ = *p++);
414588cad61Seric 					}
415588cad61Seric 				}
416588cad61Seric 
41763780dbdSeric 				/* now send the data */
41863780dbdSeric 				if (tobuf[0] == '\0')
41963780dbdSeric 					e->e_to = NULL;
420911693bfSbostic 				else {
42163780dbdSeric 					e->e_to = tobuf + 1;
42277b52738Seric 					rcode = smtpdata(m, e);
42363780dbdSeric 				}
42463780dbdSeric 
42563780dbdSeric 				/* now close the connection */
426a294c4b0Seric 				smtpquit(m);
42763780dbdSeric 			}
428c579ef51Seric 		}
429912a731aSbostic 	}
430c579ef51Seric 	else
431911693bfSbostic #endif /* SMTP */
432a05b3449Sbostic 	{
433912a731aSbostic 		message(Arpa_Info, "Connecting to %s (%s)...", host, m->m_name);
43477b52738Seric 		rcode = sendoff(e, m, pv, ctladdr);
435a05b3449Sbostic 	}
436134746fbSeric #ifdef NAMED_BIND
437912a731aSbostic 	_res.options |= RES_DEFNAMES | RES_DNSRCH;	/* XXX */
438134746fbSeric #endif
4395dfc646bSeric 
440c77d1c25Seric 	/*
44163780dbdSeric 	**  Do final status disposal.
44263780dbdSeric 	**	We check for something in tobuf for the SMTP case.
443c77d1c25Seric 	**	If we got a temporary failure, arrange to queue the
444c77d1c25Seric 	**		addressees.
445c77d1c25Seric 	*/
446c77d1c25Seric 
44763780dbdSeric 	if (tobuf[0] != '\0')
448198d9be0Seric 		giveresponse(rcode, m, e);
44963780dbdSeric 	if (rcode != EX_OK)
450772e6e50Seric 		for (to = tochain; to != NULL; to = to->q_tchain)
45183b7ddc9Seric 			markfailure(e, to, rcode);
452c77d1c25Seric 
45335490626Seric 	errno = 0;
454588cad61Seric 	define('g', (char *) NULL, e);
4555826d9d3Seric 	return (rcode);
45625a99e2eSeric }
4575dfc646bSeric /*
45883b7ddc9Seric **  MARKFAILURE -- mark a failure on a specific address.
45983b7ddc9Seric **
46083b7ddc9Seric **	Parameters:
46183b7ddc9Seric **		e -- the envelope we are sending.
46283b7ddc9Seric **		q -- the address to mark.
46383b7ddc9Seric **		rcode -- the code signifying the particular failure.
46483b7ddc9Seric **
46583b7ddc9Seric **	Returns:
46683b7ddc9Seric **		none.
46783b7ddc9Seric **
46883b7ddc9Seric **	Side Effects:
46983b7ddc9Seric **		marks the address (and possibly the envelope) with the
47083b7ddc9Seric **			failure so that an error will be returned or
47183b7ddc9Seric **			the message will be queued, as appropriate.
47283b7ddc9Seric */
47383b7ddc9Seric 
47483b7ddc9Seric markfailure(e, q, rcode)
47583b7ddc9Seric 	register ENVELOPE *e;
47683b7ddc9Seric 	register ADDRESS *q;
47783b7ddc9Seric 	int rcode;
47883b7ddc9Seric {
47983b7ddc9Seric 	if (rcode == EX_OK)
48083b7ddc9Seric 		return;
48183b7ddc9Seric 	else if (rcode != EX_TEMPFAIL)
48283b7ddc9Seric 		q->q_flags |= QBADADDR;
48383b7ddc9Seric 	else if (curtime() > e->e_ctime + TimeOut)
48483b7ddc9Seric 	{
48583b7ddc9Seric 		extern char *pintvl();
486198d9be0Seric 		char buf[MAXLINE];
48783b7ddc9Seric 
48883b7ddc9Seric 		if (!bitset(EF_TIMEOUT, e->e_flags))
489198d9be0Seric 		{
490198d9be0Seric 			(void) sprintf(buf, "Cannot send message for %s",
49183b7ddc9Seric 				pintvl(TimeOut, FALSE));
492198d9be0Seric 			if (e->e_message != NULL)
493198d9be0Seric 				free(e->e_message);
494198d9be0Seric 			e->e_message = newstr(buf);
495198d9be0Seric 			message(Arpa_Info, buf);
496198d9be0Seric 		}
49783b7ddc9Seric 		q->q_flags |= QBADADDR;
49883b7ddc9Seric 		e->e_flags |= EF_TIMEOUT;
49983b7ddc9Seric 	}
50083b7ddc9Seric 	else
50183b7ddc9Seric 		q->q_flags |= QQUEUEUP;
50283b7ddc9Seric }
50383b7ddc9Seric /*
50432d19d43Seric **  DOFORK -- do a fork, retrying a couple of times on failure.
50532d19d43Seric **
50632d19d43Seric **	This MUST be a macro, since after a vfork we are running
50732d19d43Seric **	two processes on the same stack!!!
50832d19d43Seric **
50932d19d43Seric **	Parameters:
51032d19d43Seric **		none.
51132d19d43Seric **
51232d19d43Seric **	Returns:
51332d19d43Seric **		From a macro???  You've got to be kidding!
51432d19d43Seric **
51532d19d43Seric **	Side Effects:
51632d19d43Seric **		Modifies the ==> LOCAL <== variable 'pid', leaving:
51732d19d43Seric **			pid of child in parent, zero in child.
51832d19d43Seric **			-1 on unrecoverable error.
51932d19d43Seric **
52032d19d43Seric **	Notes:
52132d19d43Seric **		I'm awfully sorry this looks so awful.  That's
52232d19d43Seric **		vfork for you.....
52332d19d43Seric */
52432d19d43Seric 
52532d19d43Seric # define NFORKTRIES	5
5264300ddf0Seric # ifdef VMUNIX
52732d19d43Seric # define XFORK	vfork
5284300ddf0Seric # else VMUNIX
52932d19d43Seric # define XFORK	fork
5304300ddf0Seric # endif VMUNIX
53132d19d43Seric 
53232d19d43Seric # define DOFORK(fORKfN) \
53332d19d43Seric {\
53432d19d43Seric 	register int i;\
53532d19d43Seric \
53611799049Seric 	for (i = NFORKTRIES; --i >= 0; )\
53732d19d43Seric 	{\
53832d19d43Seric 		pid = fORKfN();\
53932d19d43Seric 		if (pid >= 0)\
54032d19d43Seric 			break;\
54111799049Seric 		if (i > 0)\
5426c4635f6Seric 			sleep((unsigned) NFORKTRIES - i);\
54332d19d43Seric 	}\
54432d19d43Seric }
54532d19d43Seric /*
5462ed72599Seric **  DOFORK -- simple fork interface to DOFORK.
5472ed72599Seric **
5482ed72599Seric **	Parameters:
5492ed72599Seric **		none.
5502ed72599Seric **
5512ed72599Seric **	Returns:
5522ed72599Seric **		pid of child in parent.
5532ed72599Seric **		zero in child.
5542ed72599Seric **		-1 on error.
5552ed72599Seric **
5562ed72599Seric **	Side Effects:
5572ed72599Seric **		returns twice, once in parent and once in child.
5582ed72599Seric */
5592ed72599Seric 
5602ed72599Seric dofork()
5612ed72599Seric {
5622ed72599Seric 	register int pid;
5632ed72599Seric 
5642ed72599Seric 	DOFORK(fork);
5652ed72599Seric 	return (pid);
5662ed72599Seric }
5672ed72599Seric /*
5685dfc646bSeric **  SENDOFF -- send off call to mailer & collect response.
5695dfc646bSeric **
5705dfc646bSeric **	Parameters:
571588cad61Seric **		e -- the envelope to mail.
5725dfc646bSeric **		m -- mailer descriptor.
5735dfc646bSeric **		pvp -- parameter vector to send to it.
5746259796dSeric **		ctladdr -- an address pointer controlling the
5756259796dSeric **			user/groupid etc. of the mailer.
5765dfc646bSeric **
5775dfc646bSeric **	Returns:
5785dfc646bSeric **		exit status of mailer.
5795dfc646bSeric **
5805dfc646bSeric **	Side Effects:
5815dfc646bSeric **		none.
5825dfc646bSeric */
583912a731aSbostic static
58477b52738Seric sendoff(e, m, pvp, ctladdr)
585588cad61Seric 	register ENVELOPE *e;
586588cad61Seric 	MAILER *m;
5875dfc646bSeric 	char **pvp;
5886259796dSeric 	ADDRESS *ctladdr;
5895dfc646bSeric {
590c579ef51Seric 	auto FILE *mfile;
591c579ef51Seric 	auto FILE *rfile;
5925dfc646bSeric 	register int i;
593c579ef51Seric 	int pid;
594c579ef51Seric 
595c579ef51Seric 	/*
596c579ef51Seric 	**  Create connection to mailer.
597c579ef51Seric 	*/
598c579ef51Seric 
599c579ef51Seric 	pid = openmailer(m, pvp, ctladdr, FALSE, &mfile, &rfile);
600c579ef51Seric 	if (pid < 0)
601c579ef51Seric 		return (-1);
602c579ef51Seric 
603c579ef51Seric 	/*
604c579ef51Seric 	**  Format and send message.
605c579ef51Seric 	*/
606c579ef51Seric 
60777b52738Seric 	putfromline(mfile, m);
60877b52738Seric 	(*e->e_puthdr)(mfile, m, e);
60977b52738Seric 	putline("\n", mfile, m);
61077b52738Seric 	(*e->e_putbody)(mfile, m, e);
611c579ef51Seric 	(void) fclose(mfile);
612c579ef51Seric 
613c579ef51Seric 	i = endmailer(pid, pvp[0]);
614bc6e2962Seric 
615bc6e2962Seric 	/* arrange a return receipt if requested */
61657fc6f17Seric 	if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags))
617bc6e2962Seric 	{
618588cad61Seric 		e->e_flags |= EF_SENDRECEIPT;
619bc6e2962Seric 		/* do we want to send back more info? */
620bc6e2962Seric 	}
621bc6e2962Seric 
622c579ef51Seric 	return (i);
623c579ef51Seric }
624c579ef51Seric /*
625c579ef51Seric **  ENDMAILER -- Wait for mailer to terminate.
626c579ef51Seric **
627c579ef51Seric **	We should never get fatal errors (e.g., segmentation
628c579ef51Seric **	violation), so we report those specially.  For other
629c579ef51Seric **	errors, we choose a status message (into statmsg),
630c579ef51Seric **	and if it represents an error, we print it.
631c579ef51Seric **
632c579ef51Seric **	Parameters:
633c579ef51Seric **		pid -- pid of mailer.
634c579ef51Seric **		name -- name of mailer (for error messages).
635c579ef51Seric **
636c579ef51Seric **	Returns:
637c579ef51Seric **		exit code of mailer.
638c579ef51Seric **
639c579ef51Seric **	Side Effects:
640c579ef51Seric **		none.
641c579ef51Seric */
642c579ef51Seric 
643c579ef51Seric endmailer(pid, name)
644c579ef51Seric 	int pid;
645c579ef51Seric 	char *name;
646c579ef51Seric {
647588cad61Seric 	int st;
648c579ef51Seric 
64933db8731Seric 	/* in the IPC case there is nothing to wait for */
65033db8731Seric 	if (pid == 0)
65133db8731Seric 		return (EX_OK);
65233db8731Seric 
65333db8731Seric 	/* wait for the mailer process to die and collect status */
654588cad61Seric 	st = waitfor(pid);
655588cad61Seric 	if (st == -1)
65678de67c1Seric 	{
657588cad61Seric 		syserr("endmailer %s: wait", name);
658588cad61Seric 		return (EX_SOFTWARE);
659c579ef51Seric 	}
66033db8731Seric 
66133db8731Seric 	/* see if it died a horrid death */
662c579ef51Seric 	if ((st & 0377) != 0)
663c579ef51Seric 	{
6645f73204aSeric 		syserr("mailer %s died with signal %o", name, st);
6655f73204aSeric 		ExitStat = EX_TEMPFAIL;
6665f73204aSeric 		return (EX_TEMPFAIL);
667c579ef51Seric 	}
66833db8731Seric 
66933db8731Seric 	/* normal death -- return status */
670588cad61Seric 	st = (st >> 8) & 0377;
671588cad61Seric 	return (st);
672c579ef51Seric }
673c579ef51Seric /*
674c579ef51Seric **  OPENMAILER -- open connection to mailer.
675c579ef51Seric **
676c579ef51Seric **	Parameters:
677c579ef51Seric **		m -- mailer descriptor.
678c579ef51Seric **		pvp -- parameter vector to pass to mailer.
679c579ef51Seric **		ctladdr -- controlling address for user.
680c579ef51Seric **		clever -- create a full duplex connection.
681c579ef51Seric **		pmfile -- pointer to mfile (to mailer) connection.
682c579ef51Seric **		prfile -- pointer to rfile (from mailer) connection.
683c579ef51Seric **
684c579ef51Seric **	Returns:
68533db8731Seric **		pid of mailer ( > 0 ).
686c579ef51Seric **		-1 on error.
68733db8731Seric **		zero on an IPC connection.
688c579ef51Seric **
689c579ef51Seric **	Side Effects:
690c579ef51Seric **		creates a mailer in a subprocess.
691c579ef51Seric */
692c579ef51Seric 
693c579ef51Seric openmailer(m, pvp, ctladdr, clever, pmfile, prfile)
694588cad61Seric 	MAILER *m;
695c579ef51Seric 	char **pvp;
696c579ef51Seric 	ADDRESS *ctladdr;
697c579ef51Seric 	bool clever;
698c579ef51Seric 	FILE **pmfile;
699c579ef51Seric 	FILE **prfile;
700c579ef51Seric {
7015dfc646bSeric 	int pid;
702f8952a83Seric 	int mpvect[2];
703c579ef51Seric 	int rpvect[2];
7045dfc646bSeric 	FILE *mfile;
705c579ef51Seric 	FILE *rfile;
7065dfc646bSeric 	extern FILE *fdopen();
7075dfc646bSeric 
7086ef48975Seric 	if (tTd(11, 1))
7095dfc646bSeric 	{
7108c57e552Seric 		printf("openmailer:");
7115dfc646bSeric 		printav(pvp);
7125dfc646bSeric 	}
71335490626Seric 	errno = 0;
7145dfc646bSeric 
715ef66a9d0Seric 	CurHostName = m->m_mailer;
716ef66a9d0Seric 
71733db8731Seric 	/*
71833db8731Seric 	**  Deal with the special case of mail handled through an IPC
71933db8731Seric 	**  connection.
72033db8731Seric 	**	In this case we don't actually fork.  We must be
72133db8731Seric 	**	running SMTP for this to work.  We will return a
72233db8731Seric 	**	zero pid to indicate that we are running IPC.
723e7c1bd78Seric 	**  We also handle a debug version that just talks to stdin/out.
72433db8731Seric 	*/
72533db8731Seric 
726e7c1bd78Seric 	/* check for Local Person Communication -- not for mortals!!! */
727e7c1bd78Seric 	if (strcmp(m->m_mailer, "[LPC]") == 0)
728e7c1bd78Seric 	{
729e7c1bd78Seric 		*pmfile = stdout;
730e7c1bd78Seric 		*prfile = stdin;
731e7c1bd78Seric 		return (0);
732e7c1bd78Seric 	}
733e7c1bd78Seric 
73433db8731Seric 	if (strcmp(m->m_mailer, "[IPC]") == 0)
73533db8731Seric 	{
7365f73204aSeric #ifdef HOSTINFO
7375f73204aSeric 		register STAB *st;
7385f73204aSeric 		extern STAB *stab();
7395f73204aSeric #endif HOSTINFO
740588cad61Seric #ifdef DAEMON
741ebc61751Sbloom 		register int i, j;
7421277f9a8Seric 		register u_short port;
74333db8731Seric 
744ef66a9d0Seric 		CurHostName = pvp[1];
74533db8731Seric 		if (!clever)
74633db8731Seric 			syserr("non-clever IPC");
74793b6e3cfSeric 		if (pvp[2] != NULL)
7481277f9a8Seric 			port = atoi(pvp[2]);
74993b6e3cfSeric 		else
7501277f9a8Seric 			port = 0;
751f1853fd7Seric 		for (j = 0; j < Nmx; j++)
752ebc61751Sbloom 		{
753f1853fd7Seric 			CurHostName = MxHosts[j];
7545f73204aSeric #ifdef HOSTINFO
7555f73204aSeric 		/* see if we have already determined that this host is fried */
756f1853fd7Seric 			st = stab(MxHosts[j], ST_HOST, ST_FIND);
757912a731aSbostic 			if (st == NULL || st->s_host.ho_exitstat == EX_OK) {
758912a731aSbostic 				if (j > 1)
759912a731aSbostic 					message(Arpa_Info,
760912a731aSbostic 					    "Connecting to %s (%s)...",
761912a731aSbostic 					    MxHosts[j], m->m_name);
762f1853fd7Seric 				i = makeconnection(MxHosts[j], port, pmfile, prfile);
763912a731aSbostic 			}
7645f73204aSeric 			else
765ef66a9d0Seric 			{
7665f73204aSeric 				i = st->s_host.ho_exitstat;
767ef66a9d0Seric 				errno = st->s_host.ho_errno;
768ef66a9d0Seric 			}
7695f73204aSeric #else HOSTINFO
770f1853fd7Seric 			i = makeconnection(MxHosts[j], port, pmfile, prfile);
7715f73204aSeric #endif HOSTINFO
77233db8731Seric 			if (i != EX_OK)
773ed854c7bSeric 			{
7745f73204aSeric #ifdef HOSTINFO
7755f73204aSeric 				/* enter status of this host */
7765f73204aSeric 				if (st == NULL)
777f1853fd7Seric 					st = stab(MxHosts[j], ST_HOST, ST_ENTER);
7785f73204aSeric 				st->s_host.ho_exitstat = i;
7795f73204aSeric 				st->s_host.ho_errno = errno;
7805f73204aSeric #endif HOSTINFO
781ed854c7bSeric 				ExitStat = i;
782ebc61751Sbloom 				continue;
783ed854c7bSeric 			}
78433db8731Seric 			else
78533db8731Seric 				return (0);
786ebc61751Sbloom 		}
787ebc61751Sbloom 		return (-1);
788588cad61Seric #else DAEMON
789588cad61Seric 		syserr("openmailer: no IPC");
790588cad61Seric 		return (-1);
79133db8731Seric #endif DAEMON
792588cad61Seric 	}
79333db8731Seric 
7946328bdf7Seric 	/* create a pipe to shove the mail through */
795f8952a83Seric 	if (pipe(mpvect) < 0)
79625a99e2eSeric 	{
797588cad61Seric 		syserr("openmailer: pipe (to mailer)");
79825a99e2eSeric 		return (-1);
79925a99e2eSeric 	}
800c579ef51Seric 
8012c7e1b8dSeric #ifdef SMTP
802c579ef51Seric 	/* if this mailer speaks smtp, create a return pipe */
803c579ef51Seric 	if (clever && pipe(rpvect) < 0)
804c579ef51Seric 	{
805588cad61Seric 		syserr("openmailer: pipe (from mailer)");
806c579ef51Seric 		(void) close(mpvect[0]);
807c579ef51Seric 		(void) close(mpvect[1]);
808c579ef51Seric 		return (-1);
809c579ef51Seric 	}
8102c7e1b8dSeric #endif SMTP
811c579ef51Seric 
81233db8731Seric 	/*
81333db8731Seric 	**  Actually fork the mailer process.
81433db8731Seric 	**	DOFORK is clever about retrying.
8156984bfddSeric 	**
8166984bfddSeric 	**	Dispose of SIGCHLD signal catchers that may be laying
8176984bfddSeric 	**	around so that endmail will get it.
81833db8731Seric 	*/
81933db8731Seric 
8209a6a5f55Seric 	if (CurEnv->e_xfp != NULL)
8219a6a5f55Seric 		(void) fflush(CurEnv->e_xfp);		/* for debugging */
822588cad61Seric 	(void) fflush(stdout);
8236984bfddSeric # ifdef SIGCHLD
8246984bfddSeric 	(void) signal(SIGCHLD, SIG_DFL);
8256984bfddSeric # endif SIGCHLD
82632d19d43Seric 	DOFORK(XFORK);
827f129ec7dSeric 	/* pid is set by DOFORK */
82825a99e2eSeric 	if (pid < 0)
82925a99e2eSeric 	{
83033db8731Seric 		/* failure */
831588cad61Seric 		syserr("openmailer: cannot fork");
832f8952a83Seric 		(void) close(mpvect[0]);
833f8952a83Seric 		(void) close(mpvect[1]);
834588cad61Seric #ifdef SMTP
835c579ef51Seric 		if (clever)
836c579ef51Seric 		{
837c579ef51Seric 			(void) close(rpvect[0]);
838c579ef51Seric 			(void) close(rpvect[1]);
839c579ef51Seric 		}
840588cad61Seric #endif SMTP
84125a99e2eSeric 		return (-1);
84225a99e2eSeric 	}
84325a99e2eSeric 	else if (pid == 0)
84425a99e2eSeric 	{
84513088b9fSeric 		int i;
8465f73204aSeric 		extern int DtableSize;
84713088b9fSeric 
84825a99e2eSeric 		/* child -- set up input & exec mailer */
84903ab8e55Seric 		/* make diagnostic output be standard output */
8508f0e7860Seric 		(void) signal(SIGINT, SIG_IGN);
8518f0e7860Seric 		(void) signal(SIGHUP, SIG_IGN);
8520984da9fSeric 		(void) signal(SIGTERM, SIG_DFL);
853f8952a83Seric 
854f8952a83Seric 		/* arrange to filter standard & diag output of command */
855c579ef51Seric 		if (clever)
856c579ef51Seric 		{
857c579ef51Seric 			(void) close(rpvect[0]);
858c579ef51Seric 			(void) close(1);
859c579ef51Seric 			(void) dup(rpvect[1]);
860c579ef51Seric 			(void) close(rpvect[1]);
861c579ef51Seric 		}
862276723a8Seric 		else if (OpMode == MD_SMTP || HoldErrs)
863f8952a83Seric 		{
864588cad61Seric 			/* put mailer output in transcript */
865f8952a83Seric 			(void) close(1);
8669a6a5f55Seric 			(void) dup(fileno(CurEnv->e_xfp));
867f8952a83Seric 		}
868db8841e9Seric 		(void) close(2);
869db8841e9Seric 		(void) dup(1);
870f8952a83Seric 
871f8952a83Seric 		/* arrange to get standard input */
872f8952a83Seric 		(void) close(mpvect[1]);
873db8841e9Seric 		(void) close(0);
874f8952a83Seric 		if (dup(mpvect[0]) < 0)
87525a99e2eSeric 		{
87625a99e2eSeric 			syserr("Cannot dup to zero!");
877a590b978Seric 			_exit(EX_OSERR);
87825a99e2eSeric 		}
879f8952a83Seric 		(void) close(mpvect[0]);
88057fc6f17Seric 		if (!bitnset(M_RESTR, m->m_flags))
8810984da9fSeric 		{
88253e3fa05Seric 			if (ctladdr == NULL || ctladdr->q_uid == 0)
883e36b99e2Seric 			{
884e36b99e2Seric 				(void) setgid(DefGid);
885e36b99e2Seric 				(void) setuid(DefUid);
886e36b99e2Seric 			}
887e36b99e2Seric 			else
88869f29479Seric 			{
889e36b99e2Seric 				(void) setgid(ctladdr->q_gid);
890e36b99e2Seric 				(void) setuid(ctladdr->q_uid);
89169f29479Seric 			}
8920984da9fSeric 		}
893588cad61Seric 
89413088b9fSeric 		/* arrange for all the files to be closed */
895fccb3f7aSbostic 		for (i = 3; i < DtableSize; i++) {
896fccb3f7aSbostic 			register int j;
897fccb3f7aSbostic 			if ((j = fcntl(i, F_GETFD, 0)) != -1)
898fccb3f7aSbostic 				(void)fcntl(i, F_SETFD, j|1);
899fccb3f7aSbostic 		}
90033db8731Seric 
90133db8731Seric 		/* try to execute the mailer */
9025df317aaSeric 		execve(m->m_mailer, pvp, UserEnviron);
90313088b9fSeric 		syserr("Cannot exec %s", m->m_mailer);
9045f73204aSeric 		if (m == LocalMailer || errno == EIO || errno == EAGAIN ||
9055f73204aSeric 		    errno == ENOMEM || errno == EPROCLIM)
90655f33c03Seric 			_exit(EX_TEMPFAIL);
90755f33c03Seric 		else
908a590b978Seric 			_exit(EX_UNAVAILABLE);
90925a99e2eSeric 	}
91025a99e2eSeric 
911f8952a83Seric 	/*
912c579ef51Seric 	**  Set up return value.
913f8952a83Seric 	*/
914f8952a83Seric 
915f8952a83Seric 	(void) close(mpvect[0]);
916f8952a83Seric 	mfile = fdopen(mpvect[1], "w");
917c579ef51Seric 	if (clever)
91825a99e2eSeric 	{
919c579ef51Seric 		(void) close(rpvect[1]);
920c579ef51Seric 		rfile = fdopen(rpvect[0], "r");
92125a99e2eSeric 	}
922c579ef51Seric 
923c579ef51Seric 	*pmfile = mfile;
924c579ef51Seric 	*prfile = rfile;
925c579ef51Seric 
926c579ef51Seric 	return (pid);
92725a99e2eSeric }
92825a99e2eSeric /*
92925a99e2eSeric **  GIVERESPONSE -- Interpret an error response from a mailer
93025a99e2eSeric **
93125a99e2eSeric **	Parameters:
93225a99e2eSeric **		stat -- the status code from the mailer (high byte
93325a99e2eSeric **			only; core dumps must have been taken care of
93425a99e2eSeric **			already).
93525a99e2eSeric **		m -- the mailer descriptor for this mailer.
93625a99e2eSeric **
93725a99e2eSeric **	Returns:
938db8841e9Seric **		none.
93925a99e2eSeric **
94025a99e2eSeric **	Side Effects:
941c1f9df2cSeric **		Errors may be incremented.
94225a99e2eSeric **		ExitStat may be set.
94325a99e2eSeric */
94425a99e2eSeric 
945198d9be0Seric giveresponse(stat, m, e)
94625a99e2eSeric 	int stat;
947588cad61Seric 	register MAILER *m;
948198d9be0Seric 	ENVELOPE *e;
94925a99e2eSeric {
95025a99e2eSeric 	register char *statmsg;
95125a99e2eSeric 	extern char *SysExMsg[];
95225a99e2eSeric 	register int i;
953d4bd8f0eSbostic 	extern int N_SysEx;
954d4bd8f0eSbostic #ifdef NAMED_BIND
955d4bd8f0eSbostic 	extern int h_errno;
956d4bd8f0eSbostic #endif
957198d9be0Seric 	char buf[MAXLINE];
95825a99e2eSeric 
9597d1fc79dSeric #ifdef lint
9607d1fc79dSeric 	if (m == NULL)
9617d1fc79dSeric 		return;
9627d1fc79dSeric #endif lint
9637d1fc79dSeric 
96413bbc08cSeric 	/*
96513bbc08cSeric 	**  Compute status message from code.
96613bbc08cSeric 	*/
96713bbc08cSeric 
96825a99e2eSeric 	i = stat - EX__BASE;
969588cad61Seric 	if (stat == 0)
970588cad61Seric 		statmsg = "250 Sent";
971588cad61Seric 	else if (i < 0 || i > N_SysEx)
972588cad61Seric 	{
973588cad61Seric 		(void) sprintf(buf, "554 unknown mailer error %d", stat);
974588cad61Seric 		stat = EX_UNAVAILABLE;
975588cad61Seric 		statmsg = buf;
976588cad61Seric 	}
977198d9be0Seric 	else if (stat == EX_TEMPFAIL)
978198d9be0Seric 	{
9798557d168Seric 		(void) strcpy(buf, SysExMsg[i]);
980d4bd8f0eSbostic #ifdef NAMED_BIND
981f28da541Smiriam 		if (h_errno == TRY_AGAIN)
982f28da541Smiriam 		{
983f28da541Smiriam 			extern char *errstring();
984f28da541Smiriam 
985f28da541Smiriam 			statmsg = errstring(h_errno+MAX_ERRNO);
986f28da541Smiriam 		}
987f28da541Smiriam 		else
988d4bd8f0eSbostic #endif
989f28da541Smiriam 		{
9908557d168Seric 			if (errno != 0)
991198d9be0Seric 			{
99287c9b3e7Seric 				extern char *errstring();
9938557d168Seric 
994d87e85f3Seric 				statmsg = errstring(errno);
995d87e85f3Seric 			}
996d87e85f3Seric 			else
997d87e85f3Seric 			{
998d87e85f3Seric #ifdef SMTP
999d87e85f3Seric 				extern char SmtpError[];
1000d87e85f3Seric 
1001d87e85f3Seric 				statmsg = SmtpError;
1002d87e85f3Seric #else SMTP
1003d87e85f3Seric 				statmsg = NULL;
1004d87e85f3Seric #endif SMTP
1005d87e85f3Seric 			}
1006f28da541Smiriam 		}
1007d87e85f3Seric 		if (statmsg != NULL && statmsg[0] != '\0')
1008d87e85f3Seric 		{
100987c9b3e7Seric 			(void) strcat(buf, ": ");
1010d87e85f3Seric 			(void) strcat(buf, statmsg);
10118557d168Seric 		}
1012198d9be0Seric 		statmsg = buf;
1013198d9be0Seric 	}
101425a99e2eSeric 	else
1015d87e85f3Seric 	{
101625a99e2eSeric 		statmsg = SysExMsg[i];
1017d87e85f3Seric 	}
1018588cad61Seric 
1019588cad61Seric 	/*
1020588cad61Seric 	**  Print the message as appropriate
1021588cad61Seric 	*/
1022588cad61Seric 
1023198d9be0Seric 	if (stat == EX_OK || stat == EX_TEMPFAIL)
10245826d9d3Seric 		message(Arpa_Info, &statmsg[4]);
102525a99e2eSeric 	else
102625a99e2eSeric 	{
1027c1f9df2cSeric 		Errors++;
10285826d9d3Seric 		usrerr(statmsg);
102925a99e2eSeric 	}
103025a99e2eSeric 
103125a99e2eSeric 	/*
103225a99e2eSeric 	**  Final cleanup.
103325a99e2eSeric 	**	Log a record of the transaction.  Compute the new
103425a99e2eSeric 	**	ExitStat -- if we already had an error, stick with
103525a99e2eSeric 	**	that.
103625a99e2eSeric 	*/
103725a99e2eSeric 
103861f5a1d4Seric 	if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2))
1039eb238f8cSeric 		logdelivery(&statmsg[4]);
1040eb238f8cSeric 
1041eb238f8cSeric 	if (stat != EX_TEMPFAIL)
1042eb238f8cSeric 		setstat(stat);
1043198d9be0Seric 	if (stat != EX_OK)
1044198d9be0Seric 	{
1045198d9be0Seric 		if (e->e_message != NULL)
1046198d9be0Seric 			free(e->e_message);
1047198d9be0Seric 		e->e_message = newstr(&statmsg[4]);
1048198d9be0Seric 	}
10498557d168Seric 	errno = 0;
1050d4bd8f0eSbostic #ifdef NAMED_BIND
1051f28da541Smiriam 	h_errno = 0;
1052d4bd8f0eSbostic #endif
1053eb238f8cSeric }
1054eb238f8cSeric /*
1055eb238f8cSeric **  LOGDELIVERY -- log the delivery in the system log
1056eb238f8cSeric **
1057eb238f8cSeric **	Parameters:
1058eb238f8cSeric **		stat -- the message to print for the status
1059eb238f8cSeric **
1060eb238f8cSeric **	Returns:
1061eb238f8cSeric **		none
1062eb238f8cSeric **
1063eb238f8cSeric **	Side Effects:
1064eb238f8cSeric **		none
1065eb238f8cSeric */
1066eb238f8cSeric 
1067eb238f8cSeric logdelivery(stat)
1068eb238f8cSeric 	char *stat;
10695cf56be3Seric {
10705cf56be3Seric 	extern char *pintvl();
10715cf56be3Seric 
1072eb238f8cSeric # ifdef LOG
10735cf56be3Seric 	syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id,
1074eb238f8cSeric 	       CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat);
107525a99e2eSeric # endif LOG
107625a99e2eSeric }
107725a99e2eSeric /*
107851552439Seric **  PUTFROMLINE -- output a UNIX-style from line (or whatever)
107925a99e2eSeric **
108051552439Seric **	This can be made an arbitrary message separator by changing $l
108151552439Seric **
10829b6c17a6Seric **	One of the ugliest hacks seen by human eyes is contained herein:
10839b6c17a6Seric **	UUCP wants those stupid "remote from <host>" lines.  Why oh why
10849b6c17a6Seric **	does a well-meaning programmer such as myself have to deal with
10859b6c17a6Seric **	this kind of antique garbage????
108625a99e2eSeric **
108725a99e2eSeric **	Parameters:
108851552439Seric **		fp -- the file to output to.
108951552439Seric **		m -- the mailer describing this entry.
109025a99e2eSeric **
109125a99e2eSeric **	Returns:
109251552439Seric **		none
109325a99e2eSeric **
109425a99e2eSeric **	Side Effects:
109551552439Seric **		outputs some text to fp.
109625a99e2eSeric */
109725a99e2eSeric 
109877b52738Seric putfromline(fp, m)
109951552439Seric 	register FILE *fp;
110051552439Seric 	register MAILER *m;
110125a99e2eSeric {
11029b6c17a6Seric 	char *template = "\001l\n";
110351552439Seric 	char buf[MAXLINE];
110425a99e2eSeric 
110557fc6f17Seric 	if (bitnset(M_NHDR, m->m_flags))
110651552439Seric 		return;
110713bbc08cSeric 
11082c7e1b8dSeric # ifdef UGLYUUCP
110957fc6f17Seric 	if (bitnset(M_UGLYUUCP, m->m_flags))
111074b6e67bSeric 	{
1111ea09d6edSeric 		char *bang;
1112ea09d6edSeric 		char xbuf[MAXLINE];
111374b6e67bSeric 
11149b6c17a6Seric 		expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);
1115ea09d6edSeric 		bang = index(buf, '!');
111674b6e67bSeric 		if (bang == NULL)
1117ea09d6edSeric 			syserr("No ! in UUCP! (%s)", buf);
111874b6e67bSeric 		else
1119588cad61Seric 		{
1120ea09d6edSeric 			*bang++ = '\0';
11219b6c17a6Seric 			(void) sprintf(xbuf, "From %s  \001d remote from %s\n", bang, buf);
1122ea09d6edSeric 			template = xbuf;
112374b6e67bSeric 		}
1124588cad61Seric 	}
11252c7e1b8dSeric # endif UGLYUUCP
1126ea09d6edSeric 	expand(template, buf, &buf[sizeof buf - 1], CurEnv);
112777b52738Seric 	putline(buf, fp, m);
1128bc6e2962Seric }
1129bc6e2962Seric /*
113051552439Seric **  PUTBODY -- put the body of a message.
113151552439Seric **
113251552439Seric **	Parameters:
113351552439Seric **		fp -- file to output onto.
113477b52738Seric **		m -- a mailer descriptor to control output format.
11359a6a5f55Seric **		e -- the envelope to put out.
113651552439Seric **
113751552439Seric **	Returns:
113851552439Seric **		none.
113951552439Seric **
114051552439Seric **	Side Effects:
114151552439Seric **		The message is written onto fp.
114251552439Seric */
114351552439Seric 
114477b52738Seric putbody(fp, m, e)
114551552439Seric 	FILE *fp;
1146588cad61Seric 	MAILER *m;
11479a6a5f55Seric 	register ENVELOPE *e;
114851552439Seric {
114977b52738Seric 	char buf[MAXLINE];
115051552439Seric 
115151552439Seric 	/*
115251552439Seric 	**  Output the body of the message
115351552439Seric 	*/
115451552439Seric 
11559a6a5f55Seric 	if (e->e_dfp == NULL)
115651552439Seric 	{
11579a6a5f55Seric 		if (e->e_df != NULL)
11589a6a5f55Seric 		{
11599a6a5f55Seric 			e->e_dfp = fopen(e->e_df, "r");
11609a6a5f55Seric 			if (e->e_dfp == NULL)
1161*8f9146b0Srick 				syserr("putbody: Cannot open %s for %s from %s",
1162*8f9146b0Srick 				e->e_df, e->e_to, e->e_from);
11639a6a5f55Seric 		}
11649a6a5f55Seric 		else
116577b52738Seric 			putline("<<< No Message Collected >>>", fp, m);
11669a6a5f55Seric 	}
11679a6a5f55Seric 	if (e->e_dfp != NULL)
11689a6a5f55Seric 	{
11699a6a5f55Seric 		rewind(e->e_dfp);
117077b52738Seric 		while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL)
117124fc8aeeSeric 		{
117224fc8aeeSeric 			if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) &&
117324fc8aeeSeric 			    strncmp(buf, "From", 4) == 0)
11743462ad9eSeric 				(void) putc('>', fp);
117577b52738Seric 			putline(buf, fp, m);
117624fc8aeeSeric 		}
117751552439Seric 
11789a6a5f55Seric 		if (ferror(e->e_dfp))
117951552439Seric 		{
118051552439Seric 			syserr("putbody: read error");
118151552439Seric 			ExitStat = EX_IOERR;
118251552439Seric 		}
118351552439Seric 	}
118451552439Seric 
118551552439Seric 	(void) fflush(fp);
118651552439Seric 	if (ferror(fp) && errno != EPIPE)
118751552439Seric 	{
118851552439Seric 		syserr("putbody: write error");
118951552439Seric 		ExitStat = EX_IOERR;
119051552439Seric 	}
119151552439Seric 	errno = 0;
119225a99e2eSeric }
119325a99e2eSeric /*
119425a99e2eSeric **  MAILFILE -- Send a message to a file.
119525a99e2eSeric **
1196f129ec7dSeric **	If the file has the setuid/setgid bits set, but NO execute
1197f129ec7dSeric **	bits, sendmail will try to become the owner of that file
1198f129ec7dSeric **	rather than the real user.  Obviously, this only works if
1199f129ec7dSeric **	sendmail runs as root.
1200f129ec7dSeric **
1201588cad61Seric **	This could be done as a subordinate mailer, except that it
1202588cad61Seric **	is used implicitly to save messages in ~/dead.letter.  We
1203588cad61Seric **	view this as being sufficiently important as to include it
1204588cad61Seric **	here.  For example, if the system is dying, we shouldn't have
1205588cad61Seric **	to create another process plus some pipes to save the message.
1206588cad61Seric **
120725a99e2eSeric **	Parameters:
120825a99e2eSeric **		filename -- the name of the file to send to.
12096259796dSeric **		ctladdr -- the controlling address header -- includes
12106259796dSeric **			the userid/groupid to be when sending.
121125a99e2eSeric **
121225a99e2eSeric **	Returns:
121325a99e2eSeric **		The exit code associated with the operation.
121425a99e2eSeric **
121525a99e2eSeric **	Side Effects:
121625a99e2eSeric **		none.
121725a99e2eSeric */
121825a99e2eSeric 
12196259796dSeric mailfile(filename, ctladdr)
122025a99e2eSeric 	char *filename;
12216259796dSeric 	ADDRESS *ctladdr;
122225a99e2eSeric {
122325a99e2eSeric 	register FILE *f;
122432d19d43Seric 	register int pid;
1225*8f9146b0Srick 	ENVELOPE *e = CurEnv;
122625a99e2eSeric 
122732d19d43Seric 	/*
122832d19d43Seric 	**  Fork so we can change permissions here.
122932d19d43Seric 	**	Note that we MUST use fork, not vfork, because of
123032d19d43Seric 	**	the complications of calling subroutines, etc.
123132d19d43Seric 	*/
123232d19d43Seric 
123332d19d43Seric 	DOFORK(fork);
123432d19d43Seric 
123532d19d43Seric 	if (pid < 0)
123632d19d43Seric 		return (EX_OSERR);
123732d19d43Seric 	else if (pid == 0)
123832d19d43Seric 	{
123932d19d43Seric 		/* child -- actually write to file */
1240f129ec7dSeric 		struct stat stb;
1241f129ec7dSeric 
12420984da9fSeric 		(void) signal(SIGINT, SIG_DFL);
12430984da9fSeric 		(void) signal(SIGHUP, SIG_DFL);
12440984da9fSeric 		(void) signal(SIGTERM, SIG_DFL);
12453462ad9eSeric 		(void) umask(OldUmask);
1246f129ec7dSeric 		if (stat(filename, &stb) < 0)
124724447f54Seric 		{
124824447f54Seric 			errno = 0;
1249e6e1265fSeric 			stb.st_mode = 0666;
125024447f54Seric 		}
1251f129ec7dSeric 		if (bitset(0111, stb.st_mode))
1252f129ec7dSeric 			exit(EX_CANTCREAT);
125303827b5fSeric 		if (ctladdr == NULL)
1254*8f9146b0Srick 			ctladdr = &e->e_from;
1255*8f9146b0Srick 		/* we have to open the dfile BEFORE setuid */
1256*8f9146b0Srick 		if (e->e_dfp == NULL &&  e->e_df != NULL)
1257*8f9146b0Srick 		{
1258*8f9146b0Srick 			e->e_dfp = fopen(e->e_df, "r");
1259*8f9146b0Srick 			if (e->e_dfp == NULL) {
1260*8f9146b0Srick 				syserr("mailfile: Cannot open %s for %s from %s",
1261*8f9146b0Srick 				e->e_df, e->e_to, e->e_from);
1262*8f9146b0Srick 			}
1263*8f9146b0Srick 		}
1264*8f9146b0Srick 
1265f129ec7dSeric 		if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0)
1266e36b99e2Seric 		{
1267e36b99e2Seric 			if (ctladdr->q_uid == 0)
1268e36b99e2Seric 				(void) setgid(DefGid);
1269e36b99e2Seric 			else
12706259796dSeric 				(void) setgid(ctladdr->q_gid);
1271e36b99e2Seric 		}
1272f129ec7dSeric 		if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0)
1273e36b99e2Seric 		{
1274e36b99e2Seric 			if (ctladdr->q_uid == 0)
1275e36b99e2Seric 				(void) setuid(DefUid);
1276e36b99e2Seric 			else
12776259796dSeric 				(void) setuid(ctladdr->q_uid);
1278e36b99e2Seric 		}
127927628d59Seric 		f = dfopen(filename, "a");
128025a99e2eSeric 		if (f == NULL)
128132d19d43Seric 			exit(EX_CANTCREAT);
128225a99e2eSeric 
128377b52738Seric 		putfromline(f, ProgMailer);
128477b52738Seric 		(*CurEnv->e_puthdr)(f, ProgMailer, CurEnv);
128577b52738Seric 		putline("\n", f, ProgMailer);
128677b52738Seric 		(*CurEnv->e_putbody)(f, ProgMailer, CurEnv);
128777b52738Seric 		putline("\n", f, ProgMailer);
1288db8841e9Seric 		(void) fclose(f);
128932d19d43Seric 		(void) fflush(stdout);
1290e36b99e2Seric 
129127628d59Seric 		/* reset ISUID & ISGID bits for paranoid systems */
1292c77d1c25Seric 		(void) chmod(filename, (int) stb.st_mode);
129332d19d43Seric 		exit(EX_OK);
129413bbc08cSeric 		/*NOTREACHED*/
129532d19d43Seric 	}
129632d19d43Seric 	else
129732d19d43Seric 	{
129832d19d43Seric 		/* parent -- wait for exit status */
1299588cad61Seric 		int st;
130032d19d43Seric 
1301588cad61Seric 		st = waitfor(pid);
1302588cad61Seric 		if ((st & 0377) != 0)
1303588cad61Seric 			return (EX_UNAVAILABLE);
1304588cad61Seric 		else
1305588cad61Seric 			return ((st >> 8) & 0377);
1306*8f9146b0Srick 		/*NOTREACHED*/
130732d19d43Seric 	}
130825a99e2eSeric }
1309ea4dc939Seric /*
1310ea4dc939Seric **  SENDALL -- actually send all the messages.
1311ea4dc939Seric **
1312ea4dc939Seric **	Parameters:
13130c52a0b3Seric **		e -- the envelope to send.
13147b95031aSeric **		mode -- the delivery mode to use.  If SM_DEFAULT, use
13157b95031aSeric **			the current SendMode.
1316ea4dc939Seric **
1317ea4dc939Seric **	Returns:
1318ea4dc939Seric **		none.
1319ea4dc939Seric **
1320ea4dc939Seric **	Side Effects:
1321ea4dc939Seric **		Scans the send lists and sends everything it finds.
13220c52a0b3Seric **		Delivers any appropriate error messages.
1323276723a8Seric **		If we are running in a non-interactive mode, takes the
1324276723a8Seric **			appropriate action.
1325ea4dc939Seric */
1326ea4dc939Seric 
1327276723a8Seric sendall(e, mode)
13280c52a0b3Seric 	ENVELOPE *e;
1329276723a8Seric 	char mode;
1330ea4dc939Seric {
1331e77e673fSeric 	register ADDRESS *q;
133214a8ed7aSeric 	bool oldverbose;
1333276723a8Seric 	int pid;
1334*8f9146b0Srick 	FILE *lockfp, *queueup();
1335ea4dc939Seric 
13367b95031aSeric 	/* determine actual delivery mode */
13377b95031aSeric 	if (mode == SM_DEFAULT)
13387b95031aSeric 	{
13395f73204aSeric 		extern bool shouldqueue();
13407b95031aSeric 
13415f73204aSeric 		if (shouldqueue(e->e_msgpriority))
13427b95031aSeric 			mode = SM_QUEUE;
13437b95031aSeric 		else
13447b95031aSeric 			mode = SendMode;
13457b95031aSeric 	}
13467b95031aSeric 
1347df864a8fSeric 	if (tTd(13, 1))
1348772e6e50Seric 	{
1349276723a8Seric 		printf("\nSENDALL: mode %c, sendqueue:\n", mode);
13500c52a0b3Seric 		printaddr(e->e_sendqueue, TRUE);
1351772e6e50Seric 	}
1352ea4dc939Seric 
13530c52a0b3Seric 	/*
1354276723a8Seric 	**  Do any preprocessing necessary for the mode we are running.
1355588cad61Seric 	**	Check to make sure the hop count is reasonable.
1356588cad61Seric 	**	Delete sends to the sender in mailing lists.
1357276723a8Seric 	*/
1358276723a8Seric 
1359588cad61Seric 	CurEnv = e;
1360276723a8Seric 
1361588cad61Seric 	if (e->e_hopcount > MAXHOP)
1362276723a8Seric 	{
1363*8f9146b0Srick 		errno = 0;
1364*8f9146b0Srick 		syserr("sendall: too many hops %d (%d max): from %s, to %s",
1365*8f9146b0Srick 			e->e_hopcount, MAXHOP, e->e_from, e->e_to);
1366588cad61Seric 		return;
1367588cad61Seric 	}
1368588cad61Seric 
1369588cad61Seric 	if (!MeToo)
1370276723a8Seric 	{
1371f3d6c55cSeric 		extern ADDRESS *recipient();
1372f3d6c55cSeric 
1373588cad61Seric 		e->e_from.q_flags |= QDONTSEND;
1374f3d6c55cSeric 		(void) recipient(&e->e_from, &e->e_sendqueue);
1375276723a8Seric 	}
1376588cad61Seric 
1377588cad61Seric # ifdef QUEUE
1378b254bcb6Seric 	if ((mode == SM_QUEUE || mode == SM_FORK ||
1379b254bcb6Seric 	     (mode != SM_VERIFY && SuperSafe)) &&
1380b254bcb6Seric 	    !bitset(EF_INQUEUE, e->e_flags))
1381*8f9146b0Srick 		lockfp = queueup(e, TRUE, mode == SM_QUEUE);
1382276723a8Seric #endif QUEUE
1383276723a8Seric 
1384276723a8Seric 	oldverbose = Verbose;
1385276723a8Seric 	switch (mode)
1386276723a8Seric 	{
1387276723a8Seric 	  case SM_VERIFY:
1388276723a8Seric 		Verbose = TRUE;
1389276723a8Seric 		break;
1390276723a8Seric 
1391276723a8Seric 	  case SM_QUEUE:
1392b254bcb6Seric 		e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE;
1393276723a8Seric 		return;
1394276723a8Seric 
1395276723a8Seric 	  case SM_FORK:
13969a6a5f55Seric 		if (e->e_xfp != NULL)
13979a6a5f55Seric 			(void) fflush(e->e_xfp);
1398276723a8Seric 		pid = fork();
1399276723a8Seric 		if (pid < 0)
1400276723a8Seric 		{
1401276723a8Seric 			mode = SM_DELIVER;
1402276723a8Seric 			break;
1403276723a8Seric 		}
1404276723a8Seric 		else if (pid > 0)
1405a6fce3d8Seric 		{
1406a6fce3d8Seric 			/* be sure we leave the temp files to our child */
1407b254bcb6Seric 			e->e_id = e->e_df = NULL;
1408*8f9146b0Srick 			if (lockfp != NULL)
1409*8f9146b0Srick 				(void) fclose(lockfp);
1410276723a8Seric 			return;
1411a6fce3d8Seric 		}
1412276723a8Seric 
1413276723a8Seric 		/* double fork to avoid zombies */
1414276723a8Seric 		if (fork() > 0)
1415276723a8Seric 			exit(EX_OK);
1416276723a8Seric 
1417a6fce3d8Seric 		/* be sure we are immune from the terminal */
1418769e215aSeric 		disconnect(FALSE);
1419a6fce3d8Seric 
1420276723a8Seric 		break;
1421276723a8Seric 	}
1422276723a8Seric 
1423276723a8Seric 	/*
14240c52a0b3Seric 	**  Run through the list and send everything.
14250c52a0b3Seric 	*/
14260c52a0b3Seric 
14270c52a0b3Seric 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
1428ea4dc939Seric 	{
1429276723a8Seric 		if (mode == SM_VERIFY)
1430ea4dc939Seric 		{
1431a6fce3d8Seric 			e->e_to = q->q_paddr;
1432e77e673fSeric 			if (!bitset(QDONTSEND|QBADADDR, q->q_flags))
1433ea4dc939Seric 				message(Arpa_Info, "deliverable");
1434ea4dc939Seric 		}
1435ea4dc939Seric 		else
1436588cad61Seric 			(void) deliver(e, q);
1437ea4dc939Seric 	}
143814a8ed7aSeric 	Verbose = oldverbose;
14390c52a0b3Seric 
14400c52a0b3Seric 	/*
14410c52a0b3Seric 	**  Now run through and check for errors.
14420c52a0b3Seric 	*/
14430c52a0b3Seric 
1444*8f9146b0Srick 	if (mode == SM_VERIFY) {
1445*8f9146b0Srick 		if (lockfp != NULL)
1446*8f9146b0Srick 			(void) fclose(lockfp);
14470c52a0b3Seric 		return;
1448*8f9146b0Srick 	}
14490c52a0b3Seric 
14500c52a0b3Seric 	for (q = e->e_sendqueue; q != NULL; q = q->q_next)
14510c52a0b3Seric 	{
14520c52a0b3Seric 		register ADDRESS *qq;
14530c52a0b3Seric 
1454df864a8fSeric 		if (tTd(13, 3))
1455df864a8fSeric 		{
1456df864a8fSeric 			printf("Checking ");
1457df864a8fSeric 			printaddr(q, FALSE);
1458df864a8fSeric 		}
1459df864a8fSeric 
1460b254bcb6Seric 		/* only send errors if the message failed */
1461b254bcb6Seric 		if (!bitset(QBADADDR, q->q_flags))
1462b254bcb6Seric 			continue;
14630c52a0b3Seric 
14640c52a0b3Seric 		/* we have an address that failed -- find the parent */
14650c52a0b3Seric 		for (qq = q; qq != NULL; qq = qq->q_alias)
14660c52a0b3Seric 		{
14670c52a0b3Seric 			char obuf[MAXNAME + 6];
14680c52a0b3Seric 			extern char *aliaslookup();
14690c52a0b3Seric 
14700c52a0b3Seric 			/* we can only have owners for local addresses */
147157fc6f17Seric 			if (!bitnset(M_LOCAL, qq->q_mailer->m_flags))
14720c52a0b3Seric 				continue;
14730c52a0b3Seric 
14740c52a0b3Seric 			/* see if the owner list exists */
14750c52a0b3Seric 			(void) strcpy(obuf, "owner-");
1476cec031e3Seric 			if (strncmp(qq->q_user, "owner-", 6) == 0)
1477cec031e3Seric 				(void) strcat(obuf, "owner");
1478cec031e3Seric 			else
14790c52a0b3Seric 				(void) strcat(obuf, qq->q_user);
14800c52a0b3Seric 			if (aliaslookup(obuf) == NULL)
14810c52a0b3Seric 				continue;
14820c52a0b3Seric 
1483df864a8fSeric 			if (tTd(13, 4))
1484df864a8fSeric 				printf("Errors to %s\n", obuf);
1485df864a8fSeric 
14860c52a0b3Seric 			/* owner list exists -- add it to the error queue */
1487e3e4ed86Seric 			sendtolist(obuf, (ADDRESS *) NULL, &e->e_errorqueue);
148853e3fa05Seric 			ErrorMode = EM_MAIL;
14890c52a0b3Seric 			break;
14900c52a0b3Seric 		}
14910c52a0b3Seric 
14920c52a0b3Seric 		/* if we did not find an owner, send to the sender */
14937455aa0bSeric 		if (qq == NULL && bitset(QBADADDR, q->q_flags))
1494e3e4ed86Seric 			sendtolist(e->e_from.q_paddr, qq, &e->e_errorqueue);
14950c52a0b3Seric 	}
1496276723a8Seric 
1497*8f9146b0Srick 	/* this removes the lock on the file */
1498*8f9146b0Srick 	if (lockfp != NULL)
1499*8f9146b0Srick 		(void) fclose(lockfp);
1500*8f9146b0Srick 
1501276723a8Seric 	if (mode == SM_FORK)
1502276723a8Seric 		finis();
15030c52a0b3Seric }
1504