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