vacation.c revision 132943
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 23132943SgshapiroSM_IDSTR(id, "@(#)$Id: vacation.c,v 8.141 2002/11/01 16:49:40 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]; 8164562Sgshapiro 8290792Sgshapiro#if defined(__hpux) || defined(__osf__) 8390792Sgshapiro# ifndef SM_CONF_SYSLOG_INT 8490792Sgshapiro# define SM_CONF_SYSLOG_INT 1 8590792Sgshapiro# endif /* SM_CONF_SYSLOG_INT */ 8690792Sgshapiro#endif /* defined(__hpux) || defined(__osf__) */ 8764562Sgshapiro 8890792Sgshapiro#if SM_CONF_SYSLOG_INT 8990792Sgshapiro# define SYSLOG_RET_T int 9090792Sgshapiro# define SYSLOG_RET return 0 9190792Sgshapiro#else /* SM_CONF_SYSLOG_INT */ 9290792Sgshapiro# define SYSLOG_RET_T void 9390792Sgshapiro# define SYSLOG_RET 9490792Sgshapiro#endif /* SM_CONF_SYSLOG_INT */ 9590792Sgshapiro 9690792Sgshapirotypedef SYSLOG_RET_T SYSLOG_T __P((int, const char *, ...)); 9790792SgshapiroSYSLOG_T *msglog = syslog; 9890792Sgshapirostatic SYSLOG_RET_T debuglog __P((int, const char *, ...)); 9966494Sgshapirostatic void eatmsg __P((void)); 10090792Sgshapirostatic void listdb __P((void)); 10166494Sgshapiro 10266494Sgshapiro/* exit after reading input */ 10390792Sgshapiro#define EXITIT(excode) \ 10490792Sgshapiro{ \ 10590792Sgshapiro eatmsg(); \ 10690792Sgshapiro return excode; \ 10790792Sgshapiro} 10877349Sgshapiro 10990792Sgshapiro#define EXITM(excode) \ 11090792Sgshapiro{ \ 11198121Sgshapiro if (!initdb && !list) \ 11290792Sgshapiro eatmsg(); \ 11390792Sgshapiro exit(excode); \ 11490792Sgshapiro} 11590792Sgshapiro 11664562Sgshapiroint 11764562Sgshapiromain(argc, argv) 11864562Sgshapiro int argc; 11964562Sgshapiro char **argv; 12064562Sgshapiro{ 12198121Sgshapiro bool alwaysrespond = false; 12298121Sgshapiro bool initdb, exclude; 12390792Sgshapiro bool runasuser = false; 12498121Sgshapiro bool list = false; 12564562Sgshapiro int mfail = 0, ufail = 0; 12664562Sgshapiro int ch; 12764562Sgshapiro int result; 12866494Sgshapiro long sff; 12964562Sgshapiro time_t interval; 13064562Sgshapiro struct passwd *pw; 13164562Sgshapiro ALIAS *cur; 13277349Sgshapiro char *dbfilename = NULL; 13377349Sgshapiro char *msgfilename = NULL; 13490792Sgshapiro char *cfpath = NULL; 13564562Sgshapiro char *name; 13690792Sgshapiro char *returnaddr = NULL; 13764562Sgshapiro SMDB_USER_INFO user_info; 13864562Sgshapiro static char rnamebuf[MAXNAME]; 13964562Sgshapiro extern int optind, opterr; 14064562Sgshapiro extern char *optarg; 14164562Sgshapiro extern void usage __P((void)); 14264562Sgshapiro extern void setinterval __P((time_t)); 14398121Sgshapiro extern int readheaders __P((bool)); 14464562Sgshapiro extern bool recent __P((void)); 14564562Sgshapiro extern void setreply __P((char *, time_t)); 14690792Sgshapiro extern void sendmessage __P((char *, char *, char *)); 14790792Sgshapiro extern void xclude __P((SM_FILE_T *)); 14864562Sgshapiro 14964562Sgshapiro /* Vars needed to link with smutil */ 15064562Sgshapiro clrbitmap(DontBlameSendmail); 15164562Sgshapiro RunAsUid = RealUid = getuid(); 15264562Sgshapiro RunAsGid = RealGid = getgid(); 15364562Sgshapiro pw = getpwuid(RealUid); 15464562Sgshapiro if (pw != NULL) 15564562Sgshapiro { 15664562Sgshapiro if (strlen(pw->pw_name) > MAXNAME - 1) 15764562Sgshapiro pw->pw_name[MAXNAME] = '\0'; 15890792Sgshapiro sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); 15964562Sgshapiro } 16064562Sgshapiro else 16190792Sgshapiro sm_snprintf(rnamebuf, sizeof rnamebuf, 16290792Sgshapiro "Unknown UID %d", (int) RealUid); 16364562Sgshapiro RunAsUserName = RealUserName = rnamebuf; 16464562Sgshapiro 16577349Sgshapiro# ifdef LOG_MAIL 16664562Sgshapiro openlog("vacation", LOG_PID, LOG_MAIL); 16777349Sgshapiro# else /* LOG_MAIL */ 16864562Sgshapiro openlog("vacation", LOG_PID); 16977349Sgshapiro# endif /* LOG_MAIL */ 17064562Sgshapiro 17164562Sgshapiro opterr = 0; 17298121Sgshapiro initdb = false; 17390792Sgshapiro exclude = false; 17464562Sgshapiro interval = INTERVAL_UNDEF; 17564562Sgshapiro *From = '\0'; 17664562Sgshapiro 17764562Sgshapiro 17898121Sgshapiro#define OPTIONS "a:C:df:Iijlm:R:r:s:t:Uxz" 17990792Sgshapiro 18064562Sgshapiro while (mfail == 0 && ufail == 0 && 18164562Sgshapiro (ch = getopt(argc, argv, OPTIONS)) != -1) 18264562Sgshapiro { 18364562Sgshapiro switch((char)ch) 18464562Sgshapiro { 18564562Sgshapiro case 'a': /* alias */ 18690792Sgshapiro cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS)); 18764562Sgshapiro if (cur == NULL) 18864562Sgshapiro { 18964562Sgshapiro mfail++; 19064562Sgshapiro break; 19164562Sgshapiro } 19264562Sgshapiro cur->name = optarg; 19364562Sgshapiro cur->next = Names; 19464562Sgshapiro Names = cur; 19564562Sgshapiro break; 19664562Sgshapiro 19790792Sgshapiro case 'C': 19890792Sgshapiro cfpath = optarg; 19990792Sgshapiro break; 20090792Sgshapiro 20177349Sgshapiro case 'd': /* debug mode */ 20290792Sgshapiro msglog = debuglog; 20364562Sgshapiro break; 20464562Sgshapiro 20564562Sgshapiro case 'f': /* alternate database */ 20664562Sgshapiro dbfilename = optarg; 20764562Sgshapiro break; 20864562Sgshapiro 20964562Sgshapiro case 'I': /* backward compatible */ 21064562Sgshapiro case 'i': /* init the database */ 21198121Sgshapiro initdb = true; 21264562Sgshapiro break; 21364562Sgshapiro 21498121Sgshapiro case 'j': 21598121Sgshapiro alwaysrespond = true; 21698121Sgshapiro break; 21798121Sgshapiro 21864562Sgshapiro case 'l': 21998121Sgshapiro list = true; /* list the database */ 22064562Sgshapiro break; 22164562Sgshapiro 22264562Sgshapiro case 'm': /* alternate message file */ 22364562Sgshapiro msgfilename = optarg; 22464562Sgshapiro break; 22564562Sgshapiro 22690792Sgshapiro case 'R': 22790792Sgshapiro returnaddr = optarg; 22890792Sgshapiro break; 22990792Sgshapiro 23064562Sgshapiro case 'r': 23164562Sgshapiro if (isascii(*optarg) && isdigit(*optarg)) 23264562Sgshapiro { 23364562Sgshapiro interval = atol(optarg) * SECSPERDAY; 23464562Sgshapiro if (interval < 0) 23564562Sgshapiro ufail++; 23664562Sgshapiro } 23764562Sgshapiro else 23864562Sgshapiro interval = ONLY_ONCE; 23964562Sgshapiro break; 24064562Sgshapiro 24164562Sgshapiro case 's': /* alternate sender name */ 24290792Sgshapiro (void) sm_strlcpy(From, optarg, sizeof From); 24364562Sgshapiro break; 24464562Sgshapiro 24564562Sgshapiro case 't': /* SunOS: -t1d (default expire) */ 24664562Sgshapiro break; 24764562Sgshapiro 24877349Sgshapiro case 'U': /* run as single user mode */ 24990792Sgshapiro runasuser = true; 25077349Sgshapiro break; 25177349Sgshapiro 25264562Sgshapiro case 'x': 25390792Sgshapiro exclude = true; 25464562Sgshapiro break; 25564562Sgshapiro 25664562Sgshapiro case 'z': 25790792Sgshapiro returnaddr = "<>"; 25864562Sgshapiro break; 25964562Sgshapiro 26064562Sgshapiro case '?': 26164562Sgshapiro default: 26264562Sgshapiro ufail++; 26364562Sgshapiro break; 26464562Sgshapiro } 26564562Sgshapiro } 26664562Sgshapiro argc -= optind; 26764562Sgshapiro argv += optind; 26864562Sgshapiro 26964562Sgshapiro if (mfail != 0) 27064562Sgshapiro { 27164562Sgshapiro msglog(LOG_NOTICE, 27264562Sgshapiro "vacation: can't allocate memory for alias.\n"); 27366494Sgshapiro EXITM(EX_TEMPFAIL); 27464562Sgshapiro } 27564562Sgshapiro if (ufail != 0) 27664562Sgshapiro usage(); 27764562Sgshapiro 27864562Sgshapiro if (argc != 1) 27964562Sgshapiro { 28098121Sgshapiro if (!initdb && !list && !exclude) 28164562Sgshapiro usage(); 28264562Sgshapiro if ((pw = getpwuid(getuid())) == NULL) 28364562Sgshapiro { 28464562Sgshapiro msglog(LOG_ERR, 28564562Sgshapiro "vacation: no such user uid %u.\n", getuid()); 28666494Sgshapiro EXITM(EX_NOUSER); 28764562Sgshapiro } 28877349Sgshapiro name = pw->pw_name; 28977349Sgshapiro user_info.smdbu_id = pw->pw_uid; 29077349Sgshapiro user_info.smdbu_group_id = pw->pw_gid; 29190792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name, 29290792Sgshapiro SMDB_MAX_USER_NAME_LEN); 29377349Sgshapiro if (chdir(pw->pw_dir) != 0) 29477349Sgshapiro { 29590792Sgshapiro msglog(LOG_NOTICE, 29690792Sgshapiro "vacation: no such directory %s.\n", 29777349Sgshapiro pw->pw_dir); 29877349Sgshapiro EXITM(EX_NOINPUT); 29977349Sgshapiro } 30064562Sgshapiro } 30177349Sgshapiro else if (runasuser) 30277349Sgshapiro { 30377349Sgshapiro name = *argv; 30477349Sgshapiro if (dbfilename == NULL || msgfilename == NULL) 30577349Sgshapiro { 30677349Sgshapiro msglog(LOG_NOTICE, 30777349Sgshapiro "vacation: -U requires setting both -f and -m\n"); 30877349Sgshapiro EXITM(EX_NOINPUT); 30977349Sgshapiro } 31077349Sgshapiro user_info.smdbu_id = pw->pw_uid; 31177349Sgshapiro user_info.smdbu_group_id = pw->pw_gid; 31290792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name, 31377349Sgshapiro SMDB_MAX_USER_NAME_LEN); 31477349Sgshapiro } 31577349Sgshapiro else 31664562Sgshapiro { 31790792Sgshapiro int err; 31890792Sgshapiro SM_CF_OPT_T mbdbname; 31990792Sgshapiro SM_MBDB_T user; 32090792Sgshapiro 32194334Sgshapiro cfpath = getcfname(0, 0, SM_GET_SENDMAIL_CF, cfpath); 32290792Sgshapiro mbdbname.opt_name = "MailboxDatabase"; 32390792Sgshapiro mbdbname.opt_val = "pw"; 32490792Sgshapiro (void) sm_cf_getopt(cfpath, 1, &mbdbname); 32590792Sgshapiro err = sm_mbdb_initialize(mbdbname.opt_val); 32690792Sgshapiro if (err != EX_OK) 32777349Sgshapiro { 32890792Sgshapiro msglog(LOG_ERR, 32990792Sgshapiro "vacation: can't open mailbox database: %s.\n", 33090792Sgshapiro sm_strexit(err)); 33190792Sgshapiro EXITM(err); 33290792Sgshapiro } 33390792Sgshapiro err = sm_mbdb_lookup(*argv, &user); 33490792Sgshapiro if (err == EX_NOUSER) 33590792Sgshapiro { 33690792Sgshapiro msglog(LOG_ERR, "vacation: no such user %s.\n", *argv); 33790792Sgshapiro EXITM(EX_NOUSER); 33890792Sgshapiro } 33990792Sgshapiro if (err != EX_OK) 34090792Sgshapiro { 34190792Sgshapiro msglog(LOG_ERR, 34290792Sgshapiro "vacation: can't read mailbox database: %s.\n", 34390792Sgshapiro sm_strexit(err)); 34490792Sgshapiro EXITM(err); 34590792Sgshapiro } 34690792Sgshapiro name = user.mbdb_name; 34790792Sgshapiro if (chdir(user.mbdb_homedir) != 0) 34890792Sgshapiro { 34990792Sgshapiro msglog(LOG_NOTICE, 35090792Sgshapiro "vacation: no such directory %s.\n", 35190792Sgshapiro user.mbdb_homedir); 35277349Sgshapiro EXITM(EX_NOINPUT); 35377349Sgshapiro } 35490792Sgshapiro user_info.smdbu_id = user.mbdb_uid; 35590792Sgshapiro user_info.smdbu_group_id = user.mbdb_gid; 35690792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, user.mbdb_name, 35777349Sgshapiro SMDB_MAX_USER_NAME_LEN); 35864562Sgshapiro } 35964562Sgshapiro 36077349Sgshapiro if (dbfilename == NULL) 36177349Sgshapiro dbfilename = VDB; 36277349Sgshapiro if (msgfilename == NULL) 36377349Sgshapiro msgfilename = VMSG; 36477349Sgshapiro 36566494Sgshapiro sff = SFF_CREAT; 36666494Sgshapiro if (getegid() != getgid()) 36777349Sgshapiro { 36890792Sgshapiro /* Allow a set-group-ID vacation binary */ 36966494Sgshapiro RunAsGid = user_info.smdbu_group_id = getegid(); 37090792Sgshapiro sff |= SFF_OPENASROOT; 37177349Sgshapiro } 37294334Sgshapiro if (getuid() == 0) 37394334Sgshapiro { 37494334Sgshapiro /* Allow root to initialize user's vacation databases */ 37594334Sgshapiro sff |= SFF_OPENASROOT|SFF_ROOTOK; 37666494Sgshapiro 37794334Sgshapiro /* ... safely */ 37894334Sgshapiro sff |= SFF_NOSLINK|SFF_NOHLINK|SFF_REGONLY; 37994334Sgshapiro } 38094334Sgshapiro 38194334Sgshapiro 38264562Sgshapiro result = smdb_open_database(&Db, dbfilename, 38398121Sgshapiro O_CREAT|O_RDWR | (initdb ? O_TRUNC : 0), 38466494Sgshapiro S_IRUSR|S_IWUSR, sff, 38564562Sgshapiro SMDB_TYPE_DEFAULT, &user_info, NULL); 38664562Sgshapiro if (result != SMDBE_OK) 38764562Sgshapiro { 38864562Sgshapiro msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename, 38990792Sgshapiro sm_errstring(result)); 39066494Sgshapiro EXITM(EX_DATAERR); 39164562Sgshapiro } 39264562Sgshapiro 39398121Sgshapiro if (list) 39464562Sgshapiro { 39564562Sgshapiro listdb(); 39671345Sgshapiro (void) Db->smdb_close(Db); 39764562Sgshapiro exit(EX_OK); 39864562Sgshapiro } 39964562Sgshapiro 40064562Sgshapiro if (interval != INTERVAL_UNDEF) 40164562Sgshapiro setinterval(interval); 40264562Sgshapiro 40398121Sgshapiro if (initdb && !exclude) 40464562Sgshapiro { 40571345Sgshapiro (void) Db->smdb_close(Db); 40671345Sgshapiro exit(EX_OK); 40764562Sgshapiro } 40864562Sgshapiro 40964562Sgshapiro if (exclude) 41064562Sgshapiro { 41190792Sgshapiro xclude(smioin); 41271345Sgshapiro (void) Db->smdb_close(Db); 41366494Sgshapiro EXITM(EX_OK); 41464562Sgshapiro } 41564562Sgshapiro 41690792Sgshapiro if ((cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS))) == NULL) 41764562Sgshapiro { 41864562Sgshapiro msglog(LOG_NOTICE, 41964562Sgshapiro "vacation: can't allocate memory for username.\n"); 42071345Sgshapiro (void) Db->smdb_close(Db); 42166494Sgshapiro EXITM(EX_OSERR); 42264562Sgshapiro } 42364562Sgshapiro cur->name = name; 42464562Sgshapiro cur->next = Names; 42564562Sgshapiro Names = cur; 42664562Sgshapiro 42798121Sgshapiro result = readheaders(alwaysrespond); 42871345Sgshapiro if (result == EX_OK && !recent()) 42964562Sgshapiro { 43064562Sgshapiro time_t now; 43164562Sgshapiro 43264562Sgshapiro (void) time(&now); 43364562Sgshapiro setreply(From, now); 43471345Sgshapiro (void) Db->smdb_close(Db); 43590792Sgshapiro sendmessage(name, msgfilename, returnaddr); 43664562Sgshapiro } 43764562Sgshapiro else 43871345Sgshapiro (void) Db->smdb_close(Db); 43971345Sgshapiro if (result == EX_NOUSER) 44071345Sgshapiro result = EX_OK; 44171345Sgshapiro exit(result); 44264562Sgshapiro} 44364562Sgshapiro 44464562Sgshapiro/* 44566494Sgshapiro** EATMSG -- read stdin till EOF 44666494Sgshapiro** 44766494Sgshapiro** Parameters: 44866494Sgshapiro** none. 44966494Sgshapiro** 45066494Sgshapiro** Returns: 45166494Sgshapiro** nothing. 45266494Sgshapiro** 45366494Sgshapiro*/ 45477349Sgshapiro 45566494Sgshapirostatic void 45666494Sgshapiroeatmsg() 45766494Sgshapiro{ 45866494Sgshapiro /* 45966494Sgshapiro ** read the rest of the e-mail and ignore it to avoid problems 46066494Sgshapiro ** with EPIPE in sendmail 46166494Sgshapiro */ 46266494Sgshapiro while (getc(stdin) != EOF) 46366494Sgshapiro continue; 46466494Sgshapiro} 46566494Sgshapiro 46666494Sgshapiro/* 46764562Sgshapiro** READHEADERS -- read mail headers 46864562Sgshapiro** 46964562Sgshapiro** Parameters: 47098121Sgshapiro** alwaysrespond -- respond regardless of whether msg is to me 47164562Sgshapiro** 47264562Sgshapiro** Returns: 47371345Sgshapiro** a exit code: NOUSER if no reply, OK if reply, * if error 47464562Sgshapiro** 47566494Sgshapiro** Side Effects: 47666494Sgshapiro** may exit(). 47766494Sgshapiro** 47864562Sgshapiro*/ 47971345Sgshapiro 48071345Sgshapiroint 48198121Sgshapiroreadheaders(alwaysrespond) 48298121Sgshapiro bool alwaysrespond; 48364562Sgshapiro{ 48464562Sgshapiro bool tome, cont; 48564562Sgshapiro register char *p; 48664562Sgshapiro register ALIAS *cur; 48764562Sgshapiro char buf[MAXLINE]; 48864562Sgshapiro extern bool junkmail __P((char *)); 48964562Sgshapiro extern bool nsearch __P((char *, char *)); 49064562Sgshapiro 49198121Sgshapiro cont = false; 49298121Sgshapiro tome = alwaysrespond; 49390792Sgshapiro while (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, sizeof(buf)) && 49490792Sgshapiro *buf != '\n') 49564562Sgshapiro { 49664562Sgshapiro switch(*buf) 49764562Sgshapiro { 49864562Sgshapiro case 'F': /* "From " */ 49990792Sgshapiro cont = false; 50064562Sgshapiro if (strncmp(buf, "From ", 5) == 0) 50164562Sgshapiro { 50290792Sgshapiro bool quoted = false; 50364562Sgshapiro 50464562Sgshapiro p = buf + 5; 50564562Sgshapiro while (*p != '\0') 50664562Sgshapiro { 50764562Sgshapiro /* escaped character */ 50864562Sgshapiro if (*p == '\\') 50964562Sgshapiro { 51064562Sgshapiro p++; 51164562Sgshapiro if (*p == '\0') 51264562Sgshapiro { 51364562Sgshapiro msglog(LOG_NOTICE, 51464562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 51566494Sgshapiro EXITIT(EX_DATAERR); 51664562Sgshapiro } 51764562Sgshapiro } 51864562Sgshapiro else if (*p == '"') 51964562Sgshapiro quoted = !quoted; 52064562Sgshapiro else if (*p == '\r' || *p == '\n') 52164562Sgshapiro break; 52264562Sgshapiro else if (*p == ' ' && !quoted) 52364562Sgshapiro break; 52464562Sgshapiro p++; 52564562Sgshapiro } 52664562Sgshapiro if (quoted) 52764562Sgshapiro { 52864562Sgshapiro msglog(LOG_NOTICE, 52964562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 53066494Sgshapiro EXITIT(EX_DATAERR); 53164562Sgshapiro } 53264562Sgshapiro *p = '\0'; 53364562Sgshapiro 53464562Sgshapiro /* ok since both strings have MAXLINE length */ 53564562Sgshapiro if (*From == '\0') 53690792Sgshapiro (void) sm_strlcpy(From, buf + 5, 53790792Sgshapiro sizeof From); 53864562Sgshapiro if ((p = strchr(buf + 5, '\n')) != NULL) 53964562Sgshapiro *p = '\0'; 54064562Sgshapiro if (junkmail(buf + 5)) 54171345Sgshapiro EXITIT(EX_NOUSER); 54264562Sgshapiro } 54364562Sgshapiro break; 54464562Sgshapiro 54564562Sgshapiro case 'P': /* "Precedence:" */ 54664562Sgshapiro case 'p': 54790792Sgshapiro cont = false; 54864562Sgshapiro if (strlen(buf) <= 10 || 54964562Sgshapiro strncasecmp(buf, "Precedence", 10) != 0 || 55064562Sgshapiro (buf[10] != ':' && buf[10] != ' ' && 55164562Sgshapiro buf[10] != '\t')) 55264562Sgshapiro break; 55364562Sgshapiro if ((p = strchr(buf, ':')) == NULL) 55464562Sgshapiro break; 55564562Sgshapiro while (*++p != '\0' && isascii(*p) && isspace(*p)); 55664562Sgshapiro if (*p == '\0') 55764562Sgshapiro break; 55864562Sgshapiro if (strncasecmp(p, "junk", 4) == 0 || 55964562Sgshapiro strncasecmp(p, "bulk", 4) == 0 || 56064562Sgshapiro strncasecmp(p, "list", 4) == 0) 56171345Sgshapiro EXITIT(EX_NOUSER); 56264562Sgshapiro break; 56364562Sgshapiro 56464562Sgshapiro case 'C': /* "Cc:" */ 56564562Sgshapiro case 'c': 56664562Sgshapiro if (strncasecmp(buf, "Cc:", 3) != 0) 56764562Sgshapiro break; 56890792Sgshapiro cont = true; 56964562Sgshapiro goto findme; 57064562Sgshapiro 57164562Sgshapiro case 'T': /* "To:" */ 57264562Sgshapiro case 't': 57364562Sgshapiro if (strncasecmp(buf, "To:", 3) != 0) 57464562Sgshapiro break; 57590792Sgshapiro cont = true; 57664562Sgshapiro goto findme; 57764562Sgshapiro 57864562Sgshapiro default: 57964562Sgshapiro if (!isascii(*buf) || !isspace(*buf) || !cont || tome) 58064562Sgshapiro { 58190792Sgshapiro cont = false; 58264562Sgshapiro break; 58364562Sgshapiro } 58464562Sgshapirofindme: 58564562Sgshapiro for (cur = Names; 58664562Sgshapiro !tome && cur != NULL; 58764562Sgshapiro cur = cur->next) 58864562Sgshapiro tome = nsearch(cur->name, buf); 58964562Sgshapiro } 59064562Sgshapiro } 59164562Sgshapiro if (!tome) 59271345Sgshapiro EXITIT(EX_NOUSER); 59364562Sgshapiro if (*From == '\0') 59464562Sgshapiro { 59564562Sgshapiro msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n"); 59666494Sgshapiro EXITIT(EX_DATAERR); 59764562Sgshapiro } 59871345Sgshapiro EXITIT(EX_OK); 59964562Sgshapiro} 60064562Sgshapiro 60164562Sgshapiro/* 60264562Sgshapiro** NSEARCH -- 60364562Sgshapiro** do a nice, slow, search of a string for a substring. 60464562Sgshapiro** 60564562Sgshapiro** Parameters: 60664562Sgshapiro** name -- name to search. 60764562Sgshapiro** str -- string in which to search. 60864562Sgshapiro** 60964562Sgshapiro** Returns: 61064562Sgshapiro** is name a substring of str? 61164562Sgshapiro** 61264562Sgshapiro*/ 61377349Sgshapiro 61464562Sgshapirobool 61564562Sgshapironsearch(name, str) 61664562Sgshapiro register char *name, *str; 61764562Sgshapiro{ 61864562Sgshapiro register size_t len; 61964562Sgshapiro register char *s; 62064562Sgshapiro 62164562Sgshapiro len = strlen(name); 62264562Sgshapiro 62364562Sgshapiro for (s = str; *s != '\0'; ++s) 62464562Sgshapiro { 62564562Sgshapiro /* 62664562Sgshapiro ** Check to make sure that the string matches and 62764562Sgshapiro ** the previous character is not an alphanumeric and 62864562Sgshapiro ** the next character after the match is not an alphanumeric. 62964562Sgshapiro ** 63064562Sgshapiro ** This prevents matching "eric" to "derick" while still 63164562Sgshapiro ** matching "eric" to "<eric+detail>". 63264562Sgshapiro */ 63364562Sgshapiro 63464562Sgshapiro if (tolower(*s) == tolower(*name) && 63564562Sgshapiro strncasecmp(name, s, len) == 0 && 63664562Sgshapiro (s == str || !isascii(*(s - 1)) || !isalnum(*(s - 1))) && 63764562Sgshapiro (!isascii(*(s + len)) || !isalnum(*(s + len)))) 63890792Sgshapiro return true; 63964562Sgshapiro } 64090792Sgshapiro return false; 64164562Sgshapiro} 64264562Sgshapiro 64364562Sgshapiro/* 64464562Sgshapiro** JUNKMAIL -- 64564562Sgshapiro** read the header and return if automagic/junk/bulk/list mail 64664562Sgshapiro** 64764562Sgshapiro** Parameters: 64864562Sgshapiro** from -- sender address. 64964562Sgshapiro** 65064562Sgshapiro** Returns: 65164562Sgshapiro** is this some automated/junk/bulk/list mail? 65264562Sgshapiro** 65364562Sgshapiro*/ 65471345Sgshapiro 65571345Sgshapirostruct ignore 65671345Sgshapiro{ 65771345Sgshapiro char *name; 65871345Sgshapiro size_t len; 65971345Sgshapiro}; 66071345Sgshapiro 66171345Sgshapirotypedef struct ignore IGNORE_T; 66271345Sgshapiro 66371345Sgshapiro#define MAX_USER_LEN 256 /* maximum length of local part (sender) */ 66471345Sgshapiro 66571345Sgshapiro/* delimiters for the local part of an address */ 66671345Sgshapiro#define isdelim(c) ((c) == '%' || (c) == '@' || (c) == '+') 66771345Sgshapiro 66864562Sgshapirobool 66964562Sgshapirojunkmail(from) 67064562Sgshapiro char *from; 67164562Sgshapiro{ 67271345Sgshapiro bool quot; 67371345Sgshapiro char *e; 67471345Sgshapiro size_t len; 67571345Sgshapiro IGNORE_T *cur; 67671345Sgshapiro char sender[MAX_USER_LEN]; 67771345Sgshapiro static IGNORE_T ignore[] = 67864562Sgshapiro { 67964562Sgshapiro { "postmaster", 10 }, 68064562Sgshapiro { "uucp", 4 }, 68164562Sgshapiro { "mailer-daemon", 13 }, 68264562Sgshapiro { "mailer", 6 }, 68371345Sgshapiro { NULL, 0 } 68471345Sgshapiro }; 68571345Sgshapiro 68671345Sgshapiro static IGNORE_T ignorepost[] = 68771345Sgshapiro { 68871345Sgshapiro { "-request", 8 }, 68964562Sgshapiro { "-relay", 6 }, 69071345Sgshapiro { "-owner", 6 }, 69164562Sgshapiro { NULL, 0 } 69264562Sgshapiro }; 69364562Sgshapiro 69471345Sgshapiro static IGNORE_T ignorepre[] = 69571345Sgshapiro { 69671345Sgshapiro { "owner-", 6 }, 69771345Sgshapiro { NULL, 0 } 69871345Sgshapiro }; 69971345Sgshapiro 70064562Sgshapiro /* 70171345Sgshapiro ** This is mildly amusing, and I'm not positive it's right; trying 70271345Sgshapiro ** to find the "real" name of the sender, assuming that addresses 70371345Sgshapiro ** will be some variant of: 70471345Sgshapiro ** 70571345Sgshapiro ** From site!site!SENDER%site.domain%site.domain@site.domain 70671345Sgshapiro */ 70771345Sgshapiro 70890792Sgshapiro quot = false; 70971345Sgshapiro e = from; 71071345Sgshapiro len = 0; 71171345Sgshapiro while (*e != '\0' && (quot || !isdelim(*e))) 71264562Sgshapiro { 71371345Sgshapiro if (*e == '"') 71471345Sgshapiro { 71571345Sgshapiro quot = !quot; 71671345Sgshapiro ++e; 71771345Sgshapiro continue; 71871345Sgshapiro } 71971345Sgshapiro if (*e == '\\') 72071345Sgshapiro { 72171345Sgshapiro if (*(++e) == '\0') 72271345Sgshapiro { 72371345Sgshapiro /* '\\' at end of string? */ 72471345Sgshapiro break; 72571345Sgshapiro } 72671345Sgshapiro if (len < MAX_USER_LEN) 72771345Sgshapiro sender[len++] = *e; 72871345Sgshapiro ++e; 72971345Sgshapiro continue; 73071345Sgshapiro } 73171345Sgshapiro if (*e == '!' && !quot) 73271345Sgshapiro { 73371345Sgshapiro len = 0; 73471345Sgshapiro sender[len] = '\0'; 73571345Sgshapiro } 73664562Sgshapiro else 73771345Sgshapiro if (len < MAX_USER_LEN) 73871345Sgshapiro sender[len++] = *e; 73971345Sgshapiro ++e; 74064562Sgshapiro } 74171345Sgshapiro if (len < MAX_USER_LEN) 74271345Sgshapiro sender[len] = '\0'; 74371345Sgshapiro else 74471345Sgshapiro sender[MAX_USER_LEN - 1] = '\0'; 74571345Sgshapiro 74671345Sgshapiro if (len <= 0) 74790792Sgshapiro return false; 74871345Sgshapiro#if 0 74971345Sgshapiro if (quot) 75090792Sgshapiro return false; /* syntax error... */ 75171345Sgshapiro#endif /* 0 */ 75271345Sgshapiro 75371345Sgshapiro /* test prefixes */ 75471345Sgshapiro for (cur = ignorepre; cur->name != NULL; ++cur) 75571345Sgshapiro { 75671345Sgshapiro if (len >= cur->len && 75771345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 75890792Sgshapiro return true; 75971345Sgshapiro } 76071345Sgshapiro 76171345Sgshapiro /* 76271345Sgshapiro ** If the name is truncated, don't test the rest. 76371345Sgshapiro ** We could extract the "tail" of the sender address and 76471345Sgshapiro ** compare it it ignorepost, however, it seems not worth 76571345Sgshapiro ** the effort. 76671345Sgshapiro ** The address surely can't match any entry in ignore[] 76771345Sgshapiro ** (as long as all of them are shorter than MAX_USER_LEN). 76871345Sgshapiro */ 76971345Sgshapiro 77071345Sgshapiro if (len > MAX_USER_LEN) 77190792Sgshapiro return false; 77271345Sgshapiro 77371345Sgshapiro /* test full local parts */ 77464562Sgshapiro for (cur = ignore; cur->name != NULL; ++cur) 77564562Sgshapiro { 77671345Sgshapiro if (len == cur->len && 77771345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 77890792Sgshapiro return true; 77971345Sgshapiro } 78071345Sgshapiro 78171345Sgshapiro /* test postfixes */ 78271345Sgshapiro for (cur = ignorepost; cur->name != NULL; ++cur) 78371345Sgshapiro { 78464562Sgshapiro if (len >= cur->len && 78571345Sgshapiro strncasecmp(cur->name, e - cur->len - 1, 78671345Sgshapiro cur->len) == 0) 78790792Sgshapiro return true; 78864562Sgshapiro } 78990792Sgshapiro return false; 79064562Sgshapiro} 79164562Sgshapiro 79264562Sgshapiro#define VIT "__VACATION__INTERVAL__TIMER__" 79364562Sgshapiro 79464562Sgshapiro/* 79564562Sgshapiro** RECENT -- 79664562Sgshapiro** find out if user has gotten a vacation message recently. 79764562Sgshapiro** 79864562Sgshapiro** Parameters: 79964562Sgshapiro** none. 80064562Sgshapiro** 80164562Sgshapiro** Returns: 80290792Sgshapiro** true iff user has gotten a vacation message recently. 80364562Sgshapiro** 80464562Sgshapiro*/ 80577349Sgshapiro 80664562Sgshapirobool 80764562Sgshapirorecent() 80864562Sgshapiro{ 80964562Sgshapiro SMDB_DBENT key, data; 81064562Sgshapiro time_t then, next; 81190792Sgshapiro bool trydomain = false; 81264562Sgshapiro int st; 81364562Sgshapiro char *domain; 81464562Sgshapiro 81564562Sgshapiro memset(&key, '\0', sizeof key); 81664562Sgshapiro memset(&data, '\0', sizeof data); 81764562Sgshapiro 81864562Sgshapiro /* get interval time */ 81971345Sgshapiro key.data = VIT; 82071345Sgshapiro key.size = sizeof(VIT); 82164562Sgshapiro 82264562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 82364562Sgshapiro if (st != SMDBE_OK) 82464562Sgshapiro next = SECSPERDAY * DAYSPERWEEK; 82564562Sgshapiro else 82671345Sgshapiro memmove(&next, data.data, sizeof(next)); 82764562Sgshapiro 82864562Sgshapiro memset(&data, '\0', sizeof data); 82964562Sgshapiro 83064562Sgshapiro /* get record for this address */ 83171345Sgshapiro key.data = From; 83271345Sgshapiro key.size = strlen(From); 83364562Sgshapiro 83464562Sgshapiro do 83564562Sgshapiro { 83664562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 83764562Sgshapiro if (st == SMDBE_OK) 83864562Sgshapiro { 83971345Sgshapiro memmove(&then, data.data, sizeof(then)); 84064562Sgshapiro if (next == ONLY_ONCE || then == ONLY_ONCE || 84164562Sgshapiro then + next > time(NULL)) 84290792Sgshapiro return true; 84364562Sgshapiro } 84464562Sgshapiro if ((trydomain = !trydomain) && 84564562Sgshapiro (domain = strchr(From, '@')) != NULL) 84664562Sgshapiro { 84771345Sgshapiro key.data = domain; 84871345Sgshapiro key.size = strlen(domain); 84964562Sgshapiro } 85064562Sgshapiro } while (trydomain); 85190792Sgshapiro return false; 85264562Sgshapiro} 85364562Sgshapiro 85464562Sgshapiro/* 85564562Sgshapiro** SETINTERVAL -- 85664562Sgshapiro** store the reply interval 85764562Sgshapiro** 85864562Sgshapiro** Parameters: 85964562Sgshapiro** interval -- time interval for replies. 86064562Sgshapiro** 86164562Sgshapiro** Returns: 86264562Sgshapiro** nothing. 86364562Sgshapiro** 86464562Sgshapiro** Side Effects: 86564562Sgshapiro** stores the reply interval in database. 86664562Sgshapiro*/ 86777349Sgshapiro 86864562Sgshapirovoid 86964562Sgshapirosetinterval(interval) 87064562Sgshapiro time_t interval; 87164562Sgshapiro{ 87264562Sgshapiro SMDB_DBENT key, data; 87364562Sgshapiro 87464562Sgshapiro memset(&key, '\0', sizeof key); 87564562Sgshapiro memset(&data, '\0', sizeof data); 87664562Sgshapiro 87771345Sgshapiro key.data = VIT; 87871345Sgshapiro key.size = sizeof(VIT); 87971345Sgshapiro data.data = (char*) &interval; 88071345Sgshapiro data.size = sizeof(interval); 88171345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 88264562Sgshapiro} 88364562Sgshapiro 88464562Sgshapiro/* 88564562Sgshapiro** SETREPLY -- 88664562Sgshapiro** store that this user knows about the vacation. 88764562Sgshapiro** 88864562Sgshapiro** Parameters: 88964562Sgshapiro** from -- sender address. 89064562Sgshapiro** when -- last reply time. 89164562Sgshapiro** 89264562Sgshapiro** Returns: 89364562Sgshapiro** nothing. 89464562Sgshapiro** 89564562Sgshapiro** Side Effects: 89664562Sgshapiro** stores user/time in database. 89764562Sgshapiro*/ 89877349Sgshapiro 89964562Sgshapirovoid 90064562Sgshapirosetreply(from, when) 90164562Sgshapiro char *from; 90264562Sgshapiro time_t when; 90364562Sgshapiro{ 90464562Sgshapiro SMDB_DBENT key, data; 90564562Sgshapiro 90664562Sgshapiro memset(&key, '\0', sizeof key); 90764562Sgshapiro memset(&data, '\0', sizeof data); 90864562Sgshapiro 90971345Sgshapiro key.data = from; 91071345Sgshapiro key.size = strlen(from); 91171345Sgshapiro data.data = (char*) &when; 91271345Sgshapiro data.size = sizeof(when); 91371345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 91464562Sgshapiro} 91564562Sgshapiro 91664562Sgshapiro/* 91764562Sgshapiro** XCLUDE -- 91864562Sgshapiro** add users to vacation db so they don't get a reply. 91964562Sgshapiro** 92064562Sgshapiro** Parameters: 92164562Sgshapiro** f -- file pointer with list of address to exclude 92264562Sgshapiro** 92364562Sgshapiro** Returns: 92464562Sgshapiro** nothing. 92564562Sgshapiro** 92664562Sgshapiro** Side Effects: 92764562Sgshapiro** stores users in database. 92864562Sgshapiro*/ 92977349Sgshapiro 93064562Sgshapirovoid 93164562Sgshapiroxclude(f) 93290792Sgshapiro SM_FILE_T *f; 93364562Sgshapiro{ 93464562Sgshapiro char buf[MAXLINE], *p; 93564562Sgshapiro 93664562Sgshapiro if (f == NULL) 93764562Sgshapiro return; 93890792Sgshapiro while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf)) 93964562Sgshapiro { 94064562Sgshapiro if ((p = strchr(buf, '\n')) != NULL) 94164562Sgshapiro *p = '\0'; 94264562Sgshapiro setreply(buf, ONLY_ONCE); 94364562Sgshapiro } 94464562Sgshapiro} 94564562Sgshapiro 94664562Sgshapiro/* 94764562Sgshapiro** SENDMESSAGE -- 94864562Sgshapiro** exec sendmail to send the vacation file to sender 94964562Sgshapiro** 95064562Sgshapiro** Parameters: 95164562Sgshapiro** myname -- user name. 95264562Sgshapiro** msgfn -- name of file with vacation message. 95390792Sgshapiro** sender -- use as sender address 95464562Sgshapiro** 95564562Sgshapiro** Returns: 95664562Sgshapiro** nothing. 95764562Sgshapiro** 95864562Sgshapiro** Side Effects: 95964562Sgshapiro** sends vacation reply. 96064562Sgshapiro*/ 96177349Sgshapiro 96264562Sgshapirovoid 96390792Sgshapirosendmessage(myname, msgfn, sender) 96464562Sgshapiro char *myname; 96564562Sgshapiro char *msgfn; 96690792Sgshapiro char *sender; 96764562Sgshapiro{ 96890792Sgshapiro SM_FILE_T *mfp, *sfp; 96964562Sgshapiro int i; 97064562Sgshapiro int pvect[2]; 97177349Sgshapiro char *pv[8]; 97264562Sgshapiro char buf[MAXLINE]; 97364562Sgshapiro 97490792Sgshapiro mfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, msgfn, SM_IO_RDONLY, NULL); 97564562Sgshapiro if (mfp == NULL) 97664562Sgshapiro { 97764562Sgshapiro if (msgfn[0] == '/') 97864562Sgshapiro msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn); 97964562Sgshapiro else 98064562Sgshapiro msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", 98164562Sgshapiro myname, msgfn); 98264562Sgshapiro exit(EX_NOINPUT); 98364562Sgshapiro } 98464562Sgshapiro if (pipe(pvect) < 0) 98564562Sgshapiro { 98690792Sgshapiro msglog(LOG_ERR, "vacation: pipe: %s", sm_errstring(errno)); 98764562Sgshapiro exit(EX_OSERR); 98864562Sgshapiro } 98977349Sgshapiro pv[0] = "sendmail"; 99077349Sgshapiro pv[1] = "-oi"; 99177349Sgshapiro pv[2] = "-f"; 99290792Sgshapiro if (sender != NULL) 99390792Sgshapiro pv[3] = sender; 99477349Sgshapiro else 99577349Sgshapiro pv[3] = myname; 99677349Sgshapiro pv[4] = "--"; 99777349Sgshapiro pv[5] = From; 99877349Sgshapiro pv[6] = NULL; 99964562Sgshapiro i = fork(); 100064562Sgshapiro if (i < 0) 100164562Sgshapiro { 100290792Sgshapiro msglog(LOG_ERR, "vacation: fork: %s", sm_errstring(errno)); 100364562Sgshapiro exit(EX_OSERR); 100464562Sgshapiro } 100564562Sgshapiro if (i == 0) 100664562Sgshapiro { 100764562Sgshapiro (void) dup2(pvect[0], 0); 100864562Sgshapiro (void) close(pvect[0]); 100964562Sgshapiro (void) close(pvect[1]); 101090792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 101177349Sgshapiro (void) execv(_PATH_SENDMAIL, pv); 101264562Sgshapiro msglog(LOG_ERR, "vacation: can't exec %s: %s", 101390792Sgshapiro _PATH_SENDMAIL, sm_errstring(errno)); 101464562Sgshapiro exit(EX_UNAVAILABLE); 101564562Sgshapiro } 101664562Sgshapiro /* check return status of the following calls? XXX */ 101764562Sgshapiro (void) close(pvect[0]); 101890792Sgshapiro if ((sfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 101990792Sgshapiro (void *) &(pvect[1]), 102090792Sgshapiro SM_IO_WRONLY, NULL)) != NULL) 102164562Sgshapiro { 102290792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, "To: %s\n", From); 102390792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, 102490792Sgshapiro "Auto-Submitted: auto-replied\n"); 102590792Sgshapiro while (sm_io_fgets(mfp, SM_TIME_DEFAULT, buf, sizeof buf)) 102690792Sgshapiro (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf); 102790792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 102890792Sgshapiro (void) sm_io_close(sfp, SM_TIME_DEFAULT); 102964562Sgshapiro } 103064562Sgshapiro else 103164562Sgshapiro { 103290792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 103364562Sgshapiro msglog(LOG_ERR, "vacation: can't open pipe to sendmail"); 103464562Sgshapiro exit(EX_UNAVAILABLE); 103564562Sgshapiro } 103664562Sgshapiro} 103764562Sgshapiro 103864562Sgshapirovoid 103964562Sgshapirousage() 104064562Sgshapiro{ 104177349Sgshapiro msglog(LOG_NOTICE, 1042132943Sgshapiro "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", 1043132943Sgshapiro getuid()); 104464562Sgshapiro exit(EX_USAGE); 104564562Sgshapiro} 104664562Sgshapiro 104764562Sgshapiro/* 104864562Sgshapiro** LISTDB -- list the contents of the vacation database 104964562Sgshapiro** 105064562Sgshapiro** Parameters: 105164562Sgshapiro** none. 105264562Sgshapiro** 105364562Sgshapiro** Returns: 105464562Sgshapiro** nothing. 105564562Sgshapiro*/ 105664562Sgshapiro 105764562Sgshapirostatic void 105864562Sgshapirolistdb() 105964562Sgshapiro{ 106064562Sgshapiro int result; 106164562Sgshapiro time_t t; 106264562Sgshapiro SMDB_CURSOR *cursor = NULL; 106364562Sgshapiro SMDB_DBENT db_key, db_value; 106464562Sgshapiro 106564562Sgshapiro memset(&db_key, '\0', sizeof db_key); 106664562Sgshapiro memset(&db_value, '\0', sizeof db_value); 106764562Sgshapiro 106864562Sgshapiro result = Db->smdb_cursor(Db, &cursor, 0); 106964562Sgshapiro if (result != SMDBE_OK) 107064562Sgshapiro { 107190792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 107290792Sgshapiro "vacation: set cursor: %s\n", 107390792Sgshapiro sm_errstring(result)); 107464562Sgshapiro return; 107564562Sgshapiro } 107664562Sgshapiro 107764562Sgshapiro while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, 107864562Sgshapiro SMDB_CURSOR_GET_NEXT)) == SMDBE_OK) 107964562Sgshapiro { 108098121Sgshapiro char *timestamp; 108198121Sgshapiro 108264562Sgshapiro /* skip magic VIT entry */ 1083110560Sgshapiro if (db_key.size == strlen(VIT) + 1 && 108471345Sgshapiro strncmp((char *)db_key.data, VIT, 108571345Sgshapiro (int)db_key.size - 1) == 0) 108664562Sgshapiro continue; 108764562Sgshapiro 108864562Sgshapiro /* skip bogus values */ 108971345Sgshapiro if (db_value.size != sizeof t) 109064562Sgshapiro { 109190792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 109290792Sgshapiro "vacation: %.*s invalid time stamp\n", 109390792Sgshapiro (int) db_key.size, (char *) db_key.data); 109464562Sgshapiro continue; 109564562Sgshapiro } 109664562Sgshapiro 109771345Sgshapiro memcpy(&t, db_value.data, sizeof t); 109864562Sgshapiro 109971345Sgshapiro if (db_key.size > 40) 110071345Sgshapiro db_key.size = 40; 110164562Sgshapiro 110298121Sgshapiro if (t <= 0) 110398121Sgshapiro { 110498121Sgshapiro /* must be an exclude */ 110598121Sgshapiro timestamp = "(exclusion)\n"; 110698121Sgshapiro } 110798121Sgshapiro else 110898121Sgshapiro { 110998121Sgshapiro timestamp = ctime(&t); 111098121Sgshapiro } 111190792Sgshapiro sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%-40.*s %-10s", 111290792Sgshapiro (int) db_key.size, (char *) db_key.data, 111398121Sgshapiro timestamp); 111464562Sgshapiro 111564562Sgshapiro memset(&db_key, '\0', sizeof db_key); 111664562Sgshapiro memset(&db_value, '\0', sizeof db_value); 111764562Sgshapiro } 111864562Sgshapiro 111964562Sgshapiro if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) 112064562Sgshapiro { 112190792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 112290792Sgshapiro "vacation: get value at cursor: %s\n", 112390792Sgshapiro sm_errstring(result)); 112464562Sgshapiro if (cursor != NULL) 112564562Sgshapiro { 112664562Sgshapiro (void) cursor->smdbc_close(cursor); 112764562Sgshapiro cursor = NULL; 112864562Sgshapiro } 112964562Sgshapiro return; 113064562Sgshapiro } 113164562Sgshapiro (void) cursor->smdbc_close(cursor); 113264562Sgshapiro cursor = NULL; 113364562Sgshapiro} 113464562Sgshapiro 113564562Sgshapiro/* 113664562Sgshapiro** DEBUGLOG -- write message to standard error 113764562Sgshapiro** 113864562Sgshapiro** Append a message to the standard error for the convenience of 113964562Sgshapiro** end-users debugging without access to the syslog messages. 114064562Sgshapiro** 114164562Sgshapiro** Parameters: 114264562Sgshapiro** i -- syslog log level 114364562Sgshapiro** fmt -- string format 114464562Sgshapiro** 114564562Sgshapiro** Returns: 114664562Sgshapiro** nothing. 114764562Sgshapiro*/ 114864562Sgshapiro 114964562Sgshapiro/*VARARGS2*/ 115090792Sgshapirostatic SYSLOG_RET_T 115164562Sgshapiro#ifdef __STDC__ 115264562Sgshapirodebuglog(int i, const char *fmt, ...) 115364562Sgshapiro#else /* __STDC__ */ 115464562Sgshapirodebuglog(i, fmt, va_alist) 115564562Sgshapiro int i; 115664562Sgshapiro const char *fmt; 115764562Sgshapiro va_dcl 115864562Sgshapiro#endif /* __STDC__ */ 115964562Sgshapiro 116064562Sgshapiro{ 116190792Sgshapiro SM_VA_LOCAL_DECL 116264562Sgshapiro 116390792Sgshapiro SM_VA_START(ap, fmt); 116490792Sgshapiro sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap); 116590792Sgshapiro SM_VA_END(ap); 116690792Sgshapiro SYSLOG_RET; 116764562Sgshapiro} 1168