vacation.c revision 132943
164562Sgshapiro/*
294334Sgshapiro * Copyright (c) 1999-2002 Sendmail, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
464562Sgshapiro * Copyright (c) 1983, 1987, 1993
564562Sgshapiro *	The Regents of the University of California.  All rights reserved.
664562Sgshapiro * Copyright (c) 1983 Eric P. Allman.  All rights reserved.
764562Sgshapiro *
864562Sgshapiro * By using this file, you agree to the terms and conditions set
964562Sgshapiro * forth in the LICENSE file which can be found at the top level of
1064562Sgshapiro * the sendmail distribution.
1164562Sgshapiro *
1264562Sgshapiro */
1364562Sgshapiro
1490792Sgshapiro#include <sm/gen.h>
1590792Sgshapiro
1690792SgshapiroSM_IDSTR(copyright,
1777349Sgshapiro"@(#) Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.\n\
1864562Sgshapiro	All rights reserved.\n\
1964562Sgshapiro     Copyright (c) 1983, 1987, 1993\n\
2064562Sgshapiro	The Regents of the University of California.  All rights reserved.\n\
2190792Sgshapiro     Copyright (c) 1983 Eric P. Allman.  All rights reserved.\n")
2264562Sgshapiro
23132943SgshapiroSM_IDSTR(id, "@(#)$Id: vacation.c,v 8.141 2002/11/01 16:49:40 ca Exp $")
2464562Sgshapiro
2577349Sgshapiro
2664562Sgshapiro#include <ctype.h>
2764562Sgshapiro#include <stdlib.h>
2864562Sgshapiro#include <syslog.h>
2964562Sgshapiro#include <time.h>
3064562Sgshapiro#include <unistd.h>
3164562Sgshapiro#ifdef EX_OK
3264562Sgshapiro# undef EX_OK		/* unistd.h may have another use for this */
3364562Sgshapiro#endif /* EX_OK */
3490792Sgshapiro#include <sm/sysexits.h>
3564562Sgshapiro
3690792Sgshapiro#include <sm/cf.h>
3790792Sgshapiro#include <sm/mbdb.h>
3864562Sgshapiro#include "sendmail/sendmail.h"
3990792Sgshapiro#include <sendmail/pathnames.h>
4064562Sgshapiro#include "libsmdb/smdb.h"
4164562Sgshapiro
4264562Sgshapiro#define ONLY_ONCE	((time_t) 0)	/* send at most one reply */
4364562Sgshapiro#define INTERVAL_UNDEF	((time_t) (-1))	/* no value given */
4464562Sgshapiro
4564562Sgshapirouid_t	RealUid;
4664562Sgshapirogid_t	RealGid;
4764562Sgshapirochar	*RealUserName;
4864562Sgshapirouid_t	RunAsUid;
4964562Sgshapirouid_t	RunAsGid;
5064562Sgshapirochar	*RunAsUserName;
5164562Sgshapiroint	Verbose = 2;
5290792Sgshapirobool	DontInitGroups = false;
5364562Sgshapirouid_t	TrustedUid = 0;
5464562SgshapiroBITMAP256 DontBlameSendmail;
5564562Sgshapiro
5664562Sgshapiro/*
5764562Sgshapiro**  VACATION -- return a message to the sender when on vacation.
5864562Sgshapiro**
5964562Sgshapiro**	This program is invoked as a message receiver.  It returns a
6064562Sgshapiro**	message specified by the user to whomever sent the mail, taking
6164562Sgshapiro**	care not to return a message too often to prevent "I am on
6264562Sgshapiro**	vacation" loops.
6364562Sgshapiro*/
6464562Sgshapiro
6564562Sgshapiro#define	VDB	".vacation"		/* vacation database */
6664562Sgshapiro#define	VMSG	".vacation.msg"		/* vacation message */
6764562Sgshapiro#define SECSPERDAY	(60 * 60 * 24)
6864562Sgshapiro#define DAYSPERWEEK	7
6964562Sgshapiro
7064562Sgshapirotypedef struct alias
7164562Sgshapiro{
7264562Sgshapiro	char *name;
7364562Sgshapiro	struct alias *next;
7464562Sgshapiro} ALIAS;
7564562Sgshapiro
7664562SgshapiroALIAS *Names = NULL;
7764562Sgshapiro
7864562SgshapiroSMDB_DATABASE *Db;
7964562Sgshapiro
8064562Sgshapirochar From[MAXLINE];
8164562Sgshapiro
8290792Sgshapiro#if defined(__hpux) || defined(__osf__)
8390792Sgshapiro# ifndef SM_CONF_SYSLOG_INT
8490792Sgshapiro#  define SM_CONF_SYSLOG_INT	1
8590792Sgshapiro# endif /* SM_CONF_SYSLOG_INT */
8690792Sgshapiro#endif /* defined(__hpux) || defined(__osf__) */
8764562Sgshapiro
8890792Sgshapiro#if SM_CONF_SYSLOG_INT
8990792Sgshapiro# define SYSLOG_RET_T	int
9090792Sgshapiro# define SYSLOG_RET	return 0
9190792Sgshapiro#else /* SM_CONF_SYSLOG_INT */
9290792Sgshapiro# define SYSLOG_RET_T	void
9390792Sgshapiro# define SYSLOG_RET
9490792Sgshapiro#endif /* SM_CONF_SYSLOG_INT */
9590792Sgshapiro
9690792Sgshapirotypedef SYSLOG_RET_T SYSLOG_T __P((int, const char *, ...));
9790792SgshapiroSYSLOG_T *msglog = syslog;
9890792Sgshapirostatic SYSLOG_RET_T debuglog __P((int, const char *, ...));
9966494Sgshapirostatic void eatmsg __P((void));
10090792Sgshapirostatic void listdb __P((void));
10166494Sgshapiro
10266494Sgshapiro/* exit after reading input */
10390792Sgshapiro#define EXITIT(excode) \
10490792Sgshapiro{ \
10590792Sgshapiro	eatmsg(); \
10690792Sgshapiro	return excode; \
10790792Sgshapiro}
10877349Sgshapiro
10990792Sgshapiro#define EXITM(excode) \
11090792Sgshapiro{ \
11198121Sgshapiro	if (!initdb && !list) \
11290792Sgshapiro		eatmsg(); \
11390792Sgshapiro	exit(excode); \
11490792Sgshapiro}
11590792Sgshapiro
11664562Sgshapiroint
11764562Sgshapiromain(argc, argv)
11864562Sgshapiro	int argc;
11964562Sgshapiro	char **argv;
12064562Sgshapiro{
12198121Sgshapiro	bool alwaysrespond = false;
12298121Sgshapiro	bool initdb, exclude;
12390792Sgshapiro	bool runasuser = false;
12498121Sgshapiro	bool list = false;
12564562Sgshapiro	int mfail = 0, ufail = 0;
12664562Sgshapiro	int ch;
12764562Sgshapiro	int result;
12866494Sgshapiro	long sff;
12964562Sgshapiro	time_t interval;
13064562Sgshapiro	struct passwd *pw;
13164562Sgshapiro	ALIAS *cur;
13277349Sgshapiro	char *dbfilename = NULL;
13377349Sgshapiro	char *msgfilename = NULL;
13490792Sgshapiro	char *cfpath = NULL;
13564562Sgshapiro	char *name;
13690792Sgshapiro	char *returnaddr = NULL;
13764562Sgshapiro	SMDB_USER_INFO user_info;
13864562Sgshapiro	static char rnamebuf[MAXNAME];
13964562Sgshapiro	extern int optind, opterr;
14064562Sgshapiro	extern char *optarg;
14164562Sgshapiro	extern void usage __P((void));
14264562Sgshapiro	extern void setinterval __P((time_t));
14398121Sgshapiro	extern int readheaders __P((bool));
14464562Sgshapiro	extern bool recent __P((void));
14564562Sgshapiro	extern void setreply __P((char *, time_t));
14690792Sgshapiro	extern void sendmessage __P((char *, char *, char *));
14790792Sgshapiro	extern void xclude __P((SM_FILE_T *));
14864562Sgshapiro
14964562Sgshapiro	/* Vars needed to link with smutil */
15064562Sgshapiro	clrbitmap(DontBlameSendmail);
15164562Sgshapiro	RunAsUid = RealUid = getuid();
15264562Sgshapiro	RunAsGid = RealGid = getgid();
15364562Sgshapiro	pw = getpwuid(RealUid);
15464562Sgshapiro	if (pw != NULL)
15564562Sgshapiro	{
15664562Sgshapiro		if (strlen(pw->pw_name) > MAXNAME - 1)
15764562Sgshapiro			pw->pw_name[MAXNAME] = '\0';
15890792Sgshapiro		sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name);
15964562Sgshapiro	}
16064562Sgshapiro	else
16190792Sgshapiro		sm_snprintf(rnamebuf, sizeof rnamebuf,
16290792Sgshapiro			    "Unknown UID %d", (int) RealUid);
16364562Sgshapiro	RunAsUserName = RealUserName = rnamebuf;
16464562Sgshapiro
16577349Sgshapiro# ifdef LOG_MAIL
16664562Sgshapiro	openlog("vacation", LOG_PID, LOG_MAIL);
16777349Sgshapiro# else /* LOG_MAIL */
16864562Sgshapiro	openlog("vacation", LOG_PID);
16977349Sgshapiro# endif /* LOG_MAIL */
17064562Sgshapiro
17164562Sgshapiro	opterr = 0;
17298121Sgshapiro	initdb = false;
17390792Sgshapiro	exclude = false;
17464562Sgshapiro	interval = INTERVAL_UNDEF;
17564562Sgshapiro	*From = '\0';
17664562Sgshapiro
17764562Sgshapiro
17898121Sgshapiro#define OPTIONS	"a:C:df:Iijlm:R:r:s:t:Uxz"
17990792Sgshapiro
18064562Sgshapiro	while (mfail == 0 && ufail == 0 &&
18164562Sgshapiro	       (ch = getopt(argc, argv, OPTIONS)) != -1)
18264562Sgshapiro	{
18364562Sgshapiro		switch((char)ch)
18464562Sgshapiro		{
18564562Sgshapiro		  case 'a':			/* alias */
18690792Sgshapiro			cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS));
18764562Sgshapiro			if (cur == NULL)
18864562Sgshapiro			{
18964562Sgshapiro				mfail++;
19064562Sgshapiro				break;
19164562Sgshapiro			}
19264562Sgshapiro			cur->name = optarg;
19364562Sgshapiro			cur->next = Names;
19464562Sgshapiro			Names = cur;
19564562Sgshapiro			break;
19664562Sgshapiro
19790792Sgshapiro		  case 'C':
19890792Sgshapiro			cfpath = optarg;
19990792Sgshapiro			break;
20090792Sgshapiro
20177349Sgshapiro		  case 'd':			/* debug mode */
20290792Sgshapiro			msglog = debuglog;
20364562Sgshapiro			break;
20464562Sgshapiro
20564562Sgshapiro		  case 'f':		/* alternate database */
20664562Sgshapiro			dbfilename = optarg;
20764562Sgshapiro			break;
20864562Sgshapiro
20964562Sgshapiro		  case 'I':			/* backward compatible */
21064562Sgshapiro		  case 'i':			/* init the database */
21198121Sgshapiro			initdb = true;
21264562Sgshapiro			break;
21364562Sgshapiro
21498121Sgshapiro		  case 'j':
21598121Sgshapiro			alwaysrespond = true;
21698121Sgshapiro			break;
21798121Sgshapiro
21864562Sgshapiro		  case 'l':
21998121Sgshapiro			list = true;		/* list the database */
22064562Sgshapiro			break;
22164562Sgshapiro
22264562Sgshapiro		  case 'm':		/* alternate message file */
22364562Sgshapiro			msgfilename = optarg;
22464562Sgshapiro			break;
22564562Sgshapiro
22690792Sgshapiro		  case 'R':
22790792Sgshapiro			returnaddr = optarg;
22890792Sgshapiro			break;
22990792Sgshapiro
23064562Sgshapiro		  case 'r':
23164562Sgshapiro			if (isascii(*optarg) && isdigit(*optarg))
23264562Sgshapiro			{
23364562Sgshapiro				interval = atol(optarg) * SECSPERDAY;
23464562Sgshapiro				if (interval < 0)
23564562Sgshapiro					ufail++;
23664562Sgshapiro			}
23764562Sgshapiro			else
23864562Sgshapiro				interval = ONLY_ONCE;
23964562Sgshapiro			break;
24064562Sgshapiro
24164562Sgshapiro		  case 's':		/* alternate sender name */
24290792Sgshapiro			(void) sm_strlcpy(From, optarg, sizeof From);
24364562Sgshapiro			break;
24464562Sgshapiro
24564562Sgshapiro		  case 't':		/* SunOS: -t1d (default expire) */
24664562Sgshapiro			break;
24764562Sgshapiro
24877349Sgshapiro		  case 'U':		/* run as single user mode */
24990792Sgshapiro			runasuser = true;
25077349Sgshapiro			break;
25177349Sgshapiro
25264562Sgshapiro		  case 'x':
25390792Sgshapiro			exclude = true;
25464562Sgshapiro			break;
25564562Sgshapiro
25664562Sgshapiro		  case 'z':
25790792Sgshapiro			returnaddr = "<>";
25864562Sgshapiro			break;
25964562Sgshapiro
26064562Sgshapiro		  case '?':
26164562Sgshapiro		  default:
26264562Sgshapiro			ufail++;
26364562Sgshapiro			break;
26464562Sgshapiro		}
26564562Sgshapiro	}
26664562Sgshapiro	argc -= optind;
26764562Sgshapiro	argv += optind;
26864562Sgshapiro
26964562Sgshapiro	if (mfail != 0)
27064562Sgshapiro	{
27164562Sgshapiro		msglog(LOG_NOTICE,
27264562Sgshapiro		       "vacation: can't allocate memory for alias.\n");
27366494Sgshapiro		EXITM(EX_TEMPFAIL);
27464562Sgshapiro	}
27564562Sgshapiro	if (ufail != 0)
27664562Sgshapiro		usage();
27764562Sgshapiro
27864562Sgshapiro	if (argc != 1)
27964562Sgshapiro	{
28098121Sgshapiro		if (!initdb && !list && !exclude)
28164562Sgshapiro			usage();
28264562Sgshapiro		if ((pw = getpwuid(getuid())) == NULL)
28364562Sgshapiro		{
28464562Sgshapiro			msglog(LOG_ERR,
28564562Sgshapiro			       "vacation: no such user uid %u.\n", getuid());
28666494Sgshapiro			EXITM(EX_NOUSER);
28764562Sgshapiro		}
28877349Sgshapiro		name = pw->pw_name;
28977349Sgshapiro		user_info.smdbu_id = pw->pw_uid;
29077349Sgshapiro		user_info.smdbu_group_id = pw->pw_gid;
29190792Sgshapiro		(void) sm_strlcpy(user_info.smdbu_name, pw->pw_name,
29290792Sgshapiro				  SMDB_MAX_USER_NAME_LEN);
29377349Sgshapiro		if (chdir(pw->pw_dir) != 0)
29477349Sgshapiro		{
29590792Sgshapiro			msglog(LOG_NOTICE,
29690792Sgshapiro			       "vacation: no such directory %s.\n",
29777349Sgshapiro			       pw->pw_dir);
29877349Sgshapiro			EXITM(EX_NOINPUT);
29977349Sgshapiro		}
30064562Sgshapiro	}
30177349Sgshapiro	else if (runasuser)
30277349Sgshapiro	{
30377349Sgshapiro		name = *argv;
30477349Sgshapiro		if (dbfilename == NULL || msgfilename == NULL)
30577349Sgshapiro		{
30677349Sgshapiro			msglog(LOG_NOTICE,
30777349Sgshapiro			       "vacation: -U requires setting both -f and -m\n");
30877349Sgshapiro			EXITM(EX_NOINPUT);
30977349Sgshapiro		}
31077349Sgshapiro		user_info.smdbu_id = pw->pw_uid;
31177349Sgshapiro		user_info.smdbu_group_id = pw->pw_gid;
31290792Sgshapiro		(void) sm_strlcpy(user_info.smdbu_name, pw->pw_name,
31377349Sgshapiro			       SMDB_MAX_USER_NAME_LEN);
31477349Sgshapiro	}
31577349Sgshapiro	else
31664562Sgshapiro	{
31790792Sgshapiro		int err;
31890792Sgshapiro		SM_CF_OPT_T mbdbname;
31990792Sgshapiro		SM_MBDB_T user;
32090792Sgshapiro
32194334Sgshapiro		cfpath = getcfname(0, 0, SM_GET_SENDMAIL_CF, cfpath);
32290792Sgshapiro		mbdbname.opt_name = "MailboxDatabase";
32390792Sgshapiro		mbdbname.opt_val = "pw";
32490792Sgshapiro		(void) sm_cf_getopt(cfpath, 1, &mbdbname);
32590792Sgshapiro		err = sm_mbdb_initialize(mbdbname.opt_val);
32690792Sgshapiro		if (err != EX_OK)
32777349Sgshapiro		{
32890792Sgshapiro			msglog(LOG_ERR,
32990792Sgshapiro			       "vacation: can't open mailbox database: %s.\n",
33090792Sgshapiro			       sm_strexit(err));
33190792Sgshapiro			EXITM(err);
33290792Sgshapiro		}
33390792Sgshapiro		err = sm_mbdb_lookup(*argv, &user);
33490792Sgshapiro		if (err == EX_NOUSER)
33590792Sgshapiro		{
33690792Sgshapiro			msglog(LOG_ERR, "vacation: no such user %s.\n", *argv);
33790792Sgshapiro			EXITM(EX_NOUSER);
33890792Sgshapiro		}
33990792Sgshapiro		if (err != EX_OK)
34090792Sgshapiro		{
34190792Sgshapiro			msglog(LOG_ERR,
34290792Sgshapiro			       "vacation: can't read mailbox database: %s.\n",
34390792Sgshapiro			       sm_strexit(err));
34490792Sgshapiro			EXITM(err);
34590792Sgshapiro		}
34690792Sgshapiro		name = user.mbdb_name;
34790792Sgshapiro		if (chdir(user.mbdb_homedir) != 0)
34890792Sgshapiro		{
34990792Sgshapiro			msglog(LOG_NOTICE,
35090792Sgshapiro			       "vacation: no such directory %s.\n",
35190792Sgshapiro			       user.mbdb_homedir);
35277349Sgshapiro			EXITM(EX_NOINPUT);
35377349Sgshapiro		}
35490792Sgshapiro		user_info.smdbu_id = user.mbdb_uid;
35590792Sgshapiro		user_info.smdbu_group_id = user.mbdb_gid;
35690792Sgshapiro		(void) sm_strlcpy(user_info.smdbu_name, user.mbdb_name,
35777349Sgshapiro			       SMDB_MAX_USER_NAME_LEN);
35864562Sgshapiro	}
35964562Sgshapiro
36077349Sgshapiro	if (dbfilename == NULL)
36177349Sgshapiro		dbfilename = VDB;
36277349Sgshapiro	if (msgfilename == NULL)
36377349Sgshapiro		msgfilename = VMSG;
36477349Sgshapiro
36566494Sgshapiro	sff = SFF_CREAT;
36666494Sgshapiro	if (getegid() != getgid())
36777349Sgshapiro	{
36890792Sgshapiro		/* Allow a set-group-ID vacation binary */
36966494Sgshapiro		RunAsGid = user_info.smdbu_group_id = getegid();
37090792Sgshapiro		sff |= SFF_OPENASROOT;
37177349Sgshapiro	}
37294334Sgshapiro	if (getuid() == 0)
37394334Sgshapiro	{
37494334Sgshapiro		/* Allow root to initialize user's vacation databases */
37594334Sgshapiro		sff |= SFF_OPENASROOT|SFF_ROOTOK;
37666494Sgshapiro
37794334Sgshapiro		/* ... safely */
37894334Sgshapiro		sff |= SFF_NOSLINK|SFF_NOHLINK|SFF_REGONLY;
37994334Sgshapiro	}
38094334Sgshapiro
38194334Sgshapiro
38264562Sgshapiro	result = smdb_open_database(&Db, dbfilename,
38398121Sgshapiro				    O_CREAT|O_RDWR | (initdb ? O_TRUNC : 0),
38466494Sgshapiro				    S_IRUSR|S_IWUSR, sff,
38564562Sgshapiro				    SMDB_TYPE_DEFAULT, &user_info, NULL);
38664562Sgshapiro	if (result != SMDBE_OK)
38764562Sgshapiro	{
38864562Sgshapiro		msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename,
38990792Sgshapiro		       sm_errstring(result));
39066494Sgshapiro		EXITM(EX_DATAERR);
39164562Sgshapiro	}
39264562Sgshapiro
39398121Sgshapiro	if (list)
39464562Sgshapiro	{
39564562Sgshapiro		listdb();
39671345Sgshapiro		(void) Db->smdb_close(Db);
39764562Sgshapiro		exit(EX_OK);
39864562Sgshapiro	}
39964562Sgshapiro
40064562Sgshapiro	if (interval != INTERVAL_UNDEF)
40164562Sgshapiro		setinterval(interval);
40264562Sgshapiro
40398121Sgshapiro	if (initdb && !exclude)
40464562Sgshapiro	{
40571345Sgshapiro		(void) Db->smdb_close(Db);
40671345Sgshapiro		exit(EX_OK);
40764562Sgshapiro	}
40864562Sgshapiro
40964562Sgshapiro	if (exclude)
41064562Sgshapiro	{
41190792Sgshapiro		xclude(smioin);
41271345Sgshapiro		(void) Db->smdb_close(Db);
41366494Sgshapiro		EXITM(EX_OK);
41464562Sgshapiro	}
41564562Sgshapiro
41690792Sgshapiro	if ((cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS))) == NULL)
41764562Sgshapiro	{
41864562Sgshapiro		msglog(LOG_NOTICE,
41964562Sgshapiro		       "vacation: can't allocate memory for username.\n");
42071345Sgshapiro		(void) Db->smdb_close(Db);
42166494Sgshapiro		EXITM(EX_OSERR);
42264562Sgshapiro	}
42364562Sgshapiro	cur->name = name;
42464562Sgshapiro	cur->next = Names;
42564562Sgshapiro	Names = cur;
42664562Sgshapiro
42798121Sgshapiro	result = readheaders(alwaysrespond);
42871345Sgshapiro	if (result == EX_OK && !recent())
42964562Sgshapiro	{
43064562Sgshapiro		time_t now;
43164562Sgshapiro
43264562Sgshapiro		(void) time(&now);
43364562Sgshapiro		setreply(From, now);
43471345Sgshapiro		(void) Db->smdb_close(Db);
43590792Sgshapiro		sendmessage(name, msgfilename, returnaddr);
43664562Sgshapiro	}
43764562Sgshapiro	else
43871345Sgshapiro		(void) Db->smdb_close(Db);
43971345Sgshapiro	if (result == EX_NOUSER)
44071345Sgshapiro		result = EX_OK;
44171345Sgshapiro	exit(result);
44264562Sgshapiro}
44364562Sgshapiro
44464562Sgshapiro/*
44566494Sgshapiro** EATMSG -- read stdin till EOF
44666494Sgshapiro**
44766494Sgshapiro**	Parameters:
44866494Sgshapiro**		none.
44966494Sgshapiro**
45066494Sgshapiro**	Returns:
45166494Sgshapiro**		nothing.
45266494Sgshapiro**
45366494Sgshapiro*/
45477349Sgshapiro
45566494Sgshapirostatic void
45666494Sgshapiroeatmsg()
45766494Sgshapiro{
45866494Sgshapiro	/*
45966494Sgshapiro	**  read the rest of the e-mail and ignore it to avoid problems
46066494Sgshapiro	**  with EPIPE in sendmail
46166494Sgshapiro	*/
46266494Sgshapiro	while (getc(stdin) != EOF)
46366494Sgshapiro		continue;
46466494Sgshapiro}
46566494Sgshapiro
46666494Sgshapiro/*
46764562Sgshapiro** READHEADERS -- read mail headers
46864562Sgshapiro**
46964562Sgshapiro**	Parameters:
47098121Sgshapiro**		alwaysrespond -- respond regardless of whether msg is to me
47164562Sgshapiro**
47264562Sgshapiro**	Returns:
47371345Sgshapiro**		a exit code: NOUSER if no reply, OK if reply, * if error
47464562Sgshapiro**
47566494Sgshapiro**	Side Effects:
47666494Sgshapiro**		may exit().
47766494Sgshapiro**
47864562Sgshapiro*/
47971345Sgshapiro
48071345Sgshapiroint
48198121Sgshapiroreadheaders(alwaysrespond)
48298121Sgshapiro	bool alwaysrespond;
48364562Sgshapiro{
48464562Sgshapiro	bool tome, cont;
48564562Sgshapiro	register char *p;
48664562Sgshapiro	register ALIAS *cur;
48764562Sgshapiro	char buf[MAXLINE];
48864562Sgshapiro	extern bool junkmail __P((char *));
48964562Sgshapiro	extern bool nsearch __P((char *, char *));
49064562Sgshapiro
49198121Sgshapiro	cont = false;
49298121Sgshapiro	tome = alwaysrespond;
49390792Sgshapiro	while (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, sizeof(buf)) &&
49490792Sgshapiro	       *buf != '\n')
49564562Sgshapiro	{
49664562Sgshapiro		switch(*buf)
49764562Sgshapiro		{
49864562Sgshapiro		  case 'F':		/* "From " */
49990792Sgshapiro			cont = false;
50064562Sgshapiro			if (strncmp(buf, "From ", 5) == 0)
50164562Sgshapiro			{
50290792Sgshapiro				bool quoted = false;
50364562Sgshapiro
50464562Sgshapiro				p = buf + 5;
50564562Sgshapiro				while (*p != '\0')
50664562Sgshapiro				{
50764562Sgshapiro					/* escaped character */
50864562Sgshapiro					if (*p == '\\')
50964562Sgshapiro					{
51064562Sgshapiro						p++;
51164562Sgshapiro						if (*p == '\0')
51264562Sgshapiro						{
51364562Sgshapiro							msglog(LOG_NOTICE,
51464562Sgshapiro							       "vacation: badly formatted \"From \" line.\n");
51566494Sgshapiro							EXITIT(EX_DATAERR);
51664562Sgshapiro						}
51764562Sgshapiro					}
51864562Sgshapiro					else if (*p == '"')
51964562Sgshapiro						quoted = !quoted;
52064562Sgshapiro					else if (*p == '\r' || *p == '\n')
52164562Sgshapiro						break;
52264562Sgshapiro					else if (*p == ' ' && !quoted)
52364562Sgshapiro						break;
52464562Sgshapiro					p++;
52564562Sgshapiro				}
52664562Sgshapiro				if (quoted)
52764562Sgshapiro				{
52864562Sgshapiro					msglog(LOG_NOTICE,
52964562Sgshapiro					       "vacation: badly formatted \"From \" line.\n");
53066494Sgshapiro					EXITIT(EX_DATAERR);
53164562Sgshapiro				}
53264562Sgshapiro				*p = '\0';
53364562Sgshapiro
53464562Sgshapiro				/* ok since both strings have MAXLINE length */
53564562Sgshapiro				if (*From == '\0')
53690792Sgshapiro					(void) sm_strlcpy(From, buf + 5,
53790792Sgshapiro							  sizeof From);
53864562Sgshapiro				if ((p = strchr(buf + 5, '\n')) != NULL)
53964562Sgshapiro					*p = '\0';
54064562Sgshapiro				if (junkmail(buf + 5))
54171345Sgshapiro					EXITIT(EX_NOUSER);
54264562Sgshapiro			}
54364562Sgshapiro			break;
54464562Sgshapiro
54564562Sgshapiro		  case 'P':		/* "Precedence:" */
54664562Sgshapiro		  case 'p':
54790792Sgshapiro			cont = false;
54864562Sgshapiro			if (strlen(buf) <= 10 ||
54964562Sgshapiro			    strncasecmp(buf, "Precedence", 10) != 0 ||
55064562Sgshapiro			    (buf[10] != ':' && buf[10] != ' ' &&
55164562Sgshapiro			     buf[10] != '\t'))
55264562Sgshapiro				break;
55364562Sgshapiro			if ((p = strchr(buf, ':')) == NULL)
55464562Sgshapiro				break;
55564562Sgshapiro			while (*++p != '\0' && isascii(*p) && isspace(*p));
55664562Sgshapiro			if (*p == '\0')
55764562Sgshapiro				break;
55864562Sgshapiro			if (strncasecmp(p, "junk", 4) == 0 ||
55964562Sgshapiro			    strncasecmp(p, "bulk", 4) == 0 ||
56064562Sgshapiro			    strncasecmp(p, "list", 4) == 0)
56171345Sgshapiro				EXITIT(EX_NOUSER);
56264562Sgshapiro			break;
56364562Sgshapiro
56464562Sgshapiro		  case 'C':		/* "Cc:" */
56564562Sgshapiro		  case 'c':
56664562Sgshapiro			if (strncasecmp(buf, "Cc:", 3) != 0)
56764562Sgshapiro				break;
56890792Sgshapiro			cont = true;
56964562Sgshapiro			goto findme;
57064562Sgshapiro
57164562Sgshapiro		  case 'T':		/* "To:" */
57264562Sgshapiro		  case 't':
57364562Sgshapiro			if (strncasecmp(buf, "To:", 3) != 0)
57464562Sgshapiro				break;
57590792Sgshapiro			cont = true;
57664562Sgshapiro			goto findme;
57764562Sgshapiro
57864562Sgshapiro		  default:
57964562Sgshapiro			if (!isascii(*buf) || !isspace(*buf) || !cont || tome)
58064562Sgshapiro			{
58190792Sgshapiro				cont = false;
58264562Sgshapiro				break;
58364562Sgshapiro			}
58464562Sgshapirofindme:
58564562Sgshapiro			for (cur = Names;
58664562Sgshapiro			     !tome && cur != NULL;
58764562Sgshapiro			     cur = cur->next)
58864562Sgshapiro				tome = nsearch(cur->name, buf);
58964562Sgshapiro		}
59064562Sgshapiro	}
59164562Sgshapiro	if (!tome)
59271345Sgshapiro		EXITIT(EX_NOUSER);
59364562Sgshapiro	if (*From == '\0')
59464562Sgshapiro	{
59564562Sgshapiro		msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n");
59666494Sgshapiro		EXITIT(EX_DATAERR);
59764562Sgshapiro	}
59871345Sgshapiro	EXITIT(EX_OK);
59964562Sgshapiro}
60064562Sgshapiro
60164562Sgshapiro/*
60264562Sgshapiro** NSEARCH --
60364562Sgshapiro**	do a nice, slow, search of a string for a substring.
60464562Sgshapiro**
60564562Sgshapiro**	Parameters:
60664562Sgshapiro**		name -- name to search.
60764562Sgshapiro**		str -- string in which to search.
60864562Sgshapiro**
60964562Sgshapiro**	Returns:
61064562Sgshapiro**		is name a substring of str?
61164562Sgshapiro**
61264562Sgshapiro*/
61377349Sgshapiro
61464562Sgshapirobool
61564562Sgshapironsearch(name, str)
61664562Sgshapiro	register char *name, *str;
61764562Sgshapiro{
61864562Sgshapiro	register size_t len;
61964562Sgshapiro	register char *s;
62064562Sgshapiro
62164562Sgshapiro	len = strlen(name);
62264562Sgshapiro
62364562Sgshapiro	for (s = str; *s != '\0'; ++s)
62464562Sgshapiro	{
62564562Sgshapiro		/*
62664562Sgshapiro		**  Check to make sure that the string matches and
62764562Sgshapiro		**  the previous character is not an alphanumeric and
62864562Sgshapiro		**  the next character after the match is not an alphanumeric.
62964562Sgshapiro		**
63064562Sgshapiro		**  This prevents matching "eric" to "derick" while still
63164562Sgshapiro		**  matching "eric" to "<eric+detail>".
63264562Sgshapiro		*/
63364562Sgshapiro
63464562Sgshapiro		if (tolower(*s) == tolower(*name) &&
63564562Sgshapiro		    strncasecmp(name, s, len) == 0 &&
63664562Sgshapiro		    (s == str || !isascii(*(s - 1)) || !isalnum(*(s - 1))) &&
63764562Sgshapiro		    (!isascii(*(s + len)) || !isalnum(*(s + len))))
63890792Sgshapiro			return true;
63964562Sgshapiro	}
64090792Sgshapiro	return false;
64164562Sgshapiro}
64264562Sgshapiro
64364562Sgshapiro/*
64464562Sgshapiro** JUNKMAIL --
64564562Sgshapiro**	read the header and return if automagic/junk/bulk/list mail
64664562Sgshapiro**
64764562Sgshapiro**	Parameters:
64864562Sgshapiro**		from -- sender address.
64964562Sgshapiro**
65064562Sgshapiro**	Returns:
65164562Sgshapiro**		is this some automated/junk/bulk/list mail?
65264562Sgshapiro**
65364562Sgshapiro*/
65471345Sgshapiro
65571345Sgshapirostruct ignore
65671345Sgshapiro{
65771345Sgshapiro	char	*name;
65871345Sgshapiro	size_t	len;
65971345Sgshapiro};
66071345Sgshapiro
66171345Sgshapirotypedef struct ignore IGNORE_T;
66271345Sgshapiro
66371345Sgshapiro#define MAX_USER_LEN 256	/* maximum length of local part (sender) */
66471345Sgshapiro
66571345Sgshapiro/* delimiters for the local part of an address */
66671345Sgshapiro#define isdelim(c)	((c) == '%' || (c) == '@' || (c) == '+')
66771345Sgshapiro
66864562Sgshapirobool
66964562Sgshapirojunkmail(from)
67064562Sgshapiro	char *from;
67164562Sgshapiro{
67271345Sgshapiro	bool quot;
67371345Sgshapiro	char *e;
67471345Sgshapiro	size_t len;
67571345Sgshapiro	IGNORE_T *cur;
67671345Sgshapiro	char sender[MAX_USER_LEN];
67771345Sgshapiro	static IGNORE_T ignore[] =
67864562Sgshapiro	{
67964562Sgshapiro		{ "postmaster",		10	},
68064562Sgshapiro		{ "uucp",		4	},
68164562Sgshapiro		{ "mailer-daemon",	13	},
68264562Sgshapiro		{ "mailer",		6	},
68371345Sgshapiro		{ NULL,			0	}
68471345Sgshapiro	};
68571345Sgshapiro
68671345Sgshapiro	static IGNORE_T ignorepost[] =
68771345Sgshapiro	{
68871345Sgshapiro		{ "-request",		8	},
68964562Sgshapiro		{ "-relay",		6	},
69071345Sgshapiro		{ "-owner",		6	},
69164562Sgshapiro		{ NULL,			0	}
69264562Sgshapiro	};
69364562Sgshapiro
69471345Sgshapiro	static IGNORE_T ignorepre[] =
69571345Sgshapiro	{
69671345Sgshapiro		{ "owner-",		6	},
69771345Sgshapiro		{ NULL,			0	}
69871345Sgshapiro	};
69971345Sgshapiro
70064562Sgshapiro	/*
70171345Sgshapiro	**  This is mildly amusing, and I'm not positive it's right; trying
70271345Sgshapiro	**  to find the "real" name of the sender, assuming that addresses
70371345Sgshapiro	**  will be some variant of:
70471345Sgshapiro	**
70571345Sgshapiro	**  From site!site!SENDER%site.domain%site.domain@site.domain
70671345Sgshapiro	*/
70771345Sgshapiro
70890792Sgshapiro	quot = false;
70971345Sgshapiro	e = from;
71071345Sgshapiro	len = 0;
71171345Sgshapiro	while (*e != '\0' && (quot || !isdelim(*e)))
71264562Sgshapiro	{
71371345Sgshapiro		if (*e == '"')
71471345Sgshapiro		{
71571345Sgshapiro			quot = !quot;
71671345Sgshapiro			++e;
71771345Sgshapiro			continue;
71871345Sgshapiro		}
71971345Sgshapiro		if (*e == '\\')
72071345Sgshapiro		{
72171345Sgshapiro			if (*(++e) == '\0')
72271345Sgshapiro			{
72371345Sgshapiro				/* '\\' at end of string? */
72471345Sgshapiro				break;
72571345Sgshapiro			}
72671345Sgshapiro			if (len < MAX_USER_LEN)
72771345Sgshapiro				sender[len++] = *e;
72871345Sgshapiro			++e;
72971345Sgshapiro			continue;
73071345Sgshapiro		}
73171345Sgshapiro		if (*e == '!' && !quot)
73271345Sgshapiro		{
73371345Sgshapiro			len = 0;
73471345Sgshapiro			sender[len] = '\0';
73571345Sgshapiro		}
73664562Sgshapiro		else
73771345Sgshapiro			if (len < MAX_USER_LEN)
73871345Sgshapiro				sender[len++] = *e;
73971345Sgshapiro		++e;
74064562Sgshapiro	}
74171345Sgshapiro	if (len < MAX_USER_LEN)
74271345Sgshapiro		sender[len] = '\0';
74371345Sgshapiro	else
74471345Sgshapiro		sender[MAX_USER_LEN - 1] = '\0';
74571345Sgshapiro
74671345Sgshapiro	if (len <= 0)
74790792Sgshapiro		return false;
74871345Sgshapiro#if 0
74971345Sgshapiro	if (quot)
75090792Sgshapiro		return false;	/* syntax error... */
75171345Sgshapiro#endif /* 0 */
75271345Sgshapiro
75371345Sgshapiro	/* test prefixes */
75471345Sgshapiro	for (cur = ignorepre; cur->name != NULL; ++cur)
75571345Sgshapiro	{
75671345Sgshapiro		if (len >= cur->len &&
75771345Sgshapiro		    strncasecmp(cur->name, sender, cur->len) == 0)
75890792Sgshapiro			return true;
75971345Sgshapiro	}
76071345Sgshapiro
76171345Sgshapiro	/*
76271345Sgshapiro	**  If the name is truncated, don't test the rest.
76371345Sgshapiro	**	We could extract the "tail" of the sender address and
76471345Sgshapiro	**	compare it it ignorepost, however, it seems not worth
76571345Sgshapiro	**	the effort.
76671345Sgshapiro	**	The address surely can't match any entry in ignore[]
76771345Sgshapiro	**	(as long as all of them are shorter than MAX_USER_LEN).
76871345Sgshapiro	*/
76971345Sgshapiro
77071345Sgshapiro	if (len > MAX_USER_LEN)
77190792Sgshapiro		return false;
77271345Sgshapiro
77371345Sgshapiro	/* test full local parts */
77464562Sgshapiro	for (cur = ignore; cur->name != NULL; ++cur)
77564562Sgshapiro	{
77671345Sgshapiro		if (len == cur->len &&
77771345Sgshapiro		    strncasecmp(cur->name, sender, cur->len) == 0)
77890792Sgshapiro			return true;
77971345Sgshapiro	}
78071345Sgshapiro
78171345Sgshapiro	/* test postfixes */
78271345Sgshapiro	for (cur = ignorepost; cur->name != NULL; ++cur)
78371345Sgshapiro	{
78464562Sgshapiro		if (len >= cur->len &&
78571345Sgshapiro		    strncasecmp(cur->name, e - cur->len - 1,
78671345Sgshapiro				cur->len) == 0)
78790792Sgshapiro			return true;
78864562Sgshapiro	}
78990792Sgshapiro	return false;
79064562Sgshapiro}
79164562Sgshapiro
79264562Sgshapiro#define	VIT	"__VACATION__INTERVAL__TIMER__"
79364562Sgshapiro
79464562Sgshapiro/*
79564562Sgshapiro** RECENT --
79664562Sgshapiro**	find out if user has gotten a vacation message recently.
79764562Sgshapiro**
79864562Sgshapiro**	Parameters:
79964562Sgshapiro**		none.
80064562Sgshapiro**
80164562Sgshapiro**	Returns:
80290792Sgshapiro**		true iff user has gotten a vacation message recently.
80364562Sgshapiro**
80464562Sgshapiro*/
80577349Sgshapiro
80664562Sgshapirobool
80764562Sgshapirorecent()
80864562Sgshapiro{
80964562Sgshapiro	SMDB_DBENT key, data;
81064562Sgshapiro	time_t then, next;
81190792Sgshapiro	bool trydomain = false;
81264562Sgshapiro	int st;
81364562Sgshapiro	char *domain;
81464562Sgshapiro
81564562Sgshapiro	memset(&key, '\0', sizeof key);
81664562Sgshapiro	memset(&data, '\0', sizeof data);
81764562Sgshapiro
81864562Sgshapiro	/* get interval time */
81971345Sgshapiro	key.data = VIT;
82071345Sgshapiro	key.size = sizeof(VIT);
82164562Sgshapiro
82264562Sgshapiro	st = Db->smdb_get(Db, &key, &data, 0);
82364562Sgshapiro	if (st != SMDBE_OK)
82464562Sgshapiro		next = SECSPERDAY * DAYSPERWEEK;
82564562Sgshapiro	else
82671345Sgshapiro		memmove(&next, data.data, sizeof(next));
82764562Sgshapiro
82864562Sgshapiro	memset(&data, '\0', sizeof data);
82964562Sgshapiro
83064562Sgshapiro	/* get record for this address */
83171345Sgshapiro	key.data = From;
83271345Sgshapiro	key.size = strlen(From);
83364562Sgshapiro
83464562Sgshapiro	do
83564562Sgshapiro	{
83664562Sgshapiro		st = Db->smdb_get(Db, &key, &data, 0);
83764562Sgshapiro		if (st == SMDBE_OK)
83864562Sgshapiro		{
83971345Sgshapiro			memmove(&then, data.data, sizeof(then));
84064562Sgshapiro			if (next == ONLY_ONCE || then == ONLY_ONCE ||
84164562Sgshapiro			    then + next > time(NULL))
84290792Sgshapiro				return true;
84364562Sgshapiro		}
84464562Sgshapiro		if ((trydomain = !trydomain) &&
84564562Sgshapiro		    (domain = strchr(From, '@')) != NULL)
84664562Sgshapiro		{
84771345Sgshapiro			key.data = domain;
84871345Sgshapiro			key.size = strlen(domain);
84964562Sgshapiro		}
85064562Sgshapiro	} while (trydomain);
85190792Sgshapiro	return false;
85264562Sgshapiro}
85364562Sgshapiro
85464562Sgshapiro/*
85564562Sgshapiro** SETINTERVAL --
85664562Sgshapiro**	store the reply interval
85764562Sgshapiro**
85864562Sgshapiro**	Parameters:
85964562Sgshapiro**		interval -- time interval for replies.
86064562Sgshapiro**
86164562Sgshapiro**	Returns:
86264562Sgshapiro**		nothing.
86364562Sgshapiro**
86464562Sgshapiro**	Side Effects:
86564562Sgshapiro**		stores the reply interval in database.
86664562Sgshapiro*/
86777349Sgshapiro
86864562Sgshapirovoid
86964562Sgshapirosetinterval(interval)
87064562Sgshapiro	time_t interval;
87164562Sgshapiro{
87264562Sgshapiro	SMDB_DBENT key, data;
87364562Sgshapiro
87464562Sgshapiro	memset(&key, '\0', sizeof key);
87564562Sgshapiro	memset(&data, '\0', sizeof data);
87664562Sgshapiro
87771345Sgshapiro	key.data = VIT;
87871345Sgshapiro	key.size = sizeof(VIT);
87971345Sgshapiro	data.data = (char*) &interval;
88071345Sgshapiro	data.size = sizeof(interval);
88171345Sgshapiro	(void) (Db->smdb_put)(Db, &key, &data, 0);
88264562Sgshapiro}
88364562Sgshapiro
88464562Sgshapiro/*
88564562Sgshapiro** SETREPLY --
88664562Sgshapiro**	store that this user knows about the vacation.
88764562Sgshapiro**
88864562Sgshapiro**	Parameters:
88964562Sgshapiro**		from -- sender address.
89064562Sgshapiro**		when -- last reply time.
89164562Sgshapiro**
89264562Sgshapiro**	Returns:
89364562Sgshapiro**		nothing.
89464562Sgshapiro**
89564562Sgshapiro**	Side Effects:
89664562Sgshapiro**		stores user/time in database.
89764562Sgshapiro*/
89877349Sgshapiro
89964562Sgshapirovoid
90064562Sgshapirosetreply(from, when)
90164562Sgshapiro	char *from;
90264562Sgshapiro	time_t when;
90364562Sgshapiro{
90464562Sgshapiro	SMDB_DBENT key, data;
90564562Sgshapiro
90664562Sgshapiro	memset(&key, '\0', sizeof key);
90764562Sgshapiro	memset(&data, '\0', sizeof data);
90864562Sgshapiro
90971345Sgshapiro	key.data = from;
91071345Sgshapiro	key.size = strlen(from);
91171345Sgshapiro	data.data = (char*) &when;
91271345Sgshapiro	data.size = sizeof(when);
91371345Sgshapiro	(void) (Db->smdb_put)(Db, &key, &data, 0);
91464562Sgshapiro}
91564562Sgshapiro
91664562Sgshapiro/*
91764562Sgshapiro** XCLUDE --
91864562Sgshapiro**	add users to vacation db so they don't get a reply.
91964562Sgshapiro**
92064562Sgshapiro**	Parameters:
92164562Sgshapiro**		f -- file pointer with list of address to exclude
92264562Sgshapiro**
92364562Sgshapiro**	Returns:
92464562Sgshapiro**		nothing.
92564562Sgshapiro**
92664562Sgshapiro**	Side Effects:
92764562Sgshapiro**		stores users in database.
92864562Sgshapiro*/
92977349Sgshapiro
93064562Sgshapirovoid
93164562Sgshapiroxclude(f)
93290792Sgshapiro	SM_FILE_T *f;
93364562Sgshapiro{
93464562Sgshapiro	char buf[MAXLINE], *p;
93564562Sgshapiro
93664562Sgshapiro	if (f == NULL)
93764562Sgshapiro		return;
93890792Sgshapiro	while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf))
93964562Sgshapiro	{
94064562Sgshapiro		if ((p = strchr(buf, '\n')) != NULL)
94164562Sgshapiro			*p = '\0';
94264562Sgshapiro		setreply(buf, ONLY_ONCE);
94364562Sgshapiro	}
94464562Sgshapiro}
94564562Sgshapiro
94664562Sgshapiro/*
94764562Sgshapiro** SENDMESSAGE --
94864562Sgshapiro**	exec sendmail to send the vacation file to sender
94964562Sgshapiro**
95064562Sgshapiro**	Parameters:
95164562Sgshapiro**		myname -- user name.
95264562Sgshapiro**		msgfn -- name of file with vacation message.
95390792Sgshapiro**		sender -- use as sender address
95464562Sgshapiro**
95564562Sgshapiro**	Returns:
95664562Sgshapiro**		nothing.
95764562Sgshapiro**
95864562Sgshapiro**	Side Effects:
95964562Sgshapiro**		sends vacation reply.
96064562Sgshapiro*/
96177349Sgshapiro
96264562Sgshapirovoid
96390792Sgshapirosendmessage(myname, msgfn, sender)
96464562Sgshapiro	char *myname;
96564562Sgshapiro	char *msgfn;
96690792Sgshapiro	char *sender;
96764562Sgshapiro{
96890792Sgshapiro	SM_FILE_T *mfp, *sfp;
96964562Sgshapiro	int i;
97064562Sgshapiro	int pvect[2];
97177349Sgshapiro	char *pv[8];
97264562Sgshapiro	char buf[MAXLINE];
97364562Sgshapiro
97490792Sgshapiro	mfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, msgfn, SM_IO_RDONLY, NULL);
97564562Sgshapiro	if (mfp == NULL)
97664562Sgshapiro	{
97764562Sgshapiro		if (msgfn[0] == '/')
97864562Sgshapiro			msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn);
97964562Sgshapiro		else
98064562Sgshapiro			msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n",
98164562Sgshapiro			       myname, msgfn);
98264562Sgshapiro		exit(EX_NOINPUT);
98364562Sgshapiro	}
98464562Sgshapiro	if (pipe(pvect) < 0)
98564562Sgshapiro	{
98690792Sgshapiro		msglog(LOG_ERR, "vacation: pipe: %s", sm_errstring(errno));
98764562Sgshapiro		exit(EX_OSERR);
98864562Sgshapiro	}
98977349Sgshapiro	pv[0] = "sendmail";
99077349Sgshapiro	pv[1] = "-oi";
99177349Sgshapiro	pv[2] = "-f";
99290792Sgshapiro	if (sender != NULL)
99390792Sgshapiro		pv[3] = sender;
99477349Sgshapiro	else
99577349Sgshapiro		pv[3] = myname;
99677349Sgshapiro	pv[4] = "--";
99777349Sgshapiro	pv[5] = From;
99877349Sgshapiro	pv[6] = NULL;
99964562Sgshapiro	i = fork();
100064562Sgshapiro	if (i < 0)
100164562Sgshapiro	{
100290792Sgshapiro		msglog(LOG_ERR, "vacation: fork: %s", sm_errstring(errno));
100364562Sgshapiro		exit(EX_OSERR);
100464562Sgshapiro	}
100564562Sgshapiro	if (i == 0)
100664562Sgshapiro	{
100764562Sgshapiro		(void) dup2(pvect[0], 0);
100864562Sgshapiro		(void) close(pvect[0]);
100964562Sgshapiro		(void) close(pvect[1]);
101090792Sgshapiro		(void) sm_io_close(mfp, SM_TIME_DEFAULT);
101177349Sgshapiro		(void) execv(_PATH_SENDMAIL, pv);
101264562Sgshapiro		msglog(LOG_ERR, "vacation: can't exec %s: %s",
101390792Sgshapiro			_PATH_SENDMAIL, sm_errstring(errno));
101464562Sgshapiro		exit(EX_UNAVAILABLE);
101564562Sgshapiro	}
101664562Sgshapiro	/* check return status of the following calls? XXX */
101764562Sgshapiro	(void) close(pvect[0]);
101890792Sgshapiro	if ((sfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
101990792Sgshapiro			      (void *) &(pvect[1]),
102090792Sgshapiro			      SM_IO_WRONLY, NULL)) != NULL)
102164562Sgshapiro	{
102290792Sgshapiro		(void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, "To: %s\n", From);
102390792Sgshapiro		(void) sm_io_fprintf(sfp, SM_TIME_DEFAULT,
102490792Sgshapiro				     "Auto-Submitted: auto-replied\n");
102590792Sgshapiro		while (sm_io_fgets(mfp, SM_TIME_DEFAULT, buf, sizeof buf))
102690792Sgshapiro			(void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf);
102790792Sgshapiro		(void) sm_io_close(mfp, SM_TIME_DEFAULT);
102890792Sgshapiro		(void) sm_io_close(sfp, SM_TIME_DEFAULT);
102964562Sgshapiro	}
103064562Sgshapiro	else
103164562Sgshapiro	{
103290792Sgshapiro		(void) sm_io_close(mfp, SM_TIME_DEFAULT);
103364562Sgshapiro		msglog(LOG_ERR, "vacation: can't open pipe to sendmail");
103464562Sgshapiro		exit(EX_UNAVAILABLE);
103564562Sgshapiro	}
103664562Sgshapiro}
103764562Sgshapiro
103864562Sgshapirovoid
103964562Sgshapirousage()
104064562Sgshapiro{
104177349Sgshapiro	msglog(LOG_NOTICE,
1042132943Sgshapiro	       "uid %u: usage: vacation [-a alias] [-C cfpath] [-d] [-f db] [-i] [-j] [-l] [-m msg] [-R returnaddr] [-r interval] [-s sender] [-t time] [-U] [-x] [-z] login\n",
1043132943Sgshapiro	       getuid());
104464562Sgshapiro	exit(EX_USAGE);
104564562Sgshapiro}
104664562Sgshapiro
104764562Sgshapiro/*
104864562Sgshapiro** LISTDB -- list the contents of the vacation database
104964562Sgshapiro**
105064562Sgshapiro**	Parameters:
105164562Sgshapiro**		none.
105264562Sgshapiro**
105364562Sgshapiro**	Returns:
105464562Sgshapiro**		nothing.
105564562Sgshapiro*/
105664562Sgshapiro
105764562Sgshapirostatic void
105864562Sgshapirolistdb()
105964562Sgshapiro{
106064562Sgshapiro	int result;
106164562Sgshapiro	time_t t;
106264562Sgshapiro	SMDB_CURSOR *cursor = NULL;
106364562Sgshapiro	SMDB_DBENT db_key, db_value;
106464562Sgshapiro
106564562Sgshapiro	memset(&db_key, '\0', sizeof db_key);
106664562Sgshapiro	memset(&db_value, '\0', sizeof db_value);
106764562Sgshapiro
106864562Sgshapiro	result = Db->smdb_cursor(Db, &cursor, 0);
106964562Sgshapiro	if (result != SMDBE_OK)
107064562Sgshapiro	{
107190792Sgshapiro		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
107290792Sgshapiro			      "vacation: set cursor: %s\n",
107390792Sgshapiro			      sm_errstring(result));
107464562Sgshapiro		return;
107564562Sgshapiro	}
107664562Sgshapiro
107764562Sgshapiro	while ((result = cursor->smdbc_get(cursor, &db_key, &db_value,
107864562Sgshapiro					   SMDB_CURSOR_GET_NEXT)) == SMDBE_OK)
107964562Sgshapiro	{
108098121Sgshapiro		char *timestamp;
108198121Sgshapiro
108264562Sgshapiro		/* skip magic VIT entry */
1083110560Sgshapiro		if (db_key.size == strlen(VIT) + 1 &&
108471345Sgshapiro		    strncmp((char *)db_key.data, VIT,
108571345Sgshapiro			    (int)db_key.size - 1) == 0)
108664562Sgshapiro			continue;
108764562Sgshapiro
108864562Sgshapiro		/* skip bogus values */
108971345Sgshapiro		if (db_value.size != sizeof t)
109064562Sgshapiro		{
109190792Sgshapiro			sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
109290792Sgshapiro				      "vacation: %.*s invalid time stamp\n",
109390792Sgshapiro				      (int) db_key.size, (char *) db_key.data);
109464562Sgshapiro			continue;
109564562Sgshapiro		}
109664562Sgshapiro
109771345Sgshapiro		memcpy(&t, db_value.data, sizeof t);
109864562Sgshapiro
109971345Sgshapiro		if (db_key.size > 40)
110071345Sgshapiro			db_key.size = 40;
110164562Sgshapiro
110298121Sgshapiro		if (t <= 0)
110398121Sgshapiro		{
110498121Sgshapiro			/* must be an exclude */
110598121Sgshapiro			timestamp = "(exclusion)\n";
110698121Sgshapiro		}
110798121Sgshapiro		else
110898121Sgshapiro		{
110998121Sgshapiro			timestamp = ctime(&t);
111098121Sgshapiro		}
111190792Sgshapiro		sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%-40.*s %-10s",
111290792Sgshapiro			      (int) db_key.size, (char *) db_key.data,
111398121Sgshapiro			      timestamp);
111464562Sgshapiro
111564562Sgshapiro		memset(&db_key, '\0', sizeof db_key);
111664562Sgshapiro		memset(&db_value, '\0', sizeof db_value);
111764562Sgshapiro	}
111864562Sgshapiro
111964562Sgshapiro	if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY)
112064562Sgshapiro	{
112190792Sgshapiro		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
112290792Sgshapiro			      "vacation: get value at cursor: %s\n",
112390792Sgshapiro			      sm_errstring(result));
112464562Sgshapiro		if (cursor != NULL)
112564562Sgshapiro		{
112664562Sgshapiro			(void) cursor->smdbc_close(cursor);
112764562Sgshapiro			cursor = NULL;
112864562Sgshapiro		}
112964562Sgshapiro		return;
113064562Sgshapiro	}
113164562Sgshapiro	(void) cursor->smdbc_close(cursor);
113264562Sgshapiro	cursor = NULL;
113364562Sgshapiro}
113464562Sgshapiro
113564562Sgshapiro/*
113664562Sgshapiro** DEBUGLOG -- write message to standard error
113764562Sgshapiro**
113864562Sgshapiro**	Append a message to the standard error for the convenience of
113964562Sgshapiro**	end-users debugging without access to the syslog messages.
114064562Sgshapiro**
114164562Sgshapiro**	Parameters:
114264562Sgshapiro**		i -- syslog log level
114364562Sgshapiro**		fmt -- string format
114464562Sgshapiro**
114564562Sgshapiro**	Returns:
114664562Sgshapiro**		nothing.
114764562Sgshapiro*/
114864562Sgshapiro
114964562Sgshapiro/*VARARGS2*/
115090792Sgshapirostatic SYSLOG_RET_T
115164562Sgshapiro#ifdef __STDC__
115264562Sgshapirodebuglog(int i, const char *fmt, ...)
115364562Sgshapiro#else /* __STDC__ */
115464562Sgshapirodebuglog(i, fmt, va_alist)
115564562Sgshapiro	int i;
115664562Sgshapiro	const char *fmt;
115764562Sgshapiro	va_dcl
115864562Sgshapiro#endif /* __STDC__ */
115964562Sgshapiro
116064562Sgshapiro{
116190792Sgshapiro	SM_VA_LOCAL_DECL
116264562Sgshapiro
116390792Sgshapiro	SM_VA_START(ap, fmt);
116490792Sgshapiro	sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap);
116590792Sgshapiro	SM_VA_END(ap);
116690792Sgshapiro	SYSLOG_RET;
116764562Sgshapiro}
1168