|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983, 1987 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1983, 1987 Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)vacation.c 5.17 (Berkeley) 6/1/90"; ! 28: #endif /* not lint */ ! 29: ! 30: /* ! 31: ** Vacation ! 32: ** Copyright (c) 1983 Eric P. Allman ! 33: ** Berkeley, California ! 34: */ ! 35: ! 36: #include <sys/param.h> ! 37: #include <sys/file.h> ! 38: #include <pwd.h> ! 39: #include <ndbm.h> ! 40: #include <syslog.h> ! 41: #include <tzfile.h> ! 42: #include <stdio.h> ! 43: #include <ctype.h> ! 44: #include <paths.h> ! 45: ! 46: /* ! 47: * VACATION -- return a message to the sender when on vacation. ! 48: * ! 49: * This program is invoked as a message receiver. It returns a ! 50: * message specified by the user to whomever sent the mail, taking ! 51: * care not to return a message too often to prevent "I am on ! 52: * vacation" loops. ! 53: */ ! 54: ! 55: #define MAXLINE 500 /* max line from mail header */ ! 56: #define VMSG ".vacation.msg" /* vacation message */ ! 57: #define VACAT ".vacation" /* dbm's database prefix */ ! 58: #define VDIR ".vacation.dir" /* dbm's DB prefix, part 1 */ ! 59: #define VPAG ".vacation.pag" /* dbm's DB prefix, part 2 */ ! 60: ! 61: typedef struct alias { ! 62: struct alias *next; ! 63: char *name; ! 64: } ALIAS; ! 65: ALIAS *names; ! 66: ! 67: static DBM *db; ! 68: ! 69: extern int errno; ! 70: ! 71: static char *VIT = "__VACATION__INTERVAL__TIMER__"; ! 72: static char from[MAXLINE]; ! 73: ! 74: main(argc, argv) ! 75: int argc; ! 76: char **argv; ! 77: { ! 78: extern int optind, opterr; ! 79: extern char *optarg; ! 80: struct passwd *pw; ! 81: ALIAS *cur; ! 82: time_t interval; ! 83: int ch, iflag; ! 84: char *malloc(); ! 85: uid_t getuid(); ! 86: long atol(); ! 87: ! 88: opterr = iflag = 0; ! 89: interval = -1; ! 90: while ((ch = getopt(argc, argv, "a:Iir:")) != EOF) ! 91: switch((char)ch) { ! 92: case 'a': /* alias */ ! 93: if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS)))) ! 94: break; ! 95: cur->name = optarg; ! 96: cur->next = names; ! 97: names = cur; ! 98: break; ! 99: case 'I': /* backward compatible */ ! 100: case 'i': /* init the database */ ! 101: iflag = 1; ! 102: break; ! 103: case 'r': ! 104: if (isdigit(*optarg)) { ! 105: interval = atol(optarg) * SECSPERDAY; ! 106: if (interval < 0) ! 107: goto usage; ! 108: } ! 109: else ! 110: interval = LONG_MAX; ! 111: break; ! 112: case '?': ! 113: default: ! 114: goto usage; ! 115: } ! 116: argc -= optind; ! 117: argv += optind; ! 118: ! 119: if (argc != 1) { ! 120: if (!iflag) { ! 121: usage: syslog(LOG_NOTICE, "uid %u: usage: vacation [-i] [-a alias] login\n", getuid()); ! 122: myexit(1); ! 123: } ! 124: if (!(pw = getpwuid(getuid()))) { ! 125: syslog(LOG_ERR, "vacation: no such user uid %u.\n", getuid()); ! 126: myexit(1); ! 127: } ! 128: } ! 129: else if (!(pw = getpwnam(*argv))) { ! 130: syslog(LOG_ERR, "vacation: no such user %s.\n", *argv); ! 131: myexit(1); ! 132: } ! 133: if (chdir(pw->pw_dir)) { ! 134: syslog(LOG_NOTICE, "vacation: no such directory %s.\n", pw->pw_dir); ! 135: myexit(1); ! 136: } ! 137: ! 138: if (iflag || access(VDIR, F_OK)) ! 139: initialize(); ! 140: if (!(db = dbm_open(VACAT, O_RDWR, 0))) { ! 141: syslog(LOG_NOTICE, "vacation: %s: %s\n", VACAT, ! 142: strerror(errno)); ! 143: myexit(1); ! 144: } ! 145: ! 146: if (interval != -1) ! 147: setinterval(interval); ! 148: if (iflag) ! 149: myexit(0); ! 150: ! 151: if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS)))) ! 152: myexit(1); ! 153: cur->name = pw->pw_name; ! 154: cur->next = names; ! 155: names = cur; ! 156: ! 157: readheaders(); ! 158: ! 159: if (!recent()) { ! 160: setreply(); ! 161: sendmessage(pw->pw_name); ! 162: } ! 163: myexit(0); ! 164: /* NOTREACHED */ ! 165: } ! 166: ! 167: /* ! 168: * readheaders -- ! 169: * read mail headers ! 170: */ ! 171: readheaders() ! 172: { ! 173: register ALIAS *cur; ! 174: register char *p; ! 175: int tome, cont; ! 176: char buf[MAXLINE], *strcpy(), *index(); ! 177: ! 178: cont = tome = 0; ! 179: while (fgets(buf, sizeof(buf), stdin) && *buf != '\n') ! 180: switch(*buf) { ! 181: case 'F': /* "From " */ ! 182: cont = 0; ! 183: if (!strncmp(buf, "From ", 5)) { ! 184: for (p = buf + 5; *p && *p != ' '; ++p); ! 185: *p = '\0'; ! 186: (void)strcpy(from, buf + 5); ! 187: if (p = index(from, '\n')) ! 188: *p = '\0'; ! 189: if (junkmail()) ! 190: myexit(0); ! 191: } ! 192: break; ! 193: case 'P': /* "Precedence:" */ ! 194: cont = 0; ! 195: if (strncasecmp(buf, "Precedence", 10) || buf[10] != ':' && buf[10] != ' ' && buf[10] != '\t') ! 196: break; ! 197: if (!(p = index(buf, ':'))) ! 198: break; ! 199: while (*++p && isspace(*p)); ! 200: if (!*p) ! 201: break; ! 202: if (!strncasecmp(p, "junk", 4) || !strncasecmp(p, "bulk", 4)) ! 203: myexit(0); ! 204: break; ! 205: case 'C': /* "Cc:" */ ! 206: if (strncmp(buf, "Cc:", 3)) ! 207: break; ! 208: cont = 1; ! 209: goto findme; ! 210: case 'T': /* "To:" */ ! 211: if (strncmp(buf, "To:", 3)) ! 212: break; ! 213: cont = 1; ! 214: goto findme; ! 215: default: ! 216: if (!isspace(*buf) || !cont || tome) { ! 217: cont = 0; ! 218: break; ! 219: } ! 220: findme: for (cur = names; !tome && cur; cur = cur->next) ! 221: tome += nsearch(cur->name, buf); ! 222: } ! 223: if (!tome) ! 224: myexit(0); ! 225: if (!*from) { ! 226: syslog(LOG_NOTICE, "vacation: no initial \"From\" line.\n"); ! 227: myexit(1); ! 228: } ! 229: } ! 230: ! 231: /* ! 232: * nsearch -- ! 233: * do a nice, slow, search of a string for a substring. ! 234: */ ! 235: nsearch(name, str) ! 236: register char *name, *str; ! 237: { ! 238: register int len; ! 239: ! 240: for (len = strlen(name); *str; ++str) ! 241: if (*str == *name && !strncasecmp(name, str, len)) ! 242: return(1); ! 243: return(0); ! 244: } ! 245: ! 246: /* ! 247: * junkmail -- ! 248: * read the header and return if automagic/junk/bulk mail ! 249: */ ! 250: junkmail() ! 251: { ! 252: static struct ignore { ! 253: char *name; ! 254: int len; ! 255: } ignore[] = { ! 256: "-request", 8, "postmaster", 10, "uucp", 4, ! 257: "mailer-daemon", 13, "mailer", 6, "-relay", 6, ! 258: NULL, NULL, ! 259: }; ! 260: register struct ignore *cur; ! 261: register int len; ! 262: register char *p; ! 263: char *index(), *rindex(); ! 264: ! 265: /* ! 266: * This is mildly amusing, and I'm not positive it's right; trying ! 267: * to find the "real" name of the sender, assuming that addresses ! 268: * will be some variant of: ! 269: * ! 270: * From site!site!SENDER%site.domain%[email protected] ! 271: */ ! 272: if (!(p = index(from, '%'))) ! 273: if (!(p = index(from, '@'))) { ! 274: if (p = rindex(from, '!')) ! 275: ++p; ! 276: else ! 277: p = from; ! 278: for (; *p; ++p); ! 279: } ! 280: len = p - from; ! 281: for (cur = ignore; cur->name; ++cur) ! 282: if (len >= cur->len && !strncasecmp(cur->name, p - cur->len, cur->len)) ! 283: return(1); ! 284: return(0); ! 285: } ! 286: ! 287: /* ! 288: * recent -- ! 289: * find out if user has gotten a vacation message recently. ! 290: * use bcopy for machines with alignment restrictions ! 291: */ ! 292: recent() ! 293: { ! 294: datum key, data; ! 295: time_t then, next, time(); ! 296: ! 297: /* get interval time */ ! 298: key.dptr = VIT; ! 299: key.dsize = sizeof(VIT) - 1; ! 300: data = dbm_fetch(db, key); ! 301: if (data.dptr) ! 302: bcopy(data.dptr, (char *)&next, sizeof(next)); ! 303: else ! 304: next = SECSPERDAY * DAYSPERWEEK; ! 305: ! 306: /* get record for this address */ ! 307: key.dptr = from; ! 308: key.dsize = strlen(from); ! 309: data = dbm_fetch(db, key); ! 310: if (data.dptr) { ! 311: bcopy(data.dptr, (char *)&then, sizeof(then)); ! 312: if (next == LONG_MAX || then + next > time((time_t *)NULL)) ! 313: return(1); ! 314: } ! 315: return(0); ! 316: } ! 317: ! 318: /* ! 319: * setinterval -- ! 320: * store the reply interval ! 321: */ ! 322: setinterval(interval) ! 323: time_t interval; ! 324: { ! 325: datum key, data; ! 326: ! 327: key.dptr = VIT; ! 328: key.dsize = sizeof(VIT) - 1; ! 329: data.dptr = (char *)&interval; ! 330: data.dsize = sizeof(interval); ! 331: dbm_store(db, key, data, DBM_REPLACE); ! 332: } ! 333: ! 334: /* ! 335: * setreply -- ! 336: * store that this user knows about the vacation. ! 337: */ ! 338: setreply() ! 339: { ! 340: datum key, data; ! 341: time_t now, time(); ! 342: ! 343: key.dptr = from; ! 344: key.dsize = strlen(from); ! 345: (void)time(&now); ! 346: data.dptr = (char *)&now; ! 347: data.dsize = sizeof(now); ! 348: dbm_store(db, key, data, DBM_REPLACE); ! 349: } ! 350: ! 351: /* ! 352: * sendmessage -- ! 353: * exec sendmail to send the vacation file to sender ! 354: */ ! 355: sendmessage(myname) ! 356: char *myname; ! 357: { ! 358: if (!freopen(VMSG, "r", stdin)) { ! 359: syslog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", myname, VMSG); ! 360: myexit(1); ! 361: } ! 362: execl(_PATH_SENDMAIL, "sendmail", "-f", myname, from, NULL); ! 363: syslog(LOG_ERR, "vacation: can't exec %s.\n", _PATH_SENDMAIL); ! 364: myexit(1); ! 365: } ! 366: ! 367: /* ! 368: * initialize -- ! 369: * initialize the dbm database ! 370: */ ! 371: initialize() ! 372: { ! 373: int fd; ! 374: ! 375: if ((fd = open(VDIR, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { ! 376: syslog(LOG_NOTICE, "vacation: %s: %s\n", VDIR, strerror(errno)); ! 377: exit(1); ! 378: } ! 379: (void)close(fd); ! 380: if ((fd = open(VPAG, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { ! 381: syslog(LOG_NOTICE, "vacation: %s: %s\n", VPAG, strerror(errno)); ! 382: exit(1); ! 383: } ! 384: (void)close(fd); ! 385: } ! 386: ! 387: /* ! 388: * myexit -- ! 389: * we're outta here... ! 390: */ ! 391: myexit(eval) ! 392: int eval; ! 393: { ! 394: if (db) ! 395: dbm_close(db); ! 396: exit(eval); ! 397: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.