vacation.c

来自「< linux网络编程工具>>配套源码」· C语言 代码 · 共 1,069 行 · 第 1/2 页

C
1,069
字号
/*
 * Copyright (c) 1999-2000 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 * Copyright (c) 1983, 1987, 1993
 *	The Regents of the University of California.  All rights reserved.
 * Copyright (c) 1983 Eric P. Allman.  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) 1983, 1987, 1993\n\
	The Regents of the University of California.  All rights reserved.\n\
     Copyright (c) 1983 Eric P. Allman.  All rights reserved.\n";
#endif /* ! lint */

#ifndef lint
static char id[] = "@(#)$Id: vacation.c,v 8.68.4.7 2000/09/05 21:48:45 gshapiro Exp $";
#endif /* ! lint */

#include <ctype.h>
#include <stdlib.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 "sendmail/sendmail.h"
#include "libsmdb/smdb.h"

#if defined(__hpux) && !defined(HPUX11)
# undef syslog		/* Undo hard_syslog conf.h change */
#endif /* defined(__hpux) && !defined(HPUX11) */

#ifndef _PATH_SENDMAIL
# define _PATH_SENDMAIL "/usr/lib/sendmail"
#endif /* ! _PATH_SENDMAIL */

#define ONLY_ONCE	((time_t) 0)	/* send at most one reply */
#define INTERVAL_UNDEF	((time_t) (-1))	/* no value given */

uid_t	RealUid;
gid_t	RealGid;
char	*RealUserName;
uid_t	RunAsUid;
uid_t	RunAsGid;
char	*RunAsUserName;
int	Verbose = 2;
bool	DontInitGroups = FALSE;
uid_t	TrustedUid = 0;
BITMAP256 DontBlameSendmail;

/*
**  VACATION -- return a message to the sender when on vacation.
**
**	This program is invoked as a message receiver.  It returns a
**	message specified by the user to whomever sent the mail, taking
**	care not to return a message too often to prevent "I am on
**	vacation" loops.
*/

#define	VDB	".vacation"		/* vacation database */
#define	VMSG	".vacation.msg"		/* vacation message */
#define SECSPERDAY	(60 * 60 * 24)
#define DAYSPERWEEK	7

#ifndef TRUE
# define TRUE	1
# define FALSE	0
#endif /* ! TRUE */

#ifndef __P
# ifdef __STDC__
#  define __P(protos)	protos
# else /* __STDC__ */
#  define __P(protos)	()
#  define const
# endif /* __STDC__ */
#endif /* ! __P */

typedef struct alias
{
	char *name;
	struct alias *next;
} ALIAS;

ALIAS *Names = NULL;

SMDB_DATABASE *Db;

char From[MAXLINE];

#if _FFR_DEBUG
void (*msglog)(int, const char *, ...) = &syslog;
static void debuglog __P((int, const char *, ...));
#else /* _FFR_DEBUG */
# define msglog		syslog
#endif /* _FFR_DEBUG */

static void eatmsg __P((void));

/* exit after reading input */
#define EXITIT(excode)	{ \
				eatmsg(); \
				exit(excode); \
			}
int
main(argc, argv)
	int argc;
	char **argv;
{
	bool iflag, emptysender, exclude;
#if _FFR_LISTDB
	bool lflag = FALSE;
#endif /* _FFR_LISTDB */
	int mfail = 0, ufail = 0;
	int ch;
	int result;
	long sff;
	time_t interval;
	struct passwd *pw;
	ALIAS *cur;
	char *dbfilename = VDB;
	char *msgfilename = VMSG;
	char *name;
	SMDB_USER_INFO user_info;
	static char rnamebuf[MAXNAME];
	extern int optind, opterr;
	extern char *optarg;
	extern void usage __P((void));
	extern void setinterval __P((time_t));
	extern void readheaders __P((void));
	extern bool recent __P((void));
	extern void setreply __P((char *, time_t));
	extern void sendmessage __P((char *, char *, bool));
	extern void xclude __P((FILE *));
#if _FFR_LISTDB
#define EXITM(excode)	{ \
				if (!iflag && !lflag) \
					eatmsg(); \
				exit(excode); \
			}
#else /* _FFR_LISTDB */
#define EXITM(excode)	{ \
				if (!iflag) \
					eatmsg(); \
				exit(excode); \
			}
#endif /* _FFR_LISTDB */

	/* Vars needed to link with smutil */
	clrbitmap(DontBlameSendmail);
	RunAsUid = RealUid = getuid();
	RunAsGid = RealGid = getgid();
	pw = getpwuid(RealUid);
	if (pw != NULL)
	{
		if (strlen(pw->pw_name) > MAXNAME - 1)
			pw->pw_name[MAXNAME] = '\0';
		snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
	}
	else
		snprintf(rnamebuf, sizeof rnamebuf,
			 "Unknown UID %d", (int) RealUid);
	RunAsUserName = RealUserName = rnamebuf;

#ifdef LOG_MAIL
	openlog("vacation", LOG_PID, LOG_MAIL);
#else /* LOG_MAIL */
	openlog("vacation", LOG_PID);
#endif /* LOG_MAIL */

	opterr = 0;
	iflag = FALSE;
	emptysender = FALSE;
	exclude = FALSE;
	interval = INTERVAL_UNDEF;
	*From = '\0';

#if _FFR_DEBUG && _FFR_LISTDB
# define OPTIONS		"a:df:Iilm:r:s:t:xz"
#else /* _FFR_DEBUG && _FFR_LISTDB */
# if _FFR_DEBUG
#  define OPTIONS		"a:df:Iim:r:s:t:xz"
# else /* _FFR_DEBUG */
#  if _FFR_LISTDB
#   define OPTIONS		"a:f:Iilm:r:s:t:xz"
#  else /* _FFR_LISTDB */
#   define OPTIONS		"a:f:Iim:r:s:t:xz"
#  endif /* _FFR_LISTDB */
# endif /* _FFR_DEBUG */
#endif /* _FFR_DEBUG && _FFR_LISTDB */

	while (mfail == 0 && ufail == 0 &&
	       (ch = getopt(argc, argv, OPTIONS)) != -1)
	{
		switch((char)ch)
		{
		  case 'a':			/* alias */
			cur = (ALIAS *)malloc((u_int)sizeof(ALIAS));
			if (cur == NULL)
			{
				mfail++;
				break;
			}
			cur->name = optarg;
			cur->next = Names;
			Names = cur;
			break;

#if _FFR_DEBUG
		case 'd':			/* debug mode */
			msglog = &debuglog;
			break;
#endif /* _FFR_DEBUG */


		  case 'f':		/* alternate database */
			dbfilename = optarg;
			break;

		  case 'I':			/* backward compatible */
		  case 'i':			/* init the database */
			iflag = TRUE;
			break;

#if _FFR_LISTDB
		  case 'l':
			lflag = TRUE;		/* list the database */
			break;
#endif /* _FFR_LISTDB */

		  case 'm':		/* alternate message file */
			msgfilename = optarg;
			break;

		  case 'r':
			if (isascii(*optarg) && isdigit(*optarg))
			{
				interval = atol(optarg) * SECSPERDAY;
				if (interval < 0)
					ufail++;
			}
			else
				interval = ONLY_ONCE;
			break;

		  case 's':		/* alternate sender name */
			(void) strlcpy(From, optarg, sizeof From);
			break;

		  case 't':		/* SunOS: -t1d (default expire) */
			break;

		  case 'x':
			exclude = TRUE;
			break;

		  case 'z':
			emptysender = TRUE;
			break;

		  case '?':
		  default:
			ufail++;
			break;
		}
	}
	argc -= optind;
	argv += optind;

	if (mfail != 0)
	{
		msglog(LOG_NOTICE,
		       "vacation: can't allocate memory for alias.\n");
		EXITM(EX_TEMPFAIL);
	}
	if (ufail != 0)
		usage();

	if (argc != 1)
	{
		if (!iflag &&
#if _FFR_LISTDB
		    !lflag &&
#endif /* _FFR_LISTDB */
		    !exclude)
			usage();
		if ((pw = getpwuid(getuid())) == NULL)
		{
			msglog(LOG_ERR,
			       "vacation: no such user uid %u.\n", getuid());
			EXITM(EX_NOUSER);
		}
	}
#if _FFR_BLACKBOX
	name = *argv;
#else /* _FFR_BLACKBOX */
	else if ((pw = getpwnam(*argv)) == NULL)
	{
		msglog(LOG_ERR, "vacation: no such user %s.\n", *argv);
		EXITM(EX_NOUSER);
	}
	name = pw->pw_name;
	if (chdir(pw->pw_dir) != 0)
	{
		msglog(LOG_NOTICE,
		       "vacation: no such directory %s.\n", pw->pw_dir);
		EXITM(EX_NOINPUT);
	}
#endif /* _FFR_BLACKBOX */
	user_info.smdbu_id = pw->pw_uid;
	user_info.smdbu_group_id = pw->pw_gid;
	(void) strlcpy(user_info.smdbu_name, pw->pw_name,
		       SMDB_MAX_USER_NAME_LEN);

	sff = SFF_CREAT;
#if _FFR_BLACKBOX
	if (getegid() != getgid())
		RunAsGid = user_info.smdbu_group_id = getegid();

	sff |= SFF_NOPATHCHECK|SFF_OPENASROOT;
#endif /* _FFR_BLACKBOX */

	result = smdb_open_database(&Db, dbfilename,
				    O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0),
				    S_IRUSR|S_IWUSR, sff,
				    SMDB_TYPE_DEFAULT, &user_info, NULL);
	if (result != SMDBE_OK)
	{
		msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename,
		       errstring(result));
		EXITM(EX_DATAERR);
	}

#if _FFR_LISTDB
	if (lflag)
	{
		static void listdb __P((void));

		listdb();
		(void)Db->smdb_close(Db);
		exit(EX_OK);
	}
#endif /* _FFR_LISTDB */

	if (interval != INTERVAL_UNDEF)
		setinterval(interval);

	if (iflag)
	{
		result = Db->smdb_close(Db);
		if (!exclude)
			exit(EX_OK);
	}

	if (exclude)
	{
		xclude(stdin);
		result = Db->smdb_close(Db);
		EXITM(EX_OK);
	}

	if ((cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))) == NULL)
	{
		msglog(LOG_NOTICE,
		       "vacation: can't allocate memory for username.\n");
		EXITM(EX_OSERR);
	}
	cur->name = name;
	cur->next = Names;
	Names = cur;

	readheaders();
	if (!recent())
	{
		time_t now;

		(void) time(&now);
		setreply(From, now);
		result = Db->smdb_close(Db);
		sendmessage(name, msgfilename, emptysender);
	}
	else
		result = Db->smdb_close(Db);
	exit(EX_OK);
	/* NOTREACHED */
	return EX_OK;
}

/*
** EATMSG -- read stdin till EOF
**
**	Parameters:
**		none.
**
**	Returns:
**		nothing.
**
*/
static void
eatmsg()
{
	/*
	**  read the rest of the e-mail and ignore it to avoid problems
	**  with EPIPE in sendmail
	*/
	while (getc(stdin) != EOF)
		continue;
}

/*
** READHEADERS -- read mail headers
**
**	Parameters:
**		none.
**
**	Returns:
**		nothing.
**
**	Side Effects:
**		may exit().
**
*/
void
readheaders()
{
	bool tome, cont;
	register char *p;
	register ALIAS *cur;
	char buf[MAXLINE];
	extern bool junkmail __P((char *));
	extern bool nsearch __P((char *, char *));

	cont = tome = FALSE;
	while (fgets(buf, sizeof(buf), stdin) && *buf != '\n')
	{
		switch(*buf)
		{
		  case 'F':		/* "From " */
			cont = FALSE;
			if (strncmp(buf, "From ", 5) == 0)
			{
				bool quoted = FALSE;

				p = buf + 5;
				while (*p != '\0')
				{
					/* escaped character */
					if (*p == '\\')
					{
						p++;
						if (*p == '\0')
						{
							msglog(LOG_NOTICE,
							       "vacation: badly formatted \"From \" line.\n");
							EXITIT(EX_DATAERR);
						}
					}
					else if (*p == '"')
						quoted = !quoted;
					else if (*p == '\r' || *p == '\n')
						break;
					else if (*p == ' ' && !quoted)
						break;
					p++;
				}
				if (quoted)
				{
					msglog(LOG_NOTICE,
					       "vacation: badly formatted \"From \" line.\n");
					EXITIT(EX_DATAERR);
				}
				*p = '\0';

				/* ok since both strings have MAXLINE length */
				if (*From == '\0')
					(void)strlcpy(From, buf + 5,
						      sizeof From);
				if ((p = strchr(buf + 5, '\n')) != NULL)
					*p = '\0';
				if (junkmail(buf + 5))
					EXITIT(EX_OK);
			}
			break;

		  case 'P':		/* "Precedence:" */
		  case 'p':
			cont = FALSE;
			if (strlen(buf) <= 10 ||
			    strncasecmp(buf, "Precedence", 10) != 0 ||
			    (buf[10] != ':' && buf[10] != ' ' &&
			     buf[10] != '\t'))
				break;
			if ((p = strchr(buf, ':')) == NULL)
				break;
			while (*++p != '\0' && isascii(*p) && isspace(*p));
			if (*p == '\0')
				break;
			if (strncasecmp(p, "junk", 4) == 0 ||
			    strncasecmp(p, "bulk", 4) == 0 ||
			    strncasecmp(p, "list", 4) == 0)
				EXITIT(EX_OK);
			break;

		  case 'C':		/* "Cc:" */
		  case 'c':
			if (strncasecmp(buf, "Cc:", 3) != 0)
				break;
			cont = TRUE;
			goto findme;

		  case 'T':		/* "To:" */
		  case 't':
			if (strncasecmp(buf, "To:", 3) != 0)
				break;
			cont = TRUE;
			goto findme;

		  default:
			if (!isascii(*buf) || !isspace(*buf) || !cont || tome)
			{
				cont = FALSE;
				break;
			}
findme:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?