vacation.c revision 141858
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 23141858SgshapiroSM_IDSTR(id, "@(#)$Id: vacation.c,v 8.142 2004/11/02 18:25:33 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]; 81141858Sgshapirobool CloseMBDB = false; 8264562Sgshapiro 8390792Sgshapiro#if defined(__hpux) || defined(__osf__) 8490792Sgshapiro# ifndef SM_CONF_SYSLOG_INT 8590792Sgshapiro# define SM_CONF_SYSLOG_INT 1 8690792Sgshapiro# endif /* SM_CONF_SYSLOG_INT */ 8790792Sgshapiro#endif /* defined(__hpux) || defined(__osf__) */ 8864562Sgshapiro 8990792Sgshapiro#if SM_CONF_SYSLOG_INT 9090792Sgshapiro# define SYSLOG_RET_T int 9190792Sgshapiro# define SYSLOG_RET return 0 9290792Sgshapiro#else /* SM_CONF_SYSLOG_INT */ 9390792Sgshapiro# define SYSLOG_RET_T void 9490792Sgshapiro# define SYSLOG_RET 9590792Sgshapiro#endif /* SM_CONF_SYSLOG_INT */ 9690792Sgshapiro 9790792Sgshapirotypedef SYSLOG_RET_T SYSLOG_T __P((int, const char *, ...)); 9890792SgshapiroSYSLOG_T *msglog = syslog; 9990792Sgshapirostatic SYSLOG_RET_T debuglog __P((int, const char *, ...)); 10066494Sgshapirostatic void eatmsg __P((void)); 10190792Sgshapirostatic void listdb __P((void)); 10266494Sgshapiro 10366494Sgshapiro/* exit after reading input */ 104141858Sgshapiro#define EXITIT(excode) \ 105141858Sgshapiro{ \ 106141858Sgshapiro eatmsg(); \ 107141858Sgshapiro if (CloseMBDB) \ 108141858Sgshapiro { \ 109141858Sgshapiro sm_mbdb_terminate(); \ 110141858Sgshapiro CloseMBDB = false; \ 111141858Sgshapiro } \ 112141858Sgshapiro return excode; \ 11390792Sgshapiro} 11477349Sgshapiro 115141858Sgshapiro#define EXITM(excode) \ 116141858Sgshapiro{ \ 117141858Sgshapiro if (!initdb && !list) \ 118141858Sgshapiro eatmsg(); \ 119141858Sgshapiro if (CloseMBDB) \ 120141858Sgshapiro { \ 121141858Sgshapiro sm_mbdb_terminate(); \ 122141858Sgshapiro CloseMBDB = false; \ 123141858Sgshapiro } \ 124141858Sgshapiro exit(excode); \ 12590792Sgshapiro} 12690792Sgshapiro 12764562Sgshapiroint 12864562Sgshapiromain(argc, argv) 12964562Sgshapiro int argc; 13064562Sgshapiro char **argv; 13164562Sgshapiro{ 13298121Sgshapiro bool alwaysrespond = false; 13398121Sgshapiro bool initdb, exclude; 13490792Sgshapiro bool runasuser = false; 13598121Sgshapiro bool list = false; 13664562Sgshapiro int mfail = 0, ufail = 0; 13764562Sgshapiro int ch; 13864562Sgshapiro int result; 13966494Sgshapiro long sff; 14064562Sgshapiro time_t interval; 14164562Sgshapiro struct passwd *pw; 14264562Sgshapiro ALIAS *cur; 14377349Sgshapiro char *dbfilename = NULL; 14477349Sgshapiro char *msgfilename = NULL; 14590792Sgshapiro char *cfpath = NULL; 14664562Sgshapiro char *name; 14790792Sgshapiro char *returnaddr = NULL; 14864562Sgshapiro SMDB_USER_INFO user_info; 14964562Sgshapiro static char rnamebuf[MAXNAME]; 15064562Sgshapiro extern int optind, opterr; 15164562Sgshapiro extern char *optarg; 15264562Sgshapiro extern void usage __P((void)); 15364562Sgshapiro extern void setinterval __P((time_t)); 15498121Sgshapiro extern int readheaders __P((bool)); 15564562Sgshapiro extern bool recent __P((void)); 15664562Sgshapiro extern void setreply __P((char *, time_t)); 15790792Sgshapiro extern void sendmessage __P((char *, char *, char *)); 15890792Sgshapiro extern void xclude __P((SM_FILE_T *)); 15964562Sgshapiro 16064562Sgshapiro /* Vars needed to link with smutil */ 16164562Sgshapiro clrbitmap(DontBlameSendmail); 16264562Sgshapiro RunAsUid = RealUid = getuid(); 16364562Sgshapiro RunAsGid = RealGid = getgid(); 16464562Sgshapiro pw = getpwuid(RealUid); 16564562Sgshapiro if (pw != NULL) 16664562Sgshapiro { 16764562Sgshapiro if (strlen(pw->pw_name) > MAXNAME - 1) 16864562Sgshapiro pw->pw_name[MAXNAME] = '\0'; 16990792Sgshapiro sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); 17064562Sgshapiro } 17164562Sgshapiro else 17290792Sgshapiro sm_snprintf(rnamebuf, sizeof rnamebuf, 17390792Sgshapiro "Unknown UID %d", (int) RealUid); 17464562Sgshapiro RunAsUserName = RealUserName = rnamebuf; 17564562Sgshapiro 17677349Sgshapiro# ifdef LOG_MAIL 17764562Sgshapiro openlog("vacation", LOG_PID, LOG_MAIL); 17877349Sgshapiro# else /* LOG_MAIL */ 17964562Sgshapiro openlog("vacation", LOG_PID); 18077349Sgshapiro# endif /* LOG_MAIL */ 18164562Sgshapiro 18264562Sgshapiro opterr = 0; 18398121Sgshapiro initdb = false; 18490792Sgshapiro exclude = false; 18564562Sgshapiro interval = INTERVAL_UNDEF; 18664562Sgshapiro *From = '\0'; 18764562Sgshapiro 18864562Sgshapiro 18998121Sgshapiro#define OPTIONS "a:C:df:Iijlm:R:r:s:t:Uxz" 19090792Sgshapiro 19164562Sgshapiro while (mfail == 0 && ufail == 0 && 19264562Sgshapiro (ch = getopt(argc, argv, OPTIONS)) != -1) 19364562Sgshapiro { 19464562Sgshapiro switch((char)ch) 19564562Sgshapiro { 19664562Sgshapiro case 'a': /* alias */ 19790792Sgshapiro cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS)); 19864562Sgshapiro if (cur == NULL) 19964562Sgshapiro { 20064562Sgshapiro mfail++; 20164562Sgshapiro break; 20264562Sgshapiro } 20364562Sgshapiro cur->name = optarg; 20464562Sgshapiro cur->next = Names; 20564562Sgshapiro Names = cur; 20664562Sgshapiro break; 20764562Sgshapiro 20890792Sgshapiro case 'C': 20990792Sgshapiro cfpath = optarg; 21090792Sgshapiro break; 21190792Sgshapiro 21277349Sgshapiro case 'd': /* debug mode */ 21390792Sgshapiro msglog = debuglog; 21464562Sgshapiro break; 21564562Sgshapiro 21664562Sgshapiro case 'f': /* alternate database */ 21764562Sgshapiro dbfilename = optarg; 21864562Sgshapiro break; 21964562Sgshapiro 22064562Sgshapiro case 'I': /* backward compatible */ 22164562Sgshapiro case 'i': /* init the database */ 22298121Sgshapiro initdb = true; 22364562Sgshapiro break; 22464562Sgshapiro 22598121Sgshapiro case 'j': 22698121Sgshapiro alwaysrespond = true; 22798121Sgshapiro break; 22898121Sgshapiro 22964562Sgshapiro case 'l': 23098121Sgshapiro list = true; /* list the database */ 23164562Sgshapiro break; 23264562Sgshapiro 23364562Sgshapiro case 'm': /* alternate message file */ 23464562Sgshapiro msgfilename = optarg; 23564562Sgshapiro break; 23664562Sgshapiro 23790792Sgshapiro case 'R': 23890792Sgshapiro returnaddr = optarg; 23990792Sgshapiro break; 24090792Sgshapiro 24164562Sgshapiro case 'r': 24264562Sgshapiro if (isascii(*optarg) && isdigit(*optarg)) 24364562Sgshapiro { 24464562Sgshapiro interval = atol(optarg) * SECSPERDAY; 24564562Sgshapiro if (interval < 0) 24664562Sgshapiro ufail++; 24764562Sgshapiro } 24864562Sgshapiro else 24964562Sgshapiro interval = ONLY_ONCE; 25064562Sgshapiro break; 25164562Sgshapiro 25264562Sgshapiro case 's': /* alternate sender name */ 25390792Sgshapiro (void) sm_strlcpy(From, optarg, sizeof From); 25464562Sgshapiro break; 25564562Sgshapiro 25664562Sgshapiro case 't': /* SunOS: -t1d (default expire) */ 25764562Sgshapiro break; 25864562Sgshapiro 25977349Sgshapiro case 'U': /* run as single user mode */ 26090792Sgshapiro runasuser = true; 26177349Sgshapiro break; 26277349Sgshapiro 26364562Sgshapiro case 'x': 26490792Sgshapiro exclude = true; 26564562Sgshapiro break; 26664562Sgshapiro 26764562Sgshapiro case 'z': 26890792Sgshapiro returnaddr = "<>"; 26964562Sgshapiro break; 27064562Sgshapiro 27164562Sgshapiro case '?': 27264562Sgshapiro default: 27364562Sgshapiro ufail++; 27464562Sgshapiro break; 27564562Sgshapiro } 27664562Sgshapiro } 27764562Sgshapiro argc -= optind; 27864562Sgshapiro argv += optind; 27964562Sgshapiro 28064562Sgshapiro if (mfail != 0) 28164562Sgshapiro { 28264562Sgshapiro msglog(LOG_NOTICE, 28364562Sgshapiro "vacation: can't allocate memory for alias.\n"); 28466494Sgshapiro EXITM(EX_TEMPFAIL); 28564562Sgshapiro } 28664562Sgshapiro if (ufail != 0) 28764562Sgshapiro usage(); 28864562Sgshapiro 28964562Sgshapiro if (argc != 1) 29064562Sgshapiro { 29198121Sgshapiro if (!initdb && !list && !exclude) 29264562Sgshapiro usage(); 29364562Sgshapiro if ((pw = getpwuid(getuid())) == NULL) 29464562Sgshapiro { 29564562Sgshapiro msglog(LOG_ERR, 29664562Sgshapiro "vacation: no such user uid %u.\n", getuid()); 29766494Sgshapiro EXITM(EX_NOUSER); 29864562Sgshapiro } 29977349Sgshapiro name = pw->pw_name; 30077349Sgshapiro user_info.smdbu_id = pw->pw_uid; 30177349Sgshapiro user_info.smdbu_group_id = pw->pw_gid; 30290792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name, 30390792Sgshapiro SMDB_MAX_USER_NAME_LEN); 30477349Sgshapiro if (chdir(pw->pw_dir) != 0) 30577349Sgshapiro { 30690792Sgshapiro msglog(LOG_NOTICE, 30790792Sgshapiro "vacation: no such directory %s.\n", 30877349Sgshapiro pw->pw_dir); 30977349Sgshapiro EXITM(EX_NOINPUT); 31077349Sgshapiro } 31164562Sgshapiro } 31277349Sgshapiro else if (runasuser) 31377349Sgshapiro { 31477349Sgshapiro name = *argv; 31577349Sgshapiro if (dbfilename == NULL || msgfilename == NULL) 31677349Sgshapiro { 31777349Sgshapiro msglog(LOG_NOTICE, 31877349Sgshapiro "vacation: -U requires setting both -f and -m\n"); 31977349Sgshapiro EXITM(EX_NOINPUT); 32077349Sgshapiro } 32177349Sgshapiro user_info.smdbu_id = pw->pw_uid; 32277349Sgshapiro user_info.smdbu_group_id = pw->pw_gid; 32390792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name, 32477349Sgshapiro SMDB_MAX_USER_NAME_LEN); 32577349Sgshapiro } 32677349Sgshapiro else 32764562Sgshapiro { 32890792Sgshapiro int err; 32990792Sgshapiro SM_CF_OPT_T mbdbname; 33090792Sgshapiro SM_MBDB_T user; 33190792Sgshapiro 33294334Sgshapiro cfpath = getcfname(0, 0, SM_GET_SENDMAIL_CF, cfpath); 33390792Sgshapiro mbdbname.opt_name = "MailboxDatabase"; 33490792Sgshapiro mbdbname.opt_val = "pw"; 33590792Sgshapiro (void) sm_cf_getopt(cfpath, 1, &mbdbname); 33690792Sgshapiro err = sm_mbdb_initialize(mbdbname.opt_val); 33790792Sgshapiro if (err != EX_OK) 33877349Sgshapiro { 33990792Sgshapiro msglog(LOG_ERR, 34090792Sgshapiro "vacation: can't open mailbox database: %s.\n", 34190792Sgshapiro sm_strexit(err)); 34290792Sgshapiro EXITM(err); 34390792Sgshapiro } 344141858Sgshapiro CloseMBDB = true; 34590792Sgshapiro err = sm_mbdb_lookup(*argv, &user); 34690792Sgshapiro if (err == EX_NOUSER) 34790792Sgshapiro { 34890792Sgshapiro msglog(LOG_ERR, "vacation: no such user %s.\n", *argv); 34990792Sgshapiro EXITM(EX_NOUSER); 35090792Sgshapiro } 35190792Sgshapiro if (err != EX_OK) 35290792Sgshapiro { 35390792Sgshapiro msglog(LOG_ERR, 35490792Sgshapiro "vacation: can't read mailbox database: %s.\n", 35590792Sgshapiro sm_strexit(err)); 35690792Sgshapiro EXITM(err); 35790792Sgshapiro } 35890792Sgshapiro name = user.mbdb_name; 35990792Sgshapiro if (chdir(user.mbdb_homedir) != 0) 36090792Sgshapiro { 36190792Sgshapiro msglog(LOG_NOTICE, 36290792Sgshapiro "vacation: no such directory %s.\n", 36390792Sgshapiro user.mbdb_homedir); 36477349Sgshapiro EXITM(EX_NOINPUT); 36577349Sgshapiro } 36690792Sgshapiro user_info.smdbu_id = user.mbdb_uid; 36790792Sgshapiro user_info.smdbu_group_id = user.mbdb_gid; 36890792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, user.mbdb_name, 36977349Sgshapiro SMDB_MAX_USER_NAME_LEN); 37064562Sgshapiro } 37164562Sgshapiro 37277349Sgshapiro if (dbfilename == NULL) 37377349Sgshapiro dbfilename = VDB; 37477349Sgshapiro if (msgfilename == NULL) 37577349Sgshapiro msgfilename = VMSG; 37677349Sgshapiro 37766494Sgshapiro sff = SFF_CREAT; 37866494Sgshapiro if (getegid() != getgid()) 37977349Sgshapiro { 38090792Sgshapiro /* Allow a set-group-ID vacation binary */ 38166494Sgshapiro RunAsGid = user_info.smdbu_group_id = getegid(); 38290792Sgshapiro sff |= SFF_OPENASROOT; 38377349Sgshapiro } 38494334Sgshapiro if (getuid() == 0) 38594334Sgshapiro { 38694334Sgshapiro /* Allow root to initialize user's vacation databases */ 38794334Sgshapiro sff |= SFF_OPENASROOT|SFF_ROOTOK; 38866494Sgshapiro 38994334Sgshapiro /* ... safely */ 39094334Sgshapiro sff |= SFF_NOSLINK|SFF_NOHLINK|SFF_REGONLY; 39194334Sgshapiro } 39294334Sgshapiro 39394334Sgshapiro 39464562Sgshapiro result = smdb_open_database(&Db, dbfilename, 39598121Sgshapiro O_CREAT|O_RDWR | (initdb ? O_TRUNC : 0), 39666494Sgshapiro S_IRUSR|S_IWUSR, sff, 39764562Sgshapiro SMDB_TYPE_DEFAULT, &user_info, NULL); 39864562Sgshapiro if (result != SMDBE_OK) 39964562Sgshapiro { 40064562Sgshapiro msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename, 40190792Sgshapiro sm_errstring(result)); 40266494Sgshapiro EXITM(EX_DATAERR); 40364562Sgshapiro } 40464562Sgshapiro 40598121Sgshapiro if (list) 40664562Sgshapiro { 40764562Sgshapiro listdb(); 40871345Sgshapiro (void) Db->smdb_close(Db); 40964562Sgshapiro exit(EX_OK); 41064562Sgshapiro } 41164562Sgshapiro 41264562Sgshapiro if (interval != INTERVAL_UNDEF) 41364562Sgshapiro setinterval(interval); 41464562Sgshapiro 41598121Sgshapiro if (initdb && !exclude) 41664562Sgshapiro { 41771345Sgshapiro (void) Db->smdb_close(Db); 41871345Sgshapiro exit(EX_OK); 41964562Sgshapiro } 42064562Sgshapiro 42164562Sgshapiro if (exclude) 42264562Sgshapiro { 42390792Sgshapiro xclude(smioin); 42471345Sgshapiro (void) Db->smdb_close(Db); 42566494Sgshapiro EXITM(EX_OK); 42664562Sgshapiro } 42764562Sgshapiro 42890792Sgshapiro if ((cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS))) == NULL) 42964562Sgshapiro { 43064562Sgshapiro msglog(LOG_NOTICE, 43164562Sgshapiro "vacation: can't allocate memory for username.\n"); 43271345Sgshapiro (void) Db->smdb_close(Db); 43366494Sgshapiro EXITM(EX_OSERR); 43464562Sgshapiro } 43564562Sgshapiro cur->name = name; 43664562Sgshapiro cur->next = Names; 43764562Sgshapiro Names = cur; 43864562Sgshapiro 43998121Sgshapiro result = readheaders(alwaysrespond); 44071345Sgshapiro if (result == EX_OK && !recent()) 44164562Sgshapiro { 44264562Sgshapiro time_t now; 44364562Sgshapiro 44464562Sgshapiro (void) time(&now); 44564562Sgshapiro setreply(From, now); 44671345Sgshapiro (void) Db->smdb_close(Db); 44790792Sgshapiro sendmessage(name, msgfilename, returnaddr); 44864562Sgshapiro } 44964562Sgshapiro else 45071345Sgshapiro (void) Db->smdb_close(Db); 45171345Sgshapiro if (result == EX_NOUSER) 45271345Sgshapiro result = EX_OK; 45371345Sgshapiro exit(result); 45464562Sgshapiro} 45564562Sgshapiro 45664562Sgshapiro/* 45766494Sgshapiro** EATMSG -- read stdin till EOF 45866494Sgshapiro** 45966494Sgshapiro** Parameters: 46066494Sgshapiro** none. 46166494Sgshapiro** 46266494Sgshapiro** Returns: 46366494Sgshapiro** nothing. 46466494Sgshapiro** 46566494Sgshapiro*/ 46677349Sgshapiro 46766494Sgshapirostatic void 46866494Sgshapiroeatmsg() 46966494Sgshapiro{ 47066494Sgshapiro /* 47166494Sgshapiro ** read the rest of the e-mail and ignore it to avoid problems 47266494Sgshapiro ** with EPIPE in sendmail 47366494Sgshapiro */ 47466494Sgshapiro while (getc(stdin) != EOF) 47566494Sgshapiro continue; 47666494Sgshapiro} 47766494Sgshapiro 47866494Sgshapiro/* 47964562Sgshapiro** READHEADERS -- read mail headers 48064562Sgshapiro** 48164562Sgshapiro** Parameters: 48298121Sgshapiro** alwaysrespond -- respond regardless of whether msg is to me 48364562Sgshapiro** 48464562Sgshapiro** Returns: 48571345Sgshapiro** a exit code: NOUSER if no reply, OK if reply, * if error 48664562Sgshapiro** 48766494Sgshapiro** Side Effects: 48866494Sgshapiro** may exit(). 48966494Sgshapiro** 49064562Sgshapiro*/ 49171345Sgshapiro 49271345Sgshapiroint 49398121Sgshapiroreadheaders(alwaysrespond) 49498121Sgshapiro bool alwaysrespond; 49564562Sgshapiro{ 49664562Sgshapiro bool tome, cont; 49764562Sgshapiro register char *p; 49864562Sgshapiro register ALIAS *cur; 49964562Sgshapiro char buf[MAXLINE]; 50064562Sgshapiro extern bool junkmail __P((char *)); 50164562Sgshapiro extern bool nsearch __P((char *, char *)); 50264562Sgshapiro 50398121Sgshapiro cont = false; 50498121Sgshapiro tome = alwaysrespond; 50590792Sgshapiro while (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, sizeof(buf)) && 50690792Sgshapiro *buf != '\n') 50764562Sgshapiro { 50864562Sgshapiro switch(*buf) 50964562Sgshapiro { 51064562Sgshapiro case 'F': /* "From " */ 51190792Sgshapiro cont = false; 51264562Sgshapiro if (strncmp(buf, "From ", 5) == 0) 51364562Sgshapiro { 51490792Sgshapiro bool quoted = false; 51564562Sgshapiro 51664562Sgshapiro p = buf + 5; 51764562Sgshapiro while (*p != '\0') 51864562Sgshapiro { 51964562Sgshapiro /* escaped character */ 52064562Sgshapiro if (*p == '\\') 52164562Sgshapiro { 52264562Sgshapiro p++; 52364562Sgshapiro if (*p == '\0') 52464562Sgshapiro { 52564562Sgshapiro msglog(LOG_NOTICE, 52664562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 52766494Sgshapiro EXITIT(EX_DATAERR); 52864562Sgshapiro } 52964562Sgshapiro } 53064562Sgshapiro else if (*p == '"') 53164562Sgshapiro quoted = !quoted; 53264562Sgshapiro else if (*p == '\r' || *p == '\n') 53364562Sgshapiro break; 53464562Sgshapiro else if (*p == ' ' && !quoted) 53564562Sgshapiro break; 53664562Sgshapiro p++; 53764562Sgshapiro } 53864562Sgshapiro if (quoted) 53964562Sgshapiro { 54064562Sgshapiro msglog(LOG_NOTICE, 54164562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 54266494Sgshapiro EXITIT(EX_DATAERR); 54364562Sgshapiro } 54464562Sgshapiro *p = '\0'; 54564562Sgshapiro 54664562Sgshapiro /* ok since both strings have MAXLINE length */ 54764562Sgshapiro if (*From == '\0') 54890792Sgshapiro (void) sm_strlcpy(From, buf + 5, 54990792Sgshapiro sizeof From); 55064562Sgshapiro if ((p = strchr(buf + 5, '\n')) != NULL) 55164562Sgshapiro *p = '\0'; 55264562Sgshapiro if (junkmail(buf + 5)) 55371345Sgshapiro EXITIT(EX_NOUSER); 55464562Sgshapiro } 55564562Sgshapiro break; 55664562Sgshapiro 55764562Sgshapiro case 'P': /* "Precedence:" */ 55864562Sgshapiro case 'p': 55990792Sgshapiro cont = false; 56064562Sgshapiro if (strlen(buf) <= 10 || 56164562Sgshapiro strncasecmp(buf, "Precedence", 10) != 0 || 56264562Sgshapiro (buf[10] != ':' && buf[10] != ' ' && 56364562Sgshapiro buf[10] != '\t')) 56464562Sgshapiro break; 56564562Sgshapiro if ((p = strchr(buf, ':')) == NULL) 56664562Sgshapiro break; 56764562Sgshapiro while (*++p != '\0' && isascii(*p) && isspace(*p)); 56864562Sgshapiro if (*p == '\0') 56964562Sgshapiro break; 57064562Sgshapiro if (strncasecmp(p, "junk", 4) == 0 || 57164562Sgshapiro strncasecmp(p, "bulk", 4) == 0 || 57264562Sgshapiro strncasecmp(p, "list", 4) == 0) 57371345Sgshapiro EXITIT(EX_NOUSER); 57464562Sgshapiro break; 57564562Sgshapiro 57664562Sgshapiro case 'C': /* "Cc:" */ 57764562Sgshapiro case 'c': 57864562Sgshapiro if (strncasecmp(buf, "Cc:", 3) != 0) 57964562Sgshapiro break; 58090792Sgshapiro cont = true; 58164562Sgshapiro goto findme; 58264562Sgshapiro 58364562Sgshapiro case 'T': /* "To:" */ 58464562Sgshapiro case 't': 58564562Sgshapiro if (strncasecmp(buf, "To:", 3) != 0) 58664562Sgshapiro break; 58790792Sgshapiro cont = true; 58864562Sgshapiro goto findme; 58964562Sgshapiro 59064562Sgshapiro default: 59164562Sgshapiro if (!isascii(*buf) || !isspace(*buf) || !cont || tome) 59264562Sgshapiro { 59390792Sgshapiro cont = false; 59464562Sgshapiro break; 59564562Sgshapiro } 59664562Sgshapirofindme: 59764562Sgshapiro for (cur = Names; 59864562Sgshapiro !tome && cur != NULL; 59964562Sgshapiro cur = cur->next) 60064562Sgshapiro tome = nsearch(cur->name, buf); 60164562Sgshapiro } 60264562Sgshapiro } 60364562Sgshapiro if (!tome) 60471345Sgshapiro EXITIT(EX_NOUSER); 60564562Sgshapiro if (*From == '\0') 60664562Sgshapiro { 60764562Sgshapiro msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n"); 60866494Sgshapiro EXITIT(EX_DATAERR); 60964562Sgshapiro } 61071345Sgshapiro EXITIT(EX_OK); 61164562Sgshapiro} 61264562Sgshapiro 61364562Sgshapiro/* 61464562Sgshapiro** NSEARCH -- 61564562Sgshapiro** do a nice, slow, search of a string for a substring. 61664562Sgshapiro** 61764562Sgshapiro** Parameters: 61864562Sgshapiro** name -- name to search. 61964562Sgshapiro** str -- string in which to search. 62064562Sgshapiro** 62164562Sgshapiro** Returns: 62264562Sgshapiro** is name a substring of str? 62364562Sgshapiro** 62464562Sgshapiro*/ 62577349Sgshapiro 62664562Sgshapirobool 62764562Sgshapironsearch(name, str) 62864562Sgshapiro register char *name, *str; 62964562Sgshapiro{ 63064562Sgshapiro register size_t len; 63164562Sgshapiro register char *s; 63264562Sgshapiro 63364562Sgshapiro len = strlen(name); 63464562Sgshapiro 63564562Sgshapiro for (s = str; *s != '\0'; ++s) 63664562Sgshapiro { 63764562Sgshapiro /* 63864562Sgshapiro ** Check to make sure that the string matches and 63964562Sgshapiro ** the previous character is not an alphanumeric and 64064562Sgshapiro ** the next character after the match is not an alphanumeric. 64164562Sgshapiro ** 64264562Sgshapiro ** This prevents matching "eric" to "derick" while still 64364562Sgshapiro ** matching "eric" to "<eric+detail>". 64464562Sgshapiro */ 64564562Sgshapiro 64664562Sgshapiro if (tolower(*s) == tolower(*name) && 64764562Sgshapiro strncasecmp(name, s, len) == 0 && 64864562Sgshapiro (s == str || !isascii(*(s - 1)) || !isalnum(*(s - 1))) && 64964562Sgshapiro (!isascii(*(s + len)) || !isalnum(*(s + len)))) 65090792Sgshapiro return true; 65164562Sgshapiro } 65290792Sgshapiro return false; 65364562Sgshapiro} 65464562Sgshapiro 65564562Sgshapiro/* 65664562Sgshapiro** JUNKMAIL -- 65764562Sgshapiro** read the header and return if automagic/junk/bulk/list mail 65864562Sgshapiro** 65964562Sgshapiro** Parameters: 66064562Sgshapiro** from -- sender address. 66164562Sgshapiro** 66264562Sgshapiro** Returns: 66364562Sgshapiro** is this some automated/junk/bulk/list mail? 66464562Sgshapiro** 66564562Sgshapiro*/ 66671345Sgshapiro 66771345Sgshapirostruct ignore 66871345Sgshapiro{ 66971345Sgshapiro char *name; 67071345Sgshapiro size_t len; 67171345Sgshapiro}; 67271345Sgshapiro 67371345Sgshapirotypedef struct ignore IGNORE_T; 67471345Sgshapiro 67571345Sgshapiro#define MAX_USER_LEN 256 /* maximum length of local part (sender) */ 67671345Sgshapiro 67771345Sgshapiro/* delimiters for the local part of an address */ 67871345Sgshapiro#define isdelim(c) ((c) == '%' || (c) == '@' || (c) == '+') 67971345Sgshapiro 68064562Sgshapirobool 68164562Sgshapirojunkmail(from) 68264562Sgshapiro char *from; 68364562Sgshapiro{ 68471345Sgshapiro bool quot; 68571345Sgshapiro char *e; 68671345Sgshapiro size_t len; 68771345Sgshapiro IGNORE_T *cur; 68871345Sgshapiro char sender[MAX_USER_LEN]; 68971345Sgshapiro static IGNORE_T ignore[] = 69064562Sgshapiro { 69164562Sgshapiro { "postmaster", 10 }, 69264562Sgshapiro { "uucp", 4 }, 69364562Sgshapiro { "mailer-daemon", 13 }, 69464562Sgshapiro { "mailer", 6 }, 69571345Sgshapiro { NULL, 0 } 69671345Sgshapiro }; 69771345Sgshapiro 69871345Sgshapiro static IGNORE_T ignorepost[] = 69971345Sgshapiro { 70071345Sgshapiro { "-request", 8 }, 70164562Sgshapiro { "-relay", 6 }, 70271345Sgshapiro { "-owner", 6 }, 70364562Sgshapiro { NULL, 0 } 70464562Sgshapiro }; 70564562Sgshapiro 70671345Sgshapiro static IGNORE_T ignorepre[] = 70771345Sgshapiro { 70871345Sgshapiro { "owner-", 6 }, 70971345Sgshapiro { NULL, 0 } 71071345Sgshapiro }; 71171345Sgshapiro 71264562Sgshapiro /* 71371345Sgshapiro ** This is mildly amusing, and I'm not positive it's right; trying 71471345Sgshapiro ** to find the "real" name of the sender, assuming that addresses 71571345Sgshapiro ** will be some variant of: 71671345Sgshapiro ** 71771345Sgshapiro ** From site!site!SENDER%site.domain%site.domain@site.domain 71871345Sgshapiro */ 71971345Sgshapiro 72090792Sgshapiro quot = false; 72171345Sgshapiro e = from; 72271345Sgshapiro len = 0; 72371345Sgshapiro while (*e != '\0' && (quot || !isdelim(*e))) 72464562Sgshapiro { 72571345Sgshapiro if (*e == '"') 72671345Sgshapiro { 72771345Sgshapiro quot = !quot; 72871345Sgshapiro ++e; 72971345Sgshapiro continue; 73071345Sgshapiro } 73171345Sgshapiro if (*e == '\\') 73271345Sgshapiro { 73371345Sgshapiro if (*(++e) == '\0') 73471345Sgshapiro { 73571345Sgshapiro /* '\\' at end of string? */ 73671345Sgshapiro break; 73771345Sgshapiro } 73871345Sgshapiro if (len < MAX_USER_LEN) 73971345Sgshapiro sender[len++] = *e; 74071345Sgshapiro ++e; 74171345Sgshapiro continue; 74271345Sgshapiro } 74371345Sgshapiro if (*e == '!' && !quot) 74471345Sgshapiro { 74571345Sgshapiro len = 0; 74671345Sgshapiro sender[len] = '\0'; 74771345Sgshapiro } 74864562Sgshapiro else 74971345Sgshapiro if (len < MAX_USER_LEN) 75071345Sgshapiro sender[len++] = *e; 75171345Sgshapiro ++e; 75264562Sgshapiro } 75371345Sgshapiro if (len < MAX_USER_LEN) 75471345Sgshapiro sender[len] = '\0'; 75571345Sgshapiro else 75671345Sgshapiro sender[MAX_USER_LEN - 1] = '\0'; 75771345Sgshapiro 75871345Sgshapiro if (len <= 0) 75990792Sgshapiro return false; 76071345Sgshapiro#if 0 76171345Sgshapiro if (quot) 76290792Sgshapiro return false; /* syntax error... */ 76371345Sgshapiro#endif /* 0 */ 76471345Sgshapiro 76571345Sgshapiro /* test prefixes */ 76671345Sgshapiro for (cur = ignorepre; cur->name != NULL; ++cur) 76771345Sgshapiro { 76871345Sgshapiro if (len >= cur->len && 76971345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 77090792Sgshapiro return true; 77171345Sgshapiro } 77271345Sgshapiro 77371345Sgshapiro /* 77471345Sgshapiro ** If the name is truncated, don't test the rest. 77571345Sgshapiro ** We could extract the "tail" of the sender address and 77671345Sgshapiro ** compare it it ignorepost, however, it seems not worth 77771345Sgshapiro ** the effort. 77871345Sgshapiro ** The address surely can't match any entry in ignore[] 77971345Sgshapiro ** (as long as all of them are shorter than MAX_USER_LEN). 78071345Sgshapiro */ 78171345Sgshapiro 78271345Sgshapiro if (len > MAX_USER_LEN) 78390792Sgshapiro return false; 78471345Sgshapiro 78571345Sgshapiro /* test full local parts */ 78664562Sgshapiro for (cur = ignore; cur->name != NULL; ++cur) 78764562Sgshapiro { 78871345Sgshapiro if (len == cur->len && 78971345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 79090792Sgshapiro return true; 79171345Sgshapiro } 79271345Sgshapiro 79371345Sgshapiro /* test postfixes */ 79471345Sgshapiro for (cur = ignorepost; cur->name != NULL; ++cur) 79571345Sgshapiro { 79664562Sgshapiro if (len >= cur->len && 79771345Sgshapiro strncasecmp(cur->name, e - cur->len - 1, 79871345Sgshapiro cur->len) == 0) 79990792Sgshapiro return true; 80064562Sgshapiro } 80190792Sgshapiro return false; 80264562Sgshapiro} 80364562Sgshapiro 80464562Sgshapiro#define VIT "__VACATION__INTERVAL__TIMER__" 80564562Sgshapiro 80664562Sgshapiro/* 80764562Sgshapiro** RECENT -- 80864562Sgshapiro** find out if user has gotten a vacation message recently. 80964562Sgshapiro** 81064562Sgshapiro** Parameters: 81164562Sgshapiro** none. 81264562Sgshapiro** 81364562Sgshapiro** Returns: 81490792Sgshapiro** true iff user has gotten a vacation message recently. 81564562Sgshapiro** 81664562Sgshapiro*/ 81777349Sgshapiro 81864562Sgshapirobool 81964562Sgshapirorecent() 82064562Sgshapiro{ 82164562Sgshapiro SMDB_DBENT key, data; 82264562Sgshapiro time_t then, next; 82390792Sgshapiro bool trydomain = false; 82464562Sgshapiro int st; 82564562Sgshapiro char *domain; 82664562Sgshapiro 82764562Sgshapiro memset(&key, '\0', sizeof key); 82864562Sgshapiro memset(&data, '\0', sizeof data); 82964562Sgshapiro 83064562Sgshapiro /* get interval time */ 83171345Sgshapiro key.data = VIT; 83271345Sgshapiro key.size = sizeof(VIT); 83364562Sgshapiro 83464562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 83564562Sgshapiro if (st != SMDBE_OK) 83664562Sgshapiro next = SECSPERDAY * DAYSPERWEEK; 83764562Sgshapiro else 83871345Sgshapiro memmove(&next, data.data, sizeof(next)); 83964562Sgshapiro 84064562Sgshapiro memset(&data, '\0', sizeof data); 84164562Sgshapiro 84264562Sgshapiro /* get record for this address */ 84371345Sgshapiro key.data = From; 84471345Sgshapiro key.size = strlen(From); 84564562Sgshapiro 84664562Sgshapiro do 84764562Sgshapiro { 84864562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 84964562Sgshapiro if (st == SMDBE_OK) 85064562Sgshapiro { 85171345Sgshapiro memmove(&then, data.data, sizeof(then)); 85264562Sgshapiro if (next == ONLY_ONCE || then == ONLY_ONCE || 85364562Sgshapiro then + next > time(NULL)) 85490792Sgshapiro return true; 85564562Sgshapiro } 85664562Sgshapiro if ((trydomain = !trydomain) && 85764562Sgshapiro (domain = strchr(From, '@')) != NULL) 85864562Sgshapiro { 85971345Sgshapiro key.data = domain; 86071345Sgshapiro key.size = strlen(domain); 86164562Sgshapiro } 86264562Sgshapiro } while (trydomain); 86390792Sgshapiro return false; 86464562Sgshapiro} 86564562Sgshapiro 86664562Sgshapiro/* 86764562Sgshapiro** SETINTERVAL -- 86864562Sgshapiro** store the reply interval 86964562Sgshapiro** 87064562Sgshapiro** Parameters: 87164562Sgshapiro** interval -- time interval for replies. 87264562Sgshapiro** 87364562Sgshapiro** Returns: 87464562Sgshapiro** nothing. 87564562Sgshapiro** 87664562Sgshapiro** Side Effects: 87764562Sgshapiro** stores the reply interval in database. 87864562Sgshapiro*/ 87977349Sgshapiro 88064562Sgshapirovoid 88164562Sgshapirosetinterval(interval) 88264562Sgshapiro time_t interval; 88364562Sgshapiro{ 88464562Sgshapiro SMDB_DBENT key, data; 88564562Sgshapiro 88664562Sgshapiro memset(&key, '\0', sizeof key); 88764562Sgshapiro memset(&data, '\0', sizeof data); 88864562Sgshapiro 88971345Sgshapiro key.data = VIT; 89071345Sgshapiro key.size = sizeof(VIT); 89171345Sgshapiro data.data = (char*) &interval; 89271345Sgshapiro data.size = sizeof(interval); 89371345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 89464562Sgshapiro} 89564562Sgshapiro 89664562Sgshapiro/* 89764562Sgshapiro** SETREPLY -- 89864562Sgshapiro** store that this user knows about the vacation. 89964562Sgshapiro** 90064562Sgshapiro** Parameters: 90164562Sgshapiro** from -- sender address. 90264562Sgshapiro** when -- last reply time. 90364562Sgshapiro** 90464562Sgshapiro** Returns: 90564562Sgshapiro** nothing. 90664562Sgshapiro** 90764562Sgshapiro** Side Effects: 90864562Sgshapiro** stores user/time in database. 90964562Sgshapiro*/ 91077349Sgshapiro 91164562Sgshapirovoid 91264562Sgshapirosetreply(from, when) 91364562Sgshapiro char *from; 91464562Sgshapiro time_t when; 91564562Sgshapiro{ 91664562Sgshapiro SMDB_DBENT key, data; 91764562Sgshapiro 91864562Sgshapiro memset(&key, '\0', sizeof key); 91964562Sgshapiro memset(&data, '\0', sizeof data); 92064562Sgshapiro 92171345Sgshapiro key.data = from; 92271345Sgshapiro key.size = strlen(from); 92371345Sgshapiro data.data = (char*) &when; 92471345Sgshapiro data.size = sizeof(when); 92571345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 92664562Sgshapiro} 92764562Sgshapiro 92864562Sgshapiro/* 92964562Sgshapiro** XCLUDE -- 93064562Sgshapiro** add users to vacation db so they don't get a reply. 93164562Sgshapiro** 93264562Sgshapiro** Parameters: 93364562Sgshapiro** f -- file pointer with list of address to exclude 93464562Sgshapiro** 93564562Sgshapiro** Returns: 93664562Sgshapiro** nothing. 93764562Sgshapiro** 93864562Sgshapiro** Side Effects: 93964562Sgshapiro** stores users in database. 94064562Sgshapiro*/ 94177349Sgshapiro 94264562Sgshapirovoid 94364562Sgshapiroxclude(f) 94490792Sgshapiro SM_FILE_T *f; 94564562Sgshapiro{ 94664562Sgshapiro char buf[MAXLINE], *p; 94764562Sgshapiro 94864562Sgshapiro if (f == NULL) 94964562Sgshapiro return; 95090792Sgshapiro while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf)) 95164562Sgshapiro { 95264562Sgshapiro if ((p = strchr(buf, '\n')) != NULL) 95364562Sgshapiro *p = '\0'; 95464562Sgshapiro setreply(buf, ONLY_ONCE); 95564562Sgshapiro } 95664562Sgshapiro} 95764562Sgshapiro 95864562Sgshapiro/* 95964562Sgshapiro** SENDMESSAGE -- 96064562Sgshapiro** exec sendmail to send the vacation file to sender 96164562Sgshapiro** 96264562Sgshapiro** Parameters: 96364562Sgshapiro** myname -- user name. 96464562Sgshapiro** msgfn -- name of file with vacation message. 96590792Sgshapiro** sender -- use as sender address 96664562Sgshapiro** 96764562Sgshapiro** Returns: 96864562Sgshapiro** nothing. 96964562Sgshapiro** 97064562Sgshapiro** Side Effects: 97164562Sgshapiro** sends vacation reply. 97264562Sgshapiro*/ 97377349Sgshapiro 97464562Sgshapirovoid 97590792Sgshapirosendmessage(myname, msgfn, sender) 97664562Sgshapiro char *myname; 97764562Sgshapiro char *msgfn; 97890792Sgshapiro char *sender; 97964562Sgshapiro{ 98090792Sgshapiro SM_FILE_T *mfp, *sfp; 98164562Sgshapiro int i; 98264562Sgshapiro int pvect[2]; 98377349Sgshapiro char *pv[8]; 98464562Sgshapiro char buf[MAXLINE]; 98564562Sgshapiro 98690792Sgshapiro mfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, msgfn, SM_IO_RDONLY, NULL); 98764562Sgshapiro if (mfp == NULL) 98864562Sgshapiro { 98964562Sgshapiro if (msgfn[0] == '/') 99064562Sgshapiro msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn); 99164562Sgshapiro else 99264562Sgshapiro msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", 99364562Sgshapiro myname, msgfn); 99464562Sgshapiro exit(EX_NOINPUT); 99564562Sgshapiro } 99664562Sgshapiro if (pipe(pvect) < 0) 99764562Sgshapiro { 99890792Sgshapiro msglog(LOG_ERR, "vacation: pipe: %s", sm_errstring(errno)); 99964562Sgshapiro exit(EX_OSERR); 100064562Sgshapiro } 100177349Sgshapiro pv[0] = "sendmail"; 100277349Sgshapiro pv[1] = "-oi"; 100377349Sgshapiro pv[2] = "-f"; 100490792Sgshapiro if (sender != NULL) 100590792Sgshapiro pv[3] = sender; 100677349Sgshapiro else 100777349Sgshapiro pv[3] = myname; 100877349Sgshapiro pv[4] = "--"; 100977349Sgshapiro pv[5] = From; 101077349Sgshapiro pv[6] = NULL; 101164562Sgshapiro i = fork(); 101264562Sgshapiro if (i < 0) 101364562Sgshapiro { 101490792Sgshapiro msglog(LOG_ERR, "vacation: fork: %s", sm_errstring(errno)); 101564562Sgshapiro exit(EX_OSERR); 101664562Sgshapiro } 101764562Sgshapiro if (i == 0) 101864562Sgshapiro { 101964562Sgshapiro (void) dup2(pvect[0], 0); 102064562Sgshapiro (void) close(pvect[0]); 102164562Sgshapiro (void) close(pvect[1]); 102290792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 102377349Sgshapiro (void) execv(_PATH_SENDMAIL, pv); 102464562Sgshapiro msglog(LOG_ERR, "vacation: can't exec %s: %s", 102590792Sgshapiro _PATH_SENDMAIL, sm_errstring(errno)); 102664562Sgshapiro exit(EX_UNAVAILABLE); 102764562Sgshapiro } 102864562Sgshapiro /* check return status of the following calls? XXX */ 102964562Sgshapiro (void) close(pvect[0]); 103090792Sgshapiro if ((sfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 103190792Sgshapiro (void *) &(pvect[1]), 103290792Sgshapiro SM_IO_WRONLY, NULL)) != NULL) 103364562Sgshapiro { 103490792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, "To: %s\n", From); 103590792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, 103690792Sgshapiro "Auto-Submitted: auto-replied\n"); 103790792Sgshapiro while (sm_io_fgets(mfp, SM_TIME_DEFAULT, buf, sizeof buf)) 103890792Sgshapiro (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf); 103990792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 104090792Sgshapiro (void) sm_io_close(sfp, SM_TIME_DEFAULT); 104164562Sgshapiro } 104264562Sgshapiro else 104364562Sgshapiro { 104490792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 104564562Sgshapiro msglog(LOG_ERR, "vacation: can't open pipe to sendmail"); 104664562Sgshapiro exit(EX_UNAVAILABLE); 104764562Sgshapiro } 104864562Sgshapiro} 104964562Sgshapiro 105064562Sgshapirovoid 105164562Sgshapirousage() 105264562Sgshapiro{ 105377349Sgshapiro msglog(LOG_NOTICE, 1054132943Sgshapiro "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", 1055132943Sgshapiro getuid()); 105664562Sgshapiro exit(EX_USAGE); 105764562Sgshapiro} 105864562Sgshapiro 105964562Sgshapiro/* 106064562Sgshapiro** LISTDB -- list the contents of the vacation database 106164562Sgshapiro** 106264562Sgshapiro** Parameters: 106364562Sgshapiro** none. 106464562Sgshapiro** 106564562Sgshapiro** Returns: 106664562Sgshapiro** nothing. 106764562Sgshapiro*/ 106864562Sgshapiro 106964562Sgshapirostatic void 107064562Sgshapirolistdb() 107164562Sgshapiro{ 107264562Sgshapiro int result; 107364562Sgshapiro time_t t; 107464562Sgshapiro SMDB_CURSOR *cursor = NULL; 107564562Sgshapiro SMDB_DBENT db_key, db_value; 107664562Sgshapiro 107764562Sgshapiro memset(&db_key, '\0', sizeof db_key); 107864562Sgshapiro memset(&db_value, '\0', sizeof db_value); 107964562Sgshapiro 108064562Sgshapiro result = Db->smdb_cursor(Db, &cursor, 0); 108164562Sgshapiro if (result != SMDBE_OK) 108264562Sgshapiro { 108390792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 108490792Sgshapiro "vacation: set cursor: %s\n", 108590792Sgshapiro sm_errstring(result)); 108664562Sgshapiro return; 108764562Sgshapiro } 108864562Sgshapiro 108964562Sgshapiro while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, 109064562Sgshapiro SMDB_CURSOR_GET_NEXT)) == SMDBE_OK) 109164562Sgshapiro { 109298121Sgshapiro char *timestamp; 109398121Sgshapiro 109464562Sgshapiro /* skip magic VIT entry */ 1095110560Sgshapiro if (db_key.size == strlen(VIT) + 1 && 109671345Sgshapiro strncmp((char *)db_key.data, VIT, 109771345Sgshapiro (int)db_key.size - 1) == 0) 109864562Sgshapiro continue; 109964562Sgshapiro 110064562Sgshapiro /* skip bogus values */ 110171345Sgshapiro if (db_value.size != sizeof t) 110264562Sgshapiro { 110390792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 110490792Sgshapiro "vacation: %.*s invalid time stamp\n", 110590792Sgshapiro (int) db_key.size, (char *) db_key.data); 110664562Sgshapiro continue; 110764562Sgshapiro } 110864562Sgshapiro 110971345Sgshapiro memcpy(&t, db_value.data, sizeof t); 111064562Sgshapiro 111171345Sgshapiro if (db_key.size > 40) 111271345Sgshapiro db_key.size = 40; 111364562Sgshapiro 111498121Sgshapiro if (t <= 0) 111598121Sgshapiro { 111698121Sgshapiro /* must be an exclude */ 111798121Sgshapiro timestamp = "(exclusion)\n"; 111898121Sgshapiro } 111998121Sgshapiro else 112098121Sgshapiro { 112198121Sgshapiro timestamp = ctime(&t); 112298121Sgshapiro } 112390792Sgshapiro sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%-40.*s %-10s", 112490792Sgshapiro (int) db_key.size, (char *) db_key.data, 112598121Sgshapiro timestamp); 112664562Sgshapiro 112764562Sgshapiro memset(&db_key, '\0', sizeof db_key); 112864562Sgshapiro memset(&db_value, '\0', sizeof db_value); 112964562Sgshapiro } 113064562Sgshapiro 113164562Sgshapiro if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) 113264562Sgshapiro { 113390792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 113490792Sgshapiro "vacation: get value at cursor: %s\n", 113590792Sgshapiro sm_errstring(result)); 113664562Sgshapiro if (cursor != NULL) 113764562Sgshapiro { 113864562Sgshapiro (void) cursor->smdbc_close(cursor); 113964562Sgshapiro cursor = NULL; 114064562Sgshapiro } 114164562Sgshapiro return; 114264562Sgshapiro } 114364562Sgshapiro (void) cursor->smdbc_close(cursor); 114464562Sgshapiro cursor = NULL; 114564562Sgshapiro} 114664562Sgshapiro 114764562Sgshapiro/* 114864562Sgshapiro** DEBUGLOG -- write message to standard error 114964562Sgshapiro** 115064562Sgshapiro** Append a message to the standard error for the convenience of 115164562Sgshapiro** end-users debugging without access to the syslog messages. 115264562Sgshapiro** 115364562Sgshapiro** Parameters: 115464562Sgshapiro** i -- syslog log level 115564562Sgshapiro** fmt -- string format 115664562Sgshapiro** 115764562Sgshapiro** Returns: 115864562Sgshapiro** nothing. 115964562Sgshapiro*/ 116064562Sgshapiro 116164562Sgshapiro/*VARARGS2*/ 116290792Sgshapirostatic SYSLOG_RET_T 116364562Sgshapiro#ifdef __STDC__ 116464562Sgshapirodebuglog(int i, const char *fmt, ...) 116564562Sgshapiro#else /* __STDC__ */ 116664562Sgshapirodebuglog(i, fmt, va_alist) 116764562Sgshapiro int i; 116864562Sgshapiro const char *fmt; 116964562Sgshapiro va_dcl 117064562Sgshapiro#endif /* __STDC__ */ 117164562Sgshapiro 117264562Sgshapiro{ 117390792Sgshapiro SM_VA_LOCAL_DECL 117464562Sgshapiro 117590792Sgshapiro SM_VA_START(ap, fmt); 117690792Sgshapiro sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap); 117790792Sgshapiro SM_VA_END(ap); 117890792Sgshapiro SYSLOG_RET; 117964562Sgshapiro} 1180