xref: /freebsd/contrib/sendmail/src/usersmtp.c (revision c3debd01c8e835bcbdb7c758506f8bd5c7976d2c)
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.108 (Berkeley) 10/6/1998 (with SMTP)";
18 #else
19 static char sccsid[] = "@(#)usersmtp.c	8.108 (Berkeley) 10/6/1998 (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 	int l;
331 	char *bufp;
332 	char *bodytype;
333 	char buf[MAXNAME + 1];
334 	char optbuf[MAXLINE];
335 
336 	if (tTd(18, 2))
337 		printf("smtpmailfrom: CurHost=%s\n", CurHostName);
338 
339 	/* set up appropriate options to include */
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 	l = sizeof optbuf - strlen(optbuf) - 1;
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 && strlen(bodytype) + 7 < l)
356 		{
357 			strcat(optbuf, " BODY=");
358 			strcat(optbuf, bodytype);
359 			l -= strlen(optbuf);
360 		}
361 	}
362 	else if (bitnset(M_8BITS, m->m_flags) ||
363 		 !bitset(EF_HAS8BIT, e->e_flags) ||
364 		 bitset(MCIF_8BITOK, mci->mci_flags))
365 	{
366 		/* just pass it through */
367 	}
368 #if MIME8TO7
369 	else if (bitset(MM_CVTMIME, MimeMode) &&
370 		 !bitset(EF_DONT_MIME, e->e_flags) &&
371 		 (!bitset(MM_PASS8BIT, MimeMode) ||
372 		  bitset(EF_IS_MIME, e->e_flags)))
373 	{
374 		/* must convert from 8bit MIME format to 7bit encoded */
375 		mci->mci_flags |= MCIF_CVT8TO7;
376 	}
377 #endif
378 	else if (!bitset(MM_PASS8BIT, MimeMode))
379 	{
380 		/* cannot just send a 8-bit version */
381 		extern char MsgBuf[];
382 
383 		usrerr("%s does not support 8BITMIME", CurHostName);
384 		mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
385 		return EX_DATAERR;
386 	}
387 
388 	if (bitset(MCIF_DSN, mci->mci_flags))
389 	{
390 		if (e->e_envid != NULL && strlen(e->e_envid) < (SIZE_T) (l - 7))
391 		{
392 			strcat(optbuf, " ENVID=");
393 			strcat(optbuf, e->e_envid);
394 			l -= strlen(optbuf);
395 		}
396 
397 		/* RET= parameter */
398 		if (bitset(EF_RET_PARAM, e->e_flags) && l >= 9)
399 		{
400 			strcat(optbuf, " RET=");
401 			if (bitset(EF_NO_BODY_RETN, e->e_flags))
402 				strcat(optbuf, "HDRS");
403 			else
404 				strcat(optbuf, "FULL");
405 			l -= 9;
406 		}
407 	}
408 
409 	/*
410 	**  Send the MAIL command.
411 	**	Designates the sender.
412 	*/
413 
414 	mci->mci_state = MCIS_ACTIVE;
415 
416 	if (bitset(EF_RESPONSE, e->e_flags) &&
417 	    !bitnset(M_NO_NULL_FROM, m->m_flags))
418 		(void) strcpy(buf, "");
419 	else
420 		expand("\201g", buf, sizeof buf, e);
421 	if (buf[0] == '<')
422 	{
423 		/* strip off <angle brackets> (put back on below) */
424 		bufp = &buf[strlen(buf) - 1];
425 		if (*bufp == '>')
426 			*bufp = '\0';
427 		bufp = &buf[1];
428 	}
429 	else
430 		bufp = buf;
431 	if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
432 	    !bitnset(M_FROMPATH, m->m_flags))
433 	{
434 		smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
435 	}
436 	else
437 	{
438 		smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
439 			*bufp == '@' ? ',' : ':', bufp, optbuf);
440 	}
441 	SmtpPhase = mci->mci_phase = "client MAIL";
442 	sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
443 	r = reply(m, mci, e, TimeOuts.to_mail, NULL);
444 	if (r < 0)
445 	{
446 		/* communications failure */
447 		mci->mci_errno = errno;
448 		mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
449 		smtpquit(m, mci, e);
450 		return EX_TEMPFAIL;
451 	}
452 	else if (r == 421)
453 	{
454 		/* service shutting down */
455 		mci_setstat(mci, EX_TEMPFAIL, "4.5.0", SmtpReplyBuffer);
456 		smtpquit(m, mci, e);
457 		return EX_TEMPFAIL;
458 	}
459 	else if (REPLYTYPE(r) == 4)
460 	{
461 		mci_setstat(mci, EX_NOTSTICKY, smtptodsn(r), SmtpReplyBuffer);
462 		return EX_TEMPFAIL;
463 	}
464 	else if (REPLYTYPE(r) == 2)
465 	{
466 		return EX_OK;
467 	}
468 	else if (r == 501)
469 	{
470 		/* syntax error in arguments */
471 		mci_setstat(mci, EX_NOTSTICKY, "5.5.2", SmtpReplyBuffer);
472 		return EX_DATAERR;
473 	}
474 	else if (r == 553)
475 	{
476 		/* mailbox name not allowed */
477 		mci_setstat(mci, EX_NOTSTICKY, "5.1.3", SmtpReplyBuffer);
478 		return EX_DATAERR;
479 	}
480 	else if (r == 552)
481 	{
482 		/* exceeded storage allocation */
483 		mci_setstat(mci, EX_NOTSTICKY, "5.3.4", SmtpReplyBuffer);
484 		if (bitset(MCIF_SIZE, mci->mci_flags))
485 			e->e_flags |= EF_NO_BODY_RETN;
486 		return EX_UNAVAILABLE;
487 	}
488 	else if (REPLYTYPE(r) == 5)
489 	{
490 		/* unknown error */
491 		mci_setstat(mci, EX_NOTSTICKY, "5.0.0", SmtpReplyBuffer);
492 		return EX_UNAVAILABLE;
493 	}
494 
495 	if (LogLevel > 1)
496 	{
497 		sm_syslog(LOG_CRIT, e->e_id,
498 			"%.100s: SMTP MAIL protocol error: %s",
499 			CurHostName,
500 			shortenstring(SmtpReplyBuffer, 403));
501 	}
502 
503 	/* protocol error -- close up */
504 	mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer);
505 	smtpquit(m, mci, e);
506 	return EX_PROTOCOL;
507 }
508 /*
509 **  SMTPRCPT -- designate recipient.
510 **
511 **	Parameters:
512 **		to -- address of recipient.
513 **		m -- the mailer we are sending to.
514 **		mci -- the connection info for this transaction.
515 **		e -- the envelope for this transaction.
516 **
517 **	Returns:
518 **		exit status corresponding to recipient status.
519 **
520 **	Side Effects:
521 **		Sends the mail via SMTP.
522 */
523 
524 int
525 smtprcpt(to, m, mci, e)
526 	ADDRESS *to;
527 	register MAILER *m;
528 	MCI *mci;
529 	ENVELOPE *e;
530 {
531 	register int r;
532 	int l;
533 	char optbuf[MAXLINE];
534 
535 	strcpy(optbuf, "");
536 	l = sizeof optbuf - 1;
537 	if (bitset(MCIF_DSN, mci->mci_flags))
538 	{
539 		/* NOTIFY= parameter */
540 		if (bitset(QHASNOTIFY, to->q_flags) &&
541 		    bitset(QPRIMARY, to->q_flags) &&
542 		    !bitnset(M_LOCALMAILER, m->m_flags))
543 		{
544 			bool firstone = TRUE;
545 
546 			strcat(optbuf, " NOTIFY=");
547 			if (bitset(QPINGONSUCCESS, to->q_flags))
548 			{
549 				strcat(optbuf, "SUCCESS");
550 				firstone = FALSE;
551 			}
552 			if (bitset(QPINGONFAILURE, to->q_flags))
553 			{
554 				if (!firstone)
555 					strcat(optbuf, ",");
556 				strcat(optbuf, "FAILURE");
557 				firstone = FALSE;
558 			}
559 			if (bitset(QPINGONDELAY, to->q_flags))
560 			{
561 				if (!firstone)
562 					strcat(optbuf, ",");
563 				strcat(optbuf, "DELAY");
564 				firstone = FALSE;
565 			}
566 			if (firstone)
567 				strcat(optbuf, "NEVER");
568 			l -= strlen(optbuf);
569 		}
570 
571 		/* ORCPT= parameter */
572 		if (to->q_orcpt != NULL && strlen(to->q_orcpt) + 7 < l)
573 		{
574 			strcat(optbuf, " ORCPT=");
575 			strcat(optbuf, to->q_orcpt);
576 			l -= strlen(optbuf);
577 		}
578 	}
579 
580 	smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
581 
582 	SmtpPhase = mci->mci_phase = "client RCPT";
583 	sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
584 	r = reply(m, mci, e, TimeOuts.to_rcpt, NULL);
585 	to->q_rstatus = newstr(SmtpReplyBuffer);
586 	to->q_status = smtptodsn(r);
587 	to->q_statmta = mci->mci_host;
588 	if (r < 0 || REPLYTYPE(r) == 4)
589 		return EX_TEMPFAIL;
590 	else if (REPLYTYPE(r) == 2)
591 		return EX_OK;
592 	else if (r == 550)
593 	{
594 		to->q_status = "5.1.1";
595 		return EX_NOUSER;
596 	}
597 	else if (r == 551)
598 	{
599 		to->q_status = "5.1.6";
600 		return EX_NOUSER;
601 	}
602 	else if (r == 553)
603 	{
604 		to->q_status = "5.1.3";
605 		return EX_NOUSER;
606 	}
607 	else if (REPLYTYPE(r) == 5)
608 	{
609 		return EX_UNAVAILABLE;
610 	}
611 
612 	if (LogLevel > 1)
613 	{
614 		sm_syslog(LOG_CRIT, e->e_id,
615 			"%.100s: SMTP RCPT protocol error: %s",
616 			CurHostName,
617 			shortenstring(SmtpReplyBuffer, 403));
618 	}
619 
620 	mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer);
621 	return EX_PROTOCOL;
622 }
623 /*
624 **  SMTPDATA -- send the data and clean up the transaction.
625 **
626 **	Parameters:
627 **		m -- mailer being sent to.
628 **		mci -- the mailer connection information.
629 **		e -- the envelope for this message.
630 **
631 **	Returns:
632 **		exit status corresponding to DATA command.
633 **
634 **	Side Effects:
635 **		none.
636 */
637 
638 static jmp_buf	CtxDataTimeout;
639 static void	datatimeout __P((void));
640 
641 int
642 smtpdata(m, mci, e)
643 	MAILER *m;
644 	register MCI *mci;
645 	register ENVELOPE *e;
646 {
647 	register int r;
648 	register EVENT *ev;
649 	int rstat;
650 	int xstat;
651 	time_t timeout;
652 
653 	/*
654 	**  Send the data.
655 	**	First send the command and check that it is ok.
656 	**	Then send the data.
657 	**	Follow it up with a dot to terminate.
658 	**	Finally get the results of the transaction.
659 	*/
660 
661 	/* send the command and check ok to proceed */
662 	smtpmessage("DATA", m, mci);
663 	SmtpPhase = mci->mci_phase = "client DATA 354";
664 	sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
665 	r = reply(m, mci, e, TimeOuts.to_datainit, NULL);
666 	if (r < 0 || REPLYTYPE(r) == 4)
667 	{
668 		smtpquit(m, mci, e);
669 		return EX_TEMPFAIL;
670 	}
671 	else if (REPLYTYPE(r) == 5)
672 	{
673 		smtprset(m, mci, e);
674 		return EX_UNAVAILABLE;
675 	}
676 	else if (r != 354)
677 	{
678 		if (LogLevel > 1)
679 		{
680 			sm_syslog(LOG_CRIT, e->e_id,
681 				"%.100s: SMTP DATA-1 protocol error: %s",
682 				CurHostName,
683 				shortenstring(SmtpReplyBuffer, 403));
684 		}
685 		smtprset(m, mci, e);
686 		mci_setstat(mci, EX_PROTOCOL, "5.5.1", SmtpReplyBuffer);
687 		return (EX_PROTOCOL);
688 	}
689 
690 	/*
691 	**  Set timeout around data writes.  Make it at least large
692 	**  enough for DNS timeouts on all recipients plus some fudge
693 	**  factor.  The main thing is that it should not be infinite.
694 	*/
695 
696 	if (setjmp(CtxDataTimeout) != 0)
697 	{
698 		mci->mci_errno = errno;
699 		mci->mci_state = MCIS_ERROR;
700 		mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
701 		syserr("451 timeout writing message to %s", CurHostName);
702 		smtpquit(m, mci, e);
703 		return EX_TEMPFAIL;
704 	}
705 
706 	timeout = e->e_msgsize / 16;
707 	if (timeout < (time_t) 600)
708 		timeout = (time_t) 600;
709 	timeout += e->e_nrcpts * 300;
710 	ev = setevent(timeout, datatimeout, 0);
711 
712 	/*
713 	**  Output the actual message.
714 	*/
715 
716 	(*e->e_puthdr)(mci, e->e_header, e);
717 	(*e->e_putbody)(mci, e, NULL);
718 
719 	/*
720 	**  Cleanup after sending message.
721 	*/
722 
723 	clrevent(ev);
724 
725 	if (ferror(mci->mci_out))
726 	{
727 		/* error during processing -- don't send the dot */
728 		mci->mci_errno = EIO;
729 		mci->mci_state = MCIS_ERROR;
730 		mci_setstat(mci, EX_IOERR, "4.4.2", NULL);
731 		smtpquit(m, mci, e);
732 		return EX_IOERR;
733 	}
734 
735 	/* terminate the message */
736 	fprintf(mci->mci_out, ".%s", m->m_eol);
737 	if (TrafficLogFile != NULL)
738 		fprintf(TrafficLogFile, "%05d >>> .\n", (int) getpid());
739 	if (Verbose)
740 		nmessage(">>> .");
741 
742 	/* check for the results of the transaction */
743 	SmtpPhase = mci->mci_phase = "client DATA status";
744 	sm_setproctitle(TRUE, "%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
745 	if (bitnset(M_LMTP, m->m_flags))
746 		return EX_OK;
747 	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL);
748 	if (r < 0)
749 	{
750 		smtpquit(m, mci, e);
751 		return EX_TEMPFAIL;
752 	}
753 	mci->mci_state = MCIS_OPEN;
754 	xstat = EX_NOTSTICKY;
755 	if (r == 452)
756 		rstat = EX_TEMPFAIL;
757 	else if (REPLYTYPE(r) == 4)
758 		rstat = xstat = EX_TEMPFAIL;
759 	else if (REPLYCLASS(r) != 5)
760 		rstat = xstat = EX_PROTOCOL;
761 	else if (REPLYTYPE(r) == 2)
762 		rstat = xstat = EX_OK;
763 	else if (REPLYTYPE(r) == 5)
764 		rstat = EX_UNAVAILABLE;
765 	else
766 		rstat = EX_PROTOCOL;
767 	mci_setstat(mci, xstat, smtptodsn(r), SmtpReplyBuffer);
768 	if (e->e_statmsg != NULL)
769 		free(e->e_statmsg);
770 	e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
771 	if (rstat != EX_PROTOCOL)
772 		return rstat;
773 	if (LogLevel > 1)
774 	{
775 		sm_syslog(LOG_CRIT, e->e_id,
776 			"%.100s: SMTP DATA-2 protocol error: %s",
777 			CurHostName,
778 			shortenstring(SmtpReplyBuffer, 403));
779 	}
780 	return rstat;
781 }
782 
783 
784 static void
785 datatimeout()
786 {
787 	longjmp(CtxDataTimeout, 1);
788 }
789 /*
790 **  SMTPGETSTAT -- get status code from DATA in LMTP
791 **
792 **	Parameters:
793 **		m -- the mailer to which we are sending the message.
794 **		mci -- the mailer connection structure.
795 **		e -- the current envelope.
796 **
797 **	Returns:
798 **		The exit status corresponding to the reply code.
799 */
800 
801 int
802 smtpgetstat(m, mci, e)
803 	MAILER *m;
804 	MCI *mci;
805 	ENVELOPE *e;
806 {
807 	int r;
808 	int stat;
809 
810 	/* check for the results of the transaction */
811 	r = reply(m, mci, e, TimeOuts.to_datafinal, NULL);
812 	if (r < 0)
813 	{
814 		smtpquit(m, mci, e);
815 		return EX_TEMPFAIL;
816 	}
817 	if (e->e_statmsg != NULL)
818 		free(e->e_statmsg);
819 	e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
820 	if (REPLYTYPE(r) == 4)
821 		stat = EX_TEMPFAIL;
822 	else if (REPLYCLASS(r) != 5)
823 		stat = EX_PROTOCOL;
824 	else if (REPLYTYPE(r) == 2)
825 		stat = EX_OK;
826 	else if (REPLYTYPE(r) == 5)
827 		stat = EX_UNAVAILABLE;
828 	else
829 		stat = EX_PROTOCOL;
830 	mci_setstat(mci, stat, smtptodsn(r), SmtpReplyBuffer);
831 	if (LogLevel > 1 && stat == EX_PROTOCOL)
832 	{
833 		sm_syslog(LOG_CRIT, e->e_id,
834 			"%.100s: SMTP DATA-3 protocol error: %s",
835 			CurHostName,
836 			shortenstring(SmtpReplyBuffer, 403));
837 	}
838 	return stat;
839 }
840 /*
841 **  SMTPQUIT -- close the SMTP connection.
842 **
843 **	Parameters:
844 **		m -- a pointer to the mailer.
845 **		mci -- the mailer connection information.
846 **		e -- the current envelope.
847 **
848 **	Returns:
849 **		none.
850 **
851 **	Side Effects:
852 **		sends the final protocol and closes the connection.
853 */
854 
855 void
856 smtpquit(m, mci, e)
857 	register MAILER *m;
858 	register MCI *mci;
859 	ENVELOPE *e;
860 {
861 	bool oldSuprErrs = SuprErrs;
862 
863 	/*
864 	**	Suppress errors here -- we may be processing a different
865 	**	job when we do the quit connection, and we don't want the
866 	**	new job to be penalized for something that isn't it's
867 	**	problem.
868 	*/
869 
870 	SuprErrs = TRUE;
871 
872 	/* send the quit message if we haven't gotten I/O error */
873 	if (mci->mci_state != MCIS_ERROR)
874 	{
875 		SmtpPhase = "client QUIT";
876 		smtpmessage("QUIT", m, mci);
877 		(void) reply(m, mci, e, TimeOuts.to_quit, NULL);
878 		SuprErrs = oldSuprErrs;
879 		if (mci->mci_state == MCIS_CLOSED)
880 			return;
881 	}
882 
883 	/* now actually close the connection and pick up the zombie */
884 	(void) endmailer(mci, e, NULL);
885 
886 	SuprErrs = oldSuprErrs;
887 }
888 /*
889 **  SMTPRSET -- send a RSET (reset) command
890 */
891 
892 void
893 smtprset(m, mci, e)
894 	register MAILER *m;
895 	register MCI *mci;
896 	ENVELOPE *e;
897 {
898 	int r;
899 
900 	SmtpPhase = "client RSET";
901 	smtpmessage("RSET", m, mci);
902 	r = reply(m, mci, e, TimeOuts.to_rset, NULL);
903 	if (r < 0)
904 		mci->mci_state = MCIS_ERROR;
905 	else if (REPLYTYPE(r) == 2)
906 	{
907 		mci->mci_state = MCIS_OPEN;
908 		return;
909 	}
910 	smtpquit(m, mci, e);
911 }
912 /*
913 **  SMTPPROBE -- check the connection state
914 */
915 
916 int
917 smtpprobe(mci)
918 	register MCI *mci;
919 {
920 	int r;
921 	MAILER *m = mci->mci_mailer;
922 	extern ENVELOPE BlankEnvelope;
923 	ENVELOPE *e = &BlankEnvelope;
924 
925 	SmtpPhase = "client probe";
926 	smtpmessage("RSET", m, mci);
927 	r = reply(m, mci, e, TimeOuts.to_miscshort, NULL);
928 	if (r < 0 || REPLYTYPE(r) != 2)
929 		smtpquit(m, mci, e);
930 	return r;
931 }
932 /*
933 **  REPLY -- read arpanet reply
934 **
935 **	Parameters:
936 **		m -- the mailer we are reading the reply from.
937 **		mci -- the mailer connection info structure.
938 **		e -- the current envelope.
939 **		timeout -- the timeout for reads.
940 **		pfunc -- processing function called on each line of response.
941 **			If null, no special processing is done.
942 **
943 **	Returns:
944 **		reply code it reads.
945 **
946 **	Side Effects:
947 **		flushes the mail file.
948 */
949 
950 int
951 reply(m, mci, e, timeout, pfunc)
952 	MAILER *m;
953 	MCI *mci;
954 	ENVELOPE *e;
955 	time_t timeout;
956 	void (*pfunc)();
957 {
958 	register char *bufp;
959 	register int r;
960 	bool firstline = TRUE;
961 	char junkbuf[MAXLINE];
962 
963 	if (mci->mci_out != NULL)
964 		(void) fflush(mci->mci_out);
965 
966 	if (tTd(18, 1))
967 		printf("reply\n");
968 
969 	/*
970 	**  Read the input line, being careful not to hang.
971 	*/
972 
973 	bufp = SmtpReplyBuffer;
974 	for (;;)
975 	{
976 		register char *p;
977 
978 		/* actually do the read */
979 		if (e->e_xfp != NULL)
980 			(void) fflush(e->e_xfp);	/* for debugging */
981 
982 		/* if we are in the process of closing just give the code */
983 		if (mci->mci_state == MCIS_CLOSED)
984 			return (SMTPCLOSING);
985 
986 		if (mci->mci_out != NULL)
987 			fflush(mci->mci_out);
988 
989 		/* get the line from the other side */
990 		p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
991 		mci->mci_lastuse = curtime();
992 
993 		if (p == NULL)
994 		{
995 			bool oldholderrs;
996 			extern char MsgBuf[];
997 
998 			/* if the remote end closed early, fake an error */
999 			if (errno == 0)
1000 # ifdef ECONNRESET
1001 				errno = ECONNRESET;
1002 # else /* ECONNRESET */
1003 				errno = EPIPE;
1004 # endif /* ECONNRESET */
1005 
1006 			mci->mci_errno = errno;
1007 			oldholderrs = HoldErrs;
1008 			HoldErrs = TRUE;
1009 			usrerr("451 reply: read error from %s", CurHostName);
1010 
1011 			/* errors on QUIT should not be persistent */
1012 			if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0)
1013 				mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
1014 
1015 			/* if debugging, pause so we can see state */
1016 			if (tTd(18, 100))
1017 				pause();
1018 			mci->mci_state = MCIS_ERROR;
1019 			smtpquit(m, mci, e);
1020 #if XDEBUG
1021 			{
1022 				char wbuf[MAXLINE];
1023 				char *p = wbuf;
1024 				int wbufleft = sizeof wbuf;
1025 
1026 				if (e->e_to != NULL)
1027 				{
1028 					int plen;
1029 
1030 					snprintf(p, wbufleft, "%s... ",
1031 						shortenstring(e->e_to, MAXSHORTSTR));
1032 					plen = strlen(p);
1033 					p += plen;
1034 					wbufleft -= plen;
1035 				}
1036 				snprintf(p, wbufleft, "reply(%.100s) during %s",
1037 					 CurHostName == NULL ? "NO_HOST" : CurHostName,
1038 					 SmtpPhase);
1039 				checkfd012(wbuf);
1040 			}
1041 #endif
1042 			HoldErrs = oldholderrs;
1043 			return (-1);
1044 		}
1045 		fixcrlf(bufp, TRUE);
1046 
1047 		/* EHLO failure is not a real error */
1048 		if (e->e_xfp != NULL && (bufp[0] == '4' ||
1049 		    (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
1050 		{
1051 			/* serious error -- log the previous command */
1052 			if (SmtpNeedIntro)
1053 			{
1054 				/* inform user who we are chatting with */
1055 				fprintf(CurEnv->e_xfp,
1056 					"... while talking to %s:\n",
1057 					CurHostName);
1058 				SmtpNeedIntro = FALSE;
1059 			}
1060 			if (SmtpMsgBuffer[0] != '\0')
1061 				fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
1062 			SmtpMsgBuffer[0] = '\0';
1063 
1064 			/* now log the message as from the other side */
1065 			fprintf(e->e_xfp, "<<< %s\n", bufp);
1066 		}
1067 
1068 		/* display the input for verbose mode */
1069 		if (Verbose)
1070 			nmessage("050 %s", bufp);
1071 
1072 		/* ignore improperly formated input */
1073 		if (!(isascii(bufp[0]) && isdigit(bufp[0])) ||
1074 		    !(isascii(bufp[1]) && isdigit(bufp[1])) ||
1075 		    !(isascii(bufp[2]) && isdigit(bufp[2])) ||
1076 		    !(bufp[3] == ' ' || bufp[3] == '-' || bufp[3] == '\0'))
1077 			continue;
1078 
1079 		/* process the line */
1080 		if (pfunc != NULL)
1081 			(*pfunc)(bufp, firstline, m, mci, e);
1082 
1083 		firstline = FALSE;
1084 
1085 		/* decode the reply code */
1086 		r = atoi(bufp);
1087 
1088 		/* extra semantics: 0xx codes are "informational" */
1089 		if (r < 100)
1090 			continue;
1091 
1092 		/* if no continuation lines, return this line */
1093 		if (bufp[3] != '-')
1094 			break;
1095 
1096 		/* first line of real reply -- ignore rest */
1097 		bufp = junkbuf;
1098 	}
1099 
1100 	/*
1101 	**  Now look at SmtpReplyBuffer -- only care about the first
1102 	**  line of the response from here on out.
1103 	*/
1104 
1105 	/* save temporary failure messages for posterity */
1106 	if (SmtpReplyBuffer[0] == '4' &&
1107 	    (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == '\0'))
1108 		snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer);
1109 
1110 	/* reply code 421 is "Service Shutting Down" */
1111 	if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
1112 	{
1113 		/* send the quit protocol */
1114 		mci->mci_state = MCIS_SSD;
1115 		smtpquit(m, mci, e);
1116 	}
1117 
1118 	return (r);
1119 }
1120 /*
1121 **  SMTPMESSAGE -- send message to server
1122 **
1123 **	Parameters:
1124 **		f -- format
1125 **		m -- the mailer to control formatting.
1126 **		a, b, c -- parameters
1127 **
1128 **	Returns:
1129 **		none.
1130 **
1131 **	Side Effects:
1132 **		writes message to mci->mci_out.
1133 */
1134 
1135 /*VARARGS1*/
1136 void
1137 #ifdef __STDC__
1138 smtpmessage(char *f, MAILER *m, MCI *mci, ...)
1139 #else
1140 smtpmessage(f, m, mci, va_alist)
1141 	char *f;
1142 	MAILER *m;
1143 	MCI *mci;
1144 	va_dcl
1145 #endif
1146 {
1147 	VA_LOCAL_DECL
1148 
1149 	VA_START(mci);
1150 	(void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap);
1151 	VA_END;
1152 
1153 	if (tTd(18, 1) || Verbose)
1154 		nmessage(">>> %s", SmtpMsgBuffer);
1155 	if (TrafficLogFile != NULL)
1156 		fprintf(TrafficLogFile, "%05d >>> %s\n",
1157 			(int) getpid(), SmtpMsgBuffer);
1158 	if (mci->mci_out != NULL)
1159 	{
1160 		fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
1161 			m == NULL ? "\r\n" : m->m_eol);
1162 	}
1163 	else if (tTd(18, 1))
1164 	{
1165 		printf("smtpmessage: NULL mci_out\n");
1166 	}
1167 }
1168 
1169 # endif /* SMTP */
1170