122716Sdist /*
234921Sbostic  * Copyright (c) 1983 Eric P. Allman
333731Sbostic  * Copyright (c) 1988 Regents of the University of California.
433731Sbostic  * All rights reserved.
533731Sbostic  *
642831Sbostic  * %sccs.include.redist.c%
733731Sbostic  */
822716Sdist 
933731Sbostic # include "sendmail.h"
1022716Sdist 
1133731Sbostic #ifndef lint
1233731Sbostic #ifdef SMTP
13*53751Seric static char sccsid[] = "@(#)usersmtp.c	5.21 (Berkeley) 05/31/92 (with SMTP)";
1433731Sbostic #else
15*53751Seric static char sccsid[] = "@(#)usersmtp.c	5.21 (Berkeley) 05/31/92 (without SMTP)";
1633731Sbostic #endif
1733731Sbostic #endif /* not lint */
1833731Sbostic 
194684Seric # include <sysexits.h>
2021065Seric # include <errno.h>
214684Seric 
2233731Sbostic # ifdef SMTP
234684Seric 
244684Seric /*
259391Seric **  USERSMTP -- run SMTP protocol from the user end.
269391Seric **
279391Seric **	This protocol is described in RFC821.
289391Seric */
299391Seric 
309391Seric #define REPLYTYPE(r)	((r) / 100)		/* first digit of reply code */
319391Seric #define REPLYCLASS(r)	(((r) / 10) % 10)	/* second digit of reply code */
329391Seric #define SMTPCLOSING	421			/* "Service Shutting Down" */
339391Seric 
3414900Seric char	SmtpMsgBuffer[MAXLINE];		/* buffer for commands */
3510054Seric char	SmtpReplyBuffer[MAXLINE];	/* buffer for replies */
3621065Seric char	SmtpError[MAXLINE] = "";	/* save failure error messages */
3710054Seric int	SmtpPid;			/* pid of mailer */
389391Seric /*
394865Seric **  SMTPINIT -- initialize SMTP.
404684Seric **
414865Seric **	Opens the connection and sends the initial protocol.
424684Seric **
434684Seric **	Parameters:
444865Seric **		m -- mailer to create connection to.
454865Seric **		pvp -- pointer to parameter vector to pass to
464865Seric **			the mailer.
474684Seric **
484684Seric **	Returns:
494865Seric **		appropriate exit status -- EX_OK on success.
5014913Seric **		If not EX_OK, it should close the connection.
514684Seric **
524684Seric **	Side Effects:
534865Seric **		creates connection and sends initial protocol.
544684Seric */
554684Seric 
5614886Seric jmp_buf	CtxGreeting;
5714886Seric 
58*53751Seric MCONINFO *
59*53751Seric smtpinit(m, pvp, e)
604865Seric 	struct mailer *m;
614865Seric 	char **pvp;
62*53751Seric 	ENVELOPE *e;
634684Seric {
644865Seric 	register int r;
6514886Seric 	EVENT *gte;
66*53751Seric 	MCONINFO *mci;
6746928Sbostic 	static int greettimeout();
6852107Seric 	extern STAB *stab();
6953740Seric 	extern MCONINFO *openmailer();
704684Seric 
714865Seric 	/*
724865Seric 	**  Open the connection to the mailer.
734865Seric 	*/
744684Seric 
7521065Seric 	SmtpError[0] = '\0';
76*53751Seric 	setproctitle("%s %s: %s", e->e_id, pvp[1], "user open");
7752676Seric 	mci = openmailer(m, pvp, (ADDRESS *) NULL, TRUE);
78*53751Seric 	if (mci == NULL)
79*53751Seric 		return NULL;
80*53751Seric 	if (mci->mci_state != MCIS_OPENING && mci->mci_state != MCIS_CLOSED)
81*53751Seric 		return mci;
82*53751Seric 	mci->mci_phase = "user open";
83*53751Seric 	mci->mci_state = MCIS_OPENING;
84*53751Seric 	if (mci->mci_pid < 0)
856051Seric 	{
867677Seric 		if (tTd(18, 1))
879391Seric 			printf("smtpinit: cannot open %s: stat %d errno %d\n",
889391Seric 			   pvp[0], ExitStat, errno);
89*53751Seric 		if (e->e_xfp != NULL)
9015139Seric 		{
9121065Seric 			register char *p;
9215139Seric 			extern char *errstring();
9321065Seric 			extern char *statstring();
9415139Seric 
9521065Seric 			if (errno == 0)
9621065Seric 			{
9721065Seric 				p = statstring(ExitStat);
98*53751Seric 				fprintf(e->e_xfp,
9921065Seric 					"%.3s %s.%s... %s\n",
10021065Seric 					p, pvp[1], m->m_name, p);
10121065Seric 			}
10221065Seric 			else
10321065Seric 			{
10436584Sbostic 				r = errno;
105*53751Seric 				fprintf(e->e_xfp,
10621065Seric 					"421 %s.%s... Deferred: %s\n",
10721065Seric 					pvp[1], m->m_name, errstring(errno));
10836584Sbostic 				errno = r;
10921065Seric 			}
11015139Seric 		}
111*53751Seric 		mci->mci_exitstat = ExitStat;
112*53751Seric 		return mci;
1136051Seric 	}
1144796Seric 
1154865Seric 	/*
1164865Seric 	**  Get the greeting message.
11714913Seric 	**	This should appear spontaneously.  Give it five minutes to
11814886Seric 	**	happen.
1194865Seric 	*/
1204797Seric 
12114886Seric 	if (setjmp(CtxGreeting) != 0)
12252104Seric 		goto tempfail1;
12316141Seric 	gte = setevent((time_t) 300, greettimeout, 0);
124*53751Seric 	mci->mci_phase = "greeting wait";
125*53751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
126*53751Seric 	r = reply(m, mci, e);
12714886Seric 	clrevent(gte);
1288005Seric 	if (r < 0 || REPLYTYPE(r) != 2)
12952104Seric 		goto tempfail1;
1304684Seric 
1314865Seric 	/*
1324976Seric 	**  Send the HELO command.
1337963Seric 	**	My mother taught me to always introduce myself.
1344976Seric 	*/
1354976Seric 
136*53751Seric 	smtpmessage("HELO %s", m, mci, MyHostName);
137*53751Seric 	mci->mci_phase = "HELO wait";
138*53751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
139*53751Seric 	r = reply(m, mci, e);
1408005Seric 	if (r < 0)
14152104Seric 		goto tempfail1;
1428005Seric 	else if (REPLYTYPE(r) == 5)
14314913Seric 		goto unavailable;
1447963Seric 	else if (REPLYTYPE(r) != 2)
14552104Seric 		goto tempfail1;
1464976Seric 
1474976Seric 	/*
1489315Seric 	**  If this is expected to be another sendmail, send some internal
1499315Seric 	**  commands.
1509315Seric 	*/
1519315Seric 
15210688Seric 	if (bitnset(M_INTERNAL, m->m_flags))
1539315Seric 	{
1549315Seric 		/* tell it to be verbose */
155*53751Seric 		smtpmessage("VERB", m, mci);
156*53751Seric 		r = reply(m, mci, e);
1579315Seric 		if (r < 0)
15852104Seric 			goto tempfail2;
1599315Seric 
1609315Seric 		/* tell it we will be sending one transaction only */
161*53751Seric 		smtpmessage("ONEX", m, mci);
162*53751Seric 		r = reply(m, mci, e);
1639315Seric 		if (r < 0)
16452104Seric 			goto tempfail2;
1659315Seric 	}
1669315Seric 
167*53751Seric 	mci->mci_state = MCIS_OPEN;
168*53751Seric 	return mci;
169*53751Seric 
170*53751Seric   tempfail1:
171*53751Seric   tempfail2:
172*53751Seric 	mci->mci_exitstat = EX_TEMPFAIL;
173*53751Seric 	mci->mci_errno = errno;
174*53751Seric 	smtpquit(m, mci, e);
175*53751Seric 	mci->mci_state = MCIS_TEMPFAIL;
176*53751Seric 	return mci;
177*53751Seric 
178*53751Seric   unavailable:
179*53751Seric 	mci->mci_exitstat = EX_UNAVAILABLE;
180*53751Seric 	mci->mci_errno = errno;
181*53751Seric 	smtpquit(m, mci, e);
182*53751Seric 	mci->mci_state = MCIS_ERROR;
183*53751Seric 	return mci;
184*53751Seric }
185*53751Seric 
186*53751Seric smtpmailfrom(m, mci, e)
187*53751Seric 	struct mailer *m;
188*53751Seric 	MCONINFO *mci;
189*53751Seric 	ENVELOPE *e;
190*53751Seric {
191*53751Seric 	int r;
192*53751Seric 	char buf[MAXNAME];
193*53751Seric 
1949315Seric 	/*
1954865Seric 	**  Send the MAIL command.
1964865Seric 	**	Designates the sender.
1974865Seric 	*/
1984796Seric 
199*53751Seric 	mci->mci_state = MCIS_ACTIVE;
200*53751Seric 
201*53751Seric 	expand("\001<", buf, &buf[sizeof buf - 1], e);
202*53751Seric 	if (e->e_from.q_mailer == LocalMailer ||
20310688Seric 	    !bitnset(M_FROMPATH, m->m_flags))
2048436Seric 	{
205*53751Seric 		smtpmessage("MAIL From:<%s>", m, mci, buf);
2068436Seric 	}
2078436Seric 	else
2088436Seric 	{
209*53751Seric 		smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName,
21010308Seric 			buf[0] == '@' ? ',' : ':', buf);
2118436Seric 	}
212*53751Seric 	mci->mci_phase = "MAIL wait";
213*53751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
214*53751Seric 	r = reply(m, mci, e);
2158005Seric 	if (r < 0 || REPLYTYPE(r) == 4)
216*53751Seric 	{
217*53751Seric 		mci->mci_exitstat = EX_TEMPFAIL;
218*53751Seric 		mci->mci_errno = errno;
219*53751Seric 		smtpquit(m, mci, e);
220*53751Seric 		mci->mci_state = MCIS_TEMPFAIL;
221*53751Seric 		return EX_TEMPFAIL;
222*53751Seric 	}
2237963Seric 	else if (r == 250)
224*53751Seric 	{
225*53751Seric 		mci->mci_exitstat = EX_OK;
226*53751Seric 		return EX_OK;
227*53751Seric 	}
2287963Seric 	else if (r == 552)
229*53751Seric 	{
230*53751Seric 		/* signal service unavailable */
231*53751Seric 		mci->mci_exitstat = EX_UNAVAILABLE;
232*53751Seric 		smtpquit(m, mci, e);
233*53751Seric 		mci->mci_state = MCIS_ERROR;
234*53751Seric 		return EX_UNAVAILABLE;
235*53751Seric 	}
23614913Seric 
23714913Seric 	/* protocol error -- close up */
238*53751Seric 	smtpquit(m, mci, e);
239*53751Seric 	mci->mci_exitstat = EX_PROTOCOL;
240*53751Seric 	mci->mci_state = MCIS_ERROR;
241*53751Seric 	return EX_PROTOCOL;
2424684Seric }
24314886Seric 
24414886Seric 
24514886Seric static
24614886Seric greettimeout()
24714886Seric {
24814886Seric 	/* timeout reading the greeting message */
24914886Seric 	longjmp(CtxGreeting, 1);
25014886Seric }
2514684Seric /*
2524976Seric **  SMTPRCPT -- designate recipient.
2534797Seric **
2544797Seric **	Parameters:
2554865Seric **		to -- address of recipient.
25610175Seric **		m -- the mailer we are sending to.
2574797Seric **
2584797Seric **	Returns:
2594865Seric **		exit status corresponding to recipient status.
2604797Seric **
2614797Seric **	Side Effects:
2624865Seric **		Sends the mail via SMTP.
2634797Seric */
2644797Seric 
265*53751Seric smtprcpt(to, m, mci, e)
2664865Seric 	ADDRESS *to;
26710175Seric 	register MAILER *m;
26853740Seric 	MCONINFO *mci;
269*53751Seric 	ENVELOPE *e;
2704797Seric {
2714797Seric 	register int r;
27210308Seric 	extern char *remotename();
2734797Seric 
274*53751Seric 	smtpmessage("RCPT To:<%s>", m, mci, to->q_user);
2754865Seric 
276*53751Seric 	mci->mci_phase = "RCPT wait";
277*53751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
278*53751Seric 	r = reply(m, mci, e);
2798005Seric 	if (r < 0 || REPLYTYPE(r) == 4)
2804865Seric 		return (EX_TEMPFAIL);
2817963Seric 	else if (REPLYTYPE(r) == 2)
2827963Seric 		return (EX_OK);
2837964Seric 	else if (r == 550 || r == 551 || r == 553)
2847964Seric 		return (EX_NOUSER);
2857964Seric 	else if (r == 552 || r == 554)
2867964Seric 		return (EX_UNAVAILABLE);
2877964Seric 	return (EX_PROTOCOL);
2884797Seric }
2894797Seric /*
29010175Seric **  SMTPDATA -- send the data and clean up the transaction.
2914684Seric **
2924684Seric **	Parameters:
2934865Seric **		m -- mailer being sent to.
2946980Seric **		e -- the envelope for this message.
2954684Seric **
2964684Seric **	Returns:
2974976Seric **		exit status corresponding to DATA command.
2984684Seric **
2994684Seric **	Side Effects:
3004865Seric **		none.
3014684Seric */
3024684Seric 
30353740Seric smtpdata(m, mci, e)
3044865Seric 	struct mailer *m;
30553740Seric 	register MCONINFO *mci;
3066980Seric 	register ENVELOPE *e;
3074684Seric {
3084684Seric 	register int r;
3094684Seric 
3104797Seric 	/*
3114797Seric 	**  Send the data.
31210175Seric 	**	First send the command and check that it is ok.
31310175Seric 	**	Then send the data.
31410175Seric 	**	Follow it up with a dot to terminate.
31510175Seric 	**	Finally get the results of the transaction.
3164797Seric 	*/
3174797Seric 
31810175Seric 	/* send the command and check ok to proceed */
319*53751Seric 	smtpmessage("DATA", m, mci);
320*53751Seric 	mci->mci_phase = "DATA wait";
321*53751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
322*53751Seric 	r = reply(m, mci, e);
3238005Seric 	if (r < 0 || REPLYTYPE(r) == 4)
3244797Seric 		return (EX_TEMPFAIL);
3257963Seric 	else if (r == 554)
3267963Seric 		return (EX_UNAVAILABLE);
3277963Seric 	else if (r != 354)
3287964Seric 		return (EX_PROTOCOL);
32910175Seric 
33010175Seric 	/* now output the actual message */
331*53751Seric 	(*e->e_puthdr)(mci->mci_out, m, e);
33253740Seric 	putline("\n", mci->mci_out, m);
333*53751Seric 	(*e->e_putbody)(mci->mci_out, m, e);
33410175Seric 
33510175Seric 	/* terminate the message */
33653740Seric 	fprintf(mci->mci_out, ".%s", m->m_eol);
33710215Seric 	if (Verbose && !HoldErrs)
33810215Seric 		nmessage(Arpa_Info, ">>> .");
33910175Seric 
34010175Seric 	/* check for the results of the transaction */
341*53751Seric 	mci->mci_phase = "result wait";
342*53751Seric 	setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase);
343*53751Seric 	r = reply(m, mci, e);
344*53751Seric 	if (r < 0)
3454797Seric 		return (EX_TEMPFAIL);
346*53751Seric 	mci->mci_state = MCIS_OPEN;
347*53751Seric 	if (REPLYTYPE(r) == 4)
348*53751Seric 		return (EX_TEMPFAIL);
3497963Seric 	else if (r == 250)
3507963Seric 		return (EX_OK);
3517963Seric 	else if (r == 552 || r == 554)
3527963Seric 		return (EX_UNAVAILABLE);
3537964Seric 	return (EX_PROTOCOL);
3544684Seric }
3554684Seric /*
3564865Seric **  SMTPQUIT -- close the SMTP connection.
3574865Seric **
3584865Seric **	Parameters:
35915535Seric **		m -- a pointer to the mailer.
3604865Seric **
3614865Seric **	Returns:
3624865Seric **		none.
3634865Seric **
3644865Seric **	Side Effects:
3654865Seric **		sends the final protocol and closes the connection.
3664865Seric */
3674865Seric 
368*53751Seric smtpquit(m, mci, e)
369*53751Seric 	register MAILER *m;
37052676Seric 	register MCONINFO *mci;
371*53751Seric 	ENVELOPE *e;
3724865Seric {
3739391Seric 	int i;
3744865Seric 
37510148Seric 	/* if the connection is already closed, don't bother */
37653740Seric 	if (mci->mci_state == MCIS_CLOSED)
37710148Seric 		return;
37810148Seric 
37910148Seric 	/* send the quit message if not a forced quit */
380*53751Seric 	if (mci->mci_state != MCIS_ERROR)
3819391Seric 	{
382*53751Seric 		smtpmessage("QUIT", m, mci);
383*53751Seric 		(void) reply(m, mci, e);
38453740Seric 		if (mci->mci_state == MCIS_CLOSED)
38510159Seric 			return;
3869391Seric 	}
3879391Seric 
38852676Seric 	/* now actually close the connection and pick up the zombie */
38952676Seric 	i = endmailer(mci, m->m_argv[0]);
3909391Seric 	if (i != EX_OK)
39115535Seric 		syserr("smtpquit %s: stat %d", m->m_argv[0], i);
3924865Seric }
3934865Seric /*
3944684Seric **  REPLY -- read arpanet reply
3954684Seric **
3964684Seric **	Parameters:
39710175Seric **		m -- the mailer we are reading the reply from.
3984684Seric **
3994684Seric **	Returns:
4004684Seric **		reply code it reads.
4014684Seric **
4024684Seric **	Side Effects:
4034684Seric **		flushes the mail file.
4044684Seric */
4054684Seric 
406*53751Seric reply(m, mci, e)
407*53751Seric 	MAILER *m;
40853740Seric 	MCONINFO *mci;
409*53751Seric 	ENVELOPE *e;
4104684Seric {
41153740Seric 	(void) fflush(mci->mci_out);
4124684Seric 
4137677Seric 	if (tTd(18, 1))
4144796Seric 		printf("reply\n");
4154796Seric 
4167356Seric 	/*
4177356Seric 	**  Read the input line, being careful not to hang.
4187356Seric 	*/
4197356Seric 
4204684Seric 	for (;;)
4214684Seric 	{
4224684Seric 		register int r;
4237356Seric 		register char *p;
424*53751Seric 		extern time_t curtime();
4254684Seric 
4267685Seric 		/* actually do the read */
427*53751Seric 		if (e->e_xfp != NULL)
428*53751Seric 			(void) fflush(e->e_xfp);	/* for debugging */
4297356Seric 
43010054Seric 		/* if we are in the process of closing just give the code */
43153740Seric 		if (mci->mci_state == MCIS_CLOSED)
43210054Seric 			return (SMTPCLOSING);
43310054Seric 
43410054Seric 		/* get the line from the other side */
43553740Seric 		p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in);
436*53751Seric 		mci->mci_lastuse = curtime();
437*53751Seric 
43810054Seric 		if (p == NULL)
43910131Seric 		{
44010148Seric 			extern char MsgBuf[];		/* err.c */
44110148Seric 			extern char Arpa_TSyserr[];	/* conf.c */
44210148Seric 
44321065Seric 			/* if the remote end closed early, fake an error */
44421065Seric 			if (errno == 0)
44521065Seric # ifdef ECONNRESET
44621065Seric 				errno = ECONNRESET;
44721065Seric # else ECONNRESET
44821065Seric 				errno = EPIPE;
44921065Seric # endif ECONNRESET
45021065Seric 
45110148Seric 			message(Arpa_TSyserr, "reply: read error");
45210420Seric 			/* if debugging, pause so we can see state */
45310420Seric 			if (tTd(18, 100))
45410420Seric 				pause();
45510148Seric # ifdef LOG
45636234Skarels 			syslog(LOG_INFO, "%s", &MsgBuf[4]);
45710148Seric # endif LOG
45853740Seric 			mci->mci_state = MCIS_CLOSED;
459*53751Seric 			smtpquit(m, mci, e);
46010054Seric 			return (-1);
46110131Seric 		}
46210054Seric 		fixcrlf(SmtpReplyBuffer, TRUE);
46310054Seric 
464*53751Seric 		if (e->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL)
46514900Seric 		{
46614900Seric 			/* serious error -- log the previous command */
46714900Seric 			if (SmtpMsgBuffer[0] != '\0')
468*53751Seric 				fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer);
46914900Seric 			SmtpMsgBuffer[0] = '\0';
47014900Seric 
47114900Seric 			/* now log the message as from the other side */
472*53751Seric 			fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer);
47314900Seric 		}
47414900Seric 
47514900Seric 		/* display the input for verbose mode */
4767229Seric 		if (Verbose && !HoldErrs)
4779391Seric 			nmessage(Arpa_Info, "%s", SmtpReplyBuffer);
4787356Seric 
4797356Seric 		/* if continuation is required, we can go on */
4809391Seric 		if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0]))
4814684Seric 			continue;
4827356Seric 
4837356Seric 		/* decode the reply code */
4849391Seric 		r = atoi(SmtpReplyBuffer);
4857356Seric 
4867356Seric 		/* extra semantics: 0xx codes are "informational" */
4874684Seric 		if (r < 100)
4884684Seric 			continue;
4897356Seric 
4909391Seric 		/* reply code 421 is "Service Shutting Down" */
49153740Seric 		if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
4929391Seric 		{
49310054Seric 			/* send the quit protocol */
49453740Seric 			mci->mci_state = MCIS_SSD;
495*53751Seric 			smtpquit(m, mci, e);
4969391Seric 		}
4979391Seric 
49821065Seric 		/* save temporary failure messages for posterity */
49921065Seric 		if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
50021065Seric 			(void) strcpy(SmtpError, &SmtpReplyBuffer[4]);
50121065Seric 
5024684Seric 		return (r);
5034684Seric 	}
5044684Seric }
5054796Seric /*
5064865Seric **  SMTPMESSAGE -- send message to server
5074796Seric **
5084796Seric **	Parameters:
5094796Seric **		f -- format
51010175Seric **		m -- the mailer to control formatting.
5114796Seric **		a, b, c -- parameters
5124796Seric **
5134796Seric **	Returns:
5144796Seric **		none.
5154796Seric **
5164796Seric **	Side Effects:
51753740Seric **		writes message to mci->mci_out.
5184796Seric */
5194796Seric 
5204865Seric /*VARARGS1*/
52153740Seric smtpmessage(f, m, mci, a, b, c)
5224796Seric 	char *f;
52310175Seric 	MAILER *m;
52453740Seric 	MCONINFO *mci;
5254796Seric {
52614900Seric 	(void) sprintf(SmtpMsgBuffer, f, a, b, c);
5277677Seric 	if (tTd(18, 1) || (Verbose && !HoldErrs))
52814900Seric 		nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer);
52953740Seric 	if (mci->mci_out != NULL)
53053740Seric 		fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
53140997Sbostic 			m == 0 ? "\r\n" : m->m_eol);
5324796Seric }
5335182Seric 
5345182Seric # endif SMTP
535