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