⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 udb.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
 * Copyright (c) 1988, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 *
 */

#include <sendmail.h>

#ifndef lint
# if USERDB
static char id[] = "@(#)$Id: udb.c,v 8.111 1999/11/16 02:04:04 gshapiro Exp $ (with USERDB)";
# else /* USERDB */
static char id[] = "@(#)$Id: udb.c,v 8.111 1999/11/16 02:04:04 gshapiro Exp $ (without USERDB)";
# endif /* USERDB */
#endif /* ! lint */

#if USERDB

# ifdef NEWDB
#  include <db.h>
#  ifndef DB_VERSION_MAJOR
#   define DB_VERSION_MAJOR 1
#  endif /* ! DB_VERSION_MAJOR */
# else /* NEWDB */
#  define DBT	struct _data_base_thang_
DBT
{
	void	*data;		/* pointer to data */
	size_t	size;		/* length of data */
};
# endif /* NEWDB */

/*
**  UDB.C -- interface between sendmail and Berkeley User Data Base.
**
**	This depends on the 4.4BSD db package.
*/


struct udbent
{
	char	*udb_spec;		/* string version of spec */
	int	udb_type;		/* type of entry */
	pid_t	udb_pid;		/* PID of process which opened db */
	char	*udb_default;		/* default host for outgoing mail */
	union
	{
# if NETINET || NETINET6
		/* type UE_REMOTE -- do remote call for lookup */
		struct
		{
			SOCKADDR	_udb_addr;	/* address */
			int		_udb_timeout;	/* timeout */
		} udb_remote;
#  define udb_addr	udb_u.udb_remote._udb_addr
#  define udb_timeout	udb_u.udb_remote._udb_timeout
# endif /* NETINET || NETINET6 */

		/* type UE_FORWARD -- forward message to remote */
		struct
		{
			char	*_udb_fwdhost;	/* name of forward host */
		} udb_forward;
# define udb_fwdhost	udb_u.udb_forward._udb_fwdhost

# ifdef NEWDB
		/* type UE_FETCH -- lookup in local database */
		struct
		{
			char	*_udb_dbname;	/* pathname of database */
			DB	*_udb_dbp;	/* open database ptr */
		} udb_lookup;
#  define udb_dbname	udb_u.udb_lookup._udb_dbname
#  define udb_dbp	udb_u.udb_lookup._udb_dbp
# endif /* NEWDB */
	} udb_u;
};

# define UDB_EOLIST	0	/* end of list */
# define UDB_SKIP	1	/* skip this entry */
# define UDB_REMOTE	2	/* look up in remote database */
# define UDB_DBFETCH	3	/* look up in local database */
# define UDB_FORWARD	4	/* forward to remote host */
# define UDB_HESIOD	5	/* look up via hesiod */

# define MAXUDBENT	10	/* maximum number of UDB entries */


struct udb_option
{
	char	*udbo_name;
	char	*udbo_val;
};

# ifdef HESIOD
static int	hes_udb_get __P((DBT *, DBT *));
# endif /* HESIOD */
static char	*udbmatch __P((char *, char *));
static int	_udbx_init __P((ENVELOPE *));
static int	_udb_parsespec __P((char *, struct udb_option [], int));

/*
**  UDBEXPAND -- look up user in database and expand
**
**	Parameters:
**		a -- address to expand.
**		sendq -- pointer to head of sendq to put the expansions in.
**		aliaslevel -- the current alias nesting depth.
**		e -- the current envelope.
**
**	Returns:
**		EX_TEMPFAIL -- if something "odd" happened -- probably due
**			to accessing a file on an NFS server that is down.
**		EX_OK -- otherwise.
**
**	Side Effects:
**		Modifies sendq.
*/

static struct udbent	UdbEnts[MAXUDBENT + 1];
static bool		UdbInitialized = FALSE;

int
udbexpand(a, sendq, aliaslevel, e)
	register ADDRESS *a;
	ADDRESS **sendq;
	int aliaslevel;
	register ENVELOPE *e;
{
	int i;
	DBT key;
	DBT info;
	bool breakout;
	register struct udbent *up;
	int keylen;
	int naddrs;
	char *user;
	char keybuf[MAXKEY];

	memset(&key, '\0', sizeof key);
	memset(&info, '\0', sizeof info);

	if (tTd(28, 1))
		dprintf("udbexpand(%s)\n", a->q_paddr);

	/* make certain we are supposed to send to this address */
	if (!QS_IS_SENDABLE(a->q_state))
		return EX_OK;
	e->e_to = a->q_paddr;

	/* on first call, locate the database */
	if (!UdbInitialized)
	{
		if (_udbx_init(e) == EX_TEMPFAIL)
			return EX_TEMPFAIL;
	}

	/* short circuit the process if no chance of a match */
	if (UdbSpec == NULL || UdbSpec[0] == '\0')
		return EX_OK;

	/* extract user to do userdb matching on */
	user = a->q_user;

	/* short circuit name begins with '\\' since it can't possibly match */
	/* (might want to treat this as unquoted instead) */
	if (user[0] == '\\')
		return EX_OK;

	/* if name is too long, assume it won't match */
	if (strlen(user) > (SIZE_T) sizeof keybuf - 12)
		return EX_OK;

	/* if name begins with a colon, it indicates our metadata */
	if (user[0] == ':')
		return EX_OK;

	/* build actual database key */
	(void) strlcpy(keybuf, user, sizeof keybuf);
	(void) strlcat(keybuf, ":maildrop", sizeof keybuf);
	keylen = strlen(keybuf);

	breakout = FALSE;
	for (up = UdbEnts; !breakout; up++)
	{
		int usersize;
		int userleft;
		char userbuf[MEMCHUNKSIZE];
# if defined(HESIOD) && defined(HES_GETMAILHOST)
		char pobuf[MAXNAME];
# endif /* defined(HESIOD) && defined(HES_GETMAILHOST) */
# if defined(NEWDB) && DB_VERSION_MAJOR > 1
		DBC *dbc = NULL;
# endif /* defined(NEWDB) && DB_VERSION_MAJOR > 1 */

		user = userbuf;
		userbuf[0] = '\0';
		usersize = sizeof userbuf;
		userleft = sizeof userbuf - 1;

		/*
		**  Select action based on entry type.
		**
		**	On dropping out of this switch, "class" should
		**	explain the type of the data, and "user" should
		**	contain the user information.
		*/

		switch (up->udb_type)
		{
# ifdef NEWDB
		  case UDB_DBFETCH:
			key.data = keybuf;
			key.size = keylen;
			if (tTd(28, 80))
				dprintf("udbexpand: trying %s (%d) via db\n",
					keybuf, keylen);
#  if DB_VERSION_MAJOR < 2
			i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_CURSOR);
#  else /* DB_VERSION_MAJOR < 2 */
			i = 0;
			if (dbc == NULL &&
#   if DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6
			    (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
							    NULL, &dbc, 0)) != 0)
#   else /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
			    (errno = (*up->udb_dbp->cursor)(up->udb_dbp,
							    NULL, &dbc)) != 0)
#   endif /* DB_VERSION_MAJOR > 2 || DB_VERSION_MINOR >= 6 */
				i = -1;
			if (i != 0 || dbc == NULL ||
			    (errno = dbc->c_get(dbc, &key,
						&info, DB_SET)) != 0)
				i = 1;
#  endif /* DB_VERSION_MAJOR < 2 */
			if (i > 0 || info.size <= 0)
			{
				if (tTd(28, 2))
					dprintf("udbexpand: no match on %s (%d)\n",
						keybuf, keylen);
#  if DB_VERSION_MAJOR > 1
				if (dbc != NULL)
				{
					(void) dbc->c_close(dbc);
					dbc = NULL;
				}
#  endif /* DB_VERSION_MAJOR > 1 */
				break;
			}
			if (tTd(28, 80))
				dprintf("udbexpand: match %.*s: %.*s\n",
					(int) key.size, (char *) key.data,
					(int) info.size, (char *) info.data);

			a->q_flags &= ~QSELFREF;
			while (i == 0 && key.size == keylen &&
			       memcmp(key.data, keybuf, keylen) == 0)
			{
				char *p;

				if (bitset(EF_VRFYONLY, e->e_flags))
				{
					a->q_state = QS_VERIFIED;
#  if DB_VERSION_MAJOR > 1
					if (dbc != NULL)
					{
						(void) dbc->c_close(dbc);
						dbc = NULL;
					}
#  endif /* DB_VERSION_MAJOR > 1 */
					return EX_OK;
				}

				breakout = TRUE;
				if (info.size >= userleft - 1)
				{
					char *nuser;
					int size = MEMCHUNKSIZE;

					if (info.size > MEMCHUNKSIZE)
						size = info.size;
					nuser = xalloc(usersize + size);

					memmove(nuser, user, usersize);
					if (user != userbuf)
						free(user);
					user = nuser;
					usersize += size;
					userleft += size;
				}
				p = &user[strlen(user)];
				if (p != user)
				{
					*p++ = ',';
					userleft--;
				}
				memmove(p, info.data, info.size);
				p[info.size] = '\0';
				userleft -= info.size;

				/* get the next record */
#  if DB_VERSION_MAJOR < 2
				i = (*up->udb_dbp->seq)(up->udb_dbp, &key, &info, R_NEXT);
#  else /* DB_VERSION_MAJOR < 2 */
				i = 0;
				if ((errno = dbc->c_get(dbc, &key,
							&info, DB_NEXT)) != 0)
					i = 1;
#  endif /* DB_VERSION_MAJOR < 2 */
			}

#  if DB_VERSION_MAJOR > 1
			if (dbc != NULL)
			{
				(void) dbc->c_close(dbc);
				dbc = NULL;
			}
#  endif /* DB_VERSION_MAJOR > 1 */

			/* if nothing ever matched, try next database */
			if (!breakout)
				break;

			message("expanded to %s", user);
			if (LogLevel > 10)
				sm_syslog(LOG_INFO, e->e_id,
					  "expand %.100s => %s",
					  e->e_to,
					  shortenstring(user, MAXSHORTSTR));
			naddrs = sendtolist(user, a, sendq, aliaslevel + 1, e);
			if (naddrs > 0 && !bitset(QSELFREF, a->q_flags))
			{
				if (tTd(28, 5))
				{
					dprintf("udbexpand: QS_EXPANDED ");
					printaddr(a, FALSE);
				}
				a->q_state = QS_EXPANDED;
			}
			if (i < 0)
			{
				syserr("udbexpand: db-get %.*s stat %d",
					(int) key.size, (char *) key.data, i);
				return EX_TEMPFAIL;
			}

			/*
			**  If this address has a -request address, reflect
			**  it into the envelope.
			*/

			memset(&key, '\0', sizeof key);
			memset(&info, '\0', sizeof info);
			(void) strlcpy(keybuf, a->q_user, sizeof keybuf);
			(void) strlcat(keybuf, ":mailsender", sizeof keybuf);
			keylen = strlen(keybuf);
			key.data = keybuf;
			key.size = keylen;

#  if DB_VERSION_MAJOR < 2
			i = (*up->udb_dbp->get)(up->udb_dbp, &key, &info, 0);
#  else /* DB_VERSION_MAJOR < 2 */
			i = errno = (*up->udb_dbp->get)(up->udb_dbp, NULL,
							&key, &info, 0);
#  endif /* DB_VERSION_MAJOR < 2 */
			if (i != 0 || info.size <= 0)
				break;
			a->q_owner = xalloc(info.size + 1);
			memmove(a->q_owner, info.data, info.size);
			a->q_owner[info.size] = '\0';

			/* announce delivery; NORECEIPT bit set later */
			if (e->e_xfp != NULL)
			{
				fprintf(e->e_xfp,
					"Message delivered to mailing list %s\n",
					a->q_paddr);
			}
			e->e_flags |= EF_SENDRECEIPT;
			a->q_flags |= QDELIVERED|QEXPANDED;
			break;
# endif /* NEWDB */

# ifdef HESIOD
		  case UDB_HESIOD:
			key.data = keybuf;
			key.size = keylen;
			if (tTd(28, 80))
				dprintf("udbexpand: trying %s (%d) via hesiod\n",
					keybuf, keylen);
			/* look up the key via hesiod */
			i = hes_udb_get(&key, &info);
			if (i < 0)
			{
				syserr("udbexpand: hesiod-get %.*s stat %d",
					(int) key.size, (char *) key.data, i);
				return EX_TEMPFAIL;
			}
			else if (i > 0 || info.size <= 0)
			{
#  if HES_GETMAILHOST
				struct hes_postoffice *hp;
#  endif /* HES_GETMAILHOST */

				if (tTd(28, 2))
					dprintf("udbexpand: no match on %s (%d)\n",
						(char *) keybuf, (int) keylen);
#  if HES_GETMAILHOST
				if (tTd(28, 8))
					dprintf("  ... trying hes_getmailhost(%s)\n",
						a->q_user);
				hp = hes_getmailhost(a->q_user);
				if (hp == NULL)
				{
					if (hes_error() == HES_ER_NET)
					{
						syserr("udbexpand: hesiod-getmail %s stat %d",
							a->q_user, hes_error());
						return EX_TEMPFAIL;
					}
					if (tTd(28, 2))
						dprintf("hes_getmailhost(%s): %d\n",
							a->q_user, hes_error());
					break;
				}
				if (strlen(hp->po_name) + strlen(hp->po_host) >
				    sizeof pobuf - 2)
				{
					if (tTd(28, 2))
						dprintf("hes_getmailhost(%s): expansion too long: %.30s@%.30s\n",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -