Annotation of coherent/a/tmp/smail/alias.c, revision 1.1.1.1

1.1       root        1: #ifndef lint
                      2: static char *sccsid = "@(#)alias.c     2.5 (smail) 9/15/87";
                      3: #endif
                      4: 
                      5: #include <stdio.h>
                      6: #include <sys/types.h>
                      7: #include <sys/stat.h>
                      8: #include <pwd.h>
                      9: #include "defs.h"
                     10: #include <ctype.h>
                     11: 
                     12: extern enum edebug debug;      /* verbose and debug modes              */
                     13: extern char hostdomain[];
                     14: extern char hostname[];
                     15: extern char *aliasfile;
                     16: #ifdef HOMEALIASES
                     17: extern char *homealias;
                     18: #endif /* HOMEALIASES */
                     19: 
                     20: /*
                     21: **
                     22: ** Picture of the alias graph structure
                     23: **
                     24: **     head
                     25: **       |
                     26: **       v
                     27: **     maps -> mark -> gjm -> mel -> NNULL
                     28: **       |
                     29: **       v
                     30: **     sys ->  root -> ron -> NNULL
                     31: **       |
                     32: **       v
                     33: **     root -> mark -> chris -> lda -> NNULL
                     34: **       |
                     35: **       v
                     36: **      NNULL
                     37: */
                     38: 
                     39: typedef struct alias_node node;
                     40: 
                     41: static struct alias_node {
                     42:        char *string;
                     43:        node *horz;
                     44:        node *vert;
                     45: };
                     46: 
                     47: #ifndef SENDMAIL
                     48: static node aliases = {"", 0, 0}; /* this is the 'dummy header' */
                     49: #endif /* not SENDMAIL */
                     50: 
                     51: /*
                     52: ** lint free forms of NULL
                     53: */
                     54: 
                     55: #define NNULL  ((node   *) 0)
                     56: #define CNULL  ('\0')
                     57: 
                     58: #define TRUE ((int) (1==1))
                     59: #define FALSE ((int) (1==2))
                     60: /*
                     61: ** string parsing macros
                     62: */
                     63: #define SKIPWORD(Z)  while(*Z!=' ' && *Z!='\t' && *Z!='\n' && *Z!=',') Z++;
                     64: #define SKIPSPACE(Z) while(*Z==' ' || *Z=='\t' || *Z=='\n' || *Z==',') Z++;
                     65: 
                     66: static int nargc = 0;
                     67: static char *nargv[MAXARGS];
                     68: static int no_backslash = TRUE;
                     69: static int last_no_backslash = TRUE;
                     70: 
                     71: void   add_horz();
                     72: void   load_alias(), strip_comments();
                     73: int    recipients();
                     74: node   *pop();
                     75: #ifndef SENDMAIL
                     76: node   *v_search(), *h_search();
                     77: char   *tilde();
                     78: #endif /* not SENDMAIL */
                     79: 
                     80: /* our horizontal linked list looks like a stack */
                     81: #define push           add_horz
                     82: 
                     83: #define escape(s)      ((*s != '\\') ? (s) : (s+1))
                     84: 
                     85: char **
                     86: alias(pargc, argv)
                     87: int *pargc;
                     88: char **argv;
                     89: {
                     90: /*
                     91: **  alias the addresses
                     92: */
                     93:        int     i;
                     94:        char    domain[SMLBUF], ubuf[SMLBUF], *user;
                     95:        node    *addr, addrstk;
                     96:        node    *flist,  fliststk, *u;
                     97: 
                     98: #ifndef SENDMAIL
                     99:        FILE    *fp;
                    100:        node    *a;
                    101:        char    *home, buf[SMLBUF];
                    102:        int     aliased;
                    103:        struct  stat st;
                    104: #endif /* not SENDMAIL */
                    105: 
                    106: #ifdef FULLNAME
                    107:        char *res_fname();      /* Does fullname processing */
                    108: #endif
                    109: 
                    110:        addr  = &addrstk;
                    111:        flist = &fliststk;
                    112:        user  = ubuf;
                    113: 
                    114:        addr->horz = NNULL;
                    115:        flist->horz  = NNULL;
                    116: 
                    117:        /*
                    118:        ** push all of the addresses onto a stack
                    119:        */
                    120:        for(i=0; i < *pargc; i++) {
                    121:                push(addr, argv[i]);
                    122:        }
                    123: 
                    124:        /*
                    125:        ** for each adress, check for included files, aliases,
                    126:        ** full name mapping, and .forward files
                    127:        */
                    128: 
                    129:        while((nargc < MAXARGS) && ((u = pop(addr)) != NNULL)) {
                    130: #ifndef SENDMAIL
                    131:                if(strncmpic(u->string, ":include:", 9) == 0) {
                    132:                        /*
                    133:                        ** make sure it's a full path name
                    134:                        ** don't allow multiple sourcing
                    135:                        ** of a given include file
                    136:                        */
                    137:                        char *p = u->string + 9;
                    138: 
                    139:                        if((*p == '/')
                    140:                        && (h_search(flist, p) == NULL)) {
                    141:                                push(flist, p);
                    142:                                if((stat(p, &st) >= 0)
                    143:                                &&((st.st_mode & S_IFMT) == S_IFREG)
                    144:                                &&((fp = fopen(p, "r")) != NULL)) {
                    145:                                        while(fgets(buf, sizeof buf, fp)) {
                    146:                                                (void) recipients(addr, buf);
                    147:                                        }
                    148:                                        (void) fclose(fp);
                    149:                                }
                    150:                        }
                    151:                        continue;
                    152:                }
                    153: #endif /* not SENDMAIL */
                    154:                /*
                    155:                ** parse the arg to see if it's to be aliased
                    156:                */
                    157: 
                    158:                if(islocal(u->string, domain, ubuf) == 0) {
                    159:                        goto aliasing_complete;
                    160:                }
                    161: 
                    162:                /*
                    163:                ** local form - try to alias user
                    164:                ** aliases file takes precedence over ~user/.forward
                    165:                ** since that's the way that sendmail does it.
                    166:                */
                    167: 
                    168: #ifdef LOWERLOGNAME
                    169:                /* squish 'user' into lower case */
                    170:                for(user = ubuf; *user ; user++) {
                    171:                        *user = lower(*user);
                    172:                }
                    173: #endif
                    174:                user = escape(ubuf);
                    175: 
                    176:                (void) strcpy(u->string, user); /* local => elide domain */
                    177: #ifndef SENDMAIL
                    178:                /*
                    179:                ** check for alias - all this complication is necessary
                    180:                ** to handle perverted aliases like these:
                    181:                ** # mail to 's' resolves to 't' 'm' and 'rmt!j'
                    182:                ** s    t,g,j,m
                    183:                ** g    j,m
                    184:                ** j    rmt!j
                    185:                ** # mail to 'a' resolves to 'rmt!d'
                    186:                ** a    b c
                    187:                ** b    c
                    188:                ** c    rmt!d
                    189:                ** # mail to x resolves to 'x'
                    190:                ** x    local!x
                    191:                ** # mail to 'y' resolves to 'y' and 'z'
                    192:                ** y    \y z
                    193:                */
                    194:                if(((a = v_search(user)) != NNULL)) {
                    195:                        char dtmpb[SMLBUF], utmpb[SMLBUF], *ut;
                    196:                        int user_inalias = 0;
                    197:                        node *t = a;
                    198: 
                    199:                        for(a = a->horz; a != NNULL; a=a->horz) {
                    200:                                if(islocal(a->string, dtmpb, utmpb)) {
                    201: #ifdef LOWERLOGNAME
                    202:                                        /* squish 'utmpb' into lower case */
                    203:                                        for(ut = utmpb; *ut ; ut++) {
                    204:                                                *ut = lower(*ut);
                    205:                                        }
                    206: #endif
                    207: 
                    208:                                        ut = escape(utmpb);
                    209: #ifdef CASEALIAS
                    210:                                        if(strcmp(ut, user) == 0)
                    211: #else
                    212:                                        if(strcmpic(ut, user) == 0)
                    213: #endif
                    214:                                        {
                    215:                                                user_inalias = 1;
                    216:                                        } else {
                    217:                                                push(addr, a->string);
                    218:                                        }
                    219:                                } else {
                    220:                                        push(addr, a->string);
                    221:                                }
                    222:                        }
                    223:                        t->horz = NNULL; /* truncate horz list of aliases */
                    224:                        if(user_inalias == 0) {
                    225:                                continue;
                    226:                        }
                    227:                }
                    228: 
                    229:                if((home = tilde(user)) != NULL) {
                    230:                        /* don't allow multiple sourcing
                    231:                        ** of a given .forward file
                    232:                        */
                    233: 
                    234:                        if((h_search(flist, home) != NULL)) {
                    235:                                continue;
                    236:                        }
                    237:                        push(flist, home);
                    238: 
                    239:                        /*
                    240:                        ** check for ~user/.forward file
                    241:                        ** must be a regular, readable file
                    242:                        */
                    243: 
                    244:                        (void) sprintf(buf, "%s/%s", home, ".forward");
                    245:                        if((stat(buf, &st) >= 0)
                    246:                        &&((st.st_mode & S_IFMT) == S_IFREG)
                    247:                        &&((st.st_mode & 0444)   == 0444)
                    248:                        &&((fp = fopen(buf, "r")) != NULL)) {
                    249:                                aliased = 0;
                    250:                                while(fgets(buf, sizeof buf, fp)) {
                    251:                                        aliased |= recipients(addr, buf);
                    252:                                }
                    253:                                (void) fclose(fp);
                    254:                                if(aliased) {
                    255:                                        continue;
                    256:                                }
                    257:                        }
                    258:                }
                    259: #endif /* not SENDMAIL */
                    260: 
                    261: #ifdef FULLNAME
                    262:                /*
                    263:                ** Do possible fullname substitution.
                    264:                */
                    265: #ifdef DOT_REQD
                    266:                if (index(user, '.') != NULL)
                    267: #endif
                    268:                {
                    269:                        static char t_dom[SMLBUF], t_unam[SMLBUF];
                    270:                        char *t_user = res_fname(user);
                    271:                        if (t_user != NULL) {
                    272:                                if(islocal(t_user, t_dom, t_unam) == 0) {
                    273:                                        /* aliased to non-local address */
                    274:                                        push(addr, t_user);
                    275:                                        continue;
                    276:                                }
                    277:                                if(strcmp(t_unam, user) != 0) {
                    278:                                        /* aliased to different local address */
                    279:                                        push(addr, t_unam);
                    280:                                        continue;
                    281:                                }
                    282:                        }
                    283:                }
                    284: #endif
                    285: 
                    286: aliasing_complete:
                    287:                user = escape(u->string);
                    288:                for(i=0; i < nargc; i++) {
                    289: #ifdef CASEALIAS
                    290:                        if(strcmp(nargv[i], user) == 0) {
                    291: #else
                    292:                        if(strcmpic(nargv[i], user) == 0) {
                    293: #endif
                    294:                                break;
                    295:                        }
                    296:                }
                    297: 
                    298:                if(i == nargc) {
                    299:                        nargv[nargc++] = user;
                    300:                }
                    301:        }
                    302:        *pargc     = nargc;
                    303:        return(nargv);
                    304: }
                    305: 
                    306: #ifndef SENDMAIL
                    307: /*
                    308: ** v_search
                    309: **     given an string, look for its alias in
                    310: **     the 'vertical' linked list of aliases.
                    311: */
                    312: node *
                    313: v_search(user)
                    314: char *user;
                    315: {
                    316:        node *head;
                    317:        node *a;
                    318:        static int loaded = 0;
                    319: 
                    320:        head = &aliases;
                    321:        if(loaded == 0) {
                    322:                load_alias(head, aliasfile);
                    323: #ifdef HOMEALIASES
                    324:                /* Load $HOME/.aliases if there is one.  */
                    325:                /* NB:  Security problem if aliases can pipe to programs.  */
                    326:                if (( homealias = getenv("HOME") ) != NULL ) {
                    327:                        FILE *fp;
                    328: 
                    329:                        strcat(homealias, HOMEALIASES);
                    330:                        /* This fopen is just an existence and perm check.  */
                    331:                        if((fp = fopen(homealias,"r")) != NULL) {
                    332:                                fclose(fp);
                    333:                                load_alias(head, homealias);
                    334:                        } else {
                    335:                                fclose(fp);
                    336:                        }
                    337:                }
                    338: #endif
                    339:                loaded = 1;
                    340:        }
                    341: 
                    342:        for(a = head->vert; a != NNULL; a = a->vert) {
                    343: #ifdef CASEALIAS
                    344:                if(strcmp(a->string, user) == 0)
                    345: #else
                    346:                if(strcmpic(a->string, user) == 0)
                    347: #endif
                    348:                {
                    349:                        break;
                    350:                }
                    351:        }
                    352:        if(a == NNULL) {                /* not in graph */
                    353:                return(NNULL);
                    354:        }
                    355:        return(a);
                    356: }
                    357: 
                    358: /*
                    359: ** h_search
                    360: **     given an string, look for it in
                    361: **     a 'horizontal' linked list of strings.
                    362: */
                    363: node *
                    364: h_search(head, str)
                    365: node *head;
                    366: char *str;
                    367: {
                    368:        node *a;
                    369:        for(a = head->horz; a != NNULL; a = a->horz) {
                    370: #ifdef CASEALIAS
                    371:                if(strcmp(a->string, str) == 0)
                    372: #else
                    373:                if(strcmpic(a->string, str) == 0)
                    374: #endif
                    375:                {
                    376:                        break;
                    377:                }
                    378:        }
                    379:        return(a);
                    380: }
                    381: #endif /* not SENDMAIL */
                    382: 
                    383: /*
                    384: ** load_alias
                    385: **     parse an 'aliases' file and add the aliases to the alias graph.
                    386: **     Handle inclusion of other 'aliases' files.
                    387: */
                    388: 
                    389: void
                    390: load_alias(head, filename)
                    391: node *head;
                    392: char *filename;
                    393: {
                    394:        FILE *fp;
                    395:        node *v, *h, *add_vert();
                    396:        char domain[SMLBUF], user[SMLBUF];
                    397:        char *p, *b, buf[SMLBUF];
                    398: 
                    399:        if((fp = fopen(filename,"r")) == NULL) {
                    400: DEBUG("load_alias open('%s') failed\n", filename);
                    401:                return;
                    402:        }
                    403: 
                    404:        while(fgets(buf, sizeof buf, fp) != NULL) {
                    405:                p = buf;
                    406: 
                    407:                /* Check for trailing \, mark for later.  */
                    408:                no_backslash = last_no_backslash;
                    409:                if(strlen(p) > 0) {
                    410:                        if(p[strlen(p) - 2 ] == '\\') {
                    411:                                last_no_backslash = FALSE;
                    412:                        } else {
                    413:                                last_no_backslash = TRUE;
                    414:                        }
                    415:                } else {
                    416:                        last_no_backslash = TRUE;
                    417:                } /* check for trailing \ */
                    418: 
                    419:                if((*p == '#') || (*p == '\n')) {
                    420:                        continue;
                    421:                }
                    422: 
                    423:                /*
                    424:                ** include another file of aliases
                    425:                */
                    426: 
                    427:                if(strncmp(p, ":include:", 9) == 0) {
                    428:                        char *nl;
                    429:                        p += 9;
                    430:                        if((nl = index(p, '\n')) != NULL) {
                    431:                                *nl = CNULL;
                    432:                        }
                    433: DEBUG("load_alias '%s' includes file '%s'\n", filename, p);
                    434:                        load_alias(head, p);
                    435:                        continue; /* bug? line truncated after :include: */
                    436:                }
                    437: 
                    438:                /*
                    439:                **  if the first char on the line is a space or tab
                    440:                **  or the last character of the last line was a '\'
                    441:                **  then it's a continuation line.  Otherwise,
                    442:                **  we start a new alias.
                    443:                */
                    444:                if(*p != ' ' && *p != '\t' && no_backslash) {
                    445:                        b = p;
                    446:                        SKIPWORD(p);
                    447:                        *p++ = CNULL;
                    448:                        /*
                    449:                        ** be sure that the alias is in local form
                    450:                        */
                    451:                        if(islocal(b, domain, user) == 0) {
                    452:                                /*
                    453:                                ** non-local alias format - skip it
                    454:                                */
                    455:                                continue;
                    456:                        }
                    457:                        /*
                    458:                        ** add the alias to the (vertical) list of aliases
                    459:                        */
                    460:                        if((h = add_vert(head, user)) == NNULL) {
                    461: DEBUG("load_alias for '%s' failed\n", b);
                    462:                                fclose(fp);
                    463:                                return;
                    464:                        }
                    465:                }
                    466:                /*
                    467:                **  Next on the line is the list of recipents.
                    468:                **  Strip out each word and add it to the
                    469:                **  horizontal linked list.
                    470:                */
                    471:                (void) recipients(h, p);
                    472: 
                    473:        } /* while (fgets(buf, sizeof buf, fp) != NULL) */
                    474:        (void) fclose(fp);
                    475:        /*
                    476:        ** strip out aliases which have no members
                    477:        */
                    478:        for(v = head; v->vert != NNULL; ) {
                    479:                if(v->vert->horz == NNULL) {
                    480:                        v->vert = v->vert->vert;
                    481:                } else {
                    482:                        v = v->vert;
                    483:                }
                    484:        }
                    485: }
                    486: 
                    487: /*
                    488: ** add each word in a string (*p) of recipients
                    489: ** to the (horizontal) linked list associated with 'h'
                    490: */
                    491: 
                    492: recipients(h, p)
                    493: node *h;
                    494: char *p;
                    495: {
                    496: 
                    497:        char *b, d[SMLBUF], u[SMLBUF];
                    498:        int ret = 0;
                    499: 
                    500:        strip_comments(p);      /* strip out stuff in ()'s */
                    501: 
                    502:        SKIPSPACE(p);           /* skip leading whitespace on line */
                    503: 
                    504:        while((*p != NULL) && (*p != '#')) {
                    505:                b = p;
                    506:                if(*b == '"') {
                    507:                        if((p = index(++b, '"')) == NULL) {
                    508:                                /* syntax error - no matching quote */
                    509:                                /* skip the rest of the line */
                    510:                                return(ret);
                    511:                        }
                    512:                } else {
                    513:                        SKIPWORD(p);
                    514:                }
                    515: 
                    516:                if(*p != CNULL) {
                    517:                        *p++ = CNULL;
                    518:                }
                    519: 
                    520:                /* don't allow aliases of the form
                    521:                ** a    a
                    522:                */
                    523:                if((islocal(b, d, u) == 0)
                    524: #ifdef CASEALIAS
                    525:                || (strcmp(h->string, u) != 0)) {
                    526: #else
                    527:                || (strcmpic(h->string, u) != 0)) {
                    528: #endif
                    529:                        add_horz(h, b);
                    530:                        ret = 1;
                    531:                }
                    532:                SKIPSPACE(p);
                    533:        }
                    534:        return(ret);
                    535: }
                    536: 
                    537: /*
                    538: ** some aliases may have comments on the line like:
                    539: **
                    540: ** moderators  [email protected]       (Moderator's Name)
                    541: **             [email protected]    (Another Moderator's Name)
                    542: **
                    543: ** strip out the stuff in ()'s
                    544: **
                    545: */
                    546: 
                    547: void
                    548: strip_comments(p)
                    549: char *p;
                    550: {
                    551:        char *b;
                    552:        while((p = index(p, '(')) != NULL) {
                    553:                b = p++;        /*
                    554:                                ** save pointer to open parenthesis
                    555:                                */
                    556:                if((p = index(p, ')')) != NULL) {/* look for close paren */
                    557:                        (void) strcpy(b, ++p);   /* slide string left    */
                    558:                } else {
                    559:                        *b = CNULL;     /* no paren, skip rest of line  */
                    560:                        break;
                    561:                }
                    562:        }
                    563: }
                    564: 
                    565: /*
                    566: ** add_vert - add a (vertical) link to the chain of aliases.
                    567: */
                    568: 
                    569: node *
                    570: add_vert(head, str)
                    571: node *head;
                    572: char *str;
                    573: {
                    574:        char *p, *malloc();
                    575:        void free();
                    576:        node *new;
                    577: 
                    578:        /*
                    579:        ** strip colons off the end of alias names
                    580:        */
                    581:        if((p = index(str, ':')) != NULL) {
                    582:                *p = CNULL;
                    583:        }
                    584:        if((new = (node *) malloc(sizeof(node))) != NNULL) {
                    585:                if((new->string = malloc((unsigned) strlen(str)+1)) == NULL) {
                    586:                        free(new);
                    587:                        new = NNULL;
                    588:                } else {
                    589:                        (void) strcpy(new->string, str);
                    590:                        new->vert   = head->vert;
                    591:                        new->horz   = NNULL;
                    592:                        head->vert  = new;
                    593: /*DEBUG("add_vert %s->%s\n", head->string, new->string);/* */
                    594:                }
                    595:        }
                    596:        return(new);
                    597: }
                    598: 
                    599: /*
                    600: ** add_horz - add a (horizontal) link to the chain of recipients.
                    601: */
                    602: 
                    603: void
                    604: add_horz(head, str)
                    605: node *head;
                    606: char *str;
                    607: {
                    608:        char *malloc();
                    609:        node *new;
                    610: 
                    611:        if((new = (node *) malloc(sizeof(node))) != NNULL) {
                    612:                if((new->string = malloc((unsigned) strlen(str)+1)) == NULL) {
                    613:                        free(new);
                    614:                        new = NNULL;
                    615:                } else {
                    616:                        (void) strcpy(new->string, str);
                    617:                        new->horz  = head->horz;
                    618:                        new->vert  = NNULL;
                    619:                        head->horz = new;
                    620:                }
                    621: /*DEBUG("add_horz %s->%s\n", head->string, new->string);/* */
                    622:        }
                    623: }
                    624: 
                    625: node *
                    626: pop(head)
                    627: node *head;
                    628: {
                    629:        node *ret = NNULL;
                    630: 
                    631: 
                    632:        if(head != NNULL) {
                    633:                ret = head->horz;
                    634:                if(ret != NNULL) {
                    635:                        head->horz = ret->horz;
                    636:                }
                    637:        }
                    638:        return(ret);
                    639: }

unix.superglobalmegacorp.com

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