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