diff options
Diffstat (limited to 'usr.sbin/sendmail/src/srvrsmtp.c')
-rw-r--r-- | usr.sbin/sendmail/src/srvrsmtp.c | 637 |
1 files changed, 192 insertions, 445 deletions
diff --git a/usr.sbin/sendmail/src/srvrsmtp.c b/usr.sbin/sendmail/src/srvrsmtp.c index 5e7ab64..e2a09e4 100644 --- a/usr.sbin/sendmail/src/srvrsmtp.c +++ b/usr.sbin/sendmail/src/srvrsmtp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983, 1995 Eric P. Allman + * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -36,9 +36,9 @@ #ifndef lint #ifdef SMTP -static char sccsid[] = "@(#)srvrsmtp.c 8.97 (Berkeley) 11/18/95 (with SMTP)"; +static char sccsid[] = "@(#)srvrsmtp.c 8.37 (Berkeley) 4/13/94 (with SMTP)"; #else -static char sccsid[] = "@(#)srvrsmtp.c 8.97 (Berkeley) 11/18/95 (without SMTP)"; +static char sccsid[] = "@(#)srvrsmtp.c 8.37 (Berkeley) 4/13/94 (without SMTP)"; #endif #endif /* not lint */ @@ -117,34 +117,35 @@ bool OneXact = FALSE; /* one xaction only this run */ char *CurSmtpClient; /* who's at the other end of channel */ static char *skipword(); +extern char RealUserName[]; #define MAXBADCOMMANDS 25 /* maximum number of bad commands */ -void smtp(e) - register ENVELOPE *volatile e; + register ENVELOPE *e; { register char *p; register struct cmd *c; char *cmd; auto ADDRESS *vrfyqueue; ADDRESS *a; - volatile bool gotmail; /* mail command received */ - volatile bool gothello; /* helo command received */ + bool gotmail; /* mail command received */ + bool gothello; /* helo command received */ bool vrfy; /* set if this is a vrfy command */ - char *volatile protocol; /* sending protocol */ - char *volatile sendinghost; /* sending hostname */ - char *volatile peerhostname; /* name of SMTP peer or "localhost" */ + char *protocol; /* sending protocol */ + char *sendinghost; /* sending hostname */ + unsigned long msize; /* approximate maximum message size */ + char *peerhostname; /* name of SMTP peer or "localhost" */ auto char *delimptr; char *id; - volatile int nrcpts = 0; /* number of RCPT commands */ + int nrcpts; /* number of RCPT commands */ bool doublequeue; - volatile int badcommands = 0; /* count of bad commands */ + int badcommands = 0; /* count of bad commands */ char inp[MAXLINE]; char cmdbuf[MAXLINE]; + extern char Version[]; extern ENVELOPE BlankEnvelope; - extern void help __P((char *)); if (fileno(OutChannel) != fileno(stdout)) { @@ -161,41 +162,28 @@ smtp(e) CurSmtpClient = CurHostName; setproctitle("server %s startup", CurSmtpClient); -#ifdef LOG - if (LogLevel > 11) - { - /* log connection information */ - syslog(LOG_INFO, "SMTP connect from %.100s (%.100s)", - CurSmtpClient, anynet_ntoa(&RealHostAddr)); - } -#endif - - /* output the first line, inserting "ESMTP" as second word */ - expand(SmtpGreeting, inp, sizeof inp, e); - p = strchr(inp, '\n'); - if (p != NULL) - *p++ = '\0'; - id = strchr(inp, ' '); - if (id == NULL) - id = &inp[strlen(inp)]; - cmd = p == NULL ? "220 %.*s ESMTP%s" : "220-%.*s ESMTP%s"; - message(cmd, id - inp, inp, id); - - /* output remaining lines */ - while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL) + expand("\201e", inp, &inp[sizeof inp], e); + if (BrokenSmtpPeers) { - *p++ = '\0'; - if (isascii(*id) && isspace(*id)) - id++; - message("220-%s", id); + p = strchr(inp, '\n'); + if (p != NULL) + *p = '\0'; + message("220 %s", inp); } - if (id != NULL) + else { - if (isascii(*id) && isspace(*id)) - id++; - message("220 %s", id); - } + char *q = inp; + while (q != NULL) + { + p = strchr(q, '\n'); + if (p != NULL) + *p++ = '\0'; + message("220-%s", q); + q = p; + } + message("220 ESMTP spoken here"); + } protocol = NULL; sendinghost = macvalue('s', e); gothello = FALSE; @@ -225,7 +213,7 @@ smtp(e) /* read the input line */ SmtpPhase = "server cmd read"; - setproctitle("server %s cmd read", CurSmtpClient); + setproctitle("server %s cmd read", CurHostName); p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand, SmtpPhase); @@ -238,7 +226,7 @@ smtp(e) MyHostName, CurSmtpClient); #ifdef LOG if (LogLevel > (gotmail ? 1 : 19)) - syslog(LOG_NOTICE, "lost input channel from %.100s", + syslog(LOG_NOTICE, "lost input channel from %s", CurSmtpClient); #endif if (InChild) @@ -297,39 +285,6 @@ smtp(e) protocol = "SMTP"; SmtpPhase = "server HELO"; } - - /* check for valid domain name (re 1123 5.2.5) */ - if (*p == '\0') - { - message("501 %s requires domain address", - cmdbuf); - break; - } - else - { - register char *q; - - for (q = p; *q != '\0'; q++) - { - if (!isascii(*q)) - break; - if (isalnum(*q)) - continue; - if (isspace(*q)) - { - *q = '\0'; - break; - } - if (strchr("[].-_#", *q) == NULL) - break; - } - if (*q != '\0') - { - message("501 Invalid domain name"); - break; - } - } - sendinghost = newstr(p); gothello = TRUE; if (c->cmdcode != CMDEHLO) @@ -339,25 +294,16 @@ smtp(e) MyHostName, CurSmtpClient); break; } - + /* print extended message and brag */ message("250-%s Hello %s, pleased to meet you", MyHostName, CurSmtpClient); if (!bitset(PRIV_NOEXPN, PrivacyFlags)) message("250-EXPN"); -#if MIME8TO7 - message("250-8BITMIME"); -#endif if (MaxMessageSize > 0) message("250-SIZE %ld", MaxMessageSize); else message("250-SIZE"); -#if DSN - if (SendMIMEErrors) - message("250-DSN"); -#endif - message("250-VERB"); - message("250-ONEX"); message("250 HELP"); break; @@ -398,7 +344,7 @@ smtp(e) { auth_warning(e, "Host %s didn't use HELO protocol", - CurSmtpClient); + peerhostname); } #ifdef PICKY_HELO_CHECK if (strcasecmp(sendinghost, peerhostname) != 0 && @@ -406,7 +352,7 @@ smtp(e) strcasecmp(sendinghost, MyHostName) != 0)) { auth_warning(e, "Host %s claimed to be %s", - CurSmtpClient, sendinghost); + peerhostname, sendinghost); } #endif @@ -416,7 +362,7 @@ smtp(e) define('s', sendinghost, e); initsys(e); nrcpts = 0; - e->e_flags |= EF_LOGSENDER|EF_CLRQUEUE; + e->e_flags |= EF_LOGSENDER; setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp); /* child -- go do the processing */ @@ -446,21 +392,19 @@ smtp(e) /* check for possible spoofing */ if (RealUid != 0 && OpMode == MD_SMTP && - !wordinclass(RealUserName, 't') && - !bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && - strcmp(e->e_from.q_user, RealUserName) != 0) + (e->e_from.q_mailer != LocalMailer && + strcmp(e->e_from.q_user, RealUserName) != 0)) { auth_warning(e, "%s owned process doing -bs", RealUserName); } /* now parse ESMTP arguments */ - e->e_msgsize = 0; + msize = 0; while (p != NULL && *p != '\0') { char *kp; char *vp = NULL; - extern void mail_esmtp_args __P((char *, char *, ENVELOPE *)); /* locate the beginning of the keyword */ while (isascii(*p) && isspace(*p)) @@ -491,17 +435,59 @@ smtp(e) printf("MAIL: got arg %s=\"%s\"\n", kp, vp == NULL ? "<null>" : vp); - mail_esmtp_args(kp, vp, e); + if (strcasecmp(kp, "size") == 0) + { + if (vp == NULL) + { + usrerr("501 SIZE requires a value"); + /* NOTREACHED */ + } +# ifdef __STDC__ + msize = strtoul(vp, (char **) NULL, 10); +# else + msize = strtol(vp, (char **) NULL, 10); +# endif + } + else if (strcasecmp(kp, "body") == 0) + { + if (vp == NULL) + { + usrerr("501 BODY requires a value"); + /* NOTREACHED */ + } +# ifdef MIME + if (strcasecmp(vp, "8bitmime") == 0) + { + e->e_bodytype = "8BITMIME"; + SevenBit = FALSE; + } + else if (strcasecmp(vp, "7bit") == 0) + { + e->e_bodytype = "7BIT"; + SevenBit = TRUE; + } + else + { + usrerr("501 Unknown BODY type %s", + vp); + } +# endif + } + else + { + usrerr("501 %s parameter unrecognized", kp); + /* NOTREACHED */ + } } - if (MaxMessageSize > 0 && e->e_msgsize > MaxMessageSize) + if (MaxMessageSize > 0 && msize > MaxMessageSize) { usrerr("552 Message size exceeds fixed maximum message size (%ld)", MaxMessageSize); /* NOTREACHED */ } - - if (!enoughdiskspace(e->e_msgsize)) + + if (!enoughspace(msize)) { message("452 Insufficient disk space; try again later"); break; @@ -531,53 +517,11 @@ smtp(e) p = skipword(p, "to"); if (p == NULL) break; - a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e); + a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', NULL, e); if (a == NULL) break; - p = delimptr; - - /* now parse ESMTP arguments */ - while (p != NULL && *p != '\0') - { - char *kp; - char *vp = NULL; - extern void rcpt_esmtp_args __P((ADDRESS *, char *, char *, ENVELOPE *)); - - /* locate the beginning of the keyword */ - while (isascii(*p) && isspace(*p)) - p++; - if (*p == '\0') - break; - kp = p; - - /* skip to the value portion */ - while (isascii(*p) && isalnum(*p) || *p == '-') - p++; - if (*p == '=') - { - *p++ = '\0'; - vp = p; - - /* skip to the end of the value */ - while (*p != '\0' && *p != ' ' && - !(isascii(*p) && iscntrl(*p)) && - *p != '=') - p++; - } - - if (*p != '\0') - *p++ = '\0'; - - if (tTd(19, 1)) - printf("RCPT: got arg %s=\"%s\"\n", kp, - vp == NULL ? "<null>" : vp); - - rcpt_esmtp_args(a, kp, vp, e); - } - - /* save in recipient list after ESMTP mods */ - a = recipient(a, &e->e_sendqueue, 0, e); - + a->q_flags |= QPRIMARY; + a = recipient(a, &e->e_sendqueue, e); if (Errors != 0) break; @@ -631,18 +575,10 @@ smtp(e) /* collect the text of the message */ SmtpPhase = "collect"; - buffer_errors(); - collect(InChannel, TRUE, doublequeue, NULL, e); - flush_errors(TRUE); + collect(TRUE, doublequeue, e); if (Errors != 0) goto abortmessage; - - /* make sure we actually do delivery */ - e->e_flags &= ~EF_CLRQUEUE; - - /* from now on, we have to operate silently */ - buffer_errors(); - e->e_errormode = EM_MAIL; + HoldErrs = TRUE; /* ** Arrange to send to everyone. @@ -663,32 +599,42 @@ smtp(e) */ SmtpPhase = "delivery"; + if (nrcpts != 1 && !doublequeue) + { + HoldErrs = TRUE; + e->e_errormode = EM_MAIL; + } e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp); id = e->e_id; - if (doublequeue) + /* send to all recipients */ + sendall(e, doublequeue ? SM_QUEUE : SM_DEFAULT); + e->e_to = NULL; + + /* issue success if appropriate and reset */ + if (Errors == 0 || HoldErrs) + message("250 %s Message accepted for delivery", id); + + if (bitset(EF_FATALERRS, e->e_flags) && !HoldErrs) { - /* make sure it is in the queue */ - queueup(e, FALSE); + /* avoid sending back an extra message */ + e->e_flags &= ~EF_FATALERRS; + e->e_flags |= EF_CLRQUEUE; } else { - /* send to all recipients */ - sendall(e, SM_DEFAULT); - } - e->e_to = NULL; + /* from now on, we have to operate silently */ + HoldErrs = TRUE; + e->e_errormode = EM_MAIL; - /* issue success message */ - message("250 %s Message accepted for delivery", id); - - /* if we just queued, poke it */ - if (doublequeue && e->e_sendmode != SM_QUEUE && - e->e_sendmode != SM_DEFER) - { - extern pid_t dowork(); + /* if we just queued, poke it */ + if (doublequeue && e->e_sendmode != SM_QUEUE) + { + extern pid_t dowork(); - unlockqueue(e); - (void) dowork(id, TRUE, TRUE, e); + unlockqueue(e); + (void) dowork(id, TRUE, TRUE, e); + } } abortmessage: @@ -705,9 +651,6 @@ smtp(e) case CMDRSET: /* rset -- reset state */ message("250 Reset state"); - - /* arrange to ignore any current send list */ - e->e_sendqueue = NULL; e->e_flags |= EF_CLRQUEUE; if (InChild) finis(); @@ -725,14 +668,13 @@ smtp(e) PrivacyFlags)) { if (vrfy) - message("252 Cannot VRFY user; try RCPT to attempt delivery (or try finger)"); + message("252 Who's to say?"); else message("502 Sorry, we do not allow this operation"); #ifdef LOG if (LogLevel > 5) - syslog(LOG_INFO, "%.100s: %s [rejected]", - CurSmtpClient, - shortenstring(inp, 203)); + syslog(LOG_INFO, "%s: %s [rejected]", + CurSmtpClient, inp); #endif break; } @@ -747,16 +689,14 @@ smtp(e) break; #ifdef LOG if (LogLevel > 5) - syslog(LOG_INFO, "%.100s: %s", - CurSmtpClient, - shortenstring(inp, 203)); + syslog(LOG_INFO, "%s: %s", CurSmtpClient, inp); #endif vrfyqueue = NULL; QuickAbort = TRUE; if (vrfy) e->e_flags |= EF_VRFYONLY; while (*p != '\0' && isascii(*p) && isspace(*p)) - p++; + *p++; if (*p == '\0') { message("501 Argument required"); @@ -764,7 +704,7 @@ smtp(e) } else { - (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e); + (void) sendtolist(p, NULLADDR, &vrfyqueue, e); } if (Errors != 0) { @@ -778,8 +718,6 @@ smtp(e) } while (vrfyqueue != NULL) { - extern void printvrfyaddr __P((ADDRESS *, bool)); - a = vrfyqueue; while ((a = a->q_next) != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags)) @@ -804,9 +742,6 @@ smtp(e) message("221 %s closing connection", MyHostName); doquit: - /* arrange to ignore any current send list */ - e->e_sendqueue = NULL; - /* avoid future 050 messages */ disconnect(1, e); @@ -851,8 +786,8 @@ doquit: # ifdef LOG if (LogLevel > 0) syslog(LOG_CRIT, - "\"%s\" command from %.100s (%.100s)", - c->cmdname, CurSmtpClient, + "\"%s\" command from %s (%s)", + c->cmdname, peerhostname, anynet_ntoa(&RealHostAddr)); # endif /* FALL THROUGH */ @@ -912,7 +847,7 @@ skipword(p, w) { syntax: message("501 Syntax error in parameters scanning \"%s\"", - shortenstring(firstp, 203)); + firstp); Errors++; return (NULL); } @@ -930,183 +865,6 @@ skipword(p, w) return (p); } /* -** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line -** -** Parameters: -** kp -- the parameter key. -** vp -- the value of that parameter. -** e -- the envelope. -** -** Returns: -** none. -*/ - -void -mail_esmtp_args(kp, vp, e) - char *kp; - char *vp; - ENVELOPE *e; -{ - if (strcasecmp(kp, "size") == 0) - { - if (vp == NULL) - { - usrerr("501 SIZE requires a value"); - /* NOTREACHED */ - } -# if defined(__STDC__) && !defined(BROKEN_ANSI_LIBRARY) - e->e_msgsize = strtoul(vp, (char **) NULL, 10); -# else - e->e_msgsize = strtol(vp, (char **) NULL, 10); -# endif - } - else if (strcasecmp(kp, "body") == 0) - { - if (vp == NULL) - { - usrerr("501 BODY requires a value"); - /* NOTREACHED */ - } - else if (strcasecmp(vp, "8bitmime") == 0) - { - SevenBitInput = FALSE; - } - else if (strcasecmp(vp, "7bit") == 0) - { - SevenBitInput = TRUE; - } - else - { - usrerr("501 Unknown BODY type %s", - vp); - /* NOTREACHED */ - } - e->e_bodytype = newstr(vp); - } - else if (strcasecmp(kp, "envid") == 0) - { - if (vp == NULL) - { - usrerr("501 ENVID requires a value"); - /* NOTREACHED */ - } - if (!xtextok(vp)) - { - usrerr("501 Syntax error in ENVID parameter value"); - /* NOTREACHED */ - } - if (e->e_envid != NULL) - { - usrerr("501 Duplicate ENVID parameter"); - /* NOTREACHED */ - } - e->e_envid = newstr(vp); - } - else if (strcasecmp(kp, "ret") == 0) - { - if (vp == NULL) - { - usrerr("501 RET requires a value"); - /* NOTREACHED */ - } - if (bitset(EF_RET_PARAM, e->e_flags)) - { - usrerr("501 Duplicate RET parameter"); - /* NOTREACHED */ - } - e->e_flags |= EF_RET_PARAM; - if (strcasecmp(vp, "hdrs") == 0) - e->e_flags |= EF_NO_BODY_RETN; - else if (strcasecmp(vp, "full") != 0) - { - usrerr("501 Bad argument \"%s\" to RET", vp); - /* NOTREACHED */ - } - } - else - { - usrerr("501 %s parameter unrecognized", kp); - /* NOTREACHED */ - } -} -/* -** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line -** -** Parameters: -** a -- the address corresponding to the To: parameter. -** kp -- the parameter key. -** vp -- the value of that parameter. -** e -- the envelope. -** -** Returns: -** none. -*/ - -void -rcpt_esmtp_args(a, kp, vp, e) - ADDRESS *a; - char *kp; - char *vp; - ENVELOPE *e; -{ - if (strcasecmp(kp, "notify") == 0) - { - char *p; - - if (vp == NULL) - { - usrerr("501 NOTIFY requires a value"); - /* NOTREACHED */ - } - a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY); - a->q_flags |= QHASNOTIFY; - if (strcasecmp(vp, "never") == 0) - return; - for (p = vp; p != NULL; vp = p) - { - p = strchr(p, ','); - if (p != NULL) - *p++ = '\0'; - if (strcasecmp(vp, "success") == 0) - a->q_flags |= QPINGONSUCCESS; - else if (strcasecmp(vp, "failure") == 0) - a->q_flags |= QPINGONFAILURE; - else if (strcasecmp(vp, "delay") == 0) - a->q_flags |= QPINGONDELAY; - else - { - usrerr("501 Bad argument \"%s\" to NOTIFY", - vp); - /* NOTREACHED */ - } - } - } - else if (strcasecmp(kp, "orcpt") == 0) - { - if (vp == NULL) - { - usrerr("501 ORCPT requires a value"); - /* NOTREACHED */ - } - if (strchr(vp, ';') == NULL || !xtextok(vp)) - { - usrerr("501 Syntax error in ORCPT parameter value"); - /* NOTREACHED */ - } - if (a->q_orcpt != NULL) - { - usrerr("501 Duplicate ORCPT parameter"); - /* NOTREACHED */ - } - a->q_orcpt = newstr(vp); - } - else - { - usrerr("501 %s parameter unrecognized", kp); - /* NOTREACHED */ - } -} -/* ** PRINTVRFYADDR -- print an entry in the verify queue ** ** Parameters: @@ -1120,7 +878,6 @@ rcpt_esmtp_args(a, kp, vp, e) ** Prints the appropriate 250 codes. */ -void printvrfyaddr(a, last) register ADDRESS *a; bool last; @@ -1148,6 +905,66 @@ printvrfyaddr(a, last) } } /* +** HELP -- implement the HELP command. +** +** Parameters: +** topic -- the topic we want help for. +** +** Returns: +** none. +** +** Side Effects: +** outputs the help file to message output. +*/ + +help(topic) + char *topic; +{ + register FILE *hf; + int len; + char buf[MAXLINE]; + bool noinfo; + + if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) + { + /* no help */ + errno = 0; + message("502 HELP not implemented"); + return; + } + + if (topic == NULL || *topic == '\0') + topic = "smtp"; + else + makelower(topic); + + len = strlen(topic); + noinfo = TRUE; + + while (fgets(buf, sizeof buf, hf) != NULL) + { + if (strncmp(buf, topic, len) == 0) + { + register char *p; + + p = strchr(buf, '\t'); + if (p == NULL) + p = buf; + else + p++; + fixcrlf(p, TRUE); + message("214-%s", p); + noinfo = FALSE; + } + } + + if (noinfo) + message("504 HELP topic unknown"); + else + message("214 End of HELP info"); + (void) fclose(hf); +} +/* ** RUNINCHILD -- return twice -- once in the child, then in the parent again ** ** Parameters: @@ -1161,7 +978,6 @@ printvrfyaddr(a, last) ** none. */ -int runinchild(label, e) char *label; register ENVELOPE *e; @@ -1173,7 +989,7 @@ runinchild(label, e) childpid = dofork(); if (childpid < 0) { - syserr("451 %s: cannot fork", label); + syserr("%s: cannot fork", label); return (1); } if (childpid > 0) @@ -1181,12 +997,12 @@ runinchild(label, e) auto int st; /* parent -- wait for child to complete */ - setproctitle("server %s child wait", CurSmtpClient); + setproctitle("server %s child wait", CurHostName); st = waitfor(childpid); if (st == -1) - syserr("451 %s: lost child", label); + syserr("%s: lost child", label); else if (!WIFEXITED(st)) - syserr("451 %s: died on signal %d", + syserr("%s: died on signal %d", label, st & 0177); /* if we exited on a QUIT command, complete the process */ @@ -1214,72 +1030,3 @@ runinchild(label, e) } # endif /* SMTP */ -/* -** HELP -- implement the HELP command. -** -** Parameters: -** topic -- the topic we want help for. -** -** Returns: -** none. -** -** Side Effects: -** outputs the help file to message output. -*/ - -void -help(topic) - char *topic; -{ - register FILE *hf; - int len; - bool noinfo; - char buf[MAXLINE]; - extern char Version[]; - - - if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL) - { - /* no help */ - errno = 0; - message("502 Sendmail %s -- HELP not implemented", Version); - return; - } - - if (topic == NULL || *topic == '\0') - { - topic = "smtp"; - message("214-This is Sendmail version %s", Version); - noinfo = FALSE; - } - else - { - makelower(topic); - noinfo = TRUE; - } - - len = strlen(topic); - - while (fgets(buf, sizeof buf, hf) != NULL) - { - if (strncmp(buf, topic, len) == 0) - { - register char *p; - - p = strchr(buf, '\t'); - if (p == NULL) - p = buf; - else - p++; - fixcrlf(p, TRUE); - message("214-%s", p); - noinfo = FALSE; - } - } - - if (noinfo) - message("504 HELP topic \"%.10s\" unknown", topic); - else - message("214 End of HELP info"); - (void) fclose(hf); -} |