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