4afac7d8140b5ba9db58491b0e675aec2b72ae08
SCCSID(@
(#)alias.c 4.8 %G% (with DBM));
SCCSID(@
(#)alias.c 4.8 %G% (without DBM));
** ALIAS -- Compute aliases.
** Scans the alias file for an alias for the given address.
** If found, it arranges to deliver to the alias list instead.
** Uses libdbm database if -DDBM.
** a -- address to alias.
** sendq -- a pointer to the head of the send queue
** to put the aliases in.
** Aliases found are expanded.
** If NoAlias (the "-n" flag) is set, no aliasing is
** It should complain about names that are aliased to
extern ADDRESS
*sendto();
extern char *aliaslookup();
printf("alias(%s)\n", a
->q_paddr
);
/* don't realias already aliased names */
if (bitset(QDONTSEND
, a
->q_flags
))
CurEnv
->e_to
= a
->q_paddr
;
p
= aliaslookup(a
->q_user
);
** Deliver to the target list.
printf("%s (%s, %s) aliased to %s\n",
a
->q_paddr
, a
->q_host
, a
->q_user
, p
);
message(Arpa_Info
, "aliased to %s", p
);
a
->q_child
= sendto(p
, 1, a
, 0);
** ALIASLOOKUP -- look up a name in the alias file.
** name -- the name to look up.
** The return value will be trashed across calls.
/* create a key for fetch */
lhs
.dsize
= strlen(name
) + 1;
s
= stab(name
, ST_ALIAS
, ST_FIND
);
** INITALIASES -- initialize for aliasing
** Very different depending on whether we are running DBM or not.
** aliasfile -- location of aliases.
** init -- if set and if DBM, initialize the DBM files.
** if DBM: opens the database.
** if ~DBM: reads the aliases into the symbol table.
initaliases(aliasfile
, init
)
if (aliasfile
== NULL
|| stat(aliasfile
, &stb
) < 0)
** Check to see that the alias file is complete.
** If not, we will assume that someone died, and it is up
while (!init
&& atcnt
-- >= 0 && aliaslookup("@") == NULL
)
** See if the DBM version of the file is out of date with
** the text version. If so, go into 'init' mode automatically.
** This only happens if our effective userid owns the DBM
** version or if the mode of the database is 666 -- this
** is an attempt to avoid protection problems. Note the
** unpalatable hack to see if the stat succeeded.
(void) strcpy(buf
, aliasfile
);
(void) strcat(buf
, ".pag");
if (!init
&& (atcnt
< 0 || stat(buf
, &stb
) < 0 || stb
.st_mtime
< modtime
))
if (AutoRebuild
&& stb
.st_ino
!= 0 &&
((stb
.st_mode
& 0777) == 0666 || stb
.st_uid
== geteuid()))
message(Arpa_Info
, "rebuilding alias database");
message(Arpa_Info
, "Warning: alias database out of date");
** If initializing, create the new files.
** We should lock the alias file here to prevent other
** instantiations of sendmail from reading an incomplete
** file -- or worse yet, doing a concurrent initialize.
oldsigint
= signal(SIGINT
, SIG_IGN
);
(void) strcpy(buf
, aliasfile
);
(void) strcat(buf
, ".dir");
if (close(creat(buf
, DBMMODE
)) < 0)
syserr("cannot make %s", buf
);
(void) signal(SIGINT
, oldsigint
);
(void) strcpy(buf
, aliasfile
);
(void) strcat(buf
, ".pag");
if (close(creat(buf
, DBMMODE
)) < 0)
syserr("cannot make %s", buf
);
(void) signal(SIGINT
, oldsigint
);
** If necessary, load the DBM file.
** If running without DBM, load the symbol table.
** After loading the DBM file, add the distinquished alias "@".
readaliases(aliasfile
, TRUE
);
(void) signal(SIGINT
, oldsigint
);
readaliases(aliasfile
, init
);
** 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.
** aliasfile -- the pathname of the alias file master.
** init -- if set, initialize the DBM stuff.
** Reads aliasfile into the symbol table.
** Optionally, builds the .dir & .pag files.
readaliases(aliasfile
, init
)
int naliases
, bytes
, longest
;
if ((af
= fopen(aliasfile
, "r")) == NULL
)
printf("Can't open %s\n", aliasfile
);
** Read and interpret lines
naliases
= bytes
= longest
= 0;
while (fgets(line
, sizeof (line
), af
) != NULL
)
syserr("Non-continuation line starts with space");
** Find the final colon, and parse the address.
** It should resolve to a local name.
** Alternatively, it can be "@hostname" for host
** aliases -- all we do here is map case. Hostname
** need not be a single token.
for (p
= line
; *p
!= '\0' && *p
!= ':' && *p
!= '\n'; p
++)
syserr("%s, line %d: syntax error", aliasfile
, lineno
);
if (parseaddr(line
, &al
, 1, ':') == NULL
)
syserr("illegal alias name");
if (al
.q_mailer
!= LocalMailer
)
syserr("cannot alias non-local names");
** 'al' is the internal form of the LHS address.
** 'p' points to the text of the RHS.
** 'p' may begin with a colon (i.e., the
** separator was "::") which will use the
** first address as the person to send
** errors to -- i.e., designates the
while (*p
!= '\0' && *p
!= ',')
maint
= parse(p
, (ADDRESS
*) NULL
, 1);
syserr("Illegal list maintainer for list %s", al
.q_user
);
else if (CurEnv
->e_returnto
== &CurEnv
->e_from
)
CurEnv
->e_returnto
= maint
;
/* do parsing & compression of addresses */
while (*p
!= '\n' && *p
!= ',' && *p
!= '\0')
(void) parseaddr(p2
, &bl
, -1, ',');
/* see if there should be a continuation line */
if (c
!= ' ' && c
!= '\t')
/* read continuation line */
if (fgets(p
, sizeof line
- (p
- line
), af
) == NULL
)
** Insert alias into symbol table or DBM file
lhssize
= strlen(lhs
) + 1;
rhssize
= strlen(rhs
) + 1;
s
= stab(al
.q_user
, ST_ALIAS
, ST_ENTER
);
s
->s_alias
= newstr(rhs
);
bytes
+= lhssize
+ rhssize
;
message(Arpa_Info
, "%d aliases, longest %d bytes, %d bytes total",
naliases
, longest
, bytes
);
** FORWARD -- Try to forward mail
** This is similar but not identical to aliasing.
** 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
** sendq -- a pointer to the head of the send queue to
** put this user's aliases in.
** New names are added to send queues.
printf("forward(%s)\n", user
->q_paddr
);
if (user
->q_mailer
!= LocalMailer
|| bitset(QBADADDR
, user
->q_flags
))
if (user
->q_home
== NULL
)
syserr("forward: no home");
/* good address -- look for .forward file in home */
define('z', user
->q_home
, CurEnv
);
expand("\001z/.forward", buf
, &buf
[sizeof buf
- 1], CurEnv
);
if (!safefile(buf
, user
->q_uid
, S_IREAD
))
/* we do have an address to forward to -- do it */
include(buf
, "forwarding", user
, sendq
);
** MAPHOST -- given a host description, produce a mapping.
** This is done by looking up the name in the alias file,
** preceeded by an "@". This can be used for UUCP mapping.
** For example, a call with {blia, ., UUCP} as arguments
** might return {ucsfcgl, !, blia, ., UUCP} as the result.
** We first break the input into three parts -- before the
** lookup, the lookup itself, and after the lookup. We
** then do the lookup, concatenate them together, and rescan
** pvp -- the parameter vector to map.
** The result of the mapping. If nothing found, it
** should just concatenate the three parts together and
** Extract the three parts of the input as strings.
/* find the part before the lookup */
for (bvp
= pvp
; *bvp
!= NULL
&& **bvp
!= MATCHLOOKUP
; bvp
++)
cataddr(pvp
, buf1
, sizeof buf1
);
/* find the rest of the lookup */
for (avp
= bvp
; *pvp
!= NULL
&& **bvp
!= MATCHELOOKUP
; bvp
++)
cataddr(avp
, buf2
, sizeof buf2
);
/* save the part after the lookup */
cataddr(bvp
, buf3
, sizeof buf3
);
** Now look up the middle part.
** Put the three parts back together and break into tokens.
avp
= prescan(buf1
, '\0');
/* return this mapping */