map.c revision 77349
138032Speter/* 273188Sgshapiro * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1992, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1992, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1438032Speter#ifndef lint 1577349Sgshapirostatic char id[] = "@(#)$Id: map.c,v 8.414.4.53 2001/05/04 01:29:00 gshapiro Exp $"; 1664562Sgshapiro#endif /* ! lint */ 1738032Speter 1864562Sgshapiro#include <sendmail.h> 1938032Speter 2064562Sgshapiro 2138032Speter#ifdef NDBM 2238032Speter# include <ndbm.h> 2338032Speter# ifdef R_FIRST 2438032Speter ERROR README: You are running the Berkeley DB version of ndbm.h. See 2538032Speter ERROR README: the README file about tweaking Berkeley DB so it can 2638032Speter ERROR README: coexist with NDBM, or delete -DNDBM from the Makefile 2738032Speter ERROR README: and use -DNEWDB instead. 2864562Sgshapiro# endif /* R_FIRST */ 2964562Sgshapiro#endif /* NDBM */ 3038032Speter#ifdef NEWDB 3138032Speter# include <db.h> 3238032Speter# ifndef DB_VERSION_MAJOR 3338032Speter# define DB_VERSION_MAJOR 1 3464562Sgshapiro# endif /* ! DB_VERSION_MAJOR */ 3564562Sgshapiro#endif /* NEWDB */ 3638032Speter#ifdef NIS 3738032Speter struct dom_binding; /* forward reference needed on IRIX */ 3838032Speter# include <rpcsvc/ypclnt.h> 3938032Speter# ifdef NDBM 4038032Speter# define NDBM_YP_COMPAT /* create YP-compatible NDBM files */ 4164562Sgshapiro# endif /* NDBM */ 4264562Sgshapiro#endif /* NIS */ 4338032Speter 4464562Sgshapiro#ifdef NEWDB 4564562Sgshapiro# if DB_VERSION_MAJOR < 2 4664562Sgshapirostatic bool db_map_open __P((MAP *, int, char *, DBTYPE, const void *)); 4764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 4864562Sgshapiro# if DB_VERSION_MAJOR == 2 4964562Sgshapirostatic bool db_map_open __P((MAP *, int, char *, DBTYPE, DB_INFO *)); 5064562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */ 5164562Sgshapiro# if DB_VERSION_MAJOR > 2 5264562Sgshapirostatic bool db_map_open __P((MAP *, int, char *, DBTYPE, void **)); 5364562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 5464562Sgshapiro#endif /* NEWDB */ 5573188Sgshapirostatic bool extract_canonname __P((char *, char *, char *, char[], int)); 5664562Sgshapiro#ifdef LDAPMAP 5764562Sgshapirostatic void ldapmap_clear __P((LDAPMAP_STRUCT *)); 5864562Sgshapirostatic STAB *ldapmap_findconn __P((LDAPMAP_STRUCT *)); 5964562Sgshapirostatic int ldapmap_geterrno __P((LDAP *)); 6064562Sgshapirostatic void ldapmap_setopts __P((LDAP *, LDAPMAP_STRUCT *)); 6164562Sgshapirostatic bool ldapmap_start __P((MAP *)); 6264562Sgshapirostatic void ldaptimeout __P((int)); 6364562Sgshapiro#endif /* LDAPMAP */ 6464562Sgshapirostatic void map_close __P((STAB *, int)); 6564562Sgshapirostatic void map_init __P((STAB *, int)); 6664562Sgshapiro#ifdef NISPLUS 6764562Sgshapirostatic bool nisplus_getcanonname __P((char *, int, int *)); 6864562Sgshapiro#endif /* NISPLUS */ 6964562Sgshapiro#ifdef NIS 7064562Sgshapirostatic bool nis_getcanonname __P((char *, int, int *)); 7164562Sgshapiro#endif /* NIS */ 7264562Sgshapiro#if NETINFO 7364562Sgshapirostatic bool ni_getcanonname __P((char *, int, int *)); 7464562Sgshapiro#endif /* NETINFO */ 7564562Sgshapirostatic bool text_getcanonname __P((char *, int, int *)); 7664562Sgshapiro 7738032Speter/* 7838032Speter** MAP.C -- implementations for various map classes. 7938032Speter** 8038032Speter** Each map class implements a series of functions: 8138032Speter** 8238032Speter** bool map_parse(MAP *map, char *args) 8338032Speter** Parse the arguments from the config file. Return TRUE 8438032Speter** if they were ok, FALSE otherwise. Fill in map with the 8538032Speter** values. 8638032Speter** 8738032Speter** char *map_lookup(MAP *map, char *key, char **args, int *pstat) 8838032Speter** Look up the key in the given map. If found, do any 8938032Speter** rewriting the map wants (including "args" if desired) 9038032Speter** and return the value. Set *pstat to the appropriate status 9138032Speter** on error and return NULL. Args will be NULL if called 9238032Speter** from the alias routines, although this should probably 9338032Speter** not be relied upon. It is suggested you call map_rewrite 9438032Speter** to return the results -- it takes care of null termination 9538032Speter** and uses a dynamically expanded buffer as needed. 9638032Speter** 9738032Speter** void map_store(MAP *map, char *key, char *value) 9838032Speter** Store the key:value pair in the map. 9938032Speter** 10038032Speter** bool map_open(MAP *map, int mode) 10138032Speter** Open the map for the indicated mode. Mode should 10238032Speter** be either O_RDONLY or O_RDWR. Return TRUE if it 10338032Speter** was opened successfully, FALSE otherwise. If the open 10438032Speter** failed an the MF_OPTIONAL flag is not set, it should 10538032Speter** also print an error. If the MF_ALIAS bit is set 10638032Speter** and this map class understands the @:@ convention, it 10738032Speter** should call aliaswait() before returning. 10838032Speter** 10938032Speter** void map_close(MAP *map) 11038032Speter** Close the map. 11138032Speter** 11238032Speter** This file also includes the implementation for getcanonname. 11338032Speter** It is currently implemented in a pretty ad-hoc manner; it ought 11438032Speter** to be more properly integrated into the map structure. 11538032Speter*/ 11638032Speter 11738032Speter#define DBMMODE 0644 11838032Speter 11938032Speter#ifndef EX_NOTFOUND 12038032Speter# define EX_NOTFOUND EX_NOHOST 12164562Sgshapiro#endif /* ! EX_NOTFOUND */ 12238032Speter 12338032Speter#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL 12438032Speter# define LOCK_ON_OPEN 1 /* we can open/create a locked file */ 12564562Sgshapiro#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */ 12638032Speter# define LOCK_ON_OPEN 0 /* no such luck -- bend over backwards */ 12764562Sgshapiro#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */ 12838032Speter 12938032Speter#ifndef O_ACCMODE 13038032Speter# define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) 13164562Sgshapiro#endif /* ! O_ACCMODE */ 13238032Speter/* 13338032Speter** MAP_PARSEARGS -- parse config line arguments for database lookup 13438032Speter** 13538032Speter** This is a generic version of the map_parse method. 13638032Speter** 13738032Speter** Parameters: 13838032Speter** map -- the map being initialized. 13938032Speter** ap -- a pointer to the args on the config line. 14038032Speter** 14138032Speter** Returns: 14238032Speter** TRUE -- if everything parsed OK. 14338032Speter** FALSE -- otherwise. 14438032Speter** 14538032Speter** Side Effects: 14638032Speter** null terminates the filename; stores it in map 14738032Speter*/ 14838032Speter 14938032Speterbool 15038032Spetermap_parseargs(map, ap) 15138032Speter MAP *map; 15238032Speter char *ap; 15338032Speter{ 15438032Speter register char *p = ap; 15538032Speter 15664562Sgshapiro /* 15764562Sgshapiro ** there is no check whether there is really an argument, 15864562Sgshapiro ** but that's not important enough to warrant extra code 15964562Sgshapiro */ 16038032Speter map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL; 16164562Sgshapiro map->map_spacesub = SpaceSub; /* default value */ 16238032Speter for (;;) 16338032Speter { 16438032Speter while (isascii(*p) && isspace(*p)) 16538032Speter p++; 16638032Speter if (*p != '-') 16738032Speter break; 16838032Speter switch (*++p) 16938032Speter { 17038032Speter case 'N': 17138032Speter map->map_mflags |= MF_INCLNULL; 17238032Speter map->map_mflags &= ~MF_TRY0NULL; 17338032Speter break; 17438032Speter 17538032Speter case 'O': 17638032Speter map->map_mflags &= ~MF_TRY1NULL; 17738032Speter break; 17838032Speter 17938032Speter case 'o': 18038032Speter map->map_mflags |= MF_OPTIONAL; 18138032Speter break; 18238032Speter 18338032Speter case 'f': 18438032Speter map->map_mflags |= MF_NOFOLDCASE; 18538032Speter break; 18638032Speter 18738032Speter case 'm': 18838032Speter map->map_mflags |= MF_MATCHONLY; 18938032Speter break; 19038032Speter 19138032Speter case 'A': 19238032Speter map->map_mflags |= MF_APPEND; 19338032Speter break; 19438032Speter 19538032Speter case 'q': 19638032Speter map->map_mflags |= MF_KEEPQUOTES; 19738032Speter break; 19838032Speter 19938032Speter case 'a': 20038032Speter map->map_app = ++p; 20138032Speter break; 20238032Speter 20338032Speter case 'T': 20438032Speter map->map_tapp = ++p; 20538032Speter break; 20638032Speter 20738032Speter case 'k': 20838032Speter while (isascii(*++p) && isspace(*p)) 20938032Speter continue; 21038032Speter map->map_keycolnm = p; 21138032Speter break; 21238032Speter 21338032Speter case 'v': 21438032Speter while (isascii(*++p) && isspace(*p)) 21538032Speter continue; 21638032Speter map->map_valcolnm = p; 21738032Speter break; 21838032Speter 21938032Speter case 'z': 22038032Speter if (*++p != '\\') 22138032Speter map->map_coldelim = *p; 22238032Speter else 22338032Speter { 22438032Speter switch (*++p) 22538032Speter { 22638032Speter case 'n': 22738032Speter map->map_coldelim = '\n'; 22838032Speter break; 22938032Speter 23038032Speter case 't': 23138032Speter map->map_coldelim = '\t'; 23238032Speter break; 23338032Speter 23438032Speter default: 23538032Speter map->map_coldelim = '\\'; 23638032Speter } 23738032Speter } 23838032Speter break; 23938032Speter 24038032Speter case 't': 24138032Speter map->map_mflags |= MF_NODEFER; 24238032Speter break; 24338032Speter 24464562Sgshapiro 24564562Sgshapiro case 'S': 24664562Sgshapiro map->map_spacesub = *++p; 24738032Speter break; 24838032Speter 24964562Sgshapiro case 'D': 25064562Sgshapiro map->map_mflags |= MF_DEFER; 25138032Speter break; 25264562Sgshapiro 25364562Sgshapiro default: 25464562Sgshapiro syserr("Illegal option %c map %s", *p, map->map_mname); 25564562Sgshapiro break; 25638032Speter } 25738032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 25838032Speter p++; 25938032Speter if (*p != '\0') 26038032Speter *p++ = '\0'; 26138032Speter } 26238032Speter if (map->map_app != NULL) 26338032Speter map->map_app = newstr(map->map_app); 26438032Speter if (map->map_tapp != NULL) 26538032Speter map->map_tapp = newstr(map->map_tapp); 26638032Speter if (map->map_keycolnm != NULL) 26738032Speter map->map_keycolnm = newstr(map->map_keycolnm); 26838032Speter if (map->map_valcolnm != NULL) 26938032Speter map->map_valcolnm = newstr(map->map_valcolnm); 27038032Speter 27138032Speter if (*p != '\0') 27238032Speter { 27338032Speter map->map_file = p; 27438032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 27538032Speter p++; 27638032Speter if (*p != '\0') 27738032Speter *p++ = '\0'; 27838032Speter map->map_file = newstr(map->map_file); 27938032Speter } 28038032Speter 28138032Speter while (*p != '\0' && isascii(*p) && isspace(*p)) 28238032Speter p++; 28338032Speter if (*p != '\0') 28438032Speter map->map_rebuild = newstr(p); 28538032Speter 28638032Speter if (map->map_file == NULL && 28738032Speter !bitset(MCF_OPTFILE, map->map_class->map_cflags)) 28838032Speter { 28938032Speter syserr("No file name for %s map %s", 29038032Speter map->map_class->map_cname, map->map_mname); 29138032Speter return FALSE; 29238032Speter } 29338032Speter return TRUE; 29438032Speter} 29538032Speter/* 29638032Speter** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 29738032Speter** 29838032Speter** It also adds the map_app string. It can be used as a utility 29938032Speter** in the map_lookup method. 30038032Speter** 30138032Speter** Parameters: 30238032Speter** map -- the map that causes this. 30338032Speter** s -- the string to rewrite, NOT necessarily null terminated. 30438032Speter** slen -- the length of s. 30538032Speter** av -- arguments to interpolate into buf. 30638032Speter** 30738032Speter** Returns: 30838032Speter** Pointer to rewritten result. This is static data that 30938032Speter** should be copied if it is to be saved! 31038032Speter** 31138032Speter** Side Effects: 31238032Speter** none. 31338032Speter*/ 31438032Speter 31538032Speterchar * 31638032Spetermap_rewrite(map, s, slen, av) 31738032Speter register MAP *map; 31838032Speter register const char *s; 31938032Speter size_t slen; 32038032Speter char **av; 32138032Speter{ 32238032Speter register char *bp; 32338032Speter register char c; 32438032Speter char **avp; 32538032Speter register char *ap; 32638032Speter size_t l; 32738032Speter size_t len; 32838032Speter static size_t buflen = 0; 32938032Speter static char *buf = NULL; 33038032Speter 33138032Speter if (tTd(39, 1)) 33238032Speter { 33364562Sgshapiro dprintf("map_rewrite(%.*s), av =", (int)slen, s); 33438032Speter if (av == NULL) 33564562Sgshapiro dprintf(" (nullv)"); 33638032Speter else 33738032Speter { 33838032Speter for (avp = av; *avp != NULL; avp++) 33964562Sgshapiro dprintf("\n\t%s", *avp); 34038032Speter } 34164562Sgshapiro dprintf("\n"); 34238032Speter } 34338032Speter 34438032Speter /* count expected size of output (can safely overestimate) */ 34538032Speter l = len = slen; 34638032Speter if (av != NULL) 34738032Speter { 34838032Speter const char *sp = s; 34938032Speter 35038032Speter while (l-- > 0 && (c = *sp++) != '\0') 35138032Speter { 35238032Speter if (c != '%') 35338032Speter continue; 35438032Speter if (l-- <= 0) 35538032Speter break; 35638032Speter c = *sp++; 35738032Speter if (!(isascii(c) && isdigit(c))) 35838032Speter continue; 35938032Speter for (avp = av; --c >= '0' && *avp != NULL; avp++) 36038032Speter continue; 36138032Speter if (*avp == NULL) 36238032Speter continue; 36338032Speter len += strlen(*avp); 36438032Speter } 36538032Speter } 36638032Speter if (map->map_app != NULL) 36738032Speter len += strlen(map->map_app); 36838032Speter if (buflen < ++len) 36938032Speter { 37038032Speter /* need to malloc additional space */ 37138032Speter buflen = len; 37238032Speter if (buf != NULL) 37377349Sgshapiro sm_free(buf); 37438032Speter buf = xalloc(buflen); 37538032Speter } 37638032Speter 37738032Speter bp = buf; 37838032Speter if (av == NULL) 37938032Speter { 38064562Sgshapiro memmove(bp, s, slen); 38138032Speter bp += slen; 38264562Sgshapiro 38364562Sgshapiro /* assert(len > slen); */ 38464562Sgshapiro len -= slen; 38538032Speter } 38638032Speter else 38738032Speter { 38838032Speter while (slen-- > 0 && (c = *s++) != '\0') 38938032Speter { 39038032Speter if (c != '%') 39138032Speter { 39238032Speter pushc: 39364562Sgshapiro if (--len <= 0) 39464562Sgshapiro break; 39538032Speter *bp++ = c; 39638032Speter continue; 39738032Speter } 39838032Speter if (slen-- <= 0 || (c = *s++) == '\0') 39938032Speter c = '%'; 40038032Speter if (c == '%') 40138032Speter goto pushc; 40238032Speter if (!(isascii(c) && isdigit(c))) 40338032Speter { 40438032Speter *bp++ = '%'; 40564562Sgshapiro --len; 40638032Speter goto pushc; 40738032Speter } 40838032Speter for (avp = av; --c >= '0' && *avp != NULL; avp++) 40938032Speter continue; 41038032Speter if (*avp == NULL) 41138032Speter continue; 41238032Speter 41338032Speter /* transliterate argument into output string */ 41464562Sgshapiro for (ap = *avp; (c = *ap++) != '\0' && len > 0; --len) 41538032Speter *bp++ = c; 41638032Speter } 41738032Speter } 41864562Sgshapiro if (map->map_app != NULL && len > 0) 41964562Sgshapiro (void) strlcpy(bp, map->map_app, len); 42038032Speter else 42138032Speter *bp = '\0'; 42238032Speter if (tTd(39, 1)) 42364562Sgshapiro dprintf("map_rewrite => %s\n", buf); 42438032Speter return buf; 42538032Speter} 42638032Speter/* 42764562Sgshapiro** INITMAPS -- rebuild alias maps 42838032Speter** 42938032Speter** Parameters: 43064562Sgshapiro** none. 43138032Speter** 43238032Speter** Returns: 43338032Speter** none. 43438032Speter*/ 43538032Speter 43638032Spetervoid 43764562Sgshapiroinitmaps() 43838032Speter{ 43938032Speter#if XDEBUG 44038032Speter checkfd012("entering initmaps"); 44164562Sgshapiro#endif /* XDEBUG */ 44238032Speter stabapply(map_init, 0); 44338032Speter#if XDEBUG 44438032Speter checkfd012("exiting initmaps"); 44564562Sgshapiro#endif /* XDEBUG */ 44638032Speter} 44764562Sgshapiro/* 44864562Sgshapiro** MAP_INIT -- rebuild a map 44964562Sgshapiro** 45064562Sgshapiro** Parameters: 45164562Sgshapiro** s -- STAB entry: if map: try to rebuild 45264562Sgshapiro** unused -- unused variable 45364562Sgshapiro** 45464562Sgshapiro** Returns: 45564562Sgshapiro** none. 45664562Sgshapiro** 45764562Sgshapiro** Side Effects: 45864562Sgshapiro** will close already open rebuildable map. 45964562Sgshapiro*/ 46038032Speter 46164562Sgshapiro/* ARGSUSED1 */ 46264562Sgshapirostatic void 46364562Sgshapiromap_init(s, unused) 46438032Speter register STAB *s; 46564562Sgshapiro int unused; 46638032Speter{ 46738032Speter register MAP *map; 46838032Speter 46938032Speter /* has to be a map */ 47038032Speter if (s->s_type != ST_MAP) 47138032Speter return; 47238032Speter 47338032Speter map = &s->s_map; 47438032Speter if (!bitset(MF_VALID, map->map_mflags)) 47538032Speter return; 47638032Speter 47738032Speter if (tTd(38, 2)) 47864562Sgshapiro dprintf("map_init(%s:%s, %s)\n", 47938032Speter map->map_class->map_cname == NULL ? "NULL" : 48038032Speter map->map_class->map_cname, 48138032Speter map->map_mname == NULL ? "NULL" : map->map_mname, 48264562Sgshapiro map->map_file == NULL ? "NULL" : map->map_file); 48338032Speter 48464562Sgshapiro if (!bitset(MF_ALIAS, map->map_mflags) || 48564562Sgshapiro !bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 48638032Speter { 48738032Speter if (tTd(38, 3)) 48864562Sgshapiro dprintf("\tnot rebuildable\n"); 48938032Speter return; 49038032Speter } 49138032Speter 49238032Speter /* if already open, close it (for nested open) */ 49338032Speter if (bitset(MF_OPEN, map->map_mflags)) 49438032Speter { 49577349Sgshapiro map->map_mflags |= MF_CLOSING; 49638032Speter map->map_class->map_close(map); 49777349Sgshapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 49838032Speter } 49938032Speter 50064562Sgshapiro (void) rebuildaliases(map, FALSE); 50164562Sgshapiro return; 50264562Sgshapiro} 50364562Sgshapiro/* 50464562Sgshapiro** OPENMAP -- open a map 50564562Sgshapiro** 50664562Sgshapiro** Parameters: 50764562Sgshapiro** map -- map to open (it must not be open). 50864562Sgshapiro** 50964562Sgshapiro** Returns: 51064562Sgshapiro** whether open succeeded. 51164562Sgshapiro** 51264562Sgshapiro*/ 51364562Sgshapiro 51464562Sgshapirobool 51564562Sgshapiroopenmap(map) 51664562Sgshapiro MAP *map; 51764562Sgshapiro{ 51864562Sgshapiro bool restore = FALSE; 51964562Sgshapiro bool savehold = HoldErrs; 52064562Sgshapiro bool savequick = QuickAbort; 52164562Sgshapiro int saveerrors = Errors; 52264562Sgshapiro 52364562Sgshapiro if (!bitset(MF_VALID, map->map_mflags)) 52464562Sgshapiro return FALSE; 52564562Sgshapiro 52664562Sgshapiro /* better safe than sorry... */ 52764562Sgshapiro if (bitset(MF_OPEN, map->map_mflags)) 52864562Sgshapiro return TRUE; 52964562Sgshapiro 53064562Sgshapiro /* Don't send a map open error out via SMTP */ 53164562Sgshapiro if ((OnlyOneError || QuickAbort) && 53264562Sgshapiro (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 53338032Speter { 53464562Sgshapiro restore = TRUE; 53564562Sgshapiro HoldErrs = TRUE; 53664562Sgshapiro QuickAbort = FALSE; 53738032Speter } 53838032Speter 53964562Sgshapiro errno = 0; 54038032Speter if (map->map_class->map_open(map, O_RDONLY)) 54138032Speter { 54238032Speter if (tTd(38, 4)) 54364562Sgshapiro dprintf("openmap()\t%s:%s %s: valid\n", 54438032Speter map->map_class->map_cname == NULL ? "NULL" : 54538032Speter map->map_class->map_cname, 54638032Speter map->map_mname == NULL ? "NULL" : 54738032Speter map->map_mname, 54838032Speter map->map_file == NULL ? "NULL" : 54938032Speter map->map_file); 55038032Speter map->map_mflags |= MF_OPEN; 55142575Speter map->map_pid = getpid(); 55238032Speter } 55338032Speter else 55438032Speter { 55538032Speter if (tTd(38, 4)) 55664562Sgshapiro dprintf("openmap()\t%s:%s %s: invalid%s%s\n", 55738032Speter map->map_class->map_cname == NULL ? "NULL" : 55838032Speter map->map_class->map_cname, 55938032Speter map->map_mname == NULL ? "NULL" : 56038032Speter map->map_mname, 56138032Speter map->map_file == NULL ? "NULL" : 56238032Speter map->map_file, 56364562Sgshapiro errno == 0 ? "" : ": ", 56464562Sgshapiro errno == 0 ? "" : errstring(errno)); 56538032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 56638032Speter { 56738032Speter extern MAPCLASS BogusMapClass; 56838032Speter 56938032Speter map->map_class = &BogusMapClass; 57038032Speter map->map_mflags |= MF_OPEN; 57142575Speter map->map_pid = getpid(); 57266494Sgshapiro MapOpenErr = TRUE; 57338032Speter } 57464562Sgshapiro else 57564562Sgshapiro { 57664562Sgshapiro /* don't try again */ 57764562Sgshapiro map->map_mflags &= ~MF_VALID; 57864562Sgshapiro } 57938032Speter } 58064562Sgshapiro 58164562Sgshapiro if (restore) 58264562Sgshapiro { 58364562Sgshapiro Errors = saveerrors; 58464562Sgshapiro HoldErrs = savehold; 58564562Sgshapiro QuickAbort = savequick; 58664562Sgshapiro } 58764562Sgshapiro 58864562Sgshapiro return bitset(MF_OPEN, map->map_mflags); 58938032Speter} 59038032Speter/* 59142575Speter** CLOSEMAPS -- close all open maps opened by the current pid. 59242575Speter** 59342575Speter** Parameters: 59442575Speter** none 59542575Speter** 59642575Speter** Returns: 59742575Speter** none. 59842575Speter*/ 59942575Speter 60042575Spetervoid 60142575Speterclosemaps() 60242575Speter{ 60342575Speter stabapply(map_close, 0); 60442575Speter} 60564562Sgshapiro/* 60664562Sgshapiro** MAP_CLOSE -- close a map opened by the current pid. 60764562Sgshapiro** 60864562Sgshapiro** Parameters: 60964562Sgshapiro** s -- STAB entry: if map: try to open 61064562Sgshapiro** second parameter is unused (required by stabapply()) 61164562Sgshapiro** 61264562Sgshapiro** Returns: 61364562Sgshapiro** none. 61464562Sgshapiro*/ 61542575Speter 61642575Speter/* ARGSUSED1 */ 61764562Sgshapirostatic void 61842575Spetermap_close(s, unused) 61942575Speter register STAB *s; 62042575Speter int unused; 62142575Speter{ 62242575Speter MAP *map; 62342575Speter 62442575Speter if (s->s_type != ST_MAP) 62542575Speter return; 62664562Sgshapiro 62742575Speter map = &s->s_map; 62842575Speter 62942575Speter if (!bitset(MF_VALID, map->map_mflags) || 63042575Speter !bitset(MF_OPEN, map->map_mflags) || 63177349Sgshapiro bitset(MF_CLOSING, map->map_mflags) || 63242575Speter map->map_pid != getpid()) 63342575Speter return; 63464562Sgshapiro 63542575Speter if (tTd(38, 5)) 63664562Sgshapiro dprintf("closemaps: closing %s (%s)\n", 63764562Sgshapiro map->map_mname == NULL ? "NULL" : map->map_mname, 63864562Sgshapiro map->map_file == NULL ? "NULL" : map->map_file); 63964562Sgshapiro 64077349Sgshapiro map->map_mflags |= MF_CLOSING; 64142575Speter map->map_class->map_close(map); 64277349Sgshapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 64342575Speter} 64442575Speter/* 64538032Speter** GETCANONNAME -- look up name using service switch 64638032Speter** 64738032Speter** Parameters: 64838032Speter** host -- the host name to look up. 64938032Speter** hbsize -- the size of the host buffer. 65038032Speter** trymx -- if set, try MX records. 65138032Speter** 65238032Speter** Returns: 65338032Speter** TRUE -- if the host was found. 65438032Speter** FALSE -- otherwise. 65538032Speter*/ 65638032Speter 65738032Speterbool 65838032Spetergetcanonname(host, hbsize, trymx) 65938032Speter char *host; 66038032Speter int hbsize; 66138032Speter bool trymx; 66238032Speter{ 66338032Speter int nmaps; 66438032Speter int mapno; 66538032Speter bool found = FALSE; 66638032Speter bool got_tempfail = FALSE; 66764562Sgshapiro auto int status; 66838032Speter char *maptype[MAXMAPSTACK]; 66938032Speter short mapreturn[MAXMAPACTIONS]; 67038032Speter 67138032Speter nmaps = switch_map_find("hosts", maptype, mapreturn); 67238032Speter for (mapno = 0; mapno < nmaps; mapno++) 67338032Speter { 67438032Speter int i; 67538032Speter 67638032Speter if (tTd(38, 20)) 67764562Sgshapiro dprintf("getcanonname(%s), trying %s\n", 67838032Speter host, maptype[mapno]); 67938032Speter if (strcmp("files", maptype[mapno]) == 0) 68038032Speter { 68164562Sgshapiro found = text_getcanonname(host, hbsize, &status); 68238032Speter } 68338032Speter#ifdef NIS 68438032Speter else if (strcmp("nis", maptype[mapno]) == 0) 68538032Speter { 68664562Sgshapiro found = nis_getcanonname(host, hbsize, &status); 68738032Speter } 68864562Sgshapiro#endif /* NIS */ 68938032Speter#ifdef NISPLUS 69038032Speter else if (strcmp("nisplus", maptype[mapno]) == 0) 69138032Speter { 69264562Sgshapiro found = nisplus_getcanonname(host, hbsize, &status); 69338032Speter } 69464562Sgshapiro#endif /* NISPLUS */ 69538032Speter#if NAMED_BIND 69638032Speter else if (strcmp("dns", maptype[mapno]) == 0) 69738032Speter { 69864562Sgshapiro found = dns_getcanonname(host, hbsize, trymx, &status); 69938032Speter } 70064562Sgshapiro#endif /* NAMED_BIND */ 70138032Speter#if NETINFO 70238032Speter else if (strcmp("netinfo", maptype[mapno]) == 0) 70338032Speter { 70464562Sgshapiro found = ni_getcanonname(host, hbsize, &status); 70538032Speter } 70664562Sgshapiro#endif /* NETINFO */ 70738032Speter else 70838032Speter { 70938032Speter found = FALSE; 71064562Sgshapiro status = EX_UNAVAILABLE; 71138032Speter } 71238032Speter 71338032Speter /* 71438032Speter ** Heuristic: if $m is not set, we are running during system 71538032Speter ** startup. In this case, when a name is apparently found 71638032Speter ** but has no dot, treat is as not found. This avoids 71738032Speter ** problems if /etc/hosts has no FQDN but is listed first 71838032Speter ** in the service switch. 71938032Speter */ 72038032Speter 72138032Speter if (found && 72238032Speter (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL)) 72338032Speter break; 72438032Speter 72538032Speter /* see if we should continue */ 72664562Sgshapiro if (status == EX_TEMPFAIL) 72738032Speter { 72838032Speter i = MA_TRYAGAIN; 72938032Speter got_tempfail = TRUE; 73038032Speter } 73164562Sgshapiro else if (status == EX_NOTFOUND) 73238032Speter i = MA_NOTFOUND; 73338032Speter else 73438032Speter i = MA_UNAVAIL; 73538032Speter if (bitset(1 << mapno, mapreturn[i])) 73638032Speter break; 73738032Speter } 73838032Speter 73938032Speter if (found) 74038032Speter { 74138032Speter char *d; 74238032Speter 74338032Speter if (tTd(38, 20)) 74464562Sgshapiro dprintf("getcanonname(%s), found\n", host); 74538032Speter 74638032Speter /* 74738032Speter ** If returned name is still single token, compensate 74838032Speter ** by tagging on $m. This is because some sites set 74938032Speter ** up their DNS or NIS databases wrong. 75038032Speter */ 75138032Speter 75238032Speter if ((d = strchr(host, '.')) == NULL || d[1] == '\0') 75338032Speter { 75438032Speter d = macvalue('m', CurEnv); 75538032Speter if (d != NULL && 75638032Speter hbsize > (int) (strlen(host) + strlen(d) + 1)) 75738032Speter { 75838032Speter if (host[strlen(host) - 1] != '.') 75964562Sgshapiro (void) strlcat(host, ".", hbsize); 76064562Sgshapiro (void) strlcat(host, d, hbsize); 76138032Speter } 76238032Speter else 76338032Speter return FALSE; 76438032Speter } 76538032Speter return TRUE; 76638032Speter } 76738032Speter 76838032Speter if (tTd(38, 20)) 76964562Sgshapiro dprintf("getcanonname(%s), failed, status=%d\n", host, status); 77038032Speter 77138032Speter#if NAMED_BIND 77238032Speter if (got_tempfail) 77373188Sgshapiro SM_SET_H_ERRNO(TRY_AGAIN); 77438032Speter else 77573188Sgshapiro SM_SET_H_ERRNO(HOST_NOT_FOUND); 77664562Sgshapiro#endif /* NAMED_BIND */ 77738032Speter return FALSE; 77838032Speter} 77938032Speter/* 78038032Speter** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry 78138032Speter** 78238032Speter** Parameters: 78338032Speter** name -- the name against which to match. 78473188Sgshapiro** dot -- where to reinsert '.' to get FQDN 78538032Speter** line -- the /etc/hosts line. 78638032Speter** cbuf -- the location to store the result. 78738032Speter** cbuflen -- the size of cbuf. 78838032Speter** 78938032Speter** Returns: 79038032Speter** TRUE -- if the line matched the desired name. 79138032Speter** FALSE -- otherwise. 79238032Speter*/ 79338032Speter 79464562Sgshapirostatic bool 79573188Sgshapiroextract_canonname(name, dot, line, cbuf, cbuflen) 79638032Speter char *name; 79773188Sgshapiro char *dot; 79838032Speter char *line; 79938032Speter char cbuf[]; 80038032Speter int cbuflen; 80138032Speter{ 80238032Speter int i; 80338032Speter char *p; 80438032Speter bool found = FALSE; 80538032Speter 80638032Speter cbuf[0] = '\0'; 80738032Speter if (line[0] == '#') 80838032Speter return FALSE; 80938032Speter 81038032Speter for (i = 1; ; i++) 81138032Speter { 81238032Speter char nbuf[MAXNAME + 1]; 81338032Speter 81438032Speter p = get_column(line, i, '\0', nbuf, sizeof nbuf); 81538032Speter if (p == NULL) 81638032Speter break; 81738032Speter if (*p == '\0') 81838032Speter continue; 81938032Speter if (cbuf[0] == '\0' || 82038032Speter (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL)) 82138032Speter { 82238032Speter snprintf(cbuf, cbuflen, "%s", p); 82338032Speter } 82438032Speter if (strcasecmp(name, p) == 0) 82538032Speter found = TRUE; 82673188Sgshapiro else if (dot != NULL) 82773188Sgshapiro { 82873188Sgshapiro /* try looking for the FQDN as well */ 82973188Sgshapiro *dot = '.'; 83073188Sgshapiro if (strcasecmp(name, p) == 0) 83173188Sgshapiro found = TRUE; 83273188Sgshapiro *dot = '\0'; 83373188Sgshapiro } 83438032Speter } 83538032Speter if (found && strchr(cbuf, '.') == NULL) 83638032Speter { 83738032Speter /* try to add a domain on the end of the name */ 83838032Speter char *domain = macvalue('m', CurEnv); 83938032Speter 84038032Speter if (domain != NULL && 84164562Sgshapiro strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen) 84238032Speter { 84364562Sgshapiro p = &cbuf[i]; 84438032Speter *p++ = '.'; 84564562Sgshapiro (void) strlcpy(p, domain, cbuflen - i - 1); 84638032Speter } 84738032Speter } 84838032Speter return found; 84938032Speter} 85038032Speter/* 85138032Speter** NDBM modules 85238032Speter*/ 85338032Speter 85438032Speter#ifdef NDBM 85538032Speter 85638032Speter/* 85738032Speter** NDBM_MAP_OPEN -- DBM-style map open 85838032Speter*/ 85938032Speter 86038032Speterbool 86138032Speterndbm_map_open(map, mode) 86238032Speter MAP *map; 86338032Speter int mode; 86438032Speter{ 86538032Speter register DBM *dbm; 86664562Sgshapiro int save_errno; 86738032Speter int dfd; 86838032Speter int pfd; 86964562Sgshapiro long sff; 87038032Speter int ret; 87138032Speter int smode = S_IREAD; 87238032Speter char dirfile[MAXNAME + 1]; 87338032Speter char pagfile[MAXNAME + 1]; 87464562Sgshapiro struct stat st; 87538032Speter struct stat std, stp; 87638032Speter 87738032Speter if (tTd(38, 2)) 87864562Sgshapiro dprintf("ndbm_map_open(%s, %s, %d)\n", 87938032Speter map->map_mname, map->map_file, mode); 88038032Speter map->map_lockfd = -1; 88138032Speter mode &= O_ACCMODE; 88238032Speter 88338032Speter /* do initial file and directory checks */ 88438032Speter snprintf(dirfile, sizeof dirfile, "%s.dir", map->map_file); 88538032Speter snprintf(pagfile, sizeof pagfile, "%s.pag", map->map_file); 88638032Speter sff = SFF_ROOTOK|SFF_REGONLY; 88738032Speter if (mode == O_RDWR) 88838032Speter { 88938032Speter sff |= SFF_CREAT; 89064562Sgshapiro if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 89138032Speter sff |= SFF_NOSLINK; 89264562Sgshapiro if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 89338032Speter sff |= SFF_NOHLINK; 89438032Speter smode = S_IWRITE; 89538032Speter } 89638032Speter else 89738032Speter { 89864562Sgshapiro if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 89938032Speter sff |= SFF_NOWLINK; 90038032Speter } 90164562Sgshapiro if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail)) 90238032Speter sff |= SFF_SAFEDIRPATH; 90338032Speter ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName, 90438032Speter sff, smode, &std); 90538032Speter if (ret == 0) 90638032Speter ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName, 90738032Speter sff, smode, &stp); 90864562Sgshapiro 90964562Sgshapiro# if !_FFR_REMOVE_AUTOREBUILD 91038032Speter if (ret == ENOENT && AutoRebuild && 91138032Speter bitset(MCF_REBUILDABLE, map->map_class->map_cflags) && 91238032Speter (bitset(MF_IMPL_NDBM, map->map_mflags) || 91338032Speter bitset(MF_ALIAS, map->map_mflags)) && 91438032Speter mode == O_RDONLY) 91538032Speter { 91638032Speter bool impl = bitset(MF_IMPL_NDBM, map->map_mflags); 91738032Speter 91838032Speter /* may be able to rebuild */ 91938032Speter map->map_mflags &= ~MF_IMPL_NDBM; 92038032Speter if (!rebuildaliases(map, TRUE)) 92138032Speter return FALSE; 92238032Speter if (impl) 92338032Speter return impl_map_open(map, O_RDONLY); 92438032Speter else 92538032Speter return ndbm_map_open(map, O_RDONLY); 92638032Speter } 92764562Sgshapiro# endif /* !_FFR_REMOVE_AUTOREBUILD */ 92864562Sgshapiro 92938032Speter if (ret != 0) 93038032Speter { 93138032Speter char *prob = "unsafe"; 93238032Speter 93338032Speter /* cannot open this map */ 93438032Speter if (ret == ENOENT) 93538032Speter prob = "missing"; 93638032Speter if (tTd(38, 2)) 93764562Sgshapiro dprintf("\t%s map file: %d\n", prob, ret); 93838032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 93938032Speter syserr("dbm map \"%s\": %s map file %s", 94038032Speter map->map_mname, prob, map->map_file); 94138032Speter return FALSE; 94238032Speter } 94338032Speter if (std.st_mode == ST_MODE_NOFILE) 94438032Speter mode |= O_CREAT|O_EXCL; 94538032Speter 94664562Sgshapiro# if LOCK_ON_OPEN 94738032Speter if (mode == O_RDONLY) 94838032Speter mode |= O_SHLOCK; 94938032Speter else 95038032Speter mode |= O_TRUNC|O_EXLOCK; 95164562Sgshapiro# else /* LOCK_ON_OPEN */ 95238032Speter if ((mode & O_ACCMODE) == O_RDWR) 95338032Speter { 95464562Sgshapiro# if NOFTRUNCATE 95538032Speter /* 95638032Speter ** Warning: race condition. Try to lock the file as 95738032Speter ** quickly as possible after opening it. 95838032Speter ** This may also have security problems on some systems, 95938032Speter ** but there isn't anything we can do about it. 96038032Speter */ 96138032Speter 96238032Speter mode |= O_TRUNC; 96364562Sgshapiro# else /* NOFTRUNCATE */ 96438032Speter /* 96538032Speter ** This ugly code opens the map without truncating it, 96638032Speter ** locks the file, then truncates it. Necessary to 96738032Speter ** avoid race conditions. 96838032Speter */ 96938032Speter 97038032Speter int dirfd; 97138032Speter int pagfd; 97264562Sgshapiro long sff = SFF_CREAT|SFF_OPENASROOT; 97338032Speter 97464562Sgshapiro if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 97538032Speter sff |= SFF_NOSLINK; 97664562Sgshapiro if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 97738032Speter sff |= SFF_NOHLINK; 97838032Speter 97938032Speter dirfd = safeopen(dirfile, mode, DBMMODE, sff); 98038032Speter pagfd = safeopen(pagfile, mode, DBMMODE, sff); 98138032Speter 98238032Speter if (dirfd < 0 || pagfd < 0) 98338032Speter { 98464562Sgshapiro save_errno = errno; 98538032Speter if (dirfd >= 0) 98638032Speter (void) close(dirfd); 98738032Speter if (pagfd >= 0) 98838032Speter (void) close(pagfd); 98938032Speter errno = save_errno; 99038032Speter syserr("ndbm_map_open: cannot create database %s", 99138032Speter map->map_file); 99238032Speter return FALSE; 99338032Speter } 99438032Speter if (ftruncate(dirfd, (off_t) 0) < 0 || 99538032Speter ftruncate(pagfd, (off_t) 0) < 0) 99638032Speter { 99764562Sgshapiro save_errno = errno; 99838032Speter (void) close(dirfd); 99938032Speter (void) close(pagfd); 100038032Speter errno = save_errno; 100138032Speter syserr("ndbm_map_open: cannot truncate %s.{dir,pag}", 100238032Speter map->map_file); 100338032Speter return FALSE; 100438032Speter } 100538032Speter 100638032Speter /* if new file, get "before" bits for later filechanged check */ 100738032Speter if (std.st_mode == ST_MODE_NOFILE && 100838032Speter (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0)) 100938032Speter { 101064562Sgshapiro save_errno = errno; 101138032Speter (void) close(dirfd); 101238032Speter (void) close(pagfd); 101338032Speter errno = save_errno; 101438032Speter syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file", 101538032Speter map->map_file); 101638032Speter return FALSE; 101738032Speter } 101838032Speter 101938032Speter /* have to save the lock for the duration (bletch) */ 102038032Speter map->map_lockfd = dirfd; 102164562Sgshapiro (void) close(pagfd); 102238032Speter 102338032Speter /* twiddle bits for dbm_open */ 102438032Speter mode &= ~(O_CREAT|O_EXCL); 102564562Sgshapiro# endif /* NOFTRUNCATE */ 102638032Speter } 102764562Sgshapiro# endif /* LOCK_ON_OPEN */ 102838032Speter 102938032Speter /* open the database */ 103038032Speter dbm = dbm_open(map->map_file, mode, DBMMODE); 103138032Speter if (dbm == NULL) 103238032Speter { 103364562Sgshapiro save_errno = errno; 103438032Speter if (bitset(MF_ALIAS, map->map_mflags) && 103538032Speter aliaswait(map, ".pag", FALSE)) 103638032Speter return TRUE; 103764562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE 103838032Speter if (map->map_lockfd >= 0) 103964562Sgshapiro (void) close(map->map_lockfd); 104064562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */ 104138032Speter errno = save_errno; 104238032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 104338032Speter syserr("Cannot open DBM database %s", map->map_file); 104438032Speter return FALSE; 104538032Speter } 104638032Speter dfd = dbm_dirfno(dbm); 104738032Speter pfd = dbm_pagfno(dbm); 104838032Speter if (dfd == pfd) 104938032Speter { 105038032Speter /* heuristic: if files are linked, this is actually gdbm */ 105138032Speter dbm_close(dbm); 105264562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE 105338032Speter if (map->map_lockfd >= 0) 105464562Sgshapiro (void) close(map->map_lockfd); 105564562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */ 105638032Speter errno = 0; 105738032Speter syserr("dbm map \"%s\": cannot support GDBM", 105838032Speter map->map_mname); 105938032Speter return FALSE; 106038032Speter } 106138032Speter 106238032Speter if (filechanged(dirfile, dfd, &std) || 106338032Speter filechanged(pagfile, pfd, &stp)) 106438032Speter { 106564562Sgshapiro save_errno = errno; 106638032Speter dbm_close(dbm); 106764562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE 106838032Speter if (map->map_lockfd >= 0) 106964562Sgshapiro (void) close(map->map_lockfd); 107064562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */ 107138032Speter errno = save_errno; 107238032Speter syserr("ndbm_map_open(%s): file changed after open", 107338032Speter map->map_file); 107438032Speter return FALSE; 107538032Speter } 107638032Speter 107738032Speter map->map_db1 = (ARBPTR_T) dbm; 107864562Sgshapiro 107964562Sgshapiro /* 108064562Sgshapiro ** Need to set map_mtime before the call to aliaswait() 108164562Sgshapiro ** as aliaswait() will call map_lookup() which requires 108264562Sgshapiro ** map_mtime to be set 108364562Sgshapiro */ 108464562Sgshapiro 108577349Sgshapiro if (fstat(pfd, &st) >= 0) 108664562Sgshapiro map->map_mtime = st.st_mtime; 108764562Sgshapiro 108838032Speter if (mode == O_RDONLY) 108938032Speter { 109064562Sgshapiro# if LOCK_ON_OPEN 109138032Speter if (dfd >= 0) 109238032Speter (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN); 109338032Speter if (pfd >= 0) 109438032Speter (void) lockfile(pfd, map->map_file, ".pag", LOCK_UN); 109564562Sgshapiro# endif /* LOCK_ON_OPEN */ 109638032Speter if (bitset(MF_ALIAS, map->map_mflags) && 109738032Speter !aliaswait(map, ".pag", TRUE)) 109838032Speter return FALSE; 109938032Speter } 110038032Speter else 110138032Speter { 110238032Speter map->map_mflags |= MF_LOCKED; 110342575Speter if (geteuid() == 0 && TrustedUid != 0) 110438032Speter { 110564562Sgshapiro# if HASFCHOWN 110642575Speter if (fchown(dfd, TrustedUid, -1) < 0 || 110742575Speter fchown(pfd, TrustedUid, -1) < 0) 110838032Speter { 110938032Speter int err = errno; 111038032Speter 111138032Speter sm_syslog(LOG_ALERT, NOQID, 111238032Speter "ownership change on %s failed: %s", 111338032Speter map->map_file, errstring(err)); 111438032Speter message("050 ownership change on %s failed: %s", 111538032Speter map->map_file, errstring(err)); 111638032Speter } 111764562Sgshapiro# endif /* HASFCHOWN */ 111838032Speter } 111938032Speter } 112038032Speter return TRUE; 112138032Speter} 112238032Speter 112338032Speter 112438032Speter/* 112538032Speter** NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map 112638032Speter*/ 112738032Speter 112838032Speterchar * 112938032Speterndbm_map_lookup(map, name, av, statp) 113038032Speter MAP *map; 113138032Speter char *name; 113238032Speter char **av; 113338032Speter int *statp; 113438032Speter{ 113538032Speter datum key, val; 113677349Sgshapiro int dfd, pfd; 113738032Speter char keybuf[MAXNAME + 1]; 113838032Speter struct stat stbuf; 113938032Speter 114038032Speter if (tTd(38, 20)) 114164562Sgshapiro dprintf("ndbm_map_lookup(%s, %s)\n", 114238032Speter map->map_mname, name); 114338032Speter 114438032Speter key.dptr = name; 114538032Speter key.dsize = strlen(name); 114638032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 114738032Speter { 114838032Speter if (key.dsize > sizeof keybuf - 1) 114938032Speter key.dsize = sizeof keybuf - 1; 115064562Sgshapiro memmove(keybuf, key.dptr, key.dsize); 115138032Speter keybuf[key.dsize] = '\0'; 115238032Speter makelower(keybuf); 115338032Speter key.dptr = keybuf; 115438032Speter } 115538032Speterlockdbm: 115677349Sgshapiro dfd = dbm_dirfno((DBM *) map->map_db1); 115777349Sgshapiro if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 115877349Sgshapiro (void) lockfile(dfd, map->map_file, ".dir", LOCK_SH); 115977349Sgshapiro pfd = dbm_pagfno((DBM *) map->map_db1); 116077349Sgshapiro if (pfd < 0 || fstat(pfd, &stbuf) < 0 || 116177349Sgshapiro stbuf.st_mtime > map->map_mtime) 116238032Speter { 116338032Speter /* Reopen the database to sync the cache */ 116438032Speter int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR 116538032Speter : O_RDONLY; 116638032Speter 116777349Sgshapiro if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 116877349Sgshapiro (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN); 116977349Sgshapiro map->map_mflags |= MF_CLOSING; 117038032Speter map->map_class->map_close(map); 117177349Sgshapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 117238032Speter if (map->map_class->map_open(map, omode)) 117338032Speter { 117438032Speter map->map_mflags |= MF_OPEN; 117542575Speter map->map_pid = getpid(); 117638032Speter if ((omode && O_ACCMODE) == O_RDWR) 117738032Speter map->map_mflags |= MF_WRITABLE; 117838032Speter goto lockdbm; 117938032Speter } 118038032Speter else 118138032Speter { 118238032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 118338032Speter { 118438032Speter extern MAPCLASS BogusMapClass; 118538032Speter 118638032Speter *statp = EX_TEMPFAIL; 118738032Speter map->map_class = &BogusMapClass; 118838032Speter map->map_mflags |= MF_OPEN; 118942575Speter map->map_pid = getpid(); 119038032Speter syserr("Cannot reopen NDBM database %s", 119138032Speter map->map_file); 119238032Speter } 119338032Speter return NULL; 119438032Speter } 119538032Speter } 119638032Speter val.dptr = NULL; 119738032Speter if (bitset(MF_TRY0NULL, map->map_mflags)) 119838032Speter { 119938032Speter val = dbm_fetch((DBM *) map->map_db1, key); 120038032Speter if (val.dptr != NULL) 120138032Speter map->map_mflags &= ~MF_TRY1NULL; 120238032Speter } 120338032Speter if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags)) 120438032Speter { 120538032Speter key.dsize++; 120638032Speter val = dbm_fetch((DBM *) map->map_db1, key); 120738032Speter if (val.dptr != NULL) 120838032Speter map->map_mflags &= ~MF_TRY0NULL; 120938032Speter } 121077349Sgshapiro if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 121177349Sgshapiro (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN); 121238032Speter if (val.dptr == NULL) 121338032Speter return NULL; 121438032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 121538032Speter return map_rewrite(map, name, strlen(name), NULL); 121638032Speter else 121738032Speter return map_rewrite(map, val.dptr, val.dsize, av); 121838032Speter} 121938032Speter 122038032Speter 122138032Speter/* 122238032Speter** NDBM_MAP_STORE -- store a datum in the database 122338032Speter*/ 122438032Speter 122538032Spetervoid 122638032Speterndbm_map_store(map, lhs, rhs) 122738032Speter register MAP *map; 122838032Speter char *lhs; 122938032Speter char *rhs; 123038032Speter{ 123138032Speter datum key; 123238032Speter datum data; 123364562Sgshapiro int status; 123438032Speter char keybuf[MAXNAME + 1]; 123538032Speter 123638032Speter if (tTd(38, 12)) 123764562Sgshapiro dprintf("ndbm_map_store(%s, %s, %s)\n", 123838032Speter map->map_mname, lhs, rhs); 123938032Speter 124038032Speter key.dsize = strlen(lhs); 124138032Speter key.dptr = lhs; 124238032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 124338032Speter { 124438032Speter if (key.dsize > sizeof keybuf - 1) 124538032Speter key.dsize = sizeof keybuf - 1; 124664562Sgshapiro memmove(keybuf, key.dptr, key.dsize); 124738032Speter keybuf[key.dsize] = '\0'; 124838032Speter makelower(keybuf); 124938032Speter key.dptr = keybuf; 125038032Speter } 125138032Speter 125238032Speter data.dsize = strlen(rhs); 125338032Speter data.dptr = rhs; 125438032Speter 125538032Speter if (bitset(MF_INCLNULL, map->map_mflags)) 125638032Speter { 125738032Speter key.dsize++; 125838032Speter data.dsize++; 125938032Speter } 126038032Speter 126164562Sgshapiro status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); 126264562Sgshapiro if (status > 0) 126338032Speter { 126438032Speter if (!bitset(MF_APPEND, map->map_mflags)) 126538032Speter message("050 Warning: duplicate alias name %s", lhs); 126638032Speter else 126738032Speter { 126838032Speter static char *buf = NULL; 126938032Speter static int bufsiz = 0; 127038032Speter auto int xstat; 127138032Speter datum old; 127238032Speter 127338032Speter old.dptr = ndbm_map_lookup(map, key.dptr, 127438032Speter (char **)NULL, &xstat); 127538032Speter if (old.dptr != NULL && *(char *) old.dptr != '\0') 127638032Speter { 127738032Speter old.dsize = strlen(old.dptr); 127838032Speter if (data.dsize + old.dsize + 2 > bufsiz) 127938032Speter { 128038032Speter if (buf != NULL) 128177349Sgshapiro sm_free(buf); 128238032Speter bufsiz = data.dsize + old.dsize + 2; 128338032Speter buf = xalloc(bufsiz); 128438032Speter } 128538032Speter snprintf(buf, bufsiz, "%s,%s", 128638032Speter data.dptr, old.dptr); 128738032Speter data.dsize = data.dsize + old.dsize + 1; 128838032Speter data.dptr = buf; 128938032Speter if (tTd(38, 9)) 129064562Sgshapiro dprintf("ndbm_map_store append=%s\n", 129164562Sgshapiro data.dptr); 129238032Speter } 129338032Speter } 129464562Sgshapiro status = dbm_store((DBM *) map->map_db1, 129564562Sgshapiro key, data, DBM_REPLACE); 129638032Speter } 129764562Sgshapiro if (status != 0) 129864562Sgshapiro syserr("readaliases: dbm put (%s): %d", lhs, status); 129938032Speter} 130038032Speter 130138032Speter 130238032Speter/* 130338032Speter** NDBM_MAP_CLOSE -- close the database 130438032Speter*/ 130538032Speter 130638032Spetervoid 130738032Speterndbm_map_close(map) 130838032Speter register MAP *map; 130938032Speter{ 131038032Speter if (tTd(38, 9)) 131164562Sgshapiro dprintf("ndbm_map_close(%s, %s, %lx)\n", 131238032Speter map->map_mname, map->map_file, map->map_mflags); 131338032Speter 131438032Speter if (bitset(MF_WRITABLE, map->map_mflags)) 131538032Speter { 131664562Sgshapiro# ifdef NDBM_YP_COMPAT 131738032Speter bool inclnull; 131842575Speter char buf[MAXHOSTNAMELEN]; 131938032Speter 132038032Speter inclnull = bitset(MF_INCLNULL, map->map_mflags); 132138032Speter map->map_mflags &= ~MF_INCLNULL; 132238032Speter 132338032Speter if (strstr(map->map_file, "/yp/") != NULL) 132438032Speter { 132538032Speter long save_mflags = map->map_mflags; 132638032Speter 132738032Speter map->map_mflags |= MF_NOFOLDCASE; 132838032Speter 132938032Speter (void) snprintf(buf, sizeof buf, "%010ld", curtime()); 133038032Speter ndbm_map_store(map, "YP_LAST_MODIFIED", buf); 133138032Speter 133238032Speter (void) gethostname(buf, sizeof buf); 133338032Speter ndbm_map_store(map, "YP_MASTER_NAME", buf); 133438032Speter 133538032Speter map->map_mflags = save_mflags; 133638032Speter } 133738032Speter 133838032Speter if (inclnull) 133938032Speter map->map_mflags |= MF_INCLNULL; 134064562Sgshapiro# endif /* NDBM_YP_COMPAT */ 134138032Speter 134238032Speter /* write out the distinguished alias */ 134338032Speter ndbm_map_store(map, "@", "@"); 134438032Speter } 134538032Speter dbm_close((DBM *) map->map_db1); 134638032Speter 134738032Speter /* release lock (if needed) */ 134864562Sgshapiro# if !LOCK_ON_OPEN 134938032Speter if (map->map_lockfd >= 0) 135038032Speter (void) close(map->map_lockfd); 135164562Sgshapiro# endif /* !LOCK_ON_OPEN */ 135238032Speter} 135338032Speter 135464562Sgshapiro#endif /* NDBM */ 135538032Speter/* 135638032Speter** NEWDB (Hash and BTree) Modules 135738032Speter*/ 135838032Speter 135938032Speter#ifdef NEWDB 136038032Speter 136138032Speter/* 136238032Speter** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. 136338032Speter** 136438032Speter** These do rather bizarre locking. If you can lock on open, 136538032Speter** do that to avoid the condition of opening a database that 136638032Speter** is being rebuilt. If you don't, we'll try to fake it, but 136738032Speter** there will be a race condition. If opening for read-only, 136838032Speter** we immediately release the lock to avoid freezing things up. 136938032Speter** We really ought to hold the lock, but guarantee that we won't 137038032Speter** be pokey about it. That's hard to do. 137138032Speter*/ 137238032Speter 137338032Speter/* these should be K line arguments */ 137464562Sgshapiro# if DB_VERSION_MAJOR < 2 137564562Sgshapiro# define db_cachesize cachesize 137664562Sgshapiro# define h_nelem nelem 137764562Sgshapiro# ifndef DB_CACHE_SIZE 137864562Sgshapiro# define DB_CACHE_SIZE (1024 * 1024) /* database memory cache size */ 137964562Sgshapiro# endif /* ! DB_CACHE_SIZE */ 138064562Sgshapiro# ifndef DB_HASH_NELEM 138164562Sgshapiro# define DB_HASH_NELEM 4096 /* (starting) size of hash table */ 138264562Sgshapiro# endif /* ! DB_HASH_NELEM */ 138364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 138438032Speter 138538032Speterbool 138638032Speterbt_map_open(map, mode) 138738032Speter MAP *map; 138838032Speter int mode; 138938032Speter{ 139064562Sgshapiro# if DB_VERSION_MAJOR < 2 139138032Speter BTREEINFO btinfo; 139264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 139364562Sgshapiro# if DB_VERSION_MAJOR == 2 139438032Speter DB_INFO btinfo; 139564562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */ 139664562Sgshapiro# if DB_VERSION_MAJOR > 2 139764562Sgshapiro void *btinfo = NULL; 139864562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 139938032Speter 140038032Speter if (tTd(38, 2)) 140164562Sgshapiro dprintf("bt_map_open(%s, %s, %d)\n", 140238032Speter map->map_mname, map->map_file, mode); 140338032Speter 140464562Sgshapiro# if DB_VERSION_MAJOR < 3 140564562Sgshapiro memset(&btinfo, '\0', sizeof btinfo); 140664562Sgshapiro# ifdef DB_CACHE_SIZE 140738032Speter btinfo.db_cachesize = DB_CACHE_SIZE; 140864562Sgshapiro# endif /* DB_CACHE_SIZE */ 140964562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */ 141064562Sgshapiro 141138032Speter return db_map_open(map, mode, "btree", DB_BTREE, &btinfo); 141238032Speter} 141338032Speter 141438032Speterbool 141538032Speterhash_map_open(map, mode) 141638032Speter MAP *map; 141738032Speter int mode; 141838032Speter{ 141964562Sgshapiro# if DB_VERSION_MAJOR < 2 142038032Speter HASHINFO hinfo; 142164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 142264562Sgshapiro# if DB_VERSION_MAJOR == 2 142338032Speter DB_INFO hinfo; 142464562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */ 142564562Sgshapiro# if DB_VERSION_MAJOR > 2 142664562Sgshapiro void *hinfo = NULL; 142764562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 142838032Speter 142938032Speter if (tTd(38, 2)) 143064562Sgshapiro dprintf("hash_map_open(%s, %s, %d)\n", 143138032Speter map->map_mname, map->map_file, mode); 143238032Speter 143364562Sgshapiro# if DB_VERSION_MAJOR < 3 143464562Sgshapiro memset(&hinfo, '\0', sizeof hinfo); 143564562Sgshapiro# ifdef DB_HASH_NELEM 143638032Speter hinfo.h_nelem = DB_HASH_NELEM; 143764562Sgshapiro# endif /* DB_HASH_NELEM */ 143864562Sgshapiro# ifdef DB_CACHE_SIZE 143938032Speter hinfo.db_cachesize = DB_CACHE_SIZE; 144064562Sgshapiro# endif /* DB_CACHE_SIZE */ 144164562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */ 144264562Sgshapiro 144338032Speter return db_map_open(map, mode, "hash", DB_HASH, &hinfo); 144438032Speter} 144538032Speter 144664562Sgshapirostatic bool 144738032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo) 144838032Speter MAP *map; 144938032Speter int mode; 145038032Speter char *mapclassname; 145138032Speter DBTYPE dbtype; 145264562Sgshapiro# if DB_VERSION_MAJOR < 2 145338032Speter const void *openinfo; 145464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 145564562Sgshapiro# if DB_VERSION_MAJOR == 2 145638032Speter DB_INFO *openinfo; 145764562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */ 145864562Sgshapiro# if DB_VERSION_MAJOR > 2 145964562Sgshapiro void **openinfo; 146064562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 146138032Speter{ 146238032Speter DB *db = NULL; 146338032Speter int i; 146438032Speter int omode; 146538032Speter int smode = S_IREAD; 146638032Speter int fd; 146764562Sgshapiro long sff; 146864562Sgshapiro int save_errno; 146938032Speter struct stat st; 147038032Speter char buf[MAXNAME + 1]; 147138032Speter 147238032Speter /* do initial file and directory checks */ 147364562Sgshapiro (void) strlcpy(buf, map->map_file, sizeof buf - 3); 147438032Speter i = strlen(buf); 147538032Speter if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 147664562Sgshapiro (void) strlcat(buf, ".db", sizeof buf); 147738032Speter 147838032Speter mode &= O_ACCMODE; 147938032Speter omode = mode; 148038032Speter 148138032Speter sff = SFF_ROOTOK|SFF_REGONLY; 148238032Speter if (mode == O_RDWR) 148338032Speter { 148438032Speter sff |= SFF_CREAT; 148564562Sgshapiro if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 148638032Speter sff |= SFF_NOSLINK; 148764562Sgshapiro if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 148838032Speter sff |= SFF_NOHLINK; 148938032Speter smode = S_IWRITE; 149038032Speter } 149138032Speter else 149238032Speter { 149364562Sgshapiro if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 149438032Speter sff |= SFF_NOWLINK; 149538032Speter } 149664562Sgshapiro if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail)) 149738032Speter sff |= SFF_SAFEDIRPATH; 149838032Speter i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st); 149964562Sgshapiro 150064562Sgshapiro# if !_FFR_REMOVE_AUTOREBUILD 150138032Speter if (i == ENOENT && AutoRebuild && 150238032Speter bitset(MCF_REBUILDABLE, map->map_class->map_cflags) && 150338032Speter (bitset(MF_IMPL_HASH, map->map_mflags) || 150438032Speter bitset(MF_ALIAS, map->map_mflags)) && 150538032Speter mode == O_RDONLY) 150638032Speter { 150738032Speter bool impl = bitset(MF_IMPL_HASH, map->map_mflags); 150838032Speter 150938032Speter /* may be able to rebuild */ 151038032Speter map->map_mflags &= ~MF_IMPL_HASH; 151138032Speter if (!rebuildaliases(map, TRUE)) 151238032Speter return FALSE; 151338032Speter if (impl) 151438032Speter return impl_map_open(map, O_RDONLY); 151538032Speter else 151638032Speter return db_map_open(map, O_RDONLY, mapclassname, 151738032Speter dbtype, openinfo); 151838032Speter } 151964562Sgshapiro# endif /* !_FFR_REMOVE_AUTOREBUILD */ 152038032Speter 152138032Speter if (i != 0) 152238032Speter { 152338032Speter char *prob = "unsafe"; 152438032Speter 152538032Speter /* cannot open this map */ 152638032Speter if (i == ENOENT) 152738032Speter prob = "missing"; 152838032Speter if (tTd(38, 2)) 152964562Sgshapiro dprintf("\t%s map file: %s\n", prob, errstring(i)); 153038032Speter errno = i; 153138032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 153238032Speter syserr("%s map \"%s\": %s map file %s", 153338032Speter mapclassname, map->map_mname, prob, buf); 153438032Speter return FALSE; 153538032Speter } 153638032Speter if (st.st_mode == ST_MODE_NOFILE) 153738032Speter omode |= O_CREAT|O_EXCL; 153838032Speter 153938032Speter map->map_lockfd = -1; 154038032Speter 154164562Sgshapiro# if LOCK_ON_OPEN 154238032Speter if (mode == O_RDWR) 154338032Speter omode |= O_TRUNC|O_EXLOCK; 154438032Speter else 154538032Speter omode |= O_SHLOCK; 154664562Sgshapiro# else /* LOCK_ON_OPEN */ 154738032Speter /* 154838032Speter ** Pre-lock the file to avoid race conditions. In particular, 154938032Speter ** since dbopen returns NULL if the file is zero length, we 155038032Speter ** must have a locked instance around the dbopen. 155138032Speter */ 155238032Speter 155338032Speter fd = open(buf, omode, DBMMODE); 155438032Speter if (fd < 0) 155538032Speter { 155638032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 155738032Speter syserr("db_map_open: cannot pre-open database %s", buf); 155838032Speter return FALSE; 155938032Speter } 156038032Speter 156138032Speter /* make sure no baddies slipped in just before the open... */ 156238032Speter if (filechanged(buf, fd, &st)) 156338032Speter { 156464562Sgshapiro save_errno = errno; 156538032Speter (void) close(fd); 156638032Speter errno = save_errno; 156738032Speter syserr("db_map_open(%s): file changed after pre-open", buf); 156838032Speter return FALSE; 156938032Speter } 157038032Speter 157138032Speter /* if new file, get the "before" bits for later filechanged check */ 157238032Speter if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0) 157338032Speter { 157464562Sgshapiro save_errno = errno; 157538032Speter (void) close(fd); 157638032Speter errno = save_errno; 157738032Speter syserr("db_map_open(%s): cannot fstat pre-opened file", 157838032Speter buf); 157938032Speter return FALSE; 158038032Speter } 158138032Speter 158238032Speter /* actually lock the pre-opened file */ 158338032Speter if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX)) 158438032Speter syserr("db_map_open: cannot lock %s", buf); 158538032Speter 158638032Speter /* set up mode bits for dbopen */ 158738032Speter if (mode == O_RDWR) 158838032Speter omode |= O_TRUNC; 158938032Speter omode &= ~(O_EXCL|O_CREAT); 159064562Sgshapiro# endif /* LOCK_ON_OPEN */ 159138032Speter 159264562Sgshapiro# if DB_VERSION_MAJOR < 2 159338032Speter db = dbopen(buf, omode, DBMMODE, dbtype, openinfo); 159464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 159538032Speter { 159638032Speter int flags = 0; 159764562Sgshapiro# if DB_VERSION_MAJOR > 2 159864562Sgshapiro int ret; 159964562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 160038032Speter 160138032Speter if (mode == O_RDONLY) 160238032Speter flags |= DB_RDONLY; 160338032Speter if (bitset(O_CREAT, omode)) 160438032Speter flags |= DB_CREATE; 160538032Speter if (bitset(O_TRUNC, omode)) 160638032Speter flags |= DB_TRUNCATE; 160738032Speter 160864562Sgshapiro# if !HASFLOCK && defined(DB_FCNTL_LOCKING) 160964562Sgshapiro flags |= DB_FCNTL_LOCKING; 161064562Sgshapiro# endif /* !HASFLOCK && defined(DB_FCNTL_LOCKING) */ 161164562Sgshapiro 161264562Sgshapiro# if DB_VERSION_MAJOR > 2 161364562Sgshapiro ret = db_create(&db, NULL, 0); 161464562Sgshapiro# ifdef DB_CACHE_SIZE 161564562Sgshapiro if (ret == 0 && db != NULL) 161664562Sgshapiro { 161764562Sgshapiro ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0); 161864562Sgshapiro if (ret != 0) 161964562Sgshapiro { 162064562Sgshapiro (void) db->close(db, 0); 162164562Sgshapiro db = NULL; 162264562Sgshapiro } 162364562Sgshapiro } 162464562Sgshapiro# endif /* DB_CACHE_SIZE */ 162564562Sgshapiro# ifdef DB_HASH_NELEM 162664562Sgshapiro if (dbtype == DB_HASH && ret == 0 && db != NULL) 162764562Sgshapiro { 162864562Sgshapiro ret = db->set_h_nelem(db, DB_HASH_NELEM); 162964562Sgshapiro if (ret != 0) 163064562Sgshapiro { 163164562Sgshapiro (void) db->close(db, 0); 163264562Sgshapiro db = NULL; 163364562Sgshapiro } 163464562Sgshapiro } 163564562Sgshapiro# endif /* DB_HASH_NELEM */ 163664562Sgshapiro if (ret == 0 && db != NULL) 163764562Sgshapiro { 163864562Sgshapiro ret = db->open(db, buf, NULL, dbtype, flags, DBMMODE); 163964562Sgshapiro if (ret != 0) 164064562Sgshapiro { 164173188Sgshapiro#ifdef DB_OLD_VERSION 164273188Sgshapiro if (ret == DB_OLD_VERSION) 164373188Sgshapiro ret = EINVAL; 164473188Sgshapiro#endif /* DB_OLD_VERSION */ 164564562Sgshapiro (void) db->close(db, 0); 164664562Sgshapiro db = NULL; 164764562Sgshapiro } 164864562Sgshapiro } 164964562Sgshapiro errno = ret; 165064562Sgshapiro# else /* DB_VERSION_MAJOR > 2 */ 165138032Speter errno = db_open(buf, dbtype, flags, DBMMODE, 165238032Speter NULL, openinfo, &db); 165364562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 165438032Speter } 165564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 165664562Sgshapiro save_errno = errno; 165738032Speter 165864562Sgshapiro# if !LOCK_ON_OPEN 165938032Speter if (mode == O_RDWR) 166038032Speter map->map_lockfd = fd; 166138032Speter else 166238032Speter (void) close(fd); 166364562Sgshapiro# endif /* !LOCK_ON_OPEN */ 166438032Speter 166538032Speter if (db == NULL) 166638032Speter { 166738032Speter if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) && 166838032Speter aliaswait(map, ".db", FALSE)) 166938032Speter return TRUE; 167064562Sgshapiro# if !LOCK_ON_OPEN 167138032Speter if (map->map_lockfd >= 0) 167238032Speter (void) close(map->map_lockfd); 167364562Sgshapiro# endif /* !LOCK_ON_OPEN */ 167464562Sgshapiro errno = save_errno; 167538032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 167638032Speter syserr("Cannot open %s database %s", 167738032Speter mapclassname, buf); 167838032Speter return FALSE; 167938032Speter } 168038032Speter 168164562Sgshapiro# if DB_VERSION_MAJOR < 2 168238032Speter fd = db->fd(db); 168364562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 168438032Speter fd = -1; 168538032Speter errno = db->fd(db, &fd); 168664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 168738032Speter if (filechanged(buf, fd, &st)) 168838032Speter { 168964562Sgshapiro save_errno = errno; 169064562Sgshapiro# if DB_VERSION_MAJOR < 2 169164562Sgshapiro (void) db->close(db); 169264562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 169338032Speter errno = db->close(db, 0); 169464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 169564562Sgshapiro# if !LOCK_ON_OPEN 169638032Speter if (map->map_lockfd >= 0) 169764562Sgshapiro (void) close(map->map_lockfd); 169864562Sgshapiro# endif /* !LOCK_ON_OPEN */ 169938032Speter errno = save_errno; 170038032Speter syserr("db_map_open(%s): file changed after open", buf); 170138032Speter return FALSE; 170238032Speter } 170338032Speter 170438032Speter if (mode == O_RDWR) 170538032Speter map->map_mflags |= MF_LOCKED; 170664562Sgshapiro# if LOCK_ON_OPEN 170738032Speter if (fd >= 0 && mode == O_RDONLY) 170838032Speter { 170938032Speter (void) lockfile(fd, buf, NULL, LOCK_UN); 171038032Speter } 171164562Sgshapiro# endif /* LOCK_ON_OPEN */ 171238032Speter 171338032Speter /* try to make sure that at least the database header is on disk */ 171438032Speter if (mode == O_RDWR) 171538032Speter { 171638032Speter (void) db->sync(db, 0); 171742575Speter if (geteuid() == 0 && TrustedUid != 0) 171838032Speter { 171964562Sgshapiro# if HASFCHOWN 172042575Speter if (fchown(fd, TrustedUid, -1) < 0) 172138032Speter { 172238032Speter int err = errno; 172338032Speter 172438032Speter sm_syslog(LOG_ALERT, NOQID, 172538032Speter "ownership change on %s failed: %s", 172638032Speter buf, errstring(err)); 172738032Speter message("050 ownership change on %s failed: %s", 172838032Speter buf, errstring(err)); 172938032Speter } 173064562Sgshapiro# endif /* HASFCHOWN */ 173138032Speter } 173238032Speter } 173338032Speter 173464562Sgshapiro map->map_db2 = (ARBPTR_T) db; 173564562Sgshapiro 173664562Sgshapiro /* 173764562Sgshapiro ** Need to set map_mtime before the call to aliaswait() 173864562Sgshapiro ** as aliaswait() will call map_lookup() which requires 173964562Sgshapiro ** map_mtime to be set 174064562Sgshapiro */ 174164562Sgshapiro 174238032Speter if (fd >= 0 && fstat(fd, &st) >= 0) 174338032Speter map->map_mtime = st.st_mtime; 174438032Speter 174538032Speter if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) && 174638032Speter !aliaswait(map, ".db", TRUE)) 174738032Speter return FALSE; 174838032Speter return TRUE; 174938032Speter} 175038032Speter 175138032Speter 175238032Speter/* 175338032Speter** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 175438032Speter*/ 175538032Speter 175638032Speterchar * 175738032Speterdb_map_lookup(map, name, av, statp) 175838032Speter MAP *map; 175938032Speter char *name; 176038032Speter char **av; 176138032Speter int *statp; 176238032Speter{ 176338032Speter DBT key, val; 176438032Speter register DB *db = (DB *) map->map_db2; 176538032Speter int i; 176638032Speter int st; 176764562Sgshapiro int save_errno; 176838032Speter int fd; 176938032Speter struct stat stbuf; 177038032Speter char keybuf[MAXNAME + 1]; 177138032Speter char buf[MAXNAME + 1]; 177238032Speter 177364562Sgshapiro memset(&key, '\0', sizeof key); 177464562Sgshapiro memset(&val, '\0', sizeof val); 177538032Speter 177638032Speter if (tTd(38, 20)) 177764562Sgshapiro dprintf("db_map_lookup(%s, %s)\n", 177838032Speter map->map_mname, name); 177938032Speter 178038032Speter i = strlen(map->map_file); 178138032Speter if (i > MAXNAME) 178238032Speter i = MAXNAME; 178364562Sgshapiro (void) strlcpy(buf, map->map_file, i + 1); 178438032Speter if (i > 3 && strcmp(&buf[i - 3], ".db") == 0) 178538032Speter buf[i - 3] = '\0'; 178638032Speter 178738032Speter key.size = strlen(name); 178838032Speter if (key.size > sizeof keybuf - 1) 178938032Speter key.size = sizeof keybuf - 1; 179038032Speter key.data = keybuf; 179164562Sgshapiro memmove(keybuf, name, key.size); 179238032Speter keybuf[key.size] = '\0'; 179338032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 179438032Speter makelower(keybuf); 179538032Speter lockdb: 179664562Sgshapiro# if DB_VERSION_MAJOR < 2 179738032Speter fd = db->fd(db); 179864562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 179938032Speter fd = -1; 180038032Speter errno = db->fd(db, &fd); 180164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 180238032Speter if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 180338032Speter (void) lockfile(fd, buf, ".db", LOCK_SH); 180438032Speter if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime) 180538032Speter { 180638032Speter /* Reopen the database to sync the cache */ 180738032Speter int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR 180838032Speter : O_RDONLY; 180938032Speter 181064562Sgshapiro if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 181164562Sgshapiro (void) lockfile(fd, buf, ".db", LOCK_UN); 181277349Sgshapiro map->map_mflags |= MF_CLOSING; 181338032Speter map->map_class->map_close(map); 181477349Sgshapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 181538032Speter if (map->map_class->map_open(map, omode)) 181638032Speter { 181738032Speter map->map_mflags |= MF_OPEN; 181842575Speter map->map_pid = getpid(); 181938032Speter if ((omode && O_ACCMODE) == O_RDWR) 182038032Speter map->map_mflags |= MF_WRITABLE; 182138032Speter db = (DB *) map->map_db2; 182238032Speter goto lockdb; 182338032Speter } 182438032Speter else 182538032Speter { 182638032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 182738032Speter { 182838032Speter extern MAPCLASS BogusMapClass; 182938032Speter 183038032Speter *statp = EX_TEMPFAIL; 183138032Speter map->map_class = &BogusMapClass; 183238032Speter map->map_mflags |= MF_OPEN; 183342575Speter map->map_pid = getpid(); 183438032Speter syserr("Cannot reopen DB database %s", 183538032Speter map->map_file); 183638032Speter } 183738032Speter return NULL; 183838032Speter } 183938032Speter } 184038032Speter 184138032Speter st = 1; 184238032Speter if (bitset(MF_TRY0NULL, map->map_mflags)) 184338032Speter { 184464562Sgshapiro# if DB_VERSION_MAJOR < 2 184538032Speter st = db->get(db, &key, &val, 0); 184664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 184738032Speter errno = db->get(db, NULL, &key, &val, 0); 184838032Speter switch (errno) 184938032Speter { 185038032Speter case DB_NOTFOUND: 185138032Speter case DB_KEYEMPTY: 185238032Speter st = 1; 185338032Speter break; 185438032Speter 185538032Speter case 0: 185638032Speter st = 0; 185738032Speter break; 185838032Speter 185938032Speter default: 186038032Speter st = -1; 186138032Speter break; 186238032Speter } 186364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 186438032Speter if (st == 0) 186538032Speter map->map_mflags &= ~MF_TRY1NULL; 186638032Speter } 186738032Speter if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 186838032Speter { 186938032Speter key.size++; 187064562Sgshapiro# if DB_VERSION_MAJOR < 2 187138032Speter st = db->get(db, &key, &val, 0); 187264562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 187338032Speter errno = db->get(db, NULL, &key, &val, 0); 187438032Speter switch (errno) 187538032Speter { 187638032Speter case DB_NOTFOUND: 187738032Speter case DB_KEYEMPTY: 187838032Speter st = 1; 187938032Speter break; 188038032Speter 188138032Speter case 0: 188238032Speter st = 0; 188338032Speter break; 188438032Speter 188538032Speter default: 188638032Speter st = -1; 188738032Speter break; 188838032Speter } 188964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 189038032Speter if (st == 0) 189138032Speter map->map_mflags &= ~MF_TRY0NULL; 189238032Speter } 189364562Sgshapiro save_errno = errno; 189438032Speter if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 189538032Speter (void) lockfile(fd, buf, ".db", LOCK_UN); 189638032Speter if (st != 0) 189738032Speter { 189864562Sgshapiro errno = save_errno; 189938032Speter if (st < 0) 190038032Speter syserr("db_map_lookup: get (%s)", name); 190138032Speter return NULL; 190238032Speter } 190338032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 190438032Speter return map_rewrite(map, name, strlen(name), NULL); 190538032Speter else 190638032Speter return map_rewrite(map, val.data, val.size, av); 190738032Speter} 190838032Speter 190938032Speter 191038032Speter/* 191138032Speter** DB_MAP_STORE -- store a datum in the NEWDB database 191238032Speter*/ 191338032Speter 191438032Spetervoid 191538032Speterdb_map_store(map, lhs, rhs) 191638032Speter register MAP *map; 191738032Speter char *lhs; 191838032Speter char *rhs; 191938032Speter{ 192064562Sgshapiro int status; 192138032Speter DBT key; 192238032Speter DBT data; 192338032Speter register DB *db = map->map_db2; 192438032Speter char keybuf[MAXNAME + 1]; 192538032Speter 192664562Sgshapiro memset(&key, '\0', sizeof key); 192764562Sgshapiro memset(&data, '\0', sizeof data); 192838032Speter 192938032Speter if (tTd(38, 12)) 193064562Sgshapiro dprintf("db_map_store(%s, %s, %s)\n", 193138032Speter map->map_mname, lhs, rhs); 193238032Speter 193338032Speter key.size = strlen(lhs); 193438032Speter key.data = lhs; 193538032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 193638032Speter { 193738032Speter if (key.size > sizeof keybuf - 1) 193838032Speter key.size = sizeof keybuf - 1; 193964562Sgshapiro memmove(keybuf, key.data, key.size); 194038032Speter keybuf[key.size] = '\0'; 194138032Speter makelower(keybuf); 194238032Speter key.data = keybuf; 194338032Speter } 194438032Speter 194538032Speter data.size = strlen(rhs); 194638032Speter data.data = rhs; 194738032Speter 194838032Speter if (bitset(MF_INCLNULL, map->map_mflags)) 194938032Speter { 195038032Speter key.size++; 195138032Speter data.size++; 195238032Speter } 195338032Speter 195464562Sgshapiro# if DB_VERSION_MAJOR < 2 195564562Sgshapiro status = db->put(db, &key, &data, R_NOOVERWRITE); 195664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 195738032Speter errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE); 195838032Speter switch (errno) 195938032Speter { 196038032Speter case DB_KEYEXIST: 196164562Sgshapiro status = 1; 196238032Speter break; 196338032Speter 196438032Speter case 0: 196564562Sgshapiro status = 0; 196638032Speter break; 196738032Speter 196838032Speter default: 196964562Sgshapiro status = -1; 197038032Speter break; 197138032Speter } 197264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 197364562Sgshapiro if (status > 0) 197438032Speter { 197538032Speter if (!bitset(MF_APPEND, map->map_mflags)) 197638032Speter message("050 Warning: duplicate alias name %s", lhs); 197738032Speter else 197838032Speter { 197938032Speter static char *buf = NULL; 198038032Speter static int bufsiz = 0; 198138032Speter DBT old; 198238032Speter 198364562Sgshapiro memset(&old, '\0', sizeof old); 198438032Speter 198564562Sgshapiro old.data = db_map_lookup(map, key.data, 198664562Sgshapiro (char **)NULL, &status); 198738032Speter if (old.data != NULL) 198838032Speter { 198938032Speter old.size = strlen(old.data); 199064562Sgshapiro if (data.size + old.size + 2 > (size_t)bufsiz) 199138032Speter { 199238032Speter if (buf != NULL) 199377349Sgshapiro sm_free(buf); 199438032Speter bufsiz = data.size + old.size + 2; 199538032Speter buf = xalloc(bufsiz); 199638032Speter } 199738032Speter snprintf(buf, bufsiz, "%s,%s", 199838032Speter (char *) data.data, (char *) old.data); 199938032Speter data.size = data.size + old.size + 1; 200038032Speter data.data = buf; 200138032Speter if (tTd(38, 9)) 200264562Sgshapiro dprintf("db_map_store append=%s\n", 200364562Sgshapiro (char *) data.data); 200438032Speter } 200538032Speter } 200664562Sgshapiro# if DB_VERSION_MAJOR < 2 200764562Sgshapiro status = db->put(db, &key, &data, 0); 200864562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 200964562Sgshapiro status = errno = db->put(db, NULL, &key, &data, 0); 201064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 201138032Speter } 201264562Sgshapiro if (status != 0) 201338032Speter syserr("readaliases: db put (%s)", lhs); 201438032Speter} 201538032Speter 201638032Speter 201738032Speter/* 201838032Speter** DB_MAP_CLOSE -- add distinguished entries and close the database 201938032Speter*/ 202038032Speter 202138032Spetervoid 202238032Speterdb_map_close(map) 202338032Speter MAP *map; 202438032Speter{ 202538032Speter register DB *db = map->map_db2; 202638032Speter 202738032Speter if (tTd(38, 9)) 202864562Sgshapiro dprintf("db_map_close(%s, %s, %lx)\n", 202938032Speter map->map_mname, map->map_file, map->map_mflags); 203038032Speter 203138032Speter if (bitset(MF_WRITABLE, map->map_mflags)) 203238032Speter { 203338032Speter /* write out the distinguished alias */ 203438032Speter db_map_store(map, "@", "@"); 203538032Speter } 203638032Speter 203738032Speter (void) db->sync(db, 0); 203838032Speter 203964562Sgshapiro# if !LOCK_ON_OPEN 204038032Speter if (map->map_lockfd >= 0) 204138032Speter (void) close(map->map_lockfd); 204264562Sgshapiro# endif /* !LOCK_ON_OPEN */ 204338032Speter 204464562Sgshapiro# if DB_VERSION_MAJOR < 2 204538032Speter if (db->close(db) != 0) 204664562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 204742575Speter /* 204842575Speter ** Berkeley DB can use internal shared memory 204942575Speter ** locking for its memory pool. Closing a map 205042575Speter ** opened by another process will interfere 205142575Speter ** with the shared memory and locks of the parent 205242575Speter ** process leaving things in a bad state. 205343730Speter */ 205443730Speter 205543730Speter /* 205642575Speter ** If this map was not opened by the current 205743730Speter ** process, do not close the map but recover 205842575Speter ** the file descriptor. 205942575Speter */ 206042575Speter if (map->map_pid != getpid()) 206142575Speter { 206242575Speter int fd = -1; 206342575Speter 206442575Speter errno = db->fd(db, &fd); 206542575Speter if (fd >= 0) 206642575Speter (void) close(fd); 206742575Speter return; 206842575Speter } 206942575Speter 207038032Speter if ((errno = db->close(db, 0)) != 0) 207164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 207242575Speter syserr("db_map_close(%s, %s, %lx): db close failure", 207342575Speter map->map_mname, map->map_file, map->map_mflags); 207438032Speter} 207564562Sgshapiro#endif /* NEWDB */ 207638032Speter/* 207738032Speter** NIS Modules 207838032Speter*/ 207938032Speter 208064562Sgshapiro#ifdef NIS 208138032Speter 208238032Speter# ifndef YPERR_BUSY 208338032Speter# define YPERR_BUSY 16 208464562Sgshapiro# endif /* ! YPERR_BUSY */ 208538032Speter 208638032Speter/* 208738032Speter** NIS_MAP_OPEN -- open DBM map 208838032Speter*/ 208938032Speter 209038032Speterbool 209138032Speternis_map_open(map, mode) 209238032Speter MAP *map; 209338032Speter int mode; 209438032Speter{ 209538032Speter int yperr; 209638032Speter register char *p; 209738032Speter auto char *vp; 209838032Speter auto int vsize; 209938032Speter 210038032Speter if (tTd(38, 2)) 210164562Sgshapiro dprintf("nis_map_open(%s, %s, %d)\n", 210238032Speter map->map_mname, map->map_file, mode); 210338032Speter 210438032Speter mode &= O_ACCMODE; 210538032Speter if (mode != O_RDONLY) 210638032Speter { 210738032Speter /* issue a pseudo-error message */ 210864562Sgshapiro# ifdef ENOSYS 210938032Speter errno = ENOSYS; 211064562Sgshapiro# else /* ENOSYS */ 211164562Sgshapiro# ifdef EFTYPE 211238032Speter errno = EFTYPE; 211364562Sgshapiro# else /* EFTYPE */ 211438032Speter errno = ENXIO; 211564562Sgshapiro# endif /* EFTYPE */ 211664562Sgshapiro# endif /* ENOSYS */ 211738032Speter return FALSE; 211838032Speter } 211938032Speter 212038032Speter p = strchr(map->map_file, '@'); 212138032Speter if (p != NULL) 212238032Speter { 212338032Speter *p++ = '\0'; 212438032Speter if (*p != '\0') 212538032Speter map->map_domain = p; 212638032Speter } 212738032Speter 212838032Speter if (*map->map_file == '\0') 212938032Speter map->map_file = "mail.aliases"; 213038032Speter 213138032Speter if (map->map_domain == NULL) 213238032Speter { 213338032Speter yperr = yp_get_default_domain(&map->map_domain); 213438032Speter if (yperr != 0) 213538032Speter { 213638032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 213764562Sgshapiro syserr("421 4.3.5 NIS map %s specified, but NIS not running", 213864562Sgshapiro map->map_file); 213938032Speter return FALSE; 214038032Speter } 214138032Speter } 214238032Speter 214338032Speter /* check to see if this map actually exists */ 214464562Sgshapiro vp = NULL; 214538032Speter yperr = yp_match(map->map_domain, map->map_file, "@", 1, 214638032Speter &vp, &vsize); 214738032Speter if (tTd(38, 10)) 214864562Sgshapiro dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n", 214938032Speter map->map_domain, map->map_file, yperr_string(yperr)); 215064562Sgshapiro if (vp != NULL) 215177349Sgshapiro sm_free(vp); 215264562Sgshapiro 215338032Speter if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 215438032Speter { 215538032Speter /* 215638032Speter ** We ought to be calling aliaswait() here if this is an 215738032Speter ** alias file, but powerful HP-UX NIS servers apparently 215838032Speter ** don't insert the @:@ token into the alias map when it 215938032Speter ** is rebuilt, so aliaswait() just hangs. I hate HP-UX. 216038032Speter */ 216138032Speter 216264562Sgshapiro# if 0 216338032Speter if (!bitset(MF_ALIAS, map->map_mflags) || 216438032Speter aliaswait(map, NULL, TRUE)) 216564562Sgshapiro# endif /* 0 */ 216638032Speter return TRUE; 216738032Speter } 216838032Speter 216938032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 217038032Speter { 217164562Sgshapiro syserr("421 4.0.0 Cannot bind to map %s in domain %s: %s", 217238032Speter map->map_file, map->map_domain, yperr_string(yperr)); 217338032Speter } 217438032Speter 217538032Speter return FALSE; 217638032Speter} 217738032Speter 217838032Speter 217938032Speter/* 218038032Speter** NIS_MAP_LOOKUP -- look up a datum in a NIS map 218138032Speter*/ 218238032Speter 218338032Speter/* ARGSUSED3 */ 218438032Speterchar * 218538032Speternis_map_lookup(map, name, av, statp) 218638032Speter MAP *map; 218738032Speter char *name; 218838032Speter char **av; 218938032Speter int *statp; 219038032Speter{ 219138032Speter char *vp; 219238032Speter auto int vsize; 219338032Speter int buflen; 219438032Speter int yperr; 219538032Speter char keybuf[MAXNAME + 1]; 219638032Speter 219738032Speter if (tTd(38, 20)) 219864562Sgshapiro dprintf("nis_map_lookup(%s, %s)\n", 219938032Speter map->map_mname, name); 220038032Speter 220138032Speter buflen = strlen(name); 220238032Speter if (buflen > sizeof keybuf - 1) 220338032Speter buflen = sizeof keybuf - 1; 220464562Sgshapiro memmove(keybuf, name, buflen); 220538032Speter keybuf[buflen] = '\0'; 220638032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 220738032Speter makelower(keybuf); 220838032Speter yperr = YPERR_KEY; 220964562Sgshapiro vp = NULL; 221038032Speter if (bitset(MF_TRY0NULL, map->map_mflags)) 221138032Speter { 221238032Speter yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 221338032Speter &vp, &vsize); 221438032Speter if (yperr == 0) 221538032Speter map->map_mflags &= ~MF_TRY1NULL; 221638032Speter } 221738032Speter if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 221838032Speter { 221964562Sgshapiro if (vp != NULL) 222064562Sgshapiro { 222177349Sgshapiro sm_free(vp); 222264562Sgshapiro vp = NULL; 222364562Sgshapiro } 222438032Speter buflen++; 222538032Speter yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 222638032Speter &vp, &vsize); 222738032Speter if (yperr == 0) 222838032Speter map->map_mflags &= ~MF_TRY0NULL; 222938032Speter } 223038032Speter if (yperr != 0) 223138032Speter { 223238032Speter if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 223338032Speter map->map_mflags &= ~(MF_VALID|MF_OPEN); 223464562Sgshapiro if (vp != NULL) 223577349Sgshapiro sm_free(vp); 223638032Speter return NULL; 223738032Speter } 223838032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 223938032Speter return map_rewrite(map, name, strlen(name), NULL); 224038032Speter else 224164562Sgshapiro { 224264562Sgshapiro char *ret; 224364562Sgshapiro 224464562Sgshapiro ret = map_rewrite(map, vp, vsize, av); 224564562Sgshapiro if (vp != NULL) 224677349Sgshapiro sm_free(vp); 224764562Sgshapiro return ret; 224864562Sgshapiro } 224938032Speter} 225038032Speter 225138032Speter 225238032Speter/* 225338032Speter** NIS_GETCANONNAME -- look up canonical name in NIS 225438032Speter*/ 225538032Speter 225664562Sgshapirostatic bool 225738032Speternis_getcanonname(name, hbsize, statp) 225838032Speter char *name; 225938032Speter int hbsize; 226038032Speter int *statp; 226138032Speter{ 226238032Speter char *vp; 226338032Speter auto int vsize; 226438032Speter int keylen; 226538032Speter int yperr; 226638032Speter static bool try0null = TRUE; 226738032Speter static bool try1null = TRUE; 226838032Speter static char *yp_domain = NULL; 226938032Speter char host_record[MAXLINE]; 227038032Speter char cbuf[MAXNAME]; 227138032Speter char nbuf[MAXNAME + 1]; 227238032Speter 227338032Speter if (tTd(38, 20)) 227464562Sgshapiro dprintf("nis_getcanonname(%s)\n", name); 227538032Speter 227664562Sgshapiro if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf) 227738032Speter { 227838032Speter *statp = EX_UNAVAILABLE; 227938032Speter return FALSE; 228038032Speter } 228173188Sgshapiro (void) shorten_hostname(nbuf); 228238032Speter keylen = strlen(nbuf); 228338032Speter 228438032Speter if (yp_domain == NULL) 228564562Sgshapiro (void) yp_get_default_domain(&yp_domain); 228638032Speter makelower(nbuf); 228738032Speter yperr = YPERR_KEY; 228864562Sgshapiro vp = NULL; 228938032Speter if (try0null) 229038032Speter { 229138032Speter yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen, 229238032Speter &vp, &vsize); 229338032Speter if (yperr == 0) 229438032Speter try1null = FALSE; 229538032Speter } 229638032Speter if (yperr == YPERR_KEY && try1null) 229738032Speter { 229864562Sgshapiro if (vp != NULL) 229964562Sgshapiro { 230077349Sgshapiro sm_free(vp); 230164562Sgshapiro vp = NULL; 230264562Sgshapiro } 230338032Speter keylen++; 230438032Speter yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen, 230538032Speter &vp, &vsize); 230638032Speter if (yperr == 0) 230738032Speter try0null = FALSE; 230838032Speter } 230938032Speter if (yperr != 0) 231038032Speter { 231138032Speter if (yperr == YPERR_KEY) 231238032Speter *statp = EX_NOHOST; 231338032Speter else if (yperr == YPERR_BUSY) 231438032Speter *statp = EX_TEMPFAIL; 231538032Speter else 231638032Speter *statp = EX_UNAVAILABLE; 231764562Sgshapiro if (vp != NULL) 231877349Sgshapiro sm_free(vp); 231938032Speter return FALSE; 232038032Speter } 232164562Sgshapiro (void) strlcpy(host_record, vp, sizeof host_record); 232277349Sgshapiro sm_free(vp); 232338032Speter if (tTd(38, 44)) 232464562Sgshapiro dprintf("got record `%s'\n", host_record); 232573188Sgshapiro if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof cbuf)) 232638032Speter { 232738032Speter /* this should not happen, but.... */ 232838032Speter *statp = EX_NOHOST; 232938032Speter return FALSE; 233038032Speter } 233173188Sgshapiro if (hbsize <= strlen(cbuf)) 233238032Speter { 233338032Speter *statp = EX_UNAVAILABLE; 233438032Speter return FALSE; 233538032Speter } 233664562Sgshapiro (void) strlcpy(name, cbuf, hbsize); 233738032Speter *statp = EX_OK; 233838032Speter return TRUE; 233938032Speter} 234038032Speter 234164562Sgshapiro#endif /* NIS */ 234238032Speter/* 234338032Speter** NISPLUS Modules 234438032Speter** 234538032Speter** This code donated by Sun Microsystems. 234638032Speter*/ 234738032Speter 234838032Speter#ifdef NISPLUS 234938032Speter 235064562Sgshapiro# undef NIS /* symbol conflict in nis.h */ 235164562Sgshapiro# undef T_UNSPEC /* symbol conflict in nis.h -> ... -> sys/tiuser.h */ 235264562Sgshapiro# include <rpcsvc/nis.h> 235364562Sgshapiro# include <rpcsvc/nislib.h> 235438032Speter 235564562Sgshapiro# define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val 235664562Sgshapiro# define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name 235764562Sgshapiro# define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len) 235864562Sgshapiro# define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.') 235938032Speter 236038032Speter/* 236138032Speter** NISPLUS_MAP_OPEN -- open nisplus table 236238032Speter*/ 236338032Speter 236438032Speterbool 236538032Speternisplus_map_open(map, mode) 236638032Speter MAP *map; 236738032Speter int mode; 236838032Speter{ 236938032Speter nis_result *res = NULL; 237038032Speter int retry_cnt, max_col, i; 237138032Speter char qbuf[MAXLINE + NIS_MAXNAMELEN]; 237238032Speter 237338032Speter if (tTd(38, 2)) 237464562Sgshapiro dprintf("nisplus_map_open(%s, %s, %d)\n", 237538032Speter map->map_mname, map->map_file, mode); 237638032Speter 237738032Speter mode &= O_ACCMODE; 237838032Speter if (mode != O_RDONLY) 237938032Speter { 238038032Speter errno = EPERM; 238138032Speter return FALSE; 238238032Speter } 238338032Speter 238438032Speter if (*map->map_file == '\0') 238538032Speter map->map_file = "mail_aliases.org_dir"; 238638032Speter 238738032Speter if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL) 238838032Speter { 238938032Speter /* set default NISPLUS Domain to $m */ 239038032Speter map->map_domain = newstr(nisplus_default_domain()); 239138032Speter if (tTd(38, 2)) 239264562Sgshapiro dprintf("nisplus_map_open(%s): using domain %s\n", 239364562Sgshapiro map->map_file, map->map_domain); 239438032Speter } 239538032Speter if (!PARTIAL_NAME(map->map_file)) 239638032Speter { 239738032Speter map->map_domain = newstr(""); 239838032Speter snprintf(qbuf, sizeof qbuf, "%s", map->map_file); 239938032Speter } 240038032Speter else 240138032Speter { 240238032Speter /* check to see if this map actually exists */ 240338032Speter snprintf(qbuf, sizeof qbuf, "%s.%s", 240438032Speter map->map_file, map->map_domain); 240538032Speter } 240638032Speter 240738032Speter retry_cnt = 0; 240838032Speter while (res == NULL || res->status != NIS_SUCCESS) 240938032Speter { 241038032Speter res = nis_lookup(qbuf, FOLLOW_LINKS); 241138032Speter switch (res->status) 241238032Speter { 241338032Speter case NIS_SUCCESS: 241438032Speter break; 241538032Speter 241638032Speter case NIS_TRYAGAIN: 241738032Speter case NIS_RPCERROR: 241838032Speter case NIS_NAMEUNREACHABLE: 241938032Speter if (retry_cnt++ > 4) 242038032Speter { 242138032Speter errno = EAGAIN; 242238032Speter return FALSE; 242338032Speter } 242438032Speter /* try not to overwhelm hosed server */ 242538032Speter sleep(2); 242638032Speter break; 242738032Speter 242838032Speter default: /* all other nisplus errors */ 242964562Sgshapiro# if 0 243038032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 243164562Sgshapiro syserr("421 4.0.0 Cannot find table %s.%s: %s", 243238032Speter map->map_file, map->map_domain, 243338032Speter nis_sperrno(res->status)); 243464562Sgshapiro# endif /* 0 */ 243538032Speter errno = EAGAIN; 243638032Speter return FALSE; 243738032Speter } 243838032Speter } 243938032Speter 244038032Speter if (NIS_RES_NUMOBJ(res) != 1 || 244138032Speter (NIS_RES_OBJECT(res)->zo_data.zo_type != TABLE_OBJ)) 244238032Speter { 244338032Speter if (tTd(38, 10)) 244464562Sgshapiro dprintf("nisplus_map_open: %s is not a table\n", qbuf); 244564562Sgshapiro# if 0 244638032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 244764562Sgshapiro syserr("421 4.0.0 %s.%s: %s is not a table", 244838032Speter map->map_file, map->map_domain, 244938032Speter nis_sperrno(res->status)); 245064562Sgshapiro# endif /* 0 */ 245138032Speter errno = EBADF; 245238032Speter return FALSE; 245338032Speter } 245438032Speter /* default key column is column 0 */ 245538032Speter if (map->map_keycolnm == NULL) 245638032Speter map->map_keycolnm = newstr(COL_NAME(res,0)); 245738032Speter 245838032Speter max_col = COL_MAX(res); 245938032Speter 246038032Speter /* verify the key column exist */ 246164562Sgshapiro for (i = 0; i< max_col; i++) 246238032Speter { 246364562Sgshapiro if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0) 246438032Speter break; 246538032Speter } 246638032Speter if (i == max_col) 246738032Speter { 246838032Speter if (tTd(38, 2)) 246964562Sgshapiro dprintf("nisplus_map_open(%s): can not find key column %s\n", 247038032Speter map->map_file, map->map_keycolnm); 247138032Speter errno = ENOENT; 247238032Speter return FALSE; 247338032Speter } 247438032Speter 247538032Speter /* default value column is the last column */ 247638032Speter if (map->map_valcolnm == NULL) 247738032Speter { 247838032Speter map->map_valcolno = max_col - 1; 247938032Speter return TRUE; 248038032Speter } 248138032Speter 248264562Sgshapiro for (i = 0; i< max_col; i++) 248338032Speter { 248438032Speter if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0) 248538032Speter { 248638032Speter map->map_valcolno = i; 248738032Speter return TRUE; 248838032Speter } 248938032Speter } 249038032Speter 249138032Speter if (tTd(38, 2)) 249264562Sgshapiro dprintf("nisplus_map_open(%s): can not find column %s\n", 249364562Sgshapiro map->map_file, map->map_keycolnm); 249438032Speter errno = ENOENT; 249538032Speter return FALSE; 249638032Speter} 249738032Speter 249838032Speter 249938032Speter/* 250038032Speter** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table 250138032Speter*/ 250238032Speter 250338032Speterchar * 250438032Speternisplus_map_lookup(map, name, av, statp) 250538032Speter MAP *map; 250638032Speter char *name; 250738032Speter char **av; 250838032Speter int *statp; 250938032Speter{ 251038032Speter char *p; 251138032Speter auto int vsize; 251238032Speter char *skp; 251338032Speter int skleft; 251438032Speter char search_key[MAXNAME + 4]; 251538032Speter char qbuf[MAXLINE + NIS_MAXNAMELEN]; 251638032Speter nis_result *result; 251738032Speter 251838032Speter if (tTd(38, 20)) 251964562Sgshapiro dprintf("nisplus_map_lookup(%s, %s)\n", 252038032Speter map->map_mname, name); 252138032Speter 252238032Speter if (!bitset(MF_OPEN, map->map_mflags)) 252338032Speter { 252438032Speter if (nisplus_map_open(map, O_RDONLY)) 252542575Speter { 252638032Speter map->map_mflags |= MF_OPEN; 252742575Speter map->map_pid = getpid(); 252842575Speter } 252938032Speter else 253038032Speter { 253138032Speter *statp = EX_UNAVAILABLE; 253238032Speter return NULL; 253338032Speter } 253438032Speter } 253538032Speter 253638032Speter /* 253738032Speter ** Copy the name to the key buffer, escaping double quote characters 253838032Speter ** by doubling them and quoting "]" and "," to avoid having the 253938032Speter ** NIS+ parser choke on them. 254038032Speter */ 254138032Speter 254238032Speter skleft = sizeof search_key - 4; 254338032Speter skp = search_key; 254438032Speter for (p = name; *p != '\0' && skleft > 0; p++) 254538032Speter { 254638032Speter switch (*p) 254738032Speter { 254838032Speter case ']': 254938032Speter case ',': 255038032Speter /* quote the character */ 255138032Speter *skp++ = '"'; 255238032Speter *skp++ = *p; 255338032Speter *skp++ = '"'; 255438032Speter skleft -= 3; 255538032Speter break; 255638032Speter 255738032Speter case '"': 255838032Speter /* double the quote */ 255938032Speter *skp++ = '"'; 256038032Speter skleft--; 256164562Sgshapiro /* FALLTHROUGH */ 256238032Speter 256338032Speter default: 256438032Speter *skp++ = *p; 256538032Speter skleft--; 256638032Speter break; 256738032Speter } 256838032Speter } 256938032Speter *skp = '\0'; 257038032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 257138032Speter makelower(search_key); 257238032Speter 257338032Speter /* construct the query */ 257438032Speter if (PARTIAL_NAME(map->map_file)) 257538032Speter snprintf(qbuf, sizeof qbuf, "[%s=%s],%s.%s", 257638032Speter map->map_keycolnm, search_key, map->map_file, 257738032Speter map->map_domain); 257838032Speter else 257938032Speter snprintf(qbuf, sizeof qbuf, "[%s=%s],%s", 258038032Speter map->map_keycolnm, search_key, map->map_file); 258138032Speter 258238032Speter if (tTd(38, 20)) 258364562Sgshapiro dprintf("qbuf=%s\n", qbuf); 258438032Speter result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); 258538032Speter if (result->status == NIS_SUCCESS) 258638032Speter { 258738032Speter int count; 258838032Speter char *str; 258938032Speter 259038032Speter if ((count = NIS_RES_NUMOBJ(result)) != 1) 259138032Speter { 259238032Speter if (LogLevel > 10) 259338032Speter sm_syslog(LOG_WARNING, CurEnv->e_id, 259464562Sgshapiro "%s: lookup error, expected 1 entry, got %d", 259564562Sgshapiro map->map_file, count); 259638032Speter 259738032Speter /* ignore second entry */ 259838032Speter if (tTd(38, 20)) 259964562Sgshapiro dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n", 260038032Speter name, count); 260138032Speter } 260238032Speter 260338032Speter p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno)); 260438032Speter /* set the length of the result */ 260538032Speter if (p == NULL) 260638032Speter p = ""; 260738032Speter vsize = strlen(p); 260838032Speter if (tTd(38, 20)) 260964562Sgshapiro dprintf("nisplus_map_lookup(%s), found %s\n", 261038032Speter name, p); 261138032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 261238032Speter str = map_rewrite(map, name, strlen(name), NULL); 261338032Speter else 261438032Speter str = map_rewrite(map, p, vsize, av); 261538032Speter nis_freeresult(result); 261638032Speter *statp = EX_OK; 261738032Speter return str; 261838032Speter } 261938032Speter else 262038032Speter { 262138032Speter if (result->status == NIS_NOTFOUND) 262238032Speter *statp = EX_NOTFOUND; 262338032Speter else if (result->status == NIS_TRYAGAIN) 262438032Speter *statp = EX_TEMPFAIL; 262538032Speter else 262638032Speter { 262738032Speter *statp = EX_UNAVAILABLE; 262838032Speter map->map_mflags &= ~(MF_VALID|MF_OPEN); 262938032Speter } 263038032Speter } 263138032Speter if (tTd(38, 20)) 263264562Sgshapiro dprintf("nisplus_map_lookup(%s), failed\n", name); 263338032Speter nis_freeresult(result); 263438032Speter return NULL; 263538032Speter} 263638032Speter 263738032Speter 263838032Speter 263938032Speter/* 264038032Speter** NISPLUS_GETCANONNAME -- look up canonical name in NIS+ 264138032Speter*/ 264238032Speter 264364562Sgshapirostatic bool 264438032Speternisplus_getcanonname(name, hbsize, statp) 264538032Speter char *name; 264638032Speter int hbsize; 264738032Speter int *statp; 264838032Speter{ 264938032Speter char *vp; 265038032Speter auto int vsize; 265138032Speter nis_result *result; 265238032Speter char *p; 265338032Speter char nbuf[MAXNAME + 1]; 265438032Speter char qbuf[MAXLINE + NIS_MAXNAMELEN]; 265538032Speter 265638032Speter if (strlen(name) >= sizeof nbuf) 265738032Speter { 265838032Speter *statp = EX_UNAVAILABLE; 265938032Speter return FALSE; 266038032Speter } 266164562Sgshapiro (void) strlcpy(nbuf, name, sizeof nbuf); 266273188Sgshapiro (void) shorten_hostname(nbuf); 266338032Speter 266438032Speter p = strchr(nbuf, '.'); 266538032Speter if (p == NULL) 266638032Speter { 266738032Speter /* single token */ 266838032Speter snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir", nbuf); 266938032Speter } 267038032Speter else if (p[1] != '\0') 267138032Speter { 267238032Speter /* multi token -- take only first token in nbuf */ 267338032Speter *p = '\0'; 267438032Speter snprintf(qbuf, sizeof qbuf, "[name=%s],hosts.org_dir.%s", 267538032Speter nbuf, &p[1]); 267638032Speter } 267738032Speter else 267838032Speter { 267938032Speter *statp = EX_NOHOST; 268038032Speter return FALSE; 268138032Speter } 268238032Speter 268338032Speter if (tTd(38, 20)) 268464562Sgshapiro dprintf("\nnisplus_getcanoname(%s), qbuf=%s\n", 268564562Sgshapiro name, qbuf); 268638032Speter 268738032Speter result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH, 268838032Speter NULL, NULL); 268938032Speter 269038032Speter if (result->status == NIS_SUCCESS) 269138032Speter { 269238032Speter int count; 269338032Speter char *domain; 269438032Speter 269538032Speter if ((count = NIS_RES_NUMOBJ(result)) != 1) 269638032Speter { 269738032Speter if (LogLevel > 10) 269838032Speter sm_syslog(LOG_WARNING, CurEnv->e_id, 269964562Sgshapiro "nisplus_getcanonname: lookup error, expected 1 entry, got %d", 270064562Sgshapiro count); 270138032Speter 270238032Speter /* ignore second entry */ 270338032Speter if (tTd(38, 20)) 270464562Sgshapiro dprintf("nisplus_getcanoname(%s), got %d entries, all but first ignored\n", 270538032Speter name, count); 270638032Speter } 270738032Speter 270838032Speter if (tTd(38, 20)) 270964562Sgshapiro dprintf("nisplus_getcanoname(%s), found in directory \"%s\"\n", 271064562Sgshapiro name, (NIS_RES_OBJECT(result))->zo_domain); 271138032Speter 271238032Speter 271338032Speter vp = ((NIS_RES_OBJECT(result))->EN_col(0)); 271438032Speter vsize = strlen(vp); 271538032Speter if (tTd(38, 20)) 271664562Sgshapiro dprintf("nisplus_getcanonname(%s), found %s\n", 271738032Speter name, vp); 271838032Speter if (strchr(vp, '.') != NULL) 271938032Speter { 272038032Speter domain = ""; 272138032Speter } 272238032Speter else 272338032Speter { 272438032Speter domain = macvalue('m', CurEnv); 272538032Speter if (domain == NULL) 272638032Speter domain = ""; 272738032Speter } 272838032Speter if (hbsize > vsize + (int) strlen(domain) + 1) 272938032Speter { 273038032Speter if (domain[0] == '\0') 273164562Sgshapiro (void) strlcpy(name, vp, hbsize); 273238032Speter else 273338032Speter snprintf(name, hbsize, "%s.%s", vp, domain); 273438032Speter *statp = EX_OK; 273538032Speter } 273638032Speter else 273738032Speter *statp = EX_NOHOST; 273838032Speter nis_freeresult(result); 273938032Speter return TRUE; 274038032Speter } 274138032Speter else 274238032Speter { 274338032Speter if (result->status == NIS_NOTFOUND) 274438032Speter *statp = EX_NOHOST; 274538032Speter else if (result->status == NIS_TRYAGAIN) 274638032Speter *statp = EX_TEMPFAIL; 274738032Speter else 274838032Speter *statp = EX_UNAVAILABLE; 274938032Speter } 275038032Speter if (tTd(38, 20)) 275164562Sgshapiro dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n", 275238032Speter name, result->status, *statp); 275338032Speter nis_freeresult(result); 275438032Speter return FALSE; 275538032Speter} 275638032Speter 275738032Speterchar * 275838032Speternisplus_default_domain() 275938032Speter{ 276038032Speter static char default_domain[MAXNAME + 1] = ""; 276138032Speter char *p; 276238032Speter 276338032Speter if (default_domain[0] != '\0') 276464562Sgshapiro return default_domain; 276538032Speter 276638032Speter p = nis_local_directory(); 276738032Speter snprintf(default_domain, sizeof default_domain, "%s", p); 276838032Speter return default_domain; 276938032Speter} 277038032Speter 277138032Speter#endif /* NISPLUS */ 277238032Speter/* 277338032Speter** LDAP Modules 277438032Speter*/ 277538032Speter 277664562Sgshapiro/* 277764562Sgshapiro** LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs 277864562Sgshapiro*/ 277964562Sgshapiro 278064562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP) 278164562Sgshapiro 278264562Sgshapiro# ifdef PH_MAP 278364562Sgshapiro# define ph_map_dequote ldapmap_dequote 278464562Sgshapiro# endif /* PH_MAP */ 278564562Sgshapiro 278664562Sgshapirochar * 278764562Sgshapiroldapmap_dequote(str) 278864562Sgshapiro char *str; 278964562Sgshapiro{ 279064562Sgshapiro char *p; 279164562Sgshapiro char *start; 279264562Sgshapiro 279364562Sgshapiro if (str == NULL) 279464562Sgshapiro return NULL; 279564562Sgshapiro 279664562Sgshapiro p = str; 279764562Sgshapiro if (*p == '"') 279864562Sgshapiro { 279964562Sgshapiro /* Should probably swallow initial whitespace here */ 280064562Sgshapiro start = ++p; 280164562Sgshapiro } 280264562Sgshapiro else 280364562Sgshapiro return str; 280464562Sgshapiro while (*p != '"' && *p != '\0') 280564562Sgshapiro p++; 280664562Sgshapiro if (*p != '\0') 280764562Sgshapiro *p = '\0'; 280864562Sgshapiro return start; 280964562Sgshapiro} 281064562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */ 281164562Sgshapiro 281238032Speter#ifdef LDAPMAP 281338032Speter 281464562SgshapiroLDAPMAP_STRUCT *LDAPDefaults = NULL; 281538032Speter 281638032Speter/* 281764562Sgshapiro** LDAPMAP_OPEN -- open LDAP map 281838032Speter** 281964562Sgshapiro** Connect to the LDAP server. Re-use existing connections since a 282064562Sgshapiro** single server connection to a host (with the same host, port, 282164562Sgshapiro** bind DN, and secret) can answer queries for multiple maps. 282238032Speter*/ 282338032Speter 282438032Speterbool 282564562Sgshapiroldapmap_open(map, mode) 282638032Speter MAP *map; 282738032Speter int mode; 282838032Speter{ 282964562Sgshapiro LDAPMAP_STRUCT *lmap; 283064562Sgshapiro STAB *s; 283164562Sgshapiro 283238032Speter if (tTd(38, 2)) 283366494Sgshapiro dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode); 283438032Speter 283538032Speter mode &= O_ACCMODE; 283664562Sgshapiro 283764562Sgshapiro /* sendmail doesn't have the ability to write to LDAP (yet) */ 283838032Speter if (mode != O_RDONLY) 283938032Speter { 284038032Speter /* issue a pseudo-error message */ 284164562Sgshapiro# ifdef ENOSYS 284238032Speter errno = ENOSYS; 284364562Sgshapiro# else /* ENOSYS */ 284464562Sgshapiro# ifdef EFTYPE 284538032Speter errno = EFTYPE; 284664562Sgshapiro# else /* EFTYPE */ 284738032Speter errno = ENXIO; 284864562Sgshapiro# endif /* EFTYPE */ 284964562Sgshapiro# endif /* ENOSYS */ 285038032Speter return FALSE; 285138032Speter } 285264562Sgshapiro 285364562Sgshapiro /* Comma separate if used as an alias file */ 285464562Sgshapiro if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags)) 285564562Sgshapiro map->map_coldelim = ','; 285664562Sgshapiro 285764562Sgshapiro lmap = (LDAPMAP_STRUCT *) map->map_db1; 285864562Sgshapiro 285964562Sgshapiro s = ldapmap_findconn(lmap); 286077349Sgshapiro if (s->s_lmap != NULL) 286164562Sgshapiro { 286264562Sgshapiro /* Already have a connection open to this LDAP server */ 286377349Sgshapiro lmap->ldap_ld = ((LDAPMAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld; 286477349Sgshapiro 286577349Sgshapiro /* Add this map as head of linked list */ 286677349Sgshapiro lmap->ldap_next = s->s_lmap; 286777349Sgshapiro s->s_lmap = map; 286877349Sgshapiro 286966494Sgshapiro if (tTd(38, 2)) 287066494Sgshapiro dprintf("using cached connection\n"); 287164562Sgshapiro return TRUE; 287264562Sgshapiro } 287364562Sgshapiro 287466494Sgshapiro if (tTd(38, 2)) 287566494Sgshapiro dprintf("opening new connection\n"); 287666494Sgshapiro 287764562Sgshapiro /* No connection yet, connect */ 287864562Sgshapiro if (!ldapmap_start(map)) 287964562Sgshapiro return FALSE; 288064562Sgshapiro 288164562Sgshapiro /* Save connection for reuse */ 288277349Sgshapiro s->s_lmap = map; 288338032Speter return TRUE; 288438032Speter} 288538032Speter 288638032Speter/* 288764562Sgshapiro** LDAPMAP_START -- actually connect to an LDAP server 288838032Speter** 288964562Sgshapiro** Parameters: 289064562Sgshapiro** map -- the map being opened. 289164562Sgshapiro** 289264562Sgshapiro** Returns: 289364562Sgshapiro** TRUE if connection is successful, FALSE otherwise. 289464562Sgshapiro** 289564562Sgshapiro** Side Effects: 289664562Sgshapiro** Populates lmap->ldap_ld. 289738032Speter*/ 289838032Speter 289938032Speterstatic jmp_buf LDAPTimeout; 290038032Speter 290164562Sgshapirostatic bool 290264562Sgshapiroldapmap_start(map) 290338032Speter MAP *map; 290438032Speter{ 290564562Sgshapiro register int bind_result; 290664562Sgshapiro int save_errno; 290764562Sgshapiro register EVENT *ev = NULL; 290864562Sgshapiro LDAPMAP_STRUCT *lmap; 290938032Speter LDAP *ld; 291038032Speter 291138032Speter if (tTd(38, 2)) 291264562Sgshapiro dprintf("ldapmap_start(%s)\n", map->map_mname); 291338032Speter 291464562Sgshapiro lmap = (LDAPMAP_STRUCT *) map->map_db1; 291538032Speter 291638032Speter if (tTd(38,9)) 291764562Sgshapiro dprintf("ldapmap_start(%s, %d)\n", 291864562Sgshapiro lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host, 291964562Sgshapiro lmap->ldap_port); 292038032Speter 292164562Sgshapiro# if USE_LDAP_INIT 292264562Sgshapiro ld = ldap_init(lmap->ldap_host, lmap->ldap_port); 292371345Sgshapiro save_errno = errno; 292464562Sgshapiro# else /* USE_LDAP_INIT */ 292564562Sgshapiro /* 292664562Sgshapiro ** If using ldap_open(), the actual connection to the server 292764562Sgshapiro ** happens now so we need the timeout here. For ldap_init(), 292864562Sgshapiro ** the connection happens at bind time. 292964562Sgshapiro */ 293038032Speter 293138032Speter /* set the timeout */ 293264562Sgshapiro if (lmap->ldap_timeout.tv_sec != 0) 293338032Speter { 293438032Speter if (setjmp(LDAPTimeout) != 0) 293538032Speter { 293638032Speter if (LogLevel > 1) 293738032Speter sm_syslog(LOG_NOTICE, CurEnv->e_id, 293864562Sgshapiro "timeout conning to LDAP server %.100s", 293964562Sgshapiro lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host); 294064562Sgshapiro return FALSE; 294138032Speter } 294264562Sgshapiro ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0); 294338032Speter } 294438032Speter 294564562Sgshapiro ld = ldap_open(lmap->ldap_host, lmap->ldap_port); 294664562Sgshapiro save_errno = errno; 294742575Speter 294864562Sgshapiro /* clear the event if it has not sprung */ 294964562Sgshapiro if (ev != NULL) 295042575Speter clrevent(ev); 295164562Sgshapiro# endif /* USE_LDAP_INIT */ 295242575Speter 295364562Sgshapiro errno = save_errno; 295442575Speter if (ld == NULL) 295538032Speter { 295638032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 295738032Speter { 295864562Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 295964562Sgshapiro syserr("%s failed to %s in map %s", 296064562Sgshapiro# if USE_LDAP_INIT 296164562Sgshapiro "ldap_init", 296264562Sgshapiro# else /* USE_LDAP_INIT */ 296364562Sgshapiro "ldap_open", 296464562Sgshapiro# endif /* USE_LDAP_INIT */ 296564562Sgshapiro lmap->ldap_host == NULL ? "localhost" 296664562Sgshapiro : lmap->ldap_host, 296764562Sgshapiro map->map_mname); 296864562Sgshapiro else 296964562Sgshapiro syserr("421 4.0.0 %s failed to %s in map %s", 297064562Sgshapiro# if USE_LDAP_INIT 297164562Sgshapiro "ldap_init", 297264562Sgshapiro# else /* USE_LDAP_INIT */ 297364562Sgshapiro "ldap_open", 297464562Sgshapiro# endif /* USE_LDAP_INIT */ 297564562Sgshapiro lmap->ldap_host == NULL ? "localhost" 297664562Sgshapiro : lmap->ldap_host, 297764562Sgshapiro map->map_mname); 297838032Speter } 297938032Speter return FALSE; 298038032Speter } 298138032Speter 298264562Sgshapiro ldapmap_setopts(ld, lmap); 298338032Speter 298464562Sgshapiro# if USE_LDAP_INIT 298564562Sgshapiro /* 298664562Sgshapiro ** If using ldap_init(), the actual connection to the server 298764562Sgshapiro ** happens at ldap_bind_s() so we need the timeout here. 298864562Sgshapiro */ 298964562Sgshapiro 299064562Sgshapiro /* set the timeout */ 299164562Sgshapiro if (lmap->ldap_timeout.tv_sec != 0) 299238032Speter { 299364562Sgshapiro if (setjmp(LDAPTimeout) != 0) 299438032Speter { 299564562Sgshapiro if (LogLevel > 1) 299664562Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, 299764562Sgshapiro "timeout conning to LDAP server %.100s", 299864562Sgshapiro lmap->ldap_host == NULL ? "localhost" 299964562Sgshapiro : lmap->ldap_host); 300064562Sgshapiro return FALSE; 300138032Speter } 300264562Sgshapiro ev = setevent(lmap->ldap_timeout.tv_sec, ldaptimeout, 0); 300338032Speter } 300464562Sgshapiro# endif /* USE_LDAP_INIT */ 300564562Sgshapiro 300664562Sgshapiro# ifdef LDAP_AUTH_KRBV4 300764562Sgshapiro if (lmap->ldap_method == LDAP_AUTH_KRBV4 && 300864562Sgshapiro lmap->ldap_secret != NULL) 300938032Speter { 301064562Sgshapiro /* 301164562Sgshapiro ** Need to put ticket in environment here instead of 301264562Sgshapiro ** during parseargs as there may be different tickets 301364562Sgshapiro ** for different LDAP connections. 301464562Sgshapiro */ 301564562Sgshapiro 301664562Sgshapiro (void) putenv(lmap->ldap_secret); 301738032Speter } 301864562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */ 301938032Speter 302064562Sgshapiro bind_result = ldap_bind_s(ld, lmap->ldap_binddn, 302164562Sgshapiro lmap->ldap_secret, lmap->ldap_method); 302264562Sgshapiro 302364562Sgshapiro# if USE_LDAP_INIT 302464562Sgshapiro /* clear the event if it has not sprung */ 302564562Sgshapiro if (ev != NULL) 302664562Sgshapiro clrevent(ev); 302764562Sgshapiro# endif /* USE_LDAP_INIT */ 302864562Sgshapiro 302964562Sgshapiro if (bind_result != LDAP_SUCCESS) 303064562Sgshapiro { 303164562Sgshapiro errno = bind_result + E_LDAPBASE; 303264562Sgshapiro if (!bitset(MF_OPTIONAL, map->map_mflags)) 303364562Sgshapiro { 303464562Sgshapiro syserr("421 4.0.0 Cannot bind to map %s in ldap server %s", 303564562Sgshapiro map->map_mname, 303664562Sgshapiro lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host); 303764562Sgshapiro } 303864562Sgshapiro return FALSE; 303964562Sgshapiro } 304064562Sgshapiro 304164562Sgshapiro /* We need to cast ld into the map structure */ 304264562Sgshapiro lmap->ldap_ld = ld; 304364562Sgshapiro return TRUE; 304438032Speter} 304538032Speter 304664562Sgshapiro/* ARGSUSED */ 304764562Sgshapirostatic void 304864562Sgshapiroldaptimeout(sig_no) 304964562Sgshapiro int sig_no; 305064562Sgshapiro{ 305177349Sgshapiro /* 305277349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 305377349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 305477349Sgshapiro ** DOING. 305577349Sgshapiro */ 305677349Sgshapiro 305777349Sgshapiro errno = ETIMEDOUT; 305864562Sgshapiro longjmp(LDAPTimeout, 1); 305964562Sgshapiro} 306038032Speter 306138032Speter/* 306264562Sgshapiro** LDAPMAP_CLOSE -- close ldap map 306338032Speter*/ 306438032Speter 306538032Spetervoid 306664562Sgshapiroldapmap_close(map) 306738032Speter MAP *map; 306838032Speter{ 306964562Sgshapiro LDAPMAP_STRUCT *lmap; 307064562Sgshapiro STAB *s; 307143730Speter 307264562Sgshapiro if (tTd(38, 2)) 307364562Sgshapiro dprintf("ldapmap_close(%s)\n", map->map_mname); 307464562Sgshapiro 307564562Sgshapiro lmap = (LDAPMAP_STRUCT *) map->map_db1; 307664562Sgshapiro 307764562Sgshapiro /* Check if already closed */ 307864562Sgshapiro if (lmap->ldap_ld == NULL) 307964562Sgshapiro return; 308064562Sgshapiro 308177349Sgshapiro /* Close the LDAP connection */ 308277349Sgshapiro ldap_unbind(lmap->ldap_ld); 308377349Sgshapiro 308477349Sgshapiro /* Mark all the maps that share the connection as closed */ 308564562Sgshapiro s = ldapmap_findconn(lmap); 308664562Sgshapiro 308777349Sgshapiro while (s->s_lmap != NULL) 308877349Sgshapiro { 308977349Sgshapiro MAP *smap = s->s_lmap; 309064562Sgshapiro 309177349Sgshapiro if (tTd(38, 2) && smap != map) 309277349Sgshapiro dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n", 309377349Sgshapiro map->map_mname, smap->map_mname); 309464562Sgshapiro 309577349Sgshapiro smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 309677349Sgshapiro lmap = (LDAPMAP_STRUCT *) smap->map_db1; 309764562Sgshapiro lmap->ldap_ld = NULL; 309877349Sgshapiro s->s_lmap = lmap->ldap_next; 309977349Sgshapiro lmap->ldap_next = NULL; 310043730Speter } 310138032Speter} 310238032Speter 310364562Sgshapiro# ifdef SUNET_ID 310443730Speter/* 310542575Speter** SUNET_ID_HASH -- Convert a string to it's Sunet_id canonical form 310642575Speter** This only makes sense at Stanford University. 310738032Speter*/ 310838032Speter 310938032Speterchar * 311038032Spetersunet_id_hash(str) 311138032Speter char *str; 311238032Speter{ 311338032Speter char *p, *p_last; 311438032Speter 311538032Speter p = str; 311638032Speter p_last = p; 311738032Speter while (*p != '\0') 311838032Speter { 311938032Speter if (islower(*p) || isdigit(*p)) 312038032Speter { 312138032Speter *p_last = *p; 312238032Speter p_last++; 312338032Speter } 312438032Speter else if (isupper(*p)) 312538032Speter { 312638032Speter *p_last = tolower(*p); 312738032Speter p_last++; 312838032Speter } 312938032Speter ++p; 313038032Speter } 313138032Speter if (*p_last != '\0') 313238032Speter *p_last = '\0'; 313364562Sgshapiro return str; 313438032Speter} 313564562Sgshapiro# endif /* SUNET_ID */ 313638032Speter 313738032Speter/* 313864562Sgshapiro** LDAPMAP_LOOKUP -- look up a datum in a LDAP map 313938032Speter*/ 314038032Speter 314138032Speterchar * 314264562Sgshapiroldapmap_lookup(map, name, av, statp) 314338032Speter MAP *map; 314438032Speter char *name; 314538032Speter char **av; 314638032Speter int *statp; 314738032Speter{ 314864562Sgshapiro int i; 314964562Sgshapiro int entries = 0; 315064562Sgshapiro int msgid; 315164562Sgshapiro int ret; 315264562Sgshapiro int vsize; 315364562Sgshapiro char *fp, *vp; 315464562Sgshapiro char *p, *q; 315564562Sgshapiro char *result = NULL; 315664562Sgshapiro LDAPMAP_STRUCT *lmap = NULL; 315738032Speter char keybuf[MAXNAME + 1]; 315864562Sgshapiro char filter[LDAPMAP_MAX_FILTER + 1]; 315938032Speter 316038032Speter if (tTd(38, 20)) 316164562Sgshapiro dprintf("ldapmap_lookup(%s, %s)\n", map->map_mname, name); 316238032Speter 316338032Speter /* Get ldap struct pointer from map */ 316464562Sgshapiro lmap = (LDAPMAP_STRUCT *) map->map_db1; 316564562Sgshapiro ldapmap_setopts(lmap->ldap_ld, lmap); 316638032Speter 316764562Sgshapiro (void) strlcpy(keybuf, name, sizeof keybuf); 316838032Speter 316938032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 317064562Sgshapiro { 317164562Sgshapiro# ifdef SUNET_ID 317238032Speter sunet_id_hash(keybuf); 317364562Sgshapiro# else /* SUNET_ID */ 317438032Speter makelower(keybuf); 317564562Sgshapiro# endif /* SUNET_ID */ 317664562Sgshapiro } 317738032Speter 317842575Speter /* substitute keybuf into filter, perhaps multiple times */ 317964562Sgshapiro memset(filter, '\0', sizeof filter); 318042575Speter fp = filter; 318164562Sgshapiro p = lmap->ldap_filter; 318242575Speter while ((q = strchr(p, '%')) != NULL) 318342575Speter { 318442575Speter if (q[1] == 's') 318542575Speter { 318642575Speter snprintf(fp, SPACELEFT(filter, fp), "%.*s%s", 318766494Sgshapiro (int) (q - p), p, keybuf); 318864562Sgshapiro fp += strlen(fp); 318942575Speter p = q + 2; 319042575Speter } 319164562Sgshapiro else if (q[1] == '0') 319264562Sgshapiro { 319364562Sgshapiro char *k = keybuf; 319464562Sgshapiro 319564562Sgshapiro snprintf(fp, SPACELEFT(filter, fp), "%.*s", 319666494Sgshapiro (int) (q - p), p); 319764562Sgshapiro fp += strlen(fp); 319864562Sgshapiro p = q + 2; 319964562Sgshapiro 320064562Sgshapiro /* Properly escape LDAP special characters */ 320164562Sgshapiro while (SPACELEFT(filter, fp) > 0 && 320264562Sgshapiro *k != '\0') 320364562Sgshapiro { 320464562Sgshapiro if (*k == '*' || *k == '(' || 320564562Sgshapiro *k == ')' || *k == '\\') 320664562Sgshapiro { 320764562Sgshapiro (void) strlcat(fp, 320864562Sgshapiro (*k == '*' ? "\\2A" : 320964562Sgshapiro (*k == '(' ? "\\28" : 321064562Sgshapiro (*k == ')' ? "\\29" : 321164562Sgshapiro (*k == '\\' ? "\\5C" : 321264562Sgshapiro "\00")))), 321364562Sgshapiro SPACELEFT(filter, fp)); 321464562Sgshapiro fp += strlen(fp); 321564562Sgshapiro k++; 321664562Sgshapiro } 321764562Sgshapiro else 321864562Sgshapiro *fp++ = *k++; 321964562Sgshapiro } 322064562Sgshapiro } 322142575Speter else 322242575Speter { 322342575Speter snprintf(fp, SPACELEFT(filter, fp), "%.*s", 322466494Sgshapiro (int) (q - p + 1), p); 322542575Speter p = q + (q[1] == '%' ? 2 : 1); 322664562Sgshapiro fp += strlen(fp); 322742575Speter } 322842575Speter } 322942575Speter snprintf(fp, SPACELEFT(filter, fp), "%s", p); 323042575Speter if (tTd(38, 20)) 323164562Sgshapiro dprintf("ldap search filter=%s\n", filter); 323238032Speter 323364562Sgshapiro lmap->ldap_res = NULL; 323464562Sgshapiro msgid = ldap_search(lmap->ldap_ld, lmap->ldap_base, lmap->ldap_scope, 323564562Sgshapiro filter, 323664562Sgshapiro (lmap->ldap_attr[0] == NULL ? NULL : 323764562Sgshapiro lmap->ldap_attr), 323864562Sgshapiro lmap->ldap_attrsonly); 323964562Sgshapiro if (msgid == -1) 324038032Speter { 324177349Sgshapiro int save_errno; 324277349Sgshapiro 324364562Sgshapiro errno = ldapmap_geterrno(lmap->ldap_ld) + E_LDAPBASE; 324477349Sgshapiro save_errno = errno; 324564562Sgshapiro if (!bitset(MF_OPTIONAL, map->map_mflags)) 324638032Speter { 324764562Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 324866494Sgshapiro syserr("Error in ldap_search using %s in map %s", 324964562Sgshapiro filter, map->map_mname); 325064562Sgshapiro else 325166494Sgshapiro syserr("421 4.0.0 Error in ldap_search using %s in map %s", 325264562Sgshapiro filter, map->map_mname); 325338032Speter } 325464562Sgshapiro *statp = EX_TEMPFAIL; 325566494Sgshapiro#ifdef LDAP_SERVER_DOWN 325677349Sgshapiro errno = save_errno; 325777349Sgshapiro if (errno == LDAP_SERVER_DOWN + E_LDAPBASE) 325866494Sgshapiro { 325966494Sgshapiro /* server disappeared, try reopen on next search */ 326077349Sgshapiro ldapmap_close(map); 326166494Sgshapiro } 326266494Sgshapiro#endif /* LDAP_SERVER_DOWN */ 326377349Sgshapiro errno = save_errno; 326464562Sgshapiro return NULL; 326564562Sgshapiro } 326664562Sgshapiro 326764562Sgshapiro *statp = EX_NOTFOUND; 326864562Sgshapiro vp = NULL; 326964562Sgshapiro 327064562Sgshapiro /* Get results (all if MF_NOREWRITE, otherwise one by one) */ 327164562Sgshapiro while ((ret = ldap_result(lmap->ldap_ld, msgid, 327264562Sgshapiro bitset(MF_NOREWRITE, map->map_mflags), 327364562Sgshapiro (lmap->ldap_timeout.tv_sec == 0 ? NULL : 327464562Sgshapiro &(lmap->ldap_timeout)), 327564562Sgshapiro &(lmap->ldap_res))) == LDAP_RES_SEARCH_ENTRY) 327664562Sgshapiro { 327764562Sgshapiro LDAPMessage *entry; 327864562Sgshapiro 327964562Sgshapiro if (bitset(MF_SINGLEMATCH, map->map_mflags)) 328038032Speter { 328164562Sgshapiro entries += ldap_count_entries(lmap->ldap_ld, 328264562Sgshapiro lmap->ldap_res); 328364562Sgshapiro if (entries > 1) 328464562Sgshapiro { 328564562Sgshapiro *statp = EX_NOTFOUND; 328664562Sgshapiro if (lmap->ldap_res != NULL) 328764562Sgshapiro { 328864562Sgshapiro ldap_msgfree(lmap->ldap_res); 328964562Sgshapiro lmap->ldap_res = NULL; 329064562Sgshapiro } 329164562Sgshapiro (void) ldap_abandon(lmap->ldap_ld, msgid); 329264562Sgshapiro if (vp != NULL) 329377349Sgshapiro sm_free(vp); 329464562Sgshapiro if (tTd(38, 25)) 329564562Sgshapiro dprintf("ldap search found multiple on a single match query\n"); 329664562Sgshapiro return NULL; 329764562Sgshapiro } 329864562Sgshapiro } 329964562Sgshapiro 330064562Sgshapiro /* If we don't want multiple values and we have one, break */ 330164562Sgshapiro if (map->map_coldelim == '\0' && vp != NULL) 330264562Sgshapiro break; 330364562Sgshapiro 330464562Sgshapiro /* Cycle through all entries */ 330564562Sgshapiro for (entry = ldap_first_entry(lmap->ldap_ld, lmap->ldap_res); 330664562Sgshapiro entry != NULL; 330764562Sgshapiro entry = ldap_next_entry(lmap->ldap_ld, lmap->ldap_res)) 330864562Sgshapiro { 330964562Sgshapiro BerElement *ber; 331064562Sgshapiro char *attr; 331164562Sgshapiro char **vals = NULL; 331264562Sgshapiro 331364562Sgshapiro /* 331464562Sgshapiro ** If matching only and found an entry, 331564562Sgshapiro ** no need to spin through attributes 331664562Sgshapiro */ 331764562Sgshapiro 331864562Sgshapiro if (*statp == EX_OK && 331964562Sgshapiro bitset(MF_MATCHONLY, map->map_mflags)) 332064562Sgshapiro continue; 332164562Sgshapiro 332264562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 332364562Sgshapiro /* 332464562Sgshapiro ** Reset value to prevent lingering 332564562Sgshapiro ** LDAP_DECODING_ERROR due to 332664562Sgshapiro ** OpenLDAP 1.X's hack (see below) 332764562Sgshapiro */ 332864562Sgshapiro 332964562Sgshapiro lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 333064562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 333164562Sgshapiro 333264562Sgshapiro for (attr = ldap_first_attribute(lmap->ldap_ld, entry, 333364562Sgshapiro &ber); 333464562Sgshapiro attr != NULL; 333564562Sgshapiro attr = ldap_next_attribute(lmap->ldap_ld, entry, 333664562Sgshapiro ber)) 333764562Sgshapiro { 333864562Sgshapiro char *tmp, *vp_tmp; 333964562Sgshapiro 334064562Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_FALSE) 334164562Sgshapiro { 334264562Sgshapiro vals = ldap_get_values(lmap->ldap_ld, 334364562Sgshapiro entry, 334464562Sgshapiro attr); 334564562Sgshapiro if (vals == NULL) 334664562Sgshapiro { 334764562Sgshapiro errno = ldapmap_geterrno(lmap->ldap_ld); 334864562Sgshapiro if (errno == LDAP_SUCCESS) 334964562Sgshapiro continue; 335064562Sgshapiro 335164562Sgshapiro /* Must be an error */ 335264562Sgshapiro errno += E_LDAPBASE; 335364562Sgshapiro if (!bitset(MF_OPTIONAL, 335464562Sgshapiro map->map_mflags)) 335564562Sgshapiro { 335664562Sgshapiro if (bitset(MF_NODEFER, 335764562Sgshapiro map->map_mflags)) 335864562Sgshapiro syserr("Error getting LDAP values in map %s", 335964562Sgshapiro map->map_mname); 336064562Sgshapiro else 336164562Sgshapiro syserr("421 4.0.0 Error getting LDAP values in map %s", 336264562Sgshapiro map->map_mname); 336364562Sgshapiro } 336464562Sgshapiro *statp = EX_TEMPFAIL; 336564562Sgshapiro# if USING_NETSCAPE_LDAP 336666494Sgshapiro ldap_memfree(attr); 336764562Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 336864562Sgshapiro if (lmap->ldap_res != NULL) 336964562Sgshapiro { 337064562Sgshapiro ldap_msgfree(lmap->ldap_res); 337164562Sgshapiro lmap->ldap_res = NULL; 337264562Sgshapiro } 337364562Sgshapiro (void) ldap_abandon(lmap->ldap_ld, 337464562Sgshapiro msgid); 337564562Sgshapiro if (vp != NULL) 337677349Sgshapiro sm_free(vp); 337764562Sgshapiro return NULL; 337864562Sgshapiro } 337964562Sgshapiro } 338064562Sgshapiro 338164562Sgshapiro *statp = EX_OK; 338264562Sgshapiro 338364562Sgshapiro# if !defined(LDAP_VERSION_MAX) && !defined(LDAP_OPT_SIZELIMIT) 338464562Sgshapiro /* 338564562Sgshapiro ** Reset value to prevent lingering 338664562Sgshapiro ** LDAP_DECODING_ERROR due to 338764562Sgshapiro ** OpenLDAP 1.X's hack (see below) 338864562Sgshapiro */ 338964562Sgshapiro 339064562Sgshapiro lmap->ldap_ld->ld_errno = LDAP_SUCCESS; 339164562Sgshapiro# endif /* !defined(LDAP_VERSION_MAX) !defined(LDAP_OPT_SIZELIMIT) */ 339264562Sgshapiro 339364562Sgshapiro /* 339464562Sgshapiro ** If matching only, 339564562Sgshapiro ** no need to spin through entries 339664562Sgshapiro */ 339764562Sgshapiro 339864562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 339964562Sgshapiro continue; 340064562Sgshapiro 340164562Sgshapiro /* 340264562Sgshapiro ** If we don't want multiple values, 340364562Sgshapiro ** return first found. 340464562Sgshapiro */ 340564562Sgshapiro 340664562Sgshapiro if (map->map_coldelim == '\0') 340764562Sgshapiro { 340864562Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 340964562Sgshapiro { 341064562Sgshapiro vp = newstr(attr); 341164562Sgshapiro# if USING_NETSCAPE_LDAP 341266494Sgshapiro ldap_memfree(attr); 341364562Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 341464562Sgshapiro break; 341564562Sgshapiro } 341664562Sgshapiro 341764562Sgshapiro if (vals[0] == NULL) 341864562Sgshapiro { 341964562Sgshapiro ldap_value_free(vals); 342064562Sgshapiro# if USING_NETSCAPE_LDAP 342166494Sgshapiro ldap_memfree(attr); 342264562Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 342364562Sgshapiro continue; 342464562Sgshapiro } 342564562Sgshapiro 342664562Sgshapiro vp = newstr(vals[0]); 342764562Sgshapiro ldap_value_free(vals); 342864562Sgshapiro# if USING_NETSCAPE_LDAP 342966494Sgshapiro ldap_memfree(attr); 343064562Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 343164562Sgshapiro break; 343264562Sgshapiro } 343364562Sgshapiro 343464562Sgshapiro /* attributes only */ 343564562Sgshapiro if (lmap->ldap_attrsonly == LDAPMAP_TRUE) 343664562Sgshapiro { 343764562Sgshapiro if (vp == NULL) 343864562Sgshapiro vp = newstr(attr); 343964562Sgshapiro else 344064562Sgshapiro { 344164562Sgshapiro vsize = strlen(vp) + 344264562Sgshapiro strlen(attr) + 2; 344364562Sgshapiro tmp = xalloc(vsize); 344464562Sgshapiro snprintf(tmp, vsize, "%s%c%s", 344564562Sgshapiro vp, map->map_coldelim, 344664562Sgshapiro attr); 344777349Sgshapiro sm_free(vp); 344864562Sgshapiro vp = tmp; 344964562Sgshapiro } 345064562Sgshapiro# if USING_NETSCAPE_LDAP 345166494Sgshapiro ldap_memfree(attr); 345264562Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 345364562Sgshapiro continue; 345464562Sgshapiro } 345564562Sgshapiro 345664562Sgshapiro /* 345764562Sgshapiro ** If there is more than one, 345864562Sgshapiro ** munge then into a map_coldelim 345964562Sgshapiro ** separated string 346064562Sgshapiro */ 346164562Sgshapiro 346264562Sgshapiro vsize = 0; 346364562Sgshapiro for (i = 0; vals[i] != NULL; i++) 346464562Sgshapiro vsize += strlen(vals[i]) + 1; 346564562Sgshapiro vp_tmp = xalloc(vsize); 346664562Sgshapiro *vp_tmp = '\0'; 346764562Sgshapiro 346864562Sgshapiro p = vp_tmp; 346964562Sgshapiro for (i = 0; vals[i] != NULL; i++) 347064562Sgshapiro { 347164562Sgshapiro p += strlcpy(p, vals[i], 347264562Sgshapiro vsize - (p - vp_tmp)); 347364562Sgshapiro if (p >= vp_tmp + vsize) 347464562Sgshapiro syserr("ldapmap_lookup: Internal error: buffer too small for LDAP values"); 347564562Sgshapiro if (vals[i + 1] != NULL) 347664562Sgshapiro *p++ = map->map_coldelim; 347764562Sgshapiro } 347864562Sgshapiro 347964562Sgshapiro ldap_value_free(vals); 348064562Sgshapiro# if USING_NETSCAPE_LDAP 348166494Sgshapiro ldap_memfree(attr); 348264562Sgshapiro# endif /* USING_NETSCAPE_LDAP */ 348364562Sgshapiro if (vp == NULL) 348464562Sgshapiro { 348564562Sgshapiro vp = vp_tmp; 348664562Sgshapiro continue; 348764562Sgshapiro } 348864562Sgshapiro vsize = strlen(vp) + strlen(vp_tmp) + 2; 348964562Sgshapiro tmp = xalloc(vsize); 349064562Sgshapiro snprintf(tmp, vsize, "%s%c%s", 349164562Sgshapiro vp, map->map_coldelim, vp_tmp); 349264562Sgshapiro 349377349Sgshapiro sm_free(vp); 349477349Sgshapiro sm_free(vp_tmp); 349564562Sgshapiro vp = tmp; 349664562Sgshapiro } 349764562Sgshapiro errno = ldapmap_geterrno(lmap->ldap_ld); 349864562Sgshapiro 349964562Sgshapiro /* 350064562Sgshapiro ** We check errno != LDAP_DECODING_ERROR since 350164562Sgshapiro ** OpenLDAP 1.X has a very ugly *undocumented* 350264562Sgshapiro ** hack of returning this error code from 350364562Sgshapiro ** ldap_next_attribute() if the library freed the 350464562Sgshapiro ** ber attribute. See: 350564562Sgshapiro ** http://www.openldap.org/lists/openldap-devel/9901/msg00064.html 350664562Sgshapiro */ 350764562Sgshapiro 350864562Sgshapiro if (errno != LDAP_SUCCESS && 350964562Sgshapiro errno != LDAP_DECODING_ERROR) 351064562Sgshapiro { 351164562Sgshapiro /* Must be an error */ 351264562Sgshapiro errno += E_LDAPBASE; 351364562Sgshapiro if (!bitset(MF_OPTIONAL, map->map_mflags)) 351464562Sgshapiro { 351564562Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 351664562Sgshapiro syserr("Error getting LDAP attributes in map %s", 351764562Sgshapiro map->map_mname); 351864562Sgshapiro else 351964562Sgshapiro syserr("421 4.0.0 Error getting LDAP attributes in map %s", 352064562Sgshapiro map->map_mname); 352164562Sgshapiro } 352264562Sgshapiro *statp = EX_TEMPFAIL; 352364562Sgshapiro if (lmap->ldap_res != NULL) 352464562Sgshapiro { 352564562Sgshapiro ldap_msgfree(lmap->ldap_res); 352664562Sgshapiro lmap->ldap_res = NULL; 352764562Sgshapiro } 352864562Sgshapiro (void) ldap_abandon(lmap->ldap_ld, msgid); 352964562Sgshapiro if (vp != NULL) 353077349Sgshapiro sm_free(vp); 353164562Sgshapiro return NULL; 353264562Sgshapiro } 353364562Sgshapiro 353464562Sgshapiro /* We don't want multiple values and we have one */ 353564562Sgshapiro if (map->map_coldelim == '\0' && vp != NULL) 353664562Sgshapiro break; 353764562Sgshapiro } 353864562Sgshapiro errno = ldapmap_geterrno(lmap->ldap_ld); 353964562Sgshapiro if (errno != LDAP_SUCCESS && errno != LDAP_DECODING_ERROR) 354064562Sgshapiro { 354164562Sgshapiro /* Must be an error */ 354264562Sgshapiro errno += E_LDAPBASE; 354338032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 354438032Speter { 354564562Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 354664562Sgshapiro syserr("Error getting LDAP entries in map %s", 354764562Sgshapiro map->map_mname); 354864562Sgshapiro else 354964562Sgshapiro syserr("421 4.0.0 Error getting LDAP entries in map %s", 355064562Sgshapiro map->map_mname); 355138032Speter } 355238032Speter *statp = EX_TEMPFAIL; 355364562Sgshapiro if (lmap->ldap_res != NULL) 355464562Sgshapiro { 355564562Sgshapiro ldap_msgfree(lmap->ldap_res); 355664562Sgshapiro lmap->ldap_res = NULL; 355764562Sgshapiro } 355864562Sgshapiro (void) ldap_abandon(lmap->ldap_ld, msgid); 355964562Sgshapiro if (vp != NULL) 356077349Sgshapiro sm_free(vp); 356164562Sgshapiro return NULL; 356238032Speter } 356364562Sgshapiro ldap_msgfree(lmap->ldap_res); 356464562Sgshapiro lmap->ldap_res = NULL; 356538032Speter } 356638032Speter 356764562Sgshapiro /* 356864562Sgshapiro ** If grabbing all results at once for MF_NOREWRITE and 356964562Sgshapiro ** only want a single match, make sure that's all we have 357064562Sgshapiro */ 357164562Sgshapiro 357264562Sgshapiro if (ret == LDAP_RES_SEARCH_RESULT && 357364562Sgshapiro bitset(MF_NOREWRITE|MF_SINGLEMATCH, map->map_mflags)) 357438032Speter { 357564562Sgshapiro entries += ldap_count_entries(lmap->ldap_ld, lmap->ldap_res); 357664562Sgshapiro if (entries > 1) 357764562Sgshapiro { 357864562Sgshapiro *statp = EX_NOTFOUND; 357964562Sgshapiro if (lmap->ldap_res != NULL) 358064562Sgshapiro { 358164562Sgshapiro ldap_msgfree(lmap->ldap_res); 358264562Sgshapiro lmap->ldap_res = NULL; 358364562Sgshapiro } 358464562Sgshapiro if (vp != NULL) 358577349Sgshapiro sm_free(vp); 358664562Sgshapiro return NULL; 358764562Sgshapiro } 358864562Sgshapiro *statp = EX_OK; 358938032Speter } 359038032Speter 359164562Sgshapiro if (ret == 0) 359264562Sgshapiro errno = ETIMEDOUT; 359364562Sgshapiro else 359464562Sgshapiro errno = ldapmap_geterrno(lmap->ldap_ld); 359564562Sgshapiro if (errno != LDAP_SUCCESS) 359638032Speter { 359777349Sgshapiro int save_errno; 359877349Sgshapiro 359964562Sgshapiro /* Must be an error */ 360064562Sgshapiro if (ret != 0) 360164562Sgshapiro errno += E_LDAPBASE; 360277349Sgshapiro save_errno = errno; 360377349Sgshapiro 360464562Sgshapiro if (!bitset(MF_OPTIONAL, map->map_mflags)) 360564562Sgshapiro { 360664562Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 360764562Sgshapiro syserr("Error getting LDAP results in map %s", 360864562Sgshapiro map->map_mname); 360964562Sgshapiro else 361064562Sgshapiro syserr("421 4.0.0 Error getting LDAP results in map %s", 361164562Sgshapiro map->map_mname); 361264562Sgshapiro } 361364562Sgshapiro *statp = EX_TEMPFAIL; 361464562Sgshapiro if (vp != NULL) 361577349Sgshapiro sm_free(vp); 361677349Sgshapiro#ifdef LDAP_SERVER_DOWN 361777349Sgshapiro errno = save_errno; 361877349Sgshapiro if (errno == LDAP_SERVER_DOWN + E_LDAPBASE) 361977349Sgshapiro { 362077349Sgshapiro /* server disappeared, try reopen on next search */ 362177349Sgshapiro ldapmap_close(map); 362277349Sgshapiro } 362377349Sgshapiro#endif /* LDAP_SERVER_DOWN */ 362477349Sgshapiro errno = save_errno; 362564562Sgshapiro return NULL; 362638032Speter } 362738032Speter 362864562Sgshapiro /* Did we match anything? */ 362971345Sgshapiro if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags)) 363064562Sgshapiro return NULL; 363138032Speter 363264562Sgshapiro /* 363364562Sgshapiro ** If MF_NOREWRITE, we are special map which doesn't 363464562Sgshapiro ** actually return a map value. Instead, we don't free 363564562Sgshapiro ** ldap_res and let the calling function process the LDAP 363664562Sgshapiro ** results. The caller should ldap_msgfree(lmap->ldap_res). 363764562Sgshapiro */ 363838032Speter 363964562Sgshapiro if (bitset(MF_NOREWRITE, map->map_mflags)) 364064562Sgshapiro { 364171345Sgshapiro if (vp != NULL) 364277349Sgshapiro sm_free(vp); 364364562Sgshapiro return ""; 364464562Sgshapiro } 364538032Speter 364664562Sgshapiro if (*statp == EX_OK) 364764562Sgshapiro { 364864562Sgshapiro if (LogLevel > 9) 364964562Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, 365071345Sgshapiro "ldap %.100s => %s", name, 365171345Sgshapiro vp == NULL ? "<NULL>" : vp); 365264562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 365364562Sgshapiro result = map_rewrite(map, name, strlen(name), NULL); 365464562Sgshapiro else 365571345Sgshapiro { 365671345Sgshapiro /* vp != NULL according to test above */ 365764562Sgshapiro result = map_rewrite(map, vp, strlen(vp), av); 365871345Sgshapiro } 365971345Sgshapiro if (vp != NULL) 366077349Sgshapiro sm_free(vp); 366164562Sgshapiro } 366264562Sgshapiro return result; 366338032Speter} 366438032Speter 366538032Speter/* 366664562Sgshapiro** LDAPMAP_FINDCONN -- find an LDAP connection to the server 366764562Sgshapiro** 366864562Sgshapiro** Cache LDAP connections based on the host, port, bind DN, 366966494Sgshapiro** secret, and PID so we don't have multiple connections open to 367066494Sgshapiro** the same server for different maps. Need a separate connection 367166494Sgshapiro** per PID since a parent process may close the map before the 367266494Sgshapiro** child is done with it. 367364562Sgshapiro** 367464562Sgshapiro** Parameters: 367564562Sgshapiro** lmap -- LDAP map information 367664562Sgshapiro** 367764562Sgshapiro** Returns: 367864562Sgshapiro** Symbol table entry for the LDAP connection. 367964562Sgshapiro** 368038032Speter*/ 368138032Speter 368264562Sgshapirostatic STAB * 368364562Sgshapiroldapmap_findconn(lmap) 368464562Sgshapiro LDAPMAP_STRUCT *lmap; 368538032Speter{ 368664562Sgshapiro int len; 368764562Sgshapiro char *nbuf; 368864562Sgshapiro STAB *s; 368938032Speter 369064562Sgshapiro len = (lmap->ldap_host == NULL ? strlen("localhost") : 369164562Sgshapiro strlen(lmap->ldap_host)) + 1 + 8 + 1 + 369264562Sgshapiro (lmap->ldap_binddn == NULL ? 0 : strlen(lmap->ldap_binddn)) + 369364562Sgshapiro 1 + 369464562Sgshapiro (lmap->ldap_secret == NULL ? 0 : strlen(lmap->ldap_secret)) + 369566494Sgshapiro 8 + 1; 369664562Sgshapiro nbuf = xalloc(len); 369766494Sgshapiro snprintf(nbuf, len, "%s%c%d%c%s%c%s%d", 369864562Sgshapiro (lmap->ldap_host == NULL ? "localhost" : lmap->ldap_host), 369964562Sgshapiro CONDELSE, 370064562Sgshapiro lmap->ldap_port, 370164562Sgshapiro CONDELSE, 370264562Sgshapiro (lmap->ldap_binddn == NULL ? "" : lmap->ldap_binddn), 370364562Sgshapiro CONDELSE, 370466494Sgshapiro (lmap->ldap_secret == NULL ? "" : lmap->ldap_secret), 370577349Sgshapiro (int) getpid()); 370677349Sgshapiro s = stab(nbuf, ST_LMAP, ST_ENTER); 370777349Sgshapiro sm_free(nbuf); 370864562Sgshapiro return s; 370964562Sgshapiro} 371064562Sgshapiro/* 371164562Sgshapiro** LDAPMAP_SETOPTS -- set LDAP options 371264562Sgshapiro** 371364562Sgshapiro** Parameters: 371464562Sgshapiro** ld -- LDAP session handle 371564562Sgshapiro** lmap -- LDAP map information 371664562Sgshapiro** 371764562Sgshapiro** Returns: 371864562Sgshapiro** None. 371964562Sgshapiro** 372064562Sgshapiro*/ 372164562Sgshapiro 372264562Sgshapirostatic void 372364562Sgshapiroldapmap_setopts(ld, lmap) 372464562Sgshapiro LDAP *ld; 372564562Sgshapiro LDAPMAP_STRUCT *lmap; 372664562Sgshapiro{ 372764562Sgshapiro# if USE_LDAP_SET_OPTION 372864562Sgshapiro ldap_set_option(ld, LDAP_OPT_DEREF, &lmap->ldap_deref); 372964562Sgshapiro if (bitset(LDAP_OPT_REFERRALS, lmap->ldap_options)) 373064562Sgshapiro ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_ON); 373138032Speter else 373264562Sgshapiro ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 373364562Sgshapiro ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &lmap->ldap_sizelimit); 373464562Sgshapiro ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &lmap->ldap_timelimit); 373564562Sgshapiro# else /* USE_LDAP_SET_OPTION */ 373664562Sgshapiro /* From here on in we can use ldap internal timelimits */ 373764562Sgshapiro ld->ld_deref = lmap->ldap_deref; 373864562Sgshapiro ld->ld_options = lmap->ldap_options; 373964562Sgshapiro ld->ld_sizelimit = lmap->ldap_sizelimit; 374064562Sgshapiro ld->ld_timelimit = lmap->ldap_timelimit; 374164562Sgshapiro# endif /* USE_LDAP_SET_OPTION */ 374238032Speter} 374364562Sgshapiro/* 374464562Sgshapiro** LDAPMAP_GETERRNO -- get ldap errno value 374564562Sgshapiro** 374664562Sgshapiro** Parameters: 374764562Sgshapiro** ld -- LDAP session handle 374864562Sgshapiro** 374964562Sgshapiro** Returns: 375064562Sgshapiro** LDAP errno. 375164562Sgshapiro** 375264562Sgshapiro*/ 375338032Speter 375464562Sgshapirostatic int 375564562Sgshapiroldapmap_geterrno(ld) 375664562Sgshapiro LDAP *ld; 375764562Sgshapiro{ 375864562Sgshapiro int err = LDAP_SUCCESS; 375964562Sgshapiro 376064562Sgshapiro# if defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 376164562Sgshapiro (void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &err); 376264562Sgshapiro# else /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 376364562Sgshapiro# ifdef LDAP_OPT_SIZELIMIT 376464562Sgshapiro err = ldap_get_lderrno(ld, NULL, NULL); 376564562Sgshapiro# else /* LDAP_OPT_SIZELIMIT */ 376664562Sgshapiro err = ld->ld_errno; 376764562Sgshapiro 376864562Sgshapiro /* 376964562Sgshapiro ** Reset value to prevent lingering LDAP_DECODING_ERROR due to 377064562Sgshapiro ** OpenLDAP 1.X's hack (see above) 377164562Sgshapiro */ 377264562Sgshapiro 377364562Sgshapiro ld->ld_errno = LDAP_SUCCESS; 377464562Sgshapiro# endif /* LDAP_OPT_SIZELIMIT */ 377564562Sgshapiro# endif /* defined(LDAP_VERSION_MAX) && LDAP_VERSION_MAX >= 3 */ 377664562Sgshapiro return err; 377764562Sgshapiro} 377864562Sgshapiro 377938032Speter/* 378064562Sgshapiro** LDAPX_MAP_PARSEARGS -- print warning about use of ldapx map. 378138032Speter*/ 378238032Speter 378338032Speterbool 378464562Sgshapiroldapx_map_parseargs(map, args) 378538032Speter MAP *map; 378638032Speter char *args; 378738032Speter{ 378864562Sgshapiro printf("Warning: The \"ldapx\" map class is deprecated and will be removed in a future\n"); 378964562Sgshapiro printf(" version. Use the \"ldap\" map class instead for map \"%s\".\n", 379064562Sgshapiro map->map_mname); 379164562Sgshapiro return ldapmap_parseargs(map, args); 379264562Sgshapiro} 379338032Speter 379464562Sgshapiro/* 379564562Sgshapiro** LDAPMAP_PARSEARGS -- parse ldap map definition args. 379664562Sgshapiro*/ 379738032Speter 379864562Sgshapirostruct lamvalues LDAPAuthMethods[] = 379964562Sgshapiro{ 380064562Sgshapiro { "none", LDAP_AUTH_NONE }, 380164562Sgshapiro { "simple", LDAP_AUTH_SIMPLE }, 380264562Sgshapiro# ifdef LDAP_AUTH_KRBV4 380364562Sgshapiro { "krbv4", LDAP_AUTH_KRBV4 }, 380464562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */ 380564562Sgshapiro { NULL, 0 } 380664562Sgshapiro}; 380738032Speter 380864562Sgshapirostruct ladvalues LDAPAliasDereference[] = 380964562Sgshapiro{ 381064562Sgshapiro { "never", LDAP_DEREF_NEVER }, 381164562Sgshapiro { "always", LDAP_DEREF_ALWAYS }, 381264562Sgshapiro { "search", LDAP_DEREF_SEARCHING }, 381364562Sgshapiro { "find", LDAP_DEREF_FINDING }, 381464562Sgshapiro { NULL, 0 } 381564562Sgshapiro}; 381638032Speter 381764562Sgshapirostruct lssvalues LDAPSearchScope[] = 381864562Sgshapiro{ 381964562Sgshapiro { "base", LDAP_SCOPE_BASE }, 382064562Sgshapiro { "one", LDAP_SCOPE_ONELEVEL }, 382164562Sgshapiro { "sub", LDAP_SCOPE_SUBTREE }, 382264562Sgshapiro { NULL, 0 } 382364562Sgshapiro}; 382438032Speter 382564562Sgshapirobool 382664562Sgshapiroldapmap_parseargs(map, args) 382764562Sgshapiro MAP *map; 382864562Sgshapiro char *args; 382964562Sgshapiro{ 383064562Sgshapiro bool secretread = TRUE; 383164562Sgshapiro int i; 383264562Sgshapiro register char *p = args; 383364562Sgshapiro LDAPMAP_STRUCT *lmap; 383464562Sgshapiro struct lamvalues *lam; 383564562Sgshapiro struct ladvalues *lad; 383664562Sgshapiro struct lssvalues *lss; 383764562Sgshapiro char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD]; 383864562Sgshapiro 383964562Sgshapiro /* Get ldap struct pointer from map */ 384064562Sgshapiro lmap = (LDAPMAP_STRUCT *) map->map_db1; 384164562Sgshapiro 384264562Sgshapiro /* Check if setting the initial LDAP defaults */ 384364562Sgshapiro if (lmap == NULL || lmap != LDAPDefaults) 384464562Sgshapiro { 384564562Sgshapiro /* We need to alloc an LDAPMAP_STRUCT struct */ 384664562Sgshapiro lmap = (LDAPMAP_STRUCT *) xalloc(sizeof *lmap); 384764562Sgshapiro if (LDAPDefaults == NULL) 384864562Sgshapiro ldapmap_clear(lmap); 384964562Sgshapiro else 385064562Sgshapiro STRUCTCOPY(*LDAPDefaults, *lmap); 385164562Sgshapiro } 385264562Sgshapiro 385364562Sgshapiro /* there is no check whether there is really an argument */ 385464562Sgshapiro map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL; 385564562Sgshapiro map->map_spacesub = SpaceSub; /* default value */ 385638032Speter for (;;) 385738032Speter { 385838032Speter while (isascii(*p) && isspace(*p)) 385938032Speter p++; 386038032Speter if (*p != '-') 386138032Speter break; 386238032Speter switch (*++p) 386338032Speter { 386438032Speter case 'N': 386538032Speter map->map_mflags |= MF_INCLNULL; 386638032Speter map->map_mflags &= ~MF_TRY0NULL; 386738032Speter break; 386838032Speter 386938032Speter case 'O': 387038032Speter map->map_mflags &= ~MF_TRY1NULL; 387138032Speter break; 387238032Speter 387338032Speter case 'o': 387438032Speter map->map_mflags |= MF_OPTIONAL; 387538032Speter break; 387638032Speter 387738032Speter case 'f': 387838032Speter map->map_mflags |= MF_NOFOLDCASE; 387938032Speter break; 388038032Speter 388138032Speter case 'm': 388238032Speter map->map_mflags |= MF_MATCHONLY; 388338032Speter break; 388438032Speter 388538032Speter case 'A': 388638032Speter map->map_mflags |= MF_APPEND; 388738032Speter break; 388838032Speter 388938032Speter case 'q': 389038032Speter map->map_mflags |= MF_KEEPQUOTES; 389138032Speter break; 389238032Speter 389338032Speter case 'a': 389438032Speter map->map_app = ++p; 389538032Speter break; 389638032Speter 389738032Speter case 'T': 389838032Speter map->map_tapp = ++p; 389938032Speter break; 390038032Speter 390164562Sgshapiro case 't': 390264562Sgshapiro map->map_mflags |= MF_NODEFER; 390364562Sgshapiro break; 390464562Sgshapiro 390564562Sgshapiro case 'S': 390664562Sgshapiro map->map_spacesub = *++p; 390764562Sgshapiro break; 390864562Sgshapiro 390964562Sgshapiro case 'D': 391064562Sgshapiro map->map_mflags |= MF_DEFER; 391164562Sgshapiro break; 391264562Sgshapiro 391364562Sgshapiro case 'z': 391464562Sgshapiro if (*++p != '\\') 391564562Sgshapiro map->map_coldelim = *p; 391664562Sgshapiro else 391764562Sgshapiro { 391864562Sgshapiro switch (*++p) 391964562Sgshapiro { 392064562Sgshapiro case 'n': 392164562Sgshapiro map->map_coldelim = '\n'; 392264562Sgshapiro break; 392364562Sgshapiro 392464562Sgshapiro case 't': 392564562Sgshapiro map->map_coldelim = '\t'; 392664562Sgshapiro break; 392764562Sgshapiro 392864562Sgshapiro default: 392964562Sgshapiro map->map_coldelim = '\\'; 393064562Sgshapiro } 393164562Sgshapiro } 393264562Sgshapiro break; 393364562Sgshapiro 393464562Sgshapiro /* Start of ldapmap specific args */ 393538032Speter case 'k': /* search field */ 393638032Speter while (isascii(*++p) && isspace(*p)) 393738032Speter continue; 393864562Sgshapiro lmap->ldap_filter = p; 393938032Speter break; 394038032Speter 394138032Speter case 'v': /* attr to return */ 394238032Speter while (isascii(*++p) && isspace(*p)) 394338032Speter continue; 394464562Sgshapiro lmap->ldap_attr[0] = p; 394564562Sgshapiro lmap->ldap_attr[1] = NULL; 394638032Speter break; 394738032Speter 394864562Sgshapiro case '1': 394964562Sgshapiro map->map_mflags |= MF_SINGLEMATCH; 395064562Sgshapiro break; 395164562Sgshapiro 395238032Speter /* args stolen from ldapsearch.c */ 395338032Speter case 'R': /* don't auto chase referrals */ 395464562Sgshapiro# ifdef LDAP_REFERRALS 395538032Speter lmap->ldap_options &= ~LDAP_OPT_REFERRALS; 395664562Sgshapiro# else /* LDAP_REFERRALS */ 395738032Speter syserr("compile with -DLDAP_REFERRALS for referral support\n"); 395864562Sgshapiro# endif /* LDAP_REFERRALS */ 395938032Speter break; 396038032Speter 396164562Sgshapiro case 'n': /* retrieve attribute names only */ 396264562Sgshapiro lmap->ldap_attrsonly = LDAPMAP_TRUE; 396338032Speter break; 396438032Speter 396564562Sgshapiro case 'r': /* alias dereferencing */ 396664562Sgshapiro while (isascii(*++p) && isspace(*p)) 396764562Sgshapiro continue; 396864562Sgshapiro 396964562Sgshapiro if (strncasecmp(p, "LDAP_DEREF_", 11) == 0) 397064562Sgshapiro p += 11; 397164562Sgshapiro 397264562Sgshapiro for (lad = LDAPAliasDereference; 397364562Sgshapiro lad != NULL && lad->lad_name != NULL; lad++) 397438032Speter { 397564562Sgshapiro if (strncasecmp(p, lad->lad_name, 397664562Sgshapiro strlen(lad->lad_name)) == 0) 397764562Sgshapiro break; 397838032Speter } 397964562Sgshapiro if (lad->lad_name != NULL) 398064562Sgshapiro lmap->ldap_deref = lad->lad_code; 398164562Sgshapiro else 398238032Speter { 398364562Sgshapiro /* bad config line */ 398464562Sgshapiro if (!bitset(MCF_OPTFILE, 398564562Sgshapiro map->map_class->map_cflags)) 398664562Sgshapiro { 398764562Sgshapiro char *ptr; 398864562Sgshapiro 398964562Sgshapiro if ((ptr = strchr(p, ' ')) != NULL) 399064562Sgshapiro *ptr = '\0'; 399173188Sgshapiro syserr("Deref must be [never|always|search|find] (not %s) in map %s", 399264562Sgshapiro p, map->map_mname); 399364562Sgshapiro if (ptr != NULL) 399464562Sgshapiro *ptr = ' '; 399564562Sgshapiro return FALSE; 399664562Sgshapiro } 399738032Speter } 399864562Sgshapiro break; 399964562Sgshapiro 400064562Sgshapiro case 's': /* search scope */ 400164562Sgshapiro while (isascii(*++p) && isspace(*p)) 400264562Sgshapiro continue; 400364562Sgshapiro 400464562Sgshapiro if (strncasecmp(p, "LDAP_SCOPE_", 11) == 0) 400564562Sgshapiro p += 11; 400664562Sgshapiro 400764562Sgshapiro for (lss = LDAPSearchScope; 400864562Sgshapiro lss != NULL && lss->lss_name != NULL; lss++) 400938032Speter { 401064562Sgshapiro if (strncasecmp(p, lss->lss_name, 401164562Sgshapiro strlen(lss->lss_name)) == 0) 401264562Sgshapiro break; 401338032Speter } 401464562Sgshapiro if (lss->lss_name != NULL) 401564562Sgshapiro lmap->ldap_scope = lss->lss_code; 401638032Speter else 401764562Sgshapiro { 401864562Sgshapiro /* bad config line */ 401964562Sgshapiro if (!bitset(MCF_OPTFILE, 402064562Sgshapiro map->map_class->map_cflags)) 402138032Speter { 402238032Speter char *ptr; 402338032Speter 402438032Speter if ((ptr = strchr(p, ' ')) != NULL) 402538032Speter *ptr = '\0'; 402673188Sgshapiro syserr("Scope must be [base|one|sub] (not %s) in map %s", 402738032Speter p, map->map_mname); 402838032Speter if (ptr != NULL) 402938032Speter *ptr = ' '; 403038032Speter return FALSE; 403138032Speter } 403238032Speter } 403338032Speter break; 403438032Speter 403538032Speter case 'h': /* ldap host */ 403638032Speter while (isascii(*++p) && isspace(*p)) 403738032Speter continue; 403864562Sgshapiro lmap->ldap_host = p; 403938032Speter break; 404038032Speter 404138032Speter case 'b': /* search base */ 404238032Speter while (isascii(*++p) && isspace(*p)) 404338032Speter continue; 404464562Sgshapiro lmap->ldap_base = p; 404538032Speter break; 404638032Speter 404738032Speter case 'p': /* ldap port */ 404838032Speter while (isascii(*++p) && isspace(*p)) 404938032Speter continue; 405064562Sgshapiro lmap->ldap_port = atoi(p); 405138032Speter break; 405238032Speter 405338032Speter case 'l': /* time limit */ 405438032Speter while (isascii(*++p) && isspace(*p)) 405538032Speter continue; 405664562Sgshapiro lmap->ldap_timelimit = atoi(p); 405764562Sgshapiro lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit; 405838032Speter break; 405938032Speter 406064562Sgshapiro case 'Z': 406164562Sgshapiro while (isascii(*++p) && isspace(*p)) 406264562Sgshapiro continue; 406364562Sgshapiro lmap->ldap_sizelimit = atoi(p); 406464562Sgshapiro break; 406564562Sgshapiro 406664562Sgshapiro case 'd': /* Dn to bind to server as */ 406764562Sgshapiro while (isascii(*++p) && isspace(*p)) 406864562Sgshapiro continue; 406964562Sgshapiro lmap->ldap_binddn = p; 407064562Sgshapiro break; 407164562Sgshapiro 407264562Sgshapiro case 'M': /* Method for binding */ 407364562Sgshapiro while (isascii(*++p) && isspace(*p)) 407464562Sgshapiro continue; 407564562Sgshapiro 407664562Sgshapiro if (strncasecmp(p, "LDAP_AUTH_", 10) == 0) 407764562Sgshapiro p += 10; 407864562Sgshapiro 407964562Sgshapiro for (lam = LDAPAuthMethods; 408064562Sgshapiro lam != NULL && lam->lam_name != NULL; lam++) 408164562Sgshapiro { 408264562Sgshapiro if (strncasecmp(p, lam->lam_name, 408364562Sgshapiro strlen(lam->lam_name)) == 0) 408464562Sgshapiro break; 408564562Sgshapiro } 408664562Sgshapiro if (lam->lam_name != NULL) 408764562Sgshapiro lmap->ldap_method = lam->lam_code; 408864562Sgshapiro else 408964562Sgshapiro { 409064562Sgshapiro /* bad config line */ 409164562Sgshapiro if (!bitset(MCF_OPTFILE, 409264562Sgshapiro map->map_class->map_cflags)) 409364562Sgshapiro { 409464562Sgshapiro char *ptr; 409564562Sgshapiro 409664562Sgshapiro if ((ptr = strchr(p, ' ')) != NULL) 409764562Sgshapiro *ptr = '\0'; 409873188Sgshapiro syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s", 409964562Sgshapiro p, map->map_mname); 410064562Sgshapiro if (ptr != NULL) 410164562Sgshapiro *ptr = ' '; 410264562Sgshapiro return FALSE; 410364562Sgshapiro } 410464562Sgshapiro } 410564562Sgshapiro 410664562Sgshapiro break; 410764562Sgshapiro 410864562Sgshapiro /* 410964562Sgshapiro ** This is a string that is dependent on the 411064562Sgshapiro ** method used defined above. 411164562Sgshapiro */ 411264562Sgshapiro 411364562Sgshapiro case 'P': /* Secret password for binding */ 411464562Sgshapiro while (isascii(*++p) && isspace(*p)) 411564562Sgshapiro continue; 411664562Sgshapiro lmap->ldap_secret = p; 411764562Sgshapiro secretread = FALSE; 411864562Sgshapiro break; 411964562Sgshapiro 412064562Sgshapiro default: 412164562Sgshapiro syserr("Illegal option %c map %s", *p, map->map_mname); 412264562Sgshapiro break; 412338032Speter } 412438032Speter 412564562Sgshapiro /* need to account for quoted strings here */ 412664562Sgshapiro while (*p != '\0' && !(isascii(*p) && isspace(*p))) 412738032Speter { 412838032Speter if (*p == '"') 412938032Speter { 413038032Speter while (*++p != '"' && *p != '\0') 413138032Speter continue; 413238032Speter if (*p != '\0') 413338032Speter p++; 413438032Speter } 413538032Speter else 413638032Speter p++; 413738032Speter } 413838032Speter 413938032Speter if (*p != '\0') 414038032Speter *p++ = '\0'; 414138032Speter } 414238032Speter 414338032Speter if (map->map_app != NULL) 414464562Sgshapiro map->map_app = newstr(ldapmap_dequote(map->map_app)); 414538032Speter if (map->map_tapp != NULL) 414664562Sgshapiro map->map_tapp = newstr(ldapmap_dequote(map->map_tapp)); 414738032Speter 414838032Speter /* 414942575Speter ** We need to swallow up all the stuff into a struct 415042575Speter ** and dump it into map->map_dbptr1 415138032Speter */ 415238032Speter 415364562Sgshapiro if (lmap->ldap_host != NULL && 415464562Sgshapiro (LDAPDefaults == NULL || 415564562Sgshapiro LDAPDefaults == lmap || 415664562Sgshapiro LDAPDefaults->ldap_host != lmap->ldap_host)) 415764562Sgshapiro lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host)); 415864562Sgshapiro map->map_domain = lmap->ldap_host; 415964562Sgshapiro 416064562Sgshapiro if (lmap->ldap_binddn != NULL && 416164562Sgshapiro (LDAPDefaults == NULL || 416264562Sgshapiro LDAPDefaults == lmap || 416364562Sgshapiro LDAPDefaults->ldap_binddn != lmap->ldap_binddn)) 416464562Sgshapiro lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn)); 416564562Sgshapiro 416664562Sgshapiro if (lmap->ldap_secret != NULL && 416764562Sgshapiro (LDAPDefaults == NULL || 416864562Sgshapiro LDAPDefaults == lmap || 416964562Sgshapiro LDAPDefaults->ldap_secret != lmap->ldap_secret)) 417038032Speter { 417164562Sgshapiro FILE *sfd; 417264562Sgshapiro long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES; 417338032Speter 417464562Sgshapiro if (DontLockReadFiles) 417564562Sgshapiro sff |= SFF_NOLOCK; 417638032Speter 417764562Sgshapiro /* need to use method to map secret to passwd string */ 417864562Sgshapiro switch (lmap->ldap_method) 417964562Sgshapiro { 418064562Sgshapiro case LDAP_AUTH_NONE: 418164562Sgshapiro /* Do nothing */ 418264562Sgshapiro break; 418338032Speter 418464562Sgshapiro case LDAP_AUTH_SIMPLE: 418538032Speter 418664562Sgshapiro /* 418764562Sgshapiro ** Secret is the name of a file with 418864562Sgshapiro ** the first line as the password. 418964562Sgshapiro */ 419064562Sgshapiro 419164562Sgshapiro /* Already read in the secret? */ 419264562Sgshapiro if (secretread) 419364562Sgshapiro break; 419464562Sgshapiro 419564562Sgshapiro sfd = safefopen(ldapmap_dequote(lmap->ldap_secret), 419664562Sgshapiro O_RDONLY, 0, sff); 419764562Sgshapiro if (sfd == NULL) 419864562Sgshapiro { 419964562Sgshapiro syserr("LDAP map: cannot open secret %s", 420064562Sgshapiro ldapmap_dequote(lmap->ldap_secret)); 420164562Sgshapiro return FALSE; 420264562Sgshapiro } 420364562Sgshapiro lmap->ldap_secret = sfgets(m_tmp, LDAPMAP_MAX_PASSWD, 420466494Sgshapiro sfd, TimeOuts.to_fileopen, 420566494Sgshapiro "ldapmap_parseargs"); 420664562Sgshapiro (void) fclose(sfd); 420764562Sgshapiro if (lmap->ldap_secret != NULL && 420864562Sgshapiro strlen(m_tmp) > 0) 420964562Sgshapiro { 421064562Sgshapiro /* chomp newline */ 421164562Sgshapiro if (m_tmp[strlen(m_tmp) - 1] == '\n') 421264562Sgshapiro m_tmp[strlen(m_tmp) - 1] = '\0'; 421364562Sgshapiro 421464562Sgshapiro lmap->ldap_secret = m_tmp; 421564562Sgshapiro } 421664562Sgshapiro break; 421764562Sgshapiro 421864562Sgshapiro# ifdef LDAP_AUTH_KRBV4 421964562Sgshapiro case LDAP_AUTH_KRBV4: 422064562Sgshapiro 422164562Sgshapiro /* 422264562Sgshapiro ** Secret is where the ticket file is 422364562Sgshapiro ** stashed 422464562Sgshapiro */ 422564562Sgshapiro 422664562Sgshapiro snprintf(m_tmp, MAXPATHLEN + LDAPMAP_MAX_PASSWD, 422764562Sgshapiro "KRBTKFILE=%s", 422864562Sgshapiro ldapmap_dequote(lmap->ldap_secret)); 422964562Sgshapiro lmap->ldap_secret = m_tmp; 423064562Sgshapiro break; 423164562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */ 423264562Sgshapiro 423364562Sgshapiro default: /* Should NEVER get here */ 423464562Sgshapiro syserr("LDAP map: Illegal value in lmap method"); 423564562Sgshapiro return FALSE; 423664562Sgshapiro break; 423764562Sgshapiro } 423838032Speter } 423938032Speter 424064562Sgshapiro if (lmap->ldap_secret != NULL && 424164562Sgshapiro (LDAPDefaults == NULL || 424264562Sgshapiro LDAPDefaults == lmap || 424364562Sgshapiro LDAPDefaults->ldap_secret != lmap->ldap_secret)) 424464562Sgshapiro lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret)); 424538032Speter 424664562Sgshapiro if (lmap->ldap_base != NULL && 424764562Sgshapiro (LDAPDefaults == NULL || 424864562Sgshapiro LDAPDefaults == lmap || 424964562Sgshapiro LDAPDefaults->ldap_base != lmap->ldap_base)) 425064562Sgshapiro lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base)); 425164562Sgshapiro 425264562Sgshapiro /* 425364562Sgshapiro ** Save the server from extra work. If request is for a single 425464562Sgshapiro ** match, tell the server to only return enough records to 425564562Sgshapiro ** determine if there is a single match or not. This can not 425664562Sgshapiro ** be one since the server would only return one and we wouldn't 425764562Sgshapiro ** know if there were others available. 425864562Sgshapiro */ 425964562Sgshapiro 426064562Sgshapiro if (bitset(MF_SINGLEMATCH, map->map_mflags)) 426164562Sgshapiro lmap->ldap_sizelimit = 2; 426264562Sgshapiro 426364562Sgshapiro /* If setting defaults, don't process ldap_filter and ldap_attr */ 426464562Sgshapiro if (lmap == LDAPDefaults) 426564562Sgshapiro return TRUE; 426664562Sgshapiro 426764562Sgshapiro if (lmap->ldap_filter != NULL) 426864562Sgshapiro lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter)); 426938032Speter else 427038032Speter { 427138032Speter if (!bitset(MCF_OPTFILE, map->map_class->map_cflags)) 427238032Speter { 427338032Speter syserr("No filter given in map %s", map->map_mname); 427438032Speter return FALSE; 427538032Speter } 427638032Speter } 427764562Sgshapiro 427864562Sgshapiro if (lmap->ldap_attr[0] != NULL) 427938032Speter { 428064562Sgshapiro i = 0; 428164562Sgshapiro p = ldapmap_dequote(lmap->ldap_attr[0]); 428264562Sgshapiro lmap->ldap_attr[0] = NULL; 428364562Sgshapiro 428464562Sgshapiro while (p != NULL) 428538032Speter { 428664562Sgshapiro char *v; 428764562Sgshapiro 428864562Sgshapiro while (isascii(*p) && isspace(*p)) 428964562Sgshapiro p++; 429064562Sgshapiro if (*p == '\0') 429164562Sgshapiro break; 429264562Sgshapiro v = p; 429364562Sgshapiro p = strchr(v, ','); 429464562Sgshapiro if (p != NULL) 429564562Sgshapiro *p++ = '\0'; 429664562Sgshapiro 429771345Sgshapiro if (i >= LDAPMAP_MAX_ATTR) 429864562Sgshapiro { 429964562Sgshapiro syserr("Too many return attributes in %s (max %d)", 430064562Sgshapiro map->map_mname, LDAPMAP_MAX_ATTR); 430164562Sgshapiro return FALSE; 430264562Sgshapiro } 430364562Sgshapiro if (*v != '\0') 430464562Sgshapiro lmap->ldap_attr[i++] = newstr(v); 430538032Speter } 430664562Sgshapiro lmap->ldap_attr[i] = NULL; 430738032Speter } 430838032Speter 430938032Speter map->map_db1 = (ARBPTR_T) lmap; 431038032Speter return TRUE; 431138032Speter} 431238032Speter 431364562Sgshapiro/* 431464562Sgshapiro** LDAPMAP_CLEAR -- set default values for LDAPMAP_STRUCT 431564562Sgshapiro** 431664562Sgshapiro** Parameters: 431764562Sgshapiro** lmap -- pointer to LDAPMAP_STRUCT to clear 431864562Sgshapiro** 431964562Sgshapiro** Returns: 432064562Sgshapiro** None. 432164562Sgshapiro** 432264562Sgshapiro*/ 432364562Sgshapiro 432464562Sgshapirostatic void 432564562Sgshapiroldapmap_clear(lmap) 432664562Sgshapiro LDAPMAP_STRUCT *lmap; 432764562Sgshapiro{ 432864562Sgshapiro lmap->ldap_host = NULL; 432964562Sgshapiro lmap->ldap_port = LDAP_PORT; 433064562Sgshapiro lmap->ldap_deref = LDAP_DEREF_NEVER; 433164562Sgshapiro lmap->ldap_timelimit = LDAP_NO_LIMIT; 433264562Sgshapiro lmap->ldap_sizelimit = LDAP_NO_LIMIT; 433364562Sgshapiro# ifdef LDAP_REFERRALS 433464562Sgshapiro lmap->ldap_options = LDAP_OPT_REFERRALS; 433564562Sgshapiro# else /* LDAP_REFERRALS */ 433664562Sgshapiro lmap->ldap_options = 0; 433764562Sgshapiro# endif /* LDAP_REFERRALS */ 433864562Sgshapiro lmap->ldap_binddn = NULL; 433964562Sgshapiro lmap->ldap_secret = NULL; 434064562Sgshapiro lmap->ldap_method = LDAP_AUTH_SIMPLE; 434164562Sgshapiro lmap->ldap_base = NULL; 434264562Sgshapiro lmap->ldap_scope = LDAP_SCOPE_SUBTREE; 434364562Sgshapiro lmap->ldap_attrsonly = LDAPMAP_FALSE; 434464562Sgshapiro lmap->ldap_timeout.tv_sec = 0; 434564562Sgshapiro lmap->ldap_timeout.tv_usec = 0; 434664562Sgshapiro lmap->ldap_ld = NULL; 434764562Sgshapiro lmap->ldap_filter = NULL; 434864562Sgshapiro lmap->ldap_attr[0] = NULL; 434964562Sgshapiro lmap->ldap_res = NULL; 435077349Sgshapiro lmap->ldap_next = NULL; 435164562Sgshapiro} 435238032Speter/* 435364562Sgshapiro** LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf 435464562Sgshapiro** 435564562Sgshapiro** Parameters: 435664562Sgshapiro** spec -- map argument string from LDAPDefaults option 435764562Sgshapiro** 435864562Sgshapiro** Returns: 435964562Sgshapiro** None. 436064562Sgshapiro** 436164562Sgshapiro*/ 436264562Sgshapiro 436364562Sgshapirovoid 436464562Sgshapiroldapmap_set_defaults(spec) 436564562Sgshapiro char *spec; 436664562Sgshapiro{ 436773188Sgshapiro STAB *class; 436864562Sgshapiro MAP map; 436964562Sgshapiro 437064562Sgshapiro /* Allocate and set the default values */ 437164562Sgshapiro if (LDAPDefaults == NULL) 437264562Sgshapiro LDAPDefaults = (LDAPMAP_STRUCT *) xalloc(sizeof *LDAPDefaults); 437364562Sgshapiro ldapmap_clear(LDAPDefaults); 437464562Sgshapiro 437564562Sgshapiro memset(&map, '\0', sizeof map); 437673188Sgshapiro 437773188Sgshapiro /* look up the class */ 437873188Sgshapiro class = stab("ldap", ST_MAPCLASS, ST_FIND); 437973188Sgshapiro if (class == NULL) 438073188Sgshapiro { 438173188Sgshapiro syserr("readcf: LDAPDefaultSpec: class ldap not available"); 438273188Sgshapiro return; 438373188Sgshapiro } 438473188Sgshapiro map.map_class = &class->s_mapclass; 438564562Sgshapiro map.map_db1 = (ARBPTR_T) LDAPDefaults; 438673188Sgshapiro map.map_mname = "O LDAPDefaultSpec"; 438764562Sgshapiro 438864562Sgshapiro (void) ldapmap_parseargs(&map, spec); 438964562Sgshapiro 439064562Sgshapiro /* These should never be set in LDAPDefaults */ 439164562Sgshapiro if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) || 439264562Sgshapiro map.map_spacesub != SpaceSub || 439364562Sgshapiro map.map_app != NULL || 439464562Sgshapiro map.map_tapp != NULL) 439564562Sgshapiro { 439664562Sgshapiro syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags"); 439764562Sgshapiro if (map.map_app != NULL) 439864562Sgshapiro { 439977349Sgshapiro sm_free(map.map_app); 440064562Sgshapiro map.map_app = NULL; 440164562Sgshapiro } 440264562Sgshapiro if (map.map_tapp != NULL) 440364562Sgshapiro { 440477349Sgshapiro sm_free(map.map_tapp); 440564562Sgshapiro map.map_tapp = NULL; 440664562Sgshapiro } 440764562Sgshapiro } 440864562Sgshapiro 440964562Sgshapiro if (LDAPDefaults->ldap_filter != NULL) 441064562Sgshapiro { 441164562Sgshapiro syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter"); 441264562Sgshapiro /* don't free, it isn't malloc'ed in parseargs */ 441364562Sgshapiro LDAPDefaults->ldap_filter = NULL; 441464562Sgshapiro } 441564562Sgshapiro 441664562Sgshapiro if (LDAPDefaults->ldap_attr[0] != NULL) 441764562Sgshapiro { 441864562Sgshapiro syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes"); 441964562Sgshapiro /* don't free, they aren't malloc'ed in parseargs */ 442064562Sgshapiro LDAPDefaults->ldap_attr[0] = NULL; 442164562Sgshapiro } 442264562Sgshapiro} 442364562Sgshapiro#endif /* LDAPMAP */ 442464562Sgshapiro/* 442564562Sgshapiro** PH map 442664562Sgshapiro*/ 442764562Sgshapiro 442864562Sgshapiro#ifdef PH_MAP 442964562Sgshapiro 443064562Sgshapiro/* 443164562Sgshapiro** Support for the CCSO Nameserver (ph/qi). 443264562Sgshapiro** This code is intended to replace the so-called "ph mailer". 443364562Sgshapiro** Contributed by Mark D. Roth <roth@uiuc.edu>. Contact him for support. 443464562Sgshapiro*/ 443564562Sgshapiro 443664562Sgshapiro# include <qiapi.h> 443764562Sgshapiro# include <qicode.h> 443864562Sgshapiro 443964562Sgshapiro/* 444064562Sgshapiro** PH_MAP_PARSEARGS -- parse ph map definition args. 444164562Sgshapiro*/ 444264562Sgshapiro 444364562Sgshapirobool 444464562Sgshapiroph_map_parseargs(map, args) 444564562Sgshapiro MAP *map; 444664562Sgshapiro char *args; 444764562Sgshapiro{ 444864562Sgshapiro int i; 444964562Sgshapiro register int done; 445064562Sgshapiro PH_MAP_STRUCT *pmap = NULL; 445164562Sgshapiro register char *p = args; 445264562Sgshapiro 445364562Sgshapiro pmap = (PH_MAP_STRUCT *) xalloc(sizeof *pmap); 445464562Sgshapiro 445564562Sgshapiro /* defaults */ 445664562Sgshapiro pmap->ph_servers = NULL; 445764562Sgshapiro pmap->ph_field_list = NULL; 445864562Sgshapiro pmap->ph_to_server = NULL; 445964562Sgshapiro pmap->ph_from_server = NULL; 446064562Sgshapiro pmap->ph_sockfd = -1; 446164562Sgshapiro pmap->ph_timeout = 0; 446264562Sgshapiro 446364562Sgshapiro map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL; 446464562Sgshapiro for (;;) 446564562Sgshapiro { 446664562Sgshapiro while (isascii(*p) && isspace(*p)) 446764562Sgshapiro p++; 446864562Sgshapiro if (*p != '-') 446964562Sgshapiro break; 447064562Sgshapiro switch (*++p) 447164562Sgshapiro { 447264562Sgshapiro case 'N': 447364562Sgshapiro map->map_mflags |= MF_INCLNULL; 447464562Sgshapiro map->map_mflags &= ~MF_TRY0NULL; 447564562Sgshapiro break; 447664562Sgshapiro 447764562Sgshapiro case 'O': 447864562Sgshapiro map->map_mflags &= ~MF_TRY1NULL; 447964562Sgshapiro break; 448064562Sgshapiro 448164562Sgshapiro case 'o': 448264562Sgshapiro map->map_mflags |= MF_OPTIONAL; 448364562Sgshapiro break; 448464562Sgshapiro 448564562Sgshapiro case 'f': 448664562Sgshapiro map->map_mflags |= MF_NOFOLDCASE; 448764562Sgshapiro break; 448864562Sgshapiro 448964562Sgshapiro case 'm': 449064562Sgshapiro map->map_mflags |= MF_MATCHONLY; 449164562Sgshapiro break; 449264562Sgshapiro 449364562Sgshapiro case 'A': 449464562Sgshapiro map->map_mflags |= MF_APPEND; 449564562Sgshapiro break; 449664562Sgshapiro 449764562Sgshapiro case 'q': 449864562Sgshapiro map->map_mflags |= MF_KEEPQUOTES; 449964562Sgshapiro break; 450064562Sgshapiro 450164562Sgshapiro case 't': 450264562Sgshapiro map->map_mflags |= MF_NODEFER; 450364562Sgshapiro break; 450464562Sgshapiro 450564562Sgshapiro case 'a': 450664562Sgshapiro map->map_app = ++p; 450764562Sgshapiro break; 450864562Sgshapiro 450964562Sgshapiro case 'T': 451064562Sgshapiro map->map_tapp = ++p; 451164562Sgshapiro break; 451264562Sgshapiro 451364562Sgshapiro#if _FFR_PHMAP_TIMEOUT 451464562Sgshapiro case 'l': 451564562Sgshapiro while (isascii(*++p) && isspace(*p)) 451664562Sgshapiro continue; 451764562Sgshapiro pmap->ph_timeout = atoi(p); 451864562Sgshapiro break; 451964562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 452064562Sgshapiro 452164562Sgshapiro case 'S': 452264562Sgshapiro map->map_spacesub = *++p; 452364562Sgshapiro break; 452464562Sgshapiro 452564562Sgshapiro case 'D': 452664562Sgshapiro map->map_mflags |= MF_DEFER; 452764562Sgshapiro break; 452864562Sgshapiro 452964562Sgshapiro case 'h': /* PH server list */ 453064562Sgshapiro while (isascii(*++p) && isspace(*p)) 453164562Sgshapiro continue; 453264562Sgshapiro pmap->ph_servers = p; 453364562Sgshapiro break; 453464562Sgshapiro 453564562Sgshapiro case 'v': /* fields to search for */ 453664562Sgshapiro while (isascii(*++p) && isspace(*p)) 453764562Sgshapiro continue; 453864562Sgshapiro pmap->ph_field_list = p; 453964562Sgshapiro break; 454064562Sgshapiro 454164562Sgshapiro default: 454264562Sgshapiro syserr("ph_map_parseargs: unknown option -%c\n", *p); 454364562Sgshapiro } 454464562Sgshapiro 454564562Sgshapiro /* try to account for quoted strings */ 454664562Sgshapiro done = isascii(*p) && isspace(*p); 454764562Sgshapiro while (*p != '\0' && !done) 454864562Sgshapiro { 454964562Sgshapiro if (*p == '"') 455064562Sgshapiro { 455164562Sgshapiro while (*++p != '"' && *p != '\0') 455264562Sgshapiro continue; 455364562Sgshapiro if (*p != '\0') 455464562Sgshapiro p++; 455564562Sgshapiro } 455664562Sgshapiro else 455764562Sgshapiro p++; 455864562Sgshapiro done = isascii(*p) && isspace(*p); 455964562Sgshapiro } 456064562Sgshapiro 456164562Sgshapiro if (*p != '\0') 456264562Sgshapiro *p++ = '\0'; 456364562Sgshapiro } 456464562Sgshapiro 456564562Sgshapiro if (map->map_app != NULL) 456664562Sgshapiro map->map_app = newstr(ph_map_dequote(map->map_app)); 456764562Sgshapiro if (map->map_tapp != NULL) 456864562Sgshapiro map->map_tapp = newstr(ph_map_dequote(map->map_tapp)); 456964562Sgshapiro 457064562Sgshapiro if (pmap->ph_field_list != NULL) 457164562Sgshapiro pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list)); 457264562Sgshapiro else 457364562Sgshapiro pmap->ph_field_list = DEFAULT_PH_MAP_FIELDS; 457464562Sgshapiro 457564562Sgshapiro if (pmap->ph_servers != NULL) 457664562Sgshapiro pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers)); 457764562Sgshapiro else 457864562Sgshapiro { 457964562Sgshapiro syserr("ph_map_parseargs: -h flag is required"); 458064562Sgshapiro return FALSE; 458164562Sgshapiro } 458264562Sgshapiro 458364562Sgshapiro map->map_db1 = (ARBPTR_T) pmap; 458464562Sgshapiro return TRUE; 458564562Sgshapiro} 458664562Sgshapiro 458764562Sgshapiro#if _FFR_PHMAP_TIMEOUT 458864562Sgshapiro/* 458964562Sgshapiro** PH_MAP_CLOSE -- close the connection to the ph server 459064562Sgshapiro*/ 459164562Sgshapiro 459264562Sgshapirostatic void 459364562Sgshapiroph_map_safeclose(map) 459464562Sgshapiro MAP *map; 459564562Sgshapiro{ 459664562Sgshapiro int save_errno = errno; 459764562Sgshapiro PH_MAP_STRUCT *pmap; 459864562Sgshapiro 459964562Sgshapiro pmap = (PH_MAP_STRUCT *)map->map_db1; 460064562Sgshapiro 460164562Sgshapiro if (pmap->ph_sockfd != -1) 460264562Sgshapiro { 460364562Sgshapiro (void) close(pmap->ph_sockfd); 460464562Sgshapiro pmap->ph_sockfd = -1; 460564562Sgshapiro } 460664562Sgshapiro if (pmap->ph_from_server != NULL) 460764562Sgshapiro { 460864562Sgshapiro (void) fclose(pmap->ph_from_server); 460964562Sgshapiro pmap->ph_from_server = NULL; 461064562Sgshapiro } 461164562Sgshapiro if (pmap->ph_to_server != NULL) 461264562Sgshapiro { 461364562Sgshapiro (void) fclose(pmap->ph_to_server); 461464562Sgshapiro pmap->ph_to_server = NULL; 461564562Sgshapiro } 461664562Sgshapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 461764562Sgshapiro errno = save_errno; 461864562Sgshapiro} 461964562Sgshapiro 462064562Sgshapirovoid 462164562Sgshapiroph_map_close(map) 462264562Sgshapiro MAP *map; 462364562Sgshapiro{ 462464562Sgshapiro PH_MAP_STRUCT *pmap; 462564562Sgshapiro 462664562Sgshapiro pmap = (PH_MAP_STRUCT *)map->map_db1; 462764562Sgshapiro (void) fprintf(pmap->ph_to_server, "quit\n"); 462864562Sgshapiro (void) fflush(pmap->ph_to_server); 462964562Sgshapiro ph_map_safeclose(map); 463064562Sgshapiro} 463164562Sgshapiro 463264562Sgshapirostatic jmp_buf PHTimeout; 463364562Sgshapiro 463464562Sgshapiro/* ARGSUSED */ 463564562Sgshapirostatic void 463677349Sgshapiroph_timeout(sig) 463777349Sgshapiro int sig; 463864562Sgshapiro{ 463977349Sgshapiro /* 464077349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 464177349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 464277349Sgshapiro ** DOING. 464377349Sgshapiro */ 464477349Sgshapiro 464577349Sgshapiro errno = ETIMEDOUT; 464664562Sgshapiro longjmp(PHTimeout, 1); 464764562Sgshapiro} 464864562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */ 464964562Sgshapiro/* 465064562Sgshapiro** PH_MAP_CLOSE -- close the connection to the ph server 465164562Sgshapiro*/ 465264562Sgshapiro 465364562Sgshapirovoid 465464562Sgshapiroph_map_close(map) 465564562Sgshapiro MAP *map; 465664562Sgshapiro{ 465764562Sgshapiro PH_MAP_STRUCT *pmap; 465864562Sgshapiro 465964562Sgshapiro pmap = (PH_MAP_STRUCT *)map->map_db1; 466064562Sgshapiro CloseQi(pmap->ph_to_server, pmap->ph_from_server); 466164562Sgshapiro pmap->ph_to_server = NULL; 466264562Sgshapiro pmap->ph_from_server = NULL; 466364562Sgshapiro} 466464562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 466564562Sgshapiro 466664562Sgshapiro/* 466764562Sgshapiro** PH_MAP_OPEN -- sub for opening PH map 466864562Sgshapiro*/ 466964562Sgshapirobool 467064562Sgshapiroph_map_open(map, mode) 467164562Sgshapiro MAP *map; 467264562Sgshapiro int mode; 467364562Sgshapiro{ 467464562Sgshapiro#if !_FFR_PHMAP_TIMEOUT 467564562Sgshapiro int save_errno = 0; 467664562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */ 467764562Sgshapiro int j; 467864562Sgshapiro char *hostlist, *tmp; 467964562Sgshapiro QIR *server_data = NULL; 468064562Sgshapiro PH_MAP_STRUCT *pmap; 468164562Sgshapiro#if _FFR_PHMAP_TIMEOUT 468264562Sgshapiro register EVENT *ev = NULL; 468364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 468464562Sgshapiro 468564562Sgshapiro if (tTd(38, 2)) 468664562Sgshapiro dprintf("ph_map_open(%s)\n", map->map_mname); 468764562Sgshapiro 468864562Sgshapiro mode &= O_ACCMODE; 468964562Sgshapiro if (mode != O_RDONLY) 469064562Sgshapiro { 469164562Sgshapiro /* issue a pseudo-error message */ 469264562Sgshapiro# ifdef ENOSYS 469364562Sgshapiro errno = ENOSYS; 469464562Sgshapiro# else /* ENOSYS */ 469564562Sgshapiro# ifdef EFTYPE 469664562Sgshapiro errno = EFTYPE; 469764562Sgshapiro# else /* EFTYPE */ 469864562Sgshapiro errno = ENXIO; 469964562Sgshapiro# endif /* EFTYPE */ 470064562Sgshapiro# endif /* ENOSYS */ 470164562Sgshapiro return FALSE; 470264562Sgshapiro } 470364562Sgshapiro 470466494Sgshapiro if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER && 470566494Sgshapiro bitset(MF_DEFER, map->map_mflags)) 470666494Sgshapiro { 470766494Sgshapiro if (tTd(9, 1)) 470866494Sgshapiro dprintf("ph_map_open(%s) => DEFERRED\n", 470971345Sgshapiro map->map_mname); 471066494Sgshapiro 471166494Sgshapiro /* 471266494Sgshapiro ** Unset MF_DEFER here so that map_lookup() returns 471366494Sgshapiro ** a temporary failure using the bogus map and 471466494Sgshapiro ** map->map_tapp instead of the default permanent error. 471566494Sgshapiro */ 471666494Sgshapiro 471766494Sgshapiro map->map_mflags &= ~MF_DEFER; 471866494Sgshapiro return FALSE; 471966494Sgshapiro } 472066494Sgshapiro 472164562Sgshapiro pmap = (PH_MAP_STRUCT *)map->map_db1; 472264562Sgshapiro 472364562Sgshapiro hostlist = newstr(pmap->ph_servers); 472464562Sgshapiro tmp = strtok(hostlist, " "); 472564562Sgshapiro do 472664562Sgshapiro { 472764562Sgshapiro#if _FFR_PHMAP_TIMEOUT 472864562Sgshapiro if (pmap->ph_timeout != 0) 472964562Sgshapiro { 473064562Sgshapiro if (setjmp(PHTimeout) != 0) 473164562Sgshapiro { 473264562Sgshapiro ev = NULL; 473364562Sgshapiro if (LogLevel > 1) 473464562Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, 473564562Sgshapiro "timeout connecting to PH server %.100s", 473664562Sgshapiro tmp); 473764562Sgshapiro# ifdef ETIMEDOUT 473864562Sgshapiro errno = ETIMEDOUT; 473964562Sgshapiro# else /* ETIMEDOUT */ 474066494Sgshapiro errno = EAGAIN; 474164562Sgshapiro# endif /* ETIMEDOUT */ 474264562Sgshapiro goto ph_map_open_abort; 474364562Sgshapiro } 474477349Sgshapiro ev = setevent(pmap->ph_timeout, ph_timeout, 0); 474564562Sgshapiro } 474664562Sgshapiro if (!OpenQiSock(tmp, &(pmap->ph_sockfd)) && 474764562Sgshapiro !Sock2FILEs(pmap->ph_sockfd, &(pmap->ph_to_server), 474864562Sgshapiro &(pmap->ph_from_server)) && 474964562Sgshapiro fprintf(pmap->ph_to_server, "id sendmail+phmap\n") >= 0 && 475064562Sgshapiro fflush(pmap->ph_to_server) == 0 && 475164562Sgshapiro (server_data = ReadQi(pmap->ph_from_server, &j)) != NULL && 475264562Sgshapiro server_data->code == 200) 475364562Sgshapiro { 475464562Sgshapiro if (ev != NULL) 475564562Sgshapiro clrevent(ev); 475664562Sgshapiro FreeQIR(server_data); 475764562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */ 475864562Sgshapiro if (OpenQi(tmp, &(pmap->ph_to_server), 475964562Sgshapiro &(pmap->ph_from_server)) >= 0) 476064562Sgshapiro { 476164562Sgshapiro if (fprintf(pmap->ph_to_server, 476264562Sgshapiro "id sendmail+phmap\n") < 0 || 476377349Sgshapiro fflush(pmap->ph_to_server) != 0 || 476464562Sgshapiro (server_data = ReadQi(pmap->ph_from_server, 476564562Sgshapiro &j)) == NULL || 476664562Sgshapiro server_data->code != 200) 476764562Sgshapiro { 476864562Sgshapiro save_errno = errno; 476964562Sgshapiro CloseQi(pmap->ph_to_server, 477064562Sgshapiro pmap->ph_from_server); 477164562Sgshapiro continue; 477264562Sgshapiro } 477364562Sgshapiro if (server_data != NULL) 477464562Sgshapiro FreeQIR(server_data); 477564562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 477677349Sgshapiro sm_free(hostlist); 477764562Sgshapiro return TRUE; 477864562Sgshapiro } 477964562Sgshapiro#if _FFR_PHMAP_TIMEOUT 478064562Sgshapiro ph_map_open_abort: 478164562Sgshapiro if (ev != NULL) 478264562Sgshapiro clrevent(ev); 478364562Sgshapiro ph_map_safeclose(map); 478464562Sgshapiro if (server_data != NULL) 478564562Sgshapiro { 478664562Sgshapiro FreeQIR(server_data); 478764562Sgshapiro server_data = NULL; 478864562Sgshapiro } 478964562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */ 479064562Sgshapiro save_errno = errno; 479164562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 479264562Sgshapiro } while (tmp = strtok(NULL, " ")); 479364562Sgshapiro 479464562Sgshapiro#if !_FFR_PHMAP_TIMEOUT 479564562Sgshapiro errno = save_errno; 479664562Sgshapiro#endif /* !_FFR_PHMAP_TIMEOUT */ 479766494Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 479864562Sgshapiro { 479966494Sgshapiro if (errno == 0) 480064562Sgshapiro errno = EAGAIN; 480166494Sgshapiro syserr("ph_map_open: %s: cannot connect to PH server", 480266494Sgshapiro map->map_mname); 480364562Sgshapiro } 480466494Sgshapiro else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1) 480564562Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, 480666494Sgshapiro "ph_map_open: %s: cannot connect to PH server", 480766494Sgshapiro map->map_mname); 480877349Sgshapiro sm_free(hostlist); 480964562Sgshapiro return FALSE; 481064562Sgshapiro} 481164562Sgshapiro 481264562Sgshapiro/* 481364562Sgshapiro** PH_MAP_LOOKUP -- look up key from ph server 481464562Sgshapiro*/ 481564562Sgshapiro 481664562Sgshapiro#if _FFR_PHMAP_TIMEOUT 481764562Sgshapiro# define MAX_PH_FIELDS 20 481864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 481964562Sgshapiro 482064562Sgshapirochar * 482164562Sgshapiroph_map_lookup(map, key, args, pstat) 482264562Sgshapiro MAP *map; 482364562Sgshapiro char *key; 482464562Sgshapiro char **args; 482564562Sgshapiro int *pstat; 482664562Sgshapiro{ 482764562Sgshapiro int j; 482864562Sgshapiro size_t sz; 482964562Sgshapiro char *tmp, *tmp2; 483064562Sgshapiro char *message = NULL, *field = NULL, *fmtkey; 483164562Sgshapiro QIR *server_data = NULL; 483264562Sgshapiro QIR *qirp; 483364562Sgshapiro char keybuf[MAXKEY + 1], fieldbuf[101]; 483464562Sgshapiro#if _FFR_PHMAP_TIMEOUT 483564562Sgshapiro QIR *hold_data[MAX_PH_FIELDS]; 483664562Sgshapiro int hold_data_idx = 0; 483764562Sgshapiro register EVENT *ev = NULL; 483864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 483964562Sgshapiro PH_MAP_STRUCT *pmap; 484064562Sgshapiro 484164562Sgshapiro pmap = (PH_MAP_STRUCT *)map->map_db1; 484264562Sgshapiro 484364562Sgshapiro *pstat = EX_OK; 484464562Sgshapiro 484564562Sgshapiro#if _FFR_PHMAP_TIMEOUT 484664562Sgshapiro if (pmap->ph_timeout != 0) 484764562Sgshapiro { 484864562Sgshapiro if (setjmp(PHTimeout) != 0) 484964562Sgshapiro { 485064562Sgshapiro ev = NULL; 485164562Sgshapiro if (LogLevel > 1) 485264562Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, 485364562Sgshapiro "timeout during PH lookup of %.100s", 485464562Sgshapiro key); 485564562Sgshapiro# ifdef ETIMEDOUT 485664562Sgshapiro errno = ETIMEDOUT; 485764562Sgshapiro# else /* ETIMEDOUT */ 485864562Sgshapiro errno = 0; 485964562Sgshapiro# endif /* ETIMEDOUT */ 486064562Sgshapiro *pstat = EX_TEMPFAIL; 486164562Sgshapiro goto ph_map_lookup_abort; 486264562Sgshapiro } 486377349Sgshapiro ev = setevent(pmap->ph_timeout, ph_timeout, 0); 486464562Sgshapiro } 486564562Sgshapiro 486664562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 486764562Sgshapiro /* check all relevant fields */ 486864562Sgshapiro tmp = pmap->ph_field_list; 486964562Sgshapiro do 487064562Sgshapiro { 487164562Sgshapiro#if _FFR_PHMAP_TIMEOUT 487264562Sgshapiro server_data = NULL; 487364562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 487464562Sgshapiro while (isascii(*tmp) && isspace(*tmp)) 487564562Sgshapiro tmp++; 487664562Sgshapiro if (*tmp == '\0') 487764562Sgshapiro break; 487864562Sgshapiro sz = strcspn(tmp, " ") + 1; 487964562Sgshapiro if (sz > sizeof fieldbuf) 488064562Sgshapiro sz = sizeof fieldbuf; 488164562Sgshapiro (void) strlcpy(fieldbuf, tmp, sz); 488264562Sgshapiro field = fieldbuf; 488364562Sgshapiro tmp += sz; 488464562Sgshapiro 488564562Sgshapiro (void) strlcpy(keybuf, key, sizeof keybuf); 488664562Sgshapiro fmtkey = keybuf; 488764562Sgshapiro if (strcmp(field, "alias") == 0) 488864562Sgshapiro { 488964562Sgshapiro /* 489064562Sgshapiro ** for alias lookups, replace any punctuation 489164562Sgshapiro ** characters with '-' 489264562Sgshapiro */ 489364562Sgshapiro 489464562Sgshapiro for (tmp2 = fmtkey; *tmp2 != '\0'; tmp2++) 489564562Sgshapiro { 489664562Sgshapiro if (isascii(*tmp2) && ispunct(*tmp2)) 489764562Sgshapiro *tmp2 = '-'; 489864562Sgshapiro } 489964562Sgshapiro tmp2 = field; 490064562Sgshapiro } 490164562Sgshapiro else if (strcmp(field,"spacedname") == 0) 490264562Sgshapiro { 490364562Sgshapiro /* 490464562Sgshapiro ** for "spaced" name lookups, replace any 490564562Sgshapiro ** punctuation characters with a space 490664562Sgshapiro */ 490764562Sgshapiro 490864562Sgshapiro for (tmp2 = fmtkey; *tmp2 != '\0'; tmp2++) 490964562Sgshapiro { 491064562Sgshapiro if (isascii(*tmp2) && ispunct(*tmp2) && 491164562Sgshapiro *tmp2 != '*') 491264562Sgshapiro *tmp2 = ' '; 491364562Sgshapiro } 491464562Sgshapiro tmp2 = &(field[6]); 491564562Sgshapiro } 491664562Sgshapiro else 491764562Sgshapiro tmp2 = field; 491864562Sgshapiro 491964562Sgshapiro if (LogLevel > 9) 492064562Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, 492164562Sgshapiro "ph_map_lookup: query %s=\"%s\" return email", 492264562Sgshapiro tmp2, fmtkey); 492364562Sgshapiro if (tTd(38, 20)) 492464562Sgshapiro dprintf("ph_map_lookup: query %s=\"%s\" return email\n", 492564562Sgshapiro tmp2, fmtkey); 492664562Sgshapiro 492764562Sgshapiro j = 0; 492864562Sgshapiro 492964562Sgshapiro if (fprintf(pmap->ph_to_server, "query %s=%s return email\n", 493064562Sgshapiro tmp2, fmtkey) < 0) 493164562Sgshapiro message = "qi query command failed"; 493277349Sgshapiro else if (fflush(pmap->ph_to_server) != 0) 493364562Sgshapiro message = "qi fflush failed"; 493464562Sgshapiro else if ((server_data = ReadQi(pmap->ph_from_server, 493564562Sgshapiro &j)) == NULL) 493664562Sgshapiro message = "ReadQi() returned NULL"; 493764562Sgshapiro 493864562Sgshapiro#if _FFR_PHMAP_TIMEOUT 493964562Sgshapiro if ((hold_data[hold_data_idx] = server_data) != NULL) 494064562Sgshapiro { 494164562Sgshapiro /* save pointer for later free() */ 494264562Sgshapiro hold_data_idx++; 494364562Sgshapiro } 494464562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 494564562Sgshapiro 494664562Sgshapiro if (server_data == NULL || 494764562Sgshapiro (server_data->code >= 400 && 494864562Sgshapiro server_data->code < 500)) 494964562Sgshapiro { 495064562Sgshapiro /* temporary failure */ 495164562Sgshapiro *pstat = EX_TEMPFAIL; 495264562Sgshapiro#if _FFR_PHMAP_TIMEOUT 495364562Sgshapiro break; 495464562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */ 495564562Sgshapiro if (server_data != NULL) 495664562Sgshapiro { 495764562Sgshapiro FreeQIR(server_data); 495864562Sgshapiro server_data = NULL; 495964562Sgshapiro } 496064562Sgshapiro return NULL; 496164562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 496264562Sgshapiro } 496364562Sgshapiro 496464562Sgshapiro /* 496564562Sgshapiro ** if we found a single match, break out. 496664562Sgshapiro ** otherwise, try the next field. 496764562Sgshapiro */ 496864562Sgshapiro 496964562Sgshapiro if (j == 1) 497064562Sgshapiro break; 497164562Sgshapiro 497264562Sgshapiro /* 497364562Sgshapiro ** check for a single response which is an error: 497464562Sgshapiro ** ReadQi() doesn't set j on error responses, 497564562Sgshapiro ** but we should stop here instead of moving on if 497664562Sgshapiro ** it happens (e.g., alias found but email field empty) 497764562Sgshapiro */ 497864562Sgshapiro 497964562Sgshapiro for (qirp = server_data; 498064562Sgshapiro qirp != NULL && qirp->code < 0; 498164562Sgshapiro qirp++) 498264562Sgshapiro { 498364562Sgshapiro if (tTd(38, 20)) 498464562Sgshapiro dprintf("ph_map_lookup: QIR: %d:%d:%d:%s\n", 498564562Sgshapiro qirp->code, qirp->subcode, qirp->field, 498664562Sgshapiro (qirp->message ? qirp->message 498764562Sgshapiro : "[NULL]")); 498864562Sgshapiro if (qirp->code <= -500) 498964562Sgshapiro { 499064562Sgshapiro j = 0; 499164562Sgshapiro goto ph_map_lookup_abort; 499264562Sgshapiro } 499364562Sgshapiro } 499464562Sgshapiro 499564562Sgshapiro#if _FFR_PHMAP_TIMEOUT 499664562Sgshapiro } while (*tmp != '\0' && hold_data_idx < MAX_PH_FIELDS); 499764562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */ 499864562Sgshapiro } while (*tmp != '\0'); 499964562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 500064562Sgshapiro 500164562Sgshapiro ph_map_lookup_abort: 500264562Sgshapiro#if _FFR_PHMAP_TIMEOUT 500364562Sgshapiro if (ev != NULL) 500464562Sgshapiro clrevent(ev); 500564562Sgshapiro 500664562Sgshapiro /* 500764562Sgshapiro ** Return EX_TEMPFAIL if the timer popped 500864562Sgshapiro ** or we got a temporary PH error 500964562Sgshapiro */ 501064562Sgshapiro 501164562Sgshapiro if (*pstat == EX_TEMPFAIL) 501264562Sgshapiro ph_map_safeclose(map); 501364562Sgshapiro 501464562Sgshapiro /* if we didn't find a single match, bail out */ 501564562Sgshapiro if (*pstat == EX_OK && j != 1) 501664562Sgshapiro *pstat = EX_UNAVAILABLE; 501764562Sgshapiro 501864562Sgshapiro if (*pstat == EX_OK) 501964562Sgshapiro { 502064562Sgshapiro /* 502164562Sgshapiro ** skip leading whitespace and chop at first address 502264562Sgshapiro */ 502364562Sgshapiro 502464562Sgshapiro for (tmp = server_data->message; 502564562Sgshapiro isascii(*tmp) && isspace(*tmp); 502664562Sgshapiro tmp++) 502764562Sgshapiro continue; 502864562Sgshapiro 502964562Sgshapiro for (tmp2 = tmp; *tmp2 != '\0'; tmp2++) 503064562Sgshapiro { 503164562Sgshapiro if (isascii(*tmp2) && isspace(*tmp2)) 503264562Sgshapiro { 503364562Sgshapiro *tmp2 = '\0'; 503464562Sgshapiro break; 503564562Sgshapiro } 503664562Sgshapiro } 503764562Sgshapiro 503864562Sgshapiro if (tTd(38,20)) 503964562Sgshapiro dprintf("ph_map_lookup: %s => %s\n", key, tmp); 504064562Sgshapiro 504164562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 504264562Sgshapiro message = map_rewrite(map, key, strlen(key), NULL); 504364562Sgshapiro else 504464562Sgshapiro message = map_rewrite(map, tmp, strlen(tmp), args); 504564562Sgshapiro } 504664562Sgshapiro 504764562Sgshapiro /* 504864562Sgshapiro ** Deferred free() of returned server_data values 504964562Sgshapiro ** the deferral is to avoid the risk of a free() being 505064562Sgshapiro ** interrupted by the event timer. By now the timeout event 505164562Sgshapiro ** has been cleared and none of the data is still in use. 505264562Sgshapiro */ 505364562Sgshapiro 505464562Sgshapiro while (--hold_data_idx >= 0) 505564562Sgshapiro { 505664562Sgshapiro if (hold_data[hold_data_idx] != NULL) 505764562Sgshapiro FreeQIR(hold_data[hold_data_idx]); 505864562Sgshapiro } 505964562Sgshapiro 506064562Sgshapiro if (*pstat == EX_OK) 506164562Sgshapiro return message; 506264562Sgshapiro 506364562Sgshapiro return NULL; 506464562Sgshapiro#else /* _FFR_PHMAP_TIMEOUT */ 506564562Sgshapiro /* if we didn't find a single match, bail out */ 506664562Sgshapiro if (j != 1) 506764562Sgshapiro { 506864562Sgshapiro *pstat = EX_UNAVAILABLE; 506964562Sgshapiro if (server_data != NULL) 507064562Sgshapiro { 507164562Sgshapiro FreeQIR(server_data); 507264562Sgshapiro server_data = NULL; 507364562Sgshapiro } 507464562Sgshapiro return NULL; 507564562Sgshapiro } 507664562Sgshapiro 507764562Sgshapiro /* 507864562Sgshapiro ** skip leading whitespace and chop at first address 507964562Sgshapiro */ 508064562Sgshapiro 508164562Sgshapiro for (tmp = server_data->message; 508264562Sgshapiro isascii(*tmp) && isspace(*tmp); 508364562Sgshapiro tmp++) 508464562Sgshapiro continue; 508564562Sgshapiro 508664562Sgshapiro for (tmp2 = tmp; *tmp2 != '\0'; tmp2++) 508764562Sgshapiro { 508864562Sgshapiro if (isascii(*tmp2) && isspace(*tmp2)) 508964562Sgshapiro { 509064562Sgshapiro *tmp2 = '\0'; 509164562Sgshapiro break; 509264562Sgshapiro } 509364562Sgshapiro } 509464562Sgshapiro 509564562Sgshapiro if (tTd(38,20)) 509664562Sgshapiro dprintf("ph_map_lookup: %s => %s\n", key, tmp); 509764562Sgshapiro 509864562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 509964562Sgshapiro message = map_rewrite(map, key, strlen(key), NULL); 510064562Sgshapiro else 510164562Sgshapiro message = map_rewrite(map, tmp, strlen(tmp), args); 510264562Sgshapiro if (server_data != NULL) 510364562Sgshapiro { 510464562Sgshapiro FreeQIR(server_data); 510564562Sgshapiro server_data = NULL; 510664562Sgshapiro } 510764562Sgshapiro return message; 510864562Sgshapiro#endif /* _FFR_PHMAP_TIMEOUT */ 510964562Sgshapiro} 511064562Sgshapiro#endif /* PH_MAP */ 511164562Sgshapiro/* 511242575Speter** syslog map 511338032Speter*/ 511438032Speter 511538032Speter#define map_prio map_lockfd /* overload field */ 511638032Speter 511738032Speter/* 511842575Speter** SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages. 511938032Speter*/ 512038032Speter 512138032Speterbool 512238032Spetersyslog_map_parseargs(map, args) 512338032Speter MAP *map; 512438032Speter char *args; 512538032Speter{ 512638032Speter char *p = args; 512738032Speter char *priority = NULL; 512838032Speter 512964562Sgshapiro /* there is no check whether there is really an argument */ 513064562Sgshapiro while (*p != '\0') 513138032Speter { 513238032Speter while (isascii(*p) && isspace(*p)) 513338032Speter p++; 513438032Speter if (*p != '-') 513538032Speter break; 513664562Sgshapiro ++p; 513764562Sgshapiro if (*p == 'D') 513864562Sgshapiro { 513964562Sgshapiro map->map_mflags |= MF_DEFER; 514064562Sgshapiro ++p; 514164562Sgshapiro } 514264562Sgshapiro else if (*p == 'S') 514364562Sgshapiro { 514464562Sgshapiro map->map_spacesub = *++p; 514564562Sgshapiro if (*p != '\0') 514664562Sgshapiro p++; 514764562Sgshapiro } 514864562Sgshapiro else if (*p == 'L') 514964562Sgshapiro { 515064562Sgshapiro while (*++p != '\0' && isascii(*p) && isspace(*p)) 515164562Sgshapiro continue; 515264562Sgshapiro if (*p == '\0') 515364562Sgshapiro break; 515464562Sgshapiro priority = p; 515564562Sgshapiro while (*p != '\0' && !(isascii(*p) && isspace(*p))) 515664562Sgshapiro p++; 515764562Sgshapiro if (*p != '\0') 515864562Sgshapiro *p++ = '\0'; 515964562Sgshapiro } 516064562Sgshapiro else 516164562Sgshapiro { 516264562Sgshapiro syserr("Illegal option %c map syslog", *p); 516364562Sgshapiro ++p; 516464562Sgshapiro } 516538032Speter } 516638032Speter 516738032Speter if (priority == NULL) 516838032Speter map->map_prio = LOG_INFO; 516938032Speter else 517038032Speter { 517138032Speter if (strncasecmp("LOG_", priority, 4) == 0) 517238032Speter priority += 4; 517338032Speter 517438032Speter#ifdef LOG_EMERG 517538032Speter if (strcasecmp("EMERG", priority) == 0) 517638032Speter map->map_prio = LOG_EMERG; 517738032Speter else 517864562Sgshapiro#endif /* LOG_EMERG */ 517938032Speter#ifdef LOG_ALERT 518038032Speter if (strcasecmp("ALERT", priority) == 0) 518138032Speter map->map_prio = LOG_ALERT; 518238032Speter else 518364562Sgshapiro#endif /* LOG_ALERT */ 518438032Speter#ifdef LOG_CRIT 518538032Speter if (strcasecmp("CRIT", priority) == 0) 518638032Speter map->map_prio = LOG_CRIT; 518738032Speter else 518864562Sgshapiro#endif /* LOG_CRIT */ 518938032Speter#ifdef LOG_ERR 519038032Speter if (strcasecmp("ERR", priority) == 0) 519138032Speter map->map_prio = LOG_ERR; 519238032Speter else 519364562Sgshapiro#endif /* LOG_ERR */ 519438032Speter#ifdef LOG_WARNING 519538032Speter if (strcasecmp("WARNING", priority) == 0) 519638032Speter map->map_prio = LOG_WARNING; 519738032Speter else 519864562Sgshapiro#endif /* LOG_WARNING */ 519938032Speter#ifdef LOG_NOTICE 520038032Speter if (strcasecmp("NOTICE", priority) == 0) 520138032Speter map->map_prio = LOG_NOTICE; 520238032Speter else 520364562Sgshapiro#endif /* LOG_NOTICE */ 520438032Speter#ifdef LOG_INFO 520538032Speter if (strcasecmp("INFO", priority) == 0) 520638032Speter map->map_prio = LOG_INFO; 520738032Speter else 520864562Sgshapiro#endif /* LOG_INFO */ 520938032Speter#ifdef LOG_DEBUG 521038032Speter if (strcasecmp("DEBUG", priority) == 0) 521138032Speter map->map_prio = LOG_DEBUG; 521238032Speter else 521364562Sgshapiro#endif /* LOG_DEBUG */ 521438032Speter { 521538032Speter syserr("syslog_map_parseargs: Unknown priority %s\n", 521638032Speter priority); 521738032Speter return FALSE; 521838032Speter } 521938032Speter } 522038032Speter return TRUE; 522138032Speter} 522238032Speter 522338032Speter/* 522442575Speter** SYSLOG_MAP_LOOKUP -- rewrite and syslog message. Always return empty string 522538032Speter*/ 522638032Speter 522738032Speterchar * 522838032Spetersyslog_map_lookup(map, string, args, statp) 522938032Speter MAP *map; 523038032Speter char *string; 523138032Speter char **args; 523238032Speter int *statp; 523338032Speter{ 523438032Speter char *ptr = map_rewrite(map, string, strlen(string), args); 523538032Speter 523638032Speter if (ptr != NULL) 523738032Speter { 523838032Speter if (tTd(38, 20)) 523964562Sgshapiro dprintf("syslog_map_lookup(%s (priority %d): %s\n", 524064562Sgshapiro map->map_mname, map->map_prio, ptr); 524138032Speter 524238032Speter sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr); 524338032Speter } 524438032Speter 524538032Speter *statp = EX_OK; 524638032Speter return ""; 524738032Speter} 524838032Speter 524938032Speter/* 525038032Speter** HESIOD Modules 525138032Speter*/ 525238032Speter 525338032Speter#ifdef HESIOD 525438032Speter 525538032Speterbool 525638032Speterhes_map_open(map, mode) 525738032Speter MAP *map; 525838032Speter int mode; 525938032Speter{ 526038032Speter if (tTd(38, 2)) 526164562Sgshapiro dprintf("hes_map_open(%s, %s, %d)\n", 526238032Speter map->map_mname, map->map_file, mode); 526338032Speter 526438032Speter if (mode != O_RDONLY) 526538032Speter { 526638032Speter /* issue a pseudo-error message */ 526764562Sgshapiro# ifdef ENOSYS 526838032Speter errno = ENOSYS; 526964562Sgshapiro# else /* ENOSYS */ 527064562Sgshapiro# ifdef EFTYPE 527138032Speter errno = EFTYPE; 527264562Sgshapiro# else /* EFTYPE */ 527338032Speter errno = ENXIO; 527464562Sgshapiro# endif /* EFTYPE */ 527564562Sgshapiro# endif /* ENOSYS */ 527638032Speter return FALSE; 527738032Speter } 527838032Speter 527964562Sgshapiro# ifdef HESIOD_INIT 528038032Speter if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0) 528138032Speter return TRUE; 528238032Speter 528338032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 528464562Sgshapiro syserr("421 4.0.0 cannot initialize Hesiod map (%s)", 528538032Speter errstring(errno)); 528638032Speter return FALSE; 528764562Sgshapiro# else /* HESIOD_INIT */ 528838032Speter if (hes_error() == HES_ER_UNINIT) 528938032Speter hes_init(); 529038032Speter switch (hes_error()) 529138032Speter { 529238032Speter case HES_ER_OK: 529338032Speter case HES_ER_NOTFOUND: 529438032Speter return TRUE; 529538032Speter } 529638032Speter 529738032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 529864562Sgshapiro syserr("421 4.0.0 cannot initialize Hesiod map (%d)", hes_error()); 529938032Speter 530038032Speter return FALSE; 530164562Sgshapiro# endif /* HESIOD_INIT */ 530238032Speter} 530338032Speter 530438032Speterchar * 530538032Speterhes_map_lookup(map, name, av, statp) 530638032Speter MAP *map; 530738032Speter char *name; 530838032Speter char **av; 530938032Speter int *statp; 531038032Speter{ 531138032Speter char **hp; 531238032Speter 531338032Speter if (tTd(38, 20)) 531464562Sgshapiro dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name); 531538032Speter 531638032Speter if (name[0] == '\\') 531738032Speter { 531838032Speter char *np; 531938032Speter int nl; 532077349Sgshapiro int save_errno; 532138032Speter char nbuf[MAXNAME]; 532238032Speter 532338032Speter nl = strlen(name); 532438032Speter if (nl < sizeof nbuf - 1) 532538032Speter np = nbuf; 532638032Speter else 532738032Speter np = xalloc(strlen(name) + 2); 532838032Speter np[0] = '\\'; 532964562Sgshapiro (void) strlcpy(&np[1], name, (sizeof nbuf) - 1); 533064562Sgshapiro# ifdef HESIOD_INIT 533138032Speter hp = hesiod_resolve(HesiodContext, np, map->map_file); 533264562Sgshapiro# else /* HESIOD_INIT */ 533338032Speter hp = hes_resolve(np, map->map_file); 533464562Sgshapiro# endif /* HESIOD_INIT */ 533577349Sgshapiro save_errno = errno; 533638032Speter if (np != nbuf) 533777349Sgshapiro sm_free(np); 533877349Sgshapiro errno = save_errno; 533938032Speter } 534038032Speter else 534138032Speter { 534264562Sgshapiro# ifdef HESIOD_INIT 534338032Speter hp = hesiod_resolve(HesiodContext, name, map->map_file); 534464562Sgshapiro# else /* HESIOD_INIT */ 534538032Speter hp = hes_resolve(name, map->map_file); 534664562Sgshapiro# endif /* HESIOD_INIT */ 534738032Speter } 534864562Sgshapiro# ifdef HESIOD_INIT 534977349Sgshapiro if (hp == NULL || *hp == NULL) 535038032Speter { 535138032Speter switch (errno) 535238032Speter { 535338032Speter case ENOENT: 535438032Speter *statp = EX_NOTFOUND; 535538032Speter break; 535638032Speter case ECONNREFUSED: 535738032Speter case EMSGSIZE: 535838032Speter *statp = EX_TEMPFAIL; 535938032Speter break; 536038032Speter case ENOMEM: 536138032Speter default: 536238032Speter *statp = EX_UNAVAILABLE; 536338032Speter break; 536438032Speter } 536577349Sgshapiro hesiod_free_list(HesiodContext, hp); 536638032Speter return NULL; 536738032Speter } 536864562Sgshapiro# else /* HESIOD_INIT */ 536938032Speter if (hp == NULL || hp[0] == NULL) 537038032Speter { 537138032Speter switch (hes_error()) 537238032Speter { 537338032Speter case HES_ER_OK: 537438032Speter *statp = EX_OK; 537538032Speter break; 537638032Speter 537738032Speter case HES_ER_NOTFOUND: 537838032Speter *statp = EX_NOTFOUND; 537938032Speter break; 538038032Speter 538138032Speter case HES_ER_CONFIG: 538238032Speter *statp = EX_UNAVAILABLE; 538338032Speter break; 538438032Speter 538538032Speter case HES_ER_NET: 538638032Speter *statp = EX_TEMPFAIL; 538738032Speter break; 538838032Speter } 538938032Speter return NULL; 539038032Speter } 539164562Sgshapiro# endif /* HESIOD_INIT */ 539238032Speter 539338032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 539438032Speter return map_rewrite(map, name, strlen(name), NULL); 539538032Speter else 539638032Speter return map_rewrite(map, hp[0], strlen(hp[0]), av); 539738032Speter} 539838032Speter 539964562Sgshapiro#endif /* HESIOD */ 540038032Speter/* 540138032Speter** NeXT NETINFO Modules 540238032Speter*/ 540338032Speter 540438032Speter#if NETINFO 540538032Speter 540638032Speter# define NETINFO_DEFAULT_DIR "/aliases" 540738032Speter# define NETINFO_DEFAULT_PROPERTY "members" 540838032Speter 540938032Speter/* 541038032Speter** NI_MAP_OPEN -- open NetInfo Aliases 541138032Speter*/ 541238032Speter 541338032Speterbool 541438032Speterni_map_open(map, mode) 541538032Speter MAP *map; 541638032Speter int mode; 541738032Speter{ 541838032Speter if (tTd(38, 2)) 541964562Sgshapiro dprintf("ni_map_open(%s, %s, %d)\n", 542038032Speter map->map_mname, map->map_file, mode); 542138032Speter mode &= O_ACCMODE; 542238032Speter 542338032Speter if (*map->map_file == '\0') 542438032Speter map->map_file = NETINFO_DEFAULT_DIR; 542538032Speter 542638032Speter if (map->map_valcolnm == NULL) 542738032Speter map->map_valcolnm = NETINFO_DEFAULT_PROPERTY; 542838032Speter 542938032Speter if (map->map_coldelim == '\0' && bitset(MF_ALIAS, map->map_mflags)) 543038032Speter map->map_coldelim = ','; 543138032Speter 543238032Speter return TRUE; 543338032Speter} 543438032Speter 543538032Speter 543638032Speter/* 543738032Speter** NI_MAP_LOOKUP -- look up a datum in NetInfo 543838032Speter*/ 543938032Speter 544038032Speterchar * 544138032Speterni_map_lookup(map, name, av, statp) 544238032Speter MAP *map; 544338032Speter char *name; 544438032Speter char **av; 544538032Speter int *statp; 544638032Speter{ 544738032Speter char *res; 544838032Speter char *propval; 544938032Speter 545038032Speter if (tTd(38, 20)) 545164562Sgshapiro dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name); 545238032Speter 545338032Speter propval = ni_propval(map->map_file, map->map_keycolnm, name, 545438032Speter map->map_valcolnm, map->map_coldelim); 545538032Speter 545638032Speter if (propval == NULL) 545738032Speter return NULL; 545838032Speter 545938032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 546038032Speter res = map_rewrite(map, name, strlen(name), NULL); 546138032Speter else 546238032Speter res = map_rewrite(map, propval, strlen(propval), av); 546377349Sgshapiro sm_free(propval); 546438032Speter return res; 546538032Speter} 546638032Speter 546738032Speter 546864562Sgshapirostatic bool 546938032Speterni_getcanonname(name, hbsize, statp) 547038032Speter char *name; 547138032Speter int hbsize; 547238032Speter int *statp; 547338032Speter{ 547438032Speter char *vptr; 547538032Speter char *ptr; 547638032Speter char nbuf[MAXNAME + 1]; 547738032Speter 547838032Speter if (tTd(38, 20)) 547964562Sgshapiro dprintf("ni_getcanonname(%s)\n", name); 548038032Speter 548164562Sgshapiro if (strlcpy(nbuf, name, sizeof nbuf) >= sizeof nbuf) 548238032Speter { 548338032Speter *statp = EX_UNAVAILABLE; 548438032Speter return FALSE; 548538032Speter } 548673188Sgshapiro (void) shorten_hostname(nbuf); 548738032Speter 548838032Speter /* we only accept single token search key */ 548938032Speter if (strchr(nbuf, '.')) 549038032Speter { 549138032Speter *statp = EX_NOHOST; 549238032Speter return FALSE; 549338032Speter } 549438032Speter 549538032Speter /* Do the search */ 549638032Speter vptr = ni_propval("/machines", NULL, nbuf, "name", '\n'); 549738032Speter 549838032Speter if (vptr == NULL) 549938032Speter { 550038032Speter *statp = EX_NOHOST; 550138032Speter return FALSE; 550238032Speter } 550338032Speter 550438032Speter /* Only want the first machine name */ 550538032Speter if ((ptr = strchr(vptr, '\n')) != NULL) 550638032Speter *ptr = '\0'; 550738032Speter 550838032Speter if (hbsize >= strlen(vptr)) 550938032Speter { 551064562Sgshapiro (void) strlcpy(name, vptr, hbsize); 551177349Sgshapiro sm_free(vptr); 551238032Speter *statp = EX_OK; 551338032Speter return TRUE; 551438032Speter } 551538032Speter *statp = EX_UNAVAILABLE; 551677349Sgshapiro sm_free(vptr); 551738032Speter return FALSE; 551838032Speter} 551938032Speter 552038032Speter 552138032Speter/* 552238032Speter** NI_PROPVAL -- NetInfo property value lookup routine 552338032Speter** 552438032Speter** Parameters: 552538032Speter** keydir -- the NetInfo directory name in which to search 552638032Speter** for the key. 552738032Speter** keyprop -- the name of the property in which to find the 552838032Speter** property we are interested. Defaults to "name". 552938032Speter** keyval -- the value for which we are really searching. 553038032Speter** valprop -- the property name for the value in which we 553138032Speter** are interested. 553238032Speter** sepchar -- if non-nil, this can be multiple-valued, and 553338032Speter** we should return a string separated by this 553438032Speter** character. 553538032Speter** 553638032Speter** Returns: 553738032Speter** NULL -- if: 553838032Speter** 1. the directory is not found 553938032Speter** 2. the property name is not found 554038032Speter** 3. the property contains multiple values 554164562Sgshapiro** 4. some error occurred 554238032Speter** else -- the value of the lookup. 554338032Speter** 554438032Speter** Example: 554538032Speter** To search for an alias value, use: 554638032Speter** ni_propval("/aliases", "name", aliasname, "members", ',') 554738032Speter** 554838032Speter** Notes: 554964562Sgshapiro** Caller should free the return value of ni_proval 555038032Speter*/ 555138032Speter 555238032Speter# include <netinfo/ni.h> 555338032Speter 555464562Sgshapiro# define LOCAL_NETINFO_DOMAIN "." 555564562Sgshapiro# define PARENT_NETINFO_DOMAIN ".." 555664562Sgshapiro# define MAX_NI_LEVELS 256 555738032Speter 555838032Speterchar * 555938032Speterni_propval(keydir, keyprop, keyval, valprop, sepchar) 556038032Speter char *keydir; 556138032Speter char *keyprop; 556238032Speter char *keyval; 556338032Speter char *valprop; 556438032Speter int sepchar; 556538032Speter{ 556638032Speter char *propval = NULL; 556738032Speter int i; 556864562Sgshapiro int j, alen, l; 556938032Speter void *ni = NULL; 557038032Speter void *lastni = NULL; 557138032Speter ni_status nis; 557238032Speter ni_id nid; 557338032Speter ni_namelist ninl; 557438032Speter register char *p; 557538032Speter char keybuf[1024]; 557638032Speter 557738032Speter /* 557838032Speter ** Create the full key from the two parts. 557938032Speter ** 558038032Speter ** Note that directory can end with, e.g., "name=" to specify 558138032Speter ** an alternate search property. 558238032Speter */ 558338032Speter 558438032Speter i = strlen(keydir) + strlen(keyval) + 2; 558538032Speter if (keyprop != NULL) 558638032Speter i += strlen(keyprop) + 1; 558764562Sgshapiro if (i >= sizeof keybuf) 558838032Speter return NULL; 558964562Sgshapiro (void) strlcpy(keybuf, keydir, sizeof keybuf); 559064562Sgshapiro (void) strlcat(keybuf, "/", sizeof keybuf); 559138032Speter if (keyprop != NULL) 559238032Speter { 559364562Sgshapiro (void) strlcat(keybuf, keyprop, sizeof keybuf); 559464562Sgshapiro (void) strlcat(keybuf, "=", sizeof keybuf); 559538032Speter } 559664562Sgshapiro (void) strlcat(keybuf, keyval, sizeof keybuf); 559738032Speter 559838032Speter if (tTd(38, 21)) 559964562Sgshapiro dprintf("ni_propval(%s, %s, %s, %s, %d) keybuf='%s'\n", 560038032Speter keydir, keyprop, keyval, valprop, sepchar, keybuf); 560138032Speter /* 560238032Speter ** If the passed directory and property name are found 560338032Speter ** in one of netinfo domains we need to search (starting 560438032Speter ** from the local domain moving all the way back to the 560538032Speter ** root domain) set propval to the property's value 560638032Speter ** and return it. 560738032Speter */ 560838032Speter 560938032Speter for (i = 0; i < MAX_NI_LEVELS && propval == NULL; i++) 561038032Speter { 561138032Speter if (i == 0) 561238032Speter { 561338032Speter nis = ni_open(NULL, LOCAL_NETINFO_DOMAIN, &ni); 561438032Speter if (tTd(38, 20)) 561564562Sgshapiro dprintf("ni_open(LOCAL) = %d\n", nis); 561638032Speter } 561738032Speter else 561838032Speter { 561938032Speter if (lastni != NULL) 562038032Speter ni_free(lastni); 562138032Speter lastni = ni; 562238032Speter nis = ni_open(lastni, PARENT_NETINFO_DOMAIN, &ni); 562338032Speter if (tTd(38, 20)) 562464562Sgshapiro dprintf("ni_open(PARENT) = %d\n", nis); 562538032Speter } 562638032Speter 562738032Speter /* 562838032Speter ** Don't bother if we didn't get a handle on a 562938032Speter ** proper domain. This is not necessarily an error. 563038032Speter ** We would get a positive ni_status if, for instance 563138032Speter ** we never found the directory or property and tried 563238032Speter ** to open the parent of the root domain! 563338032Speter */ 563438032Speter 563538032Speter if (nis != 0) 563638032Speter break; 563738032Speter 563838032Speter /* 563938032Speter ** Find the path to the server information. 564038032Speter */ 564138032Speter 564238032Speter if (ni_pathsearch(ni, &nid, keybuf) != 0) 564338032Speter continue; 564438032Speter 564538032Speter /* 564638032Speter ** Find associated value information. 564738032Speter */ 564838032Speter 564938032Speter if (ni_lookupprop(ni, &nid, valprop, &ninl) != 0) 565038032Speter continue; 565138032Speter 565238032Speter if (tTd(38, 20)) 565364562Sgshapiro dprintf("ni_lookupprop: len=%d\n", 565464562Sgshapiro ninl.ni_namelist_len); 565564562Sgshapiro 565638032Speter /* 565738032Speter ** See if we have an acceptable number of values. 565838032Speter */ 565938032Speter 566038032Speter if (ninl.ni_namelist_len <= 0) 566138032Speter continue; 566238032Speter 566338032Speter if (sepchar == '\0' && ninl.ni_namelist_len > 1) 566438032Speter { 566538032Speter ni_namelist_free(&ninl); 566638032Speter continue; 566738032Speter } 566838032Speter 566938032Speter /* 567038032Speter ** Calculate number of bytes needed and build result 567138032Speter */ 567238032Speter 567338032Speter alen = 1; 567438032Speter for (j = 0; j < ninl.ni_namelist_len; j++) 567538032Speter alen += strlen(ninl.ni_namelist_val[j]) + 1; 567638032Speter propval = p = xalloc(alen); 567738032Speter for (j = 0; j < ninl.ni_namelist_len; j++) 567838032Speter { 567964562Sgshapiro (void) strlcpy(p, ninl.ni_namelist_val[j], alen); 568064562Sgshapiro l = strlen(p); 568164562Sgshapiro p += l; 568238032Speter *p++ = sepchar; 568364562Sgshapiro alen -= l + 1; 568438032Speter } 568538032Speter *--p = '\0'; 568638032Speter 568738032Speter ni_namelist_free(&ninl); 568838032Speter } 568938032Speter 569038032Speter /* 569138032Speter ** Clean up. 569238032Speter */ 569338032Speter 569438032Speter if (ni != NULL) 569538032Speter ni_free(ni); 569638032Speter if (lastni != NULL && ni != lastni) 569738032Speter ni_free(lastni); 569838032Speter if (tTd(38, 20)) 569964562Sgshapiro dprintf("ni_propval returns: '%s'\n", propval); 570038032Speter 570138032Speter return propval; 570238032Speter} 570338032Speter 570442575Speter#endif /* NETINFO */ 570538032Speter/* 570638032Speter** TEXT (unindexed text file) Modules 570738032Speter** 570838032Speter** This code donated by Sun Microsystems. 570938032Speter*/ 571038032Speter 571138032Speter#define map_sff map_lockfd /* overload field */ 571238032Speter 571338032Speter 571438032Speter/* 571538032Speter** TEXT_MAP_OPEN -- open text table 571638032Speter*/ 571738032Speter 571838032Speterbool 571938032Spetertext_map_open(map, mode) 572038032Speter MAP *map; 572138032Speter int mode; 572238032Speter{ 572364562Sgshapiro long sff; 572438032Speter int i; 572538032Speter 572638032Speter if (tTd(38, 2)) 572764562Sgshapiro dprintf("text_map_open(%s, %s, %d)\n", 572838032Speter map->map_mname, map->map_file, mode); 572938032Speter 573038032Speter mode &= O_ACCMODE; 573138032Speter if (mode != O_RDONLY) 573238032Speter { 573338032Speter errno = EPERM; 573438032Speter return FALSE; 573538032Speter } 573638032Speter 573738032Speter if (*map->map_file == '\0') 573838032Speter { 573938032Speter syserr("text map \"%s\": file name required", 574038032Speter map->map_mname); 574138032Speter return FALSE; 574238032Speter } 574338032Speter 574438032Speter if (map->map_file[0] != '/') 574538032Speter { 574638032Speter syserr("text map \"%s\": file name must be fully qualified", 574738032Speter map->map_mname); 574838032Speter return FALSE; 574938032Speter } 575038032Speter 575138032Speter sff = SFF_ROOTOK|SFF_REGONLY; 575264562Sgshapiro if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 575338032Speter sff |= SFF_NOWLINK; 575464562Sgshapiro if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail)) 575538032Speter sff |= SFF_SAFEDIRPATH; 575638032Speter if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName, 575738032Speter sff, S_IRUSR, NULL)) != 0) 575838032Speter { 575964562Sgshapiro int save_errno = errno; 576064562Sgshapiro 576138032Speter /* cannot open this map */ 576238032Speter if (tTd(38, 2)) 576364562Sgshapiro dprintf("\tunsafe map file: %d\n", i); 576464562Sgshapiro errno = save_errno; 576538032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 576638032Speter syserr("text map \"%s\": unsafe map file %s", 576738032Speter map->map_mname, map->map_file); 576838032Speter return FALSE; 576938032Speter } 577038032Speter 577138032Speter if (map->map_keycolnm == NULL) 577238032Speter map->map_keycolno = 0; 577338032Speter else 577438032Speter { 577538032Speter if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm))) 577638032Speter { 577738032Speter syserr("text map \"%s\", file %s: -k should specify a number, not %s", 577838032Speter map->map_mname, map->map_file, 577938032Speter map->map_keycolnm); 578038032Speter return FALSE; 578138032Speter } 578238032Speter map->map_keycolno = atoi(map->map_keycolnm); 578338032Speter } 578438032Speter 578538032Speter if (map->map_valcolnm == NULL) 578638032Speter map->map_valcolno = 0; 578738032Speter else 578838032Speter { 578938032Speter if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm))) 579038032Speter { 579138032Speter syserr("text map \"%s\", file %s: -v should specify a number, not %s", 579238032Speter map->map_mname, map->map_file, 579338032Speter map->map_valcolnm); 579438032Speter return FALSE; 579538032Speter } 579638032Speter map->map_valcolno = atoi(map->map_valcolnm); 579738032Speter } 579838032Speter 579938032Speter if (tTd(38, 2)) 580038032Speter { 580164562Sgshapiro dprintf("text_map_open(%s, %s): delimiter = ", 580238032Speter map->map_mname, map->map_file); 580338032Speter if (map->map_coldelim == '\0') 580464562Sgshapiro dprintf("(white space)\n"); 580538032Speter else 580664562Sgshapiro dprintf("%c\n", map->map_coldelim); 580738032Speter } 580838032Speter 580938032Speter map->map_sff = sff; 581038032Speter return TRUE; 581138032Speter} 581238032Speter 581338032Speter 581438032Speter/* 581538032Speter** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table 581638032Speter*/ 581738032Speter 581838032Speterchar * 581938032Spetertext_map_lookup(map, name, av, statp) 582038032Speter MAP *map; 582138032Speter char *name; 582238032Speter char **av; 582338032Speter int *statp; 582438032Speter{ 582538032Speter char *vp; 582638032Speter auto int vsize; 582738032Speter int buflen; 582838032Speter FILE *f; 582938032Speter char delim; 583038032Speter int key_idx; 583138032Speter bool found_it; 583264562Sgshapiro long sff = map->map_sff; 583338032Speter char search_key[MAXNAME + 1]; 583438032Speter char linebuf[MAXLINE]; 583538032Speter char buf[MAXNAME + 1]; 583638032Speter 583738032Speter found_it = FALSE; 583838032Speter if (tTd(38, 20)) 583964562Sgshapiro dprintf("text_map_lookup(%s, %s)\n", map->map_mname, name); 584038032Speter 584138032Speter buflen = strlen(name); 584238032Speter if (buflen > sizeof search_key - 1) 584338032Speter buflen = sizeof search_key - 1; 584464562Sgshapiro memmove(search_key, name, buflen); 584538032Speter search_key[buflen] = '\0'; 584638032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 584738032Speter makelower(search_key); 584838032Speter 584938032Speter f = safefopen(map->map_file, O_RDONLY, FileMode, sff); 585038032Speter if (f == NULL) 585138032Speter { 585238032Speter map->map_mflags &= ~(MF_VALID|MF_OPEN); 585338032Speter *statp = EX_UNAVAILABLE; 585438032Speter return NULL; 585538032Speter } 585638032Speter key_idx = map->map_keycolno; 585738032Speter delim = map->map_coldelim; 585838032Speter while (fgets(linebuf, MAXLINE, f) != NULL) 585938032Speter { 586038032Speter char *p; 586138032Speter 586238032Speter /* skip comment line */ 586338032Speter if (linebuf[0] == '#') 586438032Speter continue; 586538032Speter p = strchr(linebuf, '\n'); 586638032Speter if (p != NULL) 586738032Speter *p = '\0'; 586838032Speter p = get_column(linebuf, key_idx, delim, buf, sizeof buf); 586938032Speter if (p != NULL && strcasecmp(search_key, p) == 0) 587038032Speter { 587138032Speter found_it = TRUE; 587238032Speter break; 587338032Speter } 587438032Speter } 587564562Sgshapiro (void) fclose(f); 587638032Speter if (!found_it) 587738032Speter { 587838032Speter *statp = EX_NOTFOUND; 587938032Speter return NULL; 588038032Speter } 588138032Speter vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof buf); 588242575Speter if (vp == NULL) 588342575Speter { 588442575Speter *statp = EX_NOTFOUND; 588542575Speter return NULL; 588642575Speter } 588738032Speter vsize = strlen(vp); 588838032Speter *statp = EX_OK; 588938032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 589038032Speter return map_rewrite(map, name, strlen(name), NULL); 589138032Speter else 589238032Speter return map_rewrite(map, vp, vsize, av); 589338032Speter} 589438032Speter 589538032Speter/* 589638032Speter** TEXT_GETCANONNAME -- look up canonical name in hosts file 589738032Speter*/ 589838032Speter 589964562Sgshapirostatic bool 590038032Spetertext_getcanonname(name, hbsize, statp) 590138032Speter char *name; 590238032Speter int hbsize; 590338032Speter int *statp; 590438032Speter{ 590538032Speter bool found; 590673188Sgshapiro char *dot; 590738032Speter FILE *f; 590838032Speter char linebuf[MAXLINE]; 590938032Speter char cbuf[MAXNAME + 1]; 591038032Speter char nbuf[MAXNAME + 1]; 591138032Speter 591238032Speter if (tTd(38, 20)) 591364562Sgshapiro dprintf("text_getcanonname(%s)\n", name); 591438032Speter 591538032Speter if (strlen(name) >= (SIZE_T) sizeof nbuf) 591638032Speter { 591738032Speter *statp = EX_UNAVAILABLE; 591838032Speter return FALSE; 591938032Speter } 592064562Sgshapiro (void) strlcpy(nbuf, name, sizeof nbuf); 592173188Sgshapiro dot = shorten_hostname(nbuf); 592238032Speter 592338032Speter f = fopen(HostsFile, "r"); 592438032Speter if (f == NULL) 592538032Speter { 592638032Speter *statp = EX_UNAVAILABLE; 592738032Speter return FALSE; 592838032Speter } 592938032Speter found = FALSE; 593038032Speter while (!found && fgets(linebuf, MAXLINE, f) != NULL) 593138032Speter { 593238032Speter char *p = strpbrk(linebuf, "#\n"); 593338032Speter 593438032Speter if (p != NULL) 593538032Speter *p = '\0'; 593638032Speter if (linebuf[0] != '\0') 593773188Sgshapiro found = extract_canonname(nbuf, dot, linebuf, 593873188Sgshapiro cbuf, sizeof cbuf); 593938032Speter } 594064562Sgshapiro (void) fclose(f); 594138032Speter if (!found) 594238032Speter { 594338032Speter *statp = EX_NOHOST; 594438032Speter return FALSE; 594538032Speter } 594638032Speter 594738032Speter if ((SIZE_T) hbsize >= strlen(cbuf)) 594838032Speter { 594964562Sgshapiro (void) strlcpy(name, cbuf, hbsize); 595038032Speter *statp = EX_OK; 595138032Speter return TRUE; 595238032Speter } 595338032Speter *statp = EX_UNAVAILABLE; 595438032Speter return FALSE; 595538032Speter} 595638032Speter/* 595738032Speter** STAB (Symbol Table) Modules 595838032Speter*/ 595938032Speter 596038032Speter 596138032Speter/* 596238032Speter** STAB_MAP_LOOKUP -- look up alias in symbol table 596338032Speter*/ 596438032Speter 596538032Speter/* ARGSUSED2 */ 596638032Speterchar * 596738032Speterstab_map_lookup(map, name, av, pstat) 596838032Speter register MAP *map; 596938032Speter char *name; 597038032Speter char **av; 597138032Speter int *pstat; 597238032Speter{ 597338032Speter register STAB *s; 597438032Speter 597538032Speter if (tTd(38, 20)) 597664562Sgshapiro dprintf("stab_lookup(%s, %s)\n", 597738032Speter map->map_mname, name); 597838032Speter 597938032Speter s = stab(name, ST_ALIAS, ST_FIND); 598038032Speter if (s != NULL) 598164562Sgshapiro return s->s_alias; 598264562Sgshapiro return NULL; 598338032Speter} 598438032Speter 598538032Speter 598638032Speter/* 598738032Speter** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 598838032Speter*/ 598938032Speter 599038032Spetervoid 599138032Speterstab_map_store(map, lhs, rhs) 599238032Speter register MAP *map; 599338032Speter char *lhs; 599438032Speter char *rhs; 599538032Speter{ 599638032Speter register STAB *s; 599738032Speter 599838032Speter s = stab(lhs, ST_ALIAS, ST_ENTER); 599938032Speter s->s_alias = newstr(rhs); 600038032Speter} 600138032Speter 600238032Speter 600338032Speter/* 600438032Speter** STAB_MAP_OPEN -- initialize (reads data file) 600538032Speter** 600638032Speter** This is a wierd case -- it is only intended as a fallback for 600738032Speter** aliases. For this reason, opens for write (only during a 600838032Speter** "newaliases") always fails, and opens for read open the 600938032Speter** actual underlying text file instead of the database. 601038032Speter*/ 601138032Speter 601238032Speterbool 601338032Speterstab_map_open(map, mode) 601438032Speter register MAP *map; 601538032Speter int mode; 601638032Speter{ 601738032Speter FILE *af; 601864562Sgshapiro long sff; 601938032Speter struct stat st; 602038032Speter 602138032Speter if (tTd(38, 2)) 602264562Sgshapiro dprintf("stab_map_open(%s, %s, %d)\n", 602338032Speter map->map_mname, map->map_file, mode); 602438032Speter 602538032Speter mode &= O_ACCMODE; 602638032Speter if (mode != O_RDONLY) 602738032Speter { 602838032Speter errno = EPERM; 602938032Speter return FALSE; 603038032Speter } 603138032Speter 603238032Speter sff = SFF_ROOTOK|SFF_REGONLY; 603364562Sgshapiro if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 603438032Speter sff |= SFF_NOWLINK; 603564562Sgshapiro if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail)) 603638032Speter sff |= SFF_SAFEDIRPATH; 603738032Speter af = safefopen(map->map_file, O_RDONLY, 0444, sff); 603838032Speter if (af == NULL) 603938032Speter return FALSE; 604038032Speter readaliases(map, af, FALSE, FALSE); 604138032Speter 604238032Speter if (fstat(fileno(af), &st) >= 0) 604338032Speter map->map_mtime = st.st_mtime; 604464562Sgshapiro (void) fclose(af); 604538032Speter 604638032Speter return TRUE; 604738032Speter} 604838032Speter/* 604938032Speter** Implicit Modules 605038032Speter** 605138032Speter** Tries several types. For back compatibility of aliases. 605238032Speter*/ 605338032Speter 605438032Speter 605538032Speter/* 605638032Speter** IMPL_MAP_LOOKUP -- lookup in best open database 605738032Speter*/ 605838032Speter 605938032Speterchar * 606038032Speterimpl_map_lookup(map, name, av, pstat) 606138032Speter MAP *map; 606238032Speter char *name; 606338032Speter char **av; 606438032Speter int *pstat; 606538032Speter{ 606638032Speter if (tTd(38, 20)) 606764562Sgshapiro dprintf("impl_map_lookup(%s, %s)\n", 606838032Speter map->map_mname, name); 606938032Speter 607038032Speter#ifdef NEWDB 607138032Speter if (bitset(MF_IMPL_HASH, map->map_mflags)) 607238032Speter return db_map_lookup(map, name, av, pstat); 607364562Sgshapiro#endif /* NEWDB */ 607438032Speter#ifdef NDBM 607538032Speter if (bitset(MF_IMPL_NDBM, map->map_mflags)) 607638032Speter return ndbm_map_lookup(map, name, av, pstat); 607764562Sgshapiro#endif /* NDBM */ 607838032Speter return stab_map_lookup(map, name, av, pstat); 607938032Speter} 608038032Speter 608138032Speter/* 608238032Speter** IMPL_MAP_STORE -- store in open databases 608338032Speter*/ 608438032Speter 608538032Spetervoid 608638032Speterimpl_map_store(map, lhs, rhs) 608738032Speter MAP *map; 608838032Speter char *lhs; 608938032Speter char *rhs; 609038032Speter{ 609138032Speter if (tTd(38, 12)) 609264562Sgshapiro dprintf("impl_map_store(%s, %s, %s)\n", 609338032Speter map->map_mname, lhs, rhs); 609438032Speter#ifdef NEWDB 609538032Speter if (bitset(MF_IMPL_HASH, map->map_mflags)) 609638032Speter db_map_store(map, lhs, rhs); 609764562Sgshapiro#endif /* NEWDB */ 609838032Speter#ifdef NDBM 609938032Speter if (bitset(MF_IMPL_NDBM, map->map_mflags)) 610038032Speter ndbm_map_store(map, lhs, rhs); 610164562Sgshapiro#endif /* NDBM */ 610238032Speter stab_map_store(map, lhs, rhs); 610338032Speter} 610438032Speter 610538032Speter/* 610638032Speter** IMPL_MAP_OPEN -- implicit database open 610738032Speter*/ 610838032Speter 610938032Speterbool 611038032Speterimpl_map_open(map, mode) 611138032Speter MAP *map; 611238032Speter int mode; 611338032Speter{ 611438032Speter if (tTd(38, 2)) 611564562Sgshapiro dprintf("impl_map_open(%s, %s, %d)\n", 611638032Speter map->map_mname, map->map_file, mode); 611738032Speter 611838032Speter mode &= O_ACCMODE; 611938032Speter#ifdef NEWDB 612038032Speter map->map_mflags |= MF_IMPL_HASH; 612138032Speter if (hash_map_open(map, mode)) 612238032Speter { 612338032Speter# ifdef NDBM_YP_COMPAT 612438032Speter if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL) 612564562Sgshapiro# endif /* NDBM_YP_COMPAT */ 612638032Speter return TRUE; 612738032Speter } 612838032Speter else 612938032Speter map->map_mflags &= ~MF_IMPL_HASH; 613064562Sgshapiro#endif /* NEWDB */ 613138032Speter#ifdef NDBM 613238032Speter map->map_mflags |= MF_IMPL_NDBM; 613338032Speter if (ndbm_map_open(map, mode)) 613438032Speter { 613538032Speter return TRUE; 613638032Speter } 613738032Speter else 613838032Speter map->map_mflags &= ~MF_IMPL_NDBM; 613964562Sgshapiro#endif /* NDBM */ 614038032Speter 614138032Speter#if defined(NEWDB) || defined(NDBM) 614238032Speter if (Verbose) 614338032Speter message("WARNING: cannot open alias database %s%s", 614438032Speter map->map_file, 614538032Speter mode == O_RDONLY ? "; reading text version" : ""); 614664562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */ 614738032Speter if (mode != O_RDONLY) 614838032Speter usrerr("Cannot rebuild aliases: no database format defined"); 614964562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */ 615038032Speter 615138032Speter if (mode == O_RDONLY) 615238032Speter return stab_map_open(map, mode); 615338032Speter else 615438032Speter return FALSE; 615538032Speter} 615638032Speter 615738032Speter 615838032Speter/* 615938032Speter** IMPL_MAP_CLOSE -- close any open database(s) 616038032Speter*/ 616138032Speter 616238032Spetervoid 616338032Speterimpl_map_close(map) 616438032Speter MAP *map; 616538032Speter{ 616638032Speter if (tTd(38, 9)) 616764562Sgshapiro dprintf("impl_map_close(%s, %s, %lx)\n", 616838032Speter map->map_mname, map->map_file, map->map_mflags); 616938032Speter#ifdef NEWDB 617038032Speter if (bitset(MF_IMPL_HASH, map->map_mflags)) 617138032Speter { 617238032Speter db_map_close(map); 617338032Speter map->map_mflags &= ~MF_IMPL_HASH; 617438032Speter } 617564562Sgshapiro#endif /* NEWDB */ 617638032Speter 617738032Speter#ifdef NDBM 617838032Speter if (bitset(MF_IMPL_NDBM, map->map_mflags)) 617938032Speter { 618038032Speter ndbm_map_close(map); 618138032Speter map->map_mflags &= ~MF_IMPL_NDBM; 618238032Speter } 618364562Sgshapiro#endif /* NDBM */ 618438032Speter} 618538032Speter/* 618638032Speter** User map class. 618738032Speter** 618838032Speter** Provides access to the system password file. 618938032Speter*/ 619038032Speter 619138032Speter/* 619238032Speter** USER_MAP_OPEN -- open user map 619338032Speter** 619438032Speter** Really just binds field names to field numbers. 619538032Speter*/ 619638032Speter 619738032Speterbool 619838032Speteruser_map_open(map, mode) 619938032Speter MAP *map; 620038032Speter int mode; 620138032Speter{ 620238032Speter if (tTd(38, 2)) 620364562Sgshapiro dprintf("user_map_open(%s, %d)\n", 620438032Speter map->map_mname, mode); 620538032Speter 620638032Speter mode &= O_ACCMODE; 620738032Speter if (mode != O_RDONLY) 620838032Speter { 620938032Speter /* issue a pseudo-error message */ 621038032Speter#ifdef ENOSYS 621138032Speter errno = ENOSYS; 621264562Sgshapiro#else /* ENOSYS */ 621338032Speter# ifdef EFTYPE 621438032Speter errno = EFTYPE; 621564562Sgshapiro# else /* EFTYPE */ 621638032Speter errno = ENXIO; 621764562Sgshapiro# endif /* EFTYPE */ 621864562Sgshapiro#endif /* ENOSYS */ 621938032Speter return FALSE; 622038032Speter } 622138032Speter if (map->map_valcolnm == NULL) 622264562Sgshapiro /* EMPTY */ 622338032Speter /* nothing */ ; 622438032Speter else if (strcasecmp(map->map_valcolnm, "name") == 0) 622538032Speter map->map_valcolno = 1; 622638032Speter else if (strcasecmp(map->map_valcolnm, "passwd") == 0) 622738032Speter map->map_valcolno = 2; 622838032Speter else if (strcasecmp(map->map_valcolnm, "uid") == 0) 622938032Speter map->map_valcolno = 3; 623038032Speter else if (strcasecmp(map->map_valcolnm, "gid") == 0) 623138032Speter map->map_valcolno = 4; 623238032Speter else if (strcasecmp(map->map_valcolnm, "gecos") == 0) 623338032Speter map->map_valcolno = 5; 623438032Speter else if (strcasecmp(map->map_valcolnm, "dir") == 0) 623538032Speter map->map_valcolno = 6; 623638032Speter else if (strcasecmp(map->map_valcolnm, "shell") == 0) 623738032Speter map->map_valcolno = 7; 623838032Speter else 623938032Speter { 624038032Speter syserr("User map %s: unknown column name %s", 624138032Speter map->map_mname, map->map_valcolnm); 624238032Speter return FALSE; 624338032Speter } 624438032Speter return TRUE; 624538032Speter} 624638032Speter 624738032Speter 624838032Speter/* 624938032Speter** USER_MAP_LOOKUP -- look up a user in the passwd file. 625038032Speter*/ 625138032Speter 625238032Speter/* ARGSUSED3 */ 625338032Speterchar * 625438032Speteruser_map_lookup(map, key, av, statp) 625538032Speter MAP *map; 625638032Speter char *key; 625738032Speter char **av; 625838032Speter int *statp; 625938032Speter{ 626038032Speter struct passwd *pw; 626138032Speter auto bool fuzzy; 626238032Speter 626338032Speter if (tTd(38, 20)) 626464562Sgshapiro dprintf("user_map_lookup(%s, %s)\n", 626538032Speter map->map_mname, key); 626638032Speter 626738032Speter pw = finduser(key, &fuzzy); 626838032Speter if (pw == NULL) 626938032Speter return NULL; 627038032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 627138032Speter return map_rewrite(map, key, strlen(key), NULL); 627238032Speter else 627338032Speter { 627438032Speter char *rwval = NULL; 627538032Speter char buf[30]; 627638032Speter 627738032Speter switch (map->map_valcolno) 627838032Speter { 627938032Speter case 0: 628038032Speter case 1: 628138032Speter rwval = pw->pw_name; 628238032Speter break; 628338032Speter 628438032Speter case 2: 628538032Speter rwval = pw->pw_passwd; 628638032Speter break; 628738032Speter 628838032Speter case 3: 628964562Sgshapiro snprintf(buf, sizeof buf, "%d", (int) pw->pw_uid); 629038032Speter rwval = buf; 629138032Speter break; 629238032Speter 629338032Speter case 4: 629464562Sgshapiro snprintf(buf, sizeof buf, "%d", (int) pw->pw_gid); 629538032Speter rwval = buf; 629638032Speter break; 629738032Speter 629838032Speter case 5: 629938032Speter rwval = pw->pw_gecos; 630038032Speter break; 630138032Speter 630238032Speter case 6: 630338032Speter rwval = pw->pw_dir; 630438032Speter break; 630538032Speter 630638032Speter case 7: 630738032Speter rwval = pw->pw_shell; 630838032Speter break; 630938032Speter } 631038032Speter return map_rewrite(map, rwval, strlen(rwval), av); 631138032Speter } 631238032Speter} 631338032Speter/* 631438032Speter** Program map type. 631538032Speter** 631638032Speter** This provides access to arbitrary programs. It should be used 631738032Speter** only very sparingly, since there is no way to bound the cost 631838032Speter** of invoking an arbitrary program. 631938032Speter*/ 632038032Speter 632138032Speterchar * 632238032Speterprog_map_lookup(map, name, av, statp) 632338032Speter MAP *map; 632438032Speter char *name; 632538032Speter char **av; 632638032Speter int *statp; 632738032Speter{ 632838032Speter int i; 632964562Sgshapiro int save_errno; 633038032Speter int fd; 633164562Sgshapiro int status; 633238032Speter auto pid_t pid; 633364562Sgshapiro register char *p; 633438032Speter char *rval; 633538032Speter char *argv[MAXPV + 1]; 633638032Speter char buf[MAXLINE]; 633738032Speter 633838032Speter if (tTd(38, 20)) 633964562Sgshapiro dprintf("prog_map_lookup(%s, %s) %s\n", 634038032Speter map->map_mname, name, map->map_file); 634138032Speter 634238032Speter i = 0; 634338032Speter argv[i++] = map->map_file; 634438032Speter if (map->map_rebuild != NULL) 634538032Speter { 634638032Speter snprintf(buf, sizeof buf, "%s", map->map_rebuild); 634738032Speter for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t")) 634838032Speter { 634938032Speter if (i >= MAXPV - 1) 635038032Speter break; 635138032Speter argv[i++] = p; 635238032Speter } 635338032Speter } 635438032Speter argv[i++] = name; 635538032Speter argv[i] = NULL; 635638032Speter if (tTd(38, 21)) 635738032Speter { 635864562Sgshapiro dprintf("prog_open:"); 635938032Speter for (i = 0; argv[i] != NULL; i++) 636064562Sgshapiro dprintf(" %s", argv[i]); 636164562Sgshapiro dprintf("\n"); 636238032Speter } 636338032Speter (void) blocksignal(SIGCHLD); 636438032Speter pid = prog_open(argv, &fd, CurEnv); 636538032Speter if (pid < 0) 636638032Speter { 636738032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 636838032Speter syserr("prog_map_lookup(%s) failed (%s) -- closing", 636938032Speter map->map_mname, errstring(errno)); 637038032Speter else if (tTd(38, 9)) 637164562Sgshapiro dprintf("prog_map_lookup(%s) failed (%s) -- closing", 637238032Speter map->map_mname, errstring(errno)); 637338032Speter map->map_mflags &= ~(MF_VALID|MF_OPEN); 637438032Speter *statp = EX_OSFILE; 637538032Speter return NULL; 637638032Speter } 637738032Speter i = read(fd, buf, sizeof buf - 1); 637838032Speter if (i < 0) 637938032Speter { 638038032Speter syserr("prog_map_lookup(%s): read error %s\n", 638138032Speter map->map_mname, errstring(errno)); 638238032Speter rval = NULL; 638338032Speter } 638438032Speter else if (i == 0) 638538032Speter { 638638032Speter if (tTd(38, 20)) 638764562Sgshapiro dprintf("prog_map_lookup(%s): empty answer\n", 638838032Speter map->map_mname); 638938032Speter rval = NULL; 639038032Speter } 639138032Speter else 639238032Speter { 639338032Speter buf[i] = '\0'; 639438032Speter p = strchr(buf, '\n'); 639538032Speter if (p != NULL) 639638032Speter *p = '\0'; 639738032Speter 639838032Speter /* collect the return value */ 639938032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 640038032Speter rval = map_rewrite(map, name, strlen(name), NULL); 640138032Speter else 640277349Sgshapiro rval = map_rewrite(map, buf, strlen(buf), av); 640338032Speter 640438032Speter /* now flush any additional output */ 640538032Speter while ((i = read(fd, buf, sizeof buf)) > 0) 640638032Speter continue; 640738032Speter } 640838032Speter 640938032Speter /* wait for the process to terminate */ 641064562Sgshapiro (void) close(fd); 641164562Sgshapiro status = waitfor(pid); 641264562Sgshapiro save_errno = errno; 641338032Speter (void) releasesignal(SIGCHLD); 641464562Sgshapiro errno = save_errno; 641538032Speter 641664562Sgshapiro if (status == -1) 641738032Speter { 641838032Speter syserr("prog_map_lookup(%s): wait error %s\n", 641938032Speter map->map_mname, errstring(errno)); 642038032Speter *statp = EX_SOFTWARE; 642138032Speter rval = NULL; 642238032Speter } 642364562Sgshapiro else if (WIFEXITED(status)) 642438032Speter { 642564562Sgshapiro if ((*statp = WEXITSTATUS(status)) != EX_OK) 642638032Speter rval = NULL; 642738032Speter } 642838032Speter else 642938032Speter { 643038032Speter syserr("prog_map_lookup(%s): child died on signal %d", 643164562Sgshapiro map->map_mname, status); 643238032Speter *statp = EX_UNAVAILABLE; 643338032Speter rval = NULL; 643438032Speter } 643538032Speter return rval; 643638032Speter} 643738032Speter/* 643838032Speter** Sequenced map type. 643938032Speter** 644038032Speter** Tries each map in order until something matches, much like 644138032Speter** implicit. Stores go to the first map in the list that can 644238032Speter** support storing. 644338032Speter** 644438032Speter** This is slightly unusual in that there are two interfaces. 644538032Speter** The "sequence" interface lets you stack maps arbitrarily. 644638032Speter** The "switch" interface builds a sequence map by looking 644738032Speter** at a system-dependent configuration file such as 644838032Speter** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix. 644938032Speter** 645038032Speter** We don't need an explicit open, since all maps are 645138032Speter** opened during startup, including underlying maps. 645238032Speter*/ 645338032Speter 645438032Speter/* 645538032Speter** SEQ_MAP_PARSE -- Sequenced map parsing 645638032Speter*/ 645738032Speter 645838032Speterbool 645938032Speterseq_map_parse(map, ap) 646038032Speter MAP *map; 646138032Speter char *ap; 646238032Speter{ 646338032Speter int maxmap; 646438032Speter 646538032Speter if (tTd(38, 2)) 646664562Sgshapiro dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap); 646738032Speter maxmap = 0; 646838032Speter while (*ap != '\0') 646938032Speter { 647038032Speter register char *p; 647138032Speter STAB *s; 647238032Speter 647338032Speter /* find beginning of map name */ 647438032Speter while (isascii(*ap) && isspace(*ap)) 647538032Speter ap++; 647664562Sgshapiro for (p = ap; 647764562Sgshapiro (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.'; 647864562Sgshapiro p++) 647938032Speter continue; 648038032Speter if (*p != '\0') 648138032Speter *p++ = '\0'; 648238032Speter while (*p != '\0' && (!isascii(*p) || !isalnum(*p))) 648338032Speter p++; 648438032Speter if (*ap == '\0') 648538032Speter { 648638032Speter ap = p; 648738032Speter continue; 648838032Speter } 648938032Speter s = stab(ap, ST_MAP, ST_FIND); 649038032Speter if (s == NULL) 649138032Speter { 649238032Speter syserr("Sequence map %s: unknown member map %s", 649338032Speter map->map_mname, ap); 649438032Speter } 649538032Speter else if (maxmap == MAXMAPSTACK) 649638032Speter { 649738032Speter syserr("Sequence map %s: too many member maps (%d max)", 649838032Speter map->map_mname, MAXMAPSTACK); 649938032Speter maxmap++; 650038032Speter } 650138032Speter else if (maxmap < MAXMAPSTACK) 650238032Speter { 650338032Speter map->map_stack[maxmap++] = &s->s_map; 650438032Speter } 650538032Speter ap = p; 650638032Speter } 650738032Speter return TRUE; 650838032Speter} 650938032Speter 651038032Speter 651138032Speter/* 651238032Speter** SWITCH_MAP_OPEN -- open a switched map 651338032Speter** 651438032Speter** This looks at the system-dependent configuration and builds 651538032Speter** a sequence map that does the same thing. 651638032Speter** 651738032Speter** Every system must define a switch_map_find routine in conf.c 651838032Speter** that will return the list of service types associated with a 651938032Speter** given service class. 652038032Speter*/ 652138032Speter 652238032Speterbool 652338032Speterswitch_map_open(map, mode) 652438032Speter MAP *map; 652538032Speter int mode; 652638032Speter{ 652738032Speter int mapno; 652838032Speter int nmaps; 652938032Speter char *maptype[MAXMAPSTACK]; 653038032Speter 653138032Speter if (tTd(38, 2)) 653264562Sgshapiro dprintf("switch_map_open(%s, %s, %d)\n", 653338032Speter map->map_mname, map->map_file, mode); 653438032Speter 653538032Speter mode &= O_ACCMODE; 653638032Speter nmaps = switch_map_find(map->map_file, maptype, map->map_return); 653738032Speter if (tTd(38, 19)) 653838032Speter { 653964562Sgshapiro dprintf("\tswitch_map_find => %d\n", nmaps); 654038032Speter for (mapno = 0; mapno < nmaps; mapno++) 654164562Sgshapiro dprintf("\t\t%s\n", maptype[mapno]); 654238032Speter } 654338032Speter if (nmaps <= 0 || nmaps > MAXMAPSTACK) 654438032Speter return FALSE; 654538032Speter 654638032Speter for (mapno = 0; mapno < nmaps; mapno++) 654738032Speter { 654838032Speter register STAB *s; 654938032Speter char nbuf[MAXNAME + 1]; 655038032Speter 655138032Speter if (maptype[mapno] == NULL) 655238032Speter continue; 655338032Speter (void) snprintf(nbuf, sizeof nbuf, "%s.%s", 655438032Speter map->map_mname, maptype[mapno]); 655538032Speter s = stab(nbuf, ST_MAP, ST_FIND); 655638032Speter if (s == NULL) 655738032Speter { 655838032Speter syserr("Switch map %s: unknown member map %s", 655938032Speter map->map_mname, nbuf); 656038032Speter } 656138032Speter else 656238032Speter { 656338032Speter map->map_stack[mapno] = &s->s_map; 656438032Speter if (tTd(38, 4)) 656564562Sgshapiro dprintf("\tmap_stack[%d] = %s:%s\n", 656638032Speter mapno, s->s_map.map_class->map_cname, 656738032Speter nbuf); 656838032Speter } 656938032Speter } 657038032Speter return TRUE; 657138032Speter} 657238032Speter 657338032Speter 657438032Speter/* 657538032Speter** SEQ_MAP_CLOSE -- close all underlying maps 657638032Speter*/ 657738032Speter 657838032Spetervoid 657938032Speterseq_map_close(map) 658038032Speter MAP *map; 658138032Speter{ 658238032Speter int mapno; 658338032Speter 658438032Speter if (tTd(38, 9)) 658564562Sgshapiro dprintf("seq_map_close(%s)\n", map->map_mname); 658638032Speter 658738032Speter for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 658838032Speter { 658938032Speter MAP *mm = map->map_stack[mapno]; 659038032Speter 659138032Speter if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags)) 659238032Speter continue; 659377349Sgshapiro mm->map_mflags |= MF_CLOSING; 659438032Speter mm->map_class->map_close(mm); 659577349Sgshapiro mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 659638032Speter } 659738032Speter} 659838032Speter 659938032Speter 660038032Speter/* 660138032Speter** SEQ_MAP_LOOKUP -- sequenced map lookup 660238032Speter*/ 660338032Speter 660438032Speterchar * 660538032Speterseq_map_lookup(map, key, args, pstat) 660638032Speter MAP *map; 660738032Speter char *key; 660838032Speter char **args; 660938032Speter int *pstat; 661038032Speter{ 661138032Speter int mapno; 661238032Speter int mapbit = 0x01; 661338032Speter bool tempfail = FALSE; 661438032Speter 661538032Speter if (tTd(38, 20)) 661664562Sgshapiro dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key); 661738032Speter 661838032Speter for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++) 661938032Speter { 662038032Speter MAP *mm = map->map_stack[mapno]; 662138032Speter char *rv; 662238032Speter 662338032Speter if (mm == NULL) 662438032Speter continue; 662564562Sgshapiro if (!bitset(MF_OPEN, mm->map_mflags) && 662664562Sgshapiro !openmap(mm)) 662738032Speter { 662838032Speter if (bitset(mapbit, map->map_return[MA_UNAVAIL])) 662938032Speter { 663038032Speter *pstat = EX_UNAVAILABLE; 663138032Speter return NULL; 663238032Speter } 663338032Speter continue; 663438032Speter } 663538032Speter *pstat = EX_OK; 663638032Speter rv = mm->map_class->map_lookup(mm, key, args, pstat); 663738032Speter if (rv != NULL) 663838032Speter return rv; 663938032Speter if (*pstat == EX_TEMPFAIL) 664038032Speter { 664138032Speter if (bitset(mapbit, map->map_return[MA_TRYAGAIN])) 664238032Speter return NULL; 664338032Speter tempfail = TRUE; 664438032Speter } 664538032Speter else if (bitset(mapbit, map->map_return[MA_NOTFOUND])) 664638032Speter break; 664738032Speter } 664838032Speter if (tempfail) 664938032Speter *pstat = EX_TEMPFAIL; 665038032Speter else if (*pstat == EX_OK) 665138032Speter *pstat = EX_NOTFOUND; 665238032Speter return NULL; 665338032Speter} 665438032Speter 665538032Speter 665638032Speter/* 665738032Speter** SEQ_MAP_STORE -- sequenced map store 665838032Speter*/ 665938032Speter 666038032Spetervoid 666138032Speterseq_map_store(map, key, val) 666238032Speter MAP *map; 666338032Speter char *key; 666438032Speter char *val; 666538032Speter{ 666638032Speter int mapno; 666738032Speter 666838032Speter if (tTd(38, 12)) 666964562Sgshapiro dprintf("seq_map_store(%s, %s, %s)\n", 667038032Speter map->map_mname, key, val); 667138032Speter 667238032Speter for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 667338032Speter { 667438032Speter MAP *mm = map->map_stack[mapno]; 667538032Speter 667638032Speter if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags)) 667738032Speter continue; 667838032Speter 667938032Speter mm->map_class->map_store(mm, key, val); 668038032Speter return; 668138032Speter } 668238032Speter syserr("seq_map_store(%s, %s, %s): no writable map", 668338032Speter map->map_mname, key, val); 668438032Speter} 668538032Speter/* 668638032Speter** NULL stubs 668738032Speter*/ 668838032Speter 668938032Speter/* ARGSUSED */ 669038032Speterbool 669138032Speternull_map_open(map, mode) 669238032Speter MAP *map; 669338032Speter int mode; 669438032Speter{ 669538032Speter return TRUE; 669638032Speter} 669738032Speter 669838032Speter/* ARGSUSED */ 669938032Spetervoid 670038032Speternull_map_close(map) 670138032Speter MAP *map; 670238032Speter{ 670338032Speter return; 670438032Speter} 670538032Speter 670638032Speterchar * 670738032Speternull_map_lookup(map, key, args, pstat) 670838032Speter MAP *map; 670938032Speter char *key; 671038032Speter char **args; 671138032Speter int *pstat; 671238032Speter{ 671338032Speter *pstat = EX_NOTFOUND; 671438032Speter return NULL; 671538032Speter} 671638032Speter 671738032Speter/* ARGSUSED */ 671838032Spetervoid 671938032Speternull_map_store(map, key, val) 672038032Speter MAP *map; 672138032Speter char *key; 672238032Speter char *val; 672338032Speter{ 672438032Speter return; 672538032Speter} 672638032Speter 672738032Speter 672838032Speter/* 672938032Speter** BOGUS stubs 673038032Speter*/ 673138032Speter 673238032Speterchar * 673338032Speterbogus_map_lookup(map, key, args, pstat) 673438032Speter MAP *map; 673538032Speter char *key; 673638032Speter char **args; 673738032Speter int *pstat; 673838032Speter{ 673938032Speter *pstat = EX_TEMPFAIL; 674038032Speter return NULL; 674138032Speter} 674238032Speter 674338032SpeterMAPCLASS BogusMapClass = 674438032Speter{ 674538032Speter "bogus-map", NULL, 0, 674638032Speter NULL, bogus_map_lookup, null_map_store, 674738032Speter null_map_open, null_map_close, 674838032Speter}; 674938032Speter/* 675064562Sgshapiro** MACRO modules 675164562Sgshapiro*/ 675264562Sgshapiro 675364562Sgshapirochar * 675464562Sgshapiromacro_map_lookup(map, name, av, statp) 675564562Sgshapiro MAP *map; 675664562Sgshapiro char *name; 675764562Sgshapiro char **av; 675864562Sgshapiro int *statp; 675964562Sgshapiro{ 676064562Sgshapiro int mid; 676164562Sgshapiro 676264562Sgshapiro if (tTd(38, 20)) 676364562Sgshapiro dprintf("macro_map_lookup(%s, %s)\n", map->map_mname, 676464562Sgshapiro name == NULL ? "NULL" : name); 676564562Sgshapiro 676664562Sgshapiro if (name == NULL || 676764562Sgshapiro *name == '\0' || 676864562Sgshapiro (mid = macid(name, NULL)) == '\0') 676964562Sgshapiro { 677064562Sgshapiro *statp = EX_CONFIG; 677164562Sgshapiro return NULL; 677264562Sgshapiro } 677364562Sgshapiro 677464562Sgshapiro if (av[1] == NULL) 677564562Sgshapiro define(mid, NULL, CurEnv); 677664562Sgshapiro else 677764562Sgshapiro define(mid, newstr(av[1]), CurEnv); 677864562Sgshapiro 677964562Sgshapiro *statp = EX_OK; 678064562Sgshapiro return ""; 678164562Sgshapiro} 678264562Sgshapiro/* 678338032Speter** REGEX modules 678438032Speter*/ 678538032Speter 678638032Speter#ifdef MAP_REGEX 678738032Speter 678838032Speter# include <regex.h> 678938032Speter 679038032Speter# define DEFAULT_DELIM CONDELSE 679138032Speter 679238032Speter# define END_OF_FIELDS -1 679338032Speter 679438032Speter# define ERRBUF_SIZE 80 679538032Speter# define MAX_MATCH 32 679638032Speter 679764562Sgshapiro# define xnalloc(s) memset(xalloc(s), '\0', s); 679838032Speter 679938032Speterstruct regex_map 680038032Speter{ 680171345Sgshapiro regex_t *regex_pattern_buf; /* xalloc it */ 680238032Speter int *regex_subfields; /* move to type MAP */ 680364562Sgshapiro char *regex_delim; /* move to type MAP */ 680438032Speter}; 680538032Speter 680638032Speterstatic int 680738032Speterparse_fields(s, ibuf, blen, nr_substrings) 680838032Speter char *s; 680938032Speter int *ibuf; /* array */ 681038032Speter int blen; /* number of elements in ibuf */ 681138032Speter int nr_substrings; /* number of substrings in the pattern */ 681238032Speter{ 681338032Speter register char *cp; 681438032Speter int i = 0; 681538032Speter bool lastone = FALSE; 681638032Speter 681738032Speter blen--; /* for terminating END_OF_FIELDS */ 681838032Speter cp = s; 681938032Speter do 682038032Speter { 682138032Speter for (;; cp++) 682238032Speter { 682338032Speter if (*cp == ',') 682438032Speter { 682538032Speter *cp = '\0'; 682638032Speter break; 682738032Speter } 682838032Speter if (*cp == '\0') 682938032Speter { 683038032Speter lastone = TRUE; 683138032Speter break; 683238032Speter } 683338032Speter } 683438032Speter if (i < blen) 683538032Speter { 683638032Speter int val = atoi(s); 683738032Speter 683838032Speter if (val < 0 || val >= nr_substrings) 683938032Speter { 684038032Speter syserr("field (%d) out of range, only %d substrings in pattern", 684138032Speter val, nr_substrings); 684238032Speter return -1; 684338032Speter } 684438032Speter ibuf[i++] = val; 684538032Speter } 684638032Speter else 684738032Speter { 684838032Speter syserr("too many fields, %d max\n", blen); 684938032Speter return -1; 685038032Speter } 685138032Speter s = ++cp; 685238032Speter } while (!lastone); 685338032Speter ibuf[i] = END_OF_FIELDS; 685438032Speter return i; 685538032Speter} 685638032Speter 685738032Speterbool 685838032Speterregex_map_init(map, ap) 685938032Speter MAP *map; 686038032Speter char *ap; 686138032Speter{ 686238032Speter int regerr; 686338032Speter struct regex_map *map_p; 686438032Speter register char *p; 686538032Speter char *sub_param = NULL; 686638032Speter int pflags; 686738032Speter static char defdstr[] = { (char)DEFAULT_DELIM, '\0' }; 686838032Speter 686938032Speter if (tTd(38, 2)) 687064562Sgshapiro dprintf("regex_map_init: mapname '%s', args '%s'\n", 687164562Sgshapiro map->map_mname, ap); 687238032Speter 687338032Speter pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB; 687438032Speter 687538032Speter p = ap; 687638032Speter 687764562Sgshapiro map_p = (struct regex_map *) xnalloc(sizeof *map_p); 687871345Sgshapiro map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t)); 687938032Speter 688038032Speter for (;;) 688164562Sgshapiro { 688238032Speter while (isascii(*p) && isspace(*p)) 688338032Speter p++; 688438032Speter if (*p != '-') 688538032Speter break; 688638032Speter switch (*++p) 688738032Speter { 688838032Speter case 'n': /* not */ 688938032Speter map->map_mflags |= MF_REGEX_NOT; 689038032Speter break; 689138032Speter 689238032Speter case 'f': /* case sensitive */ 689338032Speter map->map_mflags |= MF_NOFOLDCASE; 689438032Speter pflags &= ~REG_ICASE; 689538032Speter break; 689638032Speter 689738032Speter case 'b': /* basic regular expressions */ 689838032Speter pflags &= ~REG_EXTENDED; 689938032Speter break; 690038032Speter 690138032Speter case 's': /* substring match () syntax */ 690238032Speter sub_param = ++p; 690338032Speter pflags &= ~REG_NOSUB; 690438032Speter break; 690538032Speter 690638032Speter case 'd': /* delimiter */ 690764562Sgshapiro map_p->regex_delim = ++p; 690838032Speter break; 690938032Speter 691038032Speter case 'a': /* map append */ 691138032Speter map->map_app = ++p; 691238032Speter break; 691338032Speter 691438032Speter case 'm': /* matchonly */ 691538032Speter map->map_mflags |= MF_MATCHONLY; 691638032Speter break; 691738032Speter 691864562Sgshapiro case 'S': 691964562Sgshapiro map->map_spacesub = *++p; 692064562Sgshapiro break; 692164562Sgshapiro 692264562Sgshapiro case 'D': 692364562Sgshapiro map->map_mflags |= MF_DEFER; 692464562Sgshapiro break; 692564562Sgshapiro 692638032Speter } 692764562Sgshapiro while (*p != '\0' && !(isascii(*p) && isspace(*p))) 692864562Sgshapiro p++; 692964562Sgshapiro if (*p != '\0') 693064562Sgshapiro *p++ = '\0'; 693138032Speter } 693238032Speter if (tTd(38, 3)) 693364562Sgshapiro dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags); 693438032Speter 693571345Sgshapiro if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0) 693638032Speter { 693738032Speter /* Errorhandling */ 693838032Speter char errbuf[ERRBUF_SIZE]; 693938032Speter 694071345Sgshapiro (void) regerror(regerr, map_p->regex_pattern_buf, 694164562Sgshapiro errbuf, ERRBUF_SIZE); 694238032Speter syserr("pattern-compile-error: %s\n", errbuf); 694377349Sgshapiro sm_free(map_p->regex_pattern_buf); 694477349Sgshapiro sm_free(map_p); 694538032Speter return FALSE; 694638032Speter } 694738032Speter 694838032Speter if (map->map_app != NULL) 694938032Speter map->map_app = newstr(map->map_app); 695064562Sgshapiro if (map_p->regex_delim != NULL) 695164562Sgshapiro map_p->regex_delim = newstr(map_p->regex_delim); 695238032Speter else 695364562Sgshapiro map_p->regex_delim = defdstr; 695438032Speter 695538032Speter if (!bitset(REG_NOSUB, pflags)) 695638032Speter { 695738032Speter /* substring matching */ 695838032Speter int substrings; 695964562Sgshapiro int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1)); 696038032Speter 696171345Sgshapiro substrings = map_p->regex_pattern_buf->re_nsub + 1; 696238032Speter 696338032Speter if (tTd(38, 3)) 696464562Sgshapiro dprintf("regex_map_init: nr of substrings %d\n", 696564562Sgshapiro substrings); 696638032Speter 696738032Speter if (substrings >= MAX_MATCH) 696838032Speter { 696938032Speter syserr("too many substrings, %d max\n", MAX_MATCH); 697077349Sgshapiro sm_free(map_p->regex_pattern_buf); 697177349Sgshapiro sm_free(map_p); 697238032Speter return FALSE; 697338032Speter } 697438032Speter if (sub_param != NULL && sub_param[0] != '\0') 697538032Speter { 697638032Speter /* optional parameter -sfields */ 697738032Speter if (parse_fields(sub_param, fields, 697838032Speter MAX_MATCH + 1, substrings) == -1) 697938032Speter return FALSE; 698038032Speter } 698138032Speter else 698238032Speter { 698364562Sgshapiro /* set default fields */ 698438032Speter int i; 698538032Speter 698638032Speter for (i = 0; i < substrings; i++) 698738032Speter fields[i] = i; 698838032Speter fields[i] = END_OF_FIELDS; 698938032Speter } 699038032Speter map_p->regex_subfields = fields; 699138032Speter if (tTd(38, 3)) 699238032Speter { 699338032Speter int *ip; 699438032Speter 699564562Sgshapiro dprintf("regex_map_init: subfields"); 699638032Speter for (ip = fields; *ip != END_OF_FIELDS; ip++) 699764562Sgshapiro dprintf(" %d", *ip); 699864562Sgshapiro dprintf("\n"); 699938032Speter } 700038032Speter } 700138032Speter map->map_db1 = (ARBPTR_T)map_p; /* dirty hack */ 700238032Speter 700338032Speter return TRUE; 700438032Speter} 700538032Speter 700638032Speterstatic char * 700738032Speterregex_map_rewrite(map, s, slen, av) 700838032Speter MAP *map; 700938032Speter const char *s; 701038032Speter size_t slen; 701138032Speter char **av; 701238032Speter{ 701338032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 701438032Speter return map_rewrite(map, av[0], strlen(av[0]), NULL); 701538032Speter else 701677349Sgshapiro return map_rewrite(map, s, slen, av); 701738032Speter} 701838032Speter 701938032Speterchar * 702038032Speterregex_map_lookup(map, name, av, statp) 702138032Speter MAP *map; 702238032Speter char *name; 702338032Speter char **av; 702438032Speter int *statp; 702538032Speter{ 702638032Speter int reg_res; 702738032Speter struct regex_map *map_p; 702838032Speter regmatch_t pmatch[MAX_MATCH]; 702938032Speter 703038032Speter if (tTd(38, 20)) 703138032Speter { 703238032Speter char **cpp; 703338032Speter 703464562Sgshapiro dprintf("regex_map_lookup: key '%s'\n", name); 703564562Sgshapiro for (cpp = av; cpp != NULL && *cpp != NULL; cpp++) 703664562Sgshapiro dprintf("regex_map_lookup: arg '%s'\n", *cpp); 703738032Speter } 703838032Speter 703938032Speter map_p = (struct regex_map *)(map->map_db1); 704071345Sgshapiro reg_res = regexec(map_p->regex_pattern_buf, 704164562Sgshapiro name, MAX_MATCH, pmatch, 0); 704238032Speter 704338032Speter if (bitset(MF_REGEX_NOT, map->map_mflags)) 704438032Speter { 704538032Speter /* option -n */ 704638032Speter if (reg_res == REG_NOMATCH) 704738032Speter return regex_map_rewrite(map, "", (size_t)0, av); 704838032Speter else 704938032Speter return NULL; 705038032Speter } 705138032Speter if (reg_res == REG_NOMATCH) 705238032Speter return NULL; 705338032Speter 705438032Speter if (map_p->regex_subfields != NULL) 705538032Speter { 705638032Speter /* option -s */ 705738032Speter static char retbuf[MAXNAME]; 705838032Speter int fields[MAX_MATCH + 1]; 705938032Speter bool first = TRUE; 706038032Speter int anglecnt = 0, cmntcnt = 0, spacecnt = 0; 706138032Speter bool quotemode = FALSE, bslashmode = FALSE; 706238032Speter register char *dp, *sp; 706338032Speter char *endp, *ldp; 706438032Speter int *ip; 706538032Speter 706638032Speter dp = retbuf; 706738032Speter ldp = retbuf + sizeof(retbuf) - 1; 706838032Speter 706938032Speter if (av[1] != NULL) 707038032Speter { 707138032Speter if (parse_fields(av[1], fields, MAX_MATCH + 1, 707271345Sgshapiro (int) map_p->regex_pattern_buf->re_nsub + 1) == -1) 707338032Speter { 707438032Speter *statp = EX_CONFIG; 707538032Speter return NULL; 707638032Speter } 707738032Speter ip = fields; 707838032Speter } 707938032Speter else 708038032Speter ip = map_p->regex_subfields; 708138032Speter 708238032Speter for ( ; *ip != END_OF_FIELDS; ip++) 708338032Speter { 708438032Speter if (!first) 708538032Speter { 708664562Sgshapiro for (sp = map_p->regex_delim; *sp; sp++) 708738032Speter { 708838032Speter if (dp < ldp) 708938032Speter *dp++ = *sp; 709038032Speter } 709138032Speter } 709238032Speter else 709338032Speter first = FALSE; 709438032Speter 709538032Speter 709671345Sgshapiro if (*ip >= MAX_MATCH || 709771345Sgshapiro pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0) 709838032Speter continue; 709938032Speter 710038032Speter sp = name + pmatch[*ip].rm_so; 710138032Speter endp = name + pmatch[*ip].rm_eo; 710238032Speter for (; endp > sp; sp++) 710338032Speter { 710438032Speter if (dp < ldp) 710538032Speter { 710664562Sgshapiro if (bslashmode) 710764562Sgshapiro { 710838032Speter *dp++ = *sp; 710938032Speter bslashmode = FALSE; 711038032Speter } 711164562Sgshapiro else if (quotemode && *sp != '"' && 711238032Speter *sp != '\\') 711338032Speter { 711438032Speter *dp++ = *sp; 711538032Speter } 711638032Speter else switch(*dp++ = *sp) 711738032Speter { 711838032Speter case '\\': 711938032Speter bslashmode = TRUE; 712038032Speter break; 712138032Speter 712238032Speter case '(': 712338032Speter cmntcnt++; 712438032Speter break; 712538032Speter 712638032Speter case ')': 712738032Speter cmntcnt--; 712838032Speter break; 712938032Speter 713038032Speter case '<': 713138032Speter anglecnt++; 713238032Speter break; 713338032Speter 713438032Speter case '>': 713538032Speter anglecnt--; 713638032Speter break; 713738032Speter 713838032Speter case ' ': 713938032Speter spacecnt++; 714038032Speter break; 714138032Speter 714238032Speter case '"': 714338032Speter quotemode = !quotemode; 714438032Speter break; 714538032Speter } 714638032Speter } 714738032Speter } 714838032Speter } 714938032Speter if (anglecnt != 0 || cmntcnt != 0 || quotemode || 715038032Speter bslashmode || spacecnt != 0) 715138032Speter { 715264562Sgshapiro sm_syslog(LOG_WARNING, NOQID, 715364562Sgshapiro "Warning: regex may cause prescan() failure map=%s lookup=%s", 715464562Sgshapiro map->map_mname, name); 715538032Speter return NULL; 715638032Speter } 715738032Speter 715838032Speter *dp = '\0'; 715938032Speter 716038032Speter return regex_map_rewrite(map, retbuf, strlen(retbuf), av); 716138032Speter } 716238032Speter return regex_map_rewrite(map, "", (size_t)0, av); 716338032Speter} 716438032Speter#endif /* MAP_REGEX */ 716564562Sgshapiro/* 716664562Sgshapiro** NSD modules 716764562Sgshapiro*/ 716864562Sgshapiro#ifdef MAP_NSD 716964562Sgshapiro 717064562Sgshapiro# include <ndbm.h> 717164562Sgshapiro# define _DATUM_DEFINED 717264562Sgshapiro# include <ns_api.h> 717364562Sgshapiro 717464562Sgshapirotypedef struct ns_map_list 717564562Sgshapiro{ 717664562Sgshapiro ns_map_t *map; 717764562Sgshapiro char *mapname; 717864562Sgshapiro struct ns_map_list *next; 717964562Sgshapiro} ns_map_list_t; 718064562Sgshapiro 718164562Sgshapirostatic ns_map_t * 718264562Sgshapirons_map_t_find(mapname) 718364562Sgshapiro char *mapname; 718464562Sgshapiro{ 718564562Sgshapiro static ns_map_list_t *ns_maps = NULL; 718664562Sgshapiro ns_map_list_t *ns_map; 718764562Sgshapiro 718864562Sgshapiro /* walk the list of maps looking for the correctly named map */ 718964562Sgshapiro for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next) 719064562Sgshapiro { 719164562Sgshapiro if (strcmp(ns_map->mapname, mapname) == 0) 719264562Sgshapiro break; 719364562Sgshapiro } 719464562Sgshapiro 719564562Sgshapiro /* if we are looking at a NULL ns_map_list_t, then create a new one */ 719664562Sgshapiro if (ns_map == NULL) 719764562Sgshapiro { 719864562Sgshapiro ns_map = (ns_map_list_t *) xalloc(sizeof *ns_map); 719964562Sgshapiro ns_map->mapname = newstr(mapname); 720064562Sgshapiro ns_map->map = (ns_map_t *) xalloc(sizeof *ns_map->map); 720164562Sgshapiro ns_map->next = ns_maps; 720264562Sgshapiro ns_maps = ns_map; 720364562Sgshapiro } 720464562Sgshapiro return ns_map->map; 720564562Sgshapiro} 720664562Sgshapiro 720764562Sgshapirochar * 720864562Sgshapironsd_map_lookup(map, name, av, statp) 720964562Sgshapiro MAP *map; 721064562Sgshapiro char *name; 721164562Sgshapiro char **av; 721264562Sgshapiro int *statp; 721364562Sgshapiro{ 721471345Sgshapiro int buflen, r; 721564562Sgshapiro char *p; 721664562Sgshapiro ns_map_t *ns_map; 721764562Sgshapiro char keybuf[MAXNAME + 1]; 721864562Sgshapiro char buf[MAXLINE]; 721964562Sgshapiro 722064562Sgshapiro if (tTd(38, 20)) 722164562Sgshapiro dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name); 722264562Sgshapiro 722364562Sgshapiro buflen = strlen(name); 722464562Sgshapiro if (buflen > sizeof keybuf - 1) 722564562Sgshapiro buflen = sizeof keybuf - 1; 722664562Sgshapiro memmove(keybuf, name, buflen); 722764562Sgshapiro keybuf[buflen] = '\0'; 722864562Sgshapiro if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 722964562Sgshapiro makelower(keybuf); 723064562Sgshapiro 723164562Sgshapiro ns_map = ns_map_t_find(map->map_file); 723264562Sgshapiro if (ns_map == NULL) 723364562Sgshapiro { 723464562Sgshapiro if (tTd(38, 20)) 723564562Sgshapiro dprintf("nsd_map_t_find failed\n"); 723671345Sgshapiro *statp = EX_UNAVAILABLE; 723764562Sgshapiro return NULL; 723864562Sgshapiro } 723971345Sgshapiro r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL, buf, MAXLINE); 724071345Sgshapiro if (r == NS_UNAVAIL || r == NS_TRYAGAIN) 724171345Sgshapiro { 724271345Sgshapiro *statp = EX_TEMPFAIL; 724364562Sgshapiro return NULL; 724471345Sgshapiro } 724577349Sgshapiro if (r == NS_BADREQ 724677349Sgshapiro# ifdef NS_NOPERM 724777349Sgshapiro || r == NS_NOPERM 724877349Sgshapiro# endif /* NS_NOPERM */ 724977349Sgshapiro ) 725071345Sgshapiro { 725171345Sgshapiro *statp = EX_CONFIG; 725271345Sgshapiro return NULL; 725371345Sgshapiro } 725471345Sgshapiro if (r != NS_SUCCESS) 725571345Sgshapiro { 725671345Sgshapiro *statp = EX_NOTFOUND; 725771345Sgshapiro return NULL; 725871345Sgshapiro } 725964562Sgshapiro 726071345Sgshapiro *statp = EX_OK; 726171345Sgshapiro 726264562Sgshapiro /* Null out trailing \n */ 726364562Sgshapiro if ((p = strchr(buf, '\n')) != NULL) 726464562Sgshapiro *p = '\0'; 726564562Sgshapiro 726664562Sgshapiro return map_rewrite(map, buf, strlen(buf), av); 726764562Sgshapiro} 726864562Sgshapiro#endif /* MAP_NSD */ 726964562Sgshapiro 727064562Sgshapirochar * 727164562Sgshapiroarith_map_lookup(map, name, av, statp) 727264562Sgshapiro MAP *map; 727364562Sgshapiro char *name; 727464562Sgshapiro char **av; 727564562Sgshapiro int *statp; 727664562Sgshapiro{ 727764562Sgshapiro long r; 727864562Sgshapiro long v[2]; 727964562Sgshapiro bool res = FALSE; 728064562Sgshapiro bool boolres; 728164562Sgshapiro static char result[16]; 728264562Sgshapiro char **cpp; 728364562Sgshapiro 728464562Sgshapiro if (tTd(38, 2)) 728564562Sgshapiro { 728664562Sgshapiro dprintf("arith_map_lookup: key '%s'\n", name); 728764562Sgshapiro for (cpp = av; cpp != NULL && *cpp != NULL; cpp++) 728864562Sgshapiro dprintf("arith_map_lookup: arg '%s'\n", *cpp); 728964562Sgshapiro } 729064562Sgshapiro r = 0; 729164562Sgshapiro boolres = FALSE; 729264562Sgshapiro cpp = av; 729364562Sgshapiro *statp = EX_OK; 729464562Sgshapiro 729564562Sgshapiro /* 729664562Sgshapiro ** read arguments for arith map 729764562Sgshapiro ** - no check is made whether they are really numbers 729864562Sgshapiro ** - just ignores args after the second 729964562Sgshapiro */ 730064562Sgshapiro for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++) 730164562Sgshapiro v[r++] = strtol(*cpp, NULL, 0); 730264562Sgshapiro 730364562Sgshapiro /* operator and (at least) two operands given? */ 730464562Sgshapiro if (name != NULL && r == 2) 730564562Sgshapiro { 730664562Sgshapiro switch(*name) 730764562Sgshapiro { 730864562Sgshapiro#if _FFR_ARITH 730964562Sgshapiro case '|': 731064562Sgshapiro r = v[0] | v[1]; 731164562Sgshapiro break; 731264562Sgshapiro 731364562Sgshapiro case '&': 731464562Sgshapiro r = v[0] & v[1]; 731564562Sgshapiro break; 731664562Sgshapiro 731764562Sgshapiro case '%': 731864562Sgshapiro if (v[1] == 0) 731964562Sgshapiro return NULL; 732064562Sgshapiro r = v[0] % v[1]; 732164562Sgshapiro break; 732264562Sgshapiro#endif /* _FFR_ARITH */ 732364562Sgshapiro 732464562Sgshapiro case '+': 732564562Sgshapiro r = v[0] + v[1]; 732664562Sgshapiro break; 732764562Sgshapiro 732864562Sgshapiro case '-': 732964562Sgshapiro r = v[0] - v[1]; 733064562Sgshapiro break; 733164562Sgshapiro 733264562Sgshapiro case '*': 733364562Sgshapiro r = v[0] * v[1]; 733464562Sgshapiro break; 733564562Sgshapiro 733664562Sgshapiro case '/': 733764562Sgshapiro if (v[1] == 0) 733864562Sgshapiro return NULL; 733964562Sgshapiro r = v[0] / v[1]; 734064562Sgshapiro break; 734164562Sgshapiro 734264562Sgshapiro case 'l': 734364562Sgshapiro res = v[0] < v[1]; 734464562Sgshapiro boolres = TRUE; 734564562Sgshapiro break; 734664562Sgshapiro 734764562Sgshapiro case '=': 734864562Sgshapiro res = v[0] == v[1]; 734964562Sgshapiro boolres = TRUE; 735064562Sgshapiro break; 735164562Sgshapiro 735264562Sgshapiro default: 735364562Sgshapiro /* XXX */ 735464562Sgshapiro *statp = EX_CONFIG; 735564562Sgshapiro if (LogLevel > 10) 735664562Sgshapiro sm_syslog(LOG_WARNING, NOQID, 735764562Sgshapiro "arith_map: unknown operator %c", 735864562Sgshapiro isprint(*name) ? *name : '?'); 735964562Sgshapiro return NULL; 736064562Sgshapiro } 736164562Sgshapiro if (boolres) 736264562Sgshapiro snprintf(result, sizeof result, res ? "TRUE" : "FALSE"); 736364562Sgshapiro else 736464562Sgshapiro snprintf(result, sizeof result, "%ld", r); 736564562Sgshapiro return result; 736664562Sgshapiro } 736764562Sgshapiro *statp = EX_CONFIG; 736864562Sgshapiro return NULL; 736964562Sgshapiro} 7370