vacation.c revision 110560
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 23110560SgshapiroSM_IDSTR(id, "@(#)$Id: vacation.c,v 8.137.2.2 2002/11/01 16:48:55 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#if _FFR_RESPOND_ALL 21598121Sgshapiro case 'j': 21698121Sgshapiro alwaysrespond = true; 21798121Sgshapiro break; 21898121Sgshapiro#endif /* _FFR_RESPOND_ALL */ 21998121Sgshapiro 22064562Sgshapiro case 'l': 22198121Sgshapiro list = true; /* list the database */ 22264562Sgshapiro break; 22364562Sgshapiro 22464562Sgshapiro case 'm': /* alternate message file */ 22564562Sgshapiro msgfilename = optarg; 22664562Sgshapiro break; 22764562Sgshapiro 22890792Sgshapiro#if _FFR_RETURN_ADDR 22990792Sgshapiro case 'R': 23090792Sgshapiro returnaddr = optarg; 23190792Sgshapiro break; 23290792Sgshapiro#endif /* _FFR_RETURN_ADDR */ 23390792Sgshapiro 23464562Sgshapiro case 'r': 23564562Sgshapiro if (isascii(*optarg) && isdigit(*optarg)) 23664562Sgshapiro { 23764562Sgshapiro interval = atol(optarg) * SECSPERDAY; 23864562Sgshapiro if (interval < 0) 23964562Sgshapiro ufail++; 24064562Sgshapiro } 24164562Sgshapiro else 24264562Sgshapiro interval = ONLY_ONCE; 24364562Sgshapiro break; 24464562Sgshapiro 24564562Sgshapiro case 's': /* alternate sender name */ 24690792Sgshapiro (void) sm_strlcpy(From, optarg, sizeof From); 24764562Sgshapiro break; 24864562Sgshapiro 24964562Sgshapiro case 't': /* SunOS: -t1d (default expire) */ 25064562Sgshapiro break; 25164562Sgshapiro 25277349Sgshapiro case 'U': /* run as single user mode */ 25390792Sgshapiro runasuser = true; 25477349Sgshapiro break; 25577349Sgshapiro 25664562Sgshapiro case 'x': 25790792Sgshapiro exclude = true; 25864562Sgshapiro break; 25964562Sgshapiro 26064562Sgshapiro case 'z': 26190792Sgshapiro returnaddr = "<>"; 26264562Sgshapiro break; 26364562Sgshapiro 26464562Sgshapiro case '?': 26564562Sgshapiro default: 26664562Sgshapiro ufail++; 26764562Sgshapiro break; 26864562Sgshapiro } 26964562Sgshapiro } 27064562Sgshapiro argc -= optind; 27164562Sgshapiro argv += optind; 27264562Sgshapiro 27364562Sgshapiro if (mfail != 0) 27464562Sgshapiro { 27564562Sgshapiro msglog(LOG_NOTICE, 27664562Sgshapiro "vacation: can't allocate memory for alias.\n"); 27766494Sgshapiro EXITM(EX_TEMPFAIL); 27864562Sgshapiro } 27964562Sgshapiro if (ufail != 0) 28064562Sgshapiro usage(); 28164562Sgshapiro 28264562Sgshapiro if (argc != 1) 28364562Sgshapiro { 28498121Sgshapiro if (!initdb && !list && !exclude) 28564562Sgshapiro usage(); 28664562Sgshapiro if ((pw = getpwuid(getuid())) == NULL) 28764562Sgshapiro { 28864562Sgshapiro msglog(LOG_ERR, 28964562Sgshapiro "vacation: no such user uid %u.\n", getuid()); 29066494Sgshapiro EXITM(EX_NOUSER); 29164562Sgshapiro } 29277349Sgshapiro name = pw->pw_name; 29377349Sgshapiro user_info.smdbu_id = pw->pw_uid; 29477349Sgshapiro user_info.smdbu_group_id = pw->pw_gid; 29590792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name, 29690792Sgshapiro SMDB_MAX_USER_NAME_LEN); 29777349Sgshapiro if (chdir(pw->pw_dir) != 0) 29877349Sgshapiro { 29990792Sgshapiro msglog(LOG_NOTICE, 30090792Sgshapiro "vacation: no such directory %s.\n", 30177349Sgshapiro pw->pw_dir); 30277349Sgshapiro EXITM(EX_NOINPUT); 30377349Sgshapiro } 30464562Sgshapiro } 30577349Sgshapiro else if (runasuser) 30677349Sgshapiro { 30777349Sgshapiro name = *argv; 30877349Sgshapiro if (dbfilename == NULL || msgfilename == NULL) 30977349Sgshapiro { 31077349Sgshapiro msglog(LOG_NOTICE, 31177349Sgshapiro "vacation: -U requires setting both -f and -m\n"); 31277349Sgshapiro EXITM(EX_NOINPUT); 31377349Sgshapiro } 31477349Sgshapiro user_info.smdbu_id = pw->pw_uid; 31577349Sgshapiro user_info.smdbu_group_id = pw->pw_gid; 31690792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name, 31777349Sgshapiro SMDB_MAX_USER_NAME_LEN); 31877349Sgshapiro } 31977349Sgshapiro else 32064562Sgshapiro { 32190792Sgshapiro int err; 32290792Sgshapiro SM_CF_OPT_T mbdbname; 32390792Sgshapiro SM_MBDB_T user; 32490792Sgshapiro 32594334Sgshapiro cfpath = getcfname(0, 0, SM_GET_SENDMAIL_CF, cfpath); 32690792Sgshapiro mbdbname.opt_name = "MailboxDatabase"; 32790792Sgshapiro mbdbname.opt_val = "pw"; 32890792Sgshapiro (void) sm_cf_getopt(cfpath, 1, &mbdbname); 32990792Sgshapiro err = sm_mbdb_initialize(mbdbname.opt_val); 33090792Sgshapiro if (err != EX_OK) 33177349Sgshapiro { 33290792Sgshapiro msglog(LOG_ERR, 33390792Sgshapiro "vacation: can't open mailbox database: %s.\n", 33490792Sgshapiro sm_strexit(err)); 33590792Sgshapiro EXITM(err); 33690792Sgshapiro } 33790792Sgshapiro err = sm_mbdb_lookup(*argv, &user); 33890792Sgshapiro if (err == EX_NOUSER) 33990792Sgshapiro { 34090792Sgshapiro msglog(LOG_ERR, "vacation: no such user %s.\n", *argv); 34190792Sgshapiro EXITM(EX_NOUSER); 34290792Sgshapiro } 34390792Sgshapiro if (err != EX_OK) 34490792Sgshapiro { 34590792Sgshapiro msglog(LOG_ERR, 34690792Sgshapiro "vacation: can't read mailbox database: %s.\n", 34790792Sgshapiro sm_strexit(err)); 34890792Sgshapiro EXITM(err); 34990792Sgshapiro } 35090792Sgshapiro name = user.mbdb_name; 35190792Sgshapiro if (chdir(user.mbdb_homedir) != 0) 35290792Sgshapiro { 35390792Sgshapiro msglog(LOG_NOTICE, 35490792Sgshapiro "vacation: no such directory %s.\n", 35590792Sgshapiro user.mbdb_homedir); 35677349Sgshapiro EXITM(EX_NOINPUT); 35777349Sgshapiro } 35890792Sgshapiro user_info.smdbu_id = user.mbdb_uid; 35990792Sgshapiro user_info.smdbu_group_id = user.mbdb_gid; 36090792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, user.mbdb_name, 36177349Sgshapiro SMDB_MAX_USER_NAME_LEN); 36264562Sgshapiro } 36364562Sgshapiro 36477349Sgshapiro if (dbfilename == NULL) 36577349Sgshapiro dbfilename = VDB; 36677349Sgshapiro if (msgfilename == NULL) 36777349Sgshapiro msgfilename = VMSG; 36877349Sgshapiro 36966494Sgshapiro sff = SFF_CREAT; 37066494Sgshapiro if (getegid() != getgid()) 37177349Sgshapiro { 37290792Sgshapiro /* Allow a set-group-ID vacation binary */ 37366494Sgshapiro RunAsGid = user_info.smdbu_group_id = getegid(); 37490792Sgshapiro sff |= SFF_OPENASROOT; 37577349Sgshapiro } 37694334Sgshapiro if (getuid() == 0) 37794334Sgshapiro { 37894334Sgshapiro /* Allow root to initialize user's vacation databases */ 37994334Sgshapiro sff |= SFF_OPENASROOT|SFF_ROOTOK; 38066494Sgshapiro 38194334Sgshapiro /* ... safely */ 38294334Sgshapiro sff |= SFF_NOSLINK|SFF_NOHLINK|SFF_REGONLY; 38394334Sgshapiro } 38494334Sgshapiro 38594334Sgshapiro 38664562Sgshapiro result = smdb_open_database(&Db, dbfilename, 38798121Sgshapiro O_CREAT|O_RDWR | (initdb ? O_TRUNC : 0), 38866494Sgshapiro S_IRUSR|S_IWUSR, sff, 38964562Sgshapiro SMDB_TYPE_DEFAULT, &user_info, NULL); 39064562Sgshapiro if (result != SMDBE_OK) 39164562Sgshapiro { 39264562Sgshapiro msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename, 39390792Sgshapiro sm_errstring(result)); 39466494Sgshapiro EXITM(EX_DATAERR); 39564562Sgshapiro } 39664562Sgshapiro 39798121Sgshapiro if (list) 39864562Sgshapiro { 39964562Sgshapiro listdb(); 40071345Sgshapiro (void) Db->smdb_close(Db); 40164562Sgshapiro exit(EX_OK); 40264562Sgshapiro } 40364562Sgshapiro 40464562Sgshapiro if (interval != INTERVAL_UNDEF) 40564562Sgshapiro setinterval(interval); 40664562Sgshapiro 40798121Sgshapiro if (initdb && !exclude) 40864562Sgshapiro { 40971345Sgshapiro (void) Db->smdb_close(Db); 41071345Sgshapiro exit(EX_OK); 41164562Sgshapiro } 41264562Sgshapiro 41364562Sgshapiro if (exclude) 41464562Sgshapiro { 41590792Sgshapiro xclude(smioin); 41671345Sgshapiro (void) Db->smdb_close(Db); 41766494Sgshapiro EXITM(EX_OK); 41864562Sgshapiro } 41964562Sgshapiro 42090792Sgshapiro if ((cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS))) == NULL) 42164562Sgshapiro { 42264562Sgshapiro msglog(LOG_NOTICE, 42364562Sgshapiro "vacation: can't allocate memory for username.\n"); 42471345Sgshapiro (void) Db->smdb_close(Db); 42566494Sgshapiro EXITM(EX_OSERR); 42664562Sgshapiro } 42764562Sgshapiro cur->name = name; 42864562Sgshapiro cur->next = Names; 42964562Sgshapiro Names = cur; 43064562Sgshapiro 43198121Sgshapiro result = readheaders(alwaysrespond); 43271345Sgshapiro if (result == EX_OK && !recent()) 43364562Sgshapiro { 43464562Sgshapiro time_t now; 43564562Sgshapiro 43664562Sgshapiro (void) time(&now); 43764562Sgshapiro setreply(From, now); 43871345Sgshapiro (void) Db->smdb_close(Db); 43990792Sgshapiro sendmessage(name, msgfilename, returnaddr); 44064562Sgshapiro } 44164562Sgshapiro else 44271345Sgshapiro (void) Db->smdb_close(Db); 44371345Sgshapiro if (result == EX_NOUSER) 44471345Sgshapiro result = EX_OK; 44571345Sgshapiro exit(result); 44664562Sgshapiro} 44764562Sgshapiro 44864562Sgshapiro/* 44966494Sgshapiro** EATMSG -- read stdin till EOF 45066494Sgshapiro** 45166494Sgshapiro** Parameters: 45266494Sgshapiro** none. 45366494Sgshapiro** 45466494Sgshapiro** Returns: 45566494Sgshapiro** nothing. 45666494Sgshapiro** 45766494Sgshapiro*/ 45877349Sgshapiro 45966494Sgshapirostatic void 46066494Sgshapiroeatmsg() 46166494Sgshapiro{ 46266494Sgshapiro /* 46366494Sgshapiro ** read the rest of the e-mail and ignore it to avoid problems 46466494Sgshapiro ** with EPIPE in sendmail 46566494Sgshapiro */ 46666494Sgshapiro while (getc(stdin) != EOF) 46766494Sgshapiro continue; 46866494Sgshapiro} 46966494Sgshapiro 47066494Sgshapiro/* 47164562Sgshapiro** READHEADERS -- read mail headers 47264562Sgshapiro** 47364562Sgshapiro** Parameters: 47498121Sgshapiro** alwaysrespond -- respond regardless of whether msg is to me 47564562Sgshapiro** 47664562Sgshapiro** Returns: 47771345Sgshapiro** a exit code: NOUSER if no reply, OK if reply, * if error 47864562Sgshapiro** 47966494Sgshapiro** Side Effects: 48066494Sgshapiro** may exit(). 48166494Sgshapiro** 48264562Sgshapiro*/ 48371345Sgshapiro 48471345Sgshapiroint 48598121Sgshapiroreadheaders(alwaysrespond) 48698121Sgshapiro bool alwaysrespond; 48764562Sgshapiro{ 48864562Sgshapiro bool tome, cont; 48964562Sgshapiro register char *p; 49064562Sgshapiro register ALIAS *cur; 49164562Sgshapiro char buf[MAXLINE]; 49264562Sgshapiro extern bool junkmail __P((char *)); 49364562Sgshapiro extern bool nsearch __P((char *, char *)); 49464562Sgshapiro 49598121Sgshapiro cont = false; 49698121Sgshapiro tome = alwaysrespond; 49790792Sgshapiro while (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, sizeof(buf)) && 49890792Sgshapiro *buf != '\n') 49964562Sgshapiro { 50064562Sgshapiro switch(*buf) 50164562Sgshapiro { 50264562Sgshapiro case 'F': /* "From " */ 50390792Sgshapiro cont = false; 50464562Sgshapiro if (strncmp(buf, "From ", 5) == 0) 50564562Sgshapiro { 50690792Sgshapiro bool quoted = false; 50764562Sgshapiro 50864562Sgshapiro p = buf + 5; 50964562Sgshapiro while (*p != '\0') 51064562Sgshapiro { 51164562Sgshapiro /* escaped character */ 51264562Sgshapiro if (*p == '\\') 51364562Sgshapiro { 51464562Sgshapiro p++; 51564562Sgshapiro if (*p == '\0') 51664562Sgshapiro { 51764562Sgshapiro msglog(LOG_NOTICE, 51864562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 51966494Sgshapiro EXITIT(EX_DATAERR); 52064562Sgshapiro } 52164562Sgshapiro } 52264562Sgshapiro else if (*p == '"') 52364562Sgshapiro quoted = !quoted; 52464562Sgshapiro else if (*p == '\r' || *p == '\n') 52564562Sgshapiro break; 52664562Sgshapiro else if (*p == ' ' && !quoted) 52764562Sgshapiro break; 52864562Sgshapiro p++; 52964562Sgshapiro } 53064562Sgshapiro if (quoted) 53164562Sgshapiro { 53264562Sgshapiro msglog(LOG_NOTICE, 53364562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 53466494Sgshapiro EXITIT(EX_DATAERR); 53564562Sgshapiro } 53664562Sgshapiro *p = '\0'; 53764562Sgshapiro 53864562Sgshapiro /* ok since both strings have MAXLINE length */ 53964562Sgshapiro if (*From == '\0') 54090792Sgshapiro (void) sm_strlcpy(From, buf + 5, 54190792Sgshapiro sizeof From); 54264562Sgshapiro if ((p = strchr(buf + 5, '\n')) != NULL) 54364562Sgshapiro *p = '\0'; 54464562Sgshapiro if (junkmail(buf + 5)) 54571345Sgshapiro EXITIT(EX_NOUSER); 54664562Sgshapiro } 54764562Sgshapiro break; 54864562Sgshapiro 54964562Sgshapiro case 'P': /* "Precedence:" */ 55064562Sgshapiro case 'p': 55190792Sgshapiro cont = false; 55264562Sgshapiro if (strlen(buf) <= 10 || 55364562Sgshapiro strncasecmp(buf, "Precedence", 10) != 0 || 55464562Sgshapiro (buf[10] != ':' && buf[10] != ' ' && 55564562Sgshapiro buf[10] != '\t')) 55664562Sgshapiro break; 55764562Sgshapiro if ((p = strchr(buf, ':')) == NULL) 55864562Sgshapiro break; 55964562Sgshapiro while (*++p != '\0' && isascii(*p) && isspace(*p)); 56064562Sgshapiro if (*p == '\0') 56164562Sgshapiro break; 56264562Sgshapiro if (strncasecmp(p, "junk", 4) == 0 || 56364562Sgshapiro strncasecmp(p, "bulk", 4) == 0 || 56464562Sgshapiro strncasecmp(p, "list", 4) == 0) 56571345Sgshapiro EXITIT(EX_NOUSER); 56664562Sgshapiro break; 56764562Sgshapiro 56864562Sgshapiro case 'C': /* "Cc:" */ 56964562Sgshapiro case 'c': 57064562Sgshapiro if (strncasecmp(buf, "Cc:", 3) != 0) 57164562Sgshapiro break; 57290792Sgshapiro cont = true; 57364562Sgshapiro goto findme; 57464562Sgshapiro 57564562Sgshapiro case 'T': /* "To:" */ 57664562Sgshapiro case 't': 57764562Sgshapiro if (strncasecmp(buf, "To:", 3) != 0) 57864562Sgshapiro break; 57990792Sgshapiro cont = true; 58064562Sgshapiro goto findme; 58164562Sgshapiro 58264562Sgshapiro default: 58364562Sgshapiro if (!isascii(*buf) || !isspace(*buf) || !cont || tome) 58464562Sgshapiro { 58590792Sgshapiro cont = false; 58664562Sgshapiro break; 58764562Sgshapiro } 58864562Sgshapirofindme: 58964562Sgshapiro for (cur = Names; 59064562Sgshapiro !tome && cur != NULL; 59164562Sgshapiro cur = cur->next) 59264562Sgshapiro tome = nsearch(cur->name, buf); 59364562Sgshapiro } 59464562Sgshapiro } 59564562Sgshapiro if (!tome) 59671345Sgshapiro EXITIT(EX_NOUSER); 59764562Sgshapiro if (*From == '\0') 59864562Sgshapiro { 59964562Sgshapiro msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n"); 60066494Sgshapiro EXITIT(EX_DATAERR); 60164562Sgshapiro } 60271345Sgshapiro EXITIT(EX_OK); 60364562Sgshapiro} 60464562Sgshapiro 60564562Sgshapiro/* 60664562Sgshapiro** NSEARCH -- 60764562Sgshapiro** do a nice, slow, search of a string for a substring. 60864562Sgshapiro** 60964562Sgshapiro** Parameters: 61064562Sgshapiro** name -- name to search. 61164562Sgshapiro** str -- string in which to search. 61264562Sgshapiro** 61364562Sgshapiro** Returns: 61464562Sgshapiro** is name a substring of str? 61564562Sgshapiro** 61664562Sgshapiro*/ 61777349Sgshapiro 61864562Sgshapirobool 61964562Sgshapironsearch(name, str) 62064562Sgshapiro register char *name, *str; 62164562Sgshapiro{ 62264562Sgshapiro register size_t len; 62364562Sgshapiro register char *s; 62464562Sgshapiro 62564562Sgshapiro len = strlen(name); 62664562Sgshapiro 62764562Sgshapiro for (s = str; *s != '\0'; ++s) 62864562Sgshapiro { 62964562Sgshapiro /* 63064562Sgshapiro ** Check to make sure that the string matches and 63164562Sgshapiro ** the previous character is not an alphanumeric and 63264562Sgshapiro ** the next character after the match is not an alphanumeric. 63364562Sgshapiro ** 63464562Sgshapiro ** This prevents matching "eric" to "derick" while still 63564562Sgshapiro ** matching "eric" to "<eric+detail>". 63664562Sgshapiro */ 63764562Sgshapiro 63864562Sgshapiro if (tolower(*s) == tolower(*name) && 63964562Sgshapiro strncasecmp(name, s, len) == 0 && 64064562Sgshapiro (s == str || !isascii(*(s - 1)) || !isalnum(*(s - 1))) && 64164562Sgshapiro (!isascii(*(s + len)) || !isalnum(*(s + len)))) 64290792Sgshapiro return true; 64364562Sgshapiro } 64490792Sgshapiro return false; 64564562Sgshapiro} 64664562Sgshapiro 64764562Sgshapiro/* 64864562Sgshapiro** JUNKMAIL -- 64964562Sgshapiro** read the header and return if automagic/junk/bulk/list mail 65064562Sgshapiro** 65164562Sgshapiro** Parameters: 65264562Sgshapiro** from -- sender address. 65364562Sgshapiro** 65464562Sgshapiro** Returns: 65564562Sgshapiro** is this some automated/junk/bulk/list mail? 65664562Sgshapiro** 65764562Sgshapiro*/ 65871345Sgshapiro 65971345Sgshapirostruct ignore 66071345Sgshapiro{ 66171345Sgshapiro char *name; 66271345Sgshapiro size_t len; 66371345Sgshapiro}; 66471345Sgshapiro 66571345Sgshapirotypedef struct ignore IGNORE_T; 66671345Sgshapiro 66771345Sgshapiro#define MAX_USER_LEN 256 /* maximum length of local part (sender) */ 66871345Sgshapiro 66971345Sgshapiro/* delimiters for the local part of an address */ 67071345Sgshapiro#define isdelim(c) ((c) == '%' || (c) == '@' || (c) == '+') 67171345Sgshapiro 67264562Sgshapirobool 67364562Sgshapirojunkmail(from) 67464562Sgshapiro char *from; 67564562Sgshapiro{ 67671345Sgshapiro bool quot; 67771345Sgshapiro char *e; 67871345Sgshapiro size_t len; 67971345Sgshapiro IGNORE_T *cur; 68071345Sgshapiro char sender[MAX_USER_LEN]; 68171345Sgshapiro static IGNORE_T ignore[] = 68264562Sgshapiro { 68364562Sgshapiro { "postmaster", 10 }, 68464562Sgshapiro { "uucp", 4 }, 68564562Sgshapiro { "mailer-daemon", 13 }, 68664562Sgshapiro { "mailer", 6 }, 68771345Sgshapiro { NULL, 0 } 68871345Sgshapiro }; 68971345Sgshapiro 69071345Sgshapiro static IGNORE_T ignorepost[] = 69171345Sgshapiro { 69271345Sgshapiro { "-request", 8 }, 69364562Sgshapiro { "-relay", 6 }, 69471345Sgshapiro { "-owner", 6 }, 69564562Sgshapiro { NULL, 0 } 69664562Sgshapiro }; 69764562Sgshapiro 69871345Sgshapiro static IGNORE_T ignorepre[] = 69971345Sgshapiro { 70071345Sgshapiro { "owner-", 6 }, 70171345Sgshapiro { NULL, 0 } 70271345Sgshapiro }; 70371345Sgshapiro 70464562Sgshapiro /* 70571345Sgshapiro ** This is mildly amusing, and I'm not positive it's right; trying 70671345Sgshapiro ** to find the "real" name of the sender, assuming that addresses 70771345Sgshapiro ** will be some variant of: 70871345Sgshapiro ** 70971345Sgshapiro ** From site!site!SENDER%site.domain%site.domain@site.domain 71071345Sgshapiro */ 71171345Sgshapiro 71290792Sgshapiro quot = false; 71371345Sgshapiro e = from; 71471345Sgshapiro len = 0; 71571345Sgshapiro while (*e != '\0' && (quot || !isdelim(*e))) 71664562Sgshapiro { 71771345Sgshapiro if (*e == '"') 71871345Sgshapiro { 71971345Sgshapiro quot = !quot; 72071345Sgshapiro ++e; 72171345Sgshapiro continue; 72271345Sgshapiro } 72371345Sgshapiro if (*e == '\\') 72471345Sgshapiro { 72571345Sgshapiro if (*(++e) == '\0') 72671345Sgshapiro { 72771345Sgshapiro /* '\\' at end of string? */ 72871345Sgshapiro break; 72971345Sgshapiro } 73071345Sgshapiro if (len < MAX_USER_LEN) 73171345Sgshapiro sender[len++] = *e; 73271345Sgshapiro ++e; 73371345Sgshapiro continue; 73471345Sgshapiro } 73571345Sgshapiro if (*e == '!' && !quot) 73671345Sgshapiro { 73771345Sgshapiro len = 0; 73871345Sgshapiro sender[len] = '\0'; 73971345Sgshapiro } 74064562Sgshapiro else 74171345Sgshapiro if (len < MAX_USER_LEN) 74271345Sgshapiro sender[len++] = *e; 74371345Sgshapiro ++e; 74464562Sgshapiro } 74571345Sgshapiro if (len < MAX_USER_LEN) 74671345Sgshapiro sender[len] = '\0'; 74771345Sgshapiro else 74871345Sgshapiro sender[MAX_USER_LEN - 1] = '\0'; 74971345Sgshapiro 75071345Sgshapiro if (len <= 0) 75190792Sgshapiro return false; 75271345Sgshapiro#if 0 75371345Sgshapiro if (quot) 75490792Sgshapiro return false; /* syntax error... */ 75571345Sgshapiro#endif /* 0 */ 75671345Sgshapiro 75771345Sgshapiro /* test prefixes */ 75871345Sgshapiro for (cur = ignorepre; cur->name != NULL; ++cur) 75971345Sgshapiro { 76071345Sgshapiro if (len >= cur->len && 76171345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 76290792Sgshapiro return true; 76371345Sgshapiro } 76471345Sgshapiro 76571345Sgshapiro /* 76671345Sgshapiro ** If the name is truncated, don't test the rest. 76771345Sgshapiro ** We could extract the "tail" of the sender address and 76871345Sgshapiro ** compare it it ignorepost, however, it seems not worth 76971345Sgshapiro ** the effort. 77071345Sgshapiro ** The address surely can't match any entry in ignore[] 77171345Sgshapiro ** (as long as all of them are shorter than MAX_USER_LEN). 77271345Sgshapiro */ 77371345Sgshapiro 77471345Sgshapiro if (len > MAX_USER_LEN) 77590792Sgshapiro return false; 77671345Sgshapiro 77771345Sgshapiro /* test full local parts */ 77864562Sgshapiro for (cur = ignore; cur->name != NULL; ++cur) 77964562Sgshapiro { 78071345Sgshapiro if (len == cur->len && 78171345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 78290792Sgshapiro return true; 78371345Sgshapiro } 78471345Sgshapiro 78571345Sgshapiro /* test postfixes */ 78671345Sgshapiro for (cur = ignorepost; cur->name != NULL; ++cur) 78771345Sgshapiro { 78864562Sgshapiro if (len >= cur->len && 78971345Sgshapiro strncasecmp(cur->name, e - cur->len - 1, 79071345Sgshapiro cur->len) == 0) 79190792Sgshapiro return true; 79264562Sgshapiro } 79390792Sgshapiro return false; 79464562Sgshapiro} 79564562Sgshapiro 79664562Sgshapiro#define VIT "__VACATION__INTERVAL__TIMER__" 79764562Sgshapiro 79864562Sgshapiro/* 79964562Sgshapiro** RECENT -- 80064562Sgshapiro** find out if user has gotten a vacation message recently. 80164562Sgshapiro** 80264562Sgshapiro** Parameters: 80364562Sgshapiro** none. 80464562Sgshapiro** 80564562Sgshapiro** Returns: 80690792Sgshapiro** true iff user has gotten a vacation message recently. 80764562Sgshapiro** 80864562Sgshapiro*/ 80977349Sgshapiro 81064562Sgshapirobool 81164562Sgshapirorecent() 81264562Sgshapiro{ 81364562Sgshapiro SMDB_DBENT key, data; 81464562Sgshapiro time_t then, next; 81590792Sgshapiro bool trydomain = false; 81664562Sgshapiro int st; 81764562Sgshapiro char *domain; 81864562Sgshapiro 81964562Sgshapiro memset(&key, '\0', sizeof key); 82064562Sgshapiro memset(&data, '\0', sizeof data); 82164562Sgshapiro 82264562Sgshapiro /* get interval time */ 82371345Sgshapiro key.data = VIT; 82471345Sgshapiro key.size = sizeof(VIT); 82564562Sgshapiro 82664562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 82764562Sgshapiro if (st != SMDBE_OK) 82864562Sgshapiro next = SECSPERDAY * DAYSPERWEEK; 82964562Sgshapiro else 83071345Sgshapiro memmove(&next, data.data, sizeof(next)); 83164562Sgshapiro 83264562Sgshapiro memset(&data, '\0', sizeof data); 83364562Sgshapiro 83464562Sgshapiro /* get record for this address */ 83571345Sgshapiro key.data = From; 83671345Sgshapiro key.size = strlen(From); 83764562Sgshapiro 83864562Sgshapiro do 83964562Sgshapiro { 84064562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 84164562Sgshapiro if (st == SMDBE_OK) 84264562Sgshapiro { 84371345Sgshapiro memmove(&then, data.data, sizeof(then)); 84464562Sgshapiro if (next == ONLY_ONCE || then == ONLY_ONCE || 84564562Sgshapiro then + next > time(NULL)) 84690792Sgshapiro return true; 84764562Sgshapiro } 84864562Sgshapiro if ((trydomain = !trydomain) && 84964562Sgshapiro (domain = strchr(From, '@')) != NULL) 85064562Sgshapiro { 85171345Sgshapiro key.data = domain; 85271345Sgshapiro key.size = strlen(domain); 85364562Sgshapiro } 85464562Sgshapiro } while (trydomain); 85590792Sgshapiro return false; 85664562Sgshapiro} 85764562Sgshapiro 85864562Sgshapiro/* 85964562Sgshapiro** SETINTERVAL -- 86064562Sgshapiro** store the reply interval 86164562Sgshapiro** 86264562Sgshapiro** Parameters: 86364562Sgshapiro** interval -- time interval for replies. 86464562Sgshapiro** 86564562Sgshapiro** Returns: 86664562Sgshapiro** nothing. 86764562Sgshapiro** 86864562Sgshapiro** Side Effects: 86964562Sgshapiro** stores the reply interval in database. 87064562Sgshapiro*/ 87177349Sgshapiro 87264562Sgshapirovoid 87364562Sgshapirosetinterval(interval) 87464562Sgshapiro time_t interval; 87564562Sgshapiro{ 87664562Sgshapiro SMDB_DBENT key, data; 87764562Sgshapiro 87864562Sgshapiro memset(&key, '\0', sizeof key); 87964562Sgshapiro memset(&data, '\0', sizeof data); 88064562Sgshapiro 88171345Sgshapiro key.data = VIT; 88271345Sgshapiro key.size = sizeof(VIT); 88371345Sgshapiro data.data = (char*) &interval; 88471345Sgshapiro data.size = sizeof(interval); 88571345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 88664562Sgshapiro} 88764562Sgshapiro 88864562Sgshapiro/* 88964562Sgshapiro** SETREPLY -- 89064562Sgshapiro** store that this user knows about the vacation. 89164562Sgshapiro** 89264562Sgshapiro** Parameters: 89364562Sgshapiro** from -- sender address. 89464562Sgshapiro** when -- last reply time. 89564562Sgshapiro** 89664562Sgshapiro** Returns: 89764562Sgshapiro** nothing. 89864562Sgshapiro** 89964562Sgshapiro** Side Effects: 90064562Sgshapiro** stores user/time in database. 90164562Sgshapiro*/ 90277349Sgshapiro 90364562Sgshapirovoid 90464562Sgshapirosetreply(from, when) 90564562Sgshapiro char *from; 90664562Sgshapiro time_t when; 90764562Sgshapiro{ 90864562Sgshapiro SMDB_DBENT key, data; 90964562Sgshapiro 91064562Sgshapiro memset(&key, '\0', sizeof key); 91164562Sgshapiro memset(&data, '\0', sizeof data); 91264562Sgshapiro 91371345Sgshapiro key.data = from; 91471345Sgshapiro key.size = strlen(from); 91571345Sgshapiro data.data = (char*) &when; 91671345Sgshapiro data.size = sizeof(when); 91771345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 91864562Sgshapiro} 91964562Sgshapiro 92064562Sgshapiro/* 92164562Sgshapiro** XCLUDE -- 92264562Sgshapiro** add users to vacation db so they don't get a reply. 92364562Sgshapiro** 92464562Sgshapiro** Parameters: 92564562Sgshapiro** f -- file pointer with list of address to exclude 92664562Sgshapiro** 92764562Sgshapiro** Returns: 92864562Sgshapiro** nothing. 92964562Sgshapiro** 93064562Sgshapiro** Side Effects: 93164562Sgshapiro** stores users in database. 93264562Sgshapiro*/ 93377349Sgshapiro 93464562Sgshapirovoid 93564562Sgshapiroxclude(f) 93690792Sgshapiro SM_FILE_T *f; 93764562Sgshapiro{ 93864562Sgshapiro char buf[MAXLINE], *p; 93964562Sgshapiro 94064562Sgshapiro if (f == NULL) 94164562Sgshapiro return; 94290792Sgshapiro while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf)) 94364562Sgshapiro { 94464562Sgshapiro if ((p = strchr(buf, '\n')) != NULL) 94564562Sgshapiro *p = '\0'; 94664562Sgshapiro setreply(buf, ONLY_ONCE); 94764562Sgshapiro } 94864562Sgshapiro} 94964562Sgshapiro 95064562Sgshapiro/* 95164562Sgshapiro** SENDMESSAGE -- 95264562Sgshapiro** exec sendmail to send the vacation file to sender 95364562Sgshapiro** 95464562Sgshapiro** Parameters: 95564562Sgshapiro** myname -- user name. 95664562Sgshapiro** msgfn -- name of file with vacation message. 95790792Sgshapiro** sender -- use as sender address 95864562Sgshapiro** 95964562Sgshapiro** Returns: 96064562Sgshapiro** nothing. 96164562Sgshapiro** 96264562Sgshapiro** Side Effects: 96364562Sgshapiro** sends vacation reply. 96464562Sgshapiro*/ 96577349Sgshapiro 96664562Sgshapirovoid 96790792Sgshapirosendmessage(myname, msgfn, sender) 96864562Sgshapiro char *myname; 96964562Sgshapiro char *msgfn; 97090792Sgshapiro char *sender; 97164562Sgshapiro{ 97290792Sgshapiro SM_FILE_T *mfp, *sfp; 97364562Sgshapiro int i; 97464562Sgshapiro int pvect[2]; 97577349Sgshapiro char *pv[8]; 97664562Sgshapiro char buf[MAXLINE]; 97764562Sgshapiro 97890792Sgshapiro mfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, msgfn, SM_IO_RDONLY, NULL); 97964562Sgshapiro if (mfp == NULL) 98064562Sgshapiro { 98164562Sgshapiro if (msgfn[0] == '/') 98264562Sgshapiro msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn); 98364562Sgshapiro else 98464562Sgshapiro msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", 98564562Sgshapiro myname, msgfn); 98664562Sgshapiro exit(EX_NOINPUT); 98764562Sgshapiro } 98864562Sgshapiro if (pipe(pvect) < 0) 98964562Sgshapiro { 99090792Sgshapiro msglog(LOG_ERR, "vacation: pipe: %s", sm_errstring(errno)); 99164562Sgshapiro exit(EX_OSERR); 99264562Sgshapiro } 99377349Sgshapiro pv[0] = "sendmail"; 99477349Sgshapiro pv[1] = "-oi"; 99577349Sgshapiro pv[2] = "-f"; 99690792Sgshapiro if (sender != NULL) 99790792Sgshapiro pv[3] = sender; 99877349Sgshapiro else 99977349Sgshapiro pv[3] = myname; 100077349Sgshapiro pv[4] = "--"; 100177349Sgshapiro pv[5] = From; 100277349Sgshapiro pv[6] = NULL; 100364562Sgshapiro i = fork(); 100464562Sgshapiro if (i < 0) 100564562Sgshapiro { 100690792Sgshapiro msglog(LOG_ERR, "vacation: fork: %s", sm_errstring(errno)); 100764562Sgshapiro exit(EX_OSERR); 100864562Sgshapiro } 100964562Sgshapiro if (i == 0) 101064562Sgshapiro { 101164562Sgshapiro (void) dup2(pvect[0], 0); 101264562Sgshapiro (void) close(pvect[0]); 101364562Sgshapiro (void) close(pvect[1]); 101490792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 101577349Sgshapiro (void) execv(_PATH_SENDMAIL, pv); 101664562Sgshapiro msglog(LOG_ERR, "vacation: can't exec %s: %s", 101790792Sgshapiro _PATH_SENDMAIL, sm_errstring(errno)); 101864562Sgshapiro exit(EX_UNAVAILABLE); 101964562Sgshapiro } 102064562Sgshapiro /* check return status of the following calls? XXX */ 102164562Sgshapiro (void) close(pvect[0]); 102290792Sgshapiro if ((sfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 102390792Sgshapiro (void *) &(pvect[1]), 102490792Sgshapiro SM_IO_WRONLY, NULL)) != NULL) 102564562Sgshapiro { 102690792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, "To: %s\n", From); 102790792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, 102890792Sgshapiro "Auto-Submitted: auto-replied\n"); 102990792Sgshapiro while (sm_io_fgets(mfp, SM_TIME_DEFAULT, buf, sizeof buf)) 103090792Sgshapiro (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf); 103190792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 103290792Sgshapiro (void) sm_io_close(sfp, SM_TIME_DEFAULT); 103364562Sgshapiro } 103464562Sgshapiro else 103564562Sgshapiro { 103690792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 103764562Sgshapiro msglog(LOG_ERR, "vacation: can't open pipe to sendmail"); 103864562Sgshapiro exit(EX_UNAVAILABLE); 103964562Sgshapiro } 104064562Sgshapiro} 104164562Sgshapiro 104264562Sgshapirovoid 104364562Sgshapirousage() 104464562Sgshapiro{ 104598121Sgshapiro char *retusage = ""; 104698121Sgshapiro char *respusage = ""; 104790792Sgshapiro 104890792Sgshapiro#if _FFR_RETURN_ADDR 104990792Sgshapiro retusage = "[-R returnaddr] "; 105090792Sgshapiro#endif /* _FFR_RETURN_ADDR */ 105190792Sgshapiro 105298121Sgshapiro#if _FFR_RESPOND_ALL 105398121Sgshapiro respusage = "[-j] "; 105498121Sgshapiro#endif /* _FFR_RESPOND_ALL */ 105598121Sgshapiro 105677349Sgshapiro msglog(LOG_NOTICE, 105798121Sgshapiro "uid %u: usage: vacation [-a alias] [-C cfpath] [-d] [-f db] [-i] %s[-l] [-m msg] %s[-r interval] [-s sender] [-t time] [-U] [-x] [-z] login\n", 105898121Sgshapiro getuid(), respusage, retusage); 105964562Sgshapiro exit(EX_USAGE); 106064562Sgshapiro} 106164562Sgshapiro 106264562Sgshapiro/* 106364562Sgshapiro** LISTDB -- list the contents of the vacation database 106464562Sgshapiro** 106564562Sgshapiro** Parameters: 106664562Sgshapiro** none. 106764562Sgshapiro** 106864562Sgshapiro** Returns: 106964562Sgshapiro** nothing. 107064562Sgshapiro*/ 107164562Sgshapiro 107264562Sgshapirostatic void 107364562Sgshapirolistdb() 107464562Sgshapiro{ 107564562Sgshapiro int result; 107664562Sgshapiro time_t t; 107764562Sgshapiro SMDB_CURSOR *cursor = NULL; 107864562Sgshapiro SMDB_DBENT db_key, db_value; 107964562Sgshapiro 108064562Sgshapiro memset(&db_key, '\0', sizeof db_key); 108164562Sgshapiro memset(&db_value, '\0', sizeof db_value); 108264562Sgshapiro 108364562Sgshapiro result = Db->smdb_cursor(Db, &cursor, 0); 108464562Sgshapiro if (result != SMDBE_OK) 108564562Sgshapiro { 108690792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 108790792Sgshapiro "vacation: set cursor: %s\n", 108890792Sgshapiro sm_errstring(result)); 108964562Sgshapiro return; 109064562Sgshapiro } 109164562Sgshapiro 109264562Sgshapiro while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, 109364562Sgshapiro SMDB_CURSOR_GET_NEXT)) == SMDBE_OK) 109464562Sgshapiro { 109598121Sgshapiro char *timestamp; 109698121Sgshapiro 109764562Sgshapiro /* skip magic VIT entry */ 1098110560Sgshapiro if (db_key.size == strlen(VIT) + 1 && 109971345Sgshapiro strncmp((char *)db_key.data, VIT, 110071345Sgshapiro (int)db_key.size - 1) == 0) 110164562Sgshapiro continue; 110264562Sgshapiro 110364562Sgshapiro /* skip bogus values */ 110471345Sgshapiro if (db_value.size != sizeof t) 110564562Sgshapiro { 110690792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 110790792Sgshapiro "vacation: %.*s invalid time stamp\n", 110890792Sgshapiro (int) db_key.size, (char *) db_key.data); 110964562Sgshapiro continue; 111064562Sgshapiro } 111164562Sgshapiro 111271345Sgshapiro memcpy(&t, db_value.data, sizeof t); 111364562Sgshapiro 111471345Sgshapiro if (db_key.size > 40) 111571345Sgshapiro db_key.size = 40; 111664562Sgshapiro 111798121Sgshapiro if (t <= 0) 111898121Sgshapiro { 111998121Sgshapiro /* must be an exclude */ 112098121Sgshapiro timestamp = "(exclusion)\n"; 112198121Sgshapiro } 112298121Sgshapiro else 112398121Sgshapiro { 112498121Sgshapiro timestamp = ctime(&t); 112598121Sgshapiro } 112690792Sgshapiro sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%-40.*s %-10s", 112790792Sgshapiro (int) db_key.size, (char *) db_key.data, 112898121Sgshapiro timestamp); 112964562Sgshapiro 113064562Sgshapiro memset(&db_key, '\0', sizeof db_key); 113164562Sgshapiro memset(&db_value, '\0', sizeof db_value); 113264562Sgshapiro } 113364562Sgshapiro 113464562Sgshapiro if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) 113564562Sgshapiro { 113690792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 113790792Sgshapiro "vacation: get value at cursor: %s\n", 113890792Sgshapiro sm_errstring(result)); 113964562Sgshapiro if (cursor != NULL) 114064562Sgshapiro { 114164562Sgshapiro (void) cursor->smdbc_close(cursor); 114264562Sgshapiro cursor = NULL; 114364562Sgshapiro } 114464562Sgshapiro return; 114564562Sgshapiro } 114664562Sgshapiro (void) cursor->smdbc_close(cursor); 114764562Sgshapiro cursor = NULL; 114864562Sgshapiro} 114964562Sgshapiro 115064562Sgshapiro/* 115164562Sgshapiro** DEBUGLOG -- write message to standard error 115264562Sgshapiro** 115364562Sgshapiro** Append a message to the standard error for the convenience of 115464562Sgshapiro** end-users debugging without access to the syslog messages. 115564562Sgshapiro** 115664562Sgshapiro** Parameters: 115764562Sgshapiro** i -- syslog log level 115864562Sgshapiro** fmt -- string format 115964562Sgshapiro** 116064562Sgshapiro** Returns: 116164562Sgshapiro** nothing. 116264562Sgshapiro*/ 116364562Sgshapiro 116464562Sgshapiro/*VARARGS2*/ 116590792Sgshapirostatic SYSLOG_RET_T 116664562Sgshapiro#ifdef __STDC__ 116764562Sgshapirodebuglog(int i, const char *fmt, ...) 116864562Sgshapiro#else /* __STDC__ */ 116964562Sgshapirodebuglog(i, fmt, va_alist) 117064562Sgshapiro int i; 117164562Sgshapiro const char *fmt; 117264562Sgshapiro va_dcl 117364562Sgshapiro#endif /* __STDC__ */ 117464562Sgshapiro 117564562Sgshapiro{ 117690792Sgshapiro SM_VA_LOCAL_DECL 117764562Sgshapiro 117890792Sgshapiro SM_VA_START(ap, fmt); 117990792Sgshapiro sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap); 118090792Sgshapiro SM_VA_END(ap); 118190792Sgshapiro SYSLOG_RET; 118264562Sgshapiro} 1183