--- vacation-1.2.7.1/Makefile | 11 -- vacation-1.2.7.1/vacation-en.man | 38 +++++++ vacation-1.2.7.1/vacation.c | 195 ++++++++++++++++++++++++++++++++------- vacation-1.2.7.1/vaclook | 16 --- 4 files changed, 199 insertions(+), 61 deletions(-) --- vacation-1.2.7.1/Makefile +++ vacation-1.2.7.1/Makefile 2017-02-01 09:10:03.746060561 +0000 @@ -13,17 +13,8 @@ CFLAGS = $(RPM_OPT_FLAGS) -g -Wall ifeq "$(ARCH)" "x86_64" # Uncomment below for backwards compatibility of gdbm files. # CFLAGS = $(CFLAGS) -m32 -else -ifeq "$(ARCH)" "ppc" - CFLAGS = $(CFLAGS) -fsigned-char -else -ifeq "$(ARCH)" "ppc64" - CFLAGS = $(CFLAGS) -fsigned-char -endif -endif endif -LFLAGS = -Xlinker -warn-common IFLAGS = LIBS = -lgdbm @@ -45,7 +36,7 @@ endif BINDIR = $(PREFIX)/bin VACATION = $(BINDIR)/vacation VACLOOK = $(BINDIR)/vaclook -MANDIR = $(PREFIX)/man/man +MANDIR = $(PREFIX)/share/man/man MANEXT1 = 1 VERSION = 1 --- vacation-1.2.7.1/vacation-en.man +++ vacation-1.2.7.1/vacation-en.man 2017-02-01 09:10:03.746060561 +0000 @@ -25,8 +25,9 @@ vacation \- reply to mail automatically .SH SYNOPSIS .B vacation [ -.B \-I | \-i -] +.B \-I | \-i | \-l +] [ +.B \-F .br .B vacation [ @@ -48,6 +49,7 @@ vacation \- reply to mail automatically .B \-? ] .I username +.br .SH DESCRIPTION .IX vacation "" "\fLvacation\fR \(em automatic mail replies" .LP @@ -162,9 +164,39 @@ Initialize the .B \&.vacation.db file and start .BR vacation . +This should only be used on the command line, not +in the +.B \&.forward +file. +.TP +.B \-F +Force creation of +.B \&.vacation.db +even if the +.B $\s-1HOME +directory is identified as a NFS file system. +Please note that the used data base is not portable +between 32bit and 64bit architectures and also not +portable between little and big endianess architectures +even same bit-wide is used for. Therefore the +initial creation of the +.B \&/.vacation.db +should always happen on the server used for receiving +mails for the specific user. +.TP +.B \-l +List the content of the vacation database file +including the address and the associated time of +the last auto-response to that address. +This should only be used on the command line, not +in the +.B \&.forward +file. .LP If the -.B \-I +.BR \-I, \ \-i +or +.B \-l flag is not specified, and a .I user argument is given, --- vacation-1.2.7.1/vacation.c +++ vacation-1.2.7.1/vacation.c 2017-02-01 09:16:24.158138617 +0000 @@ -76,6 +76,7 @@ static char rcsid[] __attribute__ ((unus #include #include +#include #include #include #include @@ -91,6 +92,13 @@ static char rcsid[] __attribute__ ((unus #include "tzfile.h" #include "vacation.h" +static void eatmsg (void); +#define EXITIT(excode) { eatmsg(); if (db) gdbm_close(db); exit(excode);} +#define EXITM(excode) { if (!iflag & !lflag) eatmsg(); if (db) gdbm_close(db); exit(excode); } +#ifndef NFS_SUPER_MAGIC +# define NFS_SUPER_MAGIC 0x6969 +#endif + /* Extern definitions for getopt(3) */ extern int optind, opterr; extern char *optarg; @@ -110,14 +118,15 @@ main (int argc, char **argv) struct passwd *pw; ALIAS *cur; time_t interval; - int ch, iflag, nflag; + int ch, iflag, nflag, mfail, lflag, fflag, flags; char *vacation; char *vdomain; char *vusername; char tmpusername[ 1024 ]; openlog ("vacation", LOG_PID, LOG_MAIL); - opterr = iflag = nflag = rflag = 0; + db = (GDBM_FILE)0; + opterr = iflag = nflag = rflag = mfail = lflag = fflag = 0; interval = -1; vdomain = NULL; #ifdef _PATH_VACATION @@ -125,16 +134,16 @@ main (int argc, char **argv) #else vacation = argv[0]; #endif - if (argc == 1) + if (argc == 1 || (argc == 2 && (strcmp(argv[1], "-F") == 0))) nflag = 1; - while ((ch = getopt (argc, argv, "a:h:Iit:jrv")) != EOF) + while ((ch = getopt (argc, argv, "a:h:Iit:jrlF")) != EOF) switch ((char) ch) { case 'a': /* alias */ if (!(cur = (ALIAS *) malloc ((u_int) sizeof (ALIAS)))) { - perror ("malloc"); - exit (-1); + mfail++; + break; } cur->name = optarg; cur->next = names; @@ -163,6 +172,12 @@ main (int argc, char **argv) case 'r': /* "Reply-To:" overrides "From:" */ rflag = 1; break; + case 'l': /* List ~/vacation.db */ + lflag = 1; + break; + case 'F': /* Force creation of ~/vacation.db on NFS HOME */ + fflag = 1; + break; case 'v': /* Output vacation version number */ printf ("Linux Vacation %s\n", VACVERS); exit (0); @@ -175,32 +190,68 @@ main (int argc, char **argv) argc -= optind; argv += optind; + if (mfail) { + syslog(LOG_NOTICE, "vacation: can't allocate memory for alias.\n"); + closelog(); + EXITM(-1); + } + if (argc != 1) { - if (!iflag && !nflag) + if (!iflag && !nflag && !lflag) usage (); if (!(pw = getpwuid (getuid ()))) { syslog (LOG_ERR, "vacation: no such user uid %u.\n", getuid ()); - exit (1); + closelog(); + EXITM(1); } } else if (!(pw = getpwnam (*argv))) { snprintf( tmpusername, 1023, "%s", *argv ); syslog (LOG_ERR, "vacation: no such user %s.\n", tmpusername); - exit (1); + closelog(); + EXITM(1); } if (chdir (pw->pw_dir)) { syslog (LOG_NOTICE, "vacation: no such directory %s.\n", pw->pw_dir); - exit (1); + closelog(); + EXITM(1); } + if (iflag || nflag) { + struct statfs fs; + flags = GDBM_NEWDB; + if (fflag == 0) { + if (statfs(pw->pw_dir, &fs) < 0) { + syslog(LOG_ERR, "vacation: can not stat %s %s.\n", pw->pw_dir, strerror(errno)); + closelog(); + EXITM(1); + } + if (fs.f_type == NFS_SUPER_MAGIC) { + fprintf(stderr, "vacation: Warning %s is mounted via NFS which may cause\n" + " a corrupted ~/.vacation.db database file!\n\n" + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n" + "Please run vacation on the mail delivering server, which is\n" + "normally the NFS server, or retry with the added option -F to\n" + "force the creation of ~/.vacation.db\n\n" + ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n", + pw->pw_dir); + syslog(LOG_NOTICE, "vacation: no database on NFS file system created\n"); + closelog(); + EXITM(1); + } + } + } else if (lflag) + flags = GDBM_READER|GDBM_NOLOCK; + else + flags = GDBM_WRITER; + do { - db = gdbm_open ((char *) VDB, 128, ((iflag || nflag) ? GDBM_NEWDB : GDBM_WRITER), - 0644, NULL); + db = gdbm_open ((char *) VDB, 128, flags, 0644, NULL); if (!db && errno == ENOENT) { db = gdbm_open ((char *) VDB, 128, GDBM_NEWDB, 0644, NULL); @@ -210,12 +261,56 @@ main (int argc, char **argv) } while (!db && errno == EAGAIN); - if (!db) - { - syslog (LOG_NOTICE, "vacation: %s: %s\n", VDB, strerror (errno)); - exit (1); + if (!db) { + char *errm; + if (errno == 0) + errm = gdbm_strerror(gdbm_errno); + else + errm = gdbm_strerror(errno); + if (lflag || iflag || nflag) { + fprintf(stderr, "vacation: %s: %s\n", (char *) VDB, errm); + close(0); + } + syslog(LOG_NOTICE, "vacation: %s: %s\n", (char *) VDB, errm); + closelog(); + EXITM(1); + } + + if (lflag) { + datum key, next = gdbm_firstkey (db); + + while(next.dptr) { + key = next; + next = gdbm_nextkey(db, key); + + if (key.dptr) { + datum data = gdbm_fetch(db, key); + + if (data.dptr) { + time_t was; + + if (data.dsize == (sizeof(was) >> 1)) { + /* We read on 64bit system 32bit time_t input */ + int32_t in; + + bzero(&was, sizeof(was)); + bcopy(data.dptr, &in, sizeof(in)); + was = (time_t)in; + } else + bcopy(data.dptr, &was, sizeof(was)); + + printf("%-36.*s %.36s", key.dsize, key.dptr, ctime(&was)); + free(data.dptr); + } + + free(key.dptr); + } } + (void) gdbm_close(db); + exit(0); + } + if (interval != -1) setinterval (interval); @@ -232,8 +327,11 @@ main (int argc, char **argv) exit (0); } - if (!(cur = (ALIAS *) malloc ((u_int) sizeof (ALIAS)))) - exit (1); + if (!(cur = (ALIAS *) malloc ((u_int) sizeof (ALIAS)))) { + syslog(LOG_NOTICE, "vacation: can't allocate memory for username.\n"); + closelog(); + EXITM(-1); + } cur->name = pw->pw_name; cur->next = names; names = cur; @@ -250,8 +348,9 @@ main (int argc, char **argv) { /* add virtual domain to username */ if (!(vusername = (char *) malloc (MAXLINE))) { - perror ("malloc"); - exit (-1); + syslog(LOG_NOTICE, "vacation: cant' allocation memory for virtual domain.\n"); + closelog(); + EXITM(-1); } (void) strlcpy (vusername, pw->pw_name, MAXLINE); strlcat (vusername, "@", MAXLINE); @@ -266,10 +365,17 @@ main (int argc, char **argv) } else (void) gdbm_close (db); + closelog(); exit (0); /* NOTREACHED */ } +static void eatmsg() +{ + while(getc(stdin) != EOF) + continue; +} + /* * readheaders -- * read mail headers @@ -322,7 +428,7 @@ readheaders (void) *p = '\0'; } else - exit (1); /* this should not occur */ + EXITIT (1); /* this should not occur */ if ((p = rindex (uucpfrom, '!'))) strlcat (from, p + 1, MAXLINE); else @@ -333,7 +439,7 @@ readheaders (void) printd (logline); #endif if (junkmail ()) - exit (0); + EXITIT (0); break; case 'R': /* "Reply-To: " */ cont = 0; @@ -345,7 +451,7 @@ readheaders (void) printd (logline); #endif if (junkmail ()) - exit (0); + EXITIT (0); } break; case 'S': /* "Subject" */ @@ -360,7 +466,7 @@ readheaders (void) printd (logline); #endif if (junkmail ()) - exit (0); + EXITIT (0); } break; case 'P': /* "Precedence:" */ @@ -375,7 +481,7 @@ readheaders (void) break; if (!strncasecmp (p, "junk", 4) || !strncasecmp (p, "list", 4) || !strncasecmp (p, "bulk", 4)) - exit (0); + EXITIT (0); break; case 'A': /* "Auto-Submitted:" */ cont = 0; @@ -388,8 +494,12 @@ readheaders (void) if (!*p) break; if (strncasecmp (p, "no", 2)) - exit (0); + EXITIT (0); break; + case 'X': /* "To:" */ + cont = 0; + if (strncasecmp(buf, "X-Spam-Flag: YES", 16) == 0) + EXITIT (0); case 'C': /* "Cc:" */ if (strncasecmp (buf, "Cc:", 3)) break; @@ -400,10 +510,6 @@ readheaders (void) break; cont = 1; goto findme; - case 'X': /* Don't reply to email marked as spam by SpamAssassin */ - if (!strncasecmp (buf, "X-Spam-Status: Yes", 18)) - exit (0); - break; default: if (!isspace (*buf) || !cont || tome) { @@ -413,13 +519,15 @@ readheaders (void) findme: for (cur = names; !tome && cur; cur = cur->next) tome += nsearch (cur->name, buf); - } + } /* switch(toupper(*buf)) */ + if (!jflag && !tome) - exit (0); + EXITIT (0); if (!*from) { syslog (LOG_NOTICE, "vacation: no \"From:\" line.\n"); - exit (2); + closelog(); + EXITIT (2); } if (rflag && (*replyto != 0x0)) strlcpy (from, replyto, MAXLINE); @@ -503,7 +611,19 @@ junkmail (void) { "-programmers", 12}, { - NULL, 0},}; + "bugzilla-daemon", 15}, + { + "noreply", 7}, + { + "no-reply", 8}, + { + "info", 4}, + { + "nobody", 6}, + { + "keine.Antwort", 13}, + { + NULL, 0},}; register struct ignore *cur; register int len; register char *p; @@ -609,6 +729,7 @@ setreply (void) /* * sendmessage -- * exec sendmail to send the vacation file to sender + * A "Precedence: bulk" header is automatically added to the message. */ void sendmessage (char *myname, char *myrealname) @@ -628,17 +749,20 @@ sendmessage (char *myname, char *myrealn if (mfp == NULL) { syslog (LOG_NOTICE, "vacation: no ~%s/%s file.\n", myname, VMSG); + closelog(); exit (1); } if (pipe (pvect) < 0) { syslog (LOG_ERR, "vacation: pipe: %s", strerror (errno)); + closelog(); exit (1); } i = fork (); if (i < 0) { syslog (LOG_ERR, "vacation: fork: %s", strerror (errno)); + closelog(); exit (1); } if (i == 0) @@ -651,6 +775,7 @@ sendmessage (char *myname, char *myrealn NULL); syslog (LOG_ERR, "vacation: can't exec %s: %s", _PATH_SENDMAIL, strerror (errno)); + closelog(); exit (1); } close (pvect[0]); @@ -699,7 +824,7 @@ sendmessage (char *myname, char *myrealn void usage (void) { - puts ("usage: vacation [ -I ]"); + puts ("usage: vacation [ -I | -i | -l ] [ -F ]"); puts ("or: vacation [ -j ] [ -a alias ] [ -h hostname ] [ -tN ] [ -r ] login"); exit (1); --- vacation-1.2.7.1/vaclook +++ vacation-1.2.7.1/vaclook 2017-02-01 09:10:03.746060561 +0000 @@ -1,14 +1,4 @@ -#!/usr/bin/perl +#!/bin/sh # -# $Id$ - -require 5; # This script requires Perl v5. -use GDBM_File; # Format that 'vacation' uses. - -# Associate the file with local hash. -tie (%vacdb, GDBM_File, "$ENV{'HOME'}/.vacation.db", 0, undef); - -# Dump the contents (with converted time-stamps). -map { - printf ("%-36s %.36s\n", "$_:", scalar (localtime (unpack ('i', $vacdb{$_})))) - } sort keys %vacdb; +# +exec /usr/bin/vacation -lF