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