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