map.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:144k
- /*
- * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
- * All rights reserved.
- * Copyright (c) 1992, 1995-1997 Eric P. Allman. All rights reserved.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * By using this file, you agree to the terms and conditions set
- * forth in the LICENSE file which can be found at the top level of
- * the sendmail distribution.
- *
- */
- #ifndef lint
- static char id[] = "@(#)$Id: map.c,v 8.398 1999/12/09 19:06:59 gshapiro Exp $";
- #endif /* ! lint */
- #include <sendmail.h>
- #ifdef NDBM
- # include <ndbm.h>
- # ifdef R_FIRST
- ERROR README: You are running the Berkeley DB version of ndbm.h. See
- ERROR README: the README file about tweaking Berkeley DB so it can
- ERROR README: coexist with NDBM, or delete -DNDBM from the Makefile
- ERROR README: and use -DNEWDB instead.
- # endif /* R_FIRST */
- #endif /* NDBM */
- #ifdef NEWDB
- # include <db.h>
- # ifndef DB_VERSION_MAJOR
- # define DB_VERSION_MAJOR 1
- # endif /* ! DB_VERSION_MAJOR */
- #endif /* NEWDB */
- #ifdef NIS
- struct dom_binding; /* forward reference needed on IRIX */
- # include <rpcsvc/ypclnt.h>
- # ifdef NDBM
- # define NDBM_YP_COMPAT /* create YP-compatible NDBM files */
- # endif /* NDBM */
- #endif /* NIS */
- #ifdef NEWDB
- # if DB_VERSION_MAJOR < 2
- static bool db_map_open __P((MAP *, int, char *, DBTYPE, const void *));
- # endif /* DB_VERSION_MAJOR < 2 */
- # if DB_VERSION_MAJOR == 2
- static bool db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *));
- # endif /* DB_VERSION_MAJOR == 2 */
- # if DB_VERSION_MAJOR > 2
- static bool db_map_open __P((MAP *, int, char *, DBTYPE, void **));
- # endif /* DB_VERSION_MAJOR > 2 */
- #endif /* NEWDB */
- static bool extract_canonname __P((char *, char *, char[], int));
- #ifdef LDAPMAP
- static void ldapmap_clear __P((LDAPMAP_STRUCT *));
- static STAB *ldapmap_findconn __P((LDAPMAP_STRUCT *));
- static int ldapmap_geterrno __P((LDAP *));
- static void ldapmap_setopts __P((LDAP *, LDAPMAP_STRUCT *));
- static bool ldapmap_start __P((MAP *));
- static void ldaptimeout __P((int));
- #endif /* LDAPMAP */
- static void map_close __P((STAB *, int));
- static void map_init __P((STAB *, int));
- #ifdef NISPLUS
- static bool nisplus_getcanonname __P((char *, int, int *));
- #endif /* NISPLUS */
- #ifdef NIS
- static bool nis_getcanonname __P((char *, int, int *));
- #endif /* NIS */
- #if NETINFO
- static bool ni_getcanonname __P((char *, int, int *));
- #endif /* NETINFO */
- static bool text_getcanonname __P((char *, int, int *));
- /*
- ** MAP.C -- implementations for various map classes.
- **
- ** Each map class implements a series of functions:
- **
- ** bool map_parse(MAP *map, char *args)
- ** Parse the arguments from the config file. Return TRUE
- ** if they were ok, FALSE otherwise. Fill in map with the
- ** values.
- **
- ** char *map_lookup(MAP *map, char *key, char **args, int *pstat)
- ** Look up the key in the given map. If found, do any
- ** rewriting the map wants (including "args" if desired)
- ** and return the value. Set *pstat to the appropriate status
- ** on error and return NULL. Args will be NULL if called
- ** from the alias routines, although this should probably
- ** not be relied upon. It is suggested you call map_rewrite
- ** to return the results -- it takes care of null termination
- ** and uses a dynamically expanded buffer as needed.
- **
- ** void map_store(MAP *map, char *key, char *value)
- ** Store the key:value pair in the map.
- **
- ** bool map_open(MAP *map, int mode)
- ** Open the map for the indicated mode. Mode should
- ** be either O_RDONLY or O_RDWR. Return TRUE if it
- ** was opened successfully, FALSE otherwise. If the open
- ** failed an the MF_OPTIONAL flag is not set, it should
- ** also print an error. If the MF_ALIAS bit is set
- ** and this map class understands the @:@ convention, it
- ** should call aliaswait() before returning.
- **
- ** void map_close(MAP *map)
- ** Close the map.
- **
- ** This file also includes the implementation for getcanonname.
- ** It is currently implemented in a pretty ad-hoc manner; it ought
- ** to be more properly integrated into the map structure.
- */
- #define DBMMODE 0644
- #ifndef EX_NOTFOUND
- # define EX_NOTFOUND EX_NOHOST
- #endif /* ! EX_NOTFOUND */
- #if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL
- # define LOCK_ON_OPEN 1 /* we can open/create a locked file */
- #else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
- # define LOCK_ON_OPEN 0 /* no such luck -- bend over backwards */
- #endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */
- #ifndef O_ACCMODE
- # define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR)
- #endif /* ! O_ACCMODE */
- /*
- ** MAP_PARSEARGS -- parse config line arguments for database lookup
- **
- ** This is a generic version of the map_parse method.
- **
- ** Parameters:
- ** map -- the map being initialized.
- ** ap -- a pointer to the args on the config line.
- **
- ** Returns:
- ** TRUE -- if everything parsed OK.
- ** FALSE -- otherwise.
- **
- ** Side Effects:
- ** null terminates the filename; stores it in map
- */
- bool
- map_parseargs(map, ap)
- MAP *map;
- char *ap;
- {
- register char *p = ap;
- /*
- ** there is no check whether there is really an argument,
- ** but that's not important enough to warrant extra code
- */
- map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL;
- map->map_spacesub = SpaceSub; /* default value */
- for (;;)
- {
- while (isascii(*p) && isspace(*p))
- p++;
- if (*p != '-')
- break;
- switch (*++p)
- {
- case 'N':
- map->map_mflags |= MF_INCLNULL;
- map->map_mflags &= ~MF_TRY0NULL;
- break;
- case 'O':
- map->map_mflags &= ~MF_TRY1NULL;
- break;
- case 'o':
- map->map_mflags |= MF_OPTIONAL;
- break;
- case 'f':
- map->map_mflags |= MF_NOFOLDCASE;
- break;
- case 'm':
- map->map_mflags |= MF_MATCHONLY;
- break;
- case 'A':
- map->map_mflags |= MF_APPEND;
- break;
- case 'q':
- map->map_mflags |= MF_KEEPQUOTES;
- break;
- case 'a':
- map->map_app = ++p;
- break;
- case 'T':
- map->map_tapp = ++p;
- break;
- case 'k':
- while (isascii(*++p) && isspace(*p))
- continue;
- map->map_keycolnm = p;
- break;
- case 'v':
- while (isascii(*++p) && isspace(*p))
- continue;
- map->map_valcolnm = p;
- break;
- case 'z':
- if (*++p != '\')
- map->map_coldelim = *p;
- else
- {
- switch (*++p)
- {
- case 'n':
- map->map_coldelim = 'n';
- break;
- case 't':
- map->map_coldelim = 't';
- break;
- default:
- map->map_coldelim = '\';
- }
- }
- break;
- case 't':
- map->map_mflags |= MF_NODEFER;
- break;
- case 'S':
- map->map_spacesub = *++p;
- break;
- case 'D':
- map->map_mflags |= MF_DEFER;
- break;
- default:
- syserr("Illegal option %c map %s", *p, map->map_mname);
- break;
- }
- while (*p != ' ' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != ' ')
- *p++ = ' ';
- }
- 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 != ' ')
- {
- map->map_file = p;
- while (*p != ' ' && !(isascii(*p) && isspace(*p)))
- p++;
- if (*p != ' ')
- *p++ = ' ';
- map->map_file = newstr(map->map_file);
- }
- while (*p != ' ' && isascii(*p) && isspace(*p))
- p++;
- if (*p != ' ')
- map->map_rebuild = newstr(p);
- if (map->map_file == NULL &&
- !bitset(MCF_OPTFILE, map->map_class->map_cflags))
- {
- syserr("No file name for %s map %s",
- map->map_class->map_cname, map->map_mname);
- return FALSE;
- }
- return TRUE;
- }
- /*
- ** MAP_REWRITE -- rewrite a database key, interpolating %n indications.
- **
- ** It also adds the map_app string. It can be used as a utility
- ** in the map_lookup method.
- **
- ** Parameters:
- ** map -- the map that causes this.
- ** s -- the string to rewrite, NOT necessarily null terminated.
- ** slen -- the length of s.
- ** av -- arguments to interpolate into buf.
- **
- ** Returns:
- ** Pointer to rewritten result. This is static data that
- ** should be copied if it is to be saved!
- **
- ** Side Effects:
- ** none.
- */
- char *
- map_rewrite(map, s, slen, av)
- register MAP *map;
- register const char *s;
- size_t slen;
- char **av;
- {
- register char *bp;
- register char c;
- char **avp;
- register char *ap;
- size_t l;
- size_t len;
- static size_t buflen = 0;
- static char *buf = NULL;
- if (tTd(39, 1))
- {
- dprintf("map_rewrite(%.*s), av =", (int)slen, s);
- if (av == NULL)
- dprintf(" (nullv)");
- else
- {
- for (avp = av; *avp != NULL; avp++)
- dprintf("nt%s", *avp);
- }
- dprintf("n");
- }
- /* count expected size of output (can safely overestimate) */
- l = len = slen;
- if (av != NULL)
- {
- const char *sp = s;
- while (l-- > 0 && (c = *sp++) != ' ')
- {
- if (c != '%')
- continue;
- if (l-- <= 0)
- break;
- c = *sp++;
- if (!(isascii(c) && isdigit(c)))
- continue;
- for (avp = av; --c >= '0' && *avp != NULL; avp++)
- continue;
- if (*avp == NULL)
- continue;
- len += strlen(*avp);
- }
- }
- if (map->map_app != NULL)
- len += strlen(map->map_app);
- if (buflen < ++len)
- {
- /* need to malloc additional space */
- buflen = len;
- if (buf != NULL)
- free(buf);
- buf = xalloc(buflen);
- }
- bp = buf;
- if (av == NULL)
- {
- memmove(bp, s, slen);
- bp += slen;
- /* assert(len > slen); */
- len -= slen;
- }
- else
- {
- while (slen-- > 0 && (c = *s++) != ' ')
- {
- if (c != '%')
- {
- pushc:
- if (--len <= 0)
- break;
- *bp++ = c;
- continue;
- }
- if (slen-- <= 0 || (c = *s++) == ' ')
- c = '%';
- if (c == '%')
- goto pushc;
- if (!(isascii(c) && isdigit(c)))
- {
- *bp++ = '%';
- --len;
- goto pushc;
- }
- for (avp = av; --c >= '0' && *avp != NULL; avp++)
- continue;
- if (*avp == NULL)
- continue;
- /* transliterate argument into output string */
- for (ap = *avp; (c = *ap++) != ' ' && len > 0; --len)
- *bp++ = c;
- }
- }
- if (map->map_app != NULL && len > 0)
- (void) strlcpy(bp, map->map_app, len);
- else
- *bp = ' ';
- if (tTd(39, 1))
- dprintf("map_rewrite => %sn", buf);
- return buf;
- }
- /*
- ** INITMAPS -- rebuild alias maps
- **
- ** Parameters:
- ** none.
- **
- ** Returns:
- ** none.
- */
- void
- initmaps()
- {
- #if XDEBUG
- checkfd012("entering initmaps");
- #endif /* XDEBUG */
- stabapply(map_init, 0);
- #if XDEBUG
- checkfd012("exiting initmaps");
- #endif /* XDEBUG */
- }
- /*
- ** MAP_INIT -- rebuild a map
- **
- ** Parameters:
- ** s -- STAB entry: if map: try to rebuild
- ** unused -- unused variable
- **
- ** Returns:
- ** none.
- **
- ** Side Effects:
- ** will close already open rebuildable map.
- */
- /* ARGSUSED1 */
- static void
- map_init(s, unused)
- register STAB *s;
- int unused;
- {
- register MAP *map;
- /* has to be a map */
- if (s->s_type != ST_MAP)
- return;
- map = &s->s_map;
- if (!bitset(MF_VALID, map->map_mflags))
- return;
- if (tTd(38, 2))
- dprintf("map_init(%s:%s, %s)n",
- map->map_class->map_cname == NULL ? "NULL" :
- map->map_class->map_cname,
- map->map_mname == NULL ? "NULL" : map->map_mname,
- map->map_file == NULL ? "NULL" : map->map_file);
- if (!bitset(MF_ALIAS, map->map_mflags) ||
- !bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
- {
- if (tTd(38, 3))
- dprintf("tnot rebuildablen");
- return;
- }
- /* if already open, close it (for nested open) */
- if (bitset(MF_OPEN, map->map_mflags))
- {
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- }
- (void) rebuildaliases(map, FALSE);
- return;
- }
- /*
- ** OPENMAP -- open a map
- **
- ** Parameters:
- ** map -- map to open (it must not be open).
- **
- ** Returns:
- ** whether open succeeded.
- **
- */
- bool
- openmap(map)
- MAP *map;
- {
- bool restore = FALSE;
- bool savehold = HoldErrs;
- bool savequick = QuickAbort;
- int saveerrors = Errors;
- if (!bitset(MF_VALID, map->map_mflags))
- return FALSE;
- /* better safe than sorry... */
- if (bitset(MF_OPEN, map->map_mflags))
- return TRUE;
- /* Don't send a map open error out via SMTP */
- if ((OnlyOneError || QuickAbort) &&
- (OpMode == MD_SMTP || OpMode == MD_DAEMON))
- {
- restore = TRUE;
- HoldErrs = TRUE;
- QuickAbort = FALSE;
- }
- errno = 0;
- if (map->map_class->map_open(map, O_RDONLY))
- {
- if (tTd(38, 4))
- dprintf("openmap()t%s:%s %s: validn",
- map->map_class->map_cname == NULL ? "NULL" :
- map->map_class->map_cname,
- map->map_mname == NULL ? "NULL" :
- map->map_mname,
- map->map_file == NULL ? "NULL" :
- map->map_file);
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- }
- else
- {
- if (tTd(38, 4))
- dprintf("openmap()t%s:%s %s: invalid%s%sn",
- map->map_class->map_cname == NULL ? "NULL" :
- map->map_class->map_cname,
- map->map_mname == NULL ? "NULL" :
- map->map_mname,
- map->map_file == NULL ? "NULL" :
- map->map_file,
- errno == 0 ? "" : ": ",
- errno == 0 ? "" : errstring(errno));
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- extern MAPCLASS BogusMapClass;
- map->map_class = &BogusMapClass;
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- }
- 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:
- ** none
- **
- ** Returns:
- ** none.
- */
- void
- closemaps()
- {
- stabapply(map_close, 0);
- }
- /*
- ** MAP_CLOSE -- close a map opened by the current pid.
- **
- ** Parameters:
- ** s -- STAB entry: if map: try to open
- ** second parameter is unused (required by stabapply())
- **
- ** Returns:
- ** none.
- */
- /* ARGSUSED1 */
- static void
- map_close(s, unused)
- register STAB *s;
- int unused;
- {
- MAP *map;
- if (s->s_type != ST_MAP)
- return;
- map = &s->s_map;
- if (!bitset(MF_VALID, map->map_mflags) ||
- !bitset(MF_OPEN, map->map_mflags) ||
- map->map_pid != getpid())
- return;
- if (tTd(38, 5))
- dprintf("closemaps: closing %s (%s)n",
- map->map_mname == NULL ? "NULL" : map->map_mname,
- map->map_file == NULL ? "NULL" : map->map_file);
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- }
- /*
- ** GETCANONNAME -- look up name using service switch
- **
- ** Parameters:
- ** host -- the host name to look up.
- ** hbsize -- the size of the host buffer.
- ** trymx -- if set, try MX records.
- **
- ** Returns:
- ** TRUE -- if the host was found.
- ** FALSE -- otherwise.
- */
- bool
- getcanonname(host, hbsize, trymx)
- char *host;
- int hbsize;
- bool trymx;
- {
- int nmaps;
- int mapno;
- bool found = FALSE;
- bool got_tempfail = FALSE;
- auto int status;
- char *maptype[MAXMAPSTACK];
- short mapreturn[MAXMAPACTIONS];
- nmaps = switch_map_find("hosts", maptype, mapreturn);
- for (mapno = 0; mapno < nmaps; mapno++)
- {
- int i;
- if (tTd(38, 20))
- dprintf("getcanonname(%s), trying %sn",
- host, maptype[mapno]);
- if (strcmp("files", maptype[mapno]) == 0)
- {
- found = text_getcanonname(host, hbsize, &status);
- }
- #ifdef NIS
- else if (strcmp("nis", maptype[mapno]) == 0)
- {
- found = nis_getcanonname(host, hbsize, &status);
- }
- #endif /* NIS */
- #ifdef NISPLUS
- else if (strcmp("nisplus", maptype[mapno]) == 0)
- {
- found = nisplus_getcanonname(host, hbsize, &status);
- }
- #endif /* NISPLUS */
- #if NAMED_BIND
- else if (strcmp("dns", maptype[mapno]) == 0)
- {
- found = dns_getcanonname(host, hbsize, trymx, &status);
- }
- #endif /* NAMED_BIND */
- #if NETINFO
- else if (strcmp("netinfo", maptype[mapno]) == 0)
- {
- found = ni_getcanonname(host, hbsize, &status);
- }
- #endif /* NETINFO */
- else
- {
- found = FALSE;
- status = EX_UNAVAILABLE;
- }
- /*
- ** Heuristic: if $m is not set, we are running during system
- ** startup. In this case, when a name is apparently found
- ** but has no dot, treat is as not found. This avoids
- ** problems if /etc/hosts has no FQDN but is listed first
- ** in the service switch.
- */
- if (found &&
- (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL))
- break;
- /* see if we should continue */
- if (status == EX_TEMPFAIL)
- {
- i = MA_TRYAGAIN;
- got_tempfail = TRUE;
- }
- else if (status == EX_NOTFOUND)
- i = MA_NOTFOUND;
- else
- i = MA_UNAVAIL;
- if (bitset(1 << mapno, mapreturn[i]))
- break;
- }
- if (found)
- {
- char *d;
- if (tTd(38, 20))
- dprintf("getcanonname(%s), foundn", 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] == ' ')
- {
- d = macvalue('m', CurEnv);
- if (d != NULL &&
- hbsize > (int) (strlen(host) + strlen(d) + 1))
- {
- if (host[strlen(host) - 1] != '.')
- (void) strlcat(host, ".", hbsize);
- (void) strlcat(host, d, hbsize);
- }
- else
- return FALSE;
- }
- return TRUE;
- }
- if (tTd(38, 20))
- dprintf("getcanonname(%s), failed, status=%dn", host, status);
- #if NAMED_BIND
- if (got_tempfail)
- h_errno = TRY_AGAIN;
- else
- h_errno = HOST_NOT_FOUND;
- #endif /* NAMED_BIND */
- return FALSE;
- }
- /*
- ** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
- **
- ** Parameters:
- ** name -- the name against which to match.
- ** line -- the /etc/hosts line.
- ** cbuf -- the location to store the result.
- ** cbuflen -- the size of cbuf.
- **
- ** Returns:
- ** TRUE -- if the line matched the desired name.
- ** FALSE -- otherwise.
- */
- static bool
- extract_canonname(name, line, cbuf, cbuflen)
- char *name;
- char *line;
- char cbuf[];
- int cbuflen;
- {
- int i;
- char *p;
- bool found = FALSE;
- cbuf[0] = ' ';
- if (line[0] == '#')
- return FALSE;
- for (i = 1; ; i++)
- {
- char nbuf[MAXNAME + 1];
- p = get_column(line, i, ' ', nbuf, sizeof nbuf);
- if (p == NULL)
- break;
- if (*p == ' ')
- continue;
- if (cbuf[0] == ' ' ||
- (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL))
- {
- snprintf(cbuf, cbuflen, "%s", p);
- }
- if (strcasecmp(name, p) == 0)
- found = TRUE;
- }
- if (found && strchr(cbuf, '.') == NULL)
- {
- /* try to add a domain on the end of the name */
- char *domain = macvalue('m', CurEnv);
- if (domain != NULL &&
- strlen(domain) + (i = strlen(cbuf)) + 1 < cbuflen)
- {
- p = &cbuf[i];
- *p++ = '.';
- (void) strlcpy(p, domain, cbuflen - i - 1);
- }
- }
- return found;
- }
- /*
- ** NDBM modules
- */
- #ifdef NDBM
- /*
- ** NDBM_MAP_OPEN -- DBM-style map open
- */
- bool
- ndbm_map_open(map, mode)
- MAP *map;
- int mode;
- {
- register DBM *dbm;
- int save_errno;
- int dfd;
- int pfd;
- long sff;
- int ret;
- int smode = S_IREAD;
- char dirfile[MAXNAME + 1];
- char pagfile[MAXNAME + 1];
- struct stat st;
- struct stat std, stp;
- if (tTd(38, 2))
- dprintf("ndbm_map_open(%s, %s, %d)n",
- map->map_mname, map->map_file, mode);
- map->map_lockfd = -1;
- mode &= O_ACCMODE;
- /* do initial file and directory checks */
- snprintf(dirfile, sizeof dirfile, "%s.dir", map->map_file);
- snprintf(pagfile, sizeof pagfile, "%s.pag", map->map_file);
- sff = SFF_ROOTOK|SFF_REGONLY;
- if (mode == O_RDWR)
- {
- sff |= SFF_CREAT;
- if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
- sff |= SFF_NOSLINK;
- if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
- sff |= SFF_NOHLINK;
- smode = S_IWRITE;
- }
- else
- {
- if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
- sff |= SFF_NOWLINK;
- }
- if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
- sff |= SFF_SAFEDIRPATH;
- ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName,
- sff, smode, &std);
- if (ret == 0)
- ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName,
- sff, smode, &stp);
- # if !_FFR_REMOVE_AUTOREBUILD
- if (ret == ENOENT && AutoRebuild &&
- bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
- (bitset(MF_IMPL_NDBM, map->map_mflags) ||
- bitset(MF_ALIAS, map->map_mflags)) &&
- mode == O_RDONLY)
- {
- bool impl = bitset(MF_IMPL_NDBM, map->map_mflags);
- /* may be able to rebuild */
- map->map_mflags &= ~MF_IMPL_NDBM;
- if (!rebuildaliases(map, TRUE))
- return FALSE;
- if (impl)
- return impl_map_open(map, O_RDONLY);
- else
- return ndbm_map_open(map, O_RDONLY);
- }
- # endif /* !_FFR_REMOVE_AUTOREBUILD */
- if (ret != 0)
- {
- char *prob = "unsafe";
- /* cannot open this map */
- if (ret == ENOENT)
- prob = "missing";
- if (tTd(38, 2))
- dprintf("t%s map file: %dn", prob, ret);
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("dbm map "%s": %s map file %s",
- map->map_mname, prob, map->map_file);
- return FALSE;
- }
- if (std.st_mode == ST_MODE_NOFILE)
- mode |= O_CREAT|O_EXCL;
- # if LOCK_ON_OPEN
- if (mode == O_RDONLY)
- mode |= O_SHLOCK;
- else
- mode |= O_TRUNC|O_EXLOCK;
- # else /* LOCK_ON_OPEN */
- if ((mode & O_ACCMODE) == O_RDWR)
- {
- # if NOFTRUNCATE
- /*
- ** Warning: race condition. Try to lock the file as
- ** quickly as possible after opening it.
- ** This may also have security problems on some systems,
- ** but there isn't anything we can do about it.
- */
- mode |= O_TRUNC;
- # else /* NOFTRUNCATE */
- /*
- ** This ugly code opens the map without truncating it,
- ** locks the file, then truncates it. Necessary to
- ** avoid race conditions.
- */
- int dirfd;
- int pagfd;
- long sff = SFF_CREAT|SFF_OPENASROOT;
- if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
- sff |= SFF_NOSLINK;
- if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
- sff |= SFF_NOHLINK;
- dirfd = safeopen(dirfile, mode, DBMMODE, sff);
- pagfd = safeopen(pagfile, mode, DBMMODE, sff);
- if (dirfd < 0 || pagfd < 0)
- {
- save_errno = errno;
- if (dirfd >= 0)
- (void) close(dirfd);
- if (pagfd >= 0)
- (void) close(pagfd);
- errno = save_errno;
- syserr("ndbm_map_open: cannot create database %s",
- map->map_file);
- return FALSE;
- }
- if (ftruncate(dirfd, (off_t) 0) < 0 ||
- ftruncate(pagfd, (off_t) 0) < 0)
- {
- save_errno = errno;
- (void) close(dirfd);
- (void) close(pagfd);
- errno = save_errno;
- syserr("ndbm_map_open: cannot truncate %s.{dir,pag}",
- map->map_file);
- return FALSE;
- }
- /* if new file, get "before" bits for later filechanged check */
- if (std.st_mode == ST_MODE_NOFILE &&
- (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0))
- {
- save_errno = errno;
- (void) close(dirfd);
- (void) close(pagfd);
- errno = save_errno;
- syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file",
- map->map_file);
- return FALSE;
- }
- /* have to save the lock for the duration (bletch) */
- map->map_lockfd = dirfd;
- (void) close(pagfd);
- /* twiddle bits for dbm_open */
- mode &= ~(O_CREAT|O_EXCL);
- # endif /* NOFTRUNCATE */
- }
- # endif /* LOCK_ON_OPEN */
- /* open the database */
- dbm = dbm_open(map->map_file, mode, DBMMODE);
- if (dbm == NULL)
- {
- save_errno = errno;
- if (bitset(MF_ALIAS, map->map_mflags) &&
- aliaswait(map, ".pag", FALSE))
- return TRUE;
- # if !LOCK_ON_OPEN && !NOFTRUNCATE
- if (map->map_lockfd >= 0)
- (void) close(map->map_lockfd);
- # endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
- errno = save_errno;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("Cannot open DBM database %s", map->map_file);
- return FALSE;
- }
- dfd = dbm_dirfno(dbm);
- pfd = dbm_pagfno(dbm);
- if (dfd == pfd)
- {
- /* heuristic: if files are linked, this is actually gdbm */
- dbm_close(dbm);
- # if !LOCK_ON_OPEN && !NOFTRUNCATE
- if (map->map_lockfd >= 0)
- (void) close(map->map_lockfd);
- # endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
- errno = 0;
- syserr("dbm map "%s": cannot support GDBM",
- map->map_mname);
- return FALSE;
- }
- if (filechanged(dirfile, dfd, &std) ||
- filechanged(pagfile, pfd, &stp))
- {
- save_errno = errno;
- dbm_close(dbm);
- # if !LOCK_ON_OPEN && !NOFTRUNCATE
- if (map->map_lockfd >= 0)
- (void) close(map->map_lockfd);
- # endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */
- errno = save_errno;
- syserr("ndbm_map_open(%s): file changed after open",
- map->map_file);
- return FALSE;
- }
- map->map_db1 = (ARBPTR_T) dbm;
- /*
- ** Need to set map_mtime before the call to aliaswait()
- ** as aliaswait() will call map_lookup() which requires
- ** map_mtime to be set
- */
- if (fstat(dfd, &st) >= 0)
- map->map_mtime = st.st_mtime;
- if (mode == O_RDONLY)
- {
- # if LOCK_ON_OPEN
- if (dfd >= 0)
- (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN);
- if (pfd >= 0)
- (void) lockfile(pfd, map->map_file, ".pag", LOCK_UN);
- # endif /* LOCK_ON_OPEN */
- if (bitset(MF_ALIAS, map->map_mflags) &&
- !aliaswait(map, ".pag", TRUE))
- return FALSE;
- }
- else
- {
- map->map_mflags |= MF_LOCKED;
- if (geteuid() == 0 && TrustedUid != 0)
- {
- # if HASFCHOWN
- if (fchown(dfd, TrustedUid, -1) < 0 ||
- fchown(pfd, TrustedUid, -1) < 0)
- {
- int err = errno;
- sm_syslog(LOG_ALERT, NOQID,
- "ownership change on %s failed: %s",
- map->map_file, errstring(err));
- message("050 ownership change on %s failed: %s",
- map->map_file, errstring(err));
- }
- # endif /* HASFCHOWN */
- }
- }
- return TRUE;
- }
- /*
- ** NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map
- */
- char *
- ndbm_map_lookup(map, name, av, statp)
- MAP *map;
- char *name;
- char **av;
- int *statp;
- {
- datum key, val;
- int fd;
- char keybuf[MAXNAME + 1];
- struct stat stbuf;
- if (tTd(38, 20))
- dprintf("ndbm_map_lookup(%s, %s)n",
- map->map_mname, name);
- key.dptr = name;
- key.dsize = strlen(name);
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- {
- if (key.dsize > sizeof keybuf - 1)
- key.dsize = sizeof keybuf - 1;
- memmove(keybuf, key.dptr, key.dsize);
- keybuf[key.dsize] = ' ';
- makelower(keybuf);
- key.dptr = keybuf;
- }
- lockdbm:
- fd = dbm_dirfno((DBM *) map->map_db1);
- if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, map->map_file, ".dir", LOCK_SH);
- if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
- {
- /* Reopen the database to sync the cache */
- int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
- : O_RDONLY;
- if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, map->map_file, ".dir", LOCK_UN);
- map->map_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- if (map->map_class->map_open(map, omode))
- {
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- 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_class = &BogusMapClass;
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- 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 (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
- (void) lockfile(fd, 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))
- 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] = ' ';
- 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 != ' ')
- {
- old.dsize = strlen(old.dptr);
- if (data.dsize + old.dsize + 2 > bufsiz)
- {
- if (buf != NULL)
- (void) free(buf);
- bufsiz = data.dsize + old.dsize + 2;
- buf = xalloc(bufsiz);
- }
- snprintf(buf, bufsiz, "%s,%s",
- data.dptr, old.dptr);
- data.dsize = data.dsize + old.dsize + 1;
- data.dptr = buf;
- if (tTd(38, 9))
- dprintf("ndbm_map_store append=%sn",
- data.dptr);
- }
- }
- status = dbm_store((DBM *) map->map_db1,
- key, data, DBM_REPLACE);
- }
- if (status != 0)
- syserr("readaliases: dbm put (%s)", lhs);
- }
- /*
- ** NDBM_MAP_CLOSE -- close the database
- */
- void
- ndbm_map_close(map)
- register MAP *map;
- {
- if (tTd(38, 9))
- 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) 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
- */
- #ifdef 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))
- dprintf("bt_map_open(%s, %s, %d)n",
- map->map_mname, map->map_file, mode);
- # if DB_VERSION_MAJOR < 3
- memset(&btinfo, ' ', 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))
- dprintf("hash_map_open(%s, %s, %d)n",
- map->map_mname, map->map_file, mode);
- # if DB_VERSION_MAJOR < 3
- memset(&hinfo, ' ', 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[MAXNAME + 1];
- /* do initial file and directory checks */
- (void) strlcpy(buf, map->map_file, sizeof buf - 3);
- i = strlen(buf);
- if (i < 3 || strcmp(&buf[i - 3], ".db") != 0)
- (void) strlcat(buf, ".db", sizeof buf);
- 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 !_FFR_REMOVE_AUTOREBUILD
- if (i == ENOENT && AutoRebuild &&
- bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
- (bitset(MF_IMPL_HASH, map->map_mflags) ||
- bitset(MF_ALIAS, map->map_mflags)) &&
- mode == O_RDONLY)
- {
- bool impl = bitset(MF_IMPL_HASH, map->map_mflags);
- /* may be able to rebuild */
- map->map_mflags &= ~MF_IMPL_HASH;
- if (!rebuildaliases(map, TRUE))
- return FALSE;
- if (impl)
- return impl_map_open(map, O_RDONLY);
- else
- return db_map_open(map, O_RDONLY, mapclassname,
- dbtype, openinfo);
- }
- # endif /* !_FFR_REMOVE_AUTOREBUILD */
- if (i != 0)
- {
- char *prob = "unsafe";
- /* cannot open this map */
- if (i == ENOENT)
- prob = "missing";
- if (tTd(38, 2))
- dprintf("t%s map file: %sn", prob, 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;
- # if !HASFLOCK && defined(DB_FCNTL_LOCKING)
- flags |= DB_FCNTL_LOCKING;
- # endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */
- # 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, buf, NULL, dbtype, flags, DBMMODE);
- if (ret != 0)
- {
- (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, errstring(err));
- message("050 ownership change on %s failed: %s",
- buf, errstring(err));
- }
- # 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[MAXNAME + 1];
- memset(&key, ' ', sizeof key);
- memset(&val, ' ', sizeof val);
- if (tTd(38, 20))
- dprintf("db_map_lookup(%s, %s)n",
- map->map_mname, name);
- i = strlen(map->map_file);
- if (i > MAXNAME)
- i = MAXNAME;
- (void) strlcpy(buf, map->map_file, i + 1);
- if (i > 3 && strcmp(&buf[i - 3], ".db") == 0)
- buf[i - 3] = ' ';
- 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] = ' ';
- 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_class->map_close(map);
- map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
- if (map->map_class->map_open(map, omode))
- {
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- 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_class = &BogusMapClass;
- map->map_mflags |= MF_OPEN;
- map->map_pid = getpid();
- 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, ' ', sizeof key);
- memset(&data, ' ', sizeof data);
- if (tTd(38, 12))
- 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] = ' ';
- 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, ' ', 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 > bufsiz)
- {
- if (buf != NULL)
- (void) free(buf);
- bufsiz = data.size + old.size + 2;
- buf = xalloc(bufsiz);
- }
- snprintf(buf, bufsiz, "%s,%s",
- (char *) data.data, (char *) old.data);
- data.size = data.size + old.size + 1;
- data.data = buf;
- if (tTd(38, 9))
- dprintf("db_map_store append=%sn",
- (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))
- 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 != getpid())
- {
- 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
- */
- #ifdef 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))
- 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 */
- # ifdef ENOSYS
- errno = ENOSYS;
- # else /* ENOSYS */
- # ifdef EFTYPE
- errno = EFTYPE;
- # else /* EFTYPE */
- errno = ENXIO;
- # endif /* EFTYPE */
- # endif /* ENOSYS */
- return FALSE;
- }
- p = strchr(map->map_file, '@');
- if (p != NULL)
- {
- *p++ = ' ';
- if (*p != ' ')
- map->map_domain = p;
- }
- if (*map->map_file == ' ')
- 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("421 4.3.5 NIS map %s specified, but NIS not running",
- map->map_file);
- return FALSE;
- }
- }
- /* check to see if this map actually exists */
- yperr = yp_match(map->map_domain, map->map_file, "@", 1,
- &vp, &vsize);
- if (tTd(38, 10))
- dprintf("nis_map_open: yp_match(@, %s, %s) => %sn",
- map->map_domain, map->map_file, yperr_string(yperr));
- 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("421 4.0.0 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];
- if (tTd(38, 20))
- 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] = ' ';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(keybuf);
- yperr = YPERR_KEY;
- 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))
- {
- 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);
- return NULL;
- }
- if (bitset(MF_MATCHONLY, map->map_mflags))
- return map_rewrite(map, name, strlen(name), NULL);
- else
- return map_rewrite(map, vp, vsize, av);
- }
- /*
- ** 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))
- dprintf("nis_getcanonname(%s)n", name);
- if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf)
- {
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
- shorten_hostname(nbuf);
- keylen = strlen(nbuf);
- if (yp_domain == NULL)
- (void) yp_get_default_domain(&yp_domain);
- makelower(nbuf);
- yperr = YPERR_KEY;
- if (try0null)
- {
- yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen,
- &vp, &vsize);
- if (yperr == 0)
- try1null = FALSE;
- }
- if (yperr == YPERR_KEY && try1null)
- {
- 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;
- return FALSE;
- }
- (void) strlcpy(host_record, vp, sizeof host_record);
- if (tTd(38, 44))
- dprintf("got record `%s'n", host_record);
- if (!extract_canonname(nbuf, host_record, cbuf, sizeof cbuf))
- {
- /* this should not happen, but.... */
- *statp = EX_NOHOST;
- return FALSE;
- }
- if (hbsize < strlen(cbuf))
- {
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
- (void) strlcpy(name, cbuf, hbsize);
- *statp = EX_OK;
- return TRUE;
- }
- #endif /* NIS */
- /*
- ** NISPLUS Modules
- **
- ** This code donated by Sun Microsystems.
- */
- #ifdef 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))
- 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 == ' ')
- 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))
- dprintf("nisplus_map_open(%s): using domain %sn",
- map->map_file, map->map_domain);
- }
- if (!PARTIAL_NAME(map->map_file))
- {
- map->map_domain = newstr("");
- snprintf(qbuf, sizeof qbuf, "%s", map->map_file);
- }
- else
- {
- /* check to see if this map actually exists */
- snprintf(qbuf, sizeof qbuf, "%s.%s",
- 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("421 4.0.0 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))
- dprintf("nisplus_map_open: %s is not a tablen", qbuf);
- # if 0
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- syserr("421 4.0.0 %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)))
- break;
- }
- if (i == max_col)
- {
- if (tTd(38, 2))
- dprintf("nisplus_map_open(%s): can not find key column %sn",
- 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))
- dprintf("nisplus_map_open(%s): can not find column %sn",
- 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))
- 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 = getpid();
- }
- 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 != ' ' && 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 = ' ';
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- makelower(search_key);
- /* construct the query */
- if (PARTIAL_NAME(map->map_file))
- snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s",
- map->map_keycolnm, search_key, map->map_file,
- map->map_domain);
- else
- snprintf(qbuf, sizeof qbuf, "[%s=%s],%s",
- map->map_keycolnm, search_key, map->map_file);
- if (tTd(38, 20))
- dprintf("qbuf=%sn", 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))
- dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignoredn",
- 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))
- dprintf("nisplus_map_lookup(%s), found %sn",
- 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))
- dprintf("nisplus_map_lookup(%s), failedn", 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 (strlen(name) >= sizeof nbuf)
- {
- *statp = EX_UNAVAILABLE;
- return FALSE;
- }
- (void) strlcpy(nbuf, name, sizeof nbuf);
- shorten_hostname(nbuf);
- p = strchr(nbuf, '.');
- if (p == NULL)
- {
- /* single token */
- snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir", nbuf);
- }
- else if (p[1] != ' ')
- {
- /* multi token -- take only first token in nbuf */
- *p = ' ';
- snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir.%s",
- nbuf, &p[1]);
- }
- else
- {
- *statp = EX_NOHOST;
- return FALSE;
- }
- if (tTd(38, 20))
- dprintf("nnisplus_getcanoname(%s), qbuf=%sn",
- 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))
- dprintf("nisplus_getcanoname(%s), got %d entries, all but first ignoredn",
- name, count);
- }
- if (tTd(38, 20))
- dprintf("nisplus_getcanoname(%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))
- dprintf("nisplus_getcanonname(%s), found %sn",
- 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] == ' ')
- (void) strlcpy(name, vp, hbsize);
- else
- 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))
- dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%dn",
- 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] != ' ')
- return default_domain;
- p = nis_local_directory();
- snprintf(default_domain, sizeof default_domain, "%s", p);
- return default_domain;
- }
- #endif /* NISPLUS */
- /*
- ** LDAP Modules
- */
- /*
- ** LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs
- */
- #if defined(LDAPMAP) || defined(PH_MAP)
- # ifdef PH_MAP
- # define ph_map_dequote ldapmap_dequote
- # endif /* PH_MAP */
- 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 != ' ')
- p++;
- if (*p != ' ')
- *p = ' ';
- return start;
- }
- #endif /* defined(LDAPMAP) || defined(PH_MAP) */
- #ifdef LDAPMAP
- LDAPMAP_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;
- {
- LDAPMAP_STRUCT *lmap;
- STAB *s;
- if (tTd(38, 2))
- dprintf("ldapmap_open(%s, %d)n", map->map_mname, mode);
- mode &= O_ACCMODE;
- /* sendmail doesn't have the ability to write to LDAP (yet) */
- if (mode != O_RDONLY)
- {
- /* issue a pseudo-error message */
- # ifdef ENOSYS
- errno = ENOSYS;
- # else /* ENOSYS */
- # ifdef EFTYPE
- errno = EFTYPE;
- # else /* EFTYPE */
- errno = ENXIO;
- # endif /* EFTYPE */
- # endif /* ENOSYS */
- return FALSE;
- }
- /* Comma separate if used as an alias file */
- if (map->map_coldelim == ' ' && bitset(MF_ALIAS, map->map_mflags))
- map->map_coldelim = ',';
- lmap = (LDAPMAP_STRUCT *) map->map_db1;
- s = ldapmap_findconn(lmap);
- if (s->s_ldap != NULL)
- {
- /* Already have a connection open to this LDAP server */
- lmap->ldap_ld = s->s_ldap;
- return TRUE;
- }
- /* No connection yet, connect */
- if (!ldapmap_start(map))
- return FALSE;
- /* Save connection for reuse */
- s->s_ldap = lmap->ldap_ld;
- return TRUE;
- }
- /*
- ** LDAPMAP_START -- actually connect to an LDAP server
- **
- ** Parameters:
- ** map -- the map being opened.
- **
- ** Returns:
- ** TRUE if connection is successful, FALSE otherwise.
- **
- ** Side Effects:
- ** Populates lmap->ldap_ld.
- */
- static jmp_buf LDAPTimeout;
- static bool
- ldapmap_start(map)
- MAP *map;
- {
- register int bind_result;
- int save_errno;
- register EVENT *ev = NULL;
- LDAPMAP_STRUCT *lmap;
- LDAP *ld;
- if (tTd(38, 2))
- dprintf("ldapmap_start(%s)n", map->map_mname);
- lmap = (LDAPMAP_STRUCT *) map->map_db1;
- if (tTd(38,9))
- dprintf("ldapmap_start(%s, %d)n", lmap->ldap_host,
- lmap->ldap_port);
- # if USE_LDAP_INIT
- ld = ldap_init(lmap->ldap_host, lmap->ldap_port);
- # else /* USE_LDAP_INIT */
- /*
- ** If using ldap_open(), the actual connection to the server
- ** happens now so we need the timeout here. For ldap_init(),
- ** the connection happens at bind time.
- */
- /* set the timeout */
- if (lmap->ldap_timeout.tv_sec != 0)
- {
- if (setjmp(LDAPTimeout) != 0)
- {
- if (LogLevel > 1)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "timeout conning to LDAP server %.100s",
- lmap->ldap_host);
- return FALSE;
- }
- ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
- }
- ld = ldap_open(lmap->ldap_host, lmap->ldap_port);
- save_errno = errno;
- /* clear the event if it has not sprung */
- if (ev != NULL)
- clrevent(ev);
- # endif /* USE_LDAP_INIT */
- errno = save_errno;
- if (ld == NULL)
- {
- 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",
- # else /* USE_LDAP_INIT */
- "ldap_open",
- # endif /* USE_LDAP_INIT */
- lmap->ldap_host, map->map_mname);
- else
- syserr("421 4.0.0 %s failed to %s in map %s",
- # if USE_LDAP_INIT
- "ldap_init",
- # else /* USE_LDAP_INIT */
- "ldap_open",
- # endif /* USE_LDAP_INIT */
- lmap->ldap_host, map->map_mname);
- }
- return FALSE;
- }
- ldapmap_setopts(ld, lmap);
- # if USE_LDAP_INIT
- /*
- ** If using ldap_init(), the actual connection to the server
- ** happens at ldap_bind_s() so we need the timeout here.
- */
- /* set the timeout */
- if (lmap->ldap_timeout.tv_sec != 0)
- {
- if (setjmp(LDAPTimeout) != 0)
- {
- if (LogLevel > 1)
- sm_syslog(LOG_NOTICE, CurEnv->e_id,
- "timeout conning to LDAP server %.100s",
- lmap->ldap_host);
- return FALSE;
- }
- ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0);
- }
- # endif /* USE_LDAP_INIT */
- if (lmap->ldap_method == LDAP_AUTH_KRBV4 &&
- lmap->ldap_secret != NULL)
- {
- /*
- ** Need to put ticket in environment here instead of
- ** during parseargs as there may be different tickets
- ** for different LDAP connections.
- */
- (void) putenv(lmap->ldap_secret);
- }
- bind_result = ldap_bind_s(ld, lmap->ldap_binddn,
- lmap->ldap_secret, lmap->ldap_method);
- # if USE_LDAP_INIT
- /* clear the event if it has not sprung */
- if (ev != NULL)
- clrevent(ev);
- # endif /* USE_LDAP_INIT */
- if (bind_result != LDAP_SUCCESS)
- {
- errno = bind_result + E_LDAPBASE;
- if (!bitset(MF_OPTIONAL, map->map_mflags))
- {
- syserr("421 4.0.0 Cannot bind to map %s in ldap server %s",
- map->map_mname,
- (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host));
- }
- return FALSE;
- }
- /* We need to cast ld into the map structure */
- lmap->ldap_ld = ld;
- return TRUE;
- }
- /* ARGSUSED */
- static void
- ldaptimeout(sig_no)
- int sig_no;
- {
- longjmp(LDAPTimeout, 1);
- }
- /*
- ** LDAPMAP_CLOSE -- close ldap map
- */
- void
- ldapmap_close(map)
- MAP *map;
- {
- LDAPMAP_STRUCT *lmap;
- STAB *s;
- lmap = (LDAPMAP_STRUCT *) map->map_db1;
- /* Check if already closed */
- if (lmap->ldap_ld == NULL)
- return;
- s = ldapmap_findconn(lmap);
- /* Check if already closed */
- if (s->s_ldap == NULL)
- return;
- /* If same as saved connection, stored connection is going away */
- if (s->s_ldap == lmap->ldap_ld)
- s->s_ldap = NULL;
- if (lmap->ldap_ld != NULL)
- {
- ldap_unbind(lmap->ldap_ld);
- lmap->ldap_ld = NULL;
- }
- }
- # ifdef SUNET_ID
- /*
- ** SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form
- ** This only makes sense at Stanford University.
- */
- char *
- sunet_id_hash(str)
- char *str;
- {
- char *p, *p_last;
- p = str;
- p_last = p;
- while (*p != ' ')
- {
- if (islower(*p) || isdigit(*p))
- {
- *p_last = *p;
- p_last++;
- }
- else if (isupper(*p))
- {
- *p_last = tolower(*p);
- p_last++;
- }
- ++p;
- }
- if (*p_last != ' ')
- *p_last = ' ';
- return 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 i;
- int entries = 0;
- int msgid;
- int ret;
- int vsize;
- char *fp, *vp;
- char *p, *q;
- char *result = NULL;
- LDAPMAP_STRUCT *lmap = NULL;
- char keybuf[MAXNAME + 1];
- char filter[LDAPMAP_MAX_FILTER + 1];
- if (tTd(38, 20))
- dprintf("ldapmap_lookup(%s, %s)n", map->map_mname, name);
- /* Get ldap struct pointer from map */
- lmap = (LDAPMAP_STRUCT *) map->map_db1;
- ldapmap_setopts(lmap->ldap_ld, lmap);
- (void) strlcpy(keybuf, name, sizeof keybuf);
- if (!bitset(MF_NOFOLDCASE, map->map_mflags))
- {
- # ifdef SUNET_ID
- sunet_id_hash(keybuf);
- # else /* SUNET_ID */
- makelower(keybuf);
- # endif /* SUNET_ID */
- }
- /* substitute keybuf into filter, perhaps multiple times */
- memset(filter, ' ', sizeof filter);
- fp = filter;
- p = lmap->ldap_filter;
- while ((q = strchr(p, '%')) != NULL)
- {
- if (q[1] == 's')
- {
- snprintf(fp, SPACELEFT(filter, fp), "%.*s%s",
- q - p, p, keybuf);
- fp += strlen(fp);
- p = q + 2;
- }
- else if (q[1] == '0')
- {
- char *k = keybuf;
- snprintf(fp, SPACELEFT(filter, fp), "%.*s",
- q - p, p);
- fp += strlen(fp);
- p = q + 2;
- /* Properly escape LDAP special characters */
- while (SPACELEFT(filter, fp) > 0 &&
- *k != ' ')
- {
- if (*k == '*' || *k == '(' ||
- *k == ')' || *k == '\')
- {
- (void) strlcat(fp,
- (*k == '*' ? "\2A" :
- (*k == '(' ? "\28" :
- (*k == ')' ? "\29" :
- (*k == '\' ? "\5C" :
- "