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 96 enum _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 */ 105 static pthread_rwlock_t nss_lock = PTHREAD_RWLOCK_INITIALIZER; 106 107 /* 108 * Runtime determination of whether we are dynamically linked or not. 109 */ 110 extern int _DYNAMIC __attribute__ ((weak)); 111 #define is_dynamic() (&_DYNAMIC != NULL) 112 113 /* 114 * default sourcelist: `files' 115 */ 116 const ns_src __nsdefaultsrc[] = { 117 { NSSRC_FILES, NS_SUCCESS }, 118 { 0 }, 119 }; 120 121 /* Database, source mappings. */ 122 static unsigned int _nsmapsize; 123 static ns_dbt *_nsmap = NULL; 124 125 /* NSS modules. */ 126 static unsigned int _nsmodsize; 127 static ns_mod *_nsmod; 128 129 /* Placeholder for builtin modules' dlopen `handle'. */ 130 static int __nss_builtin_handle; 131 static 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 */ 138 static 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 */ 148 struct fb_state { 149 int fb_dispatch; 150 }; 151 static void fb_endstate(void *); 152 NSS_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 */ 167 typedef int (*vector_comparison)(const void *, const void *); 168 typedef void (*vector_free_elem)(void *); 169 static void vector_sort(void *, unsigned int, size_t, 170 vector_comparison); 171 static void vector_free(void *, unsigned int *, size_t, 172 vector_free_elem); 173 static void *vector_ref(unsigned int, void *, unsigned int, size_t); 174 static void *vector_search(const void *, void *, unsigned int, size_t, 175 vector_comparison); 176 static void *vector_append(const void *, void *, unsigned int *, size_t); 177 178 179 /* 180 * Internal interfaces. 181 */ 182 static int string_compare(const void *, const void *); 183 static int mtab_compare(const void *, const void *); 184 static int nss_configure(void); 185 static void ns_dbt_free(ns_dbt *); 186 static void ns_mod_free(ns_mod *); 187 static void ns_src_free(ns_src **, int); 188 static void nss_load_builtin_modules(void); 189 static void nss_load_module(const char *, nss_module_register_fn); 190 static void nss_atexit(void); 191 /* nsparser */ 192 extern FILE *_nsyyin; 193 194 195 /* 196 * The vector operations 197 */ 198 static void 199 vector_sort(void *vec, unsigned int count, size_t esize, 200 vector_comparison comparison) 201 { 202 qsort(vec, count, esize, comparison); 203 } 204 205 206 static void * 207 vector_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 214 static void * 215 vector_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 233 static void * 234 vector_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) 245 static void 246 vector_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 */ 264 static int 265 string_compare(const void *a, const void *b) 266 { 267 return (strcasecmp(*(const char * const *)a, *(const char * const *)b)); 268 } 269 270 271 static int 272 mtab_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 */ 287 void 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 302 void 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 */ 336 static int 337 nss_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 = 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 394 fin: 395 if (isthreaded) { 396 (void)_pthread_rwlock_unlock(&nss_lock); 397 if (result == 0) 398 result = _pthread_rwlock_rdlock(&nss_lock); 399 } 400 fin2: 401 if (isthreaded) 402 (void)_pthread_mutex_unlock(&conf_lock); 403 return (result); 404 } 405 406 407 void 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 427 static void 428 ns_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 436 static void 437 ns_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) \ 458 ns_mtab *reg(unsigned int *, nss_module_unregister_fn *); 459 #include "nss_backends.h" 460 #undef NSS_BACKEND 461 462 static void 463 nss_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 */ 475 static void 476 nss_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 = 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); 530 fin: 531 _nsmod = vector_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod)); 532 vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare); 533 } 534 535 536 537 static void 538 ns_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 */ 555 static void 556 nss_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 */ 576 static nss_method 577 nss_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 607 static void 608 fb_endstate(void *p) 609 { 610 free(p); 611 } 612 613 __weak_reference(_nsdispatch, nsdispatch); 614 615 int 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 va_start(ap, defaults); 711 result = method(retval, mdata, ap); 712 va_end(ap); 713 } 714 #else /* NS_CACHING */ 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 st->fb_dispatch = 1; 725 va_start(ap, defaults); 726 result = fb_method(retval, 727 (void *)srclist[i].name, ap); 728 va_end(ap); 729 st->fb_dispatch = 0; 730 } else 731 nss_log(LOG_DEBUG, "%s, %s, %s, not found, " 732 "and no fallback provided", 733 srclist[i].name, database, method_name); 734 } 735 } 736 737 #ifdef NS_CACHING 738 if (cache_data_p != NULL && 739 (result & (NS_NOTFOUND | NS_SUCCESS)) && cache_flag == 0) { 740 va_start(ap, defaults); 741 if (result == NS_SUCCESS) { 742 if (cache_data.info->id_func != NULL) 743 __nss_common_cache_write(retval, cache_data_p, 744 ap); 745 else if (cache_data.info->marshal_func != NULL) 746 __nss_mp_cache_write(retval, cache_data_p, ap); 747 } else if (result == NS_NOTFOUND) { 748 if (cache_data.info->id_func == NULL) { 749 if (cache_data.info->marshal_func != NULL) 750 __nss_mp_cache_write_submit(retval, 751 cache_data_p, ap); 752 } else 753 __nss_common_cache_write_negative(cache_data_p); 754 } 755 va_end(ap); 756 } 757 #endif /* NS_CACHING */ 758 759 if (isthreaded) 760 (void)_pthread_rwlock_unlock(&nss_lock); 761 fin: 762 errno = serrno; 763 return (result); 764 } 765