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