📄 map.c
字号:
map->map_mflags &= ~MF_VALID;
}
}
if (restore)
{
Errors = saveerrors;
HoldErrs = savehold;
QuickAbort = savequick;
}
return bitset(MF_OPEN, map->map_mflags);
}
/*
** CLOSEMAPS -- close all open maps opened by the current pid.
**
** Parameters:
** none
**
** Returns:
** none.
*/
void
closemaps()
{
stabapply(map_close, 0);
}
/*
** MAP_CLOSE -- close a map opened by the current pid.
**
** Parameters:
** s -- STAB entry: if map: try to open
** second parameter is unused (required by stabapply())
**
** Returns:
** none.
*/
/* ARGSUSED1 */
static void
map_close(s, unused)
register STAB *s;
int unused;
{
MAP *map;
if (s->s_type != ST_MAP)
return;
map = &s->s_map;
if (!bitset(MF_VALID, map->map_mflags) ||
!bitset(MF_OPEN, map->map_mflags) ||
map->map_pid != getpid())
return;
if (tTd(38, 5))
dprintf("closemaps: closing %s (%s)\n",
map->map_mname == NULL ? "NULL" : map->map_mname,
map->map_file == NULL ? "NULL" : map->map_file);
map->map_class->map_close(map);
map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
}
/*
** GETCANONNAME -- look up name using service switch
**
** Parameters:
** host -- the host name to look up.
** hbsize -- the size of the host buffer.
** trymx -- if set, try MX records.
**
** Returns:
** TRUE -- if the host was found.
** FALSE -- otherwise.
*/
bool
getcanonname(host, hbsize, trymx)
char *host;
int hbsize;
bool trymx;
{
int nmaps;
int mapno;
bool found = FALSE;
bool got_tempfail = FALSE;
auto int status;
char *maptype[MAXMAPSTACK];
short mapreturn[MAXMAPACTIONS];
nmaps = switch_map_find("hosts", maptype, mapreturn);
for (mapno = 0; mapno < nmaps; mapno++)
{
int i;
if (tTd(38, 20))
dprintf("getcanonname(%s), trying %s\n",
host, maptype[mapno]);
if (strcmp("files", maptype[mapno]) == 0)
{
found = text_getcanonname(host, hbsize, &status);
}
#ifdef NIS
else if (strcmp("nis", maptype[mapno]) == 0)
{
found = nis_getcanonname(host, hbsize, &status);
}
#endif /* NIS */
#ifdef NISPLUS
else if (strcmp("nisplus", maptype[mapno]) == 0)
{
found = nisplus_getcanonname(host, hbsize, &status);
}
#endif /* NISPLUS */
#if NAMED_BIND
else if (strcmp("dns", maptype[mapno]) == 0)
{
found = dns_getcanonname(host, hbsize, trymx, &status);
}
#endif /* NAMED_BIND */
#if NETINFO
else if (strcmp("netinfo", maptype[mapno]) == 0)
{
found = ni_getcanonname(host, hbsize, &status);
}
#endif /* NETINFO */
else
{
found = FALSE;
status = EX_UNAVAILABLE;
}
/*
** Heuristic: if $m is not set, we are running during system
** startup. In this case, when a name is apparently found
** but has no dot, treat is as not found. This avoids
** problems if /etc/hosts has no FQDN but is listed first
** in the service switch.
*/
if (found &&
(macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
break;
/* see if we should continue */
if (status == EX_TEMPFAIL)
{
i = MA_TRYAGAIN;
got_tempfail = TRUE;
}
else if (status == EX_NOTFOUND)
i = MA_NOTFOUND;
else
i = MA_UNAVAIL;
if (bitset(1 << mapno, mapreturn[i]))
break;
}
if (found)
{
char *d;
if (tTd(38, 20))
dprintf("getcanonname(%s), found\n", host);
/*
** If returned name is still single token, compensate
** by tagging on $m. This is because some sites set
** up their DNS or NIS databases wrong.
*/
if ((d = strchr(host, '.')) == NULL || d[1] == '\0')
{
d = macvalue('m', CurEnv);
if (d != NULL &&
hbsize > (int) (strlen(host) + strlen(d) + 1))
{
if (host[strlen(host) - 1] != '.')
(void) strlcat(host, ".", hbsize);
(void) strlcat(host, d, hbsize);
}
else
return FALSE;
}
return TRUE;
}
if (tTd(38, 20))
dprintf("getcanonname(%s), failed, status=%d\n", host, status);
#if NAMED_BIND
if (got_tempfail)
h_errno = TRY_AGAIN;
else
h_errno = HOST_NOT_FOUND;
#endif /* NAMED_BIND */
return FALSE;
}
/*
** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
**
** Parameters:
** name -- the name against which to match.
** line -- the /etc/hosts line.
** cbuf -- the location to store the result.
** cbuflen -- the size of cbuf.
**
** Returns:
** TRUE -- if the line matched the desired name.
** FALSE -- otherwise.
*/
static bool
extract_canonname(name, line, cbuf, cbuflen)
char *name;
char *line;
char cbuf[];
int cbuflen;
{
int i;
char *p;
bool found = FALSE;
cbuf[0] = '\0';
if (line[0] == '#')
return FALSE;
for (i = 1; ; i++)
{
char nbuf[MAXNAME + 1];
p = get_column(line, i, '\0', nbuf, sizeof nbuf);
if (p == NULL)
break;
if (*p == '\0')
continue;
if (cbuf[0] == '\0' ||
(strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
{
snprintf(cbuf, cbuflen, "%s", p);
}
if (strcasecmp(name, p) == 0)
found = TRUE;
}
if (found && strchr(cbuf, '.') == NULL)
{
/* try to add a domain on the end of the name */
char *domain = macvalue('m', CurEnv);
if (domain != NULL &&
strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen)
{
p = &cbuf[i];
*p++ = '.';
(void) strlcpy(p, domain, cbuflen - i - 1);
}
}
return found;
}
/*
** NDBM modules
*/
#ifdef NDBM
/*
** NDBM_MAP_OPEN -- DBM-style map open
*/
bool
ndbm_map_open(map, mode)
MAP *map;
int mode;
{
register DBM *dbm;
int save_errno;
int dfd;
int pfd;
long sff;
int ret;
int smode = S_IREAD;
char dirfile[MAXNAME + 1];
char pagfile[MAXNAME + 1];
struct stat st;
struct stat std, stp;
if (tTd(38, 2))
dprintf("ndbm_map_open(%s, %s, %d)\n",
map->map_mname, map->map_file, mode);
map->map_lockfd = -1;
mode &= O_ACCMODE;
/* do initial file and directory checks */
snprintf(dirfile, sizeof dirfile, "%s.dir", map->map_file);
snprintf(pagfile, sizeof pagfile, "%s.pag", map->map_file);
sff = SFF_ROOTOK|SFF_REGONLY;
if (mode == O_RDWR)
{
sff |= SFF_CREAT;
if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
sff |= SFF_NOSLINK;
if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
sff |= SFF_NOHLINK;
smode = S_IWRITE;
}
else
{
if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
sff |= SFF_NOWLINK;
}
if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
sff |= SFF_SAFEDIRPATH;
ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
sff, smode, &std);
if (ret == 0)
ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
sff, smode, &stp);
# if !_FFR_REMOVE_AUTOREBUILD
if (ret == ENOENT && AutoRebuild &&
bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
(bitset(MF_IMPL_NDBM, map->map_mflags) ||
bitset(MF_ALIAS, map->map_mflags)) &&
mode == O_RDONLY)
{
bool impl = bitset(MF_IMPL_NDBM, map->map_mflags);
/* may be able to rebuild */
map->map_mflags &= ~MF_IMPL_NDBM;
if (!rebuildaliases(map, TRUE))
return FALSE;
if (impl)
return impl_map_open(map, O_RDONLY);
else
return ndbm_map_open(map, O_RDONLY);
}
# endif /* !_FFR_REMOVE_AUTOREBUILD */
if (ret != 0)
{
char *prob = "unsafe";
/* cannot open this map */
if (ret == ENOENT)
prob = "missing";
if (tTd(38, 2))
dprintf("\t%s map file: %d\n", prob, ret);
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("dbm map \"%s\": %s map file %s",
map->map_mname, prob, map->map_file);
return FALSE;
}
if (std.st_mode == ST_MODE_NOFILE)
mode |= O_CREAT|O_EXCL;
# if LOCK_ON_OPEN
if (mode == O_RDONLY)
mode |= O_SHLOCK;
else
mode |= O_TRUNC|O_EXLOCK;
# else /* LOCK_ON_OPEN */
if ((mode & O_ACCMODE) == O_RDWR)
{
# if NOFTRUNCATE
/*
** Warning: race condition. Try to lock the file as
** quickly as possible after opening it.
** This may also have security problems on some systems,
** but there isn't anything we can do about it.
*/
mode |= O_TRUNC;
# else /* NOFTRUNCATE */
/*
** This ugly code opens the map without truncating it,
** locks the file, then truncates it. Necessary to
** avoid race conditions.
*/
int dirfd;
int pagfd;
long sff = SFF_CREAT|SFF_OPENASROOT;
if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
sff |= SFF_NOSLINK;
if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
sff |= SFF_NOHLINK;
dirfd = safeopen(dirfile, mode, DBMMODE, sff);
pagfd = safeopen(pagfile, mode, DBMMODE, sff);
if (dirfd < 0 || pagfd < 0)
{
save_errno = errno;
if (dirfd >= 0)
(void) close(dirfd);
if (pagfd >= 0)
(void) close(pagfd);
errno = save_errno;
syserr("ndbm_map_open: cannot create database %s",
map->map_file);
return FALSE;
}
if (ftruncate(dirfd, (off_t) 0) < 0 ||
ftruncate(pagfd, (off_t) 0) < 0)
{
save_errno = errno;
(void) close(dirfd);
(void) close(pagfd);
errno = save_errno;
syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
map->map_file);
return FALSE;
}
/* if new file, get "before" bits for later filechanged check */
if (std.st_mode == ST_MODE_NOFILE &&
(fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
{
save_errno = errno;
(void) close(dirfd);
(void) close(pagfd);
errno = save_errno;
syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
map->map_file);
return FALSE;
}
/* have to save the lock for the duration (bletch) */
map->map_lockfd = dirfd;
(void) close(pagfd);
/* twiddle bits for dbm_open */
mode &= ~(O_CREAT|O_EXCL);
# endif /* NOFTRUNCATE */
}
# endif /* LOCK_ON_OPEN */
/* open the database */
dbm = dbm_open(map->map_file, mode, DBMMODE);
if (dbm == NULL)
{
save_errno = errno;
if (bitset(MF_ALIAS, map->map_mflags) &&
aliaswait(map, ".pag", FALSE))
return TRUE;
# if !LOCK_ON_OPEN && !NOFTRUNCATE
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
errno = save_errno;
if (!bitset(MF_OPTIONAL, map->map_mflags))
syserr("Cannot open DBM database %s", map->map_file);
return FALSE;
}
dfd = dbm_dirfno(dbm);
pfd = dbm_pagfno(dbm);
if (dfd == pfd)
{
/* heuristic: if files are linked, this is actually gdbm */
dbm_close(dbm);
# if !LOCK_ON_OPEN && !NOFTRUNCATE
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
errno = 0;
syserr("dbm map \"%s\": cannot support GDBM",
map->map_mname);
return FALSE;
}
if (filechanged(dirfile, dfd, &std) ||
filechanged(pagfile, pfd, &stp))
{
save_errno = errno;
dbm_close(dbm);
# if !LOCK_ON_OPEN && !NOFTRUNCATE
if (map->map_lockfd >= 0)
(void) close(map->map_lockfd);
# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
errno = save_errno;
syserr("ndbm_map_open(%s): file changed after open",
map->map_file);
return FALSE;
}
map->map_db1 = (ARBPTR_T) dbm;
/*
** Need to set map_mtime before the call to aliaswait()
** as aliaswait() will call map_lookup() which requires
** map_mtime to be set
*/
if (fstat(dfd, &st) >= 0)
map->map_mtime = st.st_mtime;
if (mode == O_RDONLY)
{
# if LOCK_ON_OPEN
if (dfd >= 0)
(void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
if (pfd >= 0)
(void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
# endif /* LOCK_ON_OPEN */
if (bitset(MF_ALIAS, map->map_mflags) &&
!aliaswait(map, ".pag", TRUE))
return FALSE;
}
else
{
map->map_mflags |= MF_LOCKED;
if (geteuid() == 0 && TrustedUid != 0)
{
# if HASFCHOWN
if (fchown(dfd, TrustedUid, -1) < 0 ||
fchown(pfd, TrustedUid, -1) < 0)
{
int err = errno;
sm_syslog(LOG_ALERT, NOQID,
"ownership change on %s failed: %s",
map->map_file, errstring(err));
message("050 ownership change on %s failed: %s",
map->map_file, errstring(err));
}
# endif /* HASFCHOWN */
}
}
return TRUE;
}
/*
** NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
*/
char *
ndbm_map_lookup(map, name, av, statp)
MAP *map;
char *name;
char **av;
int *statp;
{
datum key, val;
int fd;
char keybuf[MAXNAME + 1];
struct stat stbuf;
if (tTd(38, 20))
dprintf("ndbm_map_lookup(%s, %s)\n",
map->map_mname, name);
key.dptr = name;
key.dsize = strlen(name);
if (!bitset(MF_NOFOLDCASE, map->map_mflags))
{
if (key.dsize > sizeof keybuf - 1)
key.dsize = sizeof keybuf - 1;
memmove(keybuf, key.dptr, key.dsize);
keybuf[key.dsize] = '\0';
makelower(keybuf);
key.dptr = keybuf;
}
lockdbm:
fd = dbm_dirfno((DBM *) map->map_db1);
if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
(void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
{
/* Reopen the database to sync the cache */
int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -