summaryrefslogtreecommitdiffstats
path: root/contrib/sendmail/src/map.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/sendmail/src/map.c')
-rw-r--r--contrib/sendmail/src/map.c7989
1 files changed, 0 insertions, 7989 deletions
diff --git a/contrib/sendmail/src/map.c b/contrib/sendmail/src/map.c
deleted file mode 100644
index 4248fd9..0000000
--- a/contrib/sendmail/src/map.c
+++ /dev/null
@@ -1,7989 +0,0 @@
-/*
- * Copyright (c) 1998-2007 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.
- *
- */
-
-#include <sendmail.h>
-
-SM_RCSID("@(#)$Id: map.c,v 8.699 2007/10/10 00:06:45 ca Exp $")
-
-#if LDAPMAP
-# include <sm/ldap.h>
-#endif /* LDAPMAP */
-
-#if 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 */
-#if NEWDB
-# include "sm/bdb.h"
-#endif /* NEWDB */
-#if NIS
- struct dom_binding; /* forward reference needed on IRIX */
-# include <rpcsvc/ypclnt.h>
-# if NDBM
-# define NDBM_YP_COMPAT /* create YP-compatible NDBM files */
-# endif /* NDBM */
-#endif /* NIS */
-
-#include "map.h"
-
-#if 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 *, char[], int));
-static void map_close __P((STAB *, int));
-static void map_init __P((STAB *, int));
-#ifdef LDAPMAP
-static STAB * ldapmap_findconn __P((SM_LDAP_STRUCT *));
-#endif /* LDAPMAP */
-#if NISPLUS
-static bool nisplus_getcanonname __P((char *, int, int *));
-#endif /* NISPLUS */
-#if 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 *));
-#if SOCKETMAP
-static STAB *socket_map_findconn __P((const char*));
-
-/* XXX arbitrary limit for sanity */
-# define SOCKETMAP_MAXL 1000000
-#endif /* SOCKETMAP */
-
-/* default error message for trying to open a map in write mode */
-#ifdef ENOSYS
-# define SM_EMAPCANTWRITE ENOSYS
-#else /* ENOSYS */
-# ifdef EFTYPE
-# define SM_EMAPCANTWRITE EFTYPE
-# else /* EFTYPE */
-# define SM_EMAPCANTWRITE ENXIO
-# endif /* EFTYPE */
-#endif /* ENOSYS */
-
-/*
-** 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 and 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.
-*/
-
-#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 */
-
-/*
-** 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!
-*/
-
-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))
- {
- sm_dprintf("map_rewrite(%.*s), av =", (int) slen, s);
- if (av == NULL)
- sm_dprintf(" (nullv)");
- else
- {
- for (avp = av; *avp != NULL; avp++)
- sm_dprintf("\n\t%s", *avp);
- }
- sm_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)
- sm_free(buf);
- buf = sm_pmalloc_x(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-- <= 1)
- break;
- *bp++ = c;
- continue;
- }
- if (slen-- <= 0 || (c = *s++) == '\0')
- c = '%';
- if (c == '%')
- goto pushc;
- if (!(isascii(c) && isdigit(c)))
- {
- if (len-- <= 1)
- break;
- *bp++ = '%';
- 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) sm_strlcpy(bp, map->map_app, len);
- else
- *bp = '\0';
- if (tTd(39, 1))
- sm_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_symtype != ST_MAP)
- return;
-
- map = &s->s_map;
- if (!bitset(MF_VALID, map->map_mflags))
- return;
-
- if (tTd(38, 2))
- sm_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))
- sm_dprintf("\tnot rebuildable\n");
- return;
- }
-
- /* if already open, close it (for nested open) */
- if (bitset(MF_OPEN, map->map_mflags))
- {
- map->map_mflags |= MF_CLOSING;
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
- }
-
- (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))
- sm_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 = CurrentPid;
- }
- else
- {
- if (tTd(38, 4))
- sm_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 ? "" : sm_errstring(errno));
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- extern MAPCLASS BogusMapClass;
-
- map->map_orgclass = map->map_class;
- map->map_class = &BogusMapClass;
- map->map_mflags |= MF_OPEN|MF_OPENBOGUS;
- map->map_pid = CurrentPid;
- }
- else
- {
- /* don't try again */
- 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:
-** bogus -- only close bogus maps.
-**
-** Returns:
-** none.
-*/
-
-void
-closemaps(bogus)
- bool bogus;
-{
- stabapply(map_close, bogus);
-}
-/*
-** MAP_CLOSE -- close a map opened by the current pid.
-**
-** Parameters:
-** s -- STAB entry: if map: try to close
-** bogus -- only close bogus maps or MCF_NOTPERSIST maps.
-**
-** Returns:
-** none.
-*/
-
-/* ARGSUSED1 */
-static void
-map_close(s, bogus)
- register STAB *s;
- int bogus; /* int because of stabapply(), used as bool */
-{
- MAP *map;
- extern MAPCLASS BogusMapClass;
-
- if (s->s_symtype != ST_MAP)
- return;
-
- map = &s->s_map;
-
- /*
- ** close the map iff:
- ** it is valid and open and opened by this process
- ** and (!bogus or it's a bogus map or it is not persistent)
- ** negate this: return iff
- ** it is not valid or it is not open or not opened by this process
- ** or (bogus and it's not a bogus map and it's not not-persistent)
- */
-
- if (!bitset(MF_VALID, map->map_mflags) ||
- !bitset(MF_OPEN, map->map_mflags) ||
- bitset(MF_CLOSING, map->map_mflags) ||
- map->map_pid != CurrentPid ||
- (bogus && map->map_class != &BogusMapClass &&
- !bitset(MCF_NOTPERSIST, map->map_class->map_cflags)))
- return;
-
- if (map->map_class == &BogusMapClass && map->map_orgclass != NULL &&
- map->map_orgclass != &BogusMapClass)
- map->map_class = map->map_orgclass;
- if (tTd(38, 5))
- sm_dprintf("closemaps: closing %s (%s)\n",
- map->map_mname == NULL ? "NULL" : map->map_mname,
- map->map_file == NULL ? "NULL" : map->map_file);
-
- if (!bitset(MF_OPENBOGUS, map->map_mflags))
- {
- map->map_mflags |= MF_CLOSING;
- map->map_class->map_close(map);
- }
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING);
-}
-
-#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
-extern int getdomainname();
-
-/* this is mainly for backward compatibility in Sun environment */
-static char *
-sun_init_domain()
-{
- /*
- ** Get the domain name from the kernel.
- ** If it does not start with a leading dot, then remove
- ** the first component. Since leading dots are funny Unix
- ** files, we treat a leading "+" the same as a leading dot.
- ** Finally, force there to be at least one dot in the domain name
- ** (i.e. top-level domains are not allowed, like "com", must be
- ** something like "sun.com").
- */
-
- char buf[MAXNAME];
- char *period, *autodomain;
-
- if (getdomainname(buf, sizeof buf) < 0)
- return NULL;
-
- if (buf[0] == '\0')
- return NULL;
-
- if (tTd(0, 20))
- printf("domainname = %s\n", buf);
-
- if (buf[0] == '+')
- buf[0] = '.';
- period = strchr(buf, '.');
- if (period == NULL)
- autodomain = buf;
- else
- autodomain = period + 1;
- if (strchr(autodomain, '.') == NULL)
- return newstr(buf);
- else
- return newstr(autodomain);
-}
-#endif /* SUN_EXTENSIONS && SUN_INIT_DOMAIN */
-
-/*
-** 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.
-** pttl -- pointer to return TTL (can be NULL).
-**
-** Returns:
-** true -- if the host was found.
-** false -- otherwise.
-*/
-
-bool
-getcanonname(host, hbsize, trymx, pttl)
- char *host;
- int hbsize;
- bool trymx;
- int *pttl;
-{
- int nmaps;
- int mapno;
- bool found = false;
- bool got_tempfail = false;
- auto int status;
- char *maptype[MAXMAPSTACK];
- short mapreturn[MAXMAPACTIONS];
-#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
- bool should_try_nis_domain = false;
- static char *nis_domain = NULL;
-#endif
-
- nmaps = switch_map_find("hosts", maptype, mapreturn);
- if (pttl != 0)
- *pttl = SM_DEFAULT_TTL;
- for (mapno = 0; mapno < nmaps; mapno++)
- {
- int i;
-
- if (tTd(38, 20))
- sm_dprintf("getcanonname(%s), trying %s\n",
- host, maptype[mapno]);
- if (strcmp("files", maptype[mapno]) == 0)
- {
- found = text_getcanonname(host, hbsize, &status);
- }
-#if NIS
- else if (strcmp("nis", maptype[mapno]) == 0)
- {
- found = nis_getcanonname(host, hbsize, &status);
-# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
- if (nis_domain == NULL)
- nis_domain = sun_init_domain();
-# endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
- }
-#endif /* NIS */
-#if NISPLUS
- else if (strcmp("nisplus", maptype[mapno]) == 0)
- {
- found = nisplus_getcanonname(host, hbsize, &status);
-# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
- if (nis_domain == NULL)
- nis_domain = sun_init_domain();
-# endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
- }
-#endif /* NISPLUS */
-#if NAMED_BIND
- else if (strcmp("dns", maptype[mapno]) == 0)
- {
- found = dns_getcanonname(host, hbsize, trymx, &status, pttl);
- }
-#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;
-
-#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
- if (found)
- should_try_nis_domain = true;
- /* but don't break, as we need to try all methods first */
-#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
-
- /* 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))
- sm_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) sm_strlcat2(host, ".", d,
- hbsize);
- else
- (void) sm_strlcat(host, d, hbsize);
- }
- else
- {
-#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
- if (VendorCode == VENDOR_SUN &&
- should_try_nis_domain)
- {
- goto try_nis_domain;
- }
-#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
- return false;
- }
- }
- return true;
- }
-
-#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN)
- if (VendorCode == VENDOR_SUN && should_try_nis_domain)
- {
- try_nis_domain:
- if (nis_domain != NULL &&
- strlen(nis_domain) + strlen(host) + 1 < hbsize)
- {
- (void) sm_strlcat2(host, ".", nis_domain, hbsize);
- return true;
- }
- }
-#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */
-
- if (tTd(38, 20))
- sm_dprintf("getcanonname(%s), failed, status=%d\n", host,
- status);
-
- if (got_tempfail)
- SM_SET_H_ERRNO(TRY_AGAIN);
- else
- SM_SET_H_ERRNO(HOST_NOT_FOUND);
-
- return false;
-}
-/*
-** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
-**
-** Parameters:
-** name -- the name against which to match.
-** dot -- where to reinsert '.' to get FQDN
-** 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, dot, line, cbuf, cbuflen)
- char *name;
- char *dot;
- 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))
- {
- (void) sm_strlcpy(cbuf, p, cbuflen);
- }
- if (sm_strcasecmp(name, p) == 0)
- found = true;
- else if (dot != NULL)
- {
- /* try looking for the FQDN as well */
- *dot = '.';
- if (sm_strcasecmp(name, p) == 0)
- found = true;
- *dot = '\0';
- }
- }
- 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) sm_strlcpy(p, domain, cbuflen - i - 1);
- }
- }
- return found;
-}
-
-/*
-** DNS modules
-*/
-
-#if NAMED_BIND
-# if DNSMAP
-
-# include "sm_resolve.h"
-# if NETINET || NETINET6
-# include <arpa/inet.h>
-# endif /* NETINET || NETINET6 */
-
-/*
-** DNS_MAP_OPEN -- stub to check proper value for dns map type
-*/
-
-bool
-dns_map_open(map, mode)
- MAP *map;
- int mode;
-{
- if (tTd(38,2))
- sm_dprintf("dns_map_open(%s, %d)\n", map->map_mname, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
- errno = SM_EMAPCANTWRITE;
- return false;
- }
- return true;
-}
-
-/*
-** DNS_MAP_PARSEARGS -- parse dns map definition args.
-**
-** Parameters:
-** map -- pointer to MAP
-** args -- pointer to the args on the config line.
-**
-** Returns:
-** true -- if everything parsed OK.
-** false -- otherwise.
-*/
-
-#define map_sizelimit map_lockfd /* overload field */
-
-struct dns_map
-{
- int dns_m_type;
-};
-
-bool
-dns_map_parseargs(map,args)
- MAP *map;
- char *args;
-{
- register char *p = args;
- struct dns_map *map_p;
-
- map_p = (struct dns_map *) xalloc(sizeof(*map_p));
- map_p->dns_m_type = -1;
- map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
-
- 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 't':
- map->map_mflags |= MF_NODEFER;
- break;
-
- case 'a':
- map->map_app = ++p;
- break;
-
- case 'T':
- map->map_tapp = ++p;
- break;
-
- case 'd':
- {
- char *h;
-
- ++p;
- h = strchr(p, ' ');
- if (h != NULL)
- *h = '\0';
- map->map_timeout = convtime(p, 's');
- if (h != NULL)
- *h = ' ';
- }
- break;
-
- case 'r':
- while (isascii(*++p) && isspace(*p))
- continue;
- map->map_retry = atoi(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 'Z':
- while (isascii(*++p) && isspace(*p))
- continue;
- map->map_sizelimit = atoi(p);
- break;
-
- /* Start of dns_map specific args */
- case 'R': /* search field */
- {
- char *h;
-
- while (isascii(*++p) && isspace(*p))
- continue;
- h = strchr(p, ' ');
- if (h != NULL)
- *h = '\0';
- map_p->dns_m_type = dns_string_to_type(p);
- if (h != NULL)
- *h = ' ';
- if (map_p->dns_m_type < 0)
- syserr("dns map %s: wrong type %s",
- map->map_mname, p);
- }
- break;
-
- case 'B': /* base domain */
- {
- char *h;
-
- while (isascii(*++p) && isspace(*p))
- continue;
- h = strchr(p, ' ');
- if (h != NULL)
- *h = '\0';
-
- /*
- ** slight abuse of map->map_file; it isn't
- ** used otherwise in this map type.
- */
-
- map->map_file = newstr(p);
- if (h != NULL)
- *h = ' ';
- }
- break;
- }
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
- }
- if (map_p->dns_m_type < 0)
- syserr("dns map %s: missing -R type", map->map_mname);
- if (map->map_app != NULL)
- map->map_app = newstr(map->map_app);
- if (map->map_tapp != NULL)
- map->map_tapp = newstr(map->map_tapp);
-
- /*
- ** Assumption: assert(sizeof(int) <= sizeof(ARBPTR_T));
- ** Even if this assumption is wrong, we use only one byte,
- ** so it doesn't really matter.
- */
-
- map->map_db1 = (ARBPTR_T) map_p;
- return true;
-}
-
-/*
-** DNS_MAP_LOOKUP -- perform dns map lookup.
-**
-** Parameters:
-** map -- pointer to MAP
-** name -- name to lookup
-** av -- arguments to interpolate into buf.
-** statp -- pointer to status (EX_)
-**
-** Returns:
-** result of lookup if succeeded.
-** NULL -- otherwise.
-*/
-
-char *
-dns_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- int resnum = 0;
- char *vp = NULL, *result = NULL;
- size_t vsize;
- struct dns_map *map_p;
- RESOURCE_RECORD_T *rr = NULL;
- DNS_REPLY_T *r = NULL;
-# if NETINET6
- static char buf6[INET6_ADDRSTRLEN];
-# endif /* NETINET6 */
-
- if (tTd(38, 20))
- sm_dprintf("dns_map_lookup(%s, %s)\n",
- map->map_mname, name);
-
- map_p = (struct dns_map *)(map->map_db1);
- if (map->map_file != NULL && *map->map_file != '\0')
- {
- size_t len;
- char *appdomain;
-
- len = strlen(map->map_file) + strlen(name) + 2;
- appdomain = (char *) sm_malloc(len);
- if (appdomain == NULL)
- {
- *statp = EX_UNAVAILABLE;
- return NULL;
- }
- (void) sm_strlcpyn(appdomain, len, 3, name, ".", map->map_file);
- r = dns_lookup_int(appdomain, C_IN, map_p->dns_m_type,
- map->map_timeout, map->map_retry);
- sm_free(appdomain);
- }
- else
- {
- r = dns_lookup_int(name, C_IN, map_p->dns_m_type,
- map->map_timeout, map->map_retry);
- }
-
- if (r == NULL)
- {
- result = NULL;
- if (h_errno == TRY_AGAIN || transienterror(errno))
- *statp = EX_TEMPFAIL;
- else
- *statp = EX_NOTFOUND;
- goto cleanup;
- }
- *statp = EX_OK;
- for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next)
- {
- char *type = NULL;
- char *value = NULL;
-
- switch (rr->rr_type)
- {
- case T_NS:
- type = "T_NS";
- value = rr->rr_u.rr_txt;
- break;
- case T_CNAME:
- type = "T_CNAME";
- value = rr->rr_u.rr_txt;
- break;
- case T_AFSDB:
- type = "T_AFSDB";
- value = rr->rr_u.rr_mx->mx_r_domain;
- break;
- case T_SRV:
- type = "T_SRV";
- value = rr->rr_u.rr_srv->srv_r_target;
- break;
- case T_PTR:
- type = "T_PTR";
- value = rr->rr_u.rr_txt;
- break;
- case T_TXT:
- type = "T_TXT";
- value = rr->rr_u.rr_txt;
- break;
- case T_MX:
- type = "T_MX";
- value = rr->rr_u.rr_mx->mx_r_domain;
- break;
-# if NETINET
- case T_A:
- type = "T_A";
- value = inet_ntoa(*(rr->rr_u.rr_a));
- break;
-# endif /* NETINET */
-# if NETINET6
- case T_AAAA:
- type = "T_AAAA";
- value = anynet_ntop(rr->rr_u.rr_aaaa, buf6,
- sizeof(buf6));
- break;
-# endif /* NETINET6 */
- }
-
- (void) strreplnonprt(value, 'X');
- if (map_p->dns_m_type != rr->rr_type)
- {
- if (tTd(38, 40))
- sm_dprintf("\tskipping type %s (%d) value %s\n",
- type != NULL ? type : "<UNKNOWN>",
- rr->rr_type,
- value != NULL ? value : "<NO VALUE>");
- continue;
- }
-
-# if NETINET6
- if (rr->rr_type == T_AAAA && value == NULL)
- {
- result = NULL;
- *statp = EX_DATAERR;
- if (tTd(38, 40))
- sm_dprintf("\tbad T_AAAA conversion\n");
- goto cleanup;
- }
-# endif /* NETINET6 */
- if (tTd(38, 40))
- sm_dprintf("\tfound type %s (%d) value %s\n",
- type != NULL ? type : "<UNKNOWN>",
- rr->rr_type,
- value != NULL ? value : "<NO VALUE>");
- if (value != NULL &&
- (map->map_coldelim == '\0' ||
- map->map_sizelimit == 1 ||
- bitset(MF_MATCHONLY, map->map_mflags)))
- {
- /* Only care about the first match */
- vp = newstr(value);
- break;
- }
- else if (vp == NULL)
- {
- /* First result */
- vp = newstr(value);
- }
- else
- {
- /* concatenate the results */
- int sz;
- char *new;
-
- sz = strlen(vp) + strlen(value) + 2;
- new = xalloc(sz);
- (void) sm_snprintf(new, sz, "%s%c%s",
- vp, map->map_coldelim, value);
- sm_free(vp);
- vp = new;
- if (map->map_sizelimit > 0 &&
- ++resnum >= map->map_sizelimit)
- break;
- }
- }
- if (vp == NULL)
- {
- result = NULL;
- *statp = EX_NOTFOUND;
- if (tTd(38, 40))
- sm_dprintf("\tno match found\n");
- goto cleanup;
- }
-
- /* Cleanly truncate for rulesets */
- truncate_at_delim(vp, PSBUFSIZE / 2, map->map_coldelim);
-
- vsize = strlen(vp);
-
- if (LogLevel > 9)
- sm_syslog(LOG_INFO, CurEnv->e_id, "dns %.100s => %s",
- name, vp);
- if (bitset(MF_MATCHONLY, map->map_mflags))
- result = map_rewrite(map, name, strlen(name), NULL);
- else
- result = map_rewrite(map, vp, vsize, av);
-
- cleanup:
- if (vp != NULL)
- sm_free(vp);
- if (r != NULL)
- dns_free_data(r);
- return result;
-}
-# endif /* DNSMAP */
-#endif /* NAMED_BIND */
-
-/*
-** NDBM modules
-*/
-
-#if 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[MAXPATHLEN];
- char pagfile[MAXPATHLEN];
- struct stat st;
- struct stat std, stp;
-
- if (tTd(38, 2))
- sm_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 */
- if (sm_strlcpyn(dirfile, sizeof(dirfile), 2,
- map->map_file, ".dir") >= sizeof(dirfile) ||
- sm_strlcpyn(pagfile, sizeof(pagfile), 2,
- map->map_file, ".pag") >= sizeof(pagfile))
- {
- errno = 0;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("dbm map \"%s\": map file %s name too long",
- map->map_mname, map->map_file);
- return false;
- }
- 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 (ret != 0)
- {
- char *prob = "unsafe";
-
- /* cannot open this map */
- if (ret == ENOENT)
- prob = "missing";
- if (tTd(38, 2))
- sm_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(pfd, &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, sm_errstring(err));
- message("050 ownership change on %s failed: %s",
- map->map_file, sm_errstring(err));
- }
-# else /* HASFCHOWN */
- sm_syslog(LOG_ALERT, NOQID,
- "no fchown(): cannot change ownership on %s",
- map->map_file);
- message("050 no fchown(): cannot change ownership on %s",
- map->map_file);
-# 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 dfd, pfd;
- char keybuf[MAXNAME + 1];
- struct stat stbuf;
-
- if (tTd(38, 20))
- sm_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:
- dfd = dbm_dirfno((DBM *) map->map_db1);
- if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(dfd, map->map_file, ".dir", LOCK_SH);
- pfd = dbm_pagfno((DBM *) map->map_db1);
- if (pfd < 0 || fstat(pfd, &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
- : O_RDONLY;
-
- if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
- map->map_mflags |= MF_CLOSING;
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
- if (map->map_class->map_open(map, omode))
- {
- map->map_mflags |= MF_OPEN;
- map->map_pid = CurrentPid;
- if ((omode && O_ACCMODE) == O_RDWR)
- map->map_mflags |= MF_WRITABLE;
- goto lockdbm;
- }
- else
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- extern MAPCLASS BogusMapClass;
-
- *statp = EX_TEMPFAIL;
- map->map_orgclass = map->map_class;
- map->map_class = &BogusMapClass;
- map->map_mflags |= MF_OPEN;
- map->map_pid = CurrentPid;
- syserr("Cannot reopen NDBM database %s",
- map->map_file);
- }
- return NULL;
- }
- }
- val.dptr = NULL;
- if (bitset(MF_TRY0NULL, map->map_mflags))
- {
- val = dbm_fetch((DBM *) map->map_db1, key);
- if (val.dptr != NULL)
- map->map_mflags &= ~MF_TRY1NULL;
- }
- if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags))
- {
- key.dsize++;
- val = dbm_fetch((DBM *) map->map_db1, key);
- if (val.dptr != NULL)
- map->map_mflags &= ~MF_TRY0NULL;
- }
- if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
- if (val.dptr == NULL)
- return NULL;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, val.dptr, val.dsize, av);
-}
-
-
-/*
-** NDBM_MAP_STORE -- store a datum in the database
-*/
-
-void
-ndbm_map_store(map, lhs, rhs)
- register MAP *map;
- char *lhs;
- char *rhs;
-{
- datum key;
- datum data;
- int status;
- char keybuf[MAXNAME + 1];
-
- if (tTd(38, 12))
- sm_dprintf("ndbm_map_store(%s, %s, %s)\n",
- map->map_mname, lhs, rhs);
-
- key.dsize = strlen(lhs);
- key.dptr = lhs;
- 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;
- }
-
- data.dsize = strlen(rhs);
- data.dptr = rhs;
-
- if (bitset(MF_INCLNULL, map->map_mflags))
- {
- key.dsize++;
- data.dsize++;
- }
-
- status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT);
- if (status > 0)
- {
- if (!bitset(MF_APPEND, map->map_mflags))
- message("050 Warning: duplicate alias name %s", lhs);
- else
- {
- static char *buf = NULL;
- static int bufsiz = 0;
- auto int xstat;
- datum old;
-
- old.dptr = ndbm_map_lookup(map, key.dptr,
- (char **) NULL, &xstat);
- if (old.dptr != NULL && *(char *) old.dptr != '\0')
- {
- old.dsize = strlen(old.dptr);
- if (data.dsize + old.dsize + 2 > bufsiz)
- {
- if (buf != NULL)
- (void) sm_free(buf);
- bufsiz = data.dsize + old.dsize + 2;
- buf = sm_pmalloc_x(bufsiz);
- }
- (void) sm_strlcpyn(buf, bufsiz, 3,
- data.dptr, ",", old.dptr);
- data.dsize = data.dsize + old.dsize + 1;
- data.dptr = buf;
- if (tTd(38, 9))
- sm_dprintf("ndbm_map_store append=%s\n",
- data.dptr);
- }
- }
- status = dbm_store((DBM *) map->map_db1,
- key, data, DBM_REPLACE);
- }
- if (status != 0)
- syserr("readaliases: dbm put (%s): %d", lhs, status);
-}
-
-
-/*
-** NDBM_MAP_CLOSE -- close the database
-*/
-
-void
-ndbm_map_close(map)
- register MAP *map;
-{
- if (tTd(38, 9))
- sm_dprintf("ndbm_map_close(%s, %s, %lx)\n",
- map->map_mname, map->map_file, map->map_mflags);
-
- if (bitset(MF_WRITABLE, map->map_mflags))
- {
-# ifdef NDBM_YP_COMPAT
- bool inclnull;
- char buf[MAXHOSTNAMELEN];
-
- inclnull = bitset(MF_INCLNULL, map->map_mflags);
- map->map_mflags &= ~MF_INCLNULL;
-
- if (strstr(map->map_file, "/yp/") != NULL)
- {
- long save_mflags = map->map_mflags;
-
- map->map_mflags |= MF_NOFOLDCASE;
-
- (void) sm_snprintf(buf, sizeof(buf), "%010ld", curtime());
- ndbm_map_store(map, "YP_LAST_MODIFIED", buf);
-
- (void) gethostname(buf, sizeof(buf));
- ndbm_map_store(map, "YP_MASTER_NAME", buf);
-
- map->map_mflags = save_mflags;
- }
-
- if (inclnull)
- map->map_mflags |= MF_INCLNULL;
-# endif /* NDBM_YP_COMPAT */
-
- /* write out the distinguished alias */
- ndbm_map_store(map, "@", "@");
- }
- dbm_close((DBM *) map->map_db1);
-
- /* release lock (if needed) */
-# if !LOCK_ON_OPEN
- if (map->map_lockfd >= 0)
- (void) close(map->map_lockfd);
-# endif /* !LOCK_ON_OPEN */
-}
-
-#endif /* NDBM */
-/*
-** NEWDB (Hash and BTree) Modules
-*/
-
-#if NEWDB
-
-/*
-** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
-**
-** These do rather bizarre locking. If you can lock on open,
-** do that to avoid the condition of opening a database that
-** is being rebuilt. If you don't, we'll try to fake it, but
-** there will be a race condition. If opening for read-only,
-** we immediately release the lock to avoid freezing things up.
-** We really ought to hold the lock, but guarantee that we won't
-** be pokey about it. That's hard to do.
-*/
-
-/* these should be K line arguments */
-# if DB_VERSION_MAJOR < 2
-# define db_cachesize cachesize
-# define h_nelem nelem
-# ifndef DB_CACHE_SIZE
-# define DB_CACHE_SIZE (1024 * 1024) /* database memory cache size */
-# endif /* ! DB_CACHE_SIZE */
-# ifndef DB_HASH_NELEM
-# define DB_HASH_NELEM 4096 /* (starting) size of hash table */
-# endif /* ! DB_HASH_NELEM */
-# endif /* DB_VERSION_MAJOR < 2 */
-
-bool
-bt_map_open(map, mode)
- MAP *map;
- int mode;
-{
-# if DB_VERSION_MAJOR < 2
- BTREEINFO btinfo;
-# endif /* DB_VERSION_MAJOR < 2 */
-# if DB_VERSION_MAJOR == 2
- DB_INFO btinfo;
-# endif /* DB_VERSION_MAJOR == 2 */
-# if DB_VERSION_MAJOR > 2
- void *btinfo = NULL;
-# endif /* DB_VERSION_MAJOR > 2 */
-
- if (tTd(38, 2))
- sm_dprintf("bt_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
-# if DB_VERSION_MAJOR < 3
- memset(&btinfo, '\0', sizeof(btinfo));
-# ifdef DB_CACHE_SIZE
- btinfo.db_cachesize = DB_CACHE_SIZE;
-# endif /* DB_CACHE_SIZE */
-# endif /* DB_VERSION_MAJOR < 3 */
-
- return db_map_open(map, mode, "btree", DB_BTREE, &btinfo);
-}
-
-bool
-hash_map_open(map, mode)
- MAP *map;
- int mode;
-{
-# if DB_VERSION_MAJOR < 2
- HASHINFO hinfo;
-# endif /* DB_VERSION_MAJOR < 2 */
-# if DB_VERSION_MAJOR == 2
- DB_INFO hinfo;
-# endif /* DB_VERSION_MAJOR == 2 */
-# if DB_VERSION_MAJOR > 2
- void *hinfo = NULL;
-# endif /* DB_VERSION_MAJOR > 2 */
-
- if (tTd(38, 2))
- sm_dprintf("hash_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
-# if DB_VERSION_MAJOR < 3
- memset(&hinfo, '\0', sizeof(hinfo));
-# ifdef DB_HASH_NELEM
- hinfo.h_nelem = DB_HASH_NELEM;
-# endif /* DB_HASH_NELEM */
-# ifdef DB_CACHE_SIZE
- hinfo.db_cachesize = DB_CACHE_SIZE;
-# endif /* DB_CACHE_SIZE */
-# endif /* DB_VERSION_MAJOR < 3 */
-
- return db_map_open(map, mode, "hash", DB_HASH, &hinfo);
-}
-
-static bool
-db_map_open(map, mode, mapclassname, dbtype, openinfo)
- MAP *map;
- int mode;
- char *mapclassname;
- DBTYPE dbtype;
-# if DB_VERSION_MAJOR < 2
- const void *openinfo;
-# endif /* DB_VERSION_MAJOR < 2 */
-# if DB_VERSION_MAJOR == 2
- DB_INFO *openinfo;
-# endif /* DB_VERSION_MAJOR == 2 */
-# if DB_VERSION_MAJOR > 2
- void **openinfo;
-# endif /* DB_VERSION_MAJOR > 2 */
-{
- DB *db = NULL;
- int i;
- int omode;
- int smode = S_IREAD;
- int fd;
- long sff;
- int save_errno;
- struct stat st;
- char buf[MAXPATHLEN];
-
- /* do initial file and directory checks */
- if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
- {
- errno = 0;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("map \"%s\": map file %s name too long",
- map->map_mname, map->map_file);
- return false;
- }
- i = strlen(buf);
- if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
- {
- if (sm_strlcat(buf, ".db", sizeof(buf)) >= sizeof(buf))
- {
- errno = 0;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("map \"%s\": map file %s name too long",
- map->map_mname, map->map_file);
- return false;
- }
- }
-
- mode &= O_ACCMODE;
- omode = mode;
-
- 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;
- i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
-
- if (i != 0)
- {
- char *prob = "unsafe";
-
- /* cannot open this map */
- if (i == ENOENT)
- prob = "missing";
- if (tTd(38, 2))
- sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(i));
- errno = i;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("%s map \"%s\": %s map file %s",
- mapclassname, map->map_mname, prob, buf);
- return false;
- }
- if (st.st_mode == ST_MODE_NOFILE)
- omode |= O_CREAT|O_EXCL;
-
- map->map_lockfd = -1;
-
-# if LOCK_ON_OPEN
- if (mode == O_RDWR)
- omode |= O_TRUNC|O_EXLOCK;
- else
- omode |= O_SHLOCK;
-# else /* LOCK_ON_OPEN */
- /*
- ** Pre-lock the file to avoid race conditions. In particular,
- ** since dbopen returns NULL if the file is zero length, we
- ** must have a locked instance around the dbopen.
- */
-
- fd = open(buf, omode, DBMMODE);
- if (fd < 0)
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("db_map_open: cannot pre-open database %s", buf);
- return false;
- }
-
- /* make sure no baddies slipped in just before the open... */
- if (filechanged(buf, fd, &st))
- {
- save_errno = errno;
- (void) close(fd);
- errno = save_errno;
- syserr("db_map_open(%s): file changed after pre-open", buf);
- return false;
- }
-
- /* if new file, get the "before" bits for later filechanged check */
- if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
- {
- save_errno = errno;
- (void) close(fd);
- errno = save_errno;
- syserr("db_map_open(%s): cannot fstat pre-opened file",
- buf);
- return false;
- }
-
- /* actually lock the pre-opened file */
- if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
- syserr("db_map_open: cannot lock %s", buf);
-
- /* set up mode bits for dbopen */
- if (mode == O_RDWR)
- omode |= O_TRUNC;
- omode &= ~(O_EXCL|O_CREAT);
-# endif /* LOCK_ON_OPEN */
-
-# if DB_VERSION_MAJOR < 2
- db = dbopen(buf, omode, DBMMODE, dbtype, openinfo);
-# else /* DB_VERSION_MAJOR < 2 */
- {
- int flags = 0;
-# if DB_VERSION_MAJOR > 2
- int ret;
-# endif /* DB_VERSION_MAJOR > 2 */
-
- if (mode == O_RDONLY)
- flags |= DB_RDONLY;
- if (bitset(O_CREAT, omode))
- flags |= DB_CREATE;
- if (bitset(O_TRUNC, omode))
- flags |= DB_TRUNCATE;
- SM_DB_FLAG_ADD(flags);
-
-# if DB_VERSION_MAJOR > 2
- ret = db_create(&db, NULL, 0);
-# ifdef DB_CACHE_SIZE
- if (ret == 0 && db != NULL)
- {
- ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0);
- if (ret != 0)
- {
- (void) db->close(db, 0);
- db = NULL;
- }
- }
-# endif /* DB_CACHE_SIZE */
-# ifdef DB_HASH_NELEM
- if (dbtype == DB_HASH && ret == 0 && db != NULL)
- {
- ret = db->set_h_nelem(db, DB_HASH_NELEM);
- if (ret != 0)
- {
- (void) db->close(db, 0);
- db = NULL;
- }
- }
-# endif /* DB_HASH_NELEM */
- if (ret == 0 && db != NULL)
- {
- ret = db->open(db,
- DBTXN /* transaction for DB 4.1 */
- buf, NULL, dbtype, flags, DBMMODE);
- if (ret != 0)
- {
-#ifdef DB_OLD_VERSION
- if (ret == DB_OLD_VERSION)
- ret = EINVAL;
-#endif /* DB_OLD_VERSION */
- (void) db->close(db, 0);
- db = NULL;
- }
- }
- errno = ret;
-# else /* DB_VERSION_MAJOR > 2 */
- errno = db_open(buf, dbtype, flags, DBMMODE,
- NULL, openinfo, &db);
-# endif /* DB_VERSION_MAJOR > 2 */
- }
-# endif /* DB_VERSION_MAJOR < 2 */
- save_errno = errno;
-
-# if !LOCK_ON_OPEN
- if (mode == O_RDWR)
- map->map_lockfd = fd;
- else
- (void) close(fd);
-# endif /* !LOCK_ON_OPEN */
-
- if (db == NULL)
- {
- if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
- aliaswait(map, ".db", false))
- return true;
-# if !LOCK_ON_OPEN
- if (map->map_lockfd >= 0)
- (void) close(map->map_lockfd);
-# endif /* !LOCK_ON_OPEN */
- errno = save_errno;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("Cannot open %s database %s",
- mapclassname, buf);
- return false;
- }
-
-# if DB_VERSION_MAJOR < 2
- fd = db->fd(db);
-# else /* DB_VERSION_MAJOR < 2 */
- fd = -1;
- errno = db->fd(db, &fd);
-# endif /* DB_VERSION_MAJOR < 2 */
- if (filechanged(buf, fd, &st))
- {
- save_errno = errno;
-# if DB_VERSION_MAJOR < 2
- (void) db->close(db);
-# else /* DB_VERSION_MAJOR < 2 */
- errno = db->close(db, 0);
-# endif /* DB_VERSION_MAJOR < 2 */
-# if !LOCK_ON_OPEN
- if (map->map_lockfd >= 0)
- (void) close(map->map_lockfd);
-# endif /* !LOCK_ON_OPEN */
- errno = save_errno;
- syserr("db_map_open(%s): file changed after open", buf);
- return false;
- }
-
- if (mode == O_RDWR)
- map->map_mflags |= MF_LOCKED;
-# if LOCK_ON_OPEN
- if (fd >= 0 && mode == O_RDONLY)
- {
- (void) lockfile(fd, buf, NULL, LOCK_UN);
- }
-# endif /* LOCK_ON_OPEN */
-
- /* try to make sure that at least the database header is on disk */
- if (mode == O_RDWR)
- {
- (void) db->sync(db, 0);
- if (geteuid() == 0 && TrustedUid != 0)
- {
-# if HASFCHOWN
- if (fchown(fd, TrustedUid, -1) < 0)
- {
- int err = errno;
-
- sm_syslog(LOG_ALERT, NOQID,
- "ownership change on %s failed: %s",
- buf, sm_errstring(err));
- message("050 ownership change on %s failed: %s",
- buf, sm_errstring(err));
- }
-# else /* HASFCHOWN */
- sm_syslog(LOG_ALERT, NOQID,
- "no fchown(): cannot change ownership on %s",
- map->map_file);
- message("050 no fchown(): cannot change ownership on %s",
- map->map_file);
-# endif /* HASFCHOWN */
- }
- }
-
- map->map_db2 = (ARBPTR_T) db;
-
- /*
- ** Need to set map_mtime before the call to aliaswait()
- ** as aliaswait() will call map_lookup() which requires
- ** map_mtime to be set
- */
-
- if (fd >= 0 && fstat(fd, &st) >= 0)
- map->map_mtime = st.st_mtime;
-
- if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
- !aliaswait(map, ".db", true))
- return false;
- return true;
-}
-
-
-/*
-** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
-*/
-
-char *
-db_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- DBT key, val;
- register DB *db = (DB *) map->map_db2;
- int i;
- int st;
- int save_errno;
- int fd;
- struct stat stbuf;
- char keybuf[MAXNAME + 1];
- char buf[MAXPATHLEN];
-
- memset(&key, '\0', sizeof(key));
- memset(&val, '\0', sizeof(val));
-
- if (tTd(38, 20))
- sm_dprintf("db_map_lookup(%s, %s)\n",
- map->map_mname, name);
-
- if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf))
- {
- errno = 0;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("map \"%s\": map file %s name too long",
- map->map_mname, map->map_file);
- return NULL;
- }
- i = strlen(buf);
- if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
- buf[i - 3] = '\0';
-
- key.size = strlen(name);
- if (key.size > sizeof(keybuf) - 1)
- key.size = sizeof(keybuf) - 1;
- key.data = keybuf;
- memmove(keybuf, name, key.size);
- keybuf[key.size] = '\0';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(keybuf);
- lockdb:
-# if DB_VERSION_MAJOR < 2
- fd = db->fd(db);
-# else /* DB_VERSION_MAJOR < 2 */
- fd = -1;
- errno = db->fd(db, &fd);
-# endif /* DB_VERSION_MAJOR < 2 */
- if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, buf, ".db", 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
- : O_RDONLY;
-
- if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, buf, ".db", LOCK_UN);
- map->map_mflags |= MF_CLOSING;
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
- if (map->map_class->map_open(map, omode))
- {
- map->map_mflags |= MF_OPEN;
- map->map_pid = CurrentPid;
- if ((omode && O_ACCMODE) == O_RDWR)
- map->map_mflags |= MF_WRITABLE;
- db = (DB *) map->map_db2;
- goto lockdb;
- }
- else
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- extern MAPCLASS BogusMapClass;
-
- *statp = EX_TEMPFAIL;
- map->map_orgclass = map->map_class;
- map->map_class = &BogusMapClass;
- map->map_mflags |= MF_OPEN;
- map->map_pid = CurrentPid;
- syserr("Cannot reopen DB database %s",
- map->map_file);
- }
- return NULL;
- }
- }
-
- st = 1;
- if (bitset(MF_TRY0NULL, map->map_mflags))
- {
-# if DB_VERSION_MAJOR < 2
- st = db->get(db, &key, &val, 0);
-# else /* DB_VERSION_MAJOR < 2 */
- errno = db->get(db, NULL, &key, &val, 0);
- switch (errno)
- {
- case DB_NOTFOUND:
- case DB_KEYEMPTY:
- st = 1;
- break;
-
- case 0:
- st = 0;
- break;
-
- default:
- st = -1;
- break;
- }
-# endif /* DB_VERSION_MAJOR < 2 */
- if (st == 0)
- map->map_mflags &= ~MF_TRY1NULL;
- }
- if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
- {
- key.size++;
-# if DB_VERSION_MAJOR < 2
- st = db->get(db, &key, &val, 0);
-# else /* DB_VERSION_MAJOR < 2 */
- errno = db->get(db, NULL, &key, &val, 0);
- switch (errno)
- {
- case DB_NOTFOUND:
- case DB_KEYEMPTY:
- st = 1;
- break;
-
- case 0:
- st = 0;
- break;
-
- default:
- st = -1;
- break;
- }
-# endif /* DB_VERSION_MAJOR < 2 */
- if (st == 0)
- map->map_mflags &= ~MF_TRY0NULL;
- }
- save_errno = errno;
- if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, buf, ".db", LOCK_UN);
- if (st != 0)
- {
- errno = save_errno;
- if (st < 0)
- syserr("db_map_lookup: get (%s)", name);
- return NULL;
- }
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, val.data, val.size, av);
-}
-
-
-/*
-** DB_MAP_STORE -- store a datum in the NEWDB database
-*/
-
-void
-db_map_store(map, lhs, rhs)
- register MAP *map;
- char *lhs;
- char *rhs;
-{
- int status;
- DBT key;
- DBT data;
- register DB *db = map->map_db2;
- char keybuf[MAXNAME + 1];
-
- memset(&key, '\0', sizeof(key));
- memset(&data, '\0', sizeof(data));
-
- if (tTd(38, 12))
- sm_dprintf("db_map_store(%s, %s, %s)\n",
- map->map_mname, lhs, rhs);
-
- key.size = strlen(lhs);
- key.data = lhs;
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- {
- if (key.size > sizeof(keybuf) - 1)
- key.size = sizeof(keybuf) - 1;
- memmove(keybuf, key.data, key.size);
- keybuf[key.size] = '\0';
- makelower(keybuf);
- key.data = keybuf;
- }
-
- data.size = strlen(rhs);
- data.data = rhs;
-
- if (bitset(MF_INCLNULL, map->map_mflags))
- {
- key.size++;
- data.size++;
- }
-
-# if DB_VERSION_MAJOR < 2
- status = db->put(db, &key, &data, R_NOOVERWRITE);
-# else /* DB_VERSION_MAJOR < 2 */
- errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE);
- switch (errno)
- {
- case DB_KEYEXIST:
- status = 1;
- break;
-
- case 0:
- status = 0;
- break;
-
- default:
- status = -1;
- break;
- }
-# endif /* DB_VERSION_MAJOR < 2 */
- if (status > 0)
- {
- if (!bitset(MF_APPEND, map->map_mflags))
- message("050 Warning: duplicate alias name %s", lhs);
- else
- {
- static char *buf = NULL;
- static int bufsiz = 0;
- DBT old;
-
- memset(&old, '\0', sizeof(old));
-
- old.data = db_map_lookup(map, key.data,
- (char **) NULL, &status);
- if (old.data != NULL)
- {
- old.size = strlen(old.data);
- if (data.size + old.size + 2 > (size_t) bufsiz)
- {
- if (buf != NULL)
- sm_free(buf);
- bufsiz = data.size + old.size + 2;
- buf = sm_pmalloc_x(bufsiz);
- }
- (void) sm_strlcpyn(buf, bufsiz, 3,
- (char *) data.data, ",",
- (char *) old.data);
- data.size = data.size + old.size + 1;
- data.data = buf;
- if (tTd(38, 9))
- sm_dprintf("db_map_store append=%s\n",
- (char *) data.data);
- }
- }
-# if DB_VERSION_MAJOR < 2
- status = db->put(db, &key, &data, 0);
-# else /* DB_VERSION_MAJOR < 2 */
- status = errno = db->put(db, NULL, &key, &data, 0);
-# endif /* DB_VERSION_MAJOR < 2 */
- }
- if (status != 0)
- syserr("readaliases: db put (%s)", lhs);
-}
-
-
-/*
-** DB_MAP_CLOSE -- add distinguished entries and close the database
-*/
-
-void
-db_map_close(map)
- MAP *map;
-{
- register DB *db = map->map_db2;
-
- if (tTd(38, 9))
- sm_dprintf("db_map_close(%s, %s, %lx)\n",
- map->map_mname, map->map_file, map->map_mflags);
-
- if (bitset(MF_WRITABLE, map->map_mflags))
- {
- /* write out the distinguished alias */
- db_map_store(map, "@", "@");
- }
-
- (void) db->sync(db, 0);
-
-# if !LOCK_ON_OPEN
- if (map->map_lockfd >= 0)
- (void) close(map->map_lockfd);
-# endif /* !LOCK_ON_OPEN */
-
-# if DB_VERSION_MAJOR < 2
- if (db->close(db) != 0)
-# else /* DB_VERSION_MAJOR < 2 */
- /*
- ** Berkeley DB can use internal shared memory
- ** locking for its memory pool. Closing a map
- ** opened by another process will interfere
- ** with the shared memory and locks of the parent
- ** process leaving things in a bad state.
- */
-
- /*
- ** If this map was not opened by the current
- ** process, do not close the map but recover
- ** the file descriptor.
- */
-
- if (map->map_pid != CurrentPid)
- {
- int fd = -1;
-
- errno = db->fd(db, &fd);
- if (fd >= 0)
- (void) close(fd);
- return;
- }
-
- if ((errno = db->close(db, 0)) != 0)
-# endif /* DB_VERSION_MAJOR < 2 */
- syserr("db_map_close(%s, %s, %lx): db close failure",
- map->map_mname, map->map_file, map->map_mflags);
-}
-#endif /* NEWDB */
-/*
-** NIS Modules
-*/
-
-#if NIS
-
-# ifndef YPERR_BUSY
-# define YPERR_BUSY 16
-# endif /* ! YPERR_BUSY */
-
-/*
-** NIS_MAP_OPEN -- open DBM map
-*/
-
-bool
-nis_map_open(map, mode)
- MAP *map;
- int mode;
-{
- int yperr;
- register char *p;
- auto char *vp;
- auto int vsize;
-
- if (tTd(38, 2))
- sm_dprintf("nis_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
- errno = SM_EMAPCANTWRITE;
- return false;
- }
-
- p = strchr(map->map_file, '@');
- if (p != NULL)
- {
- *p++ = '\0';
- if (*p != '\0')
- map->map_domain = p;
- }
-
- if (*map->map_file == '\0')
- map->map_file = "mail.aliases";
-
- if (map->map_domain == NULL)
- {
- yperr = yp_get_default_domain(&map->map_domain);
- if (yperr != 0)
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("451 4.3.5 NIS map %s specified, but NIS not running",
- map->map_file);
- return false;
- }
- }
-
- /* check to see if this map actually exists */
- vp = NULL;
- yperr = yp_match(map->map_domain, map->map_file, "@", 1,
- &vp, &vsize);
- if (tTd(38, 10))
- sm_dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n",
- map->map_domain, map->map_file, yperr_string(yperr));
- if (vp != NULL)
- sm_free(vp);
-
- if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY)
- {
- /*
- ** We ought to be calling aliaswait() here if this is an
- ** alias file, but powerful HP-UX NIS servers apparently
- ** don't insert the @:@ token into the alias map when it
- ** is rebuilt, so aliaswait() just hangs. I hate HP-UX.
- */
-
-# if 0
- if (!bitset(MF_ALIAS, map->map_mflags) ||
- aliaswait(map, NULL, true))
-# endif /* 0 */
- return true;
- }
-
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- syserr("451 4.3.5 Cannot bind to map %s in domain %s: %s",
- map->map_file, map->map_domain, yperr_string(yperr));
- }
-
- return false;
-}
-
-
-/*
-** NIS_MAP_LOOKUP -- look up a datum in a NIS map
-*/
-
-/* ARGSUSED3 */
-char *
-nis_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char *vp;
- auto int vsize;
- int buflen;
- int yperr;
- char keybuf[MAXNAME + 1];
- char *SM_NONVOLATILE result = NULL;
-
- if (tTd(38, 20))
- sm_dprintf("nis_map_lookup(%s, %s)\n",
- map->map_mname, name);
-
- buflen = strlen(name);
- if (buflen > sizeof(keybuf) - 1)
- buflen = sizeof(keybuf) - 1;
- memmove(keybuf, name, buflen);
- keybuf[buflen] = '\0';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(keybuf);
- yperr = YPERR_KEY;
- vp = NULL;
- if (bitset(MF_TRY0NULL, map->map_mflags))
- {
- yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
- &vp, &vsize);
- if (yperr == 0)
- map->map_mflags &= ~MF_TRY1NULL;
- }
- if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags))
- {
- SM_FREE_CLR(vp);
- buflen++;
- yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen,
- &vp, &vsize);
- if (yperr == 0)
- map->map_mflags &= ~MF_TRY0NULL;
- }
- if (yperr != 0)
- {
- if (yperr != YPERR_KEY && yperr != YPERR_BUSY)
- map->map_mflags &= ~(MF_VALID|MF_OPEN);
- if (vp != NULL)
- sm_free(vp);
- return NULL;
- }
- SM_TRY
- if (bitset(MF_MATCHONLY, map->map_mflags))
- result = map_rewrite(map, name, strlen(name), NULL);
- else
- result = map_rewrite(map, vp, vsize, av);
- SM_FINALLY
- if (vp != NULL)
- sm_free(vp);
- SM_END_TRY
- return result;
-}
-
-
-/*
-** NIS_GETCANONNAME -- look up canonical name in NIS
-*/
-
-static bool
-nis_getcanonname(name, hbsize, statp)
- char *name;
- int hbsize;
- int *statp;
-{
- char *vp;
- auto int vsize;
- int keylen;
- int yperr;
- static bool try0null = true;
- static bool try1null = true;
- static char *yp_domain = NULL;
- char host_record[MAXLINE];
- char cbuf[MAXNAME];
- char nbuf[MAXNAME + 1];
-
- if (tTd(38, 20))
- sm_dprintf("nis_getcanonname(%s)\n", name);
-
- if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
- {
- *statp = EX_UNAVAILABLE;
- return false;
- }
- (void) shorten_hostname(nbuf);
- keylen = strlen(nbuf);
-
- if (yp_domain == NULL)
- (void) yp_get_default_domain(&yp_domain);
- makelower(nbuf);
- yperr = YPERR_KEY;
- vp = NULL;
- if (try0null)
- {
- yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
- &vp, &vsize);
- if (yperr == 0)
- try1null = false;
- }
- if (yperr == YPERR_KEY && try1null)
- {
- SM_FREE_CLR(vp);
- keylen++;
- yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
- &vp, &vsize);
- if (yperr == 0)
- try0null = false;
- }
- if (yperr != 0)
- {
- if (yperr == YPERR_KEY)
- *statp = EX_NOHOST;
- else if (yperr == YPERR_BUSY)
- *statp = EX_TEMPFAIL;
- else
- *statp = EX_UNAVAILABLE;
- if (vp != NULL)
- sm_free(vp);
- return false;
- }
- (void) sm_strlcpy(host_record, vp, sizeof(host_record));
- sm_free(vp);
- if (tTd(38, 44))
- sm_dprintf("got record `%s'\n", host_record);
- vp = strpbrk(host_record, "#\n");
- if (vp != NULL)
- *vp = '\0';
- if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof(cbuf)))
- {
- /* this should not happen, but.... */
- *statp = EX_NOHOST;
- return false;
- }
- if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
- {
- *statp = EX_UNAVAILABLE;
- return false;
- }
- *statp = EX_OK;
- return true;
-}
-
-#endif /* NIS */
-/*
-** NISPLUS Modules
-**
-** This code donated by Sun Microsystems.
-*/
-
-#if NISPLUS
-
-# undef NIS /* symbol conflict in nis.h */
-# undef T_UNSPEC /* symbol conflict in nis.h -> ... -> sys/tiuser.h */
-# include <rpcsvc/nis.h>
-# include <rpcsvc/nislib.h>
-
-# define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
-# define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
-# define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
-# define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.')
-
-/*
-** NISPLUS_MAP_OPEN -- open nisplus table
-*/
-
-bool
-nisplus_map_open(map, mode)
- MAP *map;
- int mode;
-{
- nis_result *res = NULL;
- int retry_cnt, max_col, i;
- char qbuf[MAXLINE + NIS_MAXNAMELEN];
-
- if (tTd(38, 2))
- sm_dprintf("nisplus_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- errno = EPERM;
- return false;
- }
-
- if (*map->map_file == '\0')
- map->map_file = "mail_aliases.org_dir";
-
- if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL)
- {
- /* set default NISPLUS Domain to $m */
- map->map_domain = newstr(nisplus_default_domain());
- if (tTd(38, 2))
- sm_dprintf("nisplus_map_open(%s): using domain %s\n",
- map->map_file, map->map_domain);
- }
- if (!PARTIAL_NAME(map->map_file))
- {
- map->map_domain = newstr("");
- (void) sm_strlcpy(qbuf, map->map_file, sizeof(qbuf));
- }
- else
- {
- /* check to see if this map actually exists */
- (void) sm_strlcpyn(qbuf, sizeof(qbuf), 3,
- map->map_file, ".", map->map_domain);
- }
-
- retry_cnt = 0;
- while (res == NULL || res->status != NIS_SUCCESS)
- {
- res = nis_lookup(qbuf, FOLLOW_LINKS);
- switch (res->status)
- {
- case NIS_SUCCESS:
- break;
-
- case NIS_TRYAGAIN:
- case NIS_RPCERROR:
- case NIS_NAMEUNREACHABLE:
- if (retry_cnt++ > 4)
- {
- errno = EAGAIN;
- return false;
- }
- /* try not to overwhelm hosed server */
- sleep(2);
- break;
-
- default: /* all other nisplus errors */
-# if 0
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("451 4.3.5 Cannot find table %s.%s: %s",
- map->map_file, map->map_domain,
- nis_sperrno(res->status));
-# endif /* 0 */
- errno = EAGAIN;
- return false;
- }
- }
-
- if (NIS_RES_NUMOBJ(res) != 1 ||
- (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ))
- {
- if (tTd(38, 10))
- sm_dprintf("nisplus_map_open: %s is not a table\n", qbuf);
-# if 0
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("451 4.3.5 %s.%s: %s is not a table",
- map->map_file, map->map_domain,
- nis_sperrno(res->status));
-# endif /* 0 */
- errno = EBADF;
- return false;
- }
- /* default key column is column 0 */
- if (map->map_keycolnm == NULL)
- map->map_keycolnm = newstr(COL_NAME(res,0));
-
- max_col = COL_MAX(res);
-
- /* verify the key column exist */
- for (i = 0; i < max_col; i++)
- {
- if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0)
- break;
- }
- if (i == max_col)
- {
- if (tTd(38, 2))
- sm_dprintf("nisplus_map_open(%s): can not find key column %s\n",
- map->map_file, map->map_keycolnm);
- errno = ENOENT;
- return false;
- }
-
- /* default value column is the last column */
- if (map->map_valcolnm == NULL)
- {
- map->map_valcolno = max_col - 1;
- return true;
- }
-
- for (i = 0; i< max_col; i++)
- {
- if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0)
- {
- map->map_valcolno = i;
- return true;
- }
- }
-
- if (tTd(38, 2))
- sm_dprintf("nisplus_map_open(%s): can not find column %s\n",
- map->map_file, map->map_keycolnm);
- errno = ENOENT;
- return false;
-}
-
-
-/*
-** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
-*/
-
-char *
-nisplus_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char *p;
- auto int vsize;
- char *skp;
- int skleft;
- char search_key[MAXNAME + 4];
- char qbuf[MAXLINE + NIS_MAXNAMELEN];
- nis_result *result;
-
- if (tTd(38, 20))
- sm_dprintf("nisplus_map_lookup(%s, %s)\n",
- map->map_mname, name);
-
- if (!bitset(MF_OPEN, map->map_mflags))
- {
- if (nisplus_map_open(map, O_RDONLY))
- {
- map->map_mflags |= MF_OPEN;
- map->map_pid = CurrentPid;
- }
- else
- {
- *statp = EX_UNAVAILABLE;
- return NULL;
- }
- }
-
- /*
- ** Copy the name to the key buffer, escaping double quote characters
- ** by doubling them and quoting "]" and "," to avoid having the
- ** NIS+ parser choke on them.
- */
-
- skleft = sizeof(search_key) - 4;
- skp = search_key;
- for (p = name; *p != '\0' && skleft > 0; p++)
- {
- switch (*p)
- {
- case ']':
- case ',':
- /* quote the character */
- *skp++ = '"';
- *skp++ = *p;
- *skp++ = '"';
- skleft -= 3;
- break;
-
- case '"':
- /* double the quote */
- *skp++ = '"';
- skleft--;
- /* FALLTHROUGH */
-
- default:
- *skp++ = *p;
- skleft--;
- break;
- }
- }
- *skp = '\0';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(search_key);
-
- /* construct the query */
- if (PARTIAL_NAME(map->map_file))
- (void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s.%s",
- map->map_keycolnm, search_key, map->map_file,
- map->map_domain);
- else
- (void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s",
- map->map_keycolnm, search_key, map->map_file);
-
- if (tTd(38, 20))
- sm_dprintf("qbuf=%s\n", qbuf);
- result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL);
- if (result->status == NIS_SUCCESS)
- {
- int count;
- char *str;
-
- if ((count = NIS_RES_NUMOBJ(result)) != 1)
- {
- if (LogLevel > 10)
- sm_syslog(LOG_WARNING, CurEnv->e_id,
- "%s: lookup error, expected 1 entry, got %d",
- map->map_file, count);
-
- /* ignore second entry */
- if (tTd(38, 20))
- sm_dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
- name, count);
- }
-
- p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno));
- /* set the length of the result */
- if (p == NULL)
- p = "";
- vsize = strlen(p);
- if (tTd(38, 20))
- sm_dprintf("nisplus_map_lookup(%s), found %s\n",
- name, p);
- if (bitset(MF_MATCHONLY, map->map_mflags))
- str = map_rewrite(map, name, strlen(name), NULL);
- else
- str = map_rewrite(map, p, vsize, av);
- nis_freeresult(result);
- *statp = EX_OK;
- return str;
- }
- else
- {
- if (result->status == NIS_NOTFOUND)
- *statp = EX_NOTFOUND;
- else if (result->status == NIS_TRYAGAIN)
- *statp = EX_TEMPFAIL;
- else
- {
- *statp = EX_UNAVAILABLE;
- map->map_mflags &= ~(MF_VALID|MF_OPEN);
- }
- }
- if (tTd(38, 20))
- sm_dprintf("nisplus_map_lookup(%s), failed\n", name);
- nis_freeresult(result);
- return NULL;
-}
-
-
-
-/*
-** NISPLUS_GETCANONNAME -- look up canonical name in NIS+
-*/
-
-static bool
-nisplus_getcanonname(name, hbsize, statp)
- char *name;
- int hbsize;
- int *statp;
-{
- char *vp;
- auto int vsize;
- nis_result *result;
- char *p;
- char nbuf[MAXNAME + 1];
- char qbuf[MAXLINE + NIS_MAXNAMELEN];
-
- if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
- {
- *statp = EX_UNAVAILABLE;
- return false;
- }
- (void) shorten_hostname(nbuf);
-
- p = strchr(nbuf, '.');
- if (p == NULL)
- {
- /* single token */
- (void) sm_snprintf(qbuf, sizeof(qbuf),
- "[name=%s],hosts.org_dir", nbuf);
- }
- else if (p[1] != '\0')
- {
- /* multi token -- take only first token in nbuf */
- *p = '\0';
- (void) sm_snprintf(qbuf, sizeof(qbuf),
- "[name=%s],hosts.org_dir.%s", nbuf, &p[1]);
- }
- else
- {
- *statp = EX_NOHOST;
- return false;
- }
-
- if (tTd(38, 20))
- sm_dprintf("\nnisplus_getcanonname(%s), qbuf=%s\n",
- name, qbuf);
-
- result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH,
- NULL, NULL);
-
- if (result->status == NIS_SUCCESS)
- {
- int count;
- char *domain;
-
- if ((count = NIS_RES_NUMOBJ(result)) != 1)
- {
- if (LogLevel > 10)
- sm_syslog(LOG_WARNING, CurEnv->e_id,
- "nisplus_getcanonname: lookup error, expected 1 entry, got %d",
- count);
-
- /* ignore second entry */
- if (tTd(38, 20))
- sm_dprintf("nisplus_getcanonname(%s), got %d entries, all but first ignored\n",
- name, count);
- }
-
- if (tTd(38, 20))
- sm_dprintf("nisplus_getcanonname(%s), found in directory \"%s\"\n",
- name, (NIS_RES_OBJECT(result))->zo_domain);
-
-
- vp = ((NIS_RES_OBJECT(result))->EN_col(0));
- vsize = strlen(vp);
- if (tTd(38, 20))
- sm_dprintf("nisplus_getcanonname(%s), found %s\n",
- name, vp);
- if (strchr(vp, '.') != NULL)
- {
- domain = "";
- }
- else
- {
- domain = macvalue('m', CurEnv);
- if (domain == NULL)
- domain = "";
- }
- if (hbsize > vsize + (int) strlen(domain) + 1)
- {
- if (domain[0] == '\0')
- (void) sm_strlcpy(name, vp, hbsize);
- else
- (void) sm_snprintf(name, hbsize,
- "%s.%s", vp, domain);
- *statp = EX_OK;
- }
- else
- *statp = EX_NOHOST;
- nis_freeresult(result);
- return true;
- }
- else
- {
- if (result->status == NIS_NOTFOUND)
- *statp = EX_NOHOST;
- else if (result->status == NIS_TRYAGAIN)
- *statp = EX_TEMPFAIL;
- else
- *statp = EX_UNAVAILABLE;
- }
- if (tTd(38, 20))
- sm_dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
- name, result->status, *statp);
- nis_freeresult(result);
- return false;
-}
-
-char *
-nisplus_default_domain()
-{
- static char default_domain[MAXNAME + 1] = "";
- char *p;
-
- if (default_domain[0] != '\0')
- return default_domain;
-
- p = nis_local_directory();
- (void) sm_strlcpy(default_domain, p, sizeof(default_domain));
- return default_domain;
-}
-
-#endif /* NISPLUS */
-/*
-** LDAP Modules
-*/
-
-/*
-** LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
-*/
-
-#if defined(LDAPMAP) || defined(PH_MAP)
-
-# if PH_MAP
-# define ph_map_dequote ldapmap_dequote
-# endif /* PH_MAP */
-
-static char *ldapmap_dequote __P((char *));
-
-static char *
-ldapmap_dequote(str)
- char *str;
-{
- char *p;
- char *start;
-
- if (str == NULL)
- return NULL;
-
- p = str;
- if (*p == '"')
- {
- /* Should probably swallow initial whitespace here */
- start = ++p;
- }
- else
- return str;
- while (*p != '"' && *p != '\0')
- p++;
- if (*p != '\0')
- *p = '\0';
- return start;
-}
-#endif /* defined(LDAPMAP) || defined(PH_MAP) */
-
-#if LDAPMAP
-
-static SM_LDAP_STRUCT *LDAPDefaults = NULL;
-
-/*
-** LDAPMAP_OPEN -- open LDAP map
-**
-** Connect to the LDAP server. Re-use existing connections since a
-** single server connection to a host (with the same host, port,
-** bind DN, and secret) can answer queries for multiple maps.
-*/
-
-bool
-ldapmap_open(map, mode)
- MAP *map;
- int mode;
-{
- SM_LDAP_STRUCT *lmap;
- STAB *s;
- char *id;
-
- if (tTd(38, 2))
- sm_dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode);
-
-#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
- HASLDAPGETALIASBYNAME
- if (VendorCode == VENDOR_SUN &&
- strcmp(map->map_mname, "aliases.ldap") == 0)
- {
- return true;
- }
-#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */
-
- mode &= O_ACCMODE;
-
- /* sendmail doesn't have the ability to write to LDAP (yet) */
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
- errno = SM_EMAPCANTWRITE;
- return false;
- }
-
- lmap = (SM_LDAP_STRUCT *) map->map_db1;
-
- s = ldapmap_findconn(lmap);
- if (s->s_lmap != NULL)
- {
- /* Already have a connection open to this LDAP server */
- lmap->ldap_ld = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld;
- lmap->ldap_pid = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_pid;
-
- /* Add this map as head of linked list */
- lmap->ldap_next = s->s_lmap;
- s->s_lmap = map;
-
- if (tTd(38, 2))
- sm_dprintf("using cached connection\n");
- return true;
- }
-
- if (tTd(38, 2))
- sm_dprintf("opening new connection\n");
-
- if (lmap->ldap_host != NULL)
- id = lmap->ldap_host;
- else if (lmap->ldap_uri != NULL)
- id = lmap->ldap_uri;
- else
- id = "localhost";
-
- /* No connection yet, connect */
- if (!sm_ldap_start(map->map_mname, lmap))
- {
- if (errno == ETIMEDOUT)
- {
- if (LogLevel > 1)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "timeout conning to LDAP server %.100s",
- id);
- }
-
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- if (bitset(MF_NODEFER, map->map_mflags))
- {
- syserr("%s failed to %s in map %s",
-# if USE_LDAP_INIT
- "ldap_init/ldap_bind",
-# else /* USE_LDAP_INIT */
- "ldap_open",
-# endif /* USE_LDAP_INIT */
- id, map->map_mname);
- }
- else
- {
- syserr("451 4.3.5 %s failed to %s in map %s",
-# if USE_LDAP_INIT
- "ldap_init/ldap_bind",
-# else /* USE_LDAP_INIT */
- "ldap_open",
-# endif /* USE_LDAP_INIT */
- id, map->map_mname);
- }
- }
- return false;
- }
-
- /* Save connection for reuse */
- s->s_lmap = map;
- return true;
-}
-
-/*
-** LDAPMAP_CLOSE -- close ldap map
-*/
-
-void
-ldapmap_close(map)
- MAP *map;
-{
- SM_LDAP_STRUCT *lmap;
- STAB *s;
-
- if (tTd(38, 2))
- sm_dprintf("ldapmap_close(%s)\n", map->map_mname);
-
- lmap = (SM_LDAP_STRUCT *) map->map_db1;
-
- /* Check if already closed */
- if (lmap->ldap_ld == NULL)
- return;
-
- /* Close the LDAP connection */
- sm_ldap_close(lmap);
-
- /* Mark all the maps that share the connection as closed */
- s = ldapmap_findconn(lmap);
-
- while (s->s_lmap != NULL)
- {
- MAP *smap = s->s_lmap;
-
- if (tTd(38, 2) && smap != map)
- sm_dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n",
- map->map_mname, smap->map_mname);
- smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- lmap = (SM_LDAP_STRUCT *) smap->map_db1;
- lmap->ldap_ld = NULL;
- s->s_lmap = lmap->ldap_next;
- lmap->ldap_next = NULL;
- }
-}
-
-# ifdef SUNET_ID
-/*
-** SUNET_ID_HASH -- Convert a string to its Sunet_id canonical form
-** This only makes sense at Stanford University.
-*/
-
-static char *
-sunet_id_hash(str)
- char *str;
-{
- char *p, *p_last;
-
- p = str;
- p_last = p;
- while (*p != '\0')
- {
- if (islower(*p) || isdigit(*p))
- {
- *p_last = *p;
- p_last++;
- }
- else if (isupper(*p))
- {
- *p_last = tolower(*p);
- p_last++;
- }
- ++p;
- }
- if (*p_last != '\0')
- *p_last = '\0';
- return str;
-}
-# define SM_CONVERT_ID(str) sunet_id_hash(str)
-# else /* SUNET_ID */
-# define SM_CONVERT_ID(str) makelower(str)
-# endif /* SUNET_ID */
-
-/*
-** LDAPMAP_LOOKUP -- look up a datum in a LDAP map
-*/
-
-char *
-ldapmap_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- int flags;
- int i;
- int plen = 0;
- int psize = 0;
- int msgid;
- int save_errno;
- char *vp, *p;
- char *result = NULL;
- SM_RPOOL_T *rpool;
- SM_LDAP_STRUCT *lmap = NULL;
- char *argv[SM_LDAP_ARGS];
- char keybuf[MAXKEY];
-#if SM_LDAP_ARGS != MAX_MAP_ARGS
-# ERROR _SM_LDAP_ARGS must be the same as _MAX_MAP_ARGS
-#endif /* SM_LDAP_ARGS != MAX_MAP_ARGS */
-
-#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \
- HASLDAPGETALIASBYNAME
- if (VendorCode == VENDOR_SUN &&
- strcmp(map->map_mname, "aliases.ldap") == 0)
- {
- int rc;
-#if defined(GETLDAPALIASBYNAME_VERSION) && (GETLDAPALIASBYNAME_VERSION >= 2)
- extern char *__getldapaliasbyname();
- char *answer;
-
- answer = __getldapaliasbyname(name, &rc);
-#else
- char answer[MAXNAME + 1];
-
- rc = __getldapaliasbyname(name, answer, sizeof(answer));
-#endif
- if (rc != 0)
- {
- if (tTd(38, 20))
- sm_dprintf("getldapaliasbyname(%.100s) failed, errno=%d\n",
- name, errno);
- *statp = EX_NOTFOUND;
- return NULL;
- }
- *statp = EX_OK;
- if (tTd(38, 20))
- sm_dprintf("getldapaliasbyname(%.100s) => %s\n", name,
- answer);
- if (bitset(MF_MATCHONLY, map->map_mflags))
- result = map_rewrite(map, name, strlen(name), NULL);
- else
- result = map_rewrite(map, answer, strlen(answer), av);
-#if defined(GETLDAPALIASBYNAME_VERSION) && (GETLDAPALIASBYNAME_VERSION >= 2)
- free(answer);
-#endif
- return result;
- }
-#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */
-
- /* Get ldap struct pointer from map */
- lmap = (SM_LDAP_STRUCT *) map->map_db1;
- sm_ldap_setopts(lmap->ldap_ld, lmap);
-
- if (lmap->ldap_multi_args)
- {
- SM_REQUIRE(av != NULL);
- memset(argv, '\0', sizeof(argv));
- for (i = 0; i < SM_LDAP_ARGS && av[i] != NULL; i++)
- {
- argv[i] = sm_strdup(av[i]);
- if (argv[i] == NULL)
- {
- int save_errno, j;
-
- save_errno = errno;
- for (j = 0; j < i && argv[j] != NULL; j++)
- SM_FREE(argv[j]);
- *statp = EX_TEMPFAIL;
- errno = save_errno;
- return NULL;
- }
-
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- SM_CONVERT_ID(av[i]);
- }
- }
- else
- {
- (void) sm_strlcpy(keybuf, name, sizeof(keybuf));
-
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- SM_CONVERT_ID(keybuf);
- }
-
- if (tTd(38, 20))
- {
- if (lmap->ldap_multi_args)
- {
- sm_dprintf("ldapmap_lookup(%s, argv)\n",
- map->map_mname);
- for (i = 0; i < SM_LDAP_ARGS; i++)
- {
- sm_dprintf(" argv[%d] = %s\n", i,
- argv[i] == NULL ? "NULL" : argv[i]);
- }
- }
- else
- {
- sm_dprintf("ldapmap_lookup(%s, %s)\n",
- map->map_mname, name);
- }
- }
-
- if (lmap->ldap_multi_args)
- {
- msgid = sm_ldap_search_m(lmap, argv);
-
- /* free the argv array and its content, no longer needed */
- for (i = 0; i < SM_LDAP_ARGS && argv[i] != NULL; i++)
- SM_FREE(argv[i]);
- }
- else
- msgid = sm_ldap_search(lmap, keybuf);
- if (msgid == SM_LDAP_ERR)
- {
- errno = sm_ldap_geterrno(lmap->ldap_ld) + E_LDAPBASE;
- save_errno = errno;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- /*
- ** Do not include keybuf as this error may be shown
- ** to outsiders.
- */
-
- if (bitset(MF_NODEFER, map->map_mflags))
- syserr("Error in ldap_search in map %s",
- map->map_mname);
- else
- syserr("451 4.3.5 Error in ldap_search in map %s",
- map->map_mname);
- }
- *statp = EX_TEMPFAIL;
- switch (save_errno - E_LDAPBASE)
- {
-# ifdef LDAP_SERVER_DOWN
- case LDAP_SERVER_DOWN:
-# endif /* LDAP_SERVER_DOWN */
- case LDAP_TIMEOUT:
- case LDAP_UNAVAILABLE:
- /* server disappeared, try reopen on next search */
- ldapmap_close(map);
- break;
- }
- errno = save_errno;
- return NULL;
- }
-#if SM_LDAP_ERROR_ON_MISSING_ARGS
- else if (msgid == SM_LDAP_ERR_ARG_MISS)
- {
- if (bitset(MF_NODEFER, map->map_mflags))
- syserr("Error in ldap_search in map %s, too few arguments",
- map->map_mname);
- else
- syserr("554 5.3.5 Error in ldap_search in map %s, too few arguments",
- map->map_mname);
- *statp = EX_CONFIG;
- return NULL;
- }
-#endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */
-
- *statp = EX_NOTFOUND;
- vp = NULL;
-
- flags = 0;
- if (bitset(MF_SINGLEMATCH, map->map_mflags))
- flags |= SM_LDAP_SINGLEMATCH;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- flags |= SM_LDAP_MATCHONLY;
-# if _FFR_LDAP_SINGLEDN
- if (bitset(MF_SINGLEDN, map->map_mflags))
- flags |= SM_LDAP_SINGLEDN;
-# endif /* _FFR_LDAP_SINGLEDN */
-
- /* Create an rpool for search related memory usage */
- rpool = sm_rpool_new_x(NULL);
-
- p = NULL;
- *statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim,
- rpool, &p, &plen, &psize, NULL);
- save_errno = errno;
-
- /* Copy result so rpool can be freed */
- if (*statp == EX_OK && p != NULL)
- vp = newstr(p);
- sm_rpool_free(rpool);
-
- /* need to restart LDAP connection? */
- if (*statp == EX_RESTART)
- {
- *statp = EX_TEMPFAIL;
- ldapmap_close(map);
- }
-
- errno = save_errno;
- if (*statp != EX_OK && *statp != EX_NOTFOUND)
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- if (bitset(MF_NODEFER, map->map_mflags))
- syserr("Error getting LDAP results in map %s",
- map->map_mname);
- else
- syserr("451 4.3.5 Error getting LDAP results in map %s",
- map->map_mname);
- }
- errno = save_errno;
- return NULL;
- }
-
- /* Did we match anything? */
- if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags))
- return NULL;
-
- if (*statp == EX_OK)
- {
- if (LogLevel > 9)
- sm_syslog(LOG_INFO, CurEnv->e_id,
- "ldap %.100s => %s", name,
- vp == NULL ? "<NULL>" : vp);
- if (bitset(MF_MATCHONLY, map->map_mflags))
- result = map_rewrite(map, name, strlen(name), NULL);
- else
- {
- /* vp != NULL according to test above */
- result = map_rewrite(map, vp, strlen(vp), av);
- }
- if (vp != NULL)
- sm_free(vp); /* XXX */
- }
- return result;
-}
-
-/*
-** LDAPMAP_FINDCONN -- find an LDAP connection to the server
-**
-** Cache LDAP connections based on the host, port, bind DN,
-** secret, and PID so we don't have multiple connections open to
-** the same server for different maps. Need a separate connection
-** per PID since a parent process may close the map before the
-** child is done with it.
-**
-** Parameters:
-** lmap -- LDAP map information
-**
-** Returns:
-** Symbol table entry for the LDAP connection.
-*/
-
-static STAB *
-ldapmap_findconn(lmap)
- SM_LDAP_STRUCT *lmap;
-{
- char *format;
- char *nbuf;
- char *id;
- STAB *SM_NONVOLATILE s = NULL;
-
- if (lmap->ldap_host != NULL)
- id = lmap->ldap_host;
- else if (lmap->ldap_uri != NULL)
- id = lmap->ldap_uri;
- else
- id = "localhost";
-
- format = "%s%c%d%c%d%c%s%c%s%d";
- nbuf = sm_stringf_x(format,
- id,
- CONDELSE,
- lmap->ldap_port,
- CONDELSE,
- lmap->ldap_version,
- CONDELSE,
- (lmap->ldap_binddn == NULL ? ""
- : lmap->ldap_binddn),
- CONDELSE,
- (lmap->ldap_secret == NULL ? ""
- : lmap->ldap_secret),
- (int) CurrentPid);
- SM_TRY
- s = stab(nbuf, ST_LMAP, ST_ENTER);
- SM_FINALLY
- sm_free(nbuf);
- SM_END_TRY
- return s;
-}
-/*
-** LDAPMAP_PARSEARGS -- parse ldap map definition args.
-*/
-
-static struct lamvalues LDAPAuthMethods[] =
-{
- { "none", LDAP_AUTH_NONE },
- { "simple", LDAP_AUTH_SIMPLE },
-# ifdef LDAP_AUTH_KRBV4
- { "krbv4", LDAP_AUTH_KRBV4 },
-# endif /* LDAP_AUTH_KRBV4 */
- { NULL, 0 }
-};
-
-static struct ladvalues LDAPAliasDereference[] =
-{
- { "never", LDAP_DEREF_NEVER },
- { "always", LDAP_DEREF_ALWAYS },
- { "search", LDAP_DEREF_SEARCHING },
- { "find", LDAP_DEREF_FINDING },
- { NULL, 0 }
-};
-
-static struct lssvalues LDAPSearchScope[] =
-{
- { "base", LDAP_SCOPE_BASE },
- { "one", LDAP_SCOPE_ONELEVEL },
- { "sub", LDAP_SCOPE_SUBTREE },
- { NULL, 0 }
-};
-
-bool
-ldapmap_parseargs(map, args)
- MAP *map;
- char *args;
-{
- bool secretread = true;
- bool attrssetup = false;
- int i;
- register char *p = args;
- SM_LDAP_STRUCT *lmap;
- struct lamvalues *lam;
- struct ladvalues *lad;
- struct lssvalues *lss;
- char ldapfilt[MAXLINE];
- char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD];
-
- /* Get ldap struct pointer from map */
- lmap = (SM_LDAP_STRUCT *) map->map_db1;
-
- /* Check if setting the initial LDAP defaults */
- if (lmap == NULL || lmap != LDAPDefaults)
- {
- /* We need to alloc an SM_LDAP_STRUCT struct */
- lmap = (SM_LDAP_STRUCT *) xalloc(sizeof(*lmap));
- if (LDAPDefaults == NULL)
- sm_ldap_clear(lmap);
- else
- STRUCTCOPY(*LDAPDefaults, *lmap);
- }
-
- /* there is no check whether there is really an argument */
- map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
- map->map_spacesub = SpaceSub; /* default value */
-
- /* Check if setting up an alias or file class LDAP map */
- if (bitset(MF_ALIAS, map->map_mflags))
- {
- /* Comma separate if used as an alias file */
- map->map_coldelim = ',';
- if (*args == '\0')
- {
- int n;
- char *lc;
- char jbuf[MAXHOSTNAMELEN];
- char lcbuf[MAXLINE];
-
- /* Get $j */
- expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope);
- if (jbuf[0] == '\0')
- {
- (void) sm_strlcpy(jbuf, "localhost",
- sizeof(jbuf));
- }
-
- lc = macvalue(macid("{sendmailMTACluster}"), CurEnv);
- if (lc == NULL)
- lc = "";
- else
- {
- expand(lc, lcbuf, sizeof(lcbuf), CurEnv);
- lc = lcbuf;
- }
-
- n = sm_snprintf(ldapfilt, sizeof(ldapfilt),
- "(&(objectClass=sendmailMTAAliasObject)(sendmailMTAAliasGrouping=aliases)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))(sendmailMTAKey=%%0))",
- lc, jbuf);
- if (n >= sizeof(ldapfilt))
- {
- syserr("%s: Default LDAP string too long",
- map->map_mname);
- return false;
- }
-
- /* default args for an alias LDAP entry */
- lmap->ldap_filter = ldapfilt;
- lmap->ldap_attr[0] = "objectClass";
- lmap->ldap_attr_type[0] = SM_LDAP_ATTR_OBJCLASS;
- lmap->ldap_attr_needobjclass[0] = NULL;
- lmap->ldap_attr[1] = "sendmailMTAAliasValue";
- lmap->ldap_attr_type[1] = SM_LDAP_ATTR_NORMAL;
- lmap->ldap_attr_needobjclass[1] = NULL;
- lmap->ldap_attr[2] = "sendmailMTAAliasSearch";
- lmap->ldap_attr_type[2] = SM_LDAP_ATTR_FILTER;
- lmap->ldap_attr_needobjclass[2] = "sendmailMTAMapObject";
- lmap->ldap_attr[3] = "sendmailMTAAliasURL";
- lmap->ldap_attr_type[3] = SM_LDAP_ATTR_URL;
- lmap->ldap_attr_needobjclass[3] = "sendmailMTAMapObject";
- lmap->ldap_attr[4] = NULL;
- lmap->ldap_attr_type[4] = SM_LDAP_ATTR_NONE;
- lmap->ldap_attr_needobjclass[4] = NULL;
- attrssetup = true;
- }
- }
- else if (bitset(MF_FILECLASS, map->map_mflags))
- {
- /* Space separate if used as a file class file */
- map->map_coldelim = ' ';
- }
-
- for (;;)
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- switch (*++p)
- {
- case 'A':
- map->map_mflags |= MF_APPEND;
- break;
-
- case 'a':
- map->map_app = ++p;
- break;
-
- case 'D':
- map->map_mflags |= MF_DEFER;
- break;
-
- case 'f':
- map->map_mflags |= MF_NOFOLDCASE;
- break;
-
- case 'm':
- map->map_mflags |= MF_MATCHONLY;
- break;
-
- 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 'q':
- map->map_mflags |= MF_KEEPQUOTES;
- break;
-
- case 'S':
- map->map_spacesub = *++p;
- break;
-
- case 'T':
- map->map_tapp = ++p;
- break;
-
- case 't':
- map->map_mflags |= MF_NODEFER;
- 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;
-
- /* Start of ldapmap specific args */
- case '1':
- map->map_mflags |= MF_SINGLEMATCH;
- break;
-
-# if _FFR_LDAP_SINGLEDN
- case '2':
- map->map_mflags |= MF_SINGLEDN;
- break;
-# endif /* _FFR_LDAP_SINGLEDN */
-
- case 'b': /* search base */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_base = p;
- break;
-
-# if _FFR_LDAP_NETWORK_TIMEOUT
- case 'c': /* network (connect) timeout */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_networktmo.tv_sec = atoi(p);
- break;
-# endif /* _FFR_LDAP_NETWORK_TIMEOUT */
-
- case 'd': /* Dn to bind to server as */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_binddn = p;
- break;
-
- case 'H': /* Use LDAP URI */
-# if !USE_LDAP_INIT
- syserr("Must compile with -DUSE_LDAP_INIT to use LDAP URIs (-H) in map %s",
- map->map_mname);
- return false;
-# else /* !USE_LDAP_INIT */
- if (lmap->ldap_host != NULL)
- {
- syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
- map->map_mname);
- return false;
- }
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_uri = p;
- break;
-# endif /* !USE_LDAP_INIT */
-
- case 'h': /* ldap host */
- while (isascii(*++p) && isspace(*p))
- continue;
- if (lmap->ldap_uri != NULL)
- {
- syserr("Can not specify both an LDAP host and an LDAP URI in map %s",
- map->map_mname);
- return false;
- }
- lmap->ldap_host = p;
- break;
-
- case 'K':
- lmap->ldap_multi_args = true;
- break;
-
- case 'k': /* search field */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_filter = p;
- break;
-
- case 'l': /* time limit */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_timelimit = atoi(p);
- lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit;
- break;
-
- case 'M': /* Method for binding */
- while (isascii(*++p) && isspace(*p))
- continue;
-
- if (sm_strncasecmp(p, "LDAP_AUTH_", 10) == 0)
- p += 10;
-
- for (lam = LDAPAuthMethods;
- lam != NULL && lam->lam_name != NULL; lam++)
- {
- if (sm_strncasecmp(p, lam->lam_name,
- strlen(lam->lam_name)) == 0)
- break;
- }
- if (lam->lam_name != NULL)
- lmap->ldap_method = lam->lam_code;
- else
- {
- /* bad config line */
- if (!bitset(MCF_OPTFILE,
- map->map_class->map_cflags))
- {
- char *ptr;
-
- if ((ptr = strchr(p, ' ')) != NULL)
- *ptr = '\0';
- syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s",
- p, map->map_mname);
- if (ptr != NULL)
- *ptr = ' ';
- return false;
- }
- }
- break;
-
- case 'n': /* retrieve attribute names only */
- lmap->ldap_attrsonly = LDAPMAP_TRUE;
- break;
-
- /*
- ** This is a string that is dependent on the
- ** method used defined by 'M'.
- */
-
- case 'P': /* Secret password for binding */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_secret = p;
- secretread = false;
- break;
-
- case 'p': /* ldap port */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_port = atoi(p);
- break;
-
- /* args stolen from ldapsearch.c */
- case 'R': /* don't auto chase referrals */
-# ifdef LDAP_REFERRALS
- lmap->ldap_options &= ~LDAP_OPT_REFERRALS;
-# else /* LDAP_REFERRALS */
- syserr("compile with -DLDAP_REFERRALS for referral support");
-# endif /* LDAP_REFERRALS */
- break;
-
- case 'r': /* alias dereferencing */
- while (isascii(*++p) && isspace(*p))
- continue;
-
- if (sm_strncasecmp(p, "LDAP_DEREF_", 11) == 0)
- p += 11;
-
- for (lad = LDAPAliasDereference;
- lad != NULL && lad->lad_name != NULL; lad++)
- {
- if (sm_strncasecmp(p, lad->lad_name,
- strlen(lad->lad_name)) == 0)
- break;
- }
- if (lad->lad_name != NULL)
- lmap->ldap_deref = lad->lad_code;
- else
- {
- /* bad config line */
- if (!bitset(MCF_OPTFILE,
- map->map_class->map_cflags))
- {
- char *ptr;
-
- if ((ptr = strchr(p, ' ')) != NULL)
- *ptr = '\0';
- syserr("Deref must be [never|always|search|find] (not %s) in map %s",
- p, map->map_mname);
- if (ptr != NULL)
- *ptr = ' ';
- return false;
- }
- }
- break;
-
- case 's': /* search scope */
- while (isascii(*++p) && isspace(*p))
- continue;
-
- if (sm_strncasecmp(p, "LDAP_SCOPE_", 11) == 0)
- p += 11;
-
- for (lss = LDAPSearchScope;
- lss != NULL && lss->lss_name != NULL; lss++)
- {
- if (sm_strncasecmp(p, lss->lss_name,
- strlen(lss->lss_name)) == 0)
- break;
- }
- if (lss->lss_name != NULL)
- lmap->ldap_scope = lss->lss_code;
- else
- {
- /* bad config line */
- if (!bitset(MCF_OPTFILE,
- map->map_class->map_cflags))
- {
- char *ptr;
-
- if ((ptr = strchr(p, ' ')) != NULL)
- *ptr = '\0';
- syserr("Scope must be [base|one|sub] (not %s) in map %s",
- p, map->map_mname);
- if (ptr != NULL)
- *ptr = ' ';
- return false;
- }
- }
- break;
-
- case 'V':
- if (*++p != '\\')
- lmap->ldap_attrsep = *p;
- else
- {
- switch (*++p)
- {
- case 'n':
- lmap->ldap_attrsep = '\n';
- break;
-
- case 't':
- lmap->ldap_attrsep = '\t';
- break;
-
- default:
- lmap->ldap_attrsep = '\\';
- }
- }
- break;
-
- case 'v': /* attr to return */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_attr[0] = p;
- lmap->ldap_attr[1] = NULL;
- break;
-
- case 'w':
- /* -w should be for passwd, -P should be for version */
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_version = atoi(p);
-# ifdef LDAP_VERSION_MAX
- if (lmap->ldap_version > LDAP_VERSION_MAX)
- {
- syserr("LDAP version %d exceeds max of %d in map %s",
- lmap->ldap_version, LDAP_VERSION_MAX,
- map->map_mname);
- return false;
- }
-# endif /* LDAP_VERSION_MAX */
-# ifdef LDAP_VERSION_MIN
- if (lmap->ldap_version < LDAP_VERSION_MIN)
- {
- syserr("LDAP version %d is lower than min of %d in map %s",
- lmap->ldap_version, LDAP_VERSION_MIN,
- map->map_mname);
- return false;
- }
-# endif /* LDAP_VERSION_MIN */
- break;
-
- case 'Z':
- while (isascii(*++p) && isspace(*p))
- continue;
- lmap->ldap_sizelimit = atoi(p);
- break;
-
- default:
- syserr("Illegal option %c map %s", *p, map->map_mname);
- break;
- }
-
- /* need to account for quoted strings here */
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- {
- if (*p == '"')
- {
- while (*++p != '"' && *p != '\0')
- continue;
- if (*p != '\0')
- p++;
- }
- else
- p++;
- }
-
- if (*p != '\0')
- *p++ = '\0';
- }
-
- if (map->map_app != NULL)
- map->map_app = newstr(ldapmap_dequote(map->map_app));
- if (map->map_tapp != NULL)
- map->map_tapp = newstr(ldapmap_dequote(map->map_tapp));
-
- /*
- ** We need to swallow up all the stuff into a struct
- ** and dump it into map->map_dbptr1
- */
-
- if (lmap->ldap_host != NULL &&
- (LDAPDefaults == NULL ||
- LDAPDefaults == lmap ||
- LDAPDefaults->ldap_host != lmap->ldap_host))
- lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host));
- map->map_domain = lmap->ldap_host;
-
- if (lmap->ldap_uri != NULL &&
- (LDAPDefaults == NULL ||
- LDAPDefaults == lmap ||
- LDAPDefaults->ldap_uri != lmap->ldap_uri))
- lmap->ldap_uri = newstr(ldapmap_dequote(lmap->ldap_uri));
- map->map_domain = lmap->ldap_uri;
-
- if (lmap->ldap_binddn != NULL &&
- (LDAPDefaults == NULL ||
- LDAPDefaults == lmap ||
- LDAPDefaults->ldap_binddn != lmap->ldap_binddn))
- lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn));
-
- if (lmap->ldap_secret != NULL &&
- (LDAPDefaults == NULL ||
- LDAPDefaults == lmap ||
- LDAPDefaults->ldap_secret != lmap->ldap_secret))
- {
- SM_FILE_T *sfd;
- long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES;
-
- if (DontLockReadFiles)
- sff |= SFF_NOLOCK;
-
- /* need to use method to map secret to passwd string */
- switch (lmap->ldap_method)
- {
- case LDAP_AUTH_NONE:
- /* Do nothing */
- break;
-
- case LDAP_AUTH_SIMPLE:
-
- /*
- ** Secret is the name of a file with
- ** the first line as the password.
- */
-
- /* Already read in the secret? */
- if (secretread)
- break;
-
- sfd = safefopen(ldapmap_dequote(lmap->ldap_secret),
- O_RDONLY, 0, sff);
- if (sfd == NULL)
- {
- syserr("LDAP map: cannot open secret %s",
- ldapmap_dequote(lmap->ldap_secret));
- return false;
- }
- lmap->ldap_secret = sfgets(m_tmp, sizeof(m_tmp),
- sfd, TimeOuts.to_fileopen,
- "ldapmap_parseargs");
- (void) sm_io_close(sfd, SM_TIME_DEFAULT);
- if (strlen(m_tmp) > LDAPMAP_MAX_PASSWD)
- {
- syserr("LDAP map: secret in %s too long",
- ldapmap_dequote(lmap->ldap_secret));
- return false;
- }
- if (lmap->ldap_secret != NULL &&
- strlen(m_tmp) > 0)
- {
- /* chomp newline */
- if (m_tmp[strlen(m_tmp) - 1] == '\n')
- m_tmp[strlen(m_tmp) - 1] = '\0';
-
- lmap->ldap_secret = m_tmp;
- }
- break;
-
-# ifdef LDAP_AUTH_KRBV4
- case LDAP_AUTH_KRBV4:
-
- /*
- ** Secret is where the ticket file is
- ** stashed
- */
-
- (void) sm_snprintf(m_tmp, sizeof(m_tmp),
- "KRBTKFILE=%s",
- ldapmap_dequote(lmap->ldap_secret));
- lmap->ldap_secret = m_tmp;
- break;
-# endif /* LDAP_AUTH_KRBV4 */
-
- default: /* Should NEVER get here */
- syserr("LDAP map: Illegal value in lmap method");
- return false;
- /* NOTREACHED */
- break;
- }
- }
-
- if (lmap->ldap_secret != NULL &&
- (LDAPDefaults == NULL ||
- LDAPDefaults == lmap ||
- LDAPDefaults->ldap_secret != lmap->ldap_secret))
- lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret));
-
- if (lmap->ldap_base != NULL &&
- (LDAPDefaults == NULL ||
- LDAPDefaults == lmap ||
- LDAPDefaults->ldap_base != lmap->ldap_base))
- lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base));
-
- /*
- ** Save the server from extra work. If request is for a single
- ** match, tell the server to only return enough records to
- ** determine if there is a single match or not. This can not
- ** be one since the server would only return one and we wouldn't
- ** know if there were others available.
- */
-
- if (bitset(MF_SINGLEMATCH, map->map_mflags))
- lmap->ldap_sizelimit = 2;
-
- /* If setting defaults, don't process ldap_filter and ldap_attr */
- if (lmap == LDAPDefaults)
- return true;
-
- if (lmap->ldap_filter != NULL)
- lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter));
- else
- {
- if (!bitset(MCF_OPTFILE, map->map_class->map_cflags))
- {
- syserr("No filter given in map %s", map->map_mname);
- return false;
- }
- }
-
- if (!attrssetup && lmap->ldap_attr[0] != NULL)
- {
- bool recurse = false;
- bool normalseen = false;
-
- i = 0;
- p = ldapmap_dequote(lmap->ldap_attr[0]);
- lmap->ldap_attr[0] = NULL;
-
- /* Prime the attr list with the objectClass attribute */
- lmap->ldap_attr[i] = "objectClass";
- lmap->ldap_attr_type[i] = SM_LDAP_ATTR_OBJCLASS;
- lmap->ldap_attr_needobjclass[i] = NULL;
- i++;
-
- while (p != NULL)
- {
- char *v;
-
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p == '\0')
- break;
- v = p;
- p = strchr(v, ',');
- if (p != NULL)
- *p++ = '\0';
-
- if (i >= LDAPMAP_MAX_ATTR)
- {
- syserr("Too many return attributes in %s (max %d)",
- map->map_mname, LDAPMAP_MAX_ATTR);
- return false;
- }
- if (*v != '\0')
- {
- int j;
- int use;
- char *type;
- char *needobjclass;
-
- type = strchr(v, ':');
- if (type != NULL)
- {
- *type++ = '\0';
- needobjclass = strchr(type, ':');
- if (needobjclass != NULL)
- *needobjclass++ = '\0';
- }
- else
- {
- needobjclass = NULL;
- }
-
- use = i;
-
- /* allow override on "objectClass" type */
- if (sm_strcasecmp(v, "objectClass") == 0 &&
- lmap->ldap_attr_type[0] == SM_LDAP_ATTR_OBJCLASS)
- {
- use = 0;
- }
- else
- {
- /*
- ** Don't add something to attribute
- ** list twice.
- */
-
- for (j = 1; j < i; j++)
- {
- if (sm_strcasecmp(v, lmap->ldap_attr[j]) == 0)
- {
- syserr("Duplicate attribute (%s) in %s",
- v, map->map_mname);
- return false;
- }
- }
-
- lmap->ldap_attr[use] = newstr(v);
- if (needobjclass != NULL &&
- *needobjclass != '\0' &&
- *needobjclass != '*')
- {
- lmap->ldap_attr_needobjclass[use] = newstr(needobjclass);
- }
- else
- {
- lmap->ldap_attr_needobjclass[use] = NULL;
- }
-
- }
-
- if (type != NULL && *type != '\0')
- {
- if (sm_strcasecmp(type, "dn") == 0)
- {
- recurse = true;
- lmap->ldap_attr_type[use] = SM_LDAP_ATTR_DN;
- }
- else if (sm_strcasecmp(type, "filter") == 0)
- {
- recurse = true;
- lmap->ldap_attr_type[use] = SM_LDAP_ATTR_FILTER;
- }
- else if (sm_strcasecmp(type, "url") == 0)
- {
- recurse = true;
- lmap->ldap_attr_type[use] = SM_LDAP_ATTR_URL;
- }
- else if (sm_strcasecmp(type, "normal") == 0)
- {
- lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
- normalseen = true;
- }
- else
- {
- syserr("Unknown attribute type (%s) in %s",
- type, map->map_mname);
- return false;
- }
- }
- else
- {
- lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL;
- normalseen = true;
- }
- i++;
- }
- }
- lmap->ldap_attr[i] = NULL;
-
- /* Set in case needed in future code */
- attrssetup = true;
-
- if (recurse && !normalseen)
- {
- syserr("LDAP recursion requested in %s but no returnable attribute given",
- map->map_mname);
- return false;
- }
- if (recurse && lmap->ldap_attrsonly == LDAPMAP_TRUE)
- {
- syserr("LDAP recursion requested in %s can not be used with -n",
- map->map_mname);
- return false;
- }
- }
- map->map_db1 = (ARBPTR_T) lmap;
- return true;
-}
-
-/*
-** LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf
-**
-** Parameters:
-** spec -- map argument string from LDAPDefaults option
-**
-** Returns:
-** None.
-*/
-
-void
-ldapmap_set_defaults(spec)
- char *spec;
-{
- STAB *class;
- MAP map;
-
- /* Allocate and set the default values */
- if (LDAPDefaults == NULL)
- LDAPDefaults = (SM_LDAP_STRUCT *) xalloc(sizeof(*LDAPDefaults));
- sm_ldap_clear(LDAPDefaults);
-
- memset(&map, '\0', sizeof(map));
-
- /* look up the class */
- class = stab("ldap", ST_MAPCLASS, ST_FIND);
- if (class == NULL)
- {
- syserr("readcf: LDAPDefaultSpec: class ldap not available");
- return;
- }
- map.map_class = &class->s_mapclass;
- map.map_db1 = (ARBPTR_T) LDAPDefaults;
- map.map_mname = "O LDAPDefaultSpec";
-
- (void) ldapmap_parseargs(&map, spec);
-
- /* These should never be set in LDAPDefaults */
- if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) ||
- map.map_spacesub != SpaceSub ||
- map.map_app != NULL ||
- map.map_tapp != NULL)
- {
- syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags");
- SM_FREE_CLR(map.map_app);
- SM_FREE_CLR(map.map_tapp);
- }
-
- if (LDAPDefaults->ldap_filter != NULL)
- {
- syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter");
-
- /* don't free, it isn't malloc'ed in parseargs */
- LDAPDefaults->ldap_filter = NULL;
- }
-
- if (LDAPDefaults->ldap_attr[0] != NULL)
- {
- syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes");
- /* don't free, they aren't malloc'ed in parseargs */
- LDAPDefaults->ldap_attr[0] = NULL;
- }
-}
-#endif /* LDAPMAP */
-/*
-** PH map
-*/
-
-#if PH_MAP
-
-/*
-** Support for the CCSO Nameserver (ph/qi).
-** This code is intended to replace the so-called "ph mailer".
-** Contributed by Mark D. Roth. Contact him for support.
-*/
-
-/* what version of the ph map code we're running */
-static char phmap_id[128];
-
-/* sendmail version for phmap id string */
-extern const char Version[];
-
-/* assume we're using nph-1.2.x if not specified */
-# ifndef NPH_VERSION
-# define NPH_VERSION 10200
-# endif
-
-/* compatibility for versions older than nph-1.2.0 */
-# if NPH_VERSION < 10200
-# define PH_OPEN_ROUNDROBIN PH_ROUNDROBIN
-# define PH_OPEN_DONTID PH_DONTID
-# define PH_CLOSE_FAST PH_FASTCLOSE
-# define PH_ERR_DATAERR PH_DATAERR
-# define PH_ERR_NOMATCH PH_NOMATCH
-# endif /* NPH_VERSION < 10200 */
-
-/*
-** PH_MAP_PARSEARGS -- parse ph map definition args.
-*/
-
-bool
-ph_map_parseargs(map, args)
- MAP *map;
- char *args;
-{
- register bool done;
- register char *p = args;
- PH_MAP_STRUCT *pmap = NULL;
-
- /* initialize version string */
- (void) sm_snprintf(phmap_id, sizeof(phmap_id),
- "sendmail-%s phmap-20010529 libphclient-%s",
- Version, libphclient_version);
-
- pmap = (PH_MAP_STRUCT *) xalloc(sizeof(*pmap));
-
- /* defaults */
- pmap->ph_servers = NULL;
- pmap->ph_field_list = NULL;
- pmap->ph = NULL;
- pmap->ph_timeout = 0;
- pmap->ph_fastclose = 0;
-
- map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL;
- 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 't':
- map->map_mflags |= MF_NODEFER;
- break;
-
- case 'a':
- map->map_app = ++p;
- break;
-
- case 'T':
- map->map_tapp = ++p;
- break;
-
- case 'l':
- while (isascii(*++p) && isspace(*p))
- continue;
- pmap->ph_timeout = atoi(p);
- break;
-
- case 'S':
- map->map_spacesub = *++p;
- break;
-
- case 'D':
- map->map_mflags |= MF_DEFER;
- break;
-
- case 'h': /* PH server list */
- while (isascii(*++p) && isspace(*p))
- continue;
- pmap->ph_servers = p;
- break;
-
- case 'k': /* fields to search for */
- while (isascii(*++p) && isspace(*p))
- continue;
- pmap->ph_field_list = p;
- break;
-
- default:
- syserr("ph_map_parseargs: unknown option -%c", *p);
- }
-
- /* try to account for quoted strings */
- done = isascii(*p) && isspace(*p);
- while (*p != '\0' && !done)
- {
- if (*p == '"')
- {
- while (*++p != '"' && *p != '\0')
- continue;
- if (*p != '\0')
- p++;
- }
- else
- p++;
- done = isascii(*p) && isspace(*p);
- }
-
- if (*p != '\0')
- *p++ = '\0';
- }
-
- if (map->map_app != NULL)
- map->map_app = newstr(ph_map_dequote(map->map_app));
- if (map->map_tapp != NULL)
- map->map_tapp = newstr(ph_map_dequote(map->map_tapp));
-
- if (pmap->ph_field_list != NULL)
- pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list));
-
- if (pmap->ph_servers != NULL)
- pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers));
- else
- {
- syserr("ph_map_parseargs: -h flag is required");
- return false;
- }
-
- map->map_db1 = (ARBPTR_T) pmap;
- return true;
-}
-
-/*
-** PH_MAP_CLOSE -- close the connection to the ph server
-*/
-
-void
-ph_map_close(map)
- MAP *map;
-{
- PH_MAP_STRUCT *pmap;
-
- pmap = (PH_MAP_STRUCT *)map->map_db1;
- if (tTd(38, 9))
- sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d\n",
- map->map_mname, pmap->ph_fastclose);
-
-
- if (pmap->ph != NULL)
- {
- ph_set_sendhook(pmap->ph, NULL);
- ph_set_recvhook(pmap->ph, NULL);
- ph_close(pmap->ph, pmap->ph_fastclose);
- }
-
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
-}
-
-static jmp_buf PHTimeout;
-
-/* ARGSUSED */
-static void
-ph_timeout(unused)
- int unused;
-{
- /*
- ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
- ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
- ** DOING.
- */
-
- errno = ETIMEDOUT;
- longjmp(PHTimeout, 1);
-}
-
-static void
-#if NPH_VERSION >= 10200
-ph_map_send_debug(appdata, text)
- void *appdata;
-#else
-ph_map_send_debug(text)
-#endif
- char *text;
-{
- if (LogLevel > 9)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "ph_map_send_debug: ==> %s", text);
- if (tTd(38, 20))
- sm_dprintf("ph_map_send_debug: ==> %s\n", text);
-}
-
-static void
-#if NPH_VERSION >= 10200
-ph_map_recv_debug(appdata, text)
- void *appdata;
-#else
-ph_map_recv_debug(text)
-#endif
- char *text;
-{
- if (LogLevel > 10)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "ph_map_recv_debug: <== %s", text);
- if (tTd(38, 21))
- sm_dprintf("ph_map_recv_debug: <== %s\n", text);
-}
-
-/*
-** PH_MAP_OPEN -- sub for opening PH map
-*/
-bool
-ph_map_open(map, mode)
- MAP *map;
- int mode;
-{
- PH_MAP_STRUCT *pmap;
- register SM_EVENT *ev = NULL;
- int save_errno = 0;
- char *hostlist, *host;
-
- if (tTd(38, 2))
- sm_dprintf("ph_map_open(%s)\n", map->map_mname);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
- errno = SM_EMAPCANTWRITE;
- return false;
- }
-
- if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER &&
- bitset(MF_DEFER, map->map_mflags))
- {
- if (tTd(9, 1))
- sm_dprintf("ph_map_open(%s) => DEFERRED\n",
- map->map_mname);
-
- /*
- ** Unset MF_DEFER here so that map_lookup() returns
- ** a temporary failure using the bogus map and
- ** map->map_tapp instead of the default permanent error.
- */
-
- map->map_mflags &= ~MF_DEFER;
- return false;
- }
-
- pmap = (PH_MAP_STRUCT *)map->map_db1;
- pmap->ph_fastclose = 0; /* refresh field for reopen */
-
- /* try each host in the list */
- hostlist = newstr(pmap->ph_servers);
- for (host = strtok(hostlist, " ");
- host != NULL;
- host = strtok(NULL, " "))
- {
- /* set timeout */
- if (pmap->ph_timeout != 0)
- {
- if (setjmp(PHTimeout) != 0)
- {
- ev = NULL;
- if (LogLevel > 1)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "timeout connecting to PH server %.100s",
- host);
- errno = ETIMEDOUT;
- goto ph_map_open_abort;
- }
- ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
- }
-
- /* open connection to server */
- if (ph_open(&(pmap->ph), host,
- PH_OPEN_ROUNDROBIN|PH_OPEN_DONTID,
- ph_map_send_debug, ph_map_recv_debug
-#if NPH_VERSION >= 10200
- , NULL
-#endif
- ) == 0
- && ph_id(pmap->ph, phmap_id) == 0)
- {
- if (ev != NULL)
- sm_clrevent(ev);
- sm_free(hostlist); /* XXX */
- return true;
- }
-
- ph_map_open_abort:
- save_errno = errno;
- if (ev != NULL)
- sm_clrevent(ev);
- pmap->ph_fastclose = PH_CLOSE_FAST;
- ph_map_close(map);
- errno = save_errno;
- }
-
- if (bitset(MF_NODEFER, map->map_mflags))
- {
- if (errno == 0)
- errno = EAGAIN;
- syserr("ph_map_open: %s: cannot connect to PH server",
- map->map_mname);
- }
- else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "ph_map_open: %s: cannot connect to PH server",
- map->map_mname);
- sm_free(hostlist); /* XXX */
- return false;
-}
-
-/*
-** PH_MAP_LOOKUP -- look up key from ph server
-*/
-
-char *
-ph_map_lookup(map, key, args, pstat)
- MAP *map;
- char *key;
- char **args;
- int *pstat;
-{
- int i, save_errno = 0;
- register SM_EVENT *ev = NULL;
- PH_MAP_STRUCT *pmap;
- char *value = NULL;
-
- pmap = (PH_MAP_STRUCT *)map->map_db1;
-
- *pstat = EX_OK;
-
- /* set timeout */
- if (pmap->ph_timeout != 0)
- {
- if (setjmp(PHTimeout) != 0)
- {
- ev = NULL;
- if (LogLevel > 1)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "timeout during PH lookup of %.100s",
- key);
- errno = ETIMEDOUT;
- *pstat = EX_TEMPFAIL;
- goto ph_map_lookup_abort;
- }
- ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0);
- }
-
- /* perform lookup */
- i = ph_email_resolve(pmap->ph, key, pmap->ph_field_list, &value);
- if (i == -1)
- *pstat = EX_TEMPFAIL;
- else if (i == PH_ERR_NOMATCH || i == PH_ERR_DATAERR)
- *pstat = EX_UNAVAILABLE;
-
- ph_map_lookup_abort:
- if (ev != NULL)
- sm_clrevent(ev);
-
- /*
- ** Close the connection if the timer popped
- ** or we got a temporary PH error
- */
-
- if (*pstat == EX_TEMPFAIL)
- {
- save_errno = errno;
- pmap->ph_fastclose = PH_CLOSE_FAST;
- ph_map_close(map);
- errno = save_errno;
- }
-
- if (*pstat == EX_OK)
- {
- if (tTd(38,20))
- sm_dprintf("ph_map_lookup: %s => %s\n", key, value);
-
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, key, strlen(key), NULL);
- else
- return map_rewrite(map, value, strlen(value), args);
- }
-
- return NULL;
-}
-#endif /* PH_MAP */
-
-/*
-** syslog map
-*/
-
-#define map_prio map_lockfd /* overload field */
-
-/*
-** SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages.
-*/
-
-bool
-syslog_map_parseargs(map, args)
- MAP *map;
- char *args;
-{
- char *p = args;
- char *priority = NULL;
-
- /* there is no check whether there is really an argument */
- while (*p != '\0')
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- ++p;
- if (*p == 'D')
- {
- map->map_mflags |= MF_DEFER;
- ++p;
- }
- else if (*p == 'S')
- {
- map->map_spacesub = *++p;
- if (*p != '\0')
- p++;
- }
- else if (*p == 'L')
- {
- while (*++p != '\0' && isascii(*p) && isspace(*p))
- continue;
- if (*p == '\0')
- break;
- priority = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
- }
- else
- {
- syserr("Illegal option %c map syslog", *p);
- ++p;
- }
- }
-
- if (priority == NULL)
- map->map_prio = LOG_INFO;
- else
- {
- if (sm_strncasecmp("LOG_", priority, 4) == 0)
- priority += 4;
-
-#ifdef LOG_EMERG
- if (sm_strcasecmp("EMERG", priority) == 0)
- map->map_prio = LOG_EMERG;
- else
-#endif /* LOG_EMERG */
-#ifdef LOG_ALERT
- if (sm_strcasecmp("ALERT", priority) == 0)
- map->map_prio = LOG_ALERT;
- else
-#endif /* LOG_ALERT */
-#ifdef LOG_CRIT
- if (sm_strcasecmp("CRIT", priority) == 0)
- map->map_prio = LOG_CRIT;
- else
-#endif /* LOG_CRIT */
-#ifdef LOG_ERR
- if (sm_strcasecmp("ERR", priority) == 0)
- map->map_prio = LOG_ERR;
- else
-#endif /* LOG_ERR */
-#ifdef LOG_WARNING
- if (sm_strcasecmp("WARNING", priority) == 0)
- map->map_prio = LOG_WARNING;
- else
-#endif /* LOG_WARNING */
-#ifdef LOG_NOTICE
- if (sm_strcasecmp("NOTICE", priority) == 0)
- map->map_prio = LOG_NOTICE;
- else
-#endif /* LOG_NOTICE */
-#ifdef LOG_INFO
- if (sm_strcasecmp("INFO", priority) == 0)
- map->map_prio = LOG_INFO;
- else
-#endif /* LOG_INFO */
-#ifdef LOG_DEBUG
- if (sm_strcasecmp("DEBUG", priority) == 0)
- map->map_prio = LOG_DEBUG;
- else
-#endif /* LOG_DEBUG */
- {
- syserr("syslog_map_parseargs: Unknown priority %s",
- priority);
- return false;
- }
- }
- return true;
-}
-
-/*
-** SYSLOG_MAP_LOOKUP -- rewrite and syslog message. Always return empty string
-*/
-
-char *
-syslog_map_lookup(map, string, args, statp)
- MAP *map;
- char *string;
- char **args;
- int *statp;
-{
- char *ptr = map_rewrite(map, string, strlen(string), args);
-
- if (ptr != NULL)
- {
- if (tTd(38, 20))
- sm_dprintf("syslog_map_lookup(%s (priority %d): %s\n",
- map->map_mname, map->map_prio, ptr);
-
- sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr);
- }
-
- *statp = EX_OK;
- return "";
-}
-
-#if _FFR_DPRINTF_MAP
-/*
-** dprintf map
-*/
-
-#define map_dbg_level map_lockfd /* overload field */
-
-/*
-** DPRINTF_MAP_PARSEARGS -- check for priority level to dprintf messages.
-*/
-
-bool
-dprintf_map_parseargs(map, args)
- MAP *map;
- char *args;
-{
- char *p = args;
- char *dbg_level = NULL;
-
- /* there is no check whether there is really an argument */
- while (*p != '\0')
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- ++p;
- if (*p == 'D')
- {
- map->map_mflags |= MF_DEFER;
- ++p;
- }
- else if (*p == 'S')
- {
- map->map_spacesub = *++p;
- if (*p != '\0')
- p++;
- }
- else if (*p == 'd')
- {
- while (*++p != '\0' && isascii(*p) && isspace(*p))
- continue;
- if (*p == '\0')
- break;
- dbg_level = p;
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
- }
- else
- {
- syserr("Illegal option %c map dprintf", *p);
- ++p;
- }
- }
-
- if (dbg_level == NULL)
- map->map_dbg_level = 0;
- else
- {
- if (!(isascii(*dbg_level) && isdigit(*dbg_level)))
- {
- syserr("dprintf map \"%s\", file %s: -d should specify a number, not %s",
- map->map_mname, map->map_file,
- dbg_level);
- return false;
- }
- map->map_dbg_level = atoi(dbg_level);
- }
- return true;
-}
-
-/*
-** DPRINTF_MAP_LOOKUP -- rewrite and print message. Always return empty string
-*/
-
-char *
-dprintf_map_lookup(map, string, args, statp)
- MAP *map;
- char *string;
- char **args;
- int *statp;
-{
- char *ptr = map_rewrite(map, string, strlen(string), args);
-
- if (ptr != NULL && tTd(85, map->map_dbg_level))
- sm_dprintf("%s\n", ptr);
- *statp = EX_OK;
- return "";
-}
-#endif /* _FFR_DPRINTF_MAP */
-
-/*
-** HESIOD Modules
-*/
-
-#if HESIOD
-
-bool
-hes_map_open(map, mode)
- MAP *map;
- int mode;
-{
- if (tTd(38, 2))
- sm_dprintf("hes_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
- errno = SM_EMAPCANTWRITE;
- return false;
- }
-
-# ifdef HESIOD_INIT
- if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0)
- return true;
-
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("451 4.3.5 cannot initialize Hesiod map (%s)",
- sm_errstring(errno));
- return false;
-# else /* HESIOD_INIT */
- if (hes_error() == HES_ER_UNINIT)
- hes_init();
- switch (hes_error())
- {
- case HES_ER_OK:
- case HES_ER_NOTFOUND:
- return true;
- }
-
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("451 4.3.5 cannot initialize Hesiod map (%d)", hes_error());
-
- return false;
-# endif /* HESIOD_INIT */
-}
-
-char *
-hes_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char **hp;
-
- if (tTd(38, 20))
- sm_dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name);
-
- if (name[0] == '\\')
- {
- char *np;
- int nl;
- int save_errno;
- char nbuf[MAXNAME];
-
- nl = strlen(name);
- if (nl < sizeof(nbuf) - 1)
- np = nbuf;
- else
- np = xalloc(strlen(name) + 2);
- np[0] = '\\';
- (void) sm_strlcpy(&np[1], name, (sizeof(nbuf)) - 1);
-# ifdef HESIOD_INIT
- hp = hesiod_resolve(HesiodContext, np, map->map_file);
-# else /* HESIOD_INIT */
- hp = hes_resolve(np, map->map_file);
-# endif /* HESIOD_INIT */
- save_errno = errno;
- if (np != nbuf)
- sm_free(np); /* XXX */
- errno = save_errno;
- }
- else
- {
-# ifdef HESIOD_INIT
- hp = hesiod_resolve(HesiodContext, name, map->map_file);
-# else /* HESIOD_INIT */
- hp = hes_resolve(name, map->map_file);
-# endif /* HESIOD_INIT */
- }
-# ifdef HESIOD_INIT
- if (hp == NULL || *hp == NULL)
- {
- switch (errno)
- {
- case ENOENT:
- *statp = EX_NOTFOUND;
- break;
- case ECONNREFUSED:
- *statp = EX_TEMPFAIL;
- break;
- case EMSGSIZE:
- case ENOMEM:
- default:
- *statp = EX_UNAVAILABLE;
- break;
- }
- if (hp != NULL)
- hesiod_free_list(HesiodContext, hp);
- return NULL;
- }
-# else /* HESIOD_INIT */
- if (hp == NULL || hp[0] == NULL)
- {
- switch (hes_error())
- {
- case HES_ER_OK:
- *statp = EX_OK;
- break;
-
- case HES_ER_NOTFOUND:
- *statp = EX_NOTFOUND;
- break;
-
- case HES_ER_CONFIG:
- *statp = EX_UNAVAILABLE;
- break;
-
- case HES_ER_NET:
- *statp = EX_TEMPFAIL;
- break;
- }
- return NULL;
- }
-# endif /* HESIOD_INIT */
-
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, hp[0], strlen(hp[0]), av);
-}
-
-/*
-** HES_MAP_CLOSE -- free the Hesiod context
-*/
-
-void
-hes_map_close(map)
- MAP *map;
-{
- if (tTd(38, 20))
- sm_dprintf("hes_map_close(%s)\n", map->map_file);
-
-# ifdef HESIOD_INIT
- /* Free the hesiod context */
- if (HesiodContext != NULL)
- {
- hesiod_end(HesiodContext);
- HesiodContext = NULL;
- }
-# endif /* HESIOD_INIT */
-}
-
-#endif /* HESIOD */
-/*
-** NeXT NETINFO Modules
-*/
-
-#if NETINFO
-
-# define NETINFO_DEFAULT_DIR "/aliases"
-# define NETINFO_DEFAULT_PROPERTY "members"
-
-/*
-** NI_MAP_OPEN -- open NetInfo Aliases
-*/
-
-bool
-ni_map_open(map, mode)
- MAP *map;
- int mode;
-{
- if (tTd(38, 2))
- sm_dprintf("ni_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
- mode &= O_ACCMODE;
-
- if (*map->map_file == '\0')
- map->map_file = NETINFO_DEFAULT_DIR;
-
- if (map->map_valcolnm == NULL)
- map->map_valcolnm = NETINFO_DEFAULT_PROPERTY;
-
- if (map->map_coldelim == '\0')
- {
- if (bitset(MF_ALIAS, map->map_mflags))
- map->map_coldelim = ',';
- else if (bitset(MF_FILECLASS, map->map_mflags))
- map->map_coldelim = ' ';
- }
- return true;
-}
-
-
-/*
-** NI_MAP_LOOKUP -- look up a datum in NetInfo
-*/
-
-char *
-ni_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char *res;
- char *propval;
-
- if (tTd(38, 20))
- sm_dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name);
-
- propval = ni_propval(map->map_file, map->map_keycolnm, name,
- map->map_valcolnm, map->map_coldelim);
-
- if (propval == NULL)
- return NULL;
-
- SM_TRY
- if (bitset(MF_MATCHONLY, map->map_mflags))
- res = map_rewrite(map, name, strlen(name), NULL);
- else
- res = map_rewrite(map, propval, strlen(propval), av);
- SM_FINALLY
- sm_free(propval);
- SM_END_TRY
- return res;
-}
-
-
-static bool
-ni_getcanonname(name, hbsize, statp)
- char *name;
- int hbsize;
- int *statp;
-{
- char *vptr;
- char *ptr;
- char nbuf[MAXNAME + 1];
-
- if (tTd(38, 20))
- sm_dprintf("ni_getcanonname(%s)\n", name);
-
- if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
- {
- *statp = EX_UNAVAILABLE;
- return false;
- }
- (void) shorten_hostname(nbuf);
-
- /* we only accept single token search key */
- if (strchr(nbuf, '.'))
- {
- *statp = EX_NOHOST;
- return false;
- }
-
- /* Do the search */
- vptr = ni_propval("/machines", NULL, nbuf, "name", '\n');
-
- if (vptr == NULL)
- {
- *statp = EX_NOHOST;
- return false;
- }
-
- /* Only want the first machine name */
- if ((ptr = strchr(vptr, '\n')) != NULL)
- *ptr = '\0';
-
- if (sm_strlcpy(name, vptr, hbsize) >= hbsize)
- {
- sm_free(vptr);
- *statp = EX_UNAVAILABLE;
- return true;
- }
- sm_free(vptr);
- *statp = EX_OK;
- return false;
-}
-#endif /* NETINFO */
-/*
-** TEXT (unindexed text file) Modules
-**
-** This code donated by Sun Microsystems.
-*/
-
-#define map_sff map_lockfd /* overload field */
-
-
-/*
-** TEXT_MAP_OPEN -- open text table
-*/
-
-bool
-text_map_open(map, mode)
- MAP *map;
- int mode;
-{
- long sff;
- int i;
-
- if (tTd(38, 2))
- sm_dprintf("text_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- errno = EPERM;
- return false;
- }
-
- if (*map->map_file == '\0')
- {
- syserr("text map \"%s\": file name required",
- map->map_mname);
- return false;
- }
-
- if (map->map_file[0] != '/')
- {
- syserr("text map \"%s\": file name must be fully qualified",
- map->map_mname);
- return false;
- }
-
- sff = SFF_ROOTOK|SFF_REGONLY;
- if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
- sff |= SFF_NOWLINK;
- if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
- sff |= SFF_SAFEDIRPATH;
- if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName,
- sff, S_IRUSR, NULL)) != 0)
- {
- int save_errno = errno;
-
- /* cannot open this map */
- if (tTd(38, 2))
- sm_dprintf("\tunsafe map file: %d\n", i);
- errno = save_errno;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("text map \"%s\": unsafe map file %s",
- map->map_mname, map->map_file);
- return false;
- }
-
- if (map->map_keycolnm == NULL)
- map->map_keycolno = 0;
- else
- {
- if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm)))
- {
- syserr("text map \"%s\", file %s: -k should specify a number, not %s",
- map->map_mname, map->map_file,
- map->map_keycolnm);
- return false;
- }
- map->map_keycolno = atoi(map->map_keycolnm);
- }
-
- if (map->map_valcolnm == NULL)
- map->map_valcolno = 0;
- else
- {
- if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm)))
- {
- syserr("text map \"%s\", file %s: -v should specify a number, not %s",
- map->map_mname, map->map_file,
- map->map_valcolnm);
- return false;
- }
- map->map_valcolno = atoi(map->map_valcolnm);
- }
-
- if (tTd(38, 2))
- {
- sm_dprintf("text_map_open(%s, %s): delimiter = ",
- map->map_mname, map->map_file);
- if (map->map_coldelim == '\0')
- sm_dprintf("(white space)\n");
- else
- sm_dprintf("%c\n", map->map_coldelim);
- }
-
- map->map_sff = sff;
- return true;
-}
-
-
-/*
-** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
-*/
-
-char *
-text_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- char *vp;
- auto int vsize;
- int buflen;
- SM_FILE_T *f;
- char delim;
- int key_idx;
- bool found_it;
- long sff = map->map_sff;
- char search_key[MAXNAME + 1];
- char linebuf[MAXLINE];
- char buf[MAXNAME + 1];
-
- found_it = false;
- if (tTd(38, 20))
- sm_dprintf("text_map_lookup(%s, %s)\n", map->map_mname, name);
-
- buflen = strlen(name);
- if (buflen > sizeof(search_key) - 1)
- buflen = sizeof(search_key) - 1; /* XXX just cut if off? */
- memmove(search_key, name, buflen);
- search_key[buflen] = '\0';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(search_key);
-
- f = safefopen(map->map_file, O_RDONLY, FileMode, sff);
- if (f == NULL)
- {
- map->map_mflags &= ~(MF_VALID|MF_OPEN);
- *statp = EX_UNAVAILABLE;
- return NULL;
- }
- key_idx = map->map_keycolno;
- delim = map->map_coldelim;
- while (sm_io_fgets(f, SM_TIME_DEFAULT,
- linebuf, sizeof(linebuf)) != NULL)
- {
- char *p;
-
- /* skip comment line */
- if (linebuf[0] == '#')
- continue;
- p = strchr(linebuf, '\n');
- if (p != NULL)
- *p = '\0';
- p = get_column(linebuf, key_idx, delim, buf, sizeof(buf));
- if (p != NULL && sm_strcasecmp(search_key, p) == 0)
- {
- found_it = true;
- break;
- }
- }
- (void) sm_io_close(f, SM_TIME_DEFAULT);
- if (!found_it)
- {
- *statp = EX_NOTFOUND;
- return NULL;
- }
- vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof(buf));
- if (vp == NULL)
- {
- *statp = EX_NOTFOUND;
- return NULL;
- }
- vsize = strlen(vp);
- *statp = EX_OK;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, vp, vsize, av);
-}
-
-/*
-** TEXT_GETCANONNAME -- look up canonical name in hosts file
-*/
-
-static bool
-text_getcanonname(name, hbsize, statp)
- char *name;
- int hbsize;
- int *statp;
-{
- bool found;
- char *dot;
- SM_FILE_T *f;
- char linebuf[MAXLINE];
- char cbuf[MAXNAME + 1];
- char nbuf[MAXNAME + 1];
-
- if (tTd(38, 20))
- sm_dprintf("text_getcanonname(%s)\n", name);
-
- if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf))
- {
- *statp = EX_UNAVAILABLE;
- return false;
- }
- dot = shorten_hostname(nbuf);
-
- f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, HostsFile, SM_IO_RDONLY,
- NULL);
- if (f == NULL)
- {
- *statp = EX_UNAVAILABLE;
- return false;
- }
- found = false;
- while (!found &&
- sm_io_fgets(f, SM_TIME_DEFAULT,
- linebuf, sizeof(linebuf)) != NULL)
- {
- char *p = strpbrk(linebuf, "#\n");
-
- if (p != NULL)
- *p = '\0';
- if (linebuf[0] != '\0')
- found = extract_canonname(nbuf, dot, linebuf,
- cbuf, sizeof(cbuf));
- }
- (void) sm_io_close(f, SM_TIME_DEFAULT);
- if (!found)
- {
- *statp = EX_NOHOST;
- return false;
- }
-
- if (sm_strlcpy(name, cbuf, hbsize) >= hbsize)
- {
- *statp = EX_UNAVAILABLE;
- return false;
- }
- *statp = EX_OK;
- return true;
-}
-/*
-** STAB (Symbol Table) Modules
-*/
-
-
-/*
-** STAB_MAP_LOOKUP -- look up alias in symbol table
-*/
-
-/* ARGSUSED2 */
-char *
-stab_map_lookup(map, name, av, pstat)
- register MAP *map;
- char *name;
- char **av;
- int *pstat;
-{
- register STAB *s;
-
- if (tTd(38, 20))
- sm_dprintf("stab_lookup(%s, %s)\n",
- map->map_mname, name);
-
- s = stab(name, ST_ALIAS, ST_FIND);
- if (s == NULL)
- return NULL;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, s->s_alias, strlen(s->s_alias), av);
-}
-
-/*
-** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
-*/
-
-void
-stab_map_store(map, lhs, rhs)
- register MAP *map;
- char *lhs;
- char *rhs;
-{
- register STAB *s;
-
- s = stab(lhs, ST_ALIAS, ST_ENTER);
- s->s_alias = newstr(rhs);
-}
-
-
-/*
-** STAB_MAP_OPEN -- initialize (reads data file)
-**
-** This is a wierd case -- it is only intended as a fallback for
-** aliases. For this reason, opens for write (only during a
-** "newaliases") always fails, and opens for read open the
-** actual underlying text file instead of the database.
-*/
-
-bool
-stab_map_open(map, mode)
- register MAP *map;
- int mode;
-{
- SM_FILE_T *af;
- long sff;
- struct stat st;
-
- if (tTd(38, 2))
- sm_dprintf("stab_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- errno = EPERM;
- return false;
- }
-
- sff = SFF_ROOTOK|SFF_REGONLY;
- if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
- sff |= SFF_NOWLINK;
- if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
- sff |= SFF_SAFEDIRPATH;
- af = safefopen(map->map_file, O_RDONLY, 0444, sff);
- if (af == NULL)
- return false;
- readaliases(map, af, false, false);
-
- if (fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &st) >= 0)
- map->map_mtime = st.st_mtime;
- (void) sm_io_close(af, SM_TIME_DEFAULT);
-
- return true;
-}
-/*
-** Implicit Modules
-**
-** Tries several types. For back compatibility of aliases.
-*/
-
-
-/*
-** IMPL_MAP_LOOKUP -- lookup in best open database
-*/
-
-char *
-impl_map_lookup(map, name, av, pstat)
- MAP *map;
- char *name;
- char **av;
- int *pstat;
-{
- if (tTd(38, 20))
- sm_dprintf("impl_map_lookup(%s, %s)\n",
- map->map_mname, name);
-
-#if NEWDB
- if (bitset(MF_IMPL_HASH, map->map_mflags))
- return db_map_lookup(map, name, av, pstat);
-#endif /* NEWDB */
-#if NDBM
- if (bitset(MF_IMPL_NDBM, map->map_mflags))
- return ndbm_map_lookup(map, name, av, pstat);
-#endif /* NDBM */
- return stab_map_lookup(map, name, av, pstat);
-}
-
-/*
-** IMPL_MAP_STORE -- store in open databases
-*/
-
-void
-impl_map_store(map, lhs, rhs)
- MAP *map;
- char *lhs;
- char *rhs;
-{
- if (tTd(38, 12))
- sm_dprintf("impl_map_store(%s, %s, %s)\n",
- map->map_mname, lhs, rhs);
-#if NEWDB
- if (bitset(MF_IMPL_HASH, map->map_mflags))
- db_map_store(map, lhs, rhs);
-#endif /* NEWDB */
-#if NDBM
- if (bitset(MF_IMPL_NDBM, map->map_mflags))
- ndbm_map_store(map, lhs, rhs);
-#endif /* NDBM */
- stab_map_store(map, lhs, rhs);
-}
-
-/*
-** IMPL_MAP_OPEN -- implicit database open
-*/
-
-bool
-impl_map_open(map, mode)
- MAP *map;
- int mode;
-{
- if (tTd(38, 2))
- sm_dprintf("impl_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
-#if NEWDB
- map->map_mflags |= MF_IMPL_HASH;
- if (hash_map_open(map, mode))
- {
-# ifdef NDBM_YP_COMPAT
- if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL)
-# endif /* NDBM_YP_COMPAT */
- return true;
- }
- else
- map->map_mflags &= ~MF_IMPL_HASH;
-#endif /* NEWDB */
-#if NDBM
- map->map_mflags |= MF_IMPL_NDBM;
- if (ndbm_map_open(map, mode))
- {
- return true;
- }
- else
- map->map_mflags &= ~MF_IMPL_NDBM;
-#endif /* NDBM */
-
-#if defined(NEWDB) || defined(NDBM)
- if (Verbose)
- message("WARNING: cannot open alias database %s%s",
- map->map_file,
- mode == O_RDONLY ? "; reading text version" : "");
-#else /* defined(NEWDB) || defined(NDBM) */
- if (mode != O_RDONLY)
- usrerr("Cannot rebuild aliases: no database format defined");
-#endif /* defined(NEWDB) || defined(NDBM) */
-
- if (mode == O_RDONLY)
- return stab_map_open(map, mode);
- else
- return false;
-}
-
-
-/*
-** IMPL_MAP_CLOSE -- close any open database(s)
-*/
-
-void
-impl_map_close(map)
- MAP *map;
-{
- if (tTd(38, 9))
- sm_dprintf("impl_map_close(%s, %s, %lx)\n",
- map->map_mname, map->map_file, map->map_mflags);
-#if NEWDB
- if (bitset(MF_IMPL_HASH, map->map_mflags))
- {
- db_map_close(map);
- map->map_mflags &= ~MF_IMPL_HASH;
- }
-#endif /* NEWDB */
-
-#if NDBM
- if (bitset(MF_IMPL_NDBM, map->map_mflags))
- {
- ndbm_map_close(map);
- map->map_mflags &= ~MF_IMPL_NDBM;
- }
-#endif /* NDBM */
-}
-/*
-** User map class.
-**
-** Provides access to the system password file.
-*/
-
-/*
-** USER_MAP_OPEN -- open user map
-**
-** Really just binds field names to field numbers.
-*/
-
-bool
-user_map_open(map, mode)
- MAP *map;
- int mode;
-{
- if (tTd(38, 2))
- sm_dprintf("user_map_open(%s, %d)\n",
- map->map_mname, mode);
-
- mode &= O_ACCMODE;
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
- errno = SM_EMAPCANTWRITE;
- return false;
- }
- if (map->map_valcolnm == NULL)
- /* EMPTY */
- /* nothing */ ;
- else if (sm_strcasecmp(map->map_valcolnm, "name") == 0)
- map->map_valcolno = 1;
- else if (sm_strcasecmp(map->map_valcolnm, "passwd") == 0)
- map->map_valcolno = 2;
- else if (sm_strcasecmp(map->map_valcolnm, "uid") == 0)
- map->map_valcolno = 3;
- else if (sm_strcasecmp(map->map_valcolnm, "gid") == 0)
- map->map_valcolno = 4;
- else if (sm_strcasecmp(map->map_valcolnm, "gecos") == 0)
- map->map_valcolno = 5;
- else if (sm_strcasecmp(map->map_valcolnm, "dir") == 0)
- map->map_valcolno = 6;
- else if (sm_strcasecmp(map->map_valcolnm, "shell") == 0)
- map->map_valcolno = 7;
- else
- {
- syserr("User map %s: unknown column name %s",
- map->map_mname, map->map_valcolnm);
- return false;
- }
- return true;
-}
-
-
-/*
-** USER_MAP_LOOKUP -- look up a user in the passwd file.
-*/
-
-/* ARGSUSED3 */
-char *
-user_map_lookup(map, key, av, statp)
- MAP *map;
- char *key;
- char **av;
- int *statp;
-{
- auto bool fuzzy;
- SM_MBDB_T user;
-
- if (tTd(38, 20))
- sm_dprintf("user_map_lookup(%s, %s)\n",
- map->map_mname, key);
-
- *statp = finduser(key, &fuzzy, &user);
- if (*statp != EX_OK)
- return NULL;
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, key, strlen(key), NULL);
- else
- {
- char *rwval = NULL;
- char buf[30];
-
- switch (map->map_valcolno)
- {
- case 0:
- case 1:
- rwval = user.mbdb_name;
- break;
-
- case 2:
- rwval = "x"; /* passwd no longer supported */
- break;
-
- case 3:
- (void) sm_snprintf(buf, sizeof(buf), "%d",
- (int) user.mbdb_uid);
- rwval = buf;
- break;
-
- case 4:
- (void) sm_snprintf(buf, sizeof(buf), "%d",
- (int) user.mbdb_gid);
- rwval = buf;
- break;
-
- case 5:
- rwval = user.mbdb_fullname;
- break;
-
- case 6:
- rwval = user.mbdb_homedir;
- break;
-
- case 7:
- rwval = user.mbdb_shell;
- break;
- default:
- syserr("user_map %s: bogus field %d",
- map->map_mname, map->map_valcolno);
- return NULL;
- }
- return map_rewrite(map, rwval, strlen(rwval), av);
- }
-}
-/*
-** Program map type.
-**
-** This provides access to arbitrary programs. It should be used
-** only very sparingly, since there is no way to bound the cost
-** of invoking an arbitrary program.
-*/
-
-char *
-prog_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- int i;
- int save_errno;
- int fd;
- int status;
- auto pid_t pid;
- register char *p;
- char *rval;
- char *argv[MAXPV + 1];
- char buf[MAXLINE];
-
- if (tTd(38, 20))
- sm_dprintf("prog_map_lookup(%s, %s) %s\n",
- map->map_mname, name, map->map_file);
-
- i = 0;
- argv[i++] = map->map_file;
- if (map->map_rebuild != NULL)
- {
- (void) sm_strlcpy(buf, map->map_rebuild, sizeof(buf));
- for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t"))
- {
- if (i >= MAXPV - 1)
- break;
- argv[i++] = p;
- }
- }
- argv[i++] = name;
- argv[i] = NULL;
- if (tTd(38, 21))
- {
- sm_dprintf("prog_open:");
- for (i = 0; argv[i] != NULL; i++)
- sm_dprintf(" %s", argv[i]);
- sm_dprintf("\n");
- }
- (void) sm_blocksignal(SIGCHLD);
- pid = prog_open(argv, &fd, CurEnv);
- if (pid < 0)
- {
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("prog_map_lookup(%s) failed (%s) -- closing",
- map->map_mname, sm_errstring(errno));
- else if (tTd(38, 9))
- sm_dprintf("prog_map_lookup(%s) failed (%s) -- closing",
- map->map_mname, sm_errstring(errno));
- map->map_mflags &= ~(MF_VALID|MF_OPEN);
- *statp = EX_OSFILE;
- return NULL;
- }
- i = read(fd, buf, sizeof(buf) - 1);
- if (i < 0)
- {
- syserr("prog_map_lookup(%s): read error %s",
- map->map_mname, sm_errstring(errno));
- rval = NULL;
- }
- else if (i == 0)
- {
- if (tTd(38, 20))
- sm_dprintf("prog_map_lookup(%s): empty answer\n",
- map->map_mname);
- rval = NULL;
- }
- else
- {
- buf[i] = '\0';
- p = strchr(buf, '\n');
- if (p != NULL)
- *p = '\0';
-
- /* collect the return value */
- if (bitset(MF_MATCHONLY, map->map_mflags))
- rval = map_rewrite(map, name, strlen(name), NULL);
- else
- rval = map_rewrite(map, buf, strlen(buf), av);
-
- /* now flush any additional output */
- while ((i = read(fd, buf, sizeof(buf))) > 0)
- continue;
- }
-
- /* wait for the process to terminate */
- (void) close(fd);
- status = waitfor(pid);
- save_errno = errno;
- (void) sm_releasesignal(SIGCHLD);
- errno = save_errno;
-
- if (status == -1)
- {
- syserr("prog_map_lookup(%s): wait error %s",
- map->map_mname, sm_errstring(errno));
- *statp = EX_SOFTWARE;
- rval = NULL;
- }
- else if (WIFEXITED(status))
- {
- if ((*statp = WEXITSTATUS(status)) != EX_OK)
- rval = NULL;
- }
- else
- {
- syserr("prog_map_lookup(%s): child died on signal %d",
- map->map_mname, status);
- *statp = EX_UNAVAILABLE;
- rval = NULL;
- }
- return rval;
-}
-/*
-** Sequenced map type.
-**
-** Tries each map in order until something matches, much like
-** implicit. Stores go to the first map in the list that can
-** support storing.
-**
-** This is slightly unusual in that there are two interfaces.
-** The "sequence" interface lets you stack maps arbitrarily.
-** The "switch" interface builds a sequence map by looking
-** at a system-dependent configuration file such as
-** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
-**
-** We don't need an explicit open, since all maps are
-** opened on demand.
-*/
-
-/*
-** SEQ_MAP_PARSE -- Sequenced map parsing
-*/
-
-bool
-seq_map_parse(map, ap)
- MAP *map;
- char *ap;
-{
- int maxmap;
-
- if (tTd(38, 2))
- sm_dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap);
- maxmap = 0;
- while (*ap != '\0')
- {
- register char *p;
- STAB *s;
-
- /* find beginning of map name */
- while (isascii(*ap) && isspace(*ap))
- ap++;
- for (p = ap;
- (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.';
- p++)
- continue;
- if (*p != '\0')
- *p++ = '\0';
- while (*p != '\0' && (!isascii(*p) || !isalnum(*p)))
- p++;
- if (*ap == '\0')
- {
- ap = p;
- continue;
- }
- s = stab(ap, ST_MAP, ST_FIND);
- if (s == NULL)
- {
- syserr("Sequence map %s: unknown member map %s",
- map->map_mname, ap);
- }
- else if (maxmap >= MAXMAPSTACK)
- {
- syserr("Sequence map %s: too many member maps (%d max)",
- map->map_mname, MAXMAPSTACK);
- maxmap++;
- }
- else if (maxmap < MAXMAPSTACK)
- {
- map->map_stack[maxmap++] = &s->s_map;
- }
- ap = p;
- }
- return true;
-}
-
-/*
-** SWITCH_MAP_OPEN -- open a switched map
-**
-** This looks at the system-dependent configuration and builds
-** a sequence map that does the same thing.
-**
-** Every system must define a switch_map_find routine in conf.c
-** that will return the list of service types associated with a
-** given service class.
-*/
-
-bool
-switch_map_open(map, mode)
- MAP *map;
- int mode;
-{
- int mapno;
- int nmaps;
- char *maptype[MAXMAPSTACK];
-
- if (tTd(38, 2))
- sm_dprintf("switch_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
- nmaps = switch_map_find(map->map_file, maptype, map->map_return);
- if (tTd(38, 19))
- {
- sm_dprintf("\tswitch_map_find => %d\n", nmaps);
- for (mapno = 0; mapno < nmaps; mapno++)
- sm_dprintf("\t\t%s\n", maptype[mapno]);
- }
- if (nmaps <= 0 || nmaps > MAXMAPSTACK)
- return false;
-
- for (mapno = 0; mapno < nmaps; mapno++)
- {
- register STAB *s;
- char nbuf[MAXNAME + 1];
-
- if (maptype[mapno] == NULL)
- continue;
- (void) sm_strlcpyn(nbuf, sizeof(nbuf), 3,
- map->map_mname, ".", maptype[mapno]);
- s = stab(nbuf, ST_MAP, ST_FIND);
- if (s == NULL)
- {
- syserr("Switch map %s: unknown member map %s",
- map->map_mname, nbuf);
- }
- else
- {
- map->map_stack[mapno] = &s->s_map;
- if (tTd(38, 4))
- sm_dprintf("\tmap_stack[%d] = %s:%s\n",
- mapno,
- s->s_map.map_class->map_cname,
- nbuf);
- }
- }
- return true;
-}
-
-#if 0
-/*
-** SEQ_MAP_CLOSE -- close all underlying maps
-*/
-
-void
-seq_map_close(map)
- MAP *map;
-{
- int mapno;
-
- if (tTd(38, 9))
- sm_dprintf("seq_map_close(%s)\n", map->map_mname);
-
- for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
- {
- MAP *mm = map->map_stack[mapno];
-
- if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags))
- continue;
- mm->map_mflags |= MF_CLOSING;
- mm->map_class->map_close(mm);
- mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
- }
-}
-#endif /* 0 */
-
-/*
-** SEQ_MAP_LOOKUP -- sequenced map lookup
-*/
-
-char *
-seq_map_lookup(map, key, args, pstat)
- MAP *map;
- char *key;
- char **args;
- int *pstat;
-{
- int mapno;
- int mapbit = 0x01;
- bool tempfail = false;
-
- if (tTd(38, 20))
- sm_dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key);
-
- for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++)
- {
- MAP *mm = map->map_stack[mapno];
- char *rv;
-
- if (mm == NULL)
- continue;
- if (!bitset(MF_OPEN, mm->map_mflags) &&
- !openmap(mm))
- {
- if (bitset(mapbit, map->map_return[MA_UNAVAIL]))
- {
- *pstat = EX_UNAVAILABLE;
- return NULL;
- }
- continue;
- }
- *pstat = EX_OK;
- rv = mm->map_class->map_lookup(mm, key, args, pstat);
- if (rv != NULL)
- return rv;
- if (*pstat == EX_TEMPFAIL)
- {
- if (bitset(mapbit, map->map_return[MA_TRYAGAIN]))
- return NULL;
- tempfail = true;
- }
- else if (bitset(mapbit, map->map_return[MA_NOTFOUND]))
- break;
- }
- if (tempfail)
- *pstat = EX_TEMPFAIL;
- else if (*pstat == EX_OK)
- *pstat = EX_NOTFOUND;
- return NULL;
-}
-
-/*
-** SEQ_MAP_STORE -- sequenced map store
-*/
-
-void
-seq_map_store(map, key, val)
- MAP *map;
- char *key;
- char *val;
-{
- int mapno;
-
- if (tTd(38, 12))
- sm_dprintf("seq_map_store(%s, %s, %s)\n",
- map->map_mname, key, val);
-
- for (mapno = 0; mapno < MAXMAPSTACK; mapno++)
- {
- MAP *mm = map->map_stack[mapno];
-
- if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags))
- continue;
-
- mm->map_class->map_store(mm, key, val);
- return;
- }
- syserr("seq_map_store(%s, %s, %s): no writable map",
- map->map_mname, key, val);
-}
-/*
-** NULL stubs
-*/
-
-/* ARGSUSED */
-bool
-null_map_open(map, mode)
- MAP *map;
- int mode;
-{
- return true;
-}
-
-/* ARGSUSED */
-void
-null_map_close(map)
- MAP *map;
-{
- return;
-}
-
-char *
-null_map_lookup(map, key, args, pstat)
- MAP *map;
- char *key;
- char **args;
- int *pstat;
-{
- *pstat = EX_NOTFOUND;
- return NULL;
-}
-
-/* ARGSUSED */
-void
-null_map_store(map, key, val)
- MAP *map;
- char *key;
- char *val;
-{
- return;
-}
-
-/*
-** BOGUS stubs
-*/
-
-char *
-bogus_map_lookup(map, key, args, pstat)
- MAP *map;
- char *key;
- char **args;
- int *pstat;
-{
- *pstat = EX_TEMPFAIL;
- return NULL;
-}
-
-MAPCLASS BogusMapClass =
-{
- "bogus-map", NULL, 0,
- NULL, bogus_map_lookup, null_map_store,
- null_map_open, null_map_close,
-};
-/*
-** MACRO modules
-*/
-
-char *
-macro_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- int mid;
-
- if (tTd(38, 20))
- sm_dprintf("macro_map_lookup(%s, %s)\n", map->map_mname,
- name == NULL ? "NULL" : name);
-
- if (name == NULL ||
- *name == '\0' ||
- (mid = macid(name)) == 0)
- {
- *statp = EX_CONFIG;
- return NULL;
- }
-
- if (av[1] == NULL)
- macdefine(&CurEnv->e_macro, A_PERM, mid, NULL);
- else
- macdefine(&CurEnv->e_macro, A_TEMP, mid, av[1]);
-
- *statp = EX_OK;
- return "";
-}
-/*
-** REGEX modules
-*/
-
-#if MAP_REGEX
-
-# include <regex.h>
-
-# define DEFAULT_DELIM CONDELSE
-# define END_OF_FIELDS -1
-# define ERRBUF_SIZE 80
-# define MAX_MATCH 32
-
-# define xnalloc(s) memset(xalloc(s), '\0', s);
-
-struct regex_map
-{
- regex_t *regex_pattern_buf; /* xalloc it */
- int *regex_subfields; /* move to type MAP */
- char *regex_delim; /* move to type MAP */
-};
-
-static int parse_fields __P((char *, int *, int, int));
-static char *regex_map_rewrite __P((MAP *, const char*, size_t, char **));
-
-static int
-parse_fields(s, ibuf, blen, nr_substrings)
- char *s;
- int *ibuf; /* array */
- int blen; /* number of elements in ibuf */
- int nr_substrings; /* number of substrings in the pattern */
-{
- register char *cp;
- int i = 0;
- bool lastone = false;
-
- blen--; /* for terminating END_OF_FIELDS */
- cp = s;
- do
- {
- for (;; cp++)
- {
- if (*cp == ',')
- {
- *cp = '\0';
- break;
- }
- if (*cp == '\0')
- {
- lastone = true;
- break;
- }
- }
- if (i < blen)
- {
- int val = atoi(s);
-
- if (val < 0 || val >= nr_substrings)
- {
- syserr("field (%d) out of range, only %d substrings in pattern",
- val, nr_substrings);
- return -1;
- }
- ibuf[i++] = val;
- }
- else
- {
- syserr("too many fields, %d max", blen);
- return -1;
- }
- s = ++cp;
- } while (!lastone);
- ibuf[i] = END_OF_FIELDS;
- return i;
-}
-
-bool
-regex_map_init(map, ap)
- MAP *map;
- char *ap;
-{
- int regerr;
- struct regex_map *map_p;
- register char *p;
- char *sub_param = NULL;
- int pflags;
- static char defdstr[] = { (char) DEFAULT_DELIM, '\0' };
-
- if (tTd(38, 2))
- sm_dprintf("regex_map_init: mapname '%s', args '%s'\n",
- map->map_mname, ap);
-
- pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB;
- p = ap;
- map_p = (struct regex_map *) xnalloc(sizeof(*map_p));
- map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t));
-
- for (;;)
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- switch (*++p)
- {
- case 'n': /* not */
- map->map_mflags |= MF_REGEX_NOT;
- break;
-
- case 'f': /* case sensitive */
- map->map_mflags |= MF_NOFOLDCASE;
- pflags &= ~REG_ICASE;
- break;
-
- case 'b': /* basic regular expressions */
- pflags &= ~REG_EXTENDED;
- break;
-
- case 's': /* substring match () syntax */
- sub_param = ++p;
- pflags &= ~REG_NOSUB;
- break;
-
- case 'd': /* delimiter */
- map_p->regex_delim = ++p;
- break;
-
- case 'a': /* map append */
- map->map_app = ++p;
- break;
-
- case 'm': /* matchonly */
- map->map_mflags |= MF_MATCHONLY;
- break;
-
- case 'q':
- map->map_mflags |= MF_KEEPQUOTES;
- break;
-
- case 'S':
- map->map_spacesub = *++p;
- break;
-
- case 'D':
- map->map_mflags |= MF_DEFER;
- break;
-
- }
- while (*p != '\0' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != '\0')
- *p++ = '\0';
- }
- if (tTd(38, 3))
- sm_dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags);
-
- if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0)
- {
- /* Errorhandling */
- char errbuf[ERRBUF_SIZE];
-
- (void) regerror(regerr, map_p->regex_pattern_buf,
- errbuf, sizeof(errbuf));
- syserr("pattern-compile-error: %s", errbuf);
- sm_free(map_p->regex_pattern_buf); /* XXX */
- sm_free(map_p); /* XXX */
- return false;
- }
-
- if (map->map_app != NULL)
- map->map_app = newstr(map->map_app);
- if (map_p->regex_delim != NULL)
- map_p->regex_delim = newstr(map_p->regex_delim);
- else
- map_p->regex_delim = defdstr;
-
- if (!bitset(REG_NOSUB, pflags))
- {
- /* substring matching */
- int substrings;
- int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1));
-
- substrings = map_p->regex_pattern_buf->re_nsub + 1;
-
- if (tTd(38, 3))
- sm_dprintf("regex_map_init: nr of substrings %d\n",
- substrings);
-
- if (substrings >= MAX_MATCH)
- {
- syserr("too many substrings, %d max", MAX_MATCH);
- sm_free(map_p->regex_pattern_buf); /* XXX */
- sm_free(map_p); /* XXX */
- return false;
- }
- if (sub_param != NULL && sub_param[0] != '\0')
- {
- /* optional parameter -sfields */
- if (parse_fields(sub_param, fields,
- MAX_MATCH + 1, substrings) == -1)
- return false;
- }
- else
- {
- int i;
-
- /* set default fields */
- for (i = 0; i < substrings; i++)
- fields[i] = i;
- fields[i] = END_OF_FIELDS;
- }
- map_p->regex_subfields = fields;
- if (tTd(38, 3))
- {
- int *ip;
-
- sm_dprintf("regex_map_init: subfields");
- for (ip = fields; *ip != END_OF_FIELDS; ip++)
- sm_dprintf(" %d", *ip);
- sm_dprintf("\n");
- }
- }
- map->map_db1 = (ARBPTR_T) map_p; /* dirty hack */
- return true;
-}
-
-static char *
-regex_map_rewrite(map, s, slen, av)
- MAP *map;
- const char *s;
- size_t slen;
- char **av;
-{
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, av[0], strlen(av[0]), NULL);
- else
- return map_rewrite(map, s, slen, av);
-}
-
-char *
-regex_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- int reg_res;
- struct regex_map *map_p;
- regmatch_t pmatch[MAX_MATCH];
-
- if (tTd(38, 20))
- {
- char **cpp;
-
- sm_dprintf("regex_map_lookup: key '%s'\n", name);
- for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
- sm_dprintf("regex_map_lookup: arg '%s'\n", *cpp);
- }
-
- map_p = (struct regex_map *)(map->map_db1);
- reg_res = regexec(map_p->regex_pattern_buf,
- name, MAX_MATCH, pmatch, 0);
-
- if (bitset(MF_REGEX_NOT, map->map_mflags))
- {
- /* option -n */
- if (reg_res == REG_NOMATCH)
- return regex_map_rewrite(map, "", (size_t) 0, av);
- else
- return NULL;
- }
- if (reg_res == REG_NOMATCH)
- return NULL;
-
- if (map_p->regex_subfields != NULL)
- {
- /* option -s */
- static char retbuf[MAXNAME];
- int fields[MAX_MATCH + 1];
- bool first = true;
- int anglecnt = 0, cmntcnt = 0, spacecnt = 0;
- bool quotemode = false, bslashmode = false;
- register char *dp, *sp;
- char *endp, *ldp;
- int *ip;
-
- dp = retbuf;
- ldp = retbuf + sizeof(retbuf) - 1;
-
- if (av[1] != NULL)
- {
- if (parse_fields(av[1], fields, MAX_MATCH + 1,
- (int) map_p->regex_pattern_buf->re_nsub + 1) == -1)
- {
- *statp = EX_CONFIG;
- return NULL;
- }
- ip = fields;
- }
- else
- ip = map_p->regex_subfields;
-
- for ( ; *ip != END_OF_FIELDS; ip++)
- {
- if (!first)
- {
- for (sp = map_p->regex_delim; *sp; sp++)
- {
- if (dp < ldp)
- *dp++ = *sp;
- }
- }
- else
- first = false;
-
- if (*ip >= MAX_MATCH ||
- pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0)
- continue;
-
- sp = name + pmatch[*ip].rm_so;
- endp = name + pmatch[*ip].rm_eo;
- for (; endp > sp; sp++)
- {
- if (dp < ldp)
- {
- if (bslashmode)
- {
- *dp++ = *sp;
- bslashmode = false;
- }
- else if (quotemode && *sp != '"' &&
- *sp != '\\')
- {
- *dp++ = *sp;
- }
- else switch (*dp++ = *sp)
- {
- case '\\':
- bslashmode = true;
- break;
-
- case '(':
- cmntcnt++;
- break;
-
- case ')':
- cmntcnt--;
- break;
-
- case '<':
- anglecnt++;
- break;
-
- case '>':
- anglecnt--;
- break;
-
- case ' ':
- spacecnt++;
- break;
-
- case '"':
- quotemode = !quotemode;
- break;
- }
- }
- }
- }
- if (anglecnt != 0 || cmntcnt != 0 || quotemode ||
- bslashmode || spacecnt != 0)
- {
- sm_syslog(LOG_WARNING, NOQID,
- "Warning: regex may cause prescan() failure map=%s lookup=%s",
- map->map_mname, name);
- return NULL;
- }
-
- *dp = '\0';
-
- return regex_map_rewrite(map, retbuf, strlen(retbuf), av);
- }
- return regex_map_rewrite(map, "", (size_t)0, av);
-}
-#endif /* MAP_REGEX */
-/*
-** NSD modules
-*/
-#if MAP_NSD
-
-# include <ndbm.h>
-# define _DATUM_DEFINED
-# include <ns_api.h>
-
-typedef struct ns_map_list
-{
- ns_map_t *map; /* XXX ns_ ? */
- char *mapname;
- struct ns_map_list *next;
-} ns_map_list_t;
-
-static ns_map_t *
-ns_map_t_find(mapname)
- char *mapname;
-{
- static ns_map_list_t *ns_maps = NULL;
- ns_map_list_t *ns_map;
-
- /* walk the list of maps looking for the correctly named map */
- for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next)
- {
- if (strcmp(ns_map->mapname, mapname) == 0)
- break;
- }
-
- /* if we are looking at a NULL ns_map_list_t, then create a new one */
- if (ns_map == NULL)
- {
- ns_map = (ns_map_list_t *) xalloc(sizeof(*ns_map));
- ns_map->mapname = newstr(mapname);
- ns_map->map = (ns_map_t *) xalloc(sizeof(*ns_map->map));
- memset(ns_map->map, '\0', sizeof(*ns_map->map));
- ns_map->next = ns_maps;
- ns_maps = ns_map;
- }
- return ns_map->map;
-}
-
-char *
-nsd_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- int buflen, r;
- char *p;
- ns_map_t *ns_map;
- char keybuf[MAXNAME + 1];
- char buf[MAXLINE];
-
- if (tTd(38, 20))
- sm_dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name);
-
- buflen = strlen(name);
- if (buflen > sizeof(keybuf) - 1)
- buflen = sizeof(keybuf) - 1; /* XXX simply cut off? */
- memmove(keybuf, name, buflen);
- keybuf[buflen] = '\0';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(keybuf);
-
- ns_map = ns_map_t_find(map->map_file);
- if (ns_map == NULL)
- {
- if (tTd(38, 20))
- sm_dprintf("nsd_map_t_find failed\n");
- *statp = EX_UNAVAILABLE;
- return NULL;
- }
- r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL,
- buf, sizeof(buf));
- if (r == NS_UNAVAIL || r == NS_TRYAGAIN)
- {
- *statp = EX_TEMPFAIL;
- return NULL;
- }
- if (r == NS_BADREQ
-# ifdef NS_NOPERM
- || r == NS_NOPERM
-# endif /* NS_NOPERM */
- )
- {
- *statp = EX_CONFIG;
- return NULL;
- }
- if (r != NS_SUCCESS)
- {
- *statp = EX_NOTFOUND;
- return NULL;
- }
-
- *statp = EX_OK;
-
- /* Null out trailing \n */
- if ((p = strchr(buf, '\n')) != NULL)
- *p = '\0';
-
- return map_rewrite(map, buf, strlen(buf), av);
-}
-#endif /* MAP_NSD */
-
-char *
-arith_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- long r;
- long v[2];
- bool res = false;
- bool boolres;
- static char result[16];
- char **cpp;
-
- if (tTd(38, 2))
- {
- sm_dprintf("arith_map_lookup: key '%s'\n", name);
- for (cpp = av; cpp != NULL && *cpp != NULL; cpp++)
- sm_dprintf("arith_map_lookup: arg '%s'\n", *cpp);
- }
- r = 0;
- boolres = false;
- cpp = av;
- *statp = EX_OK;
-
- /*
- ** read arguments for arith map
- ** - no check is made whether they are really numbers
- ** - just ignores args after the second
- */
-
- for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++)
- v[r++] = strtol(*cpp, NULL, 0);
-
- /* operator and (at least) two operands given? */
- if (name != NULL && r == 2)
- {
- switch (*name)
- {
- case '|':
- r = v[0] | v[1];
- break;
-
- case '&':
- r = v[0] & v[1];
- break;
-
- case '%':
- if (v[1] == 0)
- return NULL;
- r = v[0] % v[1];
- break;
- case '+':
- r = v[0] + v[1];
- break;
-
- case '-':
- r = v[0] - v[1];
- break;
-
- case '*':
- r = v[0] * v[1];
- break;
-
- case '/':
- if (v[1] == 0)
- return NULL;
- r = v[0] / v[1];
- break;
-
- case 'l':
- res = v[0] < v[1];
- boolres = true;
- break;
-
- case '=':
- res = v[0] == v[1];
- boolres = true;
- break;
-
- case 'r':
- r = v[1] - v[0] + 1;
- if (r <= 0)
- return NULL;
- r = get_random() % r + v[0];
- break;
-
- default:
- /* XXX */
- *statp = EX_CONFIG;
- if (LogLevel > 10)
- sm_syslog(LOG_WARNING, NOQID,
- "arith_map: unknown operator %c",
- isprint(*name) ? *name : '?');
- return NULL;
- }
- if (boolres)
- (void) sm_snprintf(result, sizeof(result),
- res ? "TRUE" : "FALSE");
- else
- (void) sm_snprintf(result, sizeof(result), "%ld", r);
- return result;
- }
- *statp = EX_CONFIG;
- return NULL;
-}
-
-#if SOCKETMAP
-
-# if NETINET || NETINET6
-# include <arpa/inet.h>
-# endif /* NETINET || NETINET6 */
-
-# define socket_map_next map_stack[0]
-
-/*
-** SOCKET_MAP_OPEN -- open socket table
-*/
-
-bool
-socket_map_open(map, mode)
- MAP *map;
- int mode;
-{
- STAB *s;
- int sock = 0;
- SOCKADDR_LEN_T addrlen = 0;
- int addrno = 0;
- int save_errno;
- char *p;
- char *colon;
- char *at;
- struct hostent *hp = NULL;
- SOCKADDR addr;
-
- if (tTd(38, 2))
- sm_dprintf("socket_map_open(%s, %s, %d)\n",
- map->map_mname, map->map_file, mode);
-
- mode &= O_ACCMODE;
-
- /* sendmail doesn't have the ability to write to SOCKET (yet) */
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
- errno = SM_EMAPCANTWRITE;
- return false;
- }
-
- if (*map->map_file == '\0')
- {
- syserr("socket map \"%s\": empty or missing socket information",
- map->map_mname);
- return false;
- }
-
- s = socket_map_findconn(map->map_file);
- if (s->s_socketmap != NULL)
- {
- /* Copy open connection */
- map->map_db1 = s->s_socketmap->map_db1;
-
- /* Add this map as head of linked list */
- map->socket_map_next = s->s_socketmap;
- s->s_socketmap = map;
-
- if (tTd(38, 2))
- sm_dprintf("using cached connection\n");
- return true;
- }
-
- if (tTd(38, 2))
- sm_dprintf("opening new connection\n");
-
- /* following code is ripped from milter.c */
- /* XXX It should be put in a library... */
-
- /* protocol:filename or protocol:port@host */
- memset(&addr, '\0', sizeof(addr));
- p = map->map_file;
- colon = strchr(p, ':');
- if (colon != NULL)
- {
- *colon = '\0';
-
- if (*p == '\0')
- {
-# if NETUNIX
- /* default to AF_UNIX */
- addr.sa.sa_family = AF_UNIX;
-# else /* NETUNIX */
-# if NETINET
- /* default to AF_INET */
- addr.sa.sa_family = AF_INET;
-# else /* NETINET */
-# if NETINET6
- /* default to AF_INET6 */
- addr.sa.sa_family = AF_INET6;
-# else /* NETINET6 */
- /* no protocols available */
- syserr("socket map \"%s\": no valid socket protocols available",
- map->map_mname);
- return false;
-# endif /* NETINET6 */
-# endif /* NETINET */
-# endif /* NETUNIX */
- }
-# if NETUNIX
- else if (sm_strcasecmp(p, "unix") == 0 ||
- sm_strcasecmp(p, "local") == 0)
- addr.sa.sa_family = AF_UNIX;
-# endif /* NETUNIX */
-# if NETINET
- else if (sm_strcasecmp(p, "inet") == 0)
- addr.sa.sa_family = AF_INET;
-# endif /* NETINET */
-# if NETINET6
- else if (sm_strcasecmp(p, "inet6") == 0)
- addr.sa.sa_family = AF_INET6;
-# endif /* NETINET6 */
- else
- {
-# ifdef EPROTONOSUPPORT
- errno = EPROTONOSUPPORT;
-# else /* EPROTONOSUPPORT */
- errno = EINVAL;
-# endif /* EPROTONOSUPPORT */
- syserr("socket map \"%s\": unknown socket type %s",
- map->map_mname, p);
- return false;
- }
- *colon++ = ':';
- }
- else
- {
- colon = p;
-#if NETUNIX
- /* default to AF_UNIX */
- addr.sa.sa_family = AF_UNIX;
-#else /* NETUNIX */
-# if NETINET
- /* default to AF_INET */
- addr.sa.sa_family = AF_INET;
-# else /* NETINET */
-# if NETINET6
- /* default to AF_INET6 */
- addr.sa.sa_family = AF_INET6;
-# else /* NETINET6 */
- syserr("socket map \"%s\": unknown socket type %s",
- map->map_mname, p);
- return false;
-# endif /* NETINET6 */
-# endif /* NETINET */
-#endif /* NETUNIX */
- }
-
-# if NETUNIX
- if (addr.sa.sa_family == AF_UNIX)
- {
- long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
-
- at = colon;
- if (strlen(colon) >= sizeof(addr.sunix.sun_path))
- {
- syserr("socket map \"%s\": local socket name %s too long",
- map->map_mname, colon);
- return false;
- }
- errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
- S_IRUSR|S_IWUSR, NULL);
-
- if (errno != 0)
- {
- /* if not safe, don't create */
- syserr("socket map \"%s\": local socket name %s unsafe",
- map->map_mname, colon);
- return false;
- }
-
- (void) sm_strlcpy(addr.sunix.sun_path, colon,
- sizeof(addr.sunix.sun_path));
- addrlen = sizeof(struct sockaddr_un);
- }
- else
-# endif /* NETUNIX */
-# if NETINET || NETINET6
- if (false
-# if NETINET
- || addr.sa.sa_family == AF_INET
-# endif /* NETINET */
-# if NETINET6
- || addr.sa.sa_family == AF_INET6
-# endif /* NETINET6 */
- )
- {
- unsigned short port;
-
- /* Parse port@host */
- at = strchr(colon, '@');
- if (at == NULL)
- {
- syserr("socket map \"%s\": bad address %s (expected port@host)",
- map->map_mname, colon);
- return false;
- }
- *at = '\0';
- if (isascii(*colon) && isdigit(*colon))
- port = htons((unsigned short) atoi(colon));
- else
- {
-# ifdef NO_GETSERVBYNAME
- syserr("socket map \"%s\": invalid port number %s",
- map->map_mname, colon);
- return false;
-# else /* NO_GETSERVBYNAME */
- register struct servent *sp;
-
- sp = getservbyname(colon, "tcp");
- if (sp == NULL)
- {
- syserr("socket map \"%s\": unknown port name %s",
- map->map_mname, colon);
- return false;
- }
- port = sp->s_port;
-# endif /* NO_GETSERVBYNAME */
- }
- *at++ = '@';
- if (*at == '[')
- {
- char *end;
-
- end = strchr(at, ']');
- if (end != NULL)
- {
- bool found = false;
-# if NETINET
- unsigned long hid = INADDR_NONE;
-# endif /* NETINET */
-# if NETINET6
- struct sockaddr_in6 hid6;
-# endif /* NETINET6 */
-
- *end = '\0';
-# if NETINET
- if (addr.sa.sa_family == AF_INET &&
- (hid = inet_addr(&at[1])) != INADDR_NONE)
- {
- addr.sin.sin_addr.s_addr = hid;
- addr.sin.sin_port = port;
- found = true;
- }
-# endif /* NETINET */
-# if NETINET6
- (void) memset(&hid6, '\0', sizeof(hid6));
- if (addr.sa.sa_family == AF_INET6 &&
- anynet_pton(AF_INET6, &at[1],
- &hid6.sin6_addr) == 1)
- {
- addr.sin6.sin6_addr = hid6.sin6_addr;
- addr.sin6.sin6_port = port;
- found = true;
- }
-# endif /* NETINET6 */
- *end = ']';
- if (!found)
- {
- syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
- map->map_mname, at);
- return false;
- }
- }
- else
- {
- syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"",
- map->map_mname, at);
- return false;
- }
- }
- else
- {
- hp = sm_gethostbyname(at, addr.sa.sa_family);
- if (hp == NULL)
- {
- syserr("socket map \"%s\": Unknown host name %s",
- map->map_mname, at);
- return false;
- }
- addr.sa.sa_family = hp->h_addrtype;
- switch (hp->h_addrtype)
- {
-# if NETINET
- case AF_INET:
- memmove(&addr.sin.sin_addr,
- hp->h_addr, INADDRSZ);
- addr.sin.sin_port = port;
- addrlen = sizeof(struct sockaddr_in);
- addrno = 1;
- break;
-# endif /* NETINET */
-
-# if NETINET6
- case AF_INET6:
- memmove(&addr.sin6.sin6_addr,
- hp->h_addr, IN6ADDRSZ);
- addr.sin6.sin6_port = port;
- addrlen = sizeof(struct sockaddr_in6);
- addrno = 1;
- break;
-# endif /* NETINET6 */
-
- default:
- syserr("socket map \"%s\": Unknown protocol for %s (%d)",
- map->map_mname, at, hp->h_addrtype);
-# if NETINET6
- freehostent(hp);
-# endif /* NETINET6 */
- return false;
- }
- }
- }
- else
-# endif /* NETINET || NETINET6 */
- {
- syserr("socket map \"%s\": unknown socket protocol",
- map->map_mname);
- return false;
- }
-
- /* nope, actually connecting */
- for (;;)
- {
- sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
- if (sock < 0)
- {
- save_errno = errno;
- if (tTd(38, 5))
- sm_dprintf("socket map \"%s\": error creating socket: %s\n",
- map->map_mname,
- sm_errstring(save_errno));
-# if NETINET6
- if (hp != NULL)
- freehostent(hp);
-# endif /* NETINET6 */
- return false;
- }
-
- if (connect(sock, (struct sockaddr *) &addr, addrlen) >= 0)
- break;
-
- /* couldn't connect.... try next address */
- save_errno = errno;
- p = CurHostName;
- CurHostName = at;
- if (tTd(38, 5))
- sm_dprintf("socket_open (%s): open %s failed: %s\n",
- map->map_mname, at, sm_errstring(save_errno));
- CurHostName = p;
- (void) close(sock);
-
- /* try next address */
- if (hp != NULL && hp->h_addr_list[addrno] != NULL)
- {
- switch (addr.sa.sa_family)
- {
-# if NETINET
- case AF_INET:
- memmove(&addr.sin.sin_addr,
- hp->h_addr_list[addrno++],
- INADDRSZ);
- break;
-# endif /* NETINET */
-
-# if NETINET6
- case AF_INET6:
- memmove(&addr.sin6.sin6_addr,
- hp->h_addr_list[addrno++],
- IN6ADDRSZ);
- break;
-# endif /* NETINET6 */
-
- default:
- if (tTd(38, 5))
- sm_dprintf("socket map \"%s\": Unknown protocol for %s (%d)\n",
- map->map_mname, at,
- hp->h_addrtype);
-# if NETINET6
- freehostent(hp);
-# endif /* NETINET6 */
- return false;
- }
- continue;
- }
- p = CurHostName;
- CurHostName = at;
- if (tTd(38, 5))
- sm_dprintf("socket map \"%s\": error connecting to socket map: %s\n",
- map->map_mname, sm_errstring(save_errno));
- CurHostName = p;
-# if NETINET6
- if (hp != NULL)
- freehostent(hp);
-# endif /* NETINET6 */
- return false;
- }
-# if NETINET6
- if (hp != NULL)
- {
- freehostent(hp);
- hp = NULL;
- }
-# endif /* NETINET6 */
- if ((map->map_db1 = (ARBPTR_T) sm_io_open(SmFtStdiofd,
- SM_TIME_DEFAULT,
- (void *) &sock,
- SM_IO_RDWR,
- NULL)) == NULL)
- {
- close(sock);
- if (tTd(38, 2))
- sm_dprintf("socket_open (%s): failed to create stream: %s\n",
- map->map_mname, sm_errstring(errno));
- return false;
- }
-
- /* Save connection for reuse */
- s->s_socketmap = map;
- return true;
-}
-
-/*
-** SOCKET_MAP_FINDCONN -- find a SOCKET connection to the server
-**
-** Cache SOCKET connections based on the connection specifier
-** and PID so we don't have multiple connections open to
-** the same server for different maps. Need a separate connection
-** per PID since a parent process may close the map before the
-** child is done with it.
-**
-** Parameters:
-** conn -- SOCKET map connection specifier
-**
-** Returns:
-** Symbol table entry for the SOCKET connection.
-*/
-
-static STAB *
-socket_map_findconn(conn)
- const char *conn;
-{
- char *nbuf;
- STAB *SM_NONVOLATILE s = NULL;
-
- nbuf = sm_stringf_x("%s%c%d", conn, CONDELSE, (int) CurrentPid);
- SM_TRY
- s = stab(nbuf, ST_SOCKETMAP, ST_ENTER);
- SM_FINALLY
- sm_free(nbuf);
- SM_END_TRY
- return s;
-}
-
-/*
-** SOCKET_MAP_CLOSE -- close the socket
-*/
-
-void
-socket_map_close(map)
- MAP *map;
-{
- STAB *s;
- MAP *smap;
-
- if (tTd(38, 20))
- sm_dprintf("socket_map_close(%s), pid=%ld\n", map->map_file,
- (long) CurrentPid);
-
- /* Check if already closed */
- if (map->map_db1 == NULL)
- {
- if (tTd(38, 20))
- sm_dprintf("socket_map_close(%s) already closed\n",
- map->map_file);
- return;
- }
- sm_io_close((SM_FILE_T *)map->map_db1, SM_TIME_DEFAULT);
-
- /* Mark all the maps that share the connection as closed */
- s = socket_map_findconn(map->map_file);
- smap = s->s_socketmap;
- while (smap != NULL)
- {
- MAP *next;
-
- if (tTd(38, 2) && smap != map)
- sm_dprintf("socket_map_close(%s): closed %s (shared SOCKET connection)\n",
- map->map_mname, smap->map_mname);
-
- smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- smap->map_db1 = NULL;
- next = smap->socket_map_next;
- smap->socket_map_next = NULL;
- smap = next;
- }
- s->s_socketmap = NULL;
-}
-
-/*
-** SOCKET_MAP_LOOKUP -- look up a datum in a SOCKET table
-*/
-
-char *
-socket_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
-{
- unsigned int nettolen, replylen, recvlen;
- char *replybuf, *rval, *value, *status, *key;
- SM_FILE_T *f;
- char keybuf[MAXNAME + 1];
-
- replybuf = NULL;
- rval = NULL;
- f = (SM_FILE_T *)map->map_db1;
- if (tTd(38, 20))
- sm_dprintf("socket_map_lookup(%s, %s) %s\n",
- map->map_mname, name, map->map_file);
-
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- {
- nettolen = strlen(name);
- if (nettolen > sizeof(keybuf) - 1)
- nettolen = sizeof(keybuf) - 1;
- memmove(keybuf, name, nettolen);
- keybuf[nettolen] = '\0';
- makelower(keybuf);
- key = keybuf;
- }
- else
- key = name;
-
- nettolen = strlen(map->map_mname) + 1 + strlen(key);
- SM_ASSERT(nettolen > strlen(map->map_mname));
- SM_ASSERT(nettolen > strlen(key));
- if ((sm_io_fprintf(f, SM_TIME_DEFAULT, "%u:%s %s,",
- nettolen, map->map_mname, key) == SM_IO_EOF) ||
- (sm_io_flush(f, SM_TIME_DEFAULT) != 0) ||
- (sm_io_error(f)))
- {
- syserr("451 4.3.0 socket_map_lookup(%s): failed to send lookup request",
- map->map_mname);
- *statp = EX_TEMPFAIL;
- goto errcl;
- }
-
- if (sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen) != 1)
- {
- syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply",
- map->map_mname);
- *statp = EX_TEMPFAIL;
- goto errcl;
- }
- if (replylen > SOCKETMAP_MAXL)
- {
- syserr("451 4.3.0 socket_map_lookup(%s): reply too long: %u",
- map->map_mname, replylen);
- *statp = EX_TEMPFAIL;
- goto errcl;
- }
- if (sm_io_getc(f, SM_TIME_DEFAULT) != ':')
- {
- syserr("451 4.3.0 socket_map_lookup(%s): missing ':' in reply",
- map->map_mname);
- *statp = EX_TEMPFAIL;
- goto error;
- }
-
- replybuf = (char *) sm_malloc(replylen + 1);
- if (replybuf == NULL)
- {
- syserr("451 4.3.0 socket_map_lookup(%s): can't allocate %u bytes",
- map->map_mname, replylen + 1);
- *statp = EX_OSERR;
- goto error;
- }
-
- recvlen = sm_io_read(f, SM_TIME_DEFAULT, replybuf, replylen);
- if (recvlen < replylen)
- {
- syserr("451 4.3.0 socket_map_lookup(%s): received only %u of %u reply characters",
- map->map_mname, recvlen, replylen);
- *statp = EX_TEMPFAIL;
- goto errcl;
- }
- if (sm_io_getc(f, SM_TIME_DEFAULT) != ',')
- {
- syserr("451 4.3.0 socket_map_lookup(%s): missing ',' in reply",
- map->map_mname);
- *statp = EX_TEMPFAIL;
- goto errcl;
- }
- status = replybuf;
- replybuf[recvlen] = '\0';
- value = strchr(replybuf, ' ');
- if (value != NULL)
- {
- *value = '\0';
- value++;
- }
- if (strcmp(status, "OK") == 0)
- {
- *statp = EX_OK;
-
- /* collect the return value */
- if (bitset(MF_MATCHONLY, map->map_mflags))
- rval = map_rewrite(map, key, strlen(key), NULL);
- else
- rval = map_rewrite(map, value, strlen(value), av);
- }
- else if (strcmp(status, "NOTFOUND") == 0)
- {
- *statp = EX_NOTFOUND;
- if (tTd(38, 20))
- sm_dprintf("socket_map_lookup(%s): %s not found\n",
- map->map_mname, key);
- }
- else
- {
- if (tTd(38, 5))
- sm_dprintf("socket_map_lookup(%s, %s): server returned error: type=%s, reason=%s\n",
- map->map_mname, key, status,
- value ? value : "");
- if ((strcmp(status, "TEMP") == 0) ||
- (strcmp(status, "TIMEOUT") == 0))
- *statp = EX_TEMPFAIL;
- else if(strcmp(status, "PERM") == 0)
- *statp = EX_UNAVAILABLE;
- else
- *statp = EX_PROTOCOL;
- }
-
- if (replybuf != NULL)
- sm_free(replybuf);
- return rval;
-
- errcl:
- socket_map_close(map);
- error:
- if (replybuf != NULL)
- sm_free(replybuf);
- return rval;
-}
-#endif /* SOCKETMAP */
OpenPOWER on IntegriCloud