home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Patched for MS-DOS compatibility by Stephen Trier, March-May, 1990
- */
-
- #ifndef lint
- static char *sccsid = "@(#)alias.c 2.5 (smail) 9/15/87";
- #endif
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <pwd.h>
- #include "defs.h"
- #include <ctype.h>
-
- extern enum edebug debug; /* verbose and debug modes */
- extern char hostdomain[];
- extern char hostname[];
- extern char *aliasfile;
-
- /*
- **
- ** Picture of the alias graph structure
- **
- ** head
- ** |
- ** v
- ** maps -> mark -> gjm -> mel -> NNULL
- ** |
- ** v
- ** sys -> root -> ron -> NNULL
- ** |
- ** v
- ** root -> mark -> chris -> lda -> NNULL
- ** |
- ** v
- ** NNULL
- */
-
- typedef struct alias_node node;
-
- static struct alias_node {
- char *string;
- node *horz;
- node *vert;
- };
-
- #ifndef SENDMAIL
- static node aliases = {"", 0, 0}; /* this is the 'dummy header' */
- #endif /* not SENDMAIL */
-
- /*
- ** lint free forms of NULL
- */
-
- #define NNULL ((node *) 0)
- #define CNULL ('\0')
-
- /*
- ** string parsing macros
- */
- #define SKIPWORD(Z) while(*Z!=' ' && *Z!='\t' && *Z!='\n' && *Z!=',') Z++;
- #define SKIPSPACE(Z) while(*Z==' ' || *Z=='\t' || *Z=='\n' || *Z==',') Z++;
-
- static int nargc = 0;
- static char *nargv[MAXARGS];
-
- void add_horz();
- void load_alias(), strip_comments();
- int recipients();
- node *pop();
- #ifndef SENDMAIL
- node *v_search(), *h_search();
- char *tilde();
- #endif /* not SENDMAIL */
-
- /* our horizontal linked list looks like a stack */
- #define push add_horz
-
- #define escape(s) ((*s != '\\') ? (s) : (s+1))
-
- char **
- alias(pargc, argv)
- int *pargc;
- char **argv;
- {
- /*
- ** alias the addresses
- */
- int i;
- char domain[SMLBUF], ubuf[SMLBUF], *user;
- node *addr, addrstk;
- node *flist, fliststk, *u;
-
- #ifndef SENDMAIL
- FILE *fp;
- node *a;
- char *home, buf[SMLBUF];
- int aliased;
- struct stat st;
- #endif /* not SENDMAIL */
-
- #ifdef FULLNAME
- char *res_fname(); /* Does fullname processing */
- #endif
-
- addr = &addrstk;
- flist = &fliststk;
- user = ubuf;
-
- addr->horz = NNULL;
- flist->horz = NNULL;
-
- /*
- ** push all of the addresses onto a stack
- */
- for(i=0; i < *pargc; i++) {
- push(addr, argv[i]);
- }
-
- /*
- ** for each adress, check for included files, aliases,
- ** full name mapping, and .forward files
- */
-
- while((nargc < MAXARGS) && ((u = pop(addr)) != NNULL)) {
- #ifndef SENDMAIL
- if(strncmpic(u->string, ":include:", 9) == 0) {
- /*
- ** make sure it's a full path name
- ** don't allow multiple sourcing
- ** of a given include file
- */
- char *p = u->string + 9;
-
- if((*p == '/')
- && (h_search(flist, p) == NULL)) {
- push(flist, p);
- if((stat(p, &st) >= 0)
- &&((st.st_mode & S_IFMT) == S_IFREG)
- &&((fp = fopen(p, "r")) != NULL)) {
- while(fgets(buf, sizeof buf, fp)) {
- (void) recipients(addr, buf);
- }
- (void) fclose(fp);
- }
- }
- continue;
- }
- #endif /* not SENDMAIL */
- /*
- ** parse the arg to see if it's to be aliased
- */
-
- if(islocal(u->string, domain, ubuf) == 0) {
- goto aliasing_complete;
- }
-
- /*
- ** local form - try to alias user
- ** aliases file takes precedence over ~user/.forward
- ** since that's the way that sendmail does it.
- */
-
- #ifdef LOWERLOGNAME
- /* squish 'user' into lower case */
- for(user = ubuf; *user ; user++) {
- *user = lower(*user);
- }
- #endif
- user = escape(ubuf);
-
- (void) strcpy(u->string, user); /* local => elide domain */
- #ifndef SENDMAIL
- /*
- ** check for alias - all this complication is necessary
- ** to handle perverted aliases like these:
- ** # mail to 's' resolves to 't' 'm' and 'rmt!j'
- ** s t,g,j,m
- ** g j,m
- ** j rmt!j
- ** # mail to 'a' resolves to 'rmt!d'
- ** a b c
- ** b c
- ** c rmt!d
- ** # mail to x resolves to 'x'
- ** x local!x
- ** # mail to 'y' resolves to 'y' and 'z'
- ** y \y z
- */
- if(((a = v_search(user)) != NNULL)) {
- char dtmpb[SMLBUF], utmpb[SMLBUF], *ut;
- int user_inalias = 0;
- node *t = a;
-
- for(a = a->horz; a != NNULL; a=a->horz) {
- if(islocal(a->string, dtmpb, utmpb)) {
- #ifdef LOWERLOGNAME
- /* squish 'utmpb' into lower case */
- for(ut = utmpb; *ut ; ut++) {
- *ut = lower(*ut);
- }
- #endif
-
- ut = escape(utmpb);
- #ifdef CASEALIAS
- if(strcmp(ut, user) == 0)
- #else
- if(strcmpic(ut, user) == 0)
- #endif
- {
- user_inalias = 1;
- } else {
- push(addr, a->string);
- }
- } else {
- push(addr, a->string);
- }
- }
- t->horz = NNULL; /* truncate horz list of aliases */
- if(user_inalias == 0) {
- continue;
- }
- }
-
- if((home = tilde(user)) != NULL) {
- /* don't allow multiple sourcing
- ** of a given .forward file
- */
-
- if((h_search(flist, home) != NULL)) {
- continue;
- }
- push(flist, home);
-
- /*
- ** check for ~user/.forward file
- ** must be a regular, readable file
- */
-
- #ifndef MSDOS /* Change by SCT */
- (void) sprintf(buf, "%s/%s", home, ".forward");
- #else
- (void) sprintf(buf, "%s/%s", home, "forward");
- #endif /* MSDOS */
- if((stat(buf, &st) >= 0)
- &&((st.st_mode & S_IFMT) == S_IFREG)
- #ifndef MSDOS
- &&((st.st_mode & 0444) == 0444)
- #endif
- &&((fp = fopen(buf, "r")) != NULL)) {
- aliased = 0;
- while(fgets(buf, sizeof buf, fp)) {
- aliased |= recipients(addr, buf);
- }
- (void) fclose(fp);
- if(aliased) {
- continue;
- }
- }
- }
- #endif /* not SENDMAIL */
-
- #ifdef FULLNAME
- /*
- ** Do possible fullname substitution.
- */
- #ifdef DOT_REQD
- if (index(user, '.') != NULL)
- #endif
- {
- static char t_dom[SMLBUF], t_unam[SMLBUF];
- char *t_user = res_fname(user);
- if (t_user != NULL) {
- if(islocal(t_user, t_dom, t_unam) == 0) {
- /* aliased to non-local address */
- push(addr, t_user);
- continue;
- }
- if(strcmp(t_unam, user) != 0) {
- /* aliased to different local address */
- push(addr, t_unam);
- continue;
- }
- }
- }
- #endif
-
- aliasing_complete:
- user = escape(u->string);
- for(i=0; i < nargc; i++) {
- if(strcmpic(nargv[i], user) == 0) {
- break;
- }
- }
-
- if(i == nargc) {
- nargv[nargc++] = user;
- }
- }
- *pargc = nargc;
- return(nargv);
- }
-
- #ifndef SENDMAIL
- /*
- ** v_search
- ** given an string, look for its alias in
- ** the 'vertical' linked list of aliases.
- */
- node *
- v_search(user)
- char *user;
- {
- node *head;
- node *a;
- static int loaded = 0;
-
- head = &aliases;
- if(loaded == 0) {
- load_alias(head, aliasfile);
- loaded = 1;
- }
-
- for(a = head->vert; a != NNULL; a = a->vert) {
- #ifdef CASEALIAS
- if(strcmp(a->string, user) == 0)
- #else
- if(strcmpic(a->string, user) == 0)
- #endif
- {
- break;
- }
- }
- if(a == NNULL) { /* not in graph */
- return(NNULL);
- }
- return(a);
- }
-
- /*
- ** h_search
- ** given an string, look for it in
- ** a 'horizontal' linked list of strings.
- */
- node *
- h_search(head, str)
- node *head;
- char *str;
- {
- node *a;
- for(a = head->horz; a != NNULL; a = a->horz) {
- #ifdef CASEALIAS
- if(strcmp(a->string, str) == 0)
- #else
- if(strcmpic(a->string, str) == 0)
- #endif
- {
- break;
- }
- }
- return(a);
- }
- #endif /* not SENDMAIL */
-
- /*
- ** load_alias
- ** parse an 'aliases' file and add the aliases to the alias graph.
- ** Handle inclusion of other 'aliases' files.
- */
-
- void
- load_alias(head, filename)
- node *head;
- char *filename;
- {
- FILE *fp;
- node *v, *h, *add_vert();
- char domain[SMLBUF], user[SMLBUF];
- char *p, *b, buf[SMLBUF];
-
- if((fp = fopen(filename,"r")) == NULL) {
- DEBUG("load_alias open('%s') failed\n", filename);
- return;
- }
-
- while(fgets(buf, sizeof buf, fp) != NULL) {
- p = buf;
- if((*p == '#') || (*p == '\n')) {
- continue;
- }
-
- /*
- ** include another file of aliases
- */
-
- if(strncmp(p, ":include:", 9) == 0) {
- char *nl;
- p += 9;
- if((nl = index(p, '\n')) != NULL) {
- *nl = CNULL;
- }
- DEBUG("load_alias '%s' includes file '%s'\n", filename, p);
- load_alias(head, p);
- continue;
- }
-
- /*
- ** if the first char on the line is a space or tab
- ** then it's a continuation line. Otherwise,
- ** we start a new alias.
- */
- if(*p != ' ' && *p != '\t') {
- b = p;
- SKIPWORD(p);
- *p++ = CNULL;
- /*
- ** be sure that the alias is in local form
- */
- if(islocal(b, domain, user) == 0) {
- /*
- ** non-local alias format - skip it
- */
- continue;
- }
- /*
- ** add the alias to the (vertical) list of aliases
- */
- if((h = add_vert(head, user)) == NNULL) {
- DEBUG("load_alias for '%s' failed\n", b);
- return;
- }
- }
- /*
- ** Next on the line is the list of recipents.
- ** Strip out each word and add it to the
- ** horizontal linked list.
- */
- (void) recipients(h, p);
- }
- (void) fclose(fp);
- /*
- ** strip out aliases which have no members
- */
- for(v = head; v->vert != NNULL; ) {
- if(v->vert->horz == NNULL) {
- v->vert = v->vert->vert;
- } else {
- v = v->vert;
- }
- }
- }
-
- /*
- ** add each word in a string (*p) of recipients
- ** to the (horizontal) linked list associated with 'h'
- */
-
- recipients(h, p)
- node *h;
- char *p;
- {
-
- char *b, d[SMLBUF], u[SMLBUF];
- int ret = 0;
-
- strip_comments(p); /* strip out stuff in ()'s */
-
- SKIPSPACE(p); /* skip leading whitespace on line */
-
- while((*p != NULL) && (*p != '#')) {
- b = p;
- if(*b == '"') {
- if((p = index(++b, '"')) == NULL) {
- /* syntax error - no matching quote */
- /* skip the rest of the line */
- return(ret);
- }
- } else {
- SKIPWORD(p);
- }
-
- if(*p != CNULL) {
- *p++ = CNULL;
- }
-
- /* don't allow aliases of the form
- ** a a
- */
- if((islocal(b, d, u) == 0)
- || (strcmpic(h->string, u) != 0)) {
- add_horz(h, b);
- ret = 1;
- }
- SKIPSPACE(p);
- }
- return(ret);
- }
-
- /*
- ** some aliases may have comments on the line like:
- **
- ** moderators moderator@somehost.domain (Moderator's Name)
- ** moderator@anotherhost.domain (Another Moderator's Name)
- **
- ** strip out the stuff in ()'s
- **
- */
-
- void
- strip_comments(p)
- char *p;
- {
- char *b;
- while((p = index(p, '(')) != NULL) {
- b = p++; /*
- ** save pointer to open parenthesis
- */
- if((p = index(p, ')')) != NULL) {/* look for close paren */
- (void) strcpy(b, ++p); /* slide string left */
- } else {
- *b = CNULL; /* no paren, skip rest of line */
- break;
- }
- }
- }
-
- /*
- ** add_vert - add a (vertical) link to the chain of aliases.
- */
-
- node *
- add_vert(head, str)
- node *head;
- char *str;
- {
- char *p, *malloc();
- void free();
- node *new;
-
- /*
- ** strip colons off the end of alias names
- */
- if((p = index(str, ':')) != NULL) {
- *p = CNULL;
- }
- if((new = (node *) malloc(sizeof(node))) != NNULL) {
- if((new->string = malloc((unsigned) strlen(str)+1)) == NULL) {
- free(new);
- new = NNULL;
- } else {
- (void) strcpy(new->string, str);
- new->vert = head->vert;
- new->horz = NNULL;
- head->vert = new;
- /*DEBUG("add_vert %s->%s\n", head->string, new->string);/* */
- }
- }
- return(new);
- }
-
- /*
- ** add_horz - add a (horizontal) link to the chain of recipients.
- */
-
- void
- add_horz(head, str)
- node *head;
- char *str;
- {
- char *malloc();
- node *new;
-
- if((new = (node *) malloc(sizeof(node))) != NNULL) {
- if((new->string = malloc((unsigned) strlen(str)+1)) == NULL) {
- free(new);
- new = NNULL;
- } else {
- (void) strcpy(new->string, str);
- new->horz = head->horz;
- new->vert = NNULL;
- head->horz = new;
- }
- /*DEBUG("add_horz %s->%s\n", head->string, new->string);/* */
- }
- }
-
- node *
- pop(head)
- node *head;
- {
- node *ret = NNULL;
-
-
- if(head != NNULL) {
- ret = head->horz;
- if(ret != NNULL) {
- head->horz = ret->horz;
- }
- }
- return(ret);
- }