1 /* 2 * Copyright (c) 1992 Eric P. Allman. 3 * Copyright (c) 1992 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)map.c 6.12 (Berkeley) 05/01/93"; 11 #endif /* not lint */ 12 13 #include "sendmail.h" 14 15 #ifdef DBM_MAP 16 #include <ndbm.h> 17 #endif 18 #if defined(HASH_MAP) || defined(BTREE_MAP) 19 #undef __P 20 #include <db.h> 21 #endif 22 #ifdef NIS_MAP 23 #include <rpcsvc/ypclnt.h> 24 #endif 25 26 27 #ifdef DBM_MAP 28 29 /* 30 ** DBM_MAP_INIT -- DBM-style map initialization 31 ** 32 ** Parameters: 33 ** map -- the pointer to the actual map 34 ** mapname -- the name of the map (for error messages) 35 ** args -- a pointer to the config file line arguments 36 ** 37 ** Returns: 38 ** TRUE -- if it could successfully open the map. 39 ** FALSE -- otherwise. 40 ** 41 ** Side Effects: 42 ** Gives an error if it can't open the map. 43 */ 44 45 bool 46 dbm_map_init(map, mapname, args) 47 MAP *map; 48 char *mapname; 49 char *args; 50 { 51 DBM *dbm; 52 53 map_parseargs(map, &args); 54 if (map->map_file == NULL) 55 { 56 syserr("No file name for DBM map %s", mapname); 57 return FALSE; 58 } 59 dbm = dbm_open(map->map_file, O_RDONLY, 0644); 60 if (dbm == NULL) 61 { 62 if (!bitset(MF_OPTIONAL, map->map_flags)) 63 syserr("Cannot open DBM database %s", map->map_file); 64 return FALSE; 65 } 66 map->map_db = (void *) dbm; 67 return TRUE; 68 } 69 /* 70 ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 71 ** 72 ** Parameters: 73 ** map -- the map to look up in. 74 ** buf -- a pointer to to the buffer containing the key. 75 ** This is a null terminated string. 76 ** bufsiz -- the size of buf -- note that this is in general 77 ** larger that strlen(buf), and buf can be changed 78 ** in place if desired. 79 ** av -- arguments from the config file (can be interpolated 80 ** into the final result). 81 ** statp -- pointer to status word (out-parameter). 82 ** 83 ** Returns: 84 ** A pointer to the rewritten result. 85 ** NULL if not found in the map. 86 */ 87 88 char * 89 dbm_map_lookup(map, buf, bufsiz, av, statp) 90 MAP *map; 91 char buf[]; 92 int bufsiz; 93 char **av; 94 int *statp; 95 { 96 datum key, val; 97 98 key.dptr = buf; 99 key.dsize = strlen(buf); 100 if (!bitset(MF_NOFOLDCASE, map->map_flags)) 101 { 102 register char *p; 103 104 for (p = buf; *p != '\0'; p++) 105 if (isascii(*p) && isupper(*p)) 106 *p = tolower(*p); 107 } 108 if (bitset(MF_INCLNULL, map->map_flags)) 109 key.dsize++; 110 (void) lockfile(dbm_dirfno((DBM *) map->map_db), map->map_file, LOCK_SH); 111 val = dbm_fetch((DBM *) map->map_db, key); 112 (void) lockfile(dbm_dirfno((DBM *) map->map_db), map->map_file, LOCK_UN); 113 if (val.dptr == NULL) 114 return NULL; 115 if (!bitset(MF_MATCHONLY, map->map_flags)) 116 map_rewrite(val.dptr, val.dsize, buf, bufsiz, av); 117 return buf; 118 } 119 120 #endif /* DBM_MAP */ 121 122 #ifdef BTREE_MAP 123 124 /* 125 ** BTREE_MAP_INIT -- BTREE-style map initialization 126 ** 127 ** Parameters: 128 ** map -- the pointer to the actual map 129 ** mapname -- the name of the map (for error messages) 130 ** args -- a pointer to the config file line arguments 131 ** 132 ** Returns: 133 ** TRUE -- if it could successfully open the map. 134 ** FALSE -- otherwise. 135 ** 136 ** Side Effects: 137 ** Gives an error if it can't open the map. 138 */ 139 140 bool 141 bt_map_init(map, mapname, args) 142 MAP *map; 143 char *mapname; 144 char *args; 145 { 146 DB *db; 147 148 map_parseargs(map, &args); 149 if (map->map_file == NULL) 150 { 151 syserr("No file name for BTREE map %s", mapname); 152 return FALSE; 153 } 154 db = dbopen(map->map_file, O_RDONLY, 0644, DB_BTREE, NULL); 155 if (db == NULL) 156 { 157 if (!bitset(MF_OPTIONAL, map->map_flags)) 158 syserr("Cannot open BTREE database %s", map->map_file); 159 return FALSE; 160 } 161 map->map_db = (void *) db; 162 return TRUE; 163 } 164 165 #endif /* BTREE_MAP */ 166 167 #ifdef HASH_MAP 168 169 /* 170 ** HASH_MAP_INIT -- HASH-style map initialization 171 ** 172 ** Parameters: 173 ** map -- the pointer to the actual map 174 ** mapname -- the name of the map (for error messages) 175 ** args -- a pointer to the config file line arguments 176 ** 177 ** Returns: 178 ** TRUE -- if it could successfully open the map. 179 ** FALSE -- otherwise. 180 ** 181 ** Side Effects: 182 ** Gives an error if it can't open the map. 183 */ 184 185 bool 186 hash_map_init(map, mapname, args) 187 MAP *map; 188 char *mapname; 189 char *args; 190 { 191 DB *db; 192 193 map_parseargs(map, &args); 194 if (map->map_file == NULL) 195 { 196 syserr("No file name for HASH map %s", mapname); 197 return FALSE; 198 } 199 db = dbopen(map->map_file, O_RDONLY, 0644, DB_HASH, NULL); 200 if (db == NULL) 201 { 202 if (!bitset(MF_OPTIONAL, map->map_flags)) 203 syserr("Cannot open HASH database %s", map->map_file); 204 return FALSE; 205 } 206 map->map_db = (void *) db; 207 return TRUE; 208 } 209 210 #endif /* HASH_MAP */ 211 212 #if defined(BTREE_MAP) || defined(HASH_MAP) 213 214 /* 215 ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 216 ** 217 ** Parameters: 218 ** map -- the map to look up in. 219 ** buf -- a pointer to to the buffer containing the key. 220 ** This is a null terminated string. 221 ** bufsiz -- the size of buf -- note that this is in general 222 ** larger that strlen(buf), and buf can be changed 223 ** in place if desired. 224 ** av -- arguments from the config file (can be interpolated 225 ** into the final result). 226 ** statp -- pointer to status word (out-parameter). 227 ** 228 ** Returns: 229 ** A pointer to the rewritten result. 230 ** NULL if not found in the map. 231 */ 232 233 char * 234 db_map_lookup(map, buf, bufsiz, av, statp) 235 MAP *map; 236 char buf[]; 237 int bufsiz; 238 char **av; 239 int *statp; 240 { 241 DBT key, val; 242 243 key.data = buf; 244 key.size = strlen(buf); 245 if (!bitset(MF_NOFOLDCASE, map->map_flags)) 246 { 247 register char *p; 248 249 for (p = buf; *p != '\0'; p++) 250 if (isascii(*p) && isupper(*p)) 251 *p = tolower(*p); 252 } 253 if (bitset(MF_INCLNULL, map->map_flags)) 254 key.size++; 255 if (((DB *) map->map_db)->get((DB *) map->map_db, &key, &val, 0) != 0) 256 return NULL; 257 if (!bitset(MF_MATCHONLY, map->map_flags)) 258 map_rewrite(val.data, val.size, buf, bufsiz, av); 259 return buf; 260 } 261 262 #endif /* BTREE_MAP || HASH_MAP */ 263 /* 264 ** MAP_PARSEARGS -- parse config line arguments for database lookup 265 ** 266 ** Parameters: 267 ** map -- the map being initialized. 268 ** pp -- an indirect pointer to the config line. It will 269 ** be replaced with a pointer to the next field 270 ** on the line. 271 ** 272 ** Returns: 273 ** none 274 ** 275 ** Side Effects: 276 ** null terminates the filename; stores it in map 277 */ 278 279 map_parseargs(map, pp) 280 MAP *map; 281 char **pp; 282 { 283 register char *p = *pp; 284 285 for (;;) 286 { 287 while (isascii(*p) && isspace(*p)) 288 p++; 289 if (*p != '-') 290 break; 291 switch (*++p) 292 { 293 case 'N': 294 map->map_flags |= MF_INCLNULL; 295 break; 296 297 case 'o': 298 map->map_flags |= MF_OPTIONAL; 299 break; 300 301 case 'f': 302 map->map_flags |= MF_NOFOLDCASE; 303 break; 304 305 case 'm': 306 map->map_flags |= MF_MATCHONLY; 307 break; 308 309 case 'a': 310 map->map_app = ++p; 311 break; 312 313 case 'd': 314 map->map_domain = ++p; 315 break; 316 } 317 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 318 p++; 319 if (*p != '\0') 320 *p++ = '\0'; 321 } 322 if (map->map_app != NULL) 323 map->map_app = newstr(map->map_app); 324 if (map->map_domain != NULL) 325 map->map_domain = newstr(map->map_domain); 326 327 if (*p != '\0') 328 { 329 map->map_file = p; 330 while (*p != '\0' && !(isascii(*p) && isspace(*p))) 331 p++; 332 if (*p != '\0') 333 *p++ = '\0'; 334 map->map_file = newstr(map->map_file); 335 } 336 337 while (*p != '\0' && isascii(*p) && isspace(*p)) 338 p++; 339 *pp = p; 340 if (*p != '\0') 341 map->map_rebuild = newstr(p); 342 } 343 344 # ifdef NIS_MAP 345 346 /* 347 ** NIS_MAP_INIT -- initialize DBM map 348 ** 349 ** Parameters: 350 ** map -- the pointer to the actual map. 351 ** mapname -- the name of the map (for error messages). 352 ** args -- a pointer to the config file line arguments. 353 ** 354 ** Returns: 355 ** TRUE -- if it could successfully open the map. 356 ** FALSE -- otherwise. 357 ** 358 ** Side Effects: 359 ** Prints an error if it can't open the map. 360 */ 361 362 bool 363 nis_map_init(map, mapname, args) 364 MAP *map; 365 char *mapname; 366 char *args; 367 { 368 int yperr; 369 char *master; 370 371 /* parse arguments */ 372 map_parseargs(map, &args); 373 if (map->map_file == NULL) 374 { 375 syserr("No NIS map name for map %s", mapname); 376 return FALSE; 377 } 378 if (map->map_domain == NULL) 379 yp_get_default_domain(&map->map_domain); 380 381 /* check to see if this map actually exists */ 382 yperr = yp_master(map->map_domain, map->map_file, &master); 383 if (yperr == 0) 384 return TRUE; 385 if (!bitset(MF_OPTIONAL, map->map_flags)) 386 syserr("Cannot bind to domain %s: %s", map->map_domain, 387 yperr_string(yperr)); 388 return FALSE; 389 } 390 /* 391 ** NIS_MAP_LOOKUP -- look up a datum in a NIS map 392 ** 393 ** Parameters: 394 ** map -- the map to look up in. 395 ** buf -- a pointer to to the buffer containing the key. 396 ** This is a null terminated string. 397 ** bufsiz -- the size of buf -- note that this is in general 398 ** larger that strlen(buf), and buf can be changed 399 ** in place if desired. 400 ** av -- arguments from the config file (can be interpolated 401 ** into the final result). 402 ** statp -- pointer to status word (out-parameter). 403 ** 404 ** Returns: 405 ** A pointer to the rewritten result. 406 ** NULL if not found in the map. 407 */ 408 409 char * 410 nis_map_lookup(map, buf, bufsiz, av, statp) 411 MAP *map; 412 char buf[]; 413 int bufsiz; 414 char **av; 415 int *statp; 416 { 417 char *vp; 418 auto int vsize; 419 int buflen; 420 421 if (!bitset(MF_NOFOLDCASE, map->map_flags)) 422 { 423 register char *p; 424 425 for (p = buf; *p != '\0'; p++) 426 if (isascii(*p) && isupper(*p)) 427 *p = tolower(*p); 428 } 429 buflen = strlen(buf); 430 if (bitset(MF_INCLNULL, map->map_flags)) 431 buflen++; 432 if (yp_match(map->map_domain, map->map_file, buf, buflen, 433 &vp, &vsize) != 0) 434 return NULL; 435 if (!bitset(MF_MATCHONLY, map->map_flags)) 436 map_rewrite(vp, vsize, buf, bufsiz, av); 437 return buf; 438 } 439 440 #endif /* NIS_MAP */ 441 /* 442 ** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 443 ** 444 ** Parameters: 445 ** s -- the string to rewrite, NOT necessarily null terminated. 446 ** slen -- the length of s. 447 ** buf -- the place to write it. 448 ** buflen -- the length of buf. 449 ** av -- arguments to interpolate into buf. 450 ** 451 ** Returns: 452 ** none. 453 ** 454 ** Side Effects: 455 ** none. 456 */ 457 458 map_rewrite(s, slen, buf, buflen, av) 459 register char *s; 460 int slen; 461 char buf[]; 462 int buflen; 463 char **av; 464 { 465 register char *bp; 466 char *buflim; 467 register char c; 468 char **avp; 469 register char *ap; 470 471 if (tTd(23, 1)) 472 { 473 printf("map_rewrite(%.*s), av =\n", slen, s); 474 for (avp = av; *avp != NULL; avp++) 475 printf("\t%s\n", *avp); 476 } 477 478 bp = buf; 479 buflim = &buf[buflen - 2]; 480 while (--slen >= 0 && (c = *s++) != '\0') 481 { 482 if (c != '%') 483 { 484 pushc: 485 if (bp < buflim) 486 *bp++ = c; 487 continue; 488 } 489 if (--slen < 0 || (c = *s++) == '\0') 490 c = '%'; 491 if (c == '%') 492 goto pushc; 493 if (!(isascii(c) && isdigit(c))) 494 { 495 *bp++ = '%'; 496 goto pushc; 497 } 498 c -= '0'; 499 for (avp = av; --c >= 0 && *avp != NULL; avp++) 500 continue; 501 if (*avp == NULL) 502 continue; 503 504 /* transliterate argument into output string */ 505 for (ap = *avp; (c = *ap++) != '\0'; ) 506 { 507 if (bp < buflim) 508 *bp++ = c; 509 } 510 } 511 *bp++ = '\0'; 512 if (tTd(23, 1)) 513 printf("map_rewrite => %s\n", buf); 514 } 515