📄 srvrsmtp.c
字号:
/* * Copyright (c) 1983 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */# include "sendmail.h"#ifndef lint#ifdef SMTPstatic char sccsid[] = "@(#)srvrsmtp.c 8.37 (Berkeley) 4/13/94 (with SMTP)";#elsestatic char sccsid[] = "@(#)srvrsmtp.c 8.37 (Berkeley) 4/13/94 (without SMTP)";#endif#endif /* not lint */# include <errno.h># ifdef SMTP/*** SMTP -- run the SMTP protocol.**** Parameters:** none.**** Returns:** never.**** Side Effects:** Reads commands from the input channel and processes** them.*/struct cmd{ char *cmdname; /* command name */ int cmdcode; /* internal code, see below */};/* values for cmdcode */# define CMDERROR 0 /* bad command */# define CMDMAIL 1 /* mail -- designate sender */# define CMDRCPT 2 /* rcpt -- designate recipient */# define CMDDATA 3 /* data -- send message text */# define CMDRSET 4 /* rset -- reset state */# define CMDVRFY 5 /* vrfy -- verify address */# define CMDEXPN 6 /* expn -- expand address */# define CMDNOOP 7 /* noop -- do nothing */# define CMDQUIT 8 /* quit -- close connection and die */# define CMDHELO 9 /* helo -- be polite */# define CMDHELP 10 /* help -- give usage info */# define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) *//* non-standard commands */# define CMDONEX 16 /* onex -- sending one transaction only */# define CMDVERB 17 /* verb -- go into verbose mode *//* use this to catch and log "door handle" attempts on your system */# define CMDLOGBOGUS 23 /* bogus command that should be logged *//* debugging-only commands, only enabled if SMTPDEBUG is defined */# define CMDDBGQSHOW 24 /* showq -- show send queue */# define CMDDBGDEBUG 25 /* debug -- set debug mode */static struct cmd CmdTab[] ={ "mail", CMDMAIL, "rcpt", CMDRCPT, "data", CMDDATA, "rset", CMDRSET, "vrfy", CMDVRFY, "expn", CMDEXPN, "help", CMDHELP, "noop", CMDNOOP, "quit", CMDQUIT, "helo", CMDHELO, "ehlo", CMDEHLO, "verb", CMDVERB, "onex", CMDONEX, /* * remaining commands are here only * to trap and log attempts to use them */ "showq", CMDDBGQSHOW, "debug", CMDDBGDEBUG, "wiz", CMDLOGBOGUS, NULL, CMDERROR,};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 */smtp(e) register ENVELOPE *e;{ register char *p; register struct cmd *c; char *cmd; auto ADDRESS *vrfyqueue; ADDRESS *a; bool gotmail; /* mail command received */ bool gothello; /* helo command received */ bool vrfy; /* set if this is a vrfy command */ 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; int nrcpts; /* number of RCPT commands */ bool doublequeue; int badcommands = 0; /* count of bad commands */ char inp[MAXLINE]; char cmdbuf[MAXLINE]; extern char Version[]; extern ENVELOPE BlankEnvelope; if (fileno(OutChannel) != fileno(stdout)) { /* arrange for debugging output to go to remote host */ (void) dup2(fileno(OutChannel), fileno(stdout)); } settime(e); peerhostname = RealHostName; if (peerhostname == NULL) peerhostname = "localhost"; CurHostName = peerhostname; CurSmtpClient = macvalue('_', e); if (CurSmtpClient == NULL) CurSmtpClient = CurHostName; setproctitle("server %s startup", CurSmtpClient); expand("\201e", inp, &inp[sizeof inp], e); if (BrokenSmtpPeers) { p = strchr(inp, '\n'); if (p != NULL) *p = '\0'; message("220 %s", inp); } else { 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; gotmail = FALSE; for (;;) { /* arrange for backout */ if (setjmp(TopFrame) > 0) { /* if() nesting is necessary for Cray UNICOS */ if (InChild) { QuickAbort = FALSE; SuprErrs = TRUE; finis(); } } QuickAbort = FALSE; HoldErrs = FALSE; LogUsrErrs = FALSE; e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS); /* setup for the read */ e->e_to = NULL; Errors = 0; (void) fflush(stdout); /* read the input line */ SmtpPhase = "server cmd read"; setproctitle("server %s cmd read", CurHostName); p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand, SmtpPhase); /* handle errors */ if (p == NULL) { /* end of file, just die */ disconnect(1, e); message("421 %s Lost input channel from %s", MyHostName, CurSmtpClient);#ifdef LOG if (LogLevel > (gotmail ? 1 : 19)) syslog(LOG_NOTICE, "lost input channel from %s", CurSmtpClient);#endif if (InChild) ExitStat = EX_QUIT; finis(); } /* clean up end of line */ fixcrlf(inp, TRUE); /* echo command to transcript */ if (e->e_xfp != NULL) fprintf(e->e_xfp, "<<< %s\n", inp); if (e->e_id == NULL) setproctitle("%s: %.80s", CurSmtpClient, inp); else setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp); /* break off command */ for (p = inp; isascii(*p) && isspace(*p); p++) continue; cmd = cmdbuf; while (*p != '\0' && !(isascii(*p) && isspace(*p)) && cmd < &cmdbuf[sizeof cmdbuf - 2]) *cmd++ = *p++; *cmd = '\0'; /* throw away leading whitespace */ while (isascii(*p) && isspace(*p)) p++; /* decode command */ for (c = CmdTab; c->cmdname != NULL; c++) { if (!strcasecmp(c->cmdname, cmdbuf)) break; } /* reset errors */ errno = 0; /* process command */ switch (c->cmdcode) { case CMDHELO: /* hello -- introduce yourself */ case CMDEHLO: /* extended hello */ if (c->cmdcode == CMDEHLO) { protocol = "ESMTP"; SmtpPhase = "server EHLO"; } else { protocol = "SMTP"; SmtpPhase = "server HELO"; } sendinghost = newstr(p); gothello = TRUE; if (c->cmdcode != CMDEHLO) { /* print old message and be done with it */ message("250 %s Hello %s, pleased to meet you", 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 (MaxMessageSize > 0) message("250-SIZE %ld", MaxMessageSize); else message("250-SIZE"); message("250 HELP"); break; case CMDMAIL: /* mail -- designate sender */ SmtpPhase = "server MAIL"; /* check for validity of this command */ if (!gothello) { /* set sending host to our known value */ if (sendinghost == NULL) sendinghost = peerhostname; if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) { message("503 Polite people say HELO first"); break; } } if (gotmail) { message("503 Sender already specified"); if (InChild) finis(); break; } if (InChild) { errno = 0; syserr("503 Nested MAIL command: MAIL %s", p); finis(); } /* fork a subprocess to process this command */ if (runinchild("SMTP-MAIL", e) > 0) break; if (!gothello) { auth_warning(e, "Host %s didn't use HELO protocol", peerhostname); }#ifdef PICKY_HELO_CHECK if (strcasecmp(sendinghost, peerhostname) != 0 && (strcasecmp(peerhostname, "localhost") != 0 || strcasecmp(sendinghost, MyHostName) != 0)) { auth_warning(e, "Host %s claimed to be %s", peerhostname, sendinghost); }#endif if (protocol == NULL) protocol = "SMTP"; define('r', protocol, e); define('s', sendinghost, e); initsys(e); nrcpts = 0; e->e_flags |= EF_LOGSENDER; setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp); /* child -- go do the processing */ p = skipword(p, "from"); if (p == NULL) break; if (setjmp(TopFrame) > 0) { /* this failed -- undo work */ if (InChild) { QuickAbort = FALSE; SuprErrs = TRUE; e->e_flags &= ~EF_FATALERRS; finis(); } break; } QuickAbort = TRUE; /* must parse sender first */ delimptr = NULL; setsender(p, e, &delimptr, FALSE); p = delimptr; if (p != NULL && *p != '\0') *p++ = '\0'; /* check for possible spoofing */ if (RealUid != 0 && OpMode == MD_SMTP && (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 */ msize = 0; while (p != NULL && *p != '\0') { char *kp; char *vp = NULL; /* 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("MAIL: got arg %s=\"%s\"\n", kp, vp == NULL ? "<null>" : vp); 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 && msize > MaxMessageSize) { usrerr("552 Message size exceeds fixed maximum message size (%ld)", MaxMessageSize); /* NOTREACHED */ } if (!enoughspace(msize)) { message("452 Insufficient disk space; try again later"); break; } message("250 Sender ok"); gotmail = TRUE; break; case CMDRCPT: /* rcpt -- designate recipient */ if (!gotmail) { usrerr("503 Need MAIL before RCPT"); break; } SmtpPhase = "server RCPT"; if (setjmp(TopFrame) > 0) { e->e_flags &= ~EF_FATALERRS; break; } QuickAbort = TRUE; LogUsrErrs = TRUE; if (e->e_sendmode != SM_DELIVER) e->e_flags |= EF_VRFYONLY; p = skipword(p, "to");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -