|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T u
Length: 18593 (0x48a1)
Types: TextFile
Names: »usersmtp.c,v«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦bfebc70e2⟧ »EurOpenD3/mail/sendmail-5.65b+IDA-1.4.3.tar.Z«
└─⟦f9e35cd84⟧
└─⟦this⟧ »sendmail/src/RCS/usersmtp.c,v«
head 5.15;
branch 5.15.0;
access;
symbols
UICSO:5.15.0
VANILLA:5.15;
locks; strict;
comment @ * @;
5.15
date 90.06.20.08.37.18; author paul; state Exp;
branches
5.15.0.1;
next ;
5.15.0.1
date 90.06.20.09.44.12; author paul; state Exp;
branches;
next 5.15.0.2;
5.15.0.2
date 90.09.22.18.40.32; author paul; state Exp;
branches;
next 5.15.0.3;
5.15.0.3
date 90.10.13.19.16.32; author paul; state Exp;
branches;
next 5.15.0.4;
5.15.0.4
date 91.02.17.05.31.21; author paul; state Exp;
branches;
next 5.15.0.5;
5.15.0.5
date 91.03.07.18.41.35; author paul; state Exp;
branches;
next ;
desc
@@
5.15
log
@5.64 Berkeley release
@
text
@/*
* Copyright (c) 1983 Eric P. Allman
* Copyright (c) 1988 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted provided
* that: (1) source distributions retain this entire copyright notice and
* comment, and (2) distributions including binaries display the following
* acknowledgement: ``This product includes software developed by the
* University of California, Berkeley and its contributors'' in the
* documentation or other materials provided with the distribution and in
* all advertising materials mentioning features or use of this software.
* Neither the name of the University nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
# include "sendmail.h"
#ifndef lint
#ifdef SMTP
static char sccsid[] = "@@(#)usersmtp.c 5.15 (Berkeley) 6/1/90 (with SMTP)";
#else
static char sccsid[] = "@@(#)usersmtp.c 5.15 (Berkeley) 6/1/90 (without SMTP)";
#endif
#endif /* not lint */
# include <sysexits.h>
# include <errno.h>
# ifdef SMTP
/*
** USERSMTP -- run SMTP protocol from the user end.
**
** This protocol is described in RFC821.
*/
#define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */
#define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
#define SMTPCLOSING 421 /* "Service Shutting Down" */
char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
char SmtpError[MAXLINE] = ""; /* save failure error messages */
FILE *SmtpOut; /* output file */
FILE *SmtpIn; /* input file */
int SmtpPid; /* pid of mailer */
/* following represents the state of the SMTP connection */
int SmtpState; /* connection state, see below */
#define SMTP_CLOSED 0 /* connection is closed */
#define SMTP_OPEN 1 /* connection is open for business */
#define SMTP_SSD 2 /* service shutting down */
\f
/*
** SMTPINIT -- initialize SMTP.
**
** Opens the connection and sends the initial protocol.
**
** Parameters:
** m -- mailer to create connection to.
** pvp -- pointer to parameter vector to pass to
** the mailer.
**
** Returns:
** appropriate exit status -- EX_OK on success.
** If not EX_OK, it should close the connection.
**
** Side Effects:
** creates connection and sends initial protocol.
*/
jmp_buf CtxGreeting;
smtpinit(m, pvp)
struct mailer *m;
char **pvp;
{
register int r;
EVENT *gte;
char buf[MAXNAME];
extern greettimeout();
/*
** Open the connection to the mailer.
*/
if (SmtpState == SMTP_OPEN)
syserr("smtpinit: already open");
SmtpIn = SmtpOut = NULL;
SmtpState = SMTP_CLOSED;
SmtpError[0] = '\0';
SmtpPhase = "user open";
setproctitle("%s %s: %s", CurEnv->e_id, pvp[1], SmtpPhase);
SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn);
if (SmtpPid < 0)
{
if (tTd(18, 1))
printf("smtpinit: cannot open %s: stat %d errno %d\n",
pvp[0], ExitStat, errno);
if (CurEnv->e_xfp != NULL)
{
register char *p;
extern char *errstring();
extern char *statstring();
if (errno == 0)
{
p = statstring(ExitStat);
fprintf(CurEnv->e_xfp,
"%.3s %s.%s... %s\n",
p, pvp[1], m->m_name, p);
}
else
{
r = errno;
fprintf(CurEnv->e_xfp,
"421 %s.%s... Deferred: %s\n",
pvp[1], m->m_name, errstring(errno));
errno = r;
}
}
return (ExitStat);
}
SmtpState = SMTP_OPEN;
/*
** Get the greeting message.
** This should appear spontaneously. Give it five minutes to
** happen.
*/
if (setjmp(CtxGreeting) != 0)
goto tempfail;
gte = setevent((time_t) 300, greettimeout, 0);
SmtpPhase = "greeting wait";
setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
r = reply(m);
clrevent(gte);
if (r < 0 || REPLYTYPE(r) != 2)
goto tempfail;
/*
** Send the HELO command.
** My mother taught me to always introduce myself.
*/
smtpmessage("HELO %s", m, MyHostName);
SmtpPhase = "HELO wait";
setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
r = reply(m);
if (r < 0)
goto tempfail;
else if (REPLYTYPE(r) == 5)
goto unavailable;
else if (REPLYTYPE(r) != 2)
goto tempfail;
/*
** If this is expected to be another sendmail, send some internal
** commands.
*/
if (bitnset(M_INTERNAL, m->m_flags))
{
/* tell it to be verbose */
smtpmessage("VERB", m);
r = reply(m);
if (r < 0)
goto tempfail;
/* tell it we will be sending one transaction only */
smtpmessage("ONEX", m);
r = reply(m);
if (r < 0)
goto tempfail;
}
/*
** Send the MAIL command.
** Designates the sender.
*/
expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);
if (CurEnv->e_from.q_mailer == LocalMailer ||
!bitnset(M_FROMPATH, m->m_flags))
{
smtpmessage("MAIL From:<%s>", m, buf);
}
else
{
smtpmessage("MAIL From:<@@%s%c%s>", m, MyHostName,
buf[0] == '@@' ? ',' : ':', buf);
}
SmtpPhase = "MAIL wait";
setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
r = reply(m);
if (r < 0 || REPLYTYPE(r) == 4)
goto tempfail;
else if (r == 250)
return (EX_OK);
else if (r == 552)
goto unavailable;
/* protocol error -- close up */
smtpquit(m);
return (EX_PROTOCOL);
/* signal a temporary failure */
tempfail:
smtpquit(m);
return (EX_TEMPFAIL);
/* signal service unavailable */
unavailable:
smtpquit(m);
return (EX_UNAVAILABLE);
}
static
greettimeout()
{
/* timeout reading the greeting message */
longjmp(CtxGreeting, 1);
}
\f
/*
** SMTPRCPT -- designate recipient.
**
** Parameters:
** to -- address of recipient.
** m -- the mailer we are sending to.
**
** Returns:
** exit status corresponding to recipient status.
**
** Side Effects:
** Sends the mail via SMTP.
*/
smtprcpt(to, m)
ADDRESS *to;
register MAILER *m;
{
register int r;
extern char *remotename();
smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE));
SmtpPhase = "RCPT wait";
setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
r = reply(m);
if (r < 0 || REPLYTYPE(r) == 4)
return (EX_TEMPFAIL);
else if (REPLYTYPE(r) == 2)
return (EX_OK);
else if (r == 550 || r == 551 || r == 553)
return (EX_NOUSER);
else if (r == 552 || r == 554)
return (EX_UNAVAILABLE);
return (EX_PROTOCOL);
}
\f
/*
** SMTPDATA -- send the data and clean up the transaction.
**
** Parameters:
** m -- mailer being sent to.
** e -- the envelope for this message.
**
** Returns:
** exit status corresponding to DATA command.
**
** Side Effects:
** none.
*/
smtpdata(m, e)
struct mailer *m;
register ENVELOPE *e;
{
register int r;
/*
** Send the data.
** First send the command and check that it is ok.
** Then send the data.
** Follow it up with a dot to terminate.
** Finally get the results of the transaction.
*/
/* send the command and check ok to proceed */
smtpmessage("DATA", m);
SmtpPhase = "DATA wait";
setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
r = reply(m);
if (r < 0 || REPLYTYPE(r) == 4)
return (EX_TEMPFAIL);
else if (r == 554)
return (EX_UNAVAILABLE);
else if (r != 354)
return (EX_PROTOCOL);
/* now output the actual message */
(*e->e_puthdr)(SmtpOut, m, CurEnv);
putline("\n", SmtpOut, m);
(*e->e_putbody)(SmtpOut, m, CurEnv);
/* terminate the message */
fprintf(SmtpOut, ".%s", m->m_eol);
if (Verbose && !HoldErrs)
nmessage(Arpa_Info, ">>> .");
/* check for the results of the transaction */
SmtpPhase = "result wait";
setproctitle("%s %s: %s", CurEnv->e_id, CurHostName, SmtpPhase);
r = reply(m);
if (r < 0 || REPLYTYPE(r) == 4)
return (EX_TEMPFAIL);
else if (r == 250)
return (EX_OK);
else if (r == 552 || r == 554)
return (EX_UNAVAILABLE);
return (EX_PROTOCOL);
}
\f
/*
** SMTPQUIT -- close the SMTP connection.
**
** Parameters:
** m -- a pointer to the mailer.
**
** Returns:
** none.
**
** Side Effects:
** sends the final protocol and closes the connection.
*/
smtpquit(m)
register MAILER *m;
{
int i;
/* if the connection is already closed, don't bother */
if (SmtpIn == NULL)
return;
/* send the quit message if not a forced quit */
if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD)
{
smtpmessage("QUIT", m);
(void) reply(m);
if (SmtpState == SMTP_CLOSED)
return;
}
/* now actually close the connection */
(void) fclose(SmtpIn);
(void) fclose(SmtpOut);
SmtpIn = SmtpOut = NULL;
SmtpState = SMTP_CLOSED;
/* and pick up the zombie */
i = endmailer(SmtpPid, m->m_argv[0]);
if (i != EX_OK)
syserr("smtpquit %s: stat %d", m->m_argv[0], i);
}
\f
/*
** REPLY -- read arpanet reply
**
** Parameters:
** m -- the mailer we are reading the reply from.
**
** Returns:
** reply code it reads.
**
** Side Effects:
** flushes the mail file.
*/
reply(m)
MAILER *m;
{
(void) fflush(SmtpOut);
if (tTd(18, 1))
printf("reply\n");
/*
** Read the input line, being careful not to hang.
*/
for (;;)
{
register int r;
register char *p;
/* actually do the read */
if (CurEnv->e_xfp != NULL)
(void) fflush(CurEnv->e_xfp); /* for debugging */
/* if we are in the process of closing just give the code */
if (SmtpState == SMTP_CLOSED)
return (SMTPCLOSING);
/* get the line from the other side */
p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn);
if (p == NULL)
{
extern char MsgBuf[]; /* err.c */
extern char Arpa_TSyserr[]; /* conf.c */
/* if the remote end closed early, fake an error */
if (errno == 0)
# ifdef ECONNRESET
errno = ECONNRESET;
# else ECONNRESET
errno = EPIPE;
# endif ECONNRESET
message(Arpa_TSyserr, "reply: read error");
/* if debugging, pause so we can see state */
if (tTd(18, 100))
pause();
# ifdef LOG
syslog(LOG_INFO, "%s", &MsgBuf[4]);
# endif LOG
SmtpState = SMTP_CLOSED;
smtpquit(m);
return (-1);
}
fixcrlf(SmtpReplyBuffer, TRUE);
if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL)
{
/* serious error -- log the previous command */
if (SmtpMsgBuffer[0] != '\0')
fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer);
SmtpMsgBuffer[0] = '\0';
/* now log the message as from the other side */
fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer);
}
/* display the input for verbose mode */
if (Verbose && !HoldErrs)
nmessage(Arpa_Info, "%s", SmtpReplyBuffer);
/* if continuation is required, we can go on */
if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0]))
continue;
/* decode the reply code */
r = atoi(SmtpReplyBuffer);
/* extra semantics: 0xx codes are "informational" */
if (r < 100)
continue;
/* reply code 421 is "Service Shutting Down" */
if (r == SMTPCLOSING && SmtpState != SMTP_SSD)
{
/* send the quit protocol */
SmtpState = SMTP_SSD;
smtpquit(m);
}
/* save temporary failure messages for posterity */
if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
(void) strcpy(SmtpError, &SmtpReplyBuffer[4]);
return (r);
}
}
\f
/*
** SMTPMESSAGE -- send message to server
**
** Parameters:
** f -- format
** m -- the mailer to control formatting.
** a, b, c -- parameters
**
** Returns:
** none.
**
** Side Effects:
** writes message to SmtpOut.
*/
/*VARARGS1*/
smtpmessage(f, m, a, b, c)
char *f;
MAILER *m;
{
(void) sprintf(SmtpMsgBuffer, f, a, b, c);
if (tTd(18, 1) || (Verbose && !HoldErrs))
nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer);
if (SmtpOut != NULL)
fprintf(SmtpOut, "%s%s", SmtpMsgBuffer,
m == 0 ? "\r\n" : m->m_eol);
}
# endif SMTP
@
5.15.0.1
log
@IDA patches
@
text
@a43 1
#define SMTPGOODREPLY 250 /* positive SMTP response */
a48 1
bool SmtpNeedIntro; /* set before first error */
d77 2
d84 1
a84 1
time_t SavedReadTimeout;
d86 1
a97 1
SmtpNeedIntro = TRUE;
d116 1
a116 1
"%.3s %s (%s)... %s\n",
d123 1
a123 1
"421 %s (%s)... Deferred: %s\n",
d138 3
a142 3
SavedReadTimeout = ReadTimeout;
if (ReadTimeout > 300)
ReadTimeout = 300;
d144 1
a144 1
ReadTimeout = SavedReadTimeout;
d224 8
d253 1
a253 1
smtpmessage("RCPT To:<%s>", m, to->q_user);
d305 1
a305 1
else if (r != 354 && r != 250)
d361 1
a361 2
/* now actually close the connection, but without trashing errno */
i = errno;
a363 1
errno = i;
d388 1
a388 2
if (SmtpOut != NULL)
(void) fflush(SmtpOut);
a392 3
if (bitnset(M_BSMTP, m->m_flags))
return (SMTPGOODREPLY);
d425 1
a425 12
/* Report that connection ended prematurely */
if (CurEnv->e_xfp != NULL)
{
extern char *errstring();
extern char *statstring();
fprintf(CurEnv->e_xfp,
"421 %s (%s)... Deferred: %s\n",
CurHostName, m->m_name,
errstring(errno));
}
a440 5
/* also record who we were talking before first error */
if (SmtpNeedIntro)
fprintf(CurEnv->e_xfp,
"While talking to %s:\n", CurHostName);
SmtpNeedIntro = FALSE;
@
5.15.0.2
log
@First revisions to support HEAD and MULT extensions to SMTP for DEC's
mail11v3 program.
@
text
@d24 1
a24 1
# ifdef SMTP
d26 1
a26 1
# else /* ! SMTP */
d28 2
a29 2
# endif /* SMTP */
#endif /* ! lint */
d34 1
a34 1
#ifdef SMTP
d42 4
a45 4
# define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */
# define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
# define SMTPGOODREPLY 250 /* positive SMTP response */
# define SMTPCLOSING 421 /* "Service Shutting Down" */
a50 3
# ifdef MAIL11V3
bool SmtpManyStatus; /* set for multiple status from DATA */
# endif /* MAIL11V3 */
d58 3
a60 3
# define SMTP_CLOSED 0 /* connection is closed */
# define SMTP_OPEN 1 /* connection is open for business */
# define SMTP_SSD 2 /* service shutting down */
a69 1
** e -- the envelope to deliver (#ifdef MAIL11V3)
a78 4
# ifdef MAIL11V3
smtpinit(m, pvp, e)
register ENVELOPE *e;
# else /* ! MAIL11V3 */
a79 1
# endif /* MAIL11V3 */
a183 1
# ifdef MAIL11V3
a184 43
** If this mailer can do multiple status returns after DATA command,
** ask if it will do so.
*/
if (bitnset(M_MANYSTATUS, m->m_flags))
{
smtpmessage("MULT", m);
r = reply(m);
if (r < 0)
goto tempfail;
else if (r == 250)
SmtpManyStatus = TRUE;
}
else
SmtpManyStatus = FALSE;
/*
** If this mailer wants to see the headers and body early, ask if
** now is OK.
*/
if (bitnset(M_PREHEAD, m->m_flags))
{
smtpmessage("HEAD", m);
r = reply(m);
if (r < 0)
goto tempfail;
if (REPLYTYPE(r) == 2 || REPLYTYPE(r) == 3)
{
/* Send the header and message... */
(*e->e_puthdr)(SmtpOut, m, CurEnv);
putline("\n", SmtpOut, m);
(*e->e_putbody)(SmtpOut, m, CurEnv);
/* followed by the proper termination. */
fprintf(SmtpOut, ".%s", m->m_eol);
r = reply(m);
if (r < 0)
goto tempfail;
}
}
# endif /* MAIL11V3 */
/*
a208 7
#ifdef MAIL11V3
else if (r == 559)
{
smtpquit(m);
return (EX_NOHOST);
}
#endif /* MAIL11V3 */
a308 7
#ifdef MAIL11V3
/*
** If we are running with mail11v3 support, status is collected in
** in deliver().
*/
return (EX_OK);
#else /* ! MAIL11V3 */
a320 1
#endif /* MAIL11V3 */
d419 1
a419 1
# else /* ! ECONNRESET */
d421 1
a421 1
# endif /* ECONNRESET */
d440 1
a440 1
# endif /* LOG */
a519 18
\f
# ifdef MAIL11V3
/*
** SMTPSTAT -- collect status from DATA command
**
** Parameters:
** m -- the mailer we are reading the status from.
**
** Returns:
** status of DATA command
**
** Side Effects:
** none
*/
smtpstat(m)
struct mailer *m;
{
int r;
d521 1
a521 14
/* check the status returned after DATA command */
r = reply(m);
if (r < 0 || REPLYTYPE(r) == 4)
return (EX_TEMPFAIL);
else if (r == 250)
return (EX_OK);
else if (r == 552 || r == 554)
return (EX_UNAVAILABLE);
else if (r == 550 || r == 551 || r == 553)
return (EX_NOUSER);
return (EX_PROTOCOL);
}
# endif /* MAIL11V3 */
#endif /* SMTP */
@
5.15.0.3
log
@Bruce Lilly (bruce%balilly@@sonyd1.broadcast.sony.com) provided varargs
code modified to key off of #define VSPRINTF in conf.h.
@
text
@a576 20
#ifdef VSPRINTF
smtpmessage(va_alist)
va_dcl
{
va_list ap;
char *f;
MAILER *m;
va_start(ap);
f = va_arg(ap, char *);
m = va_arg(ap, MAILER *);
(void) vsprintf(SmtpMsgBuffer, f, ap);
if (tTd(18, 1) || (Verbose && !HoldErrs))
nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer);
if (SmtpOut != NULL)
fprintf(SmtpOut, "%s%s", SmtpMsgBuffer,
m == 0 ? "\r\n" : m->m_eol);
va_end(ap);
}
#else /* !VSPRINTF */
a587 1
#endif /* VSPRINTF */
@
5.15.0.4
log
@Added static keyword to declaration of reply() and smtpmessage().
@
text
@a35 2
static reply(), smtpmessage();
a446 1
static
a576 1
static
@
5.15.0.5
log
@ANSIfied.
@
text
@d31 2
a32 2
#include <sysexits.h>
#include <errno.h>
d36 1
a36 16
# ifdef __STDC__
static reply(MAILER *);
# ifdef VSPRINTF
/*
* The following doesn't work as gcc transforms va_alist for some reason.
*
* static void smtpmessage(const char *, MAILER *, va_alist);
*/
static void smtpmessage();
# else /* !VSPRINTF*/
static void smtpmessage();
# endif /* VSPRINTF*/
# else /* !__STDC__ */
static reply();
static void smtpmessage();
# endif /* __STDC__ */
d49 10
a58 7
static char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
static char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
char SmtpError[MAXLINE] = ""; /* save failure error messages */
static bool SmtpNeedIntro; /* set before first error */
static FILE *SmtpOut; /* output file */
static FILE *SmtpIn; /* input file */
static int SmtpPid; /* pid of mailer */
d61 1
a61 1
static int SmtpState; /* connection state, see below */
d91 1
a91 1
MAILER *m;
d120 2
d305 1
d337 1
a337 1
MAILER *m;
a404 1
void
d496 4
d504 1
d580 1
a580 1
static void
d582 1
a582 3
smtpmessage(f, m, va_alist)
const char *f;
MAILER *m;
d586 2
d590 2
d602 1
a602 1
const char *f;
a626 1
d628 1
a628 1
MAILER *m;
@