164562Sgshapiro/* 2203004Sgshapiro * Copyright (c) 1999-2002, 2009 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, 17203004Sgshapiro"@(#) Copyright (c) 1999-2002, 2009 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 23249729SgshapiroSM_IDSTR(id, "@(#)$Id: vacation.c,v 8.147 2013/03/12 15:24:56 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; 156203004Sgshapiro char *name = NULL; 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 } 302203004Sgshapiro name = strdup(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 { 317203004Sgshapiro name = strdup(*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 } 361203004Sgshapiro name = strdup(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 } 374203004Sgshapiro if (name == NULL) 375203004Sgshapiro { 376203004Sgshapiro msglog(LOG_ERR, 377203004Sgshapiro "vacation: can't allocate memory for username.\n"); 378203004Sgshapiro EXITM(EX_OSERR); 379203004Sgshapiro } 38064562Sgshapiro 38177349Sgshapiro if (dbfilename == NULL) 38277349Sgshapiro dbfilename = VDB; 38377349Sgshapiro if (msgfilename == NULL) 38477349Sgshapiro msgfilename = VMSG; 38577349Sgshapiro 38666494Sgshapiro sff = SFF_CREAT; 38766494Sgshapiro if (getegid() != getgid()) 38877349Sgshapiro { 38990792Sgshapiro /* Allow a set-group-ID vacation binary */ 39066494Sgshapiro RunAsGid = user_info.smdbu_group_id = getegid(); 39190792Sgshapiro sff |= SFF_OPENASROOT; 39277349Sgshapiro } 39394334Sgshapiro if (getuid() == 0) 39494334Sgshapiro { 39594334Sgshapiro /* Allow root to initialize user's vacation databases */ 39694334Sgshapiro sff |= SFF_OPENASROOT|SFF_ROOTOK; 39766494Sgshapiro 39894334Sgshapiro /* ... safely */ 39994334Sgshapiro sff |= SFF_NOSLINK|SFF_NOHLINK|SFF_REGONLY; 40094334Sgshapiro } 40194334Sgshapiro 40294334Sgshapiro 40364562Sgshapiro result = smdb_open_database(&Db, dbfilename, 40498121Sgshapiro O_CREAT|O_RDWR | (initdb ? O_TRUNC : 0), 40566494Sgshapiro S_IRUSR|S_IWUSR, sff, 40664562Sgshapiro SMDB_TYPE_DEFAULT, &user_info, NULL); 40764562Sgshapiro if (result != SMDBE_OK) 40864562Sgshapiro { 40964562Sgshapiro msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename, 41090792Sgshapiro sm_errstring(result)); 41166494Sgshapiro EXITM(EX_DATAERR); 41264562Sgshapiro } 41364562Sgshapiro 41498121Sgshapiro if (list) 41564562Sgshapiro { 41664562Sgshapiro listdb(); 41771345Sgshapiro (void) Db->smdb_close(Db); 41864562Sgshapiro exit(EX_OK); 41964562Sgshapiro } 42064562Sgshapiro 42164562Sgshapiro if (interval != INTERVAL_UNDEF) 42264562Sgshapiro setinterval(interval); 42364562Sgshapiro 42498121Sgshapiro if (initdb && !exclude) 42564562Sgshapiro { 42671345Sgshapiro (void) Db->smdb_close(Db); 42771345Sgshapiro exit(EX_OK); 42864562Sgshapiro } 42964562Sgshapiro 43064562Sgshapiro if (exclude) 43164562Sgshapiro { 43290792Sgshapiro xclude(smioin); 43371345Sgshapiro (void) Db->smdb_close(Db); 43466494Sgshapiro EXITM(EX_OK); 43564562Sgshapiro } 43664562Sgshapiro 43790792Sgshapiro if ((cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS))) == NULL) 43864562Sgshapiro { 43964562Sgshapiro msglog(LOG_NOTICE, 44064562Sgshapiro "vacation: can't allocate memory for username.\n"); 44171345Sgshapiro (void) Db->smdb_close(Db); 44266494Sgshapiro EXITM(EX_OSERR); 44364562Sgshapiro } 44464562Sgshapiro cur->name = name; 44564562Sgshapiro cur->next = Names; 44664562Sgshapiro Names = cur; 44764562Sgshapiro 44898121Sgshapiro result = readheaders(alwaysrespond); 44971345Sgshapiro if (result == EX_OK && !recent()) 45064562Sgshapiro { 45164562Sgshapiro time_t now; 45264562Sgshapiro 45364562Sgshapiro (void) time(&now); 45464562Sgshapiro setreply(From, now); 45571345Sgshapiro (void) Db->smdb_close(Db); 45690792Sgshapiro sendmessage(name, msgfilename, returnaddr); 45764562Sgshapiro } 45864562Sgshapiro else 45971345Sgshapiro (void) Db->smdb_close(Db); 46071345Sgshapiro if (result == EX_NOUSER) 46171345Sgshapiro result = EX_OK; 46271345Sgshapiro exit(result); 46364562Sgshapiro} 46464562Sgshapiro 46564562Sgshapiro/* 46666494Sgshapiro** EATMSG -- read stdin till EOF 46766494Sgshapiro** 46866494Sgshapiro** Parameters: 46966494Sgshapiro** none. 47066494Sgshapiro** 47166494Sgshapiro** Returns: 47266494Sgshapiro** nothing. 47366494Sgshapiro** 47466494Sgshapiro*/ 47577349Sgshapiro 47666494Sgshapirostatic void 47766494Sgshapiroeatmsg() 47866494Sgshapiro{ 47966494Sgshapiro /* 48066494Sgshapiro ** read the rest of the e-mail and ignore it to avoid problems 48166494Sgshapiro ** with EPIPE in sendmail 48266494Sgshapiro */ 48366494Sgshapiro while (getc(stdin) != EOF) 48466494Sgshapiro continue; 48566494Sgshapiro} 48666494Sgshapiro 48766494Sgshapiro/* 48864562Sgshapiro** READHEADERS -- read mail headers 48964562Sgshapiro** 49064562Sgshapiro** Parameters: 49198121Sgshapiro** alwaysrespond -- respond regardless of whether msg is to me 49264562Sgshapiro** 49364562Sgshapiro** Returns: 49471345Sgshapiro** a exit code: NOUSER if no reply, OK if reply, * if error 49564562Sgshapiro** 49666494Sgshapiro** Side Effects: 49766494Sgshapiro** may exit(). 49866494Sgshapiro** 49964562Sgshapiro*/ 50071345Sgshapiro 501168515Sgshapirostatic int 50298121Sgshapiroreadheaders(alwaysrespond) 50398121Sgshapiro bool alwaysrespond; 50464562Sgshapiro{ 50564562Sgshapiro bool tome, cont; 50664562Sgshapiro register char *p; 50764562Sgshapiro register ALIAS *cur; 50864562Sgshapiro char buf[MAXLINE]; 50964562Sgshapiro 51098121Sgshapiro cont = false; 51198121Sgshapiro tome = alwaysrespond; 512249729Sgshapiro while (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0 && 51390792Sgshapiro *buf != '\n') 51464562Sgshapiro { 51564562Sgshapiro switch(*buf) 51664562Sgshapiro { 51764562Sgshapiro case 'F': /* "From " */ 51890792Sgshapiro cont = false; 51964562Sgshapiro if (strncmp(buf, "From ", 5) == 0) 52064562Sgshapiro { 52190792Sgshapiro bool quoted = false; 52264562Sgshapiro 52364562Sgshapiro p = buf + 5; 52464562Sgshapiro while (*p != '\0') 52564562Sgshapiro { 52664562Sgshapiro /* escaped character */ 52764562Sgshapiro if (*p == '\\') 52864562Sgshapiro { 52964562Sgshapiro p++; 53064562Sgshapiro if (*p == '\0') 53164562Sgshapiro { 53264562Sgshapiro msglog(LOG_NOTICE, 53364562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 53466494Sgshapiro EXITIT(EX_DATAERR); 53564562Sgshapiro } 53664562Sgshapiro } 53764562Sgshapiro else if (*p == '"') 53864562Sgshapiro quoted = !quoted; 53964562Sgshapiro else if (*p == '\r' || *p == '\n') 54064562Sgshapiro break; 54164562Sgshapiro else if (*p == ' ' && !quoted) 54264562Sgshapiro break; 54364562Sgshapiro p++; 54464562Sgshapiro } 54564562Sgshapiro if (quoted) 54664562Sgshapiro { 54764562Sgshapiro msglog(LOG_NOTICE, 54864562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 54966494Sgshapiro EXITIT(EX_DATAERR); 55064562Sgshapiro } 55164562Sgshapiro *p = '\0'; 55264562Sgshapiro 55364562Sgshapiro /* ok since both strings have MAXLINE length */ 55464562Sgshapiro if (*From == '\0') 55590792Sgshapiro (void) sm_strlcpy(From, buf + 5, 55690792Sgshapiro sizeof From); 55764562Sgshapiro if ((p = strchr(buf + 5, '\n')) != NULL) 55864562Sgshapiro *p = '\0'; 55964562Sgshapiro if (junkmail(buf + 5)) 56071345Sgshapiro EXITIT(EX_NOUSER); 56164562Sgshapiro } 56264562Sgshapiro break; 56364562Sgshapiro 56464562Sgshapiro case 'P': /* "Precedence:" */ 56564562Sgshapiro case 'p': 56690792Sgshapiro cont = false; 56764562Sgshapiro if (strlen(buf) <= 10 || 56864562Sgshapiro strncasecmp(buf, "Precedence", 10) != 0 || 56964562Sgshapiro (buf[10] != ':' && buf[10] != ' ' && 57064562Sgshapiro buf[10] != '\t')) 57164562Sgshapiro break; 57264562Sgshapiro if ((p = strchr(buf, ':')) == NULL) 57364562Sgshapiro break; 57464562Sgshapiro while (*++p != '\0' && isascii(*p) && isspace(*p)); 57564562Sgshapiro if (*p == '\0') 57664562Sgshapiro break; 57764562Sgshapiro if (strncasecmp(p, "junk", 4) == 0 || 57864562Sgshapiro strncasecmp(p, "bulk", 4) == 0 || 57964562Sgshapiro strncasecmp(p, "list", 4) == 0) 58071345Sgshapiro EXITIT(EX_NOUSER); 58164562Sgshapiro break; 58264562Sgshapiro 58364562Sgshapiro case 'C': /* "Cc:" */ 58464562Sgshapiro case 'c': 58564562Sgshapiro if (strncasecmp(buf, "Cc:", 3) != 0) 58664562Sgshapiro break; 58790792Sgshapiro cont = true; 58864562Sgshapiro goto findme; 58964562Sgshapiro 59064562Sgshapiro case 'T': /* "To:" */ 59164562Sgshapiro case 't': 59264562Sgshapiro if (strncasecmp(buf, "To:", 3) != 0) 59364562Sgshapiro break; 59490792Sgshapiro cont = true; 59564562Sgshapiro goto findme; 59664562Sgshapiro 59764562Sgshapiro default: 59864562Sgshapiro if (!isascii(*buf) || !isspace(*buf) || !cont || tome) 59964562Sgshapiro { 60090792Sgshapiro cont = false; 60164562Sgshapiro break; 60264562Sgshapiro } 60364562Sgshapirofindme: 60464562Sgshapiro for (cur = Names; 60564562Sgshapiro !tome && cur != NULL; 60664562Sgshapiro cur = cur->next) 60764562Sgshapiro tome = nsearch(cur->name, buf); 60864562Sgshapiro } 60964562Sgshapiro } 61064562Sgshapiro if (!tome) 61171345Sgshapiro EXITIT(EX_NOUSER); 61264562Sgshapiro if (*From == '\0') 61364562Sgshapiro { 61464562Sgshapiro msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n"); 61566494Sgshapiro EXITIT(EX_DATAERR); 61664562Sgshapiro } 61771345Sgshapiro EXITIT(EX_OK); 61864562Sgshapiro} 61964562Sgshapiro 62064562Sgshapiro/* 62164562Sgshapiro** NSEARCH -- 62264562Sgshapiro** do a nice, slow, search of a string for a substring. 62364562Sgshapiro** 62464562Sgshapiro** Parameters: 62564562Sgshapiro** name -- name to search. 62664562Sgshapiro** str -- string in which to search. 62764562Sgshapiro** 62864562Sgshapiro** Returns: 62964562Sgshapiro** is name a substring of str? 63064562Sgshapiro** 63164562Sgshapiro*/ 63277349Sgshapiro 633168515Sgshapirostatic bool 63464562Sgshapironsearch(name, str) 63564562Sgshapiro register char *name, *str; 63664562Sgshapiro{ 63764562Sgshapiro register size_t len; 63864562Sgshapiro register char *s; 63964562Sgshapiro 64064562Sgshapiro len = strlen(name); 64164562Sgshapiro 64264562Sgshapiro for (s = str; *s != '\0'; ++s) 64364562Sgshapiro { 64464562Sgshapiro /* 64564562Sgshapiro ** Check to make sure that the string matches and 64664562Sgshapiro ** the previous character is not an alphanumeric and 64764562Sgshapiro ** the next character after the match is not an alphanumeric. 64864562Sgshapiro ** 64964562Sgshapiro ** This prevents matching "eric" to "derick" while still 65064562Sgshapiro ** matching "eric" to "<eric+detail>". 65164562Sgshapiro */ 65264562Sgshapiro 65364562Sgshapiro if (tolower(*s) == tolower(*name) && 65464562Sgshapiro strncasecmp(name, s, len) == 0 && 65564562Sgshapiro (s == str || !isascii(*(s - 1)) || !isalnum(*(s - 1))) && 65664562Sgshapiro (!isascii(*(s + len)) || !isalnum(*(s + len)))) 65790792Sgshapiro return true; 65864562Sgshapiro } 65990792Sgshapiro return false; 66064562Sgshapiro} 66164562Sgshapiro 66264562Sgshapiro/* 66364562Sgshapiro** JUNKMAIL -- 66464562Sgshapiro** read the header and return if automagic/junk/bulk/list mail 66564562Sgshapiro** 66664562Sgshapiro** Parameters: 66764562Sgshapiro** from -- sender address. 66864562Sgshapiro** 66964562Sgshapiro** Returns: 67064562Sgshapiro** is this some automated/junk/bulk/list mail? 67164562Sgshapiro** 67264562Sgshapiro*/ 67371345Sgshapiro 67471345Sgshapirostruct ignore 67571345Sgshapiro{ 67671345Sgshapiro char *name; 67771345Sgshapiro size_t len; 67871345Sgshapiro}; 67971345Sgshapiro 68071345Sgshapirotypedef struct ignore IGNORE_T; 68171345Sgshapiro 68271345Sgshapiro#define MAX_USER_LEN 256 /* maximum length of local part (sender) */ 68371345Sgshapiro 68471345Sgshapiro/* delimiters for the local part of an address */ 68571345Sgshapiro#define isdelim(c) ((c) == '%' || (c) == '@' || (c) == '+') 68671345Sgshapiro 687168515Sgshapirostatic bool 68864562Sgshapirojunkmail(from) 68964562Sgshapiro char *from; 69064562Sgshapiro{ 69171345Sgshapiro bool quot; 69271345Sgshapiro char *e; 69371345Sgshapiro size_t len; 69471345Sgshapiro IGNORE_T *cur; 69571345Sgshapiro char sender[MAX_USER_LEN]; 69671345Sgshapiro static IGNORE_T ignore[] = 69764562Sgshapiro { 69864562Sgshapiro { "postmaster", 10 }, 69964562Sgshapiro { "uucp", 4 }, 70064562Sgshapiro { "mailer-daemon", 13 }, 70164562Sgshapiro { "mailer", 6 }, 70271345Sgshapiro { NULL, 0 } 70371345Sgshapiro }; 70471345Sgshapiro 70571345Sgshapiro static IGNORE_T ignorepost[] = 70671345Sgshapiro { 70771345Sgshapiro { "-request", 8 }, 70864562Sgshapiro { "-relay", 6 }, 70971345Sgshapiro { "-owner", 6 }, 71064562Sgshapiro { NULL, 0 } 71164562Sgshapiro }; 71264562Sgshapiro 71371345Sgshapiro static IGNORE_T ignorepre[] = 71471345Sgshapiro { 71571345Sgshapiro { "owner-", 6 }, 71671345Sgshapiro { NULL, 0 } 71771345Sgshapiro }; 71871345Sgshapiro 71964562Sgshapiro /* 72071345Sgshapiro ** This is mildly amusing, and I'm not positive it's right; trying 72171345Sgshapiro ** to find the "real" name of the sender, assuming that addresses 72271345Sgshapiro ** will be some variant of: 72371345Sgshapiro ** 72471345Sgshapiro ** From site!site!SENDER%site.domain%site.domain@site.domain 72571345Sgshapiro */ 72671345Sgshapiro 72790792Sgshapiro quot = false; 72871345Sgshapiro e = from; 72971345Sgshapiro len = 0; 73071345Sgshapiro while (*e != '\0' && (quot || !isdelim(*e))) 73164562Sgshapiro { 73271345Sgshapiro if (*e == '"') 73371345Sgshapiro { 73471345Sgshapiro quot = !quot; 73571345Sgshapiro ++e; 73671345Sgshapiro continue; 73771345Sgshapiro } 73871345Sgshapiro if (*e == '\\') 73971345Sgshapiro { 74071345Sgshapiro if (*(++e) == '\0') 74171345Sgshapiro { 74271345Sgshapiro /* '\\' at end of string? */ 74371345Sgshapiro break; 74471345Sgshapiro } 74571345Sgshapiro if (len < MAX_USER_LEN) 74671345Sgshapiro sender[len++] = *e; 74771345Sgshapiro ++e; 74871345Sgshapiro continue; 74971345Sgshapiro } 75071345Sgshapiro if (*e == '!' && !quot) 75171345Sgshapiro { 75271345Sgshapiro len = 0; 75371345Sgshapiro sender[len] = '\0'; 75471345Sgshapiro } 75564562Sgshapiro else 75671345Sgshapiro if (len < MAX_USER_LEN) 75771345Sgshapiro sender[len++] = *e; 75871345Sgshapiro ++e; 75964562Sgshapiro } 76071345Sgshapiro if (len < MAX_USER_LEN) 76171345Sgshapiro sender[len] = '\0'; 76271345Sgshapiro else 76371345Sgshapiro sender[MAX_USER_LEN - 1] = '\0'; 76471345Sgshapiro 76571345Sgshapiro if (len <= 0) 76690792Sgshapiro return false; 76771345Sgshapiro#if 0 76871345Sgshapiro if (quot) 76990792Sgshapiro return false; /* syntax error... */ 77071345Sgshapiro#endif /* 0 */ 77171345Sgshapiro 77271345Sgshapiro /* test prefixes */ 77371345Sgshapiro for (cur = ignorepre; cur->name != NULL; ++cur) 77471345Sgshapiro { 77571345Sgshapiro if (len >= cur->len && 77671345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 77790792Sgshapiro return true; 77871345Sgshapiro } 77971345Sgshapiro 78071345Sgshapiro /* 78171345Sgshapiro ** If the name is truncated, don't test the rest. 78271345Sgshapiro ** We could extract the "tail" of the sender address and 78371345Sgshapiro ** compare it it ignorepost, however, it seems not worth 78471345Sgshapiro ** the effort. 78571345Sgshapiro ** The address surely can't match any entry in ignore[] 78671345Sgshapiro ** (as long as all of them are shorter than MAX_USER_LEN). 78771345Sgshapiro */ 78871345Sgshapiro 78971345Sgshapiro if (len > MAX_USER_LEN) 79090792Sgshapiro return false; 79171345Sgshapiro 79271345Sgshapiro /* test full local parts */ 79364562Sgshapiro for (cur = ignore; cur->name != NULL; ++cur) 79464562Sgshapiro { 79571345Sgshapiro if (len == cur->len && 79671345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 79790792Sgshapiro return true; 79871345Sgshapiro } 79971345Sgshapiro 80071345Sgshapiro /* test postfixes */ 80171345Sgshapiro for (cur = ignorepost; cur->name != NULL; ++cur) 80271345Sgshapiro { 80364562Sgshapiro if (len >= cur->len && 80471345Sgshapiro strncasecmp(cur->name, e - cur->len - 1, 80571345Sgshapiro cur->len) == 0) 80690792Sgshapiro return true; 80764562Sgshapiro } 80890792Sgshapiro return false; 80964562Sgshapiro} 81064562Sgshapiro 81164562Sgshapiro#define VIT "__VACATION__INTERVAL__TIMER__" 81264562Sgshapiro 81364562Sgshapiro/* 81464562Sgshapiro** RECENT -- 81564562Sgshapiro** find out if user has gotten a vacation message recently. 81664562Sgshapiro** 81764562Sgshapiro** Parameters: 81864562Sgshapiro** none. 81964562Sgshapiro** 82064562Sgshapiro** Returns: 82190792Sgshapiro** true iff user has gotten a vacation message recently. 82264562Sgshapiro** 82364562Sgshapiro*/ 82477349Sgshapiro 825168515Sgshapirostatic bool 82664562Sgshapirorecent() 82764562Sgshapiro{ 82864562Sgshapiro SMDB_DBENT key, data; 82964562Sgshapiro time_t then, next; 83090792Sgshapiro bool trydomain = false; 83164562Sgshapiro int st; 83264562Sgshapiro char *domain; 83364562Sgshapiro 83464562Sgshapiro memset(&key, '\0', sizeof key); 83564562Sgshapiro memset(&data, '\0', sizeof data); 83664562Sgshapiro 83764562Sgshapiro /* get interval time */ 83871345Sgshapiro key.data = VIT; 83971345Sgshapiro key.size = sizeof(VIT); 84064562Sgshapiro 84164562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 84264562Sgshapiro if (st != SMDBE_OK) 84364562Sgshapiro next = SECSPERDAY * DAYSPERWEEK; 84464562Sgshapiro else 84571345Sgshapiro memmove(&next, data.data, sizeof(next)); 84664562Sgshapiro 84764562Sgshapiro memset(&data, '\0', sizeof data); 84864562Sgshapiro 84964562Sgshapiro /* get record for this address */ 85071345Sgshapiro key.data = From; 85171345Sgshapiro key.size = strlen(From); 85264562Sgshapiro 85364562Sgshapiro do 85464562Sgshapiro { 85564562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 85664562Sgshapiro if (st == SMDBE_OK) 85764562Sgshapiro { 85871345Sgshapiro memmove(&then, data.data, sizeof(then)); 85964562Sgshapiro if (next == ONLY_ONCE || then == ONLY_ONCE || 86064562Sgshapiro then + next > time(NULL)) 86190792Sgshapiro return true; 86264562Sgshapiro } 86364562Sgshapiro if ((trydomain = !trydomain) && 86464562Sgshapiro (domain = strchr(From, '@')) != NULL) 86564562Sgshapiro { 86671345Sgshapiro key.data = domain; 86771345Sgshapiro key.size = strlen(domain); 86864562Sgshapiro } 86964562Sgshapiro } while (trydomain); 87090792Sgshapiro return false; 87164562Sgshapiro} 87264562Sgshapiro 87364562Sgshapiro/* 87464562Sgshapiro** SETINTERVAL -- 87564562Sgshapiro** store the reply interval 87664562Sgshapiro** 87764562Sgshapiro** Parameters: 87864562Sgshapiro** interval -- time interval for replies. 87964562Sgshapiro** 88064562Sgshapiro** Returns: 88164562Sgshapiro** nothing. 88264562Sgshapiro** 88364562Sgshapiro** Side Effects: 88464562Sgshapiro** stores the reply interval in database. 88564562Sgshapiro*/ 88677349Sgshapiro 887168515Sgshapirostatic void 88864562Sgshapirosetinterval(interval) 88964562Sgshapiro time_t interval; 89064562Sgshapiro{ 89164562Sgshapiro SMDB_DBENT key, data; 89264562Sgshapiro 89364562Sgshapiro memset(&key, '\0', sizeof key); 89464562Sgshapiro memset(&data, '\0', sizeof data); 89564562Sgshapiro 89671345Sgshapiro key.data = VIT; 89771345Sgshapiro key.size = sizeof(VIT); 89871345Sgshapiro data.data = (char*) &interval; 89971345Sgshapiro data.size = sizeof(interval); 90071345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 90164562Sgshapiro} 90264562Sgshapiro 90364562Sgshapiro/* 90464562Sgshapiro** SETREPLY -- 90564562Sgshapiro** store that this user knows about the vacation. 90664562Sgshapiro** 90764562Sgshapiro** Parameters: 90864562Sgshapiro** from -- sender address. 90964562Sgshapiro** when -- last reply time. 91064562Sgshapiro** 91164562Sgshapiro** Returns: 91264562Sgshapiro** nothing. 91364562Sgshapiro** 91464562Sgshapiro** Side Effects: 91564562Sgshapiro** stores user/time in database. 91664562Sgshapiro*/ 91777349Sgshapiro 918168515Sgshapirostatic void 91964562Sgshapirosetreply(from, when) 92064562Sgshapiro char *from; 92164562Sgshapiro time_t when; 92264562Sgshapiro{ 92364562Sgshapiro SMDB_DBENT key, data; 92464562Sgshapiro 92564562Sgshapiro memset(&key, '\0', sizeof key); 92664562Sgshapiro memset(&data, '\0', sizeof data); 92764562Sgshapiro 92871345Sgshapiro key.data = from; 92971345Sgshapiro key.size = strlen(from); 93071345Sgshapiro data.data = (char*) &when; 93171345Sgshapiro data.size = sizeof(when); 93271345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 93364562Sgshapiro} 93464562Sgshapiro 93564562Sgshapiro/* 93664562Sgshapiro** XCLUDE -- 93764562Sgshapiro** add users to vacation db so they don't get a reply. 93864562Sgshapiro** 93964562Sgshapiro** Parameters: 94064562Sgshapiro** f -- file pointer with list of address to exclude 94164562Sgshapiro** 94264562Sgshapiro** Returns: 94364562Sgshapiro** nothing. 94464562Sgshapiro** 94564562Sgshapiro** Side Effects: 94664562Sgshapiro** stores users in database. 94764562Sgshapiro*/ 94877349Sgshapiro 949168515Sgshapirostatic void 95064562Sgshapiroxclude(f) 95190792Sgshapiro SM_FILE_T *f; 95264562Sgshapiro{ 95364562Sgshapiro char buf[MAXLINE], *p; 95464562Sgshapiro 95564562Sgshapiro if (f == NULL) 95664562Sgshapiro return; 957249729Sgshapiro while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf) >= 0) 95864562Sgshapiro { 95964562Sgshapiro if ((p = strchr(buf, '\n')) != NULL) 96064562Sgshapiro *p = '\0'; 96164562Sgshapiro setreply(buf, ONLY_ONCE); 96264562Sgshapiro } 96364562Sgshapiro} 96464562Sgshapiro 96564562Sgshapiro/* 96664562Sgshapiro** SENDMESSAGE -- 96764562Sgshapiro** exec sendmail to send the vacation file to sender 96864562Sgshapiro** 96964562Sgshapiro** Parameters: 97064562Sgshapiro** myname -- user name. 97164562Sgshapiro** msgfn -- name of file with vacation message. 97290792Sgshapiro** sender -- use as sender address 97364562Sgshapiro** 97464562Sgshapiro** Returns: 97564562Sgshapiro** nothing. 97664562Sgshapiro** 97764562Sgshapiro** Side Effects: 97864562Sgshapiro** sends vacation reply. 97964562Sgshapiro*/ 98077349Sgshapiro 981168515Sgshapirostatic void 98290792Sgshapirosendmessage(myname, msgfn, sender) 98364562Sgshapiro char *myname; 98464562Sgshapiro char *msgfn; 98590792Sgshapiro char *sender; 98664562Sgshapiro{ 98790792Sgshapiro SM_FILE_T *mfp, *sfp; 98864562Sgshapiro int i; 98964562Sgshapiro int pvect[2]; 99077349Sgshapiro char *pv[8]; 99164562Sgshapiro char buf[MAXLINE]; 99264562Sgshapiro 99390792Sgshapiro mfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, msgfn, SM_IO_RDONLY, NULL); 99464562Sgshapiro if (mfp == NULL) 99564562Sgshapiro { 99664562Sgshapiro if (msgfn[0] == '/') 99764562Sgshapiro msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn); 99864562Sgshapiro else 99964562Sgshapiro msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", 100064562Sgshapiro myname, msgfn); 100164562Sgshapiro exit(EX_NOINPUT); 100264562Sgshapiro } 100364562Sgshapiro if (pipe(pvect) < 0) 100464562Sgshapiro { 100590792Sgshapiro msglog(LOG_ERR, "vacation: pipe: %s", sm_errstring(errno)); 100664562Sgshapiro exit(EX_OSERR); 100764562Sgshapiro } 100877349Sgshapiro pv[0] = "sendmail"; 100977349Sgshapiro pv[1] = "-oi"; 101077349Sgshapiro pv[2] = "-f"; 101190792Sgshapiro if (sender != NULL) 101290792Sgshapiro pv[3] = sender; 101377349Sgshapiro else 101477349Sgshapiro pv[3] = myname; 101577349Sgshapiro pv[4] = "--"; 101677349Sgshapiro pv[5] = From; 101777349Sgshapiro pv[6] = NULL; 101864562Sgshapiro i = fork(); 101964562Sgshapiro if (i < 0) 102064562Sgshapiro { 102190792Sgshapiro msglog(LOG_ERR, "vacation: fork: %s", sm_errstring(errno)); 102264562Sgshapiro exit(EX_OSERR); 102364562Sgshapiro } 102464562Sgshapiro if (i == 0) 102564562Sgshapiro { 102664562Sgshapiro (void) dup2(pvect[0], 0); 102764562Sgshapiro (void) close(pvect[0]); 102864562Sgshapiro (void) close(pvect[1]); 102990792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 103077349Sgshapiro (void) execv(_PATH_SENDMAIL, pv); 103164562Sgshapiro msglog(LOG_ERR, "vacation: can't exec %s: %s", 103290792Sgshapiro _PATH_SENDMAIL, sm_errstring(errno)); 103364562Sgshapiro exit(EX_UNAVAILABLE); 103464562Sgshapiro } 103564562Sgshapiro /* check return status of the following calls? XXX */ 103664562Sgshapiro (void) close(pvect[0]); 103790792Sgshapiro if ((sfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 103890792Sgshapiro (void *) &(pvect[1]), 103990792Sgshapiro SM_IO_WRONLY, NULL)) != NULL) 104064562Sgshapiro { 1041203004Sgshapiro#if _FFR_VAC_WAIT4SM 1042203004Sgshapiro# ifdef WAITUNION 1043203004Sgshapiro union wait st; 1044203004Sgshapiro# else /* WAITUNION */ 1045203004Sgshapiro auto int st; 1046203004Sgshapiro# endif /* WAITUNION */ 1047203004Sgshapiro#endif /* _FFR_VAC_WAIT4SM */ 1048203004Sgshapiro 104990792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, "To: %s\n", From); 105090792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, 105190792Sgshapiro "Auto-Submitted: auto-replied\n"); 1052249729Sgshapiro while (sm_io_fgets(mfp, SM_TIME_DEFAULT, buf, sizeof buf) >= 0) 105390792Sgshapiro (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf); 105490792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 105590792Sgshapiro (void) sm_io_close(sfp, SM_TIME_DEFAULT); 1056203004Sgshapiro#if _FFR_VAC_WAIT4SM 1057203004Sgshapiro (void) wait(&st); 1058203004Sgshapiro#endif /* _FFR_VAC_WAIT4SM */ 105964562Sgshapiro } 106064562Sgshapiro else 106164562Sgshapiro { 106290792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 106364562Sgshapiro msglog(LOG_ERR, "vacation: can't open pipe to sendmail"); 106464562Sgshapiro exit(EX_UNAVAILABLE); 106564562Sgshapiro } 106664562Sgshapiro} 106764562Sgshapiro 1068168515Sgshapirostatic void 106964562Sgshapirousage() 107064562Sgshapiro{ 107177349Sgshapiro msglog(LOG_NOTICE, 1072132943Sgshapiro "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", 1073132943Sgshapiro getuid()); 107464562Sgshapiro exit(EX_USAGE); 107564562Sgshapiro} 107664562Sgshapiro 107764562Sgshapiro/* 107864562Sgshapiro** LISTDB -- list the contents of the vacation database 107964562Sgshapiro** 108064562Sgshapiro** Parameters: 108164562Sgshapiro** none. 108264562Sgshapiro** 108364562Sgshapiro** Returns: 108464562Sgshapiro** nothing. 108564562Sgshapiro*/ 108664562Sgshapiro 108764562Sgshapirostatic void 108864562Sgshapirolistdb() 108964562Sgshapiro{ 109064562Sgshapiro int result; 109164562Sgshapiro time_t t; 109264562Sgshapiro SMDB_CURSOR *cursor = NULL; 109364562Sgshapiro SMDB_DBENT db_key, db_value; 109464562Sgshapiro 109564562Sgshapiro memset(&db_key, '\0', sizeof db_key); 109664562Sgshapiro memset(&db_value, '\0', sizeof db_value); 109764562Sgshapiro 109864562Sgshapiro result = Db->smdb_cursor(Db, &cursor, 0); 109964562Sgshapiro if (result != SMDBE_OK) 110064562Sgshapiro { 110190792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 110290792Sgshapiro "vacation: set cursor: %s\n", 110390792Sgshapiro sm_errstring(result)); 110464562Sgshapiro return; 110564562Sgshapiro } 110664562Sgshapiro 110764562Sgshapiro while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, 110864562Sgshapiro SMDB_CURSOR_GET_NEXT)) == SMDBE_OK) 110964562Sgshapiro { 111098121Sgshapiro char *timestamp; 111198121Sgshapiro 111264562Sgshapiro /* skip magic VIT entry */ 1113110560Sgshapiro if (db_key.size == strlen(VIT) + 1 && 111471345Sgshapiro strncmp((char *)db_key.data, VIT, 111571345Sgshapiro (int)db_key.size - 1) == 0) 111664562Sgshapiro continue; 111764562Sgshapiro 111864562Sgshapiro /* skip bogus values */ 111971345Sgshapiro if (db_value.size != sizeof t) 112064562Sgshapiro { 112190792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 112290792Sgshapiro "vacation: %.*s invalid time stamp\n", 112390792Sgshapiro (int) db_key.size, (char *) db_key.data); 112464562Sgshapiro continue; 112564562Sgshapiro } 112664562Sgshapiro 112771345Sgshapiro memcpy(&t, db_value.data, sizeof t); 112864562Sgshapiro 112971345Sgshapiro if (db_key.size > 40) 113071345Sgshapiro db_key.size = 40; 113164562Sgshapiro 113298121Sgshapiro if (t <= 0) 113398121Sgshapiro { 113498121Sgshapiro /* must be an exclude */ 113598121Sgshapiro timestamp = "(exclusion)\n"; 113698121Sgshapiro } 113798121Sgshapiro else 113898121Sgshapiro { 113998121Sgshapiro timestamp = ctime(&t); 114098121Sgshapiro } 114190792Sgshapiro sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%-40.*s %-10s", 114290792Sgshapiro (int) db_key.size, (char *) db_key.data, 114398121Sgshapiro timestamp); 114464562Sgshapiro 114564562Sgshapiro memset(&db_key, '\0', sizeof db_key); 114664562Sgshapiro memset(&db_value, '\0', sizeof db_value); 114764562Sgshapiro } 114864562Sgshapiro 114964562Sgshapiro if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) 115064562Sgshapiro { 115190792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 115290792Sgshapiro "vacation: get value at cursor: %s\n", 115390792Sgshapiro sm_errstring(result)); 115464562Sgshapiro if (cursor != NULL) 115564562Sgshapiro { 115664562Sgshapiro (void) cursor->smdbc_close(cursor); 115764562Sgshapiro cursor = NULL; 115864562Sgshapiro } 115964562Sgshapiro return; 116064562Sgshapiro } 116164562Sgshapiro (void) cursor->smdbc_close(cursor); 116264562Sgshapiro cursor = NULL; 116364562Sgshapiro} 116464562Sgshapiro 116564562Sgshapiro/* 116664562Sgshapiro** DEBUGLOG -- write message to standard error 116764562Sgshapiro** 116864562Sgshapiro** Append a message to the standard error for the convenience of 116964562Sgshapiro** end-users debugging without access to the syslog messages. 117064562Sgshapiro** 117164562Sgshapiro** Parameters: 117264562Sgshapiro** i -- syslog log level 117364562Sgshapiro** fmt -- string format 117464562Sgshapiro** 117564562Sgshapiro** Returns: 117664562Sgshapiro** nothing. 117764562Sgshapiro*/ 117864562Sgshapiro 117964562Sgshapiro/*VARARGS2*/ 118090792Sgshapirostatic SYSLOG_RET_T 118164562Sgshapiro#ifdef __STDC__ 118264562Sgshapirodebuglog(int i, const char *fmt, ...) 118364562Sgshapiro#else /* __STDC__ */ 118464562Sgshapirodebuglog(i, fmt, va_alist) 118564562Sgshapiro int i; 118664562Sgshapiro const char *fmt; 118764562Sgshapiro va_dcl 118864562Sgshapiro#endif /* __STDC__ */ 118964562Sgshapiro 119064562Sgshapiro{ 119190792Sgshapiro SM_VA_LOCAL_DECL 119264562Sgshapiro 119390792Sgshapiro SM_VA_START(ap, fmt); 119490792Sgshapiro sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap); 119590792Sgshapiro SM_VA_END(ap); 119690792Sgshapiro SYSLOG_RET; 119764562Sgshapiro} 1198