Annotation of 43BSDReno/usr.sbin/sendmail/src/alias.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1983 Eric P. Allman
                      3:  * Copyright (c) 1988 Regents of the University of California.
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms are permitted provided
                      7:  * that: (1) source distributions retain this entire copyright notice and
                      8:  * comment, and (2) distributions including binaries display the following
                      9:  * acknowledgement:  ``This product includes software developed by the
                     10:  * University of California, Berkeley and its contributors'' in the
                     11:  * documentation or other materials provided with the distribution and in
                     12:  * all advertising materials mentioning features or use of this software.
                     13:  * Neither the name of the University nor the names of its contributors may
                     14:  * be used to endorse or promote products derived from this software without
                     15:  * specific prior written permission.
                     16:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     17:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     18:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     19:  */
                     20: 
                     21: #ifndef lint
                     22: #ifdef DBM
                     23: static char sccsid[] = "@(#)alias.c    5.21 (Berkeley) 6/1/90 (with DBM)";
                     24: #else
                     25: static char sccsid[] = "@(#)alias.c    5.21 (Berkeley) 6/1/90 (without DBM)";
                     26: #endif
                     27: #endif /* not lint */
                     28: 
                     29: # include <sys/types.h>
                     30: # include <sys/stat.h>
                     31: # include <signal.h>
                     32: # include <errno.h>
                     33: # include "sendmail.h"
                     34: # include <sys/file.h>
                     35: # include <pwd.h>
                     36: 
                     37: /*
                     38: **  ALIAS -- Compute aliases.
                     39: **
                     40: **     Scans the alias file for an alias for the given address.
                     41: **     If found, it arranges to deliver to the alias list instead.
                     42: **     Uses libdbm database if -DDBM.
                     43: **
                     44: **     Parameters:
                     45: **             a -- address to alias.
                     46: **             sendq -- a pointer to the head of the send queue
                     47: **                     to put the aliases in.
                     48: **
                     49: **     Returns:
                     50: **             none
                     51: **
                     52: **     Side Effects:
                     53: **             Aliases found are expanded.
                     54: **
                     55: **     Notes:
                     56: **             If NoAlias (the "-n" flag) is set, no aliasing is
                     57: **                     done.
                     58: **
                     59: **     Deficiencies:
                     60: **             It should complain about names that are aliased to
                     61: **                     nothing.
                     62: */
                     63: 
                     64: 
                     65: #ifdef DBM
                     66: typedef struct
                     67: {
                     68:        char    *dptr;
                     69:        int     dsize;
                     70: } DATUM;
                     71: extern DATUM fetch();
                     72: #endif DBM
                     73: 
                     74: alias(a, sendq)
                     75:        register ADDRESS *a;
                     76:        ADDRESS **sendq;
                     77: {
                     78:        register char *p;
                     79:        extern char *aliaslookup();
                     80: 
                     81:        if (tTd(27, 1))
                     82:                printf("alias(%s)\n", a->q_paddr);
                     83: 
                     84:        /* don't realias already aliased names */
                     85:        if (bitset(QDONTSEND, a->q_flags))
                     86:                return;
                     87: 
                     88:        CurEnv->e_to = a->q_paddr;
                     89: 
                     90:        /*
                     91:        **  Look up this name
                     92:        */
                     93: 
                     94:        if (NoAlias)
                     95:                p = NULL;
                     96:        else
                     97:                p = aliaslookup(a->q_user);
                     98:        if (p == NULL)
                     99:                return;
                    100: 
                    101:        /*
                    102:        **  Match on Alias.
                    103:        **      Deliver to the target list.
                    104:        */
                    105: 
                    106:        if (tTd(27, 1))
                    107:                printf("%s (%s, %s) aliased to %s\n",
                    108:                    a->q_paddr, a->q_host, a->q_user, p);
                    109:        message(Arpa_Info, "aliased to %s", p);
                    110:        AliasLevel++;
                    111:        sendtolist(p, a, sendq);
                    112:        AliasLevel--;
                    113: }
                    114: /*
                    115: **  ALIASLOOKUP -- look up a name in the alias file.
                    116: **
                    117: **     Parameters:
                    118: **             name -- the name to look up.
                    119: **
                    120: **     Returns:
                    121: **             the value of name.
                    122: **             NULL if unknown.
                    123: **
                    124: **     Side Effects:
                    125: **             none.
                    126: **
                    127: **     Warnings:
                    128: **             The return value will be trashed across calls.
                    129: */
                    130: 
                    131: char *
                    132: aliaslookup(name)
                    133:        char *name;
                    134: {
                    135: # ifdef DBM
                    136:        DATUM rhs, lhs;
                    137: 
                    138:        /* create a key for fetch */
                    139:        lhs.dptr = name;
                    140:        lhs.dsize = strlen(name) + 1;
                    141:        rhs = fetch(lhs);
                    142:        return (rhs.dptr);
                    143: # else DBM
                    144:        register STAB *s;
                    145: 
                    146:        s = stab(name, ST_ALIAS, ST_FIND);
                    147:        if (s == NULL)
                    148:                return (NULL);
                    149:        return (s->s_alias);
                    150: # endif DBM
                    151: }
                    152: /*
                    153: **  INITALIASES -- initialize for aliasing
                    154: **
                    155: **     Very different depending on whether we are running DBM or not.
                    156: **
                    157: **     Parameters:
                    158: **             aliasfile -- location of aliases.
                    159: **             init -- if set and if DBM, initialize the DBM files.
                    160: **
                    161: **     Returns:
                    162: **             none.
                    163: **
                    164: **     Side Effects:
                    165: **             initializes aliases:
                    166: **             if DBM:  opens the database.
                    167: **             if ~DBM: reads the aliases into the symbol table.
                    168: */
                    169: 
                    170: # define DBMMODE       0644
                    171: 
                    172: initaliases(aliasfile, init)
                    173:        char *aliasfile;
                    174:        bool init;
                    175: {
                    176: #ifdef DBM
                    177:        int atcnt;
                    178:        time_t modtime;
                    179:        bool automatic = FALSE;
                    180:        char buf[MAXNAME];
                    181: #endif DBM
                    182:        struct stat stb;
                    183:        static bool initialized = FALSE;
                    184: 
                    185:        if (initialized)
                    186:                return;
                    187:        initialized = TRUE;
                    188: 
                    189:        if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
                    190:        {
                    191:                if (aliasfile != NULL && init)
                    192:                        syserr("Cannot open %s", aliasfile);
                    193:                NoAlias = TRUE;
                    194:                errno = 0;
                    195:                return;
                    196:        }
                    197: 
                    198: # ifdef DBM
                    199:        /*
                    200:        **  Check to see that the alias file is complete.
                    201:        **      If not, we will assume that someone died, and it is up
                    202:        **      to us to rebuild it.
                    203:        */
                    204: 
                    205:        if (!init)
                    206:                dbminit(aliasfile);
                    207:        atcnt = SafeAlias * 2;
                    208:        if (atcnt > 0)
                    209:        {
                    210:                while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
                    211:                {
                    212:                        /*
                    213:                        **  Reinitialize alias file in case the new
                    214:                        **  one is mv'ed in instead of cp'ed in.
                    215:                        **
                    216:                        **      Only works with new DBM -- old one will
                    217:                        **      just consume file descriptors forever.
                    218:                        **      If you have a dbmclose() it can be
                    219:                        **      added before the sleep(30).
                    220:                        */
                    221: 
                    222:                        sleep(30);
                    223: # ifdef NDBM
                    224:                        dbminit(aliasfile);
                    225: # endif NDBM
                    226:                }
                    227:        }
                    228:        else
                    229:                atcnt = 1;
                    230: 
                    231:        /*
                    232:        **  See if the DBM version of the file is out of date with
                    233:        **  the text version.  If so, go into 'init' mode automatically.
                    234:        **      This only happens if our effective userid owns the DBM.
                    235:        **      Note the unpalatable hack to see if the stat succeeded.
                    236:        */
                    237: 
                    238:        modtime = stb.st_mtime;
                    239:        (void) strcpy(buf, aliasfile);
                    240:        (void) strcat(buf, ".pag");
                    241:        stb.st_ino = 0;
                    242:        if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
                    243:        {
                    244:                errno = 0;
                    245:                if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
                    246:                {
                    247:                        init = TRUE;
                    248:                        automatic = TRUE;
                    249:                        message(Arpa_Info, "rebuilding alias database");
                    250: #ifdef LOG
                    251:                        if (LogLevel >= 7)
                    252:                                syslog(LOG_INFO, "rebuilding alias database");
                    253: #endif LOG
                    254:                }
                    255:                else
                    256:                {
                    257: #ifdef LOG
                    258:                        if (LogLevel >= 7)
                    259:                                syslog(LOG_INFO, "alias database out of date");
                    260: #endif LOG
                    261:                        message(Arpa_Info, "Warning: alias database out of date");
                    262:                }
                    263:        }
                    264: 
                    265: 
                    266:        /*
                    267:        **  If necessary, load the DBM file.
                    268:        **      If running without DBM, load the symbol table.
                    269:        */
                    270: 
                    271:        if (init)
                    272:        {
                    273: #ifdef LOG
                    274:                if (LogLevel >= 6)
                    275:                {
                    276:                        extern char *username();
                    277: 
                    278:                        syslog(LOG_NOTICE, "alias database %srebuilt by %s",
                    279:                                automatic ? "auto" : "", username());
                    280:                }
                    281: #endif LOG
                    282:                readaliases(aliasfile, TRUE);
                    283:        }
                    284: # else DBM
                    285:        readaliases(aliasfile, init);
                    286: # endif DBM
                    287: }
                    288: /*
                    289: **  READALIASES -- read and process the alias file.
                    290: **
                    291: **     This routine implements the part of initaliases that occurs
                    292: **     when we are not going to use the DBM stuff.
                    293: **
                    294: **     Parameters:
                    295: **             aliasfile -- the pathname of the alias file master.
                    296: **             init -- if set, initialize the DBM stuff.
                    297: **
                    298: **     Returns:
                    299: **             none.
                    300: **
                    301: **     Side Effects:
                    302: **             Reads aliasfile into the symbol table.
                    303: **             Optionally, builds the .dir & .pag files.
                    304: */
                    305: 
                    306: static
                    307: readaliases(aliasfile, init)
                    308:        char *aliasfile;
                    309:        bool init;
                    310: {
                    311:        register char *p;
                    312:        char *rhs;
                    313:        bool skipping;
                    314:        int naliases, bytes, longest;
                    315:        FILE *af;
                    316:        void (*oldsigint)();
                    317:        ADDRESS al, bl;
                    318:        register STAB *s;
                    319:        char line[BUFSIZ];
                    320: 
                    321:        if ((af = fopen(aliasfile, "r")) == NULL)
                    322:        {
                    323:                if (tTd(27, 1))
                    324:                        printf("Can't open %s\n", aliasfile);
                    325:                errno = 0;
                    326:                NoAlias++;
                    327:                return;
                    328:        }
                    329: 
                    330: # ifdef DBM
                    331:        /* see if someone else is rebuilding the alias file already */
                    332:        if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
                    333:        {
                    334:                /* yes, they are -- wait until done and then return */
                    335:                message(Arpa_Info, "Alias file is already being rebuilt");
                    336:                if (OpMode != MD_INITALIAS)
                    337:                {
                    338:                        /* wait for other rebuild to complete */
                    339:                        (void) flock(fileno(af), LOCK_EX);
                    340:                }
                    341:                (void) fclose(af);
                    342:                errno = 0;
                    343:                return;
                    344:        }
                    345: # endif DBM
                    346: 
                    347:        /*
                    348:        **  If initializing, create the new DBM files.
                    349:        */
                    350: 
                    351:        if (init)
                    352:        {
                    353:                oldsigint = signal(SIGINT, SIG_IGN);
                    354:                (void) strcpy(line, aliasfile);
                    355:                (void) strcat(line, ".dir");
                    356:                if (close(creat(line, DBMMODE)) < 0)
                    357:                {
                    358:                        syserr("cannot make %s", line);
                    359:                        (void) signal(SIGINT, oldsigint);
                    360:                        return;
                    361:                }
                    362:                (void) strcpy(line, aliasfile);
                    363:                (void) strcat(line, ".pag");
                    364:                if (close(creat(line, DBMMODE)) < 0)
                    365:                {
                    366:                        syserr("cannot make %s", line);
                    367:                        (void) signal(SIGINT, oldsigint);
                    368:                        return;
                    369:                }
                    370:                dbminit(aliasfile);
                    371:        }
                    372: 
                    373:        /*
                    374:        **  Read and interpret lines
                    375:        */
                    376: 
                    377:        FileName = aliasfile;
                    378:        LineNumber = 0;
                    379:        naliases = bytes = longest = 0;
                    380:        skipping = FALSE;
                    381:        while (fgets(line, sizeof (line), af) != NULL)
                    382:        {
                    383:                int lhssize, rhssize;
                    384: 
                    385:                LineNumber++;
                    386:                p = index(line, '\n');
                    387:                if (p != NULL)
                    388:                        *p = '\0';
                    389:                switch (line[0])
                    390:                {
                    391:                  case '#':
                    392:                  case '\0':
                    393:                        skipping = FALSE;
                    394:                        continue;
                    395: 
                    396:                  case ' ':
                    397:                  case '\t':
                    398:                        if (!skipping)
                    399:                                syserr("Non-continuation line starts with space");
                    400:                        skipping = TRUE;
                    401:                        continue;
                    402:                }
                    403:                skipping = FALSE;
                    404: 
                    405:                /*
                    406:                **  Process the LHS
                    407:                **      Find the final colon, and parse the address.
                    408:                **      It should resolve to a local name -- this will
                    409:                **      be checked later (we want to optionally do
                    410:                **      parsing of the RHS first to maximize error
                    411:                **      detection).
                    412:                */
                    413: 
                    414:                for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
                    415:                        continue;
                    416:                if (*p++ != ':')
                    417:                {
                    418:                        syserr("missing colon");
                    419:                        continue;
                    420:                }
                    421:                if (parseaddr(line, &al, 1, ':') == NULL)
                    422:                {
                    423:                        syserr("illegal alias name");
                    424:                        continue;
                    425:                }
                    426:                loweraddr(&al);
                    427: 
                    428:                /*
                    429:                **  Process the RHS.
                    430:                **      'al' is the internal form of the LHS address.
                    431:                **      'p' points to the text of the RHS.
                    432:                */
                    433: 
                    434:                rhs = p;
                    435:                for (;;)
                    436:                {
                    437:                        register char c;
                    438: 
                    439:                        if (init && CheckAliases)
                    440:                        {
                    441:                                /* do parsing & compression of addresses */
                    442:                                while (*p != '\0')
                    443:                                {
                    444:                                        extern char *DelimChar;
                    445: 
                    446:                                        while (isspace(*p) || *p == ',')
                    447:                                                p++;
                    448:                                        if (*p == '\0')
                    449:                                                break;
                    450:                                        if (parseaddr(p, &bl, -1, ',') == NULL)
                    451:                                                usrerr("%s... bad address", p);
                    452:                                        p = DelimChar;
                    453:                                }
                    454:                        }
                    455:                        else
                    456:                        {
                    457:                                p = &p[strlen(p)];
                    458:                                if (p[-1] == '\n')
                    459:                                        *--p = '\0';
                    460:                        }
                    461: 
                    462:                        /* see if there should be a continuation line */
                    463:                        c = fgetc(af);
                    464:                        if (!feof(af))
                    465:                                (void) ungetc(c, af);
                    466:                        if (c != ' ' && c != '\t')
                    467:                                break;
                    468: 
                    469:                        /* read continuation line */
                    470:                        if (fgets(p, sizeof line - (p - line), af) == NULL)
                    471:                                break;
                    472:                        LineNumber++;
                    473:                }
                    474:                if (al.q_mailer != LocalMailer)
                    475:                {
                    476:                        syserr("cannot alias non-local names");
                    477:                        continue;
                    478:                }
                    479: 
                    480:                /*
                    481:                **  Insert alias into symbol table or DBM file
                    482:                */
                    483: 
                    484:                lhssize = strlen(al.q_user) + 1;
                    485:                rhssize = strlen(rhs) + 1;
                    486: 
                    487: # ifdef DBM
                    488:                if (init)
                    489:                {
                    490:                        DATUM key, content;
                    491: 
                    492:                        key.dsize = lhssize;
                    493:                        key.dptr = al.q_user;
                    494:                        content.dsize = rhssize;
                    495:                        content.dptr = rhs;
                    496:                        store(key, content);
                    497:                }
                    498:                else
                    499: # endif DBM
                    500:                {
                    501:                        s = stab(al.q_user, ST_ALIAS, ST_ENTER);
                    502:                        s->s_alias = newstr(rhs);
                    503:                }
                    504: 
                    505:                /* statistics */
                    506:                naliases++;
                    507:                bytes += lhssize + rhssize;
                    508:                if (rhssize > longest)
                    509:                        longest = rhssize;
                    510:        }
                    511: 
                    512: # ifdef DBM
                    513:        if (init)
                    514:        {
                    515:                /* add the distinquished alias "@" */
                    516:                DATUM key;
                    517: 
                    518:                key.dsize = 2;
                    519:                key.dptr = "@";
                    520:                store(key, key);
                    521: 
                    522:                /* restore the old signal */
                    523:                (void) signal(SIGINT, oldsigint);
                    524:        }
                    525: # endif DBM
                    526: 
                    527:        /* closing the alias file drops the lock */
                    528:        (void) fclose(af);
                    529:        CurEnv->e_to = NULL;
                    530:        FileName = NULL;
                    531:        message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
                    532:                        naliases, longest, bytes);
                    533: # ifdef LOG
                    534:        if (LogLevel >= 8)
                    535:                syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
                    536:                        naliases, longest, bytes);
                    537: # endif LOG
                    538: }
                    539: /*
                    540: **  FORWARD -- Try to forward mail
                    541: **
                    542: **     This is similar but not identical to aliasing.
                    543: **
                    544: **     Parameters:
                    545: **             user -- the name of the user who's mail we would like
                    546: **                     to forward to.  It must have been verified --
                    547: **                     i.e., the q_home field must have been filled
                    548: **                     in.
                    549: **             sendq -- a pointer to the head of the send queue to
                    550: **                     put this user's aliases in.
                    551: **
                    552: **     Returns:
                    553: **             none.
                    554: **
                    555: **     Side Effects:
                    556: **             New names are added to send queues.
                    557: */
                    558: 
                    559: forward(user, sendq)
                    560:        ADDRESS *user;
                    561:        ADDRESS **sendq;
                    562: {
                    563:        char buf[60];
                    564:        extern bool safefile();
                    565: 
                    566:        if (tTd(27, 1))
                    567:                printf("forward(%s)\n", user->q_paddr);
                    568: 
                    569:        if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
                    570:                return;
                    571:        if (user->q_home == NULL)
                    572:                syserr("forward: no home");
                    573: 
                    574:        /* good address -- look for .forward file in home */
                    575:        define('z', user->q_home, CurEnv);
                    576:        expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
                    577:        if (!safefile(buf, user->q_uid, S_IREAD))
                    578:                return;
                    579: 
                    580:        /* we do have an address to forward to -- do it */
                    581:        include(buf, "forwarding", user, sendq);
                    582: }

unix.superglobalmegacorp.com

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