|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.