1 /*
2  * Copyright (c) 1983 Eric P. Allman
3  * Copyright (c) 1988 Regents of the University of California.
4  * 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	6.22 (Berkeley) 04/04/93 (with SMTP)";
14 #else
15 static char sccsid[] = "@(#)usersmtp.c	6.22 (Berkeley) 04/04/93 (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 
39 #ifdef __STDC__
40 extern	smtpmessage(char *f, MAILER *m, MCI *mci, ...);
41 #endif
42 /*
43 **  SMTPINIT -- initialize SMTP.
44 **
45 **	Opens the connection and sends the initial protocol.
46 **
47 **	Parameters:
48 **		m -- mailer to create connection to.
49 **		pvp -- pointer to parameter vector to pass to
50 **			the mailer.
51 **
52 **	Returns:
53 **		none.
54 **
55 **	Side Effects:
56 **		creates connection and sends initial protocol.
57 */
58 
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 STAB *stab();
67 
68 	if (tTd(17, 1))
69 	{
70 		printf("smtpinit ");
71 		mci_dump(mci);
72 	}
73 
74 	/*
75 	**  Open the connection to the mailer.
76 	*/
77 
78 	SmtpError[0] = '\0';
79 	CurHostName = mci->mci_host;		/* XXX UGLY XXX */
80 	switch (mci->mci_state)
81 	{
82 	  case MCIS_ACTIVE:
83 		/* need to clear old information */
84 		smtprset(m, mci, e);
85 		/* fall through */
86 
87 	  case MCIS_OPEN:
88 		return;
89 
90 	  case MCIS_ERROR:
91 	  case MCIS_SSD:
92 		/* shouldn't happen */
93 		smtpquit(m, mci, e);
94 		/* fall through */
95 
96 	  case MCIS_CLOSED:
97 		syserr("451 smtpinit: state CLOSED");
98 		return;
99 
100 	  case MCIS_OPENING:
101 		break;
102 	}
103 
104 	SmtpPhase = mci->mci_phase = "user open";
105 	mci->mci_state = MCIS_OPENING;
106 
107 	/*
108 	**  Get the greeting message.
109 	**	This should appear spontaneously.  Give it five minutes to
110 	**	happen.
111 	*/
112 
113 	SmtpPhase = mci->mci_phase = "greeting wait";
114 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
115 	r = reply(m, mci, e, TimeOuts.to_initial);
116 	if (r < 0 || REPLYTYPE(r) != 2)
117 		goto tempfail1;
118 
119 	/*
120 	**  Send the HELO command.
121 	**	My mother taught me to always introduce myself.
122 	*/
123 
124 	smtpmessage("HELO %s", m, mci, MyHostName);
125 	SmtpPhase = mci->mci_phase = "HELO wait";
126 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
127 	r = reply(m, mci, e, TimeOuts.to_helo);
128 	if (r < 0)
129 		goto tempfail1;
130 	else if (REPLYTYPE(r) == 5)
131 		goto unavailable;
132 	else if (REPLYTYPE(r) != 2)
133 		goto tempfail1;
134 
135 	/*
136 	**  Check to see if we actually ended up talking to ourself.
137 	**  This means we didn't know about an alias or MX, or we managed
138 	**  to connect to an echo server.
139 	*/
140 
141 	p = strchr(SmtpReplyBuffer, ' ');
142 	if (p != NULL)
143 		*p == '\0';
144 	if (strcasecmp(SmtpReplyBuffer, MyHostName) == 0)
145 	{
146 		syserr("553 %s config error: mail loops back to myself",
147 			MyHostName);
148 		mci->mci_exitstat = EX_CONFIG;
149 		mci->mci_errno = 0;
150 		smtpquit(m, mci, e);
151 		return;
152 	}
153 
154 	/*
155 	**  If this is expected to be another sendmail, send some internal
156 	**  commands.
157 	*/
158 
159 	if (bitnset(M_INTERNAL, m->m_flags))
160 	{
161 		/* tell it to be verbose */
162 		smtpmessage("VERB", m, mci);
163 		r = reply(m, mci, e, TimeOuts.to_miscshort);
164 		if (r < 0)
165 			goto tempfail2;
166 	}
167 
168 	mci->mci_state = MCIS_OPEN;
169 	return;
170 
171   tempfail1:
172   tempfail2:
173 	mci->mci_exitstat = EX_TEMPFAIL;
174 	if (mci->mci_errno == 0)
175 		mci->mci_errno = errno;
176 	if (mci->mci_state != MCIS_CLOSED)
177 		smtpquit(m, mci, e);
178 	return;
179 
180   unavailable:
181 	mci->mci_exitstat = EX_UNAVAILABLE;
182 	mci->mci_errno = errno;
183 	smtpquit(m, mci, e);
184 	return;
185 }
186 
187 smtpmailfrom(m, mci, e)
188 	struct mailer *m;
189 	MCI *mci;
190 	ENVELOPE *e;
191 {
192 	int r;
193 	char buf[MAXNAME];
194 
195 	if (tTd(17, 2))
196 		printf("smtpmailfrom: CurHost=%s\n", CurHostName);
197 
198 	/*
199 	**  Send the MAIL command.
200 	**	Designates the sender.
201 	*/
202 
203 	mci->mci_state = MCIS_ACTIVE;
204 
205 	if (bitset(EF_RESPONSE, e->e_flags))
206 		(void) strcpy(buf, "");
207 	else
208 		expand("\201g", buf, &buf[sizeof buf - 1], e);
209 	if (e->e_from.q_mailer == LocalMailer ||
210 	    !bitnset(M_FROMPATH, m->m_flags))
211 	{
212 		smtpmessage("MAIL From:<%s>", m, mci, buf);
213 	}
214 	else
215 	{
216 		smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName,
217 			buf[0] == '@' ? ',' : ':', buf);
218 	}
219 	SmtpPhase = mci->mci_phase = "MAIL wait";
220 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
221 	r = reply(m, mci, e, TimeOuts.to_mail);
222 	if (r < 0 || REPLYTYPE(r) == 4)
223 	{
224 		mci->mci_exitstat = EX_TEMPFAIL;
225 		mci->mci_errno = errno;
226 		smtpquit(m, mci, e);
227 		return EX_TEMPFAIL;
228 	}
229 	else if (r == 250)
230 	{
231 		mci->mci_exitstat = EX_OK;
232 		return EX_OK;
233 	}
234 	else if (r == 552)
235 	{
236 		/* signal service unavailable */
237 		mci->mci_exitstat = EX_UNAVAILABLE;
238 		smtpquit(m, mci, e);
239 		return EX_UNAVAILABLE;
240 	}
241 
242 #ifdef LOG
243 	if (LogLevel > 1)
244 	{
245 		syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s",
246 			e->e_id, SmtpReplyBuffer);
247 	}
248 #endif
249 
250 	/* protocol error -- close up */
251 	smtpquit(m, mci, e);
252 	mci->mci_exitstat = EX_PROTOCOL;
253 	return EX_PROTOCOL;
254 }
255 /*
256 **  SMTPRCPT -- designate recipient.
257 **
258 **	Parameters:
259 **		to -- address of recipient.
260 **		m -- the mailer we are sending to.
261 **		mci -- the connection info for this transaction.
262 **		e -- the envelope for this transaction.
263 **
264 **	Returns:
265 **		exit status corresponding to recipient status.
266 **
267 **	Side Effects:
268 **		Sends the mail via SMTP.
269 */
270 
271 smtprcpt(to, m, mci, e)
272 	ADDRESS *to;
273 	register MAILER *m;
274 	MCI *mci;
275 	ENVELOPE *e;
276 {
277 	register int r;
278 
279 	smtpmessage("RCPT To:<%s>", m, mci, to->q_user);
280 
281 	SmtpPhase = mci->mci_phase = "RCPT wait";
282 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
283 	r = reply(m, mci, e, TimeOuts.to_rcpt);
284 	if (r < 0 || REPLYTYPE(r) == 4)
285 		return (EX_TEMPFAIL);
286 	else if (REPLYTYPE(r) == 2)
287 		return (EX_OK);
288 	else if (r == 550 || r == 551 || r == 553)
289 		return (EX_NOUSER);
290 	else if (r == 552 || r == 554)
291 		return (EX_UNAVAILABLE);
292 
293 #ifdef LOG
294 	if (LogLevel > 1)
295 	{
296 		syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s",
297 			e->e_id, SmtpReplyBuffer);
298 	}
299 #endif
300 
301 	return (EX_PROTOCOL);
302 }
303 /*
304 **  SMTPDATA -- send the data and clean up the transaction.
305 **
306 **	Parameters:
307 **		m -- mailer being sent to.
308 **		e -- the envelope for this message.
309 **
310 **	Returns:
311 **		exit status corresponding to DATA command.
312 **
313 **	Side Effects:
314 **		none.
315 */
316 
317 smtpdata(m, mci, e)
318 	struct mailer *m;
319 	register MCI *mci;
320 	register ENVELOPE *e;
321 {
322 	register int r;
323 
324 	/*
325 	**  Send the data.
326 	**	First send the command and check that it is ok.
327 	**	Then send the data.
328 	**	Follow it up with a dot to terminate.
329 	**	Finally get the results of the transaction.
330 	*/
331 
332 	/* send the command and check ok to proceed */
333 	smtpmessage("DATA", m, mci);
334 	SmtpPhase = mci->mci_phase = "DATA wait";
335 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
336 	r = reply(m, mci, e, TimeOuts.to_datainit);
337 	if (r < 0 || REPLYTYPE(r) == 4)
338 	{
339 		smtpquit(m, mci, e);
340 		return (EX_TEMPFAIL);
341 	}
342 	else if (r == 554)
343 	{
344 		smtprset(m, mci, e);
345 		return (EX_UNAVAILABLE);
346 	}
347 	else if (r != 354)
348 	{
349 #ifdef LOG
350 		if (LogLevel > 1)
351 		{
352 			syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s",
353 				e->e_id, SmtpReplyBuffer);
354 		}
355 #endif
356 		smtprset(m, mci, e);
357 		return (EX_PROTOCOL);
358 	}
359 
360 	/* now output the actual message */
361 	(*e->e_puthdr)(mci->mci_out, m, e);
362 	putline("\n", mci->mci_out, m);
363 	(*e->e_putbody)(mci->mci_out, m, e);
364 
365 	/* terminate the message */
366 	fprintf(mci->mci_out, ".%s", m->m_eol);
367 	if (Verbose)
368 		nmessage(">>> .");
369 
370 	/* check for the results of the transaction */
371 	SmtpPhase = mci->mci_phase = "result wait";
372 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
373 	r = reply(m, mci, e, TimeOuts.to_datafinal);
374 	if (r < 0)
375 	{
376 		smtpquit(m, mci, e);
377 		return (EX_TEMPFAIL);
378 	}
379 	mci->mci_state = MCIS_OPEN;
380 	e->e_statmsg = newstr(&SmtpReplyBuffer[4]);
381 	if (REPLYTYPE(r) == 4)
382 		return (EX_TEMPFAIL);
383 	else if (r == 250)
384 		return (EX_OK);
385 	else if (r == 552 || r == 554)
386 		return (EX_UNAVAILABLE);
387 #ifdef LOG
388 	if (LogLevel > 1)
389 	{
390 		syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s",
391 			e->e_id, SmtpReplyBuffer);
392 	}
393 #endif
394 	return (EX_PROTOCOL);
395 }
396 /*
397 **  SMTPQUIT -- close the SMTP connection.
398 **
399 **	Parameters:
400 **		m -- a pointer to the mailer.
401 **
402 **	Returns:
403 **		none.
404 **
405 **	Side Effects:
406 **		sends the final protocol and closes the connection.
407 */
408 
409 smtpquit(m, mci, e)
410 	register MAILER *m;
411 	register MCI *mci;
412 	ENVELOPE *e;
413 {
414 	int i;
415 
416 	/* send the quit message if we haven't gotten I/O error */
417 	if (mci->mci_state != MCIS_ERROR)
418 	{
419 		smtpmessage("QUIT", m, mci);
420 		(void) reply(m, mci, e, TimeOuts.to_quit);
421 		if (mci->mci_state == MCIS_CLOSED)
422 			return;
423 	}
424 
425 	/* now actually close the connection and pick up the zombie */
426 	i = endmailer(mci, e, m->m_argv);
427 	if (i != EX_OK)
428 		syserr("451 smtpquit %s: stat %d", m->m_argv[0], i);
429 }
430 /*
431 **  SMTPRSET -- send a RSET (reset) command
432 */
433 
434 smtprset(m, mci, e)
435 	register MAILER *m;
436 	register MCI *mci;
437 	ENVELOPE *e;
438 {
439 	int r;
440 
441 	smtpmessage("RSET", m, mci);
442 	r = reply(m, mci, e, TimeOuts.to_rset);
443 	if (r < 0)
444 		mci->mci_state = MCIS_ERROR;
445 	else if (REPLYTYPE(r) == 2)
446 	{
447 		mci->mci_state = MCIS_OPEN;
448 		return;
449 	}
450 	smtpquit(m, mci, e);
451 }
452 /*
453 **  SMTPPROBE -- check the connection state
454 */
455 
456 smtpprobe(mci)
457 	register MCI *mci;
458 {
459 	int r;
460 	MAILER *m = mci->mci_mailer;
461 	extern ENVELOPE BlankEnvelope;
462 	ENVELOPE *e = &BlankEnvelope;
463 
464 	smtpmessage("RSET", m, mci);
465 	r = reply(m, mci, e, TimeOuts.to_miscshort);
466 	if (r < 0 || REPLYTYPE(r) != 2)
467 		smtpquit(m, mci, e);
468 	return r;
469 }
470 /*
471 **  REPLY -- read arpanet reply
472 **
473 **	Parameters:
474 **		m -- the mailer we are reading the reply from.
475 **		mci -- the mailer connection info structure.
476 **		e -- the current envelope.
477 **		timeout -- the timeout for reads.
478 **
479 **	Returns:
480 **		reply code it reads.
481 **
482 **	Side Effects:
483 **		flushes the mail file.
484 */
485 
486 reply(m, mci, e, timeout)
487 	MAILER *m;
488 	MCI *mci;
489 	ENVELOPE *e;
490 {
491 	char *bufp = SmtpReplyBuffer;
492 	char junkbuf[MAXLINE];
493 
494 	if (mci->mci_out != NULL)
495 		(void) fflush(mci->mci_out);
496 
497 	if (tTd(18, 1))
498 		printf("reply\n");
499 
500 	/*
501 	**  Read the input line, being careful not to hang.
502 	*/
503 
504 	for (;; bufp = junkbuf)
505 	{
506 		register int r;
507 		register char *p;
508 		extern time_t curtime();
509 
510 		/* actually do the read */
511 		if (e->e_xfp != NULL)
512 			(void) fflush(e->e_xfp);	/* for debugging */
513 
514 		/* if we are in the process of closing just give the code */
515 		if (mci->mci_state == MCIS_CLOSED)
516 			return (SMTPCLOSING);
517 
518 		if (mci->mci_out != NULL)
519 			fflush(mci->mci_out);
520 
521 		/* get the line from the other side */
522 		p = sfgets(bufp, MAXLINE, mci->mci_in, timeout);
523 		mci->mci_lastuse = curtime();
524 
525 		if (p == NULL)
526 		{
527 			extern char MsgBuf[];		/* err.c */
528 
529 			/* if the remote end closed early, fake an error */
530 			if (errno == 0)
531 # ifdef ECONNRESET
532 				errno = ECONNRESET;
533 # else /* ECONNRESET */
534 				errno = EPIPE;
535 # endif /* ECONNRESET */
536 
537 			mci->mci_errno = errno;
538 			mci->mci_exitstat = EX_TEMPFAIL;
539 			message("451 %s: reply: read error from %s",
540 				e->e_id == NULL ? "NOQUEUE" : e->e_id,
541 				mci->mci_host);
542 			/* if debugging, pause so we can see state */
543 			if (tTd(18, 100))
544 				pause();
545 # ifdef LOG
546 			if (LogLevel > 1)
547 				syslog(LOG_INFO, "%s", &MsgBuf[4]);
548 # endif /* LOG */
549 			mci->mci_state = MCIS_ERROR;
550 			smtpquit(m, mci, e);
551 			return (-1);
552 		}
553 		fixcrlf(bufp, TRUE);
554 
555 		if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL)
556 		{
557 			/* serious error -- log the previous command */
558 			if (bufp[0] != '\0')
559 				fprintf(e->e_xfp, ">>> %s\n", bufp);
560 			bufp[0] = '\0';
561 
562 			/* now log the message as from the other side */
563 			fprintf(e->e_xfp, "<<< %s\n", bufp);
564 		}
565 
566 		/* display the input for verbose mode */
567 		if (Verbose)
568 			nmessage("%s", bufp);
569 
570 		/* if continuation is required, we can go on */
571 		if (bufp[3] == '-' ||
572 		    !(isascii(bufp[0]) && isdigit(bufp[0])))
573 			continue;
574 
575 		/* decode the reply code */
576 		r = atoi(SmtpReplyBuffer);
577 
578 		/* extra semantics: 0xx codes are "informational" */
579 		if (r < 100)
580 			continue;
581 
582 		/* save temporary failure messages for posterity */
583 		if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
584 			(void) strcpy(SmtpError, SmtpReplyBuffer);
585 
586 		/* reply code 421 is "Service Shutting Down" */
587 		if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
588 		{
589 			/* send the quit protocol */
590 			mci->mci_state = MCIS_SSD;
591 			smtpquit(m, mci, e);
592 		}
593 
594 		return (r);
595 	}
596 }
597 /*
598 **  SMTPMESSAGE -- send message to server
599 **
600 **	Parameters:
601 **		f -- format
602 **		m -- the mailer to control formatting.
603 **		a, b, c -- parameters
604 **
605 **	Returns:
606 **		none.
607 **
608 **	Side Effects:
609 **		writes message to mci->mci_out.
610 */
611 
612 /*VARARGS1*/
613 #ifdef __STDC__
614 smtpmessage(char *f, MAILER *m, MCI *mci, ...)
615 #else
616 smtpmessage(f, m, mci, va_alist)
617 	char *f;
618 	MAILER *m;
619 	MCI *mci;
620 	va_dcl
621 #endif
622 {
623 	VA_LOCAL_DECL
624 
625 	VA_START(mci);
626 	(void) vsprintf(SmtpMsgBuffer, f, ap);
627 	VA_END;
628 
629 	if (tTd(18, 1) || Verbose)
630 		nmessage(">>> %s", SmtpMsgBuffer);
631 	if (mci->mci_out != NULL)
632 	{
633 		fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
634 			m == NULL ? "\r\n" : m->m_eol);
635 	}
636 	else
637 	{
638 		syserr("smtpmessage: NULL mci_out");
639 	}
640 }
641 
642 # endif /* SMTP */
643