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