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.17 (Berkeley) 03/18/93 (with SMTP)";
14 #else
15 static char sccsid[] = "@(#)usersmtp.c	6.17 (Berkeley) 03/18/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 	if (REPLYTYPE(r) == 4)
362 		return (EX_TEMPFAIL);
363 	else if (r == 250)
364 		return (EX_OK);
365 	else if (r == 552 || r == 554)
366 		return (EX_UNAVAILABLE);
367 #ifdef LOG
368 	if (LogLevel > 1)
369 	{
370 		syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s",
371 			e->e_id, SmtpReplyBuffer);
372 	}
373 #endif
374 	return (EX_PROTOCOL);
375 }
376 /*
377 **  SMTPQUIT -- close the SMTP connection.
378 **
379 **	Parameters:
380 **		m -- a pointer to the mailer.
381 **
382 **	Returns:
383 **		none.
384 **
385 **	Side Effects:
386 **		sends the final protocol and closes the connection.
387 */
388 
389 smtpquit(m, mci, e)
390 	register MAILER *m;
391 	register MCI *mci;
392 	ENVELOPE *e;
393 {
394 	int i;
395 
396 	/* send the quit message if we haven't gotten I/O error */
397 	if (mci->mci_state != MCIS_ERROR)
398 	{
399 		smtpmessage("QUIT", m, mci);
400 		(void) reply(m, mci, e, TimeOuts.to_quit);
401 		if (mci->mci_state == MCIS_CLOSED)
402 			return;
403 	}
404 
405 	/* now actually close the connection and pick up the zombie */
406 	i = endmailer(mci, m->m_argv[0]);
407 	if (i != EX_OK)
408 		syserr("451 smtpquit %s: stat %d", m->m_argv[0], i);
409 }
410 /*
411 **  SMTPRSET -- send a RSET (reset) command
412 */
413 
414 smtprset(m, mci, e)
415 	register MAILER *m;
416 	register MCI *mci;
417 	ENVELOPE *e;
418 {
419 	int r;
420 
421 	smtpmessage("RSET", m, mci);
422 	r = reply(m, mci, e, TimeOuts.to_rset);
423 	if (r < 0)
424 		mci->mci_state = MCIS_ERROR;
425 	else if (REPLYTYPE(r) == 2)
426 	{
427 		mci->mci_state = MCIS_OPEN;
428 		return;
429 	}
430 	smtpquit(m, mci, e);
431 }
432 /*
433 **  SMTPNOOP -- send a NOOP (no operation) command to check the connection state
434 */
435 
436 smtpnoop(mci)
437 	register MCI *mci;
438 {
439 	int r;
440 	MAILER *m = mci->mci_mailer;
441 	extern ENVELOPE BlankEnvelope;
442 	ENVELOPE *e = &BlankEnvelope;
443 
444 	smtpmessage("NOOP", m, mci);
445 	r = reply(m, mci, e, TimeOuts.to_miscshort);
446 	if (r < 0 || REPLYTYPE(r) != 2)
447 		smtpquit(m, mci, e);
448 	return r;
449 }
450 /*
451 **  REPLY -- read arpanet reply
452 **
453 **	Parameters:
454 **		m -- the mailer we are reading the reply from.
455 **		mci -- the mailer connection info structure.
456 **		e -- the current envelope.
457 **		timeout -- the timeout for reads.
458 **
459 **	Returns:
460 **		reply code it reads.
461 **
462 **	Side Effects:
463 **		flushes the mail file.
464 */
465 
466 reply(m, mci, e, timeout)
467 	MAILER *m;
468 	MCI *mci;
469 	ENVELOPE *e;
470 {
471 	if (mci->mci_out != NULL)
472 		(void) fflush(mci->mci_out);
473 
474 	if (tTd(18, 1))
475 		printf("reply\n");
476 
477 	/*
478 	**  Read the input line, being careful not to hang.
479 	*/
480 
481 	for (;;)
482 	{
483 		register int r;
484 		register char *p;
485 		extern time_t curtime();
486 
487 		/* actually do the read */
488 		if (e->e_xfp != NULL)
489 			(void) fflush(e->e_xfp);	/* for debugging */
490 
491 		/* if we are in the process of closing just give the code */
492 		if (mci->mci_state == MCIS_CLOSED)
493 			return (SMTPCLOSING);
494 
495 		if (mci->mci_out != NULL)
496 			fflush(mci->mci_out);
497 
498 		/* get the line from the other side */
499 		p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in,
500 			   timeout);
501 		mci->mci_lastuse = curtime();
502 
503 		if (p == NULL)
504 		{
505 			extern char MsgBuf[];		/* err.c */
506 
507 			/* if the remote end closed early, fake an error */
508 			if (errno == 0)
509 # ifdef ECONNRESET
510 				errno = ECONNRESET;
511 # else /* ECONNRESET */
512 				errno = EPIPE;
513 # endif /* ECONNRESET */
514 
515 			mci->mci_errno = errno;
516 			mci->mci_exitstat = EX_TEMPFAIL;
517 			message("451 %s: reply: read error from %s",
518 				e->e_id == NULL ? "NOQUEUE" : e->e_id,
519 				mci->mci_host);
520 			/* if debugging, pause so we can see state */
521 			if (tTd(18, 100))
522 				pause();
523 # ifdef LOG
524 			if (LogLevel > 1)
525 				syslog(LOG_INFO, "%s", &MsgBuf[4]);
526 # endif /* LOG */
527 			mci->mci_state = MCIS_ERROR;
528 			smtpquit(m, mci, e);
529 			return (-1);
530 		}
531 		fixcrlf(SmtpReplyBuffer, TRUE);
532 
533 		if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL)
534 		{
535 			/* serious error -- log the previous command */
536 			if (SmtpMsgBuffer[0] != '\0')
537 				fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
538 			SmtpMsgBuffer[0] = '\0';
539 
540 			/* now log the message as from the other side */
541 			fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer);
542 		}
543 
544 		/* display the input for verbose mode */
545 		if (Verbose)
546 			nmessage("%s", SmtpReplyBuffer);
547 
548 		/* if continuation is required, we can go on */
549 		if (SmtpReplyBuffer[3] == '-' ||
550 		    !(isascii(SmtpReplyBuffer[0]) && isdigit(SmtpReplyBuffer[0])))
551 			continue;
552 
553 		/* decode the reply code */
554 		r = atoi(SmtpReplyBuffer);
555 
556 		/* extra semantics: 0xx codes are "informational" */
557 		if (r < 100)
558 			continue;
559 
560 		/* save temporary failure messages for posterity */
561 		if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
562 			(void) strcpy(SmtpError, SmtpReplyBuffer);
563 
564 		/* reply code 421 is "Service Shutting Down" */
565 		if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
566 		{
567 			/* send the quit protocol */
568 			mci->mci_state = MCIS_SSD;
569 			smtpquit(m, mci, e);
570 		}
571 
572 		return (r);
573 	}
574 }
575 /*
576 **  SMTPMESSAGE -- send message to server
577 **
578 **	Parameters:
579 **		f -- format
580 **		m -- the mailer to control formatting.
581 **		a, b, c -- parameters
582 **
583 **	Returns:
584 **		none.
585 **
586 **	Side Effects:
587 **		writes message to mci->mci_out.
588 */
589 
590 /*VARARGS1*/
591 #ifdef __STDC__
592 smtpmessage(char *f, MAILER *m, MCI *mci, ...)
593 #else
594 smtpmessage(f, m, mci, va_alist)
595 	char *f;
596 	MAILER *m;
597 	MCI *mci;
598 	va_dcl
599 #endif
600 {
601 	VA_LOCAL_DECL
602 
603 	VA_START(mci);
604 	(void) vsprintf(SmtpMsgBuffer, f, ap);
605 	VA_END;
606 
607 	if (tTd(18, 1) || Verbose)
608 		nmessage(">>> %s", SmtpMsgBuffer);
609 	if (mci->mci_out != NULL)
610 	{
611 		fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
612 			m == NULL ? "\r\n" : m->m_eol);
613 	}
614 	else
615 	{
616 		syserr("smtpmessage: NULL mci_out");
617 	}
618 }
619 
620 # endif /* SMTP */
621