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