|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T a
Length: 10178 (0x27c2)
Types: TextFile
Names: »alias.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec8/smail/src/alias.c«
#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