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