Use sendmail's version of vacation. It is command line and database

compatible with the old version but includes new functionality and bug fixes.

Since it is not part of the NO_SENDMAIL make.conf option, libsmdb and
libsmutil should always be built for vacation's sake.

PR:		15227
This commit is contained in:
Gregory Neil Shapiro 2000-10-10 18:14:30 +00:00
parent 1e1c8c164c
commit 8108227d7f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=66943
4 changed files with 32 additions and 735 deletions

View File

@ -26,7 +26,7 @@ SUBDIR= ${_csu} libcom_err ${_libcrypt} msun libmd \
libftpio libgnumalloc ${_libio} libipsec libipx libkvm libmenu \
${_libncp} \
libnetgraph libopie libpam libpanel libpcap \
libposix1e libresolv librpcsvc ${_libsmdb} libss ${_libsmutil} \
libposix1e libresolv librpcsvc libsmdb libss libsmutil \
libstand ${_libtelnet} libusb ${_libvgl} libwrap libxpg4 liby libz
.if exists(${.CURDIR}/csu/${MACHINE_ARCH}-${OBJFORMAT})
@ -43,11 +43,6 @@ _libc_r= libc_r
_libbind= libbind
.endif
.if !defined(NO_SENDMAIL)
_libsmdb= libsmdb
_libsmutil= libsmutil
.endif
_libcrypt= libcrypt
.if exists(${.CURDIR}/../secure) && !defined(NOSECURE) && !defined(NOCRYPT) && !defined(NO_DESCRYPT)
# Build both libraries. They have different names, so no harm,

View File

@ -1,7 +1,36 @@
# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
# $FreeBSD$
SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail
.PATH: ${SENDMAIL_DIR}/vacation
PROG= vacation
CFLAGS+= -Wall
SRCS= vacation.c
MAN8= vacation.1
CFLAGS+=-I${SENDMAIL_DIR}/src -I${SENDMAIL_DIR}/include
CFLAGS+=-DNEWDB -DNOT_SENDMAIL
CFLAGS+=-D_FFR_LISTDB -D_FFR_DEBUG
.if exists(${.OBJDIR}/../../lib/libsmdb)
LIBSMDBDIR:= ${.OBJDIR}/../../lib/libsmdb
.else
LIBSMDBDIR!= cd ${.CURDIR}/../../lib/libsmdb; make -V .OBJDIR
.endif
LIBSMDB:= ${LIBSMDBDIR}/libsmdb.a
.if exists(${.OBJDIR}/../../lib/libsmutil)
LIBSMUTILDIR:= ${.OBJDIR}/../../lib/libsmutil
.else
LIBSMUTILDIR!= cd ${.CURDIR}/../../lib/libsmutil; make -V .OBJDIR
.endif
LIBSMUTIL:= ${LIBSMUTILDIR}/libsmutil.a
DPADD+= ${LIBSMDB} ${LIBSMUTIL}
LDADD+= ${LIBSMDB} ${LIBSMUTIL}
# User customizations to the sendmail build environment
CFLAGS+=${SENDMAIL_CFLAGS}
LDFLAGS+=${SENDMAIL_LDFLAGS}
LDADD+=${SENDMAIL_LDADD}
DPADD+=${SENDMAIL_DPADD}
.include <bsd.prog.mk>

View File

@ -1,202 +0,0 @@
.\" Copyright (c) 1985, 1987, 1990, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" From: @(#)vacation.1 8.1 (Berkeley) 6/16/93
.\" $FreeBSD$
.\"
.Dd June 16, 1993
.Dt VACATION 1
.Os BSD 4.3
.Sh NAME
.Nm vacation
.Nd return ``I am not here'' indication
.Sh SYNOPSIS
.Nm vacation
.Op Fl d
.Fl i
.Op Fl r Ar interval
.Nm vacation
.Op Fl d
.Fl l
.Nm vacation
.Op Fl d
.Op Fl a Ar alias
.Ar login
.Sh DESCRIPTION
.Nm Vacation
returns a message to the sender of a message telling them that you
are currently not reading your mail. The intended use is in a
.Pa .forward
file. For example, your
.Pa .forward
file might have:
.Bd -literal -offset indent
\eeric, "|/usr/bin/vacation -a allman eric"
.Ed
which would send messages to you (assuming your login name was eric) and
reply to any messages for
.Dq eric
or
.Dq allman .
.Pp
Available options:
.Bl -tag -width Ds
.It Fl a Ar alias
Handle messages for
.Ar alias
in the same manner as those received for the user's
login name.
.It Fl d
Enable debugging mode.
See below.
.It Fl i
Initialize the vacation database files. It should be used
before you modify your
.Pa .forward
file.
.It Fl r
Set the reply interval to
.Ar interval
days. The default is one week. An interval of
.Dq 0
means that
a reply is sent to each message, and an interval of
.Dq Li infinite
(actually, any non-numeric character) will never send more than
one reply. It should be noted that intervals of
.Dq Li \&0
are quite
dangerous, as it allows mailers to get into
.Dq I am on vacation
loops.
.It Fl l
Print the contents of the vacation database files. For each entry,
the address the reply has been sent to and the associated time will
be printed to standard output.
.El
.Pp
No message will be sent unless
.Ar login
(or an
.Ar alias
supplied using the
.Fl a
option) is part of either the
.Dq To:
or
.Dq Cc:
headers of the mail.
No messages from
.Dq ???-REQUEST ,
.Dq Postmaster ,
.Dq Tn UUCP ,
.Dq MAILER ,
or
.Dq MAILER-DAEMON
will be replied to (where these strings are
case insensitive) nor is a notification sent if a
.Dq Precedence: bulk
or
.Dq Precedence: junk
line is included in the mail headers.
The people who have sent you messages are maintained as a
.Xr hash 3
database in the file
.Pa .vacation.db
in your home directory.
.Pp
.Nm Vacation
expects a file
.Pa .vacation.msg ,
in your home directory, containing a message to be sent back to each
sender. It should be an entire message (including headers). For
example, it might contain:
.Pp
.Bd -unfilled -offset indent -compact
From: eric@CS.Berkeley.EDU (Eric Allman)
Subject: I am on vacation
Delivered-By-The-Graces-Of: The Vacation program
Precedence: bulk
I am on vacation until July 22. If you have something urgent,
please contact Keith Bostic <bostic@CS.Berkeley.EDU>.
--eric
.Ed
.Pp
.Nm Vacation
reads the first line from the standard input for a
.Ux
.Dq From
line to determine the sender.
.Xr Sendmail 8
includes this
.Dq From
line automatically.
.Pp
Fatal errors, such as calling
.Nm vacation
with incorrect arguments, or with non-existent
.Ar login Ns Ar s ,
are logged in the system log file, using
.Xr syslog 3
unless debugging mode is enabled with the
.Fl d
option, in which case they are written to the standard error output.
.Pp
Building on the example provided above, you might choose to have errors
redirected to a file while you are testing vacation's operation with
the following in your
.Pa .forward
file:
.Pp
.Bd -literal -offset indent
\eeric, "|/bin/sh -c '/usr/bin/vacation -d -a allman eric' 2>/home/eric/.vacation.log"
.Ed
.Sh DIAGNOSTICS
The
.Nm
utility exits 0 on success, and >0 if an error occurs.
.Sh FILES
.Bl -tag -width "vacation.dirxxx" -compact
.It Pa ~/.vacation.db
database file
.It Pa ~/.vacation.msg
message to send
.El
.Sh SEE ALSO
.Xr syslog 3 ,
.Xr sendmail 8 ,
.Xr syslogd 8
.Sh HISTORY
The
.Nm vacation
command appeared in
.Bx 4.3 .

View File

@ -1,525 +0,0 @@
/*
* Copyright (c) 1983, 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static const char copyright[] =
"@(#) Copyright (c) 1983, 1987, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)from: vacation.c 8.2 (Berkeley) 1/26/94";
#endif
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
/*
** Vacation
** Copyright (c) 1983 Eric P. Allman
** Berkeley, California
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pwd.h>
#include <db.h>
#include <time.h>
#include <syslog.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <paths.h>
/*
* 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 MAXLINE 1024 /* max line from mail header */
#define VDB ".vacation.db" /* dbm's database */
#define VMSG ".vacation.msg" /* vacation message */
typedef struct alias {
struct alias *next;
char *name;
} ALIAS;
ALIAS *names;
DB *db;
char from[MAXLINE];
void (*msglog)(int, const char *, ...) = &syslog;
static int isdelim __P((int));
static int junkmail __P((void));
static void listdb __P((void));
static int nsearch __P((char *, char *));
static void readheaders __P((void));
static int recent __P((void));
static void sendmessage __P((char *));
static void setinterval __P((time_t));
static void setreply __P((void));
static void usage __P((void));
static void debuglog __P((int, const char *, ...));
int
main(argc, argv)
int argc;
char **argv;
{
struct passwd *pw;
ALIAS *cur;
time_t interval;
int ch, iflag, lflag, mfail, ufail;
opterr = iflag = lflag = mfail = ufail = 0;
interval = -1;
while ((ch = getopt(argc, argv, "a:dIilr:")) != -1) {
switch((char)ch) {
case 'a': /* alias */
if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS)))) {
mfail++;
break;
}
cur->name = optarg;
cur->next = names;
names = cur;
break;
case 'd': /* debug mode */
msglog = &debuglog;
break;
case 'I': /* backward compatible */
case 'i': /* init the database */
iflag = 1;
break;
case 'l':
lflag = 1; /* list the database */
break;
case 'r':
if (isdigit(*optarg)) {
interval = atol(optarg) * 86400;
if (interval < 0)
ufail++;
}
else
interval = LONG_MAX;
break;
case '?':
default:
ufail++;
}
}
/*
* Only die on the above malloc and usage errors here so that the
* correct logging medium is used.
*/
if (mfail) {
msglog(LOG_ERR, "vacation: malloc failed\n");
exit(EX_TEMPFAIL);
}
else if (ufail)
usage();
argc -= optind;
argv += optind;
if (argc != 1) {
if (!iflag && !lflag)
usage();
if (!(pw = getpwuid(getuid()))) {
msglog(LOG_ERR,
"vacation: no such user uid %u.\n", getuid());
exit(1);
}
}
else if (!(pw = getpwnam(*argv))) {
msglog(LOG_ERR, "vacation: no such user %s.\n", *argv);
exit(1);
}
if (chdir(pw->pw_dir)) {
msglog(LOG_NOTICE,
"vacation: no such directory %s.\n", pw->pw_dir);
exit(1);
}
db = dbopen(VDB, O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0),
S_IRUSR|S_IWUSR, DB_HASH, NULL);
if (!db) {
msglog(LOG_NOTICE, "vacation: %s: %s\n", VDB, strerror(errno));
exit(1);
}
if (lflag)
listdb();
else if (interval != -1)
setinterval(interval);
if (iflag || lflag) {
(void)(db->close)(db);
exit(0);
}
if (!(cur = malloc((u_int)sizeof(ALIAS)))) {
msglog(LOG_ERR, "vacation: malloc failed\n");
exit(EX_TEMPFAIL);
}
cur->name = pw->pw_name;
cur->next = names;
names = cur;
readheaders();
if (!recent()) {
setreply();
(void)(db->close)(db);
sendmessage(pw->pw_name);
}
else
(void)(db->close)(db);
exit(0);
/* NOTREACHED */
}
/*
* readheaders --
* read mail headers
*/
static void
readheaders()
{
register ALIAS *cur;
register char *p;
int tome, cont;
char buf[MAXLINE];
cont = tome = 0;
while (fgets(buf, sizeof(buf), stdin) && *buf != '\n')
switch(*buf) {
case 'F': /* "From " */
cont = 0;
if (!strncmp(buf, "From ", 5)) {
for (p = buf + 5; *p && *p != ' '; ++p);
*p = '\0';
(void)strcpy(from, buf + 5);
if ((p = index(from, '\n')))
*p = '\0';
if (junkmail())
exit(0);
}
break;
case 'P': /* "Precedence:" */
cont = 0;
if (strncasecmp(buf, "Precedence", 10) ||
(buf[10] != ':' && buf[10] != ' ' && buf[10] != '\t'))
break;
if (!(p = index(buf, ':')))
break;
while (*++p && isspace(*p));
if (!*p)
break;
if (!strncasecmp(p, "junk", 4) ||
!strncasecmp(p, "bulk", 4) ||
!strncasecmp(p, "list", 4))
exit(0);
break;
case 'C': /* "Cc:" */
if (strncmp(buf, "Cc:", 3))
break;
cont = 1;
goto findme;
case 'T': /* "To:" */
if (strncmp(buf, "To:", 3))
break;
cont = 1;
goto findme;
default:
if (!isspace(*buf) || !cont || tome) {
cont = 0;
break;
}
findme: for (cur = names; !tome && cur; cur = cur->next)
tome += nsearch(cur->name, buf);
}
if (!tome)
exit(0);
if (!*from) {
msglog(LOG_NOTICE, "vacation: no initial \"From\" line.\n");
exit(1);
}
}
/*
* nsearch --
* do a nice, slow, search of a string for a substring.
*/
static int
nsearch(name, str)
register char *name, *str;
{
register int len;
for (len = strlen(name); *str; ++str)
if (*str == *name &&
!strncasecmp(name, str, len) &&
isdelim((unsigned char)str[len]))
return(1);
return(0);
}
/*
* junkmail --
* read the header and return if automagic/junk/bulk/list mail
*/
static int
junkmail()
{
static struct ignore {
char *name;
int len;
} ignore[] = {
{"-request", 8}, {"postmaster", 10}, {"uucp", 4},
{"mailer-daemon", 13}, {"mailer", 6}, {"-relay", 6},
{NULL, 0},
};
register struct ignore *cur;
register int len;
register char *p;
/*
* 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
*/
if (!(p = index(from, '%')))
if (!((p = index(from, '@')))) {
if ((p = rindex(from, '!')))
++p;
else
p = from;
for (; *p; ++p);
}
len = p - from;
for (cur = ignore; cur->name; ++cur)
if (len >= cur->len &&
!strncasecmp(cur->name, p - cur->len, cur->len))
return(1);
return(0);
}
#define VIT "__VACATION__INTERVAL__TIMER__"
/*
* recent --
* find out if user has gotten a vacation message recently.
* use bcopy for machines with alignment restrictions
*/
static int
recent()
{
DBT key, data;
time_t then, next;
/* get interval time */
key.data = VIT;
key.size = sizeof(VIT);
if ((db->get)(db, &key, &data, 0))
next = 86400 * 7;
else
bcopy(data.data, &next, sizeof(next));
/* get record for this address */
key.data = from;
key.size = strlen(from);
if (!(db->get)(db, &key, &data, 0)) {
bcopy(data.data, &then, sizeof(then));
if (next == LONG_MAX || then + next > time(NULL))
return(1);
}
return(0);
}
/*
* setinterval --
* store the reply interval
*/
static void
setinterval(interval)
time_t interval;
{
DBT key, data;
key.data = VIT;
key.size = sizeof(VIT);
data.data = &interval;
data.size = sizeof(interval);
(void)(db->put)(db, &key, &data, 0);
}
/*
* setreply --
* store that this user knows about the vacation.
*/
static void
setreply()
{
DBT key, data;
time_t now;
key.data = from;
key.size = strlen(from);
(void)time(&now);
data.data = &now;
data.size = sizeof(now);
(void)(db->put)(db, &key, &data, 0);
}
/*
* sendmessage --
* exec sendmail to send the vacation file to sender
*/
static void
sendmessage(myname)
char *myname;
{
FILE *mfp, *sfp;
int i;
int pvect[2];
char buf[MAXLINE];
mfp = fopen(VMSG, "r");
if (mfp == NULL) {
msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", myname, VMSG);
exit(1);
}
if (pipe(pvect) < 0) {
msglog(LOG_ERR, "vacation: pipe: %s", strerror(errno));
exit(1);
}
i = fork();
if (i < 0) {
msglog(LOG_ERR, "vacation: fork: %s", strerror(errno));
exit(1);
}
if (i == 0) {
dup2(pvect[0], 0);
close(pvect[0]);
close(pvect[1]);
close(fileno(mfp));
execl(_PATH_SENDMAIL, "sendmail", "-f", myname, "--", from, NULL);
msglog(LOG_ERR, "vacation: can't exec %s: %s",
_PATH_SENDMAIL, strerror(errno));
_exit(1);
}
close(pvect[0]);
sfp = fdopen(pvect[1], "w");
fprintf(sfp, "To: %s\n", from);
while (fgets(buf, sizeof buf, mfp))
fputs(buf, sfp);
fclose(mfp);
fclose(sfp);
}
static void
usage()
{
msglog(LOG_NOTICE, "uid %u: usage: vacation [-d] [-i [-rinterval]] [-l] [-a alias] login\n",
getuid());
exit(1);
}
static void
listdb()
{
DBT key, data;
int rv;
time_t t;
char user[MAXLINE];
while((rv = db->seq(db, &key, &data, R_NEXT)) == 0) {
bcopy(key.data, user, key.size);
user[key.size] = '\0';
if (strcmp(user, VIT) == 0)
continue;
bcopy(data.data, &t, data.size);
printf("%-40s %-10s", user, ctime(&t));
}
if (rv == -1)
perror("IO error in database");
}
/*
* Is `c' a delimiting character for a recipient name?
*/
static int
isdelim(c)
int c;
{
/*
* NB: don't use setlocale() before, headers are supposed to
* consist only of ASCII (aka. C locale) characters.
*/
if (isalnum(c))
return(0);
if (c == '_' || c == '-' || c == '.')
return(0);
return(1);
}
/*
* Append a message to the standard error for the convenience of end-users
* debugging without access to the syslog messages.
*/
static void
debuglog(int i, const char *fmt, ...)
{
va_list ap;
i = 0; /* Printing syslog priority not implemented */
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}