vacation.c revision 173340
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 23173340SgshapiroSM_IDSTR(id, "@(#)$Id: vacation.c,v 8.144 2007/05/11 18:50:36 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; 49173340Sgshapirogid_t RunAsGid; 5064562Sgshapirochar *RunAsUserName; 5164562Sgshapiroint Verbose = 2; 5290792Sgshapirobool DontInitGroups = false; 5364562Sgshapirouid_t TrustedUid = 0; 5464562SgshapiroBITMAP256 DontBlameSendmail; 5564562Sgshapiro 56168515Sgshapirostatic int readheaders __P((bool)); 57168515Sgshapirostatic bool junkmail __P((char *)); 58168515Sgshapirostatic bool nsearch __P((char *, char *)); 59168515Sgshapirostatic void usage __P((void)); 60168515Sgshapirostatic void setinterval __P((time_t)); 61168515Sgshapirostatic bool recent __P((void)); 62168515Sgshapirostatic void setreply __P((char *, time_t)); 63168515Sgshapirostatic void sendmessage __P((char *, char *, char *)); 64168515Sgshapirostatic void xclude __P((SM_FILE_T *)); 65168515Sgshapiro 6664562Sgshapiro/* 6764562Sgshapiro** VACATION -- return a message to the sender when on vacation. 6864562Sgshapiro** 6964562Sgshapiro** This program is invoked as a message receiver. It returns a 7064562Sgshapiro** message specified by the user to whomever sent the mail, taking 7164562Sgshapiro** care not to return a message too often to prevent "I am on 7264562Sgshapiro** vacation" loops. 7364562Sgshapiro*/ 7464562Sgshapiro 7564562Sgshapiro#define VDB ".vacation" /* vacation database */ 7664562Sgshapiro#define VMSG ".vacation.msg" /* vacation message */ 7764562Sgshapiro#define SECSPERDAY (60 * 60 * 24) 7864562Sgshapiro#define DAYSPERWEEK 7 7964562Sgshapiro 8064562Sgshapirotypedef struct alias 8164562Sgshapiro{ 8264562Sgshapiro char *name; 8364562Sgshapiro struct alias *next; 8464562Sgshapiro} ALIAS; 8564562Sgshapiro 8664562SgshapiroALIAS *Names = NULL; 8764562Sgshapiro 8864562SgshapiroSMDB_DATABASE *Db; 8964562Sgshapiro 9064562Sgshapirochar From[MAXLINE]; 91141858Sgshapirobool CloseMBDB = false; 9264562Sgshapiro 9390792Sgshapiro#if defined(__hpux) || defined(__osf__) 9490792Sgshapiro# ifndef SM_CONF_SYSLOG_INT 9590792Sgshapiro# define SM_CONF_SYSLOG_INT 1 9690792Sgshapiro# endif /* SM_CONF_SYSLOG_INT */ 9790792Sgshapiro#endif /* defined(__hpux) || defined(__osf__) */ 9864562Sgshapiro 9990792Sgshapiro#if SM_CONF_SYSLOG_INT 10090792Sgshapiro# define SYSLOG_RET_T int 10190792Sgshapiro# define SYSLOG_RET return 0 10290792Sgshapiro#else /* SM_CONF_SYSLOG_INT */ 10390792Sgshapiro# define SYSLOG_RET_T void 10490792Sgshapiro# define SYSLOG_RET 10590792Sgshapiro#endif /* SM_CONF_SYSLOG_INT */ 10690792Sgshapiro 10790792Sgshapirotypedef SYSLOG_RET_T SYSLOG_T __P((int, const char *, ...)); 10890792SgshapiroSYSLOG_T *msglog = syslog; 10990792Sgshapirostatic SYSLOG_RET_T debuglog __P((int, const char *, ...)); 11066494Sgshapirostatic void eatmsg __P((void)); 11190792Sgshapirostatic void listdb __P((void)); 11266494Sgshapiro 11366494Sgshapiro/* exit after reading input */ 114141858Sgshapiro#define EXITIT(excode) \ 115141858Sgshapiro{ \ 116141858Sgshapiro eatmsg(); \ 117141858Sgshapiro if (CloseMBDB) \ 118141858Sgshapiro { \ 119141858Sgshapiro sm_mbdb_terminate(); \ 120141858Sgshapiro CloseMBDB = false; \ 121141858Sgshapiro } \ 122141858Sgshapiro return excode; \ 12390792Sgshapiro} 12477349Sgshapiro 125141858Sgshapiro#define EXITM(excode) \ 126141858Sgshapiro{ \ 127141858Sgshapiro if (!initdb && !list) \ 128141858Sgshapiro eatmsg(); \ 129141858Sgshapiro if (CloseMBDB) \ 130141858Sgshapiro { \ 131141858Sgshapiro sm_mbdb_terminate(); \ 132141858Sgshapiro CloseMBDB = false; \ 133141858Sgshapiro } \ 134141858Sgshapiro exit(excode); \ 13590792Sgshapiro} 13690792Sgshapiro 13764562Sgshapiroint 13864562Sgshapiromain(argc, argv) 13964562Sgshapiro int argc; 14064562Sgshapiro char **argv; 14164562Sgshapiro{ 14298121Sgshapiro bool alwaysrespond = false; 14398121Sgshapiro bool initdb, exclude; 14490792Sgshapiro bool runasuser = false; 14598121Sgshapiro bool list = false; 14664562Sgshapiro int mfail = 0, ufail = 0; 14764562Sgshapiro int ch; 14864562Sgshapiro int result; 14966494Sgshapiro long sff; 15064562Sgshapiro time_t interval; 15164562Sgshapiro struct passwd *pw; 15264562Sgshapiro ALIAS *cur; 15377349Sgshapiro char *dbfilename = NULL; 15477349Sgshapiro char *msgfilename = NULL; 15590792Sgshapiro char *cfpath = NULL; 15664562Sgshapiro char *name; 15790792Sgshapiro char *returnaddr = NULL; 15864562Sgshapiro SMDB_USER_INFO user_info; 15964562Sgshapiro static char rnamebuf[MAXNAME]; 16064562Sgshapiro extern int optind, opterr; 16164562Sgshapiro extern char *optarg; 16264562Sgshapiro 16364562Sgshapiro /* Vars needed to link with smutil */ 16464562Sgshapiro clrbitmap(DontBlameSendmail); 16564562Sgshapiro RunAsUid = RealUid = getuid(); 16664562Sgshapiro RunAsGid = RealGid = getgid(); 16764562Sgshapiro pw = getpwuid(RealUid); 16864562Sgshapiro if (pw != NULL) 16964562Sgshapiro { 17064562Sgshapiro if (strlen(pw->pw_name) > MAXNAME - 1) 17164562Sgshapiro pw->pw_name[MAXNAME] = '\0'; 17290792Sgshapiro sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); 17364562Sgshapiro } 17464562Sgshapiro else 17590792Sgshapiro sm_snprintf(rnamebuf, sizeof rnamebuf, 17690792Sgshapiro "Unknown UID %d", (int) RealUid); 17764562Sgshapiro RunAsUserName = RealUserName = rnamebuf; 17864562Sgshapiro 17977349Sgshapiro# ifdef LOG_MAIL 18064562Sgshapiro openlog("vacation", LOG_PID, LOG_MAIL); 18177349Sgshapiro# else /* LOG_MAIL */ 18264562Sgshapiro openlog("vacation", LOG_PID); 18377349Sgshapiro# endif /* LOG_MAIL */ 18464562Sgshapiro 18564562Sgshapiro opterr = 0; 18698121Sgshapiro initdb = false; 18790792Sgshapiro exclude = false; 18864562Sgshapiro interval = INTERVAL_UNDEF; 18964562Sgshapiro *From = '\0'; 19064562Sgshapiro 19164562Sgshapiro 19298121Sgshapiro#define OPTIONS "a:C:df:Iijlm:R:r:s:t:Uxz" 19390792Sgshapiro 19464562Sgshapiro while (mfail == 0 && ufail == 0 && 19564562Sgshapiro (ch = getopt(argc, argv, OPTIONS)) != -1) 19664562Sgshapiro { 19764562Sgshapiro switch((char)ch) 19864562Sgshapiro { 19964562Sgshapiro case 'a': /* alias */ 20090792Sgshapiro cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS)); 20164562Sgshapiro if (cur == NULL) 20264562Sgshapiro { 20364562Sgshapiro mfail++; 20464562Sgshapiro break; 20564562Sgshapiro } 20664562Sgshapiro cur->name = optarg; 20764562Sgshapiro cur->next = Names; 20864562Sgshapiro Names = cur; 20964562Sgshapiro break; 21064562Sgshapiro 21190792Sgshapiro case 'C': 21290792Sgshapiro cfpath = optarg; 21390792Sgshapiro break; 21490792Sgshapiro 21577349Sgshapiro case 'd': /* debug mode */ 21690792Sgshapiro msglog = debuglog; 21764562Sgshapiro break; 21864562Sgshapiro 21964562Sgshapiro case 'f': /* alternate database */ 22064562Sgshapiro dbfilename = optarg; 22164562Sgshapiro break; 22264562Sgshapiro 22364562Sgshapiro case 'I': /* backward compatible */ 22464562Sgshapiro case 'i': /* init the database */ 22598121Sgshapiro initdb = true; 22664562Sgshapiro break; 22764562Sgshapiro 22898121Sgshapiro case 'j': 22998121Sgshapiro alwaysrespond = true; 23098121Sgshapiro break; 23198121Sgshapiro 23264562Sgshapiro case 'l': 23398121Sgshapiro list = true; /* list the database */ 23464562Sgshapiro break; 23564562Sgshapiro 23664562Sgshapiro case 'm': /* alternate message file */ 23764562Sgshapiro msgfilename = optarg; 23864562Sgshapiro break; 23964562Sgshapiro 24090792Sgshapiro case 'R': 24190792Sgshapiro returnaddr = optarg; 24290792Sgshapiro break; 24390792Sgshapiro 24464562Sgshapiro case 'r': 24564562Sgshapiro if (isascii(*optarg) && isdigit(*optarg)) 24664562Sgshapiro { 24764562Sgshapiro interval = atol(optarg) * SECSPERDAY; 24864562Sgshapiro if (interval < 0) 24964562Sgshapiro ufail++; 25064562Sgshapiro } 25164562Sgshapiro else 25264562Sgshapiro interval = ONLY_ONCE; 25364562Sgshapiro break; 25464562Sgshapiro 25564562Sgshapiro case 's': /* alternate sender name */ 25690792Sgshapiro (void) sm_strlcpy(From, optarg, sizeof From); 25764562Sgshapiro break; 25864562Sgshapiro 25964562Sgshapiro case 't': /* SunOS: -t1d (default expire) */ 26064562Sgshapiro break; 26164562Sgshapiro 26277349Sgshapiro case 'U': /* run as single user mode */ 26390792Sgshapiro runasuser = true; 26477349Sgshapiro break; 26577349Sgshapiro 26664562Sgshapiro case 'x': 26790792Sgshapiro exclude = true; 26864562Sgshapiro break; 26964562Sgshapiro 27064562Sgshapiro case 'z': 27190792Sgshapiro returnaddr = "<>"; 27264562Sgshapiro break; 27364562Sgshapiro 27464562Sgshapiro case '?': 27564562Sgshapiro default: 27664562Sgshapiro ufail++; 27764562Sgshapiro break; 27864562Sgshapiro } 27964562Sgshapiro } 28064562Sgshapiro argc -= optind; 28164562Sgshapiro argv += optind; 28264562Sgshapiro 28364562Sgshapiro if (mfail != 0) 28464562Sgshapiro { 28564562Sgshapiro msglog(LOG_NOTICE, 28664562Sgshapiro "vacation: can't allocate memory for alias.\n"); 28766494Sgshapiro EXITM(EX_TEMPFAIL); 28864562Sgshapiro } 28964562Sgshapiro if (ufail != 0) 29064562Sgshapiro usage(); 29164562Sgshapiro 29264562Sgshapiro if (argc != 1) 29364562Sgshapiro { 29498121Sgshapiro if (!initdb && !list && !exclude) 29564562Sgshapiro usage(); 29664562Sgshapiro if ((pw = getpwuid(getuid())) == NULL) 29764562Sgshapiro { 29864562Sgshapiro msglog(LOG_ERR, 29964562Sgshapiro "vacation: no such user uid %u.\n", getuid()); 30066494Sgshapiro EXITM(EX_NOUSER); 30164562Sgshapiro } 30277349Sgshapiro name = pw->pw_name; 30377349Sgshapiro user_info.smdbu_id = pw->pw_uid; 30477349Sgshapiro user_info.smdbu_group_id = pw->pw_gid; 30590792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name, 30690792Sgshapiro SMDB_MAX_USER_NAME_LEN); 30777349Sgshapiro if (chdir(pw->pw_dir) != 0) 30877349Sgshapiro { 30990792Sgshapiro msglog(LOG_NOTICE, 31090792Sgshapiro "vacation: no such directory %s.\n", 31177349Sgshapiro pw->pw_dir); 31277349Sgshapiro EXITM(EX_NOINPUT); 31377349Sgshapiro } 31464562Sgshapiro } 31577349Sgshapiro else if (runasuser) 31677349Sgshapiro { 31777349Sgshapiro name = *argv; 31877349Sgshapiro if (dbfilename == NULL || msgfilename == NULL) 31977349Sgshapiro { 32077349Sgshapiro msglog(LOG_NOTICE, 32177349Sgshapiro "vacation: -U requires setting both -f and -m\n"); 32277349Sgshapiro EXITM(EX_NOINPUT); 32377349Sgshapiro } 32477349Sgshapiro user_info.smdbu_id = pw->pw_uid; 32577349Sgshapiro user_info.smdbu_group_id = pw->pw_gid; 32690792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name, 32777349Sgshapiro SMDB_MAX_USER_NAME_LEN); 32877349Sgshapiro } 32977349Sgshapiro else 33064562Sgshapiro { 33190792Sgshapiro int err; 33290792Sgshapiro SM_CF_OPT_T mbdbname; 33390792Sgshapiro SM_MBDB_T user; 33490792Sgshapiro 33594334Sgshapiro cfpath = getcfname(0, 0, SM_GET_SENDMAIL_CF, cfpath); 33690792Sgshapiro mbdbname.opt_name = "MailboxDatabase"; 33790792Sgshapiro mbdbname.opt_val = "pw"; 33890792Sgshapiro (void) sm_cf_getopt(cfpath, 1, &mbdbname); 33990792Sgshapiro err = sm_mbdb_initialize(mbdbname.opt_val); 34090792Sgshapiro if (err != EX_OK) 34177349Sgshapiro { 34290792Sgshapiro msglog(LOG_ERR, 34390792Sgshapiro "vacation: can't open mailbox database: %s.\n", 34490792Sgshapiro sm_strexit(err)); 34590792Sgshapiro EXITM(err); 34690792Sgshapiro } 347141858Sgshapiro CloseMBDB = true; 34890792Sgshapiro err = sm_mbdb_lookup(*argv, &user); 34990792Sgshapiro if (err == EX_NOUSER) 35090792Sgshapiro { 35190792Sgshapiro msglog(LOG_ERR, "vacation: no such user %s.\n", *argv); 35290792Sgshapiro EXITM(EX_NOUSER); 35390792Sgshapiro } 35490792Sgshapiro if (err != EX_OK) 35590792Sgshapiro { 35690792Sgshapiro msglog(LOG_ERR, 35790792Sgshapiro "vacation: can't read mailbox database: %s.\n", 35890792Sgshapiro sm_strexit(err)); 35990792Sgshapiro EXITM(err); 36090792Sgshapiro } 36190792Sgshapiro name = user.mbdb_name; 36290792Sgshapiro if (chdir(user.mbdb_homedir) != 0) 36390792Sgshapiro { 36490792Sgshapiro msglog(LOG_NOTICE, 36590792Sgshapiro "vacation: no such directory %s.\n", 36690792Sgshapiro user.mbdb_homedir); 36777349Sgshapiro EXITM(EX_NOINPUT); 36877349Sgshapiro } 36990792Sgshapiro user_info.smdbu_id = user.mbdb_uid; 37090792Sgshapiro user_info.smdbu_group_id = user.mbdb_gid; 37190792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, user.mbdb_name, 37277349Sgshapiro SMDB_MAX_USER_NAME_LEN); 37364562Sgshapiro } 37464562Sgshapiro 37577349Sgshapiro if (dbfilename == NULL) 37677349Sgshapiro dbfilename = VDB; 37777349Sgshapiro if (msgfilename == NULL) 37877349Sgshapiro msgfilename = VMSG; 37977349Sgshapiro 38066494Sgshapiro sff = SFF_CREAT; 38166494Sgshapiro if (getegid() != getgid()) 38277349Sgshapiro { 38390792Sgshapiro /* Allow a set-group-ID vacation binary */ 38466494Sgshapiro RunAsGid = user_info.smdbu_group_id = getegid(); 38590792Sgshapiro sff |= SFF_OPENASROOT; 38677349Sgshapiro } 38794334Sgshapiro if (getuid() == 0) 38894334Sgshapiro { 38994334Sgshapiro /* Allow root to initialize user's vacation databases */ 39094334Sgshapiro sff |= SFF_OPENASROOT|SFF_ROOTOK; 39166494Sgshapiro 39294334Sgshapiro /* ... safely */ 39394334Sgshapiro sff |= SFF_NOSLINK|SFF_NOHLINK|SFF_REGONLY; 39494334Sgshapiro } 39594334Sgshapiro 39694334Sgshapiro 39764562Sgshapiro result = smdb_open_database(&Db, dbfilename, 39898121Sgshapiro O_CREAT|O_RDWR | (initdb ? O_TRUNC : 0), 39966494Sgshapiro S_IRUSR|S_IWUSR, sff, 40064562Sgshapiro SMDB_TYPE_DEFAULT, &user_info, NULL); 40164562Sgshapiro if (result != SMDBE_OK) 40264562Sgshapiro { 40364562Sgshapiro msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename, 40490792Sgshapiro sm_errstring(result)); 40566494Sgshapiro EXITM(EX_DATAERR); 40664562Sgshapiro } 40764562Sgshapiro 40898121Sgshapiro if (list) 40964562Sgshapiro { 41064562Sgshapiro listdb(); 41171345Sgshapiro (void) Db->smdb_close(Db); 41264562Sgshapiro exit(EX_OK); 41364562Sgshapiro } 41464562Sgshapiro 41564562Sgshapiro if (interval != INTERVAL_UNDEF) 41664562Sgshapiro setinterval(interval); 41764562Sgshapiro 41898121Sgshapiro if (initdb && !exclude) 41964562Sgshapiro { 42071345Sgshapiro (void) Db->smdb_close(Db); 42171345Sgshapiro exit(EX_OK); 42264562Sgshapiro } 42364562Sgshapiro 42464562Sgshapiro if (exclude) 42564562Sgshapiro { 42690792Sgshapiro xclude(smioin); 42771345Sgshapiro (void) Db->smdb_close(Db); 42866494Sgshapiro EXITM(EX_OK); 42964562Sgshapiro } 43064562Sgshapiro 43190792Sgshapiro if ((cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS))) == NULL) 43264562Sgshapiro { 43364562Sgshapiro msglog(LOG_NOTICE, 43464562Sgshapiro "vacation: can't allocate memory for username.\n"); 43571345Sgshapiro (void) Db->smdb_close(Db); 43666494Sgshapiro EXITM(EX_OSERR); 43764562Sgshapiro } 43864562Sgshapiro cur->name = name; 43964562Sgshapiro cur->next = Names; 44064562Sgshapiro Names = cur; 44164562Sgshapiro 44298121Sgshapiro result = readheaders(alwaysrespond); 44371345Sgshapiro if (result == EX_OK && !recent()) 44464562Sgshapiro { 44564562Sgshapiro time_t now; 44664562Sgshapiro 44764562Sgshapiro (void) time(&now); 44864562Sgshapiro setreply(From, now); 44971345Sgshapiro (void) Db->smdb_close(Db); 45090792Sgshapiro sendmessage(name, msgfilename, returnaddr); 45164562Sgshapiro } 45264562Sgshapiro else 45371345Sgshapiro (void) Db->smdb_close(Db); 45471345Sgshapiro if (result == EX_NOUSER) 45571345Sgshapiro result = EX_OK; 45671345Sgshapiro exit(result); 45764562Sgshapiro} 45864562Sgshapiro 45964562Sgshapiro/* 46066494Sgshapiro** EATMSG -- read stdin till EOF 46166494Sgshapiro** 46266494Sgshapiro** Parameters: 46366494Sgshapiro** none. 46466494Sgshapiro** 46566494Sgshapiro** Returns: 46666494Sgshapiro** nothing. 46766494Sgshapiro** 46866494Sgshapiro*/ 46977349Sgshapiro 47066494Sgshapirostatic void 47166494Sgshapiroeatmsg() 47266494Sgshapiro{ 47366494Sgshapiro /* 47466494Sgshapiro ** read the rest of the e-mail and ignore it to avoid problems 47566494Sgshapiro ** with EPIPE in sendmail 47666494Sgshapiro */ 47766494Sgshapiro while (getc(stdin) != EOF) 47866494Sgshapiro continue; 47966494Sgshapiro} 48066494Sgshapiro 48166494Sgshapiro/* 48264562Sgshapiro** READHEADERS -- read mail headers 48364562Sgshapiro** 48464562Sgshapiro** Parameters: 48598121Sgshapiro** alwaysrespond -- respond regardless of whether msg is to me 48664562Sgshapiro** 48764562Sgshapiro** Returns: 48871345Sgshapiro** a exit code: NOUSER if no reply, OK if reply, * if error 48964562Sgshapiro** 49066494Sgshapiro** Side Effects: 49166494Sgshapiro** may exit(). 49266494Sgshapiro** 49364562Sgshapiro*/ 49471345Sgshapiro 495168515Sgshapirostatic int 49698121Sgshapiroreadheaders(alwaysrespond) 49798121Sgshapiro bool alwaysrespond; 49864562Sgshapiro{ 49964562Sgshapiro bool tome, cont; 50064562Sgshapiro register char *p; 50164562Sgshapiro register ALIAS *cur; 50264562Sgshapiro char buf[MAXLINE]; 50364562Sgshapiro 50498121Sgshapiro cont = false; 50598121Sgshapiro tome = alwaysrespond; 50690792Sgshapiro while (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, sizeof(buf)) && 50790792Sgshapiro *buf != '\n') 50864562Sgshapiro { 50964562Sgshapiro switch(*buf) 51064562Sgshapiro { 51164562Sgshapiro case 'F': /* "From " */ 51290792Sgshapiro cont = false; 51364562Sgshapiro if (strncmp(buf, "From ", 5) == 0) 51464562Sgshapiro { 51590792Sgshapiro bool quoted = false; 51664562Sgshapiro 51764562Sgshapiro p = buf + 5; 51864562Sgshapiro while (*p != '\0') 51964562Sgshapiro { 52064562Sgshapiro /* escaped character */ 52164562Sgshapiro if (*p == '\\') 52264562Sgshapiro { 52364562Sgshapiro p++; 52464562Sgshapiro if (*p == '\0') 52564562Sgshapiro { 52664562Sgshapiro msglog(LOG_NOTICE, 52764562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 52866494Sgshapiro EXITIT(EX_DATAERR); 52964562Sgshapiro } 53064562Sgshapiro } 53164562Sgshapiro else if (*p == '"') 53264562Sgshapiro quoted = !quoted; 53364562Sgshapiro else if (*p == '\r' || *p == '\n') 53464562Sgshapiro break; 53564562Sgshapiro else if (*p == ' ' && !quoted) 53664562Sgshapiro break; 53764562Sgshapiro p++; 53864562Sgshapiro } 53964562Sgshapiro if (quoted) 54064562Sgshapiro { 54164562Sgshapiro msglog(LOG_NOTICE, 54264562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 54366494Sgshapiro EXITIT(EX_DATAERR); 54464562Sgshapiro } 54564562Sgshapiro *p = '\0'; 54664562Sgshapiro 54764562Sgshapiro /* ok since both strings have MAXLINE length */ 54864562Sgshapiro if (*From == '\0') 54990792Sgshapiro (void) sm_strlcpy(From, buf + 5, 55090792Sgshapiro sizeof From); 55164562Sgshapiro if ((p = strchr(buf + 5, '\n')) != NULL) 55264562Sgshapiro *p = '\0'; 55364562Sgshapiro if (junkmail(buf + 5)) 55471345Sgshapiro EXITIT(EX_NOUSER); 55564562Sgshapiro } 55664562Sgshapiro break; 55764562Sgshapiro 55864562Sgshapiro case 'P': /* "Precedence:" */ 55964562Sgshapiro case 'p': 56090792Sgshapiro cont = false; 56164562Sgshapiro if (strlen(buf) <= 10 || 56264562Sgshapiro strncasecmp(buf, "Precedence", 10) != 0 || 56364562Sgshapiro (buf[10] != ':' && buf[10] != ' ' && 56464562Sgshapiro buf[10] != '\t')) 56564562Sgshapiro break; 56664562Sgshapiro if ((p = strchr(buf, ':')) == NULL) 56764562Sgshapiro break; 56864562Sgshapiro while (*++p != '\0' && isascii(*p) && isspace(*p)); 56964562Sgshapiro if (*p == '\0') 57064562Sgshapiro break; 57164562Sgshapiro if (strncasecmp(p, "junk", 4) == 0 || 57264562Sgshapiro strncasecmp(p, "bulk", 4) == 0 || 57364562Sgshapiro strncasecmp(p, "list", 4) == 0) 57471345Sgshapiro EXITIT(EX_NOUSER); 57564562Sgshapiro break; 57664562Sgshapiro 57764562Sgshapiro case 'C': /* "Cc:" */ 57864562Sgshapiro case 'c': 57964562Sgshapiro if (strncasecmp(buf, "Cc:", 3) != 0) 58064562Sgshapiro break; 58190792Sgshapiro cont = true; 58264562Sgshapiro goto findme; 58364562Sgshapiro 58464562Sgshapiro case 'T': /* "To:" */ 58564562Sgshapiro case 't': 58664562Sgshapiro if (strncasecmp(buf, "To:", 3) != 0) 58764562Sgshapiro break; 58890792Sgshapiro cont = true; 58964562Sgshapiro goto findme; 59064562Sgshapiro 59164562Sgshapiro default: 59264562Sgshapiro if (!isascii(*buf) || !isspace(*buf) || !cont || tome) 59364562Sgshapiro { 59490792Sgshapiro cont = false; 59564562Sgshapiro break; 59664562Sgshapiro } 59764562Sgshapirofindme: 59864562Sgshapiro for (cur = Names; 59964562Sgshapiro !tome && cur != NULL; 60064562Sgshapiro cur = cur->next) 60164562Sgshapiro tome = nsearch(cur->name, buf); 60264562Sgshapiro } 60364562Sgshapiro } 60464562Sgshapiro if (!tome) 60571345Sgshapiro EXITIT(EX_NOUSER); 60664562Sgshapiro if (*From == '\0') 60764562Sgshapiro { 60864562Sgshapiro msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n"); 60966494Sgshapiro EXITIT(EX_DATAERR); 61064562Sgshapiro } 61171345Sgshapiro EXITIT(EX_OK); 61264562Sgshapiro} 61364562Sgshapiro 61464562Sgshapiro/* 61564562Sgshapiro** NSEARCH -- 61664562Sgshapiro** do a nice, slow, search of a string for a substring. 61764562Sgshapiro** 61864562Sgshapiro** Parameters: 61964562Sgshapiro** name -- name to search. 62064562Sgshapiro** str -- string in which to search. 62164562Sgshapiro** 62264562Sgshapiro** Returns: 62364562Sgshapiro** is name a substring of str? 62464562Sgshapiro** 62564562Sgshapiro*/ 62677349Sgshapiro 627168515Sgshapirostatic bool 62864562Sgshapironsearch(name, str) 62964562Sgshapiro register char *name, *str; 63064562Sgshapiro{ 63164562Sgshapiro register size_t len; 63264562Sgshapiro register char *s; 63364562Sgshapiro 63464562Sgshapiro len = strlen(name); 63564562Sgshapiro 63664562Sgshapiro for (s = str; *s != '\0'; ++s) 63764562Sgshapiro { 63864562Sgshapiro /* 63964562Sgshapiro ** Check to make sure that the string matches and 64064562Sgshapiro ** the previous character is not an alphanumeric and 64164562Sgshapiro ** the next character after the match is not an alphanumeric. 64264562Sgshapiro ** 64364562Sgshapiro ** This prevents matching "eric" to "derick" while still 64464562Sgshapiro ** matching "eric" to "<eric+detail>". 64564562Sgshapiro */ 64664562Sgshapiro 64764562Sgshapiro if (tolower(*s) == tolower(*name) && 64864562Sgshapiro strncasecmp(name, s, len) == 0 && 64964562Sgshapiro (s == str || !isascii(*(s - 1)) || !isalnum(*(s - 1))) && 65064562Sgshapiro (!isascii(*(s + len)) || !isalnum(*(s + len)))) 65190792Sgshapiro return true; 65264562Sgshapiro } 65390792Sgshapiro return false; 65464562Sgshapiro} 65564562Sgshapiro 65664562Sgshapiro/* 65764562Sgshapiro** JUNKMAIL -- 65864562Sgshapiro** read the header and return if automagic/junk/bulk/list mail 65964562Sgshapiro** 66064562Sgshapiro** Parameters: 66164562Sgshapiro** from -- sender address. 66264562Sgshapiro** 66364562Sgshapiro** Returns: 66464562Sgshapiro** is this some automated/junk/bulk/list mail? 66564562Sgshapiro** 66664562Sgshapiro*/ 66771345Sgshapiro 66871345Sgshapirostruct ignore 66971345Sgshapiro{ 67071345Sgshapiro char *name; 67171345Sgshapiro size_t len; 67271345Sgshapiro}; 67371345Sgshapiro 67471345Sgshapirotypedef struct ignore IGNORE_T; 67571345Sgshapiro 67671345Sgshapiro#define MAX_USER_LEN 256 /* maximum length of local part (sender) */ 67771345Sgshapiro 67871345Sgshapiro/* delimiters for the local part of an address */ 67971345Sgshapiro#define isdelim(c) ((c) == '%' || (c) == '@' || (c) == '+') 68071345Sgshapiro 681168515Sgshapirostatic bool 68264562Sgshapirojunkmail(from) 68364562Sgshapiro char *from; 68464562Sgshapiro{ 68571345Sgshapiro bool quot; 68671345Sgshapiro char *e; 68771345Sgshapiro size_t len; 68871345Sgshapiro IGNORE_T *cur; 68971345Sgshapiro char sender[MAX_USER_LEN]; 69071345Sgshapiro static IGNORE_T ignore[] = 69164562Sgshapiro { 69264562Sgshapiro { "postmaster", 10 }, 69364562Sgshapiro { "uucp", 4 }, 69464562Sgshapiro { "mailer-daemon", 13 }, 69564562Sgshapiro { "mailer", 6 }, 69671345Sgshapiro { NULL, 0 } 69771345Sgshapiro }; 69871345Sgshapiro 69971345Sgshapiro static IGNORE_T ignorepost[] = 70071345Sgshapiro { 70171345Sgshapiro { "-request", 8 }, 70264562Sgshapiro { "-relay", 6 }, 70371345Sgshapiro { "-owner", 6 }, 70464562Sgshapiro { NULL, 0 } 70564562Sgshapiro }; 70664562Sgshapiro 70771345Sgshapiro static IGNORE_T ignorepre[] = 70871345Sgshapiro { 70971345Sgshapiro { "owner-", 6 }, 71071345Sgshapiro { NULL, 0 } 71171345Sgshapiro }; 71271345Sgshapiro 71364562Sgshapiro /* 71471345Sgshapiro ** This is mildly amusing, and I'm not positive it's right; trying 71571345Sgshapiro ** to find the "real" name of the sender, assuming that addresses 71671345Sgshapiro ** will be some variant of: 71771345Sgshapiro ** 71871345Sgshapiro ** From site!site!SENDER%site.domain%site.domain@site.domain 71971345Sgshapiro */ 72071345Sgshapiro 72190792Sgshapiro quot = false; 72271345Sgshapiro e = from; 72371345Sgshapiro len = 0; 72471345Sgshapiro while (*e != '\0' && (quot || !isdelim(*e))) 72564562Sgshapiro { 72671345Sgshapiro if (*e == '"') 72771345Sgshapiro { 72871345Sgshapiro quot = !quot; 72971345Sgshapiro ++e; 73071345Sgshapiro continue; 73171345Sgshapiro } 73271345Sgshapiro if (*e == '\\') 73371345Sgshapiro { 73471345Sgshapiro if (*(++e) == '\0') 73571345Sgshapiro { 73671345Sgshapiro /* '\\' at end of string? */ 73771345Sgshapiro break; 73871345Sgshapiro } 73971345Sgshapiro if (len < MAX_USER_LEN) 74071345Sgshapiro sender[len++] = *e; 74171345Sgshapiro ++e; 74271345Sgshapiro continue; 74371345Sgshapiro } 74471345Sgshapiro if (*e == '!' && !quot) 74571345Sgshapiro { 74671345Sgshapiro len = 0; 74771345Sgshapiro sender[len] = '\0'; 74871345Sgshapiro } 74964562Sgshapiro else 75071345Sgshapiro if (len < MAX_USER_LEN) 75171345Sgshapiro sender[len++] = *e; 75271345Sgshapiro ++e; 75364562Sgshapiro } 75471345Sgshapiro if (len < MAX_USER_LEN) 75571345Sgshapiro sender[len] = '\0'; 75671345Sgshapiro else 75771345Sgshapiro sender[MAX_USER_LEN - 1] = '\0'; 75871345Sgshapiro 75971345Sgshapiro if (len <= 0) 76090792Sgshapiro return false; 76171345Sgshapiro#if 0 76271345Sgshapiro if (quot) 76390792Sgshapiro return false; /* syntax error... */ 76471345Sgshapiro#endif /* 0 */ 76571345Sgshapiro 76671345Sgshapiro /* test prefixes */ 76771345Sgshapiro for (cur = ignorepre; cur->name != NULL; ++cur) 76871345Sgshapiro { 76971345Sgshapiro if (len >= cur->len && 77071345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 77190792Sgshapiro return true; 77271345Sgshapiro } 77371345Sgshapiro 77471345Sgshapiro /* 77571345Sgshapiro ** If the name is truncated, don't test the rest. 77671345Sgshapiro ** We could extract the "tail" of the sender address and 77771345Sgshapiro ** compare it it ignorepost, however, it seems not worth 77871345Sgshapiro ** the effort. 77971345Sgshapiro ** The address surely can't match any entry in ignore[] 78071345Sgshapiro ** (as long as all of them are shorter than MAX_USER_LEN). 78171345Sgshapiro */ 78271345Sgshapiro 78371345Sgshapiro if (len > MAX_USER_LEN) 78490792Sgshapiro return false; 78571345Sgshapiro 78671345Sgshapiro /* test full local parts */ 78764562Sgshapiro for (cur = ignore; cur->name != NULL; ++cur) 78864562Sgshapiro { 78971345Sgshapiro if (len == cur->len && 79071345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 79190792Sgshapiro return true; 79271345Sgshapiro } 79371345Sgshapiro 79471345Sgshapiro /* test postfixes */ 79571345Sgshapiro for (cur = ignorepost; cur->name != NULL; ++cur) 79671345Sgshapiro { 79764562Sgshapiro if (len >= cur->len && 79871345Sgshapiro strncasecmp(cur->name, e - cur->len - 1, 79971345Sgshapiro cur->len) == 0) 80090792Sgshapiro return true; 80164562Sgshapiro } 80290792Sgshapiro return false; 80364562Sgshapiro} 80464562Sgshapiro 80564562Sgshapiro#define VIT "__VACATION__INTERVAL__TIMER__" 80664562Sgshapiro 80764562Sgshapiro/* 80864562Sgshapiro** RECENT -- 80964562Sgshapiro** find out if user has gotten a vacation message recently. 81064562Sgshapiro** 81164562Sgshapiro** Parameters: 81264562Sgshapiro** none. 81364562Sgshapiro** 81464562Sgshapiro** Returns: 81590792Sgshapiro** true iff user has gotten a vacation message recently. 81664562Sgshapiro** 81764562Sgshapiro*/ 81877349Sgshapiro 819168515Sgshapirostatic bool 82064562Sgshapirorecent() 82164562Sgshapiro{ 82264562Sgshapiro SMDB_DBENT key, data; 82364562Sgshapiro time_t then, next; 82490792Sgshapiro bool trydomain = false; 82564562Sgshapiro int st; 82664562Sgshapiro char *domain; 82764562Sgshapiro 82864562Sgshapiro memset(&key, '\0', sizeof key); 82964562Sgshapiro memset(&data, '\0', sizeof data); 83064562Sgshapiro 83164562Sgshapiro /* get interval time */ 83271345Sgshapiro key.data = VIT; 83371345Sgshapiro key.size = sizeof(VIT); 83464562Sgshapiro 83564562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 83664562Sgshapiro if (st != SMDBE_OK) 83764562Sgshapiro next = SECSPERDAY * DAYSPERWEEK; 83864562Sgshapiro else 83971345Sgshapiro memmove(&next, data.data, sizeof(next)); 84064562Sgshapiro 84164562Sgshapiro memset(&data, '\0', sizeof data); 84264562Sgshapiro 84364562Sgshapiro /* get record for this address */ 84471345Sgshapiro key.data = From; 84571345Sgshapiro key.size = strlen(From); 84664562Sgshapiro 84764562Sgshapiro do 84864562Sgshapiro { 84964562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 85064562Sgshapiro if (st == SMDBE_OK) 85164562Sgshapiro { 85271345Sgshapiro memmove(&then, data.data, sizeof(then)); 85364562Sgshapiro if (next == ONLY_ONCE || then == ONLY_ONCE || 85464562Sgshapiro then + next > time(NULL)) 85590792Sgshapiro return true; 85664562Sgshapiro } 85764562Sgshapiro if ((trydomain = !trydomain) && 85864562Sgshapiro (domain = strchr(From, '@')) != NULL) 85964562Sgshapiro { 86071345Sgshapiro key.data = domain; 86171345Sgshapiro key.size = strlen(domain); 86264562Sgshapiro } 86364562Sgshapiro } while (trydomain); 86490792Sgshapiro return false; 86564562Sgshapiro} 86664562Sgshapiro 86764562Sgshapiro/* 86864562Sgshapiro** SETINTERVAL -- 86964562Sgshapiro** store the reply interval 87064562Sgshapiro** 87164562Sgshapiro** Parameters: 87264562Sgshapiro** interval -- time interval for replies. 87364562Sgshapiro** 87464562Sgshapiro** Returns: 87564562Sgshapiro** nothing. 87664562Sgshapiro** 87764562Sgshapiro** Side Effects: 87864562Sgshapiro** stores the reply interval in database. 87964562Sgshapiro*/ 88077349Sgshapiro 881168515Sgshapirostatic void 88264562Sgshapirosetinterval(interval) 88364562Sgshapiro time_t interval; 88464562Sgshapiro{ 88564562Sgshapiro SMDB_DBENT key, data; 88664562Sgshapiro 88764562Sgshapiro memset(&key, '\0', sizeof key); 88864562Sgshapiro memset(&data, '\0', sizeof data); 88964562Sgshapiro 89071345Sgshapiro key.data = VIT; 89171345Sgshapiro key.size = sizeof(VIT); 89271345Sgshapiro data.data = (char*) &interval; 89371345Sgshapiro data.size = sizeof(interval); 89471345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 89564562Sgshapiro} 89664562Sgshapiro 89764562Sgshapiro/* 89864562Sgshapiro** SETREPLY -- 89964562Sgshapiro** store that this user knows about the vacation. 90064562Sgshapiro** 90164562Sgshapiro** Parameters: 90264562Sgshapiro** from -- sender address. 90364562Sgshapiro** when -- last reply time. 90464562Sgshapiro** 90564562Sgshapiro** Returns: 90664562Sgshapiro** nothing. 90764562Sgshapiro** 90864562Sgshapiro** Side Effects: 90964562Sgshapiro** stores user/time in database. 91064562Sgshapiro*/ 91177349Sgshapiro 912168515Sgshapirostatic void 91364562Sgshapirosetreply(from, when) 91464562Sgshapiro char *from; 91564562Sgshapiro time_t when; 91664562Sgshapiro{ 91764562Sgshapiro SMDB_DBENT key, data; 91864562Sgshapiro 91964562Sgshapiro memset(&key, '\0', sizeof key); 92064562Sgshapiro memset(&data, '\0', sizeof data); 92164562Sgshapiro 92271345Sgshapiro key.data = from; 92371345Sgshapiro key.size = strlen(from); 92471345Sgshapiro data.data = (char*) &when; 92571345Sgshapiro data.size = sizeof(when); 92671345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 92764562Sgshapiro} 92864562Sgshapiro 92964562Sgshapiro/* 93064562Sgshapiro** XCLUDE -- 93164562Sgshapiro** add users to vacation db so they don't get a reply. 93264562Sgshapiro** 93364562Sgshapiro** Parameters: 93464562Sgshapiro** f -- file pointer with list of address to exclude 93564562Sgshapiro** 93664562Sgshapiro** Returns: 93764562Sgshapiro** nothing. 93864562Sgshapiro** 93964562Sgshapiro** Side Effects: 94064562Sgshapiro** stores users in database. 94164562Sgshapiro*/ 94277349Sgshapiro 943168515Sgshapirostatic void 94464562Sgshapiroxclude(f) 94590792Sgshapiro SM_FILE_T *f; 94664562Sgshapiro{ 94764562Sgshapiro char buf[MAXLINE], *p; 94864562Sgshapiro 94964562Sgshapiro if (f == NULL) 95064562Sgshapiro return; 95190792Sgshapiro while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf)) 95264562Sgshapiro { 95364562Sgshapiro if ((p = strchr(buf, '\n')) != NULL) 95464562Sgshapiro *p = '\0'; 95564562Sgshapiro setreply(buf, ONLY_ONCE); 95664562Sgshapiro } 95764562Sgshapiro} 95864562Sgshapiro 95964562Sgshapiro/* 96064562Sgshapiro** SENDMESSAGE -- 96164562Sgshapiro** exec sendmail to send the vacation file to sender 96264562Sgshapiro** 96364562Sgshapiro** Parameters: 96464562Sgshapiro** myname -- user name. 96564562Sgshapiro** msgfn -- name of file with vacation message. 96690792Sgshapiro** sender -- use as sender address 96764562Sgshapiro** 96864562Sgshapiro** Returns: 96964562Sgshapiro** nothing. 97064562Sgshapiro** 97164562Sgshapiro** Side Effects: 97264562Sgshapiro** sends vacation reply. 97364562Sgshapiro*/ 97477349Sgshapiro 975168515Sgshapirostatic void 97690792Sgshapirosendmessage(myname, msgfn, sender) 97764562Sgshapiro char *myname; 97864562Sgshapiro char *msgfn; 97990792Sgshapiro char *sender; 98064562Sgshapiro{ 98190792Sgshapiro SM_FILE_T *mfp, *sfp; 98264562Sgshapiro int i; 98364562Sgshapiro int pvect[2]; 98477349Sgshapiro char *pv[8]; 98564562Sgshapiro char buf[MAXLINE]; 98664562Sgshapiro 98790792Sgshapiro mfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, msgfn, SM_IO_RDONLY, NULL); 98864562Sgshapiro if (mfp == NULL) 98964562Sgshapiro { 99064562Sgshapiro if (msgfn[0] == '/') 99164562Sgshapiro msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn); 99264562Sgshapiro else 99364562Sgshapiro msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", 99464562Sgshapiro myname, msgfn); 99564562Sgshapiro exit(EX_NOINPUT); 99664562Sgshapiro } 99764562Sgshapiro if (pipe(pvect) < 0) 99864562Sgshapiro { 99990792Sgshapiro msglog(LOG_ERR, "vacation: pipe: %s", sm_errstring(errno)); 100064562Sgshapiro exit(EX_OSERR); 100164562Sgshapiro } 100277349Sgshapiro pv[0] = "sendmail"; 100377349Sgshapiro pv[1] = "-oi"; 100477349Sgshapiro pv[2] = "-f"; 100590792Sgshapiro if (sender != NULL) 100690792Sgshapiro pv[3] = sender; 100777349Sgshapiro else 100877349Sgshapiro pv[3] = myname; 100977349Sgshapiro pv[4] = "--"; 101077349Sgshapiro pv[5] = From; 101177349Sgshapiro pv[6] = NULL; 101264562Sgshapiro i = fork(); 101364562Sgshapiro if (i < 0) 101464562Sgshapiro { 101590792Sgshapiro msglog(LOG_ERR, "vacation: fork: %s", sm_errstring(errno)); 101664562Sgshapiro exit(EX_OSERR); 101764562Sgshapiro } 101864562Sgshapiro if (i == 0) 101964562Sgshapiro { 102064562Sgshapiro (void) dup2(pvect[0], 0); 102164562Sgshapiro (void) close(pvect[0]); 102264562Sgshapiro (void) close(pvect[1]); 102390792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 102477349Sgshapiro (void) execv(_PATH_SENDMAIL, pv); 102564562Sgshapiro msglog(LOG_ERR, "vacation: can't exec %s: %s", 102690792Sgshapiro _PATH_SENDMAIL, sm_errstring(errno)); 102764562Sgshapiro exit(EX_UNAVAILABLE); 102864562Sgshapiro } 102964562Sgshapiro /* check return status of the following calls? XXX */ 103064562Sgshapiro (void) close(pvect[0]); 103190792Sgshapiro if ((sfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 103290792Sgshapiro (void *) &(pvect[1]), 103390792Sgshapiro SM_IO_WRONLY, NULL)) != NULL) 103464562Sgshapiro { 103590792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, "To: %s\n", From); 103690792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, 103790792Sgshapiro "Auto-Submitted: auto-replied\n"); 103890792Sgshapiro while (sm_io_fgets(mfp, SM_TIME_DEFAULT, buf, sizeof buf)) 103990792Sgshapiro (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf); 104090792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 104190792Sgshapiro (void) sm_io_close(sfp, SM_TIME_DEFAULT); 104264562Sgshapiro } 104364562Sgshapiro else 104464562Sgshapiro { 104590792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 104664562Sgshapiro msglog(LOG_ERR, "vacation: can't open pipe to sendmail"); 104764562Sgshapiro exit(EX_UNAVAILABLE); 104864562Sgshapiro } 104964562Sgshapiro} 105064562Sgshapiro 1051168515Sgshapirostatic void 105264562Sgshapirousage() 105364562Sgshapiro{ 105477349Sgshapiro msglog(LOG_NOTICE, 1055132943Sgshapiro "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", 1056132943Sgshapiro getuid()); 105764562Sgshapiro exit(EX_USAGE); 105864562Sgshapiro} 105964562Sgshapiro 106064562Sgshapiro/* 106164562Sgshapiro** LISTDB -- list the contents of the vacation database 106264562Sgshapiro** 106364562Sgshapiro** Parameters: 106464562Sgshapiro** none. 106564562Sgshapiro** 106664562Sgshapiro** Returns: 106764562Sgshapiro** nothing. 106864562Sgshapiro*/ 106964562Sgshapiro 107064562Sgshapirostatic void 107164562Sgshapirolistdb() 107264562Sgshapiro{ 107364562Sgshapiro int result; 107464562Sgshapiro time_t t; 107564562Sgshapiro SMDB_CURSOR *cursor = NULL; 107664562Sgshapiro SMDB_DBENT db_key, db_value; 107764562Sgshapiro 107864562Sgshapiro memset(&db_key, '\0', sizeof db_key); 107964562Sgshapiro memset(&db_value, '\0', sizeof db_value); 108064562Sgshapiro 108164562Sgshapiro result = Db->smdb_cursor(Db, &cursor, 0); 108264562Sgshapiro if (result != SMDBE_OK) 108364562Sgshapiro { 108490792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 108590792Sgshapiro "vacation: set cursor: %s\n", 108690792Sgshapiro sm_errstring(result)); 108764562Sgshapiro return; 108864562Sgshapiro } 108964562Sgshapiro 109064562Sgshapiro while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, 109164562Sgshapiro SMDB_CURSOR_GET_NEXT)) == SMDBE_OK) 109264562Sgshapiro { 109398121Sgshapiro char *timestamp; 109498121Sgshapiro 109564562Sgshapiro /* skip magic VIT entry */ 1096110560Sgshapiro if (db_key.size == strlen(VIT) + 1 && 109771345Sgshapiro strncmp((char *)db_key.data, VIT, 109871345Sgshapiro (int)db_key.size - 1) == 0) 109964562Sgshapiro continue; 110064562Sgshapiro 110164562Sgshapiro /* skip bogus values */ 110271345Sgshapiro if (db_value.size != sizeof t) 110364562Sgshapiro { 110490792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 110590792Sgshapiro "vacation: %.*s invalid time stamp\n", 110690792Sgshapiro (int) db_key.size, (char *) db_key.data); 110764562Sgshapiro continue; 110864562Sgshapiro } 110964562Sgshapiro 111071345Sgshapiro memcpy(&t, db_value.data, sizeof t); 111164562Sgshapiro 111271345Sgshapiro if (db_key.size > 40) 111371345Sgshapiro db_key.size = 40; 111464562Sgshapiro 111598121Sgshapiro if (t <= 0) 111698121Sgshapiro { 111798121Sgshapiro /* must be an exclude */ 111898121Sgshapiro timestamp = "(exclusion)\n"; 111998121Sgshapiro } 112098121Sgshapiro else 112198121Sgshapiro { 112298121Sgshapiro timestamp = ctime(&t); 112398121Sgshapiro } 112490792Sgshapiro sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%-40.*s %-10s", 112590792Sgshapiro (int) db_key.size, (char *) db_key.data, 112698121Sgshapiro timestamp); 112764562Sgshapiro 112864562Sgshapiro memset(&db_key, '\0', sizeof db_key); 112964562Sgshapiro memset(&db_value, '\0', sizeof db_value); 113064562Sgshapiro } 113164562Sgshapiro 113264562Sgshapiro if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) 113364562Sgshapiro { 113490792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 113590792Sgshapiro "vacation: get value at cursor: %s\n", 113690792Sgshapiro sm_errstring(result)); 113764562Sgshapiro if (cursor != NULL) 113864562Sgshapiro { 113964562Sgshapiro (void) cursor->smdbc_close(cursor); 114064562Sgshapiro cursor = NULL; 114164562Sgshapiro } 114264562Sgshapiro return; 114364562Sgshapiro } 114464562Sgshapiro (void) cursor->smdbc_close(cursor); 114564562Sgshapiro cursor = NULL; 114664562Sgshapiro} 114764562Sgshapiro 114864562Sgshapiro/* 114964562Sgshapiro** DEBUGLOG -- write message to standard error 115064562Sgshapiro** 115164562Sgshapiro** Append a message to the standard error for the convenience of 115264562Sgshapiro** end-users debugging without access to the syslog messages. 115364562Sgshapiro** 115464562Sgshapiro** Parameters: 115564562Sgshapiro** i -- syslog log level 115664562Sgshapiro** fmt -- string format 115764562Sgshapiro** 115864562Sgshapiro** Returns: 115964562Sgshapiro** nothing. 116064562Sgshapiro*/ 116164562Sgshapiro 116264562Sgshapiro/*VARARGS2*/ 116390792Sgshapirostatic SYSLOG_RET_T 116464562Sgshapiro#ifdef __STDC__ 116564562Sgshapirodebuglog(int i, const char *fmt, ...) 116664562Sgshapiro#else /* __STDC__ */ 116764562Sgshapirodebuglog(i, fmt, va_alist) 116864562Sgshapiro int i; 116964562Sgshapiro const char *fmt; 117064562Sgshapiro va_dcl 117164562Sgshapiro#endif /* __STDC__ */ 117264562Sgshapiro 117364562Sgshapiro{ 117490792Sgshapiro SM_VA_LOCAL_DECL 117564562Sgshapiro 117690792Sgshapiro SM_VA_START(ap, fmt); 117790792Sgshapiro sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap); 117890792Sgshapiro SM_VA_END(ap); 117990792Sgshapiro SYSLOG_RET; 118064562Sgshapiro} 1181