156822Seric /* 256822Seric * Copyright (c) 1992 Eric P. Allman. 356822Seric * Copyright (c) 1992 Regents of the University of California. 456822Seric * All rights reserved. 556822Seric * 656822Seric * %sccs.include.redist.c% 756822Seric */ 856822Seric 956822Seric #ifndef lint 10*57216Seric static char sccsid[] = "@(#)map.c 5.7 (Berkeley) 12/18/92"; 1156822Seric #endif /* not lint */ 1256822Seric 1356822Seric #include "sendmail.h" 1456822Seric #include <sys/file.h> 1556822Seric 1656822Seric #ifdef DBM_MAP 1756822Seric #include <ndbm.h> 1856822Seric #endif 1956822Seric #if defined(HASH_MAP) || defined(BTREE_MAP) 2056822Seric #include <db.h> 2156822Seric #endif 2257208Seric #ifdef NIS_MAP 2357208Seric #include <rpcsvc/ypclnt.h> 2457208Seric #endif 2556822Seric 2656822Seric 2756822Seric #ifdef DBM_MAP 2856822Seric 2956822Seric /* 3056822Seric ** DBM_MAP_INIT -- DBM-style map initialization 3156822Seric ** 3256822Seric ** Parameters: 3356822Seric ** map -- the pointer to the actual map 3456822Seric ** mapname -- the name of the map (for error messages) 3556822Seric ** args -- a pointer to the config file line arguments 3656822Seric ** 3756822Seric ** Returns: 3856822Seric ** TRUE -- if it could successfully open the map. 3956822Seric ** FALSE -- otherwise. 4056822Seric ** 4156822Seric ** Side Effects: 4256822Seric ** Gives an error if it can't open the map. 4356822Seric */ 4456822Seric 4556822Seric bool 4656822Seric dbm_map_init(map, mapname, args) 4756822Seric MAP *map; 4856822Seric char *mapname; 4956822Seric char *args; 5056822Seric { 5156822Seric DBM *dbm; 5256822Seric 5357208Seric map_parseargs(map, &args); 5456822Seric if (map->map_file == NULL) 5557208Seric { 5657208Seric syserr("No file name for DBM map %s", mapname); 5756822Seric return FALSE; 5857208Seric } 5956822Seric dbm = dbm_open(map->map_file, O_RDONLY, 0644); 6056822Seric if (dbm == NULL) 6156822Seric { 6256836Seric if (!bitset(MF_OPTIONAL, map->map_flags)) 6356836Seric syserr("Cannot open DBM database %s", map->map_file); 6456822Seric return FALSE; 6556822Seric } 6656822Seric map->map_db = (void *) dbm; 6756822Seric return TRUE; 6856822Seric } 6956822Seric /* 7056822Seric ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 7156822Seric ** 7256822Seric ** Parameters: 7356822Seric ** map -- the map to look up in. 7456822Seric ** buf -- a pointer to to the buffer containing the key. 7556822Seric ** This is a null terminated string. 7656822Seric ** bufsiz -- the size of buf -- note that this is in general 7756822Seric ** larger that strlen(buf), and buf can be changed 7856822Seric ** in place if desired. 7956822Seric ** av -- arguments from the config file (can be interpolated 8056822Seric ** into the final result). 8156822Seric ** 8256822Seric ** Returns: 8356822Seric ** A pointer to the rewritten result. 8456822Seric ** NULL if not found in the map. 8556822Seric */ 8656822Seric 8756822Seric char * 8856822Seric dbm_map_lookup(map, buf, bufsiz, av) 8956822Seric MAP *map; 9056822Seric char buf[]; 9156822Seric int bufsiz; 9256822Seric char **av; 9356822Seric { 9456822Seric datum key, val; 9556822Seric 9656822Seric key.dptr = buf; 9756822Seric key.dsize = strlen(buf); 9857033Seric if (!bitset(MF_NOFOLDCASE, map->map_flags)) 9957014Seric { 10057014Seric register char *p; 10157014Seric 10257014Seric for (p = buf; *p != '\0'; p++) 10357014Seric if (isupper(*p)) 10457014Seric *p = tolower(*p); 10557014Seric } 10656822Seric if (bitset(MF_INCLNULL, map->map_flags)) 10756822Seric key.dsize++; 10856822Seric val = dbm_fetch(map->map_db, key); 10956822Seric if (val.dptr == NULL) 11056822Seric return NULL; 11157208Seric if (!bitset(MF_MATCHONLY, map->map_flags)) 11257208Seric map_rewrite(val.dptr, val.dsize, buf, bufsiz, av); 11356822Seric return buf; 11456822Seric } 11556822Seric 11656822Seric #endif /* DBM_MAP */ 11756822Seric 11856822Seric #ifdef BTREE_MAP 11956822Seric 12056822Seric /* 12156822Seric ** BTREE_MAP_INIT -- BTREE-style map initialization 12256822Seric ** 12356822Seric ** Parameters: 12456822Seric ** map -- the pointer to the actual map 12556822Seric ** mapname -- the name of the map (for error messages) 12656822Seric ** args -- a pointer to the config file line arguments 12756822Seric ** 12856822Seric ** Returns: 12956822Seric ** TRUE -- if it could successfully open the map. 13056822Seric ** FALSE -- otherwise. 13156822Seric ** 13256822Seric ** Side Effects: 13356822Seric ** Gives an error if it can't open the map. 13456822Seric */ 13556822Seric 13656822Seric bool 13756822Seric bt_map_init(map, mapname, args) 13856822Seric MAP *map; 13956822Seric char *mapname; 14056822Seric char *args; 14156822Seric { 14256822Seric DB *db; 14356822Seric 14457208Seric map_parseargs(map, &args); 14556822Seric if (map->map_file == NULL) 14657208Seric { 14757208Seric syserr("No file name for BTREE map %s", mapname); 14856822Seric return FALSE; 14957208Seric } 15056822Seric db = dbopen(map->map_file, O_RDONLY, 0644, DB_BTREE, NULL); 15156822Seric if (db == NULL) 15256822Seric { 15356836Seric if (!bitset(MF_OPTIONAL, map->map_flags)) 15456836Seric syserr("Cannot open BTREE database %s", map->map_file); 15556822Seric return FALSE; 15656822Seric } 15756822Seric map->map_db = (void *) db; 15856822Seric return TRUE; 15956822Seric } 16056822Seric 16156822Seric #endif /* BTREE_MAP */ 16256822Seric 16356822Seric #ifdef HASH_MAP 16456822Seric 16556822Seric /* 16656822Seric ** HASH_MAP_INIT -- HASH-style map initialization 16756822Seric ** 16856822Seric ** Parameters: 16956822Seric ** map -- the pointer to the actual map 17056822Seric ** mapname -- the name of the map (for error messages) 17156822Seric ** args -- a pointer to the config file line arguments 17256822Seric ** 17356822Seric ** Returns: 17456822Seric ** TRUE -- if it could successfully open the map. 17556822Seric ** FALSE -- otherwise. 17656822Seric ** 17756822Seric ** Side Effects: 17856822Seric ** Gives an error if it can't open the map. 17956822Seric */ 18056822Seric 18156822Seric bool 18256822Seric hash_map_init(map, mapname, args) 18356822Seric MAP *map; 18456822Seric char *mapname; 18556822Seric char *args; 18656822Seric { 18756822Seric DB *db; 18856822Seric 18957208Seric map_parseargs(map, &args); 19056822Seric if (map->map_file == NULL) 19157208Seric { 19257208Seric syserr("No file name for HASH map %s", mapname); 19356822Seric return FALSE; 19457208Seric } 19556822Seric db = dbopen(map->map_file, O_RDONLY, 0644, DB_HASH, NULL); 19656822Seric if (db == NULL) 19756822Seric { 19856836Seric if (!bitset(MF_OPTIONAL, map->map_flags)) 19956836Seric syserr("Cannot open HASH database %s", map->map_file); 20056822Seric return FALSE; 20156822Seric } 20256822Seric map->map_db = (void *) db; 20356822Seric return TRUE; 20456822Seric } 20556822Seric 20656822Seric #endif /* HASH_MAP */ 20756822Seric 20856822Seric #if defined(BTREE_MAP) || defined(HASH_MAP) 20956822Seric 21056822Seric /* 21156822Seric ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 21256822Seric ** 21356822Seric ** Parameters: 21456822Seric ** map -- the map to look up in. 21556822Seric ** buf -- a pointer to to the buffer containing the key. 21656822Seric ** This is a null terminated string. 21756822Seric ** bufsiz -- the size of buf -- note that this is in general 21856822Seric ** larger that strlen(buf), and buf can be changed 21956822Seric ** in place if desired. 22056822Seric ** av -- arguments from the config file (can be interpolated 22156822Seric ** into the final result). 22256822Seric ** 22356822Seric ** Returns: 22456822Seric ** A pointer to the rewritten result. 22556822Seric ** NULL if not found in the map. 22656822Seric */ 22756822Seric 22856822Seric char * 22956822Seric db_map_lookup(map, buf, bufsiz, av) 23056822Seric MAP *map; 23156822Seric char buf[]; 23256822Seric int bufsiz; 23356822Seric char **av; 23456822Seric { 23556822Seric DBT key, val; 23656822Seric 23756822Seric key.data = buf; 23856822Seric key.size = strlen(buf); 23957033Seric if (!bitset(MF_NOFOLDCASE, map->map_flags)) 24056847Seric { 24156847Seric register char *p; 24256847Seric 24356847Seric for (p = buf; *p != '\0'; p++) 24456847Seric if (isupper(*p)) 24556847Seric *p = tolower(*p); 24656847Seric } 24756822Seric if (bitset(MF_INCLNULL, map->map_flags)) 24856822Seric key.size++; 24956836Seric if (((DB *) map->map_db)->get((DB *) map->map_db, &key, &val, 0) != 0) 25056822Seric return NULL; 25157208Seric if (!bitset(MF_MATCHONLY, map->map_flags)) 25257208Seric map_rewrite(val.data, val.size, buf, bufsiz, av); 25356822Seric return buf; 25456822Seric } 25556822Seric 25656822Seric #endif /* BTREE_MAP || HASH_MAP */ 25756822Seric /* 25856822Seric ** MAP_PARSEARGS -- parse config line arguments for database lookup 25956822Seric ** 26056822Seric ** Parameters: 26156822Seric ** map -- the map being initialized. 26256822Seric ** pp -- an indirect pointer to the config line. It will 26356822Seric ** be replaced with a pointer to the next field 26456822Seric ** on the line. 26556822Seric ** 26656822Seric ** Returns: 26756822Seric ** none 26856822Seric ** 26956822Seric ** Side Effects: 27056822Seric ** null terminates the filename; stores it in map 27156822Seric */ 27256822Seric 27357208Seric map_parseargs(map, pp) 27456822Seric MAP *map; 27556822Seric char **pp; 27656822Seric { 27756822Seric register char *p = *pp; 27856822Seric 27956822Seric for (;;) 28056822Seric { 28156822Seric while (isspace(*p)) 28256822Seric p++; 28356822Seric if (*p != '-') 28456822Seric break; 28556822Seric switch (*++p) 28656822Seric { 28756822Seric case 'N': 28856822Seric map->map_flags |= MF_INCLNULL; 28956822Seric break; 29056836Seric 29156836Seric case 'o': 29256836Seric map->map_flags |= MF_OPTIONAL; 29356836Seric break; 29456836Seric 29556847Seric case 'f': 29657033Seric map->map_flags |= MF_NOFOLDCASE; 29756847Seric break; 29856847Seric 29957208Seric case 'm': 30057208Seric map->map_flags |= MF_MATCHONLY; 30157208Seric break; 30257208Seric 30356836Seric case 'a': 30456836Seric map->map_app = ++p; 30556836Seric break; 30657208Seric 30757208Seric case 'd': 30857208Seric map->map_domain = ++p; 30957208Seric break; 31056822Seric } 31156822Seric while (*p != '\0' && !isspace(*p)) 31256822Seric p++; 31356836Seric if (*p != '\0') 31456836Seric *p++ = 0; 31556822Seric } 31656836Seric if (map->map_app != NULL) 31756836Seric map->map_app = newstr(map->map_app); 31857208Seric if (map->map_domain != NULL) 31957208Seric map->map_domain = newstr(map->map_domain); 32056822Seric 32156822Seric if (*p == '\0') 32256822Seric return NULL; 32356822Seric map->map_file = p; 32456822Seric while (*p != '\0' && !isspace(*p)) 32556822Seric p++; 32656822Seric if (*p != '\0') 32756822Seric *p++ = '\0'; 32856836Seric map->map_file = newstr(map->map_file); 32956822Seric *pp = p; 33056822Seric } 33157208Seric 33257208Seric # ifdef NIS_MAP 33357208Seric 33457208Seric /* 33557208Seric ** NIS_MAP_INIT -- initialize DBM map 33657208Seric ** 33757208Seric ** Parameters: 33857208Seric ** map -- the pointer to the actual map. 33957208Seric ** mapname -- the name of the map (for error messages). 34057208Seric ** args -- a pointer to the config file line arguments. 34157208Seric ** 34257208Seric ** Returns: 34357208Seric ** TRUE -- if it could successfully open the map. 34457208Seric ** FALSE -- otherwise. 34557208Seric ** 34657208Seric ** Side Effects: 34757208Seric ** Prints an error if it can't open the map. 34857208Seric */ 34957208Seric 35057208Seric bool 35157208Seric nis_map_init(map, mapname, args) 35257208Seric MAP *map; 35357208Seric char *mapname; 35457208Seric char *args; 35557208Seric { 356*57216Seric int yperr; 357*57216Seric char *master; 358*57216Seric 35957208Seric /* parse arguments */ 36057208Seric map_parseargs(map, &args); 36157208Seric if (map->map_file == NULL) 36257208Seric { 36357208Seric syserr("No NIS map name for map %s", mapname); 36457208Seric return FALSE; 36557208Seric } 36657208Seric if (map->map_domain == NULL) 36757208Seric yp_get_default_domain(&map->map_domain); 368*57216Seric 369*57216Seric /* check to see if this map actually exists */ 370*57216Seric yperr = yp_master(map->map_domain, map->map_file, &master); 371*57216Seric if (yperr == 0) 372*57216Seric return TRUE; 373*57216Seric if (!bitset(MF_OPTIONAL, map->map_flags)) 374*57216Seric syserr("Cannot bind to domain %s: %s", map->map_domain, 375*57216Seric yperr_string(yperr)); 376*57216Seric return FALSE; 37757208Seric } 37856822Seric /* 37957208Seric ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 38057208Seric ** 38157208Seric ** Parameters: 38257208Seric ** map -- the map to look up in. 38357208Seric ** buf -- a pointer to to the buffer containing the key. 38457208Seric ** This is a null terminated string. 38557208Seric ** bufsiz -- the size of buf -- note that this is in general 38657208Seric ** larger that strlen(buf), and buf can be changed 38757208Seric ** in place if desired. 38857208Seric ** av -- arguments from the config file (can be interpolated 38957208Seric ** into the final result). 39057208Seric ** 39157208Seric ** Returns: 39257208Seric ** A pointer to the rewritten result. 39357208Seric ** NULL if not found in the map. 39457208Seric */ 39557208Seric 39657208Seric char * 39757208Seric nis_map_lookup(map, buf, bufsiz, av) 39857208Seric MAP *map; 39957208Seric char buf[]; 40057208Seric int bufsiz; 40157208Seric char **av; 40257208Seric { 40357208Seric char *vp; 40457208Seric int *vsize; 40557208Seric 40657208Seric if (!bitset(MF_NOFOLDCASE, map->map_flags)) 40757208Seric { 40857208Seric register char *p; 40957208Seric 41057208Seric for (p = buf; *p != '\0'; p++) 41157208Seric if (isupper(*p)) 41257208Seric *p = tolower(*p); 41357208Seric } 41457208Seric if (yp_match(map->map_domain, map->map_file, buf, bufsiz, &vp, &vsize) != 0) 41557208Seric return NULL; 41657208Seric if (!bitset(MF_MATCHONLY, map->map_flags)) 41757208Seric map_rewrite(vp, vsize, buf, bufsiz, av); 41857208Seric return buf; 41957208Seric } 42057208Seric 42157208Seric #endif /* NIS_MAP */ 42257208Seric /* 42356822Seric ** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 42456822Seric ** 42556822Seric ** Parameters: 42656822Seric ** s -- the string to rewrite, NOT necessarily null terminated. 42756822Seric ** slen -- the length of s. 42856822Seric ** buf -- the place to write it. 42956822Seric ** buflen -- the length of buf. 43056822Seric ** av -- arguments to interpolate into buf. 43156822Seric ** 43256822Seric ** Returns: 43356822Seric ** none. 43456822Seric ** 43556822Seric ** Side Effects: 43656822Seric ** none. 43756822Seric */ 43856822Seric 43956822Seric map_rewrite(s, slen, buf, buflen, av) 44056822Seric register char *s; 44156822Seric int slen; 44256822Seric char buf[]; 44356822Seric int buflen; 44456822Seric char **av; 44556822Seric { 44656822Seric register char *bp; 44756822Seric char *buflim; 44856822Seric register char c; 44956822Seric char **avp; 45056822Seric register char *ap; 45156822Seric 45256822Seric if (tTd(23, 1)) 45356822Seric { 45456822Seric printf("map_rewrite(%.*s), av =\n", slen, s); 45556822Seric for (avp = av; *avp != NULL; avp++) 45656822Seric printf("\t%s\n", *avp); 45756822Seric } 45856822Seric 45956822Seric bp = buf; 46056822Seric buflim = &buf[buflen - 2]; 46156822Seric while (--slen >= 0 && (c = *s++) != '\0') 46256822Seric { 46356822Seric if (c != '%') 46456822Seric { 46556822Seric pushc: 46656822Seric if (bp < buflim) 46756822Seric *bp++ = c; 46856822Seric continue; 46956822Seric } 47056822Seric if (--slen < 0 || (c = *s++) == '\0') 47156822Seric c = '%'; 47256822Seric if (c == '%') 47356822Seric goto pushc; 47456822Seric if (!isdigit(c)) 47556822Seric { 47656822Seric *bp++ = '%'; 47756822Seric goto pushc; 47856822Seric } 47956822Seric c -= '0'; 48056822Seric for (avp = av; --c >= 0 && *avp != NULL; avp++) 48156822Seric continue; 48256822Seric if (*avp == NULL) 48356822Seric continue; 48456822Seric 48556822Seric /* transliterate argument into output string */ 48656822Seric for (ap = *avp; (c = *ap++) != '\0'; ) 48756822Seric { 48856822Seric if (bp < buflim) 48956822Seric *bp++ = c; 49056822Seric } 49156822Seric } 49256822Seric *bp++ = '\0'; 49356822Seric if (tTd(23, 1)) 49456822Seric printf("map_rewrite => %s\n", buf); 49556822Seric } 496