[BACK]Return to vacation.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / vacation

Annotation of src/usr.bin/vacation/vacation.c, Revision 1.1.1.1

1.1       deraadt     1: /*     $NetBSD: vacation.c,v 1.7 1995/04/29 05:58:27 cgd Exp $ */
                      2:
                      3: /*
                      4:  * Copyright (c) 1983, 1987, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *     This product includes software developed by the University of
                     18:  *     California, Berkeley and its contributors.
                     19:  * 4. Neither the name of the University nor the names of its contributors
                     20:  *    may be used to endorse or promote products derived from this software
                     21:  *    without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     33:  * SUCH DAMAGE.
                     34:  */
                     35:
                     36: #ifndef lint
                     37: static char copyright[] =
                     38: "@(#) Copyright (c) 1983, 1987, 1993\n\
                     39:        The Regents of the University of California.  All rights reserved.\n";
                     40: #endif /* not lint */
                     41:
                     42: #ifndef lint
                     43: #if 0
                     44: static char sccsid[] = "@(#)vacation.c 8.2 (Berkeley) 1/26/94";
                     45: #endif
                     46: static char rcsid[] = "$NetBSD: vacation.c,v 1.7 1995/04/29 05:58:27 cgd Exp $";
                     47: #endif /* not lint */
                     48:
                     49: /*
                     50: **  Vacation
                     51: **  Copyright (c) 1983  Eric P. Allman
                     52: **  Berkeley, California
                     53: */
                     54:
                     55: #include <sys/param.h>
                     56: #include <sys/stat.h>
                     57: #include <fcntl.h>
                     58: #include <pwd.h>
                     59: #include <db.h>
                     60: #include <time.h>
                     61: #include <syslog.h>
                     62: #include <tzfile.h>
                     63: #include <errno.h>
                     64: #include <unistd.h>
                     65: #include <stdio.h>
                     66: #include <ctype.h>
                     67: #include <stdlib.h>
                     68: #include <string.h>
                     69: #include <paths.h>
                     70:
                     71: /*
                     72:  *  VACATION -- return a message to the sender when on vacation.
                     73:  *
                     74:  *     This program is invoked as a message receiver.  It returns a
                     75:  *     message specified by the user to whomever sent the mail, taking
                     76:  *     care not to return a message too often to prevent "I am on
                     77:  *     vacation" loops.
                     78:  */
                     79:
                     80: #define        MAXLINE 1024                    /* max line from mail header */
                     81: #define        VDB     ".vacation.db"          /* dbm's database */
                     82: #define        VMSG    ".vacation.msg"         /* vacation message */
                     83:
                     84: typedef struct alias {
                     85:        struct alias *next;
                     86:        char *name;
                     87: } ALIAS;
                     88: ALIAS *names;
                     89:
                     90: DB *db;
                     91: char from[MAXLINE];
                     92:
                     93: int junkmail __P((void));
                     94: int nsearch __P((char *, char *));
                     95: void readheaders __P((void));
                     96: int recent __P((void));
                     97: void sendmessage __P((char *));
                     98: void setinterval __P((time_t));
                     99: void setreply __P((void));
                    100: void usage __P((void));
                    101:
                    102: int
                    103: main(argc, argv)
                    104:        int argc;
                    105:        char **argv;
                    106: {
                    107:        extern int optind, opterr;
                    108:        extern char *optarg;
                    109:        struct passwd *pw;
                    110:        ALIAS *cur;
                    111:        time_t interval;
                    112:        int ch, iflag;
                    113:
                    114:        opterr = iflag = 0;
                    115:        interval = -1;
                    116:        while ((ch = getopt(argc, argv, "a:Iir:")) != EOF)
                    117:                switch((char)ch) {
                    118:                case 'a':                       /* alias */
                    119:                        if (!(cur = (ALIAS *)malloc((u_int)sizeof(ALIAS))))
                    120:                                break;
                    121:                        cur->name = optarg;
                    122:                        cur->next = names;
                    123:                        names = cur;
                    124:                        break;
                    125:                case 'I':                       /* backward compatible */
                    126:                case 'i':                       /* init the database */
                    127:                        iflag = 1;
                    128:                        break;
                    129:                case 'r':
                    130:                        if (isdigit(*optarg)) {
                    131:                                interval = atol(optarg) * SECSPERDAY;
                    132:                                if (interval < 0)
                    133:                                        usage();
                    134:                        }
                    135:                        else
                    136:                                interval = (time_t)LONG_MAX;    /* XXX */
                    137:                        break;
                    138:                case '?':
                    139:                default:
                    140:                        usage();
                    141:                }
                    142:        argc -= optind;
                    143:        argv += optind;
                    144:
                    145:        if (argc != 1) {
                    146:                if (!iflag)
                    147:                        usage();
                    148:                if (!(pw = getpwuid(getuid()))) {
                    149:                        syslog(LOG_ERR,
                    150:                            "vacation: no such user uid %u.\n", getuid());
                    151:                        exit(1);
                    152:                }
                    153:        }
                    154:        else if (!(pw = getpwnam(*argv))) {
                    155:                syslog(LOG_ERR, "vacation: no such user %s.\n", *argv);
                    156:                exit(1);
                    157:        }
                    158:        if (chdir(pw->pw_dir)) {
                    159:                syslog(LOG_NOTICE,
                    160:                    "vacation: no such directory %s.\n", pw->pw_dir);
                    161:                exit(1);
                    162:        }
                    163:
                    164:        db = dbopen(VDB, O_CREAT|O_RDWR | (iflag ? O_TRUNC : 0),
                    165:            S_IRUSR|S_IWUSR, DB_HASH, NULL);
                    166:        if (!db) {
                    167:                syslog(LOG_NOTICE, "vacation: %s: %s\n", VDB, strerror(errno));
                    168:                exit(1);
                    169:        }
                    170:
                    171:        if (interval != -1)
                    172:                setinterval(interval);
                    173:
                    174:        if (iflag) {
                    175:                (void)(db->close)(db);
                    176:                exit(0);
                    177:        }
                    178:
                    179:        if (!(cur = malloc((u_int)sizeof(ALIAS))))
                    180:                exit(1);
                    181:        cur->name = pw->pw_name;
                    182:        cur->next = names;
                    183:        names = cur;
                    184:
                    185:        readheaders();
                    186:        if (!recent()) {
                    187:                setreply();
                    188:                (void)(db->close)(db);
                    189:                sendmessage(pw->pw_name);
                    190:        }
                    191:        else
                    192:                (void)(db->close)(db);
                    193:        exit(0);
                    194:        /* NOTREACHED */
                    195: }
                    196:
                    197: /*
                    198:  * readheaders --
                    199:  *     read mail headers
                    200:  */
                    201: void
                    202: readheaders()
                    203: {
                    204:        register ALIAS *cur;
                    205:        register char *p;
                    206:        int tome, cont;
                    207:        char buf[MAXLINE];
                    208:
                    209:        cont = tome = 0;
                    210:        while (fgets(buf, sizeof(buf), stdin) && *buf != '\n')
                    211:                switch(*buf) {
                    212:                case 'F':               /* "From " */
                    213:                        cont = 0;
                    214:                        if (!strncmp(buf, "From ", 5)) {
                    215:                                for (p = buf + 5; *p && *p != ' '; ++p);
                    216:                                *p = '\0';
                    217:                                (void)strcpy(from, buf + 5);
                    218:                                if (p = index(from, '\n'))
                    219:                                        *p = '\0';
                    220:                                if (junkmail())
                    221:                                        exit(0);
                    222:                        }
                    223:                        break;
                    224:                case 'P':               /* "Precedence:" */
                    225:                        cont = 0;
                    226:                        if (strncasecmp(buf, "Precedence", 10) ||
                    227:                            buf[10] != ':' && buf[10] != ' ' && buf[10] != '\t')
                    228:                                break;
                    229:                        if (!(p = index(buf, ':')))
                    230:                                break;
                    231:                        while (*++p && isspace(*p));
                    232:                        if (!*p)
                    233:                                break;
                    234:                        if (!strncasecmp(p, "junk", 4) ||
                    235:                            !strncasecmp(p, "bulk", 4) ||
                    236:                            !strncasecmp(p, "list", 4))
                    237:                                exit(0);
                    238:                        break;
                    239:                case 'C':               /* "Cc:" */
                    240:                        if (strncmp(buf, "Cc:", 3))
                    241:                                break;
                    242:                        cont = 1;
                    243:                        goto findme;
                    244:                case 'T':               /* "To:" */
                    245:                        if (strncmp(buf, "To:", 3))
                    246:                                break;
                    247:                        cont = 1;
                    248:                        goto findme;
                    249:                default:
                    250:                        if (!isspace(*buf) || !cont || tome) {
                    251:                                cont = 0;
                    252:                                break;
                    253:                        }
                    254: findme:                        for (cur = names; !tome && cur; cur = cur->next)
                    255:                                tome += nsearch(cur->name, buf);
                    256:                }
                    257:        if (!tome)
                    258:                exit(0);
                    259:        if (!*from) {
                    260:                syslog(LOG_NOTICE, "vacation: no initial \"From\" line.\n");
                    261:                exit(1);
                    262:        }
                    263: }
                    264:
                    265: /*
                    266:  * nsearch --
                    267:  *     do a nice, slow, search of a string for a substring.
                    268:  */
                    269: int
                    270: nsearch(name, str)
                    271:        register char *name, *str;
                    272: {
                    273:        register int len;
                    274:
                    275:        for (len = strlen(name); *str; ++str)
                    276:                if (*str == *name && !strncasecmp(name, str, len))
                    277:                        return(1);
                    278:        return(0);
                    279: }
                    280:
                    281: /*
                    282:  * junkmail --
                    283:  *     read the header and return if automagic/junk/bulk/list mail
                    284:  */
                    285: int
                    286: junkmail()
                    287: {
                    288:        static struct ignore {
                    289:                char    *name;
                    290:                int     len;
                    291:        } ignore[] = {
                    292:                "-request", 8,          "postmaster", 10,       "uucp", 4,
                    293:                "mailer-daemon", 13,    "mailer", 6,            "-relay", 6,
                    294:                NULL, NULL,
                    295:        };
                    296:        register struct ignore *cur;
                    297:        register int len;
                    298:        register char *p;
                    299:
                    300:        /*
                    301:         * This is mildly amusing, and I'm not positive it's right; trying
                    302:         * to find the "real" name of the sender, assuming that addresses
                    303:         * will be some variant of:
                    304:         *
                    305:         * From site!site!SENDER%site.domain%site.domain@site.domain
                    306:         */
                    307:        if (!(p = index(from, '%')))
                    308:                if (!(p = index(from, '@'))) {
                    309:                        if (p = rindex(from, '!'))
                    310:                                ++p;
                    311:                        else
                    312:                                p = from;
                    313:                        for (; *p; ++p);
                    314:                }
                    315:        len = p - from;
                    316:        for (cur = ignore; cur->name; ++cur)
                    317:                if (len >= cur->len &&
                    318:                    !strncasecmp(cur->name, p - cur->len, cur->len))
                    319:                        return(1);
                    320:        return(0);
                    321: }
                    322:
                    323: #define        VIT     "__VACATION__INTERVAL__TIMER__"
                    324:
                    325: /*
                    326:  * recent --
                    327:  *     find out if user has gotten a vacation message recently.
                    328:  *     use bcopy for machines with alignment restrictions
                    329:  */
                    330: int
                    331: recent()
                    332: {
                    333:        DBT key, data;
                    334:        time_t then, next;
                    335:
                    336:        /* get interval time */
                    337:        key.data = VIT;
                    338:        key.size = sizeof(VIT);
                    339:        if ((db->get)(db, &key, &data, 0))
                    340:                next = SECSPERDAY * DAYSPERWEEK;
                    341:        else
                    342:                bcopy(data.data, &next, sizeof(next));
                    343:
                    344:        /* get record for this address */
                    345:        key.data = from;
                    346:        key.size = strlen(from);
                    347:        if (!(db->get)(db, &key, &data, 0)) {
                    348:                bcopy(data.data, &then, sizeof(then));
                    349:                if (next == (time_t)LONG_MAX ||                 /* XXX */
                    350:                    then + next > time(NULL))
                    351:                        return(1);
                    352:        }
                    353:        return(0);
                    354: }
                    355:
                    356: /*
                    357:  * setinterval --
                    358:  *     store the reply interval
                    359:  */
                    360: void
                    361: setinterval(interval)
                    362:        time_t interval;
                    363: {
                    364:        DBT key, data;
                    365:
                    366:        key.data = VIT;
                    367:        key.size = sizeof(VIT);
                    368:        data.data = &interval;
                    369:        data.size = sizeof(interval);
                    370:        (void)(db->put)(db, &key, &data, 0);
                    371: }
                    372:
                    373: /*
                    374:  * setreply --
                    375:  *     store that this user knows about the vacation.
                    376:  */
                    377: void
                    378: setreply()
                    379: {
                    380:        DBT key, data;
                    381:        time_t now;
                    382:
                    383:        key.data = from;
                    384:        key.size = strlen(from);
                    385:        (void)time(&now);
                    386:        data.data = &now;
                    387:        data.size = sizeof(now);
                    388:        (void)(db->put)(db, &key, &data, 0);
                    389: }
                    390:
                    391: /*
                    392:  * sendmessage --
                    393:  *     exec sendmail to send the vacation file to sender
                    394:  */
                    395: void
                    396: sendmessage(myname)
                    397:        char *myname;
                    398: {
                    399:        FILE *mfp, *sfp;
                    400:        int i;
                    401:        int pvect[2];
                    402:        char buf[MAXLINE];
                    403:
                    404:        mfp = fopen(VMSG, "r");
                    405:        if (mfp == NULL) {
                    406:                syslog(LOG_NOTICE, "vacation: no ~%s/%s file.\n", myname, VMSG);
                    407:                exit(1);
                    408:        }
                    409:        if (pipe(pvect) < 0) {
                    410:                syslog(LOG_ERR, "vacation: pipe: %s", strerror(errno));
                    411:                exit(1);
                    412:        }
                    413:        i = vfork();
                    414:        if (i < 0) {
                    415:                syslog(LOG_ERR, "vacation: fork: %s", strerror(errno));
                    416:                exit(1);
                    417:        }
                    418:        if (i == 0) {
                    419:                dup2(pvect[0], 0);
                    420:                close(pvect[0]);
                    421:                close(pvect[1]);
                    422:                fclose(mfp);
                    423:                execl(_PATH_SENDMAIL, "sendmail", "-f", myname, from, NULL);
                    424:                syslog(LOG_ERR, "vacation: can't exec %s: %s",
                    425:                        _PATH_SENDMAIL, strerror(errno));
                    426:                exit(1);
                    427:        }
                    428:        close(pvect[0]);
                    429:        sfp = fdopen(pvect[1], "w");
                    430:        fprintf(sfp, "To: %s\n", from);
                    431:        while (fgets(buf, sizeof buf, mfp))
                    432:                fputs(buf, sfp);
                    433:        fclose(mfp);
                    434:        fclose(sfp);
                    435: }
                    436:
                    437: void
                    438: usage()
                    439: {
                    440:        syslog(LOG_NOTICE, "uid %u: usage: vacation [-i] [-a alias] login\n",
                    441:            getuid());
                    442:        exit(1);
                    443: }