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 88enum _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 */ 97static pthread_rwlock_t nss_lock = PTHREAD_RWLOCK_INITIALIZER; 98 99/* 100 * Runtime determination of whether we are dynamically linked or not. 101 */ 102extern int _DYNAMIC __attribute__ ((weak)); 103#define is_dynamic() (&_DYNAMIC != NULL) 104 105/* 106 * default sourcelist: `files' 107 */ 108const ns_src __nsdefaultsrc[] = { 109 { NSSRC_FILES, NS_SUCCESS }, 110 { 0 }, 111}; 112 113/* Database, source mappings. */ 114static unsigned int _nsmapsize; 115static ns_dbt *_nsmap = NULL; 116 117/* NSS modules. */ 118static unsigned int _nsmodsize; 119static ns_mod *_nsmod; 120 121/* Placeholder for builtin modules' dlopen `handle'. */ 122static int __nss_builtin_handle; 123static 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 */ 130static 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 */ 142struct fb_state { 143 int dispatch_depth; 144 int fallback_depth; 145}; 146static void fb_endstate(void *); 147NSS_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 */ 162typedef int (*vector_comparison)(const void *, const void *); 163typedef void (*vector_free_elem)(void *); 164static void vector_sort(void *, unsigned int, size_t, 165 vector_comparison); 166static void vector_free(void *, unsigned int *, size_t, 167 vector_free_elem); 168static void *vector_ref(unsigned int, void *, unsigned int, size_t); 169static void *vector_search(const void *, void *, unsigned int, size_t, 170 vector_comparison); 171static void *vector_append(const void *, void *, unsigned int *, size_t); 172 173 174/* 175 * Internal interfaces. 176 */ 177static int string_compare(const void *, const void *); 178static int mtab_compare(const void *, const void *); 179static int nss_configure(void); 180static void ns_dbt_free(ns_dbt *); 181static void ns_mod_free(ns_mod *); 182static void ns_src_free(ns_src **, int); 183static void nss_load_builtin_modules(void); 184static void nss_load_module(const char *, nss_module_register_fn); 185static void nss_atexit(void); 186/* nsparser */ 187extern FILE *_nsyyin; 188 189 190/* 191 * The vector operations 192 */ 193static void 194vector_sort(void *vec, unsigned int count, size_t esize, 195 vector_comparison comparison) 196{ 197 qsort(vec, count, esize, comparison); 198} 199 200 201static void * 202vector_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 209static void * 210vector_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 228static void * 229vector_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) 240static void 241vector_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 */ 259static int 260string_compare(const void *a, const void *b) 261{ 262 return (strcasecmp(*(const char * const *)a, *(const char * const *)b)); 263} 264 265 266static int 267mtab_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 */ 282void 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 297void 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 */ 331static int 332nss_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 402fin: 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 412void 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 432static void 433ns_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 441static void 442ns_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) \ 463ns_mtab *reg(unsigned int *, nss_module_unregister_fn *); 464#include "nss_backends.h" 465#undef NSS_BACKEND 466 467static void 468nss_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 */ 480static void 481nss_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); 545fin: 546 _nsmod = vector_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod)); 547 vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare); 548} 549 550static int exiting = 0; 551 552static void 553ns_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 */ 568static void 569nss_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 */ 588static nss_method 589nss_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 619static void 620fb_endstate(void *p) 621{ 622 free(p); 623} 624 625__weak_reference(_nsdispatch, nsdispatch); 626 627int 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; 779fin: 780 errno = serrno; 781 return (result); 782} 783