DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T a

⟦65c08ca59⟧ TextFile

    Length: 10178 (0x27c2)
    Types: TextFile
    Names: »alias.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/euug-87hel/sec8/smail/src/alias.c« 

TextFile

#ifndef lint
static char *sccsid = "@(#)alias.c	2.3 (smail) 1/28/87";
#endif

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include "defs.h"
#ifdef BSD
#include <strings.h>
#else
#include <string.h>
#endif

extern enum edebug debug;	/* verbose and debug modes		*/
extern char hostdomain[];
extern char hostname[];
extern char *aliasfile;

#ifdef SENDMAIL
char **
alias(pargc, argv)
int *pargc;
char **argv;
{
	int i;
/*
**  aliasing was done by sendmail - so don't do anything here
**  except to possibly truncate the argument count to MAXARGS.
*/
	if(MAXARGS < *pargc) {
		for(i = MAXARGS ; i < *pargc ; i++) {
			ADVISE("too many recipents - skipping %s\n", argv[i]);
		}
		*pargc = MAXARGS;
	}
	return(argv);
}
#else

/*
**
** Picture of the alias graph structure
**
**	head
**       |
**       v
**	maps -> mark -> gjm -> mel -> NNULL
**       |
**       v
**	sys ->  root -> ron -> NNULL
**       |       |
**       | +-----+
**       | |
**       v v
**	root -> mark -> chris -> lda -> NNULL
**       |
**       v
**      NNULL
*/

typedef struct alias_node node;

static struct alias_node {
	char *string;
	node *horz;
	node *vert;
};

static node aliases = {"", 0, 0}; /* this is the 'dummy header' */

/*
** 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();
node	*vsearch(), *hsearch(), *pop();
int	recipients();
char	*tilde();

/* 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
*/
	FILE	*fp;
	int	i, aliased;
	char	domain[SMLBUF], ubuf[SMLBUF], *user;
	char	*home, buf[SMLBUF];
	node	*addr, addrstk;
	node	*flist,  fliststk;
	node	*u, *a;
	struct	stat st;

	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 and .forward files
	*/
	while((nargc < MAXARGS) && ((u = pop(addr)) != NNULL)) {
		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 == '/')
			&& (hsearch(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)) {
						recipients(addr, buf);
					}
					fclose(fp);
				}
			}
			continue;
		}

		/*
		** 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.
		*/

		user = escape(ubuf);
		if((a = vsearch(user)) != NNULL) {
		/*
		** check for alias
		*/
			node *t = a;
			for(a = a->horz; a != NNULL; a=a->horz) {
				push(addr, a->string);
			}
			t->horz = NNULL;
			continue;
		}

		if((home = tilde(user)) != NULL) {
			/* don't allow multiple sourcing
			** of a given .forward file
			*/

			if((hsearch(flist, home) != NULL)) {
				continue;
			}
			push(flist, home);

			/*
			** check for ~user/.forward file
			** must be a regular, readable file
			*/

			sprintf(buf, "%s/%s", home, ".forward");
			if((stat(buf, &st) >= 0)
			&&((st.st_mode & S_IFMT) == S_IFREG)
			&&((fp = fopen(buf, "r")) != NULL)) {
				aliased = 0;
				while(fgets(buf, sizeof buf, fp)) {
					aliased |= recipients(addr, buf);
				}
				fclose(fp);
				if(aliased) {
					continue;
				}
			}
		}
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);
}

/*
** vsearch
**	given an string, look for its alias in
**	the 'vertical' linked list of aliases.
*/
node *
vsearch(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 */
	|| (a->horz == NNULL)) {	/* null list (poss. prev. aliased) */
		return(NNULL);
	}
	return(a);
}

/*
** hsearch
**	given an string, look for it in
**	a 'horizontal' linked list of strings.
*/
node *
hsearch(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);
}

/*
** 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 *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.
		*/
		recipients(h, p);
	}
	(void) fclose(fp);
}

/*
** 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;
	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;
		}

		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);/* */
	}
}

char *
tilde(user)
char *user;
{
	struct passwd *getpwent(), *pw;
	static node pwdstk;
	static int pw_eof = 0;

	node *a, *pwd;

	char buf[SMLBUF];
	int i;

	pwd = &pwdstk;

	/*
	** check for previously cached user
	*/

	if((a = hsearch(pwd, user)) != NNULL) {
		return(a->string + strlen(a->string) + 1);
	}

	/*
	** cache previous username and home directory
	** this bit of code is quite implementation dependent.
	** The kludge here is that the string login:home is
	** pushed onto a linked list, and then the ':' is
	** replaced with a null character.  This lets us
	** search the list without the hassel of index()'ing
	** on the ':' and doing strncmp().
	*/

	while((pw_eof == 0) && ((pw = getpwent()) != NULL)) {
		strcpy(buf, pw->pw_name);
		i = strlen(buf);
		buf[i] = ':';
		strcpy(&buf[i+1], pw->pw_dir);
		push(pwd, buf);
		a = pwd->horz;
		a->string[i] = '\0';
		if(strcmp(user, pw->pw_name) == 0) {
			return(a->string + strlen(a->string) + 1);
		}
	}
	pw_eof = 1;
	return(NULL);
}

node *
pop(head)
node *head;
{
	node *ret = NNULL;

	if(head != NNULL) {
		ret = head->horz;
		if(ret != NNULL) {
			head->horz = ret->horz;
		}
	}
	return(ret);
}
#endif