📄 alias.c
字号:
FILE *af;
bool nolock = FALSE;
bool success = FALSE;
long sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK;
sigfunc_t oldsigint, oldsigquit;
#ifdef SIGTSTP
sigfunc_t oldsigtstp;
#endif /* SIGTSTP */
if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
return FALSE;
if (!bitnset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail))
sff |= SFF_NOWLINK;
if (!bitnset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail))
sff |= SFF_NOGWFILES;
if (!bitnset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail))
sff |= SFF_NOWWFILES;
/* try to lock the source file */
if ((af = safefopen(map->map_file, O_RDWR, 0, sff)) == NULL)
{
struct stat stb;
if ((errno != EACCES && errno != EROFS) || automatic ||
(af = safefopen(map->map_file, O_RDONLY, 0, sff)) == NULL)
{
int saveerr = errno;
if (tTd(27, 1))
dprintf("Can't open %s: %s\n",
map->map_file, errstring(saveerr));
if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
message("newaliases: cannot open %s: %s",
map->map_file, errstring(saveerr));
errno = 0;
return FALSE;
}
nolock = TRUE;
if (tTd(27, 1) ||
fstat(fileno(af), &stb) < 0 ||
bitset(S_IWUSR|S_IWGRP|S_IWOTH, stb.st_mode))
message("warning: cannot lock %s: %s",
map->map_file, errstring(errno));
}
/* see if someone else is rebuilding the alias file */
if (!nolock &&
!lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
{
/* yes, they are -- wait until done */
message("Alias file %s is locked (maybe being rebuilt)",
map->map_file);
if (OpMode != MD_INITALIAS)
{
/* wait for other rebuild to complete */
(void) lockfile(fileno(af), map->map_file, NULL,
LOCK_EX);
}
(void) fclose(af);
errno = 0;
return FALSE;
}
oldsigint = setsignal(SIGINT, SIG_IGN);
oldsigquit = setsignal(SIGQUIT, SIG_IGN);
#ifdef SIGTSTP
oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
#endif /* SIGTSTP */
if (map->map_class->map_open(map, O_RDWR))
{
if (LogLevel > 7)
{
sm_syslog(LOG_NOTICE, NOQID,
"alias database %s %srebuilt by %s",
map->map_file, automatic ? "auto" : "",
username());
}
map->map_mflags |= MF_OPEN|MF_WRITABLE;
map->map_pid = getpid();
readaliases(map, af, !automatic, TRUE);
success = TRUE;
}
else
{
if (tTd(27, 1))
dprintf("Can't create database for %s: %s\n",
map->map_file, errstring(errno));
if (!automatic)
syserr("Cannot create database for alias file %s",
map->map_file);
}
/* close the file, thus releasing locks */
(void) fclose(af);
/* add distinguished entries and close the database */
if (bitset(MF_OPEN, map->map_mflags))
{
map->map_class->map_close(map);
map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
}
/* restore the old signals */
(void) setsignal(SIGINT, oldsigint);
(void) setsignal(SIGQUIT, oldsigquit);
# ifdef SIGTSTP
(void) setsignal(SIGTSTP, oldsigtstp);
# endif /* SIGTSTP */
return success;
}
/*
** 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:
** map -- the alias database descriptor.
** af -- file to read the aliases from.
** announcestats -- announce statistics regarding number of
** aliases, longest alias, etc.
** logstats -- lot the same info.
**
** Returns:
** none.
**
** Side Effects:
** Reads aliasfile into the symbol table.
** Optionally, builds the .dir & .pag files.
*/
void
readaliases(map, af, announcestats, logstats)
register MAP *map;
FILE *af;
bool announcestats;
bool logstats;
{
register char *p;
char *rhs;
bool skipping;
long naliases, bytes, longest;
ADDRESS al, bl;
char line[BUFSIZ];
/*
** Read and interpret lines
*/
FileName = map->map_file;
LineNumber = 0;
naliases = bytes = longest = 0;
skipping = FALSE;
while (fgets(line, sizeof line, af) != NULL)
{
int lhssize, rhssize;
int c;
LineNumber++;
p = strchr(line, '\n');
while (p != NULL && p > line && p[-1] == '\\')
{
p--;
if (fgets(p, SPACELEFT(line, p), af) == NULL)
break;
LineNumber++;
p = strchr(p, '\n');
}
if (p != NULL)
*p = '\0';
else if (!feof(af))
{
errno = 0;
syserr("554 5.3.0 alias line too long");
/* flush to end of line */
while ((c = getc(af)) != EOF && c != '\n')
continue;
/* skip any continuation lines */
skipping = TRUE;
continue;
}
switch (line[0])
{
case '#':
case '\0':
skipping = FALSE;
continue;
case ' ':
case '\t':
if (!skipping)
syserr("554 5.3.5 Non-continuation line starts with space");
skipping = TRUE;
continue;
}
skipping = FALSE;
/*
** Process the LHS
** Find the colon separator, 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++ != ':')
{
syserr("554 5.3.5 missing colon");
continue;
}
if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
{
syserr("554 5.3.5 %.40s... illegal alias name", line);
continue;
}
/*
** Process the RHS.
** 'al' is the internal form of the LHS address.
** 'p' points to the text of the RHS.
*/
while (isascii(*p) && isspace(*p))
p++;
rhs = p;
for (;;)
{
register char *nlp;
nlp = &p[strlen(p)];
if (nlp[-1] == '\n')
*--nlp = '\0';
if (CheckAliases)
{
/* do parsing & compression of addresses */
while (*p != '\0')
{
auto char *delimptr;
while ((isascii(*p) && isspace(*p)) ||
*p == ',')
p++;
if (*p == '\0')
break;
if (parseaddr(p, &bl, RF_COPYNONE, ',',
&delimptr, CurEnv) == NULL)
usrerr("553 5.3.5 %s... bad address", p);
p = delimptr;
}
}
else
{
p = nlp;
}
/* see if there should be a continuation line */
c = getc(af);
if (!feof(af))
(void) ungetc(c, af);
if (c != ' ' && c != '\t')
break;
/* read continuation line */
if (fgets(p, sizeof line - (p - line), af) == NULL)
break;
LineNumber++;
/* check for line overflow */
if (strchr(p, '\n') == NULL && !feof(af))
{
usrerr("554 5.3.5 alias too long");
while ((c = fgetc(af)) != EOF && c != '\n')
continue;
skipping = TRUE;
break;
}
}
if (skipping)
continue;
if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
{
syserr("554 5.3.5 %s... cannot alias non-local names",
al.q_paddr);
continue;
}
/*
** Insert alias into symbol table or database file.
**
** Special case pOStmaStER -- always make it lower case.
*/
if (strcasecmp(al.q_user, "postmaster") == 0)
makelower(al.q_user);
lhssize = strlen(al.q_user);
rhssize = strlen(rhs);
if (rhssize > 0)
{
/* is RHS empty (just spaces)? */
p = rhs;
while (isascii(*p) && isspace(*p))
p++;
}
if (rhssize == 0 || *p == '\0')
{
syserr("554 5.3.5 %.40s... missing value for alias",
line);
}
else
{
map->map_class->map_store(map, al.q_user, rhs);
/* statistics */
naliases++;
bytes += lhssize + rhssize;
if (rhssize > longest)
longest = rhssize;
}
if (al.q_paddr != NULL)
free(al.q_paddr);
if (al.q_host != NULL)
free(al.q_host);
if (al.q_user != NULL)
free(al.q_user);
}
CurEnv->e_to = NULL;
FileName = NULL;
if (Verbose || announcestats)
message("%s: %ld aliases, longest %ld bytes, %ld bytes total",
map->map_file, naliases, longest, bytes);
if (LogLevel > 7 && logstats)
sm_syslog(LOG_INFO, NOQID,
"%s: %ld aliases, longest %ld bytes, %ld bytes total",
map->map_file, naliases, longest, bytes);
}
/*
** 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.
** sendq -- a pointer to the head of the send queue to
** put this user's aliases in.
** aliaslevel -- the current alias nesting depth.
** e -- the current envelope.
**
** Returns:
** none.
**
** Side Effects:
** New names are added to send queues.
*/
void
forward(user, sendq, aliaslevel, e)
ADDRESS *user;
ADDRESS **sendq;
int aliaslevel;
register ENVELOPE *e;
{
char *pp;
char *ep;
bool got_transient;
if (tTd(27, 1))
dprintf("forward(%s)\n", user->q_paddr);
if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
!QS_IS_OK(user->q_state))
return;
if (user->q_home == NULL)
{
syserr("554 5.3.0 forward: no home");
user->q_home = "/no/such/directory";
}
/* 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);
if (ForwardPath == NULL)
ForwardPath = newstr("\201z/.forward");
got_transient = FALSE;
for (pp = ForwardPath; pp != NULL; pp = ep)
{
int err;
char buf[MAXPATHLEN + 1];
struct stat st;
ep = strchr(pp, SEPARATOR);
if (ep != NULL)
*ep = '\0';
expand(pp, buf, sizeof buf, e);
if (ep != NULL)
*ep++ = SEPARATOR;
if (buf[0] == '\0')
continue;
if (tTd(27, 3))
dprintf("forward: trying %s\n", buf);
err = include(buf, TRUE, user, sendq, aliaslevel, e);
if (err == 0)
break;
else if (transienterror(err))
{
/* we may have to suspend this message */
got_transient = TRUE;
if (tTd(27, 2))
dprintf("forward: transient error on %s\n",
buf);
if (LogLevel > 2)
{
char *curhost = CurHostName;
CurHostName = NULL;
sm_syslog(LOG_ERR, e->e_id,
"forward %s: transient error: %s",
buf, errstring(err));
CurHostName = curhost;
}
}
else
{
switch (err)
{
case ENOENT:
break;
case E_SM_WWDIR:
case E_SM_GWDIR:
/* check if it even exists */
if (stat(buf, &st) < 0 && errno == ENOENT)
{
if (bitnset(DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH,
DontBlameSendmail))
break;
}
/* FALLTHROUGH */
#if _FFR_FORWARD_SYSERR
case E_SM_NOSLINK:
case E_SM_NOHLINK:
case E_SM_REGONLY:
case E_SM_ISEXEC:
case E_SM_WWFILE:
case E_SM_GWFILE:
syserr("forward: %s: %s", buf, errstring(err));
break;
#endif /* _FFR_FORWARD_SYSERR */
default:
if (LogLevel > (RunAsUid == 0 ? 2 : 10))
sm_syslog(LOG_WARNING, e->e_id,
"forward %s: %s", buf,
errstring(err));
if (Verbose)
message("forward: %s: %s",
buf,
errstring(err));
break;
}
}
}
if (pp == NULL && got_transient)
{
/*
** There was no successful .forward open and at least one
** transient open. We have to defer this address for
** further delivery.
*/
message("transient .forward open error: message queued");
user->q_state = QS_QUEUEUP;
return;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -