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