1 /* $NetBSD: nsdispatch.c,v 1.9 1999/01/25 00:16:17 lukem Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Luke Mewburn. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 /*- 34 * Copyright (c) 2003 Networks Associates Technology, Inc. 35 * All rights reserved. 36 * 37 * Portions of this software were developed for the FreeBSD Project by 38 * Jacques A. Vidrine, Safeport Network Services, and Network 39 * Associates Laboratories, the Security Research Division of Network 40 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 41 * ("CBOSS"), as part of the DARPA CHATS research program. 42 * 43 * Redistribution and use in source and binary forms, with or without 44 * modification, are permitted provided that the following conditions 45 * are met: 46 * 1. Redistributions of source code must retain the above copyright 47 * notice, this list of conditions and the following disclaimer. 48 * 2. Redistributions in binary form must reproduce the above copyright 49 * notice, this list of conditions and the following disclaimer in the 50 * documentation and/or other materials provided with the distribution. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 * 64 */ 65 #include "namespace.h" 66 #include <sys/param.h> 67 #include <sys/stat.h> 68 69 #include <dlfcn.h> 70 #include <errno.h> 71 #include <fcntl.h> 72 #define _NS_PRIVATE 73 #include <nsswitch.h> 74 #include <pthread.h> 75 #include <pthread_np.h> 76 #include <stdio.h> 77 #include <stdlib.h> 78 #include <string.h> 79 #include <syslog.h> 80 #include <unistd.h> 81 #include "un-namespace.h" 82 #include "nss_tls.h" 83 #include "libc_private.h" 84 #ifdef NS_CACHING 85 #include "nscache.h" 86 #endif 87 88 enum _nss_constants { 89 /* Number of elements allocated when we grow a vector */ 90 ELEMSPERCHUNK = 8 91 }; 92 93 /* 94 * Global NSS data structures are mostly read-only, but we update 95 * them when we read or re-read the nsswitch.conf. 96 */ 97 static pthread_rwlock_t nss_lock = PTHREAD_RWLOCK_INITIALIZER; 98 99 /* 100 * Runtime determination of whether we are dynamically linked or not. 101 */ 102 extern int _DYNAMIC __attribute__ ((weak)); 103 #define is_dynamic() (&_DYNAMIC != NULL) 104 105 /* 106 * default sourcelist: `files' 107 */ 108 const ns_src __nsdefaultsrc[] = { 109 { NSSRC_FILES, NS_SUCCESS }, 110 { 0 }, 111 }; 112 113 /* Database, source mappings. */ 114 static unsigned int _nsmapsize; 115 static ns_dbt *_nsmap = NULL; 116 117 /* NSS modules. */ 118 static unsigned int _nsmodsize; 119 static ns_mod *_nsmod; 120 121 /* Placeholder for builtin modules' dlopen `handle'. */ 122 static int __nss_builtin_handle; 123 static void *nss_builtin_handle = &__nss_builtin_handle; 124 125 #ifdef NS_CACHING 126 /* 127 * Cache lookup cycle prevention function - if !NULL then no cache lookups 128 * will be made 129 */ 130 static void *nss_cache_cycle_prevention_func = NULL; 131 #endif 132 133 /* 134 * We keep track of nsdispatch() nesting depth in dispatch_depth. When a 135 * fallback method is invoked from nsdispatch(), we temporarily set 136 * fallback_depth to the current dispatch depth plus one. Subsequent 137 * calls at that exact depth will run in fallback mode (restricted to the 138 * same source as the call that was handled by the fallback method), while 139 * calls below that depth will be handled normally, allowing fallback 140 * methods to perform arbitrary lookups. 141 */ 142 struct fb_state { 143 int dispatch_depth; 144 int fallback_depth; 145 }; 146 static void fb_endstate(void *); 147 NSS_TLS_HANDLING(fb); 148 149 /* 150 * Attempt to spew relatively uniform messages to syslog. 151 */ 152 #define nss_log(level, fmt, ...) \ 153 syslog((level), "NSSWITCH(%s): " fmt, __func__, __VA_ARGS__) 154 #define nss_log_simple(level, s) \ 155 syslog((level), "NSSWITCH(%s): " s, __func__) 156 157 /* 158 * Dynamically growable arrays are used for lists of databases, sources, 159 * and modules. The following `vector' interface is used to isolate the 160 * common operations. 161 */ 162 typedef int (*vector_comparison)(const void *, const void *); 163 typedef void (*vector_free_elem)(void *); 164 static void vector_sort(void *, unsigned int, size_t, 165 vector_comparison); 166 static void vector_free(void *, unsigned int *, size_t, 167 vector_free_elem); 168 static void *vector_ref(unsigned int, void *, unsigned int, size_t); 169 static void *vector_search(const void *, void *, unsigned int, size_t, 170 vector_comparison); 171 static void *vector_append(const void *, void *, unsigned int *, size_t); 172 173 174 /* 175 * Internal interfaces. 176 */ 177 static int string_compare(const void *, const void *); 178 static int mtab_compare(const void *, const void *); 179 static int nss_configure(void); 180 static void ns_dbt_free(ns_dbt *); 181 static void ns_mod_free(ns_mod *); 182 static void ns_src_free(ns_src **, int); 183 static void nss_load_builtin_modules(void); 184 static void nss_load_module(const char *, nss_module_register_fn); 185 static void nss_atexit(void); 186 /* nsparser */ 187 extern FILE *_nsyyin; 188 189 190 /* 191 * The vector operations 192 */ 193 static void 194 vector_sort(void *vec, unsigned int count, size_t esize, 195 vector_comparison comparison) 196 { 197 qsort(vec, count, esize, comparison); 198 } 199 200 201 static void * 202 vector_search(const void *key, void *vec, unsigned int count, size_t esize, 203 vector_comparison comparison) 204 { 205 return (bsearch(key, vec, count, esize, comparison)); 206 } 207 208 209 static void * 210 vector_append(const void *elem, void *vec, unsigned int *count, size_t esize) 211 { 212 void *p; 213 214 if ((*count % ELEMSPERCHUNK) == 0) { 215 p = reallocarray(vec, *count + ELEMSPERCHUNK, esize); 216 if (p == NULL) { 217 nss_log_simple(LOG_ERR, "memory allocation failure"); 218 return (vec); 219 } 220 vec = p; 221 } 222 memmove((void *)(((uintptr_t)vec) + (*count * esize)), elem, esize); 223 (*count)++; 224 return (vec); 225 } 226 227 228 static void * 229 vector_ref(unsigned int i, void *vec, unsigned int count, size_t esize) 230 { 231 if (i < count) 232 return (void *)((uintptr_t)vec + (i * esize)); 233 else 234 return (NULL); 235 } 236 237 238 #define VECTOR_FREE(v, c, s, f) \ 239 do { vector_free(v, c, s, f); v = NULL; } while (0) 240 static void 241 vector_free(void *vec, unsigned int *count, size_t esize, 242 vector_free_elem free_elem) 243 { 244 unsigned int i; 245 void *elem; 246 247 for (i = 0; i < *count; i++) { 248 elem = vector_ref(i, vec, *count, esize); 249 if (elem != NULL) 250 free_elem(elem); 251 } 252 free(vec); 253 *count = 0; 254 } 255 256 /* 257 * Comparison functions for vector_search. 258 */ 259 static int 260 string_compare(const void *a, const void *b) 261 { 262 return (strcasecmp(*(const char * const *)a, *(const char * const *)b)); 263 } 264 265 266 static int 267 mtab_compare(const void *a, const void *b) 268 { 269 int cmp; 270 271 cmp = strcmp(((const ns_mtab *)a)->name, ((const ns_mtab *)b)->name); 272 if (cmp != 0) 273 return (cmp); 274 else 275 return (strcmp(((const ns_mtab *)a)->database, 276 ((const ns_mtab *)b)->database)); 277 } 278 279 /* 280 * NSS nsmap management. 281 */ 282 void 283 _nsdbtaddsrc(ns_dbt *dbt, const ns_src *src) 284 { 285 const ns_mod *modp; 286 287 dbt->srclist = vector_append(src, dbt->srclist, &dbt->srclistsize, 288 sizeof(*src)); 289 modp = vector_search(&src->name, _nsmod, _nsmodsize, sizeof(*_nsmod), 290 string_compare); 291 if (modp == NULL) 292 nss_load_module(src->name, NULL); 293 } 294 295 296 #ifdef _NSS_DEBUG 297 void 298 _nsdbtdump(const ns_dbt *dbt) 299 { 300 int i; 301 302 printf("%s (%d source%s):", dbt->name, dbt->srclistsize, 303 dbt->srclistsize == 1 ? "" : "s"); 304 for (i = 0; i < (int)dbt->srclistsize; i++) { 305 printf(" %s", dbt->srclist[i].name); 306 if (!(dbt->srclist[i].flags & 307 (NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) && 308 (dbt->srclist[i].flags & NS_SUCCESS)) 309 continue; 310 printf(" ["); 311 if (!(dbt->srclist[i].flags & NS_SUCCESS)) 312 printf(" SUCCESS=continue"); 313 if (dbt->srclist[i].flags & NS_UNAVAIL) 314 printf(" UNAVAIL=return"); 315 if (dbt->srclist[i].flags & NS_NOTFOUND) 316 printf(" NOTFOUND=return"); 317 if (dbt->srclist[i].flags & NS_TRYAGAIN) 318 printf(" TRYAGAIN=return"); 319 printf(" ]"); 320 } 321 printf("\n"); 322 } 323 #endif 324 325 326 /* 327 * The first time nsdispatch is called (during a process's lifetime, 328 * or after nsswitch.conf has been updated), nss_configure will 329 * prepare global data needed by NSS. 330 */ 331 static int 332 nss_configure(void) 333 { 334 static time_t confmod; 335 #ifndef NS_REREAD_CONF 336 static int already_initialized = 0; 337 #endif 338 struct stat statbuf; 339 int result, isthreaded; 340 const char *path; 341 #ifdef NS_CACHING 342 void *handle; 343 #endif 344 345 result = 0; 346 isthreaded = __isthreaded; 347 #if defined(_NSS_DEBUG) && defined(_NSS_SHOOT_FOOT) 348 /* NOTE WELL: THIS IS A SECURITY HOLE. This must only be built 349 * for debugging purposes and MUST NEVER be used in production. 350 */ 351 path = getenv("NSSWITCH_CONF"); 352 if (path == NULL) 353 #endif 354 path = _PATH_NS_CONF; 355 #ifndef NS_REREAD_CONF 356 /* 357 * Define NS_REREAD_CONF to have nsswitch notice changes 358 * to nsswitch.conf(5) during runtime. This involves calling 359 * stat(2) every time, which can result in performance hit. 360 */ 361 if (already_initialized) 362 return (0); 363 already_initialized = 1; 364 #endif /* NS_REREAD_CONF */ 365 if (stat(path, &statbuf) != 0) 366 return (0); 367 if (statbuf.st_mtime <= confmod) 368 return (0); 369 if (isthreaded) { 370 (void)_pthread_rwlock_unlock(&nss_lock); 371 result = _pthread_rwlock_wrlock(&nss_lock); 372 if (result != 0) 373 return (result); 374 if (stat(path, &statbuf) != 0) 375 goto fin; 376 if (statbuf.st_mtime <= confmod) 377 goto fin; 378 } 379 _nsyyin = fopen(path, "re"); 380 if (_nsyyin == NULL) 381 goto fin; 382 VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap), 383 (vector_free_elem)ns_dbt_free); 384 VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod), 385 (vector_free_elem)ns_mod_free); 386 if (confmod == 0) 387 (void)atexit(nss_atexit); 388 nss_load_builtin_modules(); 389 _nsyyparse(); 390 (void)fclose(_nsyyin); 391 vector_sort(_nsmap, _nsmapsize, sizeof(*_nsmap), string_compare); 392 confmod = statbuf.st_mtime; 393 394 #ifdef NS_CACHING 395 handle = libc_dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); 396 if (handle != NULL) { 397 nss_cache_cycle_prevention_func = dlsym(handle, 398 "_nss_cache_cycle_prevention_function"); 399 dlclose(handle); 400 } 401 #endif 402 fin: 403 if (isthreaded) { 404 (void)_pthread_rwlock_unlock(&nss_lock); 405 if (result == 0) 406 result = _pthread_rwlock_rdlock(&nss_lock); 407 } 408 return (result); 409 } 410 411 412 void 413 _nsdbtput(const ns_dbt *dbt) 414 { 415 unsigned int i; 416 ns_dbt *p; 417 418 for (i = 0; i < _nsmapsize; i++) { 419 p = vector_ref(i, _nsmap, _nsmapsize, sizeof(*_nsmap)); 420 if (string_compare(&dbt->name, &p->name) == 0) { 421 /* overwrite existing entry */ 422 if (p->srclist != NULL) 423 ns_src_free(&p->srclist, p->srclistsize); 424 memmove(p, dbt, sizeof(*dbt)); 425 return; 426 } 427 } 428 _nsmap = vector_append(dbt, _nsmap, &_nsmapsize, sizeof(*_nsmap)); 429 } 430 431 432 static void 433 ns_dbt_free(ns_dbt *dbt) 434 { 435 ns_src_free(&dbt->srclist, dbt->srclistsize); 436 if (dbt->name) 437 free((void *)dbt->name); 438 } 439 440 441 static void 442 ns_src_free(ns_src **src, int srclistsize) 443 { 444 int i; 445 446 for (i = 0; i < srclistsize; i++) 447 if ((*src)[i].name != NULL) 448 /* This one was allocated by nslexer. You'll just 449 * have to trust me. 450 */ 451 free((void *)((*src)[i].name)); 452 free(*src); 453 *src = NULL; 454 } 455 456 457 458 /* 459 * NSS module management. 460 */ 461 /* The built-in NSS modules are all loaded at once. */ 462 #define NSS_BACKEND(name, reg) \ 463 ns_mtab *reg(unsigned int *, nss_module_unregister_fn *); 464 #include "nss_backends.h" 465 #undef NSS_BACKEND 466 467 static void 468 nss_load_builtin_modules(void) 469 { 470 #define NSS_BACKEND(name, reg) nss_load_module(#name, reg); 471 #include "nss_backends.h" 472 #undef NSS_BACKEND 473 } 474 475 476 /* Load a built-in or dynamically linked module. If the `reg_fn' 477 * argument is non-NULL, assume a built-in module and use reg_fn to 478 * register it. Otherwise, search for a dynamic NSS module. 479 */ 480 static void 481 nss_load_module(const char *source, nss_module_register_fn reg_fn) 482 { 483 char buf[PATH_MAX]; 484 ns_mod mod; 485 nss_module_register_fn fn; 486 487 memset(&mod, 0, sizeof(mod)); 488 mod.name = strdup(source); 489 if (mod.name == NULL) { 490 nss_log_simple(LOG_ERR, "memory allocation failure"); 491 return; 492 } 493 if (reg_fn != NULL) { 494 /* The placeholder is required, as a NULL handle 495 * represents an invalid module. 496 */ 497 mod.handle = nss_builtin_handle; 498 fn = reg_fn; 499 } else if (!is_dynamic()) { 500 goto fin; 501 } else if (strcmp(source, NSSRC_CACHE) == 0 || 502 strcmp(source, NSSRC_COMPAT) == 0 || 503 strcmp(source, NSSRC_DB) == 0 || 504 strcmp(source, NSSRC_DNS) == 0 || 505 strcmp(source, NSSRC_FILES) == 0 || 506 strcmp(source, NSSRC_NIS) == 0) { 507 /* 508 * Avoid calling dlopen(3) for built-in modules. 509 */ 510 goto fin; 511 } else { 512 if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name, 513 NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf)) 514 goto fin; 515 mod.handle = libc_dlopen(buf, RTLD_LOCAL|RTLD_LAZY); 516 if (mod.handle == NULL) { 517 #ifdef _NSS_DEBUG 518 /* This gets pretty annoying since the built-in 519 * sources aren't modules yet. 520 */ 521 nss_log(LOG_DEBUG, "%s, %s", mod.name, dlerror()); 522 #endif 523 goto fin; 524 } 525 fn = (nss_module_register_fn)dlfunc(mod.handle, 526 "nss_module_register"); 527 if (fn == NULL) { 528 (void)dlclose(mod.handle); 529 mod.handle = NULL; 530 nss_log(LOG_ERR, "%s, %s", mod.name, dlerror()); 531 goto fin; 532 } 533 } 534 mod.mtab = fn(mod.name, &mod.mtabsize, &mod.unregister); 535 if (mod.mtab == NULL || mod.mtabsize == 0) { 536 if (mod.handle != nss_builtin_handle) 537 (void)dlclose(mod.handle); 538 mod.handle = NULL; 539 nss_log(LOG_ERR, "%s, registration failed", mod.name); 540 goto fin; 541 } 542 if (mod.mtabsize > 1) 543 qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]), 544 mtab_compare); 545 fin: 546 _nsmod = vector_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod)); 547 vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare); 548 } 549 550 static int exiting = 0; 551 552 static void 553 ns_mod_free(ns_mod *mod) 554 { 555 556 free(mod->name); 557 if (mod->handle == NULL) 558 return; 559 if (mod->unregister != NULL) 560 mod->unregister(mod->mtab, mod->mtabsize); 561 if (mod->handle != nss_builtin_handle && !exiting) 562 (void)dlclose(mod->handle); 563 } 564 565 /* 566 * Cleanup 567 */ 568 static void 569 nss_atexit(void) 570 { 571 int isthreaded; 572 573 exiting = 1; 574 isthreaded = __isthreaded; 575 if (isthreaded) 576 (void)_pthread_rwlock_wrlock(&nss_lock); 577 VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap), 578 (vector_free_elem)ns_dbt_free); 579 VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod), 580 (vector_free_elem)ns_mod_free); 581 if (isthreaded) 582 (void)_pthread_rwlock_unlock(&nss_lock); 583 } 584 585 /* 586 * Finally, the actual implementation. 587 */ 588 static nss_method 589 nss_method_lookup(const char *source, const char *database, 590 const char *method, const ns_dtab disp_tab[], void **mdata) 591 { 592 ns_mod *mod; 593 ns_mtab *match, key; 594 int i; 595 596 if (disp_tab != NULL) 597 for (i = 0; disp_tab[i].src != NULL; i++) 598 if (strcasecmp(source, disp_tab[i].src) == 0) { 599 *mdata = disp_tab[i].mdata; 600 return (disp_tab[i].method); 601 } 602 mod = vector_search(&source, _nsmod, _nsmodsize, sizeof(*_nsmod), 603 string_compare); 604 if (mod != NULL && mod->handle != NULL) { 605 key.database = database; 606 key.name = method; 607 match = bsearch(&key, mod->mtab, mod->mtabsize, 608 sizeof(mod->mtab[0]), mtab_compare); 609 if (match != NULL) { 610 *mdata = match->mdata; 611 return (match->method); 612 } 613 } 614 615 *mdata = NULL; 616 return (NULL); 617 } 618 619 static void 620 fb_endstate(void *p) 621 { 622 free(p); 623 } 624 625 __weak_reference(_nsdispatch, nsdispatch); 626 627 int 628 _nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database, 629 const char *method_name, const ns_src defaults[], ...) 630 { 631 va_list ap; 632 const ns_dbt *dbt; 633 const ns_src *srclist; 634 nss_method method, fb_method; 635 void *mdata; 636 int isthreaded, serrno, i, result, srclistsize; 637 struct fb_state *st; 638 int saved_depth; 639 640 #ifdef NS_CACHING 641 nss_cache_data cache_data; 642 nss_cache_data *cache_data_p; 643 int cache_flag; 644 #endif 645 646 dbt = NULL; 647 fb_method = NULL; 648 649 isthreaded = __isthreaded; 650 serrno = errno; 651 if (isthreaded) { 652 result = _pthread_rwlock_rdlock(&nss_lock); 653 if (result != 0) { 654 result = NS_UNAVAIL; 655 goto fin; 656 } 657 } 658 659 result = fb_getstate(&st); 660 if (result != 0) { 661 result = NS_UNAVAIL; 662 goto fin; 663 } 664 665 result = nss_configure(); 666 if (result != 0) { 667 result = NS_UNAVAIL; 668 goto fin; 669 } 670 ++st->dispatch_depth; 671 if (st->dispatch_depth > st->fallback_depth) { 672 dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap), 673 string_compare); 674 fb_method = nss_method_lookup(NSSRC_FALLBACK, database, 675 method_name, disp_tab, &mdata); 676 } 677 678 if (dbt != NULL) { 679 srclist = dbt->srclist; 680 srclistsize = dbt->srclistsize; 681 } else { 682 srclist = defaults; 683 srclistsize = 0; 684 while (srclist[srclistsize].name != NULL) 685 srclistsize++; 686 } 687 688 #ifdef NS_CACHING 689 cache_data_p = NULL; 690 cache_flag = 0; 691 #endif 692 for (i = 0; i < srclistsize; i++) { 693 result = NS_NOTFOUND; 694 method = nss_method_lookup(srclist[i].name, database, 695 method_name, disp_tab, &mdata); 696 697 if (method != NULL) { 698 #ifdef NS_CACHING 699 if (strcmp(srclist[i].name, NSSRC_CACHE) == 0 && 700 nss_cache_cycle_prevention_func == NULL) { 701 #ifdef NS_STRICT_LIBC_EID_CHECKING 702 if (issetugid() != 0) 703 continue; 704 #endif 705 cache_flag = 1; 706 707 memset(&cache_data, 0, sizeof(nss_cache_data)); 708 cache_data.info = (nss_cache_info const *)mdata; 709 cache_data_p = &cache_data; 710 711 va_start(ap, defaults); 712 if (cache_data.info->id_func != NULL) 713 result = __nss_common_cache_read(retval, 714 cache_data_p, ap); 715 else if (cache_data.info->marshal_func != NULL) 716 result = __nss_mp_cache_read(retval, 717 cache_data_p, ap); 718 else 719 result = __nss_mp_cache_end(retval, 720 cache_data_p, ap); 721 va_end(ap); 722 } else { 723 cache_flag = 0; 724 errno = 0; 725 va_start(ap, defaults); 726 result = method(retval, mdata, ap); 727 va_end(ap); 728 } 729 #else /* NS_CACHING */ 730 errno = 0; 731 va_start(ap, defaults); 732 result = method(retval, mdata, ap); 733 va_end(ap); 734 #endif /* NS_CACHING */ 735 736 if (result & (srclist[i].flags)) 737 break; 738 } else { 739 if (fb_method != NULL) { 740 saved_depth = st->fallback_depth; 741 st->fallback_depth = st->dispatch_depth + 1; 742 va_start(ap, defaults); 743 result = fb_method(retval, 744 (void *)srclist[i].name, ap); 745 va_end(ap); 746 st->fallback_depth = saved_depth; 747 } else 748 nss_log(LOG_DEBUG, "%s, %s, %s, not found, " 749 "and no fallback provided", 750 srclist[i].name, database, method_name); 751 } 752 } 753 754 #ifdef NS_CACHING 755 if (cache_data_p != NULL && 756 (result & (NS_NOTFOUND | NS_SUCCESS)) && cache_flag == 0) { 757 va_start(ap, defaults); 758 if (result == NS_SUCCESS) { 759 if (cache_data.info->id_func != NULL) 760 __nss_common_cache_write(retval, cache_data_p, 761 ap); 762 else if (cache_data.info->marshal_func != NULL) 763 __nss_mp_cache_write(retval, cache_data_p, ap); 764 } else if (result == NS_NOTFOUND) { 765 if (cache_data.info->id_func == NULL) { 766 if (cache_data.info->marshal_func != NULL) 767 __nss_mp_cache_write_submit(retval, 768 cache_data_p, ap); 769 } else 770 __nss_common_cache_write_negative(cache_data_p); 771 } 772 va_end(ap); 773 } 774 #endif /* NS_CACHING */ 775 776 if (isthreaded) 777 (void)_pthread_rwlock_unlock(&nss_lock); 778 --st->dispatch_depth; 779 fin: 780 errno = serrno; 781 return (result); 782 } 783