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