📄 mail.local.c
字号:
if (strncasecmp(buf+5, "from:", 5) != 0 ||
((return_path = parseaddr(buf + 10,
FALSE)) == NULL))
{
printf("501 5.5.4 Syntax error in parameters\r\n");
continue;
}
printf("250 2.5.0 ok\r\n");
continue;
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'n':
case 'N':
if (strcasecmp(buf, "noop") == 0)
{
printf("250 2.0.0 ok\r\n");
continue;
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'q':
case 'Q':
if (strcasecmp(buf, "quit") == 0)
{
printf("221 2.0.0 bye\r\n");
exit(EX_OK);
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'r':
case 'R':
if (strncasecmp(buf, "rcpt ", 5) == 0)
{
if (return_path == NULL)
{
printf("503 5.5.1 Need MAIL command\r\n");
continue;
}
if (rcpt_num >= rcpt_alloc)
{
rcpt_alloc += RCPT_GROW;
rcpt_addr = (char **)
REALLOC((char *) rcpt_addr,
rcpt_alloc *
sizeof(char **));
if (rcpt_addr == NULL)
{
printf("421 4.3.0 memory exhausted\r\n");
exit(EX_TEMPFAIL);
}
}
if (strncasecmp(buf + 5, "to:", 3) != 0 ||
((rcpt_addr[rcpt_num] = parseaddr(buf + 8,
TRUE)) == NULL))
{
printf("501 5.5.4 Syntax error in parameters\r\n");
continue;
}
if ((err = process_recipient(rcpt_addr[rcpt_num])) != NULL)
{
printf("%s\r\n", err);
continue;
}
rcpt_num++;
printf("250 2.1.5 ok\r\n");
continue;
}
else if (strcasecmp(buf, "rset") == 0)
{
printf("250 2.0.0 ok\r\n");
rset:
while (rcpt_num)
free(rcpt_addr[--rcpt_num]);
if (return_path != NULL)
free(return_path);
return_path = NULL;
continue;
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'v':
case 'V':
if (strncasecmp(buf, "vrfy ", 5) == 0)
{
printf("252 2.3.3 try RCPT to attempt delivery\r\n");
continue;
}
goto syntaxerr;
/* NOTREACHED */
break;
default:
syntaxerr:
printf("500 5.5.2 Syntax error\r\n");
continue;
/* NOTREACHED */
break;
}
}
}
int
store(from, lmtprcpts)
char *from;
int lmtprcpts;
{
FILE *fp = NULL;
time_t tval;
bool eline;
bool fullline = TRUE; /* current line is terminated */
bool prevfl; /* previous line was terminated */
char line[2048];
int fd;
char tmpbuf[sizeof _PATH_LOCTMP + 1];
(void) umask(0077);
(void) strlcpy(tmpbuf, _PATH_LOCTMP, sizeof tmpbuf);
if ((fd = mkstemp(tmpbuf)) == -1 || (fp = fdopen(fd, "w+")) == NULL)
{
if (lmtprcpts)
{
printf("451 4.3.0 unable to open temporary file\r\n");
return -1;
}
else
{
mailerr("451 4.3.0", "unable to open temporary file");
exit(ExitVal);
}
}
(void) unlink(tmpbuf);
if (LMTPMode)
{
printf("354 go ahead\r\n");
(void) fflush(stdout);
}
(void) time(&tval);
(void) fprintf(fp, "From %s %s", from, ctime(&tval));
#ifdef CONTENTLENGTH
HeaderLength = 0;
BodyLength = -1;
#endif /* CONTENTLENGTH */
line[0] = '\0';
eline = TRUE;
while (fgets(line, sizeof(line), stdin) != (char *)NULL)
{
size_t line_len = 0;
int peek;
prevfl = fullline; /* preserve state of previous line */
while (line[line_len] != '\n' && line_len < sizeof(line) - 2)
line_len++;
line_len++;
/* Check for dot-stuffing */
if (prevfl && lmtprcpts && line[0] == '.')
{
if (line[1] == '\n' ||
(line[1] == '\r' && line[2] == '\n'))
goto lmtpdot;
memcpy(line, line + 1, line_len);
line_len--;
}
/* Check to see if we have the full line from fgets() */
fullline = FALSE;
if (line_len > 0)
{
if (line[line_len - 1] == '\n')
{
if (line_len >= 2 &&
line[line_len - 2] == '\r')
{
line[line_len - 2] = '\n';
line[line_len - 1] = '\0';
line_len--;
}
fullline = TRUE;
}
else if (line[line_len - 1] == '\r')
{
/* Did we just miss the CRLF? */
peek = fgetc(stdin);
if (peek == '\n')
{
line[line_len - 1] = '\n';
fullline = TRUE;
}
else
(void) ungetc(peek, stdin);
}
}
else
fullline = TRUE;
#ifdef CONTENTLENGTH
if (prevfl && line[0] == '\n' && HeaderLength == 0)
{
eline = FALSE;
HeaderLength = ftell(fp);
if (HeaderLength <= 0)
{
/*
** shouldn't happen, unless ftell() is
** badly broken
*/
HeaderLength = -1;
}
}
#else /* CONTENTLENGTH */
if (prevfl && line[0] == '\n')
eline = TRUE;
#endif /* CONTENTLENGTH */
else
{
if (eline && line[0] == 'F' &&
!memcmp(line, "From ", 5))
(void) putc('>', fp);
eline = FALSE;
#ifdef CONTENTLENGTH
/* discard existing "Content-Length:" headers */
if (prevfl && HeaderLength == 0 &&
(line[0] == 'C' || line[0] == 'c') &&
strncasecmp(line, ContentHdr, 15) == 0)
{
/*
** be paranoid: clear the line
** so no "wrong matches" may occur later
*/
line[0] = '\0';
continue;
}
#endif /* CONTENTLENGTH */
}
(void) fwrite(line, sizeof(char), line_len, fp);
if (ferror(fp))
{
if (lmtprcpts)
{
while (lmtprcpts--)
printf("451 4.3.0 temporary file write error\r\n");
(void) fclose(fp);
return -1;
}
else
{
mailerr("451 4.3.0",
"temporary file write error");
(void) fclose(fp);
exit(ExitVal);
}
}
}
if (lmtprcpts)
{
/* Got a premature EOF -- toss message and exit */
exit(EX_OK);
}
/* If message not newline terminated, need an extra. */
if (strchr(line, '\n') == NULL)
(void) putc('\n', fp);
lmtpdot:
#ifdef CONTENTLENGTH
BodyLength = ftell(fp);
if (HeaderLength == 0 && BodyLength > 0) /* empty body */
{
HeaderLength = BodyLength;
BodyLength = 0;
}
else
BodyLength = BodyLength - HeaderLength - 1 ;
if (HeaderLength > 0 && BodyLength >= 0)
{
extern char *quad_to_string();
if (sizeof BodyLength > sizeof(long))
snprintf(line, sizeof line, "%s\n",
quad_to_string(BodyLength));
else
snprintf(line, sizeof line, "%ld\n",
(long) BodyLength);
strlcpy(&ContentHdr[16], line, sizeof(ContentHdr) - 16);
}
else
BodyLength = -1; /* Something is wrong here */
#endif /* CONTENTLENGTH */
/* Output a newline; note, empty messages are allowed. */
(void) putc('\n', fp);
if (fflush(fp) == EOF || ferror(fp) != 0)
{
if (lmtprcpts)
{
while (lmtprcpts--)
printf("451 4.3.0 temporary file write error\r\n");
(void) fclose(fp);
return -1;
}
else
{
mailerr("451 4.3.0", "temporary file write error");
(void) fclose(fp);
exit(ExitVal);
}
}
return fd;
}
void
deliver(fd, name, bouncequota)
int fd;
char *name;
bool bouncequota;
{
struct stat fsb;
struct stat sb;
struct passwd *pw;
char path[MAXPATHLEN];
int mbfd, nr = 0, nw, off;
char *p;
off_t curoff;
#ifdef CONTENTLENGTH
off_t headerbytes;
int readamount;
#endif /* CONTENTLENGTH */
char biffmsg[100], buf[8*1024];
extern char *quad_to_string();
/*
** Disallow delivery to unknown names -- special mailboxes can be
** handled in the sendmail aliases file.
*/
if ((pw = getpwnam(name)) == NULL)
{
if (ExitVal != EX_TEMPFAIL)
ExitVal = EX_UNAVAILABLE;
if (LMTPMode)
{
if (ExitVal == EX_TEMPFAIL)
printf("451 4.3.0 cannot lookup name: %s\r\n",
name);
else
printf("550 5.1.1 unknown name: %s\r\n", name);
}
else
{
char *errcode = NULL;
if (ExitVal == EX_TEMPFAIL)
errcode = "451 4.3.0";
else
errcode = "550 5.1.1";
mailerr(errcode, "unknown name: %s", name);
}
return;
}
endpwent();
/*
** Keep name reasonably short to avoid buffer overruns.
** This isn't necessary on BSD because of the proper
** definition of snprintf(), but it can cause problems
** on other systems.
** Also, clear out any bogus characters.
*/
if (strlen(name) > 40)
name[40] = '\0';
for (p = name; *p != '\0'; p++)
{
if (!isascii(*p))
*p &= 0x7f;
else if (!isprint(*p))
*p = '.';
}
(void) snprintf(path, sizeof(path), "%s/%s", _PATH_MAILDIR, name);
/*
** If the mailbox is linked or a symlink, fail. There's an obvious
** race here, that the file was replaced with a symbolic link after
** the lstat returned, but before the open. We attempt to detect
** this by comparing the original stat information and information
** returned by an fstat of the file descriptor returned by the open.
**
** NB: this is a symptom of a larger problem, that the mail spooling
** directory is writeable by the wrong users. If that directory is
** writeable, system security is compromised for other reasons, and
** it cannot be fixed here.
**
** If we created the mailbox, set the owner/group. If that fails,
** just return. Another process may have already opened it, so we
** can't unlink it. Historically, binmail set the owner/group at
** each mail delivery. We no longer do this, assuming that if the
** ownership or permissions were changed there was a reason.
**
** XXX
** open(2) should support flock'ing the file.
*/
tryagain:
#ifdef MAILLOCK
p = name;
#else /* MAILLOCK */
p = path;
#endif /* MAILLOCK */
if ((off = lockmbox(p)) != 0)
{
if (off == EX_TEMPFAIL || e_to_sys(off) == EX_TEMPFAIL)
{
ExitVal = EX_TEMPFAIL;
mailerr("451 4.3.0",
"lockmailbox %s failed; error code %d %s",
p, off, errno > 0 ? errstring(errno) : "");
}
else
{
mailerr("551 5.3.0",
"lockmailbox %s failed; error code %d %s",
p, off, errno > 0 ? errstring(errno) : "");
}
return;
}
if (lstat(path, &sb) < 0)
{
int save_errno;
int mode = S_IRUSR|S_IWUSR;
gid_t gid = U_GID;
#ifdef MAILGID
(void) umask(0007);
gid = MAILGID;
mode |= S_IRGRP|S_IWGRP;
#endif /* MAILGID */
mbfd = open(path, O_APPEND|O_CREAT|O_EXCL|O_WRONLY|EXTRA_MODE,
mode);
save_errno = errno;
if (lstat(path, &sb) < 0)
{
ExitVal = EX_CANTCREAT;
mailerr("550 5.2.0",
"%s: lstat: file changed after open", path);
goto err1;
}
if (mbfd == -1)
{
if (save_errno == EEXIST)
goto tryagain;
/* open failed, don't try again */
mailerr("450 4.2.0", "%s: %s", path,
errstring(save_errno));
goto err0;
}
else if (fchown(mbfd, U_UID, gid) < 0)
{
mailerr("451 4.3.0", "chown %u.%u: %s",
U_UID, gid, name);
goto err1;
}
else
{
/*
** open() was successful, now close it so can
** be opened as the right owner again.
** Paranoia: reset mbdf since the file descriptor
** is no longer valid; better safe than sorry.
*/
sb.st_uid = U_UID;
(void) close(mbfd);
mbfd = -1;
}
}
else if (sb.st_nlink != 1 || !S_ISREG(sb.st_mode))
{
mailerr("550 5.2.0", "%s: irregular file", path);
goto err0;
}
else if (sb.st_uid != U_UID)
{
ExitVal = EX_CANTCREAT;
mailerr("550 5.2.0", "%s: wrong ownership (%d)",
path, sb.st_uid);
goto err0;
}
/* change UID for quota checks */
if (setreuid(0, U_UID) < 0)
{
mailerr("450 4.2.0", "setreuid(0, %d): %s (r=%d, e=%d)",
U_UID, errstring(errno), getuid(), geteuid());
goto err1;
}
#ifdef DEBUG
fprintf(stderr, "new euid = %d\n", geteuid());
#endif /* DEBUG */
mbfd = open(path, O_APPEND|O_WRONLY|EXTRA_MODE, 0);
if (mbfd < 0)
{
mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
goto err0;
}
else if (fstat(mbfd, &fsb) < 0 ||
fsb.st_nlink != 1 ||
sb.st_nlink != 1 ||
!S_ISREG(fsb.st_mode) ||
sb.st_dev != fsb.st_dev ||
sb.st_ino != fsb.st_ino ||
# if HAS_ST_GEN && 0 /* AFS returns random values for st_gen */
sb.st_gen != fsb.st_gen ||
# endif /* HAS_ST_GEN && 0 */
sb.st_uid != fsb.st_uid)
{
ExitVal = EX_TEMPFAIL;
mailerr("550 5.2.0", "%s: fstat: file changed after open",
path);
goto err1;
}
/* Wait until we can get a lock on the file. */
if (flock(mbfd, LOCK_EX) < 0)
{
mailerr("450 4.2.0", "%s: %s", path, errstring(errno));
goto err1;
}
/* Get the starting offset of the new message for biff. */
curoff = lseek(mbfd, (off_t)0, SEEK_END);
if (sizeof curoff > sizeof(long))
(void) snprintf(biffmsg, sizeof(biffmsg), "%s@%s\n",
name, quad_to_string(curoff));
else
(void) snprintf(biffmsg, sizeof(biffmsg), "%s@%ld\n",
name, (long) curoff);
/* Copy the message into the file. */
if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1)
{
mailerr("450 4.2.0", "temporary file: %s",
errstring(errno));
goto err1;
}
#ifdef DEBUG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -