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