/*
* Copyright (c) 1999-2002, 2009 Proofpoint, 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.
*
*/
"@(#) Copyright (c) 1999-2002, 2009 Proofpoint, 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")
#include <ctype.h>
#include <stdlib.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#ifdef EX_OK
#endif /* EX_OK */
#include <sm/sysexits.h>
#include "sendmail/sendmail.h"
#include <sendmail/pathnames.h>
char *RealUserName;
char *RunAsUserName;
bool DontInitGroups = false;
static int readheaders __P((bool));
static void sendmessage __P((char *, char *, char *));
/*
** 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.
*/
typedef struct alias
{
char *name;
} ALIAS;
bool CloseMBDB = false;
# ifndef SM_CONF_SYSLOG_INT
# endif /* SM_CONF_SYSLOG_INT */
#endif /* defined(__hpux) || defined(__osf__) */
# define SYSLOG_RET_T int
# define SYSLOG_RET return 0
#else /* SM_CONF_SYSLOG_INT */
# define SYSLOG_RET_T void
# define SYSLOG_RET
#endif /* SM_CONF_SYSLOG_INT */
/* exit after reading input */
{ \
eatmsg(); \
if (CloseMBDB) \
{ \
sm_mbdb_terminate(); \
CloseMBDB = false; \
} \
return excode; \
}
{ \
eatmsg(); \
if (CloseMBDB) \
{ \
sm_mbdb_terminate(); \
CloseMBDB = false; \
} \
}
int
int argc;
char **argv;
{
bool alwaysrespond = false;
bool runasuser = false;
bool list = false;
int ch;
int result;
long sff;
extern char *optarg;
/* Vars needed to link with smutil */
{
}
else
"Unknown UID %d", (int) RealUid);
# ifdef LOG_MAIL
# else /* LOG_MAIL */
# endif /* LOG_MAIL */
opterr = 0;
initdb = false;
exclude = false;
*From = '\0';
{
switch((char)ch)
{
case 'a': /* alias */
{
mfail++;
break;
}
break;
case 'C':
break;
case 'd': /* debug mode */
break;
case 'f': /* alternate database */
dbfilename = optarg;
break;
case 'I': /* backward compatible */
case 'i': /* init the database */
initdb = true;
break;
case 'j':
alwaysrespond = true;
break;
case 'l':
list = true; /* list the database */
break;
case 'm': /* alternate message file */
break;
case 'R':
returnaddr = optarg;
break;
case 'r':
{
if (interval < 0)
ufail++;
}
else
break;
case 's': /* alternate sender name */
break;
case 't': /* SunOS: -t1d (default expire) */
break;
case 'U': /* run as single user mode */
runasuser = true;
break;
case 'x':
exclude = true;
break;
case 'z':
returnaddr = "<>";
break;
case '?':
default:
ufail++;
break;
}
}
if (mfail != 0)
{
"vacation: can't allocate memory for alias.\n");
}
if (ufail != 0)
usage();
if (argc != 1)
{
usage();
{
"vacation: no such user uid %u.\n", getuid());
}
{
"vacation: no such directory %s.\n",
}
}
else if (runasuser)
{
{
"vacation: -U requires setting both -f and -m\n");
}
}
else
{
int err;
{
"vacation: can't open mailbox database: %s.\n",
sm_strexit(err));
}
CloseMBDB = true;
{
}
{
"vacation: can't read mailbox database: %s.\n",
sm_strexit(err));
}
{
"vacation: no such directory %s.\n",
}
}
{
"vacation: can't allocate memory for username.\n");
}
if (dbfilename == NULL)
dbfilename = VDB;
if (msgfilename == NULL)
msgfilename = VMSG;
{
/* Allow a set-group-ID vacation binary */
sff |= SFF_OPENASROOT;
}
if (getuid() == 0)
{
/* Allow root to initialize user's vacation databases */
/* ... safely */
}
{
}
if (list)
{
listdb();
}
if (interval != INTERVAL_UNDEF)
{
}
if (exclude)
{
}
{
"vacation: can't allocate memory for username.\n");
}
{
}
else
}
/*
** 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
*/
continue;
}
/*
** READHEADERS -- read mail headers
**
** Parameters:
** alwaysrespond -- respond regardless of whether msg is to me
**
** Returns:
** a exit code: NOUSER if no reply, OK if reply, * if error
**
** Side Effects:
** may exit().
**
*/
static int
bool alwaysrespond;
{
register char *p;
cont = false;
*buf != '\n')
{
switch(*buf)
{
case 'F': /* "From " */
cont = false;
{
bool quoted = false;
p = buf + 5;
while (*p != '\0')
{
/* escaped character */
if (*p == '\\')
{
p++;
if (*p == '\0')
{
"vacation: badly formatted \"From \" line.\n");
}
}
else if (*p == '"')
else if (*p == '\r' || *p == '\n')
break;
else if (*p == ' ' && !quoted)
break;
p++;
}
if (quoted)
{
"vacation: badly formatted \"From \" line.\n");
}
*p = '\0';
/* ok since both strings have MAXLINE length */
if (*From == '\0')
sizeof From);
*p = '\0';
}
break;
case 'P': /* "Precedence:" */
case 'p':
cont = false;
break;
break;
if (*p == '\0')
break;
break;
case 'C': /* "Cc:" */
case 'c':
break;
cont = true;
goto findme;
case 'T': /* "To:" */
case 't':
break;
cont = true;
goto findme;
default:
{
cont = false;
break;
}
}
}
if (!tome)
if (*From == '\0')
{
}
}
/*
** NSEARCH --
** do a nice, slow, search of a string for a substring.
**
** Parameters:
** name -- name to search.
** str -- string in which to search.
**
** Returns:
** is name a substring of str?
**
*/
static bool
{
register char *s;
for (s = str; *s != '\0'; ++s)
{
/*
** Check to make sure that the string matches and
** the previous character is not an alphanumeric and
** the next character after the match is not an alphanumeric.
**
** This prevents matching "eric" to "derick" while still
** matching "eric" to "<eric+detail>".
*/
return true;
}
return false;
}
/*
** JUNKMAIL --
**
** Parameters:
** from -- sender address.
**
** Returns:
**
*/
struct ignore
{
char *name;
};
/* delimiters for the local part of an address */
static bool
char *from;
{
bool quot;
char *e;
{
{ "postmaster", 10 },
{ "uucp", 4 },
{ "mailer-daemon", 13 },
{ "mailer", 6 },
{ NULL, 0 }
};
{
{ "-request", 8 },
{ "-relay", 6 },
{ "-owner", 6 },
{ NULL, 0 }
};
{
{ "owner-", 6 },
{ NULL, 0 }
};
/*
** This is mildly amusing, and I'm not positive it's right; trying
** to find the "real" name of the sender, assuming that addresses
** will be some variant of:
**
** From site!site!SENDER%site.domain%site.domain@site.domain
*/
quot = false;
e = from;
len = 0;
{
if (*e == '"')
{
++e;
continue;
}
if (*e == '\\')
{
if (*(++e) == '\0')
{
/* '\\' at end of string? */
break;
}
if (len < MAX_USER_LEN)
++e;
continue;
}
if (*e == '!' && !quot)
{
len = 0;
}
else
if (len < MAX_USER_LEN)
++e;
}
if (len < MAX_USER_LEN)
else
if (len <= 0)
return false;
#if 0
if (quot)
return false; /* syntax error... */
#endif /* 0 */
/* test prefixes */
{
return true;
}
/*
** If the name is truncated, don't test the rest.
** We could extract the "tail" of the sender address and
** compare it it ignorepost, however, it seems not worth
** the effort.
** The address surely can't match any entry in ignore[]
** (as long as all of them are shorter than MAX_USER_LEN).
*/
if (len > MAX_USER_LEN)
return false;
/* test full local parts */
{
return true;
}
/* test postfixes */
{
return true;
}
return false;
}
/*
** RECENT --
** find out if user has gotten a vacation message recently.
**
** Parameters:
** none.
**
** Returns:
** true iff user has gotten a vacation message recently.
**
*/
static bool
recent()
{
bool trydomain = false;
int st;
char *domain;
/* get interval time */
else
/* get record for this address */
do
{
{
return true;
}
{
}
} while (trydomain);
return false;
}
/*
** SETINTERVAL --
** store the reply interval
**
** Parameters:
** interval -- time interval for replies.
**
** Returns:
** nothing.
**
** Side Effects:
** stores the reply interval in database.
*/
static void
{
}
/*
** SETREPLY --
** store that this user knows about the vacation.
**
** Parameters:
** from -- sender address.
** when -- last reply time.
**
** Returns:
** nothing.
**
** Side Effects:
*/
static void
char *from;
{
}
/*
** XCLUDE --
** add users to vacation db so they don't get a reply.
**
** Parameters:
** f -- file pointer with list of address to exclude
**
** Returns:
** nothing.
**
** Side Effects:
** stores users in database.
*/
static void
xclude(f)
SM_FILE_T *f;
{
if (f == NULL)
return;
{
*p = '\0';
}
}
/*
** SENDMESSAGE --
** exec sendmail to send the vacation file to sender
**
** Parameters:
** myname -- user name.
** msgfn -- name of file with vacation message.
** sender -- use as sender address
**
** Returns:
** nothing.
**
** Side Effects:
** sends vacation reply.
*/
static void
char *myname;
char *msgfn;
char *sender;
{
int i;
{
if (msgfn[0] == '/')
else
}
{
}
pv[0] = "sendmail";
else
i = fork();
if (i < 0)
{
}
if (i == 0)
{
}
/* check return status of the following calls? XXX */
(void *) &(pvect[1]),
{
#if _FFR_VAC_WAIT4SM
# ifdef WAITUNION
# else /* WAITUNION */
auto int st;
# endif /* WAITUNION */
#endif /* _FFR_VAC_WAIT4SM */
"Auto-Submitted: auto-replied\n");
#if _FFR_VAC_WAIT4SM
#endif /* _FFR_VAC_WAIT4SM */
}
else
{
}
}
static void
usage()
{
"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",
getuid());
}
/*
** LISTDB -- list the contents of the vacation database
**
** Parameters:
** none.
**
** Returns:
** nothing.
*/
static void
listdb()
{
int result;
time_t t;
{
"vacation: set cursor: %s\n",
return;
}
SMDB_CURSOR_GET_NEXT)) == SMDBE_OK)
{
char *timestamp;
/* skip magic VIT entry */
continue;
/* skip bogus values */
{
"vacation: %.*s invalid time stamp\n",
continue;
}
if (t <= 0)
{
/* must be an exclude */
timestamp = "(exclusion)\n";
}
else
{
}
}
{
"vacation: get value at cursor: %s\n",
{
}
return;
}
}
/*
** DEBUGLOG -- write message to standard error
**
** Append a message to the standard error for the convenience of
** end-users debugging without access to the syslog messages.
**
** Parameters:
** i -- syslog log level
** fmt -- string format
**
** Returns:
** nothing.
*/
/*VARARGS2*/
static SYSLOG_RET_T
#ifdef __STDC__
#else /* __STDC__ */
int i;
const char *fmt;
#endif /* __STDC__ */
{
}