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