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