1/*
2 * Copyright (c) 1998-2003, 2006, 2012, 2013 Proofpoint, Inc. and its suppliers.
3 *	All rights reserved.
4 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5 * Copyright (c) 1988, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * By using this file, you agree to the terms and conditions set
9 * forth in the LICENSE file which can be found at the top level of
10 * the sendmail distribution.
11 *
12 */
13
14#include <sendmail.h>
15
16SM_RCSID("@(#)$Id: savemail.c,v 8.319 2013-11-22 20:51:56 ca Exp $")
17
18static bool	errbody __P((MCI *, ENVELOPE *, char *));
19static bool	pruneroute __P((char *));
20
21/*
22**  SAVEMAIL -- Save mail on error
23**
24**	If mailing back errors, mail it back to the originator
25**	together with an error message; otherwise, just put it in
26**	dead.letter in the user's home directory (if he exists on
27**	this machine).
28**
29**	Parameters:
30**		e -- the envelope containing the message in error.
31**		sendbody -- if true, also send back the body of the
32**			message; otherwise just send the header.
33**
34**	Returns:
35**		true if savemail panic'ed, (i.e., the data file should
36**		be preserved by dropenvelope())
37**
38**	Side Effects:
39**		Saves the letter, by writing or mailing it back to the
40**		sender, or by putting it in dead.letter in her home
41**		directory.
42*/
43
44/* defines for state machine */
45#define ESM_REPORT		0	/* report to sender's terminal */
46#define ESM_MAIL		1	/* mail back to sender */
47#define ESM_QUIET		2	/* mail has already been returned */
48#define ESM_DEADLETTER		3	/* save in ~/dead.letter */
49#define ESM_POSTMASTER		4	/* return to postmaster */
50#define ESM_DEADLETTERDROP	5	/* save in DeadLetterDrop */
51#define ESM_PANIC		6	/* call loseqfile() */
52#define ESM_DONE		7	/* message is successfully delivered */
53
54bool
55savemail(e, sendbody)
56	register ENVELOPE *e;
57	bool sendbody;
58{
59	register SM_FILE_T *fp;
60	bool panic = false;
61	int state;
62	auto ADDRESS *q = NULL;
63	register char *p;
64	MCI mcibuf;
65	int flags;
66	long sff;
67	char buf[MAXLINE + 1];
68	char dlbuf[MAXPATHLEN];
69	SM_MBDB_T user;
70
71
72	if (tTd(6, 1))
73	{
74		sm_dprintf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n  e_from=",
75			e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
76			ExitStat);
77		printaddr(sm_debug_file(), &e->e_from, false);
78	}
79
80	if (e->e_id == NULL)
81	{
82		/* can't return a message with no id */
83		return panic;
84	}
85
86	/*
87	**  In the unhappy event we don't know who to return the mail
88	**  to, make someone up.
89	*/
90
91	if (e->e_from.q_paddr == NULL)
92	{
93		e->e_sender = "Postmaster";
94		if (parseaddr(e->e_sender, &e->e_from,
95			      RF_COPYPARSE|RF_SENDERADDR,
96			      '\0', NULL, e, false) == NULL)
97		{
98			syserr("553 5.3.5 Cannot parse Postmaster!");
99			finis(true, true, EX_SOFTWARE);
100		}
101	}
102	e->e_to = NULL;
103
104	/*
105	**  Basic state machine.
106	**
107	**	This machine runs through the following states:
108	**
109	**	ESM_QUIET	Errors have already been printed iff the
110	**			sender is local.
111	**	ESM_REPORT	Report directly to the sender's terminal.
112	**	ESM_MAIL	Mail response to the sender.
113	**	ESM_DEADLETTER	Save response in ~/dead.letter.
114	**	ESM_POSTMASTER	Mail response to the postmaster.
115	**	ESM_DEADLETTERDROP
116	**			If DeadLetterDrop set, save it there.
117	**	ESM_PANIC	Save response anywhere possible.
118	*/
119
120	/* determine starting state */
121	switch (e->e_errormode)
122	{
123	  case EM_WRITE:
124		state = ESM_REPORT;
125		break;
126
127	  case EM_BERKNET:
128	  case EM_MAIL:
129		state = ESM_MAIL;
130		break;
131
132	  case EM_PRINT:
133	  case '\0':
134		state = ESM_QUIET;
135		break;
136
137	  case EM_QUIET:
138		/* no need to return anything at all */
139		return panic;
140
141	  default:
142		syserr("554 5.3.0 savemail: bogus errormode x%x",
143		       e->e_errormode);
144		state = ESM_MAIL;
145		break;
146	}
147
148	/* if this is already an error response, send to postmaster */
149	if (bitset(EF_RESPONSE, e->e_flags))
150	{
151		if (e->e_parent != NULL &&
152		    bitset(EF_RESPONSE, e->e_parent->e_flags))
153		{
154			/* got an error sending a response -- can it */
155			return panic;
156		}
157		state = ESM_POSTMASTER;
158	}
159
160	while (state != ESM_DONE)
161	{
162		if (tTd(6, 5))
163			sm_dprintf("  state %d\n", state);
164
165		switch (state)
166		{
167		  case ESM_QUIET:
168			if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags))
169				state = ESM_DEADLETTER;
170			else
171				state = ESM_MAIL;
172			break;
173
174		  case ESM_REPORT:
175
176			/*
177			**  If the user is still logged in on the same terminal,
178			**  then write the error messages back to hir (sic).
179			*/
180
181#if USE_TTYPATH
182			p = ttypath();
183#else
184			p = NULL;
185#endif
186
187			if (p == NULL || sm_io_reopen(SmFtStdio,
188						      SM_TIME_DEFAULT,
189						      p, SM_IO_WRONLY, NULL,
190						      smioout) == NULL)
191			{
192				state = ESM_MAIL;
193				break;
194			}
195
196			expand("\201n", buf, sizeof(buf), e);
197			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
198					     "\r\nMessage from %s...\r\n", buf);
199			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
200					     "Errors occurred while sending mail.\r\n");
201			if (e->e_xfp != NULL)
202			{
203				(void) bfrewind(e->e_xfp);
204				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
205						     "Transcript follows:\r\n");
206				while (sm_io_fgets(e->e_xfp, SM_TIME_DEFAULT,
207						   buf, sizeof(buf)) >= 0 &&
208				       !sm_io_error(smioout))
209					(void) sm_io_fputs(smioout,
210							   SM_TIME_DEFAULT,
211							   buf);
212			}
213			else
214			{
215				syserr("Cannot open %s",
216				       queuename(e, XSCRPT_LETTER));
217				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
218						     "Transcript of session is unavailable.\r\n");
219			}
220			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
221					     "Original message will be saved in dead.letter.\r\n");
222			state = ESM_DEADLETTER;
223			break;
224
225		  case ESM_MAIL:
226			/*
227			**  If mailing back, do it.
228			**	Throw away all further output.  Don't alias,
229			**	since this could cause loops, e.g., if joe
230			**	mails to joe@x, and for some reason the network
231			**	for @x is down, then the response gets sent to
232			**	joe@x, which gives a response, etc.  Also force
233			**	the mail to be delivered even if a version of
234			**	it has already been sent to the sender.
235			**
236			**  If this is a configuration or local software
237			**	error, send to the local postmaster as well,
238			**	since the originator can't do anything
239			**	about it anyway.  Note that this is a full
240			**	copy of the message (intentionally) so that
241			**	the Postmaster can forward things along.
242			*/
243
244			if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
245			{
246				(void) sendtolist("postmaster", NULLADDR,
247						  &e->e_errorqueue, 0, e);
248			}
249			if (!emptyaddr(&e->e_from))
250			{
251				char from[TOBUFSIZE];
252
253				if (sm_strlcpy(from, e->e_from.q_paddr,
254						sizeof(from)) >= sizeof(from))
255				{
256					state = ESM_POSTMASTER;
257					break;
258				}
259
260				if (!DontPruneRoutes)
261					(void) pruneroute(from);
262
263				(void) sendtolist(from, NULLADDR,
264						  &e->e_errorqueue, 0, e);
265			}
266
267			/*
268			**  Deliver a non-delivery report to the
269			**  Postmaster-designate (not necessarily
270			**  Postmaster).  This does not include the
271			**  body of the message, for privacy reasons.
272			**  You really shouldn't need this.
273			*/
274
275			e->e_flags |= EF_PM_NOTIFY;
276
277			/* check to see if there are any good addresses */
278			for (q = e->e_errorqueue; q != NULL; q = q->q_next)
279			{
280				if (QS_IS_SENDABLE(q->q_state))
281					break;
282			}
283			if (q == NULL)
284			{
285				/* this is an error-error */
286				state = ESM_POSTMASTER;
287				break;
288			}
289			if (returntosender(e->e_message, e->e_errorqueue,
290					   sendbody ? RTSF_SEND_BODY
291						    : RTSF_NO_BODY,
292					   e) == 0)
293			{
294				state = ESM_DONE;
295				break;
296			}
297
298			/* didn't work -- return to postmaster */
299			state = ESM_POSTMASTER;
300			break;
301
302		  case ESM_POSTMASTER:
303			/*
304			**  Similar to previous case, but to system postmaster.
305			*/
306
307			q = NULL;
308			expand(DoubleBounceAddr, buf, sizeof(buf), e);
309
310			/*
311			**  Just drop it on the floor if DoubleBounceAddr
312			**  expands to an empty string.
313			*/
314
315			if (*buf == '\0')
316			{
317				state = ESM_DONE;
318				break;
319			}
320			if (sendtolist(buf, NULLADDR, &q, 0, e) <= 0)
321			{
322				syserr("553 5.3.0 cannot parse %s!", buf);
323				ExitStat = EX_SOFTWARE;
324				state = ESM_DEADLETTERDROP;
325				break;
326			}
327			flags = RTSF_PM_BOUNCE;
328			if (sendbody)
329				flags |= RTSF_SEND_BODY;
330			if (returntosender(e->e_message, q, flags, e) == 0)
331			{
332				state = ESM_DONE;
333				break;
334			}
335
336			/* didn't work -- last resort */
337			state = ESM_DEADLETTERDROP;
338			break;
339
340		  case ESM_DEADLETTER:
341			/*
342			**  Save the message in dead.letter.
343			**	If we weren't mailing back, and the user is
344			**	local, we should save the message in
345			**	~/dead.letter so that the poor person doesn't
346			**	have to type it over again -- and we all know
347			**	what poor typists UNIX users are.
348			*/
349
350			p = NULL;
351			if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
352			{
353				if (e->e_from.q_home != NULL)
354					p = e->e_from.q_home;
355				else if (sm_mbdb_lookup(e->e_from.q_user, &user)
356					 == EX_OK &&
357					 *user.mbdb_homedir != '\0')
358					p = user.mbdb_homedir;
359			}
360			if (p == NULL || e->e_dfp == NULL)
361			{
362				/* no local directory or no data file */
363				state = ESM_MAIL;
364				break;
365			}
366
367			/* we have a home directory; write dead.letter */
368			macdefine(&e->e_macro, A_TEMP, 'z', p);
369
370			/* get the sender for the UnixFromLine */
371			p = macvalue('g', e);
372			macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
373
374			expand("\201z/dead.letter", dlbuf, sizeof(dlbuf), e);
375			sff = SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
376			if (RealUid == 0)
377				sff |= SFF_ROOTOK;
378			e->e_to = dlbuf;
379			if (writable(dlbuf, NULL, sff) &&
380			    mailfile(dlbuf, FileMailer, NULL, sff, e) == EX_OK)
381			{
382				int oldverb = Verbose;
383
384				if (OpMode != MD_DAEMON && OpMode != MD_SMTP)
385					Verbose = 1;
386				if (Verbose > 0)
387					message("Saved message in %s", dlbuf);
388				Verbose = oldverb;
389				macdefine(&e->e_macro, A_PERM, 'g', p);
390				state = ESM_DONE;
391				break;
392			}
393			macdefine(&e->e_macro, A_PERM, 'g', p);
394			state = ESM_MAIL;
395			break;
396
397		  case ESM_DEADLETTERDROP:
398			/*
399			**  Log the mail in DeadLetterDrop file.
400			*/
401
402			if (e->e_class < 0)
403			{
404				state = ESM_DONE;
405				break;
406			}
407
408			if ((SafeFileEnv != NULL && SafeFileEnv[0] != '\0') ||
409			    DeadLetterDrop == NULL ||
410			    DeadLetterDrop[0] == '\0')
411			{
412				state = ESM_PANIC;
413				break;
414			}
415
416			sff = SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT|SFF_MUSTOWN;
417			if (!writable(DeadLetterDrop, NULL, sff) ||
418			    (fp = safefopen(DeadLetterDrop, O_WRONLY|O_APPEND,
419					    FileMode, sff)) == NULL)
420			{
421				state = ESM_PANIC;
422				break;
423			}
424
425			memset(&mcibuf, '\0', sizeof(mcibuf));
426			mcibuf.mci_out = fp;
427			mcibuf.mci_mailer = FileMailer;
428			if (bitnset(M_7BITS, FileMailer->m_flags))
429				mcibuf.mci_flags |= MCIF_7BIT;
430
431			/* get the sender for the UnixFromLine */
432			p = macvalue('g', e);
433			macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
434
435			if (!putfromline(&mcibuf, e) ||
436			    !(*e->e_puthdr)(&mcibuf, e->e_header, e,
437					M87F_OUTER) ||
438			    !(*e->e_putbody)(&mcibuf, e, NULL) ||
439			    !putline("\n", &mcibuf) ||
440			    sm_io_flush(fp, SM_TIME_DEFAULT) == SM_IO_EOF ||
441			    sm_io_error(fp) ||
442			    sm_io_close(fp, SM_TIME_DEFAULT) < 0)
443				state = ESM_PANIC;
444			else
445			{
446				int oldverb = Verbose;
447
448				if (OpMode != MD_DAEMON && OpMode != MD_SMTP)
449					Verbose = 1;
450				if (Verbose > 0)
451					message("Saved message in %s",
452						DeadLetterDrop);
453				Verbose = oldverb;
454				if (LogLevel > 3)
455					sm_syslog(LOG_NOTICE, e->e_id,
456						  "Saved message in %s",
457						  DeadLetterDrop);
458				state = ESM_DONE;
459			}
460			macdefine(&e->e_macro, A_PERM, 'g', p);
461			break;
462
463		  default:
464			syserr("554 5.3.5 savemail: unknown state %d", state);
465			/* FALLTHROUGH */
466
467		  case ESM_PANIC:
468			/* leave the locked queue & transcript files around */
469			loseqfile(e, "savemail panic");
470			panic = true;
471			errno = 0;
472			syserr("554 savemail: cannot save rejected email anywhere");
473			state = ESM_DONE;
474			break;
475		}
476	}
477	return panic;
478}
479/*
480**  RETURNTOSENDER -- return a message to the sender with an error.
481**
482**	Parameters:
483**		msg -- the explanatory message.
484**		returnq -- the queue of people to send the message to.
485**		flags -- flags tweaking the operation:
486**			RTSF_SENDBODY -- include body of message (otherwise
487**				just send the header).
488**			RTSF_PMBOUNCE -- this is a postmaster bounce.
489**		e -- the current envelope.
490**
491**	Returns:
492**		zero -- if everything went ok.
493**		else -- some error.
494**
495**	Side Effects:
496**		Returns the current message to the sender via mail.
497*/
498
499#define MAXRETURNS	6	/* max depth of returning messages */
500#define ERRORFUDGE	1024	/* nominal size of error message text */
501
502int
503returntosender(msg, returnq, flags, e)
504	char *msg;
505	ADDRESS *returnq;
506	int flags;
507	register ENVELOPE *e;
508{
509	int ret;
510	register ENVELOPE *ee;
511	ENVELOPE *oldcur = CurEnv;
512	ENVELOPE errenvelope;
513	static int returndepth = 0;
514	register ADDRESS *q;
515	char *p;
516	char buf[MAXNAME + 1];
517
518	if (returnq == NULL)
519		return -1;
520
521	if (msg == NULL)
522		msg = "Unable to deliver mail";
523
524	if (tTd(6, 1))
525	{
526		sm_dprintf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%p, returnq=",
527			msg, returndepth, (void *)e);
528		printaddr(sm_debug_file(), returnq, true);
529		if (tTd(6, 20))
530		{
531			sm_dprintf("Sendq=");
532			printaddr(sm_debug_file(), e->e_sendqueue, true);
533		}
534	}
535
536	if (++returndepth >= MAXRETURNS)
537	{
538		if (returndepth != MAXRETURNS)
539			syserr("554 5.3.0 returntosender: infinite recursion on %s",
540			       returnq->q_paddr);
541		/* don't "unrecurse" and fake a clean exit */
542		/* returndepth--; */
543		return 0;
544	}
545
546	macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
547	macdefine(&e->e_macro, A_PERM, 'u', NULL);
548
549	/* initialize error envelope */
550	ee = newenvelope(&errenvelope, e, sm_rpool_new_x(NULL));
551	macdefine(&ee->e_macro, A_PERM, 'a', "\201b");
552	macdefine(&ee->e_macro, A_PERM, 'r', "");
553	macdefine(&ee->e_macro, A_PERM, 's', "localhost");
554	macdefine(&ee->e_macro, A_PERM, '_', "localhost");
555	clrsessenvelope(ee);
556
557	ee->e_puthdr = putheader;
558	ee->e_putbody = errbody;
559	ee->e_flags |= EF_RESPONSE|EF_METOO;
560	if (!bitset(EF_OLDSTYLE, e->e_flags))
561		ee->e_flags &= ~EF_OLDSTYLE;
562	if (bitset(EF_DONT_MIME, e->e_flags))
563	{
564		ee->e_flags |= EF_DONT_MIME;
565
566		/*
567		**  If we can't convert to MIME and we don't pass
568		**  8-bit, we can't send the body.
569		*/
570
571		if (bitset(EF_HAS8BIT, e->e_flags) &&
572		    !bitset(MM_PASS8BIT, MimeMode))
573			flags &= ~RTSF_SEND_BODY;
574	}
575
576	ee->e_sendqueue = returnq;
577	ee->e_msgsize = 0;
578	if (bitset(RTSF_SEND_BODY, flags) &&
579	    !bitset(PRIV_NOBODYRETN, PrivacyFlags))
580		ee->e_msgsize = ERRORFUDGE + e->e_msgsize;
581	else
582		ee->e_flags |= EF_NO_BODY_RETN;
583
584#if _FFR_BOUNCE_QUEUE
585	if (BounceQueue != NOQGRP)
586		ee->e_qgrp = ee->e_dfqgrp = BounceQueue;
587#endif
588	if (!setnewqueue(ee))
589	{
590		syserr("554 5.3.0 returntosender: cannot select queue for %s",
591			       returnq->q_paddr);
592		ExitStat = EX_UNAVAILABLE;
593		returndepth--;
594		return -1;
595	}
596	initsys(ee);
597
598#if NAMED_BIND
599	_res.retry = TimeOuts.res_retry[RES_TO_FIRST];
600	_res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
601#endif
602	for (q = returnq; q != NULL; q = q->q_next)
603	{
604		if (QS_IS_BADADDR(q->q_state))
605			continue;
606
607		q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
608		q->q_flags |= QPINGONFAILURE;
609
610		if (!QS_IS_DEAD(q->q_state))
611			ee->e_nrcpts++;
612
613		if (q->q_alias == NULL)
614			addheader("To", q->q_paddr, 0, ee, true);
615	}
616
617	if (LogLevel > 5)
618	{
619		if (bitset(EF_RESPONSE, e->e_flags))
620			p = "return to sender";
621		else if (bitset(EF_WARNING, e->e_flags))
622			p = "sender notify";
623		else if (bitset(RTSF_PM_BOUNCE, flags))
624			p = "postmaster notify";
625		else
626			p = "DSN";
627		sm_syslog(LOG_INFO, e->e_id, "%s: %s: %s",
628			  ee->e_id, p, shortenstring(msg, MAXSHORTSTR));
629	}
630
631	if (SendMIMEErrors)
632	{
633		addheader("MIME-Version", "1.0", 0, ee, true);
634		(void) sm_snprintf(buf, sizeof(buf), "%s.%ld/%.100s",
635				ee->e_id, (long)curtime(), MyHostName);
636		ee->e_msgboundary = sm_rpool_strdup_x(ee->e_rpool, buf);
637		(void) sm_snprintf(buf, sizeof(buf),
638#if DSN
639				"multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"",
640#else
641				"multipart/mixed; boundary=\"%s\"",
642#endif
643				ee->e_msgboundary);
644		addheader("Content-Type", buf, 0, ee, true);
645
646		p = hvalue("Content-Transfer-Encoding", e->e_header);
647		if (p != NULL && sm_strcasecmp(p, "binary") != 0)
648			p = NULL;
649		if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
650			p = "8bit";
651		if (p != NULL)
652			addheader("Content-Transfer-Encoding", p, 0, ee, true);
653	}
654	if (strncmp(msg, "Warning:", 8) == 0)
655	{
656		addheader("Subject", msg, 0, ee, true);
657		p = "warning-timeout";
658	}
659	else if (strncmp(msg, "Postmaster warning:", 19) == 0)
660	{
661		addheader("Subject", msg, 0, ee, true);
662		p = "postmaster-warning";
663	}
664	else if (strcmp(msg, "Return receipt") == 0)
665	{
666		addheader("Subject", msg, 0, ee, true);
667		p = "return-receipt";
668	}
669	else if (bitset(RTSF_PM_BOUNCE, flags))
670	{
671		(void) sm_snprintf(buf, sizeof(buf),
672			 "Postmaster notify: see transcript for details");
673		addheader("Subject", buf, 0, ee, true);
674		p = "postmaster-notification";
675	}
676	else
677	{
678		(void) sm_snprintf(buf, sizeof(buf),
679			 "Returned mail: see transcript for details");
680		addheader("Subject", buf, 0, ee, true);
681		p = "failure";
682	}
683	(void) sm_snprintf(buf, sizeof(buf), "auto-generated (%s)", p);
684	addheader("Auto-Submitted", buf, 0, ee, true);
685
686	/* fake up an address header for the from person */
687	expand("\201n", buf, sizeof(buf), e);
688	if (parseaddr(buf, &ee->e_from,
689		      RF_COPYALL|RF_SENDERADDR, '\0', NULL, e, false) == NULL)
690	{
691		syserr("553 5.3.5 Can't parse myself!");
692		ExitStat = EX_SOFTWARE;
693		returndepth--;
694		return -1;
695	}
696	ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
697	ee->e_from.q_flags |= QPINGONFAILURE;
698	ee->e_sender = ee->e_from.q_paddr;
699
700	/* push state into submessage */
701	CurEnv = ee;
702	macdefine(&ee->e_macro, A_PERM, 'f', "\201n");
703	macdefine(&ee->e_macro, A_PERM, 'x', "Mail Delivery Subsystem");
704	eatheader(ee, true, true);
705
706	/* mark statistics */
707	markstats(ee, NULLADDR, STATS_NORMAL);
708
709#if _FFR_BOUNCE_QUEUE
710	if (BounceQueue == NOQGRP)
711	{
712#endif
713		/* actually deliver the error message */
714		sendall(ee, SM_DELIVER);
715#if _FFR_BOUNCE_QUEUE
716	}
717#endif
718	(void) dropenvelope(ee, true, false);
719
720	/* check for delivery errors */
721	ret = -1;
722	if (ee->e_parent == NULL ||
723	    !bitset(EF_RESPONSE, ee->e_parent->e_flags))
724	{
725		ret = 0;
726	}
727	else
728	{
729		for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
730		{
731			if (QS_IS_ATTEMPTED(q->q_state))
732			{
733				ret = 0;
734				break;
735			}
736		}
737	}
738
739	/* restore state */
740	sm_rpool_free(ee->e_rpool);
741	CurEnv = oldcur;
742	returndepth--;
743
744	return ret;
745}
746
747
748/*
749**  DSNTYPENAME -- Returns the DSN name of the addrtype for this address
750**
751**	Sendmail's addrtypes are largely in different universes, and
752**	'fred' may be a valid address in different addrtype
753**	universes.
754**
755**	EAI extends the rfc822 universe rather than introduce a new
756**	universe.  Because of that, sendmail uses the rfc822 addrtype,
757**	but names it utf-8 when the EAI DSN extension requires that.
758**
759**	Parameters:
760**		addrtype -- address type
761**		addr -- the address
762**
763**	Returns:
764**		type for DSN
765**
766*/
767
768static const char *dsntypename __P((const char *, const char *));
769
770static const char *
771dsntypename(addrtype, addr)
772	const char *addrtype;
773	const char *addr;
774{
775	if (sm_strcasecmp(addrtype, "rfc822") != 0)
776		return addrtype;
777#if _FFR_EAI
778	if (!addr_is_ascii(addr))
779		return "utf-8";
780#endif
781	return "rfc822";
782}
783
784
785/*
786**  ERRBODY -- output the body of an error message.
787**
788**	Typically this is a copy of the transcript plus a copy of the
789**	original offending message.
790**
791**	Parameters:
792**		mci -- the mailer connection information.
793**		e -- the envelope we are working in.
794**		separator -- any possible MIME separator (unused).
795**
796**	Returns:
797**		true iff body was written successfully
798**
799**	Side Effects:
800**		Outputs the body of an error message.
801*/
802
803/* ARGSUSED2 */
804static bool
805errbody(mci, e, separator)
806	register MCI *mci;
807	register ENVELOPE *e;
808	char *separator;
809{
810	bool printheader;
811	bool sendbody;
812	bool pm_notify;
813	int save_errno;
814	register SM_FILE_T *xfile;
815	char *p;
816	register ADDRESS *q = NULL;
817	char actual[MAXLINE];
818	char buf[MAXLINE];
819
820	if (bitset(MCIF_INHEADER, mci->mci_flags))
821	{
822		if (!putline("", mci))
823			goto writeerr;
824		mci->mci_flags &= ~MCIF_INHEADER;
825	}
826	if (e->e_parent == NULL)
827	{
828		syserr("errbody: null parent");
829		if (!putline("   ----- Original message lost -----\n", mci))
830			goto writeerr;
831		return true;
832	}
833
834	/*
835	**  Output MIME header.
836	*/
837
838	if (e->e_msgboundary != NULL)
839	{
840		(void) sm_strlcpyn(buf, sizeof(buf), 2, "--", e->e_msgboundary);
841		if (!putline("This is a MIME-encapsulated message", mci) ||
842		    !putline("", mci) ||
843		    !putline(buf, mci) ||
844		    !putline("", mci))
845			goto writeerr;
846	}
847
848	/*
849	**  Output introductory information.
850	*/
851
852	pm_notify = false;
853	p = hvalue("subject", e->e_header);
854	if (p != NULL && strncmp(p, "Postmaster ", 11) == 0)
855		pm_notify = true;
856	else
857	{
858		for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
859		{
860			if (QS_IS_BADADDR(q->q_state))
861				break;
862		}
863	}
864	if (!pm_notify && q == NULL &&
865	    !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
866	{
867		if (!putline("    **********************************************",
868			mci) ||
869		    !putline("    **      THIS IS A WARNING MESSAGE ONLY      **",
870			mci) ||
871		    !putline("    **  YOU DO NOT NEED TO RESEND YOUR MESSAGE  **",
872			mci) ||
873		    !putline("    **********************************************",
874			mci) ||
875		    !putline("", mci))
876			goto writeerr;
877	}
878	(void) sm_snprintf(buf, sizeof(buf),
879		"The original message was received at %s",
880		arpadate(ctime(&e->e_parent->e_ctime)));
881	if (!putline(buf, mci))
882		goto writeerr;
883	expand("from \201_", buf, sizeof(buf), e->e_parent);
884	if (!putline(buf, mci))
885		goto writeerr;
886
887	/* include id in postmaster copies */
888	if (pm_notify && e->e_parent->e_id != NULL)
889	{
890		(void) sm_strlcpyn(buf, sizeof(buf), 2, "with id ",
891			e->e_parent->e_id);
892		if (!putline(buf, mci))
893			goto writeerr;
894	}
895	if (!putline("", mci))
896		goto writeerr;
897
898	/*
899	**  Output error message header (if specified and available).
900	*/
901
902	if (ErrMsgFile != NULL &&
903	    !bitset(EF_SENDRECEIPT, e->e_parent->e_flags))
904	{
905		if (*ErrMsgFile == '/')
906		{
907			long sff = SFF_ROOTOK|SFF_REGONLY;
908
909			if (DontLockReadFiles)
910				sff |= SFF_NOLOCK;
911			if (!bitnset(DBS_ERRORHEADERINUNSAFEDIRPATH,
912				     DontBlameSendmail))
913				sff |= SFF_SAFEDIRPATH;
914			xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, sff);
915			if (xfile != NULL)
916			{
917				while (sm_io_fgets(xfile, SM_TIME_DEFAULT, buf,
918						   sizeof(buf)) >= 0)
919				{
920					int lbs;
921					bool putok;
922					char *lbp;
923
924					lbs = sizeof(buf);
925					lbp = translate_dollars(buf, buf, &lbs);
926					expand(lbp, lbp, lbs, e);
927					putok = putline(lbp, mci);
928					if (lbp != buf)
929						sm_free(lbp);
930					if (!putok)
931						goto writeerr;
932				}
933				(void) sm_io_close(xfile, SM_TIME_DEFAULT);
934				if (!putline("\n", mci))
935					goto writeerr;
936			}
937		}
938		else
939		{
940			expand(ErrMsgFile, buf, sizeof(buf), e);
941			if (!putline(buf, mci) || !putline("", mci))
942				goto writeerr;
943		}
944	}
945
946	/*
947	**  Output message introduction
948	*/
949
950	/* permanent fatal errors */
951	printheader = true;
952	for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
953	{
954		if (!QS_IS_BADADDR(q->q_state) ||
955		    !bitset(QPINGONFAILURE, q->q_flags))
956			continue;
957
958		if (printheader)
959		{
960			if (!putline("   ----- The following addresses had permanent fatal errors -----",
961					mci))
962				goto writeerr;
963			printheader = false;
964		}
965
966		(void) sm_strlcpy(buf, shortenstring(q->q_paddr, MAXSHORTSTR),
967				  sizeof(buf));
968		if (!putline(buf, mci))
969			goto writeerr;
970		if (q->q_rstatus != NULL)
971		{
972			(void) sm_snprintf(buf, sizeof(buf),
973				"    (reason: %s)",
974				shortenstring(exitstat(q->q_rstatus),
975					      MAXSHORTSTR));
976			if (!putline(buf, mci))
977				goto writeerr;
978		}
979		if (q->q_alias != NULL)
980		{
981			(void) sm_snprintf(buf, sizeof(buf),
982				"    (expanded from: %s)",
983				shortenstring(q->q_alias->q_paddr,
984					      MAXSHORTSTR));
985			if (!putline(buf, mci))
986				goto writeerr;
987		}
988	}
989	if (!printheader && !putline("", mci))
990		goto writeerr;
991
992	/* transient non-fatal errors */
993	printheader = true;
994	for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
995	{
996		if (QS_IS_BADADDR(q->q_state) ||
997		    !bitset(QPRIMARY, q->q_flags) ||
998		    !bitset(QBYNDELAY, q->q_flags) ||
999		    !bitset(QDELAYED, q->q_flags))
1000			continue;
1001
1002		if (printheader)
1003		{
1004			if (!putline("   ----- The following addresses had transient non-fatal errors -----",
1005					mci))
1006				goto writeerr;
1007			printheader = false;
1008		}
1009
1010		(void) sm_strlcpy(buf, shortenstring(q->q_paddr, MAXSHORTSTR),
1011				  sizeof(buf));
1012		if (!putline(buf, mci))
1013			goto writeerr;
1014		if (q->q_alias != NULL)
1015		{
1016			(void) sm_snprintf(buf, sizeof(buf),
1017				"    (expanded from: %s)",
1018				shortenstring(q->q_alias->q_paddr,
1019					      MAXSHORTSTR));
1020			if (!putline(buf, mci))
1021				goto writeerr;
1022		}
1023	}
1024	if (!printheader && !putline("", mci))
1025		goto writeerr;
1026
1027	/* successful delivery notifications */
1028	printheader = true;
1029	for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
1030	{
1031		if (QS_IS_BADADDR(q->q_state) ||
1032		    !bitset(QPRIMARY, q->q_flags) ||
1033		    bitset(QBYNDELAY, q->q_flags) ||
1034		    bitset(QDELAYED, q->q_flags))
1035			continue;
1036		else if (bitset(QBYNRELAY, q->q_flags))
1037			p = "Deliver-By notify: relayed";
1038		else if (bitset(QBYTRACE, q->q_flags))
1039			p = "Deliver-By trace: relayed";
1040		else if (!bitset(QPINGONSUCCESS, q->q_flags))
1041			continue;
1042		else if (bitset(QRELAYED, q->q_flags))
1043			p = "relayed to non-DSN-aware mailer";
1044		else if (bitset(QDELIVERED, q->q_flags))
1045		{
1046			if (bitset(QEXPANDED, q->q_flags))
1047				p = "successfully delivered to mailing list";
1048			else
1049				p = "successfully delivered to mailbox";
1050		}
1051		else if (bitset(QEXPANDED, q->q_flags))
1052			p = "expanded by alias";
1053		else
1054			continue;
1055
1056		if (printheader)
1057		{
1058			if (!putline("   ----- The following addresses had successful delivery notifications -----",
1059					mci))
1060				goto writeerr;
1061			printheader = false;
1062		}
1063
1064		(void) sm_snprintf(buf, sizeof(buf), "%s  (%s)",
1065			 shortenstring(q->q_paddr, MAXSHORTSTR), p);
1066		if (!putline(buf, mci))
1067			goto writeerr;
1068		if (q->q_alias != NULL)
1069		{
1070			(void) sm_snprintf(buf, sizeof(buf),
1071				"    (expanded from: %s)",
1072				shortenstring(q->q_alias->q_paddr,
1073					      MAXSHORTSTR));
1074			if (!putline(buf, mci))
1075				goto writeerr;
1076		}
1077	}
1078	if (!printheader && !putline("", mci))
1079		goto writeerr;
1080
1081	/*
1082	**  Output transcript of errors
1083	*/
1084
1085	(void) sm_io_flush(smioout, SM_TIME_DEFAULT);
1086	if (e->e_parent->e_xfp == NULL)
1087	{
1088		if (!putline("   ----- Transcript of session is unavailable -----\n",
1089				mci))
1090			goto writeerr;
1091	}
1092	else
1093	{
1094		int blen;
1095
1096		printheader = true;
1097		(void) bfrewind(e->e_parent->e_xfp);
1098		if (e->e_xfp != NULL)
1099			(void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
1100		while ((blen = sm_io_fgets(e->e_parent->e_xfp, SM_TIME_DEFAULT,
1101					buf, sizeof(buf))) >= 0)
1102		{
1103			if (printheader && !putline("   ----- Transcript of session follows -----\n",
1104						mci))
1105				goto writeerr;
1106			printheader = false;
1107			if (!putxline(buf, blen, mci, PXLF_MAPFROM))
1108				goto writeerr;
1109		}
1110	}
1111	errno = 0;
1112
1113#if DSN
1114	/*
1115	**  Output machine-readable version.
1116	*/
1117
1118	if (e->e_msgboundary != NULL)
1119	{
1120		(void) sm_strlcpyn(buf, sizeof(buf), 2, "--", e->e_msgboundary);
1121		if (!putline("", mci) ||
1122		    !putline(buf, mci) ||
1123#if _FFR_EAI
1124		    !putline(e->e_parent->e_smtputf8
1125			     ? "Content-Type: message/global-delivery-status"
1126			     : "Content-Type: message/delivery-status", mci) ||
1127#else
1128		    !putline("Content-Type: message/delivery-status", mci) ||
1129#endif
1130		    !putline("", mci))
1131			goto writeerr;
1132
1133		/*
1134		**  Output per-message information.
1135		*/
1136
1137		/* original envelope id from MAIL FROM: line */
1138		if (e->e_parent->e_envid != NULL)
1139		{
1140			(void) sm_snprintf(buf, sizeof(buf),
1141					"Original-Envelope-Id: %.800s",
1142					xuntextify(e->e_parent->e_envid));
1143			if (!putline(buf, mci))
1144				goto writeerr;
1145		}
1146
1147		/* Reporting-MTA: is us (required) */
1148		(void) sm_snprintf(buf, sizeof(buf),
1149				   "Reporting-MTA: dns; %.800s", MyHostName);
1150		if (!putline(buf, mci))
1151			goto writeerr;
1152
1153		/* DSN-Gateway: not relevant since we are not translating */
1154
1155		/* Received-From-MTA: shows where we got this message from */
1156		if (RealHostName != NULL)
1157		{
1158			/* XXX use $s for type? */
1159			if (e->e_parent->e_from.q_mailer == NULL ||
1160			    (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
1161				p = "dns";
1162			(void) sm_snprintf(buf, sizeof(buf),
1163					"Received-From-MTA: %s; %.800s",
1164					p, RealHostName);
1165			if (!putline(buf, mci))
1166				goto writeerr;
1167		}
1168
1169		/* Arrival-Date: -- when it arrived here */
1170		(void) sm_strlcpyn(buf, sizeof(buf), 2, "Arrival-Date: ",
1171				arpadate(ctime(&e->e_parent->e_ctime)));
1172		if (!putline(buf, mci))
1173			goto writeerr;
1174
1175		/* Deliver-By-Date: -- when it should have been delivered */
1176		if (IS_DLVR_BY(e->e_parent))
1177		{
1178			time_t dbyd;
1179
1180			dbyd = e->e_parent->e_ctime + e->e_parent->e_deliver_by;
1181			(void) sm_strlcpyn(buf, sizeof(buf), 2,
1182					"Deliver-By-Date: ",
1183					arpadate(ctime(&dbyd)));
1184			if (!putline(buf, mci))
1185				goto writeerr;
1186		}
1187
1188		/*
1189		**  Output per-address information.
1190		*/
1191
1192		for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
1193		{
1194			char *action;
1195
1196			if (QS_IS_BADADDR(q->q_state))
1197			{
1198				/* RFC 1891, 6.2.6 (b) */
1199				if (bitset(QHASNOTIFY, q->q_flags) &&
1200				    !bitset(QPINGONFAILURE, q->q_flags))
1201					continue;
1202				action = "failed";
1203			}
1204			else if (!bitset(QPRIMARY, q->q_flags))
1205				continue;
1206			else if (bitset(QDELIVERED, q->q_flags))
1207			{
1208				if (bitset(QEXPANDED, q->q_flags))
1209					action = "delivered (to mailing list)";
1210				else
1211					action = "delivered (to mailbox)";
1212			}
1213			else if (bitset(QRELAYED, q->q_flags))
1214				action = "relayed (to non-DSN-aware mailer)";
1215			else if (bitset(QEXPANDED, q->q_flags))
1216				action = "expanded (to multi-recipient alias)";
1217			else if (bitset(QDELAYED, q->q_flags))
1218				action = "delayed";
1219			else if (bitset(QBYTRACE, q->q_flags))
1220				action = "relayed (Deliver-By trace mode)";
1221			else if (bitset(QBYNDELAY, q->q_flags))
1222				action = "delayed (Deliver-By notify mode)";
1223			else if (bitset(QBYNRELAY, q->q_flags))
1224				action = "relayed (Deliver-By notify mode)";
1225			else
1226				continue;
1227
1228			if (!putline("", mci))
1229				goto writeerr;
1230
1231			/* Original-Recipient: -- passed from on high */
1232			if (q->q_orcpt != NULL)
1233			{
1234				p = strchr(q->q_orcpt, ';');
1235
1236				/*
1237				**  p == NULL shouldn't happen due to
1238				**  check in srvrsmtp.c
1239				**  we could log an error in this case.
1240				*/
1241
1242				if (p != NULL)
1243				{
1244					*p = '\0';
1245					(void) sm_snprintf(buf, sizeof(buf),
1246						"Original-Recipient: %.100s;%.700s",
1247						q->q_orcpt, xuntextify(p + 1));
1248					*p = ';';
1249					if (!putline(buf, mci))
1250						goto writeerr;
1251				}
1252			}
1253
1254			/* Figure out actual recipient */
1255			actual[0] = '\0';
1256			if (q->q_user[0] != '\0')
1257			{
1258				if (q->q_mailer != NULL &&
1259				    q->q_mailer->m_addrtype != NULL)
1260					p = q->q_mailer->m_addrtype;
1261				else
1262					p = "rfc822";
1263
1264				if (sm_strcasecmp(p, "rfc822") == 0 &&
1265				    strchr(q->q_user, '@') == NULL)
1266				{
1267					(void) sm_snprintf(actual,
1268							   sizeof(actual),
1269							   "%s; %.700s@%.100s",
1270							   dsntypename(p, q->q_user),
1271							   q->q_user,
1272							   MyHostName);
1273				}
1274				else
1275				{
1276					(void) sm_snprintf(actual,
1277							   sizeof(actual),
1278							   "%s; %.800s",
1279							   dsntypename(p, q->q_user),
1280							   q->q_user);
1281				}
1282			}
1283
1284			/* Final-Recipient: -- the name from the RCPT command */
1285			if (q->q_finalrcpt == NULL)
1286			{
1287				/* should never happen */
1288				sm_syslog(LOG_ERR, e->e_id,
1289					  "returntosender: q_finalrcpt is NULL");
1290
1291				/* try to fall back to the actual recipient */
1292				if (actual[0] != '\0')
1293					q->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool,
1294									   actual);
1295			}
1296
1297#if _FFR_EAI
1298			if (sm_strncasecmp("rfc822;", q->q_finalrcpt, 7) == 0 &&
1299			    !addr_is_ascii(q->q_user))
1300			{
1301				char *a;
1302				char utf8rcpt[1024];
1303
1304				a = strchr(q->q_finalrcpt, ';');
1305				while(*a == ';' || *a == ' ')
1306					a++;
1307				sm_snprintf(utf8rcpt, sizeof(utf8rcpt),
1308					    "utf-8; %.800s", a);
1309				q->q_finalrcpt = sm_rpool_strdup_x(e->e_rpool,
1310								   utf8rcpt);
1311			}
1312#endif
1313
1314			if (q->q_finalrcpt != NULL)
1315			{
1316				(void) sm_snprintf(buf, sizeof(buf),
1317						   "Final-Recipient: %s",
1318						   q->q_finalrcpt);
1319				if (!putline(buf, mci))
1320					goto writeerr;
1321			}
1322
1323			/* X-Actual-Recipient: -- the real problem address */
1324			if (actual[0] != '\0' &&
1325			    q->q_finalrcpt != NULL &&
1326			    !bitset(PRIV_NOACTUALRECIPIENT, PrivacyFlags) &&
1327			    strcmp(actual, q->q_finalrcpt) != 0)
1328			{
1329				(void) sm_snprintf(buf, sizeof(buf),
1330						   "X-Actual-Recipient: %s",
1331						   actual);
1332				if (!putline(buf, mci))
1333					goto writeerr;
1334			}
1335
1336			/* Action: -- what happened? */
1337			(void) sm_strlcpyn(buf, sizeof(buf), 2, "Action: ",
1338				action);
1339			if (!putline(buf, mci))
1340				goto writeerr;
1341
1342			/* Status: -- what _really_ happened? */
1343			if (q->q_status != NULL)
1344				p = q->q_status;
1345			else if (QS_IS_BADADDR(q->q_state))
1346				p = "5.0.0";
1347			else if (QS_IS_QUEUEUP(q->q_state))
1348				p = "4.0.0";
1349			else
1350				p = "2.0.0";
1351			(void) sm_strlcpyn(buf, sizeof(buf), 2, "Status: ", p);
1352			if (!putline(buf, mci))
1353				goto writeerr;
1354
1355			/* Remote-MTA: -- who was I talking to? */
1356			if (q->q_statmta != NULL)
1357			{
1358				if (q->q_mailer == NULL ||
1359				    (p = q->q_mailer->m_mtatype) == NULL)
1360					p = "dns";
1361				(void) sm_snprintf(buf, sizeof(buf),
1362						"Remote-MTA: %s; %.800s",
1363						p, q->q_statmta);
1364				p = &buf[strlen(buf) - 1];
1365				if (*p == '.')
1366					*p = '\0';
1367				if (!putline(buf, mci))
1368					goto writeerr;
1369			}
1370
1371			/* Diagnostic-Code: -- actual result from other end */
1372			if (q->q_rstatus != NULL)
1373			{
1374				if (q->q_mailer == NULL ||
1375				    (p = q->q_mailer->m_diagtype) == NULL)
1376					p = "smtp";
1377				(void) sm_snprintf(buf, sizeof(buf),
1378						"Diagnostic-Code: %s; %.800s",
1379						p, q->q_rstatus);
1380				if (!putline(buf, mci))
1381					goto writeerr;
1382			}
1383
1384			/* Last-Attempt-Date: -- fine granularity */
1385			if (q->q_statdate == (time_t) 0L)
1386				q->q_statdate = curtime();
1387			(void) sm_strlcpyn(buf, sizeof(buf), 2,
1388					"Last-Attempt-Date: ",
1389					arpadate(ctime(&q->q_statdate)));
1390			if (!putline(buf, mci))
1391				goto writeerr;
1392
1393			/* Will-Retry-Until: -- for delayed messages only */
1394			if (QS_IS_QUEUEUP(q->q_state))
1395			{
1396				time_t xdate;
1397
1398				xdate = e->e_parent->e_ctime +
1399					TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
1400				(void) sm_strlcpyn(buf, sizeof(buf), 2,
1401					 "Will-Retry-Until: ",
1402					 arpadate(ctime(&xdate)));
1403				if (!putline(buf, mci))
1404					goto writeerr;
1405			}
1406		}
1407	}
1408#endif /* DSN */
1409
1410	/*
1411	**  Output text of original message
1412	*/
1413
1414	if (!putline("", mci))
1415		goto writeerr;
1416	if (bitset(EF_HAS_DF, e->e_parent->e_flags))
1417	{
1418		sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
1419			   !bitset(EF_NO_BODY_RETN, e->e_flags);
1420
1421		if (e->e_msgboundary == NULL)
1422		{
1423			if (!putline(
1424				sendbody
1425				? "   ----- Original message follows -----\n"
1426				: "   ----- Message header follows -----\n",
1427				mci))
1428			{
1429				goto writeerr;
1430			}
1431		}
1432		else
1433		{
1434			(void) sm_strlcpyn(buf, sizeof(buf), 2, "--",
1435					e->e_msgboundary);
1436
1437			if (!putline(buf, mci))
1438				goto writeerr;
1439#if _FFR_EAI
1440			if (e->e_parent->e_smtputf8)
1441				(void) sm_strlcpyn(buf, sizeof(buf), 2,
1442						   "Content-Type: message/global",
1443						   sendbody ? "" : "-headers");
1444			else
1445				(void) sm_strlcpyn(buf, sizeof(buf), 2,
1446						   "Content-Type: ",
1447						sendbody ? "message/rfc822"
1448							 : "text/rfc822-headers");
1449#else /* _FFR_EAI */
1450			(void) sm_strlcpyn(buf, sizeof(buf), 2, "Content-Type: ",
1451					sendbody ? "message/rfc822"
1452						 : "text/rfc822-headers");
1453#endif /* _FFR_EAI */
1454			if (!putline(buf, mci))
1455				goto writeerr;
1456
1457			p = hvalue("Content-Transfer-Encoding",
1458				   e->e_parent->e_header);
1459			if (p != NULL && sm_strcasecmp(p, "binary") != 0)
1460				p = NULL;
1461			if (p == NULL &&
1462			    bitset(EF_HAS8BIT, e->e_parent->e_flags))
1463				p = "8bit";
1464			if (p != NULL)
1465			{
1466				(void) sm_snprintf(buf, sizeof(buf),
1467						"Content-Transfer-Encoding: %s",
1468						p);
1469				if (!putline(buf, mci))
1470					goto writeerr;
1471			}
1472		}
1473		if (!putline("", mci))
1474			goto writeerr;
1475		save_errno = errno;
1476		if (!putheader(mci, e->e_parent->e_header, e->e_parent,
1477				M87F_OUTER))
1478			goto writeerr;
1479		errno = save_errno;
1480		if (sendbody)
1481		{
1482			if (!putbody(mci, e->e_parent, e->e_msgboundary))
1483				goto writeerr;
1484		}
1485		else if (e->e_msgboundary == NULL)
1486		{
1487			if (!putline("", mci) ||
1488			    !putline("   ----- Message body suppressed -----",
1489					mci))
1490			{
1491				goto writeerr;
1492			}
1493		}
1494	}
1495	else if (e->e_msgboundary == NULL)
1496	{
1497		if (!putline("  ----- No message was collected -----\n", mci))
1498			goto writeerr;
1499	}
1500
1501	if (e->e_msgboundary != NULL)
1502	{
1503		(void) sm_strlcpyn(buf, sizeof(buf), 3, "--", e->e_msgboundary,
1504				   "--");
1505		if (!putline("", mci) || !putline(buf, mci))
1506			goto writeerr;
1507	}
1508	if (!putline("", mci) ||
1509	    sm_io_flush(mci->mci_out, SM_TIME_DEFAULT) == SM_IO_EOF)
1510			goto writeerr;
1511
1512	/*
1513	**  Cleanup and exit
1514	*/
1515
1516	if (errno != 0)
1517	{
1518  writeerr:
1519		syserr("errbody: I/O error");
1520		return false;
1521	}
1522	return true;
1523}
1524
1525/*
1526**  SMTPTODSN -- convert SMTP to DSN status code
1527**
1528**	Parameters:
1529**		smtpstat -- the smtp status code (e.g., 550).
1530**
1531**	Returns:
1532**		The DSN version of the status code.
1533**
1534**	Storage Management:
1535**		smtptodsn() returns a pointer to a character string literal,
1536**		which will remain valid forever, and thus does not need to
1537**		be copied.  Current code relies on this property.
1538*/
1539
1540char *
1541smtptodsn(smtpstat)
1542	int smtpstat;
1543{
1544	if (smtpstat < 0)
1545		return "4.4.2";
1546
1547	switch (smtpstat)
1548	{
1549	  case 450:	/* Req mail action not taken: mailbox unavailable */
1550		return "4.2.0";
1551
1552	  case 451:	/* Req action aborted: local error in processing */
1553		return "4.3.0";
1554
1555	  case 452:	/* Req action not taken: insufficient sys storage */
1556		return "4.3.1";
1557
1558	  case 500:	/* Syntax error, command unrecognized */
1559		return "5.5.2";
1560
1561	  case 501:	/* Syntax error in parameters or arguments */
1562		return "5.5.4";
1563
1564	  case 502:	/* Command not implemented */
1565		return "5.5.1";
1566
1567	  case 503:	/* Bad sequence of commands */
1568		return "5.5.1";
1569
1570	  case 504:	/* Command parameter not implemented */
1571		return "5.5.4";
1572
1573	  case 550:	/* Req mail action not taken: mailbox unavailable */
1574		return "5.2.0";
1575
1576	  case 551:	/* User not local; please try <...> */
1577		return "5.1.6";
1578
1579	  case 552:	/* Req mail action aborted: exceeded storage alloc */
1580		return "5.2.2";
1581
1582	  case 553:	/* Req action not taken: mailbox name not allowed */
1583		return "5.1.0";
1584
1585	  case 554:	/* Transaction failed */
1586		return "5.0.0";
1587	}
1588
1589	if (REPLYTYPE(smtpstat) == 2)
1590		return "2.0.0";
1591	if (REPLYTYPE(smtpstat) == 4)
1592		return "4.0.0";
1593	return "5.0.0";
1594}
1595/*
1596**  XTEXTIFY -- take regular text and turn it into DSN-style xtext
1597**
1598**	Parameters:
1599**		t -- the text to convert.
1600**		taboo -- additional characters that must be encoded.
1601**
1602**	Returns:
1603**		The xtext-ified version of the same string.
1604*/
1605
1606char *
1607xtextify(t, taboo)
1608	register char *t;
1609	char *taboo;
1610{
1611	register char *p;
1612	int l;
1613	int nbogus;
1614	static char *bp = NULL;
1615	static int bplen = 0;
1616
1617	if (taboo == NULL)
1618		taboo = "";
1619
1620	/* figure out how long this xtext will have to be */
1621	nbogus = l = 0;
1622	for (p = t; *p != '\0'; p++)
1623	{
1624		register int c = (*p & 0xff);
1625
1626		/* ASCII dependence here -- this is the way the spec words it */
1627		if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
1628		    strchr(taboo, c) != NULL)
1629			nbogus++;
1630		l++;
1631	}
1632	if (nbogus < 0)
1633	{
1634		/* since nbogus is ssize_t and wrapped, 2 * size_t would wrap */
1635		syserr("!xtextify string too long");
1636	}
1637	if (nbogus == 0)
1638		return t;
1639	l += nbogus * 2 + 1;
1640
1641	/* now allocate space if necessary for the new string */
1642	if (l > bplen)
1643	{
1644		if (bp != NULL)
1645			sm_free(bp); /* XXX */
1646		bp = sm_pmalloc_x(l);
1647		bplen = l;
1648	}
1649
1650	/* ok, copy the text with byte expansion */
1651	for (p = bp; *t != '\0'; )
1652	{
1653		register int c = (*t++ & 0xff);
1654
1655		/* ASCII dependence here -- this is the way the spec words it */
1656		if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
1657		    strchr(taboo, c) != NULL)
1658		{
1659			*p++ = '+';
1660			*p++ = "0123456789ABCDEF"[c >> 4];
1661			*p++ = "0123456789ABCDEF"[c & 0xf];
1662		}
1663		else
1664			*p++ = c;
1665	}
1666	*p = '\0';
1667	return bp;
1668}
1669/*
1670**  XUNTEXTIFY -- take xtext and turn it into plain text
1671**
1672**	Parameters:
1673**		t -- the xtextified text.
1674**
1675**	Returns:
1676**		The decoded text.  No attempt is made to deal with
1677**		null strings in the resulting text.
1678*/
1679
1680char *
1681xuntextify(t)
1682	register char *t;
1683{
1684	register char *p;
1685	int l;
1686	static char *bp = NULL;
1687	static int bplen = 0;
1688
1689	/* heuristic -- if no plus sign, just return the input */
1690	if (strchr(t, '+') == NULL)
1691		return t;
1692
1693	/* xtext is always longer than decoded text */
1694	l = strlen(t);
1695	if (l > bplen)
1696	{
1697		if (bp != NULL)
1698			sm_free(bp); /* XXX */
1699		bp = xalloc(l);
1700		bplen = l;
1701	}
1702
1703	/* ok, copy the text with byte compression */
1704	for (p = bp; *t != '\0'; t++)
1705	{
1706		register int c = *t & 0xff;
1707
1708		if (c != '+')
1709		{
1710			*p++ = c;
1711			continue;
1712		}
1713
1714		c = *++t & 0xff;
1715		if (!isascii(c) || !isxdigit(c))
1716		{
1717			/* error -- first digit is not hex */
1718			usrerr("bogus xtext: +%c", c);
1719			t--;
1720			continue;
1721		}
1722		if (isdigit(c))
1723			c -= '0';
1724		else if (isupper(c))
1725			c -= 'A' - 10;
1726		else
1727			c -= 'a' - 10;
1728		*p = c << 4;
1729
1730		c = *++t & 0xff;
1731		if (!isascii(c) || !isxdigit(c))
1732		{
1733			/* error -- second digit is not hex */
1734			usrerr("bogus xtext: +%x%c", *p >> 4, c);
1735			t--;
1736			continue;
1737		}
1738		if (isdigit(c))
1739			c -= '0';
1740		else if (isupper(c))
1741			c -= 'A' - 10;
1742		else
1743			c -= 'a' - 10;
1744		*p++ |= c;
1745	}
1746	*p = '\0';
1747	return bp;
1748}
1749/*
1750**  XTEXTOK -- check if a string is legal xtext
1751**
1752**	Xtext is used in Delivery Status Notifications.  The spec was
1753**	taken from RFC 1891, ``SMTP Service Extension for Delivery
1754**	Status Notifications''.
1755**
1756**	Parameters:
1757**		s -- the string to check.
1758**
1759**	Returns:
1760**		true -- if 's' is legal xtext.
1761**		false -- if it has any illegal characters in it.
1762*/
1763
1764bool
1765xtextok(s)
1766	char *s;
1767{
1768	int c;
1769
1770	while ((c = *s++) != '\0')
1771	{
1772		if (c == '+')
1773		{
1774			c = *s++;
1775			if (!isascii(c) || !isxdigit(c))
1776				return false;
1777			c = *s++;
1778			if (!isascii(c) || !isxdigit(c))
1779				return false;
1780		}
1781		else if (c < '!' || c > '~' || c == '=')
1782			return false;
1783	}
1784	return true;
1785}
1786
1787/*
1788**  ISATOM -- check if a string is an "atom"
1789**
1790**	Parameters:
1791**		s -- the string to check.
1792**
1793**	Returns:
1794**		true -- iff s is an atom
1795*/
1796
1797bool
1798isatom(s)
1799	const char *s;
1800{
1801	int c;
1802
1803	if (s == NULL || *s == '\0')
1804		return false;
1805	while ((c = *s++) != '\0')
1806	{
1807		if (strchr("()<>@,;:\\.[]\"", c) != NULL)
1808			return false;
1809		if (c < '!' || c > '~')
1810			return false;
1811	}
1812	return true;
1813}
1814/*
1815**  PRUNEROUTE -- prune an RFC-822 source route
1816**
1817**	Trims down a source route to the last internet-registered hop.
1818**	This is encouraged by RFC 1123 section 5.3.3.
1819**
1820**	Parameters:
1821**		addr -- the address
1822**
1823**	Returns:
1824**		true -- address was modified
1825**		false -- address could not be pruned
1826**
1827**	Side Effects:
1828**		modifies addr in-place
1829*/
1830
1831static bool
1832pruneroute(addr)
1833	char *addr;
1834{
1835#if NAMED_BIND
1836	char *start, *at, *comma;
1837	char c;
1838	int braclev;
1839	int rcode;
1840	int i;
1841	char hostbuf[BUFSIZ];
1842	char *mxhosts[MAXMXHOSTS + 1];
1843
1844	/* check to see if this is really a route-addr */
1845	if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
1846		return false;
1847
1848	/*
1849	**  Can't simply find the first ':' is the address might be in the
1850	**  form:  "<@[IPv6:::1]:user@host>" and the first ':' in inside
1851	**  the IPv6 address.
1852	*/
1853
1854	start = addr;
1855	braclev = 0;
1856	while (*start != '\0')
1857	{
1858		if (*start == ':' && braclev <= 0)
1859			break;
1860		else if (*start == '[')
1861			braclev++;
1862		else if (*start == ']' && braclev > 0)
1863			braclev--;
1864		start++;
1865	}
1866	if (braclev > 0 || *start != ':')
1867		return false;
1868
1869	at = strrchr(addr, '@');
1870	if (at == NULL || at < start)
1871		return false;
1872
1873	/* slice off the angle brackets */
1874	i = strlen(at + 1);
1875	if (i >= sizeof(hostbuf))
1876		return false;
1877	(void) sm_strlcpy(hostbuf, at + 1, sizeof(hostbuf));
1878	hostbuf[i - 1] = '\0';
1879
1880	while (start != NULL)
1881	{
1882		if (getmxrr(hostbuf, mxhosts, NULL, TRYFALLBACK, &rcode, NULL, -1)
1883		    > 0)
1884		{
1885			(void) sm_strlcpy(addr + 1, start + 1,
1886					  strlen(addr) - 1);
1887			return true;
1888		}
1889		c = *start;
1890		*start = '\0';
1891		comma = strrchr(addr, ',');
1892		if (comma != NULL && comma[1] == '@' &&
1893		    strlen(comma + 2) < sizeof(hostbuf))
1894			(void) sm_strlcpy(hostbuf, comma + 2, sizeof(hostbuf));
1895		else
1896			comma = NULL;
1897		*start = c;
1898		start = comma;
1899	}
1900#endif /* NAMED_BIND */
1901	return false;
1902}
1903