diff options
Diffstat (limited to 'contrib/sendmail/src/map.c')
-rw-r--r-- | contrib/sendmail/src/map.c | 7989 |
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 */ |