vacation.c revision 94334
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 2394334SgshapiroSM_IDSTR(id, "@(#)$Id: vacation.c,v 8.134 2002/03/01 20:45:00 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{ \ 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 32294334Sgshapiro cfpath = getcfname(0, 0, SM_GET_SENDMAIL_CF, cfpath); 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 } 37394334Sgshapiro if (getuid() == 0) 37494334Sgshapiro { 37594334Sgshapiro /* Allow root to initialize user's vacation databases */ 37694334Sgshapiro sff |= SFF_OPENASROOT|SFF_ROOTOK; 37766494Sgshapiro 37894334Sgshapiro /* ... safely */ 37994334Sgshapiro sff |= SFF_NOSLINK|SFF_NOHLINK|SFF_REGONLY; 38094334Sgshapiro } 38194334Sgshapiro 38294334Sgshapiro 38364562Sgshapiro result = smdb_open_database(&Db, dbfilename, 38464562Sgshapiro O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0), 38566494Sgshapiro S_IRUSR|S_IWUSR, sff, 38664562Sgshapiro SMDB_TYPE_DEFAULT, &user_info, NULL); 38764562Sgshapiro if (result != SMDBE_OK) 38864562Sgshapiro { 38964562Sgshapiro msglog(LOG_NOTICE, "vacation: %s: %s\n", dbfilename, 39090792Sgshapiro sm_errstring(result)); 39166494Sgshapiro EXITM(EX_DATAERR); 39264562Sgshapiro } 39364562Sgshapiro 39464562Sgshapiro if (lflag) 39564562Sgshapiro { 39664562Sgshapiro listdb(); 39771345Sgshapiro (void) Db->smdb_close(Db); 39864562Sgshapiro exit(EX_OK); 39964562Sgshapiro } 40064562Sgshapiro 40164562Sgshapiro if (interval != INTERVAL_UNDEF) 40264562Sgshapiro setinterval(interval); 40364562Sgshapiro 40471345Sgshapiro if (iflag && !exclude) 40564562Sgshapiro { 40671345Sgshapiro (void) Db->smdb_close(Db); 40771345Sgshapiro exit(EX_OK); 40864562Sgshapiro } 40964562Sgshapiro 41064562Sgshapiro if (exclude) 41164562Sgshapiro { 41290792Sgshapiro xclude(smioin); 41371345Sgshapiro (void) Db->smdb_close(Db); 41466494Sgshapiro EXITM(EX_OK); 41564562Sgshapiro } 41664562Sgshapiro 41790792Sgshapiro if ((cur = (ALIAS *) malloc((unsigned int) sizeof(ALIAS))) == NULL) 41864562Sgshapiro { 41964562Sgshapiro msglog(LOG_NOTICE, 42064562Sgshapiro "vacation: can't allocate memory for username.\n"); 42171345Sgshapiro (void) Db->smdb_close(Db); 42266494Sgshapiro EXITM(EX_OSERR); 42364562Sgshapiro } 42464562Sgshapiro cur->name = name; 42564562Sgshapiro cur->next = Names; 42664562Sgshapiro Names = cur; 42764562Sgshapiro 42871345Sgshapiro result = readheaders(); 42971345Sgshapiro if (result == EX_OK && !recent()) 43064562Sgshapiro { 43164562Sgshapiro time_t now; 43264562Sgshapiro 43364562Sgshapiro (void) time(&now); 43464562Sgshapiro setreply(From, now); 43571345Sgshapiro (void) Db->smdb_close(Db); 43690792Sgshapiro sendmessage(name, msgfilename, returnaddr); 43764562Sgshapiro } 43864562Sgshapiro else 43971345Sgshapiro (void) Db->smdb_close(Db); 44071345Sgshapiro if (result == EX_NOUSER) 44171345Sgshapiro result = EX_OK; 44271345Sgshapiro exit(result); 44364562Sgshapiro} 44464562Sgshapiro 44564562Sgshapiro/* 44666494Sgshapiro** EATMSG -- read stdin till EOF 44766494Sgshapiro** 44866494Sgshapiro** Parameters: 44966494Sgshapiro** none. 45066494Sgshapiro** 45166494Sgshapiro** Returns: 45266494Sgshapiro** nothing. 45366494Sgshapiro** 45466494Sgshapiro*/ 45577349Sgshapiro 45666494Sgshapirostatic void 45766494Sgshapiroeatmsg() 45866494Sgshapiro{ 45966494Sgshapiro /* 46066494Sgshapiro ** read the rest of the e-mail and ignore it to avoid problems 46166494Sgshapiro ** with EPIPE in sendmail 46266494Sgshapiro */ 46366494Sgshapiro while (getc(stdin) != EOF) 46466494Sgshapiro continue; 46566494Sgshapiro} 46666494Sgshapiro 46766494Sgshapiro/* 46864562Sgshapiro** READHEADERS -- read mail headers 46964562Sgshapiro** 47064562Sgshapiro** Parameters: 47164562Sgshapiro** none. 47264562Sgshapiro** 47364562Sgshapiro** Returns: 47471345Sgshapiro** a exit code: NOUSER if no reply, OK if reply, * if error 47564562Sgshapiro** 47666494Sgshapiro** Side Effects: 47766494Sgshapiro** may exit(). 47866494Sgshapiro** 47964562Sgshapiro*/ 48071345Sgshapiro 48171345Sgshapiroint 48264562Sgshapiroreadheaders() 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 49190792Sgshapiro cont = tome = false; 49290792Sgshapiro while (sm_io_fgets(smioin, SM_TIME_DEFAULT, buf, sizeof(buf)) && 49390792Sgshapiro *buf != '\n') 49464562Sgshapiro { 49564562Sgshapiro switch(*buf) 49664562Sgshapiro { 49764562Sgshapiro case 'F': /* "From " */ 49890792Sgshapiro cont = false; 49964562Sgshapiro if (strncmp(buf, "From ", 5) == 0) 50064562Sgshapiro { 50190792Sgshapiro bool quoted = false; 50264562Sgshapiro 50364562Sgshapiro p = buf + 5; 50464562Sgshapiro while (*p != '\0') 50564562Sgshapiro { 50664562Sgshapiro /* escaped character */ 50764562Sgshapiro if (*p == '\\') 50864562Sgshapiro { 50964562Sgshapiro p++; 51064562Sgshapiro if (*p == '\0') 51164562Sgshapiro { 51264562Sgshapiro msglog(LOG_NOTICE, 51364562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 51466494Sgshapiro EXITIT(EX_DATAERR); 51564562Sgshapiro } 51664562Sgshapiro } 51764562Sgshapiro else if (*p == '"') 51864562Sgshapiro quoted = !quoted; 51964562Sgshapiro else if (*p == '\r' || *p == '\n') 52064562Sgshapiro break; 52164562Sgshapiro else if (*p == ' ' && !quoted) 52264562Sgshapiro break; 52364562Sgshapiro p++; 52464562Sgshapiro } 52564562Sgshapiro if (quoted) 52664562Sgshapiro { 52764562Sgshapiro msglog(LOG_NOTICE, 52864562Sgshapiro "vacation: badly formatted \"From \" line.\n"); 52966494Sgshapiro EXITIT(EX_DATAERR); 53064562Sgshapiro } 53164562Sgshapiro *p = '\0'; 53264562Sgshapiro 53364562Sgshapiro /* ok since both strings have MAXLINE length */ 53464562Sgshapiro if (*From == '\0') 53590792Sgshapiro (void) sm_strlcpy(From, buf + 5, 53690792Sgshapiro sizeof From); 53764562Sgshapiro if ((p = strchr(buf + 5, '\n')) != NULL) 53864562Sgshapiro *p = '\0'; 53964562Sgshapiro if (junkmail(buf + 5)) 54071345Sgshapiro EXITIT(EX_NOUSER); 54164562Sgshapiro } 54264562Sgshapiro break; 54364562Sgshapiro 54464562Sgshapiro case 'P': /* "Precedence:" */ 54564562Sgshapiro case 'p': 54690792Sgshapiro cont = false; 54764562Sgshapiro if (strlen(buf) <= 10 || 54864562Sgshapiro strncasecmp(buf, "Precedence", 10) != 0 || 54964562Sgshapiro (buf[10] != ':' && buf[10] != ' ' && 55064562Sgshapiro buf[10] != '\t')) 55164562Sgshapiro break; 55264562Sgshapiro if ((p = strchr(buf, ':')) == NULL) 55364562Sgshapiro break; 55464562Sgshapiro while (*++p != '\0' && isascii(*p) && isspace(*p)); 55564562Sgshapiro if (*p == '\0') 55664562Sgshapiro break; 55764562Sgshapiro if (strncasecmp(p, "junk", 4) == 0 || 55864562Sgshapiro strncasecmp(p, "bulk", 4) == 0 || 55964562Sgshapiro strncasecmp(p, "list", 4) == 0) 56071345Sgshapiro EXITIT(EX_NOUSER); 56164562Sgshapiro break; 56264562Sgshapiro 56364562Sgshapiro case 'C': /* "Cc:" */ 56464562Sgshapiro case 'c': 56564562Sgshapiro if (strncasecmp(buf, "Cc:", 3) != 0) 56664562Sgshapiro break; 56790792Sgshapiro cont = true; 56864562Sgshapiro goto findme; 56964562Sgshapiro 57064562Sgshapiro case 'T': /* "To:" */ 57164562Sgshapiro case 't': 57264562Sgshapiro if (strncasecmp(buf, "To:", 3) != 0) 57364562Sgshapiro break; 57490792Sgshapiro cont = true; 57564562Sgshapiro goto findme; 57664562Sgshapiro 57764562Sgshapiro default: 57864562Sgshapiro if (!isascii(*buf) || !isspace(*buf) || !cont || tome) 57964562Sgshapiro { 58090792Sgshapiro cont = false; 58164562Sgshapiro break; 58264562Sgshapiro } 58364562Sgshapirofindme: 58464562Sgshapiro for (cur = Names; 58564562Sgshapiro !tome && cur != NULL; 58664562Sgshapiro cur = cur->next) 58764562Sgshapiro tome = nsearch(cur->name, buf); 58864562Sgshapiro } 58964562Sgshapiro } 59064562Sgshapiro if (!tome) 59171345Sgshapiro EXITIT(EX_NOUSER); 59264562Sgshapiro if (*From == '\0') 59364562Sgshapiro { 59464562Sgshapiro msglog(LOG_NOTICE, "vacation: no initial \"From \" line.\n"); 59566494Sgshapiro EXITIT(EX_DATAERR); 59664562Sgshapiro } 59771345Sgshapiro EXITIT(EX_OK); 59864562Sgshapiro} 59964562Sgshapiro 60064562Sgshapiro/* 60164562Sgshapiro** NSEARCH -- 60264562Sgshapiro** do a nice, slow, search of a string for a substring. 60364562Sgshapiro** 60464562Sgshapiro** Parameters: 60564562Sgshapiro** name -- name to search. 60664562Sgshapiro** str -- string in which to search. 60764562Sgshapiro** 60864562Sgshapiro** Returns: 60964562Sgshapiro** is name a substring of str? 61064562Sgshapiro** 61164562Sgshapiro*/ 61277349Sgshapiro 61364562Sgshapirobool 61464562Sgshapironsearch(name, str) 61564562Sgshapiro register char *name, *str; 61664562Sgshapiro{ 61764562Sgshapiro register size_t len; 61864562Sgshapiro register char *s; 61964562Sgshapiro 62064562Sgshapiro len = strlen(name); 62164562Sgshapiro 62264562Sgshapiro for (s = str; *s != '\0'; ++s) 62364562Sgshapiro { 62464562Sgshapiro /* 62564562Sgshapiro ** Check to make sure that the string matches and 62664562Sgshapiro ** the previous character is not an alphanumeric and 62764562Sgshapiro ** the next character after the match is not an alphanumeric. 62864562Sgshapiro ** 62964562Sgshapiro ** This prevents matching "eric" to "derick" while still 63064562Sgshapiro ** matching "eric" to "<eric+detail>". 63164562Sgshapiro */ 63264562Sgshapiro 63364562Sgshapiro if (tolower(*s) == tolower(*name) && 63464562Sgshapiro strncasecmp(name, s, len) == 0 && 63564562Sgshapiro (s == str || !isascii(*(s - 1)) || !isalnum(*(s - 1))) && 63664562Sgshapiro (!isascii(*(s + len)) || !isalnum(*(s + len)))) 63790792Sgshapiro return true; 63864562Sgshapiro } 63990792Sgshapiro return false; 64064562Sgshapiro} 64164562Sgshapiro 64264562Sgshapiro/* 64364562Sgshapiro** JUNKMAIL -- 64464562Sgshapiro** read the header and return if automagic/junk/bulk/list mail 64564562Sgshapiro** 64664562Sgshapiro** Parameters: 64764562Sgshapiro** from -- sender address. 64864562Sgshapiro** 64964562Sgshapiro** Returns: 65064562Sgshapiro** is this some automated/junk/bulk/list mail? 65164562Sgshapiro** 65264562Sgshapiro*/ 65371345Sgshapiro 65471345Sgshapirostruct ignore 65571345Sgshapiro{ 65671345Sgshapiro char *name; 65771345Sgshapiro size_t len; 65871345Sgshapiro}; 65971345Sgshapiro 66071345Sgshapirotypedef struct ignore IGNORE_T; 66171345Sgshapiro 66271345Sgshapiro#define MAX_USER_LEN 256 /* maximum length of local part (sender) */ 66371345Sgshapiro 66471345Sgshapiro/* delimiters for the local part of an address */ 66571345Sgshapiro#define isdelim(c) ((c) == '%' || (c) == '@' || (c) == '+') 66671345Sgshapiro 66764562Sgshapirobool 66864562Sgshapirojunkmail(from) 66964562Sgshapiro char *from; 67064562Sgshapiro{ 67171345Sgshapiro bool quot; 67271345Sgshapiro char *e; 67371345Sgshapiro size_t len; 67471345Sgshapiro IGNORE_T *cur; 67571345Sgshapiro char sender[MAX_USER_LEN]; 67671345Sgshapiro static IGNORE_T ignore[] = 67764562Sgshapiro { 67864562Sgshapiro { "postmaster", 10 }, 67964562Sgshapiro { "uucp", 4 }, 68064562Sgshapiro { "mailer-daemon", 13 }, 68164562Sgshapiro { "mailer", 6 }, 68271345Sgshapiro { NULL, 0 } 68371345Sgshapiro }; 68471345Sgshapiro 68571345Sgshapiro static IGNORE_T ignorepost[] = 68671345Sgshapiro { 68771345Sgshapiro { "-request", 8 }, 68864562Sgshapiro { "-relay", 6 }, 68971345Sgshapiro { "-owner", 6 }, 69064562Sgshapiro { NULL, 0 } 69164562Sgshapiro }; 69264562Sgshapiro 69371345Sgshapiro static IGNORE_T ignorepre[] = 69471345Sgshapiro { 69571345Sgshapiro { "owner-", 6 }, 69671345Sgshapiro { NULL, 0 } 69771345Sgshapiro }; 69871345Sgshapiro 69964562Sgshapiro /* 70071345Sgshapiro ** This is mildly amusing, and I'm not positive it's right; trying 70171345Sgshapiro ** to find the "real" name of the sender, assuming that addresses 70271345Sgshapiro ** will be some variant of: 70371345Sgshapiro ** 70471345Sgshapiro ** From site!site!SENDER%site.domain%site.domain@site.domain 70571345Sgshapiro */ 70671345Sgshapiro 70790792Sgshapiro quot = false; 70871345Sgshapiro e = from; 70971345Sgshapiro len = 0; 71071345Sgshapiro while (*e != '\0' && (quot || !isdelim(*e))) 71164562Sgshapiro { 71271345Sgshapiro if (*e == '"') 71371345Sgshapiro { 71471345Sgshapiro quot = !quot; 71571345Sgshapiro ++e; 71671345Sgshapiro continue; 71771345Sgshapiro } 71871345Sgshapiro if (*e == '\\') 71971345Sgshapiro { 72071345Sgshapiro if (*(++e) == '\0') 72171345Sgshapiro { 72271345Sgshapiro /* '\\' at end of string? */ 72371345Sgshapiro break; 72471345Sgshapiro } 72571345Sgshapiro if (len < MAX_USER_LEN) 72671345Sgshapiro sender[len++] = *e; 72771345Sgshapiro ++e; 72871345Sgshapiro continue; 72971345Sgshapiro } 73071345Sgshapiro if (*e == '!' && !quot) 73171345Sgshapiro { 73271345Sgshapiro len = 0; 73371345Sgshapiro sender[len] = '\0'; 73471345Sgshapiro } 73564562Sgshapiro else 73671345Sgshapiro if (len < MAX_USER_LEN) 73771345Sgshapiro sender[len++] = *e; 73871345Sgshapiro ++e; 73964562Sgshapiro } 74071345Sgshapiro if (len < MAX_USER_LEN) 74171345Sgshapiro sender[len] = '\0'; 74271345Sgshapiro else 74371345Sgshapiro sender[MAX_USER_LEN - 1] = '\0'; 74471345Sgshapiro 74571345Sgshapiro if (len <= 0) 74690792Sgshapiro return false; 74771345Sgshapiro#if 0 74871345Sgshapiro if (quot) 74990792Sgshapiro return false; /* syntax error... */ 75071345Sgshapiro#endif /* 0 */ 75171345Sgshapiro 75271345Sgshapiro /* test prefixes */ 75371345Sgshapiro for (cur = ignorepre; cur->name != NULL; ++cur) 75471345Sgshapiro { 75571345Sgshapiro if (len >= cur->len && 75671345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 75790792Sgshapiro return true; 75871345Sgshapiro } 75971345Sgshapiro 76071345Sgshapiro /* 76171345Sgshapiro ** If the name is truncated, don't test the rest. 76271345Sgshapiro ** We could extract the "tail" of the sender address and 76371345Sgshapiro ** compare it it ignorepost, however, it seems not worth 76471345Sgshapiro ** the effort. 76571345Sgshapiro ** The address surely can't match any entry in ignore[] 76671345Sgshapiro ** (as long as all of them are shorter than MAX_USER_LEN). 76771345Sgshapiro */ 76871345Sgshapiro 76971345Sgshapiro if (len > MAX_USER_LEN) 77090792Sgshapiro return false; 77171345Sgshapiro 77271345Sgshapiro /* test full local parts */ 77364562Sgshapiro for (cur = ignore; cur->name != NULL; ++cur) 77464562Sgshapiro { 77571345Sgshapiro if (len == cur->len && 77671345Sgshapiro strncasecmp(cur->name, sender, cur->len) == 0) 77790792Sgshapiro return true; 77871345Sgshapiro } 77971345Sgshapiro 78071345Sgshapiro /* test postfixes */ 78171345Sgshapiro for (cur = ignorepost; cur->name != NULL; ++cur) 78271345Sgshapiro { 78364562Sgshapiro if (len >= cur->len && 78471345Sgshapiro strncasecmp(cur->name, e - cur->len - 1, 78571345Sgshapiro cur->len) == 0) 78690792Sgshapiro return true; 78764562Sgshapiro } 78890792Sgshapiro return false; 78964562Sgshapiro} 79064562Sgshapiro 79164562Sgshapiro#define VIT "__VACATION__INTERVAL__TIMER__" 79264562Sgshapiro 79364562Sgshapiro/* 79464562Sgshapiro** RECENT -- 79564562Sgshapiro** find out if user has gotten a vacation message recently. 79664562Sgshapiro** 79764562Sgshapiro** Parameters: 79864562Sgshapiro** none. 79964562Sgshapiro** 80064562Sgshapiro** Returns: 80190792Sgshapiro** true iff user has gotten a vacation message recently. 80264562Sgshapiro** 80364562Sgshapiro*/ 80477349Sgshapiro 80564562Sgshapirobool 80664562Sgshapirorecent() 80764562Sgshapiro{ 80864562Sgshapiro SMDB_DBENT key, data; 80964562Sgshapiro time_t then, next; 81090792Sgshapiro bool trydomain = false; 81164562Sgshapiro int st; 81264562Sgshapiro char *domain; 81364562Sgshapiro 81464562Sgshapiro memset(&key, '\0', sizeof key); 81564562Sgshapiro memset(&data, '\0', sizeof data); 81664562Sgshapiro 81764562Sgshapiro /* get interval time */ 81871345Sgshapiro key.data = VIT; 81971345Sgshapiro key.size = sizeof(VIT); 82064562Sgshapiro 82164562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 82264562Sgshapiro if (st != SMDBE_OK) 82364562Sgshapiro next = SECSPERDAY * DAYSPERWEEK; 82464562Sgshapiro else 82571345Sgshapiro memmove(&next, data.data, sizeof(next)); 82664562Sgshapiro 82764562Sgshapiro memset(&data, '\0', sizeof data); 82864562Sgshapiro 82964562Sgshapiro /* get record for this address */ 83071345Sgshapiro key.data = From; 83171345Sgshapiro key.size = strlen(From); 83264562Sgshapiro 83364562Sgshapiro do 83464562Sgshapiro { 83564562Sgshapiro st = Db->smdb_get(Db, &key, &data, 0); 83664562Sgshapiro if (st == SMDBE_OK) 83764562Sgshapiro { 83871345Sgshapiro memmove(&then, data.data, sizeof(then)); 83964562Sgshapiro if (next == ONLY_ONCE || then == ONLY_ONCE || 84064562Sgshapiro then + next > time(NULL)) 84190792Sgshapiro return true; 84264562Sgshapiro } 84364562Sgshapiro if ((trydomain = !trydomain) && 84464562Sgshapiro (domain = strchr(From, '@')) != NULL) 84564562Sgshapiro { 84671345Sgshapiro key.data = domain; 84771345Sgshapiro key.size = strlen(domain); 84864562Sgshapiro } 84964562Sgshapiro } while (trydomain); 85090792Sgshapiro return false; 85164562Sgshapiro} 85264562Sgshapiro 85364562Sgshapiro/* 85464562Sgshapiro** SETINTERVAL -- 85564562Sgshapiro** store the reply interval 85664562Sgshapiro** 85764562Sgshapiro** Parameters: 85864562Sgshapiro** interval -- time interval for replies. 85964562Sgshapiro** 86064562Sgshapiro** Returns: 86164562Sgshapiro** nothing. 86264562Sgshapiro** 86364562Sgshapiro** Side Effects: 86464562Sgshapiro** stores the reply interval in database. 86564562Sgshapiro*/ 86677349Sgshapiro 86764562Sgshapirovoid 86864562Sgshapirosetinterval(interval) 86964562Sgshapiro time_t interval; 87064562Sgshapiro{ 87164562Sgshapiro SMDB_DBENT key, data; 87264562Sgshapiro 87364562Sgshapiro memset(&key, '\0', sizeof key); 87464562Sgshapiro memset(&data, '\0', sizeof data); 87564562Sgshapiro 87671345Sgshapiro key.data = VIT; 87771345Sgshapiro key.size = sizeof(VIT); 87871345Sgshapiro data.data = (char*) &interval; 87971345Sgshapiro data.size = sizeof(interval); 88071345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 88164562Sgshapiro} 88264562Sgshapiro 88364562Sgshapiro/* 88464562Sgshapiro** SETREPLY -- 88564562Sgshapiro** store that this user knows about the vacation. 88664562Sgshapiro** 88764562Sgshapiro** Parameters: 88864562Sgshapiro** from -- sender address. 88964562Sgshapiro** when -- last reply time. 89064562Sgshapiro** 89164562Sgshapiro** Returns: 89264562Sgshapiro** nothing. 89364562Sgshapiro** 89464562Sgshapiro** Side Effects: 89564562Sgshapiro** stores user/time in database. 89664562Sgshapiro*/ 89777349Sgshapiro 89864562Sgshapirovoid 89964562Sgshapirosetreply(from, when) 90064562Sgshapiro char *from; 90164562Sgshapiro time_t when; 90264562Sgshapiro{ 90364562Sgshapiro SMDB_DBENT key, data; 90464562Sgshapiro 90564562Sgshapiro memset(&key, '\0', sizeof key); 90664562Sgshapiro memset(&data, '\0', sizeof data); 90764562Sgshapiro 90871345Sgshapiro key.data = from; 90971345Sgshapiro key.size = strlen(from); 91071345Sgshapiro data.data = (char*) &when; 91171345Sgshapiro data.size = sizeof(when); 91271345Sgshapiro (void) (Db->smdb_put)(Db, &key, &data, 0); 91364562Sgshapiro} 91464562Sgshapiro 91564562Sgshapiro/* 91664562Sgshapiro** XCLUDE -- 91764562Sgshapiro** add users to vacation db so they don't get a reply. 91864562Sgshapiro** 91964562Sgshapiro** Parameters: 92064562Sgshapiro** f -- file pointer with list of address to exclude 92164562Sgshapiro** 92264562Sgshapiro** Returns: 92364562Sgshapiro** nothing. 92464562Sgshapiro** 92564562Sgshapiro** Side Effects: 92664562Sgshapiro** stores users in database. 92764562Sgshapiro*/ 92877349Sgshapiro 92964562Sgshapirovoid 93064562Sgshapiroxclude(f) 93190792Sgshapiro SM_FILE_T *f; 93264562Sgshapiro{ 93364562Sgshapiro char buf[MAXLINE], *p; 93464562Sgshapiro 93564562Sgshapiro if (f == NULL) 93664562Sgshapiro return; 93790792Sgshapiro while (sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof buf)) 93864562Sgshapiro { 93964562Sgshapiro if ((p = strchr(buf, '\n')) != NULL) 94064562Sgshapiro *p = '\0'; 94164562Sgshapiro setreply(buf, ONLY_ONCE); 94264562Sgshapiro } 94364562Sgshapiro} 94464562Sgshapiro 94564562Sgshapiro/* 94664562Sgshapiro** SENDMESSAGE -- 94764562Sgshapiro** exec sendmail to send the vacation file to sender 94864562Sgshapiro** 94964562Sgshapiro** Parameters: 95064562Sgshapiro** myname -- user name. 95164562Sgshapiro** msgfn -- name of file with vacation message. 95290792Sgshapiro** sender -- use as sender address 95364562Sgshapiro** 95464562Sgshapiro** Returns: 95564562Sgshapiro** nothing. 95664562Sgshapiro** 95764562Sgshapiro** Side Effects: 95864562Sgshapiro** sends vacation reply. 95964562Sgshapiro*/ 96077349Sgshapiro 96164562Sgshapirovoid 96290792Sgshapirosendmessage(myname, msgfn, sender) 96364562Sgshapiro char *myname; 96464562Sgshapiro char *msgfn; 96590792Sgshapiro char *sender; 96664562Sgshapiro{ 96790792Sgshapiro SM_FILE_T *mfp, *sfp; 96864562Sgshapiro int i; 96964562Sgshapiro int pvect[2]; 97077349Sgshapiro char *pv[8]; 97164562Sgshapiro char buf[MAXLINE]; 97264562Sgshapiro 97390792Sgshapiro mfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, msgfn, SM_IO_RDONLY, NULL); 97464562Sgshapiro if (mfp == NULL) 97564562Sgshapiro { 97664562Sgshapiro if (msgfn[0] == '/') 97764562Sgshapiro msglog(LOG_NOTICE, "vacation: no %s file.\n", msgfn); 97864562Sgshapiro else 97964562Sgshapiro msglog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", 98064562Sgshapiro myname, msgfn); 98164562Sgshapiro exit(EX_NOINPUT); 98264562Sgshapiro } 98364562Sgshapiro if (pipe(pvect) < 0) 98464562Sgshapiro { 98590792Sgshapiro msglog(LOG_ERR, "vacation: pipe: %s", sm_errstring(errno)); 98664562Sgshapiro exit(EX_OSERR); 98764562Sgshapiro } 98877349Sgshapiro pv[0] = "sendmail"; 98977349Sgshapiro pv[1] = "-oi"; 99077349Sgshapiro pv[2] = "-f"; 99190792Sgshapiro if (sender != NULL) 99290792Sgshapiro pv[3] = sender; 99377349Sgshapiro else 99477349Sgshapiro pv[3] = myname; 99577349Sgshapiro pv[4] = "--"; 99677349Sgshapiro pv[5] = From; 99777349Sgshapiro pv[6] = NULL; 99864562Sgshapiro i = fork(); 99964562Sgshapiro if (i < 0) 100064562Sgshapiro { 100190792Sgshapiro msglog(LOG_ERR, "vacation: fork: %s", sm_errstring(errno)); 100264562Sgshapiro exit(EX_OSERR); 100364562Sgshapiro } 100464562Sgshapiro if (i == 0) 100564562Sgshapiro { 100664562Sgshapiro (void) dup2(pvect[0], 0); 100764562Sgshapiro (void) close(pvect[0]); 100864562Sgshapiro (void) close(pvect[1]); 100990792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 101077349Sgshapiro (void) execv(_PATH_SENDMAIL, pv); 101164562Sgshapiro msglog(LOG_ERR, "vacation: can't exec %s: %s", 101290792Sgshapiro _PATH_SENDMAIL, sm_errstring(errno)); 101364562Sgshapiro exit(EX_UNAVAILABLE); 101464562Sgshapiro } 101564562Sgshapiro /* check return status of the following calls? XXX */ 101664562Sgshapiro (void) close(pvect[0]); 101790792Sgshapiro if ((sfp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 101890792Sgshapiro (void *) &(pvect[1]), 101990792Sgshapiro SM_IO_WRONLY, NULL)) != NULL) 102064562Sgshapiro { 102190792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, "To: %s\n", From); 102290792Sgshapiro (void) sm_io_fprintf(sfp, SM_TIME_DEFAULT, 102390792Sgshapiro "Auto-Submitted: auto-replied\n"); 102490792Sgshapiro while (sm_io_fgets(mfp, SM_TIME_DEFAULT, buf, sizeof buf)) 102590792Sgshapiro (void) sm_io_fputs(sfp, SM_TIME_DEFAULT, buf); 102690792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 102790792Sgshapiro (void) sm_io_close(sfp, SM_TIME_DEFAULT); 102864562Sgshapiro } 102964562Sgshapiro else 103064562Sgshapiro { 103190792Sgshapiro (void) sm_io_close(mfp, SM_TIME_DEFAULT); 103264562Sgshapiro msglog(LOG_ERR, "vacation: can't open pipe to sendmail"); 103364562Sgshapiro exit(EX_UNAVAILABLE); 103464562Sgshapiro } 103564562Sgshapiro} 103664562Sgshapiro 103764562Sgshapirovoid 103864562Sgshapirousage() 103964562Sgshapiro{ 104090792Sgshapiro char *retusage; 104190792Sgshapiro 104290792Sgshapiro#if _FFR_RETURN_ADDR 104390792Sgshapiro retusage = "[-R returnaddr] "; 104490792Sgshapiro#else /* _FFR_RETURN_ADDR */ 104590792Sgshapiro retusage = ""; 104690792Sgshapiro#endif /* _FFR_RETURN_ADDR */ 104790792Sgshapiro 104877349Sgshapiro msglog(LOG_NOTICE, 104990792Sgshapiro "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", 105090792Sgshapiro getuid(), retusage); 105164562Sgshapiro exit(EX_USAGE); 105264562Sgshapiro} 105364562Sgshapiro 105464562Sgshapiro/* 105564562Sgshapiro** LISTDB -- list the contents of the vacation database 105664562Sgshapiro** 105764562Sgshapiro** Parameters: 105864562Sgshapiro** none. 105964562Sgshapiro** 106064562Sgshapiro** Returns: 106164562Sgshapiro** nothing. 106264562Sgshapiro*/ 106364562Sgshapiro 106464562Sgshapirostatic void 106564562Sgshapirolistdb() 106664562Sgshapiro{ 106764562Sgshapiro int result; 106864562Sgshapiro time_t t; 106964562Sgshapiro SMDB_CURSOR *cursor = NULL; 107064562Sgshapiro SMDB_DBENT db_key, db_value; 107164562Sgshapiro 107264562Sgshapiro memset(&db_key, '\0', sizeof db_key); 107364562Sgshapiro memset(&db_value, '\0', sizeof db_value); 107464562Sgshapiro 107564562Sgshapiro result = Db->smdb_cursor(Db, &cursor, 0); 107664562Sgshapiro if (result != SMDBE_OK) 107764562Sgshapiro { 107890792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 107990792Sgshapiro "vacation: set cursor: %s\n", 108090792Sgshapiro sm_errstring(result)); 108164562Sgshapiro return; 108264562Sgshapiro } 108364562Sgshapiro 108464562Sgshapiro while ((result = cursor->smdbc_get(cursor, &db_key, &db_value, 108564562Sgshapiro SMDB_CURSOR_GET_NEXT)) == SMDBE_OK) 108664562Sgshapiro { 108764562Sgshapiro /* skip magic VIT entry */ 108890792Sgshapiro if ((int)db_key.size - 1 == strlen(VIT) && 108971345Sgshapiro strncmp((char *)db_key.data, VIT, 109071345Sgshapiro (int)db_key.size - 1) == 0) 109164562Sgshapiro continue; 109264562Sgshapiro 109364562Sgshapiro /* skip bogus values */ 109471345Sgshapiro if (db_value.size != sizeof t) 109564562Sgshapiro { 109690792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 109790792Sgshapiro "vacation: %.*s invalid time stamp\n", 109890792Sgshapiro (int) db_key.size, (char *) db_key.data); 109964562Sgshapiro continue; 110064562Sgshapiro } 110164562Sgshapiro 110271345Sgshapiro memcpy(&t, db_value.data, sizeof t); 110364562Sgshapiro 110471345Sgshapiro if (db_key.size > 40) 110571345Sgshapiro db_key.size = 40; 110664562Sgshapiro 110790792Sgshapiro sm_io_fprintf(smioout, SM_TIME_DEFAULT, "%-40.*s %-10s", 110890792Sgshapiro (int) db_key.size, (char *) db_key.data, 110990792Sgshapiro ctime(&t)); 111064562Sgshapiro 111164562Sgshapiro memset(&db_key, '\0', sizeof db_key); 111264562Sgshapiro memset(&db_value, '\0', sizeof db_value); 111364562Sgshapiro } 111464562Sgshapiro 111564562Sgshapiro if (result != SMDBE_OK && result != SMDBE_LAST_ENTRY) 111664562Sgshapiro { 111790792Sgshapiro sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 111890792Sgshapiro "vacation: get value at cursor: %s\n", 111990792Sgshapiro sm_errstring(result)); 112064562Sgshapiro if (cursor != NULL) 112164562Sgshapiro { 112264562Sgshapiro (void) cursor->smdbc_close(cursor); 112364562Sgshapiro cursor = NULL; 112464562Sgshapiro } 112564562Sgshapiro return; 112664562Sgshapiro } 112764562Sgshapiro (void) cursor->smdbc_close(cursor); 112864562Sgshapiro cursor = NULL; 112964562Sgshapiro} 113064562Sgshapiro 113164562Sgshapiro/* 113264562Sgshapiro** DEBUGLOG -- write message to standard error 113364562Sgshapiro** 113464562Sgshapiro** Append a message to the standard error for the convenience of 113564562Sgshapiro** end-users debugging without access to the syslog messages. 113664562Sgshapiro** 113764562Sgshapiro** Parameters: 113864562Sgshapiro** i -- syslog log level 113964562Sgshapiro** fmt -- string format 114064562Sgshapiro** 114164562Sgshapiro** Returns: 114264562Sgshapiro** nothing. 114364562Sgshapiro*/ 114464562Sgshapiro 114564562Sgshapiro/*VARARGS2*/ 114690792Sgshapirostatic SYSLOG_RET_T 114764562Sgshapiro#ifdef __STDC__ 114864562Sgshapirodebuglog(int i, const char *fmt, ...) 114964562Sgshapiro#else /* __STDC__ */ 115064562Sgshapirodebuglog(i, fmt, va_alist) 115164562Sgshapiro int i; 115264562Sgshapiro const char *fmt; 115364562Sgshapiro va_dcl 115464562Sgshapiro#endif /* __STDC__ */ 115564562Sgshapiro 115664562Sgshapiro{ 115790792Sgshapiro SM_VA_LOCAL_DECL 115864562Sgshapiro 115990792Sgshapiro SM_VA_START(ap, fmt); 116090792Sgshapiro sm_io_vfprintf(smioerr, SM_TIME_DEFAULT, fmt, ap); 116190792Sgshapiro SM_VA_END(ap); 116290792Sgshapiro SYSLOG_RET; 116364562Sgshapiro} 1164