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