map.c revision 285303
138032Speter/* 2261363Sgshapiro * Copyright (c) 1998-2008 Proofpoint, 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 1464562Sgshapiro#include <sendmail.h> 1538032Speter 16266692SgshapiroSM_RCSID("@(#)$Id: map.c,v 8.713 2013-11-22 20:51:55 ca Exp $") 1764562Sgshapiro 1890792Sgshapiro#if LDAPMAP 1990792Sgshapiro# include <sm/ldap.h> 2090792Sgshapiro#endif /* LDAPMAP */ 2190792Sgshapiro 2290792Sgshapiro#if NDBM 2338032Speter# include <ndbm.h> 2438032Speter# ifdef R_FIRST 2538032Speter ERROR README: You are running the Berkeley DB version of ndbm.h. See 2638032Speter ERROR README: the README file about tweaking Berkeley DB so it can 2738032Speter ERROR README: coexist with NDBM, or delete -DNDBM from the Makefile 2838032Speter ERROR README: and use -DNEWDB instead. 2964562Sgshapiro# endif /* R_FIRST */ 3064562Sgshapiro#endif /* NDBM */ 3190792Sgshapiro#if NEWDB 32110560Sgshapiro# include "sm/bdb.h" 3364562Sgshapiro#endif /* NEWDB */ 3490792Sgshapiro#if NIS 3538032Speter struct dom_binding; /* forward reference needed on IRIX */ 3638032Speter# include <rpcsvc/ypclnt.h> 3790792Sgshapiro# if NDBM 3838032Speter# define NDBM_YP_COMPAT /* create YP-compatible NDBM files */ 3964562Sgshapiro# endif /* NDBM */ 4064562Sgshapiro#endif /* NIS */ 4138032Speter 42168515Sgshapiro#include "map.h" 43168515Sgshapiro 4490792Sgshapiro#if 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)); 5690792Sgshapirostatic void map_close __P((STAB *, int)); 5790792Sgshapirostatic void map_init __P((STAB *, int)); 5864562Sgshapiro#ifdef LDAPMAP 5990792Sgshapirostatic STAB * ldapmap_findconn __P((SM_LDAP_STRUCT *)); 6064562Sgshapiro#endif /* LDAPMAP */ 6190792Sgshapiro#if NISPLUS 6264562Sgshapirostatic bool nisplus_getcanonname __P((char *, int, int *)); 6364562Sgshapiro#endif /* NISPLUS */ 6490792Sgshapiro#if NIS 6564562Sgshapirostatic bool nis_getcanonname __P((char *, int, int *)); 6664562Sgshapiro#endif /* NIS */ 6764562Sgshapiro#if NETINFO 6864562Sgshapirostatic bool ni_getcanonname __P((char *, int, int *)); 6964562Sgshapiro#endif /* NETINFO */ 7064562Sgshapirostatic bool text_getcanonname __P((char *, int, int *)); 71132943Sgshapiro#if SOCKETMAP 72132943Sgshapirostatic STAB *socket_map_findconn __P((const char*)); 7364562Sgshapiro 74132943Sgshapiro/* XXX arbitrary limit for sanity */ 75132943Sgshapiro# define SOCKETMAP_MAXL 1000000 76132943Sgshapiro#endif /* SOCKETMAP */ 77132943Sgshapiro 7890792Sgshapiro/* default error message for trying to open a map in write mode */ 7990792Sgshapiro#ifdef ENOSYS 8090792Sgshapiro# define SM_EMAPCANTWRITE ENOSYS 8190792Sgshapiro#else /* ENOSYS */ 8290792Sgshapiro# ifdef EFTYPE 8390792Sgshapiro# define SM_EMAPCANTWRITE EFTYPE 8490792Sgshapiro# else /* EFTYPE */ 8590792Sgshapiro# define SM_EMAPCANTWRITE ENXIO 8690792Sgshapiro# endif /* EFTYPE */ 8790792Sgshapiro#endif /* ENOSYS */ 8890792Sgshapiro 8938032Speter/* 9038032Speter** MAP.C -- implementations for various map classes. 9138032Speter** 9238032Speter** Each map class implements a series of functions: 9338032Speter** 9438032Speter** bool map_parse(MAP *map, char *args) 9590792Sgshapiro** Parse the arguments from the config file. Return true 9690792Sgshapiro** if they were ok, false otherwise. Fill in map with the 9738032Speter** values. 9838032Speter** 9938032Speter** char *map_lookup(MAP *map, char *key, char **args, int *pstat) 10038032Speter** Look up the key in the given map. If found, do any 10138032Speter** rewriting the map wants (including "args" if desired) 10238032Speter** and return the value. Set *pstat to the appropriate status 10338032Speter** on error and return NULL. Args will be NULL if called 10438032Speter** from the alias routines, although this should probably 10538032Speter** not be relied upon. It is suggested you call map_rewrite 10638032Speter** to return the results -- it takes care of null termination 10738032Speter** and uses a dynamically expanded buffer as needed. 10838032Speter** 10938032Speter** void map_store(MAP *map, char *key, char *value) 11038032Speter** Store the key:value pair in the map. 11138032Speter** 11238032Speter** bool map_open(MAP *map, int mode) 11338032Speter** Open the map for the indicated mode. Mode should 11490792Sgshapiro** be either O_RDONLY or O_RDWR. Return true if it 11590792Sgshapiro** was opened successfully, false otherwise. If the open 11690792Sgshapiro** failed and the MF_OPTIONAL flag is not set, it should 11738032Speter** also print an error. If the MF_ALIAS bit is set 11838032Speter** and this map class understands the @:@ convention, it 11938032Speter** should call aliaswait() before returning. 12038032Speter** 12138032Speter** void map_close(MAP *map) 12238032Speter** Close the map. 12338032Speter** 12438032Speter** This file also includes the implementation for getcanonname. 12538032Speter** It is currently implemented in a pretty ad-hoc manner; it ought 12638032Speter** to be more properly integrated into the map structure. 12738032Speter*/ 12838032Speter 12938032Speter#if O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL 13038032Speter# define LOCK_ON_OPEN 1 /* we can open/create a locked file */ 13164562Sgshapiro#else /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */ 13238032Speter# define LOCK_ON_OPEN 0 /* no such luck -- bend over backwards */ 13364562Sgshapiro#endif /* O_EXLOCK && HASFLOCK && !BOGUS_O_EXCL */ 13438032Speter 13590792Sgshapiro/* 13638032Speter** MAP_PARSEARGS -- parse config line arguments for database lookup 13738032Speter** 13838032Speter** This is a generic version of the map_parse method. 13938032Speter** 14038032Speter** Parameters: 14138032Speter** map -- the map being initialized. 14238032Speter** ap -- a pointer to the args on the config line. 14338032Speter** 14438032Speter** Returns: 14590792Sgshapiro** true -- if everything parsed OK. 14690792Sgshapiro** false -- otherwise. 14738032Speter** 14838032Speter** Side Effects: 14938032Speter** null terminates the filename; stores it in map 15038032Speter*/ 15138032Speter 15238032Speterbool 15338032Spetermap_parseargs(map, ap) 15438032Speter MAP *map; 15538032Speter char *ap; 15638032Speter{ 15738032Speter register char *p = ap; 15838032Speter 15964562Sgshapiro /* 16090792Sgshapiro ** There is no check whether there is really an argument, 16190792Sgshapiro ** but that's not important enough to warrant extra code. 16264562Sgshapiro */ 16390792Sgshapiro 16490792Sgshapiro map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL; 16564562Sgshapiro map->map_spacesub = SpaceSub; /* default value */ 16638032Speter for (;;) 16738032Speter { 16838032Speter while (isascii(*p) && isspace(*p)) 16938032Speter p++; 17038032Speter if (*p != '-') 17138032Speter break; 17238032Speter switch (*++p) 17338032Speter { 17438032Speter case 'N': 17538032Speter map->map_mflags |= MF_INCLNULL; 17638032Speter map->map_mflags &= ~MF_TRY0NULL; 17738032Speter break; 17838032Speter 17938032Speter case 'O': 18038032Speter map->map_mflags &= ~MF_TRY1NULL; 18138032Speter break; 18238032Speter 18338032Speter case 'o': 18438032Speter map->map_mflags |= MF_OPTIONAL; 18538032Speter break; 18638032Speter 18738032Speter case 'f': 18838032Speter map->map_mflags |= MF_NOFOLDCASE; 18938032Speter break; 19038032Speter 19138032Speter case 'm': 19238032Speter map->map_mflags |= MF_MATCHONLY; 19338032Speter break; 19438032Speter 19538032Speter case 'A': 19638032Speter map->map_mflags |= MF_APPEND; 19738032Speter break; 19838032Speter 19938032Speter case 'q': 20038032Speter map->map_mflags |= MF_KEEPQUOTES; 20138032Speter break; 20238032Speter 20338032Speter case 'a': 20438032Speter map->map_app = ++p; 20538032Speter break; 20638032Speter 207285303Sgshapiro case 'd': 208285303Sgshapiro { 209285303Sgshapiro char *h; 210285303Sgshapiro 211285303Sgshapiro ++p; 212285303Sgshapiro h = strchr(p, ' '); 213285303Sgshapiro if (h != NULL) 214285303Sgshapiro *h = '\0'; 215285303Sgshapiro map->map_timeout = convtime(p, 's'); 216285303Sgshapiro if (h != NULL) 217285303Sgshapiro *h = ' '; 218285303Sgshapiro } 219285303Sgshapiro break; 220285303Sgshapiro 22138032Speter case 'T': 22238032Speter map->map_tapp = ++p; 22338032Speter break; 22438032Speter 22538032Speter case 'k': 22638032Speter while (isascii(*++p) && isspace(*p)) 22738032Speter continue; 22838032Speter map->map_keycolnm = p; 22938032Speter break; 23038032Speter 23138032Speter case 'v': 23238032Speter while (isascii(*++p) && isspace(*p)) 23338032Speter continue; 23438032Speter map->map_valcolnm = p; 23538032Speter break; 23638032Speter 23738032Speter case 'z': 23838032Speter if (*++p != '\\') 23938032Speter map->map_coldelim = *p; 24038032Speter else 24138032Speter { 24238032Speter switch (*++p) 24338032Speter { 24438032Speter case 'n': 24538032Speter map->map_coldelim = '\n'; 24638032Speter break; 24738032Speter 24838032Speter case 't': 24938032Speter map->map_coldelim = '\t'; 25038032Speter break; 25138032Speter 25238032Speter default: 25338032Speter map->map_coldelim = '\\'; 25438032Speter } 25538032Speter } 25638032Speter break; 25738032Speter 25838032Speter case 't': 25938032Speter map->map_mflags |= MF_NODEFER; 26038032Speter break; 26138032Speter 26264562Sgshapiro 26364562Sgshapiro case 'S': 26464562Sgshapiro map->map_spacesub = *++p; 26538032Speter break; 26638032Speter 26764562Sgshapiro case 'D': 26864562Sgshapiro map->map_mflags |= MF_DEFER; 26938032Speter break; 27064562Sgshapiro 27164562Sgshapiro default: 27264562Sgshapiro syserr("Illegal option %c map %s", *p, map->map_mname); 27364562Sgshapiro break; 27438032Speter } 27538032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 27638032Speter p++; 27738032Speter if (*p != '\0') 27838032Speter *p++ = '\0'; 27938032Speter } 28038032Speter if (map->map_app != NULL) 28138032Speter map->map_app = newstr(map->map_app); 28238032Speter if (map->map_tapp != NULL) 28338032Speter map->map_tapp = newstr(map->map_tapp); 28438032Speter if (map->map_keycolnm != NULL) 28538032Speter map->map_keycolnm = newstr(map->map_keycolnm); 28638032Speter if (map->map_valcolnm != NULL) 28738032Speter map->map_valcolnm = newstr(map->map_valcolnm); 28838032Speter 28938032Speter if (*p != '\0') 29038032Speter { 29138032Speter map->map_file = p; 29238032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 29338032Speter p++; 29438032Speter if (*p != '\0') 29538032Speter *p++ = '\0'; 29638032Speter map->map_file = newstr(map->map_file); 29738032Speter } 29838032Speter 29938032Speter while (*p != '\0' && isascii(*p) && isspace(*p)) 30038032Speter p++; 30138032Speter if (*p != '\0') 30238032Speter map->map_rebuild = newstr(p); 30338032Speter 30438032Speter if (map->map_file == NULL && 30538032Speter !bitset(MCF_OPTFILE, map->map_class->map_cflags)) 30638032Speter { 30738032Speter syserr("No file name for %s map %s", 30838032Speter map->map_class->map_cname, map->map_mname); 30990792Sgshapiro return false; 31038032Speter } 31190792Sgshapiro return true; 31238032Speter} 31390792Sgshapiro/* 31438032Speter** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 31538032Speter** 31638032Speter** It also adds the map_app string. It can be used as a utility 31738032Speter** in the map_lookup method. 31838032Speter** 31938032Speter** Parameters: 32038032Speter** map -- the map that causes this. 32138032Speter** s -- the string to rewrite, NOT necessarily null terminated. 32238032Speter** slen -- the length of s. 32338032Speter** av -- arguments to interpolate into buf. 32438032Speter** 32538032Speter** Returns: 32638032Speter** Pointer to rewritten result. This is static data that 32738032Speter** should be copied if it is to be saved! 32838032Speter*/ 32938032Speter 33038032Speterchar * 33138032Spetermap_rewrite(map, s, slen, av) 33238032Speter register MAP *map; 33338032Speter register const char *s; 33438032Speter size_t slen; 33538032Speter char **av; 33638032Speter{ 33738032Speter register char *bp; 33838032Speter register char c; 33938032Speter char **avp; 34038032Speter register char *ap; 34138032Speter size_t l; 34238032Speter size_t len; 34338032Speter static size_t buflen = 0; 34438032Speter static char *buf = NULL; 34538032Speter 34638032Speter if (tTd(39, 1)) 34738032Speter { 34890792Sgshapiro sm_dprintf("map_rewrite(%.*s), av =", (int) slen, s); 34938032Speter if (av == NULL) 35090792Sgshapiro sm_dprintf(" (nullv)"); 35138032Speter else 35238032Speter { 35338032Speter for (avp = av; *avp != NULL; avp++) 35490792Sgshapiro sm_dprintf("\n\t%s", *avp); 35538032Speter } 35690792Sgshapiro sm_dprintf("\n"); 35738032Speter } 35838032Speter 35938032Speter /* count expected size of output (can safely overestimate) */ 36038032Speter l = len = slen; 36138032Speter if (av != NULL) 36238032Speter { 36338032Speter const char *sp = s; 36438032Speter 36538032Speter while (l-- > 0 && (c = *sp++) != '\0') 36638032Speter { 36738032Speter if (c != '%') 36838032Speter continue; 36938032Speter if (l-- <= 0) 37038032Speter break; 37138032Speter c = *sp++; 37238032Speter if (!(isascii(c) && isdigit(c))) 37338032Speter continue; 37438032Speter for (avp = av; --c >= '0' && *avp != NULL; avp++) 37538032Speter continue; 37638032Speter if (*avp == NULL) 37738032Speter continue; 37838032Speter len += strlen(*avp); 37938032Speter } 38038032Speter } 38138032Speter if (map->map_app != NULL) 38238032Speter len += strlen(map->map_app); 38338032Speter if (buflen < ++len) 38438032Speter { 38538032Speter /* need to malloc additional space */ 38638032Speter buflen = len; 38738032Speter if (buf != NULL) 38877349Sgshapiro sm_free(buf); 38990792Sgshapiro buf = sm_pmalloc_x(buflen); 39038032Speter } 39138032Speter 39238032Speter bp = buf; 39338032Speter if (av == NULL) 39438032Speter { 39564562Sgshapiro memmove(bp, s, slen); 39638032Speter bp += slen; 39764562Sgshapiro 39864562Sgshapiro /* assert(len > slen); */ 39964562Sgshapiro len -= slen; 40038032Speter } 40138032Speter else 40238032Speter { 40338032Speter while (slen-- > 0 && (c = *s++) != '\0') 40438032Speter { 40538032Speter if (c != '%') 40638032Speter { 40738032Speter pushc: 408120256Sgshapiro if (len-- <= 1) 40990792Sgshapiro break; 41038032Speter *bp++ = c; 41138032Speter continue; 41238032Speter } 41338032Speter if (slen-- <= 0 || (c = *s++) == '\0') 41438032Speter c = '%'; 41538032Speter if (c == '%') 41638032Speter goto pushc; 41738032Speter if (!(isascii(c) && isdigit(c))) 41838032Speter { 419120256Sgshapiro if (len-- <= 1) 420120256Sgshapiro break; 42138032Speter *bp++ = '%'; 42238032Speter goto pushc; 42338032Speter } 42438032Speter for (avp = av; --c >= '0' && *avp != NULL; avp++) 42538032Speter continue; 42638032Speter if (*avp == NULL) 42738032Speter continue; 42838032Speter 42938032Speter /* transliterate argument into output string */ 43064562Sgshapiro for (ap = *avp; (c = *ap++) != '\0' && len > 0; --len) 43138032Speter *bp++ = c; 43238032Speter } 43338032Speter } 43464562Sgshapiro if (map->map_app != NULL && len > 0) 43590792Sgshapiro (void) sm_strlcpy(bp, map->map_app, len); 43638032Speter else 43738032Speter *bp = '\0'; 43838032Speter if (tTd(39, 1)) 43990792Sgshapiro sm_dprintf("map_rewrite => %s\n", buf); 44038032Speter return buf; 44138032Speter} 44290792Sgshapiro/* 44364562Sgshapiro** INITMAPS -- rebuild alias maps 44438032Speter** 44538032Speter** Parameters: 44664562Sgshapiro** none. 44738032Speter** 44838032Speter** Returns: 44938032Speter** none. 45038032Speter*/ 45138032Speter 45238032Spetervoid 45364562Sgshapiroinitmaps() 45438032Speter{ 45538032Speter#if XDEBUG 45638032Speter checkfd012("entering initmaps"); 45764562Sgshapiro#endif /* XDEBUG */ 45838032Speter stabapply(map_init, 0); 45938032Speter#if XDEBUG 46038032Speter checkfd012("exiting initmaps"); 46164562Sgshapiro#endif /* XDEBUG */ 46238032Speter} 46390792Sgshapiro/* 46464562Sgshapiro** MAP_INIT -- rebuild a map 46564562Sgshapiro** 46664562Sgshapiro** Parameters: 46764562Sgshapiro** s -- STAB entry: if map: try to rebuild 46864562Sgshapiro** unused -- unused variable 46964562Sgshapiro** 47064562Sgshapiro** Returns: 47164562Sgshapiro** none. 47264562Sgshapiro** 47364562Sgshapiro** Side Effects: 47464562Sgshapiro** will close already open rebuildable map. 47564562Sgshapiro*/ 47638032Speter 47764562Sgshapiro/* ARGSUSED1 */ 47864562Sgshapirostatic void 47964562Sgshapiromap_init(s, unused) 48038032Speter register STAB *s; 48164562Sgshapiro int unused; 48238032Speter{ 48338032Speter register MAP *map; 48438032Speter 48538032Speter /* has to be a map */ 48690792Sgshapiro if (s->s_symtype != ST_MAP) 48738032Speter return; 48838032Speter 48938032Speter map = &s->s_map; 49038032Speter if (!bitset(MF_VALID, map->map_mflags)) 49138032Speter return; 49238032Speter 49338032Speter if (tTd(38, 2)) 49490792Sgshapiro sm_dprintf("map_init(%s:%s, %s)\n", 49538032Speter map->map_class->map_cname == NULL ? "NULL" : 49638032Speter map->map_class->map_cname, 49738032Speter map->map_mname == NULL ? "NULL" : map->map_mname, 49864562Sgshapiro map->map_file == NULL ? "NULL" : map->map_file); 49938032Speter 50064562Sgshapiro if (!bitset(MF_ALIAS, map->map_mflags) || 50164562Sgshapiro !bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 50238032Speter { 50338032Speter if (tTd(38, 3)) 50490792Sgshapiro sm_dprintf("\tnot rebuildable\n"); 50538032Speter return; 50638032Speter } 50738032Speter 50838032Speter /* if already open, close it (for nested open) */ 50938032Speter if (bitset(MF_OPEN, map->map_mflags)) 51038032Speter { 51177349Sgshapiro map->map_mflags |= MF_CLOSING; 51238032Speter map->map_class->map_close(map); 51377349Sgshapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 51438032Speter } 51538032Speter 51690792Sgshapiro (void) rebuildaliases(map, false); 51764562Sgshapiro return; 51864562Sgshapiro} 51990792Sgshapiro/* 52064562Sgshapiro** OPENMAP -- open a map 52164562Sgshapiro** 52264562Sgshapiro** Parameters: 52364562Sgshapiro** map -- map to open (it must not be open). 52464562Sgshapiro** 52564562Sgshapiro** Returns: 52664562Sgshapiro** whether open succeeded. 52764562Sgshapiro*/ 52864562Sgshapiro 52964562Sgshapirobool 53064562Sgshapiroopenmap(map) 53164562Sgshapiro MAP *map; 53264562Sgshapiro{ 53390792Sgshapiro bool restore = false; 53464562Sgshapiro bool savehold = HoldErrs; 53564562Sgshapiro bool savequick = QuickAbort; 53664562Sgshapiro int saveerrors = Errors; 53764562Sgshapiro 53864562Sgshapiro if (!bitset(MF_VALID, map->map_mflags)) 53990792Sgshapiro return false; 54064562Sgshapiro 54164562Sgshapiro /* better safe than sorry... */ 54264562Sgshapiro if (bitset(MF_OPEN, map->map_mflags)) 54390792Sgshapiro return true; 54464562Sgshapiro 54564562Sgshapiro /* Don't send a map open error out via SMTP */ 54664562Sgshapiro if ((OnlyOneError || QuickAbort) && 54764562Sgshapiro (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 54838032Speter { 54990792Sgshapiro restore = true; 55090792Sgshapiro HoldErrs = true; 55190792Sgshapiro QuickAbort = false; 55238032Speter } 55338032Speter 55464562Sgshapiro errno = 0; 55538032Speter if (map->map_class->map_open(map, O_RDONLY)) 55638032Speter { 55738032Speter if (tTd(38, 4)) 55890792Sgshapiro sm_dprintf("openmap()\t%s:%s %s: valid\n", 55938032Speter map->map_class->map_cname == NULL ? "NULL" : 56038032Speter map->map_class->map_cname, 56138032Speter map->map_mname == NULL ? "NULL" : 56238032Speter map->map_mname, 56338032Speter map->map_file == NULL ? "NULL" : 56438032Speter map->map_file); 56538032Speter map->map_mflags |= MF_OPEN; 56690792Sgshapiro map->map_pid = CurrentPid; 56738032Speter } 56838032Speter else 56938032Speter { 57038032Speter if (tTd(38, 4)) 57190792Sgshapiro sm_dprintf("openmap()\t%s:%s %s: invalid%s%s\n", 57238032Speter map->map_class->map_cname == NULL ? "NULL" : 57338032Speter map->map_class->map_cname, 57438032Speter map->map_mname == NULL ? "NULL" : 57538032Speter map->map_mname, 57638032Speter map->map_file == NULL ? "NULL" : 57738032Speter map->map_file, 57864562Sgshapiro errno == 0 ? "" : ": ", 57990792Sgshapiro errno == 0 ? "" : sm_errstring(errno)); 58038032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 58138032Speter { 58238032Speter extern MAPCLASS BogusMapClass; 58338032Speter 58490792Sgshapiro map->map_orgclass = map->map_class; 58538032Speter map->map_class = &BogusMapClass; 58690792Sgshapiro map->map_mflags |= MF_OPEN|MF_OPENBOGUS; 58790792Sgshapiro map->map_pid = CurrentPid; 58838032Speter } 58964562Sgshapiro else 59064562Sgshapiro { 59164562Sgshapiro /* don't try again */ 59264562Sgshapiro map->map_mflags &= ~MF_VALID; 59364562Sgshapiro } 59438032Speter } 59564562Sgshapiro 59664562Sgshapiro if (restore) 59764562Sgshapiro { 59864562Sgshapiro Errors = saveerrors; 59964562Sgshapiro HoldErrs = savehold; 60064562Sgshapiro QuickAbort = savequick; 60164562Sgshapiro } 60264562Sgshapiro 60364562Sgshapiro return bitset(MF_OPEN, map->map_mflags); 60438032Speter} 60590792Sgshapiro/* 60642575Speter** CLOSEMAPS -- close all open maps opened by the current pid. 60742575Speter** 60842575Speter** Parameters: 60990792Sgshapiro** bogus -- only close bogus maps. 61042575Speter** 61142575Speter** Returns: 61242575Speter** none. 61342575Speter*/ 61442575Speter 61542575Spetervoid 61690792Sgshapiroclosemaps(bogus) 61790792Sgshapiro bool bogus; 61842575Speter{ 61990792Sgshapiro stabapply(map_close, bogus); 62042575Speter} 62190792Sgshapiro/* 62264562Sgshapiro** MAP_CLOSE -- close a map opened by the current pid. 62364562Sgshapiro** 62464562Sgshapiro** Parameters: 62590792Sgshapiro** s -- STAB entry: if map: try to close 62690792Sgshapiro** bogus -- only close bogus maps or MCF_NOTPERSIST maps. 62764562Sgshapiro** 62864562Sgshapiro** Returns: 62964562Sgshapiro** none. 63064562Sgshapiro*/ 63142575Speter 63242575Speter/* ARGSUSED1 */ 63364562Sgshapirostatic void 63490792Sgshapiromap_close(s, bogus) 63542575Speter register STAB *s; 63690792Sgshapiro int bogus; /* int because of stabapply(), used as bool */ 63742575Speter{ 63842575Speter MAP *map; 63990792Sgshapiro extern MAPCLASS BogusMapClass; 64042575Speter 64190792Sgshapiro if (s->s_symtype != ST_MAP) 64242575Speter return; 64364562Sgshapiro 64442575Speter map = &s->s_map; 64542575Speter 64690792Sgshapiro /* 64790792Sgshapiro ** close the map iff: 64890792Sgshapiro ** it is valid and open and opened by this process 64990792Sgshapiro ** and (!bogus or it's a bogus map or it is not persistent) 65090792Sgshapiro ** negate this: return iff 65190792Sgshapiro ** it is not valid or it is not open or not opened by this process 65290792Sgshapiro ** or (bogus and it's not a bogus map and it's not not-persistent) 65390792Sgshapiro */ 65490792Sgshapiro 65542575Speter if (!bitset(MF_VALID, map->map_mflags) || 65642575Speter !bitset(MF_OPEN, map->map_mflags) || 65777349Sgshapiro bitset(MF_CLOSING, map->map_mflags) || 65890792Sgshapiro map->map_pid != CurrentPid || 65990792Sgshapiro (bogus && map->map_class != &BogusMapClass && 66090792Sgshapiro !bitset(MCF_NOTPERSIST, map->map_class->map_cflags))) 66142575Speter return; 66264562Sgshapiro 66390792Sgshapiro if (map->map_class == &BogusMapClass && map->map_orgclass != NULL && 66490792Sgshapiro map->map_orgclass != &BogusMapClass) 66590792Sgshapiro map->map_class = map->map_orgclass; 66642575Speter if (tTd(38, 5)) 66790792Sgshapiro sm_dprintf("closemaps: closing %s (%s)\n", 66864562Sgshapiro map->map_mname == NULL ? "NULL" : map->map_mname, 66964562Sgshapiro map->map_file == NULL ? "NULL" : map->map_file); 67064562Sgshapiro 67190792Sgshapiro if (!bitset(MF_OPENBOGUS, map->map_mflags)) 67290792Sgshapiro { 67390792Sgshapiro map->map_mflags |= MF_CLOSING; 67490792Sgshapiro map->map_class->map_close(map); 67590792Sgshapiro } 67690792Sgshapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_OPENBOGUS|MF_CLOSING); 67742575Speter} 678168515Sgshapiro 679168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) 680168515Sgshapiroextern int getdomainname(); 681168515Sgshapiro 682168515Sgshapiro/* this is mainly for backward compatibility in Sun environment */ 683168515Sgshapirostatic char * 684168515Sgshapirosun_init_domain() 685168515Sgshapiro{ 686168515Sgshapiro /* 687168515Sgshapiro ** Get the domain name from the kernel. 688168515Sgshapiro ** If it does not start with a leading dot, then remove 689168515Sgshapiro ** the first component. Since leading dots are funny Unix 690168515Sgshapiro ** files, we treat a leading "+" the same as a leading dot. 691168515Sgshapiro ** Finally, force there to be at least one dot in the domain name 692168515Sgshapiro ** (i.e. top-level domains are not allowed, like "com", must be 693168515Sgshapiro ** something like "sun.com"). 694168515Sgshapiro */ 695168515Sgshapiro 696168515Sgshapiro char buf[MAXNAME]; 697168515Sgshapiro char *period, *autodomain; 698168515Sgshapiro 699168515Sgshapiro if (getdomainname(buf, sizeof buf) < 0) 700168515Sgshapiro return NULL; 701168515Sgshapiro 702168515Sgshapiro if (buf[0] == '\0') 703168515Sgshapiro return NULL; 704168515Sgshapiro 705168515Sgshapiro if (tTd(0, 20)) 706168515Sgshapiro printf("domainname = %s\n", buf); 707168515Sgshapiro 708168515Sgshapiro if (buf[0] == '+') 709168515Sgshapiro buf[0] = '.'; 710168515Sgshapiro period = strchr(buf, '.'); 711168515Sgshapiro if (period == NULL) 712168515Sgshapiro autodomain = buf; 713168515Sgshapiro else 714168515Sgshapiro autodomain = period + 1; 715168515Sgshapiro if (strchr(autodomain, '.') == NULL) 716168515Sgshapiro return newstr(buf); 717168515Sgshapiro else 718168515Sgshapiro return newstr(autodomain); 719168515Sgshapiro} 720168515Sgshapiro#endif /* SUN_EXTENSIONS && SUN_INIT_DOMAIN */ 721168515Sgshapiro 72290792Sgshapiro/* 72338032Speter** GETCANONNAME -- look up name using service switch 72438032Speter** 72538032Speter** Parameters: 72638032Speter** host -- the host name to look up. 72738032Speter** hbsize -- the size of the host buffer. 72838032Speter** trymx -- if set, try MX records. 72990792Sgshapiro** pttl -- pointer to return TTL (can be NULL). 73038032Speter** 73138032Speter** Returns: 73290792Sgshapiro** true -- if the host was found. 73390792Sgshapiro** false -- otherwise. 73438032Speter*/ 73538032Speter 73638032Speterbool 73790792Sgshapirogetcanonname(host, hbsize, trymx, pttl) 73838032Speter char *host; 73938032Speter int hbsize; 74038032Speter bool trymx; 74190792Sgshapiro int *pttl; 74238032Speter{ 74338032Speter int nmaps; 74438032Speter int mapno; 74590792Sgshapiro bool found = false; 74690792Sgshapiro bool got_tempfail = false; 747203004Sgshapiro auto int status = EX_UNAVAILABLE; 74838032Speter char *maptype[MAXMAPSTACK]; 74938032Speter short mapreturn[MAXMAPACTIONS]; 750168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) 751168515Sgshapiro bool should_try_nis_domain = false; 752168515Sgshapiro static char *nis_domain = NULL; 753168515Sgshapiro#endif 75438032Speter 75538032Speter nmaps = switch_map_find("hosts", maptype, mapreturn); 75690792Sgshapiro if (pttl != 0) 75790792Sgshapiro *pttl = SM_DEFAULT_TTL; 75838032Speter for (mapno = 0; mapno < nmaps; mapno++) 75938032Speter { 76038032Speter int i; 76138032Speter 76238032Speter if (tTd(38, 20)) 76390792Sgshapiro sm_dprintf("getcanonname(%s), trying %s\n", 76438032Speter host, maptype[mapno]); 76538032Speter if (strcmp("files", maptype[mapno]) == 0) 76638032Speter { 76764562Sgshapiro found = text_getcanonname(host, hbsize, &status); 76838032Speter } 76990792Sgshapiro#if NIS 77038032Speter else if (strcmp("nis", maptype[mapno]) == 0) 77138032Speter { 77264562Sgshapiro found = nis_getcanonname(host, hbsize, &status); 773168515Sgshapiro# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) 774168515Sgshapiro if (nis_domain == NULL) 775168515Sgshapiro nis_domain = sun_init_domain(); 776168515Sgshapiro# endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */ 77738032Speter } 77864562Sgshapiro#endif /* NIS */ 77990792Sgshapiro#if NISPLUS 78038032Speter else if (strcmp("nisplus", maptype[mapno]) == 0) 78138032Speter { 78264562Sgshapiro found = nisplus_getcanonname(host, hbsize, &status); 783168515Sgshapiro# if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) 784168515Sgshapiro if (nis_domain == NULL) 785168515Sgshapiro nis_domain = sun_init_domain(); 786168515Sgshapiro# endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */ 78738032Speter } 78864562Sgshapiro#endif /* NISPLUS */ 78938032Speter#if NAMED_BIND 79038032Speter else if (strcmp("dns", maptype[mapno]) == 0) 79138032Speter { 79290792Sgshapiro found = dns_getcanonname(host, hbsize, trymx, &status, pttl); 79338032Speter } 79464562Sgshapiro#endif /* NAMED_BIND */ 79538032Speter#if NETINFO 79638032Speter else if (strcmp("netinfo", maptype[mapno]) == 0) 79738032Speter { 79864562Sgshapiro found = ni_getcanonname(host, hbsize, &status); 79938032Speter } 80064562Sgshapiro#endif /* NETINFO */ 80138032Speter else 80238032Speter { 80390792Sgshapiro found = false; 80464562Sgshapiro status = EX_UNAVAILABLE; 80538032Speter } 80638032Speter 80738032Speter /* 80838032Speter ** Heuristic: if $m is not set, we are running during system 80938032Speter ** startup. In this case, when a name is apparently found 81038032Speter ** but has no dot, treat is as not found. This avoids 81138032Speter ** problems if /etc/hosts has no FQDN but is listed first 81238032Speter ** in the service switch. 81338032Speter */ 81438032Speter 81538032Speter if (found && 81638032Speter (macvalue('m', CurEnv) != NULL || strchr(host, '.') != NULL)) 81738032Speter break; 81838032Speter 819168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) 820168515Sgshapiro if (found) 821168515Sgshapiro should_try_nis_domain = true; 822168515Sgshapiro /* but don't break, as we need to try all methods first */ 823168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */ 824168515Sgshapiro 82538032Speter /* see if we should continue */ 82664562Sgshapiro if (status == EX_TEMPFAIL) 82738032Speter { 82838032Speter i = MA_TRYAGAIN; 82990792Sgshapiro got_tempfail = true; 83038032Speter } 83164562Sgshapiro else if (status == EX_NOTFOUND) 83238032Speter i = MA_NOTFOUND; 83338032Speter else 83438032Speter i = MA_UNAVAIL; 83538032Speter if (bitset(1 << mapno, mapreturn[i])) 83638032Speter break; 83738032Speter } 83838032Speter 83938032Speter if (found) 84038032Speter { 84138032Speter char *d; 84238032Speter 84338032Speter if (tTd(38, 20)) 84490792Sgshapiro sm_dprintf("getcanonname(%s), found\n", host); 84538032Speter 84638032Speter /* 84738032Speter ** If returned name is still single token, compensate 84838032Speter ** by tagging on $m. This is because some sites set 84938032Speter ** up their DNS or NIS databases wrong. 85038032Speter */ 85138032Speter 85238032Speter if ((d = strchr(host, '.')) == NULL || d[1] == '\0') 85338032Speter { 85438032Speter d = macvalue('m', CurEnv); 85538032Speter if (d != NULL && 85638032Speter hbsize > (int) (strlen(host) + strlen(d) + 1)) 85738032Speter { 85838032Speter if (host[strlen(host) - 1] != '.') 85990792Sgshapiro (void) sm_strlcat2(host, ".", d, 86090792Sgshapiro hbsize); 86190792Sgshapiro else 86290792Sgshapiro (void) sm_strlcat(host, d, hbsize); 86338032Speter } 86438032Speter else 865168515Sgshapiro { 866168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) 867168515Sgshapiro if (VendorCode == VENDOR_SUN && 868168515Sgshapiro should_try_nis_domain) 869168515Sgshapiro { 870168515Sgshapiro goto try_nis_domain; 871168515Sgshapiro } 872168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */ 87390792Sgshapiro return false; 874168515Sgshapiro } 87538032Speter } 87690792Sgshapiro return true; 87738032Speter } 87838032Speter 879168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) 880168515Sgshapiro if (VendorCode == VENDOR_SUN && should_try_nis_domain) 881168515Sgshapiro { 882168515Sgshapiro try_nis_domain: 883168515Sgshapiro if (nis_domain != NULL && 884168515Sgshapiro strlen(nis_domain) + strlen(host) + 1 < hbsize) 885168515Sgshapiro { 886168515Sgshapiro (void) sm_strlcat2(host, ".", nis_domain, hbsize); 887168515Sgshapiro return true; 888168515Sgshapiro } 889168515Sgshapiro } 890168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_INIT_DOMAIN) */ 891168515Sgshapiro 89238032Speter if (tTd(38, 20)) 89390792Sgshapiro sm_dprintf("getcanonname(%s), failed, status=%d\n", host, 89490792Sgshapiro status); 89538032Speter 89638032Speter if (got_tempfail) 89773188Sgshapiro SM_SET_H_ERRNO(TRY_AGAIN); 89838032Speter else 89973188Sgshapiro SM_SET_H_ERRNO(HOST_NOT_FOUND); 90090792Sgshapiro 90190792Sgshapiro return false; 90238032Speter} 90390792Sgshapiro/* 90438032Speter** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry 90538032Speter** 90638032Speter** Parameters: 90738032Speter** name -- the name against which to match. 90873188Sgshapiro** dot -- where to reinsert '.' to get FQDN 90938032Speter** line -- the /etc/hosts line. 91038032Speter** cbuf -- the location to store the result. 91138032Speter** cbuflen -- the size of cbuf. 91238032Speter** 91338032Speter** Returns: 91490792Sgshapiro** true -- if the line matched the desired name. 91590792Sgshapiro** false -- otherwise. 91638032Speter*/ 91738032Speter 91864562Sgshapirostatic bool 91973188Sgshapiroextract_canonname(name, dot, line, cbuf, cbuflen) 92038032Speter char *name; 92173188Sgshapiro char *dot; 92238032Speter char *line; 92338032Speter char cbuf[]; 92438032Speter int cbuflen; 92538032Speter{ 92638032Speter int i; 92738032Speter char *p; 92890792Sgshapiro bool found = false; 92938032Speter 93038032Speter cbuf[0] = '\0'; 93138032Speter if (line[0] == '#') 93290792Sgshapiro return false; 93338032Speter 93438032Speter for (i = 1; ; i++) 93538032Speter { 93638032Speter char nbuf[MAXNAME + 1]; 93738032Speter 938168515Sgshapiro p = get_column(line, i, '\0', nbuf, sizeof(nbuf)); 93938032Speter if (p == NULL) 94038032Speter break; 94138032Speter if (*p == '\0') 94238032Speter continue; 94338032Speter if (cbuf[0] == '\0' || 94438032Speter (strchr(cbuf, '.') == NULL && strchr(p, '.') != NULL)) 94538032Speter { 94690792Sgshapiro (void) sm_strlcpy(cbuf, p, cbuflen); 94738032Speter } 94890792Sgshapiro if (sm_strcasecmp(name, p) == 0) 94990792Sgshapiro found = true; 95073188Sgshapiro else if (dot != NULL) 95173188Sgshapiro { 95273188Sgshapiro /* try looking for the FQDN as well */ 95373188Sgshapiro *dot = '.'; 95490792Sgshapiro if (sm_strcasecmp(name, p) == 0) 95590792Sgshapiro found = true; 95673188Sgshapiro *dot = '\0'; 95773188Sgshapiro } 95838032Speter } 95938032Speter if (found && strchr(cbuf, '.') == NULL) 96038032Speter { 96138032Speter /* try to add a domain on the end of the name */ 96238032Speter char *domain = macvalue('m', CurEnv); 96338032Speter 96438032Speter if (domain != NULL && 96564562Sgshapiro strlen(domain) + (i = strlen(cbuf)) + 1 < (size_t) cbuflen) 96638032Speter { 96764562Sgshapiro p = &cbuf[i]; 96838032Speter *p++ = '.'; 96990792Sgshapiro (void) sm_strlcpy(p, domain, cbuflen - i - 1); 97038032Speter } 97138032Speter } 97238032Speter return found; 97338032Speter} 97490792Sgshapiro 97590792Sgshapiro/* 97690792Sgshapiro** DNS modules 97790792Sgshapiro*/ 97890792Sgshapiro 97990792Sgshapiro#if NAMED_BIND 98090792Sgshapiro# if DNSMAP 98190792Sgshapiro 98290792Sgshapiro# include "sm_resolve.h" 98390792Sgshapiro# if NETINET || NETINET6 98490792Sgshapiro# include <arpa/inet.h> 98590792Sgshapiro# endif /* NETINET || NETINET6 */ 98690792Sgshapiro 98790792Sgshapiro/* 98890792Sgshapiro** DNS_MAP_OPEN -- stub to check proper value for dns map type 98990792Sgshapiro*/ 99090792Sgshapiro 99190792Sgshapirobool 99290792Sgshapirodns_map_open(map, mode) 99390792Sgshapiro MAP *map; 99490792Sgshapiro int mode; 99590792Sgshapiro{ 99690792Sgshapiro if (tTd(38,2)) 99790792Sgshapiro sm_dprintf("dns_map_open(%s, %d)\n", map->map_mname, mode); 99890792Sgshapiro 99990792Sgshapiro mode &= O_ACCMODE; 100090792Sgshapiro if (mode != O_RDONLY) 100190792Sgshapiro { 100290792Sgshapiro /* issue a pseudo-error message */ 100390792Sgshapiro errno = SM_EMAPCANTWRITE; 100490792Sgshapiro return false; 100590792Sgshapiro } 100690792Sgshapiro return true; 100790792Sgshapiro} 100890792Sgshapiro 100990792Sgshapiro/* 101090792Sgshapiro** DNS_MAP_PARSEARGS -- parse dns map definition args. 101190792Sgshapiro** 101290792Sgshapiro** Parameters: 101390792Sgshapiro** map -- pointer to MAP 101490792Sgshapiro** args -- pointer to the args on the config line. 101590792Sgshapiro** 101690792Sgshapiro** Returns: 101790792Sgshapiro** true -- if everything parsed OK. 101890792Sgshapiro** false -- otherwise. 101990792Sgshapiro*/ 102090792Sgshapiro 1021168515Sgshapiro#define map_sizelimit map_lockfd /* overload field */ 102290792Sgshapiro 102390792Sgshapirostruct dns_map 102490792Sgshapiro{ 102590792Sgshapiro int dns_m_type; 102690792Sgshapiro}; 102790792Sgshapiro 102890792Sgshapirobool 102990792Sgshapirodns_map_parseargs(map,args) 103090792Sgshapiro MAP *map; 103190792Sgshapiro char *args; 103290792Sgshapiro{ 103390792Sgshapiro register char *p = args; 103490792Sgshapiro struct dns_map *map_p; 103590792Sgshapiro 1036168515Sgshapiro map_p = (struct dns_map *) xalloc(sizeof(*map_p)); 103790792Sgshapiro map_p->dns_m_type = -1; 103890792Sgshapiro map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL; 103990792Sgshapiro 104090792Sgshapiro for (;;) 104190792Sgshapiro { 104290792Sgshapiro while (isascii(*p) && isspace(*p)) 104390792Sgshapiro p++; 104490792Sgshapiro if (*p != '-') 104590792Sgshapiro break; 104690792Sgshapiro switch (*++p) 104790792Sgshapiro { 104890792Sgshapiro case 'N': 104990792Sgshapiro map->map_mflags |= MF_INCLNULL; 105090792Sgshapiro map->map_mflags &= ~MF_TRY0NULL; 105190792Sgshapiro break; 105290792Sgshapiro 105390792Sgshapiro case 'O': 105490792Sgshapiro map->map_mflags &= ~MF_TRY1NULL; 105590792Sgshapiro break; 105690792Sgshapiro 105790792Sgshapiro case 'o': 105890792Sgshapiro map->map_mflags |= MF_OPTIONAL; 105990792Sgshapiro break; 106090792Sgshapiro 106190792Sgshapiro case 'f': 106290792Sgshapiro map->map_mflags |= MF_NOFOLDCASE; 106390792Sgshapiro break; 106490792Sgshapiro 106590792Sgshapiro case 'm': 106690792Sgshapiro map->map_mflags |= MF_MATCHONLY; 106790792Sgshapiro break; 106890792Sgshapiro 106990792Sgshapiro case 'A': 107090792Sgshapiro map->map_mflags |= MF_APPEND; 107190792Sgshapiro break; 107290792Sgshapiro 107390792Sgshapiro case 'q': 107490792Sgshapiro map->map_mflags |= MF_KEEPQUOTES; 107590792Sgshapiro break; 107690792Sgshapiro 107790792Sgshapiro case 't': 107890792Sgshapiro map->map_mflags |= MF_NODEFER; 107990792Sgshapiro break; 108090792Sgshapiro 108190792Sgshapiro case 'a': 108290792Sgshapiro map->map_app = ++p; 108390792Sgshapiro break; 108490792Sgshapiro 108590792Sgshapiro case 'T': 108690792Sgshapiro map->map_tapp = ++p; 108790792Sgshapiro break; 108890792Sgshapiro 108990792Sgshapiro case 'd': 109090792Sgshapiro { 109190792Sgshapiro char *h; 109290792Sgshapiro 109390792Sgshapiro ++p; 109490792Sgshapiro h = strchr(p, ' '); 109590792Sgshapiro if (h != NULL) 109690792Sgshapiro *h = '\0'; 109790792Sgshapiro map->map_timeout = convtime(p, 's'); 109890792Sgshapiro if (h != NULL) 109990792Sgshapiro *h = ' '; 110090792Sgshapiro } 110190792Sgshapiro break; 110290792Sgshapiro 110390792Sgshapiro case 'r': 110490792Sgshapiro while (isascii(*++p) && isspace(*p)) 110590792Sgshapiro continue; 110690792Sgshapiro map->map_retry = atoi(p); 110790792Sgshapiro break; 110890792Sgshapiro 110990792Sgshapiro case 'z': 111090792Sgshapiro if (*++p != '\\') 111190792Sgshapiro map->map_coldelim = *p; 111290792Sgshapiro else 111390792Sgshapiro { 111490792Sgshapiro switch (*++p) 111590792Sgshapiro { 111690792Sgshapiro case 'n': 111790792Sgshapiro map->map_coldelim = '\n'; 111890792Sgshapiro break; 111990792Sgshapiro 112090792Sgshapiro case 't': 112190792Sgshapiro map->map_coldelim = '\t'; 112290792Sgshapiro break; 112390792Sgshapiro 112490792Sgshapiro default: 112590792Sgshapiro map->map_coldelim = '\\'; 112690792Sgshapiro } 112790792Sgshapiro } 112890792Sgshapiro break; 112990792Sgshapiro 113090792Sgshapiro case 'Z': 113190792Sgshapiro while (isascii(*++p) && isspace(*p)) 113290792Sgshapiro continue; 113390792Sgshapiro map->map_sizelimit = atoi(p); 113490792Sgshapiro break; 113590792Sgshapiro 113690792Sgshapiro /* Start of dns_map specific args */ 113790792Sgshapiro case 'R': /* search field */ 113890792Sgshapiro { 113990792Sgshapiro char *h; 114090792Sgshapiro 114190792Sgshapiro while (isascii(*++p) && isspace(*p)) 114290792Sgshapiro continue; 114390792Sgshapiro h = strchr(p, ' '); 114490792Sgshapiro if (h != NULL) 114590792Sgshapiro *h = '\0'; 114690792Sgshapiro map_p->dns_m_type = dns_string_to_type(p); 114790792Sgshapiro if (h != NULL) 114890792Sgshapiro *h = ' '; 114990792Sgshapiro if (map_p->dns_m_type < 0) 115090792Sgshapiro syserr("dns map %s: wrong type %s", 115190792Sgshapiro map->map_mname, p); 115290792Sgshapiro } 115390792Sgshapiro break; 115490792Sgshapiro 115590792Sgshapiro case 'B': /* base domain */ 115690792Sgshapiro { 115790792Sgshapiro char *h; 115890792Sgshapiro 115990792Sgshapiro while (isascii(*++p) && isspace(*p)) 116090792Sgshapiro continue; 116190792Sgshapiro h = strchr(p, ' '); 116290792Sgshapiro if (h != NULL) 116390792Sgshapiro *h = '\0'; 116490792Sgshapiro 116590792Sgshapiro /* 116690792Sgshapiro ** slight abuse of map->map_file; it isn't 116790792Sgshapiro ** used otherwise in this map type. 116890792Sgshapiro */ 116990792Sgshapiro 117090792Sgshapiro map->map_file = newstr(p); 117190792Sgshapiro if (h != NULL) 117290792Sgshapiro *h = ' '; 117390792Sgshapiro } 117490792Sgshapiro break; 117590792Sgshapiro } 117690792Sgshapiro while (*p != '\0' && !(isascii(*p) && isspace(*p))) 117790792Sgshapiro p++; 117890792Sgshapiro if (*p != '\0') 117990792Sgshapiro *p++ = '\0'; 118090792Sgshapiro } 118190792Sgshapiro if (map_p->dns_m_type < 0) 118290792Sgshapiro syserr("dns map %s: missing -R type", map->map_mname); 118390792Sgshapiro if (map->map_app != NULL) 118490792Sgshapiro map->map_app = newstr(map->map_app); 118590792Sgshapiro if (map->map_tapp != NULL) 118690792Sgshapiro map->map_tapp = newstr(map->map_tapp); 118790792Sgshapiro 118890792Sgshapiro /* 1189168515Sgshapiro ** Assumption: assert(sizeof(int) <= sizeof(ARBPTR_T)); 119090792Sgshapiro ** Even if this assumption is wrong, we use only one byte, 119190792Sgshapiro ** so it doesn't really matter. 119290792Sgshapiro */ 119390792Sgshapiro 119490792Sgshapiro map->map_db1 = (ARBPTR_T) map_p; 119590792Sgshapiro return true; 119690792Sgshapiro} 119790792Sgshapiro 119890792Sgshapiro/* 119990792Sgshapiro** DNS_MAP_LOOKUP -- perform dns map lookup. 120090792Sgshapiro** 120190792Sgshapiro** Parameters: 120290792Sgshapiro** map -- pointer to MAP 120390792Sgshapiro** name -- name to lookup 120490792Sgshapiro** av -- arguments to interpolate into buf. 120590792Sgshapiro** statp -- pointer to status (EX_) 120690792Sgshapiro** 120790792Sgshapiro** Returns: 120890792Sgshapiro** result of lookup if succeeded. 120990792Sgshapiro** NULL -- otherwise. 121090792Sgshapiro*/ 121190792Sgshapiro 121290792Sgshapirochar * 121390792Sgshapirodns_map_lookup(map, name, av, statp) 121490792Sgshapiro MAP *map; 121590792Sgshapiro char *name; 121690792Sgshapiro char **av; 121790792Sgshapiro int *statp; 121890792Sgshapiro{ 121990792Sgshapiro int resnum = 0; 122090792Sgshapiro char *vp = NULL, *result = NULL; 122190792Sgshapiro size_t vsize; 122290792Sgshapiro struct dns_map *map_p; 122390792Sgshapiro RESOURCE_RECORD_T *rr = NULL; 122490792Sgshapiro DNS_REPLY_T *r = NULL; 122590792Sgshapiro# if NETINET6 122690792Sgshapiro static char buf6[INET6_ADDRSTRLEN]; 122790792Sgshapiro# endif /* NETINET6 */ 122890792Sgshapiro 122990792Sgshapiro if (tTd(38, 20)) 123090792Sgshapiro sm_dprintf("dns_map_lookup(%s, %s)\n", 123190792Sgshapiro map->map_mname, name); 123290792Sgshapiro 123390792Sgshapiro map_p = (struct dns_map *)(map->map_db1); 123490792Sgshapiro if (map->map_file != NULL && *map->map_file != '\0') 123590792Sgshapiro { 123690792Sgshapiro size_t len; 123790792Sgshapiro char *appdomain; 123890792Sgshapiro 123990792Sgshapiro len = strlen(map->map_file) + strlen(name) + 2; 124090792Sgshapiro appdomain = (char *) sm_malloc(len); 124190792Sgshapiro if (appdomain == NULL) 124290792Sgshapiro { 124390792Sgshapiro *statp = EX_UNAVAILABLE; 124490792Sgshapiro return NULL; 124590792Sgshapiro } 124690792Sgshapiro (void) sm_strlcpyn(appdomain, len, 3, name, ".", map->map_file); 124790792Sgshapiro r = dns_lookup_int(appdomain, C_IN, map_p->dns_m_type, 124890792Sgshapiro map->map_timeout, map->map_retry); 124990792Sgshapiro sm_free(appdomain); 125090792Sgshapiro } 125190792Sgshapiro else 125290792Sgshapiro { 125390792Sgshapiro r = dns_lookup_int(name, C_IN, map_p->dns_m_type, 125490792Sgshapiro map->map_timeout, map->map_retry); 125590792Sgshapiro } 125690792Sgshapiro 125790792Sgshapiro if (r == NULL) 125890792Sgshapiro { 125990792Sgshapiro result = NULL; 1260120256Sgshapiro if (h_errno == TRY_AGAIN || transienterror(errno)) 126190792Sgshapiro *statp = EX_TEMPFAIL; 126290792Sgshapiro else 126390792Sgshapiro *statp = EX_NOTFOUND; 126490792Sgshapiro goto cleanup; 126590792Sgshapiro } 126690792Sgshapiro *statp = EX_OK; 126790792Sgshapiro for (rr = r->dns_r_head; rr != NULL; rr = rr->rr_next) 126890792Sgshapiro { 126990792Sgshapiro char *type = NULL; 127090792Sgshapiro char *value = NULL; 127190792Sgshapiro 127290792Sgshapiro switch (rr->rr_type) 127390792Sgshapiro { 127490792Sgshapiro case T_NS: 127590792Sgshapiro type = "T_NS"; 127690792Sgshapiro value = rr->rr_u.rr_txt; 127790792Sgshapiro break; 127890792Sgshapiro case T_CNAME: 127990792Sgshapiro type = "T_CNAME"; 128090792Sgshapiro value = rr->rr_u.rr_txt; 128190792Sgshapiro break; 128290792Sgshapiro case T_AFSDB: 128390792Sgshapiro type = "T_AFSDB"; 128490792Sgshapiro value = rr->rr_u.rr_mx->mx_r_domain; 128590792Sgshapiro break; 128690792Sgshapiro case T_SRV: 128790792Sgshapiro type = "T_SRV"; 128890792Sgshapiro value = rr->rr_u.rr_srv->srv_r_target; 128990792Sgshapiro break; 129090792Sgshapiro case T_PTR: 129190792Sgshapiro type = "T_PTR"; 129290792Sgshapiro value = rr->rr_u.rr_txt; 129390792Sgshapiro break; 129490792Sgshapiro case T_TXT: 129590792Sgshapiro type = "T_TXT"; 129690792Sgshapiro value = rr->rr_u.rr_txt; 129790792Sgshapiro break; 129890792Sgshapiro case T_MX: 129990792Sgshapiro type = "T_MX"; 130090792Sgshapiro value = rr->rr_u.rr_mx->mx_r_domain; 130190792Sgshapiro break; 130290792Sgshapiro# if NETINET 130390792Sgshapiro case T_A: 130490792Sgshapiro type = "T_A"; 130590792Sgshapiro value = inet_ntoa(*(rr->rr_u.rr_a)); 130690792Sgshapiro break; 130790792Sgshapiro# endif /* NETINET */ 130890792Sgshapiro# if NETINET6 130990792Sgshapiro case T_AAAA: 131090792Sgshapiro type = "T_AAAA"; 131190792Sgshapiro value = anynet_ntop(rr->rr_u.rr_aaaa, buf6, 1312168515Sgshapiro sizeof(buf6)); 131390792Sgshapiro break; 131490792Sgshapiro# endif /* NETINET6 */ 131590792Sgshapiro } 131690792Sgshapiro 131798841Sgshapiro (void) strreplnonprt(value, 'X'); 131890792Sgshapiro if (map_p->dns_m_type != rr->rr_type) 131990792Sgshapiro { 132090792Sgshapiro if (tTd(38, 40)) 132190792Sgshapiro sm_dprintf("\tskipping type %s (%d) value %s\n", 132290792Sgshapiro type != NULL ? type : "<UNKNOWN>", 132390792Sgshapiro rr->rr_type, 132490792Sgshapiro value != NULL ? value : "<NO VALUE>"); 132590792Sgshapiro continue; 132690792Sgshapiro } 132790792Sgshapiro 132890792Sgshapiro# if NETINET6 132990792Sgshapiro if (rr->rr_type == T_AAAA && value == NULL) 133090792Sgshapiro { 133190792Sgshapiro result = NULL; 133290792Sgshapiro *statp = EX_DATAERR; 133390792Sgshapiro if (tTd(38, 40)) 133490792Sgshapiro sm_dprintf("\tbad T_AAAA conversion\n"); 133590792Sgshapiro goto cleanup; 133690792Sgshapiro } 133790792Sgshapiro# endif /* NETINET6 */ 133890792Sgshapiro if (tTd(38, 40)) 133990792Sgshapiro sm_dprintf("\tfound type %s (%d) value %s\n", 134090792Sgshapiro type != NULL ? type : "<UNKNOWN>", 134190792Sgshapiro rr->rr_type, 134290792Sgshapiro value != NULL ? value : "<NO VALUE>"); 134390792Sgshapiro if (value != NULL && 134490792Sgshapiro (map->map_coldelim == '\0' || 134590792Sgshapiro map->map_sizelimit == 1 || 134690792Sgshapiro bitset(MF_MATCHONLY, map->map_mflags))) 134790792Sgshapiro { 134890792Sgshapiro /* Only care about the first match */ 134990792Sgshapiro vp = newstr(value); 135090792Sgshapiro break; 135190792Sgshapiro } 135290792Sgshapiro else if (vp == NULL) 135390792Sgshapiro { 135490792Sgshapiro /* First result */ 135590792Sgshapiro vp = newstr(value); 135690792Sgshapiro } 135790792Sgshapiro else 135890792Sgshapiro { 135990792Sgshapiro /* concatenate the results */ 136090792Sgshapiro int sz; 136190792Sgshapiro char *new; 136290792Sgshapiro 136390792Sgshapiro sz = strlen(vp) + strlen(value) + 2; 136490792Sgshapiro new = xalloc(sz); 136590792Sgshapiro (void) sm_snprintf(new, sz, "%s%c%s", 136690792Sgshapiro vp, map->map_coldelim, value); 136790792Sgshapiro sm_free(vp); 136890792Sgshapiro vp = new; 136990792Sgshapiro if (map->map_sizelimit > 0 && 137090792Sgshapiro ++resnum >= map->map_sizelimit) 137190792Sgshapiro break; 137290792Sgshapiro } 137390792Sgshapiro } 137490792Sgshapiro if (vp == NULL) 137590792Sgshapiro { 137690792Sgshapiro result = NULL; 137790792Sgshapiro *statp = EX_NOTFOUND; 137890792Sgshapiro if (tTd(38, 40)) 137990792Sgshapiro sm_dprintf("\tno match found\n"); 138090792Sgshapiro goto cleanup; 138190792Sgshapiro } 138290792Sgshapiro 138390792Sgshapiro /* Cleanly truncate for rulesets */ 138490792Sgshapiro truncate_at_delim(vp, PSBUFSIZE / 2, map->map_coldelim); 138590792Sgshapiro 138690792Sgshapiro vsize = strlen(vp); 138790792Sgshapiro 138890792Sgshapiro if (LogLevel > 9) 138990792Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, "dns %.100s => %s", 139090792Sgshapiro name, vp); 139190792Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 139290792Sgshapiro result = map_rewrite(map, name, strlen(name), NULL); 139390792Sgshapiro else 139490792Sgshapiro result = map_rewrite(map, vp, vsize, av); 139590792Sgshapiro 139690792Sgshapiro cleanup: 139790792Sgshapiro if (vp != NULL) 139890792Sgshapiro sm_free(vp); 139990792Sgshapiro if (r != NULL) 140090792Sgshapiro dns_free_data(r); 140190792Sgshapiro return result; 140290792Sgshapiro} 140390792Sgshapiro# endif /* DNSMAP */ 140490792Sgshapiro#endif /* NAMED_BIND */ 140590792Sgshapiro 140690792Sgshapiro/* 140738032Speter** NDBM modules 140838032Speter*/ 140938032Speter 141090792Sgshapiro#if NDBM 141138032Speter 141238032Speter/* 141338032Speter** NDBM_MAP_OPEN -- DBM-style map open 141438032Speter*/ 141538032Speter 141638032Speterbool 141738032Speterndbm_map_open(map, mode) 141838032Speter MAP *map; 141938032Speter int mode; 142038032Speter{ 142138032Speter register DBM *dbm; 142264562Sgshapiro int save_errno; 142338032Speter int dfd; 142438032Speter int pfd; 142564562Sgshapiro long sff; 142638032Speter int ret; 142738032Speter int smode = S_IREAD; 142898121Sgshapiro char dirfile[MAXPATHLEN]; 142998121Sgshapiro char pagfile[MAXPATHLEN]; 143064562Sgshapiro struct stat st; 143138032Speter struct stat std, stp; 143238032Speter 143338032Speter if (tTd(38, 2)) 143490792Sgshapiro sm_dprintf("ndbm_map_open(%s, %s, %d)\n", 143538032Speter map->map_mname, map->map_file, mode); 143638032Speter map->map_lockfd = -1; 143738032Speter mode &= O_ACCMODE; 143838032Speter 143938032Speter /* do initial file and directory checks */ 1440168515Sgshapiro if (sm_strlcpyn(dirfile, sizeof(dirfile), 2, 1441168515Sgshapiro map->map_file, ".dir") >= sizeof(dirfile) || 1442168515Sgshapiro sm_strlcpyn(pagfile, sizeof(pagfile), 2, 1443168515Sgshapiro map->map_file, ".pag") >= sizeof(pagfile)) 144498121Sgshapiro { 144598121Sgshapiro errno = 0; 144698121Sgshapiro if (!bitset(MF_OPTIONAL, map->map_mflags)) 144798121Sgshapiro syserr("dbm map \"%s\": map file %s name too long", 144898121Sgshapiro map->map_mname, map->map_file); 144998121Sgshapiro return false; 145098121Sgshapiro } 145138032Speter sff = SFF_ROOTOK|SFF_REGONLY; 145238032Speter if (mode == O_RDWR) 145338032Speter { 145438032Speter sff |= SFF_CREAT; 145564562Sgshapiro if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 145638032Speter sff |= SFF_NOSLINK; 145764562Sgshapiro if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 145838032Speter sff |= SFF_NOHLINK; 145938032Speter smode = S_IWRITE; 146038032Speter } 146138032Speter else 146238032Speter { 146364562Sgshapiro if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 146438032Speter sff |= SFF_NOWLINK; 146538032Speter } 146664562Sgshapiro if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail)) 146738032Speter sff |= SFF_SAFEDIRPATH; 146838032Speter ret = safefile(dirfile, RunAsUid, RunAsGid, RunAsUserName, 146990792Sgshapiro sff, smode, &std); 147038032Speter if (ret == 0) 147138032Speter ret = safefile(pagfile, RunAsUid, RunAsGid, RunAsUserName, 147238032Speter sff, smode, &stp); 147364562Sgshapiro 147438032Speter if (ret != 0) 147538032Speter { 147638032Speter char *prob = "unsafe"; 147738032Speter 147838032Speter /* cannot open this map */ 147938032Speter if (ret == ENOENT) 148038032Speter prob = "missing"; 148138032Speter if (tTd(38, 2)) 148290792Sgshapiro sm_dprintf("\t%s map file: %d\n", prob, ret); 148338032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 148438032Speter syserr("dbm map \"%s\": %s map file %s", 148538032Speter map->map_mname, prob, map->map_file); 148690792Sgshapiro return false; 148738032Speter } 148838032Speter if (std.st_mode == ST_MODE_NOFILE) 148938032Speter mode |= O_CREAT|O_EXCL; 149038032Speter 149164562Sgshapiro# if LOCK_ON_OPEN 149238032Speter if (mode == O_RDONLY) 149338032Speter mode |= O_SHLOCK; 149438032Speter else 149538032Speter mode |= O_TRUNC|O_EXLOCK; 149664562Sgshapiro# else /* LOCK_ON_OPEN */ 149738032Speter if ((mode & O_ACCMODE) == O_RDWR) 149838032Speter { 149964562Sgshapiro# if NOFTRUNCATE 150038032Speter /* 150138032Speter ** Warning: race condition. Try to lock the file as 150238032Speter ** quickly as possible after opening it. 150338032Speter ** This may also have security problems on some systems, 150438032Speter ** but there isn't anything we can do about it. 150538032Speter */ 150638032Speter 150738032Speter mode |= O_TRUNC; 150864562Sgshapiro# else /* NOFTRUNCATE */ 150938032Speter /* 151038032Speter ** This ugly code opens the map without truncating it, 151138032Speter ** locks the file, then truncates it. Necessary to 151238032Speter ** avoid race conditions. 151338032Speter */ 151438032Speter 151538032Speter int dirfd; 151638032Speter int pagfd; 151764562Sgshapiro long sff = SFF_CREAT|SFF_OPENASROOT; 151838032Speter 151964562Sgshapiro if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 152038032Speter sff |= SFF_NOSLINK; 152164562Sgshapiro if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 152238032Speter sff |= SFF_NOHLINK; 152338032Speter 152438032Speter dirfd = safeopen(dirfile, mode, DBMMODE, sff); 152538032Speter pagfd = safeopen(pagfile, mode, DBMMODE, sff); 152638032Speter 152738032Speter if (dirfd < 0 || pagfd < 0) 152838032Speter { 152964562Sgshapiro save_errno = errno; 153038032Speter if (dirfd >= 0) 153138032Speter (void) close(dirfd); 153238032Speter if (pagfd >= 0) 153338032Speter (void) close(pagfd); 153438032Speter errno = save_errno; 153538032Speter syserr("ndbm_map_open: cannot create database %s", 153638032Speter map->map_file); 153790792Sgshapiro return false; 153838032Speter } 153938032Speter if (ftruncate(dirfd, (off_t) 0) < 0 || 154038032Speter ftruncate(pagfd, (off_t) 0) < 0) 154138032Speter { 154264562Sgshapiro save_errno = errno; 154338032Speter (void) close(dirfd); 154438032Speter (void) close(pagfd); 154538032Speter errno = save_errno; 154638032Speter syserr("ndbm_map_open: cannot truncate %s.{dir,pag}", 154738032Speter map->map_file); 154890792Sgshapiro return false; 154938032Speter } 155038032Speter 155138032Speter /* if new file, get "before" bits for later filechanged check */ 155238032Speter if (std.st_mode == ST_MODE_NOFILE && 155338032Speter (fstat(dirfd, &std) < 0 || fstat(pagfd, &stp) < 0)) 155438032Speter { 155564562Sgshapiro save_errno = errno; 155638032Speter (void) close(dirfd); 155738032Speter (void) close(pagfd); 155838032Speter errno = save_errno; 155938032Speter syserr("ndbm_map_open(%s.{dir,pag}): cannot fstat pre-opened file", 156038032Speter map->map_file); 156190792Sgshapiro return false; 156238032Speter } 156338032Speter 156438032Speter /* have to save the lock for the duration (bletch) */ 156538032Speter map->map_lockfd = dirfd; 156664562Sgshapiro (void) close(pagfd); 156738032Speter 156838032Speter /* twiddle bits for dbm_open */ 156938032Speter mode &= ~(O_CREAT|O_EXCL); 157064562Sgshapiro# endif /* NOFTRUNCATE */ 157138032Speter } 157264562Sgshapiro# endif /* LOCK_ON_OPEN */ 157338032Speter 157438032Speter /* open the database */ 157538032Speter dbm = dbm_open(map->map_file, mode, DBMMODE); 157638032Speter if (dbm == NULL) 157738032Speter { 157864562Sgshapiro save_errno = errno; 157938032Speter if (bitset(MF_ALIAS, map->map_mflags) && 158090792Sgshapiro aliaswait(map, ".pag", false)) 158190792Sgshapiro return true; 158264562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE 158338032Speter if (map->map_lockfd >= 0) 158464562Sgshapiro (void) close(map->map_lockfd); 158564562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */ 158638032Speter errno = save_errno; 158738032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 158838032Speter syserr("Cannot open DBM database %s", map->map_file); 158990792Sgshapiro return false; 159038032Speter } 159138032Speter dfd = dbm_dirfno(dbm); 159238032Speter pfd = dbm_pagfno(dbm); 159338032Speter if (dfd == pfd) 159438032Speter { 159538032Speter /* heuristic: if files are linked, this is actually gdbm */ 159638032Speter dbm_close(dbm); 159764562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE 159838032Speter if (map->map_lockfd >= 0) 159964562Sgshapiro (void) close(map->map_lockfd); 160064562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */ 160138032Speter errno = 0; 160238032Speter syserr("dbm map \"%s\": cannot support GDBM", 160338032Speter map->map_mname); 160490792Sgshapiro return false; 160538032Speter } 160638032Speter 160738032Speter if (filechanged(dirfile, dfd, &std) || 160838032Speter filechanged(pagfile, pfd, &stp)) 160938032Speter { 161064562Sgshapiro save_errno = errno; 161138032Speter dbm_close(dbm); 161264562Sgshapiro# if !LOCK_ON_OPEN && !NOFTRUNCATE 161338032Speter if (map->map_lockfd >= 0) 161464562Sgshapiro (void) close(map->map_lockfd); 161564562Sgshapiro# endif /* !LOCK_ON_OPEN && !NOFTRUNCATE */ 161638032Speter errno = save_errno; 161738032Speter syserr("ndbm_map_open(%s): file changed after open", 161838032Speter map->map_file); 161990792Sgshapiro return false; 162038032Speter } 162138032Speter 162238032Speter map->map_db1 = (ARBPTR_T) dbm; 162364562Sgshapiro 162464562Sgshapiro /* 162564562Sgshapiro ** Need to set map_mtime before the call to aliaswait() 162664562Sgshapiro ** as aliaswait() will call map_lookup() which requires 162764562Sgshapiro ** map_mtime to be set 162864562Sgshapiro */ 162964562Sgshapiro 163077349Sgshapiro if (fstat(pfd, &st) >= 0) 163164562Sgshapiro map->map_mtime = st.st_mtime; 163264562Sgshapiro 163338032Speter if (mode == O_RDONLY) 163438032Speter { 163564562Sgshapiro# if LOCK_ON_OPEN 163638032Speter if (dfd >= 0) 163738032Speter (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN); 163838032Speter if (pfd >= 0) 163938032Speter (void) lockfile(pfd, map->map_file, ".pag", LOCK_UN); 164064562Sgshapiro# endif /* LOCK_ON_OPEN */ 164138032Speter if (bitset(MF_ALIAS, map->map_mflags) && 164290792Sgshapiro !aliaswait(map, ".pag", true)) 164390792Sgshapiro return false; 164438032Speter } 164538032Speter else 164638032Speter { 164738032Speter map->map_mflags |= MF_LOCKED; 164842575Speter if (geteuid() == 0 && TrustedUid != 0) 164938032Speter { 165064562Sgshapiro# if HASFCHOWN 165142575Speter if (fchown(dfd, TrustedUid, -1) < 0 || 165242575Speter fchown(pfd, TrustedUid, -1) < 0) 165338032Speter { 165438032Speter int err = errno; 165538032Speter 165638032Speter sm_syslog(LOG_ALERT, NOQID, 165738032Speter "ownership change on %s failed: %s", 165890792Sgshapiro map->map_file, sm_errstring(err)); 165938032Speter message("050 ownership change on %s failed: %s", 166090792Sgshapiro map->map_file, sm_errstring(err)); 166138032Speter } 166290792Sgshapiro# else /* HASFCHOWN */ 166390792Sgshapiro sm_syslog(LOG_ALERT, NOQID, 166490792Sgshapiro "no fchown(): cannot change ownership on %s", 166590792Sgshapiro map->map_file); 166690792Sgshapiro message("050 no fchown(): cannot change ownership on %s", 166790792Sgshapiro map->map_file); 166864562Sgshapiro# endif /* HASFCHOWN */ 166938032Speter } 167038032Speter } 167190792Sgshapiro return true; 167238032Speter} 167338032Speter 167438032Speter 167538032Speter/* 167638032Speter** NDBM_MAP_LOOKUP -- look up a datum in a DBM-type map 167738032Speter*/ 167838032Speter 167938032Speterchar * 168038032Speterndbm_map_lookup(map, name, av, statp) 168138032Speter MAP *map; 168238032Speter char *name; 168338032Speter char **av; 168438032Speter int *statp; 168538032Speter{ 168638032Speter datum key, val; 168777349Sgshapiro int dfd, pfd; 168838032Speter char keybuf[MAXNAME + 1]; 168938032Speter struct stat stbuf; 169038032Speter 169138032Speter if (tTd(38, 20)) 169290792Sgshapiro sm_dprintf("ndbm_map_lookup(%s, %s)\n", 169338032Speter map->map_mname, name); 169438032Speter 169538032Speter key.dptr = name; 169638032Speter key.dsize = strlen(name); 169738032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 169838032Speter { 1699168515Sgshapiro if (key.dsize > sizeof(keybuf) - 1) 1700168515Sgshapiro key.dsize = sizeof(keybuf) - 1; 170164562Sgshapiro memmove(keybuf, key.dptr, key.dsize); 170238032Speter keybuf[key.dsize] = '\0'; 170338032Speter makelower(keybuf); 170438032Speter key.dptr = keybuf; 170538032Speter } 170638032Speterlockdbm: 170777349Sgshapiro dfd = dbm_dirfno((DBM *) map->map_db1); 170877349Sgshapiro if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 170977349Sgshapiro (void) lockfile(dfd, map->map_file, ".dir", LOCK_SH); 171077349Sgshapiro pfd = dbm_pagfno((DBM *) map->map_db1); 171177349Sgshapiro if (pfd < 0 || fstat(pfd, &stbuf) < 0 || 171277349Sgshapiro stbuf.st_mtime > map->map_mtime) 171338032Speter { 171438032Speter /* Reopen the database to sync the cache */ 171538032Speter int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR 171638032Speter : O_RDONLY; 171738032Speter 171877349Sgshapiro if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 171977349Sgshapiro (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN); 172077349Sgshapiro map->map_mflags |= MF_CLOSING; 172138032Speter map->map_class->map_close(map); 172277349Sgshapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 172338032Speter if (map->map_class->map_open(map, omode)) 172438032Speter { 172538032Speter map->map_mflags |= MF_OPEN; 172690792Sgshapiro map->map_pid = CurrentPid; 1727203004Sgshapiro if ((omode & O_ACCMODE) == O_RDWR) 172838032Speter map->map_mflags |= MF_WRITABLE; 172938032Speter goto lockdbm; 173038032Speter } 173138032Speter else 173238032Speter { 173338032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 173438032Speter { 173538032Speter extern MAPCLASS BogusMapClass; 173638032Speter 173738032Speter *statp = EX_TEMPFAIL; 173890792Sgshapiro map->map_orgclass = map->map_class; 173938032Speter map->map_class = &BogusMapClass; 174038032Speter map->map_mflags |= MF_OPEN; 174190792Sgshapiro map->map_pid = CurrentPid; 174238032Speter syserr("Cannot reopen NDBM database %s", 174338032Speter map->map_file); 174438032Speter } 174538032Speter return NULL; 174638032Speter } 174738032Speter } 174838032Speter val.dptr = NULL; 174938032Speter if (bitset(MF_TRY0NULL, map->map_mflags)) 175038032Speter { 175138032Speter val = dbm_fetch((DBM *) map->map_db1, key); 175238032Speter if (val.dptr != NULL) 175338032Speter map->map_mflags &= ~MF_TRY1NULL; 175438032Speter } 175538032Speter if (val.dptr == NULL && bitset(MF_TRY1NULL, map->map_mflags)) 175638032Speter { 175738032Speter key.dsize++; 175838032Speter val = dbm_fetch((DBM *) map->map_db1, key); 175938032Speter if (val.dptr != NULL) 176038032Speter map->map_mflags &= ~MF_TRY0NULL; 176138032Speter } 176277349Sgshapiro if (dfd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 176377349Sgshapiro (void) lockfile(dfd, map->map_file, ".dir", LOCK_UN); 176438032Speter if (val.dptr == NULL) 176538032Speter return NULL; 176638032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 176738032Speter return map_rewrite(map, name, strlen(name), NULL); 176838032Speter else 176938032Speter return map_rewrite(map, val.dptr, val.dsize, av); 177038032Speter} 177138032Speter 177238032Speter 177338032Speter/* 177438032Speter** NDBM_MAP_STORE -- store a datum in the database 177538032Speter*/ 177638032Speter 177738032Spetervoid 177838032Speterndbm_map_store(map, lhs, rhs) 177938032Speter register MAP *map; 178038032Speter char *lhs; 178138032Speter char *rhs; 178238032Speter{ 178338032Speter datum key; 178438032Speter datum data; 178564562Sgshapiro int status; 178638032Speter char keybuf[MAXNAME + 1]; 178738032Speter 178838032Speter if (tTd(38, 12)) 178990792Sgshapiro sm_dprintf("ndbm_map_store(%s, %s, %s)\n", 179038032Speter map->map_mname, lhs, rhs); 179138032Speter 179238032Speter key.dsize = strlen(lhs); 179338032Speter key.dptr = lhs; 179438032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 179538032Speter { 1796168515Sgshapiro if (key.dsize > sizeof(keybuf) - 1) 1797168515Sgshapiro key.dsize = sizeof(keybuf) - 1; 179864562Sgshapiro memmove(keybuf, key.dptr, key.dsize); 179938032Speter keybuf[key.dsize] = '\0'; 180038032Speter makelower(keybuf); 180138032Speter key.dptr = keybuf; 180238032Speter } 180338032Speter 180438032Speter data.dsize = strlen(rhs); 180538032Speter data.dptr = rhs; 180638032Speter 180738032Speter if (bitset(MF_INCLNULL, map->map_mflags)) 180838032Speter { 180938032Speter key.dsize++; 181038032Speter data.dsize++; 181138032Speter } 181238032Speter 181364562Sgshapiro status = dbm_store((DBM *) map->map_db1, key, data, DBM_INSERT); 181464562Sgshapiro if (status > 0) 181538032Speter { 181638032Speter if (!bitset(MF_APPEND, map->map_mflags)) 181738032Speter message("050 Warning: duplicate alias name %s", lhs); 181838032Speter else 181938032Speter { 182038032Speter static char *buf = NULL; 182138032Speter static int bufsiz = 0; 182238032Speter auto int xstat; 182338032Speter datum old; 182438032Speter 182538032Speter old.dptr = ndbm_map_lookup(map, key.dptr, 182690792Sgshapiro (char **) NULL, &xstat); 182738032Speter if (old.dptr != NULL && *(char *) old.dptr != '\0') 182838032Speter { 182938032Speter old.dsize = strlen(old.dptr); 183038032Speter if (data.dsize + old.dsize + 2 > bufsiz) 183138032Speter { 183238032Speter if (buf != NULL) 183390792Sgshapiro (void) sm_free(buf); 183438032Speter bufsiz = data.dsize + old.dsize + 2; 183590792Sgshapiro buf = sm_pmalloc_x(bufsiz); 183638032Speter } 183790792Sgshapiro (void) sm_strlcpyn(buf, bufsiz, 3, 183890792Sgshapiro data.dptr, ",", old.dptr); 183938032Speter data.dsize = data.dsize + old.dsize + 1; 184038032Speter data.dptr = buf; 184138032Speter if (tTd(38, 9)) 184290792Sgshapiro sm_dprintf("ndbm_map_store append=%s\n", 1843285303Sgshapiro (char *)data.dptr); 184438032Speter } 184538032Speter } 184664562Sgshapiro status = dbm_store((DBM *) map->map_db1, 184764562Sgshapiro key, data, DBM_REPLACE); 184838032Speter } 184964562Sgshapiro if (status != 0) 185064562Sgshapiro syserr("readaliases: dbm put (%s): %d", lhs, status); 185138032Speter} 185238032Speter 185338032Speter 185438032Speter/* 185538032Speter** NDBM_MAP_CLOSE -- close the database 185638032Speter*/ 185738032Speter 185838032Spetervoid 185938032Speterndbm_map_close(map) 186038032Speter register MAP *map; 186138032Speter{ 186238032Speter if (tTd(38, 9)) 186390792Sgshapiro sm_dprintf("ndbm_map_close(%s, %s, %lx)\n", 186438032Speter map->map_mname, map->map_file, map->map_mflags); 186538032Speter 186638032Speter if (bitset(MF_WRITABLE, map->map_mflags)) 186738032Speter { 186864562Sgshapiro# ifdef NDBM_YP_COMPAT 186938032Speter bool inclnull; 187042575Speter char buf[MAXHOSTNAMELEN]; 187138032Speter 187238032Speter inclnull = bitset(MF_INCLNULL, map->map_mflags); 187338032Speter map->map_mflags &= ~MF_INCLNULL; 187438032Speter 187538032Speter if (strstr(map->map_file, "/yp/") != NULL) 187638032Speter { 187738032Speter long save_mflags = map->map_mflags; 187838032Speter 187938032Speter map->map_mflags |= MF_NOFOLDCASE; 188038032Speter 1881168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%010ld", curtime()); 188238032Speter ndbm_map_store(map, "YP_LAST_MODIFIED", buf); 188338032Speter 1884168515Sgshapiro (void) gethostname(buf, sizeof(buf)); 188538032Speter ndbm_map_store(map, "YP_MASTER_NAME", buf); 188638032Speter 188738032Speter map->map_mflags = save_mflags; 188838032Speter } 188938032Speter 189038032Speter if (inclnull) 189138032Speter map->map_mflags |= MF_INCLNULL; 189264562Sgshapiro# endif /* NDBM_YP_COMPAT */ 189338032Speter 189438032Speter /* write out the distinguished alias */ 189538032Speter ndbm_map_store(map, "@", "@"); 189638032Speter } 189738032Speter dbm_close((DBM *) map->map_db1); 189838032Speter 189938032Speter /* release lock (if needed) */ 190064562Sgshapiro# if !LOCK_ON_OPEN 190138032Speter if (map->map_lockfd >= 0) 190238032Speter (void) close(map->map_lockfd); 190364562Sgshapiro# endif /* !LOCK_ON_OPEN */ 190438032Speter} 190538032Speter 190664562Sgshapiro#endif /* NDBM */ 190790792Sgshapiro/* 190838032Speter** NEWDB (Hash and BTree) Modules 190938032Speter*/ 191038032Speter 191190792Sgshapiro#if NEWDB 191238032Speter 191338032Speter/* 191438032Speter** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives. 191538032Speter** 191638032Speter** These do rather bizarre locking. If you can lock on open, 191738032Speter** do that to avoid the condition of opening a database that 191838032Speter** is being rebuilt. If you don't, we'll try to fake it, but 191938032Speter** there will be a race condition. If opening for read-only, 192038032Speter** we immediately release the lock to avoid freezing things up. 192138032Speter** We really ought to hold the lock, but guarantee that we won't 192238032Speter** be pokey about it. That's hard to do. 192338032Speter*/ 192438032Speter 192538032Speter/* these should be K line arguments */ 192664562Sgshapiro# if DB_VERSION_MAJOR < 2 192764562Sgshapiro# define db_cachesize cachesize 192864562Sgshapiro# define h_nelem nelem 192964562Sgshapiro# ifndef DB_CACHE_SIZE 193064562Sgshapiro# define DB_CACHE_SIZE (1024 * 1024) /* database memory cache size */ 193164562Sgshapiro# endif /* ! DB_CACHE_SIZE */ 193264562Sgshapiro# ifndef DB_HASH_NELEM 193364562Sgshapiro# define DB_HASH_NELEM 4096 /* (starting) size of hash table */ 193464562Sgshapiro# endif /* ! DB_HASH_NELEM */ 193564562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 193638032Speter 193738032Speterbool 193838032Speterbt_map_open(map, mode) 193938032Speter MAP *map; 194038032Speter int mode; 194138032Speter{ 194264562Sgshapiro# if DB_VERSION_MAJOR < 2 194338032Speter BTREEINFO btinfo; 194464562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 194564562Sgshapiro# if DB_VERSION_MAJOR == 2 194638032Speter DB_INFO btinfo; 194764562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */ 194864562Sgshapiro# if DB_VERSION_MAJOR > 2 194964562Sgshapiro void *btinfo = NULL; 195064562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 195138032Speter 195238032Speter if (tTd(38, 2)) 195390792Sgshapiro sm_dprintf("bt_map_open(%s, %s, %d)\n", 195438032Speter map->map_mname, map->map_file, mode); 195538032Speter 195664562Sgshapiro# if DB_VERSION_MAJOR < 3 1957168515Sgshapiro memset(&btinfo, '\0', sizeof(btinfo)); 195864562Sgshapiro# ifdef DB_CACHE_SIZE 195938032Speter btinfo.db_cachesize = DB_CACHE_SIZE; 196064562Sgshapiro# endif /* DB_CACHE_SIZE */ 196164562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */ 196264562Sgshapiro 196338032Speter return db_map_open(map, mode, "btree", DB_BTREE, &btinfo); 196438032Speter} 196538032Speter 196638032Speterbool 196738032Speterhash_map_open(map, mode) 196838032Speter MAP *map; 196938032Speter int mode; 197038032Speter{ 197164562Sgshapiro# if DB_VERSION_MAJOR < 2 197238032Speter HASHINFO hinfo; 197364562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 197464562Sgshapiro# if DB_VERSION_MAJOR == 2 197538032Speter DB_INFO hinfo; 197664562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */ 197764562Sgshapiro# if DB_VERSION_MAJOR > 2 197864562Sgshapiro void *hinfo = NULL; 197964562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 198038032Speter 198138032Speter if (tTd(38, 2)) 198290792Sgshapiro sm_dprintf("hash_map_open(%s, %s, %d)\n", 198338032Speter map->map_mname, map->map_file, mode); 198438032Speter 198564562Sgshapiro# if DB_VERSION_MAJOR < 3 1986168515Sgshapiro memset(&hinfo, '\0', sizeof(hinfo)); 198764562Sgshapiro# ifdef DB_HASH_NELEM 198838032Speter hinfo.h_nelem = DB_HASH_NELEM; 198964562Sgshapiro# endif /* DB_HASH_NELEM */ 199064562Sgshapiro# ifdef DB_CACHE_SIZE 199138032Speter hinfo.db_cachesize = DB_CACHE_SIZE; 199264562Sgshapiro# endif /* DB_CACHE_SIZE */ 199364562Sgshapiro# endif /* DB_VERSION_MAJOR < 3 */ 199464562Sgshapiro 199538032Speter return db_map_open(map, mode, "hash", DB_HASH, &hinfo); 199638032Speter} 199738032Speter 199864562Sgshapirostatic bool 199938032Speterdb_map_open(map, mode, mapclassname, dbtype, openinfo) 200038032Speter MAP *map; 200138032Speter int mode; 200238032Speter char *mapclassname; 200338032Speter DBTYPE dbtype; 200464562Sgshapiro# if DB_VERSION_MAJOR < 2 200538032Speter const void *openinfo; 200664562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 200764562Sgshapiro# if DB_VERSION_MAJOR == 2 200838032Speter DB_INFO *openinfo; 200964562Sgshapiro# endif /* DB_VERSION_MAJOR == 2 */ 201064562Sgshapiro# if DB_VERSION_MAJOR > 2 201164562Sgshapiro void **openinfo; 201264562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 201338032Speter{ 201438032Speter DB *db = NULL; 201538032Speter int i; 201638032Speter int omode; 201738032Speter int smode = S_IREAD; 201838032Speter int fd; 201964562Sgshapiro long sff; 202064562Sgshapiro int save_errno; 202138032Speter struct stat st; 202298121Sgshapiro char buf[MAXPATHLEN]; 202338032Speter 202438032Speter /* do initial file and directory checks */ 2025168515Sgshapiro if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf)) 202698121Sgshapiro { 202798121Sgshapiro errno = 0; 202898121Sgshapiro if (!bitset(MF_OPTIONAL, map->map_mflags)) 202998121Sgshapiro syserr("map \"%s\": map file %s name too long", 203098121Sgshapiro map->map_mname, map->map_file); 203198121Sgshapiro return false; 203298121Sgshapiro } 203338032Speter i = strlen(buf); 203438032Speter if (i < 3 || strcmp(&buf[i - 3], ".db") != 0) 203598121Sgshapiro { 2036168515Sgshapiro if (sm_strlcat(buf, ".db", sizeof(buf)) >= sizeof(buf)) 203798121Sgshapiro { 203898121Sgshapiro errno = 0; 203998121Sgshapiro if (!bitset(MF_OPTIONAL, map->map_mflags)) 204098121Sgshapiro syserr("map \"%s\": map file %s name too long", 204198121Sgshapiro map->map_mname, map->map_file); 204298121Sgshapiro return false; 204398121Sgshapiro } 204498121Sgshapiro } 204538032Speter 204638032Speter mode &= O_ACCMODE; 204738032Speter omode = mode; 204838032Speter 204938032Speter sff = SFF_ROOTOK|SFF_REGONLY; 205038032Speter if (mode == O_RDWR) 205138032Speter { 205238032Speter sff |= SFF_CREAT; 205364562Sgshapiro if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail)) 205438032Speter sff |= SFF_NOSLINK; 205564562Sgshapiro if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail)) 205638032Speter sff |= SFF_NOHLINK; 205738032Speter smode = S_IWRITE; 205838032Speter } 205938032Speter else 206038032Speter { 206164562Sgshapiro if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 206238032Speter sff |= SFF_NOWLINK; 206338032Speter } 206464562Sgshapiro if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail)) 206538032Speter sff |= SFF_SAFEDIRPATH; 206638032Speter i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st); 206764562Sgshapiro 206838032Speter if (i != 0) 206938032Speter { 207038032Speter char *prob = "unsafe"; 207138032Speter 207238032Speter /* cannot open this map */ 207338032Speter if (i == ENOENT) 207438032Speter prob = "missing"; 207538032Speter if (tTd(38, 2)) 207690792Sgshapiro sm_dprintf("\t%s map file: %s\n", prob, sm_errstring(i)); 207738032Speter errno = i; 207838032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 207938032Speter syserr("%s map \"%s\": %s map file %s", 208038032Speter mapclassname, map->map_mname, prob, buf); 208190792Sgshapiro return false; 208238032Speter } 208338032Speter if (st.st_mode == ST_MODE_NOFILE) 208438032Speter omode |= O_CREAT|O_EXCL; 208538032Speter 208638032Speter map->map_lockfd = -1; 208738032Speter 208864562Sgshapiro# if LOCK_ON_OPEN 208938032Speter if (mode == O_RDWR) 209038032Speter omode |= O_TRUNC|O_EXLOCK; 209138032Speter else 209238032Speter omode |= O_SHLOCK; 209364562Sgshapiro# else /* LOCK_ON_OPEN */ 209438032Speter /* 209538032Speter ** Pre-lock the file to avoid race conditions. In particular, 209638032Speter ** since dbopen returns NULL if the file is zero length, we 209738032Speter ** must have a locked instance around the dbopen. 209838032Speter */ 209938032Speter 210038032Speter fd = open(buf, omode, DBMMODE); 210138032Speter if (fd < 0) 210238032Speter { 210338032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 210438032Speter syserr("db_map_open: cannot pre-open database %s", buf); 210590792Sgshapiro return false; 210638032Speter } 210738032Speter 210838032Speter /* make sure no baddies slipped in just before the open... */ 210938032Speter if (filechanged(buf, fd, &st)) 211038032Speter { 211164562Sgshapiro save_errno = errno; 211238032Speter (void) close(fd); 211338032Speter errno = save_errno; 211438032Speter syserr("db_map_open(%s): file changed after pre-open", buf); 211590792Sgshapiro return false; 211638032Speter } 211738032Speter 211838032Speter /* if new file, get the "before" bits for later filechanged check */ 211938032Speter if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0) 212038032Speter { 212164562Sgshapiro save_errno = errno; 212238032Speter (void) close(fd); 212338032Speter errno = save_errno; 212438032Speter syserr("db_map_open(%s): cannot fstat pre-opened file", 212538032Speter buf); 212690792Sgshapiro return false; 212738032Speter } 212838032Speter 212938032Speter /* actually lock the pre-opened file */ 213038032Speter if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX)) 213138032Speter syserr("db_map_open: cannot lock %s", buf); 213238032Speter 213338032Speter /* set up mode bits for dbopen */ 213438032Speter if (mode == O_RDWR) 213538032Speter omode |= O_TRUNC; 213638032Speter omode &= ~(O_EXCL|O_CREAT); 213764562Sgshapiro# endif /* LOCK_ON_OPEN */ 213838032Speter 213964562Sgshapiro# if DB_VERSION_MAJOR < 2 214038032Speter db = dbopen(buf, omode, DBMMODE, dbtype, openinfo); 214164562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 214238032Speter { 214338032Speter int flags = 0; 214464562Sgshapiro# if DB_VERSION_MAJOR > 2 214564562Sgshapiro int ret; 214664562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 214738032Speter 214838032Speter if (mode == O_RDONLY) 214938032Speter flags |= DB_RDONLY; 215038032Speter if (bitset(O_CREAT, omode)) 215138032Speter flags |= DB_CREATE; 215238032Speter if (bitset(O_TRUNC, omode)) 215338032Speter flags |= DB_TRUNCATE; 2154110560Sgshapiro SM_DB_FLAG_ADD(flags); 215538032Speter 215664562Sgshapiro# if DB_VERSION_MAJOR > 2 215764562Sgshapiro ret = db_create(&db, NULL, 0); 215864562Sgshapiro# ifdef DB_CACHE_SIZE 215964562Sgshapiro if (ret == 0 && db != NULL) 216064562Sgshapiro { 216164562Sgshapiro ret = db->set_cachesize(db, 0, DB_CACHE_SIZE, 0); 216264562Sgshapiro if (ret != 0) 216364562Sgshapiro { 216464562Sgshapiro (void) db->close(db, 0); 216564562Sgshapiro db = NULL; 216664562Sgshapiro } 216764562Sgshapiro } 216864562Sgshapiro# endif /* DB_CACHE_SIZE */ 216964562Sgshapiro# ifdef DB_HASH_NELEM 217064562Sgshapiro if (dbtype == DB_HASH && ret == 0 && db != NULL) 217164562Sgshapiro { 217264562Sgshapiro ret = db->set_h_nelem(db, DB_HASH_NELEM); 217364562Sgshapiro if (ret != 0) 217464562Sgshapiro { 217564562Sgshapiro (void) db->close(db, 0); 217664562Sgshapiro db = NULL; 217764562Sgshapiro } 217864562Sgshapiro } 217964562Sgshapiro# endif /* DB_HASH_NELEM */ 218064562Sgshapiro if (ret == 0 && db != NULL) 218164562Sgshapiro { 2182110560Sgshapiro ret = db->open(db, 2183110560Sgshapiro DBTXN /* transaction for DB 4.1 */ 2184110560Sgshapiro buf, NULL, dbtype, flags, DBMMODE); 218564562Sgshapiro if (ret != 0) 218664562Sgshapiro { 218773188Sgshapiro#ifdef DB_OLD_VERSION 218873188Sgshapiro if (ret == DB_OLD_VERSION) 218973188Sgshapiro ret = EINVAL; 219073188Sgshapiro#endif /* DB_OLD_VERSION */ 219164562Sgshapiro (void) db->close(db, 0); 219264562Sgshapiro db = NULL; 219364562Sgshapiro } 219464562Sgshapiro } 219564562Sgshapiro errno = ret; 219664562Sgshapiro# else /* DB_VERSION_MAJOR > 2 */ 219738032Speter errno = db_open(buf, dbtype, flags, DBMMODE, 219838032Speter NULL, openinfo, &db); 219964562Sgshapiro# endif /* DB_VERSION_MAJOR > 2 */ 220038032Speter } 220164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 220264562Sgshapiro save_errno = errno; 220338032Speter 220464562Sgshapiro# if !LOCK_ON_OPEN 220538032Speter if (mode == O_RDWR) 220638032Speter map->map_lockfd = fd; 220738032Speter else 220838032Speter (void) close(fd); 220964562Sgshapiro# endif /* !LOCK_ON_OPEN */ 221038032Speter 221138032Speter if (db == NULL) 221238032Speter { 221338032Speter if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) && 221490792Sgshapiro aliaswait(map, ".db", false)) 221590792Sgshapiro return true; 221664562Sgshapiro# if !LOCK_ON_OPEN 221738032Speter if (map->map_lockfd >= 0) 221838032Speter (void) close(map->map_lockfd); 221964562Sgshapiro# endif /* !LOCK_ON_OPEN */ 222064562Sgshapiro errno = save_errno; 222138032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 222238032Speter syserr("Cannot open %s database %s", 222338032Speter mapclassname, buf); 222490792Sgshapiro return false; 222538032Speter } 222638032Speter 222764562Sgshapiro# if DB_VERSION_MAJOR < 2 222838032Speter fd = db->fd(db); 222964562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 223038032Speter fd = -1; 223138032Speter errno = db->fd(db, &fd); 223264562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 223338032Speter if (filechanged(buf, fd, &st)) 223438032Speter { 223564562Sgshapiro save_errno = errno; 223664562Sgshapiro# if DB_VERSION_MAJOR < 2 223764562Sgshapiro (void) db->close(db); 223864562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 223938032Speter errno = db->close(db, 0); 224064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 224164562Sgshapiro# if !LOCK_ON_OPEN 224238032Speter if (map->map_lockfd >= 0) 224364562Sgshapiro (void) close(map->map_lockfd); 224464562Sgshapiro# endif /* !LOCK_ON_OPEN */ 224538032Speter errno = save_errno; 224638032Speter syserr("db_map_open(%s): file changed after open", buf); 224790792Sgshapiro return false; 224838032Speter } 224938032Speter 225038032Speter if (mode == O_RDWR) 225138032Speter map->map_mflags |= MF_LOCKED; 225264562Sgshapiro# if LOCK_ON_OPEN 225338032Speter if (fd >= 0 && mode == O_RDONLY) 225438032Speter { 225538032Speter (void) lockfile(fd, buf, NULL, LOCK_UN); 225638032Speter } 225764562Sgshapiro# endif /* LOCK_ON_OPEN */ 225838032Speter 225938032Speter /* try to make sure that at least the database header is on disk */ 226038032Speter if (mode == O_RDWR) 226138032Speter { 226238032Speter (void) db->sync(db, 0); 226342575Speter if (geteuid() == 0 && TrustedUid != 0) 226438032Speter { 226564562Sgshapiro# if HASFCHOWN 226642575Speter if (fchown(fd, TrustedUid, -1) < 0) 226738032Speter { 226838032Speter int err = errno; 226938032Speter 227038032Speter sm_syslog(LOG_ALERT, NOQID, 227138032Speter "ownership change on %s failed: %s", 227290792Sgshapiro buf, sm_errstring(err)); 227338032Speter message("050 ownership change on %s failed: %s", 227490792Sgshapiro buf, sm_errstring(err)); 227538032Speter } 227690792Sgshapiro# else /* HASFCHOWN */ 227790792Sgshapiro sm_syslog(LOG_ALERT, NOQID, 227890792Sgshapiro "no fchown(): cannot change ownership on %s", 227990792Sgshapiro map->map_file); 228090792Sgshapiro message("050 no fchown(): cannot change ownership on %s", 228190792Sgshapiro map->map_file); 228264562Sgshapiro# endif /* HASFCHOWN */ 228338032Speter } 228438032Speter } 228538032Speter 228664562Sgshapiro map->map_db2 = (ARBPTR_T) db; 228764562Sgshapiro 228864562Sgshapiro /* 228964562Sgshapiro ** Need to set map_mtime before the call to aliaswait() 229064562Sgshapiro ** as aliaswait() will call map_lookup() which requires 229164562Sgshapiro ** map_mtime to be set 229264562Sgshapiro */ 229364562Sgshapiro 229438032Speter if (fd >= 0 && fstat(fd, &st) >= 0) 229538032Speter map->map_mtime = st.st_mtime; 229638032Speter 229738032Speter if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) && 229890792Sgshapiro !aliaswait(map, ".db", true)) 229990792Sgshapiro return false; 230090792Sgshapiro return true; 230138032Speter} 230238032Speter 230338032Speter 230438032Speter/* 230538032Speter** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 230638032Speter*/ 230738032Speter 230838032Speterchar * 230938032Speterdb_map_lookup(map, name, av, statp) 231038032Speter MAP *map; 231138032Speter char *name; 231238032Speter char **av; 231338032Speter int *statp; 231438032Speter{ 231538032Speter DBT key, val; 231638032Speter register DB *db = (DB *) map->map_db2; 231738032Speter int i; 231838032Speter int st; 231964562Sgshapiro int save_errno; 232038032Speter int fd; 232138032Speter struct stat stbuf; 232238032Speter char keybuf[MAXNAME + 1]; 232398121Sgshapiro char buf[MAXPATHLEN]; 232438032Speter 2325168515Sgshapiro memset(&key, '\0', sizeof(key)); 2326168515Sgshapiro memset(&val, '\0', sizeof(val)); 232738032Speter 232838032Speter if (tTd(38, 20)) 232990792Sgshapiro sm_dprintf("db_map_lookup(%s, %s)\n", 233038032Speter map->map_mname, name); 233138032Speter 2332168515Sgshapiro if (sm_strlcpy(buf, map->map_file, sizeof(buf)) >= sizeof(buf)) 233398121Sgshapiro { 233498121Sgshapiro errno = 0; 233598121Sgshapiro if (!bitset(MF_OPTIONAL, map->map_mflags)) 233698121Sgshapiro syserr("map \"%s\": map file %s name too long", 233798121Sgshapiro map->map_mname, map->map_file); 233898121Sgshapiro return NULL; 233998121Sgshapiro } 234098121Sgshapiro i = strlen(buf); 234138032Speter if (i > 3 && strcmp(&buf[i - 3], ".db") == 0) 234238032Speter buf[i - 3] = '\0'; 234338032Speter 234438032Speter key.size = strlen(name); 2345168515Sgshapiro if (key.size > sizeof(keybuf) - 1) 2346168515Sgshapiro key.size = sizeof(keybuf) - 1; 234738032Speter key.data = keybuf; 234864562Sgshapiro memmove(keybuf, name, key.size); 234938032Speter keybuf[key.size] = '\0'; 235038032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 235138032Speter makelower(keybuf); 235238032Speter lockdb: 235364562Sgshapiro# if DB_VERSION_MAJOR < 2 235438032Speter fd = db->fd(db); 235564562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 235638032Speter fd = -1; 235738032Speter errno = db->fd(db, &fd); 235864562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 235938032Speter if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 236038032Speter (void) lockfile(fd, buf, ".db", LOCK_SH); 236138032Speter if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime) 236238032Speter { 236338032Speter /* Reopen the database to sync the cache */ 236438032Speter int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR 236538032Speter : O_RDONLY; 236638032Speter 236764562Sgshapiro if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 236864562Sgshapiro (void) lockfile(fd, buf, ".db", LOCK_UN); 236977349Sgshapiro map->map_mflags |= MF_CLOSING; 237038032Speter map->map_class->map_close(map); 237177349Sgshapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 237238032Speter if (map->map_class->map_open(map, omode)) 237338032Speter { 237438032Speter map->map_mflags |= MF_OPEN; 237590792Sgshapiro map->map_pid = CurrentPid; 2376203004Sgshapiro if ((omode & O_ACCMODE) == O_RDWR) 237738032Speter map->map_mflags |= MF_WRITABLE; 237838032Speter db = (DB *) map->map_db2; 237938032Speter goto lockdb; 238038032Speter } 238138032Speter else 238238032Speter { 238338032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 238438032Speter { 238538032Speter extern MAPCLASS BogusMapClass; 238638032Speter 238738032Speter *statp = EX_TEMPFAIL; 238890792Sgshapiro map->map_orgclass = map->map_class; 238938032Speter map->map_class = &BogusMapClass; 239038032Speter map->map_mflags |= MF_OPEN; 239190792Sgshapiro map->map_pid = CurrentPid; 239238032Speter syserr("Cannot reopen DB database %s", 239338032Speter map->map_file); 239438032Speter } 239538032Speter return NULL; 239638032Speter } 239738032Speter } 239838032Speter 239938032Speter st = 1; 240038032Speter if (bitset(MF_TRY0NULL, map->map_mflags)) 240138032Speter { 240264562Sgshapiro# if DB_VERSION_MAJOR < 2 240338032Speter st = db->get(db, &key, &val, 0); 240464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 240538032Speter errno = db->get(db, NULL, &key, &val, 0); 240638032Speter switch (errno) 240738032Speter { 240838032Speter case DB_NOTFOUND: 240938032Speter case DB_KEYEMPTY: 241038032Speter st = 1; 241138032Speter break; 241238032Speter 241338032Speter case 0: 241438032Speter st = 0; 241538032Speter break; 241638032Speter 241738032Speter default: 241838032Speter st = -1; 241938032Speter break; 242038032Speter } 242164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 242238032Speter if (st == 0) 242338032Speter map->map_mflags &= ~MF_TRY1NULL; 242438032Speter } 242538032Speter if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags)) 242638032Speter { 242738032Speter key.size++; 242864562Sgshapiro# if DB_VERSION_MAJOR < 2 242938032Speter st = db->get(db, &key, &val, 0); 243064562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 243138032Speter errno = db->get(db, NULL, &key, &val, 0); 243238032Speter switch (errno) 243338032Speter { 243438032Speter case DB_NOTFOUND: 243538032Speter case DB_KEYEMPTY: 243638032Speter st = 1; 243738032Speter break; 243838032Speter 243938032Speter case 0: 244038032Speter st = 0; 244138032Speter break; 244238032Speter 244338032Speter default: 244438032Speter st = -1; 244538032Speter break; 244638032Speter } 244764562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 244838032Speter if (st == 0) 244938032Speter map->map_mflags &= ~MF_TRY0NULL; 245038032Speter } 245164562Sgshapiro save_errno = errno; 245238032Speter if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags)) 245338032Speter (void) lockfile(fd, buf, ".db", LOCK_UN); 245438032Speter if (st != 0) 245538032Speter { 245664562Sgshapiro errno = save_errno; 245738032Speter if (st < 0) 245838032Speter syserr("db_map_lookup: get (%s)", name); 245938032Speter return NULL; 246038032Speter } 246138032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 246238032Speter return map_rewrite(map, name, strlen(name), NULL); 246338032Speter else 246438032Speter return map_rewrite(map, val.data, val.size, av); 246538032Speter} 246638032Speter 246738032Speter 246838032Speter/* 246938032Speter** DB_MAP_STORE -- store a datum in the NEWDB database 247038032Speter*/ 247138032Speter 247238032Spetervoid 247338032Speterdb_map_store(map, lhs, rhs) 247438032Speter register MAP *map; 247538032Speter char *lhs; 247638032Speter char *rhs; 247738032Speter{ 247864562Sgshapiro int status; 247938032Speter DBT key; 248038032Speter DBT data; 248138032Speter register DB *db = map->map_db2; 248238032Speter char keybuf[MAXNAME + 1]; 248338032Speter 2484168515Sgshapiro memset(&key, '\0', sizeof(key)); 2485168515Sgshapiro memset(&data, '\0', sizeof(data)); 248638032Speter 248738032Speter if (tTd(38, 12)) 248890792Sgshapiro sm_dprintf("db_map_store(%s, %s, %s)\n", 248938032Speter map->map_mname, lhs, rhs); 249038032Speter 249138032Speter key.size = strlen(lhs); 249238032Speter key.data = lhs; 249338032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 249438032Speter { 2495168515Sgshapiro if (key.size > sizeof(keybuf) - 1) 2496168515Sgshapiro key.size = sizeof(keybuf) - 1; 249764562Sgshapiro memmove(keybuf, key.data, key.size); 249838032Speter keybuf[key.size] = '\0'; 249938032Speter makelower(keybuf); 250038032Speter key.data = keybuf; 250138032Speter } 250238032Speter 250338032Speter data.size = strlen(rhs); 250438032Speter data.data = rhs; 250538032Speter 250638032Speter if (bitset(MF_INCLNULL, map->map_mflags)) 250738032Speter { 250838032Speter key.size++; 250938032Speter data.size++; 251038032Speter } 251138032Speter 251264562Sgshapiro# if DB_VERSION_MAJOR < 2 251364562Sgshapiro status = db->put(db, &key, &data, R_NOOVERWRITE); 251464562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 251538032Speter errno = db->put(db, NULL, &key, &data, DB_NOOVERWRITE); 251638032Speter switch (errno) 251738032Speter { 251838032Speter case DB_KEYEXIST: 251964562Sgshapiro status = 1; 252038032Speter break; 252138032Speter 252238032Speter case 0: 252364562Sgshapiro status = 0; 252438032Speter break; 252538032Speter 252638032Speter default: 252764562Sgshapiro status = -1; 252838032Speter break; 252938032Speter } 253064562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 253164562Sgshapiro if (status > 0) 253238032Speter { 253338032Speter if (!bitset(MF_APPEND, map->map_mflags)) 253438032Speter message("050 Warning: duplicate alias name %s", lhs); 253538032Speter else 253638032Speter { 253738032Speter static char *buf = NULL; 253838032Speter static int bufsiz = 0; 253938032Speter DBT old; 254038032Speter 2541168515Sgshapiro memset(&old, '\0', sizeof(old)); 254238032Speter 254364562Sgshapiro old.data = db_map_lookup(map, key.data, 254490792Sgshapiro (char **) NULL, &status); 254538032Speter if (old.data != NULL) 254638032Speter { 254738032Speter old.size = strlen(old.data); 254890792Sgshapiro if (data.size + old.size + 2 > (size_t) bufsiz) 254938032Speter { 255038032Speter if (buf != NULL) 255177349Sgshapiro sm_free(buf); 255238032Speter bufsiz = data.size + old.size + 2; 255390792Sgshapiro buf = sm_pmalloc_x(bufsiz); 255438032Speter } 255590792Sgshapiro (void) sm_strlcpyn(buf, bufsiz, 3, 255690792Sgshapiro (char *) data.data, ",", 255790792Sgshapiro (char *) old.data); 255838032Speter data.size = data.size + old.size + 1; 255938032Speter data.data = buf; 256038032Speter if (tTd(38, 9)) 256190792Sgshapiro sm_dprintf("db_map_store append=%s\n", 256264562Sgshapiro (char *) data.data); 256338032Speter } 256438032Speter } 256564562Sgshapiro# if DB_VERSION_MAJOR < 2 256664562Sgshapiro status = db->put(db, &key, &data, 0); 256764562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 256864562Sgshapiro status = errno = db->put(db, NULL, &key, &data, 0); 256964562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 257038032Speter } 257164562Sgshapiro if (status != 0) 257238032Speter syserr("readaliases: db put (%s)", lhs); 257338032Speter} 257438032Speter 257538032Speter 257638032Speter/* 257738032Speter** DB_MAP_CLOSE -- add distinguished entries and close the database 257838032Speter*/ 257938032Speter 258038032Spetervoid 258138032Speterdb_map_close(map) 258238032Speter MAP *map; 258338032Speter{ 258438032Speter register DB *db = map->map_db2; 258538032Speter 258638032Speter if (tTd(38, 9)) 258790792Sgshapiro sm_dprintf("db_map_close(%s, %s, %lx)\n", 258838032Speter map->map_mname, map->map_file, map->map_mflags); 258938032Speter 259038032Speter if (bitset(MF_WRITABLE, map->map_mflags)) 259138032Speter { 259238032Speter /* write out the distinguished alias */ 259338032Speter db_map_store(map, "@", "@"); 259438032Speter } 259538032Speter 259638032Speter (void) db->sync(db, 0); 259738032Speter 259864562Sgshapiro# if !LOCK_ON_OPEN 259938032Speter if (map->map_lockfd >= 0) 260038032Speter (void) close(map->map_lockfd); 260164562Sgshapiro# endif /* !LOCK_ON_OPEN */ 260238032Speter 260364562Sgshapiro# if DB_VERSION_MAJOR < 2 260438032Speter if (db->close(db) != 0) 260564562Sgshapiro# else /* DB_VERSION_MAJOR < 2 */ 260642575Speter /* 260742575Speter ** Berkeley DB can use internal shared memory 260842575Speter ** locking for its memory pool. Closing a map 260942575Speter ** opened by another process will interfere 261042575Speter ** with the shared memory and locks of the parent 261142575Speter ** process leaving things in a bad state. 261243730Speter */ 261343730Speter 261443730Speter /* 261542575Speter ** If this map was not opened by the current 261643730Speter ** process, do not close the map but recover 261742575Speter ** the file descriptor. 261842575Speter */ 261990792Sgshapiro 262090792Sgshapiro if (map->map_pid != CurrentPid) 262142575Speter { 262242575Speter int fd = -1; 262342575Speter 262442575Speter errno = db->fd(db, &fd); 262542575Speter if (fd >= 0) 262642575Speter (void) close(fd); 262742575Speter return; 262842575Speter } 262942575Speter 263038032Speter if ((errno = db->close(db, 0)) != 0) 263164562Sgshapiro# endif /* DB_VERSION_MAJOR < 2 */ 263242575Speter syserr("db_map_close(%s, %s, %lx): db close failure", 263342575Speter map->map_mname, map->map_file, map->map_mflags); 263438032Speter} 263564562Sgshapiro#endif /* NEWDB */ 263690792Sgshapiro/* 263738032Speter** NIS Modules 263838032Speter*/ 263938032Speter 264090792Sgshapiro#if NIS 264138032Speter 264238032Speter# ifndef YPERR_BUSY 264338032Speter# define YPERR_BUSY 16 264464562Sgshapiro# endif /* ! YPERR_BUSY */ 264538032Speter 264638032Speter/* 264738032Speter** NIS_MAP_OPEN -- open DBM map 264838032Speter*/ 264938032Speter 265038032Speterbool 265138032Speternis_map_open(map, mode) 265238032Speter MAP *map; 265338032Speter int mode; 265438032Speter{ 265538032Speter int yperr; 265638032Speter register char *p; 265738032Speter auto char *vp; 265838032Speter auto int vsize; 265938032Speter 266038032Speter if (tTd(38, 2)) 266190792Sgshapiro sm_dprintf("nis_map_open(%s, %s, %d)\n", 266238032Speter map->map_mname, map->map_file, mode); 266338032Speter 266438032Speter mode &= O_ACCMODE; 266538032Speter if (mode != O_RDONLY) 266638032Speter { 266738032Speter /* issue a pseudo-error message */ 266890792Sgshapiro errno = SM_EMAPCANTWRITE; 266990792Sgshapiro return false; 267038032Speter } 267138032Speter 267238032Speter p = strchr(map->map_file, '@'); 267338032Speter if (p != NULL) 267438032Speter { 267538032Speter *p++ = '\0'; 267638032Speter if (*p != '\0') 267738032Speter map->map_domain = p; 267838032Speter } 267938032Speter 268038032Speter if (*map->map_file == '\0') 268138032Speter map->map_file = "mail.aliases"; 268238032Speter 268338032Speter if (map->map_domain == NULL) 268438032Speter { 268538032Speter yperr = yp_get_default_domain(&map->map_domain); 268638032Speter if (yperr != 0) 268738032Speter { 268838032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 268994334Sgshapiro syserr("451 4.3.5 NIS map %s specified, but NIS not running", 269064562Sgshapiro map->map_file); 269190792Sgshapiro return false; 269238032Speter } 269338032Speter } 269438032Speter 269538032Speter /* check to see if this map actually exists */ 269664562Sgshapiro vp = NULL; 269738032Speter yperr = yp_match(map->map_domain, map->map_file, "@", 1, 269838032Speter &vp, &vsize); 269938032Speter if (tTd(38, 10)) 270090792Sgshapiro sm_dprintf("nis_map_open: yp_match(@, %s, %s) => %s\n", 270138032Speter map->map_domain, map->map_file, yperr_string(yperr)); 270264562Sgshapiro if (vp != NULL) 270377349Sgshapiro sm_free(vp); 270464562Sgshapiro 270538032Speter if (yperr == 0 || yperr == YPERR_KEY || yperr == YPERR_BUSY) 270638032Speter { 270738032Speter /* 270838032Speter ** We ought to be calling aliaswait() here if this is an 270938032Speter ** alias file, but powerful HP-UX NIS servers apparently 271038032Speter ** don't insert the @:@ token into the alias map when it 271138032Speter ** is rebuilt, so aliaswait() just hangs. I hate HP-UX. 271238032Speter */ 271338032Speter 271464562Sgshapiro# if 0 271538032Speter if (!bitset(MF_ALIAS, map->map_mflags) || 271690792Sgshapiro aliaswait(map, NULL, true)) 271764562Sgshapiro# endif /* 0 */ 271890792Sgshapiro return true; 271938032Speter } 272038032Speter 272138032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 272238032Speter { 272394334Sgshapiro syserr("451 4.3.5 Cannot bind to map %s in domain %s: %s", 272438032Speter map->map_file, map->map_domain, yperr_string(yperr)); 272538032Speter } 272638032Speter 272790792Sgshapiro return false; 272838032Speter} 272938032Speter 273038032Speter 273138032Speter/* 273238032Speter** NIS_MAP_LOOKUP -- look up a datum in a NIS map 273338032Speter*/ 273438032Speter 273538032Speter/* ARGSUSED3 */ 273638032Speterchar * 273738032Speternis_map_lookup(map, name, av, statp) 273838032Speter MAP *map; 273938032Speter char *name; 274038032Speter char **av; 274138032Speter int *statp; 274238032Speter{ 274338032Speter char *vp; 274438032Speter auto int vsize; 274538032Speter int buflen; 274638032Speter int yperr; 274738032Speter char keybuf[MAXNAME + 1]; 274890792Sgshapiro char *SM_NONVOLATILE result = NULL; 274938032Speter 275038032Speter if (tTd(38, 20)) 275190792Sgshapiro sm_dprintf("nis_map_lookup(%s, %s)\n", 275238032Speter map->map_mname, name); 275338032Speter 275438032Speter buflen = strlen(name); 2755168515Sgshapiro if (buflen > sizeof(keybuf) - 1) 2756168515Sgshapiro buflen = sizeof(keybuf) - 1; 275764562Sgshapiro memmove(keybuf, name, buflen); 275838032Speter keybuf[buflen] = '\0'; 275938032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 276038032Speter makelower(keybuf); 276138032Speter yperr = YPERR_KEY; 276264562Sgshapiro vp = NULL; 276338032Speter if (bitset(MF_TRY0NULL, map->map_mflags)) 276438032Speter { 276538032Speter yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 276638032Speter &vp, &vsize); 276738032Speter if (yperr == 0) 276838032Speter map->map_mflags &= ~MF_TRY1NULL; 276938032Speter } 277038032Speter if (yperr == YPERR_KEY && bitset(MF_TRY1NULL, map->map_mflags)) 277138032Speter { 277290792Sgshapiro SM_FREE_CLR(vp); 277338032Speter buflen++; 277438032Speter yperr = yp_match(map->map_domain, map->map_file, keybuf, buflen, 277538032Speter &vp, &vsize); 277638032Speter if (yperr == 0) 277738032Speter map->map_mflags &= ~MF_TRY0NULL; 277838032Speter } 277938032Speter if (yperr != 0) 278038032Speter { 278138032Speter if (yperr != YPERR_KEY && yperr != YPERR_BUSY) 278238032Speter map->map_mflags &= ~(MF_VALID|MF_OPEN); 278364562Sgshapiro if (vp != NULL) 278477349Sgshapiro sm_free(vp); 278538032Speter return NULL; 278638032Speter } 278790792Sgshapiro SM_TRY 278890792Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 278990792Sgshapiro result = map_rewrite(map, name, strlen(name), NULL); 279090792Sgshapiro else 279190792Sgshapiro result = map_rewrite(map, vp, vsize, av); 279290792Sgshapiro SM_FINALLY 279364562Sgshapiro if (vp != NULL) 279477349Sgshapiro sm_free(vp); 279590792Sgshapiro SM_END_TRY 279690792Sgshapiro return result; 279738032Speter} 279838032Speter 279938032Speter 280038032Speter/* 280138032Speter** NIS_GETCANONNAME -- look up canonical name in NIS 280238032Speter*/ 280338032Speter 280464562Sgshapirostatic bool 280538032Speternis_getcanonname(name, hbsize, statp) 280638032Speter char *name; 280738032Speter int hbsize; 280838032Speter int *statp; 280938032Speter{ 281038032Speter char *vp; 281138032Speter auto int vsize; 281238032Speter int keylen; 281338032Speter int yperr; 281490792Sgshapiro static bool try0null = true; 281590792Sgshapiro static bool try1null = true; 281638032Speter static char *yp_domain = NULL; 281738032Speter char host_record[MAXLINE]; 281838032Speter char cbuf[MAXNAME]; 281938032Speter char nbuf[MAXNAME + 1]; 282038032Speter 282138032Speter if (tTd(38, 20)) 282290792Sgshapiro sm_dprintf("nis_getcanonname(%s)\n", name); 282338032Speter 2824168515Sgshapiro if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf)) 282538032Speter { 282638032Speter *statp = EX_UNAVAILABLE; 282790792Sgshapiro return false; 282838032Speter } 282973188Sgshapiro (void) shorten_hostname(nbuf); 283038032Speter keylen = strlen(nbuf); 283138032Speter 283238032Speter if (yp_domain == NULL) 283364562Sgshapiro (void) yp_get_default_domain(&yp_domain); 283438032Speter makelower(nbuf); 283538032Speter yperr = YPERR_KEY; 283664562Sgshapiro vp = NULL; 283738032Speter if (try0null) 283838032Speter { 283938032Speter yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen, 284038032Speter &vp, &vsize); 284138032Speter if (yperr == 0) 284290792Sgshapiro try1null = false; 284338032Speter } 284438032Speter if (yperr == YPERR_KEY && try1null) 284538032Speter { 284690792Sgshapiro SM_FREE_CLR(vp); 284738032Speter keylen++; 284838032Speter yperr = yp_match(yp_domain, "hosts.byname", nbuf, keylen, 284938032Speter &vp, &vsize); 285038032Speter if (yperr == 0) 285190792Sgshapiro try0null = false; 285238032Speter } 285338032Speter if (yperr != 0) 285438032Speter { 285538032Speter if (yperr == YPERR_KEY) 285638032Speter *statp = EX_NOHOST; 285738032Speter else if (yperr == YPERR_BUSY) 285838032Speter *statp = EX_TEMPFAIL; 285938032Speter else 286038032Speter *statp = EX_UNAVAILABLE; 286164562Sgshapiro if (vp != NULL) 286277349Sgshapiro sm_free(vp); 286390792Sgshapiro return false; 286438032Speter } 2865168515Sgshapiro (void) sm_strlcpy(host_record, vp, sizeof(host_record)); 286677349Sgshapiro sm_free(vp); 286738032Speter if (tTd(38, 44)) 286890792Sgshapiro sm_dprintf("got record `%s'\n", host_record); 286990792Sgshapiro vp = strpbrk(host_record, "#\n"); 287090792Sgshapiro if (vp != NULL) 287190792Sgshapiro *vp = '\0'; 2872168515Sgshapiro if (!extract_canonname(nbuf, NULL, host_record, cbuf, sizeof(cbuf))) 287338032Speter { 287438032Speter /* this should not happen, but.... */ 287538032Speter *statp = EX_NOHOST; 287690792Sgshapiro return false; 287738032Speter } 287890792Sgshapiro if (sm_strlcpy(name, cbuf, hbsize) >= hbsize) 287938032Speter { 288038032Speter *statp = EX_UNAVAILABLE; 288190792Sgshapiro return false; 288238032Speter } 288338032Speter *statp = EX_OK; 288490792Sgshapiro return true; 288538032Speter} 288638032Speter 288764562Sgshapiro#endif /* NIS */ 288890792Sgshapiro/* 288938032Speter** NISPLUS Modules 289038032Speter** 289138032Speter** This code donated by Sun Microsystems. 289238032Speter*/ 289338032Speter 289490792Sgshapiro#if NISPLUS 289538032Speter 289664562Sgshapiro# undef NIS /* symbol conflict in nis.h */ 289764562Sgshapiro# undef T_UNSPEC /* symbol conflict in nis.h -> ... -> sys/tiuser.h */ 289864562Sgshapiro# include <rpcsvc/nis.h> 289964562Sgshapiro# include <rpcsvc/nislib.h> 2900249729Sgshapiro# ifndef NIS_TABLE_OBJ 2901249729Sgshapiro# define NIS_TABLE_OBJ TABLE_OBJ 2902249729Sgshapiro# endif /* NIS_TABLE_OBJ */ 290338032Speter 290464562Sgshapiro# define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val 290564562Sgshapiro# define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name 290664562Sgshapiro# define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len) 290764562Sgshapiro# define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.') 290838032Speter 290938032Speter/* 291038032Speter** NISPLUS_MAP_OPEN -- open nisplus table 291138032Speter*/ 291238032Speter 291338032Speterbool 291438032Speternisplus_map_open(map, mode) 291538032Speter MAP *map; 291638032Speter int mode; 291738032Speter{ 291838032Speter nis_result *res = NULL; 291938032Speter int retry_cnt, max_col, i; 292038032Speter char qbuf[MAXLINE + NIS_MAXNAMELEN]; 292138032Speter 292238032Speter if (tTd(38, 2)) 292390792Sgshapiro sm_dprintf("nisplus_map_open(%s, %s, %d)\n", 292438032Speter map->map_mname, map->map_file, mode); 292538032Speter 292638032Speter mode &= O_ACCMODE; 292738032Speter if (mode != O_RDONLY) 292838032Speter { 292938032Speter errno = EPERM; 293090792Sgshapiro return false; 293138032Speter } 293238032Speter 293338032Speter if (*map->map_file == '\0') 293438032Speter map->map_file = "mail_aliases.org_dir"; 293538032Speter 293638032Speter if (PARTIAL_NAME(map->map_file) && map->map_domain == NULL) 293738032Speter { 293838032Speter /* set default NISPLUS Domain to $m */ 293938032Speter map->map_domain = newstr(nisplus_default_domain()); 294038032Speter if (tTd(38, 2)) 294190792Sgshapiro sm_dprintf("nisplus_map_open(%s): using domain %s\n", 294264562Sgshapiro map->map_file, map->map_domain); 294338032Speter } 294438032Speter if (!PARTIAL_NAME(map->map_file)) 294538032Speter { 294638032Speter map->map_domain = newstr(""); 2947168515Sgshapiro (void) sm_strlcpy(qbuf, map->map_file, sizeof(qbuf)); 294838032Speter } 294938032Speter else 295038032Speter { 295138032Speter /* check to see if this map actually exists */ 2952168515Sgshapiro (void) sm_strlcpyn(qbuf, sizeof(qbuf), 3, 295390792Sgshapiro map->map_file, ".", map->map_domain); 295438032Speter } 295538032Speter 295638032Speter retry_cnt = 0; 295738032Speter while (res == NULL || res->status != NIS_SUCCESS) 295838032Speter { 295938032Speter res = nis_lookup(qbuf, FOLLOW_LINKS); 296038032Speter switch (res->status) 296138032Speter { 296238032Speter case NIS_SUCCESS: 296338032Speter break; 296438032Speter 296538032Speter case NIS_TRYAGAIN: 296638032Speter case NIS_RPCERROR: 296738032Speter case NIS_NAMEUNREACHABLE: 296838032Speter if (retry_cnt++ > 4) 296938032Speter { 297038032Speter errno = EAGAIN; 297190792Sgshapiro return false; 297238032Speter } 297338032Speter /* try not to overwhelm hosed server */ 297438032Speter sleep(2); 297538032Speter break; 297638032Speter 297738032Speter default: /* all other nisplus errors */ 297864562Sgshapiro# if 0 297938032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 298094334Sgshapiro syserr("451 4.3.5 Cannot find table %s.%s: %s", 298138032Speter map->map_file, map->map_domain, 298238032Speter nis_sperrno(res->status)); 298364562Sgshapiro# endif /* 0 */ 298438032Speter errno = EAGAIN; 298590792Sgshapiro return false; 298638032Speter } 298738032Speter } 298838032Speter 298938032Speter if (NIS_RES_NUMOBJ(res) != 1 || 2990249729Sgshapiro (NIS_RES_OBJECT(res)->zo_data.zo_type != NIS_TABLE_OBJ)) 299138032Speter { 299238032Speter if (tTd(38, 10)) 299390792Sgshapiro sm_dprintf("nisplus_map_open: %s is not a table\n", qbuf); 299464562Sgshapiro# if 0 299538032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 299694334Sgshapiro syserr("451 4.3.5 %s.%s: %s is not a table", 299738032Speter map->map_file, map->map_domain, 299838032Speter nis_sperrno(res->status)); 299964562Sgshapiro# endif /* 0 */ 300038032Speter errno = EBADF; 300190792Sgshapiro return false; 300238032Speter } 300338032Speter /* default key column is column 0 */ 300438032Speter if (map->map_keycolnm == NULL) 300538032Speter map->map_keycolnm = newstr(COL_NAME(res,0)); 300638032Speter 300738032Speter max_col = COL_MAX(res); 300838032Speter 300938032Speter /* verify the key column exist */ 301090792Sgshapiro for (i = 0; i < max_col; i++) 301138032Speter { 301264562Sgshapiro if (strcmp(map->map_keycolnm, COL_NAME(res,i)) == 0) 301338032Speter break; 301438032Speter } 301538032Speter if (i == max_col) 301638032Speter { 301738032Speter if (tTd(38, 2)) 301890792Sgshapiro sm_dprintf("nisplus_map_open(%s): can not find key column %s\n", 301938032Speter map->map_file, map->map_keycolnm); 302038032Speter errno = ENOENT; 302190792Sgshapiro return false; 302238032Speter } 302338032Speter 302438032Speter /* default value column is the last column */ 302538032Speter if (map->map_valcolnm == NULL) 302638032Speter { 302738032Speter map->map_valcolno = max_col - 1; 302890792Sgshapiro return true; 302938032Speter } 303038032Speter 303164562Sgshapiro for (i = 0; i< max_col; i++) 303238032Speter { 303338032Speter if (strcmp(map->map_valcolnm, COL_NAME(res,i)) == 0) 303438032Speter { 303538032Speter map->map_valcolno = i; 303690792Sgshapiro return true; 303738032Speter } 303838032Speter } 303938032Speter 304038032Speter if (tTd(38, 2)) 304190792Sgshapiro sm_dprintf("nisplus_map_open(%s): can not find column %s\n", 304264562Sgshapiro map->map_file, map->map_keycolnm); 304338032Speter errno = ENOENT; 304490792Sgshapiro return false; 304538032Speter} 304638032Speter 304738032Speter 304838032Speter/* 304938032Speter** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table 305038032Speter*/ 305138032Speter 305238032Speterchar * 305338032Speternisplus_map_lookup(map, name, av, statp) 305438032Speter MAP *map; 305538032Speter char *name; 305638032Speter char **av; 305738032Speter int *statp; 305838032Speter{ 305938032Speter char *p; 306038032Speter auto int vsize; 306138032Speter char *skp; 306238032Speter int skleft; 306338032Speter char search_key[MAXNAME + 4]; 306438032Speter char qbuf[MAXLINE + NIS_MAXNAMELEN]; 306538032Speter nis_result *result; 306638032Speter 306738032Speter if (tTd(38, 20)) 306890792Sgshapiro sm_dprintf("nisplus_map_lookup(%s, %s)\n", 306938032Speter map->map_mname, name); 307038032Speter 307138032Speter if (!bitset(MF_OPEN, map->map_mflags)) 307238032Speter { 307338032Speter if (nisplus_map_open(map, O_RDONLY)) 307442575Speter { 307538032Speter map->map_mflags |= MF_OPEN; 307690792Sgshapiro map->map_pid = CurrentPid; 307742575Speter } 307838032Speter else 307938032Speter { 308038032Speter *statp = EX_UNAVAILABLE; 308138032Speter return NULL; 308238032Speter } 308338032Speter } 308438032Speter 308538032Speter /* 308638032Speter ** Copy the name to the key buffer, escaping double quote characters 308738032Speter ** by doubling them and quoting "]" and "," to avoid having the 308838032Speter ** NIS+ parser choke on them. 308938032Speter */ 309038032Speter 3091168515Sgshapiro skleft = sizeof(search_key) - 4; 309238032Speter skp = search_key; 309338032Speter for (p = name; *p != '\0' && skleft > 0; p++) 309438032Speter { 309538032Speter switch (*p) 309638032Speter { 309738032Speter case ']': 309838032Speter case ',': 309938032Speter /* quote the character */ 310038032Speter *skp++ = '"'; 310138032Speter *skp++ = *p; 310238032Speter *skp++ = '"'; 310338032Speter skleft -= 3; 310438032Speter break; 310538032Speter 310638032Speter case '"': 310738032Speter /* double the quote */ 310838032Speter *skp++ = '"'; 310938032Speter skleft--; 311064562Sgshapiro /* FALLTHROUGH */ 311138032Speter 311238032Speter default: 311338032Speter *skp++ = *p; 311438032Speter skleft--; 311538032Speter break; 311638032Speter } 311738032Speter } 311838032Speter *skp = '\0'; 311938032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 312038032Speter makelower(search_key); 312138032Speter 312238032Speter /* construct the query */ 312338032Speter if (PARTIAL_NAME(map->map_file)) 3124168515Sgshapiro (void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s.%s", 312538032Speter map->map_keycolnm, search_key, map->map_file, 312638032Speter map->map_domain); 312738032Speter else 3128168515Sgshapiro (void) sm_snprintf(qbuf, sizeof(qbuf), "[%s=%s],%s", 312938032Speter map->map_keycolnm, search_key, map->map_file); 313038032Speter 313138032Speter if (tTd(38, 20)) 313290792Sgshapiro sm_dprintf("qbuf=%s\n", qbuf); 313338032Speter result = nis_list(qbuf, FOLLOW_LINKS | FOLLOW_PATH, NULL, NULL); 313438032Speter if (result->status == NIS_SUCCESS) 313538032Speter { 313638032Speter int count; 313738032Speter char *str; 313838032Speter 313938032Speter if ((count = NIS_RES_NUMOBJ(result)) != 1) 314038032Speter { 314138032Speter if (LogLevel > 10) 314238032Speter sm_syslog(LOG_WARNING, CurEnv->e_id, 314364562Sgshapiro "%s: lookup error, expected 1 entry, got %d", 314464562Sgshapiro map->map_file, count); 314538032Speter 314638032Speter /* ignore second entry */ 314738032Speter if (tTd(38, 20)) 314890792Sgshapiro sm_dprintf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n", 314938032Speter name, count); 315038032Speter } 315138032Speter 315238032Speter p = ((NIS_RES_OBJECT(result))->EN_col(map->map_valcolno)); 315338032Speter /* set the length of the result */ 315438032Speter if (p == NULL) 315538032Speter p = ""; 315638032Speter vsize = strlen(p); 315738032Speter if (tTd(38, 20)) 315890792Sgshapiro sm_dprintf("nisplus_map_lookup(%s), found %s\n", 315938032Speter name, p); 316038032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 316138032Speter str = map_rewrite(map, name, strlen(name), NULL); 316238032Speter else 316338032Speter str = map_rewrite(map, p, vsize, av); 316438032Speter nis_freeresult(result); 316538032Speter *statp = EX_OK; 316638032Speter return str; 316738032Speter } 316838032Speter else 316938032Speter { 317038032Speter if (result->status == NIS_NOTFOUND) 317138032Speter *statp = EX_NOTFOUND; 317238032Speter else if (result->status == NIS_TRYAGAIN) 317338032Speter *statp = EX_TEMPFAIL; 317438032Speter else 317538032Speter { 317638032Speter *statp = EX_UNAVAILABLE; 317738032Speter map->map_mflags &= ~(MF_VALID|MF_OPEN); 317838032Speter } 317938032Speter } 318038032Speter if (tTd(38, 20)) 318190792Sgshapiro sm_dprintf("nisplus_map_lookup(%s), failed\n", name); 318238032Speter nis_freeresult(result); 318338032Speter return NULL; 318438032Speter} 318538032Speter 318638032Speter 318738032Speter 318838032Speter/* 318938032Speter** NISPLUS_GETCANONNAME -- look up canonical name in NIS+ 319038032Speter*/ 319138032Speter 319264562Sgshapirostatic bool 319338032Speternisplus_getcanonname(name, hbsize, statp) 319438032Speter char *name; 319538032Speter int hbsize; 319638032Speter int *statp; 319738032Speter{ 319838032Speter char *vp; 319938032Speter auto int vsize; 320038032Speter nis_result *result; 320138032Speter char *p; 320238032Speter char nbuf[MAXNAME + 1]; 320338032Speter char qbuf[MAXLINE + NIS_MAXNAMELEN]; 320438032Speter 3205168515Sgshapiro if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf)) 320638032Speter { 320738032Speter *statp = EX_UNAVAILABLE; 320890792Sgshapiro return false; 320938032Speter } 321073188Sgshapiro (void) shorten_hostname(nbuf); 321138032Speter 321238032Speter p = strchr(nbuf, '.'); 321338032Speter if (p == NULL) 321438032Speter { 321538032Speter /* single token */ 3216168515Sgshapiro (void) sm_snprintf(qbuf, sizeof(qbuf), 321790792Sgshapiro "[name=%s],hosts.org_dir", nbuf); 321838032Speter } 321938032Speter else if (p[1] != '\0') 322038032Speter { 322138032Speter /* multi token -- take only first token in nbuf */ 322238032Speter *p = '\0'; 3223168515Sgshapiro (void) sm_snprintf(qbuf, sizeof(qbuf), 322490792Sgshapiro "[name=%s],hosts.org_dir.%s", nbuf, &p[1]); 322538032Speter } 322638032Speter else 322738032Speter { 322838032Speter *statp = EX_NOHOST; 322990792Sgshapiro return false; 323038032Speter } 323138032Speter 323238032Speter if (tTd(38, 20)) 323394334Sgshapiro sm_dprintf("\nnisplus_getcanonname(%s), qbuf=%s\n", 323490792Sgshapiro name, qbuf); 323538032Speter 323638032Speter result = nis_list(qbuf, EXPAND_NAME|FOLLOW_LINKS|FOLLOW_PATH, 323790792Sgshapiro NULL, NULL); 323838032Speter 323938032Speter if (result->status == NIS_SUCCESS) 324038032Speter { 324138032Speter int count; 324238032Speter char *domain; 324338032Speter 324438032Speter if ((count = NIS_RES_NUMOBJ(result)) != 1) 324538032Speter { 324638032Speter if (LogLevel > 10) 324738032Speter sm_syslog(LOG_WARNING, CurEnv->e_id, 324864562Sgshapiro "nisplus_getcanonname: lookup error, expected 1 entry, got %d", 324964562Sgshapiro count); 325038032Speter 325138032Speter /* ignore second entry */ 325238032Speter if (tTd(38, 20)) 325394334Sgshapiro sm_dprintf("nisplus_getcanonname(%s), got %d entries, all but first ignored\n", 325490792Sgshapiro name, count); 325538032Speter } 325638032Speter 325738032Speter if (tTd(38, 20)) 325894334Sgshapiro sm_dprintf("nisplus_getcanonname(%s), found in directory \"%s\"\n", 325990792Sgshapiro name, (NIS_RES_OBJECT(result))->zo_domain); 326038032Speter 326138032Speter 326238032Speter vp = ((NIS_RES_OBJECT(result))->EN_col(0)); 326338032Speter vsize = strlen(vp); 326438032Speter if (tTd(38, 20)) 326590792Sgshapiro sm_dprintf("nisplus_getcanonname(%s), found %s\n", 326690792Sgshapiro name, vp); 326738032Speter if (strchr(vp, '.') != NULL) 326838032Speter { 326938032Speter domain = ""; 327038032Speter } 327138032Speter else 327238032Speter { 327338032Speter domain = macvalue('m', CurEnv); 327438032Speter if (domain == NULL) 327538032Speter domain = ""; 327638032Speter } 327738032Speter if (hbsize > vsize + (int) strlen(domain) + 1) 327838032Speter { 327938032Speter if (domain[0] == '\0') 328090792Sgshapiro (void) sm_strlcpy(name, vp, hbsize); 328138032Speter else 328290792Sgshapiro (void) sm_snprintf(name, hbsize, 328390792Sgshapiro "%s.%s", vp, domain); 328438032Speter *statp = EX_OK; 328538032Speter } 328638032Speter else 328738032Speter *statp = EX_NOHOST; 328838032Speter nis_freeresult(result); 328990792Sgshapiro return true; 329038032Speter } 329138032Speter else 329238032Speter { 329338032Speter if (result->status == NIS_NOTFOUND) 329438032Speter *statp = EX_NOHOST; 329538032Speter else if (result->status == NIS_TRYAGAIN) 329638032Speter *statp = EX_TEMPFAIL; 329738032Speter else 329838032Speter *statp = EX_UNAVAILABLE; 329938032Speter } 330038032Speter if (tTd(38, 20)) 330190792Sgshapiro sm_dprintf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n", 330290792Sgshapiro name, result->status, *statp); 330338032Speter nis_freeresult(result); 330490792Sgshapiro return false; 330538032Speter} 330638032Speter 330738032Speterchar * 330838032Speternisplus_default_domain() 330938032Speter{ 331038032Speter static char default_domain[MAXNAME + 1] = ""; 331138032Speter char *p; 331238032Speter 331338032Speter if (default_domain[0] != '\0') 331464562Sgshapiro return default_domain; 331538032Speter 331638032Speter p = nis_local_directory(); 3317168515Sgshapiro (void) sm_strlcpy(default_domain, p, sizeof(default_domain)); 331838032Speter return default_domain; 331938032Speter} 332038032Speter 332138032Speter#endif /* NISPLUS */ 332290792Sgshapiro/* 332338032Speter** LDAP Modules 332438032Speter*/ 332538032Speter 332664562Sgshapiro/* 332764562Sgshapiro** LDAPMAP_DEQUOTE - helper routine for ldapmap_parseargs 332864562Sgshapiro*/ 332964562Sgshapiro 333064562Sgshapiro#if defined(LDAPMAP) || defined(PH_MAP) 333164562Sgshapiro 333290792Sgshapiro# if PH_MAP 333364562Sgshapiro# define ph_map_dequote ldapmap_dequote 333464562Sgshapiro# endif /* PH_MAP */ 333564562Sgshapiro 333690792Sgshapirostatic char *ldapmap_dequote __P((char *)); 333790792Sgshapiro 333890792Sgshapirostatic char * 333964562Sgshapiroldapmap_dequote(str) 334064562Sgshapiro char *str; 334164562Sgshapiro{ 334264562Sgshapiro char *p; 334364562Sgshapiro char *start; 334464562Sgshapiro 334564562Sgshapiro if (str == NULL) 334664562Sgshapiro return NULL; 334764562Sgshapiro 334864562Sgshapiro p = str; 334964562Sgshapiro if (*p == '"') 335064562Sgshapiro { 335164562Sgshapiro /* Should probably swallow initial whitespace here */ 335264562Sgshapiro start = ++p; 335364562Sgshapiro } 335464562Sgshapiro else 335564562Sgshapiro return str; 335664562Sgshapiro while (*p != '"' && *p != '\0') 335764562Sgshapiro p++; 335864562Sgshapiro if (*p != '\0') 335964562Sgshapiro *p = '\0'; 336064562Sgshapiro return start; 336164562Sgshapiro} 336264562Sgshapiro#endif /* defined(LDAPMAP) || defined(PH_MAP) */ 336364562Sgshapiro 336490792Sgshapiro#if LDAPMAP 336538032Speter 336690792Sgshapirostatic SM_LDAP_STRUCT *LDAPDefaults = NULL; 336738032Speter 336838032Speter/* 336964562Sgshapiro** LDAPMAP_OPEN -- open LDAP map 337038032Speter** 337164562Sgshapiro** Connect to the LDAP server. Re-use existing connections since a 337264562Sgshapiro** single server connection to a host (with the same host, port, 337364562Sgshapiro** bind DN, and secret) can answer queries for multiple maps. 337438032Speter*/ 337538032Speter 337638032Speterbool 337764562Sgshapiroldapmap_open(map, mode) 337838032Speter MAP *map; 337938032Speter int mode; 338038032Speter{ 338190792Sgshapiro SM_LDAP_STRUCT *lmap; 338264562Sgshapiro STAB *s; 3383132943Sgshapiro char *id; 338464562Sgshapiro 338538032Speter if (tTd(38, 2)) 338690792Sgshapiro sm_dprintf("ldapmap_open(%s, %d): ", map->map_mname, mode); 338738032Speter 3388168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \ 3389168515Sgshapiro HASLDAPGETALIASBYNAME 3390168515Sgshapiro if (VendorCode == VENDOR_SUN && 3391168515Sgshapiro strcmp(map->map_mname, "aliases.ldap") == 0) 3392168515Sgshapiro { 3393168515Sgshapiro return true; 3394168515Sgshapiro } 3395168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */ 3396168515Sgshapiro 339738032Speter mode &= O_ACCMODE; 339864562Sgshapiro 339964562Sgshapiro /* sendmail doesn't have the ability to write to LDAP (yet) */ 340038032Speter if (mode != O_RDONLY) 340138032Speter { 340238032Speter /* issue a pseudo-error message */ 340390792Sgshapiro errno = SM_EMAPCANTWRITE; 340490792Sgshapiro return false; 340538032Speter } 340664562Sgshapiro 340790792Sgshapiro lmap = (SM_LDAP_STRUCT *) map->map_db1; 340864562Sgshapiro 340964562Sgshapiro s = ldapmap_findconn(lmap); 341077349Sgshapiro if (s->s_lmap != NULL) 341164562Sgshapiro { 341264562Sgshapiro /* Already have a connection open to this LDAP server */ 341390792Sgshapiro lmap->ldap_ld = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_ld; 341490792Sgshapiro lmap->ldap_pid = ((SM_LDAP_STRUCT *)s->s_lmap->map_db1)->ldap_pid; 341577349Sgshapiro 341677349Sgshapiro /* Add this map as head of linked list */ 341777349Sgshapiro lmap->ldap_next = s->s_lmap; 341877349Sgshapiro s->s_lmap = map; 341977349Sgshapiro 342066494Sgshapiro if (tTd(38, 2)) 342190792Sgshapiro sm_dprintf("using cached connection\n"); 342290792Sgshapiro return true; 342364562Sgshapiro } 342464562Sgshapiro 342566494Sgshapiro if (tTd(38, 2)) 342690792Sgshapiro sm_dprintf("opening new connection\n"); 342766494Sgshapiro 3428132943Sgshapiro if (lmap->ldap_host != NULL) 3429132943Sgshapiro id = lmap->ldap_host; 3430132943Sgshapiro else if (lmap->ldap_uri != NULL) 3431132943Sgshapiro id = lmap->ldap_uri; 3432132943Sgshapiro else 3433132943Sgshapiro id = "localhost"; 3434132943Sgshapiro 3435203004Sgshapiro if (tTd(74, 104)) 3436203004Sgshapiro { 3437203004Sgshapiro extern MAPCLASS NullMapClass; 3438203004Sgshapiro 3439203004Sgshapiro /* debug mode: don't actually open an LDAP connection */ 3440203004Sgshapiro map->map_orgclass = map->map_class; 3441203004Sgshapiro map->map_class = &NullMapClass; 3442203004Sgshapiro map->map_mflags |= MF_OPEN; 3443203004Sgshapiro map->map_pid = CurrentPid; 3444203004Sgshapiro return true; 3445203004Sgshapiro } 3446203004Sgshapiro 344764562Sgshapiro /* No connection yet, connect */ 344890792Sgshapiro if (!sm_ldap_start(map->map_mname, lmap)) 344938032Speter { 345090792Sgshapiro if (errno == ETIMEDOUT) 345138032Speter { 345238032Speter if (LogLevel > 1) 345338032Speter sm_syslog(LOG_NOTICE, CurEnv->e_id, 3454244833Sgshapiro "timeout connecting to LDAP server %.100s", 3455132943Sgshapiro id); 345638032Speter } 345738032Speter 345838032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 345938032Speter { 346064562Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 3461132943Sgshapiro { 346264562Sgshapiro syserr("%s failed to %s in map %s", 346364562Sgshapiro# if USE_LDAP_INIT 346490792Sgshapiro "ldap_init/ldap_bind", 346564562Sgshapiro# else /* USE_LDAP_INIT */ 346664562Sgshapiro "ldap_open", 346764562Sgshapiro# endif /* USE_LDAP_INIT */ 3468132943Sgshapiro id, map->map_mname); 3469132943Sgshapiro } 347064562Sgshapiro else 3471132943Sgshapiro { 347294334Sgshapiro syserr("451 4.3.5 %s failed to %s in map %s", 347364562Sgshapiro# if USE_LDAP_INIT 347490792Sgshapiro "ldap_init/ldap_bind", 347564562Sgshapiro# else /* USE_LDAP_INIT */ 347664562Sgshapiro "ldap_open", 347764562Sgshapiro# endif /* USE_LDAP_INIT */ 3478132943Sgshapiro id, map->map_mname); 3479132943Sgshapiro } 348038032Speter } 348190792Sgshapiro return false; 348238032Speter } 348338032Speter 348490792Sgshapiro /* Save connection for reuse */ 348590792Sgshapiro s->s_lmap = map; 348690792Sgshapiro return true; 348738032Speter} 348838032Speter 348938032Speter/* 349064562Sgshapiro** LDAPMAP_CLOSE -- close ldap map 349138032Speter*/ 349238032Speter 349338032Spetervoid 349464562Sgshapiroldapmap_close(map) 349538032Speter MAP *map; 349638032Speter{ 349790792Sgshapiro SM_LDAP_STRUCT *lmap; 349864562Sgshapiro STAB *s; 349943730Speter 350064562Sgshapiro if (tTd(38, 2)) 350190792Sgshapiro sm_dprintf("ldapmap_close(%s)\n", map->map_mname); 350264562Sgshapiro 350390792Sgshapiro lmap = (SM_LDAP_STRUCT *) map->map_db1; 350464562Sgshapiro 350564562Sgshapiro /* Check if already closed */ 350664562Sgshapiro if (lmap->ldap_ld == NULL) 350764562Sgshapiro return; 350864562Sgshapiro 350977349Sgshapiro /* Close the LDAP connection */ 351090792Sgshapiro sm_ldap_close(lmap); 351177349Sgshapiro 351277349Sgshapiro /* Mark all the maps that share the connection as closed */ 351364562Sgshapiro s = ldapmap_findconn(lmap); 351464562Sgshapiro 351577349Sgshapiro while (s->s_lmap != NULL) 351677349Sgshapiro { 351777349Sgshapiro MAP *smap = s->s_lmap; 351864562Sgshapiro 351977349Sgshapiro if (tTd(38, 2) && smap != map) 352090792Sgshapiro sm_dprintf("ldapmap_close(%s): closed %s (shared LDAP connection)\n", 352190792Sgshapiro map->map_mname, smap->map_mname); 352277349Sgshapiro smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 352390792Sgshapiro lmap = (SM_LDAP_STRUCT *) smap->map_db1; 352464562Sgshapiro lmap->ldap_ld = NULL; 352577349Sgshapiro s->s_lmap = lmap->ldap_next; 352677349Sgshapiro lmap->ldap_next = NULL; 352743730Speter } 352838032Speter} 352938032Speter 353064562Sgshapiro# ifdef SUNET_ID 353143730Speter/* 353290792Sgshapiro** SUNET_ID_HASH -- Convert a string to its Sunet_id canonical form 353342575Speter** This only makes sense at Stanford University. 353438032Speter*/ 353538032Speter 353690792Sgshapirostatic char * 353738032Spetersunet_id_hash(str) 353838032Speter char *str; 353938032Speter{ 354038032Speter char *p, *p_last; 354138032Speter 354238032Speter p = str; 354338032Speter p_last = p; 354438032Speter while (*p != '\0') 354538032Speter { 3546203004Sgshapiro if (isascii(*p) && (islower(*p) || isdigit(*p))) 354738032Speter { 354838032Speter *p_last = *p; 354938032Speter p_last++; 355038032Speter } 3551203004Sgshapiro else if (isascii(*p) && isupper(*p)) 355238032Speter { 355338032Speter *p_last = tolower(*p); 355438032Speter p_last++; 355538032Speter } 355638032Speter ++p; 355738032Speter } 355838032Speter if (*p_last != '\0') 355938032Speter *p_last = '\0'; 356064562Sgshapiro return str; 356138032Speter} 3562168515Sgshapiro# define SM_CONVERT_ID(str) sunet_id_hash(str) 3563168515Sgshapiro# else /* SUNET_ID */ 3564168515Sgshapiro# define SM_CONVERT_ID(str) makelower(str) 356564562Sgshapiro# endif /* SUNET_ID */ 356638032Speter 356738032Speter/* 356864562Sgshapiro** LDAPMAP_LOOKUP -- look up a datum in a LDAP map 356938032Speter*/ 357038032Speter 357138032Speterchar * 357264562Sgshapiroldapmap_lookup(map, name, av, statp) 357338032Speter MAP *map; 357438032Speter char *name; 357538032Speter char **av; 357638032Speter int *statp; 357738032Speter{ 3578132943Sgshapiro int flags; 3579168515Sgshapiro int i; 358094334Sgshapiro int plen = 0; 358194334Sgshapiro int psize = 0; 358264562Sgshapiro int msgid; 358390792Sgshapiro int save_errno; 358490792Sgshapiro char *vp, *p; 358564562Sgshapiro char *result = NULL; 3586132943Sgshapiro SM_RPOOL_T *rpool; 358790792Sgshapiro SM_LDAP_STRUCT *lmap = NULL; 3588168515Sgshapiro char *argv[SM_LDAP_ARGS]; 3589157001Sgshapiro char keybuf[MAXKEY]; 3590168515Sgshapiro#if SM_LDAP_ARGS != MAX_MAP_ARGS 3591168515Sgshapiro# ERROR _SM_LDAP_ARGS must be the same as _MAX_MAP_ARGS 3592168515Sgshapiro#endif /* SM_LDAP_ARGS != MAX_MAP_ARGS */ 359338032Speter 3594168515Sgshapiro#if defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && \ 3595168515Sgshapiro HASLDAPGETALIASBYNAME 3596168515Sgshapiro if (VendorCode == VENDOR_SUN && 3597168515Sgshapiro strcmp(map->map_mname, "aliases.ldap") == 0) 3598168515Sgshapiro { 3599168515Sgshapiro int rc; 3600173340Sgshapiro#if defined(GETLDAPALIASBYNAME_VERSION) && (GETLDAPALIASBYNAME_VERSION >= 2) 3601173340Sgshapiro extern char *__getldapaliasbyname(); 3602173340Sgshapiro char *answer; 360338032Speter 3604173340Sgshapiro answer = __getldapaliasbyname(name, &rc); 3605173340Sgshapiro#else 3606173340Sgshapiro char answer[MAXNAME + 1]; 3607173340Sgshapiro 3608168515Sgshapiro rc = __getldapaliasbyname(name, answer, sizeof(answer)); 3609173340Sgshapiro#endif 3610168515Sgshapiro if (rc != 0) 3611168515Sgshapiro { 3612168515Sgshapiro if (tTd(38, 20)) 3613168515Sgshapiro sm_dprintf("getldapaliasbyname(%.100s) failed, errno=%d\n", 3614168515Sgshapiro name, errno); 3615168515Sgshapiro *statp = EX_NOTFOUND; 3616168515Sgshapiro return NULL; 3617168515Sgshapiro } 3618168515Sgshapiro *statp = EX_OK; 3619168515Sgshapiro if (tTd(38, 20)) 3620168515Sgshapiro sm_dprintf("getldapaliasbyname(%.100s) => %s\n", name, 3621168515Sgshapiro answer); 3622168515Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 3623168515Sgshapiro result = map_rewrite(map, name, strlen(name), NULL); 3624168515Sgshapiro else 3625168515Sgshapiro result = map_rewrite(map, answer, strlen(answer), av); 3626173340Sgshapiro#if defined(GETLDAPALIASBYNAME_VERSION) && (GETLDAPALIASBYNAME_VERSION >= 2) 3627173340Sgshapiro free(answer); 3628173340Sgshapiro#endif 3629168515Sgshapiro return result; 3630168515Sgshapiro } 3631168515Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_SIMPLIFIED_LDAP) && ... */ 3632168515Sgshapiro 363338032Speter /* Get ldap struct pointer from map */ 363490792Sgshapiro lmap = (SM_LDAP_STRUCT *) map->map_db1; 363590792Sgshapiro sm_ldap_setopts(lmap->ldap_ld, lmap); 363638032Speter 3637168515Sgshapiro if (lmap->ldap_multi_args) 3638168515Sgshapiro { 3639168515Sgshapiro SM_REQUIRE(av != NULL); 3640168515Sgshapiro memset(argv, '\0', sizeof(argv)); 3641168515Sgshapiro for (i = 0; i < SM_LDAP_ARGS && av[i] != NULL; i++) 3642168515Sgshapiro { 3643168515Sgshapiro argv[i] = sm_strdup(av[i]); 3644168515Sgshapiro if (argv[i] == NULL) 3645168515Sgshapiro { 3646168515Sgshapiro int save_errno, j; 364738032Speter 3648168515Sgshapiro save_errno = errno; 3649168515Sgshapiro for (j = 0; j < i && argv[j] != NULL; j++) 3650168515Sgshapiro SM_FREE(argv[j]); 3651168515Sgshapiro *statp = EX_TEMPFAIL; 3652168515Sgshapiro errno = save_errno; 3653168515Sgshapiro return NULL; 3654168515Sgshapiro } 3655168515Sgshapiro 3656168515Sgshapiro if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 3657168515Sgshapiro SM_CONVERT_ID(av[i]); 3658168515Sgshapiro } 3659168515Sgshapiro } 3660168515Sgshapiro else 366164562Sgshapiro { 3662168515Sgshapiro (void) sm_strlcpy(keybuf, name, sizeof(keybuf)); 3663168515Sgshapiro 3664168515Sgshapiro if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 3665168515Sgshapiro SM_CONVERT_ID(keybuf); 366664562Sgshapiro } 366738032Speter 3668168515Sgshapiro if (tTd(38, 20)) 366938032Speter { 3670168515Sgshapiro if (lmap->ldap_multi_args) 3671168515Sgshapiro { 3672168515Sgshapiro sm_dprintf("ldapmap_lookup(%s, argv)\n", 3673168515Sgshapiro map->map_mname); 3674168515Sgshapiro for (i = 0; i < SM_LDAP_ARGS; i++) 3675168515Sgshapiro { 3676168515Sgshapiro sm_dprintf(" argv[%d] = %s\n", i, 3677168515Sgshapiro argv[i] == NULL ? "NULL" : argv[i]); 3678168515Sgshapiro } 3679168515Sgshapiro } 3680168515Sgshapiro else 3681168515Sgshapiro { 3682168515Sgshapiro sm_dprintf("ldapmap_lookup(%s, %s)\n", 3683168515Sgshapiro map->map_mname, name); 3684168515Sgshapiro } 3685168515Sgshapiro } 3686168515Sgshapiro 3687168515Sgshapiro if (lmap->ldap_multi_args) 3688168515Sgshapiro { 3689168515Sgshapiro msgid = sm_ldap_search_m(lmap, argv); 3690168515Sgshapiro 3691168515Sgshapiro /* free the argv array and its content, no longer needed */ 3692168515Sgshapiro for (i = 0; i < SM_LDAP_ARGS && argv[i] != NULL; i++) 3693168515Sgshapiro SM_FREE(argv[i]); 3694168515Sgshapiro } 3695168515Sgshapiro else 3696168515Sgshapiro msgid = sm_ldap_search(lmap, keybuf); 3697168515Sgshapiro if (msgid == SM_LDAP_ERR) 3698168515Sgshapiro { 369990792Sgshapiro errno = sm_ldap_geterrno(lmap->ldap_ld) + E_LDAPBASE; 370077349Sgshapiro save_errno = errno; 370164562Sgshapiro if (!bitset(MF_OPTIONAL, map->map_mflags)) 370238032Speter { 3703168515Sgshapiro /* 3704168515Sgshapiro ** Do not include keybuf as this error may be shown 3705168515Sgshapiro ** to outsiders. 3706168515Sgshapiro */ 3707168515Sgshapiro 370864562Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 3709168515Sgshapiro syserr("Error in ldap_search in map %s", 3710168515Sgshapiro map->map_mname); 371164562Sgshapiro else 3712168515Sgshapiro syserr("451 4.3.5 Error in ldap_search in map %s", 3713168515Sgshapiro map->map_mname); 371438032Speter } 371564562Sgshapiro *statp = EX_TEMPFAIL; 371690792Sgshapiro switch (save_errno - E_LDAPBASE) 371790792Sgshapiro { 371894334Sgshapiro# ifdef LDAP_SERVER_DOWN 371990792Sgshapiro case LDAP_SERVER_DOWN: 372094334Sgshapiro# endif /* LDAP_SERVER_DOWN */ 372190792Sgshapiro case LDAP_TIMEOUT: 372290792Sgshapiro case LDAP_UNAVAILABLE: 372366494Sgshapiro /* server disappeared, try reopen on next search */ 372477349Sgshapiro ldapmap_close(map); 372590792Sgshapiro break; 372666494Sgshapiro } 372777349Sgshapiro errno = save_errno; 372864562Sgshapiro return NULL; 372964562Sgshapiro } 3730168515Sgshapiro#if SM_LDAP_ERROR_ON_MISSING_ARGS 3731168515Sgshapiro else if (msgid == SM_LDAP_ERR_ARG_MISS) 3732168515Sgshapiro { 3733168515Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 3734168515Sgshapiro syserr("Error in ldap_search in map %s, too few arguments", 3735168515Sgshapiro map->map_mname); 3736168515Sgshapiro else 3737168515Sgshapiro syserr("554 5.3.5 Error in ldap_search in map %s, too few arguments", 3738168515Sgshapiro map->map_mname); 3739168515Sgshapiro *statp = EX_CONFIG; 3740168515Sgshapiro return NULL; 3741168515Sgshapiro } 3742168515Sgshapiro#endif /* SM_LDAP_ERROR_ON_MISSING_ARGS */ 374364562Sgshapiro 374464562Sgshapiro *statp = EX_NOTFOUND; 374564562Sgshapiro vp = NULL; 374664562Sgshapiro 3747132943Sgshapiro flags = 0; 3748132943Sgshapiro if (bitset(MF_SINGLEMATCH, map->map_mflags)) 3749132943Sgshapiro flags |= SM_LDAP_SINGLEMATCH; 3750132943Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 3751132943Sgshapiro flags |= SM_LDAP_MATCHONLY; 3752157001Sgshapiro# if _FFR_LDAP_SINGLEDN 3753157001Sgshapiro if (bitset(MF_SINGLEDN, map->map_mflags)) 3754157001Sgshapiro flags |= SM_LDAP_SINGLEDN; 3755157001Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */ 375690792Sgshapiro 3757132943Sgshapiro /* Create an rpool for search related memory usage */ 3758132943Sgshapiro rpool = sm_rpool_new_x(NULL); 375990792Sgshapiro 3760132943Sgshapiro p = NULL; 3761132943Sgshapiro *statp = sm_ldap_results(lmap, msgid, flags, map->map_coldelim, 3762132943Sgshapiro rpool, &p, &plen, &psize, NULL); 3763132943Sgshapiro save_errno = errno; 376490792Sgshapiro 3765132943Sgshapiro /* Copy result so rpool can be freed */ 3766132943Sgshapiro if (*statp == EX_OK && p != NULL) 3767132943Sgshapiro vp = newstr(p); 3768132943Sgshapiro sm_rpool_free(rpool); 376990792Sgshapiro 3770132943Sgshapiro /* need to restart LDAP connection? */ 3771132943Sgshapiro if (*statp == EX_RESTART) 377264562Sgshapiro { 3773132943Sgshapiro *statp = EX_TEMPFAIL; 3774132943Sgshapiro ldapmap_close(map); 377538032Speter } 377638032Speter 3777132943Sgshapiro errno = save_errno; 3778132943Sgshapiro if (*statp != EX_OK && *statp != EX_NOTFOUND) 377938032Speter { 378064562Sgshapiro if (!bitset(MF_OPTIONAL, map->map_mflags)) 378164562Sgshapiro { 378264562Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 3783244833Sgshapiro syserr("Error getting LDAP results, map=%s, name=%s", 3784244833Sgshapiro map->map_mname, name); 378564562Sgshapiro else 3786244833Sgshapiro syserr("451 4.3.5 Error getting LDAP results, map=%s, name=%s", 3787244833Sgshapiro map->map_mname, name); 378864562Sgshapiro } 378977349Sgshapiro errno = save_errno; 379064562Sgshapiro return NULL; 379138032Speter } 379290792Sgshapiro 379364562Sgshapiro /* Did we match anything? */ 379471345Sgshapiro if (vp == NULL && !bitset(MF_MATCHONLY, map->map_mflags)) 379564562Sgshapiro return NULL; 379638032Speter 379764562Sgshapiro if (*statp == EX_OK) 379864562Sgshapiro { 379964562Sgshapiro if (LogLevel > 9) 380064562Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, 3801244833Sgshapiro "ldap=%s, %.100s=>%s", map->map_mname, name, 380271345Sgshapiro vp == NULL ? "<NULL>" : vp); 380364562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 380464562Sgshapiro result = map_rewrite(map, name, strlen(name), NULL); 380564562Sgshapiro else 380671345Sgshapiro { 380771345Sgshapiro /* vp != NULL according to test above */ 380864562Sgshapiro result = map_rewrite(map, vp, strlen(vp), av); 380971345Sgshapiro } 381071345Sgshapiro if (vp != NULL) 381190792Sgshapiro sm_free(vp); /* XXX */ 381264562Sgshapiro } 381364562Sgshapiro return result; 381438032Speter} 381538032Speter 381638032Speter/* 381764562Sgshapiro** LDAPMAP_FINDCONN -- find an LDAP connection to the server 381864562Sgshapiro** 381964562Sgshapiro** Cache LDAP connections based on the host, port, bind DN, 382066494Sgshapiro** secret, and PID so we don't have multiple connections open to 382166494Sgshapiro** the same server for different maps. Need a separate connection 382266494Sgshapiro** per PID since a parent process may close the map before the 382366494Sgshapiro** child is done with it. 382464562Sgshapiro** 382564562Sgshapiro** Parameters: 382664562Sgshapiro** lmap -- LDAP map information 382764562Sgshapiro** 382864562Sgshapiro** Returns: 382964562Sgshapiro** Symbol table entry for the LDAP connection. 383038032Speter*/ 383138032Speter 383264562Sgshapirostatic STAB * 383364562Sgshapiroldapmap_findconn(lmap) 383490792Sgshapiro SM_LDAP_STRUCT *lmap; 383538032Speter{ 383694334Sgshapiro char *format; 383764562Sgshapiro char *nbuf; 3838132943Sgshapiro char *id; 383990792Sgshapiro STAB *SM_NONVOLATILE s = NULL; 384038032Speter 3841132943Sgshapiro if (lmap->ldap_host != NULL) 3842132943Sgshapiro id = lmap->ldap_host; 3843132943Sgshapiro else if (lmap->ldap_uri != NULL) 3844132943Sgshapiro id = lmap->ldap_uri; 3845132943Sgshapiro else 3846132943Sgshapiro id = "localhost"; 3847132943Sgshapiro 384894334Sgshapiro format = "%s%c%d%c%d%c%s%c%s%d"; 384994334Sgshapiro nbuf = sm_stringf_x(format, 3850132943Sgshapiro id, 385190792Sgshapiro CONDELSE, 385290792Sgshapiro lmap->ldap_port, 385390792Sgshapiro CONDELSE, 385494334Sgshapiro lmap->ldap_version, 385594334Sgshapiro CONDELSE, 385690792Sgshapiro (lmap->ldap_binddn == NULL ? "" 385790792Sgshapiro : lmap->ldap_binddn), 385890792Sgshapiro CONDELSE, 385990792Sgshapiro (lmap->ldap_secret == NULL ? "" 386090792Sgshapiro : lmap->ldap_secret), 386190792Sgshapiro (int) CurrentPid); 386290792Sgshapiro SM_TRY 386390792Sgshapiro s = stab(nbuf, ST_LMAP, ST_ENTER); 386490792Sgshapiro SM_FINALLY 386590792Sgshapiro sm_free(nbuf); 386690792Sgshapiro SM_END_TRY 386764562Sgshapiro return s; 386864562Sgshapiro} 386938032Speter/* 387064562Sgshapiro** LDAPMAP_PARSEARGS -- parse ldap map definition args. 387164562Sgshapiro*/ 387238032Speter 387390792Sgshapirostatic struct lamvalues LDAPAuthMethods[] = 387464562Sgshapiro{ 387564562Sgshapiro { "none", LDAP_AUTH_NONE }, 387664562Sgshapiro { "simple", LDAP_AUTH_SIMPLE }, 387764562Sgshapiro# ifdef LDAP_AUTH_KRBV4 387864562Sgshapiro { "krbv4", LDAP_AUTH_KRBV4 }, 387964562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */ 388064562Sgshapiro { NULL, 0 } 388164562Sgshapiro}; 388238032Speter 388390792Sgshapirostatic struct ladvalues LDAPAliasDereference[] = 388464562Sgshapiro{ 388564562Sgshapiro { "never", LDAP_DEREF_NEVER }, 388664562Sgshapiro { "always", LDAP_DEREF_ALWAYS }, 388764562Sgshapiro { "search", LDAP_DEREF_SEARCHING }, 388864562Sgshapiro { "find", LDAP_DEREF_FINDING }, 388964562Sgshapiro { NULL, 0 } 389064562Sgshapiro}; 389138032Speter 389290792Sgshapirostatic struct lssvalues LDAPSearchScope[] = 389364562Sgshapiro{ 389464562Sgshapiro { "base", LDAP_SCOPE_BASE }, 389564562Sgshapiro { "one", LDAP_SCOPE_ONELEVEL }, 389664562Sgshapiro { "sub", LDAP_SCOPE_SUBTREE }, 389764562Sgshapiro { NULL, 0 } 389864562Sgshapiro}; 389938032Speter 390064562Sgshapirobool 390164562Sgshapiroldapmap_parseargs(map, args) 390264562Sgshapiro MAP *map; 390364562Sgshapiro char *args; 390464562Sgshapiro{ 390590792Sgshapiro bool secretread = true; 3906132943Sgshapiro bool attrssetup = false; 390764562Sgshapiro int i; 390864562Sgshapiro register char *p = args; 390990792Sgshapiro SM_LDAP_STRUCT *lmap; 391064562Sgshapiro struct lamvalues *lam; 391164562Sgshapiro struct ladvalues *lad; 391264562Sgshapiro struct lssvalues *lss; 391390792Sgshapiro char ldapfilt[MAXLINE]; 391464562Sgshapiro char m_tmp[MAXPATHLEN + LDAPMAP_MAX_PASSWD]; 391564562Sgshapiro 391664562Sgshapiro /* Get ldap struct pointer from map */ 391790792Sgshapiro lmap = (SM_LDAP_STRUCT *) map->map_db1; 391864562Sgshapiro 391964562Sgshapiro /* Check if setting the initial LDAP defaults */ 392064562Sgshapiro if (lmap == NULL || lmap != LDAPDefaults) 392164562Sgshapiro { 392290792Sgshapiro /* We need to alloc an SM_LDAP_STRUCT struct */ 3923168515Sgshapiro lmap = (SM_LDAP_STRUCT *) xalloc(sizeof(*lmap)); 392464562Sgshapiro if (LDAPDefaults == NULL) 392590792Sgshapiro sm_ldap_clear(lmap); 392664562Sgshapiro else 392764562Sgshapiro STRUCTCOPY(*LDAPDefaults, *lmap); 392864562Sgshapiro } 392964562Sgshapiro 393064562Sgshapiro /* there is no check whether there is really an argument */ 393164562Sgshapiro map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL; 393264562Sgshapiro map->map_spacesub = SpaceSub; /* default value */ 393390792Sgshapiro 393490792Sgshapiro /* Check if setting up an alias or file class LDAP map */ 393590792Sgshapiro if (bitset(MF_ALIAS, map->map_mflags)) 393690792Sgshapiro { 393790792Sgshapiro /* Comma separate if used as an alias file */ 393890792Sgshapiro map->map_coldelim = ','; 393990792Sgshapiro if (*args == '\0') 394090792Sgshapiro { 394190792Sgshapiro int n; 394290792Sgshapiro char *lc; 394390792Sgshapiro char jbuf[MAXHOSTNAMELEN]; 394490792Sgshapiro char lcbuf[MAXLINE]; 394590792Sgshapiro 394690792Sgshapiro /* Get $j */ 3947168515Sgshapiro expand("\201j", jbuf, sizeof(jbuf), &BlankEnvelope); 394890792Sgshapiro if (jbuf[0] == '\0') 394990792Sgshapiro { 395090792Sgshapiro (void) sm_strlcpy(jbuf, "localhost", 3951168515Sgshapiro sizeof(jbuf)); 395290792Sgshapiro } 395390792Sgshapiro 395490792Sgshapiro lc = macvalue(macid("{sendmailMTACluster}"), CurEnv); 395590792Sgshapiro if (lc == NULL) 395690792Sgshapiro lc = ""; 395790792Sgshapiro else 395890792Sgshapiro { 3959168515Sgshapiro expand(lc, lcbuf, sizeof(lcbuf), CurEnv); 396090792Sgshapiro lc = lcbuf; 396190792Sgshapiro } 396290792Sgshapiro 3963168515Sgshapiro n = sm_snprintf(ldapfilt, sizeof(ldapfilt), 396490792Sgshapiro "(&(objectClass=sendmailMTAAliasObject)(sendmailMTAAliasGrouping=aliases)(|(sendmailMTACluster=%s)(sendmailMTAHost=%s))(sendmailMTAKey=%%0))", 396590792Sgshapiro lc, jbuf); 3966168515Sgshapiro if (n >= sizeof(ldapfilt)) 396790792Sgshapiro { 396890792Sgshapiro syserr("%s: Default LDAP string too long", 396990792Sgshapiro map->map_mname); 397090792Sgshapiro return false; 397190792Sgshapiro } 397290792Sgshapiro 397390792Sgshapiro /* default args for an alias LDAP entry */ 397490792Sgshapiro lmap->ldap_filter = ldapfilt; 3975132943Sgshapiro lmap->ldap_attr[0] = "objectClass"; 3976132943Sgshapiro lmap->ldap_attr_type[0] = SM_LDAP_ATTR_OBJCLASS; 3977132943Sgshapiro lmap->ldap_attr_needobjclass[0] = NULL; 3978132943Sgshapiro lmap->ldap_attr[1] = "sendmailMTAAliasValue"; 3979132943Sgshapiro lmap->ldap_attr_type[1] = SM_LDAP_ATTR_NORMAL; 3980132943Sgshapiro lmap->ldap_attr_needobjclass[1] = NULL; 3981132943Sgshapiro lmap->ldap_attr[2] = "sendmailMTAAliasSearch"; 3982132943Sgshapiro lmap->ldap_attr_type[2] = SM_LDAP_ATTR_FILTER; 3983132943Sgshapiro lmap->ldap_attr_needobjclass[2] = "sendmailMTAMapObject"; 3984132943Sgshapiro lmap->ldap_attr[3] = "sendmailMTAAliasURL"; 3985132943Sgshapiro lmap->ldap_attr_type[3] = SM_LDAP_ATTR_URL; 3986132943Sgshapiro lmap->ldap_attr_needobjclass[3] = "sendmailMTAMapObject"; 3987132943Sgshapiro lmap->ldap_attr[4] = NULL; 3988132943Sgshapiro lmap->ldap_attr_type[4] = SM_LDAP_ATTR_NONE; 3989132943Sgshapiro lmap->ldap_attr_needobjclass[4] = NULL; 3990132943Sgshapiro attrssetup = true; 399190792Sgshapiro } 399290792Sgshapiro } 399390792Sgshapiro else if (bitset(MF_FILECLASS, map->map_mflags)) 399490792Sgshapiro { 399590792Sgshapiro /* Space separate if used as a file class file */ 399690792Sgshapiro map->map_coldelim = ' '; 399790792Sgshapiro } 399890792Sgshapiro 3999203004Sgshapiro# if _FFR_LDAP_NETWORK_TIMEOUT 4000203004Sgshapiro lmap->ldap_networktmo = 120; 4001203004Sgshapiro# endif /* _FFR_LDAP_NETWORK_TIMEOUT */ 4002203004Sgshapiro 400338032Speter for (;;) 400438032Speter { 400538032Speter while (isascii(*p) && isspace(*p)) 400638032Speter p++; 400738032Speter if (*p != '-') 400838032Speter break; 400938032Speter switch (*++p) 401038032Speter { 4011173340Sgshapiro case 'A': 4012173340Sgshapiro map->map_mflags |= MF_APPEND; 401338032Speter break; 401438032Speter 4015173340Sgshapiro case 'a': 4016173340Sgshapiro map->map_app = ++p; 401738032Speter break; 401838032Speter 4019173340Sgshapiro case 'D': 4020173340Sgshapiro map->map_mflags |= MF_DEFER; 402138032Speter break; 402238032Speter 402338032Speter case 'f': 402438032Speter map->map_mflags |= MF_NOFOLDCASE; 402538032Speter break; 402638032Speter 402738032Speter case 'm': 402838032Speter map->map_mflags |= MF_MATCHONLY; 402938032Speter break; 403038032Speter 4031173340Sgshapiro case 'N': 4032173340Sgshapiro map->map_mflags |= MF_INCLNULL; 4033173340Sgshapiro map->map_mflags &= ~MF_TRY0NULL; 403438032Speter break; 403538032Speter 4036173340Sgshapiro case 'O': 4037173340Sgshapiro map->map_mflags &= ~MF_TRY1NULL; 4038173340Sgshapiro break; 4039173340Sgshapiro 4040173340Sgshapiro case 'o': 4041173340Sgshapiro map->map_mflags |= MF_OPTIONAL; 4042173340Sgshapiro break; 4043173340Sgshapiro 404438032Speter case 'q': 404538032Speter map->map_mflags |= MF_KEEPQUOTES; 404638032Speter break; 404738032Speter 4048173340Sgshapiro case 'S': 4049173340Sgshapiro map->map_spacesub = *++p; 405038032Speter break; 405138032Speter 405238032Speter case 'T': 405338032Speter map->map_tapp = ++p; 405438032Speter break; 405538032Speter 405664562Sgshapiro case 't': 405764562Sgshapiro map->map_mflags |= MF_NODEFER; 405864562Sgshapiro break; 405964562Sgshapiro 406064562Sgshapiro case 'z': 406164562Sgshapiro if (*++p != '\\') 406264562Sgshapiro map->map_coldelim = *p; 406364562Sgshapiro else 406464562Sgshapiro { 406564562Sgshapiro switch (*++p) 406664562Sgshapiro { 406764562Sgshapiro case 'n': 406864562Sgshapiro map->map_coldelim = '\n'; 406964562Sgshapiro break; 407064562Sgshapiro 407164562Sgshapiro case 't': 407264562Sgshapiro map->map_coldelim = '\t'; 407364562Sgshapiro break; 407464562Sgshapiro 407564562Sgshapiro default: 407664562Sgshapiro map->map_coldelim = '\\'; 407764562Sgshapiro } 407864562Sgshapiro } 407964562Sgshapiro break; 408064562Sgshapiro 408164562Sgshapiro /* Start of ldapmap specific args */ 4082173340Sgshapiro case '1': 4083173340Sgshapiro map->map_mflags |= MF_SINGLEMATCH; 4084173340Sgshapiro break; 408590792Sgshapiro 4086173340Sgshapiro# if _FFR_LDAP_SINGLEDN 4087173340Sgshapiro case '2': 4088173340Sgshapiro map->map_mflags |= MF_SINGLEDN; 4089173340Sgshapiro break; 4090173340Sgshapiro# endif /* _FFR_LDAP_SINGLEDN */ 409190792Sgshapiro 4092173340Sgshapiro case 'b': /* search base */ 4093173340Sgshapiro while (isascii(*++p) && isspace(*p)) 4094173340Sgshapiro continue; 4095173340Sgshapiro lmap->ldap_base = p; 4096173340Sgshapiro break; 4097173340Sgshapiro 4098173340Sgshapiro# if _FFR_LDAP_NETWORK_TIMEOUT 4099173340Sgshapiro case 'c': /* network (connect) timeout */ 4100173340Sgshapiro while (isascii(*++p) && isspace(*p)) 4101173340Sgshapiro continue; 4102203004Sgshapiro lmap->ldap_networktmo = atoi(p); 4103173340Sgshapiro break; 4104173340Sgshapiro# endif /* _FFR_LDAP_NETWORK_TIMEOUT */ 4105173340Sgshapiro 4106173340Sgshapiro case 'd': /* Dn to bind to server as */ 4107173340Sgshapiro while (isascii(*++p) && isspace(*p)) 4108173340Sgshapiro continue; 4109173340Sgshapiro lmap->ldap_binddn = p; 4110173340Sgshapiro break; 4111173340Sgshapiro 4112173340Sgshapiro case 'H': /* Use LDAP URI */ 4113173340Sgshapiro# if !USE_LDAP_INIT 4114173340Sgshapiro syserr("Must compile with -DUSE_LDAP_INIT to use LDAP URIs (-H) in map %s", 4115173340Sgshapiro map->map_mname); 4116173340Sgshapiro return false; 4117173340Sgshapiro# else /* !USE_LDAP_INIT */ 4118173340Sgshapiro if (lmap->ldap_host != NULL) 4119173340Sgshapiro { 4120173340Sgshapiro syserr("Can not specify both an LDAP host and an LDAP URI in map %s", 4121173340Sgshapiro map->map_mname); 4122173340Sgshapiro return false; 412390792Sgshapiro } 4124173340Sgshapiro while (isascii(*++p) && isspace(*p)) 4125173340Sgshapiro continue; 4126173340Sgshapiro lmap->ldap_uri = p; 412790792Sgshapiro break; 4128173340Sgshapiro# endif /* !USE_LDAP_INIT */ 412990792Sgshapiro 4130173340Sgshapiro case 'h': /* ldap host */ 4131173340Sgshapiro while (isascii(*++p) && isspace(*p)) 4132173340Sgshapiro continue; 4133173340Sgshapiro if (lmap->ldap_uri != NULL) 4134173340Sgshapiro { 4135173340Sgshapiro syserr("Can not specify both an LDAP host and an LDAP URI in map %s", 4136173340Sgshapiro map->map_mname); 4137173340Sgshapiro return false; 4138173340Sgshapiro } 4139173340Sgshapiro lmap->ldap_host = p; 4140173340Sgshapiro break; 4141173340Sgshapiro 4142173340Sgshapiro case 'K': 4143173340Sgshapiro lmap->ldap_multi_args = true; 4144173340Sgshapiro break; 4145173340Sgshapiro 414638032Speter case 'k': /* search field */ 414738032Speter while (isascii(*++p) && isspace(*p)) 414838032Speter continue; 414964562Sgshapiro lmap->ldap_filter = p; 415038032Speter break; 415138032Speter 4152173340Sgshapiro case 'l': /* time limit */ 415338032Speter while (isascii(*++p) && isspace(*p)) 415438032Speter continue; 4155173340Sgshapiro lmap->ldap_timelimit = atoi(p); 4156173340Sgshapiro lmap->ldap_timeout.tv_sec = lmap->ldap_timelimit; 415738032Speter break; 415838032Speter 4159173340Sgshapiro case 'M': /* Method for binding */ 4160173340Sgshapiro while (isascii(*++p) && isspace(*p)) 4161173340Sgshapiro continue; 4162173340Sgshapiro 4163173340Sgshapiro if (sm_strncasecmp(p, "LDAP_AUTH_", 10) == 0) 4164173340Sgshapiro p += 10; 4165173340Sgshapiro 4166173340Sgshapiro for (lam = LDAPAuthMethods; 4167173340Sgshapiro lam != NULL && lam->lam_name != NULL; lam++) 4168173340Sgshapiro { 4169173340Sgshapiro if (sm_strncasecmp(p, lam->lam_name, 4170173340Sgshapiro strlen(lam->lam_name)) == 0) 4171173340Sgshapiro break; 4172173340Sgshapiro } 4173173340Sgshapiro if (lam->lam_name != NULL) 4174173340Sgshapiro lmap->ldap_method = lam->lam_code; 4175173340Sgshapiro else 4176173340Sgshapiro { 4177173340Sgshapiro /* bad config line */ 4178173340Sgshapiro if (!bitset(MCF_OPTFILE, 4179173340Sgshapiro map->map_class->map_cflags)) 4180173340Sgshapiro { 4181173340Sgshapiro char *ptr; 4182173340Sgshapiro 4183173340Sgshapiro if ((ptr = strchr(p, ' ')) != NULL) 4184173340Sgshapiro *ptr = '\0'; 4185173340Sgshapiro syserr("Method for binding must be [none|simple|krbv4] (not %s) in map %s", 4186173340Sgshapiro p, map->map_mname); 4187173340Sgshapiro if (ptr != NULL) 4188173340Sgshapiro *ptr = ' '; 4189173340Sgshapiro return false; 4190173340Sgshapiro } 4191173340Sgshapiro } 419264562Sgshapiro break; 419364562Sgshapiro 4194173340Sgshapiro case 'n': /* retrieve attribute names only */ 4195173340Sgshapiro lmap->ldap_attrsonly = LDAPMAP_TRUE; 4196157001Sgshapiro break; 4197157001Sgshapiro 4198173340Sgshapiro /* 4199173340Sgshapiro ** This is a string that is dependent on the 4200173340Sgshapiro ** method used defined by 'M'. 4201173340Sgshapiro */ 4202173340Sgshapiro 4203173340Sgshapiro case 'P': /* Secret password for binding */ 4204173340Sgshapiro while (isascii(*++p) && isspace(*p)) 4205173340Sgshapiro continue; 4206173340Sgshapiro lmap->ldap_secret = p; 4207173340Sgshapiro secretread = false; 4208173340Sgshapiro break; 4209173340Sgshapiro 4210173340Sgshapiro case 'p': /* ldap port */ 4211173340Sgshapiro while (isascii(*++p) && isspace(*p)) 4212173340Sgshapiro continue; 4213173340Sgshapiro lmap->ldap_port = atoi(p); 4214173340Sgshapiro break; 4215173340Sgshapiro 421638032Speter /* args stolen from ldapsearch.c */ 421738032Speter case 'R': /* don't auto chase referrals */ 421864562Sgshapiro# ifdef LDAP_REFERRALS 421938032Speter lmap->ldap_options &= ~LDAP_OPT_REFERRALS; 422064562Sgshapiro# else /* LDAP_REFERRALS */ 422190792Sgshapiro syserr("compile with -DLDAP_REFERRALS for referral support"); 422264562Sgshapiro# endif /* LDAP_REFERRALS */ 422338032Speter break; 422438032Speter 422564562Sgshapiro case 'r': /* alias dereferencing */ 422664562Sgshapiro while (isascii(*++p) && isspace(*p)) 422764562Sgshapiro continue; 422864562Sgshapiro 422990792Sgshapiro if (sm_strncasecmp(p, "LDAP_DEREF_", 11) == 0) 423064562Sgshapiro p += 11; 423164562Sgshapiro 423264562Sgshapiro for (lad = LDAPAliasDereference; 423364562Sgshapiro lad != NULL && lad->lad_name != NULL; lad++) 423438032Speter { 423590792Sgshapiro if (sm_strncasecmp(p, lad->lad_name, 423690792Sgshapiro strlen(lad->lad_name)) == 0) 423764562Sgshapiro break; 423838032Speter } 423964562Sgshapiro if (lad->lad_name != NULL) 424064562Sgshapiro lmap->ldap_deref = lad->lad_code; 424164562Sgshapiro else 424238032Speter { 424364562Sgshapiro /* bad config line */ 424464562Sgshapiro if (!bitset(MCF_OPTFILE, 424564562Sgshapiro map->map_class->map_cflags)) 424664562Sgshapiro { 424764562Sgshapiro char *ptr; 424864562Sgshapiro 424964562Sgshapiro if ((ptr = strchr(p, ' ')) != NULL) 425064562Sgshapiro *ptr = '\0'; 425173188Sgshapiro syserr("Deref must be [never|always|search|find] (not %s) in map %s", 425264562Sgshapiro p, map->map_mname); 425364562Sgshapiro if (ptr != NULL) 425464562Sgshapiro *ptr = ' '; 425590792Sgshapiro return false; 425664562Sgshapiro } 425738032Speter } 425864562Sgshapiro break; 425964562Sgshapiro 426064562Sgshapiro case 's': /* search scope */ 426164562Sgshapiro while (isascii(*++p) && isspace(*p)) 426264562Sgshapiro continue; 426364562Sgshapiro 426490792Sgshapiro if (sm_strncasecmp(p, "LDAP_SCOPE_", 11) == 0) 426564562Sgshapiro p += 11; 426664562Sgshapiro 426764562Sgshapiro for (lss = LDAPSearchScope; 426864562Sgshapiro lss != NULL && lss->lss_name != NULL; lss++) 426938032Speter { 427090792Sgshapiro if (sm_strncasecmp(p, lss->lss_name, 427190792Sgshapiro strlen(lss->lss_name)) == 0) 427264562Sgshapiro break; 427338032Speter } 427464562Sgshapiro if (lss->lss_name != NULL) 427564562Sgshapiro lmap->ldap_scope = lss->lss_code; 427638032Speter else 427764562Sgshapiro { 427864562Sgshapiro /* bad config line */ 427964562Sgshapiro if (!bitset(MCF_OPTFILE, 428064562Sgshapiro map->map_class->map_cflags)) 428138032Speter { 428238032Speter char *ptr; 428338032Speter 428438032Speter if ((ptr = strchr(p, ' ')) != NULL) 428538032Speter *ptr = '\0'; 428673188Sgshapiro syserr("Scope must be [base|one|sub] (not %s) in map %s", 428738032Speter p, map->map_mname); 428838032Speter if (ptr != NULL) 428938032Speter *ptr = ' '; 429090792Sgshapiro return false; 429138032Speter } 429238032Speter } 429338032Speter break; 429438032Speter 4295173340Sgshapiro case 'V': 4296173340Sgshapiro if (*++p != '\\') 4297173340Sgshapiro lmap->ldap_attrsep = *p; 429864562Sgshapiro else 429964562Sgshapiro { 4300173340Sgshapiro switch (*++p) 430164562Sgshapiro { 4302173340Sgshapiro case 'n': 4303173340Sgshapiro lmap->ldap_attrsep = '\n'; 4304173340Sgshapiro break; 430564562Sgshapiro 4306173340Sgshapiro case 't': 4307173340Sgshapiro lmap->ldap_attrsep = '\t'; 4308173340Sgshapiro break; 4309173340Sgshapiro 4310173340Sgshapiro default: 4311173340Sgshapiro lmap->ldap_attrsep = '\\'; 431264562Sgshapiro } 431364562Sgshapiro } 431464562Sgshapiro break; 431564562Sgshapiro 4316173340Sgshapiro case 'v': /* attr to return */ 431794334Sgshapiro while (isascii(*++p) && isspace(*p)) 431894334Sgshapiro continue; 4319173340Sgshapiro lmap->ldap_attr[0] = p; 4320173340Sgshapiro lmap->ldap_attr[1] = NULL; 432194334Sgshapiro break; 432294334Sgshapiro 432394334Sgshapiro case 'w': 432494334Sgshapiro /* -w should be for passwd, -P should be for version */ 432594334Sgshapiro while (isascii(*++p) && isspace(*p)) 432694334Sgshapiro continue; 432794334Sgshapiro lmap->ldap_version = atoi(p); 4328132943Sgshapiro# ifdef LDAP_VERSION_MAX 432994334Sgshapiro if (lmap->ldap_version > LDAP_VERSION_MAX) 433094334Sgshapiro { 433194334Sgshapiro syserr("LDAP version %d exceeds max of %d in map %s", 433294334Sgshapiro lmap->ldap_version, LDAP_VERSION_MAX, 433394334Sgshapiro map->map_mname); 433494334Sgshapiro return false; 433594334Sgshapiro } 4336132943Sgshapiro# endif /* LDAP_VERSION_MAX */ 4337132943Sgshapiro# ifdef LDAP_VERSION_MIN 433894334Sgshapiro if (lmap->ldap_version < LDAP_VERSION_MIN) 433994334Sgshapiro { 434094334Sgshapiro syserr("LDAP version %d is lower than min of %d in map %s", 434194334Sgshapiro lmap->ldap_version, LDAP_VERSION_MIN, 434294334Sgshapiro map->map_mname); 434394334Sgshapiro return false; 434494334Sgshapiro } 4345132943Sgshapiro# endif /* LDAP_VERSION_MIN */ 434694334Sgshapiro break; 434794334Sgshapiro 4348173340Sgshapiro case 'Z': 4349173340Sgshapiro while (isascii(*++p) && isspace(*p)) 4350173340Sgshapiro continue; 4351173340Sgshapiro lmap->ldap_sizelimit = atoi(p); 4352168515Sgshapiro break; 4353168515Sgshapiro 435464562Sgshapiro default: 435564562Sgshapiro syserr("Illegal option %c map %s", *p, map->map_mname); 435664562Sgshapiro break; 435738032Speter } 435838032Speter 435964562Sgshapiro /* need to account for quoted strings here */ 436064562Sgshapiro while (*p != '\0' && !(isascii(*p) && isspace(*p))) 436138032Speter { 436238032Speter if (*p == '"') 436338032Speter { 436438032Speter while (*++p != '"' && *p != '\0') 436538032Speter continue; 436638032Speter if (*p != '\0') 436738032Speter p++; 436838032Speter } 436938032Speter else 437038032Speter p++; 437138032Speter } 437238032Speter 437338032Speter if (*p != '\0') 437438032Speter *p++ = '\0'; 437538032Speter } 437638032Speter 437738032Speter if (map->map_app != NULL) 437864562Sgshapiro map->map_app = newstr(ldapmap_dequote(map->map_app)); 437938032Speter if (map->map_tapp != NULL) 438064562Sgshapiro map->map_tapp = newstr(ldapmap_dequote(map->map_tapp)); 438138032Speter 438238032Speter /* 438342575Speter ** We need to swallow up all the stuff into a struct 438442575Speter ** and dump it into map->map_dbptr1 438538032Speter */ 438638032Speter 4387132943Sgshapiro if (lmap->ldap_host != NULL && 438864562Sgshapiro (LDAPDefaults == NULL || 438964562Sgshapiro LDAPDefaults == lmap || 4390132943Sgshapiro LDAPDefaults->ldap_host != lmap->ldap_host)) 4391132943Sgshapiro lmap->ldap_host = newstr(ldapmap_dequote(lmap->ldap_host)); 4392132943Sgshapiro map->map_domain = lmap->ldap_host; 439364562Sgshapiro 4394132943Sgshapiro if (lmap->ldap_uri != NULL && 4395132943Sgshapiro (LDAPDefaults == NULL || 4396132943Sgshapiro LDAPDefaults == lmap || 4397132943Sgshapiro LDAPDefaults->ldap_uri != lmap->ldap_uri)) 4398132943Sgshapiro lmap->ldap_uri = newstr(ldapmap_dequote(lmap->ldap_uri)); 4399132943Sgshapiro map->map_domain = lmap->ldap_uri; 4400132943Sgshapiro 440164562Sgshapiro if (lmap->ldap_binddn != NULL && 440264562Sgshapiro (LDAPDefaults == NULL || 440364562Sgshapiro LDAPDefaults == lmap || 440464562Sgshapiro LDAPDefaults->ldap_binddn != lmap->ldap_binddn)) 440564562Sgshapiro lmap->ldap_binddn = newstr(ldapmap_dequote(lmap->ldap_binddn)); 440664562Sgshapiro 440764562Sgshapiro if (lmap->ldap_secret != NULL && 440864562Sgshapiro (LDAPDefaults == NULL || 440964562Sgshapiro LDAPDefaults == lmap || 441064562Sgshapiro LDAPDefaults->ldap_secret != lmap->ldap_secret)) 441138032Speter { 441290792Sgshapiro SM_FILE_T *sfd; 441364562Sgshapiro long sff = SFF_OPENASROOT|SFF_ROOTOK|SFF_NOWLINK|SFF_NOWWFILES|SFF_NOGWFILES; 441438032Speter 441564562Sgshapiro if (DontLockReadFiles) 441664562Sgshapiro sff |= SFF_NOLOCK; 441738032Speter 441864562Sgshapiro /* need to use method to map secret to passwd string */ 441964562Sgshapiro switch (lmap->ldap_method) 442064562Sgshapiro { 442164562Sgshapiro case LDAP_AUTH_NONE: 442264562Sgshapiro /* Do nothing */ 442364562Sgshapiro break; 442438032Speter 442564562Sgshapiro case LDAP_AUTH_SIMPLE: 442638032Speter 442764562Sgshapiro /* 442864562Sgshapiro ** Secret is the name of a file with 442964562Sgshapiro ** the first line as the password. 443064562Sgshapiro */ 443164562Sgshapiro 443264562Sgshapiro /* Already read in the secret? */ 443364562Sgshapiro if (secretread) 443464562Sgshapiro break; 443564562Sgshapiro 443664562Sgshapiro sfd = safefopen(ldapmap_dequote(lmap->ldap_secret), 443764562Sgshapiro O_RDONLY, 0, sff); 443864562Sgshapiro if (sfd == NULL) 443964562Sgshapiro { 444064562Sgshapiro syserr("LDAP map: cannot open secret %s", 444164562Sgshapiro ldapmap_dequote(lmap->ldap_secret)); 444290792Sgshapiro return false; 444364562Sgshapiro } 4444168515Sgshapiro lmap->ldap_secret = sfgets(m_tmp, sizeof(m_tmp), 444566494Sgshapiro sfd, TimeOuts.to_fileopen, 444666494Sgshapiro "ldapmap_parseargs"); 444790792Sgshapiro (void) sm_io_close(sfd, SM_TIME_DEFAULT); 444898121Sgshapiro if (strlen(m_tmp) > LDAPMAP_MAX_PASSWD) 444998121Sgshapiro { 445098121Sgshapiro syserr("LDAP map: secret in %s too long", 445198121Sgshapiro ldapmap_dequote(lmap->ldap_secret)); 445298121Sgshapiro return false; 445398121Sgshapiro } 445464562Sgshapiro if (lmap->ldap_secret != NULL && 445564562Sgshapiro strlen(m_tmp) > 0) 445664562Sgshapiro { 445764562Sgshapiro /* chomp newline */ 445864562Sgshapiro if (m_tmp[strlen(m_tmp) - 1] == '\n') 445964562Sgshapiro m_tmp[strlen(m_tmp) - 1] = '\0'; 446064562Sgshapiro 446164562Sgshapiro lmap->ldap_secret = m_tmp; 446264562Sgshapiro } 446364562Sgshapiro break; 446464562Sgshapiro 446564562Sgshapiro# ifdef LDAP_AUTH_KRBV4 446664562Sgshapiro case LDAP_AUTH_KRBV4: 446764562Sgshapiro 446864562Sgshapiro /* 446964562Sgshapiro ** Secret is where the ticket file is 447064562Sgshapiro ** stashed 447164562Sgshapiro */ 447264562Sgshapiro 4473168515Sgshapiro (void) sm_snprintf(m_tmp, sizeof(m_tmp), 447490792Sgshapiro "KRBTKFILE=%s", 447590792Sgshapiro ldapmap_dequote(lmap->ldap_secret)); 447664562Sgshapiro lmap->ldap_secret = m_tmp; 447764562Sgshapiro break; 447864562Sgshapiro# endif /* LDAP_AUTH_KRBV4 */ 447964562Sgshapiro 448064562Sgshapiro default: /* Should NEVER get here */ 448164562Sgshapiro syserr("LDAP map: Illegal value in lmap method"); 448290792Sgshapiro return false; 448390792Sgshapiro /* NOTREACHED */ 448464562Sgshapiro break; 448564562Sgshapiro } 448638032Speter } 448738032Speter 448864562Sgshapiro if (lmap->ldap_secret != NULL && 448964562Sgshapiro (LDAPDefaults == NULL || 449064562Sgshapiro LDAPDefaults == lmap || 449164562Sgshapiro LDAPDefaults->ldap_secret != lmap->ldap_secret)) 449264562Sgshapiro lmap->ldap_secret = newstr(ldapmap_dequote(lmap->ldap_secret)); 449338032Speter 449464562Sgshapiro if (lmap->ldap_base != NULL && 449564562Sgshapiro (LDAPDefaults == NULL || 449664562Sgshapiro LDAPDefaults == lmap || 449764562Sgshapiro LDAPDefaults->ldap_base != lmap->ldap_base)) 449864562Sgshapiro lmap->ldap_base = newstr(ldapmap_dequote(lmap->ldap_base)); 449964562Sgshapiro 450064562Sgshapiro /* 450164562Sgshapiro ** Save the server from extra work. If request is for a single 450264562Sgshapiro ** match, tell the server to only return enough records to 450364562Sgshapiro ** determine if there is a single match or not. This can not 450464562Sgshapiro ** be one since the server would only return one and we wouldn't 450564562Sgshapiro ** know if there were others available. 450664562Sgshapiro */ 450764562Sgshapiro 450864562Sgshapiro if (bitset(MF_SINGLEMATCH, map->map_mflags)) 450964562Sgshapiro lmap->ldap_sizelimit = 2; 451064562Sgshapiro 451164562Sgshapiro /* If setting defaults, don't process ldap_filter and ldap_attr */ 451264562Sgshapiro if (lmap == LDAPDefaults) 451390792Sgshapiro return true; 451464562Sgshapiro 451564562Sgshapiro if (lmap->ldap_filter != NULL) 451664562Sgshapiro lmap->ldap_filter = newstr(ldapmap_dequote(lmap->ldap_filter)); 451738032Speter else 451838032Speter { 451938032Speter if (!bitset(MCF_OPTFILE, map->map_class->map_cflags)) 452038032Speter { 452138032Speter syserr("No filter given in map %s", map->map_mname); 452290792Sgshapiro return false; 452338032Speter } 452438032Speter } 452564562Sgshapiro 4526132943Sgshapiro if (!attrssetup && lmap->ldap_attr[0] != NULL) 452738032Speter { 452890792Sgshapiro bool recurse = false; 452994334Sgshapiro bool normalseen = false; 453090792Sgshapiro 453164562Sgshapiro i = 0; 453264562Sgshapiro p = ldapmap_dequote(lmap->ldap_attr[0]); 453364562Sgshapiro lmap->ldap_attr[0] = NULL; 453464562Sgshapiro 453594334Sgshapiro /* Prime the attr list with the objectClass attribute */ 453694334Sgshapiro lmap->ldap_attr[i] = "objectClass"; 453794334Sgshapiro lmap->ldap_attr_type[i] = SM_LDAP_ATTR_OBJCLASS; 453894334Sgshapiro lmap->ldap_attr_needobjclass[i] = NULL; 453994334Sgshapiro i++; 454094334Sgshapiro 454164562Sgshapiro while (p != NULL) 454238032Speter { 454364562Sgshapiro char *v; 454464562Sgshapiro 454564562Sgshapiro while (isascii(*p) && isspace(*p)) 454664562Sgshapiro p++; 454764562Sgshapiro if (*p == '\0') 454864562Sgshapiro break; 454964562Sgshapiro v = p; 455064562Sgshapiro p = strchr(v, ','); 455164562Sgshapiro if (p != NULL) 455264562Sgshapiro *p++ = '\0'; 455364562Sgshapiro 455471345Sgshapiro if (i >= LDAPMAP_MAX_ATTR) 455564562Sgshapiro { 455664562Sgshapiro syserr("Too many return attributes in %s (max %d)", 455764562Sgshapiro map->map_mname, LDAPMAP_MAX_ATTR); 455890792Sgshapiro return false; 455964562Sgshapiro } 456064562Sgshapiro if (*v != '\0') 456190792Sgshapiro { 456294334Sgshapiro int j; 456394334Sgshapiro int use; 456490792Sgshapiro char *type; 456594334Sgshapiro char *needobjclass; 456690792Sgshapiro 456790792Sgshapiro type = strchr(v, ':'); 456890792Sgshapiro if (type != NULL) 456994334Sgshapiro { 457090792Sgshapiro *type++ = '\0'; 457194334Sgshapiro needobjclass = strchr(type, ':'); 457294334Sgshapiro if (needobjclass != NULL) 457394334Sgshapiro *needobjclass++ = '\0'; 457494334Sgshapiro } 457594334Sgshapiro else 457694334Sgshapiro { 457794334Sgshapiro needobjclass = NULL; 457894334Sgshapiro } 457990792Sgshapiro 458094334Sgshapiro use = i; 458190792Sgshapiro 458294334Sgshapiro /* allow override on "objectClass" type */ 458394334Sgshapiro if (sm_strcasecmp(v, "objectClass") == 0 && 458494334Sgshapiro lmap->ldap_attr_type[0] == SM_LDAP_ATTR_OBJCLASS) 458590792Sgshapiro { 458694334Sgshapiro use = 0; 458794334Sgshapiro } 458894334Sgshapiro else 458994334Sgshapiro { 459094334Sgshapiro /* 459194334Sgshapiro ** Don't add something to attribute 459294334Sgshapiro ** list twice. 459394334Sgshapiro */ 459494334Sgshapiro 459594334Sgshapiro for (j = 1; j < i; j++) 459690792Sgshapiro { 459794334Sgshapiro if (sm_strcasecmp(v, lmap->ldap_attr[j]) == 0) 459894334Sgshapiro { 459994334Sgshapiro syserr("Duplicate attribute (%s) in %s", 460094334Sgshapiro v, map->map_mname); 460194334Sgshapiro return false; 460294334Sgshapiro } 460390792Sgshapiro } 460494334Sgshapiro 460594334Sgshapiro lmap->ldap_attr[use] = newstr(v); 460694334Sgshapiro if (needobjclass != NULL && 460794334Sgshapiro *needobjclass != '\0' && 460894334Sgshapiro *needobjclass != '*') 460990792Sgshapiro { 461094334Sgshapiro lmap->ldap_attr_needobjclass[use] = newstr(needobjclass); 461194334Sgshapiro } 461294334Sgshapiro else 461394334Sgshapiro { 461494334Sgshapiro lmap->ldap_attr_needobjclass[use] = NULL; 461594334Sgshapiro } 461694334Sgshapiro 461794334Sgshapiro } 461894334Sgshapiro 461994334Sgshapiro if (type != NULL && *type != '\0') 462094334Sgshapiro { 462194334Sgshapiro if (sm_strcasecmp(type, "dn") == 0) 462294334Sgshapiro { 462390792Sgshapiro recurse = true; 462494334Sgshapiro lmap->ldap_attr_type[use] = SM_LDAP_ATTR_DN; 462590792Sgshapiro } 462690792Sgshapiro else if (sm_strcasecmp(type, "filter") == 0) 462790792Sgshapiro { 462890792Sgshapiro recurse = true; 462994334Sgshapiro lmap->ldap_attr_type[use] = SM_LDAP_ATTR_FILTER; 463090792Sgshapiro } 463190792Sgshapiro else if (sm_strcasecmp(type, "url") == 0) 463290792Sgshapiro { 463390792Sgshapiro recurse = true; 463494334Sgshapiro lmap->ldap_attr_type[use] = SM_LDAP_ATTR_URL; 463590792Sgshapiro } 463694334Sgshapiro else if (sm_strcasecmp(type, "normal") == 0) 463790792Sgshapiro { 463894334Sgshapiro lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL; 463994334Sgshapiro normalseen = true; 464090792Sgshapiro } 464190792Sgshapiro else 464290792Sgshapiro { 464390792Sgshapiro syserr("Unknown attribute type (%s) in %s", 464490792Sgshapiro type, map->map_mname); 464590792Sgshapiro return false; 464690792Sgshapiro } 464790792Sgshapiro } 464890792Sgshapiro else 464994334Sgshapiro { 465094334Sgshapiro lmap->ldap_attr_type[use] = SM_LDAP_ATTR_NORMAL; 465194334Sgshapiro normalseen = true; 465294334Sgshapiro } 465390792Sgshapiro i++; 465490792Sgshapiro } 465538032Speter } 465664562Sgshapiro lmap->ldap_attr[i] = NULL; 4657141858Sgshapiro 4658141858Sgshapiro /* Set in case needed in future code */ 4659132943Sgshapiro attrssetup = true; 4660141858Sgshapiro 466194334Sgshapiro if (recurse && !normalseen) 466290792Sgshapiro { 466394334Sgshapiro syserr("LDAP recursion requested in %s but no returnable attribute given", 466490792Sgshapiro map->map_mname); 466590792Sgshapiro return false; 466690792Sgshapiro } 466790792Sgshapiro if (recurse && lmap->ldap_attrsonly == LDAPMAP_TRUE) 466890792Sgshapiro { 466990792Sgshapiro syserr("LDAP recursion requested in %s can not be used with -n", 467090792Sgshapiro map->map_mname); 467190792Sgshapiro return false; 467290792Sgshapiro } 467338032Speter } 467438032Speter map->map_db1 = (ARBPTR_T) lmap; 467590792Sgshapiro return true; 467638032Speter} 467738032Speter 467864562Sgshapiro/* 467964562Sgshapiro** LDAPMAP_SET_DEFAULTS -- Read default map spec from LDAPDefaults in .cf 468064562Sgshapiro** 468164562Sgshapiro** Parameters: 468264562Sgshapiro** spec -- map argument string from LDAPDefaults option 468364562Sgshapiro** 468464562Sgshapiro** Returns: 468564562Sgshapiro** None. 468664562Sgshapiro*/ 468764562Sgshapiro 468864562Sgshapirovoid 468964562Sgshapiroldapmap_set_defaults(spec) 469064562Sgshapiro char *spec; 469164562Sgshapiro{ 469273188Sgshapiro STAB *class; 469364562Sgshapiro MAP map; 469464562Sgshapiro 469564562Sgshapiro /* Allocate and set the default values */ 469664562Sgshapiro if (LDAPDefaults == NULL) 4697168515Sgshapiro LDAPDefaults = (SM_LDAP_STRUCT *) xalloc(sizeof(*LDAPDefaults)); 469890792Sgshapiro sm_ldap_clear(LDAPDefaults); 469964562Sgshapiro 4700168515Sgshapiro memset(&map, '\0', sizeof(map)); 470173188Sgshapiro 470273188Sgshapiro /* look up the class */ 470373188Sgshapiro class = stab("ldap", ST_MAPCLASS, ST_FIND); 470473188Sgshapiro if (class == NULL) 470573188Sgshapiro { 470673188Sgshapiro syserr("readcf: LDAPDefaultSpec: class ldap not available"); 470773188Sgshapiro return; 470873188Sgshapiro } 470973188Sgshapiro map.map_class = &class->s_mapclass; 471064562Sgshapiro map.map_db1 = (ARBPTR_T) LDAPDefaults; 471173188Sgshapiro map.map_mname = "O LDAPDefaultSpec"; 471264562Sgshapiro 471364562Sgshapiro (void) ldapmap_parseargs(&map, spec); 471464562Sgshapiro 471564562Sgshapiro /* These should never be set in LDAPDefaults */ 471664562Sgshapiro if (map.map_mflags != (MF_TRY0NULL|MF_TRY1NULL) || 471764562Sgshapiro map.map_spacesub != SpaceSub || 471864562Sgshapiro map.map_app != NULL || 471964562Sgshapiro map.map_tapp != NULL) 472064562Sgshapiro { 472164562Sgshapiro syserr("readcf: option LDAPDefaultSpec: Do not set non-LDAP specific flags"); 472290792Sgshapiro SM_FREE_CLR(map.map_app); 472390792Sgshapiro SM_FREE_CLR(map.map_tapp); 472464562Sgshapiro } 472564562Sgshapiro 472664562Sgshapiro if (LDAPDefaults->ldap_filter != NULL) 472764562Sgshapiro { 472864562Sgshapiro syserr("readcf: option LDAPDefaultSpec: Do not set the LDAP search filter"); 472994334Sgshapiro 473064562Sgshapiro /* don't free, it isn't malloc'ed in parseargs */ 473164562Sgshapiro LDAPDefaults->ldap_filter = NULL; 473264562Sgshapiro } 473364562Sgshapiro 473464562Sgshapiro if (LDAPDefaults->ldap_attr[0] != NULL) 473564562Sgshapiro { 473664562Sgshapiro syserr("readcf: option LDAPDefaultSpec: Do not set the requested LDAP attributes"); 473764562Sgshapiro /* don't free, they aren't malloc'ed in parseargs */ 473864562Sgshapiro LDAPDefaults->ldap_attr[0] = NULL; 473964562Sgshapiro } 474064562Sgshapiro} 474164562Sgshapiro#endif /* LDAPMAP */ 474290792Sgshapiro/* 474364562Sgshapiro** PH map 474464562Sgshapiro*/ 474564562Sgshapiro 474690792Sgshapiro#if PH_MAP 474764562Sgshapiro 474864562Sgshapiro/* 474964562Sgshapiro** Support for the CCSO Nameserver (ph/qi). 475064562Sgshapiro** This code is intended to replace the so-called "ph mailer". 4751168515Sgshapiro** Contributed by Mark D. Roth. Contact him for support. 475264562Sgshapiro*/ 475364562Sgshapiro 475490792Sgshapiro/* what version of the ph map code we're running */ 4755110560Sgshapirostatic char phmap_id[128]; 475664562Sgshapiro 475790792Sgshapiro/* sendmail version for phmap id string */ 475890792Sgshapiroextern const char Version[]; 475990792Sgshapiro 4760132943Sgshapiro/* assume we're using nph-1.2.x if not specified */ 4761110560Sgshapiro# ifndef NPH_VERSION 4762132943Sgshapiro# define NPH_VERSION 10200 4763110560Sgshapiro# endif 4764110560Sgshapiro 4765110560Sgshapiro/* compatibility for versions older than nph-1.2.0 */ 4766110560Sgshapiro# if NPH_VERSION < 10200 4767110560Sgshapiro# define PH_OPEN_ROUNDROBIN PH_ROUNDROBIN 4768110560Sgshapiro# define PH_OPEN_DONTID PH_DONTID 4769110560Sgshapiro# define PH_CLOSE_FAST PH_FASTCLOSE 4770110560Sgshapiro# define PH_ERR_DATAERR PH_DATAERR 4771110560Sgshapiro# define PH_ERR_NOMATCH PH_NOMATCH 4772110560Sgshapiro# endif /* NPH_VERSION < 10200 */ 4773110560Sgshapiro 477464562Sgshapiro/* 477564562Sgshapiro** PH_MAP_PARSEARGS -- parse ph map definition args. 477664562Sgshapiro*/ 477764562Sgshapiro 477864562Sgshapirobool 477964562Sgshapiroph_map_parseargs(map, args) 478064562Sgshapiro MAP *map; 478164562Sgshapiro char *args; 478264562Sgshapiro{ 478390792Sgshapiro register bool done; 478490792Sgshapiro register char *p = args; 478564562Sgshapiro PH_MAP_STRUCT *pmap = NULL; 478664562Sgshapiro 478790792Sgshapiro /* initialize version string */ 4788168515Sgshapiro (void) sm_snprintf(phmap_id, sizeof(phmap_id), 478990792Sgshapiro "sendmail-%s phmap-20010529 libphclient-%s", 479090792Sgshapiro Version, libphclient_version); 479190792Sgshapiro 4792168515Sgshapiro pmap = (PH_MAP_STRUCT *) xalloc(sizeof(*pmap)); 479364562Sgshapiro 479464562Sgshapiro /* defaults */ 479564562Sgshapiro pmap->ph_servers = NULL; 479664562Sgshapiro pmap->ph_field_list = NULL; 479790792Sgshapiro pmap->ph = NULL; 479864562Sgshapiro pmap->ph_timeout = 0; 479990792Sgshapiro pmap->ph_fastclose = 0; 480064562Sgshapiro 480164562Sgshapiro map->map_mflags |= MF_TRY0NULL|MF_TRY1NULL; 480264562Sgshapiro for (;;) 480364562Sgshapiro { 480464562Sgshapiro while (isascii(*p) && isspace(*p)) 480564562Sgshapiro p++; 480664562Sgshapiro if (*p != '-') 480764562Sgshapiro break; 480864562Sgshapiro switch (*++p) 480964562Sgshapiro { 481064562Sgshapiro case 'N': 481164562Sgshapiro map->map_mflags |= MF_INCLNULL; 481264562Sgshapiro map->map_mflags &= ~MF_TRY0NULL; 481364562Sgshapiro break; 481464562Sgshapiro 481564562Sgshapiro case 'O': 481664562Sgshapiro map->map_mflags &= ~MF_TRY1NULL; 481764562Sgshapiro break; 481864562Sgshapiro 481964562Sgshapiro case 'o': 482064562Sgshapiro map->map_mflags |= MF_OPTIONAL; 482164562Sgshapiro break; 482264562Sgshapiro 482364562Sgshapiro case 'f': 482464562Sgshapiro map->map_mflags |= MF_NOFOLDCASE; 482564562Sgshapiro break; 482664562Sgshapiro 482764562Sgshapiro case 'm': 482864562Sgshapiro map->map_mflags |= MF_MATCHONLY; 482964562Sgshapiro break; 483064562Sgshapiro 483164562Sgshapiro case 'A': 483264562Sgshapiro map->map_mflags |= MF_APPEND; 483364562Sgshapiro break; 483464562Sgshapiro 483564562Sgshapiro case 'q': 483664562Sgshapiro map->map_mflags |= MF_KEEPQUOTES; 483764562Sgshapiro break; 483864562Sgshapiro 483964562Sgshapiro case 't': 484064562Sgshapiro map->map_mflags |= MF_NODEFER; 484164562Sgshapiro break; 484264562Sgshapiro 484364562Sgshapiro case 'a': 484464562Sgshapiro map->map_app = ++p; 484564562Sgshapiro break; 484664562Sgshapiro 484764562Sgshapiro case 'T': 484864562Sgshapiro map->map_tapp = ++p; 484964562Sgshapiro break; 485064562Sgshapiro 485164562Sgshapiro case 'l': 485264562Sgshapiro while (isascii(*++p) && isspace(*p)) 485364562Sgshapiro continue; 485464562Sgshapiro pmap->ph_timeout = atoi(p); 485564562Sgshapiro break; 485664562Sgshapiro 485764562Sgshapiro case 'S': 485864562Sgshapiro map->map_spacesub = *++p; 485964562Sgshapiro break; 486064562Sgshapiro 486164562Sgshapiro case 'D': 486264562Sgshapiro map->map_mflags |= MF_DEFER; 486364562Sgshapiro break; 486464562Sgshapiro 486564562Sgshapiro case 'h': /* PH server list */ 486664562Sgshapiro while (isascii(*++p) && isspace(*p)) 486764562Sgshapiro continue; 486864562Sgshapiro pmap->ph_servers = p; 486964562Sgshapiro break; 487064562Sgshapiro 487190792Sgshapiro case 'k': /* fields to search for */ 487264562Sgshapiro while (isascii(*++p) && isspace(*p)) 487364562Sgshapiro continue; 487464562Sgshapiro pmap->ph_field_list = p; 487564562Sgshapiro break; 487664562Sgshapiro 487764562Sgshapiro default: 487890792Sgshapiro syserr("ph_map_parseargs: unknown option -%c", *p); 487964562Sgshapiro } 488064562Sgshapiro 488164562Sgshapiro /* try to account for quoted strings */ 488264562Sgshapiro done = isascii(*p) && isspace(*p); 488364562Sgshapiro while (*p != '\0' && !done) 488464562Sgshapiro { 488564562Sgshapiro if (*p == '"') 488664562Sgshapiro { 488764562Sgshapiro while (*++p != '"' && *p != '\0') 488864562Sgshapiro continue; 488964562Sgshapiro if (*p != '\0') 489064562Sgshapiro p++; 489164562Sgshapiro } 489264562Sgshapiro else 489364562Sgshapiro p++; 489464562Sgshapiro done = isascii(*p) && isspace(*p); 489564562Sgshapiro } 489664562Sgshapiro 489764562Sgshapiro if (*p != '\0') 489864562Sgshapiro *p++ = '\0'; 489964562Sgshapiro } 490064562Sgshapiro 490164562Sgshapiro if (map->map_app != NULL) 490264562Sgshapiro map->map_app = newstr(ph_map_dequote(map->map_app)); 490364562Sgshapiro if (map->map_tapp != NULL) 490464562Sgshapiro map->map_tapp = newstr(ph_map_dequote(map->map_tapp)); 490564562Sgshapiro 490664562Sgshapiro if (pmap->ph_field_list != NULL) 490764562Sgshapiro pmap->ph_field_list = newstr(ph_map_dequote(pmap->ph_field_list)); 490864562Sgshapiro 490964562Sgshapiro if (pmap->ph_servers != NULL) 491064562Sgshapiro pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers)); 491164562Sgshapiro else 491264562Sgshapiro { 491364562Sgshapiro syserr("ph_map_parseargs: -h flag is required"); 491490792Sgshapiro return false; 491564562Sgshapiro } 491664562Sgshapiro 491764562Sgshapiro map->map_db1 = (ARBPTR_T) pmap; 491890792Sgshapiro return true; 491964562Sgshapiro} 492064562Sgshapiro 492164562Sgshapiro/* 492264562Sgshapiro** PH_MAP_CLOSE -- close the connection to the ph server 492364562Sgshapiro*/ 492464562Sgshapiro 492590792Sgshapirovoid 492690792Sgshapiroph_map_close(map) 492764562Sgshapiro MAP *map; 492864562Sgshapiro{ 492964562Sgshapiro PH_MAP_STRUCT *pmap; 493064562Sgshapiro 493164562Sgshapiro pmap = (PH_MAP_STRUCT *)map->map_db1; 493290792Sgshapiro if (tTd(38, 9)) 493394334Sgshapiro sm_dprintf("ph_map_close(%s): pmap->ph_fastclose=%d\n", 493490792Sgshapiro map->map_mname, pmap->ph_fastclose); 493564562Sgshapiro 493690792Sgshapiro 493790792Sgshapiro if (pmap->ph != NULL) 493864562Sgshapiro { 493990792Sgshapiro ph_set_sendhook(pmap->ph, NULL); 494090792Sgshapiro ph_set_recvhook(pmap->ph, NULL); 494190792Sgshapiro ph_close(pmap->ph, pmap->ph_fastclose); 494264562Sgshapiro } 494390792Sgshapiro 494464562Sgshapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 494564562Sgshapiro} 494664562Sgshapiro 494764562Sgshapirostatic jmp_buf PHTimeout; 494864562Sgshapiro 494964562Sgshapiro/* ARGSUSED */ 495064562Sgshapirostatic void 495190792Sgshapiroph_timeout(unused) 495290792Sgshapiro int unused; 495364562Sgshapiro{ 495477349Sgshapiro /* 495577349Sgshapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 495677349Sgshapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 495777349Sgshapiro ** DOING. 495877349Sgshapiro */ 495977349Sgshapiro 496077349Sgshapiro errno = ETIMEDOUT; 496164562Sgshapiro longjmp(PHTimeout, 1); 496264562Sgshapiro} 496364562Sgshapiro 496490792Sgshapirostatic void 4965110560Sgshapiro#if NPH_VERSION >= 10200 4966110560Sgshapiroph_map_send_debug(appdata, text) 4967110560Sgshapiro void *appdata; 4968110560Sgshapiro#else 496990792Sgshapiroph_map_send_debug(text) 4970110560Sgshapiro#endif 497190792Sgshapiro char *text; 497264562Sgshapiro{ 497390792Sgshapiro if (LogLevel > 9) 497490792Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, 497590792Sgshapiro "ph_map_send_debug: ==> %s", text); 497690792Sgshapiro if (tTd(38, 20)) 497790792Sgshapiro sm_dprintf("ph_map_send_debug: ==> %s\n", text); 497890792Sgshapiro} 497964562Sgshapiro 498090792Sgshapirostatic void 4981110560Sgshapiro#if NPH_VERSION >= 10200 4982110560Sgshapiroph_map_recv_debug(appdata, text) 4983110560Sgshapiro void *appdata; 4984110560Sgshapiro#else 498590792Sgshapiroph_map_recv_debug(text) 4986110560Sgshapiro#endif 498790792Sgshapiro char *text; 498890792Sgshapiro{ 498990792Sgshapiro if (LogLevel > 10) 499090792Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, 499190792Sgshapiro "ph_map_recv_debug: <== %s", text); 499290792Sgshapiro if (tTd(38, 21)) 499390792Sgshapiro sm_dprintf("ph_map_recv_debug: <== %s\n", text); 499464562Sgshapiro} 499564562Sgshapiro 499690792Sgshapiro/* 499764562Sgshapiro** PH_MAP_OPEN -- sub for opening PH map 499864562Sgshapiro*/ 499964562Sgshapirobool 500064562Sgshapiroph_map_open(map, mode) 500164562Sgshapiro MAP *map; 500264562Sgshapiro int mode; 500364562Sgshapiro{ 500490792Sgshapiro PH_MAP_STRUCT *pmap; 500590792Sgshapiro register SM_EVENT *ev = NULL; 500664562Sgshapiro int save_errno = 0; 500790792Sgshapiro char *hostlist, *host; 500864562Sgshapiro 500964562Sgshapiro if (tTd(38, 2)) 501090792Sgshapiro sm_dprintf("ph_map_open(%s)\n", map->map_mname); 501164562Sgshapiro 501264562Sgshapiro mode &= O_ACCMODE; 501364562Sgshapiro if (mode != O_RDONLY) 501464562Sgshapiro { 501564562Sgshapiro /* issue a pseudo-error message */ 501690792Sgshapiro errno = SM_EMAPCANTWRITE; 501790792Sgshapiro return false; 501864562Sgshapiro } 501964562Sgshapiro 502066494Sgshapiro if (CurEnv != NULL && CurEnv->e_sendmode == SM_DEFER && 502166494Sgshapiro bitset(MF_DEFER, map->map_mflags)) 502266494Sgshapiro { 502366494Sgshapiro if (tTd(9, 1)) 502490792Sgshapiro sm_dprintf("ph_map_open(%s) => DEFERRED\n", 502590792Sgshapiro map->map_mname); 502666494Sgshapiro 502766494Sgshapiro /* 502890792Sgshapiro ** Unset MF_DEFER here so that map_lookup() returns 502990792Sgshapiro ** a temporary failure using the bogus map and 503090792Sgshapiro ** map->map_tapp instead of the default permanent error. 503166494Sgshapiro */ 503266494Sgshapiro 503366494Sgshapiro map->map_mflags &= ~MF_DEFER; 503490792Sgshapiro return false; 503566494Sgshapiro } 503666494Sgshapiro 503764562Sgshapiro pmap = (PH_MAP_STRUCT *)map->map_db1; 503890792Sgshapiro pmap->ph_fastclose = 0; /* refresh field for reopen */ 503964562Sgshapiro 504090792Sgshapiro /* try each host in the list */ 504164562Sgshapiro hostlist = newstr(pmap->ph_servers); 504290792Sgshapiro for (host = strtok(hostlist, " "); 504390792Sgshapiro host != NULL; 504490792Sgshapiro host = strtok(NULL, " ")) 504564562Sgshapiro { 504690792Sgshapiro /* set timeout */ 504764562Sgshapiro if (pmap->ph_timeout != 0) 504864562Sgshapiro { 504964562Sgshapiro if (setjmp(PHTimeout) != 0) 505064562Sgshapiro { 505164562Sgshapiro ev = NULL; 505264562Sgshapiro if (LogLevel > 1) 505364562Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, 505464562Sgshapiro "timeout connecting to PH server %.100s", 505590792Sgshapiro host); 505664562Sgshapiro errno = ETIMEDOUT; 505764562Sgshapiro goto ph_map_open_abort; 505864562Sgshapiro } 505990792Sgshapiro ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0); 506064562Sgshapiro } 506190792Sgshapiro 506290792Sgshapiro /* open connection to server */ 5063110560Sgshapiro if (ph_open(&(pmap->ph), host, 5064110560Sgshapiro PH_OPEN_ROUNDROBIN|PH_OPEN_DONTID, 5065110560Sgshapiro ph_map_send_debug, ph_map_recv_debug 5066110560Sgshapiro#if NPH_VERSION >= 10200 5067110560Sgshapiro , NULL 5068110560Sgshapiro#endif 5069110560Sgshapiro ) == 0 5070110560Sgshapiro && ph_id(pmap->ph, phmap_id) == 0) 507164562Sgshapiro { 507264562Sgshapiro if (ev != NULL) 507390792Sgshapiro sm_clrevent(ev); 507490792Sgshapiro sm_free(hostlist); /* XXX */ 507590792Sgshapiro return true; 507664562Sgshapiro } 507790792Sgshapiro 507864562Sgshapiro ph_map_open_abort: 507990792Sgshapiro save_errno = errno; 508064562Sgshapiro if (ev != NULL) 508190792Sgshapiro sm_clrevent(ev); 5082110560Sgshapiro pmap->ph_fastclose = PH_CLOSE_FAST; 508390792Sgshapiro ph_map_close(map); 508490792Sgshapiro errno = save_errno; 508590792Sgshapiro } 508664562Sgshapiro 508766494Sgshapiro if (bitset(MF_NODEFER, map->map_mflags)) 508864562Sgshapiro { 508966494Sgshapiro if (errno == 0) 509064562Sgshapiro errno = EAGAIN; 509166494Sgshapiro syserr("ph_map_open: %s: cannot connect to PH server", 509266494Sgshapiro map->map_mname); 509364562Sgshapiro } 509466494Sgshapiro else if (!bitset(MF_OPTIONAL, map->map_mflags) && LogLevel > 1) 509564562Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, 509666494Sgshapiro "ph_map_open: %s: cannot connect to PH server", 509766494Sgshapiro map->map_mname); 509890792Sgshapiro sm_free(hostlist); /* XXX */ 509990792Sgshapiro return false; 510064562Sgshapiro} 510164562Sgshapiro 510264562Sgshapiro/* 510364562Sgshapiro** PH_MAP_LOOKUP -- look up key from ph server 510464562Sgshapiro*/ 510564562Sgshapiro 510664562Sgshapirochar * 510764562Sgshapiroph_map_lookup(map, key, args, pstat) 510864562Sgshapiro MAP *map; 510964562Sgshapiro char *key; 511064562Sgshapiro char **args; 511164562Sgshapiro int *pstat; 511264562Sgshapiro{ 511390792Sgshapiro int i, save_errno = 0; 511490792Sgshapiro register SM_EVENT *ev = NULL; 511564562Sgshapiro PH_MAP_STRUCT *pmap; 511690792Sgshapiro char *value = NULL; 511764562Sgshapiro 511864562Sgshapiro pmap = (PH_MAP_STRUCT *)map->map_db1; 511964562Sgshapiro 512064562Sgshapiro *pstat = EX_OK; 512164562Sgshapiro 512290792Sgshapiro /* set timeout */ 512364562Sgshapiro if (pmap->ph_timeout != 0) 512464562Sgshapiro { 512564562Sgshapiro if (setjmp(PHTimeout) != 0) 512664562Sgshapiro { 512764562Sgshapiro ev = NULL; 512864562Sgshapiro if (LogLevel > 1) 512964562Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, 513064562Sgshapiro "timeout during PH lookup of %.100s", 513164562Sgshapiro key); 513264562Sgshapiro errno = ETIMEDOUT; 513364562Sgshapiro *pstat = EX_TEMPFAIL; 513464562Sgshapiro goto ph_map_lookup_abort; 513564562Sgshapiro } 513690792Sgshapiro ev = sm_setevent(pmap->ph_timeout, ph_timeout, 0); 513764562Sgshapiro } 513864562Sgshapiro 513990792Sgshapiro /* perform lookup */ 514090792Sgshapiro i = ph_email_resolve(pmap->ph, key, pmap->ph_field_list, &value); 514190792Sgshapiro if (i == -1) 514290792Sgshapiro *pstat = EX_TEMPFAIL; 5143110560Sgshapiro else if (i == PH_ERR_NOMATCH || i == PH_ERR_DATAERR) 514490792Sgshapiro *pstat = EX_UNAVAILABLE; 514564562Sgshapiro 514664562Sgshapiro ph_map_lookup_abort: 514764562Sgshapiro if (ev != NULL) 514890792Sgshapiro sm_clrevent(ev); 514964562Sgshapiro 515064562Sgshapiro /* 515190792Sgshapiro ** Close the connection if the timer popped 515264562Sgshapiro ** or we got a temporary PH error 515364562Sgshapiro */ 515464562Sgshapiro 515564562Sgshapiro if (*pstat == EX_TEMPFAIL) 515690792Sgshapiro { 515790792Sgshapiro save_errno = errno; 5158110560Sgshapiro pmap->ph_fastclose = PH_CLOSE_FAST; 515990792Sgshapiro ph_map_close(map); 516090792Sgshapiro errno = save_errno; 516190792Sgshapiro } 516264562Sgshapiro 516364562Sgshapiro if (*pstat == EX_OK) 516464562Sgshapiro { 516564562Sgshapiro if (tTd(38,20)) 516690792Sgshapiro sm_dprintf("ph_map_lookup: %s => %s\n", key, value); 516764562Sgshapiro 516864562Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 516990792Sgshapiro return map_rewrite(map, key, strlen(key), NULL); 517064562Sgshapiro else 517190792Sgshapiro return map_rewrite(map, value, strlen(value), args); 517264562Sgshapiro } 517364562Sgshapiro 517464562Sgshapiro return NULL; 517564562Sgshapiro} 517664562Sgshapiro#endif /* PH_MAP */ 5177168515Sgshapiro 517890792Sgshapiro/* 517942575Speter** syslog map 518038032Speter*/ 518138032Speter 518238032Speter#define map_prio map_lockfd /* overload field */ 518338032Speter 518438032Speter/* 518542575Speter** SYSLOG_MAP_PARSEARGS -- check for priority level to syslog messages. 518638032Speter*/ 518738032Speter 518838032Speterbool 518938032Spetersyslog_map_parseargs(map, args) 519038032Speter MAP *map; 519138032Speter char *args; 519238032Speter{ 519338032Speter char *p = args; 519438032Speter char *priority = NULL; 519538032Speter 519664562Sgshapiro /* there is no check whether there is really an argument */ 519764562Sgshapiro while (*p != '\0') 519838032Speter { 519938032Speter while (isascii(*p) && isspace(*p)) 520038032Speter p++; 520138032Speter if (*p != '-') 520238032Speter break; 520364562Sgshapiro ++p; 520464562Sgshapiro if (*p == 'D') 520564562Sgshapiro { 520664562Sgshapiro map->map_mflags |= MF_DEFER; 520764562Sgshapiro ++p; 520864562Sgshapiro } 520964562Sgshapiro else if (*p == 'S') 521064562Sgshapiro { 521164562Sgshapiro map->map_spacesub = *++p; 521264562Sgshapiro if (*p != '\0') 521364562Sgshapiro p++; 521464562Sgshapiro } 521564562Sgshapiro else if (*p == 'L') 521664562Sgshapiro { 521764562Sgshapiro while (*++p != '\0' && isascii(*p) && isspace(*p)) 521864562Sgshapiro continue; 521964562Sgshapiro if (*p == '\0') 522064562Sgshapiro break; 522164562Sgshapiro priority = p; 522264562Sgshapiro while (*p != '\0' && !(isascii(*p) && isspace(*p))) 522364562Sgshapiro p++; 522464562Sgshapiro if (*p != '\0') 522564562Sgshapiro *p++ = '\0'; 522664562Sgshapiro } 522764562Sgshapiro else 522864562Sgshapiro { 522964562Sgshapiro syserr("Illegal option %c map syslog", *p); 523064562Sgshapiro ++p; 523164562Sgshapiro } 523238032Speter } 523338032Speter 523438032Speter if (priority == NULL) 523538032Speter map->map_prio = LOG_INFO; 523638032Speter else 523738032Speter { 523890792Sgshapiro if (sm_strncasecmp("LOG_", priority, 4) == 0) 523938032Speter priority += 4; 524038032Speter 524138032Speter#ifdef LOG_EMERG 524290792Sgshapiro if (sm_strcasecmp("EMERG", priority) == 0) 524338032Speter map->map_prio = LOG_EMERG; 524438032Speter else 524564562Sgshapiro#endif /* LOG_EMERG */ 524638032Speter#ifdef LOG_ALERT 524790792Sgshapiro if (sm_strcasecmp("ALERT", priority) == 0) 524838032Speter map->map_prio = LOG_ALERT; 524938032Speter else 525064562Sgshapiro#endif /* LOG_ALERT */ 525138032Speter#ifdef LOG_CRIT 525290792Sgshapiro if (sm_strcasecmp("CRIT", priority) == 0) 525338032Speter map->map_prio = LOG_CRIT; 525438032Speter else 525564562Sgshapiro#endif /* LOG_CRIT */ 525638032Speter#ifdef LOG_ERR 525790792Sgshapiro if (sm_strcasecmp("ERR", priority) == 0) 525838032Speter map->map_prio = LOG_ERR; 525938032Speter else 526064562Sgshapiro#endif /* LOG_ERR */ 526138032Speter#ifdef LOG_WARNING 526290792Sgshapiro if (sm_strcasecmp("WARNING", priority) == 0) 526338032Speter map->map_prio = LOG_WARNING; 526438032Speter else 526564562Sgshapiro#endif /* LOG_WARNING */ 526638032Speter#ifdef LOG_NOTICE 526790792Sgshapiro if (sm_strcasecmp("NOTICE", priority) == 0) 526838032Speter map->map_prio = LOG_NOTICE; 526938032Speter else 527064562Sgshapiro#endif /* LOG_NOTICE */ 527138032Speter#ifdef LOG_INFO 527290792Sgshapiro if (sm_strcasecmp("INFO", priority) == 0) 527338032Speter map->map_prio = LOG_INFO; 527438032Speter else 527564562Sgshapiro#endif /* LOG_INFO */ 527638032Speter#ifdef LOG_DEBUG 527790792Sgshapiro if (sm_strcasecmp("DEBUG", priority) == 0) 527838032Speter map->map_prio = LOG_DEBUG; 527938032Speter else 528064562Sgshapiro#endif /* LOG_DEBUG */ 528138032Speter { 528290792Sgshapiro syserr("syslog_map_parseargs: Unknown priority %s", 528338032Speter priority); 528490792Sgshapiro return false; 528538032Speter } 528638032Speter } 528790792Sgshapiro return true; 528838032Speter} 528938032Speter 529038032Speter/* 529142575Speter** SYSLOG_MAP_LOOKUP -- rewrite and syslog message. Always return empty string 529238032Speter*/ 529338032Speter 529438032Speterchar * 529538032Spetersyslog_map_lookup(map, string, args, statp) 529638032Speter MAP *map; 529738032Speter char *string; 529838032Speter char **args; 529938032Speter int *statp; 530038032Speter{ 530138032Speter char *ptr = map_rewrite(map, string, strlen(string), args); 530238032Speter 530338032Speter if (ptr != NULL) 530438032Speter { 530538032Speter if (tTd(38, 20)) 530690792Sgshapiro sm_dprintf("syslog_map_lookup(%s (priority %d): %s\n", 530764562Sgshapiro map->map_mname, map->map_prio, ptr); 530838032Speter 530938032Speter sm_syslog(map->map_prio, CurEnv->e_id, "%s", ptr); 531038032Speter } 531138032Speter 531238032Speter *statp = EX_OK; 531338032Speter return ""; 531438032Speter} 531538032Speter 5316168515Sgshapiro#if _FFR_DPRINTF_MAP 531790792Sgshapiro/* 5318168515Sgshapiro** dprintf map 5319168515Sgshapiro*/ 5320168515Sgshapiro 5321168515Sgshapiro#define map_dbg_level map_lockfd /* overload field */ 5322168515Sgshapiro 5323168515Sgshapiro/* 5324168515Sgshapiro** DPRINTF_MAP_PARSEARGS -- check for priority level to dprintf messages. 5325168515Sgshapiro*/ 5326168515Sgshapiro 5327168515Sgshapirobool 5328168515Sgshapirodprintf_map_parseargs(map, args) 5329168515Sgshapiro MAP *map; 5330168515Sgshapiro char *args; 5331168515Sgshapiro{ 5332168515Sgshapiro char *p = args; 5333168515Sgshapiro char *dbg_level = NULL; 5334168515Sgshapiro 5335168515Sgshapiro /* there is no check whether there is really an argument */ 5336168515Sgshapiro while (*p != '\0') 5337168515Sgshapiro { 5338168515Sgshapiro while (isascii(*p) && isspace(*p)) 5339168515Sgshapiro p++; 5340168515Sgshapiro if (*p != '-') 5341168515Sgshapiro break; 5342168515Sgshapiro ++p; 5343168515Sgshapiro if (*p == 'D') 5344168515Sgshapiro { 5345168515Sgshapiro map->map_mflags |= MF_DEFER; 5346168515Sgshapiro ++p; 5347168515Sgshapiro } 5348168515Sgshapiro else if (*p == 'S') 5349168515Sgshapiro { 5350168515Sgshapiro map->map_spacesub = *++p; 5351168515Sgshapiro if (*p != '\0') 5352168515Sgshapiro p++; 5353168515Sgshapiro } 5354168515Sgshapiro else if (*p == 'd') 5355168515Sgshapiro { 5356168515Sgshapiro while (*++p != '\0' && isascii(*p) && isspace(*p)) 5357168515Sgshapiro continue; 5358168515Sgshapiro if (*p == '\0') 5359168515Sgshapiro break; 5360168515Sgshapiro dbg_level = p; 5361168515Sgshapiro while (*p != '\0' && !(isascii(*p) && isspace(*p))) 5362168515Sgshapiro p++; 5363168515Sgshapiro if (*p != '\0') 5364168515Sgshapiro *p++ = '\0'; 5365168515Sgshapiro } 5366168515Sgshapiro else 5367168515Sgshapiro { 5368168515Sgshapiro syserr("Illegal option %c map dprintf", *p); 5369168515Sgshapiro ++p; 5370168515Sgshapiro } 5371168515Sgshapiro } 5372168515Sgshapiro 5373168515Sgshapiro if (dbg_level == NULL) 5374168515Sgshapiro map->map_dbg_level = 0; 5375168515Sgshapiro else 5376168515Sgshapiro { 5377168515Sgshapiro if (!(isascii(*dbg_level) && isdigit(*dbg_level))) 5378168515Sgshapiro { 5379168515Sgshapiro syserr("dprintf map \"%s\", file %s: -d should specify a number, not %s", 5380168515Sgshapiro map->map_mname, map->map_file, 5381168515Sgshapiro dbg_level); 5382168515Sgshapiro return false; 5383168515Sgshapiro } 5384168515Sgshapiro map->map_dbg_level = atoi(dbg_level); 5385168515Sgshapiro } 5386168515Sgshapiro return true; 5387168515Sgshapiro} 5388168515Sgshapiro 5389168515Sgshapiro/* 5390168515Sgshapiro** DPRINTF_MAP_LOOKUP -- rewrite and print message. Always return empty string 5391168515Sgshapiro*/ 5392168515Sgshapiro 5393168515Sgshapirochar * 5394168515Sgshapirodprintf_map_lookup(map, string, args, statp) 5395168515Sgshapiro MAP *map; 5396168515Sgshapiro char *string; 5397168515Sgshapiro char **args; 5398168515Sgshapiro int *statp; 5399168515Sgshapiro{ 5400168515Sgshapiro char *ptr = map_rewrite(map, string, strlen(string), args); 5401168515Sgshapiro 5402168515Sgshapiro if (ptr != NULL && tTd(85, map->map_dbg_level)) 5403168515Sgshapiro sm_dprintf("%s\n", ptr); 5404168515Sgshapiro *statp = EX_OK; 5405168515Sgshapiro return ""; 5406168515Sgshapiro} 5407168515Sgshapiro#endif /* _FFR_DPRINTF_MAP */ 5408168515Sgshapiro 5409168515Sgshapiro/* 541038032Speter** HESIOD Modules 541138032Speter*/ 541238032Speter 541390792Sgshapiro#if HESIOD 541438032Speter 541538032Speterbool 541638032Speterhes_map_open(map, mode) 541738032Speter MAP *map; 541838032Speter int mode; 541938032Speter{ 542038032Speter if (tTd(38, 2)) 542190792Sgshapiro sm_dprintf("hes_map_open(%s, %s, %d)\n", 542238032Speter map->map_mname, map->map_file, mode); 542338032Speter 542438032Speter if (mode != O_RDONLY) 542538032Speter { 542638032Speter /* issue a pseudo-error message */ 542790792Sgshapiro errno = SM_EMAPCANTWRITE; 542890792Sgshapiro return false; 542938032Speter } 543038032Speter 543164562Sgshapiro# ifdef HESIOD_INIT 543238032Speter if (HesiodContext != NULL || hesiod_init(&HesiodContext) == 0) 543390792Sgshapiro return true; 543438032Speter 543538032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 543694334Sgshapiro syserr("451 4.3.5 cannot initialize Hesiod map (%s)", 543790792Sgshapiro sm_errstring(errno)); 543890792Sgshapiro return false; 543964562Sgshapiro# else /* HESIOD_INIT */ 544038032Speter if (hes_error() == HES_ER_UNINIT) 544138032Speter hes_init(); 544238032Speter switch (hes_error()) 544338032Speter { 544438032Speter case HES_ER_OK: 544538032Speter case HES_ER_NOTFOUND: 544690792Sgshapiro return true; 544738032Speter } 544838032Speter 544938032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 545094334Sgshapiro syserr("451 4.3.5 cannot initialize Hesiod map (%d)", hes_error()); 545138032Speter 545290792Sgshapiro return false; 545364562Sgshapiro# endif /* HESIOD_INIT */ 545438032Speter} 545538032Speter 545638032Speterchar * 545738032Speterhes_map_lookup(map, name, av, statp) 545838032Speter MAP *map; 545938032Speter char *name; 546038032Speter char **av; 546138032Speter int *statp; 546238032Speter{ 546338032Speter char **hp; 546438032Speter 546538032Speter if (tTd(38, 20)) 546690792Sgshapiro sm_dprintf("hes_map_lookup(%s, %s)\n", map->map_file, name); 546738032Speter 546838032Speter if (name[0] == '\\') 546938032Speter { 547038032Speter char *np; 547138032Speter int nl; 547277349Sgshapiro int save_errno; 547338032Speter char nbuf[MAXNAME]; 547438032Speter 547538032Speter nl = strlen(name); 5476168515Sgshapiro if (nl < sizeof(nbuf) - 1) 547738032Speter np = nbuf; 547838032Speter else 547938032Speter np = xalloc(strlen(name) + 2); 548038032Speter np[0] = '\\'; 5481168515Sgshapiro (void) sm_strlcpy(&np[1], name, (sizeof(nbuf)) - 1); 548264562Sgshapiro# ifdef HESIOD_INIT 548338032Speter hp = hesiod_resolve(HesiodContext, np, map->map_file); 548464562Sgshapiro# else /* HESIOD_INIT */ 548538032Speter hp = hes_resolve(np, map->map_file); 548664562Sgshapiro# endif /* HESIOD_INIT */ 548777349Sgshapiro save_errno = errno; 548838032Speter if (np != nbuf) 548990792Sgshapiro sm_free(np); /* XXX */ 549077349Sgshapiro errno = save_errno; 549138032Speter } 549238032Speter else 549338032Speter { 549464562Sgshapiro# ifdef HESIOD_INIT 549538032Speter hp = hesiod_resolve(HesiodContext, name, map->map_file); 549664562Sgshapiro# else /* HESIOD_INIT */ 549738032Speter hp = hes_resolve(name, map->map_file); 549864562Sgshapiro# endif /* HESIOD_INIT */ 549938032Speter } 550064562Sgshapiro# ifdef HESIOD_INIT 550177349Sgshapiro if (hp == NULL || *hp == NULL) 550238032Speter { 550338032Speter switch (errno) 550438032Speter { 550538032Speter case ENOENT: 550638032Speter *statp = EX_NOTFOUND; 550738032Speter break; 550838032Speter case ECONNREFUSED: 550938032Speter *statp = EX_TEMPFAIL; 551038032Speter break; 551190792Sgshapiro case EMSGSIZE: 551238032Speter case ENOMEM: 551338032Speter default: 551438032Speter *statp = EX_UNAVAILABLE; 551538032Speter break; 551638032Speter } 551782017Sgshapiro if (hp != NULL) 551882017Sgshapiro hesiod_free_list(HesiodContext, hp); 551938032Speter return NULL; 552038032Speter } 552164562Sgshapiro# else /* HESIOD_INIT */ 552238032Speter if (hp == NULL || hp[0] == NULL) 552338032Speter { 552438032Speter switch (hes_error()) 552538032Speter { 552638032Speter case HES_ER_OK: 552738032Speter *statp = EX_OK; 552838032Speter break; 552938032Speter 553038032Speter case HES_ER_NOTFOUND: 553138032Speter *statp = EX_NOTFOUND; 553238032Speter break; 553338032Speter 553438032Speter case HES_ER_CONFIG: 553538032Speter *statp = EX_UNAVAILABLE; 553638032Speter break; 553738032Speter 553838032Speter case HES_ER_NET: 553938032Speter *statp = EX_TEMPFAIL; 554038032Speter break; 554138032Speter } 554238032Speter return NULL; 554338032Speter } 554464562Sgshapiro# endif /* HESIOD_INIT */ 554538032Speter 554638032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 554738032Speter return map_rewrite(map, name, strlen(name), NULL); 554838032Speter else 554938032Speter return map_rewrite(map, hp[0], strlen(hp[0]), av); 555038032Speter} 555138032Speter 555290792Sgshapiro/* 555390792Sgshapiro** HES_MAP_CLOSE -- free the Hesiod context 555490792Sgshapiro*/ 555590792Sgshapiro 555690792Sgshapirovoid 555790792Sgshapirohes_map_close(map) 555890792Sgshapiro MAP *map; 555990792Sgshapiro{ 556090792Sgshapiro if (tTd(38, 20)) 556190792Sgshapiro sm_dprintf("hes_map_close(%s)\n", map->map_file); 556290792Sgshapiro 556390792Sgshapiro# ifdef HESIOD_INIT 556490792Sgshapiro /* Free the hesiod context */ 556590792Sgshapiro if (HesiodContext != NULL) 556690792Sgshapiro { 556790792Sgshapiro hesiod_end(HesiodContext); 556890792Sgshapiro HesiodContext = NULL; 556990792Sgshapiro } 557090792Sgshapiro# endif /* HESIOD_INIT */ 557190792Sgshapiro} 557290792Sgshapiro 557364562Sgshapiro#endif /* HESIOD */ 557490792Sgshapiro/* 557538032Speter** NeXT NETINFO Modules 557638032Speter*/ 557738032Speter 557838032Speter#if NETINFO 557938032Speter 558038032Speter# define NETINFO_DEFAULT_DIR "/aliases" 558138032Speter# define NETINFO_DEFAULT_PROPERTY "members" 558238032Speter 558338032Speter/* 558438032Speter** NI_MAP_OPEN -- open NetInfo Aliases 558538032Speter*/ 558638032Speter 558738032Speterbool 558838032Speterni_map_open(map, mode) 558938032Speter MAP *map; 559038032Speter int mode; 559138032Speter{ 559238032Speter if (tTd(38, 2)) 559390792Sgshapiro sm_dprintf("ni_map_open(%s, %s, %d)\n", 559438032Speter map->map_mname, map->map_file, mode); 559538032Speter mode &= O_ACCMODE; 559638032Speter 559738032Speter if (*map->map_file == '\0') 559838032Speter map->map_file = NETINFO_DEFAULT_DIR; 559938032Speter 560038032Speter if (map->map_valcolnm == NULL) 560138032Speter map->map_valcolnm = NETINFO_DEFAULT_PROPERTY; 560238032Speter 560390792Sgshapiro if (map->map_coldelim == '\0') 560490792Sgshapiro { 560590792Sgshapiro if (bitset(MF_ALIAS, map->map_mflags)) 560690792Sgshapiro map->map_coldelim = ','; 560790792Sgshapiro else if (bitset(MF_FILECLASS, map->map_mflags)) 560890792Sgshapiro map->map_coldelim = ' '; 560990792Sgshapiro } 561090792Sgshapiro return true; 561138032Speter} 561238032Speter 561338032Speter 561438032Speter/* 561538032Speter** NI_MAP_LOOKUP -- look up a datum in NetInfo 561638032Speter*/ 561738032Speter 561838032Speterchar * 561938032Speterni_map_lookup(map, name, av, statp) 562038032Speter MAP *map; 562138032Speter char *name; 562238032Speter char **av; 562338032Speter int *statp; 562438032Speter{ 562538032Speter char *res; 562638032Speter char *propval; 562738032Speter 562838032Speter if (tTd(38, 20)) 562990792Sgshapiro sm_dprintf("ni_map_lookup(%s, %s)\n", map->map_mname, name); 563038032Speter 563138032Speter propval = ni_propval(map->map_file, map->map_keycolnm, name, 563238032Speter map->map_valcolnm, map->map_coldelim); 563338032Speter 563438032Speter if (propval == NULL) 563538032Speter return NULL; 563638032Speter 563790792Sgshapiro SM_TRY 563890792Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 563990792Sgshapiro res = map_rewrite(map, name, strlen(name), NULL); 564090792Sgshapiro else 564190792Sgshapiro res = map_rewrite(map, propval, strlen(propval), av); 564290792Sgshapiro SM_FINALLY 564390792Sgshapiro sm_free(propval); 564490792Sgshapiro SM_END_TRY 564538032Speter return res; 564638032Speter} 564738032Speter 564838032Speter 564964562Sgshapirostatic bool 565038032Speterni_getcanonname(name, hbsize, statp) 565138032Speter char *name; 565238032Speter int hbsize; 565338032Speter int *statp; 565438032Speter{ 565538032Speter char *vptr; 565638032Speter char *ptr; 565738032Speter char nbuf[MAXNAME + 1]; 565838032Speter 565938032Speter if (tTd(38, 20)) 566090792Sgshapiro sm_dprintf("ni_getcanonname(%s)\n", name); 566138032Speter 5662168515Sgshapiro if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf)) 566338032Speter { 566438032Speter *statp = EX_UNAVAILABLE; 566590792Sgshapiro return false; 566638032Speter } 566773188Sgshapiro (void) shorten_hostname(nbuf); 566838032Speter 566938032Speter /* we only accept single token search key */ 567038032Speter if (strchr(nbuf, '.')) 567138032Speter { 567238032Speter *statp = EX_NOHOST; 567390792Sgshapiro return false; 567438032Speter } 567538032Speter 567638032Speter /* Do the search */ 567738032Speter vptr = ni_propval("/machines", NULL, nbuf, "name", '\n'); 567838032Speter 567938032Speter if (vptr == NULL) 568038032Speter { 568138032Speter *statp = EX_NOHOST; 568290792Sgshapiro return false; 568338032Speter } 568438032Speter 568538032Speter /* Only want the first machine name */ 568638032Speter if ((ptr = strchr(vptr, '\n')) != NULL) 568738032Speter *ptr = '\0'; 568838032Speter 568990792Sgshapiro if (sm_strlcpy(name, vptr, hbsize) >= hbsize) 569038032Speter { 569177349Sgshapiro sm_free(vptr); 569290792Sgshapiro *statp = EX_UNAVAILABLE; 569390792Sgshapiro return true; 569438032Speter } 569577349Sgshapiro sm_free(vptr); 569690792Sgshapiro *statp = EX_OK; 569790792Sgshapiro return false; 569838032Speter} 569990792Sgshapiro#endif /* NETINFO */ 570038032Speter/* 570138032Speter** TEXT (unindexed text file) Modules 570238032Speter** 570338032Speter** This code donated by Sun Microsystems. 570438032Speter*/ 570538032Speter 570638032Speter#define map_sff map_lockfd /* overload field */ 570738032Speter 570838032Speter 570938032Speter/* 571038032Speter** TEXT_MAP_OPEN -- open text table 571138032Speter*/ 571238032Speter 571338032Speterbool 571438032Spetertext_map_open(map, mode) 571538032Speter MAP *map; 571638032Speter int mode; 571738032Speter{ 571864562Sgshapiro long sff; 571938032Speter int i; 572038032Speter 572138032Speter if (tTd(38, 2)) 572290792Sgshapiro sm_dprintf("text_map_open(%s, %s, %d)\n", 572338032Speter map->map_mname, map->map_file, mode); 572438032Speter 572538032Speter mode &= O_ACCMODE; 572638032Speter if (mode != O_RDONLY) 572738032Speter { 572838032Speter errno = EPERM; 572990792Sgshapiro return false; 573038032Speter } 573138032Speter 573238032Speter if (*map->map_file == '\0') 573338032Speter { 573438032Speter syserr("text map \"%s\": file name required", 573538032Speter map->map_mname); 573690792Sgshapiro return false; 573738032Speter } 573838032Speter 573938032Speter if (map->map_file[0] != '/') 574038032Speter { 574138032Speter syserr("text map \"%s\": file name must be fully qualified", 574238032Speter map->map_mname); 574390792Sgshapiro return false; 574438032Speter } 574538032Speter 574638032Speter sff = SFF_ROOTOK|SFF_REGONLY; 574764562Sgshapiro if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 574838032Speter sff |= SFF_NOWLINK; 574964562Sgshapiro if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail)) 575038032Speter sff |= SFF_SAFEDIRPATH; 575138032Speter if ((i = safefile(map->map_file, RunAsUid, RunAsGid, RunAsUserName, 575238032Speter sff, S_IRUSR, NULL)) != 0) 575338032Speter { 575464562Sgshapiro int save_errno = errno; 575564562Sgshapiro 575638032Speter /* cannot open this map */ 575738032Speter if (tTd(38, 2)) 575890792Sgshapiro sm_dprintf("\tunsafe map file: %d\n", i); 575964562Sgshapiro errno = save_errno; 576038032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 576138032Speter syserr("text map \"%s\": unsafe map file %s", 576238032Speter map->map_mname, map->map_file); 576390792Sgshapiro return false; 576438032Speter } 576538032Speter 576638032Speter if (map->map_keycolnm == NULL) 576738032Speter map->map_keycolno = 0; 576838032Speter else 576938032Speter { 577038032Speter if (!(isascii(*map->map_keycolnm) && isdigit(*map->map_keycolnm))) 577138032Speter { 577238032Speter syserr("text map \"%s\", file %s: -k should specify a number, not %s", 577338032Speter map->map_mname, map->map_file, 577438032Speter map->map_keycolnm); 577590792Sgshapiro return false; 577638032Speter } 577738032Speter map->map_keycolno = atoi(map->map_keycolnm); 577838032Speter } 577938032Speter 578038032Speter if (map->map_valcolnm == NULL) 578138032Speter map->map_valcolno = 0; 578238032Speter else 578338032Speter { 578438032Speter if (!(isascii(*map->map_valcolnm) && isdigit(*map->map_valcolnm))) 578538032Speter { 578638032Speter syserr("text map \"%s\", file %s: -v should specify a number, not %s", 578738032Speter map->map_mname, map->map_file, 578838032Speter map->map_valcolnm); 578990792Sgshapiro return false; 579038032Speter } 579138032Speter map->map_valcolno = atoi(map->map_valcolnm); 579238032Speter } 579338032Speter 579438032Speter if (tTd(38, 2)) 579538032Speter { 579690792Sgshapiro sm_dprintf("text_map_open(%s, %s): delimiter = ", 579738032Speter map->map_mname, map->map_file); 579838032Speter if (map->map_coldelim == '\0') 579990792Sgshapiro sm_dprintf("(white space)\n"); 580038032Speter else 580190792Sgshapiro sm_dprintf("%c\n", map->map_coldelim); 580238032Speter } 580338032Speter 580438032Speter map->map_sff = sff; 580590792Sgshapiro return true; 580638032Speter} 580738032Speter 580838032Speter 580938032Speter/* 581038032Speter** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table 581138032Speter*/ 581238032Speter 581338032Speterchar * 581438032Spetertext_map_lookup(map, name, av, statp) 581538032Speter MAP *map; 581638032Speter char *name; 581738032Speter char **av; 581838032Speter int *statp; 581938032Speter{ 582038032Speter char *vp; 582138032Speter auto int vsize; 582238032Speter int buflen; 582390792Sgshapiro SM_FILE_T *f; 582438032Speter char delim; 582538032Speter int key_idx; 582638032Speter bool found_it; 582764562Sgshapiro long sff = map->map_sff; 582838032Speter char search_key[MAXNAME + 1]; 582938032Speter char linebuf[MAXLINE]; 583038032Speter char buf[MAXNAME + 1]; 583138032Speter 583290792Sgshapiro found_it = false; 583338032Speter if (tTd(38, 20)) 583490792Sgshapiro sm_dprintf("text_map_lookup(%s, %s)\n", map->map_mname, name); 583538032Speter 583638032Speter buflen = strlen(name); 5837168515Sgshapiro if (buflen > sizeof(search_key) - 1) 5838168515Sgshapiro buflen = sizeof(search_key) - 1; /* XXX just cut if off? */ 583964562Sgshapiro memmove(search_key, name, buflen); 584038032Speter search_key[buflen] = '\0'; 584138032Speter if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 584238032Speter makelower(search_key); 584338032Speter 584438032Speter f = safefopen(map->map_file, O_RDONLY, FileMode, sff); 584538032Speter if (f == NULL) 584638032Speter { 584738032Speter map->map_mflags &= ~(MF_VALID|MF_OPEN); 584838032Speter *statp = EX_UNAVAILABLE; 584938032Speter return NULL; 585038032Speter } 585138032Speter key_idx = map->map_keycolno; 585238032Speter delim = map->map_coldelim; 585398121Sgshapiro while (sm_io_fgets(f, SM_TIME_DEFAULT, 5854249729Sgshapiro linebuf, sizeof(linebuf)) >= 0) 585538032Speter { 585638032Speter char *p; 585738032Speter 585838032Speter /* skip comment line */ 585938032Speter if (linebuf[0] == '#') 586038032Speter continue; 586138032Speter p = strchr(linebuf, '\n'); 586238032Speter if (p != NULL) 586338032Speter *p = '\0'; 5864168515Sgshapiro p = get_column(linebuf, key_idx, delim, buf, sizeof(buf)); 586590792Sgshapiro if (p != NULL && sm_strcasecmp(search_key, p) == 0) 586638032Speter { 586790792Sgshapiro found_it = true; 586838032Speter break; 586938032Speter } 587038032Speter } 587190792Sgshapiro (void) sm_io_close(f, SM_TIME_DEFAULT); 587238032Speter if (!found_it) 587338032Speter { 587438032Speter *statp = EX_NOTFOUND; 587538032Speter return NULL; 587638032Speter } 5877168515Sgshapiro vp = get_column(linebuf, map->map_valcolno, delim, buf, sizeof(buf)); 587842575Speter if (vp == NULL) 587942575Speter { 588042575Speter *statp = EX_NOTFOUND; 588142575Speter return NULL; 588242575Speter } 588338032Speter vsize = strlen(vp); 588438032Speter *statp = EX_OK; 588538032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 588638032Speter return map_rewrite(map, name, strlen(name), NULL); 588738032Speter else 588838032Speter return map_rewrite(map, vp, vsize, av); 588938032Speter} 589038032Speter 589138032Speter/* 589238032Speter** TEXT_GETCANONNAME -- look up canonical name in hosts file 589338032Speter*/ 589438032Speter 589564562Sgshapirostatic bool 589638032Spetertext_getcanonname(name, hbsize, statp) 589738032Speter char *name; 589838032Speter int hbsize; 589938032Speter int *statp; 590038032Speter{ 590138032Speter bool found; 590273188Sgshapiro char *dot; 590390792Sgshapiro SM_FILE_T *f; 590438032Speter char linebuf[MAXLINE]; 590538032Speter char cbuf[MAXNAME + 1]; 590638032Speter char nbuf[MAXNAME + 1]; 590738032Speter 590838032Speter if (tTd(38, 20)) 590990792Sgshapiro sm_dprintf("text_getcanonname(%s)\n", name); 591038032Speter 5911168515Sgshapiro if (sm_strlcpy(nbuf, name, sizeof(nbuf)) >= sizeof(nbuf)) 591238032Speter { 591338032Speter *statp = EX_UNAVAILABLE; 591490792Sgshapiro return false; 591538032Speter } 591673188Sgshapiro dot = shorten_hostname(nbuf); 591738032Speter 591890792Sgshapiro f = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, HostsFile, SM_IO_RDONLY, 591990792Sgshapiro NULL); 592038032Speter if (f == NULL) 592138032Speter { 592238032Speter *statp = EX_UNAVAILABLE; 592390792Sgshapiro return false; 592438032Speter } 592590792Sgshapiro found = false; 592690792Sgshapiro while (!found && 592798121Sgshapiro sm_io_fgets(f, SM_TIME_DEFAULT, 5928249729Sgshapiro linebuf, sizeof(linebuf)) >= 0) 592938032Speter { 593038032Speter char *p = strpbrk(linebuf, "#\n"); 593138032Speter 593238032Speter if (p != NULL) 593338032Speter *p = '\0'; 593438032Speter if (linebuf[0] != '\0') 593573188Sgshapiro found = extract_canonname(nbuf, dot, linebuf, 5936168515Sgshapiro cbuf, sizeof(cbuf)); 593738032Speter } 593890792Sgshapiro (void) sm_io_close(f, SM_TIME_DEFAULT); 593938032Speter if (!found) 594038032Speter { 594138032Speter *statp = EX_NOHOST; 594290792Sgshapiro return false; 594338032Speter } 594438032Speter 594590792Sgshapiro if (sm_strlcpy(name, cbuf, hbsize) >= hbsize) 594638032Speter { 594790792Sgshapiro *statp = EX_UNAVAILABLE; 594890792Sgshapiro return false; 594938032Speter } 595090792Sgshapiro *statp = EX_OK; 595190792Sgshapiro return true; 595238032Speter} 595390792Sgshapiro/* 595438032Speter** STAB (Symbol Table) Modules 595538032Speter*/ 595638032Speter 595738032Speter 595838032Speter/* 595938032Speter** STAB_MAP_LOOKUP -- look up alias in symbol table 596038032Speter*/ 596138032Speter 596238032Speter/* ARGSUSED2 */ 596338032Speterchar * 596438032Speterstab_map_lookup(map, name, av, pstat) 596538032Speter register MAP *map; 596638032Speter char *name; 596738032Speter char **av; 596838032Speter int *pstat; 596938032Speter{ 597038032Speter register STAB *s; 597138032Speter 597238032Speter if (tTd(38, 20)) 597390792Sgshapiro sm_dprintf("stab_lookup(%s, %s)\n", 597438032Speter map->map_mname, name); 597538032Speter 597638032Speter s = stab(name, ST_ALIAS, ST_FIND); 5977147078Sgshapiro if (s == NULL) 5978147078Sgshapiro return NULL; 5979147078Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 5980147078Sgshapiro return map_rewrite(map, name, strlen(name), NULL); 5981147078Sgshapiro else 5982147078Sgshapiro return map_rewrite(map, s->s_alias, strlen(s->s_alias), av); 598338032Speter} 598438032Speter 598538032Speter/* 598638032Speter** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild) 598738032Speter*/ 598838032Speter 598938032Spetervoid 599038032Speterstab_map_store(map, lhs, rhs) 599138032Speter register MAP *map; 599238032Speter char *lhs; 599338032Speter char *rhs; 599438032Speter{ 599538032Speter register STAB *s; 599638032Speter 599738032Speter s = stab(lhs, ST_ALIAS, ST_ENTER); 599838032Speter s->s_alias = newstr(rhs); 599938032Speter} 600038032Speter 600138032Speter 600238032Speter/* 600338032Speter** STAB_MAP_OPEN -- initialize (reads data file) 600438032Speter** 6005223067Sgshapiro** This is a weird case -- it is only intended as a fallback for 600638032Speter** aliases. For this reason, opens for write (only during a 600738032Speter** "newaliases") always fails, and opens for read open the 600838032Speter** actual underlying text file instead of the database. 600938032Speter*/ 601038032Speter 601138032Speterbool 601238032Speterstab_map_open(map, mode) 601338032Speter register MAP *map; 601438032Speter int mode; 601538032Speter{ 601690792Sgshapiro SM_FILE_T *af; 601764562Sgshapiro long sff; 601838032Speter struct stat st; 601938032Speter 602038032Speter if (tTd(38, 2)) 602190792Sgshapiro sm_dprintf("stab_map_open(%s, %s, %d)\n", 602238032Speter map->map_mname, map->map_file, mode); 602338032Speter 602438032Speter mode &= O_ACCMODE; 602538032Speter if (mode != O_RDONLY) 602638032Speter { 602738032Speter errno = EPERM; 602890792Sgshapiro return false; 602938032Speter } 603038032Speter 603138032Speter sff = SFF_ROOTOK|SFF_REGONLY; 603264562Sgshapiro if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail)) 603338032Speter sff |= SFF_NOWLINK; 603464562Sgshapiro if (!bitnset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail)) 603538032Speter sff |= SFF_SAFEDIRPATH; 603638032Speter af = safefopen(map->map_file, O_RDONLY, 0444, sff); 603738032Speter if (af == NULL) 603890792Sgshapiro return false; 603990792Sgshapiro readaliases(map, af, false, false); 604038032Speter 604190792Sgshapiro if (fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &st) >= 0) 604238032Speter map->map_mtime = st.st_mtime; 604390792Sgshapiro (void) sm_io_close(af, SM_TIME_DEFAULT); 604438032Speter 604590792Sgshapiro return true; 604638032Speter} 604790792Sgshapiro/* 604838032Speter** Implicit Modules 604938032Speter** 605038032Speter** Tries several types. For back compatibility of aliases. 605138032Speter*/ 605238032Speter 605338032Speter 605438032Speter/* 605538032Speter** IMPL_MAP_LOOKUP -- lookup in best open database 605638032Speter*/ 605738032Speter 605838032Speterchar * 605938032Speterimpl_map_lookup(map, name, av, pstat) 606038032Speter MAP *map; 606138032Speter char *name; 606238032Speter char **av; 606338032Speter int *pstat; 606438032Speter{ 606538032Speter if (tTd(38, 20)) 606690792Sgshapiro sm_dprintf("impl_map_lookup(%s, %s)\n", 606738032Speter map->map_mname, name); 606838032Speter 606990792Sgshapiro#if NEWDB 607038032Speter if (bitset(MF_IMPL_HASH, map->map_mflags)) 607138032Speter return db_map_lookup(map, name, av, pstat); 607264562Sgshapiro#endif /* NEWDB */ 607390792Sgshapiro#if NDBM 607438032Speter if (bitset(MF_IMPL_NDBM, map->map_mflags)) 607538032Speter return ndbm_map_lookup(map, name, av, pstat); 607664562Sgshapiro#endif /* NDBM */ 607738032Speter return stab_map_lookup(map, name, av, pstat); 607838032Speter} 607938032Speter 608038032Speter/* 608138032Speter** IMPL_MAP_STORE -- store in open databases 608238032Speter*/ 608338032Speter 608438032Spetervoid 608538032Speterimpl_map_store(map, lhs, rhs) 608638032Speter MAP *map; 608738032Speter char *lhs; 608838032Speter char *rhs; 608938032Speter{ 609038032Speter if (tTd(38, 12)) 609190792Sgshapiro sm_dprintf("impl_map_store(%s, %s, %s)\n", 609238032Speter map->map_mname, lhs, rhs); 609390792Sgshapiro#if NEWDB 609438032Speter if (bitset(MF_IMPL_HASH, map->map_mflags)) 609538032Speter db_map_store(map, lhs, rhs); 609664562Sgshapiro#endif /* NEWDB */ 609790792Sgshapiro#if NDBM 609838032Speter if (bitset(MF_IMPL_NDBM, map->map_mflags)) 609938032Speter ndbm_map_store(map, lhs, rhs); 610064562Sgshapiro#endif /* NDBM */ 610138032Speter stab_map_store(map, lhs, rhs); 610238032Speter} 610338032Speter 610438032Speter/* 610538032Speter** IMPL_MAP_OPEN -- implicit database open 610638032Speter*/ 610738032Speter 610838032Speterbool 610938032Speterimpl_map_open(map, mode) 611038032Speter MAP *map; 611138032Speter int mode; 611238032Speter{ 611338032Speter if (tTd(38, 2)) 611490792Sgshapiro sm_dprintf("impl_map_open(%s, %s, %d)\n", 611538032Speter map->map_mname, map->map_file, mode); 611638032Speter 611738032Speter mode &= O_ACCMODE; 611890792Sgshapiro#if NEWDB 611938032Speter map->map_mflags |= MF_IMPL_HASH; 612038032Speter if (hash_map_open(map, mode)) 612138032Speter { 612238032Speter# ifdef NDBM_YP_COMPAT 612338032Speter if (mode == O_RDONLY || strstr(map->map_file, "/yp/") == NULL) 612464562Sgshapiro# endif /* NDBM_YP_COMPAT */ 612590792Sgshapiro return true; 612638032Speter } 612738032Speter else 612838032Speter map->map_mflags &= ~MF_IMPL_HASH; 612964562Sgshapiro#endif /* NEWDB */ 613090792Sgshapiro#if NDBM 613138032Speter map->map_mflags |= MF_IMPL_NDBM; 613238032Speter if (ndbm_map_open(map, mode)) 613338032Speter { 613490792Sgshapiro return true; 613538032Speter } 613638032Speter else 613738032Speter map->map_mflags &= ~MF_IMPL_NDBM; 613864562Sgshapiro#endif /* NDBM */ 613938032Speter 614038032Speter#if defined(NEWDB) || defined(NDBM) 614138032Speter if (Verbose) 614238032Speter message("WARNING: cannot open alias database %s%s", 614338032Speter map->map_file, 614438032Speter mode == O_RDONLY ? "; reading text version" : ""); 614564562Sgshapiro#else /* defined(NEWDB) || defined(NDBM) */ 614638032Speter if (mode != O_RDONLY) 614738032Speter usrerr("Cannot rebuild aliases: no database format defined"); 614864562Sgshapiro#endif /* defined(NEWDB) || defined(NDBM) */ 614938032Speter 615038032Speter if (mode == O_RDONLY) 615138032Speter return stab_map_open(map, mode); 615238032Speter else 615390792Sgshapiro return false; 615438032Speter} 615538032Speter 615638032Speter 615738032Speter/* 615838032Speter** IMPL_MAP_CLOSE -- close any open database(s) 615938032Speter*/ 616038032Speter 616138032Spetervoid 616238032Speterimpl_map_close(map) 616338032Speter MAP *map; 616438032Speter{ 616538032Speter if (tTd(38, 9)) 616690792Sgshapiro sm_dprintf("impl_map_close(%s, %s, %lx)\n", 616738032Speter map->map_mname, map->map_file, map->map_mflags); 616890792Sgshapiro#if NEWDB 616938032Speter if (bitset(MF_IMPL_HASH, map->map_mflags)) 617038032Speter { 617138032Speter db_map_close(map); 617238032Speter map->map_mflags &= ~MF_IMPL_HASH; 617338032Speter } 617464562Sgshapiro#endif /* NEWDB */ 617538032Speter 617690792Sgshapiro#if NDBM 617738032Speter if (bitset(MF_IMPL_NDBM, map->map_mflags)) 617838032Speter { 617938032Speter ndbm_map_close(map); 618038032Speter map->map_mflags &= ~MF_IMPL_NDBM; 618138032Speter } 618264562Sgshapiro#endif /* NDBM */ 618338032Speter} 618490792Sgshapiro/* 618538032Speter** User map class. 618638032Speter** 618738032Speter** Provides access to the system password file. 618838032Speter*/ 618938032Speter 619038032Speter/* 619138032Speter** USER_MAP_OPEN -- open user map 619238032Speter** 619338032Speter** Really just binds field names to field numbers. 619438032Speter*/ 619538032Speter 619638032Speterbool 619738032Speteruser_map_open(map, mode) 619838032Speter MAP *map; 619938032Speter int mode; 620038032Speter{ 620138032Speter if (tTd(38, 2)) 620290792Sgshapiro sm_dprintf("user_map_open(%s, %d)\n", 620338032Speter map->map_mname, mode); 620438032Speter 620538032Speter mode &= O_ACCMODE; 620638032Speter if (mode != O_RDONLY) 620738032Speter { 620838032Speter /* issue a pseudo-error message */ 620990792Sgshapiro errno = SM_EMAPCANTWRITE; 621090792Sgshapiro return false; 621138032Speter } 621238032Speter if (map->map_valcolnm == NULL) 621364562Sgshapiro /* EMPTY */ 621438032Speter /* nothing */ ; 621590792Sgshapiro else if (sm_strcasecmp(map->map_valcolnm, "name") == 0) 621638032Speter map->map_valcolno = 1; 621790792Sgshapiro else if (sm_strcasecmp(map->map_valcolnm, "passwd") == 0) 621838032Speter map->map_valcolno = 2; 621990792Sgshapiro else if (sm_strcasecmp(map->map_valcolnm, "uid") == 0) 622038032Speter map->map_valcolno = 3; 622190792Sgshapiro else if (sm_strcasecmp(map->map_valcolnm, "gid") == 0) 622238032Speter map->map_valcolno = 4; 622390792Sgshapiro else if (sm_strcasecmp(map->map_valcolnm, "gecos") == 0) 622438032Speter map->map_valcolno = 5; 622590792Sgshapiro else if (sm_strcasecmp(map->map_valcolnm, "dir") == 0) 622638032Speter map->map_valcolno = 6; 622790792Sgshapiro else if (sm_strcasecmp(map->map_valcolnm, "shell") == 0) 622838032Speter map->map_valcolno = 7; 622938032Speter else 623038032Speter { 623138032Speter syserr("User map %s: unknown column name %s", 623238032Speter map->map_mname, map->map_valcolnm); 623390792Sgshapiro return false; 623438032Speter } 623590792Sgshapiro return true; 623638032Speter} 623738032Speter 623838032Speter 623938032Speter/* 624038032Speter** USER_MAP_LOOKUP -- look up a user in the passwd file. 624138032Speter*/ 624238032Speter 624338032Speter/* ARGSUSED3 */ 624438032Speterchar * 624538032Speteruser_map_lookup(map, key, av, statp) 624638032Speter MAP *map; 624738032Speter char *key; 624838032Speter char **av; 624938032Speter int *statp; 625038032Speter{ 625138032Speter auto bool fuzzy; 625290792Sgshapiro SM_MBDB_T user; 625338032Speter 625438032Speter if (tTd(38, 20)) 625590792Sgshapiro sm_dprintf("user_map_lookup(%s, %s)\n", 625638032Speter map->map_mname, key); 625738032Speter 625890792Sgshapiro *statp = finduser(key, &fuzzy, &user); 625990792Sgshapiro if (*statp != EX_OK) 626038032Speter return NULL; 626138032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 626238032Speter return map_rewrite(map, key, strlen(key), NULL); 626338032Speter else 626438032Speter { 626538032Speter char *rwval = NULL; 626638032Speter char buf[30]; 626738032Speter 626838032Speter switch (map->map_valcolno) 626938032Speter { 627038032Speter case 0: 627138032Speter case 1: 627290792Sgshapiro rwval = user.mbdb_name; 627338032Speter break; 627438032Speter 627538032Speter case 2: 627690792Sgshapiro rwval = "x"; /* passwd no longer supported */ 627738032Speter break; 627838032Speter 627938032Speter case 3: 6280168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%d", 628190792Sgshapiro (int) user.mbdb_uid); 628238032Speter rwval = buf; 628338032Speter break; 628438032Speter 628538032Speter case 4: 6286168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%d", 628790792Sgshapiro (int) user.mbdb_gid); 628838032Speter rwval = buf; 628938032Speter break; 629038032Speter 629138032Speter case 5: 629290792Sgshapiro rwval = user.mbdb_fullname; 629338032Speter break; 629438032Speter 629538032Speter case 6: 629690792Sgshapiro rwval = user.mbdb_homedir; 629738032Speter break; 629838032Speter 629938032Speter case 7: 630090792Sgshapiro rwval = user.mbdb_shell; 630138032Speter break; 6302159609Sgshapiro default: 6303159609Sgshapiro syserr("user_map %s: bogus field %d", 6304159609Sgshapiro map->map_mname, map->map_valcolno); 6305159609Sgshapiro return NULL; 630638032Speter } 630738032Speter return map_rewrite(map, rwval, strlen(rwval), av); 630838032Speter } 630938032Speter} 631090792Sgshapiro/* 631138032Speter** Program map type. 631238032Speter** 631338032Speter** This provides access to arbitrary programs. It should be used 631438032Speter** only very sparingly, since there is no way to bound the cost 631538032Speter** of invoking an arbitrary program. 631638032Speter*/ 631738032Speter 631838032Speterchar * 631938032Speterprog_map_lookup(map, name, av, statp) 632038032Speter MAP *map; 632138032Speter char *name; 632238032Speter char **av; 632338032Speter int *statp; 632438032Speter{ 632538032Speter int i; 632664562Sgshapiro int save_errno; 632738032Speter int fd; 632864562Sgshapiro int status; 632938032Speter auto pid_t pid; 633064562Sgshapiro register char *p; 633138032Speter char *rval; 633238032Speter char *argv[MAXPV + 1]; 633338032Speter char buf[MAXLINE]; 633438032Speter 633538032Speter if (tTd(38, 20)) 633690792Sgshapiro sm_dprintf("prog_map_lookup(%s, %s) %s\n", 633738032Speter map->map_mname, name, map->map_file); 633838032Speter 633938032Speter i = 0; 634038032Speter argv[i++] = map->map_file; 634138032Speter if (map->map_rebuild != NULL) 634238032Speter { 6343168515Sgshapiro (void) sm_strlcpy(buf, map->map_rebuild, sizeof(buf)); 634438032Speter for (p = strtok(buf, " \t"); p != NULL; p = strtok(NULL, " \t")) 634538032Speter { 634638032Speter if (i >= MAXPV - 1) 634738032Speter break; 634838032Speter argv[i++] = p; 634938032Speter } 635038032Speter } 635138032Speter argv[i++] = name; 635238032Speter argv[i] = NULL; 635338032Speter if (tTd(38, 21)) 635438032Speter { 635590792Sgshapiro sm_dprintf("prog_open:"); 635638032Speter for (i = 0; argv[i] != NULL; i++) 635790792Sgshapiro sm_dprintf(" %s", argv[i]); 635890792Sgshapiro sm_dprintf("\n"); 635938032Speter } 636090792Sgshapiro (void) sm_blocksignal(SIGCHLD); 636138032Speter pid = prog_open(argv, &fd, CurEnv); 636238032Speter if (pid < 0) 636338032Speter { 636438032Speter if (!bitset(MF_OPTIONAL, map->map_mflags)) 636538032Speter syserr("prog_map_lookup(%s) failed (%s) -- closing", 636690792Sgshapiro map->map_mname, sm_errstring(errno)); 636738032Speter else if (tTd(38, 9)) 636890792Sgshapiro sm_dprintf("prog_map_lookup(%s) failed (%s) -- closing", 636990792Sgshapiro map->map_mname, sm_errstring(errno)); 637038032Speter map->map_mflags &= ~(MF_VALID|MF_OPEN); 637138032Speter *statp = EX_OSFILE; 637238032Speter return NULL; 637338032Speter } 6374168515Sgshapiro i = read(fd, buf, sizeof(buf) - 1); 637538032Speter if (i < 0) 637638032Speter { 637790792Sgshapiro syserr("prog_map_lookup(%s): read error %s", 637890792Sgshapiro map->map_mname, sm_errstring(errno)); 637938032Speter rval = NULL; 638038032Speter } 638138032Speter else if (i == 0) 638238032Speter { 638338032Speter if (tTd(38, 20)) 638490792Sgshapiro sm_dprintf("prog_map_lookup(%s): empty answer\n", 638590792Sgshapiro map->map_mname); 638638032Speter rval = NULL; 638738032Speter } 638838032Speter else 638938032Speter { 639038032Speter buf[i] = '\0'; 639138032Speter p = strchr(buf, '\n'); 639238032Speter if (p != NULL) 639338032Speter *p = '\0'; 639438032Speter 639538032Speter /* collect the return value */ 639638032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 639738032Speter rval = map_rewrite(map, name, strlen(name), NULL); 639838032Speter else 639977349Sgshapiro rval = map_rewrite(map, buf, strlen(buf), av); 640038032Speter 640138032Speter /* now flush any additional output */ 6402168515Sgshapiro while ((i = read(fd, buf, sizeof(buf))) > 0) 640338032Speter continue; 640438032Speter } 640538032Speter 640638032Speter /* wait for the process to terminate */ 640764562Sgshapiro (void) close(fd); 640864562Sgshapiro status = waitfor(pid); 640964562Sgshapiro save_errno = errno; 641090792Sgshapiro (void) sm_releasesignal(SIGCHLD); 641164562Sgshapiro errno = save_errno; 641238032Speter 641364562Sgshapiro if (status == -1) 641438032Speter { 641590792Sgshapiro syserr("prog_map_lookup(%s): wait error %s", 641690792Sgshapiro map->map_mname, sm_errstring(errno)); 641738032Speter *statp = EX_SOFTWARE; 641838032Speter rval = NULL; 641938032Speter } 642064562Sgshapiro else if (WIFEXITED(status)) 642138032Speter { 642264562Sgshapiro if ((*statp = WEXITSTATUS(status)) != EX_OK) 642338032Speter rval = NULL; 642438032Speter } 642538032Speter else 642638032Speter { 642738032Speter syserr("prog_map_lookup(%s): child died on signal %d", 642890792Sgshapiro map->map_mname, status); 642938032Speter *statp = EX_UNAVAILABLE; 643038032Speter rval = NULL; 643138032Speter } 643238032Speter return rval; 643338032Speter} 643490792Sgshapiro/* 643538032Speter** Sequenced map type. 643638032Speter** 643738032Speter** Tries each map in order until something matches, much like 643838032Speter** implicit. Stores go to the first map in the list that can 643938032Speter** support storing. 644038032Speter** 644138032Speter** This is slightly unusual in that there are two interfaces. 644238032Speter** The "sequence" interface lets you stack maps arbitrarily. 644338032Speter** The "switch" interface builds a sequence map by looking 644438032Speter** at a system-dependent configuration file such as 644538032Speter** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix. 644638032Speter** 644738032Speter** We don't need an explicit open, since all maps are 644890792Sgshapiro** opened on demand. 644938032Speter*/ 645038032Speter 645138032Speter/* 645238032Speter** SEQ_MAP_PARSE -- Sequenced map parsing 645338032Speter*/ 645438032Speter 645538032Speterbool 645638032Speterseq_map_parse(map, ap) 645738032Speter MAP *map; 645838032Speter char *ap; 645938032Speter{ 646038032Speter int maxmap; 646138032Speter 646238032Speter if (tTd(38, 2)) 646390792Sgshapiro sm_dprintf("seq_map_parse(%s, %s)\n", map->map_mname, ap); 646438032Speter maxmap = 0; 646538032Speter while (*ap != '\0') 646638032Speter { 646738032Speter register char *p; 646838032Speter STAB *s; 646938032Speter 647038032Speter /* find beginning of map name */ 647138032Speter while (isascii(*ap) && isspace(*ap)) 647238032Speter ap++; 647364562Sgshapiro for (p = ap; 647464562Sgshapiro (isascii(*p) && isalnum(*p)) || *p == '_' || *p == '.'; 647564562Sgshapiro p++) 647638032Speter continue; 647738032Speter if (*p != '\0') 647838032Speter *p++ = '\0'; 647938032Speter while (*p != '\0' && (!isascii(*p) || !isalnum(*p))) 648038032Speter p++; 648138032Speter if (*ap == '\0') 648238032Speter { 648338032Speter ap = p; 648438032Speter continue; 648538032Speter } 648638032Speter s = stab(ap, ST_MAP, ST_FIND); 648738032Speter if (s == NULL) 648838032Speter { 648938032Speter syserr("Sequence map %s: unknown member map %s", 649038032Speter map->map_mname, ap); 649138032Speter } 649290792Sgshapiro else if (maxmap >= MAXMAPSTACK) 649338032Speter { 649438032Speter syserr("Sequence map %s: too many member maps (%d max)", 649538032Speter map->map_mname, MAXMAPSTACK); 649638032Speter maxmap++; 649738032Speter } 649838032Speter else if (maxmap < MAXMAPSTACK) 649938032Speter { 650038032Speter map->map_stack[maxmap++] = &s->s_map; 650138032Speter } 650238032Speter ap = p; 650338032Speter } 650490792Sgshapiro return true; 650538032Speter} 650638032Speter 650738032Speter/* 650838032Speter** SWITCH_MAP_OPEN -- open a switched map 650938032Speter** 651038032Speter** This looks at the system-dependent configuration and builds 651138032Speter** a sequence map that does the same thing. 651238032Speter** 651338032Speter** Every system must define a switch_map_find routine in conf.c 651438032Speter** that will return the list of service types associated with a 651538032Speter** given service class. 651638032Speter*/ 651738032Speter 651838032Speterbool 651938032Speterswitch_map_open(map, mode) 652038032Speter MAP *map; 652138032Speter int mode; 652238032Speter{ 652338032Speter int mapno; 652438032Speter int nmaps; 652538032Speter char *maptype[MAXMAPSTACK]; 652638032Speter 652738032Speter if (tTd(38, 2)) 652890792Sgshapiro sm_dprintf("switch_map_open(%s, %s, %d)\n", 652938032Speter map->map_mname, map->map_file, mode); 653038032Speter 653138032Speter mode &= O_ACCMODE; 653238032Speter nmaps = switch_map_find(map->map_file, maptype, map->map_return); 653338032Speter if (tTd(38, 19)) 653438032Speter { 653590792Sgshapiro sm_dprintf("\tswitch_map_find => %d\n", nmaps); 653638032Speter for (mapno = 0; mapno < nmaps; mapno++) 653790792Sgshapiro sm_dprintf("\t\t%s\n", maptype[mapno]); 653838032Speter } 653938032Speter if (nmaps <= 0 || nmaps > MAXMAPSTACK) 654090792Sgshapiro return false; 654138032Speter 654238032Speter for (mapno = 0; mapno < nmaps; mapno++) 654338032Speter { 654438032Speter register STAB *s; 654538032Speter char nbuf[MAXNAME + 1]; 654638032Speter 654738032Speter if (maptype[mapno] == NULL) 654838032Speter continue; 6549168515Sgshapiro (void) sm_strlcpyn(nbuf, sizeof(nbuf), 3, 655090792Sgshapiro map->map_mname, ".", maptype[mapno]); 655138032Speter s = stab(nbuf, ST_MAP, ST_FIND); 655238032Speter if (s == NULL) 655338032Speter { 655438032Speter syserr("Switch map %s: unknown member map %s", 655538032Speter map->map_mname, nbuf); 655638032Speter } 655738032Speter else 655838032Speter { 655938032Speter map->map_stack[mapno] = &s->s_map; 656038032Speter if (tTd(38, 4)) 656190792Sgshapiro sm_dprintf("\tmap_stack[%d] = %s:%s\n", 656290792Sgshapiro mapno, 656390792Sgshapiro s->s_map.map_class->map_cname, 656490792Sgshapiro nbuf); 656538032Speter } 656638032Speter } 656790792Sgshapiro return true; 656838032Speter} 656938032Speter 657090792Sgshapiro#if 0 657138032Speter/* 657238032Speter** SEQ_MAP_CLOSE -- close all underlying maps 657338032Speter*/ 657438032Speter 657538032Spetervoid 657638032Speterseq_map_close(map) 657738032Speter MAP *map; 657838032Speter{ 657938032Speter int mapno; 658038032Speter 658138032Speter if (tTd(38, 9)) 658290792Sgshapiro sm_dprintf("seq_map_close(%s)\n", map->map_mname); 658338032Speter 658438032Speter for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 658538032Speter { 658638032Speter MAP *mm = map->map_stack[mapno]; 658738032Speter 658838032Speter if (mm == NULL || !bitset(MF_OPEN, mm->map_mflags)) 658938032Speter continue; 659077349Sgshapiro mm->map_mflags |= MF_CLOSING; 659138032Speter mm->map_class->map_close(mm); 659277349Sgshapiro mm->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 659338032Speter } 659438032Speter} 659590792Sgshapiro#endif /* 0 */ 659638032Speter 659738032Speter/* 659838032Speter** SEQ_MAP_LOOKUP -- sequenced map lookup 659938032Speter*/ 660038032Speter 660138032Speterchar * 660238032Speterseq_map_lookup(map, key, args, pstat) 660338032Speter MAP *map; 660438032Speter char *key; 660538032Speter char **args; 660638032Speter int *pstat; 660738032Speter{ 660838032Speter int mapno; 660938032Speter int mapbit = 0x01; 661090792Sgshapiro bool tempfail = false; 661138032Speter 661238032Speter if (tTd(38, 20)) 661390792Sgshapiro sm_dprintf("seq_map_lookup(%s, %s)\n", map->map_mname, key); 661438032Speter 661538032Speter for (mapno = 0; mapno < MAXMAPSTACK; mapbit <<= 1, mapno++) 661638032Speter { 661738032Speter MAP *mm = map->map_stack[mapno]; 661838032Speter char *rv; 661938032Speter 662038032Speter if (mm == NULL) 662138032Speter continue; 662264562Sgshapiro if (!bitset(MF_OPEN, mm->map_mflags) && 662364562Sgshapiro !openmap(mm)) 662438032Speter { 662538032Speter if (bitset(mapbit, map->map_return[MA_UNAVAIL])) 662638032Speter { 662738032Speter *pstat = EX_UNAVAILABLE; 662838032Speter return NULL; 662938032Speter } 663038032Speter continue; 663138032Speter } 663238032Speter *pstat = EX_OK; 663338032Speter rv = mm->map_class->map_lookup(mm, key, args, pstat); 663438032Speter if (rv != NULL) 663538032Speter return rv; 663638032Speter if (*pstat == EX_TEMPFAIL) 663738032Speter { 663838032Speter if (bitset(mapbit, map->map_return[MA_TRYAGAIN])) 663938032Speter return NULL; 664090792Sgshapiro tempfail = true; 664138032Speter } 664238032Speter else if (bitset(mapbit, map->map_return[MA_NOTFOUND])) 664338032Speter break; 664438032Speter } 664538032Speter if (tempfail) 664638032Speter *pstat = EX_TEMPFAIL; 664738032Speter else if (*pstat == EX_OK) 664838032Speter *pstat = EX_NOTFOUND; 664938032Speter return NULL; 665038032Speter} 665138032Speter 665238032Speter/* 665338032Speter** SEQ_MAP_STORE -- sequenced map store 665438032Speter*/ 665538032Speter 665638032Spetervoid 665738032Speterseq_map_store(map, key, val) 665838032Speter MAP *map; 665938032Speter char *key; 666038032Speter char *val; 666138032Speter{ 666238032Speter int mapno; 666338032Speter 666438032Speter if (tTd(38, 12)) 666590792Sgshapiro sm_dprintf("seq_map_store(%s, %s, %s)\n", 666638032Speter map->map_mname, key, val); 666738032Speter 666838032Speter for (mapno = 0; mapno < MAXMAPSTACK; mapno++) 666938032Speter { 667038032Speter MAP *mm = map->map_stack[mapno]; 667138032Speter 667238032Speter if (mm == NULL || !bitset(MF_WRITABLE, mm->map_mflags)) 667338032Speter continue; 667438032Speter 667538032Speter mm->map_class->map_store(mm, key, val); 667638032Speter return; 667738032Speter } 667838032Speter syserr("seq_map_store(%s, %s, %s): no writable map", 667938032Speter map->map_mname, key, val); 668038032Speter} 668190792Sgshapiro/* 668238032Speter** NULL stubs 668338032Speter*/ 668438032Speter 668538032Speter/* ARGSUSED */ 668638032Speterbool 668738032Speternull_map_open(map, mode) 668838032Speter MAP *map; 668938032Speter int mode; 669038032Speter{ 669190792Sgshapiro return true; 669238032Speter} 669338032Speter 669438032Speter/* ARGSUSED */ 669538032Spetervoid 669638032Speternull_map_close(map) 669738032Speter MAP *map; 669838032Speter{ 669938032Speter return; 670038032Speter} 670138032Speter 670238032Speterchar * 670338032Speternull_map_lookup(map, key, args, pstat) 670438032Speter MAP *map; 670538032Speter char *key; 670638032Speter char **args; 670738032Speter int *pstat; 670838032Speter{ 670938032Speter *pstat = EX_NOTFOUND; 671038032Speter return NULL; 671138032Speter} 671238032Speter 671338032Speter/* ARGSUSED */ 671438032Spetervoid 671538032Speternull_map_store(map, key, val) 671638032Speter MAP *map; 671738032Speter char *key; 671838032Speter char *val; 671938032Speter{ 672038032Speter return; 672138032Speter} 672238032Speter 6723203004SgshapiroMAPCLASS NullMapClass = 6724203004Sgshapiro{ 6725203004Sgshapiro "null-map", NULL, 0, 6726203004Sgshapiro NULL, null_map_lookup, null_map_store, 6727203004Sgshapiro null_map_open, null_map_close, 6728203004Sgshapiro}; 6729203004Sgshapiro 673038032Speter/* 673138032Speter** BOGUS stubs 673238032Speter*/ 673338032Speter 673438032Speterchar * 673538032Speterbogus_map_lookup(map, key, args, pstat) 673638032Speter MAP *map; 673738032Speter char *key; 673838032Speter char **args; 673938032Speter int *pstat; 674038032Speter{ 674138032Speter *pstat = EX_TEMPFAIL; 674238032Speter return NULL; 674338032Speter} 674438032Speter 674538032SpeterMAPCLASS BogusMapClass = 674638032Speter{ 674790792Sgshapiro "bogus-map", NULL, 0, 674890792Sgshapiro NULL, bogus_map_lookup, null_map_store, 674990792Sgshapiro null_map_open, null_map_close, 675038032Speter}; 675190792Sgshapiro/* 675264562Sgshapiro** MACRO modules 675364562Sgshapiro*/ 675464562Sgshapiro 675564562Sgshapirochar * 675664562Sgshapiromacro_map_lookup(map, name, av, statp) 675764562Sgshapiro MAP *map; 675864562Sgshapiro char *name; 675964562Sgshapiro char **av; 676064562Sgshapiro int *statp; 676164562Sgshapiro{ 676264562Sgshapiro int mid; 676364562Sgshapiro 676464562Sgshapiro if (tTd(38, 20)) 676590792Sgshapiro sm_dprintf("macro_map_lookup(%s, %s)\n", map->map_mname, 676664562Sgshapiro name == NULL ? "NULL" : name); 676764562Sgshapiro 676864562Sgshapiro if (name == NULL || 676964562Sgshapiro *name == '\0' || 677090792Sgshapiro (mid = macid(name)) == 0) 677164562Sgshapiro { 677264562Sgshapiro *statp = EX_CONFIG; 677364562Sgshapiro return NULL; 677464562Sgshapiro } 677564562Sgshapiro 677664562Sgshapiro if (av[1] == NULL) 677790792Sgshapiro macdefine(&CurEnv->e_macro, A_PERM, mid, NULL); 677864562Sgshapiro else 677990792Sgshapiro macdefine(&CurEnv->e_macro, A_TEMP, mid, av[1]); 678064562Sgshapiro 678164562Sgshapiro *statp = EX_OK; 678264562Sgshapiro return ""; 678364562Sgshapiro} 678490792Sgshapiro/* 678538032Speter** REGEX modules 678638032Speter*/ 678738032Speter 678890792Sgshapiro#if MAP_REGEX 678938032Speter 679038032Speter# include <regex.h> 679138032Speter 679238032Speter# define DEFAULT_DELIM CONDELSE 679338032Speter# define END_OF_FIELDS -1 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 6806141858Sgshapirostatic int parse_fields __P((char *, int *, int, int)); 6807141858Sgshapirostatic char *regex_map_rewrite __P((MAP *, const char*, size_t, char **)); 6808141858Sgshapiro 680938032Speterstatic int 681038032Speterparse_fields(s, ibuf, blen, nr_substrings) 681138032Speter char *s; 681238032Speter int *ibuf; /* array */ 681338032Speter int blen; /* number of elements in ibuf */ 681438032Speter int nr_substrings; /* number of substrings in the pattern */ 681538032Speter{ 681638032Speter register char *cp; 681738032Speter int i = 0; 681890792Sgshapiro bool lastone = false; 681938032Speter 682038032Speter blen--; /* for terminating END_OF_FIELDS */ 682138032Speter cp = s; 682238032Speter do 682338032Speter { 682438032Speter for (;; cp++) 682538032Speter { 682638032Speter if (*cp == ',') 682738032Speter { 682838032Speter *cp = '\0'; 682938032Speter break; 683038032Speter } 683138032Speter if (*cp == '\0') 683238032Speter { 683390792Sgshapiro lastone = true; 683438032Speter break; 683538032Speter } 683638032Speter } 683738032Speter if (i < blen) 683838032Speter { 683938032Speter int val = atoi(s); 684038032Speter 684138032Speter if (val < 0 || val >= nr_substrings) 684238032Speter { 684338032Speter syserr("field (%d) out of range, only %d substrings in pattern", 684438032Speter val, nr_substrings); 684538032Speter return -1; 684638032Speter } 684738032Speter ibuf[i++] = val; 684838032Speter } 684938032Speter else 685038032Speter { 685190792Sgshapiro syserr("too many fields, %d max", blen); 685238032Speter return -1; 685338032Speter } 685438032Speter s = ++cp; 685538032Speter } while (!lastone); 685638032Speter ibuf[i] = END_OF_FIELDS; 685738032Speter return i; 685838032Speter} 685938032Speter 686038032Speterbool 686138032Speterregex_map_init(map, ap) 686238032Speter MAP *map; 686338032Speter char *ap; 686438032Speter{ 686538032Speter int regerr; 686638032Speter struct regex_map *map_p; 686738032Speter register char *p; 686838032Speter char *sub_param = NULL; 686938032Speter int pflags; 687090792Sgshapiro static char defdstr[] = { (char) DEFAULT_DELIM, '\0' }; 687138032Speter 687238032Speter if (tTd(38, 2)) 687390792Sgshapiro sm_dprintf("regex_map_init: mapname '%s', args '%s'\n", 687464562Sgshapiro map->map_mname, ap); 687538032Speter 687638032Speter pflags = REG_ICASE | REG_EXTENDED | REG_NOSUB; 687738032Speter p = ap; 6878168515Sgshapiro map_p = (struct regex_map *) xnalloc(sizeof(*map_p)); 687971345Sgshapiro map_p->regex_pattern_buf = (regex_t *)xnalloc(sizeof(regex_t)); 688038032Speter 688138032Speter for (;;) 688264562Sgshapiro { 688338032Speter while (isascii(*p) && isspace(*p)) 688438032Speter p++; 688538032Speter if (*p != '-') 688638032Speter break; 688738032Speter switch (*++p) 688838032Speter { 688938032Speter case 'n': /* not */ 689038032Speter map->map_mflags |= MF_REGEX_NOT; 689138032Speter break; 689238032Speter 689338032Speter case 'f': /* case sensitive */ 689438032Speter map->map_mflags |= MF_NOFOLDCASE; 689538032Speter pflags &= ~REG_ICASE; 689638032Speter break; 689738032Speter 689838032Speter case 'b': /* basic regular expressions */ 689938032Speter pflags &= ~REG_EXTENDED; 690038032Speter break; 690138032Speter 690238032Speter case 's': /* substring match () syntax */ 690338032Speter sub_param = ++p; 690438032Speter pflags &= ~REG_NOSUB; 690538032Speter break; 690638032Speter 690738032Speter case 'd': /* delimiter */ 690864562Sgshapiro map_p->regex_delim = ++p; 690938032Speter break; 691038032Speter 691138032Speter case 'a': /* map append */ 691238032Speter map->map_app = ++p; 691338032Speter break; 691438032Speter 691538032Speter case 'm': /* matchonly */ 691638032Speter map->map_mflags |= MF_MATCHONLY; 691738032Speter break; 691838032Speter 6919120256Sgshapiro case 'q': 6920120256Sgshapiro map->map_mflags |= MF_KEEPQUOTES; 6921120256Sgshapiro break; 6922120256Sgshapiro 692364562Sgshapiro case 'S': 692464562Sgshapiro map->map_spacesub = *++p; 692564562Sgshapiro break; 692664562Sgshapiro 692764562Sgshapiro case 'D': 692864562Sgshapiro map->map_mflags |= MF_DEFER; 692964562Sgshapiro break; 693064562Sgshapiro 693138032Speter } 693264562Sgshapiro while (*p != '\0' && !(isascii(*p) && isspace(*p))) 693364562Sgshapiro p++; 693464562Sgshapiro if (*p != '\0') 693564562Sgshapiro *p++ = '\0'; 693638032Speter } 693738032Speter if (tTd(38, 3)) 693890792Sgshapiro sm_dprintf("regex_map_init: compile '%s' 0x%x\n", p, pflags); 693938032Speter 694071345Sgshapiro if ((regerr = regcomp(map_p->regex_pattern_buf, p, pflags)) != 0) 694138032Speter { 694238032Speter /* Errorhandling */ 694338032Speter char errbuf[ERRBUF_SIZE]; 694438032Speter 694571345Sgshapiro (void) regerror(regerr, map_p->regex_pattern_buf, 6946168515Sgshapiro errbuf, sizeof(errbuf)); 694790792Sgshapiro syserr("pattern-compile-error: %s", errbuf); 694890792Sgshapiro sm_free(map_p->regex_pattern_buf); /* XXX */ 694990792Sgshapiro sm_free(map_p); /* XXX */ 695090792Sgshapiro return false; 695138032Speter } 695238032Speter 695338032Speter if (map->map_app != NULL) 695438032Speter map->map_app = newstr(map->map_app); 695564562Sgshapiro if (map_p->regex_delim != NULL) 695664562Sgshapiro map_p->regex_delim = newstr(map_p->regex_delim); 695738032Speter else 695864562Sgshapiro map_p->regex_delim = defdstr; 695938032Speter 696038032Speter if (!bitset(REG_NOSUB, pflags)) 696138032Speter { 696238032Speter /* substring matching */ 696338032Speter int substrings; 696464562Sgshapiro int *fields = (int *) xalloc(sizeof(int) * (MAX_MATCH + 1)); 696538032Speter 696671345Sgshapiro substrings = map_p->regex_pattern_buf->re_nsub + 1; 696738032Speter 696838032Speter if (tTd(38, 3)) 696990792Sgshapiro sm_dprintf("regex_map_init: nr of substrings %d\n", 697064562Sgshapiro substrings); 697138032Speter 697238032Speter if (substrings >= MAX_MATCH) 697338032Speter { 697490792Sgshapiro syserr("too many substrings, %d max", MAX_MATCH); 697590792Sgshapiro sm_free(map_p->regex_pattern_buf); /* XXX */ 697690792Sgshapiro sm_free(map_p); /* XXX */ 697790792Sgshapiro return false; 697838032Speter } 697938032Speter if (sub_param != NULL && sub_param[0] != '\0') 698038032Speter { 698138032Speter /* optional parameter -sfields */ 698238032Speter if (parse_fields(sub_param, fields, 698338032Speter MAX_MATCH + 1, substrings) == -1) 698490792Sgshapiro return false; 698538032Speter } 698638032Speter else 698738032Speter { 698838032Speter int i; 698938032Speter 699090792Sgshapiro /* set default fields */ 699138032Speter for (i = 0; i < substrings; i++) 699238032Speter fields[i] = i; 699338032Speter fields[i] = END_OF_FIELDS; 699438032Speter } 699538032Speter map_p->regex_subfields = fields; 699638032Speter if (tTd(38, 3)) 699738032Speter { 699838032Speter int *ip; 699938032Speter 700090792Sgshapiro sm_dprintf("regex_map_init: subfields"); 700138032Speter for (ip = fields; *ip != END_OF_FIELDS; ip++) 700290792Sgshapiro sm_dprintf(" %d", *ip); 700390792Sgshapiro sm_dprintf("\n"); 700438032Speter } 700538032Speter } 700690792Sgshapiro map->map_db1 = (ARBPTR_T) map_p; /* dirty hack */ 700790792Sgshapiro return true; 700838032Speter} 700938032Speter 701038032Speterstatic char * 701138032Speterregex_map_rewrite(map, s, slen, av) 701238032Speter MAP *map; 701338032Speter const char *s; 701438032Speter size_t slen; 701538032Speter char **av; 701638032Speter{ 701738032Speter if (bitset(MF_MATCHONLY, map->map_mflags)) 701838032Speter return map_rewrite(map, av[0], strlen(av[0]), NULL); 701938032Speter else 702077349Sgshapiro return map_rewrite(map, s, slen, av); 702138032Speter} 702238032Speter 702338032Speterchar * 702438032Speterregex_map_lookup(map, name, av, statp) 702538032Speter MAP *map; 702638032Speter char *name; 702738032Speter char **av; 702838032Speter int *statp; 702938032Speter{ 703038032Speter int reg_res; 703138032Speter struct regex_map *map_p; 703238032Speter regmatch_t pmatch[MAX_MATCH]; 703338032Speter 703438032Speter if (tTd(38, 20)) 703538032Speter { 703638032Speter char **cpp; 703738032Speter 703890792Sgshapiro sm_dprintf("regex_map_lookup: key '%s'\n", name); 703964562Sgshapiro for (cpp = av; cpp != NULL && *cpp != NULL; cpp++) 704090792Sgshapiro sm_dprintf("regex_map_lookup: arg '%s'\n", *cpp); 704138032Speter } 704238032Speter 704338032Speter map_p = (struct regex_map *)(map->map_db1); 704471345Sgshapiro reg_res = regexec(map_p->regex_pattern_buf, 704564562Sgshapiro name, MAX_MATCH, pmatch, 0); 704638032Speter 704738032Speter if (bitset(MF_REGEX_NOT, map->map_mflags)) 704838032Speter { 704938032Speter /* option -n */ 705038032Speter if (reg_res == REG_NOMATCH) 705190792Sgshapiro return regex_map_rewrite(map, "", (size_t) 0, av); 705238032Speter else 705338032Speter return NULL; 705438032Speter } 705538032Speter if (reg_res == REG_NOMATCH) 705638032Speter return NULL; 705738032Speter 705838032Speter if (map_p->regex_subfields != NULL) 705938032Speter { 706038032Speter /* option -s */ 706138032Speter static char retbuf[MAXNAME]; 706238032Speter int fields[MAX_MATCH + 1]; 706390792Sgshapiro bool first = true; 706438032Speter int anglecnt = 0, cmntcnt = 0, spacecnt = 0; 706590792Sgshapiro bool quotemode = false, bslashmode = false; 706638032Speter register char *dp, *sp; 706738032Speter char *endp, *ldp; 706838032Speter int *ip; 706938032Speter 707038032Speter dp = retbuf; 707138032Speter ldp = retbuf + sizeof(retbuf) - 1; 707238032Speter 707338032Speter if (av[1] != NULL) 707438032Speter { 707538032Speter if (parse_fields(av[1], fields, MAX_MATCH + 1, 707671345Sgshapiro (int) map_p->regex_pattern_buf->re_nsub + 1) == -1) 707738032Speter { 707838032Speter *statp = EX_CONFIG; 707938032Speter return NULL; 708038032Speter } 708138032Speter ip = fields; 708238032Speter } 708338032Speter else 708438032Speter ip = map_p->regex_subfields; 708538032Speter 708638032Speter for ( ; *ip != END_OF_FIELDS; ip++) 708738032Speter { 708838032Speter if (!first) 708938032Speter { 709064562Sgshapiro for (sp = map_p->regex_delim; *sp; sp++) 709138032Speter { 709238032Speter if (dp < ldp) 709338032Speter *dp++ = *sp; 709438032Speter } 709538032Speter } 709638032Speter else 709790792Sgshapiro first = false; 709838032Speter 709971345Sgshapiro if (*ip >= MAX_MATCH || 710071345Sgshapiro pmatch[*ip].rm_so < 0 || pmatch[*ip].rm_eo < 0) 710138032Speter continue; 710238032Speter 710338032Speter sp = name + pmatch[*ip].rm_so; 710438032Speter endp = name + pmatch[*ip].rm_eo; 710538032Speter for (; endp > sp; sp++) 710638032Speter { 710738032Speter if (dp < ldp) 710838032Speter { 710964562Sgshapiro if (bslashmode) 711064562Sgshapiro { 711138032Speter *dp++ = *sp; 711290792Sgshapiro bslashmode = false; 711338032Speter } 711464562Sgshapiro else if (quotemode && *sp != '"' && 711538032Speter *sp != '\\') 711638032Speter { 711738032Speter *dp++ = *sp; 711838032Speter } 711990792Sgshapiro else switch (*dp++ = *sp) 712038032Speter { 712190792Sgshapiro case '\\': 712290792Sgshapiro bslashmode = true; 712338032Speter break; 712438032Speter 712590792Sgshapiro case '(': 712638032Speter cmntcnt++; 712738032Speter break; 712838032Speter 712990792Sgshapiro case ')': 713038032Speter cmntcnt--; 713138032Speter break; 713238032Speter 713390792Sgshapiro case '<': 713438032Speter anglecnt++; 713538032Speter break; 713638032Speter 713790792Sgshapiro case '>': 713838032Speter anglecnt--; 713938032Speter break; 714038032Speter 714190792Sgshapiro case ' ': 714238032Speter spacecnt++; 714338032Speter break; 714438032Speter 714590792Sgshapiro case '"': 714638032Speter quotemode = !quotemode; 714738032Speter break; 714838032Speter } 714938032Speter } 715038032Speter } 715138032Speter } 715238032Speter if (anglecnt != 0 || cmntcnt != 0 || quotemode || 715338032Speter bslashmode || spacecnt != 0) 715438032Speter { 715564562Sgshapiro sm_syslog(LOG_WARNING, NOQID, 715664562Sgshapiro "Warning: regex may cause prescan() failure map=%s lookup=%s", 715764562Sgshapiro map->map_mname, name); 715838032Speter return NULL; 715938032Speter } 716038032Speter 716138032Speter *dp = '\0'; 716238032Speter 716338032Speter return regex_map_rewrite(map, retbuf, strlen(retbuf), av); 716438032Speter } 716538032Speter return regex_map_rewrite(map, "", (size_t)0, av); 716638032Speter} 716738032Speter#endif /* MAP_REGEX */ 716890792Sgshapiro/* 716964562Sgshapiro** NSD modules 717064562Sgshapiro*/ 717190792Sgshapiro#if MAP_NSD 717264562Sgshapiro 717364562Sgshapiro# include <ndbm.h> 717464562Sgshapiro# define _DATUM_DEFINED 717564562Sgshapiro# include <ns_api.h> 717664562Sgshapiro 717764562Sgshapirotypedef struct ns_map_list 717864562Sgshapiro{ 717990792Sgshapiro ns_map_t *map; /* XXX ns_ ? */ 718090792Sgshapiro char *mapname; 718190792Sgshapiro struct ns_map_list *next; 718264562Sgshapiro} ns_map_list_t; 718364562Sgshapiro 718464562Sgshapirostatic ns_map_t * 718564562Sgshapirons_map_t_find(mapname) 718664562Sgshapiro char *mapname; 718764562Sgshapiro{ 718864562Sgshapiro static ns_map_list_t *ns_maps = NULL; 718964562Sgshapiro ns_map_list_t *ns_map; 719064562Sgshapiro 719164562Sgshapiro /* walk the list of maps looking for the correctly named map */ 719264562Sgshapiro for (ns_map = ns_maps; ns_map != NULL; ns_map = ns_map->next) 719364562Sgshapiro { 719464562Sgshapiro if (strcmp(ns_map->mapname, mapname) == 0) 719564562Sgshapiro break; 719664562Sgshapiro } 719764562Sgshapiro 719864562Sgshapiro /* if we are looking at a NULL ns_map_list_t, then create a new one */ 719964562Sgshapiro if (ns_map == NULL) 720064562Sgshapiro { 7201168515Sgshapiro ns_map = (ns_map_list_t *) xalloc(sizeof(*ns_map)); 720264562Sgshapiro ns_map->mapname = newstr(mapname); 7203168515Sgshapiro ns_map->map = (ns_map_t *) xalloc(sizeof(*ns_map->map)); 7204168515Sgshapiro memset(ns_map->map, '\0', sizeof(*ns_map->map)); 720564562Sgshapiro ns_map->next = ns_maps; 720664562Sgshapiro ns_maps = ns_map; 720764562Sgshapiro } 720864562Sgshapiro return ns_map->map; 720964562Sgshapiro} 721064562Sgshapiro 721164562Sgshapirochar * 721264562Sgshapironsd_map_lookup(map, name, av, statp) 721364562Sgshapiro MAP *map; 721464562Sgshapiro char *name; 721564562Sgshapiro char **av; 721664562Sgshapiro int *statp; 721764562Sgshapiro{ 721871345Sgshapiro int buflen, r; 721964562Sgshapiro char *p; 722064562Sgshapiro ns_map_t *ns_map; 722164562Sgshapiro char keybuf[MAXNAME + 1]; 722264562Sgshapiro char buf[MAXLINE]; 722364562Sgshapiro 722464562Sgshapiro if (tTd(38, 20)) 722590792Sgshapiro sm_dprintf("nsd_map_lookup(%s, %s)\n", map->map_mname, name); 722664562Sgshapiro 722764562Sgshapiro buflen = strlen(name); 7228168515Sgshapiro if (buflen > sizeof(keybuf) - 1) 7229168515Sgshapiro buflen = sizeof(keybuf) - 1; /* XXX simply cut off? */ 723064562Sgshapiro memmove(keybuf, name, buflen); 723164562Sgshapiro keybuf[buflen] = '\0'; 723264562Sgshapiro if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 723364562Sgshapiro makelower(keybuf); 723464562Sgshapiro 723564562Sgshapiro ns_map = ns_map_t_find(map->map_file); 723664562Sgshapiro if (ns_map == NULL) 723764562Sgshapiro { 723864562Sgshapiro if (tTd(38, 20)) 723990792Sgshapiro sm_dprintf("nsd_map_t_find failed\n"); 724071345Sgshapiro *statp = EX_UNAVAILABLE; 724164562Sgshapiro return NULL; 724264562Sgshapiro } 724398121Sgshapiro r = ns_lookup(ns_map, NULL, map->map_file, keybuf, NULL, 7244168515Sgshapiro buf, sizeof(buf)); 724571345Sgshapiro if (r == NS_UNAVAIL || r == NS_TRYAGAIN) 724671345Sgshapiro { 724771345Sgshapiro *statp = EX_TEMPFAIL; 724864562Sgshapiro return NULL; 724971345Sgshapiro } 725077349Sgshapiro if (r == NS_BADREQ 725177349Sgshapiro# ifdef NS_NOPERM 725277349Sgshapiro || r == NS_NOPERM 725377349Sgshapiro# endif /* NS_NOPERM */ 725477349Sgshapiro ) 725571345Sgshapiro { 725671345Sgshapiro *statp = EX_CONFIG; 725771345Sgshapiro return NULL; 725871345Sgshapiro } 725971345Sgshapiro if (r != NS_SUCCESS) 726071345Sgshapiro { 726171345Sgshapiro *statp = EX_NOTFOUND; 726271345Sgshapiro return NULL; 726371345Sgshapiro } 726464562Sgshapiro 726571345Sgshapiro *statp = EX_OK; 726671345Sgshapiro 726764562Sgshapiro /* Null out trailing \n */ 726864562Sgshapiro if ((p = strchr(buf, '\n')) != NULL) 726964562Sgshapiro *p = '\0'; 727064562Sgshapiro 727164562Sgshapiro return map_rewrite(map, buf, strlen(buf), av); 727264562Sgshapiro} 727364562Sgshapiro#endif /* MAP_NSD */ 727464562Sgshapiro 727564562Sgshapirochar * 727664562Sgshapiroarith_map_lookup(map, name, av, statp) 727764562Sgshapiro MAP *map; 727864562Sgshapiro char *name; 727964562Sgshapiro char **av; 728064562Sgshapiro int *statp; 728164562Sgshapiro{ 728264562Sgshapiro long r; 728364562Sgshapiro long v[2]; 728490792Sgshapiro bool res = false; 728564562Sgshapiro bool boolres; 728664562Sgshapiro static char result[16]; 728764562Sgshapiro char **cpp; 728864562Sgshapiro 728964562Sgshapiro if (tTd(38, 2)) 729064562Sgshapiro { 729190792Sgshapiro sm_dprintf("arith_map_lookup: key '%s'\n", name); 729264562Sgshapiro for (cpp = av; cpp != NULL && *cpp != NULL; cpp++) 729390792Sgshapiro sm_dprintf("arith_map_lookup: arg '%s'\n", *cpp); 729464562Sgshapiro } 729564562Sgshapiro r = 0; 729690792Sgshapiro boolres = false; 729764562Sgshapiro cpp = av; 729864562Sgshapiro *statp = EX_OK; 729964562Sgshapiro 730064562Sgshapiro /* 730164562Sgshapiro ** read arguments for arith map 730264562Sgshapiro ** - no check is made whether they are really numbers 730364562Sgshapiro ** - just ignores args after the second 730464562Sgshapiro */ 730590792Sgshapiro 730664562Sgshapiro for (++cpp; cpp != NULL && *cpp != NULL && r < 2; cpp++) 730764562Sgshapiro v[r++] = strtol(*cpp, NULL, 0); 730864562Sgshapiro 730964562Sgshapiro /* operator and (at least) two operands given? */ 731064562Sgshapiro if (name != NULL && r == 2) 731164562Sgshapiro { 731290792Sgshapiro switch (*name) 731364562Sgshapiro { 731464562Sgshapiro case '|': 731564562Sgshapiro r = v[0] | v[1]; 731664562Sgshapiro break; 731764562Sgshapiro 731864562Sgshapiro case '&': 731964562Sgshapiro r = v[0] & v[1]; 732064562Sgshapiro break; 732164562Sgshapiro 732264562Sgshapiro case '%': 732364562Sgshapiro if (v[1] == 0) 732464562Sgshapiro return NULL; 732564562Sgshapiro r = v[0] % v[1]; 732664562Sgshapiro break; 732764562Sgshapiro case '+': 732864562Sgshapiro r = v[0] + v[1]; 732964562Sgshapiro break; 733064562Sgshapiro 733164562Sgshapiro case '-': 733264562Sgshapiro r = v[0] - v[1]; 733364562Sgshapiro break; 733464562Sgshapiro 733564562Sgshapiro case '*': 733664562Sgshapiro r = v[0] * v[1]; 733764562Sgshapiro break; 733864562Sgshapiro 733964562Sgshapiro case '/': 734064562Sgshapiro if (v[1] == 0) 734164562Sgshapiro return NULL; 734264562Sgshapiro r = v[0] / v[1]; 734364562Sgshapiro break; 734464562Sgshapiro 734564562Sgshapiro case 'l': 734664562Sgshapiro res = v[0] < v[1]; 734790792Sgshapiro boolres = true; 734864562Sgshapiro break; 734964562Sgshapiro 735064562Sgshapiro case '=': 735164562Sgshapiro res = v[0] == v[1]; 735290792Sgshapiro boolres = true; 735364562Sgshapiro break; 735464562Sgshapiro 7355168515Sgshapiro case 'r': 7356168515Sgshapiro r = v[1] - v[0] + 1; 7357168515Sgshapiro if (r <= 0) 7358168515Sgshapiro return NULL; 7359168515Sgshapiro r = get_random() % r + v[0]; 7360168515Sgshapiro break; 7361168515Sgshapiro 736264562Sgshapiro default: 736364562Sgshapiro /* XXX */ 736464562Sgshapiro *statp = EX_CONFIG; 736564562Sgshapiro if (LogLevel > 10) 736664562Sgshapiro sm_syslog(LOG_WARNING, NOQID, 736764562Sgshapiro "arith_map: unknown operator %c", 7368203004Sgshapiro (isascii(*name) && isprint(*name)) ? 7369203004Sgshapiro *name : '?'); 737064562Sgshapiro return NULL; 737164562Sgshapiro } 737264562Sgshapiro if (boolres) 7373168515Sgshapiro (void) sm_snprintf(result, sizeof(result), 737490792Sgshapiro res ? "TRUE" : "FALSE"); 737564562Sgshapiro else 7376168515Sgshapiro (void) sm_snprintf(result, sizeof(result), "%ld", r); 737764562Sgshapiro return result; 737864562Sgshapiro } 737964562Sgshapiro *statp = EX_CONFIG; 738064562Sgshapiro return NULL; 738164562Sgshapiro} 7382132943Sgshapiro 7383261363Sgshapirochar * 7384261363Sgshapiroarpa_map_lookup(map, name, av, statp) 7385261363Sgshapiro MAP *map; 7386261363Sgshapiro char *name; 7387261363Sgshapiro char **av; 7388261363Sgshapiro int *statp; 7389261363Sgshapiro{ 7390261363Sgshapiro int r; 7391261363Sgshapiro char *rval; 7392261363Sgshapiro char result[128]; /* IPv6: 64 + 10 + 1 would be enough */ 7393261363Sgshapiro 7394261363Sgshapiro if (tTd(38, 2)) 7395261363Sgshapiro sm_dprintf("arpa_map_lookup: key '%s'\n", name); 7396261363Sgshapiro *statp = EX_DATAERR; 7397261363Sgshapiro r = 1; 7398261363Sgshapiro memset(result, '\0', sizeof(result)); 7399261363Sgshapiro rval = NULL; 7400261363Sgshapiro 7401261363Sgshapiro# if NETINET6 7402261363Sgshapiro if (sm_strncasecmp(name, "IPv6:", 5) == 0) 7403261363Sgshapiro { 7404261363Sgshapiro struct in6_addr in6_addr; 7405261363Sgshapiro 7406261363Sgshapiro r = anynet_pton(AF_INET6, name, &in6_addr); 7407261363Sgshapiro if (r == 1) 7408261363Sgshapiro { 7409261363Sgshapiro static char hex_digits[] = 7410261363Sgshapiro { '0', '1', '2', '3', '4', '5', '6', '7', '8', 7411261363Sgshapiro '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 7412261363Sgshapiro 7413261363Sgshapiro unsigned char *src; 7414261363Sgshapiro char *dst; 7415261363Sgshapiro int i; 7416261363Sgshapiro 7417261363Sgshapiro src = (unsigned char *) &in6_addr; 7418261363Sgshapiro dst = result; 7419261363Sgshapiro for (i = 15; i >= 0; i--) { 7420261363Sgshapiro *dst++ = hex_digits[src[i] & 0x0f]; 7421261363Sgshapiro *dst++ = '.'; 7422261363Sgshapiro *dst++ = hex_digits[(src[i] >> 4) & 0x0f]; 7423261363Sgshapiro if (i > 0) 7424261363Sgshapiro *dst++ = '.'; 7425261363Sgshapiro } 7426261363Sgshapiro *statp = EX_OK; 7427261363Sgshapiro } 7428261363Sgshapiro } 7429261363Sgshapiro else 7430261363Sgshapiro# endif /* NETINET6 */ 7431261363Sgshapiro# if NETINET 7432261363Sgshapiro { 7433261363Sgshapiro struct in_addr in_addr; 7434261363Sgshapiro 7435285303Sgshapiro r = inet_pton(AF_INET, name, &in_addr); 7436261363Sgshapiro if (r == 1) 7437261363Sgshapiro { 7438261363Sgshapiro unsigned char *src; 7439261363Sgshapiro 7440261363Sgshapiro src = (unsigned char *) &in_addr; 7441261363Sgshapiro (void) snprintf(result, sizeof(result), 7442261363Sgshapiro "%u.%u.%u.%u", 7443261363Sgshapiro src[3], src[2], src[1], src[0]); 7444261363Sgshapiro *statp = EX_OK; 7445261363Sgshapiro } 7446261363Sgshapiro } 7447261363Sgshapiro# endif /* NETINET */ 7448261363Sgshapiro if (r < 0) 7449261363Sgshapiro *statp = EX_UNAVAILABLE; 7450261363Sgshapiro if (tTd(38, 2)) 7451261363Sgshapiro sm_dprintf("arpa_map_lookup: r=%d, result='%s'\n", r, result); 7452261363Sgshapiro if (*statp == EX_OK) 7453261363Sgshapiro { 7454261363Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 7455261363Sgshapiro rval = map_rewrite(map, name, strlen(name), NULL); 7456261363Sgshapiro else 7457261363Sgshapiro rval = map_rewrite(map, result, strlen(result), av); 7458261363Sgshapiro } 7459261363Sgshapiro return rval; 7460261363Sgshapiro} 7461261363Sgshapiro 7462132943Sgshapiro#if SOCKETMAP 7463132943Sgshapiro 7464132943Sgshapiro# if NETINET || NETINET6 7465132943Sgshapiro# include <arpa/inet.h> 7466132943Sgshapiro# endif /* NETINET || NETINET6 */ 7467132943Sgshapiro 7468132943Sgshapiro# define socket_map_next map_stack[0] 7469132943Sgshapiro 7470132943Sgshapiro/* 7471132943Sgshapiro** SOCKET_MAP_OPEN -- open socket table 7472132943Sgshapiro*/ 7473132943Sgshapiro 7474132943Sgshapirobool 7475132943Sgshapirosocket_map_open(map, mode) 7476132943Sgshapiro MAP *map; 7477132943Sgshapiro int mode; 7478132943Sgshapiro{ 7479132943Sgshapiro STAB *s; 7480132943Sgshapiro int sock = 0; 7481285303Sgshapiro int tmo; 7482132943Sgshapiro SOCKADDR_LEN_T addrlen = 0; 7483132943Sgshapiro int addrno = 0; 7484132943Sgshapiro int save_errno; 7485132943Sgshapiro char *p; 7486132943Sgshapiro char *colon; 7487132943Sgshapiro char *at; 7488132943Sgshapiro struct hostent *hp = NULL; 7489132943Sgshapiro SOCKADDR addr; 7490132943Sgshapiro 7491132943Sgshapiro if (tTd(38, 2)) 7492132943Sgshapiro sm_dprintf("socket_map_open(%s, %s, %d)\n", 7493132943Sgshapiro map->map_mname, map->map_file, mode); 7494132943Sgshapiro 7495132943Sgshapiro mode &= O_ACCMODE; 7496132943Sgshapiro 7497132943Sgshapiro /* sendmail doesn't have the ability to write to SOCKET (yet) */ 7498132943Sgshapiro if (mode != O_RDONLY) 7499132943Sgshapiro { 7500132943Sgshapiro /* issue a pseudo-error message */ 7501132943Sgshapiro errno = SM_EMAPCANTWRITE; 7502132943Sgshapiro return false; 7503132943Sgshapiro } 7504132943Sgshapiro 7505132943Sgshapiro if (*map->map_file == '\0') 7506132943Sgshapiro { 7507132943Sgshapiro syserr("socket map \"%s\": empty or missing socket information", 7508132943Sgshapiro map->map_mname); 7509132943Sgshapiro return false; 7510132943Sgshapiro } 7511132943Sgshapiro 7512132943Sgshapiro s = socket_map_findconn(map->map_file); 7513132943Sgshapiro if (s->s_socketmap != NULL) 7514132943Sgshapiro { 7515132943Sgshapiro /* Copy open connection */ 7516132943Sgshapiro map->map_db1 = s->s_socketmap->map_db1; 7517132943Sgshapiro 7518132943Sgshapiro /* Add this map as head of linked list */ 7519132943Sgshapiro map->socket_map_next = s->s_socketmap; 7520132943Sgshapiro s->s_socketmap = map; 7521132943Sgshapiro 7522132943Sgshapiro if (tTd(38, 2)) 7523132943Sgshapiro sm_dprintf("using cached connection\n"); 7524132943Sgshapiro return true; 7525132943Sgshapiro } 7526132943Sgshapiro 7527132943Sgshapiro if (tTd(38, 2)) 7528132943Sgshapiro sm_dprintf("opening new connection\n"); 7529132943Sgshapiro 7530132943Sgshapiro /* following code is ripped from milter.c */ 7531132943Sgshapiro /* XXX It should be put in a library... */ 7532132943Sgshapiro 7533132943Sgshapiro /* protocol:filename or protocol:port@host */ 7534168515Sgshapiro memset(&addr, '\0', sizeof(addr)); 7535132943Sgshapiro p = map->map_file; 7536132943Sgshapiro colon = strchr(p, ':'); 7537132943Sgshapiro if (colon != NULL) 7538132943Sgshapiro { 7539132943Sgshapiro *colon = '\0'; 7540132943Sgshapiro 7541132943Sgshapiro if (*p == '\0') 7542132943Sgshapiro { 7543132943Sgshapiro# if NETUNIX 7544132943Sgshapiro /* default to AF_UNIX */ 7545132943Sgshapiro addr.sa.sa_family = AF_UNIX; 7546132943Sgshapiro# else /* NETUNIX */ 7547132943Sgshapiro# if NETINET 7548132943Sgshapiro /* default to AF_INET */ 7549132943Sgshapiro addr.sa.sa_family = AF_INET; 7550132943Sgshapiro# else /* NETINET */ 7551132943Sgshapiro# if NETINET6 7552132943Sgshapiro /* default to AF_INET6 */ 7553132943Sgshapiro addr.sa.sa_family = AF_INET6; 7554132943Sgshapiro# else /* NETINET6 */ 7555132943Sgshapiro /* no protocols available */ 7556132943Sgshapiro syserr("socket map \"%s\": no valid socket protocols available", 7557132943Sgshapiro map->map_mname); 7558132943Sgshapiro return false; 7559132943Sgshapiro# endif /* NETINET6 */ 7560132943Sgshapiro# endif /* NETINET */ 7561132943Sgshapiro# endif /* NETUNIX */ 7562132943Sgshapiro } 7563132943Sgshapiro# if NETUNIX 7564132943Sgshapiro else if (sm_strcasecmp(p, "unix") == 0 || 7565132943Sgshapiro sm_strcasecmp(p, "local") == 0) 7566132943Sgshapiro addr.sa.sa_family = AF_UNIX; 7567132943Sgshapiro# endif /* NETUNIX */ 7568132943Sgshapiro# if NETINET 7569132943Sgshapiro else if (sm_strcasecmp(p, "inet") == 0) 7570132943Sgshapiro addr.sa.sa_family = AF_INET; 7571132943Sgshapiro# endif /* NETINET */ 7572132943Sgshapiro# if NETINET6 7573132943Sgshapiro else if (sm_strcasecmp(p, "inet6") == 0) 7574132943Sgshapiro addr.sa.sa_family = AF_INET6; 7575132943Sgshapiro# endif /* NETINET6 */ 7576132943Sgshapiro else 7577132943Sgshapiro { 7578132943Sgshapiro# ifdef EPROTONOSUPPORT 7579132943Sgshapiro errno = EPROTONOSUPPORT; 7580132943Sgshapiro# else /* EPROTONOSUPPORT */ 7581132943Sgshapiro errno = EINVAL; 7582132943Sgshapiro# endif /* EPROTONOSUPPORT */ 7583132943Sgshapiro syserr("socket map \"%s\": unknown socket type %s", 7584132943Sgshapiro map->map_mname, p); 7585132943Sgshapiro return false; 7586132943Sgshapiro } 7587132943Sgshapiro *colon++ = ':'; 7588132943Sgshapiro } 7589132943Sgshapiro else 7590132943Sgshapiro { 7591132943Sgshapiro colon = p; 7592132943Sgshapiro#if NETUNIX 7593132943Sgshapiro /* default to AF_UNIX */ 7594132943Sgshapiro addr.sa.sa_family = AF_UNIX; 7595132943Sgshapiro#else /* NETUNIX */ 7596132943Sgshapiro# if NETINET 7597132943Sgshapiro /* default to AF_INET */ 7598132943Sgshapiro addr.sa.sa_family = AF_INET; 7599132943Sgshapiro# else /* NETINET */ 7600132943Sgshapiro# if NETINET6 7601132943Sgshapiro /* default to AF_INET6 */ 7602132943Sgshapiro addr.sa.sa_family = AF_INET6; 7603132943Sgshapiro# else /* NETINET6 */ 7604132943Sgshapiro syserr("socket map \"%s\": unknown socket type %s", 7605132943Sgshapiro map->map_mname, p); 7606132943Sgshapiro return false; 7607132943Sgshapiro# endif /* NETINET6 */ 7608132943Sgshapiro# endif /* NETINET */ 7609132943Sgshapiro#endif /* NETUNIX */ 7610132943Sgshapiro } 7611132943Sgshapiro 7612132943Sgshapiro# if NETUNIX 7613132943Sgshapiro if (addr.sa.sa_family == AF_UNIX) 7614132943Sgshapiro { 7615132943Sgshapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK; 7616132943Sgshapiro 7617132943Sgshapiro at = colon; 7618168515Sgshapiro if (strlen(colon) >= sizeof(addr.sunix.sun_path)) 7619132943Sgshapiro { 7620132943Sgshapiro syserr("socket map \"%s\": local socket name %s too long", 7621132943Sgshapiro map->map_mname, colon); 7622132943Sgshapiro return false; 7623132943Sgshapiro } 7624132943Sgshapiro errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, 7625132943Sgshapiro S_IRUSR|S_IWUSR, NULL); 7626132943Sgshapiro 7627132943Sgshapiro if (errno != 0) 7628132943Sgshapiro { 7629132943Sgshapiro /* if not safe, don't create */ 7630132943Sgshapiro syserr("socket map \"%s\": local socket name %s unsafe", 7631132943Sgshapiro map->map_mname, colon); 7632132943Sgshapiro return false; 7633132943Sgshapiro } 7634132943Sgshapiro 7635132943Sgshapiro (void) sm_strlcpy(addr.sunix.sun_path, colon, 7636168515Sgshapiro sizeof(addr.sunix.sun_path)); 7637168515Sgshapiro addrlen = sizeof(struct sockaddr_un); 7638132943Sgshapiro } 7639132943Sgshapiro else 7640132943Sgshapiro# endif /* NETUNIX */ 7641132943Sgshapiro# if NETINET || NETINET6 7642132943Sgshapiro if (false 7643132943Sgshapiro# if NETINET 7644132943Sgshapiro || addr.sa.sa_family == AF_INET 7645132943Sgshapiro# endif /* NETINET */ 7646132943Sgshapiro# if NETINET6 7647132943Sgshapiro || addr.sa.sa_family == AF_INET6 7648132943Sgshapiro# endif /* NETINET6 */ 7649132943Sgshapiro ) 7650132943Sgshapiro { 7651132943Sgshapiro unsigned short port; 7652132943Sgshapiro 7653132943Sgshapiro /* Parse port@host */ 7654132943Sgshapiro at = strchr(colon, '@'); 7655132943Sgshapiro if (at == NULL) 7656132943Sgshapiro { 7657132943Sgshapiro syserr("socket map \"%s\": bad address %s (expected port@host)", 7658132943Sgshapiro map->map_mname, colon); 7659132943Sgshapiro return false; 7660132943Sgshapiro } 7661132943Sgshapiro *at = '\0'; 7662132943Sgshapiro if (isascii(*colon) && isdigit(*colon)) 7663132943Sgshapiro port = htons((unsigned short) atoi(colon)); 7664132943Sgshapiro else 7665132943Sgshapiro { 7666132943Sgshapiro# ifdef NO_GETSERVBYNAME 7667132943Sgshapiro syserr("socket map \"%s\": invalid port number %s", 7668132943Sgshapiro map->map_mname, colon); 7669132943Sgshapiro return false; 7670132943Sgshapiro# else /* NO_GETSERVBYNAME */ 7671132943Sgshapiro register struct servent *sp; 7672132943Sgshapiro 7673132943Sgshapiro sp = getservbyname(colon, "tcp"); 7674132943Sgshapiro if (sp == NULL) 7675132943Sgshapiro { 7676132943Sgshapiro syserr("socket map \"%s\": unknown port name %s", 7677132943Sgshapiro map->map_mname, colon); 7678132943Sgshapiro return false; 7679132943Sgshapiro } 7680132943Sgshapiro port = sp->s_port; 7681132943Sgshapiro# endif /* NO_GETSERVBYNAME */ 7682132943Sgshapiro } 7683132943Sgshapiro *at++ = '@'; 7684132943Sgshapiro if (*at == '[') 7685132943Sgshapiro { 7686132943Sgshapiro char *end; 7687132943Sgshapiro 7688132943Sgshapiro end = strchr(at, ']'); 7689132943Sgshapiro if (end != NULL) 7690132943Sgshapiro { 7691132943Sgshapiro bool found = false; 7692132943Sgshapiro# if NETINET 7693132943Sgshapiro unsigned long hid = INADDR_NONE; 7694132943Sgshapiro# endif /* NETINET */ 7695132943Sgshapiro# if NETINET6 7696132943Sgshapiro struct sockaddr_in6 hid6; 7697132943Sgshapiro# endif /* NETINET6 */ 7698132943Sgshapiro 7699132943Sgshapiro *end = '\0'; 7700132943Sgshapiro# if NETINET 7701132943Sgshapiro if (addr.sa.sa_family == AF_INET && 7702132943Sgshapiro (hid = inet_addr(&at[1])) != INADDR_NONE) 7703132943Sgshapiro { 7704132943Sgshapiro addr.sin.sin_addr.s_addr = hid; 7705132943Sgshapiro addr.sin.sin_port = port; 7706132943Sgshapiro found = true; 7707132943Sgshapiro } 7708132943Sgshapiro# endif /* NETINET */ 7709132943Sgshapiro# if NETINET6 7710168515Sgshapiro (void) memset(&hid6, '\0', sizeof(hid6)); 7711132943Sgshapiro if (addr.sa.sa_family == AF_INET6 && 7712132943Sgshapiro anynet_pton(AF_INET6, &at[1], 7713132943Sgshapiro &hid6.sin6_addr) == 1) 7714132943Sgshapiro { 7715132943Sgshapiro addr.sin6.sin6_addr = hid6.sin6_addr; 7716132943Sgshapiro addr.sin6.sin6_port = port; 7717132943Sgshapiro found = true; 7718132943Sgshapiro } 7719132943Sgshapiro# endif /* NETINET6 */ 7720132943Sgshapiro *end = ']'; 7721132943Sgshapiro if (!found) 7722132943Sgshapiro { 7723132943Sgshapiro syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"", 7724132943Sgshapiro map->map_mname, at); 7725132943Sgshapiro return false; 7726132943Sgshapiro } 7727132943Sgshapiro } 7728132943Sgshapiro else 7729132943Sgshapiro { 7730132943Sgshapiro syserr("socket map \"%s\": Invalid numeric domain spec \"%s\"", 7731132943Sgshapiro map->map_mname, at); 7732132943Sgshapiro return false; 7733132943Sgshapiro } 7734132943Sgshapiro } 7735132943Sgshapiro else 7736132943Sgshapiro { 7737132943Sgshapiro hp = sm_gethostbyname(at, addr.sa.sa_family); 7738132943Sgshapiro if (hp == NULL) 7739132943Sgshapiro { 7740132943Sgshapiro syserr("socket map \"%s\": Unknown host name %s", 7741132943Sgshapiro map->map_mname, at); 7742132943Sgshapiro return false; 7743132943Sgshapiro } 7744132943Sgshapiro addr.sa.sa_family = hp->h_addrtype; 7745132943Sgshapiro switch (hp->h_addrtype) 7746132943Sgshapiro { 7747132943Sgshapiro# if NETINET 7748132943Sgshapiro case AF_INET: 7749132943Sgshapiro memmove(&addr.sin.sin_addr, 7750132943Sgshapiro hp->h_addr, INADDRSZ); 7751132943Sgshapiro addr.sin.sin_port = port; 7752168515Sgshapiro addrlen = sizeof(struct sockaddr_in); 7753132943Sgshapiro addrno = 1; 7754132943Sgshapiro break; 7755132943Sgshapiro# endif /* NETINET */ 7756132943Sgshapiro 7757132943Sgshapiro# if NETINET6 7758132943Sgshapiro case AF_INET6: 7759132943Sgshapiro memmove(&addr.sin6.sin6_addr, 7760132943Sgshapiro hp->h_addr, IN6ADDRSZ); 7761132943Sgshapiro addr.sin6.sin6_port = port; 7762168515Sgshapiro addrlen = sizeof(struct sockaddr_in6); 7763132943Sgshapiro addrno = 1; 7764132943Sgshapiro break; 7765132943Sgshapiro# endif /* NETINET6 */ 7766132943Sgshapiro 7767132943Sgshapiro default: 7768132943Sgshapiro syserr("socket map \"%s\": Unknown protocol for %s (%d)", 7769132943Sgshapiro map->map_mname, at, hp->h_addrtype); 7770132943Sgshapiro# if NETINET6 7771132943Sgshapiro freehostent(hp); 7772132943Sgshapiro# endif /* NETINET6 */ 7773132943Sgshapiro return false; 7774132943Sgshapiro } 7775132943Sgshapiro } 7776132943Sgshapiro } 7777132943Sgshapiro else 7778132943Sgshapiro# endif /* NETINET || NETINET6 */ 7779132943Sgshapiro { 7780132943Sgshapiro syserr("socket map \"%s\": unknown socket protocol", 7781132943Sgshapiro map->map_mname); 7782132943Sgshapiro return false; 7783132943Sgshapiro } 7784132943Sgshapiro 7785132943Sgshapiro /* nope, actually connecting */ 7786132943Sgshapiro for (;;) 7787132943Sgshapiro { 7788132943Sgshapiro sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); 7789132943Sgshapiro if (sock < 0) 7790132943Sgshapiro { 7791132943Sgshapiro save_errno = errno; 7792132943Sgshapiro if (tTd(38, 5)) 7793132943Sgshapiro sm_dprintf("socket map \"%s\": error creating socket: %s\n", 7794132943Sgshapiro map->map_mname, 7795132943Sgshapiro sm_errstring(save_errno)); 7796132943Sgshapiro# if NETINET6 7797132943Sgshapiro if (hp != NULL) 7798132943Sgshapiro freehostent(hp); 7799132943Sgshapiro# endif /* NETINET6 */ 7800132943Sgshapiro return false; 7801132943Sgshapiro } 7802132943Sgshapiro 7803132943Sgshapiro if (connect(sock, (struct sockaddr *) &addr, addrlen) >= 0) 7804132943Sgshapiro break; 7805132943Sgshapiro 7806132943Sgshapiro /* couldn't connect.... try next address */ 7807132943Sgshapiro save_errno = errno; 7808132943Sgshapiro p = CurHostName; 7809132943Sgshapiro CurHostName = at; 7810132943Sgshapiro if (tTd(38, 5)) 7811132943Sgshapiro sm_dprintf("socket_open (%s): open %s failed: %s\n", 7812132943Sgshapiro map->map_mname, at, sm_errstring(save_errno)); 7813132943Sgshapiro CurHostName = p; 7814132943Sgshapiro (void) close(sock); 7815132943Sgshapiro 7816132943Sgshapiro /* try next address */ 7817132943Sgshapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL) 7818132943Sgshapiro { 7819132943Sgshapiro switch (addr.sa.sa_family) 7820132943Sgshapiro { 7821132943Sgshapiro# if NETINET 7822132943Sgshapiro case AF_INET: 7823132943Sgshapiro memmove(&addr.sin.sin_addr, 7824132943Sgshapiro hp->h_addr_list[addrno++], 7825132943Sgshapiro INADDRSZ); 7826132943Sgshapiro break; 7827132943Sgshapiro# endif /* NETINET */ 7828132943Sgshapiro 7829132943Sgshapiro# if NETINET6 7830132943Sgshapiro case AF_INET6: 7831132943Sgshapiro memmove(&addr.sin6.sin6_addr, 7832132943Sgshapiro hp->h_addr_list[addrno++], 7833132943Sgshapiro IN6ADDRSZ); 7834132943Sgshapiro break; 7835132943Sgshapiro# endif /* NETINET6 */ 7836132943Sgshapiro 7837132943Sgshapiro default: 7838132943Sgshapiro if (tTd(38, 5)) 7839132943Sgshapiro sm_dprintf("socket map \"%s\": Unknown protocol for %s (%d)\n", 7840132943Sgshapiro map->map_mname, at, 7841132943Sgshapiro hp->h_addrtype); 7842132943Sgshapiro# if NETINET6 7843132943Sgshapiro freehostent(hp); 7844132943Sgshapiro# endif /* NETINET6 */ 7845132943Sgshapiro return false; 7846132943Sgshapiro } 7847132943Sgshapiro continue; 7848132943Sgshapiro } 7849132943Sgshapiro p = CurHostName; 7850132943Sgshapiro CurHostName = at; 7851132943Sgshapiro if (tTd(38, 5)) 7852132943Sgshapiro sm_dprintf("socket map \"%s\": error connecting to socket map: %s\n", 7853132943Sgshapiro map->map_mname, sm_errstring(save_errno)); 7854132943Sgshapiro CurHostName = p; 7855132943Sgshapiro# if NETINET6 7856132943Sgshapiro if (hp != NULL) 7857132943Sgshapiro freehostent(hp); 7858132943Sgshapiro# endif /* NETINET6 */ 7859132943Sgshapiro return false; 7860132943Sgshapiro } 7861132943Sgshapiro# if NETINET6 7862132943Sgshapiro if (hp != NULL) 7863132943Sgshapiro { 7864132943Sgshapiro freehostent(hp); 7865132943Sgshapiro hp = NULL; 7866132943Sgshapiro } 7867132943Sgshapiro# endif /* NETINET6 */ 7868132943Sgshapiro if ((map->map_db1 = (ARBPTR_T) sm_io_open(SmFtStdiofd, 7869132943Sgshapiro SM_TIME_DEFAULT, 7870132943Sgshapiro (void *) &sock, 7871132943Sgshapiro SM_IO_RDWR, 7872132943Sgshapiro NULL)) == NULL) 7873132943Sgshapiro { 7874132943Sgshapiro close(sock); 7875132943Sgshapiro if (tTd(38, 2)) 7876132943Sgshapiro sm_dprintf("socket_open (%s): failed to create stream: %s\n", 7877132943Sgshapiro map->map_mname, sm_errstring(errno)); 7878132943Sgshapiro return false; 7879132943Sgshapiro } 7880132943Sgshapiro 7881285303Sgshapiro tmo = map->map_timeout; 7882285303Sgshapiro if (tmo == 0) 7883285303Sgshapiro tmo = 30000; /* default: 30s */ 7884285303Sgshapiro else 7885285303Sgshapiro tmo *= 1000; /* s -> ms */ 7886285303Sgshapiro sm_io_setinfo(map->map_db1, SM_IO_WHAT_TIMEOUT, &tmo); 7887285303Sgshapiro 7888132943Sgshapiro /* Save connection for reuse */ 7889132943Sgshapiro s->s_socketmap = map; 7890132943Sgshapiro return true; 7891132943Sgshapiro} 7892132943Sgshapiro 7893132943Sgshapiro/* 7894132943Sgshapiro** SOCKET_MAP_FINDCONN -- find a SOCKET connection to the server 7895132943Sgshapiro** 7896132943Sgshapiro** Cache SOCKET connections based on the connection specifier 7897132943Sgshapiro** and PID so we don't have multiple connections open to 7898132943Sgshapiro** the same server for different maps. Need a separate connection 7899132943Sgshapiro** per PID since a parent process may close the map before the 7900132943Sgshapiro** child is done with it. 7901132943Sgshapiro** 7902132943Sgshapiro** Parameters: 7903132943Sgshapiro** conn -- SOCKET map connection specifier 7904132943Sgshapiro** 7905132943Sgshapiro** Returns: 7906132943Sgshapiro** Symbol table entry for the SOCKET connection. 7907132943Sgshapiro*/ 7908132943Sgshapiro 7909132943Sgshapirostatic STAB * 7910132943Sgshapirosocket_map_findconn(conn) 7911132943Sgshapiro const char *conn; 7912132943Sgshapiro{ 7913132943Sgshapiro char *nbuf; 7914132943Sgshapiro STAB *SM_NONVOLATILE s = NULL; 7915132943Sgshapiro 7916132943Sgshapiro nbuf = sm_stringf_x("%s%c%d", conn, CONDELSE, (int) CurrentPid); 7917132943Sgshapiro SM_TRY 7918132943Sgshapiro s = stab(nbuf, ST_SOCKETMAP, ST_ENTER); 7919132943Sgshapiro SM_FINALLY 7920132943Sgshapiro sm_free(nbuf); 7921132943Sgshapiro SM_END_TRY 7922132943Sgshapiro return s; 7923132943Sgshapiro} 7924132943Sgshapiro 7925132943Sgshapiro/* 7926132943Sgshapiro** SOCKET_MAP_CLOSE -- close the socket 7927132943Sgshapiro*/ 7928132943Sgshapiro 7929132943Sgshapirovoid 7930132943Sgshapirosocket_map_close(map) 7931132943Sgshapiro MAP *map; 7932132943Sgshapiro{ 7933132943Sgshapiro STAB *s; 7934132943Sgshapiro MAP *smap; 7935132943Sgshapiro 7936132943Sgshapiro if (tTd(38, 20)) 7937132943Sgshapiro sm_dprintf("socket_map_close(%s), pid=%ld\n", map->map_file, 7938132943Sgshapiro (long) CurrentPid); 7939132943Sgshapiro 7940132943Sgshapiro /* Check if already closed */ 7941132943Sgshapiro if (map->map_db1 == NULL) 7942132943Sgshapiro { 7943132943Sgshapiro if (tTd(38, 20)) 7944132943Sgshapiro sm_dprintf("socket_map_close(%s) already closed\n", 7945132943Sgshapiro map->map_file); 7946132943Sgshapiro return; 7947132943Sgshapiro } 7948132943Sgshapiro sm_io_close((SM_FILE_T *)map->map_db1, SM_TIME_DEFAULT); 7949132943Sgshapiro 7950132943Sgshapiro /* Mark all the maps that share the connection as closed */ 7951132943Sgshapiro s = socket_map_findconn(map->map_file); 7952132943Sgshapiro smap = s->s_socketmap; 7953132943Sgshapiro while (smap != NULL) 7954132943Sgshapiro { 7955132943Sgshapiro MAP *next; 7956132943Sgshapiro 7957132943Sgshapiro if (tTd(38, 2) && smap != map) 7958132943Sgshapiro sm_dprintf("socket_map_close(%s): closed %s (shared SOCKET connection)\n", 7959132943Sgshapiro map->map_mname, smap->map_mname); 7960132943Sgshapiro 7961132943Sgshapiro smap->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 7962132943Sgshapiro smap->map_db1 = NULL; 7963132943Sgshapiro next = smap->socket_map_next; 7964132943Sgshapiro smap->socket_map_next = NULL; 7965132943Sgshapiro smap = next; 7966132943Sgshapiro } 7967132943Sgshapiro s->s_socketmap = NULL; 7968132943Sgshapiro} 7969132943Sgshapiro 7970132943Sgshapiro/* 7971132943Sgshapiro** SOCKET_MAP_LOOKUP -- look up a datum in a SOCKET table 7972132943Sgshapiro*/ 7973132943Sgshapiro 7974132943Sgshapirochar * 7975132943Sgshapirosocket_map_lookup(map, name, av, statp) 7976132943Sgshapiro MAP *map; 7977132943Sgshapiro char *name; 7978132943Sgshapiro char **av; 7979132943Sgshapiro int *statp; 7980132943Sgshapiro{ 7981132943Sgshapiro unsigned int nettolen, replylen, recvlen; 7982147078Sgshapiro char *replybuf, *rval, *value, *status, *key; 7983132943Sgshapiro SM_FILE_T *f; 7984147078Sgshapiro char keybuf[MAXNAME + 1]; 7985132943Sgshapiro 7986132943Sgshapiro replybuf = NULL; 7987132943Sgshapiro rval = NULL; 7988132943Sgshapiro f = (SM_FILE_T *)map->map_db1; 7989132943Sgshapiro if (tTd(38, 20)) 7990132943Sgshapiro sm_dprintf("socket_map_lookup(%s, %s) %s\n", 7991132943Sgshapiro map->map_mname, name, map->map_file); 7992132943Sgshapiro 7993147078Sgshapiro if (!bitset(MF_NOFOLDCASE, map->map_mflags)) 7994147078Sgshapiro { 7995147078Sgshapiro nettolen = strlen(name); 7996168515Sgshapiro if (nettolen > sizeof(keybuf) - 1) 7997168515Sgshapiro nettolen = sizeof(keybuf) - 1; 7998147078Sgshapiro memmove(keybuf, name, nettolen); 7999147078Sgshapiro keybuf[nettolen] = '\0'; 8000147078Sgshapiro makelower(keybuf); 8001147078Sgshapiro key = keybuf; 8002147078Sgshapiro } 8003147078Sgshapiro else 8004147078Sgshapiro key = name; 8005147078Sgshapiro 8006147078Sgshapiro nettolen = strlen(map->map_mname) + 1 + strlen(key); 8007132943Sgshapiro SM_ASSERT(nettolen > strlen(map->map_mname)); 8008147078Sgshapiro SM_ASSERT(nettolen > strlen(key)); 8009132943Sgshapiro if ((sm_io_fprintf(f, SM_TIME_DEFAULT, "%u:%s %s,", 8010147078Sgshapiro nettolen, map->map_mname, key) == SM_IO_EOF) || 8011132943Sgshapiro (sm_io_flush(f, SM_TIME_DEFAULT) != 0) || 8012132943Sgshapiro (sm_io_error(f))) 8013132943Sgshapiro { 8014132943Sgshapiro syserr("451 4.3.0 socket_map_lookup(%s): failed to send lookup request", 8015132943Sgshapiro map->map_mname); 8016132943Sgshapiro *statp = EX_TEMPFAIL; 8017132943Sgshapiro goto errcl; 8018132943Sgshapiro } 8019132943Sgshapiro 8020132943Sgshapiro if (sm_io_fscanf(f, SM_TIME_DEFAULT, "%9u", &replylen) != 1) 8021132943Sgshapiro { 8022285303Sgshapiro if (errno == EAGAIN) 8023285303Sgshapiro { 8024285303Sgshapiro syserr("451 4.3.0 socket_map_lookup(%s): read timeout", 8025285303Sgshapiro map->map_mname); 8026285303Sgshapiro } 8027285303Sgshapiro else 8028285303Sgshapiro { 8029285303Sgshapiro syserr("451 4.3.0 socket_map_lookup(%s): failed to read length parameter of reply %d", 8030285303Sgshapiro map->map_mname, errno); 8031285303Sgshapiro } 8032132943Sgshapiro *statp = EX_TEMPFAIL; 8033132943Sgshapiro goto errcl; 8034132943Sgshapiro } 8035132943Sgshapiro if (replylen > SOCKETMAP_MAXL) 8036132943Sgshapiro { 8037132943Sgshapiro syserr("451 4.3.0 socket_map_lookup(%s): reply too long: %u", 8038132943Sgshapiro map->map_mname, replylen); 8039132943Sgshapiro *statp = EX_TEMPFAIL; 8040132943Sgshapiro goto errcl; 8041132943Sgshapiro } 8042132943Sgshapiro if (sm_io_getc(f, SM_TIME_DEFAULT) != ':') 8043132943Sgshapiro { 8044132943Sgshapiro syserr("451 4.3.0 socket_map_lookup(%s): missing ':' in reply", 8045132943Sgshapiro map->map_mname); 8046132943Sgshapiro *statp = EX_TEMPFAIL; 8047132943Sgshapiro goto error; 8048132943Sgshapiro } 8049132943Sgshapiro 8050132943Sgshapiro replybuf = (char *) sm_malloc(replylen + 1); 8051132943Sgshapiro if (replybuf == NULL) 8052132943Sgshapiro { 8053132943Sgshapiro syserr("451 4.3.0 socket_map_lookup(%s): can't allocate %u bytes", 8054132943Sgshapiro map->map_mname, replylen + 1); 8055132943Sgshapiro *statp = EX_OSERR; 8056132943Sgshapiro goto error; 8057132943Sgshapiro } 8058132943Sgshapiro 8059132943Sgshapiro recvlen = sm_io_read(f, SM_TIME_DEFAULT, replybuf, replylen); 8060132943Sgshapiro if (recvlen < replylen) 8061132943Sgshapiro { 8062132943Sgshapiro syserr("451 4.3.0 socket_map_lookup(%s): received only %u of %u reply characters", 8063132943Sgshapiro map->map_mname, recvlen, replylen); 8064132943Sgshapiro *statp = EX_TEMPFAIL; 8065132943Sgshapiro goto errcl; 8066132943Sgshapiro } 8067132943Sgshapiro if (sm_io_getc(f, SM_TIME_DEFAULT) != ',') 8068132943Sgshapiro { 8069132943Sgshapiro syserr("451 4.3.0 socket_map_lookup(%s): missing ',' in reply", 8070132943Sgshapiro map->map_mname); 8071132943Sgshapiro *statp = EX_TEMPFAIL; 8072132943Sgshapiro goto errcl; 8073132943Sgshapiro } 8074132943Sgshapiro status = replybuf; 8075132943Sgshapiro replybuf[recvlen] = '\0'; 8076132943Sgshapiro value = strchr(replybuf, ' '); 8077132943Sgshapiro if (value != NULL) 8078132943Sgshapiro { 8079132943Sgshapiro *value = '\0'; 8080132943Sgshapiro value++; 8081132943Sgshapiro } 8082132943Sgshapiro if (strcmp(status, "OK") == 0) 8083132943Sgshapiro { 8084132943Sgshapiro *statp = EX_OK; 8085132943Sgshapiro 8086132943Sgshapiro /* collect the return value */ 8087132943Sgshapiro if (bitset(MF_MATCHONLY, map->map_mflags)) 8088147078Sgshapiro rval = map_rewrite(map, key, strlen(key), NULL); 8089132943Sgshapiro else 8090132943Sgshapiro rval = map_rewrite(map, value, strlen(value), av); 8091132943Sgshapiro } 8092132943Sgshapiro else if (strcmp(status, "NOTFOUND") == 0) 8093132943Sgshapiro { 8094132943Sgshapiro *statp = EX_NOTFOUND; 8095132943Sgshapiro if (tTd(38, 20)) 8096132943Sgshapiro sm_dprintf("socket_map_lookup(%s): %s not found\n", 8097147078Sgshapiro map->map_mname, key); 8098132943Sgshapiro } 8099132943Sgshapiro else 8100132943Sgshapiro { 8101132943Sgshapiro if (tTd(38, 5)) 8102132943Sgshapiro sm_dprintf("socket_map_lookup(%s, %s): server returned error: type=%s, reason=%s\n", 8103147078Sgshapiro map->map_mname, key, status, 8104132943Sgshapiro value ? value : ""); 8105132943Sgshapiro if ((strcmp(status, "TEMP") == 0) || 8106132943Sgshapiro (strcmp(status, "TIMEOUT") == 0)) 8107132943Sgshapiro *statp = EX_TEMPFAIL; 8108132943Sgshapiro else if(strcmp(status, "PERM") == 0) 8109132943Sgshapiro *statp = EX_UNAVAILABLE; 8110132943Sgshapiro else 8111132943Sgshapiro *statp = EX_PROTOCOL; 8112132943Sgshapiro } 8113132943Sgshapiro 8114132943Sgshapiro if (replybuf != NULL) 8115132943Sgshapiro sm_free(replybuf); 8116132943Sgshapiro return rval; 8117132943Sgshapiro 8118132943Sgshapiro errcl: 8119132943Sgshapiro socket_map_close(map); 8120132943Sgshapiro error: 8121132943Sgshapiro if (replybuf != NULL) 8122132943Sgshapiro sm_free(replybuf); 8123132943Sgshapiro return rval; 8124132943Sgshapiro} 8125132943Sgshapiro#endif /* SOCKETMAP */ 8126