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