xref: /freebsd/contrib/sendmail/src/usersmtp.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
1 /*
2  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
3  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
4  * Copyright (c) 1988, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * By using this file, you agree to the terms and conditions set
8  * forth in the LICENSE file which can be found at the top level of
9  * the sendmail distribution.
10  *
11  */
12 
13 # include "sendmail.h"
14 
15 #ifndef lint
16 #if SMTP
17 static char sccsid[] = "@(#)usersmtp.c	8.111 (Berkeley) 2/3/1999 (with SMTP)";
18 #else
19 static char sccsid[] = "@(#)usersmtp.c	8.111 (Berkeley) 2/3/1999 (without SMTP)";
20 #endif
21 #endif /* not lint */
22 
23 # include <sysexits.h>
24 # include <errno.h>
25 
26 # if SMTP
27 
28 /*
29 **  USERSMTP -- run SMTP protocol from the user end.
30 **
31 **	This protocol is described in RFC821.
32 */
33 
34 #define REPLYTYPE(r)	((r) / 100)		/* first digit of reply code */
35 #define REPLYCLASS(r)	(((r) / 10) % 10)	/* second digit of reply code */
36 #define SMTPCLOSING	421			/* "Service Shutting Down" */
37 
38 char	SmtpMsgBuffer[MAXLINE];		/* buffer for commands */
39 char	SmtpReplyBuffer[MAXLINE];	/* buffer for replies */
40 char	SmtpError[MAXLINE] = "";	/* save failure error messages */
41 bool	SmtpNeedIntro;			/* need "while talking" in transcript */
42 
43 extern void	smtpmessage __P((char *f, MAILER *m, MCI *mci, ...));
44 extern int	reply __P((MAILER *, MCI *, ENVELOPE *, time_t, void (*)()));
45 /*
46 **  SMTPINIT -- initialize SMTP.
47 **
48 **	Opens the connection and sends the initial protocol.
49 **
50 **	Parameters:
51 **		m -- mailer to create connection to.
52 **		pvp -- pointer to parameter vector to pass to
53 **			the mailer.
54 **
55 **	Returns:
56 **		none.
57 **
58 **	Side Effects:
59 **		creates connection and sends initial protocol.
60 */
61 
62 void
63 smtpinit(m, mci, e)
64 	MAILER *m;
65 	register MCI *mci;
66 	ENVELOPE *e;
67 {
68 	register int r;
69 	register char *p;
70 	extern void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
71 	extern void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
72 
73 	if (tTd(18, 1))
74 	{
75 		printf("smtpinit ");
76 		mci_dump(mci, FALSE);
77 	}
78 
79 	/*
80 	**  Open the connection to the mailer.
81 	*/
82 
83 	SmtpError[0] = '\0';
84 	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
85 	if (CurHostName == NULL)
86 		CurHostName = MyHostName;
87 	SmtpNeedIntro = TRUE;
88 	switch (mci->mci_state)
89 	{
90 	  case MCIS_ACTIVE:
91 		/* need to clear old information */
92 		smtprset(m, mci, e);
93 		/* fall through */
94 
95 	  case MCIS_OPEN:
96 		return;
97 
98 	  case MCIS_ERROR:
99 	  case MCIS_SSD:
100 		/* shouldn't happen */
101 		smtpquit(m, mci, e);
102 		/* fall through */
103 
104 	  case MCIS_CLOSED:
105 		syserr("451 smtpinit: state CLOSED");
106 		return;
107 
108 	  case MCIS_OPENING:
109 		break;
110 	}
111 
112 	mci->mci_state = MCIS_OPENING;
113 
114 	/*
115 	**  Get the greeting message.
116 	**	This should appear spontaneously.  Give it five minutes to
117 	**	happen.
118 	*/
119 
120 	SmtpPhase = mci->mci_phase = "client greeting";
121 	sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
122 	r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check);
123 	if (r < 0)
124 		goto tempfail1;
125 	if (REPLYTYPE(r) == 4)
126 		goto tempfail2;
127 	if (REPLYTYPE(r) != 2)
128 		goto unavailable;
129 
130 	/*
131 	**  Send the HELO command.
132 	**	My mother taught me to always introduce myself.
133 	*/
134 
135 	if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags))
136 		mci->mci_flags |= MCIF_ESMTP;
137 
138 tryhelo:
139 	if (bitnset(M_LMTP, m->m_flags))
140 	{
141 		smtpmessage("LHLO %s", m, mci, MyHostName);
142 		SmtpPhase = mci->mci_phase = "client LHLO";
143 	}
144 	else if (bitset(MCIF_ESMTP, mci->mci_flags))
145 	{
146 		smtpmessage("EHLO %s", m, mci, MyHostName);
147 		SmtpPhase = mci->mci_phase = "client EHLO";
148 	}
149 	else
150 	{
151 		smtpmessage("HELO %s", m, mci, MyHostName);
152 		SmtpPhase = mci->mci_phase = "client HELO";
153 	}
154 	sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
155 	r = reply(m, mci, e, TimeOuts.to_helo, helo_options);
156 	if (r < 0)
157 		goto tempfail1;
158 	else if (REPLYTYPE(r) == 5)
159 	{
160 		if (bitset(MCIF_ESMTP, mci->mci_flags) &&
161 		    !bitnset(M_LMTP, m->m_flags))
162 		{
163 			/* try old SMTP instead */
164 			mci->mci_flags &= ~MCIF_ESMTP;
165 			goto tryhelo;
166 		}
167 		goto unavailable;
168 	}
169 	else if (REPLYTYPE(r) != 2)
170 		goto tempfail2;
171 
172 	/*
173 	**  Check to see if we actually ended up talking to ourself.
174 	**  This means we didn't know about an alias or MX, or we managed
175 	**  to connect to an echo server.
176 	*/
177 
178 	p = strchr(&SmtpReplyBuffer[4], ' ');
179 	if (p != NULL)
180 		*p = '\0';
181 	if (!bitnset(M_NOLOOPCHECK, m->m_flags) &&
182 	    !bitnset(M_LMTP, m->m_flags) &&
183 	    strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
184 	{
185 		syserr("553 %s config error: mail loops back to me (MX problem?)",
186 			CurHostName);
187 		mci_setstat(mci, EX_CONFIG, NULL, NULL);
188 		mci->mci_errno = 0;
189 		smtpquit(m, mci, e);
190 		return;
191 	}
192 
193 	/*
194 	**  If this is expected to be another sendmail, send some internal
195 	**  commands.
196 	*/
197 
198 	if (bitnset(M_INTERNAL, m->m_flags))
199 	{
200 		/* tell it to be verbose */
201 		smtpmessage("VERB", m, mci);
202 		r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
203 		if (r < 0)
204 			goto tempfail1;
205 	}
206 
207 	if (mci->mci_state != MCIS_CLOSED)
208 	{
209 		mci->mci_state = MCIS_OPEN;
210 		return;
211 	}
212 
213 	/* got a 421 error code during startup */
214 
215   tempfail1:
216 	if (mci->mci_errno == 0)
217 		mci->mci_errno = errno;
218 	mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
219 	if (mci->mci_state != MCIS_CLOSED)
220 		smtpquit(m, mci, e);
221 	return;
222 
223   tempfail2:
224 	if (mci->mci_errno == 0)
225 		mci->mci_errno = errno;
226 	/* XXX should use code from other end iff ENHANCEDSTATUSCODES */
227 	mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer);
228 	if (mci->mci_state != MCIS_CLOSED)
229 		smtpquit(m, mci, e);
230 	return;
231 
232   unavailable:
233 	mci->mci_errno = errno;
234 	mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer);
235 	smtpquit(m, mci, e);
236 	return;
237 }
238 /*
239 **  ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
240 **
241 **	Parameters:
242 **		line -- the response line.
243 **		firstline -- set if this is the first line of the reply.
244 **		m -- the mailer.
245 **		mci -- the mailer connection info.
246 **		e -- the envelope.
247 **
248 **	Returns:
249 **		none.
250 */
251 
252 void
253 esmtp_check(line, firstline, m, mci, e)
254 	char *line;
255 	bool firstline;
256 	MAILER *m;
257 	register MCI *mci;
258 	ENVELOPE *e;
259 {
260 	if (strstr(line, "ESMTP") != NULL)
261 		mci->mci_flags |= MCIF_ESMTP;
262 	if (strstr(line, "8BIT-OK") != NULL)
263 		mci->mci_flags |= MCIF_8BITOK;
264 }
265 /*
266 **  HELO_OPTIONS -- process the options on a HELO line.
267 **
268 **	Parameters:
269 **		line -- the response line.
270 **		firstline -- set if this is the first line of the reply.
271 **		m -- the mailer.
272 **		mci -- the mailer connection info.
273 **		e -- the envelope.
274 **
275 **	Returns:
276 **		none.
277 */
278 
279 void
280 helo_options(line, firstline, m, mci, e)
281 	char *line;
282 	bool firstline;
283 	MAILER *m;
284 	register MCI *mci;
285 	ENVELOPE *e;
286 {
287 	register char *p;
288 
289 	if (firstline)
290 		return;
291 
292 	if (strlen(line) < (SIZE_T) 5)
293 		return;
294 	line += 4;
295 	p = strchr(line, ' ');
296 	if (p != NULL)
297 		*p++ = '\0';
298 	if (strcasecmp(line, "size") == 0)
299 	{
300 		mci->mci_flags |= MCIF_SIZE;
301 		if (p != NULL)
302 			mci->mci_maxsize = atol(p);
303 	}
304 	else if (strcasecmp(line, "8bitmime") == 0)
305 	{
306 		mci->mci_flags |= MCIF_8BITMIME;
307 		mci->mci_flags &= ~MCIF_7BIT;
308 	}
309 	else if (strcasecmp(line, "expn") == 0)
310 		mci->mci_flags |= MCIF_EXPN;
311 	else if (strcasecmp(line, "dsn") == 0)
312 		mci->mci_flags |= MCIF_DSN;
313 }
314 /*
315 **  SMTPMAILFROM -- send MAIL command
316 **
317 **	Parameters:
318 **		m -- the mailer.
319 **		mci -- the mailer connection structure.
320 **		e -- the envelope (including the sender to specify).
321 */
322 
323 int
324 smtpmailfrom(m, mci, e)
325 	MAILER *m;
326 	MCI *mci;
327 	ENVELOPE *e;
328 {
329 	int r;
330 	char *bufp;
331 	char *bodytype;
332 	char buf[MAXNAME + 1];
333 	char optbuf[MAXLINE];
334 
335 	if (tTd(18, 2))
336 		printf("smtpmailfrom: CurHost=%s\n", CurHostName);
337 
338 	/* set up appropriate options to include */
339 	bufp = optbuf;
340 	if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
341 		snprintf(optbuf, sizeof optbuf, " SIZE=%ld", e->e_msgsize);
342 	else
343 		strcpy(optbuf, "");
344 	bufp = &optbuf[strlen(optbuf)];
345 
346 	bodytype = e->e_bodytype;
347 	if (bitset(MCIF_8BITMIME, mci->mci_flags))
348 	{
349 		if (bodytype == NULL &&
350 		    bitset(MM_MIME8BIT, MimeMode) &&
351 		    bitset(EF_HAS8BIT, e->e_flags) &&
352 		    !bitset(EF_DONT_MIME, e->e_flags) &&
353 		    !bitnset(M_8BITS, m->m_flags))
354 			bodytype = "8BITMIME";
355 		if (bodytype != NULL &&
356 		    SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
357 		{
358 			snprintf(bufp, SPACELEFT(optbuf, bufp),
359 				 " BODY=%s", bodytype);
360 			bufp += strlen(bufp);
361 		}
362 	}
363 	else if (bitnset(M_8BITS, m->m_flags) ||
364 		 !bitset(EF_HAS8BIT, e->e_flags) ||
365 		 bitset(MCIF_8BITOK, mci->mci_flags))
366 	{
367 		/* just pass it through */
368 	}
369 #if MIME8TO7
370 	else if (bitset(MM_CVTMIME, MimeMode) &&
371 		 !bitset(EF_DONT_MIME, e->e_flags) &&
372 		 (!bitset(MM_PASS8BIT, MimeMode) ||
373 		  bitset(EF_IS_MIME, e->e_flags)))
374 	{
375 		/* must convert from 8bit MIME format to 7bit encoded */
376 		mci->mci_flags |= MCIF_CVT8TO7;
377 	}
378 #endif
379 	else if (!bitset(MM_PASS8BIT, MimeMode))
380 	{
381 		/* cannot just send a 8-bit version */
382 		extern char MsgBuf[];
383 
384 		usrerr("%s does not support 8BITMIME", CurHostName);
385 		mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
386 		return EX_DATAERR;
387 	}
388 
389 	if (bitset(MCIF_DSN, mci->mci_flags))
390 	{
391 		if (e->e_envid != NULL &&
392 		    SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
393 		{
394 			snprintf(bufp, SPACELEFT(optbuf, bufp),
395 				 " ENVID=%s", e->e_envid);
396 			bufp += strlen(bufp);
397 		}
398 
399 		/* RET= parameter */
400 		if (bitset(EF_RET_PARAM, e->e_flags) &&
401 		    SPACELEFT(optbuf, bufp) > 9)
402 		{
403 			snprintf(bufp, SPACELEFT(optbuf, bufp),
404 				 " RET=%s",
405 				 bitset(EF_NO_BODY_RETN, e->e_flags) ?
406 					"HDRS" : "FULL");
407 			bufp += strlen(bufp);
408 		}
409 	}
410 
411 	/*
412 	**  Send the MAIL command.
413 	**	Designates the sender.
414 	*/
415 
416 	mci->mci_state = MCIS_ACTIVE;
417 
418 	if (bitset(EF_RESPONSE, e->e_flags) &&
419 	    !bitnset(M_NO_NULL_FROM, m->m_flags))
420 		(void) strcpy(buf, "");
421 	else
422 		expand("\201g", buf, sizeof buf, e);
423 	if (buf[0] == '<')
424 	{
425 		/* strip off <angle brackets> (put back on below) */
426 		bufp = &buf[strlen(buf) - 1];
427 		if (*bufp == '>')
428 			*bufp = '\0';
429 		bufp = &buf[1];
430 	}
431 	else
432 		bufp = buf;
433 	if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
434 	    !bitnset(M_FROMPATH, m->m_flags))
435 	{
436 		smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
437 	}
438 	else
439 	{
440 		smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
441 			*bufp == '@' ? ',' : ':', bufp, optbuf);
442 	}
443 	SmtpPhase = mci->mci_phase = "client MAIL";
444 	sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
445 	r = reply(m, mci, e, TimeOuts.to_mail, NULL);
446 	if (r < 0)
447 	{
448 		/* communications failure */
449 		mci->mci_errno = errno;
450 		mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
451 		smtpquit(m, mci, e);
452 		return EX_TEMPFAIL;
453 	}
454 	else if (r == 421)
455 	{
456 		/* service shutting down */
457 		mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer);
458 		smtpquit(m, mci, e);
459 		return EX_TEMPFAIL;
460 	}
461 	else if (REPLYTYPE(r) == 4)
462 	{
463 		mci_setstat(mci, EX_NOTSTICKY, smtptodsn(r), SmtpReplyBuffer);
464 		return EX_TEMPFAIL;
465 	}
466 	else if (REPLYTYPE(r) == 2)
467 	{
468 		return EX_OK;
469 	}
470 	else if (r == 501)
471 	{
472 		/* syntax error in arguments */
473 		mci_setstat(mci, EX_NOTSTICKY, "5.5.2", SmtpReplyBuffer);
474 		return EX_DATAERR;
475 	}
476 	else if (r == 553)
477 	{
478 		/* mailbox name not allowed */
479 		mci_setstat(mci, EX_NOTSTICKY, "5.1.3", SmtpReplyBuffer);
480 		return EX_DATAERR;
481 	}
482 	else if (r == 552)
483 	{
484 		/* exceeded storage allocation */
485 		mci_setstat(mci, EX_NOTSTICKY, "5.3.4", SmtpReplyBuffer);
486 		if (bitset(MCIF_SIZE, mci->mci_flags))
487 			e->e_flags |= EF_NO_BODY_RETN;
488 		return EX_UNAVAILABLE;
489 	}
490 	else if (REPLYTYPE(r) == 5)
491 	{
492 		/* unknown error */
493 		mci_setstat(mci, EX_NOTSTICKY, "5.0.0", SmtpReplyBuffer);
494 		return EX_UNAVAILABLE;
495 	}
496 
497 	if (LogLevel > 1)
498 	{
499 		sm_syslog(LOG_CRIT, e->e_id,
500 			"%.100s: SMTP MAIL protocol error: %s",
501 			CurHostName,
502 			shortenstring(SmtpReplyBuffer, 403));
503 	}
504 
505 	/* protocol error -- close up */
506 	mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer);
507 	smtpquit(m, mci, e);
508 	return EX_PROTOCOL;
509 }
510 /*
511 **  SMTPRCPT -- designate recipient.
512 **
513 **	Parameters:
514 **		to -- address of recipient.
515 **		m -- the mailer we are sending to.
516 **		mci -- the connection info for this transaction.
517 **		e -- the envelope for this transaction.
518 **
519 **	Returns:
520 **		exit status corresponding to recipient status.
521 **
522 **	Side Effects:
523 **		Sends the mail via SMTP.
524 */
525 
526 int
527 smtprcpt(to, m, mci, e)
528 	ADDRESS *to;
529 	register MAILER *m;
530 	MCI *mci;
531 	ENVELOPE *e;
532 {
533 	register int r;
534 	char *bufp;
535 	char optbuf[MAXLINE];
536 
537 	strcpy(optbuf, "");
538 	bufp = &optbuf[strlen(optbuf)];
539 	if (bitset(MCIF_DSN, mci->mci_flags))
540 	{
541 		/* NOTIFY= parameter */
542 		if (bitset(QHASNOTIFY, to->q_flags) &&
543 		    bitset(QPRIMARY, to->q_flags) &&
544 		    !bitnset(M_LOCALMAILER, m->m_flags))
545 		{
546 			bool firstone = TRUE;
547 
548 			strcat(bufp, " NOTIFY=");
549 			if (bitset(QPINGONSUCCESS, to->q_flags))
550 			{
551 				strcat(bufp, "SUCCESS");
552 				firstone = FALSE;
553 			}
554 			if (bitset(QPINGONFAILURE, to->q_flags))
555 			{
556 				if (!firstone)
557 					strcat(bufp, ",");
558 				strcat(bufp, "FAILURE");
559 				firstone = FALSE;
560 			}
561 			if (bitset(QPINGONDELAY, to->q_flags))
562 			{
563 				if (!firstone)
564 					strcat(bufp, ",");
565 				strcat(bufp, "DELAY");
566 				firstone = FALSE;
567 			}
568 			if (firstone)
569 				strcat(bufp, "NEVER");
570 			bufp += strlen(bufp);
571 		}
572 
573 		/* ORCPT= parameter */
574 		if (to->q_orcpt != NULL &&
575 		    SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
576 		{
577 			snprintf(bufp, SPACELEFT(optbuf, bufp),
578 				 " ORCPT=%s", to->q_orcpt);
579 			bufp += strlen(bufp);
580 		}
581 	}
582 
583 	smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
584 
585 	SmtpPhase = mci->mci_phase = "client RCPT";
586 	sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
587 	r = reply(m, mci, e, TimeOuts.to_rcpt, NULL);
588 	to->q_rstatus = newstr(SmtpReplyBuffer);
589 	to->q_status = smtptodsn(r);
590 	to->q_statmta = mci->mci_host;
591 	if (r < 0 || REPLYTYPE(r) == 4)
592 		return EX_TEMPFAIL;
593 	else if (REPLYTYPE(r) == 2)
594 		return EX_OK;
595 	else if (r == 550)
596 	{
597 		to->q_status = "5.1.1";
598 		return EX_NOUSER;
599 	}
600 	else if (r == 551)
601 	{
602 		to->q_status = "5.1.6";
603 		return EX_NOUSER;
604 	}
605 	else if (r == 553)
606 	{
607 		to->q_status = "5.1.3";
608 		return EX_NOUSER;
609 	}
610 	else if (REPLYTYPE(r) == 5)
611 	{
612 		return EX_UNAVAILABLE;
613 	}
614 
615 	if (LogLevel > 1)
616 	{
617 		sm_syslog(LOG_CRIT, e->e_id,
618 			"%.100s: SMTP RCPT protocol error: %s",
619 			CurHostName,
620 			shortenstring(SmtpReplyBuffer, 403));
621 	}
622 
623 	mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer);
624 	return EX_PROTOCOL;
625 }
626 /*
627 **  SMTPDATA -- send the data and clean up the transaction.
628 **
629 **	Parameters:
630 **		m -- mailer being sent to.
631 **		mci -- the mailer connection information.
632 **		e -- the envelope for this message.
633 **
634 **	Returns:
635 **		exit status corresponding to DATA command.
636 **
637 **	Side Effects:
638 **		none.
639 */
640 
641 static jmp_buf	CtxDataTimeout;
642 static void	datatimeout __P((void));
643 
644 int
645 smtpdata(m, mci, e)
646 	MAILER *m;
647 	register MCI *mci;
648 	register ENVELOPE *e;
649 {
650 	register int r;
651 	register EVENT *ev;
652 	int rstat;
653 	int xstat;
654 	time_t timeout;
655 
656 	/*
657 	**  Send the data.
658 	**	First send the command and check that it is ok.
659 	**	Then send the data.
660 	**	Follow it up with a dot to terminate.
661 	**	Finally get the results of the transaction.
662 	*/
663 
664 	/* send the command and check ok to proceed */
665 	smtpmessage("DATA", m, mci);
666 	SmtpPhase = mci->mci_phase = "client DATA 354";
667 	sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
668 	r = reply(m, mci, e, TimeOuts.to_datainit, NULL);
669 	if (r < 0 || REPLYTYPE(r) == 4)
670 	{
671 		smtpquit(m, mci, e);
672 		return EX_TEMPFAIL;
673 	}
674 	else if (REPLYTYPE(r) == 5)
675 	{
676 		smtprset(m, mci, e);
677 		return EX_UNAVAILABLE;
678 	}
679 	else if (REPLYTYPE(r) != 3)
680 	{
681 		if (LogLevel > 1)
682 		{
683 			sm_syslog(LOG_CRIT, e->e_id,
684 				"%.100s: SMTP DATA-1 protocol error: %s",
685 				CurHostName,
686 				shortenstring(SmtpReplyBuffer, 403));
687 		}
688 		smtprset(m, mci, e);
689 		mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer);
690 		return (EX_PROTOCOL);
691 	}
692 
693 	/*
694 	**  Set timeout around data writes.  Make it at least large
695 	**  enough for DNS timeouts on all recipients plus some fudge
696 	**  factor.  The main thing is that it should not be infinite.
697 	*/
698 
699 	if (setjmp(CtxDataTimeout) != 0)
700 	{
701 		mci->mci_errno = errno;
702 		mci->mci_state = MCIS_ERROR;
703 		mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
704 		syserr("451 timeout writing message to %s", CurHostName);
705 		smtpquit(m, mci, e);
706 		return EX_TEMPFAIL;
707 	}
708 
709 	timeout = e->e_msgsize / 16;
710 	if (timeout < (time_t) 600)
711 		timeout = (time_t) 600;
712 	timeout += e->e_nrcpts * 300;
713 	ev = setevent(timeout, datatimeout, 0);
714 
715 	/*
716 	**  Output the actual message.
717 	*/
718 
719 	(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
720 	(*e->e_putbody)(mci, e, NULL);
721 
722 	/*
723 	**  Cleanup after sending message.
724 	*/
725 
726 	clrevent(ev);
727 
728 	if (ferror(mci->mci_out))
729 	{
730 		/* error during processing -- don't send the dot */
731 		mci->mci_errno = EIO;
732 		mci->mci_state = MCIS_ERROR;
733 		mci_setstat(mci, EX_IOERR, "4.4.2", NULL);
734 		smtpquit(m, mci, e);
735 		return EX_IOERR;
736 	}
737 
738 	/* terminate the message */
739 	fprintf(mci->mci_out, ".%s", m->m_eol);
740 	if (TrafficLogFile != NULL)
741 		fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid());
742 	if (Verbose)
743 		nmessage(">>> .");
744 
745 	/* check for the results of the transaction */
746 	SmtpPhase = mci->mci_phase = "client DATA status";
747 	sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
748 	if (bitnset(M_LMTP, m->m_flags))
749 		return EX_OK;
750 	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL);
751 	if (r < 0)
752 	{
753 		smtpquit(m, mci, e);
754 		return EX_TEMPFAIL;
755 	}
756 	mci->mci_state = MCIS_OPEN;
757 	xstat = EX_NOTSTICKY;
758 	if (r == 452)
759 		rstat = EX_TEMPFAIL;
760 	else if (REPLYTYPE(r) == 4)
761 		rstat = xstat = EX_TEMPFAIL;
762 	else if (REPLYCLASS(r) != 5)
763 		rstat = xstat = EX_PROTOCOL;
764 	else if (REPLYTYPE(r) == 2)
765 		rstat = xstat = EX_OK;
766 	else if (REPLYTYPE(r) == 5)
767 		rstat = EX_UNAVAILABLE;
768 	else
769 		rstat = EX_PROTOCOL;
770 	mci_setstat(mci, xstat, smtptodsn(r), SmtpReplyBuffer);
771 	if (e->e_statmsg != NULL)
772 		free(e->e_statmsg);
773 	e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
774 	if (rstat != EX_PROTOCOL)
775 		return rstat;
776 	if (LogLevel > 1)
777 	{
778 		sm_syslog(LOG_CRIT, e->e_id,
779 			"%.100s: SMTP DATA-2 protocol error: %s",
780 			CurHostName,
781 			shortenstring(SmtpReplyBuffer, 403));
782 	}
783 	return rstat;
784 }
785 
786 
787 static void
788 datatimeout()
789 {
790 	longjmp(CtxDataTimeout, 1);
791 }
792 /*
793 **  SMTPGETSTAT -- get status code from DATA in LMTP
794 **
795 **	Parameters:
796 **		m -- the mailer to which we are sending the message.
797 **		mci -- the mailer connection structure.
798 **		e -- the current envelope.
799 **
800 **	Returns:
801 **		The exit status corresponding to the reply code.
802 */
803 
804 int
805 smtpgetstat(m, mci, e)
806 	MAILER *m;
807 	MCI *mci;
808 	ENVELOPE *e;
809 {
810 	int r;
811 	int stat;
812 
813 	/* check for the results of the transaction */
814 	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL);
815 	if (r < 0)
816 	{
817 		smtpquit(m, mci, e);
818 		return EX_TEMPFAIL;
819 	}
820 	if (e->e_statmsg != NULL)
821 		free(e->e_statmsg);
822 	e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
823 	if (REPLYTYPE(r) == 4)
824 		stat = EX_TEMPFAIL;
825 	else if (REPLYCLASS(r) != 5)
826 		stat = EX_PROTOCOL;
827 	else if (REPLYTYPE(r) == 2)
828 		stat = EX_OK;
829 	else if (REPLYTYPE(r) == 5)
830 		stat = EX_UNAVAILABLE;
831 	else
832 		stat = EX_PROTOCOL;
833 	mci_setstat(mci, stat, smtptodsn(r), SmtpReplyBuffer);
834 	if (LogLevel > 1 && stat == EX_PROTOCOL)
835 	{
836 		sm_syslog(LOG_CRIT, e->e_id,
837 			"%.100s: SMTP DATA-3 protocol error: %s",
838 			CurHostName,
839 			shortenstring(SmtpReplyBuffer, 403));
840 	}
841 	return stat;
842 }
843 /*
844 **  SMTPQUIT -- close the SMTP connection.
845 **
846 **	Parameters:
847 **		m -- a pointer to the mailer.
848 **		mci -- the mailer connection information.
849 **		e -- the current envelope.
850 **
851 **	Returns:
852 **		none.
853 **
854 **	Side Effects:
855 **		sends the final protocol and closes the connection.
856 */
857 
858 void
859 smtpquit(m, mci, e)
860 	register MAILER *m;
861 	register MCI *mci;
862 	ENVELOPE *e;
863 {
864 	bool oldSuprErrs = SuprErrs;
865 
866 	/*
867 	**	Suppress errors here -- we may be processing a different
868 	**	job when we do the quit connection, and we don't want the
869 	**	new job to be penalized for something that isn't it's
870 	**	problem.
871 	*/
872 
873 	SuprErrs = TRUE;
874 
875 	/* send the quit message if we haven't gotten I/O error */
876 	if (mci->mci_state != MCIS_ERROR)
877 	{
878 		SmtpPhase = "client QUIT";
879 		smtpmessage("QUIT", m, mci);
880 		(void) reply(m, mci, e, TimeOuts.to_quit, NULL);
881 		SuprErrs = oldSuprErrs;
882 		if (mci->mci_state == MCIS_CLOSED)
883 			return;
884 	}
885 
886 	/* now actually close the connection and pick up the zombie */
887 	(void) endmailer(mci, e, NULL);
888 
889 	SuprErrs = oldSuprErrs;
890 }
891 /*
892 **  SMTPRSET -- send a RSET (reset) command
893 */
894 
895 void
896 smtprset(m, mci, e)
897 	register MAILER *m;
898 	register MCI *mci;
899 	ENVELOPE *e;
900 {
901 	int r;
902 
903 	SmtpPhase = "client RSET";
904 	smtpmessage("RSET", m, mci);
905 	r = reply(m, mci, e, TimeOuts.to_rset, NULL);
906 	if (r < 0)
907 		mci->mci_state = MCIS_ERROR;
908 	else if (REPLYTYPE(r) == 2)
909 	{
910 		mci->mci_state = MCIS_OPEN;
911 		return;
912 	}
913 	smtpquit(m, mci, e);
914 }
915 /*
916 **  SMTPPROBE -- check the connection state
917 */
918 
919 int
920 smtpprobe(mci)
921 	register MCI *mci;
922 {
923 	int r;
924 	MAILER *m = mci->mci_mailer;
925 	extern ENVELOPE BlankEnvelope;
926 	ENVELOPE *e = &BlankEnvelope;
927 
928 	SmtpPhase = "client probe";
929 	smtpmessage("RSET", m, mci);
930 	r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
931 	if (r < 0 || REPLYTYPE(r) != 2)
932 		smtpquit(m, mci, e);
933 	return r;
934 }
935 /*
936 **  REPLY -- read arpanet reply
937 **
938 **	Parameters:
939 **		m -- the mailer we are reading the reply from.
940 **		mci -- the mailer connection info structure.
941 **		e -- the current envelope.
942 **		timeout -- the timeout for reads.
943 **		pfunc -- processing function called on each line of response.
944 **			If null, no special processing is done.
945 **
946 **	Returns:
947 **		reply code it reads.
948 **
949 **	Side Effects:
950 **		flushes the mail file.
951 */
952 
953 int
954 reply(m, mci, e, timeout, pfunc)
955 	MAILER *m;
956 	MCI *mci;
957 	ENVELOPE *e;
958 	time_t timeout;
959 	void (*pfunc)();
960 {
961 	register char *bufp;
962 	register int r;
963 	bool firstline = TRUE;
964 	char junkbuf[MAXLINE];
965 
966 	if (mci->mci_out != NULL)
967 		(void) fflush(mci->mci_out);
968 
969 	if (tTd(18, 1))
970 		printf("reply\n");
971 
972 	/*
973 	**  Read the input line, being careful not to hang.
974 	*/
975 
976 	bufp = SmtpReplyBuffer;
977 	for (;;)
978 	{
979 		register char *p;
980 
981 		/* actually do the read */
982 		if (e->e_xfp != NULL)
983 			(void) fflush(e->e_xfp);	/* for debugging */
984 
985 		/* if we are in the process of closing just give the code */
986 		if (mci->mci_state == MCIS_CLOSED)
987 			return (SMTPCLOSING);
988 
989 		if (mci->mci_out != NULL)
990 			fflush(mci->mci_out);
991 
992 		/* get the line from the other side */
993 		p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
994 		mci->mci_lastuse = curtime();
995 
996 		if (p == NULL)
997 		{
998 			bool oldholderrs;
999 			extern char MsgBuf[];
1000 
1001 			/* if the remote end closed early, fake an error */
1002 			if (errno == 0)
1003 # ifdef ECONNRESET
1004 				errno = ECONNRESET;
1005 # else /* ECONNRESET */
1006 				errno = EPIPE;
1007 # endif /* ECONNRESET */
1008 
1009 			mci->mci_errno = errno;
1010 			oldholderrs = HoldErrs;
1011 			HoldErrs = TRUE;
1012 			usrerr("451 reply: read error from %s", CurHostName);
1013 
1014 			/* errors on QUIT should not be persistent */
1015 			if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0)
1016 				mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
1017 
1018 			/* if debugging, pause so we can see state */
1019 			if (tTd(18, 100))
1020 				pause();
1021 			mci->mci_state = MCIS_ERROR;
1022 			smtpquit(m, mci, e);
1023 #if XDEBUG
1024 			{
1025 				char wbuf[MAXLINE];
1026 				char *p = wbuf;
1027 				int wbufleft = sizeof wbuf;
1028 
1029 				if (e->e_to != NULL)
1030 				{
1031 					int plen;
1032 
1033 					snprintf(p, wbufleft, "%s... ",
1034 						shortenstring(e->e_to, MAXSHORTSTR));
1035 					plen = strlen(p);
1036 					p += plen;
1037 					wbufleft -= plen;
1038 				}
1039 				snprintf(p, wbufleft, "reply(%.100s) during %s",
1040 					 CurHostName == NULL ? "NO_HOST" : CurHostName,
1041 					 SmtpPhase);
1042 				checkfd012(wbuf);
1043 			}
1044 #endif
1045 			HoldErrs = oldholderrs;
1046 			return (-1);
1047 		}
1048 		fixcrlf(bufp, TRUE);
1049 
1050 		/* EHLO failure is not a real error */
1051 		if (e->e_xfp != NULL && (bufp[0] == '4' ||
1052 		    (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
1053 		{
1054 			/* serious error -- log the previous command */
1055 			if (SmtpNeedIntro)
1056 			{
1057 				/* inform user who we are chatting with */
1058 				fprintf(CurEnv->e_xfp,
1059 					"... while talking to %s:\n",
1060 					CurHostName);
1061 				SmtpNeedIntro = FALSE;
1062 			}
1063 			if (SmtpMsgBuffer[0] != '\0')
1064 				fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
1065 			SmtpMsgBuffer[0] = '\0';
1066 
1067 			/* now log the message as from the other side */
1068 			fprintf(e->e_xfp, "<<< %s\n", bufp);
1069 		}
1070 
1071 		/* display the input for verbose mode */
1072 		if (Verbose)
1073 			nmessage("050 %s", bufp);
1074 
1075 		/* ignore improperly formated input */
1076 		if (!(isascii(bufp[0]) && isdigit(bufp[0])) ||
1077 		    !(isascii(bufp[1]) && isdigit(bufp[1])) ||
1078 		    !(isascii(bufp[2]) && isdigit(bufp[2])) ||
1079 		    !(bufp[3] == ' ' || bufp[3] == '-' || bufp[3] == '\0'))
1080 			continue;
1081 
1082 		/* process the line */
1083 		if (pfunc != NULL)
1084 			(*pfunc)(bufp, firstline, m, mci, e);
1085 
1086 		firstline = FALSE;
1087 
1088 		/* decode the reply code */
1089 		r = atoi(bufp);
1090 
1091 		/* extra semantics: 0xx codes are "informational" */
1092 		if (r < 100)
1093 			continue;
1094 
1095 		/* if no continuation lines, return this line */
1096 		if (bufp[3] != '-')
1097 			break;
1098 
1099 		/* first line of real reply -- ignore rest */
1100 		bufp = junkbuf;
1101 	}
1102 
1103 	/*
1104 	**  Now look at SmtpReplyBuffer -- only care about the first
1105 	**  line of the response from here on out.
1106 	*/
1107 
1108 	/* save temporary failure messages for posterity */
1109 	if (SmtpReplyBuffer[0] == '4' &&
1110 	    (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == '\0'))
1111 		snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer);
1112 
1113 	/* reply code 421 is "Service Shutting Down" */
1114 	if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
1115 	{
1116 		/* send the quit protocol */
1117 		mci->mci_state = MCIS_SSD;
1118 		smtpquit(m, mci, e);
1119 	}
1120 
1121 	return (r);
1122 }
1123 /*
1124 **  SMTPMESSAGE -- send message to server
1125 **
1126 **	Parameters:
1127 **		f -- format
1128 **		m -- the mailer to control formatting.
1129 **		a, b, c -- parameters
1130 **
1131 **	Returns:
1132 **		none.
1133 **
1134 **	Side Effects:
1135 **		writes message to mci->mci_out.
1136 */
1137 
1138 /*VARARGS1*/
1139 void
1140 #ifdef __STDC__
1141 smtpmessage(char *f, MAILER *m, MCI *mci, ...)
1142 #else
1143 smtpmessage(f, m, mci, va_alist)
1144 	char *f;
1145 	MAILER *m;
1146 	MCI *mci;
1147 	va_dcl
1148 #endif
1149 {
1150 	VA_LOCAL_DECL
1151 
1152 	VA_START(mci);
1153 	(void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap);
1154 	VA_END;
1155 
1156 	if (tTd(18, 1) || Verbose)
1157 		nmessage(">>> %s", SmtpMsgBuffer);
1158 	if (TrafficLogFile != NULL)
1159 		fprintf(TrafficLogFile, "%05d >>> %s\n",
1160 			(int) getpid(), SmtpMsgBuffer);
1161 	if (mci->mci_out != NULL)
1162 	{
1163 		fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
1164 			m == NULL ? "\r\n" : m->m_eol);
1165 	}
1166 	else if (tTd(18, 1))
1167 	{
1168 		printf("smtpmessage: NULL mci_out\n");
1169 	}
1170 }
1171 
1172 # endif /* SMTP */
1173