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

📄 map.c

📁 < linux网络编程工具>>配套源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 * Copyright (c) 1992, 1995-1997 Eric P. Allman.  All rights reserved.
 * Copyright (c) 1992, 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.
 *
 */

#ifndef lint
static char id[] = "@(#)$Id: map.c,v 8.414.4.24 2000/09/27 04:11:29 gshapiro Exp $";
#endif /* ! lint */

#include <sendmail.h>


#ifdef NDBM
# include <ndbm.h>
# ifdef R_FIRST
  ERROR README:	You are running the Berkeley DB version of ndbm.h.  See
  ERROR README:	the README file about tweaking Berkeley DB so it can
  ERROR README:	coexist with NDBM, or delete -DNDBM from the Makefile
  ERROR README: and use -DNEWDB instead.
# endif /* R_FIRST */
#endif /* NDBM */
#ifdef NEWDB
# include <db.h>
# ifndef DB_VERSION_MAJOR
#  define DB_VERSION_MAJOR 1
# endif /* ! DB_VERSION_MAJOR */
#endif /* NEWDB */
#ifdef NIS
  struct dom_binding;	/* forward reference needed on IRIX */
# include <rpcsvc/ypclnt.h>
# ifdef NDBM
#  define NDBM_YP_COMPAT	/* create YP-compatible NDBM files */
# endif /* NDBM */
#endif /* NIS */

#ifdef NEWDB
# if DB_VERSION_MAJOR < 2
static bool	db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
# endif /* DB_VERSION_MAJOR < 2 */
# if DB_VERSION_MAJOR == 2
static bool	db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
# endif /* DB_VERSION_MAJOR == 2 */
# if DB_VERSION_MAJOR > 2
static bool	db_map_open __P((MAP *, int, char *, DBTYPE, void **));
# endif /* DB_VERSION_MAJOR > 2 */
#endif /* NEWDB */
static bool	extract_canonname __P((char *, char *, char[], int));
#ifdef LDAPMAP
static void	ldapmap_clear __P((LDAPMAP_STRUCT *));
static STAB	*ldapmap_findconn __P((LDAPMAP_STRUCT *));
static int	ldapmap_geterrno __P((LDAP *));
static void	ldapmap_setopts __P((LDAP *, LDAPMAP_STRUCT *));
static bool	ldapmap_start __P((MAP *));
static void	ldaptimeout __P((int));
#endif /* LDAPMAP */
static void	map_close __P((STAB *, int));
static void	map_init __P((STAB *, int));
#ifdef NISPLUS
static bool	nisplus_getcanonname __P((char *, int, int *));
#endif /* NISPLUS */
#ifdef NIS
static bool	nis_getcanonname __P((char *, int, int *));
#endif /* NIS */
#if NETINFO
static bool	ni_getcanonname __P((char *, int, int *));
#endif /* NETINFO */
static bool	text_getcanonname __P((char *, int, int *));

/*
**  MAP.C -- implementations for various map classes.
**
**	Each map class implements a series of functions:
**
**	bool map_parse(MAP *map, char *args)
**		Parse the arguments from the config file.  Return TRUE
**		if they were ok, FALSE otherwise.  Fill in map with the
**		values.
**
**	char *map_lookup(MAP *map, char *key, char **args, int *pstat)
**		Look up the key in the given map.  If found, do any
**		rewriting the map wants (including "args" if desired)
**		and return the value.  Set *pstat to the appropriate status
**		on error and return NULL.  Args will be NULL if called
**		from the alias routines, although this should probably
**		not be relied upon.  It is suggested you call map_rewrite
**		to return the results -- it takes care of null termination
**		and uses a dynamically expanded buffer as needed.
**
**	void map_store(MAP *map, char *key, char *value)
**		Store the key:value pair in the map.
**
**	bool map_open(MAP *map, int mode)
**		Open the map for the indicated mode.  Mode should
**		be either O_RDONLY or O_RDWR.  Return TRUE if it
**		was opened successfully, FALSE otherwise.  If the open
**		failed an the MF_OPTIONAL flag is not set, it should
**		also print an error.  If the MF_ALIAS bit is set
**		and this map class understands the @:@ convention, it
**		should call aliaswait() before returning.
**
**	void map_close(MAP *map)
**		Close the map.
**
**	This file also includes the implementation for getcanonname.
**	It is currently implemented in a pretty ad-hoc manner; it ought
**	to be more properly integrated into the map structure.
*/

#define DBMMODE		0644

#ifndef EX_NOTFOUND
# define EX_NOTFOUND	EX_NOHOST
#endif /* ! EX_NOTFOUND */

#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
# define LOCK_ON_OPEN	1	/* we can open/create a locked file */
#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
# define LOCK_ON_OPEN	0	/* no such luck -- bend over backwards */
#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */

#ifndef O_ACCMODE
# define O_ACCMODE	(O_RDONLY|O_WRONLY|O_RDWR)
#endif /* ! O_ACCMODE */
/*
**  MAP_PARSEARGS -- parse config line arguments for database lookup
**
**	This is a generic version of the map_parse method.
**
**	Parameters:
**		map -- the map being initialized.
**		ap -- a pointer to the args on the config line.
**
**	Returns:
**		TRUE -- if everything parsed OK.
**		FALSE -- otherwise.
**
**	Side Effects:
**		null terminates the filename; stores it in map
*/

bool
map_parseargs(map, ap)
	MAP *map;
	char *ap;
{
	register char *p = ap;

	/*
	**  there is no check whether there is really an argument,
	**  but that's not important enough to warrant extra code
	*/
	map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
	map->map_spacesub = SpaceSub;	/* default value */
	for (;;)
	{
		while (isascii(*p) && isspace(*p))
			p++;
		if (*p != '-')
			break;
		switch (*++p)
		{
		  case 'N':
			map->map_mflags |= MF_INCLNULL;
			map->map_mflags &= ~MF_TRY0NULL;
			break;

		  case 'O':
			map->map_mflags &= ~MF_TRY1NULL;
			break;

		  case 'o':
			map->map_mflags |= MF_OPTIONAL;
			break;

		  case 'f':
			map->map_mflags |= MF_NOFOLDCASE;
			break;

		  case 'm':
			map->map_mflags |= MF_MATCHONLY;
			break;

		  case 'A':
			map->map_mflags |= MF_APPEND;
			break;

		  case 'q':
			map->map_mflags |= MF_KEEPQUOTES;
			break;

		  case 'a':
			map->map_app = ++p;
			break;

		  case 'T':
			map->map_tapp = ++p;
			break;

		  case 'k':
			while (isascii(*++p) && isspace(*p))
				continue;
			map->map_keycolnm = p;
			break;

		  case 'v':
			while (isascii(*++p) && isspace(*p))
				continue;
			map->map_valcolnm = p;
			break;

		  case 'z':
			if (*++p != '\\')
				map->map_coldelim = *p;
			else
			{
				switch (*++p)
				{
				  case 'n':
					map->map_coldelim = '\n';
					break;

				  case 't':
					map->map_coldelim = '\t';
					break;

				  default:
					map->map_coldelim = '\\';
				}
			}
			break;

		  case 't':
			map->map_mflags |= MF_NODEFER;
			break;


		  case 'S':
			map->map_spacesub = *++p;
			break;

		  case 'D':
			map->map_mflags |= MF_DEFER;
			break;

		  default:
			syserr("Illegal option %c map %s", *p, map->map_mname);
			break;
		}
		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
			p++;
		if (*p != '\0')
			*p++ = '\0';
	}
	if (map->map_app != NULL)
		map->map_app = newstr(map->map_app);
	if (map->map_tapp != NULL)
		map->map_tapp = newstr(map->map_tapp);
	if (map->map_keycolnm != NULL)
		map->map_keycolnm = newstr(map->map_keycolnm);
	if (map->map_valcolnm != NULL)
		map->map_valcolnm = newstr(map->map_valcolnm);

	if (*p != '\0')
	{
		map->map_file = p;
		while (*p != '\0' && !(isascii(*p) && isspace(*p)))
			p++;
		if (*p != '\0')
			*p++ = '\0';
		map->map_file = newstr(map->map_file);
	}

	while (*p != '\0' && isascii(*p) && isspace(*p))
		p++;
	if (*p != '\0')
		map->map_rebuild = newstr(p);

	if (map->map_file == NULL &&
	    !bitset(MCF_OPTFILE, map->map_class->map_cflags))
	{
		syserr("No file name for %s map %s",
			map->map_class->map_cname, map->map_mname);
		return FALSE;
	}
	return TRUE;
}
/*
**  MAP_REWRITE -- rewrite a database key, interpolating %n indications.
**
**	It also adds the map_app string.  It can be used as a utility
**	in the map_lookup method.
**
**	Parameters:
**		map -- the map that causes this.
**		s -- the string to rewrite, NOT necessarily null terminated.
**		slen -- the length of s.
**		av -- arguments to interpolate into buf.
**
**	Returns:
**		Pointer to rewritten result.  This is static data that
**		should be copied if it is to be saved!
**
**	Side Effects:
**		none.
*/

char *
map_rewrite(map, s, slen, av)
	register MAP *map;
	register const char *s;
	size_t slen;
	char **av;
{
	register char *bp;
	register char c;
	char **avp;
	register char *ap;
	size_t l;
	size_t len;
	static size_t buflen = 0;
	static char *buf = NULL;

	if (tTd(39, 1))
	{
		dprintf("map_rewrite(%.*s), av =", (int)slen, s);
		if (av == NULL)
			dprintf(" (nullv)");
		else
		{
			for (avp = av; *avp != NULL; avp++)
				dprintf("\n\t%s", *avp);
		}
		dprintf("\n");
	}

	/* count expected size of output (can safely overestimate) */
	l = len = slen;
	if (av != NULL)
	{
		const char *sp = s;

		while (l-- > 0 && (c = *sp++) != '\0')
		{
			if (c != '%')
				continue;
			if (l-- <= 0)
				break;
			c = *sp++;
			if (!(isascii(c) && isdigit(c)))
				continue;
			for (avp = av; --c >= '0' && *avp != NULL; avp++)
				continue;
			if (*avp == NULL)
				continue;
			len += strlen(*avp);
		}
	}
	if (map->map_app != NULL)
		len += strlen(map->map_app);
	if (buflen < ++len)
	{
		/* need to malloc additional space */
		buflen = len;
		if (buf != NULL)
			free(buf);
		buf = xalloc(buflen);
	}

	bp = buf;
	if (av == NULL)
	{
		memmove(bp, s, slen);
		bp += slen;

		/* assert(len > slen); */
		len -= slen;
	}
	else
	{
		while (slen-- > 0 && (c = *s++) != '\0')
		{
			if (c != '%')
			{
  pushc:
				if (--len <= 0)
					break;
				*bp++ = c;
				continue;
			}
			if (slen-- <= 0 || (c = *s++) == '\0')
				c = '%';
			if (c == '%')
				goto pushc;
			if (!(isascii(c) && isdigit(c)))
			{
				*bp++ = '%';
				--len;
				goto pushc;
			}
			for (avp = av; --c >= '0' && *avp != NULL; avp++)
				continue;
			if (*avp == NULL)
				continue;

			/* transliterate argument into output string */
			for (ap = *avp; (c = *ap++) != '\0' && len > 0; --len)
				*bp++ = c;
		}
	}
	if (map->map_app != NULL && len > 0)
		(void) strlcpy(bp, map->map_app, len);
	else
		*bp = '\0';
	if (tTd(39, 1))
		dprintf("map_rewrite => %s\n", buf);
	return buf;
}
/*
**  INITMAPS -- rebuild alias maps
**
**	Parameters:
**		none.
**
**	Returns:
**		none.
*/

void
initmaps()
{
#if XDEBUG
	checkfd012("entering initmaps");
#endif /* XDEBUG */
	stabapply(map_init, 0);
#if XDEBUG
	checkfd012("exiting initmaps");
#endif /* XDEBUG */
}
/*
**  MAP_INIT -- rebuild a map
**
**	Parameters:
**		s -- STAB entry: if map: try to rebuild
**		unused -- unused variable
**
**	Returns:
**		none.
**
**	Side Effects:
**		will close already open rebuildable map.
*/

/* ARGSUSED1 */
static void
map_init(s, unused)
	register STAB *s;
	int unused;
{
	register MAP *map;

	/* has to be a map */
	if (s->s_type != ST_MAP)
		return;

	map = &s->s_map;
	if (!bitset(MF_VALID, map->map_mflags))
		return;

	if (tTd(38, 2))
		dprintf("map_init(%s:%s, %s)\n",
			map->map_class->map_cname == NULL ? "NULL" :
				map->map_class->map_cname,
			map->map_mname == NULL ? "NULL" : map->map_mname,
			map->map_file == NULL ? "NULL" : map->map_file);

	if (!bitset(MF_ALIAS, map->map_mflags) ||
	    !bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
	{
		if (tTd(38, 3))
			dprintf("\tnot rebuildable\n");
		return;
	}

	/* if already open, close it (for nested open) */
	if (bitset(MF_OPEN, map->map_mflags))
	{
		map->map_class->map_close(map);
		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
	}

	(void) rebuildaliases(map, FALSE);
	return;
}
/*
**  OPENMAP -- open a map
**
**	Parameters:
**		map -- map to open (it must not be open).
**
**	Returns:
**		whether open succeeded.
**
*/

bool
openmap(map)
	MAP *map;
{
	bool restore = FALSE;
	bool savehold = HoldErrs;
	bool savequick = QuickAbort;
	int saveerrors = Errors;

	if (!bitset(MF_VALID, map->map_mflags))
		return FALSE;

	/* better safe than sorry... */
	if (bitset(MF_OPEN, map->map_mflags))
		return TRUE;

	/* Don't send a map open error out via SMTP */
	if ((OnlyOneError || QuickAbort) &&
	    (OpMode == MD_SMTP || OpMode == MD_DAEMON))
	{
		restore = TRUE;
		HoldErrs = TRUE;
		QuickAbort = FALSE;
	}

	errno = 0;
	if (map->map_class->map_open(map, O_RDONLY))
	{
		if (tTd(38, 4))
			dprintf("openmap()\t%s:%s %s: valid\n",
				map->map_class->map_cname == NULL ? "NULL" :
					map->map_class->map_cname,
				map->map_mname == NULL ? "NULL" :
					map->map_mname,
				map->map_file == NULL ? "NULL" :
					map->map_file);
		map->map_mflags |= MF_OPEN;
		map->map_pid = getpid();
	}
	else
	{
		if (tTd(38, 4))
			dprintf("openmap()\t%s:%s %s: invalid%s%s\n",
				map->map_class->map_cname == NULL ? "NULL" :
					map->map_class->map_cname,
				map->map_mname == NULL ? "NULL" :
					map->map_mname,
				map->map_file == NULL ? "NULL" :
					map->map_file,
				errno == 0 ? "" : ": ",
				errno == 0 ? "" : errstring(errno));
		if (!bitset(MF_OPTIONAL, map->map_mflags))
		{
			extern MAPCLASS BogusMapClass;

			map->map_class = &BogusMapClass;
			map->map_mflags |= MF_OPEN;
			map->map_pid = getpid();
			MapOpenErr = TRUE;
		}
		else
		{
			/* don't try again */

⌨️ 快捷键说明

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