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