|
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; @