Annotation of 43BSDReno/usr.bin/vacation/vacation.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.