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

unix.superglobalmegacorp.com

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