vacation.c revision 90792
164562Sgshapiro/* 277349Sgshapiro * Copyright (c) 1999-2001 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 2390792SgshapiroSM_IDSTR(id, "@(#)$Id: vacation.c,v 8.131 2001/12/12 00:02:42 gshapiro 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{ \ 11190792Sgshapiro if (!iflag && !lflag) \ 11290792Sgshapiro eatmsg(); \ 11390792Sgshapiro exit(excode); \ 11490792Sgshapiro} 11590792Sgshapiro 11664562Sgshapiroint 11764562Sgshapiromain(argc, argv) 11864562Sgshapiro int argc; 11964562Sgshapiro char **argv; 12064562Sgshapiro{ 12190792Sgshapiro bool iflag, exclude; 12290792Sgshapiro bool runasuser = false; 12390792Sgshapiro bool lflag = false; 12464562Sgshapiro int mfail = 0, ufail = 0; 12564562Sgshapiro int ch; 12664562Sgshapiro int result; 12766494Sgshapiro long sff; 12864562Sgshapiro time_t interval; 12964562Sgshapiro struct passwd *pw; 13064562Sgshapiro ALIAS *cur; 13177349Sgshapiro char *dbfilename = NULL; 13277349Sgshapiro char *msgfilename = NULL; 13390792Sgshapiro char *cfpath = NULL; 13464562Sgshapiro char *name; 13590792Sgshapiro char *returnaddr = NULL; 13664562Sgshapiro SMDB_USER_INFO user_info; 13764562Sgshapiro static char rnamebuf[MAXNAME]; 13864562Sgshapiro extern int optind, opterr; 13964562Sgshapiro extern char *optarg; 14064562Sgshapiro extern void usage __P((void)); 14164562Sgshapiro extern void setinterval __P((time_t)); 14271345Sgshapiro extern int readheaders __P((void)); 14364562Sgshapiro extern bool recent __P((void)); 14464562Sgshapiro extern void setreply __P((char *, time_t)); 14590792Sgshapiro extern void sendmessage __P((char *, char *, char *)); 14690792Sgshapiro extern void xclude __P((SM_FILE_T *)); 14764562Sgshapiro 14864562Sgshapiro /* Vars needed to link with smutil */ 14964562Sgshapiro clrbitmap(DontBlameSendmail); 15064562Sgshapiro RunAsUid = RealUid = getuid(); 15164562Sgshapiro RunAsGid = RealGid = getgid(); 15264562Sgshapiro pw = getpwuid(RealUid); 15364562Sgshapiro if (pw != NULL) 15464562Sgshapiro { 15564562Sgshapiro if (strlen(pw->pw_name) > MAXNAME - 1) 15664562Sgshapiro pw->pw_name[MAXNAME] = '\0'; 15790792Sgshapiro sm_snprintf(rnamebuf, sizeof rnamebuf, "%s", pw->pw_name); 15864562Sgshapiro } 15964562Sgshapiro else 16090792Sgshapiro sm_snprintf(rnamebuf, sizeof rnamebuf, 16190792Sgshapiro "Unknown UID %d", (int) RealUid); 16264562Sgshapiro RunAsUserName = RealUserName = rnamebuf; 16364562Sgshapiro 16477349Sgshapiro# ifdef LOG_MAIL 16564562Sgshapiro openlog("vacation", LOG_PID, LOG_MAIL); 16677349Sgshapiro# else /* LOG_MAIL */ 16764562Sgshapiro openlog("vacation", LOG_PID); 16877349Sgshapiro# endif /* LOG_MAIL */ 16964562Sgshapiro 17064562Sgshapiro opterr = 0; 17190792Sgshapiro iflag = false; 17290792Sgshapiro exclude = false; 17364562Sgshapiro interval = INTERVAL_UNDEF; 17464562Sgshapiro *From = '\0'; 17564562Sgshapiro 17664562Sgshapiro 17790792Sgshapiro#if _FFR_RETURN_ADDR 17890792Sgshapiro# define OPTIONS "a:C:df:Iilm:R:r:s:t:Uxz" 17990792Sgshapiro#else /* _FFR_RETURN_ADDR */ 18090792Sgshapiro# define OPTIONS "a:C:df:Iilm:r:s:t:Uxz" 18190792Sgshapiro#endif /* _FFR_RETURN_ADDR */ 18290792Sgshapiro 18364562Sgshapiro while (mfail == 0 && ufail == 0 && 18464562Sgshapiro (ch = getopt(argc, argv, OPTIONS)) != -1) 18564562Sgshapiro { 18664562Sgshapiro switch((char)ch) 18764562Sgshapiro { 18864562Sgshapiro case 'a': /* alias */ 18990792Sgshapiro cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS)); 19064562Sgshapiro if (cur == NULL) 19164562Sgshapiro { 19264562Sgshapiro mfail++; 19364562Sgshapiro break; 19464562Sgshapiro } 19564562Sgshapiro cur->name = optarg; 19664562Sgshapiro cur->next = Names; 19764562Sgshapiro Names = cur; 19864562Sgshapiro break; 19964562Sgshapiro 20090792Sgshapiro case 'C': 20190792Sgshapiro cfpath = optarg; 20290792Sgshapiro break; 20390792Sgshapiro 20477349Sgshapiro case 'd': /* debug mode */ 20590792Sgshapiro msglog = debuglog; 20664562Sgshapiro break; 20764562Sgshapiro 20864562Sgshapiro case 'f': /* alternate database */ 20964562Sgshapiro dbfilename = optarg; 21064562Sgshapiro break; 21164562Sgshapiro 21264562Sgshapiro case 'I': /* backward compatible */ 21364562Sgshapiro case 'i': /* init the database */ 21490792Sgshapiro iflag = true; 21564562Sgshapiro break; 21664562Sgshapiro 21764562Sgshapiro case 'l': 21890792Sgshapiro lflag = true; /* list the database */ 21964562Sgshapiro break; 22064562Sgshapiro 22164562Sgshapiro case 'm': /* alternate message file */ 22264562Sgshapiro msgfilename = optarg; 22364562Sgshapiro break; 22464562Sgshapiro 22590792Sgshapiro#if _FFR_RETURN_ADDR 22690792Sgshapiro case 'R': 22790792Sgshapiro returnaddr = optarg; 22890792Sgshapiro break; 22990792Sgshapiro#endif /* _FFR_RETURN_ADDR */ 23090792Sgshapiro 23164562Sgshapiro case 'r': 23264562Sgshapiro if (isascii(*optarg) && isdigit(*optarg)) 23364562Sgshapiro { 23464562Sgshapiro interval = atol(optarg) * SECSPERDAY; 23564562Sgshapiro if (interval < 0) 23664562Sgshapiro ufail++; 23764562Sgshapiro } 23864562Sgshapiro else 23964562Sgshapiro interval = ONLY_ONCE; 24064562Sgshapiro break; 24164562Sgshapiro 24264562Sgshapiro case 's': /* alternate sender name */ 24390792Sgshapiro (void) sm_strlcpy(From, optarg, sizeof From); 24464562Sgshapiro break; 24564562Sgshapiro 24664562Sgshapiro case 't': /* SunOS: -t1d (default expire) */ 24764562Sgshapiro break; 24864562Sgshapiro 24977349Sgshapiro case 'U': /* run as single user mode */ 25090792Sgshapiro runasuser = true; 25177349Sgshapiro break; 25277349Sgshapiro 25364562Sgshapiro case 'x': 25490792Sgshapiro exclude = true; 25564562Sgshapiro break; 25664562Sgshapiro 25764562Sgshapiro case 'z': 25890792Sgshapiro returnaddr = "<>"; 25964562Sgshapiro break; 26064562Sgshapiro 26164562Sgshapiro case '?': 26264562Sgshapiro default: 26364562Sgshapiro ufail++; 26464562Sgshapiro break; 26564562Sgshapiro } 26664562Sgshapiro } 26764562Sgshapiro argc -= optind; 26864562Sgshapiro argv += optind; 26964562Sgshapiro 27064562Sgshapiro if (mfail != 0) 27164562Sgshapiro { 27264562Sgshapiro msglog(LOG_NOTICE, 27364562Sgshapiro "vacation: can't allocate memory for alias.\n"); 27466494Sgshapiro EXITM(EX_TEMPFAIL); 27564562Sgshapiro } 27664562Sgshapiro if (ufail != 0) 27764562Sgshapiro usage(); 27864562Sgshapiro 27964562Sgshapiro if (argc != 1) 28064562Sgshapiro { 28190792Sgshapiro if (!iflag && !lflag && !exclude) 28264562Sgshapiro usage(); 28364562Sgshapiro if ((pw = getpwuid(getuid())) == NULL) 28464562Sgshapiro { 28564562Sgshapiro msglog(LOG_ERR, 28664562Sgshapiro "vacation: no such user uid %u.\n", getuid()); 28766494Sgshapiro EXITM(EX_NOUSER); 28864562Sgshapiro } 28977349Sgshapiro name = pw->pw_name; 29077349Sgshapiro user_info.smdbu_id = pw->pw_uid; 29177349Sgshapiro user_info.smdbu_group_id = pw->pw_gid; 29290792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name, 29390792Sgshapiro SMDB_MAX_USER_NAME_LEN); 29477349Sgshapiro if (chdir(pw->pw_dir) != 0) 29577349Sgshapiro { 29690792Sgshapiro msglog(LOG_NOTICE, 29790792Sgshapiro "vacation: no such directory %s.\n", 29877349Sgshapiro pw->pw_dir); 29977349Sgshapiro EXITM(EX_NOINPUT); 30077349Sgshapiro } 30164562Sgshapiro } 30277349Sgshapiro else if (runasuser) 30377349Sgshapiro { 30477349Sgshapiro name = *argv; 30577349Sgshapiro if (dbfilename == NULL || msgfilename == NULL) 30677349Sgshapiro { 30777349Sgshapiro msglog(LOG_NOTICE, 30877349Sgshapiro "vacation: -U requires setting both -f and -m\n"); 30977349Sgshapiro EXITM(EX_NOINPUT); 31077349Sgshapiro } 31177349Sgshapiro user_info.smdbu_id = pw->pw_uid; 31277349Sgshapiro user_info.smdbu_group_id = pw->pw_gid; 31390792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, pw->pw_name, 31477349Sgshapiro SMDB_MAX_USER_NAME_LEN); 31577349Sgshapiro } 31677349Sgshapiro else 31764562Sgshapiro { 31890792Sgshapiro int err; 31990792Sgshapiro SM_CF_OPT_T mbdbname; 32090792Sgshapiro SM_MBDB_T user; 32190792Sgshapiro 32290792Sgshapiro cfpath = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL); 32390792Sgshapiro mbdbname.opt_name = "MailboxDatabase"; 32490792Sgshapiro mbdbname.opt_val = "pw"; 32590792Sgshapiro (void) sm_cf_getopt(cfpath, 1, &mbdbname); 32690792Sgshapiro err = sm_mbdb_initialize(mbdbname.opt_val); 32790792Sgshapiro if (err != EX_OK) 32877349Sgshapiro { 32990792Sgshapiro msglog(LOG_ERR, 33090792Sgshapiro "vacation: can't open mailbox database: %s.\n", 33190792Sgshapiro sm_strexit(err)); 33290792Sgshapiro EXITM(err); 33390792Sgshapiro } 33490792Sgshapiro err = sm_mbdb_lookup(*argv, &user); 33590792Sgshapiro if (err == EX_NOUSER) 33690792Sgshapiro { 33790792Sgshapiro msglog(LOG_ERR, "vacation: no such user %s.\n", *argv); 33890792Sgshapiro EXITM(EX_NOUSER); 33990792Sgshapiro } 34090792Sgshapiro if (err != EX_OK) 34190792Sgshapiro { 34290792Sgshapiro msglog(LOG_ERR, 34390792Sgshapiro "vacation: can't read mailbox database: %s.\n", 34490792Sgshapiro sm_strexit(err)); 34590792Sgshapiro EXITM(err); 34690792Sgshapiro } 34790792Sgshapiro name = user.mbdb_name; 34890792Sgshapiro if (chdir(user.mbdb_homedir) != 0) 34990792Sgshapiro { 35090792Sgshapiro msglog(LOG_NOTICE, 35190792Sgshapiro "vacation: no such directory %s.\n", 35290792Sgshapiro user.mbdb_homedir); 35377349Sgshapiro EXITM(EX_NOINPUT); 35477349Sgshapiro } 35590792Sgshapiro user_info.smdbu_id = user.mbdb_uid; 35690792Sgshapiro user_info.smdbu_group_id = user.mbdb_gid; 35790792Sgshapiro (void) sm_strlcpy(user_info.smdbu_name, user.mbdb_name, 35877349Sgshapiro SMDB_MAX_USER_NAME_LEN); 35964562Sgshapiro } 36064562Sgshapiro 36177349Sgshapiro if (dbfilename == NULL) 36277349Sgshapiro dbfilename = VDB; 36377349Sgshapiro if (msgfilename == NULL) 36477349Sgshapiro msgfilename = VMSG; 36577349Sgshapiro 36666494Sgshapiro sff = SFF_CREAT; 36766494Sgshapiro if (getegid() != getgid()) 36877349Sgshapiro { 36990792Sgshapiro /* Allow a set-group-ID vacation binary */ 37066494Sgshapiro RunAsGid = user_info.smdbu_group_id = getegid(); 37190792Sgshapiro sff |= SFF_OPENASROOT; 37277349Sgshapiro } 37366494Sgshapiro 37464562Sgshapiro result = smdb_open_database(&Db, dbfilename, 37564562Sgshapiro O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0), 37666494Sgshapiro S_IRUSR|S_IWUSR, sff, 37764562Sgshapiro SMDB_TYPE_DEFAULT, &user_info, NULL); 37864562Sgshapiro if (result != SMDBE_OK) 37964562Sgshapiro { 38064562Sgshapiro msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename, 38190792Sgshapiro sm_errstring(result)); 38266494Sgshapiro EXITM(EX_DATAERR); 38364562Sgshapiro } 38464562Sgshapiro 38564562Sgshapiro if (lflag) 38664562Sgshapiro { 38764562Sgshapiro listdb(); 38871345Sgshapiro (void) Db->smdb_close(Db); 38964562Sgshapiro exit(EX_OK); 39064562Sgshapiro } 39164562Sgshapiro 39264562Sgshapiro if (interval != INTERVAL_UNDEF) 39364562Sgshapiro setinterval(interval); 39464562Sgshapiro 39571345Sgshapiro if (iflag && !exclude) 39664562Sgshapiro { 39771345Sgshapiro (void) Db->smdb_close(Db); 39871345Sgshapiro exit(EX_OK); 39964562Sgshapiro } 40064562Sgshapiro 40164562Sgshapiro if (exclude) 40264562Sgshapiro { 40390792Sgshapiro xclude(smioin); 40471345Sgshapiro (void) Db->smdb_close(Db); 40566494Sgshapiro EXITM(EX_OK); 40664562Sgshapiro } 40764562Sgshapiro 40890792Sgshapiro if ((cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS))) == NULL) 40964562Sgshapiro { 41064562Sgshapiro msglog(LOG_NOTICE, 41164562Sgshapiro "vacation: can't allocate memory for username.\n"); 41271345Sgshapiro (void) Db->smdb_close(Db); 41366494Sgshapiro EXITM(EX_OSERR); 41464562Sgshapiro } 41564562Sgshapiro cur->name = name; 41664562Sgshapiro cur->next = Names; 41764562Sgshapiro Names = cur; 41864562Sgshapiro 41971345Sgshapiro result = readheaders(); 42071345Sgshapiro if (result == EX_OK && !recent()) 42164562Sgshapiro { 42264562Sgshapiro time_t now; 42364562Sgshapiro 42464562Sgshapiro (void) time(&now); 42564562Sgshapiro setreply(From, now); 42671345Sgshapiro (void) Db->smdb_close(Db); 42790792Sgshapiro sendmessage(name, msgfilename, returnaddr); 42864562Sgshapiro } 42964562Sgshapiro else 43071345Sgshapiro (void) Db->smdb_close(Db); 43171345Sgshapiro if (result == EX_NOUSER) 43271345Sgshapiro result = EX_OK; 43371345Sgshapiro exit(result); 43464562Sgshapiro} 43564562Sgshapiro 43664562Sgshapiro/* 43766494Sgshapiro** EATMSG -- read stdin till EOF 43866494Sgshapiro** 43966494Sgshapiro** Parameters: 44066494Sgshapiro** none. 44166494Sgshapiro** 44266494Sgshapiro** Returns: 44366494Sgshapiro** nothing. 44466494Sgshapiro** 44566494Sgshapiro*/ 44677349Sgshapiro 44766494Sgshapirostatic void 44866494Sgshapiroeatmsg() 44966494Sgshapiro{ 45066494Sgshapiro /* 45166494Sgshapiro ** read the rest of the e-mail and ignore it to avoid problems 45266494Sgshapiro ** with EPIPE in sendmail 45366494Sgshapiro */ 45466494Sgshapiro while (getc(stdin) != EOF) 45566494Sgshapiro continue; 45666494Sgshapiro} 45766494Sgshapiro 45866494Sgshapiro/* 45964562Sgshapiro** READHEADERS -- read mail headers 46064562Sgshapiro** 46164562Sgshapiro** Parameters: 46264562Sgshapiro** none. 46364562Sgshapiro** 46464562Sgshapiro** Returns: 46571345Sgshapiro** a exit code: NOUSER if no reply, OK if reply, * if error 46664562Sgshapiro** 46766494Sgshapiro** Side Effects: 46866494Sgshapiro** may exit(). 46966494Sgshapiro** 47064562Sgshapiro*/ 47171345Sgshapiro 47271345Sgshapiroint 47364562Sgshapiroreadheaders() 47464562Sgshapiro{ 47564562Sgshapiro bool tome, cont; 47664562Sgshapiro register char *p; 47764562Sgshapiro register ALIAS *cur; 47864562Sgshapiro char buf[MAXLINE]; 47964562Sgshapiro extern bool junkmail __P((char *)); 48064562Sgshapiro extern bool nsearch __P((char *, char *)); 48164562Sgshapiro 48290792Sgshapiro cont = tome = false; 48390792Sgshapiro while (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, sizeof(buf)) && 48490792Sgshapiro *buf != '\n') 48564562Sgshapiro { 48664562Sgshapiro switch(*buf) 48764562Sgshapiro { 48864562Sgshapiro case 'F': /* "From " */ 48990792Sgshapiro cont = false; 49064562Sgshapiro if (strncmp(buf, "From ", 5) == 0) 49164562Sgshapiro { 49290792Sgshapiro bool quoted = false; 49364562Sgshapiro 49464562Sgshapiro p = buf + 5; 49564562Sgshapiro while (*p != '\0') 49664562Sgshapiro { 49764562Sgshapiro /* escaped character */ 49864562Sgshapiro if (*p == '\\') 49964562Sgshapiro { 50064562Sgshapiro p++; 50164562Sgshapiro if (*p == '\0') 50264562Sgshapiro { 50364562Sgshapiro msglog(LOG_NOTICE, 50464562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 50566494Sgshapiro EXITIT(EX_DATAERR); 50664562Sgshapiro } 50764562Sgshapiro } 50864562Sgshapiro else if (*p == '"') 50964562Sgshapiro quoted = !quoted; 51064562Sgshapiro else if (*p == '\r' || *p == '\n') 51164562Sgshapiro break; 51264562Sgshapiro else if (*p == ' ' && !quoted) 51364562Sgshapiro break; 51464562Sgshapiro p++; 51564562Sgshapiro } 51664562Sgshapiro if (quoted) 51764562Sgshapiro { 51864562Sgshapiro msglog(LOG_NOTICE, 51964562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 52066494Sgshapiro EXITIT(EX_DATAERR); 52164562Sgshapiro } 52264562Sgshapiro *p = '\0'; 52364562Sgshapiro 52464562Sgshapiro /* ok since both strings have MAXLINE length */ 52564562Sgshapiro if (*From == '\0') 52690792Sgshapiro (void) sm_strlcpy(From, buf + 5, 52790792Sgshapiro sizeof From); 52864562Sgshapiro if ((p = strchr(buf + 5, '\n')) != NULL) 52964562Sgshapiro *p = '\0'; 53064562Sgshapiro if (junkmail(buf + 5)) 53171345Sgshapiro EXITIT(EX_NOUSER); 53264562Sgshapiro } 53364562Sgshapiro break; 53464562Sgshapiro 53564562Sgshapiro case 'P': /* "Precedence:" */ 53664562Sgshapiro case 'p': 53790792Sgshapiro cont = false; 53864562Sgshapiro if (strlen(buf) <= 10 || 53964562Sgshapiro strncasecmp(buf, "Precedence", 10) != 0 || 54064562Sgshapiro (buf[10] != ':' && buf[10] != ' ' && 54164562Sgshapiro buf[10] != '\t')) 54264562Sgshapiro break; 54364562Sgshapiro if ((p = strchr(buf, ':')) == NULL) 54464562Sgshapiro break; 54564562Sgshapiro while (*++p != '\0' && isascii(*p) && isspace(*p)); 54664562Sgshapiro if (*p == '\0') 54764562Sgshapiro break; 54864562Sgshapiro if (strncasecmp(p, "junk", 4) == 0 || 54964562Sgshapiro strncasecmp(p, "bulk", 4) == 0 || 55064562Sgshapiro strncasecmp(p, "list", 4) == 0) 55171345Sgshapiro EXITIT(EX_NOUSER); 55264562Sgshapiro break; 55364562Sgshapiro 55464562Sgshapiro case 'C': /* "Cc:" */ 55564562Sgshapiro case 'c': 55664562Sgshapiro if (strncasecmp(buf, "Cc:", 3) != 0) 55764562Sgshapiro break; 55890792Sgshapiro cont = true; 55964562Sgshapiro goto findme; 56064562Sgshapiro 56164562Sgshapiro case 'T': /* "To:" */ 56264562Sgshapiro case 't': 56364562Sgshapiro if (strncasecmp(buf, "To:", 3) != 0) 56464562Sgshapiro break; 56590792Sgshapiro cont = true; 56664562Sgshapiro goto findme; 56764562Sgshapiro 56864562Sgshapiro default: 56964562Sgshapiro if (!isascii(*buf) || !isspace(*buf) || !cont || tome) 57064562Sgshapiro { 57190792Sgshapiro cont = false; 57264562Sgshapiro break; 57364562Sgshapiro } 57464562Sgshapirofindme: 57564562Sgshapiro for (cur = Names; 57664562Sgshapiro !tome && cur != NULL; 57764562Sgshapiro cur = cur->next) 57864562Sgshapiro tome = nsearch(cur->name, buf); 57964562Sgshapiro } 58064562Sgshapiro } 58164562Sgshapiro if (!tome) 58271345Sgshapiro EXITIT(EX_NOUSER); 58364562Sgshapiro if (*From == '\0') 58464562Sgshapiro { 58564562Sgshapiro msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n"); 58666494Sgshapiro EXITIT(EX_DATAERR); 58764562Sgshapiro } 58871345Sgshapiro EXITIT(EX_OK); 58964562Sgshapiro} 59064562Sgshapiro 59164562Sgshapiro/* 59264562Sgshapiro** NSEARCH -- 59364562Sgshapiro** do a nice, slow, search of a string for a substring. 59464562Sgshapiro** 59564562Sgshapiro** Parameters: 59664562Sgshapiro** name -- name to search. 59764562Sgshapiro** str -- string in which to search. 59864562Sgshapiro** 59964562Sgshapiro** Returns: 60064562Sgshapiro** is name a substring of str? 60164562Sgshapiro** 60264562Sgshapiro*/ 60377349Sgshapiro 60464562Sgshapirobool 60564562Sgshapironsearch(name, str) 60664562Sgshapiro register char *name, *str; 60764562Sgshapiro{ 60864562Sgshapiro register size_t len; 60964562Sgshapiro register char *s; 61064562Sgshapiro 61164562Sgshapiro len = strlen(name); 61264562Sgshapiro 61364562Sgshapiro for (s = str; *s != '\0'; ++s) 61464562Sgshapiro { 61564562Sgshapiro /* 61664562Sgshapiro ** Check to make sure that the string matches and 61764562Sgshapiro ** the previous character is not an alphanumeric and 61864562Sgshapiro ** the next character after the match is not an alphanumeric. 61964562Sgshapiro ** 62064562Sgshapiro ** This prevents matching "eric" to "derick" while still 62164562Sgshapiro ** matching "eric" to "<eric+detail>". 62264562Sgshapiro */ 62364562Sgshapiro 62464562Sgshapiro if (tolower(*s) == tolower(*name) && 62564562Sgshapiro strncasecmp(name, s, len) == 0 && 62664562Sgshapiro (s == str || !isascii(*(s - 1)) || !isalnum(*(s - 1))) && 62764562Sgshapiro (!isascii(*(s + len)) || !isalnum(*(s + len)))) 62890792Sgshapiro return true; 62964562Sgshapiro } 63090792Sgshapiro return false; 63164562Sgshapiro} 63264562Sgshapiro 63364562Sgshapiro/* 63464562Sgshapiro** JUNKMAIL -- 63564562Sgshapiro** read the header and return if automagic/junk/bulk/list mail 63664562Sgshapiro** 63764562Sgshapiro** Parameters: 63864562Sgshapiro** from -- sender address. 63964562Sgshapiro** 64064562Sgshapiro** Returns: 64164562Sgshapiro** is this some automated/junk/bulk/list mail? 64264562Sgshapiro** 64364562Sgshapiro*/ 64471345Sgshapiro 64571345Sgshapirostruct ignore 64671345Sgshapiro{ 64771345Sgshapiro char *name; 64871345Sgshapiro size_t len; 64971345Sgshapiro}; 65071345Sgshapiro 65171345Sgshapirotypedef struct ignore IGNORE_T; 65271345Sgshapiro 65371345Sgshapiro#define MAX_USER_LEN 256 /* maximum length of local part (sender) */ 65471345Sgshapiro 65571345Sgshapiro/* delimiters for the local part of an address */ 65671345Sgshapiro#define isdelim(c) ((c) == '%' || (c) == '@' || (c) == '+') 65771345Sgshapiro 65864562Sgshapirobool 65964562Sgshapirojunkmail(from) 66064562Sgshapiro char *from; 66164562Sgshapiro{ 66271345Sgshapiro bool quot; 66371345Sgshapiro char *e; 66471345Sgshapiro size_t len; 66571345Sgshapiro IGNORE_T *cur; 66671345Sgshapiro char sender[MAX_USER_LEN]; 66771345Sgshapiro static IGNORE_T ignore[] = 66864562Sgshapiro { 66964562Sgshapiro { "postmaster", 10 }, 67064562Sgshapiro { "uucp", 4 }, 67164562Sgshapiro { "mailer-daemon", 13 }, 67264562Sgshapiro { "mailer", 6 }, 67371345Sgshapiro { NULL, 0 } 67471345Sgshapiro }; 67571345Sgshapiro 67671345Sgshapiro static IGNORE_T ignorepost[] = 67771345Sgshapiro { 67871345Sgshapiro { "-request", 8 }, 67964562Sgshapiro { "-relay", 6 }, 68071345Sgshapiro { "-owner", 6 }, 68164562Sgshapiro { NULL, 0 } 68264562Sgshapiro }; 68364562Sgshapiro 68471345Sgshapiro static IGNORE_T ignorepre[] = 68571345Sgshapiro { 68671345Sgshapiro { "owner-", 6 }, 68771345Sgshapiro { NULL, 0 } 68871345Sgshapiro }; 68971345Sgshapiro 69064562Sgshapiro /* 69171345Sgshapiro ** This is mildly amusing, and I'm not positive it's right; trying 69271345Sgshapiro ** to find the "real" name of the sender, assuming that addresses 69371345Sgshapiro ** will be some variant of: 69471345Sgshapiro ** 69571345Sgshapiro ** From site!site!SENDER%site.domain%site.domain@site.domain 69671345Sgshapiro */ 69771345Sgshapiro 69890792Sgshapiro quot = false; 69971345Sgshapiro e = from; 70071345Sgshapiro len = 0; 70171345Sgshapiro while (*e != '\0' && (quot || !isdelim(*e))) 70264562Sgshapiro { 70371345Sgshapiro if (*e == '"') 70471345Sgshapiro { 70571345Sgshapiro quot = !quot; 70671345Sgshapiro ++e; 70771345Sgshapiro continue; 70871345Sgshapiro } 70971345Sgshapiro if (*e == '\\') 71071345Sgshapiro { 71171345Sgshapiro if (*(++e) == '\0') 71271345Sgshapiro { 71371345Sgshapiro /* '\\' at end of string? */ 71471345Sgshapiro break; 71571345Sgshapiro } 71671345Sgshapiro if (len < MAX_USER_LEN) 71771345Sgshapiro sender[len++] = *e; 71871345Sgshapiro ++e; 71971345Sgshapiro continue; 72071345Sgshapiro } 72171345Sgshapiro if (*e == '!' && !quot) 72271345Sgshapiro { 72371345Sgshapiro len = 0; 72471345Sgshapiro sender[len] = '\0'; 72571345Sgshapiro } 72664562Sgshapiro else 72771345Sgshapiro if (len < MAX_USER_LEN) 72871345Sgshapiro sender[len++] = *e; 72971345Sgshapiro ++e; 73064562Sgshapiro } 73171345Sgshapiro if (len < MAX_USER_LEN) 73271345Sgshapiro sender[len] = '\0'; 73371345Sgshapiro else 73471345Sgshapiro sender[MAX_USER_LEN - 1] = '\0'; 73571345Sgshapiro 73671345Sgshapiro if (len <= 0) 73790792Sgshapiro return false; 73871345Sgshapiro#if 0 73971345Sgshapiro if (quot) 74090792Sgshapiro return false; /* syntax error... */ 74171345Sgshapiro#endif /* 0 */ 74271345Sgshapiro 74371345Sgshapiro /* test prefixes */ 74471345Sgshapiro for (cur = ignorepre; cur->name != NULL; ++cur) 74571345Sgshapiro { 74671345Sgshapiro if (len >= cur->len && 74771345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 74890792Sgshapiro return true; 74971345Sgshapiro } 75071345Sgshapiro 75171345Sgshapiro /* 75271345Sgshapiro ** If the name is truncated, don't test the rest. 75371345Sgshapiro ** We could extract the "tail" of the sender address and 75471345Sgshapiro ** compare it it ignorepost, however, it seems not worth 75571345Sgshapiro ** the effort. 75671345Sgshapiro ** The address surely can't match any entry in ignore[] 75771345Sgshapiro ** (as long as all of them are shorter than MAX_USER_LEN). 75871345Sgshapiro */ 75971345Sgshapiro 76071345Sgshapiro if (len > MAX_USER_LEN) 76190792Sgshapiro return false; 76271345Sgshapiro 76371345Sgshapiro /* test full local parts */ 76464562Sgshapiro for (cur = ignore; cur->name != NULL; ++cur) 76564562Sgshapiro { 76671345Sgshapiro if (len == cur->len && 76771345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 76890792Sgshapiro return true; 76971345Sgshapiro } 77071345Sgshapiro 77171345Sgshapiro /* test postfixes */ 77271345Sgshapiro for (cur = ignorepost; cur->name != NULL; ++cur) 77371345Sgshapiro { 77464562Sgshapiro if (len >= cur->len && 77571345Sgshapiro strncasecmp(cur->name, e - cur->len - 1, 77671345Sgshapiro cur->len) == 0) 77790792Sgshapiro return true; 77864562Sgshapiro } 77990792Sgshapiro return false; 78064562Sgshapiro} 78164562Sgshapiro 78264562Sgshapiro#define VIT "__VACATION__INTERVAL__TIMER__" 78364562Sgshapiro 78464562Sgshapiro/* 78564562Sgshapiro** RECENT -- 78664562Sgshapiro** find out if user has gotten a vacation message recently. 78764562Sgshapiro** 78864562Sgshapiro** Parameters: 78964562Sgshapiro** none. 79064562Sgshapiro** 79164562Sgshapiro** Returns: 79290792Sgshapiro** true iff user has gotten a vacation message recently. 79364562Sgshapiro** 79464562Sgshapiro*/ 79577349Sgshapiro 79664562Sgshapirobool 79764562Sgshapirorecent() 79864562Sgshapiro{ 79964562Sgshapiro SMDB_DBENT key, data; 80064562Sgshapiro time_t then, next; 80190792Sgshapiro bool trydomain = false; 80264562Sgshapiro int st; 80364562Sgshapiro char *domain; 80464562Sgshapiro 80564562Sgshapiro memset(&key, '\0', sizeof key); 80664562Sgshapiro memset(&data, '\0', sizeof data); 80764562Sgshapiro 80864562Sgshapiro /* get interval time */ 80971345Sgshapiro key.data = VIT; 81071345Sgshapiro key.size = sizeof(VIT); 81164562Sgshapiro 81264562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 81364562Sgshapiro if (st != SMDBE_OK) 81464562Sgshapiro next = SECSPERDAY * DAYSPERWEEK; 81564562Sgshapiro else 81671345Sgshapiro memmove(&next, data.data, sizeof(next)); 81764562Sgshapiro 81864562Sgshapiro memset(&data, '\0', sizeof data); 81964562Sgshapiro 82064562Sgshapiro /* get record for this address */ 82171345Sgshapiro key.data = From; 82271345Sgshapiro key.size = strlen(From); 82364562Sgshapiro 82464562Sgshapiro do 82564562Sgshapiro { 82664562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 82764562Sgshapiro if (st == SMDBE_OK) 82864562Sgshapiro { 82971345Sgshapiro memmove(&then, data.data, sizeof(then)); 83064562Sgshapiro if (next == ONLY_ONCE || then == ONLY_ONCE || 83164562Sgshapiro then + next > time(NULL)) 83290792Sgshapiro return true; 83364562Sgshapiro } 83464562Sgshapiro if ((trydomain = !trydomain) && 83564562Sgshapiro (domain = strchr(From, '@')) != NULL) 83664562Sgshapiro { 83771345Sgshapiro key.data = domain; 83871345Sgshapiro key.size = strlen(domain); 83964562Sgshapiro } 84064562Sgshapiro } while (trydomain); 84190792Sgshapiro return false; 84264562Sgshapiro} 84364562Sgshapiro 84464562Sgshapiro/* 84564562Sgshapiro** SETINTERVAL -- 84664562Sgshapiro** store the reply interval 84764562Sgshapiro** 84864562Sgshapiro** Parameters: 84964562Sgshapiro** interval -- time interval for replies. 85064562Sgshapiro** 85164562Sgshapiro** Returns: 85264562Sgshapiro** nothing. 85364562Sgshapiro** 85464562Sgshapiro** Side Effects: 85564562Sgshapiro** stores the reply interval in database. 85664562Sgshapiro*/ 85777349Sgshapiro 85864562Sgshapirovoid 85964562Sgshapirosetinterval(interval) 86064562Sgshapiro time_t interval; 86164562Sgshapiro{ 86264562Sgshapiro SMDB_DBENT key, data; 86364562Sgshapiro 86464562Sgshapiro memset(&key, '\0', sizeof key); 86564562Sgshapiro memset(&data, '\0', sizeof data); 86664562Sgshapiro 86771345Sgshapiro key.data = VIT; 86871345Sgshapiro key.size = sizeof(VIT); 86971345Sgshapiro data.data = (char*) &interval; 87071345Sgshapiro data.size = sizeof(interval); 87171345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 87264562Sgshapiro} 87364562Sgshapiro 87464562Sgshapiro/* 87564562Sgshapiro** SETREPLY -- 87664562Sgshapiro** store that this user knows about the vacation. 87764562Sgshapiro** 87864562Sgshapiro** Parameters: 87964562Sgshapiro** from -- sender address. 88064562Sgshapiro** when -- last reply time. 88164562Sgshapiro** 88264562Sgshapiro** Returns: 88364562Sgshapiro** nothing. 88464562Sgshapiro** 88564562Sgshapiro** Side Effects: 88664562Sgshapiro** stores user/time in database. 88764562Sgshapiro*/ 88877349Sgshapiro 88964562Sgshapirovoid 89064562Sgshapirosetreply(from, when) 89164562Sgshapiro char *from; 89264562Sgshapiro time_t when; 89364562Sgshapiro{ 89464562Sgshapiro SMDB_DBENT key, data; 89564562Sgshapiro 89664562Sgshapiro memset(&key, '\0', sizeof key); 89764562Sgshapiro memset(&data, '\0', sizeof data); 89864562Sgshapiro 89971345Sgshapiro key.data = from; 90071345Sgshapiro key.size = strlen(from); 90171345Sgshapiro data.data = (char*) &when; 90271345Sgshapiro data.size = sizeof(when); 90371345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 90464562Sgshapiro} 90564562Sgshapiro 90664562Sgshapiro/* 90764562Sgshapiro** XCLUDE -- 90864562Sgshapiro** add users to vacation db so they don't get a reply. 90964562Sgshapiro** 91064562Sgshapiro** Parameters: 91164562Sgshapiro** f -- file pointer with list of address to exclude 91264562Sgshapiro** 91364562Sgshapiro** Returns: 91464562Sgshapiro** nothing. 91564562Sgshapiro** 91664562Sgshapiro** Side Effects: 91764562Sgshapiro** stores users in database. 91864562Sgshapiro*/ 91977349Sgshapiro 92064562Sgshapirovoid 92164562Sgshapiroxclude(f) 92290792Sgshapiro SM_FILE_T *f; 92364562Sgshapiro{ 92464562Sgshapiro char buf[MAXLINE], *p; 92564562Sgshapiro 92664562Sgshapiro if (f == NULL) 92764562Sgshapiro return; 92890792Sgshapiro while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf)) 92964562Sgshapiro { 93064562Sgshapiro if ((p = strchr(buf, '\n')) != NULL) 93164562Sgshapiro *p = '\0'; 93264562Sgshapiro setreply(buf, ONLY_ONCE); 93364562Sgshapiro } 93464562Sgshapiro} 93564562Sgshapiro 93664562Sgshapiro/* 93764562Sgshapiro** SENDMESSAGE -- 93864562Sgshapiro** exec sendmail to send the vacation file to sender 93964562Sgshapiro** 94064562Sgshapiro** Parameters: 94164562Sgshapiro** myname -- user name. 94264562Sgshapiro** msgfn -- name of file with vacation message. 94390792Sgshapiro** sender -- use as sender address 94464562Sgshapiro** 94564562Sgshapiro** Returns: 94664562Sgshapiro** nothing. 94764562Sgshapiro** 94864562Sgshapiro** Side Effects: 94964562Sgshapiro** sends vacation reply. 95064562Sgshapiro*/ 95177349Sgshapiro 95264562Sgshapirovoid 95390792Sgshapirosendmessage(myname, msgfn, sender) 95464562Sgshapiro char *myname; 95564562Sgshapiro char *msgfn; 95690792Sgshapiro char *sender; 95764562Sgshapiro{ 95890792Sgshapiro SM_FILE_T *mfp, *sfp; 95964562Sgshapiro int i; 96064562Sgshapiro int pvect[2]; 96177349Sgshapiro char *pv[8]; 96264562Sgshapiro char buf[MAXLINE]; 96364562Sgshapiro 96490792Sgshapiro mfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, msgfn, SM_IO_RDONLY, NULL); 96564562Sgshapiro if (mfp == NULL) 96664562Sgshapiro { 96764562Sgshapiro if (msgfn[0] == '/') 96864562Sgshapiro msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn); 96964562Sgshapiro else 97064562Sgshapiro msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", 97164562Sgshapiro myname, msgfn); 97264562Sgshapiro exit(EX_NOINPUT); 97364562Sgshapiro } 97464562Sgshapiro if (pipe(pvect) < 0) 97564562Sgshapiro { 97690792Sgshapiro msglog(LOG_ERR, "vacation: pipe: %s", sm_errstring(errno)); 97764562Sgshapiro exit(EX_OSERR); 97864562Sgshapiro } 97977349Sgshapiro pv[0] = "sendmail"; 98077349Sgshapiro pv[1] = "-oi"; 98177349Sgshapiro pv[2] = "-f"; 98290792Sgshapiro if (sender != NULL) 98390792Sgshapiro pv[3] = sender; 98477349Sgshapiro else 98577349Sgshapiro pv[3] = myname; 98677349Sgshapiro pv[4] = "--"; 98777349Sgshapiro pv[5] = From; 98877349Sgshapiro pv[6] = NULL; 98964562Sgshapiro i = fork(); 99064562Sgshapiro if (i < 0) 99164562Sgshapiro { 99290792Sgshapiro msglog(LOG_ERR, "vacation: fork: %s", sm_errstring(errno)); 99364562Sgshapiro exit(EX_OSERR); 99464562Sgshapiro } 99564562Sgshapiro if (i == 0) 99664562Sgshapiro { 99764562Sgshapiro (void) dup2(pvect[0], 0); 99864562Sgshapiro (void) close(pvect[0]); 99964562Sgshapiro (void) close(pvect[1]); 100090792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 100177349Sgshapiro (void) execv(_PATH_SENDMAIL, pv); 100264562Sgshapiro msglog(LOG_ERR, "vacation: can't exec %s: %s", 100390792Sgshapiro _PATH_SENDMAIL, sm_errstring(errno)); 100464562Sgshapiro exit(EX_UNAVAILABLE); 100564562Sgshapiro } 100664562Sgshapiro /* check return status of the following calls? XXX */ 100764562Sgshapiro (void) close(pvect[0]); 100890792Sgshapiro if ((sfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 100990792Sgshapiro (void *) &(pvect[1]), 101090792Sgshapiro SM_IO_WRONLY, NULL)) != NULL) 101164562Sgshapiro { 101290792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, "To: %s\n", From); 101390792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, 101490792Sgshapiro "Auto-Submitted: auto-replied\n"); 101590792Sgshapiro while (sm_io_fgets(mfp, SM_TIME_DEFAULT, buf, sizeof buf)) 101690792Sgshapiro (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf); 101790792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 101890792Sgshapiro (void) sm_io_close(sfp, SM_TIME_DEFAULT); 101964562Sgshapiro } 102064562Sgshapiro else 102164562Sgshapiro { 102290792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 102364562Sgshapiro msglog(LOG_ERR, "vacation: can't open pipe to sendmail"); 102464562Sgshapiro exit(EX_UNAVAILABLE); 102564562Sgshapiro } 102664562Sgshapiro} 102764562Sgshapiro 102864562Sgshapirovoid 102964562Sgshapirousage() 103064562Sgshapiro{ 103190792Sgshapiro char *retusage; 103290792Sgshapiro 103390792Sgshapiro#if _FFR_RETURN_ADDR 103490792Sgshapiro retusage = "[-R returnaddr] "; 103590792Sgshapiro#else /* _FFR_RETURN_ADDR */ 103690792Sgshapiro retusage = ""; 103790792Sgshapiro#endif /* _FFR_RETURN_ADDR */ 103890792Sgshapiro 103977349Sgshapiro msglog(LOG_NOTICE, 104090792Sgshapiro "uid %u: usage: vacation [-a alias] [-C cfpath] [-d] [-f db] [-i] [-l] [-m msg] %s[-r interval] [-s sender] [-t time] [-U] [-x] [-z] login\n", 104190792Sgshapiro getuid(), retusage); 104264562Sgshapiro exit(EX_USAGE); 104364562Sgshapiro} 104464562Sgshapiro 104564562Sgshapiro/* 104664562Sgshapiro** LISTDB -- list the contents of the vacation database 104764562Sgshapiro** 104864562Sgshapiro** Parameters: 104964562Sgshapiro** none. 105064562Sgshapiro** 105164562Sgshapiro** Returns: 105264562Sgshapiro** nothing. 105364562Sgshapiro*/ 105464562Sgshapiro 105564562Sgshapirostatic void 105664562Sgshapirolistdb() 105764562Sgshapiro{ 105864562Sgshapiro int result; 105964562Sgshapiro time_t t; 106064562Sgshapiro SMDB_CURSOR *cursor = NULL; 106164562Sgshapiro SMDB_DBENT db_key, db_value; 106264562Sgshapiro 106364562Sgshapiro memset(&db_key, '\0', sizeof db_key); 106464562Sgshapiro memset(&db_value, '\0', sizeof db_value); 106564562Sgshapiro 106664562Sgshapiro result = Db->smdb_cursor(Db, &cursor, 0); 106764562Sgshapiro if (result != SMDBE_OK) 106864562Sgshapiro { 106990792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 107090792Sgshapiro "vacation: set cursor: %s\n", 107190792Sgshapiro sm_errstring(result)); 107264562Sgshapiro return; 107364562Sgshapiro } 107464562Sgshapiro 107564562Sgshapiro while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, 107664562Sgshapiro SMDB_CURSOR_GET_NEXT)) == SMDBE_OK) 107764562Sgshapiro { 107864562Sgshapiro /* skip magic VIT entry */ 107990792Sgshapiro if ((int)db_key.size - 1 == strlen(VIT) && 108071345Sgshapiro strncmp((char *)db_key.data, VIT, 108171345Sgshapiro (int)db_key.size - 1) == 0) 108264562Sgshapiro continue; 108364562Sgshapiro 108464562Sgshapiro /* skip bogus values */ 108571345Sgshapiro if (db_value.size != sizeof t) 108664562Sgshapiro { 108790792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 108890792Sgshapiro "vacation: %.*s invalid time stamp\n", 108990792Sgshapiro (int) db_key.size, (char *) db_key.data); 109064562Sgshapiro continue; 109164562Sgshapiro } 109264562Sgshapiro 109371345Sgshapiro memcpy(&t, db_value.data, sizeof t); 109464562Sgshapiro 109571345Sgshapiro if (db_key.size > 40) 109671345Sgshapiro db_key.size = 40; 109764562Sgshapiro 109890792Sgshapiro sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%-40.*s %-10s", 109990792Sgshapiro (int) db_key.size, (char *) db_key.data, 110090792Sgshapiro ctime(&t)); 110164562Sgshapiro 110264562Sgshapiro memset(&db_key, '\0', sizeof db_key); 110364562Sgshapiro memset(&db_value, '\0', sizeof db_value); 110464562Sgshapiro } 110564562Sgshapiro 110664562Sgshapiro if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) 110764562Sgshapiro { 110890792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 110990792Sgshapiro "vacation: get value at cursor: %s\n", 111090792Sgshapiro sm_errstring(result)); 111164562Sgshapiro if (cursor != NULL) 111264562Sgshapiro { 111364562Sgshapiro (void) cursor->smdbc_close(cursor); 111464562Sgshapiro cursor = NULL; 111564562Sgshapiro } 111664562Sgshapiro return; 111764562Sgshapiro } 111864562Sgshapiro (void) cursor->smdbc_close(cursor); 111964562Sgshapiro cursor = NULL; 112064562Sgshapiro} 112164562Sgshapiro 112264562Sgshapiro/* 112364562Sgshapiro** DEBUGLOG -- write message to standard error 112464562Sgshapiro** 112564562Sgshapiro** Append a message to the standard error for the convenience of 112664562Sgshapiro** end-users debugging without access to the syslog messages. 112764562Sgshapiro** 112864562Sgshapiro** Parameters: 112964562Sgshapiro** i -- syslog log level 113064562Sgshapiro** fmt -- string format 113164562Sgshapiro** 113264562Sgshapiro** Returns: 113364562Sgshapiro** nothing. 113464562Sgshapiro*/ 113564562Sgshapiro 113664562Sgshapiro/*VARARGS2*/ 113790792Sgshapirostatic SYSLOG_RET_T 113864562Sgshapiro#ifdef __STDC__ 113964562Sgshapirodebuglog(int i, const char *fmt, ...) 114064562Sgshapiro#else /* __STDC__ */ 114164562Sgshapirodebuglog(i, fmt, va_alist) 114264562Sgshapiro int i; 114364562Sgshapiro const char *fmt; 114464562Sgshapiro va_dcl 114564562Sgshapiro#endif /* __STDC__ */ 114664562Sgshapiro 114764562Sgshapiro{ 114890792Sgshapiro SM_VA_LOCAL_DECL 114964562Sgshapiro 115090792Sgshapiro SM_VA_START(ap, fmt); 115190792Sgshapiro sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap); 115290792Sgshapiro SM_VA_END(ap); 115390792Sgshapiro SYSLOG_RET; 115464562Sgshapiro} 1155