* Copyright (c) 1983 Eric P. Allman
* Copyright (c) 1988 Regents of the University of California.
* %sccs.include.redist.c%
ERROR
: DBM is no longer supported
-- use NDBM instead
.
static char sccsid
[] = "@(#)alias.c 6.36 (Berkeley) %G% (with NEWDB and NDBM)";
static char sccsid
[] = "@(#)alias.c 6.36 (Berkeley) %G% (with NEWDB)";
static char sccsid
[] = "@(#)alias.c 6.36 (Berkeley) %G% (with NDBM)";
static char sccsid
[] = "@(#)alias.c 6.36 (Berkeley) %G% (without NEWDB or NDBM)";
** 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.
** e -- the current envelope.
** Aliases found are expanded.
** If NoAlias (the "-n" flag) is set, no aliasing is
** It should complain about names that are aliased to
** Sun YP servers read the dbm files directly, so we have to build them
# define IF_MAKEDBMFILES if (makedbmfiles)
extern ADDRESS
*sendto();
extern char *aliaslookup();
printf("alias(%s)\n", a
->q_paddr
);
/* don't realias already aliased names */
if (bitset(QDONTSEND
|QBADADDR
|QVERIFIED
, a
->q_flags
))
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
);
if (bitset(EF_VRFYONLY
, e
->e_flags
))
message("aliased to %s", p
);
syslog(LOG_INFO
, "%s: alias %s => %s", e
->e_id
, a
->q_paddr
, p
);
a
->q_child
= sendto(p
, 1, a
, 0);
if (naliases
> 0 && !bitset(QSELFREF
, a
->q_flags
))
printf("alias: QDONTSEND ");
** Look for owner of alias
(void) strcpy(obuf
, "owner-");
if (strncmp(a
->q_user
, "owner-", 6) == 0)
(void) strcat(obuf
, "owner");
(void) strcat(obuf
, a
->q_user
);
if (!bitnset(M_USR_UPPER
, a
->q_mailer
->m_flags
))
owner
= aliaslookup(obuf
);
if (strchr(owner
, ',') != NULL
)
a
->q_owner
= newstr(owner
);
** ALIASLOOKUP -- look up a name in the alias file.
** name -- the name to look up.
** The return value will be trashed across calls.
char keybuf
[MAXNAME
+ 1];
# if defined(NEWDB) || defined(NDBM)
# else /* neither NEWDB nor NDBM */
/* create a key for fetch */
if (!bitnset(M_USR_UPPER
, LocalMailer
->m_flags
))
# if defined(NEWDB) || defined(NDBM)
i
= AliasDBptr
->get(AliasDBptr
, &lhs
.dbt
, &rhs
.dbt
, 0);
else if (AliasDBMptr
!= NULL
)
rhs
.dbm
= dbm_fetch(AliasDBMptr
, lhs
.dbm
);
rhs
.dbm
= dbm_fetch(AliasDBMptr
, lhs
.dbm
);
# else /* neither NEWDB nor NDBM */
s
= stab(keybuf
, ST_ALIAS
, ST_FIND
);
** INITALIASES -- initialize for aliasing
** Very different depending on whether we are running NDBM or not.
** aliasfile -- location of aliases.
** init -- if set and if NDBM, initialize the NDBM files.
** if NDBM: opens the database.
** if ~NDBM: reads the aliases into the symbol table.
initaliases(aliasfile
, init
, e
)
#if defined(NDBM) || defined(NEWDB)
static bool initialized
= FALSE
;
static int readaliases();
if (aliasfile
== NULL
|| stat(aliasfile
, &stb
) < 0)
if (aliasfile
!= NULL
&& init
)
syserr("554 Cannot open %s", aliasfile
);
# if defined(NDBM) || defined(NEWDB)
** Check to see that the alias file is complete.
** If not, we will assume that someone died, and it is up
(void) strcpy(buf
, aliasfile
);
(void) strcat(buf
, ".db");
AliasDBptr
= dbopen(buf
, O_RDONLY
, DBMMODE
, DB_HASH
, NULL
);
AliasDBMptr
= dbm_open(aliasfile
, O_RDONLY
, DBMMODE
);
syserr("WARNING: initaliases: cannot open %s", buf
);
syserr("WARNING: initaliases: cannot open %s", buf
);
AliasDBMptr
= dbm_open(aliasfile
, O_RDONLY
, DBMMODE
);
syserr("WARNING: initaliases: cannot open DBM database %s.{pag,dir}",
while (!init
&& atcnt
-- >= 0 && aliaslookup("@") == NULL
)
** Reinitialize alias file in case the new
** one is mv'ed in instead of cp'ed in.
** Only works with new DBM -- old one will
** just consume file descriptors forever.
** If you have a dbmclose() it can be
** added before the sleep(30).
AliasDBptr
->close(AliasDBptr
);
(void) strcpy(buf
, aliasfile
);
(void) strcat(buf
, ".db");
dbopen(buf
, O_RDONLY
, DBMMODE
, DB_HASH
, NULL
);
AliasDBMptr
= dbm_open(aliasfile
, O_RDONLY
, DBMMODE
);
syserr("WARNING: initaliases: cannot open %s", buf
);
AliasDBMptr
= dbm_open(aliasfile
, O_RDONLY
, DBMMODE
);
syserr("WARNING: initaliases: cannot open DBM database %s.{pag,dir}",
** See if the NDBM 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.
** Note the unpalatable hack to see if the stat succeeded.
(void) strcpy(buf
, aliasfile
);
(void) strcat(buf
, ".db");
(void) strcat(buf
, ".pag");
if (!init
&& (stat(buf
, &stb
) < 0 || stb
.st_mtime
< modtime
|| atcnt
< 0))
if (AutoRebuild
&& stb
.st_ino
!= 0 && stb
.st_uid
== geteuid())
message("rebuilding alias database");
syslog(LOG_INFO
, "rebuilding alias database");
syslog(LOG_INFO
, "alias database out of date");
message("Warning: alias database out of date");
** If necessary, load the NDBM file.
** If running without NDBM, load the symbol table.
syslog(LOG_NOTICE
, "alias database %srebuilt by %s",
automatic
? "auto" : "", username());
readaliases(aliasfile
, TRUE
, e
);
readaliases(aliasfile
, init
, e
);
** 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 NDBM stuff.
** Reads aliasfile into the symbol table.
** Optionally, builds the .dir & .pag files.
readaliases(aliasfile
, init
, e
)
int naliases
, bytes
, longest
;
if ((af
= fopen(aliasfile
, "r+")) == NULL
)
syserr("554 Can't open %s", aliasfile
);
printf("Can't open %s\n", aliasfile
);
# if defined(NDBM) || defined(NEWDB)
/* see if someone else is rebuilding the alias file already */
if (!lockfile(fileno(af
), aliasfile
, LOCK_EX
|LOCK_NB
))
/* yes, they are -- wait until done and then return */
message("Alias file is already being rebuilt");
if (OpMode
!= MD_INITALIAS
)
/* wait for other rebuild to complete */
(void) lockfile(fileno(af
), aliasfile
, LOCK_EX
);
** If initializing, create the new DBM files.
oldsigint
= signal(SIGINT
, SIG_IGN
);
(void) strcpy(line
, aliasfile
);
(void) strcat(line
, ".db");
O_RDWR
|O_CREAT
|O_TRUNC
, DBMMODE
, DB_HASH
, NULL
);
syserr("readaliases: cannot create %s", line
);
(void) signal(SIGINT
, oldsigint
);
makedbmfiles
= access("/var/yp/Makefile", R_OK
) == 0;
dbmp
= dbm_open(aliasfile
,
O_RDWR
|O_CREAT
|O_TRUNC
, DBMMODE
);
syserr("readaliases: cannot create %s.{dir,pag}",
(void) signal(SIGINT
, oldsigint
);
** Read and interpret lines
naliases
= bytes
= longest
= 0;
while (fgets(line
, sizeof (line
), af
) != NULL
)
syserr("554 Non-continuation line starts with space");
** Find the colon separator, 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 (isascii(*p
) && isspace(*p
))
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
;
if (init
&& CheckAliases
)
/* do parsing & compression of addresses */
while ((isascii(*p
) && isspace(*p
)) ||
if (parseaddr(p
, &bl
, -1, ',', &delimptr
, e
) == NULL
)
usrerr("553 %s... bad address", p
);
/* see if there should be a continuation line */
if (c
!= ' ' && c
!= '\t')
/* read continuation line */
if (fgets(p
, sizeof line
- (p
- line
), af
) == NULL
)
/* check for line overflow */
if (strchr(p
, '\n') == NULL
)
usrerr("554 alias too long");
** Insert alias into symbol table or DBM file
lhssize
= strlen(lhs
) + 1;
rhssize
= strlen(rhs
) + 1;
# if defined(NDBM) || defined(NEWDB)
content
.xx
.size
= rhssize
;
putstat
= dbp
->put(dbp
, &key
.dbt
, &content
.dbt
,
usrerr("050 Warning: duplicate alias name %s",
putstat
= dbp
->put(dbp
, &key
.dbt
,
syserr("readaliases: db put (%s)", al
.q_user
);
putstat
= dbm_store(dbmp
, key
.dbm
, content
.dbm
,
usrerr("050 Warning: duplicate alias name %s",
putstat
= dbm_store(dbmp
, key
.dbm
,
content
.dbm
, DBM_REPLACE
);
syserr("readaliases: dbm store (%s)",
s
= stab(al
.q_user
, ST_ALIAS
, ST_ENTER
);
s
->s_alias
= newstr(rhs
);
bytes
+= lhssize
+ rhssize
;
# if defined(NDBM) || defined(NEWDB)
/* add the distinquished alias "@" */
if (dbp
->sync(dbp
) != 0 ||
dbp
->put(dbp
, &key
.dbt
, &key
.dbt
, 0) != 0 ||
syserr("readaliases: db close failure");
static void nis_magic
__P((DBM
*dbmp
));
if (dbm_store(dbmp
, key
.dbm
, key
.dbm
, DBM_REPLACE
) != 0 ||
syserr("readaliases: dbm close failure");
/* restore the old signal */
(void) signal(SIGINT
, oldsigint
);
/* closing the alias file drops the lock */
message("%d aliases, longest %d bytes, %d bytes total",
naliases
, longest
, bytes
);
syslog(LOG_INFO
, "%d aliases, longest %d bytes, %d bytes total",
naliases
, longest
, bytes
);
** NIS_MAGIC -- Add NIS magic dbm data
** This adds the magic entries needed by SunOS to make this a valid
** dbmp -- a pointer to the DBM structure.
{ "YP_LAST_MODIFIED", sizeof "YP_LAST_MODIFIED" - 1 },
{ "YP_MASTER_NAME", sizeof "YP_MASTER_NAME" - 1 },
char hbuf
[MAXHOSTNAMELEN
];
(void) sprintf(tbuf
, "%010ld", curtime());
contents
[0].dsize
= strlen(tbuf
);
(void) myhostname(hbuf
, sizeof hbuf
);
contents
[1].dsize
= strlen(hbuf
);
for (i
= 0; i
< sizeof key
/ sizeof *key
; i
++)
if (dbm_store(dbmp
, key
[i
], contents
[i
], DBM_REPLACE
) != 0 ||
syserr("nis_magic: dbm_store failure");
** 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("554 forward: no home");
user
->q_home
= "/nosuchdirectory";
/* good address -- look for .forward file in home */
define('z', user
->q_home
, e
);
define('u', user
->q_user
, e
);
define('h', user
->q_host
, e
);
ForwardPath
= newstr("\201z/.forward");
for (pp
= ForwardPath
; pp
!= NULL
; pp
= ep
)
expand(pp
, buf
, &buf
[sizeof buf
- 1], e
);
printf("forward: trying %s\n", buf
);
err
= include(buf
, TRUE
, user
, sendq
, e
);
/* we have to suspend this message */
printf("forward: transient error on %s\n", buf
);
syslog(LOG_ERR
, "%s: forward %s: transient error: %e",
message("%s: %s: message queued", buf
, errstring(err
));
user
->q_flags
|= QQUEUEUP
|QDONTSEND
;
** 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 */