Annotation of 43BSD/usr.lib/sendmail/src/alias.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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