d9311a96046f7e45aafd9cce88b6f8973e1eacc6
[unix-history] / usr / src / usr.sbin / sendmail / src / alias.c
# include <pwd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include "sendmail.h"
# ifdef DBM
static char SccsId[] = "@(#)alias.c 3.19 %G% (with DBM)";
# else DBM
static char SccsId[] = "@(#)alias.c 3.19 %G% (without DBM)";
# endif DBM
/*
** ALIAS -- Compute aliases.
**
** Scans the file /usr/lib/aliases for a set of aliases.
** If found, it arranges to deliver to them. Uses libdbm
** database if -DDBM.
**
** Parameters:
** a -- address to alias.
**
** Returns:
** none
**
** Side Effects:
** Aliases found are expanded.
**
** Files:
** /usr/lib/aliases -- the mail aliases. The format is
** a series of lines of the form:
** alias:name1,name2,name3,...
** where 'alias' expands to all of
** 'name[i]'. Continuations begin with
** space or tab.
** /usr/lib/aliases.pag, /usr/lib/aliases.dir: libdbm version
** of alias file. Keys are aliases, datums
** (data?) are name1,name2, ...
**
** Notes:
** If NoAlias (the "-n" flag) is set, no aliasing is
** done.
**
** Deficiencies:
** It should complain about names that are aliased to
** nothing.
** It is unsophisticated about line overflows.
*/
#ifdef DBM
typedef struct
{
char *dptr;
int dsize;
} DATUM;
DATUM lhs, rhs;
extern DATUM fetch();
#endif DBM
alias(a)
register ADDRESS *a;
{
register char *p;
# ifndef DBM
register STAB *s;
# endif DBM
if (NoAlias)
return;
# ifdef DEBUG
if (Debug)
printf("alias(%s)\n", a->q_paddr);
# endif
/* don't realias already aliased names */
if (bitset(QDONTSEND, a->q_flags))
return;
To = a->q_paddr;
/*
** Look up this name
*/
# ifdef DBM
/* create a key for fetch */
lhs.dptr = a->q_user;
lhs.dsize = strlen(a->q_user) + 1;
rhs = fetch(lhs);
/* find this alias? */
p = rhs.dptr;
if (p == NULL)
return;
# else DBM
s = stab(a->q_user, ST_ALIAS, ST_FIND);
if (s == NULL)
return;
p = s->s_alias;
# endif DBM
/*
** Match on Alias.
** Deliver to the target list.
*/
# ifdef DEBUG
if (Debug)
printf("%s (%s, %s) aliased to %s\n",
a->q_paddr, a->q_host, a->q_user, p);
# endif
if (Verbose)
message(Arpa_Info, "aliased to %s", p);
a->q_flags |= QDONTSEND;
AliasLevel++;
sendto(p, 1);
AliasLevel--;
}
\f/*
** INITALIASES -- initialize for aliasing
**
** Very different depending on whether we are running DBM or not.
**
** Parameters:
** aliasfile -- location of aliases.
** init -- if set and if DBM, initialize the DBM files.
**
** Returns:
** none.
**
** Side Effects:
** initializes aliases:
** if DBM: opens the database.
** if ~DBM: reads the aliases into the symbol table.
*/
# define DBMMODE 0666
initaliases(aliasfile, init)
char *aliasfile;
bool init;
{
# ifdef DBM
if (init)
{
char buf[MAXNAME];
(void) strcpy(buf, aliasfile);
(void) strcat(buf, ".dir");
if (close(creat(buf, DBMMODE)) < 0)
{
syserr("cannot make %s", buf);
return;
}
(void) strcpy(buf, aliasfile);
(void) strcat(buf, ".pag");
if (close(creat(buf, DBMMODE)) < 0)
{
syserr("cannot make %s", buf);
return;
}
}
dbminit(aliasfile);
if (init)
readaliases(aliasfile, TRUE);
# else DBM
readaliases(aliasfile, init);
# endif DBM
}
\f/*
** READALIASES -- read and process the alias file.
**
** This routine implements the part of initaliases that occurs
** when we are not going to use the DBM stuff.
**
** Parameters:
** aliasfile -- the pathname of the alias file master.
** init -- if set, initialize the DBM stuff.
**
** Returns:
** none.
**
** Side Effects:
** Reads aliasfile into the symbol table.
** Optionally, builds the .dir & .pag files.
*/
static
readaliases(aliasfile, init)
char *aliasfile;
bool init;
{
char line[BUFSIZ];
register char *p;
char *p2;
char *rhs;
bool skipping;
ADDRESS al, bl;
FILE *af;
int lineno;
register STAB *s;
if ((af = fopen(aliasfile, "r")) == NULL)
{
# ifdef DEBUG
if (Debug)
printf("Can't open %s\n", aliasfile);
# endif
errno = 0;
NoAlias++;
return;
}
/*
** Read and interpret lines
*/
lineno = 0;
skipping = FALSE;
while (fgets(line, sizeof (line), af) != NULL)
{
lineno++;
switch (line[0])
{
case '#':
case '\n':
case '\0':
skipping = FALSE;
continue;
case ' ':
case '\t':
if (!skipping)
syserr("aliases: %d: Non-continuation line starts with space", lineno);
skipping = TRUE;
continue;
}
skipping = FALSE;
/*
** Process the LHS
** Find the final colon, and parse the address.
** It should resolve to a local name -- this will
** be checked later (we want to optionally do
** parsing of the RHS first to maximize error
** detection).
*/
for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
continue;
if (*p == '\0' || *p == '\n')
{
syntaxerr:
syserr("aliases: %d: missing colon", lineno);
continue;
}
*p++ = '\0';
if (parse(line, &al, 1) == NULL)
{
*--p = ':';
goto syntaxerr;
}
/*
** Process the RHS.
** 'al' is the internal form of the LHS address.
** 'p' points to the text of the RHS.
*/
rhs = p;
for (;;)
{
register char c;
if (init)
{
/* do parsing & compression of addresses */
c = *p;
while (c != '\0')
{
p2 = p;
while (*p != '\n' && *p != ',' && *p != '\0')
p++;
c = *p;
*p++ = '\0';
if (*p2 == '\0')
{
p[-1] = c;
continue;
}
(void) parse(p2, &bl, -1);
p[-1] = c;
while (isspace(*p))
p++;
}
}
else
p = &p[strlen(p)];
/* see if there should be a continuation line */
c = fgetc(af);
if (!feof(af))
(void) ungetc(c, af);
if (c != ' ' && c != '\t')
break;
/* read continuation line */
p--;
if (fgets(p, sizeof line - (p - line), af) == NULL)
break;
lineno++;
}
if (al.q_mailer != MN_LOCAL)
{
syserr("aliases: %d: cannot alias non-local names", lineno);
continue;
}
/*
** Insert alias into symbol table or DBM file
*/
# ifdef DBM
if (init)
{
DATUM key, content;
key.dsize = strlen(al.q_user) + 1;
key.dptr = al.q_user;
content.dsize = strlen(rhs) + 1;
content.dptr = rhs;
store(key, content);
}
else
# endif DBM
{
s = stab(al.q_user, ST_ALIAS, ST_ENTER);
s->s_alias = newstr(rhs);
}
}
(void) fclose(af);
}
\f/*
** FORWARD -- Try to forward mail
**
** This is similar but not identical to aliasing.
**
** Parameters:
** user -- the name of the user who's mail we would like
** to forward to. It must have been verified --
** i.e., the q_home field must have been filled
** in.
**
** Returns:
** none.
**
** Side Effects:
** New names are added to send queues.
** Sets the QDONTSEND bit in addresses that are forwarded.
*/
forward(user)
ADDRESS *user;
{
char buf[60];
struct stat stbuf;
# ifdef DEBUG
if (Debug)
printf("forward(%s)\n", user->q_paddr);
# endif DEBUG
if (user->q_mailer != MN_LOCAL || bitset(QBADADDR, user->q_flags))
return;
# ifdef DEBUG
if (user->q_home == NULL)
syserr("forward: no home");
# endif DEBUG
/* good address -- look for .forward file in home */
define('z', user->q_home);
(void) expand("$z/.forward", buf, &buf[sizeof buf - 1]);
if (stat(buf, &stbuf) < 0 || stbuf.st_uid != user->q_uid ||
!bitset(S_IREAD, stbuf.st_mode))
return;
/* we do have an address to forward to -- do it */
user->q_flags |= QDONTSEND;
include(buf, "forwarding");
}