1/*
2 * Copyright (c) 1998-2006, 2008-2010, 2014 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: usersmtp.c,v 8.488 2013-11-22 20:51:57 ca Exp $")
17
18#include <sysexits.h>
19
20
21static void	esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
22static void	helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
23static int	smtprcptstat __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *));
24
25#if SASL
26extern void	*sm_sasl_malloc __P((unsigned long));
27extern void	sm_sasl_free __P((void *));
28#endif
29
30/*
31**  USERSMTP -- run SMTP protocol from the user end.
32**
33**	This protocol is described in RFC821.
34*/
35
36#define SMTPCLOSING	421			/* "Service Shutting Down" */
37
38#define ENHSCN(e, d)	((e) == NULL ? (d) : (e))
39
40#define ENHSCN_RPOOL(e, d, rpool) \
41	((e) == NULL ? (d) : sm_rpool_strdup_x(rpool, e))
42
43static char	SmtpMsgBuffer[MAXLINE];		/* buffer for commands */
44static char	SmtpReplyBuffer[MAXLINE];	/* buffer for replies */
45static bool	SmtpNeedIntro;		/* need "while talking" in transcript */
46/*
47**  SMTPINIT -- initialize SMTP.
48**
49**	Opens the connection and sends the initial protocol.
50**
51**	Parameters:
52**		m -- mailer to create connection to.
53**		mci -- the mailer connection info.
54**		e -- the envelope.
55**		onlyhelo -- send only helo command?
56**
57**	Returns:
58**		none.
59**
60**	Side Effects:
61**		creates connection and sends initial protocol.
62*/
63
64void
65smtpinit(m, mci, e, onlyhelo)
66	MAILER *m;
67	register MCI *mci;
68	ENVELOPE *e;
69	bool onlyhelo;
70{
71	register int r;
72	int state;
73	register char *p;
74	register char *hn;
75#if _FFR_EXPAND_HELONAME
76	char hnbuf[MAXNAME + 1];
77#endif
78	char *enhsc;
79
80	enhsc = NULL;
81	if (tTd(18, 1))
82	{
83		sm_dprintf("smtpinit ");
84		mci_dump(sm_debug_file(), mci, false);
85	}
86
87	/*
88	**  Open the connection to the mailer.
89	*/
90
91	SmtpError[0] = '\0';
92	SmtpMsgBuffer[0] = '\0';
93	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
94	if (CurHostName == NULL)
95		CurHostName = MyHostName;
96	SmtpNeedIntro = true;
97	state = mci->mci_state;
98	e->e_rcode = 0;
99	e->e_renhsc[0] = '\0';
100	e->e_text = NULL;
101	switch (state)
102	{
103	  case MCIS_MAIL:
104	  case MCIS_RCPT:
105	  case MCIS_DATA:
106		/* need to clear old information */
107		smtprset(m, mci, e);
108		/* FALLTHROUGH */
109
110	  case MCIS_OPEN:
111		if (!onlyhelo)
112			return;
113		break;
114
115	  case MCIS_ERROR:
116	  case MCIS_QUITING:
117	  case MCIS_SSD:
118		/* shouldn't happen */
119		smtpquit(m, mci, e);
120		/* FALLTHROUGH */
121
122	  case MCIS_CLOSED:
123		syserr("451 4.4.0 smtpinit: state CLOSED (was %d)", state);
124		return;
125
126	  case MCIS_OPENING:
127		break;
128	}
129	if (onlyhelo)
130		goto helo;
131
132	mci->mci_state = MCIS_OPENING;
133	clrsessenvelope(e);
134
135	/*
136	**  Get the greeting message.
137	**	This should appear spontaneously.  Give it five minutes to
138	**	happen.
139	*/
140
141	SmtpPhase = mci->mci_phase = "client greeting";
142	sm_setproctitle(true, e, "%s %s: %s",
143			qid_printname(e), CurHostName, mci->mci_phase);
144	r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL, XS_GREET);
145	if (r < 0)
146		goto tempfail1;
147	if (REPLYTYPE(r) == 4)
148		goto tempfail2;
149	if (REPLYTYPE(r) != 2)
150		goto unavailable;
151
152	/*
153	**  Send the HELO command.
154	**	My mother taught me to always introduce myself.
155	*/
156
157helo:
158	if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags))
159		mci->mci_flags |= MCIF_ESMTP;
160	if (mci->mci_heloname != NULL)
161	{
162#if _FFR_EXPAND_HELONAME
163		expand(mci->mci_heloname, hnbuf, sizeof(hnbuf), e);
164		hn = hnbuf;
165#else
166		hn = mci->mci_heloname;
167#endif
168	}
169	else
170		hn = MyHostName;
171
172tryhelo:
173#if _FFR_IGNORE_EXT_ON_HELO
174	mci->mci_flags &= ~MCIF_HELO;
175#endif
176	if (bitnset(M_LMTP, m->m_flags))
177	{
178		smtpmessage("LHLO %s", m, mci, hn);
179		SmtpPhase = mci->mci_phase = "client LHLO";
180	}
181	else if (bitset(MCIF_ESMTP, mci->mci_flags) &&
182		 !bitnset(M_FSMTP, m->m_flags))
183	{
184		smtpmessage("EHLO %s", m, mci, hn);
185		SmtpPhase = mci->mci_phase = "client EHLO";
186	}
187	else
188	{
189		smtpmessage("HELO %s", m, mci, hn);
190		SmtpPhase = mci->mci_phase = "client HELO";
191#if _FFR_IGNORE_EXT_ON_HELO
192		mci->mci_flags |= MCIF_HELO;
193#endif
194	}
195	sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
196			CurHostName, mci->mci_phase);
197	r = reply(m, mci, e,
198		  bitnset(M_LMTP, m->m_flags) ? TimeOuts.to_lhlo
199					      : TimeOuts.to_helo,
200		  helo_options, NULL, XS_EHLO);
201	if (r < 0)
202		goto tempfail1;
203	else if (REPLYTYPE(r) == 5)
204	{
205		if (bitset(MCIF_ESMTP, mci->mci_flags) &&
206		    !bitnset(M_LMTP, m->m_flags))
207		{
208			/* try old SMTP instead */
209			mci->mci_flags &= ~MCIF_ESMTP;
210			goto tryhelo;
211		}
212		goto unavailable;
213	}
214	else if (REPLYTYPE(r) != 2)
215		goto tempfail2;
216
217	/*
218	**  Check to see if we actually ended up talking to ourself.
219	**  This means we didn't know about an alias or MX, or we managed
220	**  to connect to an echo server.
221	*/
222
223	p = strchr(&SmtpReplyBuffer[4], ' ');
224	if (p != NULL)
225		*p = '\0';
226	if (!bitnset(M_NOLOOPCHECK, m->m_flags) &&
227	    !bitnset(M_LMTP, m->m_flags) &&
228	    sm_strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
229	{
230		syserr("553 5.3.5 %s config error: mail loops back to me (MX problem?)",
231			CurHostName);
232		mci_setstat(mci, EX_CONFIG, "5.3.5",
233			    "553 5.3.5 system config error");
234		mci->mci_errno = 0;
235		smtpquit(m, mci, e);
236		return;
237	}
238
239	/*
240	**  If this is expected to be another sendmail, send some internal
241	**  commands.
242	**  If we're running as MSP, "propagate" -v flag if possible.
243	*/
244
245	if ((UseMSP && Verbose && bitset(MCIF_VERB, mci->mci_flags))
246	    || bitnset(M_INTERNAL, m->m_flags))
247	{
248		/* tell it to be verbose */
249		smtpmessage("VERB", m, mci);
250		r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc,
251			XS_DEFAULT);
252		if (r < 0)
253			goto tempfail1;
254	}
255
256	if (mci->mci_state != MCIS_CLOSED)
257	{
258		mci->mci_state = MCIS_OPEN;
259		return;
260	}
261
262	/* got a 421 error code during startup */
263
264  tempfail1:
265	mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.4.2"), NULL);
266	if (mci->mci_state != MCIS_CLOSED)
267		smtpquit(m, mci, e);
268	return;
269
270  tempfail2:
271	/* XXX should use code from other end iff ENHANCEDSTATUSCODES */
272	mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
273		    SmtpReplyBuffer);
274	if (mci->mci_state != MCIS_CLOSED)
275		smtpquit(m, mci, e);
276	return;
277
278  unavailable:
279	mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer);
280	smtpquit(m, mci, e);
281	return;
282}
283/*
284**  ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
285**
286**	Parameters:
287**		line -- the response line.
288**		firstline -- set if this is the first line of the reply.
289**		m -- the mailer.
290**		mci -- the mailer connection info.
291**		e -- the envelope.
292**
293**	Returns:
294**		none.
295*/
296
297static void
298esmtp_check(line, firstline, m, mci, e)
299	char *line;
300	bool firstline;
301	MAILER *m;
302	register MCI *mci;
303	ENVELOPE *e;
304{
305	if (strstr(line, "ESMTP") != NULL)
306		mci->mci_flags |= MCIF_ESMTP;
307
308	/*
309	**  Dirty hack below. Quoting the author:
310	**  This was a response to people who wanted SMTP transmission to be
311	**  just-send-8 by default.  Essentially, you could put this tag into
312	**  your greeting message to behave as though the F=8 flag was set on
313	**  the mailer.
314	*/
315
316	if (strstr(line, "8BIT-OK") != NULL)
317		mci->mci_flags |= MCIF_8BITOK;
318}
319
320#if SASL
321/* specify prototype so compiler can check calls */
322static char *str_union __P((char *, char *, SM_RPOOL_T *));
323
324/*
325**  STR_UNION -- create the union of two lists
326**
327**	Parameters:
328**		s1, s2 -- lists of items (separated by single blanks).
329**		rpool -- resource pool from which result is allocated.
330**
331**	Returns:
332**		the union of both lists.
333*/
334
335static char *
336str_union(s1, s2, rpool)
337	char *s1, *s2;
338	SM_RPOOL_T *rpool;
339{
340	char *hr, *h1, *h, *res;
341	int l1, l2, rl;
342
343	if (s1 == NULL || *s1 == '\0')
344		return s2;
345	if (s2 == NULL || *s2 == '\0')
346		return s1;
347	l1 = strlen(s1);
348	l2 = strlen(s2);
349	rl = l1 + l2;
350	if (rl <= 0)
351	{
352		sm_syslog(LOG_WARNING, NOQID,
353			  "str_union: stringlen1=%d, stringlen2=%d, sum=%d, status=overflow",
354			  l1, l2, rl);
355		res = NULL;
356	}
357	else
358		res = (char *) sm_rpool_malloc(rpool, rl + 2);
359	if (res == NULL)
360	{
361		if (l1 > l2)
362			return s1;
363		return s2;
364	}
365	(void) sm_strlcpy(res, s1, rl);
366	hr = res + l1;
367	h1 = s2;
368	h = s2;
369
370	/* walk through s2 */
371	while (h != NULL && *h1 != '\0')
372	{
373		/* is there something after the current word? */
374		if ((h = strchr(h1, ' ')) != NULL)
375			*h = '\0';
376		l1 = strlen(h1);
377
378		/* does the current word appear in s1 ? */
379		if (iteminlist(h1, s1, " ") == NULL)
380		{
381			/* add space as delimiter */
382			*hr++ = ' ';
383
384			/* copy the item */
385			memcpy(hr, h1, l1);
386
387			/* advance pointer in result list */
388			hr += l1;
389			*hr = '\0';
390		}
391		if (h != NULL)
392		{
393			/* there are more items */
394			*h = ' ';
395			h1 = h + 1;
396		}
397	}
398	return res;
399}
400#endif /* SASL */
401
402/*
403**  HELO_OPTIONS -- process the options on a HELO line.
404**
405**	Parameters:
406**		line -- the response line.
407**		firstline -- set if this is the first line of the reply.
408**		m -- the mailer.
409**		mci -- the mailer connection info.
410**		e -- the envelope (unused).
411**
412**	Returns:
413**		none.
414*/
415
416static void
417helo_options(line, firstline, m, mci, e)
418	char *line;
419	bool firstline;
420	MAILER *m;
421	register MCI *mci;
422	ENVELOPE *e;
423{
424	register char *p;
425#if _FFR_IGNORE_EXT_ON_HELO
426	static bool logged = false;
427#endif
428
429	if (firstline)
430	{
431		mci_clr_extensions(mci);
432#if _FFR_IGNORE_EXT_ON_HELO
433		logged = false;
434#endif
435		return;
436	}
437#if _FFR_IGNORE_EXT_ON_HELO
438	else if (bitset(MCIF_HELO, mci->mci_flags))
439	{
440		if (LogLevel > 8 && !logged)
441		{
442			sm_syslog(LOG_WARNING, NOQID,
443				  "server=%s [%s] returned extensions despite HELO command",
444				  macvalue(macid("{server_name}"), e),
445				  macvalue(macid("{server_addr}"), e));
446			logged = true;
447		}
448		return;
449	}
450#endif /* _FFR_IGNORE_EXT_ON_HELO */
451
452	if (strlen(line) < 5)
453		return;
454	line += 4;
455	p = strpbrk(line, " =");
456	if (p != NULL)
457		*p++ = '\0';
458	if (sm_strcasecmp(line, "size") == 0)
459	{
460		mci->mci_flags |= MCIF_SIZE;
461		if (p != NULL)
462			mci->mci_maxsize = atol(p);
463	}
464	else if (sm_strcasecmp(line, "8bitmime") == 0)
465	{
466		mci->mci_flags |= MCIF_8BITMIME;
467		mci->mci_flags &= ~MCIF_7BIT;
468	}
469	else if (sm_strcasecmp(line, "expn") == 0)
470		mci->mci_flags |= MCIF_EXPN;
471	else if (sm_strcasecmp(line, "dsn") == 0)
472		mci->mci_flags |= MCIF_DSN;
473	else if (sm_strcasecmp(line, "enhancedstatuscodes") == 0)
474		mci->mci_flags |= MCIF_ENHSTAT;
475	else if (sm_strcasecmp(line, "pipelining") == 0)
476		mci->mci_flags |= MCIF_PIPELINED;
477	else if (sm_strcasecmp(line, "verb") == 0)
478		mci->mci_flags |= MCIF_VERB;
479#if _FFR_EAI
480	else if (sm_strcasecmp(line, "smtputf8") == 0)
481		mci->mci_flags |= MCIF_EAI;
482#endif /* _FFR_EAI */
483#if STARTTLS
484	else if (sm_strcasecmp(line, "starttls") == 0)
485		mci->mci_flags |= MCIF_TLS;
486#endif
487	else if (sm_strcasecmp(line, "deliverby") == 0)
488	{
489		mci->mci_flags |= MCIF_DLVR_BY;
490		if (p != NULL)
491			mci->mci_min_by = atol(p);
492	}
493#if SASL
494	else if (sm_strcasecmp(line, "auth") == 0)
495	{
496		if (p != NULL && *p != '\0' &&
497		    !bitset(MCIF_AUTH2, mci->mci_flags))
498		{
499			if (mci->mci_saslcap != NULL)
500			{
501				/*
502				**  Create the union with previous auth
503				**  offerings because we recognize "auth "
504				**  and "auth=" (old format).
505				*/
506
507				mci->mci_saslcap = str_union(mci->mci_saslcap,
508							     p, mci->mci_rpool);
509				mci->mci_flags |= MCIF_AUTH2;
510			}
511			else
512			{
513				int l;
514
515				l = strlen(p) + 1;
516				mci->mci_saslcap = (char *)
517					sm_rpool_malloc(mci->mci_rpool, l);
518				if (mci->mci_saslcap != NULL)
519				{
520					(void) sm_strlcpy(mci->mci_saslcap, p,
521							  l);
522					mci->mci_flags |= MCIF_AUTH;
523				}
524			}
525		}
526		if (tTd(95, 5))
527			sm_syslog(LOG_DEBUG, NOQID, "AUTH flags=%lx, mechs=%s",
528				mci->mci_flags, mci->mci_saslcap);
529	}
530#endif /* SASL */
531}
532#if SASL
533
534static int getsimple	__P((void *, int, const char **, unsigned *));
535static int getsecret	__P((sasl_conn_t *, void *, int, sasl_secret_t **));
536static int saslgetrealm	__P((void *, int, const char **, const char **));
537static int readauth	__P((char *, bool, SASL_AI_T *m, SM_RPOOL_T *));
538static int getauth	__P((MCI *, ENVELOPE *, SASL_AI_T *));
539static char *removemech	__P((char *, char *, SM_RPOOL_T *));
540static int attemptauth	__P((MAILER *, MCI *, ENVELOPE *, SASL_AI_T *));
541
542static sasl_callback_t callbacks[] =
543{
544	{	SASL_CB_GETREALM,	(sasl_callback_ft)&saslgetrealm,	NULL	},
545#define CB_GETREALM_IDX	0
546	{	SASL_CB_PASS,		(sasl_callback_ft)&getsecret,	NULL	},
547#define CB_PASS_IDX	1
548	{	SASL_CB_USER,		(sasl_callback_ft)&getsimple,	NULL	},
549#define CB_USER_IDX	2
550	{	SASL_CB_AUTHNAME,	(sasl_callback_ft)&getsimple,	NULL	},
551#define CB_AUTHNAME_IDX	3
552	{	SASL_CB_VERIFYFILE,	(sasl_callback_ft)&safesaslfile,	NULL	},
553#define CB_SAFESASL_IDX	4
554	{	SASL_CB_LIST_END,	NULL,		NULL	}
555};
556
557/*
558**  INIT_SASL_CLIENT -- initialize client side of Cyrus-SASL
559**
560**	Parameters:
561**		none.
562**
563**	Returns:
564**		SASL_OK -- if successful.
565**		SASL error code -- otherwise.
566**
567**	Side Effects:
568**		checks/sets sasl_clt_init.
569**
570**	Note:
571**	Callbacks are ignored if sasl_client_init() has
572**	been called before (by a library such as libnss_ldap)
573*/
574
575static bool sasl_clt_init = false;
576
577static int
578init_sasl_client()
579{
580	int result;
581
582	if (sasl_clt_init)
583		return SASL_OK;
584	result = sasl_client_init(callbacks);
585
586	/* should we retry later again or just remember that it failed? */
587	if (result == SASL_OK)
588		sasl_clt_init = true;
589	return result;
590}
591/*
592**  STOP_SASL_CLIENT -- shutdown client side of Cyrus-SASL
593**
594**	Parameters:
595**		none.
596**
597**	Returns:
598**		none.
599**
600**	Side Effects:
601**		checks/sets sasl_clt_init.
602*/
603
604void
605stop_sasl_client()
606{
607	if (!sasl_clt_init)
608		return;
609	sasl_clt_init = false;
610	sasl_done();
611}
612/*
613**  GETSASLDATA -- process the challenges from the SASL protocol
614**
615**	This gets the relevant sasl response data out of the reply
616**	from the server.
617**
618**	Parameters:
619**		line -- the response line.
620**		firstline -- set if this is the first line of the reply.
621**		m -- the mailer.
622**		mci -- the mailer connection info.
623**		e -- the envelope (unused).
624**
625**	Returns:
626**		none.
627*/
628
629static void getsasldata __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
630
631static void
632getsasldata(line, firstline, m, mci, e)
633	char *line;
634	bool firstline;
635	MAILER *m;
636	register MCI *mci;
637	ENVELOPE *e;
638{
639	int len;
640	int result;
641# if SASL < 20000
642	char *out;
643# endif
644
645	/* if not a continue we don't care about it */
646	len = strlen(line);
647	if ((len <= 4) ||
648	    (line[0] != '3') ||
649	     !isascii(line[1]) || !isdigit(line[1]) ||
650	     !isascii(line[2]) || !isdigit(line[2]))
651	{
652		SM_FREE(mci->mci_sasl_string);
653		return;
654	}
655
656	/* forget about "334 " */
657	line += 4;
658	len -= 4;
659# if SASL >= 20000
660	/* XXX put this into a macro/function? It's duplicated below */
661	if (mci->mci_sasl_string != NULL)
662	{
663		if (mci->mci_sasl_string_len <= len)
664		{
665			sm_free(mci->mci_sasl_string); /* XXX */
666			mci->mci_sasl_string = xalloc(len + 1);
667		}
668	}
669	else
670		mci->mci_sasl_string = xalloc(len + 1);
671
672	result = sasl_decode64(line, len, mci->mci_sasl_string, len + 1,
673			       (unsigned int *) &mci->mci_sasl_string_len);
674	if (result != SASL_OK)
675	{
676		mci->mci_sasl_string_len = 0;
677		*mci->mci_sasl_string = '\0';
678	}
679# else /* SASL >= 20000 */
680	out = (char *) sm_rpool_malloc_x(mci->mci_rpool, len + 1);
681	result = sasl_decode64(line, len, out, (unsigned int *) &len);
682	if (result != SASL_OK)
683	{
684		len = 0;
685		*out = '\0';
686	}
687
688	/*
689	**  mci_sasl_string is "shared" with Cyrus-SASL library; hence
690	**	it can't be in an rpool unless we use the same memory
691	**	management mechanism (with same rpool!) for Cyrus SASL.
692	*/
693
694	if (mci->mci_sasl_string != NULL)
695	{
696		if (mci->mci_sasl_string_len <= len)
697		{
698			sm_free(mci->mci_sasl_string); /* XXX */
699			mci->mci_sasl_string = xalloc(len + 1);
700		}
701	}
702	else
703		mci->mci_sasl_string = xalloc(len + 1);
704
705	memcpy(mci->mci_sasl_string, out, len);
706	mci->mci_sasl_string[len] = '\0';
707	mci->mci_sasl_string_len = len;
708# endif /* SASL >= 20000 */
709	return;
710}
711/*
712**  READAUTH -- read auth values from a file
713**
714**	Parameters:
715**		filename -- name of file to read.
716**		safe -- if set, this is a safe read.
717**		sai -- where to store auth_info.
718**		rpool -- resource pool for sai.
719**
720**	Returns:
721**		EX_OK -- data successfully read.
722**		EX_UNAVAILABLE -- no valid filename.
723**		EX_TEMPFAIL -- temporary failure.
724*/
725
726static char *sasl_info_name[] =
727{
728	"user id",
729	"authentication id",
730	"password",
731	"realm",
732	"mechlist"
733};
734static int
735readauth(filename, safe, sai, rpool)
736	char *filename;
737	bool safe;
738	SASL_AI_T *sai;
739	SM_RPOOL_T *rpool;
740{
741	SM_FILE_T *f;
742	long sff;
743	pid_t pid;
744	int lc;
745	char *s;
746	char buf[MAXLINE];
747
748	if (filename == NULL || filename[0] == '\0')
749		return EX_UNAVAILABLE;
750
751#if !_FFR_ALLOW_SASLINFO
752	/*
753	**  make sure we don't use a program that is not
754	**  accessible to the user who specified a different authinfo file.
755	**  However, currently we don't pass this info (authinfo file
756	**  specified by user) around, so we just turn off program access.
757	*/
758
759	if (filename[0] == '|')
760	{
761		auto int fd;
762		int i;
763		char *p;
764		char *argv[MAXPV + 1];
765
766		i = 0;
767		for (p = strtok(&filename[1], " \t"); p != NULL;
768		     p = strtok(NULL, " \t"))
769		{
770			if (i >= MAXPV)
771				break;
772			argv[i++] = p;
773		}
774		argv[i] = NULL;
775		pid = prog_open(argv, &fd, CurEnv);
776		if (pid < 0)
777			f = NULL;
778		else
779			f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
780				       (void *) &fd, SM_IO_RDONLY, NULL);
781	}
782	else
783#endif /* !_FFR_ALLOW_SASLINFO */
784	{
785		pid = -1;
786		sff = SFF_REGONLY|SFF_SAFEDIRPATH|SFF_NOWLINK
787		      |SFF_NOGWFILES|SFF_NOWWFILES|SFF_NOWRFILES;
788		if (!bitnset(DBS_GROUPREADABLEAUTHINFOFILE, DontBlameSendmail))
789			sff |= SFF_NOGRFILES;
790		if (DontLockReadFiles)
791			sff |= SFF_NOLOCK;
792
793#if _FFR_ALLOW_SASLINFO
794		/*
795		**  XXX: make sure we don't read or open files that are not
796		**  accessible to the user who specified a different authinfo
797		**  file.
798		*/
799
800		sff |= SFF_MUSTOWN;
801#else /* _FFR_ALLOW_SASLINFO */
802		if (safe)
803			sff |= SFF_OPENASROOT;
804#endif /* _FFR_ALLOW_SASLINFO */
805
806		f = safefopen(filename, O_RDONLY, 0, sff);
807	}
808	if (f == NULL)
809	{
810		if (LogLevel > 5)
811			sm_syslog(LOG_ERR, NOQID,
812				  "AUTH=client, error: can't open %s: %s",
813				  filename, sm_errstring(errno));
814		return EX_TEMPFAIL;
815	}
816
817	lc = 0;
818	while (lc <= SASL_MECHLIST &&
819		sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
820	{
821		if (buf[0] != '#')
822		{
823			(*sai)[lc] = sm_rpool_strdup_x(rpool, buf);
824			if ((s = strchr((*sai)[lc], '\n')) != NULL)
825				*s = '\0';
826			lc++;
827		}
828	}
829
830	(void) sm_io_close(f, SM_TIME_DEFAULT);
831	if (pid > 0)
832		(void) waitfor(pid);
833	if (lc < SASL_PASSWORD)
834	{
835		if (LogLevel > 8)
836			sm_syslog(LOG_ERR, NOQID,
837				  "AUTH=client, error: can't read %s from %s",
838				  sasl_info_name[lc + 1], filename);
839		return EX_TEMPFAIL;
840	}
841	return EX_OK;
842}
843
844/*
845**  GETAUTH -- get authinfo from ruleset call
846**
847**	{server_name}, {server_addr} must be set
848**
849**	Parameters:
850**		mci -- the mailer connection structure.
851**		e -- the envelope (including the sender to specify).
852**		sai -- pointer to authinfo (result).
853**
854**	Returns:
855**		EX_OK -- ruleset was successfully called, data may not
856**			be available, sai must be checked.
857**		EX_UNAVAILABLE -- ruleset unavailable (or failed).
858**		EX_TEMPFAIL -- temporary failure (from ruleset).
859**
860**	Side Effects:
861**		Fills in sai if successful.
862*/
863
864static int
865getauth(mci, e, sai)
866	MCI *mci;
867	ENVELOPE *e;
868	SASL_AI_T *sai;
869{
870	int i, r, l, got, ret;
871	char **pvp;
872	char pvpbuf[PSBUFSIZE];
873
874	r = rscap("authinfo", macvalue(macid("{server_name}"), e),
875		   macvalue(macid("{server_addr}"), e), e,
876		   &pvp, pvpbuf, sizeof(pvpbuf));
877
878	if (r != EX_OK)
879		return EX_UNAVAILABLE;
880
881	/* other than expected return value: ok (i.e., no auth) */
882	if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
883		return EX_OK;
884	if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
885		return EX_TEMPFAIL;
886
887	/*
888	**  parse the data, put it into sai
889	**  format: "TDstring" (including the '"' !)
890	**  where T is a tag: 'U', ...
891	**  D is a delimiter: ':' or '='
892	*/
893
894	ret = EX_OK;	/* default return value */
895	i = 0;
896	got = 0;
897	while (i < SASL_ENTRIES)
898	{
899		if (pvp[i + 1] == NULL)
900			break;
901		if (pvp[i + 1][0] != '"')
902			break;
903		switch (pvp[i + 1][1])
904		{
905		  case 'U':
906		  case 'u':
907			r = SASL_USER;
908			break;
909		  case 'I':
910		  case 'i':
911			r = SASL_AUTHID;
912			break;
913		  case 'P':
914		  case 'p':
915			r = SASL_PASSWORD;
916			break;
917		  case 'R':
918		  case 'r':
919			r = SASL_DEFREALM;
920			break;
921		  case 'M':
922		  case 'm':
923			r = SASL_MECHLIST;
924			break;
925		  default:
926			goto fail;
927		}
928		l = strlen(pvp[i + 1]);
929
930		/* check syntax */
931		if (l <= 3 || pvp[i + 1][l - 1] != '"')
932			goto fail;
933
934		/* remove closing quote */
935		pvp[i + 1][l - 1] = '\0';
936
937		/* remove "TD and " */
938		l -= 4;
939		(*sai)[r] = (char *) sm_rpool_malloc(mci->mci_rpool, l + 1);
940		if ((*sai)[r] == NULL)
941			goto tempfail;
942		if (pvp[i + 1][2] == ':')
943		{
944			/* ':text' (just copy) */
945			(void) sm_strlcpy((*sai)[r], pvp[i + 1] + 3, l + 1);
946			got |= 1 << r;
947		}
948		else if (pvp[i + 1][2] == '=')
949		{
950			unsigned int len;
951
952			/* '=base64' (decode) */
953# if SASL >= 20000
954			ret = sasl_decode64(pvp[i + 1] + 3,
955					  (unsigned int) l, (*sai)[r],
956					  (unsigned int) l + 1, &len);
957# else /* SASL >= 20000 */
958			ret = sasl_decode64(pvp[i + 1] + 3,
959					  (unsigned int) l, (*sai)[r], &len);
960# endif /* SASL >= 20000 */
961			if (ret != SASL_OK)
962				goto fail;
963			got |= 1 << r;
964		}
965		else
966			goto fail;
967		if (tTd(95, 5))
968			sm_syslog(LOG_DEBUG, NOQID, "getauth %s=%s",
969				  sasl_info_name[r], (*sai)[r]);
970		++i;
971	}
972
973	/* did we get the expected data? */
974	/* XXX: EXTERNAL mechanism only requires (and only uses) SASL_USER */
975	if (!(bitset(SASL_USER_BIT|SASL_AUTHID_BIT, got) &&
976	      bitset(SASL_PASSWORD_BIT, got)))
977		goto fail;
978
979	/* no authid? copy uid */
980	if (!bitset(SASL_AUTHID_BIT, got))
981	{
982		l = strlen((*sai)[SASL_USER]) + 1;
983		(*sai)[SASL_AUTHID] = (char *) sm_rpool_malloc(mci->mci_rpool,
984							       l + 1);
985		if ((*sai)[SASL_AUTHID] == NULL)
986			goto tempfail;
987		(void) sm_strlcpy((*sai)[SASL_AUTHID], (*sai)[SASL_USER], l);
988	}
989
990	/* no uid? copy authid */
991	if (!bitset(SASL_USER_BIT, got))
992	{
993		l = strlen((*sai)[SASL_AUTHID]) + 1;
994		(*sai)[SASL_USER] = (char *) sm_rpool_malloc(mci->mci_rpool,
995							     l + 1);
996		if ((*sai)[SASL_USER] == NULL)
997			goto tempfail;
998		(void) sm_strlcpy((*sai)[SASL_USER], (*sai)[SASL_AUTHID], l);
999	}
1000	return EX_OK;
1001
1002  tempfail:
1003	ret = EX_TEMPFAIL;
1004  fail:
1005	if (LogLevel > 8)
1006		sm_syslog(LOG_WARNING, NOQID,
1007			  "AUTH=client, relay=%.64s [%.16s], authinfo %sfailed",
1008			  macvalue(macid("{server_name}"), e),
1009			  macvalue(macid("{server_addr}"), e),
1010			  ret == EX_TEMPFAIL ? "temp" : "");
1011	for (i = 0; i <= SASL_MECHLIST; i++)
1012		(*sai)[i] = NULL;	/* just clear; rpool */
1013	return ret;
1014}
1015
1016# if SASL >= 20000
1017/*
1018**  GETSIMPLE -- callback to get userid or authid
1019**
1020**	Parameters:
1021**		context -- sai
1022**		id -- what to do
1023**		result -- (pointer to) result
1024**		len -- (pointer to) length of result
1025**
1026**	Returns:
1027**		OK/failure values
1028*/
1029
1030static int
1031getsimple(context, id, result, len)
1032	void *context;
1033	int id;
1034	const char **result;
1035	unsigned *len;
1036{
1037	SASL_AI_T *sai;
1038
1039	if (result == NULL || context == NULL)
1040		return SASL_BADPARAM;
1041	sai = (SASL_AI_T *) context;
1042
1043	switch (id)
1044	{
1045	  case SASL_CB_USER:
1046		*result = (*sai)[SASL_USER];
1047		if (tTd(95, 5))
1048			sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
1049				  *result);
1050		if (len != NULL)
1051			*len = *result != NULL ? strlen(*result) : 0;
1052		break;
1053
1054	  case SASL_CB_AUTHNAME:
1055		*result = (*sai)[SASL_AUTHID];
1056		if (tTd(95, 5))
1057			sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
1058				  *result);
1059		if (len != NULL)
1060			*len = *result != NULL ? strlen(*result) : 0;
1061		break;
1062
1063	  case SASL_CB_LANGUAGE:
1064		*result = NULL;
1065		if (len != NULL)
1066			*len = 0;
1067		break;
1068
1069	  default:
1070		return SASL_BADPARAM;
1071	}
1072	return SASL_OK;
1073}
1074/*
1075**  GETSECRET -- callback to get password
1076**
1077**	Parameters:
1078**		conn -- connection information
1079**		context -- sai
1080**		id -- what to do
1081**		psecret -- (pointer to) result
1082**
1083**	Returns:
1084**		OK/failure values
1085*/
1086
1087static int
1088getsecret(conn, context, id, psecret)
1089	sasl_conn_t *conn;
1090	SM_UNUSED(void *context);
1091	int id;
1092	sasl_secret_t **psecret;
1093{
1094	int len;
1095	char *authpass;
1096	MCI *mci;
1097
1098	if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
1099		return SASL_BADPARAM;
1100
1101	mci = (MCI *) context;
1102	authpass = mci->mci_sai[SASL_PASSWORD];
1103	len = strlen(authpass);
1104
1105	/*
1106	**  use an rpool because we are responsible for free()ing the secret,
1107	**  but we can't free() it until after the auth completes
1108	*/
1109
1110	*psecret = (sasl_secret_t *) sm_rpool_malloc(mci->mci_rpool,
1111						     sizeof(sasl_secret_t) +
1112						     len + 1);
1113	if (*psecret == NULL)
1114		return SASL_FAIL;
1115	(void) sm_strlcpy((char *) (*psecret)->data, authpass, len + 1);
1116	(*psecret)->len = (unsigned long) len;
1117	return SASL_OK;
1118}
1119# else /* SASL >= 20000 */
1120/*
1121**  GETSIMPLE -- callback to get userid or authid
1122**
1123**	Parameters:
1124**		context -- sai
1125**		id -- what to do
1126**		result -- (pointer to) result
1127**		len -- (pointer to) length of result
1128**
1129**	Returns:
1130**		OK/failure values
1131*/
1132
1133static int
1134getsimple(context, id, result, len)
1135	void *context;
1136	int id;
1137	const char **result;
1138	unsigned *len;
1139{
1140	char *h, *s;
1141# if SASL > 10509
1142	bool addrealm;
1143# endif
1144	size_t l;
1145	SASL_AI_T *sai;
1146	char *authid = NULL;
1147
1148	if (result == NULL || context == NULL)
1149		return SASL_BADPARAM;
1150	sai = (SASL_AI_T *) context;
1151
1152	/*
1153	**  Unfortunately it is not clear whether this routine should
1154	**  return a copy of a string or just a pointer to a string.
1155	**  The Cyrus-SASL plugins treat these return values differently, e.g.,
1156	**  plugins/cram.c free()s authid, plugings/digestmd5.c does not.
1157	**  The best solution to this problem is to fix Cyrus-SASL, but it
1158	**  seems there is nobody who creates patches... Hello CMU!?
1159	**  The second best solution is to have flags that tell this routine
1160	**  whether to return an malloc()ed copy.
1161	**  The next best solution is to always return an malloc()ed copy,
1162	**  and suffer from some memory leak, which is ugly for persistent
1163	**  queue runners.
1164	**  For now we go with the last solution...
1165	**  We can't use rpools (which would avoid this particular problem)
1166	**  as explained in sasl.c.
1167	*/
1168
1169	switch (id)
1170	{
1171	  case SASL_CB_USER:
1172		l = strlen((*sai)[SASL_USER]) + 1;
1173		s = sm_sasl_malloc(l);
1174		if (s == NULL)
1175		{
1176			if (len != NULL)
1177				*len = 0;
1178			*result = NULL;
1179			return SASL_NOMEM;
1180		}
1181		(void) sm_strlcpy(s, (*sai)[SASL_USER], l);
1182		*result = s;
1183		if (tTd(95, 5))
1184			sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
1185				  *result);
1186		if (len != NULL)
1187			*len = *result != NULL ? strlen(*result) : 0;
1188		break;
1189
1190	  case SASL_CB_AUTHNAME:
1191		h = (*sai)[SASL_AUTHID];
1192# if SASL > 10509
1193		/* XXX maybe other mechanisms too?! */
1194		addrealm = (*sai)[SASL_MECH] != NULL &&
1195			   sm_strcasecmp((*sai)[SASL_MECH], "CRAM-MD5") == 0;
1196
1197		/*
1198		**  Add realm to authentication id unless authid contains
1199		**  '@' (i.e., a realm) or the default realm is empty.
1200		*/
1201
1202		if (addrealm && h != NULL && strchr(h, '@') == NULL)
1203		{
1204			/* has this been done before? */
1205			if ((*sai)[SASL_ID_REALM] == NULL)
1206			{
1207				char *realm;
1208
1209				realm = (*sai)[SASL_DEFREALM];
1210
1211				/* do not add an empty realm */
1212				if (*realm == '\0')
1213				{
1214					authid = h;
1215					(*sai)[SASL_ID_REALM] = NULL;
1216				}
1217				else
1218				{
1219					l = strlen(h) + strlen(realm) + 2;
1220
1221					/* should use rpool, but from where? */
1222					authid = sm_sasl_malloc(l);
1223					if (authid != NULL)
1224					{
1225						(void) sm_snprintf(authid, l,
1226								  "%s@%s",
1227								   h, realm);
1228						(*sai)[SASL_ID_REALM] = authid;
1229					}
1230					else
1231					{
1232						authid = h;
1233						(*sai)[SASL_ID_REALM] = NULL;
1234					}
1235				}
1236			}
1237			else
1238				authid = (*sai)[SASL_ID_REALM];
1239		}
1240		else
1241# endif /* SASL > 10509 */
1242			authid = h;
1243		l = strlen(authid) + 1;
1244		s = sm_sasl_malloc(l);
1245		if (s == NULL)
1246		{
1247			if (len != NULL)
1248				*len = 0;
1249			*result = NULL;
1250			return SASL_NOMEM;
1251		}
1252		(void) sm_strlcpy(s, authid, l);
1253		*result = s;
1254		if (tTd(95, 5))
1255			sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
1256				  *result);
1257		if (len != NULL)
1258			*len = authid ? strlen(authid) : 0;
1259		break;
1260
1261	  case SASL_CB_LANGUAGE:
1262		*result = NULL;
1263		if (len != NULL)
1264			*len = 0;
1265		break;
1266
1267	  default:
1268		return SASL_BADPARAM;
1269	}
1270	return SASL_OK;
1271}
1272/*
1273**  GETSECRET -- callback to get password
1274**
1275**	Parameters:
1276**		conn -- connection information
1277**		context -- sai
1278**		id -- what to do
1279**		psecret -- (pointer to) result
1280**
1281**	Returns:
1282**		OK/failure values
1283*/
1284
1285static int
1286getsecret(conn, context, id, psecret)
1287	sasl_conn_t *conn;
1288	SM_UNUSED(void *context);
1289	int id;
1290	sasl_secret_t **psecret;
1291{
1292	int len;
1293	char *authpass;
1294	SASL_AI_T *sai;
1295
1296	if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
1297		return SASL_BADPARAM;
1298
1299	sai = (SASL_AI_T *) context;
1300	authpass = (*sai)[SASL_PASSWORD];
1301	len = strlen(authpass);
1302	*psecret = (sasl_secret_t *) sm_sasl_malloc(sizeof(sasl_secret_t) +
1303						    len + 1);
1304	if (*psecret == NULL)
1305		return SASL_FAIL;
1306	(void) sm_strlcpy((*psecret)->data, authpass, len + 1);
1307	(*psecret)->len = (unsigned long) len;
1308	return SASL_OK;
1309}
1310# endif /* SASL >= 20000 */
1311
1312/*
1313**  SAFESASLFILE -- callback for sasl: is file safe?
1314**
1315**	Parameters:
1316**		context -- pointer to context between invocations (unused)
1317**		file -- name of file to check
1318**		type -- type of file to check
1319**
1320**	Returns:
1321**		SASL_OK -- file can be used
1322**		SASL_CONTINUE -- don't use file
1323**		SASL_FAIL -- failure (not used here)
1324**
1325*/
1326
1327int
1328#if SASL > 10515
1329safesaslfile(context, file, type)
1330#else
1331safesaslfile(context, file)
1332#endif
1333	void *context;
1334# if SASL >= 20000
1335	const char *file;
1336# else
1337	char *file;
1338# endif
1339#if SASL > 10515
1340# if SASL >= 20000
1341	sasl_verify_type_t type;
1342# else
1343	int type;
1344# endif
1345#endif
1346{
1347	long sff;
1348	int r;
1349#if SASL <= 10515
1350	size_t len;
1351#endif
1352	char *p;
1353
1354	if (file == NULL || *file == '\0')
1355		return SASL_OK;
1356	if (tTd(95, 16))
1357		sm_dprintf("safesaslfile=%s\n", file);
1358	sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOWWFILES|SFF_ROOTOK;
1359#if SASL <= 10515
1360	if ((p = strrchr(file, '/')) == NULL)
1361		p = file;
1362	else
1363		++p;
1364
1365	/* everything beside libs and .conf files must not be readable */
1366	len = strlen(p);
1367	if ((len <= 3 || strncmp(p, "lib", 3) != 0) &&
1368	    (len <= 5 || strncmp(p + len - 5, ".conf", 5) != 0))
1369	{
1370		if (!bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
1371			sff |= SFF_NORFILES;
1372		if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
1373			sff |= SFF_NOGWFILES;
1374	}
1375#else /* SASL <= 10515 */
1376	/* files containing passwords should be not readable */
1377	if (type == SASL_VRFY_PASSWD)
1378	{
1379		if (bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
1380			sff |= SFF_NOWRFILES;
1381		else
1382			sff |= SFF_NORFILES;
1383		if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
1384			sff |= SFF_NOGWFILES;
1385	}
1386#endif /* SASL <= 10515 */
1387
1388	p = (char *) file;
1389	if ((r = safefile(p, RunAsUid, RunAsGid, RunAsUserName, sff,
1390			  S_IRUSR, NULL)) == 0)
1391		return SASL_OK;
1392	if (LogLevel > (r != ENOENT ? 8 : 10))
1393		sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s",
1394			  p, sm_errstring(r));
1395	return SASL_CONTINUE;
1396}
1397
1398/*
1399**  SASLGETREALM -- return the realm for SASL
1400**
1401**	return the realm for the client
1402**
1403**	Parameters:
1404**		context -- context shared between invocations
1405**		availrealms -- list of available realms
1406**			{realm, realm, ...}
1407**		result -- pointer to result
1408**
1409**	Returns:
1410**		failure/success
1411*/
1412
1413static int
1414saslgetrealm(context, id, availrealms, result)
1415	void *context;
1416	int id;
1417	const char **availrealms;
1418	const char **result;
1419{
1420	char *r;
1421	SASL_AI_T *sai;
1422
1423	sai = (SASL_AI_T *) context;
1424	if (sai == NULL)
1425		return SASL_FAIL;
1426	r = (*sai)[SASL_DEFREALM];
1427
1428	if (LogLevel > 12)
1429		sm_syslog(LOG_INFO, NOQID,
1430			  "AUTH=client, realm=%s, available realms=%s",
1431			  r == NULL ? "<No Realm>" : r,
1432			  (availrealms == NULL || *availrealms == NULL)
1433				? "<No Realms>" : *availrealms);
1434
1435	/* check whether context is in list */
1436	if (availrealms != NULL && *availrealms != NULL)
1437	{
1438		if (iteminlist(context, (char *)(*availrealms + 1), " ,}") ==
1439		    NULL)
1440		{
1441			if (LogLevel > 8)
1442				sm_syslog(LOG_ERR, NOQID,
1443					  "AUTH=client, realm=%s not in list=%s",
1444					  r, *availrealms);
1445			return SASL_FAIL;
1446		}
1447	}
1448	*result = r;
1449	return SASL_OK;
1450}
1451/*
1452**  ITEMINLIST -- does item appear in list?
1453**
1454**	Check whether item appears in list (which must be separated by a
1455**	character in delim) as a "word", i.e. it must appear at the begin
1456**	of the list or after a space, and it must end with a space or the
1457**	end of the list.
1458**
1459**	Parameters:
1460**		item -- item to search.
1461**		list -- list of items.
1462**		delim -- list of delimiters.
1463**
1464**	Returns:
1465**		pointer to occurrence (NULL if not found).
1466*/
1467
1468char *
1469iteminlist(item, list, delim)
1470	char *item;
1471	char *list;
1472	char *delim;
1473{
1474	char *s;
1475	int len;
1476
1477	if (list == NULL || *list == '\0')
1478		return NULL;
1479	if (item == NULL || *item == '\0')
1480		return NULL;
1481	s = list;
1482	len = strlen(item);
1483	while (s != NULL && *s != '\0')
1484	{
1485		if (sm_strncasecmp(s, item, len) == 0 &&
1486		    (s[len] == '\0' || strchr(delim, s[len]) != NULL))
1487			return s;
1488		s = strpbrk(s, delim);
1489		if (s != NULL)
1490			while (*++s == ' ')
1491				continue;
1492	}
1493	return NULL;
1494}
1495/*
1496**  REMOVEMECH -- remove item [rem] from list [list]
1497**
1498**	Parameters:
1499**		rem -- item to remove
1500**		list -- list of items
1501**		rpool -- resource pool from which result is allocated.
1502**
1503**	Returns:
1504**		pointer to new list (NULL in case of error).
1505*/
1506
1507static char *
1508removemech(rem, list, rpool)
1509	char *rem;
1510	char *list;
1511	SM_RPOOL_T *rpool;
1512{
1513	char *ret;
1514	char *needle;
1515	int len;
1516
1517	if (list == NULL)
1518		return NULL;
1519	if (rem == NULL || *rem == '\0')
1520	{
1521		/* take out what? */
1522		return NULL;
1523	}
1524
1525	/* find the item in the list */
1526	if ((needle = iteminlist(rem, list, " ")) == NULL)
1527	{
1528		/* not in there: return original */
1529		return list;
1530	}
1531
1532	/* length of string without rem */
1533	len = strlen(list) - strlen(rem);
1534	if (len <= 0)
1535	{
1536		ret = (char *) sm_rpool_malloc_x(rpool, 1);
1537		*ret = '\0';
1538		return ret;
1539	}
1540	ret = (char *) sm_rpool_malloc_x(rpool, len);
1541	memset(ret, '\0', len);
1542
1543	/* copy from start to removed item */
1544	memcpy(ret, list, needle - list);
1545
1546	/* length of rest of string past removed item */
1547	len = strlen(needle) - strlen(rem) - 1;
1548	if (len > 0)
1549	{
1550		/* not last item -- copy into string */
1551		memcpy(ret + (needle - list),
1552		       list + (needle - list) + strlen(rem) + 1,
1553		       len);
1554	}
1555	else
1556		ret[(needle - list) - 1] = '\0';
1557	return ret;
1558}
1559/*
1560**  ATTEMPTAUTH -- try to AUTHenticate using one mechanism
1561**
1562**	Parameters:
1563**		m -- the mailer.
1564**		mci -- the mailer connection structure.
1565**		e -- the envelope (including the sender to specify).
1566**		sai - sasl authinfo
1567**
1568**	Returns:
1569**		EX_OK -- authentication was successful.
1570**		EX_NOPERM -- authentication failed.
1571**		EX_IOERR -- authentication dialogue failed (I/O problem?).
1572**		EX_TEMPFAIL -- temporary failure.
1573**
1574*/
1575
1576static int
1577attemptauth(m, mci, e, sai)
1578	MAILER *m;
1579	MCI *mci;
1580	ENVELOPE *e;
1581	SASL_AI_T *sai;
1582{
1583	int saslresult, smtpresult;
1584# if SASL >= 20000
1585	sasl_ssf_t ssf;
1586	const char *auth_id;
1587	const char *out;
1588# else /* SASL >= 20000 */
1589	sasl_external_properties_t ssf;
1590	char *out;
1591# endif /* SASL >= 20000 */
1592	unsigned int outlen;
1593	sasl_interact_t *client_interact = NULL;
1594	char *mechusing;
1595	sasl_security_properties_t ssp;
1596
1597	/* MUST NOT be a multiple of 4: bug in some sasl_encode64() versions */
1598	char in64[MAXOUTLEN + 1];
1599#if NETINET || (NETINET6 && SASL >= 20000)
1600	extern SOCKADDR CurHostAddr;
1601#endif
1602
1603	/* no mechanism selected (yet) */
1604	(*sai)[SASL_MECH] = NULL;
1605
1606	/* dispose old connection */
1607	if (mci->mci_conn != NULL)
1608		sasl_dispose(&(mci->mci_conn));
1609
1610	/* make a new client sasl connection */
1611# if SASL >= 20000
1612	/*
1613	**  We provide the callbacks again because global callbacks in
1614	**  sasl_client_init() are ignored if SASL has been initialized
1615	**  before, for example, by a library such as libnss-ldap.
1616	*/
1617
1618	saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
1619								 : "smtp",
1620				     CurHostName, NULL, NULL, callbacks, 0,
1621				     &mci->mci_conn);
1622# else /* SASL >= 20000 */
1623	saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
1624								 : "smtp",
1625				     CurHostName, NULL, 0, &mci->mci_conn);
1626# endif /* SASL >= 20000 */
1627	if (saslresult != SASL_OK)
1628		return EX_TEMPFAIL;
1629
1630	/* set properties */
1631	(void) memset(&ssp, '\0', sizeof(ssp));
1632
1633	/* XXX should these be options settable via .cf ? */
1634	ssp.max_ssf = MaxSLBits;
1635	ssp.maxbufsize = MAXOUTLEN;
1636#  if 0
1637	ssp.security_flags = SASL_SEC_NOPLAINTEXT;
1638#  endif
1639	saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp);
1640	if (saslresult != SASL_OK)
1641		return EX_TEMPFAIL;
1642
1643# if SASL >= 20000
1644	/* external security strength factor, authentication id */
1645	ssf = 0;
1646	auth_id = NULL;
1647#  if STARTTLS
1648	out = macvalue(macid("{cert_subject}"), e);
1649	if (out != NULL && *out != '\0')
1650		auth_id = out;
1651	out = macvalue(macid("{cipher_bits}"), e);
1652	if (out != NULL && *out != '\0')
1653		ssf = atoi(out);
1654#  endif /* STARTTLS */
1655	saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
1656	if (saslresult != SASL_OK)
1657		return EX_TEMPFAIL;
1658	saslresult = sasl_setprop(mci->mci_conn, SASL_AUTH_EXTERNAL, auth_id);
1659	if (saslresult != SASL_OK)
1660		return EX_TEMPFAIL;
1661
1662#  if NETINET || NETINET6
1663	/* set local/remote ipv4 addresses */
1664	if (mci->mci_out != NULL && (
1665#   if NETINET6
1666		CurHostAddr.sa.sa_family == AF_INET6 ||
1667#   endif
1668		CurHostAddr.sa.sa_family == AF_INET))
1669	{
1670		SOCKADDR_LEN_T addrsize;
1671		SOCKADDR saddr_l;
1672		char localip[60], remoteip[60];
1673
1674		switch (CurHostAddr.sa.sa_family)
1675		{
1676		  case AF_INET:
1677			addrsize = sizeof(struct sockaddr_in);
1678			break;
1679#   if NETINET6
1680		  case AF_INET6:
1681			addrsize = sizeof(struct sockaddr_in6);
1682			break;
1683#   endif
1684		  default:
1685			break;
1686		}
1687		if (iptostring(&CurHostAddr, addrsize,
1688			       remoteip, sizeof(remoteip)))
1689		{
1690			if (sasl_setprop(mci->mci_conn, SASL_IPREMOTEPORT,
1691					 remoteip) != SASL_OK)
1692				return EX_TEMPFAIL;
1693		}
1694		addrsize = sizeof(saddr_l);
1695		if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
1696					      NULL),
1697				(struct sockaddr *) &saddr_l, &addrsize) == 0)
1698		{
1699			if (iptostring(&saddr_l, addrsize,
1700				       localip, sizeof(localip)))
1701			{
1702				if (sasl_setprop(mci->mci_conn,
1703						 SASL_IPLOCALPORT,
1704						 localip) != SASL_OK)
1705					return EX_TEMPFAIL;
1706			}
1707		}
1708	}
1709#  endif /* NETINET || NETINET6 */
1710
1711	/* start client side of sasl */
1712	saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
1713				       &client_interact,
1714				       &out, &outlen,
1715				       (const char **) &mechusing);
1716# else /* SASL >= 20000 */
1717	/* external security strength factor, authentication id */
1718	ssf.ssf = 0;
1719	ssf.auth_id = NULL;
1720#  if STARTTLS
1721	out = macvalue(macid("{cert_subject}"), e);
1722	if (out != NULL && *out != '\0')
1723		ssf.auth_id = out;
1724	out = macvalue(macid("{cipher_bits}"), e);
1725	if (out != NULL && *out != '\0')
1726		ssf.ssf = atoi(out);
1727#  endif /* STARTTLS */
1728	saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
1729	if (saslresult != SASL_OK)
1730		return EX_TEMPFAIL;
1731
1732#  if NETINET
1733	/* set local/remote ipv4 addresses */
1734	if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET)
1735	{
1736		SOCKADDR_LEN_T addrsize;
1737		struct sockaddr_in saddr_l;
1738
1739		if (sasl_setprop(mci->mci_conn, SASL_IP_REMOTE,
1740				 (struct sockaddr_in *) &CurHostAddr)
1741		    != SASL_OK)
1742			return EX_TEMPFAIL;
1743		addrsize = sizeof(struct sockaddr_in);
1744		if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
1745					      NULL),
1746				(struct sockaddr *) &saddr_l, &addrsize) == 0)
1747		{
1748			if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL,
1749					 &saddr_l) != SASL_OK)
1750				return EX_TEMPFAIL;
1751		}
1752	}
1753#  endif /* NETINET */
1754
1755	/* start client side of sasl */
1756	saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
1757				       NULL, &client_interact,
1758				       &out, &outlen,
1759				       (const char **) &mechusing);
1760# endif /* SASL >= 20000 */
1761
1762	if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
1763	{
1764		if (saslresult == SASL_NOMECH && LogLevel > 8)
1765		{
1766			sm_syslog(LOG_NOTICE, e->e_id,
1767				  "AUTH=client, available mechanisms=%s do not fulfill requirements", mci->mci_saslcap);
1768		}
1769		return EX_TEMPFAIL;
1770	}
1771
1772	/* just point current mechanism to the data in the sasl library */
1773	(*sai)[SASL_MECH] = mechusing;
1774
1775	/* send the info across the wire */
1776	if (out == NULL
1777		/* login and digest-md5 up to 1.5.28 set out="" */
1778	    || (outlen == 0 &&
1779		(sm_strcasecmp(mechusing, "LOGIN") == 0 ||
1780		 sm_strcasecmp(mechusing, "DIGEST-MD5") == 0))
1781	   )
1782	{
1783		/* no initial response */
1784		smtpmessage("AUTH %s", m, mci, mechusing);
1785	}
1786	else if (outlen == 0)
1787	{
1788		/*
1789		**  zero-length initial response, per RFC 2554 4.:
1790		**  "Unlike a zero-length client answer to a 334 reply, a zero-
1791		**  length initial response is sent as a single equals sign"
1792		*/
1793
1794		smtpmessage("AUTH %s =", m, mci, mechusing);
1795	}
1796	else
1797	{
1798		saslresult = sasl_encode64(out, outlen, in64, sizeof(in64),
1799					   NULL);
1800		if (saslresult != SASL_OK) /* internal error */
1801		{
1802			if (LogLevel > 8)
1803				sm_syslog(LOG_ERR, e->e_id,
1804					"encode64 for AUTH failed");
1805			return EX_TEMPFAIL;
1806		}
1807		smtpmessage("AUTH %s %s", m, mci, mechusing, in64);
1808	}
1809# if SASL < 20000
1810	sm_sasl_free(out); /* XXX only if no rpool is used */
1811# endif
1812
1813	/* get the reply */
1814	smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL,
1815			XS_AUTH);
1816
1817	for (;;)
1818	{
1819		/* check return code from server */
1820		if (smtpresult == 235)
1821		{
1822			macdefine(&mci->mci_macro, A_TEMP, macid("{auth_type}"),
1823				  mechusing);
1824			return EX_OK;
1825		}
1826		if (smtpresult == -1)
1827			return EX_IOERR;
1828		if (REPLYTYPE(smtpresult) == 5)
1829			return EX_NOPERM;	/* ugly, but ... */
1830		if (REPLYTYPE(smtpresult) != 3)
1831		{
1832			/* should we fail deliberately, see RFC 2554 4. ? */
1833			/* smtpmessage("*", m, mci); */
1834			return EX_TEMPFAIL;
1835		}
1836
1837		saslresult = sasl_client_step(mci->mci_conn,
1838					      mci->mci_sasl_string,
1839					      mci->mci_sasl_string_len,
1840					      &client_interact,
1841					      &out, &outlen);
1842
1843		if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
1844		{
1845			if (tTd(95, 5))
1846				sm_dprintf("AUTH FAIL=%s (%d)\n",
1847					sasl_errstring(saslresult, NULL, NULL),
1848					saslresult);
1849
1850			/* fail deliberately, see RFC 2554 4. */
1851			smtpmessage("*", m, mci);
1852
1853			/*
1854			**  but we should only fail for this authentication
1855			**  mechanism; how to do that?
1856			*/
1857
1858			smtpresult = reply(m, mci, e, TimeOuts.to_auth,
1859					   getsasldata, NULL, XS_AUTH);
1860			return EX_NOPERM;
1861		}
1862
1863		if (outlen > 0)
1864		{
1865			saslresult = sasl_encode64(out, outlen, in64,
1866						   sizeof(in64), NULL);
1867			if (saslresult != SASL_OK)
1868			{
1869				/* give an error reply to the other side! */
1870				smtpmessage("*", m, mci);
1871				return EX_TEMPFAIL;
1872			}
1873		}
1874		else
1875			in64[0] = '\0';
1876# if SASL < 20000
1877		sm_sasl_free(out); /* XXX only if no rpool is used */
1878# endif
1879		smtpmessage("%s", m, mci, in64);
1880		smtpresult = reply(m, mci, e, TimeOuts.to_auth,
1881				   getsasldata, NULL, XS_AUTH);
1882	}
1883	/* NOTREACHED */
1884}
1885/*
1886**  SMTPAUTH -- try to AUTHenticate
1887**
1888**	This will try mechanisms in the order the sasl library decided until:
1889**	- there are no more mechanisms
1890**	- a mechanism succeeds
1891**	- the sasl library fails initializing
1892**
1893**	Parameters:
1894**		m -- the mailer.
1895**		mci -- the mailer connection info.
1896**		e -- the envelope.
1897**
1898**	Returns:
1899**		EX_OK -- authentication was successful
1900**		EX_UNAVAILABLE -- authentication not possible, e.g.,
1901**			no data available.
1902**		EX_NOPERM -- authentication failed.
1903**		EX_TEMPFAIL -- temporary failure.
1904**
1905**	Notice: AuthInfo is used for all connections, hence we must
1906**		return EX_TEMPFAIL only if we really want to retry, i.e.,
1907**		iff getauth() tempfailed or getauth() was used and
1908**		authentication tempfailed.
1909*/
1910
1911int
1912smtpauth(m, mci, e)
1913	MAILER *m;
1914	MCI *mci;
1915	ENVELOPE *e;
1916{
1917	int result;
1918	int i;
1919	bool usedgetauth;
1920
1921	mci->mci_sasl_auth = false;
1922	for (i = 0; i < SASL_MECH ; i++)
1923		mci->mci_sai[i] = NULL;
1924
1925	result = getauth(mci, e, &(mci->mci_sai));
1926	if (result == EX_TEMPFAIL)
1927		return result;
1928	usedgetauth = true;
1929
1930	/* no data available: don't try to authenticate */
1931	if (result == EX_OK && mci->mci_sai[SASL_AUTHID] == NULL)
1932		return result;
1933	if (result != EX_OK)
1934	{
1935		if (SASLInfo == NULL)
1936			return EX_UNAVAILABLE;
1937
1938		/* read authinfo from file */
1939		result = readauth(SASLInfo, true, &(mci->mci_sai),
1940				  mci->mci_rpool);
1941		if (result != EX_OK)
1942			return result;
1943		usedgetauth = false;
1944	}
1945
1946	/* check whether sufficient data is available */
1947	if (mci->mci_sai[SASL_PASSWORD] == NULL ||
1948	    *(mci->mci_sai)[SASL_PASSWORD] == '\0')
1949		return EX_UNAVAILABLE;
1950	if ((mci->mci_sai[SASL_AUTHID] == NULL ||
1951	     *(mci->mci_sai)[SASL_AUTHID] == '\0') &&
1952	    (mci->mci_sai[SASL_USER] == NULL ||
1953	     *(mci->mci_sai)[SASL_USER] == '\0'))
1954		return EX_UNAVAILABLE;
1955
1956	/* set the context for the callback function to sai */
1957# if SASL >= 20000
1958	callbacks[CB_PASS_IDX].context = (void *) mci;
1959# else
1960	callbacks[CB_PASS_IDX].context = (void *) &mci->mci_sai;
1961# endif
1962	callbacks[CB_USER_IDX].context = (void *) &mci->mci_sai;
1963	callbacks[CB_AUTHNAME_IDX].context = (void *) &mci->mci_sai;
1964	callbacks[CB_GETREALM_IDX].context = (void *) &mci->mci_sai;
1965#if 0
1966	callbacks[CB_SAFESASL_IDX].context = (void *) &mci->mci_sai;
1967#endif
1968
1969	/* set default value for realm */
1970	if ((mci->mci_sai)[SASL_DEFREALM] == NULL)
1971		(mci->mci_sai)[SASL_DEFREALM] = sm_rpool_strdup_x(e->e_rpool,
1972							macvalue('j', CurEnv));
1973
1974	/* set default value for list of mechanism to use */
1975	if ((mci->mci_sai)[SASL_MECHLIST] == NULL ||
1976	    *(mci->mci_sai)[SASL_MECHLIST] == '\0')
1977		(mci->mci_sai)[SASL_MECHLIST] = AuthMechanisms;
1978
1979	/* create list of mechanisms to try */
1980	mci->mci_saslcap = intersect((mci->mci_sai)[SASL_MECHLIST],
1981				     mci->mci_saslcap, mci->mci_rpool);
1982
1983	/* initialize sasl client library */
1984	result = init_sasl_client();
1985	if (result != SASL_OK)
1986		return usedgetauth ? EX_TEMPFAIL : EX_UNAVAILABLE;
1987	do
1988	{
1989		result = attemptauth(m, mci, e, &(mci->mci_sai));
1990		if (result == EX_OK)
1991			mci->mci_sasl_auth = true;
1992		else if (result == EX_TEMPFAIL || result == EX_NOPERM)
1993		{
1994			mci->mci_saslcap = removemech((mci->mci_sai)[SASL_MECH],
1995						      mci->mci_saslcap,
1996						      mci->mci_rpool);
1997			if (mci->mci_saslcap == NULL ||
1998			    *(mci->mci_saslcap) == '\0')
1999				return usedgetauth ? result
2000						   : EX_UNAVAILABLE;
2001		}
2002		else
2003			return result;
2004	} while (result != EX_OK);
2005	return result;
2006}
2007#endif /* SASL */
2008
2009/*
2010**  SMTPMAILFROM -- send MAIL command
2011**
2012**	Parameters:
2013**		m -- the mailer.
2014**		mci -- the mailer connection structure.
2015**		e -- the envelope (including the sender to specify).
2016*/
2017
2018int
2019smtpmailfrom(m, mci, e)
2020	MAILER *m;
2021	MCI *mci;
2022	ENVELOPE *e;
2023{
2024	int r;
2025	char *bufp;
2026	char *bodytype;
2027	char *enhsc;
2028	char buf[MAXNAME + 1];
2029	char optbuf[MAXLINE];
2030
2031	if (tTd(18, 2))
2032		sm_dprintf("smtpmailfrom: CurHost=%s\n", CurHostName);
2033	enhsc = NULL;
2034
2035	/*
2036	**  Check if connection is gone, if so
2037	**  it's a tempfail and we use mci_errno
2038	**  for the reason.
2039	*/
2040
2041	if (mci->mci_state == MCIS_CLOSED)
2042	{
2043		errno = mci->mci_errno;
2044		return EX_TEMPFAIL;
2045	}
2046
2047#if _FFR_EAI
2048	/*
2049	**  Abort right away if the message needs SMTPUTF8 and the
2050	**  server does not advertise SMTPUTF8.
2051	*/
2052
2053	if (e->e_smtputf8 && !bitset(MCIF_EAI, mci->mci_flags)) {
2054		usrerrenh("5.6.7", "%s does not support SMTPUTF8", CurHostName);
2055		mci_setstat(mci, EX_NOTSTICKY, "5.6.7", NULL);
2056		return EX_DATAERR;
2057	}
2058#endif /* _FFR_EAI */
2059
2060	/* set up appropriate options to include */
2061	if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
2062	{
2063		(void) sm_snprintf(optbuf, sizeof(optbuf), " SIZE=%ld",
2064			e->e_msgsize);
2065		bufp = &optbuf[strlen(optbuf)];
2066	}
2067	else
2068	{
2069		optbuf[0] = '\0';
2070		bufp = optbuf;
2071	}
2072
2073#if _FFR_EAI
2074	if (e->e_smtputf8) {
2075		(void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2076				 " SMTPUTF8");
2077		bufp += strlen(bufp);
2078	}
2079#endif /* _FFR_EAI */
2080
2081	bodytype = e->e_bodytype;
2082	if (bitset(MCIF_8BITMIME, mci->mci_flags))
2083	{
2084		if (bodytype == NULL &&
2085		    bitset(MM_MIME8BIT, MimeMode) &&
2086		    bitset(EF_HAS8BIT, e->e_flags) &&
2087		    !bitset(EF_DONT_MIME, e->e_flags) &&
2088		    !bitnset(M_8BITS, m->m_flags))
2089			bodytype = "8BITMIME";
2090		if (bodytype != NULL &&
2091		    SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
2092		{
2093			(void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2094				 " BODY=%s", bodytype);
2095			bufp += strlen(bufp);
2096		}
2097	}
2098	else if (bitnset(M_8BITS, m->m_flags) ||
2099		 !bitset(EF_HAS8BIT, e->e_flags) ||
2100		 bitset(MCIF_8BITOK, mci->mci_flags))
2101	{
2102		/* EMPTY */
2103		/* just pass it through */
2104	}
2105#if MIME8TO7
2106	else if (bitset(MM_CVTMIME, MimeMode) &&
2107		 !bitset(EF_DONT_MIME, e->e_flags) &&
2108		 (!bitset(MM_PASS8BIT, MimeMode) ||
2109		  bitset(EF_IS_MIME, e->e_flags)))
2110	{
2111		/* must convert from 8bit MIME format to 7bit encoded */
2112		mci->mci_flags |= MCIF_CVT8TO7;
2113	}
2114#endif /* MIME8TO7 */
2115	else if (!bitset(MM_PASS8BIT, MimeMode))
2116	{
2117		/* cannot just send a 8-bit version */
2118		extern char MsgBuf[];
2119
2120		usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName);
2121		mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
2122		return EX_DATAERR;
2123	}
2124
2125	if (bitset(MCIF_DSN, mci->mci_flags))
2126	{
2127		if (e->e_envid != NULL &&
2128		    SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
2129		{
2130			(void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2131				 " ENVID=%s", e->e_envid);
2132			bufp += strlen(bufp);
2133		}
2134
2135		/* RET= parameter */
2136		if (bitset(EF_RET_PARAM, e->e_flags) &&
2137		    SPACELEFT(optbuf, bufp) > 9)
2138		{
2139			(void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2140				 " RET=%s",
2141				 bitset(EF_NO_BODY_RETN, e->e_flags) ?
2142					"HDRS" : "FULL");
2143			bufp += strlen(bufp);
2144		}
2145	}
2146
2147	if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL &&
2148	    SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7
2149#if SASL
2150	     && (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth)
2151#endif
2152	    )
2153	{
2154		(void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2155			 " AUTH=%s", e->e_auth_param);
2156		bufp += strlen(bufp);
2157	}
2158
2159	/*
2160	**  17 is the max length required, we could use log() to compute
2161	**  the exact length (and check IS_DLVR_TRACE())
2162	*/
2163
2164	if (bitset(MCIF_DLVR_BY, mci->mci_flags) &&
2165	    IS_DLVR_BY(e) && SPACELEFT(optbuf, bufp) > 17)
2166	{
2167		long dby;
2168
2169		/*
2170		**  Avoid problems with delays (for R) since the check
2171		**  in deliver() whether min-deliver-time is sufficient.
2172		**  Alternatively we could pass the computed time to this
2173		**  function.
2174		*/
2175
2176		dby = e->e_deliver_by - (curtime() - e->e_ctime);
2177		if (dby <= 0 && IS_DLVR_RETURN(e))
2178			dby = mci->mci_min_by <= 0 ? 1 : mci->mci_min_by;
2179		(void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2180			" BY=%ld;%c%s",
2181			dby,
2182			IS_DLVR_RETURN(e) ? 'R' : 'N',
2183			IS_DLVR_TRACE(e) ? "T" : "");
2184		bufp += strlen(bufp);
2185	}
2186
2187	/*
2188	**  Send the MAIL command.
2189	**	Designates the sender.
2190	*/
2191
2192	mci->mci_state = MCIS_MAIL;
2193
2194	if (bitset(EF_RESPONSE, e->e_flags) &&
2195	    !bitnset(M_NO_NULL_FROM, m->m_flags))
2196		buf[0] = '\0';
2197	else
2198		expand("\201g", buf, sizeof(buf), e);
2199	if (buf[0] == '<')
2200	{
2201		/* strip off <angle brackets> (put back on below) */
2202		bufp = &buf[strlen(buf) - 1];
2203		if (*bufp == '>')
2204			*bufp = '\0';
2205		bufp = &buf[1];
2206	}
2207	else
2208		bufp = buf;
2209	if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
2210	    !bitnset(M_FROMPATH, m->m_flags))
2211	{
2212		smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
2213	}
2214	else
2215	{
2216		smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
2217			    *bufp == '@' ? ',' : ':', bufp, optbuf);
2218	}
2219	SmtpPhase = mci->mci_phase = "client MAIL";
2220	sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2221			CurHostName, mci->mci_phase);
2222	r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc, XS_MAIL);
2223	if (r < 0)
2224	{
2225		/* communications failure */
2226		mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
2227		return EX_TEMPFAIL;
2228	}
2229	else if (r == SMTPCLOSING)
2230	{
2231		/* service shutting down: handled by reply() */
2232		return EX_TEMPFAIL;
2233	}
2234	else if (REPLYTYPE(r) == 4)
2235	{
2236		mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)),
2237			    SmtpReplyBuffer);
2238		return EX_TEMPFAIL;
2239	}
2240	else if (REPLYTYPE(r) == 2)
2241	{
2242		return EX_OK;
2243	}
2244	else if (r == 501)
2245	{
2246		/* syntax error in arguments */
2247		mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"),
2248			    SmtpReplyBuffer);
2249		return EX_DATAERR;
2250	}
2251	else if (r == 553)
2252	{
2253		/* mailbox name not allowed */
2254		mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"),
2255			    SmtpReplyBuffer);
2256		return EX_DATAERR;
2257	}
2258	else if (r == 552)
2259	{
2260		/* exceeded storage allocation */
2261		mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"),
2262			    SmtpReplyBuffer);
2263		if (bitset(MCIF_SIZE, mci->mci_flags))
2264			e->e_flags |= EF_NO_BODY_RETN;
2265		return EX_UNAVAILABLE;
2266	}
2267	else if (REPLYTYPE(r) == 5)
2268	{
2269		/* unknown error */
2270		mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"),
2271			    SmtpReplyBuffer);
2272		return EX_UNAVAILABLE;
2273	}
2274
2275	if (LogLevel > 1)
2276	{
2277		sm_syslog(LOG_CRIT, e->e_id,
2278			  "%.100s: SMTP MAIL protocol error: %s",
2279			  CurHostName,
2280			  shortenstring(SmtpReplyBuffer, 403));
2281	}
2282
2283	/* protocol error -- close up */
2284	mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2285		    SmtpReplyBuffer);
2286	smtpquit(m, mci, e);
2287	return EX_PROTOCOL;
2288}
2289/*
2290**  SMTPRCPT -- designate recipient.
2291**
2292**	Parameters:
2293**		to -- address of recipient.
2294**		m -- the mailer we are sending to.
2295**		mci -- the connection info for this transaction.
2296**		e -- the envelope for this transaction.
2297**
2298**	Returns:
2299**		exit status corresponding to recipient status.
2300**
2301**	Side Effects:
2302**		Sends the mail via SMTP.
2303*/
2304
2305int
2306smtprcpt(to, m, mci, e, ctladdr, xstart)
2307	ADDRESS *to;
2308	register MAILER *m;
2309	MCI *mci;
2310	ENVELOPE *e;
2311	ADDRESS *ctladdr;
2312	time_t xstart;
2313{
2314	char *bufp;
2315	char optbuf[MAXLINE];
2316
2317#if PIPELINING
2318	/*
2319	**  If there is status waiting from the other end, read it.
2320	**  This should normally happen because of SMTP pipelining.
2321	*/
2322
2323	while (mci->mci_nextaddr != NULL &&
2324	       sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
2325	{
2326		int r;
2327
2328		r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
2329		if (r != EX_OK)
2330		{
2331			markfailure(e, mci->mci_nextaddr, mci, r, false);
2332			giveresponse(r, mci->mci_nextaddr->q_status,  m, mci,
2333				     ctladdr, xstart, e, to);
2334		}
2335		mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
2336	}
2337#endif /* PIPELINING */
2338
2339	/*
2340	**  Check if connection is gone, if so
2341	**  it's a tempfail and we use mci_errno
2342	**  for the reason.
2343	*/
2344
2345	if (mci->mci_state == MCIS_CLOSED)
2346	{
2347		errno = mci->mci_errno;
2348		return EX_TEMPFAIL;
2349	}
2350
2351	optbuf[0] = '\0';
2352	bufp = optbuf;
2353
2354	/*
2355	**  Warning: in the following it is assumed that the free space
2356	**  in bufp is sizeof(optbuf)
2357	*/
2358
2359	if (bitset(MCIF_DSN, mci->mci_flags))
2360	{
2361		if (IS_DLVR_NOTIFY(e) &&
2362		    !bitset(MCIF_DLVR_BY, mci->mci_flags))
2363		{
2364			/* RFC 2852: 4.1.4.2 */
2365			if (!bitset(QHASNOTIFY, to->q_flags))
2366				to->q_flags |= QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY;
2367			else if (bitset(QPINGONSUCCESS, to->q_flags) ||
2368				 bitset(QPINGONFAILURE, to->q_flags) ||
2369				 bitset(QPINGONDELAY, to->q_flags))
2370				to->q_flags |= QPINGONDELAY;
2371		}
2372
2373		/* NOTIFY= parameter */
2374		if (bitset(QHASNOTIFY, to->q_flags) &&
2375		    bitset(QPRIMARY, to->q_flags) &&
2376		    !bitnset(M_LOCALMAILER, m->m_flags))
2377		{
2378			bool firstone = true;
2379
2380			(void) sm_strlcat(bufp, " NOTIFY=", sizeof(optbuf));
2381			if (bitset(QPINGONSUCCESS, to->q_flags))
2382			{
2383				(void) sm_strlcat(bufp, "SUCCESS", sizeof(optbuf));
2384				firstone = false;
2385			}
2386			if (bitset(QPINGONFAILURE, to->q_flags))
2387			{
2388				if (!firstone)
2389					(void) sm_strlcat(bufp, ",",
2390						       sizeof(optbuf));
2391				(void) sm_strlcat(bufp, "FAILURE", sizeof(optbuf));
2392				firstone = false;
2393			}
2394			if (bitset(QPINGONDELAY, to->q_flags))
2395			{
2396				if (!firstone)
2397					(void) sm_strlcat(bufp, ",",
2398						       sizeof(optbuf));
2399				(void) sm_strlcat(bufp, "DELAY", sizeof(optbuf));
2400				firstone = false;
2401			}
2402			if (firstone)
2403				(void) sm_strlcat(bufp, "NEVER", sizeof(optbuf));
2404			bufp += strlen(bufp);
2405		}
2406
2407		/* ORCPT= parameter */
2408		if (to->q_orcpt != NULL &&
2409		    SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
2410		{
2411			(void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2412				 " ORCPT=%s", to->q_orcpt);
2413			bufp += strlen(bufp);
2414		}
2415	}
2416
2417	smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
2418	mci->mci_state = MCIS_RCPT;
2419
2420	SmtpPhase = mci->mci_phase = "client RCPT";
2421	sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2422			CurHostName, mci->mci_phase);
2423
2424#if PIPELINING
2425	/*
2426	**  If running SMTP pipelining, we will pick up status later
2427	*/
2428
2429	if (bitset(MCIF_PIPELINED, mci->mci_flags))
2430		return EX_OK;
2431#endif /* PIPELINING */
2432
2433	return smtprcptstat(to, m, mci, e);
2434}
2435/*
2436**  SMTPRCPTSTAT -- get recipient status
2437**
2438**	This is only called during SMTP pipelining
2439**
2440**	Parameters:
2441**		to -- address of recipient.
2442**		m -- mailer being sent to.
2443**		mci -- the mailer connection information.
2444**		e -- the envelope for this message.
2445**
2446**	Returns:
2447**		EX_* -- protocol status
2448*/
2449
2450static int
2451smtprcptstat(to, m, mci, e)
2452	ADDRESS *to;
2453	MAILER *m;
2454	register MCI *mci;
2455	register ENVELOPE *e;
2456{
2457	int r;
2458	int save_errno;
2459	char *enhsc;
2460
2461	/*
2462	**  Check if connection is gone, if so
2463	**  it's a tempfail and we use mci_errno
2464	**  for the reason.
2465	*/
2466
2467	if (mci->mci_state == MCIS_CLOSED)
2468	{
2469		errno = mci->mci_errno;
2470		return EX_TEMPFAIL;
2471	}
2472
2473	enhsc = NULL;
2474	r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc, XS_RCPT);
2475	save_errno = errno;
2476	to->q_rstatus = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer);
2477	to->q_status = ENHSCN_RPOOL(enhsc, smtptodsn(r), e->e_rpool);
2478	if (!bitnset(M_LMTP, m->m_flags))
2479		to->q_statmta = mci->mci_host;
2480	if (r < 0 || REPLYTYPE(r) == 4)
2481	{
2482		mci->mci_retryrcpt = true;
2483		errno = save_errno;
2484		return EX_TEMPFAIL;
2485	}
2486	else if (REPLYTYPE(r) == 2)
2487	{
2488		char *t;
2489
2490		if ((t = mci->mci_tolist) != NULL)
2491		{
2492			char *p;
2493
2494			*t++ = ',';
2495			for (p = to->q_paddr; *p != '\0'; *t++ = *p++)
2496				continue;
2497			*t = '\0';
2498			mci->mci_tolist = t;
2499		}
2500#if PIPELINING
2501		mci->mci_okrcpts++;
2502#endif
2503		return EX_OK;
2504	}
2505	else if (r == 550)
2506	{
2507		to->q_status = ENHSCN_RPOOL(enhsc, "5.1.1", e->e_rpool);
2508		return EX_NOUSER;
2509	}
2510	else if (r == 551)
2511	{
2512		to->q_status = ENHSCN_RPOOL(enhsc, "5.1.6", e->e_rpool);
2513		return EX_NOUSER;
2514	}
2515	else if (r == 553)
2516	{
2517		to->q_status = ENHSCN_RPOOL(enhsc, "5.1.3", e->e_rpool);
2518		return EX_NOUSER;
2519	}
2520	else if (REPLYTYPE(r) == 5)
2521	{
2522		return EX_UNAVAILABLE;
2523	}
2524
2525	if (LogLevel > 1)
2526	{
2527		sm_syslog(LOG_CRIT, e->e_id,
2528			  "%.100s: SMTP RCPT protocol error: %s",
2529			  CurHostName,
2530			  shortenstring(SmtpReplyBuffer, 403));
2531	}
2532
2533	mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2534		    SmtpReplyBuffer);
2535	return EX_PROTOCOL;
2536}
2537/*
2538**  SMTPDATA -- send the data and clean up the transaction.
2539**
2540**	Parameters:
2541**		m -- mailer being sent to.
2542**		mci -- the mailer connection information.
2543**		e -- the envelope for this message.
2544**
2545**	Returns:
2546**		exit status corresponding to DATA command.
2547*/
2548
2549int
2550smtpdata(m, mci, e, ctladdr, xstart)
2551	MAILER *m;
2552	register MCI *mci;
2553	register ENVELOPE *e;
2554	ADDRESS *ctladdr;
2555	time_t xstart;
2556{
2557	register int r;
2558	int rstat;
2559	int xstat;
2560	int timeout;
2561	char *enhsc;
2562
2563	/*
2564	**  Check if connection is gone, if so
2565	**  it's a tempfail and we use mci_errno
2566	**  for the reason.
2567	*/
2568
2569	if (mci->mci_state == MCIS_CLOSED)
2570	{
2571		errno = mci->mci_errno;
2572		return EX_TEMPFAIL;
2573	}
2574
2575	enhsc = NULL;
2576
2577	/*
2578	**  Send the data.
2579	**	First send the command and check that it is ok.
2580	**	Then send the data (if there are valid recipients).
2581	**	Follow it up with a dot to terminate.
2582	**	Finally get the results of the transaction.
2583	*/
2584
2585	/* send the command and check ok to proceed */
2586	smtpmessage("DATA", m, mci);
2587
2588#if PIPELINING
2589	if (mci->mci_nextaddr != NULL)
2590	{
2591		char *oldto = e->e_to;
2592
2593		/* pick up any pending RCPT responses for SMTP pipelining */
2594		while (mci->mci_nextaddr != NULL)
2595		{
2596			e->e_to = mci->mci_nextaddr->q_paddr;
2597			r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
2598			if (r != EX_OK)
2599			{
2600				markfailure(e, mci->mci_nextaddr, mci, r,
2601					    false);
2602				giveresponse(r, mci->mci_nextaddr->q_status, m,
2603					     mci, ctladdr, xstart, e,
2604					     mci->mci_nextaddr);
2605				if (r == EX_TEMPFAIL)
2606					mci->mci_nextaddr->q_state = QS_RETRY;
2607			}
2608			mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
2609		}
2610		e->e_to = oldto;
2611
2612		/*
2613		**  Connection might be closed in response to a RCPT command,
2614		**  i.e., the server responded with 421. In that case (at
2615		**  least) one RCPT has a temporary failure, hence we don't
2616		**  need to check mci_okrcpts (as it is done below) to figure
2617		**  out which error to return.
2618		*/
2619
2620		if (mci->mci_state == MCIS_CLOSED)
2621		{
2622			errno = mci->mci_errno;
2623			return EX_TEMPFAIL;
2624		}
2625	}
2626#endif /* PIPELINING */
2627
2628	/* now proceed with DATA phase */
2629	SmtpPhase = mci->mci_phase = "client DATA 354";
2630	mci->mci_state = MCIS_DATA;
2631	sm_setproctitle(true, e, "%s %s: %s",
2632			qid_printname(e), CurHostName, mci->mci_phase);
2633	r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc, XS_DATA);
2634	if (r < 0 || REPLYTYPE(r) == 4)
2635	{
2636		if (r >= 0)
2637			smtpquit(m, mci, e);
2638		errno = mci->mci_errno;
2639		return EX_TEMPFAIL;
2640	}
2641	else if (REPLYTYPE(r) == 5)
2642	{
2643		smtprset(m, mci, e);
2644#if PIPELINING
2645		if (mci->mci_okrcpts <= 0)
2646			return mci->mci_retryrcpt ? EX_TEMPFAIL
2647						  : EX_UNAVAILABLE;
2648#endif
2649		return EX_UNAVAILABLE;
2650	}
2651	else if (REPLYTYPE(r) != 3)
2652	{
2653		if (LogLevel > 1)
2654		{
2655			sm_syslog(LOG_CRIT, e->e_id,
2656				  "%.100s: SMTP DATA-1 protocol error: %s",
2657				  CurHostName,
2658				  shortenstring(SmtpReplyBuffer, 403));
2659		}
2660		smtprset(m, mci, e);
2661		mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2662			    SmtpReplyBuffer);
2663#if PIPELINING
2664		if (mci->mci_okrcpts <= 0)
2665			return mci->mci_retryrcpt ? EX_TEMPFAIL
2666						  : EX_PROTOCOL;
2667#endif
2668		return EX_PROTOCOL;
2669	}
2670
2671#if PIPELINING
2672	if (mci->mci_okrcpts > 0)
2673	{
2674#endif
2675
2676	/*
2677	**  Set timeout around data writes.  Make it at least large
2678	**  enough for DNS timeouts on all recipients plus some fudge
2679	**  factor.  The main thing is that it should not be infinite.
2680	*/
2681
2682	if (tTd(18, 101))
2683	{
2684		/* simulate a DATA timeout */
2685		timeout = 10;
2686	}
2687	else
2688		timeout = DATA_PROGRESS_TIMEOUT * 1000;
2689	sm_io_setinfo(mci->mci_out, SM_IO_WHAT_TIMEOUT, &timeout);
2690
2691
2692	/*
2693	**  Output the actual message.
2694	*/
2695
2696	if (!(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER))
2697		goto writeerr;
2698
2699	if (tTd(18, 101))
2700	{
2701		/* simulate a DATA timeout */
2702		(void) sleep(2);
2703	}
2704
2705	if (!(*e->e_putbody)(mci, e, NULL))
2706		goto writeerr;
2707
2708	/*
2709	**  Cleanup after sending message.
2710	*/
2711
2712
2713#if PIPELINING
2714	}
2715#endif
2716
2717#if _FFR_CATCH_BROKEN_MTAS
2718	if (sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
2719	{
2720		/* terminate the message */
2721		(void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s",
2722				     m->m_eol);
2723		if (TrafficLogFile != NULL)
2724			(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
2725					     "%05d >>> .\n", (int) CurrentPid);
2726		if (Verbose)
2727			nmessage(">>> .");
2728
2729		sm_syslog(LOG_CRIT, e->e_id,
2730			  "%.100s: SMTP DATA-1 protocol error: remote server returned response before final dot",
2731			  CurHostName);
2732		mci->mci_errno = EIO;
2733		mci->mci_state = MCIS_ERROR;
2734		mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL);
2735		smtpquit(m, mci, e);
2736		return EX_PROTOCOL;
2737	}
2738#endif /* _FFR_CATCH_BROKEN_MTAS */
2739
2740	if (sm_io_error(mci->mci_out))
2741	{
2742		/* error during processing -- don't send the dot */
2743		mci->mci_errno = EIO;
2744		mci->mci_state = MCIS_ERROR;
2745		mci_setstat(mci, EX_IOERR, "4.4.2", NULL);
2746		smtpquit(m, mci, e);
2747		return EX_IOERR;
2748	}
2749
2750	/* terminate the message */
2751	if (sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s.%s",
2752			bitset(MCIF_INLONGLINE, mci->mci_flags) ? m->m_eol : "",
2753			m->m_eol) == SM_IO_EOF)
2754		goto writeerr;
2755	if (TrafficLogFile != NULL)
2756		(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
2757				     "%05d >>> .\n", (int) CurrentPid);
2758	if (Verbose)
2759		nmessage(">>> .");
2760
2761	/* check for the results of the transaction */
2762	SmtpPhase = mci->mci_phase = "client DATA status";
2763	sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2764			CurHostName, mci->mci_phase);
2765	if (bitnset(M_LMTP, m->m_flags))
2766		return EX_OK;
2767	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_EOM);
2768	if (r < 0)
2769		return EX_TEMPFAIL;
2770	if (mci->mci_state == MCIS_DATA)
2771		mci->mci_state = MCIS_OPEN;
2772	xstat = EX_NOTSTICKY;
2773	if (r == 452)
2774		rstat = EX_TEMPFAIL;
2775	else if (REPLYTYPE(r) == 4)
2776		rstat = xstat = EX_TEMPFAIL;
2777	else if (REPLYTYPE(r) == 2)
2778		rstat = xstat = EX_OK;
2779	else if (REPLYCLASS(r) != 5)
2780		rstat = xstat = EX_PROTOCOL;
2781	else if (REPLYTYPE(r) == 5)
2782		rstat = EX_UNAVAILABLE;
2783	else
2784		rstat = EX_PROTOCOL;
2785	mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)),
2786		    SmtpReplyBuffer);
2787	if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
2788	    (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
2789		r += 5;
2790	else
2791		r = 4;
2792	e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[r]);
2793	SmtpPhase = mci->mci_phase = "idle";
2794	sm_setproctitle(true, e, "%s: %s", CurHostName, mci->mci_phase);
2795	if (rstat != EX_PROTOCOL)
2796		return rstat;
2797	if (LogLevel > 1)
2798	{
2799		sm_syslog(LOG_CRIT, e->e_id,
2800			  "%.100s: SMTP DATA-2 protocol error: %s",
2801			  CurHostName,
2802			  shortenstring(SmtpReplyBuffer, 403));
2803	}
2804	return rstat;
2805
2806  writeerr:
2807	mci->mci_errno = errno;
2808	mci->mci_state = MCIS_ERROR;
2809	mci_setstat(mci, bitset(MCIF_NOTSTICKY, mci->mci_flags)
2810			 ? EX_NOTSTICKY: EX_TEMPFAIL,
2811		    "4.4.2", NULL);
2812	mci->mci_flags &= ~MCIF_NOTSTICKY;
2813
2814	/*
2815	**  If putbody() couldn't finish due to a timeout,
2816	**  rewind it here in the timeout handler.  See
2817	**  comments at the end of putbody() for reasoning.
2818	*/
2819
2820	if (e->e_dfp != NULL)
2821		(void) bfrewind(e->e_dfp);
2822
2823	errno = mci->mci_errno;
2824	syserr("+451 4.4.1 timeout writing message to %s", CurHostName);
2825	smtpquit(m, mci, e);
2826	return EX_TEMPFAIL;
2827}
2828
2829/*
2830**  SMTPGETSTAT -- get status code from DATA in LMTP
2831**
2832**	Parameters:
2833**		m -- the mailer to which we are sending the message.
2834**		mci -- the mailer connection structure.
2835**		e -- the current envelope.
2836**
2837**	Returns:
2838**		The exit status corresponding to the reply code.
2839*/
2840
2841int
2842smtpgetstat(m, mci, e)
2843	MAILER *m;
2844	MCI *mci;
2845	ENVELOPE *e;
2846{
2847	int r;
2848	int off;
2849	int status, xstat;
2850	char *enhsc;
2851
2852	enhsc = NULL;
2853
2854	/* check for the results of the transaction */
2855	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DATA2);
2856	if (r < 0)
2857		return EX_TEMPFAIL;
2858	xstat = EX_NOTSTICKY;
2859	if (REPLYTYPE(r) == 4)
2860		status = EX_TEMPFAIL;
2861	else if (REPLYTYPE(r) == 2)
2862		status = xstat = EX_OK;
2863	else if (REPLYCLASS(r) != 5)
2864		status = xstat = EX_PROTOCOL;
2865	else if (REPLYTYPE(r) == 5)
2866		status = EX_UNAVAILABLE;
2867	else
2868		status = EX_PROTOCOL;
2869	if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
2870	    (off = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
2871		off += 5;
2872	else
2873		off = 4;
2874	e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[off]);
2875	mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), SmtpReplyBuffer);
2876	if (LogLevel > 1 && status == EX_PROTOCOL)
2877	{
2878		sm_syslog(LOG_CRIT, e->e_id,
2879			  "%.100s: SMTP DATA-3 protocol error: %s",
2880			  CurHostName,
2881			  shortenstring(SmtpReplyBuffer, 403));
2882	}
2883	return status;
2884}
2885/*
2886**  SMTPQUIT -- close the SMTP connection.
2887**
2888**	Parameters:
2889**		m -- a pointer to the mailer.
2890**		mci -- the mailer connection information.
2891**		e -- the current envelope.
2892**
2893**	Returns:
2894**		none.
2895**
2896**	Side Effects:
2897**		sends the final protocol and closes the connection.
2898*/
2899
2900void
2901smtpquit(m, mci, e)
2902	register MAILER *m;
2903	register MCI *mci;
2904	ENVELOPE *e;
2905{
2906	bool oldSuprErrs = SuprErrs;
2907	int rcode;
2908	char *oldcurhost;
2909
2910	if (mci->mci_state == MCIS_CLOSED)
2911	{
2912		mci_close(mci, "smtpquit:1");
2913		return;
2914	}
2915
2916	oldcurhost = CurHostName;
2917	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
2918	if (CurHostName == NULL)
2919		CurHostName = MyHostName;
2920
2921#if PIPELINING
2922	mci->mci_okrcpts = 0;
2923#endif
2924
2925	/*
2926	**	Suppress errors here -- we may be processing a different
2927	**	job when we do the quit connection, and we don't want the
2928	**	new job to be penalized for something that isn't it's
2929	**	problem.
2930	*/
2931
2932	SuprErrs = true;
2933
2934	/* send the quit message if we haven't gotten I/O error */
2935	if (mci->mci_state != MCIS_ERROR &&
2936	    mci->mci_state != MCIS_QUITING)
2937	{
2938		SmtpPhase = "client QUIT";
2939		mci->mci_state = MCIS_QUITING;
2940		smtpmessage("QUIT", m, mci);
2941		(void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL, XS_QUIT);
2942		SuprErrs = oldSuprErrs;
2943		if (mci->mci_state == MCIS_CLOSED)
2944			goto end;
2945	}
2946
2947	/* now actually close the connection and pick up the zombie */
2948	rcode = endmailer(mci, e, NULL);
2949	if (rcode != EX_OK)
2950	{
2951		char *mailer = NULL;
2952
2953		if (mci->mci_mailer != NULL &&
2954		    mci->mci_mailer->m_name != NULL)
2955			mailer = mci->mci_mailer->m_name;
2956
2957		/* look for naughty mailers */
2958		sm_syslog(LOG_ERR, e->e_id,
2959			  "smtpquit: mailer%s%s exited with exit value %d",
2960			  mailer == NULL ? "" : " ",
2961			  mailer == NULL ? "" : mailer,
2962			  rcode);
2963	}
2964
2965	SuprErrs = oldSuprErrs;
2966
2967  end:
2968	CurHostName = oldcurhost;
2969	return;
2970}
2971/*
2972**  SMTPRSET -- send a RSET (reset) command
2973**
2974**	Parameters:
2975**		m -- a pointer to the mailer.
2976**		mci -- the mailer connection information.
2977**		e -- the current envelope.
2978**
2979**	Returns:
2980**		none.
2981**
2982**	Side Effects:
2983**		closes the connection if there is no reply to RSET.
2984*/
2985
2986void
2987smtprset(m, mci, e)
2988	register MAILER *m;
2989	register MCI *mci;
2990	ENVELOPE *e;
2991{
2992	int r;
2993
2994	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
2995	if (CurHostName == NULL)
2996		CurHostName = MyHostName;
2997
2998#if PIPELINING
2999	mci->mci_okrcpts = 0;
3000#endif
3001
3002	/*
3003	**  Check if connection is gone, if so
3004	**  it's a tempfail and we use mci_errno
3005	**  for the reason.
3006	*/
3007
3008	if (mci->mci_state == MCIS_CLOSED)
3009	{
3010		errno = mci->mci_errno;
3011		return;
3012	}
3013
3014	SmtpPhase = "client RSET";
3015	smtpmessage("RSET", m, mci);
3016	r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL, XS_DEFAULT);
3017	if (r < 0)
3018		return;
3019
3020	/*
3021	**  Any response is deemed to be acceptable.
3022	**  The standard does not state the proper action
3023	**  to take when a value other than 250 is received.
3024	**
3025	**  However, if 421 is returned for the RSET, leave
3026	**  mci_state alone (MCIS_SSD can be set in reply()
3027	**  and MCIS_CLOSED can be set in smtpquit() if
3028	**  reply() gets a 421 and calls smtpquit()).
3029	*/
3030
3031	if (mci->mci_state != MCIS_SSD && mci->mci_state != MCIS_CLOSED)
3032		mci->mci_state = MCIS_OPEN;
3033	else if (mci->mci_exitstat == EX_OK)
3034		mci_setstat(mci, EX_TEMPFAIL, "4.5.0", NULL);
3035}
3036/*
3037**  SMTPPROBE -- check the connection state
3038**
3039**	Parameters:
3040**		mci -- the mailer connection information.
3041**
3042**	Returns:
3043**		none.
3044**
3045**	Side Effects:
3046**		closes the connection if there is no reply to RSET.
3047*/
3048
3049int
3050smtpprobe(mci)
3051	register MCI *mci;
3052{
3053	int r;
3054	MAILER *m = mci->mci_mailer;
3055	ENVELOPE *e;
3056	extern ENVELOPE BlankEnvelope;
3057
3058	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
3059	if (CurHostName == NULL)
3060		CurHostName = MyHostName;
3061
3062	e = &BlankEnvelope;
3063	SmtpPhase = "client probe";
3064	smtpmessage("RSET", m, mci);
3065	r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL, XS_DEFAULT);
3066	if (REPLYTYPE(r) != 2)
3067		smtpquit(m, mci, e);
3068	return r;
3069}
3070/*
3071**  REPLY -- read arpanet reply
3072**
3073**	Parameters:
3074**		m -- the mailer we are reading the reply from.
3075**		mci -- the mailer connection info structure.
3076**		e -- the current envelope.
3077**		timeout -- the timeout for reads.
3078**		pfunc -- processing function called on each line of response.
3079**			If null, no special processing is done.
3080**		enhstat -- optional, returns enhanced error code string (if set)
3081**		rtype -- type of SmtpMsgBuffer: does it contains secret data?
3082**
3083**	Returns:
3084**		reply code it reads.
3085**
3086**	Side Effects:
3087**		flushes the mail file.
3088*/
3089
3090int
3091reply(m, mci, e, timeout, pfunc, enhstat, rtype)
3092	MAILER *m;
3093	MCI *mci;
3094	ENVELOPE *e;
3095	time_t timeout;
3096	void (*pfunc) __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
3097	char **enhstat;
3098	int rtype;
3099{
3100	register char *bufp;
3101	register int r;
3102	bool firstline = true;
3103	char junkbuf[MAXLINE];
3104	static char enhstatcode[ENHSCLEN];
3105	int save_errno;
3106
3107	/*
3108	**  Flush the output before reading response.
3109	**
3110	**	For SMTP pipelining, it would be better if we didn't do
3111	**	this if there was already data waiting to be read.  But
3112	**	to do it properly means pushing it to the I/O library,
3113	**	since it really needs to be done below the buffer layer.
3114	*/
3115
3116	if (mci->mci_out != NULL)
3117		(void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
3118
3119	if (tTd(18, 1))
3120	{
3121		char *what;
3122
3123		if (SmtpMsgBuffer[0] != '\0')
3124			what = SmtpMsgBuffer;
3125		else if (SmtpPhase != NULL && SmtpPhase[0] != '\0')
3126			what = SmtpPhase;
3127		else if (XS_GREET == rtype)
3128			what = "greeting";
3129		else
3130			what = "unknown";
3131		sm_dprintf("reply to %s\n", what);
3132	}
3133
3134	/*
3135	**  Read the input line, being careful not to hang.
3136	*/
3137
3138	bufp = SmtpReplyBuffer;
3139	(void) set_tls_rd_tmo(timeout);
3140	for (;;)
3141	{
3142		register char *p;
3143
3144		/* actually do the read */
3145		if (e->e_xfp != NULL)	/* for debugging */
3146			(void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
3147
3148		/* if we are in the process of closing just give the code */
3149		if (mci->mci_state == MCIS_CLOSED)
3150			return SMTPCLOSING;
3151
3152		/* don't try to read from a non-existent fd */
3153		if (mci->mci_in == NULL)
3154		{
3155			if (mci->mci_errno == 0)
3156				mci->mci_errno = EBADF;
3157
3158			/* errors on QUIT should be ignored */
3159			if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
3160			{
3161				errno = mci->mci_errno;
3162				mci_close(mci, "reply:1");
3163				return -1;
3164			}
3165			mci->mci_state = MCIS_ERROR;
3166			smtpquit(m, mci, e);
3167			errno = mci->mci_errno;
3168			return -1;
3169		}
3170
3171		if (mci->mci_out != NULL)
3172			(void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
3173
3174		/* get the line from the other side */
3175		p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
3176		save_errno = errno;
3177		mci->mci_lastuse = curtime();
3178
3179		if (p == NULL)
3180		{
3181			bool oldholderrs;
3182			extern char MsgBuf[];
3183
3184			/* errors on QUIT should be ignored */
3185			if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
3186			{
3187				mci_close(mci, "reply:2");
3188				return -1;
3189			}
3190
3191			/* if the remote end closed early, fake an error */
3192			errno = save_errno;
3193			if (errno == 0)
3194			{
3195				(void) sm_snprintf(SmtpReplyBuffer,
3196						   sizeof(SmtpReplyBuffer),
3197						   "421 4.4.1 Connection reset by %s",
3198						   CURHOSTNAME);
3199#ifdef ECONNRESET
3200				errno = ECONNRESET;
3201#else
3202				errno = EPIPE;
3203#endif
3204			}
3205
3206			mci->mci_errno = errno;
3207			oldholderrs = HoldErrs;
3208			HoldErrs = true;
3209			usrerr("451 4.4.1 reply: read error from %s",
3210			       CURHOSTNAME);
3211			mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
3212
3213			/* if debugging, pause so we can see state */
3214			if (tTd(18, 100))
3215				(void) pause();
3216			mci->mci_state = MCIS_ERROR;
3217			smtpquit(m, mci, e);
3218#if XDEBUG
3219			{
3220				char wbuf[MAXLINE];
3221
3222				p = wbuf;
3223				if (e->e_to != NULL)
3224				{
3225					(void) sm_snprintf(p,
3226							   SPACELEFT(wbuf, p),
3227							   "%s... ",
3228							   shortenstring(e->e_to, MAXSHORTSTR));
3229					p += strlen(p);
3230				}
3231				(void) sm_snprintf(p, SPACELEFT(wbuf, p),
3232						   "reply(%.100s) during %s",
3233						   CURHOSTNAME, SmtpPhase);
3234				checkfd012(wbuf);
3235			}
3236#endif /* XDEBUG */
3237			HoldErrs = oldholderrs;
3238			errno = save_errno;
3239			return -1;
3240		}
3241		fixcrlf(bufp, true);
3242
3243		/* EHLO failure is not a real error */
3244		if (e->e_xfp != NULL && (bufp[0] == '4' ||
3245		    (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
3246		{
3247			/* serious error -- log the previous command */
3248			if (SmtpNeedIntro)
3249			{
3250				/* inform user who we are chatting with */
3251				(void) sm_io_fprintf(CurEnv->e_xfp,
3252						     SM_TIME_DEFAULT,
3253						     "... while talking to %s:\n",
3254						     CURHOSTNAME);
3255				SmtpNeedIntro = false;
3256			}
3257			if (SmtpMsgBuffer[0] != '\0')
3258			{
3259				(void) sm_io_fprintf(e->e_xfp,
3260					SM_TIME_DEFAULT,
3261					">>> %s\n",
3262					(rtype == XS_STARTTLS)
3263					? "STARTTLS dialogue"
3264					: ((rtype == XS_AUTH)
3265					   ? "AUTH dialogue"
3266					   : SmtpMsgBuffer));
3267				SmtpMsgBuffer[0] = '\0';
3268			}
3269
3270			/* now log the message as from the other side */
3271			(void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
3272					     "<<< %s\n", bufp);
3273		}
3274
3275		/* display the input for verbose mode */
3276		if (Verbose)
3277			nmessage("050 %s", bufp);
3278
3279		/* ignore improperly formatted input */
3280		if (!ISSMTPREPLY(bufp))
3281			continue;
3282
3283		if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
3284		    enhstat != NULL &&
3285		    extenhsc(bufp + 4, ' ', enhstatcode) > 0)
3286			*enhstat = enhstatcode;
3287
3288		/* process the line */
3289		if (pfunc != NULL)
3290			(*pfunc)(bufp, firstline, m, mci, e);
3291
3292		/* decode the reply code */
3293		r = atoi(bufp);
3294
3295		/* extra semantics: 0xx codes are "informational" */
3296		if (r < 100)
3297		{
3298			firstline = false;
3299			continue;
3300		}
3301		if (REPLYTYPE(r) > 3 && firstline
3302# if _FFR_PROXY
3303		    &&
3304		    (e->e_sendmode != SM_PROXY
3305		     || (e->e_sendmode == SM_PROXY
3306			 && (e->e_rcode == 0 || REPLYTYPE(e->e_rcode) < 5))
3307		    )
3308# endif
3309		   )
3310		{
3311			int o = -1;
3312# if PIPELINING
3313			/*
3314			**  ignore error iff: DATA, 5xy error, but we had
3315			**  "retryable" recipients. XREF: smtpdata()
3316			*/
3317
3318			if (!(rtype == XS_DATA && REPLYTYPE(r) == 5 &&
3319			      mci->mci_okrcpts <= 0 && mci->mci_retryrcpt))
3320# endif /* PIPELINING */
3321			{
3322				o = extenhsc(bufp + 4, ' ', enhstatcode);
3323				if (o > 0)
3324				{
3325					sm_strlcpy(e->e_renhsc, enhstatcode,
3326						sizeof(e->e_renhsc));
3327
3328					/* skip SMTP reply code, delimiters */
3329					o += 5;
3330				}
3331				else
3332					o = 4;
3333
3334				/*
3335				**  Don't use this for reply= logging
3336				**  if it was for QUIT.
3337				**  (Note: use the debug option to
3338				**  reproduce the original error.)
3339				*/
3340
3341				if (rtype != XS_QUIT || tTd(87, 101))
3342				{
3343					e->e_rcode = r;
3344					e->e_text = sm_rpool_strdup_x(
3345							e->e_rpool, bufp + o);
3346				}
3347			}
3348			if (tTd(87, 2))
3349			{
3350				sm_dprintf("user: e=%p, offset=%d, bufp=%s, rcode=%d, enhstat=%s, rtype=%d, text=%s\n"
3351					, (void *)e, o, bufp, r, e->e_renhsc
3352					, rtype, e->e_text);
3353			}
3354		}
3355
3356		firstline = false;
3357
3358		/* if no continuation lines, return this line */
3359		if (bufp[3] != '-')
3360			break;
3361
3362		/* first line of real reply -- ignore rest */
3363		bufp = junkbuf;
3364	}
3365
3366	/*
3367	**  Now look at SmtpReplyBuffer -- only care about the first
3368	**  line of the response from here on out.
3369	*/
3370
3371	/* save temporary failure messages for posterity */
3372	if (SmtpReplyBuffer[0] == '4')
3373		(void) sm_strlcpy(SmtpError, SmtpReplyBuffer, sizeof(SmtpError));
3374
3375	/* reply code 421 is "Service Shutting Down" */
3376	if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD &&
3377	    mci->mci_state != MCIS_QUITING)
3378	{
3379		/* send the quit protocol */
3380		mci->mci_state = MCIS_SSD;
3381		smtpquit(m, mci, e);
3382	}
3383
3384	return r;
3385}
3386/*
3387**  SMTPMESSAGE -- send message to server
3388**
3389**	Parameters:
3390**		f -- format
3391**		m -- the mailer to control formatting.
3392**		a, b, c -- parameters
3393**
3394**	Returns:
3395**		none.
3396**
3397**	Side Effects:
3398**		writes message to mci->mci_out.
3399*/
3400
3401/*VARARGS1*/
3402void
3403#ifdef __STDC__
3404smtpmessage(char *f, MAILER *m, MCI *mci, ...)
3405#else /* __STDC__ */
3406smtpmessage(f, m, mci, va_alist)
3407	char *f;
3408	MAILER *m;
3409	MCI *mci;
3410	va_dcl
3411#endif /* __STDC__ */
3412{
3413	SM_VA_LOCAL_DECL
3414
3415	SM_VA_START(ap, mci);
3416	(void) sm_vsnprintf(SmtpMsgBuffer, sizeof(SmtpMsgBuffer), f, ap);
3417	SM_VA_END(ap);
3418
3419	if (tTd(18, 1) || Verbose)
3420		nmessage(">>> %s", SmtpMsgBuffer);
3421	if (TrafficLogFile != NULL)
3422		(void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
3423				     "%05d >>> %s\n", (int) CurrentPid,
3424				     SmtpMsgBuffer);
3425	if (mci->mci_out != NULL)
3426	{
3427		(void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s%s",
3428				     SmtpMsgBuffer, m == NULL ? "\r\n"
3429							      : m->m_eol);
3430	}
3431	else if (tTd(18, 1))
3432	{
3433		sm_dprintf("smtpmessage: NULL mci_out\n");
3434	}
3435}
3436