From f2e44ded6a1600d10a82ddf49fd2c0a108cf9ec2 Mon Sep 17 00:00:00 2001 From: Eric Allman Date: Sun, 12 Jul 1992 01:51:58 -0800 Subject: [PATCH] open connection caching SCCS-vsn: usr.sbin/sendmail/src/usersmtp.c 5.22 SCCS-vsn: usr.sbin/sendmail/src/main.c 5.50 SCCS-vsn: usr.sbin/sendmail/src/version.c 5.101 SCCS-vsn: usr.sbin/sendmail/src/sendmail.h 5.34 SCCS-vsn: usr.sbin/sendmail/src/savemail.c 5.17 SCCS-vsn: usr.sbin/sendmail/src/daemon.c 5.46 SCCS-vsn: usr.sbin/sendmail/src/Makefile 5.25 SCCS-vsn: usr.sbin/sendmail/src/readcf.c 5.39 SCCS-vsn: usr.sbin/sendmail/src/deliver.c 5.57 SCCS-vsn: usr.sbin/sendmail/src/queue.c 5.40 SCCS-vsn: usr.sbin/sendmail/src/conf.c 5.37 SCCS-vsn: usr.sbin/sendmail/src/mci.c 5.2 --- usr/src/usr.sbin/sendmail/src/Makefile | 6 +- usr/src/usr.sbin/sendmail/src/conf.c | 4 +- usr/src/usr.sbin/sendmail/src/daemon.c | 9 +- usr/src/usr.sbin/sendmail/src/deliver.c | 579 ++++++++++++----------- usr/src/usr.sbin/sendmail/src/main.c | 22 +- usr/src/usr.sbin/sendmail/src/mci.c | 74 ++- usr/src/usr.sbin/sendmail/src/queue.c | 6 +- usr/src/usr.sbin/sendmail/src/readcf.c | 14 +- usr/src/usr.sbin/sendmail/src/savemail.c | 4 +- usr/src/usr.sbin/sendmail/src/sendmail.h | 23 +- usr/src/usr.sbin/sendmail/src/usersmtp.c | 149 +++--- usr/src/usr.sbin/sendmail/src/version.c | 4 +- 12 files changed, 490 insertions(+), 404 deletions(-) diff --git a/usr/src/usr.sbin/sendmail/src/Makefile b/usr/src/usr.sbin/sendmail/src/Makefile index 563cd57da7..2df473232f 100644 --- a/usr/src/usr.sbin/sendmail/src/Makefile +++ b/usr/src/usr.sbin/sendmail/src/Makefile @@ -1,16 +1,16 @@ -# @(#)Makefile 5.24 (Berkeley) %G% +# @(#)Makefile 5.25 (Berkeley) %G% PROG= sendmail CFLAGS+=-I${.CURDIR} SRCS= alias.c arpadate.c clock.c collect.c conf.c convtime.c daemon.c \ - deliver.c domain.c envelope.c err.c headers.c macro.c main.c \ + deliver.c domain.c envelope.c err.c headers.c macro.c main.c mci.c \ parseaddr.c queue.c readcf.c recipient.c savemail.c srvrsmtp.c \ stab.c stats.c sysexits.c trace.c udb.c usersmtp.c \ util.c version.c DPADD= ${LIBDBM} ${LIBCOMPAT} ${LIBUTIL} -LDADD= -ldbm -lcompat -lutil +LDADD= -ldbm -lcompat -lutil -lkvm MAN1= newaliases.0 MAN5= aliases.0 MAN8= sendmail.0 diff --git a/usr/src/usr.sbin/sendmail/src/conf.c b/usr/src/usr.sbin/sendmail/src/conf.c index 713fc3633c..589981c6eb 100644 --- a/usr/src/usr.sbin/sendmail/src/conf.c +++ b/usr/src/usr.sbin/sendmail/src/conf.c @@ -7,7 +7,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)conf.c 5.36 (Berkeley) %G%"; +static char sccsid[] = "@(#)conf.c 5.37 (Berkeley) %G%"; #endif /* not lint */ # include @@ -145,6 +145,8 @@ setdefaults() SendMode = SM_FORK; ErrorMode = EM_PRINT; EightBit = FALSE; + MaxMciCache = 1; + MciCacheTimeout = 300; setdefuser(); setupmaps(); } diff --git a/usr/src/usr.sbin/sendmail/src/daemon.c b/usr/src/usr.sbin/sendmail/src/daemon.c index 66f604ce6b..0be083d133 100644 --- a/usr/src/usr.sbin/sendmail/src/daemon.c +++ b/usr/src/usr.sbin/sendmail/src/daemon.c @@ -12,9 +12,9 @@ #ifndef lint #ifdef DAEMON -static char sccsid[] = "@(#)daemon.c 5.45 (Berkeley) %G% (with daemon mode)"; +static char sccsid[] = "@(#)daemon.c 5.46 (Berkeley) %G% (with daemon mode)"; #else -static char sccsid[] = "@(#)daemon.c 5.45 (Berkeley) %G% (without daemon mode)"; +static char sccsid[] = "@(#)daemon.c 5.46 (Berkeley) %G% (without daemon mode)"; #endif #endif /* not lint */ @@ -167,10 +167,11 @@ getrequests() ** none. */ +int makeconnection(host, port, mci, usesecureport) char *host; u_short port; - register MCONINFO *mci; + register MCI *mci; bool usesecureport; { register int i, s; @@ -284,7 +285,7 @@ again: } if (tTd(16, 1)) - printf("makeconnection: %d\n", s); + printf("makeconnection: fd=%d\n", s); /* turn on network debugging? */ if (tTd(16, 14)) diff --git a/usr/src/usr.sbin/sendmail/src/deliver.c b/usr/src/usr.sbin/sendmail/src/deliver.c index b5d583fbc9..2f4519e93d 100644 --- a/usr/src/usr.sbin/sendmail/src/deliver.c +++ b/usr/src/usr.sbin/sendmail/src/deliver.c @@ -7,7 +7,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)deliver.c 5.56 (Berkeley) %G%"; +static char sccsid[] = "@(#)deliver.c 5.57 (Berkeley) %G%"; #endif /* not lint */ #include "sendmail.h" @@ -55,6 +55,7 @@ deliver(e, firstto) register char *p; register MAILER *m; /* mailer for this recipient */ ADDRESS *ctladdr; + register MCI *mci; register ADDRESS *to = firstto; bool clever = FALSE; /* running user smtp to this mailer */ ADDRESS *tochain = NULL; /* chain of users in this mailer call */ @@ -68,6 +69,7 @@ deliver(e, firstto) extern bool checkcompat(); extern ADDRESS *getctladdr(); extern char *remotename(); + extern MCI *openmailer(); errno = 0; if (!ForceMail && bitset(QDONTSEND|QPSEUDO, to->q_flags)) @@ -109,7 +111,7 @@ deliver(e, firstto) e->e_to = to->q_paddr; message(Arpa_Info, "queued"); if (LogLevel > 4) - logdelivery("queued"); + logdelivery("queued", e); } e->e_to = NULL; return (0); @@ -305,7 +307,7 @@ deliver(e, firstto) { if (user[0] == '/') { - rcode = mailfile(user, getctladdr(to)); + rcode = mailfile(user, getctladdr(to), e); giveresponse(rcode, m, e); if (rcode == EX_OK) to->q_flags |= QSENT; @@ -382,81 +384,105 @@ deliver(e, firstto) if (ConfigLevel < 2) _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ #endif -#ifdef SMTP - if (clever) + mci = openmailer(m, pv, ctladdr, clever, e); + if (mci == NULL) { - register MCONINFO *mci; - - rcode = EX_OK; -#ifdef NAMED_BIND - if (host[0] && host[0] != '[') - { - expand("\001j", buf, &buf[sizeof(buf) - 1], e); - Nmx = getmxrr(host, MxHosts, buf, &rcode); - } - else -#endif + /* catastrophic error */ + rcode = -1; + goto give_up; + } + else if (mci->mci_state != MCIS_OPEN) + { + /* couldn't open the mailer */ + rcode = mci->mci_exitstat; + if (rcode == EX_OK) { - Nmx = 1; - MxHosts[0] = host; + /* shouldn't happen */ + rcode = EX_SOFTWARE; } - if (Nmx >= 0) + } + else if (!clever) + { + /* + ** Format and send message. + */ + + putfromline(mci->mci_out, m, e); + (*e->e_puthdr)(mci->mci_out, m, e); + putline("\n", mci->mci_out, m); + (*e->e_putbody)(mci->mci_out, m, e); + + /* get the exit status */ + rcode = endmailer(mci, pv[0]); + } + else +#ifdef SMTP + { + /* + ** Send the MAIL FROM: protocol + */ + + rcode = smtpmailfrom(m, mci, e); + if (rcode == EX_OK) { - extern MCONINFO *smtpinit(); + register char *t = tobuf; + register int i; - mci = smtpinit(m, pv, e); - if (mci != NULL && - mci->mci_state == MCIS_OPEN && - mci->mci_exitstat == EX_OK && - smtpmailfrom(m, mci, e) == EX_OK) + /* send the recipient list */ + tobuf[0] = '\0'; + for (to = tochain; to != NULL; to = to->q_tchain) { - register char *t = tobuf; - register int i; - - /* send the recipient list */ - tobuf[0] = '\0'; - for (to = tochain; to != NULL; to = to->q_tchain) + e->e_to = to->q_paddr; + if ((i = smtprcpt(to, m, mci, e)) != EX_OK) { - e->e_to = to->q_paddr; - if ((i = smtprcpt(to, m, mci, e)) != EX_OK) - { - markfailure(e, to, i); - giveresponse(i, m, e); - } - else - { - *t++ = ','; - for (p = to->q_paddr; *p; *t++ = *p++); - } + markfailure(e, to, i); + giveresponse(i, m, e); } - - /* now send the data */ - if (tobuf[0] == '\0') - e->e_to = NULL; else { - e->e_to = tobuf + 1; - rcode = smtpdata(m, mci, e); + *t++ = ','; + for (p = to->q_paddr; *p; *t++ = *p++) + continue; } + } - /* now close the connection */ - smtpquit(m, mci, e); + /* now send the data */ + if (tobuf[0] == '\0') + { + e->e_to = NULL; + if (bitset(MCIF_CACHED, mci->mci_flags)) + smtprset(m, mci, e); } + else + { + e->e_to = tobuf + 1; + rcode = smtpdata(m, mci, e); + } + + /* now close the connection */ + if (!bitset(MCIF_CACHED, mci->mci_flags)) + smtpquit(m, mci, e); } } - else -#endif /* SMTP */ +#else /* not SMTP */ { - static int sendoff(); - - message(Arpa_Info, "Connecting to %s (%s)...", host, m->m_name); - rcode = sendoff(e, m, pv, ctladdr); + syserr("deliver: need SMTP compiled to use clever mailer"); + rcode = -1; + goto give_up; } +#endif /* SMTP */ #ifdef NAMED_BIND if (ConfigLevel < 2) _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ #endif + /* arrange a return receipt if requested */ + if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) + { + e->e_flags |= EF_SENDRECEIPT; + /* do we want to send back more info? */ + } + /* ** Do final status disposal. ** We check for something in tobuf for the SMTP case. @@ -464,13 +490,20 @@ deliver(e, firstto) ** addressees. */ + give_up: if (tobuf[0] != '\0') giveresponse(rcode, m, e); for (to = tochain; to != NULL; to = to->q_tchain) + { if (rcode != EX_OK) markfailure(e, to, rcode); else to->q_flags |= QSENT; + } + + /* + ** Restore state and return. + */ errno = 0; define('g', (char *) NULL, e); @@ -587,61 +620,6 @@ dofork() return (pid); } /* -** SENDOFF -- send off call to mailer & collect response. -** -** Parameters: -** e -- the envelope to mail. -** m -- mailer descriptor. -** pvp -- parameter vector to send to it. -** ctladdr -- an address pointer controlling the -** user/groupid etc. of the mailer. -** -** Returns: -** exit status of mailer. -** -** Side Effects: -** none. -*/ -static -sendoff(e, m, pvp, ctladdr) - register ENVELOPE *e; - MAILER *m; - char **pvp; - ADDRESS *ctladdr; -{ - register int i; - register MCONINFO *mci; - extern MCONINFO *openmailer(); - - /* - ** Create connection to mailer. - */ - - mci = openmailer(m, pvp, ctladdr, FALSE); - if (mci == NULL) - return (-1); - - /* - ** Format and send message. - */ - - putfromline(mci->mci_out, m); - (*e->e_puthdr)(mci->mci_out, m, e); - putline("\n", mci->mci_out, m); - (*e->e_putbody)(mci->mci_out, m, e); - - i = endmailer(mci, pvp[0]); - - /* arrange a return receipt if requested */ - if (e->e_receiptto != NULL && bitnset(M_LOCAL, m->m_flags)) - { - e->e_flags |= EF_SENDRECEIPT; - /* do we want to send back more info? */ - } - - return (i); -} - /* ** ENDMAILER -- Wait for mailer to terminate. ** ** We should never get fatal errors (e.g., segmentation @@ -661,7 +639,7 @@ sendoff(e, m, pvp, ctladdr) */ endmailer(mci, name) - register MCONINFO *mci; + register MCI *mci; char *name; { int st; @@ -673,8 +651,6 @@ endmailer(mci, name) (void) fclose(mci->mci_out); mci->mci_in = mci->mci_out = NULL; mci->mci_state = MCIS_CLOSED; - if (bitset(MCIF_TEMP, mci->mci_flags)) - free(mci); /* in the IPC case there is nothing to wait for */ if (mci->mci_pid == 0) @@ -717,15 +693,16 @@ endmailer(mci, name) ** creates a mailer in a subprocess. */ -MCONINFO * -openmailer(m, pvp, ctladdr, clever) +MCI * +openmailer(m, pvp, ctladdr, clever, e) MAILER *m; char **pvp; ADDRESS *ctladdr; bool clever; + ENVELOPE *e; { int pid; - register MCONINFO *mci; + register MCI *mci; int mpvect[2]; int rpvect[2]; extern FILE *fdopen(); @@ -751,222 +728,250 @@ openmailer(m, pvp, ctladdr, clever) /* check for Local Person Communication -- not for mortals!!! */ if (strcmp(m->m_mailer, "[LPC]") == 0) { - mci = (MCONINFO *) xalloc(sizeof *mci); + mci = (MCI *) xalloc(sizeof *mci); mci->mci_in = stdin; mci->mci_out = stdout; mci->mci_pid = 0; - mci->mci_state = MCIS_OPEN; + mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; mci->mci_mailer = m; - return mci; + mci->mci_flags = 0; } - - if (strcmp(m->m_mailer, "[IPC]") == 0 || - strcmp(m->m_mailer, "[TCP]") == 0) + else if (strcmp(m->m_mailer, "[IPC]") == 0 || + strcmp(m->m_mailer, "[TCP]") == 0) { #ifdef DAEMON register STAB *st; extern STAB *stab(); register int i, j; register u_short port; + int nmx; + char *mxhosts[MAXMXHOSTS + 1]; + extern MCI *mci_get(); CurHostName = pvp[1]; +#ifdef NAMED_BIND + if (CurHostName != NULL && CurHostName[0] != '\0' && + CurHostName[0] != '[') + { + int rcode; + char buf[MAXNAME]; + + expand("\001j", buf, &buf[sizeof(buf) - 1], e); + nmx = getmxrr(CurHostName, mxhosts, buf, &rcode); + if (nmx < 0) + { + mci = mci_get(CurHostName, m); + mci->mci_exitstat = rcode; + mci->mci_errno = errno; + } + } + else +#endif + { + nmx = 1; + mxhosts[0] = CurHostName; + } + if (!clever) syserr("non-clever IPC"); if (pvp[2] != NULL) port = atoi(pvp[2]); else port = 0; - for (j = 0; j < Nmx; j++) + for (j = 0; j < nmx; j++) { /* see if we already know that this host is fried */ - CurHostName = MxHosts[j]; - st = stab(CurHostName, - ST_MCONINFO + m->m_mno, - ST_ENTER); - mci = &st->s_mci; - if (mci->mci_state == MCIS_OPEN) + CurHostName = mxhosts[j]; + mci = mci_get(CurHostName, m); + if (mci->mci_state != MCIS_CLOSED) return mci; mci->mci_mailer = m; - if (mci->mci_state == MCIS_CLOSED) - { - /* try the connection */ - message(Arpa_Info, "Connecting to %s (%s)...", - MxHosts[j], m->m_name); - i = makeconnection(MxHosts[j], port, mci, - bitnset(M_SECURE_PORT, m->m_flags)); - mci->mci_exitstat = i; - mci->mci_errno = errno; - if (i == EX_TEMPFAIL) - mci->mci_state = MCIS_TEMPFAIL; - else if (i != EX_OK) - mci->mci_state = MCIS_ERROR; - else - mci->mci_state = MCIS_OPENING; - } - else + if (mci->mci_exitstat != EX_OK) + continue; + + /* try the connection */ + setproctitle("%s %s: %s", e->e_id, mxhosts[1], "user open"); + message(Arpa_Info, "Connecting to %s (%s)...", + mxhosts[j], m->m_name); + i = makeconnection(mxhosts[j], port, mci, + bitnset(M_SECURE_PORT, m->m_flags)); + mci->mci_exitstat = i; + mci->mci_errno = errno; + if (i == EX_OK) { - i = mci->mci_exitstat; - errno = mci->mci_errno; + mci->mci_state = MCIS_OPENING; + mci_cache(mci); + break; } - if (i == EX_OK) - return mci; + else if (tTd(11, 1)) + printf("openmailer: makeconnection => stat=%d, errno=%d\n", + i, errno); + /* enter status of this host */ setstat(i); } - return NULL; -#else DAEMON +#else /* no DAEMON */ syserr("openmailer: no IPC"); return NULL; -#endif DAEMON +#endif /* DAEMON */ } - - /* create a pipe to shove the mail through */ - if (pipe(mpvect) < 0) + else { - syserr("openmailer: pipe (to mailer)"); - return NULL; - } + /* create a pipe to shove the mail through */ + if (pipe(mpvect) < 0) + { + syserr("openmailer: pipe (to mailer)"); + return NULL; + } -#ifdef SMTP - /* if this mailer speaks smtp, create a return pipe */ - if (clever && pipe(rpvect) < 0) - { - syserr("openmailer: pipe (from mailer)"); - (void) close(mpvect[0]); - (void) close(mpvect[1]); - return NULL; - } -#endif SMTP + /* if this mailer speaks smtp, create a return pipe */ + if (clever && pipe(rpvect) < 0) + { + syserr("openmailer: pipe (from mailer)"); + (void) close(mpvect[0]); + (void) close(mpvect[1]); + return NULL; + } - /* - ** Actually fork the mailer process. - ** DOFORK is clever about retrying. - ** - ** Dispose of SIGCHLD signal catchers that may be laying - ** around so that endmail will get it. - */ + /* + ** Actually fork the mailer process. + ** DOFORK is clever about retrying. + ** + ** Dispose of SIGCHLD signal catchers that may be laying + ** around so that endmail will get it. + */ - if (CurEnv->e_xfp != NULL) - (void) fflush(CurEnv->e_xfp); /* for debugging */ - (void) fflush(stdout); + if (e->e_xfp != NULL) + (void) fflush(e->e_xfp); /* for debugging */ + (void) fflush(stdout); # ifdef SIGCHLD - (void) signal(SIGCHLD, SIG_DFL); + (void) signal(SIGCHLD, SIG_DFL); # endif SIGCHLD - DOFORK(FORK); - /* pid is set by DOFORK */ - if (pid < 0) - { - /* failure */ - syserr("openmailer: cannot fork"); - (void) close(mpvect[0]); - (void) close(mpvect[1]); -#ifdef SMTP - if (clever) + DOFORK(FORK); + /* pid is set by DOFORK */ + if (pid < 0) { - (void) close(rpvect[0]); - (void) close(rpvect[1]); + /* failure */ + syserr("openmailer: cannot fork"); + (void) close(mpvect[0]); + (void) close(mpvect[1]); + if (clever) + { + (void) close(rpvect[0]); + (void) close(rpvect[1]); + } + return NULL; } -#endif SMTP - return NULL; - } - else if (pid == 0) - { - int i; - extern int DtableSize; + else if (pid == 0) + { + int i; + extern int DtableSize; - /* child -- set up input & exec mailer */ - /* make diagnostic output be standard output */ - (void) signal(SIGINT, SIG_IGN); - (void) signal(SIGHUP, SIG_IGN); - (void) signal(SIGTERM, SIG_DFL); + /* child -- set up input & exec mailer */ + /* make diagnostic output be standard output */ + (void) signal(SIGINT, SIG_IGN); + (void) signal(SIGHUP, SIG_IGN); + (void) signal(SIGTERM, SIG_DFL); - /* arrange to filter standard & diag output of command */ - if (clever) - { - (void) close(rpvect[0]); - (void) close(1); - (void) dup(rpvect[1]); - (void) close(rpvect[1]); - } - else if (OpMode == MD_SMTP || HoldErrs) - { - /* put mailer output in transcript */ - (void) close(1); - (void) dup(fileno(CurEnv->e_xfp)); - } - (void) close(2); - (void) dup(1); + /* arrange to filter std & diag output of command */ + if (clever) + { + (void) close(rpvect[0]); + (void) close(1); + (void) dup(rpvect[1]); + (void) close(rpvect[1]); + } + else if (OpMode == MD_SMTP || HoldErrs) + { + /* put mailer output in transcript */ + (void) close(1); + (void) dup(fileno(e->e_xfp)); + } + (void) close(2); + (void) dup(1); - /* arrange to get standard input */ - (void) close(mpvect[1]); - (void) close(0); - if (dup(mpvect[0]) < 0) - { - syserr("Cannot dup to zero!"); - _exit(EX_OSERR); - } - (void) close(mpvect[0]); - if (!bitnset(M_RESTR, m->m_flags)) - { - if (ctladdr == NULL || ctladdr->q_uid == 0) + /* arrange to get standard input */ + (void) close(mpvect[1]); + (void) close(0); + if (dup(mpvect[0]) < 0) { - (void) setgid(DefGid); - (void) initgroups(DefUser, DefGid); - (void) setuid(DefUid); + syserr("Cannot dup to zero!"); + _exit(EX_OSERR); } - else + (void) close(mpvect[0]); + if (!bitnset(M_RESTR, m->m_flags)) { - (void) setgid(ctladdr->q_gid); - (void) initgroups(ctladdr->q_ruser? - ctladdr->q_ruser: ctladdr->q_user, - ctladdr->q_gid); - (void) setuid(ctladdr->q_uid); + if (ctladdr == NULL || ctladdr->q_uid == 0) + { + (void) setgid(DefGid); + (void) initgroups(DefUser, DefGid); + (void) setuid(DefUid); + } + else + { + (void) setgid(ctladdr->q_gid); + (void) initgroups(ctladdr->q_ruser? + ctladdr->q_ruser: ctladdr->q_user, + ctladdr->q_gid); + (void) setuid(ctladdr->q_uid); + } } - } - /* arrange for all the files to be closed */ - for (i = 3; i < DtableSize; i++) { - register int j; - if ((j = fcntl(i, F_GETFD, 0)) != -1) - (void)fcntl(i, F_SETFD, j|1); - } + /* arrange for all the files to be closed */ + for (i = 3; i < DtableSize; i++) + { + register int j; + if ((j = fcntl(i, F_GETFD, 0)) != -1) + (void)fcntl(i, F_SETFD, j|1); + } - /* try to execute the mailer */ - execve(m->m_mailer, pvp, UserEnviron); - syserr("Cannot exec %s", m->m_mailer); - if (m == LocalMailer) - _exit(EX_TEMPFAIL); - switch (errno) - { - case EIO: - case EAGAIN: - case ENOMEM: + /* try to execute the mailer */ + execve(m->m_mailer, pvp, UserEnviron); + syserr("Cannot exec %s", m->m_mailer); + if (m == LocalMailer) + _exit(EX_TEMPFAIL); + switch (errno) + { + case EIO: + case EAGAIN: + case ENOMEM: # ifdef EPROCLIM - case EPROCLIM: + case EPROCLIM: # endif - _exit(EX_TEMPFAIL); + _exit(EX_TEMPFAIL); + } + _exit(EX_UNAVAILABLE); + } + + /* + ** Set up return value. + */ + + mci = (MCI *) xalloc(sizeof *mci); + mci->mci_mailer = m; + mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; + (void) close(mpvect[0]); + mci->mci_out = fdopen(mpvect[1], "w"); + if (clever) + { + (void) close(rpvect[1]); + mci->mci_in = fdopen(rpvect[0], "r"); + } + else + { + mci->mci_flags |= MCIF_TEMP; + mci->mci_in = NULL; } - _exit(EX_UNAVAILABLE); } /* - ** Set up return value. + ** If we are in SMTP opening state, send initial protocol. */ - mci = (MCONINFO *) xalloc(sizeof *mci); - mci->mci_mailer = m; - (void) close(mpvect[0]); - mci->mci_out = fdopen(mpvect[1], "w"); - if (clever) + if (clever && mci->mci_state != MCIS_CLOSED) { - (void) close(rpvect[1]); - mci->mci_in = fdopen(rpvect[0], "r"); - } - else - { - mci->mci_flags |= MCIF_TEMP; - mci->mci_in = NULL; + smtpinit(m, mci, e); } return mci; @@ -1082,7 +1087,7 @@ giveresponse(stat, m, e) */ if (LogLevel > ((stat == 0 || stat == EX_TEMPFAIL) ? 3 : 2)) - logdelivery(&statmsg[4]); + logdelivery(&statmsg[4], e); if (stat != EX_TEMPFAIL) setstat(stat); @@ -1110,14 +1115,15 @@ giveresponse(stat, m, e) ** none */ -logdelivery(stat) +logdelivery(stat, e) char *stat; + register ENVELOPE *e; { extern char *pintvl(); # ifdef LOG - syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", CurEnv->e_id, - CurEnv->e_to, pintvl(curtime() - CurEnv->e_ctime, TRUE), stat); + syslog(LOG_INFO, "%s: to=%s, delay=%s, stat=%s", e->e_id, + e->e_to, pintvl(curtime() - e->e_ctime, TRUE), stat); # endif LOG } /* @@ -1143,9 +1149,10 @@ logdelivery(stat) ** outputs some text to fp. */ -putfromline(fp, m) +putfromline(fp, m, e) register FILE *fp; register MAILER *m; + ENVELOPE *e; { char *template = "\001l\n"; char buf[MAXLINE]; @@ -1160,7 +1167,7 @@ putfromline(fp, m) char *bang; char xbuf[MAXLINE]; - expand("\001<", buf, &buf[sizeof buf - 1], CurEnv); + expand("\001<", buf, &buf[sizeof buf - 1], e); bang = index(buf, '!'); if (bang == NULL) syserr("No ! in UUCP! (%s)", buf); @@ -1172,7 +1179,7 @@ putfromline(fp, m) } } # endif UGLYUUCP - expand(template, buf, &buf[sizeof buf - 1], CurEnv); + expand(template, buf, &buf[sizeof buf - 1], e); putline(buf, fp, m); } /* @@ -1265,13 +1272,13 @@ putbody(fp, m, e) ** none. */ -mailfile(filename, ctladdr) +mailfile(filename, ctladdr, e) char *filename; ADDRESS *ctladdr; + register ENVELOPE *e; { register FILE *f; register int pid; - ENVELOPE *e = CurEnv; int mode; /* @@ -1354,7 +1361,7 @@ mailfile(filename, ctladdr) exit(EX_CANTCREAT); } - putfromline(f, ProgMailer); + putfromline(f, ProgMailer, e); (*CurEnv->e_puthdr)(f, ProgMailer, CurEnv); putline("\n", f, ProgMailer); (*CurEnv->e_putbody)(f, ProgMailer, CurEnv); @@ -1532,7 +1539,7 @@ sendall(e, mode) # ifdef LOG if (LogLevel > 5) syslog(LOG_NOTICE, "%s: lost lock: %m", - CurEnv->e_id); + e->e_id); # endif /* LOG */ exit(EX_OK); } diff --git a/usr/src/usr.sbin/sendmail/src/main.c b/usr/src/usr.sbin/sendmail/src/main.c index 74f062601e..e402abe963 100644 --- a/usr/src/usr.sbin/sendmail/src/main.c +++ b/usr/src/usr.sbin/sendmail/src/main.c @@ -13,13 +13,14 @@ char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 5.49 (Berkeley) %G%"; +static char sccsid[] = "@(#)main.c 5.50 (Berkeley) %G%"; #endif /* not lint */ #define _DEFINE #include #include +#include #include #include #include "sendmail.h" @@ -427,9 +428,19 @@ main(argc, argv, envp) case 'q': /* run queue files at intervals */ # ifdef QUEUE - if (getuid() != 0) { - usrerr("Permission denied"); - exit (EX_USAGE); + if (getuid() != 0) + { + struct stat stbuf; + + /* check to see if we own the queue directory */ + if (stat(QueueDir, &stbuf) < 0) + syserr("main: cannot stat %s", QueueDir); + if (stbuf.st_uid != getuid()) + { + /* nope, really a botch */ + usrerr("Permission denied"); + exit (EX_NOPERM); + } } (void) unsetenv("HOSTALIASES"); queuemode = TRUE; @@ -824,6 +835,9 @@ finis() CurEnv->e_to = NULL; dropenvelope(CurEnv); + /* flush any cached connections */ + mci_flush(); + /* post statistics */ poststats(StatFile); diff --git a/usr/src/usr.sbin/sendmail/src/mci.c b/usr/src/usr.sbin/sendmail/src/mci.c index f53fc48fd9..2c8d5b5493 100644 --- a/usr/src/usr.sbin/sendmail/src/mci.c +++ b/usr/src/usr.sbin/sendmail/src/mci.c @@ -7,12 +7,39 @@ */ #ifndef lint -static char sccsid[] = "@(#)mci.c 5.1 (Berkeley) %G%"; +static char sccsid[] = "@(#)mci.c 5.2 (Berkeley) %G%"; #endif /* not lint */ #include "sendmail.h" /* +** Mail Connection Information (MCI) Caching Module. +** +** There are actually two separate things cached. The first is +** the set of all open connections -- these are stored in a +** (small) list. The second is stored in the symbol table; it +** has the overall status for all hosts, whether or not there +** is a connection open currently. +** +** There should never be too many connections open (since this +** could flood the socket table), nor should a connection be +** allowed to sit idly for too long. +** +** MaxMciCache is the maximum number of open connections that +** will be supported. +** +** MciCacheTimeout is the time (in seconds) that a connection +** is permitted to survive without activity. +** +** We actually try any cached connections by sending a NOOP +** before we use them; if the NOOP fails we close down the +** connection and reopen it. Note that this means that a +** server SMTP that doesn't support NOOP will hose the +** algorithm -- but that doesn't seem too likely. +*/ + +MCI **MciCache; /* the open connection cache */ + /* ** MCI_CACHE -- enter a connection structure into the open connection cache ** ** This may cause something else to be flushed. @@ -25,10 +52,10 @@ static char sccsid[] = "@(#)mci.c 5.1 (Berkeley) %G%"; */ mci_cache(mci) - register MCONINFO *mci; + register MCI *mci; { - register MCONINFO **mcislot; - extern MCONINFO **mci_scan(); + register MCI **mcislot; + extern MCI **mci_scan(); if (MaxMciCache <= 0) { @@ -64,21 +91,19 @@ mci_cache(mci) ** The LRU (or empty) slot. */ -MCONINFO **MciCache; - -MCONINFO ** +MCI ** mci_scan(savemci) - MCONINFO *savemci; + MCI *savemci; { time_t now; - register MCONINFO **bestmci; - register MCONINFO *mci; + register MCI **bestmci; + register MCI *mci; register int i; if (MciCache == NULL) { /* first call */ - MciCache = (MCONINFO **) xalloc(MaxMciCache * sizeof *MciCache); + MciCache = (MCI **) xalloc(MaxMciCache * sizeof *MciCache); return (&MciCache[0]); } @@ -119,9 +144,9 @@ mci_scan(savemci) */ mci_uncache(mcislot) - register MCONINFO **mcislot; + register MCI **mcislot; { - register MCONINFO *mci; + register MCI *mci; extern ENVELOPE *BlankEnvelope; mci = *mcislot; @@ -152,10 +177,29 @@ mci_flush() ** MCI_GET -- get information about a particular host */ -MCONINFO * +MCI * mci_get(host, m) char *host; MAILER *m; { - return &(stab(host, ST_MCONINFO + m->m_mno, ST_ENTER))->s_mci; + register MCI *mci; + + mci = &(stab(host, ST_MCI + m->m_mno, ST_ENTER))->s_mci; + + if (tTd(42, 2)) + { + printf("mci_get(%s %s): mci_state=%d, _flags=%x, _exitstat=%d, _errno=%d\n", + host, m->m_name, mci->mci_state, mci->mci_flags, + mci->mci_exitstat, mci->mci_errno); + } + + /* try poking this to see if it is still usable */ + switch (mci->mci_state) + { + case MCIS_OPEN: + smtpnoop(mci); + break; + } + + return mci; } diff --git a/usr/src/usr.sbin/sendmail/src/queue.c b/usr/src/usr.sbin/sendmail/src/queue.c index 8d04b4b61e..e0559c1ee3 100644 --- a/usr/src/usr.sbin/sendmail/src/queue.c +++ b/usr/src/usr.sbin/sendmail/src/queue.c @@ -10,9 +10,9 @@ #ifndef lint #ifdef QUEUE -static char sccsid[] = "@(#)queue.c 5.39 (Berkeley) %G% (with queueing)"; +static char sccsid[] = "@(#)queue.c 5.40 (Berkeley) %G% (with queueing)"; #else -static char sccsid[] = "@(#)queue.c 5.39 (Berkeley) %G% (without queueing)"; +static char sccsid[] = "@(#)queue.c 5.40 (Berkeley) %G% (without queueing)"; #endif #endif /* not lint */ @@ -197,7 +197,7 @@ queueup(e, queueall, announce) e->e_to = q->q_paddr; message(Arpa_Info, "queued"); if (LogLevel > 4) - logdelivery("queued"); + logdelivery("queued", e); e->e_to = NULL; } if (tTd(40, 1)) diff --git a/usr/src/usr.sbin/sendmail/src/readcf.c b/usr/src/usr.sbin/sendmail/src/readcf.c index 9de1607db2..de42dee225 100644 --- a/usr/src/usr.sbin/sendmail/src/readcf.c +++ b/usr/src/usr.sbin/sendmail/src/readcf.c @@ -7,7 +7,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)readcf.c 5.38 (Berkeley) %G%"; +static char sccsid[] = "@(#)readcf.c 5.39 (Berkeley) %G%"; #endif /* not lint */ # include "sendmail.h" @@ -877,6 +877,16 @@ setoption(opt, val, sticky) IgnrDot = atobool(val); break; + case 'k': /* connection cache size */ + MaxMciCache = atoi(val); + if (MaxMciCache <= 0) + MaxMciCache = 1; + break; + + case 'K': /* connection cache timeout */ + MciCacheTimeout = convtime(val); + break; + case 'L': /* log level */ LogLevel = atoi(val); break; @@ -933,7 +943,7 @@ setoption(opt, val, sticky) case 'T': /* queue timeout */ TimeOut = convtime(val); - /*FALLTHROUGH*/ + break; case 't': /* time zone name */ TimeZoneSpec = newstr(val); diff --git a/usr/src/usr.sbin/sendmail/src/savemail.c b/usr/src/usr.sbin/sendmail/src/savemail.c index 6bd0ce17f8..bab7797b5a 100644 --- a/usr/src/usr.sbin/sendmail/src/savemail.c +++ b/usr/src/usr.sbin/sendmail/src/savemail.c @@ -7,7 +7,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)savemail.c 5.16 (Berkeley) %G%"; +static char sccsid[] = "@(#)savemail.c 5.17 (Berkeley) %G%"; #endif /* not lint */ # include @@ -299,7 +299,7 @@ savemail(e) break; } - putfromline(fp, ProgMailer); + putfromline(fp, ProgMailer, e); (*e->e_puthdr)(fp, ProgMailer, e); putline("\n", fp, ProgMailer); (*e->e_putbody)(fp, ProgMailer, e); diff --git a/usr/src/usr.sbin/sendmail/src/sendmail.h b/usr/src/usr.sbin/sendmail/src/sendmail.h index f0e448c733..3ca5dd6656 100644 --- a/usr/src/usr.sbin/sendmail/src/sendmail.h +++ b/usr/src/usr.sbin/sendmail/src/sendmail.h @@ -5,7 +5,7 @@ * * %sccs.include.redist.c% * - * @(#)sendmail.h 5.33 (Berkeley) %G% + * @(#)sendmail.h 5.34 (Berkeley) %G% */ /* @@ -15,7 +15,7 @@ # ifdef _DEFINE # define EXTERN # ifndef lint -static char SmailSccsId[] = "@(#)sendmail.h 5.33 %G%"; +static char SmailSccsId[] = "@(#)sendmail.h 5.34 %G%"; # endif lint # else _DEFINE # define EXTERN extern @@ -362,9 +362,9 @@ struct metamac ** hosts that we have looked up recently. */ -# define MCONINFO struct mailer_con_info +# define MCI struct mailer_con_info -MCONINFO +MCI { short mci_flags; /* flag bits, see below */ short mci_errno; /* error number on last connection */ @@ -382,15 +382,16 @@ MCONINFO /* flag bits */ #define MCIF_VALID 00001 /* this entry is valid */ #define MCIF_TEMP 00002 /* don't cache this connection */ +#define MCIF_CACHED 00004 /* currently in open cache */ /* states */ #define MCIS_CLOSED 0 /* no traffic on this connection */ #define MCIS_OPENING 1 /* sending initial protocol */ #define MCIS_OPEN 2 /* open, initial protocol sent */ #define MCIS_ACTIVE 3 /* message being sent */ -#define MCIS_SSD 4 /* service shutting down */ -#define MCIS_ERROR 5 /* error state */ -#define MCIS_TEMPFAIL 6 /* temporary failure */ +#define MCIS_QUITING 4 /* running quit protocol */ +#define MCIS_SSD 5 /* service shutting down */ +#define MCIS_ERROR 6 /* I/O error on connection */ /* ** Mapping functions ** @@ -444,7 +445,7 @@ struct symtab char *sv_alias; /* alias */ MAPCLASS sv_mapclass; /* mapping function class */ MAP sv_map; /* mapping function */ - MCONINFO sv_mci; /* mailer connection info */ + MCI sv_mci; /* mailer connection info */ } s_value; }; @@ -458,7 +459,7 @@ typedef struct symtab STAB; # define ST_ALIAS 4 /* an alias */ # define ST_MAPCLASS 5 /* mapping function class */ # define ST_MAP 6 /* mapping function */ -# define ST_MCONINFO 16 /* mailer connection info (offset) */ +# define ST_MCI 16 /* mailer connection info (offset) */ # define s_class s_value.sv_class # define s_address s_value.sv_addr @@ -611,9 +612,7 @@ EXTERN char SpaceSub; /* substitution for */ EXTERN int WkClassFact; /* multiplier for message class -> priority */ EXTERN int WkRecipFact; /* multiplier for # of recipients -> priority */ EXTERN int WkTimeFact; /* priority offset each time this job is run */ -EXTERN int Nmx; /* number of MX RRs */ EXTERN char *PostMasterCopy; /* address to get errs cc's */ -EXTERN char *MxHosts[MAXMXHOSTS+1]; /* for MX RRs */ EXTERN char *TrustedUsers[MAXTRUST+1]; /* list of trusted users */ EXTERN char *UserEnviron[MAXUSERENVIRON+1]; /* saved user environment */ EXTERN int CheckpointInterval; /* queue file checkpoint interval */ @@ -623,6 +622,8 @@ EXTERN int MaxHopCount; /* number of hops until we give an error */ EXTERN int ConfigLevel; /* config file level -- what does .cf expect? */ EXTERN char *TimeZoneSpec; /* override time zone specification */ EXTERN bool MatchGecos; /* look for user names in gecos field */ +EXTERN int MaxMciCache; /* maximum entries in MCI cache */ +EXTERN time_t MciCacheTimeout; /* maximum idle time on connections */ /* ** Trace information */ diff --git a/usr/src/usr.sbin/sendmail/src/usersmtp.c b/usr/src/usr.sbin/sendmail/src/usersmtp.c index 2526afa4d7..296d234265 100644 --- a/usr/src/usr.sbin/sendmail/src/usersmtp.c +++ b/usr/src/usr.sbin/sendmail/src/usersmtp.c @@ -10,9 +10,9 @@ #ifndef lint #ifdef SMTP -static char sccsid[] = "@(#)usersmtp.c 5.21 (Berkeley) %G% (with SMTP)"; +static char sccsid[] = "@(#)usersmtp.c 5.22 (Berkeley) %G% (with SMTP)"; #else -static char sccsid[] = "@(#)usersmtp.c 5.21 (Berkeley) %G% (without SMTP)"; +static char sccsid[] = "@(#)usersmtp.c 5.22 (Berkeley) %G% (without SMTP)"; #endif #endif /* not lint */ @@ -46,8 +46,7 @@ int SmtpPid; /* pid of mailer */ ** the mailer. ** ** Returns: -** appropriate exit status -- EX_OK on success. -** If not EX_OK, it should close the connection. +** none. ** ** Side Effects: ** creates connection and sends initial protocol. @@ -55,63 +54,48 @@ int SmtpPid; /* pid of mailer */ jmp_buf CtxGreeting; -MCONINFO * -smtpinit(m, pvp, e) +smtpinit(m, mci, e) struct mailer *m; - char **pvp; + register MCI *mci; ENVELOPE *e; { register int r; EVENT *gte; - MCONINFO *mci; static int greettimeout(); extern STAB *stab(); - extern MCONINFO *openmailer(); + extern MCI *openmailer(); /* ** Open the connection to the mailer. */ SmtpError[0] = '\0'; - setproctitle("%s %s: %s", e->e_id, pvp[1], "user open"); - mci = openmailer(m, pvp, (ADDRESS *) NULL, TRUE); - if (mci == NULL) - return NULL; - if (mci->mci_state != MCIS_OPENING && mci->mci_state != MCIS_CLOSED) - return mci; - mci->mci_phase = "user open"; - mci->mci_state = MCIS_OPENING; - if (mci->mci_pid < 0) + switch (mci->mci_state) { - if (tTd(18, 1)) - printf("smtpinit: cannot open %s: stat %d errno %d\n", - pvp[0], ExitStat, errno); - if (e->e_xfp != NULL) - { - register char *p; - extern char *errstring(); - extern char *statstring(); + case MCIS_ACTIVE: + /* need to clear old information */ + smtprset(m, mci, e); + mci->mci_state = MCIS_OPEN; - if (errno == 0) - { - p = statstring(ExitStat); - fprintf(e->e_xfp, - "%.3s %s.%s... %s\n", - p, pvp[1], m->m_name, p); - } - else - { - r = errno; - fprintf(e->e_xfp, - "421 %s.%s... Deferred: %s\n", - pvp[1], m->m_name, errstring(errno)); - errno = r; - } - } - mci->mci_exitstat = ExitStat; - return mci; + case MCIS_OPEN: + return; + + case MCIS_ERROR: + case MCIS_SSD: + /* shouldn't happen */ + smtpquit(m, mci, e); + + case MCIS_CLOSED: + syserr("smtpinit: state CLOSED"); + return; + + case MCIS_OPENING: + break; } + mci->mci_phase = "user open"; + mci->mci_state = MCIS_OPENING; + /* ** Get the greeting message. ** This should appear spontaneously. Give it five minutes to @@ -156,36 +140,28 @@ smtpinit(m, pvp, e) r = reply(m, mci, e); if (r < 0) goto tempfail2; - - /* tell it we will be sending one transaction only */ - smtpmessage("ONEX", m, mci); - r = reply(m, mci, e); - if (r < 0) - goto tempfail2; } mci->mci_state = MCIS_OPEN; - return mci; + return; tempfail1: tempfail2: mci->mci_exitstat = EX_TEMPFAIL; mci->mci_errno = errno; smtpquit(m, mci, e); - mci->mci_state = MCIS_TEMPFAIL; - return mci; + return; unavailable: mci->mci_exitstat = EX_UNAVAILABLE; mci->mci_errno = errno; smtpquit(m, mci, e); - mci->mci_state = MCIS_ERROR; - return mci; + return; } smtpmailfrom(m, mci, e) struct mailer *m; - MCONINFO *mci; + MCI *mci; ENVELOPE *e; { int r; @@ -225,7 +201,6 @@ smtpmailfrom(m, mci, e) mci->mci_exitstat = EX_TEMPFAIL; mci->mci_errno = errno; smtpquit(m, mci, e); - mci->mci_state = MCIS_TEMPFAIL; return EX_TEMPFAIL; } else if (r == 250) @@ -238,14 +213,12 @@ smtpmailfrom(m, mci, e) /* signal service unavailable */ mci->mci_exitstat = EX_UNAVAILABLE; smtpquit(m, mci, e); - mci->mci_state = MCIS_ERROR; return EX_UNAVAILABLE; } /* protocol error -- close up */ smtpquit(m, mci, e); mci->mci_exitstat = EX_PROTOCOL; - mci->mci_state = MCIS_ERROR; return EX_PROTOCOL; } @@ -273,7 +246,7 @@ greettimeout() smtprcpt(to, m, mci, e) ADDRESS *to; register MAILER *m; - MCONINFO *mci; + MCI *mci; ENVELOPE *e; { register int r; @@ -310,7 +283,7 @@ smtprcpt(to, m, mci, e) smtpdata(m, mci, e) struct mailer *m; - register MCONINFO *mci; + register MCI *mci; register ENVELOPE *e; { register int r; @@ -375,16 +348,12 @@ smtpdata(m, mci, e) smtpquit(m, mci, e) register MAILER *m; - register MCONINFO *mci; + register MCI *mci; ENVELOPE *e; { int i; - /* if the connection is already closed, don't bother */ - if (mci->mci_state == MCIS_CLOSED) - return; - - /* send the quit message if not a forced quit */ + /* send the quit message if we haven't gotten I/O error */ if (mci->mci_state != MCIS_ERROR) { smtpmessage("QUIT", m, mci); @@ -399,6 +368,44 @@ smtpquit(m, mci, e) syserr("smtpquit %s: stat %d", m->m_argv[0], i); } /* +** SMTPRSET -- send a RSET (reset) command +*/ + +smtprset(m, mci, e) + register MAILER *m; + register MCI *mci; + ENVELOPE *e; +{ + int r; + + smtpmessage("RSET", m, mci); + r = reply(m, mci, e); + if (r < 0 || REPLYTYPE(r) == 4) + return EX_TEMPFAIL; + else if (REPLYTYPE(r) == 2) + return EX_OK; + else + return EX_PROTOCOL; +} + /* +** SMTPNOOP -- send a NOOP (no operation) command to check the connection state +*/ + +smtpnoop(mci) + register MCI *mci; +{ + int r; + MAILER *m = mci->mci_mailer; + extern ENVELOPE BlankEnvelope; + ENVELOPE *e = &BlankEnvelope; + + smtpmessage("NOOP", m, mci); + r = reply(m, mci, e); + if (REPLYTYPE(r) != 2) + smtpquit(m, mci, e); + return r; +} + /* ** REPLY -- read arpanet reply ** ** Parameters: @@ -413,7 +420,7 @@ smtpquit(m, mci, e) reply(m, mci, e) MAILER *m; - MCONINFO *mci; + MCI *mci; ENVELOPE *e; { (void) fflush(mci->mci_out); @@ -463,7 +470,7 @@ reply(m, mci, e) # ifdef LOG syslog(LOG_INFO, "%s", &MsgBuf[4]); # endif LOG - mci->mci_state = MCIS_CLOSED; + mci->mci_state = MCIS_ERROR; smtpquit(m, mci, e); return (-1); } @@ -529,14 +536,14 @@ reply(m, mci, e) smtpmessage(f, m, mci, a, b, c) char *f; MAILER *m; - MCONINFO *mci; + MCI *mci; { (void) sprintf(SmtpMsgBuffer, f, a, b, c); if (tTd(18, 1) || (Verbose && !HoldErrs)) nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); if (mci->mci_out != NULL) fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, - m == 0 ? "\r\n" : m->m_eol); + m == NULL ? "\r\n" : m->m_eol); } # endif SMTP diff --git a/usr/src/usr.sbin/sendmail/src/version.c b/usr/src/usr.sbin/sendmail/src/version.c index 81af4db070..e896b144ce 100644 --- a/usr/src/usr.sbin/sendmail/src/version.c +++ b/usr/src/usr.sbin/sendmail/src/version.c @@ -7,7 +7,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)version.c 5.100 (Berkeley) %G%"; +static char sccsid[] = "@(#)version.c 5.101 (Berkeley) %G%"; #endif /* not lint */ -char Version[] = "5.100"; +char Version[] = "5.101"; -- 2.20.1