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