📄 udb.c
字号:
** Returns:
** EX_TEMPFAIL -- if it appeared it couldn't get hold of a
** database due to a host being down or some similar
** (recoverable) situation.
** EX_OK -- otherwise.
**
** Side Effects:
** Fills in the UdbEnts structure from UdbSpec.
*/
# define MAXUDBOPTS 27
static int
_udbx_init(e)
ENVELOPE *e;
{
int ents = 0;
register char *p;
register struct udbent *up;
if (UdbInitialized)
return EX_OK;
# ifdef UDB_DEFAULT_SPEC
if (UdbSpec == NULL)
UdbSpec = UDB_DEFAULT_SPEC;
# endif /* UDB_DEFAULT_SPEC */
p = UdbSpec;
up = UdbEnts;
while (p != NULL)
{
char *spec;
int l;
struct udb_option opts[MAXUDBOPTS + 1];
while (*p == ' ' || *p == '\t' || *p == ',')
p++;
if (*p == '\0')
break;
spec = p;
p = strchr(p, ',');
if (p != NULL)
*p++ = '\0';
if (ents >= MAXUDBENT)
{
syserr("Maximum number of UDB entries exceeded");
break;
}
/* extract options */
(void) _udb_parsespec(spec, opts, MAXUDBOPTS);
/*
** Decode database specification.
**
** In the sendmail tradition, the leading character
** defines the semantics of the rest of the entry.
**
** @hostname -- forward email to the indicated host.
** This should be the last in the list,
** since it always matches the input.
** /dbname -- search the named database on the local
** host using the Berkeley db package.
** Hesiod -- search the named database with BIND
** using the MIT Hesiod package.
*/
switch (*spec)
{
case '@': /* forward to remote host */
up->udb_type = UDB_FORWARD;
up->udb_pid = getpid();
up->udb_fwdhost = spec + 1;
ents++;
up++;
break;
# ifdef HESIOD
case 'h': /* use hesiod */
case 'H':
if (strcasecmp(spec, "hesiod") != 0)
goto badspec;
up->udb_type = UDB_HESIOD;
up->udb_pid = getpid();
ents++;
up++;
break;
# endif /* HESIOD */
# ifdef NEWDB
case '/': /* look up remote name */
l = strlen(spec);
if (l > 3 && strcmp(&spec[l - 3], ".db") == 0)
{
up->udb_dbname = spec;
}
else
{
up->udb_dbname = xalloc(l + 4);
(void) strlcpy(up->udb_dbname, spec, l + 4);
(void) strlcat(up->udb_dbname, ".db", l + 4);
}
errno = 0;
# if DB_VERSION_MAJOR < 2
up->udb_dbp = dbopen(up->udb_dbname, O_RDONLY,
0644, DB_BTREE, NULL);
# else /* DB_VERSION_MAJOR < 2 */
{
int flags = DB_RDONLY;
# if DB_VERSION_MAJOR > 2
int ret;
# endif /* DB_VERSION_MAJOR > 2 */
# if !HASFLOCK && defined(DB_FCNTL_LOCKING)
flags |= DB_FCNTL_LOCKING;
# endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */
up->udb_dbp = NULL;
# if DB_VERSION_MAJOR > 2
ret = db_create(&up->udb_dbp, NULL, 0);
if (ret != 0)
{
(void) up->udb_dbp->close(up->udb_dbp,
0);
up->udb_dbp = NULL;
}
else
{
ret = up->udb_dbp->open(up->udb_dbp,
up->udb_dbname,
NULL,
DB_BTREE,
flags,
0644);
if (ret != 0)
{
(void) up->udb_dbp->close(up->udb_dbp, 0);
up->udb_dbp = NULL;
}
}
errno = ret;
# else /* DB_VERSION_MAJOR > 2 */
errno = db_open(up->udb_dbname, DB_BTREE,
flags, 0644, NULL,
NULL, &up->udb_dbp);
# endif /* DB_VERSION_MAJOR > 2 */
}
# endif /* DB_VERSION_MAJOR < 2 */
if (up->udb_dbp == NULL)
{
if (tTd(28, 1))
{
int save_errno = errno;
# if DB_VERSION_MAJOR < 2
dprintf("dbopen(%s): %s\n",
# else /* DB_VERSION_MAJOR < 2 */
dprintf("db_open(%s): %s\n",
# endif /* DB_VERSION_MAJOR < 2 */
up->udb_dbname,
errstring(errno));
errno = save_errno;
}
if (errno != ENOENT && errno != EACCES)
{
if (LogLevel > 2)
sm_syslog(LOG_ERR, e->e_id,
# if DB_VERSION_MAJOR < 2
"dbopen(%s): %s",
# else /* DB_VERSION_MAJOR < 2 */
"db_open(%s): %s",
# endif /* DB_VERSION_MAJOR < 2 */
up->udb_dbname,
errstring(errno));
up->udb_type = UDB_EOLIST;
if (up->udb_dbname != spec)
free(up->udb_dbname);
goto tempfail;
}
if (up->udb_dbname != spec)
free(up->udb_dbname);
break;
}
if (tTd(28, 1))
{
# if DB_VERSION_MAJOR < 2
dprintf("_udbx_init: dbopen(%s)\n",
# else /* DB_VERSION_MAJOR < 2 */
dprintf("_udbx_init: db_open(%s)\n",
# endif /* DB_VERSION_MAJOR < 2 */
up->udb_dbname);
}
up->udb_type = UDB_DBFETCH;
up->udb_pid = getpid();
ents++;
up++;
break;
# endif /* NEWDB */
default:
# ifdef HESIOD
badspec:
# endif /* HESIOD */
syserr("Unknown UDB spec %s", spec);
break;
}
}
up->udb_type = UDB_EOLIST;
if (tTd(28, 4))
{
for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
{
switch (up->udb_type)
{
# if DAEMON
case UDB_REMOTE:
dprintf("REMOTE: addr %s, timeo %d\n",
anynet_ntoa((SOCKADDR *) &up->udb_addr),
up->udb_timeout);
break;
# endif /* DAEMON */
case UDB_DBFETCH:
# ifdef NEWDB
dprintf("FETCH: file %s\n",
up->udb_dbname);
# else /* NEWDB */
dprintf("FETCH\n");
# endif /* NEWDB */
break;
case UDB_FORWARD:
dprintf("FORWARD: host %s\n",
up->udb_fwdhost);
break;
case UDB_HESIOD:
dprintf("HESIOD\n");
break;
default:
dprintf("UNKNOWN\n");
break;
}
}
}
UdbInitialized = TRUE;
errno = 0;
return EX_OK;
/*
** On temporary failure, back out anything we've already done
*/
tempfail:
# ifdef NEWDB
for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
{
if (up->udb_type == UDB_DBFETCH)
{
# if DB_VERSION_MAJOR < 2
(*up->udb_dbp->close)(up->udb_dbp);
# else /* DB_VERSION_MAJOR < 2 */
errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
# endif /* DB_VERSION_MAJOR < 2 */
if (tTd(28, 1))
dprintf("_udbx_init: db->close(%s)\n",
up->udb_dbname);
}
}
# endif /* NEWDB */
return EX_TEMPFAIL;
}
static int
_udb_parsespec(udbspec, opt, maxopts)
char *udbspec;
struct udb_option opt[];
int maxopts;
{
register char *spec;
register char *spec_end;
register int optnum;
spec_end = strchr(udbspec, ':');
for (optnum = 0; optnum < maxopts && (spec = spec_end) != NULL; optnum++)
{
register char *p;
while (isascii(*spec) && isspace(*spec))
spec++;
spec_end = strchr(spec, ':');
if (spec_end != NULL)
*spec_end++ = '\0';
opt[optnum].udbo_name = spec;
opt[optnum].udbo_val = NULL;
p = strchr(spec, '=');
if (p != NULL)
opt[optnum].udbo_val = ++p;
}
return optnum;
}
/*
** _UDBX_CLOSE -- close all file based UDB entries.
**
** Parameters:
** none
**
** Returns:
** none
*/
void
_udbx_close()
{
pid_t pid;
struct udbent *up;
if (!UdbInitialized)
return;
pid = getpid();
for (up = UdbEnts; up->udb_type != UDB_EOLIST; up++)
{
if (up->udb_pid != pid)
continue;
# ifdef NEWDB
if (up->udb_type == UDB_DBFETCH)
{
# if DB_VERSION_MAJOR < 2
(*up->udb_dbp->close)(up->udb_dbp);
# else /* DB_VERSION_MAJOR < 2 */
errno = (*up->udb_dbp->close)(up->udb_dbp, 0);
# endif /* DB_VERSION_MAJOR < 2 */
}
if (tTd(28, 1))
dprintf("_udbx_init: db->close(%s)\n",
up->udb_dbname);
# endif /* NEWDB */
}
}
# ifdef HESIOD
static int
hes_udb_get(key, info)
DBT *key;
DBT *info;
{
char *name, *type;
char **hp;
char kbuf[MAXKEY + 1];
if (strlcpy(kbuf, key->data, sizeof kbuf) >= (SIZE_T) sizeof kbuf)
return 0;
name = kbuf;
type = strrchr(name, ':');
if (type == NULL)
return 1;
*type++ = '\0';
if (strchr(name, '@') != NULL)
return 1;
if (tTd(28, 1))
dprintf("hes_udb_get(%s, %s)\n", name, type);
/* make the hesiod query */
# ifdef HESIOD_INIT
if (HesiodContext == NULL && hesiod_init(&HesiodContext) != 0)
return -1;
hp = hesiod_resolve(HesiodContext, name, type);
# else /* HESIOD_INIT */
hp = hes_resolve(name, type);
# endif /* HESIOD_INIT */
*--type = ':';
# ifdef HESIOD_INIT
if (hp == NULL)
return 1;
if (*hp == NULL)
{
hesiod_free_list(HesiodContext, hp);
if (errno == ECONNREFUSED || errno == EMSGSIZE)
return -1;
return 1;
}
# else /* HESIOD_INIT */
if (hp == NULL || hp[0] == NULL)
{
/* network problem or timeout */
if (hes_error() == HES_ER_NET)
return -1;
return 1;
}
# endif /* HESIOD_INIT */
else
{
/*
** If there are multiple matches, just return the
** first one.
**
** XXX These should really be returned; for example,
** XXX it is legal for :maildrop to be multi-valued.
*/
info->data = hp[0];
info->size = (size_t) strlen(info->data);
}
if (tTd(28, 80))
dprintf("hes_udb_get => %s\n", *hp);
return 0;
}
# endif /* HESIOD */
#else /* USERDB */
int
udbexpand(a, sendq, aliaslevel, e)
ADDRESS *a;
ADDRESS **sendq;
int aliaslevel;
ENVELOPE *e;
{
return EX_OK;
}
#endif /* USERDB */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -