📄 mail.local.c
字号:
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.\n\
All rights reserved.\n\
Copyright (c) 1990, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* ! lint */
#ifndef lint
static char id[] = "@(#)$Id: mail.local.c,v 8.143.4.37 2000/09/22 00:49:10 doug Exp $";
#endif /* ! lint */
/*
** This is not intended to work on System V derived systems
** such as Solaris or HP-UX, since they use a totally different
** approach to mailboxes (essentially, they have a setgid program
** rather than setuid, and they rely on the ability to "give away"
** files to do their work). IT IS NOT A BUG that this doesn't
** work on such architectures.
*/
/* additional mode for open() */
# define EXTRA_MODE 0
# include <sys/types.h>
# include <sys/param.h>
# include <sys/stat.h>
# include <sys/socket.h>
# include <sys/file.h>
# include <netinet/in.h>
# include <arpa/nameser.h>
# include <fcntl.h>
# include <netdb.h>
# include <pwd.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <syslog.h>
# include <time.h>
# include <unistd.h>
# ifdef EX_OK
# undef EX_OK /* unistd.h may have another use for this */
# endif /* EX_OK */
# include <sysexits.h>
# include <ctype.h>
# ifndef __P
# include "sendmail/cdefs.h"
# endif /* ! __P */
# include "sendmail/useful.h"
extern size_t strlcpy __P((char *, const char *, size_t));
extern size_t strlcat __P((char *, const char *, size_t));
# if defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
# ifndef HASSTRERROR
# define HASSTRERROR 1
# endif /* ! HASSTRERROR */
# endif /* defined(BSD4_4) || defined(__osf__) || defined(__GNU_LIBRARY__) || defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
# include "sendmail/errstring.h"
# ifndef LOCKTO_RM
# define LOCKTO_RM 300 /* timeout for stale lockfile removal */
# endif /* ! LOCKTO_RM */
# ifndef LOCKTO_GLOB
# define LOCKTO_GLOB 400 /* global timeout for lockfile creation */
# endif /* ! LOCKTO_GLOB */
# ifdef __STDC__
# include <stdarg.h>
# define REALLOC(ptr, size) realloc(ptr, size)
# else /* __STDC__ */
# include <varargs.h>
/* define a realloc() which works for NULL pointers */
# define REALLOC(ptr, size) (((ptr) == NULL) ? malloc(size) : realloc(ptr, size))
# endif /* __STDC__ */
# if (defined(sun) && defined(__svr4__)) || defined(__SVR4)
# define USE_LOCKF 1
# define USE_SETEUID 1
# define _PATH_MAILDIR "/var/mail"
# endif /* (defined(sun) && defined(__svr4__)) || defined(__SVR4) */
# ifdef NCR_MP_RAS3
# define USE_LOCKF 1
# define HASSNPRINTF 1
# define _PATH_MAILDIR "/var/mail"
# endif /* NCR_MP_RAS3 */
# if defined(_AIX)
# define USE_LOCKF 1
# define USE_SETEUID 1
# define USE_VSYSLOG 0
# endif /* defined(_AIX) */
# if defined(__hpux)
# define USE_LOCKF 1
# define USE_SETRESUID 1
# define USE_VSYSLOG 0
# endif /* defined(__hpux) */
# ifdef DGUX
# define HASSNPRINTF 1
# define USE_LOCKF 1
# define USE_VSYSLOG 0
# endif /* DGUX */
# if defined(_CRAY)
# if !defined(MAXPATHLEN)
# define MAXPATHLEN PATHSIZE
# endif /* !defined(MAXPATHLEN) */
# define USE_VSYSLOG 0
# define _PATH_MAILDIR "/usr/spool/mail"
# endif /* defined(_CRAY) */
# if defined(ultrix)
# define USE_VSYSLOG 0
# endif /* defined(ultrix) */
# if defined(__osf__)
# define USE_VSYSLOG 0
# endif /* defined(__osf__) */
# if defined(NeXT) && !defined(__APPLE__)
# include <libc.h>
# define _PATH_MAILDIR "/usr/spool/mail"
# define S_IRUSR S_IREAD
# define S_IWUSR S_IWRITE
# endif /* defined(NeXT) && !defined(__APPLE__) */
# if defined(IRIX64) || defined(IRIX5) || defined(IRIX6)
# include <paths.h>
# endif /* defined(IRIX64) || defined(IRIX5) || defined(IRIX6) */
/*
* If you don't have flock, you could try using lockf instead.
*/
# ifdef USE_LOCKF
# define flock(a, b) lockf(a, b, 0)
# ifdef LOCK_EX
# undef LOCK_EX
# endif /* LOCK_EX */
# define LOCK_EX F_LOCK
# endif /* USE_LOCKF */
# ifndef USE_VSYSLOG
# define USE_VSYSLOG 1
# endif /* ! USE_VSYSLOG */
# ifndef LOCK_EX
# include <sys/file.h>
# endif /* ! LOCK_EX */
# if defined(BSD4_4) || defined(__GLIBC__)
# include <paths.h>
# define _PATH_LOCTMP "/tmp/local.XXXXXX"
# endif /* defined(BSD4_4) || defined(__GLIBC__) */
# ifdef BSD4_4
# define HAS_ST_GEN 1
# else /* BSD4_4 */
# ifndef _BSD_VA_LIST_
# define _BSD_VA_LIST_ va_list
# endif /* ! _BSD_VA_LIST_ */
# endif /* BSD4_4 */
# if defined(BSD4_4) || defined(linux)
# define HASSNPRINTF 1
# else /* defined(BSD4_4) || defined(linux) */
# ifndef ultrix
extern FILE *fdopen __P((int, const char *));
# endif /* ! ultrix */
# endif /* defined(BSD4_4) || defined(linux) */
# if SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203)
# define CONTENTLENGTH 1 /* Needs the Content-Length header */
# endif /* SOLARIS >= 20300 || (SOLARIS < 10000 && SOLARIS >= 203) */
# if SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206)
# define HASSNPRINTF 1 /* has snprintf starting in 2.6 */
# endif /* SOLARIS >= 20600 || (SOLARIS < 10000 && SOLARIS >= 206) */
# ifdef HPUX11
# define HASSNPRINTF 1 /* has snprintf starting in 11.X */
# endif /* HPUX11 */
# if _AIX4 >= 40300
# define HASSNPRINTF 1 /* has snprintf starting in 4.3 */
# endif /* _AIX4 >= 40300 */
# if !HASSNPRINTF
extern int snprintf __P((char *, size_t, const char *, ...));
# ifndef _CRAY
extern int vsnprintf __P((char *, size_t, const char *, ...));
# endif /* ! _CRAY */
# endif /* !HASSNPRINTF */
/*
** If you don't have setreuid, and you have saved uids, and you have
** a seteuid() call that doesn't try to emulate using setuid(), then
** you can try defining USE_SETEUID.
*/
# ifdef USE_SETEUID
# define setreuid(r, e) seteuid(e)
# endif /* USE_SETEUID */
/*
** And of course on hpux you have setresuid()
*/
# ifdef USE_SETRESUID
# define setreuid(r, e) setresuid(-1, e, -1)
# endif /* USE_SETRESUID */
# ifndef _PATH_LOCTMP
# define _PATH_LOCTMP "/tmp/local.XXXXXX"
# endif /* ! _PATH_LOCTMP */
# ifndef _PATH_MAILDIR
# define _PATH_MAILDIR "/var/spool/mail"
# endif /* ! _PATH_MAILDIR */
# ifndef S_ISREG
# define S_ISREG(mode) (((mode) & _S_IFMT) == S_IFREG)
# endif /* ! S_ISREG */
# ifdef MAILLOCK
# include <maillock.h>
# endif /* MAILLOCK */
# define U_UID pw->pw_uid
# define U_GID pw->pw_gid
#ifndef INADDRSZ
# define INADDRSZ 4 /* size of an IPv4 address in bytes */
#endif /* ! INADDRSZ */
#ifndef MAILER_DAEMON
# define MAILER_DAEMON "MAILER-DAEMON"
#endif /* ! MAILER_DAEMON */
#ifdef CONTENTLENGTH
char ContentHdr[40] = "Content-Length: ";
off_t HeaderLength;
off_t BodyLength;
#endif /* CONTENTLENGTH */
bool EightBitMime = TRUE; /* advertise 8BITMIME in LMTP */
int ExitVal = EX_OK; /* sysexits.h error value. */
bool LMTPMode = FALSE;
bool bouncequota = FALSE; /* permanent error when over quota */
void deliver __P((int, char *, bool));
int e_to_sys __P((int));
void notifybiff __P((char *));
int store __P((char *, int));
void usage __P((void));
void vwarn __P((const char *, _BSD_VA_LIST_));
int lockmbox __P((char *));
void unlockmbox __P((void));
void mailerr __P((const char *, const char *, ...));
int
main(argc, argv)
int argc;
char *argv[];
{
struct passwd *pw;
int ch, fd;
uid_t uid;
char *from;
extern char *optarg;
extern int optind;
extern void dolmtp __P((bool));
/* make sure we have some open file descriptors */
for (fd = 10; fd < 30; fd++)
(void) close(fd);
/* use a reasonable umask */
(void) umask(0077);
# ifdef LOG_MAIL
openlog("mail.local", 0, LOG_MAIL);
# else /* LOG_MAIL */
openlog("mail.local", 0);
# endif /* LOG_MAIL */
from = NULL;
while ((ch = getopt(argc, argv, "7bdf:r:l")) != -1)
{
switch(ch)
{
case '7': /* Do not advertise 8BITMIME */
EightBitMime = FALSE;
break;
case 'b': /* bounce mail when over quota. */
bouncequota = TRUE;
break;
case 'd': /* Backward compatible. */
break;
case 'f':
case 'r': /* Backward compatible. */
if (from != NULL)
{
mailerr(NULL, "multiple -f options");
usage();
}
from = optarg;
break;
case 'l':
LMTPMode = TRUE;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
/* initialize biff structures */
notifybiff(NULL);
if (LMTPMode)
dolmtp(bouncequota);
if (*argv == '\0')
usage();
/*
** If from not specified, use the name from getlogin() if the
** uid matches, otherwise, use the name from the password file
** corresponding to the uid.
*/
uid = getuid();
if (from == NULL && ((from = getlogin()) == NULL ||
(pw = getpwnam(from)) == NULL ||
pw->pw_uid != uid))
from = (pw = getpwuid(uid)) != NULL ? pw->pw_name : "???";
/*
** There is no way to distinguish the error status of one delivery
** from the rest of the deliveries. So, if we failed hard on one
** or more deliveries, but had no failures on any of the others, we
** return a hard failure. If we failed temporarily on one or more
** deliveries, we return a temporary failure regardless of the other
** failures. This results in the delivery being reattempted later
** at the expense of repeated failures and multiple deliveries.
*/
for (fd = store(from, 0); *argv; ++argv)
deliver(fd, *argv, bouncequota);
exit(ExitVal);
/* NOTREACHED */
return ExitVal;
}
char *
parseaddr(s, rcpt)
char *s;
bool rcpt;
{
char *p;
int l;
if (*s++ != '<')
return NULL;
p = s;
/* at-domain-list */
while (*p == '@')
{
p++;
while (*p != ',' && *p != ':' && *p != '\0')
p++;
if (*p == '\0')
return NULL;
/* Skip over , or : */
p++;
}
s = p;
/* local-part */
while (*p != '\0' && *p != '@' && *p != '>')
{
if (*p == '\\')
{
if (*++p == '\0')
return NULL;
}
else if (*p == '\"')
{
p++;
while (*p != '\0' && *p != '\"')
{
if (*p == '\\')
{
if (*++p == '\0')
return NULL;
}
p++;
}
if (*p == '\0' || *(p + 1) == '\0')
return NULL;
}
/* +detail ? */
if (*p == '+' && rcpt)
*p = '\0';
p++;
}
/* @domain */
if (*p == '@')
{
if (rcpt)
*p++ = '\0';
while (*p != '\0' && *p != '>')
p++;
}
if (*p != '>')
return NULL;
else
*p = '\0';
p++;
if (*p != '\0' && *p != ' ')
return NULL;
if (*s == '\0')
s = MAILER_DAEMON;
l = strlen(s) + 1;
p = malloc(l);
if (p == NULL)
{
printf("421 4.3.0 memory exhausted\r\n");
exit(EX_TEMPFAIL);
}
(void) strlcpy(p, s, l);
return p;
}
char *
process_recipient(addr)
char *addr;
{
if (getpwnam(addr) == NULL)
return "550 5.1.1 user unknown";
return NULL;
}
#define RCPT_GROW 30
void
dolmtp(bouncequota)
bool bouncequota;
{
char *return_path = NULL;
char **rcpt_addr = NULL;
int rcpt_num = 0;
int rcpt_alloc = 0;
bool gotlhlo = FALSE;
char *err;
int msgfd;
char *p;
int i;
char myhostname[1024];
char buf[4096];
(void) gethostname(myhostname, sizeof myhostname - 1);
printf("220 %s LMTP ready\r\n", myhostname);
for (;;)
{
(void) fflush(stdout);
if (fgets(buf, sizeof(buf) - 1, stdin) == NULL)
exit(EX_OK);
p = buf + strlen(buf) - 1;
if (p >= buf && *p == '\n')
*p-- = '\0';
if (p >= buf && *p == '\r')
*p-- = '\0';
switch (buf[0])
{
case 'd':
case 'D':
if (strcasecmp(buf, "data") == 0)
{
if (rcpt_num == 0)
{
printf("503 5.5.1 No recipients\r\n");
continue;
}
msgfd = store(return_path, rcpt_num);
if (msgfd == -1)
continue;
for (i = 0; i < rcpt_num; i++)
{
p = strchr(rcpt_addr[i], '+');
if (p != NULL)
*p++ = '\0';
deliver(msgfd, rcpt_addr[i],
bouncequota);
}
(void) close(msgfd);
goto rset;
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'l':
case 'L':
if (strncasecmp(buf, "lhlo ", 5) == 0)
{
/* check for duplicate per RFC 1651 4.2 */
if (gotlhlo)
{
printf("503 %s Duplicate LHLO\r\n",
myhostname);
continue;
}
gotlhlo = TRUE;
printf("250-%s\r\n", myhostname);
if (EightBitMime)
printf("250-8BITMIME\r\n");
printf("250-ENHANCEDSTATUSCODES\r\n");
printf("250 PIPELINING\r\n");
continue;
}
goto syntaxerr;
/* NOTREACHED */
break;
case 'm':
case 'M':
if (strncasecmp(buf, "mail ", 5) == 0)
{
if (return_path != NULL)
{
printf("503 5.5.1 Nested MAIL command\r\n");
continue;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -